docs/: Added some more docs to libs and plugins.
authorWim Taymans <wim.taymans@gmail.com>
Thu, 2 Mar 2006 16:47:34 +0000 (16:47 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Thu, 2 Mar 2006 16:47:34 +0000 (16:47 +0000)
Original commit message from CVS:
* docs/libs/gst-plugins-base-libs-docs.sgml:
* docs/libs/gst-plugins-base-libs-sections.txt:
* docs/libs/gst-plugins-base-libs.types:
* docs/plugins/Makefile.am:
* docs/plugins/gst-plugins-base-plugins-docs.sgml:
* docs/plugins/gst-plugins-base-plugins-sections.txt:
Added some more docs to libs and plugins.
* gst-libs/gst/audio/gstringbuffer.c:
(gst_ring_buffer_prepare_read), (gst_ring_buffer_clear):
* gst-libs/gst/audio/gstringbuffer.h:
Document ringbuffer some more.
* gst/videorate/gstvideorate.c: (gst_video_rate_class_init),
(gst_video_rate_setcaps), (gst_video_rate_reset),
(gst_video_rate_init), (gst_video_rate_flush_prev),
(gst_video_rate_swap_prev), (gst_video_rate_event),
(gst_video_rate_chain), (gst_video_rate_change_state):
* gst/videorate/gstvideorate.h:
Fix videorate to use segments.
Make it work with 0/1 framerates (closes #331903)
Handle EOS correctly.
Added docs.

ChangeLog
docs/libs/gst-plugins-base-libs-docs.sgml
docs/libs/gst-plugins-base-libs-sections.txt
docs/libs/gst-plugins-base-libs.types
docs/plugins/Makefile.am
docs/plugins/gst-plugins-base-plugins-docs.sgml
docs/plugins/gst-plugins-base-plugins-sections.txt
gst-libs/gst/audio/gstringbuffer.c
gst-libs/gst/audio/gstringbuffer.h
gst/videorate/gstvideorate.c
gst/videorate/gstvideorate.h [new file with mode: 0644]

index c2472b4..fcd8125 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2006-03-02  Wim Taymans  <wim@fluendo.com>
+
+       * docs/libs/gst-plugins-base-libs-docs.sgml:
+       * docs/libs/gst-plugins-base-libs-sections.txt:
+       * docs/libs/gst-plugins-base-libs.types:
+       * docs/plugins/Makefile.am:
+       * docs/plugins/gst-plugins-base-plugins-docs.sgml:
+       * docs/plugins/gst-plugins-base-plugins-sections.txt:
+       Added some more docs to libs and plugins.
+
+       * gst-libs/gst/audio/gstringbuffer.c:
+       (gst_ring_buffer_prepare_read), (gst_ring_buffer_clear):
+       * gst-libs/gst/audio/gstringbuffer.h:
+       Document ringbuffer some more.
+
+       * gst/videorate/gstvideorate.c: (gst_video_rate_class_init),
+       (gst_video_rate_setcaps), (gst_video_rate_reset),
+       (gst_video_rate_init), (gst_video_rate_flush_prev),
+       (gst_video_rate_swap_prev), (gst_video_rate_event),
+       (gst_video_rate_chain), (gst_video_rate_change_state):
+       * gst/videorate/gstvideorate.h:
+       Fix videorate to use segments.
+       Make it work with 0/1 framerates (closes #331903)
+       Handle EOS correctly.
+       Added docs.
+
 2006-03-02  Tim-Philipp Müller  <tim at centricular dot net>
 
        * ext/ogg/gstogmparse.c: (gst_ogm_parse_class_init),
index 95587c1..2ea539b 100644 (file)
@@ -7,6 +7,8 @@
 <!ENTITY GstCompiling SYSTEM "compiling.sgml">
 <!ENTITY GstAudio SYSTEM "xml/gstaudio.xml">
 <!ENTITY GstAudioMixerUtils SYSTEM "xml/gstaudiomixerutils.xml">
+<!ENTITY GstAudioSink SYSTEM "xml/gstaudiosink.xml">
+<!ENTITY GstBaseAudioSink SYSTEM "xml/gstbaseaudiosink.xml">
 <!ENTITY GstCddaBaseSrc SYSTEM "xml/gstcddabasesrc.xml">
 <!ENTITY GstVideoSink SYSTEM "xml/gstvideosink.xml">
 <!ENTITY GstVideoFilter SYSTEM "xml/gstvideofilter.xml">
@@ -43,6 +45,8 @@ This library should be linked to by getting cflags and libs from
     </para>
     &GstAudio;
     &GstAudioMixerUtils;
+    &GstBaseAudioSink;
+    &GstAudioSink;
     &GstRingBuffer;
   </chapter>
 
index 6cb3cce..e3f7c5e 100644 (file)
@@ -17,6 +17,32 @@ gst_audio_default_registry_mixer_filter
 </SECTION>
 
 <SECTION>
+<FILE>gstaudiosink</FILE>
+<INCLUDE>gst/audio/gstaudiosink.h</INCLUDE>
+GstAudioSink
+GstAudioSinkClass
+</SECTION>
+
+<SECTION>
+<FILE>gstbaseaudiosink</FILE>
+<INCLUDE>gst/audio/gstbaseaudiosink.h</INCLUDE>
+GstBaseAudioSink
+GstBaseAudioSinkClass
+GST_BASE_AUDIO_SINK_CLOCK
+GST_BASE_AUDIO_SINK_PAD
+gst_base_audio_sink_create_ringbuffer
+<SUBSECTION Standard>
+GST_BASE_AUDIO_SINK
+GST_IS_BASE_AUDIO_SINK
+GST_TYPE_BASE_AUDIO_SINK
+gst_base_audio_sink_get_type
+GST_BASE_AUDIO_SINK_CLASS
+GST_IS_BASE_AUDIO_SINK_CLASS
+GST_BASE_AUDIO_SINK_GET_CLASS
+</SECTION>
+
+
+<SECTION>
 <FILE>gstcddabasesrc</FILE>
 <INCLUDE>gst/cdda/gstcddabasesrc.h</INCLUDE>
 GstCddaBaseSrc
@@ -68,6 +94,7 @@ gst_mixer_options_get_values
 <FILE>gstringbuffer</FILE>
 <INCLUDE>gst/audio/gstringbuffer.h</INCLUDE>
 GstRingBuffer
+GstRingBufferSpec
 GstRingBufferClass
 
 gst_ring_buffer_set_callback
index a04977d..5b05c2f 100644 (file)
@@ -1,12 +1,17 @@
 #include <gst/gst.h>
 
 #include <gst/interfaces/colorbalance.h>
-#include <gst/audio/gstringbuffer.h>
+gst_color_balance_get_type
+gst_color_balance_channel_get_type
 
+#include <gst/audio/gstringbuffer.h>
 gst_ring_buffer_get_type
 
-gst_color_balance_get_type
-gst_color_balance_channel_get_type
+#include <gst/audio/gstaudiosink.h>
+gst_audio_sink_get_type
+
+#include <gst/audio/gstbaseaudiosink.h>
+gst_base_audio_sink_get_type
 
 #include <gst/cdda/gstcddabasesrc.h>
 gst_cdda_base_src_get_type
index 2de5280..bb4aac2 100644 (file)
@@ -93,6 +93,7 @@ EXTRA_HFILES = \
        $(top_srcdir)/gst/ffmpegcolorspace/gstffmpegcolorspace.h \
        $(top_srcdir)/gst/tcp/gstmultifdsink.h \
        $(top_srcdir)/gst/tcp/gsttcpserversink.h \
+       $(top_srcdir)/gst/videorate/gstvideorate.h \
        $(top_srcdir)/gst/videotestsrc/gstvideotestsrc.h \
        $(top_srcdir)/gst/volume/gstvolume.h \
        $(top_srcdir)/sys/ximage/ximagesink.h \
index 88bf4ff..2258386 100644 (file)
@@ -28,6 +28,7 @@
     <xi:include href="xml/element-textoverlay.xml" />
     <xi:include href="xml/element-textrender.xml" />
     <xi:include href="xml/element-timeoverlay.xml" />
+    <xi:include href="xml/element-videorate.xml" />
     <xi:include href="xml/element-videotestsrc.xml" />
     <xi:include href="xml/element-volume.xml" />
     <xi:include href="xml/element-vorbisdec.xml" />
index 0e382b9..7ddc98b 100644 (file)
@@ -250,6 +250,19 @@ gst_time_overlay_get_type
 </SECTION>
 
 <SECTION>
+<FILE>element-videorate</FILE>
+<TITLE>videorate</TITLE>
+GstVideoRate
+<SUBSECTION Standard>
+GstVideoRateClass
+GST_VIDEO_RATE
+GST_IS_VIDEO_RATE
+GST_TYPE_VIDEO_RATE
+GST_VIDEO_RATE_CLASS
+GST_IS_VIDEO_RATE_CLASS
+</SECTION>
+
+<SECTION>
 <FILE>element-videotestsrc</FILE>
 <TITLE>videotestsrc</TITLE>
 GstVideoTestSrc
index 27ef912..5e71269 100644 (file)
 /**
  * SECTION:gstringbuffer
  * @short_description: Base class for audio ringbuffer implementations
+ * @see_also: gstbaseaudiosink
  *
+ * <refsect2>
+ * <para>
  * This object is the base class for audio ringbuffers used by the base
  * audio source and sink classes.
- *
- * Last reviewed on 2005-11-24 (0.9.6)
+ * </para>
+ * <para>
+ * The ringbuffer abstracts a circular buffer of data. One reader and
+ * one writer can operate on the data from different threads in a lockfree 
+ * manner. The base class is sufficiently flexible to be used as an
+ * abstraction for DMA based ringbuffers as well as a pure software 
+ * implementations.
+ * </para>
+ * </refsect2>
+ *
+ * Last reviewed on 2006-02-02 (0.10.4)
  */
 
 #include <string.h>
@@ -1121,7 +1133,7 @@ flushing:
  * @buf. The first sample should be written at position @sample in
  * the ringbuffer.
  *
- * @len not needs to be a multiple of the segment size of the ringbuffer
+ * @len does not need to be a multiple of the segment size of the ringbuffer
  * although it is recommended for optimal performance.
  *
  * Returns: The number of samples written to the ringbuffer or -1 on
@@ -1336,7 +1348,7 @@ not_started:
  * @len: the number of bytes to read
  *
  * Returns a pointer to memory where the data from segment @segment
- * can be found. This function is used by subclasses.
+ * can be found. This function is mostly used by subclasses.
  *
  * Returns: FALSE if the buffer is not started.
  *
@@ -1349,11 +1361,12 @@ gst_ring_buffer_prepare_read (GstRingBuffer * buf, gint * segment,
   guint8 *data;
   gint segdone;
 
+  g_return_val_if_fail (buf != NULL, FALSE);
+
   /* buffer must be started */
   if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED)
     return FALSE;
 
-  g_return_val_if_fail (buf != NULL, FALSE);
   g_return_val_if_fail (buf->data != NULL, FALSE);
   g_return_val_if_fail (segment != NULL, FALSE);
   g_return_val_if_fail (readptr != NULL, FALSE);
@@ -1429,7 +1442,9 @@ gst_ring_buffer_clear (GstRingBuffer * buf, gint segment)
   if (G_UNLIKELY (buf->data == NULL))
     return;
 
-  g_return_if_fail (buf->empty_seg != NULL);
+  /* no empty_seg means it's not opened */
+  if (G_UNLIKELY (buf->empty_seg == NULL))
+    return;
 
   segment %= buf->spec.segtotal;
 
index 912a254..b0040b5 100644 (file)
@@ -199,6 +199,23 @@ struct _GstRingBufferSpec
 #define GST_RING_BUFFER_SIGNAL(buf)   (g_cond_signal (GST_RING_BUFFER_GET_COND (buf)))
 #define GST_RING_BUFFER_BROADCAST(buf)(g_cond_broadcast (GST_RING_BUFFER_GET_COND (buf)))
 
+/**
+ * GstRingBuffer:
+ * @cond: used to signal start/stop/pause/resume actions
+ * @open: boolean indicating that the ringbuffer is open
+ * @acquired: boolean indicating that the ringbuffer is acquired
+ * @data: data in the ringbuffer
+ * @spec: format and layout of the ringbuffer data
+ * @segstate: status of each segment in the ringbuffer (unused)
+ * @samples_per_seg: number of samples in one segment
+ * @empty_seg: pointer to memory holding one segment of silence samples
+ * @state: state of the buffer
+ * @segdone: readpointer in the ringbuffer
+ * @segbase: segment corresponding to segment 0 (unused)
+ * @waiting: is a reader or writer waiting for a free segment
+ *
+ * The ringbuffer base class structure.
+ */
 struct _GstRingBuffer {
   GstObject              object;
 
@@ -209,14 +226,14 @@ struct _GstRingBuffer {
   GstBuffer             *data;
   GstRingBufferSpec      spec;
   GstRingBufferSegState *segstate;
-  gint                   samples_per_seg;     /* number of samples per segment */
+  gint                   samples_per_seg;
   guint8                *empty_seg;
 
   /*< public >*/ /* ATOMIC */
-  gint                   state;         /* state of the buffer */
-  gint                   segdone;       /* number of segments processed since last start */
-  gint                   segbase;       /* segment corresponding to segment 0 */
-  gint                   waiting;       /* when waiting for a segment to be freed */
+  gint                   state;
+  gint                   segdone;
+  gint                   segbase;
+  gint                   waiting;
 
   /*< private >*/
   GstRingBufferCallback  callback;
@@ -232,26 +249,34 @@ struct _GstRingBuffer {
   } abidata;
 };
 
+/**
+ * GstRingBufferClass:
+ * @open_device:  open the device, don't set any params or allocate anything
+ * @acquire: allocate the resources for the ringbuffer using the given spec
+ * @release: free resources of the ringbuffer
+ * @close_device: close the device
+ * @start: start processing of samples
+ * @pause: pause processing of samples
+ * @resume: resume processing of samples after pause
+ * @stop: stop processing of samples
+ * @delay: get number of samples queued in device
+ *
+ * The vmethods that subclasses can override to implement the ringbuffer.
+ */
 struct _GstRingBufferClass {
   GstObjectClass parent_class;
 
   /*< public >*/
-  /* just open the device, don't set any params or allocate anything */
   gboolean     (*open_device)  (GstRingBuffer *buf);
-  /* allocate the resources for the ringbuffer using the given specs */
   gboolean     (*acquire)      (GstRingBuffer *buf, GstRingBufferSpec *spec);
-  /* free resources of the ringbuffer */
   gboolean     (*release)      (GstRingBuffer *buf);
-  /* close the device */
   gboolean     (*close_device) (GstRingBuffer *buf);
 
-  /* playback control */
   gboolean     (*start)        (GstRingBuffer *buf);
   gboolean     (*pause)        (GstRingBuffer *buf);
   gboolean     (*resume)       (GstRingBuffer *buf);
   gboolean     (*stop)         (GstRingBuffer *buf);
 
-  /* number of samples queued in device */
   guint        (*delay)        (GstRingBuffer *buf);
 
   /*< private >*/
index b6ec284..ac1c132 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/**
+ * SECTION:element-videorate
+ * @short_description: adjusts the framerate of video
+ *
+ * <refsect2>
+ * <para>
+ * This element converts video from one framerate to another. This operation
+ * is performed by dropping and duplicating frames, no fance algorithm is
+ * used to interpolate frames (yet).
+ * </para>
+ * <para>
+ * By default the element will simply negotiate the same framerate on its source and
+ * sink pad and will adjust timestamps/insert/drop frames in case the input stream
+ * is not respecting that framerate.
+ * </para>
+ * <para>
+ * A conversion to another framerate can be forced by using filtered caps on the source
+ * pad.
+ * </para>
+ * <para>
+ * The properties "in", "out", "duplicate" and "drop" can be read to obtain 
+ * information about respectively received frame, outputed frame, duplicated frames
+ * and dropped frames.
+ * When the "silent" property is set to FALSE, a GObject property notification will
+ * be emited whenever one of the "duplicate" or "drop" values changed. This can 
+ * potentially cause performance degradation. Also note that property notification 
+ * will happen in the streaming thread so applications should be prepared for this.
+ * </para>
+ * <title>Example pipelines</title>
+ * <para>
+ * <programlisting>
+ * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videorate ! video/x-raw-yuv,framerate=15/1 ! xvimagesink
+ * </programlisting>
+ * Decode an Ogg/Theora and adjust the framerate to 15 fps. 
+ * To create the test Ogg/Theora file refer to the documentation of theoraenc.
+ * </para>
+ * </refsect2>
+ *
+ * Last reviewed on 2006-03-02 (0.10.4)
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include <gst/gst.h>
+#include "gstvideorate.h"
 
 GST_DEBUG_CATEGORY (video_rate_debug);
 #define GST_CAT_DEFAULT video_rate_debug
 
-#define GST_TYPE_VIDEO_RATE \
-  (gst_video_rate_get_type())
-#define GST_VIDEO_RATE(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_RATE,GstVideoRate))
-#define GST_VIDEO_RATE_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_RATE,GstVideoRate))
-#define GST_IS_VIDEO_RATE(obj) \
-  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_RATE))
-#define GST_IS_VIDEO_RATE_CLASS(obj) \
-  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_RATE))
-
-typedef struct _GstVideoRate GstVideoRate;
-typedef struct _GstVideoRateClass GstVideoRateClass;
-
-struct _GstVideoRate
-{
-  GstElement element;
-
-  GstPad *sinkpad, *srcpad;
-
-  /* video state */
-  gint from_rate_numerator, from_rate_denominator;
-  gint to_rate_numerator, to_rate_denominator;
-  guint64 next_ts;              /* Timestamp of next buffer to output */
-  GstBuffer *prevbuf;
-  guint64 prev_ts;              /* Previous buffer timestamp */
-  guint64 in, out, dup, drop;
-
-  /* segment handling */
-  gint64 segment_start;
-  gint64 segment_stop;
-  gint64 segment_accum;
-
-  gboolean silent;
-  gdouble new_pref;
-};
-
-struct _GstVideoRateClass
-{
-  GstElementClass parent_class;
-};
-
 /* elementfactory information */
 static GstElementDetails video_rate_details =
 GST_ELEMENT_DETAILS ("Video rate adjuster",
@@ -114,6 +113,9 @@ static GstStaticPadTemplate gst_video_rate_sink_template =
 static void gst_video_rate_base_init (gpointer g_class);
 static void gst_video_rate_class_init (GstVideoRateClass * klass);
 static void gst_video_rate_init (GstVideoRate * videorate);
+
+static void gst_video_rate_swap_prev (GstVideoRate * videorate,
+    GstBuffer * buffer, gint64 time);
 static gboolean gst_video_rate_event (GstPad * pad, GstEvent * event);
 static GstFlowReturn gst_video_rate_chain (GstPad * pad, GstBuffer * buffer);
 
@@ -195,7 +197,7 @@ gst_video_rate_class_init (GstVideoRateClass * klass)
           DEFAULT_SILENT, G_PARAM_READWRITE));
   g_object_class_install_property (object_class, ARG_NEW_PREF,
       g_param_spec_double ("new_pref", "New Pref",
-          "Value indicating how much to prefer new frames",
+          "Value indicating how much to prefer new frames (unused)",
           0.0, 1.0, DEFAULT_NEW_PREF, G_PARAM_READWRITE));
 
   element_class->change_state = gst_video_rate_change_state;
@@ -264,12 +266,12 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
   GstPad *otherpad, *opeer;
   gint rate_numerator, rate_denominator;
 
-  videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
+  videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad));
 
   structure = gst_caps_get_structure (caps, 0);
   if (!gst_structure_get_fraction (structure, "framerate",
           &rate_numerator, &rate_denominator))
-    goto done;
+    goto no_framerate;
 
   if (pad == videorate->srcpad) {
     videorate->to_rate_numerator = rate_numerator;
@@ -297,7 +299,7 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
 
       /* see how we can transform the input caps */
       if (!gst_video_rate_transformcaps (pad, caps, otherpad, &transform))
-        goto done;
+        goto no_transform;
 
       /* see what the peer can do */
       peercaps = gst_pad_get_caps (opeer);
@@ -337,16 +339,26 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
     gst_object_unref (opeer);
   }
 done:
+  gst_object_unref (videorate);
   return ret;
+
+no_framerate:
+  {
+    GST_DEBUG_OBJECT (videorate, "no framerate specified");
+    goto done;
+  }
+no_transform:
+  {
+    GST_DEBUG_OBJECT (videorate, "no framerate transform possible");
+    ret = FALSE;
+    goto done;
+  }
 }
 
 static void
