PCM(Pulse Code Modulation,脈沖編碼調(diào)制)音頻數(shù)據(jù)是未經(jīng)壓縮的音頻采樣數(shù)據(jù)裸流,它是由模擬信號(hào)經(jīng)過采樣、量化、編碼轉(zhuǎn)換成的標(biāo)準(zhǔn)數(shù)字音頻數(shù)據(jù)。
描述PCM數(shù)據(jù)的6個(gè)參數(shù):
推薦的PCM數(shù)據(jù)播放工具:
//播放格式為f32le,單聲道,采樣頻率48000Hz的PCM數(shù)據(jù)
ffplay -f f32le -ac 1 -ar 48000 pcm_audio
如果是單聲道的音頻文件,采樣數(shù)據(jù)按時(shí)間的先后順序依次存入(有的時(shí)候也會(huì)采用LRLRLR方式存儲(chǔ),只是另一個(gè)聲道的數(shù)據(jù)為0),如果是雙聲道的話就按照LRLRLR的方式存儲(chǔ),存儲(chǔ)的時(shí)候與字節(jié)序有關(guān)。big-endian模式如下圖所示:
使用ffmpeg -formats命令,獲取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
s是有符號(hào),u是無符號(hào),f是浮點(diǎn)數(shù)。
be是大端,le是小端。
FFmpeg中音視頻數(shù)據(jù)基本上都有Packed和Planar兩種存儲(chǔ)方式,對(duì)于雙聲道音頻來說,Packed方式為兩個(gè)聲道的數(shù)據(jù)交錯(cuò)存儲(chǔ);Planar方式為兩個(gè)聲道分開存儲(chǔ)。假設(shè)一個(gè)L/R為一個(gè)采樣點(diǎn),數(shù)據(jù)存儲(chǔ)的方式如下所示:
FFmpeg音頻解碼后的數(shù)據(jù)是存放在AVFrame結(jié)構(gòu)中的。
下面為FFmpeg內(nèi)部存儲(chǔ)音頻使用的采樣格式,所有的Planar格式后面都有字母P標(biāo)識(shí)。
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
};
說明:
談到字節(jié)序的問題,必然牽涉到兩大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存儲(chǔ)數(shù)據(jù),而x86系列則采用little endian方式存儲(chǔ)數(shù)據(jù)。那么究竟什么是big endian,什么又是little endian?
big endian是指低地址存放最高有效字節(jié)(MSB,Most Significant Bit),而little endian則是低地址存放最低有效字節(jié)(LSB,Least Significant Bit)。
下面用圖像加以說明。比如數(shù)字0x12345678在兩種不同字節(jié)序CPU中的存儲(chǔ)順序如下所示:
Big Endian
低地址 高地址
----------------------------------------------------------------------------->
| 12 | 34 | 56 | 78 |
Little Endian
低地址 高地址
----------------------------------------------------------------------------->
| 78 | 56 | 34 | 12 |
所有網(wǎng)絡(luò)協(xié)議都是采用big endian的方式來傳輸數(shù)據(jù)的。所以也把big endian方式稱之為網(wǎng)絡(luò)字節(jié)序。當(dāng)兩臺(tái)采用不同字節(jié)序的主機(jī)通信時(shí),在發(fā)送數(shù)據(jù)之前都必須經(jīng)過字節(jié)序的轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)序后再進(jìn)行傳輸。
按照雙聲道的LRLRLR的PCM音頻數(shù)據(jù)可以通過將它們交叉的讀出來的方式來分離左右聲道的數(shù)據(jù)。
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;
}
聯(lián)系客服