2012-10-01 14 views
17

Dla mojego bieżącego projektu czytam wyjście kamery głównej iPhone'a. Następnie konwertuję bufor pikseli do buforowanej tekstury OpenGL za pomocą metody: CVOpenGLESTextureCacheCreateTextureFromImage. Działa to świetnie podczas przetwarzania ramek kamer używanych do podglądu. Testowane w różnych kombinacjach z urządzeniami iPhone 3GS, 4, 4S, iPod Touch (4. gen) i IOS5, IOS6.CVOpenGLESTextureCacheCreateTextureFromImage nie tworzy IOSurface

Ale dla rzeczywistego ostatecznego obrazu, który ma bardzo wysoką rozdzielczość, to działa tylko na tych kombinacjach:

  • iPhone 3GS + IOS 5.1.1
  • iPhone 4 + IOS 5.1.1
  • iPhone 4S + IOS 6,0
  • iPod touch (4. generacji) + IOS 5,0

I to nie działa dla: iPhone 4 + iOS6.

Dokładny komunikat o błędzie w konsoli:

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

mam izolowane ten problem poprzez zmianę projektu GLCameraRipple firmy Apple. Możesz sprawdzić swoją wersję tutaj: http://lab.bitshiftcop.com/iosurface.zip

Oto jak dodać stilloutput do bieżącej sesji:

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

A oto jak przechwycić wyjście nieruchomego i przetwarza je:

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

Oto, jak tworzona jest tekstura:

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

Dowolna sugestie dotyczące rozwiązania tego problemu?

+0

Testowałem na wielu urządzeniach teraz i do tej pory to wciąż wyjątkowe combo: iPhone 4 + IOS6.0. Nawet iPod touch (4. gen) może konwertować ramki do formatu GLES. – polyclick

Odpowiedz

1

Nie możemy przesłać tekstury obrazu nieruchomego do CVOpenGLESTextureCacheRef. Core Video pozwala mapować klatki wideo bezpośrednio na tekstury OpenGL. Używanie bufora wideo, w którym Core Video tworzy tekstury i przekazuje je nam, już w pamięci wideo.

Aby utworzyć OpenGLES teksturę ten link może Ci Link

2

pomóc iPhone 4 (a także iPhone 3GS i iPod touch 4th gen.) Korzysta z PowerVR SGX 535 GPU, dla którego maximum OpenGL ES texture size is 2048x2048. Tę wartość można znaleźć, dzwoniąc pod numer:

iPod Touch 4. gen. ma rozdzielczość kamery 720x960 i iPhone'a 3GS, 640x1136, ale rozdzielczość tylnego aparatu iPhone 4 to 1936x2592, która jest zbyt duża, aby zmieścić się na pojedynczej teksturze.

Zawsze można przepisać przechwycony obraz przy mniejszym rozmiarze, zachowując współczynnik proporcji (1529 x 2048). Brad Larson wykonuje to na his GPUImage framework, ale jest to całkiem proste, po prostu przerysowuję dane oryginalnego bufora pikseli za pomocą Core Graphics, a następnie robimy kolejny bufor pikseli z przerysowanych danych. Reszta frameworka jest również świetnym zasobem.