2b093f11cf4d04126b093e6b27db3295ac76d555
[platform/upstream/gstreamer.git] / ext / libvisual / visual.c
1 /* GStreamer
2  * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
3  *               2012 Stefan Sauer <ensonic@users.sf.net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "visual.h"
26
27 GST_DEBUG_CATEGORY_EXTERN (libvisual_debug);
28 #define GST_CAT_DEFAULT (libvisual_debug)
29
30 /* amounf of samples before we can feed libvisual */
31 #define VISUAL_SAMPLES  512
32
33 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
34     GST_PAD_SRC,
35     GST_PAD_ALWAYS,
36     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (" { "
37 #if G_BYTE_ORDER == G_BIG_ENDIAN
38             "\"xRGB\", " "\"RGB\", "
39 #else
40             "\"BGRx\", " "\"BGR\", "
41 #endif
42             "\"RGB16\" } "))
43     );
44
45 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
46     GST_PAD_SINK,
47     GST_PAD_ALWAYS,
48     GST_STATIC_CAPS ("audio/x-raw, "
49         "format = (string) " GST_AUDIO_NE (S16) ", "
50         "layout = (string) interleaved, " "channels = (int) { 1, 2 }, "
51         "channel-mask = (bitmask) 0x3, "
52 #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
53         "rate = (int) { 8000, 11250, 22500, 32000, 44100, 48000, 96000 }"
54 #else
55         "rate = (int) [ 1000, MAX ]"
56 #endif
57     )
58     );
59
60
61 static void gst_visual_init (GstVisual * visual);
62 static void gst_visual_finalize (GObject * object);
63
64 static gboolean gst_visual_setup (GstAudioBaseVisualizer * bscope);
65 static gboolean gst_visual_render (GstAudioBaseVisualizer * bscope,
66     GstBuffer * audio, GstBuffer * video);
67
68 static GstElementClass *parent_class = NULL;
69
70 GType
71 gst_visual_get_type (void)
72 {
73   static GType type = 0;
74
75   if (G_UNLIKELY (type == 0)) {
76     static const GTypeInfo info = {
77       sizeof (GstVisualClass),
78       NULL,
79       NULL,
80       gst_visual_class_init,
81       NULL,
82       NULL,
83       sizeof (GstVisual),
84       0,
85       (GInstanceInitFunc) gst_visual_init,
86     };
87
88     type =
89         g_type_register_static (GST_TYPE_AUDIO_BASE_VISUALIZER, "GstVisual",
90         &info, 0);
91   }
92   return type;
93 }
94
95 void
96 gst_visual_class_init (gpointer g_class, gpointer class_data)
97 {
98   GObjectClass *gobject_class = (GObjectClass *) g_class;
99   GstElementClass *element_class = (GstElementClass *) g_class;
100   GstAudioBaseVisualizerClass *scope_class =
101       (GstAudioBaseVisualizerClass *) g_class;
102   GstVisualClass *klass = (GstVisualClass *) g_class;
103
104   klass->plugin = class_data;
105
106   if (class_data == NULL) {
107     parent_class = g_type_class_peek_parent (g_class);
108   } else {
109     gchar *longname = g_strdup_printf ("libvisual %s plugin v.%s",
110         klass->plugin->info->name, klass->plugin->info->version);
111
112     /* FIXME: improve to only register what plugin supports? */
113     gst_element_class_add_pad_template (element_class,
114         gst_static_pad_template_get (&src_template));
115     gst_element_class_add_pad_template (element_class,
116         gst_static_pad_template_get (&sink_template));
117
118     gst_element_class_set_static_metadata (element_class,
119         longname, "Visualization",
120         klass->plugin->info->about, "Benjamin Otte <otte@gnome.org>");
121
122     g_free (longname);
123   }
124
125   gobject_class->finalize = gst_visual_finalize;
126
127   scope_class->setup = GST_DEBUG_FUNCPTR (gst_visual_setup);
128   scope_class->render = GST_DEBUG_FUNCPTR (gst_visual_render);
129 }
130
131 static void
132 gst_visual_init (GstVisual * visual)
133 {
134   /* do nothing */
135 }
136
137 static void
138 gst_visual_clear_actors (GstVisual * visual)
139 {
140   if (visual->actor) {
141     visual_object_unref (VISUAL_OBJECT (visual->actor));
142     visual->actor = NULL;
143   }
144   if (visual->video) {
145     visual_object_unref (VISUAL_OBJECT (visual->video));
146     visual->video = NULL;
147   }
148   if (visual->audio) {
149     visual_object_unref (VISUAL_OBJECT (visual->audio));
150     visual->audio = NULL;
151   }
152 }
153
154 static void
155 gst_visual_finalize (GObject * object)
156 {
157   GstVisual *visual = GST_VISUAL (object);
158
159   gst_visual_clear_actors (visual);
160
161   GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
162 }
163
164 static gboolean
165 gst_visual_setup (GstAudioBaseVisualizer * bscope)
166 {
167   GstVisual *visual = GST_VISUAL (bscope);
168   gint pitch, depth;
169
170   gst_visual_clear_actors (visual);
171
172   depth = bscope->vinfo.finfo->pixel_stride[0];
173   if (bscope->vinfo.finfo->bits >= 8) {
174     depth *= 8;
175   }
176
177   visual->actor =
178       visual_actor_new (GST_VISUAL_GET_CLASS (visual)->plugin->info->plugname);
179   visual->video = visual_video_new ();
180   visual->audio = visual_audio_new ();
181   /* can't have a play without actors */
182   if (!visual->actor || !visual->video)
183     goto no_actors;
184
185   if (visual_actor_realize (visual->actor) != 0)
186     goto no_realize;
187
188   visual_actor_set_video (visual->actor, visual->video);
189
190   visual_video_set_depth (visual->video,
191       visual_video_depth_enum_from_value (depth));
192   visual_video_set_dimension (visual->video, bscope->width, bscope->height);
193   pitch = GST_ROUND_UP_4 (bscope->width * visual->video->bpp);
194   visual_video_set_pitch (visual->video, pitch);
195   visual_actor_video_negotiate (visual->actor, 0, FALSE, FALSE);
196
197   GST_DEBUG_OBJECT (visual, "WxH: %dx%d, bpp: %d, pitch: %d, depth: %d",
198       bscope->width, bscope->height, visual->video->bpp, pitch, depth);
199
200   return TRUE;
201   /* ERRORS */
202 no_actors:
203   {
204     GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL),
205         ("could not create actors"));
206     gst_visual_clear_actors (visual);
207     return FALSE;
208   }
209 no_realize:
210   {
211     GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL),
212         ("could not realize actor"));
213     gst_visual_clear_actors (visual);
214     return FALSE;
215   }
216 }
217
218 static gboolean
219 gst_visual_render (GstAudioBaseVisualizer * bscope, GstBuffer * audio,
220     GstBuffer * video)
221 {
222   GstVisual *visual = GST_VISUAL (bscope);
223   GstMapInfo amap, vmap;
224   const guint16 *adata;
225   gint i, channels;
226   gboolean res = TRUE;
227
228   gst_buffer_map (audio, &amap, GST_MAP_READ);
229   gst_buffer_map (video, &vmap, GST_MAP_WRITE);
230
231   visual_video_set_buffer (visual->video, vmap.data);
232
233   channels = GST_AUDIO_INFO_CHANNELS (&bscope->ainfo);
234   adata = (const guint16 *) amap.data;
235
236 #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
237   {
238     VisBuffer *lbuf, *rbuf;
239     guint16 ldata[VISUAL_SAMPLES], rdata[VISUAL_SAMPLES];
240     VisAudioSampleRateType vrate;
241
242     lbuf = visual_buffer_new_with_buffer (ldata, sizeof (ldata), NULL);
243     rbuf = visual_buffer_new_with_buffer (rdata, sizeof (rdata), NULL);
244
245     if (channels == 2) {
246       for (i = 0; i < VISUAL_SAMPLES; i++) {
247         ldata[i] = *adata++;
248         rdata[i] = *adata++;
249       }
250     } else {
251       for (i = 0; i < VISUAL_SAMPLES; i++) {
252         ldata[i] = *adata;
253         rdata[i] = *adata++;
254       }
255     }
256
257     /* TODO(ensonic): move to setup */
258     switch (bscope->ainfo.rate) {
259       case 8000:
260         vrate = VISUAL_AUDIO_SAMPLE_RATE_8000;
261         break;
262       case 11250:
263         vrate = VISUAL_AUDIO_SAMPLE_RATE_11250;
264         break;
265       case 22500:
266         vrate = VISUAL_AUDIO_SAMPLE_RATE_22500;
267         break;
268       case 32000:
269         vrate = VISUAL_AUDIO_SAMPLE_RATE_32000;
270         break;
271       case 44100:
272         vrate = VISUAL_AUDIO_SAMPLE_RATE_44100;
273         break;
274       case 48000:
275         vrate = VISUAL_AUDIO_SAMPLE_RATE_48000;
276         break;
277       case 96000:
278         vrate = VISUAL_AUDIO_SAMPLE_RATE_96000;
279         break;
280       default:
281         visual_object_unref (VISUAL_OBJECT (lbuf));
282         visual_object_unref (VISUAL_OBJECT (rbuf));
283         GST_ERROR_OBJECT (visual, "unsupported rate %d", bscope->ainfo.rate);
284         res = FALSE;
285         goto done;
286     }
287
288     visual_audio_samplepool_input_channel (visual->audio->samplepool,
289         lbuf,
290         vrate, VISUAL_AUDIO_SAMPLE_FORMAT_S16,
291         (char *) VISUAL_AUDIO_CHANNEL_LEFT);
292     visual_audio_samplepool_input_channel (visual->audio->samplepool, rbuf,
293         vrate, VISUAL_AUDIO_SAMPLE_FORMAT_S16,
294         (char *) VISUAL_AUDIO_CHANNEL_RIGHT);
295
296     visual_object_unref (VISUAL_OBJECT (lbuf));
297     visual_object_unref (VISUAL_OBJECT (rbuf));
298
299   }
300 #else
301   if (channels == 2) {
302     guint16 *ldata = visual->audio->plugpcm[0];
303     guint16 *rdata = visual->audio->plugpcm[1];
304     for (i = 0; i < VISUAL_SAMPLES; i++) {
305       ldata[i] = *adata++;
306       rdata[i] = *adata++;
307     }
308   } else {
309     for (i = 0; i < VISUAL_SAMPLES; i++) {
310       ldata[i] = *adata;
311       rdata[i] = *adata++;
312     }
313   }
314 #endif
315
316   visual_audio_analyze (visual->audio);
317   visual_actor_run (visual->actor, visual->audio);
318   visual_video_set_buffer (visual->video, NULL);
319
320   GST_DEBUG_OBJECT (visual, "rendered one frame");
321 done:
322   gst_buffer_unmap (video, &vmap);
323   gst_buffer_unmap (audio, &amap);
324   return res;
325 }