本文记录了PCM音频采样数据处理,音频采样数据在视频播放器的解码流程中的位置如下图所示。pcm音频文件可以使用Audacity(https://www.audacityteam.org/)导入原始数据查看,我这里使用的是Cool Edit Pro,打开的时候注意选择单双声道和大小端就可以了。
包含如下几个处理函数:
- 分离PCM16LE双声道音频采样数据的左声道和右声道
- 将PCM16LE双声道音频采样数据中左声道的音量降一半
- 将PCM16LE双声道音频采样数据的声音速度提高一倍
- 将PCM16LE双声道音频采样数据转换为PCM8音频采样数据
- 从PCM16LE单声道音频采样数据中截取一部分数据
- 将PCM16LE双声道音频采样数据转换为WAVE格式音频数据
1) 分离PCM16LE双声道音频采样数据的左声道和右声道
/** * Split Left and Right channel of 16LE PCM file. * @param jstr_url Location of PCM file. * 分离PCM16LE双声道音频采样数据的左声道和右声道 * PCM16LE双声道数据中左声道和右声道的采样值是间隔存储的。每个采样值占用2Byte空间 * 例程中声音样值的采样频率一律是44100Hz,采样格式一律为16LE。“16”代表采样位数是16bit。由于1Byte=8bit,所以一个声道的一个采样值占用2Byte。“LE”代表Little Endian,代表2 Byte采样值的存储方式为高位存在高地址中 */extern "C" JNIEXPORT jint JNICALLJava_com_xohn_ffmpeg_AVUtils_pcm16leSplit( JNIEnv *env,jobject /* this */, jstring jstr_url) {char input_url[100] = {0};const char *str = env->GetStringUTFChars(jstr_url, NULL);sprintf(input_url,"%s",str);env->ReleaseStringUTFChars(jstr_url,str);FILE *fp = fopen(input_url,"rb+");if(fp == NULL) return -1;strcpy(input_url+strlen(input_url)-4,"_l.pcm");FILE *fp1 = fopen(input_url,"wb+");strcpy(input_url+strlen(input_url)-5,"r.pcm");FILE *fp2 = fopen(input_url,"wb+"); unsigned char *sample = (unsigned 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;}
函数调用
AVUtils.getInstance().pcm16leSplit(ROOT+"NocturneNo2inEflat_44.1k_s16le.pcm");
输入的双声道PCM数据的原始波形图如下。上面是左声道,下面是右声道;横坐标是时间,总长度为22秒;纵坐标是取样值,取值范围从-32768到32767
分离出来的左右声道图如下:
2) 将PCM16LE双声道音频采样数据中左声道的音量降一半
/** * Halve volume of Left channel of 16LE PCM file * @param jstr_url Location of PCM file. * 将PCM16LE双声道音频采样数据中左声道