当前位置: 首页 > news >正文

音视频入门基础:H.264专题(5)——FFmpeg源码中 解析NALU Header的函数分析

=================================================================

音视频入门基础:H.264专题系列文章:

音视频入门基础:H.264专题(1)——H.264官方文档下载

音视频入门基础:H.264专题(2)——使用FFmpeg命令生成H.264裸流文件

音视频入门基础:H.264专题(3)——EBSP, RBSP和SODB

音视频入门基础:H.264专题(4)——NALU Header:forbidden_zero_bit、nal_ref_idc、nal_unit_type简介

音视频入门基础:H.264专题(5)——FFmpeg源码中 解析NALU Header的函数分析

音视频入门基础:H.264专题(6)——FFmpeg源码:从H.264码流中提取NALU Header、EBSP、RBSP和SODB

音视频入门基础:H.264专题(7)——FFmpeg源码中 指数哥伦布编码的解码实现

音视频入门基础:H.264专题(8)——H.264官方文档的描述符

=================================================================

一、引言

FFmpeg源码中 通过h264_parse_nal_header函数将H.264码流的NALU Header解析出来。下面对h264_parse_nal_header函数进行分析。


 

二、h264_parse_nal_header函数定义

h264_parse_nal_header函数定义在FFmpeg源码(下面演示的FFmpeg源码版本是5.0.3)的源文件libavcodec/h2645_parse.c 中:

static int h264_parse_nal_header(H2645NAL *nal, void *logctx)
{GetBitContext *gb = &nal->gb;if (get_bits1(gb) != 0)return AVERROR_INVALIDDATA;nal->ref_idc = get_bits(gb, 2);nal->type    = get_bits(gb, 5);av_log(logctx, AV_LOG_DEBUG,"nal_unit_type: %d(%s), nal_ref_idc: %d\n",nal->type, h264_nal_unit_name(nal->type), nal->ref_idc);return 0;
}

该函数作用是:将NALU Header解析出来,由形参nal返回。

形参nal:

nal->gb:输入型参数。(&(nal->gb))->buffer指向存放NALU Header + RBSP 的缓冲区。

nal->ref_idc:输出型参数。执行h264_parse_nal_header函数后,nal->ref_idc的值为NALU Header中的nal_ref_idc。

nal->type:输出型参数。执行h264_parse_nal_header函数后,nal->type的值为NALU Header中的nal_unit_type。

形参logctx:输入型参数。用来输出日志,可以忽略。

返回值:解析NALU Header成功返回0。失败返回AVERROR_INVALIDDATA。

三、h264_parse_nal_header函数的内部实现原理

h264_parse_nal_header函数中,首先通过语句get_bits1(gb);拿到NALU Header中forbidden_zero_bit。关于get_bits1用法可以参考:《FFmpeg中位操作相关的源码:GetBitContext结构体,init_get_bits函数、get_bits1函数和get_bits函数分析》。

由于forbidden_zero_bit 的值应为0,如果它的值为1,则意味着比特流语法出错了,也就是FFmpeg头文件libavutil/error.h里面定义的“Invalid data found when processing input”:

#define AVERROR_INVALIDDATA        FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input

所以如果forbidden_zero_bit的值不为0,返回AVERROR_INVALIDDATA。

所以有下面语句:

if (get_bits1(gb) != 0)return AVERROR_INVALIDDATA;

然后通过下面语句,读取NALU Header中的nal_ref_idc和nal_unit_type,分别保存到nal->ref_idc和nal->type中。

nal->ref_idc = get_bits(gb, 2);
nal->type    = get_bits(gb, 5);

最后通过

av_log(logctx, AV_LOG_DEBUG,"nal_unit_type: %d(%s), nal_ref_idc: %d\n",nal->type, h264_nal_unit_name(nal->type), nal->ref_idc);

日志输出NALU Header的信息。

h264_nal_unit_name函数是用来得到nal_unit_type的名称。其定义如下:

static const char *const h264_nal_type_name[32] = {"Unspecified 0", //H264_NAL_UNSPECIFIED"Coded slice of a non-IDR picture", // H264_NAL_SLICE"Coded slice data partition A", // H264_NAL_DPA"Coded slice data partition B", // H264_NAL_DPB"Coded slice data partition C", // H264_NAL_DPC"IDR", // H264_NAL_IDR_SLICE"SEI", // H264_NAL_SEI"SPS", // H264_NAL_SPS"PPS", // H264_NAL_PPS"AUD", // H264_NAL_AUD"End of sequence", // H264_NAL_END_SEQUENCE"End of stream", // H264_NAL_END_STREAM"Filler data", // H264_NAL_FILLER_DATA"SPS extension", // H264_NAL_SPS_EXT"Prefix", // H264_NAL_PREFIX"Subset SPS", // H264_NAL_SUB_SPS"Depth parameter set", // H264_NAL_DPS"Reserved 17", // H264_NAL_RESERVED17"Reserved 18", // H264_NAL_RESERVED18"Auxiliary coded picture without partitioning", // H264_NAL_AUXILIARY_SLICE"Slice extension", // H264_NAL_EXTEN_SLICE"Slice extension for a depth view or a 3D-AVC texture view", // H264_NAL_DEPTH_EXTEN_SLICE"Reserved 22", // H264_NAL_RESERVED22"Reserved 23", // H264_NAL_RESERVED23"Unspecified 24", // H264_NAL_UNSPECIFIED24"Unspecified 25", // H264_NAL_UNSPECIFIED25"Unspecified 26", // H264_NAL_UNSPECIFIED26"Unspecified 27", // H264_NAL_UNSPECIFIED27"Unspecified 28", // H264_NAL_UNSPECIFIED28"Unspecified 29", // H264_NAL_UNSPECIFIED29"Unspecified 30", // H264_NAL_UNSPECIFIED30"Unspecified 31", // H264_NAL_UNSPECIFIED31
};static const char *h264_nal_unit_name(int nal_type)
{av_assert0(nal_type >= 0 && nal_type < 32);return h264_nal_type_name[nal_type];
}

可以看到h264_nal_unit_name函数内部通过nal_unit_type拿到数组h264_nal_type_name中对应的字符串(名称)。

h264_nal_type_name数组跟H.264官方文档《T-REC-H.264-202108-I!!PDF-E.pdf》第65页描述的nal_unit_type对应:

http://www.lryc.cn/news/387588.html

相关文章:

  • RT-Thread ENV-Windows v2.0.0安装教程
  • [HBM] HBM TSV (Through Silicon Via) 结构与工艺
  • 基于STM32的温湿度检测TFT屏幕proteus恒温控制仿真系统
  • 【Qt+opencv】编译、配置opencv
  • RDMA建链的3次握手和断链的4次挥手流程?
  • 实验4 图像空间滤波
  • 独辟蹊径:我是如何用Java自创一套工作流引擎的(下)
  • 【Python】pycharm常用快捷键操作
  • es6语法复习一
  • 【python入门】自定义函数
  • ONLYOFFICE 桌面编辑器 8.1 版发布:全面提升文档处理效率的新体验
  • ESP32实现UDP连接——micropython版本
  • Windows Ternimal
  • Unity扩展编辑器功能的特性
  • API类别 - UI核心
  • Redis-主从复制-配置主从关系
  • DigiRL:让 AI 自己学会控制手机
  • 04.Ambari自定义服务开发-自定义服务配置文件在Ambari中的设置方法
  • LSTM时间序列基础学习
  • 『Z-Workshop』 6月22日线下ALCOVE分享活动
  • 【机器学习】机器学习重要方法——迁移学习:理论、方法与实践
  • uniapp, ‍[⁠TypeError⁠]‍ “Failed to fetch dynamically imported module“ 报错解决思路
  • 四川省高等职业学校大数据技术专业建设暨专业质量监测研讨活动顺利开展
  • 深入解析三大跨平台开发框架:Flutter、React Native 和 uniapp
  • 【吊打面试官系列-MyBatis面试题】#{}和${}的区别是什么?
  • 解决HTTP 400 Bad Request错误的方法
  • Html的表单标签。(Java程序员需要掌握的前端)
  • Arduino (esp ) 下String的内存释放
  • 图灵虚拟机配置
  • 【SQL常用日期函数(一)】