docs/: Added some more docs to libs and plugins.

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.
This commit is contained in:
Wim Taymans 2006-03-02 16:47:34 +00:00
parent be085f13a8
commit 1e9f5c43ad
11 changed files with 393 additions and 150 deletions

View file

@ -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),

View 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>

View file

@ -16,6 +16,32 @@ GstAudioMixerFilterFunc
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>
@ -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

View file

@ -1,12 +1,17 @@
#include <gst/gst.h>
#include <gst/interfaces/colorbalance.h>
#include <gst/audio/gstringbuffer.h>
gst_ring_buffer_get_type
gst_color_balance_get_type
gst_color_balance_channel_get_type
#include <gst/audio/gstringbuffer.h>
gst_ring_buffer_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

View 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 \

View 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" />

View file

@ -249,6 +249,19 @@ GstTimeOverlayClass
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>

View file

@ -21,11 +21,23 @@
/**
* 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.
* </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 2005-11-24 (0.9.6)
* 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;

View 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 >*/

View file

@ -17,57 +17,56 @@
* 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));
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;
/* make sure the denominators have to be != 0 */
if (videorate->from_rate_denominator == 0 ||
videorate->to_rate_denominator == 0)
goto 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);
/* on error the _flush function posted a warning already */
if ((res = gst_video_rate_flush_prev (videorate)) != GST_FLOW_OK)
goto done;
}
GST_LOG_OBJECT (videorate,
"old is best, dup, pushed buffer outgoing ts %" GST_TIME_FORMAT,
GST_TIME_ARGS (push_ts));
}
/* 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;

View file

@ -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__ */