无法使用 AVFoundation 将 JPEG 图像写入 HDD

Can't write JPEG image to HDD using AVFoundation

我正在使用 AVFoundation 模块访问 macOS 10.13.3 上的 FaceTime 摄像头。

captureSession.startRunning()方法是运行,相机的指示灯是绿色的。但是我无法在我的硬盘上捕获和写入 JPEG 图像。我的代码有什么问题?

我需要输出 jpg 图像 167x188 像素(宽 x 高)。

我在 Xcode 9,Swift 4 工作。

import Cocoa
import AVFoundation
import CoreImage

class ViewController: NSViewController, AVCaptureVideoDataOutputSampleBufferDelegate {

    @IBOutlet weak var camera: NSView!
    @IBOutlet weak var captureButton: NSButton!
    @IBOutlet weak var saveButton: NSButton!

    let captureSession = AVCaptureSession()
    var captureDevice: AVCaptureDevice?
    var previewLayer: AVCaptureVideoPreviewLayer?
    var imageOutput: AVCaptureStillImageOutput?

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.layer?.backgroundColor = NSColor.black.cgColor

        camera.layer = CALayer()
        captureSession.sessionPreset = AVCaptureSession.Preset.low
        let devices = AVCaptureDevice.devices()

        for device in devices {
            print(device)

            if ((device as AnyObject).hasMediaType(AVMediaType.video)) {
                print(device)
                captureDevice = device 
            }
        }

        if captureDevice != nil {
            do {
                try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice!))
                previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
                previewLayer?.frame = (self.camera.layer?.frame)!
                self.camera.layer?.addSublayer(previewLayer!)

                captureSession.startRunning()

            } catch {
                print(AVCaptureSessionErrorKey.description)
            }
        }
    }

    var assetWriter: AVAssetWriter!
    var imageWriterInput: AVAssetWriterInput!
    let outputSettings = [String: Any]()
    let url = URL(fileURLWithPath: "/Users/catalyst/Desktop/image.jpg")

    @IBAction func captureImage(_ sender: NSButton) {
        print("Taking photo...")

        imageOutput = AVCaptureStillImageOutput()
        imageOutput?.outputSettings = [
            AVVideoCodecKey: AVVideoCodecType.jpeg,
            AVVideoWidthKey: NSNumber(value: Float(167)),
            AVVideoHeightKey: NSNumber(value: Float(188))
        ] as [String : Any]

        if captureSession.canAddOutput(imageOutput!) {
            captureSession.addOutput(imageOutput!)
        }
    }

    @IBAction func saveImage(_ sender: NSButton) {
        print("Saving photo...")

        let writerFileName = url

        assetWriter = try? AVAssetWriter(outputURL: writerFileName, fileType: AVFileType.jpg)
        imageWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: outputSettings)

        assetWriter.add(imageWriterInput)
    }
}

没有编译器错误,我的桌面上没有捕获的图像。

编辑完全改变了这个问题的性质,所以这里是

新答案

这帮我拍了张照片。确保沙盒不会阻止您写入您指定的路径。 AVCaptureStillImageOutput 似乎无法为您调整大小,因此您可以使用 .

调整大小
let captureSession = AVCaptureSession()
let stillImageOutput = AVCaptureStillImageOutput()
var previewLayer: AVCaptureVideoPreviewLayer! = nil

override func viewDidLoad() {
    super.viewDidLoad()

    let captureDevice = AVCaptureDevice.default(for: .video)
    if captureDevice != nil {
        do {
            try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice!))

            // AVCaptureVideoPreviewLayer code
            // assumes you have camera NSView
            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
            previewLayer!.frame = (self.camera.layer?.frame)!
            self.camera.layer?.addSublayer(previewLayer!)

            captureSession.addOutput(stillImageOutput)
            captureSession.startRunning()

        } catch {
            print(AVCaptureSessionErrorKey.description)
        }
    }
}

@IBAction func captureImage(_ sender: NSButton) {
    print("Taking photo...")
    if let videoConnection = stillImageOutput.connection(with: .video) {
        stillImageOutput.captureStillImageAsynchronously(from: videoConnection) { jpegBuffer, error in
            // TODO: check error here

            if let data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(jpegBuffer!) {
                // make sure sandboxing isn't blocking this path                
                let url = URL(fileURLWithPath: "/Users/swift/Desktop/picture.jpg")

                // resize here using something like
                // 

                try! data.write(to: url)
            }
        }
    }
}

旧答案

您的 url 引用了一个目录。尝试引用一个文件:

let url = URL(fileURLWithPath: "/Users/swift/Desktop/movie.mov")

您还需要实施 AVCaptureVideoDataOutputSampleBufferDelegate 协议。

AVCaptureVideoDataOutput 不是文件,它是一种在 real-ish 时间内使用视频和音频缓冲区进行回调的方法,您应该将样本附加到 videoWriterInput.

AVCaptureVideoDataOutputAVAssetWriter 级别很低。如果你只是想记录到一个文件,你可以用更简单的 AVCaptureMovieFileOutput.

替换它们