Avcapturesession فقط الحصول على إطار واحد لجهاز iPhone 3GS

StackOverflow https://stackoverflow.com/questions/3602624

  •  25-09-2019
  •  | 
  •  

سؤال

لديّ قطعة من التعليمات البرمجية تقوم بإعداد جلسة التقاط من الكاميرا لمعالجة الإطارات باستخدام OpenCV ثم ضبط خاصية Image الخاصة بـ UiimageView مع uiimage تم إنشاؤها من الإطار. عند بدء تشغيل التطبيق ، تكون صورة عرض الصورة لا شيء ولا تظهر أي إطارات حتى أدفع وحدة تحكم عرض أخرى على المكدس ثم قم بتشغيلها. ثم تبقى الصورة كما هي حتى أفعل ذلك مرة أخرى. تُظهر عبارات 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];
}
هل كانت مفيدة؟

المحلول

يمكن أن يكون هذا مرتبطًا بالخيوط - تجرب:

[self.delegate performSelectorOnMainThread:@selector(cameraCaptureGotFrame:) withObject:image waitUntilDone:NO];

نصائح أخرى

هذا يبدو وكأنه مشكلة في الخيوط. لا يمكنك تحديث وجهات نظرك في أي مؤشر ترابط آخر عن الخيط الرئيسي. في الإعداد الخاص بك ، وهو أمر جيد ، وظيفة المندوب CaptureOutput: didoutputsamplebuffer: يسمى في موضوع ثانوي. لذلك لا يمكنك تعيين عرض الصورة من هناك. إجابة Art Gillespie هي إحدى طرق حلها إذا تمكنت من التخلص من خطأ الوصول السيئ.

طريقة أخرى هي تعديل العينة المخزن المؤقت في CaptureOutput: didoutputsamplebuffer: ويظهر بإضافة أ AvcaptureVideOpReviewLayer مثيل لجلسة الالتقاط. هذه بالتأكيد الطريقة المفضلة إذا قمت فقط بتعديل جزء صغير من الصورة مثل تسليط الضوء على شيء ما.

راجع للشغل: قد ينشأ خطأ الوصول السيئ لأنك لا تحتفظ بالصورة التي تم إنشاؤها في الخيط الثانوي وبالتالي سيتم تحريرها من قبل 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 بعد كل تحديث خاصية صورة جديدة؟

تعديل:

أين ومتى تقوم بتحديث خاصية صورة الخلفية في طريقة عرض الصور الخاصة بك؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top