FFmpeg,如何插入SEI自定义数据

FFmpeg,如何插入SEI自定义数据

一、什么是SEI?

SEI(Supplemental Enhancement Information,补充增强信息)是H.264/H.265视频编码标准中的一种元数据载体,它允许在视频流中嵌入额外的信息,如时间戳、人脸框、设备信息等增强信息。

与视频帧数据不同,SEI信息不是解码必需的,但可以用于增强播放体验或传递辅助信息。

二、AVPacket中插入SEI

在ffmpeg中,H264裸流的数据,一个 AVPacket 可能包含多个 NALU,它们之间通过起始码 0x00 00 00 010x00 00 01 分隔。

一般情况下,SEI需要插入到IDR帧之前。

一个AVPacket中的关键帧数据包含SPS、PPS、IDR,而SEI的插入位置在PPS之后,IDR之前,如下图所示。

三、如何构建一个SEI NALU

1、SEI NALU格式

SEI NALU由起始码(0x00 00 00 01)、nal head(0x06)、payload type(0x05)、UVLC编码字节数、rbsp_data组成。其中rbsp_data由uuid(16字节)、payload、结束标记(0x80)组成,具体格式如下图所示。

字段名

说明

示例值或长度

Start Code

起始码(Annex-B 格式)

0x00000001

NAL Header

NAL 类型为 SEI

0x06

SEI Payload Type

固定为 5,表示未注册用户数据

0x05

SEI Payload Size

整个 payload 长度(字节)

0x2F(47)

UUID

16 字节,唯一标识数据类型

dc45e9bd...

Payload Content

自定义数据内容(如字符串)

"hello"

RBSP Trailing Bits

固定结尾对齐字节

0x80

2、UVLC编码字节数

UVLC(Unsigned Variable Length Coding)是H.264/H.265标准中用于编码SEI的payload_size和payload_type的压缩算法,其核心特点是:

  • 无符号整数编码:仅处理非负整数
  • 前缀码结构:通过0xFF标记实现变长
  • 自描述性:解码器无需预知长度即可解析

UVLC采用累加式多字节表示法:

若值 < 0xFF:用1字节直接表示

    value = 100 0x64

若值 0xFF

  • 第1字节固定为0xFF
  • 剩余值递归编码(value -= 255)

value = 300 0xFF 0x2D (300 = 255 + 45)

value = 550 0xFF 0xFF 0x28 (550 = 255 + 255 + 40)

3、rbsp_data

四、参考信息

1、NALU类型

NALU 的类型,共 32 种(0-31),常见类型如下表:

nal_unit_type 

NALU 类型

说明

0

未指定

保留,不使用

1

非 IDR 图像的片(Slice)

P 帧或 B 帧的 Slice 数据

2

数据分区 A

用于分片编码,存放重要的运动信息

3

数据分区 B

存放次要的运动信息

4

数据分区 C

存放残差数据

5

IDR 图像的片(Slice)

立即刷新图像(关键帧)的 Slice 数据,解码时需清空参考帧缓冲区

6

SEI(补充增强信息)

包含额外信息(如时间戳、用户数据),不影响基本解码

7

SPS(序列参数集)

包含视频序列的全局参数(如分辨率、profile 等)

8

PPS(图像参数集)

包含图像级参数(如量化参数、熵编码方式)

9

访问单元分隔符

标记视频帧的开始

10

序列结束符

标记视频序列的结束

11

流结束符

标记整个码流的结束

12

填充数据

用于增加码流长度(如测试场景)

13-23

保留

用于 H.264 的扩展功能

24-31

未指定

通常用于 RTP 等网络协议的封装

2. RBSP(Raw Byte Sequence Payload)

RBSP 是 NALU 的负载数据,包含 VCL 层的压缩信息(如 Slice 数据、参数集内容)。它由SODB(String of Data Bits) 经过处理后得到:

SODB:VCL 层输出的原始比特流(如预测残差、运动矢量等);

RBSP:在 SODB 末尾添加停止位(1 个 "1" 比特后跟若干 "0" 比特),使其字节对齐,形成 RBSP。

3、关键 NALU 类型详解

3.1 SPS(序列参数集,nal_unit_type=7)

SPS 是视频序列的全局配置,包含影响整个序列的参数,解析时需优先处理。常见参数如下:

// SPS参数示例(部分关键参数)
profile_idc                 // 编码profile(如Baseline=66,Main=77,High=100)
level_idc                   // 编码level(如3.0=30,3.1=31)
seq_parameter_set_id        // SPS的ID(用于关联PPS)
chroma_format_idc           // 色度格式(如1=4:2:0,2=4:2:2,3=4:4:4)
bit_depth_luma_minus8       // 亮度位深度(通常为8)
bit_depth_chroma_minus8     // 色度位深度(通常为8)
log2_max_frame_num_minus4   // 最大帧号的对数(用于计算帧号范围)
pic_order_cnt_type          // 图像顺序计数类型(0-2,控制POC的计算方式)
max_num_ref_frames          // 最大参考帧数量
pic_width_in_mbs_minus1     // 视频宽度(以宏块为单位,实际宽度=(值+1)*16)
pic_height_in_map_units_minus1 // 视频高度(以宏块为单位)
frame_mbs_only_flag         // 是否仅帧编码(0=支持帧/场混合,1=仅帧)

3.2 PPS(图像参数集,nal_unit_type=8)

PPS 定义单幅图像的参数,依赖于 SPS,常见参数如下:

// PPS参数示例(部分关键参数)
pic_parameter_set_id        // PPS的ID
seq_parameter_set_id        // 关联的SPS的ID
entropy_coding_mode_flag    // 熵编码方式(0=CAVLC,1=CABAC)
num_ref_idx_l0_default_active_minus1 // 默认的前向参考帧列表长度
num_ref_idx_l1_default_active_minus1 // 默认的后向参考帧列表长度
weighted_pred_flag          // 是否使用加权预测(对P帧)
weighted_bipred_idc         // 双向预测加权模式(0-2)
pic_init_qp_minus26         // 初始量化参数(QP=值+26)
deblocking_filter_control_present_flag // 是否存在去块滤波控制信息

3.3. IDR Slice(即时解码刷新,nal_unit_type=5)

IDR Slice 是一种特殊的 I Slice,属于关键帧:

解码 IDR Slice 时,解码器会清空所有参考帧缓冲区,确保后续帧的解码不依赖之前的错误帧,从而终止错误传播。

IDR Slice 必须包含完整的帧内预测信息,不依赖其他帧。

3.4. 非 IDR Slice(nal_unit_type=1)

包括 P Slice 和 B Slice:

P Slice:依赖前向参考帧(已解码的 I/P 帧)进行预测;

B Slice:依赖双向参考帧(前向和后向的 I/P 帧)进行预测,压缩效率更高。

3.5. SEI(补充增强信息,nal_unit_type=6)

携带与解码无关的辅助信息,常见类型:

时间戳信息(如 NTP 时间);

用户数据(如字幕、水印);

场景切换标记;

码流统计信息。

具体实现方式参见:

https://gitee.com/hanshuang741852/mem-push-streamhttps://gitee.com/hanshuang741852/mem-push-stream

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:
http://www.pswp.cn/web/91584.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/91584.shtml

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

相关文章

为什么分类任务偏爱交叉熵?MSE 为何折戟?

在机器学习的世界里&#xff0c;损失函数是模型的“指南针”——它定义了模型“好坏”的标准&#xff0c;直接决定了参数优化的方向。对于分类任务&#xff08;比如判断一张图片是猫还是狗&#xff09;&#xff0c;我们通常会选择交叉熵作为损失函数&#xff1b;而在回归任务&a…

[echarts]横向柱状图

前言 接到一个需求&#xff0c;需要展示一个横向的柱状图&#xff0c;按数量从大到小排序&#xff0c;并定时刷新 使用react配合echarts进行实现。 react引入echarts import React, { useEffect, useRef } from react; import * as echarts from echarts; import DeviceApi fro…

【开源项目】轻量加速利器 HubProxy 自建 Docker、GitHub 下载加速服务

​​引言​​ 如果你经常被 Docker 镜像拉取、GitHub 文件下载的龟速折磨&#xff0c;又不想依赖第三方加速服务&#xff08;担心稳定性或隐私&#xff09;&#xff0c;今天分享的 ​​HubProxy​​ 可能正是你需要的。这个开源工具用一行命令就能部署&#xff0c;以极低资源消…

java web jsp jstl练习

JSP 的学习。 核心功能模块 1. 源代码层 &#xff08; src &#xff09; HelloWorld &#xff1a;主程序入口领域模型 &#xff1a; domain 包含User.java和ceshi.java控制器 &#xff1a; servlet 包含登录验证和验证码相关ServletWeb表现层 &#xff08; web &#xff09; JS…

VSCode 完全指南:释放你的编码潜能

零、简介 在当今的软件开发领域&#xff0c;代码编辑器的选择至关重要&#xff0c;它就像是工匠手中的工具&#xff0c;直接影响着工作效率和成果质量。Visual Studio Code&#xff08;简称 VSCode&#xff09;自问世以来&#xff0c;迅速在全球开发者社区中崭露头角&#xff…

《n8n基础教学》第一节:如何使用编辑器UI界面

在本课中&#xff0c;你将学习如何操作编辑器界面。我们将浏览画布&#xff0c;向您展示每个图标的含义&#xff0c;以及在 n8n 中构建工作流程时在哪里可以找到您需要的东西。本课程基于 n8n 最新版本 。在其他版本中&#xff0c;某些用户界面可能有所不同&#xff0c;但这不会…

gcc g++ makefile CMakeLists.txt cmake make 的关系

gcc&#xff1a;C语言编译器g&#xff1a;C编译器makefile&#xff1a;定义编译规则、依赖关系和构建目标。可以手动编写&#xff0c;也可以由CMakeLists.txt生成cmake&#xff1a;读取CMakeLists.txt文件&#xff0c;生成Makefilemake&#xff1a;构建工具&#xff0c;执行Mak…

SFT 训练器

SFT 训练器 “训练时间到!” 我们现在终于可以创建一个监督微调训练器的实例了: trainer = SFTTrainer( model=model, processing_class=tokenizer, args=sft_config, train_dataset=dataset, )SFTTrainer 已经对数据集进行了预处理,因此我们可以深入查看,了解每个小批次…

Android Material Components 全面解析:打造现代化 Material Design 应用

引言 在当今移动应用开发领域&#xff0c;用户体验(UX)已成为决定应用成功与否的关键因素之一。Google推出的Material Design设计语言为开发者提供了一套完整的视觉、交互和动效规范&#xff0c;而Material Components for Android(MDC-Android)则是将这些设计理念转化为可重用…

Windows使用Powershell自动安装SqlServer2025服务器与SSMS管理工具

安装结果: 安装前准备: 1.下载mssql server 2025安装器 2.下载iso镜像 3.下载好SSMS安装程序,并放到iso同目录下 4.执行脚本开始自动安装

09 RK3568 Debian11 ES8388 模拟音频输出

1、设备树配置 确认自己的i2c,使用sdk带的驱动es8323 /SDK/kernel/sound/soc/codecs/es8323.c es8388_sound: es8388-sound {status = "okay";compatible = "rockchip,multicodecs-card"; rockchip,card-name = "rockchip,es8388-codec"; …

力扣-199.二叉树的右视图

题目链接 199.二叉树的右视图 class Solution {public List<Integer> rightSideView(TreeNode root) {List<Integer> res new ArrayList<>();Queue<TreeNode> queue new LinkedList<>();if (root null)return res;queue.offer(root);while …

Android Bitmap 完全指南:从基础到高级优化

在 Android 开发中&#xff0c;图像处理是一个核心且复杂的领域&#xff0c;而 Bitmap 作为 Android 中表示图像的基本单位&#xff0c;贯穿了从简单图片显示到复杂图像编辑的各个场景。然而&#xff0c;Bitmap 处理不当往往会导致应用性能下降、内存溢出&#xff08;OOM&#…

unity日志过滤器

背景&#xff1a;之前做游戏的时候和同组的同事聊过说日志过滤尽量不要限制大家怎么使用日志打印的接口&#xff0c;不要加额外的参数&#xff0c;比如多加一个标签string,或者使用特定的接口&#xff0c;枚举。最好就是日志大家还是用Debug.Log无感去用&#xff0c;然后通过勾…

OpenGL Camera

一. lookAt函数的参数含义glm::mat4 view glm::lookAt(cameraPos, // 相机在世界坐标系中的位置&#xff08;任意值&#xff09;cameraPos cameraFront, // 相机看向的目标点&#xff08;位置朝向&#xff09;cameraUp // 相机的"上方向"&#xff08;通…

Android RTMP推送|轻量级RTSP服务同屏实践:屏幕+音频+录像全链路落地方案

一、背景&#xff1a;从“移动终端”到“远程协作节点”&#xff0c;同屏音频录像为何成刚需&#xff1f; 在数字化办公、智慧医疗与远程教育等快速发展的推动下&#xff0c;手机作为随身终端&#xff0c;已不再只是“内容接收者”&#xff0c;而逐步成为远程信息发布与可视化…

NLP 和 LLM 区别、对比 和关系

理解自然语言处理(NLP)和大语言模型(LLM)的区别、对比和关系对于把握现代人工智能的发展非常重要。以下是清晰的分析: 核心定义 NLP (Natural Language Processing - 自然语言处理): 是什么: 一个广阔的计算机科学和人工智能子领域,致力于让计算机能够理解、解释、操作…

Altium 移除在原理图之外的元器件

Altium新手&#xff0c;最近在画原理图的时候&#xff0c;遇见了这种不小心拖到界面外的元器件&#xff0c;发现拖不回来了了&#xff0c;查阅了一下&#xff0c;总结在这里 官方推荐的方法----------------使用“SCH List”面板删除 链接&#xff1a;如何移除在原理图之外的元…

【Linux我做主】细说环境变量

Linux环境变量Linux环境变量github地址前言1. 基本概念环境变量的本质2. 认识常见的环境变量PATH查看PATH修改PATHHOMESHELL其他常见环境变量PWD与OLDPWDLOGNAME与USERSSH_TTY由环境变量理解权限使用系统调用获取环境变量理解权限3. 总结什么是环境变量3. 命令行参数和环境变量…

leecode-15 三数之和

我的解法&#xff08;不是完全解309/314&#xff09;我的思路是定义一个left和一个right&#xff0c;然后在向集合里去查询&#xff0c;看看有没有除了nums[left]&#xff0c;和nums[right]的第三个元素&#xff0c;把这个问题转换为一个遍历查找问题 利用List.contains()方法来…