audioconverter

不同格式音频间的转换。

iOS平台提供了AudioConverter这个接口来实现转换,这个接口在内存实现转换,不需要写文件(ExtAudioFile是对文件的操作,内部使用audioconverter来转换)。

下面的例子演示从pcm转aac的实现(比如录音出来的数据保存成aac的需求)。

adts aac每一个packet都是独立可播放的包(同mp3),每一个packet带packet信息(包括packet长度、采样率、声道数等),整个文件不带文件头信息。

m4a格式:{packet-table}{audio_data}{trailer},头信息之后就是音频裸数据,不带packet信息。

audioconverter转换出来的都是音频裸数据,至于组合成adts-aac还是苹果的m4a(ipod容器),由程序决定。


typedef struct

{

    void *source;

    UInt32 sourceSize;

    UInt32 channelCount;

    AudioStreamPacketDescription *packetDescriptions;

}FillComplexInputParam;


OSStatus audioConverterComplexInputDataProc(  AudioConverterRef               inAudioConverter,

                                            UInt32*                         ioNumberDataPackets,

                                            AudioBufferList*                ioData,

                                            AudioStreamPacketDescription**  outDataPacketDescription,

                                            void*                           inUserData)

{

    FillComplexInputParam* param = (FillComplexInputParam*)inUserData;

    if (param->sourceSize <= 0) {

        *ioNumberDataPackets = 0;

        return -1;

    }

    ioData->mBuffers[0].mData = param->source;

    ioData->mBuffers[0].mNumberChannels = param->channelCount;

    ioData->mBuffers[0].mDataByteSize = param->sourceSize;

    *ioNumberDataPackets = 1;

    param->sourceSize = 0;

    param->source = NULL;

    return noErr;

}


typedef struct _tagConvertContext {

    AudioConverterRef converter;

    int samplerate;

    int channels;

}ConvertContext;


// init

void* convert_init(int sample_rate, int channel_count)

{

    AudioStreamBasicDescription sourceDes;

    memset(&sourceDes, 0, sizeof(sourceDes));

    sourceDes.mSampleRate = sample_rate;

    sourceDes.mFormatID = kAudioFormatLinearPCM;

    sourceDes.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;

    sourceDes.mChannelsPerFrame = channel_count;

    sourceDes.mBitsPerChannel = 16;

    sourceDes.mBytesPerFrame = sourceDes.mBitsPerChannel/8*sourceDes.mChannelsPerFrame;

    sourceDes.mBytesPerPacket = sourceDes.mBytesPerFrame;

    sourceDes.mFramesPerPacket = 1;

    sourceDes.mReserved = 0;

    

    AudioStreamBasicDescription targetDes;

    memset(&targetDes, 0, sizeof(targetDes));

    targetDes.mFormatID = kAudioFormatMPEG4AAC;

    targetDes.mSampleRate = sample_rate;

    targetDes.mChannelsPerFrame = channel_count;

    UInt32 size = sizeof(targetDes);

    AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &targetDes);

    

    AudioClassDescription audioClassDes;

    memset(&audioClassDes, 0, sizeof(AudioClassDescription));

    AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders, sizeof(targetDes.mFormatID), &targetDes.mFormatID, &size);

    int encoderCount = size / sizeof(AudioClassDescription);

    AudioClassDescription descriptions[encoderCount];

    AudioFormatGetProperty(kAudioFormatProperty_Encoders, sizeof(targetDes.mFormatID), &targetDes.mFormatID, &size, descriptions);

    for (int pos = 0; pos < encoderCount; pos ++) {

        if (targetDes.mFormatID == descriptions[pos].mSubType && descriptions[pos].mManufacturer == kAppleSoftwareAudioCodecManufacturer) {

            memcpy(&audioClassDes, &descriptions[pos], sizeof(AudioClassDescription));

            break;

        }

    }

    

    ConvertContext *convertContex = malloc(sizeof(ConvertContext));

    OSStatus ret = AudioConverterNewSpecific(&sourceDes, &targetDes, 1, &audioClassDes, &convertContex->converter);

    if (ret == noErr) {

        AudioConverterRef converter = convertContex->converter;

        

        tmp = kAudioConverterQuality_High;

        AudioConverterSetProperty(converter, kAudioConverterCodecQuality, sizeof(tmp), &tmp);

        

        UInt32 bitRate = 96000;

        UInt32 size = sizeof(bitRate);

        ret = AudioConverterSetProperty(converter, kAudioConverterEncodeBitRate, size, &bitRate);

    }

    else {

        free(convertContex);

        convertContex = NULL;

    }

    

    return convertContex;

}


// converting

void convert(void* convertContext, void* srcdata, int srclen, void** outdata, int* outlen)

{

    ConvertContext* convertCxt = (ConvertContext*)convertContext;

    if (convertCxt && convertCxt->converter) {

        UInt32 theOuputBufSize = srclen;  

        UInt32 packetSize = 1;

        void *outBuffer = malloc(theOuputBufSize);

        memset(outBuffer, 0, theOuputBufSize);

        

        AudioStreamPacketDescription *outputPacketDescriptions = NULL;

        outputPacketDescriptions = (AudioStreamPacketDescription*)malloc(sizeof(AudioStreamPacketDescription) * packetSize);

        

        FillComplexInputParam userParam;

        userParam.source = srcdata;

        userParam.sourceSize = srclen;

        userParam.channelCount = convertCxt->channels;

        userParam.packetDescriptions = NULL;

        

        OSStatus ret = noErr;

        

        AudioBufferList* bufferList = malloc(sizeof(AudioBufferList));

        AudioBufferList outputBuffers = *bufferList;

        outputBuffers.mNumberBuffers = 1;

        outputBuffers.mBuffers[0].mNumberChannels = convertCxt->channels;

        outputBuffers.mBuffers[0].mData = outBuffer;

        outputBuffers.mBuffers[0].mDataByteSize = theOuputBufSize;

        ret = AudioConverterFillComplexBuffer(convertCxt->converter, audioConverterComplexInputDataProc, &userParam, &packetSize, &outputBuffers, outputPacketDescriptions);

        if (ret == noErr) {

            if (outputBuffers.mBuffers[0].mDataByteSize > 0) {

                

                NSData* rawAAC = [NSData dataWithBytes:outputBuffers.mBuffers[0].mData length:outputBuffers.mBuffers[0].mDataByteSize];

                *outdata = malloc([rawAAC length]);

                memcpy(*outdata, [rawAAC bytes], [rawAAC length]);

                *outlen = (int)[rawAAC length];

#if 1

                int headerLength = 0;

                char* packetHeader = newAdtsDataForPacketLength((int)[rawAAC length], convertCxt->samplerate, convertCxt->channels, &headerLength);

                NSData* adtsPacketHeader = [NSData dataWithBytes:packetHeader length:headerLength];

                free(packetHeader);

                NSMutableData* fullData = [NSMutableData dataWithData:adtsPacketHeader];

                [fullData appendData:rawAAC];

                

                NSFileManager *fileMgr = [NSFileManager defaultManager];

                NSString *filepath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/test%p.aac", convertCxt->converter];

                NSFileHandle *file = nil;

                if (![fileMgr fileExistsAtPath:filepath]) {

                    [fileMgr createFileAtPath:filepath contents:nil attributes:nil];

                }

                file = [NSFileHandle fileHandleForWritingAtPath:filepath];

                [file seekToEndOfFile];

                [file writeData:fullData];

                [file closeFile];

#endif

            }

        }

        

        free(outBuffer);

        if (outputPacketDescriptions) {

            free(outputPacketDescriptions);

        }

    }

}


// uninit

....


/**

 *  Add ADTS header at the beginning of each and every AAC packet.

 *  This is needed as MediaCodec encoder generates a packet of raw

 *  AAC data.

 *

 *  Note the packetLen must count in the ADTS header itself.

 *  See: http://wiki.multimedia.cx/index.php?title=ADTS

 *  Also: http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio#Channel_Configurations

 **/

//- (NSData*) adtsDataForPacketLength:(NSUInteger)packetLength {

