directshow媒体播放-即学即会

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,&param1, &param2, 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

这样看的不方便,我们到这里下载:
[url=http://www.esnips.com/web/RpgDIY-chinese][color=#800080]http://www.esnips.com/web/RpgDIY-chinese[/color][/url]
要想轻松地理解透彻direct show。看看这个:
[url=http://www.geekpage.jp/programming/directshow/graphedit.php][color=#0000ff]http://www.geekpage.jp/programming/directshow/graphedit.php[/color][/url]

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

要在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)等就不用多说了吧

为易语言编程软件提供了视频聊天功能接口。 主要特性: 1、视频音频的编码解码功能主要移植了ffmpeg、x264和faac等国外开源项目。 2、视频、音频采集分别使用DirectShow、DirectSound。 3、视频、音频播放分别使用GDI、DirectSound。 4、视频编码解码使用H.264算法,低码流高画质。 5、音频编码解码使用AAC算法,低码流高音质。 6、支持枚举视频音频设备,可使用多个摄像头、多个声卡。 7、支持枚举视频设备的分辨率。 8、支持使用自定义分辨率编码视频。 9、支持视频自适应窗口尺寸。 10、支持设置视频帧率。 11、支持设置关键帧间隔。 12、支持可变码流和固定码流。 13、支持视频音频质量设置。 14、支持多种视频运动估计算法,例如钻石搜索、六边形搜索、非对称十字六边形网络搜索、全搜索等。 15、支持设置运动估计搜索范围。 16、支持视频编码线程数设置,多核CPU使用多线程编码更有优势。 17、支持播放缓冲时间设置。 18、支持指定任意窗口播放视频。 19、支持视频音频采集后编码前的回调,因此可在编码前对视频音频进行自定义的相关处理,例如加水印加特效等。 20、支持视频音频解码后播放前的回调,因此可在播放前对视频音频进行自定义的相关处理,例如加水印加特效等。 凌晨孤星 Oct 6 2013 操作系统支持: Windows
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值