星期三, 4月 13, 2016

ffmpeg gop 大小 x264 設定

http://superuser.com/questions/908280/what-is-the-correct-way-to-fix-keyframes-in-ffmpeg-for-dash


Method 1: with libx264's arguments
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1

#在壓x264時,有二個參數可以用來設定gop的大小,如果要設定成固定長度的gop,如每25個frame為一個GOP,則要把keyint 及 min-keyint設成同樣的值。
#在壓x264時,如果只設定keyint,則x264內定演算法scene_cut會偵測場景變化,選擇最有效率的I frame及GOP大小進行壓縮,此時,每個GOP的大小會是不定長度。
#scenecut=-1代表disable,則會採固定長度GOP進行壓縮,壓縮效率會比較差。

You should simply set the keyint and min-keyint to the same value and disable scene detection. If you don't disable scene detection, the "counter" will indeed be reset, and your keyframes end up at irregular intervals.
Note that I am not assuming variable framerate sequences here. I honestly have no idea how to deal with those in practice—I honestly haven't come across any before.
To give you an example, I converted a clip three times:
  • keyint=25 (i.e., scenecut enabled)
  • keyint=25:scenecut=-1
  • keyint=25:min-keyint=25:scenecut=-1
The frames are shown in the three columns:

As you can see, disabling scene cut detection and setting the keyframe interval is enough. It seems that even if you don't set a minimum, it'll insert keyframes at least at the interval specified by keyint. To be safe you should probably set min-keyint too.
I've researched this quite a bit a while ago—I'm currently involved in creating an ITU-T recommendation dealing with the analysis of DASH-type video transmission, so we had to figure out encoding settings that would be realistic, and from all of the documents and guides I've read, disabling scene cut detection and forcing the keyframe interval in x264 directly was the method of choice.
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
1  
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
    
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


up vote 2 down vote accepted
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 useful scenecut option in libx264.
  • 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 = $gopsize\n";
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 $expected\n";
    $expected = (int($linenum/$gopsize) + 1)*$gopsize;
  }
  if (m/,I\s*$/) {
    if ($linenum < $expected) {
      # Don't care term, just an extra I frame. Snore.
      #print "Free IFrame at $linenum\n";
    } else {
      #print "IFrame HIT at $expected\n";
      $expected += $gopsize;
    }
  }
  $linenum += 1;
}

沒有留言: