一、H264压缩编码

1.1 H264 中的 I 帧、P帧和 B帧

H264 使用帧内压缩和帧间压缩的方式提高编码压缩率;H264 采用了独特的 I 帧、P 帧和 B 帧策略来实现,连续帧之间的压缩;

1.2 其他概念

GOP(图像组):一个IDR帧到下一个IDR帧之间间隔了多少个帧

IDR:一个序列的第一个图像叫做IDR图像(立即刷新图像),IDR图像都是I帧图像。I帧不用参考任何帧,但之后的P帧和B帧是有可能参考这个I帧之前的帧。IDR帧不允许后面PB参考前面的帧。IDR的核心作用是为了序列出现重大错误后重新同步,不用参考IDR之前的图像的数据来解码

1.3 NLU

视频流至少发从一帧SPS和一帧PPS来告诉客户端视频流信息

H.264原始码流(裸流)是由⼀个接⼀个NALU组成。它的功能分为两层,VCL (视频编码层) 和
NAL (⽹络提取层)。VCL:负责压缩视频;NAL:把VCL压缩的视频封装成NLU帧

1、NLU帧包括三个部分

[StartCode] [NALU Header] [NALU Payload]

StartCode必须是 "00 00 00 01" 或 "00 00 01"

NALU Header是NALU的头部

RBSP是I、P、B帧的数据。

NLU帧的结束也是根据00 00 00 01或00 00 01来判断的

3字节的0x000001只有⼀种场合下使⽤,就是⼀个完整的帧被编为多个slice(⽚)的时
候,包含这些sliceNALU 使⽤3字节起始码。其余场合都是4字节0x00000001的。前面的I帧就是分别存储在两个NALU中,这两个NALU的开头就是00 00 01

2、NLU Header第一个字节

其中:
T为负荷数据类型,占5bit
nal_unit_type:这个NALU单元的类型,112H.264使⽤,2431H.264以外的应⽤
使⽤
R为重要性指示位,占2bit
nal_ref_idc.:取00~11,似乎指示这个NALU的重要性,00NALU解码器可以丢弃它⽽不
影响图像的回放,03,取值越⼤,表示当前NAL越重要,需要优先受到保护。如果当前
NAL是属于参考帧的⽚,或是序列参数集,或是图像参数集这些重要的单位时,本句法元
素必需⼤于0
最后的F为禁⽌位,占1bit
forbidden_zero_bit: 在 H.264 规范中规定了这⼀位必须为 0.

3、NLU的类型

0x00 00 00 01 67
67
⼆进制:0110 0111   
00111 = 7(⼗进制)
nal_unit_typeNAL单元和RBSP语法结构的内容
0未指定
1一个非IDR图像的编码条带slice_layer_without_partitioning_rbsp( )
2
编码条带数据分割块A slice_data_partition_a_layer_rbsp( )
3
编码条带数据分割块B slice_data_partition_b_layer_rbsp( )
4
编码条带数据分割块C slice_data_partition_c_layer_rbsp( )
5
IDR图像的编码条带() slice_layer_without_partitioning_rbsp ( )
6
辅助增强信息 (SEI) sei_rbsp( )
7
序列参数集 seq_parameter_set_rbsp( )
8
图像参数集 pic_parameter_set_rbsp( )
9
访问单元分隔符 access_unit_delimiter_rbsp( )
10
序列结尾 end_of_seq_rbsp( )
11
流结尾  end_of_stream_rbsp( )
12
填充数据 filler_data_rbsp( )
13
序列参数集扩展9 seq_parameter_set_extension_rbsp( )
14...18
保留
19
未分割的辅助编码图像的编码条带 slice_layer_without_partitioning_rbsp( )
20...23
保留
24...31
未指定

1.4 H264 annexb模式

H264有两种封装

⼀种是Annex B模式,传统模式,有startcodeSPSPPS是在ES
⼀种是mp4模式,⼀般mp4 mkv都是mp4模式,没有startcodeSPSPPS以及其它信息
被封装在container中,每⼀个frame前⾯4个字节是这个frame的⻓度。很多解码器只⽀持Annex B这种模式,因此需要将mp4做转换:ffmpeg中⽤ h264_mp4toannexb_filter可以做转换
实现:
const AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb");
AVBSFContext *bsf_ctx = NULL;
// 2 初始化过滤器上下⽂
av_bsf_alloc(bsfilter, &bsf_ctx); //AVBSFContext;
// 3 添加解码器属性
avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codecpar);
av_bsf_init(bsf_ctx);

