質問者
Media foundationでH.264、main profile以上でエンコードするとstartの時間が1フレームずれる

質問
-
お世話になっております。
MediaFoundationの下記サンプルコードを参考にH.264の動画ファイルをmain Profileで出力してみたのですが出力された動画ファイルを確認するとstartの時間が1フレーム分ずれてしまいます。具体的には作成された動画ファイルをffmpegで確認すると30fpsならばstart timeが0.03333のように1フレーム分進んだ状態になっております。
chromeなどで開いて、シークを先頭にもってくるとシークが1フレーム分勝手に移動してしまうので困っています。
baselineでのプロファイルでは問題なく、main, highでは起こるようです。
https://docs.microsoft.com/ja-jp/windows/desktop/medfound/tutorial--using-the-sink-writer-to-encode-video
サンプルコードからの変更点は下記の2点です。mainプロファイルの場合は設定に特別なもの必要でしょうか?
宜しくお願い致します。//① const GUID VIDEO_ENCODING_FORMAT = MFVideoFormat_WMV3; ↓↓↓ const GUID VIDEO_ENCODING_FORMAT = MFVideoFormat_H264; //② HRESULT hr = MFCreateSinkWriterFromURL(L"output.wmv", NULL, NULL, &pSinkWriter); ↓↓↓ HRESULT hr = MFCreateSinkWriterFromURL(L"output.mp4", NULL, NULL, &pSinkWriter); //③ if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, VIDEO_ENCODING_FORMAT); } ↓↓↓ if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, VIDEO_ENCODING_FORMAT); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetUINT32(MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_Main); }
~追記~
コード全体を記載いたします。
#include <Windows.h> #include <mfapi.h> #include <mfidl.h> #include <Mfreadwrite.h> #include <mferror.h> #include <codecapi.h> #pragma comment(lib, "mfreadwrite") #pragma comment(lib, "mfplat") #pragma comment(lib, "mfuuid") template <class T> void SafeRelease(T **ppT) { if (*ppT) { (*ppT)->Release(); *ppT = NULL; } } // Format constants const UINT32 VIDEO_WIDTH = 640; const UINT32 VIDEO_HEIGHT = 480; const UINT32 VIDEO_FPS = 30; const UINT64 VIDEO_FRAME_DURATION = 10 * 1000 * 1000 / VIDEO_FPS; const UINT32 VIDEO_BIT_RATE = 800000; const GUID VIDEO_ENCODING_FORMAT = MFVideoFormat_H264; //MFVideoFormat_H264 //MFVideoFormat_WMV3 const GUID VIDEO_INPUT_FORMAT = MFVideoFormat_RGB32; const UINT32 VIDEO_PELS = VIDEO_WIDTH * VIDEO_HEIGHT; const UINT32 VIDEO_FRAME_COUNT = 20 * VIDEO_FPS; // Buffer to hold the video frame data. DWORD videoFrameBuffer[VIDEO_PELS]; HRESULT InitializeSinkWriter(IMFSinkWriter **ppWriter, DWORD *pStreamIndex) { *ppWriter = NULL; *pStreamIndex = NULL; IMFSinkWriter *pSinkWriter = NULL; IMFMediaType *pMediaTypeOut = NULL; IMFMediaType *pMediaTypeIn = NULL; DWORD streamIndex; HRESULT hr = MFCreateSinkWriterFromURL(L"output.mp4", NULL, NULL, &pSinkWriter); // Set the output media type. if (SUCCEEDED(hr)) { hr = MFCreateMediaType(&pMediaTypeOut); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, VIDEO_ENCODING_FORMAT); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetUINT32(MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_Main); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, VIDEO_BIT_RATE); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); } if (SUCCEEDED(hr)) { hr = MFSetAttributeSize(pMediaTypeOut, MF_MT_FRAME_SIZE, VIDEO_WIDTH, VIDEO_HEIGHT); } if (SUCCEEDED(hr)) { hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_FRAME_RATE, VIDEO_FPS, 1); } if (SUCCEEDED(hr)) { hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_PIXEL_ASPECT_RATIO, 1, 1); } if (SUCCEEDED(hr)) { hr = pSinkWriter->AddStream(pMediaTypeOut, &streamIndex); } // Set the input media type. if (SUCCEEDED(hr)) { hr = MFCreateMediaType(&pMediaTypeIn); } if (SUCCEEDED(hr)) { hr = pMediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); } if (SUCCEEDED(hr)) { hr = pMediaTypeIn->SetGUID(MF_MT_SUBTYPE, VIDEO_INPUT_FORMAT); } if (SUCCEEDED(hr)) { hr = pMediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); } if (SUCCEEDED(hr)) { hr = MFSetAttributeSize(pMediaTypeIn, MF_MT_FRAME_SIZE, VIDEO_WIDTH, VIDEO_HEIGHT); } if (SUCCEEDED(hr)) { hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_FRAME_RATE, VIDEO_FPS, 1); } if (SUCCEEDED(hr)) { hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_PIXEL_ASPECT_RATIO, 1, 1); } if (SUCCEEDED(hr)) { hr = pSinkWriter->SetInputMediaType(streamIndex, pMediaTypeIn, NULL); } // Tell the sink writer to start accepting data. if (SUCCEEDED(hr)) { hr = pSinkWriter->BeginWriting(); } // Return the pointer to the caller. if (SUCCEEDED(hr)) { *ppWriter = pSinkWriter; (*ppWriter)->AddRef(); *pStreamIndex = streamIndex; } SafeRelease(&pSinkWriter); SafeRelease(&pMediaTypeOut); SafeRelease(&pMediaTypeIn); return hr; } HRESULT WriteFrame( IMFSinkWriter *pWriter, DWORD streamIndex, const LONGLONG& rtStart // Time stamp. ) { IMFSample *pSample = NULL; IMFMediaBuffer *pBuffer = NULL; const LONG cbWidth = 4 * VIDEO_WIDTH; const DWORD cbBuffer = cbWidth * VIDEO_HEIGHT; BYTE *pData = NULL; // Create a new memory buffer. HRESULT hr = MFCreateMemoryBuffer(cbBuffer, &pBuffer); // Lock the buffer and copy the video frame to the buffer. if (SUCCEEDED(hr)) { hr = pBuffer->Lock(&pData, NULL, NULL); } if (SUCCEEDED(hr)) { hr = MFCopyImage( pData, // Destination buffer. cbWidth, // Destination stride. (BYTE*)videoFrameBuffer, // First row in source image. cbWidth, // Source stride. cbWidth, // Image width in bytes. VIDEO_HEIGHT // Image height in pixels. ); } if (pBuffer) { pBuffer->Unlock(); } // Set the data length of the buffer. if (SUCCEEDED(hr)) { hr = pBuffer->SetCurrentLength(cbBuffer); } // Create a media sample and add the buffer to the sample. if (SUCCEEDED(hr)) { hr = MFCreateSample(&pSample); } if (SUCCEEDED(hr)) { hr = pSample->AddBuffer(pBuffer); } // Set the time stamp and the duration. if (SUCCEEDED(hr)) { hr = pSample->SetSampleTime(rtStart); } if (SUCCEEDED(hr)) { hr = pSample->SetSampleDuration(VIDEO_FRAME_DURATION); } // Send the sample to the Sink Writer. if (SUCCEEDED(hr)) { hr = pWriter->WriteSample(streamIndex, pSample); } SafeRelease(&pSample); SafeRelease(&pBuffer); return hr; } void main() { // Set all pixels to green for (DWORD i = 0; i < VIDEO_PELS; ++i) { videoFrameBuffer[i] = 0x0000FF00; } HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (SUCCEEDED(hr)) { hr = MFStartup(MF_VERSION); if (SUCCEEDED(hr)) { IMFSinkWriter *pSinkWriter = NULL; DWORD stream; hr = InitializeSinkWriter(&pSinkWriter, &stream); if (SUCCEEDED(hr)) { // Send frames to the sink writer. LONGLONG rtStart = 0; for (DWORD i = 0; i < VIDEO_FRAME_COUNT; ++i) { hr = WriteFrame(pSinkWriter, stream, rtStart); if (FAILED(hr)) { break; } rtStart += VIDEO_FRAME_DURATION; } } if (SUCCEEDED(hr)) { hr = pSinkWriter->Finalize(); } SafeRelease(&pSinkWriter); MFShutdown(); } CoUninitialize(); } }
- 編集済み akiiiiiiiiii 2018年12月13日 10:58