char* newAdtsDataForPacketLength(int packetLength, int samplerate, int channelCount, int* ioHeaderLen) {

    int adtsLength = 7;

    char *packet = malloc(sizeof(char) * adtsLength);

    // Variables Recycled by addADTStoPacket

    int profile = 2//AAC LC

    //39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;

    int freqIdx = freqIdxForAdtsHeader(samplerate);

    int chanCfg = channelIdxForAdtsHeader(channelCount);  //MPEG-4 Audio Channel Configuration.

    NSUInteger fullLength = adtsLength + packetLength;

    // fill in ADTS data

    packet[0] = (char)0xFF; // 11111111  = syncword

    packet[1] = (char)0xF9; // 1111 1 00 1  = syncword MPEG-2 Layer CRC

    packet[2] = (char)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));

    packet[3] = (char)(((chanCfg&3)<<6) + (fullLength>>11));

    packet[4] = (char)((fullLength&0x7FF) >> 3);

    packet[5] = (char)(((fullLength&7)<<5) + 0x1F);

    packet[6] = (char)0xFC;

//    NSData *data = [NSData dataWithBytesNoCopy:packet length:adtsLength freeWhenDone:YES];

//    return data;

    *ioHeaderLen = adtsLength;

    return packet;

}




万能音频转换(Bigasoft Audio Converter) 可以在不同的音频格式间进行快速转换,支持的音频格式包括MP3,WMA,M4A,AAC,AC3, WAV, OGG, AIFF, ALAC, FLAC, CAF等。这款数字音频转换器同时也是MP3转换器、WMA转换器、M4A转换器等等。而且,这款MP3音频转换器支持批量转换,从而可以一次性地转换多个音乐文件。 Bigasoft Audio Converter可以从所有热门电影或音乐视频中快速提取高品质音轨,它支持的视频格式包括AVI, MPEG, MP4, MPG, 3GP, DivX, Xvid, ASF, VOB, MKV, WMV, H.264等 Bigasoft Audio Converter特色: 在任何地方听到的歌曲 Bigasoft音频转换器提供了一种快速的方法来将音乐格式转换成带你美妙的音乐在任何地方,当你想听到的歌曲。 你可以听你喜欢的歌曲在iPod,iPhone、黑莓手机,PSP,PS3,Zune,MP4播放器,等等。 转换音乐文件 音频转换器可以帮助您轻松地转换音频之间的几乎所有格式包括MP3,WMA,M4A,AAC、AC3,WAV,OGG,等。数字音频转换器可以用作MP3转换器,的WMA转换器,M4A转换器,等等。 转换成MP3音频 MP3音频转换器很容易转换成MP3音频格式的WMA,M4A,AAC等等。 音频mp3转换器是一款集所有功能于一身的超级强大的mp3音频转换软件。 音频分配器 智能音频分配器工具就能轻易的把音频文件到无数个人声音跟踪你。 这也完全支持分割音频文件基于标记或章基于无缝。 提示文件。 享受音乐从音乐视频 视频音频转换器允许您从所有流行的电影或音乐视频中提取音轨,如AVI、MPEG、MP4、MPG,VOB,MKV,WMV等。 批处理转换 现在有批处理音频转换,转换专业视频音频转换器支持大量的音乐或电影。 此外,它可以关闭你的电脑后自动转换。 暂停和恢复转换 在转换期间,您可以暂停、恢复您将转换或停止转换。 听到之前转换 之前听音乐剪辑音频转换可以节省你的时间。 易于使用的 友好的用户界面,音频转换工具适合退伍军人和初学者可以完成转换,1-2-3。 支持预览 这是一个功能强大的视频播放器,可以播放和预览视频和音频在各种格式。您可以在同一个窗口预览视频源和视频输出功能。 易于使用 点击几下都是你需要做的,转换视频。 批量转换和批量编辑。 它可以让你很容易地在点击转换多个视频文件。此外,您还可以编辑视频效果,如修剪,调整音频音量。 所有的编码器和解码器是内置在 完全支持所有流行的视频和音频格式。 最快的转换速度 提供最快的转换速度,完全支持多线程和双核心的CPU。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值