LoginSignup
17
11

More than 5 years have passed since last update.

H.264のmp4のキーフレーム間隔をmp4boxを使って知る

Last updated at Posted at 2016-12-01

何と言うか

キーフレームの間隔が分かったから何なんだ、と言う気がしないでもないですが、動画配信の仕事をしていると
年に2~3回はキーフレームの間隔を調べている気がするので、小ネタとして残しておきます。

mp4boxを使う

こんなコマンドを叩きます。

mp4box -dts some.mp4

すると、some_ts.txtと言う名前のファイルが出力されるのでそれを開きます。

#dumping track ID 1 timing:
Num         DTS         CTS         Size    RAP Offset  isLeading   DependsOn   DependedOn  Redundant   RAP-SampleGroup Roll-SampleGroup    Roll-Distance
Sample 1    DTS 0       CTS 0       1659    1   128407  0           0           0           0           0               0                   0
Sample 2    DTS 1001    CTS 1001    476     0   130066  0           0           0           0           0               0                   0
Sample 3    DTS 2002    CTS 2002    208     0   130542  0           0           0           0           0               0                   0
Sample 4    DTS 3003    CTS 3003    167     0   130750  0           0           0           0           0               0                   0
                                       ・
                                       ・
                                       ・
Sample 55   DTS 54054   CTS 54054   7228    0   453175  0           0           0           0           0               0                   0
Sample 56   DTS 55055   CTS 55055   8792    0   460403  0           0           0           0           0               0                   0
Sample 57   DTS 56056   CTS 56056   9341    0   469195  0           0           0           0           0               0                   0
Sample 58   DTS 57057   CTS 57057   8719    0   485898  0           0           0           0           0               0                   0
Sample 59   DTS 58058   CTS 58058   8430    0   494617  0           0           0           0           0               0                   0
Sample 60   DTS 59059   CTS 59059   8284    0   503047  0           0           0           0           0               0                   0
Sample 61   DTS 60060   CTS 60060   18047   1   511331  0           0           0           0           0               0                   0
Sample 62   DTS 61061   CTS 61061   9091    0   529378  0           0           0           0           0               0                   0
Sample 63   DTS 62062   CTS 62062   8669    0   538469  0           0           0           0           0               0                   0
Sample 64   DTS 63063   CTS 63063   8897    0   547138  0           0           0           0           0               0                   0
                                       ・
                                       ・
                                       ・
Sample 117  DTS 116116  CTS 116116  5087    0   1170777 0           0           0           0           0               0                   0
Sample 118  DTS 117117  CTS 117117  4568    0   1175864 0           0           0           0           0               0                   0
Sample 119  DTS 118118  CTS 118118  4550    0   1180432 0           0           0           0           0               0                   0
Sample 120  DTS 119119  CTS 119119  4547    0   1184982 0           0           0           0           0               0                   0
Sample 121  DTS 120120  CTS 120120  32371   1   1189529 0           0           0           0           0               0                   0
Sample 122  DTS 121121  CTS 121121  1740    0   1221900 0           0           0           0           0               0                   0
Sample 123  DTS 122122  CTS 122122  3630    0   1223640 0           0           0           0           0               0                   0
Sample 124  DTS 123123  CTS 123123  4245    0   1227270 0           0           0           0           0               0                   0
                                       ・
                                       ・
                                       ・

ファイルの中身はこんな感じです。各sampleのDTSやCTS、サイズなのが一覧できます。

一覧を眺める

各行のRAP列に注目します。RAPはRandom Access Pointの略で、要は動画再生時にシークを行った際に再生される箇所です。
このRAP列に1が立っているSampleがキーフレームです。と言う事で、RAP列に1が立ったsampleのDTSの間隔がキーフレーム間隔になります。

Sample 1    DTS 0       CTS 0       1659    1   128407  0   0   0   0   0   0   0
Sample 61   DTS 60060   CTS 60060   18047   1   511331  0   0   0   0   0   0   0
Sample 121  DTS 120120  CTS 120120  32371   1   1189529 0   0   0   0   0   0   0
Sample 181  DTS 180180  CTS 180180  21589   1   1525255 0   0   0   0   0   0   0
Sample 241  DTS 240240  CTS 240240  22444   1   1863545 0   0   0   0   0   0   0
Sample 301  DTS 300300  CTS 300300  28871   1   2082679 0   0   0   0   0   0   0
Sample 361  DTS 360360  CTS 360360  23859   1   2504712 0   0   0   0   0   0   0
Sample 421  DTS 420420  CTS 420420  29967   1   3031985 0   0   0   0   0   0   0
Sample 481  DTS 480480  CTS 480480  32377   1   3386185 0   0   0   0   0   0   0
Sample 541  DTS 540540  CTS 540540  32139   1   3677139 0   0   0   0   0   0   0
Sample 601  DTS 600600  CTS 600600  31110   1   4110642 0   0   0   0   0   0   0

キーフレームのSampleだけを幾つか抜粋してみるとこんな感じです。
きれいに60Sampleずつ、DTSが60060ずつの差になっていますね。動画配信に適したエンコードがされている様子です。

この一覧のDTSは秒ではなく、タイムスケールをベースにしたタイムスタンプなのでタイムスケールで割ってあげると秒になります。
このmp4の映像トラックのタイムスケールは30000なので、60060 ÷ 30000 = 2.002 となり、このmp4のキーフレーム間隔は約2秒となります。

別のアプローチとして

ここまではmp4boxを使ってキーフレーム間隔を調べましたが、mp4をバイナリエディタで開いて「ふむふむ、ナルホドー」と
mp4 Parsable EYEを持つ方なら、mp4の内容からキーフレーム間隔を調べることが可能です。

先程の、RAP列に1が立ったSampleの番号は、Sync Smple Box (stss) に保存されています。
ISO/IEC 14496-12の仕様で言うと

aligned(8) class SyncSampleBox extends FullBox(‘stss’, version = 0, 0) {
  unsigned int(32) entry_count;
  int i;
  for (i=0; i < entry_count; i++) {
    unsigned int(32) sample_number;
  }
}

のsample_numberがそれに当たります。
で、1sample当たりのDTSについては、Decoding Time to Sample Box (stts) に保存されています。

aligned(8) class TimeToSampleBox extends FullBox(’stts’, version = 0, 0) {
  unsigned int(32) entry_count;
  int i;
  for (i=0; i < entry_count; i++) {
    unsigned int(32) sample_count
    unsigned int(32) sample_delta;
  }
}

のsample_deltaがそれに当たります。sttsには仕様上entryを複数持つことが可能ですが、大抵の場合は1つなので
使用するsample_deltaも1つです。複数ある場合は、そのsample_deltaを適用するsampleの数がsample_countに保存されているので
sampleとsample_deltaの組合わせは一目で分かるようになっています。

タイムスケールは、Media Header Box (mdhd) のtimescaleに保存されているので、それらを使っての計算を

int i;
double[] keyframe_durations = double[stss.entry_count - 1];
for (i=0; i < stss.entry_count - 1; i++)
  int sampleCount = stss.entry[i+1].sample_number - stss.entry[i].sample_number;
  keyframe_durations = sampleCount * stts.entry[0].sample_delta / mdhd.timascale;
}

適当にコードにするとこんな感じでしょうか。
今回使用しているmp4を見てみると、

mdhd.timesclae = 30000
stss.entry_count = 30
stss.sample_number = 1, 61, 121, 181, 241, 301 ....
stts.entry_count = 1
stts.entry[0].sample_count = 1800
stts.entry[0].sample_delta = 1001

なので、
最初のキーフレームと次のキーフレームの間のsample数は、61 - 1 = 60
1sampe当たりのdeltaは1001なので60sampleだとDTSは、60 * 1001 = 60060
timescaleは30000なのでキーフレームの間隔は、60060 / 30000 = 2.002 秒
となり、mp4boxで調べた場合と同じ結果になります。

以上のように、mp4 Parsableな目を持つ方ならmp4boxを使用せずともキーフレーム間隔を知ることが出来ます。

17
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
11