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

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