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

📄 cpi_player_codec_winampplugin.c

📁 《Visual C++视频/音频开发实用工程案例精选》一书的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:

////////////////////////////////////////////////////////////////////////////////



#include "stdafx.h"
#include "globals.h"
#include "CPI_Player_CoDec.h"
#include "CP_WinAmpStructs.h"
#include "CPI_CircleBuffer.h"

////////////////////////////////////////////////////////////////////////////////
//
// This is the CoDec module - the basic idea is that the file will be opened and
// data will be sucked through the CoDec via calls to CPI_CoDec__GetPCMBlock
//
//
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
//
//
// Module functions
void CPP_OMAPLG_Uninitialise(CPs_CoDecModule* pModule);
BOOL CPP_OMAPLG_OpenFile(CPs_CoDecModule* pModule, const char* pcFilename, DWORD dwCookie, HWND hWndOwner);
void CPP_OMAPLG_CloseFile(CPs_CoDecModule* pModule);
void CPP_OMAPLG_Seek(CPs_CoDecModule* pModule, const int iNumerator, const int iDenominator);
void CPP_OMAPLG_GetFileInfo(CPs_CoDecModule* pModule, CPs_FileInfo* pInfo);
//
BOOL CPP_OMAPLG_GetPCMBlock(CPs_CoDecModule* pModule, void* pBlock, DWORD* pdwBlockSize);
int CPP_OMAPLG_GetCurrentPos_secs(CPs_CoDecModule* pModule);
//
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Dummy functions used by the in module (but we don't need 'em)
void CP_Dummy_SAVSAInit(int maxlatency_in_ms, int srate) {}
void CP_Dummy_SAVSADeInit() {}
void CP_Dummy_SAAddPCMData(void *PCMData, int nch, int bps, int timestamp) {}
int CP_Dummy_SAGetMode() { return 0; }
void CP_Dummy_SAAdd(void *data, int timestamp, int csa) {}
void CP_Dummy_VSAAddPCMData(void *PCMData, int nch, int bps, int timestamp) {}
int CP_Dummy_VSAGetMode(int *specNch, int *waveNch) { return 0; }
void CP_Dummy_VSAAdd(void *data, int timestamp) {}
int CP_Dummy_dsp_isactive() { return 0; }
int CP_Dummy_dsp_dosamples(short int *samples, int numsamples, int bps, int nch, int srate) { return 0; }
//
void CP_Dummy_VSASetInfo(int nch, int srate) {}
int CP_Dummy_SetInfo(int bitrate, int srate, int stereo, int synched) { return 0; }
//
// Dummy output functions
int CP_Dummy_Pause(int pause) { return 0; }
void CP_Dummy_SetVolume(int volume) {}
void CP_Dummy_SetPan(int pan) {}
int CP_Dummy_GetOutputTime() { return 0; }
int CP_Dummy_GetWrittenTime() { return 0; }
////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////
//
typedef struct __CPs_CoDec_WinAmpPlugin
{
    CP_PlugInModule* m_pFirstPlugIn;

    CP_PlugInModule* m_pActivePluginModule;
    HMODULE m_hModPlugin;
    In_Module* m_pInModule;
    BOOL m_bModuleIsPlaying;

    Out_Module m_FakeOutModule;

} CPs_CoDec_WinAmpPlugin;
//
////////////////////////////////////////////////////////////////////////////////


#define CIC_CIRCLE_DATABUFFER_SIZE		0x10000		//64Kb
#define CIC_WAITTIMEOUT					2000		// 2Secs
////////////////////////////////////////////////////////////////////////////////
// Callback interface (WinAmp doesn't "DO" cookies so we have to have this global
// variable) - this means that we can only have one thread (the plugins prob aren't
// thread safe anyhow) - but there we go!
//
struct CPs_OutputGlobalData
{
    CRITICAL_SECTION m_csGlobal;
    BOOL m_bStreamIsComplete;
    int m_iCurrentTime_ms;

    // Stuff for the file information
    HANDLE m_evtFileInfoValid;
    CPs_FileInfo m_FileInfo;

    // Stuff for the data buffer
    CPs_CircleBuffer* m_pCBuffer;

