【问题标题】:Switch front/back camera with AVCaptureSession使用 AVCaptureSession 切换前置/后置摄像头
【发布时间】:2015-10-31 00:31:25
【问题描述】:

我正在关注 SO 上的唯一答案 -

Switch cameras with avcapturesession

但是 cameraWithPosition 似乎不起作用。已弃用?

//Get new input
    AVCaptureDevice *newCamera = nil;
    if(((AVCaptureDeviceInput*)currentCameraInput).device.position == AVCaptureDevicePositionBack)
    {
        newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
    }
    else
    {
        newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
    }

【问题讨论】:

  • cameraWithPosition 是一种自定义方法,请查看我的答案。 :)

标签: ios objective-c avfoundation avcapturesession


【解决方案1】:

你需要做的是重新配置你的AVCaptureSession

这是我正在使用的:

// note that `AVCaptureSession * session`
//
if(session)
{
    [session beginConfiguration];

    AVCaptureInput *currentCameraInput = [session.inputs objectAtIndex:0];

    [session removeInput:currentCameraInput];

    AVCaptureDevice *newCamera = nil;

    if(((AVCaptureDeviceInput*)currentCameraInput).device.position == AVCaptureDevicePositionBack)
    {
        newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
    }
    else
    {
        newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
    }

    NSError *err = nil;

    AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:newCamera error:&err];

    if(!newVideoInput || err)
    {
        NSLog(@"Error creating capture device input: %@", err.localizedDescription);
    }
    else
    {
        [session addInput:newVideoInput];
    }

    [session commitConfiguration];
}

// make sure you have this method in your class
//
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position
{
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];

    for (AVCaptureDevice *device in devices)
    {
        if ([device position] == position)
            return device;
    }
    return nil;
}

【讨论】:

  • 这正是我所拥有的......我们可能从同一个链接中获取了它。它一直给我这个“没有可见的@interface ---选择器'cameraWithPosition:'”。
  • @durazno,可能,嗨.. 看看- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position 检查(*)或者你可能错过了什么.. 你能告诉我们你是如何实现cameraWithPosition: 的吗?跨度>
  • 啊,我们实际上必须实现 cameraWithPosition 方法...我以为它只是与 AVFoundation 一起提供的...好吧,现在明白了。谢谢!
  • 我在使用相同方法时遇到问题。当我在相机之间切换时,会自动调用委托方法 didFinishRecordingToOutputFile。
  • @ManishAhuja,这可能是相同的方法,但问题不同。使用您那里的一些基本代码发布您的问题。 :)
【解决方案2】:

在 Swift 3.0 中

/// Swap camera and reconfigures camera session with new input
fileprivate func swapCamera() {

    // Get current input
    guard let input = cameraSession.inputs[0] as? AVCaptureDeviceInput else { return }

    // Begin new session configuration and defer commit
    cameraSession.beginConfiguration()
    defer { cameraSession.commitConfiguration() }

    // Create new capture device
    var newDevice: AVCaptureDevice?
    if input.device.position == .back {
        newDevice = captureDevice(with: .front)
    } else {
        newDevice = captureDevice(with: .back)
    }

    // Create new capture input
    var deviceInput: AVCaptureDeviceInput!
    do {
        deviceInput = try AVCaptureDeviceInput(device: newDevice)
    } catch let error {
        print(error.localizedDescription)
        return
    }

    // Swap capture device inputs
    cameraSession.removeInput(input)
    cameraSession.addInput(deviceInput)
}

/// Create new capture device with requested position
fileprivate func captureDevice(with position: AVCaptureDevicePosition) -> AVCaptureDevice? {

    let devices = AVCaptureDeviceDiscoverySession(deviceTypes: [ .builtInWideAngleCamera, .builtInMicrophone, .builtInDualCamera, .builtInTelephotoCamera ], mediaType: AVMediaTypeVideo, position: .unspecified).devices

    if let devices = devices {
        for device in devices {
            if device.position == position {
                return device
            }
        }
    }

    return nil
}

