Mi aplicación es sólo horizontal. Yo estoy presentando la AVCaptureVideoPreviewLayer como este:

self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
[self.previewLayer setBackgroundColor:[[UIColor blackColor] CGColor]];
[self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspect];                    
NSLog(@"previewView: %@", self.previewView);
CALayer *rootLayer = [self.previewView layer];
[rootLayer setMasksToBounds:YES];
[self.previewLayer setFrame:[rootLayer bounds]];
    NSLog(@"previewlayer: %f, %f, %f, %f", self.previewLayer.frame.origin.x, self.previewLayer.frame.origin.y, self.previewLayer.frame.size.width, self.previewLayer.frame.size.height);
[rootLayer addSublayer:self.previewLayer];
[session startRunning];

auto.previewView tiene un marco de (0,0,568,320), lo cual es correcto. auto.previewLayer registros de un marco de (0,0,568,320), que teóricamente es correcto. Sin embargo, la pantalla de la cámara aparece como un retrato rectángulo en el centro de la pantalla horizontal, y la orientación de la cámara de vista previa de la imagen está mal por 90 grados. ¿Qué estoy haciendo mal? Necesito la cámara de vista previa de la capa de aparecer en la pantalla completa, en modo horizontal, y la imagen debe estar orientado correctamente.

  • Importante Para el 2016, pase a la respuesta correcta debajo de stackoverflow.com/a/36575423/294884 al igual que con muchos temas de computación, los detalles de API cambio a través de los años. Con autodiseño y así sucesivamente, las mayores respuestas aquí (que fueron excelentes en el tiempo) no son de ahora. (En otros tres o cuatro años habrá una nueva respuesta correcta!)
InformationsquelleAutor soleil | 2013-02-25

