UIImage, созданный из CMSampleBufferRef, не отображенного в UIImageView?

Я пытаюсь отобразить UIImage, в режиме реального времени прибывающий из камеры, и кажется, что мой UIImageView не отображает изображение правильно. Это - метод который a AVCaptureVideoDataOutputSampleBufferDelegate должен реализовать

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
       fromConnection:(AVCaptureConnection *)connection
{ 
    // Create a UIImage from the sample buffer data
    UIImage *theImage = [self imageFromSampleBuffer:sampleBuffer];
//    NSLog(@"Got an image! %f %f", theImage.size.width, theImage.size.height);
//    NSLog(@"The image view is %@", imageView);
//    UIImage *theImage = [[UIImage alloc] initWithData:[NSData 
//        dataWithContentsOfURL:[NSURL 
//        URLWithString:@"http://farm4.static.flickr.com/3092/2915896504_a88b69c9de.jpg"]]];
    [self.session stopRunning];
    [imageView setImage: theImage];
}

Избавиться от легких проблем:

  • Используя UIImagePickerController не опция (в конечном счете, мы на самом деле сделаем вещи с изображением),
  • Я знаю, что обработчик называют (вызовы NSLog выполняются, и я вижу вывод),
  • Я знаю, что мне настраивали объявления IBOutlet правильно. Если я использую прокомментированный код выше для загрузки произвольного изображения из сети вместо простой отправки setImage:theImage к imageView изображение загружается правильно (и второй вызов к отчетам NSLog ненулевой объект).
  • По крайней мере, до основной степени, изображение я добираюсь от imageFromSampleBuffer: прекрасен, начиная с отчетов NSLog размер, чтобы быть 360x480, который является размером, который я ожидал.

Код, который я использую, является недавно отправленным AVFoundation отрывок от Apple, доступной здесь.

В частности, это - код, который я использую, который настраивает AVCaptureSession объект и друзья (которых я понимаю очень мало), и создают объект UIImage из Базовых Видео буферов (это imageFromSampleBuffer метод).

Наконец, я могу заставить приложение отказывать, если я пытаюсь отправить drawInRect: к простому UIView разделяют на подклассы с UIImage возвращенный imageFromSamplerBuffer, в то время как это не отказывает, если я использую UIImage от URL как выше. Вот отслеживание стека от отладчика в катастрофическом отказе (я получаю сигнал EXC_BAD_ACCESS):

#0  0x34a977ee in decode_swap ()
#1  0x34a8f80e in decode_data ()
#2  0x34a8f674 in img_decode_read ()
#3  0x34a8a76e in img_interpolate_read ()
#4  0x34a63b46 in img_data_lock ()
#5  0x34a62302 in CGSImageDataLock ()
#6  0x351ab812 in ripc_AcquireImage ()
#7  0x351a8f28 in ripc_DrawImage ()
#8  0x34a620f6 in CGContextDelegateDrawImage ()
#9  0x34a61fb4 in CGContextDrawImage ()
#10 0x321fd0d0 in -[UIImage drawInRect:blendMode:alpha:] ()
#11 0x321fcc38 in -[UIImage drawInRect:] ()

Править: Вот еще некоторая информация о UIImage том, чтобы быть возвращенным тем битом кода.

Используя метод, описанный здесь, я могу добраться до пикселей и распечатать их, и они смотрят хорошо на первый взгляд (каждое значение в альфа-канале 255, например). Однако существует что-то немного прочь с буферными размерами. Изображение, которое я получаю из Flickr, с которой URL 375x500, и [pixelData length] дает мне 750000 = 375*500*4, который является математическим ожиданием. Однако пиксельные данные изображения, возвращенного из imageFromSampleBuffer: имеет размер 691208 = 360*480*4 + 8, таким образом, существует 8 дополнительных байтов в пиксельных данных. CVPixelBufferGetDataSize самостоятельно возвращает это off-8 значение. Я думал на мгновение, что это могло произойти из-за выделения буферов в выровненных положениях в памяти, но 691200 является кратным 256, так, чтобы не объяснял это также. Это несоответствие размера является единственной разницей, которую я могу сказать между двумя UIImages, и это могло доставлять неприятности. Однако, нет никакой причины, выделяющей дополнительную память для буфера, должен вызвать нарушение EXC_BAD_ACCESS.

Большое спасибо за любую справку, и сообщают мне, нужно ли Вам больше информации.

23
задан Community 23 May 2017 в 10:29
поделиться

2 ответа

У меня была та же проблема ... но я нашел этот старый пост, и его метод создания CGImageRef работает!

http://forum.unity3d.com/viewtopic.php?p=300819

Вот рабочий пример:

app has a member UIImage theImage;

// Delegate routine that is called when a sample buffer was written
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer  fromConnection:(AVCaptureConnection *)connection
{
        //... just an example of how to get an image out of this ...

    CGImageRef cgImage = [self imageFromSampleBuffer:sampleBuffer];
    theImage.image =     [UIImage imageWithCGImage: cgImage ];
    CGImageRelease( cgImage );
}

- (CGImageRef) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer // Create a CGImageRef from sample buffer data
{
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    CVPixelBufferLockBaseAddress(imageBuffer,0);        // Lock the image buffer 

    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);   // Get information of the image 
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

    CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    CGImageRef newImage = CGBitmapContextCreateImage(newContext); 
    CGContextRelease(newContext); 

    CGColorSpaceRelease(colorSpace); 
    CVPixelBufferUnlockBaseAddress(imageBuffer,0); 
    /* CVBufferRelease(imageBuffer); */  // do not call this!

    return newImage;
}
40
ответ дан 29 November 2019 в 01:07
поделиться

Бен Лулиер написал хорошую статью о том, как это сделать.

Я использую его пример приложения в качестве отправной точки, и оно у меня работает. Наряду с заменой функции imageFromSamplerBuffer чем-то, что создает CGImageRef с CGBitmapContextCreate, он использует основную очередь отправки (через dispatch_get_main_queue () ) при настройке делегата выходного буфера выборки. Это не лучшее решение, потому что ему нужна последовательная очередь, и, насколько я понимаю, основная очередь не является последовательной очередью. Так что, хотя у вас нет гарантии, что кадры будут в правильном порядке, это пока работает для меня :)

5
ответ дан 29 November 2019 в 01:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: