Windows Mobile多媒體開發總結之Media Player Plugins

來源:互聯網
上載者:User
文章目錄
  • Windows Media Player Skins
  • Windows Media Player Plug-ins

Windows Mobile多媒體開發總結之Media Player Plugins

 

隨著3G網路的普及,像多媒體和流媒體這樣的技術需求會越來越大,比如視訊通話。但是國內在這方面的進階人才不多,給我們這些做技術的指明了一個方向。:)

在Windows Mobile下媒體播放器開發有兩種選擇,一種是擴充Windows Media Player(下文簡稱WMP),一種是完全自己開發播放器(使用DirectShow,或者使用開源庫,比如解碼MP3的libmad庫)。開發播放器是個大骨頭,要好好去啃啃,可惜現在沒這樣的項目需求。

這次要總結的僅僅是Windows Mobile 6.0/6.1(下文簡稱WM6.0/6.1)下的WMP擴充,WM6.0/6.1使用的是WMP10版本,見。

微軟還未上市的WM6.5使用的WMP也是10版本,見。可以看到菜單風格改了,其它基本沒有變化。不知道在WMP擴充開發方面有沒有變化。

言歸正傳,從網上下載WMP 10 SDK(只有案頭系統的SDK,沒有Mobile版本的,而且文檔只有英文的):
http://msdn.microsoft.com/en-us/windowsmedia/bb190309.aspx

先總結下WMP在案頭作業系統的擴充開發。Windows Media Player Mobile是其一個子集。

Windows Media Player Skins

微軟在Mobile上是完全支援皮膚的。如果你要想在Mobile上設計一個漂亮個性的Windows Media Player,需要注意設計好各部分(如按鈕可用和不可用時)的圖片以及skin definition file編寫。展示的即時HTC一款Windows Mobile機子上的Windows Media Player。關於更多內容請見SDK,SDK上有專門的篇幅講解的,標題為:Windows Media Player for Windows Mobile Skins。

Windows Media Player Plug-ins

在Mobile上僅僅支援User Interface Plug-ins(以下紅色標識的)。

★DSP Plug-ins

-> Provides an architecture that enables the user to install and activate plug-in programs that add digital signal processing (DSP) functionality. DSP plug-ins are Microsoft DirectX Media Objects (DMOs) that connect to the Player by using COM interfaces. A typical DSP plug-in might be an audio equalizer or a video tint control.(用於資料訊號處理,比如均衡器,如)

怎樣讓WMP知道你的存在?方法是調用IWMPMediaPluginRegistrar::WMPRegisterPlayerPlugin方法向WMP註冊。

怎樣與WMP進行資料通訊?WMP通過提供一個分配好的input buffer向外掛程式提供音頻和視頻資料,外掛程式向output buffer(也是有WMP分配好的)中返回資料。
WMP通過調用被外掛程式具體實現了的方法來管理自己與外掛程式之間的資料傳遞,流程如下:

1.Windows Media Player calls IMediaObject::ProcessInput, passing a pointer to an IMediaBuffer object to the DSP plug-in.

2.The DSP plug-in keeps a reference count on the input buffer object. The DSP plug-in returns an appropriate success or failure HRESULT.

3.Windows Media Player calls IMediaObject::ProcessOutput, passing a pointer to an array of DMO_OUTPUT_DATA_BUFFER structures (which contain output buffers) to the DSP plug-in.

4.The DSP plug-in processes the data in the input buffer and then copies the data to the appropriate output buffer. The DSP plug-in releases the reference count on the input buffer object when all the data in the buffer has been processed. The DSP plug-in then returns an appropriate success or failure HRESULT.

5.Windows Media Player renders the content in the output buffer.
This process repeats continuously while the plug-in is enabled and Windows Media Player has content to render.

DoProcessOutput(在這個函數中對感興趣的音頻資料進行處理) is called each time Windows Media Player successfully calls IMediaObject::ProcessOutput. It is the function that performs the digital signal processing tasks that produce the audible result that the DSP plug-in is intended to produce.
比如當前外掛程式沒有被啟用時,應該像這樣實現DoProcessOutPut方法:
// Test whether the plug-in is disabled by the user.
if (!m_bEnabled)
{
    // Just copy the data without changing it.
    memcpy(pbOutputData, m_pbInputData, *cbBytesProcessed);

    return S_OK;
}

相關介面和描述
IMediaObject    Manages data exchange with Windows Media Player and performs digital signal processing tasks. Detailed documentation is included with the DirectX SDK.
IWMPMediaPluginRegistrar    Manages plug-in registration.
IWMPPlugin    Manages the connection to Windows Media Player.
IWMPPluginEnable    Stores whether the plug-in is currently enabled by Windows Media Player.
IWMPServices    Retrieves information from the Player about the current stream time and stream state.

