Windows Media Encoder SDK - Выяснение того, когда преобразование выполнено в собственном C ++ - PullRequest
0 голосов
/ 26 сентября 2011

Я использую Windows Media Encoder SDK для преобразования файлов WAV в формат WMA. Это работает довольно хорошо, НО у меня огромная проблема с определением, когда процесс завершен ... Забавно, что я использовал части кода из самого SDK для получения уведомлений об этом, но они, похоже, не работают ... :( Вот кусок моего кода:

class CCallBack : public IDispEventImpl< EVENT_ID, //Thsi is sth I got from the SDK
    CCallBack,
    &DIID__IWMEncoderEvents,
    &LIBID_WMEncoderLib,
    LIB_VERMAJOR, 
    LIB_VERMINOR >
{
private:
    WMENC_ENCODER_STATE m_enumState;
    WMENC_SOURCE_STATE  m_enumSrcState;

public:
    // Define the event sink map which determines the events
    // that the application receives.
    BEGIN_SINK_MAP( CCallBack )
        SINK_ENTRY_EX( EVENT_ID, 
        DIID__IWMEncoderEvents,
        DISPID_ENCODEREVENT_STATECHANGE,
        OnStateChange )
        SINK_ENTRY_EX( EVENT_ID,
        DIID__IWMEncoderEvents,
        DISPID_ENCODEREVENT_SRCSTATECHANGE,
        OnSourceStateChange )
    END_SINK_MAP()

    // Implement the event handler for the OnStateChange event.
    STDMETHOD( OnStateChange )( WMENC_ENCODER_STATE enumState )
    {
        m_enumState = enumState;
        return S_OK;
    }

    // Implement the event handler for the OnSourceStateChange event.
    STDMETHOD( OnSourceStateChange )( WMENC_SOURCE_STATE enumState,
        WMENC_SOURCE_TYPE enumType,
        short iIndex,
        BSTR bstrSourceGroup )
    {
        m_enumSrcState = enumState;
        return S_OK;
    }

    // Override the base class virtual function to provide information
    // on the implemented event handlers.
    HRESULT GetFuncInfoFromId( const IID& iid, DISPID dispidMember,
        LCID lcid, _ATL_FUNC_INFO& info )
    {
        if( InlineIsEqualGUID( iid, DIID__IWMEncoderEvents ) )
        {
            info.cc = CC_STDCALL;
            info.vtReturn = VT_ERROR;
            switch( dispidMember )
            {
                // Descibe the parameters of the
                // OnStateChange event handler.
            case DISPID_ENCODEREVENT_STATECHANGE:
                info.nParams = 1;
                info.pVarTypes[0] = VT_I4;
                return S_OK;

                // Describe the parameters of the
                // OnSourceStateChange event handler.
            case DISPID_ENCODEREVENT_SRCSTATECHANGE:
                info.nParams = 4;
                info.pVarTypes[0] = VT_I4;
                info.pVarTypes[1] = VT_I4;
                info.pVarTypes[2] = VT_I2;
                info.pVarTypes[3] = VT_BSTR;
                return S_OK;

            default:
                return E_FAIL;
            }
        }
        return E_FAIL;
    }

    // Link the events to the encoder instance.
    HRESULT CCallBack::Init( IWMEncoder* pEncoder )
    {
        if( pEncoder == NULL )
            return E_FAIL;

        HRESULT hr = DispEventAdvise( pEncoder );
        if( FAILED( hr ) ) 
        {
            // TODO: Handle failure condition.
        }
        return hr;
    }

    // Detach the event sink from the encoder instance.
    HRESULT CCallBack::Shutdown( IWMEncoder* pEncoder )
    {
        if( pEncoder == NULL )
            return E_FAIL;

        HRESULT hr = DispEventUnadvise( pEncoder );
        if( FAILED( hr ) ) 
        {
            // TODO: Handle failure condition.
        }
        return hr;
    }

    // Private member variable access functions.
    WMENC_ENCODER_STATE State() { return m_enumState; }
    WMENC_SOURCE_STATE SrcState() { return m_enumSrcState; }

    CCallBack() { _asm nop }
};

void Do() // This is my code...
{
        // Declare variables.
        HRESULT hr;
        IWMEncoder2* pEncoder = NULL;
        IWMEncSourceGroupCollection* pSrcGrpColl = NULL;
        IWMEncSourceGroup2* pSrcGrp = NULL;
        IWMEncSource* pSrcAud = NULL;
        IWMEncAudioSource* pAudSrc = NULL;
        IWMEncAudienceObj* pAudnc = NULL;
        IWMEncFile2* pFile = NULL;
        IWMEncAttributes* pAttr = NULL;
        IWMEncDisplayInfo* pDispInfo = NULL;
        IErrorInfo* pIErr = NULL;
        IWMEncStatistics* pStatistics = NULL;
        IWMEncFileArchiveStats* pFileArchiveStats = NULL;
        IWMEncOutputStats* pOutputStats = NULL;
        CComBSTR bstrName;
        long lCount = 0;
        CString str;
        CCallBack EventSink;


        // Retrieve a pointer to an IWMEncoder2 interface.
        hr = ::CoCreateInstance(CLSID_WMEncoder, NULL, CLSCTX_INPROC_SERVER, IID_IWMEncoder2, (void**) &pEncoder);
        if ( FAILED( hr ) ) goto ERR;

        hr = EventSink.Init( pEncoder );
        if( FAILED( hr ) ) goto ERR;

// Retrieve the source group collection.
        hr = pEncoder->get_SourceGroupCollection(&pSrcGrpColl);
        if ( FAILED( hr ) ) goto ERR;

        // Add a source group to the collection.
        hr = pSrcGrpColl->Add(CComBSTR("SG_1"), (IWMEncSourceGroup**)&pSrcGrp);
        if ( FAILED( hr ) ) goto ERR;

        hr = pSrcGrp->AddSource(WMENC_AUDIO, (IWMEncSource**)&pAudSrc);
        if ( FAILED( hr ) ) goto ERR;

        if(m_cComboContentType.GetCurSel()==0) hr = pAudSrc->put_ContentMode(WMENC_AUDIOCONTENT_NO_MODE);
        else if(m_cComboContentType.GetCurSel()==1) hr = pAudSrc->put_ContentMode(WMENC_AUDIOCONTENT_SPEECH_MODE);
        else if(m_cComboContentType.GetCurSel()==2) hr = pAudSrc->put_ContentMode(WMENC_AUDIOCONTENT_MIXED_MODE);
        else hr = pAudSrc->put_ContentMode(WMENC_AUDIOCONTENT_NO_MODE);
        if ( FAILED( hr ) ) goto ERR;

        {
            int val = m_cCheckBoxUseTwoPassEnc.GetCheck();
            //int val = ((CButton*)GetDlgItem(IDC_CHECK1))->GetState();
            if(val==BST_CHECKED) hr = pAudSrc->put_PreProcessPass(1);
            else hr = pAudSrc->put_PreProcessPass(0);
            if ( FAILED( hr ) ) goto ERR;
        }

        // Add audio source to the source group.
        hr = pAudSrc->SetInput(CComBSTR("D:\\WAVs\\recording_015.wav"));
        if ( FAILED( hr ) ) goto ERR;

        hr = pEncoder->get_File((IWMEncFile**)&pFile);
        if ( FAILED( hr ) ) goto ERR;

        hr = pFile->put_LocalFileName(CComBSTR("C:\\Users\\Ghost\\Desktop\\OutputFile_+8.wma"));
        if ( FAILED( hr ) ) goto ERR;

        // Set the profile in the source group.
        hr = pSrcGrp->put_Profile(CComVariant(/*(IWMEncProfile*)*/pPro2));
        if ( FAILED( hr ) ) goto ERR;

        hr = pPro2->Validate();
        if ( FAILED( hr ) ) goto ERR;

        // Start the encoding process.
        hr = pEncoder->PrepareToEncode(VARIANT_TRUE);
        if ( FAILED( hr ) ) goto ERR;

        pEncoder->put_AutoStop(VARIANT_TRUE);

        hr = pEncoder->Start();
        if ( FAILED( hr ) ) goto ERR;

        hr = pEncoder->get_Statistics(&pStatistics);
        if ( FAILED( hr ) ) goto ERR;

        WMENC_ENCODER_STATE enumCurState = WMENC_ENCODER_PAUSING;
        WMENC_ENCODER_STATE enumPrvState;
        MSG msg;

        while( TRUE )
        {
            // In order for the events to be triggered correctly,
            // the windows message queue needs to be processed.
            while(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }

            enumPrvState = enumCurState;
            enumCurState = EventSink.State();
            if( EventSink.SrcState() == WMENC_SOURCE_STOP )
                enumCurState = WMENC_ENCODER_STOPPED;

            if( enumCurState != enumPrvState )
            {
                switch ( enumCurState )
                {
                case WMENC_ENCODER_STARTING:
                    // TODO: Handle encoder starting state.
                    break;

                case WMENC_ENCODER_RUNNING:
                    // TODO: Handle encoder running state.
                    break;

                case WMENC_ENCODER_PAUSING:
                    // TODO: Handle encoder pausing state.
                    break;

                case WMENC_ENCODER_PAUSED:
                    // TODO: Handle encoder paused state.
                    break;

                case WMENC_ENCODER_STOPPING:
                    // TODO: Handle encoder stopping state.
                    break;

                case WMENC_ENCODER_STOPPED:
                    // TODO: Handle encoder stopped state.
                    goto EXIT_WAIT;

                case WMENC_ENCODER_END_PREPROCESS:
                    // TODO: Handle encoder end preprocess state.
                    break;
                }
            }
        }
EXIT_WAIT:
        hr = EventSink.Shutdown( pEncoder );
        if ( FAILED( hr ) ) goto ERR;

//      for(;;)
//      {
//          MSG msg;
//          while(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
//          {
//              TranslateMessage(&msg);
//              DispatchMessage(&msg);
//          }
// 
//          pStatistics->get_StreamOutputStats(WMENC_AUDIO, 0, 1, (IDispatch**)&pOutputStats);
//          if ( FAILED( hr ) ) goto ERR;
//          pStatistics->get_FileArchiveStats((IDispatch**)&pFileArchiveStats);
//          if ( FAILED( hr ) ) goto ERR;
//          WMENC_LONGLONG Dur;
//          pFileArchiveStats->get_FileDuration(&Dur);
//          long Dur2;
//          pAudSrc->get_Duration(&Dur2);
//          if ( FAILED( hr ) ) goto ERR;
//          WMENC_ENCODER_STATE EncState;
//          pEncoder->get_RunState(&EncState);
//          if ( FAILED( hr ) ) goto ERR;
//          WMENC_ARCHIVE_STATE ArchState;
//          pEncoder->get_ArchiveState(WMENC_ARCHIVE_LOCAL, &ArchState);
//          if ( FAILED( hr ) ) goto ERR;
//          if(ArchState == WMENC_ARCHIVE_STOPPED && EncState == WMENC_ENCODER_STOPPED)
//          {
//              break;
//          }
//          Sleep(2000);
//      }

        AfxMessageBox(_T("DONE !"));
        goto END;
ERR:
        ReportError();
END:
        // Release pointers.
        ComFree(pSrcGrpColl)
        ComFree(pSrcGrp)
        ComFree(pStatistics)
        ComFree(pFileArchiveStats)
        ComFree(pAudnc)
        ComFree(pIErr)
        ComFree(pFile)
        ComFree(pSrcAud)
        ComFree(pAttr)
        ComFree(pDispInfo)
        ComFree(pEncoder)
}

Состояние кодировщика переходит в WMENC_ENCODER_RUNNING и остается неизменным навсегда ... Как вы, наверное, видите, я пробовал оба: pEncoder-> get_RunState (& EncState); ... и Event Sink, который предлагает SDK. Тем не менее, кажется, ничего не работает ... Идеи кому-нибудь?

Другая проблема, которой я был бы рад, что вы могли бы помочь, состоит в том, что, когда я устанавливаю объект IWMEncAudioSource для использования двухпроходной кодировки, это не так. Код для этого выше, где я делаю:

pAudSrc->put_PreProcessPass(1);
...