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

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.xdnf.cn/news/1211923.html

相关文章:

  • MidJourney精选图集与提示词生成器:AI创意灵感与高效提示词工具
  • 无监督MVSNet系列网络概述
  • 高效管理Hosts文件的终极工具
  • 【Qt开发】信号与槽(三)-> 自定义信号和槽
  • Python 程序设计讲义(46):组合数据类型——集合类型:集合间运算
  • 解决 Node.js 托管 React 静态资源的跨域问题
  • 力扣54:螺旋矩阵
  • 疯狂星期四文案网第24天运营日记
  • 永磁同步电机FOC控制----电流采样的实现
  • 【Lambda】flatMap使用案例
  • 字节跳动“扣子”(Coze)开源:AI智能体生态的技术革命
  • 从结构到交互:HTML5进阶开发全解析——语义化标签、Canvas绘图与表单设计实战
  • 微软OpenAI展开深入谈判
  • DIV 指令概述
  • 视觉语言模型在视觉任务上的研究综述
  • HTML第一次作业
  • JavaWeb 进阶:Vue.js 与 Spring Boot 全栈开发实战(Java 开发者视角)
  • 【数据结构初阶】--二叉树(四)
  • Prometheus-1--什么是Prometheus?
  • Docker网络技术深度研究与实战手册
  • C++类中动态内存分配注意手册
  • 基于springboot的零食商城的设计与实现/零食销售系统的设计与实现
  • 每日学习笔记记录(分享更新版-凌乱)
  • LeetCode 11 - 盛最多水的容器
  • Vue.js 指令系统完全指南:深入理解 v- 指令
  • python的进程、线程、锁
  • DNS污染与劫持
  • Wndows Docker Desktop-Unexpected WSL error错误
  • 项目历程—生命数组游戏(两版本)
  • Vulkan入门教程 | 第二部分:创建实例