AVFoundation PhotoApp - 在图像保存在库中之前无法使闪存正常工作

Posted

技术标签:

【中文标题】AVFoundation PhotoApp - 在图像保存在库中之前无法使闪存正常工作【英文标题】:AVFoundation PhotoApp - Can't get the flash working before the image saves in the library 【发布时间】:2017-03-03 08:14:35 【问题描述】:

在我发布用于控制我的 cameraApp 主视图的 viewController 的整个代码之前,我会告诉你会发生什么,什么有效,什么无效。用于拍摄照片并保存照片的按钮,用于更改相机(前/后),将闪光灯设置为自动/关闭。这段代码中还有其他一些东西现在已经设置但未使用,但我不认为它们导致了这个问题,我认为我的无知是主要问题。我想通过你们的帮助实现的是,当我按下相机按钮时,如果闪光灯设置为自动,应用程序会在需要时使用闪光灯,然后保存图片。我希望有人可以帮助我,苹果文档告诉你所有的命令,但没有简单的方法把它们放在哪里。在此先感谢,这是我的代码:

import UIKit
import AVFoundation
import PageMenu


class randomController: UIViewController, UIImagePickerControllerDelegate,UINavigationControllerDelegate, CAPSPageMenuDelegate, AVCapturePhotoCaptureDelegate  

    @IBOutlet weak var cameraPreview: UIImageView!


    @IBAction func cameraButton(_ sender: Any) 

        let settings = AVCapturePhotoSettings()
        let previewPixelType = settings.availablePreviewPhotoPixelFormatTypes.first!
        let previewFormat = [
            kCVPixelBufferPixelFormatTypeKey as String: previewPixelType,
            kCVPixelBufferWidthKey as String: 160,
            kCVPixelBufferHeightKey as String: 160
                ]
        let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
        if (device?.hasTorch)! 
            do 
                print("diosotterrato")
                try device?.lockForConfiguration()
                //device?.torchMode = AVCaptureTorchMode.on
                // device?.torchMode = AVCaptureTorchMode.Off
                device?.torchMode = AVCaptureTorchMode.auto
                device?.unlockForConfiguration()
             catch 
                print(error)
            
        



        settings.previewPhotoFormat = previewFormat
        sessionOutput.capturePhoto(with: settings, delegate: self)

    


    @IBOutlet weak var backgroundMarrone: UIImageView!

    func askPermission() 
        print("here")
        let cameraPermissionStatus =  AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)

        switch cameraPermissionStatus 
        case .authorized:
            print("Already Authorized")
        case .denied:
            print("denied")

            let alert = UIAlertController(title: "Sorry :(" , message: "But  could you please grant permission for camera within device settings",  preferredStyle: .alert)
            let action = UIAlertAction(title: "Ok", style: .cancel,  handler: nil)
            alert.addAction(action)
            present(alert, animated: true, completion: nil)

        case .restricted:
            print("restricted")
        default:
            AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: 
                [weak self]
                (granted :Bool) -> Void in

                if granted == true 
                    // User granted
                    print("User granted")
                    DispatchQueue.main.async()
                        //Do smth that you need in main thread
                    
                
                else 
                    // User Rejected
                    print("User Rejected")

                    DispatchQueue.main.async()
                        let alert = UIAlertController(title: "WHY?" , message:  "Camera it is the main feature of our application", preferredStyle: .alert)
                        let action = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
                        alert.addAction(action)
                        self?.present(alert, animated: true, completion: nil)  
                     
                
            );
        
    
    @IBOutlet weak var cameracapture: UIImageView!
    var pageMenu : CAPSPageMenu?

    var captureSession = AVCaptureSession();
    var sessionOutput = AVCapturePhotoOutput();
    var sessionOutputSetting = AVCapturePhotoSettings(format: [AVVideoCodecKey:AVVideoCodecJPEG]);
    var previewLayer = AVCaptureVideoPreviewLayer();


    var flashButton = UIButton()

        override func viewDidLoad() 
        super.viewDidLoad()
                pageMenu?.delegate = self

        var controllerArray : [UIViewController] = []

        backgroundMarrone.frame = CGRect(x: 0, y:(view.frame.maxY/10*5), width: self.view.frame.width, height: self.view.frame.height )

        cameraPreview.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: backgroundMarrone.frame.minY  )


            let switchCameraButton = UIButton(frame: CGRect(x: 5, y: cameraPreview.frame.maxY/12*9.8, width: 50, height: 50))
            switchCameraButton.backgroundColor = UIColor(red: 100.0/255.0, green: 39.0/255.0, blue: 87.0/255.0, alpha: 0.0)
            switchCameraButton.addTarget(self, action: #selector(pressButton(button:)), for: .touchUpInside)
            switchCameraButton.setImage(#imageLiteral(resourceName: "btn_reverse_camera copy.png"), for: UIControlState.normal)
            self.view.addSubview(switchCameraButton)

            flashButton = UIButton(frame: CGRect(x: cameraPreview.frame.maxX - 55, y: cameraPreview.frame.maxY/12*9.8, width: 50, height: 50))
            flashButton.backgroundColor = UIColor(red: 100.0/255.0, green: 39.0/255.0, blue: 87.0/255.0, alpha: 0.0)
            flashButton.addTarget(self, action: #selector(pressButton1(button:)), for: .touchUpInside)
            flashButton.setImage(#imageLiteral(resourceName: "btn_flash copy.png"), for: UIControlState.normal)
            self.view.addSubview(flashButton)




        let libraryController : UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "libraryController") as! libraryController
            libraryController.title = "Libreria"
            controllerArray.append(libraryController)


            let photoController : UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "photoController") as! photoController
            photoController.title = "Foto"
            controllerArray.append(photoController)



        let videoController : UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "videoController") as! videoController
        videoController.title = "Video"
        controllerArray.append(videoController)

        let parameters: [CAPSPageMenuOption] = [
            .menuItemSeparatorWidth(0),
            .useMenuLikeSegmentedControl(true),
            .menuItemSeparatorPercentageHeight(0.1),
            .centerMenuItems (true)
        ]

        pageMenu = CAPSPageMenu(viewControllers: controllerArray, frame: CGRect(x: 0, y: cameraPreview.frame.maxY , width: self.view.frame.width, height: view.frame.height ), pageMenuOptions: parameters)

        self.view.addSubview(pageMenu!.view)

        
var ciaone = false



    override func viewWillAppear(_ animated: Bool) 


        let deviceDiscoverySession = AVCaptureDeviceDiscoverySession(deviceTypes: [AVCaptureDeviceType.builtInDualCamera, AVCaptureDeviceType.builtInTelephotoCamera,AVCaptureDeviceType.builtInWideAngleCamera], mediaType: AVMediaTypeVideo, position: AVCaptureDevicePosition.unspecified)




        for device in (deviceDiscoverySession?.devices)! 


            print("tipo di device: \(device.position)")

            if(device.position == AVCaptureDevicePosition.front)
                do

                    let input = try AVCaptureDeviceInput(device: device)
                    if(captureSession.canAddInput(input))
                        captureSession.addInput(input);
                        captureSession.startRunning()
                        print("entrato1")

                        if(captureSession.canAddOutput(sessionOutput))
                            captureSession.addOutput(sessionOutput);
                            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession);
                            previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
                            previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait;
                            cameraPreview.layer.addSublayer(previewLayer);
                        print("entrato2")
                        
                    
                
                catch
                   print("exception!");
                

            

        

        


    func beginSession(captureDevice : AVCaptureDevice?) 

        ciaone = false

        if captureSession.isRunning 
            captureSession.beginConfiguration()

            let currentInput : AVCaptureInput = captureSession.inputs[0] as! AVCaptureInput
            captureSession.removeInput(currentInput)

            do 
                try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice))
             catch 
                print("Error adding video input device")
            

            captureSession.commitConfiguration()

         else 
            // Setup the camera and layer for the first time.
            do 
                try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice))
             catch 
                print("Error adding video input device")
            


            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
            self.view.layer.insertSublayer(previewLayer, at: 0)
            previewLayer.frame = cameraPreview.bounds
            captureSession.startRunning()


        
    



    func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) 

        if let error = error 
            print("error occure : \(error.localizedDescription)")
        

        if  let sampleBuffer = photoSampleBuffer,
            let previewBuffer = previewPhotoSampleBuffer,
            let dataImage =  AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer:  sampleBuffer, previewPhotoSampleBuffer: previewBuffer) 
            print(UIImage(data: dataImage)?.size as Any)

            let dataProvider = CGDataProvider(data: dataImage as CFData)
            let cgImageRef: CGImage! = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)
            let image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right)
            UIImageWriteToSavedPhotosAlbum(image, self, nil, nil)
            self.cameracapture.image = image
         else 
            print("some error here")
        
    

    var a = 0
    func pressButton(button: UIButton) 

        if (a == 0) 
            print("dioschifoso!")
            beginSession(captureDevice: AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo))

            a = 1

         else 

            beginSession(captureDevice: AVCaptureDevice.defaultDevice(withDeviceType: AVCaptureDeviceType.builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: AVCaptureDevicePosition.front))


            a = 0

        
    
    var flash = 0




    func toggleTorch(on: Bool) 
        //guard let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) else  return 
        /*
        if device.hasTorch 
            do 
                try device.lockForConfiguration()

                if on == true 
                    device.torchMode = .on
                 else 
                    device.torchMode = .off
                

                device.unlockForConfiguration()
             catch 
                print("Torch could not be used")
            
         else 
            print("Torch is not available")
        
 */

    

    func pressButton1(button: UIButton) 

        let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
        if (device?.hasTorch)! 
            do 
                try device?.lockForConfiguration()
                //device?.torchMode = AVCaptureTorchMode.on
                // device?.torchMode = AVCaptureTorchMode.Off
                device?.torchMode = AVCaptureTorchMode.off
                device?.unlockForConfiguration()
             catch 
                print(error)
            
        

        if (a == 0) 

            let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
            if (device?.hasTorch)! 
                do 
                    try device?.lockForConfiguration()
                    device?.torchMode = AVCaptureTorchMode.auto
                   // device?.torchMode = AVCaptureTorchMode.Off
                    //device?.torchMode = AVCaptureTorchMode.auto
                    device?.unlockForConfiguration()
                 catch 
                    print(error)
                
            
            //toggleTorch(on: true)
            flashButton.setImage(#imageLiteral(resourceName: "btn_flash_off.png"), for: UIControlState.normal)


            a = 1

         else 


            //toggleTorch(on: false)
            flashButton.setImage(#imageLiteral(resourceName: "btn_flash copy.png"), for: UIControlState.normal)
            a = 0

        


    

    override func viewDidLayoutSubviews() 
        super.viewDidLayoutSubviews()
        previewLayer.frame = cameraPreview.bounds
    



    func capturePicture()


        






    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

【问题讨论】:

【参考方案1】:

Swift 3.0 和 Xcode >= 8

  @IBAction func flashTapped() 
    // check if flashlight available
        let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
        if (device?.hasTorch)! && (device?.hasFlash)! 
            do 
                try device?.lockForConfiguration()
             catch 
                // handle error
                return
            
            if device?.torchMode == .auto 
                device?.torchMode = .on
                device?.flashMode = .on
            
            else if device?.torchMode == .on 
                device?.torchMode = .off
                device?.flashMode = .off
            
            else 
                device?.torchMode = .auto
                device?.flashMode = .auto
            

            device?.unlockForConfiguration()
        

【讨论】:

我会在几分钟内整合这段代码,到时候我会报告的!顺便感谢您的帮助:) 实现了它,但它给了我很多错误,最大的错误发生在 device.lock 配置中,xcode 告诉我“参数传递给不带参数的调用”。除此之外,还有很多可选类型展开。 谢谢,iOS 10 弃用了 .flashmode,改用 AVCapturePhotoSettings.flashMode ,我该如何实现呢? 另外,我试过你的更新代码,它可以工作,但是当我拍摄照片时,如果它设置为自动,例如在黑暗的房间里,它不使用闪光灯。我不明白为什么:( 第一次尝试使用闪光灯模式 = 打开并检查暗室是否正常工作?

以上是关于AVFoundation PhotoApp - 在图像保存在库中之前无法使闪存正常工作的主要内容,如果未能解决你的问题,请参考以下文章

AVFoundation自己定义音视频频播放

在avfoundation中录制视频时可以缩放吗?

Mac OS X 上的 AVFoundation + GC

AVFoundation 初识

将视频合并在一起(AVFoundation)

使用 AVFoundation 在 iOS 上录制音频样本