    HANDLE m_evtSeekComplete;

} glb_OutputData;
//
//
//
int CP_OutPI_Open(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms)
{
    // returns >=0 on success, <0 on failure
    // NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
    //    ... so don't expect the max latency returned to be what you asked for.
    // returns max latency in ms (0 for diskwriters, etc)
    // bufferlenms and prebufferms must be in ms. 0 to use defaults.
    // prebufferms must be <= bufferlenms

    if(bitspersamp != 8 && bitspersamp != 16)
    {
        CP_TRACE0("Inappropriate stream type");
        return -1;
    }

    if(numchannels != 1 && numchannels != 2)
    {
        CP_TRACE0("Inappropriate stream type");
        return -1;
    }

    // Setup the global info struct
    {
        EnterCriticalSection(&glb_OutputData.m_csGlobal);

        glb_OutputData.m_FileInfo.m_iFileLength_Secs = 0;
        glb_OutputData.m_FileInfo.m_iBitRate_Kbs = 0;
        glb_OutputData.m_FileInfo.m_iFreq_Hz = samplerate;
        glb_OutputData.m_FileInfo.m_bStereo = (numchannels>1) ? TRUE : FALSE;
        glb_OutputData.m_FileInfo.m_b16bit = (bitspersamp==16) ? TRUE : FALSE;

        LeaveCriticalSection(&glb_OutputData.m_csGlobal);

        SetEvent(glb_OutputData.m_evtFileInfoValid);
    }

    return 1;
}
//
//
//
void CP_OutPI_Close()
{
    CP_TRACE0("CP_OutPI_Close");
    EnterCriticalSection(&glb_OutputData.m_csGlobal);

    if(glb_OutputData.m_pCBuffer)
        glb_OutputData.m_pCBuffer->SetComplete(glb_OutputData.m_pCBuffer);

    LeaveCriticalSection(&glb_OutputData.m_csGlobal);
}
//
//
//
int CP_OutPI_CanWrite()
{
    int iNumBytesFree;
    // returns number of bytes possible to write at a given time.
    // Never will decrease unless you call Write (or Close, heh)

    EnterCriticalSection(&glb_OutputData.m_csGlobal);

    if(glb_OutputData.m_pCBuffer == NULL)
        iNumBytesFree = 0xFFFFFFFF;
    else
        iNumBytesFree = glb_OutputData.m_pCBuffer->GetFreeSize(glb_OutputData.m_pCBuffer);

    LeaveCriticalSection(&glb_OutputData.m_csGlobal);

    return iNumBytesFree;
}
//
//
//
int CP_OutPI_Write(char *buf, int len)
{
    // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
    // 1 returns not able to write (yet). Non-blocking, always.
    if(len > CP_OutPI_CanWrite())
        return 1;

    EnterCriticalSection(&glb_OutputData.m_csGlobal);

    if(glb_OutputData.m_pCBuffer)
        glb_OutputData.m_pCBuffer->Write(glb_OutputData.m_pCBuffer, buf, len);

    // Update the current time
    {
        int iBytesPerSample = (glb_OutputData.m_FileInfo.m_bStereo ? 2 : 1)
                              << (glb_OutputData.m_FileInfo.m_b16bit ? 1 : 0);

        glb_OutputData.m_iCurrentTime_ms += ((len / iBytesPerSample)*1000) / glb_OutputData.m_FileInfo.m_iFreq_Hz;
    }

    LeaveCriticalSection(&glb_OutputData.m_csGlobal);
    return 0;
}
//
//
//
void CP_OutPI_Flush(int iNewTime)
{
    EnterCriticalSection(&glb_OutputData.m_csGlobal);
    if(glb_OutputData.m_pCBuffer)
        glb_OutputData.m_pCBuffer->Flush(glb_OutputData.m_pCBuffer);
    glb_OutputData.m_iCurrentTime_ms = iNewTime;
    SetEvent(glb_OutputData.m_evtSeekComplete);
    LeaveCriticalSection(&glb_OutputData.m_csGlobal);
}
//
//
//
int CP_OutPI_IsPlaying()
{
    CP_TRACE0("CP_OutPI_IsPlaying");
    EnterCriticalSection(&glb_OutputData.m_csGlobal);

    if(glb_OutputData.m_pCBuffer)
        glb_OutputData.m_pCBuffer->SetComplete(glb_OutputData.m_pCBuffer);

    LeaveCriticalSection(&glb_OutputData.m_csGlobal);

    return 0;
}
//
//
////////////////////////////////////////////////////////////////////////////////


