直接上代码
#import <MobileCoreServices/MobileCoreServices.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <AVFoundation/AVFoundation.h>
/// ogg,amr,acc 格式无法使用
@interface YSAudioTool : NSObject
+ (AudioFileID)getAudioFileID:(NSURL *)fileUrl;
+ (NSDictionary *)getAuidoBaseInfo:(AudioFileID)audioId;
+ (NSString *)getFileFormat:(AudioFileID)audioId showNormalType:(BOOL)flag;
+ (void)playAuido:(NSURL *)fileUrl;
@end
#import "YSAudioTool.h"
@interface YSAudioTool()
+ (NSString *)fileFormatCovert:(NSString*)file;
@end
@implementation YSAudioTool
+ (AudioFileID)getAudioFileID:(NSURL *)fileUrl {
AudioFileID fileID;
AudioFileOpenURL((__bridge CFURLRef)fileUrl, kAudioFileReadWritePermission,
kAudioFileWAVEType, &fileID);
return fileID;
}
/// 获取音频信息, 编码.声道数.采样率
/// @param audioId 音频文件id
+ (NSDictionary *)getAuidoBaseInfo:(AudioFileID)audioId {
NSMutableDictionary * result = [NSMutableDictionary new];
UInt32 formatListSize = 0;
OSStatus status = AudioFileGetPropertyInfo(audioId, kAudioFilePropertyFormatList, &formatListSize, NULL);
if (status == noErr) {
AudioFormatListItem *formatList = (AudioFormatListItem *)malloc(formatListSize);
status = AudioFileGetProperty(audioId, kAudioFilePropertyFormatList, &formatListSize, formatList);
for (int i = 0; i * sizeof(AudioFormatListItem) < formatListSize; i += sizeof(AudioFormatListItem))
{
AudioStreamBasicDescription pasbd = formatList[i].mASBD;
//选择需要的格式。。
switch (pasbd.mFormatID) {
case kAudioFormatAC3:
result[@"acodec"] = @"aac";
break;
case kAudioFormatOpus:
result[@"acodec"] = @"opus";
break;
case kAudioFormatLinearPCM:
result[@"acodec"] = @"pcm";
break;
case kAudioFormatMPEGLayer3:
result[@"acodec"] = @"mp3";
break;
default:
result[@"acodec"] = @"unknow";
break;
}
UInt32 channel = pasbd.mChannelsPerFrame; // 声道
result[@"channelNumber"] = @(channel);
result[@"sampleRate"] = @(pasbd.mSampleRate);
free(formatList);
}
}
return result;
}
/// 获取音频 文件类型
/// @param audioId 音频文件id
+ (NSString *)getFileFormat:(AudioFileID)audioId showNormalType:(BOOL)flag {
char * result ;
UInt32 formatListSize = 0;
OSStatus status = AudioFileGetPropertyInfo(audioId, kAudioFilePropertyFileFormat, &formatListSize, NULL);
result = (char *)malloc(formatListSize);
status = AudioFileGetProperty(audioId, kAudioFilePropertyFileFormat, &formatListSize, result);
NSMutableString *tranformFormat = [NSMutableString new];
for (long i = strlen(result) -1; i >= 0; i--) {
[tranformFormat appendFormat:@"%c", result[i]];
}
if (flag) {
return [YSAudioTool fileFormatCovert:tranformFormat];
}
return tranformFormat;
}
+ (NSString *)fileFormatCovert:(NSString*)file {
NSDictionary *params = @{
@"MPG3": @"mp3",
@"WAVE": @"wav",
@"MPG3": @"mp3"
};
return params[file];
}
+ (void)playAuido:(NSURL *)fileUrl {
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)fileUrl, &soundID);
AudioServicesPlaySystemSound(soundID);
}
/**
把mp3->wav; wav->wav;格式(ogg 不能转换,acc 不能转换)
@param originalUrlStr .m4a文件路径
@param destUrlStr .wav文件路径
@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];
NSLog(@"finallUrl: %@", destUrl);
//读取原始文件信息
NSError *error = nil;
AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:songAsset error:&error];
NSArray<AVMetadataItem *> *a = assetReader.asset.metadata;
for (int i = 0; i < a.count; i++) {
NSString* type = a[i].dataType;
NSLog(@"%@", type);
}
NSArray<AVMetadataFormat> * b = assetReader.asset.availableMetadataFormats;
for (int i = 0; i < b.count; i++) {
NSString* type = b[i].pathExtension;
NSLog(@"%@", type);
}
AVMediaSelection *selection = assetReader.asset.preferredMediaSelection;
NSArray<AVMetadataItem *> *c = selection.asset.metadata;
for (int i = 0; i < a.count; i++) {
NSString* type = c[i].dataType;
NSLog(@"%@", type);
}
// 采样率
CMTimeScale sample = assetReader.asset.duration.timescale;
NSLog(@"asdfasdfsdf %d", sample);
if (songAsset.tracks.count <= 0) {
return;
}
AVAssetReaderOutput *assetReaderOutput = [AVAssetReaderAudioMixOutput
assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks
audioSettings: nil];
if (![assetReader canAddOutput:assetReaderOutput]) {
NSLog(@"can't add reader output... die!");
completed(error);
return;
}
[assetReader addOutput:assetReaderOutput];
AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:destUrl
fileType:AVFileTypeWAVE
error:&error];
if (error) {
NSLog(@"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:8000], AVSampleRateKey,
[NSNumber numberWithInt:1], 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 {
NSLog(@"can't add asset writer input... die!");
if (completed != nil) {
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];
NSLog(@"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];
NSLog(@"FlyElephant %lld",[outputFileAttributes fileSize]);
break;
}
}
NSLog(@"转换结束");
// 删除临时temprecordAudio.m4a文件
NSError *removeError = nil;
if ([[NSFileManager defaultManager] fileExistsAtPath:originalUrlStr]) {
BOOL success = [[NSFileManager defaultManager] removeItemAtPath:originalUrlStr error:&removeError];
if (!success) {
NSLog(@"删除临时temprecordAudio.m4a文件失败:%@",removeError);
completed(removeError);
}else{
NSLog(@"删除临时temprecordAudio.m4a文件:%@成功",originalUrlStr);
if (completed != nil) {
completed(removeError);
}
}
}
}];
}
@end
您的一举一动都是对我的莫大支持