mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-06 02:32:23 +00:00
basescope: add a backbuffer and apply shading effects
Keep the last frame and apply shade and geometry effects. Expose the shading effects as a controllable gobject property on the baseclass. https://bugzilla.gnome.org/show_bug.cgi?id=651536
This commit is contained in:
parent
2271946d73
commit
2cd10856d0
4 changed files with 182 additions and 12 deletions
|
@ -5,12 +5,13 @@ libgstscopes_la_SOURCES = \
|
||||||
gstspectrascope.c gstspectrascope.h \
|
gstspectrascope.c gstspectrascope.h \
|
||||||
gstwavescope.c gstwavescope.h
|
gstwavescope.c gstwavescope.h
|
||||||
|
|
||||||
libgstscopes_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS)\
|
libgstscopes_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) \
|
||||||
$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
|
$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
|
||||||
|
$(GST_CONTROLLER_CFLAGS) $(GST_CFLAGS)
|
||||||
libgstscopes_la_LIBADD = \
|
libgstscopes_la_LIBADD = \
|
||||||
$(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
|
$(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
|
||||||
-lgstvideo-$(GST_MAJORMINOR) -lgstfft-$(GST_MAJORMINOR) \
|
-lgstvideo-$(GST_MAJORMINOR) -lgstfft-$(GST_MAJORMINOR) \
|
||||||
$(GST_BASE_LIBS) $(GST_LIBS)
|
$(GST_BASE_LIBS) $(GST_CONTROLLER_LIBS) $(GST_LIBS) $(LIBM)
|
||||||
libgstscopes_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstscopes_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
libgstscopes_la_LIBTOOLFLAGS = --tag=disable-static
|
libgstscopes_la_LIBTOOLFLAGS = --tag=disable-static
|
||||||
|
|
||||||
|
|
|
@ -27,17 +27,30 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <gst/controller/gstcontroller.h>
|
||||||
|
|
||||||
#include "gstbasescope.h"
|
#include "gstbasescope.h"
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (base_scope_debug);
|
GST_DEBUG_CATEGORY_STATIC (base_scope_debug);
|
||||||
#define GST_CAT_DEFAULT (base_scope_debug)
|
#define GST_CAT_DEFAULT (base_scope_debug)
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_SHADER
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEFAULT_SHADER GST_BASE_SCOPE_SHADER_FADE
|
||||||
|
|
||||||
static GstBaseTransformClass *parent_class = NULL;
|
static GstBaseTransformClass *parent_class = NULL;
|
||||||
|
|
||||||
static void gst_base_scope_class_init (GstBaseScopeClass * klass);
|
static void gst_base_scope_class_init (GstBaseScopeClass * klass);
|
||||||
static void gst_base_scope_init (GstBaseScope * scope,
|
static void gst_base_scope_init (GstBaseScope * scope,
|
||||||
GstBaseScopeClass * g_class);
|
GstBaseScopeClass * g_class);
|
||||||
|
static void gst_base_scope_set_property (GObject * object, guint prop_id,
|
||||||
|
const GValue * value, GParamSpec * pspec);
|
||||||
|
static void gst_base_scope_get_property (GObject * object, guint prop_id,
|
||||||
|
GValue * value, GParamSpec * pspec);
|
||||||
static void gst_base_scope_dispose (GObject * object);
|
static void gst_base_scope_dispose (GObject * object);
|
||||||
|
|
||||||
static gboolean gst_base_scope_src_negotiate (GstBaseScope * scope);
|
static gboolean gst_base_scope_src_negotiate (GstBaseScope * scope);
|
||||||
|
@ -48,6 +61,73 @@ static GstFlowReturn gst_base_scope_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static GstStateChangeReturn gst_base_scope_change_state (GstElement * element,
|
static GstStateChangeReturn gst_base_scope_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
|
|
||||||
|
/* shading functions */
|
||||||
|
|
||||||
|
#define GST_TYPE_BASE_SCOPE_SHADER (gst_base_scope_shader_get_type())
|
||||||
|
static GType
|
||||||
|
gst_base_scope_shader_get_type (void)
|
||||||
|
{
|
||||||
|
static GType shader_type = 0;
|
||||||
|
static const GEnumValue shaders[] = {
|
||||||
|
{GST_BASE_SCOPE_SHADER_NONE, "None", "none"},
|
||||||
|
{GST_BASE_SCOPE_SHADER_FADE, "Fade", "fade"},
|
||||||
|
{GST_BASE_SCOPE_SHADER_FADE_AND_MOVE_UP, "Fade and move up",
|
||||||
|
"fade-and-move-up"},
|
||||||
|
{0, NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (G_UNLIKELY (shader_type == 0)) {
|
||||||
|
shader_type = g_enum_register_static ("GstBaseScopeShader", shaders);
|
||||||
|
}
|
||||||
|
return shader_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shader_fade (GstBaseScope * scope, const guint8 * s, guint8 * d)
|
||||||
|
{
|
||||||
|
guint i, bpf = scope->bpf;
|
||||||
|
|
||||||
|
for (i = 0; i < bpf; i++) {
|
||||||
|
d[i] = (s[i] > 10) ? s[i] - 10 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shader_fade_and_move_up (GstBaseScope * scope, const guint8 * s, guint8 * d)
|
||||||
|
{
|
||||||
|
guint i, j, bpf = scope->bpf;
|
||||||
|
guint bpl = 4 * scope->width;
|
||||||
|
|
||||||
|
for (j = 0, i = bpl; i < bpf; i++, j++) {
|
||||||
|
d[j] = (s[i] > 10) ? s[i] - 10 : 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < bpl; i++, j++) {
|
||||||
|
d[j] = (s[j] > 10) ? s[j] - 10 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_base_scope_change_shader (GstBaseScope * scope)
|
||||||
|
{
|
||||||
|
switch (scope->shader_type) {
|
||||||
|
case GST_BASE_SCOPE_SHADER_NONE:
|
||||||
|
scope->shader = NULL;
|
||||||
|
break;
|
||||||
|
case GST_BASE_SCOPE_SHADER_FADE:
|
||||||
|
scope->shader = shader_fade;
|
||||||
|
break;
|
||||||
|
case GST_BASE_SCOPE_SHADER_FADE_AND_MOVE_UP:
|
||||||
|
scope->shader = shader_fade_and_move_up;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GST_ERROR ("invalid shader function");
|
||||||
|
scope->shader = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* base class */
|
||||||
|
|
||||||
GType
|
GType
|
||||||
gst_base_scope_get_type (void)
|
gst_base_scope_get_type (void)
|
||||||
{
|
{
|
||||||
|
@ -85,8 +165,17 @@ gst_base_scope_class_init (GstBaseScopeClass * klass)
|
||||||
GST_DEBUG_CATEGORY_INIT (base_scope_debug, "basescope", 0,
|
GST_DEBUG_CATEGORY_INIT (base_scope_debug, "basescope", 0,
|
||||||
"scope audio visualisation base class");
|
"scope audio visualisation base class");
|
||||||
|
|
||||||
|
gobject_class->set_property = gst_base_scope_set_property;
|
||||||
|
gobject_class->get_property = gst_base_scope_get_property;
|
||||||
gobject_class->dispose = gst_base_scope_dispose;
|
gobject_class->dispose = gst_base_scope_dispose;
|
||||||
|
|
||||||
element_class->change_state = GST_DEBUG_FUNCPTR (gst_base_scope_change_state);
|
element_class->change_state = GST_DEBUG_FUNCPTR (gst_base_scope_change_state);
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_SHADER,
|
||||||
|
g_param_spec_enum ("shader", "shader type",
|
||||||
|
"Shader function to apply on each frame", GST_TYPE_BASE_SCOPE_SHADER,
|
||||||
|
DEFAULT_SHADER,
|
||||||
|
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -116,6 +205,10 @@ gst_base_scope_init (GstBaseScope * scope, GstBaseScopeClass * g_class)
|
||||||
scope->adapter = gst_adapter_new ();
|
scope->adapter = gst_adapter_new ();
|
||||||
scope->inbuf = gst_buffer_new ();
|
scope->inbuf = gst_buffer_new ();
|
||||||
|
|
||||||
|
/* properties */
|
||||||
|
scope->shader_type = DEFAULT_SHADER;
|
||||||
|
gst_base_scope_change_shader (scope);
|
||||||
|
|
||||||
/* reset the initial video state */
|
/* reset the initial video state */
|
||||||
scope->width = 320;
|
scope->width = 320;
|
||||||
scope->height = 200;
|
scope->height = 200;
|
||||||
|
@ -131,6 +224,39 @@ gst_base_scope_init (GstBaseScope * scope, GstBaseScopeClass * g_class)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_base_scope_set_property (GObject * object, guint prop_id,
|
||||||
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
GstBaseScope *scope = GST_BASE_SCOPE (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_SHADER:
|
||||||
|
scope->shader_type = g_value_get_enum (value);
|
||||||
|
gst_base_scope_change_shader (scope);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_base_scope_get_property (GObject * object, guint prop_id,
|
||||||
|
GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
GstBaseScope *scope = GST_BASE_SCOPE (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_SHADER:
|
||||||
|
g_value_set_enum (value, scope->shader_type);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_base_scope_dispose (GObject * object)
|
gst_base_scope_dispose (GObject * object)
|
||||||
{
|
{
|
||||||
|
@ -144,7 +270,10 @@ gst_base_scope_dispose (GObject * object)
|
||||||
gst_buffer_unref (scope->inbuf);
|
gst_buffer_unref (scope->inbuf);
|
||||||
scope->inbuf = NULL;
|
scope->inbuf = NULL;
|
||||||
}
|
}
|
||||||
|
if (scope->pixelbuf) {
|
||||||
|
g_free (scope->pixelbuf);
|
||||||
|
scope->pixelbuf = NULL;
|
||||||
|
}
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,6 +409,12 @@ gst_base_scope_src_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
scope->fps_d, scope->fps_n);
|
scope->fps_d, scope->fps_n);
|
||||||
scope->req_spf = scope->spf;
|
scope->req_spf = scope->spf;
|
||||||
|
|
||||||
|
scope->bpf = w * h * 4;
|
||||||
|
|
||||||
|
if (scope->pixelbuf)
|
||||||
|
g_free (scope->pixelbuf);
|
||||||
|
scope->pixelbuf = g_malloc0 (scope->bpf);
|
||||||
|
|
||||||
if (klass->setup)
|
if (klass->setup)
|
||||||
res = klass->setup (scope);
|
res = klass->setup (scope);
|
||||||
|
|
||||||
|
@ -309,7 +444,6 @@ gst_base_scope_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
GstBaseScopeClass *klass;
|
GstBaseScopeClass *klass;
|
||||||
GstBuffer *inbuf;
|
GstBuffer *inbuf;
|
||||||
guint avail, sbpf;
|
guint avail, sbpf;
|
||||||
guint bpp;
|
|
||||||
gboolean (*render) (GstBaseScope * scope, GstBuffer * audio,
|
gboolean (*render) (GstBaseScope * scope, GstBuffer * audio,
|
||||||
GstBuffer * video);
|
GstBuffer * video);
|
||||||
|
|
||||||
|
@ -340,8 +474,6 @@ gst_base_scope_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
/* this is what we want */
|
/* this is what we want */
|
||||||
sbpf = scope->req_spf * scope->channels * sizeof (gint16);
|
sbpf = scope->req_spf * scope->channels * sizeof (gint16);
|
||||||
|
|
||||||
bpp = gst_video_format_get_pixel_stride (scope->video_format, 0);
|
|
||||||
|
|
||||||
inbuf = scope->inbuf;
|
inbuf = scope->inbuf;
|
||||||
/* FIXME: the timestamp in the adapter would be different */
|
/* FIXME: the timestamp in the adapter would be different */
|
||||||
gst_buffer_copy_metadata (inbuf, buffer, GST_BUFFER_COPY_ALL);
|
gst_buffer_copy_metadata (inbuf, buffer, GST_BUFFER_COPY_ALL);
|
||||||
|
@ -353,26 +485,38 @@ gst_base_scope_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
ret = gst_pad_alloc_buffer_and_set_caps (scope->srcpad,
|
ret = gst_pad_alloc_buffer_and_set_caps (scope->srcpad,
|
||||||
GST_BUFFER_OFFSET_NONE,
|
GST_BUFFER_OFFSET_NONE,
|
||||||
scope->width * scope->height * bpp,
|
scope->bpf, GST_PAD_CAPS (scope->srcpad), &outbuf);
|
||||||
GST_PAD_CAPS (scope->srcpad), &outbuf);
|
|
||||||
|
|
||||||
/* no buffer allocated, we don't care why. */
|
/* no buffer allocated, we don't care why. */
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* sync controlled properties */
|
||||||
|
gst_object_sync_values (G_OBJECT (scope), scope->next_ts);
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = scope->next_ts;
|
GST_BUFFER_TIMESTAMP (outbuf) = scope->next_ts;
|
||||||
GST_BUFFER_DURATION (outbuf) = scope->frame_duration;
|
GST_BUFFER_DURATION (outbuf) = scope->frame_duration;
|
||||||
memset (GST_BUFFER_DATA (outbuf), 0, GST_BUFFER_SIZE (outbuf));
|
if (scope->shader) {
|
||||||
|
memcpy (GST_BUFFER_DATA (outbuf), scope->pixelbuf, scope->bpf);
|
||||||
|
} else {
|
||||||
|
memset (GST_BUFFER_DATA (outbuf), 0, scope->bpf);
|
||||||
|
}
|
||||||
|
|
||||||
GST_BUFFER_DATA (inbuf) =
|
GST_BUFFER_DATA (inbuf) =
|
||||||
(guint8 *) gst_adapter_peek (scope->adapter, sbpf);
|
(guint8 *) gst_adapter_peek (scope->adapter, sbpf);
|
||||||
GST_BUFFER_SIZE (inbuf) = sbpf;
|
GST_BUFFER_SIZE (inbuf) = sbpf;
|
||||||
|
|
||||||
/* call class->render() vmethod */
|
/* call class->render() vmethod */
|
||||||
if (render)
|
if (render) {
|
||||||
if (!render (scope, inbuf, outbuf)) {
|
if (!render (scope, inbuf, outbuf)) {
|
||||||
ret = GST_FLOW_ERROR;
|
ret = GST_FLOW_ERROR;
|
||||||
|
} else {
|
||||||
|
/* run various post processing (shading and geometri transformation */
|
||||||
|
if (scope->shader) {
|
||||||
|
scope->shader (scope, GST_BUFFER_DATA (outbuf), scope->pixelbuf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = gst_pad_push (scope->srcpad, outbuf);
|
ret = gst_pad_push (scope->srcpad, outbuf);
|
||||||
outbuf = NULL;
|
outbuf = NULL;
|
||||||
|
|
|
@ -37,6 +37,22 @@ G_BEGIN_DECLS
|
||||||
typedef struct _GstBaseScope GstBaseScope;
|
typedef struct _GstBaseScope GstBaseScope;
|
||||||
typedef struct _GstBaseScopeClass GstBaseScopeClass;
|
typedef struct _GstBaseScopeClass GstBaseScopeClass;
|
||||||
|
|
||||||
|
typedef void (*GstBaseScopeShaderFunc)(GstBaseScope *scope, const guint8 *s, guint8 *d);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstBaseScopeShader:
|
||||||
|
* @GST_BASE_SCOPE_SHADER_NONE: no shading
|
||||||
|
* @GST_BASE_SCOPE_SHADER_FADE: plain fading
|
||||||
|
* @GST_BASE_SCOPE_SHADER_FADE_AND_MOVE_UP: fade and move up
|
||||||
|
*
|
||||||
|
* Different types of supported background shading functions.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
GST_BASE_SCOPE_SHADER_NONE,
|
||||||
|
GST_BASE_SCOPE_SHADER_FADE,
|
||||||
|
GST_BASE_SCOPE_SHADER_FADE_AND_MOVE_UP
|
||||||
|
} GstBaseScopeShader;
|
||||||
|
|
||||||
struct _GstBaseScope
|
struct _GstBaseScope
|
||||||
{
|
{
|
||||||
GstElement parent;
|
GstElement parent;
|
||||||
|
@ -46,10 +62,15 @@ struct _GstBaseScope
|
||||||
|
|
||||||
GstAdapter *adapter;
|
GstAdapter *adapter;
|
||||||
GstBuffer *inbuf;
|
GstBuffer *inbuf;
|
||||||
|
guint8 *pixelbuf;
|
||||||
|
|
||||||
|
GstBaseScopeShader shader_type;
|
||||||
|
GstBaseScopeShaderFunc shader;
|
||||||
|
|
||||||
guint64 next_ts; /* the timestamp of the next frame */
|
guint64 next_ts; /* the timestamp of the next frame */
|
||||||
guint64 frame_duration;
|
guint64 frame_duration;
|
||||||
guint bps; /* bytes per sample */
|
guint bpf; /* bytes per frame */
|
||||||
|
guint bps; /* bytes per sample */
|
||||||
guint spf; /* samples per video frame */
|
guint spf; /* samples per video frame */
|
||||||
guint req_spf; /* min samples per frame wanted by the subclass */
|
guint req_spf; /* min samples per frame wanted by the subclass */
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/controller/gstcontroller.h>
|
||||||
|
|
||||||
#include "gstspectrascope.h"
|
#include "gstspectrascope.h"
|
||||||
#include "gstsynaescope.h"
|
#include "gstsynaescope.h"
|
||||||
|
@ -32,6 +33,9 @@ plugin_init (GstPlugin * plugin)
|
||||||
{
|
{
|
||||||
gboolean res = TRUE;
|
gboolean res = TRUE;
|
||||||
|
|
||||||
|
/* initialize gst controller library */
|
||||||
|
gst_controller_init (NULL, NULL);
|
||||||
|
|
||||||
res &= gst_spectra_scope_plugin_init (plugin);
|
res &= gst_spectra_scope_plugin_init (plugin);
|
||||||
res &= gst_wave_scope_plugin_init (plugin);
|
res &= gst_wave_scope_plugin_init (plugin);
|
||||||
return res;
|
return res;
|
||||||
|
|
Loading…
Reference in a new issue