• 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

  • 相关阅读:
    学习minix 3(未完成)
    排序
    分析nat穿越(未完成)
    固定增量感知器
    分析7zip(未完成)
    分析easyVM 未完成)
    分析wrk,crk
    分析vczh的东东(未完成)
    标 题: 三维游戏里面的自动寻路的算法可能是什么样的?
    几个googlecode
  • 原文地址:https://www.cnblogs.com/madaha/p/9570574.html
Copyright © 2020-2023  润新知