您的位置:首页 > 其它

directshow媒体播放-即学即会

2014-10-06 21:18 357 查看
1。简单地播放文件

#include <dshow.h>

#pragma comment (lib,"Ole32.lib")

#pragma comment (lib,"Strmiids.lib")

#define FILENAME L"C:\\Documents and Settings\\vs6\\桌面\\temp\\FL5007822001-500-2.avi"

bool g_bExit=false; //this APP will be exited when g_bExit=TURE

#define ture (bool)-1

int main()

{

IGraphBuilder *pGraphBuilder; //这是directshow的核心

IMediaControl *pMediaControl; //帮我们连接filter(媒体文件,解码器等) //简单的说,它帮我们简单地打开和播放文件.

IVideoWindow *pVideoWindow; //用这个来控制directshow的视频窗口

//COM初始化

CoInitialize(NULL);

//建立FilterGraph

CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC,IID_IGraphBuilder,

(LPVOID*)&pGraphBuilder);

// 向directshow询问MediaControl接口:

pGraphBuilder->QueryInterface(IID_IMediaControl,(LPVOID*)&pMediaControl);

//建立 Graph:

pMediaControl->RenderFile(FILENAME);

//向directshow询问VideoWindow接口:

pGraphBuilder->QueryInterface(IID_IVideoWindow,(LPVOID*)&pVideoWindow);

// 全屏:

pVideoWindow->put_Visible(OATRUE);

pVideoWindow->put_FullScreenMode(OATRUE);

//开始播放:

pMediaControl->Run();

// 等待:

MessageBox(NULL,"Block Execution","Block",MB_OK);

//停止:

pMediaControl->Stop();

// release resource:

pVideoWindow->Release();

pMediaControl->Release();

pGraphBuilder->Release();

// COM 销毁:

CoUninitialize();

return 0;

}

instemast 发表于 2007-5-25 17:08
2。在自己的window中循环播放。

接收到“播放结束”消息的时候,重新播放文件即可实现循环。

请建立Win32 App!

#include <dshow.h>

#include <windows.h>

#pragma comment (lib,"Ole32.lib")

#pragma comment (lib,"Strmiids.lib")

#define ture (bool)-1

//你应该替换这个文件名:

#define FILENAME L"C:\\Documents and Settings\\vs6\\桌面\\temp\\FL5007822001-500-2.avi"

#define WM_GRAPH_NOTIFY (WM_APP + 1) //g_pMediaEventEx的消息

bool g_bExit=false; //当g_bExit=TURE 时,程序结束

HWND g_hwnd=0; //我们的播放器的主窗口

IMediaEventEx *g_pMediaEventEx; //可以从directshow接受事件消息

//当媒体播放结束后,它会通知我们

IMediaControl *g_pMediaControl; //帮我们连接过滤器(文件,解码器。。。) //简单地说,它帮我们简单的打开和播放文件

IMediaPosition *g_pMediaPosition; //用这个来取得/设置媒体播放的位置等。

void OnGraphNotify(); //当g_pMediaEventEx发消息通知我们时,我们就调用这个函数

LRESULT WINAPI WinProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam);

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR CmdLine,int nShowCmd)

{

IGraphBuilder *pGraphBuilder; //directshow的核心

IVideoWindow *pVideoWindow; //用这个来控制directshow的视频窗口

//COM初始化:

CoInitialize(NULL);

//建立FilterGraph:

CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC,IID_IGraphBuilder,

(LPVOID*)&pGraphBuilder);

//向directshow询问MediaControl接口:

pGraphBuilder->QueryInterface(IID_IMediaControl,(LPVOID*)&g_pMediaControl);

//向directshow询问MediaPosition接口:

pGraphBuilder->QueryInterface(IID_IMediaPosition,(LPVOID*)&g_pMediaPosition);

//向directshow询问MediaEventsEx接口:

pGraphBuilder->QueryInterface(IID_IMediaEventEx,(LPVOID*)&g_pMediaEventEx);

//这段代码是建立一个播放器主窗口并显示之:

WNDCLASSEX wc={sizeof(WNDCLASSEX),CS_CLASSDC,WinProc,0L,0L,

GetModuleHandle(0),0,0,0,0,"instemast",0};

RegisterClassEx(&wc);

//我们窗口的客户区坐标:

RECT rect={100,100,640+100-1,480+100-1};//width=right-left+1 , right=left+width-1

//按照窗口客户区的坐标来计算窗口的实际坐标:

::AdjustWindowRect(&rect,WS_OVERLAPPEDWINDOW,false);

//注意,现在,rect的值更新了!

g_hwnd=CreateWindow("instemast","dshow",WS_OVERLAPPEDWINDOW,rect.left,rect.top,

rect.right-rect.left,rect.bottom-rect.top,0,0,wc.hInstance,0);

::ShowWindow(g_hwnd,nShowCmd);

//结束建立播放器主窗口

//我们将使用g_hwnd来接受directshow的消息:

g_pMediaEventEx->SetNotifyWindow((OAHWND)g_hwnd,WM_GRAPH_NOTIFY, NULL);

//建立Graph:

g_pMediaControl->RenderFile(FILENAME);

//向 directshow 询问 VideoWindow 接口:

pGraphBuilder->QueryInterface(IID_IVideoWindow,(LPVOID*)&pVideoWindow);

pVideoWindow->put_Owner((OAHWND)g_hwnd); //视频窗口是我们g_phwnd的子窗口!

pVideoWindow->put_WindowStyle(WS_CHILD|WS_CLIPSIBLINGS);

pVideoWindow->SetWindowPosition(0,0,rect.right-rect.left+1,rect.bottom-rect.top+1);

pVideoWindow->put_Visible(OATRUE);

//start playing media:

g_pMediaControl->Run();

MSG msg;

do

{

GetMessage(&msg,0,0,0);

::TranslateMessage(&msg);

::DispatchMessage(&msg);

if(msg.message==WM_GRAPH_NOTIFY)OnGraphNotify();

}while(!g_bExit); //消息循环,直到 g_bExit=TURE 时结束

//释放资源:

g_pMediaEventEx->Release();

pVideoWindow->Release();

g_pMediaControl->Release();

pGraphBuilder->Release();

//COM 终止:

CoUninitialize();

return 0;

}

void OnGraphNotify()

{

long evCode;

LONG param1, param2;

while(SUCCEEDED(g_pMediaEventEx->GetEvent(&evCode,¶m1, ¶m2, 0)))

{

g_pMediaEventEx->FreeEventParams(evCode, param1, param2);

switch (evCode)

{

case EC_COMPLETE: //我们的媒体播放结束了

g_pMediaPosition->put_CurrentPosition(0); //重设播放位置为0,就是倒回的意思

g_pMediaControl->Run();//重新播放

//以上这样,就是循环播放!

break;

};

};

}

LRESULT WINAPI WinProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)

{

switch(msg)

{

case WM_DESTROY:

g_pMediaControl->Stop(); //停止播放

g_bExit=ture; //我们的g_hwnd被关闭了,所以我们想退出程序

break;

};

return DefWindowProc(hwnd,msg,wparam,lparam);

}

instemast 发表于 2007-5-25 17:08
3。进一步实现游戏中的一些需要(播放暂停,循环,Esc跳过动画播放等)

使用另一种方式循环播放:

用一个定时器,每1000ms检查一下当前播放位置,如果播放到结束,就重放一遍。

#include <dshow.h>

#include <windows.h>

#pragma comment (lib,"Ole32.lib")

#pragma comment (lib,"Strmiids.lib")

#define ture (bool)-1

//you should REPLACE the media file path

#define FILENAME L"C:\\Documents and Settings\\vs6\\桌面\\temp\\FL5007822001-500-2.avi"

#define WM_GRAPH_NOTIFY (WM_APP + 1) //the msg of g_pMediaEventEx

bool g_bExit=false; //this APP will be exited when g_bExit=TURE

HWND g_hwnd=0; //our player's main window

IMediaEventEx *g_pMediaEventEx; //recieve event msgs from directshow

//it notifies us when the media's playing is COMPLETE

IMediaControl *g_pMediaControl; //help us to link the filters(media file,codec...),

//in short,it helps us open and play a file EASILY.

IMediaPosition *g_pMediaPosition; //we use this to get/set the POSITION of a media's playing

double g_Len;

bool g_bIsPlaying=false;

LRESULT WINAPI WinProc(HWND,UINT,WPARAM,LPARAM);

void WINAPI OnTimer(HWND, UINT, UINT, DWORD);

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR CmdLine,int nShowCmd)

{

IGraphBuilder *pGraphBuilder; //this is the kernel of directshow

IVideoWindow *pVideoWindow; //use this to control the video window of directshow

//init COM

CoInitialize(NULL);

//create FilterGraph:

CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC,IID_IGraphBuilder,

(LPVOID*)&pGraphBuilder);

//ask directshow for the MediaControl:

pGraphBuilder->QueryInterface(IID_IMediaControl,(LPVOID*)&g_pMediaControl);

//ask directshow for the MediaPosition:

pGraphBuilder->QueryInterface(IID_IMediaPosition,(LPVOID*)&g_pMediaPosition);

//ask directshow for the MediaEventEx:

pGraphBuilder->QueryInterface(IID_IMediaEventEx,(LPVOID*)&g_pMediaEventEx);

//start to create a window and show it

WNDCLASSEX wc={sizeof(WNDCLASSEX),CS_CLASSDC,WinProc,0L,0L,

GetModuleHandle(0),0,0,0,0,"instemast",0};

RegisterClassEx(&wc);

//our window's CLIENT positions:

RECT rect={100,100,640+100-1,480+100-1};//width=right-left+1 , right=left+width-1

//calculate our window's REAL positions from client positions:

::AdjustWindowRect(&rect,WS_OVERLAPPEDWINDOW,false);

//NOW, rect's values are updated

g_hwnd=CreateWindow("instemast","Esc=stop Space=pause/play F1=speed+ F2=speed- F3=normal",WS_OVERLAPPEDWINDOW,rect.left,rect.top,

rect.right-rect.left,rect.bottom-rect.top,0,0,wc.hInstance,0);

::ShowWindow(g_hwnd,nShowCmd);

//end of creating window

//we will recieve directshow's msg by g_hwnd:

g_pMediaEventEx->SetNotifyWindow((OAHWND)g_hwnd,WM_GRAPH_NOTIFY, NULL);

//create Graph:

g_pMediaControl->RenderFile(FILENAME);

//get our media's length:

g_pMediaPosition->get_Duration(&g_Len);

//ask directshow for the VideoWindow interface:

pGraphBuilder->QueryInterface(IID_IVideoWindow,(LPVOID*)&pVideoWindow);

pVideoWindow->put_Owner((OAHWND)g_hwnd); //VIDEOwindow is the child of OUR g_hwnd

pVideoWindow->put_WindowStyle(WS_CHILD|WS_CLIPSIBLINGS);

pVideoWindow->SetWindowPosition(0,0,rect.right-rect.left+1,rect.bottom-rect.top+1);

pVideoWindow->put_Visible(OATRUE);

//start playing media:

g_pMediaControl->Run();

g_bIsPlaying=ture;

::SetTimer(g_hwnd,0,1000,&OnTimer);

MSG msg;

do

{

GetMessage(&msg,0,0,0);

::TranslateMessage(&msg);

::DispatchMessage(&msg);

}while(!g_bExit); //do msg loop,until g_bExit=TURE

//release the resource:

g_pMediaEventEx->Release();

pVideoWindow->Release();

g_pMediaControl->Release();

pGraphBuilder->Release();

//COM destroy:

CoUninitialize();

return 0;

}

LRESULT WINAPI WinProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)

{

double rate;

switch(msg)

{

case WM_KEYDOWN:

switch(wparam)

{

case 27: //[Esc] key--Stop media

g_pMediaControl->Stop(); //stop media

g_bIsPlaying=false;

//show FIRST frame:

g_pMediaPosition->put_CurrentPosition(0);

g_pMediaControl->Run();

::Sleep(2);

g_pMediaControl->Pause();

//stop media:

g_pMediaPosition->put_CurrentPosition(0);

g_pMediaControl->Stop();

break;

case ' ': //pause or resume or play

if(g_bIsPlaying)

{

g_pMediaControl->Pause();

g_bIsPlaying=false;

}

else

{

g_pMediaControl->Run();

g_bIsPlaying=ture;

};

break;

case VK_F1: //rate(speed): 1.0=normal

g_pMediaPosition->get_Rate(&rate);

g_pMediaPosition->put_Rate(rate*1.25);

break;

case VK_F2:

g_pMediaPosition->get_Rate(&rate);

g_pMediaPosition->put_Rate(rate*0.8);

break;

case VK_F3:

g_pMediaPosition->put_Rate(1.0);

};

break;

case WM_DESTROY:

g_pMediaControl->Stop(); //stop our media

g_bIsPlaying=false;

g_bExit=ture; //our g_hwnd has been closed,so we want to exit the app

break;

};

return DefWindowProc(hwnd,msg,wparam,lparam);

}

void WINAPI OnTimer(HWND hwnd, UINT, UINT, DWORD)

{

double pos;

g_pMediaPosition->get_CurrentPosition(&pos);

if(pos>=g_Len)

{

g_pMediaPosition->put_CurrentPosition(0);

g_pMediaControl->Run();

};

}

instemast 发表于 2007-5-25 17:11

这样看的不方便,我们到这里下载:

[color=#800080]http://www.esnips.com/web/RpgDIY-chinese[/color]

要想轻松地理解透彻direct show。看看这个:

[color=#0000ff]http://www.geekpage.jp/programming/directshow/graphedit.php[/color]

有个朋友的问题,也请大家注意:

要在renderfile之后设置fullscreenmode,否则出错!

pGraphBuilder->RenderFile(FileName,NULL);

pVideoWindow->put_FullScreenMode(OATRUE);

我们再来看一下怎么关闭当前文件,

最简单的做法是:

safe(m_pMediaControl)->Stop();

safe(m_pBasicAudio)->Release();

safe(m_pBasicVideo)->Release();

safe(m_pVideoWindow)->Release();

safe(m_pMediaEventEx)->Release();

safe(m_pMediaPosition)->Release();

safe(m_pMediaControl)->Release();

safe(m_pGraphBuilder)->Release();

即可。

入门之后,就很简单了。再补充两个类,十分简单,光看函数名也知道是干什么的,dsk中帮助文档里有。

IBasicAudio接口:

put_Volume/get_Volume设置音量,这个对游戏也很有用。

IBasicVideo接口:

get/put_VideoWidth/Height视频的原始宽高。

接下来两组方法和我们缩放拷贝位图时相似:

get/put_DestinationLeft/Top/Width/Height目标显示的位置,大小。

get/put_SourceLeft/Top/Width/Height从源视频中截取的区域。

还有其他的比特率(bitrate)等就不用多说了吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: