现在位置:首页 >> 嵌入式操作系统 >> Windows CE
WinCE 下用DirectShow播放音频和视频
作者:phantom 时间:2009/8/20 文章来源:来自网络

        虽然网上关于wince下如何使用DirectShow播放多媒体文件的资料不多,但WinCE毕竟还属于windows,而桌面系统的DirectShow例子网上信手拈来,并且其中DirectShow的功能方法与之WinCE下差别不大,又本人实在没有信心比他们的轮子造得更为华丽,所以这篇文章就直接切入正题,不介绍DirectShow的结构功能,直接来看看怎么用吧.(其实还是自己懒惰的原因大一些,恩,不过这个和本文的主题没多大关系:-)).
      
        为了方便代码的移植,所以我将DirectShow的操作封装成CMedia类,只要直接调用该类,就可以相当简便地调用DirectShow来播放多媒体文件了
       
        好,闲话至此,我们以具体代码看看是如何:         //获取CMedia的实例
        CMedia *m_pMedia = CMedia::GetInstance();
       
        //设置播放的窗口
        m_pMedia->SetVideoWindow(hWnd);
       
        //打开媒体文件
        m_pMedia->Open(TEXT("A.AVI"));
       
        //播放
        m_pMedia->Play();
       
        ...
       
        //播放结束后,调用Close释放资源
        m_pMedia->Open();
        没错,就是六行代码,就这么简单,可以顺利播放媒体文件.在这里要说一下的是,因为我们播放的是视频,需要有一个窗口显示,所以需要调用SetVideoWindow()函数来设置播放窗口.这个播放视频的窗口,可以是普通的窗口,也可以是Picture控件.当然咯,如果是播放音频文件,那么则完全可以无视这个函数.
       
        还有一个最值得注意的地方,当调用Open()成功之后,一定要调用Close()来释放资源,然后才能打开另一个媒体文件.否则,不释放的资源可能会导致很多莫名其妙的后果哦.
               
        等等,代码似乎还不完美,比如说,我想在文件播放之后再接着播放另外一个文件,那么我如何知道什么时候文件已经播放完毕了呢?这时候我们就需要请出SetNotifyWindow().
       
        该函数的作用是设置一个接受消息的窗口,当DirectShow有事件变更时,就会发送指定的消息到指定的窗口,原型如下:
       
        SetNotifyWindow(HWND hWnd, UINT wMsg,long lInstanceData)
       
        hWnd:接收消息的窗口句柄.
       
        wMsg:指定的自定义消息
       
        lInstanceData:消息的参数.
       
       
        那么,现在以接收一个视频播放结束事件的代码片段为例子:         //自定义一个消息
        #define WM_GRAPHNOTIFY        (WM_USER + 13)
       
        //设置接收消息窗口和消息
        m_pMedia->SetVideoWindow(hWnd,WM_GRAPHNOTIFY,NULL);
       
        ...
       
        //这个是消息循环函数
        LRESULT CMainWnd::WndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
        ...{
            switch(wMsg)
            ...{
           
                ...
           
                case WM_GRAPHNOTIFY:
                ...{
                    LONG evCode,evParam1,evParam2;
                   
                    //获取此时的DirectShow事件
                    if(m_pMedia->GetEvent(&evCode,&evParam1,&evParam2) == TRUE)
                    ...{
                        if(evCode == EC_COMPLETE)
                        ...{
                            MessageBox(NULL,TEXT("播放完毕"),TEXT(""),MB_OK);
                        }
                    }
                    return 0;
                }
            }
           
            ...
           
        }
       
        好了,知道播放完毕,就这么简单.恩,还很复杂..?呵呵,我觉得已经很简单了.
       
        文章的最后,让我们再来看看CMedia的其它几个有用的函数吧:
       
        CheckVisibility()
        描述:判断文件的种类
        当返回值为TRUE时,为视频文件;反之为只是音频文件.
       
       
        SetVolume(LONG lVolume, LONG lBalance)
        描述:设置音量.
        lVolume:设置音量的大小,范围为–10,000 到 0.
        lBalance:设置左右音量的均衡,范围是–10,000 到 10,000,默认是0.
       
       
        SetDisplayMode(DISPLAYMODE mode)
        描述:设置播放模式.
        DISP_FIT:按比例拉伸至视屏窗口.
        DISP_STRETCH:不按比例拉伸至视屏窗口.
        DISP_NATIVE:如果视频原本尺寸小于屏幕,则以原视频文件大小播放.否则,将和DISP_FIT相同
        DISP_FULLSCREEN:全屏


/**//////////////////////////////////////////////////////////////////////       
//Media.h: interface for the CMedia class.
//
//Version:
//    1.2.0
//Date:
//    2007.05.08
/**///////////////////////////////////////////////////////////////////////
#ifndef MEDIA_H
#define    MEDIA_H


#include <mmsystem.h>
#include <streams.h>

//--------------------------------------------------------------------
//Macro define

//The volume value
#define MAX_VOLUME                    0
#define MIN_VOLUME                    -10000

//The balance value
#define MAX_BALANCE                    10000
#define MIN_BALANCE                    -10000

//--------------------------------------------------------------------
//Enum value

enum DISPLAYMODE
...{   
    //Fit to the play window size. How wide (height) the window is, how
    //is the move. Keep aspect ratio.
    DISP_FIT,

    //Stretch to the play window size. Don't keep the aspect ratio.
    DISP_STRETCH,

    //Full screen play.
    DISP_FULLSCREEN,

    //When the size of video is smaller than the play window, it displayes
    //as the video size. If it's bigger , it just like the DISP_FIT mode.
    DISP_NATIVE
};
//--------------------------------------------------------------------

//The media file property
typedef struct
...{
    //The volume range is –10,000 to 0.
    //Divide by 100 to get equivalent decibel value (for example –10,000 = –100 dB).
    LONG lVolume;

    //The value from –10,000 to 10,000 indicating the stereo balance
    //As with the Volume property, units correspond to .01 decibels (multiplied by –1 when plBalance is a positive value).
    //For example, a value of 1000 indicates –10 dB on the right channel and –90 dB on the left channel.
    LONG lBalance;

    //Width of the video 
    LONG lWidth;

    //Height of the video
    LONG lHeight;

    //Approximate bit rate
    LONG lBitRate;

}MEDIAPROPERTY,*PMEDIAPROPERTY;
//--------------------------------------------------------------------
class CMedia 
...{
public:
    BOOL GetEvent(LONG *plEvCode, LONG *plParam1, LONG *plParam2);
    BOOL SetNotifyWindow(HWND hWnd, UINT wMsg,long lInstanceData);
    BOOL SetVolume(LONG lVolume, LONG lBalance = 0);
    BOOL SetDisplayMode(DISPLAYMODE mode);
    BOOL GetMediaProperty(PMEDIAPROPERTY pOutProperty);
    static CMedia * GetInstance();
    void Close();
    BOOL CheckVisibility();
    void SetVideoWindow(HWND hWndVideo);
    BOOL Open(TCHAR * pszFileName);
    BOOL Stop();
    BOOL Pause();
    BOOL Play();
    virtual ~CMedia();

protected:


    CMedia();
   
    // Collection of interfaces
    IGraphBuilder *m_pGB;
    IMediaControl *m_pMC;
    IMediaEventEx *m_pME;
    IVideoWindow  *m_pVW;
    IBasicAudio   *m_pBA;
    IBasicVideo   *m_pBV;
    IMediaSeeking *m_pMS;

    TCHAR m_szFileName[MAX_PATH];
    HWND m_hWndVideo; //The window play video
    HWND m_hWndNotify; //The window notify
    BOOL m_bExitThrd;
    BOOL m_bThrdRunning;
    static CMedia * m_pInstance;
    DISPLAYMODE m_DispMode;

};

#endif //#ifndef MEDIA_H

 

 

/**///////////////////////////////////////////////////////////////////////
// Media.cpp: implementation of the CMedia class.
//
/**///////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Media.h"


//----------------------------------------------------------------------------------------------
//Macro define

//Default play mode
#define DEFAULT_DISPLAY_MODE        DISP_NATIVE

//----------------------------------------------------------------------
//Initialize
CMedia *CMedia::m_pInstance = NULL;
//------------------------------------------------------------------------


/**///////////////////////////////////////////////////////////////////////
// Construction/Destruction
/**///////////////////////////////////////////////////////////////////////

CMedia::CMedia():
m_pGB(NULL),
m_pMC(NULL),
m_pME(NULL),
m_pVW(NULL),
m_pBA(NULL),
m_pBV(NULL),
m_pMS(NULL),
m_hWndVideo(NULL),
m_bExitThrd(TRUE),
m_bThrdRunning(FALSE),
m_DispMode(DEFAULT_DISPLAY_MODE),
m_hWndNotify(NULL)
...{
    memset(m_szFileName,0,sizeof(m_szFileName));
}

