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