IOS lame库 pcm转mp3 分析(方案二)

方案二:使用AudioQueues获取实时PCM音频流数据,调用lame转码,写入mp3文件

 

1.规定录制音频流相关参数

AudioStreamBasicDescription _format;


// 录制音频数据格式

    _format.mFormatID = kAudioFormatLinearPCM;

    // 标签格式

    _format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;

    // 语音每采样点占用位数[8/16/24/32]

    _format.mBitsPerChannel = 16;

    // 单通道双通道

    _format.mChannelsPerFrame = 1;

    // 每个数据包中的Bytes数量 &  每帧的Byte

    _format.mBytesPerPacket = _format.mBytesPerFrame = (_format.mBitsPerChannel / 8) * _format.mChannelsPerFrame;

    // 每个数据包中的帧数量

    _format.mFramesPerPacket = 1;

    // 录音采样率

    _format.mSampleRate = 8000.0f;


2.初始化lame

   

lame = lame_init();

lame_set_in_samplerate(lame, format.mSampleRate);       

lame_set_num_channels(lame, format.mChannelsPerFrame);       

lame_set_VBR(lame, vbr_default);        

lame_set_brate(lame, format.mBitsPerChannel);       

lame_set_quality(lame,2);

lame_init_params(lame);


3.打开mp3文件流

NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"test.mp3"];     

FILE *mp3 = fopen([path    cStringUsingEncoding:NSASCIIStringEncoding], "wb+");


4.音频队列回调音频缓冲数据并开始转码(仍然需要判断单通道&双通道)最后写入mp3文件

/*

         

@typedef    AudioQueueInputCallback

 当一个录音的音频队列已经填满其中一个缓冲区会调用回调函数

 @param      inUserData

 为录音数据创建一个新的音频队列(AudioQueueNewInput)中的标明的参数

 @param      inAQ

 音频队列调用回调函数

 @param      inBuffer

 音频队列中最新被填充满的最新的音频数据缓冲区

 @param      inStartTime

 

 @param      inNumberPacketDescriptions

 多少个数据包

 @param      inPacketDescs

 音频流数据包描述


typedef void (*AudioQueueInputCallback)( void * __nullable               inUserData,

                                         AudioQueueRef                   inAQ,

                                         AudioQueueBufferRef             inBuffer,

                                         const AudioTimeStamp *          inStartTime,

                                         UInt32                          inNumberPacketDescriptions,

                                         const AudioStreamPacketDescription * __nullable inPacketDescs);

*/

    

int mp3DataSize = inNumberPacketDescriptions;

unsigned char mp3Buffer[mp3DataSize];

 

int encodedBytes = 0;

        

        /* AudioQueueBuffer 结构体

         typedef AudioQueueBuffer *AudioQueueBufferRef;

 

         mAudioData: 这是一个指向音频数据缓冲区的指针

         inNumberPacketDescriptions: 数据包

         */

        if (_format.mChannelsPerFrame == 1) {

            // 单通道

            encodedBytes = lame_encode_buffer( lame, inBuffer->mAudioData,NULL, inNumberPacketDescriptions, mp3Buffer, mp3DataSize);

      

        } else {

           

            // 双通道

            encodedBytes = lame_encode_buffer_interleaved(lame, inBuffer->mAudioData, inNumberPacketDescriptions, mp3Buffer, mp3DataSize);

        }

        

        fwrite(mp3Buffer, encodedBytes, 1, mp3);


5.找到mp3文件播放测试

 

 

参考资料:

http://www.cocoachina.com/bbs/read.php?tid=203683

https://blog.csdn.net/jiangyiaxiu/article/details/9190035

posted on 2018-09-01 15:34  马大哈哈  阅读(598)  评论(0编辑  收藏  举报

导航