项目记录:MPEG-DASH整理2
这一篇主要是介绍DASH封装 (如何生成DASH媒体内容)
以及 关于DASh实现的一些软件与程序库,重点会看 libdash
DASH媒体内容的生成
- DASH(Dynamic Adaptive Streaming over HTTP)即自适应流媒体传输,典型的系统框图如下:
- 在服务器端提前存好同一内容的不同码率、不同分辨率的多个分片以及相应的描述文件MPD,客户端在播放时即可以根据自身性能以及网络环境选择最适宜的版本。更多详细的内容可以参见MPEG组织出台的标准,标准号ISO/IEC 23009-1。
- 如何在服务器端生成对应的媒体内容和相应的MPD文件呢?
- 输入
- 编码
- 分片
- 生成MPD
内容生成器
-
MP4Box
-
FFMPEG
等等
DASH实现
服务器
- 将生成好的媒体内容和MPD文件放到服务器上;
- Nginx 搭建DASH服务器
客户端和程序库
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;
队列中.