MediaFoundation --- 動画書き出し
下記記事にてMediaFoundationで動画を読み込む方法を調べました。
MediaFoundation --- 動画の読み込み - 何でもプログラミング
今回は書き出しについて調べたいと思います。
尚、見通し優先のため、エラー処理は省いてあります。
アプリケーションコード
動画はOpenCVのサンプル、vtest.aviを利用します。
動画を読み込んでH.264で出力します。
動画の読み込みにはOpenCVを利用しています。
ConfigureVideoEncoder、Writeは後述いたします。
#include <mfapi.h> #include <mfidl.h> #include <mfreadwrite.h> #pragma comment(lib, "mfplat.lib") #pragma comment(lib, "mfuuid.lib") #pragma comment(lib, "mfreadwrite.lib") #include <opencv2\opencv.hpp> #pragma comment(lib, "opencv_world320d.lib") int main() { CoInitialize(NULL); MFStartup(MF_VERSION); // 動画読み込み cv::VideoCapture capture("c:\\lib\\opencv3.2\\sources\\samples\\data\\vtest.avi"); int width = (int)capture.get(CV_CAP_PROP_FRAME_WIDTH); int height = (int)capture.get(CV_CAP_PROP_FRAME_HEIGHT); double fps = capture.get(CV_CAP_PROP_FPS); // Writer準備 IMFSinkWriter* writer; MFCreateSinkWriterFromURL(L"output.mp4", NULL, NULL, &writer); int streamIndex = ConfigureVideoEncoder(writer, MFVideoFormat_RGB24, MFVideoFormat_H264, width, height, fps, width * height); // 書き出し writer->BeginWriting(); while (true) { cv::Mat frame; capture >> frame; if (frame.empty()) break; cv::flip(frame, frame, 0); // H264で出力する際、上下反転が必要 Write(writer, streamIndex, frame.data, frame.elemSize() * frame.total()); } writer->Finalize(); // 後処理 writer->Release(); MFShutdown(); CoUninitialize(); return 0; }
ConfigureVideoEncoder
入力フォーマット、エンコーダ、画像サイズ、fps、平均bitrate、以上を渡してエンコーダをセットアップします。
DWORD ConfigureVideoEncoder(IMFSinkWriter* writer, GUID inputFormat, GUID outputFormat, int width, int height, double fps, int bitrate) { auto createType = [&](GUID subtype) { IMFMediaType* type; MFCreateMediaType(&type); type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); type->SetGUID(MF_MT_SUBTYPE, subtype); type->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); MFSetAttributeSize(type, MF_MT_FRAME_SIZE, width, height); MFSetAttributeRatio(type, MF_MT_FRAME_RATE, (int)(fps * 10000000), 10000000); return type; }; // OutputType IMFMediaType* outputType = createType(outputFormat); DWORD streamIndex; outputType->SetUINT32(MF_MT_AVG_BITRATE, bitrate); writer->AddStream(outputType, &streamIndex); outputType->Release(); // InputType IMFMediaType* inputType = createType(inputFormat); writer->SetInputMediaType(streamIndex, inputType, NULL); inputType->Release(); return streamIndex; }
Write
WMVで出力したい場合は、IMFSampleのSetSampleTimeとSetSampleDurationを設定する必要があります。
void Write(IMFSinkWriter* writer, int streamIndex, BYTE* data, int size) { // buffer作成 IMFMediaBuffer* buffer; MFCreateMemoryBuffer(size, &buffer); BYTE* bufferPtr; buffer->Lock(&bufferPtr, NULL, NULL); memcpy(bufferPtr, data, size); buffer->Unlock(); buffer->SetCurrentLength(size); // Sample作成 IMFSample* sample; MFCreateSample(&sample); sample->AddBuffer(buffer); // 書き出し writer->WriteSample(streamIndex, sample); sample->Release(); buffer->Release(); }