音声や映像ファイルをエンコードする部品です。Sink Writerは動画のリサイズやフレームレートの変換、それに音声のリサンプリングを提供しません。
HRESULT MFCreateSinkWriterFromURL( LPCWSTR pwszOutputURL, // 出力ファイルのURLを含む文字列 IMFByteStream *pByteStream, // IMFAttributes *pAttributes, // IMFSinkWriter **ppSinkWriter // );MFCreateSinkWriterFromURL function (mfreadwrite.h) | Microsoft Learn
戻り値でERROR_PATH_NOT_FOUND (0x80070003) が返されるときは、pwszOutputURLのパスが存在しているか確認します。
出力形式をPCMとした場合、作成されるファイルのRIFFチャンクの後には、JUNKチャンクが続きます。
書き込むために、Sink Writerを初期化します。これはWriteSample()などの前に呼び出す必要があります。
HRESULT BeginWriting();IMFSinkWriter::BeginWriting (mfreadwrite.h) | Microsoft Learn
Sink Writerに追加したStreamに適切なMedia Typeが設定されていないと、MF_E_INVALIDMEDIATYPE (0xC00D36B4) が返されます。
戻り値でMF_E_INVALIDMEDIATYPE (0xC00D36B4) が返されるときは、Sink Writerに追加するStreamに、適切なMedia Typeを設定します。
Sink WriterへMedia Sampleを送ります。
HRESULT WriteSample( DWORD dwStreamIndex, IMFSample *pSample );IMFSinkWriter::WriteSample (mfreadwrite.h) | Microsoft Learn
1000Hz、8bit、モノラルの3秒間の矩形波の音声は、次のように作成できます。
UINT32 sampleRate = 1000; // 1000 Hz UINT32 bitsPerSample = 8; // 8 bit UINT32 channels = 1; // 1 channel UINT32 blockAlign = channels * (bitsPerSample / 8); UINT32 bytesPerSecond = blockAlign * sampleRate; UINT32 dataSecond = 3; // 3秒 DWORD cbDataLength = dataSecond * bytesPerSecond; // 書き込むデータを用意する BYTE* pSrc = new BYTE[cbDataLength]; for (int i = 0; i < cbDataLength; i++) { pSrc[i] = (i % 2) * 0xff; } HRESULT hr = S_OK; hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); hr = MFStartup(MF_VERSION); // Sink Writerを初期化する LPCWSTR pwszOutputURL = L"C:\\sample.wav"; IMFSinkWriter* pSinkWriter = NULL; hr = MFCreateSinkWriterFromURL(pwszOutputURL, NULL, NULL, &pSinkWriter); // 出力用のMediaTypeを設定する IMFMediaType* pMediaTypeOut = NULL; hr = MFCreateMediaType(&pMediaTypeOut); hr = pMediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio); hr = pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM); hr = pMediaTypeOut->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, channels); hr = pMediaTypeOut->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, sampleRate); hr = pMediaTypeOut->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, blockAlign); hr = pMediaTypeOut->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, bytesPerSecond); hr = pMediaTypeOut->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample); hr = pMediaTypeOut->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); DWORD streamIndex; hr = pSinkWriter->AddStream(pMediaTypeOut, &streamIndex); // 入力用のMediaTypeを設定する IMFMediaType* pMediaTypeIn = pMediaTypeOut; // 出力側と同一ならば、それを用いる hr = pSinkWriter->SetInputMediaType(streamIndex, pMediaTypeIn, NULL); // Sink writerに、データの受け入れを開始するように指示する hr = pSinkWriter->BeginWriting(); // 新しいメモリ バッファを作成する IMFMediaBuffer* pBuffer = NULL; hr = MFCreateMemoryBuffer(cbDataLength, &pBuffer); // バッファをロックし、バッファへデータをコピーする BYTE* pData = NULL; hr = pBuffer->Lock(&pData, NULL, NULL); memcpy_s(pData, cbDataLength, pSrc, cbDataLength); hr = pBuffer->Unlock(); // バッファのデータ長を設定する hr = pBuffer->SetCurrentLength(cbDataLength); // Media Sampleを作成し、それにバッファを追加する IMFSample* pSample = NULL; hr = MFCreateSample(&pSample); hr = pSample->AddBuffer(pBuffer); // タイムスタンプを設定する LONGLONG hnsSampleTime = 0; hr = pSample->SetSampleTime(hnsSampleTime); // Sink WriterへMedia Sampleを送る hr = pSinkWriter->WriteSample(streamIndex, pSample); hr = pSinkWriter->Finalize(); delete[] pSrc; SafeRelease(pBuffer); SafeRelease(pSample); SafeRelease(&pSinkWriter); SafeRelease(&pMediaTypeOut); // SafeRelease(&pMediaTypeIn); MFShutdown(); CoUninitialize();Example Code - Tutorial: Using the Sink Writer to Encode Video - Win32 apps | Microsoft Learn
Sink Writerのすべての書き込み処理を完了させられます。
HRESULT Finalize();IMFSinkWriter::Finalize (mfreadwrite.h) | Microsoft Learn
戻り値でMF_E_NO_SAMPLE_TIMESTAMP (0xC00D36C8) が返されるときには、Sink Writerへ送るMedia Sampleに、IMFSample::SetSampleTime()でPresentation Timeを設定します。