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