视频作为OpenGL ES2.0中的纹理

时间:2014-12-03 10:01:51

标签: ios video opengl-es textures

我想在OpenGLES 2.0 iOS中将视频作为纹理放置到对象中。 我使用AVPlayer创建AVPlayerItemVideoOutput,设置

NSDictionary *videoOutputOptions = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [NSNumber numberWithInt:kCVPixelFormatType_32BGRA], kCVPixelBufferPixelFormatTypeKey,
                                   [NSDictionary dictionary], kCVPixelBufferIOSurfacePropertiesKey,
                                   nil];
self.videoOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:videoOutputOptions];

比我每时每刻得到CVPixelBufferRef

CMTime currentTime = [self.videoOutput itemTimeForHostTime:CACurrentMediaTime()];
CVPixelBufferRef buffer = [self.videoOutput copyPixelBufferForItemTime:currentTime itemTimeForDisplay:NULL];

然后我用这种方法将它转换为UIImage

+ (UIImage *)imageWithCVPixelBufferUsingUIGraphicsContext:(CVPixelBufferRef)pixelBuffer
{
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);        
    int w = CVPixelBufferGetWidth(pixelBuffer);
    int h = CVPixelBufferGetHeight(pixelBuffer);
    int r = CVPixelBufferGetBytesPerRow(pixelBuffer);
    int bytesPerPixel = r/w;        
    unsigned char *bufferU = CVPixelBufferGetBaseAddress(pixelBuffer);
    UIGraphicsBeginImageContext(CGSizeMake(w, h));        
    CGContextRef c = UIGraphicsGetCurrentContext();        
    unsigned char* data = CGBitmapContextGetData(c);
    if (data) {
        int maxY = h;
        for(int y = 0; y < maxY; y++) {
            for(int x = 0; x < w; x++) {
                int offset = bytesPerPixel*((w*y)+x);
                data[offset] = bufferU[offset];     // R
                data[offset+1] = bufferU[offset+1]; // G
                data[offset+2] = bufferU[offset+2]; // B
                data[offset+3] = bufferU[offset+3]; // A
            }
        }
    }
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
    CFRelease(pixelBuffer);
    return image;
}

结果我从视频中得到了所需的帧:

enter image description here

毕竟我尝试用

更新纹理
- (void)setupTextureWithImage:(UIImage *)image
{
    if (_texture.name) {
        GLuint textureName = _texture.name;
        glDeleteTextures(1, &textureName);
    }

    NSError *error;
    _texture = [GLKTextureLoader textureWithCGImage:image.CGImage options:nil error:&error];
    if (error) {
        NSLog(@"Error during loading texture: %@", error);
    }
}

我在GLKView的update方法中调用此方法,但结果是黑屏,只有音频可用。

任何人都可以解释做错了吗?看起来我对纹理做错了......

2 个答案:

答案 0 :(得分:1)

问题很可能发生在你发布的代码的其他地方。要检查纹理本身,请创建一个快照(Xcode中的一个功能),看看是否可以在那里看到正确的纹理。显示纹理对象时,您的坐标可能不正确或某些参数丢失,可能是您忘记启用某些属性或者着色器不存在...

由于你到目前为止我建议你首先尝试绘制一个彩色方块,然后尝试将纹理(不是从视频)应用到它,直到你得到正确的结果。然后从视频中实现纹理。

只是一个建议,因为你从视频中获取原始像素数据,你应该考虑只创建一个纹理,然后使用纹理子图像函数直接用数据更新纹理,而不是做一些奇怪的迭代和转换到图像。 glTexSubImage2D将直接获取缓冲区指针并进行更新。

答案 1 :(得分:0)

我尝试在设备上启动 - 它运行正常。

看起来问题是模拟器不支持某些操作