Mp4ToPcmHelper.m 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. //
  2. // M4aToPcmHelper.m
  3. // TianyiProSwift
  4. //
  5. // Created by i2国际私塾 on 2017/3/21.
  6. // Copyright © 2017年 Chengdu Aitu Education Technology Ltd. All rights reserved.
  7. //
  8. #import "Mp4ToPcmHelper.h"
  9. #import "M4aToPcmHelper.h"
  10. #import <AudioToolbox/AudioToolbox.h>
  11. #import <AVFoundation/AVFoundation.h>
  12. #import <MediaPlayer/MediaPlayer.h>
  13. @implementation Mp4ToPcmHelper
  14. + (void)Mp4ToPcmWithUrl:(NSURL*)videoUrl completion:(void(^)(NSData*data))completionHandle
  15. {
  16. NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  17. NSString *documentsDirectoryPath = [dirs objectAtIndex:0];
  18. NSString *exportPath = [documentsDirectoryPath stringByAppendingPathComponent:@"pcmData.pcm"];
  19. if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) {
  20. [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
  21. }
  22. NSURL *exportURL = [NSURL fileURLWithPath:exportPath];
  23. AVURLAsset* videoAsset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];
  24. [videoAsset loadValuesAsynchronouslyForKeys:@[@"tracks"] completionHandler:^{
  25. NSError *error = nil;
  26. AVKeyValueStatus status = [videoAsset statusOfValueForKey:@"tracks"error:&error];
  27. if(status == AVKeyValueStatusLoaded) { //数据加载完成
  28. NSError *assetError = nil;
  29. AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:videoAsset error:&assetError];
  30. if (assetError) {
  31. completionHandle(nil);
  32. return;
  33. }
  34. NSMutableDictionary *outputSettings = [NSMutableDictionary dictionary];
  35. [outputSettings setObject:@(kCVPixelFormatType_32BGRA) forKey:(id)kCVPixelBufferPixelFormatTypeKey];
  36. NSArray *audioTracks = [videoAsset tracksWithMediaType:AVMediaTypeAudio];
  37. AVAssetReaderTrackOutput *readerAudioTrackOutput = nil;
  38. if ([audioTracks count] > 0)
  39. {
  40. AVAssetTrack* audioTrack = [audioTracks objectAtIndex:0];
  41. NSDictionary *outputSettings = @{AVFormatIDKey:@(kAudioFormatLinearPCM),
  42. AVLinearPCMIsBigEndianKey:@NO,
  43. AVLinearPCMIsFloatKey:@NO,
  44. AVLinearPCMBitDepthKey :@(16)
  45. };
  46. readerAudioTrackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings: outputSettings];
  47. readerAudioTrackOutput.alwaysCopiesSampleData = NO;
  48. [assetReader addOutput:readerAudioTrackOutput];
  49. }
  50. AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:exportURL fileType:AVFileTypeCoreAudioFormat error:&assetError];
  51. if (assetError) {
  52. completionHandle(nil);
  53. return;
  54. }
  55. AudioChannelLayout channelLayout;
  56. memset(&channelLayout, 0, sizeof(AudioChannelLayout));
  57. channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
  58. NSDictionary *outputSettings2 = [NSDictionary dictionaryWithObjectsAndKeys:
  59. [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
  60. [NSNumber numberWithFloat:8000.0], AVSampleRateKey,
  61. [NSNumber numberWithInt:2], AVNumberOfChannelsKey,
  62. [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey,
  63. [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
  64. [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
  65. [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
  66. [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
  67. nil];
  68. AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:outputSettings2];
  69. if ([assetWriter canAddInput:assetWriterInput]) {
  70. [assetWriter addInput:assetWriterInput];
  71. } else {
  72. completionHandle(nil);
  73. return;
  74. }
  75. assetWriterInput.expectsMediaDataInRealTime = NO;
  76. if ([assetReader startReading] == NO){
  77. completionHandle(nil);
  78. return;
  79. }
  80. [assetWriter startWriting];
  81. AVAssetTrack *soundTrack = [[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
  82. CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale);
  83. [assetWriter startSessionAtSourceTime: kCMTimeZero];
  84. // __block UInt64 convertedByteCount = 0;
  85. //
  86. // while (assetWriterInput.readyForMoreMediaData) {
  87. // CMSampleBufferRef nextBuffer = [readerAudioTrackOutput copyNextSampleBuffer];
  88. // if (nextBuffer) {
  89. // // append buffer
  90. // [assetWriterInput appendSampleBuffer: nextBuffer];
  91. // convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
  92. // } else {
  93. // // done!
  94. // [assetWriterInput markAsFinished];
  95. // [assetWriter finishWritingWithCompletionHandler:^{
  96. // }];
  97. // [assetReader cancelReading];
  98. // completionHandle([NSData dataWithContentsOfURL:exportURL]);
  99. // return;
  100. // break;
  101. // }
  102. // }
  103. CMSampleBufferRef sample = [readerAudioTrackOutput copyNextSampleBuffer];
  104. while(sample != NULL)
  105. {
  106. while (TRUE) {
  107. if ([assetWriterInput isReadyForMoreMediaData]) {
  108. [assetWriterInput appendSampleBuffer:sample];
  109. break;
  110. }
  111. }
  112. CFRelease( sample );
  113. sample = [readerAudioTrackOutput copyNextSampleBuffer];
  114. }
  115. [assetWriterInput markAsFinished];
  116. [assetWriter finishWritingWithCompletionHandler:^{
  117. }];
  118. [assetReader cancelReading];
  119. dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  120. NSData *data = [[NSData alloc] initWithContentsOfURL:exportURL];
  121. dispatch_async(dispatch_get_main_queue(), ^{
  122. completionHandle(data);
  123. });
  124. });
  125. return;
  126. }}
  127. ];
  128. return;
  129. }
  130. @end