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.
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.
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.
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:
#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);
#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
#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.