tizen 2.0 init
[framework/multimedia/gst-plugins-good0.10.git] / ext / jpeg / gstsmokedec.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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  * SECTION:element-smokedec
22  *
23  * Decodes images in smoke format.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29 #include <string.h>
30
31 /*#define DEBUG_ENABLED*/
32 #include "gstsmokedec.h"
33 #include <gst/video/video.h>
34
35 GST_DEBUG_CATEGORY_STATIC (smokedec_debug);
36 #define GST_CAT_DEFAULT smokedec_debug
37
38 /* SmokeDec signals and args */
39 enum
40 {
41   LAST_SIGNAL
42 };
43
44 enum
45 {
46   PROP_0
47 };
48
49 static void gst_smokedec_base_init (gpointer g_class);
50 static void gst_smokedec_class_init (GstSmokeDec * klass);
51 static void gst_smokedec_init (GstSmokeDec * smokedec);
52 static void gst_smokedec_finalize (GObject * object);
53
54 static GstStateChangeReturn
55 gst_smokedec_change_state (GstElement * element, GstStateChange transition);
56
57 static GstFlowReturn gst_smokedec_chain (GstPad * pad, GstBuffer * buf);
58
59 static GstElementClass *parent_class = NULL;
60
61 /*static guint gst_smokedec_signals[LAST_SIGNAL] = { 0 }; */
62
63 GType
64 gst_smokedec_get_type (void)
65 {
66   static GType smokedec_type = 0;
67
68   if (!smokedec_type) {
69     static const GTypeInfo smokedec_info = {
70       sizeof (GstSmokeDecClass),
71       gst_smokedec_base_init,
72       NULL,
73       (GClassInitFunc) gst_smokedec_class_init,
74       NULL,
75       NULL,
76       sizeof (GstSmokeDec),
77       0,
78       (GInstanceInitFunc) gst_smokedec_init,
79     };
80
81     smokedec_type =
82         g_type_register_static (GST_TYPE_ELEMENT, "GstSmokeDec", &smokedec_info,
83         0);
84   }
85   return smokedec_type;
86 }
87
88 static GstStaticPadTemplate gst_smokedec_src_pad_template =
89 GST_STATIC_PAD_TEMPLATE ("src",
90     GST_PAD_SRC,
91     GST_PAD_ALWAYS,
92     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
93     );
94
95 static GstStaticPadTemplate gst_smokedec_sink_pad_template =
96 GST_STATIC_PAD_TEMPLATE ("sink",
97     GST_PAD_SINK,
98     GST_PAD_ALWAYS,
99     GST_STATIC_CAPS ("video/x-smoke, "
100         "width = (int) [ 16, 4096 ], "
101         "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0/1, MAX ]")
102     );
103
104 static void
105 gst_smokedec_base_init (gpointer g_class)
106 {
107   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
108
109   gst_element_class_add_static_pad_template (element_class,
110       &gst_smokedec_src_pad_template);
111   gst_element_class_add_static_pad_template (element_class,
112       &gst_smokedec_sink_pad_template);
113   gst_element_class_set_details_simple (element_class, "Smoke video decoder",
114       "Codec/Decoder/Video",
115       "Decode video from Smoke format", "Wim Taymans <wim@fluendo.com>");
116 }
117
118 static void
119 gst_smokedec_class_init (GstSmokeDec * klass)
120 {
121   GObjectClass *gobject_class;
122   GstElementClass *gstelement_class;
123
124   gobject_class = (GObjectClass *) klass;
125   gstelement_class = (GstElementClass *) klass;
126
127   parent_class = g_type_class_peek_parent (klass);
128
129   gobject_class->finalize = gst_smokedec_finalize;
130
131   gstelement_class->change_state =
132       GST_DEBUG_FUNCPTR (gst_smokedec_change_state);
133
134   GST_DEBUG_CATEGORY_INIT (smokedec_debug, "smokedec", 0, "Smoke decoder");
135 }
136
137 static void
138 gst_smokedec_init (GstSmokeDec * smokedec)
139 {
140   GST_DEBUG_OBJECT (smokedec, "gst_smokedec_init: initializing");
141   /* create the sink and src pads */
142
143   smokedec->sinkpad =
144       gst_pad_new_from_static_template (&gst_smokedec_sink_pad_template,
145       "sink");
146   gst_pad_set_chain_function (smokedec->sinkpad, gst_smokedec_chain);
147   gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->sinkpad);
148
149   smokedec->srcpad =
150       gst_pad_new_from_static_template (&gst_smokedec_src_pad_template, "src");
151   gst_pad_use_fixed_caps (smokedec->srcpad);
152   gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->srcpad);
153
154   smokecodec_decode_new (&smokedec->info);
155 }
156
157 static void
158 gst_smokedec_finalize (GObject * object)
159 {
160   GstSmokeDec *dec = GST_SMOKEDEC (object);
161
162   smokecodec_info_free (dec->info);
163
164   G_OBJECT_CLASS (parent_class)->finalize (object);
165 }
166
167 static GstFlowReturn
168 gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
169 {
170   GstSmokeDec *smokedec;
171   guint8 *data, *outdata;
172   gulong size, outsize;
173   GstBuffer *outbuf;
174   SmokeCodecFlags flags;
175   GstClockTime time;
176   guint width, height;
177   guint fps_num, fps_denom;
178   gint smokeret;
179   GstFlowReturn ret;
180
181   smokedec = GST_SMOKEDEC (gst_pad_get_parent (pad));
182
183   data = GST_BUFFER_DATA (buf);
184   size = GST_BUFFER_SIZE (buf);
185   time = GST_BUFFER_TIMESTAMP (buf);
186
187   if (size < 1)
188     goto too_small;
189
190   GST_LOG_OBJECT (smokedec, "got buffer of %lu bytes", size);
191
192   /* have the ID packet. */
193   if (data[0] == SMOKECODEC_TYPE_ID) {
194     smokeret = smokecodec_parse_id (smokedec->info, data, size);
195     if (smokeret != SMOKECODEC_OK)
196       goto header_error;
197
198     ret = GST_FLOW_OK;
199     goto done;
200   }
201
202   /* now handle data packets */
203   GST_DEBUG_OBJECT (smokedec, "reading header %08lx", *(gulong *) data);
204   smokecodec_parse_header (smokedec->info, data, size, &flags, &width, &height,
205       &fps_num, &fps_denom);
206
207   if (smokedec->height != height || smokedec->width != width ||
208       smokedec->fps_num != fps_num || smokedec->fps_denom != fps_denom) {
209     GstCaps *caps;
210
211     GST_DEBUG_OBJECT (smokedec, "parameter change: %dx%d @ %d/%dfps",
212         width, height, fps_num, fps_denom);
213
214     smokedec->height = height;
215     smokedec->width = width;
216
217     caps = gst_caps_new_simple ("video/x-raw-yuv",
218         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
219         "width", G_TYPE_INT, width,
220         "height", G_TYPE_INT, height,
221         "framerate", GST_TYPE_FRACTION, fps_num, fps_denom, NULL);
222
223     gst_pad_set_caps (smokedec->srcpad, caps);
224     gst_caps_unref (caps);
225   }
226
227   if (smokedec->need_keyframe) {
228     if (!(flags & SMOKECODEC_KEYFRAME))
229       goto keyframe_skip;
230
231     smokedec->need_keyframe = FALSE;
232   }
233
234   outsize = width * height + width * height / 2;
235   outbuf = gst_buffer_new_and_alloc (outsize);
236   outdata = GST_BUFFER_DATA (outbuf);
237
238   GST_BUFFER_DURATION (outbuf) =
239       gst_util_uint64_scale_int (GST_SECOND, fps_denom, fps_num);
240   GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf);
241   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokedec->srcpad));
242
243   if (time == GST_CLOCK_TIME_NONE) {
244     if (GST_BUFFER_OFFSET (buf) == -1) {
245       time = smokedec->next_time;
246     } else {
247       time = GST_BUFFER_OFFSET (buf) * GST_BUFFER_DURATION (outbuf);
248     }
249   }
250   GST_BUFFER_TIMESTAMP (outbuf) = time;
251   if (time != -1)
252     smokedec->next_time = time + GST_BUFFER_DURATION (outbuf);
253   else
254     smokedec->next_time = -1;
255
256   smokeret = smokecodec_decode (smokedec->info, data, size, outdata);
257   if (smokeret != SMOKECODEC_OK)
258     goto decode_error;
259
260   GST_DEBUG_OBJECT (smokedec, "gst_smokedec_chain: sending buffer");
261   ret = gst_pad_push (smokedec->srcpad, outbuf);
262
263 done:
264   gst_buffer_unref (buf);
265   gst_object_unref (smokedec);
266
267   return ret;
268
269   /* ERRORS */
270 too_small:
271   {
272     GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
273         (NULL), ("Input buffer too small"));
274     ret = GST_FLOW_ERROR;
275     goto done;
276   }
277 header_error:
278   {
279     GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
280         (NULL), ("Could not parse smoke header, reason: %d", smokeret));
281     ret = GST_FLOW_ERROR;
282     goto done;
283   }
284 keyframe_skip:
285   {
286     GST_DEBUG_OBJECT (smokedec, "dropping buffer while waiting for keyframe");
287     ret = GST_FLOW_OK;
288     goto done;
289   }
290 decode_error:
291   {
292     GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
293         (NULL), ("Could not decode smoke frame, reason: %d", smokeret));
294     ret = GST_FLOW_ERROR;
295     goto done;
296   }
297 }
298
299 static GstStateChangeReturn
300 gst_smokedec_change_state (GstElement * element, GstStateChange transition)
301 {
302   GstStateChangeReturn ret;
303   GstSmokeDec *dec;
304
305   dec = GST_SMOKEDEC (element);
306
307   switch (transition) {
308     case GST_STATE_CHANGE_READY_TO_PAUSED:
309       /* reset the initial video state */
310       dec->format = -1;
311       dec->width = -1;
312       dec->height = -1;
313       dec->fps_num = -1;
314       dec->fps_denom = -1;
315       dec->next_time = 0;
316     default:
317       break;
318   }
319
320   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
321   if (ret != GST_STATE_CHANGE_SUCCESS)
322     return ret;
323
324   switch (transition) {
325     case GST_STATE_CHANGE_PAUSED_TO_READY:
326       break;
327     default:
328       break;
329   }
330
331   return ret;
332 }