avfvideosrc: support screen capture on OSX

https://bugzilla.gnome.org/show_bug.cgi?id=711432
This commit is contained in:
Matthieu Bouron 2013-11-04 11:14:35 +00:00 committed by Andoni Morales Alastruey
parent 88b5ff76f6
commit 66334591cc

View file

@ -72,9 +72,12 @@ G_DEFINE_TYPE (GstAVFVideoSrc, gst_avf_video_src, GST_TYPE_PUSH_SRC);
gint deviceIndex;
BOOL doStats;
#ifndef HAVE_IOS
CGDirectDisplayID displayId;
#endif
AVCaptureSession *session;
AVCaptureDeviceInput *input;
AVCaptureInput *input;
AVCaptureVideoDataOutput *output;
AVCaptureDevice *device;
@ -102,7 +105,12 @@ G_DEFINE_TYPE (GstAVFVideoSrc, gst_avf_video_src, GST_TYPE_PUSH_SRC);
@property int deviceIndex;
@property BOOL doStats;
@property int fps;
@property BOOL captureScreen;
@property BOOL captureScreenCursor;
@property BOOL captureScreenMouseClicks;
- (BOOL)openScreenInput;
- (BOOL)openDeviceInput;
- (BOOL)openDevice;
- (void)closeDevice;
- (GstVideoFormat)getGstVideoFormat:(NSNumber *)pixel_format;
@ -142,6 +150,12 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
pushSrc = src;
deviceIndex = DEFAULT_DEVICE_INDEX;
captureScreen = NO;
captureScreenCursor = NO;
captureScreenMouseClicks = NO;
#ifndef HAVE_IOS
displayId = kCGDirectMainDisplay;
#endif
mainQueue =
dispatch_queue_create ("org.freedesktop.gstreamer.avfvideosrc.main", NULL);
@ -165,13 +179,11 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
[super finalize];
}
@synthesize deviceIndex, doStats, fps;
@synthesize deviceIndex, doStats, fps, captureScreen,
captureScreenCursor, captureScreenMouseClicks;
- (BOOL)openDevice
- (BOOL)openDeviceInput
{
BOOL success = NO, *successPtr = &success;
dispatch_sync (mainQueue, ^{
NSString *mediaType = AVMediaTypeVideo;
NSError *err;
@ -180,14 +192,14 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
if (device == nil) {
GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND,
("No video capture devices found"), (NULL));
return;
return NO;
}
} else {
NSArray *devices = [AVCaptureDevice devicesWithMediaType:mediaType];
if (deviceIndex >= [devices count]) {
GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND,
("Invalid video capture device index"), (NULL));
return;
return NO;
}
device = [devices objectAtIndex:deviceIndex];
}
@ -205,9 +217,52 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
(NULL));
[device release];
device = nil;
return;
return NO;
}
[input retain];
return YES;
}
- (BOOL)openScreenInput
{
#if HAVE_IOS
return NO;
#else
AVCaptureScreenInput *screenInput =
[[AVCaptureScreenInput alloc] initWithDisplayID:displayId];
@try {
[screenInput setValue:[NSNumber numberWithBool:captureScreenCursor]
forKey:@"capturesCursor"];
} @catch (NSException *exception) {
if (![[exception name] isEqualTo:NSUndefinedKeyException]) {
GST_WARNING ("An unexpected error occured: %s",
[[exception reason] UTF8String]);
}
GST_WARNING ("Capturing cursor is only supported in OS X >= 10.8");
}
screenInput.capturesMouseClicks = captureScreenMouseClicks;
input = screenInput;
[input retain];
return YES;
#endif
}
- (BOOL)openDevice
{
BOOL success = NO, *successPtr = &success;
dispatch_sync (mainQueue, ^{
BOOL ret;
if (captureScreen)
ret = [self openScreenInput];
else
ret = [self openDeviceInput];
if (!ret)
return;
output = [[AVCaptureVideoDataOutput alloc] init];
[output setSampleBufferDelegate:self
@ -242,8 +297,10 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
[output release];
output = nil;
if (!captureScreen) {
[device release];
device = nil;
}
if (caps)
gst_caps_unref (caps);
@ -430,6 +487,24 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
result = gst_caps_new_empty ();
pixel_formats = output.availableVideoCVPixelFormatTypes;
if (captureScreen) {
#ifndef HAVE_IOS
CGRect rect = CGDisplayBounds (displayId);
for (NSNumber *pixel_format in pixel_formats) {
GstVideoFormat gst_format = [self getGstVideoFormat:pixel_format];
if (gst_format != GST_VIDEO_FORMAT_UNKNOWN)
gst_caps_append (result, gst_caps_new_simple ("video/x-raw",
"width", G_TYPE_INT, (int)rect.size.width,
"height", G_TYPE_INT, (int)rect.size.height,
"format", G_TYPE_STRING, gst_video_format_to_string (gst_format),
NULL));
}
#else
GST_WARNING ("Screen capture is not supported by iOS");
#endif
return result;
}
@try {
[self getDeviceCaps:result];
@ -465,6 +540,16 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
g_assert (![session isRunning]);
if (captureScreen) {
#ifndef HAVE_IOS
AVCaptureScreenInput *screenInput = (AVCaptureScreenInput *)input;
screenInput.minFrameDuration = CMTimeMake(info.fps_d, info.fps_n);
#else
GST_WARNING ("Screen capture is not supported by iOS");
*successPtr = NO;
return;
#endif
} else {
@try {
/* formats and activeFormat keys are only available on OSX >= 10.7 and iOS >= 7.0 */
@ -485,6 +570,7 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
if (*successPtr != YES)
return;
}
}
switch (format) {
case GST_VIDEO_FORMAT_NV12:
@ -760,7 +846,12 @@ enum
PROP_0,
PROP_DEVICE_INDEX,
PROP_DO_STATS,
PROP_FPS
PROP_FPS,
#ifndef HAVE_IOS
PROP_CAPTURE_SCREEN,
PROP_CAPTURE_SCREEN_CURSOR,
PROP_CAPTURE_SCREEN_MOUSE_CLICKS,
#endif
};
@ -830,6 +921,20 @@ gst_avf_video_src_class_init (GstAVFVideoSrcClass * klass)
g_param_spec_int ("fps", "Frames per second",
"Last measured framerate, if statistics are enabled",
-1, G_MAXINT, -1, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
#ifndef HAVE_IOS
g_object_class_install_property (gobject_class, PROP_CAPTURE_SCREEN,
g_param_spec_boolean ("capture-screen", "Enable screen capture",
"Enable screen capture functionality", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CAPTURE_SCREEN_CURSOR,
g_param_spec_boolean ("capture-screen-cursor", "Capture screen cursor",
"Enable cursor capture while capturing screen", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CAPTURE_SCREEN_MOUSE_CLICKS,
g_param_spec_boolean ("capture-screen-mouse-clicks", "Enable mouse clicks capture",
"Enable mouse clicks capture while capturing screen", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#endif
GST_DEBUG_CATEGORY_INIT (gst_avf_video_src_debug, "avfvideosrc",
0, "iOS AVFoundation video source");
@ -868,6 +973,17 @@ gst_avf_video_src_get_property (GObject * object, guint prop_id, GValue * value,
GstAVFVideoSrcImpl *impl = GST_AVF_VIDEO_SRC_IMPL (object);
switch (prop_id) {
#ifndef HAVE_IOS
case PROP_CAPTURE_SCREEN:
g_value_set_boolean (value, impl.captureScreen);
break;
case PROP_CAPTURE_SCREEN_CURSOR:
g_value_set_boolean (value, impl.captureScreenCursor);
break;
case PROP_CAPTURE_SCREEN_MOUSE_CLICKS:
g_value_set_boolean (value, impl.captureScreenMouseClicks);
break;
#endif
case PROP_DEVICE_INDEX:
g_value_set_int (value, impl.deviceIndex);
break;
@ -892,6 +1008,17 @@ gst_avf_video_src_set_property (GObject * object, guint prop_id,
GstAVFVideoSrcImpl *impl = GST_AVF_VIDEO_SRC_IMPL (object);
switch (prop_id) {
#ifndef HAVE_IOS
case PROP_CAPTURE_SCREEN:
impl.captureScreen = g_value_get_boolean (value);
break;
case PROP_CAPTURE_SCREEN_CURSOR:
impl.captureScreenCursor = g_value_get_boolean (value);
break;
case PROP_CAPTURE_SCREEN_MOUSE_CLICKS:
impl.captureScreenMouseClicks = g_value_get_boolean (value);
break;
#endif
case PROP_DEVICE_INDEX:
impl.deviceIndex = g_value_get_int (value);
break;