2010-07-26 21 views
6

Je capture la vidéo et la convertit en une CGImage pour faire le traitement dessus. Il fonctionnera pendant ~ 10 secondes, recevra un avertissement de mémoire, puis se bloquera (généralement, il est dit que les formateurs de données sont temporairement indisponibles). Quelqu'un peut-il m'aider à résoudre le problème?iPhone: écrasement de sortie de capture AVCaptureSession (AVCaptureVideoDataOutput)

- (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { 

// CONVERT CMSAMPLEBUFFER INTO A CGIMAGE 
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 

CVPixelBufferLockBaseAddress(imageBuffer,0); 


uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer); 
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 cgimage = CGBitmapContextCreateImage(newContext); 
UIImage *sourceImage= [UIImage imageWithCGImage:cgimage scale:1.0f orientation:UIImageOrientationLeftMirrored]; 
CGImageRelease(cgimage); 
CGContextRelease(newContext); 
CGColorSpaceRelease(colorSpace); 

CVPixelBufferUnlockBaseAddress(imageBuffer,0); 


// *** 
// Adding code after this point to do image transformation usually causes it to crash 
UIImage *rot = [self scaleAndRotateImage:sourceImage]; 
self.detectImage = rot; 



} 

Code pour transformer l'image ....

- (UIImage*)scaleAndRotateImage:(UIImage *)image{ 
    int kMaxResolution = 320; // Or whatever 

    CGImageRef imgRef = image.CGImage; 

    CGFloat width = CGImageGetWidth(imgRef); 
    CGFloat height = CGImageGetHeight(imgRef); 

    CGAffineTransform transform = CGAffineTransformIdentity; 
    CGRect bounds = CGRectMake(0, 0, width, height); 
    if (width > kMaxResolution || height > kMaxResolution) { 
     CGFloat ratio = width/height; 
     if (ratio > 1) { 
      bounds.size.width = kMaxResolution; 
      bounds.size.height = bounds.size.width/ratio; 
     } 
     else { 
      bounds.size.height = kMaxResolution; 
      bounds.size.width = bounds.size.height * ratio; 
     } 
    } 

    CGFloat scaleRatio = bounds.size.width/width; 
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); 
    CGFloat boundHeight; 
    UIImageOrientation orient = image.imageOrientation; 
    switch(orient) { 

     case UIImageOrientationUp: //EXIF = 1 
      transform = CGAffineTransformIdentity; 
      break; 

     case UIImageOrientationUpMirrored: //EXIF = 2 
      transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0); 
      transform = CGAffineTransformScale(transform, -1.0, 1.0); 
      break; 

     case UIImageOrientationDown: //EXIF = 3 
      transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height); 
      transform = CGAffineTransformRotate(transform, M_PI); 
      break; 

     case UIImageOrientationDownMirrored: //EXIF = 4 
      transform = CGAffineTransformMakeTranslation(0.0, imageSize.height); 
      transform = CGAffineTransformScale(transform, 1.0, -1.0); 
      break; 

     case UIImageOrientationLeftMirrored: //EXIF = 5 
      boundHeight = bounds.size.height; 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = boundHeight; 
      transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.height); 
      transform = CGAffineTransformScale(transform, -1.0, 1.0); 
      transform = CGAffineTransformRotate(transform, 3.0 * M_PI/2.0); 
      break; 

     case UIImageOrientationLeft: //EXIF = 6 
      boundHeight = bounds.size.height; 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = boundHeight; 
      transform = CGAffineTransformMakeTranslation(0.0, imageSize.width); 
      transform = CGAffineTransformRotate(transform, 3.0 * M_PI/2.0); 
      break; 

     case UIImageOrientationRightMirrored: //EXIF = 7 
      boundHeight = bounds.size.height; 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = boundHeight; 
      transform = CGAffineTransformMakeScale(-1.0, 1.0); 
      transform = CGAffineTransformRotate(transform, M_PI/2.0); 
      break; 

     case UIImageOrientationRight: //EXIF = 8 
      boundHeight = bounds.size.height; 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = boundHeight; 
      transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0); 
      transform = CGAffineTransformRotate(transform, M_PI/2.0); 
      break; 

     default: 
      [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"]; 

    } 

    UIGraphicsBeginImageContext(bounds.size); 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) { 
     CGContextScaleCTM(context, -scaleRatio, scaleRatio); 
     CGContextTranslateCTM(context, -height, 0); 
    } 
    else { 
     CGContextScaleCTM(context, scaleRatio, -scaleRatio); 
     CGContextTranslateCTM(context, 0, -height); 
    } 

    CGContextConcatCTM(context, transform); 

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef); 
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    //[self setRotatedImage:imageCopy]; 
    return imageCopy; 
} 

Cette fonction est juste fond pour voir comment je configurer la sortie vidéo ...

AVCaptureVideoDataOutput *videoOut = [[AVCaptureVideoDataOutput alloc] init]; 
[videoOut setAlwaysDiscardsLateVideoFrames:YES]; 
[videoOut setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey]]; // BGRA is necessary for manual preview 
dispatch_queue_t my_queue = dispatch_queue_create("com.example.subsystem.taskXYZ", NULL); 
[videoOut setSampleBufferDelegate:self queue:my_queue]; 
if ([self.captureSession canAddOutput:videoOut]) [self.captureSession addOutput:videoOut]; 
else NSLog(@"Couldn't add video output"); 
[videoOut release]; 

Répondre

0

Dans la mise en place de la sortie vidéo, la file d'attente de répartition nouvellement créée n'est pas libérée. Vous pouvez le libérer avec

dispatch_release(queue); 

Mais je ne crois pas que cette fonction soit appelée trop souvent, donc la fuite provient probablement d'ailleurs. Vous avez parcouru votre code plusieurs fois, vous n'avez trouvé aucun autre coupable ...

Avez-vous essayé de rechercher la fuite avec l'outil d'instrument de fuite?

4

J'ai eu un problème similaire. Ce qui s'est passé, c'est que la file d'attente se remplissait de trames non traitées, car je ne traitais pas assez vite dans l'objet délégué.

Ma solution était de faire (une fois par trame traitée):

proctr++; 
if ((proctr % 20) == 0) { 
    deferImageProcessing = true; 
    dispatch_sync(queue, ^{ 
    [self queueFlushed]; 
    }); 
} 

- (void)queueFlushed { 
    deferImageProcessing = false; 
} 

Ensuite, dans le code de traitement d'image réelle

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
    didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
    fromConnection:(AVCaptureConnection *)connection 
{ 
    if (deferImageProcessing) 
    return; 
    // do whatever else I'm doing... 
} 

Essentiellement, nous suspendons de temps en temps de traitement d'image jusqu'à ce que la file d'attente vide.
J'espère que c'est utile.

+0

Où dans votre code avez-vous mis le proctr ++; partie du code? L'avez-vous mis après le // faire tout ce que je fais ... section? Je suis le même problème maintenant, se bloque après le traitement d'environ 420 images. – Davido