DirectShow应用:只用API调用实现网络播放
本文只用一个main.cpp文件就实现了简单的网络媒体播放。代码如下:
一. 预定义
#define NO_SHLWAPI_STRFCNS
#include <DShow.h>
#include <atlcomcli.h>
#pragma comment(lib,"strmiids.lib")
LPCTSTR lpAppName = TEXT("An Example of Playing Internet File\(http:\\\\www.entrigle.com\\movie\\Megamind.avi) By Simply Using WindowsAPI!");
LPCTSTR lpClassName= TEXT("MY Class");
LRESULT CALLBACKWndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam );
void play( HWND hwnd );
头文件dshow.h中包含DirectShow常用的内容,altcomcli.h包含智能指针等相关内容。接下来,引用需要的库,定义回调函数及播放函数原型。
二. 入口函数
int APIENTRY WinMain( HINSTANCE hinstance, HINSTANCEhPreviousInsance,
LPTSTR lpCmdLine, intnCmdShow )
{
// to setupthe properties of the window
MSG msg;
HWND hwnd;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc; // 为窗体指定回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon( hinstance,IDI_APPLICATION );
wc.hCursor = LoadCursor( hinstance,IDC_ARROW );
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = lpAppName;
wc.lpszClassName = lpClassName;
// toregister and create the window
if(!RegisterClass( &wc ) )
{
returnFALSE;
}
hwnd = CreateWindow( lpClassName,lpAppName, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,0,
CW_USEDEFAULT,0,
NULL,
NULL,
hinstance,
NULL
);
if(!hwnd )
{
returnFALSE;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// to playthe network file
play( hwnd );
// 进入消息循环
while(GetMessage(&msg, NULL, 0, 0 ))
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
returnmsg.wParam;
}
如上,定义Windows入口函数WinMain,首先定义窗体结构WNDCLASS变量,并通过调用RegisterClass进行注册,调用CreateWindow创建一个窗体,并激活之。然后,调用函数play播放一个网络文件。
函数play的实现代码如下:
void play( HWND hwnd )
{
// initializethe com library
HRESULT hr = CoInitializeEx( NULL,COINIT_APARTMENTTHREADED );
if(FAILED(hr) )
{
MessageBox( NULL, TEXT("Initialize error!"), NULL, 0 );
return;
}
// to get thepointer for Graph Builder
CComPtr<IGraphBuilder> pGraph;
hr = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph );
if(FAILED(hr) )
{
MessageBox( NULL, TEXT("Create Graph builder error!"), NULL, 0);
CoUninitialize();
return;
}
// to makeintelligent connection
hr = pGraph->RenderFile( L"http:\\\\\www.entrigle.com\\movie\\Megamind.avi",NULL );
if(FAILED(hr) )
{
MessageBox( NULL, TEXT("Renderer file error!"), NULL, 0 );
pGraph = NULL;
CoUninitialize();
return;
}
// to get thepointer for media controlling
CComPtr<IMediaControl> pControl;
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl );
if(FAILED(hr) )
{
MessageBox( NULL, TEXT("Create Control error!"), NULL, 0 );
pGraph = NULL;
CoUninitialize();
return;
}
// to get thepointer for media events
CComPtr<IMediaEventEx> pEvent;
hr = pGraph->QueryInterface(IID_IMediaEventEx, (void **)&pEvent );
if(FAILED(hr) )
{
MessageBox( NULL, TEXT("Create Event error!"), NULL, 0 );
pGraph = NULL;
pControl = NULL;
CoUninitialize();
return;
}
// to get thepointer for video window
CComPtr<IVideoWindow> pVideo;
hr = pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVideo );
if(FAILED(hr) )
{
MessageBox( NULL, TEXT("Create Video Window error!"), NULL, 0);
pGraph = NULL;
pControl = NULL;
CoUninitialize();
}
// to bind itto the window created before
pVideo->put_Owner( (OAHWND)hwnd );
RECT rect;
GetClientRect( hwnd, &rect );
pVideo->put_Left( 0 );
pVideo->put_Top( 0 );
pVideo->put_Width( rect.right -rect.left );
pVideo->put_Height( rect.bottom -rect.top );
// to playand wait
pControl->Run();
longcvCode;
pEvent->WaitForCompletion( INFINITE,&cvCode );
// to stopand release
pControl->Stop();
pVideo = NULL;
pEvent = NULL;
pControl = NULL;
pGraph = NULL;
CoUninitialize();
}
三. 回调函数
回调函数只进行简单的处理,当窗口关闭时发送应用程序终止消息,当按下任意键时可重复播放。代码如下:
LRESULT CALLBACKWndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
{
switch(message)
{
caseWM_DESTROY :
PostQuitMessage(0);
break;
caseWM_KEYDOWN :
play( hwnd );
break;
default:
return DefWindowProc( hwnd, message, wparam, lparam);
break;
}
return0L;
}
本文旨在探索只用调用API的方式运用directshow技术,使代码量尽可能的减少,这对于Windows Api的学习和运用无疑是一个有益的尝试。