一、背景
全民直播時代,人們每天刷著五花八門的短視頻,每分每秒都有無數的視頻文件被生成、播放。但你可曾想過這些電視劇、電影、視頻廣告、短視頻等影音是以怎樣的數據形式在我們的顯示設備中播放出來的?本文將基于 OpenHarmony 3.2 Beta1 版本的媒體能力,為你詳細解讀一個視頻文件(本文以 MP4 封裝格式、H264 壓縮格式的視頻文件為例)是怎么在基于 OpenHarmony 標準系統的設備上播放出來的。同時也帶你一窺“播放一個視頻文件”這件對 OpenHarmony 3.2 Beta1 版本系統能力很輕松的事,是由多少服務層、功能接口、工具、插件、命令行及代碼等共同協作完成的。
二、OpenHarmony 3.2媒體能力全景
OpenHarmony 技術架構如下圖所示,完成視頻文件播放功能的是多媒體子系統。
下圖所示為多媒體子系統框架圖
如圖所示,OpenHarmony 多媒體子系統拉起了一個叫 mediaserver 的服務來處理媒體事務,并且封裝了接口層包括JS接口、native 接口提供給 APP 調用,mediaserver 的核心則是引入了 gstreamer(以下簡稱 gst)框架來完成媒體功能(注:gstreamer 是一套功能強大、兼容性好、結構清晰的開源媒體框架,這里不做贅述,后面有專文解析)。OpenHarmony 也在 gst 的基礎上開發了 player engine 來實現播放,同時也利用 gst 豐富的插件資源實現幾乎所有的媒體功能。截至目前,已移植進來的開源插件包括 file source、demuxer、video decoder、libav 插件等,當然也包括 OpenHarmony 自研的 video sink、memsink、codec hdi 插件等。
三、把大象裝冰箱(H264視頻播放)總共分幾步?
視頻播放流程圖如下:
如圖所示,播放一個視頻大致分為 4 步:
解協議->解封裝->解壓縮->送顯
播放pipeline
根據視頻播放的步驟,我們在 OpenHarmony 上每一個環節都能找到對應的插件來完成,同時參考 media_standard 代碼倉的代碼目錄,相關的代碼都可以找到對應的實現邏輯。
1、對于一個本地視頻文件(比如/data/h264-640x480.mp4),對應的 filesrc 插件來完成文件的解析,拿到MP4文件流;
OpenHarmony 處理本地視頻文件 URI 的 SetSource 邏輯代碼如下:
int32_t PlayerEngineGstImpl::SetSource(const std::string &url){ std::unique_lock
這樣就會得到一個 URI:file:///data/h264-640x480.mp4,gst 正是通過 URI 前綴來判斷是否是本地視頻文件,然后獲取文件內容。
2、拿到 MP4 文件流后,對應的 qtdemux 插件來解封裝,完成音視頻分流,輸出 H264 裸碼流和音頻流;
3、拿到 H264 碼流后,h264parse 插件開始切片,輸出 H264 幀數據;
4、處理 H264 幀數據,就由 avdec_h264 插件來完成,一般情況會輸出 NV12 的像素數據,當然這個解碼器是基于 ffmpeg 的軟解插件,相信不久各個芯片廠商的硬件加速解碼器都會加進來;
可以使用 gst-inspect 工具查看 avdec_h264 解碼插件,使用 ffmpeg 的解碼能力,支持的格式非常豐富。
5、至此解碼的工作已經完成,后面就要根據顯示的像素格式、size 來對解碼輸出數據進行后處理(轉換、縮放、裁剪等),會由 Converter、Scaler、Clip 插件來完成;
6、滿足顯示要求后就會使用 surfacesink 插件完成合成送顯。
送顯需要先申請顯示 surface buffer,申請邏輯代碼如下:
GstSurfaceMemory *gst_surface_allocator_alloc(GstSurfaceAllocator *allocator, GstSurfaceAllocParam param){ g_return_val_if_fail(allocator != nullptr && allocator->surface != nullptr, nullptr); static constexpr int32_t stride_alignment = 8; int32_t wait_time = param.dont_wait ? 0 : INT_MAX; // wait forever or no wait. OHOS::BufferRequestConfig request_config = { param.width, param.height, stride_alignment, param.format, static_cast
申請好的 buffer 會放入 buffer pool,形成一個 buffer 隊列。
解碼器解完一幀會將數據放入 buffer pool,sink 插件會從 buffer pool 中拿到數據送顯,代碼邏輯如下:
static GstFlowReturn gst_surface_mem_sink_do_app_render(GstMemSink *memsink, GstBuffer *buffer, bool is_preroll){ g_return_val_if_fail(memsink != nullptr && buffer != nullptr, GST_FLOW_ERROR); GstSurfaceMemSink *surface_sink = GST_SURFACE_MEM_SINK_CAST(memsink); g_return_val_if_fail(surface_sink != nullptr, GST_FLOW_ERROR); GstSurfaceMemSinkPrivate *priv = surface_sink->priv; GST_OBJECT_LOCK(surface_sink); if (gst_surface_mem_sink_drop_frame_check(surface_sink) == FALSE) { GST_OBJECT_UNLOCK(surface_sink); GST_DEBUG_OBJECT(surface_sink, "user set rate, drop same frame"); return GST_FLOW_OK; } if (surface_sink->firstRenderFrame) { GST_WARNING_OBJECT(surface_sink, "KPI-TRACE: first render frame"); surface_sink->firstRenderFrame = FALSE; } for (guint i = 0; i < gst_buffer_n_memory(buffer); i++) { GstMemory *memory = gst_buffer_peek_memory(buffer, i); if (!gst_is_surface_memory(memory)) { GST_WARNING_OBJECT(surface_sink, "not surface buffer !, 0x%06" PRIXPTR, FAKE_POINTER(memory)); continue; } GstSurfaceMemory *surface_mem = reinterpret_cast
再加上 audio 的插件解碼出音頻數據,OpenHarmony 的 player 會完成音視頻同步,至此一個視頻文件就會播放顯示在屏幕上。
OpenHarmony 為了實現更好的用戶體驗,同時也引入了一些解決性能問題的插件,比如 multiqueue 插件來實現 buffer 隊列,也使用 decodebin 高級插件來完成解碼 element 的選擇。
通過梳理,我們最終可以得到一條播放的 pipeline:
而通過播放 OpenHarmony 自帶的圖庫播放本地 H264 視頻,抓取 log,搜索 OnElementSetupCb 關鍵字也可以得到播放的 pipeline,這也進一步驗證了本文的分析。
另外,我們也可以使用 gst-launch 手動創建 pipeline 來驗證:
gst-launch--gst-plugin-path=/system/lib/media/pluginsfilesrclocation=/data/media/h264.mp4!qtdemux!h264parse!avdec_h264!videoconvert!videoscale!video/x-raw,width=640,height=480!surfacememsink
附錄:
OpenHarmony標準系統media組件介紹
https://gitee.com/openharmony/multimedia_media_standardhttps://gitee.com/openharmony/multimedia_media_standard
MP4封裝格式介紹
https://wenku.baidu.com/view/b4f52a376ddb6f1aff00bed5b9f3f90f76c64dbd.htmlhttps://wenku.baidu.com/view/b4f52a376ddb6f1aff00bed5b9f3f90f76c64dbd.html
gst介紹
https://gstreamer.freedesktop.org/documentation/tutorials/index.html?gi-language=chttps://gstreamer.freedesktop.org/documentation/tutorials/index.html?gi-language=c
https://blog.csdn.net/qq_45662588/article/details/120763198https://blog.csdn.net/qq_45662588/article/details/120763198
OpenHarmony 3.2 Beta1 版本路書
https://gitee.com/openharmony/docs/blob/master/zh-cn/release-notes/OpenHarmony-v3.2-beta1.md
OpenHarmony媒體子系統框架介紹
https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E5%AA%92%E4%BD%93%E5%AD%90%E7%B3%BB%E7%BB%9F.mdhttps://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E5%AA%92%E4%BD%93%E5%AD%90%E7%B3%BB%E7%BB%9F.md
OpenHarmony視頻播放應用開發指導
https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/media/video-playback.md
審核編輯 :李倩
-
視頻
+關注
關注
6文章
1937瀏覽量
72821 -
OpenHarmony
+關注
關注
25文章
3665瀏覽量
16161
原文標題:基于OpenHarmony 3.2 Beta1版本的H264視頻播放之路詳解
文章出處:【微信號:gh_e4f28cfa3159,微信公眾號:OpenAtom OpenHarmony】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論