赞
踩
可分层视频编码,又叫可分级视频编码、可伸缩视频编码,是视频编码的扩展标准,目前常用的包含SVC(H.264编码标准采用的可伸缩扩展)和SHVC(H.265编码标准采用的可扩展标准)。
其特点是能一次编码出时域分层、空域分层、质量域分层的码流结构,满足因网络、终端能力和用户需求不同带来的的差异化需求。
时域可分层视频编码, 是指能编码出时域分层码流的视频编码,下图是通过参考关系构建的4层时域分层码流结构。
从高到低逐层丢弃部分层级的码流(丢弃顺序L3->L2->L1),能实现不同程度的帧率伸缩,以满足传输和解码能力的变化需求。
如下图所示,是上述4层时域分层码流结构丢弃L3后组成的新的码流结构,能在解码正常的情况下实现帧率减半的效果。其他层的丢弃同理。
基础码流是由一个或多个独立图像组(Group Of Pictures,简称GOP)组合而成的。GOP是在编码中一组从I帧开始到I帧结束的连续的可独立解码的图像组。
时域分层码流可以在GOP内继续细分为独立的一个或多个时域图像组(Temporal Group Of Pictures, 简称TGOP),每一个TGOP由一个基本层和后续的一个或多个增强层组合而成,如上述4层时域分层码流结构中的帧0到帧7是一个TGOP。
时域分层码流结构的实现是依靠参考关系逐帧指定实现的,参考帧按在解码图像缓存区(Decoded Picture Buffer,简称DPB)驻留的时长分为短期参考帧和长期参考帧。
虽然STR个数大于1时,也能实现一定的跨帧参考结构,但受限于存在时效过短,时域分层结构支持的跨度有限。LTR则不存在上述问题,也能覆盖短期参考帧跨帧场景。优选使用LTR实现时域分层码流结构。
基于上述描述的时域分层编码特点,推荐以下场景使用:
若开发场景不涉及动态调整时域参考结构,且分层结构简单,则推荐使用[全局时域可分层特性],否则使能[长期参考帧特性]。
不可以混用全局时域可分层特性和长期参考帧特性。
由于底层实现归一,全局时域可分层特性和长期参考帧特性不能同时开启。
叠加强制IDR配置时,请使用随帧通路配置。
参考帧仅在GOP内有效,刷新I帧后,DPB随之清空,参考帧也会被清空,因此参考关系的指定受I帧刷新位置影响很大。
使能时域分层能力后,若需要通过OH_MD_KEY_REQUEST_I_FRAME临时请求I帧,应使用生效时机确定的随帧通路配置方式准确告知框架I帧刷新位置以避免参考关系错乱,参考随帧通路配置相关指导,避免使用生效时机不确定的OH_VideoEncoder_SetParameter方式。
支持OH_AVBuffer回调通路,不支持OH_AVMemory回调通路。
新特性依赖随帧特性,应避免使用OH_AVMemory回调OH_AVCodecAsyncCallback,应使用OH_AVBuffer回调OH_AVCodecCallback。
支持时域P分层,不支持时域B分层。
时域可分层编码按分层帧类型分为基于P帧的时域分层和基于B帧的时域编码,当前支持分层P编码,不支持分层B编码。
全局时域可层特性,适用于编码稳定和简单的时域分层结构,初始配置,全局生效,不支持动态修改。开发配置参数如下:
配置参数 | 语义 |
---|---|
OH_MD_KEY_VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY | 全局时域分层编码使能参数 |
OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_SIZE | 全局时域分层编码TGOP大小参数 |
OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE | 全局时域分层编码TGOP参考模式 |
使用举例1:TGOP=4,相邻参考模式
使用举例2:TGOP=4,跨帧参考模式
基础编码流程请参考[视频编码开发指导],下面仅针与基础视频编码过程中存在的区别做具体说明。
// 1.1 获取对应视频编码器能力句柄,此处以H.264为例
OH_AVCapability *cap = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
// 1.2 通过特性能力查询接口校验是否支持全局时域可分层特性
bool isSupported = OH_AVCapability_isFeatureSupported(cap, VIDEO_ENCODER_TEMPORAL_SCALABILITY);
若支持,则可以使能全局时域可分层特性。
constexpr int32_t TGOP_SIZE = 3;
// 2.1 创建配置用临时AVFormat
OH_AVFormat *format = OH_AVFormat_Create();
// 2.2 填充使能参数键值对
OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY, 1);
// 2.3 (可选)填充TGOP大小和TGOP内参考模式键值对
OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_SIZE, TGOP_SIZE);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, ADJACENT_REFERENCE);
// 2.4 参数配置
int32_t ret = OH_VideoEncoder_Configure(videoEnc, format);
if (ret != AV_ERR_OK) {
// 异常处理
}
// 2.5 配置完成后销毁临时AVFormat
OH_AVFormat_Destroy(format);
(可选)在运行阶段输出轮转中,获取码流对应时域层级信息。
开发者可基于已配置的TGOP参数,按编码出帧数目周期性获取。
通过配置周期获取示例代码如下:
uint32_t outPoc = 0; // 通过输出回调中有效帧数,获取TGOP内相对位置,对照配置确认层级 static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { // 注:若涉及复杂处理流程,建议相关 struct OH_AVCodecBufferAttr attr; (void)buffer->GetBufferAttr(attr); // 刷新I帧后poc归零 if (attr.flags & AVCODEC_BUFFER_FLAG_KEY_FRAME) { outPoc = 0; } // 没有帧码流只有XPS的输出需要跳过 if (attr.flags != AVCODEC_BUFFER_FLAG_CODEC_DATA) { int32_t tGopInner = outPoc % TGOP_SIZE; if (tGopInner == 0) { // 时域关键帧,后续传输、解码流程不可丢弃 } else { // 时域非关键帧,后续传输、解码流程可以丢弃 } outPoc++; } }
(可选)在运行阶段输出轮转中,使用步骤3获取的时域层级信息,自适应传输或自适应解码。
基于获取的时域可分层码流和对应的层级信息,开发者可选择需要的层级进行传输,或携带至对端自适应选帧解码。
长期参考帧特性提供帧级灵活的参考关系配置。适用于灵活和复杂的时域分层结构。
配置参数 | 语义 |
---|---|
OH_MD_KEY_VIDEO_ENCODER_LTR_FRAME_COUNT | 长期参考帧个数参数 |
OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_MARK_LTR | 当前帧标记为LTR帧 |
OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_USE_LTR | 当前帧参考的LTR帧号 |
使用举例,实现[时域可分层视频编码介绍]中的4层时域分层结构的配置如下:
在配置阶段,将OH_MD_KEY_VIDEO_ENCODER_LTR_FRAME_COUNT 配置为5。
在运行阶段输入轮转中,按如下表所示随帧配置LTR相关参数,下表中\表示不做配置。
配置\POC | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MARK_LTR | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 |
USE_LTR | \ | \ | 0 | \ | 0 | \ | 4 | \ | 0 | \ | 8 | \ | 8 | \ | 12 | 0 | 8 |
基础编码流程请参考[视频编码开发指导],下面仅针与基础视频编码过程中存在的区别做具体说明。
constexpr int32_t NEEDED_LTR_COUNT = 5;
bool isSupported = false;
int32_t supportedLTRCount = 0;
// 1.1 获取对应编码器能力句柄,此处以H.264为例
OH_AVCapability *cap = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
// 1.2 通过特性能力查询接口校验是否支持LTR特性
isSupported = OH_AVCapability_isFeatureSupported(cap, VIDEO_ENCODER_LONG_TERM_REFERENCE);
// 1.3 确定支持的LTR数目
if (isSupported) {
OH_AVFormat *properties = OH_AVCapability_GetFeatureProperties(cap, VIDEO_ENCODER_LONG_TERM_REFERENCE);
OH_AVFormat_GetIntValue(properties, OH_FEATURE_PROPERTY_KEY_VIDEO_ENCODER_MAX_LTR_FRAME_COUNT, &supportedLTRCount);
OH_AVFormat_Destroy(properties);
// 1.4 判断LTR是否满足结构需求
isSupported = supportedLTRCount >= NEEDED_LTR_COUNT;
}
若支持,且支持的LTR数目满足自身码流结构需求,则可以使能LTR特性。
Buffer输入模式示例:
// 2.1 编码输入回调OH_AVCodecOnNeedInputBuffer实现 static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { // 输入帧buffer对应的index,送入InIndexQueue队列 // 输入帧的数据buffer送入InBufferQueue队列 // 数据处理,请参考: // - 写入编码码流 // - 通知编码器码流结束 // - 随帧参数写入 OH_AVFormat *format = OH_AVBuffer_GetParameter(buffer); OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_MARK_LTR, 1); OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_USE_LTR, 4); OH_AVBuffer_SetParameter(buffer, format); // 通知编码器buffer输入完成 OH_VideoEncoder_PushInputBuffer(codec, index); } // 2.2 编码输出回调OH_AVCodecOnNewOutputBuffer实现 static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { // 完成帧buffer对应的index,送入outIndexQueue队列 // 完成帧的数据buffer送入outBufferQueue队列 // 数据处理,请参考: // - 释放编码帧 // - 记录POC和LTR生效情况 } // 2.3 注册数据回调 OH_AVCodecCallback cb; cb.onNeedInputBuffer = OnNeedInputBuffer; cb.onNewOutputBuffer = OnNewOutputBuffer; OH_VideoEncoder_RegisterCallback(codec, cb, nullptr);
Surface输入模式示例:
// 2.1 编码输入参数回调OH_VideoEncoder_OnNeedInputParameter实现 static void OnNeedInputParameter(OH_AVCodec *codec, uint32_t index, OH_AVFormat *parameter, void *userData) { // 输入帧buffer对应的index,送入InIndexQueue队列 // 输入帧的数据avformat送入InFormatQueue队列 // 数据处理,请参考: // - 写入编码码流 // - 通知编码器码流结束 // - 随帧参数写入 OH_AVFormat_SetIntValue(parameter, OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_MARK_LTR, 1); OH_AVFormat_SetIntValue(parameter, OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_USE_LTR, 4); // 通知编码器随帧参数配置输入完成 OH_VideoEncoder_PushInputParameter(codec, index); } // 2.2 编码输出回调OH_AVCodecOnNewOutputBuffer实现 static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { // 完成帧buffer对应的index,送入outIndexQueue队列 // 完成帧的数据buffer送入outBufferQueue队列 // 数据处理,请参考: // - 释放编码帧 // - 记录POC和LTR生效情况 } // 2.3 注册数据回调 OH_AVCodecCallback cb; cb.onNewOutputBuffer = OnNewOutputBuffer; OH_VideoEncoder_RegisterCallback(codec, cb, nullptr); // 2.4 注册随帧参数回调 OH_VideoEncoder_OnNeedInputParameter inParaCb = OnNeedInputParameter; OH_VideoEncoder_RegisterParameterCallback(codec, inParaCb, nullptr);
constexpr int32_t TGOP_SIZE = 3;
// 3.1 创建配置用临时AVFormat
OH_AVFormat *format = OH_AVFormat_Create();
// 3.2 填充使能LTR个数键值对
OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_LTR_FRAME_COUNT, NEEDED_LTR_COUNT);
// 3.3 参数配置
int32_t ret = OH_VideoEncoder_Configure(videoEnc, format);
if (ret != AV_ERR_OK) {
// 异常处理
}
// 3.4 配置完成后销毁临时AVFormat
OH_AVFormat_Destroy(format);
(可选)在运行阶段输出轮转中,获取码流对应时域层级信息。
同全局时域分层特性。
因在输入轮转有配置LTR参数,也可在输入轮转中中记录,输出轮转中找到对应的输入参数。
(可选)在运行阶段输出轮转中,使用步骤4获取的时域层级信息,自适应传输或自适应解码。
同全局时域分层特性。
很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。
而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点
如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。
针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细鸿蒙(OpenHarmony )手册(共计1236页)与鸿蒙(OpenHarmony )开发入门视频,帮助大家在技术的道路上更进一步。
鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。
并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行! 自↓↓↓拿
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。