gstgoom.c 10.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* gstgoom.c: implementation of goom drawing element
 * Copyright (C) <2001> Richard Boulton <richard@tartarus.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

20 21 22
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
23 24
#include <config.h>
#include <gst/gst.h>
25
#include <gst/video/video.h>
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#include "goom_core.h"

#define GST_TYPE_GOOM (gst_goom_get_type())
#define GST_GOOM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GOOM,GstGOOM))
#define GST_GOOM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GOOM,GstGOOM))
#define GST_IS_GOOM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GOOM))
#define GST_IS_GOOM_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GOOM))

typedef struct _GstGOOM GstGOOM;
typedef struct _GstGOOMClass GstGOOMClass;

struct _GstGOOM {
  GstElement element;

  /* pads */
  GstPad *sinkpad,*srcpad;

43
  /* the timestamp of the next frame */
44
  guint64 next_time;
Wim Taymans's avatar
Wim Taymans committed
45
  gint16 datain[2][512];
46

47
  /* video state */
48
  gfloat fps;
49 50
  gint width;
  gint height;
Wim Taymans's avatar
Wim Taymans committed
51 52
  gint channels;
  gboolean srcnegotiated;
53 54 55 56 57 58 59 60 61 62 63 64
};

struct _GstGOOMClass {
  GstElementClass parent_class;
};

GType gst_goom_get_type(void);


/* elementfactory information */
static GstElementDetails gst_goom_details = {
  "GOOM: what a GOOM!",
65
  "Visualization",
66
  "Takes frames of data and outputs video frames using the GOOM filter",
Ronald S. Bultje's avatar
Ronald S. Bultje committed
67
  "Wim Taymans <wim.taymans@chello.be>"
68 69 70 71 72 73 74 75 76 77 78 79 80
};

/* signals and args */
enum {
  /* FILL ME */
  LAST_SIGNAL
};

enum {
  ARG_0,
  /* FILL ME */
};

81
GST_PAD_TEMPLATE_FACTORY (src_template,
82 83 84
  "src",
  GST_PAD_SRC,
  GST_PAD_ALWAYS,
85
  gst_caps_new (
86
    "goomsrc",
87 88
    "video/x-raw-rgb",
    GST_VIDEO_RGB_PAD_TEMPLATE_PROPS_32
89 90 91
  )
)

92
GST_PAD_TEMPLATE_FACTORY (sink_template,
93
  "sink",				/* the name of the pads */
94
  GST_PAD_SINK,				/* type of the pad */
95
  GST_PAD_ALWAYS,			/* ALWAYS/SOMETIMES */
96 97
  GST_CAPS_NEW (
    "goomsink",				/* the name of the caps */
98
    "audio/x-raw-int",			/* the mime type of the caps */
99 100 101 102 103 104
       /* Properties follow: */
      "endianness", GST_PROPS_INT (G_BYTE_ORDER),
      "signed",     GST_PROPS_BOOLEAN (TRUE),
      "width",      GST_PROPS_INT (16),
      "depth",      GST_PROPS_INT (16),
      "rate",       GST_PROPS_INT_RANGE (8000, 96000),
Wim Taymans's avatar
Wim Taymans committed
105
      "channels",   GST_PROPS_INT_RANGE (1, 2)
106 107 108 109 110
  )
)


static void		gst_goom_class_init	(GstGOOMClass *klass);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
111
static void		gst_goom_base_init	(GstGOOMClass *klass);
112
static void		gst_goom_init		(GstGOOM *goom);
Wim Taymans's avatar
Wim Taymans committed
113
static void		gst_goom_dispose	(GObject *object);
114

115 116 117
static GstElementStateReturn
			gst_goom_change_state 	(GstElement *element);

118
static void		gst_goom_chain		(GstPad *pad, GstData *_data);
119

Wim Taymans's avatar
Wim Taymans committed
120 121
static GstPadLinkReturn gst_goom_sinkconnect 	(GstPad *pad, GstCaps *caps);
static GstPadLinkReturn gst_goom_srcconnect 	(GstPad *pad, GstCaps *caps);
122 123 124 125 126 127 128 129 130 131 132

static GstElementClass *parent_class = NULL;

GType
gst_goom_get_type (void)
{
  static GType type = 0;

  if (!type) {
    static const GTypeInfo info = {
      sizeof (GstGOOMClass),      
Ronald S. Bultje's avatar
Ronald S. Bultje committed
133
      (GBaseInitFunc) gst_goom_base_init,      
134 135 136 137 138 139 140 141 142 143 144 145 146
      NULL,      
      (GClassInitFunc) gst_goom_class_init,
      NULL,
      NULL,
      sizeof (GstGOOM),
      0,
      (GInstanceInitFunc) gst_goom_init,
    };
    type = g_type_register_static (GST_TYPE_ELEMENT, "GstGOOM", &info, 0);
  }
  return type;
}

Ronald S. Bultje's avatar
Ronald S. Bultje committed
147 148 149 150 151 152 153 154 155 156 157 158
static void
gst_goom_base_init (GstGOOMClass *klass)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);

  gst_element_class_set_details (element_class, &gst_goom_details);
  gst_element_class_add_pad_template (element_class,
	GST_PAD_TEMPLATE_GET (sink_template));
  gst_element_class_add_pad_template (element_class,
	GST_PAD_TEMPLATE_GET (src_template));
}

159 160 161 162 163 164 165 166 167 168 169
static void
gst_goom_class_init(GstGOOMClass *klass)
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

  gobject_class = (GObjectClass*) klass;
  gstelement_class = (GstElementClass*) klass;

  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);

Wim Taymans's avatar
Wim Taymans committed
170
  gobject_class->dispose	= gst_goom_dispose;
171 172

  gstelement_class->change_state = gst_goom_change_state;
173 174 175 176 177 178 179
}

static void
gst_goom_init (GstGOOM *goom)
{
  /* create the sink and src pads */
  goom->sinkpad = gst_pad_new_from_template (
180
		  GST_PAD_TEMPLATE_GET (sink_template ), "sink");
181
  goom->srcpad = gst_pad_new_from_template (
182
		  GST_PAD_TEMPLATE_GET (src_template ), "src");
183 184 185
  gst_element_add_pad (GST_ELEMENT (goom), goom->sinkpad);
  gst_element_add_pad (GST_ELEMENT (goom), goom->srcpad);

Wim Taymans's avatar
Wim Taymans committed
186 187
  GST_FLAG_SET (goom, GST_ELEMENT_EVENT_AWARE);

188
  gst_pad_set_chain_function (goom->sinkpad, gst_goom_chain);
189
  gst_pad_set_link_function (goom->sinkpad, gst_goom_sinkconnect);
190

Wim Taymans's avatar
Wim Taymans committed
191 192
  gst_pad_set_link_function (goom->srcpad, gst_goom_srcconnect);

193 194
  goom->width = 320;
  goom->height = 200;
195
  goom->fps = 25.; /* desired frame rate */
Wim Taymans's avatar
Wim Taymans committed
196 197 198 199 200 201 202 203 204 205 206
  goom->channels = 0;
  /* set to something */
  goom_init (50, 50);
}

static void
gst_goom_dispose (GObject *object)
{
  goom_close ();
  
  G_OBJECT_CLASS (parent_class)->dispose (object);
207 208
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
209
static GstPadLinkReturn
210 211 212 213 214 215
gst_goom_sinkconnect (GstPad *pad, GstCaps *caps)
{
  GstGOOM *goom;
  goom = GST_GOOM (gst_pad_get_parent (pad));

  if (!GST_CAPS_IS_FIXED (caps)) {
216
    return GST_PAD_LINK_DELAYED;
217 218
  }

Wim Taymans's avatar
Wim Taymans committed
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
  gst_caps_get_int (caps, "channels", &goom->channels);

  return GST_PAD_LINK_OK;
}

static GstPadLinkReturn
gst_goom_srcconnect (GstPad *pad, GstCaps *caps)
{
  GstGOOM *goom;
  goom = GST_GOOM (gst_pad_get_parent (pad));

  if (!GST_CAPS_IS_FIXED (caps)) {
    return GST_PAD_LINK_DELAYED;
  }

234 235 236 237 238 239 240 241 242
  if (gst_caps_has_property_typed (caps, "width", GST_PROPS_INT_TYPE)) {
    gst_caps_get_int (caps, "width", &goom->width);
  }
  if (gst_caps_has_property_typed (caps, "height", GST_PROPS_INT_TYPE)) {
    gst_caps_get_int (caps, "height", &goom->height);
  }
  if (gst_caps_has_property_typed (caps, "framerate", GST_PROPS_FLOAT_TYPE)) {
    gst_caps_get_float (caps, "framerate", &goom->fps);
  }
Wim Taymans's avatar
Wim Taymans committed
243 244 245 246

  goom_set_resolution (goom->width, goom->height);
  goom->srcnegotiated = TRUE;

247
  return GST_PAD_LINK_OK;
248 249
}

Wim Taymans's avatar
Wim Taymans committed
250 251 252 253 254 255 256
static gboolean
gst_goom_negotiate_default (GstGOOM *goom)
{
  GstCaps *caps;

  caps = GST_CAPS_NEW (
	     "goomsrc",
257
	     "video/x-raw-rgb",
Wim Taymans's avatar
Wim Taymans committed
258 259 260
	       "format", 	GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")), 
	       "bpp", 		GST_PROPS_INT (32), 
	       "depth", 	GST_PROPS_INT (32), 
261 262 263 264
	       "endianness", 	GST_PROPS_INT (G_BIG_ENDIAN),
	       "red_mask", 	GST_PROPS_INT (R_MASK_32), 
	       "green_mask", 	GST_PROPS_INT (G_MASK_32), 
	       "blue_mask", 	GST_PROPS_INT (B_MASK_32), 
Wim Taymans's avatar
Wim Taymans committed
265
	       "width", 	GST_PROPS_INT (goom->width), 
266 267
	       "height", 	GST_PROPS_INT (goom->height),
	       "framerate",	GST_PROPS_FLOAT (goom->fps)
Wim Taymans's avatar
Wim Taymans committed
268 269 270 271 272 273 274 275 276 277 278 279
	   );

  if (gst_pad_try_set_caps (goom->srcpad, caps) <= 0) {
    return FALSE;
  }

  goom_set_resolution (goom->width, goom->height);
  goom->srcnegotiated = TRUE;

  return TRUE;
}

280
static void
281
gst_goom_chain (GstPad *pad, GstData *_data)
282
{
283
  GstBuffer *bufin = GST_BUFFER (_data);
284 285 286
  GstGOOM *goom;
  GstBuffer *bufout;
  guint32 samples_in;
Wim Taymans's avatar
Wim Taymans committed
287 288
  gint16 *data;
  gint i;
289 290 291

  goom = GST_GOOM (gst_pad_get_parent (pad));

292
  GST_DEBUG ("GOOM: chainfunc called");
293

Wim Taymans's avatar
Wim Taymans committed
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
  if (GST_IS_EVENT (bufin)) {
    GstEvent *event = GST_EVENT (bufin);

    switch (GST_EVENT_TYPE (event)) {
      case GST_EVENT_DISCONTINUOUS:
      {
	gint64 value = 0;

	gst_event_discont_get_value (event, GST_FORMAT_TIME, &value);

        goom->next_time = value;
      }
      default:
	gst_pad_event_default (pad, event);
	break;
    }
    return;
  }

Wim Taymans's avatar
Wim Taymans committed
313
  if (goom->channels == 0) {
314
    gst_element_error (GST_ELEMENT (goom), "sink format not negotiated");
Wim Taymans's avatar
Wim Taymans committed
315 316 317 318 319 320 321 322
    goto done;
  }

  if (!GST_PAD_IS_USABLE (goom->srcpad))
    goto done;

  if (!goom->srcnegotiated) {
    if (!gst_goom_negotiate_default (goom)) {
323
      gst_element_error (GST_ELEMENT (goom), "could not negotiate src format");
Wim Taymans's avatar
Wim Taymans committed
324 325 326 327 328
      goto done;
    }
  }

  samples_in = GST_BUFFER_SIZE (bufin) / (sizeof (gint16) * goom->channels);
329

330
  GST_DEBUG ("input buffer has %d samples", samples_in);
331

Wim Taymans's avatar
Wim Taymans committed
332 333
  if (GST_BUFFER_TIMESTAMP (bufin) < goom->next_time || samples_in < 512) {
    goto done;
334
  }
Wim Taymans's avatar
Wim Taymans committed
335 336

  data = (gint16 *) GST_BUFFER_DATA (bufin);
Wim Taymans's avatar
Wim Taymans committed
337 338 339 340 341
  if (goom->channels == 2) {
    for (i=0; i < 512; i++) {
      goom->datain[0][i] = *data++;
      goom->datain[1][i] = *data++;
    }
Wim Taymans's avatar
Wim Taymans committed
342
  }
Wim Taymans's avatar
Wim Taymans committed
343 344 345 346
  else {
    for (i=0; i < 512; i++) {
      goom->datain[0][i] = *data;
      goom->datain[1][i] = *data++;
347 348 349 350 351
    }
  }

  bufout = gst_buffer_new ();
  GST_BUFFER_SIZE (bufout) = goom->width * goom->height * 4;
Wim Taymans's avatar
Wim Taymans committed
352 353
  GST_BUFFER_DATA (bufout) = (guchar *) goom_update (goom->datain);
  GST_BUFFER_TIMESTAMP (bufout) = goom->next_time;
354 355
  GST_BUFFER_FLAG_SET (bufout, GST_BUFFER_DONTFREE);

Wim Taymans's avatar
Wim Taymans committed
356
  goom->next_time += GST_SECOND / goom->fps;
Wim Taymans's avatar
Wim Taymans committed
357

358
  gst_pad_push (goom->srcpad, GST_DATA (bufout));
359

Wim Taymans's avatar
Wim Taymans committed
360
done:
361 362
  gst_buffer_unref (bufin);

363
  GST_DEBUG ("GOOM: exiting chainfunc");
364 365
}

366 367 368 369 370 371 372 373 374 375 376 377
static GstElementStateReturn
gst_goom_change_state (GstElement *element)
{ 
  GstGOOM *goom = GST_GOOM (element);

  switch (GST_STATE_TRANSITION (element)) {
    case GST_STATE_NULL_TO_READY:
      break;
    case GST_STATE_READY_TO_NULL:
      break; 
    case GST_STATE_READY_TO_PAUSED:
      goom->next_time = 0;
Wim Taymans's avatar
Wim Taymans committed
378 379
      goom->srcnegotiated = FALSE;
      goom->channels = 0;
380 381 382 383 384 385 386 387 388 389 390 391 392
      break;
    case GST_STATE_PAUSED_TO_READY:
      break;
    default:
      break;
  }

  if (GST_ELEMENT_CLASS (parent_class)->change_state)
    return GST_ELEMENT_CLASS (parent_class)->change_state (element);

  return GST_STATE_SUCCESS;
}

393
static gboolean
Ronald S. Bultje's avatar
Ronald S. Bultje committed
394
plugin_init (GstPlugin *plugin)
395
{
Ronald S. Bultje's avatar
Ronald S. Bultje committed
396 397
  return gst_element_register (plugin, "goom",
			       GST_RANK_NONE, GST_TYPE_GOOM);
398 399
}

Ronald S. Bultje's avatar
Ronald S. Bultje committed
400
GST_PLUGIN_DEFINE (
401 402 403
  GST_VERSION_MAJOR,
  GST_VERSION_MINOR,
  "goom",
Ronald S. Bultje's avatar
Ronald S. Bultje committed
404 405 406 407 408 409 410 411
  "GOOM visualization filter",
  plugin_init,
  VERSION,
  GST_LICENSE,
  GST_COPYRIGHT,
  GST_PACKAGE,
  GST_ORIGIN
)