compatibility fix for new GST_DEBUG stuff.
[platform/upstream/gstreamer.git] / gst / cdxaparse / gstcdxaparse.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *               <2002> Wim Taymans <wim.taymans@chello.be>
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
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <string.h>
26
27 #include "gstcdxaparse.h"
28
29 #define MAKE_FOUR_CC(a,b,c,d) ( ((guint32)a)     | (((guint32)b)<< 8) | \
30                                 ((guint32)c)<<16 | (((guint32)d)<<24) )
31
32
33 /* RIFF types */
34 #define GST_RIFF_TAG_RIFF  MAKE_FOUR_CC('R','I','F','F')
35 #define GST_RIFF_RIFF_CDXA MAKE_FOUR_CC('C','D','X','A')
36
37
38 #define GST_RIFF_TAG_fmt  MAKE_FOUR_CC('f','m','t',' ')
39 #define GST_RIFF_TAG_data MAKE_FOUR_CC('d','a','t','a')
40
41
42 /* elementfactory information */
43 static GstElementDetails gst_cdxa_parse_details = {
44   ".dat parser",
45   "Codec/Parser",
46   "LGPL",
47   "Parse a .dat file (VCD) into raw mpeg1",
48   VERSION,
49   "Wim Taymans <wim.taymans@tvd.be>",
50   "(C) 2002",
51 };
52
53 static GstCaps* cdxa_type_find (GstBuffer *buf, gpointer private);
54
55 /* typefactory for 'cdxa' */
56 static GstTypeDefinition cdxadefinition = {
57   "cdxaparse_video/avi",
58   "video/avi",
59   ".dat",
60   cdxa_type_find,
61 };
62
63 /* CDXAParse signals and args */
64 enum {
65   /* FILL ME */
66   LAST_SIGNAL
67 };
68
69 enum {
70   ARG_0,
71   /* FILL ME */
72 };
73
74 GST_PAD_TEMPLATE_FACTORY (sink_templ,
75   "sink",
76   GST_PAD_SINK,
77   GST_PAD_ALWAYS,
78   GST_CAPS_NEW (
79     "cdxaparse_sink",
80      "video/avi",
81       "format", GST_PROPS_STRING ("CDXA")
82   )
83 )
84
85 GST_PAD_TEMPLATE_FACTORY (src_templ,
86   "src",
87   GST_PAD_SRC,
88   GST_PAD_ALWAYS,
89   GST_CAPS_NEW (
90     "cdxaparse_src",
91     "video/mpeg",
92       "mpegversion",   GST_PROPS_INT (1),
93       "systemstream",  GST_PROPS_BOOLEAN (TRUE)
94   )
95 )
96
97 static void     gst_cdxa_parse_class_init       (GstCDXAParseClass *klass);
98 static void     gst_cdxa_parse_init             (GstCDXAParse *cdxa_parse);
99
100 static void     gst_cdxa_parse_loop             (GstElement *element);
101
102 static GstElementStateReturn
103                 gst_cdxa_parse_change_state     (GstElement *element);
104
105
106 static GstElementClass *parent_class = NULL;
107 /*static guint gst_cdxa_parse_signals[LAST_SIGNAL] = { 0 }; */
108
109 GType
110 gst_cdxa_parse_get_type(void) 
111 {
112   static GType cdxa_parse_type = 0;
113
114   if (!cdxa_parse_type) {
115     static const GTypeInfo cdxa_parse_info = {
116       sizeof(GstCDXAParseClass),      
117       NULL,
118       NULL,
119       (GClassInitFunc)gst_cdxa_parse_class_init,
120       NULL,
121       NULL,
122       sizeof(GstCDXAParse),
123       0,
124       (GInstanceInitFunc)gst_cdxa_parse_init,
125     };
126     cdxa_parse_type = g_type_register_static(GST_TYPE_ELEMENT, "GstCDXAParse", &cdxa_parse_info, 0);
127   }
128   return cdxa_parse_type;
129 }
130
131 static void
132 gst_cdxa_parse_class_init (GstCDXAParseClass *klass) 
133 {
134   GObjectClass *gobject_class;
135   GstElementClass *gstelement_class;
136
137   gobject_class = (GObjectClass*)klass;
138   gstelement_class = (GstElementClass*)klass;
139
140   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
141   
142   gstelement_class->change_state = gst_cdxa_parse_change_state;
143 }
144
145 static void 
146 gst_cdxa_parse_init (GstCDXAParse *cdxa_parse) 
147 {
148   GST_FLAG_SET (cdxa_parse, GST_ELEMENT_EVENT_AWARE);
149                                 
150   cdxa_parse->sinkpad = gst_pad_new_from_template (
151                   GST_PAD_TEMPLATE_GET (sink_templ), "sink");
152   gst_element_add_pad (GST_ELEMENT (cdxa_parse), cdxa_parse->sinkpad);
153
154   cdxa_parse->srcpad = gst_pad_new_from_template (
155                   GST_PAD_TEMPLATE_GET (src_templ), "src");
156   gst_element_add_pad (GST_ELEMENT (cdxa_parse), cdxa_parse->srcpad);
157
158   gst_element_set_loop_function (GST_ELEMENT (cdxa_parse), gst_cdxa_parse_loop);
159
160 }
161
162 static GstCaps*
163 cdxa_type_find (GstBuffer *buf,
164               gpointer private)
165 {
166   gchar *data = GST_BUFFER_DATA (buf);
167   GstCaps *new;
168
169   GST_DEBUG ("cdxa_parse: typefind");
170
171   if (GUINT32_FROM_LE (((guint32 *)data)[0]) != GST_RIFF_TAG_RIFF)
172     return NULL;
173   if (GUINT32_FROM_LE (((guint32 *)data)[2]) != GST_RIFF_RIFF_CDXA)
174     return NULL;
175
176   new = GST_CAPS_NEW ("cdxa_type_find",
177                       "video/avi", 
178                         "RIFF", GST_PROPS_STRING ("CDXA"));
179
180   return new;
181 }
182
183 static gboolean
184 gst_cdxa_parse_handle_event (GstCDXAParse *cdxa_parse)
185 {
186   guint32 remaining;
187   GstEvent *event;
188   GstEventType type;
189   
190   gst_bytestream_get_status (cdxa_parse->bs, &remaining, &event);
191
192   type = event? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
193
194   switch (type) {
195     case GST_EVENT_EOS:
196       gst_pad_event_default (cdxa_parse->sinkpad, event);
197       break;
198     case GST_EVENT_SEEK:
199       g_warning ("seek event\n");
200       break;
201     case GST_EVENT_FLUSH:
202       g_warning ("flush event\n");
203       break;
204     case GST_EVENT_DISCONTINUOUS:
205       g_warning ("discont event\n");
206       break;
207     default:
208       g_warning ("unhandled event %d\n", type);
209       break;
210   }
211
212   return TRUE;
213 }
214
215 /*
216
217 CDXA starts with the following header:
218  
219 ! RIFF:4 ! size:4 ! "CDXA" ! "fmt " ! size:4 ! (size+1)&~1 bytes of crap ! 
220 ! "data" ! data_size:4 ! (data_size/2352) sectors...
221
222 */
223
224 typedef struct 
225 {
226   gchar   RIFF_tag[4];
227   guint32 riff_size;
228   gchar   CDXA_tag[4];
229   gchar   fmt_tag[4];
230   guint32 fmt_size;
231 } CDXAParseHeader;
232    
233 /*
234 A sectors is 2352 bytes long and is composed of:
235
236 !  sync    !  header ! subheader ! data ...   ! edc     !
237 ! 12 bytes ! 4 bytes ! 8 bytes   ! 2324 bytes ! 4 bytes !
238 !-------------------------------------------------------!
239
240 We parse the data out of it and send it to the srcpad.
241 */
242
243 static void
244 gst_cdxa_parse_loop (GstElement *element)
245 {
246   GstCDXAParse *cdxa_parse;
247   CDXAParseHeader *header;
248   guint8 *headerdata;
249
250   g_return_if_fail (element != NULL);
251   g_return_if_fail (GST_IS_CDXA_PARSE (element));
252
253   cdxa_parse = GST_CDXA_PARSE (element);
254
255   if (cdxa_parse->state == CDXA_PARSE_HEADER) {
256     guint32 fmt_size;
257     guint8 *buf;
258     guint32 got_bytes;
259
260     got_bytes = gst_bytestream_peek_bytes (cdxa_parse->bs, &headerdata, 20);
261     header = (CDXAParseHeader *) headerdata;
262     if (got_bytes < 20)
263       return;
264
265     cdxa_parse->riff_size = GUINT32_FROM_LE (header->riff_size);
266     fmt_size = (GUINT32_FROM_LE (header->fmt_size) + 1)&~1;
267
268     /* flush the header + fmt_size bytes + 4 bytes "data" */
269     if (!gst_bytestream_flush (cdxa_parse->bs, 20 + fmt_size + 4))
270       return;
271     
272     /* get the data size */
273     got_bytes = gst_bytestream_peek_bytes (cdxa_parse->bs, (guint8**)&buf, 4);
274     if (got_bytes < 4)
275       return;
276     cdxa_parse->data_size = GUINT32_FROM_LE (*((guint32 *)buf));
277
278     /* flush the data size */
279     if (!gst_bytestream_flush (cdxa_parse->bs, 4))
280       return;
281
282     if (cdxa_parse->data_size % CDXA_SECTOR_SIZE)
283       g_warning ("cdxa_parse: size not multiple of %d bytes", CDXA_SECTOR_SIZE);
284
285     cdxa_parse->sectors = cdxa_parse->data_size / CDXA_SECTOR_SIZE;
286     
287     cdxa_parse->state = CDXA_PARSE_DATA;
288   }
289   else {
290     GstBuffer *buf;
291     GstBuffer *outbuf;
292     guint32 got_bytes;
293
294     got_bytes = gst_bytestream_read (cdxa_parse->bs, &buf, CDXA_SECTOR_SIZE);
295     if (got_bytes < CDXA_SECTOR_SIZE) {
296       gst_cdxa_parse_handle_event (cdxa_parse);
297       return;
298     }
299
300     outbuf = gst_buffer_create_sub (buf, 24, CDXA_DATA_SIZE);
301     gst_buffer_unref (buf);
302
303     gst_pad_push (cdxa_parse->srcpad, outbuf);
304   }
305 }
306
307 static GstElementStateReturn
308 gst_cdxa_parse_change_state (GstElement *element)
309 {
310   GstCDXAParse *cdxa_parse = GST_CDXA_PARSE (element);
311
312   switch (GST_STATE_TRANSITION (element)) {
313     case GST_STATE_NULL_TO_READY:
314       break;
315     case GST_STATE_READY_TO_PAUSED:
316       cdxa_parse->state = CDXA_PARSE_HEADER;
317       cdxa_parse->bs = gst_bytestream_new (cdxa_parse->sinkpad);
318       break;
319     case GST_STATE_PAUSED_TO_PLAYING:
320       break;
321     case GST_STATE_PLAYING_TO_PAUSED:
322       break;
323     case GST_STATE_PAUSED_TO_READY:
324       gst_bytestream_destroy (cdxa_parse->bs);
325       break;
326     case GST_STATE_READY_TO_NULL:
327       break;
328     default:
329       break;
330   }
331
332   parent_class->change_state (element);
333
334   return GST_STATE_SUCCESS;
335 }
336
337 static gboolean
338 plugin_init (GModule *module, GstPlugin *plugin)
339 {
340   GstElementFactory *factory;
341   GstTypeFactory *type;
342
343   /* this filter needs the riff parser */
344   if (!gst_library_load ("gstbytestream"))
345     return FALSE;
346
347   /* create an elementfactory for the cdxa_parse element */
348   factory = gst_element_factory_new ("cdxaparse", GST_TYPE_CDXA_PARSE,
349                                     &gst_cdxa_parse_details);
350   g_return_val_if_fail (factory != NULL, FALSE);
351
352   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_templ));
353   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_templ));
354
355   type = gst_type_factory_new (&cdxadefinition);
356   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
357
358   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
359
360   return TRUE;
361 }
362
363 GstPluginDesc plugin_desc = {
364   GST_VERSION_MAJOR,
365   GST_VERSION_MINOR,
366   "cdxaparse",
367   plugin_init
368 };
369