376b916b831e2793b2fe6f0af3256ff4ceb3693a
[platform/upstream/gstreamer.git] / ext / mimic / gstmimenc.c
1    /* 
2  * GStreamer
3  * Copyright (c) 2005 INdT.
4  * @author Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
5  * @author Philippe Khalaf <burger@speedy.org>
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gst/gst.h>
28
29 #include "gstmimenc.h"
30
31 GST_DEBUG_CATEGORY (mimenc_debug);
32 #define GST_CAT_DEFAULT (mimenc_debug)
33
34 #define MAX_INTERFRAMES 15
35
36 static GstStaticPadTemplate sink_factory =
37 GST_STATIC_PAD_TEMPLATE (
38     "sink",
39     GST_PAD_SINK,
40     GST_PAD_ALWAYS,
41     GST_STATIC_CAPS (
42       "video/x-raw-rgb, "
43         "bpp = (int) 24, "
44         "depth = (int) 24, "
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, "
50         "width = (int) 320, "
51         "height = (int) 240"
52       ";video/x-raw-rgb, "
53         "bpp = (int) 24, "
54         "depth = (int) 24, "
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, "
60         "width = (int) 160, "
61         "height = (int) 120"
62     )
63 );
64
65 static GstStaticPadTemplate src_factory =
66 GST_STATIC_PAD_TEMPLATE (
67   "src",
68   GST_PAD_SRC,
69   GST_PAD_ALWAYS,
70   GST_STATIC_CAPS ("video/x-msnwebcam") 
71 );
72
73
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);
77
78 static gboolean      gst_mimenc_setcaps           (GstPad         *pad, 
79                                                    GstCaps        *caps);
80 static GstFlowReturn gst_mimenc_chain             (GstPad         *pad, 
81                                                    GstBuffer      *in);
82 static GstBuffer*    gst_mimenc_create_tcp_header (GstMimEnc      *mimenc, 
83                                                    gint            payload_size);
84
85 #if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1)
86 static GstElementStateReturn
87                      gst_mimenc_change_state      (GstElement     *element);
88 #else
89 static GstStateChangeReturn
90                      gst_mimenc_change_state      (GstElement     *element, 
91                                                   GstStateChange   transition);
92 #endif
93
94 static GstElementClass *parent_class = NULL;
95
96 GType
97 gst_gst_mimenc_get_type (void)
98 {
99   static GType plugin_type = 0;
100
101   if (!plugin_type)
102   {
103     static const GTypeInfo plugin_info =
104     {
105       sizeof (GstMimEncClass),
106       (GBaseInitFunc) gst_mimenc_base_init,
107       NULL,
108       (GClassInitFunc) gst_mimenc_class_init,
109       NULL,
110       NULL,
111       sizeof (GstMimEnc),
112       0,
113       (GInstanceInitFunc) gst_mimenc_init,
114     };
115     plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
116                                               "GstMimEnc",
117                                           &plugin_info, 0);
118   }
119   return plugin_type;
120 }
121
122 static void
123 gst_mimenc_base_init (GstMimEncClass *klass)
124 {
125   static GstElementDetails plugin_details = {
126     "MimEnc",
127     "Codec/Encoder/Video",
128     "Mimic encoder",
129     "Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>"
130   };
131   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
132
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);
138 }
139
140 static void
141 gst_mimenc_class_init (GstMimEncClass *klass)
142 {
143   GObjectClass *gobject_class;
144   GstElementClass *gstelement_class;
145
146   gobject_class = (GObjectClass*) klass;
147   gstelement_class = (GstElementClass*) klass;
148   gstelement_class->change_state = gst_mimenc_change_state;
149
150   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
151
152   GST_DEBUG_CATEGORY_INIT (mimenc_debug, "mimenc", 0, "Mimic encoder plugin");
153 }
154
155 static void
156 gst_mimenc_init (GstMimEnc *mimenc)
157 {
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);
163
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);
167
168   mimenc->enc = NULL;
169
170   // TODO property to set resolution
171   mimenc->res = MIMIC_RES_HIGH;
172   mimenc->buffer_size = -1;
173   mimenc->width = 0;
174   mimenc->height = 0;
175   mimenc->frames = 0;
176 }
177
178 static gboolean
179 gst_mimenc_setcaps (GstPad *pad, GstCaps *caps)
180 {
181   GstMimEnc *filter;
182   GstStructure *structure;
183   int ret, height, width;
184
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);
188
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);
196   if (!ret) {
197       gst_object_unref(filter);
198       return FALSE;
199   }
200   gst_object_unref(filter);
201   return TRUE;
202 }
203
204 static GstFlowReturn
205 gst_mimenc_chain (GstPad *pad, GstBuffer *in)
206 {
207   GstMimEnc *mimenc;
208   GstBuffer *out_buf, *buf;
209   guchar *data;
210   gint buffer_size;
211   GstBuffer * header = NULL;
212
213   g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
214   mimenc = GST_MIMENC (GST_OBJECT_PARENT (pad));
215
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);
218
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;
224     }
225     
226     if (!mimic_encoder_init (mimenc->enc, mimenc->res)) {
227       GST_WARNING ("mimic_encoder_init error\n");
228       mimic_close (mimenc->enc);
229       mimenc->enc = NULL;
230       return GST_FLOW_ERROR;
231     }
232     
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);
236       mimenc->enc = NULL;
237       return GST_FLOW_ERROR;
238     }
239   }
240
241   buf = in;
242   data = GST_BUFFER_DATA (buf);
243
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;
253   }
254   GST_BUFFER_SIZE (out_buf) = buffer_size;
255
256   GST_DEBUG ("incoming buf size %d, encoded size %d", GST_BUFFER_SIZE(buf), GST_BUFFER_SIZE(out_buf));
257   ++mimenc->frames;
258
259   // now let's create that tcp header
260   header = gst_mimenc_create_tcp_header (mimenc, buffer_size);
261
262   if (header)
263   {
264       gst_pad_push (mimenc->srcpad, header);
265       gst_pad_push (mimenc->srcpad, out_buf);
266   }
267   else
268   {
269       GST_DEBUG("header not created succesfully");
270       return GST_FLOW_ERROR;
271   }
272
273   gst_buffer_unref (buf);
274
275   return GST_FLOW_OK;
276 }
277
278 static GstBuffer* 
279 gst_mimenc_create_tcp_header (GstMimEnc *mimenc, gint payload_size)
280 {
281     // 24 bytes
282     GstBuffer *buf_header = gst_buffer_new_and_alloc (24);
283     guchar *p = (guchar *) GST_BUFFER_DATA(buf_header);
284
285     p[0] = 24;
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 */
294
295     return buf_header;
296 }
297
298 #if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1)
299 static GstElementStateReturn
300 gst_mimenc_change_state (GstElement * element)
301 {
302   GstMimEnc *mimenc;
303
304   switch (GST_STATE_TRANSITION (element)) {
305     case GST_STATE_READY_TO_NULL:
306 #else
307 static GstStateChangeReturn
308 gst_mimenc_change_state (GstElement * element, GstStateChange transition)
309 {
310   GstMimEnc *mimenc;
311
312   switch (transition) {
313     case GST_STATE_CHANGE_READY_TO_NULL:
314 #endif
315       mimenc = GST_MIMENC (element);
316       if (mimenc->enc != NULL) {
317         mimic_close (mimenc->enc);
318         mimenc->enc = NULL;
319         mimenc->buffer_size = -1;
320         mimenc->frames = 0;
321       }
322       break;
323
324     default:
325       break;
326   }
327
328 #if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1)
329   return GST_ELEMENT_CLASS (parent_class)->change_state (element);
330 #else
331   return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
332 }