GetOutputStatus says output is ready, ProcessOutput says NEED_MORE_INPUT

4

I am getting stuck in this situation where I get conflicting information:

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;

Looking at the data media sample I've sent to processOutput to be filled in it simply writes a null terminator '\0' in the beginning of the buffer but otherwise it does not write any output.

GetOutputStatus

If the method returns the MFT_OUTPUT_STATUS_SAMPLE_READY flag, it means you can generate one or more output samples by calling IMFTransform::ProcessOutput.

...

After the client has set valid media types on all of the streams, the MFT should always be in one of two states: Able to accept more input, or able to produce more output.

I got no errors earlier while setting up the decoders input and output streams so Im thinking the streams should be good. And I've not got any warnings while sending in the input media either so Im thinking I should be in a valid state. But the behaviour does not seem to match what I think the documentation is suggesting. Also I only have 1 input and 1 output stream if that is of interest.

So how could this happen? I have conflicting information from the tool. Is the data ready but I am reading it wrong, or is there something else going on?

Edit:

There were a few comments asking for more information, and one asking for a minimum complete example so I decided to try it out. Below is a small c program that runs all the things I run and it simulates my environment by reading input from a file and sending it in the same way I am getting my data. I have striped out almost all error handling, removed helper functions and hardcoded a few things. This program reproduces the issue. I am running this in 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;
}

The "file.txt" references in the code should contain the following inserted as hex:

47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066200198800DE120000000000000000000000000000000000000000000001C47FC0000B090800300FF4A214DE73987D722230566AD966E80B72A99797BFFB7978EB3DB9E248875BA38E42B7924EF58A2CCC578931AE67157BF6E7E3DC51B70265C888DA8CB0074753F9F0F3EF9B0F70CD8D5B2363C3B9CE1275DE0E4E7313C6F88FC611D87A932D4263BDFB8C74B5E9052DD5046AF66EA3AB55F9E2186ABCC5A72A3664F1CA21CC678AC24CBECD3797D7C2C50B335556E7DF5E51E5BECBEA1337CA71ACB7ACFD9EDABE47139CB0695F8D575EAB0E461BB5336ED00E2F0F5F381CAD2E9E2C0750FAE43460E9B372CCD016EE6E5547FF4F89EBACF3BE2EA21D7E9038E190CA4D46DB54633FCB9331E830DC6AFB7A1325F0E79DD1C6D886320F8C728DAA34AD00CA999CC089702E7CD7FD8EDEB1FEFFAB63F8D9E798CD483BE697B314BF749F17967FE9F46688D45D8D6B926300840223B9AD2B7291B288518835BB2629B61D79EAB5760D16FBEA3B909D4E7F56747FC0000B090800300FFFFB4216BD505EE8504B0D098342810840D0AF6CCCD71DEADAD6EB2F7117B85CAE255CC5C39130EF0EA7A7F7565275CB6CCBB9E70843BA4847444976535677F95480D0AEC0D0A63F40F1BF7B645AB70307D0262A388BBB2DE0F90E12FF5B46A2EAEB1C8E85C50061833EF9324731B4F7D29580BE0FA0DFAB6AA78341FF25422B0A7039F64C34BA063763E54D489805ADE242371C3C865F17360ADFD3956E6A6AC18D8463879AC4FA70D0ADAC9C5E146F5BB6541F8ACB2EEA53D1EF35EB0ED715F7C4B9A1A072908A66CE92A76328E43010B3820EC9E255C388BC5DE3E02D1393EA9FC70CD44555DE9F6E419C20F804F0361AC702CFFBDD6DEC4BBF6C7736AA1F207CFFC9934E9DBF039FE469D1B2B50B4507E8F6326BA9BD42B71A1A7AE74D23FF1F89CDAF27D614D3C2F8AD767004AC2421E11D8B86B058DEF88EB9A9C8E8C35CF980D0A56664CF27385181987F7878D06AB6F7E46200764841CB0820195C383613579C8836BA8622C06DF3889D200773EDC28AF89E3656DEE0699E66DDB9E7070EFB96BB024F2B4155A9E7806649A8C00A383586956581A0602015141282C140B100CF358BE372EEF5B65E51ACDEB2EDC4A9ADAD00D10420408761E859304BCD8828E72EEEC4AD4219560E77946692F3C51EA9BE12AC6431DFF674CF94931D357B6EF90E912A3B9ED135C6D620EBF7D887A38CC78E67B543838ABA936E67848A2744AF716CB8955C1CE9FB4784271584E49DE019496B654C6B413D74AA09ACFDF68233F39F176931E10A093B0C47961BC72F87C31FC3EA92BF55438EB90345122D1DE3BA14653C459A53C0E5CA3D8ED1097DDD3D5DB39C645D5E07396C76131C03B329A3C98E65A19E63380B51105F21089088038309AE0E4A17C6D6D827D5D85FF804805BAFC4441580F7FE5872EC3DD9C9C00312022F67A4D40AF900D0A1A5427DA204E113C93931E9A0209F7CD2303102E9F674A3B2B706E47FC0000B090800300FFEA210BD5159E8F6982B1602C703386BC713BE1AA54E75B0BA9092E29726E03838C74AADE6D55F03227C9F0F84F90159F2C64D517A77D6F1D69258146F8A3397C3BBA296084B027A9E6581390F1A00E4A3A26E67944B2F09DDEF851344D3BF2DA8A8B11C1C00750A7B34A310D04481F02AE190D0A41F83BD088CE2ED2BE9FE1819099C7A22D5C6738C32DE20F2201D6A603A2082DA21D6A677E2E471044B72C64C6085C734BD1C8D9E1287E93A588C4BAFB075E0D0A3751BC5ED4009F7F7E2500A8394D0B3D0D0A18F9CA85996BB1651362C72A739DE23A9ECDCF6CE771C523B42CB0A698213E554967559681AB800574D36050440CA4D00E48AA71748E65F5CAF6BAF7B01A64803C453ED2093582B6236DDE26AB2B2BC500002A129D1A56FA19400000E22952C4AE3BA298876484D89D4A832819C4D733AF5E6BADCACAE37CA17624B936E2A77A0914FB393C13DB11C2EF9C7E039F0718E7FFA578FDD875ADE3B4F3FAB20CF08AC721C4182E60E5A2D4DBCDA1810F88D64ADDA7CAD3981ABD3AD8E114BD505EBD8D5D7CBC9967899697B38D411ABAE11B391718EE9BCFAB917196FCC2B910B9170351CBAEB97577CD6F1D3215B0E72EAC739176AEAD6009AEBF56B882BE32319DFDFD33D5F28BA0706BA273601740829B8BADCE4537BD6BEF9BE0F9D2CBE60884F9225109718E47FC0000B090800300FFCF210BD51DB18561A4C0D9683033CD5F8EB5EB55ABDC64ADD244B26A26489960D9D84969A878658210307F2D01CE29359116C0739E92EA87B35B0D0AD5F223F143BE0D5D6EB2B69CCACFDECB8C36B5D9B771E03295998B9A62498D887106EC5E918E0C30076F5ECE6403391363A62CB44CBB6EFFD74CAC0CF90D0A2ADDC490E2306145701D85B1A9CA12C258CB7D81532D99FA8DF3C7A1894357950D0A0C0B7CBDB8D297200CFAAD4AEBC92BBDEE087AA9BFF6A49C2B7A7BC66900EBD78F859330033EB9C009C649B8A0E99E774E3ACC0C01DED63CC2247BB5A3C857D2D50D73D92C5BD345ECB6E9A6FEC7000D0AC2F870CEA2AB20BE4057C9EF9922083AA2ED64350DB514A84A0405E3CE51B6FAE53316CBFA2C87B393C5CDAEFB9561FB12DEC4C75F3C69C876464D094EC255825E57DF5AED77158BAEE979A9AA4BBCE372507AA149F8A2108A682471F2BD48D3DDDA49E896AFEA79BBCBCB96E00759FB9E77B110866D32F8C3061C4655E056BF8FD5F0417D1BF296F735F0D682437F67D9BCC05D6E8BD6E725050C41133E9D9D3E76280444FC260D435C631302720B6EA53BE9E7B890405D4564310F7F2C48027535A15DF807777F1EEF7F57DC0BDBBB398004C1CC5D159991BDAB0373926719A000006A1C47FC0000B090800300FFDE210BD515B290C2A0C1944C741819E4E755755C632A537335ADAD2EF5544B5481F1B472C55D552D4982F5FF89A5E18B3853B70D0A6380EF43AED06FBE5510F067C8E66CC6E0568C614076560EDDA09A3150EC4091D6FFEC2D78A38EF6FD5D52D0DC9F2BD2F3DC2DF9FA413F130355403920A91E9D2FA1FBAF09A7C239059DF6D3A72B24E8B96340288C68DEB4D9D44E9D2DAB0D3F8BBF15CDA44D549DCF8345F55DC594A21615BD6128E17D700240980B9DE7FC2456E7B7D5A0999AAD8EEEFF8B970E78B5BC34559F98FBA90D9C28BE444F0D0A8DEC59EB7D38104926B66CAC98E8B6DD3E69A2BA899B77D4C002DAC600A5734B62A006A1886E511063F09E93ADF3800B8E1CEBC528B8630900AE86759E7D1F08DF9DE47E57E93EC05714FDAAC43FCF03E57A551D29094162A8506AA31021E738E784DB8DDF350E667536B3875554BD5609E7C846792B5B0D0AA9DCCACFB143A6AB0B087917695136C22505859DDFB9E2CF3FC73FBDBEE77C1E853B74A0C023755C2BBA329D4C1D0298AC33342083E328F7F6663D5403C12943925C1007AAD0789F0E429D909DE53DA00D0ADEE57C77A966388A04C096FE3D08E41189037D5C2F32D71C015B46F31DF3F1D6855556F7A9339D0D0ADB788178227218CEB505E03BB5C7EEAD6A0BC63CFF7E9F4F00DD1C47FC0000B090800300FFE6210BD50D9E936181B0A0AC270B1102C451019A943352D95553994D5EEEEA5EB55448342299BD823F916D8AE11EB398B2D5CEB34CFAD3B2818D3F9E30884B0D0AEC3A05147354117537040109F46A27CD52806C4279C1C3E9FD9F6620C3ABF2AD8702767FBE226C934BDCD0E2BBD40E4003136CB1A3CCFD951FB2D8E9DE5415B55384B798B48C32469B56B54506917A7627332D8C4FD7A85897697186EBFCEBBE26D3C6D94D107198D32BAC82FCD0B081BFF7B43C4D8CF9786BE3221B39DB69080052494AF6E6A310BB6D8A50A45AD99DC00D0AAD604E4169612A8E75F96CB437EBE93645816D58F03BF46FEA654056FBABAE703A4899000C90F7F748200D39BD4FF897B19092B0BA000066B80E8357461289899CAF12055C66FEBE9E118E572C4494A438208A0F45632A1022503349AC6F8BE32B19399249BBBA4EB46DAA258D847BADAF69EADE38B19AA09DBD707825ABFE12D1E74C88B545354477A140A7CF3E83A47350CCA0796ED91F102C2378BD91B2A8820D9C0430C8096CC6C007279AF9984B6EAAC420D41DC51656027437981BC26ADA054E2EC7F2E24AF461733B014002A18EEFB2635C38700D0A89F872EACE26AF3B019F86B15383BFC72075F52EBE1F0CE3BFF5E3AE75AE38C4CA402304400714037E466C2802534AF14B0600101370D000705BE2E047FC0000B090800300FFB6212BD4ED9E936182D0A08CB04353DEC47192B753BE0975256A5945A507ED211FBFABFBDFD8B7E5E14B401438D2ED27B9D8E7E30651A8224007FF029525ACBEC13E7B2D6503DC54CAA43A1E35D7D264D0DB50F3789F04142A8902C1D6E0ED0080C561CD098EA1EDED08A04A8EBA2993001374E57D54528315752B83C7116C3725458CB05078123B8D8F3CB6E0976FB8F0A914A051B66CE31EDF5153AD9A011948859002F1A81CA6529E33155B64EAE03D2599AB5A501F05A72EAB90002CC2FA2BAE2E929CC7659A8099E80D6B9E79CA3C6E40B8FC25B18C6D689E819DBB335A7405E539405ECEAA41395B6D315146F14C910D40EC95B768B86204D44640B5A806AAF52AC2DDD423CC4B4E108F5844E6235D051E16A18131548023200C44065F1F6B5E5DEB2F2B75BD5D59755ABBA55CB04027445D19A4858A1C48F732E11169DB549AEC4BE6E3910C01EB3DBF85B3585D7E4DCAD92DFBBCEF54298CE02321D79BA0DAB0010D88105387DFFF664000066AC6CCFABF22F7401899A064D249404E84C90B989B5405C6FB534842FA37DAAE4679C9B902EBA4675EEE5DADF46E00251781D8F6DC5D6BCE23F1FC2194128B1316D08805038047FC0000B090800300FFFF72214DDEFFFFFF3336A9B1A2D1C81B54A1DA62A80B8F112FA2FF1FF13779A9C4DDF41DBF58B878CF6840F504F3FED85D1608DE4BDA7D0748C2711E387AFD2C656A7C078531B2A9B2D5A7F07E8671F9E7E41B3ED4F031EE923A47C8FF0D0A94305B24B1CEEA67EC5A3A74EA9B6F7285B3C68E0FB587FE1A30DBFBD5170532508F2D095022535C81BAF3C8068A2E476984FA49121FB15851DE70AA3EDAC7A4F285AC068F1F39BC124BAB7BCBEDB59A0D0A7EAB05AEE759E63F48C64EEAB770833C3352FBCE1E417534B457F411155A5694BBA5D190B8C934CE6B5DF88DAB9777303994614BDDA9A50CBC15E0AFEC1F3DA00DEBBC25304658E57ACDCCFE743CCF2D97096C43ABBA3EFDA47676B38B3C7E308D54B45A3B8D8470BF98EFCED3C9D5A375EE4566E39C6807A0072BA6F9F19E8B25EFEA994AFFE67886B80DAFE0FBF9A26768E3D4EA63974BA55CB83B15CBBDD95E3D3007C2009000009AA31113136E40D46506CD162A80AF9893DB1AFDFFECABE78BE1BB807B20B5E81EF71CC44F05FBA36F78B60957374E4DA34C8A7A9236A3EF391BC15CD9ED7957AB2422E89444BCBAE7B93F9D6E23D8FA2DDEE93FAE64FB7FB824389C1F8096FA407C88C3081FE7CB3FEBCE03728C752131676EA6B105B4681D75368D4F245EE81EACF386076278C95924087B56FC0E2AD55F77A6A44B28A9B25AF286BEBD27226A18C2E2BA296FD959452A32E9231ACF2CEE5C050478175B83696AFAE0118C5984F3F724A329DCE25230C9ABA45FA9EADB6E64C57E9609F22B4D3E8651E60DDF127A6010A3320BA3D0BFA22D921572043923A011330D0A003A5A67F67D3F2FB39FFDFF0D0ACF6763F88F838C001F3CFD9D523FCDFB3B02F19000007047FC0000B090800300FFF2216BD4FDBE8D0E620840EC8BC78BDFD139EED7968BC6B495922D9438B20F89CE72499D90F50FD31ABA4B912523B81ABD5BC3F1AE5F9FF34E75F97E68E4876E1AE381C96FE987C9F366AB724F3C634CA9AA4A1E27758C5D5EA32DF47634CE4B8EAC1DA6522172C6BEF6B78B6C21A968325B87FA4B8C75DFC9AF7E3AD024A6D45DF651B19D99133869232C0CA24BEF0DA6CA2133CC0277D02C0FBD2104C9A58C22A45E6E0520C1A55DEE48AA9B600D0AEA6BEE37AE66ACB8DDE4E53C23D36D4448C397749D19F2B1E68428D0A7C57EB91A4860B12C4D69769DF1D4C69CD4D04F9D72934AB58E51072C4B09925BD7DA02259693C4C0FC25218F6A78216AA094DB7AA3619D6F9E696E7B25510006A6DC24FD5BDB1348F57C63CAB3DF759729524CEF7E40014C5637D7AE61000322198D20A41142EC4C45431504650433AAD667339FAB5F7DC6B22D2AB8D456EEA5B63493B898F6DF0F70DD916C86A6D462BB14C15C776CF8EDA49868E510773CC69988D806E1870859E0B344AB8F1B6C3BFE417BF7E9884F2128F5F4DC3B63E1238E6312D76F2E8E576057340BD2E2A4ADD6484457609AA80209CD4DBE126F9A509DD011A9FA7DBD617DCF84B948BB7B616CEFDBE094B829D525FBCA7B2582A52421BAA94AC8A8A667836D98C5D5711A92FFE8B8F97433278764D5D5D597F7BE5013C0CD605C1C47FC0000B090800300FFC2210BD50DBA0D618431602A200B04C40656A92FD4DF152AAAEB591245A242AAED06E8F0672C5946157169B9AB6ACB4F1866BA4137814BE13F05A2411098969DCFF61E40B4BE944463971C375920B2BEBF3A52F0E2D1869C9A888FA900465D2C74FC76F45CA4CE0D0A140D0A695E04899CC9250D0A8F80C42290A86140C5B248EC8EB7392B6E14215BF0C9CA0341490623A1391B0D914C92E7395009A2E15134A7125C2557891339CE05826194D5D4EDAC6B192FF34B8600071E6E14E38CD3852EEEB194F2D963C817DF43D0C0E0FA9128E525AF7A10B9257719C014437538E585FC4A8F51E58128CCBE659EF01E420D0A1A6AFDDE784FA351F1AFD5009DF4FB669871E7BA8C8A2CD84E5DC355583B2A7A9F0FD2DE041D1BA072F00292D30563A2D4802108215EDB8E3F4D6F52AEB76D622D5A45CBCCAE01AC8707447199D2B8193647757C0014E4BC4E8DD9D251E0755086332FE1E122E318533919E1171A85F17DEC4B7F30EA40005ECF1322EF9705A2DADB354EF0D71653C09BA5771CF866F6B4692BFB53A20D0A36ED3BD63B5397E1AB1C76A6066610535CEC5857AA165F8A3BDE3AFE62C14540A8AFF1CAFD7351D7638E0D0AFE577D1B1753015C98CF3AD1588056C07EF11C47FC0000B090800300FFFF14210BD51DD612C2A238A04A1032F86DAF9E39F6BEEF61256A2492AE5A492E507266D8A485B1C91050CF618CD9D24CE9422880B92E969794BD6EE21043A9B997E8E5D02CAD01D5EDFCD8B871220B37D4CE28394314B723411472F6DA23E15CA10D66D7147D38C0B31AF672573349490915B6D97078FB5216D535437AFA64A678C4507414C17AE5E54217F0928AE120AA4785CF3F2AFE23CE722FEC6DAF8231ECE7B282285F116A70137C711FA2C90995AE22233874438CA69F0827AC2318B4DB7DD3825F4DCD72EFCA13BEECA7B33B500C24F86B032995348674CDE93D20D28DC69B44836A2268C6383600AD36D5EC1C7BEC2C0513E4629551BA966ADF93A8F5685BEEAF417384CBA8556AA4C9C797361D1FF6F65CAF91AA2A7180000D0AECFCF8A27CB9FCBB33CA6E75A45F9A5D5566D68ED32A7169E09938465DC13D5FF9F6F1C635A8AF3F648535B98D4154A08C4C15080982A2032FE3337AED5ED399CD5E5D719A8BAB9BE2173A6034F9A257E49449860F1F3234D1E7A7C1FA3154C6FC7C53088642EC3B6454AAE6AFB85BA6A3437CBE2624C9CDC9D46A9C00CAC1300557BF14621033ED6CCE4F846AB973EBF9F216D31DFC2A6205E3B65BF0EC84AFBF58E701778C6E78EF8004EE98EBEF8ADEFF856C00089D7AAD2B65E220AFE016A1473108E0CE9461F75AEAE24B9753B810A8C348A9870D7373F8FB3AFEE07C3521BFCCF7E51132B76548165BFAB62A73300FBF40003847FC0000B090800300FFFF1F210BD51DC6890761C0E84A281819D5E7377DB9F3795855CBA5DDB24BB9217C503B377F9A2BEC89E1CFC791C41158ED857519F6B98E872BBEA9B614500C6FCF7E468CB64F31AE089CDE696E45B29D9F3874F083E36F6AA0CA5F849622858B8F4153CB0721ABACB0FCF4B0A209E092CB70A10D0AC689F786783E85E022E8E02D4CC2AC1AE0984E701926788007936A163026CEC02DA74C159B3AB81003236120A2630E9E85980966AF95D712FAEBCA35EF9F4918972FF646A17B757FB28F2A67007C26B281C925832AE31703971AC6C931F10CD6DACABB61D49A8BF071B4947D952A33789A89A54C5757C1DF155B58C62BE42982A928E8ACE39C75DA8B0D2F0B518C7D975D846EC28236543C505AFB3D7ECA81A80000673F2EBE8DECEDFDFACAD8AB7AE33B43B2F05E722499D77A4D223A2DF7DC42437AC0B03D271F05379CE739CEA7B4B1A82C210D894C8452889828103BDB59BBBEF3BF699372A389556E1BB6AE495E3DBCE02863569A20106734826201CEDD6DBF328E8EA8E13833AFA5CE678A43ECACAE056F438204DE3F666ACC594CF22AC0A0238671CB13CA31BBEF5D1E38EC8CEFA372BA8EF29CB1EA825590EEC95BE0AB98BC4DFBFA60C7DFD18CA5FD6F1D94832B9D4A2F46EB40E777B2C321FC8BE45BBD477B3BFE94D7BFABB61DDDE62B2F679F007BB8ED7ACFD9D5C7D935F1E9E3FE9F1800AFEDF1FFAFE5F672FF3DE2FE50E7B83AFA400004B8275F20987F35768CCDAEE5D92358534EF57847FC0000B090800300FFE9210BD525A68D6181D098B4180B0E02C451308C20679BA6FCFBD73E655EF6B8B2692A4B092F554152C8CC9205E29FA1F9D772C440C559DA53E5DFD1398ACB4BE64512620F63F0F92B20EEC15947AB0E2032125AE3D054070D0A7FF21BED4335F82519E41E12FF8F0051C5B625EFCA1005A8AEBEFF8DE407E4DB9655E7ECB95ED8C7CB496524916480007916D9278CC3EBC697721DFF0D0869C9A008D1326C2993079D09DCB1D3D0AB84EF3ED249260EDBB1F2C37F7F6D7A3BBB6E69EF7291A667BAAAD6B918D4A92544E23A89B38AA35E781A4BEA47FAEFD482A873DD4D7CE903BB5C9B7826170537DD2C9D293450B2E49701CCE49E9CFE1DDF8D98C4700B9808559CD6F7BE9E000D01A4B1F4FA8B8787C3FCF282FAD6CCDC960542EB9CF77D5D75DC63F7AF27A51920A741D9A156250D0A115402408880CEA5CBBF9DEFCDE71CF3347189C52AEB8CB2BE302116B6FAA464C548A09BF3AC27F9AC0093C55F0004D671C4A53924BB758CF48C9F302A31E1B0E340339630896052D4E6D2C418E38203E952003C4B7F9635A743DE4D2C284D206EA7E25CEB9AAAD095F1306F11D7F2FE5323ABBE05EFBE031D2D467BF711A847074702B60B910C639FB30BC600066000DF8F6856EEE57D3C2B35BDCEBBFAD20365E9598E8854AB6361A0790B5FE6DB3F2DA27493AE106C01C0

