赞
踩
PCM(Pulse Code Modulation,脉冲编码调制)音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样、量化、编码转换成的标准数字音频数据。
描述PCM数据的6个参数:
字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
大端字节序(Big Endian):将多个字节值的最高有效字节储存于较低的内存位置。在大端处理器的机器上,数值0xABCD1234在内存存储为连续字节0xAB、0xCD、0x12、0x34。
小端字节序(Little endian):将多个字节值的最低有效字节存储于较低的内存位置。比如在小段处理器的机器上,数值0xABCD1234在内存中存储为连续的字节0x34、0x12、0xCD、0x341。
在cmder中使用ffmpeg -formats | grep PCM
命令,获取ffmpeg支持的音视频格式,其中我们可以找到支持的PCM格式。
DE alaw PCM A-law DE f32be PCM 32-bit floating-point big-endian DE f32le PCM 32-bit floating-point little-endian DE f64be PCM 64-bit floating-point big-endian DE f64le PCM 64-bit floating-point little-endian DE mulaw PCM mu-law DE s16be PCM signed 16-bit big-endian DE s16le PCM signed 16-bit little-endian DE s24be PCM signed 24-bit big-endian DE s24le PCM signed 24-bit little-endian DE s32be PCM signed 32-bit big-endian DE s32le PCM signed 32-bit little-endian DE s8 PCM signed 8-bit DE u16be PCM unsigned 16-bit big-endian DE u16le PCM unsigned 16-bit little-endian DE u24be PCM unsigned 24-bit big-endian DE u24le PCM unsigned 24-bit little-endian DE u32be PCM unsigned 32-bit big-endian DE u32le PCM unsigned 32-bit little-endian DE u8 PCM unsigned 8-bit DE vidc PCM Archimedes VIDC
s是有符号,u是无符号,f是浮点数。
be是大端,le是小端。
FFmpeg中音视频数据基本上都有Packed(打包格式)和Planar(平面格式)两种存储方式,对于双声道音频来说,Packed方式为两个声道的数据交错存储;Planar方式为两个声道分开存储。假设一个L/R为一个采样点,数据存储的方式如下所示:
FFmpeg音频解码后的数据是存放在AVFrame结构中的。
下面为FFmpeg内部存储音频使用的采样格式,所有的Planar格式后面都有字母P标识。
enum AVSampleFormat { AV_SAMPLE_FMT_NONE = -1, AV_SAMPLE_FMT_U8, ///< unsigned 8 bits AV_SAMPLE_FMT_S16, ///< signed 16 bits AV_SAMPLE_FMT_S32, ///< signed 32 bits AV_SAMPLE_FMT_FLT, ///< float AV_SAMPLE_FMT_DBL, ///< double AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar AV_SAMPLE_FMT_FLTP, ///< float, planar AV_SAMPLE_FMT_DBLP, ///< double, planar AV_SAMPLE_FMT_S64, ///< signed 64 bits AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically };
说明:
先用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.000000Z
vendor_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.000000Z
vendor_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
输出
文件-原理音频
按照双声道的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); //L fwrite(sample, 1, 2, fp1); //R fwrite(sample + 2, 1, 2, fp2); } free(sample); fclose(fp); fclose(fp1); fclose(fp2); return 0; }
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)
成功读取的元素总数会以 size_t
对象返回,size_t
对象是一个整型数据类型。如果总数与 nmemb
参数不同,则可能发生了一个错误或者到达了文件末尾。
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)
如果成功,该函数返回一个 size_t
对象,表示元素的总数,该对象时一个整型数据类型。如果该数字与 nmemb
参数不同,则会显示一个错误。
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 来标识错误。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。