2

我是 Windows 原生开发的新手,但我的任务是创建一个小应用程序,列出各种视频+音频编解码器的所有转换器。

查看 MSDN 文档,似乎没有太多关于这样做的直接文档。我发现的文档表明此信息存储在注册表中(不确定在哪里),因此可能是一个向量。

  1. 这可能吗?
  2. 一般我应该怎么做?

谢谢

编辑:

似乎调用 MFTEnumEx 并将 MFT_REGISTER_TYPE_INFO 类型的参数设置为 NULL 返回计数为 8

MFTEnumEx(MFT_CATEGORY_VIDEO_DECODER,MFT_ENUM_FLAG_ALL,NULL, NULL, &ppActivate, &count);
assert(count > 0);

尽管如此,仍然必须获得实际值。但是传递的 ppActivate 参数应该包含它们的枚举。

编辑: 令人惊讶的是,虽然上面的计数 == 8,但没有视频或音频属性(视频/音频 IMFAttributes 对象为 NULL)

 IMFAttributes* videoAttributes = NULL;    
        if(SUCCEEDED(hr)){
            hr = pProfile->GetVideoAttributes(&videoAttributes);
            //If there are no container attributes set in the transcode profile, the GetVideoAttributes method succeeds and videoAttributes receives NULL.

        }
assert(videoAttributes != NULL);  //FAILS!

编辑:

这是一种从机器中提取所有 IMFMediaTypes 的方法(来自《开发 Microsoft® 媒体基础应用程序》一书的修改调用);然后我在调用者中枚举它们:

HRESULT CTranscoder::GetVideoOutputAvailableTypes(
    DWORD flags, 
    CComPtr<IMFCollection>& pTypeCollection)
{
    HRESULT hr = S_OK;
    IMFActivate** pActivateArray = NULL;
    MFT_REGISTER_TYPE_INFO outputType;
    UINT32 nMftsFound = 0;

    do
    {
        // create the collection in which we will return the types found
        hr = MFCreateCollection(&pTypeCollection);
        BREAK_ON_FAIL(hr);

        // initialize the structure that describes the output streams that the encoders must
        // be able to produce.  In this case we want video encoders - so major type is video, 
        // and we want the specified subtype
        outputType.guidMajorType = MFMediaType_Video;
        outputType.guidSubtype = MFVideoFormat_WMV3;

        // get a collection of MFTs that fit the requested pattern - video encoders,
        // with the specified subtype, and using the specified search flags
        hr = MFTEnumEx(
            MFT_CATEGORY_VIDEO_ENCODER,         // type of object to find - video encoders
            flags,                              // search flags
            NULL,                               // match all input types for an encoder
            &outputType,                        // get encoders with specified output type
            &pActivateArray,
            &nMftsFound);
        BREAK_ON_FAIL(hr);

        // now that we have an array of activation objects for matching MFTs, loop through 
        // each of those MFTs, extracting all possible and available formats from each of them
        for(UINT32 x = 0; x < nMftsFound; x++)
        {
            CComPtr<IMFTransform> pEncoder;
            UINT32 typeIndex = 0;

            // activate the encoder that corresponds to the activation object
            hr = pActivateArray[x]->ActivateObject(IID_IMFTransform, 
                (void**)&pEncoder);

            // while we don't have a failure, get each available output type for the MFT 
            // encoder we keep looping until there are no more available types.  If there 
            // are no more types for the encoder, IMFTransform::GetOutputAvailableTypes[] 
            // will return MF_E_NO_MORE_TYPES
            while(SUCCEEDED(hr))
            {
                IMFMediaType* pType;

                // get the avilable type for the type index, and increment the typeIndex 
                // counter
                hr = pEncoder->GetOutputAvailableType(0, typeIndex++, &pType);
                if(SUCCEEDED(hr))
                {
                    // store the type in the IMFCollection
                    hr = pTypeCollection->AddElement(pType);
                }
            }
        }
    } while(false);

    // possible valid errors that may be returned after the previous for loop is done
    if(hr == MF_E_NO_MORE_TYPES  ||  hr == MF_E_TRANSFORM_TYPE_NOT_SET)
        hr = S_OK;

    // if we successfully used MFTEnumEx() to allocate an array of the MFT activation 
    // objects, then it is our responsibility to release each one and free up the memory 
    // used by the array
    if(pActivateArray != NULL)
    {
        // release the individual activation objects
        for(UINT32 x = 0; x < nMftsFound; x++)
        {
            if(pActivateArray[x] != NULL)
                pActivateArray[x]->Release();
        }

        // free the memory used by the array
        CoTaskMemFree(pActivateArray);
        pActivateArray = NULL;
    }

    return hr;
}

呼叫者:

    hr=transcoder.GetVideoOutputAvailableTypes( MFT_ENUM_FLAG_ALL, availableTypes);
    if (FAILED(hr)){
        wprintf_s(L"didn't like the printVideoProfiles method");
    }

    DWORD availableInputTypeCount =0;
    if(SUCCEEDED(hr)){
        hr= availableTypes->GetElementCount(&availableInputTypeCount);
    }
    for(DWORD i = 0; i< availableInputTypeCount  && SUCCEEDED(hr); i++)
    {

        //really a IMFMediaType*
        IMFAttributes* mediaInterface = NULL;
            if(SUCCEEDED(hr)){
                hr = availableTypes->GetElement(i, (IUnknown**)&mediaInterface) ;}

            if(SUCCEEDED(hr)){ 
                //see http://msdn.microsoft.com/en-us/library/aa376629(v=VS.85).aspx for a list of attributes to pull off the media interface.

                GUID majorType;
                hr = mediaInterface->GetGUID(MF_MT_MAJOR_TYPE, &majorType);
                LPOLESTR majorGuidString = NULL;
                hr = StringFromCLSID(majorType,&majorGuidString);
                wprintf_s(L"major type: %s \n", majorGuidString);
                wprintf_s(L"is a video? %i \n", IsEqualGUID(MFMediaType_Video,majorType));

                GUID subType;
                if(SUCCEEDED(mediaInterface->GetGUID(MF_MT_SUBTYPE, &subType))){
                    LPOLESTR minorGuidString = NULL;
                    if(SUCCEEDED(StringFromCLSID(subType,&minorGuidString)))
                        wprintf_s(L"subtype: %s \n", minorGuidString);
                }

                //Contains a DirectShow format GUID for a media type: http://msdn.microsoft.com/en-us/library/dd373477(v=VS.85).aspx
                GUID formatType;
                if(SUCCEEDED(mediaInterface->GetGUID(MF_MT_AM_FORMAT_TYPE, &formatType))){
                    LPOLESTR formatTypeString = NULL;
                    if(SUCCEEDED(StringFromCLSID(formatType,&formatTypeString)))
                        wprintf_s(L"format type: %s \n", formatTypeString);
                }

                UINT32 numeratorFrameRate = 0;
                UINT32 denominatorFrameRate = 0;
                if(SUCCEEDED(MFGetAttributeRatio(mediaInterface, MF_MT_FRAME_RATE, &numeratorFrameRate, &denominatorFrameRate)))
                    wprintf_s(L"framerate: %i/%i \n", numeratorFrameRate, denominatorFrameRate);

                UINT32 widthOfFrame = 0;
                UINT32 heightOfFrame = 0;
                if(SUCCEEDED(MFGetAttributeSize(mediaInterface, MF_MT_FRAME_SIZE, &widthOfFrame, &heightOfFrame)))
                    wprintf_s(L"height of frame: %i width of frame: %i \n", heightOfFrame, widthOfFrame);

                UINT32 isCompressedP = 0;
                if(SUCCEEDED(mediaInterface->GetUINT32(MF_MT_COMPRESSED, &isCompressedP)))
                    wprintf_s(L"is media compressed? %iu \n", (BOOL)isCompressedP);

                BOOL isCompressedP2 = 0;
                if(SUCCEEDED((((IMFMediaType*)mediaInterface)->IsCompressedFormat(&isCompressedP2))))
                    wprintf_s(L"is media compressed2? %i \n", isCompressedP2);

                UINT32 fixedSampleSizeP = 0;
                if(SUCCEEDED(mediaInterface->GetUINT32(MF_MT_FIXED_SIZE_SAMPLES, &fixedSampleSizeP)))
                    wprintf_s(L"is fixed sample size? %iu \n", fixedSampleSizeP);

                UINT32 sampleSize = 0;
                if(SUCCEEDED(mediaInterface->GetUINT32(MF_MT_SAMPLE_SIZE, &sampleSize)))
                    wprintf_s(L"sample size: %iu \n", sampleSize);

                UINT32 averateBitrate = 0;
                if(SUCCEEDED(mediaInterface->GetUINT32(MF_MT_AVG_BITRATE, &averateBitrate)))
                    wprintf_s(L"average bitrate: %iu \n", averateBitrate);

                UINT32 aspectRatio = 0;
                if(SUCCEEDED(mediaInterface->GetUINT32(MF_MT_PAD_CONTROL_FLAGS, &aspectRatio)))
                    wprintf_s(L"4 by 3? %i  16 by 9? %i None? %i \n", aspectRatio == MFVideoPadFlag_PAD_TO_4x3, MFVideoPadFlag_PAD_TO_16x9 == aspectRatio, MFVideoPadFlag_PAD_TO_None == aspectRatio);

                UINT32 drmFlag = 0;
                if(SUCCEEDED(mediaInterface->GetUINT32(MF_MT_DRM_FLAGS, &drmFlag)))
                    wprintf_s(L"requires digital drm: %i requires analog drm: %i  requires no drm: %i", drmFlag == MFVideoDRMFlag_DigitallyProtected, drmFlag == MFVideoDRMFlag_AnalogProtected, MFVideoDRMFlag_None == drmFlag);

                UINT32 panScanEnabled = 0;
                if(SUCCEEDED(mediaInterface->GetUINT32(MF_MT_PAN_SCAN_ENABLED, &panScanEnabled)))
                    wprintf_s(L"pan/scan enabled? %i", panScanEnabled);

                UINT32 maxFrameRateNumerator = 0;
                UINT32 maxFrameRateDenominator = 0;
                if(SUCCEEDED(MFGetAttributeRatio(mediaInterface, MF_MT_FRAME_RATE_RANGE_MAX, &maxFrameRateNumerator, &maxFrameRateDenominator)))
                    wprintf_s(L"max framerate range: %i/%i \n", maxFrameRateNumerator, maxFrameRateDenominator);

            }

    }

它从 IMFMediaInterface 获取了一些属性,但设置的属性并不多,并且调用mediaInterface->GetUINT32(MF_MT_COMPRESSED, &isCompressedP)不成功,但调用成功(IMFMediaType*)mediaInterface)->IsCompressedFormat(&isCompressedP2),这让我怀疑我是否做错了。

4

1 回答 1

2

这是一个古老的问题,但没有人应该在没有答案的情况下离开。

正如您所发现的,MFTEnumEx可以为您提供MFTs批量列表或使用条件过滤的列表。现在,一旦您拥有了转换集合,您就拥有IMFActivate了每个可用的转换。

IMFActivate手头上有,请参阅此代码片段,您如何获取有关此转换的信息:您列出属性或使用其键访问感兴趣的属性,您可以获得类别、输入和输出媒体类型 ( MFT_INPUT_TYPES_Attributes, MFT_OUTPUT_TYPES_Attributes)。

这是示例代码和 MFT 转储示例:

于 2012-08-07T20:50:42.430 回答