-gst_video_rate_blank_data (GstVideoRate * videorate)
+gst_video_rate_reset (GstVideoRate * videorate)
 {
   GST_DEBUG ("resetting data");
-  if (videorate->prevbuf)
-    gst_buffer_unref (videorate->prevbuf);
-  videorate->prevbuf = NULL;
 
   videorate->from_rate_numerator = 0;
   videorate->from_rate_denominator = 0;
@@ -357,11 +369,9 @@ gst_video_rate_blank_data (GstVideoRate * videorate)
   videorate->drop = 0;
   videorate->dup = 0;
   videorate->next_ts = G_GINT64_CONSTANT (0);
-  videorate->prev_ts = G_GINT64_CONSTANT (0);
+  gst_video_rate_swap_prev (videorate, NULL, 0);
 
-  videorate->segment_start = 0;
-  videorate->segment_stop = 0;
-  videorate->segment_accum = 0;
+  gst_segment_init (&videorate->segment, GST_FORMAT_TIME);
 }
 
 static void
@@ -382,57 +392,125 @@ gst_video_rate_init (GstVideoRate * videorate)
   gst_pad_set_getcaps_function (videorate->srcpad, gst_video_rate_getcaps);
   gst_pad_set_setcaps_function (videorate->srcpad, gst_video_rate_setcaps);
 
-  gst_video_rate_blank_data (videorate);
+  gst_video_rate_reset (videorate);
   videorate->silent = DEFAULT_SILENT;
   videorate->new_pref = DEFAULT_NEW_PREF;
 }
 
+/* flush the oldest buffer */
+static GstFlowReturn
+gst_video_rate_flush_prev (GstVideoRate * videorate)
+{
+  GstFlowReturn res;
+  GstBuffer *outbuf;
+  GstClockTime push_ts;
+
+  /* make sure we can write to the metadata */
+  outbuf =
+      gst_buffer_create_sub (videorate->prevbuf, 0,
+      GST_BUFFER_SIZE (videorate->prevbuf));
+
+  /* this is the timestamp we put on the buffer */
+  push_ts = videorate->next_ts;
+  GST_BUFFER_TIMESTAMP (outbuf) = push_ts;
+
+  videorate->out++;
+  if (videorate->to_rate_numerator) {
+    videorate->next_ts =
+        gst_util_uint64_scale (videorate->out,
+        videorate->to_rate_denominator * GST_SECOND,
+        videorate->to_rate_numerator);
+    GST_BUFFER_DURATION (outbuf) =
+        videorate->next_ts - GST_BUFFER_TIMESTAMP (outbuf);
+  }
+  /* adapt for looping, bring back to time in current segment. */
+  GST_BUFFER_TIMESTAMP (outbuf) -= videorate->segment.accum;
+  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (videorate->srcpad));
+
+  GST_LOG_OBJECT (videorate,
+      "old is best, dup, pushing buffer outgoing ts %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (push_ts));
+
+  if ((res = gst_pad_push (videorate->srcpad, outbuf)) != GST_FLOW_OK)
+    goto push_error;
+
+  return res;
+
+  /* ERRORS */
+push_error:
+  {
+    GST_WARNING_OBJECT (videorate, "couldn't push buffer on srcpad, reason %s",
+        gst_flow_get_name (res));
+    return res;
+  }
+}
+
+static void
+gst_video_rate_swap_prev (GstVideoRate * videorate, GstBuffer * buffer,
+    gint64 time)
+{
+  if (videorate->prevbuf)
+    gst_buffer_unref (videorate->prevbuf);
+  videorate->prevbuf = buffer;
+  videorate->prev_ts = time;
+}
+
 static GstFlowReturn
 gst_video_rate_event (GstPad * pad, GstEvent * event)
 {
   GstVideoRate *videorate;
 
-  videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
+  videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad));
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_NEWSEGMENT:
     {
-      gint64 start, stop, base;
+      gint64 start, stop, time;
       gdouble rate;
       gboolean update;
       GstFormat format;
 
       gst_event_parse_new_segment (event, &update, &rate, &format, &start,
-          &stop, &base);
+          &stop, &time);
 
-      if (format != GST_FORMAT_TIME) {
-        GST_WARNING ("Got discont but doesn't have GST_FORMAT_TIME value");
-      } else {
-        /* 
-           We just want to update the accumulated stream_time.
-         */
-        videorate->segment_accum +=
-            videorate->segment_stop - videorate->segment_start;
-        videorate->segment_start = start;
-        videorate->segment_stop = stop;
-        GST_DEBUG_OBJECT (videorate, "Updated segment_accum:%" GST_TIME_FORMAT
-            " segment_start:%" GST_TIME_FORMAT " segment_stop:%"
-            GST_TIME_FORMAT, GST_TIME_ARGS (videorate->segment_accum),
-            GST_TIME_ARGS (videorate->segment_start),
-            GST_TIME_ARGS (videorate->segment_stop));
-      }
+      if (format != videorate->segment.format)
+        goto format_error;
 
+      /* We just want to update the accumulated stream_time  */
+      gst_segment_set_newsegment (&videorate->segment, update, rate,
+          format, start, stop, time);
+
+      GST_DEBUG_OBJECT (videorate, "Updated segment.accum:%" GST_TIME_FORMAT
+          " segment.start:%" GST_TIME_FORMAT " segment.stop:%"
+          GST_TIME_FORMAT, GST_TIME_ARGS (videorate->segment.accum),
+          GST_TIME_ARGS (videorate->segment.start),
+          GST_TIME_ARGS (videorate->segment.stop));
       break;
     }
