音视频编程ffmepg中的关键术语与概念:深度解析与实践(一)https://developer.aliyun.com/article/1465227
4.2 容器格式:MP4,MKV等
在音视频编程中,我们经常会遇到各种各样的文件格式,这些文件格式通常被称为“容器”(Container)。容器可以包含多种类型的数据,例如音频流,视频流,字幕,元数据等。每种容器都有其特定的特性和用途。下面我们将详细介绍几种常见的容器格式。
4.2.1 MP4(MPEG-4 Part 14)
MP4(MPEG-4 Part 14)是一种非常常见的容器格式,它由Moving Picture Experts Group(MPEG)开发。MP4格式支持多种类型的数据,包括音频(如AAC和MP3),视频(如H.264和H.265),字幕以及元数据。
MP4的主要优点是高度兼容性和广泛的支持。几乎所有的设备和平台都支持MP4格式,包括各种浏览器,操作系统,移动设备等。此外,MP4还支持高质量的视频和音频,以及高效的压缩算法,使得MP4文件可以在保持较高质量的同时,具有较小的文件大小。
4.2.2 MKV(Matroska Video)
MKV是一种开源的容器格式,它可以包含无限数量的音频,视频,字幕轨道以及元数据。MKV的主要优点是其灵活性和功能强大。例如,MKV支持几乎所有的音频和视频编解码格式,支持多种字幕格式,以及丰富的元数据。
MKV的一个重要特性是支持章节,菜单和元数据,这使得MKV非常适合用于存储电影和电视节目。此外,MKV还支持无损音频和高质量视频,使得它在音乐和电影爱好者中非常受欢迎。
4.2.3 其他容器格式
除了MP4和MKV之外,还有许多其他的容器格式,例如AVI,MOV,FLV等。这些格式各有其特点和用途,例如AVI格式在早期的Windows平台上非常流行,MOV是Apple的QuickTime软件的默认格式,FLV被广泛用于网络视频流等。
在选择容器格式时,需要考虑多
个因素,包括你的目标平台,所需的功能,以及你的音频和视频编解码格式等。
在音视频编程中,理解和选择合适的容器格式是非常重要的。不同的容器格式有不同的特性和优点,选择合适的容器可以帮助你更有效地处理和传输音视频数据。
4.3 编解码库:FFmpeg,Libav等
在音视频流处理中,编解码库(Codec Libraries)是非常关键的一部分,它们提供了音视频编解码、格式转换、流媒体传输等功能。在这里,我们将重点介绍两个广泛使用的开源编解码库:FFmpeg和Libav。
4.3.1 FFmpeg
FFmpeg(快速前向移动图片组)是一个开源的音视频处理库,包含了众多音视频编解码器,用于录制、转换数字音视频,并能将其转化为流。它提供了录制、转换以及流化音视频的完整解决方案,包括了领先的音、视频编码库。
- 功能丰富:FFmpeg具有非常丰富的功能,包括音视频录制、音视频转换、音视频编解码、音视频流化等。它几乎支持所有的音视频格式,能够满足大部分音视频处理的需求。
- 跨平台:FFmpeg不仅支持Linux,还支持Windows、Mac OS X等操作系统,甚至包括一些嵌入式系统,如Android和iOS。
- 高效性能:FFmpeg在设计时充分考虑了效率问题,能够充分利用现代CPU的多核特性,进行并行处理,大大提高了音视频处理的效率。
- 活跃的社区:FFmpeg有一个非常活跃的开源社区,不断有新的功能被添加进来,同时也有很多人在维护和优化,保证了FFmpeg的稳定性和先进性。
4.3.2 Libav
Libav是从FFmpeg项目中分离出来的一个开源项目,它提供了一套完整的解决方案,用于处理多媒体数据,包括音频、视频、字幕、元数据等。
- 全面的解决方案:Libav包含了一系列工具,包括用于处理音视频数据的库,以及用于音视频转换、流化的命令行工具。
- 高度兼容:由于Libav和FFmpeg有共同的祖先,因此它们在API和ABI上有很高的兼容性,大部分基于FFmpeg的应用可以无缝切换到Libav。
- 活跃的社区:Libav也有一个
活跃的社区:Libav也有一个非常活跃的开源社区,不断有新的功能被添加进来,同时也有很多人在维护和优化,保证了Libav的稳定性和先进性。
在音视频流处理中,FFmpeg和Libav都是非常重要的工具,它们提供了丰富的功能,能够满足大部分音视频处理的需求。然而,它们各有特点,选择使用哪一个,需要根据具体的需求来决定。
例如,一项研究《A Novel Real-time Video Transmission Approach for Remote Laboratory Development》中,作者使用了FFmpeg来开发一个基于HTTP Live Streaming (HLS)协议的实时视频传输解决方案,成功解决了网络防火墙的问题,使得终端用户可以在任何便携设备上观看实时实验直播视频,无需担心防火墙问题或需要第三方插件。
这个例子展示了FFmpeg在处理音视频流时的强大能力。然而,这并不意味着Libav就没有用武之地,事实上,由于Libav和FFmpeg有共同的祖先,因此它们在API和ABI上有很高的兼容性,大部分基于FFmpeg的应用可以无缝切换到Libav,这为开发者提供了更多的选择。
总的来说,FFmpeg和Libav都是非常优秀的音视频处理库,选择使用哪一个,需要根据具体的项目需求和个人喜好来决定。
5. 音频采样格式详解
5.1 音频采样格式:平面格式(Planar Formats)
在音频编程中,除了音频采样的数据类型(如整数、浮点数等)外,音频数据的存储方式也是非常重要的。这就引出了我们的下一个主题:平面格式(Planar Formats)。
5.1.1 平面格式(Planar)和打包格式(Packed)
在处理多声道音频数据时,有两种常见的数据布局:平面(Planar)和打包(Packed)。
- 打包格式(Packed):在打包格式中,多个声道的样本是交错存储的。例如,对于立体声(stereo)音频,左声道(L)和右声道(R)的样本可能会以LRLRLR的方式交错存储。
- 平面格式(Planar):在平面格式中,每个声道的样本都是连续存储的。例如,对于立体声音频,所有左声道的样本会先存储,然后是所有右声道的样本,形成LL…RR…的存储方式。
5.1.2 FLTP(Float Planar)
FLTP是一种特殊的音频采样格式,它结合了浮点数和平面格式的特性。在FLTP中,音频数据是以浮点数形式存储的,并且采用平面格式布局。这意味着每个声道的所有样本都是连续存储的,而且每个样本都是浮点数。
FLTP格式的优点是它可以提供大的动态范围和精确的表示,同时也方便对单个声道的数据进行处理。例如,如果你想要修改音频的左声道,你可以直接访问存储左声道样本的内存区域,而不需要遍历整个音频数据来找到左声道的样本。
然而,FLTP格式的缺点是它需要更多的内存来存储音频数据,因为浮点数通常需要更多的存储空间。此外,处理浮点数也需要更多的计算资源,尤其是在嵌入式系统或低功耗设备上。
5.1.3 其他平面格式
除了FLTP外,还有其他的平面格式,如:
- S16P(Signed 16-bit Planar):这是一种16位有符号整数平面格式。在S16P中,音频数据以16位有符号整数形式存储,并采用平面格式布局。
- U8P(Unsigned 8-bit Planar):这是一种8位无符号整数平面格式。在U8P中,音频数据以8位无符号整数形式存储,并采用平面格式布局。
这些平面格式各有优缺点,选择哪种
格式取决于你的具体需求,包括你的音频数据的特性(如声道数、采样率等),你的硬件和软件环境(如处理器的性能、内存的大小、操作系统等),以及你的应用场景(如实时音频处理、音频文件编码等)。
5.1.4 平面格式的编程应用
在编程中,处理平面格式的音频数据需要一些特殊的技巧。由于平面格式中每个声道的样本都是连续存储的,所以我们不能简单地通过一个循环来遍历所有的样本。相反,我们需要分别处理每个声道的数据。
例如,假设我们有一个FLTP格式的立体声音频数据,我们想要将左声道的音量增加50%,右声道的音量减少50%。我们可以通过以下的代码来实现这个功能:
float *left_channel = audio_data; float *right_channel = audio_data + num_samples; for (int i = 0; i < num_samples; i++) { left_channel[i] *= 1.5; // 增加左声道的音量 right_channel[i] *= 0.5; // 减少右声道的音量 }
在这个例子中,我们首先通过指针运算获取到左声道和右声道数据的起始位置。然后,我们分别处理左声道和右声道的数据,通过直接修改音频数据来改变音量。
这种处理方式的优点是它可以直接对音频数据进行操作,无需额外的数据结构或复杂的算法。然而,这也意味着我们需要对音频数据的内部结构有深入的理解,才能正确地处理平面格式的音频数据。
5.2音频采样格式:打包格式(Packed Formats)
在我们之前的讨论中,我们已经介绍了平面格式(Planar Formats),这是一种音频数据的布局方式,其中每个声道的样本都是连续存储的。然而,平面格式并不是唯一的音频数据布局方式。在这一节中,我们将介绍另一种常见的布局方式:打包格式(Packed Formats)。
5.2.1 打包格式(Packed)的概念
在打包格式(Packed)中,多个声道的样本是交错存储的。例如,对于立体声(stereo)音频,左声道(L)和右声道(R)的样本可能会以LRLRLR的方式交错存储。这种布局方式的优点是它可以更好地利用内存,因为它不需要为每个声道分配单独的内存区域。
5.2.2 打包格式的音频采样格式
在FFmpeg中,打包格式的音频采样格式通常以"P"结尾。例如:
- FLT(Float Packed):在FLT中,音频数据是以浮点数形式存储的,并且采用打包格式布局。这意味着左声道和右声道的样本会交错存储,形成LRLRLR…的存储方式。
- S16(Signed 16-bit Packed):这是一种16位有符号整数打包格式。在S16中,音频数据以16位有符号整数形式存储,并采用打包格式布局。
- U8(Unsigned 8-bit Packed):这是一种8位无符号整数打包格式。在U8中,音频数据以8位无符号整数形式存储,并采用打包格式布局。
5.2.3 打包格式的编程应用
在编程中,处理打包格式的音频数据比处理平面格式的音频数据要简单一些。由于打包格式中多个声道的样本是交错存储的,我们可以通过一个简单的循环来遍历所有的样本。
例如,假设我们有一个FLT格式的立体声音频数据,我们想要将左声道的音量增加50%,右声道的音量减少50%。我们可以通过以下的代码来实现这个功能:
float *audio_data = ...; int num_samples = ...; for (int i = 0; i < num_samples; i += 2) { audio_data[i] *= 1.5; // 增加左声道的音量 audio_data[i + 1] *= 0.5; // 减少右声道的音量 }
在这个例子中,我们通过一个循环来遍历所有的样本。由于左声道和右声道的样本是交错存
储的,所以我们可以通过索引i和i+1来分别访问左声道和右声道的样本。然后,我们通过直接修改音频数据来改变音量。
这种处理方式的优点是它可以直接对音频数据进行操作,无需额外的数据结构或复杂的算法。然而,这也意味着我们需要对音频数据的内部结构有深入的理解,才能正确地处理打包格式的音频数据。
5.2.4 打包格式和平面格式的选择
在选择使用打包格式还是平面格式时,需要考虑多个因素。首先,打包格式的音频数据更容易处理,因为它们可以通过一个简单的循环来遍历所有的样本。然而,打包格式的音频数据在处理多声道音频时可能会遇到一些问题,因为不同声道的样本是交错存储的,这可能会导致缓存未命中(cache miss)和其他性能问题。
另一方面,平面格式的音频数据在处理多声道音频时更为高效,因为每个声道的样本都是连续存储的。然而,平面格式的音频数据在处理单声道音频时可能会浪费内存,因为它们需要为每个声道分配单独的内存区域。
总的来说,选择使用打包格式还是平面格式主要取决于你的具体需求,包括你的音频数据的特性(如声道数、采样率等),你的硬件和软件环境(如处理器的性能、内存的大小、操作系统等),以及你的应用场景(如实时音频处理、音频文件编码等)。
5.3 音频采样格式:其他格式
除了我们已经介绍的平面格式和打包格式,FFmpeg还支持其他一些音频采样格式。在这一节中,我们将介绍其中的一些。
5.3.1 双精度浮点数格式(Double)
在双精度浮点数格式(Double)中,音频数据是以双精度浮点数(即64位浮点数)形式存储的。这种格式提供了非常高的精度,但也需要更多的内存和计算资源。在FFmpeg中,双精度浮点数格式的音频采样格式通常以"D"开头。例如:
- DBL(Double Packed):在DBL中,音频数据是以双精度浮点数形式存储的,并且采用打包格式布局。
- DBLP(Double Planar):在DBLP中,音频数据是以双精度浮点数形式存储的,并且采用平面格式布局。
5.3.2 无符号整数格式(Unsigned Integer)
在无符号整数格式(Unsigned Integer)中,音频数据是以无符号整数形式存储的。这种格式通常用于表示非负的音频数据。在FFmpeg中,无符号整数格式的音频采样格式通常以"U"开头。例如:
- U8(Unsigned 8-bit Packed):这是一种8位无符号整数打包格式。在U8中,音频数据以8位无符号整数形式存储,并采用打包格式布局。
- U8P(Unsigned 8-bit Planar):这是一种8位无符号整数平面格式。在U8P中,音频数据以8位无符号整数形式存储,并采用平面格式布局。
5.3.3 有符号整数格式(Signed Integer)
在有符号整数格式(Signed Integer)中,音频数据是以有符号整数形式存储的。这种格式可以表示正数和负数的音频数据。在FFmpeg中,有符号整数格式的音频采样格式通常以"S"开头。例如:
- S16(Signed 16-bit Packed):这是一种16位有符号整数打包格式。在S16中,音频数据以16位有符号整数形式存储,并采用打包格式布局。
- S16P(Signed 16-bit Planar):这是一种16位有符号整数平面格式。在S16P中,音频数据以16位有符号整数形式存储,并采用平面格式布局。
这些音频采样格式提供了不同的精度和存储效率,可以根据具体的需求和资源限制来选择合适的格式。
6. 音视频编程的实践应用(Practical Applications of Audio and Video Programming)
6.1 使用FFmpeg进行音视频编解码
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。它提供了录制、转换以及流化音视频的完整解决方案。在音视频编程中,我们常常需要对音视频数据进行编解码操作,而FFmpeg提供了一套完整的解决方案。
6.1.1 FFmpeg简介(Introduction to FFmpeg)
FFmpeg是一个开源项目,它包含了一系列的音视频处理工具,如ffmpeg, ffplay, ffprobe等。其中,ffmpeg是一个非常强大的工具,能够解码、编码、转码、复用、解复用、流、过滤和播放任何人类和机器创造的音/视频。
6.1.2 FFmpeg的音视频编解码流程(Audio and Video Encoding and Decoding Process of FFmpeg)
在FFmpeg中,音视频编解码的流程大致可以分为以下几个步骤:
- 打开输入文件:使用
avformat_open_input()
函数打开输入文件,获取到AVFormatContext
结构体。 - 获取音视频流信息:使用
avformat_find_stream_info()
函数获取音视频流的信息。 - 找到音视频流:在
AVFormatContext
中找到音频流和视频流。 - 打开解码器:对于找到的音频流和视频流,需要找到对应的解码器,并使用
avcodec_open2()
函数打开解码器。 - 读取音视频帧:使用
av_read_frame()
函数读取音视频帧。 - 解码音视频帧:使用
avcodec_send_packet()
和avcodec_receive_frame()
函数对音视频帧进行解码。 - 处理解码后的帧:对解码后的帧进行处理,如显示视频、播放音频等。
- 关闭解码器和输入文件:使用
avcodec_close()
和avformat_close_input()
函数关闭解码器和输入文件。
以上就是使用FFmpeg进行音视频编解码的基本流程。在实际的音视频处理中,可能还需要进行音视频同步、格式转换等操作,这就需要更深入地学习和理解FFmpeg。
6.2 立体声和多声道音频处理
在音频处理中,声道布局是一个重要的概念。声道布局描述了音频数据中的声道信息,例如声道的数量、类型以及它们的相对位置等。在FFmpeg中,我们可以通过AVChannelLayout
结构体来表示声道布局。
6.2.1 立体声(Stereo)
立体声,也称为双声道(Stereo),是一种音频系统,它使用两个独立的音频信号来模拟声音的方向性,从而创建出一种更为真实的音场环境。在立体声系统中,左声道(FL)和右声道(FR)的音频信号是独立的,它们可以分别连接到左右两个扬声器,从而模拟出声音的左右位置。
在FFmpeg中,我们可以使用AV_CH_LAYOUT_STEREO
来表示立体声的声道布局,它包含了左声道(FL)和右声道(FR)。
6.2.2 多声道音频处理(Multi-Channel Audio Processing)
除了立体声,还有很多其他的声道布局,例如5.1声道、7.1声道等。这些声道布局通常用于家庭影院系统,它们可以提供更为丰富和真实的音场环境。
在FFmpeg中,我们可以使用AV_CH_LAYOUT_5POINT1
、AV_CH_LAYOUT_7POINT1
等来表示不同的多声道声道布局。
在处理多声道音频数据时,我们需要注意声道的顺序。在FFmpeg中,声道的顺序是固定的,例如在5.1声道中,声道的顺序为FL、FR、FC、LFE、BL、BR。
6.3 声道布局的转换
在音频处理中,我们可能会遇到需要改变声道布局的情况,例如将立体声转换为单声道,或者将5.1声道转换为立体声。在FFmpeg中,我们可以使用swr_alloc_set_opts
函数来进行声道布局的转换。
6.3.1 立体声转单声道
立体声转单声道是一种常见的声道布局转换。在这种转换中,我们需要将左声道和右声道的音频数据合并为一个声道。
在FFmpeg中,我们可以设置swr_alloc_set_opts
函数的out_ch_layout
参数为AV_CH_LAYOUT_MONO
,并将in_ch_layout
参数设置为AV_CH_LAYOUT_STEREO
,然后调用swr_init
函数来初始化转换器。在转换音频数据时,我们可以使用swr_convert
函数。
6.3.2 5.1声道转立体声
5.1声道转立体声是另一种常见的声道布局转换。在这种转换中,我们需要将5.1声道的音频数据合并为两个声道。
在FFmpeg中,我们可以设置swr_alloc_set_opts
函数的out_ch_layout
参数为AV_CH_LAYOUT_STEREO
,并将in_ch_layout
参数设置为AV_CH_LAYOUT_5POINT1
,然后调用swr_init
函数来初始化转换器。在转换音频数据时,我们可以使用swr_convert
函数。
6.4 音频采样格式的处理
音频采样格式描述了音频数据的存储方式,例如,音频数据可以是整数或浮点数,可以是8位、16位、32位或64位,可以是有符号或无符号,等等。在FFmpeg中,音频采样格式由enum AVSampleFormat
表示。
6.4.1 音频采样格式的转换
在音频处理中,我们可能会遇到需要改变音频采样格式的情况,例如,将16位整数格式转换为32位浮点数格式。在FFmpeg中,我们可以使用swr_alloc_set_opts
函数来进行音频采样格式的转换。
在设置swr_alloc_set_opts
函数的参数时,我们需要将out_sample_fmt
参数设置为目标音频采样格式,将in_sample_fmt
参数设置为源音频采样格式,然后调用swr_init
函数来初始化转换器。在转换音频数据时,我们可以使用swr_convert
函数。
6.4.2 音频采样格式的查询
在FFmpeg中,我们可以使用av_get_sample_fmt_name
函数来获取音频采样格式的名称。这个函数接受一个enum AVSampleFormat
参数,返回一个表示音频采样格式名称的字符串。
例如,我们可以使用以下代码来获取音频采样格式的名称:
const char* sample_fmt_name = av_get_sample_fmt_name(codec_ctx_->sample_fmt);
在这段代码中,codec_ctx_->sample_fmt
是音频编解码器上下文中的音频采样格式,sample_fmt_name
是音频采样格式的名称。
6.5 音频采样率的处理
音频采样率描述了在一秒钟内对音频信号进行采样的次数,单位是Hz(赫兹)。常见的音频采样率有44100Hz、48000Hz等。在FFmpeg中,音频采样率由整数表示。
6.5.1 音频采样率的转换
在音频处理中,我们可能会遇到需要改变音频采样率的情况,例如,将44100Hz的音频转换为48000Hz的音频。在FFmpeg中,我们可以使用swr_alloc_set_opts
函数来进行音频采样率的转换。
在设置swr_alloc_set_opts
函数的参数时,我们需要将out_sample_rate
参数设置为目标音频采样率,将in_sample_rate
参数设置为源音频采样率,然后调用swr_init
函数来初始化转换器。在转换音频数据时,我们可以使用swr_convert
函数。
6.5.2 音频采样率的查询
在FFmpeg中,我们可以直接从音频编解码器上下文中获取音频采样率。例如,我们可以使用以下代码来获取音频采样率:
int sample_rate = codec_ctx_->sample_rate;
在这段代码中,codec_ctx_->sample_rate
是音频编解码器上下文中的音频采样率,sample_rate
是获取到的音频采样率。
6.6 音频声道数的处理
音频声道数描述了音频信号中的声道数量。常见的音频声道数有1(单声道)、2(立体声)、5(5.1环绕声)等。在FFmpeg中,音频声道数由整数表示。
6.6.1 音频声道数的转换
在音频处理中,我们可能会遇到需要改变音频声道数的情况,例如,将单声道音频转换为立体声音频。在FFmpeg中,我们可以使用swr_alloc_set_opts
函数来进行音频声道数的转换。
在设置swr_alloc_set_opts
函数的参数时,我们需要将out_ch_layout
参数设置为目标音频声道数对应的声道布局,将in_ch_layout
参数设置为源音频声道数对应的声道布局,然后调用swr_init
函数来初始化转换器。在转换音频数据时,我们可以使用swr_convert
函数。
6.6.2 音频声道数的查询
在FFmpeg中,我们可以直接从音频编解码器上下文中获取音频声道数。例如,我们可以使用以下代码来获取音频声道数:
int channels = codec_ctx_->channels;
在这段代码中,codec_ctx_->channels
是音频编解码器上下文中的音频声道数,channels
是获取到的音频声道数。
在下一节,我们将介绍如何处理不同的音频格式。
6.7 音频格式的处理
音频格式描述了音频数据的存储方式。常见的音频格式有PCM、FLTP等。在FFmpeg中,音频格式由枚举类型AVSampleFormat
表示。
6.7.1 音频格式的转换
在音频处理中,我们可能会遇到需要改变音频格式的情况,例如,将PCM格式的音频转换为FLTP格式的音频。在FFmpeg中,我们可以使用swr_alloc_set_opts
函数来进行音频格式的转换。
在设置swr_alloc_set_opts
函数的参数时,我们需要将out_sample_fmt
参数设置为目标音频格式,将in_sample_fmt
参数设置为源音频格式,然后调用swr_init
函数来初始化转换器。在转换音频数据时,我们可以使用swr_convert
函数。
6.7.2 音频格式的查询
在FFmpeg中,我们可以直接从音频编解码器上下文中获取音频格式。例如,我们可以使用以下代码来获取音频格式:
AVSampleFormat sample_fmt = codec_ctx_->sample_fmt;
在这段代码中,codec_ctx_->sample_fmt
是音频编解码器上下文中的音频格式,sample_fmt
是获取到的音频格式。