1. Annex B内部数据,对应的了前面讲解的内容

[4字节起始码] + [SPS NALU数据] 
[4字节起始码] + [PPS NALU数据] 
[3字节起始码] + [I帧NALU数据] 
[3字节起始码] + [P帧NALU数据] 
[3字节起始码] + [B帧NALU数据] 
...(后续NALU以此类推)

输出的文件是H.264视频文件

2. MP4直接的码流对应下图右边,开头记录的是NALU帧的长度,都是4字节

二、MP4->H.264代码

#include <iostream>extern "C"{#include <libavutil/log.h>#include <libavformat/avio.h>#include <libavformat/avformat.h>#include <libavcodec/bsf.h> 
}using namespace std;static char err_buf[128] = {0};
static char* av_get_err(int errnum)
{av_strerror(errnum, err_buf, 128);return err_buf;
}int main(int argc, char **argv) {string inputFile = "believe.mp4";string outputFile = "believe.h264"; FILE * outfp = fopen(outputFile.c_str(),"wb");printf("in:%s out:%s\n", inputFile.c_str(), outputFile.c_str());// 创建AVFormatContext上下文AVFormatContext * ifmt_ctx = avformat_alloc_context();if (!ifmt_ctx) {printf("[error] Could not allocate context.\n");return -1;}int ret = avformat_open_input(&ifmt_ctx, inputFile.c_str(), NULL, NULL);if (ret != 0) {printf("[error] avformat_open_input: %s\n", av_get_err(ret));return -1;}ret = avformat_find_stream_info(ifmt_ctx, NULL);if (ret < 0) {printf("[error] avformat_find_stream_info: %s\n", av_get_err(ret));avformat_close_input(&ifmt_ctx);return -1;}// 查找出哪个码流是video/audio/subtitlesint videoindex = -1;videoindex = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);if(videoindex == -1) {printf("[error] Didn't find a video stream.\n");avformat_close_input(&ifmt_ctx);return -1;}// 创建AVPacket包AVPacket * pkt = av_packet_alloc();av_init_packet(pkt);// 1 获取一个名为"h264_mp4toannexb"的比特流过滤器// 用于将MP4容器中的H.264视频流转换为Annex B格式的H.264流const AVBitStreamFilter * bsfilter = av_bsf_get_by_name("h264_mp4toannexb");AVBSFContext * bsf_ctx = NULL;// 2 初始化过滤器上下文av_bsf_alloc(bsfilter, &bsf_ctx); //AVBSFContext;// 3 复制视频流的编解码参数到过滤器上下文avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codecpar);av_bsf_init(bsf_ctx);int file_end = 0;while (0 == file_end) {if((ret = av_read_frame(ifmt_ctx, pkt)) < 0) {// 没有更多包可读file_end = 1;printf("read file end: ret:%d\n", ret);}if(ret == 0 && pkt->stream_index == videoindex) {int input_size = pkt->size;int out_pkt_count = 0;if (av_bsf_send_packet(bsf_ctx, pkt) != 0) // bitstreamfilter内部去维护内存空间{av_packet_unref(pkt);   // 你不用了就把资源释放掉continue;       // 继续送}av_packet_unref(pkt);   // 释放资源while(av_bsf_receive_packet(bsf_ctx, pkt) == 0) {out_pkt_count++;// printf("fwrite size:%d\n", pkt->size);size_t size = fwrite(pkt->data, 1, pkt->size, outfp);if(size != pkt->size){printf("fwrite failed-> write:%u, pkt_size:%u\n", size, pkt->size);}av_packet_unref(pkt);}if(out_pkt_count >= 2){printf("cur pkt(size:%d) only get 1 out pkt, it get %d pkts\n", input_size, out_pkt_count);}// 注释掉前面代码,可以直接保存mp4流// size_t size = fwrite(pkt->data, 1, pkt->size, outfp);// if(size != pkt->size)// {//     printf("fwrite failed-> write:%u, pkt_size:%u\n", size, pkt->size);// }// av_packet_unref(pkt);}else {if(ret == 0) av_packet_unref(pkt); // 释放内存}}if (outfp) fclose(outfp);if (bsf_ctx) av_bsf_free(&bsf_ctx);if (pkt) av_packet_free(&pkt);if (ifmt_ctx) avformat_close_input(&ifmt_ctx);printf("finish\n");return 0;
}

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

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

