Beispiel #1
0
static gboolean
gst_ks_video_src_open_device (GstKsVideoSrc * self)
{
  GstKsVideoSrcPrivate *priv = GST_KS_VIDEO_SRC_GET_PRIVATE (self);
  GstKsVideoDevice *device = NULL;
  GList *devices, *cur;

  g_assert (priv->device == NULL);

  devices = ks_enumerate_devices (&KSCATEGORY_VIDEO);
  if (devices == NULL)
    goto error_no_devices;

  devices = ks_video_device_list_sort_cameras_first (devices);

  for (cur = devices; cur != NULL; cur = cur->next) {
    KsDeviceEntry *entry = cur->data;

    GST_DEBUG_OBJECT (self, "device %d: name='%s' path='%s'",
        entry->index, entry->name, entry->path);
  }

  for (cur = devices; cur != NULL && device == NULL; cur = cur->next) {
    KsDeviceEntry *entry = cur->data;
    gboolean match;

    if (priv->device_path != NULL) {
      match = g_strcasecmp (entry->path, priv->device_path) == 0;
    } else if (priv->device_name != NULL) {
      match = g_strcasecmp (entry->name, priv->device_name) == 0;
    } else if (priv->device_index >= 0) {
      match = entry->index == priv->device_index;
    } else {
      match = TRUE;             /* pick the first entry */
    }

    if (match) {
      priv->ksclock = g_object_new (GST_TYPE_KS_CLOCK, NULL);
      if (priv->ksclock != NULL && gst_ks_clock_open (priv->ksclock)) {
        GstClock *clock = GST_ELEMENT_CLOCK (self);
        if (clock != NULL)
          gst_ks_clock_provide_master_clock (priv->ksclock, clock);
      } else {
        GST_WARNING_OBJECT (self, "failed to create/open KsClock");
        g_object_unref (priv->ksclock);
        priv->ksclock = NULL;
      }

      device = gst_ks_video_device_new (entry->path, priv->ksclock,
          gst_ks_video_src_alloc_buffer, self);
    }

    ks_device_entry_free (entry);
  }

  g_list_free (devices);

  if (device == NULL)
    goto error_no_match;

  if (!gst_ks_video_device_open (device))
    goto error_open;

  priv->device = device;

  return TRUE;

  /* ERRORS */
error_no_devices:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
        ("No video capture devices found"), (NULL));
    return FALSE;
  }
error_no_match:
  {
    if (priv->device_path != NULL) {
      GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
          ("Specified video capture device with path '%s' not found",
              priv->device_path), (NULL));
    } else if (priv->device_name != NULL) {
      GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
          ("Specified video capture device with name '%s' not found",
              priv->device_name), (NULL));
    } else {
      GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
          ("Specified video capture device with index %d not found",
              priv->device_index), (NULL));
    }
    return FALSE;
  }
error_open:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ,
        ("Failed to open device"), (NULL));
    g_object_unref (device);
    return FALSE;
  }
}
Beispiel #2
0
static gboolean
gst_ks_video_src_timestamp_buffer (GstKsVideoSrc * self, GstBuffer * buf,
                                   GstClockTime presentation_time)
{
    GstKsVideoSrcPrivate *priv = GST_KS_VIDEO_SRC_GET_PRIVATE (self);
    GstClockTime duration;
    GstClock *clock;
    GstClockTime timestamp;

    /* Don't timestamp muxed streams */
    if (gst_ks_video_device_stream_is_muxed (priv->device)) {
        duration = timestamp = GST_CLOCK_TIME_NONE;
        priv->offset++;
        goto timestamp;
    }

    duration = gst_ks_video_device_get_duration (priv->device);

    GST_OBJECT_LOCK (self);
    clock = GST_ELEMENT_CLOCK (self);
    if (clock != NULL) {
        gst_object_ref (clock);
        timestamp = GST_ELEMENT (self)->base_time;

        if (GST_CLOCK_TIME_IS_VALID (presentation_time)) {
            if (presentation_time > GST_ELEMENT (self)->base_time)
                presentation_time -= GST_ELEMENT (self)->base_time;
            else
                presentation_time = 0;
        }
    } else {
        timestamp = GST_CLOCK_TIME_NONE;
    }
    GST_OBJECT_UNLOCK (self);

    if (clock != NULL) {

        /* The time according to the current clock */
        timestamp = gst_clock_get_time (clock) - timestamp;
        if (timestamp > duration)
            timestamp -= duration;
        else
            timestamp = 0;

        if (GST_CLOCK_TIME_IS_VALID (presentation_time)) {
            /*
             * We don't use this for anything yet, need to ponder how to deal
             * with pins that use an internal clock and timestamp from 0.
             */
            GstClockTimeDiff diff = GST_CLOCK_DIFF (presentation_time, timestamp);
            GST_DEBUG_OBJECT (self, "diff between gst and driver timestamp: %"
                              G_GINT64_FORMAT, diff);
        }

        gst_object_unref (clock);
        clock = NULL;

        /* Unless it's the first frame, align the current timestamp on a multiple
         * of duration since the previous */
        if (GST_CLOCK_TIME_IS_VALID (priv->prev_ts)) {
            GstClockTime delta;
            guint delta_remainder, delta_offset;

            /* REVISIT: I've seen this happen with the GstSystemClock on Windows,
             *          scary... */
            if (timestamp < priv->prev_ts) {
                GST_INFO_OBJECT (self, "clock is ticking backwards");
                return FALSE;
            }

            /* Round to a duration boundary */
            delta = timestamp - priv->prev_ts;
            delta_remainder = delta % duration;

            if (delta_remainder < duration / 3)
                timestamp -= delta_remainder;
            else
                timestamp += duration - delta_remainder;

            /* How many frames are we off then? */
            delta = timestamp - priv->prev_ts;
            delta_offset = delta / duration;

            if (delta_offset == 1)    /* perfect */
                GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
            else if (delta_offset > 1) {
                guint lost = delta_offset - 1;
                GST_INFO_OBJECT (self, "lost %d frame%s, setting discont flag",
                                 lost, (lost > 1) ? "s" : "");
                GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
            } else if (delta_offset == 0) {   /* overproduction, skip this frame */
                GST_INFO_OBJECT (self, "skipping frame");
                return FALSE;
            }

            priv->offset += delta_offset;
        }

        priv->prev_ts = timestamp;
    }

timestamp:
    GST_BUFFER_OFFSET (buf) = priv->offset;
    GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET (buf) + 1;
    GST_BUFFER_PTS (buf) = timestamp;
    GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
    GST_BUFFER_DURATION (buf) = duration;

    return TRUE;
}
Beispiel #3
0
static GstFlowReturn
gst_ks_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf)
{
    GstKsVideoSrc *self = GST_KS_VIDEO_SRC (pushsrc);
    GstKsVideoSrcPrivate *priv = GST_KS_VIDEO_SRC_GET_PRIVATE (self);
    GstFlowReturn result;
    GstClockTime presentation_time;
    gulong error_code;
    gchar *error_str;

    g_assert (priv->device != NULL);

    if (!gst_ks_video_device_has_caps (priv->device))
        goto error_no_caps;

    if (G_UNLIKELY (!priv->running)) {
        KS_WORKER_LOCK (priv);
        priv->worker_pending_run = TRUE;
        KS_WORKER_NOTIFY (priv);
        while (priv->worker_pending_run)
            KS_WORKER_WAIT_FOR_RESULT (priv);
        priv->running = priv->worker_run_result;
        error_code = priv->worker_error_code;
        KS_WORKER_UNLOCK (priv);

        if (!priv->running)
            goto error_start_capture;
    }

    do {
        if (*buf != NULL) {
            gst_buffer_unref (*buf);
            *buf = NULL;
        }

        result = gst_ks_video_device_read_frame (priv->device, buf,
                 &presentation_time, &error_code, &error_str);
        if (G_UNLIKELY (result != GST_FLOW_OK))
            goto error_read_frame;
    }
    while (!gst_ks_video_src_timestamp_buffer (self, *buf, presentation_time));

    if (G_UNLIKELY (priv->do_stats))
        gst_ks_video_src_update_statistics (self);

    if (!gst_ks_video_device_postprocess_frame (priv->device, *buf)) {
        GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("Postprocessing failed"),
                           ("Postprocessing failed"));
        return GST_FLOW_ERROR;
    }

    return GST_FLOW_OK;

    /* ERRORS */
error_no_caps:
    {
        GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
                           ("not negotiated"), ("maybe setcaps failed?"));

        return GST_FLOW_ERROR;
    }
