📄 cpi_player_codec_winampplugin.c
字号:
////////////////////////////////////////////////////////////////////////////////
#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 + -