📄 source.cpp
字号:
IDirectDrawSurface* pDDSurface;
IAudioMediaStream* pAudMStream;
IAudioStreamSample* pAudSample;
IAudioData* pAudData;
BYTE* audioBuffer;
int next_frame, first_audio_sample, next_audio_sample;
VideoInfo vi;
// frameLength;
// totalTime;
bool OpenVideo(const char* fileName);
bool OpenAudio(const char* fileName);
public:
DirectShowSource(const char* fileName);
~DirectShowSource();
void GetFrame(int n, unsigned char* buf);
void GetAudio(void* buf, int start, int count);
void GetVideoInfo(VideoInfo* pvi);
bool GetParity(int n);
static PVideoFilter __cdecl Create(const FilterInfo*, const Arg* args, const char*) {
return new DirectShowSource(args[0].string);
}
};
void DirectShowSource::GetVideoInfo(VideoInfo* pvi) { *pvi = vi; }
bool DirectShowSource::GetParity(int n) { return false; }
DirectShowSource::DirectShowSource(const char* fileName) {
pDD = NULL;
pMMStream = NULL;
pAudMMStream = NULL;
pVidStream = NULL;
pAudStream = NULL;
pDDMStream = NULL;
pDDSample = NULL;
pDDSurface = NULL;
pAudMStream = NULL;
pAudSample = NULL;
pAudData = NULL;
audioBuffer = NULL;
memset(&vi, 0, sizeof(VideoInfo));
try {
// need non-short-circuiting & here!
if (!OpenVideo(fileName) & !OpenAudio(fileName))
throw FilterChainError(Sprintf("DirectShowSource: Could not open %s", fileName));
if (!vi.HasVideo() && !vi.HasAudio())
throw FilterChainError(Sprintf("DirectShowSource: no video or audio stream found"));
}
catch (FilterChainError) {
this->~DirectShowSource();
throw;
}
next_frame = 0;
first_audio_sample = 0;
next_audio_sample = 0;
}
bool DirectShowSource::OpenVideo(const char* fileName) {
WCHAR wPath[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, fileName, -1, wPath, sizeof(wPath)/sizeof(wPath[0]));
if (CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER,
IID_IAMMultiMediaStream, (void **)&pMMStream) != S_OK)
{
throw FilterChainError("DirectShowSource: Could not create AMMultiMediaStream (video)");
}
if (pMMStream->Initialize(STREAMTYPE_READ, 0, NULL) != S_OK)
throw FilterChainError("DirectShowSource: Could not initialize AMMultiMediaStream (video)");
if (pMMStream->AddMediaStream(NULL, &MSPID_PrimaryVideo, 0, NULL) != S_OK)
throw FilterChainError("DirectShowSource: Could not add PrimaryVideo to AMMultiMediaStream");
if (pMMStream->OpenFile(wPath, AMMSF_NOCLOCK) != S_OK)
return false;
if (pMMStream->GetMediaStream(MSPID_PrimaryVideo, &pVidStream) != S_OK)
throw FilterChainError("DirectShowSource: Could not get PrimaryVideo");
if (pVidStream->QueryInterface(IID_IDirectDrawMediaStream, (void **)&pDDMStream) != S_OK)
throw FilterChainError("DirectShowSource: Could not get IDirectDrawMediaStream from PrimaryVideo");
__int64 frameLength;
if (pDDMStream->GetTimePerFrame(&frameLength) != S_OK)
return true;
// throw FilterChainError("DirectShowSource: Could not get time per frame from IDirectDrawStream");
__int64 totalTime;
if (pMMStream->GetDuration(&totalTime) != S_OK)
throw FilterChainError("DirectShowSource: Could not get Duration from IMultiMediaStream (video)");
vi.num_frames = long((totalTime+(frameLength>>1)) / frameLength);
vi.fps_numerator = 10000000;
vi.fps_denominator = int(frameLength);
vi.field_based = false;
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
if (pDDMStream->GetFormat(&ddsd, NULL, NULL, NULL) != S_OK)
throw FilterChainError("DirectShowSource: Could not get video width and height");
if (!(ddsd.dwFlags & DDSD_WIDTH) || !(ddsd.dwFlags & DDSD_HEIGHT))
throw FilterChainError("DirectShowSource: Could not get video width and height 1");
vi.width = ddsd.dwWidth;
vi.height = ddsd.dwHeight;
vi.pixel_type = VideoInfo::BGR24;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwWidth = vi.width;
ddsd.dwHeight = vi.height;
ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
ddsd.ddpfPixelFormat.dwRBitMask = 0x00FF0000;
ddsd.ddpfPixelFormat.dwGBitMask = 0x0000FF00;
ddsd.ddpfPixelFormat.dwBBitMask = 0x000000FF;
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
if (DirectDrawCreate(NULL, &pDD, NULL) != DD_OK)
throw FilterChainError("DirectShowSource: Could not create a DirectDraw instance");
if (pDD->SetCooperativeLevel(GetDesktopWindow(), DDSCL_NORMAL) != DD_OK)
throw FilterChainError("DirectShowSource: Could not set the DirectDraw Cooperative level");
if (pDD->CreateSurface(&ddsd, &pDDSurface, NULL) != DD_OK)
throw FilterChainError("DirectShowSource: Could not create a DirectDraw surface");
if (pDDMStream->SetDirectDraw(pDD) != S_OK)
throw FilterChainError("DirectShowSource: Could not set the DirectDraw surface");
if (pDDMStream->CreateSample(pDDSurface, NULL, 0, &pDDSample) != S_OK)
throw FilterChainError("DirectShowSource: Could not create a DirectDraw sample");
if (pMMStream->SetState(STREAMSTATE_RUN) != S_OK)
throw FilterChainError("DirectShowSource: Could not start stream running (video)");
return true;
}
bool DirectShowSource::OpenAudio(const char* fileName) {
WCHAR wPath[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, fileName, -1, wPath, sizeof(wPath)/sizeof(wPath[0]));
if (CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER,
IID_IAMMultiMediaStream, (void **)&pAudMMStream) != S_OK)
{
throw FilterChainError("DirectShowSource: Could not create AMMultiMediaStream (audio)");
}
if (pAudMMStream->Initialize(STREAMTYPE_READ, 0, NULL) != S_OK)
throw FilterChainError("DirectShowSource: Could not initialize AMMultiMediaStream (audio)");
if (pAudMMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, 0, NULL) != S_OK)
throw FilterChainError("DirectShowSource: Could not add PrimaryAudio to AMMultiMediaStream");
if (pAudMMStream->OpenFile(wPath, AMMSF_NOCLOCK) != S_OK)
return false;
__int64 totalTime;
if (pAudMMStream->GetDuration(&totalTime) != S_OK)
throw FilterChainError("DirectShowSource: Could not get Duration from IMultiMediaStream");
if (pAudMMStream->GetMediaStream(MSPID_PrimaryAudio, &pAudStream) != S_OK)
throw FilterChainError("DirectShowSource: Could not get PrimaryAudio");
if (pAudStream->QueryInterface(IID_IAudioMediaStream, (void**)&pAudMStream) != S_OK)
throw FilterChainError("DirectShowSource: Could not get IAudioMediaStream from PrimaryAudio");
WAVEFORMATEX audioFormat;
if (pAudMStream->GetFormat(&audioFormat) != S_OK)
return true;
if (audioFormat.wFormatTag != WAVE_FORMAT_PCM)
return true; // other types not supported
if (CoCreateInstance(CLSID_AMAudioData, NULL, CLSCTX_INPROC_SERVER,
IID_IAudioData, (void **)&pAudData) != S_OK)
return true; // "Could not create IAudioData"
vi.audio_samples_per_second = audioFormat.nSamplesPerSec;
vi.num_audio_samples = int(totalTime / 10000000.0 * audioFormat.nSamplesPerSec);
vi.stereo = (audioFormat.nChannels == 2);
vi.sixteen_bit = (audioFormat.wBitsPerSample == 16);
int audioBufferSize = vi.BytesFromAudioSamples(vi.audio_samples_per_second);
audioBuffer = new BYTE[audioBufferSize];
if (!audioBuffer)
throw FilterChainError("DirectShowSource: Could not create an audio buffer");
if (pAudData->SetBuffer(audioBufferSize, audioBuffer, 0) != S_OK)
throw FilterChainError("DirectShowSource: Could not set the audio buffer in IAudioData");
if (pAudData->SetFormat(&audioFormat) != S_OK)
throw FilterChainError("DirectShowSource: Could not set the format in IAudioData");
if (pAudMStream->CreateSample(pAudData, 0, &pAudSample) != S_OK)
throw FilterChainError("DirectShowSource: Could not create IAudioStreamSample");
if (pAudMMStream->SetState(STREAMSTATE_RUN) != S_OK)
throw FilterChainError("DirectShowSource: Could not start stream running (audio)");
return true;
}
void DirectShowSource::GetFrame(int n, unsigned char* buf) {
n = min(max(n,0),vi.num_frames-1);
if (n != next_frame) {
// note: vi.fps_denominator happens to equal frame length in 10^-7 sec. units
__int64 pos = n * __int64(vi.fps_denominator);
if (pMMStream->Seek(pos) != S_OK)
throw FilterChainError(Sprintf("DirectShowSource: Seek to %d failed", n));
}
next_frame=n+1;
if (FAILED(pDDSample->Update(0, NULL, NULL, 0)))
throw FilterChainError("DirectShowSource: DDSample::Update failed");
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (pDDSurface->Lock(NULL, &ddsd, 0, NULL) != DD_OK)
throw FilterChainError("DirectShowSource: DDSurface::Lock failed");
unsigned char* src = (unsigned char*)ddsd.lpSurface + vi.width*4*(vi.height-1);
unsigned char* dst = buf;
for (int y=vi.height; y; --y) {
for (int x=0; x<vi.width; ++x) {
dst[x*3+0] = src[x*4+0];
dst[x*3+1] = src[x*4+1];
dst[x*3+2] = src[x*4+2];
}
dst += vi.width*3;
src -= vi.width*4;
}
if (pDDSurface->Unlock(NULL) != S_OK)
throw FilterChainError("DirectShowSource: DDSurface::Unlock failed");
}
void DirectShowSource::GetAudio(void* buf, int start, int count) {
count = vi.AudioSamplesFromBytes(count);
if (start < 0) {
int leading_zeroes = min(0-start, count);
memset(buf, 0, vi.BytesFromAudioSamples(leading_zeroes));
count -= leading_zeroes;
start += leading_zeroes;
}
if (start+count > vi.num_audio_samples) {
if (start >= vi.num_audio_samples) {
memset(buf, 0, vi.BytesFromAudioSamples(count));
return;
} else {
memset((char*)buf+vi.BytesFromAudioSamples(vi.num_audio_samples-start), 0, vi.BytesFromAudioSamples(start+count-vi.num_audio_samples));
count = vi.num_audio_samples - start;
}
}
while (count) {
if (first_audio_sample <= start && next_audio_sample > start) {
const int from = start;
const int to = min(start+count, next_audio_sample);
memcpy(buf, audioBuffer + vi.BytesFromAudioSamples(from-first_audio_sample), vi.BytesFromAudioSamples(to-from));
buf = (char*)buf + vi.BytesFromAudioSamples(to-from);
count -= to-from;
start = to;
if (!count) return;
}
if (start != next_audio_sample) {
__int64 pos = start * 10000000i64 / vi.audio_samples_per_second;
if (pAudMMStream->Seek(pos) != S_OK)
throw FilterChainError("DirectShowSource: AudMMStream::Seek failed");
}
first_audio_sample = start;
next_audio_sample = first_audio_sample + vi.audio_samples_per_second;
if (FAILED(pAudSample->Update(0, NULL, NULL, 0)))
throw FilterChainError("DirectShowSource: AudSample::Update failed");
}
}
DirectShowSource::~DirectShowSource()
{
if (pAudSample) pAudSample->Release();
if (pAudData) pAudData->Release();
if (pAudMStream) pAudMStream->Release();
if (pAudStream) pAudStream->Release();
if (audioBuffer) delete[] audioBuffer;
if (pAudMMStream) pAudMMStream->Release();
if (pDDSample) pDDSample->Release();
if (pDDSurface) pDDSurface->Release();
if (pDD) pDD->Release();
if (pDDMStream) pDDMStream->Release();
if (pVidStream) pVidStream->Release();
if (pMMStream) pMMStream->Release();
}
/********************************************************************
********************************************************************/
PVideoFilter __cdecl Create_SegmentedAVISource(const FilterInfo*, const Arg* args, const char* arg_types) {
PVideoFilter result = 0;
for (int i = 0; arg_types[i]; ++i) {
char basename[260];
strcpy(basename, args[i].string);
char* extension = strrchr(basename, '.');
if (extension)
*extension++ = 0;
else
extension = "";
for (int j = 0; j < 100; ++j) {
char filename[260];
wsprintf(filename, "%s.%02d.%s", basename, j, extension);
if (GetFileAttributes(filename) != (DWORD)-1) { // check if file exists
PVideoFilter clip = new AVISource(filename, 0);
result = !result ? clip : new_Splice(false, result, clip);
}
}
}
if (!result)
throw FilterChainError("SegmentedAVISource: no files found!");
return result;
}
PVideoFilter __cdecl Create_Version(const FilterInfo*, const Arg*, const char*) {
VideoInfo vi;
memset(&vi, 0, sizeof(vi));
vi.width = 512;
vi.height = 32;
vi.fps_denominator = 1;
vi.fps_numerator = 15;
vi.num_frames = 150;
vi.pixel_type = VideoInfo::BGR24;
return new_Subtitle("Avisynth v0.3, copyright 2000 Ben Rudiak-Gould", -1, 23, 0, 999, "Arial", 24, 0xFF8800, 0, new Blackness(&vi));
}
FilterInfo source_filters[] = {
{ "AVISource", "s", AVISource::Create },
{ "AVIFileSource", "s", AVISource::CreateAVIFile },
{ "WAVSource", "s", AVISource::CreateAVIFile },
{ "OpenDMLSource", "s", AVISource::CreateOpenDML },
{ "SegmentedAVISource", "s+", Create_SegmentedAVISource },
{ "IPCSource", "s", IPCSource::Create },
{ "DirectShowSource", "s", DirectShowSource::Create },
{ "Blackness", "ic", Blackness::Create },
{ "Version", "", Create_Version },
{ 0,0,0 }
};
PVideoFilter new_Blackness(VideoInfo* pvi) { return new Blackness(pvi); }
PVideoFilter new_Blackness(PVideoFilter pvf, int num_frames) { return new Blackness(pvf, num_frames); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -