【问题标题】:Can't write JPEG image to HDD using AVFoundation无法使用 AVFoundation 将 JPEG 图像写入 HDD
【发布时间】:2018-08-16 15:31:49
【问题描述】:

我正在使用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)
    }
}

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

【问题讨论】:

  • 不硬编码文件路径将是一个好的开始。
  • 你应该使用URL(fileURLWithPath: "/Users/swift/Desktop/")
  • @andy,正试图解决您的问题,今天才意识到我的 Mac 网络摄像头已经停止工作,我没有在devices() 电话中返回它

标签: macos cocoa avfoundation swift4 core-image


【解决方案1】:

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

新答案

这为我捕获了图像。确保沙盒不会阻止您写入您指定的路径。 AVCaptureStillImageOutput 似乎没有为您调整大小,因此您可以使用 like this 调整大小。

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
                // https://stackoverflow.com/a/32991610/22147

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

老答案

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

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

您还需要实现AVCaptureVideoDataOutputSampleBufferDelegate 协议。

AVCaptureVideoDataOutput 不是文件,它是一种实时获取带有视频和音频缓冲区的回调的方法,您应该将样本附加到 videoWriterInput

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

【讨论】:

  • 你知道如何停止录制,而不是使用 captureSession.stopRunning() 停止捕获会话吗?
  • 只是不要在AVCaptureVideoDataOutput 回调中写信给您的AVAssetWriter。 p.s.这是一个新问题
  • ...我的硬盘上仍然没有输出文件。
  • 您的代码缺少一些部分,请参阅我的更新答案。
  • 你应该使用AVCaptureMovieFileOutput
猜你喜欢
  • 2018-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-19
  • 2014-03-07
  • 2012-06-30
  • 2012-02-28
相关资源
最近更新 更多