音视频入门基础: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的函数分析

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

一、引言

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.mzph.cn/news/860438.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

供应全志T507-H芯片

长期供应各品牌芯片&#xff1a; T507-H D6FH1G842A3CZ D6DA2G140K2A7-Z D5DA942M5K2G6 MT51J256M32HF-70:B MT62F1536M64D8CH-031 WT:A MT62F1536M64D8CL-023 WT:B MT62F1536M64D8CL-026 WT:B MT62F1536M64D8EK-023 WT:B MT62F1G64D8CH-031 WT:B SVF8N65RDTR 60…

SpringBoot-在配置文件中使用Profile

Profile&#xff0c;译为“配置文件” 在这里的Spring Boot也是一样&#xff0c;我们可以配置很多个Profile&#xff0c;每个Profile都对应一整个完整的全局配置&#xff0c;激活哪个&#xff0c;那个对应的全局配置就生效&#xff0c;具体的配置&#xff1a; 1、properties格…

浔川AI五子棋(改进(完整)版1.3)——浔川python社

简介&#xff1a; 浔川AI五子棋是一种使用人工智能技术来进行五子棋对弈的游戏。它采用了先进的算法和模型&#xff0c;在对弈过程中能够实时分析棋局并进行决策&#xff0c;使得游戏更具挑战性和趣味性。 浔川AI五子棋的核心技术是人工智能算法。它使用深度学习模型对大量的…

漏洞挖掘 | 记一次edusrc--轻松拿下中危信息泄露

1.前言 也是一次漏洞挖掘的思路分享 上次我们讲过了关于小程序方面的一些小思路&#xff0c;即关于抓包更改id号造成的一个信息泄露&#xff0c;但是在小程序上的信息泄露很难涉及到公民三要素这是一个痛点&#xff0c;今天就来分享一下一次edu挖掘时挖到的一个涉及公民三要素…

【讲师招募】PowerData 2024数字经济开源行

【讲师招募】PowerData 2024数字经济开源行 活动信息讲师招募往期活动回顾 活动信息 2023&#xff0c;社区经过一年的发展&#xff0c;凝聚起了一批热爱数据、热爱开源的伙伴。 2024&#xff0c;社区计划在全国十个城市举办"数字经济-城市开源行"活动&#xff0c;连…

2024年最新中级会计职称考试题库。

46.甲将一汇票背书转让给乙&#xff0c;但该汇票上未记载乙的名称。其后&#xff0c;乙在该汇票被背书人栏内记载了自己的名称。根据《票据法》的规定&#xff0c;下列有关该汇票背书与记载效力的表述中&#xff0c;正确的是&#xff08;&#xff09;。 A.甲的背书无效&#x…

Qt案例-ApplicationExamples-Calqlatr

项目 一个Qt Quick应用程序设计的横向和纵向设备&#xff0c;使用自定义组件&#xff0c;响应式布局和JavaScript的应用程序逻辑。 项目路径&#xff1a; Qt\Examples\Qt-6.7.1\demos 环境&#xff1a;Qt6.7.1 MSVC 2019 64位 项目目录&#xff1a; calqlatr--CMakeList.txt…

三、用户中心项目笔记----后端多环境实战+原始部署

后端多环境主要是修改&#xff1a; 依赖的环境地址 数据库地址 缓存地址 消息队列地址 项目端口号 服务器配置 后端怎么去区分不同的环境&#xff1f; 我们后端的SpringBoot项目&#xff0c;通过application.yml添加不同后缀来区分配置文件 application.yml就是公共的配置&a…

Sam Altman:从少儿奇才到OpenAI掌舵人

自2022年底发布了ChatGPT以来&#xff0c;OpenAI及其首席执行官Sam Altman迅速成为科技界的焦点人物。Altman的崛起并非偶然&#xff0c;而是长期以来不断追求权力和创新的结果。本文将回顾Altman的成长历程&#xff0c;探索他如何一步步走向OpenAI的顶峰。 童年与教育背景 S…

乌班图Ubuntu 24.04初始化MySQL报错error while loading shared libraries: libaio.so.1

由于乌班图24.04 LTS已经发布了&#xff0c;因此准备新业务逐步往这上面迁移&#xff0c;毕竟支持有效期比22.04更长 准备在24.04上进行MySQL的初始化&#xff0c;因为习惯自定义安装存储目录&#xff0c;所以使用mysql-8.0.37-linux-glibc2.28-x86_64.tar.xz这个最新的二进制版…

7款三维地球软件/框架:Google Earth SkylineGlobe,Cesium等

可视化大屏已经不满足于2D和3D展示了&#xff0c;开始向着星辰大海迈进了&#xff0c;本文介绍7款三维地球软件/开发框架&#xff0c;带各位老铁入个门。 1. Google Earth: 大名鼎鼎&#xff0c;Google Earth 是由 Google 开发的一款免费的虚拟地球软件。它提供了全球范围内的…

【自然语言处理系列】手动安装和测试Spacy中en_core_web_sm模型的详细教程

摘要&#xff1a;本教程旨在为自然语言处理&#xff08;NLP&#xff09;初学者提供一个详细的指南&#xff0c;用于手动安装流行的NLP库Spacy及其英语模型en_core_web_sm。文章将逐步指导您如何安装Spacy库、查看其版本&#xff0c;确定并下载适合的en_core_web_sm模型版本&…

HarmonyOS应用开发——Hello World

下载 HUAWEI DevEco Studio: https://developer.harmonyos.com/cn/develop/deveco-studio/#download 同意&#xff0c;进入配置页面&#xff1a; 配置下载源以及本地存放路径&#xff0c;包括nodejs和ohpm: 配置鸿蒙SDK路径&#xff1a; 接受协议&#xff1a; 确认无误后&#…

<Linux> 缓冲区谁维护?

缓冲区是谁提供的&#xff1f; 来看一段代码 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> int main() {const char *str1 "a";printf("%s", str1);const char *str2 "b";writ…

C++并发之阻塞队列(block,queue)

目录 1 概述2 实现3 测试3 运行 1 概述 最近研究了C11的并发编程的线程/互斥/锁/条件变量&#xff0c;利用互斥/锁/条件变量实现一个支持多线程并发的阻塞队列&#xff0c;队列大小没有限制。 阻塞队列是一个模板类&#xff0c;有两个模块参数&#xff0c;参数1是元素类型&…

C++ 左值右值 || std::move() || 浅拷贝,深拷贝 || 数据类型

数据类型&#xff1a; 作用&#xff1a;决定变量所占内存空间的字节大小&#xff0c;和布局方式基本数据类型&#xff1a; 算数类型&#xff1a; 整形&#xff08;bool / char……扩展集 / int / long……&#xff09;&& 浮点形&#xff08;float/double……&#xff…

java-包装类 2

### 8. 包装类的应用场景 #### 8.1 集合框架 包装类在Java集合框架中得到了广泛应用&#xff0c;因为集合只能存储对象而不能存储基本数据类型。 java import java.util.HashMap; public class CollectionExample { public static void main(String[] args) { …

MySQL2(Mysql对数据的增删改 数据的备份和还原 单表查询 常用的聚合函数(⭐⭐))

目录 一、Mysql对数据的增删改 1. 增加数据&#xff08;INSERT语句&#xff09; 2. 修改数据&#xff08;UPDATE语句&#xff09; ​编辑 WHERE子句&#xff08;⭐&#xff09;&#xff1a; ​编辑 3. 删除数据&#xff08;DELETE语句&#xff09; 删除数据&#xff0…

轮播图的制作大全

例如该样式: 1.Vue的方法(可实现自动轮播和左右按钮和下方原点按钮轮播) <div id="app"><div class="a" ref="b" @mouseenter="MouseFun(c)" @mouseleave="MouseFun(d)">//1.图片显示盒子<div class=&qu…

接受两个参数,并基于给定的概率(40%和60%)返回相应的参数值

function getRandomValue(param1, param2) {// 生成一个0到1之间的随机数const randomNum Math.random();// 定义40%和60%的概率const probability1 0.4; // param1的概率为40%const probability2 0.6; // param2的概率为60%// 根据概率返回相应的参数if (randomNum < pr…