2012-06-14 10 views
6

私はUIImageからビデオを生成するプロジェクトに取り組んでいます。私はここで見つけたコードを使用しています。これを最適化するために数日間苦労しています。シミュレータで5分、メモリのためにデバイス上でクラッシュする)。CVPixelBufferRefの最適化

-(void) writeImageAsMovie:(NSArray *)array toPath:(NSString*)path size:(CGSize)size duration:(int)duration 
{ 
    NSError *error = nil; 
    AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path] fileType:AVFileTypeQuickTimeMovie error:&error]; 
    NSParameterAssert(videoWriter); 

    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
           AVVideoCodecH264, AVVideoCodecKey, 
           [NSNumber numberWithInt:size.width], AVVideoWidthKey, 
           [NSNumber numberWithInt:size.height], AVVideoHeightKey, 
           nil]; 
    AVAssetWriterInput* writerInput = [AVAssetWriterInput 
            assetWriterInputWithMediaType:AVMediaTypeVideo 
            outputSettings:videoSettings]; 

    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:nil]; 
    NSParameterAssert(writerInput); 
    NSParameterAssert([videoWriter canAddInput:writerInput]); 
    [videoWriter addInput:writerInput]; 


    //Start a session: 
    [videoWriter startWriting]; 
    [videoWriter startSessionAtSourceTime:kCMTimeZero]; 

    CVPixelBufferRef buffer = NULL; 
    buffer = [self newPixelBufferFromCGImage:[[self.frames objectAtIndex:0] CGImage]]; 

    CVPixelBufferPoolCreatePixelBuffer (NULL, adaptor.pixelBufferPool, &buffer); 

    [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero]; 

    dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL); 
    int frameNumber = [self.frames count]; 

    [writerInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^{ 
     NSLog(@"Entering block with frames: %i", [self.frames count]); 
     if(!self.frames || [self.frames count] == 0) 
     { 
      return; 
     } 
     int i = 1; 
     while (1) 
     { 
      if (i == frameNumber) 
      { 
       break; 
      } 
      if ([writerInput isReadyForMoreMediaData]) 
      { 
       freeMemory(); 
       NSLog(@"inside for loop %d (%i)",i, [self.frames count]); 
       UIImage *image = [self.frames objectAtIndex:i]; 
       CGImageRef imageRef = [image CGImage]; 
       CVPixelBufferRef sampleBuffer = [self newPixelBufferFromCGImage:imageRef]; 
       CMTime frameTime = CMTimeMake(1, TIME_STEP); 

       CMTime lastTime=CMTimeMake(i, TIME_STEP); 

       CMTime presentTime=CMTimeAdd(lastTime, frameTime);  

       if (sampleBuffer) 
       { 
        [adaptor appendPixelBuffer:sampleBuffer withPresentationTime:presentTime]; 
        i++; 
        CVPixelBufferRelease(sampleBuffer); 
       } 
       else 
       { 
        break; 
       } 
      } 
     } 

     [writerInput markAsFinished]; 
     [videoWriter finishWriting]; 
     self.frames = nil; 

     CVPixelBufferPoolRelease(adaptor.pixelBufferPool); 

    }]; 
} 

そして今、機能ピクセルバッファを得るために、私は苦労していたと::

- (CVPixelBufferRef) newPixelBufferFromCGImage: (CGImageRef) image 
{ 
    CVPixelBufferRef pxbuffer = NULL; 

    int width = CGImageGetWidth(image)*2; 
    int height = CGImageGetHeight(image)*2; 

    NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, [NSNumber numberWithInt:width], kCVPixelBufferWidthKey, [NSNumber numberWithInt:height], kCVPixelBufferHeightKey, nil]; 
    CVPixelBufferPoolRef pixelBufferPool; 
    CVReturn theError = CVPixelBufferPoolCreate(kCFAllocatorDefault, NULL, (__bridge CFDictionaryRef) attributes, &pixelBufferPool); 
    NSParameterAssert(theError == kCVReturnSuccess); 
    CVReturn status = CVPixelBufferPoolCreatePixelBuffer(NULL, pixelBufferPool, &pxbuffer); 
    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL); 

    CVPixelBufferLockBaseAddress(pxbuffer, 0); 
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer); 
    NSParameterAssert(pxdata != NULL); 

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(pxdata, width, 
              height, 8, width*4, rgbColorSpace, 
              kCGImageAlphaNoneSkipFirst); 
    NSParameterAssert(context); 
    CGContextDrawImage(context, CGRectMake(0, 0, width, 
             height), image); 
    CGColorSpaceRelease(rgbColorSpace); 
    CGContextRelease(context); 

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0); 

    return pxbuffer; 
} 
を私は(私はアークで動作)今日持っている作業コードから始めましょう

最初の奇妙なこと:この関数でわかるように、幅と高さに2を掛けなければなりません。そうでなければ、結果ビデオはすべて乱れてしまいます。なぜか理解できません(スクリーンショットを投稿できます助けてください、ピクセルは私のイメージから来るようですが、幅が正しくなく、大きな黒い鱗がありますビデオの下半分に表示されます)。

もう1つの問題は、実際には大量のメモリが必要になることです。私は、ピクセルバッファーの割り当てを解除することはできないと思っていますが、理由は分かりません。

最後に、それは非常に遅いですが、私はそれを改善するための2つのアイデアがありますが、これは失敗します。

  • 私は(uint8_t *)のデータとUIImageを自分で生成するので、最初は、私のピクセルバッファを作成するためにUIImageを使用しないことです。私は 'CVPixelBufferCreateWithBytes'を使用しようとしましたが、動作しませんでした。 ;私の画像データは、ピクセルあたり16ビットに符号化され、そしてIが良好なOSタイプの引数を見つけることができなかった

    OSType pixFmt = CVPixelBufferGetPixelFormatType(pxbuffer); 
    CVPixelBufferCreateWithBytes(kCFAllocatorDefault, width, height, pixFmt, self.composition.srcImage.resultImageData, width*2, NULL, NULL, (__bridge CFDictionaryRef) attributes, &pxbuffer); 
    

を(引数は上記の関数と同じである:ここで私はそれを試した方法であります関数に与えることができます。 誰かがそれを使う方法を知っていれば(16ビット/ピクセルデータでは不可能かもしれません)、本当に役に立たない変換を避けるのに役立ちます。

  • 第2の点は、私のビデオ用にkCVPixelFormatType_32ARGBを避けたいということです。私はそれが少しビット/ピクセルで何かを使用する方が速くなると思いますが、試してみると(私は5ビット/コンポーネントとkCGImageAlphaNoneSkipFirstで作成されたコンテキストですべてのkCVPixelFormatType_16XXXXX形式を試しました)、クラッシュするか、何も含まれていない(kCVPixelFormatType_16BE555)。

私は唯一つのポストで多くのことを聞いて知っているが、私は一種のこのコードで失われています、私は非常に多くの組み合わせを試してみましたが、それらのどれも働いていない...

+0

これは10秒以内にしてください。あなたが流出しているように聞こえ、イメージデータも複製しているようです。どのようにイメージを読み込んでいますか?おそらくCVPixelBufferに直接ロードする方法があります。 –

+0

私はちょうど昨日、漏れていない何かに行くために管理しました!しかし、私はすべての方向で同時に検索していたので、問題は何だったのかは分かりません...私はここからコードを使用しました:http://codethink.no-ip.org/wordpress/archives/673私はたくさん修正して、リークしないもので終わった... 私は(int *)データからイメージを作成し、後でそのイメージに変換するので、まだ完璧ではありませんが、少なくともメモリ問題のためにクラッシュしません。 – Grhyll

+0

この最終版はありますか?コード?私は同じ問題を抱えている。もしあなたがそれを分かち合うことができれば幸いです。ありがとう。 – SpaceDog

答えて

0

I have to multiply the width and height by 2, otherwise, the result video is all messed up, and I can't understand why

をポイント対ピクセル?高dpi網膜スクリーンは、1ポイントあたり2倍のピクセル数を有する。