Question

I am capturing some legacy interlaced video (using Firewire), and encoding it using the H.264 encoder, into an MP4 file, using the sample project MFCaptureToFile from the Media Foundation samples. I would like to configure the MF so that the output H.264 picture is progressive. Can it be done?

As I understand, I must set the AVEncVideoOutputScanType property of the ICodecAPI to eAVEncVideoOutputScan_Progressive. How do I obtain the ICodecAPI from the IMFSinkWriter? Do I use the GetServiceForStream method? I tried, but I get E_NOINTERFACE if I use GUID_NULL for the second parameter, and IID_ICodecAPI for the third parameter.

Was it helpful?

Solution

Have you tried setting the MF_MT_INTERLACE_MODE to MFVideoInterlace_Progressive on the output media type?

IMFMediaType    *pMediaTypeOut;   
...
pMediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); 

As for the ICodecAPI, here is a slighty modified encoding example from MSDN that queries the interface from a sink writer, and it does work, but sadly the return from SetValue(CODECAPI_AVEncVideoOutputScanType,...) is E_NOTIMPL, so check if setting the value on the output media type does the job.

#include <Windows.h>


#include <mfapi.h>
#include <Mfidl.h>
#include <mfreadwrite.h>
#include <icodecapi.h>
#include <codecapi.h>

#pragma comment(lib, "Mfuuid.lib")
#pragma comment(lib, "Mfplat.lib")
#pragma comment(lib, "Mfreadwrite.lib")

const UINT32 VIDEO_WIDTH = 640;
const UINT32 VIDEO_HEIGHT = 480;
const UINT32 VIDEO_FPS = 25;
const UINT32 VIDEO_BIT_RATE = 800000;
const GUID   VIDEO_ENCODING_FORMAT = MFVideoFormat_H264;
const GUID   VIDEO_INPUT_FORMAT = MFVideoFormat_RGB32;
const UINT32 VIDEO_PELS = VIDEO_WIDTH * VIDEO_HEIGHT;
const UINT32 VIDEO_FRAME_COUNT = 20 * VIDEO_FPS;

HRESULT InitializeSinkWriter(IMFSinkWriter **ppWriter, DWORD *pStreamIndex)
{
    *ppWriter = NULL;
    *pStreamIndex = NULL;

    IMFSinkWriter   *pSinkWriter = NULL;
    IMFMediaType    *pMediaTypeOut;   
    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_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;
    }

    if(pSinkWriter)
        pSinkWriter->Release();
    if(pMediaTypeOut)
        pMediaTypeOut->Release();
    if(pMediaTypeIn)
        pMediaTypeIn->Release();
    return hr;
}

int main(int argc, char** argv)
{
    int nCodecIds[] = { 1 };
    ::CoInitialize(NULL);
    ::MFStartup(MF_VERSION);
    IMFSinkWriter* pWriter;
    DWORD nStreamIndex;
    HRESULT hr = InitializeSinkWriter(&pWriter, &nStreamIndex);
    if (pWriter)
    {
        ICodecAPI *pCodecApi;
        hr = pWriter->GetServiceForStream(nStreamIndex, GUID_NULL, __uuidof(ICodecAPI), (LPVOID*)&pCodecApi);
        if(SUCCEEDED(hr))
        {
            VARIANT value, currentValue;
            VariantInit(&value);
            value.vt = VT_UI4;
            value.uintVal = eAVEncVideoOutputScan_Progressive;
            hr = pCodecApi->SetValue(&CODECAPI_AVEncVideoOutputScanType, &value);
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top