Reputation: 65
I'm processing video using Media Foundation and a Media Foundation Transform (MFT), but the output image appears completely corrupted.
I'm attempting to convert video frames from one format to another, but the resulting video is not rendering correctly. The output image is distorted and unusable.
HRESULT capture_video_to_mp4(IMFSourceReader* pReader, int videoTimeSeconds) {
IMFMediaType* pMediaTypeIn = NULL;
IMFMediaType* pMediaTypeOut = NULL;
IMFMediaType* pMediaTypeTransformIn = NULL;
IMFMediaType* pMediaTypeTransformOut = NULL;
IMFSinkWriter* pSinkWriter = NULL;
IMFTransform* pTransform = NULL;
IMFSample* pSample = NULL;
DWORD streamIndex = MF_SOURCE_READER_FIRST_VIDEO_STREAM, flags = 0;
LONGLONG llTimeStamp = 0;
HRESULT hr = S_OK;
hr = pReader->lpVtbl->GetCurrentMediaType(pReader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pMediaTypeIn);
CHECK_HR(hr);
hr = MFCreateSinkWriterFromURL(L"output.mp4", NULL, NULL, &pSinkWriter);
CHECK_HR(hr);
hr = CoCreateInstance(&CLSID_CMSH264EncoderMFT, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void**)&pTransform);
CHECK_HR(hr);
UINT32 customBitrate = 1600000;
hr = pMediaTypeIn->lpVtbl->SetUINT32(pMediaTypeIn, &MF_MT_AVG_BITRATE, customBitrate);
CHECK_HR(hr);
hr = MFCreateMediaType(&pMediaTypeTransformOut);
pMediaTypeIn->lpVtbl->CopyAllItems(pMediaTypeIn, pMediaTypeTransformOut);
CHECK_HR(hr);
hr = pMediaTypeTransformOut->lpVtbl->SetGUID(pMediaTypeTransformOut, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
CHECK_HR(hr);
hr = pMediaTypeTransformOut->lpVtbl->SetGUID(pMediaTypeTransformOut, &MF_MT_SUBTYPE, &MFVideoFormat_H264);
CHECK_HR(hr);
hr = pMediaTypeTransformOut->lpVtbl->SetUINT32(pMediaTypeTransformOut, &MF_MT_AVG_BITRATE, customBitrate);
CHECK_HR(hr);
hr = pMediaTypeTransformOut->lpVtbl->SetUINT32(pMediaTypeTransformOut, &MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_Main);
CHECK_HR(hr);
hr = pMediaTypeTransformOut->lpVtbl->SetUINT32(pMediaTypeTransformOut, &MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
CHECK_HR(hr);
hr = pTransform->lpVtbl->SetOutputType(pTransform, 0, pMediaTypeTransformOut, 0);
CHECK_HR(hr);
hr = MFCreateMediaType(&pMediaTypeTransformIn);
pMediaTypeTransformOut->lpVtbl->CopyAllItems(pMediaTypeTransformOut,pMediaTypeTransformIn);
CHECK_HR(hr);
hr = pMediaTypeTransformIn->lpVtbl->SetGUID(pMediaTypeTransformIn, &MF_MT_SUBTYPE, &MFVideoFormat_YUY2);
CHECK_HR(hr);
hr = pTransform->lpVtbl->SetInputType(pTransform, 0, pMediaTypeTransformIn, 0);
CHECK_HR(hr);
DWORD streamIndexOut;
hr = pSinkWriter->lpVtbl->AddStream(pSinkWriter, pMediaTypeTransformOut, &streamIndexOut);
CHECK_HR(hr);
hr = pSinkWriter->lpVtbl->SetInputMediaType(pSinkWriter, streamIndexOut, pMediaTypeIn, NULL);
CHECK_HR(hr);
IMFSample* data[240];
memset(data, 0, 240);
DWORD processOutputStatus = 0, m_dwOutputID = 0;
MFT_OUTPUT_DATA_BUFFER outputDataBuffer;
IMFMediaBuffer* pBuffer = NULL;
videoTimeSeconds = 10;
int frame = 0;
int time_ = 0;
bool first = true;
IMFAttributes* pAttributes = NULL;
hr = MFCreateAttributes(&pAttributes, 1);
hr = pTransform->lpVtbl->QueryInterface(pTransform, &IID_IMFAttributes, (void**)&pAttributes);
if (SUCCEEDED(hr) && pAttributes != NULL) {
hr = pAttributes->lpVtbl->SetUINT32(pAttributes, &MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
CHECK_HR(hr);
pAttributes->lpVtbl->Release(pAttributes);
}
else {
wprintf(L"IMFTransform does not support IMFAttributes.\n");
}
const LONGLONG frameDuration = 416700;
LONGLONG baseTime = 0;
while ((videoTimeSeconds * 24) > frame) {
while (true) {
hr = pReader->lpVtbl->ReadSample(pReader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, &streamIndex, &flags, &llTimeStamp, &pSample);
if (FAILED(hr) || pSample == NULL) {
continue;
}
hr = pTransform->lpVtbl->ProcessInput(pTransform, 0, pSample, 0);
pSample->lpVtbl->Release(pSample);
CHECK_HR(hr);
break;
hr = pSample->lpVtbl->ConvertToContiguousBuffer(pSample, &pBuffer);
if (FAILED(hr)) {
pSample->lpVtbl->Release(pSample);
continue;
}
BYTE* pData = NULL;
DWORD bufferLength = 0;
hr = pBuffer->lpVtbl->Lock(pBuffer, &pData, NULL, &bufferLength);
if (SUCCEEDED(hr)) {
BYTE* pNV12Data = (BYTE*)malloc(bufferLength / 2 * 3);
IMFSample* pNV12Sample = NULL;
hr = MFCreateSample(&pNV12Sample);
if (SUCCEEDED(hr)) {
IMFMediaBuffer* pNV12Buffer = NULL;
hr = MFCreateMemoryBuffer(bufferLength / 2 * 3, &pNV12Buffer);
if (SUCCEEDED(hr)) {
BYTE* pDest = NULL;
hr = pNV12Buffer->lpVtbl->Lock(pNV12Buffer, &pDest, NULL, NULL);
if (SUCCEEDED(hr)) {
memcpy(pDest, pNV12Data, bufferLength / 2 * 3);
pNV12Buffer->lpVtbl->Unlock(pNV12Buffer);
pNV12Buffer->lpVtbl->SetCurrentLength(pNV12Buffer, bufferLength / 2 * 3);
pNV12Sample->lpVtbl->AddBuffer(pNV12Sample, pNV12Buffer);
if (first) {
baseTime = llTimeStamp;
first = false;
}
LONGLONG adjustedTimeStamp = baseTime + (frame * frameDuration);
pNV12Sample->lpVtbl->SetSampleTime(pNV12Sample, adjustedTimeStamp);
pNV12Sample->lpVtbl->SetSampleDuration(pNV12Sample, frameDuration);
hr = pTransform->lpVtbl->ProcessInput(pTransform, 0, pNV12Sample, 0);
}
pNV12Buffer->lpVtbl->Release(pNV12Buffer);
}
pNV12Sample->lpVtbl->Release(pNV12Sample);
}
free(pNV12Data);
pBuffer->lpVtbl->Unlock(pBuffer);
pBuffer->lpVtbl->Release(pBuffer);
pSample->lpVtbl->Release(pSample);
break;
}
pBuffer->lpVtbl->Release(pBuffer);
pSample->lpVtbl->Release(pSample);
}
while (true) {
MFT_OUTPUT_DATA_BUFFER outputDataBuffer;
ZeroMemory(&outputDataBuffer, sizeof(outputDataBuffer));
outputDataBuffer.dwStreamID = m_dwOutputID;
hr = MFCreateSample(&outputDataBuffer.pSample);
if (FAILED(hr)) {
break;
}
MFT_OUTPUT_STREAM_INFO streamInfo;
hr = pTransform->lpVtbl->GetOutputStreamInfo(pTransform, m_dwOutputID, &streamInfo);
if (FAILED(hr)) {
outputDataBuffer.pSample->lpVtbl->Release(outputDataBuffer.pSample);
break;
}
IMFMediaBuffer* pBufferOut = NULL;
DWORD outputBufferSize = streamInfo.cbSize > 614400 ? streamInfo.cbSize : 614400;
hr = MFCreateMemoryBuffer(outputBufferSize, &pBufferOut);
if (FAILED(hr)) {
outputDataBuffer.pSample->lpVtbl->Release(outputDataBuffer.pSample);
break;
}
hr = outputDataBuffer.pSample->lpVtbl->AddBuffer(outputDataBuffer.pSample, pBufferOut);
if (FAILED(hr)) {
pBufferOut->lpVtbl->Release(pBufferOut);
outputDataBuffer.pSample->lpVtbl->Release(outputDataBuffer.pSample);
break;
}
DWORD processOutputStatus = 0;
hr = pTransform->lpVtbl->ProcessOutput(pTransform, 0, 1, &outputDataBuffer, &processOutputStatus);
if (SUCCEEDED(hr)) {
data[frame] = outputDataBuffer.pSample;
frame++;
}
else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
outputDataBuffer.pSample->lpVtbl->Release(outputDataBuffer.pSample);
pBufferOut->lpVtbl->Release(pBufferOut);
break;
}
else {
outputDataBuffer.pSample->lpVtbl->Release(outputDataBuffer.pSample);
pBufferOut->lpVtbl->Release(pBufferOut);
break;
}
pBufferOut->lpVtbl->Release(pBufferOut);
break;
}
}
hr = pSinkWriter->lpVtbl->BeginWriting(pSinkWriter);
for (int i = 0; i < 240; i++) {
Sleep(10);
data[i]->lpVtbl->SetSampleTime(data[i], baseTime + (i * frameDuration));
data[i]->lpVtbl->SetSampleDuration(data[i], frameDuration);
hr = pSinkWriter->lpVtbl->WriteSample(pSinkWriter, streamIndexOut, data[i]);
}
goto done;
done:
if (pSinkWriter) {
pSinkWriter->lpVtbl->Finalize(pSinkWriter);
pSinkWriter->lpVtbl->Release(pSinkWriter);
}
if (pTransform) {
pTransform->lpVtbl->Release(pTransform);
}
if (pMediaTypeIn) {
pMediaTypeIn->lpVtbl->Release(pMediaTypeIn);
}
if (pMediaTypeOut) {
pMediaTypeOut->lpVtbl->Release(pMediaTypeOut);
}
if (pMediaTypeTransformIn) {
pMediaTypeTransformIn->lpVtbl->Release(pMediaTypeTransformIn);
}
if (pMediaTypeTransformOut) {
pMediaTypeTransformOut->lpVtbl->Release(pMediaTypeTransformOut);
}
return 0;
}
this is output:
Transform needs more input.
Transform needs more input.
Transform needs more input.
Transform needs more input.
Transform needs more input.
Processing output sample successful.
Sample written successfully to sink writer.
Processing output sample successful.
Sample written successfully to sink writer.
Processing output sample successful.
Sample written successfully to sink writer.
Processing output sample successful.
Sample written successfully to sink writer.
Processing output sample successful.
Sample written successfully to sink writer.
Processing output sample successful.
Sample written successfully to sink writer.
Processing output sample successful.
Sample written successfully to sink writer.
Processing output sample successful.
Sample written successfully to sink writer.
Processing output sample successful.
Sample written successfully to sink writer.
Processing output sample successful.
Sample written successfully to sink writer.
Processing output sample successful.
Sample written successfully to sink writer.
finish ....
Upvotes: 2
Views: 73