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

ffmpeg解封装解码

文章目录

  • 封装和解封装
    • 封装
    • 解封装
  • 相关接口
    • 解封装的流程图
    • 关于AVPacket的解释
    • 如何区分不同的码流,视频流,音频流?
      • 第一种方式av_find_best_stream
      • 第二种方式 通过遍历流
    • 代码

封装和解封装

封装

是把音频流 ,视频流,字幕流,其他成分 按照一定的规则组合程一个视频文件(mp4/ flv)的

解封装

流程和封装完全相反 是把一个视频文件的音频流,视频流,字幕流,其他成分给分离出来。

相关接口

◼ avformat_alloc_context();负责申请一个AVFormatContext
结构的内存,并进行简单初始化 AVFormatContext是描述一个媒体文件或媒体流的构成和基本信息的结构体

-注意:这个接口 也不是必须调用的 因为在avformat_open_input()的的时候 传入第一个参数 ,如果检测为空的化,这个函数内部会自动进行检测和分配相关的内存
在这里插入图片描述

◼ avformat_free_context();释放该结构里的所有东西以及该结构本身
◼ avformat_close_input();关闭解复用器。关闭后就不再需要使用avformat_free_context 进行释放。
◼ avformat_open_input();打开输入视频文件
◼ avformat_find_stream_info():获取视频文件信息
◼ av_read_frame(); 读取音视频包
◼ avformat_seek_file(); 定位文件
◼ av_seek_frame():定位文件

解封装的流程图

在这里插入图片描述

关于AVPacket的解释

FFMpeg AVPacket 之理解与掌握
这里的讲解是比较好的
总结来说 ,就是用来装一帧数据流的包 ,包里面有包头和包体,
av_packet_alloc()是分配一个包结构
这里的使用是 av_read_frame() 来记录一帧,并进行输出 ,有一点需要注意的是 ,在读取新的帧的时候 要调用av_packet_unref去释放相关的包结构,避免相关包在释放的时候 查看到引用不为0而不去释放,导致的未知的错误事件发生
并且在最后不用的时候 要调用av_packet_free 去释放掉对应的空间
av_packet_ref 可以让一个包去引用另外一个包的内容
注意不能通过赋值直接去引用,这样两者指向的是 同一个包头 ,这样包头释放的时候 会导致两个指针的失效.

如何区分不同的码流,视频流,音频流?

第一种方式av_find_best_stream

在这里插入图片描述
通过接口
举例 获取视频流
video_index = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,-1,-1, NULL, 0)
获取音频流
audio_index = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,-1,-1, NULL, 0)
可选参数
在这里插入图片描述

第二种方式 通过遍历流

下面AVFormatContext里面有相关流的数量
通过 遍历 streams里面的数据 去获取对应的流
in_stream->codecpar->codec_type 可以表示对应的流
在这里插入图片描述
下面有代码演示具体的用法
注意点:
avformat_open_input和avformat_find_stream_info分别用于打 开一个流和分析流信息。 在初始信息不足的情况下(比如FLV和H264文件), avformat_find_stream_info接口需要在内部调用 read_frame_internal接口读取流数据(音视频帧),然后再分 析后,设置核心数据结构AVFormatContext。 由于需要读取数据包,avformat_find_stream_info接口会带来 很大的延迟。

代码

#include <libavformat/avformat.h>
#include <stdio.h>int main(int argc, char **argv) {// 打开网络流。这里如果只需要读取本地媒体文件,不需要用到网络功能,可以不用加上这一句//     avformat_network_init();const char *default_filename = "believe.mp4";char *in_filename = NULL;if (argv[ 1 ] == NULL) {in_filename = default_filename;} else {in_filename = argv[ 1 ];}printf("in_filename = %s\n", in_filename);// AVFormatContext是描述一个媒体文件或媒体流的构成和基本信息的结构体AVFormatContext *ifmt_ctx = NULL; // 输入文件的demuxint videoindex = -1; // 视频索引int audioindex = -1; // 音频索引// 打开文件,主要是探测协议类型,如果是网络文件则创建网络链接int ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL);if (ret < 0) // 如果打开媒体文件失败,打印失败原因{char buf[ 1024 ] = {0};av_strerror(ret, buf, sizeof(buf) - 1);printf("open %s failed:%s\n", in_filename, buf);goto failed;}// 读取媒体文件的数据包以获取流的信息ret = avformat_find_stream_info(ifmt_ctx, NULL);if (ret < 0) // 如果打开媒体文件失败,打印失败原因{char buf[ 1024 ] = {0};av_strerror(ret, buf, sizeof(buf) - 1);printf("avformat_find_stream_info %s failed:%s\n", in_filename, buf);goto failed;}// 打开媒体文件成功printf_s("\n==== av_dump_format in_filename:%s ===\n", in_filename);av_dump_format(ifmt_ctx, 0, in_filename, 0);printf_s("\n==== av_dump_format finish =======\n\n");// url: 调用avformat_open_input读取到的媒体文件的路径/名字printf("media name:%s\n", ifmt_ctx->url);// nb_streams: nb_streams媒体流数量printf("stream number:%d\n", ifmt_ctx->nb_streams);// bit_rate: 媒体文件的码率,单位为bpsprintf("media average ratio:%lldkbps\n", ( int64_t )(ifmt_ctx->bit_rate / 1024));// 时间int total_seconds, hour, minute, second;// duration: 媒体文件时长,单位微妙total_seconds = (ifmt_ctx->duration) / AV_TIME_BASE; // 1000us = 1ms, 1000ms = 1秒hour = total_seconds / 3600;minute = (total_seconds % 3600) / 60;second = (total_seconds % 60);// 通过上述运算,可以得到媒体文件的总时长printf("total duration: %02d:%02d:%02d\n", hour, minute, second);printf("\n");/** 老版本通过遍历的方式读取媒体文件视频和音频的信息* 新版本的FFmpeg新增加了函数av_find_best_stream,也可以取得同样的效果*/for (uint32_t i = 0; i < ifmt_ctx->nb_streams; i++) {AVStream *in_stream = ifmt_ctx->streams[ i ]; // 音频流、视频流、字幕流// 如果是音频流,则打印音频的信息if (AVMEDIA_TYPE_AUDIO == in_stream->codecpar->codec_type) {printf("----- Audio info:\n");// index: 每个流成分在ffmpeg解复用分析后都有唯一的index作为标识printf("index:%d\n", in_stream->index);// sample_rate: 音频编解码器的采样率,单位为Hzprintf("samplerate:%dHz\n", in_stream->codecpar->sample_rate);// codecpar->format: 音频采样格式if (AV_SAMPLE_FMT_FLTP == in_stream->codecpar->format) {printf("sampleformat:AV_SAMPLE_FMT_FLTP\n");} else if (AV_SAMPLE_FMT_S16P == in_stream->codecpar->format) {printf("sampleformat:AV_SAMPLE_FMT_S16P\n");}// channels: 音频信道数目printf("channel number:%d\n", in_stream->codecpar->channels);// codec_id: 音频压缩编码格式if (AV_CODEC_ID_AAC == in_stream->codecpar->codec_id) {printf("audio codec:AAC\n");} else if (AV_CODEC_ID_MP3 == in_stream->codecpar->codec_id) {printf("audio codec:MP3\n");} else {printf("audio codec_id:%d\n", in_stream->codecpar->codec_id);}// 音频总时长,单位为秒。注意如果把单位放大为毫秒或者微妙,音频总时长跟视频总时长不一定相等的if (in_stream->duration != AV_NOPTS_VALUE) {int duration_audio = (in_stream->duration) * av_q2d(in_stream->time_base);// 将音频总时长转换为时分秒的格式打印到控制台上printf("audio duration: %02d:%02d:%02d\n",duration_audio / 3600, (duration_audio % 3600) / 60, (duration_audio % 60));} else {printf("audio duration unknown");}printf("\n");audioindex = i; // 获取音频的索引} else if (AVMEDIA_TYPE_VIDEO == in_stream->codecpar->codec_type) // 如果是视频流,则打印视频的信息{printf("----- Video info:\n");printf("index:%d\n", in_stream->index);// avg_frame_rate: 视频帧率,单位为fps,表示每秒出现多少帧printf("fps:%lffps\n", av_q2d(in_stream->avg_frame_rate));if (AV_CODEC_ID_MPEG4 == in_stream->codecpar->codec_id) // 视频压缩编码格式{printf("video codec:MPEG4\n");} else if (AV_CODEC_ID_H264 == in_stream->codecpar->codec_id) // 视频压缩编码格式{printf("video codec:H264\n");} else {printf("video codec_id:%d\n", in_stream->codecpar->codec_id);}// 视频帧宽度和帧高度printf("width:%d height:%d\n", in_stream->codecpar->width,in_stream->codecpar->height);// 视频总时长,单位为秒。注意如果把单位放大为毫秒或者微妙,音频总时长跟视频总时长不一定相等的if (in_stream->duration != AV_NOPTS_VALUE) {int duration_video = (in_stream->duration) * av_q2d(in_stream->time_base);printf("video duration: %02d:%02d:%02d\n",duration_video / 3600,(duration_video % 3600) / 60,(duration_video % 60)); // 将视频总时长转换为时分秒的格式打印到控制台上} else {printf("video duration unknown");}printf("\n");videoindex = i;}}// 解码的packet包 分配一个// 这个相当于一个包 包含包头和包体AVPacket *pkt = av_packet_alloc();int pkt_count = 0;int print_max_count = 10;printf("\n-----av_read_frame start\n");while (1) {// 从流中读取一帧的数据ret = av_read_frame(ifmt_ctx, pkt);if (ret < 0) {printf("av_read_frame end\n");break;}// 这里最大读取10帧的数据if (pkt_count++ < print_max_count) {if (pkt->stream_index == audioindex) {printf("audio pts: %lld\n", pkt->pts);printf("audio dts: %lld\n", pkt->dts);printf("audio size: %d\n", pkt->size);printf("audio pos: %lld\n", pkt->pos);printf("audio duration: %lf\n\n",pkt->duration * av_q2d(ifmt_ctx->streams[ audioindex ]->time_base));} else if (pkt->stream_index == videoindex) {printf("video pts: %lld\n", pkt->pts);printf("video dts: %lld\n", pkt->dts);printf("video size: %d\n", pkt->size);printf("video pos: %lld\n", pkt->pos);printf("video duration: %lf\n\n",pkt->duration * av_q2d(ifmt_ctx->streams[ videoindex ]->time_base));} else {printf("unknown stream_index:\n", pkt->stream_index);}}// 读取的过程就相当于对某一帧的引用 让相关的信息 读取完之后 要调用接口 去取消这个引用// 不能直接去读取新的引用,不然可能会导致内存泄漏的问题 相关的包释放掉之后里面的某些帧的内容还无法释放掉av_packet_unref(pkt);}if (pkt)av_packet_free(&pkt);
failed:if (ifmt_ctx)avformat_close_input(&ifmt_ctx);getchar(); // 加上这一句,防止程序打印完信息马上退出return 0;
}

相关文章:

ffmpeg解封装解码

文章目录 封装和解封装封装解封装 相关接口解封装的流程图关于AVPacket的解释如何区分不同的码流&#xff0c;视频流&#xff0c;音频流&#xff1f;第一种方式av_find_best_stream第二种方式 通过遍历流 代码 封装和解封装 封装 是把音频流 &#xff0c;视频流&#xff0c;字…...

golang学习笔记10-循环结构

注&#xff1a;本人已有C&#xff0c;C,Python基础&#xff0c;只写本人认为的重点。 go的循环只有for循环&#xff0c;但有多个语法&#xff0c;可以实现C/C中的while和do while。当然&#xff0c;for循环也有break和continue&#xff0c;这点和C/C相同。 语法1&#xff1a; f…...

Java高级编程——泛型(泛型类、泛型接口、泛型方法,完成详解,并附有案例+代码)

文章目录 泛型21.1 概述21.2 泛型类21.3 泛型方法21.4 泛型接口 泛型 21.1 概述 JDK5中引入的特性&#xff0c;在编译阶段约束操作的数据类型&#xff0c;并进行检查 泛型格式&#xff1a;<数据类型> 泛型只能支持引用数据类型&#xff0c;如果写基本数据类型需要写对…...

GPU硬件如何实现光栅化?

版权声明 本文为“优梦创客”原创文章&#xff0c;您可以自由转载&#xff0c;但必须加入完整的版权声明文章内容不得删减、修改、演绎本文视频版本&#xff1a;见文末 引言 大家好&#xff0c;我是老雷&#xff0c;今天我想从GPU硬件原理出发&#xff0c;给大家分享在图形渲…...

Python写入文件内容:从入门到精通

在日常编程工作中&#xff0c;我们常常会遇到需要将数据保存至磁盘的需求。无论是日志记录、配置文件管理还是数据持久化&#xff0c;掌握如何有效地使用Python来写入文件内容都是必不可少的一项技能。本文将从基础语法开始&#xff0c;逐步深入探讨Python中写入文件内容的各种…...

相亲交易系统源码详解与开发指南

随着互联网技术的发展&#xff0c;越来越多的传统行业开始寻求线上转型&#xff0c;其中就包括婚恋服务。传统的相亲方式已经不能满足现代人快节奏的生活需求&#xff0c;因此&#xff0c;开发一款基于Web的相亲交易系统显得尤为重要开发者h17711347205。本文将详细介绍如何使用…...

Golang | Leetcode Golang题解之第413题等差数列划分

题目&#xff1a; 题解&#xff1a; func numberOfArithmeticSlices(nums []int) (ans int) {n : len(nums)if n 1 {return}d, t : nums[0]-nums[1], 0// 因为等差数列的长度至少为 3&#xff0c;所以可以从 i2 开始枚举for i : 2; i < n; i {if nums[i-1]-nums[i] d {t}…...

汽车总线之----FlexRay总线

Introduction 随着汽车智能化发展&#xff0c;车辆开发的ECU数量不断增加&#xff0c;人们对汽车系统的各个性能方面提出了更高的需求&#xff0c;比如更多的数据交互&#xff0c;更高的传输带宽等。现如今人们广泛接受电子功能来提高驾驶安全性&#xff0c;像ABS防抱死系统&a…...

前端代替后端做分页操作

如果后端没有分页api&#xff0c;前端如何做分页一、使用computed 这个变量应该是计算之后的值&#xff0c;是一个状态管理变量&#xff0c;跟onMounted类似import {computed} from vue // 定义ref储存rolelist&#xff0c;这里是原始数据 const roleList ref([])// 定义页码…...

L3 逻辑回归

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 在周将使用 LogisticRegression 函数对经典的鸢尾花 (Iris) 数据集进行分类。将详细介绍逻辑回归的数学原理。 1. 逻辑回归的数学原理 逻辑回归是一种线性分…...

Flink系列知识之:Checkpoint原理

Flink系列知识之&#xff1a;Checkpoint原理 在介绍checkpoint的执行流程之前&#xff0c;需要先明白Flink中状态的存储机制&#xff0c;因为状态对于检查点的持续备份至关重要。 State Backends分类 下图显示了Flink中三个内置的状态存储种类。MemoryStateBackend和FsState…...

智算中心动环监控:构建高效、安全的数字基础设施@卓振思众

在当今快速发展的数字经济时代&#xff0c;智算中心作为人工智能和大数据技术的核心支撑设施&#xff0c;正日益成为各行业实现智能化转型的重要基石。为了确保这些高性能计算环境的安全与稳定&#xff0c;卓振思众动环监控应运而生&#xff0c;成为智算中心管理的重要组成部分…...

PyTorch VGG16手写数字识别教程

手写数字识别教程&#xff1a;使用PyTorch和VGG16 1. 环境准备 确保你已安装以下库&#xff1a; pip install torch torchvision2. 导入必要的库 import torch import torch.nn as nn import torch.optim as optim import torchvision.transforms as transforms import tor…...

安卓13删除下拉栏中的设置按钮 android13删除设置按钮

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.编译6.彩蛋1.前言 顶部导航栏下拉可以看到,底部这里有个设置按钮,点击可以进入设备的设置页面,这里我们将更改为删除,不同用户通过这个地方进入设置。也就是下面这个按钮。 2.问题分析…...

FDA辅料数据库在线免费查询-药用辅料

在药物制剂的研制过程中&#xff0c;需要确定这些药用辅料的安全用量。而美国食品药品监督管理局&#xff08;FDA&#xff09;的辅料数据库&#xff08;IID&#xff09;提供了其制剂研发中的关键参考资源&#xff0c;使得更多的医药研发相关人员及企业单位节省试验环节及时间成…...

git pull 报错 refusing to merge unrelated histories

这个对我来说非常常见&#xff0c;因为我都是先由本地项目&#xff0c;再想着传到github上去。 在本地项目中执行 git init git add . git commit -m “xxx” 在github上创建项目&#xff0c;添加了 README.md 文件。 git remote add origin https://github.com/raoxiaoya/x…...

STM32G431RBT6(蓝桥杯)串口(发送)

一、基础配置 (1) PA9和PA10就是串口对应在单片机上的端口 注意&#xff1a;一定要先选择PA9的TX和PA10的RX&#xff0c;再去打开异步的模式 (2) 二、查看单片机的端口连接至电脑的哪里 &#xff08;1&#xff09;此电脑->右击属性 &#xff08;2&#xff09;找到端…...

使用 typed-rest-client 进行 REST API 调用

typed-rest-client 是一个用于 Node.js 的库&#xff0c;它提供了一种类型安全的方式来与 RESTful API 进行交互。其主要功能包括&#xff1a; 安装 typed-rest-client 要使用 typed-rest-client&#xff0c;首先需要安装它&#xff0c;可以通过 npm 来安装&#xff1a; $ n…...

在Ubuntu 14.04上安装Solr的方法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 简介 Solr 是基于 Apache Lucene 的搜索引擎平台。它用 Java 编写&#xff0c;并使用 Lucene 库来实现索引。可以通过各种 REST API&am…...

LabVIEW提高开发效率技巧----使用LabVIEW工具

LabVIEW为开发者提供了多种工具和功能&#xff0c;不仅提高工作效率&#xff0c;还能确保项目的质量和可维护性。以下详细介绍几种关键工具&#xff0c;并结合实际案例说明它们的应用。 1. VI Analyzer&#xff1a;自动检查代码质量 VI Analyzer 是LabVIEW提供的一款强大的工…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

API网关Kong的鉴权与限流:高并发场景下的核心实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中&#xff0c;API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关&#xff0c;Kong凭借其插件化架构…...