+    case GST_EVENT_EOS:
+      /* flush last queued frame */
+      gst_video_rate_flush_prev (videorate);
+      break;
     case GST_EVENT_FLUSH_STOP:
-    {
-      gst_video_rate_blank_data (videorate);
-    }
+      /* also resets the segment */
+      gst_video_rate_reset (videorate);
+      break;
     default:
       break;
   }
 
+done:
+  gst_object_unref (videorate);
+
   return gst_pad_event_default (pad, event);
+
+  /* ERRORS */
+format_error:
+  {
+    GST_WARNING_OBJECT (videorate,
+        "Got segment but doesn't have GST_FORMAT_TIME value");
+    goto done;
+  }
 }
 
 static GstFlowReturn
@@ -440,31 +518,28 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
 {
   GstVideoRate *videorate;
   GstFlowReturn res = GST_FLOW_OK;
+  GstClockTime intime;
 
-  videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
+  videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad));
+
+  /* make sure the denominators have to be != 0 */
+  if (videorate->from_rate_denominator == 0 ||
+      videorate->to_rate_denominator == 0)
+    goto not_negotiated;
 
-  if (videorate->from_rate_numerator == 0 ||
-      videorate->from_rate_denominator == 0 ||
-      videorate->to_rate_denominator == 0 || videorate->to_rate_numerator == 0)
-    return GST_FLOW_NOT_NEGOTIATED;
+  intime = gst_segment_to_running_time (&videorate->segment,
+      GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer));
 
   /* pull in 2 buffers */
   if (videorate->prevbuf == NULL) {
-    /* We're sure it's a GstBuffer here */
-    videorate->prevbuf = buffer;
-    videorate->prev_ts =
-        GST_BUFFER_TIMESTAMP (buffer) - videorate->segment_start +
-        videorate->segment_accum;
+    gst_video_rate_swap_prev (videorate, buffer, intime);
     videorate->next_ts = 0;
   } else {
-    GstClockTime prevtime, intime;
+    GstClockTime prevtime;
     gint count = 0;
     gint64 diff1, diff2;
 
     prevtime = videorate->prev_ts;
-    intime =
-        GST_BUFFER_TIMESTAMP (buffer) - videorate->segment_start +
-        videorate->segment_accum;
 
     GST_LOG_OBJECT (videorate,
         "BEGINNING prev buf %" GST_TIME_FORMAT " new buf %" GST_TIME_FORMAT
@@ -492,40 +567,11 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
 
       /* output first one when its the best */
       if (diff1 < diff2) {
-        GstBuffer *outbuf;
-        GstClockTime push_ts;
-
         count++;
-        outbuf =
-            gst_buffer_create_sub (videorate->prevbuf, 0,
-            GST_BUFFER_SIZE (videorate->prevbuf));
-        GST_BUFFER_TIMESTAMP (outbuf) = videorate->next_ts;
-        push_ts = GST_BUFFER_TIMESTAMP (outbuf);
-        videorate->out++;
-        if (videorate->to_rate_numerator) {
-          videorate->next_ts =
-              gst_util_uint64_scale_int (videorate->out * GST_SECOND,
-              videorate->to_rate_denominator, videorate->to_rate_numerator);
-          GST_BUFFER_DURATION (outbuf) =
-              videorate->next_ts - GST_BUFFER_TIMESTAMP (outbuf);
-        }
-        /* adapt for looping */
-        GST_BUFFER_TIMESTAMP (outbuf) -= videorate->segment_accum;
-        gst_buffer_set_caps (outbuf, GST_PAD_CAPS (videorate->srcpad));
-
-        GST_LOG_OBJECT (videorate,
-            "old is best, dup, pushing buffer outgoing ts %" GST_TIME_FORMAT,
-            GST_TIME_ARGS (push_ts));
-
-        if ((res = gst_pad_push (videorate->srcpad, outbuf)) != GST_FLOW_OK) {
-          GST_WARNING_OBJECT (videorate, "couldn't push buffer on srcpad:%d",
-              res);
-          goto done;
-        }
 
-        GST_LOG_OBJECT (videorate,
-            "old is best, dup, pushed buffer outgoing ts %" GST_TIME_FORMAT,
-            GST_TIME_ARGS (push_ts));
+        /* on error the _flush function posted a warning already */
+        if ((res = gst_video_rate_flush_prev (videorate)) != GST_FLOW_OK)
+          goto done;
       }
       /* continue while the first one was the best */
     }
@@ -540,8 +586,10 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
     /* if we didn't output the first buffer, we have a drop */
     else if (count == 0) {
       videorate->drop++;
+
       if (!videorate->silent)
         g_object_notify (G_OBJECT (videorate), "drop");
+
       GST_LOG_OBJECT (videorate,
           "new is best, old never used, drop, outgoing ts %"
           GST_TIME_FORMAT, GST_TIME_ARGS (videorate->next_ts));
@@ -554,15 +602,19 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
         videorate->in, videorate->out, videorate->drop, videorate->dup);
 
     /* swap in new one when it's the best */
-    gst_buffer_unref (videorate->prevbuf);
-    videorate->prevbuf = buffer;
-    videorate->prev_ts =
-        GST_BUFFER_TIMESTAMP (buffer) - videorate->segment_start +
-        videorate->segment_accum;
+    gst_video_rate_swap_prev (videorate, buffer, intime);
   }
 done:
-
+  gst_object_unref (videorate);
   return res;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_WARNING_OBJECT (videorate, "no framerate negotiated");
+    res = GST_FLOW_NOT_NEGOTIATED;
+    goto done;
+  }
 }
 
 static void
@@ -632,7 +684,7 @@ gst_video_rate_change_state (GstElement * element, GstStateChange transition)
 
   switch (transition) {
     case GST_STATE_CHANGE_PAUSED_TO_READY:
-      gst_video_rate_blank_data (videorate);
+      gst_video_rate_reset (videorate);
       break;
     default:
       break;
diff --git a/gst/videorate/gstvideorate.h b/gst/videorate/gstvideorate.h
new file mode 100644 (file)
index 0000000..8780c11
--- /dev/null
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_VIDEO_RATE_H__
+#define __GST_VIDEO_RATE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VIDEO_RATE \
+  (gst_video_rate_get_type())
+#define GST_VIDEO_RATE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_RATE,GstVideoRate))
+#define GST_VIDEO_RATE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_RATE,GstVideoRate))
+#define GST_IS_VIDEO_RATE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_RATE))
+#define GST_IS_VIDEO_RATE_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_RATE))
+
+typedef struct _GstVideoRate GstVideoRate;
+typedef struct _GstVideoRateClass GstVideoRateClass;
+
+/**
+ * GstVideoRate:
+ *
+ * Opaque data structure.
+ */
+struct _GstVideoRate
+{
+  GstElement element;
+
+  GstPad *sinkpad, *srcpad;
+
+  /* video state */
+  gint from_rate_numerator, from_rate_denominator;
+  gint to_rate_numerator, to_rate_denominator;
+  guint64 next_ts;              /* Timestamp of next buffer to output */
+  GstBuffer *prevbuf;
+  guint64 prev_ts;              /* Previous buffer timestamp */
+  guint64 in, out, dup, drop;
+
+  /* segment handling */
+  GstSegment segment;
+
+  gboolean silent;
+  gdouble new_pref;
+};
+
+struct _GstVideoRateClass
+{
+  GstElementClass parent_class;
+};
+
+G_END_DECLS
+
+#endif /* __GST_VIDEO_RATE_H__ */