Blame ext/gtk/gstgtkbasesink.c

Packit 1f69a5
/*
Packit 1f69a5
 * GStreamer
Packit 1f69a5
 * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
Packit 1f69a5
 *
Packit 1f69a5
 * This library is free software; you can redistribute it and/or
Packit 1f69a5
 * modify it under the terms of the GNU Library General Public
Packit 1f69a5
 * License as published by the Free Software Foundation; either
Packit 1f69a5
 * version 2 of the License, or (at your option) any later version.
Packit 1f69a5
 *
Packit 1f69a5
 * This library is distributed in the hope that it will be useful,
Packit 1f69a5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1f69a5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 1f69a5
 * Library General Public License for more details.
Packit 1f69a5
 *
Packit 1f69a5
 * You should have received a copy of the GNU Library General Public
Packit 1f69a5
 * License along with this library; if not, write to the
Packit 1f69a5
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 1f69a5
 * Boston, MA 02110-1301, USA.
Packit 1f69a5
 */
Packit 1f69a5
Packit 1f69a5
/**
Packit 1f69a5
 * SECTION:gtkgstsink
Packit 1f69a5
 * @title: GstGtkBaseSink
Packit 1f69a5
 *
Packit 1f69a5
 */
Packit 1f69a5
Packit 1f69a5
#ifdef HAVE_CONFIG_H
Packit 1f69a5
#include "config.h"
Packit 1f69a5
#endif
Packit 1f69a5
Packit 1f69a5
#include "gstgtkbasesink.h"
Packit 1f69a5
#include "gstgtkutils.h"
Packit 1f69a5
Packit 1f69a5
GST_DEBUG_CATEGORY (gst_debug_gtk_base_sink);
Packit 1f69a5
#define GST_CAT_DEFAULT gst_debug_gtk_base_sink
Packit 1f69a5
Packit 1f69a5
#define DEFAULT_FORCE_ASPECT_RATIO  TRUE
Packit 1f69a5
#define DEFAULT_PAR_N               0
Packit 1f69a5
#define DEFAULT_PAR_D               1
Packit 1f69a5
#define DEFAULT_IGNORE_ALPHA        TRUE
Packit 1f69a5
Packit 1f69a5
static void gst_gtk_base_sink_finalize (GObject * object);
Packit 1f69a5
static void gst_gtk_base_sink_set_property (GObject * object, guint prop_id,
Packit 1f69a5
    const GValue * value, GParamSpec * param_spec);
Packit 1f69a5
static void gst_gtk_base_sink_get_property (GObject * object, guint prop_id,
Packit 1f69a5
    GValue * value, GParamSpec * param_spec);
Packit 1f69a5
Packit 1f69a5
static gboolean gst_gtk_base_sink_start (GstBaseSink * bsink);
Packit 1f69a5
static gboolean gst_gtk_base_sink_stop (GstBaseSink * bsink);
Packit 1f69a5
Packit 1f69a5
static GstStateChangeReturn
Packit 1f69a5
gst_gtk_base_sink_change_state (GstElement * element,
Packit 1f69a5
    GstStateChange transition);
Packit 1f69a5
Packit 1f69a5
static void gst_gtk_base_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
Packit 1f69a5
    GstClockTime * start, GstClockTime * end);
Packit 1f69a5
static gboolean gst_gtk_base_sink_set_caps (GstBaseSink * bsink,
Packit 1f69a5
    GstCaps * caps);
Packit 1f69a5
static GstFlowReturn gst_gtk_base_sink_show_frame (GstVideoSink * bsink,
Packit 1f69a5
    GstBuffer * buf);
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_gtk_base_sink_navigation_interface_init (GstNavigationInterface * iface);
Packit 1f69a5
Packit 1f69a5
enum
Packit 1f69a5
{
Packit 1f69a5
  PROP_0,
Packit 1f69a5
  PROP_WIDGET,
Packit 1f69a5
  PROP_FORCE_ASPECT_RATIO,
Packit 1f69a5
  PROP_PIXEL_ASPECT_RATIO,
Packit 1f69a5
  PROP_IGNORE_ALPHA,
Packit 1f69a5
};
Packit 1f69a5
Packit 1f69a5
#define gst_gtk_base_sink_parent_class parent_class
Packit 1f69a5
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGtkBaseSink, gst_gtk_base_sink,
Packit 1f69a5
    GST_TYPE_VIDEO_SINK,
Packit 1f69a5
    G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
Packit 1f69a5
        gst_gtk_base_sink_navigation_interface_init);
Packit 1f69a5
    GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink,
Packit 1f69a5
        "gtkbasesink", 0, "Gtk Video Sink base class"));
Packit 1f69a5
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass)
Packit 1f69a5
{
Packit 1f69a5
  GObjectClass *gobject_class;
Packit 1f69a5
  GstElementClass *gstelement_class;
Packit 1f69a5
  GstBaseSinkClass *gstbasesink_class;
Packit 1f69a5
  GstVideoSinkClass *gstvideosink_class;
Packit 1f69a5
Packit 1f69a5
  gobject_class = (GObjectClass *) klass;
Packit 1f69a5
  gstelement_class = (GstElementClass *) klass;
Packit 1f69a5
  gstbasesink_class = (GstBaseSinkClass *) klass;
Packit 1f69a5
  gstvideosink_class = (GstVideoSinkClass *) klass;
Packit 1f69a5
Packit 1f69a5
  gobject_class->set_property = gst_gtk_base_sink_set_property;
Packit 1f69a5
  gobject_class->get_property = gst_gtk_base_sink_get_property;
Packit 1f69a5
Packit 1f69a5
  g_object_class_install_property (gobject_class, PROP_WIDGET,
Packit 1f69a5
      g_param_spec_object ("widget", "Gtk Widget",
Packit 1f69a5
          "The GtkWidget to place in the widget hierarchy "
Packit 1f69a5
          "(must only be get from the GTK main thread)",
Packit 1f69a5
          GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 1f69a5
Packit 1f69a5
  g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
Packit 1f69a5
      g_param_spec_boolean ("force-aspect-ratio",
Packit 1f69a5
          "Force aspect ratio",
Packit 1f69a5
          "When enabled, scaling will respect original aspect ratio",
Packit 1f69a5
          DEFAULT_FORCE_ASPECT_RATIO,
Packit 1f69a5
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 1f69a5
Packit 1f69a5
  g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
Packit 1f69a5
      gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
Packit 1f69a5
          "The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D,
Packit 1f69a5
          G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 1f69a5
Packit 1f69a5
  g_object_class_install_property (gobject_class, PROP_IGNORE_ALPHA,
Packit 1f69a5
      g_param_spec_boolean ("ignore-alpha", "Ignore Alpha",
Packit 1f69a5
          "When enabled, alpha will be ignored and converted to black",
Packit 1f69a5
          DEFAULT_IGNORE_ALPHA, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 1f69a5
Packit 1f69a5
  gobject_class->finalize = gst_gtk_base_sink_finalize;
Packit 1f69a5
Packit 1f69a5
  gstelement_class->change_state = gst_gtk_base_sink_change_state;
Packit 1f69a5
  gstbasesink_class->set_caps = gst_gtk_base_sink_set_caps;
Packit 1f69a5
  gstbasesink_class->get_times = gst_gtk_base_sink_get_times;
Packit 1f69a5
  gstbasesink_class->start = gst_gtk_base_sink_start;
Packit 1f69a5
  gstbasesink_class->stop = gst_gtk_base_sink_stop;
Packit 1f69a5
Packit 1f69a5
  gstvideosink_class->show_frame = gst_gtk_base_sink_show_frame;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_gtk_base_sink_init (GstGtkBaseSink * gtk_sink)
Packit 1f69a5
{
Packit 1f69a5
  gtk_sink->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
Packit 1f69a5
  gtk_sink->par_n = DEFAULT_PAR_N;
Packit 1f69a5
  gtk_sink->par_d = DEFAULT_PAR_D;
Packit 1f69a5
  gtk_sink->ignore_alpha = DEFAULT_IGNORE_ALPHA;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_gtk_base_sink_finalize (GObject * object)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (object);
Packit 1f69a5
Packit 1f69a5
  GST_OBJECT_LOCK (gtk_sink);
Packit 1f69a5
  if (gtk_sink->window && gtk_sink->window_destroy_id)
Packit 1f69a5
    g_signal_handler_disconnect (gtk_sink->window, gtk_sink->window_destroy_id);
Packit 1f69a5
  if (gtk_sink->widget && gtk_sink->widget_destroy_id)
Packit 1f69a5
    g_signal_handler_disconnect (gtk_sink->widget, gtk_sink->widget_destroy_id);
Packit 1f69a5
Packit 1f69a5
  g_clear_object (&gtk_sink->widget);
Packit 1f69a5
  GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
Packit 1f69a5
  G_OBJECT_CLASS (parent_class)->finalize (object);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
widget_destroy_cb (GtkWidget * widget, GstGtkBaseSink * gtk_sink)
Packit 1f69a5
{
Packit 1f69a5
  GST_OBJECT_LOCK (gtk_sink);
Packit 1f69a5
  g_clear_object (&gtk_sink->widget);
Packit 1f69a5
  GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
window_destroy_cb (GtkWidget * widget, GstGtkBaseSink * gtk_sink)
Packit 1f69a5
{
Packit 1f69a5
  GST_OBJECT_LOCK (gtk_sink);
Packit 1f69a5
  gtk_sink->window = NULL;
Packit 1f69a5
  GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static GtkGstBaseWidget *
Packit 1f69a5
gst_gtk_base_sink_get_widget (GstGtkBaseSink * gtk_sink)
Packit 1f69a5
{
Packit 1f69a5
  if (gtk_sink->widget != NULL)
Packit 1f69a5
    return gtk_sink->widget;
Packit 1f69a5
Packit 1f69a5
  /* Ensure GTK is initialized, this has no side effect if it was already
Packit 1f69a5
   * initialized. Also, we do that lazily, so the application can be first */
Packit 1f69a5
  if (!gtk_init_check (NULL, NULL)) {
Packit 1f69a5
    GST_ERROR_OBJECT (gtk_sink, "Could not ensure GTK initialization.");
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  g_assert (GST_GTK_BASE_SINK_GET_CLASS (gtk_sink)->create_widget);
Packit 1f69a5
  gtk_sink->widget = (GtkGstBaseWidget *)
Packit 1f69a5
      GST_GTK_BASE_SINK_GET_CLASS (gtk_sink)->create_widget ();
Packit 1f69a5
Packit 1f69a5
  gtk_sink->bind_aspect_ratio =
Packit 1f69a5
      g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget,
Packit 1f69a5
      "force-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
Packit 1f69a5
  gtk_sink->bind_pixel_aspect_ratio =
Packit 1f69a5
      g_object_bind_property (gtk_sink, "pixel-aspect-ratio", gtk_sink->widget,
Packit 1f69a5
      "pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
Packit 1f69a5
  gtk_sink->bind_ignore_alpha =
Packit 1f69a5
      g_object_bind_property (gtk_sink, "ignore-alpha", gtk_sink->widget,
Packit 1f69a5
      "ignore-alpha", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
Packit 1f69a5
Packit 1f69a5
  /* Take the floating ref, other wise the destruction of the container will
Packit 1f69a5
   * make this widget disapear possibly before we are done. */
Packit 1f69a5
  gst_object_ref_sink (gtk_sink->widget);
Packit 1f69a5
  gtk_sink->widget_destroy_id = g_signal_connect (gtk_sink->widget, "destroy",
Packit 1f69a5
      G_CALLBACK (widget_destroy_cb), gtk_sink);
Packit 1f69a5
Packit 1f69a5
  /* back pointer */
Packit 1f69a5
  gtk_gst_base_widget_set_element (GTK_GST_BASE_WIDGET (gtk_sink->widget),
Packit 1f69a5
      GST_ELEMENT (gtk_sink));
Packit 1f69a5
Packit 1f69a5
  return gtk_sink->widget;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_gtk_base_sink_get_property (GObject * object, guint prop_id,
Packit 1f69a5
    GValue * value, GParamSpec * pspec)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (object);
Packit 1f69a5
Packit 1f69a5
  switch (prop_id) {
Packit 1f69a5
    case PROP_WIDGET:
Packit 1f69a5
    {
Packit 1f69a5
      GObject *widget = NULL;
Packit 1f69a5
Packit 1f69a5
      GST_OBJECT_LOCK (gtk_sink);
Packit 1f69a5
      if (gtk_sink->widget != NULL)
Packit 1f69a5
        widget = G_OBJECT (gtk_sink->widget);
Packit 1f69a5
      GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
Packit 1f69a5
      if (!widget)
Packit 1f69a5
        widget =
Packit 1f69a5
            gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_get_widget,
Packit 1f69a5
            gtk_sink);
Packit 1f69a5
Packit 1f69a5
      g_value_set_object (value, widget);
Packit 1f69a5
      break;
Packit 1f69a5
    }
Packit 1f69a5
    case PROP_FORCE_ASPECT_RATIO:
Packit 1f69a5
      g_value_set_boolean (value, gtk_sink->force_aspect_ratio);
Packit 1f69a5
      break;
Packit 1f69a5
    case PROP_PIXEL_ASPECT_RATIO:
Packit 1f69a5
      gst_value_set_fraction (value, gtk_sink->par_n, gtk_sink->par_d);
Packit 1f69a5
      break;
Packit 1f69a5
    case PROP_IGNORE_ALPHA:
Packit 1f69a5
      g_value_set_boolean (value, gtk_sink->ignore_alpha);
Packit 1f69a5
      break;
Packit 1f69a5
    default:
Packit 1f69a5
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_gtk_base_sink_set_property (GObject * object, guint prop_id,
Packit 1f69a5
    const GValue * value, GParamSpec * pspec)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (object);
Packit 1f69a5
Packit 1f69a5
  switch (prop_id) {
Packit 1f69a5
    case PROP_FORCE_ASPECT_RATIO:
Packit 1f69a5
      gtk_sink->force_aspect_ratio = g_value_get_boolean (value);
Packit 1f69a5
      break;
Packit 1f69a5
    case PROP_PIXEL_ASPECT_RATIO:
Packit 1f69a5
      gtk_sink->par_n = gst_value_get_fraction_numerator (value);
Packit 1f69a5
      gtk_sink->par_d = gst_value_get_fraction_denominator (value);
Packit 1f69a5
      break;
Packit 1f69a5
    case PROP_IGNORE_ALPHA:
Packit 1f69a5
      gtk_sink->ignore_alpha = g_value_get_boolean (value);
Packit 1f69a5
      break;
Packit 1f69a5
    default:
Packit 1f69a5
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_gtk_base_sink_navigation_send_event (GstNavigation * navigation,
Packit 1f69a5
    GstStructure * structure)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *sink = GST_GTK_BASE_SINK (navigation);
Packit 1f69a5
  GstEvent *event;
Packit 1f69a5
  GstPad *pad;
Packit 1f69a5
Packit 1f69a5
  event = gst_event_new_navigation (structure);
Packit 1f69a5
  pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink));
Packit 1f69a5
Packit 1f69a5
  GST_TRACE_OBJECT (sink, "navigation event %" GST_PTR_FORMAT, structure);
Packit 1f69a5
Packit 1f69a5
  if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) {
Packit 1f69a5
    if (!gst_pad_send_event (pad, gst_event_ref (event))) {
Packit 1f69a5
      /* If upstream didn't handle the event we'll post a message with it
Packit 1f69a5
       * for the application in case it wants to do something with it */
Packit 1f69a5
      gst_element_post_message (GST_ELEMENT_CAST (sink),
Packit 1f69a5
          gst_navigation_message_new_event (GST_OBJECT_CAST (sink), event));
Packit 1f69a5
    }
Packit 1f69a5
    gst_event_unref (event);
Packit 1f69a5
    gst_object_unref (pad);
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_gtk_base_sink_navigation_interface_init (GstNavigationInterface * iface)
Packit 1f69a5
{
Packit 1f69a5
  iface->send_event = gst_gtk_base_sink_navigation_send_event;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static gboolean
Packit 1f69a5
gst_gtk_base_sink_start_on_main (GstBaseSink * bsink)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink);
Packit 1f69a5
  GstGtkBaseSinkClass *klass = GST_GTK_BASE_SINK_GET_CLASS (bsink);
Packit 1f69a5
  GtkWidget *toplevel;
Packit 1f69a5
Packit 1f69a5
  if (gst_gtk_base_sink_get_widget (gst_sink) == NULL)
Packit 1f69a5
    return FALSE;
Packit 1f69a5
Packit 1f69a5
  /* After this point, gtk_sink->widget will always be set */
Packit 1f69a5
Packit 1f69a5
  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (gst_sink->widget));
Packit 1f69a5
  if (!gtk_widget_is_toplevel (toplevel)) {
Packit 1f69a5
    /* sanity check */
Packit 1f69a5
    g_assert (klass->window_title);
Packit 1f69a5
Packit 1f69a5
    /* User did not add widget its own UI, let's popup a new GtkWindow to
Packit 1f69a5
     * make gst-launch-1.0 work. */
Packit 1f69a5
    gst_sink->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit 1f69a5
    gtk_window_set_default_size (GTK_WINDOW (gst_sink->window), 640, 480);
Packit 1f69a5
    gtk_window_set_title (GTK_WINDOW (gst_sink->window), klass->window_title);
Packit 1f69a5
    gtk_container_add (GTK_CONTAINER (gst_sink->window), toplevel);
Packit 1f69a5
    gst_sink->window_destroy_id = g_signal_connect (gst_sink->window, "destroy",
Packit 1f69a5
        G_CALLBACK (window_destroy_cb), gst_sink);
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  return TRUE;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static gboolean
Packit 1f69a5
gst_gtk_base_sink_start (GstBaseSink * bsink)
Packit 1f69a5
{
Packit 1f69a5
  return ! !gst_gtk_invoke_on_main ((GThreadFunc)
Packit 1f69a5
      gst_gtk_base_sink_start_on_main, bsink);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static gboolean
Packit 1f69a5
gst_gtk_base_sink_stop_on_main (GstBaseSink * bsink)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink);
Packit 1f69a5
Packit 1f69a5
  if (gst_sink->window) {
Packit 1f69a5
    gtk_widget_destroy (gst_sink->window);
Packit 1f69a5
    gst_sink->window = NULL;
Packit 1f69a5
    gst_sink->widget = NULL;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  return TRUE;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static gboolean
Packit 1f69a5
gst_gtk_base_sink_stop (GstBaseSink * bsink)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink);
Packit 1f69a5
Packit 1f69a5
  if (gst_sink->window)
Packit 1f69a5
    return ! !gst_gtk_invoke_on_main ((GThreadFunc)
Packit 1f69a5
        gst_gtk_base_sink_stop_on_main, bsink);
Packit 1f69a5
Packit 1f69a5
  return TRUE;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_gtk_widget_show_all_and_unref (GtkWidget * widget)
Packit 1f69a5
{
Packit 1f69a5
  gtk_widget_show_all (widget);
Packit 1f69a5
  g_object_unref (widget);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static GstStateChangeReturn
Packit 1f69a5
gst_gtk_base_sink_change_state (GstElement * element, GstStateChange transition)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (element);
Packit 1f69a5
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG_OBJECT (element, "changing state: %s => %s",
Packit 1f69a5
      gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
Packit 1f69a5
      gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
Packit 1f69a5
Packit 1f69a5
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
Packit 1f69a5
  if (ret == GST_STATE_CHANGE_FAILURE)
Packit 1f69a5
    return ret;
Packit 1f69a5
Packit 1f69a5
  switch (transition) {
Packit 1f69a5
    case GST_STATE_CHANGE_READY_TO_PAUSED:
Packit 1f69a5
    {
Packit 1f69a5
      GtkWindow *window = NULL;
Packit 1f69a5
Packit 1f69a5
      GST_OBJECT_LOCK (gtk_sink);
Packit 1f69a5
      if (gtk_sink->window)
Packit 1f69a5
        window = g_object_ref (GTK_WINDOW (gtk_sink->window));
Packit 1f69a5
      GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
Packit 1f69a5
      if (window)
Packit 1f69a5
        gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_widget_show_all_and_unref,
Packit 1f69a5
            window);
Packit 1f69a5
Packit 1f69a5
      break;
Packit 1f69a5
    }
Packit 1f69a5
    case GST_STATE_CHANGE_PAUSED_TO_READY:
Packit 1f69a5
      GST_OBJECT_LOCK (gtk_sink);
Packit 1f69a5
      if (gtk_sink->widget)
Packit 1f69a5
        gtk_gst_base_widget_set_buffer (gtk_sink->widget, NULL);
Packit 1f69a5
      GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
      break;
Packit 1f69a5
    default:
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  return ret;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_gtk_base_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
Packit 1f69a5
    GstClockTime * start, GstClockTime * end)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *gtk_sink;
Packit 1f69a5
Packit 1f69a5
  gtk_sink = GST_GTK_BASE_SINK (bsink);
Packit 1f69a5
Packit 1f69a5
  if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
Packit 1f69a5
    *start = GST_BUFFER_TIMESTAMP (buf);
Packit 1f69a5
    if (GST_BUFFER_DURATION_IS_VALID (buf))
Packit 1f69a5
      *end = *start + GST_BUFFER_DURATION (buf);
Packit 1f69a5
    else {
Packit 1f69a5
      if (GST_VIDEO_INFO_FPS_N (&gtk_sink->v_info) > 0) {
Packit 1f69a5
        *end = *start +
Packit 1f69a5
            gst_util_uint64_scale_int (GST_SECOND,
Packit 1f69a5
            GST_VIDEO_INFO_FPS_D (&gtk_sink->v_info),
Packit 1f69a5
            GST_VIDEO_INFO_FPS_N (&gtk_sink->v_info));
Packit 1f69a5
      }
Packit 1f69a5
    }
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
gboolean
Packit 1f69a5
gst_gtk_base_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (bsink);
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
Packit 1f69a5
Packit 1f69a5
  if (!gst_video_info_from_caps (&gtk_sink->v_info, caps))
Packit 1f69a5
    return FALSE;
Packit 1f69a5
Packit 1f69a5
  GST_OBJECT_LOCK (gtk_sink);
Packit 1f69a5
Packit 1f69a5
  if (gtk_sink->widget == NULL) {
Packit 1f69a5
    GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
    GST_ELEMENT_ERROR (gtk_sink, RESOURCE, NOT_FOUND,
Packit 1f69a5
        ("%s", "Output widget was destroyed"), (NULL));
Packit 1f69a5
    return FALSE;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  if (!gtk_gst_base_widget_set_format (gtk_sink->widget, &gtk_sink->v_info)) {
Packit 1f69a5
    GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
    return FALSE;
Packit 1f69a5
  }
Packit 1f69a5
  GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
Packit 1f69a5
  return TRUE;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static GstFlowReturn
Packit 1f69a5
gst_gtk_base_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
Packit 1f69a5
{
Packit 1f69a5
  GstGtkBaseSink *gtk_sink;
Packit 1f69a5
Packit 1f69a5
  GST_TRACE ("rendering buffer:%p", buf);
Packit 1f69a5
Packit 1f69a5
  gtk_sink = GST_GTK_BASE_SINK (vsink);
Packit 1f69a5
Packit 1f69a5
  GST_OBJECT_LOCK (vsink);
Packit 1f69a5
Packit 1f69a5
  if (gtk_sink->widget == NULL) {
Packit 1f69a5
    GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
    GST_ELEMENT_ERROR (gtk_sink, RESOURCE, NOT_FOUND,
Packit 1f69a5
        ("%s", "Output widget was destroyed"), (NULL));
Packit 1f69a5
    return GST_FLOW_ERROR;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  gtk_gst_base_widget_set_buffer (gtk_sink->widget, buf);
Packit 1f69a5
Packit 1f69a5
  GST_OBJECT_UNLOCK (gtk_sink);
Packit 1f69a5
Packit 1f69a5
  return GST_FLOW_OK;
Packit 1f69a5
}