What is the correct way to fix keyframes in FFmpeg for DASH? Announcing the arrival of Valued...
Weaponising the Grasp-at-a-Distance spell
Does traveling In The United States require a passport or can I use my green card if not a US citizen?
How to produce a PS1 prompt in bash or ksh93 similar to tcsh
Why are two-digit numbers in Jonathan Swift's "Gulliver's Travels" (1726) written in "German style"?
What documents does someone with a long-term visa need to travel to another Schengen country?
Why aren't these two solutions equivalent? Combinatorics problem
“Since the train was delayed for more than an hour, passengers were given a full refund.” – Why is there no article before “passengers”?
"Destructive force" carried by a B-52?
How do I deal with an erroneously large refund?
Why did Israel vote against lifting the American embargo on Cuba?
What kind of equipment or other technology is necessary to photograph sprites (atmospheric phenomenon)
Will the Antimagic Field spell cause elementals not summoned by magic to dissipate?
Recursive calls to a function - why is the address of the parameter passed to it lowering with each call?
What is the difference between 准时 and 按时?
Sorting the characters in a utf-16 string in java
Can gravitational waves pass through a black hole?
Compiling and throwing simple dynamic exceptions at runtime for JVM
Marquee sign letters
What were wait-states, and why was it only an issue for PCs?
Is Bran literally the world's memory?
Is my guitar’s action too high?
Is there a verb for listening stealthily?
How to break 信じようとしていただけかも知れない into separate parts?
Can this water damage be explained by lack of gutters and grading issues?
What is the correct way to fix keyframes in FFmpeg for DASH?
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)FFMPEG how to control number of i-frames in encoded video?FFMPEG: Stream a file with original playing rateProblems with frame rate on video conversion using ffmpeg with libx264What ffmpeg command line matches the one YouTube uses?FFMPEG / libx264: How to specify a variable frame rate but with a maximum?How do I use ffmpeg to split a video into images and then reassemble exactly the same?FFMPEG: How to split a video *NOT* on a GOP boundary/Keyframe WITHOUT transcoding?How to use ffmpeg with keyframesHow to encode one input file to multiple HLS streams with FFmpeg including the master playlistWhat is the difference between webm and webm_chunk?ffmpeg looping audio on slideshow the best way
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
When conditioning a stream for DASH playback, random access points must be at the exact same source stream time in all streams. The usual way to do this is to force a fixed frame rate and fixed GOP length (i.e. a keyframe every N frames).
In FFmpeg, fixed frame rate is easy (-r NUMBER).
But for fixed keyframe locations (GOP length), there are three methods...which one is "correct"? The FFmpeg documentation is frustratingly vague on this.
Method 1: messing with libx264's arguments
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
There seems to be some debate if scenecut should be turned off or not, as it is unclear if the keyframe "counter" is restarted when a scene cut happens.
Method 2: setting a fixed GOP size:
-g GOP_LEN_IN_FRAMES
This is unfortunately only documented in passing in the FFMPEG documentation, and thus the effect of this argument is very unclear.
Method 3: insert a keyframe every N seconds (Maybe?):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
This is explicitly documented. But it is still not immediately clear if the "time counter" restarts after every key frame. For instance, in an expected 5-second GOP, if there is a scenecut
keyframe injected 3 seconds in by libx264, would the next keyframe be 5 seconds later or 2 seconds later?
In fact, the FFmpeg documentation differentiates between this and the -g
option, but it doesn't really say how these two options above are the least bit different (obviously, -g
is going to require a fixed frame rate).
Which is right?
It would seem that the -force_key_frames
would be superior, as it would not require a fixed frame rate. However, this requires that
- it conforms to GOP specifications in H.264 (if any)
- it GUARANTEES that there would be a keyframe in fixed cadence, irrespective of libx264
scenecut
keyframes.
It would also seem that -g
could not work without forcing a fixed frame rate (-r
), as there is no guarantee that multiple runs of ffmpeg
with different codec arguments would provide the same instantaneous frame rate in each resolution. Fixed frame rates may reduce compression performance (IMPORTANT in a DASH scenario!).
Finally, the keyint
method just seems like a hack. I hope against hope that this isn't the correct answer.
References:
An example using the -force_key_frames
method
An example using the keyint
method
FFmpeg advanced video options section
video ffmpeg streaming video-conversion
add a comment |
When conditioning a stream for DASH playback, random access points must be at the exact same source stream time in all streams. The usual way to do this is to force a fixed frame rate and fixed GOP length (i.e. a keyframe every N frames).
In FFmpeg, fixed frame rate is easy (-r NUMBER).
But for fixed keyframe locations (GOP length), there are three methods...which one is "correct"? The FFmpeg documentation is frustratingly vague on this.
Method 1: messing with libx264's arguments
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
There seems to be some debate if scenecut should be turned off or not, as it is unclear if the keyframe "counter" is restarted when a scene cut happens.
Method 2: setting a fixed GOP size:
-g GOP_LEN_IN_FRAMES
This is unfortunately only documented in passing in the FFMPEG documentation, and thus the effect of this argument is very unclear.
Method 3: insert a keyframe every N seconds (Maybe?):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
This is explicitly documented. But it is still not immediately clear if the "time counter" restarts after every key frame. For instance, in an expected 5-second GOP, if there is a scenecut
keyframe injected 3 seconds in by libx264, would the next keyframe be 5 seconds later or 2 seconds later?
In fact, the FFmpeg documentation differentiates between this and the -g
option, but it doesn't really say how these two options above are the least bit different (obviously, -g
is going to require a fixed frame rate).
Which is right?
It would seem that the -force_key_frames
would be superior, as it would not require a fixed frame rate. However, this requires that
- it conforms to GOP specifications in H.264 (if any)
- it GUARANTEES that there would be a keyframe in fixed cadence, irrespective of libx264
scenecut
keyframes.
It would also seem that -g
could not work without forcing a fixed frame rate (-r
), as there is no guarantee that multiple runs of ffmpeg
with different codec arguments would provide the same instantaneous frame rate in each resolution. Fixed frame rates may reduce compression performance (IMPORTANT in a DASH scenario!).
Finally, the keyint
method just seems like a hack. I hope against hope that this isn't the correct answer.
References:
An example using the -force_key_frames
method
An example using the keyint
method
FFmpeg advanced video options section
video ffmpeg streaming video-conversion
add a comment |
When conditioning a stream for DASH playback, random access points must be at the exact same source stream time in all streams. The usual way to do this is to force a fixed frame rate and fixed GOP length (i.e. a keyframe every N frames).
In FFmpeg, fixed frame rate is easy (-r NUMBER).
But for fixed keyframe locations (GOP length), there are three methods...which one is "correct"? The FFmpeg documentation is frustratingly vague on this.
Method 1: messing with libx264's arguments
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
There seems to be some debate if scenecut should be turned off or not, as it is unclear if the keyframe "counter" is restarted when a scene cut happens.
Method 2: setting a fixed GOP size:
-g GOP_LEN_IN_FRAMES
This is unfortunately only documented in passing in the FFMPEG documentation, and thus the effect of this argument is very unclear.
Method 3: insert a keyframe every N seconds (Maybe?):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
This is explicitly documented. But it is still not immediately clear if the "time counter" restarts after every key frame. For instance, in an expected 5-second GOP, if there is a scenecut
keyframe injected 3 seconds in by libx264, would the next keyframe be 5 seconds later or 2 seconds later?
In fact, the FFmpeg documentation differentiates between this and the -g
option, but it doesn't really say how these two options above are the least bit different (obviously, -g
is going to require a fixed frame rate).
Which is right?
It would seem that the -force_key_frames
would be superior, as it would not require a fixed frame rate. However, this requires that
- it conforms to GOP specifications in H.264 (if any)
- it GUARANTEES that there would be a keyframe in fixed cadence, irrespective of libx264
scenecut
keyframes.
It would also seem that -g
could not work without forcing a fixed frame rate (-r
), as there is no guarantee that multiple runs of ffmpeg
with different codec arguments would provide the same instantaneous frame rate in each resolution. Fixed frame rates may reduce compression performance (IMPORTANT in a DASH scenario!).
Finally, the keyint
method just seems like a hack. I hope against hope that this isn't the correct answer.
References:
An example using the -force_key_frames
method
An example using the keyint
method
FFmpeg advanced video options section
video ffmpeg streaming video-conversion
When conditioning a stream for DASH playback, random access points must be at the exact same source stream time in all streams. The usual way to do this is to force a fixed frame rate and fixed GOP length (i.e. a keyframe every N frames).
In FFmpeg, fixed frame rate is easy (-r NUMBER).
But for fixed keyframe locations (GOP length), there are three methods...which one is "correct"? The FFmpeg documentation is frustratingly vague on this.
Method 1: messing with libx264's arguments
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
There seems to be some debate if scenecut should be turned off or not, as it is unclear if the keyframe "counter" is restarted when a scene cut happens.
Method 2: setting a fixed GOP size:
-g GOP_LEN_IN_FRAMES
This is unfortunately only documented in passing in the FFMPEG documentation, and thus the effect of this argument is very unclear.
Method 3: insert a keyframe every N seconds (Maybe?):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
This is explicitly documented. But it is still not immediately clear if the "time counter" restarts after every key frame. For instance, in an expected 5-second GOP, if there is a scenecut
keyframe injected 3 seconds in by libx264, would the next keyframe be 5 seconds later or 2 seconds later?
In fact, the FFmpeg documentation differentiates between this and the -g
option, but it doesn't really say how these two options above are the least bit different (obviously, -g
is going to require a fixed frame rate).
Which is right?
It would seem that the -force_key_frames
would be superior, as it would not require a fixed frame rate. However, this requires that
- it conforms to GOP specifications in H.264 (if any)
- it GUARANTEES that there would be a keyframe in fixed cadence, irrespective of libx264
scenecut
keyframes.
It would also seem that -g
could not work without forcing a fixed frame rate (-r
), as there is no guarantee that multiple runs of ffmpeg
with different codec arguments would provide the same instantaneous frame rate in each resolution. Fixed frame rates may reduce compression performance (IMPORTANT in a DASH scenario!).
Finally, the keyint
method just seems like a hack. I hope against hope that this isn't the correct answer.
References:
An example using the -force_key_frames
method
An example using the keyint
method
FFmpeg advanced video options section
video ffmpeg streaming video-conversion
video ffmpeg streaming video-conversion
edited 5 hours ago
JakeGould
33k10100142
33k10100142
asked Apr 30 '15 at 19:16
Mark GerolimatosMark Gerolimatos
6642819
6642819
add a comment |
add a comment |
6 Answers
6
active
oldest
votes
TL;DR
I would recommend the following:
libx264
:-g X -keyint_min X
(and optionally add-force_key_frames "expr:gte(t,n_forced*N)"
)
libx265
:-x265-params "keyint=X:min-keyint=X"
libvpx-vp9
:-g X
where X
is the interval in frames and N
is the interval in seconds. For example, for a 2-second interval with a 30fps video, X
= 60 and N
= 2.
A note about different frame types
In order to properly explain this topic, we first have to define the two types of I-frames / keyframes:
- Instantaneous Decoder Refresh (IDR) frames: These allow independent decoding of the following frames, without access to frames previous to the IDR frame.
- Non-IDR-frames: These require a previous IDR frame for the decoding to work. Non-IDR frames can be used for scene cuts in the middle of a GOP (group of pictures).
What is recommended for streaming?
For the streaming case, you want to:
- Ensure that all IDR frames are at regular positions (e.g. at 2, 4, 6, … seconds) so that the video can be split up into segments of equal length.
- Enable scene cut detection, so as to improve coding efficiency / quality. This means allowing I-frames to be placed in between IDR frames. You can still work with scene cut detection disabled (and this is part of many guides, still), but it's not necessary.
What do the parameters do?
In order to configure the encoder, we have to understand what the keyframe parameters do. I did some tests and discovered the following, for the three encoders libx264
, libx265
and libvpx-vp9
in FFmpeg:
libx264
:
-g
sets the keyframe interval.
-keyint_min
sets the minimum keyframe interval.
-x264-params "keyint=x:min-keyint=y"
is the same as-g x -keyint_min y
.
Note: When setting both to the same value, the minimum is internally set to half the maximum interval plus one, as seen in the
x264
code:
h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
libx265
:
-g
is not implemented.
-x265-params "keyint=x:min-keyint=y"
works.
libvpx-vp9
:
-g
sets the keyframe interval.
-keyint_min
sets the minimum keyframe interval
Note: Due to how FFmpeg works,
-keyint_min
is only forwarded to the encoder when it is the same as-g
. In the code fromlibvpxenc.c
in FFmpeg we can find:
if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
enccfg.kf_min_dist = avctx->keyint_min;
if (avctx->gop_size >= 0)
enccfg.kf_max_dist = avctx->gop_size;
This might be a bug (or lack of feature?), since
libvpx
definitely supports setting a different value forkf_min_dist
.
Should you use -force_key_frames
?
The -force_key_frames
option forcibly inserts keyframes at the given interval (expression). This works for all encoders, but it might mess with the rate control mechanism. Especially for VP9, I've noticed severe quality fluctuations, so I cannot recommend using it in this case.
Thank you! This is great feedback. One question I have is how you generated that awesome table. I could totally use something like that.
– Mark Gerolimatos
Apr 30 '15 at 21:39
(There appears to be no way to write you directly) Can you please point me towards links to any threads in this ITU-T discussion? Thanks!
– Mark Gerolimatos
Apr 30 '15 at 21:45
2
I just made that in Excel, pasting the output I got from three runs offfprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, then coloring the cells. I'm afraid there are no public discussions, but I'll see if I can dig up some of the links I found back then.
– slhck
Apr 30 '15 at 22:01
Could you please re-try your experiment with the-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
form? I just tried it and found that while there were extra I frames in the stream, it DID seem to abide by my rule. A PERL program will follow as an "answer", as you cannot apparently use markup in comments.
– Mark Gerolimatos
May 1 '15 at 1:08
Interesting. I believe it's worth a separate "real" answer if you found out that it works. (Stack Exchange sites aren't really good for this discussion-style reply.) The last time I checked,-force_key_frames
didn't work for me, and so I never tried it again. That was more than a year ago. Perhaps it was a bug. I'll try again soon.
– slhck
May 1 '15 at 8:00
add a comment |
Here is my fifty cents for the case.
Method 1:
messing with libx264's arguments
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
Generate iframes only at the desired intervals.
Example 1:
ffmpeg -i test.mp4 -codec:v libx264
-r 23.976
-x264opts "keyint=48:min-keyint=48:no-scenecut"
-c:a copy
-y test_keyint_48.mp4
Generate iframes as expected like this:
Iframes Seconds
1 0
49 2
97 4
145 6
193 8
241 10
289 12
337 14
385 16
433 18
481 20
529 22
577 24
625 26
673 28
721 30
769 32
817 34
865 36
913 38
961 40
1009 42
1057 44
1105 46
1153 48
1201 50
1249 52
1297 54
1345 56
1393 58
Method 2 is depreciated. Ommitted.
Method 3:
insert a keyframe every N seconds (MAYBE):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
Example 2
ffmpeg -i test.mp4 -codec:v libx264
-r 23.976
-force_key_frames "expr:gte(t,n_forced*2)"
-c:a copy
-y test_fkf_2.mp4
Generate an iframes in a slightly different way:
Iframes Seconds
1 0
49 2
97 4
145 6
193 8
241 10
289 12
337 14
385 16
433 18
481 20
519 21.58333333
529 22
577 24
625 26
673 28
721 30
769 32
817 34
865 36
913 38
931 38.75
941 39.16666667
961 40
1008 42
1056 44
1104 46
1152 48
1200 50
1248 52
1296 54
1305 54.375
1344 56
1367 56.95833333
1392 58
1430 59.58333333
1440 60
1475 61.45833333
1488 62
1536 64
1544 64.33333333
1584 66
1591 66.29166667
1632 68
1680 70
1728 72
1765 73.54166667
1776 74
1811 75.45833333
1824 75.95833333
1853 77.16666667
1872 77.95833333
1896 78.95833333
1920 79.95833333
1939 80.75
1968 81.95833333
As you can see it places iframes every 2 seconds AND on scenecut (seconds with floating part) which is important for video stream complexity in my opinion.
Genearated file sizes are pretty the same. Very strange that even with more keyframes in Method 3 it generates sometimes less file than standard x264 library algorithm.
For generating multiple bitrate files for HLS stream we choose method three. It perfectly aligned with 2 seconds between chunks, they have iframe at the beginning of every chunk and they have additional iframes on complex scenes which provides better experience for users who has an outdated devices and can not playback x264 high profiles.
Hope it helps someone.
Fantastic, thanks for your 50 cents!
– BrunoFenzl
Oct 12 '16 at 22:23
add a comment |
The answer therefore seems to be:
- Method 1 is verified to work, but is
libx264
-specific, and comes at the cost of eliminating the very usefulscenecut
option inlibx264
. - Method 3 works as of the FFMPEG version of April 2015, but you should verify your results with with the script included at the bottom of this post, as the FFMPEG documentation is unclear as to the effect of the option. If it works, it is the superior of the two options.
DO NOT USE Method 2,-g
appears to be deprecated. It neither appears to work, nor is it explicitly defined in the documentation, nor is found in the help, nor does it appear to be used in the code. Code inspection shows that the-g
option is likely meant for MPEG-2 streams (there are even code stanzas referring to PAL and NTSC!).
Also:
- Files generated with Method 3 may be slightly larger than Method 1, as
interstitial I frames (keyframes) are allowed. - You should explicitly set the "-r" flag in both cases, even though Method 3 places an I frame at the next frameslot on or after the time specified. Failure to set the "-r" flag places you at the mercy of the source file, possibly with a variable frame rate. Incompatible DASH transitions may result.
- Despite the warnings in the FFMPEG documentation, method 3 is NOT less efficient than others. In fact, tests show that it might be slightly MORE efficient than method 1.
Script for the -force_key_frames
option
Here is a short PERL program I used to verify I-frame cadence based on the output of slhck's ffprobe suggestion. It seems to verify that the -force_key_frames
method will also work, and has the added benefit of allowing for scenecut
frames. I have absolutely no idea how FFMPEG makes this work, or if I just lucked out somehow because my streams happen to be well-conditioned.
In my case, I encoded at 30fps with an expected GOP size of 6 seconds, or 180 frames. I used 180 as the gopsize argument to this program verified an I frame at each multiple of 180, but setting it to 181 (or any other number not a multiple of 180) made it complain.
#!/usr/bin/perl
use strict;
my $gopsize = shift(@ARGV);
my $file = shift(@ARGV);
print "GOPSIZE = $gopsizen";
my $linenum = 0;
my $expected = 0;
open my $pipe, "ffprobe -i $file -select_streams v -show_frames -of csv -show_entries frame=pict_type |"
or die "Blah";
while (<$pipe>) {
if ($linenum > $expected) {
# Won't catch all the misses. But even one is good enough to fail.
print "Missed IFrame at $expectedn";
$expected = (int($linenum/$gopsize) + 1)*$gopsize;
}
if (m/,Is*$/) {
if ($linenum < $expected) {
# Don't care term, just an extra I frame. Snore.
#print "Free IFrame at $linenumn";
} else {
#print "IFrame HIT at $expectedn";
$expected += $gopsize;
}
}
$linenum += 1;
}
Just a note: Since this is a Q&A site and not really a discussion forum where posts are ordered chronologically, it's best to put all the information into one answer, so that people looking for a solution just have to read one post and not to look at who posted what, when :) I merged your answers and gave you a +1 on this, too. Since cross posting is not allowed, I'd suggest you delete your question on the Video site. People will find the answer(s) here.
– slhck
May 2 '15 at 10:36
1
I just had one more thought (actually it was raised on the FFmpeg mailing list). When you useforce_key_frames
, it kind of messes up the x264 bit allocation algorithm, so it may give you worse quality than simply setting a fixed keyframe interval.
– slhck
May 5 '15 at 19:25
Holy crap. Yet one more reason to have FFMPEG provide a codec-nonspecfic way to do this, an argument that would "do the best thing for the codec in question". I tried to file a ticket for this with FFMPEG's trac, but the bounced :-(
– Mark Gerolimatos
May 5 '15 at 23:16
@slhck: Could you give more details please? I've looked in the mailing list archives in May 2015 but couldn't find anything. The bottom line would be to forget about "Method 3" and stick to "Method 1".
– schieferstapel
Oct 4 '16 at 18:32
2
@MarkGerolimatos : about-g
, you say, "It neither appears to work, ... nor does it appear to be used in the code.". I checked and the the input ofg
is stored inavctx->gop_size
and that libx264 makes use of it:x4->params.i_keyint_max = avctx->gop_size;
. When I probe this generated test file:ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
, I get keyframes at exactly0,37,74,111,148,185,222,259,296,333,370
. A GOP could be cut short if scene change is triggered, and for that-sc_threshold
could be set, which is also picked up by x264.
– Gyan
Mar 3 '17 at 11:03
add a comment |
I wanted to add some info here since my googling pulled up this discussion quite a bit in my quest to find info on trying to find a way to segment my DASH encoding the way I wanted, and none of the info I found was totally correct.
First several misconceptions to get rid of:
Not all I-frames are the same. There's big "I" frames and little "i" frames. Or to use correct terminology, IDR I-Frames and non-IDR I-Frames. IDR I-frames (sometimes called "keyframes") will create a new GOP. The non-IDR frames will not. They are handy to have inside of a GOP where there is a scene change.
-x264opts keyint=GOPSIZE:min-keyint=GOPSIZE
← This does not do what you think it does. This took me a little while to figure out. It turns out themin-keyint
is limited in the code. It is not allowed to be greater than(keyint / 2) + 1
. So assigning the same value to these two variables results in the value formin-keyint
getting knocked down by half when encoding.
Here's the thing: scene-cut is really great, especially in video that has fast hard cuts. It keeps it nice and crisp, so I don't want to disable it, but at the same time I couldn't get a fixed GOP size as long as it was enabled. I wanted to enable scene-cut, but to only have it use non-IDR I-frames. But it wasn't working. Until I figured out (from lots of reading) about misconception #2.
It turns out I needed to set keyint
to double my desired GOP size. This means that min-keyint
can be set to my desired GOP size (without the internal code cutting it in half), which prevents scene-cut detection from using IDR I-frames inside the GOP size because the frame count since the last IDR I-Frame is always less than min-keyinit
.
And finally setting the force_key_frame
option overrides the double size keyint
. So here's what works:
I prefer segments in 2 second chunks, so my GOPSIZE = Framerate * 2
ffmpeg <other_options> -force_key_frames "expr:eq(mod(n,<GOPSIZE>),0)" -x264opts rc-lookahead=<GOPSIZE>:keyint=<GOPSIZE * 2>:min-keyint=<GOPSIZE> <other_options>
You can verify using ffprobe:
ffprobe <SRC_FLE> -select_streams v -show_frames -of csv -show_entries frame=coded_picture_number,key_frame,pict_type > frames.csv
In the generated CSV file each line will tell you: frame, [is_an_IDR_?], [frame_type], [frame_number]
:
frame,1,I,60 <-- frame 60, is I frame, 1 means is an IDR I-frame (aka KeyFrame)
frame,0,I,71 <-- frame 71, is I frame, 0 means not an IDR I_frame
The result is that you should only see IDR I-Frames at fixed GOPSIZE
intervals, while all other I frames are non-IDR I-frames inserted as needed by scene-cut detection.
that was fantastic! It was aldo highly counterintuitive, thank you for putting in the effort. And to summarize, I assume your definition of "I-frames" and "i-frames" is conceptual (that is, not explictly configurable in libx264) , and that the "max * 2" was the way you enforced it?
– Mark Gerolimatos
Jun 27 '17 at 18:47
Yes that was conceptual, although I've seen people use "I" vs "i" to distinguish between IDR and non-IDR I-frames. And yes, setting keyinit to the desired gop size * 2 is a way to force all I frames inside the gop to be non-IDR I-frames. Then the ffmpeg -force-key-frames over-rides key-init in the x264opts. Basically it's a really backwards way to get the desired outcome that would be possible if the x264 code allowed you to set min-keyinit and keyinit to the same value.
– Reuben
Jun 27 '17 at 21:57
... while also being able to both keep the scene-cut detection turned on and get fixed GOP size.
– Reuben
Jun 27 '17 at 22:04
thanks again for your awesome work! Sounds like we need a less "backwards" way of effecting it
– Mark Gerolimatos
Jun 27 '17 at 22:21
Is rc-lookahead necessary here? It affects mbtree and VBV, but does it affect i-frame generation?
– Alexander Svetkin
Apr 23 '18 at 15:41
|
show 1 more comment
It seems that this syntax doesnt allways work.. Ive tested quite alot on our VOD content as well as live content (file dumps) and sometimes scenecut doesnt work and trigger a inbetween iframe:
Syntax for a i50->p50 upconvertion, 2 sec gop/segment, IDR at the start, iframes inbetween if needed
ffmpeg.exe -loglevel verbose -i avc_50i.ts -pix_fmt yuv420p -filter_complex yadif=1,scale=1920:1080 -vcodec libx264 -preset fast -x264-params "rc-lookahead=100:keyint=200:min-keyint=100:hrd=1:vbv_maxrate=12000:vbv_bufsize=12000:no-open-gop=1" -r 50 -crf 22 -force_key_frames "expr:eq(mod(n,100),0)" -codec:a aac -b:a 128k -y target.ts
add a comment |
Twitch has a post about this. They explain that they decided to use their own program for several reasons; one of them was that ffmpeg doesn't let you run different x264 instances in different threads, but instead devotes all specified threads to one frame in one output before moving on to the next output.
If you aren't doing real-time streaming, you have more luxury. The 'correct' way is probably to encode at one resolution with just the GOP size specified with -g, and then encode the other resolutions forcing keyframes at the same places.
If you wanted to do that, you might use ffprobe to get the keyframe times and then use a shell script or an actual programming language to convert that into an ffmpeg command.
But for most content, there's very little difference between having one keyframe every 5 seconds and two keyframes every 5 seconds (one forced and one from scenecut). This is about the average I-frame size vs the size of P-frames and B-frames. If you use x264 with typical settings (the only reason I think you should do anything to affect these is if you set -qmin, as a poor way of preventing x264 from using bitrate on easy content; this limits all frame types to the same value, I think) and get a result like I-frame average size of 46 kB, P-frame 24 kB, B-frame 17 kB (half as frequent as P-frames), then an extra I-frame every second at 30 fps is only a 3% increase in file size. The difference between h264 and h263 might be made up of a bunch of 3% decreases, but a single one isn't very important.
On other types of content, frame sizes will be different. To be fair, this is about temporal complexity and not spatial complexity, so it isn't just easy content vs hard content. But generally, streaming video sites have a bitrate limit, and content with relatively large I-frames is easy content that will be encoded at high quality no matter how many extra keyframes are added. It's wasteful, but this waste will usually not be noticed. The most wasteful case is probably a video that's just a static image accompanying a song, where each keyframe is exactly the same.
One thing I'm not sure of is how forced keyframes interact with the rate limiter set with -maxrate and -bufsize. I think even YouTube has had recent problems correctly configuring buffer settings to give consistent quality. If you're just using average bitrate settings as can be seen by some sites (since you can inspect x264's options in the header/mov atom? with a hex editor) then the buffer model isn't a problem, but if you're serving user-generated content, average bitrate encourages users to add a black screen at the end of their video.
Ffmpeg's -g option, or any other encoder option that you use, is mapped to the encoder-specific option. So '-x264-params keyint=GOPSIZE' is equivalent to '-g GOPSIZE'.
One problem with using scene detection is if you prefer keyframes near specific numbers for whatever reason. If you specify keyframes every 5 seconds and use scene detection, and there's a scene change at 4.5, then it should be detected, but then the next keyframe will be at 9.5. If the time keeps getting stepped up like this, you could end up with keyframes at 42.5, 47.5, 52.5, etc., instead of 40, 45, 50, 55. Conversely, if there's a scene change at 5.5, then there will be a keyframe at 5 and 5.5 will be too early for another one. Ffmpeg doesn't let you specify "make a keyframe here if there's no scene change within the next 30 frames". Someone who understands C could add that option, though.
For variable-frame-rate video, when you're not live-streaming like Twitch, you should be able to use scene changes without converting permanently to constant frame-rate. If you use the 'select' filter in ffmpeg and use the 'scene' constant in the expression, then the debug output (-v debug or press '+' several times while encoding) shows the scene change number. This is probably different from, and not as useful as, the number used by x264, but it could still be useful.
The procedure, then, would probably be to do a test video that's only for keyframe changes, but maybe could be used for rate control data if using 2-pass. (Not sure if the generated data is at all useful for different resolutions and settings; the macroblock-tree data won't be.) Convert it to constant-framerate video, but see this bug about stuttering output when halving framerate if you ever decide to use the fps filter for other purposes. Run it through x264 with your desired keyframe and GOP settings.
Then just use these keyframe times with the original variable frame-rate video.
If you allow completely crazy user-generated content with a 20-second gap between frames, then for the variable frame-rate encode, you could split the output, use fps filter, somehow use select filter (maybe build a really long expression that has every keyframe time)... or maybe you could use the test video as input and either decode only keyframes, if that ffmpeg option works, or use the select filter to select keyframes. Then scale it to the correct size (there's even a scale2ref filter for this) and overlay the original video on it. Then use the interleave filter to combine these destined-to-be forced keyframes with the original video. If this results in two frames that are 0.001 sec apart that the interleave filter doesn't prevent, then address this problem yourself with another select filter. Dealing with frame buffer limits for the interleave filter could be the main problem here. These could all work: use some kind of filter to buffer the denser stream (fifo filter?); refer to the input file multiple times so it's decoded more than once and frames don't have to be stored; use the 'streamselect' filter, which I have never done, at exactly the times of the keyframes; improve the interleave filter by changing its default behaviour or adding an option to output the oldest frame in a buffer instead of dropping a frame.
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "3"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f908280%2fwhat-is-the-correct-way-to-fix-keyframes-in-ffmpeg-for-dash%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
TL;DR
I would recommend the following:
libx264
:-g X -keyint_min X
(and optionally add-force_key_frames "expr:gte(t,n_forced*N)"
)
libx265
:-x265-params "keyint=X:min-keyint=X"
libvpx-vp9
:-g X
where X
is the interval in frames and N
is the interval in seconds. For example, for a 2-second interval with a 30fps video, X
= 60 and N
= 2.
A note about different frame types
In order to properly explain this topic, we first have to define the two types of I-frames / keyframes:
- Instantaneous Decoder Refresh (IDR) frames: These allow independent decoding of the following frames, without access to frames previous to the IDR frame.
- Non-IDR-frames: These require a previous IDR frame for the decoding to work. Non-IDR frames can be used for scene cuts in the middle of a GOP (group of pictures).
What is recommended for streaming?
For the streaming case, you want to:
- Ensure that all IDR frames are at regular positions (e.g. at 2, 4, 6, … seconds) so that the video can be split up into segments of equal length.
- Enable scene cut detection, so as to improve coding efficiency / quality. This means allowing I-frames to be placed in between IDR frames. You can still work with scene cut detection disabled (and this is part of many guides, still), but it's not necessary.
What do the parameters do?
In order to configure the encoder, we have to understand what the keyframe parameters do. I did some tests and discovered the following, for the three encoders libx264
, libx265
and libvpx-vp9
in FFmpeg:
libx264
:
-g
sets the keyframe interval.
-keyint_min
sets the minimum keyframe interval.
-x264-params "keyint=x:min-keyint=y"
is the same as-g x -keyint_min y
.
Note: When setting both to the same value, the minimum is internally set to half the maximum interval plus one, as seen in the
x264
code:
h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
libx265
:
-g
is not implemented.
-x265-params "keyint=x:min-keyint=y"
works.
libvpx-vp9
:
-g
sets the keyframe interval.
-keyint_min
sets the minimum keyframe interval
Note: Due to how FFmpeg works,
-keyint_min
is only forwarded to the encoder when it is the same as-g
. In the code fromlibvpxenc.c
in FFmpeg we can find:
if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
enccfg.kf_min_dist = avctx->keyint_min;
if (avctx->gop_size >= 0)
enccfg.kf_max_dist = avctx->gop_size;
This might be a bug (or lack of feature?), since
libvpx
definitely supports setting a different value forkf_min_dist
.
Should you use -force_key_frames
?
The -force_key_frames
option forcibly inserts keyframes at the given interval (expression). This works for all encoders, but it might mess with the rate control mechanism. Especially for VP9, I've noticed severe quality fluctuations, so I cannot recommend using it in this case.
Thank you! This is great feedback. One question I have is how you generated that awesome table. I could totally use something like that.
– Mark Gerolimatos
Apr 30 '15 at 21:39
(There appears to be no way to write you directly) Can you please point me towards links to any threads in this ITU-T discussion? Thanks!
– Mark Gerolimatos
Apr 30 '15 at 21:45
2
I just made that in Excel, pasting the output I got from three runs offfprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, then coloring the cells. I'm afraid there are no public discussions, but I'll see if I can dig up some of the links I found back then.
– slhck
Apr 30 '15 at 22:01
Could you please re-try your experiment with the-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
form? I just tried it and found that while there were extra I frames in the stream, it DID seem to abide by my rule. A PERL program will follow as an "answer", as you cannot apparently use markup in comments.
– Mark Gerolimatos
May 1 '15 at 1:08
Interesting. I believe it's worth a separate "real" answer if you found out that it works. (Stack Exchange sites aren't really good for this discussion-style reply.) The last time I checked,-force_key_frames
didn't work for me, and so I never tried it again. That was more than a year ago. Perhaps it was a bug. I'll try again soon.
– slhck
May 1 '15 at 8:00
add a comment |
TL;DR
I would recommend the following:
libx264
:-g X -keyint_min X
(and optionally add-force_key_frames "expr:gte(t,n_forced*N)"
)
libx265
:-x265-params "keyint=X:min-keyint=X"
libvpx-vp9
:-g X
where X
is the interval in frames and N
is the interval in seconds. For example, for a 2-second interval with a 30fps video, X
= 60 and N
= 2.
A note about different frame types
In order to properly explain this topic, we first have to define the two types of I-frames / keyframes:
- Instantaneous Decoder Refresh (IDR) frames: These allow independent decoding of the following frames, without access to frames previous to the IDR frame.
- Non-IDR-frames: These require a previous IDR frame for the decoding to work. Non-IDR frames can be used for scene cuts in the middle of a GOP (group of pictures).
What is recommended for streaming?
For the streaming case, you want to:
- Ensure that all IDR frames are at regular positions (e.g. at 2, 4, 6, … seconds) so that the video can be split up into segments of equal length.
- Enable scene cut detection, so as to improve coding efficiency / quality. This means allowing I-frames to be placed in between IDR frames. You can still work with scene cut detection disabled (and this is part of many guides, still), but it's not necessary.
What do the parameters do?
In order to configure the encoder, we have to understand what the keyframe parameters do. I did some tests and discovered the following, for the three encoders libx264
, libx265
and libvpx-vp9
in FFmpeg:
libx264
:
-g
sets the keyframe interval.
-keyint_min
sets the minimum keyframe interval.
-x264-params "keyint=x:min-keyint=y"
is the same as-g x -keyint_min y
.
Note: When setting both to the same value, the minimum is internally set to half the maximum interval plus one, as seen in the
x264
code:
h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
libx265
:
-g
is not implemented.
-x265-params "keyint=x:min-keyint=y"
works.
libvpx-vp9
:
-g
sets the keyframe interval.
-keyint_min
sets the minimum keyframe interval
Note: Due to how FFmpeg works,
-keyint_min
is only forwarded to the encoder when it is the same as-g
. In the code fromlibvpxenc.c
in FFmpeg we can find:
if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
enccfg.kf_min_dist = avctx->keyint_min;
if (avctx->gop_size >= 0)
enccfg.kf_max_dist = avctx->gop_size;
This might be a bug (or lack of feature?), since
libvpx
definitely supports setting a different value forkf_min_dist
.
Should you use -force_key_frames
?
The -force_key_frames
option forcibly inserts keyframes at the given interval (expression). This works for all encoders, but it might mess with the rate control mechanism. Especially for VP9, I've noticed severe quality fluctuations, so I cannot recommend using it in this case.
Thank you! This is great feedback. One question I have is how you generated that awesome table. I could totally use something like that.
– Mark Gerolimatos
Apr 30 '15 at 21:39
(There appears to be no way to write you directly) Can you please point me towards links to any threads in this ITU-T discussion? Thanks!
– Mark Gerolimatos
Apr 30 '15 at 21:45
2
I just made that in Excel, pasting the output I got from three runs offfprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, then coloring the cells. I'm afraid there are no public discussions, but I'll see if I can dig up some of the links I found back then.
– slhck
Apr 30 '15 at 22:01
Could you please re-try your experiment with the-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
form? I just tried it and found that while there were extra I frames in the stream, it DID seem to abide by my rule. A PERL program will follow as an "answer", as you cannot apparently use markup in comments.
– Mark Gerolimatos
May 1 '15 at 1:08
Interesting. I believe it's worth a separate "real" answer if you found out that it works. (Stack Exchange sites aren't really good for this discussion-style reply.) The last time I checked,-force_key_frames
didn't work for me, and so I never tried it again. That was more than a year ago. Perhaps it was a bug. I'll try again soon.
– slhck
May 1 '15 at 8:00
add a comment |
TL;DR
I would recommend the following:
libx264
:-g X -keyint_min X
(and optionally add-force_key_frames "expr:gte(t,n_forced*N)"
)
libx265
:-x265-params "keyint=X:min-keyint=X"
libvpx-vp9
:-g X
where X
is the interval in frames and N
is the interval in seconds. For example, for a 2-second interval with a 30fps video, X
= 60 and N
= 2.
A note about different frame types
In order to properly explain this topic, we first have to define the two types of I-frames / keyframes:
- Instantaneous Decoder Refresh (IDR) frames: These allow independent decoding of the following frames, without access to frames previous to the IDR frame.
- Non-IDR-frames: These require a previous IDR frame for the decoding to work. Non-IDR frames can be used for scene cuts in the middle of a GOP (group of pictures).
What is recommended for streaming?
For the streaming case, you want to:
- Ensure that all IDR frames are at regular positions (e.g. at 2, 4, 6, … seconds) so that the video can be split up into segments of equal length.
- Enable scene cut detection, so as to improve coding efficiency / quality. This means allowing I-frames to be placed in between IDR frames. You can still work with scene cut detection disabled (and this is part of many guides, still), but it's not necessary.
What do the parameters do?
In order to configure the encoder, we have to understand what the keyframe parameters do. I did some tests and discovered the following, for the three encoders libx264
, libx265
and libvpx-vp9
in FFmpeg:
libx264
:
-g
sets the keyframe interval.
-keyint_min
sets the minimum keyframe interval.
-x264-params "keyint=x:min-keyint=y"
is the same as-g x -keyint_min y
.
Note: When setting both to the same value, the minimum is internally set to half the maximum interval plus one, as seen in the
x264
code:
h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
libx265
:
-g
is not implemented.
-x265-params "keyint=x:min-keyint=y"
works.
libvpx-vp9
:
-g
sets the keyframe interval.
-keyint_min
sets the minimum keyframe interval
Note: Due to how FFmpeg works,
-keyint_min
is only forwarded to the encoder when it is the same as-g
. In the code fromlibvpxenc.c
in FFmpeg we can find:
if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
enccfg.kf_min_dist = avctx->keyint_min;
if (avctx->gop_size >= 0)
enccfg.kf_max_dist = avctx->gop_size;
This might be a bug (or lack of feature?), since
libvpx
definitely supports setting a different value forkf_min_dist
.
Should you use -force_key_frames
?
The -force_key_frames
option forcibly inserts keyframes at the given interval (expression). This works for all encoders, but it might mess with the rate control mechanism. Especially for VP9, I've noticed severe quality fluctuations, so I cannot recommend using it in this case.
TL;DR
I would recommend the following:
libx264
:-g X -keyint_min X
(and optionally add-force_key_frames "expr:gte(t,n_forced*N)"
)
libx265
:-x265-params "keyint=X:min-keyint=X"
libvpx-vp9
:-g X
where X
is the interval in frames and N
is the interval in seconds. For example, for a 2-second interval with a 30fps video, X
= 60 and N
= 2.
A note about different frame types
In order to properly explain this topic, we first have to define the two types of I-frames / keyframes:
- Instantaneous Decoder Refresh (IDR) frames: These allow independent decoding of the following frames, without access to frames previous to the IDR frame.
- Non-IDR-frames: These require a previous IDR frame for the decoding to work. Non-IDR frames can be used for scene cuts in the middle of a GOP (group of pictures).
What is recommended for streaming?
For the streaming case, you want to:
- Ensure that all IDR frames are at regular positions (e.g. at 2, 4, 6, … seconds) so that the video can be split up into segments of equal length.
- Enable scene cut detection, so as to improve coding efficiency / quality. This means allowing I-frames to be placed in between IDR frames. You can still work with scene cut detection disabled (and this is part of many guides, still), but it's not necessary.
What do the parameters do?
In order to configure the encoder, we have to understand what the keyframe parameters do. I did some tests and discovered the following, for the three encoders libx264
, libx265
and libvpx-vp9
in FFmpeg:
libx264
:
-g
sets the keyframe interval.
-keyint_min
sets the minimum keyframe interval.
-x264-params "keyint=x:min-keyint=y"
is the same as-g x -keyint_min y
.
Note: When setting both to the same value, the minimum is internally set to half the maximum interval plus one, as seen in the
x264
code:
h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
libx265
:
-g
is not implemented.
-x265-params "keyint=x:min-keyint=y"
works.
libvpx-vp9
:
-g
sets the keyframe interval.
-keyint_min
sets the minimum keyframe interval
Note: Due to how FFmpeg works,
-keyint_min
is only forwarded to the encoder when it is the same as-g
. In the code fromlibvpxenc.c
in FFmpeg we can find:
if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
enccfg.kf_min_dist = avctx->keyint_min;
if (avctx->gop_size >= 0)
enccfg.kf_max_dist = avctx->gop_size;
This might be a bug (or lack of feature?), since
libvpx
definitely supports setting a different value forkf_min_dist
.
Should you use -force_key_frames
?
The -force_key_frames
option forcibly inserts keyframes at the given interval (expression). This works for all encoders, but it might mess with the rate control mechanism. Especially for VP9, I've noticed severe quality fluctuations, so I cannot recommend using it in this case.
edited Mar 13 '18 at 12:05
answered Apr 30 '15 at 21:31
slhckslhck
164k47452477
164k47452477
Thank you! This is great feedback. One question I have is how you generated that awesome table. I could totally use something like that.
– Mark Gerolimatos
Apr 30 '15 at 21:39
(There appears to be no way to write you directly) Can you please point me towards links to any threads in this ITU-T discussion? Thanks!
– Mark Gerolimatos
Apr 30 '15 at 21:45
2
I just made that in Excel, pasting the output I got from three runs offfprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, then coloring the cells. I'm afraid there are no public discussions, but I'll see if I can dig up some of the links I found back then.
– slhck
Apr 30 '15 at 22:01
Could you please re-try your experiment with the-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
form? I just tried it and found that while there were extra I frames in the stream, it DID seem to abide by my rule. A PERL program will follow as an "answer", as you cannot apparently use markup in comments.
– Mark Gerolimatos
May 1 '15 at 1:08
Interesting. I believe it's worth a separate "real" answer if you found out that it works. (Stack Exchange sites aren't really good for this discussion-style reply.) The last time I checked,-force_key_frames
didn't work for me, and so I never tried it again. That was more than a year ago. Perhaps it was a bug. I'll try again soon.
– slhck
May 1 '15 at 8:00
add a comment |
Thank you! This is great feedback. One question I have is how you generated that awesome table. I could totally use something like that.
– Mark Gerolimatos
Apr 30 '15 at 21:39
(There appears to be no way to write you directly) Can you please point me towards links to any threads in this ITU-T discussion? Thanks!
– Mark Gerolimatos
Apr 30 '15 at 21:45
2
I just made that in Excel, pasting the output I got from three runs offfprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, then coloring the cells. I'm afraid there are no public discussions, but I'll see if I can dig up some of the links I found back then.
– slhck
Apr 30 '15 at 22:01
Could you please re-try your experiment with the-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
form? I just tried it and found that while there were extra I frames in the stream, it DID seem to abide by my rule. A PERL program will follow as an "answer", as you cannot apparently use markup in comments.
– Mark Gerolimatos
May 1 '15 at 1:08
Interesting. I believe it's worth a separate "real" answer if you found out that it works. (Stack Exchange sites aren't really good for this discussion-style reply.) The last time I checked,-force_key_frames
didn't work for me, and so I never tried it again. That was more than a year ago. Perhaps it was a bug. I'll try again soon.
– slhck
May 1 '15 at 8:00
Thank you! This is great feedback. One question I have is how you generated that awesome table. I could totally use something like that.
– Mark Gerolimatos
Apr 30 '15 at 21:39
Thank you! This is great feedback. One question I have is how you generated that awesome table. I could totally use something like that.
– Mark Gerolimatos
Apr 30 '15 at 21:39
(There appears to be no way to write you directly) Can you please point me towards links to any threads in this ITU-T discussion? Thanks!
– Mark Gerolimatos
Apr 30 '15 at 21:45
(There appears to be no way to write you directly) Can you please point me towards links to any threads in this ITU-T discussion? Thanks!
– Mark Gerolimatos
Apr 30 '15 at 21:45
2
2
I just made that in Excel, pasting the output I got from three runs of
ffprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, then coloring the cells. I'm afraid there are no public discussions, but I'll see if I can dig up some of the links I found back then.– slhck
Apr 30 '15 at 22:01
I just made that in Excel, pasting the output I got from three runs of
ffprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, then coloring the cells. I'm afraid there are no public discussions, but I'll see if I can dig up some of the links I found back then.– slhck
Apr 30 '15 at 22:01
Could you please re-try your experiment with the
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
form? I just tried it and found that while there were extra I frames in the stream, it DID seem to abide by my rule. A PERL program will follow as an "answer", as you cannot apparently use markup in comments.– Mark Gerolimatos
May 1 '15 at 1:08
Could you please re-try your experiment with the
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
form? I just tried it and found that while there were extra I frames in the stream, it DID seem to abide by my rule. A PERL program will follow as an "answer", as you cannot apparently use markup in comments.– Mark Gerolimatos
May 1 '15 at 1:08
Interesting. I believe it's worth a separate "real" answer if you found out that it works. (Stack Exchange sites aren't really good for this discussion-style reply.) The last time I checked,
-force_key_frames
didn't work for me, and so I never tried it again. That was more than a year ago. Perhaps it was a bug. I'll try again soon.– slhck
May 1 '15 at 8:00
Interesting. I believe it's worth a separate "real" answer if you found out that it works. (Stack Exchange sites aren't really good for this discussion-style reply.) The last time I checked,
-force_key_frames
didn't work for me, and so I never tried it again. That was more than a year ago. Perhaps it was a bug. I'll try again soon.– slhck
May 1 '15 at 8:00
add a comment |
Here is my fifty cents for the case.
Method 1:
messing with libx264's arguments
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
Generate iframes only at the desired intervals.
Example 1:
ffmpeg -i test.mp4 -codec:v libx264
-r 23.976
-x264opts "keyint=48:min-keyint=48:no-scenecut"
-c:a copy
-y test_keyint_48.mp4
Generate iframes as expected like this:
Iframes Seconds
1 0
49 2
97 4
145 6
193 8
241 10
289 12
337 14
385 16
433 18
481 20
529 22
577 24
625 26
673 28
721 30
769 32
817 34
865 36
913 38
961 40
1009 42
1057 44
1105 46
1153 48
1201 50
1249 52
1297 54
1345 56
1393 58
Method 2 is depreciated. Ommitted.
Method 3:
insert a keyframe every N seconds (MAYBE):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
Example 2
ffmpeg -i test.mp4 -codec:v libx264
-r 23.976
-force_key_frames "expr:gte(t,n_forced*2)"
-c:a copy
-y test_fkf_2.mp4
Generate an iframes in a slightly different way:
Iframes Seconds
1 0
49 2
97 4
145 6
193 8
241 10
289 12
337 14
385 16
433 18
481 20
519 21.58333333
529 22
577 24
625 26
673 28
721 30
769 32
817 34
865 36
913 38
931 38.75
941 39.16666667
961 40
1008 42
1056 44
1104 46
1152 48
1200 50
1248 52
1296 54
1305 54.375
1344 56
1367 56.95833333
1392 58
1430 59.58333333
1440 60
1475 61.45833333
1488 62
1536 64
1544 64.33333333
1584 66
1591 66.29166667
1632 68
1680 70
1728 72
1765 73.54166667
1776 74
1811 75.45833333
1824 75.95833333
1853 77.16666667
1872 77.95833333
1896 78.95833333
1920 79.95833333
1939 80.75
1968 81.95833333
As you can see it places iframes every 2 seconds AND on scenecut (seconds with floating part) which is important for video stream complexity in my opinion.
Genearated file sizes are pretty the same. Very strange that even with more keyframes in Method 3 it generates sometimes less file than standard x264 library algorithm.
For generating multiple bitrate files for HLS stream we choose method three. It perfectly aligned with 2 seconds between chunks, they have iframe at the beginning of every chunk and they have additional iframes on complex scenes which provides better experience for users who has an outdated devices and can not playback x264 high profiles.
Hope it helps someone.
Fantastic, thanks for your 50 cents!
– BrunoFenzl
Oct 12 '16 at 22:23
add a comment |
Here is my fifty cents for the case.
Method 1:
messing with libx264's arguments
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
Generate iframes only at the desired intervals.
Example 1:
ffmpeg -i test.mp4 -codec:v libx264
-r 23.976
-x264opts "keyint=48:min-keyint=48:no-scenecut"
-c:a copy
-y test_keyint_48.mp4
Generate iframes as expected like this:
Iframes Seconds
1 0
49 2
97 4
145 6
193 8
241 10
289 12
337 14
385 16
433 18
481 20
529 22
577 24
625 26
673 28
721 30
769 32
817 34
865 36
913 38
961 40
1009 42
1057 44
1105 46
1153 48
1201 50
1249 52
1297 54
1345 56
1393 58
Method 2 is depreciated. Ommitted.
Method 3:
insert a keyframe every N seconds (MAYBE):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
Example 2
ffmpeg -i test.mp4 -codec:v libx264
-r 23.976
-force_key_frames "expr:gte(t,n_forced*2)"
-c:a copy
-y test_fkf_2.mp4
Generate an iframes in a slightly different way:
Iframes Seconds
1 0
49 2
97 4
145 6
193 8
241 10
289 12
337 14
385 16
433 18
481 20
519 21.58333333
529 22
577 24
625 26
673 28
721 30
769 32
817 34
865 36
913 38
931 38.75
941 39.16666667
961 40
1008 42
1056 44
1104 46
1152 48
1200 50
1248 52
1296 54
1305 54.375
1344 56
1367 56.95833333
1392 58
1430 59.58333333
1440 60
1475 61.45833333
1488 62
1536 64
1544 64.33333333
1584 66
1591 66.29166667
1632 68
1680 70
1728 72
1765 73.54166667
1776 74
1811 75.45833333
1824 75.95833333
1853 77.16666667
1872 77.95833333
1896 78.95833333
1920 79.95833333
1939 80.75
1968 81.95833333
As you can see it places iframes every 2 seconds AND on scenecut (seconds with floating part) which is important for video stream complexity in my opinion.
Genearated file sizes are pretty the same. Very strange that even with more keyframes in Method 3 it generates sometimes less file than standard x264 library algorithm.
For generating multiple bitrate files for HLS stream we choose method three. It perfectly aligned with 2 seconds between chunks, they have iframe at the beginning of every chunk and they have additional iframes on complex scenes which provides better experience for users who has an outdated devices and can not playback x264 high profiles.
Hope it helps someone.
Fantastic, thanks for your 50 cents!
– BrunoFenzl
Oct 12 '16 at 22:23
add a comment |
Here is my fifty cents for the case.
Method 1:
messing with libx264's arguments
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
Generate iframes only at the desired intervals.
Example 1:
ffmpeg -i test.mp4 -codec:v libx264
-r 23.976
-x264opts "keyint=48:min-keyint=48:no-scenecut"
-c:a copy
-y test_keyint_48.mp4
Generate iframes as expected like this:
Iframes Seconds
1 0
49 2
97 4
145 6
193 8
241 10
289 12
337 14
385 16
433 18
481 20
529 22
577 24
625 26
673 28
721 30
769 32
817 34
865 36
913 38
961 40
1009 42
1057 44
1105 46
1153 48
1201 50
1249 52
1297 54
1345 56
1393 58
Method 2 is depreciated. Ommitted.
Method 3:
insert a keyframe every N seconds (MAYBE):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
Example 2
ffmpeg -i test.mp4 -codec:v libx264
-r 23.976
-force_key_frames "expr:gte(t,n_forced*2)"
-c:a copy
-y test_fkf_2.mp4
Generate an iframes in a slightly different way:
Iframes Seconds
1 0
49 2
97 4
145 6
193 8
241 10
289 12
337 14
385 16
433 18
481 20
519 21.58333333
529 22
577 24
625 26
673 28
721 30
769 32
817 34
865 36
913 38
931 38.75
941 39.16666667
961 40
1008 42
1056 44
1104 46
1152 48
1200 50
1248 52
1296 54
1305 54.375
1344 56
1367 56.95833333
1392 58
1430 59.58333333
1440 60
1475 61.45833333
1488 62
1536 64
1544 64.33333333
1584 66
1591 66.29166667
1632 68
1680 70
1728 72
1765 73.54166667
1776 74
1811 75.45833333
1824 75.95833333
1853 77.16666667
1872 77.95833333
1896 78.95833333
1920 79.95833333
1939 80.75
1968 81.95833333
As you can see it places iframes every 2 seconds AND on scenecut (seconds with floating part) which is important for video stream complexity in my opinion.
Genearated file sizes are pretty the same. Very strange that even with more keyframes in Method 3 it generates sometimes less file than standard x264 library algorithm.
For generating multiple bitrate files for HLS stream we choose method three. It perfectly aligned with 2 seconds between chunks, they have iframe at the beginning of every chunk and they have additional iframes on complex scenes which provides better experience for users who has an outdated devices and can not playback x264 high profiles.
Hope it helps someone.
Here is my fifty cents for the case.
Method 1:
messing with libx264's arguments
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
Generate iframes only at the desired intervals.
Example 1:
ffmpeg -i test.mp4 -codec:v libx264
-r 23.976
-x264opts "keyint=48:min-keyint=48:no-scenecut"
-c:a copy
-y test_keyint_48.mp4
Generate iframes as expected like this:
Iframes Seconds
1 0
49 2
97 4
145 6
193 8
241 10
289 12
337 14
385 16
433 18
481 20
529 22
577 24
625 26
673 28
721 30
769 32
817 34
865 36
913 38
961 40
1009 42
1057 44
1105 46
1153 48
1201 50
1249 52
1297 54
1345 56
1393 58
Method 2 is depreciated. Ommitted.
Method 3:
insert a keyframe every N seconds (MAYBE):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
Example 2
ffmpeg -i test.mp4 -codec:v libx264
-r 23.976
-force_key_frames "expr:gte(t,n_forced*2)"
-c:a copy
-y test_fkf_2.mp4
Generate an iframes in a slightly different way:
Iframes Seconds
1 0
49 2
97 4
145 6
193 8
241 10
289 12
337 14
385 16
433 18
481 20
519 21.58333333
529 22
577 24
625 26
673 28
721 30
769 32
817 34
865 36
913 38
931 38.75
941 39.16666667
961 40
1008 42
1056 44
1104 46
1152 48
1200 50
1248 52
1296 54
1305 54.375
1344 56
1367 56.95833333
1392 58
1430 59.58333333
1440 60
1475 61.45833333
1488 62
1536 64
1544 64.33333333
1584 66
1591 66.29166667
1632 68
1680 70
1728 72
1765 73.54166667
1776 74
1811 75.45833333
1824 75.95833333
1853 77.16666667
1872 77.95833333
1896 78.95833333
1920 79.95833333
1939 80.75
1968 81.95833333
As you can see it places iframes every 2 seconds AND on scenecut (seconds with floating part) which is important for video stream complexity in my opinion.
Genearated file sizes are pretty the same. Very strange that even with more keyframes in Method 3 it generates sometimes less file than standard x264 library algorithm.
For generating multiple bitrate files for HLS stream we choose method three. It perfectly aligned with 2 seconds between chunks, they have iframe at the beginning of every chunk and they have additional iframes on complex scenes which provides better experience for users who has an outdated devices and can not playback x264 high profiles.
Hope it helps someone.
edited Jun 11 '17 at 6:33
answered Jul 8 '16 at 7:17
Ara SaahovAra Saahov
11113
11113
Fantastic, thanks for your 50 cents!
– BrunoFenzl
Oct 12 '16 at 22:23
add a comment |
Fantastic, thanks for your 50 cents!
– BrunoFenzl
Oct 12 '16 at 22:23
Fantastic, thanks for your 50 cents!
– BrunoFenzl
Oct 12 '16 at 22:23
Fantastic, thanks for your 50 cents!
– BrunoFenzl
Oct 12 '16 at 22:23
add a comment |
The answer therefore seems to be:
- Method 1 is verified to work, but is
libx264
-specific, and comes at the cost of eliminating the very usefulscenecut
option inlibx264
. - Method 3 works as of the FFMPEG version of April 2015, but you should verify your results with with the script included at the bottom of this post, as the FFMPEG documentation is unclear as to the effect of the option. If it works, it is the superior of the two options.
DO NOT USE Method 2,-g
appears to be deprecated. It neither appears to work, nor is it explicitly defined in the documentation, nor is found in the help, nor does it appear to be used in the code. Code inspection shows that the-g
option is likely meant for MPEG-2 streams (there are even code stanzas referring to PAL and NTSC!).
Also:
- Files generated with Method 3 may be slightly larger than Method 1, as
interstitial I frames (keyframes) are allowed. - You should explicitly set the "-r" flag in both cases, even though Method 3 places an I frame at the next frameslot on or after the time specified. Failure to set the "-r" flag places you at the mercy of the source file, possibly with a variable frame rate. Incompatible DASH transitions may result.
- Despite the warnings in the FFMPEG documentation, method 3 is NOT less efficient than others. In fact, tests show that it might be slightly MORE efficient than method 1.
Script for the -force_key_frames
option
Here is a short PERL program I used to verify I-frame cadence based on the output of slhck's ffprobe suggestion. It seems to verify that the -force_key_frames
method will also work, and has the added benefit of allowing for scenecut
frames. I have absolutely no idea how FFMPEG makes this work, or if I just lucked out somehow because my streams happen to be well-conditioned.
In my case, I encoded at 30fps with an expected GOP size of 6 seconds, or 180 frames. I used 180 as the gopsize argument to this program verified an I frame at each multiple of 180, but setting it to 181 (or any other number not a multiple of 180) made it complain.
#!/usr/bin/perl
use strict;
my $gopsize = shift(@ARGV);
my $file = shift(@ARGV);
print "GOPSIZE = $gopsizen";
my $linenum = 0;
my $expected = 0;
open my $pipe, "ffprobe -i $file -select_streams v -show_frames -of csv -show_entries frame=pict_type |"
or die "Blah";
while (<$pipe>) {
if ($linenum > $expected) {
# Won't catch all the misses. But even one is good enough to fail.
print "Missed IFrame at $expectedn";
$expected = (int($linenum/$gopsize) + 1)*$gopsize;
}
if (m/,Is*$/) {
if ($linenum < $expected) {
# Don't care term, just an extra I frame. Snore.
#print "Free IFrame at $linenumn";
} else {
#print "IFrame HIT at $expectedn";
$expected += $gopsize;
}
}
$linenum += 1;
}
Just a note: Since this is a Q&A site and not really a discussion forum where posts are ordered chronologically, it's best to put all the information into one answer, so that people looking for a solution just have to read one post and not to look at who posted what, when :) I merged your answers and gave you a +1 on this, too. Since cross posting is not allowed, I'd suggest you delete your question on the Video site. People will find the answer(s) here.
– slhck
May 2 '15 at 10:36
1
I just had one more thought (actually it was raised on the FFmpeg mailing list). When you useforce_key_frames
, it kind of messes up the x264 bit allocation algorithm, so it may give you worse quality than simply setting a fixed keyframe interval.
– slhck
May 5 '15 at 19:25
Holy crap. Yet one more reason to have FFMPEG provide a codec-nonspecfic way to do this, an argument that would "do the best thing for the codec in question". I tried to file a ticket for this with FFMPEG's trac, but the bounced :-(
– Mark Gerolimatos
May 5 '15 at 23:16
@slhck: Could you give more details please? I've looked in the mailing list archives in May 2015 but couldn't find anything. The bottom line would be to forget about "Method 3" and stick to "Method 1".
– schieferstapel
Oct 4 '16 at 18:32
2
@MarkGerolimatos : about-g
, you say, "It neither appears to work, ... nor does it appear to be used in the code.". I checked and the the input ofg
is stored inavctx->gop_size
and that libx264 makes use of it:x4->params.i_keyint_max = avctx->gop_size;
. When I probe this generated test file:ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
, I get keyframes at exactly0,37,74,111,148,185,222,259,296,333,370
. A GOP could be cut short if scene change is triggered, and for that-sc_threshold
could be set, which is also picked up by x264.
– Gyan
Mar 3 '17 at 11:03
add a comment |
The answer therefore seems to be:
- Method 1 is verified to work, but is
libx264
-specific, and comes at the cost of eliminating the very usefulscenecut
option inlibx264
. - Method 3 works as of the FFMPEG version of April 2015, but you should verify your results with with the script included at the bottom of this post, as the FFMPEG documentation is unclear as to the effect of the option. If it works, it is the superior of the two options.
DO NOT USE Method 2,-g
appears to be deprecated. It neither appears to work, nor is it explicitly defined in the documentation, nor is found in the help, nor does it appear to be used in the code. Code inspection shows that the-g
option is likely meant for MPEG-2 streams (there are even code stanzas referring to PAL and NTSC!).
Also:
- Files generated with Method 3 may be slightly larger than Method 1, as
interstitial I frames (keyframes) are allowed. - You should explicitly set the "-r" flag in both cases, even though Method 3 places an I frame at the next frameslot on or after the time specified. Failure to set the "-r" flag places you at the mercy of the source file, possibly with a variable frame rate. Incompatible DASH transitions may result.
- Despite the warnings in the FFMPEG documentation, method 3 is NOT less efficient than others. In fact, tests show that it might be slightly MORE efficient than method 1.
Script for the -force_key_frames
option
Here is a short PERL program I used to verify I-frame cadence based on the output of slhck's ffprobe suggestion. It seems to verify that the -force_key_frames
method will also work, and has the added benefit of allowing for scenecut
frames. I have absolutely no idea how FFMPEG makes this work, or if I just lucked out somehow because my streams happen to be well-conditioned.
In my case, I encoded at 30fps with an expected GOP size of 6 seconds, or 180 frames. I used 180 as the gopsize argument to this program verified an I frame at each multiple of 180, but setting it to 181 (or any other number not a multiple of 180) made it complain.
#!/usr/bin/perl
use strict;
my $gopsize = shift(@ARGV);
my $file = shift(@ARGV);
print "GOPSIZE = $gopsizen";
my $linenum = 0;
my $expected = 0;
open my $pipe, "ffprobe -i $file -select_streams v -show_frames -of csv -show_entries frame=pict_type |"
or die "Blah";
while (<$pipe>) {
if ($linenum > $expected) {
# Won't catch all the misses. But even one is good enough to fail.
print "Missed IFrame at $expectedn";
$expected = (int($linenum/$gopsize) + 1)*$gopsize;
}
if (m/,Is*$/) {
if ($linenum < $expected) {
# Don't care term, just an extra I frame. Snore.
#print "Free IFrame at $linenumn";
} else {
#print "IFrame HIT at $expectedn";
$expected += $gopsize;
}
}
$linenum += 1;
}
Just a note: Since this is a Q&A site and not really a discussion forum where posts are ordered chronologically, it's best to put all the information into one answer, so that people looking for a solution just have to read one post and not to look at who posted what, when :) I merged your answers and gave you a +1 on this, too. Since cross posting is not allowed, I'd suggest you delete your question on the Video site. People will find the answer(s) here.
– slhck
May 2 '15 at 10:36
1
I just had one more thought (actually it was raised on the FFmpeg mailing list). When you useforce_key_frames
, it kind of messes up the x264 bit allocation algorithm, so it may give you worse quality than simply setting a fixed keyframe interval.
– slhck
May 5 '15 at 19:25
Holy crap. Yet one more reason to have FFMPEG provide a codec-nonspecfic way to do this, an argument that would "do the best thing for the codec in question". I tried to file a ticket for this with FFMPEG's trac, but the bounced :-(
– Mark Gerolimatos
May 5 '15 at 23:16
@slhck: Could you give more details please? I've looked in the mailing list archives in May 2015 but couldn't find anything. The bottom line would be to forget about "Method 3" and stick to "Method 1".
– schieferstapel
Oct 4 '16 at 18:32
2
@MarkGerolimatos : about-g
, you say, "It neither appears to work, ... nor does it appear to be used in the code.". I checked and the the input ofg
is stored inavctx->gop_size
and that libx264 makes use of it:x4->params.i_keyint_max = avctx->gop_size;
. When I probe this generated test file:ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
, I get keyframes at exactly0,37,74,111,148,185,222,259,296,333,370
. A GOP could be cut short if scene change is triggered, and for that-sc_threshold
could be set, which is also picked up by x264.
– Gyan
Mar 3 '17 at 11:03
add a comment |
The answer therefore seems to be:
- Method 1 is verified to work, but is
libx264
-specific, and comes at the cost of eliminating the very usefulscenecut
option inlibx264
. - Method 3 works as of the FFMPEG version of April 2015, but you should verify your results with with the script included at the bottom of this post, as the FFMPEG documentation is unclear as to the effect of the option. If it works, it is the superior of the two options.
DO NOT USE Method 2,-g
appears to be deprecated. It neither appears to work, nor is it explicitly defined in the documentation, nor is found in the help, nor does it appear to be used in the code. Code inspection shows that the-g
option is likely meant for MPEG-2 streams (there are even code stanzas referring to PAL and NTSC!).
Also:
- Files generated with Method 3 may be slightly larger than Method 1, as
interstitial I frames (keyframes) are allowed. - You should explicitly set the "-r" flag in both cases, even though Method 3 places an I frame at the next frameslot on or after the time specified. Failure to set the "-r" flag places you at the mercy of the source file, possibly with a variable frame rate. Incompatible DASH transitions may result.
- Despite the warnings in the FFMPEG documentation, method 3 is NOT less efficient than others. In fact, tests show that it might be slightly MORE efficient than method 1.
Script for the -force_key_frames
option
Here is a short PERL program I used to verify I-frame cadence based on the output of slhck's ffprobe suggestion. It seems to verify that the -force_key_frames
method will also work, and has the added benefit of allowing for scenecut
frames. I have absolutely no idea how FFMPEG makes this work, or if I just lucked out somehow because my streams happen to be well-conditioned.
In my case, I encoded at 30fps with an expected GOP size of 6 seconds, or 180 frames. I used 180 as the gopsize argument to this program verified an I frame at each multiple of 180, but setting it to 181 (or any other number not a multiple of 180) made it complain.
#!/usr/bin/perl
use strict;
my $gopsize = shift(@ARGV);
my $file = shift(@ARGV);
print "GOPSIZE = $gopsizen";
my $linenum = 0;
my $expected = 0;
open my $pipe, "ffprobe -i $file -select_streams v -show_frames -of csv -show_entries frame=pict_type |"
or die "Blah";
while (<$pipe>) {
if ($linenum > $expected) {
# Won't catch all the misses. But even one is good enough to fail.
print "Missed IFrame at $expectedn";
$expected = (int($linenum/$gopsize) + 1)*$gopsize;
}
if (m/,Is*$/) {
if ($linenum < $expected) {
# Don't care term, just an extra I frame. Snore.
#print "Free IFrame at $linenumn";
} else {
#print "IFrame HIT at $expectedn";
$expected += $gopsize;
}
}
$linenum += 1;
}
The answer therefore seems to be:
- Method 1 is verified to work, but is
libx264
-specific, and comes at the cost of eliminating the very usefulscenecut
option inlibx264
. - Method 3 works as of the FFMPEG version of April 2015, but you should verify your results with with the script included at the bottom of this post, as the FFMPEG documentation is unclear as to the effect of the option. If it works, it is the superior of the two options.
DO NOT USE Method 2,-g
appears to be deprecated. It neither appears to work, nor is it explicitly defined in the documentation, nor is found in the help, nor does it appear to be used in the code. Code inspection shows that the-g
option is likely meant for MPEG-2 streams (there are even code stanzas referring to PAL and NTSC!).
Also:
- Files generated with Method 3 may be slightly larger than Method 1, as
interstitial I frames (keyframes) are allowed. - You should explicitly set the "-r" flag in both cases, even though Method 3 places an I frame at the next frameslot on or after the time specified. Failure to set the "-r" flag places you at the mercy of the source file, possibly with a variable frame rate. Incompatible DASH transitions may result.
- Despite the warnings in the FFMPEG documentation, method 3 is NOT less efficient than others. In fact, tests show that it might be slightly MORE efficient than method 1.
Script for the -force_key_frames
option
Here is a short PERL program I used to verify I-frame cadence based on the output of slhck's ffprobe suggestion. It seems to verify that the -force_key_frames
method will also work, and has the added benefit of allowing for scenecut
frames. I have absolutely no idea how FFMPEG makes this work, or if I just lucked out somehow because my streams happen to be well-conditioned.
In my case, I encoded at 30fps with an expected GOP size of 6 seconds, or 180 frames. I used 180 as the gopsize argument to this program verified an I frame at each multiple of 180, but setting it to 181 (or any other number not a multiple of 180) made it complain.
#!/usr/bin/perl
use strict;
my $gopsize = shift(@ARGV);
my $file = shift(@ARGV);
print "GOPSIZE = $gopsizen";
my $linenum = 0;
my $expected = 0;
open my $pipe, "ffprobe -i $file -select_streams v -show_frames -of csv -show_entries frame=pict_type |"
or die "Blah";
while (<$pipe>) {
if ($linenum > $expected) {
# Won't catch all the misses. But even one is good enough to fail.
print "Missed IFrame at $expectedn";
$expected = (int($linenum/$gopsize) + 1)*$gopsize;
}
if (m/,Is*$/) {
if ($linenum < $expected) {
# Don't care term, just an extra I frame. Snore.
#print "Free IFrame at $linenumn";
} else {
#print "IFrame HIT at $expectedn";
$expected += $gopsize;
}
}
$linenum += 1;
}
edited May 2 '15 at 10:35
slhck
164k47452477
164k47452477
answered May 1 '15 at 19:51
Mark GerolimatosMark Gerolimatos
6642819
6642819
Just a note: Since this is a Q&A site and not really a discussion forum where posts are ordered chronologically, it's best to put all the information into one answer, so that people looking for a solution just have to read one post and not to look at who posted what, when :) I merged your answers and gave you a +1 on this, too. Since cross posting is not allowed, I'd suggest you delete your question on the Video site. People will find the answer(s) here.
– slhck
May 2 '15 at 10:36
1
I just had one more thought (actually it was raised on the FFmpeg mailing list). When you useforce_key_frames
, it kind of messes up the x264 bit allocation algorithm, so it may give you worse quality than simply setting a fixed keyframe interval.
– slhck
May 5 '15 at 19:25
Holy crap. Yet one more reason to have FFMPEG provide a codec-nonspecfic way to do this, an argument that would "do the best thing for the codec in question". I tried to file a ticket for this with FFMPEG's trac, but the bounced :-(
– Mark Gerolimatos
May 5 '15 at 23:16
@slhck: Could you give more details please? I've looked in the mailing list archives in May 2015 but couldn't find anything. The bottom line would be to forget about "Method 3" and stick to "Method 1".
– schieferstapel
Oct 4 '16 at 18:32
2
@MarkGerolimatos : about-g
, you say, "It neither appears to work, ... nor does it appear to be used in the code.". I checked and the the input ofg
is stored inavctx->gop_size
and that libx264 makes use of it:x4->params.i_keyint_max = avctx->gop_size;
. When I probe this generated test file:ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
, I get keyframes at exactly0,37,74,111,148,185,222,259,296,333,370
. A GOP could be cut short if scene change is triggered, and for that-sc_threshold
could be set, which is also picked up by x264.
– Gyan
Mar 3 '17 at 11:03
add a comment |
Just a note: Since this is a Q&A site and not really a discussion forum where posts are ordered chronologically, it's best to put all the information into one answer, so that people looking for a solution just have to read one post and not to look at who posted what, when :) I merged your answers and gave you a +1 on this, too. Since cross posting is not allowed, I'd suggest you delete your question on the Video site. People will find the answer(s) here.
– slhck
May 2 '15 at 10:36
1
I just had one more thought (actually it was raised on the FFmpeg mailing list). When you useforce_key_frames
, it kind of messes up the x264 bit allocation algorithm, so it may give you worse quality than simply setting a fixed keyframe interval.
– slhck
May 5 '15 at 19:25
Holy crap. Yet one more reason to have FFMPEG provide a codec-nonspecfic way to do this, an argument that would "do the best thing for the codec in question". I tried to file a ticket for this with FFMPEG's trac, but the bounced :-(
– Mark Gerolimatos
May 5 '15 at 23:16
@slhck: Could you give more details please? I've looked in the mailing list archives in May 2015 but couldn't find anything. The bottom line would be to forget about "Method 3" and stick to "Method 1".
– schieferstapel
Oct 4 '16 at 18:32
2
@MarkGerolimatos : about-g
, you say, "It neither appears to work, ... nor does it appear to be used in the code.". I checked and the the input ofg
is stored inavctx->gop_size
and that libx264 makes use of it:x4->params.i_keyint_max = avctx->gop_size;
. When I probe this generated test file:ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
, I get keyframes at exactly0,37,74,111,148,185,222,259,296,333,370
. A GOP could be cut short if scene change is triggered, and for that-sc_threshold
could be set, which is also picked up by x264.
– Gyan
Mar 3 '17 at 11:03
Just a note: Since this is a Q&A site and not really a discussion forum where posts are ordered chronologically, it's best to put all the information into one answer, so that people looking for a solution just have to read one post and not to look at who posted what, when :) I merged your answers and gave you a +1 on this, too. Since cross posting is not allowed, I'd suggest you delete your question on the Video site. People will find the answer(s) here.
– slhck
May 2 '15 at 10:36
Just a note: Since this is a Q&A site and not really a discussion forum where posts are ordered chronologically, it's best to put all the information into one answer, so that people looking for a solution just have to read one post and not to look at who posted what, when :) I merged your answers and gave you a +1 on this, too. Since cross posting is not allowed, I'd suggest you delete your question on the Video site. People will find the answer(s) here.
– slhck
May 2 '15 at 10:36
1
1
I just had one more thought (actually it was raised on the FFmpeg mailing list). When you use
force_key_frames
, it kind of messes up the x264 bit allocation algorithm, so it may give you worse quality than simply setting a fixed keyframe interval.– slhck
May 5 '15 at 19:25
I just had one more thought (actually it was raised on the FFmpeg mailing list). When you use
force_key_frames
, it kind of messes up the x264 bit allocation algorithm, so it may give you worse quality than simply setting a fixed keyframe interval.– slhck
May 5 '15 at 19:25
Holy crap. Yet one more reason to have FFMPEG provide a codec-nonspecfic way to do this, an argument that would "do the best thing for the codec in question". I tried to file a ticket for this with FFMPEG's trac, but the bounced :-(
– Mark Gerolimatos
May 5 '15 at 23:16
Holy crap. Yet one more reason to have FFMPEG provide a codec-nonspecfic way to do this, an argument that would "do the best thing for the codec in question". I tried to file a ticket for this with FFMPEG's trac, but the bounced :-(
– Mark Gerolimatos
May 5 '15 at 23:16
@slhck: Could you give more details please? I've looked in the mailing list archives in May 2015 but couldn't find anything. The bottom line would be to forget about "Method 3" and stick to "Method 1".
– schieferstapel
Oct 4 '16 at 18:32
@slhck: Could you give more details please? I've looked in the mailing list archives in May 2015 but couldn't find anything. The bottom line would be to forget about "Method 3" and stick to "Method 1".
– schieferstapel
Oct 4 '16 at 18:32
2
2
@MarkGerolimatos : about
-g
, you say, "It neither appears to work, ... nor does it appear to be used in the code.". I checked and the the input of g
is stored in avctx->gop_size
and that libx264 makes use of it: x4->params.i_keyint_max = avctx->gop_size;
. When I probe this generated test file: ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
, I get keyframes at exactly 0,37,74,111,148,185,222,259,296,333,370
. A GOP could be cut short if scene change is triggered, and for that -sc_threshold
could be set, which is also picked up by x264.– Gyan
Mar 3 '17 at 11:03
@MarkGerolimatos : about
-g
, you say, "It neither appears to work, ... nor does it appear to be used in the code.". I checked and the the input of g
is stored in avctx->gop_size
and that libx264 makes use of it: x4->params.i_keyint_max = avctx->gop_size;
. When I probe this generated test file: ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
, I get keyframes at exactly 0,37,74,111,148,185,222,259,296,333,370
. A GOP could be cut short if scene change is triggered, and for that -sc_threshold
could be set, which is also picked up by x264.– Gyan
Mar 3 '17 at 11:03
add a comment |
I wanted to add some info here since my googling pulled up this discussion quite a bit in my quest to find info on trying to find a way to segment my DASH encoding the way I wanted, and none of the info I found was totally correct.
First several misconceptions to get rid of:
Not all I-frames are the same. There's big "I" frames and little "i" frames. Or to use correct terminology, IDR I-Frames and non-IDR I-Frames. IDR I-frames (sometimes called "keyframes") will create a new GOP. The non-IDR frames will not. They are handy to have inside of a GOP where there is a scene change.
-x264opts keyint=GOPSIZE:min-keyint=GOPSIZE
← This does not do what you think it does. This took me a little while to figure out. It turns out themin-keyint
is limited in the code. It is not allowed to be greater than(keyint / 2) + 1
. So assigning the same value to these two variables results in the value formin-keyint
getting knocked down by half when encoding.
Here's the thing: scene-cut is really great, especially in video that has fast hard cuts. It keeps it nice and crisp, so I don't want to disable it, but at the same time I couldn't get a fixed GOP size as long as it was enabled. I wanted to enable scene-cut, but to only have it use non-IDR I-frames. But it wasn't working. Until I figured out (from lots of reading) about misconception #2.
It turns out I needed to set keyint
to double my desired GOP size. This means that min-keyint
can be set to my desired GOP size (without the internal code cutting it in half), which prevents scene-cut detection from using IDR I-frames inside the GOP size because the frame count since the last IDR I-Frame is always less than min-keyinit
.
And finally setting the force_key_frame
option overrides the double size keyint
. So here's what works:
I prefer segments in 2 second chunks, so my GOPSIZE = Framerate * 2
ffmpeg <other_options> -force_key_frames "expr:eq(mod(n,<GOPSIZE>),0)" -x264opts rc-lookahead=<GOPSIZE>:keyint=<GOPSIZE * 2>:min-keyint=<GOPSIZE> <other_options>
You can verify using ffprobe:
ffprobe <SRC_FLE> -select_streams v -show_frames -of csv -show_entries frame=coded_picture_number,key_frame,pict_type > frames.csv
In the generated CSV file each line will tell you: frame, [is_an_IDR_?], [frame_type], [frame_number]
:
frame,1,I,60 <-- frame 60, is I frame, 1 means is an IDR I-frame (aka KeyFrame)
frame,0,I,71 <-- frame 71, is I frame, 0 means not an IDR I_frame
The result is that you should only see IDR I-Frames at fixed GOPSIZE
intervals, while all other I frames are non-IDR I-frames inserted as needed by scene-cut detection.
that was fantastic! It was aldo highly counterintuitive, thank you for putting in the effort. And to summarize, I assume your definition of "I-frames" and "i-frames" is conceptual (that is, not explictly configurable in libx264) , and that the "max * 2" was the way you enforced it?
– Mark Gerolimatos
Jun 27 '17 at 18:47
Yes that was conceptual, although I've seen people use "I" vs "i" to distinguish between IDR and non-IDR I-frames. And yes, setting keyinit to the desired gop size * 2 is a way to force all I frames inside the gop to be non-IDR I-frames. Then the ffmpeg -force-key-frames over-rides key-init in the x264opts. Basically it's a really backwards way to get the desired outcome that would be possible if the x264 code allowed you to set min-keyinit and keyinit to the same value.
– Reuben
Jun 27 '17 at 21:57
... while also being able to both keep the scene-cut detection turned on and get fixed GOP size.
– Reuben
Jun 27 '17 at 22:04
thanks again for your awesome work! Sounds like we need a less "backwards" way of effecting it
– Mark Gerolimatos
Jun 27 '17 at 22:21
Is rc-lookahead necessary here? It affects mbtree and VBV, but does it affect i-frame generation?
– Alexander Svetkin
Apr 23 '18 at 15:41
|
show 1 more comment
I wanted to add some info here since my googling pulled up this discussion quite a bit in my quest to find info on trying to find a way to segment my DASH encoding the way I wanted, and none of the info I found was totally correct.
First several misconceptions to get rid of:
Not all I-frames are the same. There's big "I" frames and little "i" frames. Or to use correct terminology, IDR I-Frames and non-IDR I-Frames. IDR I-frames (sometimes called "keyframes") will create a new GOP. The non-IDR frames will not. They are handy to have inside of a GOP where there is a scene change.
-x264opts keyint=GOPSIZE:min-keyint=GOPSIZE
← This does not do what you think it does. This took me a little while to figure out. It turns out themin-keyint
is limited in the code. It is not allowed to be greater than(keyint / 2) + 1
. So assigning the same value to these two variables results in the value formin-keyint
getting knocked down by half when encoding.
Here's the thing: scene-cut is really great, especially in video that has fast hard cuts. It keeps it nice and crisp, so I don't want to disable it, but at the same time I couldn't get a fixed GOP size as long as it was enabled. I wanted to enable scene-cut, but to only have it use non-IDR I-frames. But it wasn't working. Until I figured out (from lots of reading) about misconception #2.
It turns out I needed to set keyint
to double my desired GOP size. This means that min-keyint
can be set to my desired GOP size (without the internal code cutting it in half), which prevents scene-cut detection from using IDR I-frames inside the GOP size because the frame count since the last IDR I-Frame is always less than min-keyinit
.
And finally setting the force_key_frame
option overrides the double size keyint
. So here's what works:
I prefer segments in 2 second chunks, so my GOPSIZE = Framerate * 2
ffmpeg <other_options> -force_key_frames "expr:eq(mod(n,<GOPSIZE>),0)" -x264opts rc-lookahead=<GOPSIZE>:keyint=<GOPSIZE * 2>:min-keyint=<GOPSIZE> <other_options>
You can verify using ffprobe:
ffprobe <SRC_FLE> -select_streams v -show_frames -of csv -show_entries frame=coded_picture_number,key_frame,pict_type > frames.csv
In the generated CSV file each line will tell you: frame, [is_an_IDR_?], [frame_type], [frame_number]
:
frame,1,I,60 <-- frame 60, is I frame, 1 means is an IDR I-frame (aka KeyFrame)
frame,0,I,71 <-- frame 71, is I frame, 0 means not an IDR I_frame
The result is that you should only see IDR I-Frames at fixed GOPSIZE
intervals, while all other I frames are non-IDR I-frames inserted as needed by scene-cut detection.
that was fantastic! It was aldo highly counterintuitive, thank you for putting in the effort. And to summarize, I assume your definition of "I-frames" and "i-frames" is conceptual (that is, not explictly configurable in libx264) , and that the "max * 2" was the way you enforced it?
– Mark Gerolimatos
Jun 27 '17 at 18:47
Yes that was conceptual, although I've seen people use "I" vs "i" to distinguish between IDR and non-IDR I-frames. And yes, setting keyinit to the desired gop size * 2 is a way to force all I frames inside the gop to be non-IDR I-frames. Then the ffmpeg -force-key-frames over-rides key-init in the x264opts. Basically it's a really backwards way to get the desired outcome that would be possible if the x264 code allowed you to set min-keyinit and keyinit to the same value.
– Reuben
Jun 27 '17 at 21:57
... while also being able to both keep the scene-cut detection turned on and get fixed GOP size.
– Reuben
Jun 27 '17 at 22:04
thanks again for your awesome work! Sounds like we need a less "backwards" way of effecting it
– Mark Gerolimatos
Jun 27 '17 at 22:21
Is rc-lookahead necessary here? It affects mbtree and VBV, but does it affect i-frame generation?
– Alexander Svetkin
Apr 23 '18 at 15:41
|
show 1 more comment
I wanted to add some info here since my googling pulled up this discussion quite a bit in my quest to find info on trying to find a way to segment my DASH encoding the way I wanted, and none of the info I found was totally correct.
First several misconceptions to get rid of:
Not all I-frames are the same. There's big "I" frames and little "i" frames. Or to use correct terminology, IDR I-Frames and non-IDR I-Frames. IDR I-frames (sometimes called "keyframes") will create a new GOP. The non-IDR frames will not. They are handy to have inside of a GOP where there is a scene change.
-x264opts keyint=GOPSIZE:min-keyint=GOPSIZE
← This does not do what you think it does. This took me a little while to figure out. It turns out themin-keyint
is limited in the code. It is not allowed to be greater than(keyint / 2) + 1
. So assigning the same value to these two variables results in the value formin-keyint
getting knocked down by half when encoding.
Here's the thing: scene-cut is really great, especially in video that has fast hard cuts. It keeps it nice and crisp, so I don't want to disable it, but at the same time I couldn't get a fixed GOP size as long as it was enabled. I wanted to enable scene-cut, but to only have it use non-IDR I-frames. But it wasn't working. Until I figured out (from lots of reading) about misconception #2.
It turns out I needed to set keyint
to double my desired GOP size. This means that min-keyint
can be set to my desired GOP size (without the internal code cutting it in half), which prevents scene-cut detection from using IDR I-frames inside the GOP size because the frame count since the last IDR I-Frame is always less than min-keyinit
.
And finally setting the force_key_frame
option overrides the double size keyint
. So here's what works:
I prefer segments in 2 second chunks, so my GOPSIZE = Framerate * 2
ffmpeg <other_options> -force_key_frames "expr:eq(mod(n,<GOPSIZE>),0)" -x264opts rc-lookahead=<GOPSIZE>:keyint=<GOPSIZE * 2>:min-keyint=<GOPSIZE> <other_options>
You can verify using ffprobe:
ffprobe <SRC_FLE> -select_streams v -show_frames -of csv -show_entries frame=coded_picture_number,key_frame,pict_type > frames.csv
In the generated CSV file each line will tell you: frame, [is_an_IDR_?], [frame_type], [frame_number]
:
frame,1,I,60 <-- frame 60, is I frame, 1 means is an IDR I-frame (aka KeyFrame)
frame,0,I,71 <-- frame 71, is I frame, 0 means not an IDR I_frame
The result is that you should only see IDR I-Frames at fixed GOPSIZE
intervals, while all other I frames are non-IDR I-frames inserted as needed by scene-cut detection.
I wanted to add some info here since my googling pulled up this discussion quite a bit in my quest to find info on trying to find a way to segment my DASH encoding the way I wanted, and none of the info I found was totally correct.
First several misconceptions to get rid of:
Not all I-frames are the same. There's big "I" frames and little "i" frames. Or to use correct terminology, IDR I-Frames and non-IDR I-Frames. IDR I-frames (sometimes called "keyframes") will create a new GOP. The non-IDR frames will not. They are handy to have inside of a GOP where there is a scene change.
-x264opts keyint=GOPSIZE:min-keyint=GOPSIZE
← This does not do what you think it does. This took me a little while to figure out. It turns out themin-keyint
is limited in the code. It is not allowed to be greater than(keyint / 2) + 1
. So assigning the same value to these two variables results in the value formin-keyint
getting knocked down by half when encoding.
Here's the thing: scene-cut is really great, especially in video that has fast hard cuts. It keeps it nice and crisp, so I don't want to disable it, but at the same time I couldn't get a fixed GOP size as long as it was enabled. I wanted to enable scene-cut, but to only have it use non-IDR I-frames. But it wasn't working. Until I figured out (from lots of reading) about misconception #2.
It turns out I needed to set keyint
to double my desired GOP size. This means that min-keyint
can be set to my desired GOP size (without the internal code cutting it in half), which prevents scene-cut detection from using IDR I-frames inside the GOP size because the frame count since the last IDR I-Frame is always less than min-keyinit
.
And finally setting the force_key_frame
option overrides the double size keyint
. So here's what works:
I prefer segments in 2 second chunks, so my GOPSIZE = Framerate * 2
ffmpeg <other_options> -force_key_frames "expr:eq(mod(n,<GOPSIZE>),0)" -x264opts rc-lookahead=<GOPSIZE>:keyint=<GOPSIZE * 2>:min-keyint=<GOPSIZE> <other_options>
You can verify using ffprobe:
ffprobe <SRC_FLE> -select_streams v -show_frames -of csv -show_entries frame=coded_picture_number,key_frame,pict_type > frames.csv
In the generated CSV file each line will tell you: frame, [is_an_IDR_?], [frame_type], [frame_number]
:
frame,1,I,60 <-- frame 60, is I frame, 1 means is an IDR I-frame (aka KeyFrame)
frame,0,I,71 <-- frame 71, is I frame, 0 means not an IDR I_frame
The result is that you should only see IDR I-Frames at fixed GOPSIZE
intervals, while all other I frames are non-IDR I-frames inserted as needed by scene-cut detection.
edited Apr 24 '18 at 18:47
answered Jun 27 '17 at 18:39
ReubenReuben
792
792
that was fantastic! It was aldo highly counterintuitive, thank you for putting in the effort. And to summarize, I assume your definition of "I-frames" and "i-frames" is conceptual (that is, not explictly configurable in libx264) , and that the "max * 2" was the way you enforced it?
– Mark Gerolimatos
Jun 27 '17 at 18:47
Yes that was conceptual, although I've seen people use "I" vs "i" to distinguish between IDR and non-IDR I-frames. And yes, setting keyinit to the desired gop size * 2 is a way to force all I frames inside the gop to be non-IDR I-frames. Then the ffmpeg -force-key-frames over-rides key-init in the x264opts. Basically it's a really backwards way to get the desired outcome that would be possible if the x264 code allowed you to set min-keyinit and keyinit to the same value.
– Reuben
Jun 27 '17 at 21:57
... while also being able to both keep the scene-cut detection turned on and get fixed GOP size.
– Reuben
Jun 27 '17 at 22:04
thanks again for your awesome work! Sounds like we need a less "backwards" way of effecting it
– Mark Gerolimatos
Jun 27 '17 at 22:21
Is rc-lookahead necessary here? It affects mbtree and VBV, but does it affect i-frame generation?
– Alexander Svetkin
Apr 23 '18 at 15:41
|
show 1 more comment
that was fantastic! It was aldo highly counterintuitive, thank you for putting in the effort. And to summarize, I assume your definition of "I-frames" and "i-frames" is conceptual (that is, not explictly configurable in libx264) , and that the "max * 2" was the way you enforced it?
– Mark Gerolimatos
Jun 27 '17 at 18:47
Yes that was conceptual, although I've seen people use "I" vs "i" to distinguish between IDR and non-IDR I-frames. And yes, setting keyinit to the desired gop size * 2 is a way to force all I frames inside the gop to be non-IDR I-frames. Then the ffmpeg -force-key-frames over-rides key-init in the x264opts. Basically it's a really backwards way to get the desired outcome that would be possible if the x264 code allowed you to set min-keyinit and keyinit to the same value.
– Reuben
Jun 27 '17 at 21:57
... while also being able to both keep the scene-cut detection turned on and get fixed GOP size.
– Reuben
Jun 27 '17 at 22:04
thanks again for your awesome work! Sounds like we need a less "backwards" way of effecting it
– Mark Gerolimatos
Jun 27 '17 at 22:21
Is rc-lookahead necessary here? It affects mbtree and VBV, but does it affect i-frame generation?
– Alexander Svetkin
Apr 23 '18 at 15:41
that was fantastic! It was aldo highly counterintuitive, thank you for putting in the effort. And to summarize, I assume your definition of "I-frames" and "i-frames" is conceptual (that is, not explictly configurable in libx264) , and that the "max * 2" was the way you enforced it?
– Mark Gerolimatos
Jun 27 '17 at 18:47
that was fantastic! It was aldo highly counterintuitive, thank you for putting in the effort. And to summarize, I assume your definition of "I-frames" and "i-frames" is conceptual (that is, not explictly configurable in libx264) , and that the "max * 2" was the way you enforced it?
– Mark Gerolimatos
Jun 27 '17 at 18:47
Yes that was conceptual, although I've seen people use "I" vs "i" to distinguish between IDR and non-IDR I-frames. And yes, setting keyinit to the desired gop size * 2 is a way to force all I frames inside the gop to be non-IDR I-frames. Then the ffmpeg -force-key-frames over-rides key-init in the x264opts. Basically it's a really backwards way to get the desired outcome that would be possible if the x264 code allowed you to set min-keyinit and keyinit to the same value.
– Reuben
Jun 27 '17 at 21:57
Yes that was conceptual, although I've seen people use "I" vs "i" to distinguish between IDR and non-IDR I-frames. And yes, setting keyinit to the desired gop size * 2 is a way to force all I frames inside the gop to be non-IDR I-frames. Then the ffmpeg -force-key-frames over-rides key-init in the x264opts. Basically it's a really backwards way to get the desired outcome that would be possible if the x264 code allowed you to set min-keyinit and keyinit to the same value.
– Reuben
Jun 27 '17 at 21:57
... while also being able to both keep the scene-cut detection turned on and get fixed GOP size.
– Reuben
Jun 27 '17 at 22:04
... while also being able to both keep the scene-cut detection turned on and get fixed GOP size.
– Reuben
Jun 27 '17 at 22:04
thanks again for your awesome work! Sounds like we need a less "backwards" way of effecting it
– Mark Gerolimatos
Jun 27 '17 at 22:21
thanks again for your awesome work! Sounds like we need a less "backwards" way of effecting it
– Mark Gerolimatos
Jun 27 '17 at 22:21
Is rc-lookahead necessary here? It affects mbtree and VBV, but does it affect i-frame generation?
– Alexander Svetkin
Apr 23 '18 at 15:41
Is rc-lookahead necessary here? It affects mbtree and VBV, but does it affect i-frame generation?
– Alexander Svetkin
Apr 23 '18 at 15:41
|
show 1 more comment
It seems that this syntax doesnt allways work.. Ive tested quite alot on our VOD content as well as live content (file dumps) and sometimes scenecut doesnt work and trigger a inbetween iframe:
Syntax for a i50->p50 upconvertion, 2 sec gop/segment, IDR at the start, iframes inbetween if needed
ffmpeg.exe -loglevel verbose -i avc_50i.ts -pix_fmt yuv420p -filter_complex yadif=1,scale=1920:1080 -vcodec libx264 -preset fast -x264-params "rc-lookahead=100:keyint=200:min-keyint=100:hrd=1:vbv_maxrate=12000:vbv_bufsize=12000:no-open-gop=1" -r 50 -crf 22 -force_key_frames "expr:eq(mod(n,100),0)" -codec:a aac -b:a 128k -y target.ts
add a comment |
It seems that this syntax doesnt allways work.. Ive tested quite alot on our VOD content as well as live content (file dumps) and sometimes scenecut doesnt work and trigger a inbetween iframe:
Syntax for a i50->p50 upconvertion, 2 sec gop/segment, IDR at the start, iframes inbetween if needed
ffmpeg.exe -loglevel verbose -i avc_50i.ts -pix_fmt yuv420p -filter_complex yadif=1,scale=1920:1080 -vcodec libx264 -preset fast -x264-params "rc-lookahead=100:keyint=200:min-keyint=100:hrd=1:vbv_maxrate=12000:vbv_bufsize=12000:no-open-gop=1" -r 50 -crf 22 -force_key_frames "expr:eq(mod(n,100),0)" -codec:a aac -b:a 128k -y target.ts
add a comment |
It seems that this syntax doesnt allways work.. Ive tested quite alot on our VOD content as well as live content (file dumps) and sometimes scenecut doesnt work and trigger a inbetween iframe:
Syntax for a i50->p50 upconvertion, 2 sec gop/segment, IDR at the start, iframes inbetween if needed
ffmpeg.exe -loglevel verbose -i avc_50i.ts -pix_fmt yuv420p -filter_complex yadif=1,scale=1920:1080 -vcodec libx264 -preset fast -x264-params "rc-lookahead=100:keyint=200:min-keyint=100:hrd=1:vbv_maxrate=12000:vbv_bufsize=12000:no-open-gop=1" -r 50 -crf 22 -force_key_frames "expr:eq(mod(n,100),0)" -codec:a aac -b:a 128k -y target.ts
It seems that this syntax doesnt allways work.. Ive tested quite alot on our VOD content as well as live content (file dumps) and sometimes scenecut doesnt work and trigger a inbetween iframe:
Syntax for a i50->p50 upconvertion, 2 sec gop/segment, IDR at the start, iframes inbetween if needed
ffmpeg.exe -loglevel verbose -i avc_50i.ts -pix_fmt yuv420p -filter_complex yadif=1,scale=1920:1080 -vcodec libx264 -preset fast -x264-params "rc-lookahead=100:keyint=200:min-keyint=100:hrd=1:vbv_maxrate=12000:vbv_bufsize=12000:no-open-gop=1" -r 50 -crf 22 -force_key_frames "expr:eq(mod(n,100),0)" -codec:a aac -b:a 128k -y target.ts
edited 5 hours ago
JakeGould
33k10100142
33k10100142
answered Oct 31 '18 at 12:06
TEBTEB
1
1
add a comment |
add a comment |
Twitch has a post about this. They explain that they decided to use their own program for several reasons; one of them was that ffmpeg doesn't let you run different x264 instances in different threads, but instead devotes all specified threads to one frame in one output before moving on to the next output.
If you aren't doing real-time streaming, you have more luxury. The 'correct' way is probably to encode at one resolution with just the GOP size specified with -g, and then encode the other resolutions forcing keyframes at the same places.
If you wanted to do that, you might use ffprobe to get the keyframe times and then use a shell script or an actual programming language to convert that into an ffmpeg command.
But for most content, there's very little difference between having one keyframe every 5 seconds and two keyframes every 5 seconds (one forced and one from scenecut). This is about the average I-frame size vs the size of P-frames and B-frames. If you use x264 with typical settings (the only reason I think you should do anything to affect these is if you set -qmin, as a poor way of preventing x264 from using bitrate on easy content; this limits all frame types to the same value, I think) and get a result like I-frame average size of 46 kB, P-frame 24 kB, B-frame 17 kB (half as frequent as P-frames), then an extra I-frame every second at 30 fps is only a 3% increase in file size. The difference between h264 and h263 might be made up of a bunch of 3% decreases, but a single one isn't very important.
On other types of content, frame sizes will be different. To be fair, this is about temporal complexity and not spatial complexity, so it isn't just easy content vs hard content. But generally, streaming video sites have a bitrate limit, and content with relatively large I-frames is easy content that will be encoded at high quality no matter how many extra keyframes are added. It's wasteful, but this waste will usually not be noticed. The most wasteful case is probably a video that's just a static image accompanying a song, where each keyframe is exactly the same.
One thing I'm not sure of is how forced keyframes interact with the rate limiter set with -maxrate and -bufsize. I think even YouTube has had recent problems correctly configuring buffer settings to give consistent quality. If you're just using average bitrate settings as can be seen by some sites (since you can inspect x264's options in the header/mov atom? with a hex editor) then the buffer model isn't a problem, but if you're serving user-generated content, average bitrate encourages users to add a black screen at the end of their video.
Ffmpeg's -g option, or any other encoder option that you use, is mapped to the encoder-specific option. So '-x264-params keyint=GOPSIZE' is equivalent to '-g GOPSIZE'.
One problem with using scene detection is if you prefer keyframes near specific numbers for whatever reason. If you specify keyframes every 5 seconds and use scene detection, and there's a scene change at 4.5, then it should be detected, but then the next keyframe will be at 9.5. If the time keeps getting stepped up like this, you could end up with keyframes at 42.5, 47.5, 52.5, etc., instead of 40, 45, 50, 55. Conversely, if there's a scene change at 5.5, then there will be a keyframe at 5 and 5.5 will be too early for another one. Ffmpeg doesn't let you specify "make a keyframe here if there's no scene change within the next 30 frames". Someone who understands C could add that option, though.
For variable-frame-rate video, when you're not live-streaming like Twitch, you should be able to use scene changes without converting permanently to constant frame-rate. If you use the 'select' filter in ffmpeg and use the 'scene' constant in the expression, then the debug output (-v debug or press '+' several times while encoding) shows the scene change number. This is probably different from, and not as useful as, the number used by x264, but it could still be useful.
The procedure, then, would probably be to do a test video that's only for keyframe changes, but maybe could be used for rate control data if using 2-pass. (Not sure if the generated data is at all useful for different resolutions and settings; the macroblock-tree data won't be.) Convert it to constant-framerate video, but see this bug about stuttering output when halving framerate if you ever decide to use the fps filter for other purposes. Run it through x264 with your desired keyframe and GOP settings.
Then just use these keyframe times with the original variable frame-rate video.
If you allow completely crazy user-generated content with a 20-second gap between frames, then for the variable frame-rate encode, you could split the output, use fps filter, somehow use select filter (maybe build a really long expression that has every keyframe time)... or maybe you could use the test video as input and either decode only keyframes, if that ffmpeg option works, or use the select filter to select keyframes. Then scale it to the correct size (there's even a scale2ref filter for this) and overlay the original video on it. Then use the interleave filter to combine these destined-to-be forced keyframes with the original video. If this results in two frames that are 0.001 sec apart that the interleave filter doesn't prevent, then address this problem yourself with another select filter. Dealing with frame buffer limits for the interleave filter could be the main problem here. These could all work: use some kind of filter to buffer the denser stream (fifo filter?); refer to the input file multiple times so it's decoded more than once and frames don't have to be stored; use the 'streamselect' filter, which I have never done, at exactly the times of the keyframes; improve the interleave filter by changing its default behaviour or adding an option to output the oldest frame in a buffer instead of dropping a frame.
add a comment |
Twitch has a post about this. They explain that they decided to use their own program for several reasons; one of them was that ffmpeg doesn't let you run different x264 instances in different threads, but instead devotes all specified threads to one frame in one output before moving on to the next output.
If you aren't doing real-time streaming, you have more luxury. The 'correct' way is probably to encode at one resolution with just the GOP size specified with -g, and then encode the other resolutions forcing keyframes at the same places.
If you wanted to do that, you might use ffprobe to get the keyframe times and then use a shell script or an actual programming language to convert that into an ffmpeg command.
But for most content, there's very little difference between having one keyframe every 5 seconds and two keyframes every 5 seconds (one forced and one from scenecut). This is about the average I-frame size vs the size of P-frames and B-frames. If you use x264 with typical settings (the only reason I think you should do anything to affect these is if you set -qmin, as a poor way of preventing x264 from using bitrate on easy content; this limits all frame types to the same value, I think) and get a result like I-frame average size of 46 kB, P-frame 24 kB, B-frame 17 kB (half as frequent as P-frames), then an extra I-frame every second at 30 fps is only a 3% increase in file size. The difference between h264 and h263 might be made up of a bunch of 3% decreases, but a single one isn't very important.
On other types of content, frame sizes will be different. To be fair, this is about temporal complexity and not spatial complexity, so it isn't just easy content vs hard content. But generally, streaming video sites have a bitrate limit, and content with relatively large I-frames is easy content that will be encoded at high quality no matter how many extra keyframes are added. It's wasteful, but this waste will usually not be noticed. The most wasteful case is probably a video that's just a static image accompanying a song, where each keyframe is exactly the same.
One thing I'm not sure of is how forced keyframes interact with the rate limiter set with -maxrate and -bufsize. I think even YouTube has had recent problems correctly configuring buffer settings to give consistent quality. If you're just using average bitrate settings as can be seen by some sites (since you can inspect x264's options in the header/mov atom? with a hex editor) then the buffer model isn't a problem, but if you're serving user-generated content, average bitrate encourages users to add a black screen at the end of their video.
Ffmpeg's -g option, or any other encoder option that you use, is mapped to the encoder-specific option. So '-x264-params keyint=GOPSIZE' is equivalent to '-g GOPSIZE'.
One problem with using scene detection is if you prefer keyframes near specific numbers for whatever reason. If you specify keyframes every 5 seconds and use scene detection, and there's a scene change at 4.5, then it should be detected, but then the next keyframe will be at 9.5. If the time keeps getting stepped up like this, you could end up with keyframes at 42.5, 47.5, 52.5, etc., instead of 40, 45, 50, 55. Conversely, if there's a scene change at 5.5, then there will be a keyframe at 5 and 5.5 will be too early for another one. Ffmpeg doesn't let you specify "make a keyframe here if there's no scene change within the next 30 frames". Someone who understands C could add that option, though.
For variable-frame-rate video, when you're not live-streaming like Twitch, you should be able to use scene changes without converting permanently to constant frame-rate. If you use the 'select' filter in ffmpeg and use the 'scene' constant in the expression, then the debug output (-v debug or press '+' several times while encoding) shows the scene change number. This is probably different from, and not as useful as, the number used by x264, but it could still be useful.
The procedure, then, would probably be to do a test video that's only for keyframe changes, but maybe could be used for rate control data if using 2-pass. (Not sure if the generated data is at all useful for different resolutions and settings; the macroblock-tree data won't be.) Convert it to constant-framerate video, but see this bug about stuttering output when halving framerate if you ever decide to use the fps filter for other purposes. Run it through x264 with your desired keyframe and GOP settings.
Then just use these keyframe times with the original variable frame-rate video.
If you allow completely crazy user-generated content with a 20-second gap between frames, then for the variable frame-rate encode, you could split the output, use fps filter, somehow use select filter (maybe build a really long expression that has every keyframe time)... or maybe you could use the test video as input and either decode only keyframes, if that ffmpeg option works, or use the select filter to select keyframes. Then scale it to the correct size (there's even a scale2ref filter for this) and overlay the original video on it. Then use the interleave filter to combine these destined-to-be forced keyframes with the original video. If this results in two frames that are 0.001 sec apart that the interleave filter doesn't prevent, then address this problem yourself with another select filter. Dealing with frame buffer limits for the interleave filter could be the main problem here. These could all work: use some kind of filter to buffer the denser stream (fifo filter?); refer to the input file multiple times so it's decoded more than once and frames don't have to be stored; use the 'streamselect' filter, which I have never done, at exactly the times of the keyframes; improve the interleave filter by changing its default behaviour or adding an option to output the oldest frame in a buffer instead of dropping a frame.
add a comment |
Twitch has a post about this. They explain that they decided to use their own program for several reasons; one of them was that ffmpeg doesn't let you run different x264 instances in different threads, but instead devotes all specified threads to one frame in one output before moving on to the next output.
If you aren't doing real-time streaming, you have more luxury. The 'correct' way is probably to encode at one resolution with just the GOP size specified with -g, and then encode the other resolutions forcing keyframes at the same places.
If you wanted to do that, you might use ffprobe to get the keyframe times and then use a shell script or an actual programming language to convert that into an ffmpeg command.
But for most content, there's very little difference between having one keyframe every 5 seconds and two keyframes every 5 seconds (one forced and one from scenecut). This is about the average I-frame size vs the size of P-frames and B-frames. If you use x264 with typical settings (the only reason I think you should do anything to affect these is if you set -qmin, as a poor way of preventing x264 from using bitrate on easy content; this limits all frame types to the same value, I think) and get a result like I-frame average size of 46 kB, P-frame 24 kB, B-frame 17 kB (half as frequent as P-frames), then an extra I-frame every second at 30 fps is only a 3% increase in file size. The difference between h264 and h263 might be made up of a bunch of 3% decreases, but a single one isn't very important.
On other types of content, frame sizes will be different. To be fair, this is about temporal complexity and not spatial complexity, so it isn't just easy content vs hard content. But generally, streaming video sites have a bitrate limit, and content with relatively large I-frames is easy content that will be encoded at high quality no matter how many extra keyframes are added. It's wasteful, but this waste will usually not be noticed. The most wasteful case is probably a video that's just a static image accompanying a song, where each keyframe is exactly the same.
One thing I'm not sure of is how forced keyframes interact with the rate limiter set with -maxrate and -bufsize. I think even YouTube has had recent problems correctly configuring buffer settings to give consistent quality. If you're just using average bitrate settings as can be seen by some sites (since you can inspect x264's options in the header/mov atom? with a hex editor) then the buffer model isn't a problem, but if you're serving user-generated content, average bitrate encourages users to add a black screen at the end of their video.
Ffmpeg's -g option, or any other encoder option that you use, is mapped to the encoder-specific option. So '-x264-params keyint=GOPSIZE' is equivalent to '-g GOPSIZE'.
One problem with using scene detection is if you prefer keyframes near specific numbers for whatever reason. If you specify keyframes every 5 seconds and use scene detection, and there's a scene change at 4.5, then it should be detected, but then the next keyframe will be at 9.5. If the time keeps getting stepped up like this, you could end up with keyframes at 42.5, 47.5, 52.5, etc., instead of 40, 45, 50, 55. Conversely, if there's a scene change at 5.5, then there will be a keyframe at 5 and 5.5 will be too early for another one. Ffmpeg doesn't let you specify "make a keyframe here if there's no scene change within the next 30 frames". Someone who understands C could add that option, though.
For variable-frame-rate video, when you're not live-streaming like Twitch, you should be able to use scene changes without converting permanently to constant frame-rate. If you use the 'select' filter in ffmpeg and use the 'scene' constant in the expression, then the debug output (-v debug or press '+' several times while encoding) shows the scene change number. This is probably different from, and not as useful as, the number used by x264, but it could still be useful.
The procedure, then, would probably be to do a test video that's only for keyframe changes, but maybe could be used for rate control data if using 2-pass. (Not sure if the generated data is at all useful for different resolutions and settings; the macroblock-tree data won't be.) Convert it to constant-framerate video, but see this bug about stuttering output when halving framerate if you ever decide to use the fps filter for other purposes. Run it through x264 with your desired keyframe and GOP settings.
Then just use these keyframe times with the original variable frame-rate video.
If you allow completely crazy user-generated content with a 20-second gap between frames, then for the variable frame-rate encode, you could split the output, use fps filter, somehow use select filter (maybe build a really long expression that has every keyframe time)... or maybe you could use the test video as input and either decode only keyframes, if that ffmpeg option works, or use the select filter to select keyframes. Then scale it to the correct size (there's even a scale2ref filter for this) and overlay the original video on it. Then use the interleave filter to combine these destined-to-be forced keyframes with the original video. If this results in two frames that are 0.001 sec apart that the interleave filter doesn't prevent, then address this problem yourself with another select filter. Dealing with frame buffer limits for the interleave filter could be the main problem here. These could all work: use some kind of filter to buffer the denser stream (fifo filter?); refer to the input file multiple times so it's decoded more than once and frames don't have to be stored; use the 'streamselect' filter, which I have never done, at exactly the times of the keyframes; improve the interleave filter by changing its default behaviour or adding an option to output the oldest frame in a buffer instead of dropping a frame.
Twitch has a post about this. They explain that they decided to use their own program for several reasons; one of them was that ffmpeg doesn't let you run different x264 instances in different threads, but instead devotes all specified threads to one frame in one output before moving on to the next output.
If you aren't doing real-time streaming, you have more luxury. The 'correct' way is probably to encode at one resolution with just the GOP size specified with -g, and then encode the other resolutions forcing keyframes at the same places.
If you wanted to do that, you might use ffprobe to get the keyframe times and then use a shell script or an actual programming language to convert that into an ffmpeg command.
But for most content, there's very little difference between having one keyframe every 5 seconds and two keyframes every 5 seconds (one forced and one from scenecut). This is about the average I-frame size vs the size of P-frames and B-frames. If you use x264 with typical settings (the only reason I think you should do anything to affect these is if you set -qmin, as a poor way of preventing x264 from using bitrate on easy content; this limits all frame types to the same value, I think) and get a result like I-frame average size of 46 kB, P-frame 24 kB, B-frame 17 kB (half as frequent as P-frames), then an extra I-frame every second at 30 fps is only a 3% increase in file size. The difference between h264 and h263 might be made up of a bunch of 3% decreases, but a single one isn't very important.
On other types of content, frame sizes will be different. To be fair, this is about temporal complexity and not spatial complexity, so it isn't just easy content vs hard content. But generally, streaming video sites have a bitrate limit, and content with relatively large I-frames is easy content that will be encoded at high quality no matter how many extra keyframes are added. It's wasteful, but this waste will usually not be noticed. The most wasteful case is probably a video that's just a static image accompanying a song, where each keyframe is exactly the same.
One thing I'm not sure of is how forced keyframes interact with the rate limiter set with -maxrate and -bufsize. I think even YouTube has had recent problems correctly configuring buffer settings to give consistent quality. If you're just using average bitrate settings as can be seen by some sites (since you can inspect x264's options in the header/mov atom? with a hex editor) then the buffer model isn't a problem, but if you're serving user-generated content, average bitrate encourages users to add a black screen at the end of their video.
Ffmpeg's -g option, or any other encoder option that you use, is mapped to the encoder-specific option. So '-x264-params keyint=GOPSIZE' is equivalent to '-g GOPSIZE'.
One problem with using scene detection is if you prefer keyframes near specific numbers for whatever reason. If you specify keyframes every 5 seconds and use scene detection, and there's a scene change at 4.5, then it should be detected, but then the next keyframe will be at 9.5. If the time keeps getting stepped up like this, you could end up with keyframes at 42.5, 47.5, 52.5, etc., instead of 40, 45, 50, 55. Conversely, if there's a scene change at 5.5, then there will be a keyframe at 5 and 5.5 will be too early for another one. Ffmpeg doesn't let you specify "make a keyframe here if there's no scene change within the next 30 frames". Someone who understands C could add that option, though.
For variable-frame-rate video, when you're not live-streaming like Twitch, you should be able to use scene changes without converting permanently to constant frame-rate. If you use the 'select' filter in ffmpeg and use the 'scene' constant in the expression, then the debug output (-v debug or press '+' several times while encoding) shows the scene change number. This is probably different from, and not as useful as, the number used by x264, but it could still be useful.
The procedure, then, would probably be to do a test video that's only for keyframe changes, but maybe could be used for rate control data if using 2-pass. (Not sure if the generated data is at all useful for different resolutions and settings; the macroblock-tree data won't be.) Convert it to constant-framerate video, but see this bug about stuttering output when halving framerate if you ever decide to use the fps filter for other purposes. Run it through x264 with your desired keyframe and GOP settings.
Then just use these keyframe times with the original variable frame-rate video.
If you allow completely crazy user-generated content with a 20-second gap between frames, then for the variable frame-rate encode, you could split the output, use fps filter, somehow use select filter (maybe build a really long expression that has every keyframe time)... or maybe you could use the test video as input and either decode only keyframes, if that ffmpeg option works, or use the select filter to select keyframes. Then scale it to the correct size (there's even a scale2ref filter for this) and overlay the original video on it. Then use the interleave filter to combine these destined-to-be forced keyframes with the original video. If this results in two frames that are 0.001 sec apart that the interleave filter doesn't prevent, then address this problem yourself with another select filter. Dealing with frame buffer limits for the interleave filter could be the main problem here. These could all work: use some kind of filter to buffer the denser stream (fifo filter?); refer to the input file multiple times so it's decoded more than once and frames don't have to be stored; use the 'streamselect' filter, which I have never done, at exactly the times of the keyframes; improve the interleave filter by changing its default behaviour or adding an option to output the oldest frame in a buffer instead of dropping a frame.
edited 5 hours ago
answered 6 hours ago
MisakiMisaki
185
185
add a comment |
add a comment |
Thanks for contributing an answer to Super User!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f908280%2fwhat-is-the-correct-way-to-fix-keyframes-in-ffmpeg-for-dash%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown