Add atrac3plus lib.

This commit is contained in:
oioitff 2013-05-14 19:01:33 +08:00
parent a1d7d8f25f
commit 9b0c22f87d
5 changed files with 974 additions and 2 deletions

View File

@ -67,7 +67,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\include;../common;..;../native;../native/ext/glew;../ext/zlib</AdditionalIncludeDirectories>
<PreprocessorDefinitions>USE_FFMPEG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<PreprocessorDefinitions>USE_FFMPEG;_USE_DSHOW_;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
@ -107,7 +107,7 @@
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<FloatingPointModel>Fast</FloatingPointModel>
<PreprocessorDefinitions>USE_FFMPEG;_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<PreprocessorDefinitions>USE_FFMPEG;_USE_DSHOW_;_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
</ClCompile>
<Link>
@ -226,8 +226,10 @@
<ClCompile Include="HLE\sceVaudio.cpp" />
<ClCompile Include="HLE\__sceAudio.cpp" />
<ClCompile Include="Host.cpp" />
<ClCompile Include="HW\audioPlayer.cpp" />
<ClCompile Include="HW\MediaEngine.cpp" />
<ClCompile Include="HW\MemoryStick.cpp" />
<ClCompile Include="HW\OMAConvert.cpp" />
<ClCompile Include="HW\SasAudio.cpp" />
<ClCompile Include="Loaders.cpp" />
<ClCompile Include="MemMap.cpp" />
@ -400,7 +402,9 @@
<ClInclude Include="HLE\sceVaudio.h" />
<ClInclude Include="HLE\__sceAudio.h" />
<ClInclude Include="Host.h" />
<ClInclude Include="HW\audioPlayer.h" />
<ClInclude Include="HW\MediaEngine.h" />
<ClInclude Include="HW\OMAConvert.h" />
<ClInclude Include="HW\SasAudio.h" />
<ClInclude Include="HW\MemoryStick.h" />
<ClInclude Include="Loaders.h" />

358
Core/HW/OMAConvert.cpp Normal file
View File

@ -0,0 +1,358 @@
#include "OMAConvert.h"
namespace OMAConvert {
const u32 OMA_EA3_MAGIC = 0x45413301;
const u8 OMA_CODECID_ATRAC3P = 1;
const int OMAHeaderSize = 96;
const int FMT_CHUNK_MAGIC = 0x20746D66;
const int DATA_CHUNK_MAGIC = 0x61746164;
const int SMPL_CHUNK_MAGIC = 0x6C706D73;
const int FACT_CHUNK_MAGIC = 0x74636166;
const int AT3_MAGIC = 0x0270;
const int AT3_PLUS_MAGIC = 0xFFFE;
template <typename T> void BigEndianWriteBuf(u8* buf, T x, int &pos)
{
int k = sizeof(T);
for (int i = k - 1; i >= 0; i--)
{
buf[pos + i] = (u8)(x & 0xFF);
x >>= 8;
}
pos += k;
}
template <typename T> inline T getBufValue(T* buf, int offsetbytes)
{
return *(T*)(((u8*)buf) + offsetbytes);
}
inline void WriteBuf(u8* dst, int &pos, u8* src, int size)
{
memcpy(dst + pos, src, size);
pos += size;
}
bool isHeader(u8* audioStream, int offset)
{
const u8 header1 = (u8)0x0F;
const u8 header2 = (u8)0xD0;
return (audioStream[offset] == header1) && (audioStream[offset+1] == header2);
}
// header set to the headerbuf, and return it's size
int getOmaHeader(u8 codecId, u8 headerCode0, u8 headerCode1, u8 headerCode2, u8* headerbuf)
{
int pos = 0;
BigEndianWriteBuf(headerbuf, (u32)OMA_EA3_MAGIC, pos);
BigEndianWriteBuf(headerbuf, (u16)OMAHeaderSize, pos);
BigEndianWriteBuf(headerbuf, (u16)-1, pos);
// Unknown 24 bytes...
BigEndianWriteBuf(headerbuf, (u32)0x00000000, pos);
BigEndianWriteBuf(headerbuf, (u32)0x010f5000, pos);
BigEndianWriteBuf(headerbuf, (u32)0x00040000, pos);
BigEndianWriteBuf(headerbuf, (u32)0x0000f5ce, pos);
BigEndianWriteBuf(headerbuf, (u32)0xd2929132, pos);
BigEndianWriteBuf(headerbuf, (u32)0x2480451c, pos);
BigEndianWriteBuf(headerbuf, (u8)codecId, pos);
BigEndianWriteBuf(headerbuf, (u8)headerCode0, pos);
BigEndianWriteBuf(headerbuf, (u8)headerCode1, pos);
BigEndianWriteBuf(headerbuf, (u8)headerCode2, pos);
while (pos < OMAHeaderSize) BigEndianWriteBuf(headerbuf, (u8)0, pos);
return pos;
}
int getNextHeaderPosition(u8* audioStream, int curpos, int limit, int frameSize)
{
int endScan = limit - 1;
// Most common case: the header can be found at each frameSize
int offset = curpos + frameSize - 8;
if (offset < endScan && isHeader(audioStream, offset))
return offset;
for (int scan = curpos; scan < endScan; scan++) {
if (isHeader(audioStream, scan))
return scan;
}
return -1;
}
void releaseStream(u8** stream)
{
if (*stream) delete [] (*stream);
*stream = 0;
}
// atrac3plus radio
// 352kbps 0xff
// 320kbps 0xe8
// 256kbps 0xb9
// 192kbps 0x8b
// 160kbps 0x74
// 128kbps 0x5c
// 96kbps 0x45
// 64kbps 0x2e
// 48kbps 0x22
const u8 atrac3plusradio[] = {0xff, 0xe8, 0xb9, 0x8b, 0x74, 0x5c, 0x45, 0x2e, 0x22};
const int atrac3plusradiosize = sizeof(atrac3plusradio);
int convertStreamtoOMA(u8* audioStream, int audioSize, u8** outputStream)
{
if (!isHeader(audioStream, 0))
{
*outputStream = 0;
return 0;
}
u8 headerCode1 = audioStream[2];
u8 headerCode2 = audioStream[3];
if (headerCode1 == 0x28)
{
bool bsupported = false;
for (int i = 0; i < atrac3plusradiosize; i++) {
if (atrac3plusradio[i] == headerCode2)
{
bsupported = true;
break;
}
}
if (bsupported == false)
{
*outputStream = 0;
return 0;
}
}
else
{
*outputStream = 0;
return 0;
}
int frameSize = ((headerCode1 & 0x03) << 8) | (headerCode2 & 0xFF) * 8 + 0x10;
int numCompleteFrames = audioSize / (frameSize + 8);
int lastFrameSize = audioSize - (numCompleteFrames * (frameSize + 8));
int omaStreamSize = OMAHeaderSize + numCompleteFrames * frameSize + lastFrameSize;
// Allocate an OMA stream size large enough (better too large than too short)
if (audioSize > omaStreamSize) omaStreamSize = audioSize;
u8* oma = new u8[omaStreamSize];
int omapos = 0;
int audiopos = 0;
omapos += getOmaHeader(OMA_CODECID_ATRAC3P, 0, headerCode1, headerCode2, oma);
while (audioSize - audiopos > 8) {
// Skip 8 bytes frame header
audiopos += 8;
int nextHeader = getNextHeaderPosition(audioStream, audiopos, audioSize, frameSize);
u8* frame = audioStream + audiopos;
int framelimit = audioSize - audiopos;
if (nextHeader >= 0) {
framelimit = nextHeader - audiopos;
audiopos = nextHeader;
} else
audiopos = audioSize;
WriteBuf(oma, omapos, frame, framelimit);
}
*outputStream = oma;
return omapos;
}
int getChunkOffset(u8* riff, int limit, int chunkMagic, int offset) {
for (int i = offset; i <= limit - 8;) {
if (getBufValue((int*)riff, i) == chunkMagic)
return i;
// Move to next chunk
int chunkSize = getBufValue((int*)riff, i + 4);
i += chunkSize + 8;
}
return -1;
}
int convertRIFFtoOMA(u8* riff, int riffSize, u8** outputStream, int* readSize)
{
const int firstChunkOffset = 12;
int fmtChunkOffset = getChunkOffset(riff, riffSize, FMT_CHUNK_MAGIC, firstChunkOffset);
if (fmtChunkOffset < 0) {
*outputStream = 0;
return 0;
}
u8 codecId = getBufValue(riff, fmtChunkOffset + 0x30);
u8 headerCode0 = getBufValue(riff, fmtChunkOffset + 0x31);
u8 headerCode1 = getBufValue(riff, fmtChunkOffset + 0x32);
u8 headerCode2 = getBufValue(riff, fmtChunkOffset + 0x33);
bool bsupported = false;
u16 magic = getBufValue((u16*)riff, fmtChunkOffset + 0x08);
if (magic == AT3_MAGIC)
{
u8 key = getBufValue((u8*)riff, fmtChunkOffset + 0x11);
u16 channel = getBufValue((u16*)riff, fmtChunkOffset + 0x0a);
switch (key)
{
case 0x20:
{
// 66kpbs
codecId = 0;
headerCode0 = 0x02;
headerCode1 = 0x20;
headerCode2 = 0x18;
}
break;
case 0x40:
{
// 132kpbs
codecId = 0;
headerCode0 = 0x00;
headerCode1 = 0x20;
headerCode2 = 0x30;
}
break;
default:
{
// 105kpbs
codecId = 0;
headerCode0 = 0x00;
headerCode1 = 0x20;
headerCode2 = 0x26;
}
break;
}
if (channel == 2)
bsupported = true;
else
bsupported = false;
}
else if (magic == AT3_PLUS_MAGIC && headerCode0 == 0x00
&& headerCode1 == 0x28)
{
for (int i = 0; i < atrac3plusradiosize; i++) {
if (atrac3plusradio[i] == headerCode2)
{
bsupported = true;
break;
}
}
}
if (bsupported == false)
{
*outputStream = 0;
return 0;
}
int dataChunkOffset = getChunkOffset(riff, riffSize, DATA_CHUNK_MAGIC, firstChunkOffset);
if (dataChunkOffset < 0) {
*outputStream = 0;
return 0;
}
int dataSize = getBufValue((int*)riff, dataChunkOffset + 4);
int datapos = dataChunkOffset + 8;
u8* oma = new u8[OMAHeaderSize + dataSize];
int omapos = 0;
omapos += getOmaHeader(codecId, headerCode0, headerCode1, headerCode2, oma);
WriteBuf(oma, omapos, riff + datapos, dataSize);
*outputStream = oma;
if (readSize)
*readSize = OMAHeaderSize + riffSize - datapos;
return omapos;
}
int getOMANumberAudioChannels(u8* oma)
{
int headerParameters = getBufValue((int*)oma, 0x20);
int channels = (headerParameters >> 18) & 0x7;
return channels;
}
int getRIFFSize(u8* riff, int bufsize)
{
const int firstChunkOffset = 12;
int fmtChunkOffset = getChunkOffset(riff, bufsize, FMT_CHUNK_MAGIC, firstChunkOffset);
int dataChunkOffset = getChunkOffset(riff, bufsize, DATA_CHUNK_MAGIC, firstChunkOffset);
if (fmtChunkOffset < 0 || dataChunkOffset < 0)
return 0;
int dataSize = getBufValue((int*)riff, dataChunkOffset + 4);
return dataSize + dataChunkOffset + 8;
}
int getRIFFLoopNum(u8* riff, int bufsize, int *startsample, int *endsample)
{
const int firstChunkOffset = 12;
int dataChunkOffset = getChunkOffset(riff, bufsize, DATA_CHUNK_MAGIC, firstChunkOffset);
if (dataChunkOffset < 0)
return 0;
int smplChunkOffset = getChunkOffset(riff, dataChunkOffset, SMPL_CHUNK_MAGIC, firstChunkOffset);
if (smplChunkOffset < 0)
return 0;
int factChunkOffset = getChunkOffset(riff, dataChunkOffset, FACT_CHUNK_MAGIC, firstChunkOffset);
int atracSampleOffset = 0;
if (factChunkOffset >= 0) {
int factChunkSize = getBufValue((int*)riff, factChunkOffset + 4);
if (factChunkSize >= 8) {
atracSampleOffset = getBufValue((int*)riff, factChunkOffset + 12);
}
}
int smplChunkSize = getBufValue((int*)riff, smplChunkOffset + 4);
int checkNumLoops = getBufValue((int*)riff, smplChunkOffset + 36);
if (smplChunkSize >= 36 + checkNumLoops * 24)
{
// find loop info, simple return -1 now for endless loop
int numLoops = checkNumLoops;
int loopInfoAddr = smplChunkOffset + 44;
int loopcounts = (numLoops > 1) ? -1 : 0;
for (int i = 0; i < 1; i++) {
if (startsample)
*startsample = getBufValue((int*)riff, loopInfoAddr + 8) - atracSampleOffset;
if (endsample)
*endsample = getBufValue((int*)riff, loopInfoAddr + 12) - atracSampleOffset;
int playcount = getBufValue((int*)riff, loopInfoAddr + 20);
if (playcount != 1)
loopcounts = -1;
loopInfoAddr += 24;
}
return loopcounts;
}
return 0;
}
int getRIFFendSample(u8* riff, int bufsize)
{
const int firstChunkOffset = 12;
int dataChunkOffset = getChunkOffset(riff, bufsize, DATA_CHUNK_MAGIC, firstChunkOffset);
if (dataChunkOffset < 0)
return -1;
int factChunkOffset = getChunkOffset(riff, dataChunkOffset, FACT_CHUNK_MAGIC, firstChunkOffset);
if (factChunkOffset >= 0) {
int factChunkSize = getBufValue((int*)riff, factChunkOffset + 4);
if (factChunkSize >= 8) {
int endSample = getBufValue((int*)riff, factChunkOffset + 8);
return endSample;
}
}
return -1;
}
int getRIFFChannels(u8* riff, int bufsize)
{
const int firstChunkOffset = 12;
int fmtChunkOffset = getChunkOffset(riff, bufsize, FMT_CHUNK_MAGIC, firstChunkOffset);
if (fmtChunkOffset < 0)
return 0;
u16 channel = getBufValue((u16*)riff, fmtChunkOffset + 0x0a);
return channel;
}
} // namespace OMAConvert

