php caf 转wav,iOS音频格式m4a、caf、amr的相互转换

这几年做了许多涉及到音视频的app,里面有很多时候需要要转换格式,比如在合成拼接的时候,或者与服务器所需格式不一致的时候。我在此总结了几种常见格式间的互相转换。希望能帮到广告开发同行们。

一、m4a格式转caf格式

/**

把.m4a转为.caf格式

@param originalUrlStr .m4a文件路径

@param destUrlStr .caf文件路径

@param completed 转化完成的block

*/

+ (void)convetM4aToWav:(NSString *)originalUrlStr

destUrl:(NSString *)destUrlStr

completed:(void (^)(NSError *error)) completed {

if ([[NSFileManager defaultManager] fileExistsAtPath:destUrlStr]) {

[[NSFileManager defaultManager] removeItemAtPath:destUrlStr error:nil];

}

NSURL *originalUrl = [NSURL fileURLWithPath:originalUrlStr];

NSURL *destUrl = [NSURL fileURLWithPath:destUrlStr];

AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:originalUrl options:nil];

//读取原始文件信息

NSError *error = nil;

AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:songAsset error:&error];

if (error) {

DebugLog (@"error: %@", error);

completed(error);

return;

}

AVAssetReaderOutput *assetReaderOutput = [AVAssetReaderAudioMixOutput

assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks

audioSettings: nil];

if (![assetReader canAddOutput:assetReaderOutput]) {

DebugLog (@"can't add reader output... die!");

completed(error);

return;

}

[assetReader addOutput:assetReaderOutput];

AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:destUrl

fileType:AVFileTypeCoreAudioFormat

error:&error];

if (error) {

DebugLog (@"error: %@", error);

completed(error);

return;

}

AudioChannelLayout channelLayout;

memset(&channelLayout, 0, sizeof(AudioChannelLayout));

channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;

NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:

[NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,

[NSNumber numberWithFloat:44100], AVSampleRateKey,

[NSNumber numberWithInt:2], AVNumberOfChannelsKey,

[NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,

[NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,

[NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,

[NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,

nil];

AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio

outputSettings:outputSettings];

if ([assetWriter canAddInput:assetWriterInput]) {

[assetWriter addInput:assetWriterInput];

} else {

DebugLog (@"can't add asset writer input... die!");

completed(error);

return;

}

assetWriterInput.expectsMediaDataInRealTime = NO;

[assetWriter startWriting];

[assetReader startReading];

AVAssetTrack *soundTrack = [songAsset.tracks objectAtIndex:0];

CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale);

[assetWriter startSessionAtSourceTime:startTime];

__block UInt64 convertedByteCount = 0;

dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);

[assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue

usingBlock: ^

{

while (assetWriterInput.readyForMoreMediaData) {

CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer];

if (nextBuffer) {

// append buffer

[assetWriterInput appendSampleBuffer: nextBuffer];

DebugLog (@"appended a buffer (%zu bytes)",

CMSampleBufferGetTotalSampleSize (nextBuffer));

convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);

} else {

[assetWriterInput markAsFinished];

[assetWriter finishWritingWithCompletionHandler:^{

}];

[assetReader cancelReading];

NSDictionary *outputFileAttributes = [[NSFileManager defaultManager]

attributesOfItemAtPath:[destUrl path]

error:nil];

DebugLog (@"FlyElephant %lld",[outputFileAttributes fileSize]);

break;

}

}

DebugLog(@"转换结束");

// 删除临时temprecordAudio.m4a文件

NSError *removeError = nil;

if ([[NSFileManager defaultManager] fileExistsAtPath:originalUrlStr]) {

BOOL success = [[NSFileManager defaultManager] removeItemAtPath:originalUrlStr error:&removeError];

if (!success) {

DebugLog(@"删除临时temprecordAudio.m4a文件失败:%@",removeError);

completed(removeError);

}else{

DebugLog(@"删除临时temprecordAudio.m4a文件:%@成功",originalUrlStr);

completed(removeError);

}

}

}];

}

二、caf格式转m4a格式

/**

把.caf转为.m4a格式

@param cafUrlStr .m4a文件路径

@param m4aUrlStr .caf文件路径

@param completed 转化完成的block

*/

+ (void)convetCafToM4a:(NSString *)cafUrlStr

destUrl:(NSString *)m4aUrlStr

completed:(void (^)(NSError *error)) completed {

AVMutableComposition* mixComposition = [AVMutableComposition composition];

// 音频插入的开始时间

CMTime beginTime = kCMTimeZero;

// 获取音频合并音轨

AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

// 用于记录错误的对象

NSError *error = nil;

// 音频原文件资源

AVURLAsset *cafAsset = [[AVURLAsset alloc]initWithURL:[NSURL fileURLWithPath:cafUrlStr] options:nil];

// 原音频需要合并的音频文件的区间

CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, cafAsset.duration);

BOOL success = [compositionAudioTrack insertTimeRange:audio_timeRange ofTrack:[[cafAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:beginTime error:&error];

if (!success) {

DebugLog(@"插入原音频失败: %@",error);

}else {

DebugLog(@"插入原音频成功");

}

// 创建一个导入M4A格式的音频的导出对象

AVAssetExportSession* assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetAppleM4A];

// 导入音视频的URL

assetExport.outputURL = [NSURL fileURLWithPath:m4aUrlStr];

// 导出音视频的文件格式

assetExport.outputFileType = @"com.apple.m4a-audio";

[assetExport exportAsynchronouslyWithCompletionHandler:^{

// 分发到主线程

dispatch_async(dispatch_get_main_queue(), ^{

int exportStatus = assetExport.status;

if (exportStatus == AVAssetExportSessionStatusCompleted) {

// 合成成功

completed(nil);

NSError *removeError = nil;

if([cafUrlStr hasSuffix:@"caf"]) {

// 删除老录音caf文件

if ([[NSFileManager defaultManager] fileExistsAtPath:cafUrlStr]) {

BOOL success = [[NSFileManager defaultManager] removeItemAtPath:cafUrlStr error:&removeError];

if (!success) {

DebugLog(@"删除老录音caf文件失败:%@",removeError);

}else{

DebugLog(@"删除老录音caf文件:%@成功",cafUrlStr);

}

}

}

}else {

completed(assetExport.error);

}

});

}];

}

三、caf或m4a转为aac或mp3

这个的转换需要引入一个第三方库,就是lame.

+ (BOOL)audio_PCMtoMP3WithPCMUrl:(NSString *)pcmUrl andTimesTamps:(NSString *)timesTamps{

// 导出aac的地址

NSString *timestampsPath = [kRecorderPath stringByAppendingPathComponent: timesTamps];

NSString *mp3FilePath = [timestampsPath stringByAppendingPathComponent: kRecordAACSaveName];

NSError *removeError = nil;

if ([[NSFileManager defaultManager] fileExistsAtPath:mp3FilePath]) {

// 如果有旧文件则删除

BOOL success = [[NSFileManager defaultManager] removeItemAtPath:mp3FilePath error:&removeError];

if (!success) {

DebugLog(@"删除老aac文件失败:%@",removeError);

}else{

DebugLog(@"删除老aac文件:%@成功",mp3FilePath);

}

}

@try {

int read, write;

FILE *pcm = fopen([pcmUrl 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;//8192

const int MP3_SIZE = 8192;//8192

short int pcm_buffer[PCM_SIZE*2];

unsigned char mp3_buffer[MP3_SIZE];

lame_t lame = lame_init();

lame_set_in_samplerate(lame, 44100);//采样播音速度,值越大播报速度越快,反之。

lame_set_VBR(lame, vbr_default);

lame_init_params(lame);

do {

read = 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_close(lame);

fclose(mp3);

fclose(pcm);

}

@catch (NSException *exception) {

DebugLog(@"CAF转AAC失败:%@",[exception description]);

return NO;

}

@finally {

DebugLog(@"CAF转AAC成功!");

return YES;

}

}

四、caf和amr的互转

这两者的互相转换,我用到了一个三方库,libopencore-amrnb,百度可以搜到。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值