2013-05-15 4 views
0

Я пытаюсь использовать Media Foundation Transforms для преобразования аудиопотока HE-AAC (полученного live555, RTP-библиотекой) в PCM (для воспроизведения через API waveOutXxx Win32). Однако в настоящее время я обрабатываю предварительно записанные пакеты.IMFTransform :: ProcessOutput возвращает MF_E_TRANSFORM_STREAM_CHANGE для HE-AAC -> PCM

Когда я звоню IMFTransform::ProcessOutput, он возвращает MF_E_TRANSFORM_STREAM_CHANGE. Документация для этого в _MFT_PROCESS_OUTPUT_STATUS указывает, что я должен определить правильный тип streamType и снова вызвать IMFTransform::SetOutputType.

Однако, я не могу определить, какие правильные параметры для SetOutputType.

Для справки, описание RTSP потока является

m=audio 0 RTP/AVP 97 
a=rtpmap:97 mpeg4-generic/16000/1 
a=fmtp:97 streamtype=5; profile-level-id=15; mode=AAC-hbr; config=1408; 
    sizeLength=13; indexLength=3; indexDeltaLength=3; profile=1; bitrate=32000; 

Мой код (извините за длину, обработка ошибок удалены для краткости)

static IMFMediaType *s_inputMediaType; 
static IMFMediaType *s_outputMediaType; 
static IMFTransform *s_transform; 
static DWORD   s_outputSampleSize; 

static void InitMFT() 
{ 
    HRESULT res; 
    res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); // probably should use threaded in production 
#if 0 
    res = MFCreateMediaType(&inputMediaType); 
    res = MFCreateMediaType(&outputMediaType); 

    res = inputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio); 
    res = inputMediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC); 
    res = inputMediaType->SetUINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 15); 
    res = inputMediaType->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 1); // Audio Data Transport Stream 

    res = outputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio); 
    res = outputMediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM); 
    res = outputMediaType->SetUINT32(MF_MT_SAMPLE_SIZE, 2); 
    res = outputMediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, 2); 
    res = outputMediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8 * 2); 
    res = outputMediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 8000); 
    res = outputMediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 8000 * 2 *2); 
#endif 
    CLSID *clsids = NULL; 
    UINT32 clsidCount=0; 

    MFT_REGISTER_TYPE_INFO inputType = {MFMediaType_Audio, MEDIASUBTYPE_MPEG_HEAAC}; // WAVE_FORMAT_MPEG_HEAAC can't be searched for 
    MFT_REGISTER_TYPE_INFO outputType = {MFMediaType_Audio, WAVE_FORMAT_PCM};   // MEDIASUBTYPE_PCM doesn't exist (but can be search for if created) 

    res = MFTEnum(MFT_CATEGORY_AUDIO_DECODER, 0, 
        &inputType, 
        NULL, /* &outputType, */ // search fails if outputType is not NULL 
        NULL, &clsids, &clsidCount); 

    ListTranscoders(clsids, clsidCount); 

    res = CoCreateInstance(clsids[0], NULL, CLSCTX_ALL, IID_PPV_ARGS(&s_transform)); 

    /* GetStreamCount and GetStreamIDs always return E_NOTIMPL */ 
    DWORD inputCount; 
    DWORD outputCount; 
    res = s_transform->GetStreamCount(&inputCount, &outputCount); 

    DWORD inputIDs[16]; 
    DWORD outputIDs[16]; 

    res = s_transform->GetStreamIDs(inputCount, inputIDs, 
            outputCount, outputIDs); 

    res = s_transform->GetInputAvailableType(0, 0, &s_inputMediaType); 
    res = s_transform->SetInputType(0, s_inputMediaType, 0); 

    res = s_transform->GetOutputAvailableType(0, 1, &s_outputMediaType); // 1 here is because PCM outputer is the second output offered in ListTranscoders 
    res = s_transform->SetOutputType(0, s_outputMediaType, 0); 

    MFT_OUTPUT_STREAM_INFO outputStreamInfo; 
    res = s_transform->GetOutputStreamInfo(0, &outputStreamInfo); 
    s_outputSampleSize = outputStreamInfo.cbSize; 

    GUID inputCodec; 
    GUID outputCodec; 

    res = s_inputMediaType ->GetGUID(MF_MT_SUBTYPE, &inputCodec); 
    res = s_outputMediaType->GetGUID(MF_MT_SUBTYPE, &outputCodec); 

    CoTaskMemFree(clsids); 
} 

/* 
http://msdn.microsoft.com/en-us/library/bb530106%28v=vs.85%29.aspx 
http://msdn.microsoft.com/en-us/library/bb530123%28v=vs.85%29.aspx 
*/ 

