iOS的音频文件的格式转换

时间:2022-10-20 19:46:43

背景

因为我的公司需要设计到app与硬件的通信,所以去年深入的研究了一下音频各种格式的转换,曾写过一篇简书(https://www.jianshu.com/p/2937ab95c0f2),现在搬过来丰富下自己的blog。

首先介绍一下常用的音频文件格式

.amr:体积很小,1秒到约为1kb,所以音质缩水也很厉害,一般用于手机铃声或彩信

.mp3:比较流行的,有损音频,某些部分失真,,音质随码率的提高,越高越好

.wav:为无损音频

.pcm:无损的wav文件中音频数据的一种编码方式

由于App是通过AVAudioRecorder录制音频,默认格式为pcm,文件比较大,所以不适合用于聊天通信的文件格式,所以最优的选择是转换成amr格式

音频格式转换方式

.pcm-->.wav-->.amr

    a)将pcm转成wav

        http://www.jianshu.com/p/1d1f893e53e9这里详细写了pcm和wav的区别,我简单概括成pcm少了一个wav头描述信息。为此我从讯飞语音的sdk中移植出填写wav头的函数并修改了一下

// 为pcm文件写入wav头
+ (NSData*) writeWavHead:(NSData *)audioData {
    long sampleRate = [[self GetAudioRecorderSettingDict][AVSampleRateKey] longValue];
    long numOfChannelsKey = [[self GetAudioRecorderSettingDict][AVNumberOfChannelsKey] longValue];
    Byte waveHead[44];
    waveHead[0] = 'R';
    waveHead[1] = 'I';
    waveHead[2] = 'F';
    waveHead[3] = 'F';
    
    long totalDatalength = [audioData length] + 44;
    waveHead[4] = (Byte)(totalDatalength & 0xff);
    waveHead[5] = (Byte)((totalDatalength >> 8) & 0xff);
    waveHead[6] = (Byte)((totalDatalength >> 16) & 0xff);
    waveHead[7] = (Byte)((totalDatalength >> 24) & 0xff);
    
    waveHead[8] = 'W';
    waveHead[9] = 'A';
    waveHead[10] = 'V';
    waveHead[11] = 'E';
    
    waveHead[12] = 'f';
    waveHead[13] = 'm';
    waveHead[14] = 't';
    waveHead[15] = ' ';
    
    waveHead[16] = 16;  //size of 'fmt '
    waveHead[17] = 0;
    waveHead[18] = 0;
    waveHead[19] = 0;
    
    waveHead[20] = 1;   //format
    waveHead[21] = 0;
    
    waveHead[22] = numOfChannelsKey;   //chanel
    waveHead[23] = 0;
    
    waveHead[24] = (Byte)(sampleRate & 0xff);
    waveHead[25] = (Byte)((sampleRate >> 8) & 0xff);
    waveHead[26] = (Byte)((sampleRate >> 16) & 0xff);
    waveHead[27] = (Byte)((sampleRate >> 24) & 0xff);
    
    long byteRate = sampleRate * 2 * (16 >> 3);;
    waveHead[28] = (Byte)(byteRate & 0xff);
    waveHead[29] = (Byte)((byteRate >> 8) & 0xff);
    waveHead[30] = (Byte)((byteRate >> 16) & 0xff);
    waveHead[31] = (Byte)((byteRate >> 24) & 0xff);
    
    waveHead[32] = 2*(16 >> 3);
    waveHead[33] = 0;
    
    waveHead[34] = 16;
    waveHead[35] = 0;
    
    waveHead[36] = 'd';
    waveHead[37] = 'a';
    waveHead[38] = 't';
    waveHead[39] = 'a';
    
    long totalAudiolength = [audioData length];
    
    waveHead[40] = (Byte)(totalAudiolength & 0xff);
    waveHead[41] = (Byte)((totalAudiolength >> 8) & 0xff);
    waveHead[42] = (Byte)((totalAudiolength >> 16) & 0xff);
    waveHead[43] = (Byte)((totalAudiolength >> 24) & 0xff);
    
    NSMutableData *pcmData = [[NSMutableData alloc]initWithBytes:&waveHead length:sizeof(waveHead)];
    [pcmData appendData:audioData];
    
    
    return pcmData;
    //    [pcmData writeToFile:kVoiceWav atomically:true];
    
}

        同时还需把关键的属性抽取出来(如:采样率,通道数…)

//录音格式的设置
+ (NSDictionary*)GetAudioRecorderSettingDict{
    NSDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:
                                   [NSNumber numberWithFloat: 8000],AVSampleRateKey, //采样率
                                   [NSNumber numberWithInt: kAudioFormatLinearPCM],AVFormatIDKey,
                                   [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,//采样位数 默认 16
                                   [NSNumber numberWithInt: 2], AVNumberOfChannelsKey,//通道的数目
                                   nil];
    return recordSetting;
}

    b)将wav转成amr

        使用VoiceConvert(by:Tang Xiaoping)库能将wav转成amr,后来发现环信的EaseUI框架中也使用了这个

        反过来转换也是差不多的

pcm<--->mp3

    这个就很简单了,用lame的框架进行转换,这个框架网上资料一大堆


本人为此花了不少时间整理了一下这些文件格式的转换方法

/**
 *  转换wav到amr
 *
 *  @param wavPath  wav文件路径
 *  @param isDelete 转换成功后是否删除源文件
 *
 *  @return NO 失败 YES成功
 */
+ (BOOL) wav2Amr:(NSString *)wavPath isDeleteSourchFile:(BOOL)isDelete;

/**
 *  转换amr到wav
 *
 *  @param amrPath  amr文件路径
 *  @param isDelete 转换成功后是否删除源文件
 *
 *  @return NO 失败 YES成功
 */
+ (BOOL) amr2Wav:(NSString *)amrPath isDeleteSourchFile:(BOOL)isDelete;

/**
 *  转换pcm到mp3
 *
 *  @param pcmPath  pcm文件路径
 *  @param isDelete 转换成功后是否删除源文件
 *
 *  @return NO 失败 YES成功
 */
+ (BOOL) pcm2Mp3: (NSString *)pcmPath isDeleteSourchFile:(BOOL)isDelete;
/**
 *  转换pcm到wav
 *
 *  @param pcmPath  pcm文件路径
 *  @param isDelete 转换成功后是否删除源文件
 *
 *  @return NO 失败 YES成功
 */
+ (BOOL) pcm2Wav: (NSString *)pcmPath isDeleteSourchFile:(BOOL)isDelete;

/**
 *  转换pcm到amr
 *
 *  @param pcmPath  pcm文件路径
 *  @param isDelete 转换成功后是否删除源文件
 *
 *  @return NO 失败 YES成功
 */
+ (BOOL) pcm2Amr:(NSString *)pcmPath isDeleteSourchFile:(BOOL)isDelete;

/**
 *  为pcm文件写入wav头    
 */
+ (NSData*) writeWavHead:(NSData *)audioData;
void conventToMp3(NSString *pcmFile,NSString *mp3File);

/**
	录音格式设置,转换的时候需要获取.(如:采样率、采样位数、通道的数目)
    建议使用此设置,如有修改,则转换amr时也要对应修改参数,比较麻烦
 
	@returns 录音设置
 */
+ (NSDictionary*)GetAudioRecorderSettingDict;

demo的下载地址https://github.com/qq631192328/PFAudio.git,如果觉得好麻烦点下星,如果有什么问题欢迎指正