深入浅出:FFmpeg 音频解码与处理AVFrame全解析(一)

简介: 深入浅出:FFmpeg 音频解码与处理AVFrame全解析

一、FFmpeg 简介

1.1 FFmpeg 的历史与发展

FFmpeg 是一个开源的音视频处理软件,它包含了一系列的库和程序,用于处理音频、视频和其他多媒体数据。FFmpeg 的名字来源于 “Fast Forward MPEG”,其中 MPEG 是一种常见的音视频编码标准。

FFmpeg 项目于 2000 年由 Fabrice Bellard 启动,他是 QEMU(一种开源的计算机模拟器和虚拟机)的创始人。FFmpeg 的目标是提供一个全面、高效和高质量的解决方案,用于处理多媒体数据。

在过去的二十多年里,FFmpeg 经历了多次重大的更新和改进,逐渐成为了音视频处理领域的重要工具。它被广泛应用于各种场景,包括流媒体、视频编辑、转码、录制等。

FFmpeg 的主要组成部分包括:

  • libavcodec(音视频编解码库):这是 FFmpeg 中最重要的库,它包含了所有的音视频编解码器。libavcodec 支持多种音视频编码格式,包括常见的 MPEG、H.264、AAC 等。
  • libavformat(音视频封装库):这个库用于处理音视频数据的封装和解封装。它支持多种媒体文件格式,包括 MP4、AVI、MKV 等。
  • libavfilter(音视频滤镜库):这个库提供了一系列的音视频滤镜,用于处理音视频数据,例如裁剪、旋转、调色等。
  • libavdevice(音视频设备库):这个库提供了访问设备的功能,例如摄像头、麦克风等。
  • libavutil(工具库):这个库提供了一些通用的函数和工具,例如日志、错误处理、内存管理等。
  • ffmpeg(命令行工具):这是 FFmpeg 的主程序,它提供了一个命令行接口,用于处理音视频数据。

FFmpeg 的发展历程充满了挑战和创新,它的成功在很大程度上源于开源社区的贡献。今天,FFmpeg 已经成为了音视频处理领域的重要工具,它的影响力远超过了最初的预期。

1.2 FFmpeg 的主要组成部分

FFmpeg 是一个复杂的多媒体处理框架,它由多个库和工具组成,每个部分都有其特定的功能和用途。下面我们将详细介绍 FFmpeg 的主要组成部分:

  1. libavcodec(音视频编解码库):libavcodec 是 FFmpeg 中最重要的库之一,它提供了大量的音频编解码器和视频编解码器。这个库支持多种音视频编码格式,包括常见的 MPEG、H.264、AAC 等。通过 libavcodec,我们可以轻松地进行音视频数据的编码和解码操作。
  2. libavformat(音视频封装库):libavformat 是用于处理音视频数据的封装和解封装的库。它支持多种媒体文件格式,包括 MP4、AVI、MKV 等。通过 libavformat,我们可以读取和写入各种格式的音视频文件。
  3. libavfilter(音视频滤镜库):libavfilter 提供了一系列的音视频滤镜,用于处理音视频数据,例如裁剪、旋转、调色等。通过 libavfilter,我们可以对音视频数据进行各种复杂的处理和转换。
  4. libavdevice(音视频设备库):libavdevice 是一个特殊的库,它提供了访问设备的功能,例如摄像头、麦克风等。通过 libavdevice,我们可以直接从设备获取音视频数据,或者将音视频数据输出到设备。
  5. libavutil(工具库):libavutil 是一个通用的工具库,它提供了一些基础的函数和工具,例如日志、错误处理、内存管理等。虽然 libavutil 的功能看起来比较基础,但它是 FFmpeg 的核心组成部分,其他的库都依赖于它。
  6. ffmpeg(命令行工具):ffmpeg 是 FFmpeg 的主程序,它提供了一个命令行接口,用于处理音视频数据。通过 ffmpeg,我们可以方便地进行音视频编解码、格式转换、滤镜处理等操作。

以上就是 FFmpeg 的主要组成部分,每个部分都有其特定的功能和用途,它们共同构成了 FFmpeg 这个强大的多媒体处理框架。

二、音频编解码基础 (Basics of Audio Encoding and Decoding)

2.1 音频编解码的原理 (Principle of Audio Encoding and Decoding)

音频编解码是数字音频处理的核心技术之一,它涉及到音频信号的采样、量化、编码和解码等一系列过程。

2.1.1 采样 (Sampling)

采样是将连续的模拟信号转换为离散的数字信号的过程。在音频处理中,采样率(Sampling Rate)是一个重要的参数,它表示每秒钟采样的次数。常见的采样率有44.1kHz、48kHz等,其中44.1kHz是CD音质的采样率。

2.1.2 量化 (Quantization)

量化是将连续的信号幅度转换为离散的过程。在音频处理中,量化位数(Bit Depth)是一个重要的参数,它表示每个采样点的精度。常见的量化位数有16位、24位等,其中16位是CD音质的量化位数。

2.1.3 编码 (Encoding)

编码是将离散的数字信号转换为可以存储和传输的数据的过程。在音频处理中,编码格式(Codec)是一个重要的参数,它决定了音频数据的压缩方式和质量。常见的音频编码格式有PCM、AAC、MP3等。

2.1.4 解码 (Decoding)

解码是编码的逆过程,它将编码后的数据恢复为原始的音频信号。在音频播放设备中,解码器(Decoder)是一个重要的组件,它负责将音频数据解码为可以播放的信号。

2.1.5 音频帧和样本

在音频处理中,一个音频帧是一个包含一定数量样本的数据块。样本是音频信号的离散表示,通常以一定的采样率(如44100Hz)进行采样。

2.2 常见音频编码格式 (Common Audio Encoding Formats)

音频编码格式是音频数据压缩和存储的方式,不同的编码格式有不同的特点和应用场景。以下是一些常见的音频编码格式:

2.2.1 PCM (Pulse Code Modulation)

脉冲编码调制(PCM)是一种无损的音频编码格式,它直接记录了音频信号的样本值。PCM 编码的音频质量非常高,但是数据量也非常大,通常用于专业音频处理和高质量音乐播放。

2.2.2 AAC (Advanced Audio Coding)

高级音频编码(AAC)是一种有损的音频编码格式,它使用了复杂的压缩算法来减小数据量。AAC 编码的音频质量相对较高,数据量相对较小,是目前最常用的音频编码格式之一。

2.2.3 MP3 (MPEG-1 Audio Layer III)

MP3 是一种有损的音频编码格式,它是早期数字音乐的主要格式。MP3 编码的音频质量和数据量都适中,但是由于技术的发展,现在已经被 AAC 等更先进的格式取代。

2.2.4 Opus

Opus 是一种新型的音频编码格式,它既可以进行无损编码,也可以进行有损编码。Opus 编码的音频质量非常高,数据量非常小,特别适合于网络传输和实时通信。

以上就是一些常见的音频编码格式,每种格式都有其优点和缺点,选择哪种格式取决于具体的应用需求。在 FFmpeg 中,我们可以使用不同的编解码器来处理这些不同格式的音频数据。

2.3 FFmpeg 中的音频编解码 (Audio Encoding and Decoding in FFmpeg)

FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。在音频编解码方面,FFmpeg 提供了丰富的功能和灵活的选项。

2.3.1 FFmpeg 的音频编解码器 (Audio Codecs in FFmpeg)

FFmpeg 支持大量的音频编解码器,包括上述提到的 PCM、AAC、MP3 和 Opus 等。每种编解码器都有其特定的参数和选项,可以通过 FFmpeg 的命令行工具或者编程接口进行配置。

2.3.2 FFmpeg 的音频编码过程 (Audio Encoding Process in FFmpeg)

在 FFmpeg 中,音频编码过程主要包括以下步骤:

  1. 打开编解码器:使用 avcodec_open2 函数打开指定的编解码器。
  2. 准备音频帧:创建 AVFrame 结构体,填充音频数据和相关参数。
  3. 编码音频帧:使用 avcodec_send_frameavcodec_receive_packet 函数将音频帧编码为音频包。
  4. 写入音频包:将编码后的音频包写入输出文件或者发送到网络。

2.3.3 FFmpeg 的音频解码过程 (Audio Decoding Process in FFmpeg)

在 FFmpeg 中,音频解码过程主要包括以下步骤:

  1. 打开编解码器:使用 avcodec_open2 函数打开指定的编解码器。
  2. 读取音频包:从输入文件或者网络读取音频包。
  3. 解码音频包:使用 avcodec_send_packetavcodec_receive_frame 函数将音频包解码为音频帧。
  4. 处理音频帧:根据需要处理解码后的音频帧,例如播放、存储或者进一步处理。

以上就是 FFmpeg 中音频编解码的基本过程,接下来我们将深入探讨这些过程的具体实现和应用。

三、深入理解 avcodec_receive_frame 函数

3.1 avcodec_receive_frame 函数的作用

在 FFmpeg 中,avcodec_receive_frame 函数是一个核心的解码函数,它的主要作用是从解码器中获取解码后的帧数据。这个函数的原型如下:

int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);

这个函数接收两个参数:一个是解码器上下文 AVCodecContext,另一个是用于存储解码后的帧数据的 AVFrame 结构体。

AVCodecContext(解码器上下文)是 FFmpeg 中用于存储解码器状态的结构体,它包含了解码器的所有信息,如解码器类型、解码参数等。在调用 avcodec_receive_frame 函数时,我们需要传入一个已经初始化并打开的解码器上下文。

AVFrame(帧数据)是 FFmpeg 中用于存储解码后的帧数据的结构体,它包含了帧的所有信息,如帧的数据、帧的大小、帧的时间戳等。在调用 avcodec_receive_frame 函数时,我们需要传入一个 AVFrame 结构体,函数会将解码后的帧数据填充到这个结构体中。

avcodec_receive_frame 函数的返回值是一个整数,表示函数的执行结果。如果函数执行成功,返回值为 0;如果函数执行失败,返回值为一个负数,表示错误码。我们可以通过检查这个返回值来判断函数是否执行成功,以及在出错时获取错误的具体原因。

在实际使用中,我们通常会在一个循环中调用 avcodec_receive_frame 函数,以便连续地获取解码后的帧数据。在每次循环中,我们首先调用 avcodec_receive_frame 函数获取解码后的帧数据,然后处理这个帧数据,最后使用 av_frame_unref 函数释放帧数据的资源。这个过程会一直重复,直到 avcodec_receive_frame 函数返回 AVERROR(EAGAIN)AVERROR_EOF,表示没有更多的帧数据可以获取。

总的来说,avcodec_receive_frame 函数是 FFmpeg 中音频解码的核心函数,它的作用是从解码器中获取解码后的帧数据,我们可以通过这个函数获取到音频的原始数据,然后进行进一步的处理。

3.2 avcodec_receive_frame 函数的使用

avcodec_receive_frame 函数的使用通常包含在一个解码循环中,该循环会持续进行,直到所有的输入数据都被解码并返回。下面是一个基本的使用示例:

AVFrame *frame = av_frame_alloc();
if (!frame) {
    // 处理内存分配失败的情况
}
while (1) {
    ret = avcodec_receive_frame(codec_ctx, frame);
    if (ret == 0) {
        // 在这里处理解码后的帧数据
    } else if (ret == AVERROR_EOF) {
        // 所有的输入数据都已经被解码并返回
        break;
    } else if (ret == AVERROR(EAGAIN)) {
        // 需要更多的输入数据才能返回下一帧
        continue;
    } else {
        // 处理其他错误情况
    }
    av_frame_unref(frame);
}

在这个示例中,我们首先使用 av_frame_alloc 函数创建一个 AVFrame 结构体,用于存储解码后的帧数据。然后,我们进入一个无限循环,不断地调用 avcodec_receive_frame 函数获取解码后的帧数据。

在每次循环中,我们首先调用 avcodec_receive_frame 函数,传入解码器上下文 codec_ctxAVFrame 结构体 frame。如果函数返回 0,表示成功获取到了解码后的帧数据,我们可以在这里处理这个帧数据。如果函数返回 AVERROR_EOF,表示所有的输入数据都已经被解码并返回,我们可以退出循环。如果函数返回 AVERROR(EAGAIN),表示需要更多的输入数据才能返回下一帧,我们可以继续循环。如果函数返回其他错误码,我们需要处理这个错误情况。

在处理完帧数据后,我们需要使用 av_frame_unref 函数释放帧数据的资源,以避免内存泄漏。

总的来说,avcodec_receive_frame 函数的使用需要结合解码器上下文和 AVFrame 结构体,通过循环不断地获取和处理解码后的帧数据,直到所有的输入数据都被解码并返回。

3.3 avcodec_receive_frame 函数的返回值处理

avcodec_receive_frame 函数的返回值是一个整数,表示函数的执行结果。这个返回值可以帮助我们理解解码过程的状态,以及在出错时获取错误的具体原因。下面是一些常见的返回值及其含义:

  • 0:成功返回,表示成功获取到了解码后的帧数据。
  • AVERROR(EAGAIN):需要更多的输入数据才能返回下一帧。这个返回值表示当前的解码器上下文中没有足够的数据来生成一个完整的帧,需要我们提供更多的输入数据。
  • AVERROR_EOF:所有的输入数据都已经被解码并返回,没有更多的帧数据可以获取。这个返回值表示解码过程已经完成,我们可以结束解码循环。
  • 其他负值:表示发生了错误。这些错误可能包括内存分配失败、无效的参数、解码错误等。我们可以使用 av_err2str 函数将错误码转换为可读的错误信息。

在处理 avcodec_receive_frame 函数的返回值时,我们需要根据不同的返回值采取不同的处理策略。例如,如果返回值为 0,我们可以处理解码后的帧数据;如果返回值为 AVERROR(EAGAIN),我们可以继续提供输入数据;如果返回值为 AVERROR_EOF,我们可以结束解码循环;如果返回值为其他负值,我们需要处理错误情况。

总的来说,avcodec_receive_frame 函数的返回值是我们理解和控制解码过程的重要工具,我们需要根据这个返回值来决定下一步的操作。


四、音频解码后的帧数据处理 (Processing Decoded Audio Frame Data)

4.1 音频帧数据的结构 (Structure of Audio Frame Data)

在 FFmpeg 中,音频帧数据被封装在 AVFrame 结构体中。AVFrame 是 FFmpeg 中一个非常重要的数据结构,它代表了解码后的原始数据。对于音频数据来说,AVFrame 主要包含以下几个关键字段:

  • nb_samples(样本数量)

这个字段表示了这个音频帧中包含的样本数量。在音频处理中,一个样本通常代表了一个时间点的音频数据。这是一个变量,表示音频帧中的样本数量。例如,1024是一个常见的音频缓冲区大小,特别是在实时音频处理中,因为1024是2的10次方,这使得它在处理器中更高效。

  • channels(通道数):

这个字段表示了音频数据的通道数。例如,对于立体声音频,通道数为 2。通道数量决定了每个样本时间点有多少个独立的样本值。例如,对于立体声(2通道)音频,每个样本时间点有两个样本值:一个用于左声道,一个用于右声道。对于四通道音频,每个样本时间点有四个独立的样本值。

  • data(数据)

这个字段是一个指针数组,用于存储音频帧的实际数据。对于音频数据,data 数组中的每个元素都是一个指向一段内存的指针,这段内存存储了对应通道的音频数据。

  • linesize(行大小)

这个字段是一个整数数组,表示了 data 中每个元素指向的数据的大小,在FFmpeg中通常用来表示音频帧中一行(对于平面格式,一行通常对应一个声道的所有样本)的字节数。

在FFmpeg中,linesize数组表示了data数组中每个元素(即每个通道)的数据大小,单位是字节。这个大小通常是每个通道的样本数量乘以每个样本的字节大小。例如,如果你有一个音频帧,它有1024个样本,每个样本是16位(2字节),那么linesize就会是2048字节。

但是,需要注意的是,linesize可能并不总是等于样本数量乘以样本的字节大小。在某些情况下,为了内存对齐或其他原因,linesize可能会比实际的样本数据大一些。因此,当你在处理data数组时,应该使用linesize来确定每个通道的数据大小,而不是仅仅依赖于样本数量和样本的字节大小。

  • frame->extended_data

这是一个指向解码后的音频数据的指针。它是一个二维数组,第一维表示通道,第二维表示每个通道的样本数据。


在处理音频帧数据时,我们需要根据这些字段的值来正确地读取和处理音频数据。例如,我们可以根据 nb_sampleslinesize 的值来确定每个样本的数据大小,然后根据 channels 的值来处理多通道音频数据。

在下一节中,我们将详细介绍如何使用这些字段来处理音频帧数据。


深入浅出:FFmpeg 音频解码与处理AVFrame全解析(二)https://developer.aliyun.com/article/1465079

