static void
gst_gdk_pixbuf_sink_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstGdkPixbufSink *sink;

  sink = GST_GDK_PIXBUF_SINK (object);

  switch (prop_id) {
    case PROP_SEND_MESSAGES:
    case PROP_POST_MESSAGES:
      GST_OBJECT_LOCK (sink);
      g_value_set_boolean (value, sink->post_messages);
      GST_OBJECT_UNLOCK (sink);
      break;
    case PROP_LAST_PIXBUF:
      GST_OBJECT_LOCK (sink);
      g_value_set_object (value, sink->last_pixbuf);
      GST_OBJECT_UNLOCK (sink);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
static GstFlowReturn
gst_gdk_pixbuf_sink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf,
    const gchar * msg_name)
{
  GstGdkPixbufSink *sink;
  GdkPixbuf *pixbuf;
  gboolean do_post;

  sink = GST_GDK_PIXBUF_SINK (basesink);

  pixbuf = gst_gdk_pixbuf_sink_get_pixbuf_from_buffer (sink, buf);

  GST_OBJECT_LOCK (sink);

  do_post = sink->post_messages;

  if (sink->last_pixbuf)
    g_object_unref (sink->last_pixbuf);

  sink->last_pixbuf = pixbuf;   /* take ownership */

  GST_OBJECT_UNLOCK (sink);

  if (G_UNLIKELY (pixbuf == NULL))
    goto error;

  if (do_post) {
    GstStructure *s;
    GstMessage *msg;

    /* it's okay to keep using pixbuf here, we can be sure no one is going to
     * unref or change sink->last_pixbuf before we return from this function.
     * The structure will take its own ref to the pixbuf. */
    s = gst_structure_new (msg_name,
        "pixbuf", GDK_TYPE_PIXBUF, pixbuf,
        "pixel-aspect-ratio", GST_TYPE_FRACTION, sink->par_d, sink->par_n,
        NULL);

    msg = gst_message_new_element (GST_OBJECT_CAST (sink), s);
    gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
  }

  g_object_notify (G_OBJECT (sink), "last-pixbuf");

  return GST_FLOW_OK;

/* ERRORS */
error:
  {
    /* This shouldn't really happen */
    GST_ELEMENT_ERROR (sink, LIBRARY, FAILED,
        ("Couldn't create pixbuf from RGB image."),
        ("Probably not enough free memory"));
    return GST_FLOW_ERROR;
  }
}
static gboolean
gst_gdk_pixbuf_sink_set_caps (GstBaseSink * basesink, GstCaps * caps)
{
  GstGdkPixbufSink *sink = GST_GDK_PIXBUF_SINK (basesink);
  GstVideoInfo info;
  GstVideoFormat fmt;
  gint w, h, s, par_n, par_d;

  GST_LOG_OBJECT (sink, "caps: %" GST_PTR_FORMAT, caps);

  if (!gst_video_info_from_caps (&info, caps)) {
    GST_WARNING_OBJECT (sink, "parse_caps failed");
    return FALSE;
  }

  fmt = GST_VIDEO_INFO_FORMAT (&info);
  w = GST_VIDEO_INFO_WIDTH (&info);
  h = GST_VIDEO_INFO_HEIGHT (&info);
  s = GST_VIDEO_INFO_COMP_PSTRIDE (&info, 0);
  par_n = GST_VIDEO_INFO_PAR_N (&info);
  par_d = GST_VIDEO_INFO_PAR_N (&info);

  g_assert ((fmt == GST_VIDEO_FORMAT_RGB && s == 3) ||
      (fmt == GST_VIDEO_FORMAT_RGBA && s == 4));

  GST_VIDEO_SINK_WIDTH (sink) = w;
  GST_VIDEO_SINK_HEIGHT (sink) = h;

  sink->par_n = par_n;
  sink->par_d = par_d;

  sink->has_alpha = GST_VIDEO_INFO_HAS_ALPHA (&info);

  GST_INFO_OBJECT (sink, "format             : %d", fmt);
  GST_INFO_OBJECT (sink, "width x height     : %d x %d", w, h);
  GST_INFO_OBJECT (sink, "pixel-aspect-ratio : %d/%d", par_n, par_d);

  sink->info = info;

  return TRUE;
}
static gboolean
gst_gdk_pixbuf_sink_stop (GstBaseSink * basesink)
{
  GstGdkPixbufSink *sink = GST_GDK_PIXBUF_SINK (basesink);

  GST_VIDEO_SINK_WIDTH (sink) = 0;
  GST_VIDEO_SINK_HEIGHT (sink) = 0;

  sink->par_n = 0;
  sink->par_d = 0;
  sink->has_alpha = FALSE;

  if (sink->last_pixbuf) {
    g_object_unref (sink->last_pixbuf);
    sink->last_pixbuf = NULL;
  }

  GST_LOG_OBJECT (sink, "stop");

  return TRUE;
}
static gboolean
gst_gdk_pixbuf_sink_set_caps (GstBaseSink * basesink, GstCaps * caps)
{
  GstGdkPixbufSink *sink = GST_GDK_PIXBUF_SINK (basesink);
  GstVideoFormat fmt;
  gint w, h, par_n, par_d;

  GST_LOG_OBJECT (sink, "caps: %" GST_PTR_FORMAT, caps);

  if (!gst_video_format_parse_caps (caps, &fmt, &w, &h)) {
    GST_WARNING_OBJECT (sink, "parse_caps failed");
    return FALSE;
  }

  if (!gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d)) {
    GST_LOG_OBJECT (sink, "no pixel aspect ratio");
    return FALSE;
  }

  g_assert ((fmt == GST_VIDEO_FORMAT_RGB &&
          gst_video_format_get_pixel_stride (fmt, 0) == 3) ||
      (fmt == GST_VIDEO_FORMAT_RGBA &&
          gst_video_format_get_pixel_stride (fmt, 0) == 4));

  GST_VIDEO_SINK_WIDTH (sink) = w;
  GST_VIDEO_SINK_HEIGHT (sink) = h;

  sink->rowstride = gst_video_format_get_row_stride (fmt, 0, w);
  sink->has_alpha = (fmt == GST_VIDEO_FORMAT_RGBA);

  sink->par_n = par_n;
  sink->par_d = par_d;

  GST_INFO_OBJECT (sink, "format             : %d", fmt);
  GST_INFO_OBJECT (sink, "width x height     : %d x %d", w, h);
  GST_INFO_OBJECT (sink, "pixel-aspect-ratio : %d/%d", par_d, par_n);

  return TRUE;
}