d5a2fb06f5283a013635bdfd81153a9c071fd170
[platform/upstream/gstreamer.git] / gst / avi / gstaviparse.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20
21 /* #define GST_DEBUG_ENABLED */
22 #include <string.h>
23 #include <config.h>
24 #include <gst/gst.h>
25 #include <gst/bytestream/bytestream.h>
26 #include <gst/riff/riff.h>
27
28 #define GST_TYPE_AVI_PARSE \
29   (gst_avi_parse_get_type())
30 #define GST_AVI_PARSE(obj) \
31   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVI_PARSE,GstAviParse))
32 #define GST_AVI_PARSE_CLASS(klass) \
33   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVI_PARSE,GstAviParse))
34 #define GST_IS_AVI_PARSE(obj) \
35   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVI_PARSE))
36 #define GST_IS_AVI_PARSE_CLASS(obj) \
37   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVI_PARSE))
38
39 typedef struct _GstAviParse GstAviParse;
40 typedef struct _GstAviParseClass GstAviParseClass;
41
42 struct _GstAviParse {
43   GstElement     element;
44
45   /* pads */
46   GstPad        *sinkpad, 
47                 *srcpad;
48
49   GstRiffParse  *rp;
50 };
51
52 struct _GstAviParseClass {
53   GstElementClass parent_class;
54 };
55
56 /* elementfactory information */
57 static GstElementDetails gst_avi_parse_details = {
58   "Avi parseer",
59   "Codec/Parseer",
60   "LGPL",
61   "Demultiplex an avi file into audio and video",
62   VERSION,
63   "Wim Taymans <wim.taymans@tvd.be>",
64   "(C) 2003",
65 };
66
67 static GstCaps* avi_type_find (GstBuffer *buf, gpointer private);
68
69 /* typefactory for 'avi' */
70 static GstTypeDefinition avidefinition = {
71   "aviparse_video/avi",
72   "video/avi",
73   ".avi",
74   avi_type_find,
75 };
76
77 /* AviParse signals and args */
78 enum {
79   /* FILL ME */
80   LAST_SIGNAL
81 };
82
83 enum {
84   ARG_0,
85   ARG_BITRATE,
86   /* FILL ME */
87 };
88
89 GST_PAD_TEMPLATE_FACTORY (sink_templ,
90   "sink",
91   GST_PAD_SINK,
92   GST_PAD_ALWAYS,
93   GST_CAPS_NEW (
94     "aviparse_sink",
95      "video/avi",
96       "format",    GST_PROPS_STRING ("AVI")
97   )
98 )
99
100 GST_PAD_TEMPLATE_FACTORY (src_templ,
101   "src",
102   GST_PAD_SRC,
103   GST_PAD_ALWAYS,
104   GST_CAPS_NEW (
105     "aviparse_sink",
106      "video/avi",
107       "format",    GST_PROPS_STRING ("AVI")
108   )
109 )
110
111 static void             gst_avi_parse_class_init                (GstAviParseClass *klass);
112 static void             gst_avi_parse_init                      (GstAviParse *avi_parse);
113
114 static void             gst_avi_parse_loop                      (GstElement *element);
115
116 static GstElementStateReturn
117                         gst_avi_parse_change_state              (GstElement *element);
118
119 static void             gst_avi_parse_get_property              (GObject *object, guint prop_id,        
120                                                                  GValue *value, GParamSpec *pspec);
121
122
123 static GstElementClass *parent_class = NULL;
124 /*static guint gst_avi_parse_signals[LAST_SIGNAL] = { 0 }; */
125
126 GType
127 gst_avi_parse_get_type(void) 
128 {
129   static GType avi_parse_type = 0;
130
131   if (!avi_parse_type) {
132     static const GTypeInfo avi_parse_info = {
133       sizeof(GstAviParseClass),      
134       NULL,
135       NULL,
136       (GClassInitFunc)gst_avi_parse_class_init,
137       NULL,
138       NULL,
139       sizeof(GstAviParse),
140       0,
141       (GInstanceInitFunc)gst_avi_parse_init,
142     };
143     avi_parse_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviParse", &avi_parse_info, 0);
144   }
145   return avi_parse_type;
146 }
147
148 static void
149 gst_avi_parse_class_init (GstAviParseClass *klass) 
150 {
151   GObjectClass *gobject_class;
152   GstElementClass *gstelement_class;
153
154   gobject_class = (GObjectClass*)klass;
155   gstelement_class = (GstElementClass*)klass;
156
157   g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_BITRATE,
158     g_param_spec_long ("bitrate","bitrate","bitrate",
159                        G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
160
161   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
162   
163   gobject_class->get_property = gst_avi_parse_get_property;
164   
165   gstelement_class->change_state = gst_avi_parse_change_state;
166 }
167
168 static void 
169 gst_avi_parse_init (GstAviParse *avi_parse) 
170 {
171   GST_FLAG_SET (avi_parse, GST_ELEMENT_EVENT_AWARE);
172                                 
173   avi_parse->sinkpad = gst_pad_new_from_template (
174                   GST_PAD_TEMPLATE_GET (sink_templ), "sink");
175   gst_element_add_pad (GST_ELEMENT (avi_parse), avi_parse->sinkpad);
176
177   avi_parse->srcpad = gst_pad_new_from_template (
178                   GST_PAD_TEMPLATE_GET (src_templ), "src");
179   gst_element_add_pad (GST_ELEMENT (avi_parse), avi_parse->srcpad);
180
181   gst_element_set_loop_function (GST_ELEMENT (avi_parse), gst_avi_parse_loop);
182 }
183
184 static GstCaps*
185 avi_type_find (GstBuffer *buf,
186               gpointer private)
187 {
188   gchar *data = GST_BUFFER_DATA (buf);
189   GstCaps *new;
190
191   GST_DEBUG (0,"avi_parse: typefind");
192
193   if (GUINT32_FROM_LE (((guint32 *)data)[0]) != GST_RIFF_TAG_RIFF)
194     return NULL;
195   if (GUINT32_FROM_LE (((guint32 *)data)[2]) != GST_RIFF_RIFF_AVI)
196     return NULL;
197
198   new = GST_CAPS_NEW ("avi_type_find",
199                       "video/avi", 
200                         "format", GST_PROPS_STRING ("AVI"));
201   return new;
202 }
203
204 static void
205 gst_avi_parse_loop (GstElement *element)
206 {
207   GstAviParse *avi_parse;
208   GstRiffParse *rp;
209   GstRiffReturn res;
210   gst_riff_chunk chunk;
211   guint32 data_size;
212   guint64 pos;
213   
214   g_return_if_fail (element != NULL);
215   g_return_if_fail (GST_IS_AVI_PARSE (element));
216
217   avi_parse = GST_AVI_PARSE (element);
218
219   rp = avi_parse->rp;
220
221   pos = gst_bytestream_tell (rp->bs);
222
223   res = gst_riff_parse_next_chunk (rp, &chunk);
224   if (res == GST_RIFF_EOS) { 
225     gst_element_set_eos (element);
226     return;
227   }
228
229   switch (chunk.id) {
230     case GST_RIFF_TAG_RIFF:
231     case GST_RIFF_TAG_LIST:
232       g_print ("%08llx: %4.4s %08x %4.4s\n", pos, (gchar *)&chunk.id, chunk.size, (gchar *)&chunk.type);
233       data_size = 0;
234       break;
235     default:
236       g_print ("%08llx: %4.4s %08x\n", pos, (gchar *)&chunk.id, chunk.size);
237       data_size = chunk.size;
238       break;
239   }
240
241   if (GST_PAD_IS_USABLE (avi_parse->srcpad) && data_size) {
242     GstBuffer *buf;
243
244     gst_riff_parse_peek (rp, &buf, data_size);
245     gst_pad_push (avi_parse->srcpad, buf);
246   }
247   data_size = (data_size + 1) & ~1;
248
249   gst_riff_parse_flush (rp, data_size);
250 }
251
252 static GstElementStateReturn
253 gst_avi_parse_change_state (GstElement *element)
254 {
255   GstAviParse *avi_parse = GST_AVI_PARSE (element);
256
257   switch (GST_STATE_TRANSITION (element)) {
258     case GST_STATE_NULL_TO_READY:
259       break;
260     case GST_STATE_READY_TO_PAUSED:
261       avi_parse->rp = gst_riff_parse_new (avi_parse->sinkpad);
262       break;
263     case GST_STATE_PAUSED_TO_PLAYING:
264       break;
265     case GST_STATE_PLAYING_TO_PAUSED:
266       break;
267     case GST_STATE_PAUSED_TO_READY:
268       gst_riff_parse_free (avi_parse->rp);
269       break;
270     case GST_STATE_READY_TO_NULL:
271       break;
272     default:
273       break;
274   }
275
276   parent_class->change_state (element);
277
278   return GST_STATE_SUCCESS;
279 }
280
281 static void
282 gst_avi_parse_get_property (GObject *object, guint prop_id, GValue *value,
283                             GParamSpec *pspec)
284 {
285   GstAviParse *src;
286
287   g_return_if_fail (GST_IS_AVI_PARSE (object));
288
289   src = GST_AVI_PARSE (object);
290
291   switch (prop_id) {
292     case ARG_BITRATE:
293       break;
294     default:
295       break;
296   }
297 }
298
299 static gboolean
300 plugin_init (GModule *module, GstPlugin *plugin)
301 {
302   GstElementFactory *factory;
303   GstTypeFactory *type;
304
305   /* this filter needs the riff parser */
306   if (!gst_library_load ("gstbytestream"))
307     return FALSE;
308
309   /* create an elementfactory for the avi_parse element */
310   factory = gst_element_factory_new ("aviparse", GST_TYPE_AVI_PARSE,
311                                      &gst_avi_parse_details);
312   g_return_val_if_fail (factory != NULL, FALSE);
313   gst_element_factory_set_rank (factory, GST_ELEMENT_RANK_PRIMARY);
314
315   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_templ));
316   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_templ));
317
318   type = gst_type_factory_new (&avidefinition);
319   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
320
321   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
322
323   return TRUE;
324 }
325
326 GstPluginDesc plugin_desc = {
327   GST_VERSION_MAJOR,
328   GST_VERSION_MINOR,
329   "aviparse",
330   plugin_init
331 };
332