【音視頻系列3】音頻MP3文件和PCM文件,分析PCM音頻文件,及轉換為WAV文件


音頻聲音文件MP3和PCM

  兩者均是封裝格式,為了分析PCM,先下載一個MP3文件,然后通過ffmpeg將MP3文件轉成PCM文件進行分析,使用分析軟件為audition音頻軟件。

轉換PCM文件

  ffmpeg -i hai.mp3 -f s16le audio1.pcm

  轉換后可以使用此命令播放看轉換是否成功:ffplay -ar 44100 -ac 2 -f s16le -i audio1.pcm

轉換后的文件放到audition中,並選擇采樣率和位寬后,便可以顯示音頻文件頻譜

  

 

   

  代碼分析PCM文件:

  PCM的左右聲道是間隔存放的,每個聲道占用2個字節,所以取值時需要間隔進行讀取並存放成左右兩個聲道

  源碼如下:

void pcm_spilit_channel(const char* pcmfile) {
	FILE* pcmFp = fopen(pcmfile, "rb+");
	FILE* pcmlFp = fopen("E:\\audio_leftC.pcm", "wb+");
	FILE* pcmrFp = fopen("E:\\audio_rightC.pcm", "wb+");
	unsigned char* samples = (unsigned char*)malloc(4);
	while (!feof(pcmFp))
	{
		fread(samples, 1, 4, pcmFp);
		fwrite(samples, 1, 2, pcmlFp);
		fwrite(samples + 2, 1, 2, pcmrFp);
	}
	free(samples);
	fclose(pcmrFp);
	fclose(pcmlFp);
	fclose(pcmFp);
}

  分離左右聲道后,音頻文件同樣的設置后通過audition進行查看 

  

 WAVE文件格式,包含3個頭部結構和一個PCM數據塊,具體如下:

  

使用C++將pcm音頻轉換為wav音頻文件

typedef struct {
	char			fccID[4];
	unsigned long	dwSize;
	char			fccType[4];
}WAV_HEADER;
typedef struct
{
	char			fccID[4];
	unsigned long	dwSize;
	unsigned short	wFromatTag;
	unsigned short	wChannels;
	unsigned long	dwSamplesPerSec;
	unsigned long	dwAvgBytesPerSec;
	unsigned short	wBlockAlign;
	unsigned short	uiBitsPerSample;
}WAV_FMT;
typedef struct {
	char			fccID[4];
	unsigned long	dwSize;
}WAV_DATA;
void pcm2wav(const char* pcmfile, int channel, int sampleRate, const char* wavfile) {
	FILE* pcmFp = fopen(pcmfile, "rb+");
	FILE* wavFp = fopen(wavfile, "wb+");
	WAV_HEADER	wavHeader;
	WAV_FMT		wavFormat;
	WAV_DATA	wavData;
	unsigned short pcmData;
	int bits	= 16;
	memcpy(wavHeader.fccID, "RIFF", strlen("RRIF"));	//設置RIFF頭
	memcpy(wavHeader.fccType, "WAVE", strlen("WAVE"));	//設置WAVE標識
	
	memcpy(wavFormat.fccID, "fmt ", strlen("fmt "));	//設置第二塊頭“fmt ”
	wavFormat.dwSize = 16;								//WAV_FORMAT的大小- sizeof(fccID) - sizeof(dwSize)
	wavFormat.wFromatTag = 1;							//PCM格式文件時設置1
	wavFormat.wChannels = channel;						
	wavFormat.dwSamplesPerSec = sampleRate;				//比特率
	wavFormat.dwAvgBytesPerSec = sampleRate * sizeof(pcmData);	//碼率
	wavFormat.wBlockAlign = sizeof(pcmData);			//每個采樣點的字節對齊寬度
	wavFormat.uiBitsPerSample = bits;					//PCM采樣的位數

	memcpy(wavData.fccID, "data", strlen("data"));		//設置第三塊頭data
	int offset = sizeof(WAV_HEADER) + sizeof(WAV_FMT) + sizeof(WAV_DATA);
	int pcmDataCount = 0;
	fseek(wavFp, offset, SEEK_CUR);
	while (!feof(pcmFp)) {
		fread(&pcmData, sizeof(unsigned short), 1, pcmFp);
		fwrite(&pcmData, sizeof(unsigned short), 1, wavFp);
		pcmDataCount++;
	}
	pcmDataCount = pcmDataCount << 1;
	wavData.dwSize = pcmDataCount;						//設置大小為PCM數據的大小
	wavHeader.dwSize = pcmDataCount + sizeof(WAV_DATA) + sizeof(WAV_FMT) + sizeof(WAV_HEADER) - 8;	//頭的大小為所有的大小-sizeof(WAV_HEADER.fccID)-sizeof(WAV_HEADER.dwSize)
	rewind(wavFp);
	fwrite(&wavHeader, 1, sizeof(wavHeader), wavFp);
	fwrite(&wavFormat, 1, sizeof(wavFormat), wavFp);
	fwrite(&wavData, 1, sizeof(wavData), wavFp);
	fclose(pcmFp);
	fclose(wavFp);
	return;
}

 注意:轉換后文件大小幾乎相同

轉換后文件可以播放,放到audition中可以看到波形圖正常即可

  

 

 由此可以了解PCM和wav文件格式,以及音頻在這兩種文件中的存放方式以及順序。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM