CPI_Player_Engine.c
上传用户:tuheem
上传日期:2007-05-01
资源大小:21889k
文件大小:21k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. #include "stdafx.h"
  2. #include "globals.h"
  3. #include "CPI_Player.h"
  4. #include "CPI_Player_Messages.h"
  5. #include "CPI_Player_CoDec.h"
  6. #include "CPI_Player_Output.h"
  7. #include "CPI_Equaliser.h"
  8. typedef struct __CPs_PlayerContext
  9. {
  10.     CPs_PlayEngine* m_pBaseEngineParams;
  11.     CPs_CoDecModule m_CoDecs[CP_CODEC_last+1];
  12.     CPs_OutputModule m_OutputModules[CP_OUTPUT_last+1];
  13.     CPs_OutputModule* m_pCurrentOutputModule;
  14.     BOOL m_bOutputActive;
  15.     DWORD m_dwCurrentOutputModule;
  16.     int m_iInternalVolume;
  17.     int m_iLastSentTime_Secs;
  18.     int m_iLastSentTime_Proportion;
  19.     int m_iProportion_TrackLength;
  20.     int m_iOpenDevice_Freq_Hz;
  21.     BOOL m_bOpenDevice_Stereo;
  22.     BOOL m_bOpenDevice_16bit;
  23.     CPs_EqualiserModule m_Equaliser;
  24. } CPs_PlayerContext;
  25. void UpdateProgress(CPs_PlayerContext* pContext);
  26. void EmptyOutputStream(CPs_PlayerContext* pContext);
  27. void StartPlay(CPs_CoDecModule* pCoDec, CPs_PlayerContext* pContext);
  28. void EnumOutputDevices(CPs_PlayerContext* pContext);
  29. CPs_CoDecModule* OpenCoDec(CPs_PlayerContext* pContext, const char* pcFilename);
  30. void CleanupCoDecs(CPs_PlayerContext* pContext);
  31. void SetCurrentOutputModule(CPs_PlayerContext* pContext, CPs_OutputModule* pNewOuputModule, BOOL* pbForceRefill);
  32. void AssociateFileExtensions(CPs_PlayerContext* pContext);
  33. ////////////////////////////////////////////////////////////////////////////////
  34. DWORD WINAPI CPI_Player__EngineEP(void* pCookie)
  35. {
  36.     BOOL bTerminateThread = FALSE;
  37.     HRESULT hr_ComState;
  38.     CPs_PlayerContext playercontext;
  39.     playercontext.m_pBaseEngineParams = (CPs_PlayEngine*)pCookie;
  40.     playercontext.m_bOutputActive = FALSE;
  41.     playercontext.m_iProportion_TrackLength = 0;
  42.     playercontext.m_iLastSentTime_Secs = -1;
  43.     playercontext.m_iLastSentTime_Proportion = -1;
  44.     playercontext.m_iInternalVolume = 100;
  45.     CP_CHECKOBJECT(playercontext.m_pBaseEngineParams);
  46.     CP_TRACE0("Cooler Engine Startup");
  47.     hr_ComState = CoInitialize(NULL);
  48.     // 为该线程初始化 USER32.DLL 
  49.     {
  50.         MSG msgDummy;
  51.         PeekMessage(&msgDummy, 0, WM_USER, WM_USER, PM_NOREMOVE);
  52.         // 用信号通知此线程已经准备好输入
  53.         SetEvent(playercontext.m_pBaseEngineParams->m_hEvtThreadReady);
  54.     }
  55.     // 初始化 CoDecs
  56.     CP_InitialiseCodec_MPEG(&playercontext.m_CoDecs[CP_CODEC_MPEG]);
  57.     CP_InitialiseCodec_WAV(&playercontext.m_CoDecs[CP_CODEC_WAV]);
  58.  //   CP_InitialiseCodec_OGG(&playercontext.m_CoDecs[CP_CODEC_OGG]);
  59. //    CP_InitialiseCodec_WinAmpPlugin(&playercontext.m_CoDecs[CP_CODEC_WINAMPPLUGIN]);
  60.     // 初始化输出模式
  61.     if(options.decoder_output_mode > CP_OUTPUT_last)
  62.         options.decoder_output_mode = CP_OUTPUT_last;
  63.     playercontext.m_dwCurrentOutputModule = options.decoder_output_mode;
  64.     CPI_Player_Output_Initialise_WaveMapper(&playercontext.m_OutputModules[CP_OUTPUT_WAVE]);
  65.     CPI_Player_Output_Initialise_DirectSound(&playercontext.m_OutputModules[CP_OUTPUT_DIRECTSOUND]);
  66.     CPI_Player_Output_Initialise_File(&playercontext.m_OutputModules[CP_OUTPUT_FILE]);
  67.     playercontext.m_pCurrentOutputModule = &playercontext.m_OutputModules[playercontext.m_dwCurrentOutputModule];
  68.     // 初始化 EQ
  69.     CPI_Player_Equaliser_Initialise_Basic(&playercontext.m_Equaliser);
  70.     do
  71.     {
  72.         // 处理任何未决的消息
  73.         BOOL bForceRefill = FALSE;
  74.         MSG msg;
  75.         DWORD dwWaitResult;
  76.         while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  77.         {
  78.             // 解码引擎消息
  79.             switch(msg.message)
  80.             {
  81.             case CPTM_QUIT:
  82.                 bTerminateThread = TRUE;
  83.                 break;
  84.             case CPTM_OPENFILE:
  85.                 {
  86.                     char* pcFilename = (char*)msg.wParam;
  87.                     // 如果这里有另一个不定的打开文件,那么忽略此文件。
  88.                     // 当进程没有响应(on an http connect for example),
  89.                     // 而且用户还在不停的点击播放按钮时,这将非常有用。
  90. //- (这将导致大量的打开/关闭消息被放置倒队列中,而这些消息将占用线程几年的时间)
  91.                     MSG msg2;
  92.                     if(PeekMessage(&msg2, NULL, CPTM_OPENFILE, CPTM_OPENFILE, PM_NOREMOVE) == FALSE)
  93.                     {
  94.                         CPs_CoDecModule* pNewCoDec;
  95.                         // 如果此处有CoDec播放,那么关闭之
  96.                         if(playercontext.m_pCurrentOutputModule->m_pCoDec)
  97.                         {
  98.                             playercontext.m_pCurrentOutputModule->m_pCoDec->CloseFile(playercontext.m_pCurrentOutputModule->m_pCoDec);
  99.                             playercontext.m_pCurrentOutputModule->m_pCoDec = NULL;
  100.                         }
  101.                         CP_TRACE1("Openfile "%s"", pcFilename);
  102.                         pNewCoDec = OpenCoDec(&playercontext, pcFilename);
  103.                         // 如果打开失败,那么从接口申请一个新的流
  104.                         if(pNewCoDec == NULL)
  105.                         {
  106.                             PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsEndOfStream, 0);
  107.                         }
  108.                         // 检查文件格式 - 取样率,声道数或者取样大小是否改变
  109.                         // 然后,清除当前的输出,关闭输出装备 (着将导致一个 gap
  110.                         // - 但仅当格式改变时)
  111.                         else if(playercontext.m_bOutputActive == TRUE)
  112.                         {
  113.                             CPs_FileInfo FileInfo;
  114.                             pNewCoDec->GetFileInfo(pNewCoDec, &FileInfo);
  115.                             if(//FileInfo.m_iFreq_Hz != playercontext.m_iOpenDevice_Freq_Hz
  116.                                     FileInfo.m_bStereo != playercontext.m_bOpenDevice_Stereo
  117.                                     || FileInfo.m_b16bit != playercontext.m_bOpenDevice_16bit
  118. )
  119.                             {
  120.                                 CP_TRACE0("Stream format changes - clearing stream");
  121.                                 EmptyOutputStream(&playercontext);
  122.                                 StartPlay(pNewCoDec, &playercontext);
  123.                                 bForceRefill = TRUE;
  124.                             }
  125.                         }
  126.                         playercontext.m_pCurrentOutputModule->m_pCoDec = pNewCoDec;
  127.                     }
  128. #ifdef _DEBUG
  129.                     else
  130.                     {
  131.                         CP_TRACE1("Openfile of "%s" ignored due to other opens in the queue", pcFilename);
  132.                     }
  133. #endif
  134.                     // 清空
  135.                     free(pcFilename);
  136.                 }
  137.                 break;
  138.             case CPTM_SEEK:
  139.                 if(playercontext.m_bOutputActive == TRUE)
  140.                 {
  141.                     // 如果有另一个消息在此位置,忽略其他的!
  142.                     MSG msg2;
  143.                     if(PeekMessage(&msg2, NULL, CPTM_SEEK, CPTM_SEEK, PM_NOREMOVE) == FALSE)
  144.                     {
  145.                         if(playercontext.m_pCurrentOutputModule->m_pCoDec)
  146.                             playercontext.m_pCurrentOutputModule->m_pCoDec->Seek(playercontext.m_pCurrentOutputModule->m_pCoDec, (int)msg.wParam, (int)msg.lParam);
  147.                         playercontext.m_pCurrentOutputModule->Flush(playercontext.m_pCurrentOutputModule);
  148.                         bForceRefill = TRUE;
  149.                     }
  150.                 }
  151.                 break;
  152.             case CPTM_PLAY:
  153.                 if(playercontext.m_pCurrentOutputModule->m_pCoDec)
  154.                 {
  155.                     // 如果没有输出stage - 马上初始化
  156.                     if(playercontext.m_bOutputActive == FALSE)
  157.                     {
  158.                         StartPlay(playercontext.m_pCurrentOutputModule->m_pCoDec, &playercontext);
  159.                         bForceRefill = TRUE;
  160.                     }
  161.                     playercontext.m_pCurrentOutputModule->SetPause(playercontext.m_pCurrentOutputModule, FALSE);
  162.                     PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsPlaying, 0);
  163.                     playercontext.m_iLastSentTime_Secs = -1;
  164.                     playercontext.m_iLastSentTime_Proportion = -1;
  165.                     UpdateProgress(&playercontext);
  166.                 }
  167.                 break;
  168.             case CPTM_STOP:
  169.                 if(playercontext.m_pCurrentOutputModule->m_pCoDec)
  170.                 {
  171.                     playercontext.m_pCurrentOutputModule->m_pCoDec->CloseFile(playercontext.m_pCurrentOutputModule->m_pCoDec);
  172.                     playercontext.m_pCurrentOutputModule->m_pCoDec = NULL;
  173.                 }
  174.                 if(playercontext.m_bOutputActive == TRUE)
  175.                 {
  176.                     playercontext.m_bOutputActive = FALSE;
  177.                     playercontext.m_pCurrentOutputModule->Uninitialise(playercontext.m_pCurrentOutputModule);
  178.                 }
  179.                 PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsStopped, 0);
  180.                 break;
  181.             case CPTM_PAUSE:
  182.                 CP_TRACE0("Pause");
  183.                 if(playercontext.m_bOutputActive == TRUE)
  184.                     playercontext.m_pCurrentOutputModule->SetPause(playercontext.m_pCurrentOutputModule, TRUE);
  185.                 PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsPaused, 0);
  186.                 break;
  187.             case CPTM_SETPROGRESSTRACKLENGTH:
  188.                 playercontext.m_iProportion_TrackLength = (int)msg.wParam;
  189.                 break;
  190.             case CPTM_SENDSYNCCOOKIE:
  191.                 PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_SYNCCOOKIE, msg.wParam, 0);
  192.                 break;
  193.             case CPTM_BLOCKMSGUNTILENDOFSTREAM:
  194.                 EmptyOutputStream(&playercontext);
  195.                 break;
  196.             case CPTM_ENUMOUTPUTDEVICES:
  197.                 EnumOutputDevices(&playercontext);
  198.                 break;
  199.             case CPTM_SETEQSETTINGS:
  200.                 {
  201.                     MSG msg2;
  202.                     CPs_EQSettings* pEQ = (CPs_EQSettings*)msg.wParam;
  203.                     // 如果有另一个未决的EQ 消息,不要处理这个(试图减少噪音)
  204.                     if(PeekMessage(&msg2, NULL, CPTM_SETEQSETTINGS, CPTM_OPENFILE, PM_NOREMOVE) == FALSE)
  205.                     {
  206.                         BOOL bEQEnableStateChanged;
  207.                         playercontext.m_Equaliser.ApplySettings(&playercontext.m_Equaliser, pEQ, &bEQEnableStateChanged);
  208.                         // 清空缓存(这将音乐的不连续,但至少
  209. //  EQ 设置会立即改变
  210.                         if(playercontext.m_bOutputActive == TRUE && playercontext.m_pCurrentOutputModule->OnEQChanged)
  211.                             playercontext.m_pCurrentOutputModule->OnEQChanged(playercontext.m_pCurrentOutputModule);
  212.                     }
  213.                     free(pEQ);
  214.                 }
  215.                 break;
  216.             case CPTM_ONOUTPUTMODULECHANGE:
  217.                 {
  218.                     playercontext.m_dwCurrentOutputModule = options.decoder_output_mode;
  219.                     SetCurrentOutputModule(&playercontext, NULL, &bForceRefill);
  220.                 }
  221.                 break;
  222.             case CPTM_ASSOCIATEFILEEXTENSIONS:
  223.                 AssociateFileExtensions(&playercontext);
  224.                 break;
  225.             case CPTM_SETINTERNALVOLUME:
  226.                 playercontext.m_iInternalVolume = (int)msg.wParam;
  227.                 if(playercontext.m_bOutputActive == TRUE && playercontext.m_pCurrentOutputModule->SetInternalVolume)
  228.                     playercontext.m_pCurrentOutputModule->SetInternalVolume(playercontext.m_pCurrentOutputModule, playercontext.m_iInternalVolume);
  229.                 break;
  230.             }
  231.         }
  232.         if(bTerminateThread)
  233.             break;
  234.         // 等待下一个消息或者缓冲区满 (假如有播放器)
  235.         if(playercontext.m_bOutputActive)
  236.         {
  237.             dwWaitResult = 0L;
  238.             if(bForceRefill == FALSE)
  239.             {
  240.                 if(playercontext.m_pCurrentOutputModule->m_evtBlockFree)
  241.                     dwWaitResult = MsgWaitForMultipleObjects(1, &playercontext.m_pCurrentOutputModule->m_evtBlockFree, FALSE, 1000, QS_POSTMESSAGE);
  242.                 else
  243.                     dwWaitResult = WAIT_OBJECT_0;
  244.             }
  245.             // 如果缓冲区消息被发送,那么请求重新填充
  246.             if(bForceRefill == TRUE || dwWaitResult == WAIT_OBJECT_0)
  247.             {
  248.                 if(playercontext.m_pCurrentOutputModule->m_pCoDec)
  249.                 {
  250.                     playercontext.m_pCurrentOutputModule->RefillBuffers(playercontext.m_pCurrentOutputModule);
  251.                     if(playercontext.m_pCurrentOutputModule->m_pCoDec == NULL)
  252.                     {
  253.                         // 通知 UI 需要另一个播放文件
  254.                         PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsEndOfStream, 0);
  255.                     }
  256.                     else
  257.                         UpdateProgress(&playercontext);
  258.                 }
  259.                 // 如果输出结束了应作的每件事,关闭引擎
  260.                 else if(playercontext.m_pCurrentOutputModule->IsOutputComplete(playercontext.m_pCurrentOutputModule) == TRUE)
  261.                 {
  262.                     playercontext.m_bOutputActive = FALSE;
  263.                     playercontext.m_pCurrentOutputModule->Uninitialise(playercontext.m_pCurrentOutputModule);
  264.                     PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsStopped, 0);
  265.                 }
  266.             }
  267.         }
  268.         else
  269.         {
  270.             WaitMessage();
  271.         }
  272.     }
  273.     while(bTerminateThread == FALSE);
  274.     // 清空输出(如果仍然是活跃的)
  275.     if(playercontext.m_pCurrentOutputModule->m_pCoDec)
  276.     {
  277.         playercontext.m_pCurrentOutputModule->m_pCoDec->CloseFile(playercontext.m_pCurrentOutputModule->m_pCoDec);
  278.         playercontext.m_pCurrentOutputModule->m_pCoDec = NULL;
  279.     }
  280.     if(playercontext.m_bOutputActive == TRUE)
  281.         playercontext.m_pCurrentOutputModule->Uninitialise(playercontext.m_pCurrentOutputModule);
  282.     // 清空模板
  283.     playercontext.m_Equaliser.Uninitialise(&playercontext.m_Equaliser);
  284.     CleanupCoDecs(&playercontext);
  285.     if(hr_ComState == S_OK)
  286.         CoUninitialize();
  287.     CP_TRACE0("Cooler Engine terminating");
  288.     return 0;
  289. }
  290. //
  291. //
  292. //
  293. void UpdateProgress(CPs_PlayerContext* pContext)
  294. {
  295.     int iCurrentTime_Secs;
  296.     // 如果文件偏移改变,重新发送通知
  297.     if(pContext->m_bOutputActive == TRUE)
  298.         iCurrentTime_Secs = pContext->m_pCurrentOutputModule->m_pCoDec->GetCurrentPos_secs(pContext->m_pCurrentOutputModule->m_pCoDec);
  299.     else
  300.         iCurrentTime_Secs = 0;
  301.     if(iCurrentTime_Secs != pContext->m_iLastSentTime_Secs)
  302.     {
  303.         CPs_FileInfo* pFileInfo;
  304.         int iFileLength_Secs;
  305.         pContext->m_iLastSentTime_Secs = iCurrentTime_Secs;
  306.         // (重)发文件信息
  307.         pFileInfo = (CPs_FileInfo*)malloc(sizeof(*pFileInfo));
  308.         pContext->m_pCurrentOutputModule->m_pCoDec->GetFileInfo(pContext->m_pCurrentOutputModule->m_pCoDec, pFileInfo);
  309.         iFileLength_Secs = pFileInfo->m_iFileLength_Secs;
  310.         PostMessage(pContext->m_pBaseEngineParams->m_hWndNotify, CPNM_FILEINFO, (WPARAM)pFileInfo, 0);
  311.         // 发送当前进程
  312.         PostMessage(pContext->m_pBaseEngineParams->m_hWndNotify, CPNM_FILEOFFSET_SECS, (WPARAM)iCurrentTime_Secs, 0);
  313.         // Send the proportion along the track (if it has changed)
  314.         if(pContext->m_iProportion_TrackLength != 0 && iFileLength_Secs != 0)
  315.         {
  316.             int iProportionAlongTrack = (int)( ( (float)iCurrentTime_Secs / (float)iFileLength_Secs)
  317.                                                * (float)pContext->m_iProportion_TrackLength );
  318.             if(iProportionAlongTrack != pContext->m_iLastSentTime_Proportion)
  319.             {
  320.                 pContext->m_iLastSentTime_Proportion = iProportionAlongTrack;
  321.                 PostMessage(pContext->m_pBaseEngineParams->m_hWndNotify, CPNM_FILEOFFSET_PROP, (WPARAM)iProportionAlongTrack, 0);
  322.             }
  323.         }
  324.     }
  325. }
  326. //
  327. //
  328. //
  329. void EmptyOutputStream(CPs_PlayerContext* pContext)
  330. {
  331.     if(pContext->m_bOutputActive == FALSE)
  332.         return;
  333.     while(pContext->m_pCurrentOutputModule->IsOutputComplete(pContext->m_pCurrentOutputModule) == FALSE)
  334.     {
  335.         WaitForSingleObject(pContext->m_pCurrentOutputModule->m_evtBlockFree, 1000);
  336.         if(pContext->m_pCurrentOutputModule->m_pCoDec)
  337.             UpdateProgress(pContext);
  338.     }
  339.     pContext->m_bOutputActive = FALSE;
  340.     pContext->m_pCurrentOutputModule->Uninitialise(pContext->m_pCurrentOutputModule);
  341.     PostMessage(pContext->m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsStopped, 0);
  342. }
  343. //
  344. //
  345. //
  346. void EnumOutputDevices(CPs_PlayerContext* pContext)
  347. {
  348.     int iOutputModuleIDX;
  349.     // 列举输出模板
  350.     for(iOutputModuleIDX = 0; iOutputModuleIDX <= CP_OUTPUT_last; iOutputModuleIDX++)
  351.     {
  352.         const CPs_OutputModule* pOutputModule = pContext->m_OutputModules + iOutputModuleIDX;
  353.         char* pcDeviceName;
  354.         // 缓冲释放
  355.         STR_AllocSetString(&pcDeviceName, pOutputModule->m_pcModuleName, FALSE);
  356.         PostMessage(pContext->m_pBaseEngineParams->m_hWndNotify, CPNM_FOUNDOUTPUTDEVICE, (WPARAM)pcDeviceName, (LPARAM)iOutputModuleIDX);
  357.     }
  358. }
  359. //
  360. //
  361. //
  362. void StartPlay(CPs_CoDecModule* pCoDec, CPs_PlayerContext* pContext)
  363. {
  364.     CPs_FileInfo FileInfo;
  365.     pCoDec->GetFileInfo(pCoDec, &FileInfo);
  366.     pContext->m_bOutputActive = TRUE;
  367.     pContext->m_iOpenDevice_Freq_Hz = FileInfo.m_iFreq_Hz;
  368.     pContext->m_bOpenDevice_Stereo = FileInfo.m_bStereo;
  369.     pContext->m_bOpenDevice_16bit = FileInfo.m_b16bit;
  370.     // 获得模板并初始化
  371.     pContext->m_Equaliser.Initialise(&pContext->m_Equaliser, FileInfo.m_iFreq_Hz, FileInfo.m_b16bit);
  372.     pContext->m_pCurrentOutputModule->Initialise(pContext->m_pCurrentOutputModule, &FileInfo, &pContext->m_Equaliser);
  373.     // 如果音量不是100% 那么设置音量级
  374. //    if(!pContext->m_iInternalVolume)
  375.         pContext->m_pCurrentOutputModule->SetInternalVolume(pContext->m_pCurrentOutputModule, pContext->m_iInternalVolume);
  376. }
  377. //
  378. //
  379. //
  380. CPs_CoDecModule* OpenCoDec(CPs_PlayerContext* pContext, const char* pcFilename)
  381. {
  382. const char* pcLastDot = NULL;
  383. int iCoDecIDX = 0;
  384. BOOL bOpenSucceeded;
  385. DWORD dwCookie=0;
  386. // 查找扩展名
  387. char *extension=NULL;
  388. char *dot=strrchr(pcFilename,'.');
  389. if(dot) extension=dot+1;
  390. /* if(dot)
  391. {
  392. if(CPFA_IsAssociated(&pContext->m_CoDecs[CP_CODEC_WINAMPPLUGIN], extension, &dwCookie) == TRUE)
  393. {
  394. bOpenSucceeded = pContext->m_CoDecs[CP_CODEC_WINAMPPLUGIN].OpenFile(
  395. &pContext->m_CoDecs[CP_CODEC_WINAMPPLUGIN],
  396. pcFilename,
  397. dwCookie,
  398. pContext->m_pBaseEngineParams->m_hWndNotify);
  399. if(bOpenSucceeded == TRUE)
  400. return &pContext->m_CoDecs[CP_CODEC_WINAMPPLUGIN];
  401. }
  402. }
  403. */
  404. // Find a CoDec that wants this association
  405. for(iCoDecIDX =CP_CODEC_WAV; iCoDecIDX <= CP_CODEC_last; iCoDecIDX++)
  406. {
  407. bOpenSucceeded = pContext->m_CoDecs[iCoDecIDX].OpenFile( &pContext->m_CoDecs[iCoDecIDX],
  408. pcFilename,
  409. dwCookie,
  410. pContext->m_pBaseEngineParams->m_hWndNotify);
  411. if(bOpenSucceeded == TRUE)
  412. return &pContext->m_CoDecs[iCoDecIDX];
  413. }
  414. return NULL;
  415. }
  416. //
  417. //
  418. //
  419. void CleanupCoDecs(CPs_PlayerContext* pContext)
  420. {
  421.     int iCoDecIDX = 0;
  422.     for(iCoDecIDX =CP_CODEC_WAV; iCoDecIDX <= CP_CODEC_last; iCoDecIDX++)
  423.         pContext->m_CoDecs[iCoDecIDX].Uninitialise(&pContext->m_CoDecs[iCoDecIDX]);
  424. }
  425. //
  426. //
  427. //
  428. void SetCurrentOutputModule(CPs_PlayerContext* pContext, CPs_OutputModule* pNewOuputModule, BOOL* pbForceRefill)
  429. {
  430.     if(!pNewOuputModule)
  431.         pNewOuputModule = &pContext->m_OutputModules[pContext->m_dwCurrentOutputModule];
  432.     // 如果输出模板改变,那么关闭老的,使用新的
  433.     if(pContext->m_pCurrentOutputModule == pNewOuputModule)
  434.         return;
  435.     // 关闭当前存在的
  436.     if(pContext->m_bOutputActive)
  437.     {
  438.         pContext->m_pCurrentOutputModule->Uninitialise(pContext->m_pCurrentOutputModule);
  439.         pContext->m_bOutputActive = FALSE;
  440.     }
  441.     // 转换解码器到新的输出模板
  442.     pNewOuputModule->m_pCoDec = pContext->m_pCurrentOutputModule->m_pCoDec;
  443.     // 设置新模板为当前使用
  444.     pContext->m_pCurrentOutputModule = pNewOuputModule;
  445.     if(pContext->m_bOutputActive == FALSE && pContext->m_pCurrentOutputModule->m_pCoDec)
  446.     {
  447.         StartPlay(pContext->m_pCurrentOutputModule->m_pCoDec, pContext);
  448.         *pbForceRefill = TRUE;
  449.     }
  450. }
  451. //
  452. //
  453. //
  454. void AssociateFileExtensions(CPs_PlayerContext* pContext)
  455. {
  456.     int iCoDecIDX;
  457.     for(iCoDecIDX =0; iCoDecIDX <= CP_CODEC_last; iCoDecIDX++)
  458.         CPFA_AssociateWithEXE(&pContext->m_CoDecs[iCoDecIDX]);
  459. }
  460. //
  461. //
  462. //