void ProcessData(const void* inputData, DWORD inputSize, 
         void* outputData, DWORD &outputSize) 
{ 
    HRESULT   res; 
    IMFSample  *pSample; 
    IMFMediaBuffer *pBuffer; 
    BYTE *pData = NULL; 

    /**** Create an input sample buffer, from the supplied data ****/ 
    res = MFCreateSample(&pSample); 
    res = MFCreateMemoryBuffer(inputSize, &pBuffer); 
    res = pBuffer->Lock(&pData, NULL, NULL); 
    memcpy_s(pData, inputSize, inputData, inputSize); 
    res = pBuffer->SetCurrentLength(inputSize); 
    res = pBuffer->Unlock(); 
    res = pSample->AddBuffer(pBuffer); 

    /**** Create output buffer ****/ 
    IMFSample  *pOutputSample; 
    IMFMediaBuffer *pOutputBuffer; 

    res = MFCreateSample(&pOutputSample); 
    res = MFCreateMemoryBuffer(s_outputSampleSize, &pOutputBuffer); 
    res = pOutputSample->AddBuffer(pOutputBuffer); 

    MFT_OUTPUT_DATA_BUFFER outputDataBuffer; // can be an array 
    outputDataBuffer.dwStreamID=0; 
    outputDataBuffer.pSample=pOutputSample; 
    outputDataBuffer.dwStatus=0; 
    outputDataBuffer.pEvents = NULL; 

    DWORD outputStatus=0; 

    /*** Process the data, and get it back ****/ 
    res = s_transform->ProcessInput(0, pSample, 0); 
    res = s_transform->ProcessOutput(MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER, 
            1, &outputDataBuffer, &outputStatus); 


    if (res==MF_E_TRANSFORM_STREAM_CHANGE) 
    { 
     // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815%28v=vs.85%29.aspx 
     // indicates that the output always changes 
     // but not how to handle it 

     /* GetStreamCount and GetStreamIDs always return E_NOTIMPL */ 

     DWORD inputCount; 
     DWORD outputCount; 
     res = s_transform->GetStreamCount(&inputCount, &outputCount); 

     DWORD inputIDs[16]; 
     DWORD outputIDs[16]; 

     res = s_transform->GetStreamIDs(inputCount, inputIDs, 
             outputCount, outputIDs); 

     res = s_transform->GetInputAvailableType(0, 0, &s_inputMediaType); 
     res = s_transform->SetInputType(0, s_inputMediaType, 0); 

     res = s_transform->GetOutputAvailableType(0, 1, &s_outputMediaType); // 1 here is because PCM outputer is the second output offered 
     res = s_transform->SetOutputType(0, s_outputMediaType, 0); 
    } 

    /**** Extract converted audio from the sample ****/ 
    DWORD dwNumOutputBuffers, i; 
    res = outputDataBuffer.pSample->GetBufferCount(&dwNumOutputBuffers); 

    for(i=0; i<dwNumOutputBuffers; i++) 
    { 
     IMFMediaBuffer *outputBuffer; 
     res = outputDataBuffer.pSample->GetBufferByIndex(i, &outputBuffer); 
     BYTE *outData; 
     DWORD outDataLen = 0; 

     res = outputBuffer->Lock(&outData, NULL, &outDataLen); 

     memcpy(outputBuffer, outData, outDataLen); 

     res = outputBuffer->Unlock(); 
    } 

    /* TODO: Release any neccessery references */ 
} 
+0

Я полагаю, вы не должны делать 'SetInputType' после получения' MF_E_TRANSFORM_STREAM_CHANGE', MSDN не предлагает вам это делать. Вместо этого, имея уже установленный тип входного носителя и внутреннее состояние MFT, как есть, проверьте, какой тип вывода он рекламирует как доступный. Я полагаю, он хочет, чтобы вы меняли выход, потому что нужно изменить частоту дискретизации или количество каналов. –

ответ

0

Я делаю очень похожи вещь. Вы должны сделать установить тип выхода, в противном случае ваш следующий ProcessInput даст вам MF_E_TRANSFORM_TYPE_NOT_SET,

Вы должны также продувку декодер, в противном случае ваш следующий входной процесс будет возвращать MF_E_NOTACCEPTING. Работа с вашего кода, я получил его на работу, удалив Рез входного набора типа добавляющий после этой строки

res = s_transform->GetOutputAvailableType(0, 1, &s_outputMediaType); // 1 here is because PCM outputer is the second output offered 
    GUID outputCodec; 
    res = s_outputMediaType->GetGUID(MF_MT_SUBTYPE, &outputCodec); 
    if (outputCodec == MFAudioFormat_PCM){ 
     printf("\nDecoder Output is expecting pcm format");     
     res = s_transform->SetOutputType(0, s_outputMediaType, 0);//setting the type again 

    } 
    if (outputCodec == MFAudioFormat_Float){ 
     printf("\nDecoder Output is expecting float pcm format"); 
    } 
    s_transform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH,NULL);   

    return res;//no output coming get another input to process. 

Для тестирования я использовал образцы, которые пришли от читателя источника к хорошему файлу. Обязательно сыграйте много пакетов, так как некоторые пакеты, содержащие «тихий», могут быть короткими и все 0.

Кроме того, таким образом URL http://msdn.microsoft.com/en-us/library/windows/desktop/ff485864%28v=vs.85%29.aspx прекрасно определяет, как настроить вывод. Это очень полезно.

Чтение близко http://msdn.microsoft.com/en-us/library/windows/desktop/dd742784%28v=vs.85%29.aspx вы можете заметить, что некоторые из атрибутов (MF_MT_AUDIO_BITS_PER_SAMPLE) на входе типа носителя сказать декодер, как выход должен быть отформатирован. Если вы можете более точно указать желаемый ввод и вывод, вы можете избежать изменения потока. Вместо этого ваш первый образец может быть MF_E_TRANSFORM_NEED_MORE_INPUT.

+0

Спасибо за ваш ответ, однако я больше не работаю над этим кодом. Это может быть полезно для следующего человека, который застрял в этой области. – CSM

 Смежные вопросы

  • Нет связанных вопросов^_^