Mp4ToPcmHelper.m 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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: startTime];
  84. __block UInt64 convertedByteCount = 0;
  85. while (assetWriterInput.readyForMoreMediaData) {
  86. CMSampleBufferRef nextBuffer = [readerAudioTrackOutput copyNextSampleBuffer];
  87. if (nextBuffer) {
  88. // append buffer
  89. [assetWriterInput appendSampleBuffer: nextBuffer];
  90. convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
  91. } else {
  92. // done!
  93. [assetWriterInput markAsFinished];
  94. [assetWriter finishWritingWithCompletionHandler:^{
  95. }];
  96. [assetReader cancelReading];
  97. completionHandle([NSData dataWithContentsOfURL:exportURL]);
  98. return;
  99. break;
  100. }
  101. }
  102. completionHandle(nil);
  103. return;
  104. }}
  105. ];
  106. }
  107. @end