2012-01-12 18 views
2


iOS開発とstackoverflowの両方に新しいので、私のコードが見栄えが良くない場合は私にご負担ください。

ARCとAVAssetWriterを使ってテストアプリケーションをセットアップして、アプリケーションバンドルに存在する画像を含むビデオを作成しました。すべてが期待どおりに動作し、ビデオが正しく作成されますが、Instrumentsでアプリケーションのプロファイルを作成すると、私のコードに関連する詳細ビューでは何も表示されないため、修正方法がわからないメモリリークが発生します(すべての流出オブジェクトはMallocであり、責任ライブラリはVideoToolboxです)。ここ

は、私は私のビューコントローラクラスでビデオの書き込みを開始するために呼び出すメソッドです:
iOS AVAssetWriterを使用して画像からビデオを作成するとメモリリークが発生する

- (void)writeVideo 
{ 
    // Set the frameDuration ivar (50/600 = 1 sec/12 number of frames) 
    frameDuration = CMTimeMake(50, 600); 
    nextPresentationTimeStamp = kCMTimeZero; 

    [self deleteTempVideo]; 

    NSError *error = nil; 
    AVAssetWriter *writer = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:self.videoPath] fileType:AVFileTypeQuickTimeMovie error:&error]; 
    if (!error) { 
     // Define video settings to be passed to the AVAssetWriterInput instance 
     NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
             AVVideoCodecH264, AVVideoCodecKey, 
             [NSNumber numberWithInt:640],AVVideoWidthKey, 
             [NSNumber numberWithInt:480], AVVideoHeightKey, nil]; 
     // Instanciate the AVAssetWriterInput 
     AVAssetWriterInput *writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings]; 
     // Instanciate the AVAssetWriterInputPixelBufferAdaptor to be connected to the writer input 
     AVAssetWriterInputPixelBufferAdaptor *pixelBufferAdaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:nil]; 
     // Add the writer input to the writer and begin writing 
     [writer addInput:writerInput]; 
     [writer startWriting]; 
     [writer startSessionAtSourceTime:nextPresentationTimeStamp]; 
     // 
     dispatch_queue_t mediaDataRequestQueue = dispatch_queue_create("Media data request queue", NULL); 
     [writerInput requestMediaDataWhenReadyOnQueue:mediaDataRequestQueue usingBlock:^{ 
      while (writerInput.isReadyForMoreMediaData) { 
       CVPixelBufferRef nextBuffer = [self fetchNextPixelBuffer]; 
       if (nextBuffer) { 
        [pixelBufferAdaptor appendPixelBuffer:nextBuffer withPresentationTime:nextPresentationTimeStamp]; 
        nextPresentationTimeStamp = CMTimeAdd(nextPresentationTimeStamp, frameDuration); 
        CVPixelBufferRelease(nextBuffer);      
        dispatch_async(dispatch_get_main_queue(), ^{ 
         NSUInteger totalFrames = [self.imagesNames count]; 
         float progress = 1.0 * (totalFrames - [self.imageNamesCopy count])/totalFrames; 
         [self.progressBar setProgress:progress animated:YES]; 
        }); 
       } else { 
        [writerInput markAsFinished]; 
        [writer finishWriting]; 
        [self loadVideo]; 
        dispatch_release(mediaDataRequestQueue); 
        break; 
       } 
      } 
     }]; 
    } 
} 


そして、ここでは、私はインスタンス化ピクセルバッファアダプタに追加するピクセルバッファをフェッチするために使用する方法であり、従来の方法では:

// Consume the imageNamesCopy mutable array and return a CVPixelBufferRef relative to the last object of the array 
- (CVPixelBufferRef)fetchNextPixelBuffer 
{ 
    NSString *imageName = [self.imageNamesCopy lastObject]; 
    if (imageName) [self.imageNamesCopy removeLastObject]; 
    // Create an UIImage instance 
    UIImage *image = [UIImage imageNamed:imageName]; 
    CGImageRef imageRef = image.CGImage;  

    CVPixelBufferRef buffer = NULL; 
    size_t width = CGImageGetWidth(imageRef); 
    size_t height = CGImageGetHeight(imageRef); 
    // Pixel buffer options 
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
          [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, 
          [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil]; 
    // Create the pixel buffer 
    CVReturn result = CVPixelBufferCreate(NULL, width, height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, &buffer); 
    if (result == kCVReturnSuccess && buffer) { 
     CVPixelBufferLockBaseAddress(buffer, 0); 
     void *bufferPointer = CVPixelBufferGetBaseAddress(buffer); 
     // Define the color space 
     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
     // Create the bitmap context to draw the image 
     CGContextRef context = CGBitmapContextCreate(bufferPointer, width, height, 8, 4 * width, colorSpace, kCGImageAlphaNoneSkipFirst); 
     CGColorSpaceRelease(colorSpace); 
     if (context) { 
      CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); 
      CGContextRelease(context); 
     } 
     CVPixelBufferUnlockBaseAddress(buffer, 0); 
    } 
    return buffer; 
} 
+0

AVAssetWriter * writerは決して解放されません。 – Allyn

+0

@Allyn:多分私は何かが不足しているかもしれませんが、私はARCを使っているので、どうやってAVAssetWriter *ライターをリリースするのですか? – marco

+0

申し訳ありませんが、ARCを使用しています。その場合、CVReturnの結果を決して公開しないかもしれない - 私はそれがARCによって処理されるとは思わない。 – Allyn

答えて

1

私は、メモリリークが映像書き込みコードに関連していないことが判明しました。漏れたコードは[self deleteTempVideo]のように見えます- (void)writeVideo

私はまだ何が間違っているのか把握する必要がありますが、私の質問はこの時点で範囲外です。
ここ- (void)deleteTempVideoのコードです:

- (void)deleteTempVideo 
{ 
    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    if ([fileManager isReadableFileAtPath:self.videoPath]) [fileManager removeItemAtPath:self.videoPath error:nil]; 
} 

そして、ここでは、私がself.videoPathの@propertyにアクセスするために使用ゲッターです:私の経験については

- (NSString *)videoPath 
{ 
    if (!_videoPath) { 
     NSString *fileName = @"test.mov"; 
     NSString *directoryPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 
     _videoPath = [directoryPath stringByAppendingPathComponent:fileName]; 
    } 
    return _videoPath; 
} 
0

、あなたはアークとブロックの両方を使用する場合、 メンバー変数を直接使用しないでください。 代わりに、弱いプロパティを使用できます。

ClassAという名前のクラスと、メンバ変数名_memberAがあるとします。 通常、memberAのプロパティを定義します。次に、以下のようにコードを書くことができます。

__weak ClassA *weakSelf = self; 
SomeVariable.function = ^() { 
    weakSelf.memberA ..... (not use _memberA Here) 
} 

PS。 ブロックが[UIView animation:duration:completion:]のような静的関数からのものである場合、メンバ変数を使用すると問題はないようです。

このように多くのメモリリークを解決しました。

関連する問題