mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #1803 from oioitff/atrac3plus
Add atrac3plus filter for windows
This commit is contained in:
commit
a1060ffabd
22 changed files with 4020 additions and 13 deletions
|
@ -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>
|
||||
|
@ -228,8 +228,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" />
|
||||
|
@ -404,7 +406,10 @@
|
|||
<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\qeditsimple.h" />
|
||||
<ClInclude Include="HW\SasAudio.h" />
|
||||
<ClInclude Include="HW\MemoryStick.h" />
|
||||
<ClInclude Include="Loaders.h" />
|
||||
|
|
|
@ -74,6 +74,10 @@ extern "C" {
|
|||
}
|
||||
#endif // USE_FFMPEG
|
||||
|
||||
#ifdef _USE_DSHOW_
|
||||
#include "../HW/audioPlayer.h"
|
||||
#endif // _USE_DSHOW_
|
||||
|
||||
struct InputBuffer {
|
||||
u32 addr;
|
||||
u32 size;
|
||||
|
@ -113,11 +117,21 @@ struct Atrac {
|
|||
}
|
||||
|
||||
~Atrac() {
|
||||
CleanStuff();
|
||||
}
|
||||
|
||||
void CleanStuff() {
|
||||
#ifdef USE_FFMPEG
|
||||
ReleaseFFMPEGContext();
|
||||
#endif // USE_FFMPEG
|
||||
|
||||
#ifdef _USE_DSHOW_
|
||||
deleteAtrac3Audio(atracID);
|
||||
#endif // _USE_DSHOW_
|
||||
|
||||
if (data_buf)
|
||||
delete [] data_buf;
|
||||
data_buf = 0;
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p) {
|
||||
|
@ -128,6 +142,11 @@ struct Atrac {
|
|||
p.Do(first);
|
||||
p.Do(atracBufSize);
|
||||
p.Do(codeType);
|
||||
|
||||
p.Do(currentSample);
|
||||
p.Do(endSample);
|
||||
p.Do(firstSampleoffset);
|
||||
|
||||
u32 has_data_buf = data_buf != NULL;
|
||||
p.Do(has_data_buf);
|
||||
if (has_data_buf) {
|
||||
|
@ -147,10 +166,6 @@ struct Atrac {
|
|||
p.Do(atracBitrate);
|
||||
p.Do(atracBytesPerFrame);
|
||||
|
||||
p.Do(currentSample);
|
||||
p.Do(endSample);
|
||||
p.Do(firstSampleoffset);
|
||||
|
||||
p.Do(loopinfo);
|
||||
p.Do(loopinfoNum);
|
||||
|
||||
|
@ -254,6 +269,11 @@ void __AtracInit() {
|
|||
avcodec_register_all();
|
||||
av_register_all();
|
||||
#endif // USE_FFMPEG
|
||||
|
||||
#ifdef _USE_DSHOW_
|
||||
initaudioEngine();
|
||||
#endif //_USE_DSHOW_
|
||||
|
||||
}
|
||||
|
||||
void __AtracDoState(PointerWrap &p) {
|
||||
|
@ -268,6 +288,9 @@ void __AtracShutdown() {
|
|||
delete it->second;
|
||||
}
|
||||
atracMap.clear();
|
||||
#ifdef _USE_DSHOW_
|
||||
shutdownEngine();
|
||||
#endif // _USE_DSHOW_
|
||||
}
|
||||
|
||||
Atrac *getAtrac(int atracID) {
|
||||
|
@ -447,6 +470,13 @@ u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd)
|
|||
int addbytes = std::min(bytesToAdd, atrac->first.filesize - atrac->first.fileoffset);
|
||||
Memory::Memcpy(atrac->data_buf + atrac->first.fileoffset, atrac->first.addr + atrac->first.offset, addbytes);
|
||||
}
|
||||
#ifdef _USE_DSHOW_
|
||||
audioEngine *engine = getaudioEngineByID(atracID);
|
||||
if (engine && bytesToAdd > 0) {
|
||||
engine->addStreamData(atrac->first.fileoffset - atrac->firstSampleoffset + 96, Memory::GetPointer(atrac->first.addr + atrac->first.offset),
|
||||
bytesToAdd, atrac->currentSample);
|
||||
}
|
||||
#endif
|
||||
atrac->first.size += bytesToAdd;
|
||||
if (atrac->first.size > atrac->first.filesize)
|
||||
atrac->first.size = atrac->first.filesize;
|
||||
|
@ -462,6 +492,10 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF
|
|||
DEBUG_LOG(HLE, "sceAtracDecodeData(%i, %08x, %08x, %08x, %08x)", atracID, outAddr, numSamplesAddr, finishFlagAddr, remainAddr);
|
||||
Atrac *atrac = getAtrac(atracID);
|
||||
|
||||
#ifdef _USE_DSHOW_
|
||||
audioEngine *engine = getaudioEngineByID(atracID);
|
||||
#endif // _USE_DSHOW_
|
||||
|
||||
u32 ret = 0;
|
||||
if (atrac != NULL) {
|
||||
// We already passed the end - return an error (many games check for this.)
|
||||
|
@ -511,6 +545,24 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF
|
|||
|
||||
} else
|
||||
#endif // USE_FFMPEG
|
||||
#ifdef _USE_DSHOW_
|
||||
if (engine) {
|
||||
static s16 buf[ATRAC_MAX_SAMPLES * 2];
|
||||
int gotsize = engine->getNextSamples((u8*)buf, ATRAC_MAX_SAMPLES * sizeof(s16) * atrac->atracChannels);
|
||||
numSamples = gotsize / sizeof(s16) / atrac->atracChannels;
|
||||
s16* in = buf;
|
||||
s16* out = (s16*)Memory::GetPointer(outAddr);
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
s16 sampleL = *in++;
|
||||
s16 sampleR = sampleL;
|
||||
if (atrac->atracChannels == 2)
|
||||
sampleR = *in++;
|
||||
*out++ = sampleL;
|
||||
if (atrac->atracOutputChannels == 2)
|
||||
*out++ = sampleR;
|
||||
}
|
||||
} else
|
||||
#endif // _USE_DSHOW
|
||||
{
|
||||
numSamples = atrac->endSample - atrac->currentSample;
|
||||
if (atrac->currentSample >= atrac->endSample) {
|
||||
|
@ -534,6 +586,10 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF
|
|||
if (atrac->loopNum != 0 && (atrac->currentSample >= atrac->loopEndSample ||
|
||||
(numSamples == 0 && atrac->first.size >= atrac->first.filesize))) {
|
||||
atrac->currentSample = atrac->loopStartSample;
|
||||
#ifdef _USE_DSHOW_
|
||||
if (engine)
|
||||
engine->setPlaySample(atrac->currentSample);
|
||||
#endif // _USE_DSHOW
|
||||
if (atrac->loopNum > 0)
|
||||
atrac->loopNum --;
|
||||
} else if (atrac->currentSample >= atrac->endSample ||
|
||||
|
@ -784,6 +840,13 @@ u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFirstBuf,
|
|||
//return -1;
|
||||
} else {
|
||||
atrac->currentSample = sample;
|
||||
#ifdef _USE_DSHOW_
|
||||
audioEngine *engine = getaudioEngineByID(atracID);
|
||||
if (engine != NULL)
|
||||
{
|
||||
engine->setPlaySample(sample);
|
||||
}
|
||||
#endif // _USE_DSHOW_
|
||||
#ifdef USE_FFMPEG
|
||||
if (atrac->codeType == PSP_MODE_AT_3 && atrac->pCodecCtx) {
|
||||
atrac->SeekToSample(sample);
|
||||
|
@ -829,6 +892,17 @@ int64_t _AtracSeekbuffer(void *opaque, int64_t offset, int whence)
|
|||
|
||||
int __AtracSetContext(Atrac *atrac, u32 buffer, u32 bufferSize)
|
||||
{
|
||||
#ifdef _USE_DSHOW_
|
||||
if (atrac->codeType == PSP_MODE_AT_3_PLUS && atrac->atracChannels != 1) {
|
||||
addAtrac3Audio(atrac->data_buf, atrac->first.size, atrac->atracID);
|
||||
if (atrac->currentSample != 0) {
|
||||
audioEngine *engine = getaudioEngineByID(atrac->atracID);
|
||||
if (engine)
|
||||
engine->setPlaySample(atrac->currentSample);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif // _USE_DSHOW_
|
||||
#ifdef USE_FFMPEG
|
||||
u8* tempbuf = (u8*)av_malloc(atrac->atracBufSize);
|
||||
|
||||
|
@ -910,22 +984,30 @@ int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize)
|
|||
atrac->first.writableBytes = (u32)std::max((int)bufferSize - (int)atrac->first.size, 0);
|
||||
atrac->first.offset = atrac->first.size;
|
||||
|
||||
// some games may reuse an atracID for playing sound
|
||||
atrac->CleanStuff();
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
if (atrac->codeType == PSP_MODE_AT_3) {
|
||||
WARN_LOG(HLE, "This is an atrac3 audio");
|
||||
|
||||
// some games may reuse an atracID for playing sound
|
||||
atrac->ReleaseFFMPEGContext();
|
||||
|
||||
if (atrac->data_buf)
|
||||
delete [] atrac->data_buf;
|
||||
|
||||
atrac->data_buf = new u8[atrac->first.filesize];
|
||||
Memory::Memcpy(atrac->data_buf, buffer, std::min(bufferSize, atrac->first.filesize));
|
||||
|
||||
return __AtracSetContext(atrac, buffer, bufferSize);
|
||||
} else if (atrac->codeType == PSP_MODE_AT_3_PLUS)
|
||||
} else if (atrac->codeType == PSP_MODE_AT_3_PLUS) {
|
||||
WARN_LOG(HLE, "This is an atrac3+ audio");
|
||||
#ifdef _USE_DSHOW_
|
||||
if (atrac->atracChannels == 1) {
|
||||
WARN_LOG(HLE, "Unsupported mono atrac3+ audio!");
|
||||
} else {
|
||||
atrac->data_buf = new u8[atrac->first.filesize];
|
||||
Memory::Memcpy(atrac->data_buf, buffer, std::min(bufferSize, atrac->first.filesize));
|
||||
|
||||
return __AtracSetContext(atrac, buffer, bufferSize);
|
||||
}
|
||||
#endif // _USE_DSHOW
|
||||
}
|
||||
#endif // USE_FFMPEG
|
||||
|
||||
return 0;
|
||||
|
|
358
Core/HW/OMAConvert.cpp
Normal file
358
Core/HW/OMAConvert.cpp
Normal 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
27
Core/HW/OMAConvert.h
Normal 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
523
Core/HW/audioPlayer.cpp
Normal file
|
@ -0,0 +1,523 @@
|
|||
#ifdef _USE_DSHOW_
|
||||
|
||||
#include "audioPlayer.h"
|
||||
#include <dshow.h>
|
||||
#include "qeditsimple.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
60
Core/HW/audioPlayer.h
Normal 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_
|
381
Core/HW/qeditsimple.h
Normal file
381
Core/HW/qeditsimple.h
Normal file
|
@ -0,0 +1,381 @@
|
|||
// it's a simple mirror for directshow qedit.h
|
||||
|
||||
#ifndef __QEDIT_SIMPLE_H__
|
||||
#define __QEDIT_SIMPLE_H__
|
||||
|
||||
#ifndef __ISampleGrabberCB_FWD_DEFINED__
|
||||
#define __ISampleGrabberCB_FWD_DEFINED__
|
||||
typedef interface ISampleGrabberCB ISampleGrabberCB;
|
||||
#endif /* __ISampleGrabberCB_FWD_DEFINED__ */
|
||||
|
||||
|
||||
#ifndef __ISampleGrabber_FWD_DEFINED__
|
||||
#define __ISampleGrabber_FWD_DEFINED__
|
||||
typedef interface ISampleGrabber ISampleGrabber;
|
||||
#endif /* __ISampleGrabber_FWD_DEFINED__ */
|
||||
|
||||
EXTERN_C const CLSID CLSID_SampleGrabber;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
class DECLSPEC_UUID("C1F400A0-3F08-11d3-9F0B-006008039E37")
|
||||
SampleGrabber;
|
||||
#endif
|
||||
|
||||
EXTERN_C const CLSID CLSID_NullRenderer;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
class DECLSPEC_UUID("C1F400A4-3F08-11d3-9F0B-006008039E37")
|
||||
NullRenderer;
|
||||
#endif
|
||||
|
||||
#ifndef __ISampleGrabberCB_INTERFACE_DEFINED__
|
||||
#define __ISampleGrabberCB_INTERFACE_DEFINED__
|
||||
|
||||
/* interface ISampleGrabberCB */
|
||||
/* [unique][helpstring][local][uuid][object] */
|
||||
|
||||
|
||||
EXTERN_C const IID IID_ISampleGrabberCB;
|
||||
|
||||
#if defined(__cplusplus) && !defined(CINTERFACE)
|
||||
|
||||
MIDL_INTERFACE("0579154A-2B53-4994-B0D0-E773148EFF85")
|
||||
ISampleGrabberCB : public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE SampleCB(
|
||||
double SampleTime,
|
||||
IMediaSample *pSample) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE BufferCB(
|
||||
double SampleTime,
|
||||
BYTE *pBuffer,
|
||||
long BufferLen) = 0;
|
||||
|
||||
};
|
||||
|
||||
#else /* C style interface */
|
||||
|
||||
typedef struct ISampleGrabberCBVtbl
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
|
||||
ISampleGrabberCB * This,
|
||||
/* [in] */ REFIID riid,
|
||||
/* [iid_is][out] */ void **ppvObject);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *AddRef )(
|
||||
ISampleGrabberCB * This);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *Release )(
|
||||
ISampleGrabberCB * This);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *SampleCB )(
|
||||
ISampleGrabberCB * This,
|
||||
double SampleTime,
|
||||
IMediaSample *pSample);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *BufferCB )(
|
||||
ISampleGrabberCB * This,
|
||||
double SampleTime,
|
||||
BYTE *pBuffer,
|
||||
long BufferLen);
|
||||
|
||||
END_INTERFACE
|
||||
} ISampleGrabberCBVtbl;
|
||||
|
||||
interface ISampleGrabberCB
|
||||
{
|
||||
CONST_VTBL struct ISampleGrabberCBVtbl *lpVtbl;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef COBJMACROS
|
||||
|
||||
|
||||
#define ISampleGrabberCB_QueryInterface(This,riid,ppvObject) \
|
||||
(This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
|
||||
|
||||
#define ISampleGrabberCB_AddRef(This) \
|
||||
(This)->lpVtbl -> AddRef(This)
|
||||
|
||||
#define ISampleGrabberCB_Release(This) \
|
||||
(This)->lpVtbl -> Release(This)
|
||||
|
||||
|
||||
#define ISampleGrabberCB_SampleCB(This,SampleTime,pSample) \
|
||||
(This)->lpVtbl -> SampleCB(This,SampleTime,pSample)
|
||||
|
||||
#define ISampleGrabberCB_BufferCB(This,SampleTime,pBuffer,BufferLen) \
|
||||
(This)->lpVtbl -> BufferCB(This,SampleTime,pBuffer,BufferLen)
|
||||
|
||||
#endif /* COBJMACROS */
|
||||
|
||||
|
||||
#endif /* C style interface */
|
||||
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ISampleGrabberCB_SampleCB_Proxy(
|
||||
ISampleGrabberCB * This,
|
||||
double SampleTime,
|
||||
IMediaSample *pSample);
|
||||
|
||||
|
||||
void __RPC_STUB ISampleGrabberCB_SampleCB_Stub(
|
||||
IRpcStubBuffer *This,
|
||||
IRpcChannelBuffer *_pRpcChannelBuffer,
|
||||
PRPC_MESSAGE _pRpcMessage,
|
||||
DWORD *_pdwStubPhase);
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ISampleGrabberCB_BufferCB_Proxy(
|
||||
ISampleGrabberCB * This,
|
||||
double SampleTime,
|
||||
BYTE *pBuffer,
|
||||
long BufferLen);
|
||||
|
||||
|
||||
void __RPC_STUB ISampleGrabberCB_BufferCB_Stub(
|
||||
IRpcStubBuffer *This,
|
||||
IRpcChannelBuffer *_pRpcChannelBuffer,
|
||||
PRPC_MESSAGE _pRpcMessage,
|
||||
DWORD *_pdwStubPhase);
|
||||
|
||||
|
||||
|
||||
#endif /* __ISampleGrabberCB_INTERFACE_DEFINED__ */
|
||||
|
||||
|
||||
#ifndef __ISampleGrabber_INTERFACE_DEFINED__
|
||||
#define __ISampleGrabber_INTERFACE_DEFINED__
|
||||
|
||||
/* interface ISampleGrabber */
|
||||
/* [unique][helpstring][local][uuid][object] */
|
||||
|
||||
|
||||
EXTERN_C const IID IID_ISampleGrabber;
|
||||
|
||||
#if defined(__cplusplus) && !defined(CINTERFACE)
|
||||
|
||||
MIDL_INTERFACE("6B652FFF-11FE-4fce-92AD-0266B5D7C78F")
|
||||
ISampleGrabber : public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE SetOneShot(
|
||||
BOOL OneShot) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetMediaType(
|
||||
const AM_MEDIA_TYPE *pType) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType(
|
||||
AM_MEDIA_TYPE *pType) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetBufferSamples(
|
||||
BOOL BufferThem) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer(
|
||||
/* [out][in] */ long *pBufferSize,
|
||||
/* [out] */ long *pBuffer) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetCurrentSample(
|
||||
/* [retval][out] */ IMediaSample **ppSample) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetCallback(
|
||||
ISampleGrabberCB *pCallback,
|
||||
long WhichMethodToCallback) = 0;
|
||||
|
||||
};
|
||||
|
||||
#else /* C style interface */
|
||||
|
||||
typedef struct ISampleGrabberVtbl
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
|
||||
ISampleGrabber * This,
|
||||
/* [in] */ REFIID riid,
|
||||
/* [iid_is][out] */ void **ppvObject);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *AddRef )(
|
||||
ISampleGrabber * This);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *Release )(
|
||||
ISampleGrabber * This);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *SetOneShot )(
|
||||
ISampleGrabber * This,
|
||||
BOOL OneShot);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *SetMediaType )(
|
||||
ISampleGrabber * This,
|
||||
const AM_MEDIA_TYPE *pType);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *GetConnectedMediaType )(
|
||||
ISampleGrabber * This,
|
||||
AM_MEDIA_TYPE *pType);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *SetBufferSamples )(
|
||||
ISampleGrabber * This,
|
||||
BOOL BufferThem);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *GetCurrentBuffer )(
|
||||
ISampleGrabber * This,
|
||||
/* [out][in] */ long *pBufferSize,
|
||||
/* [out] */ long *pBuffer);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *GetCurrentSample )(
|
||||
ISampleGrabber * This,
|
||||
/* [retval][out] */ IMediaSample **ppSample);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *SetCallback )(
|
||||
ISampleGrabber * This,
|
||||
ISampleGrabberCB *pCallback,
|
||||
long WhichMethodToCallback);
|
||||
|
||||
END_INTERFACE
|
||||
} ISampleGrabberVtbl;
|
||||
|
||||
interface ISampleGrabber
|
||||
{
|
||||
CONST_VTBL struct ISampleGrabberVtbl *lpVtbl;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef COBJMACROS
|
||||
|
||||
|
||||
#define ISampleGrabber_QueryInterface(This,riid,ppvObject) \
|
||||
(This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
|
||||
|
||||
#define ISampleGrabber_AddRef(This) \
|
||||
(This)->lpVtbl -> AddRef(This)
|
||||
|
||||
#define ISampleGrabber_Release(This) \
|
||||
(This)->lpVtbl -> Release(This)
|
||||
|
||||
|
||||
#define ISampleGrabber_SetOneShot(This,OneShot) \
|
||||
(This)->lpVtbl -> SetOneShot(This,OneShot)
|
||||
|
||||
#define ISampleGrabber_SetMediaType(This,pType) \
|
||||
(This)->lpVtbl -> SetMediaType(This,pType)
|
||||
|
||||
#define ISampleGrabber_GetConnectedMediaType(This,pType) \
|
||||
(This)->lpVtbl -> GetConnectedMediaType(This,pType)
|
||||
|
||||
#define ISampleGrabber_SetBufferSamples(This,BufferThem) \
|
||||
(This)->lpVtbl -> SetBufferSamples(This,BufferThem)
|
||||
|
||||
#define ISampleGrabber_GetCurrentBuffer(This,pBufferSize,pBuffer) \
|
||||
(This)->lpVtbl -> GetCurrentBuffer(This,pBufferSize,pBuffer)
|
||||
|
||||
#define ISampleGrabber_GetCurrentSample(This,ppSample) \
|
||||
(This)->lpVtbl -> GetCurrentSample(This,ppSample)
|
||||
|
||||
#define ISampleGrabber_SetCallback(This,pCallback,WhichMethodToCallback) \
|
||||
(This)->lpVtbl -> SetCallback(This,pCallback,WhichMethodToCallback)
|
||||
|
||||
#endif /* COBJMACROS */
|
||||
|
||||
|
||||
#endif /* C style interface */
|
||||
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ISampleGrabber_SetOneShot_Proxy(
|
||||
ISampleGrabber * This,
|
||||
BOOL OneShot);
|
||||
|
||||
|
||||
void __RPC_STUB ISampleGrabber_SetOneShot_Stub(
|
||||
IRpcStubBuffer *This,
|
||||
IRpcChannelBuffer *_pRpcChannelBuffer,
|
||||
PRPC_MESSAGE _pRpcMessage,
|
||||
DWORD *_pdwStubPhase);
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ISampleGrabber_SetMediaType_Proxy(
|
||||
ISampleGrabber * This,
|
||||
const AM_MEDIA_TYPE *pType);
|
||||
|
||||
|
||||
void __RPC_STUB ISampleGrabber_SetMediaType_Stub(
|
||||
IRpcStubBuffer *This,
|
||||
IRpcChannelBuffer *_pRpcChannelBuffer,
|
||||
PRPC_MESSAGE _pRpcMessage,
|
||||
DWORD *_pdwStubPhase);
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ISampleGrabber_GetConnectedMediaType_Proxy(
|
||||
ISampleGrabber * This,
|
||||
AM_MEDIA_TYPE *pType);
|
||||
|
||||
|
||||
void __RPC_STUB ISampleGrabber_GetConnectedMediaType_Stub(
|
||||
IRpcStubBuffer *This,
|
||||
IRpcChannelBuffer *_pRpcChannelBuffer,
|
||||
PRPC_MESSAGE _pRpcMessage,
|
||||
DWORD *_pdwStubPhase);
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ISampleGrabber_SetBufferSamples_Proxy(
|
||||
ISampleGrabber * This,
|
||||
BOOL BufferThem);
|
||||
|
||||
|
||||
void __RPC_STUB ISampleGrabber_SetBufferSamples_Stub(
|
||||
IRpcStubBuffer *This,
|
||||
IRpcChannelBuffer *_pRpcChannelBuffer,
|
||||
PRPC_MESSAGE _pRpcMessage,
|
||||
DWORD *_pdwStubPhase);
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ISampleGrabber_GetCurrentBuffer_Proxy(
|
||||
ISampleGrabber * This,
|
||||
/* [out][in] */ long *pBufferSize,
|
||||
/* [out] */ long *pBuffer);
|
||||
|
||||
|
||||
void __RPC_STUB ISampleGrabber_GetCurrentBuffer_Stub(
|
||||
IRpcStubBuffer *This,
|
||||
IRpcChannelBuffer *_pRpcChannelBuffer,
|
||||
PRPC_MESSAGE _pRpcMessage,
|
||||
DWORD *_pdwStubPhase);
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ISampleGrabber_GetCurrentSample_Proxy(
|
||||
ISampleGrabber * This,
|
||||
/* [retval][out] */ IMediaSample **ppSample);
|
||||
|
||||
|
||||
void __RPC_STUB ISampleGrabber_GetCurrentSample_Stub(
|
||||
IRpcStubBuffer *This,
|
||||
IRpcChannelBuffer *_pRpcChannelBuffer,
|
||||
PRPC_MESSAGE _pRpcMessage,
|
||||
DWORD *_pdwStubPhase);
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ISampleGrabber_SetCallback_Proxy(
|
||||
ISampleGrabber * This,
|
||||
ISampleGrabberCB *pCallback,
|
||||
long WhichMethodToCallback);
|
||||
|
||||
|
||||
void __RPC_STUB ISampleGrabber_SetCallback_Stub(
|
||||
IRpcStubBuffer *This,
|
||||
IRpcChannelBuffer *_pRpcChannelBuffer,
|
||||
PRPC_MESSAGE _pRpcMessage,
|
||||
DWORD *_pdwStubPhase);
|
||||
|
||||
|
||||
|
||||
#endif /* __ISampleGrabber_INTERFACE_DEFINED__ */
|
||||
|
||||
#endif // __QEDIT_SIMPLE_H__
|
149
filter/asyncStreamflt/asyncflt.cpp
Normal file
149
filter/asyncStreamflt/asyncflt.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
// A simple stream source filter based on the sample code
|
||||
// It requires DirectShow BasicClass for compiling
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
#include "asyncio.h"
|
||||
#include "asyncrdr.h"
|
||||
|
||||
#pragma warning(disable:4710) // 'function' not inlined (optimization)
|
||||
#include "asyncflt.h"
|
||||
|
||||
//
|
||||
// Setup data for filter registration
|
||||
//
|
||||
const AMOVIESETUP_MEDIATYPE sudOpPinTypes =
|
||||
{ &MEDIATYPE_Stream // clsMajorType
|
||||
, &MEDIASUBTYPE_NULL }; // clsMinorType
|
||||
|
||||
const AMOVIESETUP_PIN sudOpPin =
|
||||
{ L"Output" // strName
|
||||
, FALSE // bRendered
|
||||
, TRUE // bOutput
|
||||
, FALSE // bZero
|
||||
, FALSE // bMany
|
||||
, &CLSID_NULL // clsConnectsToFilter
|
||||
, L"Input" // strConnectsToPin
|
||||
, 1 // nTypes
|
||||
, &sudOpPinTypes }; // lpTypes
|
||||
|
||||
const AMOVIESETUP_FILTER sudAsync =
|
||||
{ &CLSID_AsyncStreamSource // clsID
|
||||
, L"Stream/File Source (Async.)" // strName
|
||||
, MERIT_UNLIKELY // dwMerit
|
||||
, 1 // nPins
|
||||
, &sudOpPin }; // lpPin
|
||||
|
||||
|
||||
//
|
||||
// Object creation template
|
||||
//
|
||||
CFactoryTemplate g_Templates[1] = {
|
||||
{ L"Stream/File Source (Async.)"
|
||||
, &CLSID_AsyncStreamSource
|
||||
, CAsyncFilter::CreateInstance
|
||||
, NULL
|
||||
, &sudAsync }
|
||||
};
|
||||
|
||||
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Exported entry points for registration and unregistration
|
||||
// (in this case they only call through to default implementations).
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
STDAPI DllRegisterServer()
|
||||
{
|
||||
return AMovieDllRegisterServer2(TRUE);
|
||||
}
|
||||
|
||||
STDAPI DllUnregisterServer()
|
||||
{
|
||||
return AMovieDllRegisterServer2(FALSE);
|
||||
}
|
||||
|
||||
//
|
||||
// DllEntryPoint
|
||||
//
|
||||
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
|
||||
|
||||
BOOL APIENTRY DllMain(HANDLE hModule,
|
||||
DWORD dwReason,
|
||||
LPVOID lpReserved)
|
||||
{
|
||||
return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
|
||||
}
|
||||
|
||||
|
||||
//* Create a new instance of this class
|
||||
CUnknown * WINAPI CAsyncFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
|
||||
{
|
||||
ASSERT(phr);
|
||||
|
||||
// DLLEntry does the right thing with the return code and
|
||||
// the returned value on failure
|
||||
|
||||
return new CAsyncFilter(pUnk, phr);
|
||||
}
|
||||
|
||||
|
||||
BOOL CAsyncFilter::ReadTheFile(LPCTSTR lpszFileName)
|
||||
{
|
||||
DWORD dwBytesRead;
|
||||
|
||||
// Open the requested file
|
||||
HANDLE hFile = CreateFile(lpszFileName,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DbgLog((LOG_TRACE, 2, TEXT("Could not open %s\n"), lpszFileName));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Determine the file size
|
||||
ULARGE_INTEGER uliSize;
|
||||
uliSize.LowPart = GetFileSize(hFile, &uliSize.HighPart);
|
||||
|
||||
PBYTE pbMem = new BYTE[uliSize.LowPart];
|
||||
if (pbMem == NULL)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Read the data from the file
|
||||
if (!ReadFile(hFile,
|
||||
(LPVOID) pbMem,
|
||||
uliSize.LowPart,
|
||||
&dwBytesRead,
|
||||
NULL) ||
|
||||
(dwBytesRead != uliSize.LowPart))
|
||||
{
|
||||
DbgLog((LOG_TRACE, 1, TEXT("Could not read file\n")));
|
||||
|
||||
delete [] pbMem;
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Save a pointer to the data that was read from the file
|
||||
if (m_pbData)
|
||||
delete [] m_pbData;
|
||||
m_pbData = pbMem;
|
||||
m_llSize = (LONGLONG)uliSize.QuadPart;
|
||||
|
||||
// Close the file
|
||||
CloseHandle(hFile);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
13
filter/asyncStreamflt/asyncflt.def
Normal file
13
filter/asyncStreamflt/asyncflt.def
Normal file
|
@ -0,0 +1,13 @@
|
|||
;===========================================================================
|
||||
; Copyright (c) 1992-2002 Microsoft Corporation. All Rights Reserved.
|
||||
;===========================================================================
|
||||
|
||||
LIBRARY AsyncStreamflt.ax
|
||||
|
||||
EXPORTS
|
||||
DllMain PRIVATE
|
||||
DllGetClassObject PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllRegisterServer PRIVATE
|
||||
DllUnregisterServer PRIVATE
|
||||
|
305
filter/asyncStreamflt/asyncflt.h
Normal file
305
filter/asyncStreamflt/asyncflt.h
Normal file
|
@ -0,0 +1,305 @@
|
|||
// A simple stream source filter based on the sample code
|
||||
|
||||
#include "StreamSourceflt.h"
|
||||
|
||||
// NOTE: This filter does NOT support AVI format
|
||||
|
||||
//
|
||||
// Define an internal filter that wraps the base CBaseReader stuff
|
||||
//
|
||||
|
||||
class CMemStream : public CAsyncStream
|
||||
{
|
||||
public:
|
||||
CMemStream() :
|
||||
m_llPosition(0)
|
||||
{
|
||||
}
|
||||
|
||||
/* Initialization */
|
||||
void Init(LPBYTE pbData, LONGLONG llLength, DWORD dwKBPerSec = INFINITE)
|
||||
{
|
||||
m_pbData = pbData;
|
||||
m_llLength = llLength;
|
||||
m_dwKBPerSec = dwKBPerSec;
|
||||
m_dwTimeStart = timeGetTime();
|
||||
m_llreadSize = llLength;
|
||||
m_bisReadPassEnd = FALSE;
|
||||
}
|
||||
|
||||
HRESULT SetPointer(LONGLONG llPos)
|
||||
{
|
||||
if (llPos < 0 || llPos > m_llLength) {
|
||||
return S_FALSE;
|
||||
} else {
|
||||
m_llPosition = llPos;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT Read(PBYTE pbBuffer,
|
||||
DWORD dwBytesToRead,
|
||||
BOOL bAlign,
|
||||
LPDWORD pdwBytesRead)
|
||||
{
|
||||
CAutoLock lck(&m_csLock);
|
||||
DWORD dwReadLength;
|
||||
|
||||
/* Wait until the bytes are here! */
|
||||
DWORD dwTime = timeGetTime();
|
||||
|
||||
if (m_llPosition + dwBytesToRead > m_llLength) {
|
||||
dwReadLength = (DWORD)(m_llLength - m_llPosition);
|
||||
} else {
|
||||
dwReadLength = dwBytesToRead;
|
||||
}
|
||||
DWORD dwTimeToArrive =
|
||||
((DWORD)m_llPosition + dwReadLength) / m_dwKBPerSec;
|
||||
|
||||
if (dwTime - m_dwTimeStart < dwTimeToArrive) {
|
||||
Sleep(dwTimeToArrive - dwTime + m_dwTimeStart);
|
||||
}
|
||||
|
||||
CopyMemory((PVOID)pbBuffer, (PVOID)(m_pbData + m_llPosition),
|
||||
dwReadLength);
|
||||
|
||||
m_llPosition += dwReadLength;
|
||||
*pdwBytesRead = dwReadLength;
|
||||
if (m_llPosition >= m_llreadSize)
|
||||
m_bisReadPassEnd = TRUE;
|
||||
else
|
||||
m_bisReadPassEnd = FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
LONGLONG Size(LONGLONG *pSizeAvailable)
|
||||
{
|
||||
LONGLONG llCurrentAvailable =
|
||||
static_cast <LONGLONG> (UInt32x32To64((timeGetTime() - m_dwTimeStart),m_dwKBPerSec));
|
||||
|
||||
*pSizeAvailable = min(m_llLength, llCurrentAvailable);
|
||||
return m_llLength;
|
||||
}
|
||||
|
||||
DWORD Alignment()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Lock()
|
||||
{
|
||||
m_csLock.Lock();
|
||||
}
|
||||
|
||||
void Unlock()
|
||||
{
|
||||
m_csLock.Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
CCritSec m_csLock;
|
||||
PBYTE m_pbData;
|
||||
LONGLONG m_llLength;
|
||||
LONGLONG m_llPosition;
|
||||
DWORD m_dwKBPerSec;
|
||||
DWORD m_dwTimeStart;
|
||||
public:
|
||||
LONGLONG m_llreadSize;
|
||||
BOOL m_bisReadPassEnd;
|
||||
};
|
||||
|
||||
class CAsyncFilter : public CAsyncReader, public IStreamSourceFilter
|
||||
{
|
||||
public:
|
||||
CAsyncFilter(LPUNKNOWN pUnk, HRESULT *phr) :
|
||||
CAsyncReader(NAME("Mem Reader"), pUnk, &m_Stream, phr),
|
||||
m_pFileName(NULL),
|
||||
m_pbData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~CAsyncFilter()
|
||||
{
|
||||
delete [] m_pbData;
|
||||
delete [] m_pFileName;
|
||||
}
|
||||
|
||||
static CUnknown * WINAPI CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
if (riid == IID_IStreamSourceFilter) {
|
||||
return GetInterface((IStreamSourceFilter *)this, ppv);
|
||||
} else if (riid == IID_IFileSourceFilter) {
|
||||
return GetInterface((IFileSourceFilter *)this, ppv);
|
||||
} else {
|
||||
return CAsyncReader::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
|
||||
/* IFileSourceFilter methods */
|
||||
|
||||
// Load a (new) file
|
||||
STDMETHODIMP Load(LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt)
|
||||
{
|
||||
CheckPointer(lpwszFileName, E_POINTER);
|
||||
|
||||
// lstrlenW is one of the few Unicode functions that works on win95
|
||||
int cch = lstrlenW(lpwszFileName) + 1;
|
||||
|
||||
#ifndef UNICODE
|
||||
TCHAR *lpszFileName=0;
|
||||
lpszFileName = new char[cch * 2];
|
||||
if (!lpszFileName) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
WideCharToMultiByte(GetACP(), 0, lpwszFileName, -1,
|
||||
lpszFileName, cch, NULL, NULL);
|
||||
#else
|
||||
TCHAR lpszFileName[MAX_PATH]={0};
|
||||
(void)StringCchCopy(lpszFileName, NUMELMS(lpszFileName), lpwszFileName);
|
||||
#endif
|
||||
CAutoLock lck(&m_csFilter);
|
||||
|
||||
/* Check the file type */
|
||||
CMediaType cmt;
|
||||
if (NULL == pmt) {
|
||||
cmt.SetType(&MEDIATYPE_Stream);
|
||||
cmt.SetSubtype(&MEDIASUBTYPE_NULL);
|
||||
} else {
|
||||
cmt = *pmt;
|
||||
}
|
||||
|
||||
if (!ReadTheFile(lpszFileName)) {
|
||||
#ifndef UNICODE
|
||||
delete [] lpszFileName;
|
||||
#endif
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
m_Stream.Init(m_pbData, m_llSize);
|
||||
|
||||
if (m_pFileName)
|
||||
delete [] m_pFileName;
|
||||
m_pFileName = new WCHAR[cch];
|
||||
|
||||
if (m_pFileName!=NULL)
|
||||
CopyMemory(m_pFileName, lpwszFileName, cch*sizeof(WCHAR));
|
||||
|
||||
// this is not a simple assignment... pointers and format
|
||||
// block (if any) are intelligently copied
|
||||
m_mt = cmt;
|
||||
|
||||
/* Work out file type */
|
||||
cmt.bTemporalCompression = TRUE; //???
|
||||
cmt.lSampleSize = 1;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Modeled on IPersistFile::Load
|
||||
// Caller needs to CoTaskMemFree or equivalent.
|
||||
|
||||
STDMETHODIMP GetCurFile(LPOLESTR * ppszFileName, AM_MEDIA_TYPE *pmt)
|
||||
{
|
||||
CheckPointer(ppszFileName, E_POINTER);
|
||||
*ppszFileName = NULL;
|
||||
|
||||
if (m_pFileName!=NULL) {
|
||||
DWORD n = sizeof(WCHAR)*(1+lstrlenW(m_pFileName));
|
||||
|
||||
*ppszFileName = (LPOLESTR) CoTaskMemAlloc( n );
|
||||
if (*ppszFileName!=NULL) {
|
||||
CopyMemory(*ppszFileName, m_pFileName, n);
|
||||
}
|
||||
}
|
||||
|
||||
if (pmt!=NULL) {
|
||||
CopyMediaType(pmt, &m_mt);
|
||||
}
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
STDMETHODIMP LoadStream(void *stream, LONGLONG readSize, LONGLONG streamSize, AM_MEDIA_TYPE *pmt )
|
||||
{
|
||||
CAutoLock lck(&m_csFilter);
|
||||
|
||||
/* Check the file type */
|
||||
CMediaType cmt;
|
||||
if (NULL == pmt) {
|
||||
cmt.SetType(&MEDIATYPE_Stream);
|
||||
cmt.SetSubtype(&MEDIASUBTYPE_NULL);
|
||||
} else {
|
||||
cmt = *pmt;
|
||||
}
|
||||
|
||||
if (m_pFileName)
|
||||
delete [] m_pFileName;
|
||||
m_pFileName = NULL;
|
||||
PBYTE pbMem = new BYTE[streamSize];
|
||||
if (pbMem == NULL)
|
||||
return E_FAIL;
|
||||
CopyMemory(pbMem, stream, readSize);
|
||||
if (m_pbData)
|
||||
delete [] m_pbData;
|
||||
m_pbData = pbMem;
|
||||
m_llSize = streamSize;
|
||||
|
||||
m_Stream.Init(m_pbData, m_llSize);
|
||||
m_Stream.m_llreadSize = readSize;
|
||||
|
||||
// this is not a simple assignment... pointers and format
|
||||
// block (if any) are intelligently copied
|
||||
m_mt = cmt;
|
||||
|
||||
/* Work out file type */
|
||||
cmt.bTemporalCompression = TRUE; //???
|
||||
cmt.lSampleSize = 1;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP AddStreamData(LONGLONG offset, void *stream, LONGLONG addSize)
|
||||
{
|
||||
if (m_pbData == NULL)
|
||||
return E_FAIL;
|
||||
if (addSize > m_llSize - offset)
|
||||
addSize = m_llSize - offset;
|
||||
CopyMemory(m_pbData + offset, stream, addSize);
|
||||
if (offset + addSize > m_Stream.m_llreadSize)
|
||||
m_Stream.m_llreadSize = offset + addSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetStreamInfo(LONGLONG *readSize, LONGLONG *streamSize)
|
||||
{
|
||||
if (readSize)
|
||||
*readSize = m_Stream.m_llreadSize;
|
||||
if (streamSize)
|
||||
*streamSize = m_llSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP SetReadSize(LONGLONG readSize)
|
||||
{
|
||||
m_Stream.m_llreadSize = readSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
BOOL STDMETHODCALLTYPE IsReadPassEnd()
|
||||
{
|
||||
return m_Stream.m_bisReadPassEnd;
|
||||
}
|
||||
|
||||
private:
|
||||
BOOL CAsyncFilter::ReadTheFile(LPCTSTR lpszFileName);
|
||||
|
||||
private:
|
||||
LPWSTR m_pFileName;
|
||||
LONGLONG m_llSize;
|
||||
PBYTE m_pbData;
|
||||
CMemStream m_Stream;
|
||||
};
|
53
filter/asyncStreamflt/asyncflt.rc
Normal file
53
filter/asyncStreamflt/asyncflt.rc
Normal file
|
@ -0,0 +1,53 @@
|
|||
//==========================================================================;
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
||||
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
||||
// PURPOSE.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
//
|
||||
//--------------------------------------------------------------------------;
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 9,0,0,0
|
||||
PRODUCTVERSION 9,0,0,0
|
||||
FILEFLAGSMASK 0x30003fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0xbL
|
||||
#else
|
||||
FILEFLAGS 0xaL
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904e4"
|
||||
BEGIN
|
||||
VALUE "ActiveMovie", "Filter dll"
|
||||
VALUE "Comment", "Async Stream/File Source Filter"
|
||||
VALUE "CompanyName", "NULL"
|
||||
VALUE "FileDescription", "Stream/File Source (Async.)"
|
||||
VALUE "FileVersion", "9.00"
|
||||
VALUE "InternalName", "AsyncStreamflt.ax"
|
||||
VALUE "LegalCopyright", "NULL"
|
||||
VALUE "OLESelfRegister", "AM20"
|
||||
VALUE "OriginalFilename", "AsyncStreamflt.ax"
|
||||
VALUE "ProductName", "Async Stream/File Source Filter"
|
||||
VALUE "ProductVersion", "9.00"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
21
filter/asyncStreamflt/asyncflt.sln
Normal file
21
filter/asyncStreamflt/asyncflt.sln
Normal file
|
@ -0,0 +1,21 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "async", "asyncflt.vcxproj", "{0413A576-4B1B-7294-5FA3-3F839282D877}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug Unicode|Win32 = Debug Unicode|Win32
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release Unicode|Win32 = Release Unicode|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0413A576-4B1B-7294-5FA3-3F839282D877}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32
|
||||
{0413A576-4B1B-7294-5FA3-3F839282D877}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0413A576-4B1B-7294-5FA3-3F839282D877}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32
|
||||
{0413A576-4B1B-7294-5FA3-3F839282D877}.Release|Win32.ActiveCfg = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
305
filter/asyncStreamflt/asyncflt.vcxproj
Normal file
305
filter/asyncStreamflt/asyncflt.vcxproj
Normal file
|
@ -0,0 +1,305 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug Unicode|Win32">
|
||||
<Configuration>Debug Unicode</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release Unicode|Win32">
|
||||
<Configuration>Release Unicode</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>async</ProjectName>
|
||||
<SccProjectName />
|
||||
<SccLocalPath />
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\lib</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</IntDir>
|
||||
<IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</IgnoreImportLibrary>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">.\Debug_Unicode\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">.\Debug_Unicode\</IntDir>
|
||||
<IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">true</IgnoreImportLibrary>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">true</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">..\lib</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">.\Release_Unicode\</IntDir>
|
||||
<IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">true</IgnoreImportLibrary>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">false</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</IntDir>
|
||||
<IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</IgnoreImportLibrary>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'" />
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'" />
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">$(IncludePath)</IncludePath>
|
||||
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">$(LibraryPath)</LibraryPath>
|
||||
<IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IncludePath)</IncludePath>
|
||||
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LibraryPath)</LibraryPath>
|
||||
<IncludePath Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">$(IncludePath)</IncludePath>
|
||||
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">$(LibraryPath)</LibraryPath>
|
||||
<IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IncludePath)</IncludePath>
|
||||
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LibraryPath)</LibraryPath>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AsyncStreamflt.ax</TargetName>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">AsyncStreamflt_u.ax</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;ASYNC_EXPORTS;INC_OLE2;STRICT;_WIN32_WINNT=0x0403;WIN32;_WIN32;_MT;_DLL;_X86_=1;WINVER=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>streams.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>.\Release/asyncflt.pch</PrecompiledHeaderOutputFile>
|
||||
<AssemblerListingLocation>.\Release/</AssemblerListingLocation>
|
||||
<ObjectFileName>.\Release/</ObjectFileName>
|
||||
<ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<CallingConvention>StdCall</CallingConvention>
|
||||
<CompileAs>Default</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalOptions>/MACHINE:I386 /IGNORE:4089 /IGNORE:4098 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalDependencies>strmbase.lib;quartz.lib;winmm.lib;msvcrt.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>..\lib\AsyncStreamflt.ax</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ModuleDefinitionFile>.\asyncflt.def</ModuleDefinitionFile>
|
||||
<ProgramDatabaseFile>.\Release/asyncflt.pdb</ProgramDatabaseFile>
|
||||
<OptimizeReferences>
|
||||
</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<ImportLibrary>.\Release/asyncflt.lib</ImportLibrary>
|
||||
</Link>
|
||||
<Midl>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MkTypLibCompatible>true</MkTypLibCompatible>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TargetEnvironment>Win32</TargetEnvironment>
|
||||
<TypeLibraryName>.\Release/asyncflt.tlb</TypeLibraryName>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0409</Culture>
|
||||
<AdditionalIncludeDirectories>..\..\..\BaseClasses;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>INC_OLE2;STRICT;_WIN32_WINNT=0x0403;_WIN32;_MT;_DLL;_X86_=1;WINVER=0x0403;DBG=1;DEBUG;_DEBUG;WIN32;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>streams.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>.\Debug_Unicode/asyncflt.pch</PrecompiledHeaderOutputFile>
|
||||
<AssemblerListingLocation>.\Debug_Unicode/</AssemblerListingLocation>
|
||||
<ObjectFileName>.\Debug_Unicode/</ObjectFileName>
|
||||
<ProgramDataBaseFileName>.\Debug_Unicode/</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<CallingConvention>StdCall</CallingConvention>
|
||||
<CompileAs>Default</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalOptions>/MACHINE:I386 /IGNORE:4089 /IGNORE:4098 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalDependencies>strmbasd.lib;quartz.lib;winmm.lib;msvcrtd.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>Debug_Unicode/asyncflt.ax</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ModuleDefinitionFile>.\asyncflt.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ImportLibrary>.\Debug_Unicode/asyncflt.lib</ImportLibrary>
|
||||
</Link>
|
||||
<Midl>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MkTypLibCompatible>true</MkTypLibCompatible>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TargetEnvironment>Win32</TargetEnvironment>
|
||||
<TypeLibraryName>.\Debug_Unicode/asyncflt.tlb</TypeLibraryName>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0409</Culture>
|
||||
<AdditionalIncludeDirectories>..\..\..\BaseClasses;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">
|
||||
<ClCompile>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_MBCS;_USRDLL;ASYNC_EXPORTS;INC_OLE2;STRICT;_WIN32_WINNT=0x0403;_WIN32;_MT;_DLL;_X86_=1;WINVER=0x0403;WIN32;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>streams.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>.\Release_Unicode/asyncflt.pch</PrecompiledHeaderOutputFile>
|
||||
<AssemblerListingLocation>.\Release_Unicode/</AssemblerListingLocation>
|
||||
<ObjectFileName>.\Release_Unicode/</ObjectFileName>
|
||||
<ProgramDataBaseFileName>.\Release_Unicode/</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<CallingConvention>StdCall</CallingConvention>
|
||||
<CompileAs>Default</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalOptions>/MACHINE:I386 /IGNORE:4089 /IGNORE:4098 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalDependencies>strmbase.lib;quartz.lib;winmm.lib;msvcrt.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>Release_Unicode/asyncflt.ax</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ModuleDefinitionFile>.\asyncflt.def</ModuleDefinitionFile>
|
||||
<ProgramDatabaseFile>.\Release_Unicode/asyncflt.pdb</ProgramDatabaseFile>
|
||||
<OptimizeReferences>
|
||||
</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<ImportLibrary>.\Release_Unicode/asyncflt.lib</ImportLibrary>
|
||||
</Link>
|
||||
<Midl>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MkTypLibCompatible>true</MkTypLibCompatible>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TargetEnvironment>Win32</TargetEnvironment>
|
||||
<TypeLibraryName>.\Release_Unicode/asyncflt.tlb</TypeLibraryName>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0409</Culture>
|
||||
<AdditionalIncludeDirectories>..\..\..\BaseClasses;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>INC_OLE2;STRICT;_WIN32_WINNT=0x0403;WIN32;_WIN32;_MT;_DLL;_X86_=1;WINVER=0x0403;DBG=1;DEBUG;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>streams.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>.\Debug/asyncflt.pch</PrecompiledHeaderOutputFile>
|
||||
<AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
|
||||
<ObjectFileName>.\Debug/</ObjectFileName>
|
||||
<ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<CallingConvention>StdCall</CallingConvention>
|
||||
<CompileAs>Default</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalOptions>/MACHINE:I386 /IGNORE:4089 /IGNORE:4098 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalDependencies>strmbasd.lib;quartz.lib;winmm.lib;msvcrtd.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>Debug/asyncflt.ax</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ModuleDefinitionFile>.\asyncflt.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ImportLibrary>.\Debug/asyncflt.lib</ImportLibrary>
|
||||
</Link>
|
||||
<Midl>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MkTypLibCompatible>true</MkTypLibCompatible>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TargetEnvironment>Win32</TargetEnvironment>
|
||||
<TypeLibraryName>.\Debug/asyncflt.tlb</TypeLibraryName>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0409</Culture>
|
||||
<AdditionalIncludeDirectories>..\..\..\BaseClasses;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="asyncflt.cpp" />
|
||||
<ClCompile Include="asyncio.cpp" />
|
||||
<ClCompile Include="asyncrdr.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="asyncflt.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="asyncflt.h" />
|
||||
<ClInclude Include="asyncio.h" />
|
||||
<ClInclude Include="asyncrdr.h" />
|
||||
<ClInclude Include="StreamSourceflt.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="asyncflt.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
52
filter/asyncStreamflt/asyncflt.vcxproj.filters
Normal file
52
filter/asyncStreamflt/asyncflt.vcxproj.filters
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{2cb60d77-18ca-45ad-a4f3-0d736ca63aac}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{1aece6a2-e345-4279-81ae-993564c5b48a}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{56fe04f5-c6f6-43c9-95e2-a95245afadd0}</UniqueIdentifier>
|
||||
<Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="asyncflt.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asyncio.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asyncrdr.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="asyncflt.def">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="asyncflt.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="asyncio.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="asyncrdr.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StreamSourceflt.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="asyncflt.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
708
filter/asyncStreamflt/asyncio.cpp
Normal file
708
filter/asyncStreamflt/asyncio.cpp
Normal file
|
@ -0,0 +1,708 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// File: AsyncIo.cpp
|
||||
//
|
||||
// Desc: DirectShow sample code - base library with I/O functionality.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include "asyncio.h"
|
||||
|
||||
// --- CAsyncRequest ---
|
||||
|
||||
|
||||
// implementation of CAsyncRequest representing a single
|
||||
// outstanding request. All the i/o for this object is done
|
||||
// in the Complete method.
|
||||
|
||||
|
||||
// init the params for this request.
|
||||
// Read is not issued until the complete call
|
||||
HRESULT
|
||||
CAsyncRequest::Request(
|
||||
CAsyncIo *pIo,
|
||||
CAsyncStream *pStream,
|
||||
LONGLONG llPos,
|
||||
LONG lLength,
|
||||
BOOL bAligned,
|
||||
BYTE* pBuffer,
|
||||
LPVOID pContext, // filter's context
|
||||
DWORD_PTR dwUser) // downstream filter's context
|
||||
{
|
||||
m_pIo = pIo;
|
||||
m_pStream = pStream;
|
||||
m_llPos = llPos;
|
||||
m_lLength = lLength;
|
||||
m_bAligned = bAligned;
|
||||
m_pBuffer = pBuffer;
|
||||
m_pContext = pContext;
|
||||
m_dwUser = dwUser;
|
||||
m_hr = VFW_E_TIMEOUT; // not done yet
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// issue the i/o if not overlapped, and block until i/o complete.
|
||||
// returns error code of file i/o
|
||||
//
|
||||
//
|
||||
HRESULT
|
||||
CAsyncRequest::Complete()
|
||||
{
|
||||
m_pStream->Lock();
|
||||
|
||||
m_hr = m_pStream->SetPointer(m_llPos);
|
||||
if(S_OK == m_hr)
|
||||
{
|
||||
DWORD dwActual;
|
||||
|
||||
m_hr = m_pStream->Read(m_pBuffer, m_lLength, m_bAligned, &dwActual);
|
||||
if(m_hr == OLE_S_FIRST)
|
||||
{
|
||||
if(m_pContext)
|
||||
{
|
||||
IMediaSample *pSample = reinterpret_cast<IMediaSample *>(m_pContext);
|
||||
pSample->SetDiscontinuity(TRUE);
|
||||
m_hr = S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if(FAILED(m_hr))
|
||||
{
|
||||
}
|
||||
else if(dwActual != (DWORD)m_lLength)
|
||||
{
|
||||
// tell caller size changed - probably because of EOF
|
||||
m_lLength = (LONG) dwActual;
|
||||
m_hr = S_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hr = S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
m_pStream->Unlock();
|
||||
return m_hr;
|
||||
}
|
||||
|
||||
|
||||
// --- CAsyncIo ---
|
||||
|
||||
// note - all events created manual reset
|
||||
|
||||
CAsyncIo::CAsyncIo(CAsyncStream *pStream)
|
||||
: m_hThread(NULL),
|
||||
m_evWork(TRUE),
|
||||
m_evDone(TRUE),
|
||||
m_evStop(TRUE),
|
||||
m_listWork(NAME("Work list")),
|
||||
m_listDone(NAME("Done list")),
|
||||
m_bFlushing(FALSE),
|
||||
m_cItemsOut(0),
|
||||
m_bWaiting(FALSE),
|
||||
m_pStream(pStream)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
CAsyncIo::~CAsyncIo()
|
||||
{
|
||||
// move everything to the done list
|
||||
BeginFlush();
|
||||
|
||||
// shutdown worker thread
|
||||
CloseThread();
|
||||
|
||||
// empty the done list
|
||||
POSITION pos = m_listDone.GetHeadPosition();
|
||||
while(pos)
|
||||
{
|
||||
CAsyncRequest* pRequest = m_listDone.GetNext(pos);
|
||||
delete pRequest;
|
||||
}
|
||||
|
||||
m_listDone.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
// ready for async activity - call this before calling Request.
|
||||
//
|
||||
// start the worker thread if we need to
|
||||
//
|
||||
// !!! use overlapped i/o if possible
|
||||
HRESULT
|
||||
CAsyncIo::AsyncActive(void)
|
||||
{
|
||||
return StartThread();
|
||||
}
|
||||
|
||||
// call this when no more async activity will happen before
|
||||
// the next AsyncActive call
|
||||
//
|
||||
// stop the worker thread if active
|
||||
HRESULT
|
||||
CAsyncIo::AsyncInactive(void)
|
||||
{
|
||||
return CloseThread();
|
||||
}
|
||||
|
||||
|
||||
// add a request to the queue.
|
||||
HRESULT
|
||||
CAsyncIo::Request(
|
||||
LONGLONG llPos,
|
||||
LONG lLength,
|
||||
BOOL bAligned,
|
||||
BYTE * pBuffer,
|
||||
LPVOID pContext,
|
||||
DWORD_PTR dwUser)
|
||||
{
|
||||
if(bAligned)
|
||||
{
|
||||
if(!IsAligned(llPos) ||
|
||||
!IsAligned(lLength) ||
|
||||
!IsAligned((LONG_PTR) pBuffer))
|
||||
{
|
||||
return VFW_E_BADALIGN;
|
||||
}
|
||||
}
|
||||
|
||||
CAsyncRequest* pRequest = new CAsyncRequest;
|
||||
if (!pRequest)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
HRESULT hr = pRequest->Request(this,
|
||||
m_pStream,
|
||||
llPos,
|
||||
lLength,
|
||||
bAligned,
|
||||
pBuffer,
|
||||
pContext,
|
||||
dwUser);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
// might fail if flushing
|
||||
hr = PutWorkItem(pRequest);
|
||||
}
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
delete pRequest;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// wait for the next request to complete
|
||||
HRESULT
|
||||
CAsyncIo::WaitForNext(
|
||||
DWORD dwTimeout,
|
||||
LPVOID * ppContext,
|
||||
DWORD_PTR * pdwUser,
|
||||
LONG * pcbActual)
|
||||
{
|
||||
CheckPointer(ppContext,E_POINTER);
|
||||
CheckPointer(pdwUser,E_POINTER);
|
||||
CheckPointer(pcbActual,E_POINTER);
|
||||
|
||||
// some errors find a sample, others don't. Ensure that
|
||||
// *ppContext is NULL if no sample found
|
||||
*ppContext = NULL;
|
||||
|
||||
// wait until the event is set, but since we are not
|
||||
// holding the critsec when waiting, we may need to re-wait
|
||||
for(;;)
|
||||
{
|
||||
if(!m_evDone.Wait(dwTimeout))
|
||||
{
|
||||
// timeout occurred
|
||||
return VFW_E_TIMEOUT;
|
||||
}
|
||||
|
||||
// get next event from list
|
||||
CAsyncRequest* pRequest = GetDoneItem();
|
||||
if(pRequest)
|
||||
{
|
||||
// found a completed request
|
||||
|
||||
// check if ok
|
||||
HRESULT hr = pRequest->GetHResult();
|
||||
if(hr == S_FALSE)
|
||||
{
|
||||
// this means the actual length was less than
|
||||
// requested - may be ok if he aligned the end of file
|
||||
if((pRequest->GetActualLength() +
|
||||
pRequest->GetStart()) == Size())
|
||||
{
|
||||
hr = S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// it was an actual read error
|
||||
hr = E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// return actual bytes read
|
||||
*pcbActual = pRequest->GetActualLength();
|
||||
|
||||
// return his context
|
||||
*ppContext = pRequest->GetContext();
|
||||
*pdwUser = pRequest->GetUser();
|
||||
|
||||
delete pRequest;
|
||||
return hr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hold the critical section while checking the list state
|
||||
CAutoLock lck(&m_csLists);
|
||||
if(m_bFlushing && !m_bWaiting)
|
||||
{
|
||||
// can't block as we are between BeginFlush and EndFlush
|
||||
|
||||
// but note that if m_bWaiting is set, then there are some
|
||||
// items not yet complete that we should block for.
|
||||
|
||||
return VFW_E_WRONG_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
// done item was grabbed between completion and
|
||||
// us locking m_csLists.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// perform a synchronous read request on this thread.
|
||||
// Need to hold m_csFile while doing this (done in request object)
|
||||
HRESULT
|
||||
CAsyncIo::SyncReadAligned(
|
||||
LONGLONG llPos,
|
||||
LONG lLength,
|
||||
BYTE * pBuffer,
|
||||
LONG * pcbActual,
|
||||
PVOID pvContext)
|
||||
{
|
||||
CheckPointer(pcbActual,E_POINTER);
|
||||
|
||||
if(!IsAligned(llPos) ||
|
||||
!IsAligned(lLength) ||
|
||||
!IsAligned((LONG_PTR) pBuffer))
|
||||
{
|
||||
return VFW_E_BADALIGN;
|
||||
}
|
||||
|
||||
CAsyncRequest request;
|
||||
|
||||
HRESULT hr = request.Request(this,
|
||||
m_pStream,
|
||||
llPos,
|
||||
lLength,
|
||||
TRUE,
|
||||
pBuffer,
|
||||
pvContext,
|
||||
0);
|
||||
if(FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = request.Complete();
|
||||
|
||||
// return actual data length
|
||||
*pcbActual = request.GetActualLength();
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
CAsyncIo::Length(LONGLONG *pllTotal, LONGLONG *pllAvailable)
|
||||
{
|
||||
CheckPointer(pllTotal,E_POINTER);
|
||||
|
||||
*pllTotal = m_pStream->Size(pllAvailable);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// cancel all items on the worklist onto the done list
|
||||
// and refuse further requests or further WaitForNext calls
|
||||
// until the end flush
|
||||
//
|
||||
// WaitForNext must return with NULL only if there are no successful requests.
|
||||
// So Flush does the following:
|
||||
// 1. set m_bFlushing ensures no more requests succeed
|
||||
// 2. move all items from work list to the done list.
|
||||
// 3. If there are any outstanding requests, then we need to release the
|
||||
// critsec to allow them to complete. The m_bWaiting as well as ensuring
|
||||
// that we are signalled when they are all done is also used to indicate
|
||||
// to WaitForNext that it should continue to block.
|
||||
// 4. Once all outstanding requests are complete, we force m_evDone set and
|
||||
// m_bFlushing set and m_bWaiting false. This ensures that WaitForNext will
|
||||
// not block when the done list is empty.
|
||||
HRESULT
|
||||
CAsyncIo::BeginFlush()
|
||||
{
|
||||
// hold the lock while emptying the work list
|
||||
{
|
||||
CAutoLock lock(&m_csLists);
|
||||
|
||||
// prevent further requests being queued.
|
||||
// Also WaitForNext will refuse to block if this is set
|
||||
// unless m_bWaiting is also set which it will be when we release
|
||||
// the critsec if there are any outstanding).
|
||||
m_bFlushing = TRUE;
|
||||
|
||||
CAsyncRequest * preq;
|
||||
while((preq = GetWorkItem()) != 0)
|
||||
{
|
||||
preq->Cancel();
|
||||
PutDoneItem(preq);
|
||||
}
|
||||
|
||||
// now wait for any outstanding requests to complete
|
||||
if(m_cItemsOut > 0)
|
||||
{
|
||||
// can be only one person waiting
|
||||
ASSERT(!m_bWaiting);
|
||||
|
||||
// this tells the completion routine that we need to be
|
||||
// signalled via m_evAllDone when all outstanding items are
|
||||
// done. It also tells WaitForNext to continue blocking.
|
||||
m_bWaiting = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// all done
|
||||
|
||||
// force m_evDone set so that even if list is empty,
|
||||
// WaitForNext will not block
|
||||
// don't do this until we are sure that all
|
||||
// requests are on the done list.
|
||||
m_evDone.Set();
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(m_bWaiting);
|
||||
|
||||
// wait without holding critsec
|
||||
for(;;)
|
||||
{
|
||||
m_evAllDone.Wait();
|
||||
{
|
||||
// hold critsec to check
|
||||
CAutoLock lock(&m_csLists);
|
||||
|
||||
if(m_cItemsOut == 0)
|
||||
{
|
||||
// now we are sure that all outstanding requests are on
|
||||
// the done list and no more will be accepted
|
||||
m_bWaiting = FALSE;
|
||||
|
||||
// force m_evDone set so that even if list is empty,
|
||||
// WaitForNext will not block
|
||||
// don't do this until we are sure that all
|
||||
// requests are on the done list.
|
||||
m_evDone.Set();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// end a flushing state
|
||||
HRESULT
|
||||
CAsyncIo::EndFlush()
|
||||
{
|
||||
CAutoLock lock(&m_csLists);
|
||||
|
||||
m_bFlushing = FALSE;
|
||||
|
||||
ASSERT(!m_bWaiting);
|
||||
|
||||
// m_evDone might have been set by BeginFlush - ensure it is
|
||||
// set IFF m_listDone is non-empty
|
||||
if(m_listDone.GetCount() > 0)
|
||||
{
|
||||
m_evDone.Set();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_evDone.Reset();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// start the thread
|
||||
HRESULT
|
||||
CAsyncIo::StartThread(void)
|
||||
{
|
||||
if(m_hThread)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// clear the stop event before starting
|
||||
m_evStop.Reset();
|
||||
|
||||
DWORD dwThreadID;
|
||||
m_hThread = CreateThread(NULL,
|
||||
0,
|
||||
InitialThreadProc,
|
||||
this,
|
||||
0,
|
||||
&dwThreadID);
|
||||
if(!m_hThread)
|
||||
{
|
||||
DWORD dwErr = GetLastError();
|
||||
return HRESULT_FROM_WIN32(dwErr);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// stop the thread and close the handle
|
||||
HRESULT
|
||||
CAsyncIo::CloseThread(void)
|
||||
{
|
||||
// signal the thread-exit object
|
||||
m_evStop.Set();
|
||||
|
||||
if(m_hThread)
|
||||
{
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
CloseHandle(m_hThread);
|
||||
m_hThread = NULL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// manage the list of requests. hold m_csLists and ensure
|
||||
// that the (manual reset) event hevList is set when things on
|
||||
// the list but reset when the list is empty.
|
||||
// returns null if list empty
|
||||
CAsyncRequest*
|
||||
CAsyncIo::GetWorkItem()
|
||||
{
|
||||
CAutoLock lck(&m_csLists);
|
||||
CAsyncRequest * preq = m_listWork.RemoveHead();
|
||||
|
||||
// force event set correctly
|
||||
if(m_listWork.GetCount() == 0)
|
||||
{
|
||||
m_evWork.Reset();
|
||||
}
|
||||
|
||||
return preq;
|
||||
}
|
||||
|
||||
|
||||
// get an item from the done list
|
||||
CAsyncRequest*
|
||||
CAsyncIo::GetDoneItem()
|
||||
{
|
||||
CAutoLock lock(&m_csLists);
|
||||
CAsyncRequest * preq = m_listDone.RemoveHead();
|
||||
|
||||
// force event set correctly if list now empty
|
||||
// or we're in the final stages of flushing
|
||||
// Note that during flushing the way it's supposed to work is that
|
||||
// everything is shoved on the Done list then the application is
|
||||
// supposed to pull until it gets nothing more
|
||||
//
|
||||
// Thus we should not set m_evDone unconditionally until everything
|
||||
// has moved to the done list which means we must wait until
|
||||
// cItemsOut is 0 (which is guaranteed by m_bWaiting being TRUE).
|
||||
|
||||
if(m_listDone.GetCount() == 0 &&
|
||||
(!m_bFlushing || m_bWaiting))
|
||||
{
|
||||
m_evDone.Reset();
|
||||
}
|
||||
|
||||
return preq;
|
||||
}
|
||||
|
||||
|
||||
// put an item on the work list - fail if bFlushing
|
||||
HRESULT
|
||||
CAsyncIo::PutWorkItem(CAsyncRequest* pRequest)
|
||||
{
|
||||
CAutoLock lock(&m_csLists);
|
||||
HRESULT hr;
|
||||
|
||||
if(m_bFlushing)
|
||||
{
|
||||
hr = VFW_E_WRONG_STATE;
|
||||
}
|
||||
else if(m_listWork.AddTail(pRequest))
|
||||
{
|
||||
// event should now be in a set state - force this
|
||||
m_evWork.Set();
|
||||
|
||||
// start the thread now if not already started
|
||||
hr = StartThread();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
return(hr);
|
||||
}
|
||||
|
||||
|
||||
// put an item on the done list - ok to do this when
|
||||
// flushing
|
||||
HRESULT
|
||||
CAsyncIo::PutDoneItem(CAsyncRequest* pRequest)
|
||||
{
|
||||
ASSERT(CritCheckIn(&m_csLists));
|
||||
|
||||
if(m_listDone.AddTail(pRequest))
|
||||
{
|
||||
// event should now be in a set state - force this
|
||||
m_evDone.Set();
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// called on thread to process any active requests
|
||||
void
|
||||
CAsyncIo::ProcessRequests(void)
|
||||
{
|
||||
// lock to get the item and increment the outstanding count
|
||||
CAsyncRequest * preq = NULL;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
{
|
||||
CAutoLock lock(&m_csLists);
|
||||
|
||||
preq = GetWorkItem();
|
||||
if(preq == NULL)
|
||||
{
|
||||
// done
|
||||
return;
|
||||
}
|
||||
|
||||
// one more item not on the done or work list
|
||||
m_cItemsOut++;
|
||||
|
||||
// release critsec
|
||||
}
|
||||
|
||||
preq->Complete();
|
||||
|
||||
// regain critsec to replace on done list
|
||||
{
|
||||
CAutoLock l(&m_csLists);
|
||||
|
||||
PutDoneItem(preq);
|
||||
|
||||
if(--m_cItemsOut == 0)
|
||||
{
|
||||
if(m_bWaiting)
|
||||
m_evAllDone.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// the thread proc - assumes that DWORD thread param is the
|
||||
// this pointer
|
||||
DWORD
|
||||
CAsyncIo::ThreadProc(void)
|
||||
{
|
||||
HANDLE ahev[] = {m_evStop, m_evWork};
|
||||
|
||||
for(;;)
|
||||
{
|
||||
DWORD dw = WaitForMultipleObjects(2,
|
||||
ahev,
|
||||
FALSE,
|
||||
INFINITE);
|
||||
if(dw == WAIT_OBJECT_0+1)
|
||||
{
|
||||
// requests need processing
|
||||
ProcessRequests();
|
||||
}
|
||||
else
|
||||
{
|
||||
// any error or stop event - we should exit
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// perform a synchronous read request on this thread.
|
||||
// may not be aligned - so we will have to buffer.
|
||||
HRESULT
|
||||
CAsyncIo::SyncRead(
|
||||
LONGLONG llPos,
|
||||
LONG lLength,
|
||||
BYTE * pBuffer)
|
||||
{
|
||||
if(IsAligned(llPos) &&
|
||||
IsAligned(lLength) &&
|
||||
IsAligned((LONG_PTR) pBuffer))
|
||||
{
|
||||
LONG cbUnused;
|
||||
return SyncReadAligned(llPos, lLength, pBuffer, &cbUnused, NULL);
|
||||
}
|
||||
|
||||
// not aligned with requirements - use buffered file handle.
|
||||
//!!! might want to fix this to buffer the data ourselves?
|
||||
|
||||
CAsyncRequest request;
|
||||
|
||||
HRESULT hr = request.Request(this,
|
||||
m_pStream,
|
||||
llPos,
|
||||
lLength,
|
||||
FALSE,
|
||||
pBuffer,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
return request.Complete();
|
||||
}
|
||||
|
||||
|
||||
// Return the alignment
|
||||
HRESULT
|
||||
CAsyncIo::Alignment(LONG *pAlignment)
|
||||
{
|
||||
CheckPointer(pAlignment,E_POINTER);
|
||||
|
||||
*pAlignment = Alignment();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
273
filter/asyncStreamflt/asyncio.h
Normal file
273
filter/asyncStreamflt/asyncio.h
Normal file
|
@ -0,0 +1,273 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// File: AsyncIo.h
|
||||
//
|
||||
// Desc: DirectShow sample code - base library for I/O functionality.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __ASYNCIO_H__
|
||||
#define __ASYNCIO_H__
|
||||
|
||||
//
|
||||
// definition of CAsyncFile object that performs file access. It provides
|
||||
// asynchronous, unbuffered, aligned reads from a file, using a worker thread
|
||||
// on win95 and potentially overlapped i/o if available.
|
||||
|
||||
// !!! Need to use real overlapped i/o if available
|
||||
// currently only uses worker thread, not overlapped i/o
|
||||
|
||||
|
||||
class CAsyncIo;
|
||||
class CAsyncStream;
|
||||
|
||||
//
|
||||
// Model the stream we read from based on a file-like interface
|
||||
//
|
||||
class CAsyncStream
|
||||
{
|
||||
public:
|
||||
virtual ~CAsyncStream() {};
|
||||
virtual HRESULT SetPointer(LONGLONG llPos) = 0;
|
||||
virtual HRESULT Read(PBYTE pbBuffer,
|
||||
DWORD dwBytesToRead,
|
||||
BOOL bAlign,
|
||||
LPDWORD pdwBytesRead) = 0;
|
||||
|
||||
virtual LONGLONG Size(LONGLONG *pSizeAvailable = NULL) = 0;
|
||||
virtual DWORD Alignment() = 0;
|
||||
virtual void Lock() = 0;
|
||||
virtual void Unlock() = 0;
|
||||
//virtual void SetStopHandle(HANDLE hevStop) {}
|
||||
};
|
||||
|
||||
// represents a single request and performs the i/o. Can be called on either
|
||||
// worker thread or app thread, but must hold pcsFile across file accesses.
|
||||
// (ie across SetFilePointer/ReadFile pairs)
|
||||
class CAsyncRequest
|
||||
{
|
||||
CAsyncIo *m_pIo;
|
||||
CAsyncStream *m_pStream;
|
||||
LONGLONG m_llPos;
|
||||
BOOL m_bAligned;
|
||||
LONG m_lLength;
|
||||
BYTE* m_pBuffer;
|
||||
LPVOID m_pContext;
|
||||
DWORD_PTR m_dwUser;
|
||||
HRESULT m_hr;
|
||||
|
||||
public:
|
||||
// init the params for this request. Issue the i/o
|
||||
// if overlapped i/o is possible.
|
||||
HRESULT Request(
|
||||
CAsyncIo *pIo,
|
||||
CAsyncStream *pStream,
|
||||
LONGLONG llPos,
|
||||
LONG lLength,
|
||||
BOOL bAligned,
|
||||
BYTE* pBuffer,
|
||||
LPVOID pContext, // filter's context
|
||||
DWORD_PTR dwUser); // downstream filter's context
|
||||
|
||||
// issue the i/o if not overlapped, and block until i/o complete.
|
||||
// returns error code of file i/o
|
||||
HRESULT Complete();
|
||||
|
||||
// cancels the i/o. blocks until i/o is no longer pending
|
||||
HRESULT Cancel()
|
||||
{
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
// accessor functions
|
||||
LPVOID GetContext()
|
||||
{
|
||||
return m_pContext;
|
||||
};
|
||||
|
||||
DWORD_PTR GetUser()
|
||||
{
|
||||
return m_dwUser;
|
||||
};
|
||||
|
||||
HRESULT GetHResult() {
|
||||
return m_hr;
|
||||
};
|
||||
|
||||
// we set m_lLength to the actual length
|
||||
LONG GetActualLength() {
|
||||
return m_lLength;
|
||||
};
|
||||
|
||||
LONGLONG GetStart() {
|
||||
return m_llPos;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
typedef CGenericList<CAsyncRequest> CRequestList;
|
||||
|
||||
// this class needs a worker thread, but the ones defined in classes\base
|
||||
// are not suitable (they assume you have one message sent or posted per
|
||||
// request, whereas here for efficiency we want just to set an event when
|
||||
// there is work on the queue).
|
||||
//
|
||||
// we create CAsyncRequest objects and queue them on m_listWork. The worker
|
||||
// thread pulls them off, completes them and puts them on m_listDone.
|
||||
// The events m_evWork and m_evDone are set when the corresponding lists are
|
||||
// not empty.
|
||||
//
|
||||
// Synchronous requests are done on the caller thread. These should be
|
||||
// synchronised by the caller, but to make sure we hold m_csFile across
|
||||
// the SetFilePointer/ReadFile code.
|
||||
//
|
||||
// Flush by calling BeginFlush. This rejects all further requests (by
|
||||
// setting m_bFlushing within m_csLists), cancels all requests and moves them
|
||||
// to the done list, and sets m_evDone to ensure that no WaitForNext operations
|
||||
// will block. Call EndFlush to cancel this state.
|
||||
//
|
||||
// we support unaligned calls to SyncRead. This is done by opening the file
|
||||
// twice if we are using unbuffered i/o (m_dwAlign > 1).
|
||||
// !!!fix this to buffer on top of existing file handle?
|
||||
class CAsyncIo
|
||||
{
|
||||
|
||||
CCritSec m_csReader;
|
||||
CAsyncStream *m_pStream;
|
||||
|
||||
CCritSec m_csLists; // locks access to the list and events
|
||||
BOOL m_bFlushing; // true if between BeginFlush/EndFlush
|
||||
|
||||
CRequestList m_listWork;
|
||||
CRequestList m_listDone;
|
||||
|
||||
CAMEvent m_evWork; // set when list is not empty
|
||||
CAMEvent m_evDone;
|
||||
|
||||
// for correct flush behaviour: all protected by m_csLists
|
||||
LONG m_cItemsOut; // nr of items not on listDone or listWork
|
||||
BOOL m_bWaiting; // TRUE if someone waiting for m_evAllDone
|
||||
CAMEvent m_evAllDone; // signal when m_cItemsOut goes to 0 if m_cWaiting
|
||||
|
||||
|
||||
CAMEvent m_evStop; // set when thread should exit
|
||||
HANDLE m_hThread;
|
||||
|
||||
LONGLONG Size() {
|
||||
ASSERT(m_pStream != NULL);
|
||||
return m_pStream->Size();
|
||||
};
|
||||
|
||||
// start the thread
|
||||
HRESULT StartThread(void);
|
||||
|
||||
// stop the thread and close the handle
|
||||
HRESULT CloseThread(void);
|
||||
|
||||
// manage the list of requests. hold m_csLists and ensure
|
||||
// that the (manual reset) event hevList is set when things on
|
||||
// the list but reset when the list is empty.
|
||||
// returns null if list empty
|
||||
CAsyncRequest* GetWorkItem();
|
||||
|
||||
// get an item from the done list
|
||||
CAsyncRequest* GetDoneItem();
|
||||
|
||||
// put an item on the work list
|
||||
HRESULT PutWorkItem(CAsyncRequest* pRequest);
|
||||
|
||||
// put an item on the done list
|
||||
HRESULT PutDoneItem(CAsyncRequest* pRequest);
|
||||
|
||||
// called on thread to process any active requests
|
||||
void ProcessRequests(void);
|
||||
|
||||
// initial static thread proc calls ThreadProc with DWORD
|
||||
// param as this
|
||||
static DWORD WINAPI InitialThreadProc(LPVOID pv) {
|
||||
CAsyncIo * pThis = (CAsyncIo*) pv;
|
||||
return pThis->ThreadProc();
|
||||
};
|
||||
|
||||
DWORD ThreadProc(void);
|
||||
|
||||
public:
|
||||
|
||||
CAsyncIo(CAsyncStream *pStream);
|
||||
~CAsyncIo();
|
||||
|
||||
// open the file
|
||||
HRESULT Open(LPCTSTR pName);
|
||||
|
||||
// ready for async activity - call this before
|
||||
// calling Request
|
||||
HRESULT AsyncActive(void);
|
||||
|
||||
// call this when no more async activity will happen before
|
||||
// the next AsyncActive call
|
||||
HRESULT AsyncInactive(void);
|
||||
|
||||
// queue a requested read. must be aligned.
|
||||
HRESULT Request(
|
||||
LONGLONG llPos,
|
||||
LONG lLength,
|
||||
BOOL bAligned,
|
||||
BYTE* pBuffer,
|
||||
LPVOID pContext,
|
||||
DWORD_PTR dwUser);
|
||||
|
||||
// wait for the next read to complete
|
||||
HRESULT WaitForNext(
|
||||
DWORD dwTimeout,
|
||||
LPVOID *ppContext,
|
||||
DWORD_PTR * pdwUser,
|
||||
LONG * pcbActual);
|
||||
|
||||
// perform a read of an already aligned buffer
|
||||
HRESULT SyncReadAligned(
|
||||
LONGLONG llPos,
|
||||
LONG lLength,
|
||||
BYTE* pBuffer,
|
||||
LONG* pcbActual,
|
||||
PVOID pvContext);
|
||||
|
||||
// perform a synchronous read. will be buffered
|
||||
// if not aligned.
|
||||
HRESULT SyncRead(
|
||||
LONGLONG llPos,
|
||||
LONG lLength,
|
||||
BYTE* pBuffer);
|
||||
|
||||
// return length
|
||||
HRESULT Length(LONGLONG *pllTotal, LONGLONG* pllAvailable);
|
||||
|
||||
// all Reader positions, read lengths and memory locations must
|
||||
// be aligned to this.
|
||||
HRESULT Alignment(LONG* pl);
|
||||
|
||||
HRESULT BeginFlush();
|
||||
HRESULT EndFlush();
|
||||
|
||||
LONG Alignment()
|
||||
{
|
||||
return m_pStream->Alignment();
|
||||
};
|
||||
|
||||
BOOL IsAligned(LONG l) {
|
||||
if ((l & (Alignment() -1)) == 0) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
BOOL IsAligned(LONGLONG ll) {
|
||||
return IsAligned( (LONG) (ll & 0xffffffff));
|
||||
};
|
||||
|
||||
// Accessor
|
||||
HANDLE StopEvent() const { return m_evDone; }
|
||||
};
|
||||
|
||||
#endif // __ASYNCIO_H__
|
436
filter/asyncStreamflt/asyncrdr.cpp
Normal file
436
filter/asyncStreamflt/asyncrdr.cpp
Normal file
|
@ -0,0 +1,436 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// File: AsyncRdr.cpp
|
||||
//
|
||||
// Desc: DirectShow sample code - base library with I/O functionality.
|
||||
// This file implements I/O source filter methods and output pin
|
||||
// methods for CAsyncReader and CAsyncOutputPin.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include "asyncio.h"
|
||||
#include "asyncrdr.h"
|
||||
|
||||
#include <initguid.h>
|
||||
|
||||
#include "asyncflt.h"
|
||||
|
||||
// --- CAsyncOutputPin implementation ---
|
||||
|
||||
CAsyncOutputPin::CAsyncOutputPin(
|
||||
HRESULT * phr,
|
||||
CAsyncReader *pReader,
|
||||
CAsyncIo *pIo,
|
||||
CCritSec * pLock)
|
||||
: CBasePin(
|
||||
NAME("Async output pin"),
|
||||
pReader,
|
||||
pLock,
|
||||
phr,
|
||||
L"Output",
|
||||
PINDIR_OUTPUT),
|
||||
m_pReader(pReader),
|
||||
m_pIo(pIo)
|
||||
{
|
||||
}
|
||||
|
||||
CAsyncOutputPin::~CAsyncOutputPin()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CAsyncOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
CheckPointer(ppv,E_POINTER);
|
||||
|
||||
if(riid == IID_IAsyncReader)
|
||||
{
|
||||
m_bQueriedForAsyncReader = TRUE;
|
||||
return GetInterface((IAsyncReader*) this, ppv);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CBasePin::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT CAsyncOutputPin::GetMediaType(int iPosition, CMediaType *pMediaType)
|
||||
{
|
||||
if(iPosition < 0)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if(iPosition > 0)
|
||||
{
|
||||
return VFW_S_NO_MORE_ITEMS;
|
||||
}
|
||||
|
||||
CheckPointer(pMediaType,E_POINTER);
|
||||
CheckPointer(m_pReader,E_UNEXPECTED);
|
||||
|
||||
*pMediaType = *m_pReader->LoadType();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CAsyncOutputPin::CheckMediaType(const CMediaType* pType)
|
||||
{
|
||||
CAutoLock lck(m_pLock);
|
||||
|
||||
/* We treat MEDIASUBTYPE_NULL subtype as a wild card */
|
||||
if((m_pReader->LoadType()->majortype == pType->majortype) &&
|
||||
(m_pReader->LoadType()->subtype == MEDIASUBTYPE_NULL ||
|
||||
m_pReader->LoadType()->subtype == pType->subtype))
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CAsyncOutputPin::InitAllocator(IMemAllocator **ppAlloc)
|
||||
{
|
||||
CheckPointer(ppAlloc,E_POINTER);
|
||||
|
||||
HRESULT hr = NOERROR;
|
||||
CMemAllocator *pMemObject = NULL;
|
||||
|
||||
*ppAlloc = NULL;
|
||||
|
||||
/* Create a default memory allocator */
|
||||
pMemObject = new CMemAllocator(NAME("Base memory allocator"), NULL, &hr);
|
||||
if(pMemObject == NULL)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if(FAILED(hr))
|
||||
{
|
||||
delete pMemObject;
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Get a reference counted IID_IMemAllocator interface */
|
||||
hr = pMemObject->QueryInterface(IID_IMemAllocator,(void **)ppAlloc);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
delete pMemObject;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ASSERT(*ppAlloc != NULL);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// we need to return an addrefed allocator, even if it is the preferred
|
||||
// one, since he doesn't know whether it is the preferred one or not.
|
||||
STDMETHODIMP
|
||||
CAsyncOutputPin::RequestAllocator(
|
||||
IMemAllocator* pPreferred,
|
||||
ALLOCATOR_PROPERTIES* pProps,
|
||||
IMemAllocator ** ppActual)
|
||||
{
|
||||
CheckPointer(pPreferred,E_POINTER);
|
||||
CheckPointer(pProps,E_POINTER);
|
||||
CheckPointer(ppActual,E_POINTER);
|
||||
ASSERT(m_pIo);
|
||||
|
||||
// we care about alignment but nothing else
|
||||
if(!pProps->cbAlign || !m_pIo->IsAligned(pProps->cbAlign))
|
||||
{
|
||||
m_pIo->Alignment(&pProps->cbAlign);
|
||||
}
|
||||
|
||||
ALLOCATOR_PROPERTIES Actual;
|
||||
HRESULT hr;
|
||||
|
||||
if(pPreferred)
|
||||
{
|
||||
hr = pPreferred->SetProperties(pProps, &Actual);
|
||||
|
||||
if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign))
|
||||
{
|
||||
pPreferred->AddRef();
|
||||
*ppActual = pPreferred;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// create our own allocator
|
||||
IMemAllocator* pAlloc;
|
||||
hr = InitAllocator(&pAlloc);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
//...and see if we can make it suitable
|
||||
hr = pAlloc->SetProperties(pProps, &Actual);
|
||||
if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign))
|
||||
{
|
||||
// we need to release our refcount on pAlloc, and addref
|
||||
// it to pass a refcount to the caller - this is a net nothing.
|
||||
*ppActual = pAlloc;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// failed to find a suitable allocator
|
||||
pAlloc->Release();
|
||||
|
||||
// if we failed because of the IsAligned test, the error code will
|
||||
// not be failure
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
hr = VFW_E_BADALIGN;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// queue an aligned read request. call WaitForNext to get
|
||||
// completion.
|
||||
STDMETHODIMP CAsyncOutputPin::Request(
|
||||
IMediaSample* pSample,
|
||||
DWORD_PTR dwUser) // user context
|
||||
{
|
||||
CheckPointer(pSample,E_POINTER);
|
||||
|
||||
REFERENCE_TIME tStart, tStop;
|
||||
HRESULT hr = pSample->GetTime(&tStart, &tStop);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
LONGLONG llPos = tStart / UNITS;
|
||||
LONG lLength = (LONG) ((tStop - tStart) / UNITS);
|
||||
|
||||
LONGLONG llTotal=0, llAvailable=0;
|
||||
|
||||
hr = m_pIo->Length(&llTotal, &llAvailable);
|
||||
if(llPos + lLength > llTotal)
|
||||
{
|
||||
// the end needs to be aligned, but may have been aligned
|
||||
// on a coarser alignment.
|
||||
LONG lAlign;
|
||||
m_pIo->Alignment(&lAlign);
|
||||
|
||||
llTotal = (llTotal + lAlign -1) & ~(lAlign-1);
|
||||
|
||||
if(llPos + lLength > llTotal)
|
||||
{
|
||||
lLength = (LONG) (llTotal - llPos);
|
||||
|
||||
// must be reducing this!
|
||||
ASSERT((llTotal * UNITS) <= tStop);
|
||||
tStop = llTotal * UNITS;
|
||||
pSample->SetTime(&tStart, &tStop);
|
||||
}
|
||||
}
|
||||
|
||||
BYTE* pBuffer;
|
||||
hr = pSample->GetPointer(&pBuffer);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
return m_pIo->Request(llPos,
|
||||
lLength,
|
||||
TRUE,
|
||||
pBuffer,
|
||||
(LPVOID)pSample,
|
||||
dwUser);
|
||||
}
|
||||
|
||||
|
||||
// sync-aligned request. just like a request/waitfornext pair.
|
||||
STDMETHODIMP
|
||||
CAsyncOutputPin::SyncReadAligned(
|
||||
IMediaSample* pSample)
|
||||
{
|
||||
CheckPointer(pSample,E_POINTER);
|
||||
|
||||
REFERENCE_TIME tStart, tStop;
|
||||
HRESULT hr = pSample->GetTime(&tStart, &tStop);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
LONGLONG llPos = tStart / UNITS;
|
||||
LONG lLength = (LONG) ((tStop - tStart) / UNITS);
|
||||
|
||||
LONGLONG llTotal;
|
||||
LONGLONG llAvailable;
|
||||
|
||||
hr = m_pIo->Length(&llTotal, &llAvailable);
|
||||
if(llPos + lLength > llTotal)
|
||||
{
|
||||
// the end needs to be aligned, but may have been aligned
|
||||
// on a coarser alignment.
|
||||
LONG lAlign;
|
||||
m_pIo->Alignment(&lAlign);
|
||||
|
||||
llTotal = (llTotal + lAlign -1) & ~(lAlign-1);
|
||||
|
||||
if(llPos + lLength > llTotal)
|
||||
{
|
||||
lLength = (LONG) (llTotal - llPos);
|
||||
|
||||
// must be reducing this!
|
||||
ASSERT((llTotal * UNITS) <= tStop);
|
||||
tStop = llTotal * UNITS;
|
||||
pSample->SetTime(&tStart, &tStop);
|
||||
}
|
||||
}
|
||||
|
||||
BYTE* pBuffer;
|
||||
hr = pSample->GetPointer(&pBuffer);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
LONG cbActual;
|
||||
hr = m_pIo->SyncReadAligned(llPos,
|
||||
lLength,
|
||||
pBuffer,
|
||||
&cbActual,
|
||||
pSample);
|
||||
|
||||
pSample->SetActualDataLength(cbActual);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// collect the next ready sample
|
||||
STDMETHODIMP
|
||||
CAsyncOutputPin::WaitForNext(
|
||||
DWORD dwTimeout,
|
||||
IMediaSample** ppSample, // completed sample
|
||||
DWORD_PTR * pdwUser) // user context
|
||||
{
|
||||
CheckPointer(ppSample,E_POINTER);
|
||||
|
||||
LONG cbActual;
|
||||
IMediaSample* pSample=0;
|
||||
|
||||
HRESULT hr = m_pIo->WaitForNext(dwTimeout,
|
||||
(LPVOID*) &pSample,
|
||||
pdwUser,
|
||||
&cbActual);
|
||||
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
pSample->SetActualDataLength(cbActual);
|
||||
}
|
||||
|
||||
*ppSample = pSample;
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// synchronous read that need not be aligned.
|
||||
STDMETHODIMP
|
||||
CAsyncOutputPin::SyncRead(
|
||||
LONGLONG llPosition, // absolute Io position
|
||||
LONG lLength, // nr bytes required
|
||||
BYTE* pBuffer) // write data here
|
||||
{
|
||||
return m_pIo->SyncRead(llPosition, lLength, pBuffer);
|
||||
}
|
||||
|
||||
|
||||
// return the length of the file, and the length currently
|
||||
// available locally. We only support locally accessible files,
|
||||
// so they are always the same
|
||||
STDMETHODIMP
|
||||
CAsyncOutputPin::Length(
|
||||
LONGLONG* pTotal,
|
||||
LONGLONG* pAvailable)
|
||||
{
|
||||
return m_pIo->Length(pTotal, pAvailable);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CAsyncOutputPin::BeginFlush(void)
|
||||
{
|
||||
return m_pIo->BeginFlush();
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CAsyncOutputPin::EndFlush(void)
|
||||
{
|
||||
return m_pIo->EndFlush();
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CAsyncOutputPin::Connect(
|
||||
IPin * pReceivePin,
|
||||
const AM_MEDIA_TYPE *pmt // optional media type
|
||||
)
|
||||
{
|
||||
return m_pReader->Connect(pReceivePin, pmt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --- CAsyncReader implementation ---
|
||||
|
||||
#pragma warning(disable:4355)
|
||||
|
||||
CAsyncReader::CAsyncReader(
|
||||
TCHAR *pName,
|
||||
LPUNKNOWN pUnk,
|
||||
CAsyncStream *pStream,
|
||||
HRESULT *phr)
|
||||
: CBaseFilter(
|
||||
pName,
|
||||
pUnk,
|
||||
&m_csFilter,
|
||||
CLSID_AsyncStreamSource,
|
||||
NULL
|
||||
),
|
||||
m_OutputPin(
|
||||
phr,
|
||||
this,
|
||||
&m_Io,
|
||||
&m_csFilter),
|
||||
m_Io(pStream)
|
||||
{
|
||||
}
|
||||
|
||||
CAsyncReader::~CAsyncReader()
|
||||
{
|
||||
}
|
||||
|
||||
int CAsyncReader::GetPinCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
CBasePin * CAsyncReader::GetPin(int n)
|
||||
{
|
||||
if((GetPinCount() > 0) && (n == 0))
|
||||
{
|
||||
return &m_OutputPin;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
228
filter/asyncStreamflt/asyncrdr.h
Normal file
228
filter/asyncStreamflt/asyncrdr.h
Normal file
|
@ -0,0 +1,228 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// File: AsyncRdr.h
|
||||
//
|
||||
// Desc: DirectShow sample code - base library for I/O functionality.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __ASYNCRDR_H__
|
||||
#define __ASYNCRDR_H__
|
||||
|
||||
|
||||
//
|
||||
// AsyncRdr
|
||||
//
|
||||
// Defines an IO source filter.
|
||||
//
|
||||
// This filter (CAsyncReader) supports IBaseFilter and IFileSourceFilter interfaces from the
|
||||
// filter object itself. It has a single output pin (CAsyncOutputPin)
|
||||
// which supports IPin and IAsyncReader.
|
||||
//
|
||||
// This filter is essentially a wrapper for the CAsyncFile class that does
|
||||
// all the work.
|
||||
//
|
||||
|
||||
|
||||
// the filter class (defined below)
|
||||
class CAsyncReader;
|
||||
|
||||
|
||||
// the output pin class
|
||||
class CAsyncOutputPin
|
||||
: public IAsyncReader,
|
||||
public CBasePin
|
||||
{
|
||||
protected:
|
||||
CAsyncReader* m_pReader;
|
||||
CAsyncIo * m_pIo;
|
||||
|
||||
// This is set every time we're asked to return an IAsyncReader
|
||||
// interface
|
||||
// This allows us to know if the downstream pin can use
|
||||
// this transport, otherwise we can hook up to thinks like the
|
||||
// dump filter and nothing happens
|
||||
BOOL m_bQueriedForAsyncReader;
|
||||
|
||||
HRESULT InitAllocator(IMemAllocator **ppAlloc);
|
||||
|
||||
public:
|
||||
// constructor and destructor
|
||||
CAsyncOutputPin(
|
||||
HRESULT * phr,
|
||||
CAsyncReader *pReader,
|
||||
CAsyncIo *pIo,
|
||||
CCritSec * pLock);
|
||||
|
||||
~CAsyncOutputPin();
|
||||
|
||||
// --- CUnknown ---
|
||||
|
||||
// need to expose IAsyncReader
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID, void**);
|
||||
|
||||
// --- IPin methods ---
|
||||
STDMETHODIMP Connect(
|
||||
IPin * pReceivePin,
|
||||
const AM_MEDIA_TYPE *pmt // optional media type
|
||||
);
|
||||
|
||||
// --- CBasePin methods ---
|
||||
|
||||
// return the types we prefer - this will return the known
|
||||
// file type
|
||||
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
|
||||
|
||||
// can we support this type?
|
||||
HRESULT CheckMediaType(const CMediaType* pType);
|
||||
|
||||
// Clear the flag so we see if IAsyncReader is queried for
|
||||
HRESULT CheckConnect(IPin *pPin)
|
||||
{
|
||||
m_bQueriedForAsyncReader = FALSE;
|
||||
return CBasePin::CheckConnect(pPin);
|
||||
}
|
||||
|
||||
// See if it was asked for
|
||||
HRESULT CompleteConnect(IPin *pReceivePin)
|
||||
{
|
||||
if (m_bQueriedForAsyncReader) {
|
||||
return CBasePin::CompleteConnect(pReceivePin);
|
||||
} else {
|
||||
|
||||
#ifdef VFW_E_NO_TRANSPORT
|
||||
return VFW_E_NO_TRANSPORT;
|
||||
#else
|
||||
return E_FAIL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Remove our connection status
|
||||
HRESULT BreakConnect()
|
||||
{
|
||||
m_bQueriedForAsyncReader = FALSE;
|
||||
return CBasePin::BreakConnect();
|
||||
}
|
||||
|
||||
// --- IAsyncReader methods ---
|
||||
// pass in your preferred allocator and your preferred properties.
|
||||
// method returns the actual allocator to be used. Call GetProperties
|
||||
// on returned allocator to learn alignment and prefix etc chosen.
|
||||
// this allocator will be not be committed and decommitted by
|
||||
// the async reader, only by the consumer.
|
||||
STDMETHODIMP RequestAllocator(
|
||||
IMemAllocator* pPreferred,
|
||||
ALLOCATOR_PROPERTIES* pProps,
|
||||
IMemAllocator ** ppActual);
|
||||
|
||||
// queue a request for data.
|
||||
// media sample start and stop times contain the requested absolute
|
||||
// byte position (start inclusive, stop exclusive).
|
||||
// may fail if sample not obtained from agreed allocator.
|
||||
// may fail if start/stop position does not match agreed alignment.
|
||||
// samples allocated from source pin's allocator may fail
|
||||
// GetPointer until after returning from WaitForNext.
|
||||
STDMETHODIMP Request(
|
||||
IMediaSample* pSample,
|
||||
DWORD_PTR dwUser); // user context
|
||||
|
||||
// block until the next sample is completed or the timeout occurs.
|
||||
// timeout (millisecs) may be 0 or INFINITE. Samples may not
|
||||
// be delivered in order. If there is a read error of any sort, a
|
||||
// notification will already have been sent by the source filter,
|
||||
// and STDMETHODIMP will be an error.
|
||||
STDMETHODIMP WaitForNext(
|
||||
DWORD dwTimeout,
|
||||
IMediaSample** ppSample, // completed sample
|
||||
DWORD_PTR * pdwUser); // user context
|
||||
|
||||
// sync read of data. Sample passed in must have been acquired from
|
||||
// the agreed allocator. Start and stop position must be aligned.
|
||||
// equivalent to a Request/WaitForNext pair, but may avoid the
|
||||
// need for a thread on the source filter.
|
||||
STDMETHODIMP SyncReadAligned(
|
||||
IMediaSample* pSample);
|
||||
|
||||
|
||||
// sync read. works in stopped state as well as run state.
|
||||
// need not be aligned. Will fail if read is beyond actual total
|
||||
// length.
|
||||
STDMETHODIMP SyncRead(
|
||||
LONGLONG llPosition, // absolute file position
|
||||
LONG lLength, // nr bytes required
|
||||
BYTE* pBuffer); // write data here
|
||||
|
||||
// return total length of stream, and currently available length.
|
||||
// reads for beyond the available length but within the total length will
|
||||
// normally succeed but may block for a long period.
|
||||
STDMETHODIMP Length(
|
||||
LONGLONG* pTotal,
|
||||
LONGLONG* pAvailable);
|
||||
|
||||
// cause all outstanding reads to return, possibly with a failure code
|
||||
// (VFW_E_TIMEOUT) indicating they were cancelled.
|
||||
// these are defined on IAsyncReader and IPin
|
||||
STDMETHODIMP BeginFlush(void);
|
||||
STDMETHODIMP EndFlush(void);
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// The filter object itself. Supports IBaseFilter through
|
||||
// CBaseFilter and also IFileSourceFilter directly in this object
|
||||
|
||||
class CAsyncReader : public CBaseFilter
|
||||
{
|
||||
|
||||
protected:
|
||||
// filter-wide lock
|
||||
CCritSec m_csFilter;
|
||||
|
||||
// all i/o done here
|
||||
CAsyncIo m_Io;
|
||||
|
||||
// our output pin
|
||||
CAsyncOutputPin m_OutputPin;
|
||||
|
||||
// Type we think our data is
|
||||
CMediaType m_mt;
|
||||
|
||||
public:
|
||||
|
||||
// construction / destruction
|
||||
|
||||
CAsyncReader(
|
||||
TCHAR *pName,
|
||||
LPUNKNOWN pUnk,
|
||||
CAsyncStream *pStream,
|
||||
HRESULT *phr);
|
||||
|
||||
~CAsyncReader();
|
||||
|
||||
|
||||
// --- CBaseFilter methods ---
|
||||
int GetPinCount();
|
||||
CBasePin *GetPin(int n);
|
||||
|
||||
// --- Access our media type
|
||||
const CMediaType *LoadType() const
|
||||
{
|
||||
return &m_mt;
|
||||
}
|
||||
|
||||
virtual HRESULT Connect(
|
||||
IPin * pReceivePin,
|
||||
const AM_MEDIA_TYPE *pmt // optional media type
|
||||
)
|
||||
{
|
||||
return m_OutputPin.CBasePin::Connect(pReceivePin, pmt);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //__ASYNCRDR_H__
|
26
filter/include/StreamSourceflt.h
Normal file
26
filter/include/StreamSourceflt.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
// This is a header file for the stream/file source filter
|
||||
|
||||
#ifndef __ASYNC_STREAMSOURCE_H__
|
||||
#define __ASYNC_STREAMSOURCE_H__
|
||||
|
||||
// {2AE44C10-B451-4B01-9BBE-A5FBEF68C9D4}
|
||||
DEFINE_GUID(CLSID_AsyncStreamSource,
|
||||
0x2ae44c10, 0xb451, 0x4b01, 0x9b, 0xbe, 0xa5, 0xfb, 0xef, 0x68, 0xc9, 0xd4);
|
||||
|
||||
// {268424D1-B6E9-4B28-8751-B7774F5ECF77}
|
||||
DEFINE_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;
|
||||
};
|
||||
|
||||
#endif // __ASYNC_STREAMSOURCE_H__
|
BIN
filter/lib/AsyncStreamflt.ax
Normal file
BIN
filter/lib/AsyncStreamflt.ax
Normal file
Binary file not shown.
1
filter/lib/register.bat
Normal file
1
filter/lib/register.bat
Normal file
|
@ -0,0 +1 @@
|
|||
@regsvr32 AsyncStreamflt.ax
|
1
filter/lib/unregister.bat
Normal file
1
filter/lib/unregister.bat
Normal file
|
@ -0,0 +1 @@
|
|||
@regsvr32 /u AsyncStreamflt.ax
|
Loading…
Add table
Reference in a new issue