1

Is there a template for video sink in gstreamer, just like for plugin element ?

I have the idea for something very simple: one init function, render (display) function and deinit function. Nothing more.

2 Answers2

1

The best "templates" are the available source-code. Take a simple sink from -base or -good, and use that as a starting-point. It is also a great way to learn about GStreamer, understanding how a well written element behaves. The base-class you want is probably gstbasesink, since there is such a thing as a gstbaseaudiosink, but not (yet) a gstbasevideosink.

Havard Graff
  • 2,805
  • 1
  • 15
  • 16
0

I have also sought a sink "template" based on the gstbasesink and have not been able to find one. I followed the advise above to create one from the fakesink element that I have called vpphlsvideosink although it is not specifically a video sink (yet). It does nothing except send an 'r' char for rendering and an 'e' char for events to the std cout. These are the files:

  1. gstvpphlsvideosink.cpp
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "vpphlsvideosink.h"

static gboolean plugin_init (GstPlugin * plugin)
{
  return gst_element_register(plugin, "vpphlsvideosink", GST_RANK_NONE, GST_TYPE_VPPHLSVIDEOSINK);
}//end plugin_init.

// GST_PLUGIN_DEFINE needs PACKAGE to be defined.

#ifndef PACKAGE
#define PACKAGE "vpphlsvideosink"
#endif

#ifndef VERSION
#define VERSION "1.0.0.0"
#endif

#ifndef GST_PACKAGE_NAME
#define GST_PACKAGE_NAME "GStreamer"
#endif

#ifndef GST_PACKAGE_ORIGIN
#define GST_PACKAGE_ORIGIN "http://somewhere.net/"
#endif

GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
                   GST_VERSION_MINOR,
                   vpphlsvideosink,
                   "HLS Video Sink Plugin",
                   plugin_init, 
                     VERSION, 
                     "LGPL", 
                     GST_PACKAGE_NAME, 
                     GST_PACKAGE_ORIGIN);

  1. vpphlsvideosink.h
#pragma once

#include <gst/gst.h>
#include <gst/base/gstbasesink.h>

G_BEGIN_DECLS

// Definition of structure storing data for this element.
typedef struct _Gstvpphlsvideosink
{
  GstBaseSink element;
  gboolean    silent;
} Gstvpphlsvideosink;

// Standard definition defining a class for this element.
typedef struct _GstvpphlsvideosinkClass
{
  GstBaseSinkClass parent_class;
} GstvpphlsvideosinkClass;

// Standard macros for defining types for this element.
#define GST_TYPE_VPPHLSVIDEOSINK (gst_vpphlsvideosink_get_type())
#define GST_VPPHLSVIDEOSINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VPPHLSVIDEOSINK,Gstvpphlsvideosink))
#define GST_VPPHLSVIDEOSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VPPHLSVIDEOSINK,GstvpphlsvideosinkClass))
#define GST_IS_VPPHLSVIDEOSINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VPPHLSVIDEOSINK))
#define GST_IS_VPPHLSVIDEOSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VPPHLSVIDEOSINK))

GType gst_vpphlsvideosink_get_type(void);

G_END_DECLS

  1. vpphlsvideosink.cpp
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include "vpphlsvideosink.h"
#include <iostream>

using namespace std;

GST_DEBUG_CATEGORY_STATIC (gst_vpphlsvideosink_debug);
#define GST_CAT_DEFAULT gst_vpphlsvideosink_debug

#define DEFAULT_SYNC              true

#define DEFAULT_SILENT            false

// Filter signals and args
enum
{
  /* FILL ME */
  LAST_SIGNAL
};

enum
{
  PROP_0,
  PROP_SILENT
};

// The capabilities of the inputs and outputs.
static GstStaticPadTemplate sinkpadtemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("ANY"));

#define gst_vpphlsvideosink_parent_class parent_class

G_DEFINE_TYPE(Gstvpphlsvideosink, gst_vpphlsvideosink, GST_TYPE_BASE_SINK);

static void gst_vpphlsvideosink_set_property (GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec);
static void gst_vpphlsvideosink_get_property (GObject* object, guint prop_id, GValue* value, GParamSpec* pspec);
static void gst_vpphlsvideosink_finalize(GObject* obj);

static GstStateChangeReturn gst_vpphlsvideosink_change_state(GstElement* element,  GstStateChange transition);

static GstFlowReturn  gst_vpphlsvideosink_render(GstBaseSink* parent, GstBuffer* buffer);
static GstFlowReturn  gst_vpphlsvideosink_preroll(GstBaseSink* parent, GstBuffer* buffer);
static gboolean       gst_vpphlsvideosink_event(GstBaseSink* parent, GstEvent* event);
static gboolean       gst_vpphlsvideosink_query(GstBaseSink* parent, GstQuery* query);

// Use this when there is at least one signal enum defined
//static guint          gst_vpphlsvideosink_signals[LAST_SIGNAL] = { 0 };

// ------------- GObject virtual methods ------------------------------------------------------------------------------

// Initialize the vpphlsvideosink class
static void gst_vpphlsvideosink_class_init(GstvpphlsvideosinkClass* klass)
{
  GObjectClass*     gobject_class     = G_OBJECT_CLASS(klass);
  GstElementClass*  gstelement_class  = GST_ELEMENT_CLASS(klass);
  GstBaseSinkClass* gstbasesink_class = GST_BASE_SINK_CLASS(klass);

  gobject_class->set_property = gst_vpphlsvideosink_set_property;
  gobject_class->get_property = gst_vpphlsvideosink_get_property;
  gobject_class->finalize     = gst_vpphlsvideosink_finalize;

  g_object_class_install_property (gobject_class, PROP_SILENT,
                                   g_param_spec_boolean ("silent", "Silent", "Produce verbose output?",
                                   DEFAULT_SILENT, 
                                   (GParamFlags)(G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS)));

  gst_element_class_set_static_metadata(gstelement_class,
    "A VPP HLS Video Sink",
    "Sink/VPPHLSVIDEOSINK",
    "Writes video buffers to an externally defined queue",
    "Keith L Ferguson <<user@hostname.org>>");

  // The one sink pad template
  gst_element_class_add_static_pad_template(gstelement_class, &sinkpadtemplate);

  // Set override methods
  gstbasesink_class->render   = GST_DEBUG_FUNCPTR(gst_vpphlsvideosink_render);
  gstbasesink_class->preroll  = GST_DEBUG_FUNCPTR(gst_vpphlsvideosink_preroll);
  gstbasesink_class->event    = GST_DEBUG_FUNCPTR(gst_vpphlsvideosink_event);
  gstbasesink_class->query    = GST_DEBUG_FUNCPTR(gst_vpphlsvideosink_query);

}//end gst_vpphlsvideosink_class_init.

// Initialise the new element.
static void gst_vpphlsvideosink_init (Gstvpphlsvideosink* vsink)
{
  // On this sink class
  vsink->silent = DEFAULT_SILENT;

  // On the base class
  gst_base_sink_set_sync(GST_BASE_SINK(vsink), DEFAULT_SYNC);

}//end gst_vpphlsvideosink_init.

static void gst_vpphlsvideosink_finalize(GObject* obj)
{
  G_OBJECT_CLASS(parent_class)->finalize(obj);
}//end gst_vpphlsvideosink_finalize.

static void gst_vpphlsvideosink_set_property (GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
{
  Gstvpphlsvideosink* vsink = GST_VPPHLSVIDEOSINK (object);

  switch (prop_id) 
  {
    case PROP_SILENT:
      vsink->silent = g_value_get_boolean (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }//end switch prop_id...
}//end gst_vpphlsvideosink_set_property.

static void gst_vpphlsvideosink_get_property (GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
{
  Gstvpphlsvideosink* vsink = GST_VPPHLSVIDEOSINK (object);

  switch (prop_id) 
  {
    case PROP_SILENT:
      g_value_set_boolean (value, vsink->silent);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }//end switch prop_id...
}//end gst_vpphlsvideosink_get_property.

// -------------- GstBaseSink virtual methods ---------------------------------------------------------------

static GstFlowReturn gst_vpphlsvideosink_render(GstBaseSink* parent, GstBuffer* buffer)
{
  Gstvpphlsvideosink* vsink = GST_VPPHLSVIDEOSINK(parent);

  if (!vsink->silent)
    cout << "r";

  return GST_FLOW_OK;
}//end gst_vpphlsvideosink_render.

static GstFlowReturn gst_vpphlsvideosink_preroll(GstBaseSink* parent, GstBuffer* buffer)
{
  Gstvpphlsvideosink* vsink = GST_VPPHLSVIDEOSINK(parent);

  if (!vsink->silent)
    cout << "p";

  return GST_FLOW_OK;
}//end gst_vpphlsvideosink_preroll.

static gboolean gst_vpphlsvideosink_event(GstBaseSink* parent, GstEvent* event)
{
  Gstvpphlsvideosink* vsink = GST_VPPHLSVIDEOSINK(parent);

  if (!vsink->silent)
    cout << "e";

  return GST_BASE_SINK_CLASS(parent_class)->event(parent, event);
}//end gst_vpphlsvideosink_event.

static gboolean gst_vpphlsvideosink_query(GstBaseSink* parent, GstQuery* query)
{
  gboolean ret;

  switch (GST_QUERY_TYPE(query)) 
  {
    case GST_QUERY_SEEKING: 
    {
      // Seeking is not supported
      GstFormat fmt;
      gst_query_parse_seeking(query, &fmt, NULL, NULL, NULL);
      gst_query_set_seeking(query, fmt, FALSE, 0, -1);
      ret = TRUE;
      break;
    }
    default:
      ret = GST_BASE_SINK_CLASS(parent_class)->query(parent, query);
      break;
  }//end switch query...

  return ret;
}//end gst_vpphlsvideosink_query.

static GstStateChangeReturn gst_vpphlsvideosink_change_state(GstElement* element, GstStateChange transition)
{
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
  Gstvpphlsvideosink* vsink = GST_VPPHLSVIDEOSINK(element);

  ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
}//end gst_vpphlsvideosink_change_state.
Keith
  • 71
  • 4