我使用 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); ...以及 SDK 建议的事件接收器。然而,似乎没有任何工作......有想法吗?
我很高兴您能提供帮助的另一个问题是,当我将 IWMEncAudioSource 对象设置为使用两遍编码时,它不会。上面的代码是我做的:
pAudSrc->put_PreProcessPass(1);