J'ai fait une implémentation minimale qui acquiert l'écran d'un iPhone câblé à un mac en temps réel.
Jusqu'à présent, il était nécessaire de démarrer QuickTime Player et de sélectionner l'iPhone dans "Nouvel enregistrement de film", etc., mais il est désormais possible de le faire avec votre propre programme.
Il est téléchargé sur GitHub. https://github.com/satoshi0212/DeviceCameraMonitorSample
Les mises à jour d'informations telles que la caméra virtuelle / AR / expression vidéo, y compris cette implémentation, sont publiées sur Twitter. https://twitter.com/shmdevelop
«Matériel» et «Caméra» doivent être sélectionnés.
plist
Ajoutez Privacy --Camera Usage Description
à votre plist.
ʻAVCaptureDevice.DiscoverySession` En spécifiant ce qui suit avant l'exécution, le périphérique externe sera affiché par opt-in.
var prop = CMIOObjectPropertyAddress(
mSelector: CMIOObjectPropertySelector(kCMIOHardwarePropertyAllowScreenCaptureDevices),
mScope: CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal),
mElement: CMIOObjectPropertyElement(kCMIOObjectPropertyElementMaster))
var allow: UInt32 = 1;
CMIOObjectSetPropertyData(CMIOObjectID(kCMIOObjectSystemObject), &prop, 0, nil, UInt32(MemoryLayout.size(ofValue: allow)), &allow)
Et si vous recherchez avec les paramètres suivants, l'iPhone est inclus dans les appareils. Vous pouvez identifier les appareils iPhone en filtrant les appareils trouvés de manière appropriée par «modelID» et «fabricant».
let devices = AVCaptureDevice.DiscoverySession(deviceTypes: [.externalUnknown], mediaType: nil, position: .unspecified).devices
if let device = devices.filter({ $0.modelID == "iOS Device" && $0.manufacturer == "Apple Inc." }).first {
...
}
Cependant, il était également nécessaire d'observer la notification de ʻAVCaptureDeviceWasConnectedNotification` car l'iPhone peut ne pas être trouvé immédiatement après le démarrage ou la recherche.
let nc = NotificationCenter.default
nc.addObserver(forName: NSNotification.Name(rawValue: "AVCaptureDeviceWasConnectedNotification"), object: nil, queue: .main) { (notification) in
print(notification)
guard let device = notification.object as? AVCaptureDevice else { return }
...
}
Dans l'implémentation téléchargée, il a été redimensionné pour l'affichage à l'écran.
Calculez le rapport avec la hauteur comme valeur fixe, calculez la largeur et spécifiez la taille de l'imageView.
L'image est redimensionnée avec CGAffineTransform
.
private func resizeIfNeeded(w: CGFloat, h: CGFloat) {
guard targetRect == nil else { return }
let aspect = h / fixedHeight
let rect = CGRect(x: 0, y: 0, width: floor(w / aspect), height: fixedHeight)
imageView.frame = rect
targetRect = rect
}
...
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
connection.videoOrientation = .portrait
DispatchQueue.main.async(execute: {
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let w = CGFloat(CVPixelBufferGetWidth(pixelBuffer))
let h = CGFloat(CVPixelBufferGetHeight(pixelBuffer))
self.resizeIfNeeded(w: w, h: h)
guard let targetRect = self.targetRect else { return }
let m = CGAffineTransform(scaleX: targetRect.width / w, y: targetRect.height / h)
let resizedImage = ciImage.transformed(by: m)
let cgimage = self.context.createCGImage(resizedImage, from: targetRect)!
let image = NSImage(cgImage: cgimage, size: targetRect.size)
self.imageView.image = image
})
}