locked
SetTopology with added encoder fails with MF_E_INVALIDMEDIATYPE error RRS feed

  • Question

  • I want to make a transcoding to a ASF file (later to MP4 too). I’ve started with a simple topology with a media source and a sink created with MFCreateASFMediaSinkActivate. This worked fine.

    Then I create and add the encoder to the topology, connect input node, encoder node and output node. But when I set the topology I receive an MF_E_INVALIDMEDIATYPE error in IMFAsyncCallback::Invoke.

    In details:

    1.  Create encoder with CoCreateInstance.

    2.  Get the property store and set MFPKEY_VBRENABLED to FALSE

    3.  Get the current media type of the input node make a copy and configure the copy:

    a.  Set subtype to the subtype of receive from GetInputAvailableType of the encoder

    b.  Make it uncompressed - SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);

    4.  Set encoder’s input type (SetInputType)

    5.  Get available output media types (GetOutputAvailableType), choose the first, set the bitrate and the private data and set the encoder’s output type.

    6.  Create an encoder node and add it to the topology

    7.  Connect input node and encoder node

    8.  Connect encoder node and output node

    9.  Set the topology.

     

    Here is the „encoder“ part of my code (without error handling)

     

    // encoder

    CComPtr<IMFTransform> pEncoder;

    hr = CoCreateInstance(CLSID_CWMV9EncMediaObject, NULL, CLSCTX_INPROC_SERVER, __uuidof(IMFTransform), (LPVOID*)&pEncoder);  

     

    CComPtr<IPropertyStore> pPropertyStore;

    hr = pEncoder->QueryInterface<IPropertyStore>(&pPropertyStore);

     

    PROPVARIANT var;

    var.vt = VT_BOOL;

    var.boolVal = FALSE;

    hr = pPropertyStore->SetValue(MFPKEY_VBRENABLED, var);

     

    CComPtr<IMFMediaType> pSourceMediaType;

    hr = pHandler->GetCurrentMediaType(&pSourceMediaType);

     

    CComPtr<IMFMediaType> pEncInputType;

    MFCreateMediaType(&pEncInputType);

    hr = pSourceMediaType->CopyAllItems(pEncInputType);

     

    CComPtr<IMFMediaType> pAvailableInputediaType;

    hr = pEncoder->GetInputAvailableType(0, 0, &pAvailableInputediaType);

                                

    GUID subtype = GUID_NULL;

    hr = pAvailableInputediaType->GetGUID(MF_MT_SUBTYPE, &subtype);               

                                

    hr = pEncInputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);

     

    hr = pEncInputType->SetGUID(MF_MT_SUBTYPE, subtype);

     

    hr = pEncInputType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);

                             

    hr = pEncoder->SetInputType(0, pEncInputType, 0);

     

    CComPtr<IMFMediaType> pEncTypeOut;

    hr = pEncoder->GetOutputAvailableType(0, 0, &pEncTypeOut);

     

    hr = pEncTypeOut->SetUINT32(MF_MT_AVG_BITRATE, 100000);  

     

    CComPtr<IWMCodecPrivateData> pPrivData;

    DMO_MEDIA_TYPE mtOut = { 0 };

    hr = MFInitAMMediaTypeFromMFMediaType(pEncTypeOut, FORMAT_VideoInfo, (AM_MEDIA_TYPE*)&mtOut);

     

    hr = pEncoder->QueryInterface<IWMCodecPrivateData>(&pPrivData);

     

    hr = pPrivData->SetPartialOutputType(&mtOut);

                                

    ULONG cbData = 0;

    hr = pPrivData->GetPrivateData(NULL, &cbData);

                                

    BYTE *pData = NULL;

    pData = new BYTE[cbData];

    hr = pPrivData->GetPrivateData(pData, &cbData);

     

    hr = pEncTypeOut->SetBlob(MF_MT_USER_DATA, pData, cbData);

     

    hr = pEncoder->SetOutputType(0, pEncTypeOut, 0);

      

    CComPtr<IMFTopologyNode> pEncoderNode;

    hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &pEncoderNode);

     

    hr = pEncoderNode->SetObject(pEncoder);

     

    hr = pTopology->AddNode(pEncoderNode);

     

    hr = pInputNode->ConnectOutput(0, pEncoderNode, 0);

     

    hr = pEncoderNode->ConnectOutput(0, pOutputNode, 0);

     

    hr = m_pSession->SetTopology(0, pTopology);

     

    Tuesday, October 20, 2009 12:26 PM

Answers

  • The WMV encoder accepts FORMAT_MFVideoFormat for media types, and the MFVideoFormat structure supports pixel aspect ratio.
    • Marked as answer by The March Hare Wednesday, December 2, 2009 4:05 PM
    Tuesday, October 27, 2009 5:58 PM

