static void
gst_mio_video_device_formats_foreach (GstMIOVideoDevice * self,
    GstMIOVideoDeviceEachFormatFunc func, gpointer user_data)
{
  GstCMApi *cm = self->ctx->cm;
  GstMIOApi *mio = self->ctx->mio;
  TundraTargetSpec spec = { 0, };
  GArray *streams;
  guint stream_idx;

  spec.name = kTundraDevicePropertyStreams;
  spec.scope = kTundraScopeInput;
  streams = gst_mio_object_get_array (self->handle, &spec,
      sizeof (TundraObjectID), mio);

  /* TODO: We only consider the first stream for now */
  for (stream_idx = 0; stream_idx != MIN (streams->len, 1); stream_idx++) {
    TundraObjectID stream;
    CFArrayRef formats;
    CFIndex num_formats, fmt_idx;

    stream = g_array_index (streams, TundraObjectID, stream_idx);

    spec.name = kTundraStreamPropertyFormatDescriptions;
    spec.scope = kTundraScopeInput;

    formats = gst_mio_object_get_pointer (stream, &spec, mio);
    num_formats = CFArrayGetCount (formats);

    for (fmt_idx = 0; fmt_idx != num_formats; fmt_idx++) {
      GstMIOVideoFormat fmt;

      fmt.stream = stream;
      fmt.desc = (CMFormatDescriptionRef)
          CFArrayGetValueAtIndex (formats, fmt_idx);
      if (cm->CMFormatDescriptionGetMediaType (fmt.desc) != kFigMediaTypeVideo)
        continue;
      fmt.type = cm->CMFormatDescriptionGetMediaSubType (fmt.desc);
      fmt.dim = cm->CMVideoFormatDescriptionGetDimensions (fmt.desc);

      func (self, &fmt, user_data);
    }
  }

  g_array_free (streams, TRUE);
}
void
gst_mio_video_device_print_debug_info (GstMIOVideoDevice * self)
{
  GstCMApi *cm = self->ctx->cm;
  GstMIOApi *mio = self->ctx->mio;
  TundraTargetSpec spec = { 0, };
  gchar *str;
  GArray *streams;
  guint stream_idx;

  g_print ("Device %p with handle %d\n", self, self->handle);

  spec.scope = kTundraScopeGlobal;

  spec.name = kTundraObjectPropertyClass;
  str = gst_mio_object_get_fourcc (self->handle, &spec, mio);
  g_print ("  Class: '%s'\n", str);
  g_free (str);

  spec.name = kTundraObjectPropertyCreator;
  str = gst_mio_object_get_string (self->handle, &spec, mio);
  g_print ("  Creator: \"%s\"\n", str);
  g_free (str);

  spec.name = kTundraDevicePropertyModelUID;
  str = gst_mio_object_get_string (self->handle, &spec, mio);
  g_print ("  Model UID: \"%s\"\n", str);
  g_free (str);

  spec.name = kTundraDevicePropertyTransportType;
  str = gst_mio_object_get_fourcc (self->handle, &spec, mio);
  g_print ("  Transport Type: '%s'\n", str);
  g_free (str);

  g_print ("  Streams:\n");
  spec.name = kTundraDevicePropertyStreams;
  spec.scope = kTundraScopeInput;
  streams = gst_mio_object_get_array (self->handle, &spec,
      sizeof (TundraObjectID), mio);
  for (stream_idx = 0; stream_idx != streams->len; stream_idx++) {
    TundraObjectID stream;
    CFArrayRef formats;
    CFIndex num_formats, fmt_idx;

    stream = g_array_index (streams, TundraObjectID, stream_idx);

    g_print ("    stream[%u] = %d\n", stream_idx, stream);

    spec.scope = kTundraScopeInput;
    spec.name = kTundraStreamPropertyFormatDescriptions;

    formats = gst_mio_object_get_pointer (stream, &spec, mio);
    num_formats = CFArrayGetCount (formats);

    g_print ("      <%u formats>\n", (guint) num_formats);

    for (fmt_idx = 0; fmt_idx != num_formats; fmt_idx++) {
      CMFormatDescriptionRef fmt;
      gchar *media_type;
      gchar *media_sub_type;
      CMVideoDimensions dim;
      GArray *rates;
      guint rate_idx;

      fmt = CFArrayGetValueAtIndex (formats, fmt_idx);
      media_type = gst_mio_fourcc_to_string
          (cm->CMFormatDescriptionGetMediaType (fmt));
      media_sub_type = gst_mio_fourcc_to_string
          (cm->CMFormatDescriptionGetMediaSubType (fmt));
      dim = cm->CMVideoFormatDescriptionGetDimensions (fmt);

      g_print ("      format[%u]: MediaType='%s' MediaSubType='%s' %ux%u\n",
          (guint) fmt_idx, media_type, media_sub_type,
          (guint) dim.width, (guint) dim.height);

      spec.name = kTundraStreamPropertyFrameRates;
      rates = gst_mio_object_get_array_full (stream, &spec, sizeof (fmt), &fmt,
          sizeof (TundraFramerate), mio);
      for (rate_idx = 0; rate_idx != rates->len; rate_idx++) {
        TundraFramerate *rate;

        rate = &g_array_index (rates, TundraFramerate, rate_idx);
        g_print ("        %f\n", rate->value);
      }
      g_array_free (rates, TRUE);

      g_free (media_sub_type);
      g_free (media_type);
    }
  }

  g_array_free (streams, TRUE);
}