Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/106.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何将实时摄影机预览添加到UIView_Ios_Iphone_Swift_Avfoundation - Fatal编程技术网

Ios 如何将实时摄影机预览添加到UIView

Ios 如何将实时摄影机预览添加到UIView,ios,iphone,swift,avfoundation,Ios,Iphone,Swift,Avfoundation,我遇到了一个问题,我正试图在UIView边界内解决,有没有办法将相机预览添加到UIView?并在UIView顶部添加其他内容(按钮、标签等) 我尝试使用AVFoundation框架,但没有足够的文档用于Swift。更新为Swift 5 您可以尝试以下方法: import UIKit import AVFoundation class ViewController: UIViewController{ var previewView : UIView! var boxView:U

我遇到了一个问题,我正试图在UIView边界内解决,有没有办法将相机预览添加到UIView?并在UIView顶部添加其他内容(按钮、标签等)


我尝试使用AVFoundation框架,但没有足够的文档用于Swift。

更新为Swift 5

您可以尝试以下方法:

import UIKit
import AVFoundation

class ViewController: UIViewController{
    var previewView : UIView!
    var boxView:UIView!
    let myButton: UIButton = UIButton()

    //Camera Capture requiered properties
    var videoDataOutput: AVCaptureVideoDataOutput!
    var videoDataOutputQueue: DispatchQueue!
    var previewLayer:AVCaptureVideoPreviewLayer!
    var captureDevice : AVCaptureDevice!
    let session = AVCaptureSession()

    override func viewDidLoad() {
        super.viewDidLoad()
        previewView = UIView(frame: CGRect(x: 0,
                                           y: 0,
                                           width: UIScreen.main.bounds.size.width,
                                           height: UIScreen.main.bounds.size.height))
        previewView.contentMode = UIView.ContentMode.scaleAspectFit
        view.addSubview(previewView)

        //Add a view on top of the cameras' view
        boxView = UIView(frame: self.view.frame)

        myButton.frame = CGRect(x: 0, y: 0, width: 200, height: 40)
        myButton.backgroundColor = UIColor.red
        myButton.layer.masksToBounds = true
        myButton.setTitle("press me", for: .normal)
        myButton.setTitleColor(UIColor.white, for: .normal)
        myButton.layer.cornerRadius = 20.0
        myButton.layer.position = CGPoint(x: self.view.frame.width/2, y:200)
        myButton.addTarget(self, action: #selector(self.onClickMyButton(sender:)), for: .touchUpInside)

        view.addSubview(boxView)
        view.addSubview(myButton)

        self.setupAVCapture()
    }

    override var shouldAutorotate: Bool {
        if (UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft ||
        UIDevice.current.orientation == UIDeviceOrientation.landscapeRight ||
        UIDevice.current.orientation == UIDeviceOrientation.unknown) {
            return false
        }
        else {
            return true
        }
    }

    @objc func onClickMyButton(sender: UIButton){
        print("button pressed")
    }
}


// AVCaptureVideoDataOutputSampleBufferDelegate protocol and related methods
extension ViewController:  AVCaptureVideoDataOutputSampleBufferDelegate{
     func setupAVCapture(){
        session.sessionPreset = AVCaptureSession.Preset.vga640x480
        guard let device = AVCaptureDevice
        .default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, 
                 for: .video,
                 position: AVCaptureDevice.Position.back) else {
                            return
        }
        captureDevice = device
        beginSession()
    }

    func beginSession(){
        var deviceInput: AVCaptureDeviceInput!

        do {
            deviceInput = try AVCaptureDeviceInput(device: captureDevice)
            guard deviceInput != nil else {
                print("error: cant get deviceInput")
                return
            }

            if self.session.canAddInput(deviceInput){
                self.session.addInput(deviceInput)
            }

            videoDataOutput = AVCaptureVideoDataOutput()
            videoDataOutput.alwaysDiscardsLateVideoFrames=true
            videoDataOutputQueue = DispatchQueue(label: "VideoDataOutputQueue")
            videoDataOutput.setSampleBufferDelegate(self, queue:self.videoDataOutputQueue)

            if session.canAddOutput(self.videoDataOutput){
                session.addOutput(self.videoDataOutput)
            }

            videoDataOutput.connection(with: .video)?.isEnabled = true

            previewLayer = AVCaptureVideoPreviewLayer(session: self.session)
            previewLayer.videoGravity = AVLayerVideoGravity.resizeAspect

            let rootLayer :CALayer = self.previewView.layer
            rootLayer.masksToBounds=true
            previewLayer.frame = rootLayer.bounds
            rootLayer.addSublayer(self.previewLayer)
            session.startRunning()
        } catch let error as NSError {
            deviceInput = nil
            print("error: \(error.localizedDescription)")
        }
    }

    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        // do stuff here
    }

    // clean up AVCapture
    func stopCamera(){
        session.stopRunning()
    }

}
在这里,我使用名为previewView的
UIView
启动相机,然后在previewView上方添加名为boxView的新
UIView
。我向boxView添加了一个
ui按钮

重要

请记住,在iOS 10及更高版本中,您需要首先向用户请求权限,才能访问摄像头。您可以通过添加用法来实现这一点 在应用程序的
Info.plist
中键入目的字符串 因为如果你没有声明使用情况,你的应用程序在使用时会崩溃 首先是进入

这里有一个屏幕截图显示摄像头访问请求 Swift 3:

@IBOutlet weak var cameraContainerView:UIView!

var imagePickers:UIImagePickerController?
在ViewDidLoad上:

override func viewDidLoad() {

        super.viewDidLoad()
        addImagePickerToContainerView()

    }
func addImagePickerToContainerView(){

        imagePickers = UIImagePickerController()
        if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerControllerCameraDevice.front) {
            imagePickers?.delegate = self
            imagePickers?.sourceType = UIImagePickerControllerSourceType.camera

            //add as a childviewcontroller
            addChildViewController(imagePickers!)

            // Add the child's View as a subview
            self.cameraContainerView.addSubview((imagePickers?.view)!)
            imagePickers?.view.frame = cameraContainerView.bounds
            imagePickers?.allowsEditing = false
            imagePickers?.showsCameraControls = false
            imagePickers?.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        }
    }
@IBAction func cameraButtonPressed(_ sender: Any) {

         if UIImagePickerController.isSourceTypeAvailable(.camera){
            imagePickers?.takePicture()

         } else{

          //Camera not available.
        }  
    }
将相机预览添加到容器视图:

override func viewDidLoad() {

        super.viewDidLoad()
        addImagePickerToContainerView()

    }
func addImagePickerToContainerView(){

        imagePickers = UIImagePickerController()
        if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerControllerCameraDevice.front) {
            imagePickers?.delegate = self
            imagePickers?.sourceType = UIImagePickerControllerSourceType.camera

            //add as a childviewcontroller
            addChildViewController(imagePickers!)

            // Add the child's View as a subview
            self.cameraContainerView.addSubview((imagePickers?.view)!)
            imagePickers?.view.frame = cameraContainerView.bounds
            imagePickers?.allowsEditing = false
            imagePickers?.showsCameraControls = false
            imagePickers?.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        }
    }
@IBAction func cameraButtonPressed(_ sender: Any) {

         if UIImagePickerController.isSourceTypeAvailable(.camera){
            imagePickers?.takePicture()

         } else{

          //Camera not available.
        }  
    }
自定义按钮操作:

override func viewDidLoad() {

        super.viewDidLoad()
        addImagePickerToContainerView()

    }
func addImagePickerToContainerView(){

        imagePickers = UIImagePickerController()
        if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerControllerCameraDevice.front) {
            imagePickers?.delegate = self
            imagePickers?.sourceType = UIImagePickerControllerSourceType.camera

            //add as a childviewcontroller
            addChildViewController(imagePickers!)

            // Add the child's View as a subview
            self.cameraContainerView.addSubview((imagePickers?.view)!)
            imagePickers?.view.frame = cameraContainerView.bounds
            imagePickers?.allowsEditing = false
            imagePickers?.showsCameraControls = false
            imagePickers?.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        }
    }