CMedia::~CMedia()
...{
    if(m_pInstance != NULL)
    ...{
        delete m_pInstance;
        m_pInstance = NULL;
    }

}

 


//------------------------------------------------------------
//Description:
//    Play the media file
//    When you call the function,you should call Open() before.
//
//-------------------------------------------------------------
BOOL CMedia::Play()
...{   
    // Run the graph to play the media file

    if(m_pMC == NULL)
    ...{
        return FALSE;
    }

       


    m_pMC->Run();

    return TRUE;
}

 


//------------------------------------------------------------
//Description:
//    Pause.
//    When you call the function,you should call Open() before.
//
//-------------------------------------------------------------
BOOL CMedia::Pause()
...{

    if(m_pMC == NULL)
    ...{
        return FALSE;
    }
   
    m_pMC->Pause();

    return TRUE;
}

 


//------------------------------------------------------------
//Description:
//    Stop.
//    When you call the function,you should call Open() before.
//
//-------------------------------------------------------------
BOOL CMedia::Stop()
...{

    if(m_pMC == NULL || m_pMS == NULL)
    ...{
        return FALSE;
    }

   
    m_pMC->Stop();   
    m_pMS->SetPositions(0, AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);   
  
    return TRUE;
}

 


//--------------------------------------------------------------------------
//Description:
//    Open the media file. When succeed in calling the function ,
//you should call the Close() to release the resource
//
//-------------------------------------------------------------------------
BOOL CMedia::Open(TCHAR *pszFileName)
...{
    BOOL bResult = FALSE;
   

    if(_tcslen(pszFileName) >= MAX_PATH)
    ...{
        goto END;
    }
    else
    ...{
        _tcscpy(m_szFileName,pszFileName);

        //Check the file existing
        HANDLE hdFile = CreateFile(m_szFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,NULL,NULL);
        if(hdFile == INVALID_HANDLE_VALUE)
        ...{
            //The file doesn't exist
            goto END;
        }
        else
        ...{
            CloseHandle(hdFile);
        }
    }

   

 

    // Initialize COM
    if(CoInitializeEx(NULL, COINIT_MULTITHREADED) != S_OK)
    ...{
        goto END;
    }

    // Get the interface for DirectShow's GraphBuilder
    if(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGB) != S_OK)
    ...{
        goto END;
    }


    // Have the graph construct its the appropriate graph automatically
    if(m_pGB->RenderFile(m_szFileName, NULL) != NOERROR)
    ...{
        goto END;
    }
   

    // QueryInterface for DirectShow interfaces
    if(m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC) != NOERROR)
    ...{
        goto END;
    }
    if(m_pGB->QueryInterface(IID_IMediaEventEx, (void **)&m_pME) != NOERROR)
    ...{
        goto END;
    }
    if(m_pGB->QueryInterface(IID_IMediaSeeking, (void **)&m_pMS) != NOERROR)
    ...{
        goto END;
    }
   

    // Query for video interfaces, which may not be relevant for audio files
    if(m_pGB->QueryInterface(IID_IVideoWindow, (void **)&m_pVW) != NOERROR)
    ...{
        goto END;
    }
    if(m_pGB->QueryInterface(IID_IBasicVideo, (void **)&m_pBV) != NOERROR)
    ...{
        goto END;
    }
   

    // Query for audio interfaces, which may not be relevant for video-only files
    if(m_pGB->QueryInterface(IID_IBasicAudio, (void **)&m_pBA) != NOERROR)
    ...{
        goto END;
    }
   
    // Is this an audio-only file (no video component)?
    if (CheckVisibility() == TRUE)
    ...{
        if(m_pVW->put_Owner((OAHWND)m_hWndVideo) != NOERROR)
        ...{
            goto END;
        }

   
        if(m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN) != NOERROR)
        ...{
            goto END;
        }
    }
   


    //Set play mode
    SetDisplayMode(m_DispMode);
   
   
    bResult = TRUE;

END:   

    if(bResult == FALSE)
    ...{
        //Release the resource
        Close();
    }

    return bResult;
}

 


//------------------------------------------------------------
//Description:
//    This method sets an owning parent for the video window.
//
//Parameters:
//    hWnd : [in] Handle of new owner window.
//
//----------------------------------------------------------
void CMedia::SetVideoWindow(HWND hWndVideo)
...{
    m_hWndVideo = hWndVideo;
}

 

