AudioConverter.m 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. //
  2. // AudioConverter.m
  3. // ContactPoster
  4. //
  5. // Created by TSYH on 2024/1/25.
  6. //
  7. #import "AudioConverter.h"
  8. #import "lame.h"
  9. #import <AVFoundation/AVFoundation.h>
  10. @implementation AudioConverter
  11. // 转换为mp3
  12. + (void)convenrtToMp3WithResult:(NSString *)originalPath
  13. outPath:(NSString *)outPath
  14. completion:(ConvertCompletionHandler)completion {
  15. [[NSFileManager defaultManager] removeItemAtPath:outPath error:nil];
  16. @try {
  17. int read, write;
  18. FILE *pcm = fopen([originalPath cStringUsingEncoding:1], "rb");//被转换的文件
  19. fseek(pcm, 4*1024, SEEK_CUR); //skip file header
  20. FILE *mp3 = fopen([outPath cStringUsingEncoding:1], "wb");//转换后文件的存放位置
  21. const int PCM_SIZE = 8192;
  22. const int MP3_SIZE = 8192;
  23. short int pcm_buffer[PCM_SIZE*2];
  24. unsigned char mp3_buffer[MP3_SIZE];
  25. lame_t lame = lame_init();
  26. lame_set_num_channels (lame, 2 ); // 设置 1 为单通道,默认为 2 双通道
  27. lame_set_in_samplerate(lame, 44100);//
  28. lame_set_brate (lame, 8);
  29. lame_set_mode (lame, 3);
  30. lame_set_VBR(lame, vbr_default);
  31. lame_set_quality (lame, 2); /* 2=high 5 = medium 7=low 音 质 */
  32. lame_init_params(lame);
  33. do {
  34. read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
  35. if (read == 0)
  36. write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
  37. else
  38. write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
  39. fwrite(mp3_buffer, write, 1, mp3);
  40. } while (read != 0);
  41. lame_close(lame);
  42. fclose(mp3);
  43. fclose(pcm);
  44. }
  45. @catch (NSException *exception) {
  46. // NSLog(@"%@",[exception description]);
  47. completion(nil, exception.reason);
  48. }
  49. @finally {
  50. completion(outPath, nil);
  51. }
  52. }
  53. + (void)convertM4aToWav:(NSString *)originalPath
  54. outPath:(NSString *)outPath
  55. compltion:(ConvertCompletionHandler)compltion {
  56. if ([[NSFileManager defaultManager] fileExistsAtPath:outPath]) {
  57. NSError *error;
  58. [[NSFileManager defaultManager] removeItemAtPath:outPath error:&error];
  59. }
  60. NSURL *originalUrl = [NSURL fileURLWithPath:originalPath];
  61. NSURL *outPutUrl = [NSURL fileURLWithPath:outPath];
  62. AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:originalUrl options:nil]; //读取原始文件信息
  63. NSError *error = nil;
  64. AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:songAsset error:&error];
  65. if (error) {
  66. NSLog (@"error: %@", error);
  67. compltion(nil, error.description);
  68. return;
  69. }
  70. AVAssetReaderOutput *assetReaderOutput = [AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks audioSettings: nil];
  71. if (![assetReader canAddOutput:assetReaderOutput]) {
  72. NSLog (@"can't add reader output... die!");
  73. compltion(nil, @"can't add reader output... die!");
  74. return;
  75. }
  76. [assetReader addOutput:assetReaderOutput];
  77. AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:outPutUrl fileType:AVFileTypeCoreAudioFormat error:&error];
  78. if (error) {
  79. NSLog (@"error: %@", error);
  80. compltion(nil, error.description);
  81. return;
  82. }
  83. AudioChannelLayout channelLayout;
  84. memset(&channelLayout, 0, sizeof(AudioChannelLayout));
  85. channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
  86. /** 配置音频参数 */
  87. NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
  88. [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey, [NSNumber numberWithFloat:44100.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];
  89. AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:outputSettings];
  90. if ([assetWriter canAddInput:assetWriterInput]) {
  91. [assetWriter addInput:assetWriterInput];
  92. } else {
  93. NSLog (@"can't add asset writer input... die!");
  94. compltion(nil, @"can't add asset writer input... die!");
  95. return;
  96. }
  97. assetWriterInput.expectsMediaDataInRealTime = NO;
  98. [assetWriter startWriting];
  99. [assetReader startReading];
  100. AVAssetTrack *soundTrack = [songAsset.tracks objectAtIndex:0];
  101. CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale);
  102. [assetWriter startSessionAtSourceTime:startTime];
  103. __block UInt64 convertedByteCount = 0;
  104. dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
  105. [assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock: ^ {
  106. while (assetWriterInput.readyForMoreMediaData) {
  107. CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer];
  108. if (nextBuffer) {
  109. // append buffer
  110. [assetWriterInput appendSampleBuffer: nextBuffer];
  111. convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
  112. } else {
  113. [assetWriterInput markAsFinished];
  114. [assetWriter finishWritingWithCompletionHandler:^{
  115. }];
  116. [assetReader cancelReading];
  117. NSDictionary *outputFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[outPutUrl path] error:nil];
  118. NSLog (@"FlyElephant %lld",[outputFileAttributes fileSize]);
  119. compltion(outPath, nil);
  120. break;
  121. }
  122. }
  123. }];
  124. }
  125. @end