[MOVED FROM BAD] + checking in plugin category changes
[platform/upstream/gst-plugins-good.git] / gst / y4m / gsty4mencode.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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <string.h>
24 #include <math.h>
25 #include <gst/gst.h>
26 #include <gst/video/video.h>
27 #include "gsty4mencode.h"
28
29 static GstElementDetails y4mencode_details = GST_ELEMENT_DETAILS (
30   "Y4mEncode",
31   "Codec/Encoder/Video",
32   "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)",
33   "Wim Taymans <wim.taymans@chello.be>"
34 );
35
36
37 /* Filter signals and args */
38 enum {
39   /* FILL ME */
40   LAST_SIGNAL
41 };
42
43 enum {
44   ARG_0
45 };
46
47 GST_PAD_TEMPLATE_FACTORY (y4mencode_src_factory,
48   "src",
49   GST_PAD_SRC,
50   GST_PAD_ALWAYS,
51   GST_CAPS_NEW (
52     "test_src",
53     "application/x-yuv4mpeg",
54       "y4mversion", GST_PROPS_INT (1)
55   )
56 )
57
58 GST_PAD_TEMPLATE_FACTORY (y4mencode_sink_factory,
59   "sink",
60   GST_PAD_SINK,
61   GST_PAD_ALWAYS,
62   gst_caps_new (
63     "test_src",
64     "video/x-raw-yuv",
65       GST_VIDEO_YUV_PAD_TEMPLATE_PROPS (
66               GST_PROPS_FOURCC (GST_STR_FOURCC ("I420")))
67   )
68 )
69
70 static void     gst_y4mencode_base_init         (gpointer g_class);
71 static void     gst_y4mencode_class_init        (GstY4mEncodeClass *klass);
72 static void     gst_y4mencode_init              (GstY4mEncode *filter);
73
74 static void     gst_y4mencode_set_property      (GObject       *object,
75                                                  guint          prop_id,
76                                                  const GValue  *value,
77                                                  GParamSpec    *pspec);
78 static void     gst_y4mencode_get_property      (GObject       *object,
79                                                  guint          prop_id,
80                                                  GValue        *value,
81                                                  GParamSpec    *pspec);
82
83 static void     gst_y4mencode_chain             (GstPad        *pad,
84                                                  GstData       *_data);
85 static GstElementStateReturn
86                 gst_y4mencode_change_state      (GstElement    *element);
87
88
89 static GstElementClass *parent_class = NULL;
90 /*static guint gst_filter_signals[LAST_SIGNAL] = { 0 }; */
91
92 GType
93 gst_y4mencode_get_type(void) {
94   static GType y4mencode_type = 0;
95
96   if (!y4mencode_type) {
97     static const GTypeInfo y4mencode_info = {
98       sizeof(GstY4mEncodeClass),
99       gst_y4mencode_base_init,
100       NULL,
101       (GClassInitFunc)gst_y4mencode_class_init,
102       NULL,
103       NULL,
104       sizeof(GstY4mEncode),
105       0,
106       (GInstanceInitFunc)gst_y4mencode_init,
107     };
108     y4mencode_type = g_type_register_static(GST_TYPE_ELEMENT,
109                                              "GstY4mEncode",
110                                              &y4mencode_info, 0);
111   }
112   return y4mencode_type;
113 }
114
115
116 static void
117 gst_y4mencode_base_init (gpointer g_class)
118 {
119   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
120   
121   gst_element_class_add_pad_template (element_class, 
122                   GST_PAD_TEMPLATE_GET (y4mencode_src_factory));
123   gst_element_class_add_pad_template (element_class, 
124                   GST_PAD_TEMPLATE_GET (y4mencode_sink_factory));
125   gst_element_class_set_details (element_class, &y4mencode_details);
126 }
127 static void
128 gst_y4mencode_class_init (GstY4mEncodeClass *klass)
129 {
130   GObjectClass *gobject_class;
131   GstElementClass *gstelement_class;
132
133   gobject_class = (GObjectClass*)klass;
134   gstelement_class = (GstElementClass*)klass;
135
136   parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
137
138   gstelement_class->change_state = gst_y4mencode_change_state;
139
140   gobject_class->set_property = gst_y4mencode_set_property;
141   gobject_class->get_property = gst_y4mencode_get_property;
142 }
143
144 static GstPadLinkReturn
145 gst_y4mencode_sinkconnect (GstPad *pad, GstCaps *caps)
146 {
147   GstY4mEncode *filter;
148   gint idx = -1, i;
149   gfloat fps;
150   float framerates[] = {
151     00.000,
152     23.976, 24.000,              /* 24fps movie */
153     25.000,                      /* PAL */
154     29.970, 30.000,              /* NTSC */
155     50.000,
156     59.940, 60.000
157   };
158
159   filter = GST_Y4MENCODE (gst_pad_get_parent (pad));
160
161   if (!GST_CAPS_IS_FIXED (caps))
162     return GST_PAD_LINK_DELAYED;
163
164   gst_caps_get_int (caps, "width", &filter->width);
165   gst_caps_get_int (caps, "height", &filter->height);
166   gst_caps_get_float (caps, "framerate", &fps);
167
168   /* find fps idx */
169   for (i = 1; i < 9; i++) {
170     if (idx == -1) {
171        idx = i;
172     } else {
173       gfloat old_diff = fabs(framerates[idx] - fps),
174              new_diff = fabs(framerates[i]   - fps);
175
176       if (new_diff < old_diff) {
177         idx = i;
178       }
179     }
180   }
181   filter->fps_idx = idx;
182
183   return GST_PAD_LINK_OK;
184 }
185
186 static void
187 gst_y4mencode_init (GstY4mEncode *filter)
188 {
189   filter->sinkpad = gst_pad_new_from_template(
190                   GST_PAD_TEMPLATE_GET (y4mencode_sink_factory), "sink");
191   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
192   gst_pad_set_chain_function (filter->sinkpad, gst_y4mencode_chain);
193   gst_pad_set_link_function (filter->sinkpad, gst_y4mencode_sinkconnect);
194
195   filter->srcpad = gst_pad_new_from_template(
196                   GST_PAD_TEMPLATE_GET (y4mencode_src_factory), "src");
197   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
198
199   filter->init = TRUE;
200 }
201
202 static void
203 gst_y4mencode_chain (GstPad *pad,GstData *_data)
204 {
205   GstBuffer *buf = GST_BUFFER (_data);
206   GstY4mEncode *filter;
207   GstBuffer* outbuf;
208   gchar *header;
209   gint len;
210
211   g_return_if_fail(pad != NULL);
212   g_return_if_fail(GST_IS_PAD(pad));
213   g_return_if_fail(buf != NULL);
214
215   filter = GST_Y4MENCODE (gst_pad_get_parent (pad));
216   g_return_if_fail(filter != NULL);
217   g_return_if_fail(GST_IS_Y4MENCODE(filter));
218
219   outbuf = gst_buffer_new ();
220   GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (buf) + 256);
221
222   if (filter->init) {
223     header = "YUV4MPEG %d %d %d\nFRAME\n";
224     filter->init = FALSE;
225   }
226   else {
227     header = "FRAME\n";
228   }
229
230   snprintf (GST_BUFFER_DATA (outbuf), 255, header,
231             filter->width, filter->height, filter->fps_idx);
232   len = strlen (GST_BUFFER_DATA (outbuf));
233
234   memcpy (GST_BUFFER_DATA (outbuf) + len, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
235   GST_BUFFER_SIZE (outbuf) = GST_BUFFER_SIZE (buf) + len;
236
237   gst_buffer_unref(buf);
238
239   gst_pad_push(filter->srcpad,GST_DATA (outbuf));
240 }
241
242 static void
243 gst_y4mencode_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
244 {
245   GstY4mEncode *filter;
246
247   /* it's not null if we got it, but it might not be ours */
248   g_return_if_fail(GST_IS_Y4MENCODE(object));
249   filter = GST_Y4MENCODE(object);
250
251   switch (prop_id) {
252     default:
253       break;
254   }
255 }
256
257 static void
258 gst_y4mencode_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
259 {
260   GstY4mEncode *filter;
261
262   /* it's not null if we got it, but it might not be ours */
263   g_return_if_fail(GST_IS_Y4MENCODE(object));
264   filter = GST_Y4MENCODE(object);
265
266   switch (prop_id) {
267     default:
268       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
269       break;
270   }
271 }
272
273 static GstElementStateReturn
274 gst_y4mencode_change_state (GstElement *element)
275 {
276   GstY4mEncode *filter;
277
278   g_return_val_if_fail (GST_IS_Y4MENCODE (element), GST_STATE_FAILURE);
279
280   filter = GST_Y4MENCODE(element);
281
282   if (GST_STATE_TRANSITION (element) == GST_STATE_NULL_TO_READY) {
283     filter->init = TRUE;
284   }
285
286   if (GST_ELEMENT_CLASS (parent_class)->change_state)
287     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
288
289   return GST_STATE_SUCCESS;
290 }
291
292 static gboolean
293 plugin_init (GstPlugin *plugin)
294 {
295   return gst_element_register (plugin, "y4menc", GST_RANK_NONE, GST_TYPE_Y4MENCODE);
296 }
297
298 GST_PLUGIN_DEFINE (
299   GST_VERSION_MAJOR,
300   GST_VERSION_MINOR,
301   "y4menc",
302   "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)",
303   plugin_init,
304   VERSION,
305   GST_LICENSE,
306   GST_COPYRIGHT,
307   GST_PACKAGE,
308   GST_ORIGIN
309 )