2014-03-12 51 views
1

構建一個目標爲10.7+的64位本地OSX(不是iOS)ap。在可可領域處理視頻文件有點新。如何使用AVFoundation從視頻中獲取openGL紋理?

我希望能夠打開一個視頻文件並在openGL渲染器中顯示輸出結果(IE,我希望能夠有效地訪問視頻的幀緩衝區並將每幀轉換爲opengl紋理。)

從概念上講,這看起來簡單明瞭,但我很難瀏覽各種(舊的和不推薦的)示例和選項,這些示例和選項似乎最近都被棄用,而不贊成使用AVFoundation。我可能錯過了一些東西,但是在OpenGL上使用AVFoundation的例子在地面上看起來很薄弱。

爲了進一步闡明,this sample application (QTCoreVideo101 from Apple)做的或多或少正是我想要的,不同之處在於它建立在棄用的QTKit之上,因此不會以64位編譯。

我正在通過AVFoundation文檔閱讀,但我仍然不確定嘗試從AVFoundation獲取glTexture還是我應該在其他地方尋找它是有意義的。

UPDATE

這是我結束了去解決。 「thisLayer.layerSource.videoPlayerOutput」是AVPlayerItemVideoOutput對象。

if ([thisLayer.layerSource.videoPlayerOutput hasNewPixelBufferForItemTime:playerTime]){ 

    frameBuffer= [thisLayer.layerSource.videoPlayerOutput copyPixelBufferForItemTime:playerTime itemTimeForDisplay:NULL]; 

    CVReturn result= CVOpenGLTextureCacheCreateTextureFromImage(NULL, 
              textureCache, 
              frameBuffer, 
              NULL, 
              &textureRef); 
    if(result == kCVReturnSuccess){ 
      // These appear to be GL_TEXTURE_RECTANGLE_ARB 
      thisLayer.layerSource.vid_glTextureTarget=CVOpenGLTextureGetTarget(textureRef); 
      thisLayer.layerSource.vid_glTexture=CVOpenGLTextureGetName(textureRef); 
      thisLayer.layerSource.vid_glTextureSize=NSMakeSize(CVPixelBufferGetWidth(frameBuffer), CVPixelBufferGetHeight(frameBuffer)); 
      thisLayer.layerSource.vid_ciimage=[CIImage imageWithCVImageBuffer:frameBuffer]; 
      CFRelease(textureRef); 
      CVOpenGLTextureCacheFlush(textureCache, 0); 
    }else{ 
      NSLog(@"INTERNAL ERROR FAILED WITH CODE: %i",result); 
    } 
    CVBufferRelease(frameBuffer); 
} 

回答

0

AVAssetReaderTrackOutput(添加到您的AVAssetReader)會輸出一個CVPixelBufferRef,其中您可以指定首選格式通過glTexImageglTexSubImage上傳到OpenGL的。

0

我一直在尋找這也,這是我目前的解決方案:

- (BOOL) renderWithCVPixelBufferForTime: (NSTimeInterval) time 
{ 
    CMTime vTime = [self.playeroutput itemTimeForHostTime:CACurrentMediaTime()]; 

    if ([self.playeroutput hasNewPixelBufferForItemTime:vTime]) { 
     if (_cvPixelBufferRef) { 
      CVPixelBufferUnlockBaseAddress(_cvPixelBufferRef, kCVPixelBufferLock_ReadOnly); 
      CVPixelBufferRelease(_cvPixelBufferRef); 
     } 
     _cvPixelBufferRef = [self.playeroutput copyPixelBufferForItemTime:vTime itemTimeForDisplay:NULL]; 

     CVPixelBufferLockBaseAddress(_cvPixelBufferRef, kCVPixelBufferLock_ReadOnly); 
     GLsizei  texWidth = CVPixelBufferGetWidth(_cvPixelBufferRef); 
     GLsizei  texHeight = CVPixelBufferGetHeight(_cvPixelBufferRef); 
     GLvoid *baseAddress = CVPixelBufferGetBaseAddress(_cvPixelBufferRef); 


     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textureName); 
     glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE); 
     glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, texWidth, texHeight, 0, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, baseAddress); 

     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); 
    } 
    return YES; 
} 

不過,我想知道,如果沒有一個更有效的解決方案,我也有同樣的問題有幾種方法話題:

Best path from AVPlayerItemVideoOutput to openGL Texture

鎖定基址呼叫是豬,我不知道它的真正需要。

+0

不錯......我最終做了類似的事情(使用pixelbuffer並將其放入texturecache中)。我實際上並沒有嘗試對你的代碼進行分析,因此我不確定速度如何,但我會在一段時間內將代碼發佈到另一個答案中(太長的評論)。我沒有做任何鎖定 - 也許我應該有,但在一段時間的生產環境中工作得很好,甚至一次運行幾個高清視頻。 – andrew