【讨论】:

    【解决方案3】:

    Swift 4.2 的代码更新

    /// Swap camera and reconfigures camera session with new input
    fileprivate func swapCamera() {
    
        // Get current input
        guard let input = captureSession.inputs[0] as? AVCaptureDeviceInput else { return }
    
        // Begin new session configuration and defer commit
        captureSession.beginConfiguration()
        defer { captureSession.commitConfiguration() }
    
        // Create new capture device
        var newDevice: AVCaptureDevice?
        if input.device.position == .back {
            newDevice = captureDevice(with: .front)
        } else {
            newDevice = captureDevice(with: .back)
        }
    
        // Create new capture input
        var deviceInput: AVCaptureDeviceInput!
        do {
            deviceInput = try AVCaptureDeviceInput(device: newDevice!)
        } catch let error {
            print(error.localizedDescription)
            return
        }
    
        // Swap capture device inputs
        captureSession.removeInput(input)
        captureSession.addInput(deviceInput)
    }
    
    /// Create new capture device with requested position
    fileprivate func captureDevice(with position: AVCaptureDevice.Position) -> AVCaptureDevice? {
    
        let devices = AVCaptureDevice.DiscoverySession(deviceTypes: [ .builtInWideAngleCamera, .builtInMicrophone, .builtInDualCamera, .builtInTelephotoCamera ], mediaType: AVMediaType.video, position: .unspecified).devices
    
        //if let devices = devices {
            for device in devices {
                if device.position == position {
                    return device
                }
            }
        //}
    
        return nil
    }
    

    【讨论】:

      【解决方案4】:

      Swift 5 的代码更新

      extension CameraManager {
          func switchCamera() {
              captureSession.beginConfiguration()
              defer {captureSession.commitConfiguration()}
      
              let nextPosition = ((currentCameraInput as? AVCaptureDeviceInput)?.device.position == .front) ? AVCaptureDevice.Position.back : .front
      
              if let currentCameraInput = currentCameraInput {
                  captureSession.removeInput(currentCameraInput)
              }
      
              if let newCamera = cameraDevice(position: nextPosition),
                  let newVideoInput: AVCaptureDeviceInput = try? AVCaptureDeviceInput(device: newCamera),
                  captureSession.canAddInput(newVideoInput) {
      
                  captureSession.addInput(newVideoInput)
                  currentCameraInput = newVideoInput
      
                  videoDataOutput.connection(with: .video)?.videoOrientation = .portrait
                  videoDataOutput.connection(with: .video)?.automaticallyAdjustsVideoMirroring = false
                  videoDataOutput.connection(with: .video)?.isVideoMirrored = nextPosition == .front
              }
          }
      
          private func cameraDevice(position: AVCaptureDevice.Position) -> AVCaptureDevice? {
              let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)
              for device in discoverySession.devices where device.position == position {
                  return device
              }
      
              return nil
          }
      }
      

      使用 AVCaptureSession 的相机的完整代码是this gist.

      【讨论】:

        【解决方案5】:

        下面是一个在视频会话中使用开关的示例:

        .h
        
        UIViewController<AVCaptureFileOutputRecordingDelegate>
        
        @property(nonatomic,strong)  AVCaptureSession *CaptureSession;
        @property(nonatomic,strong) AVCaptureMovieFileOutput *MovieFileOutput;
        @property(nonatomic,strong) AVCaptureDeviceInput *VideoInputDevice;
        
        - (void) CameraSetOutputProperties;
        - (AVCaptureDevice *) CameraWithPosition:(AVCaptureDevicePosition) Position;
        

        然后:

        .m
        
        - (void)viewDidLoad {
        
           [super viewDidLoad];
        
           CaptureSession = [[AVCaptureSession alloc] init];
        
           //etc
        
        
        }
        
        - (IBAction)CameraToggle:(id)sender
        {
            if ([[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count] > 1)        //Only do if device has multiple cameras
            {
                NSError *error;
                //AVCaptureDeviceInput *videoInput = [self videoInput];
                AVCaptureDeviceInput *NewVideoInput;
                AVCaptureDevicePosition position = [[VideoInputDevice device] position];
                if (position == AVCaptureDevicePositionBack)
                {
                    NewVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self CameraWithPosition:AVCaptureDevicePositionFront] error:&error];
                }
                else if (position == AVCaptureDevicePositionFront)
                {
                    NewVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self CameraWithPosition:AVCaptureDevicePositionBack] error:&error];
                }
        
                if (NewVideoInput != nil)
                {
                    [CaptureSession beginConfiguration];
                    [CaptureSession removeInput:VideoInputDevice];
                    if ([CaptureSession canAddInput:NewVideoInput])
                    {
                        [CaptureSession addInput:NewVideoInput];
                        VideoInputDevice = NewVideoInput;
                    }
                    else
                    {
                        [CaptureSession addInput:VideoInputDevice];
                    }
        
                    //Set the connection properties again
                    [self CameraSetOutputProperties];
        
        
                    [CaptureSession commitConfiguration];
                }
            }
        }
        

        【讨论】:

        • cameraWithPosition方法从何而来???是来自我不知道的某个图书馆吗?
        • - (AVCaptureDevice *) CameraWithPosition:(AVCaptureDevicePosition) 位置;这是在标题中声明的。这是一种根据当前捕获位置返回设备的方法。没什么太花哨的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-23
        • 2011-09-29
        • 2013-06-08
        • 2012-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多