2010-09-07 15 views
34

He estado rasgándome el pelo intentando que la cámara AVFoundation capture una imagen en la orientación correcta (es decir, la orientación del dispositivo) pero no puedo hacer que funcione.iPhone AVFoundation orientación de la cámara

He visto tutoriales, he visto la presentación de WWDC y he descargado el programa de ejemplo WWDC, pero incluso eso no lo hace.

El código de mi aplicación es ...

AVCaptureConnection *videoConnection = [CameraVC connectionWithMediaType:AVMediaTypeVideo fromConnections:[imageCaptureOutput connections]]; 
if ([videoConnection isVideoOrientationSupported]) 
{ 
    [videoConnection setVideoOrientation:[UIApplication sharedApplication].statusBarOrientation]; 
} 

[imageCaptureOutput captureStillImageAsynchronouslyFromConnection:videoConnection 
               completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) 
{ 
    if (imageDataSampleBuffer != NULL) 
    { 
     //NSLog(@"%d", screenOrientation); 

     //CMSetAttachment(imageDataSampleBuffer, kCGImagePropertyOrientation, [NSString stringWithFormat:@"%d", screenOrientation], 0); 

     NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; 
     UIImage *image = [[UIImage alloc] initWithData:imageData]; 

     [self processImage:image]; 
    } 
}]; 

(processImage utiliza el mismo método writeImage ... como el código de la WWDC)

y el código de la aplicación de la WWDC es ...

AVCaptureConnection *videoConnection = [AVCamDemoCaptureManager connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]]; 
     if ([videoConnection isVideoOrientationSupported]) { 
      [videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait]; 
     } 

[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection 
                  completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) { 
                   if (imageDataSampleBuffer != NULL) { 
                    NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; 
                    UIImage *image = [[UIImage alloc] initWithData:imageData];                 
                    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; 
                    [library writeImageToSavedPhotosAlbum:[image CGImage] 
                           orientation:(ALAssetOrientation)[image imageOrientation] 
                          completionBlock:^(NSURL *assetURL, NSError *error){ 
                           if (error) { 
                            id delegate = [self delegate]; 
                            if ([delegate respondsToSelector:@selector(captureStillImageFailedWithError:)]) { 
                             [delegate captureStillImageFailedWithError:error]; 
                            }                        
                           } 
                          }]; 
                    [library release]; 
                    [image release]; 
                   } else if (error) { 
                    id delegate = [self delegate]; 
                    if ([delegate respondsToSelector:@selector(captureStillImageFailedWithError:)]) { 
                     [delegate captureStillImageFailedWithError:error]; 
                    } 
                   } 
                  }]; 

al comienzo de su código que defina el AVOrientation al retrato que parece muy extraño, pero estoy tratando de conseguir que se detecta la orientación actual del dispositivo y utilizar eso.

Como puedes ver, he puesto [UIApplication sharedApplication] statusBarOrientation para intentar obtener esto, pero aún así solo guardo las fotos en vertical.

¿Alguien puede ofrecer alguna ayuda o consejo sobre lo que debo hacer?

Gracias!

Oliver

Respuesta

44

Bueno, me ha tomado fracking para siempre, pero lo he hecho!

El trozo de código que estaba buscando es

[UIDevice currentDevice].orientation; 

Esto va en como tan

AVCaptureConnection *videoConnection = [CameraVC connectionWithMediaType:AVMediaTypeVideo fromConnections:[imageCaptureOutput connections]]; 
if ([videoConnection isVideoOrientationSupported]) 
{ 
    [videoConnection setVideoOrientation:[UIDevice currentDevice].orientation]; 
} 

y funciona perfectamente: D

Woop woop!

+2

Bueno, pensé que había arreglado pero por desgracia estaba equivocado. Soluciona el problema de mostrar la imagen en el teléfono y la guarda correctamente en la biblioteca, pero cuando se cargan en Facebook o se miran en mi computadora, siguen estando equivocados :( – Fogmeister

+2

¿Cuál fue su solución final? Noté una rareza que su publicación me ayudó con. UIDeviceOrientation y AVCaptureVideoOrientation no son idénticos. LandscapeRight y LandscapeLeft se intercambian en la enumeración. Me estaba haciendo un largo (si retrato/conjunto retrato, si paisaje izquierda/establece paisaje izquierda) y mis imágenes de paisaje siempre estaban boca abajo! Parece que el intercambio es necesario para mantener la asignación correcta, pero no estoy seguro de cómo funciona. –

+0

Hmm.Para mí, la orientación de la miniatura en la biblioteca de fotos se rota, pero la imagen en sí misma está bien. –

-1

¿Cómo usar con AVCaptureFileOutput?

- (void)detectVideoOrientation:(AVCaptureFileOutput *)captureOutput { 
    for(int i = 0; i < [[captureOutput connections] count]; i++) { 
     AVCaptureConnection *captureConnection = [[captureOutput connections] objectAtIndex:i]; 
     if([captureConnection isVideoOrientationSupported]) { 
      [captureConnection setVideoOrientation:[[UIDevice currentDevice] orientation]]; 
     } 
    } 
} 
+0

Gracias, me iré mañana por la noche. No tendré acceso a mi MBP hasta entonces. – Fogmeister

4

hay dos cosas a notar

a) como escribió Brian King - LandscapeRight y LandscapeLeft se intercambian en la enumeración. ver AVCamCaptureManager ejemplo:

// AVCapture and UIDevice have opposite meanings for landscape left and right (AVCapture orientation is the same as UIInterfaceOrientation) 
else if (deviceOrientation == UIDeviceOrientationLandscapeLeft) 
    orientation = AVCaptureVideoOrientationLandscapeRight; 
else if (deviceOrientation == UIDeviceOrientationLandscapeRight) 
    orientation = AVCaptureVideoOrientationLandscapeLeft; 

b) También hay UIDeviceOrientationFaceUp y UIDeviceOrientationFaceDown estados, que si se intenta establecer como la orientación de vídeo, el vídeo se producirá un error de grabación. ¡Asegúrese de no utilizarlos cuando llame al [UIDevice currentDevice].orientation!

11

El siguiente es de AVCam, he añadido también que:

- (void)deviceOrientationDidChange{ 

    UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation]; 

    AVCaptureVideoOrientation newOrientation; 

    if (deviceOrientation == UIDeviceOrientationPortrait){ 
     NSLog(@"deviceOrientationDidChange - Portrait"); 
     newOrientation = AVCaptureVideoOrientationPortrait; 
    } 
    else if (deviceOrientation == UIDeviceOrientationPortraitUpsideDown){ 
     NSLog(@"deviceOrientationDidChange - UpsideDown"); 
     newOrientation = AVCaptureVideoOrientationPortraitUpsideDown; 
    } 

    // AVCapture and UIDevice have opposite meanings for landscape left and right (AVCapture orientation is the same as UIInterfaceOrientation) 
    else if (deviceOrientation == UIDeviceOrientationLandscapeLeft){ 
     NSLog(@"deviceOrientationDidChange - LandscapeLeft"); 
     newOrientation = AVCaptureVideoOrientationLandscapeRight; 
    } 
    else if (deviceOrientation == UIDeviceOrientationLandscapeRight){ 
     NSLog(@"deviceOrientationDidChange - LandscapeRight"); 
     newOrientation = AVCaptureVideoOrientationLandscapeLeft; 
    } 

    else if (deviceOrientation == UIDeviceOrientationUnknown){ 
     NSLog(@"deviceOrientationDidChange - Unknown "); 
     newOrientation = AVCaptureVideoOrientationPortrait; 
    } 

    else{ 
     NSLog(@"deviceOrientationDidChange - Face Up or Down"); 
     newOrientation = AVCaptureVideoOrientationPortrait; 
    } 

    [self setOrientation:newOrientation]; 
} 

y asegúrese de agregar esto a su método init:

NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 
[notificationCenter addObserver:self 
    selector:@selector(deviceOrientationDidChange) 
    name:UIDeviceOrientationDidChangeNotification object:nil]; 
[self setOrientation:AVCaptureVideoOrientationPortrait]; 
+0

¿No es esto un poco más limpio? –

+0

Esta solución junto con UIImage + fixOrientation.h soluciona el problema de la orientación completamente –

0

También puede crear una CIImage intermedia, y agarrar las propiedades Diccionario

NSDictionary *propDict = [aCIImage properties]; 
NSString *orientString = [propDict objectForKey:kCGImagePropertyOrientation]; 

y transformar en consecuencia :)

¡Me encanta lo fácil que es acceder a todos estos metadatos de imagen en iOS5!

3

Si está utilizando AVCaptureVideoPreviewLayer puede hacer lo siguiente dentro de su controlador de visualización.

(suponiendo que tiene una instancia de AVCaptureVideoPreviewLayer llamado "previewLayer")

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    [self.previewLayer setOrientation:[[UIDevice currentDevice] orientation]]; 
} 
+4

AVCaptureVideoPreviewLayer setOrientation: está en desuso. –

+1

@TalYaniv en el momento en que se escribió esta respuesta, no fue desaprobada. –

12

No es esto un poco más limpio?

AVCaptureVideoOrientation newOrientation; 
    switch ([[UIDevice currentDevice] orientation]) { 
    case UIDeviceOrientationPortrait: 
     newOrientation = AVCaptureVideoOrientationPortrait; 
     break; 
    case UIDeviceOrientationPortraitUpsideDown: 
     newOrientation = AVCaptureVideoOrientationPortraitUpsideDown; 
     break; 
    case UIDeviceOrientationLandscapeLeft: 
     newOrientation = AVCaptureVideoOrientationLandscapeRight; 
     break; 
    case UIDeviceOrientationLandscapeRight: 
     newOrientation = AVCaptureVideoOrientationLandscapeLeft; 
     break; 
    default: 
     newOrientation = AVCaptureVideoOrientationPortrait; 
    } 
    [stillConnection setVideoOrientation: newOrientation]; 
+4

Posiblemente. Esta pregunta tiene tres años. Ni siquiera puedo recordar la aplicación que estaba escribiendo cuando lo pregunté :) – Fogmeister

+0

Sigue produciendo una imagen de paisaje si la estoy capturando en la orientación horizontal del dispositivo. Quiero la imagen en modo retrato siempre. por favor sugiérame. –

+0

Muchas gracias. Funcionó junto con Image + fixOrientation. –

1

Esto utiliza el método de orientación del controlador de vista. Esto funciona para mí, espero que funcione para usted.

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; 

    AVCaptureConnection *videoConnection = self.prevLayer.connection; 
    [videoConnection setVideoOrientation:(AVCaptureVideoOrientation)toInterfaceOrientation]; 
} 
1

En Swift usted debe hacer esto:

videoOutput = AVCaptureVideoDataOutput() 
    videoOutput!.setSampleBufferDelegate(self, queue: dispatch_queue_create("sample buffer delegate", DISPATCH_QUEUE_SERIAL)) 

    if captureSession!.canAddOutput(self.videoOutput) { 
     captureSession!.addOutput(self.videoOutput) 
    } 

    videoOutput!.connectionWithMediaType(AVMediaTypeVideo).videoOrientation = AVCaptureVideoOrientation.PortraitUpsideDown 

Funciona perfectamente para mí!

1

Estoy escribiendo este código en Swift en caso de que pueda ser necesario para alguien.

Paso-1: Generar notificaciones de orientación (en su viewDidLoad)

UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications() 
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("deviceOrientationDidChange:"), name: UIDeviceOrientationDidChangeNotification, object: nil) 

Paso 2: Tome el cuadro. Aquí intercambiaremos la orientación de videoConnection. En AVFoundation hay un cambio menor en la orientación, especialmente para la orientación horizontal. Entonces solo lo intercambiaremos. Por ejemplo vamos a cambiar de LandscapeRight a LandscapeLeft y viceversa

func takePicture() { 
if let videoConnection = stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo) { 

    var newOrientation: AVCaptureVideoOrientation? 
    switch (UIDevice.currentDevice().orientation) { 
    case .Portrait: 
     newOrientation = .Portrait 
     break 
    case .PortraitUpsideDown: 
     newOrientation = .PortraitUpsideDown 
     break 
    case .LandscapeLeft: 
     newOrientation = .LandscapeRight 
     break 
    case .LandscapeRight: 
     newOrientation = .LandscapeLeft 
     break 
    default : 
     newOrientation = .Portrait 
     break 

    } 
    videoConnection.videoOrientation = newOrientation! 


    stillImageOutput!.captureStillImageAsynchronouslyFromConnection(videoConnection) { 
    (imageDataSampleBuffer, error) -> Void in 

    let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer) 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) { 

     dispatch_async(dispatch_get_main_queue()) { 

     let image = UIImage(data: imageData!)! 
     let portraitImage = image.fixOrientation() 


     } 
    } 


    } 
} 

    } 

NOTA: Tenga en cuenta el nuevo valor de orientación para las orientaciones del paisaje. Es todo lo contrario. (Este es el culpable :: UHHHH)

Paso 3: Fijar la orientación (UIImage extensión)

extension UIImage { 

func fixOrientation() -> UIImage { 

    if imageOrientation == UIImageOrientation.Up { 
     return self 
    } 

    var transform: CGAffineTransform = CGAffineTransformIdentity 

    switch imageOrientation { 
    case UIImageOrientation.Down, UIImageOrientation.DownMirrored: 
     transform = CGAffineTransformTranslate(transform, size.width, size.height) 
     transform = CGAffineTransformRotate(transform, CGFloat(M_PI)) 
     break 
    case UIImageOrientation.Left, UIImageOrientation.LeftMirrored: 
     transform = CGAffineTransformTranslate(transform, size.width, 0) 
     transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2)) 
     break 
    case UIImageOrientation.Right, UIImageOrientation.RightMirrored: 
     transform = CGAffineTransformTranslate(transform, 0, size.height) 
     transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2)) 
     break 
    case UIImageOrientation.Up, UIImageOrientation.UpMirrored: 
     break 
    } 

    switch imageOrientation { 
    case UIImageOrientation.UpMirrored, UIImageOrientation.DownMirrored: 
     CGAffineTransformTranslate(transform, size.width, 0) 
     CGAffineTransformScale(transform, -1, 1) 
     break 
    case UIImageOrientation.LeftMirrored, UIImageOrientation.RightMirrored: 
     CGAffineTransformTranslate(transform, size.height, 0) 
     CGAffineTransformScale(transform, -1, 1) 
    case UIImageOrientation.Up, UIImageOrientation.Down, UIImageOrientation.Left, UIImageOrientation.Right: 
     break 
    } 

    let ctx: CGContextRef = CGBitmapContextCreate(nil, Int(size.width), Int(size.height), CGImageGetBitsPerComponent(CGImage), 0, CGImageGetColorSpace(CGImage), CGImageAlphaInfo.PremultipliedLast.rawValue)! 

    CGContextConcatCTM(ctx, transform) 

    switch imageOrientation { 
    case UIImageOrientation.Left, UIImageOrientation.LeftMirrored, UIImageOrientation.Right, UIImageOrientation.RightMirrored: 
     CGContextDrawImage(ctx, CGRectMake(0, 0, size.height, size.width), CGImage) 
     break 
    default: 
     CGContextDrawImage(ctx, CGRectMake(0, 0, size.width, size.height), CGImage) 
     break 
    } 

    let cgImage: CGImageRef = CGBitmapContextCreateImage(ctx)! 

    return UIImage(CGImage: cgImage) 
} 


    } 
Cuestiones relacionadas