鸿蒙NEXT开发实战往期必看文章:
一分钟了解”纯血版!鸿蒙HarmonyOS Next应用开发!
“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)
HarmonyOS NEXT应用开发案例实践总结合(持续更新......)
HarmonyOS NEXT应用开发性能优化实践总结(持续更新......)
调用者可以调用本模块的Native API接口,完成视频编码,即将未压缩的视频数据压缩成视频码流。
当前支持的编码能力如下:
目前仅支持硬件编码,基于MimeType创建编码器时,支持配置为H264 (OH_AVCODEC_MIMETYPE_VIDEO_AVC) 和 H265 (OH_AVCODEC_MIMETYPE_VIDEO_HEVC)。
每一种编码的能力范围,可以通过能力查询获取。
视频编码支持以下能力:
设置LTR帧、参考帧具体可参考:时域可分层视频编码
- Buffer模式不支持10bit的图像数据。
- 由于硬件编码器资源有限,每个编码器在使用完毕后都必须调用OH_VideoEncoder_Destroy接口来销毁实例并释放资源。
- 一旦调用Flush,Reset,Stop接口,会触发系统回收OH_AVBuffer,调用者不应对之前回调函数获取到的OH_AVBuffer继续进行操作。
- Buffer模式和Surface模式使用方式一致的接口,所以只提供了Surface模式的示例。
- 在Buffer模式下,调用者通过输入回调函数OH_AVCodecOnNeedInputBuffer获取到OH_AVBuffer的指针对象后,必须通过调用OH_VideoEncoder_PushInputBuffer接口 来通知系统该对象已被使用完毕。这样系统才能够将该对象里面的数据进行编码。如果调用者在调用OH_AVBuffer_GetNativeBuffer接口时获取到OH_NativeBuffer指针对象,并且该对象的生命周期超过了当前的OH_AVBuffer指针对象,那么需要进行一次数据的拷贝操作。在这种情况下,调用者需要自行管理新生成的OH_NativeBuffer对象的生命周期,确保其正确使用和释放。
- 两者的数据来源不同。
- 两者的适用场景不同:
- surface输入是指用OHNativeWindow来传递输入数据,可以与其他模块对接,例如相机模块。
- buffer输入是指有一块预先分配好的内存区域,调用者需要将原始数据拷贝进这块内存区域中。更适用于从文件中读取视频数据等场景。
- 在接口调用的过程中,两种方式的接口调用方式基本一致,但存在以下差异点:
- Buffer模式下,调用者通过OH_VideoEncoder_PushInputBuffer接口输入数据;Surface模式下,调用者应在编码器就绪前调用OH_VideoEncoder_GetSurface接口,获取OHNativeWindow用于传递视频数据。
- Buffer模式下,调用者通过OH_AVBuffer中的attr传入结束flag,编码器读取到尾帧后,停止编码;Surface模式下,需要调用OH_VideoEncoder_NotifyEndOfStream接口通知编码器输入流结束。
两种模式的开发步骤详细说明请参考:Surface模式和Buffer模式。
如下为状态机调用关系图:
- 有两种方式可以使编码器进入Initialized状态:
- 初始创建编码器实例时,编码器处于Initialized状态。
- 任何状态下调用OH_VideoEncoder_Reset接口,编码器将会移回Initialized状态。
- Initialized状态下,调用OH_VideoEncoder_Configure接口配置编码器,配置成功后编码器进入Configured状态。
- Configured状态下调用OH_VideoEncoder_Prepare()进入Prepared状态。
- Prepared状态调用OH_VideoEncoder_Start接口使编码器进入Executing状态:
- 处于Executing状态时,调用OH_VideoEncoder_Stop接口可以使编码器返回到Prepared状态。
- 在极少数情况下,编码器可能会遇到错误并进入Error状态。编码器的错误传递,可以通过队列操作返回无效值或者抛出异常:
- Error状态下可以调用OH_VideoEncoder_Reset接口将编码器移到Initialized状态;或者调用OH_VideoEncoder_Destroy接口移动到最后的Released状态。
- Executing 状态具有三个子状态:Flushed、Running和End-of-Stream:
- 在调用了OH_VideoEncoder_Start接口之后,编码器立即进入Running子状态。
- 对于处于Executing状态的编码器,可以调用OH_VideoEncoder_Flush接口返回到Flushed子状态。
- 当待处理数据全部传递给编码器后,可以在input buffers队列中为最后一个入队的input buffer中添加AVCODEC_BUFFER_FLAGS_EOS标记,遇到这个标记时,编码器会转换为End-of-Stream子状态。在此状态下,编码器不再接受新的输入,但是仍然会继续生成输出,直到输出到达尾帧。
- 使用完编码器后,必须调用OH_VideoEncoder_Destroy接口销毁编码器实例。使编码器进入Released状态。
详细的API说明请参考API文档。 如下为视频编码调用关系图:
- 虚线表示可选。
- 实线表示必选。
在 CMake 脚本中链接动态库
说明:
上述’sample’字样仅为示例,此处由调用者根据实际工程目录自定义。
Surface模式
参考以下示例代码,调用者可以完成Surface模式下视频编码的全流程。此处以surface数据输入,编码成H.264格式为例。 本模块目前仅支持异步模式的数据轮转。
- 添加头文件。
- 全局变量。
- 创建编码器实例对象。
调用者可以通过名称或媒体类型创建编码器。示例中的变量说明如下:
- videoEnc:视频编码器实例的指针;
- capability:编解码器能力查询实例的指针;
- OH_AVCODEC_MIMETYPE_VIDEO_AVC:AVC格式视频编解码器。
创建方式示例如下:
- 调用OH_VideoEncoder_RegisterCallback()设置回调函数。
注册回调函数指针集合OH_AVCodecCallback,包括:
- OH_AVCodecOnError 编码器运行错误,返回的错误码详情请参见OH_AVCodecOnError;
- OH_AVCodecOnStreamChanged 码流信息变化,如格式变化等;
- OH_AVCodecOnNeedInputBuffer 输入回调无作用,调用者通过获取的surface输入数据;
- OH_AVCodecOnNewOutputBuffer 运行过程中产生了新的输出数据,即编码完成。
示例如下所示:
说明: 在回调函数中,对数据队列进行操作时,需要注意多线程同步的问题。
- (可选)调用OH_VideoEncoder_RegisterParameterCallback()在Configur接口之前注册随帧通路回调。
详情请参考时域可分层视频编码。
- 调用OH_VideoEncoder_Configure()配置编码器。
详细可配置选项的说明请参考视频专有键值对。
参数校验规则请参考OH_VideoEncoder_Configure()参考文档。
参数取值范围可以通过能力查询接口获取,具体示例请参考获取支持的编解码能力文档。
目前支持的所有格式都必须配置以下选项:视频帧宽度、视频帧高度、视频像素格式。示例中的变量如下:
- DEFAULT_WIDTH:320像素宽度;
- DEFAULT_HEIGHT:240像素高度;
- DEFAULT_PIXELFORMAT: 像素格式,因为示例使用YUV的文件保存的像素格式是NV12,所以设置为 AV_PIXEL_FORMAT_NV12。
注意: 配置非必须参数错误时,会返回AV_ERR_INVAILD_VAL错误码。但OH_VideoEncoder_Configure()不会失败,而是使用默认值继续执行。
- 获取Surface。
获取编码器Surface模式的OHNativeWindow输入,获取surface需要在准备编码器之前完成。
OHNativeWindow*变量类型的使用方法请参考图形子系统 OHNativeWindow
- 调用OH_VideoEncoder_Prepare()编码器就绪。
该接口将在编码器运行前进行一些数据的准备工作。
- 调用OH_VideoEncoder_Start()启动编码器。
- (可选)OH_VideoEncoder_SetParameter()在运行过程中动态配置编码器参数。 详细可配置选项的说明请参考视频专有键值对。
- 写入编码图像。 在之前的第7步中,开发者已经对OH_VideoEncoder_GetSurface接口返回的OHNativeWindow*类型变量进行配置。因为编码所需的数据,由配置的Surface进行持续地输入,所以开发者无需对OnNeedInputBuffer回调函数进行处理,也无需使用OH_VideoEncoder_PushInputBuffer接口输入数据。
- (可选)调用OH_VideoEncoder_PushInputParameter()通知编码器随帧参数配置输入完成。 在之前的第5步中,调用者已经注册随帧通路回调
以下示例中:
- index:回调函数OnNeedInputParameter传入的参数,与buffer唯一对应的标识。
- 调用OH_VideoEncoder_NotifyEndOfStream()通知编码器结束。
- 调用OH_VideoEncoder_FreeOutputBuffer()释放编码帧。
以下示例中:
- index:回调函数OnNewOutputBuffer传入的参数,与buffer唯一对应的标识。
- buffer: 回调函数OnNewOutputBuffer传入的参数,Surface模式调用者无法通过OH_AVBuffer_GetAddr接口获取图像虚拟地址。
- (可选)调用OH_VideoEncoder_Flush()刷新编码器。
调用OH_VideoEncoder_Flush接口后,编码器仍处于运行态,但会清除编码器中缓存的输入和输出数据及参数集如H264格式的PPS/SPS。
此时需要调用OH_VideoEncoder_Start接口重新开始编码。
- (可选)调用OH_VideoEncoder_Reset()重置编码器。
调用OH_VideoEncoder_Reset接口后,编码器将回到初始化的状态,需要调用OH_VideoEncoder_Configure接口和OH_VideoEncoder_Prepare接口重新配置。
- (可选)调用OH_VideoEncoder_Stop()停止编码器。
调用OH_VideoEncoder_Stop接口后,编码器保留了编码实例,释放输入输出buffer。调用者可以直接调用OH_VideoEncoder_Start接口继续编码,
输入的第一个buffer需要携带参数集,从IDR帧开始送入。
- 调用OH_VideoEncoder_Destroy()销毁编码器实例,释放资源。
说明:
不能在回调函数中调用; 执行该步骤之后,需要调用者将videoEnc指向NULL,防止野指针导致程序错误。
Buffer模式
参考以下示例代码,调用者可以完成Buffer模式下视频编码的全流程。此处以YUV文件输入,编码成H.264格式为例。 本模块目前仅支持异步模式的数据轮转。
- 添加头文件。
- 创建编码器实例对象。
与Surface模式相同,此处不再赘述。
- 调用OH_VideoEncoder_RegisterCallback()设置回调函数。
注册回调函数指针集合OH_AVCodecCallback,包括:
- OH_AVCodecOnError 编码器运行错误,返回的错误码详情请参见OH_AVCodecOnError;
- OH_AVCodecOnStreamChanged 码流信息变化,如格式变化等;
- OH_AVCodecOnNeedInputBuffer 运行过程中需要新的输入数据,即编码器已准备好,可以输入YUV/RGB数据;
- OH_AVCodecOnNewOutputBuffer 运行过程中产生了新的输出数据,即编码完成。
调用者可以通过处理该回调报告的信息,确保编码器正常运转。
说明:
在回调函数中,对数据队列进行操作时,需要注意多线程同步的问题。
- 调用OH_VideoEncoder_Configure()配置编码器。
与Surface模式相同,此处不再赘述。
- 调用OH_VideoEncoder_Prepare()编码器就绪。
该接口将在编码器运行前进行一些数据的准备工作。
- 调用OH_VideoEncoder_Start()启动编码器,进入运行态。
启动编码器后,回调函数将开始响应事件。所以,需要先配置输入文件、输出文件。
- (可选)在运行过程中动态配置编码器参数。
- 调用OH_VideoEncoder_PushInputBuffer()写入编码图像。
送入输入队列进行编码,以下示例中:
- buffer:回调函数OnNeedInputBuffer传入的参数,可以通过OH_AVBuffer_GetAddr接口得到共享内存地址的指针;
- index:回调函数OnNeedInputBuffer传入的参数,与buffer唯一对应的标识;
- flags:缓冲区标记的类别,请参考OH_AVCodecBufferFlags
- stride: 获取到的buffer数据的跨距。
对跨距进行偏移,以NV12图像为例,示例如下:
以NV12图像为例,width、height、wStride、hStride图像排布参考下图:
- OH_MD_KEY_VIDEO_PIC_WIDTH表示width;
- OH_MD_KEY_VIDEO_PIC_HEIGHT表示height;
- OH_MD_KEY_VIDEO_STRIDE表示wStride;
- OH_MD_KEY_VIDEO_SLICE_HEIGHT表示hStride。
添加头文件。
使用示例:
硬件编码在处理buffer数据时(推送数据前),需要调用者拷贝宽高对齐后的图像数据到输入回调的AVbuffer中。 一般需要获取数据的宽高、跨距、像素格式来保证编码输入数据被正确的处理。
具体实现请参考:Buffer模式的步骤3-调用OH_VideoEncoder_RegisterCallback接口设置回调函数来获取数据的宽高、跨距、像素格式。
- 通知编码器结束。
以下示例中:
- index:回调函数OnNeedInputBuffer传入的参数,与buffer唯一对应的标识。
- buffer:回调函数OnNeedInputBuffer传入的参数,可以通过OH_AVBuffer_GetAddr接口得到共享内存地址的指针;
与“8. 写入编码图像”一样,使用同一个接口OH_VideoEncoder_PushInputBuffer,通知编码器输入结束,需要将flag标识成AVCODEC_BUFFER_FLAGS_EOS。
- 调用OH_VideoEncoder_FreeOutputBuffer()释放编码帧。 与Surface模式相同,此处不再赘述。
后续流程(包括刷新编码器、重置编码器、停止编码器、销毁编码器)与Surface模式一致,请参考Surface模式的步骤15-18。
到此这篇鸿蒙软件后缀格式(鸿蒙系统软件的后缀)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/haskellbc/39923.html