All replies

  • I'm having the same issues with putting together some sort of Transcoding pipeline as well. Not sure if your issue is the same as mine but the main problem I'm having is finding a decoder-encoder pair which support a common media type.

    For example, the H.264 Decoder transform will only output with the uncompressed formats of IYUV, NV12, YUY2 and YV12. These formats are perfect for pumping straight into an EVR but the MP4 Sink doesn't seem to take these formats. Since I can't find any documentation about what media subtypes are supported by the various MF Sinks, I used MFCreateSinkWriterFromURL to create a generic Archive Sink. I tried combinations of containers (ASF,MP4,WMV) and input media types and I always get MF_E_INVALIDMEDIATYPE when setting the input media type after setting the output media type. This error is indicative of lack of registered transforms available within MF or media types supported by the sink itself.

    One path I did try to go down was creating my own uncompressed video transform to convert YUY2 to R8B8G8 so the data would be Sink-Friendly. These kinds of transforms don't ship with MF since the conversions are simple and linear. The problem I had was conversions litterally took forever for a 1280x720 image(approx 1.8MB conversion per frame). When I get the time, I'll try again with using a D3D9 hardware transform for colour-space conversions. I can't seem to find enough documentation as to how MF can encapsulate a Direct3D Device as an IMFTransform. IMFVideoProcessor doesn't seem remotely like transform which can be used in a Topology but I could be wrong.
    Tuesday, October 20, 2009 8:03 PM
  • If you set the input types and output types on the encoder and it returned S_OK from both calls, then the encoder is generally fine.  I would look at the connection between the encoder and the sink.  Specifically, was the IMFASFContentInfo object you passed to MFCreateASFMediaSinkActivate set up to handle the media type you set on the encoder?  The ASF stream's media types you set on the IMFASFProfile should match attribute for attribute with the respective encoder.

    Nobby - The MF sinks do not have encoders inside of them.  They generally only support compressed formats (I believe the ASF sink may support storing uncompressed data in the output file, but I would not recommend it) outputted by an independent encoder MFT. 

    For the color conversion issue, D3D acceleration is not really available for transcode topologies.  If you wanted to create a D3D device handle and somehow use it inside of a transform to accelerate video processing, that should be fine.  DXVA ( http://msdn.microsoft.com/en-us/library/cc307941(VS.85).aspx ) may have some of the support you are looking for.  However, I would check to see if the base MF color converter (http://msdn.microsoft.com/en-us/library/dd443213(VS.85).aspx) supports the conversion -- though it does not support hardware acceleration, I believe many if not all of the conversions are highly optimized.

    Wednesday, October 21, 2009 2:01 AM
  • Thanks for the fast reply.

    I've now added the following code to configure the output node. I create a new profile and apply the media type that I've set to the encoder's output to the profile. Then I create a ASFContentInfo and set the new profile. I left the encoder part as it was before. 
    I've checked the success of all operrations and they all succeed.
    But my changes have the same result. After SetTopology I get a MF_E_INVALIDMEDIATYPE error in the invoke callback function.

    // create an empty ASF profile object
    CComPtr<IMFASFProfile> pNewProfile; 
    hr = MFCreateASFProfile(&pNewProfile);
    
    // create a new stream for the ASF profile
    CComPtr<IMFASFStreamConfig> pStream;
    hr = pNewProfile->CreateStream(pEncTypeOut, &pStream);
    
    // assign a stream identifier
    hr = pStream->SetStreamNumber(1);
    
    // Set "leaky bucket" values.
    LeakyBucket bucket;
    bucket.dwBitrate = 8 * MFGetAttributeUINT32(pEncTypeOut, MF_MT_AVG_BITRATE, 0);
    CComPtr<IWMCodecLeakyBucket> pLeakyBuckets;
    hr = pEncoder->QueryInterface(IID_PPV_ARGS(&pLeakyBuckets));
    
    ULONG ulBuffer = 0;
    hr = pLeakyBuckets->GetBufferSizeBits(&ulBuffer);
    bucket.msBufferSize = ulBuffer / (bucket.dwBitrate / 1000);    
    
    hr = pStream->SetBlob(MF_ASFSTREAMCONFIG_LEAKYBUCKET1, (UINT8*)&bucket, sizeof(bucket));
    
    //Add the stream to the profile
    hr = pNewProfile->SetStream(pStream);
    
    // Create the ASF ContentInfo object.
    CComPtr<IMFASFContentInfo> pContentInfo; 
    hr = MFCreateASFContentInfo(&pContentInfo);
    
    hr = pContentInfo->SetProfile(pNewProfile);
    
    // create the media sink
    CComPtr<IMFActivate> pSinkActivate; 
    hr = MFCreateASFMediaSinkActivate(outFilePath.c_str(), pContentInfo, &pSinkActivate);
    
    // Create the node.
    CComPtr<IMFTopologyNode> pOutputNode;
    
    hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pOutputNode);
    
    // Set stream id
    WORD wSinkStreamID = 0;
    
    hr = pNewProfile->GetStream( 0, &wSinkStreamID, NULL ) ;
    
    hr = pOutputNode->SetUINT32(MF_TOPONODE_STREAMID, wSinkStreamID);
    
    hr = pOutputNode->SetObject(pSinkActivate);
    
     
    Wednesday, October 21, 2009 12:43 PM
  • To emulate how we set up the WMV encoder, try the following:  Do not set the encoder's input type.  Encoders should all support setting the output type first.  Set your desired encoder output type through IWMCodecPrivateData::SetPartialOutputType.  Do not worry about calling GetPrivateData or SetOutputType.  Let the topology loader resolve the encoder's input type and set the final output type on the encoder and sink. 
    Wednesday, October 21, 2009 5:59 PM
  • Hi Matt,

    Now I do the following and get MF_E_ATTRIBUTENOTFOUND :

    ·         I do not create an input media type for the encoder and I donot call SetInputType.

    ·         Next I get an output media type via GetOutputAvailableType and set the bitrate  and call Set SetPartialOutputType on the encoder’s IWMCodecPrivateData interface. I do not call SetOutputType.

    ·         Then I connect input node and encoder node.

    ·         The I use a new profile and with a new stream created with the outputtype used for SetPartialOutputType. I set the profile to the ContentInfo and create a sink with MFCreateASFMediaSinkActivate.

    ·         I create the output node and connect it with the encoder node.

    ·         Set the topology

    ·         Get a MF_E_ATTRIBUTENOTFOUND error in the invoke callback.

    Here is the (nearly) complete code.

     

    // CreateSource

    CComPtr<IMFSourceResolver> pSourceResolver;

    hr = MFCreateSourceResolver(&pSourceResolver);

     

    CComPtr<IUnknown> pSourceObj;

    MF_OBJECT_TYPE objectType = MF_OBJECT_INVALID;

    hr = pSourceResolver->CreateObjectFromURL(inFilePath.c_str(),
    MF_RESOLUTION_MEDIASOURCE, NULL, &objectType, &pSourceObj);

     

    CComPtr<IMFMediaSource> pMediaSource;

    hr = pSourceObj->QueryInterface<IMFMediaSource>(&pMediaSource);

         

    // CreateASFProfile

    CComPtr<IMFPresentationDescriptor> pSourcePresentationDescription;

    hr = pMediaSource->CreatePresentationDescriptor(&pSourcePresentationDescription);

     

    DWORD dwSourceStreams = 0;

    hr = pSourcePresentationDescription->GetStreamDescriptorCount(&dwSourceStreams);

     

    for (DWORD i = 0; i < dwSourceStreams; i++)

    {

          BOOL bSelected = FALSE;

     

          CComPtr<IMFStreamDescriptor> pStreamDescriptor;

    hr = pSourcePresentationDescription->GetStreamDescriptorByIndex(i, &bSelected, &pStreamDescriptor);

          if (bSelected)

          {

                CComPtr<IMFMediaTypeHandler> pHandler;

                hr = pStreamDescriptor->GetMediaTypeHandler(&pHandler);

     

                GUID guidMajorType = GUID_NULL;

                hr = pHandler->GetMajorType(&guidMajorType);

     

                if (MFMediaType_Audio == guidMajorType)

                {

               

                      hr = pSourcePresentationDescription->DeselectStream(i);

                }

                else if (MFMediaType_Video == guidMajorType)

                {

                      CComPtr<IMFTopologyNode> pInputNode;

                      hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pInputNode);

                           

                      hr = pInputNode->SetUnknown(MF_TOPONODE_SOURCE, pMediaSource);

     

                      hr = pInputNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pSourcePresentationDescription);

     

                      hr = pInputNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pStreamDescriptor);

     

                      hr = pTopology->AddNode(pInputNode);

     

                      // encoder

                      CComPtr<IMFTransform> pEncoder;

                      hr = CoCreateInstance(ppCLSIDs[dwEncoderIndex - 1], NULL, CLSCTX_INPROC_SERVER, __uuidof(IMFTransform), (LPVOID*)&pEncoder);    

     

                      CComPtr<IPropertyStore> pPropertyStore;

                      PROPVARIANT var;

                      HRESULT hr = pEncoder->QueryInterface<IPropertyStore>(&pPropertyStore);

     

                      var.vt = VT_BOOL;

                      var.boolVal = FALSE;

                      hr = pPropertyStore->SetValue(MFPKEY_VBRENABLED, var);

     

     

                      CComPtr<IMFMediaType> pEncTypeOut;

                      hr = pEncoder->GetOutputAvailableType(0, 0, &pEncTypeOut);

     

                      hr = pEncTypeOut->SetUINT32(MF_MT_AVG_BITRATE, 100000);  

     

                      DMO_MEDIA_TYPE mtOut = { 0 };

                      hr = MFInitAMMediaTypeFromMFMediaType(pEncTypeOut, FORMAT_VideoInfo, (AM_MEDIA_TYPE*)&mtOut);

     

                      CComPtr<IWMCodecPrivateData> pPrivData;

                      hr = pEncoder->QueryInterface<IWMCodecPrivateData>(&pPrivData);

     

                      hr = pPrivData->SetPartialOutputType(&mtOut);

     

         

                      // create encoder node                

                      CComPtr<IMFTopologyNode> pEncoderNode;

                      hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &pEncoderNode);

     

                      hr = pEncoderNode->SetObject(pEncoder);

     

                      hr = pTopology->AddNode(pEncoderNode);

     

                      hr = pInputNode->ConnectOutput(0, pEncoderNode, 0);

     

                      // outout node

                      CComPtr<IMFASFProfile> pNewProfile;

                      hr = MFCreateASFProfile(&pNewProfile);

                      CComPtr<IMFASFStreamConfig> pStream;

                      hr = pNewProfile->CreateStream(pEncTypeOut, &pStream);

     

                      hr = pStream->SetStreamNumber(1);

     

                      LeakyBucket bucket;

                      bucket.dwBitrate = 8 * MFGetAttributeUINT32(pEncTypeOut, MF_MT_AVG_BITRATE, 0);

                      CComPtr<IWMCodecLeakyBucket> pLeakyBuckets;

                      hr = pEncoder->QueryInterface(IID_PPV_ARGS(&pLeakyBuckets));

     

                      ULONG ulBuffer = 0;

                      hr = pLeakyBuckets->GetBufferSizeBits(&ulBuffer);

                      bucket.msBufferSize = ulBuffer / (bucket.dwBitrate / 1000);   

                      hr = pStream->SetBlob(MF_ASFSTREAMCONFIG_LEAKYBUCKET1, (UINT8*)&bucket, sizeof(bucket));

     

                      hr = pNewProfile->SetStream(pStream);

     

                      // CreateSinkActivate

                      CComPtr<IMFASFContentInfo> pContentInfo;

                      hr = MFCreateASFContentInfo(&pContentInfo);

     

                      hr = pContentInfo->SetProfile(pNewProfile);

     

                      CComPtr<IMFActivate> pSinkActivate;

                      hr = MFCreateASFMediaSinkActivate(outFilePath.c_str(), pContentInfo, &pSinkActivate);

     

                      CComPtr<IMFTopologyNode> pOutputNode;

                      hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pOutputNode);

                                

                      WORD wSinkStreamID = 0;

                      hr = pNewProfile->GetStream( 0, &wSinkStreamID, NULL ) ;

     

                      hr = pOutputNode->SetUINT32(MF_TOPONODE_STREAMID, wSinkStreamID);

     

                      hr = pOutputNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, TRUE);

                                

                      hr = pOutputNode->SetObject(pSinkActivate);

     

                      pTopology->AddNode(pOutputNode);

     

     

                      hr = pEncoderNode->ConnectOutput(0, pOutputNode, 0);

                }

    }

    }

    hr = g_pSession->SetTopology(0, pTopology);

    Thursday, October 22, 2009 10:01 AM
  • The partial output type for the encoder should include the frame rate and the frame size, as the encoder cannot provide these.  Typically you just copy these values from the source media type.  I am hoping this is what is causing the MF_E_ATTRIBUTENOTFOUND error (usually this comes back as MF_E_INVALIDMEDIATYPE).
    Thursday, October 22, 2009 7:31 PM
  • I've set frame rate and the frame size and the error turns from MF_E_ATTRIBUTENOTFOUND to MF_E_INVALIDMEDIATYPE. 

    Then I checked the properties of the source sample. It has non-square pixel. I've transcoded the sample with windows media encoder from non-square to square. And the new sample works.

    I've set the pixel aspect ration attribute but no change.

    Further I've tried to use VideoInfoHeader2 by calling:
    hr = MFInitAMMediaTypeFromMFMediaType(pEncTypeOut, FORMAT_VideoInfo2, (AM_MEDIA_TYPE*)&mtOut);
    hr = pPrivData->SetPartialOutputType(&mtOut); 

    But SetPartialOutputType fails with 0x80040205

    Tuesday, October 27, 2009 4:39 PM
  • The WMV encoder accepts FORMAT_MFVideoFormat for media types, and the MFVideoFormat structure supports pixel aspect ratio.
    • Marked as answer by The March Hare Wednesday, December 2, 2009 4:05 PM
    Tuesday, October 27, 2009 5:58 PM