0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于OpenHarmony 3.2 Beta1版本的媒体能力

OpenAtom OpenHarmony 来源:OpenAtom OpenHarmony 作者:OpenAtom OpenHarmony 2022-07-01 10:58 次阅读

一、背景

全民直播时代,人们每天刷着五花八门的短视频,每分每秒都有无数的视频文件被生成、播放。但你可曾想过这些电视剧、电影、视频广告、短视频等影音是以怎样的数据形式在我们的显示设备中播放出来的?本文将基于 OpenHarmony 3.2 Beta1 版本的媒体能力,为你详细解读一个视频文件(本文以 MP4 封装格式、H264 压缩格式的视频文件为例)是怎么在基于 OpenHarmony 标准系统的设备上播放出来的。同时也带你一窥“播放一个视频文件”这件对 OpenHarmony 3.2 Beta1 版本系统能力很轻松的事,是由多少服务层、功能接口、工具、插件、命令行及代码等共同协作完成的。

二、OpenHarmony 3.2媒体能力全景

OpenHarmony 技术架构如下图所示,完成视频文件播放功能的是多媒体子系统。

7b5704ea-f875-11ec-ba43-dac502259ad0.png

下图所示为多媒体子系统框架图

7b6c7064-f875-11ec-ba43-dac502259ad0.png

如图所示,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视频播放)总共分几步?

视频播放流程图如下:

7b9cdb1e-f875-11ec-ba43-dac502259ad0.png

如图所示,播放一个视频大致分为 4 步:

解协议->解封装->解压缩->送显

播放pipeline

根据视频播放的步骤,我们在 OpenHarmony 上每一个环节都能找到对应的插件来完成,同时参考 media_standard 代码仓的代码目录,相关的代码都可以找到对应的实现逻辑。

7bc0cef2-f875-11ec-ba43-dac502259ad0.png

1、对于一个本地视频文件(比如/data/h264-640x480.mp4),对应的 filesrc 插件来完成文件的解析,拿到MP4文件流;

OpenHarmony 处理本地视频文件 URI 的 SetSource 逻辑代码如下:

int32_t PlayerEngineGstImpl::SetSource(const std::string &url){ std::unique_lock lock(mutex_); CHECK_AND_RETURN_RET_LOG(!url.empty(), MSERR_INVALID_VAL, "input url is empty!"); CHECK_AND_RETURN_RET_LOG(url.length() <= MAX_URI_SIZE, MSERR_INVALID_VAL, "input url length is invalid!"); std::string realUriPath; int32_t ret = MSERR_OK; if (IsFileUrl(url)) { ret = GetRealPath(url, realUriPath); if (ret != MSERR_OK) { return ret; } url_ = "file://" + realUriPath; } else { url_ = url; } MEDIA_LOGD("set player source: %{public}s", url_.c_str()); return ret;} 

这样就会得到一个 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 的解码能力,支持的格式非常丰富。

7bf6923a-f875-11ec-ba43-dac502259ad0.png

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(param.usage) | HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA, wait_time }; int32_t release_fence = -1; OHOS::sptr surface_buffer = nullptr; OHOS::SurfaceError ret = allocator->surface->RequestBuffer(surface_buffer, release_fence, request_config); if (ret == OHOS::SURFACE_ERROR_NO_BUFFER) { GST_INFO("there is no more buffers"); } if (ret != OHOS::SURFACE_ERROR_OK || surface_buffer == nullptr) { return nullptr; } ret = surface_buffer->Map(); if (ret != OHOS::SURFACE_ERROR_OK) { GST_ERROR("surface_buffer Map failed"); return nullptr; } OHOS::sptr autoFence = new(std::nothrow) OHOS::SyncFence(release_fence); if (autoFence != nullptr) { autoFence->Wait(100); // 100ms } GstSurfaceMemory *memory = reinterpret_cast(g_slice_alloc0(sizeof(GstSurfaceMemory))); if (memory == nullptr) { GST_ERROR("alloc GstSurfaceMemory slice failed"); allocator->surface->CancelBuffer(surface_buffer); return nullptr; } gst_memory_init(GST_MEMORY_CAST(memory), (GstMemoryFlags)0, GST_ALLOCATOR_CAST(allocator), nullptr, surface_buffer->GetSize(), 0, 0, surface_buffer->GetSize()); memory->buf = surface_buffer; memory->fence = -1; memory->need_render = FALSE; GST_DEBUG("alloc surface buffer for width: %d, height: %d, format: %d, size: %u", param.width, param.height, param.format, surface_buffer->GetSize()); return memory;}

申请好的 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(memory); surface_mem->need_render = TRUE; gboolean needFlush = TRUE; if (is_preroll) { surface_sink->prerollBuffer = buffer; } else { if (surface_sink->prerollBuffer == buffer) { // if it's paused, then play, this buffer is render by preroll surface_sink->prerollBuffer = nullptr; needFlush = FALSE; } } if (needFlush) { OHOS::BufferFlushConfig flushConfig = { { 0, 0, surface_mem->buf->GetWidth(), surface_mem->buf->GetHeight() }, }; gst_surface_mem_sink_dump_buffer(surface_sink, buffer); OHOS::SurfaceError ret = priv->surface->FlushBuffer(surface_mem->buf, surface_mem->fence, flushConfig); if (ret != OHOS::SURFACE_ERROR_OK) { surface_mem->need_render = FALSE; GST_ERROR_OBJECT(surface_sink, "flush buffer to surface failed, %d", ret); } } } GST_OBJECT_UNLOCK(surface_sink); GST_DEBUG_OBJECT(surface_sink, "End gst_surface_mem_sink_do_app_render"); return GST_FLOW_OK;}

再加上 audio 的插件解码出音频数据,OpenHarmony 的 player 会完成音视频同步,至此一个视频文件就会播放显示在屏幕上。

OpenHarmony 为了实现更好的用户体验,同时也引入了一些解决性能问题的插件,比如 multiqueue 插件来实现 buffer 队列,也使用 decodebin 高级插件来完成解码 element 的选择。

通过梳理,我们最终可以得到一条播放的 pipeline:

7c148362-f875-11ec-ba43-dac502259ad0.png

而通过播放 OpenHarmony 自带的图库播放本地 H264 视频,抓取 log,搜索 OnElementSetupCb 关键字也可以得到播放的 pipeline,这也进一步验证了本文的分析。

7c2e4784-f875-11ec-ba43-dac502259ad0.png

另外,我们也可以使用 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

    文章

    1890

    浏览量

    71882
  • OpenHarmony
    +关注

    关注

    23

    文章

    3272

    浏览量

    15159

原文标题:基于OpenHarmony 3.2 Beta1版本的H264视频播放之路详解

文章出处:【微信号:gh_e4f28cfa3159,微信公众号:OpenAtom OpenHarmony】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    搭载KaihongOS的高动态人形机器人“夸父”通过OpenHarmony 3.2 Release版本兼容性测评

    OpenHarmony”)3.2 Release版本兼容性测评并获颁兼容性证书 。这体现了深圳开鸿数字产业发展有限公司(以下简称”深开鸿“)OpenHarmony生 态建设
    的头像 发表于 12-20 09:45 203次阅读
    搭载KaihongOS的高动态人形机器人“夸父”通过<b class='flag-5'>OpenHarmony</b> <b class='flag-5'>3.2</b> Release<b class='flag-5'>版本</b>兼容性测评

    搭载KaihongOS的高动态人形机器人“夸父”通过OpenHarmony3.2 Release版本兼容性测评

      近日,搭载KaihongOS的国内首款可跳跃、可适应多地形行走的开源鸿蒙人形机器人通过OpenAtom OpenHarmony(以下简称“OpenHarmony”)3.2 Release
    的头像 发表于 12-07 18:15 263次阅读

    Unity中国、Cocos为OpenHarmony游戏生态插上腾飞的翅膀

    需求,结合本土文化元素和市场特色,为创作提供全面支持。团结引擎已兼容适配了中国科技生态内的众多软硬件平台,并联合基金会共同研发适配,已经完成了OpenHarmony3.2Release和 4.0 beta
    发表于 10-23 16:15

    润开鸿DAYU200及DAYU210联袂通过OpenHarmony 3.2 Release版本兼容性测评

    线”的全新突破,也为基于OpenHarmony 3.2 Release 新能力开发商用富设备及相关行业应用奠定了基础。 未来,基于OpenHarmony
    发表于 09-22 11:11

    润开鸿DAYU200及DAYU210联袂通过OpenHarmony 3.2 Release版本兼容性测评

    3.2 Release版本兼容性测评,在引领技术共建、有力推动OpenHarmony版本先行示范的同时,为基于3.2 Release
    的头像 发表于 09-21 21:10 582次阅读
    润开鸿DAYU200及DAYU210联袂通过<b class='flag-5'>OpenHarmony</b> <b class='flag-5'>3.2</b> Release<b class='flag-5'>版本</b>兼容性测评

    润开鸿DAYU200及DAYU210联袂通过OpenHarmony 3.2 Release版本兼容性测评

    近日,润开鸿HH-SCDAYU200及HH-SCDAYU210两款开发平台同时通过OpenHarmony3.2Release版本兼容性测评,在引领技术共建、推动OpenHarmony版本
    的头像 发表于 09-09 08:02 1222次阅读
    润开鸿DAYU200及DAYU210联袂通过<b class='flag-5'>OpenHarmony</b> <b class='flag-5'>3.2</b> Release<b class='flag-5'>版本</b>兼容性测评

    抢先体验!OpenHarmony 4.0 Beta2新版本发布

    2023年8月3日,OpenAtom OpenHarmony(简称“OpenHarmony”)发布了Beta2版本,相较于历史版本我们持续完
    的头像 发表于 08-28 12:05 625次阅读

    OpenHarmony 4.0 Beta2新版本发布,邀您体验

    2023年8月3日,OpenAtom OpenHarmony(简称“OpenHarmony”)发布了Beta2版本,相较于历史版本我们持续完
    发表于 08-25 09:49

    OpenHarmony 4.0 Beta2新版本发布,邀您体验

    Beta2版本,相较于历史版本我们持续完善ArkUI、文件管理、媒体、窗口、安全等系统能力、提升体验。欢迎开发者了解并升级使用,积极反馈宝
    的头像 发表于 08-24 21:10 441次阅读

    搭载KaihongOS的工业平板、机器人、无人机等产品通过3.2版本兼容性测评,持续繁荣OpenHarmony生态

    兼容性证书 新行业拓展新场景 深开鸿作为3.2版本先行示范单位、OpenHarmony发行版厂商,充分发挥生态共建的带头作用,积极拓展新行业、新场景,开展新版本在工业平板、机器人、无人
    发表于 08-17 18:02

    OpenHarmony 4.0 Beta1发布,邀您体验

    版本如期而至。4.0 Beta1版本3.2 Release版本基础上,继续提升标准系统的ArkUI、应用框架、图形
    的头像 发表于 06-08 18:30 396次阅读

    OpenHarmony 4.0 Beta1发布,邀您体验

    初夏之际,OpenAtom OpenHarmony(简称“OpenHarmony”) 4.0 Beta1版本如期而至。4.0 Beta1
    发表于 06-08 14:14

    OpenHarmony 4.0版本发布 赶快来一瞧究竟

    了!   于是乎我更好奇了,就找了一下相关文档,终于发现了 4.0 带来的一些新的变化,这次还是更多的聚焦于标准系统上。 首先第一个更新就是 OpenHarmony 4.0 Beta1 版本,开始提供
    的头像 发表于 06-06 09:26 965次阅读
    <b class='flag-5'>OpenHarmony</b> 4.0<b class='flag-5'>版本</b>发布  赶快来一瞧究竟

    一加6T适配OpenHarmony 3.2

    OpenHarmony-3.2-Release 已发布,并且已经有好一段时间,本次释放一加 6/6T 相关刷机包,主要升级为 OpenHarmony-3.2-Release 正式版并初步支持部分外设功能(如音频播放和蓝牙),及更新内核。
    的头像 发表于 05-30 15:39 600次阅读
    一加6T适配<b class='flag-5'>OpenHarmony</b> <b class='flag-5'>3.2</b>

    基于RK3588的润开鸿DAYU210旗舰级标准系统开发平台合入OpenHarmony主干

    日发布。作为一个全新的系统版本OpenHarmony 3.2 Release 解锁了更丰富功能和特性,系统能力进一步提升,呼唤性能更强的旗舰级芯片作为硬件承载。针对此需求,润开鸿提前
    发表于 05-17 14:17