⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpi_player_engine.c

📁 VC++视频开发实例集锦(包括“远程视频监控”"语音识别系统"等13个经典例子)
💻 C
📖 第 1 页 / 共 2 页
字号:
#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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -