3 * Copyright (c) 2005 INdT.
4 * @author Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
5 * @author Philippe Khalaf <burger@speedy.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
29 #include "gstmimenc.h"
31 GST_DEBUG_CATEGORY (mimenc_debug);
32 #define GST_CAT_DEFAULT (mimenc_debug)
34 #define MAX_INTERFRAMES 15
36 static GstStaticPadTemplate sink_factory =
37 GST_STATIC_PAD_TEMPLATE (
45 "endianness = (int) 4321, "
46 "framerate = (double) [1.0, 30.0], "
47 "red_mask = (int) 16711680, "
48 "green_mask = (int) 65280, "
49 "blue_mask = (int) 255, "
55 "endianness = (int) 4321, "
56 "framerate = (double) [1.0, 30.0], "
57 "red_mask = (int) 16711680, "
58 "green_mask = (int) 65280, "
59 "blue_mask = (int) 255, "
65 static GstStaticPadTemplate src_factory =
66 GST_STATIC_PAD_TEMPLATE (
70 GST_STATIC_CAPS ("video/x-msnwebcam")
74 static void gst_mimenc_class_init (GstMimEncClass *klass);
75 static void gst_mimenc_base_init (GstMimEncClass *klass);
76 static void gst_mimenc_init (GstMimEnc *mimenc);
78 static gboolean gst_mimenc_setcaps (GstPad *pad,
80 static GstFlowReturn gst_mimenc_chain (GstPad *pad,
82 static GstBuffer* gst_mimenc_create_tcp_header (GstMimEnc *mimenc,
85 #if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1)
86 static GstElementStateReturn
87 gst_mimenc_change_state (GstElement *element);
89 static GstStateChangeReturn
90 gst_mimenc_change_state (GstElement *element,
91 GstStateChange transition);
94 static GstElementClass *parent_class = NULL;
97 gst_gst_mimenc_get_type (void)
99 static GType plugin_type = 0;
103 static const GTypeInfo plugin_info =
105 sizeof (GstMimEncClass),
106 (GBaseInitFunc) gst_mimenc_base_init,
108 (GClassInitFunc) gst_mimenc_class_init,
113 (GInstanceInitFunc) gst_mimenc_init,
115 plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
123 gst_mimenc_base_init (GstMimEncClass *klass)
125 static GstElementDetails plugin_details = {
127 "Codec/Encoder/Video",
129 "Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>"
131 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
133 gst_element_class_add_pad_template (element_class,
134 gst_static_pad_template_get (&src_factory));
135 gst_element_class_add_pad_template (element_class,
136 gst_static_pad_template_get (&sink_factory));
137 gst_element_class_set_details (element_class, &plugin_details);
141 gst_mimenc_class_init (GstMimEncClass *klass)
143 GObjectClass *gobject_class;
144 GstElementClass *gstelement_class;
146 gobject_class = (GObjectClass*) klass;
147 gstelement_class = (GstElementClass*) klass;
148 gstelement_class->change_state = gst_mimenc_change_state;
150 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
152 GST_DEBUG_CATEGORY_INIT (mimenc_debug, "mimenc", 0, "Mimic encoder plugin");
156 gst_mimenc_init (GstMimEnc *mimenc)
158 mimenc->sinkpad = gst_pad_new_from_template (
159 gst_static_pad_template_get (&sink_factory), "sink");
160 gst_element_add_pad (GST_ELEMENT (mimenc), mimenc->sinkpad);
161 gst_pad_set_setcaps_function (mimenc->sinkpad, gst_mimenc_setcaps);
162 gst_pad_set_chain_function (mimenc->sinkpad, gst_mimenc_chain);
164 mimenc->srcpad = gst_pad_new_from_template (
165 gst_static_pad_template_get (&src_factory), "src");
166 gst_element_add_pad (GST_ELEMENT (mimenc), mimenc->srcpad);
170 // TODO property to set resolution
171 mimenc->res = MIMIC_RES_HIGH;
172 mimenc->buffer_size = -1;
179 gst_mimenc_setcaps (GstPad *pad, GstCaps *caps)
182 GstStructure *structure;
183 int ret, height, width;
185 filter = GST_MIMENC (gst_pad_get_parent (pad));
186 g_return_val_if_fail (filter != NULL, FALSE);
187 g_return_val_if_fail (GST_IS_MIMENC (filter), FALSE);
189 structure = gst_caps_get_structure( caps, 0 );
190 ret = gst_structure_get_int( structure, "width", &width );
191 ret = gst_structure_get_int( structure, "height", &height );
192 filter->width = (guint16)width;
193 filter->height = (guint16)height;
194 filter->res = (width == 320) ? MIMIC_RES_HIGH : MIMIC_RES_LOW;
195 GST_DEBUG ("Got info from caps w : %d, h : %d", filter->width, filter->height);
197 gst_object_unref(filter);
200 gst_object_unref(filter);
205 gst_mimenc_chain (GstPad *pad, GstBuffer *in)
208 GstBuffer *out_buf, *buf;
211 GstBuffer * header = NULL;
213 g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
214 mimenc = GST_MIMENC (GST_OBJECT_PARENT (pad));
216 g_return_val_if_fail (GST_IS_MIMENC (mimenc), GST_FLOW_ERROR);
217 g_return_val_if_fail (GST_PAD_IS_LINKED (mimenc->srcpad), GST_FLOW_ERROR);
219 if (mimenc->enc == NULL) {
220 mimenc->enc = mimic_open ();
221 if (mimenc->enc == NULL) {
222 GST_WARNING ("mimic_open error\n");
223 return GST_FLOW_ERROR;
226 if (!mimic_encoder_init (mimenc->enc, mimenc->res)) {
227 GST_WARNING ("mimic_encoder_init error\n");
228 mimic_close (mimenc->enc);
230 return GST_FLOW_ERROR;
233 if (!mimic_get_property (mimenc->enc, "buffer_size", &mimenc->buffer_size)) {
234 GST_WARNING ("mimic_get_property('buffer_size') error\n");
235 mimic_close (mimenc->enc);
237 return GST_FLOW_ERROR;
242 data = GST_BUFFER_DATA (buf);
244 out_buf = gst_buffer_new_and_alloc (mimenc->buffer_size);
245 GST_BUFFER_TIMESTAMP(out_buf) = GST_BUFFER_TIMESTAMP(buf);
246 buffer_size = mimenc->buffer_size;
247 if (!mimic_encode_frame (mimenc->enc, data, GST_BUFFER_DATA (out_buf),
248 &buffer_size, ((mimenc->frames % MAX_INTERFRAMES) == 0 ? TRUE : FALSE))) {
249 GST_WARNING ("mimic_encode_frame error\n");
250 gst_buffer_unref (out_buf);
251 gst_buffer_unref (buf);
252 return GST_FLOW_ERROR;
254 GST_BUFFER_SIZE (out_buf) = buffer_size;
256 GST_DEBUG ("incoming buf size %d, encoded size %d", GST_BUFFER_SIZE(buf), GST_BUFFER_SIZE(out_buf));
259 // now let's create that tcp header
260 header = gst_mimenc_create_tcp_header (mimenc, buffer_size);
264 gst_pad_push (mimenc->srcpad, header);
265 gst_pad_push (mimenc->srcpad, out_buf);
269 GST_DEBUG("header not created succesfully");
270 return GST_FLOW_ERROR;
273 gst_buffer_unref (buf);
279 gst_mimenc_create_tcp_header (GstMimEnc *mimenc, gint payload_size)
282 GstBuffer *buf_header = gst_buffer_new_and_alloc (24);
283 guchar *p = (guchar *) GST_BUFFER_DATA(buf_header);
286 *((guchar *) (p + 1)) = 0;
287 *((guint16 *) (p + 2)) = GUINT16_TO_LE(mimenc->width);
288 *((guint16 *) (p + 4)) = GUINT16_TO_LE(mimenc->height);
289 *((guint16 *) (p + 6)) = 0;
290 *((guint32 *) (p + 8)) = GUINT32_TO_LE(payload_size);
291 *((guint32 *) (p + 12)) = GUINT32_TO_LE(GST_MAKE_FOURCC ('M', 'L', '2', '0'));
292 *((guint32 *) (p + 16)) = 0;
293 *((guint32 *) (p + 20)) = 0; /* FIXME: must be timestamp */
298 #if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1)
299 static GstElementStateReturn
300 gst_mimenc_change_state (GstElement * element)
304 switch (GST_STATE_TRANSITION (element)) {
305 case GST_STATE_READY_TO_NULL:
307 static GstStateChangeReturn
308 gst_mimenc_change_state (GstElement * element, GstStateChange transition)
312 switch (transition) {
313 case GST_STATE_CHANGE_READY_TO_NULL:
315 mimenc = GST_MIMENC (element);
316 if (mimenc->enc != NULL) {
317 mimic_close (mimenc->enc);
319 mimenc->buffer_size = -1;
328 #if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1)
329 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
331 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);