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

音视频八股文(6)-- ffmpeg大体介绍和内存模型

播放器框架

在这里插入图片描述

常用音视频术语

• 容器/文件(Conainer/File):即特定格式的多媒体文件,
比如mp4、flv、mkv等。

• 媒体流(Stream):表示时间轴上的一段连续数据,如一
段声音数据、一段视频数据或一段字幕数据,可以是压缩
的,也可以是非压缩的,压缩的数据需要关联特定的编解
码器(有些码流音频他是纯PCM)。

• 数据帧/数据包(Frame/Packet):通常,一个媒体流是
由大量的数据帧组成的,对于压缩数据,帧对应着编解码
器的最小处理单元,分属于不同媒体流的数据帧交错存储
于容器之中。

• 编解码器:编解码器是以帧为单位实现压缩数据和原始数
据之间的相互转换的。

常用概念-复用器

在这里插入图片描述

常用概念-编解码器

在这里插入图片描述

FFmpeg的整体结构

在这里插入图片描述

FFMPEG有8个常用库

• AVUtil:核心工具库,下面的许多其他模块都会依赖该库做一些基本的音视频处理操作。

• AVFormat:文件格式和协议库,该模块是最重要的模块之一,封装了Protocol层和Demuxer、Muxer层,使得协议和格式对于开发者来说是透明的。

• AVCodec:编解码库,封装了Codec层,但是有一些Codec是具备自己的License的,FFmpeg是不会默认添加像libx264、FDK-AAC等库的,但是FFmpeg就像一个平台一样,可以将其他的第三方的Codec以插件的方式添加进来,然后为开发者提供统一的接口。

• AVFilter:音视频滤镜库,该模块提供了包括音频特效和视频特效的处理,在使用FFmpeg的API进行编解码的过程中,直接使用该模块为音视频数据做特效处理是非常方便同时也非常高效的一种方式。

• AVDevice:输入输出设备库,比如,需要编译出播放声音或者视频的工具ffplay,就需要确保该模块是打开的,同时也需要SDL的预先编译,因为该设备模块播放声音与播放视频使用的都是SDL库。

• SwrRessample:该模块可用于音频重采样,可以对数字音频进行声道数、数据格式、采样率等多种基本信息的转换。

• SWScale:该模块是将图像进行格式转换的模块,比如,可以将YUV的数据转换为RGB的数据,缩放尺寸由1280720变为800480。

• PostProc:该模块可用于进行后期处理,当我们使用AVFilter的时候需要打开该模块的开关,因为Filter中会使用到该模块的一些基础函数。

FFmpeg函数简介

◼ av_register_all():注册所有组件,4.0已经弃用

◼ avdevice_register_all()对设备进行注册,比如V4L2等。

◼ avformat_network_init();初始化网络库以及网络加密协议相关的库(比如openssl)

FFmpeg函数简介-封装格式相关

◼ avformat_alloc_context();负责申请一个AVFormatContext结构的内存,并进行简单初始化

◼ 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():定位文件

在这里插入图片描述

FFmpeg解码函数简介-解码器相关

• avcodec_alloc_context3(): 分配解码器上下文

• avcodec_find_decoder():根据ID查找解码器

• avcodec_find_decoder_by_name():根据解码器名字

• avcodec_open2(): 打开编解码器

• avcodec_decode_video2():解码一帧视频数据

• avcodec_decode_audio4():解码一帧音频数据

• avcodec_send_packet(): 发送编码数据包

• avcodec_receive_frame(): 接收解码后数据

• avcodec_free_context():释放解码器上下文,包含了avcodec_close()

• avcodec_close():关闭解码器

在这里插入图片描述

FFmpeg 3.x 组件注册方式

我们使用ffmpeg,首先要执行av_register_all,把全局的解码器、编码器等结构体注册到各自全局的对象链表里,以便后面查找调用。

在这里插入图片描述

FFmpeg 4.x 组件注册方式

FFmpeg内部去做,不需要用户调用API去注册。
以codec编解码器为例:

  1. 在configure的时候生成要注册的组件./configure:7203:print_enabled_components libavcodec/codec_list.c AVCodec codec_list $CODEC_LIST这里会生成一个codec_list.c 文件,里面只有static const AVCodec *
    const codec_list[]数组。

  2. 在libavcodec/allcodecs.c将static const AVCodec * const codec_list[]的编解码器用链表的方式组织起来。

Ffmpeg 4.0.2 组件注册方式

FFmepg内部去做,不需要用户调用API去注册。

对于demuxer/muxer(解复用器,也称容器)则对应

  1. libavformat/muxer_list.c libavformat/demuxer_list.c 这两个文件也是在configure的时候生成,也就是说直接下载源码是没有这两个文件的。

  2. 在libavformat/allformats.c将demuxer_list[]和muexr_list[]以链表的方式组织。

其他组件也是类似的方式

FFmpeg数据结构简介

AVFormatContext
封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息。

AVInputFormat demuxer
每种封装格式(例如FLV, MKV, MP4, AVI)对应一个该结构体。

AVOutputFormat muxer

AVStream
视频文件中每个视频(音频)流对应一个该结构体。

AVCodecContext
编解码器上下文结构体,保存了视频(音频)编解码相关信息。

AVCodec
每种视频(音频)编解码器(例如H.264解码器)对应一个该结构体。

AVPacket
存储一帧压缩编码数据。

AVFrame
存储一帧解码后像素(采样)数据。

如果上下文数据保存在解码器里面?
多路解码的时候数据肯定有冲突。

FFmpeg数据结构之间的关系

AVFormatContext和AVInputFormat之间的关系

AVFormatContext API调用
AVInputFormat 主要是FFMPEG内部调用

在这里插入图片描述

AVCodecContext和AVCodec之间的关系

AVCodecContext 编码器上下文结构体
struct AVCodec *codec;

AVCodec 每种视频(音频)编解码器
int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt);
int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr);

AVFormatContext, AVStream和AVCodecContext之间的关系

在这里插入图片描述

区分不同的码流

◼ AVMEDIA_TYPE_VIDEO视频流

video_index = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,-1,-1, NULL, 0)

◼ AVMEDIA_TYPE_AUDIO音频流

audio_index = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,-1,-1, NULL, 0)

AVPacket 里面也有一个index的字段

FFmpeg数据结构分析

◼ AVFormatContext

• iformat:输入媒体的AVInputFormat,比如指向AVInputFormat
ff_flv_demuxer

• nb_streams:输入媒体的AVStream 个数

• streams:输入媒体的AVStream []数组

• duration:输入媒体的时长(以微秒为单位),计算方式可以参
考av_dump_format()函数。

• bit_rate:输入媒体的码率

◼ AVInputFormat

• name:封装格式名称

• extensions:封装格式的扩展名

• id:封装格式ID

• 一些封装格式处理的接口函数,比如read_packet()

◼ AVStream

• index:标识该视频/音频流

• time_base:该流的时基,PTS*time_base=真正的时间(秒)

• avg_frame_rate: 该流的帧率

• duration:该视频/音频流长度

• codecpar:编解码器参数属性

◼ AVCodecParameters

• codec_type:媒体类型,比如AVMEDIA_TYPE_VIDEO
AVMEDIA_TYPE_AUDIO等

• codec_id:编解码器类型, 比如AV_CODEC_ID_H264
AV_CODEC_ID_AAC等。

◼ AVCodecContext

• codec:编解码器的AVCodec,比如指向AVCodec
ff_aac_latm_decoder

• width, height:图像的宽高(只针对视频)

• pix_fmt:像素格式(只针对视频)

• sample_rate:采样率(只针对音频)

• channels:声道数(只针对音频)

• sample_fmt:采样格式(只针对音频)

◼ AVCodec

• name:编解码器名称

• type:编解码器类型

• id:编解码器ID

• 一些编解码的接口函数,比如int (*decode)()

◼ AVCodecContext

• codec:编解码器的AVCodec,比如指向AVCodec
ff_aac_latm_decoder

• width, height:图像的宽高(只针对视频)

• pix_fmt:像素格式(只针对视频)

• sample_rate:采样率(只针对音频)

• channels:声道数(只针对音频)

• sample_fmt:采样格式(只针对音频)

◼ AVCodec

• name:编解码器名称

• type:编解码器类型

• id:编解码器ID

• 一些编解码的接口函数,比如int (*decode)()

AVPacket

• pts:显示时间戳

• dts:解码时间戳

• data:压缩编码数据

• size:压缩编码数据大小

• pos:数据的偏移地址

• stream_index:所属的AVStream

AVFrame

• data:解码后的图像像素数据(音频采样数据)

• linesize:对视频来说是图像中一行像素的大小;对音频来说是整个音频帧的大小

• width, height:图像的宽高(只针对视频)

• key_frame:是否为关键帧(只针对视频) 。

• pict_type:帧类型(只针对视频) 。例如I, P, B

• sample_rate:音频采样率(只针对音频)

• nb_samples:音频每通道采样数(只针对音频)

• pts:显示时间

FFmpeg内存模型