27
Core/HW/OMAConvert.h Normal file
View File

@ -0,0 +1,27 @@
// It can simply convert a at3+ file or stream to oma format
// Thanks to JPCSP project
#pragma once
#include "../../Globals.h"
namespace OMAConvert {
// output OMA to outputStream, and return it's size. You need to release it by use releaseStream()
int convertStreamtoOMA(u8* audioStream, int audioSize, u8** outputStream);
// output OMA to outputStream, and return it's size. You need to release it by use releaseStream()
int convertRIFFtoOMA(u8* riff, int riffSize, u8** outputStream, int *readSize = 0);
void releaseStream(u8** stream);
int getOMANumberAudioChannels(u8* oma);
int getRIFFSize(u8* riff, int bufsize);
int getRIFFLoopNum(u8* riff, int bufsize, int *startsample = 0, int *endsample = 0);
int getRIFFendSample(u8* riff, int bufsize);
int getRIFFChannels(u8* riff, int bufsize);
} // namespace OMAConvert

523
Core/HW/audioPlayer.cpp Normal file
View File

@ -0,0 +1,523 @@
#ifdef _USE_DSHOW_
#include "audioPlayer.h"
#include <dshow.h>
#include <qedit.h>
#pragma comment(lib, "Strmiids.lib")
#pragma comment(lib, "Quartz.lib")
#include "OMAConvert.h"
#include <map>
#include "StdMutex.h"
#include "../Core/System.h"
#define JIF(x) if (FAILED(hr=(x))) \
{return false;}
#define KIF(x) if (FAILED(hr=(x))) \
{return hr;}
#define LIF(x) if (FAILED(hr=(x))) \
{}
// {2AE44C10-B451-4B01-9BBE-A5FBEF68C9D4}
static const GUID CLSID_AsyncStreamSource =
{ 0x2ae44c10, 0xb451, 0x4b01, { 0x9b, 0xbe, 0xa5, 0xfb, 0xef, 0x68, 0xc9, 0xd4 } };
// {268424D1-B6E9-4B28-8751-B7774F5ECF77}
static const GUID IID_IStreamSourceFilter =
{ 0x268424d1, 0xb6e9, 0x4b28, { 0x87, 0x51, 0xb7, 0x77, 0x4f, 0x5e, 0xcf, 0x77 } };
// We define the interface the app can use to program us
MIDL_INTERFACE("268424D1-B6E9-4B28-8751-B7774F5ECF77")
IStreamSourceFilter : public IFileSourceFilter
{
public:
virtual STDMETHODIMP LoadStream(void *stream, LONGLONG readSize, LONGLONG streamSize, AM_MEDIA_TYPE *pmt ) = 0;
virtual STDMETHODIMP AddStreamData(LONGLONG offset, void *stream, LONGLONG addSize) = 0;
virtual STDMETHODIMP GetStreamInfo(LONGLONG *readSize, LONGLONG *streamSize) = 0;
virtual STDMETHODIMP SetReadSize(LONGLONG readSize) = 0;
virtual BOOL STDMETHODCALLTYPE IsReadPassEnd() = 0;
};
HRESULT GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin)
{
IEnumPins *pEnum;
IPin *pPin;
pFilter->EnumPins(&pEnum);
while(pEnum->Next(1, &pPin, 0) == S_OK)
{
PIN_DIRECTION PinDirThis;
pPin->QueryDirection(&PinDirThis);
if (PinDir == PinDirThis)
{
pEnum->Release();
*ppPin = pPin;
return S_OK;
}
pPin->Release();
}
pEnum->Release();
return E_FAIL;
}
HRESULT ConnectFilters(IGraphBuilder *pGraph, IBaseFilter *pFirst, IBaseFilter *pSecond)
{
IPin *pOut = NULL, *pIn = NULL;
HRESULT hr = GetPin(pFirst, PINDIR_OUTPUT, &pOut);
if (FAILED(hr)) return hr;
hr = GetPin(pSecond, PINDIR_INPUT, &pIn);
if (FAILED(hr))
{
pOut->Release();
return E_FAIL;
}
hr = pGraph->Connect(pOut, pIn);
pIn->Release();
pOut->Release();
return hr;
}
class CSampleGrabberCallback : public ISampleGrabberCB
{
public:
CSampleGrabberCallback(audioPlayer *player)
{
m_player = player;
// 1MB round buffer size
m_bufsize = 0x100000;
m_buf = new u8[m_bufsize];
isNeedReset = true;
m_readPos = m_writePos = 0;
}
~CSampleGrabberCallback(){ if (m_buf) delete [] m_buf; }
STDMETHODIMP_(ULONG) AddRef() { return 2; }
STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
{
return S_OK;
}
STDMETHODIMP SampleCB(double Time, IMediaSample *pSample)
{
return S_OK;
}
STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long buflen)
{
m_mutex.lock();
if (isNeedReset) {
isNeedReset = false;
m_readPos = 0;
m_writePos = 0;
}
if (m_writePos + buflen <= m_bufsize) {
memcpy(m_buf + m_writePos, pBuffer, buflen);
} else {
int size = m_bufsize - m_writePos;
memcpy(m_buf + m_writePos, pBuffer, size);
memcpy(m_buf, pBuffer + size, buflen - size);
}
m_writePos = (m_writePos + buflen) % m_bufsize;
// check how much space left to write
int space = (m_readPos - m_writePos + m_bufsize) % m_bufsize;
m_mutex.unlock();
if (space < buflen * 3) {
m_player->pause();
}
return S_OK;
}
int getNextSamples(u8* buf, int wantedbufsize) {
int timecount = 0;
while (isNeedReset) {
Sleep(1);
timecount++;
if (timecount >= 10)
return 0;
}
m_mutex.lock();
// check how much space left to read
int space = (m_writePos - m_readPos + m_bufsize) % m_bufsize;
if (m_readPos + wantedbufsize <= m_bufsize) {
memcpy(buf, m_buf + m_readPos, wantedbufsize);
} else {
int size = m_bufsize - m_readPos;
memcpy(buf, m_buf + m_readPos, size);
memcpy(buf + size, m_buf, wantedbufsize - size);
}
int bytesgot = min(wantedbufsize, space);
m_readPos = (m_readPos + bytesgot) % m_bufsize;
// check how much space left to read
space = (m_writePos - m_readPos + m_bufsize) % m_bufsize;
m_mutex.unlock();
if (space < wantedbufsize * 3) {
m_player->play();
}
return bytesgot;
}
void setResetflag(bool reset) { isNeedReset = reset; }
private:
audioPlayer *m_player;
u8* m_buf;
int m_bufsize;
int m_readPos;
int m_writePos;
bool isNeedReset;
std::recursive_mutex m_mutex;
};
bool addSampleGrabber(IGraphBuilder *pGB, IBaseFilter *pSrc,
ISampleGrabberCB *callback, void **outgrabber)
{
HRESULT hr;
ISampleGrabber *pGrabber = 0;
IBaseFilter *pGrabberF = 0;
JIF(CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void **)&pGrabberF));
JIF(pGB->AddFilter(pGrabberF, L"Sample Grabber"));
JIF(pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber));
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Audio;
mt.subtype = MEDIASUBTYPE_PCM;
JIF(pGrabber->SetMediaType(&mt));
JIF(ConnectFilters(pGB, pSrc, pGrabberF));
pGrabberF->Release();
IBaseFilter *pNull = NULL;
JIF(CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pNull));
JIF(pGB->AddFilter(pNull, L"NullRenderer"));
JIF(ConnectFilters(pGB, pGrabberF, pNull));
// Set one-shot mode and buffering.
JIF(pGrabber->SetOneShot(FALSE));
JIF(pGrabber->SetBufferSamples(TRUE));
JIF(pGrabber->SetCallback(callback, 1));
// close the clock to run as fast as possible
IMediaFilter *pMediaFilter = 0;
pGB->QueryInterface(IID_IMediaFilter, (void**)&pMediaFilter);
pMediaFilter->SetSyncSource(0);
pMediaFilter->Release();
*outgrabber = (void*)pGrabber;
return true;
}
static volatile int g_volume = 60;
audioPlayer::audioPlayer(void)
{
m_playmode = -1;
m_volume = g_volume;
m_pMC = 0;
m_pGB = 0;
m_pMS = 0;
m_pGrabber = 0;
m_pGrabberCB = 0;
m_pStreamReader = 0;
}
audioPlayer::~audioPlayer(void)
{
closeMedia();
}
bool audioPlayer::load(const char* filename, u8* stream, int readSize, int streamSize, bool samplebuffermode, bool isWave)
{
if (m_playmode == 1)
return false;
WCHAR wstrfilename[MAX_PATH + 1];
MultiByteToWideChar( CP_ACP, 0, filename ? filename : "stream", -1,
wstrfilename, MAX_PATH );
wstrfilename[MAX_PATH] = 0;
HRESULT hr;
JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&m_pGB));
IGraphBuilder *pGB=(IGraphBuilder*)m_pGB;
JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC));
JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&m_pMS));
IBaseFilter *pSrc = 0;
JIF(CoCreateInstance(CLSID_AsyncStreamSource, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pSrc));
JIF(pGB->AddFilter(pSrc,wstrfilename));
JIF(pSrc->QueryInterface(IID_IStreamSourceFilter,(void**)&m_pStreamReader));
IStreamSourceFilter* pStreamReader = (IStreamSourceFilter*)m_pStreamReader;
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(mt));
mt.majortype = MEDIATYPE_Stream;
mt.subtype = isWave ? MEDIASUBTYPE_WAVE : MEDIASUBTYPE_NULL;
if (filename) {
JIF(pStreamReader->Load(wstrfilename, &mt));
} else {
JIF(pStreamReader->LoadStream(stream, readSize, streamSize, &mt));
}
if (samplebuffermode) {
m_pGrabberCB = new CSampleGrabberCallback(this);
addSampleGrabber(pGB, pSrc, (ISampleGrabberCB*)m_pGrabberCB, &m_pGrabber);
pSrc->Release();
m_playmode = 0;
play();
} else {
IPin *pOut;
JIF(GetPin(pSrc, PINDIR_OUTPUT, &pOut));
pSrc->Release();
JIF(pGB->Render(pOut));
pOut->Release();
setVolume(m_volume);
m_playmode = 0;
}
IMediaSeeking *pMS=(IMediaSeeking*)m_pMS;
m_startpos = 0;
JIF(pMS->GetStopPosition(&m_endpos));
return true;
}
bool audioPlayer::play()
{
if ((!m_pMC) || (m_playmode == -1))
return false;
IMediaControl *pMC = (IMediaControl*)m_pMC;
HRESULT hr;
JIF(pMC->Run());
m_playmode = 1;
return true;
}
bool audioPlayer::pause()
{
if ((!m_pMC) || (m_playmode == -1))
return false;
IMediaControl *pMC = (IMediaControl*)m_pMC;
HRESULT hr;
JIF(pMC->Pause());
m_playmode = 2;
return true;
}
bool audioPlayer::stop()
{
if ((!m_pMC) || (m_playmode <= 0))
return true;
IMediaControl *pMC = (IMediaControl*)m_pMC;
HRESULT hr;
JIF(pMC->Stop());
m_playmode = 0;
return true;
}
bool audioPlayer::closeMedia()
{
if (m_pGrabber) {
ISampleGrabber *pGrabber = (ISampleGrabber *)m_pGrabber;
pGrabber->SetCallback(0, 1);
pGrabber->Release();
}
if (m_pGrabberCB)
delete ((CSampleGrabberCallback*)m_pGrabberCB);
m_pGrabber = 0;
m_pGrabberCB = 0;
stop();
if (m_pMS)
((IMediaSeeking*)m_pMS)->Release();
if (m_pMC)
((IMediaControl*)m_pMC)->Release();
if (m_pStreamReader)
((IStreamSourceFilter*)m_pStreamReader)->Release();
if (m_pGB)
((IGraphBuilder*)m_pGB)->Release();
m_pMS = 0;
m_pMC = 0;
m_pStreamReader = 0;
m_pGB = 0;
m_playmode = -1;
return true;
}
bool audioPlayer::setVolume(int volume)
{
if ((volume < 0) || (volume > 100))
return false;
m_volume = volume;
if (!m_pGB)
return true;
IBasicAudio *pBA = NULL;
HRESULT hr;
int now = -(int)(exp(log((double)10001)/100*(100-volume))-1+0.5);
JIF(((IGraphBuilder*)m_pGB)->QueryInterface(IID_IBasicAudio, (void**)&pBA));
pBA->put_Volume(now);
pBA->Release();
return true;
}
bool audioPlayer::isEnd(long *mstimetoend)
{
if (!m_pMS)
return false;
IMediaSeeking *pMS=(IMediaSeeking*)m_pMS;
LONGLONG curpos;
HRESULT hr;
JIF(pMS->GetCurrentPosition(&curpos));
if (curpos >= m_endpos)
return true;
if (mstimetoend)
*mstimetoend = (m_endpos - curpos) / 10000;
return false;
}
bool audioPlayer::setPlayPos(long ms)
{
if (!m_pGB)
return false;
HRESULT hr;
IMediaSeeking *pMS = (IMediaSeeking*)m_pMS;
LONGLONG pos = ((LONGLONG)ms)*10000;
if (!m_pGrabberCB) {
JIF(pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning,
NULL, AM_SEEKING_NoPositioning));
} else {
pause();
JIF(pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning,
NULL, AM_SEEKING_NoPositioning));
((CSampleGrabberCallback*)m_pGrabberCB)->setResetflag(true);
play();
}
return true;
}
bool audioPlayer::getPlayPos(long *ms)
{
if (!m_pGB)
return false;
HRESULT hr;
IMediaSeeking *pMS = (IMediaSeeking*)m_pMS;
LONGLONG curpos;
JIF(pMS->GetCurrentPosition(&curpos));
if (ms)
*ms = curpos / 10000;
return true;
}
int audioPlayer::getNextSamples(u8* buf, int wantedbufsize)
{
if (!m_pGrabberCB || !m_pMC) {
memset(buf, 0, wantedbufsize);
return wantedbufsize;
}
return ((CSampleGrabberCallback*)m_pGrabberCB)->getNextSamples(buf, wantedbufsize);
}
////////////////////////////////////////////////////////////////////////
// audioEngine
bool audioEngine::loadRIFFStream(u8* stream, int streamsize, int atracID)
{
u8 *oma = 0;
m_ID = atracID;
m_channel = OMAConvert::getRIFFChannels(stream, streamsize);
bool bResult = false;
if (m_channel != 1) {
int readsize = 0;
int omasize = OMAConvert::convertRIFFtoOMA(stream, streamsize, &oma, &readsize);
if (omasize > 0){
bResult = load(0, oma, readsize, omasize, true);
OMAConvert::releaseStream(&oma);
}
}
return bResult;
}
bool audioEngine::closeStream()
{
bool bResult = closeMedia();
m_ID = -1;
return bResult;
}
bool audioEngine::setPlaySample(int sample)
{
return setPlayPos(((s64)sample) * 1000 / 44100);
}
void audioEngine::addStreamData(int offset, u8* buf, int size, int cursample)
{
if ((!m_pGB) || (m_channel == 1))
return;
IStreamSourceFilter* pStreamReader = (IStreamSourceFilter*)m_pStreamReader;
pStreamReader->AddStreamData(offset, buf, size);
bool bsetpos = pStreamReader->IsReadPassEnd();
if (bsetpos)
setPlaySample(cursample);
}
//////////////////////////////////////////////////////////////////////////////
//
std::map<int, audioEngine*> audioMap;
std::recursive_mutex atracsection;
void addAtrac3Audio(u8* stream, int streamsize, int atracID)
{
if (audioMap.find(atracID) != audioMap.end())
return;
audioEngine *temp = new audioEngine();
bool bResult = temp->loadRIFFStream(stream, streamsize, atracID);
atracsection.lock();
audioMap[atracID] = temp;
atracsection.unlock();
if (!bResult)
temp->closeMedia();
}
audioEngine* getaudioEngineByID(int atracID)
{
if (audioMap.find(atracID) == audioMap.end()) {
return NULL;
}
return audioMap[atracID];
}
void deleteAtrac3Audio(int atracID)
{
atracsection.lock();
if (audioMap.find(atracID) != audioMap.end()) {
delete audioMap[atracID];
audioMap.erase(atracID);
}
atracsection.unlock();
}
void initaudioEngine()
{
CoInitialize(0);
}
void shutdownEngine()
{
atracsection.lock();
for (auto it = audioMap.begin(); it != audioMap.end(); ++it) {
delete it->second;
}
audioMap.clear();
atracsection.unlock();
CoUninitialize();
system("cleanAudios.bat");
}
#endif // _USE_DSHOW_

60
Core/HW/audioPlayer.h Normal file
View File

@ -0,0 +1,60 @@
#pragma once
#ifdef _USE_DSHOW_
#include "../../Globals.h"
class audioPlayer
{
public:
audioPlayer(void);
~audioPlayer(void);
// if samplebuffermode is true, it would provide sample buffers instead play sounds
// if filename is set, then load a file, otherwise load from stream
bool load(const char* filename, u8* stream = 0, int readSize = 0, int streamSize = 0,
bool samplebuffermode = false, bool isWave = false);
bool play();
bool pause();
bool stop();
bool closeMedia();
bool setVolume(int volume);
bool isEnd(long *mstimetoend = 0);
bool setPlayPos(long ms);
bool getPlayPos(long *ms);
int getNextSamples(u8* buf, int wantedbufsize);
protected:
void *m_pGB;
void *m_pMC;
void *m_pMS;
void *m_pStreamReader;
void *m_pGrabber;
void *m_pGrabberCB;
// 0 for stop, 1 for playing, 2 for pause, -1 for not loaded files
int m_playmode;
int m_volume;
protected:
s64 m_startpos;
s64 m_endpos;
};
class audioEngine: public audioPlayer{
public:
audioEngine(void):audioPlayer(), m_ID(-1){}
~audioEngine(void){ closeStream();}
bool loadRIFFStream(u8* stream, int streamsize, int atracID);
bool closeStream();
bool setPlaySample(int sample);
void addStreamData(int offset, u8* buf, int size, int cursample);
private:
int m_ID;
int m_channel;
};
void addAtrac3Audio(u8* stream, int streamsize, int atracID);
audioEngine* getaudioEngineByID(int atracID);
void deleteAtrac3Audio(int atracID);
void initaudioEngine();
void shutdownEngine();
#endif // _USE_DSHOW_