如何一次性下载.m3u8文件

31

我在远程主机上有一个 .m3u8 文件,其中包含一定数量的固定命名的 .ts 片段文件,并非流媒体:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.736,
media_0.ts
#EXTINF:9.96,
media_1.ts
#EXTINF:10.0,
media_2.ts
#EXTINF:10.0,
media_3.ts
#EXTINF:10.0,
media_4.ts
#EXTINF:10.2,
media_5.ts
#EXTINF:10.0,

当我使用这个命令时:

# ffmpeg -i "http://example.com/chunklist.m3u8" file.mp4

frame=  582 fps=9.4 q=28.0 size=    1536kB time=00:00:23.21 bitrate= 542.1kbits/s dup=2 drop=4 speed=0.375x

它能工作,但需要逐帧获取视频,需要很长时间(几乎需要播放整个视频的时间)。

但是既然所有.ts文件的路径都已知。(http://example.com/media_0.tshttp://example.com/media_1.ts,...),一定有一种方法可以同时获取和合并它们。

但是如何直接在ffmpeg中实现呢?!

编辑(尝试解决方案):

对于一个解决方案,我知道如何使用ffmpeg连接文件。

ffmpeg -i "concat:0.ts|1.ts|2.ts|3.ts|4.ts|5.ts" -c copy output.mp4

这个 ffmpeg 命令效果很棒,而且只需不到 1 秒的时间!

因此,试着用以下命令使用 CURL 下载所有 .ts 文件:

curl \
http://example.com/media_0.ts -o 0.ts \
http://example.com/media_1.ts -o 1.ts \
http://example.com/media_2.ts -o 2.ts \
http://example.com/media_3.ts -o 3.ts \
http://example.com/media_4.ts -o 4.ts \
http://example.com/media_5.ts -o 5.ts

但是你可以看到结果:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  687k  100  687k    0     0  75108      0  0:00:09  0:00:09 --:--:-- 74111
100  652k  100  652k    0     0  59404      0  0:00:11  0:00:11 --:--:-- 53400
100  673k  100  673k    0     0  48675      0  0:00:14  0:00:14 --:--:-- 55781
100  657k  100  657k    0     0  63573      0  0:00:10  0:00:10 --:--:-- 62494
100  671k  100  671k    0     0  39019      0  0:00:17  0:00:17 --:--:-- 40863
100  692k  100  692k    0     0  63480      0  0:00:11  0:00:11 --:--:-- 80049

看,总下载时间为72秒,而所有部分的总持续时间为59秒! 这个时间非常长!

非常抱歉,下载所有部分然后连接起来并不是一个好的解决方案。

编辑2

我尝试了另一个具有不同URL的另一台服务器上的.m3u8文件:

下载并合并在一起:

ffmpeg -i "concat:\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_0.ts|\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_1.ts|\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_2.ts|\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_3.ts|\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_4.ts|\
http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_5.ts\
" -c copy -y output.ts

使用input.txt文件URL的另一个命令。

ffmpeg -f "concat" -i "input.txt" -c copy -y output.ts

input.txt文件:

file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_0.ts'
file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_1.ts'
file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_2.ts'
file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_3.ts'
file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_4.ts'
file 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/media_w442897525_b560000_5.ts'

如果需要的话,可以使用这个命令:

ffmpeg -f "concat" -safe "0" -protocol_whitelist "file,http,https,tcp,tls" -i "input.txt" -c copy -y output.ts

最后,由于下载速度良好,可能是因为我的服务器目标带宽有限。 :-(


如果您控制服务器端,为何不在那里使用zip归档文件,然后在下载后进行解压缩? - Dave S
@DaveS 这是一种不好的行为。 - Nabi K.A.Z.
6
将http://reading/documentation/is/magic/just/try/it/really.m3u8的视频流转换为MP4格式并保存为file.mp4,命令为`ffmpeg -i http://reading/documentation/is/magic/just/try/it/really.m3u8 -c copy file.mp4`。 - aergistal
4个回答

64

拼接m3u8播放列表中多个视频文件的正确方法是:

ffmpeg -i "http://example.com/chunklist.m3u8" -codec copy file.mp4


  • m3u8播放列表可以在web上或本地目录中。
    • 它包含相对于播放列表的文件路径列表。
  • -codec copy用于避免编码(需要时间)。
  • 容器类型很重要:
    • *.mp4是可行的,但是当从web获取播放列表时速度较慢。
    • *.mkv*.ts 对我来说效果最好。

2

我无法让ffmpeg正常工作而不跳帧(而且他们的bug跟踪器还坏了,所以我甚至不能报告它 -_-),但我找到了另外两种可行的方法:

  1. Youtube-dl. The command

    youtube-dl.exe --hls-prefer-native "https://link-to-m3u8-file"
    

    just worked immediately, and ripped the raw audio from the stream in (in my case) .mp4 format

  2. VLC. Go to Media --> Open Network Stream, then paste the m3u8 URL. Click the dropdown next to 'Play' and choose 'Convert', then choose your conversion settings.
    They have an option for "dump raw input", but I wasn't able to get it to work. However "mp3" worked fine.


1
我可以确认youtube-dl非常好用。如果你的网络有问题,youtube-dl会等待并在可以时恢复下载。这里提到的其他方法只会停在那里。 - Aivils Štoss
在Windows 10上使用youtube-dl命令时,我遇到了以下错误:“FFmpeg尚未实现,欢迎提供补丁”。 - jeppoo1

1
你可以尝试。
命令: ffmpeg -y \ -v warning \ -loglevel debug \ -i "m3u8 url" \ -vcodec copy \ -c copy -f mpegts out.ts
将ts转换为mp4:
ffmpeg -i out.ts -acodec copy -vcodec copy out.mp4

0

这里有一些 Python 代码可以实现它,你只需要提供第一个片段的 URL 和片段数量(从 .m3u8 文件中获取):

def dumpSegs(initUrl, n, path, append=False):
    """ downlaod and combine the .ts files
    given the first seg's url, the number of segments and
    the destination download path """
    with open(path, 'ab' if append else 'wb') as f:
        for i in range(1, n + 1):
            segurl = initUrl.replace('seg-1-', 'seg-{:d}-'.format(i))
            success = False
            while not success:
                try:
                    seg = requests.get(segurl, headers=HEADERS)
                    success = True
                except:
                    print('retrying...')
            f.write(seg.content)

这里是带有更多花哨功能的相同代码


1
这是第二个仅包含链接的帖子,宣传同一套软件包。这几乎属于过度自我推广。你可能想阅读一下《如何避免成为垃圾邮件发送者》。你在SO社区贡献了几个好答案,所以我不会将其标记为垃圾邮件,但它绝对是一个仅包含链接的答案。为了改善你的答案并避免被删除,我建议你在此贴中包含一些相关代码。你的答案应该能够独立存在,而链接只应该是补充。 - Tom Aranda
1
不错的[编辑]。只需确保披露链接是您的存储库。 - Tom Aranda
这个问题是关于m3u8文件的,但是你的回答假设所有在m3u8中的ts文件都严格遵循"seg-1"的模式,也许你至少需要手动从m3u8中提取所有的ts链接。 - Luk Aron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接