2 * Copyright (C) <2011> Stefan Kost <ensonic@users.sf.net>
4 * gstbaseaudiovisualizer.h: base class for audio visualisation elements
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * SECTION:gstbaseaudiovisualizer
23 * A basclass for scopes (visualizers). It takes care of re-fitting the
24 * audio-rate to video-rate and handles renegotiation (downstream video size
27 * It also provides several background shading effects. These effects are
28 * applied to a previous picture before the render() implementation can draw a
36 #include <gst/controller/gstcontroller.h>
38 #include "gstbaseaudiovisualizer.h"
40 GST_DEBUG_CATEGORY_STATIC (base_audio_visualizer_debug);
41 #define GST_CAT_DEFAULT (base_audio_visualizer_debug)
43 #define DEFAULT_SHADER GST_BASE_AUDIO_VISUALIZER_SHADER_FADE
44 #define DEFAULT_SHADE_AMOUNT 0x000a0a0a
53 static GstBaseTransformClass *parent_class = NULL;
55 static void gst_base_audio_visualizer_class_init (GstBaseAudioVisualizerClass *
57 static void gst_base_audio_visualizer_init (GstBaseAudioVisualizer * scope,
58 GstBaseAudioVisualizerClass * g_class);
59 static void gst_base_audio_visualizer_set_property (GObject * object,
60 guint prop_id, const GValue * value, GParamSpec * pspec);
61 static void gst_base_audio_visualizer_get_property (GObject * object,
62 guint prop_id, GValue * value, GParamSpec * pspec);
63 static void gst_base_audio_visualizer_dispose (GObject * object);
65 static gboolean gst_base_audio_visualizer_src_negotiate (GstBaseAudioVisualizer
67 static gboolean gst_base_audio_visualizer_src_setcaps (GstPad * pad,
69 static gboolean gst_base_audio_visualizer_sink_setcaps (GstPad * pad,
72 static GstFlowReturn gst_base_audio_visualizer_chain (GstPad * pad,
74 static GstStateChangeReturn gst_base_audio_visualizer_change_state (GstElement *
75 element, GstStateChange transition);
77 /* shading functions */
79 #define GST_TYPE_BASE_AUDIO_VISUALIZER_SHADER (gst_base_audio_visualizer_shader_get_type())
81 gst_base_audio_visualizer_shader_get_type (void)
83 static GType shader_type = 0;
84 static const GEnumValue shaders[] = {
85 {GST_BASE_AUDIO_VISUALIZER_SHADER_NONE, "None", "none"},
86 {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE, "Fade", "fade"},
87 {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_UP, "Fade and move up",
89 {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN, "Fade and move down",
90 "fade-and-move-down"},
91 {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT, "Fade and move left",
92 "fade-and-move-left"},
93 {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT,
94 "Fade and move right",
95 "fade-and-move-right"},
96 {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT,
97 "Fade and move horizontally out", "fade-and-move-horiz-out"},
98 {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN,
99 "Fade and move horizontally in", "fade-and-move-horiz-in"},
100 {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT,
101 "Fade and move vertically out", "fade-and-move-vert-out"},
102 {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN,
103 "Fade and move vertically in", "fade-and-move-vert-in"},
107 if (G_UNLIKELY (shader_type == 0)) {
109 g_enum_register_static ("GstBaseAudioVisualizerShader", shaders);
114 /* we're only supporting GST_VIDEO_FORMAT_xRGB right now) */
115 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
117 #define SHADE1(_d, _s, _i, _r, _g, _b) \
119 _d[_i] = (_s[_i] > _b) ? _s[_i] - _b : 0; \
121 _d[_i] = (_s[_i] > _g) ? _s[_i] - _g : 0; \
123 _d[_i] = (_s[_i] > _r) ? _s[_i] - _r : 0; \
128 #define SHADE2(_d, _s, _j, _i, _r, _g, _b) \
130 _d[_j++] = (_s[_i] > _b) ? _s[_i] - _b : 0; \
132 _d[_j++] = (_s[_i] > _g) ? _s[_i] - _g : 0; \
134 _d[_j++] = (_s[_i] > _r) ? _s[_i] - _r : 0; \
142 #define SHADE1(_d, _s, _i, _r, _g, _b) \
145 _d[_i] = (_s[_i] > _r) ? _s[_i] - _r : 0; \
147 _d[_i] = (_s[_i] > _g) ? _s[_i] - _g : 0; \
149 _d[_i] = (_s[_i] > _b) ? _s[_i] - _b : 0; \
153 #define SHADE2(_d, _s, _j, _i, _r, _g, _b) \
157 _d[_j++] = (_s[_i] > _r) ? _s[_i] - _r : 0; \
159 _d[_j++] = (_s[_i] > _g) ? _s[_i] - _g : 0; \
161 _d[_j++] = (_s[_i] > _b) ? _s[_i] - _b : 0; \
168 shader_fade (GstBaseAudioVisualizer * scope, const guint8 * s, guint8 * d)
170 guint i, bpf = scope->bpf;
171 guint r = (scope->shade_amount >> 16) & 0xff;
172 guint g = (scope->shade_amount >> 8) & 0xff;
173 guint b = (scope->shade_amount >> 0) & 0xff;
175 for (i = 0; i < bpf;) {
176 SHADE1 (d, s, i, r, g, b);
181 shader_fade_and_move_up (GstBaseAudioVisualizer * scope, const guint8 * s,
184 guint i, j, bpf = scope->bpf;
185 guint bpl = 4 * scope->width;
186 guint r = (scope->shade_amount >> 16) & 0xff;
187 guint g = (scope->shade_amount >> 8) & 0xff;
188 guint b = (scope->shade_amount >> 0) & 0xff;
190 for (j = 0, i = bpl; i < bpf;) {
191 SHADE2 (d, s, j, i, r, g, b);
196 shader_fade_and_move_down (GstBaseAudioVisualizer * scope, const guint8 * s,
199 guint i, j, bpf = scope->bpf;
200 guint bpl = 4 * scope->width;
201 guint r = (scope->shade_amount >> 16) & 0xff;
202 guint g = (scope->shade_amount >> 8) & 0xff;
203 guint b = (scope->shade_amount >> 0) & 0xff;
205 for (j = bpl, i = 0; j < bpf;) {
206 SHADE2 (d, s, j, i, r, g, b);
211 shader_fade_and_move_left (GstBaseAudioVisualizer * scope,
212 const guint8 * s, guint8 * d)
214 guint i, j, k, bpf = scope->bpf;
215 guint w = scope->width;
216 guint r = (scope->shade_amount >> 16) & 0xff;
217 guint g = (scope->shade_amount >> 8) & 0xff;
218 guint b = (scope->shade_amount >> 0) & 0xff;
220 /* move to the left */
221 for (j = 0, i = 4; i < bpf;) {
222 for (k = 0; k < w - 1; k++) {
223 SHADE2 (d, s, j, i, r, g, b);
231 shader_fade_and_move_right (GstBaseAudioVisualizer * scope,
232 const guint8 * s, guint8 * d)
234 guint i, j, k, bpf = scope->bpf;
235 guint w = scope->width;
236 guint r = (scope->shade_amount >> 16) & 0xff;
237 guint g = (scope->shade_amount >> 8) & 0xff;
238 guint b = (scope->shade_amount >> 0) & 0xff;
240 /* move to the left */
241 for (j = 4, i = 0; i < bpf;) {
242 for (k = 0; k < w - 1; k++) {
243 SHADE2 (d, s, j, i, r, g, b);
251 shader_fade_and_move_horiz_out (GstBaseAudioVisualizer * scope,
252 const guint8 * s, guint8 * d)
254 guint i, j, bpf = scope->bpf / 2;
255 guint bpl = 4 * scope->width;
256 guint r = (scope->shade_amount >> 16) & 0xff;
257 guint g = (scope->shade_amount >> 8) & 0xff;
258 guint b = (scope->shade_amount >> 0) & 0xff;
260 /* move upper half up */
261 for (j = 0, i = bpl; i < bpf;) {
262 SHADE2 (d, s, j, i, r, g, b);
264 /* move lower half down */
265 for (j = bpf + bpl, i = bpf; j < bpf + bpf;) {
266 SHADE2 (d, s, j, i, r, g, b);
271 shader_fade_and_move_horiz_in (GstBaseAudioVisualizer * scope,
272 const guint8 * s, guint8 * d)
274 guint i, j, bpf = scope->bpf / 2;
275 guint bpl = 4 * scope->width;
276 guint r = (scope->shade_amount >> 16) & 0xff;
277 guint g = (scope->shade_amount >> 8) & 0xff;
278 guint b = (scope->shade_amount >> 0) & 0xff;
280 /* move upper half down */
281 for (i = 0, j = bpl; i < bpf;) {
282 SHADE2 (d, s, j, i, r, g, b);
284 /* move lower half up */
285 for (i = bpf + bpl, j = bpf; i < bpf + bpf;) {
286 SHADE2 (d, s, j, i, r, g, b);
291 shader_fade_and_move_vert_out (GstBaseAudioVisualizer * scope,
292 const guint8 * s, guint8 * d)
294 guint i, j, k, bpf = scope->bpf;
295 guint m = scope->width / 2;
296 guint r = (scope->shade_amount >> 16) & 0xff;
297 guint g = (scope->shade_amount >> 8) & 0xff;
298 guint b = (scope->shade_amount >> 0) & 0xff;
300 /* move left half to the left */
301 for (j = 0, i = 4; i < bpf;) {
302 for (k = 0; k < m; k++) {
303 SHADE2 (d, s, j, i, r, g, b);
308 /* move right half to the right */
309 for (j = 4 * (m + 1), i = 4 * m; j < bpf;) {
310 for (k = 0; k < m; k++) {
311 SHADE2 (d, s, j, i, r, g, b);
319 shader_fade_and_move_vert_in (GstBaseAudioVisualizer * scope,
320 const guint8 * s, guint8 * d)
322 guint i, j, k, bpf = scope->bpf;
323 guint m = scope->width / 2;
324 guint r = (scope->shade_amount >> 16) & 0xff;
325 guint g = (scope->shade_amount >> 8) & 0xff;
326 guint b = (scope->shade_amount >> 0) & 0xff;
328 /* move left half to the right */
329 for (j = 4, i = 0; j < bpf;) {
330 for (k = 0; k < m; k++) {
331 SHADE2 (d, s, j, i, r, g, b);
336 /* move right half to the left */
337 for (j = 4 * m, i = 4 * (m + 1); i < bpf;) {
338 for (k = 0; k < m; k++) {
339 SHADE2 (d, s, j, i, r, g, b);
347 gst_base_audio_visualizer_change_shader (GstBaseAudioVisualizer * scope)
349 switch (scope->shader_type) {
350 case GST_BASE_AUDIO_VISUALIZER_SHADER_NONE:
351 scope->shader = NULL;
353 case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE:
354 scope->shader = shader_fade;
356 case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_UP:
357 scope->shader = shader_fade_and_move_up;
359 case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN:
360 scope->shader = shader_fade_and_move_down;
362 case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT:
363 scope->shader = shader_fade_and_move_left;
365 case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT:
366 scope->shader = shader_fade_and_move_right;
368 case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT:
369 scope->shader = shader_fade_and_move_horiz_out;
371 case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN:
372 scope->shader = shader_fade_and_move_horiz_in;
374 case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT:
375 scope->shader = shader_fade_and_move_vert_out;
377 case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN:
378 scope->shader = shader_fade_and_move_vert_in;
381 GST_ERROR ("invalid shader function");
382 scope->shader = NULL;
390 gst_base_audio_visualizer_get_type (void)
392 static volatile gsize base_audio_visualizer_type = 0;
394 if (g_once_init_enter (&base_audio_visualizer_type)) {
395 static const GTypeInfo base_audio_visualizer_info = {
396 sizeof (GstBaseAudioVisualizerClass),
399 (GClassInitFunc) gst_base_audio_visualizer_class_init,
402 sizeof (GstBaseAudioVisualizer),
404 (GInstanceInitFunc) gst_base_audio_visualizer_init,
408 _type = g_type_register_static (GST_TYPE_ELEMENT,
409 "GstBaseAudioVisualizer", &base_audio_visualizer_info,
410 G_TYPE_FLAG_ABSTRACT);
411 g_once_init_leave (&base_audio_visualizer_type, _type);
413 return (GType) base_audio_visualizer_type;
417 gst_base_audio_visualizer_class_init (GstBaseAudioVisualizerClass * klass)
419 GObjectClass *gobject_class = (GObjectClass *) klass;
420 GstElementClass *element_class = (GstElementClass *) klass;
422 parent_class = g_type_class_peek_parent (klass);
424 GST_DEBUG_CATEGORY_INIT (base_audio_visualizer_debug, "baseaudiovisualizer",
425 0, "scope audio visualisation base class");
427 gobject_class->set_property = gst_base_audio_visualizer_set_property;
428 gobject_class->get_property = gst_base_audio_visualizer_get_property;
429 gobject_class->dispose = gst_base_audio_visualizer_dispose;
431 element_class->change_state =
432 GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_change_state);
434 g_object_class_install_property (gobject_class, PROP_SHADER,
435 g_param_spec_enum ("shader", "shader type",
436 "Shader function to apply on each frame",
437 GST_TYPE_BASE_AUDIO_VISUALIZER_SHADER, DEFAULT_SHADER,
438 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
439 g_object_class_install_property (gobject_class, PROP_SHADE_AMOUNT,
440 g_param_spec_uint ("shade-amount", "shade amount",
441 "Shading color to use (big-endian ARGB)", 0, G_MAXUINT32,
442 DEFAULT_SHADE_AMOUNT,
443 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
447 gst_base_audio_visualizer_init (GstBaseAudioVisualizer * scope,
448 GstBaseAudioVisualizerClass * g_class)
450 GstPadTemplate *pad_template;
452 /* create the sink and src pads */
454 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
455 g_return_if_fail (pad_template != NULL);
456 scope->sinkpad = gst_pad_new_from_template (pad_template, "sink");
457 gst_pad_set_chain_function (scope->sinkpad,
458 GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_chain));
459 gst_pad_set_setcaps_function (scope->sinkpad,
460 GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_sink_setcaps));
461 gst_element_add_pad (GST_ELEMENT (scope), scope->sinkpad);
464 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
465 g_return_if_fail (pad_template != NULL);
466 scope->srcpad = gst_pad_new_from_template (pad_template, "src");
467 gst_pad_set_setcaps_function (scope->srcpad,
468 GST_DEBUG_FUNCPTR (gst_base_audio_visualizer_src_setcaps));
469 gst_element_add_pad (GST_ELEMENT (scope), scope->srcpad);
471 scope->adapter = gst_adapter_new ();
472 scope->inbuf = gst_buffer_new ();
475 scope->shader_type = DEFAULT_SHADER;
476 gst_base_audio_visualizer_change_shader (scope);
477 scope->shade_amount = DEFAULT_SHADE_AMOUNT;
479 /* reset the initial video state */
482 scope->fps_n = 25; /* desired frame rate */
484 scope->frame_duration = GST_CLOCK_TIME_NONE;
486 /* reset the initial audio state */
487 scope->rate = GST_AUDIO_DEF_RATE;
490 scope->next_ts = GST_CLOCK_TIME_NONE;
492 scope->config_lock = g_mutex_new ();
496 gst_base_audio_visualizer_set_property (GObject * object, guint prop_id,
497 const GValue * value, GParamSpec * pspec)
499 GstBaseAudioVisualizer *scope = GST_BASE_AUDIO_VISUALIZER (object);
503 scope->shader_type = g_value_get_enum (value);
504 gst_base_audio_visualizer_change_shader (scope);
506 case PROP_SHADE_AMOUNT:
507 scope->shade_amount = g_value_get_uint (value);
510 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
516 gst_base_audio_visualizer_get_property (GObject * object, guint prop_id,
517 GValue * value, GParamSpec * pspec)
519 GstBaseAudioVisualizer *scope = GST_BASE_AUDIO_VISUALIZER (object);
523 g_value_set_enum (value, scope->shader_type);
525 case PROP_SHADE_AMOUNT:
526 g_value_set_uint (value, scope->shade_amount);
529 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
535 gst_base_audio_visualizer_dispose (GObject * object)
537 GstBaseAudioVisualizer *scope = GST_BASE_AUDIO_VISUALIZER (object);
539 if (scope->adapter) {
540 g_object_unref (scope->adapter);
541 scope->adapter = NULL;
544 gst_buffer_unref (scope->inbuf);
547 if (scope->pixelbuf) {
548 g_free (scope->pixelbuf);
549 scope->pixelbuf = NULL;
551 if (scope->config_lock) {
552 g_mutex_free (scope->config_lock);
553 scope->config_lock = NULL;
555 G_OBJECT_CLASS (parent_class)->dispose (object);
559 gst_base_audio_visualizer_sink_setcaps (GstPad * pad, GstCaps * caps)
561 GstBaseAudioVisualizer *scope;
562 GstStructure *structure;
567 scope = GST_BASE_AUDIO_VISUALIZER (gst_pad_get_parent (pad));
568 structure = gst_caps_get_structure (caps, 0);
570 if (!gst_structure_get_int (structure, "channels", &channels) ||
571 !gst_structure_get_int (structure, "rate", &rate))
572 goto missing_caps_details;
580 scope->channels = channels;
583 GST_DEBUG_OBJECT (scope, "audio: channels %d, rate %d",
584 scope->channels, scope->rate);
587 gst_object_unref (scope);
591 missing_caps_details:
593 GST_WARNING_OBJECT (scope, "missing channels or rate in the caps");
599 GST_WARNING_OBJECT (scope, "number of channels must be 2, but is %d",
606 GST_WARNING_OBJECT (scope, "sample rate must be >0, but is %d", rate);
613 gst_base_audio_visualizer_src_negotiate (GstBaseAudioVisualizer * scope)
615 GstCaps *othercaps, *target, *intersect;
616 GstStructure *structure;
617 const GstCaps *templ;
619 templ = gst_pad_get_pad_template_caps (scope->srcpad);
621 GST_DEBUG_OBJECT (scope, "performing negotiation");
623 /* see what the peer can do */
624 othercaps = gst_pad_peer_get_caps (scope->srcpad);
626 intersect = gst_caps_intersect (othercaps, templ);
627 gst_caps_unref (othercaps);
629 if (gst_caps_is_empty (intersect))
632 target = gst_caps_copy_nth (intersect, 0);
633 gst_caps_unref (intersect);
635 target = gst_caps_ref ((GstCaps *) templ);
638 structure = gst_caps_get_structure (target, 0);
639 gst_structure_fixate_field_nearest_int (structure, "width", scope->width);
640 gst_structure_fixate_field_nearest_int (structure, "height", scope->height);
641 gst_structure_fixate_field_nearest_fraction (structure, "framerate",
642 scope->fps_n, scope->fps_d);
644 GST_DEBUG_OBJECT (scope, "final caps are %" GST_PTR_FORMAT, target);
646 gst_pad_set_caps (scope->srcpad, target);
647 gst_caps_unref (target);
653 gst_caps_unref (intersect);
659 gst_base_audio_visualizer_src_setcaps (GstPad * pad, GstCaps * caps)
661 GstBaseAudioVisualizer *scope;
662 GstBaseAudioVisualizerClass *klass;
665 GstVideoFormat format;
668 scope = GST_BASE_AUDIO_VISUALIZER (gst_pad_get_parent (pad));
669 klass = GST_BASE_AUDIO_VISUALIZER_CLASS (G_OBJECT_GET_CLASS (scope));
671 if (!gst_video_format_parse_caps (caps, &format, &w, &h)) {
672 goto missing_caps_details;
674 if (!gst_video_parse_caps_framerate (caps, &num, &denom)) {
675 goto missing_caps_details;
678 g_mutex_lock (scope->config_lock);
683 scope->fps_d = denom;
684 scope->video_format = format;
686 scope->frame_duration = gst_util_uint64_scale_int (GST_SECOND,
687 scope->fps_d, scope->fps_n);
688 scope->spf = gst_util_uint64_scale_int (scope->rate,
689 scope->fps_d, scope->fps_n);
690 scope->req_spf = scope->spf;
692 scope->bpf = w * h * 4;
695 g_free (scope->pixelbuf);
696 scope->pixelbuf = g_malloc0 (scope->bpf);
699 res = klass->setup (scope);
701 GST_DEBUG_OBJECT (scope, "video: dimension %dx%d, framerate %d/%d",
702 scope->width, scope->height, scope->fps_n, scope->fps_d);
703 GST_DEBUG_OBJECT (scope, "blocks: spf %u, req_spf %u",
704 scope->spf, scope->req_spf);
706 g_mutex_unlock (scope->config_lock);
709 gst_object_unref (scope);
713 missing_caps_details:
715 GST_WARNING_OBJECT (scope,
716 "missing width, height or framerate in the caps");
723 gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer)
725 GstFlowReturn ret = GST_FLOW_OK;
726 GstBaseAudioVisualizer *scope;
727 GstBaseAudioVisualizerClass *klass;
731 gboolean (*render) (GstBaseAudioVisualizer * scope, GstBuffer * audio,
734 scope = GST_BASE_AUDIO_VISUALIZER (gst_pad_get_parent (pad));
735 klass = GST_BASE_AUDIO_VISUALIZER_CLASS (G_OBJECT_GET_CLASS (scope));
737 render = klass->render;
739 GST_LOG_OBJECT (scope, "chainfunc called");
741 /* resync on DISCONT */
742 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
743 scope->next_ts = GST_CLOCK_TIME_NONE;
744 gst_adapter_clear (scope->adapter);
747 if (GST_PAD_CAPS (scope->srcpad) == NULL) {
748 if (!gst_base_audio_visualizer_src_negotiate (scope))
749 return GST_FLOW_NOT_NEGOTIATED;
752 /* Match timestamps from the incoming audio */
753 if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE)
754 scope->next_ts = GST_BUFFER_TIMESTAMP (buffer);
756 gst_adapter_push (scope->adapter, buffer);
758 g_mutex_lock (scope->config_lock);
760 /* this is what we want */
761 sbpf = scope->req_spf * scope->channels * sizeof (gint16);
763 inbuf = scope->inbuf;
764 /* FIXME: the timestamp in the adapter would be different */
765 gst_buffer_copy_metadata (inbuf, buffer, GST_BUFFER_COPY_ALL);
767 /* this is what we have */
768 avail = gst_adapter_available (scope->adapter);
769 GST_LOG_OBJECT (scope, "avail: %u, bpf: %u", avail, sbpf);
770 while (avail >= sbpf) {
773 g_mutex_unlock (scope->config_lock);
774 ret = gst_pad_alloc_buffer_and_set_caps (scope->srcpad,
775 GST_BUFFER_OFFSET_NONE,
776 scope->bpf, GST_PAD_CAPS (scope->srcpad), &outbuf);
777 g_mutex_lock (scope->config_lock);
778 /* recheck as the value could have changed */
779 sbpf = scope->req_spf * scope->channels * sizeof (gint16);
781 /* no buffer allocated, we don't care why. */
782 if (ret != GST_FLOW_OK)
785 /* sync controlled properties */
786 gst_object_sync_values (G_OBJECT (scope), scope->next_ts);
788 GST_BUFFER_TIMESTAMP (outbuf) = scope->next_ts;
789 GST_BUFFER_DURATION (outbuf) = scope->frame_duration;
791 memcpy (GST_BUFFER_DATA (outbuf), scope->pixelbuf, scope->bpf);
793 memset (GST_BUFFER_DATA (outbuf), 0, scope->bpf);
796 /* this can fail as the data size we need could have changed */
797 if (!(adata = (guint8 *) gst_adapter_peek (scope->adapter, sbpf)))
800 GST_BUFFER_DATA (inbuf) = adata;
801 GST_BUFFER_SIZE (inbuf) = sbpf;
803 /* call class->render() vmethod */
805 if (!render (scope, inbuf, outbuf)) {
806 ret = GST_FLOW_ERROR;
808 /* run various post processing (shading and geometri transformation */
810 scope->shader (scope, GST_BUFFER_DATA (outbuf), scope->pixelbuf);
815 g_mutex_unlock (scope->config_lock);
816 ret = gst_pad_push (scope->srcpad, outbuf);
818 g_mutex_lock (scope->config_lock);
820 /* recheck as the value could have changed */
821 sbpf = scope->req_spf * scope->channels * sizeof (gint16);
822 GST_LOG_OBJECT (scope, "avail: %u, bpf: %u", avail, sbpf);
823 /* we want to take less or more, depending on spf : req_spf */
824 if (avail - sbpf >= sbpf) {
825 gst_adapter_flush (scope->adapter, sbpf);
826 } else if (avail - sbpf >= 0) {
827 /* just flush a bit and stop */
828 gst_adapter_flush (scope->adapter, (avail - sbpf));
831 avail = gst_adapter_available (scope->adapter);
833 if (ret != GST_FLOW_OK)
836 if (scope->next_ts != GST_CLOCK_TIME_NONE)
837 scope->next_ts += scope->frame_duration;
840 g_mutex_unlock (scope->config_lock);
842 gst_object_unref (scope);
847 static GstStateChangeReturn
848 gst_base_audio_visualizer_change_state (GstElement * element,
849 GstStateChange transition)
851 GstBaseAudioVisualizer *scope;
853 scope = GST_BASE_AUDIO_VISUALIZER (element);
855 switch (transition) {
856 case GST_STATE_CHANGE_READY_TO_PAUSED:
857 scope->next_ts = GST_CLOCK_TIME_NONE;
858 gst_adapter_clear (scope->adapter);
864 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);