AVCapturesessions только один кадр для iPhone 3GS
-
25-09-2019 - |
Вопрос
У меня есть кусок кода, который устанавливает сеанс захвата от камеры для обработки кадров с использованием OpenCV, а затем установить свойство изображения UIImageView с генерируемым Uiimage из кадра. Когда приложение запускается, изображение представления изображения является Nil и никаких кадров не отображается до тех пор, пока я не начнусь на другой контроллер просмотра в стеке, а затем выключить его. Тогда изображение остается прежним, пока не сделаю это снова. Заявления NSLog показывают, что обратный вызов вызывается примерно при правильной частоте кадров. Любые идеи, почему это не появляется? Я сократил пламерат до 2 кадров в секунду. Это не обработано достаточно быстро?
Вот код:
- (void)setupCaptureSession {
NSError *error = nil;
// Create the session
AVCaptureSession *session = [[AVCaptureSession alloc] init];
// Configure the session to produce lower resolution video frames, if your
// processing algorithm can cope. We'll specify medium quality for the
// chosen device.
session.sessionPreset = AVCaptureSessionPresetLow;
// Find a suitable AVCaptureDevice
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// Create a device input with the device and add it to the session.
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device
error:&error];
if (!input) {
// Handling the error appropriately.
}
[session addInput:input];
// Create a VideoDataOutput and add it to the session
AVCaptureVideoDataOutput *output = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
output.alwaysDiscardsLateVideoFrames = YES;
[session addOutput:output];
// Configure your output.
dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
[output setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);
// Specify the pixel format
output.videoSettings =
[NSDictionary dictionaryWithObject:
[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
// If you wish to cap the frame rate to a known value, such as 15 fps, set
// minFrameDuration.
output.minFrameDuration = CMTimeMake(1, 1);
// Start the session running to start the flow of data
[session startRunning];
// Assign session to an ivar.
[self setSession:session];
}
// Create a UIImage from sample buffer data
- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer {
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
// Lock the base address of the pixel buffer
CVPixelBufferLockBaseAddress(imageBuffer,0);
// Get the number of bytes per row for the pixel buffer
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
// Get the pixel buffer width and height
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
// Create a device-dependent RGB color space
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
if (!colorSpace)
{
NSLog(@"CGColorSpaceCreateDeviceRGB failure");
return nil;
}
// Get the base address of the pixel buffer
void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
// Get the data size for contiguous planes of the pixel buffer.
size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);
// Create a Quartz direct-access data provider that uses data we supply
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, baseAddress, bufferSize,
NULL);
// Create a bitmap image from data supplied by our data provider
CGImageRef cgImage =
CGImageCreate(width,
height,
8,
32,
bytesPerRow,
colorSpace,
kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
provider,
NULL,
true,
kCGRenderingIntentDefault);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
// Create and return an image object representing the specified Quartz image
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
return image;
}
// Delegate routine that is called when a sample buffer was written
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection {
// Create a UIImage from the sample buffer data
UIImage *image = [self imageFromSampleBuffer:sampleBuffer];
[self.delegate cameraCaptureGotFrame:image];
}
Решение
Это может быть связано с Threading-Try:
[self.delegate performSelectorOnMainThread:@selector(cameraCaptureGotFrame:) withObject:image waitUntilDone:NO];
Другие советы
Это выглядит как проблема в потоке. Вы не можете обновить свои представления в любом другом потоке, чем в основном потоке. В вашей настройке, которая хорошая, функция делегата CaptureOutput: Didoutputsamplebuffer: называется в вторичном потоке. Таким образом, вы не можете установить вид изображения оттуда. Ответ Art Gillespie - один из способов решения его, если вы можете избавиться от ошибки плохого доступа.
Другим способом является изменение образца буфера в CaptureOutput: Didoutputsamplebuffer: и имеют показано, добавляя Avcapturevideopreviewlayer. экземпляр к вашей сессии захвата. Это, безусловно, предпочтительнее способ, если вы изменяете небольшую часть изображения, такого как что-то подчеркивая.
BTW: ошибка вашей плохой доступа может возникнуть, потому что вы не сохраняете созданное изображение во вторичном потоке, и поэтому он будет освобожден до CameracaptureGotFrame. вызывается на главной ните.
Обновлять: Чтобы правильно сохранить изображение, увеличьте ссылочный счет в CaptureOutput: Didoutputsamplebuffer: (во вторичном потоке) и уменьшение его в CameracaptureGotFrame: (в главной ните).
// Delegate routine that is called when a sample buffer was written
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
// Create a UIImage from the sample buffer data
UIImage *image = [self imageFromSampleBuffer:sampleBuffer];
// increment ref count
[image retain];
[self.delegate performSelectorOnMainThread:@selector(cameraCaptureGotFrame:)
withObject:image waitUntilDone:NO];
}
- (void) cameraCaptureGotFrame:(UIImage*)image
{
// whatever this function does, e.g.:
imageView.image = image;
// decrement ref count
[image release];
}
Если вы не увеличите ссылочный счетчик, изображение освобождается от пула автоматического выпуска второго потока до CameracaptureGotFrame: вызывается в главной ните. Если вы не уменьшаете его в основной поток, изображения никогда не освобождаются, и вы не хватаете памяти в течение нескольких секунд.
Вы делаете SETNEEDSDISPLAY на UiimageView после каждого нового обновления свойства изображения?
Редактировать:
Где и когда вы обновляете свойство фона изображения на вашем изображении?