From 6eda64430363955f5873a4ae63da92f9c21f7af3 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sat, 26 Jan 2019 22:09:59 -0500 Subject: Add device provider for AVFoundation capture devices. --- sys/applemedia/Makefile.am | 1 + sys/applemedia/avfdeviceprovider.h | 91 +++++++++++++++ sys/applemedia/avfdeviceprovider.m | 216 ++++++++++++++++++++++++++++++++++ sys/applemedia/avfvideosrc.h | 3 + sys/applemedia/avfvideosrc.m | 229 ++++++++++++++++++++----------------- sys/applemedia/meson.build | 3 +- sys/applemedia/plugin.m | 3 + 7 files changed, 443 insertions(+), 103 deletions(-) create mode 100644 sys/applemedia/avfdeviceprovider.h create mode 100644 sys/applemedia/avfdeviceprovider.m diff --git a/sys/applemedia/Makefile.am b/sys/applemedia/Makefile.am index bde9969d3..feebb19ba 100644 --- a/sys/applemedia/Makefile.am +++ b/sys/applemedia/Makefile.am @@ -109,6 +109,7 @@ if HAVE_AVFOUNDATION libgstapplemedia_la_SOURCES += \ avfvideosrc.m \ + avfdeviceprovider.m \ avfassetsrc.m \ avsamplevideosink.m diff --git a/sys/applemedia/avfdeviceprovider.h b/sys/applemedia/avfdeviceprovider.h new file mode 100644 index 000000000..9596222c6 --- /dev/null +++ b/sys/applemedia/avfdeviceprovider.h @@ -0,0 +1,91 @@ +/* GStreamer + * Copyright (C) 2019 Josh Matthews + * + * avfdeviceprovider.h: AVF device probing and monitoring + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_AVF_DEVICE_PROVIDER_H__ +#define __GST_AVF_DEVICE_PROVIDER_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "avfvideosrc.h" + +G_BEGIN_DECLS + +typedef struct _GstAVFDeviceProvider GstAVFDeviceProvider; +typedef struct _GstAVFDeviceProviderPrivate GstAVFDeviceProviderPrivate; +typedef struct _GstAVFDeviceProviderClass GstAVFDeviceProviderClass; + +#define GST_TYPE_AVF_DEVICE_PROVIDER (gst_avf_device_provider_get_type()) +#define GST_IS_AVF_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AVF_DEVICE_PROVIDER)) +#define GST_IS_AVF_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AVF_DEVICE_PROVIDER)) +#define GST_AVF_DEVICE_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_AVF_DEVICE_PROVIDER, GstAVFDeviceProviderClass)) +#define GST_AVF_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AVF_DEVICE_PROVIDER, GstAVFDeviceProvider)) +#define GST_AVF_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_PROVIDER, GstAVFDeviceProviderClass)) +#define GST_AVF_DEVICE_PROVIDER_CAST(obj) ((GstAvfDeviceProvider *)(obj)) + +struct _GstAVFDeviceProvider { + GstDeviceProvider parent; +}; + +typedef enum { + GST_AVF_DEVICE_TYPE_INVALID = 0, + GST_AVF_DEVICE_TYPE_VIDEO_SOURCE, +} GstAvfDeviceType; + +struct _GstAVFDeviceProviderClass { + GstDeviceProviderClass parent_class; +}; + +GType gst_avf_device_provider_get_type (void); + + +typedef struct _GstAvfDevice GstAvfDevice; +typedef struct _GstAvfDevicePrivate GstAvfDevicePrivate; +typedef struct _GstAvfDeviceClass GstAvfDeviceClass; + +#define GST_TYPE_AVF_DEVICE (gst_avf_device_get_type()) +#define GST_IS_AVF_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AVF_DEVICE)) +#define GST_IS_AVF_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AVF_DEVICE)) +#define GST_AVF_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_AVF_DEVICE, GstAvfDeviceClass)) +#define GST_AVF_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AVF_DEVICE, GstAvfDevice)) +#define GST_AVF_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE, GstAvfDeviceClass)) +#define GST_AVF_DEVICE_CAST(obj) ((GstAvfDevice *)(obj)) + +struct _GstAvfDevice { + GstDevice parent; + + GstAvfDeviceType type; + int device_index; + const gchar *element; +}; + +struct _GstAvfDeviceClass { + GstDeviceClass parent_class; +}; + +GType gst_avf_device_get_type (void); + +G_END_DECLS + +#endif /* __GST_AVF_DEVICE_PROVIDER_H__ */ diff --git a/sys/applemedia/avfdeviceprovider.m b/sys/applemedia/avfdeviceprovider.m new file mode 100644 index 000000000..c2d384d7a --- /dev/null +++ b/sys/applemedia/avfdeviceprovider.m @@ -0,0 +1,216 @@ +/* GStreamer + * Copyright (C) 2019 Josh Matthews + * + * avfdeviceprovider.c: AVF device probing and monitoring + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#import +#include "avfvideosrc.h" +#include "avfdeviceprovider.h" + +#include + +#include + +static GstDevice *gst_avf_device_new (const gchar * device_name, int device_index, + GstCaps * caps, GstAvfDeviceType type); +G_DEFINE_TYPE (GstAVFDeviceProvider, gst_avf_device_provider, + GST_TYPE_DEVICE_PROVIDER); + +static GList *gst_avf_device_provider_probe (GstDeviceProvider * provider); + +static void +gst_avf_device_provider_class_init (GstAVFDeviceProviderClass * klass) +{ + GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass); + + // TODO: Add start/stop callbacks to receive device notifications. + // https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/886 + dm_class->probe = gst_avf_device_provider_probe; + + gst_device_provider_class_set_static_metadata (dm_class, + "AVF Device Provider", "Source/Video", + "List and provide AVF source devices", + "Josh Matthews "); +} + +static void +gst_avf_device_provider_init (GstAVFDeviceProvider * self) +{ +} + +static GList * +gst_avf_device_provider_probe (GstDeviceProvider * provider) +{ + GList *result; + + result = NULL; + + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init]; + for (int i = 0; i < [devices count]; i++) { + AVCaptureDevice *device = [devices objectAtIndex:i]; + g_assert (device != nil); + GstCaps *caps = gst_av_capture_device_get_caps (device, output, GST_AVF_VIDEO_SOURCE_ORIENTATION_DEFAULT); + const gchar *deviceName = [[device localizedName] UTF8String]; + GstDevice *gst_device = gst_avf_device_new (deviceName, i, caps, GST_AVF_DEVICE_TYPE_VIDEO_SOURCE); + + result = g_list_prepend (result, gst_object_ref_sink (gst_device)); + } + + result = g_list_reverse (result); + + return result; +} + +enum +{ + PROP_DEVICE_INDEX = 1 +}; + +G_DEFINE_TYPE (GstAvfDevice, gst_avf_device, GST_TYPE_DEVICE); + +static GstElement *gst_avf_device_create_element (GstDevice * device, + const gchar * name); +static gboolean gst_avf_device_reconfigure_element (GstDevice * device, + GstElement * element); + +static void gst_avf_device_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_avf_device_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + +static void +gst_avf_device_class_init (GstAvfDeviceClass * klass) +{ + GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + dev_class->create_element = gst_avf_device_create_element; + dev_class->reconfigure_element = gst_avf_device_reconfigure_element; + + object_class->get_property = gst_avf_device_get_property; + object_class->set_property = gst_avf_device_set_property; + + g_object_class_install_property (object_class, PROP_DEVICE_INDEX, + g_param_spec_int ("device-index", "Device Index", + "The zero-based device index", -1, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_avf_device_init (GstAvfDevice * device) +{ +} + +static GstElement * +gst_avf_device_create_element (GstDevice * device, const gchar * name) +{ + GstAvfDevice *avf_dev = GST_AVF_DEVICE (device); + GstElement *elem; + + elem = gst_element_factory_make (avf_dev->element, name); + g_object_set (elem, "device-index", avf_dev->device_index, NULL); + + return elem; +} + +static gboolean +gst_avf_device_reconfigure_element (GstDevice * device, GstElement * element) +{ + GstAvfDevice *avf_dev = GST_AVF_DEVICE (device); + + if (!strcmp (avf_dev->element, "avfvideosrc") && GST_IS_AVF_VIDEO_SRC (element)) { + g_object_set (element, "device-index", avf_dev->device_index, NULL); + return TRUE; + } + + return FALSE; +} + +static void +gst_avf_device_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstAvfDevice *device; + + device = GST_AVF_DEVICE_CAST (object); + + switch (prop_id) { + case PROP_DEVICE_INDEX: + g_value_set_int (value, device->device_index); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_avf_device_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstAvfDevice *device; + + device = GST_AVF_DEVICE_CAST (object); + + switch (prop_id) { + case PROP_DEVICE_INDEX: + device->device_index = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstDevice * +gst_avf_device_new (const gchar * device_name, int device_index, GstCaps * caps, GstAvfDeviceType type) +{ + GstAvfDevice *gstdev; + const gchar *element = NULL; + const gchar *klass = NULL; + + g_return_val_if_fail (device_name, NULL); + g_return_val_if_fail (caps, NULL); + + + switch (type) { + case GST_AVF_DEVICE_TYPE_VIDEO_SOURCE: + element = "avfvideosrc"; + klass = "Video/Source"; + break; + default: + g_assert_not_reached (); + break; + } + + + gstdev = g_object_new (GST_TYPE_AVF_DEVICE, + "display-name", device_name, "caps", caps, "device-class", klass, + "device-index", device_index, NULL); + + gstdev->type = type; + gstdev->element = element; + + return GST_DEVICE (gstdev); +} diff --git a/sys/applemedia/avfvideosrc.h b/sys/applemedia/avfvideosrc.h index c49df5986..15ebcec51 100644 --- a/sys/applemedia/avfvideosrc.h +++ b/sys/applemedia/avfvideosrc.h @@ -20,6 +20,7 @@ #ifndef __GST_AVF_VIDEO_SRC_H__ #define __GST_AVF_VIDEO_SRC_H__ +#import #include G_BEGIN_DECLS @@ -82,6 +83,8 @@ struct _GstAVFVideoSrcClass GType gst_avf_video_src_get_type (void); +GstCaps *gst_av_capture_device_get_caps (AVCaptureDevice *device, AVCaptureVideoDataOutput *output, GstAVFVideoSourceOrientation orientation); + G_END_DECLS #endif /* __GST_AVF_VIDEO_SRC_H__ */ diff --git a/sys/applemedia/avfvideosrc.m b/sys/applemedia/avfvideosrc.m index 349429131..ac6e17976 100644 --- a/sys/applemedia/avfvideosrc.m +++ b/sys/applemedia/avfvideosrc.m @@ -48,6 +48,10 @@ GST_DEBUG_CATEGORY (gst_avf_video_src_debug); #define GST_CAT_DEFAULT gst_avf_video_src_debug +static GstVideoFormat get_gst_video_format(NSNumber *pixel_format); +static CMVideoDimensions +get_oriented_dimensions(GstAVFVideoSourceOrientation orientation, CMVideoDimensions dimensions); + static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, @@ -507,27 +511,11 @@ static AVCaptureVideoOrientation GstAVFVideoSourceOrientation2AVCaptureVideoOrie - (GstVideoFormat)getGstVideoFormat:(NSNumber *)pixel_format { - GstVideoFormat gst_format = GST_VIDEO_FORMAT_UNKNOWN; - - switch ([pixel_format integerValue]) { - case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: /* 420v */ - gst_format = GST_VIDEO_FORMAT_NV12; - break; - case kCVPixelFormatType_422YpCbCr8: /* 2vuy */ - gst_format = GST_VIDEO_FORMAT_UYVY; - break; - case kCVPixelFormatType_32BGRA: /* BGRA */ - gst_format = GST_VIDEO_FORMAT_BGRA; - break; - case kCVPixelFormatType_422YpCbCr8_yuvs: /* yuvs */ - gst_format = GST_VIDEO_FORMAT_YUY2; - break; - default: + GstVideoFormat gst_format = get_gst_video_format(pixel_format); + if (gst_format == GST_VIDEO_FORMAT_UNKNOWN) { GST_LOG_OBJECT (element, "Pixel format %s is not handled by avfvideosrc", [[pixel_format stringValue] UTF8String]); - break; } - return gst_format; } @@ -568,96 +556,16 @@ static AVCaptureVideoOrientation GstAVFVideoSourceOrientation2AVCaptureVideoOrie - (CMVideoDimensions)orientedDimensions:(CMVideoDimensions)dimensions { - CMVideoDimensions orientedDimensions; - if (orientation == GST_AVF_VIDEO_SOURCE_ORIENTATION_PORTRAIT_UPSIDE_DOWN || - orientation == GST_AVF_VIDEO_SOURCE_ORIENTATION_PORTRAIT) { - orientedDimensions.width = dimensions.height; - orientedDimensions.height = dimensions.width; - } else { - orientedDimensions = dimensions; - } - return orientedDimensions; + return get_oriented_dimensions(orientation, dimensions); } - (GstCaps *)getDeviceCaps { - NSArray *formats = [device valueForKey:@"formats"]; - NSArray *pixel_formats = output.availableVideoCVPixelFormatTypes; - GstCaps *result_caps, *result_gl_caps; -#if !HAVE_IOS - GstVideoFormat gl_format = GST_VIDEO_FORMAT_UYVY; -#else - GstVideoFormat gl_format = GST_VIDEO_FORMAT_NV12; -#endif - GST_DEBUG_OBJECT (element, "Getting device caps"); + GstCaps *device_caps = gst_av_capture_device_get_caps (device, output, orientation); + GST_DEBUG_OBJECT (element, "Device returned the following caps %" GST_PTR_FORMAT, device_caps); - result_caps = gst_caps_new_empty (); - result_gl_caps = gst_caps_new_empty (); - - /* Do not use AVCaptureDeviceFormat or AVFrameRateRange only - * available in iOS >= 7.0. We use a dynamic approach with key-value - * coding or performSelector */ - for (NSObject *f in [formats reverseObjectEnumerator]) { - /* formatDescription can't be retrieved with valueForKey so use a selector here */ - CMFormatDescriptionRef formatDescription = (__bridge CMFormatDescriptionRef) [f performSelector:@selector(formatDescription)]; - CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription); - dimensions = [self orientedDimensions:dimensions]; - - for (NSObject *rate in [f valueForKey:@"videoSupportedFrameRateRanges"]) { - int min_fps_n, min_fps_d, max_fps_n, max_fps_d; - gdouble min_fps, max_fps; - - [[rate valueForKey:@"minFrameRate"] getValue:&min_fps]; - gst_util_double_to_fraction (min_fps, &min_fps_n, &min_fps_d); - - [[rate valueForKey:@"maxFrameRate"] getValue:&max_fps]; - gst_util_double_to_fraction (max_fps, &max_fps_n, &max_fps_d); - - for (NSNumber *pixel_format in pixel_formats) { - GstVideoFormat gst_format = [self getGstVideoFormat:pixel_format]; - - if (gst_format != GST_VIDEO_FORMAT_UNKNOWN) { - if (min_fps != max_fps) - gst_caps_append (result_caps, GST_AVF_FPS_RANGE_CAPS_NEW (gst_format, dimensions.width, dimensions.height, min_fps_n, min_fps_d, max_fps_n, max_fps_d)); - else - gst_caps_append (result_caps, GST_AVF_CAPS_NEW (gst_format, dimensions.width, dimensions.height, max_fps_n, max_fps_d)); - } - - if (gst_format == gl_format) { - GstCaps *gl_caps; - if (min_fps != max_fps) { - gl_caps = GST_AVF_FPS_RANGE_CAPS_NEW (gl_format, - dimensions.width, dimensions.height, - min_fps_n, min_fps_d, - max_fps_n, max_fps_d); - } else { - gl_caps = GST_AVF_CAPS_NEW (gl_format, - dimensions.width, dimensions.height, - max_fps_n, max_fps_d); - } - gst_caps_set_features (gl_caps, 0, - gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, - NULL)); - gst_caps_set_simple (gl_caps, - "texture-target", G_TYPE_STRING, -#if !HAVE_IOS - GST_GL_TEXTURE_TARGET_RECTANGLE_STR, -#else - GST_GL_TEXTURE_TARGET_2D_STR, -#endif - NULL); - gst_caps_append (result_gl_caps, gl_caps); - } - } - } - } - - result_gl_caps = gst_caps_simplify (gst_caps_merge (result_gl_caps, result_caps)); - - GST_DEBUG_OBJECT (element, "Device returned the following caps %" GST_PTR_FORMAT, result_gl_caps); - - return result_gl_caps; + return device_caps; } - (BOOL)setDeviceCaps:(GstVideoInfo *)info @@ -1605,3 +1513,120 @@ gst_avf_video_src_set_context (GstElement * element, GstContext * context) { [GST_AVF_VIDEO_SRC_IMPL (element) setContext:context]; } + +GstCaps* +gst_av_capture_device_get_caps (AVCaptureDevice *device, AVCaptureVideoDataOutput *output, GstAVFVideoSourceOrientation orientation) +{ + NSArray *formats = [device valueForKey:@"formats"]; + NSArray *pixel_formats = output.availableVideoCVPixelFormatTypes; + GstCaps *result_caps, *result_gl_caps; +#if !HAVE_IOS + GstVideoFormat gl_format = GST_VIDEO_FORMAT_UYVY; +#else + GstVideoFormat gl_format = GST_VIDEO_FORMAT_NV12; +#endif + + result_caps = gst_caps_new_empty (); + result_gl_caps = gst_caps_new_empty (); + + /* Do not use AVCaptureDeviceFormat or AVFrameRateRange only + * available in iOS >= 7.0. We use a dynamic approach with key-value + * coding or performSelector */ + for (NSObject *f in [formats reverseObjectEnumerator]) { + /* formatDescription can't be retrieved with valueForKey so use a selector here */ + CMFormatDescriptionRef formatDescription = (__bridge CMFormatDescriptionRef) [f performSelector:@selector(formatDescription)]; + CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions (formatDescription); + dimensions = get_oriented_dimensions (orientation, dimensions); + + for (NSObject *rate in [f valueForKey:@"videoSupportedFrameRateRanges"]) { + int min_fps_n, min_fps_d, max_fps_n, max_fps_d; + gdouble min_fps, max_fps; + + [[rate valueForKey:@"minFrameRate"] getValue:&min_fps]; + gst_util_double_to_fraction (min_fps, &min_fps_n, &min_fps_d); + + [[rate valueForKey:@"maxFrameRate"] getValue:&max_fps]; + gst_util_double_to_fraction (max_fps, &max_fps_n, &max_fps_d); + + for (NSNumber *pixel_format in pixel_formats) { + GstVideoFormat gst_format = get_gst_video_format (pixel_format); + + if (gst_format != GST_VIDEO_FORMAT_UNKNOWN) { + if (min_fps != max_fps) + gst_caps_append (result_caps, GST_AVF_FPS_RANGE_CAPS_NEW (gst_format, dimensions.width, dimensions.height, min_fps_n, min_fps_d, max_fps_n, max_fps_d)); + else + gst_caps_append (result_caps, GST_AVF_CAPS_NEW (gst_format, dimensions.width, dimensions.height, max_fps_n, max_fps_d)); + } + + if (gst_format == gl_format) { + GstCaps *gl_caps; + if (min_fps != max_fps) { + gl_caps = GST_AVF_FPS_RANGE_CAPS_NEW (gl_format, + dimensions.width, dimensions.height, + min_fps_n, min_fps_d, + max_fps_n, max_fps_d); + } else { + gl_caps = GST_AVF_CAPS_NEW (gl_format, + dimensions.width, dimensions.height, + max_fps_n, max_fps_d); + } + gst_caps_set_features (gl_caps, 0, + gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, + NULL)); + gst_caps_set_simple (gl_caps, + "texture-target", G_TYPE_STRING, +#if !HAVE_IOS + GST_GL_TEXTURE_TARGET_RECTANGLE_STR, +#else + GST_GL_TEXTURE_TARGET_2D_STR, +#endif + NULL); + gst_caps_append (result_gl_caps, gl_caps); + } + } + } + } + + result_gl_caps = gst_caps_simplify (gst_caps_merge (result_gl_caps, result_caps)); + + return result_gl_caps; +} + +static GstVideoFormat +get_gst_video_format (NSNumber *pixel_format) +{ + GstVideoFormat gst_format = GST_VIDEO_FORMAT_UNKNOWN; + + switch ([pixel_format integerValue]) { + case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: /* 420v */ + gst_format = GST_VIDEO_FORMAT_NV12; + break; + case kCVPixelFormatType_422YpCbCr8: /* 2vuy */ + gst_format = GST_VIDEO_FORMAT_UYVY; + break; + case kCVPixelFormatType_32BGRA: /* BGRA */ + gst_format = GST_VIDEO_FORMAT_BGRA; + break; + case kCVPixelFormatType_422YpCbCr8_yuvs: /* yuvs */ + gst_format = GST_VIDEO_FORMAT_YUY2; + break; + default: + break; + } + + return gst_format; +} + +static CMVideoDimensions +get_oriented_dimensions (GstAVFVideoSourceOrientation orientation, CMVideoDimensions dimensions) +{ + CMVideoDimensions orientedDimensions; + if (orientation == GST_AVF_VIDEO_SOURCE_ORIENTATION_PORTRAIT_UPSIDE_DOWN || + orientation == GST_AVF_VIDEO_SOURCE_ORIENTATION_PORTRAIT) { + orientedDimensions.width = dimensions.height; + orientedDimensions.height = dimensions.width; + } else { + orientedDimensions = dimensions; + } + return orientedDimensions; +} diff --git a/sys/applemedia/meson.build b/sys/applemedia/meson.build index eab919ce1..0ca1e5223 100644 --- a/sys/applemedia/meson.build +++ b/sys/applemedia/meson.build @@ -35,7 +35,8 @@ if avfoundation_dep.found() applemedia_sources += [ 'avfvideosrc.m', 'avfassetsrc.m', - 'avsamplevideosink.m' + 'avsamplevideosink.m', + 'avfdeviceprovider.m', ] applemedia_frameworks += [avfoundation_dep] endif diff --git a/sys/applemedia/plugin.m b/sys/applemedia/plugin.m index 5adc96a82..a96b680c2 100644 --- a/sys/applemedia/plugin.m +++ b/sys/applemedia/plugin.m @@ -30,6 +30,7 @@ #ifdef HAVE_AVFOUNDATION #include "avfvideosrc.h" #include "avfassetsrc.h" +#include "avfdeviceprovider.h" #include "avsamplevideosink.h" #endif #ifdef HAVE_VIDEOTOOLBOX @@ -80,6 +81,8 @@ plugin_init (GstPlugin * plugin) GST_TYPE_AVF_ASSET_SRC); res &= gst_element_register (plugin, "avsamplebufferlayersink", GST_RANK_NONE, GST_TYPE_AV_SAMPLE_VIDEO_SINK); + res &= gst_device_provider_register (plugin, "avfdeviceprovider", + GST_RANK_PRIMARY, GST_TYPE_AVF_DEVICE_PROVIDER); #endif res &= gst_element_register (plugin, "atdec", GST_RANK_MARGINAL, GST_TYPE_ATDEC); -- cgit v1.2.1