[FFmpeg-user] Fixed GOP encoding for HLS

Stefano Sabatini stefasab at gmail.com
Wed Dec 12 11:52:40 CET 2012


On date Wednesday 2012-12-12 15:56:03 +1100, Andrew Sinclair wrote:
> To wrap this one up and assist anyone else trying to do this here is how I
> am achieving good results i.e. nicely aligned m3u8 files. Though there is
> definitely some issue in regard to the lengths of the segments as reported
> in the m3u8 files.
> 
> In summary best thing I have found so far is to drop the scenecut frame
> hints i.e. -g and -keyint_min and only add the -force_key_frames
> 

> Apologies for the format of the output below but I have had to wrap this
> all up in a series of Python scripts where I am also using ffprobe to check
> that I have keyframes exactly where I want them.
> 
> Encode cmd: ffmpeg -y -i /home/parallels/Videos/131375031.mp4 -pix_fmt
> yuv420p -vcodec libx264 -r 24.0     -profile:v baseline -b:v 500k -maxrate
> 500k  -force_key_frames

> 0:00:06,0:00:12,0:00:18,0:00:24,0:00:30,0:00:36,0:00:42,0:00:48,0:00:54,0:01:00,0:01:06,0:01:12,0:01:18,0:01:24,0:01:30,0:01:36,0:01:42,0:01:48,0:01:54,0:02:00,0:02:06,0:02:12,0:02:18,0:02:24,0:02:30,0:02:36,0:02:42,0:02:48,0:02:54,0:03:00,0:03:06,0:03:12,0:03:18,0:03:24,0:03:30,0:03:36,0:03:42,0:03:48,0:03:54,0:04:00,0:04:06,0:04:12,0:04:18,0:04:24,0:04:30,0:04:36,0:04:42,0:04:48,0:04:54,0:05:00,0:05:06,0:05:12,0:05:18,0:05:24,0:05:30,0:05:36,0:05:42

I think you can write the number of seconds, like 6,12,18,...

Also maybe we should support reading from a file, or an expression of
the type force_key_frames_expr gt(n*6-delta)*lt(n*6-delta)

>      -s 640x360
[...]
> ffprobe -show_frames
> /home/parallels/encodes/hls/131375031/131375031_500_640x360.ts
> 
> ##### This is my parsed output showing that I have I frames exactly where I
> want them ####
> Found I frame as expected at 144.0
> Found I frame as expected at 288.0
> Found I frame as expected at 432.0
[...]

These doesn't match with the specified times (or are they frames
numbers?).

[...] 
> #### This is the full list of I Frames generated which shows additional
> frames likely generated on scenecut so maintains maximum efficiency/quality
> trade off
> 
> 0,3,83,110,144,185,245,288,299,355,432,446,522,562,576,603,652,712,720,827,864,869,922,954,1008,1029,1090,1123,1139,1152,1177,1210,1238,1275,1296,1301,1331,1373,1398,1435,1440,1460,1479,1514,1584,1614,1633,1664,1695,1710,1727,1728,1746,1768,1797,1814,1835,1872,1998,2014,2016,2033,2042,2077,2132,2148,2160,2164,2204,2225,2252,2271,2282,2304,2319,2376,2399,2431,2448,2512,2513,2514,2535,2555,2575,2592,2613,2686,2736,2779,2880,2903,3024,3034,3064,3168,3194,3237,3266,3279,3291,3312,3323,3358,3442,3450,3456,3489,3578,3600,3604,3634,3682,3744,3888,3930,3975,4024,4032,4092,4131,4176,4194,4253,4265,4303,4320,4367,4397,4434,4464,4483,4512,4551,4608,4624,4689,4752,4803,4840,4896,4945,5007,5040,5066,5102,5141,5170,5184,5196,5211,5223,5237,5246,5266,5297,5318,5328,5373,5388,5413,5441,5457,5472,5490,5564,5616,5647,5694,5704,5742,5760,5899,5904,5936,5974,6048,6052,6070,6092,6119,6132,6155,6166,6180,6192,6206,6226,6239,6269,6291,6317,6332,6336,6340,6351,6366,6376,6384,6397,6406,6415,6426,6433
>  ,6456,6480,6528,6553,6577,6590,6602,6611,6619,6624,6628,6639,6649,6654,6669,6704,6751,6768,6816,6832,6855,6903,6912,6916,6937,6945,7008,7056,7200,7344,7488,7632,7776,7920,8064,8208,
[...] 
> Segmenting file: ffmpeg -y -i
> /home/parallels/encodes/hls/131375031/131375031_500_640x360.ts -codec copy
> -map 0 -f segment -segment_list
> /home/parallels/encodes/hls/131375031/index_500.m3u8 -segment_time 6
>  -segment_list_type m3u8 131375031_500_640x360_%03d.ts
> ('', "ffmpeg version N-45739-g04bf2e7 Copyright (c) 2000-2012 the FFmpeg
> developers\n  built on Oct 20 2012 13:34:12 with gcc 4.6 (Ubuntu/Linaro
> 4.6.3-1ubuntu5)\n  configuration: --enable-gpl --enable-libfaac
> --enable-libfdk-aac --enable-libmp3lame --enable-libopencore-amrnb
> --enable-libopencore-amrwb --enable-librtmp --enable-libtheora
> --enable-libvorbis --enable-libvpx --enable-x11grab --enable-libx264
> --enable-nonfree --enable-version3\n  libavutil      51. 76.100 / 51.
> 76.100\n  libavcodec     54. 67.100 / 54. 67.100\n  libavformat    54.
> 33.100 / 54. 33.100\n  libavdevice    54.  3.100 / 54.  3.100\n
>  libavfilter     3. 19.103 /  3. 19.103\n  libswscale      2.  1.101 /  2.
>  1.101\n  libswresample   0. 16.100 /  0. 16.100\n  libpostproc    52.
>  1.100 / 52.  1.100\n[mpegts @ 0x302f260] max_analyze_duration 5000000
> reached at 5015467\nInput #0, mpegts, from
> '/home/parallels/encodes/hls/131375031/131375031_500_640x360.ts':\n
>  Duration: 00:05:45.34, start: 1.389089, bitrate: 658 kb/s\n  Program 1 \n
>    Metadata:\n      service_name    : Service01\n      service_provider:
> FFmpeg\n    Stream #0:0[0x100]: Video: h264 (Constrained Baseline)
> ([27][0][0][0] / 0x001B), yuv420p, 640x360 [SAR 1:1 DAR 16:9], 24 fps, 24
> tbr, 90k tbn, 48 tbc\n    Stream #0:1[0x101](und): Audio: mp2 ([3][0][0][0]
> / 0x0003), 44100 Hz, stereo, s16, 128 kb/s\nOutput #0, segment, to
> '131375031_500_640x360_%03d.ts':\n  Metadata:\n    encoder         :
> Lavf54.33.100\n    Stream #0:0: Video: h264 ([27][0][0][0] / 0x001B),
> yuv420p, 640x360 [SAR 1:1 DAR 16:9], q=2-31, 24 fps, 90k tbn, 24 tbc\n
>  Stream #0:1(und): Audio: mp2 ([3][0][0][0] / 0x0003), 44100 Hz, stereo,
> 128 kb/s\nStream mapping:\n  Stream #0:0 -> #0:0 (copy)\n  Stream #0:1 ->
> #0:1 (copy)\nPress [q] to stop, [?] for help\nframe= 8289 fps=0.0 q=-1.0
> Lsize=       0kB time=00:05:45.41 bitrate=   0.0kbits/s
>  \r\nvideo:19380kB audio:5397kB subtitle:0 global headers:0kB muxing
> overhead -100.000000%\n")
> Finish UTC time: 1355287042.41
> 
> Segments then generate nicely aligned m3u8 however there is still something
> a little odd with the rounding on the fragment sizes which don't appear to
> line up with the actual fragment sizes.
> 
> #EXTM3U
> #EXT-X-VERSION:3
> #EXT-X-MEDIA-SEQUENCE:0
> #EXT-X-ALLOWCACHE:1
> #EXTINF:6.034289,
> 131375031_3500_1280x720_000.ts
> #EXTINF:6.005422,
> 131375031_3500_1280x720_001.ts
> #EXTINF:6.013578,
> 131375031_3500_1280x720_002.ts
> #EXTINF:6.021744,
> 131375031_3500_1280x720_003.ts
> #EXTINF:6.003789,
> 131375031_3500_1280x720_004.ts
> #EXTINF:6.011944,
> 131375031_3500_1280x720_005.ts
> #EXTINF:6.020111,
> 131375031_3500_1280x720_006.ts
> #EXTINF:6.002156,
> 131375031_3500_1280x720_007.ts
> #EXTINF:6.010322,
> 131375031_3500_1280x720_008.ts
> #EXTINF:6.018478,
> 131375031_3500_1280x720_009.ts
> #EXTINF:6.000522,
> 131375031_3500_1280x720_010.ts
> #EXTINF:6.008689,
> 131375031_3500_1280x720_011.ts
> #EXTINF:6.016844,
> 131375031_3500_1280x720_012.ts
> #EXTINF:6.025011,
> 131375031_3500_1280x720_013.ts
> #EXTINF:6.007056,
> 131375031_3500_1280x720_014.ts
> #EXTINF:6.015211,
> 131375031_3500_1280x720_015.ts
> #EXTINF:6.023378,
> 131375031_3500_1280x720_016.ts
> #EXTINF:6.005422,
> 131375031_3500_1280x720_017.ts
> #EXTINF:6.013578,
> 131375031_3500_1280x720_018.ts
> #EXTINF:6.021744,
> 131375031_3500_1280x720_019.ts
> #EXTINF:6.003789,
> 131375031_3500_1280x720_020.ts
> #EXTINF:6.011944,
> 131375031_3500_1280x720_021.ts
> #EXTINF:6.020111,
> 131375031_3500_1280x720_022.ts
> #EXTINF:6.002156,
> 131375031_3500_1280x720_023.ts
> #EXTINF:6.010322,
> 131375031_3500_1280x720_024.ts
> #EXTINF:6.018478,
> 131375031_3500_1280x720_025.ts
> #EXTINF:6.000522,
> 131375031_3500_1280x720_026.ts
> #EXTINF:6.008689,
> 131375031_3500_1280x720_027.ts
> #EXTINF:6.016844,
> 131375031_3500_1280x720_028.ts
> #EXTINF:6.025011,
> 131375031_3500_1280x720_029.ts
> #EXTINF:6.007056,
> 131375031_3500_1280x720_030.ts
> #EXTINF:6.015211,
> 131375031_3500_1280x720_031.ts
> #EXTINF:6.023378,
> 131375031_3500_1280x720_032.ts
> #EXTINF:6.005422,
> 131375031_3500_1280x720_033.ts
> #EXTINF:6.013578,
> 131375031_3500_1280x720_034.ts
> #EXTINF:6.021744,
> 131375031_3500_1280x720_035.ts
> #EXTINF:6.003789,
> 131375031_3500_1280x720_036.ts
> #EXTINF:6.011944,
> 131375031_3500_1280x720_037.ts
> #EXTINF:6.020111,
> 131375031_3500_1280x720_038.ts
> #EXTINF:6.002156,
> 131375031_3500_1280x720_039.ts
> #EXTINF:6.010322,
> 131375031_3500_1280x720_040.ts
> #EXTINF:6.018478,
> 131375031_3500_1280x720_041.ts
> #EXTINF:6.000522,
> 131375031_3500_1280x720_042.ts
> #EXTINF:6.008689,
> 131375031_3500_1280x720_043.ts
> #EXTINF:6.016844,
> 131375031_3500_1280x720_044.ts
> #EXTINF:6.025011,
> 131375031_3500_1280x720_045.ts
> #EXTINF:6.007056,
> 131375031_3500_1280x720_046.ts
> #EXTINF:6.015211,
> 131375031_3500_1280x720_047.ts
> #EXTINF:6.023378,
> 131375031_3500_1280x720_048.ts
> #EXTINF:6.005422,
> 131375031_3500_1280x720_049.ts
> #EXTINF:6.013578,
> 131375031_3500_1280x720_050.ts
> #EXTINF:6.021744,
> 131375031_3500_1280x720_051.ts
> #EXTINF:6.003789,
> 131375031_3500_1280x720_052.ts
> #EXTINF:6.011944,
> 131375031_3500_1280x720_053.ts
> #EXTINF:6.020111,
> 131375031_3500_1280x720_054.ts
> #EXTINF:6.002156,
> 131375031_3500_1280x720_055.ts
> #EXTINF:6.010322,
> 131375031_3500_1280x720_056.ts
> #EXTINF:3.406233,
> 131375031_3500_1280x720_057.ts
> #EXT-X-TARGETDURATION:7
> #EXT-X-ENDLIST
> 
> However if I check the actual fragments using ffprobe it reports a
> different length to in the m3u8
> 
> ffprobe 131375031_3500_1280x720_000.ts
> ffprobe version N-45739-g04bf2e7 Copyright (c) 2007-2012 the FFmpeg
> developers
>   built on Oct 20 2012 13:34:12 with gcc 4.6 (Ubuntu/Linaro 4.6.3-1ubuntu5)
>   configuration: --enable-gpl --enable-libfaac --enable-libfdk-aac
> --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb
> --enable-librtmp --enable-libtheora --enable-libvorbis --enable-libvpx
> --enable-x11grab --enable-libx264 --enable-nonfree --enable-version3
>   libavutil      51. 76.100 / 51. 76.100
>   libavcodec     54. 67.100 / 54. 67.100
>   libavformat    54. 33.100 / 54. 33.100
>   libavdevice    54.  3.100 / 54.  3.100
>   libavfilter     3. 19.103 /  3. 19.103
>   libswscale      2.  1.101 /  2.  1.101
>   libswresample   0. 16.100 /  0. 16.100
>   libpostproc    52.  1.100 / 52.  1.100
> [mpegts @ 0x17e6c20] max_analyze_duration 5000000 reached at 5015467
> Input #0, mpegts, from '131375031_3500_1280x720_000.ts':
>   Duration: 00:00:06.00, start: 0.000000, bitrate: 3038 kb/s