#define CP_INVALIDCHARPOS	-1
typedef In_Module* (*wp_winampGetInModule2)();
////////////////////////////////////////////////////////////////////////////////
//
//
//
void ProbeWinAmpModule(CPs_CoDecModule* pCoDec, const char* pcModulePath)
{
    CPs_CoDec_WinAmpPlugin *pContext;
    HMODULE hModPlugin;
    wp_winampGetInModule2 pfnGetInModule;
    In_Module* pInModule;
    pContext = (CPs_CoDec_WinAmpPlugin*)pCoDec->m_pModuleCookie;
    CP_CHECKOBJECT(pContext);

    // Load plugin and get EP
    hModPlugin = LoadLibrary(pcModulePath);
    if(!hModPlugin)
        return;
    pfnGetInModule = (wp_winampGetInModule2)GetProcAddress(hModPlugin, "winampGetInModule2");
    if(!pfnGetInModule)
    {
        FreeLibrary(hModPlugin);
        return;
    }

    // Get the plug in descriptor
    pInModule = pfnGetInModule();

    // Skip modules that we cannot support
    if(!pInModule->UsesOutputPlug)
    {
        CP_TRACE1("\"%s\" Cannot be supported (not an output user)", pcModulePath);
        FreeLibrary(hModPlugin);
        return;
    }

    // Get the extensions supported by this plugin
    if(pInModule && pInModule->FileExtensions && pInModule->FileExtensions[0])
    {
        char* pExtensions = pInModule->FileExtensions;
        CP_PlugInModule* pNewPlugInModule = (CP_PlugInModule*)malloc(sizeof(CP_PlugInModule));

        // Create new plug in module and add it to our list
        pNewPlugInModule->m_pNext = pContext->m_pFirstPlugIn;
        STR_AllocSetString(&pNewPlugInModule->m_pcModuleName, pcModulePath, FALSE);
        pContext->m_pFirstPlugIn = pNewPlugInModule;

        // Attach etensions to this module
        CP_TRACE1("Probing module: \"%s\"", pcModulePath);
        while(*pExtensions)
        {
            char* pDescription = pExtensions + strlen(pExtensions) + 1;
            CP_TRACE2("Extensions: \"%s\" type:\"%s\"", pExtensions, pDescription);

            // The extensions are in the format EXT1;EXT2;EXT3  - split these and
            // add them to the player's extension list
            {
                char* pcExtensionCursor;
                char* pcLastExtensionStart = pExtensions;

                for(pcExtensionCursor = pExtensions; *pcExtensionCursor; pcExtensionCursor++)
                {
                    // Look for an extension break
                    if(*pcExtensionCursor == ';' && pcExtensionCursor != pcLastExtensionStart)
                    {
                        const int iExtensionLen = pcExtensionCursor - pcLastExtensionStart;
                        char* pcExtensionCopy = (char*)malloc(iExtensionLen+1);

                        memcpy(pcExtensionCopy, pcLastExtensionStart, iExtensionLen);
                        pcExtensionCopy[iExtensionLen] = '\0';

                        CPFA_AddFileAssociation(pCoDec, pcExtensionCopy, (DWORD)pNewPlugInModule);

                        free(pcExtensionCopy);
                        pcLastExtensionStart = pcExtensionCursor+1;
                    }
                }

                // Add last extension
                if(*pcLastExtensionStart)
                    CPFA_AddFileAssociation(pCoDec, pcLastExtensionStart, (DWORD)pNewPlugInModule);
            }

            // Move cursor to next extension set
            pExtensions = pDescription + strlen(pDescription) + 1;
        }
    }

    // Free plugin
    FreeLibrary(hModPlugin);
}
//
//
//
void AddWinAmpModulesInPath(CPs_CoDecModule* pCoDec, const char* pcFileInPath)
{
    WIN32_FIND_DATA finddata;
    HANDLE hFileFind;
    char pcModuleDirectory[MAX_PATH];
    char pcSearchWildcard[MAX_PATH];

    strcpy(pcModuleDirectory, pcFileInPath);

    // Work out the module directory
    {
        int iLastSlashPos, iCharIDX;

        iLastSlashPos = CP_INVALIDCHARPOS;
        for(iCharIDX=0; pcModuleDirectory[iCharIDX]; iCharIDX++)
        {
            if(pcModuleDirectory[iCharIDX] == '\\')
                iLastSlashPos = iCharIDX;
        }
        // We must exist in some kind of directory!!!
        CP_ASSERT(iLastSlashPos != CP_INVALIDCHARPOS);
        pcModuleDirectory[iLastSlashPos+1] = '\0';
    }

    // Setup wildcard
    strcpy(pcSearchWildcard,pcModuleDirectory);
    strcat(pcSearchWildcard, "in_*.dll");

    // Load each module to find out the file extensions that it supports
    // ProbeWinAmpModule will also produce a linked list of module names
    // and assign them to the FileAssociation cookie
    hFileFind = FindFirstFile(pcSearchWildcard, &finddata);
    if(hFileFind != INVALID_HANDLE_VALUE)
    {
        do
        {
            char pcFullPath[MAX_PATH];
            strcpy(pcFullPath,pcModuleDirectory);
            strcat(pcFullPath, finddata.cFileName);

            ProbeWinAmpModule(pCoDec, pcFullPath);

        } while(FindNextFile(hFileFind, &finddata) != 0);

        FindClose(hFileFind);

⌨️ 快捷键说明

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