我一直试图在课堂上解决这个问题,但对我来说这绝对是一场噩梦。我的项目是简单的笔记应用程序。它有一个注释表,当您单击按钮添加注释时,它会以模态方式显示一个新的视图控制器,您可以在其中输入注释内容。在此视图中,有一个相机按钮,它启动到下面发布的视图控制器的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 实现吗?