Swift:使用AVFoundation捕获剧照

时间:2014-12-09 23:56:32

标签: xcode swift avfoundation avcapturesession avcapture

我一直试图在课堂上解决这个问题,但对我来说这绝对是一场噩梦。我的项目是简单的笔记应用程序。它有一个注释表,当您单击按钮添加注释时,它会以模态方式显示一个新的视图控制器,您可以在其中输入注释内容。在此视图中,有一个相机按钮,它启动到下面发布的视图控制器的segue。 此处的目标是允许将静态图像添加到这些“注释”对象(包含文本和图像)。我希望您能够容忍此代码,我确信它非常凌乱,业余。

以下是摄像机视图控制器使用的自定义视图的完整代码:

import UIKit
import AVFoundation

    class DEZCamPreviewView: UIView {

    var session: AVCaptureSession! {
        get {
            return (self.layer as AVCaptureVideoPreviewLayer).session
        }

        set {
            (self.layer as AVCaptureVideoPreviewLayer).session = newValue
        }
    }

    override class func layerClass() -> AnyClass {
        return AVCaptureVideoPreviewLayer.self
    }

}

以下是摄像机视图控制器的完整代码:

import UIKit
import AVFoundation
import AssetsLibrary

class DEZCamViewController: UIViewController {

// Store the note to send back it's image.
var note: Note?

@IBOutlet weak var captureButton: UIButton!
@IBOutlet weak var previewView: DEZCamPreviewView!
// Session management.
var sessionQueue: dispatch_queue_t! // Communicate with the session and other session objects on this queue.
var session: AVCaptureSession!
var videoDeviceInput: AVCaptureDeviceInput!
var stillImageOutput: AVCaptureStillImageOutput!

override func viewDidLoad() {
    super.viewDidLoad()

    self.session = AVCaptureSession()

    // Setup the preview view
    self.previewView.session = session

    self.sessionQueue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL)

    dispatch_async(sessionQueue) {
        //self.backgroundRecordingID = UIBackgroundTaskInvalid

        var error: NSError?

        let videoDevice: AVCaptureDevice = DEZCamViewController.deviceWithMediaType(AVMediaTypeVideo, preferringPosition: .Back)

        let videoDeviceInput: AVCaptureDeviceInput = AVCaptureDeviceInput(device: videoDevice, error: &error)

        if let error = error {
            println(error.localizedDescription)
        }

        if self.session.canAddInput(videoDeviceInput) {
            self.session.addInput(videoDeviceInput)
            self.videoDeviceInput = videoDeviceInput

            dispatch_async(dispatch_get_main_queue()) {
                // Why are we dispatching this to the main queue?
                // Because AVCaptureVideoPreviewLayer is the backing layer for AVCamPreviewView and 
                // UIView can only be manipulated on main thread.
                // Note: As an exception to the above rule, it is not necessary to serialize video 
                // orientation changes on the AVCaptureVideoPreviewLayer’s connection with other 
                // session manipulation.
                let avLayer = (self.previewView.layer as AVCaptureVideoPreviewLayer)
                let connection = avLayer.connection
                let orientation = AVCaptureVideoOrientation(rawValue: self.interfaceOrientation.rawValue)!
                connection.videoOrientation = orientation
            }
        }

        if let error = error {
            println(error.localizedDescription)
        }

        let stillImageOutput = AVCaptureStillImageOutput()
        if self.session.canAddOutput(stillImageOutput) {
            stillImageOutput.outputSettings[AVVideoCodecKey] = AVVideoCodecJPEG
            self.session.addOutput(stillImageOutput)
            self.stillImageOutput = stillImageOutput
        }
    }
}

override func viewWillAppear(animated: Bool) {
    dispatch_async(self.sessionQueue) {
        self.session.startRunning()
        // NEW CODE HERE
        self.captureButton.enabled = true
    }
}

override func viewWillDisappear(animated: Bool) {
    dispatch_async(self.sessionQueue) {
        self.session.stopRunning()
        println("CAM-CONTROLLER: inside viewWillDisappear -- session stop called")
    }
}

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


@IBAction func captureImageNow(sender: UIButton) {
    dispatch_async(self.sessionQueue) {
        println("CAM-CONTROLLER: inside captureImageNow")

       // Capture a still image.
        self.stillImageOutput.captureStillImageAsynchronouslyFromConnection(self.stillImageOutput.connectionWithMediaType(AVMediaTypeVideo))
            { (imageDataSampleBuffer, error) -> Void in

            if let imageDataSampleBuffer = imageDataSampleBuffer {
                println("inside closure")
                let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
                println("got image data:")
                if let image = UIImage(data: imageData) {
                    println("CAM-CONTROLLER: inside captureImageNow -- set the image: \(image)")
                    // Save the image
                    self.note?.noteImage = image

                    self.navigationController?.popViewControllerAnimated(true)

                }
            }
        }
    }

}
    class func deviceWithMediaType(mediaType: NSString, preferringPosition position: AVCaptureDevicePosition) -> AVCaptureDevice {
    let devices = AVCaptureDevice.devicesWithMediaType(mediaType) as [AVCaptureDevice]
    var captureDevice = devices[0]

    for device in devices {
        if device.position == position {
            captureDevice = device
            break
        }
    }

    return captureDevice;
}
    // MARK: - Navigation


override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
    if segue.identifier == "goBackToNoteSegue" {
        let controller = segue.destinationViewController as DEZAddNoteViewController
        if let strongNote = self.note {
            controller.existingNote = strongNote
        }
    }
}


}

我遇到了各种令人沮丧的问题。有一次,当按下捕获按钮时,控制器正在捕获图像,但是在显示相机预览之前,它只显示了之前的视图,而不是继续前一个视图...这发生了9/10次我触摸了一次性捕获按钮,所以我开始剥离控制器,直到我认为我有最少的必要代码。

现在问题是图像从未被捕获,或被捕获但从未成功发送回前一个视图控制器。任何人都可以阐明为什么这不起作用?或者,更好的是,任何人都可以指导我使用AVFoundation(在Swift中)静态图像捕获的 bare essentials 实现吗?

0 个答案:

没有答案