MP4からの静止画抽出(Media Foundation)の知識マップ(知識グラフ)
動画からの静止画抽出(指定時刻のフレーム取得)
動画ファイルの中から、指定した時刻に最も近い1枚のフレームを非圧縮画像として取り出す処理。
フレーム抽出
静止画切り出し
IMFSourceReader(Source Reader)
Media Foundationが提供する、メディアファイルからサンプルを同期的または非同期的に読み出すための入口となるインターフェイス。
Media Foundation
Windowsが提供する、メディアの再生・変換・エンコード/デコードを行うためのCOMベースのフレームワーク。
SetCurrentPositionによるseek
IMFSourceReaderで指定時刻へ移動する操作。exact seekingを保証せず、通常は指定位置の少し前、特にキーフレーム側へ寄る。
IMFSourceReaderからデコード済みのサンプルを1枚ずつ取得するメソッド。成功していてもサンプルがnullのことがある。
GOP(Group of Pictures)
あるキーフレームから次のキーフレームの直前までのフレームのまとまり。長いほどキーフレームの間隔が空く。
キーフレーム(key frame)
前後のフレームを参照せず、それ単独でデコードできるフレーム。
IDRピクチャー
stride(画像の行送りバイト数)
画像バッファで1行分が占めるバイト数。幅×1画素のバイト数と一致するとは限らず、行末にpaddingが入ることがある。
2Dの画像バッファをロックし、scan line 0の先頭ポインタと実際のstrideを取得するMedia FoundationのAPI。
top-down / bottom-up(画像の上下向き)
画像バッファの先頭が上端の行か下端の行かの違い。bottom-upはstrideが負の値で表現される。
画像の走査方向
MFVideoFormat_RGB32
Media Foundationの32bit RGBピクセル形式。byte0-2がB,G,Rで、byte3はalphaとは限らずARGB32ではない。
意図しない透明PNG
RGB32の4バイト目をalphaとしてそのままPNGに書き出した結果、画像が意図せず透明になってしまう不具合。
透明画像になる不具合
alphaの0xFF固定
保存前に画像バッファの4バイト目(alpha)へ0xFFを書き込み、完全に不透明な状態に固定する処理。
不透明化処理
WIC(Windows Imaging Component)
PNGなどの画像ファイルの読み込み・保存を行うWindows標準の画像処理コンポーネント。
ReadSampleのnullサンプル
ReadSampleがS_OKを返していても、ストリームの終端やギャップなどでサンプルが取得できていない状態。
MP4から1枚の静止画を取り出すには、Media SessionよりIMFSourceReaderのほうが入口として素直である。
IMFSourceReaderはMedia Foundationの初期化(MFStartup)を前提として動作する。
IMFSourceReaderはSetCurrentPositionによる指定時刻へのseekをサポートする。
SetCurrentPositionはexact seekingを保証しないため、そのあとReadSampleを進めて目的位置まで前進することが前提になる。
GOPが長い動画ほど、SetCurrentPositionによるseek位置が指定時刻から遠くなりやすい。
SetCurrentPositionによるseekは、指定位置の少し前、特にキーフレーム側へ寄る形で行われる。
指定時刻に最も近いフレームを選ぶには、seek後にReadSampleを繰り返してtimestampの前後を比較する必要がある。
取り出したフレームをPNGとして正しく保存するには、strideと画像の上下向きを吸収する処理が必要になる。
実際のstrideとscan line 0の先頭ポインタは、IMF2DBuffer::Lock2Dが使えるときはそれで取得する(使えないbufferではIMFMediaBuffer::Lockと既定strideの計算にフォールバックする)。
行ごとのコピーでは、画像がtop-downかbottom-up(strideが負)かを踏まえる必要がある。
MFVideoFormat_RGB32の4バイト目はalphaとは限らないため、そのままPNGに書くと画像が透明になることがある。
保存前にRGB32の4バイト目へ0xFFを入れて不透明に固定することで、透明PNGになる事故を防ぐ。
整形したtop-downのBGRAバッファは、WICのIWICBitmapEncoder/IWICBitmapFrameEncodeでPNGとして保存する。
IMFSourceReaderの出力メディアタイプをMFVideoFormat_RGB32に設定すると、保存しやすい非圧縮フレームが得られる。
ReadSampleはS_OKを返してもpSampleがnullptrのことがあり、ストリームの終端やギャップではフレームが得られない。