gpt4 book ai didi

macos - 从 AVPlayerItemVideoOutput 到 openGL 纹理的最佳路径

转载 作者:行者123 更新时间:2023-11-28 21:40:18 26 4
gpt4 key购买 nike

一直在绞尽脑汁试图找出从 AVFoundation 视频到 openGLTexture 的当前最佳路径,我发现的大部分内容都与 iOS 相关,但我似乎无法使其在 OSX 中正常运行。

首先,我是这样设置视频输出的:

NSDictionary *pbOptions = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kCVPixelFormatType_422YpCbCr8], kCVPixelBufferPixelFormatTypeKey,
[NSDictionary dictionary], kCVPixelBufferIOSurfacePropertiesKey,
nil];
self.playeroutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:pbOptions];
self.playeroutput.suppressesPlayerRendering = YES;

我正在尝试三种不同的解决方案,其中只有一种似乎始终有效,但不确定它是最快的。一个工作了一点,然后随着帧到处跳动而崩溃,一个只产生黑色。

首先,使用 glTexImage2D 的工作解决方案

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

此方法大部分时间都花在锁定像素缓冲区的基地址上,但文档说如果从 GPU 访问数据则不需要,并且会影响性​​能。我想不出一种无需锁定即可获得纹理的方法。

接下来,使用 iOSurface 的几乎可以工作的解决方案,这个工作了一点然后变得非常小故障,就好像 ioSurfaces 从以前的帧中使用一样:

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

if ([self.playeroutput hasNewPixelBufferForItemTime:vTime]) {

CVPixelBufferRef pb = [self.playeroutput copyPixelBufferForItemTime:vTime itemTimeForDisplay:NULL];
IOSurfaceRef newSurface = CVPixelBufferGetIOSurface(pb);
if (_surfaceRef != newSurface) {
IOSurfaceDecrementUseCount(_surfaceRef);
_surfaceRef = newSurface;
IOSurfaceIncrementUseCount(_surfaceRef);
GLsizei texWidth = (int) IOSurfaceGetWidth(_surfaceRef);
GLsizei texHeight= (int) IOSurfaceGetHeight(_surfaceRef);
size_t rowbytes = CVPixelBufferGetBytesPerRow(_cvPixelBufferRef);

glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textureName);
CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE_ARB, GL_RGB8, texWidth, texHeight, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, _surfaceRef, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
CVPixelBufferRelease(pb);
}
return YES;
}

这似乎是最好的解决方案,如果可行的话。我有另一个从 ioSurfaces 创建纹理的过程,它工作得很好,同时速度也非常快。

最后,似乎推荐用于 iOS 的方法是使用 CVOpenGLTextureCache,在 osx 中的实现似乎略有不同,除了黑色我无法渲染任何东西,而且它似乎比第一个解决方案更慢....

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

if ([self.playeroutput hasNewPixelBufferForItemTime:vTime]) {
_cvPixelBufferRef = [self.playeroutput copyPixelBufferForItemTime:vTime itemTimeForDisplay:NULL];
if (!_textureCacheRef) {
CVReturn error = CVOpenGLTextureCacheCreate(kCFAllocatorDefault, NULL, cgl_ctx, CGLGetPixelFormat(cgl_ctx), NULL, &_textureCacheRef);
if (error) {
NSLog(@"Texture cache create failed");
}
}

CVReturn error = CVOpenGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCacheRef, _cvPixelBufferRef, NULL, &_textureRef);
if (error) {
NSLog(@"Failed to copy video texture");
}


CVPixelBufferRelease(_cvPixelBufferRef);

_textureName = CVOpenGLTextureGetName(_textureRef);

}
return YES;
}

可能我没有设置正确,osx 中的纹理缓存的文档为零。

我发现最好在渲染周期之间保留 cvpixelbufferref,据我所知,纹理上传可以与 CGLTexImage2d 异步运行,对此我很满意,其他几个对象可能会同时渲染,当最终绘制纹理时,最终会调用 cglflushDrawable。

我找到的大多数关于 openGL 纹理视频的苹果示例都与 iOS 相关,并将纹理一分为二以在着色器中重新组合,如本例所示 https://developer.apple.com/library/ios/samplecode/GLCameraRipple/Listings/GLCameraRipple_main_m.html#//apple_ref/doc/uid/DTS40011222-GLCameraRipple_main_m-DontLinkElementID_11我无法直接调整代码,因为纹理缓存在 iOS 中有不同的实现。

所以任何指针都会很棒,它似乎是重要的功能,但我发现关于 av foundation 和 osx 上的 opengl 的信息似乎非常负面。

更新:更新了带有使用次数的 ioSurface 代码,工作时间稍长,但最终仍会出现故障。

最佳答案

我开始了同样的旅程,对 OpenGL 的了解与对养羊的了解一样多,但确实注意到您的 pbOptions 不包含 kCVPixelBufferOpenGLCompatibilityKey

NSDictionary *pbOptions = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kCVPixelFormatType_422YpCbCr8], kCVPixelBufferPixelFormatTypeKey,
[NSDictionary dictionary], kCVPixelBufferIOSurfacePropertiesKey,
[NSNumber numberWithBool:YES], kCVPixelBufferOpenGLCompatibilityKey, nil];

我请求像素缓冲区作为 kCVPixelFormatType_32BGRA 而不是组件,这对我来说适用于 _currentSurface (IOSurfaceRef)、textureName (GLuint)、_sourceWidth (int) 和 _sourceHeight (int) 的局部变量

IOSurfaceRef newSurface = CVPixelBufferGetIOSurface(pixelBuffer);
if (_currentSurface != newSurface) {
CGLContextObj cgl_ctx = (CGLContextObj)[[self openGLContext] CGLContextObj];
[[self openGLContext] makeCurrentContext];

IOSurfaceDecrementUseCount(_currentSurface);
_currentSurface = newSurface;
IOSurfaceIncrementUseCount(_currentSurface);
GLsizei texWidth = (int) IOSurfaceGetWidth(_currentSurface);
GLsizei texHeight = (int) IOSurfaceGetHeight(_currentSurface);

if (_sourceWidth == 0 && _sourceHeight == 0) {
// used during drawing of texture
_sourceWidth = texWidth;
_sourceHeight = texHeight;
}

if (!_textureName) {
GLuint name;
glGenTextures(1, &name);
_textureName = name;
}

glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _textureName);
CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, texWidth, texHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, self.currentSurface, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}

关于macos - 从 AVPlayerItemVideoOutput 到 openGL 纹理的最佳路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24933453/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com