2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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.
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.
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.
25 #include <gst/video/video.h>
27 #define GST_TYPE_VIDEORATE \
28 (gst_videorate_get_type())
29 #define GST_VIDEORATE(obj) \
30 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEORATE,GstVideorate))
31 #define GST_VIDEORATE_CLASS(klass) \
32 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEORATE,GstVideorate))
33 #define GST_IS_VIDEORATE(obj) \
34 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEORATE))
35 #define GST_IS_VIDEORATE_CLASS(obj) \
36 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEORATE))
38 typedef struct _GstVideorate GstVideorate;
39 typedef struct _GstVideorateClass GstVideorateClass;
45 GstPad *sinkpad, *srcpad;
48 gdouble from_fps, to_fps;
51 guint64 in, out, dup, drop;
54 struct _GstVideorateClass
56 GstElementClass parent_class;
59 /* elementfactory information */
60 static GstElementDetails videorate_details =
61 GST_ELEMENT_DETAILS ("Video rate adjuster",
62 "Filter/Effect/Video",
63 "Drops/duplicates/adjusts timestamps on video frames to make a perfect stream",
64 "Wim Taymans <wim@fluendo.com>");
66 /* GstVideorate signals and args */
83 static GstStaticPadTemplate gst_videorate_src_template =
84 GST_STATIC_PAD_TEMPLATE ("src",
87 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ YUY2, I420, YV12, YUYV, UYVY }")
91 static GstStaticPadTemplate gst_videorate_sink_template =
92 GST_STATIC_PAD_TEMPLATE ("sink",
95 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ YUY2, I420, YV12, YUYV, UYVY }")
99 static void gst_videorate_base_init (gpointer g_class);
100 static void gst_videorate_class_init (GstVideorateClass * klass);
101 static void gst_videorate_init (GstVideorate * videorate);
102 static void gst_videorate_chain (GstPad * pad, GstData * _data);
104 static void gst_videorate_set_property (GObject * object,
105 guint prop_id, const GValue * value, GParamSpec * pspec);
106 static void gst_videorate_get_property (GObject * object,
107 guint prop_id, GValue * value, GParamSpec * pspec);
109 static GstElementStateReturn gst_videorate_change_state (GstElement * element);
111 static GstElementClass *parent_class = NULL;
113 /*static guint gst_videorate_signals[LAST_SIGNAL] = { 0 }; */
116 gst_videorate_get_type (void)
118 static GType videorate_type = 0;
120 if (!videorate_type) {
121 static const GTypeInfo videorate_info = {
122 sizeof (GstVideorateClass),
123 gst_videorate_base_init,
125 (GClassInitFunc) gst_videorate_class_init,
128 sizeof (GstVideorate),
130 (GInstanceInitFunc) gst_videorate_init,
133 videorate_type = g_type_register_static (GST_TYPE_ELEMENT,
134 "GstVideorate", &videorate_info, 0);
137 return videorate_type;
141 gst_videorate_base_init (gpointer g_class)
143 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
145 gst_element_class_set_details (element_class, &videorate_details);
147 gst_element_class_add_pad_template (element_class,
148 gst_static_pad_template_get (&gst_videorate_sink_template));
149 gst_element_class_add_pad_template (element_class,
150 gst_static_pad_template_get (&gst_videorate_src_template));
153 gst_videorate_class_init (GstVideorateClass * klass)
155 GObjectClass *object_class = G_OBJECT_CLASS (klass);
156 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
158 parent_class = g_type_class_peek_parent (klass);
160 g_object_class_install_property (object_class, ARG_IN,
161 g_param_spec_uint64 ("in", "In",
162 "Number of input frames", 0, G_MAXUINT64, 0, G_PARAM_READABLE));
163 g_object_class_install_property (object_class, ARG_OUT,
164 g_param_spec_uint64 ("out", "Out",
165 "Number of output frames", 0, G_MAXUINT64, 0, G_PARAM_READABLE));
166 g_object_class_install_property (object_class, ARG_DUP,
167 g_param_spec_uint64 ("duplicate", "Duplicate",
168 "Number of duplicated frames", 0, G_MAXUINT64, 0, G_PARAM_READABLE));
169 g_object_class_install_property (object_class, ARG_DROP,
170 g_param_spec_uint64 ("drop", "Drop",
171 "Number of dropped frames", 0, G_MAXUINT64, 0, G_PARAM_READABLE));
173 object_class->set_property = gst_videorate_set_property;
174 object_class->get_property = gst_videorate_get_property;
176 element_class->change_state = gst_videorate_change_state;
180 gst_videorate_getcaps (GstPad * pad)
182 GstVideorate *videorate;
184 GstCaps *caps, *copy, *copy2 = NULL;
187 GstStructure *structure;
190 videorate = GST_VIDEORATE (gst_pad_get_parent (pad));
192 otherpad = (pad == videorate->srcpad) ? videorate->sinkpad :
194 negotiated = gst_pad_is_negotiated (otherpad);
195 otherfps = (pad == videorate->srcpad) ? videorate->from_fps :
198 caps = gst_pad_get_allowed_caps (otherpad);
199 copy = gst_caps_copy (caps);
201 copy2 = gst_caps_copy (caps);
203 for (i = 0; i < gst_caps_get_size (caps); i++) {
204 structure = gst_caps_get_structure (caps, i);
206 gst_structure_set (structure,
207 "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
210 for (i = 0; i < gst_caps_get_size (copy2); i++) {
211 structure = gst_caps_get_structure (copy2, i);
213 gst_structure_set (structure, "framerate", G_TYPE_DOUBLE, otherfps, NULL);
215 gst_caps_append (copy2, copy);
218 gst_caps_append (copy, caps);
223 static GstPadLinkReturn
224 gst_videorate_link (GstPad * pad, const GstCaps * caps)
226 GstVideorate *videorate;
227 GstStructure *structure;
232 videorate = GST_VIDEORATE (gst_pad_get_parent (pad));
234 otherpad = (pad == videorate->srcpad) ? videorate->sinkpad :
237 structure = gst_caps_get_structure (caps, 0);
238 ret = gst_structure_get_double (structure, "framerate", &fps);
240 return GST_PAD_LINK_REFUSED;
242 if (pad == videorate->srcpad) {
243 videorate->to_fps = fps;
245 videorate->from_fps = fps;
248 if (gst_pad_is_negotiated (otherpad)) {
250 * Ensure that the other side talks the format we're trying to set
252 GstCaps *newcaps = gst_caps_copy (caps);
254 if (pad == videorate->srcpad) {
255 gst_caps_set_simple (newcaps,
256 "framerate", G_TYPE_DOUBLE, videorate->from_fps, NULL);
258 gst_caps_set_simple (newcaps,
259 "framerate", G_TYPE_DOUBLE, videorate->to_fps, NULL);
261 ret = gst_pad_try_set_caps (otherpad, newcaps);
262 if (GST_PAD_LINK_FAILED (ret)) {
263 return GST_PAD_LINK_REFUSED;
267 return GST_PAD_LINK_OK;
271 gst_videorate_init (GstVideorate * videorate)
273 GST_FLAG_SET (videorate, GST_ELEMENT_EVENT_AWARE);
275 GST_DEBUG ("gst_videorate_init");
277 gst_pad_new_from_template (gst_static_pad_template_get
278 (&gst_videorate_sink_template), "sink");
279 gst_element_add_pad (GST_ELEMENT (videorate), videorate->sinkpad);
280 gst_pad_set_chain_function (videorate->sinkpad, gst_videorate_chain);
281 gst_pad_set_getcaps_function (videorate->sinkpad, gst_videorate_getcaps);
282 gst_pad_set_link_function (videorate->sinkpad, gst_videorate_link);
285 gst_pad_new_from_template (gst_static_pad_template_get
286 (&gst_videorate_src_template), "src");
287 gst_element_add_pad (GST_ELEMENT (videorate), videorate->srcpad);
288 gst_pad_set_getcaps_function (videorate->srcpad, gst_videorate_getcaps);
289 gst_pad_set_link_function (videorate->srcpad, gst_videorate_link);
291 videorate->prevbuf = NULL;
299 gst_videorate_chain (GstPad * pad, GstData * data)
301 GstVideorate *videorate = GST_VIDEORATE (gst_pad_get_parent (pad));
304 if (GST_IS_EVENT (data)) {
305 GstEvent *event = GST_EVENT (data);
307 gst_pad_event_default (pad, event);
311 buf = GST_BUFFER (data);
313 /* pull in 2 buffers */
314 if (videorate->prevbuf == NULL) {
315 videorate->prevbuf = buf;
317 GstClockTime prevtime, intime;
321 prevtime = GST_BUFFER_TIMESTAMP (videorate->prevbuf);
322 intime = GST_BUFFER_TIMESTAMP (buf);
326 /* got 2 buffers, see which one is the best */
328 diff1 = abs (prevtime - videorate->next_ts);
329 diff2 = abs (intime - videorate->next_ts);
331 /* output first one when its the best */
332 if (diff1 <= diff2) {
337 gst_buffer_create_sub (videorate->prevbuf, 0,
338 GST_BUFFER_SIZE (videorate->prevbuf));
339 GST_BUFFER_TIMESTAMP (outbuf) = videorate->next_ts;
341 videorate->next_ts = videorate->out / videorate->to_fps * GST_SECOND;
342 GST_BUFFER_DURATION (outbuf) =
343 videorate->next_ts - GST_BUFFER_TIMESTAMP (outbuf);
344 gst_pad_push (videorate->srcpad, GST_DATA (outbuf));
346 /* continue while the first one was the best */
348 while (diff1 <= diff2);
350 /* if we outputed the first buffer more then once, we have dups */
352 videorate->dup += count - 1;
353 /* if we didn't output the first buffer, we have a drop */
357 // g_print ("swap: diff1 %lld, diff2 %lld, in %d, out %d, drop %d, dup %d\n", diff1, diff2,
358 // videorate->in, videorate->out, videorate->drop, videorate->dup);
360 /* swap in new one when it's the best */
361 gst_buffer_unref (videorate->prevbuf);
362 videorate->prevbuf = buf;
367 gst_videorate_set_property (GObject * object,
368 guint prop_id, const GValue * value, GParamSpec * pspec)
370 //GstVideorate *videorate = GST_VIDEORATE (object);
374 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
380 gst_videorate_get_property (GObject * object,
381 guint prop_id, GValue * value, GParamSpec * pspec)
383 GstVideorate *videorate = GST_VIDEORATE (object);
387 g_value_set_uint64 (value, videorate->in);
390 g_value_set_uint64 (value, videorate->out);
393 g_value_set_uint64 (value, videorate->dup);
396 g_value_set_uint64 (value, videorate->drop);
399 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
404 static GstElementStateReturn
405 gst_videorate_change_state (GstElement * element)
407 //GstVideorate *videorate = GST_VIDEORATE (element);
409 switch (GST_STATE_TRANSITION (element)) {
410 case GST_STATE_PAUSED_TO_READY:
416 if (parent_class->change_state)
417 return parent_class->change_state (element);
419 return GST_STATE_SUCCESS;
423 plugin_init (GstPlugin * plugin)
425 return gst_element_register (plugin, "videorate", GST_RANK_NONE,
429 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
432 "Adjusts video frames",
433 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)