Ejemplo n.º 1
0
static gboolean
gst_vdp_sink_event (GstBaseSink * sink, GstEvent * event)
{
  VdpSink *vdp_sink = GST_VDP_SINK (sink);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_TAG:{
      GstTagList *l;
      gchar *title = NULL;

      gst_event_parse_tag (event, &l);
      gst_tag_list_get_string (l, GST_TAG_TITLE, &title);

      if (title) {
        GST_DEBUG_OBJECT (vdp_sink, "got tags, title='%s'", title);
        gst_vdp_sink_window_set_title (vdp_sink, vdp_sink->window, title);

        g_free (title);
      }
      break;
    }
    default:
      break;
  }
  if (GST_BASE_SINK_CLASS (parent_class)->event)
    return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
  else
    return TRUE;
}
Ejemplo n.º 2
0
static void
gst_vdp_sink_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  VdpSink *vdp_sink;

  g_return_if_fail (GST_IS_VDP_SINK (object));

  vdp_sink = GST_VDP_SINK (object);

  switch (prop_id) {
    case PROP_DISPLAY:
      g_value_set_string (value, vdp_sink->display_name);
      break;
    case PROP_SYNCHRONOUS:
      g_value_set_boolean (value, vdp_sink->synchronous);
      break;
    case PROP_PIXEL_ASPECT_RATIO:
      if (vdp_sink->par)
        g_value_transform (vdp_sink->par, value);
      break;
    case PROP_HANDLE_EVENTS:
      g_value_set_boolean (value, vdp_sink->handle_events);
      break;
    case PROP_HANDLE_EXPOSE:
      g_value_set_boolean (value, vdp_sink->handle_expose);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
Ejemplo n.º 3
0
static gboolean
gst_vdp_sink_stop (GstBaseSink * bsink)
{
  VdpSink *vdp_sink = GST_VDP_SINK (bsink);

  vdp_sink->running = FALSE;
  /* Wait for our event thread to finish before we clean up our stuff. */
  if (vdp_sink->event_thread)
    g_thread_join (vdp_sink->event_thread);

  if (vdp_sink->cur_image) {
    gst_buffer_unref (GST_BUFFER_CAST (vdp_sink->cur_image));
    vdp_sink->cur_image = NULL;
  }

  g_mutex_lock (vdp_sink->flow_lock);
  if (vdp_sink->window) {
    gst_vdp_sink_window_destroy (vdp_sink, vdp_sink->window);
    vdp_sink->window = NULL;
  }
  g_mutex_unlock (vdp_sink->flow_lock);

  gst_vdp_device_clear (vdp_sink);

  return TRUE;
}
Ejemplo n.º 4
0
static void
gst_vdp_sink_finalize (GObject * object)
{
  VdpSink *vdp_sink;

  vdp_sink = GST_VDP_SINK (object);

  if (vdp_sink->display_name) {
    g_free (vdp_sink->display_name);
    vdp_sink->display_name = NULL;
  }
  if (vdp_sink->par) {
    g_free (vdp_sink->par);
    vdp_sink->par = NULL;
  }
  if (vdp_sink->device_lock) {
    g_mutex_free (vdp_sink->device_lock);
    vdp_sink->device_lock = NULL;
  }
  if (vdp_sink->x_lock) {
    g_mutex_free (vdp_sink->x_lock);
    vdp_sink->x_lock = NULL;
  }
  if (vdp_sink->flow_lock) {
    g_mutex_free (vdp_sink->flow_lock);
    vdp_sink->flow_lock = NULL;
  }

  g_free (vdp_sink->media_title);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}
Ejemplo n.º 5
0
static void
gst_vdp_sink_set_event_handling (GstXOverlay * overlay, gboolean handle_events)
{
  VdpSink *vdp_sink = GST_VDP_SINK (overlay);

  vdp_sink->handle_events = handle_events;

  g_mutex_lock (vdp_sink->flow_lock);

  if (G_UNLIKELY (!vdp_sink->window)) {
    g_mutex_unlock (vdp_sink->flow_lock);
    return;
  }

  g_mutex_lock (vdp_sink->x_lock);

  if (handle_events) {
    if (vdp_sink->window->internal) {
      XSelectInput (vdp_sink->device->display, vdp_sink->window->win,
          ExposureMask | StructureNotifyMask | PointerMotionMask |
          KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
    } else {
      XSelectInput (vdp_sink->device->display, vdp_sink->window->win,
          ExposureMask | StructureNotifyMask | PointerMotionMask |
          KeyPressMask | KeyReleaseMask);
    }
  } else {
    XSelectInput (vdp_sink->device->display, vdp_sink->window->win, 0);
  }

  g_mutex_unlock (vdp_sink->x_lock);

  g_mutex_unlock (vdp_sink->flow_lock);
}
Ejemplo n.º 6
0
static void
gst_vdp_sink_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  VdpSink *vdp_sink;

  g_return_if_fail (GST_IS_VDP_SINK (object));

  vdp_sink = GST_VDP_SINK (object);

  switch (prop_id) {
    case PROP_DISPLAY:
      vdp_sink->display_name = g_strdup (g_value_get_string (value));
      break;
    case PROP_SYNCHRONOUS:
      vdp_sink->synchronous = g_value_get_boolean (value);
      if (vdp_sink->device) {
        GST_DEBUG_OBJECT (vdp_sink, "XSynchronize called with %s",
            vdp_sink->synchronous ? "TRUE" : "FALSE");
        g_mutex_lock (vdp_sink->x_lock);
        XSynchronize (vdp_sink->device->display, vdp_sink->synchronous);
        g_mutex_unlock (vdp_sink->x_lock);
      }
      break;
    case PROP_PIXEL_ASPECT_RATIO:
    {
      GValue *tmp;

      tmp = g_new0 (GValue, 1);
      g_value_init (tmp, GST_TYPE_FRACTION);

      if (!g_value_transform (value, tmp)) {
        GST_WARNING_OBJECT (vdp_sink,
            "Could not transform string to aspect ratio");
        g_free (tmp);
      } else {
        GST_DEBUG_OBJECT (vdp_sink, "set PAR to %d/%d",
            gst_value_get_fraction_numerator (tmp),
            gst_value_get_fraction_denominator (tmp));
        g_free (vdp_sink->par);
        vdp_sink->par = tmp;
      }
    }
      break;
    case PROP_HANDLE_EVENTS:
      gst_vdp_sink_set_event_handling (GST_X_OVERLAY (vdp_sink),
          g_value_get_boolean (value));
      break;
    case PROP_HANDLE_EXPOSE:
      vdp_sink->handle_expose = g_value_get_boolean (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
Ejemplo n.º 7
0
static GstCaps *
gst_vdp_sink_getcaps (GstBaseSink * bsink)
{
  VdpSink *vdp_sink;
  GstCaps *caps;

  vdp_sink = GST_VDP_SINK (bsink);

  if (vdp_sink->caps)
    caps = gst_caps_copy (vdp_sink->caps);
  else
    caps = gst_static_pad_template_get_caps (&sink_template);

  return caps;
}
Ejemplo n.º 8
0
static void
gst_vdp_sink_navigation_send_event (GstNavigation * navigation,
    GstStructure * structure)
{
  VdpSink *vdp_sink = GST_VDP_SINK (navigation);
  GstEvent *event;
  gint x_offset, y_offset;
  gdouble x, y;
  GstPad *pad = NULL;

  event = gst_event_new_navigation (structure);

  /* We are not converting the pointer coordinates as there's no hardware
     scaling done here. The only possible scaling is done by videoscale and
     videoscale will have to catch those events and tranform the coordinates
     to match the applied scaling. So here we just add the offset if the image
     is centered in the window.  */

  /* We take the flow_lock while we look at the window */
  g_mutex_lock (vdp_sink->flow_lock);

  if (!vdp_sink->window) {
    g_mutex_unlock (vdp_sink->flow_lock);
    return;
  }

  x_offset = vdp_sink->window->width - GST_VIDEO_SINK_WIDTH (vdp_sink);
  y_offset = vdp_sink->window->height - GST_VIDEO_SINK_HEIGHT (vdp_sink);

  g_mutex_unlock (vdp_sink->flow_lock);

  if (x_offset > 0 && gst_structure_get_double (structure, "pointer_x", &x)) {
    x -= x_offset / 2;
    gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x, NULL);
  }
  if (y_offset > 0 && gst_structure_get_double (structure, "pointer_y", &y)) {
    y -= y_offset / 2;
    gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, y, NULL);
  }

  pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (vdp_sink));

  if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) {
    gst_pad_send_event (pad, event);

    gst_object_unref (pad);
  }
}
Ejemplo n.º 9
0
static gboolean
gst_vdp_sink_start (GstBaseSink * bsink)
{
  VdpSink *vdp_sink = GST_VDP_SINK (bsink);
  gboolean res = TRUE;

  vdp_sink->window = NULL;
  vdp_sink->cur_image = NULL;

  vdp_sink->event_thread = NULL;

  vdp_sink->fps_n = 0;
  vdp_sink->fps_d = 1;

  res = gst_vdp_sink_open_device (vdp_sink);

  return res;
}
Ejemplo n.º 10
0
static void
gst_vdp_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
    GstClockTime * start, GstClockTime * end)
{
  VdpSink *vdp_sink;

  vdp_sink = GST_VDP_SINK (bsink);

  if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
    *start = GST_BUFFER_TIMESTAMP (buf);
    if (GST_BUFFER_DURATION_IS_VALID (buf)) {
      *end = *start + GST_BUFFER_DURATION (buf);
    } else {
      if (vdp_sink->fps_n > 0) {
        *end = *start +
            gst_util_uint64_scale_int (GST_SECOND, vdp_sink->fps_d,
            vdp_sink->fps_n);
      }
    }
  }
}
Ejemplo n.º 11
0
static gboolean
gst_vdp_sink_start (GstBaseSink * bsink)
{
  VdpSink *vdp_sink = GST_VDP_SINK (bsink);
  gboolean res = TRUE;

  vdp_sink->window = NULL;
  vdp_sink->cur_image = NULL;

  vdp_sink->event_thread = NULL;

  vdp_sink->fps_n = 0;
  vdp_sink->fps_d = 1;

  GST_OBJECT_LOCK (vdp_sink);
  if (!vdp_sink->device) {
    if (!(vdp_sink->device = gst_vdp_sink_setup_device (vdp_sink)))
      res = FALSE;
  }
  GST_OBJECT_UNLOCK (vdp_sink);

  return res;
}
Ejemplo n.º 12
0
/* Buffer management
 *
 * The buffer_alloc function must either return a buffer with given size and
 * caps or create a buffer with different caps attached to the buffer. This
 * last option is called reverse negotiation, ie, where the sink suggests a
 * different format from the upstream peer. 
 *
 * We try to do reverse negotiation when our geometry changes and we like a
 * resized buffer.
 */
