30

I have a .m3u8 file on remote host, with contain fixed numbers of chunk .ts file name, and not stream:

#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,

When I use this command:

# 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

It works. But It get frame by frame video and very long time needed. (It takes time almost to playback the video.)

But since the path of all the .ts files are known. (http://example.com/media_0.ts, http://example.com/media_1.ts, ...) There must be a way to get and merge them all at the same time.

But How in ffmpeg directly?!

EDIT (try a solution):

For one solution, I know how can concatenation files with ffmpeg.

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

This ffmpeg command was great, and works in less 1 sec time!

So try to download all .ts files with CURL with this command:

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

But you can see result:

  % 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

See, total download time was 72 sec, while the total duration of all parts is 59 sec! that this time is very long!

So sorry, download all parts and then concat that, was not good solution.

EDIT 2

I try for another .m3u8 file on the another server with difference URL:

Download and concat together:

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

Another command with input.txt URLs file.

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

input.txt file:

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'

Or this command some time if needed:

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

Finally, for that download speed was good, MAYBE my server target has limited bandwidth. :-(

Nabi K.A.Z.
  • 9,887
  • 6
  • 59
  • 81

4 Answers4

60

The correct way to concat multiple video files from m3u8 playlist is

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


  • the m3u8 playlist can be on web or locally in directory
    • it contains list of file paths relative to the playlist
  • -codec copy to avoid encoding (which takes time)
  • container type matters:
    • *.mp4 is fine but it seems little slow to mux when playlist is fetched from web
    • *.mkv or *.ts worked best for me
Vlastimil Ovčáčík
  • 2,799
  • 27
  • 29
2

I couldn't get ffmpeg to work correctly without skipping frames (and their bug tracker is broken so I can't even report it -_-) but I did find two other methods that work:

  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.

BlueRaja - Danny Pflughoeft
  • 84,206
  • 33
  • 197
  • 283
  • 1
    I can confirm that youtube-dl works really well. If your internet is glitchy, youtube-dl will wait and resume the download when it can. Other methods mentioned here simply stop there. – Aivils Štoss Dec 28 '22 at 08:26
  • By using this youtube-dl command on Windows 10, I'm getting the following error: "Not yet implemented in FFmpeg, patches welcome" – jeppoo1 Jan 05 '23 at 13:22
1

you can try.

command: ffmpeg -y \ -v warning \ -loglevel debug \ -i "m3u8 url" \ -vcodec copy \ -c copy -f mpegts out.ts

convert ts to mp4:

ffmpeg -i out.ts -acodec copy -vcodec copy out.mp4

Gatspy
  • 1,642
  • 3
  • 13
  • 13
0

here's some python code that does it, you just need to provide the url of the 1st segment and the number of segments (from the .m3u8 file):

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)

Here's the same code with a few more bells and whistles

sam46
  • 1,273
  • 9
  • 12
  • 1
    This is the second link-only post advertising the same package. This borders on excessive self promotion. You may want to read about (how not to be a spammer)[https://stackoverflow.com/help/promotion]. You have contributed several other good answers to the SO community, so I am not going to flag this as spam, but it is definitely a link-only answer. To improve your answer and avoid deletion, I recommend you include some of the relevant code in this post. Your answer should stand on its own without the link. The link should just be supplemental. – Tom Aranda Jan 19 '18 at 02:51
  • 1
    Nice [edit]. Just make sure you disclose that the link is to your repo. – Tom Aranda Jan 19 '18 at 14:44
  • The question ask about the m3u8 file, but your answer assume all the ts file in the m3u8 follow strictly the pattern "seg-1" , may be at least u have to manually extracted all the ts link from the m3u8 first – Luk Aron Dec 22 '20 at 10:29