GetOutputStatus表示输出已准备就绪,ProcessOutput表示NEED_MORE_INPUT

时间:2017-02-20 11:13:54

标签: c winapi ms-media-foundation

我遇到了这种情况,我遇到了相互矛盾的信息:

hr = pDecoder->lpVtbl->ProcessInput(pDecoder, dwInputStreamID, pSample, dwFlags);
if (FAILED(hr) ... )
//ProcessInput went well, no warnings from here.

hr = pDecoder->lpVtbl->GetOutputStatus(pDecoder, &dwFlags);
if (SUCCEEDED(hr)) {
        if (dwFlags == MFT_OUTPUT_STATUS_SAMPLE_READY) {
            // I get to here, sample is ready, yay!
        }
    }
dwFlags = 0;

hr = pDecoder->lpVtbl->GetInputStatus(pDecoder, 0, &dwFlags);
if (SUCCEEDED(hr)) {
    if (dwFlags == MFT_INPUT_STATUS_ACCEPT_DATA) {
        //...
    } else {
        // we go here, input does not accept more data it seems.
        // Sounds ok, we read the output that is ready and then we fill in more
    }

}
dwFlags = 0;

hr = pDecoder->lpVtbl->ProcessOutput(pDecoder,
    dwFlags,
    1,
    pOutputSamples,
    &pdwStatus
);
if (FAILED(hr)) {
    if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
        // Ok, but why did GetOutputStatus say we were ready then?
    }
}

// Calling GetOutputStatus to see whats going on
hr = pDecoder->lpVtbl->GetOutputStatus(pDecoder, &dwFlags);
if (SUCCEEDED(hr)) {
    if (dwFlags == MFT_OUTPUT_STATUS_SAMPLE_READY) {
        // nope.
    } else {
        // Now dwFlags is 0.
    }
}

hr = pDecoder->lpVtbl->GetInputStatus(pDecoder, 0, &dwFlags);
if (SUCCEEDED(hr)) {
    if (dwFlags == MFT_INPUT_STATUS_ACCEPT_DATA) {
        // this time we go here, we can now give more input again.
        // but we got no data from ProcessOutput
    } else {
        //...
    }

}
dwFlags = 0;

查看我发送到processOutput的数据媒体示例,只需在缓冲区的开头写入空终止符'\0',否则它不会写任何输出。

GetOutputStatus

  

如果方法返回 MFT_OUTPUT_STATUS_SAMPLE_READY 标志,它   意味着您可以通过调用生成一个或多个输出样本   IMFTransform :: ProcessOutput。

     

...

     

客户端设置有效媒体后   在所有流上的类型,MFT应始终为两个中的一个   状态:能够接受更多输入,或能够产生更多输出。

我在设置解码器输入和输出流时没有错误,所以我认为流应该是好的。在输入媒体时我没有收到任何警告,所以我认为我应该处于有效状态。但这种行为似乎与我认为的文档建议不符。如果感兴趣的话,我只有1个输入和1个输出流。

那怎么会发生这种情况呢?我从该工具中获得了相互矛盾的信息。数据准备好了,但我读错了,或者还有其他事情发生了吗?

编辑:

有一些评论要求提供更多信息,还有一个要求提供最低限度的完整示例,所以我决定尝试一下。下面是一个小型的c程序,它运行我运行的所有东西,它通过读取文件中的输入并以与获取数据相同的方式发送它来模拟我的环境。我已经完成了几乎所有的错误处理,删除了辅助函数和硬编码了一些东西。该程序再现了该问题。我在Visual Studio 2015中运行它。

#include <stdlib.h>

//windows media foundation test
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <stdio.h>
#include <mferror.h>

int chunk_handler(unsigned char* pBuf, unsigned short length);

IMFTransform *pDecoder = NULL;
DWORD dwInputStreamID;
DWORD dwOutputStreamID;


// inspierd by FindDecoder here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms701774(v=vs.85).aspx
HRESULT FindDecoder(
    IMFTransform **ppDecoder    // Receives a pointer to the decoder.
)
{
    HRESULT hr = S_OK;
    UINT32 count = 0;

    IMFActivate **ppActivate = NULL;

    MFT_REGISTER_TYPE_INFO inputType = { 0 };

    inputType.guidMajorType = MFMediaType_Audio;
    inputType.guidSubtype = MFAudioFormat_AAC;

    hr = MFTEnumEx(
        MFT_CATEGORY_AUDIO_DECODER,
        MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_LOCALMFT | MFT_ENUM_FLAG_SORTANDFILTER,
        &inputType,      // Input type
        NULL,       // Output type
        &ppActivate,
        &count
    );

    if (SUCCEEDED(hr) && count == 0)
    {
        hr = MF_E_TOPO_CODEC_NOT_FOUND;
    }

    // Create the first decoder in the list.

    if (SUCCEEDED(hr))
    {
        hr = ppActivate[0]->lpVtbl->ActivateObject(ppActivate[0], &IID_IMFTransform, (IUnknown**)ppDecoder);
    }

    for (UINT32 i = 0; i < count; i++)
    {
        ppActivate[i]->lpVtbl->Release(ppActivate[i]);
    }
    CoTaskMemFree(ppActivate);

    return hr;
}

