2015-10-12 30 views
5

İki video arasında bir canlı renk filtresi uygulamak için GPUImage ve AVVideoCompositing kombinasyonunu kullanıyorum. CIImageimageFromCVPixelBuffer'u CGImageGPUImage'a CGImage - CIImage - CVPixelBuffer no'lu numaralara dönüştürerek yapmak, oldukça verimsizdir ve bellek sorunlarına yol açar.AVVideoCompositing ile GPUImage'ı kullanma

GPUImage Çerçevesinde doku nesneleri, işlem hedefleri ve çerçeve arabellekleri olduğunu fark ettim. Her şeyi GPU’da tutmak için iOS’ta CVOpenGLESTextureCacheCreateTextureFromImage’u kullanabileceğini umuyordum.

Ben GPUImageTextureInput nesne üzerinde bir filtre zinciri kurmak ve daha sonra filtre en renderTarget, bir CVPixelBufferRef olduğu alabilir varsayılır, çünkü oldukça çerçevenin iç işleyişini anlamak sanmıyorum. Aşağıdaki renderTarget her zaman sıfırdır ve imageFromCurrentFrameBuffer'u çağırmak bana gri bir kutu verecektir, bu benim resmim değil.

Aşağıdaki örnekte, kroma-anahtar değil, tek bir videoda basit bir parlaklık filtresi, kavramı denemek ve kanıtlamak içindir. Benim kompozisyon daha ayrıntılı denetim gerektiğinden

@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); 
    } 
} 

ben GPUImage içinde GPUMovieWriter veya video API'leri kullanarak değilim. Kompozisyon, farklı zaman aralıklarında farklı bir yeşil video bindirmesine referans veren çok sayıda kroma-anahtar talimattan oluşabilir ve bana, GPUImage'daki film API'lerinin bir video dosyasının tamamını filtrelemekle sınırlı olduğu görülüyor. Ayrıca, parçanın parçaları ve ses karışımlarını işlemek için yeteneklerine de ihtiyacım var.

Özel gölgelendiricilerle tüm bunları GL'de yapmak için kafamı sarmayı denedim, ancak yapmaya çalıştığım şeyi yapan mevcut çerçeveleri kullanacağımı düşündüm.

cevap

0

GPUImageMovie'den değiştirilmiş GPUImageFrameInput adlı bir sınıf yazdım. CVPixelBufferRef girişidir. Böyle giderse:

  1. sarma sourcePixelBuffer
  2. GPUImageFrameInput filtre zincirini İşte

yapılan anahtar kodu

  • tamamlamak destinationPixelBuffer
  • sarılmış oluşturmak GPUImageFrameOutput için.

    // 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; 
    } 
    

    sonra başkalarına

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

    faydalı umut gibi GPUImage zinciri oluşturabilirsiniz!

  • +0

    Bunu bir şans vereceğim! Teşekkürler! – dhenke

    +0

    Bu konuda biraz kafam karıştı. Bu hemen hemen doğru GPUImageMovie, dışarı, kod gibi görünüyor, ama nasıl bir GPUImageOutput alt sınıfına uyarlamak için? CreateDataFBO çağrısı nasıl gerçekleşir? Yoksa bu alt sınıfı nasıl ayarlayacağım konusunda bazı parçalarımı mı kaçırıyorum? Ben createDataFBO çağırmak ve bir şey için bu ref atayarak sona ereceğini varsayalım? – dhenke

    +0

    üzgünüm. Çıkışı vermeyi unuttum. : P, tamir edeyim. – econi