zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    数据挂载
    LVS学习与测试——NAT模式
    VirtualBox 网络设置 VirtualBox中客机与主机互通
    [原]两个android程序间的相互调用(apk互调)
    [置顶] Android Service与Activity之间通信的几种方式
    [置顶] android 开发中判断网络是否连接的代码
    [置顶] 判断时间格式是否正确
    [置顶] 输出map信息
    [置顶] checkEmail判断邮箱格式
    [置顶] checkPhone判断手机号格式
  • 原文地址:https://www.cnblogs.com/madaha/p/9570574.html
Copyright © 2011-2022 走看看