2015-10-12 11 views
5

私はGPUImageAVVideoCompositingの組み合わせを使用して、2つのビデオ間にライブクロマキーフィルタを実装しようとしています。 CIImageimageFromCVPixelBufferCGImageGPUImageを入力してCGImageCIImageからCVPixelBufferに変更することは、非常に非効率的であり、メモリの問題を引き起こします。AVUIideoCompositingでGPUImageを使用する

GPUImageフレームワークにテクスチャオブジェクト、レンダリングターゲット、およびフレームバッファがあることに気付きました。私は、iOSでCVOpenGLESTextureCacheCreateTextureFromImageを活用して、GPU上のすべてを維持できることを期待していました。

私はGPUImageTextureInputオブジェクトにフィルタチェーンを設定し、その後、CVPixelBufferRefあるフィルタのrenderTargetを得ることができると仮定ので、私は、私はかなりフレームワークの内部の仕組みを理解してるとは思いません。下のrenderTargetは常にゼロです。imageFromCurrentFrameBufferを呼び出すと、私のイメージではない灰色のボックスが表示されます。

以下の例はクロマキーではなく、コンセプトを証明しようとする単一のビデオ上の簡単な輝度フィルタです。

@implementation MyCustomCompositor : NSObject <AVVideoCompositing> 

- (instancetype)init 
{ 
    self = [super init]; 
    if (self) { 
     CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, [GPUImageContext sharedImageProcessingContext].context, NULL, &_textureCache); 
    } 
    return self; 
} 