int main()
{
    UINT32 samplesPerSec = 44100;
    UINT32 bitsPerSample = 16;
    UINT32 cChannels = 2;

    HRESULT hr = S_OK;
    HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);

    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

    DWORD dwFlags = MFSTARTUP_FULL;
    hr = MFStartup(MF_VERSION, dwFlags);

    // Create decoder
    pDecoder = NULL;
    hr = FindDecoder(&pDecoder);

    // Create input and output audio types
    IMFMediaType *pMediaIn = NULL;        // Pointer to an encoded audio type.
    IMFMediaType *pMediaOut = NULL;       // Receives a matching PCM audio type.

    /* Create pMediaIn */

    // Calculate derived values.
    UINT32 blockAlign = cChannels * (bitsPerSample / 8);
    UINT32 bytesPerSecond = blockAlign * samplesPerSec;

    // Create the empty media type.
    hr = MFCreateMediaType(&pMediaIn);

    // Set attributes on the type.
    hr = pMediaIn->lpVtbl->SetGUID(pMediaIn, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
    hr = pMediaIn->lpVtbl->SetGUID(pMediaIn, &MF_MT_SUBTYPE, &MFAudioFormat_AAC);
    hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0x2a); // value can be found in my onenote, (AAC Profile, Level 4)
    hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AAC_PAYLOAD_TYPE, 3); // (LOAS/LATM)
    hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample);
    hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AUDIO_NUM_CHANNELS, cChannels);
    hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AUDIO_SAMPLES_PER_SECOND, samplesPerSec);

    // blockAlign, bytesPerSecond and independent samples were commented out previously
    hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AUDIO_BLOCK_ALIGNMENT, blockAlign);
    hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, bytesPerSecond);
    hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);


    //first 12 bytes:
    //wPayloadType  = 0 (raw AAC)
    //wAudioProfileLevelIndication  = 0x29 (AAC Profile, Level 2)
    //wStructType  = 0
    //  The last two bytes of MF_MT_USER_DATA contain the value of AudioSpecificConfig(), as defined by MPEG - 4.
    // 00010 0100 0010 000
    //AudioSpecificConfig.audioObjectType = 2 (AAC LC) (5 bits)
    //AudioSpecificConfig.samplingFrequencyIndex = 4 (4 bits) (44100hz)
    //AudioSpecificConfig.channelConfiguration = 2 (4 bits)
    //GASpecificConfig.frameLengthFlag = 0 (1 bit)
    //GASpecificConfig.dependsOnCoreCoder = 0 (1 bit)
    //GASpecificConfig.extensionFlag = 0 (1 bit)
    UINT8 audioSpecificConfig[] = { 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10 }; 
    hr = pMediaIn->lpVtbl->SetBlob(pMediaIn, &MF_MT_USER_DATA, audioSpecificConfig, 14);


    /* Create pMediaOut */

    // Create the empty media type.
    hr = MFCreateMediaType(&pMediaOut);

    // Set attributes on the type.
    hr = pMediaOut->lpVtbl->SetGUID(pMediaOut, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
    hr = pMediaOut->lpVtbl->SetGUID(pMediaOut, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
    hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_AUDIO_NUM_CHANNELS, cChannels);
    hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_AUDIO_SAMPLES_PER_SECOND, samplesPerSec);
    hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_AUDIO_BLOCK_ALIGNMENT, blockAlign);
    hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, bytesPerSecond);
    hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample);
    hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);

    // Figure out streamcounts and ID's
    DWORD inputStreamCount = 0;
    DWORD outputStreamCount = 0;

    hr = pDecoder->lpVtbl->GetStreamCount(pDecoder, &inputStreamCount, &outputStreamCount); // both StreamCounts == 1

    DWORD dwInputID[1] = { 0 }; //hardcoded
    DWORD dwOutputID[1] = { 0 }; //hardcoded

    hr = pDecoder->lpVtbl->GetStreamIDs(pDecoder, inputStreamCount, dwInputID, outputStreamCount, dwOutputID);
    if (FAILED(hr)) {
        if (hr == E_NOTIMPL) {
            // This is expected and quite ok. 
        }
    }

    dwInputStreamID = dwInputID[0];
    dwOutputStreamID = dwOutputID[0];

    // configure decoder for the two audio types
    hr = pDecoder->lpVtbl->SetInputType(pDecoder, dwInputStreamID, pMediaIn, 0);
    dwFlags = 0;
    hr = pDecoder->lpVtbl->SetOutputType(pDecoder, dwOutputStreamID, pMediaOut, dwFlags);

    /*one time setup is now done.*/

    // simulate sending in the first couple of chunks that I can get while trying to decode audio

    // Reading this from file, again this is just read from a file in this example, in my real application I get the data sent to me in audio frame chunks.
    // For example the first "chunk" of data is:
    //  47fc 0000 b090 8003 0020 2066 0001 9800 0de1 2000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 001c 

    errno_t err;
    FILE *file = NULL;
    fopen_s(&file, "input.txt", "rb");

    unsigned char line[10000]; //big enough
#define NR_OF_INPUTS 14
    //                           0   1   2   3   4    5    6    7    8    9   10   11   12   13
    int sizes[NR_OF_INPUTS] = { 42, 42, 42, 42, 42, 340, 708, 503, 477, 493, 499, 448, 640, 511}; // lengths of the data

    int i, j;
    for (i = 0; i < NR_OF_INPUTS; i++) {
        fread(line, sizeof(char), sizes[i], file);

        printf("Input chunk number: %d\n", i);
        for (j = 0; j < sizes[i]; j++) {
            printf(" %02x", line[j]);
        }
        printf("\n\n");

        chunk_handler(line, sizes[i]);
    }

    fclose(file);

    return 0;
}

