Swift 3:如何在自定义 AVFoundation 相机上启用闪光灯?

问题描述 投票:0回答:3

我有一个非常基本的 AVFoundation 相机,它有一个

captureButton
,可以拍照并将照片发送到
secondCameraController
以便显示。我的问题是,iOS 10 中有很多弃用内容,我不知道当我按下
captureButton
时如何快速添加。任何帮助将不胜感激。我的代码如下。谢谢你们。

class CameraController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {

let captureSession = AVCaptureSession()
var previewLayer: CALayer!

var captureDevice: AVCaptureDevice!

var takePhoto: Bool = false

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .white
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    prepareCamera()
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    navigationController?.setNavigationBarHidden(true, animated: true)
}

let cameraView: UIView = {
    let view = UIView()
    view.backgroundColor = .red
    return view
}()

func prepareCamera() {
    captureSession.sessionPreset = AVCaptureSessionPresetPhoto

    if let availableDevices = AVCaptureDeviceDiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaTypeVideo, position: .back).devices {

        captureDevice = availableDevices.first
        beginSession()
    }
}

func beginSession() {
    do {
        let captureDeviceInput = try AVCaptureDeviceInput(device: captureDevice)

        captureSession.addInput(captureDeviceInput)

    } catch {

        print(error.localizedDescription)
    }

    if let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) {
        self.previewLayer = previewLayer
        self.view.layer.addSublayer(self.previewLayer)
        self.previewLayer.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
        previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill

        self.view.addSubview(captureButton)

        let width: CGFloat = 85
        captureButton.frame = CGRect(x: (previewLayer.frame.width / 2) - width / 2, y: (previewLayer.frame.height) - width - 25, width: width, height: 85)

        captureSession.startRunning()

        let dataOutput = AVCaptureVideoDataOutput()
        dataOutput.videoSettings = [(kCVPixelBufferPixelFormatTypeKey as NSString): NSNumber(value: kCVPixelFormatType_32BGRA)]

        dataOutput.alwaysDiscardsLateVideoFrames = true

        if captureSession.canAddOutput(dataOutput) {
            captureSession.addOutput(dataOutput)
        }

        captureSession.commitConfiguration()

        let queue = DispatchQueue(label: "com.cheekylabsltd.camera")
        dataOutput.setSampleBufferDelegate(self, queue: queue)
    }
}

func handleCapture() {
    takePhoto = true
}

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {

    if takePhoto {
        takePhoto = false

        if let image = self.getImageFromSampleBuffer(buffer: sampleBuffer) {
            let secondController = SecondCameraController()
            secondController.takenPhoto = image

            DispatchQueue.main.async {
                self.present(secondController, animated: true, completion: { 
                    self.stopCaptureSession()
                })
            }
        }
    }
}

func getImageFromSampleBuffer(buffer: CMSampleBuffer) -> UIImage? {

    if let pixelBuffer = CMSampleBufferGetImageBuffer(buffer) {
        let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
        let context = CIContext()

        let imageRect = CGRect(x: 0, y: 0, width: CVPixelBufferGetWidth(pixelBuffer), height: CVPixelBufferGetHeight(pixelBuffer))

        if let image = context.createCGImage(ciImage, from: imageRect) {
            return UIImage(cgImage: image, scale: UIScreen.main.scale, orientation: .right)
        }
    }

    return nil
}

func stopCaptureSession() {
    self.captureSession.stopRunning()

    if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
        for input in inputs {
            self.captureSession.removeInput(input)
        }
    }
}

lazy var captureButton: UIButton = {
    let button = UIButton(type: .system)
    button.backgroundColor = .white
    button.layer.cornerRadius = 42.5
    button.clipsToBounds = true
    button.alpha = 0.40
    button.layer.borderWidth = 4
    button.layer.borderColor = greenColor.cgColor
    button.addTarget(self, action: #selector(handleCapture), for: .touchUpInside)
    return button
}()
}
swift swift3 avfoundation
3个回答
16
投票

试试这个代码: 斯威夫特 v3.0

private func flashOn(device:AVCaptureDevice)
    {
        do{
            if (device.hasTorch)
            {
                try device.lockForConfiguration()
                device.torchMode = .on
                device.flashMode = .on
                device.unlockForConfiguration()
            }
        }catch{
            //DISABEL FLASH BUTTON HERE IF ERROR 
            print("Device tourch Flash Error ");
        }
    }

//用于闪光关闭代码

 private func flashOff(device:AVCaptureDevice)
    {
        do{
            if (device.hasTorch){
                try device.lockForConfiguration()
                device.torchMode = .off
                device.flashMode = .off
                device.unlockForConfiguration()
            }
        }catch{
            //DISABEL FLASH BUTTON HERE IF ERROR
            print("Device tourch Flash Error ");
        }
    }

// 方法

//私有让session = AVCaptureSession()

//MARK: FLASH UITLITY METHODS
    func toggleFlash() {
        var device : AVCaptureDevice!

        if #available(iOS 10.0, *) {
            let videoDeviceDiscoverySession = AVCaptureDeviceDiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInDuoCamera], mediaType: AVMediaTypeVideo, position: .unspecified)!
            let devices = videoDeviceDiscoverySession.devices!
            device = devices.first!

        } else {
            // Fallback on earlier versions
            device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
        }

        if ((device as AnyObject).hasMediaType(AVMediaTypeVideo))
        {
            if (device.hasTorch)
            {
                self.session.beginConfiguration()
                //self.objOverlayView.disableCenterCameraBtn();
                if device.isTorchActive == false {
                    self.flashOn(device: device)
                } else {
                    self.flashOff(device: device);
                }
                //self.objOverlayView.enableCenterCameraBtn();
                self.session.commitConfiguration()
            }
        }
    }

2
投票

斯威夫特4

因此 AVFoundation 中有两种不同的行为可供选择。其中之一是捕获设备火炬开关。将 torchSwitch 操作连接到某个视图,并确保将 CameraManager.shared.backDevice 更改为提供当前输入的前置或后置设备的实例。

  @IBAction func torchSwitch(_ sender: Any) {
    guard let device = CameraManager.shared.backDevice else { return }
    guard device.isTorchAvailable else { return }
    do {
      try device.lockForConfiguration()
      device.torchMode = device.torchMode ? .off : .on
      if device.torchMode == .on {
        try device.setTorchModeOn(level: 0.7)
      }
    } catch {
      debugPrint(error)
    }
  }

AVFoundation 已弃用 device.flashMode

现在要设置闪光灯,请在相机或 vc 上声明一个变量。这里的值将是默认值。

  var flash: AVCaptureFlashMode = .off

将此操作连接到某个视图

  @IBAction func torchSwitch(_ sender: Any) { flash = flash ? .off : .on }

然后,当您想要捕获图像时,请使用AVCapturePhotoOutput并准备照片设置。 stillCameraOutputAVCapturePhotoOutput 的实例。

  let settings = AVCapturePhotoSettings()
  settings.flashMode = flash
  stillCameraOutput.capturePhoto(with: settings, delegate: self)

0
投票

斯威夫特 4: 以下代码对我来说效果很好

private enum FlashPhotoMode {
    case on
    case off
}

@IBOutlet weak var flashPhotoModeButton: UIButton!

@IBAction func toggleFlashPhotoMode(_ flashPhotoModeButton: UIButton ) {
    sessionQueue.async {
        self.flashPhotoMode = (self.flashPhotoMode == .on) ? .off : .on
        let flashPhotoMode = self.flashPhotoMode
        
        DispatchQueue.main.async {
            if flashPhotoMode == .on {
               
                self.flashPhotoModeButton.setBackgroundImage(UIImage(named: "flashON"), for: .normal)
                print("flashON")
            } else {
                self.flashPhotoModeButton.setBackgroundImage(UIImage(named: "flashOFF"), for: .normal)
                print("flashOFF")
            }
        }
    }
}

@IBAction private func capturePhoto(_ photoButton: UIButton) {
    if self.videoDeviceInput.device.isFlashAvailable {
        if self.flashPhotoMode == .on {
            photoSettings.flashMode = .on
            print("FLASH ON ")
        } else {
            print("FLASH OFF ")
            photoSettings.flashMode = .off
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.