【问题标题】:Memory issue for reading large size of Audio file while converting audio转换音频时读取大尺寸音频文件的内存问题
【发布时间】:2013-10-11 10:25:56
【问题描述】:

我有 sampleaudio.caf(300 MB) 音频文件。我将音频 .caf 转换为 .wav 格式。在应用程序崩溃之后,它会显示警告“收到内存警告。级别 = 1”和“收到内存警告。级别 = 2”。但它适用于ipad。如何在转换发生时使用缓冲区读取少量数据。

这是我的代码:

NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"sampleaudio" ofType:@"caf"];

NSURL *assetURL = [NSURL fileURLWithPath:soundFilePath];
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];

NSError *assetError = nil;
AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:songAsset
                                                           error:&assetError]
;
if (assetError) {
    NSLog (@"error: %@", assetError);
    return;
}

AVAssetReaderOutput *assetReaderOutput = [AVAssetReaderAudioMixOutput
                                          assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks
                                          audioSettings: nil];
if (! [assetReader canAddOutput: assetReaderOutput]) {
    NSLog (@"can't add reader output... die!");
    return;
}
[assetReader addOutput: assetReaderOutput];

NSString *strWavFileName = [NSString stringWithFormat:@"%@.wav",[[soundFilePath lastPathComponent] stringByDeletingPathExtension]];
NSString *wavFilePath = [delegate.strCassettePathSide stringByAppendingPathComponent:strWavFileName];

if ([[NSFileManager defaultManager] fileExistsAtPath:wavFilePath])
{
    [[NSFileManager defaultManager] removeItemAtPath:wavFilePath error:nil];
}
NSURL *exportURL = [NSURL fileURLWithPath:wavFilePath];
AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:exportURL
                                                      fileType:AVFileTypeWAVE
                                                         error:&assetError];
if (assetError)
{
    NSLog (@"error: %@", assetError);
    return;
}

AppDelegate *appDelegate =[[UIApplication sharedApplication]delegate];
int nSampleRate=[[appDelegate.dictWAVQuality valueForKey:@"samplerate"] integerValue];
AudioChannelLayout channelLayout;
memset(&channelLayout, 0, sizeof(AudioChannelLayout));
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
                                [NSNumber numberWithFloat:nSampleRate], 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:outputSettings];
if ([assetWriter canAddInput:assetWriterInput])
{
    [assetWriter addInput:assetWriterInput];
}
else
{
    NSLog(@"can't add asset writer input... die!");
    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];
             convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
         }
         else
         {
             [assetWriterInput markAsFinished];
             //              [assetWriter finishWriting];
             [assetReader cancelReading];

             break;
         }
     }
 }];}

如何纠正内存问题。

【问题讨论】:

    标签: iphone ios objective-c


    【解决方案1】:
      CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer];
      if (nextBuffer)
      {
           // append buffer
           [assetWriterInput appendSampleBuffer: nextBuffer];
           convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
    
    
         ////////////////////you need to add following line////////////////////
    
           CMSampleBufferInvalidate(nextBuffer); 
           CFRelease(nextBuffer);
           nextBuffer = NULL;
     }
    

    【讨论】:

      【解决方案2】:

      https://developer.apple.com/library/mac/documentation/AVFoundation/Reference/AVAssetReaderOutput_Class/Reference/Reference.html#//apple_ref/occ/instm/AVAssetReaderOutput/copyNextSampleBuffer

      所有权遵循内存管理中的“创建规则” Core Foundation 编程指南。

      您必须释放从-(CMSampleBufferRef)copyNextSampleBuffer 获得的 CMSampleBufferRef,否则您会发生内存泄漏。

      【讨论】:

      • ARC 不会为您处理 CoreFoundation 对象。如果它们是免费桥接的,您要么必须自己释放它们,要么手动将所有权转移给 ARC。由于 CMSampleBufferRef 不是免费桥接的,您必须自己释放它。
      • developer.apple.com/library/mac/releasenotes/ObjectiveC/…The compiler does not automatically manage the lifetimes of Core Foundation objects; you must call CFRetain and CFRelease (or the corresponding type-specific variants) as dictated by the Core Foundation memory management rules
      • 投反对票的原因?我给出的答案与接受的答案几乎相同,但没有代码示例(从我的答案中可以明显看出)。以及 ARC 没有帮助的原因。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-09
      • 2017-04-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多