static GstFlowReturn
gst_vdp_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
    GstCaps * caps, GstBuffer ** buf)
{
  VdpSink *vdp_sink;
  GstStructure *structure = NULL;
  GstFlowReturn ret = GST_FLOW_OK;
  gint width, height;
  GstCaps *alloc_caps;
  gint w_width, w_height;
  GError *err;

  vdp_sink = GST_VDP_SINK (bsink);

  GST_LOG_OBJECT (vdp_sink,
      "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT
      " and offset %" G_GUINT64_FORMAT, size, caps, offset);

  /* get struct to see what is requested */
  structure = gst_caps_get_structure (caps, 0);
  if (!gst_structure_get_int (structure, "width", &width) ||
      !gst_structure_get_int (structure, "height", &height)) {
    GST_WARNING_OBJECT (vdp_sink, "invalid caps for buffer allocation %"
        GST_PTR_FORMAT, caps);
    ret = GST_FLOW_NOT_NEGOTIATED;
    goto beach;
  }

  alloc_caps = gst_caps_ref (caps);

  /* We take the flow_lock because the window might go away */
  g_mutex_lock (vdp_sink->flow_lock);
  if (!vdp_sink->window) {
    g_mutex_unlock (vdp_sink->flow_lock);
    goto alloc;
  }

  /* What is our geometry */
  gst_vdp_sink_window_update_geometry (vdp_sink, vdp_sink->window);
  w_width = vdp_sink->window->width;
  w_height = vdp_sink->window->height;

  g_mutex_unlock (vdp_sink->flow_lock);

  /* We would like another geometry */
  if (width != w_width || height != w_height) {
    GstCaps *new_caps, *allowed_caps, *desired_caps;
    GstStructure *desired_struct;

    /* make a copy of the incomming caps to create the new
     * suggestion. We can't use make_writable because we might
     * then destroy the original caps which we still need when the
     * peer does not accept the suggestion. */
    new_caps = gst_caps_copy (caps);
    desired_struct = gst_caps_get_structure (new_caps, 0);

    GST_DEBUG ("we would love to receive a %dx%d video", w_width, w_height);
    gst_structure_set (desired_struct, "width", G_TYPE_INT, w_width, NULL);
    gst_structure_set (desired_struct, "height", G_TYPE_INT, w_height, NULL);

    allowed_caps = gst_pad_get_caps (GST_BASE_SINK_PAD (vdp_sink));
    desired_caps = gst_caps_intersect (new_caps, allowed_caps);

    gst_caps_unref (new_caps);
    gst_caps_unref (allowed_caps);

    /* see if peer accepts our new suggestion, if there is no peer, this 
     * function returns true. */
    if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (vdp_sink), desired_caps)) {
      /* we will not alloc a buffer of the new suggested caps. Make sure
       * we also unref this new caps after we set it on the buffer. */
      GST_DEBUG ("peer pad accepts our desired caps %" GST_PTR_FORMAT,
          desired_caps);
      gst_caps_unref (alloc_caps);
      alloc_caps = desired_caps;
    } else {
      GST_DEBUG ("peer pad does not accept our desired caps %" GST_PTR_FORMAT,
          desired_caps);
      /* we alloc a buffer with the original incomming caps already in the
       * width and height variables */
      gst_caps_unref (desired_caps);
    }
  }

alloc:
  gst_vdp_buffer_pool_set_caps (vdp_sink->bpool, alloc_caps);
  gst_caps_unref (alloc_caps);

  err = NULL;
  *buf =
      GST_BUFFER_CAST (gst_vdp_buffer_pool_get_buffer (vdp_sink->bpool, &err));
  if (!*buf) {
    gst_vdp_sink_post_error (vdp_sink, err);
    return GST_FLOW_ERROR;
  }

beach:
  return ret;
}
Ejemplo n.º 13
0
static GstFlowReturn
gst_vdp_sink_show_frame (GstBaseSink * bsink, GstBuffer * outbuf)
{
  VdpSink *vdp_sink = GST_VDP_SINK (bsink);
  VdpStatus status;
  GstVdpDevice *device;

  g_return_val_if_fail (GST_IS_VDP_SINK (vdp_sink), FALSE);

  /* We take the flow_lock. If expose is in there we don't want to run
     concurrently from the data flow thread */
  g_mutex_lock (vdp_sink->flow_lock);

  if (G_UNLIKELY (vdp_sink->window == NULL)) {
    g_mutex_unlock (vdp_sink->flow_lock);
    return GST_FLOW_ERROR;
  }

  device = vdp_sink->device;

  if (vdp_sink->cur_image) {
    VdpOutputSurface surface =
        GST_VDP_OUTPUT_BUFFER (vdp_sink->cur_image)->surface;
    VdpPresentationQueueStatus queue_status;
    VdpTime pres_time;

    g_mutex_lock (vdp_sink->x_lock);
    status =
        device->vdp_presentation_queue_query_surface_status (vdp_sink->
        window->queue, surface, &queue_status, &pres_time);
    g_mutex_unlock (vdp_sink->x_lock);

    if (queue_status == VDP_PRESENTATION_QUEUE_STATUS_QUEUED) {
      g_mutex_unlock (vdp_sink->flow_lock);
      return GST_FLOW_OK;
    }
  }

  /* Expose sends a NULL image, we take the latest frame */
  if (!outbuf) {
    if (vdp_sink->cur_image) {
      outbuf = vdp_sink->cur_image;
    } else {
      g_mutex_unlock (vdp_sink->flow_lock);
      return GST_FLOW_OK;
    }
  }

  gst_vdp_sink_window_update_geometry (vdp_sink, vdp_sink->window);

  g_mutex_lock (vdp_sink->x_lock);

  status = device->vdp_presentation_queue_display (vdp_sink->window->queue,
      GST_VDP_OUTPUT_BUFFER (outbuf)->surface, 0, 0, 0);
  if (status != VDP_STATUS_OK) {
    GST_ELEMENT_ERROR (vdp_sink, RESOURCE, READ,
        ("Could not display frame"),
        ("Error returned from vdpau was: %s",
            device->vdp_get_error_string (status)));

    g_mutex_unlock (vdp_sink->x_lock);
    g_mutex_unlock (vdp_sink->flow_lock);
    return GST_FLOW_ERROR;
  }


  if (!vdp_sink->cur_image)
    vdp_sink->cur_image = gst_buffer_ref (outbuf);

  else if (vdp_sink->cur_image != outbuf) {
    gst_buffer_unref (vdp_sink->cur_image);
    vdp_sink->cur_image = gst_buffer_ref (outbuf);
  }

  XSync (vdp_sink->device->display, FALSE);

  g_mutex_unlock (vdp_sink->x_lock);
  g_mutex_unlock (vdp_sink->flow_lock);

  return GST_FLOW_OK;
}
Ejemplo n.º 14
0
static gboolean
gst_vdp_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
{
  VdpSink *vdp_sink;
  GstCaps *allowed_caps;
  gboolean ret = TRUE;
  GstStructure *structure;
  GstCaps *intersection;
  gint new_width, new_height;
  const GValue *fps;

  vdp_sink = GST_VDP_SINK (bsink);

  GST_OBJECT_LOCK (vdp_sink);
  if (!vdp_sink->device)
    return FALSE;
  GST_OBJECT_UNLOCK (vdp_sink);

  allowed_caps = gst_pad_get_caps (GST_BASE_SINK_PAD (bsink));
  GST_DEBUG_OBJECT (vdp_sink,
      "sinkconnect possible caps %" GST_PTR_FORMAT " with given caps %"
      GST_PTR_FORMAT, allowed_caps, caps);

  /* We intersect those caps with our template to make sure they are correct */
  intersection = gst_caps_intersect (allowed_caps, caps);
  gst_caps_unref (allowed_caps);

  GST_DEBUG_OBJECT (vdp_sink, "intersection returned %" GST_PTR_FORMAT,
      intersection);
  if (gst_caps_is_empty (intersection)) {
    gst_caps_unref (intersection);
    return FALSE;
  }

  gst_caps_unref (intersection);

  structure = gst_caps_get_structure (caps, 0);

  ret &= gst_structure_get_int (structure, "width", &new_width);
  ret &= gst_structure_get_int (structure, "height", &new_height);
  fps = gst_structure_get_value (structure, "framerate");
  ret &= (fps != NULL);
  if (!ret)
    return FALSE;

  GST_VIDEO_SINK_WIDTH (vdp_sink) = new_width;
  GST_VIDEO_SINK_HEIGHT (vdp_sink) = new_height;
  vdp_sink->fps_n = gst_value_get_fraction_numerator (fps);
  vdp_sink->fps_d = gst_value_get_fraction_denominator (fps);

  gst_vdp_buffer_pool_set_caps (vdp_sink->bpool, caps);

  /* Notify application to set xwindow id now */
  g_mutex_lock (vdp_sink->flow_lock);
  if (!vdp_sink->window) {
    g_mutex_unlock (vdp_sink->flow_lock);
    gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (vdp_sink));
  } else {
    g_mutex_unlock (vdp_sink->flow_lock);
  }

  /* Creating our window and our image */
  if (GST_VIDEO_SINK_WIDTH (vdp_sink) <= 0
      || GST_VIDEO_SINK_HEIGHT (vdp_sink) <= 0) {
    GST_ELEMENT_ERROR (vdp_sink, CORE, NEGOTIATION, (NULL),
        ("Invalid image size."));
    return FALSE;
  }

  g_mutex_lock (vdp_sink->flow_lock);
  if (!vdp_sink->window) {
    vdp_sink->window = gst_vdp_sink_window_new (vdp_sink,
        GST_VIDEO_SINK_WIDTH (vdp_sink), GST_VIDEO_SINK_HEIGHT (vdp_sink));
  }
  g_mutex_unlock (vdp_sink->flow_lock);

  return TRUE;
}
Ejemplo n.º 15
0
static void
gst_vdp_sink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id)
{
  VdpSink *vdp_sink = GST_VDP_SINK (overlay);
  GstVdpWindow *window = NULL;
  XWindowAttributes attr;

  /* We acquire the stream lock while setting this window in the element.
     We are basically cleaning tons of stuff replacing the old window, putting
     images while we do that would surely crash */
  g_mutex_lock (vdp_sink->flow_lock);

  /* If we already use that window return */
  if (vdp_sink->window && (xwindow_id == vdp_sink->window->win)) {
    g_mutex_unlock (vdp_sink->flow_lock);
    return;
  }

  /* If the element has not initialized the X11 context try to do so */
  if (!gst_vdp_sink_open_device (vdp_sink)) {
    g_mutex_unlock (vdp_sink->flow_lock);
    /* we have thrown a GST_ELEMENT_ERROR now */
    return;
  }

  /* If a window is there already we destroy it */
  if (vdp_sink->window) {
    gst_vdp_sink_window_destroy (vdp_sink, vdp_sink->window);
    vdp_sink->window = NULL;
  }

  /* If the xid is 0 we go back to an internal window */
  if (xwindow_id == 0) {
    /* If no width/height caps nego did not happen window will be created
       during caps nego then */
    if (GST_VIDEO_SINK_WIDTH (vdp_sink) && GST_VIDEO_SINK_HEIGHT (vdp_sink)) {
      window = gst_vdp_sink_window_new (vdp_sink,
          GST_VIDEO_SINK_WIDTH (vdp_sink), GST_VIDEO_SINK_HEIGHT (vdp_sink));
    }
  } else {
    window = g_new0 (GstVdpWindow, 1);

    window->win = xwindow_id;

    /* We get window geometry, set the event we want to receive,
       and create a GC */
    g_mutex_lock (vdp_sink->x_lock);
    XGetWindowAttributes (vdp_sink->device->display, window->win, &attr);
    window->width = attr.width;
    window->height = attr.height;
    window->internal = FALSE;
    if (vdp_sink->handle_events) {
      XSelectInput (vdp_sink->device->display, window->win, ExposureMask |
          StructureNotifyMask | PointerMotionMask | KeyPressMask |
          KeyReleaseMask);
    }

    g_mutex_unlock (vdp_sink->x_lock);
  }

  if (window)
    vdp_sink->window = window;

  g_mutex_unlock (vdp_sink->flow_lock);
}