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

news2024/12/26 0:51:37

播放器框架

在这里插入图片描述

常用音视频术语

• 容器/文件(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()

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

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

相关文章

dubbogo如何实现路由规则功能

dubbo-go中如何实现路由规则功能 路由规则( routing rule )是为了改变网络流量所经过的途径而修改路由信息的技术,主要通过改变路由属性(包括可达性)来实现。在发起一次 RPC 调用前起到过滤目标服务器地址的作用&…

Node第三方包 【node-xlsx】

文章目录 🌟前言🌟node-xlsx🌟安装🌟导出xlsx文件🌟解析xlsx文件🌟另外:其他支持读写Excel的Node.js模块有:🌟直接导出excel文件 🌟写在最后 🌟前…

麒麟信安联合主办 | openEuler Developer Day 2023召开 openEuler全场景走向深入

【中国,上海,2023年4月21日】openEuler Developer Day 2023于4月20-21日在线上和线下同步举办。本次大会由开放原子开源基金会、中国软件行业协会、openEuler社区、边缘计算产业联盟共同主办,以“万涓汇流,奔涌向前”为主题&#…

【FTP工具】- Win10下免费的FTP服务器搭建 - FileZilla 的下载、安装、使用

目录 一、概述二、下载、安装2.1 下载2.2 安装 三、FileZilla服务器的使用3.1 连接服务器3.2 配置用户权限 四、在windows访问该Ftp服务器4.1 查看Ftp服务器IP4.2 访问Ftp服务器 一、概述 FileZilla服务器是一个免费的开源FTP和FTPS服务器,是根据GNU通用公共许可证条…

HTB靶机03-Shocker-WP

Shocker scan 2023-03-30 23:22 ┌──(xavier㉿xavier)-[~/Desktop/Inbox] └─$ sudo nmap -sSV -T4 -F 10.10.10.56 Starting Nmap 7.91 ( https://nmap.org ) at 2023-03-30 23:22 HKT Nmap scan report for 10.10.10.56 Host is up (0.40s latency). Not shown: 99 clos…

QT-day(2)-(常用类、信号与槽.....)

题目:编写一个登录功能的界面,在登录框项目中,将登陆按钮发射的tclicked信号,连接到自定义的槽函数中,在槽函数中,判断u界面输入的用户名是否为"admin ,密码是否为"123456如果验证成功&#xff0…

数据结构_时间复杂度/空间复杂度

目录 1. 数据结构在学什么 2. 数据结构的基本概念 3. 算法和算法评价 3.1 算法的基本概念 3.2 算法的特征 3.3 算法效率的度量 3.3.1 时间复杂度 3.3.2 空间复杂度 1. 数据结构在学什么 常言道:学以致用;学习完基本C语言程序,我们希…

AB数对 码蹄集

题目来源:码蹄集 题目描述: 大致思路: 遍历输入的n个整数,将每个数存入哈希表中,key为数值,value为该数出现的次数。 再次遍历这n个整数,对于每个数x,计算出x-C和xC的值&#xff0…

Go语言基础----Go语言简介

【原文链接】Go语言基础----Go语言简介 一、Go语言简介 Go语言,又称Golang,是Google公司的Robert Griesemer,Rob Pike 及 Ken Thompson开发的一种静态强类型、编译型的语言。Go语言语法和C语言接近,但是功能上内存安全&#xff…

【Python】lambda匿名函数

文章目录 前言lambda匿名函数的定义lambda匿名函数的使用使用lambda匿名函数写一个计算器总结 前言 在Python中,可以使用def 关键字定义函数,使用def定义的关键字是有名称的,在调用时可以重复使用.还有一种是使用lambda关键字进行函数的定义,这个方式定义的函数是匿名函数,只能…

51单片机(四)静态数码管和动态数码管显示

❤️ 专栏简介:本专栏记录了从零学习单片机的过程,其中包括51单片机和STM32单片机两部分;建议先学习51单片机,其是STM32等高级单片机的基础;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 :适用于想要…

内存优化-比glibc更快的tcmalloc

TCMalloc 是 Google 开发的内存分配器,在不少项目中都有使用,例如在 Golang 中就使用了类似的算法进行内存分配。它具有现代化内存分配器的基本特征:对抗内存碎片、在多核处理器能够 scale。据称,它的内存分配速度是 glibc2.3 中实…

3d网上渲染平台是怎么渲图的_云渲染流程详解!

题主说的看到许多网友对‘’3d网上渲染平台是怎么渲图的‘’进行提问,瑞云渲染小编也提供自己的小小见解。针对3D网上渲染平台是指什么,实际应该是指云渲染农场。几十年来,随着计算机软硬件不断更迭,图形图像渲染的效果更加清晰、…

信号完整性分析基础知识之传输线和反射(二):阻性负载的反射,源端阻抗,弹跳图

传输线的端接需要考虑三种重要的特殊情况,每种情况中,传输线的特性阻抗均为50Ohm。信号将从源端在这条传输线上传播,并以特定的阻抗端接到达远端。 TIP:在时域中,信号对瞬时阻抗十分敏感,第二区域并不一定是一条传输线…

常见的链表的OJ题

在本次的博客当中,为了巩固关于链表技能的运用,我们先来看一些与链表有关的OJ题。 🌵反转链表 题目详情如下: 第一道题目从逻辑上看不难,我们只需要将链表进行拆分,将我们下一个节点进行一个类似于头插的操…

【Java 数据结构】Map和Set

🎉🎉🎉点进来你就是我的人了 博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!人生格言:当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔🦾&am…

35岁程序员被裁赔偿27万,公司又涨薪让我回去,前提是退还补偿金,能回吗?

在大多数人眼里,35岁似乎都是一道槛,互联网界一直都有着“程序员是吃青春饭”的说法,。 如果在35岁的时候被裁能获得27万的赔偿,公司又涨薪请你回去上班,你会怎么选? 最近,就有一位朋友在网上…

Linux安装miniconda3

下载Miniconda(Python3版本) 下载地址:https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh 安装Miniconda(需要连网) (1)将Miniconda3-latest-Linux-x86_64.sh上传到/o…

研读Rust圣经解析——Rust learn-14(面向对象)

研读Rust圣经解析——Rust learn-14(面向对象) Rust面向对象对象包含数据和行为封装继承多态 实现面向对象书写最外层逻辑userServiceUser Rust面向对象 在一些定义下,Rust 是面向对象的;在其他定义下,Rust 不是 对象…

算法刷题|300.最长递增子序列、674.最长连续递增序列、718.最长重复子数组

最大递增子序列 题目:给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6…