1. 程式人生 > >專案記錄:MPEG-DASH整理2

專案記錄:MPEG-DASH整理2

專案記錄:MPEG-DASH整理2

這一篇主要是介紹DASH封裝 (如何生成DASH媒體內容)

以及 關於DASh實現的一些軟體與程式庫,重點會看 libdash

DASH媒體內容的生成

  • DASH(Dynamic Adaptive Streaming over HTTP)即自適應流媒體傳輸,典型的系統框圖如下:

img

  • 在伺服器端提前存好同一內容的不同位元速率、不同解析度的多個分片以及相應的描述檔案MPD,客戶端在播放時即可以根據自身效能以及網路環境選擇最適宜的版本。更多詳細的內容可以參見MPEG組織出臺的標準,標準號ISO/IEC 23009-1。
  • 如何在伺服器端生成對應的媒體內容和相應的MPD檔案呢?
    1. 輸入
    2. 編碼
    3. 分片
    4. 生成MPD

內容生成器

  • MP4Box

  • FFMPEG

    等等


DASH實現

伺服器

客戶端和程式庫

  • 參考Wiki百科;

  • libdash

    libdash是bitmovin公司開源的一個DASH庫,完整實現了DASH協議,可以在Github上獲取其程式碼。

Libdash

  • 從Github下載了 2.2版本的進行研究.libdash作為一個庫提供給SamplePlayer呼叫.

SamplePlayer

SamplePlayer是一個 Dash客戶端.

主要三個類:

  • SDLRenderer : 使用SDL進行渲染顯示;
  • DASHReceiver :呼叫Libdash負責下載媒體檔案;
  • LibavDecoder : 呼叫FFMPEG作為解碼工具;

程式按 觀察者模式 進行設計.

具體細節:

[mian函式]

int main(int argc, char *argv[])
{
	
    SDLRenderer     *renderer = new SDLRenderer();	  // 建立一個SDLRender類物件
	DASHReceiver    *receiver = new DASHReceiver(30); // Init a DASHReceiver with a buffer size of 30 Segments

	//receiver->Init("http://127.0.0.1/cuc_ieschool_2s.mpd");
	receiver->Init("http://127.0.0.1/1.mpd");

	// 通過 DASHReceiver例項receiver的資料 建立 一個LibavDecoder的例項decoder
    LibavDecoder *decoder = new LibavDecoder(receiver);

	// 將SDLRenderer的例項renderer註冊為LibavDecoder的觀察者
    decoder->attachVideoObserver(renderer);
    decoder->setFrameRate(30);
	
	// !!!
    decoder->init();
    
    bool eos = false;

    while(!renderer->isQuitKeyPressed() && !eos)
	{
        eos = !decoder->decode(); // 解碼和通知渲染!!!

		renderer->processEvents(); // 處理SDL的按鍵事件
    }

    decoder->stop();
    return 0;
}

[ 自適應下載邏輯 ]

namespace sampleplayer
{
    namespace input
    {
        class DASHReceiver : public IDataReceiver
        {
            public:
                DASHReceiver            (uint32_t maxcapacity);
                virtual ~DASHReceiver   ();

                bool Init   (std::string mpdurl);

                virtual int IORead (uint8_t *buf, int buf_size);

            private:
                dash::IDASHManager  *manager; //manager解析url返回一個mpd給 this->mpd
                dash::mpd::IMPD     *mpd;
                MediaObjectBuffer   *buffer;

                int                 count;
                uint32_t            maxcapacity;
                AdaptationLogic     *logic;
                THREAD_HANDLE       bufferingThread;

                /* Thread that does the buffering of segments */
				static void* DoBuffering(void *receiver);
				
        };
    }
}

[ DASHReceiver 類中 ]

  • dash::IDASHManager *manager; 複雜解析給定mpd_url返回一個mpd給 dash::mpd::IMPD *mpd;

  • MediaObjectBuffer *buffer; 其實完成一個佇列的功能,複雜管理下載的資料

    namespace sampleplayer
    {
        namespace input
        {
            class MediaObjectBuffer
            {
                public:
                    MediaObjectBuffer             (uint32_t maxcapacity);
                    virtual ~MediaObjectBuffer    ();
    
                    void            Push    (MediaObject *media);
                    MediaObject*    Front   ();
                    void            Pop     ();
                    void            SetEOS  (bool value);
                    uint32_t        Length  ();
    
                private:
                    std::queue<MediaObject *>   mediaobjects;
                    bool                        eos;
                    uint32_t                    maxcapacity;
                    mutable CRITICAL_SECTION    monitorMutex;
                    mutable CONDITION_VARIABLE  full;
                    mutable CONDITION_VARIABLE  empty;
            };
        }
    }
    
  • AdaptationLogic *logic; 負責控制下載邏輯.下載的邏輯與控制可以在進行修改

  • static void* DoBuffering(void *receiver); 這是一個執行緒,主要就是負責下載,將下載的 MediaObject *media 放進MediaObjectBuffer *buffer; 佇列中.

參考文件

  1. 自適應流媒體傳輸(一)——DASH媒體內容的生成
  2. Nginx 搭建DASH伺服器
  3. LibDash程式碼解析