mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
avfvideosrc: support screen capture on OSX
https://bugzilla.gnome.org/show_bug.cgi?id=711432
This commit is contained in:
parent
88b5ff76f6
commit
66334591cc
1 changed files with 180 additions and 53 deletions
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue