何と言うか
キーフレームの間隔が分かったから何なんだ、と言う気がしないでもないですが、動画配信の仕事をしていると
年に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を使用せずともキーフレーム間隔を知ることが出来ます。