当前位置: 首页 > 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对应:

相关文章:

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

音视频入门基础&#xff1a;H.264专题系列文章&#xff1a; 音视频入门基础&#xff1a;H.264专题&#xff08;1&#xff09;——H.264官方文档下载 音视频入门基础&#xff1a;H.264专题&#xff08;2&#xff09;——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…...

RT-Thread ENV-Windows v2.0.0安装教程

前言 前几天RT-Thread官方更新了env工具&#xff0c;开源仓库的Kconfig的写法都不大一样了&#xff1b;如果继续用原来的env工具&#xff0c;拉新代码之后很多示例都编译不了 在最新的env工具中menuconfig全面采用kconfiglib&#xff0c;升级env脚本和python版本&#xff0c;改…...

[HBM] HBM TSV (Through Silicon Via) 结构与工艺

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解DDR》 全文 3300 字。 1 概念 1.1 什么是HBM TSV 使用 TSV 堆叠多个DDR DRAM成为一块HBM, 成倍提高了存储器位宽&#xff0c; 一条位宽相当于高速公路的一条车道&#xff0c; 车道越多&#xff…...

基于STM32的温湿度检测TFT屏幕proteus恒温控制仿真系统

一、引言 本文介绍了一个基于STM32的恒温控制箱检测系统&#xff0c;该系统通过DHT11温湿度传感器采集环境中的温湿度数据&#xff0c;并利用TFT LCD屏幕进行实时显示。通过按键切换页面显示&#xff0c;通过按键切换实现恒温控制箱的恒温控制。为了验证系统的可靠性和稳定性&…...

【Qt+opencv】编译、配置opencv

文章目录 前言下载opencv编译opencvmingw版本 总结 前言 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库&#xff0c;它包含了超过2500个优化的算法。这些算法可以用来检测和识别面部&#xff0c;识别对象&#x…...

RDMA建链的3次握手和断链的4次挥手流程?

文章目录 基础信息建链 3次握手断链4次挥手建联状态active端passive端 报文结构函数关系其他后记 基础信息 CM: Communication Management 通信管理 连接管理SIDR: Service ID Resolution Protocol. 作用&#xff1a; enables users of Unreliable Datagram service to locate …...

实验4 图像空间滤波

1. 实验目的 ①掌握图像空间滤波的主要原理与方法&#xff1b; ②掌握图像边缘提取的主要原理和方法&#xff1b; ③了解空间滤波在图像处理和机器学习中的应用。 2. 实验内容 ①调用 Matlab / Python OpenCV中的函数&#xff0c;实现均值滤波、高斯滤波、中值滤波等。 ②调…...

独辟蹊径:我是如何用Java自创一套工作流引擎的(下)

作者&#xff1a;后端小肥肠 创作不易&#xff0c;未经允许严禁转载。 姊妹篇&#xff1a;独辟蹊径&#xff1a;我是如何用Java自创一套工作流引擎的&#xff08;上&#xff09;_java工作流引擎-CSDN博客 1. 前言 在上一篇博客中&#xff0c;我们详细介绍了如何利用Java语言从…...

【Python】pycharm常用快捷键操作

目录 一.pycharm自定义修改快捷键 二.pycharm默认常用快捷键 一.pycharm自定义修改快捷键 在file-setting-keymap中可以修改快捷键&#xff0c;建议刚开始没特殊需求就不用修改&#xff0c;先熟悉系统默认的常用快捷键&#xff0c;但是以下情况可以考虑修改: 之前使用其他I…...

es6语法复习一

es6语法 1.var 变量提升 2.let 不存在变量提升&#xff0c;只能定义一次 3.const 先定义再使用&#xff0c;定义好来不能修改 4.解构赋值 [a,b,c][1,2,3],{a,b,c}{a:1,b:2,c:3} 5.模版字符串 let aaa; ${a} is ok 6.对象简化写法 const school{ name, change, improve(){ cons…...

【python入门】自定义函数

文章目录 定义自定义函数的基本语法参数类型示例代码函数作用域匿名函数&#xff08;Lambda&#xff09;闭包装饰器 Python中的自定义函数允许你编写一段可重用的代码块&#xff0c;这段代码可以带参数&#xff08;输入&#xff09;&#xff0c;并可能返回一个值&#xff08;输…...

ONLYOFFICE 桌面编辑器 8.1 版发布:全面提升文档处理效率的新体验

文章目录 什么是ONLYOFFICE &#xff1f;ONLYOFFICE 桌面编辑器 8.1 发布&#xff1a;新功能和改进功能强大的 PDF 编辑器幻灯片版式功能从右至左语言支持多媒体功能增强无缝切换工作模式其他改进和优化总结 什么是ONLYOFFICE &#xff1f; https://www.onlyoffice.com/zh/off…...

ESP32实现UDP连接——micropython版本

代码&#xff1a; import network import socket import timedef wifiInit(name, port):ap network.WLAN(network.AP_IF) # 创建一个热点ap.config(essidname, authmodenetwork.AUTH_OPEN) # 无需密码ap.active(True) # 激活热点ip ap.ifconfig()[0] # 获取ip地址print(…...

Windows Ternimal

Windows Ternimal 安装 Windows 终端概述 | Microsoft Learn wt --help在当前目录打开 lextm/windowsterminal-shell: Install/uninstall scripts for Windows Terminal context menu items 打开指定目录 wt -d %USERPROFILE% ohmyposh 美化 1 安装 2 添加 ohmyposh bin…...

Unity扩展编辑器功能的特性

1.添加分组标题 用于在Unity的Inspector视图中为属性或变量组创建一个自定义的标题或头部&#xff0c;有助于在Inspector中组织和分类不同的属性&#xff0c;使其更易于阅读和管理。 [Header("Common Properties")] public float MouseSensitivity 5; public float…...

API类别 - UI核心

API类别 - UI核心 引言 在当今的数字时代,用户界面(UI)是任何软件或应用成功的关键因素之一。UI核心API作为构建用户界面的基础,提供了丰富的功能和工具,使得开发者能够创建出既美观又实用的用户界面。本文将深入探讨UI核心API的不同类别,以及它们如何影响现代软件开发…...

Redis-主从复制-配置主从关系

文章目录 1、修改配置文件中的 bind ,注释该配置,取消绑定仅主机登录2、修改protected-mode 为no,取消保护模式3、查看redis的进程状态4、配置6380是6379的从机5、配置6381是6379的从机6、查看主机 6379 的主从信息 1、修改配置文件中的 bind ,注释该配置,取消绑定仅主机登录 …...

DigiRL:让 AI 自己学会控制手机

类似于苹果此前发布的Ferret-UI 的安卓开源平替。主要用于在 Android 设备上识别 UI 和执行指令&#xff0c;不同的是它利用了离线到在线强化学习&#xff08;Offline-to-Online RL&#xff09;&#xff0c;能够快速适应应用更新或 UI 变化。...

04.Ambari自定义服务开发-自定义服务配置文件在Ambari中的设置方法

文章目录 设置方法配置文件设置Custom xxx配置文件详细的配置方法.xml文件的整体格式基础参数格式value-attributes配置介绍设置属性在服务安装后不可修改设置允许字段为空是否显示配置名称参数类型设置字符串类型PasswordBooleanIntFloatDirectoryDirectoriesContent-多行文本…...

LSTM时间序列基础学习

时间序列 时间序列可以是一维&#xff0c;二维&#xff0c;三维甚至更高维度的数据&#xff0c;在深度学习的世界中常见的是三维时间序列&#xff0c;这三个维度分别是&#xff08;batch_size,time_step,input_dimensions&#xff09;。 其中time_step是时间步&#xff0c;它…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...