//------------------------------------------------------------
//Description:
//    Check the file visibility
//    When you call the function,you should call Open() before.
//
//Parameters:
//    TRUE: Video
//    FALSE: It's not the video
//
//------------------------------------------------------------
BOOL CMedia::CheckVisibility()
...{
   
   
    if (!m_pVW)
    ...{
        //No VideoWindow interface.  Assuming audio/MIDI file or unsupported video codec
        return FALSE;
    }
   
    if (!m_pBV)
    ...{
        //No BasicVideo interface.  Assuming audio/MIDI file or unsupported video codec.
        return FALSE;
    }
   
   
    // If this is an audio-only clip, get_Visible() won't work.
    //
    // Also, if this video is encoded with an unsupported codec,
    // we won't see any video, although the audio will work if it is
    // of a supported format.
    long lVisible;
    if(m_pVW->get_Visible(&lVisible) != NOERROR)
    ...{
        return FALSE;
    }
   
   
    return TRUE;
}

 


//------------------------------------------------------------
//Description:
//    Release the resource which opened in the Open()   
//
//------------------------------------------------------------
void CMedia::Close()
...{

    // Relinquish ownership (IMPORTANT!) after hiding
    if(m_pVW)
    ...{
        m_pVW->put_Visible(OAFALSE);
        m_pVW->put_Owner(NULL);
    }

    if(m_pMC != NULL)
    ...{
        m_pMC->Release();
        m_pMC = NULL;
    }

    if(m_pME != NULL)
    ...{
        m_pME->SetNotifyWindow(NULL,NULL,NULL);

        m_pME->Release();
        m_pME = NULL;
    }

    if(m_pMS != NULL)
    ...{
        m_pMS->Release();
        m_pMS = NULL;
    }

    if(m_pBV != NULL)
    ...{
        m_pBV->Release();
        m_pBV = NULL;
    }
   
    if(m_pBA != NULL)
    ...{
        m_pBA->Release();
        m_pBA = NULL;
    }
   
    if(m_pVW != NULL)
    ...{
        m_pVW->Release();
        m_pVW = NULL;
    }

    if(m_pGB != NULL)
    ...{
        m_pGB->Release();
        m_pGB = NULL;
    }

    // Finished with COM
    memset(m_szFileName,0,sizeof(m_szFileName));


    CoUninitialize();
}


//------------------------------------------------------------
//Description:
//    Get the instance of object
//
//------------------------------------------------------------
CMedia * CMedia::GetInstance()
...{
    if(m_pInstance == NULL)
    ...{
        m_pInstance = new CMedia();
    }

    return m_pInstance;
}

 


//------------------------------------------------------------
//Description:
//    Get the media file property.
//    When you call the function,you should call Open() before.
//
//------------------------------------------------------------
BOOL CMedia::GetMediaProperty(PMEDIAPROPERTY pOutProperty)
...{

    MEDIAPROPERTY prop = ...{0};

    if(m_pBA == NULL || m_pBV == NULL)
    ...{
        return FALSE;
    }


    //Get the audio property
    m_pBA->get_Volume(&prop.lVolume);
    m_pBA->get_Balance(&prop.lBalance);


    //Get the video property
    if(CheckVisibility() == TRUE)
    ...{
        m_pBV->get_BitRate(&prop.lBitRate);
        m_pBV->GetVideoSize(&prop.lWidth,&prop.lHeight);

    }

    *pOutProperty = prop;


    return TRUE;
}