19 Comentarios

  1. 64

    La cámara por defecto orientación es horizontal a la Izquierda (botón de inicio uno de la izquierda). Es necesario hacer dos cosas aquí:

    1 – Cambiar el previewLayer marco:

    self.previewLayer.frame=self.view.bounds;

    Que usted necesita para establecer la vista previa de la capa de marco a los límites de la pantalla de forma que la imagen de la vista previa de la capa de cambios cuando la pantalla rota (usted no puede utilizar el marco de la raíz de vista, ya que no cambia con la rotación, pero los límites de la raíz de la vista de hacer). En tu ejemplo, se establece el previewlayer marco de una previewView propiedad que no veo.

    2 – tienes Que girar la vista previa de la capa de conexión con la rotación del dispositivo. Agregue este código en viewDidAppear:

    -(void) viewDidAppear:(BOOL)animated
    {
      [super viewDidAppear:YES];
    
      //Get Preview Layer connection
      AVCaptureConnection *previewLayerConnection=self.previewLayer.connection;
    
      if ([previewLayerConnection isVideoOrientationSupported])
        [previewLayerConnection setVideoOrientation:[[UIApplication sharedApplication] statusBarOrientation]]; 
    }

    Espero que esto lo soluciona.

    Revelación completa: Esta es una versión simplificada ya que no importa si el Paisaje a la derecha o Paisaje a la izquierda.

    • Gracias, esto funciona. En realidad yo había conseguido que funcione con el auto.previewLayer.orientación = UIInterfaceOrientationLandscapeLeft, pero yo no estaba cómodo con eso, ya es obsoleto. ¿Cómo podría yo añadir soporte para ambos el Paisaje de la Izquierda y la Derecha?
    • Sin embargo, el código de necesidades sobre iOS 6.0 debido a que el auto.previewLayer.conexión; Para uso captureVideoPreviewLayer.orientación = UIInterfaceOrientationLandscapeLeft;
    • statusBarOrientation ya no se utiliza en iOS 9, por lo que no es aconsejable su uso. También, se devuelve un UIDeviceOrientation que es un tipo diferente de AVCaptureVideoOrientation, por lo que puede ser indefinido lo que va a suceder si, por ejemplo, están en una indefinida de la orientación del dispositivo o lugar de su dispositivo de forma plana sobre la mesa.
    • Como por algas sugieren, el uso de este en la actualidad podemos comprobar la orientación actual a través de UIApplication.shared.statusBarOrientation, a continuación, establezca el vídeo de orientación a través de AVCaptureVideoOrientation. Asigna uno-a-uno.
  2. 64

    MEJOR RESPUESTA PARA SWIFT 3.0 Y XCODE 8.0

    private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
    
        layer.videoOrientation = orientation
    
        previewLayer.frame = self.view.bounds
    
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        if let connection =  self.previewLayer?.connection  {
    
            let currentDevice: UIDevice = UIDevice.current
    
            let orientation: UIDeviceOrientation = currentDevice.orientation
    
            let previewLayerConnection : AVCaptureConnection = connection
    
            if previewLayerConnection.isVideoOrientationSupported {
    
                switch (orientation) {
                case .portrait: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
    
                    break
    
                case .landscapeRight: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeLeft)
    
                    break
    
                case .landscapeLeft: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeRight)
    
                    break
    
                case .portraitUpsideDown: updatePreviewLayer(layer: previewLayerConnection, orientation: .portraitUpsideDown)
    
                    break
    
                default: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
    
                    break
                }
            }
        }
    }

    MEJOR RESPUESTA PARA SWIFT 2.2 Y XCODE 7.3

    private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
    
        layer.videoOrientation = orientation
    
        previewLayer.frame = self.view.bounds
    
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        if let connection =  self.previewLayer?.connection  {
    
            let currentDevice: UIDevice = UIDevice.currentDevice()
    
            let orientation: UIDeviceOrientation = currentDevice.orientation
    
            let previewLayerConnection : AVCaptureConnection = connection
    
            if (previewLayerConnection.supportsVideoOrientation) {
    
                switch (orientation) {
                case .Portrait: updatePreviewLayer(previewLayerConnection, orientation: .Portrait)
    
                    break
    
                case .LandscapeRight: updatePreviewLayer(previewLayerConnection, orientation: .LandscapeLeft)
    
                    break
    
                case .LandscapeLeft: updatePreviewLayer(previewLayerConnection, orientation: .LandscapeRight)
    
                    break
    
                case .PortraitUpsideDown: updatePreviewLayer(previewLayerConnection, orientation: .PortraitUpsideDown)
    
                    break
    
                default: updatePreviewLayer(previewLayerConnection, orientation: .Portrait)
    
                    break
                }
            }
        }
    }
    • Esto es increíblemente hermosa.
    • Buen código aquí … drivecurrent.com/devops/…
    • Muchas gracias 🙂
    • Esta respuesta se produce un error si usted girar rápidamente de un modo horizontal para el otro. El método de diseño no se llama en ese escenario. También he probado con viewWillLayout y obtener el mismo resultado.
    • En el interruptor, 2 casos (LandscapeRight y LandscapeLeft) están invertidos pero funciona muy bien.
    • me ayudó mucho, gracias!
    • Esto funcionó a la perfección para mí. Impresionante.
    • Usted loco!! Gracias!
    • Esta solución funcionó a la perfección para mí hasta iOS 11/Swift 4. Este fijo que es para mí, stackoverflow.com/a/34480478/945247
    • Usted no tiene que escribir el descanso dentro de swift interruptor, en la forma de C.
    • traté de usar el código, pero sigo teniendo problemas. Tengo una pregunta aquí si tienes tiempo para echar un vistazo: stackoverflow.com/questions/46913953/…
    • Todos estos break declaraciones son innecesarios. Swift switch casos no sean por defecto, como se hace en Objective-C.

  3. 27
    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
        if let connection = self.previewLayer?.connection {
            var currentDevice: UIDevice = UIDevice.currentDevice()
            var orientation: UIDeviceOrientation = currentDevice.orientation
            var previewLayerConnection : AVCaptureConnection = connection
    
            if (previewLayerConnection.supportsVideoOrientation) {
                switch (orientation) {
                case .portrait:
                    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.portrait
                case .landscapeRight:
                    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.landscapeRight
                case .landscapeLeft:
                    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.landscapeLeft
                case .portraitUpsideDown:
                    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.portraitUpsideDown
    
                default:
                    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.portrait
                }
            }
        }
    }
    • cuando yo uso este código con el dispositivo en modo horizontal, el marco de la vista previa de la capa no está en la posición correcta en su lugar aparece en la esquina inferior izquierda, puede usted por favor sugerir cómo puedo solucionar este problema ? gracias
    • usted puede superar este cuando se establece el marco de la previewLayer de nuevo: previewLayer?.frame = CGRectMake(0, 0, el tamaño.de ancho, el tamaño.altura)
    • Cuidado – UIDevice.currentDevice().orientation devuelve la orientación del dispositivo, independientemente de la interfaz de usuario admite. Es mejor comparar contra UIApplication.shared.statusBarOrientation para asegurarse de que su videoPreviewLayer tiene la misma orientación que su interfaz de usuario.
    • Todos estos break declaraciones son innecesarios. Swift switch casos no sean por defecto, como se hace en Objective-C. También, previewLayerConnection.videoOrientation es conocido por ser AVCaptureVideoOrientation, así que usted puede simplificar declaraciones a previewLayerConnection.videoOrientation = .portrait.
  4. 16

    Que no podemos usar

    [previewLayerConnection setVideoOrientation:[[UIApplication sharedApplication] statusBarOrientation]]; 

    porque UIInterfaceOrientation != AVCaptureVideoOrientation

    Pero podemos simplemente los valores de la prueba… y este trabajo,con el siguiente código.

    -(void)viewDidLayoutSubviews {
        [super viewDidLayoutSubviews];
    
        UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
        switch (orientation) {
            case UIInterfaceOrientationPortrait:
                [_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
                break;
            case UIInterfaceOrientationPortraitUpsideDown:
                [_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown];
                break;
            case UIInterfaceOrientationLandscapeLeft:
                [_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft];
                break;
            case UIInterfaceOrientationLandscapeRight:
                [_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
                break;
        }
    }
    • Añadir un default: break;
    • Esta es elegante y funciona a la perfección.
  5. 11

    La API parece haber cambiado un poco. videoOrientation es ahora una propiedad en la vista previa de la capa de connection de la propiedad. Además, no hay necesidad de usar un interruptor. Respuesta para Swift 3.0:

    override func viewDidLayoutSubviews() {
        self.configureVideoOrientation()
    }
    
    private func configureVideoOrientation() {
        if let previewLayer = self.previewLayer,
            let connection = previewLayer.connection {
            let orientation = UIDevice.current.orientation
    
            if connection.isVideoOrientationSupported,
                let videoOrientation = AVCaptureVideoOrientation(rawValue: orientation.rawValue) {
                previewLayer.frame = self.view.bounds
                connection.videoOrientation = videoOrientation
            }
        }
    }
    • Esta debe ser la respuesta. Gracias!
    • Realmente agradable. Un poco de revisión; la última línea debe ser connection.videoOrientation = videoOrientation (quitar previewLayer.)
    • Debe ser la respuesta, funciona. previewLayer.la conexión es nullable debe estar en la línea de las: previewLayer.conexión?.videoOrientation = videoOrientation
  6. 7

    Para cualquier persona que está luchando en un completo funcional previa de la cámara. Aquí está el código de producción. Por supuesto, el inconveniente es el lag cuando los cambios de orientación. Si alguien tiene una mejor solución para superar esto, por favor compartir

    - (void)viewDidLoad
    {
    [super viewDidLoad];
    [self initCamera];
    }
    - (void)initCamera
    {
    AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] error:nil];
    if (captureInput) {
    mSession = [[AVCaptureSession alloc] init];
    [mSession addInput:captureInput];
    }
    }
    - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
    {
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    if ([mSession isRunning]) {
    [mSession stopRunning];
    [mCameraLayer removeFromSuperlayer];
    [self initCamera];
    [self startCamera];
    }
    }
    - (void)startCamera
    {
    [mSession startRunning];
    Settings::getInstance()->setClearColor(Color(0, 0, 0, 0));
    mCameraLayer = [AVCaptureVideoPreviewLayer layerWithSession: mSession];
    [self updateCameraLayer];
    [mCameraView.layer addSublayer:mCameraLayer];
    }
    - (void)stopCamera
    {
    [mSession stopRunning];
    [mCameraLayer removeFromSuperlayer];
    Settings::getInstance()->setDefClearColor();
    }
    - (void)toggleCamera
    {
    mSession.isRunning ? [self stopCamera] : [self startCamera];
    [mGLKView setNeedsDisplay];
    }
    - (void)updateCameraLayer
    {
    mCameraLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    mCameraLayer.frame = mCameraView.bounds;
    float x = mCameraView.frame.origin.x;
    float y = mCameraView.frame.origin.y;
    float w = mCameraView.frame.size.width;
    float h = mCameraView.frame.size.height;
    CATransform3D transform = CATransform3DIdentity;
    if (UIDeviceOrientationLandscapeLeft == [[UIDevice currentDevice] orientation]) {
    mCameraLayer.frame = CGRectMake(x, y, h, w);
    transform = CATransform3DTranslate(transform, (w - h) / 2, (h - w) / 2, 0);
    transform = CATransform3DRotate(transform, -M_PI/2, 0, 0, 1);
    } else if (UIDeviceOrientationLandscapeRight == [[UIDevice currentDevice] orientation]) {
    mCameraLayer.frame = CGRectMake(x, y, h, w);
    transform = CATransform3DTranslate(transform, (w - h) / 2, (h - w) / 2, 0);
    transform = CATransform3DRotate(transform, M_PI/2, 0, 0, 1);
    } else if (UIDeviceOrientationPortraitUpsideDown == [[UIDevice currentDevice] orientation]) {
    mCameraLayer.frame = mCameraView.bounds;
    transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
    } else {
    mCameraLayer.frame = mCameraView.bounds;
    }
    mCameraLayer.transform  = transform;
    }
    enter code here
    • solución para resolver que es para anular el viewDidLayoutSubviews método en el controlador de vista y actualización de los límites en consecuencia
    • Bien llamando updateCameraLayer trabajó para mí. +1 de mí 😉
    • Yo llame updateCameraLayer en viewDidAppear. Algunos cambios de menor importancia fueron necesarios: float x = mCameraView.bounds.origin.x y la primera mCameraLayer.frame = mCameraView.bounds; puede ser omitido.
    • Cómo arreglar el lag? Estoy recibiendo un 2 segundos de retraso sobre la vista previa de la capa cuando me cambio de orientación.
  7. 4

    Ya que hay una desatención y la conversión de advertencia de uso de la solución anterior, y el establecimiento de videoOrientation no parece estar trabajando en iOS7, puedo poner controles para la orientación en mi getter para la AVCaptureVideoPreviewLayer así:

    - (AVCaptureVideoPreviewLayer *) previewLayer
    {
    if(!_previewLayer)
    {
    _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession: self.captureSession];
    [_previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    _previewLayer.frame = self.view.bounds; //Assume you want the preview layer to fill the view.
    [_previewLayer setPosition:CGPointMake(0,0)];
    if (UIDeviceOrientationLandscapeLeft == [[UIDevice currentDevice] orientation]) {
    _previewLayer.transform = CATransform3DMakeRotation(-M_PI/2, 0, 0, 1);
    }
    else if (UIDeviceOrientationLandscapeRight == [[UIDevice currentDevice] orientation])
    {
    _previewLayer.transform = CATransform3DMakeRotation(M_PI/2, 0, 0, 1);
    }
    }
    return _previewLayer;
    }
  8. 3

    Trabaja con Swift 4, Xcode 9:

      override func viewWillTransition(to size: CGSize,
    with coordinator: UIViewControllerTransitionCoordinator)
    {
    super.viewWillTransition(to: size, with: coordinator)
    guard
    let conn = self.previewLayer?.connection,
    conn.isVideoOrientationSupported
    else { return }
    let deviceOrientation = UIDevice.current.orientation
    switch deviceOrientation {
    case .portrait: conn.videoOrientation = .portrait
    case .landscapeRight: conn.videoOrientation = .landscapeLeft
    case .landscapeLeft: conn.videoOrientation = .landscapeRight
    case .portraitUpsideDown: conn.videoOrientation = .portraitUpsideDown
    default: conn.videoOrientation = .portrait
    }
    }

    Una sutileza a notar aquí es que UIDeviceOrientation.landscapeRight va con AVCaptureVideoOrientation.landscapeLeft.

    El otro paisaje caso es del mismo modo que no coinciden. Esto es deliberado, y ofrece una desafortunada coincidencia entre UIKit y AVFoundation. Si usted coincide con la de los casos por la coincidencia de los nombres, no va a funcionar, y el vídeo será al revés en el paisaje configuraciones.

    • Lo correcto acerca de la falta de coincidencia entre UIKit y AVFoundation orientaciones. Que fue de disparo de mí. En mi caso, también he tenido que cambiar el previewLayer del marco para que coincida con el nuevo tamaño mediante: previewLayer.posición = CGPointMake(tamaño.ancho/2.0, tamaño.altura/2.0) previewLayer.frame = CGRectMake(0, 0, el tamaño.de ancho, el tamaño.altura)
  9. 3

    Correcta asignación de UIDeviceOrientation a AVCaptureVideoOrientation es necesario.

    Si tu aplicación es compatible device rotation, resizing preview.frame también es necesario, y este func debe ser llamado desde viewDidLayoutSubviews() y viewWillTransition().

    private func configureVideoOrientation() {
    if let preview = self.previewLayer,
    let connection = preview.connection {
    let orientation = UIDevice.current.orientation
    if connection.isVideoOrientationSupported {
    var videoOrientation: AVCaptureVideoOrientation
    switch orientation {
    case .portrait:
    videoOrientation = .portrait
    case .portraitUpsideDown:
    videoOrientation = .portraitUpsideDown
    case .landscapeLeft:
    videoOrientation = .landscapeRight
    case .landscapeRight:
    videoOrientation = .landscapeLeft
    default:
    videoOrientation = .portrait
    }
    preview.frame = self.view.bounds
    connection.videoOrientation = videoOrientation
    }
    }
    }
  10. 2

    Hola Chicos gracias por todas las respuestas y comentarios acerca de esto, me encontré con este como estoy trabajando en una rápida aplicación. Usted puede lograr que la cámara a girar con su dispositivo utilizando este código:

    override func shouldAutorotate() -> Bool {
    if your cameraController.previewLayer.connection != nil {
    var currentDevice: UIDevice = UIDevice.currentDevice()
    var orientation: UIDeviceOrientation = currentDevice.orientation
    var previewLayerConnection : AVCaptureConnection = your cameraController.previewLayer.connection
    if (previewLayerConnection.supportsVideoOrientation)
    {
    switch (orientation)
    {
    case .Portrait:
    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
    break
    case .LandscapeRight:
    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.LandscapeLeft
    break
    case .LandscapeLeft:
    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.LandscapeRight
    break
    default:
    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
    break
    }
    }
    }
    return true
    }

    Espero que esto ayude!

    • cómo venir a la derecha y a la izquierda están invertidos? Todavía estoy havingtrouble guardar la imagen de la vista previa de la capa con la orientación correcta. Q aquí si tienes cualquier momento: stackoverflow.com/questions/46913953/…
    • Quitar los break declaraciones. Esta es rápido, sin fallthrough en switch declaraciones como Objective-C no.
  11. 1

    Primero tenemos que crear la AVCaptureVideoPreviewLayer y :

    1. establecer su videoGravity
      (como en mi caso estoy usando una pequeña vista para tener salida de vídeo).
    2. establecer el marco.

      [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
      [_videoPreviewLayer setFrame:_viewPreview.layer.bounds];
    3. establecer la orientación inicialmente

      if (_videoPreviewLayer.connection.supportsVideoOrientation) {
      _videoPreviewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation:[UIApplication sharedApplication].statusBarOrientation];
      }
    4. establecer la orientación de cada caso mediante un simple interruptor caso

      -(AVCaptureVideoOrientation)interfaceOrientationToVideoOrientation:

      (UIInterfaceOrientation)orientation {
      switch (orientation) {
      case UIInterfaceOrientationPortrait:
      return AVCaptureVideoOrientationPortrait;
      case UIInterfaceOrientationPortraitUpsideDown:
      return AVCaptureVideoOrientationPortraitUpsideDown;
      case UIInterfaceOrientationLandscapeLeft:
      return AVCaptureVideoOrientationLandscapeLeft ;
      case UIInterfaceOrientationLandscapeRight:
      return AVCaptureVideoOrientationLandscapeRight;
      default:
      break;
      }
      NSLog(@"Warning - Didn't recognise interface orientation (%d)",orientation);
      return AVCaptureVideoOrientationPortrait;
      

      }

    5. Ya que el dispositivo es compatible tanto landscapeLeft y landscapeRight uso de la delegación exhortó a la rotación:
      - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
      if (_videoPreviewLayer.connection.supportsVideoOrientation) {
      _videoPreviewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation:toInterfaceOrientation];
      }
      }
  12. 1

    Yo también estaba de frente a la misma
    Esto fue a arreglar mi la orientación de la Cámara

    override func shouldAutorotate() -> Bool {
    return false
    }
    override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return UIInterfaceOrientation.LandscapeLeft
    }
    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.LandscapeLeft
    }

    Para fijar la cámara

    let previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.avCaptureSession)    
    previewLayer.frame = self.view.layer.frame
    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
  13. 1

    Maselko la respuesta casi trabajó para mí, excepto que si la barra de estado, orientación volteretas, a continuación, la salida de la cámara muestra al revés. He abordado este problema mediante la re-llamar Maselko la lógica cuando la barra de estado volteretas.

    Aquí está mi modificado Maselko solución (probado en ios12/swift4):

    override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    setCameraOrientation()
    }
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    setCameraOrientation()
    }
    @objc func setCameraOrientation() {
    if let connection =  self.previewLayer?.connection  {
    let currentDevice: UIDevice = UIDevice.current
    let orientation: UIDeviceOrientation = currentDevice.orientation
    let previewLayerConnection : AVCaptureConnection = connection
    if previewLayerConnection.isVideoOrientationSupported {
    let o: AVCaptureVideoOrientation
    switch (orientation) {
    case .portrait: o = .portrait
    case .landscapeRight: o = .landscapeLeft
    case .landscapeLeft: o = .landscapeRight
    case .portraitUpsideDown: o = .portraitUpsideDown
    default: o = .portrait
    }
    previewLayerConnection.videoOrientation = o
    previewLayer!.frame = self.view.bounds
    }
    }
    }
  14. 1

    De la respuesta seleccionada de trabajo para Swift 4.2 – Xcode 10.0 – iOS 12.0:

    var videoPreviewLayer: AVCaptureVideoPreviewLayer?
    override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if let previewLayerConnection =  self.videoPreviewLayer?.connection, previewLayerConnection.isVideoOrientationSupported {
    updatePreviewLayer(layer: previewLayerConnection, orientation: UIApplication.shared.statusBarOrientation.videoOrientation)
    }
    }
    private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
    layer.videoOrientation = orientation
    videoPreviewLayer?.frame = self.view.bounds
    }

    No olvides que la asignación de UIInterfaceOrientation a AVCaptureVideoOrientation

    extension UIInterfaceOrientation {
    public var videoOrientation: AVCaptureVideoOrientation {
    switch self {
    case .portrait:
    return AVCaptureVideoOrientation.portrait
    case .landscapeRight:
    return AVCaptureVideoOrientation.landscapeRight
    case .landscapeLeft:
    return AVCaptureVideoOrientation.landscapeLeft
    case .portraitUpsideDown:
    return AVCaptureVideoOrientation.portraitUpsideDown
    default:
    return AVCaptureVideoOrientation.portrait
    }
    }
    }
  15. 1

    Swift Versión 5

      override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    updatePreview()
    }
    func updatePreview() {
    let orientation: AVCaptureVideoOrientation
    switch UIDevice.current.orientation {
    case .portrait:
    orientation = .portrait
    case .landscapeRight:
    orientation = .landscapeLeft
    case .landscapeLeft:
    orientation = .landscapeRight
    case .portraitUpsideDown:
    orientation = .portraitUpsideDown
    default:
    orientation = .portrait
    }
    if previewLayer?.connection?.isVideoOrientationSupported == true {
    previewLayer?.connection?.videoOrientation = orientation
    }
    previewLayer.frame = view.bounds
    }
  16. 0

    La única forma en que trabajó para mí en iOS 8 a 11.1 sin ningún problema para hacer esto y debo mencionar que en mi caso, he cargado mi aplicación sólo en el modo de paisaje, pero se debe trabajar en todas las orientaciones.(Por cierto, se puede superponer la cámara manualmente a través de un imageview o cualquier cosa que deseas de esta manera muy fácil)

    @interface ViewController (){
    AVCaptureVideoPreviewLayer * previewLayer;
    AVCaptureSession* session;
    }
    @property (weak, nonatomic) IBOutlet UIView *cameraPreviewView;
    -(void)viewDidLoad{
    AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] error:nil];
    if (captureInput) {
    session = [[AVCaptureSession alloc] init];
    [session addInput:captureInput];
    }
    previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    [previewLayer setBackgroundColor:[[UIColor blackColor] CGColor]];
    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspect];
    CALayer *rootLayer = [self.cameraPreviewView layer];
    [rootLayer setMasksToBounds:YES];
    [previewLayer setFrame:[self.view bounds]];
    [rootLayer addSublayer:previewLayer];
    [session startRunning];
    //Orientation Code is in viewDidLayoutSubviews method
    }
    -(void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    switch (orientation) {
    case UIInterfaceOrientationPortrait:
    [previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
    break;
    case UIInterfaceOrientationPortraitUpsideDown:
    [previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown];
    break;
    case UIInterfaceOrientationLandscapeLeft:
    [previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft];
    break;
    case UIInterfaceOrientationLandscapeRight:
    [previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
    break;
    default:break;
    }
    }
  17. 0

    @Maselko ‘s respuesta es correcta, pero por una cosa: Usted debe utilizar UIApplication.shared.statusBarOrientation en lugar de UIDevice.current.orientation, debido a la orientación del dispositivo es la forma en que su dispositivo es físicamente posicionado. Se rompe cuando el dispositivo está en el paisaje, pero su interfaz de usuario no soporta que la orientación (como cuando yo estaba haciendo un paisaje-sólo la aplicación de la cámara y el inicio de la vista cuando el dispositivo está en posición vertical).

    private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
    layer.videoOrientation = orientation
    previewLayer.frame = self.view.bounds
    }
    override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if let connection =  self.previewLayer?.connection  {
    let currentDevice: UIDevice = UIDevice.current
    let orientation = UIApplication.shared.statusBarOrientation
    let previewLayerConnection : AVCaptureConnection = connection
    if previewLayerConnection.isVideoOrientationSupported {
    switch (orientation) {
    case .portrait: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
    break
    case .landscapeRight: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeLeft)
    break
    case .landscapeLeft: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeRight)
    break
    case .portraitUpsideDown: updatePreviewLayer(layer: previewLayerConnection, orientation: .portraitUpsideDown)
    break
    default: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
    break
    }
    }
    }
    }
  18. 0

    Aquí está la solución que estoy usando con Swift 4.

    Es corta y funciona de maravilla para mí.

    open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    let videoLayer = self.previewLayer
    coordinator.animate(alongsideTransition: { (context: UIViewControllerTransitionCoordinatorContext) in
    guard let connection = videoLayer?.connection, connection.isVideoOrientationSupported, let orientation = AVCaptureVideoOrientation(rawValue: UIApplication.shared.statusBarOrientation.rawValue) else {
    return
    }
    connection.videoOrientation = orientation
    videoLayer?.frame = self.view.bounds
    }) { (context: UIViewControllerTransitionCoordinatorContext) in
    //handle any completion logic here...
    }
    }
  19. 0

    Versión mejorada de Maselko la respuesta de

    Funciona simplemente genial!

    override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if let connection =  previewView.connection  {
    if connection.isVideoOrientationSupported {
    let videoOrientation = AVCaptureVideoOrientation.init(rawValue: UIApplication.shared.statusBarOrientation.rawValue)!
    connection.videoOrientation = videoOrientation
    previewView.frame = self.view.bounds
    }
    }
    }

Dejar respuesta

Please enter your comment!
Please enter your name here