// // M4aToPcmHelper.m // TianyiProSwift // // Created by i2国际私塾 on 2017/3/21. // Copyright © 2017年 Chengdu Aitu Education Technology Ltd. All rights reserved. // #import "Mp4ToPcmHelper.h" #import "M4aToPcmHelper.h" #import #import #import @implementation Mp4ToPcmHelper + (void)Mp4ToPcmWithUrl:(NSURL*)videoUrl completion:(void(^)(NSData*data))completionHandle { NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectoryPath = [dirs objectAtIndex:0]; NSString *exportPath = [documentsDirectoryPath stringByAppendingPathComponent:@"pcmData.pcm"]; if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) { [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil]; } NSURL *exportURL = [NSURL fileURLWithPath:exportPath]; AVURLAsset* videoAsset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil]; [videoAsset loadValuesAsynchronouslyForKeys:@[@"tracks"] completionHandler:^{ NSError *error = nil; AVKeyValueStatus status = [videoAsset statusOfValueForKey:@"tracks"error:&error]; if(status == AVKeyValueStatusLoaded) { //数据加载完成 NSError *assetError = nil; AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:videoAsset error:&assetError]; if (assetError) { completionHandle(nil); return; } NSMutableDictionary *outputSettings = [NSMutableDictionary dictionary]; [outputSettings setObject:@(kCVPixelFormatType_32BGRA) forKey:(id)kCVPixelBufferPixelFormatTypeKey]; NSArray *audioTracks = [videoAsset tracksWithMediaType:AVMediaTypeAudio]; AVAssetReaderTrackOutput *readerAudioTrackOutput = nil; if ([audioTracks count] > 0) { AVAssetTrack* audioTrack = [audioTracks objectAtIndex:0]; NSDictionary *outputSettings = @{AVFormatIDKey:@(kAudioFormatLinearPCM), AVLinearPCMIsBigEndianKey:@NO, AVLinearPCMIsFloatKey:@NO, AVLinearPCMBitDepthKey :@(16) }; readerAudioTrackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings: outputSettings]; readerAudioTrackOutput.alwaysCopiesSampleData = NO; [assetReader addOutput:readerAudioTrackOutput]; } AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:exportURL fileType:AVFileTypeCoreAudioFormat error:&assetError]; if (assetError) { completionHandle(nil); return; } AudioChannelLayout channelLayout; memset(&channelLayout, 0, sizeof(AudioChannelLayout)); channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; NSDictionary *outputSettings2 = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey, [NSNumber numberWithFloat:8000.0], AVSampleRateKey, [NSNumber numberWithInt:2], AVNumberOfChannelsKey, [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey, [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey, [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved, [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey, [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey, nil]; AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:outputSettings2]; if ([assetWriter canAddInput:assetWriterInput]) { [assetWriter addInput:assetWriterInput]; } else { completionHandle(nil); return; } assetWriterInput.expectsMediaDataInRealTime = NO; if ([assetReader startReading] == NO){ completionHandle(nil); return; } [assetWriter startWriting]; AVAssetTrack *soundTrack = [[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale); [assetWriter startSessionAtSourceTime: kCMTimeZero]; // __block UInt64 convertedByteCount = 0; // // while (assetWriterInput.readyForMoreMediaData) { // CMSampleBufferRef nextBuffer = [readerAudioTrackOutput copyNextSampleBuffer]; // if (nextBuffer) { // // append buffer // [assetWriterInput appendSampleBuffer: nextBuffer]; // convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer); // } else { // // done! // [assetWriterInput markAsFinished]; // [assetWriter finishWritingWithCompletionHandler:^{ // }]; // [assetReader cancelReading]; // completionHandle([NSData dataWithContentsOfURL:exportURL]); // return; // break; // } // } CMSampleBufferRef sample = [readerAudioTrackOutput copyNextSampleBuffer]; while(sample != NULL) { while (TRUE) { if ([assetWriterInput isReadyForMoreMediaData]) { [assetWriterInput appendSampleBuffer:sample]; break; } } CFRelease( sample ); sample = [readerAudioTrackOutput copyNextSampleBuffer]; } [assetWriterInput markAsFinished]; [assetWriter finishWritingWithCompletionHandler:^{ }]; [assetReader cancelReading]; dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData *data = [[NSData alloc] initWithContentsOfURL:exportURL]; dispatch_async(dispatch_get_main_queue(), ^{ completionHandle(data); }); }); return; }} ]; return; } @end