概要
次のようなフレームレート(fps)がおかしい動画ファイルの修正を実施。
原因
恐らく、PTSやDTSといった情報が不整合を起こしているためこのようになっていると思われる。
参考:ffmpeg を使うなら知っておきたい話 PTSとかDTSの話:音ずれ問題や時間が変になるときのために ヽ(゚ー゚*ヽ)(ノ*゚ー゚)ノわぁい - Qiita
前提
-
ffmpeg及びffprobeを導入済みであること
-
ffmpeg/ffprobe version
version N-105859-g37480b1b85-20220305
-
対象とする動画ファイル名は「inputFile.mp4」とする
解決方法
音声ストリーム、動画ストリームをそれぞれを書き出し、fpsを指定して結合(Mux)し直す。
手順1 ファイル情報の確認
Windowsではファイルのプロパティから最初の図のようにフレームレートを確認することができるが、
念のためffprobe
を用いて確認する。
ffprobe -i inputFile.mp4 -hide_banner
手順2 元の動画ファイルのフレームレートを確認する
元の動画ファイルのフレームレートが不明な場合はffprobe
を使用して求める。
※フレームレートが判明している場合はこの手順は不要
手順2-1 総フレーム数の取得
ffprobe -v error -select_streams v -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 inputFile.mp4
ここで得られたフレーム数を「108000」とする。
各種オプションの補足
-
-v error
ffprobeの出力結果のみにする -
-select_streams v
動画ストリームのみを選択 -
-show_entries stream=nb_frames
エントリーの表示。stream=nb_freams
でフレーム数の表示。 -
-of default=nokey=1:noprint_wrappers=1
default=nokey=1
:キーの非表示
noprint_wrappers=1
:セクションの非表示
手順2-2 再生時間の取得
音声ファイルは正常と考え、音声ストリームの再生時間を取得する。(単位は秒)
ffprobe -v error -select_streams a -show_entries stream=duration -of default=nokey=1:noprint_wrappers=1 inputFile.mp4
ここで得られた再生時間を「3600」とする。
各種オプションの補足
-
-select_streams a
音声ストリームのみを選択 -
-show_entries stream=duration
エントリーの表示。stream=duration
で再生時間の表示。
手順2-3 フレームレートの算出
手順2-1で取得した総フレーム数を、
手順2-2で取得した再生時間で割る。
108000 / 3600 = 30
よって元動画ファイルのフレームレートは「30fps」となる。
手順3 音声ファイルのみを抜き出す
「audio.aac」というファイル名で音声ファイルを抜き出す
ffmpeg -i inputFile.mp4 -vn -c:a copy audio.aac
各種オプションの補足
-
-vn
動画ストリームを無効にする。 -
-c:a copy
入力ファイルの音声コーデックと出力ファイルのコーデックを同じにする。
-codec:a copy
や-acodec copy
と同等
手順4 動画ストリームだけを抜き出す
H.264形式で書き出す。
ffmpeg -i inputFile.mp4 -an -c:v copy -f h264 noaudio.h264
各種オプションの補足
-
-an
音声ストリームを無効にする -
-c:v copy
入力ファイルの動画コーデックと出力ファイルのコーデックを同じにする。
-codec:v copy
や-vcodec copy
と同等 -
-f h264
フォーマットを指定する。「H264」を指定する。
上図のようにエラーが出る場合があるが無視。
※DTSは増加していく情報であるが、そのようになっていないフレームがあるとのエラーのよう。
「Application provided~」のログレベルはエラーに設定されているが、処理が止まることはなく問題なく出力される。
ソースコードを見ると、今回はそれ以外の原因でエラーとなっている気がする。
https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/mux.c#L540-L549
手順5 音声と動画を結合(Mux)する
手順3で作成した音声ファイルと、手順4で作成した動画ファイルを結合する。
-r 30
には、元ファイルと同じフレームレートを指定する。(今回は30)
ffmpeg -r 30 -i noaudio.h264 -i audio.aac -c:v copy -c:a copy outputFile.mp4
各種オプションの補足
-
-r
フレームレートの指定
noaudio.h264ファイルにPTS情報がないので警告が出ているが、ffmpegがいい感じにやってくれる。
完成
です。
蛇足
- 手順2でフレームレートを算出しているが、手順4で作成した.h264ファイルに対して
ffprobe -v error -show_entries stream=r_frame_rate -of default=nokey=1:noprint_wrappers=1 noaudio.h264
とすることでフレームレートがわかる。
-
そもそもフレームレートを算出しておかなくても、手順5の出力時に
-r
で指定しなければ.h264ファイルのフレームレート情報を見に行ってか、ffmpegがなんかいい感じにやってくれる。
今回はなんとなく指定した。 -
可変フレームレートの場合は知りません。
-
ストリームの順番が入力ファイルと異なってしまって困る場合は、
-map
オプションを使用して、明示的に指定してください。