No se puede capturar datos de video en Swift Playgrounds, no se llama al método delegado captureOutput AVCaptureVideoDataOutputSampleBufferDelegate
camera swift-playground (2)
Quiero acceder a la cámara del iPad en la aplicación Swift Playgrounds iPad. Descubrí que no es posible capturar datos de video, aunque mi área de juegos funciona bien.
captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!)
, un método delegado del protocolo AVCaptureVideoDataOutputSampleBufferDelegate
, no se llama. la aplicación
La vista en mi área de juegos se supone que muestra la vista de la cámara FaceTime. ¿Por qué no puedo mostrar la salida de la cámara a pesar de que Apple explícitamente dice que está permitido hacerlo ? Además, la aplicación Playground me pide permisos de cámara tan pronto como abra mi área de juegos, por lo que debería permitirse de alguna manera.
import UIKit
import CoreImage
import AVFoundation
import ImageIO
import PlaygroundSupport
class Visage: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {
var visageCameraView : UIView = UIView()
fileprivate var faceDetector : CIDetector?
fileprivate var videoDataOutput : AVCaptureVideoDataOutput?
fileprivate var videoDataOutputQueue : DispatchQueue?
fileprivate var cameraPreviewLayer : AVCaptureVideoPreviewLayer?
fileprivate var captureSession : AVCaptureSession = AVCaptureSession()
fileprivate let notificationCenter : NotificationCenter = NotificationCenter.default
override init() {
super.init()
self.captureSetup(AVCaptureDevicePosition.front)
var faceDetectorOptions : [String : AnyObject]?
faceDetectorOptions = [CIDetectorAccuracy : CIDetectorAccuracyHigh as AnyObject]
self.faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: faceDetectorOptions)
}
func beginFaceDetection() {
self.captureSession.startRunning()
}
func endFaceDetection() {
self.captureSession.stopRunning()
}
fileprivate func captureSetup (_ position : AVCaptureDevicePosition) {
var captureError : NSError?
var captureDevice : AVCaptureDevice!
for testedDevice in AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo){
if ((testedDevice as AnyObject).position == position) {
captureDevice = testedDevice as! AVCaptureDevice
}
}
if (captureDevice == nil) {
captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
}
var deviceInput : AVCaptureDeviceInput?
do {
deviceInput = try AVCaptureDeviceInput(device: captureDevice)
} catch let error as NSError {
captureError = error
deviceInput = nil
}
captureSession.sessionPreset = AVCaptureSessionPresetHigh
if (captureError == nil) {
if (captureSession.canAddInput(deviceInput)) {
captureSession.addInput(deviceInput)
}
self.videoDataOutput = AVCaptureVideoDataOutput()
self.videoDataOutput!.videoSettings = [kCVPixelBufferPixelFormatTypeKey as AnyHashable: Int(kCVPixelFormatType_32BGRA)]
self.videoDataOutput!.alwaysDiscardsLateVideoFrames = true
self.videoDataOutputQueue = DispatchQueue(label: "VideoDataOutputQueue", attributes: [])
self.videoDataOutput!.setSampleBufferDelegate(self, queue: self.videoDataOutputQueue!)
if (captureSession.canAddOutput(self.videoDataOutput)) {
captureSession.addOutput(self.videoDataOutput)
}
}
visageCameraView.frame = UIScreen.main.bounds
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer?.frame = UIScreen.main.bounds
previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
visageCameraView.layer.addSublayer(previewLayer!)
}
// NOT CALLED
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
print("delegate method called!")
}
}
class SmileView: UIView {
let smileView = UIView()
var smileRec: Visage!
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(smileView)
self.translatesAutoresizingMaskIntoConstraints = false
smileRec = Visage()
smileRec.beginFaceDetection()
let cameraView = smileRec.visageCameraView
self.addSubview(cameraView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
let frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
let sView = SmileView(frame: frame)
PlaygroundPage.current.liveView = sView
Creo que necesitas establecer la propiedad needsIndefiniteExecution
para que la ejecución no se detenga una vez que se complete tu código. De manzana
De forma predeterminada, se ejecuta todo el código de nivel superior y, a continuación, se termina la ejecución. Al trabajar con código asíncrono, habilite la ejecución indefinida para permitir que la ejecución continúe después de que se alcance el final del código de nivel superior del patio de recreo. Esto, a su vez, le da tiempo a los subprocesos y devoluciones de llamada para ejecutar.
La edición del campo de juego detiene automáticamente la ejecución, incluso cuando la ejecución indefinida está habilitada.
Establezca needsIndefiniteExecution en true para continuar la ejecución después del final del código de nivel superior. configúrelo en falso para detener la ejecución en ese punto.
Así que el código posible al final será:
let frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
let sView = SmileView(frame: frame)
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = sView
Edición: esto debería haber sido arreglado :)
-
Edición: esto fue confirmado como un error por Apple.
He presentado un informe de error y actualizaré esta respuesta cuando llegue nueva información oficial.