error_start_capture:
    {
        const gchar *debug_str = "failed to change pin state to KSSTATE_RUN";

        switch (error_code) {
        case ERROR_FILE_NOT_FOUND:
            GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
                               ("failed to start capture (device unplugged)"), ("%s", debug_str));
            break;
        case ERROR_NO_SYSTEM_RESOURCES:
            GST_ELEMENT_ERROR (self, RESOURCE, BUSY,
                               ("failed to start capture (device already in use)"), ("%s",
                                       debug_str));
            break;
        default:
            GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
                               ("failed to start capture (0x%08x)", (guint) error_code), ("%s",
                                       debug_str));
            break;
        }

        return GST_FLOW_ERROR;
    }
error_read_frame:
    {
        if (result == GST_FLOW_ERROR) {
            if (error_str != NULL) {
                GST_ELEMENT_ERROR (self, RESOURCE, READ,
                                   ("read failed: %s [0x%08x]", error_str, (guint) error_code),
                                   ("gst_ks_video_device_read_frame failed"));
            }
        } else if (result == GST_FLOW_CUSTOM_ERROR) {
            GST_ELEMENT_ERROR (self, RESOURCE, READ,
                               ("read failed"), ("gst_ks_video_device_read_frame failed"));
        }

        g_free (error_str);

        return result;
    }
}
Beispiel #4
0
static GstFlowReturn
gst_ks_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
{
  GstKsVideoSrc *self = GST_KS_VIDEO_SRC (pushsrc);
  GstKsVideoSrcPrivate *priv = GST_KS_VIDEO_SRC_GET_PRIVATE (self);
  guint buf_size;
  GstCaps *caps;
  GstBuffer *buf = NULL;
  GstFlowReturn result;
  GstClockTime presentation_time;
  gulong error_code;
  gchar *error_str;

  g_assert (priv->device != NULL);

  if (!gst_ks_video_device_has_caps (priv->device))
    goto error_no_caps;

  buf_size = gst_ks_video_device_get_frame_size (priv->device);
  g_assert (buf_size);

  caps = gst_pad_get_negotiated_caps (GST_BASE_SRC_PAD (self));
  if (caps == NULL)
    goto error_no_caps;
  result = gst_pad_alloc_buffer (GST_BASE_SRC_PAD (self), priv->offset,
      buf_size, caps, &buf);
  gst_caps_unref (caps);
  if (G_UNLIKELY (result != GST_FLOW_OK))
    goto error_alloc_buffer;

  if (G_UNLIKELY (!priv->running)) {
    KS_WORKER_LOCK (priv);
    priv->worker_pending_run = TRUE;
    KS_WORKER_NOTIFY (priv);
    while (priv->worker_pending_run)
      KS_WORKER_WAIT_FOR_RESULT (priv);
    priv->running = priv->worker_run_result;
    KS_WORKER_UNLOCK (priv);

    if (!priv->running)
      goto error_start_capture;
  }

  do {
    gulong bytes_read;

    result = gst_ks_video_device_read_frame (priv->device,
        GST_BUFFER_DATA (buf), buf_size, &bytes_read, &presentation_time,
        &error_code, &error_str);
    if (G_UNLIKELY (result != GST_FLOW_OK))
      goto error_read_frame;

    GST_BUFFER_SIZE (buf) = bytes_read;
  }
  while (!gst_ks_video_src_timestamp_buffer (self, buf, presentation_time));

  if (G_UNLIKELY (priv->do_stats))
    gst_ks_video_src_update_statistics (self);

  gst_ks_video_device_postprocess_frame (priv->device,
      GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));

  *buffer = buf;
  return GST_FLOW_OK;

  /* ERRORS */
error_no_caps:
  {
    GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
        ("not negotiated"), ("maybe setcaps failed?"));

    return GST_FLOW_ERROR;
  }
error_start_capture:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ,
        ("could not start capture"),
        ("failed to change pin state to KSSTATE_RUN"));

    return GST_FLOW_ERROR;
  }
error_alloc_buffer:
  {
    GST_ELEMENT_ERROR (self, CORE, PAD, ("alloc_buffer failed"), (NULL));

    return result;
  }
error_read_frame:
  {
    if (result != GST_FLOW_WRONG_STATE && result != GST_FLOW_UNEXPECTED) {
      GST_ELEMENT_ERROR (self, RESOURCE, READ,
          ("read failed: %s [0x%08x]", error_str, error_code),
          ("gst_ks_video_device_read_frame failed"));
    }

    g_free (error_str);
    gst_buffer_unref (buf);

    return result;
  }
}