问题
I'm trying screen capture on a Mac with AVCaptureScreenInput, but AVCaptureVideoDataOutput delegate captureOutput is never called, and I'm not sure why. I do get a notification saying the capture session was started.
import Cocoa
import AVFoundation
class ViewController: NSViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
var captureSession: AVCaptureSession!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear() {
super.viewWillAppear()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.errorNotif), name: AVCaptureSessionRuntimeErrorNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.startedNotif), name: AVCaptureSessionDidStartRunningNotification, object: nil)
startScreenCapture()
}
override func viewWillDisappear() {
super.viewWillDisappear()
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func captureOutput(captureOutput: AVCaptureOutput!, didDropSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {
print("ignore frame, add code to handle later")
}
func startScreenCapture() {
let displayId = CGMainDisplayID()
captureSession = AVCaptureSession()
if captureSession.canSetSessionPreset(AVCaptureSessionPresetHigh) {
captureSession.sessionPreset = AVCaptureSessionPresetHigh
}
let captureScreenInput = AVCaptureScreenInput(displayID: displayId)
if captureSession.canAddInput(captureScreenInput) {
captureSession.addInput(captureScreenInput)
} else {
print("Could not add main display to capture input")
}
let output = AVCaptureVideoDataOutput()
let queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL)
output.setSampleBufferDelegate(self, queue: queue)
output.alwaysDiscardsLateVideoFrames = true
output.videoSettings = [kCVPixelBufferPixelFormatTypeKey as NSString: NSNumber(unsignedInt: kCVPixelFormatType_32BGRA)]
captureSession.addOutput(output)
captureSession.startRunning()
}
func errorNotif() {
print("error starting capture")
}
func startedNotif() {
print("started screen capture")
}
}
回答1:
You need to define the didOutputSampleBuffer delegate callback to actually receive the captured frames:
func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {
print("captured \(sampleBuffer)")
}
p.s. I'm not sure about macOS, but viewWillAppear may not be a good place to do initialisation because on iOS at least it can be called multiple times.
回答2:
I added for basic example AVCaptureVideoDataOutputSampleBufferDelegate
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
let videoQueue = DispatchQueue(label: "VIDEO_QUEUE")
override func viewDidLoad() {
super.viewDidLoad()
let captureSession = AVCaptureSession()
guard let captureDevice = AVCaptureDevice.default(for: .video) else { return }
guard let input = try? AVCaptureDeviceInput(device: captureDevice) else { return }
captureSession.addInput(input)
captureSession.startRunning()
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
view.layer.addSublayer(previewLayer)
previewLayer.frame = view.frame
let dataOutput = AVCaptureVideoDataOutput()
dataOutput.setSampleBufferDelegate(self, queue: videoQueue)
captureSession.addOutput(dataOutput)
}
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
print("Camera was able to capture a frame:", Date())
}
}
来源:https://stackoverflow.com/questions/37890791/avcapturevideodataoutput-captureoutput-not-being-called