游戏开发论坛

 找回密码
 立即注册
搜索
查看: 15385|回复: 24

游戏中的dshow媒体播放-即学即会-详细注释

[复制链接]

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
发表于 2007-3-7 18:57:00 | 显示全部楼层 |阅读模式
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;
}

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2007-3-7 19:06:00 | 显示全部楼层

Re: 游戏中的dshow媒体播放-即学即会-详细注释

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);
                :ispatchMessage(&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);
}

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2007-3-7 19:09:00 | 显示全部楼层

Re:游戏中的dshow媒体播放-即学即会-详细注释

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);
                :ispatchMessage(&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-&gtause();

                        //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();
        };
}

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2007-3-7 19:12:00 | 显示全部楼层

Re:游戏中的dshow媒体播放-即学即会-详细注释

这样看的不方便,我们到这里下载:
http://www.esnips.com/web/RpgDIY-chinese

7

主题

25

帖子

25

积分

注册会员

Rank: 2

积分
25
发表于 2007-3-7 21:33:00 | 显示全部楼层

Re:游戏中的dshow媒体播放-即学即会-详细注释

楼主真是大好人啊........
正在学习第一节中,不过为什么
pVideoWindow->put_Visible(OATRUE);
pVideoWindow->put_FullScreenMode(OATRUE);
仍然没有全屏呢?

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2007-3-8 17:38:00 | 显示全部楼层

Re:游戏中的dshow媒体播放-即学即会-详细注释

要想轻松地理解透彻direct show。看看这个:
http://www.geekpage.jp/programming/directshow/graphedit.php

我大致翻译以下:
先安装dx9sdk
启动开始->所有程序->......->GraphEdit这个软件。用这个软件来播放声音!

选择菜单的「Graph > Insert Filters」(插入过滤器)


于是会出现“Which filters do you want to insert ?”的对话框。选择:
DirectShow Filters > File Source (Async) 。
然后选择一个音频文件。比如“Windows XP Startup.wav”


接下来,从filter选择对话框中选择:
Audio Renderers > Default DirectSound Device


Windows XP Startup 的方框边上,有 Output 接口、点击他,
鼠标拖动到Default DirectSound Device的Audio Input pin (renderered)接口上!

最后,点“>”按钮开始播放!

译注:以上过程中,是 IGraphBuilder 在工作。 这是directshow的核心!,其他的组件,只是辅助的而已拉!

=====================================================

这样手工操作很麻烦。我们可以让“IMediaControl”来帮助我们做这些事。
在GraphEdit中点File > Render Media File即可!

现在再看看代码,就可以更好的理解了吧!

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2007-3-8 17:43:00 | 显示全部楼层

Re: Re:游戏中的dshow媒体播放-即学即会-详细注释

fyxx: Re:游戏中的dshow媒体播放-即学即会-详细注释

楼主真是大好人啊........
正在学习第一节中,不过为什么
pVideoWindow->put_Visible(OATRUE);
pVideo...


把你的代码给我看看。。。

59

主题

1104

帖子

1199

积分

金牌会员

Rank: 6Rank: 6

积分
1199
发表于 2007-3-8 17:56:00 | 显示全部楼层

Re:游戏中的dshow媒体播放-即学即会-详细注释

Graphic Edit是好用,之前有阵子用过,用来调试自编filter很王道

7

主题

25

帖子

25

积分

注册会员

Rank: 2

积分
25
发表于 2007-3-8 22:33:00 | 显示全部楼层

Re: Re: Re:游戏中的dshow媒体播放-即学即会-详细注释

instemast: Re: Re:游戏中的dshow媒体播放-即学即会-详细注释



把你的代码给我看看。。。


这个是代码,谢谢你了

sf_200738223255.rar

53.78 KB, 下载次数:

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2007-3-10 23:36:00 | 显示全部楼层

Re:游戏中的dshow媒体播放-即学即会-详细注释

要在renderfile之后设置fullscreenmode,否则出错!
pGraphBuilder->RenderFile(FileName,NULL);
pVideoWindow->put_FullScreenMode(OATRUE);
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-6-21 08:34

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表