Как конвертировать CVImageBufferRef в UIImage

Я пытаюсь захватить видео с камеры. я получил captureOutput:didOutputSampleBuffer: обратный вызов для запуска, и это дает мне пример буфера, который я затем преобразовать в CVImageBufferRef, Затем я пытаюсь преобразовать это изображение в UIImage что я могу затем просмотреть в моем приложении.

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    /*Lock the image buffer*/
    CVPixelBufferLockBaseAddress(imageBuffer,0); 
    /*Get information about the image*/
    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer); 
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

    /*We unlock the  image buffer*/
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);

    /*Create a CGImageRef from the CVImageBufferRef*/
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    CGImageRef newImage = CGBitmapContextCreateImage(newContext); 

    /*We release some components*/
    CGContextRelease(newContext); 
     CGColorSpaceRelease(colorSpace);

     /*We display the result on the custom layer*/
    /*self.customLayer.contents = (id) newImage;*/

    /*We display the result on the image view (We need to change the orientation of the image so that the video is displayed correctly)*/
    UIImage *image= [UIImage imageWithCGImage:newImage scale:1.0 orientation:UIImageOrientationRight];
    self.capturedView.image = image;

    /*We relase the CGImageRef*/
    CGImageRelease(newImage);
}

кажется, что код работает нормально до вызова CGBitmapContextCreate, это всегда возвращает NULL указатель. следовательно, ни одна из остальных функций не работает. Независимо от того, что я, кажется, передать его, функция возвращает ноль. Понятия не имею почему.

4 ответа

Решение

То, как вы передаете baseAddress, предполагает, что данные изображения находятся в форме

СКПК

(где C - некоторая цветовая составляющая, R || G || B).

Если вы настроили AVCaptureSession для захвата видеокадров в собственном формате, скорее всего, вы вернете видеоданные обратно в плоский формат YUV420. (см.: текст ссылки). Чтобы сделать то, что вы пытаетесь сделать здесь, вероятно, проще всего было бы указать, что вы хотите, чтобы видеокадры были захвачены в kCVPixelFormatType_32RGBA . Apple рекомендует захватывать видеокадры в kCVPixelFormatType_32BGRA, если вы вообще захватываете его в непланарном формате, причина чего не указана, но я могу предположить, что это связано с соображениями производительности.

Предостережение: я этого не делал, и я предполагаю, что такой доступ к содержимому CVPixelBufferRef является разумным способом построения образа. Я не могу ручаться за то, что это действительно работает, но я / могу / сказать вам, что то, как вы делаете вещи сейчас, надежно не будет работать из-за формата пикселя, который вы (вероятно) захватывает видеокадры.

Если вам просто нужно конвертировать CVImageBufferRef в UIImage, это будет гораздо сложнее, чем должно быть. По сути вам нужно конвертировать в CIImage, затем CGImage, THEN UIImage. Я хотел бы сказать вам, почему. Кто знает.

-(void) screenshotOfVideoStream:(CVImageBufferRef)imageBuffer
{
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer];
    CIContext *temporaryContext = [CIContext contextWithOptions:nil];
    CGImageRef videoImage = [temporaryContext
                             createCGImage:ciImage
                             fromRect:CGRectMake(0, 0,
                             CVPixelBufferGetWidth(imageBuffer),
                             CVPixelBufferGetHeight(imageBuffer))];

    UIImage *image = [[UIImage alloc] initWithCGImage:videoImage];
    [self doSomethingWithOurUIImage:image];
    CGImageRelease(videoImage);
}

Этот конкретный метод работал для меня, когда я конвертировал видео H.264 с помощью обратного вызова VTDecompressionSession, чтобы получить CVImageBufferRef (но он должен работать для любого CVImageBufferRef). Я использовал iOS 8.1, XCode 6.2.

Вы можете напрямую позвонить:

self.yourImageView.image=[[UIImage alloc] initWithCIImage:[CIImage imageWithCVPixelBuffer:imageBuffer]];

Бенджамин Лульер написал действительно хороший пост о выводе CVImageBufferRef с учетом скорости при нескольких подходах.

Вы также можете найти рабочий пример на github;)

Как насчет назад во времени?;) Вот и вы: http://web.archive.org/web/20140426162537/http://www.benjaminloulier.com/posts/ios4-and-direct-access-to-the-camera

Другие вопросы по тегам