//------------------------------------------------------------
//Description:
//    Set the display mode.
//    When you call the function,you should call Open() before.
//
//------------------------------------------------------------
BOOL CMedia::SetDisplayMode(DISPLAYMODE mode)
...{
    if(m_pVW == NULL)
    ...{
        return FALSE;
    }

    m_DispMode = mode;

    if(mode == DISP_FULLSCREEN)
    ...{
        m_pVW->put_FullScreenMode(OATRUE);
    }
    else
    ...{
        //Restore to the normal mode
        m_pVW->put_FullScreenMode(OAFALSE);
       
        RECT rcWnd = ...{0};
        GetClientRect(m_hWndVideo,&rcWnd);
        LONG lWndWidth = rcWnd.right - rcWnd.left;
        LONG lWndHeight = rcWnd.bottom - rcWnd.top;

        MEDIAPROPERTY prop = ...{0};
        GetMediaProperty(&prop);


        if(mode == DISP_FIT || mode == DISP_NATIVE)
        ...{
            LONG lDispLeft,lDispTop,lDispWidth,lDispHeight;

            if(mode == DISP_NATIVE && lWndWidth >= prop.lWidth && lWndHeight >= prop.lHeight)
            ...{
                lDispLeft = (lWndWidth - prop.lWidth) / 2;
                lDispTop = (lWndHeight - prop.lHeight) / 2;
                lDispWidth = prop.lWidth;
                lDispHeight = prop.lHeight;
            }
            else
            ...{
                if(prop.lWidth * lWndHeight > lWndWidth * prop.lHeight)
                ...{
                    lDispWidth = lWndWidth;               
                    lDispHeight = (LONG)((float)lDispWidth / (float)prop.lWidth * prop.lHeight);
                    lDispLeft = 0;
                    lDispTop = (lWndHeight - lDispHeight) / 2;       
                }
                else if(prop.lWidth * lWndHeight < lWndWidth * prop.lHeight)
                ...{
                    lDispHeight = lWndHeight;
                    lDispWidth = (LONG)((float)lDispHeight / (float)prop.lHeight * prop.lWidth);
                    lDispLeft = (lWndWidth - lDispWidth) / 2;
                    lDispTop = 0;
                }
                else
                ...{
                    lDispWidth = lWndWidth;               
                    lDispHeight = lWndHeight;
                    lDispLeft = 0;
                    lDispTop = 0;
                }
            }

           

 

            m_pVW->put_Left(lDispLeft);
            m_pVW->put_Top(lDispTop);
            m_pVW->put_Width(lDispWidth);
            m_pVW->put_Height(lDispHeight);
        }
        else if(mode == DISP_STRETCH)
        ...{

            m_pVW->put_Left(0);
            m_pVW->put_Top(0);
            m_pVW->put_Width(lWndWidth);
            m_pVW->put_Height(lWndHeight);
        }
   
    }

 

    return TRUE;
}


//------------------------------------------------------------
//Description:
//    Set the volume.
//    When you call the function,you should call Open() before.
//
//Parameters:
//    lVolume:[in] The volume (amplitude) of the audio signal.
//            Range is –10,000 to 0.
//    lBalance:[in]  The balance for the audio signal. Default value is 0.
//            The value from –10,000 to 10,000 indicating the stereo balance.
//
//------------------------------------------------------------
BOOL CMedia::SetVolume(LONG lVolume, LONG lBalance)
...{
    if(m_pBA == NULL)
    ...{
        return FALSE;
    }

    if(lVolume < MIN_VOLUME && lVolume > MAX_VOLUME && lBalance < MIN_BALANCE && lBalance > MAX_BALANCE)
    ...{
        return FALSE;
    }

    m_pBA->put_Volume(lVolume);
    m_pBA->put_Balance(lBalance);

    return TRUE;
}

 


//----------------------------------------------------------------------
//Description:
//    Registers a window that will handle messages when a specified event occurs.
//
//Parameters:
//    hWnd:[in] Handle of window to notify. Pass NULL to stop notification.
//    wMsg:[in] Window message to be passed as the notification.
//    lInstanceData:[in] Value (instance data) to be passed as the lParam parameter for the lMsg message.
//
//-----------------------------------------------------------------------------
BOOL CMedia::SetNotifyWindow(HWND hWnd, UINT wMsg,long lInstanceData)
...{
    if(m_pME == NULL)
    ...{
        return FALSE;
    }

    m_pME->SetNotifyWindow((OAHWND)hWnd,wMsg,lInstanceData);

    return TRUE;
}


//----------------------------------------------------------------------
//Description:
//    This method retrieves the notification event.
//
//-----------------------------------------------------------------------
BOOL CMedia::GetEvent(LONG *plEvCode, LONG *plParam1, LONG *plParam2)
...{
    if(m_pME == NULL)
    ...{
        return FALSE;
    }

    LONG evCode, evParam1, evParam2;   

    if(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0) == NOERROR)
    ...{
        *plEvCode = evCode;
        *plParam1 = evParam1;
        *plParam2 = evParam2;

        // Spin through the events
        m_pME->FreeEventParams(evCode, evParam1, evParam2);       
    }
    else
    ...{
        return FALSE;
    }
   

    return TRUE;
}

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/norains/archive/2007/05/14/1609118.aspx


上一篇:WinCE 5.0 virtual memory[返回列表]下一篇: WinCE 菜鸟问答