int chunk_handler(unsigned char* pBuf, unsigned short length) {

    const UINT SamplesPerSecond = 44100;
    const UINT ChannelCount = 2;
    const UINT SampleCount = length * ChannelCount;
    const UINT BitsPerSample = 16;
    const UINT BufferLength = BitsPerSample / 8 * ChannelCount * length;
    const LONGLONG sampleDuration = (long long)length * (long long)10000000 / SamplesPerSecond; // in hns (hecto nano second?) 0.000 000 1. (Duration of the sample, in 100-nanosecond units., see IMFSample)

    HRESULT hr = S_OK;
    DWORD dwFlags = 0;

    /* Setup for processInput */

    IMFSample *pSample = NULL;
    IMFMediaBuffer *pInputBuffer = NULL;
    hr = MFCreateMemoryBuffer(
        length,   // Amount of memory to allocate, in bytes.
        &pInputBuffer
    );
    BYTE *pData = NULL;

    hr = pInputBuffer->lpVtbl->Lock(pInputBuffer, &pData, NULL, NULL);
    memcpy_s(pData, length, pBuf, length);
    hr = pInputBuffer->lpVtbl->SetCurrentLength(pInputBuffer, length);
    hr = pInputBuffer->lpVtbl->Unlock(pInputBuffer);


    hr = MFCreateSample(&pSample);
    hr = pSample->lpVtbl->AddBuffer(pSample, pInputBuffer);
    //hr = pSample->lpVtbl->SetUINT32(pSample, &MFSampleExtension_Discontinuity, TRUE);


    /* Setup for processOutput */
#define SAMPLES_PER_BUFFER 1
    MFT_OUTPUT_DATA_BUFFER pOutputSamples[SAMPLES_PER_BUFFER];
    MFT_OUTPUT_STREAM_INFO streamInfo = { 0,0,0 };
    MFT_OUTPUT_STREAM_INFO *pStreamInfo = &streamInfo;
    DWORD pdwStatus = 0;

    hr = pDecoder->lpVtbl->GetOutputStreamInfo(pDecoder, dwOutputStreamID, pStreamInfo);
    IMFSample *pOutSample = NULL;
    DWORD minimumSizeOfBuffer = pStreamInfo->cbSize;
    IMFMediaBuffer *pOutputBuffer = NULL;

    // code checking for if MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLE and such, Turns out client (me) ne4ed to provide sample so lets do that

    // Create the media buffer.
    hr = MFCreateMemoryBuffer(
        minimumSizeOfBuffer,   // Amount of memory to allocate, in bytes.
        &pOutputBuffer
    );
    hr = MFCreateSample(&pOutSample);
    hr = pOutSample->lpVtbl->AddBuffer(pOutSample, pOutputBuffer);

    pOutputSamples[0].pSample = pOutSample;
    pOutputSamples[0].dwStreamID = dwOutputStreamID;
    pOutputSamples[0].dwStatus = 0;
    pOutputSamples[0].pEvents = NULL;

    //INPUT
    hr = pDecoder->lpVtbl->ProcessInput(pDecoder, dwInputStreamID, pSample, dwFlags);
    if (FAILED(hr)) {
        if (hr == MF_E_NOTACCEPTING) {
            printf("Input cannot take more data\n");
        }
        printf("error in ProcessInput\n");
    }

    //OUTPUT
    hr = pDecoder->lpVtbl->ProcessOutput(pDecoder,
        dwFlags,
        SAMPLES_PER_BUFFER,
        pOutputSamples,
        &pdwStatus
    );
    if (FAILED(hr)) {
        if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
            // this is ok, just need to make more calls to ProcessInput
            printf("ProcessOutput needs more input\n");
        }
        else {
            printf("error in ProcessOutput\n");
        }
    }
    return 0;
}

代码中的“file.txt”引用应包含以下格式插入的以下内容:

47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066200198800DE120000000000000000000000000000000000000000000001C47FC0000B090800300FF4A214DE73987D722230566AD966E80B72A99797BFFB7978EB3DB9E248875BA38E42B7924EF58A2CCC578931AE67157BF6E7E3DC51B70265C888DA8CB0074753F9F0F3EF9B0F70CD8D5B2363C3B9CE1275DE0E4E7313C6F88FC611D87A932D4263BDFB8C74B5E9052DD5046AF66EA3AB55F9E2186ABCC5A72A3664F1CA21CC678AC24CBECD3797D7C2C50B335556E7DF5E51E5BECBEA1337CA71ACB7ACFD9EDABE47139CB0695F8D575EAB0E461BB5336ED00E2F0F5F381CAD2E9E2C0750FAE43460E9B372CCD016EE6E5547FF4F89EBACF3BE2EA21D7E9038E190CA4D46DB54633FCB9331E830DC6AFB7A1325F0E79DD1C6D886320F8C728DAA34AD00CA999CC089702E7CD7FD8EDEB1FEFFAB63F8D9E798CD483BE697B314BF749F17967FE9F46688D45D8D6B926300840223B9AD2B7291B288518835BB2629B61D79EAB5760D16FBEA3B909D4E7F56747FC0000B090800300FFFFB4216BD505EE8504B0D098342810840D0AF6CCCD71DEADAD6EB2F7117B85CAE255CC5C39130EF0EA7A7F7565275CB6CCBB9E70843BA4847444976535677F95480D0AEC0D0A63F40F1BF7B645AB70307D0262A388BBB2DE0F90E12FF5B46A2EAEB1C8E85C50061833EF9324731B4F7D29580BE0FA0DFAB6AA78341FF25422B0A7039F64C34BA063763E54D489805ADE242371C3C865F17360ADFD3956E6A6AC18D8463879AC4FA70D0ADAC9C5E146F5BB6541F8ACB2EEA53D1EF35EB0ED715F7C4B9A1A072908A66CE92A76328E43010B3820EC9E255C388BC5DE3E02D1393EA9FC70CD44555DE9F6E419C20F804F0361AC702CFFBDD6DEC4BBF6C7736AA1F207CFFC9934E9DBF039FE469D1B2B50B4507E8F6326BA9BD42B71A1A7AE74D23FF1F89CDAF27D614D3C2F8AD767004AC2421E11D8B86B058DEF88EB9A9C8E8C35CF980D0A56664CF27385181987F7878D06AB6F7E46200764841CB0820195C383613579C8836BA8622C06DF3889D200773EDC28AF89E3656DEE0699E66DDB9E7070EFB96BB024F2B4155A9E7806649A8C00A383586956581A0602015141282C140B100CF358BE372EEF5B65E51ACDEB2EDC4A9ADAD00D10420408761E859304BCD8828E72EEEC4AD4219560E77946692F3C51EA9BE12AC6431DFF674CF94931D357B6EF90E912A3B9ED135C6D620EBF7D887A38CC78E67B543838ABA936E67848A2744AF716CB8955C1CE9FB4784271584E49DE019496B654C6B413D74AA09ACFDF68233F39F176931E10A093B0C47961BC72F87C31FC3EA92BF55438EB90345122D1DE3BA14653C459A53C0E5CA3D8ED1097DDD3D5DB39C645D5E07396C76131C03B329A3C98E65A19E63380B51105F21089088038309AE0E4A17C6D6D827D5D85FF804805BAFC4441580F7FE5872EC3DD9C9C00312022F67A4D40AF900D0A1A5427DA204E113C93931E9A0209F7CD2303102E9F674A3B2B706E47FC0000B090800300FFEA210BD5159E8F6982B1602C703386BC713BE1AA54E75B0BA9092E29726E03838C74AADE6D55F03227C9F0F84F90159F2C64D517A77D6F1D69258146F8A3397C3BBA296084B027A9E6581390F1A00E4A3A26E67944B2F09DDEF851344D3BF2DA8A8B11C1C00750A7B34A310D04481F02AE190D0A41F83BD088CE2ED2BE9FE1819099C7A22D5C6738C32DE20F2201D6A603A2082DA21D6A677E2E471044B72C64C6085C734BD1C8D9E1287E93A588C4BAFB075E0D0A3751BC5ED4009F7F7E2500A8394D0B3D0D0A18F9CA85996BB1651362C72A739DE23A9ECDCF6CE771C523B42CB0A698213E554967559681AB800574D36050440CA4D00E48AA71748E65F5CAF6BAF7B01A64803C453ED2093582B6236DDE26AB2B2BC500002A129D1A56FA19400000E22952C4AE3BA298876484D89D4A832819C4D733AF5E6BADCACAE37CA17624B936E2A77A0914FB393C13DB11C2EF9C7E039F0718E7FFA578FDD875ADE3B4F3FAB20CF08AC721C4182E60E5A2D4DBCDA1810F88D64ADDA7CAD3981ABD3AD8E114BD505EBD8D5D7CBC9967899697B38D411ABAE11B391718EE9BCFAB917196FCC2B910B9170351CBAEB97577CD6F1D3215B0E72EAC739176AEAD6009AEBF56B882BE32319DFDFD33D5F28BA0706BA273601740829B8BADCE4537BD6BEF9BE0F9D2CBE60884F9225109718E47FC0000B090800300FFCF210BD51DB18561A4C0D9683033CD5F8EB5EB55ABDC64ADD244B26A26489960D9D84969A878658210307F2D01CE29359116C0739E92EA87B35B0D0AD5F223F143BE0D5D6EB2B69CCACFDECB8C36B5D9B771E03295998B9A62498D887106EC5E918E0C30076F5ECE6403391363A62CB44CBB6EFFD74CAC0CF90D0A2ADDC490E2306145701D85B1A9CA12C258CB7D81532D99FA8DF3C7A1894357950D0A0C0B7CBDB8D297200CFAAD4AEBC92BBDEE087AA9BFF6A49C2B7A7BC66900EBD78F859330033EB9C009C649B8A0E99E774E3ACC0C01DED63CC2247BB5A3C857D2D50D73D92C5BD345ECB6E9A6FEC7000D0AC2F870CEA2AB20BE4057C9EF9922083AA2ED64350DB514A84A0405E3CE51B6FAE53316CBFA2C87B393C5CDAEFB9561FB12DEC4C75F3C69C876464D094EC255825E57DF5AED77158BAEE979A9AA4BBCE372507AA149F8A2108A682471F2BD48D3DDDA49E896AFEA79BBCBCB96E00759FB9E77B110866D32F8C3061C4655E056BF8FD5F0417D1BF296F735F0D682437F67D9BCC05D6E8BD6E725050C41133E9D9D3E76280444FC260D435C631302720B6EA53BE9E7B890405D4564310F7F2C48027535A15DF807777F1EEF7F57DC0BDBBB398004C1CC5D159991BDAB0373926719A000006A1C47FC0000B090800300FFDE210BD515B290C2A0C1944C741819E4E755755C632A537335ADAD2EF5544B5481F1B472C55D552D4982F5FF89A5E18B3853B70D0A6380EF43AED06FBE5510F067C8E66CC6E0568C614076560EDDA09A3150EC4091D6FFEC2D78A38EF6FD5D52D0DC9F2BD2F3DC2DF9FA413F130355403920A91E9D2FA1FBAF09A7C239059DF6D3A72B24E8B96340288C68DEB4D9D44E9D2DAB0D3F8BBF15CDA44D549DCF8345F55DC594A21615BD6128E17D700240980B9DE7FC2456E7B7D5A0999AAD8EEEFF8B970E78B5BC34559F98FBA90D9C28BE444F0D0A8DEC59EB7D38104926B66CAC98E8B6DD3E69A2BA899B77D4C002DAC600A5734B62A006A1886E511063F09E93ADF3800B8E1CEBC528B8630900AE86759E7D1F08DF9DE47E57E93EC05714FDAAC43FCF03E57A551D29094162A8506AA31021E738E784DB8DDF350E667536B3875554BD5609E7C846792B5B0D0AA9DCCACFB143A6AB0B087917695136C22505859DDFB9E2CF3FC73FBDBEE77C1E853B74A0C023755C2BBA329D4C1D0298AC33342083E328F7F6663D5403C12943925C1007AAD0789F0E429D909DE53DA00D0ADEE57C77A966388A04C096FE3D08E41189037D5C2F32D71C015B46F31DF3F1D6855556F7A9339D0D0ADB788178227218CEB505E03BB5C7EEAD6A0BC63CFF7E9F4F00DD1C47FC0000B090800300FFE6210BD50D9E936181B0A0AC270B1102C451019A943352D95553994D5EEEEA5EB55448342299BD823F916D8AE11EB398B2D5CEB34CFAD3B2818D3F9E30884B0D0AEC3A05147354117537040109F46A27CD52806C4279C1C3E9FD9F6620C3ABF2AD8702767FBE226C934BDCD0E2BBD40E4003136CB1A3CCFD951FB2D8E9DE5415B55384B798B48C32469B56B54506917A7627332D8C4FD7A85897697186EBFCEBBE26D3C6D94D107198D32BAC82FCD0B081BFF7B43C4D8CF9786BE3221B39DB69080052494AF6E6A310BB6D8A50A45AD99DC00D0AAD604E4169612A8E75F96CB437EBE93645816D58F03BF46FEA654056FBABAE703A4899000C90F7F748200D39BD4FF897B19092B0BA000066B80E8357461289899CAF12055C66FEBE9E118E572C4494A438208A0F45632A1022503349AC6F8BE32B19399249BBBA4EB46DAA258D847BADAF69EADE38B19AA09DBD707825ABFE12D1E74C88B545354477A140A7CF3E83A47350CCA0796ED91F102C2378BD91B2A8820D9C0430C8096CC6C007279AF9984B6EAAC420D41DC51656027437981BC26ADA054E2EC7F2E24AF461733B014002A18EEFB2635C38700D0A89F872EACE26AF3B019F86B15383BFC72075F52EBE1F0CE3BFF5E3AE75AE38C4CA402304400714037E466C2802534AF14B0600101370D000705BE2E047FC0000B090800300FFB6212BD4ED9E936182D0A08CB04353DEC47192B753BE0975256A5945A507ED211FBFABFBDFD8B7E5E14B401438D2ED27B9D8E7E30651A8224007FF029525ACBEC13E7B2D6503DC54CAA43A1E35D7D264D0DB50F3789F04142A8902C1D6E0ED0080C561CD098EA1EDED08A04A8EBA2993001374E57D54528315752B83C7116C3725458CB05078123B8D8F3CB6E0976FB8F0A914A051B66CE31EDF5153AD9A011948859002F1A81CA6529E33155B64EAE03D2599AB5A501F05A72EAB90002CC2FA2BAE2E929CC7659A8099E80D6B9E79CA3C6E40B8FC25B18C6D689E819DBB335A7405E539405ECEAA41395B6D315146F14C910D40EC95B768B86204D44640B5A806AAF52AC2DDD423CC4B4E108F5844E6235D051E16A18131548023200C44065F1F6B5E5DEB2F2B75BD5D59755ABBA55CB04027445D19A4858A1C48F732E11169DB549AEC4BE6E3910C01EB3DBF85B3585D7E4DCAD92DFBBCEF54298CE02321D79BA0DAB0010D88105387DFFF664000066AC6CCFABF22F7401899A064D249404E84C90B989B5405C6FB534842FA37DAAE4679C9B902EBA4675EEE5DADF46E00251781D8F6DC5D6BCE23F1FC2194128B1316D08805038047FC0000B090800300FFFF72214DDEFFFFFF3336A9B1A2D1C81B54A1DA62A80B8F112FA2FF1FF13779A9C4DDF41DBF58B878CF6840F504F3FED85D1608DE4BDA7D0748C2711E387AFD2C656A7C078531B2A9B2D5A7F07E8671F9E7E41B3ED4F031EE923A47C8FF0D0A94305B24B1CEEA67EC5A3A74EA9B6F7285B3C68E0FB587FE1A30DBFBD5170532508F2D095022535C81BAF3C8068A2E476984FA49121FB15851DE70AA3EDAC7A4F285AC068F1F39BC124BAB7BCBEDB59A0D0A7EAB05AEE759E63F48C64EEAB770833C3352FBCE1E417534B457F411155A5694BBA5D190B8C934CE6B5DF88DAB9777303994614BDDA9A50CBC15E0AFEC1F3DA00DEBBC25304658E57ACDCCFE743CCF2D97096C43ABBA3EFDA47676B38B3C7E308D54B45A3B8D8470BF98EFCED3C9D5A375EE4566E39C6807A0072BA6F9F19E8B25EFEA994AFFE67886B80DAFE0FBF9A26768E3D4EA63974BA55CB83B15CBBDD95E3D3007C2009000009AA31113136E40D46506CD162A80AF9893DB1AFDFFECABE78BE1BB807B20B5E81EF71CC44F05FBA36F78B60957374E4DA34C8A7A9236A3EF391BC15CD9ED7957AB2422E89444BCBAE7B93F9D6E23D8FA2DDEE93FAE64FB7FB824389C1F8096FA407C88C3081FE7CB3FEBCE03728C752131676EA6B105B4681D75368D4F245EE81EACF386076278C95924087B56FC0E2AD55F77A6A44B28A9B25AF286BEBD27226A18C2E2BA296FD959452A32E9231ACF2CEE5C050478175B83696AFAE0118C5984F3F724A329DCE25230C9ABA45FA9EADB6E64C57E9609F22B4D3E8651E60DDF127A6010A3320BA3D0BFA22D921572043923A011330D0A003A5A67F67D3F2FB39FFDFF0D0ACF6763F88F838C001F3CFD9D523FCDFB3B02F19000007047FC0000B090800300FFF2216BD4FDBE8D0E620840EC8BC78BDFD139EED7968BC6B495922D9438B20F89CE72499D90F50FD31ABA4B912523B81ABD5BC3F1AE5F9FF34E75F97E68E4876E1AE381C96FE987C9F366AB724F3C634CA9AA4A1E27758C5D5EA32DF47634CE4B8EAC1DA6522172C6BEF6B78B6C21A968325B87FA4B8C75DFC9AF7E3AD024A6D45DF651B19D99133869232C0CA24BEF0DA6CA2133CC0277D02C0FBD2104C9A58C22A45E6E0520C1A55DEE48AA9B600D0AEA6BEE37AE66ACB8DDE4E53C23D36D4448C397749D19F2B1E68428D0A7C57EB91A4860B12C4D69769DF1D4C69CD4D04F9D72934AB58E51072C4B09925BD7DA02259693C4C0FC25218F6A78216AA094DB7AA3619D6F9E696E7B25510006A6DC24FD5BDB1348F57C63CAB3DF759729524CEF7E40014C5637D7AE61000322198D20A41142EC4C45431504650433AAD667339FAB5F7DC6B22D2AB8D456EEA5B63493B898F6DF0F70DD916C86A6D462BB14C15C776CF8EDA49868E510773CC69988D806E1870859E0B344AB8F1B6C3BFE417BF7E9884F2128F5F4DC3B63E1238E6312D76F2E8E576057340BD2E2A4ADD6484457609AA80209CD4DBE126F9A509DD011A9FA7DBD617DCF84B948BB7B616CEFDBE094B829D525FBCA7B2582A52421BAA94AC8A8A667836D98C5D5711A92FFE8B8F97433278764D5D5D597F7BE5013C0CD605C1C47FC0000B090800300FFC2210BD50DBA0D618431602A200B04C40656A92FD4DF152AAAEB591245A242AAED06E8F0672C5946157169B9AB6ACB4F1866BA4137814BE13F05A2411098969DCFF61E40B4BE944463971C375920B2BEBF3A52F0E2D1869C9A888FA900465D2C74FC76F45CA4CE0D0A140D0A695E04899CC9250D0A8F80C42290A86140C5B248EC8EB7392B6E14215BF0C9CA0341490623A1391B0D914C92E7395009A2E15134A7125C2557891339CE05826194D5D4EDAC6B192FF34B8600071E6E14E38CD3852EEEB194F2D963C817DF43D0C0E0FA9128E525AF7A10B9257719C014437538E585FC4A8F51E58128CCBE659EF01E420D0A1A6AFDDE784FA351F1AFD5009DF4FB669871E7BA8C8A2CD84E5DC355583B2A7A9F0FD2DE041D1BA072F00292D30563A2D4802108215EDB8E3F4D6F52AEB76D622D5A45CBCCAE01AC8707447199D2B8193647757C0014E4BC4E8DD9D251E0755086332FE1E122E318533919E1171A85F17DEC4B7F30EA40005ECF1322EF9705A2DADB354EF0D71653C09BA5771CF866F6B4692BFB53A20D0A36ED3BD63B5397E1AB1C76A6066610535CEC5857AA165F8A3BDE3AFE62C14540A8AFF1CAFD7351D7638E0D0AFE577D1B1753015C98CF3AD1588056C07EF11C47FC0000B090800300FFFF14210BD51DD612C2A238A04A1032F86DAF9E39F6BEEF61256A2492AE5A492E507266D8A485B1C91050CF618CD9D24CE9422880B92E969794BD6EE21043A9B997E8E5D02CAD01D5EDFCD8B871220B37D4CE28394314B723411472F6DA23E15CA10D66D7147D38C0B31AF672573349490915B6D97078FB5216D535437AFA64A678C4507414C17AE5E54217F0928AE120AA4785CF3F2AFE23CE722FEC6DAF8231ECE7B282285F116A70137C711FA2C90995AE22233874438CA69F0827AC2318B4DB7DD3825F4DCD72EFCA13BEECA7B33B500C24F86B032995348674CDE93D20D28DC69B44836A2268C6383600AD36D5EC1C7BEC2C0513E4629551BA966ADF93A8F5685BEEAF417384CBA8556AA4C9C797361D1FF6F65CAF91AA2A7180000D0AECFCF8A27CB9FCBB33CA6E75A45F9A5D5566D68ED32A7169E09938465DC13D5FF9F6F1C635A8AF3F648535B98D4154A08C4C15080982A2032FE3337AED5ED399CD5E5D719A8BAB9BE2173A6034F9A257E49449860F1F3234D1E7A7C1FA3154C6FC7C53088642EC3B6454AAE6AFB85BA6A3437CBE2624C9CDC9D46A9C00CAC1300557BF14621033ED6CCE4F846AB973EBF9F216D31DFC2A6205E3B65BF0EC84AFBF58E701778C6E78EF8004EE98EBEF8ADEFF856C00089D7AAD2B65E220AFE016A1473108E0CE9461F75AEAE24B9753B810A8C348A9870D7373F8FB3AFEE07C3521BFCCF7E51132B76548165BFAB62A73300FBF40003847FC0000B090800300FFFF1F210BD51DC6890761C0E84A281819D5E7377DB9F3795855CBA5DDB24BB9217C503B377F9A2BEC89E1CFC791C41158ED857519F6B98E872BBEA9B614500C6FCF7E468CB64F31AE089CDE696E45B29D9F3874F083E36F6AA0CA5F849622858B8F4153CB0721ABACB0FCF4B0A209E092CB70A10D0AC689F786783E85E022E8E02D4CC2AC1AE0984E701926788007936A163026CEC02DA74C159B3AB81003236120A2630E9E85980966AF95D712FAEBCA35EF9F4918972FF646A17B757FB28F2A67007C26B281C925832AE31703971AC6C931F10CD6DACABB61D49A8BF071B4947D952A33789A89A54C5757C1DF155B58C62BE42982A928E8ACE39C75DA8B0D2F0B518C7D975D846EC28236543C505AFB3D7ECA81A80000673F2EBE8DECEDFDFACAD8AB7AE33B43B2F05E722499D77A4D223A2DF7DC42437AC0B03D271F05379CE739CEA7B4B1A82C210D894C8452889828103BDB59BBBEF3BF699372A389556E1BB6AE495E3DBCE02863569A20106734826201CEDD6DBF328E8EA8E13833AFA5CE678A43ECACAE056F438204DE3F666ACC594CF22AC0A0238671CB13CA31BBEF5D1E38EC8CEFA372BA8EF29CB1EA825590EEC95BE0AB98BC4DFBFA60C7DFD18CA5FD6F1D94832B9D4A2F46EB40E777B2C321FC8BE45BBD477B3BFE94D7BFABB61DDDE62B2F679F007BB8ED7ACFD9D5C7D935F1E9E3FE9F1800AFEDF1FFAFE5F672FF3DE2FE50E7B83AFA400004B8275F20987F35768CCDAEE5D92358534EF57847FC0000B090800300FFE9210BD525A68D6181D098B4180B0E02C451308C20679BA6FCFBD73E655EF6B8B2692A4B092F554152C8CC9205E29FA1F9D772C440C559DA53E5DFD1398ACB4BE64512620F63F0F92B20EEC15947AB0E2032125AE3D054070D0A7FF21BED4335F82519E41E12FF8F0051C5B625EFCA1005A8AEBEFF8DE407E4DB9655E7ECB95ED8C7CB496524916480007916D9278CC3EBC697721DFF0D0869C9A008D1326C2993079D09DCB1D3D0AB84EF3ED249260EDBB1F2C37F7F6D7A3BBB6E69EF7291A667BAAAD6B918D4A92544E23A89B38AA35E781A4BEA47FAEFD482A873DD4D7CE903BB5C9B7826170537DD2C9D293450B2E49701CCE49E9CFE1DDF8D98C4700B9808559CD6F7BE9E000D01A4B1F4FA8B8787C3FCF282FAD6CCDC960542EB9CF77D5D75DC63F7AF27A51920A741D9A156250D0A115402408880CEA5CBBF9DEFCDE71CF3347189C52AEB8CB2BE302116B6FAA464C548A09BF3AC27F9AC0093C55F0004D671C4A53924BB758CF48C9F302A31E1B0E340339630896052D4E6D2C418E38203E952003C4B7F9635A743DE4D2C284D206EA7E25CEB9AAAD095F1306F11D7F2FE5323ABBE05EFBE031D2D467BF711A847074702B60B910C639FB30BC600066000DF8F6856EEE57D3C2B35BDCEBBFAD20365E9598E8854AB6361A0790B5FE6DB3F2DA27493AE106C01C0