@IBAction func cameraButtonPressed(_ sender: Any) {

         if UIImagePickerController.isSourceTypeAvailable(.camera){
            imagePickers?.takePicture()

         } else{

          //Camera not available.
        }  
    }

Swift 4

mauricioconde溶液的浓缩版本

您可以将其用作插入式组件:

//
//  CameraView.swift

import Foundation
import AVFoundation
import UIKit

final class CameraView: UIView {

    private lazy var videoDataOutput: AVCaptureVideoDataOutput = {
        let v = AVCaptureVideoDataOutput()
        v.alwaysDiscardsLateVideoFrames = true
        v.setSampleBufferDelegate(self, queue: videoDataOutputQueue)
        v.connection(with: .video)?.isEnabled = true
        return v
    }()

    private let videoDataOutputQueue: DispatchQueue = DispatchQueue(label: "JKVideoDataOutputQueue")
    private lazy var previewLayer: AVCaptureVideoPreviewLayer = {
        let l = AVCaptureVideoPreviewLayer(session: session)
        l.videoGravity = .resizeAspect
        return l
    }()

    private let captureDevice: AVCaptureDevice? = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
    private lazy var session: AVCaptureSession = {
        let s = AVCaptureSession()
        s.sessionPreset = .vga640x480
        return s
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)

        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        commonInit()
    }

    private func commonInit() {
        contentMode = .scaleAspectFit
        beginSession()
    }

    private func beginSession() {
        do {
            guard let captureDevice = captureDevice else {
                fatalError("Camera doesn't work on the simulator! You have to test this on an actual device!")
            }
            let deviceInput = try AVCaptureDeviceInput(device: captureDevice)
            if session.canAddInput(deviceInput) {
                session.addInput(deviceInput)
            }

            if session.canAddOutput(videoDataOutput) {
                session.addOutput(videoDataOutput)
            }
            layer.masksToBounds = true
            layer.addSublayer(previewLayer)
            previewLayer.frame = bounds
            session.startRunning()
        } catch let error {
            debugPrint("\(self.self): \(#function) line: \(#line).  \(error.localizedDescription)")
        }
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        previewLayer.frame = bounds
    }
}

extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate {}
斯威夫特5 捷径


iOS 13/14和Swift 5.3:

private var imageVC: UIImagePickerController?
然后在要显示相机视图时调用
showCameraVC()

func showCameraVC() {    
    self.imageVC = UIImagePickerController()

    if UIImagePickerController.isCameraDeviceAvailable(.front) {
        self.imageVC?.sourceType = .camera
        self.imageVC?.cameraDevice = .front
        self.imageVC?.showsCameraControls = false
                
        let screenSize = UIScreen.main.bounds.size
        let cameraAspectRatio = CGFloat(4.0 / 3.0)
        let cameraImageHeight = screenSize.width * cameraAspectRatio
        let scale = screenSize.height / cameraImageHeight
        self.imageVC?.cameraViewTransform = CGAffineTransform(translationX: 0, y: (screenSize.height - cameraImageHeight)/2)
        self.imageVC?.cameraViewTransform = self.imageVC!.cameraViewTransform.scaledBy(x: scale, y: scale)
    
        self.imageVC?.view.frame = CGRect(x: 0, y: 0, width: screenSize.width, height: screenSize.height)
        self.view.addSubview(self.imageVC!.view)
        self.view.sendSubviewToBack(self.imageVC!.view)
    }
}

摄像头视图也将全屏显示(其他答案无法修正字母框视图)

我已投票支持您的答案。它正在做我想做的事情,但我需要取消过视图。如何从CMSampleBuffer录制电影?如何在同一代码中归档全屏cemara视图?然后如何从该图像选择器获取捕获图像路径?.takePicture()在单独的视图中显示有方法更改预览fps吗?与slo mo预览一样,slo mo预览比常规视频预览快得多。单击我添加在该视图顶部的按钮,我可以捕获图像。您应该能够使用CoreGraphics处理此问题。请看:下面的内容太棒了。在电话里看起来不错。但是,如何控制捕获的图像?注意,我已将上述内容添加为子视图,而不是通过IB