Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / gst / frei0r / gstfrei0rsrc.c
1 /* GStreamer
2  * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
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
24 #include <string.h>
25
26 #include "gstfrei0r.h"
27 #include "gstfrei0rsrc.h"
28
29 #include <gst/controller/gstcontroller.h>
30
31 GST_DEBUG_CATEGORY_EXTERN (frei0r_debug);
32 #define GST_CAT_DEFAULT frei0r_debug
33
34 typedef struct
35 {
36   f0r_plugin_info_t info;
37   GstFrei0rFuncTable ftable;
38 } GstFrei0rSrcClassData;
39
40 static gboolean
41 gst_frei0r_src_set_caps (GstBaseSrc * src, GstCaps * caps)
42 {
43   GstFrei0rSrc *self = GST_FREI0R_SRC (src);
44
45   if (!gst_video_format_parse_caps (caps, &self->fmt, &self->width,
46           &self->height)
47       || !gst_video_parse_caps_framerate (caps, &self->fps_n, &self->fps_d))
48     return FALSE;
49
50   return TRUE;
51 }
52
53 static GstCaps *
54 gst_frei0r_src_get_caps (GstBaseSrc * src)
55 {
56   if (GST_PAD_CAPS (GST_BASE_SRC_PAD (src)))
57     return gst_caps_ref (GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
58   else
59     return
60         gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (src)));
61 }
62
63 static GstFlowReturn
64 gst_frei0r_src_create (GstPushSrc * src, GstBuffer ** buf)
65 {
66   GstFrei0rSrc *self = GST_FREI0R_SRC (src);
67   GstFrei0rSrcClass *klass = GST_FREI0R_SRC_GET_CLASS (src);
68   guint size, newsize;
69   GstFlowReturn ret = GST_FLOW_OK;
70   GstBuffer *outbuf = NULL;
71   GstClockTime timestamp;
72   gdouble time;
73
74   *buf = NULL;
75
76   if (G_UNLIKELY (self->width <= 0 || self->height <= 0))
77     return GST_FLOW_NOT_NEGOTIATED;
78
79   if (G_UNLIKELY (!self->f0r_instance)) {
80     self->f0r_instance =
81         gst_frei0r_instance_construct (klass->ftable, klass->properties,
82         klass->n_properties, self->property_cache, self->width, self->height);
83
84     if (G_UNLIKELY (!self->f0r_instance))
85       return GST_FLOW_ERROR;
86   }
87
88   newsize = gst_video_format_get_size (self->fmt, self->width, self->height);
89
90   ret =
91       gst_pad_alloc_buffer_and_set_caps (GST_BASE_SRC_PAD (src),
92       GST_BUFFER_OFFSET_NONE, newsize, GST_PAD_CAPS (GST_BASE_SRC_PAD (src)),
93       &outbuf);
94   if (ret != GST_FLOW_OK)
95     return ret;
96
97   /* Format might have changed */
98   size = GST_BUFFER_SIZE (outbuf);
99   newsize = gst_video_format_get_size (self->fmt, self->width, self->height);
100
101   if (size != newsize) {
102     gst_buffer_unref (outbuf);
103     outbuf = gst_buffer_new_and_alloc (newsize);
104     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
105   }
106
107   GST_BUFFER_TIMESTAMP (outbuf) = timestamp =
108       gst_util_uint64_scale (self->n_frames, GST_SECOND * self->fps_d,
109       self->fps_n);
110   GST_BUFFER_OFFSET (outbuf) = self->n_frames;
111   self->n_frames++;
112   GST_BUFFER_OFFSET_END (outbuf) = self->n_frames;
113   GST_BUFFER_DURATION (outbuf) =
114       gst_util_uint64_scale (self->n_frames, GST_SECOND * self->fps_d,
115       self->fps_n) - GST_BUFFER_TIMESTAMP (outbuf);
116
117   timestamp =
118       gst_segment_to_stream_time (&GST_BASE_SRC_CAST (self)->segment,
119       GST_FORMAT_TIME, timestamp);
120
121   GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT,
122       GST_TIME_ARGS (timestamp));
123
124   if (GST_CLOCK_TIME_IS_VALID (timestamp))
125     gst_object_sync_values (G_OBJECT (self), timestamp);
126
127   time = ((gdouble) GST_BUFFER_TIMESTAMP (outbuf)) / GST_SECOND;
128
129   GST_OBJECT_LOCK (self);
130   if (klass->ftable->update2)
131     klass->ftable->update2 (self->f0r_instance, time, NULL, NULL, NULL,
132         (guint32 *) GST_BUFFER_DATA (outbuf));
133   else
134     klass->ftable->update (self->f0r_instance, time, NULL,
135         (guint32 *) GST_BUFFER_DATA (outbuf));
136   GST_OBJECT_UNLOCK (self);
137
138   *buf = outbuf;
139
140   return GST_FLOW_OK;
141 }
142
143 static gboolean
144 gst_frei0r_src_start (GstBaseSrc * basesrc)
145 {
146   GstFrei0rSrc *self = GST_FREI0R_SRC (basesrc);
147
148   self->n_frames = 0;
149
150   return TRUE;
151 }
152
153 static gboolean
154 gst_frei0r_src_stop (GstBaseSrc * basesrc)
155 {
156   GstFrei0rSrc *self = GST_FREI0R_SRC (basesrc);
157   GstFrei0rSrcClass *klass = GST_FREI0R_SRC_GET_CLASS (basesrc);
158
159   if (self->f0r_instance) {
160     klass->ftable->destruct (self->f0r_instance);
161     self->f0r_instance = NULL;
162   }
163
164   self->fmt = GST_VIDEO_FORMAT_UNKNOWN;
165   self->width = self->height = 0;
166   self->fps_n = self->fps_d = 0;
167   self->n_frames = 0;
168
169   return TRUE;
170 }
171
172 static gboolean
173 gst_frei0r_src_is_seekable (GstBaseSrc * psrc)
174 {
175   return TRUE;
176 }
177
178 static gboolean
179 gst_frei0r_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
180 {
181   GstClockTime time;
182   GstFrei0rSrc *self = GST_FREI0R_SRC (bsrc);
183
184   segment->time = segment->start;
185   time = segment->last_stop;
186
187   /* now move to the time indicated */
188   if (self->fps_n) {
189     self->n_frames = gst_util_uint64_scale (time,
190         self->fps_n, self->fps_d * GST_SECOND);
191   } else {
192     self->n_frames = 0;
193   }
194
195   return TRUE;
196 }
197
198 static gboolean
199 gst_frei0r_src_query (GstBaseSrc * bsrc, GstQuery * query)
200 {
201   gboolean res;
202   GstFrei0rSrc *self = GST_FREI0R_SRC (bsrc);
203   GstFrei0rSrcClass *klass = GST_FREI0R_SRC_GET_CLASS (self);
204
205   switch (GST_QUERY_TYPE (query)) {
206     case GST_QUERY_CONVERT:
207     {
208       GstFormat src_fmt, dest_fmt;
209       gint64 src_val, dest_val;
210
211       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
212       if (src_fmt == dest_fmt) {
213         dest_val = src_val;
214         goto done;
215       }
216
217       switch (src_fmt) {
218         case GST_FORMAT_DEFAULT:
219           switch (dest_fmt) {
220             case GST_FORMAT_TIME:
221               /* frames to time */
222               if (self->fps_n) {
223                 dest_val = gst_util_uint64_scale (src_val,
224                     self->fps_d * GST_SECOND, self->fps_n);
225               } else {
226                 dest_val = 0;
227               }
228               break;
229             default:
230               goto error;
231           }
232           break;
233         case GST_FORMAT_TIME:
234           switch (dest_fmt) {
235             case GST_FORMAT_DEFAULT:
236               /* time to frames */
237               if (self->fps_n) {
238                 dest_val = gst_util_uint64_scale (src_val,
239                     self->fps_n, self->fps_d * GST_SECOND);
240               } else {
241                 dest_val = 0;
242               }
243               break;
244             default:
245               goto error;
246           }
247           break;
248         default:
249           goto error;
250       }
251     done:
252       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
253       res = TRUE;
254       break;
255     }
256     default:
257       res =
258           GST_BASE_SRC_CLASS (g_type_class_peek_parent (klass))->query (bsrc,
259           query);
260   }
261   return res;
262
263   /* ERROR */
264 error:
265   {
266     GST_DEBUG_OBJECT (self, "query failed");
267     return FALSE;
268   }
269 }
270
271 static void
272 gst_frei0r_src_src_fixate (GstPad * pad, GstCaps * caps)
273 {
274   GstStructure *structure;
275
276   structure = gst_caps_get_structure (caps, 0);
277
278   gst_structure_fixate_field_nearest_int (structure, "width", 320);
279   gst_structure_fixate_field_nearest_int (structure, "height", 240);
280   gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
281 }
282
283 static void
284 gst_frei0r_src_finalize (GObject * object)
285 {
286   GstFrei0rSrc *self = GST_FREI0R_SRC (object);
287   GstFrei0rSrcClass *klass = GST_FREI0R_SRC_GET_CLASS (object);
288
289   if (self->f0r_instance) {
290     klass->ftable->destruct (self->f0r_instance);
291     self->f0r_instance = NULL;
292   }
293
294   if (self->property_cache)
295     gst_frei0r_property_cache_free (klass->properties, self->property_cache,
296         klass->n_properties);
297   self->property_cache = NULL;
298
299   G_OBJECT_CLASS (g_type_class_peek_parent (klass))->finalize (object);
300 }
301
302 static void
303 gst_frei0r_src_get_property (GObject * object, guint prop_id, GValue * value,
304     GParamSpec * pspec)
305 {
306   GstFrei0rSrc *self = GST_FREI0R_SRC (object);
307   GstFrei0rSrcClass *klass = GST_FREI0R_SRC_GET_CLASS (object);
308
309   GST_OBJECT_LOCK (self);
310   if (!gst_frei0r_get_property (self->f0r_instance, klass->ftable,
311           klass->properties, klass->n_properties, self->property_cache, prop_id,
312           value))
313     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
314   GST_OBJECT_UNLOCK (self);
315 }
316
317 static void
318 gst_frei0r_src_set_property (GObject * object, guint prop_id,
319     const GValue * value, GParamSpec * pspec)
320 {
321   GstFrei0rSrc *self = GST_FREI0R_SRC (object);
322   GstFrei0rSrcClass *klass = GST_FREI0R_SRC_GET_CLASS (object);
323
324   GST_OBJECT_LOCK (self);
325   if (!gst_frei0r_set_property (self->f0r_instance, klass->ftable,
326           klass->properties, klass->n_properties, self->property_cache, prop_id,
327           value))
328     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
329   GST_OBJECT_UNLOCK (self);
330 }
331
332 static void
333 gst_frei0r_src_class_init (GstFrei0rSrcClass * klass,
334     GstFrei0rSrcClassData * class_data)
335 {
336   GObjectClass *gobject_class = (GObjectClass *) klass;
337   GstElementClass *gstelement_class = (GstElementClass *) klass;
338   GstPushSrcClass *gstpushsrc_class = (GstPushSrcClass *) klass;
339   GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass;
340   GstPadTemplate *templ;
341   GstCaps *caps;
342   gchar *author;
343
344   klass->ftable = &class_data->ftable;
345   klass->info = &class_data->info;
346
347   gobject_class->finalize = gst_frei0r_src_finalize;
348   gobject_class->set_property = gst_frei0r_src_set_property;
349   gobject_class->get_property = gst_frei0r_src_get_property;
350
351   klass->n_properties = klass->info->num_params;
352   klass->properties = g_new0 (GstFrei0rProperty, klass->n_properties);
353
354   gst_frei0r_klass_install_properties (gobject_class, klass->ftable,
355       klass->properties, klass->n_properties);
356
357   author =
358       g_strdup_printf
359       ("Sebastian Dröge <sebastian.droege@collabora.co.uk>, %s",
360       class_data->info.author);
361   gst_element_class_set_details_simple (gstelement_class, class_data->info.name,
362       "Src/Video", class_data->info.explanation, author);
363   g_free (author);
364
365   caps = gst_frei0r_caps_from_color_model (class_data->info.color_model);
366
367   templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
368   gst_element_class_add_pad_template (gstelement_class, templ);
369   gst_object_unref (templ);
370
371   gstbasesrc_class->set_caps = gst_frei0r_src_set_caps;
372   gstbasesrc_class->get_caps = gst_frei0r_src_get_caps;
373   gstbasesrc_class->is_seekable = gst_frei0r_src_is_seekable;
374   gstbasesrc_class->do_seek = gst_frei0r_src_do_seek;
375   gstbasesrc_class->query = gst_frei0r_src_query;
376   gstbasesrc_class->start = gst_frei0r_src_start;
377   gstbasesrc_class->stop = gst_frei0r_src_stop;
378
379   gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_frei0r_src_create);
380 }
381
382 static void
383 gst_frei0r_src_init (GstFrei0rSrc * self, GstFrei0rSrcClass * klass)
384 {
385   GstPad *pad = GST_BASE_SRC_PAD (self);
386
387   self->property_cache =
388       gst_frei0r_property_cache_init (klass->properties, klass->n_properties);
389
390   gst_pad_set_fixatecaps_function (pad, gst_frei0r_src_src_fixate);
391
392   gst_base_src_set_format (GST_BASE_SRC_CAST (self), GST_FORMAT_TIME);
393 }
394
395 GstFrei0rPluginRegisterReturn
396 gst_frei0r_src_register (GstPlugin * plugin, const gchar * vendor,
397     const f0r_plugin_info_t * info, const GstFrei0rFuncTable * ftable)
398 {
399   GTypeInfo typeinfo = {
400     sizeof (GstFrei0rSrcClass),
401     NULL,
402     NULL,
403     (GClassInitFunc) gst_frei0r_src_class_init,
404     NULL,
405     NULL,
406     sizeof (GstFrei0rSrc),
407     0,
408     (GInstanceInitFunc) gst_frei0r_src_init
409   };
410   GType type;
411   gchar *type_name, *tmp;
412   GstFrei0rSrcClassData *class_data;
413   GstFrei0rPluginRegisterReturn ret = GST_FREI0R_PLUGIN_REGISTER_RETURN_FAILED;
414
415   if (vendor)
416     tmp = g_strdup_printf ("frei0r-src-%s-%s", vendor, info->name);
417   else
418     tmp = g_strdup_printf ("frei0r-src-%s", info->name);
419   type_name = g_ascii_strdown (tmp, -1);
420   g_free (tmp);
421   g_strcanon (type_name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-+", '-');
422
423   if (g_type_from_name (type_name)) {
424     GST_DEBUG ("Type '%s' already exists", type_name);
425     return GST_FREI0R_PLUGIN_REGISTER_RETURN_ALREADY_REGISTERED;
426   }
427
428   class_data = g_new0 (GstFrei0rSrcClassData, 1);
429   memcpy (&class_data->info, info, sizeof (f0r_plugin_info_t));
430   memcpy (&class_data->ftable, ftable, sizeof (GstFrei0rFuncTable));
431   typeinfo.class_data = class_data;
432
433   type = g_type_register_static (GST_TYPE_PUSH_SRC, type_name, &typeinfo, 0);
434   if (gst_element_register (plugin, type_name, GST_RANK_NONE, type))
435     ret = GST_FREI0R_PLUGIN_REGISTER_RETURN_OK;
436
437   g_free (type_name);
438   return ret;
439 }