ffmpeg を使うなら知っておきたい話 PTSとかDTSの話：音ずれ問題や時間が変になるときのために ヽ(ﾟｰﾟ*ヽ)(ﾉ*ﾟｰﾟ)ﾉわぁい

みなさん、こんにちはでス。ffmpeg関連でこんな

 - [ruby と OpenCV, ffmpeg を使用した画像/動画の認識とパフォーマンスについて ヽ(ﾟｰﾟ*ヽ)(ﾉ*ﾟｰﾟ)ﾉわぁい](http://qiita.com/scleen_x_x/items/7137a58025fbefdbd18f)
 - [複数の動画を画面n分割で同期した動画をつくるのに ffmpeg, opencv, ruby でやってみた ヽ(ﾟｰﾟ*ヽ)(ﾉ*ﾟｰﾟ)ﾉわぁい](http://qiita.com/scleen_x_x/items/ef5e49c8dd46c74df9b1)
 - [おさえておきたいffmpeg高速化のまとめ：CPU使用率100%、Load Averageがぁあぁぁぁというときに ヽ(ﾟｰﾟ*ヽ)(ﾉ*ﾟｰﾟ)ﾉわぁい](http://qiita.com/scleen_x_x/items/d72fdfba30b64c938af4)
 - [YouTube の動画をコマンドラインからダウンロードできる youtube-dl をUbuntuに入れる](http://qiita.com/scleen_x_x/items/70e8b9be7858b063e0fc)

記事を書いているものでス。 :smile: ところで、ffmpegなんて普通の人は使いません :cry: もしかしたら、「ffmpegって何？」という方もいるかもしれません。ffmpegは動画関係の超絶便利なツールです。動画といってもニコニコ動画をみたり、YouTubeをみて楽しんでいるだけのひとには関係が無いものです。

**表：動画関係のユーザー層と利用頻度の高いツール**

|ユーザー層      | 良く使用されるツールとか |
|:---------------|:---------------|
| みて楽しむ | ブラウザで十分、ニコニコ動画とかYouTube観るだけだし |
| つくって楽しむ | AviUtilとかAdobePremireとか |
| ダウンロードしてごにょごにょ | 各種ダウンローダーとか変換ツール |
| めちゃくちゃにしてやりたい | ffmpeg |

昔、東京ドームで「めちゃくちゃやってやるぜぇ」とかいいながら、気がついたら解散していた、某 サイケデリック バイオレンス クライム オブ ビジュアルショック な人たちのような感じで、とにかく動画をめちゃくちゃにしてやりたい人で、プログラミングとかCLIが大好きなひと向けのツール、それが ffmpeg です。

# この記事の内容

まぁ、これだけ変なことを書いておけば、ライトな人はもうブラウザ閉じるか、戻るボタンを押してると思うので安心して次に進めます :smiling_imp: この記事は動画のPTSとかDTSが気になった人のための内容を目指してます。普通に ffmpeg 使っていたらPTSとかDTSが気になることなんてまずありません。PTSとかDTSが気になる前に読んでもなぁーという感じで、それぐらいのライトなffmpegユーザーの人は、この記事をとりあえず何かの時のためにストックして、他の記事を読んだ方がためになります :dizzy_face: バイバーイ

# 参考記事

 - http://dranger.com/ffmpeg/tutorial05.html

この記事は↑の記事をかなり参考にして書いています、ありがとー

# なんでかいているのか？

ちょっと、PTSとかDTSではまったことがあるでございます。三日に一つぐらいqiitaに記事を書こうと思ったネタとして・・・

# PTSとかDTSとは

## 細かい話をする前に動画/動画ファイルって何？

動画ファイルは使っているソフトウェアとかデバイスによって再生 :arrow_forward: できたり、再生できなかったり :boom: します。面倒な奴です :anger: さて、話を戻して、一般的な動画ファイルは、映像 :tv: と音声 :sound: が別々に保存されてます。ファイルとしては一緒になってるんですが、中身は別々です。え、何言ってるかわからない？弁当箱 :bento: 思い浮かべて、ご飯 :rice: とおかず :fried_shrimp: の間に仕切りがあるでしょ？ごはんが映像で、音声がおかず、そんな感じ :cyclone:

で、中身自体は結構いいかげんでも良くて、、、いや、良くないんですが、動画プレイヤーにとって中身がいい加減でも再生できるような、そんな仕組みになってます。子供がつくった弁当に、おもちゃのブロッコリーが入ってても食べる時にはよけて食べればオッケーとかそんな感じです。

さらに、映像と音声もどんなふうにつくっても良いことになってます。厳密には制約があるのですが、そんなものは無いとかそれぐらいな感じで覚えておいた方がいいです。弁当のごはんに、白米、炊き込みご飯、チャーハン、麦、雑穀米、酢飯、、、何でも入れていいことになってると。それが、コーデックとか言われている代物です。

まとめると

 - 映像と音声は分けて保存されている
 - 中身はいい加減でもオッケーと言うことになっている
 - 動画を再生する側がいい加減な中身でも何とか再生しようとすることになっている

こういうのが動画ファイルです :imp: こんないい加減さが良いこともあれば、困った問題を引き起こします。

## 概要

前提が説明できたので、PTSとDTSの話を書きます。映像と音声が、弁当箱のごはんとおかずのように分かれていると書きましたが、この別れた映像と音声を動画として再生するときに綺麗に合わせなければいけません。口の動作と聞こえてくる声が合っていないと気持ち悪いですよね？その合わせる仕組みが動画ファイルの中に入っています。

それが、PTSやらDTSです。

### PTSとDTS

> Fortunately, both the audio and video streams have the information about how fast and when you are supposed to play them inside of them. Audio streams have a sample rate, and the video streams have a frames per second value. However, if we simply synced the video by just counting frames and multiplying by frame rate, there is a chance that it will go out of sync with the audio. Instead, packets from the stream might have what is called a decoding time stamp (DTS) and a presentation time stamp (PTS). To understand these two values, you need to know about the way movies are stored. Some formats, like MPEG, use what they call "B" frames (B stands for "bidirectional"). The two other kinds of frames are called "I" frames and "P" frames ("I" for "intra" and "P" for "predicted"). I frames contain a full image. P frames depend upon previous I and P frames and are like diffs or deltas. B frames are the same as P frames, but depend upon information found in frames that are displayed both before and after them! This explains why we might not have a finished frame after we call avcodec_decode_video.

引用元：http://dranger.com/ffmpeg/tutorial05.html

こんな感じです。ここで大事なのは、「音声はサンプリングレート、映像はfpsとかあるけど、そのまま再生するとずれちゃうことがあるよ」と書いてあることです。で、それをよろしくうまいことやるために、DTS (decoding time stamp) と PTS (presentation time stamp) というものがあります。

#### DTSはいつデコードするのかを示したタイムスタンプのこと

再生開始後1秒の時点でデコードしろとかそういうタイムスタンプ

#### PTSはいつ再生（表示）するのかを示したタイムスタンプのこと

再生開始後2秒の時点で表示しろとかそういうタイムスタンプ

### なんで二つもタイムスタンプの種類があるのか？

で、なんで二つもタイムスタンプの種類があるのか？って疑問がわくんだけど、先ほどの引用に戻って

> Some formats, like MPEG, use what they call "B" frames (B stands for "bidirectional"). The two other kinds of frames are called "I" frames and "P" frames ("I" for "intra" and "P" for "predicted"). I frames contain a full image. P frames depend upon previous I and P frames and are like diffs or deltas. B frames are the same as P frames, but depend upon information found in frames that are displayed both before and after them! This explains why we might not have a finished frame after we call avcodec_decode_video.

MPEGみたいなフォーマットには B, I, P みたいな3種類のフレームがあって、

 - I フレームはフルイメージの情報を持ってる（つまり1画面分の情報を持ってるフレーム）
 - P フレームはその前 I フレームとの差分情報を持ってる感じ
 - B フレームはPフレームみたいに差分情報持ってるんだけど、前後のフレームの情報を持っている感じ

※全部のフレームがIフレームでもいいけど、それだとファイルサイズが大きくなりすぎるからP、Bフレームがあるというのは説明するまでもないけど、蛇足

この3種類をうまいことすることで再生ができるわけ。で、IBBPの順で再生したいフレームがあったとするでしょ。でも、↑に書いた通りBフレームは前後のフレーム情報が必要だから、デコードする順番がIPBBにならなきゃいけなくて、その順番で保存されているのです。

<pre>
   PTS: 1 4 2 3
   DTS: 1 2 3 4
Stream: I P B B
</pre>

データの順番はIPBBで、その順番でデコードするから、DTSの順番はIPBBで、でも、PTSの順番はIBBPということです。各フレーム毎にPTS,DTSの情報が入っているので、↑のようになっているとイメージしてください。

# ffmpeg と PTS のはなし： setpts とか

ffmpeg の -filter_complex オプションを使用する例で `setpts=PTS-STARTPTS` のようなものを見たことがあるかもしれません。これが、ffmpegで動画加工するときに超重要になることがあります。 

さっき、PTSについて説明した通り、各フレームにPTS情報がついています。特に、動画から一部分を切り出すときに、このPTSを書き換える必要があります。例えば、切り出す前に8フレームあったものを、後半4フレーム切り出すとき

切り出す前

<pre>
   PTS: 1  4  2  3  5  8  6  7
   DTS: 1  2  3  4  5  6  7  8
Stream: I1 P1 B1 B2 I2 P2 B3 B4
</pre>

切り出した後

<pre>
   PTS: 1  4  2  3
   DTS: 1  2  3  4
Stream: I2 P2 B3 B4
</pre>

にしなければいけませんが、PTSを書き換えない限り、

<pre>
   PTS: 5  8  6  7
   DTS: 1  2  3  4
Stream: I2 P2 B3 B4
</pre>

として、PTSが残るので、切り出したはずが、最初の方に空白というか何も起こらない映像が流れて、元映像の5のタイミングから流れるといったことが起こります。**-filter_complex で trim を使用する場合には気を付けてください。**

おしまい

## ヽ(ﾟｰﾟ*ヽ)(ﾉ*ﾟｰﾟ)ﾉわぁい