相关文章

Unity 解决天空盒中间出现一条线

问题解决找到天空盒对应贴图&#xff0c;在Inspector 面板中找到Advanced →Generate Mip Maps 并取消勾选即可。效果动态修改天空盒RenderSettings.skybox targetSkyboxMaterial; DynamicGI.UpdateEnvironment();

Python爬虫实战:研究Showcase模块,构建电商平台销售数据采集和分析系统

1. 引言 1.1 研究背景 在数字经济快速发展的今天,电商平台积累了海量的商品信息、交易数据和用户反馈,这些数据蕴含着丰富的市场洞察。根据中国电子商务研究中心数据,2024 年我国网络零售市场规模突破 15 万亿元,平台商品数据呈现指数级增长。如何高效提取这些数据并转化…

C++中的Reactor和Proactor模型进行系统性解析

<摘要> 本解析系统阐述了网络编程中Reactor与Proactor两种高性能I/O模型的核心概念。Reactor基于同步I/O多路复用&#xff0c;通过事件循环分发通知&#xff0c;由应用层自行完成I/O操作&#xff1b;而Proactor则基于异步I/O&#xff0c;由操作系统完成I/O操作后主动回调…

【技术教程】如何将文档编辑器集成至基于Node.js的网页应用程序中

当今数字化时代&#xff0c;Web应用对在线文档编辑的需求日益增长。无论是构建在线办公系统、内容管理平台还是协作工具&#xff0c;让用户能够直接在浏览器中编辑和处理文档已成为基本需求。 想知道如何为你的 Node.js 应用添加强大的在线文档编辑功能吗&#xff1f;本文手把…

[论文阅读] 人工智能 + 软件工程 | 别让AI写的代码带“漏洞”!无触发投毒攻击的防御困境与启示

别让AI写的代码带“漏洞”&#xff01;无触发投毒攻击的防御困境与启示 论文信息 原标题&#xff1a;Evaluating Defenses Against Trigger-Free Data Poisoning Attacks on NL-to-Code Models&#xff08;评估NL-to-Code模型应对无触发数据投毒攻击的防御方法&#xff09;主要…

【Windows】通过 runas 命令实现多用户权限测试的完整流程

▒ 目录 ▒&#x1f6eb; 导读需求1️⃣ 前期准备&#xff1a;创建管理员/普通测试用户1.1 创建普通用户Test&#xff08;无管理员权限&#xff09;1.2 创建管理员用户Admin&#xff08;含管理员权限&#xff09;2️⃣ 核心操作&#xff1a;通过runas命令切换用户命令行环境2.1…

新后端漏洞(上)- H2 Database Console 未授权访问

漏洞介绍&#xff1a; H2 database是一款Java内存数据库&#xff0c;多用于单元测试。 H2 database自带一个Web管理页面&#xff0c;在Spirng开发中&#xff0c;如果我们设置如下选项&#xff0c;即可允许外部用户访问Web管理页面&#xff0c;且没有鉴权&#xff1a; spring.h2…

2025-09-04 HTML3——区块布局与表单

文章目录1 块元素与行内元素1.1 块元素 (Block-level Element)1.2 行内元素 (Inline Element)2 HTML 布局2.1 使用 <div> 元素2.2 使用 <table> 元素3 表单 (<form>)3.1 输入域&#xff08;<input>&#xff09;3.1.1 文本域&#xff08;Text Fields&am…

云数据库服务(参考自腾讯云计算工程师认证课程)更新中......

数据库基础介绍面临的挑战&#xff1a;数据库系统架构&#xff1a; 数据库DB、数据库管理系统DBMS&#xff08;负责数据库的搭建、使用和维护的系统软件&#xff0c;通过组织、索引、查询、修改数据库文件、实现数据定义、组织、存储、管理以及数据库操作、运行和维护等主要功能…

源滚滚AI编程SillyTavern酒馆配置Claude Code API教程

什么是酒馆 SillyTavern&#xff08;简称 ST&#xff09;是一款本地安装的用户界面&#xff0c;让你能够与文本生成大模型&#xff08;LLM&#xff09;、图像生成引擎以及语音合成&#xff08;TTS&#xff09;模型进行交互。我们的目标是尽可能赋予用户对 LLM 提示词的最大掌控…

软件设计师——软件工程学习笔记

软件工程 一、软件工程基础知识 1. 软件的生存周期&#xff08;1&#xff09;可行性分析与项目开发计划。这个阶段主要确定软件的开发目标及其可行性。参与该阶段的人员有用户、项目负责人、系统分析师。产生的文档有 可行性分析报告、项目开发计划。 &#xff08;2&#xff09…

阿里云ecs 2h2g 实际可用内存不足的情况

Kdump是Linux系统的一种内核崩溃转储机制&#xff0c;它允许在系统发生内核崩溃&#xff08;例如内核panic&#xff09;时&#xff0c;捕获内存的转储信息&#xff0c;从而帮助事后分析故障原因。该过程需要一块预留内存&#xff08;称为crashkernel内存&#xff09;&#xff0…

MySQL抛出的Public Key Retrieval is not allowed

有时候在连接实例的时候会遇到这样的报错Public Key Retrieval is not allowed问题分析这是因为账号使用了sha256_password或者caching_sha2_password 密码插件而sha256_password或者caching_sha2_password 插件为了加快认证过程&#xff0c;在服务端维护了一个密码哈希缓存。当…

ICP可能有用的

可以训练GICP WGICP: Differentiable Weighted GICP-Based Lidar Odometry | GAMMA CT ICP (99 封私信 / 80 条消息) KITTI里程计排行榜上第五&#xff01;CT-ICP&#xff1a;实时弹性激光雷达里程计与回环检测 - 知乎 Faster GICP github.com

nextcyber——Shells和Payloads

Shells和Payloads Shell的基础知识 正向Shells Tom可以在一个Linux目标上发出nc -lvnp 443的命令。他需要从他的攻击机连接到哪个端口&#xff0c;才能成功建立一个shell会话&#xff1f; 443SSH到目标&#xff0c;创建一个bind shell&#xff0c;然后用netcat连接到目标&a…

笔记:现代操作系统:原理与实现(2)

第三章 操作系统结构 操作系统的机制与策略 操作系统乃至计算机系统中控制复杂度的—个重要设计原则是:将策略与机制相分离&#xff0c;其中策略&#xff08;policy&#xff09;表示要‘‘做什么”&#xff0c;机制&#xff08;mechanjsm&#xff09;表示该“如何做”。 操作系…

c++ 压缩与解压缩

1、使用zip开源库&#xff0c;引入比较简单&#xff0c;只需要包含四个头文件&#xff0c;不需要编译成库文件&#xff1a;zip.h、zip.cpp、unzip.h、unzip.cpp。2、压缩使用到的主要函数&#xff1a;CreateZip 创建zip文件ZipAdd 添加文件ZipAddFolder 添加文件夹CloseZip 关闭…

水下无线光通信(UWOC)TDD系统:光收发端编解码与信号处理分析与方案(数字版)

在光收发模块中添加编解码与信号处理模块,核心目标是提升水下信道抗干扰能力(对抗后向散射、环境光、信号衰减)、降低误码率,同时兼容原有TDD时隙控制逻辑。以下从“编码方案选型”“光发送端信号处理”“光接收端信号处理”“与原有系统集成”四部分展开,形成完整技术闭环…

Seat 事务@GlobalTransactional传播行为

一&#xff0c;分布式事务传播行为调用链描述一个普通事务注解的方法&#xff0c;调用一个分布式事务注解方法分布式事务注解方法&#xff1a;包含一个本地更新&#xff0c;和两个外部服务更新操作&#xff0c;涉及三个服务问题1&#xff0c;普通事务注解方法&#xff0c;在全局…

美团龙猫利用expat库实现的保存xml指定范围数据到csv的C程序

用自己代码逐个字符解析的速度较慢&#xff0c;尝试了libxml2也比较慢&#xff0c;它需要一次性读入内存&#xff0c;而expat库支持流式读取。就让龙猫写了一个程序&#xff0c;毕竟是久经考验的库&#xff0c;程序很快就调试通过了。要不是我一开始没信心&#xff0c;让他先输…