◼ 从现有的Packet拷贝一个新Packet的时候,有两种情况:

• ①两个Packet的buf引用的是同一数据缓存空间,这时
候要注意数据缓存空间的释放问题;

• ②两个Packet的buf引用不同的数据缓存空间,每个
Packet都有数据缓存空间的copy;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

◼ 对于多个AVPacket共享同一个缓存空间,FFmpeg使用的引用计数的机制(reference-count):

◼◼ 初始化引用计数为0,只有真正分配AVBuffer的时候,引用计数初始化为1;

◼◼ 当有新的Packet引用共享的缓存空间时,就将引用计数+1;

◼◼ 当释放了引用共享空间的Packet,就将引用计数-1;引用计数为0时,就释放掉引用的缓存空间AVBuffer。

◼ AVFrame也是采用同样的机制。

AVPacket常用API

AVPacket *av_packet_alloc(void); 分配AVPacket
这个时候和buffer没有关系

void av_packet_free(AVPacket **pkt); 释放AVPacket
和_alloc对应

void av_init_packet(AVPacket *pkt); 初始化AVPacket
只是单纯初始化pkt字段

int av_new_packet(AVPacket *pkt, int size); 给AVPacket的buf分配内存,引用计数初始化为1

int av_packet_ref(AVPacket *dst, const AVPacket *src); 增加引用计数

void av_packet_unref(AVPacket *pkt); 减少引用计数

void av_packet_move_ref(AVPacket *dst, AVPacket *src); 转移引用计数

AVPacket *av_packet_clone(const AVPacket *src); 等于av_packet_alloc()+av_packet_ref()

AVFrame *av_frame_alloc(void); 分配AVFrame

void av_frame_free(AVFrame **frame); 释放AVFrame

int av_frame_ref(AVFrame *dst, const AVFrame *src); 增加引用计数

void av_frame_unref(AVFrame *frame); 减少引用计数

void av_frame_move_ref(AVFrame *dst, AVFrame *src); 转移引用计数

int av_frame_get_buffer(AVFrame *frame, int align); 根据AVFrame分配内存

AVFrame *av_frame_clone(const AVFrame *src); 等于av_frame_alloc()+av_frame_ref()

相关文章:

音视频八股文(6)-- ffmpeg大体介绍和内存模型

播放器框架 常用音视频术语 • 容器/文件(Conainer/File):即特定格式的多媒体文件, 比如mp4、flv、mkv等。 • 媒体流(Stream):表示时间轴上的一段连续数据,如一 段声音…...

4.25~~~~~

接着之前PE文件结构的预习 DOS 定位到NT 怎么操作的? 用的是e_lfanew,然后是相对于文件头的偏移量(也就是raw表示方法) 现在有个问题,为什么e_lfanew 这个变量不直接存储PE头 的绝对地址呢? 比如说&…...

Android 9.0 系统设置显示主菜单添加屏幕旋转菜单实现旋转屏幕功能

1.前言 在android9.0的系统rom定制化开发中,在对系统设置进行定制开发中,有产品需求要求增加旋转屏幕功能的菜单,就是在点击旋转屏幕菜单后弹窗显示旋转0度,旋转 90度,旋转180度,旋转270度针对不同分辨率的无重力感应的大屏设备的屏幕旋转功能的实现,接下来就来分析实现…...

Python数据结构与算法-欧几里算法(p95)

一、欧几里算法原理 欧几里得公式 欧几里得算法:gcd(a,b) gcd(b, a mod b) ; mod是指模,即a/b取余数。 运算示例: gcd(60,21) gcd(21,18) gcd(18,3)gcd(3,0) 证明略 最大公约数-欧几里得求解 &#xff08…...

【故障诊断】用于轴承故障诊断的性能增强时变形态滤波方法及用于轴承断层特征提取的增强数学形态算子研究(Matlab代码实现)

💥 💥 💞 💞 欢迎来到本博客 ❤️ ❤️ 💥 💥 🏆 博主优势: 🌞 🌞 🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 …...

水羊转债,超达转债,晓鸣转债上市价格预测

水羊转债 基本信息 转债名称:水羊转债,评级:A,发行规模:6.94987亿元。 正股名称:水羊股份,今日收盘价:13.94元,转股价格:13.71元。 当前转股价值 转债面值 /…...

从数据管理到数据资产管理

数据已经与土地、劳动力、资本、技术并称为五种生产要素,数据的价值是毋庸置疑的。数据甚至成为了国家的基础性战略资源,数字经济也正在成为经济增长的强大创新动力。那么—— 数据到底指的是什么? 数据管理又是怎么回事? 数据如何…...

RabbitMQ【#1】是什么,有什么用

RabbiMQ是什么? RabbitMQ是一种开源的消息队列软件,它实现了高级消息队列协议(AMQP)并支持多种编程语言。它可以用于将消息从一个应用程序传递到另一个应用程序或进程,并支持分布式系统中的异步消息通信。RabbitMQ的主…...

RabbitMQ防止消息丢失

生产者没有成功把消息发送到MQ 丢失的原因 :因为网络传输的不稳定性,当生产者在向MQ发送消息的过程中,MQ没有成功接收到消息,但是生产者却以为MQ成功接收到了消息,不会再次重复发送该消息,从而导致消息的丢…...

ImageJ用户手册——第二部分(ImageJ操作)

ImageJ用户手册-第二部分 ImageJ的使用4. 使用键盘快捷键5. 查找命令6. 撤消和重做7. 图像类型和格式原生格式非原生格式 8. 堆栈、虚拟堆栈、超堆栈Stacks(堆栈)Virtual Stacks(虚拟堆栈)Hyperstacks(超堆栈&#xff…...

Java中Lambda表达式(面向初学者)

目录 一、Lambda表达式是什么?什么场景下使用Lambda? 1.Lambda 表达式是什么 2.函数式接口是什么 第二章、怎么用Lambda 1.必须有一个函数式接口 2.省略规则 3.Lambda经常用来和匿名内部类比较 第三章、具体使用场景举例() …...

2023年淮阴工学院五年一贯制专转本数字电子技术考试大纲

2023年淮阴工学院五年一贯制专转本数字电子技术考试大纲 一、考核对象 本课程的考核对象是五年一贯制高职专转本电子科学与技术专业普通在校生考生。 二、考试目的及总体要求 通过本课程的考试,检查学生对掌握数字电路的基础理论知识的掌握程度,是否…...

使用 GO 编写 Web 应用:学习如何使用 GO 语言编写 Web 应用,包括使用 HTTP 路由、模板引擎等。

GO 语言是一个高效、可靠和简洁的编程语言,越来越多的开发者开始选择 GO 语言来编写 Web 应用。本文将介绍如何使用 GO 语言编写 Web 应用,并且将重点关注使用 HTTP 路由和模板引擎。 使用 HTTP 路由 HTTP 路由是 Web 应用中非常重要的一个概念。它可以帮助我们将请求路由到…...

Leetcode-day4【88】【167】【125】【345】

文章目录 88. 合并两个有序数组题目解题思路解题思路【学习】尾插入法 167. 两数之和 II - 输入有序数组题目解题思路 125. 验证回文串题目解题思路 345. 反转字符串中的元音字母题目解题思路 88. 合并两个有序数组 题目 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums…...

【IoT】如何使用软件加密(文件夹加密工具.exe),并破解工具

目录 第一步:显示隐藏的文件。 第二步:将隐藏文件变成文件夹。 第三步:解密文件。 有时候出差或者有些商务场合,需要对一些敏感文件做一下简单的加密,这样在分享内容的时候,可以起到初步的保护作用。 当…...

Spring Boot——优雅的参数校验

🎈 概述 当我们想提供可靠的 API 接口,对参数的校验,以保证最终数据入库的正确性,是 必不可少 的活。比如下图就是 我们一个项目里 新增一个菜单校验 参数的函数,写了一大堆的 if else 进行校验,或者基础校…...

【c语言】typedef的基本用法 | 定义格式

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…...

深度学习论文分享(二)Data-driven Feature Tracking for Event Cameras

深度学习论文分享&#xff08;二&#xff09;Data-driven Feature Tracking for Event Cameras&#xff08;CVPR2023&#xff09; 前言Abstract1. Introduction2. Related Work3. Method3.1. Feature Network3.2. Frame Attention Module3.3. Supervision 4. Experiments5. Con…...

蛇优化算法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 蛇优化算法算法流程图初始化进化操作搜索阶段&#xff08;无食物&#xff09;——全局搜索搜索阶段&#xff08;有食物&#xff09;——局部搜索战斗模式交配模式 备…...

循环神经网络(RNN)简单介绍—包括TF和PyTorch源码,并给出详细注释

文章目录 循环神经网络&#xff08;RNN&#xff09;入门教程1. 循环神经网络的原理2. 循环神经网络的应用3. 使用keras框架实现循环神经网络3.1导入对应的库及加载数据集3.2.数据预处理3.3定义RNN模型3.4训练模型3.5测试模型 4.使用PyTorch框架实现上述功能—注释详细5.结论 循…...

远程办公三年,我摸索出一套不被“隐形加班”吞噬的方法

作为一名有着三年远程办公经验的软件测试工程师&#xff0c;我深知“隐形加班”如同温水煮青蛙&#xff0c;在不知不觉中吞噬着我们的私人时间与生活热情。从最初的“随时待命”到如今能精准划清工作与生活的界限&#xff0c;我总结出了一套切实可行的方法&#xff0c;希望能帮…...

【笔记】HarmonyOS核心设计理念

HarmonyOS初衷不是为了平替&#xff0c;是看到了万物智联时代,对智能终端操作系统有许多新的诉求&#xff1b; 本内容主要帮助理解HarmonyOS核心设计理念的关键背景与创新驱动力&#xff1b; 第一节&#xff1a;回顾操作系统的发展历史 第一台通用计算机诞生于1946年&#xf…...

通宵降AI率?10款降AI工具亲测:哪个神器一次过,哪个白花钱

2025 年 12 月 25 日知网 AIGC 检测系统升级&#xff0c;2026 年 4 月 27 日维普 AI 率检测平台升级…2026 毕业季&#xff0c;各大主流 AIGC 检测软件陆续升级系统&#xff0c;识别 AI 痕迹更加精准。 临近毕业&#xff0c;同学们看者飘红的 AIGC 检测报告、纷繁复杂的降 AI 系…...

都在喊难,它却狂赚!深度扒开长鑫科技底牌:什么才是决定生死的产业势?

2026年的商业世界&#xff0c;正在经历一场冰火两重天的考验。 一边&#xff0c;是无数传统企业在需求萎缩、价格内卷的泥潭里苦苦挣扎&#xff0c;老板们每天为了几毛钱的利润拼得头破血流&#xff1b;而另一边&#xff0c;一份堪称“核弹级”的财报&#xff0c;直接炸翻了整个…...

进口与国产扁线电感参数PK:Coilcraft SER2918H-103KL vs TONEVEE ZER2918-H103K

在大电流电源设计领域&#xff0c;扁线电感因低直流电阻、高饱和电流及良好的散热性能&#xff0c;成为 DC-DC 转换器、VRM 及工业控制等场景的核心器件。美国 Coilcraft&#xff08;线艺&#xff09;作为国际品牌&#xff0c;其 SER2900 系列长期占据高端市场&#xff1b;国产…...

xc-union 从 1.0.0 到 2.0.0:开源私域返利基座

618 拼的不只是流量&#xff0c;更是开发效率。 每到大促节点&#xff0c;很多团队都会集中遇到同一类需求&#xff1a; 查券/导购工具要尽快上线H5 页面先跑&#xff0c;后端接口后续持续扩展要求可快速交付&#xff0c;也要支持后续二开 问题是&#xff0c;如果从零开始手撸&…...

技术选型翻车实录:我们选的那个框架,两年后停止维护了

一、惊魂一刻&#xff1a;框架停更的暴击“紧急通知&#xff0c;我们一直使用的XX测试框架将于本月底停止维护&#xff01;”当这条消息出现在团队工作群时&#xff0c;整个测试部瞬间陷入死寂。作为一家中型电商企业的测试负责人&#xff0c;我清楚地知道&#xff0c;这个框架…...

终极指南:如何用AhabAssistantLimbusCompany彻底解放《Limbus Company》游戏时间

终极指南&#xff1a;如何用AhabAssistantLimbusCompany彻底解放《Limbus Company》游戏时间 【免费下载链接】AhabAssistantLimbusCompany AALC&#xff0c;PC端Limbus Company小助手。AALC&#xff0c;Limbus Company Assistant on PC 项目地址: https://gitcode.com/gh_mi…...

大型房地产集团战略规划数字化转型PMO项目进度管理解决方案(PPT)

导读 有一个问题值得认真想一想&#xff1a;一家布局全国、同时管理几十个楼盘的大型地产集团&#xff0c;它的"项目管理"问题&#xff0c;究竟出在哪里&#xff1f; 不是因为缺人&#xff0c;也不是因为团队不努力。事实上&#xff0c;大多数地产集团在规模扩张到一…...

Aube:下一代 Node.js 包管理器,性能远超 pnpm

好的&#xff0c;我已经为您整理了关于新一代 Node.js 包管理器 Aube 的详细介绍文章。文章基于您提供的摘要和 GitHub 仓库的详细文档&#xff0c;扩充了功能介绍、使用场景和命令参考&#xff0c;以形成一个完整的详情页面。 Aube&#xff1a;下一代 Node.js 包管理器&#x…...