2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
26 #include <gst/navigation/navigation.h>
28 #include "gstcacasink.h"
30 /* elementfactory information */
31 static GstElementDetails gst_cacasink_details = {
34 "A colored ASCII art videosink",
35 "Zeeshan Ali <zak147@yahoo.com>"
38 /* cacasink signals and args */
51 static GstStaticPadTemplate sink_template =
52 GST_STATIC_PAD_TEMPLATE (
56 GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB));
58 static void gst_cacasink_base_init (gpointer g_class);
59 static void gst_cacasink_class_init (GstCACASinkClass *klass);
60 static void gst_cacasink_init (GstCACASink *cacasink);
61 static void gst_cacasink_interface_init (GstImplementsInterfaceClass *klass);
62 static gboolean gst_cacasink_interface_supported (GstImplementsInterface *iface, GType type);
63 static void gst_cacasink_navigation_init (GstNavigationInterface *iface);
64 static void gst_cacasink_navigation_send_event (GstNavigation *navigation, GstStructure *structure);
66 static void gst_cacasink_chain (GstPad *pad, GstData *_data);
68 static void gst_cacasink_set_property (GObject *object, guint prop_id,
69 const GValue *value, GParamSpec *pspec);
70 static void gst_cacasink_get_property (GObject *object, guint prop_id,
71 GValue *value, GParamSpec *pspec);
73 static GstElementStateReturn gst_cacasink_change_state (GstElement *element);
75 static GstElementClass *parent_class = NULL;
78 gst_cacasink_get_type (void)
80 static GType cacasink_type = 0;
83 static const GTypeInfo cacasink_info = {
84 sizeof(GstCACASinkClass),
85 gst_cacasink_base_init,
87 (GClassInitFunc) gst_cacasink_class_init,
92 (GInstanceInitFunc) gst_cacasink_init,
95 static const GInterfaceInfo iface_info = {
96 (GInterfaceInitFunc) gst_cacasink_interface_init,
101 static const GInterfaceInfo navigation_info = {
102 (GInterfaceInitFunc) gst_cacasink_navigation_init,
107 cacasink_type = g_type_register_static (GST_TYPE_VIDEOSINK, "GstCACASink", &cacasink_info, 0);
109 g_type_add_interface_static (cacasink_type, GST_TYPE_IMPLEMENTS_INTERFACE,
111 g_type_add_interface_static (cacasink_type, GST_TYPE_NAVIGATION,
114 return cacasink_type;
117 #define GST_TYPE_CACADITHER (gst_cacasink_dither_get_type())
119 gst_cacasink_dither_get_type (void)
121 static GType dither_type = 0;
126 gchar *caca_dithernames[] = {
127 "NONE", "ORDERED2", "ORDERED4", "ORDERED8", "RANDOM", NULL};
131 dithers = g_new0(GEnumValue, n_dithers + 1);
133 for (i = 0; i < n_dithers; i++){
134 dithers[i].value = i;
135 dithers[i].value_name = g_strdup (caca_dithernames[i]);
136 dithers[i].value_nick = g_strdup (caca_dithernames[i]);
138 dithers[i].value = 0;
139 dithers[i].value_name = NULL;
140 dithers[i].value_nick = NULL;
142 dither_type = g_enum_register_static ("GstCACASinkDithers", dithers);
148 gst_cacasink_base_init (gpointer g_class)
150 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
152 gst_element_class_set_details (element_class, &gst_cacasink_details);
153 gst_element_class_add_pad_template (element_class,
154 gst_static_pad_template_get (&sink_template));
158 gst_cacasink_class_init (GstCACASinkClass *klass)
160 GObjectClass *gobject_class;
161 GstElementClass *gstelement_class;
162 GstVideoSinkClass *gstvs_class;
164 gobject_class = (GObjectClass*)klass;
165 gstelement_class = (GstElementClass*)klass;
166 gstvs_class = (GstVideoSinkClass*) klass;
168 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
170 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SCREEN_WIDTH,
171 g_param_spec_int("screen_width","screen_width","screen_width",
172 G_MININT,G_MAXINT,0,G_PARAM_READABLE)); /* CHECKME */
173 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SCREEN_HEIGHT,
174 g_param_spec_int("screen_height","screen_height","screen_height",
175 G_MININT,G_MAXINT,0,G_PARAM_READABLE)); /* CHECKME */
176 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DITHER,
177 g_param_spec_enum("dither","dither","dither",
178 GST_TYPE_CACADITHER, 0, G_PARAM_READWRITE));
180 gobject_class->set_property = gst_cacasink_set_property;
181 gobject_class->get_property = gst_cacasink_get_property;
183 gstelement_class->change_state = gst_cacasink_change_state;
187 gst_cacasink_interface_init (GstImplementsInterfaceClass *klass)
189 klass->supported = gst_cacasink_interface_supported;
193 gst_cacasink_interface_supported (GstImplementsInterface *iface, GType type)
195 g_assert (type == GST_TYPE_NAVIGATION);
197 return (GST_STATE (iface) != GST_STATE_NULL);
201 gst_cacasink_navigation_init (GstNavigationInterface *iface)
203 iface->send_event = gst_cacasink_navigation_send_event;
207 gst_cacasink_navigation_send_event (GstNavigation *navigation,
208 GstStructure *structure)
210 GstCACASink *cacasink = GST_CACASINK (navigation);
213 event = gst_event_new (GST_EVENT_NAVIGATION);
214 /*GST_EVENT_TIMESTAMP (event) = 0;*/
215 event->event_data.structure.structure = structure;
218 * Obviously, the pointer x,y coordinates need to be adjusted by the
219 * window size and relation to the bounding window. */
221 gst_pad_send_event (gst_pad_get_peer (GST_VIDEOSINK_PAD(cacasink)),
224 static GstPadLinkReturn
225 gst_cacasink_sinkconnect (GstPad *pad, const GstCaps *caps)
227 GstCACASink *cacasink;
228 GstStructure *structure;
230 cacasink = GST_CACASINK (gst_pad_get_parent (pad));
232 /*if (!GST_CAPS_IS_FIXED (caps))
233 return GST_PAD_LINK_DELAYED;*/
235 structure = gst_caps_get_structure (caps, 0);
236 gst_structure_get_int (structure, "width",
237 &(GST_VIDEOSINK_WIDTH (cacasink)));
238 gst_structure_get_int (structure, "height",
239 &(GST_VIDEOSINK_HEIGHT (cacasink)));
240 gst_structure_get_int (structure, "bpp", &cacasink->bpp);
241 gst_structure_get_int (structure, "red_mask", &cacasink->red_mask);
242 gst_structure_get_int (structure, "green_mask", &cacasink->green_mask);
243 gst_structure_get_int (structure, "blue_mask", &cacasink->blue_mask);
245 gst_video_sink_got_video_size (GST_VIDEOSINK (cacasink), GST_VIDEOSINK_WIDTH (cacasink), GST_VIDEOSINK_HEIGHT (cacasink));
247 /*if (cacasink->bitmap != NULL) {
248 caca_free_bitmap (cacasink->bitmap);
251 caca->bitmap = caca_create_bitmap (cacasink->bpp, cacasink->image_width, cacasink->image_height, cacasink->image_width * cacasink->bpp/8, cacasink->red_mask, cacasink->green_mask, cacasink->blue_mask);*/
253 return GST_PAD_LINK_OK;
257 gst_cacasink_init (GstCACASink *cacasink)
259 GST_VIDEOSINK_PAD (cacasink) = gst_pad_new_from_template (
260 gst_static_pad_template_get (&sink_template), "sink");
261 gst_element_add_pad (GST_ELEMENT (cacasink), GST_VIDEOSINK_PAD (cacasink));
262 gst_pad_set_chain_function (GST_VIDEOSINK_PAD (cacasink),
264 gst_pad_set_link_function (GST_VIDEOSINK_PAD (cacasink),
265 gst_cacasink_sinkconnect);
267 cacasink->screen_width = GST_CACA_DEFAULT_SCREEN_WIDTH;
268 cacasink->screen_height = GST_CACA_DEFAULT_SCREEN_HEIGHT;
269 cacasink->bpp = GST_CACA_DEFAULT_BPP;
270 cacasink->red_mask = GST_CACA_DEFAULT_RED_MASK;
271 cacasink->green_mask = GST_CACA_DEFAULT_GREEN_MASK;
272 cacasink->blue_mask = GST_CACA_DEFAULT_BLUE_MASK;
274 cacasink->bitmap = NULL;
276 GST_FLAG_SET(cacasink, GST_ELEMENT_THREAD_SUGGESTED);
280 gst_cacasink_chain (GstPad *pad, GstData *_data)
282 GstBuffer *buf = GST_BUFFER (_data);
283 GstCACASink *cacasink;
284 GstClockTime time = GST_BUFFER_TIMESTAMP (buf);
287 g_return_if_fail (pad != NULL);
288 g_return_if_fail (GST_IS_PAD (pad));
289 g_return_if_fail (buf != NULL);
291 cacasink = GST_CACASINK (gst_pad_get_parent (pad));
293 if (GST_VIDEOSINK_CLOCK (cacasink) && time != -1) {
296 cacasink->id = gst_clock_new_single_shot_id (
297 GST_VIDEOSINK_CLOCK (cacasink), time);
299 GST_DEBUG ("videosink: clock %s wait: %" G_GUINT64_FORMAT " %u",
300 GST_OBJECT_NAME (GST_VIDEOSINK_CLOCK (cacasink)),
301 time, GST_BUFFER_SIZE (buf));
303 ret = gst_clock_id_wait (cacasink->id, &jitter);
304 gst_clock_id_free (cacasink->id);
309 caca_draw_bitmap (0, 0, cacasink->screen_width-1, cacasink->screen_height-1, cacasink->bitmap, GST_BUFFER_DATA (buf));
312 if (GST_VIDEOSINK_CLOCK (cacasink)) {
313 jitter = gst_clock_get_time (GST_VIDEOSINK_CLOCK (cacasink)) - time;
315 cacasink->correction = (cacasink->correction + jitter) >> 1;
316 cacasink->correction = 0;
320 gst_buffer_unref(buf);
325 gst_cacasink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
327 GstCACASink *cacasink;
329 /* it's not null if we got it, but it might not be ours */
330 g_return_if_fail (GST_IS_CACASINK (object));
332 cacasink = GST_CACASINK (object);
336 cacasink->dither = g_value_get_enum (value);
345 gst_cacasink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
347 GstCACASink *cacasink;
349 /* it's not null if we got it, but it might not be ours */
350 cacasink = GST_CACASINK(object);
353 case ARG_SCREEN_WIDTH: {
354 g_value_set_int (value, cacasink->screen_width);
357 case ARG_SCREEN_HEIGHT: {
358 g_value_set_int (value, cacasink->screen_height);
362 g_value_set_enum (value, cacasink->dither);
366 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
373 gst_cacasink_open (GstCACASink *cacasink)
375 g_return_val_if_fail (!GST_FLAG_IS_SET (cacasink ,GST_CACASINK_OPEN), FALSE);
379 cacasink->screen_width = caca_get_width ();
380 cacasink->screen_height = caca_get_height ();
381 caca_set_dithering (cacasink->dither + CACA_DITHERING_NONE);
383 cacasink->bitmap = caca_create_bitmap (
385 GST_VIDEOSINK_WIDTH (cacasink),
386 GST_VIDEOSINK_HEIGHT (cacasink),
387 GST_VIDEOSINK_WIDTH (cacasink) * cacasink->bpp/8,
389 cacasink->green_mask,
393 GST_FLAG_SET (cacasink, GST_CACASINK_OPEN);
399 gst_cacasink_close (GstCACASink *cacasink)
401 g_return_if_fail (GST_FLAG_IS_SET (cacasink ,GST_CACASINK_OPEN));
403 caca_free_bitmap (cacasink->bitmap);
404 cacasink->bitmap = NULL;
407 GST_FLAG_UNSET (cacasink, GST_CACASINK_OPEN);
410 static GstElementStateReturn
411 gst_cacasink_change_state (GstElement *element)
413 g_return_val_if_fail (GST_IS_CACASINK (element), GST_STATE_FAILURE);
415 if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
416 if (GST_FLAG_IS_SET (element, GST_CACASINK_OPEN))
417 gst_cacasink_close (GST_CACASINK (element));
419 if (!GST_FLAG_IS_SET (element, GST_CACASINK_OPEN)) {
420 if (!gst_cacasink_open (GST_CACASINK (element)))
421 return GST_STATE_FAILURE;
425 if (GST_ELEMENT_CLASS (parent_class)->change_state)
426 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
428 return GST_STATE_SUCCESS;
432 plugin_init (GstPlugin *plugin)
434 /* Loading the library containing GstVideoSink, our parent object */
435 if (!gst_library_load ("gstvideo"))
438 if (!gst_element_register (plugin, "cacasink", GST_RANK_NONE, GST_TYPE_CACASINK))
448 "Colored ASCII Art video sink",