summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2019-01-26 22:09:59 -0500
committerSebastian Dröge <slomo@coaxion.net>2019-02-08 15:25:34 +0000
commit6eda64430363955f5873a4ae63da92f9c21f7af3 (patch)
tree39224d2489d9e56aaea594393f2448261736618b
parentfffb2aa12f1c9844a60bd58d43407f8ccfc2dbb0 (diff)
downloadgstreamer-plugins-bad-6eda64430363955f5873a4ae63da92f9c21f7af3.tar.gz
Add device provider for AVFoundation capture devices.
-rw-r--r--sys/applemedia/Makefile.am1
-rw-r--r--sys/applemedia/avfdeviceprovider.h91
-rw-r--r--sys/applemedia/avfdeviceprovider.m216
-rw-r--r--sys/applemedia/avfvideosrc.h3
-rw-r--r--sys/applemedia/avfvideosrc.m229
-rw-r--r--sys/applemedia/meson.build3
-rw-r--r--sys/applemedia/plugin.m3
7 files changed, 443 insertions, 103 deletions
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 <josh@joshmatthews.net>
+ *
+ * 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 <gst/gst.h>
+#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 <josh@joshmatthews.net>
+ *
+ * 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 <AVFoundation/AVFoundation.h>
+#include "avfvideosrc.h"
+#include "avfdeviceprovider.h"
+
+#include <string.h>
+
+#include <gst/gst.h>
+
+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 <josh@joshmatthews.net>");
+}
+
+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 <AVFoundation/AVFoundation.h>
#include <gst/base/gstpushsrc.h>
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);