音视频-H264编码封装- MP4格式转Annex B格式

目录

1:H264语法结构回顾

2:H264编码补充介绍

3:MP4模式转Annex B模式输出到文件示例


1:H264语法结构回顾

在之前文章里介绍过H264的语法结构。

传送门: 视音频-H264 编码NALU语法结构简介 

2:H264编码补充介绍

   H.264视频编码标准中两种常见的封装方式:annexb模式和mp4模式。

  1. annexb模式

    • 这是传统的封装模式,其中每个视频帧的数据(NALUnit)在传输时以0x000001或0x0000001作为分隔符。
    • SPS(Sequence Parameter Set)和PPS(Picture Parameter Set)等关键信息通常会周期性地在视频流内部重复,特别是在关键帧(I帧)之前。
    • 这种模式下,视频帧的数据相对独立,不依赖于容器格式。
  2. mp4模式

    • 在这种模式下,SPS、PPS和其他相关信息被封装到了容器(如MP4、MKV)中,而不是直接在视频流内部传输。
    • 每个视频帧之前通常有一个4字节的长度字段,用于指示下一个视频帧的长度。
    • 在这种模式下,视频帧的数据是按照容器格式进行封装和传输的。

因为一些解码器只支持annexb模式,所以有时候需要将mp4格式的视频数据转换为annexb模式。在FFmpeg中,可以使用h264_mp4toannexb_filter过滤器来进行这种转换。

实现大概流程如下:

3:MP4模式转Annex B模式输出到文件示例

(填充sps pps 到H264头部信息 并输出H264文件)

        这段代码的主要功能是从MP4文件中提取H264视频流,使用bitstream过滤器将H264从MP4格式转换为AnnexB格式,并将转换后的数据写入到一个新的文件中。代码使用了FFmpeg库中的函数来处理媒体文件和Packet。程序首先查找输入媒体文件中的视频流,然后读取每个Packet,如果Packet属于视频流,则使用bitstream过滤器进行处理,并将处理后的数据包写入到输出文件中。如果出错或到达文件末尾,则退出循环并释放所有资源。

#include <stdio.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/log.h>// 定义一个全局的缓冲区,用于存储错误信息
static char err_buff[128] = {0};// 函数:获取错误信息
// 参数:errnum - 错误码
// 返回值:指向错误信息字符串的指针
static char* av_get_error(int errnum)
{// 使用av_strerror函数将错误码转换为可读的错误信息,并存储在err_buff中av_strerror(errnum, err_buff, 128);return err_buff;
}int main(int argc, char **argv)
{// 定义FFmpeg的格式上下文,用于存储输入文件的多媒体流信息AVFormatContext *ifmt_ctx = NULL;// 存储视频流的索引int             videoindex = -1;// 定义AVPacket,用于存储编解码数据包AVPacket        *pkt = NULL;// 用于存储函数调用的返回值int             ret = -1;// 标记文件是否读取结束int             file_end = 0;// 检查命令行参数数量,至少需要输入文件和输出文件两个参数if(argc < 3){printf("usage: %s input outfile\n", argv[0]);return -1;}// 打开输出文件FILE *outfp=fopen(argv[2],"wb");printf("in:%s out:%s\n", argv[1], argv[2]);// 分配格式上下文ifmt_ctx = avformat_alloc_context();if (!ifmt_ctx){printf("Could not allocate context.\n");return -1;}// 打开输入文件,准备读取多媒体流ret = avformat_open_input(&ifmt_ctx,argv[1], NULL, NULL);if(ret != 0){printf("avformat_open_input: %s\n", av_get_error(ret));return -1;}// 扫描文件,直到找到所有流的信息ret = avformat_find_stream_info(ifmt_ctx, NULL);if(ret < 0){printf("avformat_find_stream_info: %s\n", av_get_error(ret));avformat_close_input(&ifmt_ctx);return -1;}// 查找最佳的视频流videoindex = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);if(videoindex == -1){avformat_close_input(&ifmt_ctx);return -1;}// 分配一个AVPacketpkt = av_packet_alloc();av_init_packet(pkt);// 获取H.264 MP4到AnnexB比特流过滤器const AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb");// 分配一个比特流过滤器上下文AVBSFContext *bsf_ctx = NULL;av_bsf_alloc(bsfilter, &bsf_ctx);// 将视频流的编解码参数复制到过滤器的输入参数中avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codecpar);// 初始化比特流过滤器av_bsf_init(bsf_ctx);// 循环读取数据包,直到文件结束file_end = 0;while (0 == file_end){// 从格式上下文中读取一个数据包if((ret = av_read_frame(ifmt_ctx, pkt)) < 0){// 如果没有更多的数据包,则标记文件结束file_end = 1;printf("read 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){av_packet_unref(pkt);continue;}av_packet_unref(pkt); // 释放pkt,因为过滤器会使用它// 从过滤器接收转换后的数据包,并写入输出文件while(av_bsf_receive_packet(bsf_ctx, pkt) == 0){out_pkt_count++;// 将数据包的内容写入输出文件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("curent pkt(size:%d), only get 1 out pkt, get %d pkts\n",input_size, out_pkt_count);}}else{// 如果读取到的数据包不是视频流,则释放它if(ret == 0)av_packet_unref(pkt);}}// 关闭输出文件if(outfp)fclose(outfp);// 释放比特流过滤器上下文if(bsf_ctx)av_bsf_free(&bsf_ctx);// 释放AVPacketif(pkt)av_packet_free(&pkt);// 关闭输入的格式上下文if(ifmt_ctx)avformat_close_input(&ifmt_ctx);// 打印完成信息printf("finish\n");return 0;
}

相关函数如下:

  1. av_bsf_get_by_name("h264_mp4toannexb")

    • 功能:获取指定名称的比特流过滤器。
    • 参数:比特流过滤器的名称。
    • 返回值:指向 AVBitStreamFilter 结构的指针,如果找不到指定名称的过滤器,则返回 NULL。
  2. av_bsf_alloc(bsfilter, &bsf_ctx)

    • 功能:为指定的比特流过滤器分配上下文内存。
    • 参数:
      • bsfilter:要分配上下文的比特流过滤器。
      • bsf_ctx:用于存储分配的过滤器上下文的指针。
    • 返回值:成功返回 0,失败返回负值错误代码。
  3. avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codecpar)

    • 功能:复制给定的编解码器参数到过滤器上下文的输入参数中。
    • 参数:
      • bsf_ctx->par_in:过滤器上下文的输入参数。
      • ifmt_ctx->streams[videoindex]->codecpar:要复制的编解码器参数。
    • 返回值:无。
  4. av_bsf_init(bsf_ctx)

    • 功能:初始化指定的比特流过滤器上下文。
    • 参数:要初始化的过滤器上下文。
    • 返回值:成功返回 0,失败返回负值错误代码。
  5. av_bsf_send_packet(bsf_ctx, pkt)

    • 功能:发送数据包给比特流过滤器进行处理。
    • 参数:
      • bsf_ctx:要发送数据包的比特流过滤器上下文。
      • pkt:要发送的数据包。
    • 返回值:成功返回 0,表示数据包被成功发送给过滤器;否则返回负值错误代码。
  6. av_bsf_receive_packet(bsf_ctx, pkt)

    • 功能:从比特流过滤器接收处理后的数据包。
    • 参数:
      • bsf_ctx:要从中接收数据包的比特流过滤器上下文。
      • pkt:用于存储接收到的数据包。
    • 返回值:成功返回 0,表示成功接收到数据包;否则返回负值错误代码。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

紫光展锐先进技术科普 | 工业互联网遇到5G,1+1>2?

随着工厂自动化的加速普及&#xff0c;如今我们可能经常看到这样的场景&#xff1a;在高温、潮湿、粉尘、腐蚀等恶劣环境作业场景&#xff0c;巡检机器人穿梭其中&#xff0c;工人们不必弯腰去搬沉重又危险的器件&#xff0c;而旁边会有一个个机械臂帮手平稳有序地完成好所有搬…

flutter开发实战-JSON和序列化数据

flutter开发实战-JSON和序列化数据 大多数移动应用都需要与 web 服务器通信&#xff0c;同时在某些时候轻松地存储结构化数据。当创造需要网络连接的应用时&#xff0c;它迟早需要处理一些常见的 JSON。使用Json时候&#xff0c;可以使用json_serializable 一、引入json_anno…

企智汇项目管理软件有哪些优势?

一款非常好用、高效的软件——企智汇软件有哪些优势呢&#xff1f; 首先&#xff0c;我们来看看它的界面设计。企智汇软件界面简洁直观&#xff0c;用户可以轻松地使用各种功能&#xff0c;不需要学习复杂的操作流程。而且&#xff0c;软件还提供了多种配色方案和主题&#xf…

代码随想录Day 47|Leetcode|Python|392.判断子序列 ● 115.不同的子序列

392.判断子序列 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;"ace"是"abcde"的…

vuerouter声明式导航

声明式导航-跳转传参数 1.查询参数传参 语法&#xff1a;to /path?参数名值 2.对应页面组件接受传来的值 $router.query.参数名 2.动态路由传参 1.配置动态路由 2.配置导航连接 to/path/参数值 3.对应页面组件接收传递过来的值 #route.params.参数名 多个参数传递&…

IPSSL证书:为特定IP地址通信数据保驾护航

IPSSL证书&#xff0c;顾名思义&#xff0c;是专为特定IP地址设计的SSL证书。它不仅继承了传统SSL证书验证网站身份、加密数据传输的基本功能&#xff0c;还特别针对通过固定IP地址进行通信的场景提供了强化的安全保障。在IP地址直接绑定SSL证书的模式下&#xff0c;它能够确保…

互联网轻量级框架整合之装配Bean

依赖注入和依赖查找 应该说IoC的工作方式有两种&#xff0c;一种是依赖查找&#xff0c;通过资源定位&#xff0c;把对应的资源查找出来&#xff0c;例如通过JNDI找到数据源&#xff0c;依赖查找被广泛使用在第三方的资源注入上&#xff0c;比如在Web项目中&#xff0c;数据源往…

python创建新环境并安装pytorch

python创建新环境并安装pytorch 一、创建新环境1、准备工作2、创建虚拟环境并命名3、激活虚拟环境 二、安装pytorch1、pytorch官网2、选择与你的系统相对应的版本3、安装成功 一、创建新环境 1、准备工作 本次创建的环境是在anaconda环境下&#xff0c;否则需要在纯净环境下创…

SpringBoot 使用logback(多环境配置)

Logback是由log4j创始人设计的又一个开源日志组件。可用于项目日志功能。官网地址 第1步&#xff1a;添加坐标依赖 <!--logback--> <dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version…

[数据结构]红黑树的原理及其实现

文章目录 红黑树的特性红黑树的时间复杂度推导&#xff1a;结论红黑树与AVL树比较 红黑树的插入红黑树的节点定义调整策略思考情况2&#xff1a;思考情况3&#xff1a; 代码实现myBTRee.htest.cpp 红黑树的特性 红黑树最常用的平衡二叉搜索树。跟AVL树不同的是&#xff0c;红黑…

Python学习之路 | Python基础语法(一)

数据类型 Python3 中常见的数据类型有&#xff1a; Number&#xff08;数字&#xff09;String&#xff08;字符串&#xff09;bool&#xff08;布尔类型&#xff09;List&#xff08;列表&#xff09;Tuple&#xff08;元组&#xff09;Set&#xff08;集合&#xff09;Dict…

uniapp使用地图开发app, renderjs使用方法及注意事项

上次提到uniapp开发地图app时得一些问题&#xff0c;最后提到使用renderjs实现app中使用任何地图&#xff08;下面将以腾讯地图为例&#xff0c;uniapp中写app时推荐使用得是高德地图&#xff0c;无法使用腾讯地图&#xff08;renderjs方式除外&#xff09;&#xff09;。 1、…

力扣HOT100 - 279. 完全平方数

解题思路&#xff1a; 动态规划 class Solution {public int numSquares(int n) {int[] dp new int[n 1];// 初始化dp数组&#xff0c;默认最坏情况是每个数都是由1相加得到的for (int i 1; i < n; i) {dp[i] i;}for (int i 1; i < n; i) {for (int j 1; j * j &…

【案例教程】土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测

查看原文>>>土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测 土地利用/土地覆盖数据是生态、环境和气象等领域众多模型的重要输入参数之一。基于遥感影像解译&#xff0c;可获取历史或当前任何一个区域的土地利用/土地覆盖数据&#xff0c;用于评估区域的生…

【挑战全网】最全高德地图充电桩接入指南,流量必火!

分享《一套免费开源充电桩物联网系统&#xff0c;是可以立马拿去商用的&#xff01;》 一、和高德直接互联互通的优势&#xff1a; 1、高德官方直接互联互通&#xff0c;提供给合作商户独立发展自主权&#xff0c;不依赖任何第三方平台; 2、自己控制电站的上线、下线、修改电…

Pytorch代码基础—张量

Pytorch代码—张量 Pytorch张量 张量的属性&#xff1a; data&#xff1a;被包装的Tensorgrad&#xff1a;data的梯度grad_fn:创建Tensor的Function&#xff0c;是自动求导的关键requires_grad&#xff1a;指示是否需要梯度isleaf&#xff1a;指示是否是叶子结点&#xff0…

多维 HighChart

showHighChart.html <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><!-- js脚本都是官方的,后两个是highchart脚本 --><script type"text/javascript" src"jquery1.7.1.min.js"&g…

麒麟 V10 安装docker2

1. 查看系统版本 2.安装docker-ce 添加源 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 安装docker yum install docker-ce --allowerasing 重启docker systemctl start docker 3.安装nvidia-container-runtime 添…

Spring初学入门(跟学笔记)

一、Spring概述 Spring是一款主流的Java EE轻量级开源框架。 Spring的核心模块&#xff1a;IoC&#xff08;控制反转&#xff0c;指把创建对象过程交给Spring管理 &#xff09;、AOP&#xff08;面向切面编程&#xff0c;在不修改源代码的基础上增强代码功能&#xff09; 二、…

MT2057 门票

思路&#xff1a; 此题是求有多少个区间的平均值>t&#xff0c; 那么可以把每个值-t。如果新的数列的某个区间的和>0&#xff0c;那么说明这个区间满足条件。 令新数列的前缀和为b[i]&#xff0c;所以求[i, j]区间是否满足条件&#xff0c;即求b[j]-b[i-1]是否>0&am…