2 * Copyright (C) 2009 Ole André Vadla Ravnås <oravnas@cisco.com>
3 * 2009 Knut Inge Hvidsten <knuhvids@cisco.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
21 #include "miovideodevice.h"
23 #include <gst/video/video.h>
27 GST_DEBUG_CATEGORY_EXTERN (gst_mio_video_src_debug);
28 #define GST_CAT_DEFAULT gst_mio_video_src_debug
40 G_DEFINE_TYPE (GstMIOVideoDevice, gst_mio_video_device, G_TYPE_OBJECT);
42 typedef struct _GstMIOVideoFormat GstMIOVideoFormat;
43 typedef struct _GstMIOSetFormatCtx GstMIOSetFormatCtx;
44 typedef struct _GstMIOFindRateCtx GstMIOFindRateCtx;
46 struct _GstMIOVideoFormat
48 TundraObjectID stream;
49 CMFormatDescriptionRef desc;
52 CMVideoDimensions dim;
55 struct _GstMIOSetFormatCtx
63 struct _GstMIOFindRateCtx
66 gdouble closest_match;
70 static void gst_mio_video_device_collect_format (GstMIOVideoDevice * self,
71 GstMIOVideoFormat * format, gpointer user_data);
72 static GstStructure *gst_mio_video_device_format_basics_to_structure
73 (GstMIOVideoDevice * self, GstMIOVideoFormat * format);
74 static gboolean gst_mio_video_device_add_framerates_to_structure
75 (GstMIOVideoDevice * self, GstMIOVideoFormat * format, GstStructure * s);
76 static void gst_mio_video_device_add_pixel_aspect_to_structure
77 (GstMIOVideoDevice * self, GstMIOVideoFormat * format, GstStructure * s);
79 static void gst_mio_video_device_append_framerate (GstMIOVideoDevice * self,
80 GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data);
81 static void gst_mio_video_device_framerate_to_fraction_value
82 (TundraFramerate * rate, GValue * fract);
83 static gdouble gst_mio_video_device_round_to_whole_hundreths (gdouble value);
84 static void gst_mio_video_device_guess_pixel_aspect_ratio
85 (gint width, gint height, gint * par_width, gint * par_height);
87 static void gst_mio_video_device_activate_matching_format
88 (GstMIOVideoDevice * self, GstMIOVideoFormat * format, gpointer user_data);
89 static void gst_mio_video_device_find_closest_framerate
90 (GstMIOVideoDevice * self, GstMIOVideoFormat * format,
91 TundraFramerate * rate, gpointer user_data);
93 typedef void (*GstMIOVideoDeviceEachFormatFunc) (GstMIOVideoDevice * self,
94 GstMIOVideoFormat * format, gpointer user_data);
95 typedef void (*GstMIOVideoDeviceEachFramerateFunc) (GstMIOVideoDevice * self,
96 GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data);
97 static void gst_mio_video_device_formats_foreach (GstMIOVideoDevice * self,
98 GstMIOVideoDeviceEachFormatFunc func, gpointer user_data);
99 static void gst_mio_video_device_format_framerates_foreach
100 (GstMIOVideoDevice * self, GstMIOVideoFormat * format,
101 GstMIOVideoDeviceEachFramerateFunc func, gpointer user_data);
103 static gint gst_mio_video_device_compare (GstMIOVideoDevice * a,
104 GstMIOVideoDevice * b);
105 static gint gst_mio_video_device_calculate_score (GstMIOVideoDevice * device);
108 gst_mio_video_device_init (GstMIOVideoDevice * self)
113 gst_mio_video_device_dispose (GObject * object)
115 GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE_CAST (object);
117 if (self->cached_caps != NULL) {
118 gst_caps_unref (self->cached_caps);
119 self->cached_caps = NULL;
122 G_OBJECT_CLASS (gst_mio_video_device_parent_class)->dispose (object);
126 gst_mio_video_device_finalize (GObject * object)
128 GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE_CAST (object);
130 g_free (self->cached_uid);
131 g_free (self->cached_name);
133 G_OBJECT_CLASS (gst_mio_video_device_parent_class)->finalize (object);
137 gst_mio_video_device_get_property (GObject * object, guint prop_id,
138 GValue * value, GParamSpec * pspec)
140 GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE (object);
144 g_value_set_pointer (value, self->ctx);
147 g_value_set_int (value, gst_mio_video_device_get_handle (self));
150 g_value_set_string (value, gst_mio_video_device_get_uid (self));
153 g_value_set_string (value, gst_mio_video_device_get_name (self));
156 g_value_set_uint (value, gst_mio_video_device_get_transport_type (self));
159 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
165 gst_mio_video_device_set_property (GObject * object, guint prop_id,
166 const GValue * value, GParamSpec * pspec)
168 GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE (object);
172 self->ctx = g_value_get_pointer (value);
175 self->handle = g_value_get_int (value);
178 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
184 gst_mio_video_device_get_handle (GstMIOVideoDevice * self)
190 gst_mio_video_device_get_uid (GstMIOVideoDevice * self)
192 if (self->cached_uid == NULL) {
193 TundraTargetSpec pspec = { 0, };
195 pspec.name = kTundraObjectPropertyUID;
196 pspec.scope = kTundraScopeGlobal;
198 gst_mio_object_get_string (self->handle, &pspec, self->ctx->mio);
201 return self->cached_uid;
205 gst_mio_video_device_get_name (GstMIOVideoDevice * self)
207 if (self->cached_name == NULL) {
208 TundraTargetSpec pspec = { 0, };
210 pspec.name = kTundraObjectPropertyName;
211 pspec.scope = kTundraScopeGlobal;
213 gst_mio_object_get_string (self->handle, &pspec, self->ctx->mio);
216 return self->cached_name;
219 TundraDeviceTransportType
220 gst_mio_video_device_get_transport_type (GstMIOVideoDevice * self)
222 if (self->cached_transport == kTundraDeviceTransportInvalid) {
223 TundraTargetSpec pspec = { 0, };
225 pspec.name = kTundraDevicePropertyTransportType;
226 pspec.scope = kTundraScopeGlobal;
227 self->cached_transport =
228 gst_mio_object_get_uint32 (self->handle, &pspec, self->ctx->mio);
231 return self->cached_transport;
235 gst_mio_video_device_open (GstMIOVideoDevice * self)
237 /* nothing for now */
242 gst_mio_video_device_close (GstMIOVideoDevice * self)
244 /* nothing for now */
248 gst_mio_video_device_get_available_caps (GstMIOVideoDevice * self)
250 if (self->cached_caps == NULL) {
253 caps = gst_caps_new_empty ();
254 gst_mio_video_device_formats_foreach (self,
255 gst_mio_video_device_collect_format, caps);
257 self->cached_caps = caps;
260 return self->cached_caps;
264 gst_mio_video_device_collect_format (GstMIOVideoDevice * self,
265 GstMIOVideoFormat * format, gpointer user_data)
267 GstCaps *caps = user_data;
270 s = gst_mio_video_device_format_basics_to_structure (self, format);
272 goto unsupported_format;
274 if (!gst_mio_video_device_add_framerates_to_structure (self, format, s))
277 gst_mio_video_device_add_pixel_aspect_to_structure (self, format, s);
279 gst_caps_append_structure (caps, s);
288 fcc = gst_mio_fourcc_to_string (format->type);
289 GST_WARNING ("skipping unsupported format %s", fcc);
296 GST_WARNING ("no framerates?");
298 gst_structure_free (s);
304 static GstStructure *
305 gst_mio_video_device_format_basics_to_structure (GstMIOVideoDevice * self,
306 GstMIOVideoFormat * format)
310 switch (format->type) {
311 case kCVPixelFormatType_422YpCbCr8:
312 case kCVPixelFormatType_422YpCbCr8Deprecated:
316 if (format->type == kCVPixelFormatType_422YpCbCr8)
317 fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
319 fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
321 s = gst_structure_new ("video/x-raw-yuv",
322 "format", GST_TYPE_FOURCC, fcc,
323 "width", G_TYPE_INT, format->dim.width,
324 "height", G_TYPE_INT, format->dim.height, NULL);
327 case kFigVideoCodecType_JPEG_OpenDML:
329 s = gst_structure_new ("image/jpeg",
330 "width", G_TYPE_INT, format->dim.width,
331 "height", G_TYPE_INT, format->dim.height, NULL);
343 gst_mio_video_device_add_framerates_to_structure (GstMIOVideoDevice * self,
344 GstMIOVideoFormat * format, GstStructure * s)
346 GValue rates = { 0, };
347 const GValue *rates_value;
349 g_value_init (&rates, GST_TYPE_LIST);
351 gst_mio_video_device_format_framerates_foreach (self, format,
352 gst_mio_video_device_append_framerate, &rates);
353 if (gst_value_list_get_size (&rates) == 0)
356 if (gst_value_list_get_size (&rates) > 1)
357 rates_value = &rates;
359 rates_value = gst_value_list_get_value (&rates, 0);
360 gst_structure_set_value (s, "framerate", rates_value);
362 g_value_unset (&rates);
369 g_value_unset (&rates);
375 gst_mio_video_device_add_pixel_aspect_to_structure (GstMIOVideoDevice * self,
376 GstMIOVideoFormat * format, GstStructure * s)
378 gint par_width, par_height;
380 gst_mio_video_device_guess_pixel_aspect_ratio
381 (format->dim.width, format->dim.height, &par_width, &par_height);
383 gst_structure_set (s, "pixel-aspect-ratio",
384 GST_TYPE_FRACTION, par_width, par_height, NULL);
388 gst_mio_video_device_append_framerate (GstMIOVideoDevice * self,
389 GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data)
391 GValue *rates = user_data;
392 GValue value = { 0, };
394 g_value_init (&value, GST_TYPE_FRACTION);
395 gst_mio_video_device_framerate_to_fraction_value (rate, &value);
396 gst_value_list_append_value (rates, &value);
397 g_value_unset (&value);
401 gst_mio_video_device_framerate_to_fraction_value (TundraFramerate * rate,
407 rounded = gst_mio_video_device_round_to_whole_hundreths (rate->value);
408 gst_util_double_to_fraction (rounded, &n, &d);
409 gst_value_set_fraction (fract, n, d);
413 gst_mio_video_device_round_to_whole_hundreths (gdouble value)
419 y = floor ((x / m) + 0.5);
426 gst_mio_video_device_guess_pixel_aspect_ratio (gint width, gint height,
427 gint * par_width, gint * par_height)
430 * As we dont have access to the actual pixel aspect, we will try to do a
431 * best-effort guess. The guess is based on most sensors being either 4/3
432 * or 16/9, and most pixel aspects being close to 1/1.
435 if (width == 768 && height == 448) { /* special case for w448p */
439 if (((gdouble) width / (gdouble) height) < 1.2778) {
450 gst_mio_video_device_set_caps (GstMIOVideoDevice * self, GstCaps * caps)
452 GstVideoFormat format;
453 GstMIOSetFormatCtx ctx = { 0, };
455 if (gst_video_format_parse_caps (caps, &format, &ctx.width, &ctx.height)) {
456 if (format == GST_VIDEO_FORMAT_UYVY)
457 ctx.format = kCVPixelFormatType_422YpCbCr8;
458 else if (format == GST_VIDEO_FORMAT_YUY2)
459 ctx.format = kCVPixelFormatType_422YpCbCr8Deprecated;
461 g_assert_not_reached ();
465 s = gst_caps_get_structure (caps, 0);
466 g_assert (gst_structure_has_name (s, "image/jpeg"));
467 gst_structure_get_int (s, "width", &ctx.width);
468 gst_structure_get_int (s, "height", &ctx.height);
470 ctx.format = kFigVideoCodecType_JPEG_OpenDML;
473 gst_video_parse_caps_framerate (caps, &ctx.fps_n, &ctx.fps_d);
475 gst_mio_video_device_formats_foreach (self,
476 gst_mio_video_device_activate_matching_format, &ctx);
482 gst_mio_video_device_activate_matching_format (GstMIOVideoDevice * self,
483 GstMIOVideoFormat * format, gpointer user_data)
485 GstMIOSetFormatCtx *ctx = user_data;
486 GstMIOFindRateCtx find_ctx;
487 TundraTargetSpec spec = { 0, };
490 if (format->type != ctx->format)
492 else if (format->dim.width != ctx->width)
494 else if (format->dim.height != ctx->height)
497 find_ctx.needle = (gdouble) ctx->fps_n / (gdouble) ctx->fps_d;
498 find_ctx.closest_match = 0.0;
499 find_ctx.success = FALSE;
500 gst_mio_video_device_format_framerates_foreach (self, format,
501 gst_mio_video_device_find_closest_framerate, &find_ctx);
502 if (!find_ctx.success)
503 goto no_matching_framerate_found;
505 spec.scope = kTundraScopeInput;
507 spec.name = kTundraStreamPropertyFormatDescription;
508 status = self->ctx->mio->TundraObjectSetPropertyData (format->stream, &spec,
509 NULL, NULL, sizeof (format->desc), &format->desc);
510 if (status != kTundraSuccess)
511 goto failed_to_set_format;
513 spec.name = kTundraStreamPropertyFrameRate;
514 status = self->ctx->mio->TundraObjectSetPropertyData (format->stream, &spec,
515 NULL, NULL, sizeof (find_ctx.closest_match), &find_ctx.closest_match);
516 if (status != kTundraSuccess)
517 goto failed_to_set_framerate;
519 self->selected_format = format->desc;
520 self->selected_fps_n = ctx->fps_n;
521 self->selected_fps_d = ctx->fps_d;
527 no_matching_framerate_found:
529 GST_ERROR ("no matching framerate found");
532 failed_to_set_format:
534 GST_ERROR ("failed to set format: 0x%08x", status);
537 failed_to_set_framerate:
539 GST_ERROR ("failed to set framerate: 0x%08x", status);
545 gst_mio_video_device_find_closest_framerate (GstMIOVideoDevice * self,
546 GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data)
548 GstMIOFindRateCtx *ctx = user_data;
550 if (fabs (rate->value - ctx->needle) <= 0.1) {
551 ctx->closest_match = rate->value;
556 CMFormatDescriptionRef
557 gst_mio_video_device_get_selected_format (GstMIOVideoDevice * self)
559 return self->selected_format;
563 gst_mio_video_device_get_duration (GstMIOVideoDevice * self)
565 return gst_util_uint64_scale_int (GST_SECOND,
566 self->selected_fps_d, self->selected_fps_n);
570 gst_mio_video_device_formats_foreach (GstMIOVideoDevice * self,
571 GstMIOVideoDeviceEachFormatFunc func, gpointer user_data)
573 GstCMApi *cm = self->ctx->cm;
574 GstMIOApi *mio = self->ctx->mio;
575 TundraTargetSpec spec = { 0, };
579 spec.name = kTundraDevicePropertyStreams;
580 spec.scope = kTundraScopeInput;
581 streams = gst_mio_object_get_array (self->handle, &spec,
582 sizeof (TundraObjectID), mio);
584 /* TODO: We only consider the first stream for now */
585 for (stream_idx = 0; stream_idx != MIN (streams->len, 1); stream_idx++) {
586 TundraObjectID stream;
588 CFIndex num_formats, fmt_idx;
590 stream = g_array_index (streams, TundraObjectID, stream_idx);
592 spec.name = kTundraStreamPropertyFormatDescriptions;
593 spec.scope = kTundraScopeInput;
595 formats = gst_mio_object_get_pointer (stream, &spec, mio);
596 num_formats = CFArrayGetCount (formats);
598 for (fmt_idx = 0; fmt_idx != num_formats; fmt_idx++) {
599 GstMIOVideoFormat fmt;
602 fmt.desc = (CMFormatDescriptionRef)
603 CFArrayGetValueAtIndex (formats, fmt_idx);
604 if (cm->CMFormatDescriptionGetMediaType (fmt.desc) != kFigMediaTypeVideo)
606 fmt.type = cm->CMFormatDescriptionGetMediaSubType (fmt.desc);
607 fmt.dim = cm->CMVideoFormatDescriptionGetDimensions (fmt.desc);
609 func (self, &fmt, user_data);
613 g_array_free (streams, TRUE);
617 gst_mio_video_device_format_framerates_foreach (GstMIOVideoDevice * self,
618 GstMIOVideoFormat * format, GstMIOVideoDeviceEachFramerateFunc func,
621 TundraTargetSpec spec = { 0, };
625 spec.name = kTundraStreamPropertyFrameRates;
626 spec.scope = kTundraScopeInput;
627 rates = gst_mio_object_get_array_full (format->stream, &spec,
628 sizeof (format->desc), &format->desc, sizeof (TundraFramerate),
631 for (rate_idx = 0; rate_idx != rates->len; rate_idx++) {
632 TundraFramerate *rate;
634 rate = &g_array_index (rates, TundraFramerate, rate_idx);
636 func (self, format, rate, user_data);
639 g_array_free (rates, TRUE);
643 gst_mio_video_device_print_debug_info (GstMIOVideoDevice * self)
645 GstCMApi *cm = self->ctx->cm;
646 GstMIOApi *mio = self->ctx->mio;
647 TundraTargetSpec spec = { 0, };
652 g_print ("Device %p with handle %d\n", self, self->handle);
654 spec.scope = kTundraScopeGlobal;
656 spec.name = kTundraObjectPropertyClass;
657 str = gst_mio_object_get_fourcc (self->handle, &spec, mio);
658 g_print (" Class: '%s'\n", str);
661 spec.name = kTundraObjectPropertyCreator;
662 str = gst_mio_object_get_string (self->handle, &spec, mio);
663 g_print (" Creator: \"%s\"\n", str);
666 spec.name = kTundraDevicePropertyModelUID;
667 str = gst_mio_object_get_string (self->handle, &spec, mio);
668 g_print (" Model UID: \"%s\"\n", str);
671 spec.name = kTundraDevicePropertyTransportType;
672 str = gst_mio_object_get_fourcc (self->handle, &spec, mio);
673 g_print (" Transport Type: '%s'\n", str);
676 g_print (" Streams:\n");
677 spec.name = kTundraDevicePropertyStreams;
678 spec.scope = kTundraScopeInput;
679 streams = gst_mio_object_get_array (self->handle, &spec,
680 sizeof (TundraObjectID), mio);
681 for (stream_idx = 0; stream_idx != streams->len; stream_idx++) {
682 TundraObjectID stream;
684 CFIndex num_formats, fmt_idx;
686 stream = g_array_index (streams, TundraObjectID, stream_idx);
688 g_print (" stream[%u] = %d\n", stream_idx, stream);
690 spec.scope = kTundraScopeInput;
691 spec.name = kTundraStreamPropertyFormatDescriptions;
693 formats = gst_mio_object_get_pointer (stream, &spec, mio);
694 num_formats = CFArrayGetCount (formats);
696 g_print (" <%u formats>\n", (guint) num_formats);
698 for (fmt_idx = 0; fmt_idx != num_formats; fmt_idx++) {
699 CMFormatDescriptionRef fmt;
701 gchar *media_sub_type;
702 CMVideoDimensions dim;
706 fmt = CFArrayGetValueAtIndex (formats, fmt_idx);
707 media_type = gst_mio_fourcc_to_string
708 (cm->CMFormatDescriptionGetMediaType (fmt));
709 media_sub_type = gst_mio_fourcc_to_string
710 (cm->CMFormatDescriptionGetMediaSubType (fmt));
711 dim = cm->CMVideoFormatDescriptionGetDimensions (fmt);
713 g_print (" format[%u]: MediaType='%s' MediaSubType='%s' %ux%u\n",
714 (guint) fmt_idx, media_type, media_sub_type,
715 (guint) dim.width, (guint) dim.height);
717 spec.name = kTundraStreamPropertyFrameRates;
718 rates = gst_mio_object_get_array_full (stream, &spec, sizeof (fmt), &fmt,
719 sizeof (TundraFramerate), mio);
720 for (rate_idx = 0; rate_idx != rates->len; rate_idx++) {
721 TundraFramerate *rate;
723 rate = &g_array_index (rates, TundraFramerate, rate_idx);
724 g_print (" %f\n", rate->value);
726 g_array_free (rates, TRUE);
728 g_free (media_sub_type);
733 g_array_free (streams, TRUE);
737 gst_mio_video_device_class_init (GstMIOVideoDeviceClass * klass)
739 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
741 gobject_class->dispose = gst_mio_video_device_dispose;
742 gobject_class->finalize = gst_mio_video_device_finalize;
743 gobject_class->get_property = gst_mio_video_device_get_property;
744 gobject_class->set_property = gst_mio_video_device_set_property;
746 g_object_class_install_property (gobject_class, PROP_CONTEXT,
747 g_param_spec_pointer ("context", "CoreMedia Context",
748 "CoreMedia context to use",
749 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
750 g_object_class_install_property (gobject_class, PROP_HANDLE,
751 g_param_spec_int ("handle", "Handle",
752 "MIO handle of this video capture device",
753 G_MININT, G_MAXINT, -1,
754 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
755 g_object_class_install_property (gobject_class, PROP_UID,
756 g_param_spec_string ("uid", "Unique ID",
757 "Unique ID of this video capture device", NULL,
758 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
759 g_object_class_install_property (gobject_class, PROP_NAME,
760 g_param_spec_string ("name", "Device Name",
761 "Name of this video capture device", NULL,
762 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
763 g_object_class_install_property (gobject_class, PROP_TRANSPORT,
764 g_param_spec_uint ("transport", "Transport",
765 "Transport type of this video capture device",
766 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
770 gst_mio_video_device_list_create (GstCoreMediaCtx * ctx)
772 GList *devices = NULL;
773 TundraTargetSpec pspec = { 0, };
777 pspec.name = kTundraSystemPropertyDevices;
778 pspec.scope = kTundraScopeGlobal;
779 handles = gst_mio_object_get_array (TUNDRA_SYSTEM_OBJECT_ID, &pspec,
780 sizeof (TundraObjectID), ctx->mio);
784 for (handle_idx = 0; handle_idx != handles->len; handle_idx++) {
785 TundraObjectID handle;
786 GstMIOVideoDevice *device;
788 handle = g_array_index (handles, TundraObjectID, handle_idx);
789 device = g_object_new (GST_TYPE_MIO_VIDEO_DEVICE,
790 "context", ctx, "handle", handle, NULL);
792 /* TODO: Skip screen input devices for now */
793 if (gst_mio_video_device_get_transport_type (device) !=
794 kTundraDeviceTransportScreen) {
795 devices = g_list_prepend (devices, device);
797 g_object_unref (device);
801 devices = g_list_sort (devices, (GCompareFunc) gst_mio_video_device_compare);
803 g_array_free (handles, TRUE);
810 gst_mio_video_device_list_destroy (GList * devices)
812 g_list_foreach (devices, (GFunc) g_object_unref, NULL);
813 g_list_free (devices);
817 gst_mio_video_device_compare (GstMIOVideoDevice * a, GstMIOVideoDevice * b)
819 gint score_a, score_b;
821 score_a = gst_mio_video_device_calculate_score (a);
822 score_b = gst_mio_video_device_calculate_score (b);
824 if (score_a > score_b)
826 else if (score_a < score_b)
829 return g_ascii_strcasecmp (gst_mio_video_device_get_name (a),
830 gst_mio_video_device_get_name (b));
834 gst_mio_video_device_calculate_score (GstMIOVideoDevice * device)
836 switch (gst_mio_video_device_get_transport_type (device)) {
837 case kTundraDeviceTransportScreen:
839 case kTundraDeviceTransportBuiltin:
841 case kTundraDeviceTransportUSB: