How to create chapters from HLS segments, when converting M3U8 into MKV?

1

I'm converting an existing M3U8 with dozens of segments into an MKV using ffmpeg:

ffmpeg -i http://example.com/foo.m3u8 -c copy foo.mkv

FFMpeg is gluing the segments listed in the M3U8 together and the result is a monolithic MKV... Given that someone has already gone through the trouble of splitting the original into parts, I'd like to retain the information in the resulting MKV and create a chapter for each segment. Can I ask ffmpeg to record that?


Here is the output of ffmpeg -i requested in comments below:

% ffmpeg -i Marie-Octobre.m3u8 
ffmpeg version 3.2.2 Copyright (c) 2000-2016 the FFmpeg developers
  built with FreeBSD clang version 3.4.1 (tags/RELEASE_34/dot1-final 208032) 20140512
  configuration: --prefix=/opt --mandir=/opt/man --datadir=/opt/share/ffmpeg --pkgconfigdir=/opt/libdata/pkgconfig --enable-shared --enable-gpl --enable-postproc --enable-avfilter --enable-avresample --enable-pthreads --cc=cc --disable-indev=alsa --disable-outdev=alsa --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libass --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcelt --disable-chromaprint --enable-libdc1394 --disable-debug --disable-htmlpages --disable-libebur128 --enable-libfdk-aac --enable-ffserver --enable-libflite --enable-fontconfig --enable-libfreetype --enable-frei0r --enable-libfribidi --enable-libgme --enable-libgsm --enable-iconv --enable-libilbc --disable-indev=jack --enable-libkvazaar --enable-ladspa --enable-libmp3lame --enable-libbluray --enable-mmx --enable-libmodplug --enable-netcdf --enable-openal --enable-opencl --enable-libopencv --enable-opengl --enable-libopenh264 --enable-libopenjpeg --enable-libopus --disable-libpulse --disable-indev=pulse --disable-outdev=pulse --enable-runtime-cpudetect --enable-librubberband --enable-libschroedinger --enable-ffplay --disable-libsmbclient --enable-libsnappy --disable-indev=sndio --disable-outdev=sndio --disable-libsoxr --enable-libspeex --enable-sse --disable-libssh --disable-libtesseract --enable-libtheora --enable-libtwolame --disable-libv4l2 --disable-indev=v4l2 --disable-outdev=v4l2 --enable-vaapi --enable-vdpau --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libvpx --enable-libwavpack --enable-libwebp --enable-x11grab --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxvid --enable-libzimg --enable-libzmq --disable-libzvbi --disable-gcrypt --disable-gmp --enable-librtmp --disable-gnutls --enable-openssl --enable-version3 --enable-nonfree
  libavutil      55. 34.100 / 55. 34.100
  libavcodec     57. 64.101 / 57. 64.101
  libavformat    57. 56.100 / 57. 56.100
  libavdevice    57.  1.100 / 57.  1.100
  libavfilter     6. 65.100 /  6. 65.100
  libavresample   3.  1.  0 /  3.  1.  0
  libswscale      4.  2.100 /  4.  2.100
  libswresample   2.  3.100 /  2.  3.100
  libpostproc    54.  1.100 / 54.  1.100
Input #0, hls,applehttp, from 'Marie-Octobre.m3u8':
  Duration: 01:34:35.48, start: 0.101000, bitrate: 0 kb/s
  Program 0 
    Metadata:
      variant_bitrate : 0
    Stream #0:0: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(tv, smpte170m/smpte170m/bt709), 640x384, 25 fps, 25 tbr, 90k tbn, 180k tbc
    Metadata:
      variant_bitrate : 0
    Stream #0:1: Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp
    Metadata:
      variant_bitrate : 0
    Stream #0:2: Data: timed_id3 (ID3  / 0x20334449)
    Metadata:
      variant_bitrate : 0
At least one output file must be specified

The actual M38U-file lists scores of segments like:

#EXTM3U
#EXT-X-TARGETDURATION:24
#EXT-X-ALLOW-CACHE:YES
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:16.000,
seg-1-v1-a1.ts
#EXTINF:16.000,
seg-2-v1-a1.ts
#EXTINF:24.000,
seg-3-v1-a1.ts
#EXTINF:24.000,
seg-4-v1-a1.ts
#EXTINF:24.000,
...

