close #333784 unref the result of gst_pad_get_parent() by: Christophe Fergeau.
[platform/upstream/gstreamer.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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include <string.h>
25
26 /*#define DEBUG_ENABLED*/
27 #include "gstsmokedec.h"
28 #include <gst/video/video.h>
29
30 /* elementfactory information */
31 GstElementDetails gst_smokedec_details = {
32   "Smoke video decoder",
33   "Codec/Decoder/Image",
34   "Decode video from Smoke format",
35   "Wim Taymans <wim@fluendo.com>",
36 };
37
38 GST_DEBUG_CATEGORY (smokedec_debug);
39 #define GST_CAT_DEFAULT smokedec_debug
40
41 /* SmokeDec signals and args */
42 enum
43 {
44   LAST_SIGNAL
45 };
46
47 enum
48 {
49   PROP_0
50 };
51
52 static void gst_smokedec_base_init (gpointer g_class);
53 static void gst_smokedec_class_init (GstSmokeDec * klass);
54 static void gst_smokedec_init (GstSmokeDec * smokedec);
55
56 static GstFlowReturn gst_smokedec_chain (GstPad * pad, GstBuffer * buf);
57
58 static GstElementClass *parent_class = NULL;
59
60 /*static guint gst_smokedec_signals[LAST_SIGNAL] = { 0 }; */
61
62 GType
63 gst_smokedec_get_type (void)
64 {
65   static GType smokedec_type = 0;
66
67   if (!smokedec_type) {
68     static const GTypeInfo smokedec_info = {
69       sizeof (GstSmokeDecClass),
70       gst_smokedec_base_init,
71       NULL,
72       (GClassInitFunc) gst_smokedec_class_init,
73       NULL,
74       NULL,
75       sizeof (GstSmokeDec),
76       0,
77       (GInstanceInitFunc) gst_smokedec_init,
78     };
79
80     smokedec_type =
81         g_type_register_static (GST_TYPE_ELEMENT, "GstSmokeDec", &smokedec_info,
82         0);
83   }
84   return smokedec_type;
85 }
86
87 static GstStaticPadTemplate gst_smokedec_src_pad_template =
88 GST_STATIC_PAD_TEMPLATE ("src",
89     GST_PAD_SRC,
90     GST_PAD_ALWAYS,
91     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
92     );
93
94 static GstStaticPadTemplate gst_smokedec_sink_pad_template =
95 GST_STATIC_PAD_TEMPLATE ("sink",
96     GST_PAD_SINK,
97     GST_PAD_ALWAYS,
98     GST_STATIC_CAPS ("video/x-smoke, "
99         "width = (int) [ 16, 4096 ], "
100         "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0/1, MAX ]")
101     );
102
103 static void
104 gst_smokedec_base_init (gpointer g_class)
105 {
106   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
107
108   gst_element_class_add_pad_template (element_class,
109       gst_static_pad_template_get (&gst_smokedec_src_pad_template));
110   gst_element_class_add_pad_template (element_class,
111       gst_static_pad_template_get (&gst_smokedec_sink_pad_template));
112   gst_element_class_set_details (element_class, &gst_smokedec_details);
113 }
114
115 static void
116 gst_smokedec_class_init (GstSmokeDec * klass)
117 {
118   GstElementClass *gstelement_class;
119
120   gstelement_class = (GstElementClass *) klass;
121
122   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
123
124   GST_DEBUG_CATEGORY_INIT (smokedec_debug, "smokedec", 0, "Smoke decoder");
125 }
126
127 static void
128 gst_smokedec_init (GstSmokeDec * smokedec)
129 {
130   GST_DEBUG_OBJECT (smokedec, "gst_smokedec_init: initializing");
131   /* create the sink and src pads */
132
133   smokedec->sinkpad =
134       gst_pad_new_from_template (gst_static_pad_template_get
135       (&gst_smokedec_sink_pad_template), "sink");
136   gst_pad_set_chain_function (smokedec->sinkpad, gst_smokedec_chain);
137   gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->sinkpad);
138
139   smokedec->srcpad =
140       gst_pad_new_from_template (gst_static_pad_template_get
141       (&gst_smokedec_src_pad_template), "src");
142   gst_pad_use_fixed_caps (smokedec->srcpad);
143   gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->srcpad);
144
145   /* reset the initial video state */
146   smokedec->format = -1;
147   smokedec->width = -1;
148   smokedec->height = -1;
149   smokedec->fps_num = -1;
150   smokedec->fps_denom = -1;
151   smokedec->next_time = 0;
152
153   smokecodec_decode_new (&smokedec->info);
154 }
155
156 static GstFlowReturn
157 gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
158 {
159   GstSmokeDec *smokedec;
160   guint8 *data, *outdata;
161   gulong size, outsize;
162   GstBuffer *outbuf;
163   SmokeCodecFlags flags;
164   GstClockTime time;
165   guint width, height;
166   guint fps_num, fps_denom;
167   gint smokeret;
168   GstFlowReturn ret;
169
170   smokedec = GST_SMOKEDEC (gst_pad_get_parent (pad));
171
172   data = GST_BUFFER_DATA (buf);
173   size = GST_BUFFER_SIZE (buf);
174   time = GST_BUFFER_TIMESTAMP (buf);
175
176   GST_DEBUG_OBJECT (smokedec,
177       "gst_smokedec_chain: got buffer of %ld bytes in '%s'", size,
178       GST_OBJECT_NAME (smokedec));
179
180   /* have the ID packet. */
181   if (data[0] == SMOKECODEC_TYPE_ID) {
182     smokeret = smokecodec_parse_id (smokedec->info, data, size);
183     if (smokeret != SMOKECODEC_OK)
184       goto header_error;
185
186     ret = GST_FLOW_OK;
187     goto done;
188   }
189
190   /* now handle data packets */
191   GST_DEBUG_OBJECT (smokedec, "gst_smokedec_chain: reading header %08lx",
192       *(gulong *) data);
193   smokecodec_parse_header (smokedec->info, data, size, &flags, &width, &height,
194       &fps_num, &fps_denom);
195
196   if (smokedec->height != height || smokedec->width != width ||
197       smokedec->fps_num != fps_num || smokedec->fps_denom != fps_denom) {
198     GstCaps *caps;
199
200     smokedec->height = height;
201     smokedec->width = width;
202
203     caps = gst_caps_new_simple ("video/x-raw-yuv",
204         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
205         "width", G_TYPE_INT, width,
206         "height", G_TYPE_INT, height,
207         "framerate", GST_TYPE_FRACTION, fps_num, fps_denom, NULL);
208
209     gst_pad_set_caps (smokedec->srcpad, caps);
210     gst_caps_unref (caps);
211   }
212
213
214   if (smokedec->need_keyframe) {
215     if (!(flags & SMOKECODEC_KEYFRAME))
216       goto keyframe_skip;
217
218     smokedec->need_keyframe = FALSE;
219   }
220
221   outbuf = gst_buffer_new ();
222   outsize = GST_BUFFER_SIZE (outbuf) = width * height + width * height / 2;
223   outdata = g_malloc (outsize);
224   GST_BUFFER_DATA (outbuf) = outdata;
225   GST_BUFFER_MALLOCDATA (outbuf) = outdata;
226
227   GST_BUFFER_DURATION (outbuf) = GST_SECOND * fps_denom / fps_num;
228   GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf);
229   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokedec->srcpad));
230
231   if (time == GST_CLOCK_TIME_NONE) {
232     if (GST_BUFFER_OFFSET (buf) == -1) {
233       time = smokedec->next_time;
234     } else {
235       time = GST_BUFFER_OFFSET (buf) * GST_BUFFER_DURATION (outbuf);
236     }
237   }
238   GST_BUFFER_TIMESTAMP (outbuf) = time;
239   smokedec->next_time = time + GST_BUFFER_DURATION (outbuf);
240
241   smokeret = smokecodec_decode (smokedec->info, data, size, outdata);
242   if (smokeret != SMOKECODEC_OK)
243     goto decode_error;
244
245   GST_DEBUG_OBJECT (smokedec, "gst_smokedec_chain: sending buffer");
246   ret = gst_pad_push (smokedec->srcpad, outbuf);
247
248 done:
249   gst_buffer_unref (buf);
250   gst_object_unref (smokedec);
251
252   return ret;
253
254   /* ERRORS */
255 header_error:
256   {
257     GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
258         (NULL), ("Could not parse smoke header, reason: %d", smokeret));
259     ret = GST_FLOW_ERROR;
260     goto done;
261   }
262 keyframe_skip:
263   {
264     GST_DEBUG_OBJECT (smokedec, "dropping buffer while waiting for keyframe");
265     ret = GST_FLOW_OK;
266     goto done;
267   }
268 decode_error:
269   {
270     GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
271         (NULL), ("Could not decode smoke frame, reason: %d", smokeret));
272     ret = GST_FLOW_ERROR;
273     goto done;
274   }
275 }