使用python+FFmpeg实现m3u8文件内的ts视频 解密、合并 && ffmpeg截取视频

m3u8文件内内容

 

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:1
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-KEY:METHOD=AES-128,URI="E:/CTF/test/key.key",IV=0x00000000000000000000000000000001
#EXTINF:11,
00154.ts  //ts视频的路径一般都是绝对路径,我这里没有给出绝对链接
#EXT-X-KEY:METHOD=AES-128,URI="E:/CTF/test/key.key",IV=0x0000000000000000000000000000009B
#EXTINF:10,
00155.ts
#EXT-X-KEY:METHOD=AES-128,URI="E:/CTF/test/key.key",IV=0x0000000000000000000000000000009C
#EXTINF:11,
00156.ts
#EXT-X-KEY:METHOD=AES-128,URI="E:/CTF/test/key.key",IV=0x0000000000000000000000000000009D
#EXTINF:10,
00157.ts

 

这个是正式的m3u8文件(参看:https://blog.csdn.net/weixin_41624645/article/details/95939510):

 

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:13
#EXT-X-MEDIA-SEQUENCE:0

//这里是注释,真实文件里不会有的,
//看看你的m3u8文件里有没有这一行,如果有的话,那么恭喜你这个m3u8文件是加密的,请继续往下看
//如果没有这行的话,特别是没有这个#EXT-X-KEY,那么同样恭喜你,这个m3u8没有加密,你直接百度vlc下载合并就行,也可根据本文章进行合并
#EXT-X-KEY:METHOD=AES-128,URI="http://www.example.com/20180125/key.key"


#EXTINF:12.5,
//下面的这个其实才是视频真正的地址,你放在浏览器地址栏上直接回车是可以直接下载的
//不过这样的链接在m3u8文件里会有很多,建议使用工具下载(迅雷)、ffmpeg、vlc等
//这里还可能出现GBDYO3576000.ts这种情况,其实是把前面的路径省略了,可根据m3u8文件的路径自行加上
http://www.example.com/20180125/GBDYO3576000.ts
#EXTINF:12.5,
http://www.example.com/20180125/GBDYO3576001.ts
#EXTINF:12.5,
http://www.example.com/20180125/GBDYO3576002.ts

 

 

 

上面这个m3u8文件中有这样的字段:

 

#EXT-X-KEY:METHOD=AES-128,URI="E:/CTF/test/key.key",IV=0x00000000000000000000000000000001

 

就证明你这个m3u8内的ts视频是加密的(意思就是你可以把m3u8内的ts视频下载,但是因为视频被加密导致播放器无法播放)

 

那么我们就需要对ts视频解密,看上面那个字段的URI的值

 

URI="E:/CTF/test/key.key"

 

 

它的意思就是ts视频的解密文件链接为:

E:/CTF/test/key.key

那我们就把它下载下来。可能这个链接不是绝对路径,那你就去找一下这个网站的路径,把这个相对路径加到后面就组成了key.key文件的绝对路径

 

下载之后这个时候你就有两个文件一个是后缀为m3u8文件,里面放置ts视频绝对路径。还有一个key.key文件,放置视频解密所需东西

这个时候你把后缀为m3u8的文件名改为:index.m3u8

这个时候你把key.key的文件名改为:key.m3u8

 

我们假设你已经把m3u8文件内的所有ts视频都下载下来了,且ts视频地址和index.m3u8和key.m3u8文件在同一目录下

 

这个时候我们要修改一下m3u8文件内容:

 

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:1
#EXT-X-PLAYLIST-TYPE:VOD    //注意改一下这个URI地址为你电脑上的key.m3u8文件路径,相对路径也行
#EXT-X-KEY:METHOD=AES-128,URI="E:/CTF/test/key.m3u8",IV=0x00000000000000000000000000000001
#EXTINF:11,
00154.ts  //注意因为我的ts视频和index.m3u8文件在同一目录下,所以我直接写出ts视频文件名就行,如果你的视频和index文件不再一个地方,你给出你本地的绝对地址也行
#EXT-X-KEY:METHOD=AES-128,URI="E:/CTF/test/key.m3u8",IV=0x0000000000000000000000000000009B
#EXTINF:10,
00155.ts
#EXT-X-KEY:METHOD=AES-128,URI="E:/CTF/test/key.m3u8",IV=0x0000000000000000000000000000009C
#EXTINF:11,
00156.ts
#EXT-X-KEY:METHOD=AES-128,URI="E:/CTF/test/key.m3u8",IV=0x0000000000000000000000000000009D
#EXTINF:10,
00157.ts

 

 

 

接下来还需要下载一款工具ffmpeg,下载Static的那个版本就可以,然后配置环境变量Path,在Path后面直接添加你ffmpeg的安装目录加上/bin就可以了,安装完成之后重启一下,重启之后打开你index.m3u8所在的文件执行下面命令:

 

ffmpeg -allowed_extensions ALL -i index.m3u8 -c copy out.mp4

 

报错了可执行:

 

ffmpeg -allowed_extensions ALL -protocol_whitelist "file,http,crypto,tcp" -i index.m3u8 -c copy out.mp4

 

如果这里报错了,那么打开你的index.m3u8文件,修改URI的路径为网络路径(你下载时的路径),然后执行

 

ffmpeg -protocol_whitelist "file,http,crypto,tcp" -i index.m3u8 -c copy out.ts

 

 

 

操作之后合并的视频就是out.ts

所有index.m3u8的ts视频都是从00001.ts开始,因为我下载那个总的视频比较大,所以index.m3u8内的ts小视频链接三百多个,所以我就挑出来了几个ts链接

然后下载了。这个时候你要注意了,因为你只下载了几个ts视频,那也就证明index.m3u8内的有些ts视频你的电脑本地没有,那么你就要在index.m3u8文件内把这些不存在的删掉,要不然执行ffmpeg命令会报错:

[crypto @ 000000000054de40] Unable to open resource: D:\temp\vd201906291\O7rSBp5
l5847008.ts
[hls,applehttp @ 0000000000532c40] Failed to open segment 8 of playlist 0
[hls,applehttp @ 0000000000532c40] Error when loading first segment ‘D:\temp\vd2
01906291\O7rSBp5l5847000.ts’
D:\temp\vd201906291\tsmaster.m3u8: Invalid data found when processing input

最主要的原因就是因为m3u8中本地文件的路径写错了啦,所以会提示无效数据。正确的路径写法见上一篇文章。如果还是这个提示,就请检查一下这些文件是不是都存在啦。

 

 

因为有的index.m3u8文件内ts视频很多,我们手动下载要累死,那么我们可以使用python通过多线程来加速下载

使用下面这个代码,你需要在python文件同目录下提供一个index.m3u8文件就可以了

代码就会根据index.m3u8内的ts视频绝对链接,进行下载

 

import requests,os,threading
def getTsUrl():
    ts_url_list = []
    # baseUrl = "https://ycalvod.yicai.com/record/live"
    with open("qwe.m3u8", "r", encoding="utf-8") as f:
        m3u8Contents = f.readlines()
        for content in m3u8Contents:
            if content.endswith("ts\n"):
                ts_Url = content.replace("\n", "").replace("..", "")
                ts_url_list.append(ts_Url)
                # print(ts_Url)
    return ts_url_list

def download_ts_video(download_path, ts_url_list,start,last):
    # download_path = r"C:\Users\Administrator\Desktop\AiShu\下载视频\TS视频"
    for i in range(start,last):
        ts_url = ts_url_list[i]
        try:
            response = requests.get(ts_url, stream=True, verify=False)
        except Exception as e:
            print("异常请求:%s" % e.args)
            return
        name = ts_url.split('_')[-1].strip()  # 截取ts链接的最后一部分,结果为00001.ts
        ts_path = download_path + "\{}".format(name)
        with open(ts_path, "wb+") as file:
            for chunk in response.iter_content(chunk_size=1024):
                if chunk:
                    file.write(chunk)

def main(total,block,total_vedio): # 启动多线程
    start = 0
    thread_list = []  # 线程存放列表
    for i in range(total):
        if start + block > total_vedio:
            t = threading.Thread(target=download_ts_video, args=(download_path,ts_url_list ,start, total_vedio,))
        else:
            t = threading.Thread(target=download_ts_video, args=(download_path,ts_url_list,start , start + block,))
            start += block
        t.setDaemon(True)
        thread_list.append(t)

    for t in thread_list:
        t.start()

    for t in thread_list:
        t.join()


if __name__ == '__main__':
    download_path = r"E:/CTF/test"  # 视频保存在本地的地址
    total = 20  # 线程总数
    ts_url_list = getTsUrl() # 获取所有ts链接
    block = int(len(ts_url_list) / total) # 一共有total个线程,那么平均给每一个线程多少个下载任务
    if len(ts_url_list) % total != 0:
        block += 1
    main(total,block,len(ts_url_list))
    # download_ts_video(download_path, ts_url_list)
    # print(ts_url_list)

 

 

因为最后index.m3u8文件内的链接都要改成本地链接,一个一个改起来太慢,我使用的是notepad++,这个软件有个工具替换,可以一次改完

 ts链接的前面基本上都一样,你可以把ts视频绝对链接前面一部分选中,把它替换为空,那么文件名就是00001、00002、00003......类型的了

 

 

运行结果:

 

这是个警告,如果你想处理的话,你可以在请求代码前添加如下代码即可:

 

如果想要截图视频,可以通过以下命令(参考链接为:https://blog.csdn.net/huangxingli/article/details/46663143):

ffmpeg  -i ./plutopr.mp4 -vcodec copy -acodec copy -ss 00:00:10 -to 00:00:15 ./cutout1.mp4 -y

 

-ss time_off        set the start time offset 设置从视频的哪个时间点开始截取,上文从视频的第10s开始截取
-to 截到视频的哪个时间点结束。上文到视频的第15s结束。截出的视频共5s.
如果用-t 表示截取多长的时间如 上文-to 换位-t则是截取从视频的第10s开始,截取15s时长的视频。即截出来的视频共15s.
 
注意的地方是:
 如果将-ss放在-i ./plutopr.mp4后面则-to的作用就没了,跟-t一样的效果了,变成了截取多长视频。一定要注意-ss的位置。
 
参数解析
-vcodec copy表示使用跟原视频一样的视频编解码器。
-acodec copy表示使用跟原视频一样的音频编解码器。
 
-i 表示源视频文件
-y 表示如果输出文件已存在则覆盖。

 

合并视频:先弄一个filelist.txt文件

 

file  'D:\delphisr\腾讯下载地址解析子串\k0028qzpkdl.321002.1.ts'
file  'D:\delphisr\腾讯下载地址解析子串\k0028qzpkdl.321002.2.ts'
file  'D:\delphisr\腾讯下载地址解析子串\k0028qzpkdl.321002.3.ts'
file  'D:\delphisr\腾讯下载地址解析子串\k0028qzpkdl.321002.4.ts'

 

 

 

然后进入这个目录执行下面这个命令:

 

ffmpeg -f concat -safe 0 -i filelist.txt -c copy out.mp4

 

posted @ 2020-08-24 15:33  kongbursi  阅读(10973)  评论(0编辑  收藏  举报