This is possibly an approximation of the duration.

>   Program 1
>     Metadata:
>       service_name    : Service01
>       service_provider: FFmpeg
>     Stream #0:0[0x100]: Video: h264 (Constrained Baseline) ([27][0][0][0] /
> 0x001B), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 24 fps, 24 tbr, 90k tbn, 48
> tbc
>     Stream #0:1[0x101]: Audio: mp2 ([3][0][0][0] / 0x0003), 44100 Hz,
> stereo, s16, 128 kb/s
> 

> If anyone is still reading down here next step I will have a look at
> segment.c where I believe this is getting done.

What I did in a similar situation:

you set -force_key_frames with the list of frames, note that it is not
perfectly accurate because of approximations so the actual I-frames
may be placed before or after the specified time (this because you
can't predict the position of video frames in the stream).

No need to mess with encoder GOP options, since -force_key_frames
overrides it, unless you want to avoid intermediary I-frames in order
to reduce bandwidth. B-frames should be avoided.

Then you pass the same list to -segment_times, and specify a
segment_time_delta which is good enough for you (it may depends on the
input, for constant frame rate (1/frame_rate) * 1/2 should be safe).

An option to pass a file containing a list of times read by both
-force_key_frames and -segment_times may be good to simplify
scripting.
-- 
FFmpeg = Frightening and Fanciful Mega Patchable Exciting Gargoyle


More information about the ffmpeg-user mailing list