Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / gst / real / gstrealvideodec.c
1 /* RealVideo wrapper plugin
2  *
3  * Copyright (C) 2005 Lutz Mueller <lutz@topfrose.de>
4  * Copyright (C) 2006 Edward Hervey <bilboed@bilboed.com>
5  * 
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "gstreal.h"
27 #include "gstrealvideodec.h"
28
29 #include <string.h>
30
31 GST_DEBUG_CATEGORY_STATIC (realvideode_debug);
32 #define GST_CAT_DEFAULT realvideode_debug
33
34 static GstStaticPadTemplate snk_t =
35 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
36     GST_STATIC_CAPS ("video/x-pn-realvideo, " "rmversion = (int) [ 2, 4 ]"));
37 static GstStaticPadTemplate src_t =
38 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
39     GST_STATIC_CAPS ("video/x-raw-yuv, "
40         "format = (fourcc) I420, "
41         "framerate = (fraction) [0/1, MAX], "
42         "width = (int) [ 16, 4096 ], " "height = (int) [ 16, 4096 ] "));
43
44 #define DEFAULT_RV20_NAMES "drv2.so:drv2.so.6.0"
45 #define DEFAULT_RV30_NAMES "drvc.so:drv3.so.6.0"
46 #define DEFAULT_RV40_NAMES "drvc.so:drv4.so.6.0"
47 #define DEFAULT_MAX_ERRORS 25
48
49 enum
50 {
51   PROP_0,
52   PROP_REAL_CODECS_PATH,
53   PROP_RV20_NAMES,
54   PROP_RV30_NAMES,
55   PROP_RV40_NAMES,
56   PROP_MAX_ERRORS
57 };
58
59 GST_BOILERPLATE (GstRealVideoDec, gst_real_video_dec, GstElement,
60     GST_TYPE_ELEMENT);
61
62 static gboolean open_library (GstRealVideoDec * dec,
63     GstRealVideoDecVersion version, GstRVDecLibrary * lib);
64 static void close_library (GstRealVideoDec * dec, GstRVDecLibrary * lib);
65
66 typedef struct
67 {
68   guint32 datalen;
69   gint32 interpolate;
70   gint32 nfragments;
71   gpointer fragments;
72   guint32 flags;
73   guint32 timestamp;
74 } RVInData;
75
76 typedef struct
77 {
78   guint32 frames;
79   guint32 notes;
80   guint32 timestamp;
81   guint32 width;
82   guint32 height;
83 } RVOutData;
84
85 static GstFlowReturn
86 gst_real_video_dec_chain (GstPad * pad, GstBuffer * in)
87 {
88   GstRealVideoDec *dec;
89   guint8 *data;
90   guint size;
91   GstFlowReturn ret;
92   RVInData tin;
93   RVOutData tout;
94   GstClockTime timestamp, duration;
95   GstBuffer *out;
96   guint32 result;
97   guint frag_count, frag_size;
98
99   dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad));
100
101   if (G_UNLIKELY (dec->lib.Transform == NULL || dec->lib.module == NULL))
102     goto not_negotiated;
103
104   data = GST_BUFFER_DATA (in);
105   size = GST_BUFFER_SIZE (in);
106   timestamp = GST_BUFFER_TIMESTAMP (in);
107   duration = GST_BUFFER_DURATION (in);
108
109   GST_DEBUG_OBJECT (dec, "got buffer of size %u, timestamp %" GST_TIME_FORMAT,
110       size, GST_TIME_ARGS (timestamp));
111
112   /* alloc output buffer */
113   ret = gst_pad_alloc_buffer (dec->src, GST_BUFFER_OFFSET_NONE,
114       dec->width * dec->height * 3 / 2, GST_PAD_CAPS (dec->src), &out);
115   if (ret != GST_FLOW_OK)
116     goto alloc_failed;
117
118   GST_BUFFER_TIMESTAMP (out) = timestamp;
119   GST_BUFFER_DURATION (out) = duration;
120
121   frag_count = *data++;
122   frag_size = (frag_count + 1) * 8;
123   size -= (frag_size + 1);
124
125   GST_DEBUG_OBJECT (dec, "frag_count %u, frag_size %u, data size %u",
126       frag_count, frag_size, size);
127
128   /* Decode.
129    *
130    * The Buffers contain
131    *
132    *  0                   1                   2                   3
133    *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
134    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135    * |  nfragments   |   fragment1 ...                               |
136    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
137    * |  ....                                                         |
138    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
139    * |  ...          |   fragment2 ...                               |
140    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
141    *    ....                                                          
142    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
143    * |  ...          |   fragment data                               |
144    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
145    *
146    * nfragments: number of fragments 
147    * fragmentN: 8 bytes of fragment data (nfragements + 1) of them
148    * fragment data: the data of the fragments.
149    */
150   tin.datalen = size;
151   tin.interpolate = 0;
152   tin.nfragments = frag_count;
153   tin.fragments = data;
154   tin.flags = 0;
155   tin.timestamp = timestamp;
156
157   /* jump over the frag table to the fragments */
158   data += frag_size;
159
160   result = dec->lib.Transform (
161       (gchar *) data,
162       (gchar *) GST_BUFFER_DATA (out), &tin, &tout, dec->lib.context);
163   if (result)
164     goto could_not_transform;
165
166   /* When we decoded a frame, reset the error counter. We only fail after N
167    * consecutive decoding errors. */
168   dec->error_count = 0;
169
170   gst_buffer_unref (in);
171
172   /* Check for new dimensions */
173   if (tout.frames && ((dec->width != tout.width)
174           || (dec->height != tout.height))) {
175     GstCaps *caps = gst_caps_copy (GST_PAD_CAPS (dec->src));
176     GstStructure *s = gst_caps_get_structure (caps, 0);
177
178     GST_DEBUG_OBJECT (dec, "New dimensions: %"
179         G_GUINT32_FORMAT " x %" G_GUINT32_FORMAT, tout.width, tout.height);
180
181     gst_structure_set (s, "width", G_TYPE_INT, (gint) tout.width,
182         "height", G_TYPE_INT, (gint) tout.height, NULL);
183
184     gst_pad_set_caps (dec->src, caps);
185     gst_buffer_set_caps (out, caps);
186     gst_caps_unref (caps);
187
188     dec->width = tout.width;
189     dec->height = tout.height;
190     GST_BUFFER_SIZE (out) = dec->width * dec->height * 3 / 2;
191   }
192
193   GST_DEBUG_OBJECT (dec,
194       "Pushing out buffer with timestamp %" GST_TIME_FORMAT,
195       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)));
196
197   if ((ret = gst_pad_push (dec->src, out)) != GST_FLOW_OK)
198     goto could_not_push;
199
200   return ret;
201
202   /* Errors */
203 not_negotiated:
204   {
205     GST_WARNING_OBJECT (dec, "decoder not open, probably no input caps set "
206         "yet, caps on input buffer: %" GST_PTR_FORMAT, GST_BUFFER_CAPS (in));
207     gst_buffer_unref (in);
208     return GST_FLOW_NOT_NEGOTIATED;
209   }
210 alloc_failed:
211   {
212     GST_DEBUG_OBJECT (dec, "buffer alloc failed: %s", gst_flow_get_name (ret));
213     gst_buffer_unref (in);
214     return ret;
215   }
216 could_not_transform:
217   {
218     gst_buffer_unref (out);
219     gst_buffer_unref (in);
220
221     dec->error_count++;
222
223     if (dec->max_errors && dec->error_count >= dec->max_errors) {
224       GST_ELEMENT_ERROR (dec, STREAM, DECODE,
225           ("Could not decode buffer: %" G_GUINT32_FORMAT, result), (NULL));
226       return GST_FLOW_ERROR;
227     } else {
228       GST_ELEMENT_WARNING (dec, STREAM, DECODE,
229           ("Could not decode buffer: %" G_GUINT32_FORMAT, result), (NULL));
230       return GST_FLOW_OK;
231     }
232   }
233 could_not_push:
234   {
235     GST_DEBUG_OBJECT (dec, "Could not push buffer: %s",
236         gst_flow_get_name (ret));
237     return ret;
238   }
239 }
240
241 static GstCaps *
242 gst_real_video_dec_getcaps (GstPad * pad)
243 {
244   GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad));
245   GstCaps *res;
246
247   if (dec->checked_modules) {
248     GValue versions = { 0 };
249     GValue version = { 0 };
250
251     GST_LOG_OBJECT (dec, "constructing caps");
252
253     g_value_init (&versions, GST_TYPE_LIST);
254     g_value_init (&version, G_TYPE_INT);
255
256     if (dec->valid_rv20) {
257       g_value_set_int (&version, GST_REAL_VIDEO_DEC_VERSION_2);
258       gst_value_list_append_value (&versions, &version);
259     }
260     if (dec->valid_rv30) {
261       g_value_set_int (&version, GST_REAL_VIDEO_DEC_VERSION_3);
262       gst_value_list_append_value (&versions, &version);
263     }
264     if (dec->valid_rv40) {
265       g_value_set_int (&version, GST_REAL_VIDEO_DEC_VERSION_4);
266       gst_value_list_append_value (&versions, &version);
267     }
268
269     if (gst_value_list_get_size (&versions) > 0) {
270       res = gst_caps_new_simple ("video/x-pn-realvideo", NULL);
271       gst_structure_set_value (gst_caps_get_structure (res, 0),
272           "rmversion", &versions);
273     } else {
274       res = gst_caps_new_empty ();
275     }
276     g_value_unset (&versions);
277     g_value_unset (&version);
278   } else {
279     GST_LOG_OBJECT (dec, "returning padtemplate caps");
280     res = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
281   }
282   GST_LOG_OBJECT (dec, "returning caps %" GST_PTR_FORMAT, res);
283
284   return res;
285 }
286
287 static gboolean
288 gst_real_video_dec_setcaps (GstPad * pad, GstCaps * caps)
289 {
290   GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad));
291   GstStructure *s = gst_caps_get_structure (caps, 0);
292   gint version, res, width, height, format, subformat;
293   gint framerate_num, framerate_denom;
294   gchar data[36];
295   gboolean bres;
296   const GValue *v;
297
298   if (!gst_structure_get_int (s, "rmversion", &version) ||
299       !gst_structure_get_int (s, "width", (gint *) & width) ||
300       !gst_structure_get_int (s, "height", (gint *) & height) ||
301       !gst_structure_get_int (s, "format", &format) ||
302       !gst_structure_get_int (s, "subformat", &subformat) ||
303       !gst_structure_get_fraction (s, "framerate", &framerate_num,
304           &framerate_denom))
305     goto missing_keys;
306
307   GST_LOG_OBJECT (dec, "Setting version to %d", version);
308
309   close_library (dec, &dec->lib);
310
311   if (!open_library (dec, version, &dec->lib))
312     goto open_failed;
313
314   /* Initialize REAL driver. */
315   GST_WRITE_UINT16_LE (data + 0, 11);
316   GST_WRITE_UINT16_LE (data + 2, width);
317   GST_WRITE_UINT16_LE (data + 4, height);
318   GST_WRITE_UINT16_LE (data + 6, 0);
319   GST_WRITE_UINT32_LE (data + 8, 0);
320   GST_WRITE_UINT32_LE (data + 12, subformat);
321   GST_WRITE_UINT32_LE (data + 16, 1);
322   GST_WRITE_UINT32_LE (data + 20, format);
323
324   if ((res = dec->lib.Init (&data, &dec->lib.context)))
325     goto could_not_initialize;
326
327   if ((v = gst_structure_get_value (s, "codec_data"))) {
328     GstBuffer *buf;
329     guint32 *msgdata;
330     guint i;
331     guint8 *bufdata;
332     guint bufsize;
333     struct
334     {
335       guint32 type;
336       guint32 msg;
337       gpointer data;
338       guint32 extra[6];
339     } msg;
340
341     buf = g_value_peek_pointer (v);
342
343     bufdata = GST_BUFFER_DATA (buf);
344     bufsize = GST_BUFFER_SIZE (buf);
345
346     /* skip format and subformat */
347     bufdata += 8;
348     bufsize -= 8;
349
350     GST_LOG_OBJECT (dec, "Creating custom message of length %d", bufsize);
351
352     msgdata = g_new0 (guint32, bufsize + 2);
353     if (!msgdata)
354       goto could_not_allocate;
355
356     msg.type = 0x24;
357     msg.msg = 1 + ((subformat >> 16) & 7);
358     msg.data = msgdata;
359     for (i = 0; i < 6; i++)
360       msg.extra[i] = 0;
361     msgdata[0] = width;
362     msgdata[1] = height;
363     for (i = 0; i < bufsize; i++)
364       msgdata[i + 2] = 4 * (guint32) bufdata[i];
365
366     res = dec->lib.Message (&msg, dec->lib.context);
367
368     g_free (msgdata);
369     if (res)
370       goto could_not_send_message;
371   }
372
373   caps = gst_caps_new_simple ("video/x-raw-yuv",
374       "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
375       "framerate", GST_TYPE_FRACTION, framerate_num, framerate_denom,
376       "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
377
378   /* set PAR if one was specified in the sink caps */
379   if ((v = gst_structure_get_value (s, "pixel-aspect-ratio"))) {
380     gst_structure_set_value (gst_caps_get_structure (caps, 0),
381         "pixel-aspect-ratio", v);
382   }
383
384   bres = gst_pad_set_caps (GST_PAD (dec->src), caps);
385   gst_caps_unref (caps);
386   if (!bres)
387     goto could_not_set_caps;
388
389   dec->version = version;
390   dec->width = width;
391   dec->height = height;
392   dec->format = format;
393   dec->subformat = subformat;
394   dec->framerate_num = framerate_num;
395   dec->framerate_denom = framerate_denom;
396
397   return TRUE;
398
399 missing_keys:
400   {
401     GST_ERROR_OBJECT (dec, "Could not find all necessary keys in structure.");
402     return FALSE;
403   }
404 open_failed:
405   {
406     GST_ERROR_OBJECT (dec, "failed to open library");
407     return FALSE;
408   }
409 could_not_initialize:
410   {
411     GST_ERROR_OBJECT (dec, "Initialization of REAL driver failed (%i).", res);
412     close_library (dec, &dec->lib);
413     return FALSE;
414   }
415 could_not_allocate:
416   {
417     GST_ERROR_OBJECT (dec, "Could not allocate memory.");
418     close_library (dec, &dec->lib);
419     return FALSE;
420   }
421 could_not_send_message:
422   {
423     GST_ERROR_OBJECT (dec, "Failed to send custom message needed for "
424         "initialization (%i).", res);
425     close_library (dec, &dec->lib);
426     return FALSE;
427   }
428 could_not_set_caps:
429   {
430     GST_ERROR_OBJECT (dec, "Could not convince peer to accept dimensions "
431         "%i x %i.", dec->width, dec->height);
432     close_library (dec, &dec->lib);
433     return FALSE;
434   }
435 }
436
437 /* Attempts to open the correct library for the configured version */
438
439 static gboolean
440 open_library (GstRealVideoDec * dec, GstRealVideoDecVersion version,
441     GstRVDecLibrary * lib)
442 {
443   gpointer rv_custom_msg, rv_free, rv_init, rv_transform;
444   GModule *module = NULL;
445   const gchar *path, *names;
446   gchar **split_names, **split_path;
447   int i, j;
448
449   GST_DEBUG_OBJECT (dec,
450       "Attempting to open shared library for real video version %d", version);
451
452   path = dec->real_codecs_path ? dec->real_codecs_path :
453       DEFAULT_REAL_CODECS_PATH;
454
455   switch (version) {
456     case GST_REAL_VIDEO_DEC_VERSION_2:
457       names = dec->rv20_names ? dec->rv20_names : DEFAULT_RV20_NAMES;
458       break;
459     case GST_REAL_VIDEO_DEC_VERSION_3:
460       names = dec->rv30_names ? dec->rv30_names : DEFAULT_RV30_NAMES;
461       break;
462     case GST_REAL_VIDEO_DEC_VERSION_4:
463       names = dec->rv40_names ? dec->rv40_names : DEFAULT_RV40_NAMES;
464       break;
465     default:
466       goto unknown_version;
467   }
468
469   split_path = g_strsplit (path, ":", 0);
470   split_names = g_strsplit (names, ":", 0);
471
472   for (i = 0; split_path[i]; i++) {
473     for (j = 0; split_names[j]; j++) {
474       gchar *codec = g_strconcat (split_path[i], "/", split_names[j], NULL);
475
476       GST_DEBUG_OBJECT (dec, "trying %s", codec);
477       /* This is racy, but it doesn't matter here; would be nice if GModule
478        * gave us a GError instead of an error string, but it doesn't, so.. */
479       if (g_file_test (codec, G_FILE_TEST_EXISTS)) {
480         module = g_module_open (codec, G_MODULE_BIND_LAZY);
481         if (module == NULL) {
482           GST_ERROR_OBJECT (dec, "Could not open codec library '%s': %s",
483               codec, g_module_error ());
484         }
485       } else {
486         GST_LOG_OBJECT (dec, "%s does not exist", codec);
487       }
488       g_free (codec);
489       if (module)
490         goto codec_search_done;
491     }
492   }
493
494 codec_search_done:
495   g_strfreev (split_path);
496   g_strfreev (split_names);
497
498   if (module == NULL)
499     return FALSE;
500
501   GST_DEBUG_OBJECT (dec, "module opened, finding symbols");
502
503   /* First try opening legacy symbols, if that fails try loading new symbols */
504   if (g_module_symbol (module, "RV20toYUV420Init", &rv_init) &&
505       g_module_symbol (module, "RV20toYUV420Free", &rv_free) &&
506       g_module_symbol (module, "RV20toYUV420Transform", &rv_transform) &&
507       g_module_symbol (module, "RV20toYUV420CustomMessage", &rv_custom_msg)) {
508     GST_LOG_OBJECT (dec, "Loaded legacy symbols");
509   } else if (g_module_symbol (module, "RV40toYUV420Init", &rv_init) &&
510       g_module_symbol (module, "RV40toYUV420Free", &rv_free) &&
511       g_module_symbol (module, "RV40toYUV420Transform", &rv_transform) &&
512       g_module_symbol (module, "RV40toYUV420CustomMessage", &rv_custom_msg)) {
513     GST_LOG_OBJECT (dec, "Loaded new symbols");
514   } else {
515     goto could_not_load;
516   }
517
518   lib->Init = (guint32 (*)(gpointer, gpointer)) rv_init;
519   lib->Free = (guint32 (*)(gpointer)) rv_free;
520   lib->Transform = (guint32 (*)(gchar *, gchar *, gpointer, gpointer, gpointer))
521       rv_transform;
522   lib->Message = (guint32 (*)(gpointer, gpointer)) rv_custom_msg;
523   lib->module = module;
524
525   dec->error_count = 0;
526
527   return TRUE;
528
529 unknown_version:
530   {
531     GST_ERROR_OBJECT (dec, "Cannot handle version %i.", version);
532     return FALSE;
533   }
534 could_not_load:
535   {
536     close_library (dec, lib);
537     GST_ERROR_OBJECT (dec, "Could not load all symbols: %s", g_module_error ());
538     return FALSE;
539   }
540 }
541
542 static void
543 close_library (GstRealVideoDec * dec, GstRVDecLibrary * lib)
544 {
545   if (lib->context) {
546     GST_LOG_OBJECT (dec, "closing library");
547     if (lib->Free)
548       lib->Free (lib->context);
549   }
550   if (lib->module) {
551     GST_LOG_OBJECT (dec, "closing library module");
552     g_module_close (lib->module);
553     lib->module = NULL;
554   }
555   memset (lib, 0, sizeof (*lib));
556 }
557
558 static void
559 gst_real_video_dec_probe_modules (GstRealVideoDec * dec)
560 {
561   GstRVDecLibrary dummy = { NULL };
562
563   if ((dec->valid_rv20 =
564           open_library (dec, GST_REAL_VIDEO_DEC_VERSION_2, &dummy)))
565     close_library (dec, &dummy);
566   if ((dec->valid_rv30 =
567           open_library (dec, GST_REAL_VIDEO_DEC_VERSION_3, &dummy)))
568     close_library (dec, &dummy);
569   if ((dec->valid_rv40 =
570           open_library (dec, GST_REAL_VIDEO_DEC_VERSION_4, &dummy)))
571     close_library (dec, &dummy);
572 }
573
574 static GstStateChangeReturn
575 gst_real_video_dec_change_state (GstElement * element,
576     GstStateChange transition)
577 {
578   GstStateChangeReturn ret;
579   GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (element);
580
581   switch (transition) {
582     case GST_STATE_CHANGE_NULL_TO_READY:
583       gst_real_video_dec_probe_modules (dec);
584       dec->checked_modules = TRUE;
585       break;
586     default:
587       break;
588   }
589
590   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
591
592   switch (transition) {
593     case GST_STATE_CHANGE_PAUSED_TO_READY:
594       close_library (dec, &dec->lib);
595       break;
596     case GST_STATE_CHANGE_READY_TO_NULL:
597       dec->checked_modules = FALSE;
598       break;
599     default:
600       break;
601   }
602   return ret;
603 }
604
605 static void
606 gst_real_video_dec_init (GstRealVideoDec * dec, GstRealVideoDecClass * klass)
607 {
608   dec->snk = gst_pad_new_from_static_template (&snk_t, "sink");
609   gst_pad_set_getcaps_function (dec->snk,
610       GST_DEBUG_FUNCPTR (gst_real_video_dec_getcaps));
611   gst_pad_set_setcaps_function (dec->snk,
612       GST_DEBUG_FUNCPTR (gst_real_video_dec_setcaps));
613   gst_pad_set_chain_function (dec->snk,
614       GST_DEBUG_FUNCPTR (gst_real_video_dec_chain));
615   gst_element_add_pad (GST_ELEMENT (dec), dec->snk);
616
617   dec->src = gst_pad_new_from_static_template (&src_t, "src");
618   gst_pad_use_fixed_caps (dec->src);
619   gst_element_add_pad (GST_ELEMENT (dec), dec->src);
620
621   dec->max_errors = DEFAULT_MAX_ERRORS;
622   dec->error_count = 0;
623 }
624
625 static void
626 gst_real_video_dec_base_init (gpointer g_class)
627 {
628   GstElementClass *ec = GST_ELEMENT_CLASS (g_class);
629
630   gst_element_class_add_static_pad_template (ec, &snk_t);
631   gst_element_class_add_static_pad_template (ec, &src_t);
632   gst_element_class_set_details_simple (ec, "RealVideo decoder",
633       "Codec/Decoder/Video", "Decoder for RealVideo streams",
634       "Lutz Mueller <lutz@topfrose.de>");
635 }
636
637 static void
638 gst_real_video_dec_finalize (GObject * object)
639 {
640   GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (object);
641
642   close_library (dec, &dec->lib);
643
644   if (dec->real_codecs_path) {
645     g_free (dec->real_codecs_path);
646     dec->real_codecs_path = NULL;
647   }
648   if (dec->rv20_names) {
649     g_free (dec->rv20_names);
650     dec->rv20_names = NULL;
651   }
652   if (dec->rv30_names) {
653     g_free (dec->rv30_names);
654     dec->rv30_names = NULL;
655   }
656   if (dec->rv40_names) {
657     g_free (dec->rv40_names);
658     dec->rv40_names = NULL;
659   }
660
661   G_OBJECT_CLASS (parent_class)->finalize (object);
662 }
663
664 static void
665 gst_real_video_dec_set_property (GObject * object, guint prop_id,
666     const GValue * value, GParamSpec * pspec)
667 {
668   GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (object);
669
670   /* Changing the location of the .so supposes it's not being done
671    * in a state greater than READY !
672    */
673
674   switch (prop_id) {
675     case PROP_REAL_CODECS_PATH:
676       if (dec->real_codecs_path)
677         g_free (dec->real_codecs_path);
678       dec->real_codecs_path = g_value_dup_string (value);
679       break;
680     case PROP_RV20_NAMES:
681       if (dec->rv20_names)
682         g_free (dec->rv20_names);
683       dec->rv20_names = g_value_dup_string (value);
684       break;
685     case PROP_RV30_NAMES:
686       if (dec->rv30_names)
687         g_free (dec->rv30_names);
688       dec->rv30_names = g_value_dup_string (value);
689       break;
690     case PROP_RV40_NAMES:
691       if (dec->rv40_names)
692         g_free (dec->rv40_names);
693       dec->rv40_names = g_value_dup_string (value);
694       break;
695     case PROP_MAX_ERRORS:
696       dec->max_errors = g_value_get_int (value);
697       break;
698     default:
699       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
700       break;
701   }
702 }
703
704 static void
705 gst_real_video_dec_get_property (GObject * object, guint prop_id,
706     GValue * value, GParamSpec * pspec)
707 {
708   GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (object);
709
710   switch (prop_id) {
711     case PROP_REAL_CODECS_PATH:
712       g_value_set_string (value, dec->real_codecs_path ? dec->real_codecs_path
713           : DEFAULT_REAL_CODECS_PATH);
714       break;
715     case PROP_RV20_NAMES:
716       g_value_set_string (value, dec->rv20_names ? dec->rv20_names :
717           DEFAULT_RV20_NAMES);
718       break;
719     case PROP_RV30_NAMES:
720       g_value_set_string (value, dec->rv30_names ? dec->rv30_names :
721           DEFAULT_RV30_NAMES);
722       break;
723     case PROP_RV40_NAMES:
724       g_value_set_string (value, dec->rv40_names ? dec->rv40_names :
725           DEFAULT_RV40_NAMES);
726       break;
727     case PROP_MAX_ERRORS:
728       g_value_set_int (value, dec->max_errors);
729       break;
730     default:
731       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
732       break;
733   }
734 }
735
736 static void
737 gst_real_video_dec_class_init (GstRealVideoDecClass * klass)
738 {
739   GObjectClass *object_class = G_OBJECT_CLASS (klass);
740   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
741
742   object_class->set_property = gst_real_video_dec_set_property;
743   object_class->get_property = gst_real_video_dec_get_property;
744   object_class->finalize = gst_real_video_dec_finalize;
745
746   element_class->change_state = gst_real_video_dec_change_state;
747
748   g_object_class_install_property (object_class, PROP_REAL_CODECS_PATH,
749       g_param_spec_string ("real-codecs-path",
750           "Path where to search for RealPlayer codecs",
751           "Path where to search for RealPlayer codecs",
752           DEFAULT_REAL_CODECS_PATH,
753           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
754   g_object_class_install_property (object_class, PROP_RV20_NAMES,
755       g_param_spec_string ("rv20-names", "Names of rv20 driver",
756           "Names of rv20 driver", DEFAULT_RV20_NAMES,
757           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
758   g_object_class_install_property (object_class, PROP_RV30_NAMES,
759       g_param_spec_string ("rv30-names", "Names of rv30 driver",
760           "Names of rv30 driver", DEFAULT_RV30_NAMES,
761           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
762   g_object_class_install_property (object_class, PROP_RV40_NAMES,
763       g_param_spec_string ("rv40-names", "Names of rv40 driver",
764           "Names of rv40 driver", DEFAULT_RV40_NAMES,
765           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
766   g_object_class_install_property (object_class, PROP_MAX_ERRORS,
767       g_param_spec_int ("max-errors", "Max errors",
768           "Maximum number of consecutive errors (0 = unlimited)",
769           0, G_MAXINT, DEFAULT_MAX_ERRORS,
770           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
771
772   GST_DEBUG_CATEGORY_INIT (realvideode_debug, "realvideodec", 0,
773       "RealVideo decoder");
774 }