I'd like each segment to become a "chapter" in the resulting MKV...

Mikhail T.

Posted 2017-02-05T17:12:30.693

Reputation: 419

I haven’t found anything on ffmpeg being able to add any chapters at all. For all things MKV, you’d usually use MKVToolNix, a dedicated toolkit for muxing and manipulating MKV containers. – Daniel B – 2017-02-05T17:24:12.593

Try adding -map_chapters 0 – Gyan – 2017-02-05T17:30:57.113

@Mulvya, just tried redoing it with -map_chapters 0 and the result is identical to that obtained without the option... @DanielB, how would you use mkvtoolnix (command-line or GUI) to convert an M3U8 list into an MKV? – Mikhail T. – 2017-02-05T18:29:23.340

Ok, also add -map 0 – Gyan – 2017-02-05T18:51:52.457

Adding -map 0 results in an error: [matroska @ 0x819075000] Only audio, video, and subtitles are supported for Matroska. av_interleaved_write_frame(): Invalid argument – Mikhail T. – 2017-02-05T19:25:14.737

Then, need to see full console output of ffmpeg -i http://example.com/foo.m3u8 – Gyan – 2017-02-06T11:03:28.957

Here is the actual M3U8 I worked with: https://ufs1.china-cdn88nmbwacdnln8hq8qwe.com/view/r7mx7xxLxVNcng2g_UrKaQ/1486340450/39323.mp4/index-v1-a1.m3u8

– Mikhail T. – 2017-02-06T20:58:02.103

This URL returns an error 5xx. Please just post the console output as requested by Mulvya. I have the feeling the stream URL changes frequently. – slhck – 2017-02-07T08:12:07.723

I updated the question... – Mikhail T. – 2017-02-08T01:27:31.063

The original file does not specify any chapters. What you want is creating new chapters based on the HLS segments. Can I ask why you want to retain that information? The segments are more or less arbitrarily created with a fixed length; there is no correspondence to the content. Nobody has "gone through the trouble" of creating them – it's the normal procedure when generating HTTP adaptive streaming video. ffmpeg reads the input and merges it into a single input stream, which means that the individual segments are not visible to the rest of the program anymore. – slhck – 2017-02-08T08:47:44.753

Answers

1

ffmpeg itself can't do that, as what you are referring to are HLS segments and not actual chapters that the M3U8 stream specifies. ffmpeg parses the stream and sees it as a single video stream. So, what you need to do is:

  • Parse the M3U8 file
  • Create your own chapter list according to the MKV chapter format specification
  • Use mkvmerge to add these chapters to the MKV file that ffmpeg generated

More specifically, you want to parse the M3U8 and extract every segment length (as specified by EXTINF) and its name:

#EXTINF:16.000,
seg-1-v1-a1.ts
#EXTINF:16.000,
seg-2-v1-a1.ts
#EXTINF:24.000,
seg-3-v1-a1.ts
#EXTINF:24.000,
seg-4-v1-a1.ts
#EXTINF:24.000,

Then, for each segment you create a new chapter with the beginning set to the accumulated segment duration, and the name set to the segment name:

CHAPTER01=00:00:00.000
CHAPTER01NAME=seg-1-v1-a1.ts
CHAPTER02=00:00:16.000
CHAPTER02NAME=seg-2-v1-a1.ts
CHAPTER03=00:00:32.000
CHAPTER03NAME=seg-3-v1-a1.ts
CHAPTER04=00:00:56.000
CHAPTER04NAME=seg-4-v1-a1.ts
...

This could be done using Bash scripts or Python, whatever programming language suits you best. (I don't have the time to write the script now, but you get the idea.)

Save that file as chapters.txt.

Then, install mkvtoolnix and run:

mkvmerge input.mkv --chapters chapters.txt -o output.mkv

slhck

Posted 2017-02-05T17:12:30.693

Reputation: 182 472

Thanks. Wish, ffmpeg made it possible to treat the multiple segments as chapters automatically, but this method will work too. – Mikhail T. – 2017-02-08T17:54:28.643