diff options
Diffstat (limited to 'sys/applemedia/avfvideosrc.m')
-rw-r--r-- | sys/applemedia/avfvideosrc.m | 205 |
1 files changed, 191 insertions, 14 deletions
diff --git a/sys/applemedia/avfvideosrc.m b/sys/applemedia/avfvideosrc.m index 97f4715b0..a362f6a8e 100644 --- a/sys/applemedia/avfvideosrc.m +++ b/sys/applemedia/avfvideosrc.m @@ -35,6 +35,9 @@ #include "videotexturecache.h" #define DEFAULT_DEVICE_INDEX -1 +#define DEFAULT_POSITION GST_AVF_VIDEO_SOURCE_POSITION_DEFAULT +#define DEFAULT_ORIENTATION GST_AVF_VIDEO_SOURCE_ORIENTATION_DEFAULT +#define DEFAULT_DEVICE_TYPE GST_AVF_VIDEO_SOURCE_DEVICE_TYPE_DEFAULT #define DEFAULT_DO_STATS FALSE #define DEVICE_FPS_N 25 @@ -81,12 +84,84 @@ typedef enum _QueueState { #define gst_avf_video_src_parent_class parent_class G_DEFINE_TYPE (GstAVFVideoSrc, gst_avf_video_src, GST_TYPE_PUSH_SRC); +#define GST_TYPE_AVF_VIDEO_SOURCE_POSITION (gst_avf_video_source_position_get_type ()) +static GType +gst_avf_video_source_position_get_type (void) +{ + static GType avf_video_source_position_type = 0; + + if (!avf_video_source_position_type) { + static GEnumValue position_types[] = { + { GST_AVF_VIDEO_SOURCE_POSITION_FRONT, "Front-facing camera", "front" }, + { GST_AVF_VIDEO_SOURCE_POSITION_BACK, "Back-facing camera", "back" }, + { GST_AVF_VIDEO_SOURCE_POSITION_DEFAULT, "Default", "default" }, + { 0, NULL, NULL }, + }; + + avf_video_source_position_type = + g_enum_register_static ("GstAVFVideoSourcePosition", + position_types); + } + + return avf_video_source_position_type; +} + +#define GST_TYPE_AVF_VIDEO_SOURCE_ORIENTATION (gst_avf_video_source_orientation_get_type ()) +static GType +gst_avf_video_source_orientation_get_type (void) +{ + static GType avf_video_source_orientation_type = 0; + + if (!avf_video_source_orientation_type) { + static GEnumValue orientation_types[] = { + { GST_AVF_VIDEO_SOURCE_ORIENTATION_PORTRAIT, "Indicates that video should be oriented vertically, top at the top.", "portrait" }, + { GST_AVF_VIDEO_SOURCE_ORIENTATION_PORTRAIT_UPSIDE_DOWN, "Indicates that video should be oriented vertically, top at the bottom.", "portrat-upside-down" }, + { GST_AVF_VIDEO_SOURCE_ORIENTATION_LANDSCAPE_RIGHT, "Indicates that video should be oriented horizontally, top on the left.", "landscape-right" }, + { GST_AVF_VIDEO_SOURCE_ORIENTATION_LANDSCAPE_LEFT, "Indicates that video should be oriented horizontally, top on the right.", "landscape-left" }, + { GST_AVF_VIDEO_SOURCE_ORIENTATION_DEFAULT, "Default", "default" }, + { 0, NULL, NULL }, + }; + + avf_video_source_orientation_type = + g_enum_register_static ("GstAVFVideoSourceOrientation", + orientation_types); + } + + return avf_video_source_orientation_type; +} + +#define GST_TYPE_AVF_VIDEO_SOURCE_DEVICE_TYPE (gst_avf_video_source_device_type_get_type ()) +static GType +gst_avf_video_source_device_type_get_type (void) +{ + static GType avf_video_source_device_type_type = 0; + + if (!avf_video_source_device_type_type) { + static GEnumValue device_type_types[] = { + { GST_AVF_VIDEO_SOURCE_DEVICE_TYPE_BUILT_IN_WIDE_ANGLE_CAMERA, "A built-in wide angle camera. These devices are suitable for general purpose use.", "wide-angle" }, + { GST_AVF_VIDEO_SOURCE_DEVICE_TYPE_BUILT_IN_TELEPHOTO_CAMERA, "A built-in camera device with a longer focal length than a wide-angle camera.", "telephoto" }, + { GST_AVF_VIDEO_SOURCE_DEVICE_TYPE_BUILT_IN_DUAL_CAMERA, "A dual camera device, combining built-in wide-angle and telephoto cameras that work together as a single capture device.", "dual" }, + { GST_AVF_VIDEO_SOURCE_DEVICE_TYPE_DEFAULT, "Default", "default" }, + { 0, NULL, NULL }, + }; + + avf_video_source_device_type_type = + g_enum_register_static ("GstAVFVideoSourceDeviceType", + device_type_types); + } + + return avf_video_source_device_type_type; +} + @interface GstAVFVideoSrcImpl : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate> { GstElement *element; GstBaseSrc *baseSrc; GstPushSrc *pushSrc; gint deviceIndex; + GstAVFVideoSourcePosition position; + GstAVFVideoSourceOrientation orientation; + GstAVFVideoSourceDeviceType deviceType; BOOL doStats; AVCaptureSession *session; @@ -125,6 +200,9 @@ G_DEFINE_TYPE (GstAVFVideoSrc, gst_avf_video_src, GST_TYPE_PUSH_SRC); - (void)finalize; @property int deviceIndex; +@property GstAVFVideoSourcePosition position; +@property GstAVFVideoSourceOrientation orientation; +@property GstAVFVideoSourceDeviceType deviceType; @property BOOL doStats; @property int fps; @property BOOL captureScreen; @@ -163,10 +241,50 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer @end +static AVCaptureDeviceType GstAVFVideoSourceDeviceType2AVCaptureDeviceType(GstAVFVideoSourceDeviceType deviceType) { + switch (deviceType) { + case GST_AVF_VIDEO_SOURCE_DEVICE_TYPE_BUILT_IN_WIDE_ANGLE_CAMERA: + return AVCaptureDeviceTypeBuiltInWideAngleCamera; + case GST_AVF_VIDEO_SOURCE_DEVICE_TYPE_BUILT_IN_TELEPHOTO_CAMERA: + return AVCaptureDeviceTypeBuiltInTelephotoCamera; + case GST_AVF_VIDEO_SOURCE_DEVICE_TYPE_BUILT_IN_DUAL_CAMERA: + return AVCaptureDeviceTypeBuiltInDualCamera; + case GST_AVF_VIDEO_SOURCE_DEVICE_TYPE_DEFAULT: + g_assert_not_reached(); + } +} + +static AVCaptureDevicePosition GstAVFVideoSourcePosition2AVCaptureDevicePosition(GstAVFVideoSourcePosition position) { + switch (position) { + case GST_AVF_VIDEO_SOURCE_POSITION_FRONT: + return AVCaptureDevicePositionFront; + case GST_AVF_VIDEO_SOURCE_POSITION_BACK: + return AVCaptureDevicePositionBack; + case GST_AVF_VIDEO_SOURCE_POSITION_DEFAULT: + g_assert_not_reached(); + } + +} + +static AVCaptureVideoOrientation GstAVFVideoSourceOrientation2AVCaptureVideoOrientation(GstAVFVideoSourceOrientation orientation) { + switch (orientation) { + case GST_AVF_VIDEO_SOURCE_ORIENTATION_PORTRAIT: + return AVCaptureVideoOrientationPortrait; + case GST_AVF_VIDEO_SOURCE_ORIENTATION_PORTRAIT_UPSIDE_DOWN: + return AVCaptureVideoOrientationPortraitUpsideDown; + case GST_AVF_VIDEO_SOURCE_ORIENTATION_LANDSCAPE_LEFT: + return AVCaptureVideoOrientationLandscapeLeft; + case GST_AVF_VIDEO_SOURCE_ORIENTATION_LANDSCAPE_RIGHT: + return AVCaptureVideoOrientationLandscapeRight; + case GST_AVF_VIDEO_SOURCE_ORIENTATION_DEFAULT: + g_assert_not_reached(); + } +} + @implementation GstAVFVideoSrcImpl -@synthesize deviceIndex, doStats, fps, captureScreen, - captureScreenCursor, captureScreenMouseClicks; +@synthesize deviceIndex, position, orientation, deviceType, doStats, + fps, captureScreen, captureScreenCursor, captureScreenMouseClicks; - (id)init { @@ -181,6 +299,9 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer pushSrc = src; deviceIndex = DEFAULT_DEVICE_INDEX; + position = DEFAULT_POSITION; + orientation = DEFAULT_ORIENTATION; + deviceType = DEFAULT_DEVICE_TYPE; captureScreen = NO; captureScreenCursor = NO; captureScreenMouseClicks = NO; @@ -211,13 +332,20 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer NSError *err; if (deviceIndex == DEFAULT_DEVICE_INDEX) { - device = [AVCaptureDevice defaultDeviceWithMediaType:mediaType]; + if (deviceType != DEFAULT_DEVICE_TYPE && position != DEFAULT_POSITION) { + device = [AVCaptureDevice + defaultDeviceWithDeviceType:GstAVFVideoSourceDeviceType2AVCaptureDeviceType(deviceType) + mediaType:mediaType + position:GstAVFVideoSourcePosition2AVCaptureDevicePosition(position)]; + } else { + device = [AVCaptureDevice defaultDeviceWithMediaType:mediaType]; + } if (device == nil) { GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, ("No video capture devices found"), (NULL)); return NO; } - } else { + } else { // deviceIndex takes priority over position and deviceType NSArray *devices = [AVCaptureDevice devicesWithMediaType:mediaType]; if (deviceIndex >= [devices count]) { GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, @@ -306,6 +434,8 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer /* retained by session */ connection = [[output connections] firstObject]; + if (orientation != DEFAULT_ORIENTATION) + connection.videoOrientation = GstAVFVideoSourceOrientation2AVCaptureVideoOrientation(orientation); inputClock = ((AVCaptureInputPort *)connection.inputPorts[0]).clock; *successPtr = YES; @@ -421,6 +551,20 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer } #endif + +- (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; +} + - (GstCaps *)getDeviceCaps { NSArray *formats = [device valueForKey:@"formats"]; @@ -441,12 +585,11 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer * available in iOS >= 7.0. We use a dynamic approach with key-value * coding or performSelector */ for (NSObject *f in [formats reverseObjectEnumerator]) { - CMFormatDescriptionRef formatDescription; - CMVideoDimensions dimensions; - /* formatDescription can't be retrieved with valueForKey so use a selector here */ - formatDescription = (__bridge CMFormatDescriptionRef) [f performSelector:@selector(formatDescription)]; - dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription); + 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; @@ -514,11 +657,9 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer if ([device lockForConfiguration:NULL] == YES) { for (NSObject *f in formats) { - CMFormatDescriptionRef formatDescription; - CMVideoDimensions dimensions; - - formatDescription = (__bridge CMFormatDescriptionRef) [f performSelector:@selector(formatDescription)]; - dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription); + CMFormatDescriptionRef formatDescription = (__bridge CMFormatDescriptionRef) [f performSelector:@selector(formatDescription)]; + CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription); + dimensions = [self orientedDimensions:dimensions]; if (dimensions.width == info->width && dimensions.height == info->height) { found_format = TRUE; [device setValue:f forKey:@"activeFormat"]; @@ -1108,6 +1249,9 @@ enum { PROP_0, PROP_DEVICE_INDEX, + PROP_POSITION, + PROP_ORIENTATION, + PROP_DEVICE_TYPE, PROP_DO_STATS, PROP_FPS, #if !HAVE_IOS @@ -1183,6 +1327,21 @@ gst_avf_video_src_class_init (GstAVFVideoSrcClass * klass) "The zero-based device index", -1, G_MAXINT, DEFAULT_DEVICE_INDEX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_POSITION, + g_param_spec_enum ("position", "Position", + "The position of the capture device (front or back-facing)", + GST_TYPE_AVF_VIDEO_SOURCE_POSITION, DEFAULT_POSITION, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ORIENTATION, + g_param_spec_enum ("orientation", "Orientation", + "The orientation of the video", + GST_TYPE_AVF_VIDEO_SOURCE_ORIENTATION, DEFAULT_ORIENTATION, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DEVICE_TYPE, + g_param_spec_enum ("device-type", "Device Type", + "The general type of a video capture device", + GST_TYPE_AVF_VIDEO_SOURCE_DEVICE_TYPE, DEFAULT_DEVICE_TYPE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_DO_STATS, g_param_spec_boolean ("do-stats", "Enable statistics", "Enable logging of statistics", DEFAULT_DO_STATS, @@ -1245,6 +1404,15 @@ gst_avf_video_src_get_property (GObject * object, guint prop_id, GValue * value, case PROP_DEVICE_INDEX: g_value_set_int (value, impl.deviceIndex); break; + case PROP_POSITION: + g_value_set_enum(value, impl.position); + break; + case PROP_ORIENTATION: + g_value_set_enum(value, impl.orientation); + break; + case PROP_DEVICE_TYPE: + g_value_set_enum(value, impl.deviceType); + break; case PROP_DO_STATS: g_value_set_boolean (value, impl.doStats); break; @@ -1280,6 +1448,15 @@ gst_avf_video_src_set_property (GObject * object, guint prop_id, case PROP_DEVICE_INDEX: impl.deviceIndex = g_value_get_int (value); break; + case PROP_POSITION: + impl.position = g_value_get_enum(value); + break; + case PROP_ORIENTATION: + impl.orientation = g_value_get_enum(value); + break; + case PROP_DEVICE_TYPE: + impl.deviceType = g_value_get_enum(value); + break; case PROP_DO_STATS: impl.doStats = g_value_get_boolean (value); break; |