[FFmpeg-trac] #5009(ffmpeg:new): Declared EXTINF duration of the last segment in the mediaplaylist.m3u8 is shorter than the actual duration of the last MPEG-TS file

FFmpeg trac at avcodec.org
Sun Nov 15 09:15:01 CET 2015


#5009: Declared EXTINF duration of the last segment in the mediaplaylist.m3u8 is
shorter than the actual duration of the last MPEG-TS file
-------------------------------------+-------------------------------------
             Reporter:               |                     Type:  defect
  an_ffmpeg_user                     |                 Priority:  normal
               Status:  new          |                  Version:
            Component:  ffmpeg       |  unspecified
             Keywords:  HLS Segment  |               Blocked By:
  Duration                           |  Reproduced by developer:  0
             Blocking:               |
Analyzed by developer:  0            |
-------------------------------------+-------------------------------------
 Summary.  When encoding using the FFmpeg HLS output, the declared EXTINF
 duration of the last segment in the mediaplaylist.m3u8 is shorter than the
 actual duration of the last MPEG-TS file.

 Unfortunately, this affects the playback on strict HLS Players that
 consider playback to be over when the last segment's EXTINF has expired.
 End credits or copyright frames do not get displayed.

 It appears to be an issue with FFmpeg's generation of EXTINF duration in
 the m3u8 for the last segment.  The duration of the last segment in the
 playlist should not be lower than the actual TS duration.

 The FFmpeg 2.8 HLS Segmenter generates a EXT-X-VERSION:3 Playlist with
 integers to six decimal places.  HLS Protocol version 3, Draft 5
 https://tools.ietf.org/html/draft-pantos-http-live-streaming-05
 {{{
 #EXTINF:<duration>,<title>
 "duration" is an integer or floating-point number that specifies the
 duration of the media file in seconds.  Integer durations SHOULD be
 rounded to the nearest integer.
 }}}
 Floating-point durations should be accurate.  If the duration is being
 declared to six decimal places, it should be accurate to six decimal
 places.

 It is acknowledged that the duration of a TS can be ambiguous as there are
 multiple durations reported by FFprobe and MediaInfo
 - container duration
 - video duration
 - audio duration
 Therefore to avoid ambiguity, the following example uses a video-only
 stream.  FFprobe outputs of both 'container duration' and 'video duration'
 are included below.

 How to replicate...

 First, generate a 1080p30 mezzanine MP4 file to be used as a source for
 the test.  Using testsrc input so that anyone is able to reproduce:
 {{{
 $ ffmpeg -f lavfi -i testsrc=duration=14:size=1920x1080:rate=30*1000/1001
 -vf
 "drawtext=fontfile=/Library/Fonts/Verdana.ttf:timecode='00\:00\:00\:00':r=30*1000/1001:x=(w-tw)/2:y=h-(2*lh):fontcolor=white:box=1:boxcolor=0x00000099"
 -c:v libx264 -profile:v high -level 4.0 -x264opts "bitrate=3500:vbv-
 maxrate=3500:vbv-bufsize=3500" -pix_fmt yuv420p -f mp4 ./mezzanine.mp4
 }}}

 Inspect the duration of the mezzanine file.  The mezzanine MP4 has a
 duration of 14.014000 seconds (due to 29.970 vs 30.00fps).
 {{{
 $ ffprobe -loglevel quiet -print_format flat -show_entries format=duration
 "./mezzanine.mp4"
 format.duration="14.014000"
 $ ffprobe -loglevel quiet -print_format flat -show_streams -select_streams
 v -show_entries stream=duration "./mezzanine.mp4"
 streams.stream.0.duration="14.014000"
 }}}

 Now, transcode and segment the source file using the HLS output (including
 full FFmpeg command line output):
 {{{
 $ ffmpeg -i "./mezzanine.mp4" -vf "scale=1280:720" -c:v libx264 -preset
 medium -profile:v main -level 3.1 -x264opts "bitrate=2400:vbv-maxrate=2400
 :vbv-bufsize=2400:min-keyint=30:keyint=60:scenecut=0" -pix_fmt yuv420p -f
 hls -hls_time 6 -hls_list_size 0 -hls_segment_filename
 'test_1280x720_%03d.ts' ./test_mediaplaylist_1280x720.m3u8

     ffmpeg version 2.8.1 Copyright (c) 2000-2015 the FFmpeg developers
       built with Apple LLVM version 7.0.0 (clang-700.1.76)
       configuration: --prefix=/usr/local/Cellar/ffmpeg/2.8.1_1 --enable-
 shared --enable-pthreads --enable-gpl --enable-version3 --enable-
 hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-
 ldflags= --enable-opencl --enable-libx264 --enable-libmp3lame --enable-
 libvo-aacenc --enable-libxvid --enable-libfontconfig --enable-libfreetype
 --enable-libtheora --enable-libvorbis --enable-libvpx --enable-librtmp
 --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libfaac
 --enable-libass --enable-ffplay --enable-libssh --enable-libspeex
 --enable-libschroedinger --enable-libfdk-aac --enable-openssl --enable-
 libopus --enable-frei0r --enable-libcaca --enable-libsoxr --enable-libquvi
 --enable-libvidstab --enable-libx265 --enable-libwebp --enable-libopenjpeg
 --disable-decoder=jpeg2000 --extra-
 cflags=-I/usr/local/Cellar/openjpeg/1.5.2_1/include/openjpeg-1.5 --enable-
 nonfree --enable-vda
       libavutil      54. 31.100 / 54. 31.100
       libavcodec     56. 60.100 / 56. 60.100
       libavformat    56. 40.101 / 56. 40.101
       libavdevice    56.  4.100 / 56.  4.100
       libavfilter     5. 40.101 /  5. 40.101
       libavresample   2.  1.  0 /  2.  1.  0
       libswscale      3.  1.101 /  3.  1.101
       libswresample   1.  2.101 /  1.  2.101
       libpostproc    53.  3.100 / 53.  3.100
     Input #0, mov,mp4,m4a,3gp,3g2,mj2, from './mezzanine.mp4':
       Metadata:
         major_brand     : isom
         minor_version   : 512
         compatible_brands: isomiso2avc1mp41
         encoder         : Lavf56.40.101
       Duration: 00:00:14.01, start: 0.000000, bitrate: 394 kb/s
         Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p,
 1920x1080 [SAR 1:1 DAR 16:9], 393 kb/s, 29.97 fps, 29.97 tbr, 30k tbn,
 59.94 tbc (default)
         Metadata:
           handler_name    : VideoHandler
     [libx264 @ 0x7f9fe181e600] using SAR=1/1
     [libx264 @ 0x7f9fe181e600] using cpu capabilities: MMX2 SSE2Fast SSSE3
 SSE4.2
     [libx264 @ 0x7f9fe181e600] profile Main, level 3.1
     Output #0, hls, to './test_mediaplaylist_1280x720.m3u8':
       Metadata:
         major_brand     : isom
         minor_version   : 512
         compatible_brands: isomiso2avc1mp41
         encoder         : Lavf56.40.101
         Stream #0:0(und): Video: h264 (libx264), yuv420p, 1280x720 [SAR
 1:1 DAR 16:9], q=-1--1, 2400 kb/s, 29.97 fps, 90k tbn, 29.97 tbc (default)
         Metadata:
           handler_name    : VideoHandler
           encoder         : Lavc56.60.100 libx264
     Stream mapping:
       Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
     Press [q] to stop, [?] for help
     frame=  420 fps= 43 q=-1.0 Lsize=N/A time=00:00:13.94 bitrate=N/A
     video:1275kB audio:0kB subtitle:0kB other streams:0kB global
 headers:0kB muxing overhead: unknown
     [libx264 @ 0x7f9fe181e600] frame I:7     Avg QP: 0.82  size: 24041
     [libx264 @ 0x7f9fe181e600] frame P:413   Avg QP: 1.21  size:  2754
     [libx264 @ 0x7f9fe181e600] mb I  I16..4: 89.6%  0.0% 10.4%
     [libx264 @ 0x7f9fe181e600] mb P  I16..4:  8.2%  0.0%  0.1%  P16..4:
 6.6%  1.1%  0.7%  0.0%  0.0%    skip:83.4%
     [libx264 @ 0x7f9fe181e600] coded y,uvDC,uvAC intra: 1.8% 7.7% 7.6%
 inter: 1.4% 4.9% 4.5%
     [libx264 @ 0x7f9fe181e600] i16 v,h,dc,p: 99%  0%  0%  0%
     [libx264 @ 0x7f9fe181e600] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 60% 20% 13%
 3%  1%  1%  0%  1%  0%
     [libx264 @ 0x7f9fe181e600] i8c dc,h,v,p: 12%  1% 85%  1%
     [libx264 @ 0x7f9fe181e600] Weighted P-Frames: Y:0.0% UV:0.0%
     [libx264 @ 0x7f9fe181e600] ref P L0: 74.9%  0.5% 17.8%  6.8%
     [libx264 @ 0x7f9fe181e600] kb/s:745.37
 }}}

 Now inspect the m3u8...
 {{{
 $ cat ./test_mediaplaylist_1280x720.m3u8
     #EXTM3U
     #EXT-X-VERSION:3
     #EXT-X-TARGETDURATION:7
     #EXT-X-MEDIA-SEQUENCE:0
     #EXTINF:6.006000,
     test_1280x720_000.ts
     #EXTINF:6.006000,
     test_1280x720_001.ts
     #EXTINF:1.968633,
     test_1280x720_002.ts
     #EXT-X-ENDLIST
 }}}

 FFprobe sums the EXTINF values of the m3u8 and calculates a duration of
 13.980633 not 14.014000
 {{{
 $ ffprobe -loglevel quiet -print_format flat -show_entries format=duration
 "./test_mediaplaylist_1280x720.m3u8"
 format.duration="13.980633"
 }}}

 Analyzing each MPEG-TS segment using FFprobe (MediaInfo also confirms
 FFprobe's results)
 {{{
 $ ffprobe -loglevel quiet -print_format flat -show_entries format=duration
 "./test_1280x720_000.ts"
 format.duration="6.006000"
 $ ffprobe -loglevel quiet -print_format flat -show_streams -select_streams
 v -show_entries stream=duration "./test_1280x720_000.ts"
 programs.program.0.streams.stream.0.duration="6.006000"
 streams.stream.0.duration="6.006000"

 $ ffprobe -loglevel quiet -print_format flat -show_entries format=duration
 "./test_1280x720_001.ts"
 format.duration="6.006000"
 $ ffprobe -loglevel quiet -print_format flat -show_streams -select_streams
 v -show_entries stream=duration "./test_1280x720_001.ts"
 programs.program.0.streams.stream.0.duration="6.006000"
 streams.stream.0.duration="6.006000"

 $ ffprobe -loglevel quiet -print_format flat -show_entries format=duration
 "./test_1280x720_002.ts"
 format.duration="2.002000"
 $ ffprobe -loglevel quiet -print_format flat -show_streams -select_streams
 v -show_entries stream=duration "./test_1280x720_002.ts"
 programs.program.0.streams.stream.0.duration="2.002000"
 streams.stream.0.duration="2.002000"
 }}}

 (6.006 + 6.006 + 2.002) = 14.014s, as expected.

 But the sum of the EXTINF durations in the mediaplaylist.m3u8 is (6.006000
 + 6.006000 + 1.968633) = 13.980633s.  The discrepancy is caused by the
 duration of the last segment getting under-reported.

 Although this seems a small difference within this example, we have seen
 quite significant differences depending on the source file.  The example
 uses a 14s testsrc as it is the simplest way to reproduce the issue with
 the minimum number of segments.  But the issue occurs with any source
 file.

 The last segment's declared EXTINF duration in the m3u8 is always lower
 than the actual MPEG-TS duration.

 Thanks!

--
Ticket URL: <https://trac.ffmpeg.org/ticket/5009>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list