输入文件也在这里: http://filebin.ca/3DACc6lkf882/input.txt

编辑2:

以下是来自MFTrace的示例,其中包含一些额外的痕迹:

23816,3D70 10:43:31.09829 CKernel32ExportDetours::OutputDebugStringA @ ----------------------------------ProcessInput----------------------------------
23816,3D70 10:43:31.09832 CMFTransformDetours::ProcessInput @00000229F1932698 Stream ID 0, Sample @00000229F19D2160, Time 0ms, Duration 0ms, Buffers 1, Size 640B,
23816,3D70 10:43:31.09832 CMFTransformDetours::ProcessMessage @00000229F1932698 Message type=0x10000000 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, param=00000000
23816,3D70 10:43:31.09832 CKernel32ExportDetours::OutputDebugStringA @ GetOutputStatus says MFT_OUTPUT_STATUS_SAMPLE_READY
23816,3D70 10:43:31.09833 CKernel32ExportDetours::OutputDebugStringA @ GetInputStatus says does NOT accept data
23816,3D70 10:43:31.09834 CKernel32ExportDetours::OutputDebugStringA @ ----------------------------------ProcessOutput----------------------------------
23816,3D70 10:43:31.09834 CMFTransformDetours::ProcessMessage @00000229F1932698 Message type=0x10000000 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, param=00000000
23816,3D70 10:43:31.09835 CMFTransformDetours::ProcessOutput @00000229F1932698 failed hr=0xC00D6D72 MF_E_TRANSFORM_NEED_MORE_INPUT
23816,3D70 10:43:31.09835 CKernel32ExportDetours::OutputDebugStringA @ ProcessOutput needs more input
23816,3D70 10:43:31.09836 CKernel32ExportDetours::OutputDebugStringA @ GetInputStatus says MFT_INPUT_STATUS_ACCEPT_DATA

1 个答案:

答案 0 :(得分:3)

正如评论中所提到的,在花了一些时间使用代码后,我能够重现您报告的行为。但是,当我使用任意文件进行输入时也是如此。不可否认,我很惊讶地看到解码器报告的状态为MFT_OUTPUT_STATUS_SAMPLE_READY。因此,我同意Ben关于有效的AAC数据。

您可以简单地使用IMFSourceReader为您提供样本,而不是手动解析样本,这看起来类似于以下内容:

为简洁省略了ERROR检查

HRESULT configure_reader(IMFSourceReader *reader, IMFMediaType **resultingMediaType)
{
    HRESULT hr = S_OK;
    IMFMediaType *pcmMediaType = NULL;
    IMFMediaType *partialType = NULL;

    // Create a partial media type that specifies uncompressed PCM audio.
    hr = MFCreateMediaType(&partialType);
    hr = partialType->lpVtbl->SetGUID(partialType, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
    hr = partialType->lpVtbl->SetGUID(partialType, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);

    // Set this type on the source reader. The source reader will load the necessary decoder.
    hr = reader->lpVtbl->SetCurrentMediaType(reader,
                                             (DWORD) MF_SOURCE_READER_FIRST_AUDIO_STREAM,
                                             NULL,
                                             partialType);

    // Get the complete uncompressed format.
    hr = reader->lpVtbl->GetCurrentMediaType(reader,
                                             (DWORD) MF_SOURCE_READER_FIRST_AUDIO_STREAM,
                                             &pcmMediaType);

    // Ensure the stream is selected.
    hr = reader->lpVtbl->SetStreamSelection(reader,
                                            (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
                                            TRUE);

    if (resultingMediaType)
    {
        *resultingMediaType = pcmMediaType;
        (*resultingMediaType)->lpVtbl->AddRef(*resultingMediaType);
    }

    (void) pcmMediaType->lpVtbl->Release(pcmMediaType);
    (void) partialType->lpVtbl->Release(partialType);

    return hr;
}

// .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

void process_aac_audio()
{
    HRESULT hr = S_OK;
    IMFSourceReader *reader = NULL;
    hr = MFCreateSourceReaderFromURL(L"input.aac",
                                     NULL,
                                     &reader);

    IMFMediaType *pcm_media_type = NULL;
    hr = configure_reader(reader, &pcm_media_type);
    assert(pcm_media_type);

    DWORD total_bytes = 0;
    DWORD buffer_length = 0;
    BYTE *audioData = NULL;

    IMFSample *sample = NULL;
    IMFMediaBuffer *mediaBuffer = NULL;

    while (1)
    {
        DWORD dwFlags = 0;
        hr = reader->lpVtbl->ReadSample(reader,
                                        (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
                                        0,
                                        NULL,
                                        &dwFlags,
                                        NULL,
                                        &sample);

        if (FAILED(hr)) { break; }
        if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
        {
            printf("Type change \n");
            // TODO:
        }

        if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM)
        {
            printf("End of input file. \n");
            break;
        }

        if (sample == NULL)
        {
            printf("No sample \n");
            continue;
        }

        hr = sample->lpVtbl->ConvertToContiguousBuffer(sample, &mediaBuffer);
        hr = mediaBuffer->lpVtbl->Lock(mediaBuffer, &audioData, NULL, &buffer_length);
        // TODO: process buffer
        hr = mediaBuffer->lpVtbl->Unlock(mediaBuffer);
        audioData = NULL;

        total_bytes += buffer_length; // <-- update running total
        (void) sample->lpVtbl->Release(sample);
        (void) mediaBuffer->lpVtbl->Release(mediaBuffer);
    }

    if (sample)
        (void) sample->lpVtbl->Release(sample);

    if (mediaBuffer)
        (void) mediaBuffer->lpVtbl->Release(mediaBuffer);
}

在这种情况下,解码器已加载并用于直接传送PCM样本。您提供的文件(input.txt)失败,但其他有效的aac文件工作正常。

您可能正在处理流而不是文件。在这种情况下,请创建一个代码类似于以下内容的源:

HRESULT create_media_source(IMFByteStream *byteStream, IMFMediaSource **ppSource)
{
    MF_OBJECT_TYPE objectType = MF_OBJECT_INVALID;
    IMFSourceResolver* sourceResolver = NULL;
    IUnknown* source = NULL;

    HRESULT hr = MFCreateSourceResolver(&sourceResolver);
    hr = sourceResolver->lpVtbl->CreateObjectFromByteStream(sourceResolver,
                                                            byteStream,
                                                            NULL, // URL
                                                            MF_RESOLUTION_MEDIASOURCE,
                                                            NULL, // IPropertyStore
                                                            &objectType,
                                                            &source);

    // get the IMFMediaSource interface from the media source.
    hr = source->lpVtbl->QueryInterface(source, &IID_IMFMediaSource, ppSource);
    (void) sourceResolver->lpVtbl->Release(sourceResolver);
    (void) source->lpVtbl->Release(source);
    return hr;
}

但是,请注意CreateObjectFromByteStream需要一种方法来识别内容类型。您可以在字节流上实施IMFAttributes [具体GetAllocatedString]或传入网址