爬虫实战案例《抓取视频》之FFmpeg的使用(七)

Python合并ts文件至mp4格式及解密教程详解

  • m3u8是什么格式?m3u8是苹果公司推出的视频播放标准,是m3u的一种,只是编码格式采用的是UTF-8。

  • 使用m3u8格式文件主要因为可以实现多码率视频的适配,视频网站可以根据用户的网络带宽情况,自动为客户端匹配一个合适的码率文件进行播放,从而保证视频的流畅度。

  • m3u8准确来说是一种索引文件,使用m3u8文件实际上是通过它来解析对应的放在服务器上的视频网络地址,从而实现在线播放。

  • 它将视频切割成一小段一小段的ts格式的视频文件,然后存在服务器中(现在为了减少I/o访问次数,一般存在服务器的内存中),通过m3u8解析出来路径,然后去请求。

  • 合并 ts 文件其实有很多种方法,有一些教程直接使用 cmd 的 copy 命令直接合并 ts 文件:

    copy /b movie*.ts movie_new.ts

  • 这个方法虽然可以合并,但是无法转化为 mp4 格式,而且也有可能出现视频缺损的情况。因此本文将讲解如何使用 ffmpeg 合并 ts 文件为mp4格式,使用 ffmpeg 也能有效防止视频出现缺损的问题。

1.准备

  • 开始之前,你要确保Python和pip已经成功安装在电脑上
  • 如果你用Python的目的是数据分析,可以直接安装Anaconda

安装ffmpeg

  • Mac (打开终端(Terminal), 用 homebrew 安装):

    brew install ffmpeg --with-libvorbis --with-sdl2 --with-theora

  • Linux:

    apt-get install ffmpeg libavcodec-extra

  • Windows:

    1. 进入 http://ffmpeg.org/download.html#build-windows,点击 windows 对应的图标,进入下载界面点击 download 下载按钮,
    2. 解压下载好的zip文件到指定目录
    3. 将解压后的文件目录中 bin 目录(包含 ffmpeg.exe )添加进 path 环境变量中
    4. DOS 命令行输入 ffmpeg -version, 出现以下界面说明安装完成:

2. 简单合并ts文件

  • 使用 ffmpeg 合并一些 ts 文件非常简单,你只需要在终端输入一行命令即可:

    ffmpeg -f concat  -safe 0 -i file_list.txt -c copy movie.mp4
    
  • 其中 file_list.txt 为如下格式文本文件:

    file './路径/1.ts'
    file './路径/2.ts'
    file './路径/3.ts'

  • 我们可以用 Python 脚本生成这个 file_list.txt:

    目录结构

    project/

    ​ new_ts/ 存储ts文件的目录

    ​ 1.ts

    ​ 2.ts ...

    ​ file_list.txt

    ​ main.py

    main.py

    def merge(filePath, filename='output'):
        '''
        这种合并会有视频和音频对应不上的问题
        进行ts文件合并
        :param filePath:
        :return:
        '''
        # 根据当前文件名称的数字进行排序  [1.ts, 2.ts...]
        file_list = sorted(os.listdir(filePath), key=lambda x: int(x.split('.')[0]))
        # 排序后写入到文件中
        with open("./file_list.txt", "w") as f:
            for file in file_list:
                # 格式为  file ./new_ts/1.ts  ...
                f.write("file '{}/{}'\n".format(filePath, file))
        cmd = f'ffmpeg -f concat  -safe 0 -i file_list.txt -c copy {filename}.mp4'
        os.system(cmd)
    

    执行完就当前代码就执行完了合并

  • 注意:以上代码合并后的视频可能会出现视频和音频对不上的问题 如果出现这样的问题 使用下面的方式进行处理

    合并代码

    def merge(filePath, filename='output'):
        '''
        进行ts文件合并 解决视频音频不同步的问题 建议使用这种
        :param filePath:
        :return:
        '''
        # 根据当前文件名称的数字进行排序
        file_list = sorted(os.listdir(filePath), key=lambda x: int(x.split('.')[0]))
        # ./new_ts/1.ts|./new_ts/2.ts ...
        Str = '|'.join([f'{filePath}/{i}' for i in file_list]).strip('|')
        cmd = f'ffmpeg -i "concat:{Str}" -c copy -bsf:a aac_adtstoasc -movflags +faststart {filename}.mp4'
        os.system(cmd)
    

