2012-10-01 32 views
17

Para mi proyecto actual, estoy leyendo la salida de la cámara principal del iPhone. A continuación, convierto el pixelbuffer en una textura OpenGL en caché mediante el método: CVOpenGLESTextureCacheCreateTextureFromImage. Esto funciona muy bien al procesar marcos de cámara que se utilizan para la vista previa. Probado en diferentes combinaciones con el iPhone 3GS, 4, 4S, iPod Touch (4ª generación) e IOS5, IOS6.CVOpenGLESTextureCacheCreateTextureFromImage no puede crear IOSurface

Pero, para la imagen final real, que tiene una resolución muy alta, esto sólo funciona en estas combinaciones:

  • iPhone 3GS + IOS 5.1.1
  • iPhone 4 + IOS 5.1.1
  • iPhone 4S + IOS 6.0
  • iPod Touch (cuarta generación) + IOS 5,0

Y esto no funciona para: iPhone 4 + IOS6.

El mensaje de error exacto en la consola:

Failed to create IOSurface image (texture) 
2012-10-01 16:24:30.663 GLCameraRipple[676:907] Error at CVOpenGLESTextureCacheCreateTextureFromImage -6683 

He aislado este problema cambiando el proyecto GLCameraRipple de Apple. Se puede extraer de mi versión aquí: http://lab.bitshiftcop.com/iosurface.zip

Así es como añado el stilloutput a la sesión actual:

- (void)setupAVCapture 
{ 
    //-- Create CVOpenGLESTextureCacheRef for optimal CVImageBufferRef to GLES texture conversion. 
    CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, [EAGLContext currentContext], NULL, &_videoTextureCache); 
    if (err) 
    { 
     NSLog(@"Error at CVOpenGLESTextureCacheCreate %d", err); 
     return; 
    } 

    //-- Setup Capture Session. 
    _session = [[AVCaptureSession alloc] init]; 
    [_session beginConfiguration]; 

    //-- Set preset session size. 
    [_session setSessionPreset:_sessionPreset]; 

    //-- Creata a video device and input from that Device. Add the input to the capture session. 
    AVCaptureDevice * videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 
    if(videoDevice == nil) 
     assert(0); 

    //-- Add the device to the session. 
    NSError *error;   
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error]; 
    if(error) 
     assert(0); 

    [_session addInput:input]; 

    //-- Create the output for the capture session. 
    AVCaptureVideoDataOutput * dataOutput = [[AVCaptureVideoDataOutput alloc] init]; 
    [dataOutput setAlwaysDiscardsLateVideoFrames:YES]; // Probably want to set this to NO when recording 

    //-- Set to YUV420. 
    [dataOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] 
                  forKey:(id)kCVPixelBufferPixelFormatTypeKey]]; // Necessary for manual preview 

    // Set dispatch to be on the main thread so OpenGL can do things with the data 
    [dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()]; 


    // Add still output 
    stillOutput = [[AVCaptureStillImageOutput alloc] init]; 
    [stillOutput setOutputSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey]]; 
    if([_session canAddOutput:stillOutput]) [_session addOutput:stillOutput]; 

    [_session addOutput:dataOutput]; 
    [_session commitConfiguration]; 

    [_session startRunning]; 
} 

Y aquí es cómo capturar la salida todavía y procesarla:

- (void)capturePhoto 
{ 
    AVCaptureConnection *videoConnection = nil; 
    for (AVCaptureConnection *connection in stillOutput.connections) { 
     for (AVCaptureInputPort *port in [connection inputPorts]) { 
      if ([[port mediaType] isEqual:AVMediaTypeVideo]) { 
       videoConnection = connection; 
       break; 
      } 
     } 
     if (videoConnection) { break; } 
    } 

    [stillOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: 
    ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { 
     // Process hires image 
     [self captureOutput:stillOutput didOutputSampleBuffer:imageSampleBuffer fromConnection:videoConnection]; 
    }]; 
} 

Así es como se crea la textura:

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
     fromConnection:(AVCaptureConnection *)connection 
{ 
    CVReturn err; 
    CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    size_t width = CVPixelBufferGetWidth(pixelBuffer); 
    size_t height = CVPixelBufferGetHeight(pixelBuffer); 

    if (!_videoTextureCache) 
    { 
     NSLog(@"No video texture cache"); 
     return; 
    } 

    if (_ripple == nil || 
     width != _textureWidth || 
     height != _textureHeight) 
    { 
     _textureWidth = width; 
     _textureHeight = height; 

     _ripple = [[RippleModel alloc] initWithScreenWidth:_screenWidth 
               screenHeight:_screenHeight 
               meshFactor:_meshFactor 
               touchRadius:5 
               textureWidth:_textureWidth 
              textureHeight:_textureHeight]; 

     [self setupBuffers]; 
    } 

    [self cleanUpTextures]; 

    NSLog(@"%zi x %zi", _textureWidth, _textureHeight); 

    // RGBA texture 
    glActiveTexture(GL_TEXTURE0); 
    err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, 
                 _videoTextureCache, 
                 pixelBuffer, 
                 NULL, 
                 GL_TEXTURE_2D, 
                 GL_RGBA, 
                 _textureWidth, 
                 _textureHeight, 
                 GL_BGRA, 
                 GL_UNSIGNED_BYTE, 
                 0, 
                 &_chromaTexture); 
    if (err) 
    { 
     NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err); 
    } 

    glBindTexture(CVOpenGLESTextureGetTarget(_chromaTexture), CVOpenGLESTextureGetName(_chromaTexture)); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
} 

Cualquier sugerencias para una solución a este problema?

+0

He estado probando en varios dispositivos ahora y hasta ahora sigue siendo el combo único: iPhone 4 + IOS6.0. Incluso el iPod touch (4ª generación) puede convertir cuadros de cámara en Texturas GLES. – polyclick

Respuesta

1

No podemos convertir una textura de imagen fija en CVOpenGLESTextureCacheRef. Core Video le permite mapear marcos de video directamente a texturas OpenGL. Usando un búfer de video donde Core Video crea las texturas y nos las da, ya en la memoria de video.

Para crear la textura OpenGLES este enlace puede ayudarle a Link

2

El iPhone 4 (así como el iPhone 3GS y el iPod Touch cuarta generación.) Utiliza una GPU PowerVR SGX 535, para lo cual el maximum OpenGL ES texture size is 2048x2048. Este valor se puede encontrar llamando al

glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); 

El iPod Touch 4ta generación. tiene una resolución de cámara de 720x960 y iPhone 3GS, 640x1136, pero la resolución de la cámara trasera del iPhone 4 es de 1936x2592, que es demasiado grande para caber en una sola textura.

Siempre puede reescribir la imagen capturada en un tamaño más pequeño, conservando la relación de aspecto (1529x2048). Brad Larson hace esto en his GPUImage framework, pero es bastante sencillo, simplemente redibuja los datos del buffer de píxeles original usando Core Graphics y luego crea otro buffer de píxeles de los datos redibujados. El resto del marco también es un gran recurso.

Cuestiones relacionadas