目录
相关文章
|
9天前
|
编解码 Python
音频剪裁大师:使用 Python 和 ffmpeg 分割音频的完整指南
使用 Python 和 ffmpeg 进行音频文件分割。通过 `subprocess` 模块调用 ffmpeg 命令,定义 `split_audio` 函数,输入参数包括音频文件、起始时间、持续时间和输出文件名。函数构建命令行指令进行分割,然后执行。运行脚本,即可按指定时间从音频中提取片段。简单易用,适用于多种音频处理场景。
8 1
|
19天前
|
编解码 5G Linux
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
AVS3是中国首个8K及5G视频编码标准,相比AVS2和HEVC性能提升约30%。解码器libuavs3d支持8K/60P视频实时解码,兼容多种平台。《FFmpeg开发实战》书中介绍了在Windows环境下如何集成libuavs3d到FFmpeg。集成步骤包括下载源码、使用Visual Studio 2022编译、调整配置、安装库文件和头文件,以及重新配置和编译FFmpeg以启用libuavs3d。
36 0
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
|
26天前
|
编解码 Linux 5G
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
AVS3,中国制定的第三代音视频标准,是首个针对8K和5G的视频编码标准,相比AVS2和HEVC性能提升约30%。uavs3d是AVS3的解码器,支持8K/60P实时解码,且在各平台有优秀表现。要为FFmpeg集成AVS3解码器libuavs3d,需从GitHub下载最新源码,解压后配置、编译和安装。之后,重新配置FFmpeg,启用libuavs3d并编译安装,通过`ffmpeg -version`确认成功集成。
34 0
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
|
27天前
|
存储 缓存 调度
FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
《FFmpeg开发实战》第10章示例playsync.c在处理音频流和视频流交错的文件时能实现同步播放,但对于分开存储的格式,会出现先播放全部声音再快速播放视频的问题。为解决此问题,需改造程序,增加音频处理线程和队列,以及相关锁,先将音视频帧读入缓存,再按时间戳播放。改造包括声明新变量、初始化线程和锁、修改数据包处理方式等。代码修改后在playsync2.c中,编译运行成功,控制台显示日志,SDL窗口播放视频并同步音频,证明改造有效。
32 0
FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
|
30天前
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
《FFmpeg开发实战》一书中,第10章示例程序playaudio.c原本仅支持mp3和aac音频播放。为支持ogg、amr、wma等非固定帧率音频,需进行三处修改:1)当frame_size为0时,将输出采样数量设为512;2)遍历音频帧时,计算实际采样位数以确定播放数据大小;3)在SDL音频回调函数中,确保每次发送len字节数据。改进后的代码在chapter10/playaudio2.c,可编译运行播放ring.ogg测试,成功则显示日志并播放铃声。
29 1
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
|
30天前
|
缓存 编解码
FFmpeg开发笔记(十四)FFmpeg音频重采样的缓存
FFmpeg在视频流重编码和音频重采样中使用缓存机制。在音频文件格式转换时,特别是对于帧长度不固定的格式如ogg、amr、wma,需处理重采样缓存。通过调用`swr_convert`,传入空输入和0大小来清空缓存。在`swrmp3.c`中,修改帧样本数处理,并在循环结束后添加代码以冲刷缓存。编译并运行程序,将ogg文件重采样为MP3,日志显示操作成功,播放转换后的文件确认功能正常。
40 7
FFmpeg开发笔记(十四)FFmpeg音频重采样的缓存
|
30天前
|
存储 编解码 编译器
FFmpeg 7.0 正式登场:全新 VVC 解码器
【4月更文挑战第9天】最新版本的流行视频处理软件FFmpeg 7.0,代号为“Dijkstra”,已正式发布。
72 0
|
30天前
|
搜索推荐 数据管理 数据挖掘
解码2024年项目管理系统:排行榜背后的功能与特色解析
2024年十大项目管理工具:Zoho Projects以其专业成熟度领先,适合跨部门协作和进度跟踪;Nifty适合初创公司,界面直观,响应快速;Quickbase面向处理大量信息的团队,提供定制化解决方案;WorkOtter专为中大型企业资源管理和汇报设计;Asana适合大型协作团队,任务管理和沟通高效;Monday.com高度可定制,适合复杂项目管理;Smartsheet结合电子表格功能,适合流程多变的团队;Adobe Workfront针对复杂项目和自动化需求;ClickUp是一站式工作平台,功能多样;Trello则以简洁看板适合小团队和个人。考虑团队规模、项目复杂度和个性化需求来选工具
36 1
|
30天前
|
编解码 Linux API
【FFmpeg 视频流处理】FFmpeg API深度解析:视频流画面合并、拼接与裁剪技巧
【FFmpeg 视频流处理】FFmpeg API深度解析:视频流画面合并、拼接与裁剪技巧
162 0
|
30天前
|
开发工具
使用FFmpeg4.3.1的SDK官方开发包编译ffmpeg.c(三)
使用FFmpeg4.3.1的SDK官方开发包编译ffmpeg.c(三)
33 0

推荐镜像

更多