mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-03 21:12:26 +00:00
audiovisualizer: port to 0.11
This commit is contained in:
parent
02de08aaaa
commit
f8abc7e734
7 changed files with 506 additions and 203 deletions
|
@ -294,7 +294,7 @@ dnl *** plug-ins to include ***
|
||||||
dnl Non ported plugins (non-dependant, then dependant)
|
dnl Non ported plugins (non-dependant, then dependant)
|
||||||
dnl Make sure you have a space before and after all plugins
|
dnl Make sure you have a space before and after all plugins
|
||||||
GST_PLUGINS_NONPORTED=" adpcmdec adpcmenc aiff asfmux \
|
GST_PLUGINS_NONPORTED=" adpcmdec adpcmenc aiff asfmux \
|
||||||
audiovisualizers autoconvert camerabin cdxaparse coloreffects \
|
autoconvert camerabin cdxaparse coloreffects \
|
||||||
dccp debugutils dtmf faceoverlay festival \
|
dccp debugutils dtmf faceoverlay festival \
|
||||||
fieldanalysis freeze frei0r gaudieffects geometrictransform h264parse \
|
fieldanalysis freeze frei0r gaudieffects geometrictransform h264parse \
|
||||||
hdvparse hls id3tag inter interlace ivfparse jpegformat jp2kdecimator \
|
hdvparse hls id3tag inter interlace ivfparse jpegformat jp2kdecimator \
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <gst/controller/gstcontroller.h>
|
|
||||||
|
|
||||||
#include "gstbaseaudiovisualizer.h"
|
#include "gstbaseaudiovisualizer.h"
|
||||||
|
|
||||||
|
@ -64,13 +63,24 @@ static void gst_base_audio_visualizer_dispose (GObject * object);
|
||||||
|
|
||||||
static gboolean gst_base_audio_visualizer_src_negotiate (GstBaseAudioVisualizer
|
static gboolean gst_base_audio_visualizer_src_negotiate (GstBaseAudioVisualizer
|
||||||
* scope);
|
* scope);
|
||||||
static gboolean gst_base_audio_visualizer_src_setcaps (GstPad * pad,
|
static gboolean gst_base_audio_visualizer_src_setcaps (GstBaseAudioVisualizer *
|
||||||
GstCaps * caps);
|
scope, GstCaps * caps);
|
||||||
static gboolean gst_base_audio_visualizer_sink_setcaps (GstPad * pad,
|
static gboolean gst_base_audio_visualizer_sink_setcaps (GstBaseAudioVisualizer *
|
||||||
GstCaps * caps);
|
scope, GstCaps * caps);
|
||||||
|
|
||||||
static GstFlowReturn gst_base_audio_visualizer_chain (GstPad * pad,
|
static GstFlowReturn gst_base_audio_visualizer_chain (GstPad * pad,
|
||||||
GstBuffer * buffer);
|
GstBuffer * buffer);
|
||||||
|
|
||||||
|
static gboolean gst_base_audio_visualizer_src_event (GstPad * pad,
|
||||||
|
GstEvent * event);
|
||||||
|
static gboolean gst_base_audio_visualizer_sink_event (GstPad * pad,
|
||||||
|
GstEvent * event);
|
||||||
|
|
||||||
|
static gboolean gst_base_audio_visualizer_src_query (GstPad * pad,
|
||||||
|
GstQuery * query);
|
||||||
|
static gboolean gst_base_audio_visualizer_sink_query (GstPad * pad,
|
||||||
|
GstQuery * query);
|
||||||
|
|
||||||
static GstStateChangeReturn gst_base_audio_visualizer_change_state (GstElement *
|
static GstStateChangeReturn gst_base_audio_visualizer_change_state (GstElement *
|
||||||
element, GstStateChange transition);
|
element, GstStateChange transition);
|
||||||
|
|
||||||
|
@ -456,16 +466,20 @@ gst_base_audio_visualizer_init (GstBaseAudioVisualizer * scope,
|
||||||
scope->sinkpad = gst_pad_new_from_template (pad_template, "sink");
|
scope->sinkpad = gst_pad_new_from_template (pad_template, "sink");
|
||||||
gst_pad_set_chain_function (scope->sinkpad,
|
gst_pad_set_chain_function (scope->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_chain));
|
GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_chain));
|
||||||
gst_pad_set_setcaps_function (scope->sinkpad,
|
gst_pad_set_event_function (scope->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_sink_setcaps));
|
GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_sink_event));
|
||||||
|
gst_pad_set_query_function (scope->sinkpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_sink_query));
|
||||||
gst_element_add_pad (GST_ELEMENT (scope), scope->sinkpad);
|
gst_element_add_pad (GST_ELEMENT (scope), scope->sinkpad);
|
||||||
|
|
||||||
pad_template =
|
pad_template =
|
||||||
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
|
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
|
||||||
g_return_if_fail (pad_template != NULL);
|
g_return_if_fail (pad_template != NULL);
|
||||||
scope->srcpad = gst_pad_new_from_template (pad_template, "src");
|
scope->srcpad = gst_pad_new_from_template (pad_template, "src");
|
||||||
gst_pad_set_setcaps_function (scope->srcpad,
|
gst_pad_set_event_function (scope->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_src_setcaps));
|
GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_src_event));
|
||||||
|
gst_pad_set_query_function (scope->srcpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_src_query));
|
||||||
gst_element_add_pad (GST_ELEMENT (scope), scope->srcpad);
|
gst_element_add_pad (GST_ELEMENT (scope), scope->srcpad);
|
||||||
|
|
||||||
scope->adapter = gst_adapter_new ();
|
scope->adapter = gst_adapter_new ();
|
||||||
|
@ -487,8 +501,6 @@ gst_base_audio_visualizer_init (GstBaseAudioVisualizer * scope,
|
||||||
scope->rate = GST_AUDIO_DEF_RATE;
|
scope->rate = GST_AUDIO_DEF_RATE;
|
||||||
scope->channels = 2;
|
scope->channels = 2;
|
||||||
|
|
||||||
scope->next_ts = GST_CLOCK_TIME_NONE;
|
|
||||||
|
|
||||||
scope->config_lock = g_mutex_new ();
|
scope->config_lock = g_mutex_new ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,16 +567,27 @@ gst_base_audio_visualizer_dispose (GObject * object)
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_base_audio_visualizer_sink_setcaps (GstPad * pad, GstCaps * caps)
|
gst_base_audio_visualizer_reset (GstBaseAudioVisualizer * scope)
|
||||||
|
{
|
||||||
|
gst_adapter_clear (scope->adapter);
|
||||||
|
gst_segment_init (&scope->segment, GST_FORMAT_UNDEFINED);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (scope);
|
||||||
|
scope->proportion = 1.0;
|
||||||
|
scope->earliest_time = -1;
|
||||||
|
GST_OBJECT_UNLOCK (scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_base_audio_visualizer_sink_setcaps (GstBaseAudioVisualizer * scope,
|
||||||
|
GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstBaseAudioVisualizer *scope;
|
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
gint channels;
|
gint channels;
|
||||||
gint rate;
|
gint rate;
|
||||||
gboolean res = TRUE;
|
gboolean res = TRUE;
|
||||||
|
|
||||||
scope = GST_BASE_AUDIO_VISUALIZER (gst_pad_get_parent (pad));
|
|
||||||
structure = gst_caps_get_structure (caps, 0);
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
if (!gst_structure_get_int (structure, "channels", &channels) ||
|
if (!gst_structure_get_int (structure, "channels", &channels) ||
|
||||||
|
@ -584,7 +607,6 @@ gst_base_audio_visualizer_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
scope->channels, scope->rate);
|
scope->channels, scope->rate);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
gst_object_unref (scope);
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* Errors */
|
/* Errors */
|
||||||
|
@ -610,78 +632,23 @@ wrong_rate:
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_audio_visualizer_src_negotiate (GstBaseAudioVisualizer * scope)
|
gst_base_audio_visualizer_src_setcaps (GstBaseAudioVisualizer * scope,
|
||||||
|
GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstCaps *othercaps, *target, *intersect;
|
|
||||||
GstStructure *structure;
|
|
||||||
const GstCaps *templ;
|
|
||||||
|
|
||||||
templ = gst_pad_get_pad_template_caps (scope->srcpad);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (scope, "performing negotiation");
|
|
||||||
|
|
||||||
/* see what the peer can do */
|
|
||||||
othercaps = gst_pad_peer_get_caps (scope->srcpad);
|
|
||||||
if (othercaps) {
|
|
||||||
intersect = gst_caps_intersect (othercaps, templ);
|
|
||||||
gst_caps_unref (othercaps);
|
|
||||||
|
|
||||||
if (gst_caps_is_empty (intersect))
|
|
||||||
goto no_format;
|
|
||||||
|
|
||||||
target = gst_caps_copy_nth (intersect, 0);
|
|
||||||
gst_caps_unref (intersect);
|
|
||||||
} else {
|
|
||||||
target = gst_caps_ref ((GstCaps *) templ);
|
|
||||||
}
|
|
||||||
|
|
||||||
structure = gst_caps_get_structure (target, 0);
|
|
||||||
gst_structure_fixate_field_nearest_int (structure, "width", scope->width);
|
|
||||||
gst_structure_fixate_field_nearest_int (structure, "height", scope->height);
|
|
||||||
gst_structure_fixate_field_nearest_fraction (structure, "framerate",
|
|
||||||
scope->fps_n, scope->fps_d);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (scope, "final caps are %" GST_PTR_FORMAT, target);
|
|
||||||
|
|
||||||
gst_pad_set_caps (scope->srcpad, target);
|
|
||||||
gst_caps_unref (target);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
no_format:
|
|
||||||
{
|
|
||||||
gst_caps_unref (intersect);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_base_audio_visualizer_src_setcaps (GstPad * pad, GstCaps * caps)
|
|
||||||
{
|
|
||||||
GstBaseAudioVisualizer *scope;
|
|
||||||
GstBaseAudioVisualizerClass *klass;
|
GstBaseAudioVisualizerClass *klass;
|
||||||
gint w, h;
|
GstStructure *structure;
|
||||||
gint num, denom;
|
gboolean res;
|
||||||
GstVideoFormat format;
|
|
||||||
gboolean res = TRUE;
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
|
if (!gst_structure_get_int (structure, "width", &scope->width) ||
|
||||||
|
!gst_structure_get_int (structure, "height", &scope->height) ||
|
||||||
|
!gst_structure_get_fraction (structure, "framerate", &scope->fps_n,
|
||||||
|
&scope->fps_d))
|
||||||
|
goto error;
|
||||||
|
|
||||||
scope = GST_BASE_AUDIO_VISUALIZER (gst_pad_get_parent (pad));
|
|
||||||
klass = GST_BASE_AUDIO_VISUALIZER_CLASS (G_OBJECT_GET_CLASS (scope));
|
klass = GST_BASE_AUDIO_VISUALIZER_CLASS (G_OBJECT_GET_CLASS (scope));
|
||||||
|
|
||||||
if (!gst_video_format_parse_caps (caps, &format, &w, &h)) {
|
//scope->video_format = format; ??
|
||||||
goto missing_caps_details;
|
|
||||||
}
|
|
||||||
if (!gst_video_parse_caps_framerate (caps, &num, &denom)) {
|
|
||||||
goto missing_caps_details;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_mutex_lock (scope->config_lock);
|
|
||||||
|
|
||||||
scope->width = w;
|
|
||||||
scope->height = h;
|
|
||||||
scope->fps_n = num;
|
|
||||||
scope->fps_d = denom;
|
|
||||||
scope->video_format = format;
|
|
||||||
|
|
||||||
scope->frame_duration = gst_util_uint64_scale_int (GST_SECOND,
|
scope->frame_duration = gst_util_uint64_scale_int (GST_SECOND,
|
||||||
scope->fps_d, scope->fps_n);
|
scope->fps_d, scope->fps_n);
|
||||||
|
@ -689,7 +656,7 @@ gst_base_audio_visualizer_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;
|
scope->bpf = scope->width * scope->height * 4;
|
||||||
|
|
||||||
if (scope->pixelbuf)
|
if (scope->pixelbuf)
|
||||||
g_free (scope->pixelbuf);
|
g_free (scope->pixelbuf);
|
||||||
|
@ -703,22 +670,121 @@ gst_base_audio_visualizer_src_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
GST_DEBUG_OBJECT (scope, "blocks: spf %u, req_spf %u",
|
GST_DEBUG_OBJECT (scope, "blocks: spf %u, req_spf %u",
|
||||||
scope->spf, scope->req_spf);
|
scope->spf, scope->req_spf);
|
||||||
|
|
||||||
g_mutex_unlock (scope->config_lock);
|
res = gst_pad_push_event (scope->srcpad, gst_event_new_caps (caps));
|
||||||
|
|
||||||
done:
|
|
||||||
gst_object_unref (scope);
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* Errors */
|
/* ERRORS */
|
||||||
missing_caps_details:
|
error:
|
||||||
{
|
{
|
||||||
GST_WARNING_OBJECT (scope,
|
GST_DEBUG_OBJECT (scope, "error parsing caps");
|
||||||
"missing width, height or framerate in the caps");
|
return FALSE;
|
||||||
res = FALSE;
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_base_audio_visualizer_src_negotiate (GstBaseAudioVisualizer * scope)
|
||||||
|
{
|
||||||
|
GstCaps *othercaps, *target;
|
||||||
|
GstStructure *structure;
|
||||||
|
GstCaps *templ;
|
||||||
|
GstQuery *query;
|
||||||
|
GstBufferPool *pool = NULL;
|
||||||
|
guint size, min, max, prefix, alignment;
|
||||||
|
|
||||||
|
templ = gst_pad_get_pad_template_caps (scope->srcpad);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (scope, "performing negotiation");
|
||||||
|
|
||||||
|
/* see what the peer can do */
|
||||||
|
othercaps = gst_pad_peer_get_caps (scope->srcpad, NULL);
|
||||||
|
if (othercaps) {
|
||||||
|
target = gst_caps_intersect (othercaps, templ);
|
||||||
|
gst_caps_unref (othercaps);
|
||||||
|
gst_caps_unref (templ);
|
||||||
|
|
||||||
|
if (gst_caps_is_empty (target))
|
||||||
|
goto no_format;
|
||||||
|
|
||||||
|
gst_caps_truncate (target);
|
||||||
|
} else {
|
||||||
|
target = gst_caps_ref ((GstCaps *) templ);
|
||||||
|
}
|
||||||
|
|
||||||
|
structure = gst_caps_get_structure (target, 0);
|
||||||
|
gst_structure_fixate_field_nearest_int (structure, "width", scope->width);
|
||||||
|
gst_structure_fixate_field_nearest_int (structure, "height", scope->height);
|
||||||
|
gst_structure_fixate_field_nearest_fraction (structure, "framerate",
|
||||||
|
scope->fps_n, scope->fps_d);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (scope, "final caps are %" GST_PTR_FORMAT, target);
|
||||||
|
|
||||||
|
gst_base_audio_visualizer_src_setcaps (scope, target);
|
||||||
|
|
||||||
|
/* try to get a bufferpool now */
|
||||||
|
/* find a pool for the negotiated caps now */
|
||||||
|
query = gst_query_new_allocation (target, TRUE);
|
||||||
|
|
||||||
|
if (gst_pad_peer_query (scope->srcpad, query)) {
|
||||||
|
/* we got configuration from our peer, parse them */
|
||||||
|
gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
|
||||||
|
&alignment, &pool);
|
||||||
|
} else {
|
||||||
|
size = scope->bpf;
|
||||||
|
min = max = 0;
|
||||||
|
prefix = 0;
|
||||||
|
alignment = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pool == NULL) {
|
||||||
|
GstStructure *config;
|
||||||
|
|
||||||
|
/* we did not get a pool, make one ourselves then */
|
||||||
|
pool = gst_buffer_pool_new ();
|
||||||
|
|
||||||
|
config = gst_buffer_pool_get_config (pool);
|
||||||
|
gst_buffer_pool_config_set (config, target, size, min, max, prefix,
|
||||||
|
alignment);
|
||||||
|
gst_buffer_pool_set_config (pool, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scope->pool)
|
||||||
|
gst_object_unref (scope->pool);
|
||||||
|
scope->pool = pool;
|
||||||
|
|
||||||
|
/* and activate */
|
||||||
|
gst_buffer_pool_set_active (pool, TRUE);
|
||||||
|
|
||||||
|
gst_caps_unref (target);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
no_format:
|
||||||
|
{
|
||||||
|
gst_caps_unref (target);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure we are negotiated */
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_base_audio_visualizer_ensure_negotiated (GstBaseAudioVisualizer * scope)
|
||||||
|
{
|
||||||
|
gboolean reconfigure;
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (scope->srcpad);
|
||||||
|
reconfigure = GST_PAD_NEEDS_RECONFIGURE (scope->srcpad);
|
||||||
|
GST_OBJECT_FLAG_UNSET (scope->srcpad, GST_PAD_NEED_RECONFIGURE);
|
||||||
|
GST_OBJECT_UNLOCK (scope->srcpad);
|
||||||
|
|
||||||
|
/* we don't know an output format yet, pick one */
|
||||||
|
if (reconfigure || !gst_pad_has_current_caps (scope->srcpad)) {
|
||||||
|
if (!gst_base_audio_visualizer_src_negotiate (scope))
|
||||||
|
return GST_FLOW_NOT_NEGOTIATED;
|
||||||
|
}
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer)
|
gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
|
@ -726,8 +792,9 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
GstBaseAudioVisualizer *scope;
|
GstBaseAudioVisualizer *scope;
|
||||||
GstBaseAudioVisualizerClass *klass;
|
GstBaseAudioVisualizerClass *klass;
|
||||||
GstBuffer *inbuf;
|
GstBuffer *inbuf;
|
||||||
|
guint64 dist, ts;
|
||||||
guint avail, sbpf;
|
guint avail, sbpf;
|
||||||
guint8 *adata;
|
gpointer adata, vdata;
|
||||||
gboolean (*render) (GstBaseAudioVisualizer * scope, GstBuffer * audio,
|
gboolean (*render) (GstBaseAudioVisualizer * scope, GstBuffer * audio,
|
||||||
GstBuffer * video);
|
GstBuffer * video);
|
||||||
|
|
||||||
|
@ -740,18 +807,19 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
/* resync on DISCONT */
|
/* resync on DISCONT */
|
||||||
if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
|
if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
|
||||||
scope->next_ts = GST_CLOCK_TIME_NONE;
|
|
||||||
gst_adapter_clear (scope->adapter);
|
gst_adapter_clear (scope->adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_PAD_CAPS (scope->srcpad) == NULL) {
|
if (scope->bps == 0) {
|
||||||
if (!gst_base_audio_visualizer_src_negotiate (scope))
|
ret = GST_FLOW_NOT_NEGOTIATED;
|
||||||
return GST_FLOW_NOT_NEGOTIATED;
|
goto beach;
|
||||||
|
}
|
||||||
|
/* Make sure have an output format */
|
||||||
|
ret = gst_base_audio_visualizer_ensure_negotiated (scope);
|
||||||
|
if (ret != GST_FLOW_OK) {
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
goto beach;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Match timestamps from the incoming audio */
|
|
||||||
if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE)
|
|
||||||
scope->next_ts = GST_BUFFER_TIMESTAMP (buffer);
|
|
||||||
|
|
||||||
gst_adapter_push (scope->adapter, buffer);
|
gst_adapter_push (scope->adapter, buffer);
|
||||||
|
|
||||||
|
@ -762,7 +830,7 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
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_into (inbuf, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
|
||||||
|
|
||||||
/* this is what we have */
|
/* this is what we have */
|
||||||
avail = gst_adapter_available (scope->adapter);
|
avail = gst_adapter_available (scope->adapter);
|
||||||
|
@ -770,10 +838,37 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
while (avail >= sbpf) {
|
while (avail >= sbpf) {
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
|
|
||||||
|
/* get timestamp of the current adapter content */
|
||||||
|
ts = gst_adapter_prev_timestamp (scope->adapter, &dist);
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (ts)) {
|
||||||
|
/* convert bytes to time */
|
||||||
|
dist /= scope->bps;
|
||||||
|
ts += gst_util_uint64_scale_int (dist, GST_SECOND, scope->rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (ts)) {
|
||||||
|
gint64 qostime;
|
||||||
|
gboolean need_skip;
|
||||||
|
|
||||||
|
qostime =
|
||||||
|
gst_segment_to_running_time (&scope->segment, GST_FORMAT_TIME, ts) +
|
||||||
|
scope->frame_duration;
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (scope);
|
||||||
|
/* check for QoS, don't compute buffers that are known to be late */
|
||||||
|
need_skip = scope->earliest_time != -1 && qostime <= scope->earliest_time;
|
||||||
|
GST_OBJECT_UNLOCK (scope);
|
||||||
|
|
||||||
|
if (need_skip) {
|
||||||
|
GST_WARNING_OBJECT (scope,
|
||||||
|
"QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (qostime), GST_TIME_ARGS (scope->earliest_time));
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_mutex_unlock (scope->config_lock);
|
g_mutex_unlock (scope->config_lock);
|
||||||
ret = gst_pad_alloc_buffer_and_set_caps (scope->srcpad,
|
ret = gst_buffer_pool_acquire_buffer (scope->pool, &outbuf, NULL);
|
||||||
GST_BUFFER_OFFSET_NONE,
|
|
||||||
scope->bpf, GST_PAD_CAPS (scope->srcpad), &outbuf);
|
|
||||||
g_mutex_lock (scope->config_lock);
|
g_mutex_lock (scope->config_lock);
|
||||||
/* recheck as the value could have changed */
|
/* recheck as the value could have changed */
|
||||||
sbpf = scope->req_spf * scope->channels * sizeof (gint16);
|
sbpf = scope->req_spf * scope->channels * sizeof (gint16);
|
||||||
|
@ -783,22 +878,25 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* sync controlled properties */
|
/* sync controlled properties */
|
||||||
gst_object_sync_values (GST_OBJECT (scope), scope->next_ts);
|
gst_object_sync_values (GST_OBJECT (scope), ts);
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = scope->next_ts;
|
GST_BUFFER_TIMESTAMP (outbuf) = ts;
|
||||||
GST_BUFFER_DURATION (outbuf) = scope->frame_duration;
|
GST_BUFFER_DURATION (outbuf) = scope->frame_duration;
|
||||||
|
|
||||||
|
vdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
|
||||||
if (scope->shader) {
|
if (scope->shader) {
|
||||||
memcpy (GST_BUFFER_DATA (outbuf), scope->pixelbuf, scope->bpf);
|
memcpy (vdata, scope->pixelbuf, scope->bpf);
|
||||||
} else {
|
} else {
|
||||||
memset (GST_BUFFER_DATA (outbuf), 0, scope->bpf);
|
memset (vdata, 0, scope->bpf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this can fail as the data size we need could have changed */
|
/* this can fail as the data size we need could have changed */
|
||||||
if (!(adata = (guint8 *) gst_adapter_peek (scope->adapter, sbpf)))
|
if (!(adata = (gpointer) gst_adapter_map (scope->adapter, sbpf)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
GST_BUFFER_DATA (inbuf) = adata;
|
gst_buffer_take_memory (inbuf, -1,
|
||||||
GST_BUFFER_SIZE (inbuf) = sbpf;
|
gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, adata, NULL, sbpf, 0,
|
||||||
|
sbpf));
|
||||||
|
|
||||||
/* call class->render() vmethod */
|
/* call class->render() vmethod */
|
||||||
if (render) {
|
if (render) {
|
||||||
|
@ -807,59 +905,243 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
} else {
|
} else {
|
||||||
/* run various post processing (shading and geometri transformation */
|
/* run various post processing (shading and geometri transformation */
|
||||||
if (scope->shader) {
|
if (scope->shader) {
|
||||||
scope->shader (scope, GST_BUFFER_DATA (outbuf), scope->pixelbuf);
|
scope->shader (scope, vdata, scope->pixelbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_buffer_unmap (outbuf, vdata, scope->bpf);
|
||||||
|
|
||||||
g_mutex_unlock (scope->config_lock);
|
g_mutex_unlock (scope->config_lock);
|
||||||
ret = gst_pad_push (scope->srcpad, outbuf);
|
ret = gst_pad_push (scope->srcpad, outbuf);
|
||||||
outbuf = NULL;
|
outbuf = NULL;
|
||||||
g_mutex_lock (scope->config_lock);
|
g_mutex_lock (scope->config_lock);
|
||||||
|
|
||||||
|
skip:
|
||||||
/* recheck as the value could have changed */
|
/* recheck as the value could have changed */
|
||||||
sbpf = scope->req_spf * scope->channels * sizeof (gint16);
|
sbpf = scope->req_spf * scope->channels * sizeof (gint16);
|
||||||
GST_LOG_OBJECT (scope, "avail: %u, bpf: %u", avail, sbpf);
|
GST_LOG_OBJECT (scope, "avail: %u, bpf: %u", avail, sbpf);
|
||||||
/* we want to take less or more, depending on spf : req_spf */
|
/* we want to take less or more, depending on spf : req_spf */
|
||||||
if (avail - sbpf >= sbpf) {
|
if (avail - sbpf >= sbpf) {
|
||||||
gst_adapter_flush (scope->adapter, sbpf);
|
gst_adapter_flush (scope->adapter, sbpf);
|
||||||
|
gst_adapter_unmap (scope->adapter);
|
||||||
} else if (avail - sbpf >= 0) {
|
} else if (avail - sbpf >= 0) {
|
||||||
/* just flush a bit and stop */
|
/* just flush a bit and stop */
|
||||||
gst_adapter_flush (scope->adapter, (avail - sbpf));
|
gst_adapter_flush (scope->adapter, (avail - sbpf));
|
||||||
|
gst_adapter_unmap (scope->adapter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
avail = gst_adapter_available (scope->adapter);
|
avail = gst_adapter_available (scope->adapter);
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (scope->next_ts != GST_CLOCK_TIME_NONE)
|
|
||||||
scope->next_ts += scope->frame_duration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_mutex_unlock (scope->config_lock);
|
g_mutex_unlock (scope->config_lock);
|
||||||
|
|
||||||
|
beach:
|
||||||
gst_object_unref (scope);
|
gst_object_unref (scope);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_base_audio_visualizer_src_event (GstPad * pad, GstEvent * event)
|
||||||
|
{
|
||||||
|
gboolean res;
|
||||||
|
GstBaseAudioVisualizer *scope;
|
||||||
|
|
||||||
|
scope = GST_BASE_AUDIO_VISUALIZER (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_QOS:
|
||||||
|
{
|
||||||
|
gdouble proportion;
|
||||||
|
GstClockTimeDiff diff;
|
||||||
|
GstClockTime timestamp;
|
||||||
|
|
||||||
|
gst_event_parse_qos (event, NULL, &proportion, &diff, ×tamp);
|
||||||
|
|
||||||
|
/* save stuff for the _chain() function */
|
||||||
|
GST_OBJECT_LOCK (scope);
|
||||||
|
scope->proportion = proportion;
|
||||||
|
if (diff >= 0)
|
||||||
|
/* we're late, this is a good estimate for next displayable
|
||||||
|
* frame (see part-qos.txt) */
|
||||||
|
scope->earliest_time = timestamp + 2 * diff + scope->frame_duration;
|
||||||
|
else
|
||||||
|
scope->earliest_time = timestamp + diff;
|
||||||
|
GST_OBJECT_UNLOCK (scope);
|
||||||
|
|
||||||
|
res = gst_pad_push_event (scope->sinkpad, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
res = gst_pad_push_event (scope->sinkpad, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gst_object_unref (scope);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_base_audio_visualizer_sink_event (GstPad * pad, GstEvent * event)
|
||||||
|
{
|
||||||
|
gboolean res;
|
||||||
|
GstBaseAudioVisualizer *scope;
|
||||||
|
|
||||||
|
scope = GST_BASE_AUDIO_VISUALIZER (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_CAPS:
|
||||||
|
{
|
||||||
|
GstCaps *caps;
|
||||||
|
|
||||||
|
gst_event_parse_caps (event, &caps);
|
||||||
|
res = gst_base_audio_visualizer_sink_setcaps (scope, caps);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_EVENT_FLUSH_START:
|
||||||
|
res = gst_pad_push_event (scope->srcpad, event);
|
||||||
|
break;
|
||||||
|
case GST_EVENT_FLUSH_STOP:
|
||||||
|
gst_base_audio_visualizer_reset (scope);
|
||||||
|
res = gst_pad_push_event (scope->srcpad, event);
|
||||||
|
break;
|
||||||
|
case GST_EVENT_SEGMENT:
|
||||||
|
{
|
||||||
|
/* the newsegment values are used to clip the input samples
|
||||||
|
* and to convert the incomming timestamps to running time so
|
||||||
|
* we can do QoS */
|
||||||
|
gst_event_copy_segment (event, &scope->segment);
|
||||||
|
|
||||||
|
res = gst_pad_push_event (scope->srcpad, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
res = gst_pad_push_event (scope->srcpad, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gst_object_unref (scope);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_base_audio_visualizer_src_query (GstPad * pad, GstQuery * query)
|
||||||
|
{
|
||||||
|
gboolean res = FALSE;
|
||||||
|
GstBaseAudioVisualizer *scope;
|
||||||
|
|
||||||
|
scope = GST_BASE_AUDIO_VISUALIZER (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
switch (GST_QUERY_TYPE (query)) {
|
||||||
|
case GST_QUERY_LATENCY:
|
||||||
|
{
|
||||||
|
/* We need to send the query upstream and add the returned latency to our
|
||||||
|
* own */
|
||||||
|
GstClockTime min_latency, max_latency;
|
||||||
|
gboolean us_live;
|
||||||
|
GstClockTime our_latency;
|
||||||
|
guint max_samples;
|
||||||
|
|
||||||
|
if (scope->rate == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((res = gst_pad_peer_query (scope->sinkpad, query))) {
|
||||||
|
gst_query_parse_latency (query, &us_live, &min_latency, &max_latency);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (scope, "Peer latency: min %"
|
||||||
|
GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
|
||||||
|
|
||||||
|
/* the max samples we must buffer buffer */
|
||||||
|
max_samples = MAX (scope->req_spf, scope->spf);
|
||||||
|
our_latency =
|
||||||
|
gst_util_uint64_scale_int (max_samples, GST_SECOND, scope->rate);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (scope, "Our latency: %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (our_latency));
|
||||||
|
|
||||||
|
/* we add some latency but only if we need to buffer more than what
|
||||||
|
* upstream gives us */
|
||||||
|
min_latency += our_latency;
|
||||||
|
if (max_latency != -1)
|
||||||
|
max_latency += our_latency;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (scope, "Calculated total latency : min %"
|
||||||
|
GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
|
||||||
|
|
||||||
|
gst_query_set_latency (query, TRUE, min_latency, max_latency);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
res = gst_pad_peer_query (scope->sinkpad, query);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_object_unref (scope);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_base_audio_visualizer_sink_query (GstPad * pad, GstQuery * query)
|
||||||
|
{
|
||||||
|
gboolean res = FALSE;
|
||||||
|
GstBaseAudioVisualizer *scope;
|
||||||
|
|
||||||
|
scope = GST_BASE_AUDIO_VISUALIZER (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
switch (GST_QUERY_TYPE (query)) {
|
||||||
|
case GST_QUERY_ALLOCATION:
|
||||||
|
/* we convert audio to video, don't pass allocation queries for audio
|
||||||
|
* through */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = gst_pad_peer_query (scope->srcpad, query);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_object_unref (scope);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static GstStateChangeReturn
|
static GstStateChangeReturn
|
||||||
gst_base_audio_visualizer_change_state (GstElement * element,
|
gst_base_audio_visualizer_change_state (GstElement * element,
|
||||||
GstStateChange transition)
|
GstStateChange transition)
|
||||||
{
|
{
|
||||||
|
GstStateChangeReturn ret;
|
||||||
GstBaseAudioVisualizer *scope;
|
GstBaseAudioVisualizer *scope;
|
||||||
|
|
||||||
scope = GST_BASE_AUDIO_VISUALIZER (element);
|
scope = GST_BASE_AUDIO_VISUALIZER (element);
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
scope->next_ts = GST_CLOCK_TIME_NONE;
|
gst_base_audio_visualizer_reset (scope);
|
||||||
gst_adapter_clear (scope->adapter);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||||
|
|
||||||
|
switch (transition) {
|
||||||
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
|
if (scope->pool) {
|
||||||
|
gst_buffer_pool_set_active (scope->pool, FALSE);
|
||||||
|
gst_object_replace ((GstObject **) & scope->pool, NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,7 @@ struct _GstBaseAudioVisualizer
|
||||||
/* pads */
|
/* pads */
|
||||||
GstPad *srcpad, *sinkpad;
|
GstPad *srcpad, *sinkpad;
|
||||||
|
|
||||||
|
GstBufferPool *pool;
|
||||||
GstAdapter *adapter;
|
GstAdapter *adapter;
|
||||||
GstBuffer *inbuf;
|
GstBuffer *inbuf;
|
||||||
guint8 *pixelbuf;
|
guint8 *pixelbuf;
|
||||||
|
@ -82,7 +83,6 @@ struct _GstBaseAudioVisualizer
|
||||||
GstBaseAudioVisualizerShaderFunc shader;
|
GstBaseAudioVisualizerShaderFunc shader;
|
||||||
guint32 shade_amount;
|
guint32 shade_amount;
|
||||||
|
|
||||||
guint64 next_ts; /* the timestamp of the next frame */
|
|
||||||
guint64 frame_duration;
|
guint64 frame_duration;
|
||||||
guint bpf; /* bytes per frame */
|
guint bpf; /* bytes per frame */
|
||||||
guint bps; /* bytes per sample */
|
guint bps; /* bytes per sample */
|
||||||
|
@ -94,14 +94,20 @@ struct _GstBaseAudioVisualizer
|
||||||
gint fps_n, fps_d;
|
gint fps_n, fps_d;
|
||||||
gint width;
|
gint width;
|
||||||
gint height;
|
gint height;
|
||||||
gint channels;
|
|
||||||
|
|
||||||
/* audio state */
|
/* audio state */
|
||||||
gint sample_rate;
|
gint sample_rate;
|
||||||
|
gint channels;
|
||||||
gint rate;
|
gint rate;
|
||||||
|
|
||||||
/* configuration mutex */
|
/* configuration mutex */
|
||||||
GMutex *config_lock;
|
GMutex *config_lock;
|
||||||
|
|
||||||
|
/* QoS stuff *//* with LOCK */
|
||||||
|
gdouble proportion;
|
||||||
|
GstClockTime earliest_time;
|
||||||
|
|
||||||
|
GstSegment segment;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstBaseAudioVisualizerClass
|
struct _GstBaseAudioVisualizerClass
|
||||||
|
|
|
@ -41,14 +41,20 @@ static GstStaticPadTemplate gst_space_scope_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN)
|
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||||
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("xRGB"))
|
||||||
|
#else
|
||||||
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRx"))
|
||||||
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_space_scope_sink_template =
|
static GstStaticPadTemplate gst_space_scope_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS)
|
GST_STATIC_CAPS ("audio/x-raw, "
|
||||||
|
"format = (string) " GST_AUDIO_NE (S16) ", "
|
||||||
|
"rate = (int) [ 8000, 96000 ], " "channels = (int) 2")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,13 +65,14 @@ static gboolean gst_space_scope_render (GstBaseAudioVisualizer * scope,
|
||||||
GstBuffer * audio, GstBuffer * video);
|
GstBuffer * audio, GstBuffer * video);
|
||||||
|
|
||||||
|
|
||||||
GST_BOILERPLATE (GstSpaceScope, gst_space_scope, GstBaseAudioVisualizer,
|
G_DEFINE_TYPE (GstSpaceScope, gst_space_scope, GST_TYPE_BASE_AUDIO_VISUALIZER);
|
||||||
GST_TYPE_BASE_AUDIO_VISUALIZER);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_space_scope_base_init (gpointer g_class)
|
gst_space_scope_class_init (GstSpaceScopeClass * g_class)
|
||||||
{
|
{
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
GstElementClass *element_class = (GstElementClass *) g_class;
|
||||||
|
GstBaseAudioVisualizerClass *scope_class =
|
||||||
|
(GstBaseAudioVisualizerClass *) g_class;
|
||||||
|
|
||||||
gst_element_class_set_details_simple (element_class, "Stereo visualizer",
|
gst_element_class_set_details_simple (element_class, "Stereo visualizer",
|
||||||
"Visualization",
|
"Visualization",
|
||||||
|
@ -75,19 +82,12 @@ gst_space_scope_base_init (gpointer g_class)
|
||||||
gst_static_pad_template_get (&gst_space_scope_src_template));
|
gst_static_pad_template_get (&gst_space_scope_src_template));
|
||||||
gst_element_class_add_pad_template (element_class,
|
gst_element_class_add_pad_template (element_class,
|
||||||
gst_static_pad_template_get (&gst_space_scope_sink_template));
|
gst_static_pad_template_get (&gst_space_scope_sink_template));
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_space_scope_class_init (GstSpaceScopeClass * g_class)
|
|
||||||
{
|
|
||||||
GstBaseAudioVisualizerClass *scope_class =
|
|
||||||
(GstBaseAudioVisualizerClass *) g_class;
|
|
||||||
|
|
||||||
scope_class->render = GST_DEBUG_FUNCPTR (gst_space_scope_render);
|
scope_class->render = GST_DEBUG_FUNCPTR (gst_space_scope_render);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_space_scope_init (GstSpaceScope * scope, GstSpaceScopeClass * g_class)
|
gst_space_scope_init (GstSpaceScope * scope)
|
||||||
{
|
{
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
}
|
}
|
||||||
|
@ -96,15 +96,17 @@ static gboolean
|
||||||
gst_space_scope_render (GstBaseAudioVisualizer * scope, GstBuffer * audio,
|
gst_space_scope_render (GstBaseAudioVisualizer * scope, GstBuffer * audio,
|
||||||
GstBuffer * video)
|
GstBuffer * video)
|
||||||
{
|
{
|
||||||
guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video);
|
gsize asize;
|
||||||
gint16 *adata = (gint16 *) GST_BUFFER_DATA (audio);
|
guint32 *vdata =
|
||||||
|
(guint32 *) gst_buffer_map (video, NULL, NULL, GST_MAP_WRITE);
|
||||||
|
gint16 *adata = (gint16 *) gst_buffer_map (audio, &asize, NULL, GST_MAP_READ);
|
||||||
guint i, s, x, y, off, ox, oy;
|
guint i, s, x, y, off, ox, oy;
|
||||||
guint num_samples;
|
guint num_samples;
|
||||||
gfloat dx, dy;
|
gfloat dx, dy;
|
||||||
guint w = scope->width;
|
guint w = scope->width;
|
||||||
|
|
||||||
/* draw dots 1st channel x, 2nd channel y */
|
/* draw dots 1st channel x, 2nd channel y */
|
||||||
num_samples = GST_BUFFER_SIZE (audio) / (scope->channels * sizeof (gint16));
|
num_samples = asize / (scope->channels * sizeof (gint16));
|
||||||
dx = scope->width / 65536.0;
|
dx = scope->width / 65536.0;
|
||||||
ox = scope->width / 2;
|
ox = scope->width / 2;
|
||||||
dy = scope->height / 65536.0;
|
dy = scope->height / 65536.0;
|
||||||
|
@ -116,6 +118,8 @@ gst_space_scope_render (GstBaseAudioVisualizer * scope, GstBuffer * audio,
|
||||||
off = (y * w) + x;
|
off = (y * w) + x;
|
||||||
vdata[off] = 0x00FFFFFF;
|
vdata[off] = 0x00FFFFFF;
|
||||||
}
|
}
|
||||||
|
gst_buffer_unmap (video, vdata, -1);
|
||||||
|
gst_buffer_unmap (audio, adata, -1);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,20 @@ static GstStaticPadTemplate gst_spectra_scope_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN)
|
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||||
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("xRGB"))
|
||||||
|
#else
|
||||||
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRx"))
|
||||||
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_spectra_scope_sink_template =
|
static GstStaticPadTemplate gst_spectra_scope_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS)
|
GST_STATIC_CAPS ("audio/x-raw, "
|
||||||
|
"format = (string) " GST_AUDIO_NE (S16) ", "
|
||||||
|
"rate = (int) [ 8000, 96000 ], " "channels = (int) 2")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,13 +69,18 @@ static gboolean gst_spectra_scope_render (GstBaseAudioVisualizer * scope,
|
||||||
GstBuffer * audio, GstBuffer * video);
|
GstBuffer * audio, GstBuffer * video);
|
||||||
|
|
||||||
|
|
||||||
GST_BOILERPLATE (GstSpectraScope, gst_spectra_scope, GstBaseAudioVisualizer,
|
G_DEFINE_TYPE (GstSpectraScope, gst_spectra_scope,
|
||||||
GST_TYPE_BASE_AUDIO_VISUALIZER);
|
GST_TYPE_BASE_AUDIO_VISUALIZER);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_spectra_scope_base_init (gpointer g_class)
|
gst_spectra_scope_class_init (GstSpectraScopeClass * g_class)
|
||||||
{
|
{
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
GObjectClass *gobject_class = (GObjectClass *) g_class;
|
||||||
|
GstElementClass *element_class = (GstElementClass *) g_class;
|
||||||
|
GstBaseAudioVisualizerClass *scope_class =
|
||||||
|
(GstBaseAudioVisualizerClass *) g_class;
|
||||||
|
|
||||||
|
gobject_class->finalize = gst_spectra_scope_finalize;
|
||||||
|
|
||||||
gst_element_class_set_details_simple (element_class,
|
gst_element_class_set_details_simple (element_class,
|
||||||
"Frequency spectrum scope", "Visualization",
|
"Frequency spectrum scope", "Visualization",
|
||||||
|
@ -79,23 +90,13 @@ gst_spectra_scope_base_init (gpointer g_class)
|
||||||
gst_static_pad_template_get (&gst_spectra_scope_src_template));
|
gst_static_pad_template_get (&gst_spectra_scope_src_template));
|
||||||
gst_element_class_add_pad_template (element_class,
|
gst_element_class_add_pad_template (element_class,
|
||||||
gst_static_pad_template_get (&gst_spectra_scope_sink_template));
|
gst_static_pad_template_get (&gst_spectra_scope_sink_template));
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_spectra_scope_class_init (GstSpectraScopeClass * g_class)
|
|
||||||
{
|
|
||||||
GObjectClass *gobject_class = (GObjectClass *) g_class;
|
|
||||||
GstBaseAudioVisualizerClass *scope_class =
|
|
||||||
(GstBaseAudioVisualizerClass *) g_class;
|
|
||||||
|
|
||||||
gobject_class->finalize = gst_spectra_scope_finalize;
|
|
||||||
|
|
||||||
scope_class->setup = GST_DEBUG_FUNCPTR (gst_spectra_scope_setup);
|
scope_class->setup = GST_DEBUG_FUNCPTR (gst_spectra_scope_setup);
|
||||||
scope_class->render = GST_DEBUG_FUNCPTR (gst_spectra_scope_render);
|
scope_class->render = GST_DEBUG_FUNCPTR (gst_spectra_scope_render);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_spectra_scope_init (GstSpectraScope * scope, GstSpectraScopeClass * g_class)
|
gst_spectra_scope_init (GstSpectraScope * scope)
|
||||||
{
|
{
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
}
|
}
|
||||||
|
@ -114,7 +115,7 @@ gst_spectra_scope_finalize (GObject * object)
|
||||||
scope->freq_data = NULL;
|
scope->freq_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (gst_spectra_scope_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -164,9 +165,11 @@ gst_spectra_scope_render (GstBaseAudioVisualizer * bscope, GstBuffer * audio,
|
||||||
GstBuffer * video)
|
GstBuffer * video)
|
||||||
{
|
{
|
||||||
GstSpectraScope *scope = GST_SPECTRA_SCOPE (bscope);
|
GstSpectraScope *scope = GST_SPECTRA_SCOPE (bscope);
|
||||||
guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video);
|
gsize asize;
|
||||||
gint16 *adata = (gint16 *) g_memdup (GST_BUFFER_DATA (audio),
|
guint32 *vdata =
|
||||||
GST_BUFFER_SIZE (audio));
|
(guint32 *) gst_buffer_map (video, NULL, NULL, GST_MAP_WRITE);
|
||||||
|
gint16 *adata = (gint16 *) gst_buffer_map (audio, &asize, NULL, GST_MAP_READ);
|
||||||
|
gint16 *mono_adata = (gint16 *) g_memdup (adata, asize);
|
||||||
GstFFTS16Complex *fdata = scope->freq_data;
|
GstFFTS16Complex *fdata = scope->freq_data;
|
||||||
guint x, y, off;
|
guint x, y, off;
|
||||||
guint l, h = bscope->height - 1;
|
guint l, h = bscope->height - 1;
|
||||||
|
@ -175,22 +178,22 @@ gst_spectra_scope_render (GstBaseAudioVisualizer * bscope, GstBuffer * audio,
|
||||||
|
|
||||||
if (bscope->channels > 1) {
|
if (bscope->channels > 1) {
|
||||||
guint ch = bscope->channels;
|
guint ch = bscope->channels;
|
||||||
guint num_samples = GST_BUFFER_SIZE (audio) / (ch * sizeof (gint16));
|
guint num_samples = asize / (ch * sizeof (gint16));
|
||||||
guint i, c, v, s = 0;
|
guint i, c, v, s = 0;
|
||||||
|
|
||||||
/* deinterleave and mixdown adata */
|
/* deinterleave and mixdown adata */
|
||||||
for (i = 0; i < num_samples; i++) {
|
for (i = 0; i < num_samples; i++) {
|
||||||
v = 0;
|
v = 0;
|
||||||
for (c = 0; c < ch; c++) {
|
for (c = 0; c < ch; c++) {
|
||||||
v += adata[s++];
|
v += mono_adata[s++];
|
||||||
}
|
}
|
||||||
adata[i] = v / ch;
|
mono_adata[i] = v / ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* run fft */
|
/* run fft */
|
||||||
gst_fft_s16_window (scope->fft_ctx, adata, GST_FFT_WINDOW_HAMMING);
|
gst_fft_s16_window (scope->fft_ctx, mono_adata, GST_FFT_WINDOW_HAMMING);
|
||||||
gst_fft_s16_fft (scope->fft_ctx, adata, fdata);
|
gst_fft_s16_fft (scope->fft_ctx, mono_adata, fdata);
|
||||||
g_free (adata);
|
g_free (adata);
|
||||||
|
|
||||||
/* draw lines */
|
/* draw lines */
|
||||||
|
@ -210,6 +213,8 @@ gst_spectra_scope_render (GstBaseAudioVisualizer * bscope, GstBuffer * audio,
|
||||||
add_pixel (&vdata[off], 0x007F7F7F);
|
add_pixel (&vdata[off], 0x007F7F7F);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gst_buffer_unmap (video, vdata, -1);
|
||||||
|
gst_buffer_unmap (audio, adata, -1);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,14 +41,20 @@ static GstStaticPadTemplate gst_synae_scope_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN)
|
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||||
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("xRGB"))
|
||||||
|
#else
|
||||||
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRx"))
|
||||||
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_synae_scope_sink_template =
|
static GstStaticPadTemplate gst_synae_scope_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS)
|
GST_STATIC_CAPS ("audio/x-raw, "
|
||||||
|
"format = (string) " GST_AUDIO_NE (S16) ", "
|
||||||
|
"rate = (int) [ 8000, 96000 ], " "channels = (int) 2")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,13 +68,17 @@ static gboolean gst_synae_scope_render (GstBaseAudioVisualizer * scope,
|
||||||
GstBuffer * audio, GstBuffer * video);
|
GstBuffer * audio, GstBuffer * video);
|
||||||
|
|
||||||
|
|
||||||
GST_BOILERPLATE (GstSynaeScope, gst_synae_scope, GstBaseAudioVisualizer,
|
G_DEFINE_TYPE (GstSynaeScope, gst_synae_scope, GST_TYPE_BASE_AUDIO_VISUALIZER);
|
||||||
GST_TYPE_BASE_AUDIO_VISUALIZER);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_synae_scope_base_init (gpointer g_class)
|
gst_synae_scope_class_init (GstSynaeScopeClass * g_class)
|
||||||
{
|
{
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
GObjectClass *gobject_class = (GObjectClass *) g_class;
|
||||||
|
GstElementClass *element_class = (GstElementClass *) g_class;
|
||||||
|
GstBaseAudioVisualizerClass *scope_class =
|
||||||
|
(GstBaseAudioVisualizerClass *) g_class;
|
||||||
|
|
||||||
|
gobject_class->finalize = gst_synae_scope_finalize;
|
||||||
|
|
||||||
gst_element_class_set_details_simple (element_class, "Synaescope",
|
gst_element_class_set_details_simple (element_class, "Synaescope",
|
||||||
"Visualization",
|
"Visualization",
|
||||||
|
@ -79,23 +89,13 @@ gst_synae_scope_base_init (gpointer g_class)
|
||||||
gst_static_pad_template_get (&gst_synae_scope_src_template));
|
gst_static_pad_template_get (&gst_synae_scope_src_template));
|
||||||
gst_element_class_add_pad_template (element_class,
|
gst_element_class_add_pad_template (element_class,
|
||||||
gst_static_pad_template_get (&gst_synae_scope_sink_template));
|
gst_static_pad_template_get (&gst_synae_scope_sink_template));
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_synae_scope_class_init (GstSynaeScopeClass * g_class)
|
|
||||||
{
|
|
||||||
GObjectClass *gobject_class = (GObjectClass *) g_class;
|
|
||||||
GstBaseAudioVisualizerClass *scope_class =
|
|
||||||
(GstBaseAudioVisualizerClass *) g_class;
|
|
||||||
|
|
||||||
gobject_class->finalize = gst_synae_scope_finalize;
|
|
||||||
|
|
||||||
scope_class->setup = GST_DEBUG_FUNCPTR (gst_synae_scope_setup);
|
scope_class->setup = GST_DEBUG_FUNCPTR (gst_synae_scope_setup);
|
||||||
scope_class->render = GST_DEBUG_FUNCPTR (gst_synae_scope_render);
|
scope_class->render = GST_DEBUG_FUNCPTR (gst_synae_scope_render);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_synae_scope_init (GstSynaeScope * scope, GstSynaeScopeClass * g_class)
|
gst_synae_scope_init (GstSynaeScope * scope)
|
||||||
{
|
{
|
||||||
guint32 *colors = scope->colors;
|
guint32 *colors = scope->colors;
|
||||||
guint *shade = scope->shade;
|
guint *shade = scope->shade;
|
||||||
|
@ -144,7 +144,7 @@ gst_synae_scope_finalize (GObject * object)
|
||||||
scope->adata_r = NULL;
|
scope->adata_r = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (gst_synae_scope_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -203,8 +203,10 @@ gst_synae_scope_render (GstBaseAudioVisualizer * bscope, GstBuffer * audio,
|
||||||
GstBuffer * video)
|
GstBuffer * video)
|
||||||
{
|
{
|
||||||
GstSynaeScope *scope = GST_SYNAE_SCOPE (bscope);
|
GstSynaeScope *scope = GST_SYNAE_SCOPE (bscope);
|
||||||
guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video);
|
gsize asize;
|
||||||
gint16 *adata = (gint16 *) GST_BUFFER_DATA (audio);
|
guint32 *vdata =
|
||||||
|
(guint32 *) gst_buffer_map (video, NULL, NULL, GST_MAP_WRITE);
|
||||||
|
gint16 *adata = (gint16 *) gst_buffer_map (audio, &asize, NULL, GST_MAP_READ);
|
||||||
gint16 *adata_l = scope->adata_l;
|
gint16 *adata_l = scope->adata_l;
|
||||||
gint16 *adata_r = scope->adata_r;
|
gint16 *adata_r = scope->adata_r;
|
||||||
GstFFTS16Complex *fdata_l = scope->freq_data_l;
|
GstFFTS16Complex *fdata_l = scope->freq_data_l;
|
||||||
|
@ -217,7 +219,7 @@ gst_synae_scope_render (GstBaseAudioVisualizer * bscope, GstBuffer * audio,
|
||||||
guint *shade = scope->shade;
|
guint *shade = scope->shade;
|
||||||
//guint w2 = w /2;
|
//guint w2 = w /2;
|
||||||
guint ch = bscope->channels;
|
guint ch = bscope->channels;
|
||||||
guint num_samples = GST_BUFFER_SIZE (audio) / (ch * sizeof (gint16));
|
guint num_samples = asize / (ch * sizeof (gint16));
|
||||||
gint i, j, b;
|
gint i, j, b;
|
||||||
gint br, br1, br2;
|
gint br, br1, br2;
|
||||||
gint clarity;
|
gint clarity;
|
||||||
|
|
|
@ -41,14 +41,20 @@ static GstStaticPadTemplate gst_wave_scope_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN)
|
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||||
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("xRGB"))
|
||||||
|
#else
|
||||||
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRx"))
|
||||||
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_wave_scope_sink_template =
|
static GstStaticPadTemplate gst_wave_scope_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS)
|
GST_STATIC_CAPS ("audio/x-raw, "
|
||||||
|
"format = (string) " GST_AUDIO_NE (S16) ", "
|
||||||
|
"rate = (int) [ 8000, 96000 ], " "channels = (int) 2")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,13 +65,14 @@ static gboolean gst_wave_scope_render (GstBaseAudioVisualizer * scope,
|
||||||
GstBuffer * audio, GstBuffer * video);
|
GstBuffer * audio, GstBuffer * video);
|
||||||
|
|
||||||
|
|
||||||
GST_BOILERPLATE (GstWaveScope, gst_wave_scope, GstBaseAudioVisualizer,
|
G_DEFINE_TYPE (GstWaveScope, gst_wave_scope, GST_TYPE_BASE_AUDIO_VISUALIZER);
|
||||||
GST_TYPE_BASE_AUDIO_VISUALIZER);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_wave_scope_base_init (gpointer g_class)
|
gst_wave_scope_class_init (GstWaveScopeClass * g_class)
|
||||||
{
|
{
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
GstElementClass *element_class = (GstElementClass *) g_class;
|
||||||
|
GstBaseAudioVisualizerClass *scope_class =
|
||||||
|
(GstBaseAudioVisualizerClass *) g_class;
|
||||||
|
|
||||||
gst_element_class_set_details_simple (element_class, "Waveform oscilloscope",
|
gst_element_class_set_details_simple (element_class, "Waveform oscilloscope",
|
||||||
"Visualization",
|
"Visualization",
|
||||||
|
@ -75,19 +82,12 @@ gst_wave_scope_base_init (gpointer g_class)
|
||||||
gst_static_pad_template_get (&gst_wave_scope_src_template));
|
gst_static_pad_template_get (&gst_wave_scope_src_template));
|
||||||
gst_element_class_add_pad_template (element_class,
|
gst_element_class_add_pad_template (element_class,
|
||||||
gst_static_pad_template_get (&gst_wave_scope_sink_template));
|
gst_static_pad_template_get (&gst_wave_scope_sink_template));
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_wave_scope_class_init (GstWaveScopeClass * g_class)
|
|
||||||
{
|
|
||||||
GstBaseAudioVisualizerClass *scope_class =
|
|
||||||
(GstBaseAudioVisualizerClass *) g_class;
|
|
||||||
|
|
||||||
scope_class->render = GST_DEBUG_FUNCPTR (gst_wave_scope_render);
|
scope_class->render = GST_DEBUG_FUNCPTR (gst_wave_scope_render);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_wave_scope_init (GstWaveScope * scope, GstWaveScopeClass * g_class)
|
gst_wave_scope_init (GstWaveScope * scope)
|
||||||
{
|
{
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
}
|
}
|
||||||
|
@ -96,15 +96,17 @@ static gboolean
|
||||||
gst_wave_scope_render (GstBaseAudioVisualizer * scope, GstBuffer * audio,
|
gst_wave_scope_render (GstBaseAudioVisualizer * scope, GstBuffer * audio,
|
||||||
GstBuffer * video)
|
GstBuffer * video)
|
||||||
{
|
{
|
||||||
guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video);
|
gsize asize;
|
||||||
gint16 *adata = (gint16 *) GST_BUFFER_DATA (audio);
|
guint32 *vdata =
|
||||||
|
(guint32 *) gst_buffer_map (video, NULL, NULL, GST_MAP_WRITE);
|
||||||
|
gint16 *adata = (gint16 *) gst_buffer_map (audio, &asize, NULL, GST_MAP_READ);
|
||||||
guint i, c, s, x, y, off, oy;
|
guint i, c, s, x, y, off, oy;
|
||||||
guint num_samples;
|
guint num_samples;
|
||||||
gfloat dx, dy;
|
gfloat dx, dy;
|
||||||
guint w = scope->width;
|
guint w = scope->width;
|
||||||
|
|
||||||
/* draw dots */
|
/* draw dots */
|
||||||
num_samples = GST_BUFFER_SIZE (audio) / (scope->channels * sizeof (gint16));
|
num_samples = asize / (scope->channels * sizeof (gint16));
|
||||||
dx = (gfloat) scope->width / (gfloat) num_samples;
|
dx = (gfloat) scope->width / (gfloat) num_samples;
|
||||||
dy = scope->height / 65536.0;
|
dy = scope->height / 65536.0;
|
||||||
oy = scope->height / 2;
|
oy = scope->height / 2;
|
||||||
|
@ -117,6 +119,8 @@ gst_wave_scope_render (GstBaseAudioVisualizer * scope, GstBuffer * audio,
|
||||||
vdata[off] = 0x00FFFFFF;
|
vdata[off] = 0x00FFFFFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gst_buffer_unmap (video, vdata, -1);
|
||||||
|
gst_buffer_unmap (audio, adata, -1);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue