mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-26 17:18:15 +00:00
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:
parent
be085f13a8
commit
1e9f5c43ad
11 changed files with 393 additions and 150 deletions
26
ChangeLog
26
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),
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 >*/
|
||||
|
|
|
@ -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;
|
||||
|
|
74
gst/videorate/gstvideorate.h
Normal file
74
gst/videorate/gstvideorate.h
Normal 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__ */
|
Loading…
Reference in a new issue