2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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.
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.
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.
21 * SECTION:element-smokedec
23 * Decodes images in smoke format.
31 /*#define DEBUG_ENABLED*/
32 #include "gstsmokedec.h"
33 #include <gst/video/video.h>
35 GST_DEBUG_CATEGORY_STATIC (smokedec_debug);
36 #define GST_CAT_DEFAULT smokedec_debug
38 /* SmokeDec signals and args */
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);
54 static GstStateChangeReturn
55 gst_smokedec_change_state (GstElement * element, GstStateChange transition);
57 static GstFlowReturn gst_smokedec_chain (GstPad * pad, GstBuffer * buf);
59 static GstElementClass *parent_class = NULL;
61 /*static guint gst_smokedec_signals[LAST_SIGNAL] = { 0 }; */
64 gst_smokedec_get_type (void)
66 static GType smokedec_type = 0;
69 static const GTypeInfo smokedec_info = {
70 sizeof (GstSmokeDecClass),
71 gst_smokedec_base_init,
73 (GClassInitFunc) gst_smokedec_class_init,
78 (GInstanceInitFunc) gst_smokedec_init,
82 g_type_register_static (GST_TYPE_ELEMENT, "GstSmokeDec", &smokedec_info,
88 static GstStaticPadTemplate gst_smokedec_src_pad_template =
89 GST_STATIC_PAD_TEMPLATE ("src",
92 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
95 static GstStaticPadTemplate gst_smokedec_sink_pad_template =
96 GST_STATIC_PAD_TEMPLATE ("sink",
99 GST_STATIC_CAPS ("video/x-smoke, "
100 "width = (int) [ 16, 4096 ], "
101 "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0/1, MAX ]")
105 gst_smokedec_base_init (gpointer g_class)
107 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
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>");
119 gst_smokedec_class_init (GstSmokeDec * klass)
121 GObjectClass *gobject_class;
122 GstElementClass *gstelement_class;
124 gobject_class = (GObjectClass *) klass;
125 gstelement_class = (GstElementClass *) klass;
127 parent_class = g_type_class_peek_parent (klass);
129 gobject_class->finalize = gst_smokedec_finalize;
131 gstelement_class->change_state =
132 GST_DEBUG_FUNCPTR (gst_smokedec_change_state);
134 GST_DEBUG_CATEGORY_INIT (smokedec_debug, "smokedec", 0, "Smoke decoder");
138 gst_smokedec_init (GstSmokeDec * smokedec)
140 GST_DEBUG_OBJECT (smokedec, "gst_smokedec_init: initializing");
141 /* create the sink and src pads */
144 gst_pad_new_from_static_template (&gst_smokedec_sink_pad_template,
146 gst_pad_set_chain_function (smokedec->sinkpad, gst_smokedec_chain);
147 gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->sinkpad);
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);
154 smokecodec_decode_new (&smokedec->info);
158 gst_smokedec_finalize (GObject * object)
160 GstSmokeDec *dec = GST_SMOKEDEC (object);
162 smokecodec_info_free (dec->info);
164 G_OBJECT_CLASS (parent_class)->finalize (object);
168 gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
170 GstSmokeDec *smokedec;
171 guint8 *data, *outdata;
172 gulong size, outsize;
174 SmokeCodecFlags flags;
177 guint fps_num, fps_denom;
181 smokedec = GST_SMOKEDEC (gst_pad_get_parent (pad));
183 data = GST_BUFFER_DATA (buf);
184 size = GST_BUFFER_SIZE (buf);
185 time = GST_BUFFER_TIMESTAMP (buf);
190 GST_LOG_OBJECT (smokedec, "got buffer of %lu bytes", size);
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)
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);
207 if (smokedec->height != height || smokedec->width != width ||
208 smokedec->fps_num != fps_num || smokedec->fps_denom != fps_denom) {
211 GST_DEBUG_OBJECT (smokedec, "parameter change: %dx%d @ %d/%dfps",
212 width, height, fps_num, fps_denom);
214 smokedec->height = height;
215 smokedec->width = width;
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);
223 gst_pad_set_caps (smokedec->srcpad, caps);
224 gst_caps_unref (caps);
227 if (smokedec->need_keyframe) {
228 if (!(flags & SMOKECODEC_KEYFRAME))
231 smokedec->need_keyframe = FALSE;
234 outsize = width * height + width * height / 2;
235 outbuf = gst_buffer_new_and_alloc (outsize);
236 outdata = GST_BUFFER_DATA (outbuf);
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));
243 if (time == GST_CLOCK_TIME_NONE) {
244 if (GST_BUFFER_OFFSET (buf) == -1) {
245 time = smokedec->next_time;
247 time = GST_BUFFER_OFFSET (buf) * GST_BUFFER_DURATION (outbuf);
250 GST_BUFFER_TIMESTAMP (outbuf) = time;
252 smokedec->next_time = time + GST_BUFFER_DURATION (outbuf);
254 smokedec->next_time = -1;
256 smokeret = smokecodec_decode (smokedec->info, data, size, outdata);
257 if (smokeret != SMOKECODEC_OK)
260 GST_DEBUG_OBJECT (smokedec, "gst_smokedec_chain: sending buffer");
261 ret = gst_pad_push (smokedec->srcpad, outbuf);
264 gst_buffer_unref (buf);
265 gst_object_unref (smokedec);
272 GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
273 (NULL), ("Input buffer too small"));
274 ret = GST_FLOW_ERROR;
279 GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
280 (NULL), ("Could not parse smoke header, reason: %d", smokeret));
281 ret = GST_FLOW_ERROR;
286 GST_DEBUG_OBJECT (smokedec, "dropping buffer while waiting for keyframe");
292 GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
293 (NULL), ("Could not decode smoke frame, reason: %d", smokeret));
294 ret = GST_FLOW_ERROR;
299 static GstStateChangeReturn
300 gst_smokedec_change_state (GstElement * element, GstStateChange transition)
302 GstStateChangeReturn ret;
305 dec = GST_SMOKEDEC (element);
307 switch (transition) {
308 case GST_STATE_CHANGE_READY_TO_PAUSED:
309 /* reset the initial video state */
320 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
321 if (ret != GST_STATE_CHANGE_SUCCESS)
324 switch (transition) {
325 case GST_STATE_CHANGE_PAUSED_TO_READY: