CPI_Player_Engine.c
上传用户:tuheem
上传日期:2007-05-01
资源大小:21889k
文件大小:21k
- #include "stdafx.h"
- #include "globals.h"
- #include "CPI_Player.h"
- #include "CPI_Player_Messages.h"
- #include "CPI_Player_CoDec.h"
- #include "CPI_Player_Output.h"
- #include "CPI_Equaliser.h"
- typedef struct __CPs_PlayerContext
- {
- CPs_PlayEngine* m_pBaseEngineParams;
- CPs_CoDecModule m_CoDecs[CP_CODEC_last+1];
- CPs_OutputModule m_OutputModules[CP_OUTPUT_last+1];
- CPs_OutputModule* m_pCurrentOutputModule;
- BOOL m_bOutputActive;
- DWORD m_dwCurrentOutputModule;
- int m_iInternalVolume;
- int m_iLastSentTime_Secs;
- int m_iLastSentTime_Proportion;
- int m_iProportion_TrackLength;
- int m_iOpenDevice_Freq_Hz;
- BOOL m_bOpenDevice_Stereo;
- BOOL m_bOpenDevice_16bit;
- CPs_EqualiserModule m_Equaliser;
- } CPs_PlayerContext;
- void UpdateProgress(CPs_PlayerContext* pContext);
- void EmptyOutputStream(CPs_PlayerContext* pContext);
- void StartPlay(CPs_CoDecModule* pCoDec, CPs_PlayerContext* pContext);
- void EnumOutputDevices(CPs_PlayerContext* pContext);
- CPs_CoDecModule* OpenCoDec(CPs_PlayerContext* pContext, const char* pcFilename);
- void CleanupCoDecs(CPs_PlayerContext* pContext);
- void SetCurrentOutputModule(CPs_PlayerContext* pContext, CPs_OutputModule* pNewOuputModule, BOOL* pbForceRefill);
- void AssociateFileExtensions(CPs_PlayerContext* pContext);
- ////////////////////////////////////////////////////////////////////////////////
- DWORD WINAPI CPI_Player__EngineEP(void* pCookie)
- {
- BOOL bTerminateThread = FALSE;
- HRESULT hr_ComState;
- CPs_PlayerContext playercontext;
- playercontext.m_pBaseEngineParams = (CPs_PlayEngine*)pCookie;
- playercontext.m_bOutputActive = FALSE;
- playercontext.m_iProportion_TrackLength = 0;
- playercontext.m_iLastSentTime_Secs = -1;
- playercontext.m_iLastSentTime_Proportion = -1;
- playercontext.m_iInternalVolume = 100;
- CP_CHECKOBJECT(playercontext.m_pBaseEngineParams);
- CP_TRACE0("Cooler Engine Startup");
- hr_ComState = CoInitialize(NULL);
- // 为该线程初始化 USER32.DLL
- {
- MSG msgDummy;
- PeekMessage(&msgDummy, 0, WM_USER, WM_USER, PM_NOREMOVE);
- // 用信号通知此线程已经准备好输入
- SetEvent(playercontext.m_pBaseEngineParams->m_hEvtThreadReady);
- }
- // 初始化 CoDecs
- CP_InitialiseCodec_MPEG(&playercontext.m_CoDecs[CP_CODEC_MPEG]);
- CP_InitialiseCodec_WAV(&playercontext.m_CoDecs[CP_CODEC_WAV]);
- // CP_InitialiseCodec_OGG(&playercontext.m_CoDecs[CP_CODEC_OGG]);
- // CP_InitialiseCodec_WinAmpPlugin(&playercontext.m_CoDecs[CP_CODEC_WINAMPPLUGIN]);
- // 初始化输出模式
- if(options.decoder_output_mode > CP_OUTPUT_last)
- options.decoder_output_mode = CP_OUTPUT_last;
- playercontext.m_dwCurrentOutputModule = options.decoder_output_mode;
- CPI_Player_Output_Initialise_WaveMapper(&playercontext.m_OutputModules[CP_OUTPUT_WAVE]);
- CPI_Player_Output_Initialise_DirectSound(&playercontext.m_OutputModules[CP_OUTPUT_DIRECTSOUND]);
- CPI_Player_Output_Initialise_File(&playercontext.m_OutputModules[CP_OUTPUT_FILE]);
- playercontext.m_pCurrentOutputModule = &playercontext.m_OutputModules[playercontext.m_dwCurrentOutputModule];
- // 初始化 EQ
- CPI_Player_Equaliser_Initialise_Basic(&playercontext.m_Equaliser);
- do
- {
- // 处理任何未决的消息
- BOOL bForceRefill = FALSE;
- MSG msg;
- DWORD dwWaitResult;
- while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- // 解码引擎消息
- switch(msg.message)
- {
- case CPTM_QUIT:
- bTerminateThread = TRUE;
- break;
- case CPTM_OPENFILE:
- {
- char* pcFilename = (char*)msg.wParam;
- // 如果这里有另一个不定的打开文件,那么忽略此文件。
- // 当进程没有响应(on an http connect for example),
- // 而且用户还在不停的点击播放按钮时,这将非常有用。
- //- (这将导致大量的打开/关闭消息被放置倒队列中,而这些消息将占用线程几年的时间)
- MSG msg2;
- if(PeekMessage(&msg2, NULL, CPTM_OPENFILE, CPTM_OPENFILE, PM_NOREMOVE) == FALSE)
- {
- CPs_CoDecModule* pNewCoDec;
- // 如果此处有CoDec播放,那么关闭之
- if(playercontext.m_pCurrentOutputModule->m_pCoDec)
- {
- playercontext.m_pCurrentOutputModule->m_pCoDec->CloseFile(playercontext.m_pCurrentOutputModule->m_pCoDec);
- playercontext.m_pCurrentOutputModule->m_pCoDec = NULL;
- }
- CP_TRACE1("Openfile "%s"", pcFilename);
- pNewCoDec = OpenCoDec(&playercontext, pcFilename);
- // 如果打开失败,那么从接口申请一个新的流
- if(pNewCoDec == NULL)
- {
- PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsEndOfStream, 0);
- }
- // 检查文件格式 - 取样率,声道数或者取样大小是否改变
- // 然后,清除当前的输出,关闭输出装备 (着将导致一个 gap
- // - 但仅当格式改变时)
- else if(playercontext.m_bOutputActive == TRUE)
- {
- CPs_FileInfo FileInfo;
- pNewCoDec->GetFileInfo(pNewCoDec, &FileInfo);
- if(//FileInfo.m_iFreq_Hz != playercontext.m_iOpenDevice_Freq_Hz
- FileInfo.m_bStereo != playercontext.m_bOpenDevice_Stereo
- || FileInfo.m_b16bit != playercontext.m_bOpenDevice_16bit
- )
- {
- CP_TRACE0("Stream format changes - clearing stream");
- EmptyOutputStream(&playercontext);
- StartPlay(pNewCoDec, &playercontext);
- bForceRefill = TRUE;
- }
- }
- playercontext.m_pCurrentOutputModule->m_pCoDec = pNewCoDec;
- }
- #ifdef _DEBUG
- else
- {
- CP_TRACE1("Openfile of "%s" ignored due to other opens in the queue", pcFilename);
- }
- #endif
- // 清空
- free(pcFilename);
- }
- break;
- case CPTM_SEEK:
- if(playercontext.m_bOutputActive == TRUE)
- {
- // 如果有另一个消息在此位置,忽略其他的!
- MSG msg2;
- if(PeekMessage(&msg2, NULL, CPTM_SEEK, CPTM_SEEK, PM_NOREMOVE) == FALSE)
- {
- if(playercontext.m_pCurrentOutputModule->m_pCoDec)
- playercontext.m_pCurrentOutputModule->m_pCoDec->Seek(playercontext.m_pCurrentOutputModule->m_pCoDec, (int)msg.wParam, (int)msg.lParam);
- playercontext.m_pCurrentOutputModule->Flush(playercontext.m_pCurrentOutputModule);
- bForceRefill = TRUE;
- }
- }
- break;
- case CPTM_PLAY:
- if(playercontext.m_pCurrentOutputModule->m_pCoDec)
- {
- // 如果没有输出stage - 马上初始化
- if(playercontext.m_bOutputActive == FALSE)
- {
- StartPlay(playercontext.m_pCurrentOutputModule->m_pCoDec, &playercontext);
- bForceRefill = TRUE;
- }
- playercontext.m_pCurrentOutputModule->SetPause(playercontext.m_pCurrentOutputModule, FALSE);
- PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsPlaying, 0);
- playercontext.m_iLastSentTime_Secs = -1;
- playercontext.m_iLastSentTime_Proportion = -1;
- UpdateProgress(&playercontext);
- }
- break;
- case CPTM_STOP:
- if(playercontext.m_pCurrentOutputModule->m_pCoDec)
- {
- playercontext.m_pCurrentOutputModule->m_pCoDec->CloseFile(playercontext.m_pCurrentOutputModule->m_pCoDec);
- playercontext.m_pCurrentOutputModule->m_pCoDec = NULL;
- }
- if(playercontext.m_bOutputActive == TRUE)
- {
- playercontext.m_bOutputActive = FALSE;
- playercontext.m_pCurrentOutputModule->Uninitialise(playercontext.m_pCurrentOutputModule);
- }
- PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsStopped, 0);
- break;
- case CPTM_PAUSE:
- CP_TRACE0("Pause");
- if(playercontext.m_bOutputActive == TRUE)
- playercontext.m_pCurrentOutputModule->SetPause(playercontext.m_pCurrentOutputModule, TRUE);
- PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsPaused, 0);
- break;
- case CPTM_SETPROGRESSTRACKLENGTH:
- playercontext.m_iProportion_TrackLength = (int)msg.wParam;
- break;
- case CPTM_SENDSYNCCOOKIE:
- PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_SYNCCOOKIE, msg.wParam, 0);
- break;
- case CPTM_BLOCKMSGUNTILENDOFSTREAM:
- EmptyOutputStream(&playercontext);
- break;
- case CPTM_ENUMOUTPUTDEVICES:
- EnumOutputDevices(&playercontext);
- break;
- case CPTM_SETEQSETTINGS:
- {
- MSG msg2;
- CPs_EQSettings* pEQ = (CPs_EQSettings*)msg.wParam;
- // 如果有另一个未决的EQ 消息,不要处理这个(试图减少噪音)
- if(PeekMessage(&msg2, NULL, CPTM_SETEQSETTINGS, CPTM_OPENFILE, PM_NOREMOVE) == FALSE)
- {
- BOOL bEQEnableStateChanged;
- playercontext.m_Equaliser.ApplySettings(&playercontext.m_Equaliser, pEQ, &bEQEnableStateChanged);
- // 清空缓存(这将音乐的不连续,但至少
- // EQ 设置会立即改变
- if(playercontext.m_bOutputActive == TRUE && playercontext.m_pCurrentOutputModule->OnEQChanged)
- playercontext.m_pCurrentOutputModule->OnEQChanged(playercontext.m_pCurrentOutputModule);
- }
- free(pEQ);
- }
- break;
- case CPTM_ONOUTPUTMODULECHANGE:
- {
- playercontext.m_dwCurrentOutputModule = options.decoder_output_mode;
- SetCurrentOutputModule(&playercontext, NULL, &bForceRefill);
- }
- break;
- case CPTM_ASSOCIATEFILEEXTENSIONS:
- AssociateFileExtensions(&playercontext);
- break;
- case CPTM_SETINTERNALVOLUME:
- playercontext.m_iInternalVolume = (int)msg.wParam;
- if(playercontext.m_bOutputActive == TRUE && playercontext.m_pCurrentOutputModule->SetInternalVolume)
- playercontext.m_pCurrentOutputModule->SetInternalVolume(playercontext.m_pCurrentOutputModule, playercontext.m_iInternalVolume);
- break;
- }
- }
- if(bTerminateThread)
- break;
- // 等待下一个消息或者缓冲区满 (假如有播放器)
- if(playercontext.m_bOutputActive)
- {
- dwWaitResult = 0L;
- if(bForceRefill == FALSE)
- {
- if(playercontext.m_pCurrentOutputModule->m_evtBlockFree)
- dwWaitResult = MsgWaitForMultipleObjects(1, &playercontext.m_pCurrentOutputModule->m_evtBlockFree, FALSE, 1000, QS_POSTMESSAGE);
- else
- dwWaitResult = WAIT_OBJECT_0;
- }
- // 如果缓冲区消息被发送,那么请求重新填充
- if(bForceRefill == TRUE || dwWaitResult == WAIT_OBJECT_0)
- {
- if(playercontext.m_pCurrentOutputModule->m_pCoDec)
- {
- playercontext.m_pCurrentOutputModule->RefillBuffers(playercontext.m_pCurrentOutputModule);
- if(playercontext.m_pCurrentOutputModule->m_pCoDec == NULL)
- {
- // 通知 UI 需要另一个播放文件
- PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsEndOfStream, 0);
- }
- else
- UpdateProgress(&playercontext);
- }
- // 如果输出结束了应作的每件事,关闭引擎
- else if(playercontext.m_pCurrentOutputModule->IsOutputComplete(playercontext.m_pCurrentOutputModule) == TRUE)
- {
- playercontext.m_bOutputActive = FALSE;
- playercontext.m_pCurrentOutputModule->Uninitialise(playercontext.m_pCurrentOutputModule);
- PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsStopped, 0);
- }
- }
- }
- else
- {
- WaitMessage();
- }
- }
- while(bTerminateThread == FALSE);
- // 清空输出(如果仍然是活跃的)
- if(playercontext.m_pCurrentOutputModule->m_pCoDec)
- {
- playercontext.m_pCurrentOutputModule->m_pCoDec->CloseFile(playercontext.m_pCurrentOutputModule->m_pCoDec);
- playercontext.m_pCurrentOutputModule->m_pCoDec = NULL;
- }
- if(playercontext.m_bOutputActive == TRUE)
- playercontext.m_pCurrentOutputModule->Uninitialise(playercontext.m_pCurrentOutputModule);
- // 清空模板
- playercontext.m_Equaliser.Uninitialise(&playercontext.m_Equaliser);
- CleanupCoDecs(&playercontext);
- if(hr_ComState == S_OK)
- CoUninitialize();
- CP_TRACE0("Cooler Engine terminating");
- return 0;
- }
- //
- //
- //
- void UpdateProgress(CPs_PlayerContext* pContext)
- {
- int iCurrentTime_Secs;
- // 如果文件偏移改变,重新发送通知
- if(pContext->m_bOutputActive == TRUE)
- iCurrentTime_Secs = pContext->m_pCurrentOutputModule->m_pCoDec->GetCurrentPos_secs(pContext->m_pCurrentOutputModule->m_pCoDec);
- else
- iCurrentTime_Secs = 0;
- if(iCurrentTime_Secs != pContext->m_iLastSentTime_Secs)
- {
- CPs_FileInfo* pFileInfo;
- int iFileLength_Secs;
- pContext->m_iLastSentTime_Secs = iCurrentTime_Secs;
- // (重)发文件信息
- pFileInfo = (CPs_FileInfo*)malloc(sizeof(*pFileInfo));
- pContext->m_pCurrentOutputModule->m_pCoDec->GetFileInfo(pContext->m_pCurrentOutputModule->m_pCoDec, pFileInfo);
- iFileLength_Secs = pFileInfo->m_iFileLength_Secs;
- PostMessage(pContext->m_pBaseEngineParams->m_hWndNotify, CPNM_FILEINFO, (WPARAM)pFileInfo, 0);
- // 发送当前进程
- PostMessage(pContext->m_pBaseEngineParams->m_hWndNotify, CPNM_FILEOFFSET_SECS, (WPARAM)iCurrentTime_Secs, 0);
- // Send the proportion along the track (if it has changed)
- if(pContext->m_iProportion_TrackLength != 0 && iFileLength_Secs != 0)
- {
- int iProportionAlongTrack = (int)( ( (float)iCurrentTime_Secs / (float)iFileLength_Secs)
- * (float)pContext->m_iProportion_TrackLength );
- if(iProportionAlongTrack != pContext->m_iLastSentTime_Proportion)
- {
- pContext->m_iLastSentTime_Proportion = iProportionAlongTrack;
- PostMessage(pContext->m_pBaseEngineParams->m_hWndNotify, CPNM_FILEOFFSET_PROP, (WPARAM)iProportionAlongTrack, 0);
- }
- }
- }
- }
- //
- //
- //
- void EmptyOutputStream(CPs_PlayerContext* pContext)
- {
- if(pContext->m_bOutputActive == FALSE)
- return;
- while(pContext->m_pCurrentOutputModule->IsOutputComplete(pContext->m_pCurrentOutputModule) == FALSE)
- {
- WaitForSingleObject(pContext->m_pCurrentOutputModule->m_evtBlockFree, 1000);
- if(pContext->m_pCurrentOutputModule->m_pCoDec)
- UpdateProgress(pContext);
- }
- pContext->m_bOutputActive = FALSE;
- pContext->m_pCurrentOutputModule->Uninitialise(pContext->m_pCurrentOutputModule);
- PostMessage(pContext->m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsStopped, 0);
- }
- //
- //
- //
- void EnumOutputDevices(CPs_PlayerContext* pContext)
- {
- int iOutputModuleIDX;
- // 列举输出模板
- for(iOutputModuleIDX = 0; iOutputModuleIDX <= CP_OUTPUT_last; iOutputModuleIDX++)
- {
- const CPs_OutputModule* pOutputModule = pContext->m_OutputModules + iOutputModuleIDX;
- char* pcDeviceName;
- // 缓冲释放
- STR_AllocSetString(&pcDeviceName, pOutputModule->m_pcModuleName, FALSE);
- PostMessage(pContext->m_pBaseEngineParams->m_hWndNotify, CPNM_FOUNDOUTPUTDEVICE, (WPARAM)pcDeviceName, (LPARAM)iOutputModuleIDX);
- }
- }
- //
- //
- //
- void StartPlay(CPs_CoDecModule* pCoDec, CPs_PlayerContext* pContext)
- {
- CPs_FileInfo FileInfo;
- pCoDec->GetFileInfo(pCoDec, &FileInfo);
- pContext->m_bOutputActive = TRUE;
- pContext->m_iOpenDevice_Freq_Hz = FileInfo.m_iFreq_Hz;
- pContext->m_bOpenDevice_Stereo = FileInfo.m_bStereo;
- pContext->m_bOpenDevice_16bit = FileInfo.m_b16bit;
- // 获得模板并初始化
- pContext->m_Equaliser.Initialise(&pContext->m_Equaliser, FileInfo.m_iFreq_Hz, FileInfo.m_b16bit);
- pContext->m_pCurrentOutputModule->Initialise(pContext->m_pCurrentOutputModule, &FileInfo, &pContext->m_Equaliser);
- // 如果音量不是100% 那么设置音量级
- // if(!pContext->m_iInternalVolume)
- pContext->m_pCurrentOutputModule->SetInternalVolume(pContext->m_pCurrentOutputModule, pContext->m_iInternalVolume);
- }
- //
- //
- //
- CPs_CoDecModule* OpenCoDec(CPs_PlayerContext* pContext, const char* pcFilename)
- {
- const char* pcLastDot = NULL;
- int iCoDecIDX = 0;
- BOOL bOpenSucceeded;
- DWORD dwCookie=0;
- // 查找扩展名
- char *extension=NULL;
- char *dot=strrchr(pcFilename,'.');
- if(dot) extension=dot+1;
- /* if(dot)
- {
- if(CPFA_IsAssociated(&pContext->m_CoDecs[CP_CODEC_WINAMPPLUGIN], extension, &dwCookie) == TRUE)
- {
- bOpenSucceeded = pContext->m_CoDecs[CP_CODEC_WINAMPPLUGIN].OpenFile(
- &pContext->m_CoDecs[CP_CODEC_WINAMPPLUGIN],
- pcFilename,
- dwCookie,
- pContext->m_pBaseEngineParams->m_hWndNotify);
- if(bOpenSucceeded == TRUE)
- return &pContext->m_CoDecs[CP_CODEC_WINAMPPLUGIN];
- }
- }
- */
- // Find a CoDec that wants this association
- for(iCoDecIDX =CP_CODEC_WAV; iCoDecIDX <= CP_CODEC_last; iCoDecIDX++)
- {
- bOpenSucceeded = pContext->m_CoDecs[iCoDecIDX].OpenFile( &pContext->m_CoDecs[iCoDecIDX],
- pcFilename,
- dwCookie,
- pContext->m_pBaseEngineParams->m_hWndNotify);
- if(bOpenSucceeded == TRUE)
- return &pContext->m_CoDecs[iCoDecIDX];
- }
- return NULL;
- }
- //
- //
- //
- void CleanupCoDecs(CPs_PlayerContext* pContext)
- {
- int iCoDecIDX = 0;
- for(iCoDecIDX =CP_CODEC_WAV; iCoDecIDX <= CP_CODEC_last; iCoDecIDX++)
- pContext->m_CoDecs[iCoDecIDX].Uninitialise(&pContext->m_CoDecs[iCoDecIDX]);
- }
- //
- //
- //
- void SetCurrentOutputModule(CPs_PlayerContext* pContext, CPs_OutputModule* pNewOuputModule, BOOL* pbForceRefill)
- {
- if(!pNewOuputModule)
- pNewOuputModule = &pContext->m_OutputModules[pContext->m_dwCurrentOutputModule];
- // 如果输出模板改变,那么关闭老的,使用新的
- if(pContext->m_pCurrentOutputModule == pNewOuputModule)
- return;
- // 关闭当前存在的
- if(pContext->m_bOutputActive)
- {
- pContext->m_pCurrentOutputModule->Uninitialise(pContext->m_pCurrentOutputModule);
- pContext->m_bOutputActive = FALSE;
- }
- // 转换解码器到新的输出模板
- pNewOuputModule->m_pCoDec = pContext->m_pCurrentOutputModule->m_pCoDec;
- // 设置新模板为当前使用
- pContext->m_pCurrentOutputModule = pNewOuputModule;
- if(pContext->m_bOutputActive == FALSE && pContext->m_pCurrentOutputModule->m_pCoDec)
- {
- StartPlay(pContext->m_pCurrentOutputModule->m_pCoDec, pContext);
- *pbForceRefill = TRUE;
- }
- }
- //
- //
- //
- void AssociateFileExtensions(CPs_PlayerContext* pContext)
- {
- int iCoDecIDX;
- for(iCoDecIDX =0; iCoDecIDX <= CP_CODEC_last; iCoDecIDX++)
- CPFA_AssociateWithEXE(&pContext->m_CoDecs[iCoDecIDX]);
- }
- //
- //
- //