FFmpeg 命令:从入门到精通 | FFmpeg 解码流程

FFmpeg 命令:从入门到精通 | FFmpeg 解码流程

  • FFmpeg 命令:从入门到精通 | FFmpeg 解码流程
    • 流程图
    • FFmpeg 解码的函数
    • FFmpeg 解码的数据结构
    • 补充小知识

FFmpeg 命令:从入门到精通 | FFmpeg 解码流程

本内容参考雷霄骅博士的 FFmpeg 教程。

流程图

FFmpeg 解码的流程图如下所示:

在这里插入图片描述

FFmpeg 解码的流程:

  1. 注册:
    使用ffmpeg对应的库,都需要进行注册,可以注册子项也可以注册全部。
  2. 打开文件:
    打开文件,根据文件名信息获取对应的ffmpeg全局上下文。
  3. 探测流信息:
    一定要探测流信息,拿到流编码的编码格式,不探测流信息则其流编码器拿到的编码类型可能为空,后续进行数据转换的时候就无法知晓原始格式,导致错误。
  4. 查找对应的解码器:
    依据流的格式查找解码器,软解码还是硬解码是在此处决定的,但是特别注意是否支持硬件,需要自己查找本地的硬件解码器对应的标识,并查询其是否支持。普遍操作是,枚举支持文件后缀解码的所有解码器进行查找,查找到了就是可以硬解了(此处,不做过多的讨论,对应硬解码后续会有文章进行进一步研究)。(注意:解码时查找解码器,编码时查找编码器,两者函数不同,不要弄错了,否则后续能打开但是数据是错的)
  5. 打开解码器:
    打开获取到的解码器。
  6. 申请缩放数据格式转换结构体:
    此处特别注意,基本上解码的数据都是yuv系列格式,但是我们显示的数据是rgb等相关颜色空间的数据,所以此处转换结构体就是进行转换前到转换后的描述,给后续转换函数提供转码依据,是很关键并且非常常用的结构体。
  7. 申请缓存区:
    申请一个缓存区outBuffer,fill到我们目标帧数据的data上,比如rgb数据,QAVFrame的data上存是有指定格式的数据,且存储有规则,而fill到outBuffer(自己申请的目标格式一帧缓存区),则是我们需要的数据格式存储顺序。
    举个例子,解码转换后的数据为rgb888,实际直接用data数据是错误的,但是用outBuffer就是对的,所以此处应该是ffmpeg的fill函数做了一些转换。
    进入循环解码:
  8. 获取一帧packet:
    拿取封装的一个packet,判断packet数据的类型进行解码拿到存储的编码数据
  9. 数据转换:
    使用转换函数结合转换结构体对编码的数据进行转换,那拿到需要的目标宽度、高度和指定存储格式的原始数据。
  10. 自行处理:
    拿到了原始数据自行处理。不断循环,直到拿取pakcet函数成功,但是无法得到一帧数据,则代表文件解码已经完成。帧率需要自己控制循环,此处只是循环拿取,可加延迟等。
  11. 释放QAVPacket:
    此处要单独列出是因为,其实很多网上和开发者的代码在进入循环解码前进行了av_new_packet,循环中未av_free_packet,造成内存溢出;或者,在进入循环解码前进行了av_new_packet,循环中进行av_free_pakcet,那么一次new对应无数次free,在编码器上是不符合前后一一对应规范的。查看源代码,其实可以发现av_read_frame时,自动进行了av_new_packet(),那么其实对于packet,只需要进行一次av_packet_alloc()即可,解码完后av_free_packet。
    执行完后,返回执行“步骤8:获取一帧packet”,一次循环结束。
  12. 释放转换结构体:
    全部解码完成后,安装申请顺序,进行对应资源的释放。
  13. 关闭解码/编码器:
    关闭之前打开的解码/编码器。
  14. 关闭上下文:
    关闭文件上下文后,要对之前申请的变量按照申请的顺序,依次释放。

FFmpeg 解码的函数

  • av_register_all():注册所有组件。
  • avformat_open_input():打开输入视频文件。
  • avformat_find_stream_info():获取视频文件信息。
  • avcodec_find_decoder():查找解码器。
  • avcodec_open2():打开解码器。
  • av_read_frame():从输入文件读取一帧压缩数据。
  • avcodec_decode_video2():解码一帧压缩数据。
  • avcodec_close():关闭解码器。
  • avformat_close_input():关闭输入视频文件。

FFmpeg 解码的数据结构

FFmpeg 解码的数据结构如下所示:

在这里插入图片描述

FFmpeg 数据结构:

  • AVFormatContext:封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息。
  • AVInputFormat:每种封装格式(例如FLV, MKV, MP4, AVI)对应一个该结构体。
  • AVStream:视频文件中每个视频(音频)流对应一个该结构体。
  • AVCodecContext:编码器上下文结构体,保存了视频(音频)编解码相关信息。
  • AVCodec:每种视频(音频)编解码器(例如H.264解码器)对应一个该结构体。
  • AVPacket:存储一帧压缩编码数据。
  • AVFrame:存储一帧解码后像素(采样)数据。

FFmpeg 数据结构分析:

AVFormatContext:

  • iformat:输入视频的AVInputFormat
  • nb_streams :输入视频的AVStream 个数
  • streams :输入视频的AVStream []数组
  • duration :输入视频的时长(以微秒为单位)
  • bit_rate :输入视频的码率

AVInputFormat:

  • name:封装格式名称
  • long_name:封装格式的长名称
  • extensions:封装格式的扩展名
  • id:封装格式ID
  • 一些封装格式处理的接口函数

AVStream:

  • id:序号
  • codec:该流对应的AVCodecContext
  • time_base:该流的时基
  • r_frame_rate:该流的帧率

AVCodecContext:

  • codec:编解码器的AVCodec
  • width, height:图像的宽高(只针对视频)
  • pix_fmt:像素格式(只针对视频)
  • sample_rate:采样率(只针对音频)
  • channels:声道数(只针对音频)
  • sample_fmt:采样格式(只针对音频)

AVCodec:

  • name:编解码器名称
  • long_name:编解码器长名称
  • type:编解码器类型
  • id:编解码器ID
  • 一些编解码的接口函数

AVPacket:

  • pts:显示时间戳
  • dts :解码时间戳
  • data :压缩编码数据
  • size :压缩编码数据大小
  • stream_index :所属的AVStream

AVFrame:

  • data:解码后的图像像素数据(音频采样数据)。
  • linesize:对视频来说是图像中一行像素的大小;对音频来说是整个音频帧的大小。
  • width, height:图像的宽高(只针对视频)。
  • key_frame:是否为关键帧(只针对视频) 。
  • pict_type:帧类型(只针对视频) 。例如I,P,B。

补充小知识

解码后的数据为什么要经过sws_scale()函数处理?

解码后YUV格式的视频像素数据保存在AVFrame的data[0]、data[1]、data[2]中。但是这些像素值并不是连续存储的,每行有效像素之后存储了一些无效像素。以亮度Y数据为例,data[0]中一共包含了linesize[0]*height个数据。但是出于优化等方面的考虑,linesize[0]实际上并不等于宽度width,而是一个比宽度大一些的值。因此需要使用sws_scale()进行转换。转换后去除了无效数据,width和linesize[0] 取值相等。

在这里插入图片描述

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

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

相关文章

Docker 的数据管理与Docker 镜像的创建

------------------Docker 的数据管理--------------------- 管理 Docker 容器中数据主要有两种方式:数据卷(Data Volumes)和数据卷容器(DataVolumes Containers)。 1.数据卷 数据卷是一个供容器使用的特殊…

c++使用ifstream和ofstream报错:不允许使用不完整的类型

学习《C Primer》关于IO库的部分&#xff0c;输入284页的的代码&#xff0c;出现了报错&#xff1a; 不允许使用不完整的类型 原来的代码&#xff1a; #include <iostream> #include <vector> using namespace std;int main(int argc, char **argv) {ifstream in…

Python Random模块详解

Random模块详解 随机数 random模块 randint(a, b) 返回[a, b]之间的整数randrange ([start,] stop [,step]) 从指定范围内&#xff0c;按指定基数递增的集合中获取一个随机数&#xff0c;基数 缺省值为1。random.randrange(1,7,2)choice(seq) 从非空序列的元素中随机挑选一个…

NPDP产品经理知识(产品创新流程)

1.复习组合管理: 组合管理的目标 ===> 价值最大化,项目平衡,战略一致,管道平衡(资源需求和供给),盈利充分 (实现财务目标) 产品创新流程就是管理风险的过程。 模糊前端: 产品创新章程:PIC 包含 =====> 背景,聚焦舞台,目标和目的,特别准则,可持续性 新产…

基于Java的家政公司服务平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

Nacos与Eureka的区别

大家好我是苏麟今天说一说Nacos与Eureka的区别. Nacos Nacos的服务实例分为两种l类型&#xff1a; 临时实例&#xff1a;如果实例宕机超过一定时间&#xff0c;会从服务列表剔除&#xff0c;默认的类型。非临时实例&#xff1a;如果实例宕机&#xff0c;不会从服务列表剔除&…

生成Release版本的.pdb文件

软件分为Debug版本、Release版本这2种版本&#xff0c;其中Debug版本是带有.pdb调试信息文件&#xff0c;而Release版本不带.pdb调试信息文件。软件发布时&#xff0c;一般采用Release版本&#xff0c;若因内存泄漏、数组访问越界、除零错误、磁盘读写错误等异常&#xff0c;造…

Docker安装ActiveMQ

ActiveMQ简介 官网地址&#xff1a;https://activemq.apache.org/ 简介&#xff1a; ActiveMQ 是Apache出品&#xff0c;最流行的&#xff0c;能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,…

如何搭建一个 websocket

环境: NodeJssocket.io 4.7.2 安装依赖 yarn add socket.io创建服务器 引入文件 特别注意: 涉及到 colors 的代码&#xff0c;请采取 console.log() 打印 // 基础老三样 import http from "http"; import fs from "fs"; import { Server } from &quo…

FM5888协议系列-USB充电控制器 移动电源应用

产品描述&#xff1a; FM5888是一款USB快速充电控制IC&#xff0c;符合USB电池充电规范1.2版本&#xff0c;允许充电装置吸取的电流类似于使用原装充电器。FM5888可自动识别充电设备类型&#xff0c;支持多种智能手机&#xff0c;并通过对应的USB充电协议与设备握手&#xff0c…

25 mysql like 是否使用索引

前言 这里主要是 探究一下 explain $sql 中各个 type 诸如 const, ref, range, index, all 的查询的影响, 以及一个初步的效率的判断 这里会调试源码来看一下 各个类型的查询 需要 lookUp 的记录 以及 相关的差异 此系列文章建议从 mysql const 查询 开始看 测试表结构…

【100个 Unity实用技能】☀️ | UGUI Text中加入超链接文本,可直接点击跳转

Unity 小科普 老规矩&#xff0c;先介绍一下 Unity 的科普小知识&#xff1a; Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者&#xff0c;借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案&#xff…