美文网首页
iOS 通过lame将录制音频转换成Mp3

iOS 通过lame将录制音频转换成Mp3

作者: 街角仰望 | 来源:发表于2018-03-26 15:10 被阅读103次

    下载

    1、下载编译脚本:https://github.com/kewlbear/lame-ios-build
    2、下载lame:http://lame.sourceforge.net
    3、新建文件夹用来存放下载下来的lame和脚本文件
    4、在新建的文件夹下运行:./build-lame.sh,运行结果如下图

    编译完成后生成fat-lame文件夹,将fat-lame文件夹中的lame.hlibmp3lame.a导入工程即可

    使用

    将编译完成后的lame库加入到工程中

    注意:
    1、初始化lame的时候,要设置1为单通道。设置单声道会更大程度减少压缩后文件的体积。
    lame_set_num_channels(lame,1); //设置1为单通道,默认为2双通道
    2、lame_close(lame); 之前需要添加:
    lame_mp3_tags_fid(lame, mp3);// 可解决获取时长不准的问题

    引入库头文件

    //ConvertAudioFile.m
    #import "lame.h"
    

    录制完成后转码

    //这是录完再转码的方法, 如果录音时间比较长的话,会要等待几秒...
    + (void)conventToMp3WithCafFilePath:(NSString *)cafFilePath
                            mp3FilePath:(NSString *)mp3FilePath
                             sampleRate:(int)sampleRate
                               callback:(void(^)(BOOL result))callback
    {
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
            @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 输出生成的Mp3文件位置
    
                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_num_channels(lame,1);//设置1为单通道,默认为2双通道
                lame_set_in_samplerate(lame, sampleRate);
                lame_set_VBR(lame, vbr_default);
                lame_init_params(lame);
    
                do {
    
                    read = (int)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_mp3_tags_fid(lame, mp3);
    
                lame_close(lame);
                fclose(mp3);
                fclose(pcm);
            }
            @catch (NSException *exception) {
                NSLog(@"%@",[exception description]);
                if (callback) {
                    callback(NO);
                }
            }
            @finally {
                NSLog(@"-----\n  MP3生成成功: %@   -----  \n", mp3FilePath);
                if (callback) {
                    callback(YES);
                }
            }
        });
    

    调用

    [ConvertAudioFile conventToMp3WithCafFilePath:self.cafPathmp3FilePath:self.mp3Path
    
    {
    
    sampleRate:ETRECORD_RATE callback:^(BOOL result)
    
    NSLog(@"---- 转码完成 --- result %d ---- ", result);}];
    

    边录制边转码

    通常我们是在录制结束之后, 再进行转码; 当录制的时间较长 , 会消耗的时间比较长,用户需要等待转码结束后,才能操作; 但是如果我们使用边录制,边转码的方式, 开另外开个线程同时进行转码,则几乎没有等待的时间。

    具体实现方法:当录音进行中时, 会持续读取到指定大小文件来进行编码,读取不到,则线程休眠在while的条件中, 我们收到录音结束的条件,则会结束do while的循环。我们需要在录制结束后发送个信号, 让 do while跳出循环。

    - (void)conventToMp3WithCafFilePath:(NSString *)cafFilePath
                            mp3FilePath:(NSString *)mp3FilePath
                             sampleRate:(int)sampleRate
                               callback:(void(^)(BOOL result))callback
    {
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            
            @try {
                int read, write;
                
                FILE *pcm = fopen([cafFilePath cStringUsingEncoding:1], "rb");  //source 被转换的音频文件位置
                FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb+");  //output 输出生成的Mp3文件位置
                
                const int PCM_SIZE = 8192;
                const int MP3_SIZE = 8192;
                short int pcm_buffer[PCM_SIZE*2];
                unsigned char mp3_buffer[MP3_SIZE];
                
                //这里要注意,lame的配置要跟AVAudioRecorder的配置一致,否则会造成转换不成功
                lame_t lame = lame_init();
                lame_set_num_channels(lame,1);//设置1为单通道,默认为2双通道 设置单声道会更大程度减少压缩后文件的体积
                lame_set_in_samplerate(lame, sampleRate);//采样率
                lame_set_VBR(lame, vbr_default);
                lame_init_params(lame);
                
                BOOL isSkipPCMHeader = NO;
                
                __weak typeof(self) weakSelf = self;
                
                do {
                    long curpos = ftell(pcm);
                    long startPos = ftell(pcm);
                    fseek(pcm, 0, SEEK_END);
                    long endPos = ftell(pcm);
                    long length = endPos - startPos;
                    fseek(pcm, curpos, SEEK_SET);
                    
                    if (length > PCM_SIZE * 2 * sizeof(short int)) {
                        
                        if (!isSkipPCMHeader) {
                            //Uump audio file header, If you do not skip file header
                            //you will heard some noise at the beginning!!!
                            fseek(pcm, 4 * 1024, SEEK_CUR);
                            isSkipPCMHeader = YES;
                            NSLog(@"skip pcm file header !!!!!!!!!!");
                        }
                        
                        read = (int)fread(pcm_buffer, 2 * sizeof(short int), PCM_SIZE, pcm);
                        write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer,
                                                               MP3_SIZE);
                        fwrite(mp3_buffer, write, 1, mp3);
                        
                        NSLog(@"read %d bytes", write);}
                    
                    else {
                            
                            [NSThread sleepForTimeInterval:0.05];
                            
    //                        MyLog(@"sleep");
                        
                    }
                    
                } while (! weakSelf.stopRecord);
                
                lame_mp3_tags_fid(lame, mp3);// 解决获取时长不准的问题
                
                lame_close(lame);
                fclose(mp3);
                fclose(pcm);
            }
            @catch (NSException *exception) {
                MyLog(@"%@",[exception description]);
                if (callback) {
                    callback(NO);
                }
            }
            @finally {
                MyLog(@"-----\n  MP3生成成功: %@   -----  \n", mp3FilePath);
                if (callback) {
                    callback(YES);
                }
            }
        });
    }
    

    调用

    [[ConvertAudioFile sharedInstance] conventToMp3WithCafFilePath:self.cafPathmp3FilePath:self.mp3Path
    
    sampleRate:ETRECORD_RATE callback:^(BOOL result)
    
    {
    NSLog(@"---- 转码完成 --- result %d ---- ", result);
    
    }];
    

    参考:
    https://blog.csdn.net/u011270282/article/details/77483359
    https://blog.csdn.net/lovechris00/article/details/79034036
    https://blog.csdn.net/ysy441088327/article/details/7392842
    https://blog.csdn.net/lovechris00/article/details/52033555

    相关文章

      网友评论

          本文标题:iOS 通过lame将录制音频转换成Mp3

          本文链接:https://www.haomeiwen.com/subject/boixcftx.html