鸿蒙媒体开发【基于AVCodec能力的视频编解码】音频和视频

基于AVCodec能力的视频编解码

介绍

本实例基于AVCodec能力,提供基于视频编解码的视频播放和录制的功能。

  • 视频播放的主要流程是将视频文件通过解封装->解码->送显/播放。
  • 视频录制的主要流程是相机采集->编码->封装成mp4文件。

播放支持的原子能力规格

媒体格式 封装格式 码流格式
视频 mp4 视频码流:H.264/H.265, 音频码流:AudioVivid
视频 mkv 视频码流:H.264/H.265, 音频码流:aac/mp3/opus
视频 mpeg-ts 视频码流:H.264, 音频码流:AudioVivid

录制支持的原子能力规格

封装格式 视频编解码类型
mp4 H.264/H.265
m4a AVC(H.264)

注意,本示例仅支持视频录制,未集成音频能力

效果预览

使用说明

  1. 弹出是否允许"AVCodecVideo"使用相机?点击"允许"
录制
  1. 点击"录制"
  2. 选取视频输出路径,默认为【我的手机】文件夹下
  3. 录制完成后点击"停止录制"
播放
  1. 推送视频文件至storage/media/100/local/files/Docs下或点击下方"开始录制",录制一个视频文件(无音频)
  2. 点击播放按钮,选择文件,开始播放

具体实现

录制
UI层
  1. 在UI层Index页面,用户点击"录制"后,会调起文件管理,用户选择一个输出地址。录制结束后,文件会存放于此。
  2. 选择好文件后,会用刚刚打开的fd,和用户预设的录制参数,掉起ArkTS的initNative,待初始化结束后,调用OH_NativeWindow_GetSurfaceId接口,得到NativeWindow的surfaceId,并把surfaceId回调回UI层。
  3. UI层拿到编码器给的surfaceId后,调起页面路由,携带该surfaceId,跳转到Recorder页面;
  4. 录制页面XComponent构建时,会调起.onLoad()方法,此方法首先会拿到XComponent的surfaceId,然后调起createDualChannelPreview(),此函数会建立一个相机生产,XComponent和编码器的surface消费的生产消费模型。
Native层
  1. 进入录制界面后,编码器启动,开始对UI层相机预览流进行编码。
  2. 编码器每编码成功一帧,sample_callback.cpp的输出回调OnNewOutputBuffer()就会调起一次,此时用户会拿到AVCodec框架给出的OH_AVBuffer;
  3. 在输出回调中,用户需手动把帧buffer、index存入输出队列中,并通知输出线程解锁;
  4. 在输出线程中,把上一步的帧信息储存为bufferInfo后,pop出队;
  5. 在输出线程中,使用上一步的bufferInfo,调用封装接口WriteSample后,这一帧被封装入MP4中;
  6. 最后调用FreeOutputBuffer接口后,这一帧buffer释放回AVCodec框架,实现buffer轮转。
播放
UI层
  1. 在UI层Index页面,用户点击播放按钮后,触发点击事件,调起selectFile()函数,该函数会调起文件管理的选择文件模块,拿到用户选取文件的路径;
  2. 用户选择文件成功后,调起play()函数,该函数会根据上一步获取到的路径,打开一个文件,并获取到该文件的大小,改变按钮状态为不可用,之后调起ArkTS层暴露给应用层的playNative()接口;
  3. 根据playNative字段,调起PlayerNative::Play()函数,此处会注册播放结束的回调。
  4. 播放结束时,Callback()中napi_call_function()接口调起,通知应用层,恢复按钮状态为可用。
ArkTS层
  1. 在PlayerNative.cpp的Init()中调用PluginManager()中的Export()方法,注册OnSurfaceCreatedCB()回调,当屏幕上出现新的XComponent时,将其转换并赋给单例类PluginManager中的pluginWindow_;
Native层
  1. 具体实现原理:

    • 解码器Start后,解码器每拿到一帧,OnNeedInputBuffer就会被调起一次,AVCodec框架会给用户一个OH_AVBuffer。
    • 在输入回调中,用户需手动把帧buffer、index存入输入队列中,并同时输入线程解锁。
    • 在输入线程中,把上一步的帧信息储存为bufferInfo后,pop出队。
    • 在输入线程中,使用上一步的bufferInfo,调用ReadSample接口解封装帧数据。
    • 在输入线程中,使用解封装后的bufferInfo,调用解码的PushInputData接口,此时这片buffer用完,返回框架,实现buffer轮转。
    • PushInputData后,这一帧开始解码,每解码完成一帧,输出回调会被调起一次,用户需手动把帧buffer、index存入输出队列中。
    • 在输出线程中,把上一步的帧信息储存为bufferInfo后,pop出队。
    • 在输出线程中,调用FreeOutputData接口后,就会送显并释放buffer。释放的buffer会返回框架,实现buffer轮转。
  2. 解码器config阶段,OH_VideoDecoder_SetSurface接口的入参OHNativeWindow*,即为PluginManager中的pluginWindow_。

  3. 解码器config阶段,SetCallback接口,sample_callback.cpp的输入输出回调需将回调上来的帧buffer和index存入一个用户自定义容器sample_info.h中,方便后续操作。

  4. Player.cpp的Start()起两个专门用于输入和输出的线程。

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!

下面是鸿蒙的完整学习路线 ,展示如下:

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

相关推荐
盐焗西兰花10 小时前
鸿蒙学习实战之路-Reader Kit修改翻页方式字体大小及行间距最佳实践
学习·华为·harmonyos
lbb 小魔仙14 小时前
【HarmonyOS实战】React Native 表单实战:在 OpenHarmony 上构建高性能表单
react native·华为·harmonyos
上海合宙LuatOS16 小时前
LuatOS核心库API——【audio 】
java·网络·单片机·嵌入式硬件·物联网·音视频·硬件工程
一只大侠的侠16 小时前
React Native开源鸿蒙跨平台训练营 Day16自定义 useForm 高性能验证
flutter·开源·harmonyos
早點睡39017 小时前
高级进阶 React Native 鸿蒙跨平台开发:@react-native-community-slider 滑块组件
react native·react.js·harmonyos
Android系统攻城狮18 小时前
Android16进阶之音频播放定位MediaPlayer.seekTo调用流程与实战(二百二十七)
音视频·mediaplayer·android16·音频进阶·音频性能实战
一只大侠的侠18 小时前
Flutter开源鸿蒙跨平台训练营 Day11从零开发商品详情页面
flutter·开源·harmonyos
一只大侠的侠18 小时前
React Native开源鸿蒙跨平台训练营 Day18自定义useForm表单管理实战实现
flutter·开源·harmonyos
一只大侠的侠18 小时前
React Native开源鸿蒙跨平台训练营 Day20自定义 useValidator 实现高性能表单验证
flutter·开源·harmonyos
晚霞的不甘19 小时前
Flutter for OpenHarmony 可视化教学:A* 寻路算法的交互式演示
人工智能·算法·flutter·架构·开源·音视频