一、背景
全民直播时代,人们每天刷着五花八门的短视频,每分每秒都有无数的视频文件被生成、播放。但你可曾想过这些电视剧、电影、视频广告、短视频等影音是以怎样的数据形式在我们的显示设备中播放出来的?本文将基于 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/plugins filesrc location=/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
审核编辑 :李倩
全部0条评论
快来发表一下你的评论吧 !