The input file is also here: http://filebin.ca/3DACc6lkf882/input.txt

Edit 2:

Here is a sample from the MFTrace with some extra traces put in there:

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
c
winapi
ms-media-foundation
asked on Stack Overflow Feb 20, 2017 by Alex Telon • edited Feb 28, 2017 by Alex Telon

1 Answer

3

As mentioned in the comments, after spending a bit of time with your code, I was able to reproduce the behavior you reported. However, this was also true when I used arbitrary files for input. Admittedly, I was surprised to see that the decoder reported a status of MFT_OUTPUT_STATUS_SAMPLE_READY. Therefore, I agree with Ben regarding valid AAC data.

Instead of parsing the samples manually, perhaps you could simply use an IMFSourceReader to provide the samples for you, which would look similar to the following:

ERROR checking omitted for brevity

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);
}

In this case the decoder was loaded and employed for you to deliver PCM samples directly. The file you provided (input.txt) failed, however other valid aac files worked fine.

You may be dealing with a stream instead of a file. In that situation, create a source with code similar to the following:

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;
}

However, note that CreateObjectFromByteStream needs a way to identify the content type. You can either implement IMFAttributes [specifically GetAllocatedString] on your byte stream or pass in a URL

answered on Stack Overflow Feb 24, 2017 by Jeff

User contributions licensed under CC BY-SA 3.0