IOS 实现录音PCM转MP3格式(边录音边转码)

51 篇文章 0 订阅

最近做的一个项目,项目中有个录音功能,采用的录音方法是IOS下的AVAudioRecorder。录音效果不错,但是录制的原生.pcm文件太大,每分钟大约10M左右。

找了下相关的音频压缩方法,用speex的比较多。按照speex的示例文档折腾了半天,实现了转码压缩。speex压缩率还蛮高的,但是压缩之后的pcm文件不能播放,

需要解码回来,可是按照示例代码解码之后的pcm文件依旧不能播放。百思不得解,遂google之,未果。得到只言片语,说是没有添加wav头云云。个人感觉录音得

到的pcm文件是有wav头的,因为录制好的文件由AVAudioPlayer播放的时候并不受文件后缀名影响。由于不了解speex的编码原理,也没时间继续深究,只好寻求其他办法。

下了一个比较靠谱的speex转码demo,仔细研究了一下。感觉蛮复杂的(对于我这个音频编解码门外汉来说),大致是先要跳过pcm里的wav头,获取到单纯的

pcm文件之后再行编解码,中间需要分析pcm祯什么的,反正我是弄不来这个,看着头都大了。

继续寻找更简单的解决办法。。。看到一篇介绍使用lame来转码到mp3文件的博客(http://ikinglai.blog.51cto.com/6220785/1228309),感觉比较靠谱,从lame官网下了库文

件,在命令行里打包了.o文件,(如果不知道怎么打包,试试http://download.csdn.net/download/ixfly/4440512)导入到工程里,按照demo试了下,果然好使!编码实现非常简

单,得到的mp3文件大小大概是pcm文件的1/10左右。

接下来就是实现边录边转码了。上面博客里提供的demo实际上就是采用了边录边转码的实现。但是有两个问题,一个问题是编译通不过(把工程里lame相关的库文件都移除,

导入刚才打包的.o文件,在.o文件同目录下要有lame.h和lame.c文件,但是不要导入这两个文件,否则编译错误,具体原因还得再查一下)。另一个问题是这个demo的录音

功能不是基于AVAudioRecorder实现的,用的是AVAudioQueue,基于数据缓冲实现的,可以实时获取录音的buffer数据,做边录边转码很方便。而AVAudioRecorder则不能

实时获得录音数据。

于是只能是对AVAudioRecorder生成的pcm文件读取来实现实时转码了。主要的思路是:录音开始后开启转码线程,转码线程读取pcm文件,设定每次转码的frame大小,当

读入的文件小于frame大小,就等待,当文件大于这个值时,则读取frame大小的文件,并转码,添加至data中。直到录音停止。

 
  1. -(void)main  
  2. {  
  3.     //mp3压缩参数  
  4.     lame = lame_init();  
  5.     lame_set_num_channels(lame, 2);  
  6.     lame_set_in_samplerate(lame, 88200);  
  7.     lame_set_brate(lame, 88);  
  8.     lame_set_mode(lame, 1);  
  9.     lame_set_quality(lame, 2);  
  10.     lame_init_params(lame);  
  11.       
  12.     //这种方式初始化的NSData不需要手动释放  
  13.     NSMutableData *mp3Data = [[NSMutableData alloc] init];  
  14.       
  15.     NSLog(@"record path: %@",_filePath);  
  16.     NSLog(@"out path: %@", _outFile);  
  17.     FILEFILE *fp;  
  18.     fp = fopen([_filePath cStringUsingEncoding:NSASCIIStringEncoding], "rb");  
  19.           
  20.     long curpos;  
  21.     //if(fp) 这句得补上,但是还不确定是否有问题  
  22.     while (true)  
  23.     {  
  24.         //需要手动释放  
  25.         NSData *audioData = nil;  
  26.          
  27.         curpos = ftell(fp);  
  28.         long startPos = ftell(fp);//文件当前读到的位置  
  29.         fseek(fp, 0, SEEK_END);  
  30.         long endPos = ftell(fp);//文件末尾位置  
  31.         long length = endPos - startPos;//剩下未读入文件长度  
  32.         fseek(fp, curpos, SEEK_SET);//把文件指针重新置回  
  33.           
  34.         charchar *buff[frameSize] = {0};  
  35.         if(length > frameSize)  
  36.         {  
  37.             fread(buff, 1, frameSize, fp);  
  38.             audioData = [NSData dataWithBytes:buff length:frameSize];  
  39.             shortshort *recordingData = (shortshort *)audioData.bytes;  
  40.             int pcmLen = audioData.length;  
  41.             int nsamples = pcmLen / 2;  
  42.               
  43.             unsigned char buffer[pcmLen];  
  44.               
  45.             //执行encode  
  46.             int recvLen = lame_encode_buffer(lame, recordingData, recordingData, nsamples, buffer, pcmLen);  
  47.             [mp3Data appendBytes:buffer length:recvLen];  
  48.       }  
  49.       else  
  50.       {  
  51.         if (_setToStopped)  
  52.         {  
  53.             fread(buff, 1, length, fp);  
  54.             audioData = [NSData dataWithBytes:buff length:length];  
  55.             shortshort *recordingData = (shortshort *)audioData.bytes;  
  56.             int pcmLen = audioData.length;  
  57.             int nsamples = pcmLen / 2;  
  58.               
  59.             unsigned char buffer[pcmLen];  
  60.               
  61.             //执行encode  
  62.             int recvLen = lame_encode_buffer(lame, recordingData, recordingData, nsamples, buffer, pcmLen);  
  63.             [mp3Data appendBytes:buffer length:recvLen];  
  64.             break;  
  65.         }  
  66.         else  
  67.         {  
  68.           [NSThread sleepForTimeInterval:0.05];  
  69.         }  
  70.       }  
  71.     }  
  72.     
  73.     //写入文件  
  74.     [mp3Data writeToFile:_outFile atomically:YES];  
  75.       
  76.     //释放lame  
  77.     lame_close(lame);  
  78. }  

现在是一个初步的代码,好多东西没有优化,只是实现了功能。相关代码文件之后补上。

原文地址:http://www.cnblogs.com/ios8/p/IOS-PCM-MP3.html

 

iOS 通过(lame)将录制音频转换成Mp3:http://blog.csdn.net/ysy441088327/article/details/7392842

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ios录音的caf文件MP3文件,以兼容android 注意音频参数的设置,如果声音异常,请调整参数。 code: AVAudioSession *session = [AVAudioSession sharedInstance]; NSError *sessionError; [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError]; _sampleRate = 11025;//8000;//44100; _quality = AVAudioQualityLow; if(session == nil) NSLog(@"Error creating session: %@", [sessionError description]); else [session setActive:YES error:nil]; NSString *cafFilePath = strCaf; // NSString *mp3FileName = @"Mp3File"; // mp3FileName = [mp3FileName stringByAppendingString:@".mp3"]; NSString *mp3FilePath = strMP3Path;//[[NSHomeDirectory() stringByAppendingFormat:@"/Documents/"] stringByAppendingPathComponent:mp3FileName]; @try { int read, write; FILE *pcm = fopen([cafFilePath cStringUsingEncoding:1], "rb"); //source fseek(pcm, 4*1024, SEEK_CUR); //skip file header FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb"); //output const int PCM_SIZE = 8192; const int MP3_SIZE = 8192; short int pcm_buffer[PCM_SIZE*2]; unsigned char mp3_buffer[MP3_SIZE]; lame_t lame = lame_init(); lame_set_in_samplerate(lame, _sampleRate); lame_set_VBR(lame, vbr_default); lame_init_params(lame); do { read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm); if (read == 0) write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE); else write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE); fwrite(mp3_buffer, write, 1, mp3); } while (read != 0); lame_close(lame); fclose(mp3); fclose(pcm); } @catch (NSException *exception) { NSLog(@"%@",[exception description]); } @finally { }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值