mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-05 15:08:53 +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>
|
2006-03-02 Tim-Philipp Müller <tim at centricular dot net>
|
||||||
|
|
||||||
* ext/ogg/gstogmparse.c: (gst_ogm_parse_class_init),
|
* ext/ogg/gstogmparse.c: (gst_ogm_parse_class_init),
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
<!ENTITY GstCompiling SYSTEM "compiling.sgml">
|
<!ENTITY GstCompiling SYSTEM "compiling.sgml">
|
||||||
<!ENTITY GstAudio SYSTEM "xml/gstaudio.xml">
|
<!ENTITY GstAudio SYSTEM "xml/gstaudio.xml">
|
||||||
<!ENTITY GstAudioMixerUtils SYSTEM "xml/gstaudiomixerutils.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 GstCddaBaseSrc SYSTEM "xml/gstcddabasesrc.xml">
|
||||||
<!ENTITY GstVideoSink SYSTEM "xml/gstvideosink.xml">
|
<!ENTITY GstVideoSink SYSTEM "xml/gstvideosink.xml">
|
||||||
<!ENTITY GstVideoFilter SYSTEM "xml/gstvideofilter.xml">
|
<!ENTITY GstVideoFilter SYSTEM "xml/gstvideofilter.xml">
|
||||||
|
@ -43,6 +45,8 @@ This library should be linked to by getting cflags and libs from
|
||||||
</para>
|
</para>
|
||||||
&GstAudio;
|
&GstAudio;
|
||||||
&GstAudioMixerUtils;
|
&GstAudioMixerUtils;
|
||||||
|
&GstBaseAudioSink;
|
||||||
|
&GstAudioSink;
|
||||||
&GstRingBuffer;
|
&GstRingBuffer;
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,32 @@ GstAudioMixerFilterFunc
|
||||||
gst_audio_default_registry_mixer_filter
|
gst_audio_default_registry_mixer_filter
|
||||||
</SECTION>
|
</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>
|
<SECTION>
|
||||||
<FILE>gstcddabasesrc</FILE>
|
<FILE>gstcddabasesrc</FILE>
|
||||||
<INCLUDE>gst/cdda/gstcddabasesrc.h</INCLUDE>
|
<INCLUDE>gst/cdda/gstcddabasesrc.h</INCLUDE>
|
||||||
|
@ -68,6 +94,7 @@ gst_mixer_options_get_values
|
||||||
<FILE>gstringbuffer</FILE>
|
<FILE>gstringbuffer</FILE>
|
||||||
<INCLUDE>gst/audio/gstringbuffer.h</INCLUDE>
|
<INCLUDE>gst/audio/gstringbuffer.h</INCLUDE>
|
||||||
GstRingBuffer
|
GstRingBuffer
|
||||||
|
GstRingBufferSpec
|
||||||
GstRingBufferClass
|
GstRingBufferClass
|
||||||
|
|
||||||
gst_ring_buffer_set_callback
|
gst_ring_buffer_set_callback
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
#include <gst/interfaces/colorbalance.h>
|
#include <gst/interfaces/colorbalance.h>
|
||||||
#include <gst/audio/gstringbuffer.h>
|
|
||||||
|
|
||||||
gst_ring_buffer_get_type
|
|
||||||
|
|
||||||
gst_color_balance_get_type
|
gst_color_balance_get_type
|
||||||
gst_color_balance_channel_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>
|
#include <gst/cdda/gstcddabasesrc.h>
|
||||||
gst_cdda_base_src_get_type
|
gst_cdda_base_src_get_type
|
||||||
|
|
|
@ -93,6 +93,7 @@ EXTRA_HFILES = \
|
||||||
$(top_srcdir)/gst/ffmpegcolorspace/gstffmpegcolorspace.h \
|
$(top_srcdir)/gst/ffmpegcolorspace/gstffmpegcolorspace.h \
|
||||||
$(top_srcdir)/gst/tcp/gstmultifdsink.h \
|
$(top_srcdir)/gst/tcp/gstmultifdsink.h \
|
||||||
$(top_srcdir)/gst/tcp/gsttcpserversink.h \
|
$(top_srcdir)/gst/tcp/gsttcpserversink.h \
|
||||||
|
$(top_srcdir)/gst/videorate/gstvideorate.h \
|
||||||
$(top_srcdir)/gst/videotestsrc/gstvideotestsrc.h \
|
$(top_srcdir)/gst/videotestsrc/gstvideotestsrc.h \
|
||||||
$(top_srcdir)/gst/volume/gstvolume.h \
|
$(top_srcdir)/gst/volume/gstvolume.h \
|
||||||
$(top_srcdir)/sys/ximage/ximagesink.h \
|
$(top_srcdir)/sys/ximage/ximagesink.h \
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<xi:include href="xml/element-textoverlay.xml" />
|
<xi:include href="xml/element-textoverlay.xml" />
|
||||||
<xi:include href="xml/element-textrender.xml" />
|
<xi:include href="xml/element-textrender.xml" />
|
||||||
<xi:include href="xml/element-timeoverlay.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-videotestsrc.xml" />
|
||||||
<xi:include href="xml/element-volume.xml" />
|
<xi:include href="xml/element-volume.xml" />
|
||||||
<xi:include href="xml/element-vorbisdec.xml" />
|
<xi:include href="xml/element-vorbisdec.xml" />
|
||||||
|
|
|
@ -249,6 +249,19 @@ GstTimeOverlayClass
|
||||||
gst_time_overlay_get_type
|
gst_time_overlay_get_type
|
||||||
</SECTION>
|
</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>
|
<SECTION>
|
||||||
<FILE>element-videotestsrc</FILE>
|
<FILE>element-videotestsrc</FILE>
|
||||||
<TITLE>videotestsrc</TITLE>
|
<TITLE>videotestsrc</TITLE>
|
||||||
|
|
|
@ -21,11 +21,23 @@
|
||||||
/**
|
/**
|
||||||
* SECTION:gstringbuffer
|
* SECTION:gstringbuffer
|
||||||
* @short_description: Base class for audio ringbuffer implementations
|
* @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
|
* This object is the base class for audio ringbuffers used by the base
|
||||||
* audio source and sink classes.
|
* 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>
|
#include <string.h>
|
||||||
|
@ -1121,7 +1133,7 @@ flushing:
|
||||||
* @buf. The first sample should be written at position @sample in
|
* @buf. The first sample should be written at position @sample in
|
||||||
* the ringbuffer.
|
* 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.
|
* although it is recommended for optimal performance.
|
||||||
*
|
*
|
||||||
* Returns: The number of samples written to the ringbuffer or -1 on
|
* 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
|
* @len: the number of bytes to read
|
||||||
*
|
*
|
||||||
* Returns a pointer to memory where the data from segment @segment
|
* 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.
|
* Returns: FALSE if the buffer is not started.
|
||||||
*
|
*
|
||||||
|
@ -1349,11 +1361,12 @@ gst_ring_buffer_prepare_read (GstRingBuffer * buf, gint * segment,
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
gint segdone;
|
gint segdone;
|
||||||
|
|
||||||
|
g_return_val_if_fail (buf != NULL, FALSE);
|
||||||
|
|
||||||
/* buffer must be started */
|
/* buffer must be started */
|
||||||
if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED)
|
if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
g_return_val_if_fail (buf != NULL, FALSE);
|
|
||||||
g_return_val_if_fail (buf->data != NULL, FALSE);
|
g_return_val_if_fail (buf->data != NULL, FALSE);
|
||||||
g_return_val_if_fail (segment != NULL, FALSE);
|
g_return_val_if_fail (segment != NULL, FALSE);
|
||||||
g_return_val_if_fail (readptr != 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))
|
if (G_UNLIKELY (buf->data == NULL))
|
||||||
return;
|
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;
|
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_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)))
|
#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 {
|
struct _GstRingBuffer {
|
||||||
GstObject object;
|
GstObject object;
|
||||||
|
|
||||||
|
@ -209,14 +226,14 @@ struct _GstRingBuffer {
|
||||||
GstBuffer *data;
|
GstBuffer *data;
|
||||||
GstRingBufferSpec spec;
|
GstRingBufferSpec spec;
|
||||||
GstRingBufferSegState *segstate;
|
GstRingBufferSegState *segstate;
|
||||||
gint samples_per_seg; /* number of samples per segment */
|
gint samples_per_seg;
|
||||||
guint8 *empty_seg;
|
guint8 *empty_seg;
|
||||||
|
|
||||||
/*< public >*/ /* ATOMIC */
|
/*< public >*/ /* ATOMIC */
|
||||||
gint state; /* state of the buffer */
|
gint state;
|
||||||
gint segdone; /* number of segments processed since last start */
|
gint segdone;
|
||||||
gint segbase; /* segment corresponding to segment 0 */
|
gint segbase;
|
||||||
gint waiting; /* when waiting for a segment to be freed */
|
gint waiting;
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
GstRingBufferCallback callback;
|
GstRingBufferCallback callback;
|
||||||
|
@ -232,26 +249,34 @@ struct _GstRingBuffer {
|
||||||
} abidata;
|
} 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 {
|
struct _GstRingBufferClass {
|
||||||
GstObjectClass parent_class;
|
GstObjectClass parent_class;
|
||||||
|
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
/* just open the device, don't set any params or allocate anything */
|
|
||||||
gboolean (*open_device) (GstRingBuffer *buf);
|
gboolean (*open_device) (GstRingBuffer *buf);
|
||||||
/* allocate the resources for the ringbuffer using the given specs */
|
|
||||||
gboolean (*acquire) (GstRingBuffer *buf, GstRingBufferSpec *spec);
|
gboolean (*acquire) (GstRingBuffer *buf, GstRingBufferSpec *spec);
|
||||||
/* free resources of the ringbuffer */
|
|
||||||
gboolean (*release) (GstRingBuffer *buf);
|
gboolean (*release) (GstRingBuffer *buf);
|
||||||
/* close the device */
|
|
||||||
gboolean (*close_device) (GstRingBuffer *buf);
|
gboolean (*close_device) (GstRingBuffer *buf);
|
||||||
|
|
||||||
/* playback control */
|
|
||||||
gboolean (*start) (GstRingBuffer *buf);
|
gboolean (*start) (GstRingBuffer *buf);
|
||||||
gboolean (*pause) (GstRingBuffer *buf);
|
gboolean (*pause) (GstRingBuffer *buf);
|
||||||
gboolean (*resume) (GstRingBuffer *buf);
|
gboolean (*resume) (GstRingBuffer *buf);
|
||||||
gboolean (*stop) (GstRingBuffer *buf);
|
gboolean (*stop) (GstRingBuffer *buf);
|
||||||
|
|
||||||
/* number of samples queued in device */
|
|
||||||
guint (*delay) (GstRingBuffer *buf);
|
guint (*delay) (GstRingBuffer *buf);
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
|
|
|
@ -17,57 +17,56 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* 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
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include "gstvideorate.h"
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (video_rate_debug);
|
GST_DEBUG_CATEGORY (video_rate_debug);
|
||||||
#define GST_CAT_DEFAULT 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 */
|
/* elementfactory information */
|
||||||
static GstElementDetails video_rate_details =
|
static GstElementDetails video_rate_details =
|
||||||
GST_ELEMENT_DETAILS ("Video rate adjuster",
|
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_base_init (gpointer g_class);
|
||||||
static void gst_video_rate_class_init (GstVideoRateClass * klass);
|
static void gst_video_rate_class_init (GstVideoRateClass * klass);
|
||||||
static void gst_video_rate_init (GstVideoRate * videorate);
|
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 gboolean gst_video_rate_event (GstPad * pad, GstEvent * event);
|
||||||
static GstFlowReturn gst_video_rate_chain (GstPad * pad, GstBuffer * buffer);
|
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));
|
DEFAULT_SILENT, G_PARAM_READWRITE));
|
||||||
g_object_class_install_property (object_class, ARG_NEW_PREF,
|
g_object_class_install_property (object_class, ARG_NEW_PREF,
|
||||||
g_param_spec_double ("new_pref", "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));
|
0.0, 1.0, DEFAULT_NEW_PREF, G_PARAM_READWRITE));
|
||||||
|
|
||||||
element_class->change_state = gst_video_rate_change_state;
|
element_class->change_state = gst_video_rate_change_state;
|
||||||
|
@ -264,12 +266,12 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
GstPad *otherpad, *opeer;
|
GstPad *otherpad, *opeer;
|
||||||
gint rate_numerator, rate_denominator;
|
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);
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
if (!gst_structure_get_fraction (structure, "framerate",
|
if (!gst_structure_get_fraction (structure, "framerate",
|
||||||
&rate_numerator, &rate_denominator))
|
&rate_numerator, &rate_denominator))
|
||||||
goto done;
|
goto no_framerate;
|
||||||
|
|
||||||
if (pad == videorate->srcpad) {
|
if (pad == videorate->srcpad) {
|
||||||
videorate->to_rate_numerator = rate_numerator;
|
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 */
|
/* see how we can transform the input caps */
|
||||||
if (!gst_video_rate_transformcaps (pad, caps, otherpad, &transform))
|
if (!gst_video_rate_transformcaps (pad, caps, otherpad, &transform))
|
||||||
goto done;
|
goto no_transform;
|
||||||
|
|
||||||
/* see what the peer can do */
|
/* see what the peer can do */
|
||||||
peercaps = gst_pad_get_caps (opeer);
|
peercaps = gst_pad_get_caps (opeer);
|
||||||
|
@ -337,16 +339,26 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
gst_object_unref (opeer);
|
gst_object_unref (opeer);
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
gst_object_unref (videorate);
|
||||||
return ret;
|
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
|
static void
|
||||||
gst_video_rate_blank_data (GstVideoRate * videorate)
|
gst_video_rate_reset (GstVideoRate * videorate)
|
||||||
{
|
{
|
||||||
GST_DEBUG ("resetting data");
|
GST_DEBUG ("resetting data");
|
||||||
if (videorate->prevbuf)
|
|
||||||
gst_buffer_unref (videorate->prevbuf);
|
|
||||||
videorate->prevbuf = NULL;
|
|
||||||
|
|
||||||
videorate->from_rate_numerator = 0;
|
videorate->from_rate_numerator = 0;
|
||||||
videorate->from_rate_denominator = 0;
|
videorate->from_rate_denominator = 0;
|
||||||
|
@ -357,11 +369,9 @@ gst_video_rate_blank_data (GstVideoRate * videorate)
|
||||||
videorate->drop = 0;
|
videorate->drop = 0;
|
||||||
videorate->dup = 0;
|
videorate->dup = 0;
|
||||||
videorate->next_ts = G_GINT64_CONSTANT (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;
|
gst_segment_init (&videorate->segment, GST_FORMAT_TIME);
|
||||||
videorate->segment_stop = 0;
|
|
||||||
videorate->segment_accum = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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_getcaps_function (videorate->srcpad, gst_video_rate_getcaps);
|
||||||
gst_pad_set_setcaps_function (videorate->srcpad, gst_video_rate_setcaps);
|
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->silent = DEFAULT_SILENT;
|
||||||
videorate->new_pref = DEFAULT_NEW_PREF;
|
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
|
static GstFlowReturn
|
||||||
gst_video_rate_event (GstPad * pad, GstEvent * event)
|
gst_video_rate_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstVideoRate *videorate;
|
GstVideoRate *videorate;
|
||||||
|
|
||||||
videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
|
videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_NEWSEGMENT:
|
case GST_EVENT_NEWSEGMENT:
|
||||||
{
|
{
|
||||||
gint64 start, stop, base;
|
gint64 start, stop, time;
|
||||||
gdouble rate;
|
gdouble rate;
|
||||||
gboolean update;
|
gboolean update;
|
||||||
GstFormat format;
|
GstFormat format;
|
||||||
|
|
||||||
gst_event_parse_new_segment (event, &update, &rate, &format, &start,
|
gst_event_parse_new_segment (event, &update, &rate, &format, &start,
|
||||||
&stop, &base);
|
&stop, &time);
|
||||||
|
|
||||||
if (format != GST_FORMAT_TIME) {
|
if (format != videorate->segment.format)
|
||||||
GST_WARNING ("Got discont but doesn't have GST_FORMAT_TIME value");
|
goto format_error;
|
||||||
} 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* 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;
|
break;
|
||||||
}
|
}
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
/* flush last queued frame */
|
||||||
|
gst_video_rate_flush_prev (videorate);
|
||||||
|
break;
|
||||||
case GST_EVENT_FLUSH_STOP:
|
case GST_EVENT_FLUSH_STOP:
|
||||||
{
|
/* also resets the segment */
|
||||||
gst_video_rate_blank_data (videorate);
|
gst_video_rate_reset (videorate);
|
||||||
}
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
gst_object_unref (videorate);
|
||||||
|
|
||||||
return gst_pad_event_default (pad, event);
|
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
|
static GstFlowReturn
|
||||||
|
@ -440,31 +518,28 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstVideoRate *videorate;
|
GstVideoRate *videorate;
|
||||||
GstFlowReturn res = GST_FLOW_OK;
|
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 ||
|
/* make sure the denominators have to be != 0 */
|
||||||
videorate->from_rate_denominator == 0 ||
|
if (videorate->from_rate_denominator == 0 ||
|
||||||
videorate->to_rate_denominator == 0 || videorate->to_rate_numerator == 0)
|
videorate->to_rate_denominator == 0)
|
||||||
return GST_FLOW_NOT_NEGOTIATED;
|
goto not_negotiated;
|
||||||
|
|
||||||
|
intime = gst_segment_to_running_time (&videorate->segment,
|
||||||
|
GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer));
|
||||||
|
|
||||||
/* pull in 2 buffers */
|
/* pull in 2 buffers */
|
||||||
if (videorate->prevbuf == NULL) {
|
if (videorate->prevbuf == NULL) {
|
||||||
/* We're sure it's a GstBuffer here */
|
gst_video_rate_swap_prev (videorate, buffer, intime);
|
||||||
videorate->prevbuf = buffer;
|
|
||||||
videorate->prev_ts =
|
|
||||||
GST_BUFFER_TIMESTAMP (buffer) - videorate->segment_start +
|
|
||||||
videorate->segment_accum;
|
|
||||||
videorate->next_ts = 0;
|
videorate->next_ts = 0;
|
||||||
} else {
|
} else {
|
||||||
GstClockTime prevtime, intime;
|
GstClockTime prevtime;
|
||||||
gint count = 0;
|
gint count = 0;
|
||||||
gint64 diff1, diff2;
|
gint64 diff1, diff2;
|
||||||
|
|
||||||
prevtime = videorate->prev_ts;
|
prevtime = videorate->prev_ts;
|
||||||
intime =
|
|
||||||
GST_BUFFER_TIMESTAMP (buffer) - videorate->segment_start +
|
|
||||||
videorate->segment_accum;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (videorate,
|
GST_LOG_OBJECT (videorate,
|
||||||
"BEGINNING prev buf %" GST_TIME_FORMAT " new buf %" GST_TIME_FORMAT
|
"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 */
|
/* output first one when its the best */
|
||||||
if (diff1 < diff2) {
|
if (diff1 < diff2) {
|
||||||
GstBuffer *outbuf;
|
|
||||||
GstClockTime push_ts;
|
|
||||||
|
|
||||||
count++;
|
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,
|
/* on error the _flush function posted a warning already */
|
||||||
"old is best, dup, pushing buffer outgoing ts %" GST_TIME_FORMAT,
|
if ((res = gst_video_rate_flush_prev (videorate)) != GST_FLOW_OK)
|
||||||
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;
|
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 */
|
/* 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 */
|
/* if we didn't output the first buffer, we have a drop */
|
||||||
else if (count == 0) {
|
else if (count == 0) {
|
||||||
videorate->drop++;
|
videorate->drop++;
|
||||||
|
|
||||||
if (!videorate->silent)
|
if (!videorate->silent)
|
||||||
g_object_notify (G_OBJECT (videorate), "drop");
|
g_object_notify (G_OBJECT (videorate), "drop");
|
||||||
|
|
||||||
GST_LOG_OBJECT (videorate,
|
GST_LOG_OBJECT (videorate,
|
||||||
"new is best, old never used, drop, outgoing ts %"
|
"new is best, old never used, drop, outgoing ts %"
|
||||||
GST_TIME_FORMAT, GST_TIME_ARGS (videorate->next_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);
|
videorate->in, videorate->out, videorate->drop, videorate->dup);
|
||||||
|
|
||||||
/* swap in new one when it's the best */
|
/* swap in new one when it's the best */
|
||||||
gst_buffer_unref (videorate->prevbuf);
|
gst_video_rate_swap_prev (videorate, buffer, intime);
|
||||||
videorate->prevbuf = buffer;
|
|
||||||
videorate->prev_ts =
|
|
||||||
GST_BUFFER_TIMESTAMP (buffer) - videorate->segment_start +
|
|
||||||
videorate->segment_accum;
|
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
gst_object_unref (videorate);
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
not_negotiated:
|
||||||
|
{
|
||||||
|
GST_WARNING_OBJECT (videorate, "no framerate negotiated");
|
||||||
|
res = GST_FLOW_NOT_NEGOTIATED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -632,7 +684,7 @@ gst_video_rate_change_state (GstElement * element, GstStateChange transition)
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
gst_video_rate_blank_data (videorate);
|
gst_video_rate_reset (videorate);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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