Merge pull request #1803 from oioitff/atrac3plus

Add atrac3plus filter for windows
This commit is contained in:
Henrik Rydgård 2013-05-19 08:09:01 -07:00
commit a1060ffabd
22 changed files with 4020 additions and 13 deletions

View file

@ -67,7 +67,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\include;../common;..;../native;../native/ext/glew;../ext/zlib</AdditionalIncludeDirectories>
<PreprocessorDefinitions>USE_FFMPEG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<PreprocessorDefinitions>USE_FFMPEG;_USE_DSHOW_;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
@ -107,7 +107,7 @@
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<FloatingPointModel>Fast</FloatingPointModel>
<PreprocessorDefinitions>USE_FFMPEG;_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<PreprocessorDefinitions>USE_FFMPEG;_USE_DSHOW_;_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
</ClCompile>
<Link>
@ -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" />

View file

@ -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
View file

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

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

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

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

@ -0,0 +1,523 @@
#ifdef _USE_DSHOW_
#include "audioPlayer.h"
#include <dshow.h>
#include "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
View file

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

381
Core/HW/qeditsimple.h Normal file
View 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__

View 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;
}

View 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

View 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;
};

View 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

View 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

View 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>

View 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>

View 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;
}

View 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__

View 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;
}
}

View 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__

View 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__

Binary file not shown.

1
filter/lib/register.bat Normal file
View file

@ -0,0 +1 @@
@regsvr32 AsyncStreamflt.ax

View file

@ -0,0 +1 @@
@regsvr32 /u AsyncStreamflt.ax