音视频从入门到精通——FFmpeg分离出PCM数据实战
什么是PCM?
PCM(Pulse Code Modulation,脉冲编码调制)音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样、量化、编码转换成的标准数字音频数据。
描述PCM数据的6个参数:
- Sample Rate : 采样频率。8kHz(电话)、44.1kHz(CD)、48kHz(DVD)。
- Sample Size : 量化位数。通常该值为16-bit。
- Number of Channels : 通道个数。常见的音频有立体声(stereo)和单声道(mono)两种类型,立体声包含左声道和右声道。另外还有环绕立体声等其它不太常用的类型。
- Sign : 表示样本数据是否是有符号位,比如用一字节表示的样本数据,有符号的话表示范围为-128 ~ 127,无符号是0 ~ 255。
- Byte Ordering : 字节序。字节序是little-endian还是big-endian。通常均为little-endian。字节序说明见第4节。
- Integer Or Floating Point : 整形或浮点型。大多数格式的PCM样本数据使用整形表示,而在一些对精度要求高的应用方面,使用浮点类型表示PCM样本数据。
字节序
字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
大端字节序(Big Endian):将多个字节值的最高有效字节储存于较低的内存位置。在大端处理器的机器上,数值0xABCD1234在内存存储为连续字节0xAB、0xCD、0x12、0x34。
小端字节序(Little endian):将多个字节值的最低有效字节存储于较低的内存位置。比如在小段处理器的机器上,数值0xABCD1234在内存中存储为连续的字节0x34、0x12、0xCD、0x341。
FFmpeg支持的PCM数据格式
在cmder中使用ffmpeg -formats | grep PCM
命令,获取ffmpeg支持的音视频格式,其中我们可以找到支持的PCM格式。
DE alaw PCM A-lawDE f32be PCM 32-bit floating-point big-endianDE f32le PCM 32-bit floating-point little-endianDE f64be PCM 64-bit floating-point big-endianDE f64le PCM 64-bit floating-point little-endianDE mulaw PCM mu-lawDE s16be PCM signed 16-bit big-endianDE s16le PCM signed 16-bit little-endianDE s24be PCM signed 24-bit big-endianDE s24le PCM signed 24-bit little-endianDE s32be PCM signed 32-bit big-endianDE s32le PCM signed 32-bit little-endianDE s8 PCM signed 8-bitDE u16be PCM unsigned 16-bit big-endianDE u16le PCM unsigned 16-bit little-endianDE u24be PCM unsigned 24-bit big-endianDE u24le PCM unsigned 24-bit little-endianDE u32be PCM unsigned 32-bit big-endianDE u32le PCM unsigned 32-bit little-endianDE u8 PCM unsigned 8-bitDE vidc PCM Archimedes VIDC
s是有符号,u是无符号,f是浮点数。
be是大端,le是小端。
FFmpeg中Packed和Planar的PCM数据区别
FFmpeg中音视频数据基本上都有Packed(打包格式)和Planar(平面格式)两种存储方式,对于双声道音频来说,Packed方式为两个声道的数据交错存储;Planar方式为两个声道分开存储。假设一个L/R为一个采样点,数据存储的方式如下所示:
- Packed: L R L R L R L R
- Planar: L L L L R R R R
FFmpeg音频解码后的数据是存放在AVFrame结构中的。
- Packed格式,frame.data[0]或frame.extended_data[0]包含所有的音频数据中。
- Planar格式,frame.data[i]或者frame.extended_data[i]表示第i个声道的数据(假设声道0是第一个), AVFrame.data数组大小固定为8,如果声道数超过8,需要从frame.extended_data获取声道数据。
下面为FFmpeg内部存储音频使用的采样格式,所有的Planar格式后面都有字母P标识。
enum AVSampleFormat {AV_SAMPLE_FMT_NONE = -1,AV_SAMPLE_FMT_U8, ///< unsigned 8 bitsAV_SAMPLE_FMT_S16, ///< signed 16 bitsAV_SAMPLE_FMT_S32, ///< signed 32 bitsAV_SAMPLE_FMT_FLT, ///< floatAV_SAMPLE_FMT_DBL, ///< doubleAV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planarAV_SAMPLE_FMT_S16P, ///< signed 16 bits, planarAV_SAMPLE_FMT_S32P, ///< signed 32 bits, planarAV_SAMPLE_FMT_FLTP, ///< float, planarAV_SAMPLE_FMT_DBLP, ///< double, planarAV_SAMPLE_FMT_S64, ///< signed 64 bitsAV_SAMPLE_FMT_S64P, ///< signed 64 bits, planarAV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
};
说明:
- Planar模式是ffmpeg内部存储模式,我们实际使用的音频文件都是Packed模式的。
- FFmpeg解码不同格式的音频输出的音频采样格式不是一样。测试发现,其中AAC解码输出的数据为浮点型的 AV_SAMPLE_FMT_FLTP 格式,MP3解码输出的数据为 AV_SAMPLE_FMT_S16P 格式(使用的mp3文件为16位深)。具体采样格式可以查看解码后的AVFrame中的format成员或解码器的AVCodecContext中的sample_fmt成员。
- Planar或者Packed模式直接影响到保存文件时写文件的操作,操作数据的时候一定要先检测音频采样格式。
实战FFmpeg分离出PCM数据
先用ffprobe
命令查看文件详情
ffprobe -i input.mp4
详情
#音频Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)Metadata:creation_time : 2020-10-12T15:12:33.000000Zvendor_id : [0][0][0][0]
#视频 Stream #0:1(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 368x384, 383 kb/s, 29.95 fps, 29.97 tbr, 90k tbn, 60 tbc (default)Metadata:creation_time : 2020-10-12T15:12:33.000000Zvendor_id : [0][0][0][0]encoder : JVT/AVC Coding
用ffmpeg
命令转换
ffmpeg -i input.mp4 -ar 44100 -ac 2 -f s16le output.pcm
其中
# 输入文件
-i
# 格式
-f fmt force format
#设置音频采样率
-ar rate set audio sampling rate (in Hz)
#设置音频通道数
-ac channels set number of audio channels
输出
Audicity播放
文件-原理音频
分离双声道PCM音频数据左右声道的数据
按照双声道的LRLRLR的PCM音频数据可以通过将它们交叉的读出来的方式来分离左右声道的数据。
int pcm_s16le_split(const char* file, const char* out_lfile, const char* out_rfile) {FILE *fp = fopen(file, "rb+");if (fp == NULL) {printf("open %s failed\n", file);return -1;}FILE *fp1 = fopen(out_lfile, "wb+");if (fp1 == NULL) {printf("open %s failed\n", out_lfile);return -1;}FILE *fp2 = fopen(out_rfile, "wb+");if (fp2 == NULL) {printf("open %s failed\n", out_rfile);return -1;}char * sample = (char *)malloc(4);while(!feof(fp)) {fread(sample, 1, 4, fp);//Lfwrite(sample, 1, 2, fp1);//Rfwrite(sample + 2, 1, 2, fp2);}free(sample);fclose(fp);fclose(fp1);fclose(fp2);return 0;}
函数说明
fread函数
描述
C 库函数 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
从给定流 stream 读取数据到 ptr 所指向的数组中。
声明
下面是 fread()
函数的声明。
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
参数
- ptr – 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
- size – 这是要读取的每个元素的大小,以字节为单位。
- nmemb – 这是元素的个数,每个元素的大小为 size 字节。
- stream – 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
返回值
成功读取的元素总数会以 size_t
对象返回,size_t
对象是一个整型数据类型。如果总数与 nmemb
参数不同,则可能发生了一个错误或者到达了文件末尾。
fwrite函数
描述
C 库函数 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
把 ptr 所指向的数组中的数据写入到给定流 stream 中。
声明
下面是 fwrite()
函数的声明。
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
参数
- ptr – 这是指向要被写入的元素数组的指针。
- size – 这是要被写入的每个元素的大小,以字节为单位。
- nmemb – 这是元素的个数,每个元素的大小为 size 字节。
- stream – 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。
返回值
如果成功,该函数返回一个 size_t
对象,表示元素的总数,该对象时一个整型数据类型。如果该数字与 nmemb
参数不同,则会显示一个错误。
fopen函数
描述
C 库函数 FILE *fopen(const char *filename, const char *mode)
使用给定的模式 mode 打开 filename 所指向的文件。
声明
下面是 fopen()
函数的声明。
FILE *fopen(const char *filename, const char *mode)
参数
filename
– 这是 C 字符串,包含了要打开的文件名称。mode
– 这是 C 字符串,包含了文件访问模式,模式如下:
模式 | 描述 |
---|---|
“r” | 打开一个用于读取的文件。该文件必须存在。 |
“w” | 创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。 |
“a” | 追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。 |
“r+” | 打开一个用于更新的文件,可读取也可写入。该文件必须存在。 |
“w+” | 创建一个用于读写的空文件。 |
“a+” | 打开一个用于读取和追加的文件。 |
返回值
该函数返回一个 FILE
指针。否则返回 NULL,且设置全局变量 errno 来标识错误。
参考
PCM音频数据
音视频从入门到精通——FFmpeg分离出PCM数据实战相关推荐
- 音视频从入门到精通——FFmpeg之swr_convert音频重采样函数分析
文章目录 音频重采样 swr_alloc函数 swr_alloc_set_opts函数 swr_init函数 swr_convert函数 音频基础 音频开发主要应用有 音频开发具体内容有 音频应用的难 ...
- 音视频从入门到精通——FFmpeg数据结构分析
FFmpeg数据结构分析 FFmpeg解码流程 重要结构体之间的关系 AVFormatContext iformat:输入媒体的AVInputFormat,比如指向AVInputFormat ff_f ...
- 音视频从入门到精通——FFmpeg 播放器实现音视频同步的三种方式
老人们经常说,播放器对音频和视频的播放没有绝对的静态的同步,只有相对的动态的同步,实际上音视频同步就是一个"你追我赶"的过程. 音视频的同步方式有 3 种,即:音视频分别向系统时钟 ...
- 音视频从入门到精通——ffmpeg3之打印多媒体文件音视频信息
ffmpeg3之打印多媒体文件音视频信息 av_dump_format函数 /*** Print detailed information about the input or output form ...
- 3 FFmpeg从入门到精通-FFmpeg转封装
1 FFmpeg从入门到精通-FFmpeg简介 2 FFmpeg从入门到精通-FFmpeg工具使用基础 3 FFmpeg从入门到精通-FFmpeg转封装 4 FFmpeg从入门到精通-FFmpeg转码 ...
- 1 FFmpeg从入门到精通-FFmpeg简介
1 FFmpeg从入门到精通-FFmpeg简介 2 FFmpeg从入门到精通-FFmpeg工具使用基础 3 FFmpeg从入门到精通-FFmpeg转封装 4 FFmpeg从入门到精通-FFmpeg转码 ...
- 4 FFmpeg从入门到精通-FFmpeg转码
1 FFmpeg从入门到精通-FFmpeg简介 2 FFmpeg从入门到精通-FFmpeg工具使用基础 3 FFmpeg从入门到精通-FFmpeg转封装 4 FFmpeg从入门到精通-FFmpeg转码 ...
- Android音视频学习系列(十) — 基于FFmpeg + OpenSL ES实现音频万能播放器
系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...
- Android 音视频开发入门指南
最近收到很多网友通过邮件或者留言说想学习音视频开发,该如何入门,我今天专门写篇文章统一回复下吧. 音视频这块,目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的,希望我后面能挤出时间整 ...
最新文章
- 11.2 uptime:显示系统的运行时间及负载
- 【PAT甲级 排序】1096 Consecutive Factors (20 分) C++ 全部AC
- android8 呼吸灯,红米note8pro呼吸灯颜色如何设置?
- android studio按钮槽函数,AndroidStudio按钮Button退出程序
- 来,我们谈谈怎么学好计算机科学与技术
- 笔记本新机全新安装XP时遇到问题的解决方案(针对新的Vista机型装xp的解决方案)...
- 学习Bash shell编程资料推荐
- Python-爬虫抓取视频
- RPM包安装卸载命令
- 这6点解释了罗永浩为什么要卖艺
- 继微博之后,.fans建站成饭圈新宠
- Vue如何引入粒子特效
- 什么是工作流?(转贴)
- 多线程-Callable接口
- 基恩士PLC导通检测程序
- Spring5之IOC
- Fast Compressive Tracking(快速压缩跟踪)算法的C++代码实现
- ImageNet2012数据集下载
- 大津阈值法(OTSU)功能实现
- 爬取猫眼十万条评论数据
热门文章
- php activedocument-printout(),php二种读取和创建word文档方法
- 计算机类期刊信息,如影响因子、分区等快速查询
- PHPExcel导出表格乱码解决
- SitePoint播客#47:将死苹果
- python求合数的所有因子,0是素数吗(python求一个数的因子)
- 2022年如何成为一名优秀的大前端Leader?
- python判断一个列表是否包含另一个列表_Python判断一个list中是否包含另一个list全部元素的方法分析...
- java jackson包_Jackson jar包的使用
- 新概念英语2如何背诵啊?
- ESP8266学习之路一——WiFi STA