3. 解密处理

  • 上面我们讲的是没有经过加密的 ts 文件,这些文件下载后直接可以播放,但经过AES-128加密后的文件下载后会无法播放,所以还需要进行解密。

  • 如何判断是否需要加密?观察视频网站是否有m3u8的文件传输,下载下来并打开:

    无需解密index.m3u8文件

    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-TARGETDURATION:4
    #EXT-X-PLAYLIST-TYPE:VOD
    #EXT-X-MEDIA-SEQUENCE:0
    #EXTINF:3.086,
    https://hey05.cjkypo.com/20211215/FMbNtNzz/1100kb/hls/7qs6gJc0.ts
    #EXTINF:2.085,
    https://hey05.cjkypo.com/20211215/FMbNtNzz/1100kb/hls/rYpHhq0I.ts
    #EXTINF:2.085,
    https://hey05.cjkypo.com/20211215/FMbNtNzz/1100kb/hls/bfays5sw.ts
    

    需要解密index.m3u8文件

    #EXT-X-VERSION:3
    #EXT-X-TARGETDURATION:1
    #EXT-X-PLAYLIST-TYPE:VOD
    #EXT-X-MEDIA-SEQUENCE:0
    #EXT-X-KEY:METHOD=AES-128,URI="/20220418/671fJxOB/2000kb/hls/key.key" # 当前路径为解密秘钥的位置  需要使用代码拼凑成完整路径 进行请求 域名+/20220418/671fJxOB/2000kb/hls/key.key
    #EXTINF:1.235,
    /20220418/671fJxOB/2000kb/hls/kj6uqHoP.ts  # 并且这里ts的url也要拼凑完整
    #EXTINF:1.001,
    /20220418/671fJxOB/2000kb/hls/ZXX8LYPa.ts
    #EXTINF:1.001,
    /20220418/671fJxOB/2000kb/hls/sOezpD2H.ts
    #EXTINF:1.001,
    ...
    
  • 如果你的文件是加密的,那么你还需要一个key文件,Key文件下载的方法和m3u8文件类似,如下所示 key.key 就是我们需要下载的 key 文件,并注意这里 m3u8 有2个,需要使用的是像上面一样存在 ts 文件超链接的 m3u8 文件:

  • 下载所有 ts 文件,将下载好的所有的 ts 文件、m3u8、key.key 放到一个文件夹中,将 m3u8 文件改名为 index.m3u8,将 key.key 改名为 key.m3u8 。更改 index.m3u8 里的 URL,变为你本地路径的 key 文件,将所有 ts 也改为你本地的路径

    文件路径

    project/

    ​ ts/

    ​ 0.ts

    ​ 1.ts

    ​ ...

    ​ index.m3u8

    ​ key.m3u8

    修改后的index.m3u8内容如下所示:

    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-TARGETDURATION:1
    #EXT-X-PLAYLIST-TYPE:VOD
    #EXT-X-MEDIA-SEQUENCE:0
    #EXT-X-KEY:METHOD=AES-128,URI="/Users/xialigang/PycharmProjects/爬虫/抓取带秘钥的电影/ts/key.m3u8"
    #EXTINF:1.235,
    /Users/xialigang/PycharmProjects/爬虫/抓取带秘钥的电影/ts/0.ts
    #EXTINF:1.001,
    /Users/xialigang/PycharmProjects/爬虫/抓取带秘钥的电影/ts/1.ts
    #EXTINF:1.001,
    /Users/xialigang/PycharmProjects/爬虫/抓取带秘钥的电影/ts/2.ts
    

    处理index.m3u8内容的代码如下所示

    def do_m3u8_url(path):
        if not os.path.exists(path):
            os.mkdir(path)
        with open("index.m3u8", mode="r", encoding="utf-8") as f:
            data = f.readlines()
        # 修改后重新写入
        fw = open('index.m3u8', 'w')
        i = 0
        for line in data:
            # 如果不是url 则走下次循环
            if line.startswith("#"):
                fw.write(line)
            else:
                fw.write(f'/Users/xialigang/PycharmProjects/爬虫/抓取带秘钥的电影/{path}/{i}.ts\n')
                print(line, i)
                i += 1
    
  • 然后用ffmpeg进行合并:

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

    代码合并

    os.chdir("./ts")
    os.system('ffmpeg -allowed_extensions ALL -i index.m3u8 -c copy movie.mp4')
    
  • 这样就大功告成了!我们成功解密并使用 ffmpeg 合并了这些 ts 视频片段,实际应用场景可能和这不一样,具体网站具体分析

posted @ 2022-07-06 11:45  帅气的Lucky  阅读(1004)  评论(0编辑  收藏  举报