- (NSDictionary<NSString *,id> *)requiredPixelBufferAttributesForRenderContext 
{ 
    return @{(NSString *)kCVPixelBufferPixelFormatTypeKey : @[@(kCVPixelFormatType_32BGRA)], 
      (NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES}; 
} 

- (NSDictionary<NSString *,id> *)sourcePixelBufferAttributes 
{ 
    return @{(NSString *)kCVPixelBufferPixelFormatTypeKey : @[@(kCVPixelFormatType_32BGRA)], 
      (NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES}; 
} 

- (void)startVideoCompositionRequest:(AVAsynchronousVideoCompositionRequest *)asyncVideoCompositionRequest 
{ 
    @autoreleasepool { 
     CVPixelBufferRef mePixelBuffer = [asyncVideoCompositionRequest sourceFrameByTrackID:200]; 
     CVPixelBufferLockBaseAddress(mePixelBuffer, kCVPixelBufferLock_ReadOnly); 

     CVOpenGLESTextureRef meTextureRef = NULL; 
     size_t width = CVPixelBufferGetWidth(mePixelBuffer); 
     size_t height = CVPixelBufferGetHeight(mePixelBuffer); 
     CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCache, mePixelBuffer, NULL, GL_TEXTURE_2D, GL_BGRA, (int)width, (int)height, GL_BGRA, GL_UNSIGNED_BYTE, 0, &meTextureRef); 

     GPUImageTextureInput *meTextureInput = [[GPUImageTextureInput alloc] initWithTexture:CVOpenGLESTextureGetName(meTextureRef) size:CGSizeMake(width, height)]; 

     GPUImageBrightnessFilter *filter = [[GPUImageBrightnessFilter alloc] init]; 
     filter.brightness = 0.5; 
     [meTextureInput addTarget:filter]; 

     [filter setFrameProcessingCompletionBlock:^(GPUImageOutput *imageOutput, CMTime time) { 
      [asyncVideoCompositionRequest finishWithComposedVideoFrame:((GPUImageBrightnessFilter *)imageOutput).renderTarget]; 
     }]; 

     [meTextureInput processTextureWithFrameTime:kCMTimeZero]; 

     CFRelease(meTextureRef); 
     CVOpenGLESTextureCacheFlush(_textureCache, 0); 

     CVPixelBufferUnlockBaseAddress(mePixelBuffer, kCVPixelBufferLock_ReadOnly); 
    } 
} 

私は私の構図をより細かく制御する必要があるので、私はGPUImageGPUMovieWriterまたはビデオAPIを使用していません。このコンポジションは、異なる時間範囲で異なる緑のビデオオーバーレイを参照する複数のクロマキー命令から構成できます。GPUImageのムービーAPIは、ビデオファイル全体をフィルタリングすることに限定されています。トラックやオーディオミックスを操作するためのコンポジションの能力も必要です。

GLでカスタムシェイダーを使ってこのようなことをやり遂げようとしましたが、私がやろうとしていることをしているような既存のフレームワークを活用しようと考えました。

答えて

0

GPUImageMovieから変更されたGPUImageFrameInputという名前のクラスを作成しました。 CVPixelBufferRefがその入力です。それはそのようになり :

  1. はGPUImageFrameInputを作成
  2. をGPUImageFrameOutputするsourcePixelBufferをラップ
  3. はここ

を行ってフィルタチェーンを完成destinationPixelBuffer

  • を包んキーコードです。

    // output 
    // wrap the sourcePixelBuffer from the request 
    // it's modified from GPUImageVideoCamera 
    @interface GPUImageFrameOutput() { 
    
    } 
    -(void)processSourcePixelBuffer:(CVPixelBufferRef)pixelBuffer withSampleTime:(CMTime)currentSampleTime; 
    @end 
    
    @implement GPUImageFrameOutput() 
    
    -(void)processSourcePixelBuffer:(CVPixelBufferRef)pixelBuffer withSampleTime:(CMTime)currentSampleTime { 
        runSynchronouslyOnVideoProcessingQueue(^{ 
         [GPUImageContext useImageProcessingContext]; 
    
         int bufferHeight = (int) CVPixelBufferGetHeight(movieFrame); 
         int bufferWidth = (int) CVPixelBufferGetWidth(movieFrame); 
    
         if (bufferHeight == 0 || bufferWidth == 0) { 
          return; 
         } 
    
         // almost same as 
         // [GPUImageVideoCamera processVideoSampleBuffer:] 
         // 
    } 
    
    @end 
    
    // input 
    // wrap the destinationPixelBuffer 
    @interface GPUImageFrameInput() { 
        CVPixelBufferRef targetBuffer; 
        // ... others 
    } 
    @end 
    
    - (void)setPixelBuffer:(CVPixelBufferRef)buffer{ 
        targetBuffer = buffer; 
    } 
    
    - (CVOpenGLESTextureRef)createDataFBO { 
        if (!movieFramebuffer) { 
         glActiveTexture(GL_TEXTURE1); 
         glGenFramebuffers(1, &movieFramebuffer); 
         glBindFramebuffer(GL_FRAMEBUFFER, movieFramebuffer); 
        } 
    
        glBindFramebuffer(GL_FRAMEBUFFER, movieFramebuffer); 
        glViewport(0, 0, (int)_videoSize.width, (int)_videoSize.height); 
    
        CVOpenGLESTextureRef renderTexture = nil; 
    
        if ([GPUImageContext supportsFastTextureUpload]) { 
         CVBufferSetAttachment(targetBuffer, kCVImageBufferColorPrimariesKey, kCVImageBufferColorPrimaries_ITU_R_709_2, kCVAttachmentMode_ShouldPropagate); 
         CVBufferSetAttachment(targetBuffer, kCVImageBufferYCbCrMatrixKey, kCVImageBufferYCbCrMatrix_ITU_R_601_4, kCVAttachmentMode_ShouldPropagate); 
         CVBufferSetAttachment(targetBuffer, kCVImageBufferTransferFunctionKey, kCVImageBufferTransferFunction_ITU_R_709_2, kCVAttachmentMode_ShouldPropagate); 
    
         CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault, [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], 
                    targetBuffer, 
                    NULL, // texture attributes 
                    GL_TEXTURE_2D, 
                    GL_RGBA, // opengl format 
                    (int)CVPixelBufferGetWidth(targetBuffer), 
                    (int)CVPixelBufferGetHeight(targetBuffer), 
                    GL_BGRA, // native iOS format 
                    GL_UNSIGNED_BYTE, 
                    0, 
                    &renderTexture); 
    
         glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture)); 
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0); 
        } 
        else 
        { 
        //... 
        } 
        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
        NSAssert(status == GL_FRAMEBUFFER_COMPLETE, @"Incomplete filter FBO: %d", status); 
    
        return renderTexture; 
    } 
    

    は、あなたが他の人

    [frameInput setPixelBuffer:destinationPixelBuffer]; 
    
    for (...) { 
        GPUImageMovieFrameOutput *output ... 
        [output addTarget:filter atTextureLocation:index]; 
    } 
    [filter addTarget:frameInput]; 
    

    が参考に願っていますようにgpuimageチェーンを作成することができます!

  • +0

    私はこれを撃つでしょう!ありがとう! – dhenke

    +0

    私はこれで少し混乱しています。これはGPUImageMovieのコードのように見えますが、これはGPUImageOutputサブクラスにどのように適応させるのですか? createDataFBOの呼び出しはどのように行われますか?あるいは、私はこのサブクラスをどのように配置するかについていくつかの欠点がありますか?私はcreateDataFBOを呼び出して、そのrefを何かに割り当てることになると思いますか? – dhenke

    +0

    申し訳ありません。私は出力を与えることを忘れた。 :P私はそれを修正させてください。 – econi

    関連する問題