Search code examples
windowsencodingh.264ms-media-foundation

Media Foundation SetInputType returns "The stream number provided was invalid"


I'm working on a H.264 encoder using the software H264 Encoder MFT available on my machine for the sake of simplicity (as opposed to the Intel QSV hardware encoder that I will be using eventually). Following a number of tutorials I've put together the following code:

IMFTransform* encoder;
DWORD numInputs, numOutputs;
DWORD *inputIDs, *outputIDs;
MFRatio fps = { 24, 1 }, par = { 1, 1 };
HRESULT hr;

hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr)) {
    return hr;
}

// Create the MFT
hr = FindVideoEncoder(false, true, true, &encoder);
if (FAILED(hr))
{
    return hr;
}

// Obtain number of streams attached to MFT
encoder->GetStreamCount(&numInputs, &numOutputs);

// Allocate appropriate size arrays
inputIDs = new DWORD[numInputs];
outputIDs = new DWORD[numOutputs];

// Obtain stream IDs
encoder->GetStreamIDs(numInputs, inputIDs, numOutputs, outputIDs);

// Set input and output types
IMFMediaType *inputType, *outputType;

CreateVideoType(FRAME_WIDTH, FRAME_HEIGHT, MFVideoInterlace_Unknown, fps, par,
    &outputType, MFMediaType_Video, MFVideoFormat_H264);
hr = encoder->SetOutputType(outputIDs[0], outputType, 0);
if (FAILED(hr))
{
    return hr;
}

CreateVideoType(FRAME_WIDTH, FRAME_HEIGHT, MFVideoInterlace_Unknown, fps, par,
    &inputType, MFMediaType_Video, MFVideoFormat_Base);
hr = encoder->SetInputType(inputIDs[0], inputType, 0);
if (FAILED(hr))
{
    return hr;
}

The code fails on the following line, giving a HRESULT value of "The stream number provided was invalid".

hr = encoder->SetOutputType(outputIDs[0], outputType, 0);

I tried to call SetInputType before SetOutputType however it yields the same error. What am I doing wrong? Thank you in advance for the answers.

EDIT: Added CreateVideoType function to show how the outputType and inputType is created

HRESULT CreateVideoType(
    UINT32               width,
    UINT32               height,
    MFVideoInterlaceMode interlaceMode,
    const MFRatio&       frameRate,
    const MFRatio&       par,
    IMFMediaType         **ppType,
    GUID                 majorType,
    GUID                 subtype
    )
{
    if (ppType == NULL)
    {
        return E_POINTER;
    }

    LONG    lStride = 0;
    UINT    cbImage = 0;

    IMFMediaType *pType = NULL;

    // Set the subtype GUID from the FOURCC or D3DFORMAT value.
    //subtype.Data1 = D3DFMT_A8R8G8B8;

    if (FAILED(MFCreateMediaType(&pType)))
    {
        goto done;
    }

    if (FAILED(pType->SetGUID(MF_MT_MAJOR_TYPE, majorType)))
    {
        goto done;
    }

    if (FAILED(pType->SetGUID(MF_MT_SUBTYPE, subtype)))
    {
        goto done;
    }

    if (FAILED(pType->SetUINT32(MF_MT_INTERLACE_MODE, interlaceMode)))
    {
        goto done;
    }


    if (FAILED(MFSetAttributeSize(pType, MF_MT_FRAME_SIZE, width, height)))
    {
        goto done;
    }

    // Calculate the default stride value.
    if (FAILED(pType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride))))
    {
        goto done;
    }

    // Calculate the image size in bytes.
    if (FAILED(MFCalculateImageSize(subtype, width, height, &cbImage)))
    {
        goto done;
    }

    if (FAILED(pType->SetUINT32(MF_MT_SAMPLE_SIZE, cbImage)))
    {
        goto done;
    }

    if (FAILED(pType->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, TRUE)))
    {
        goto done;
    }

    if (FAILED(pType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE)))
    {
        goto done;
    }

    // Frame rate
    if (FAILED(MFSetAttributeRatio(pType, MF_MT_FRAME_RATE, frameRate.Numerator, frameRate.Denominator)))
    {
        goto done;
    }

    // Pixel aspect ratio   
    if (FAILED(MFSetAttributeRatio(pType, MF_MT_PIXEL_ASPECT_RATIO, par.Numerator, par.Denominator)))
    {
        goto done;
    }

    // Return the pointer to the caller.
    *ppType = pType;
    (*ppType)->AddRef();

done:
    SafeRelease(&pType);
    return S_OK;
}

Solution

  • Microsoft H264 Encoder MFT DOES NOT Implements GetStreamIDs- it returns E_NOTIMPL. You must set input and output stream ID to 0.