Mein Ziel ist es, den Bildschirm eines iDevice zu OSX so verzögerungsfrei wie möglich zu spiegeln.Kann VideoToolbox H264 Anhang B nativ dekodieren? Fehlercode -8969 BadData
Meines Wissens gibt es zwei Möglichkeiten, um dies:
Airplay Mirroring
(zB Reflektor)CoreMediaIO
über Lightning (zB Quicktime Recording)
Ich habe gewählt, um das zweite Verfahren zu verfolgen , weil (nach meinem Wissen) angeschlossene iDevices nach einmaliger Einrichtung automatisch als DAL-Geräte erkannt werden können.
Die wichtigste Ressource, wie dies zu tun, ist dieser Blog: https://nadavrub.wordpress.com/2015/07/06/macos-media-capture-using-coremediaio/
Das Blog sehr tief in geht, wie CoreMediaIO
zu verwenden, jedoch scheint es, wie Sie mit AVFoundation
arbeiten können, wenn Sie das angeschlossene iDevice als erkannt haben AVCaptureDevice
.
Diese Frage: How to mirror iOS screen via USB? hat eine Lösung zur Verfügung gestellt, wie man jeden Rahmen des H264 (Anhang B) muxxed Datenstroms, der vom iDevice geliefert wird, ergreift.
Mein Problem ist jedoch, dass VideoToolbox
wird nicht korrekt dekodieren (Fehlercode -8969, BadData), obwohl es keinen Unterschied im Code sein sollte.
vtDecompressionDuctDecodeSingleFrame signalisiert err = -8.969 (err) (VTVideoDecoderDecodeFrame Fehler zurückgegeben) bei /SourceCache/CoreMedia_frameworks/CoreMedia-1562.240/Sources/VideoToolbox/VTDecompressionSession.c Linie 3241
komplette Code:
#import "ViewController.h"
@import CoreMediaIO;
@import AVFoundation;
@import AppKit;
@implementation ViewController
AVCaptureSession *session;
AVCaptureDeviceInput *newVideoDeviceInput;
AVCaptureVideoDataOutput *videoDataOutput;
- (void)viewDidLoad {
[super viewDidLoad];
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
// Allow iOS Devices Discovery
CMIOObjectPropertyAddress prop =
{ kCMIOHardwarePropertyAllowScreenCaptureDevices,
kCMIOObjectPropertyScopeGlobal,
kCMIOObjectPropertyElementMaster };
UInt32 allow = 1;
CMIOObjectSetPropertyData(kCMIOObjectSystemObject,
&prop, 0, NULL,
sizeof(allow), &allow);
// Get devices
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeMuxed];
BOOL deviceAttahced = false;
for (int i = 0; i < [devices count]; i++) {
AVCaptureDevice *device = devices[i];
if ([[device uniqueID] isEqualToString:@"b48defcadf92f300baf5821923f7b3e2e9fb3947"]) {
deviceAttahced = true;
[self startSession:device];
break;
}
}
}
return self;
}
- (void) deviceConnected:(AVCaptureDevice *)device {
if ([[device uniqueID] isEqualToString:@"b48defcadf92f300baf5821923f7b3e2e9fb3947"]) {
[self startSession:device];
}
}
- (void) startSession:(AVCaptureDevice *)device {
// Init capturing session
session = [[AVCaptureSession alloc] init];
// Star session configuration
[session beginConfiguration];
// Add session input
NSError *error;
newVideoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (newVideoDeviceInput == nil) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
NSLog(@"%@", error);
});
} else {
[session addInput:newVideoDeviceInput];
}
// Add session output
videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
videoDataOutput.videoSettings = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey: (id)kCVPixelBufferPixelFormatTypeKey];
dispatch_queue_t videoQueue = dispatch_queue_create("videoQueue", NULL);
[videoDataOutput setSampleBufferDelegate:self queue:videoQueue];
[session addOutput:videoDataOutput];
// Finish session configuration
[session commitConfiguration];
// Start the session
[session startRunning];
}
#pragma mark - AVCaptureAudioDataOutputSampleBufferDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
//NSImage *resultNSImage = [self imageFromSampleBuffer:sampleBuffer];
//self.imageView.image = [self nsImageFromSampleBuffer:sampleBuffer];
self.imageView.image = [[NSImage alloc] initWithData:imageToBuffer(sampleBuffer)];
}
NSData* imageToBuffer(CMSampleBufferRef source) {
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(source);
CVPixelBufferLockBaseAddress(imageBuffer,0);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
void *src_buff = CVPixelBufferGetBaseAddress(imageBuffer);
NSData *data = [NSData dataWithBytes:src_buff length:bytesPerRow * height];
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
return data;
}