相關枚舉類型及描述
WMPPlugin_Caps    Used with IWMPPlugin::GetCaps to indicate whether the plug-in can convert between formats.
WMPServices_StreamState    Indicates the whether the stream is currently stopped, paused, or playing.
----------------------------------------------------------------------------------------------

★Custom Visualizations

-> Windows Media Player provides your code with snapshots of audio frequency and waveform data at timed intervals measured in fractions of a second. The graphical output from your visualization is a Microsoft Windows device context. This is a standard Windows drawing surface that you can draw upon every time an audio snapshot is provided. (用於根據音頻資訊輸出相應的視覺效果,如)

相關介面及描述
IWMPEffects    Interface An interface to custom visualizations.
IWMPEffects2    Interface An interface that extends IWMPEffects, allowing greater control over visualization behavior.

相關結構體和枚舉類型
PlayerState    Provides some basic states of Windows Media Player.
TimedLevel    Holds data returned from the spectrum filter.
----------------------------------------------------------------------------------------------

★User Interface Plug-ins

-> Provides a variety of control panels that allow the user to modify various aspects of the player such as the video and graphic equalizer settings. Skins are one way to provide additional functionality, but they require the developer to recreate the entire user interface (UI). As an alternative, Windows Media Player allows the creation of custom UI plug-ins that display in the full mode of the player. This functionality is provided through a programming interface that follows standard Microsoft Component Object Model (COM) guidelines. (它可以實現部分UI定製,彌補了皮膚必須全部定製UI的不足。外掛程式必須以COM伺服器的形式開發出來,所以你不光要實現IWMPPluginUI介面,還要實現作為COM伺服器所需要的介面,如DllGetClassObject, DllCanUnloadNow, DllRegisterServer等,使用ATL會更方便。)

  • Display Area Plug-ins
  • Settings Area Plug-ins
  • Metadata Area Plug-ins
  • Separate Window Plug-ins
  • Background Plug-ins(Windows Mobile下僅僅支援這種,還不清楚6.5以上版本是否會支援更多)

    相關介面及描述
    WMPNotifyPluginAddRemove    An independent function used to notify Windows Media Player that a plug-in has been installed or uninstalled.
    IWMPPluginUI下的方法: 
        Create    Called by Windows Media Player to instantiate the plug-in user interface. 
        Destroy    Called by Windows Media Player to shut down the plug-in user interface.
        DisplayPropertyPage    Called by Windows Media Player to request that the plug-in display its property page.
        GetProperty    Called by Windows Media Player to retrieve name/value property pairs from the plug-in. 
        SetCore    Called by Windows Media Player to provide plug-in access to the core Windows Media Player APIs. (這是個關鍵方法,你想要通過這個方法獲得一個WMP介面指標,然後你可以通過這個指標進一步獲得像IWMPControls、IWMPSettings這樣的介面指標,這些介面指標提供了控制WMP的方法。 )
        SetProperty    Called by Windows Media Player to set name/value property pairs for the plug-in. 
        TranslateAccelerator    Called as part of the Windows Media Player message loop to allow the plug-in to intercept and respond to keyboard events.

    註冊表鍵位置(每次WMP啟動的時候會遍曆這個位置,WMP通過這個位置繼續找到你的DLL檔案以便載入) 
    HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MediaPlayer/UIPlugins/{ClassId}
    ----------------------------------------------------------------------------------------------

    ★Rendering Plug-ins

    -> Microsoft Windows Media Player provides an architecture that enables you to develop plug-ins that decode (if necessary) and render custom data contained in a Windows Media format stream.

    相關介面及描述
    IWMPMediaPluginRegistrar    Manages plug-in registration.
    IWMPNodeRealEstate    Obtains a rendering area from Windows Media Player.
    IWMPNodeRealEstateHost    Requests state changes from Windows Media Player.
    IWMPNodeWindowed    Stores a handle to the parent window used for rendering.
    IWMPNodeWindowedHost        Sends Windows messages from the plug-in to Windows Media Player.
    IWMPNodeWindowless    Stores a device context handle used by Windows Media Player when rendering in windowless mode.
    IWMPNodeWindowlessHost    Provides methods to direct Windows Media Player to update the rendering area in windowless mode.
    IWMPPlugin    Manages the connection to Windows Media Player.
    IWMPPluginEnable    Stores whether the plug-in is currently enabled by the user.
    IWMPServices    Retrieves information from Windows Media Player about the current stream time and stream state.
    IWMPWindowMessageSink    Receives messages when in windowless mode.

    相關枚舉類型及描述
    WMPPlugin_Caps    Used with IWMPPlugin::GetCaps to indicate whether the plug-in can convert between formats.
    WMPServices_StreamState    Indicates the whether the stream is currently stopped, paused, or playing.

     

    作者: 王克偉
    出處: http://wangkewei.cnblogs.com/
    著作權聲明: 本文的著作權歸作者與部落格園共有。轉載時須註明本文的詳細連結,否則作者將保留追究其法律責任的權利。
  •  

     

    Windows Mobile多媒體開發總結之Media Player Plugins(續)

     

    在文章“Windows Mobile多媒體開發總結之Media Player Plugins ”中總結了在WM(Windows Mobile)中擴充WMP(Windows Media Player)的幾種方法。發布之後有很多朋友詢問具體做法,所以我乘機也總結下相關知識,剛好也補一下我這方面的差缺。

    需求:在WM開發中如果不是單獨開發自己的播放器或者使用第三方播放器,你就只能使用WMP,但是你可能需要在別的應用程式或者驅動中控制WMP,或者需要獲得WMP的播放狀態,那麼怎樣做呢?你可能會想到向WMP對應的按鍵發送訊息,或者類比鍵盤訊息。實際上這些都不是好的解決方案。解決方案就是使用User Interface Background Plug-ins,這在上一篇文章中提到過了。

    涉及到的知識:User Interface Background Plug-ins需要實現的介面和操作WMP的方法,COM同處理序伺服程式的編寫(在Windows下擴充微軟本身軟體,比如擴充IE,基本都以COM的形式),Today Plug-ins的編寫等。(當然你使用ATL會更方便,就不需要自己這樣一步步的實現COM了。這裡只是為了深入的瞭解下COM內部原理。)

    【第一步】在Windows Mobile中開發WMP相關標頭檔在AKU中的位置如(比如AKU 6.15):
     
    在你的項目中需要使用wmp.h和wmpplug.h標頭檔。

    【第二步】實現作為COM同處理序伺服程式需要的方法,這也是需要在DLL中匯出的方法:
    DllGetClassObject
    DllCanUnloadNow
    DllRegisterServer
    先簡單瞭解下COM伺服器在建立過程中的位置,為了偷懶,圖就直接引用VC知識庫的,組件DLL即是所要編寫的COM伺服器端,用戶端就是WMP:


    關於更多COM的原理知識和使用可以參考《COM本質論》、《深入解析ATL》(我對ATL/WTL還是知之甚少,這本書已經放我枕頭邊很久了,一直在學習Windows作業系統而耽誤了學習ATL)或VC知識庫等。

    對上面的圖再解釋一下,當用戶端調用CoCreateInstance方法(這是WMP去做的,我們不管)時,CoCreateInstance實際上完成了下列三步:
    CoGetClassObject(rclsid, dwClsContext, NULL, IID_IClassFactory, (void **)&pCF); //此方法調用我們要實現的DllGetClassObject方法,獲得工廠對象的指標
    pCF->CreateInstance(pUnkOuter, riid, ppvObject);//CMediaPlayerPluginClassFactory::CreateInstance方法此時被調用
    pCF->Release();

    看一下我們要實現的這3個方法代碼是怎樣的
    STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, VOID ** ppv)
    {
        HRESULT                             hr;
        CMediaPlayerPluginClassFactory *    pcf;

        *ppv = NULL;

        if ((pcf = new CMediaPlayerPluginClassFactory()) == NULL)
            return E_OUTOFMEMORY;

        if (FAILED(hr = pcf->QueryInterface(riid, ppv)))//把外掛程式工廠對象的指標傳遞給WMP
        {
            delete pcf;
            return hr;
        }

        return S_OK;
    }

    STDAPI DllCanUnloadNow()
    {
        if (g_pServer->CanUnload())
            return S_OK;
        else
            return S_FALSE;
    }

    STDAPI DllRegisterServer()//當你安裝外掛程式時系統調用這個方法,在這裡你把你的COM伺服器註冊到註冊表的CLSID鍵上。
    {
        TCHAR   szModulePath[MAX_PATH];

        // Get our module path.
        if (!GetModuleFileName(GetModuleHandle(s_szModuleName), szModulePath, MAX_PATH))
            return E_FAIL;

        szModulePath[MAX_PATH - 1] = _T('/0');

        // register this COM object. 
        //
        // IMPORTANT:
        // be sure to update this GUID with another if you create another plug-in.  Each plug-in must have a unique GUID.
        return DllRegisterServerImplementation(_T("{009B9B8A-5080-4d09-8F74-9BD96A3558D4}"), s_szRegDescription, szModulePath, _T("Free"));
    }

    來看看CMediaPlayerPluginClassFactory相關的實現,這個類實現IClassFactory介面,我們看下它最關鍵的一個方法是怎樣實現的:

    HRESULT CMediaPlayerPluginClassFactory::CreateInstance(IUnknown * pUnkOuter, REFIID riid, VOID ** ppvObject)
    {
        HRESULT                 hr;
        CMediaPlayerPlugin *    pPlugin; 

        *ppvObject = NULL; 

        if (pUnkOuter != NULL)
            return CLASS_E_NOAGGREGATION;

        // 建立外掛程式對象
        if ((pPlugin = new CMediaPlayerPlugin()) == NULL)
            return E_OUTOFMEMORY; 

        pPlugin->InternalAddRef();
        hr = pPlugin->FinalConstruct();//在此註冊和建立外掛程式視窗,實際上這個視窗是不可見的,僅僅是實現一個訊息迴圈,用於其它應用程式向它發送訊息。
        pPlugin->InternalRelease();

        if (FAILED(hr))
        {
            delete pPlugin;
            return hr;
        } 

        if (FAILED(hr = pPlugin->QueryInterface(riid, ppvObject)))//傳遞外掛程式對象的指標
        {
            delete pPlugin;
            return hr;
        }

        return S_OK;
    }

    另外還有像CServer類的實現,具體見附件的項目。

    【第三步】實現IWMPPluginUI等介面
    class CMediaPlayerPlugin:
        public IWMPPluginUI

    在上一篇文章中我列出了這個介面下的方法:

        STDMETHODIMP Create(HWND hwndParent, HWND * phwndWindow);
        STDMETHODIMP Destroy();
        STDMETHODIMP DisplayPropertyPage(HWND hwndParent);
        STDMETHODIMP GetProperty(LPCWSTR wszName, VARIANT * pvarProperty);
        STDMETHODIMP SetCore(IWMPCore * pCore);
        STDMETHODIMP SetProperty(LPCWSTR wszName, const VARIANT * pvarProperty);
        STDMETHODIMP TranslateAccelerator(MSG * pMsg);

    對於這些方法,實現你需要的,不感興趣的僅僅讓它為空白即可,比如:
    HRESULT CMediaPlayerPlugin::Create(HWND hwndParent, HWND * phwndWindow)
    {
        // As per the IWMPPluginUI documentation, this method will never be called
        // because we're a background plugin (our registry Capabilities flags include
        // PLUGIN_TYPE_BACKGROUND = 0x00000001).

        return E_NOTIMPL;
    }

    SetCore是個關鍵方法,因為我們需要通過它獲得操作WMP的介面指標,這裡我們把獲得的指標存放在m_pCore中:
    HRESULT CMediaPlayerPlugin::SetCore(IWMPCore * pCore)
    {
        // This method is called shortly after this instance is created, and allows
        // us to hook up to Windows Media Player. Save the interface pointer.
        //
        // When WMP is shutting down, it calls SetCore(NULL) so we have to handle that
        // as well.
        if (m_pCore != NULL)
        {
            m_pCore->Release();
        }

        m_pCore = pCore;

        if (m_pCore != NULL)
        {
            m_pCore->AddRef();
        }

        return S_OK;
    }

    然後我們可以像這樣進一步通過m_pCore獲得其它介面指標,類似這裡的get_contronls方法的還有get_settings等,更詳細的可以查看附件的項目。
    VOID CMediaPlayerPlugin::ControlPlayer(UINT uMsg)
    {
        IWMPControls *  pControls;

        // Get the 'IWMPControls' interface.
        if (SUCCEEDED(m_pCore->get_controls(&pControls)))
        {
            switch (uMsg)
            {
                // for the toggle message
                case WM_WMPTOGGLE:
                    WMPPlayState wmpps;

                    // get the current state
                    if (SUCCEEDED(m_pCore->get_playState(&wmpps)))
                    {
                      // if it playing a track, pause it
                      if (wmpps == wmppsPlaying)
                      {
                        pControls->pause();
                      }
                      // otherwise try to play the track
                      else
                      {
                        pControls->play();
                      }

                    }
                    break;

                case WM_WMPPREVIOUS:
                    pControls->previous();
                    break;

                case WM_WMPNEXT:
                    pControls->next();
                    break;

                default:
                    break;
            }

            pControls->Release();
        }
    }

    文章上個星期就寫的差不多了,一直拖到現在才發布,實在抱歉。下一篇文章我總結下Today Plugin的開發。隨便介紹下通過Today Plugin控制WMP。希望對你有所協助,我的QQ是3423 6777 6,如果你需要什麼協助,或者跟我討論的話。

    項目的環境是:
    Win32/Windows Mobile 6 Professional(CHS)/Visual Studio 2008(CHS) 
    /Files/wangkewei/WMPlayerPlugin.rar

    作者: 王克偉
    出處: http://wangkewei.cnblogs.com/
    著作權聲明: 本文的著作權歸作者與部落格園共有。轉載時須註明本文的詳細連結,否則作者將保留追究其法律責任的權利。
    相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.