【音视频学习-5 ffmpeg 框架学习】

本文基于ffmpeg4.0编写

FFmpeg库介绍:

ffmpeg常用库:

  • AVUtil:

    • 核心工具库,其他模块都会依赖该库

  • AVFormat

    • 文件格式和协议库,该模块是最重要的模块之一,封装了Protocol层和Demuxer (解复用器/复用器) Muxer层,使得协议和格式对于开发者来说是透明的。

  • AVCodec

    • 编解码库,封装了Codec层,但是有一些Codec是具备自己的License的,FFmpeg是不会默认添加像libx264、FDK-AAC等库的

  • AVFilter

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

  • ACDevice

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

  • SwrRessample

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

  • SwrRessample

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

  • PostProc

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

ffmpeg 涉及结构体:
  • AVFormatContext:

    • AVFormatContextFFmpeg中的一个重要结构体,用于表示一个多媒体文件或流的格式上下文,即解/复用器的上下文。它包含了有关媒体文件的各种信息,如文件格式、编解码器、时长、分辨率等。

    • 以下是AVFormatContext的一些常见用途:

      • 文件解析:通过分析AVFormatContext,可以获取文件的格式信息,确定文件中包含的媒体类型(如音频、视频、字幕等)以及相应的编解码器。

      • 媒体流提取:可以使用AVFormatContext来访问和分离文件中的各个媒体流,以便进行进一步的处理,如解码、播放、转码等。

      • 元数据访问:AVFormatContext还包含了文件的元数据信息,例如标题、作者、创建日期等。可以通过它获取这些元数据。

      • 媒体格式转换:在进行媒体格式转换时,AVFormatContext提供了必要的信息,以便正确地转换文件的格式和编解码器。

  • AVInputFormat:主要是ffmpeg内部调用

    • AVInputFormatFFmpeg 中的一个结构体,用于描述输入封装格式的相关信息。每种封装格式(例如FLV, MKV, MP4, AVI)对应一个该结构体。

      AVInputFormat 结构体通常包含以下信息:

      • 格式名称:标识输入封装格式的字符串。

      • 扩展名:与该格式相关联的文件扩展名列表。

      • 读取函数指针:指向用于读取输入数据的函数。

      • 探测函数指针:指向用于探测输入文件格式的函数。

      • 私有数据指针:用于存储与该格式相关的私有数据。

    • demuxer

      • demuxer 的主要功能是将多媒体文件或流解复用为各个独立的媒体流,例如音频流和视频流。它使用 AVInputFormat 来确定输入文件的格式,并调用相应的读取函数来获取媒体数据。在 FFmpeg 中,通过注册不同的 AVInputFormat 结构体,可以支持多种输入格式。当打开一个输入文件或流时,FFmpeg 会根据文件扩展名或其他特征选择合适的 AVInputFormat,并使用对应的 demuxer 进行解复用。

  • AVStream

    • AVStreamFFmpeg 中的一个结构体,用于表示多媒体流的相关信息。它通常包含以下关键成员:

      • index:流的索引。

      • codecpar:包含流的编解码器参数。

      • time_base:时间基准,表示每一个时间单位对应的实际时间。

      • avg_frame_rate:平均帧率。

      • r_frame_rate:实际帧率。

      • start_time:流的起始时间。

      • duration:流的持续时间。

    • 通过 AVStream,可以获取有关多媒体流的各种详细信息,以便进行解码、播放、转码等操作。

  • AVCodecContext

    • AVCodecContextFFmpeg 中的一个结构体,主要用于存储与解码器相关的上下文信息。

    • 以下是一些常用的成员:

      • codec:指向与该上下文相关联的解码器。

      • widthheight:视频的宽度和高度。

      • sample_rate:音频的采样率。

      • channels:音频的通道数。

      • pix_fmt:视频的像素格式。

      • bit_rate:码率。

      • time_base:时间基准

    • 通过设置和操作 AVCodecContext 结构体的成员,可以指定解码器的参数、解码后的视频和音频属性等。

  • AVPacket

    • AVPacket 结构体存储一帧压缩编码数据,以下是一些常见的成员变量:

      • data:指向数据包的数据缓冲区。

      • size:数据包的数据长度。

      • pts:显示时间戳,表示数据包应该在何时显示。

      • dts:解码时间戳,表示数据包应该在何时解码。

  • AVFrame

    • AVFrame 结构体存储一帧解码后像素(采样)数据,AVFrame 的主要作用是存储解码后的帧数据,以便进行进一步的处理,如显示、编码等。,以下是一些常见的成员变量:

      • data:指向帧数据的指针。

      • linesize:每行数据的字节数。

      • width 和 height:帧的宽度和高度。

      • format:帧的像素格式,如 YUV420P、RGB 等。

      • key_frame:指示是否为关键帧。

  • 结构体之间的关系:

    • ffmpeg 通过读取媒体文件信息初始化AVFormatContext,再通过读取AVFormatContext读取找到对应的AVInputFormat(封装格式),通过AVInputFormat调用对应的解复用函数去解复用为音频和视频流等存储在AVStream中,在AVStream中读取信息设置AVCodecContext,再通过AVCodecContext去查找对应的AVCodec(解码器),最后解码为AVPacketAVFrame

FFmpeg函数

  • av_register_all():注册所有组件,4.0已经弃用,目前不需要关注如何注册了

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

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

根据上图分析:

  1. 首先进行解复用:
    1. 初始化包含了关于媒体文件的所有相关信息的结构体: AVFormatContext (含有解复用所需要的参数,和媒体文件的相关信息等)
      • AVFormatContext *avformat_alloc_context():是 FFmpeg 中用于分配并初始化 AVFormatContext 结构体的函数。AVFormatContext 结构体是 FFmpeg 中保存媒体文件解复用相关的上下文信息的结构体

      • avformat_free_context() : 释放avformat_alloc_context返回的结构体,实际是avformat_close_input的宏定义

    2. 打开音视频文件或网络流,将AVFormatContext 结构体绑定到对应的媒体文件
      1. int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);;该函数用于打开媒体文件,根据给定的媒体文件路径打开一个输入流,并将相关的信息存储在 AVFormatContext 结构体中

        • 参数:

          • ps:指向 AVFormatContext 结构体指针的指针。调用该函数后,成功打开媒体文件时会将指向 AVFormatContext 结构体的指针保存在 ps 指向的地址中。

          • url:媒体文件的 URL 或者文件路径。

          • fmt:要使用的输入格式,一般为 NULL,表示由 FFmpeg 自动检测输入格式。

          • options:一些额外的选项,可传入 NULL。这里可以添加一些自定义的选项,例如设置解码线程数等。

    3. 从音视频文件或者网络流中读取码流信息从而填充 AVFormatContext 结构体的成员数据
      • int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);:获取媒体文件的流信息。调用该函数之后,会尝试读取媒体文件中的流信息,并将这些信息填充到 AVFormatContext 结构体中。这些流信息包括视频流、音频流、字幕流等。通过调用该函数,可以获取关于媒体文件中各个流的详细信息,例如编解码器类型、码率、长等。

        • 参数:

          • ic:指向 AVFormatContext 结构体的指针,即代表已经打开的媒体文件信息的结构体指针。

          • options:一些额外的选项,可传入 NULL。这里可以添加一些自定义的选项,例如设置解码线程数等。

    4. 读取AVFormatContext信息打开对应的音视频文件读取一帧数据并保存到队列中(循环读取数据)
      • int av_read_frame(AVFormatContext *s, AVPacket *pkt); : 调用该函数可以从媒体文件中读取一帧数据,然后将其存储在 AVPacket 结构体中,类似fread()函数

        • 参数:

          • s:指向 AVFormatContext 结构体的指针,代表已经打开的媒体文件信息的结构体指针。

          • pkt:指向 AVPacket 结构体的指针,用于存储读取到的数据包(帧)信息。

    5. 关闭解复用器,至此,我们将媒体文件解复用成视频流和音频流,字幕流等
      • void avformat_close_input(AVFormatContext **s);关闭解复用器。关闭后就不再需要

        • 参数:

          • s:指向 AVFormatContext 结构体的指针,代表已经打开的媒体文件信息的结构体指针。

        • 返回值:无

  2. 第二步,对视频流和音频流,字幕流进行解码,
    1. 同样首先进行解码器的上下文信息的结构体AVCodecContext (代表了编解码器的上下文信息,包括编解码器的参数设置、帧率、分辨率等信息。) 初始化:
      • AVCodecContext *avcodec_alloc_context3(const AVCodec *codec): 并返回一个指向AVCodecContext 结构体的指针。在这个结构体中,你可以设置和获取与指定编解码器相关的各种参数。

        • 参数:

          • codec:表示要使用的编解码器的指针。

    2. 读取将码流中的编解码器信息拷贝到 AVCodecContext 中
      1. int avcodec_parameters_to_context(AVCodecContext *codec, const AVStream *par):该函数会将 AVCodecParameters 结构体中的参数信息复制到 AVCodecContext结构体中

        • 参数:

          • codec:AVCodecContext 指针,用于接收参数的上下文对象。

          • par:AVStream 指针,包含要复制的参数的源流对象。

    3. 获取代表解码器的结构体 AVCodec
      1. AVCodec *avcodec_find_decoder(enum AVCodecID id) : 根据ID查找解码器返回对应的结构体

        • 参数:

          • id : 是要查找的解码器的编解码器ID

        • 返回值:

          • 成功返回值AVCodec结构体

          • 失败返回NULL

      2. AVCodec *avcodec_find_decoder_by_name(const char *name) : 根据name查找解码器返回对应的结构体

        • 参数:

          • name : 是要查找的解码器的名称

        • 返回值:

          • 成功返回值AVCodec结构体

          • 失败返回NULL

    4. 关联AVCodecContext 和 AVCodec ,即设置解码器的上下文,eg: 码流,帧率等
      1. int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options): 根据给定的编解码器和参数打开编解码器,并初始化编解码器上下文

        • 参数:

          • avctx :要打开的编码器上下,

          • codec :使用的编解码器,

          • options :一个指向指针的指针,可以传入一些配置选项。

        • 返回值:

          • 成功打开并初始化时,返回值为 0

          • 如果函数执行失败或者编解码器无法打开或初始化,返回一个负数作为错误代码,表示相应的错误类型。例如,AVERROR(EINVAL) 表示无效的输入参数,AVERROR(ENOMEM) 表示内存分配失败等。

    5. 向解码器发送数据包
      1. int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt): 向解码器发送数据包

        • 参数:

          • avctx :解码器的上下文,

          • avpkt :待解码的数据包。

        • 返回值:

          • 当函数执行时,返回值为0。

          • 如果返回 AVERROR(EAGAIN),表示需要更输入数据才能继续解码。

          • 如果返回 AVERROR_EOF,已经发送完所有数据包,解码器已经处于结束。

          • 其他值表示函数执行发生错误,具体代码可参考 FFmpeg 的错误代码。

    6. 接收解码后的帧
      1. avcodec_receive_frame :从解码器中接收解码后的帧

        • 参数:

          • AVCodecContext *avctx:解码器上下文。

          • AVFrame *frame:接收解码后的帧的指针。

        • 返回值:

          • int:返回值的含义取决于函数的执行结果。

            • AV_ERROR_EOF:表示已经到达输入流的末尾。

            • AV_ERROR_INVALIDDATA:输入数据损坏或不符合解码器的要求。

            • AV_ERROR_TIMEOUT:操作超时。

            • AV_ERROR_BUFFER_TOO_SMALL:提供的帧缓冲区太小。

            • 0:表示成功接收到一帧解码后的数据。

    7. 关闭解码器和释放上下文
      1. avcodec_close:关闭解码器

      2. void avcodec_free_context(AVCodecContext **avctx):释放分配给 AVCodecContext 结构体的内存。

        • 参数

          • AVCodecContext **avctx:指向要释放的 AVCodecContext 结构体的指针。

指定学习链接:https://xxetb.xetslk.com/s/1xYq7U

  • 49
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值