Direct Audio
摘自
Direct Audio是一个复合组件,它由DirectSound和DirectMusic两个组件组成。DirectMusic在DirectX8中得到了巨大的增强,但是DirectSound基本保持原有的状态。DirectSound是主要的数字声音回放组件。DirectMusic处理所有的乐曲格式,包括MIDI、DirectMusic本地格式文件和波表文件。DirectMusic处理完之后将它们送入DirectSound中做其他处理,这意味着回放MIDI的时候可以使用数字化的乐器。
以下是DirectSound COM接口:
IDirectSound8:DirectSound接口。
IDirectSoundBuffer8:主缓冲区和辅助缓冲区接口,保存数据并控制回放。
IDirectSoundNotify8:通知对象,通知应用程序指定播放位置已经达到。
各个对象间的关系如下图所示:
DirectSound8是主接口,用它来创建缓冲区(IDirectSoundBuffer8),然后用缓冲区接口创建通告接口(IDirectSoundNotify8),通告接口告诉应用程序指定的位置已经到达,通告接口在流化音频文件时非常有用。
DirectSound例子
/***************************************************************************************
PURPOSE:
Streaming Playback Demo
***************************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <dsound.h>
#include "resource.h"
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dsound.lib")
#pragma warning(disable : 4996)
#define Safe_Release(p) if((p)) (p)->Release();
// .WAV file header
struct WAVE_HEADER
{
char riff_sig[4]; // 'RIFF'
long waveform_chunk_size; // 8
char wave_sig[4]; // 'WAVE'
char format_sig[4]; // 'fmt ' (notice space after)
long format_chunk_size; // 16;
short format_tag; // WAVE_FORMAT_PCM
short channels; // # of channels
long sample_rate; // sampling rate
long bytes_per_sec; // bytes per second
short block_align; // sample block alignment
short bits_per_sample; // bits per second
char data_sig[4]; // 'data'
long data_size; // size of waveform data
};
// window handles, class.
HWND g_hwnd;
char g_class_name[] = "StreamClass";
IDirectSound8* g_ds; // directsound component
IDirectSoundBuffer8* g_ds_buffer; // sound buffer object
IDirectSoundNotify8* g_ds_notify; // notification object
HANDLE g_thread_handle; // thread handle
DWORD g_thread_id; // thread id
HANDLE g_events[4]; // notification handles
FILE* g_fp; // .WAV file handle
long g_ds_size; // directsound data buffer size
long g_ds_pos; // current directsound buffer position
long g_ds_leave; // leave directsound buffer data needed to be played
//--------------------------------------------------------------------------------
// Create wave header information from wave file.
//--------------------------------------------------------------------------------
IDirectSoundBuffer8* Create_Buffer_From_WAV(FILE* fp, WAVE_HEADER* wave_header)
{
IDirectSoundBuffer* ds_buffer_primary;
IDirectSoundBuffer8* ds_buffer_second;
DSBUFFERDESC ds_buffer_desc;
WAVEFORMATEX wave_format;
// read in the header from beginning of file
fseek(fp, 0, SEEK_SET);
fread(wave_header, 1, sizeof(WAVE_HEADER), fp);
// check the sig fields. returning if an error.
if(memcmp(wave_header->riff_sig, "RIFF", 4) || memcmp(wave_header->wave_sig, "WAVE", 4) ||
memcmp(wave_header->format_sig, "fmt ", 4) || memcmp(wave_header->data_sig, "data", 4))
{
return NULL;
}
// setup the playback format
ZeroMemory(&wave_format, sizeof(WAVEFORMATEX));
wave_format.wFormatTag = WAVE_FORMAT_PCM;
wave_format.nChannels = wave_header->channels;
wave_format.nSamplesPerSec = wave_header->sample_rate;
wave_format.wBitsPerSample = wave_header->bits_per_sample;
wave_format.nBlockAlign = wave_format.wBitsPerSample / 8 * wave_format.nChannels;
wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign;
// create the sound buffer using the header data
ZeroMemory(&ds_buffer_desc, sizeof(DSBUFFERDESC));
ds_buffer_desc.dwSize = sizeof(DSBUFFERDESC);
ds_buffer_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_LOCSOFTWARE;
ds_buffer_desc.dwBufferBytes = 65536;
ds_buffer_desc.lpwfxFormat = &wave_format;
// create main sound buffer
if(FAILED(g_ds->CreateSoundBuffer(&ds_buffer_desc, &ds_buffer_primary, NULL)))
return NULL;
// get newer interface
if(FAILED(ds_buffer_primary->QueryInterface(IID_IDirectSoundBuffer8, (void**)&ds_buffer_second)))
{
ds_buffer_primary->Release();
return NULL;
}
// return the interface
return ds_buffer_second;
}
//--------------------------------------------------------------------------------
// Load sound data from second directsound buffer.
//--------------------------------------------------------------------------------
BOOL Load_Sound_Data(IDirectSoundBuffer8* ds_buffer, long lock_pos, long lock_size, FILE* fp)
{
BYTE* ptr1;
BYTE* ptr2;
DWORD size1, size2;
if(lock_size == 0)
return FALSE;
// lock the sound buffer at position specified
if(FAILED(ds_buffer->Lock(lock_pos, lock_size, (void**)&ptr1, &size1, (void**)&ptr2, &size2, 0)))
return FALSE;
// read in the data
fread(ptr1, 1, size1, fp);
if(ptr2 != NULL)
fread(ptr2, 1, size2, fp);
// unlock it
ds_buffer->Unlock(ptr1, size1, ptr2, size2);
return TRUE;
}
//--------------------------------------------------------------------------------
// Handle directsound nofification evenet, just stream load sound buffer.
//--------------------------------------------------------------------------------
DWORD Handle_Notifications(LPVOID thread_data)
{
while(1)
{
// wait for a message
//
// return when any one or all of the specified objects are in the signaled state or the time-out
// interval elapses.
DWORD result = MsgWaitForMultipleObjects(4, g_events, FALSE, INFINITE, QS_ALLEVENTS);
// get notification #
DWORD thread_index = result - WAIT_OBJECT_0;
// check for update #
if(thread_index >= 0 && thread_index < 4)
{
// stop sound and quit thread if no more
if(g_ds_leave == 0)
ExitThread(0);
// seek to read position in file
fseek(g_fp, g_ds_pos, SEEK_SET);
// stream in data based on amount of data left
if(g_ds_leave <= 16384)
{
// if this is reached, then end of sound is coming up.
Load_Sound_Data(g_ds_buffer, thread_index * 16384, g_ds_leave, g_fp);
g_ds_leave = 0;
}
else
{
Load_Sound_Data(g_ds_buffer, thread_index * 16384, 65536, g_fp);
// reset directsound buffer leave and current position
g_ds_leave -= 16384;
g_ds_pos += 16384;
}
}
}
return 0;
}
//--------------------------------------------------------------------------------
// Play WAVE file sound which specified by filename.
//--------------------------------------------------------------------------------
void Play_Stream_Sound(char* filename)
{
DSBPOSITIONNOTIFY pos_notify[4];
WAVE_HEADER wave_header;
// open the source file
if((g_fp = fopen(filename, "rb")) == NULL)
return;
// create a 2 second buffer to stream in wave
if((g_ds_buffer = Create_Buffer_From_WAV(g_fp, &wave_header)) == NULL)
{
fclose(g_fp);
return;
}
// get streaming size and pointer
g_ds_size = wave_header.data_size;
g_ds_pos = sizeof(WAVE_HEADER);
g_ds_leave = g_ds_size;
// create a thread for notifications
g_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Handle_Notifications, NULL, 0, &g_thread_id);
// create failed
if(g_thread_handle == NULL)
return;
// create the notification interface
if(FAILED(g_ds_buffer->QueryInterface(IID_IDirectSoundNotify8, (void**)&g_ds_notify)))
return;
// create the event handles and set the notifications
for(long i = 0; i < 4; i++)
{
// create an unnamed event object
g_events[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
pos_notify[i].dwOffset = 16384 * (i+1) - 1;
pos_notify[i].hEventNotify = g_events[i];
}
// set the notification position
//
// During capture or playback, whenever the read or play cursor reached one of the specified offsets,
// the associated event is signaled.
g_ds_notify->SetNotificationPositions(4, pos_notify);
// fill buffer completely with sound
// advance file pointer to data buffer's head
fseek(g_fp, sizeof(WAVE_HEADER), SEEK_SET);
// load sound buffer data with 65536 bytes
Load_Sound_Data(g_ds_buffer, 0, 65536, g_fp);
// reset leave sound buffer and current sound buffer position
g_ds_leave -= 65536;
g_ds_pos += 65536;
// play sound looping
g_ds_buffer->SetCurrentPosition(0);
g_ds_buffer->SetVolume(DSBVOLUME_MAX);
g_ds_buffer->Play(0, 0, DSBPLAY_LOOPING);
}
//--------------------------------------------------------------------------------
// Window procedure.
//--------------------------------------------------------------------------------
long WINAPI Window_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return (long) DefWindowProc(hwnd, msg, wParam, lParam);
}
//--------------------------------------------------------------------------------
// Main function, routine entry.
//--------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
WNDCLASS win_class;
MSG msg;
// create window class and register it
win_class.style = CS_HREDRAW | CS_VREDRAW;
win_class.lpfnWndProc = Window_Proc;
win_class.cbClsExtra = 0;
win_class.cbWndExtra = DLGWINDOWEXTRA;
win_class.hInstance = inst;
win_class.hIcon = LoadIcon(inst, IDI_APPLICATION);
win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
win_class.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
win_class.lpszMenuName = NULL;
win_class.lpszClassName = g_class_name;
if(! RegisterClass(&win_class))
return FALSE;
// create the main window
g_hwnd = CreateDialog(inst, MAKEINTRESOURCE(IDD_STREAM), 0, NULL);
ShowWindow(g_hwnd, cmd_show);
UpdateWindow(g_hwnd);
// initialize and configure directsound
// creates and initializes an object that supports the IDirectSound8 interface
if(FAILED(DirectSoundCreate8(NULL, &g_ds, NULL)))
{
MessageBox(NULL, "Unable to create DirectSound object", "Error", MB_OK);
return 0;
}
// set the cooperative level of the application for this sound device
g_ds->SetCooperativeLevel(g_hwnd, DSSCL_NORMAL);
// play a streaming sound
Play_Stream_Sound("test.wav");
if(g_ds_buffer)
{
// play sound looping
g_ds_buffer->SetCurrentPosition(0);
// set volume
g_ds_buffer->SetVolume(DSBVOLUME_MAX);
// play sound
g_ds_buffer->Play(0, 0, DSBPLAY_LOOPING);
}
// start message pump, waiting for signal to quit.
ZeroMemory(&msg, sizeof(MSG));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// stop sound
if(g_ds_buffer)
g_ds_buffer->Stop();
// kill the thread
if(g_thread_handle != NULL)
{
// terminates thread
TerminateThread(g_thread_handle, 0);
// closes an open object handle
CloseHandle(g_thread_handle);
}
// release the event handle
for(int i = 0; i < 4; i++)
CloseHandle(g_events[i]);
// close .WAV file
if(g_fp)
fclose(g_fp);
// release directsound objects
Safe_Release(g_ds_buffer);
Safe_Release(g_ds);
UnregisterClass(g_class_name, inst);
return (int) msg.wParam;
}
使用DirectMusic
使用 DirectMusic的第一步是创建一个主对象,我们把这个对象叫做演奏器对象(performance object),它表现整个音乐系统,第二步创建一个叫加载器(loader object)的对象,加载器加载所有原始的音乐文件。
它们之间的交互过程如下所示:
最后必须加载音乐小节到音乐片段对象(segment object)中,多个小节可以被同时加载,并一个接一个地播放,这可以让我们创建更具动态效果的音乐。
DirectMusic例子
/***************************************************************************************
PURPOSE:
Midi Playing Demo
***************************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <dsound.h>
#include <dmusici.h>
#include "resource.h"
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dsound.lib")
#pragma warning(disable : 4996)
#define Safe_Release(p) if((p)) (p)->Release();
// window handles, class.
HWND g_hwnd;
char g_class_name[] = "MidiPlayClass";
IDirectSound8* g_ds; // directsound component
IDirectMusicPerformance8* g_dm_performance; // directmusic performance
IDirectMusicLoader8* g_dm_loader; // directmusic loader
IDirectMusicSegment8* g_dm_segment; // directmusic segment
//--------------------------------------------------------------------------------
// Window procedure.
//--------------------------------------------------------------------------------
long WINAPI Window_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return (long) DefWindowProc(hwnd, msg, wParam, lParam);
}
//--------------------------------------------------------------------------------
// Load DirectMusic collection object.
//--------------------------------------------------------------------------------
IDirectMusicCollection8* Load_DLS_Collection(char* filename)
{
DMUS_OBJECTDESC dm_obj_desc;
IDirectMusicCollection8* dm_collection;
// get the object
ZeroMemory(&dm_obj_desc, sizeof(DMUS_OBJECTDESC));
dm_obj_desc.dwSize = sizeof(DMUS_OBJECTDESC);
dm_obj_desc.guidClass = CLSID_DirectMusicCollection;
dm_obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;
// Converts a sequence of multibyte characters to a corresponding sequence of wide characters
mbstowcs(dm_obj_desc.wszFileName, filename, MAX_PATH);
// retrieves an object from a file or resource and returns the speficied interface
if(FAILED(g_dm_loader->GetObject(&dm_obj_desc, IID_IDirectMusicCollection8, (LPVOID*)&dm_collection)))
return NULL;
return dm_collection;
}
//--------------------------------------------------------------------------------
// Play midi file which specified with filename.
//--------------------------------------------------------------------------------
BOOL Play_Midi(char* filename)
{
DMUS_OBJECTDESC dm_obj_desc;
// get the object
ZeroMemory(&dm_obj_desc, sizeof(DMUS_OBJECTDESC));
dm_obj_desc.dwSize = sizeof(DMUS_OBJECTDESC);
dm_obj_desc.guidClass = CLSID_DirectMusicSegment;
dm_obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;
// Converts a sequence of multibyte characters to a corresponding sequence of wide characters
mbstowcs(dm_obj_desc.wszFileName, filename, MAX_PATH);
// retrieves an object from a file or resource and returns the speficied interface
if(FAILED(g_dm_loader->GetObject(&dm_obj_desc, IID_IDirectMusicSegment8, (LPVOID*)&g_dm_segment)))
return FALSE;
// setup midi playing
if(strstr(filename, ".mid"))
{
// set data on a track inside the segment
if(FAILED(g_dm_segment->SetParam(GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, NULL)))
return FALSE;
}
// downloads band data to a performance
if(FAILED(g_dm_segment->Download(g_dm_performance)))
return FALSE;
// set to loop forever
g_dm_segment->SetRepeats(DMUS_SEG_REPEAT_INFINITE);
// play on default audio path
g_dm_performance->PlaySegmentEx(g_dm_segment, NULL, NULL, 0, 0, NULL, NULL, NULL);
return TRUE;
}
//--------------------------------------------------------------------------------
// Main function, routine entry.
//--------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
WNDCLASS win_class;
MSG msg;
// create window class and register it
win_class.style = CS_HREDRAW | CS_VREDRAW;
win_class.lpfnWndProc = Window_Proc;
win_class.cbClsExtra = 0;
win_class.cbWndExtra = DLGWINDOWEXTRA;
win_class.hInstance = inst;
win_class.hIcon = LoadIcon(inst, IDI_APPLICATION);
win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
win_class.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
win_class.lpszMenuName = NULL;
win_class.lpszClassName = g_class_name;
if(! RegisterClass(&win_class))
return FALSE;
// create the main window
g_hwnd = CreateDialog(inst, MAKEINTRESOURCE(IDD_MIDIPLAY), 0, NULL);
ShowWindow(g_hwnd, cmd_show);
UpdateWindow(g_hwnd);
// initialize and configure directsound
// creates and initializes an object that supports the IDirectSound8 interface
if(FAILED(DirectSoundCreate8(NULL, &g_ds, NULL)))
{
MessageBox(NULL, "Unable to create DirectSound object", "Error", MB_OK);
return 0;
}
// set the cooperative level of the application for this sound device
g_ds->SetCooperativeLevel(g_hwnd, DSSCL_NORMAL);
// initialize COM
//
// initialize the COM library on the current thread and identifies the concurrency model as single-thread
// apartment (STA).
CoInitialize(0);
// create the DirectMusic performance object
//
// creates a single uninitialized object of the class associated with a specified CLSID.
CoCreateInstance(CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance8,
(void**)&g_dm_performance);
// create the DirectMusic loader object
CoCreateInstance(CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC, IID_IDirectMusicLoader8, (void**)&g_dm_loader);
// initialize the performance with the standard audio path.
// this initialize both directmusic and directsound and sets up the synthesizer.
g_dm_performance->InitAudio(NULL, NULL, g_hwnd, DMUS_APATH_SHARED_STEREOPLUSREVERB, 128, DMUS_AUDIOF_ALL, NULL);
// tell directmusic where the default search path is
char path[MAX_PATH];
WCHAR search_path[MAX_PATH];
GetCurrentDirectory(MAX_PATH, path);
// maps a character string to a wide-character (Unicode) string
MultiByteToWideChar(CP_ACP, 0, path, -1, search_path, MAX_PATH);
// set a search path for finding object files
g_dm_loader->SetSearchDirectory(GUID_DirectMusicAllTypes, search_path, FALSE);
// play midi
Play_Midi("escape.mid");
// start message pump, waiting for signal to quit.
ZeroMemory(&msg, sizeof(MSG));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// release directsound objects
if(g_dm_segment)
g_dm_segment->Unload(g_ds);
if(g_dm_loader)
g_dm_loader->ReleaseObjectByUnknown(g_dm_segment);
if(g_dm_segment)
g_dm_segment->Release();
if(g_ds)
g_ds->Release();
UnregisterClass(g_class_name, inst);
// release COM system
//
// Closes the COM library on the current thread, unloads all DLLs loaded by the thread, frees any other
// resources that the thread maintains, and forces all RPC connections on the thread to close.
CoUninitialize();
return (int) msg.wParam;
}
介绍
DirectShow是Windows平台的一种流多媒体架构(architecture)。使用它,你能够做到:
DirectX是一组COM接口组件,DirectShow也不例外,DirectShow中经常使用的组件如下:
IGraphBuilder: 帮助建立滤波图,滤波过滤图是一组对象或接口的集合,用于处理某种媒体文件。
IMediaControl:控制数据在滤波图中的流程,使用该接口控制音乐的回放。
IMediaEvents: 从滤波图中获取事件及通告,当希望知道在滤波图中发生了什么的时候这个对象很有用,比如希望知道一个音乐是否仍然在播放或者已经停止播放。
其中第一个接口IGraphBuilder是比较重要的对象,其他对象都依赖于它,或者靠它创建。它创建滤波器,用于处理媒体问题,另外很多有用的功能也是依靠这个对象。
编译环境
include <Dshow.h>
linking “strmiids.lib”
第一步-初始化COM
DirectShow基于COM模型,你需要首先初始化COM:CoInitialize()。当然使用完COM需要:CoUninitialize().
Fiter
DirectShow由大量的COM对象(被叫做fiters)组成,有许多标准filters可以使用,当然你可以开发自己的filters来扩展DirectShow。举个简单的例子,怎样使用filters来播放一AVI文件:
- 源文件filter(从AVI文件读数据)
- AVI分路fiter(分离Audio和Video)
- 解码fiter(根据使用的压缩类型解压缩Video帧)
- Video渲染器filter(绘制Video帧)
- DirectSound设备filter(发送audio到声卡)
可以看出:复杂的操作由一些小组件(filter)组成。
Pins
fiters直接连接也使用一种COM对象:Pins
上面播放AVI文件需要五个fiters协调完成(当然也需要Pins连接他们),必须全部成功,他们被称为"Filter Graph"。好像很复杂啊,但是DirectShow给我们提供了建立(Building)filter graph的组件:
- Filter Graph 组件(用于文件回放和控制filter graph)
- 捕捉Graph Builder(用于捕捉)
- DVD Graph Builder(用于DVD回放)
Filter Graph管理器是DirectShow的基本组件,多数DirectShow应用会使用。它做下面的事情:
- 提供我们方法:建立filter graph (增加,移除,连接fiters)
- 协调filters之间状态变化(播放,暂停,停止,定位)
- 处理filters之间同步(with a reference clock)
- 事件通知(能够知道状态变化和其他事件)
下面是Filter Graph管理器暴露的重要接口:
IBasicAudio (controls the volume and balance of audio stream)
IBasicVideo (sets video properties)
IGraphBuilder (help building filter graph)
IMediaControl (controls flow of data in filter graph)
IMediaEventEx (for event notifications and for overriding default event handling)
IMediaSeeking (for seeking a position in stream)
IVideoWindow (sets video window properties)
下面是Filter Graph管理器创建步骤:
- 对象创建
IGraphBuilder *pGB = NULL;
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void **)&pGB);
这样就创建了一个Filter Graph管理器,并取得IGraphBuilder 接口指针。下面需要考虑谁建立graph, 支持下面方式:
Filter Graph Manager builds the entire graph
Filter Graph Manager builds the partial graph
The application builds the entire graph
- IGraphBuilder::RenderFile方法可以用来对具体文件类自动建立filter graph. 这种方式下,Fiter Graph管理器会根据具体媒体文件链接合适的filters,这叫做智能链接。
实际上, DirectShow并不加载媒体文件,而是创建一个DirectShow滤波器到文件的连接。数据在解码的时候被流化,这样可以减少在播放过程中的内存使用,创建连接的过程叫做渲染(rendering)。渲染一个文件,需要调用IGraphBuilder::RenderFile函数。
// Have the graph builder construct the appropriate graph automatically
pGB->RenderFile(L"J:\\VIdeo\\ruby.avi", NULL);
- IMediaControl::Run方法用来在filter grah中开始数据流动。IMediaControl提供了filter grah中数据流动的run,pause和stop操作。
在媒体文件被渲染之后,就可以使用另外两个接口 IMediaControl和IMediaEvent进行播放或者对播放进行控制了。
第一个接口 IMediaControl用于播放和各种播放相关的操作,这个接口有三个函数:IMediaControl::Run,IMediaControl:: Pause,IMediaControl::Stop。
IMediaControl *pMC = NULL;
pGB->QueryInterface(IID_IMediaControl, (void **)&pMC);
pMC->Run();
- 我们主要感兴趣的IMediaEvent函数大概有三个:GetEvent,FreeEventParams,WaitForCompletion。在需要逐帧连续监视事件的时候,用GetEvent和FreeEventParams组合是很有用的,它能帮助我们获取事件并作恰当的处理。但当我们需要连续播放而不希望连续监视播放过程的时候,另外一个函数就会很有用,即WaitForCompletion函数。它可以一直播放,在播放完成的时候,会把控制权交给我们。
// Query for the media control and event objects
g_graph_builder->QueryInterface(IID_IMediaControl, (void**)&g_media_control);
g_graph_builder->QueryInterface(IID_IMediaEvent, (void**)&g_media_event);
Code
// get th status of the song, it if is done, exit program.
long event_code, param1, param2;
// retrieves the next notification event
if(SUCCEEDED(g_media_event->GetEvent(&event_code, ¶m1, ¶m2, 1)))
{
if(event_code == EC_COMPLETE)
{
// frees resources associated with the parameters of an events.
g_media_event->FreeEventParams(event_code, param1, param2);
break;
}
}
pMC->Release();
pGB->Release();
Code
CFileDialog fd(true,0,0,0,"Media Files (*.avi)|*.avi|All Files (*.*)|*.*||");
if(fd.DoModal() == IDCANCEL)
return;
Clean();
CString path = fd.GetPathName();
BSTR bstr = path.AllocSysString();
// Get the interface for DirectShow's GraphBuilder
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGB);
// Have the graph builder construct its the appropriate graph automatically
pGB->RenderFile(bstr , NULL);
pGB->QueryInterface(IID_IMediaControl, (void **)&pMC);
pMC->Run();
SysFreeString(bstr);
Code
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// get th status of the song, it if is done, exit program.
long event_code, param1, param2;
// retrieves the next notification event
if(SUCCEEDED(g_media_event->GetEvent(&event_code, ¶m1, ¶m2, 1)))
{
if(event_code == EC_COMPLETE)
{
// frees resources associated with the parameters of an events.
g_media_event->FreeEventParams(event_code, param1, param2);
break;
}
}
// frees resources associated with the parameters of an events.
g_media_event->FreeEventParams(event_code, param1, param2);
}
去学习