From: Wim Taymans Date: Thu, 2 Mar 2006 16:47:34 +0000 (+0000) Subject: docs/: Added some more docs to libs and plugins. X-Git-Tag: 1.19.3~511^2~12134 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1e9f5c43ad2dc64e79f692528794458f201f8a99;p=platform%2Fupstream%2Fgstreamer.git 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. --- diff --git a/ChangeLog b/ChangeLog index c2472b4..fcd8125 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2006-03-02 Wim Taymans + + * 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 * ext/ogg/gstogmparse.c: (gst_ogm_parse_class_init), diff --git a/docs/libs/gst-plugins-base-libs-docs.sgml b/docs/libs/gst-plugins-base-libs-docs.sgml index 95587c1..2ea539b 100644 --- a/docs/libs/gst-plugins-base-libs-docs.sgml +++ b/docs/libs/gst-plugins-base-libs-docs.sgml @@ -7,6 +7,8 @@ + + @@ -43,6 +45,8 @@ This library should be linked to by getting cflags and libs from &GstAudio; &GstAudioMixerUtils; + &GstBaseAudioSink; + &GstAudioSink; &GstRingBuffer; diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt index 6cb3cce..e3f7c5e 100644 --- a/docs/libs/gst-plugins-base-libs-sections.txt +++ b/docs/libs/gst-plugins-base-libs-sections.txt @@ -17,6 +17,32 @@ gst_audio_default_registry_mixer_filter
+gstaudiosink +gst/audio/gstaudiosink.h +GstAudioSink +GstAudioSinkClass +
+ +
+gstbaseaudiosink +gst/audio/gstbaseaudiosink.h +GstBaseAudioSink +GstBaseAudioSinkClass +GST_BASE_AUDIO_SINK_CLOCK +GST_BASE_AUDIO_SINK_PAD +gst_base_audio_sink_create_ringbuffer + +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 +
+ + +
gstcddabasesrc gst/cdda/gstcddabasesrc.h GstCddaBaseSrc @@ -68,6 +94,7 @@ gst_mixer_options_get_values gstringbuffer gst/audio/gstringbuffer.h GstRingBuffer +GstRingBufferSpec GstRingBufferClass gst_ring_buffer_set_callback diff --git a/docs/libs/gst-plugins-base-libs.types b/docs/libs/gst-plugins-base-libs.types index a04977d..5b05c2f 100644 --- a/docs/libs/gst-plugins-base-libs.types +++ b/docs/libs/gst-plugins-base-libs.types @@ -1,12 +1,17 @@ #include #include -#include +gst_color_balance_get_type +gst_color_balance_channel_get_type +#include gst_ring_buffer_get_type -gst_color_balance_get_type -gst_color_balance_channel_get_type +#include +gst_audio_sink_get_type + +#include +gst_base_audio_sink_get_type #include gst_cdda_base_src_get_type diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index 2de5280..bb4aac2 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -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 \ diff --git a/docs/plugins/gst-plugins-base-plugins-docs.sgml b/docs/plugins/gst-plugins-base-plugins-docs.sgml index 88bf4ff..2258386 100644 --- a/docs/plugins/gst-plugins-base-plugins-docs.sgml +++ b/docs/plugins/gst-plugins-base-plugins-docs.sgml @@ -28,6 +28,7 @@ + diff --git a/docs/plugins/gst-plugins-base-plugins-sections.txt b/docs/plugins/gst-plugins-base-plugins-sections.txt index 0e382b9..7ddc98b 100644 --- a/docs/plugins/gst-plugins-base-plugins-sections.txt +++ b/docs/plugins/gst-plugins-base-plugins-sections.txt @@ -250,6 +250,19 @@ gst_time_overlay_get_type
+element-videorate +videorate +GstVideoRate + +GstVideoRateClass +GST_VIDEO_RATE +GST_IS_VIDEO_RATE +GST_TYPE_VIDEO_RATE +GST_VIDEO_RATE_CLASS +GST_IS_VIDEO_RATE_CLASS +
+ +
element-videotestsrc videotestsrc GstVideoTestSrc diff --git a/gst-libs/gst/audio/gstringbuffer.c b/gst-libs/gst/audio/gstringbuffer.c index 27ef912..5e71269 100644 --- a/gst-libs/gst/audio/gstringbuffer.c +++ b/gst-libs/gst/audio/gstringbuffer.c @@ -21,11 +21,23 @@ /** * SECTION:gstringbuffer * @short_description: Base class for audio ringbuffer implementations + * @see_also: gstbaseaudiosink * + * + * * This object is the base class for audio ringbuffers used by the base * audio source and sink classes. - * - * Last reviewed on 2005-11-24 (0.9.6) + * + * + * 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. + * + * + * + * Last reviewed on 2006-02-02 (0.10.4) */ #include @@ -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; diff --git a/gst-libs/gst/audio/gstringbuffer.h b/gst-libs/gst/audio/gstringbuffer.h index 912a254..b0040b5 100644 --- a/gst-libs/gst/audio/gstringbuffer.h +++ b/gst-libs/gst/audio/gstringbuffer.h @@ -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 >*/ diff --git a/gst/videorate/gstvideorate.c b/gst/videorate/gstvideorate.c index b6ec284..ac1c132 100644 --- a/gst/videorate/gstvideorate.c +++ b/gst/videorate/gstvideorate.c @@ -17,57 +17,56 @@ * Boston, MA 02111-1307, USA. */ +/** + * SECTION:element-videorate + * @short_description: adjusts the framerate of video + * + * + * + * 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). + * + * + * 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. + * + * + * A conversion to another framerate can be forced by using filtered caps on the source + * pad. + * + * + * 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. + * + * Example pipelines + * + * + * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videorate ! video/x-raw-yuv,framerate=15/1 ! xvimagesink + * + * Decode an Ogg/Theora and adjust the framerate to 15 fps. + * To create the test Ogg/Theora file refer to the documentation of theoraenc. + * + * + * + * Last reviewed on 2006-03-02 (0.10.4) + */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include +#include "gstvideorate.h" GST_DEBUG_CATEGORY (video_rate_debug); #define GST_CAT_DEFAULT video_rate_debug -#define GST_TYPE_VIDEO_RATE \ - (gst_video_rate_get_type()) -#define GST_VIDEO_RATE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_RATE,GstVideoRate)) -#define GST_VIDEO_RATE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_RATE,GstVideoRate)) -#define GST_IS_VIDEO_RATE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_RATE)) -#define GST_IS_VIDEO_RATE_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_RATE)) - -typedef struct _GstVideoRate GstVideoRate; -typedef struct _GstVideoRateClass GstVideoRateClass; - -struct _GstVideoRate -{ - GstElement element; - - GstPad *sinkpad, *srcpad; - - /* video state */ - gint from_rate_numerator, from_rate_denominator; - gint to_rate_numerator, to_rate_denominator; - guint64 next_ts; /* Timestamp of next buffer to output */ - GstBuffer *prevbuf; - guint64 prev_ts; /* Previous buffer timestamp */ - guint64 in, out, dup, drop; - - /* segment handling */ - gint64 segment_start; - gint64 segment_stop; - gint64 segment_accum; - - gboolean silent; - gdouble new_pref; -}; - -struct _GstVideoRateClass -{ - GstElementClass parent_class; -}; - /* elementfactory information */ static GstElementDetails video_rate_details = GST_ELEMENT_DETAILS ("Video rate adjuster", @@ -114,6 +113,9 @@ static GstStaticPadTemplate gst_video_rate_sink_template = static void gst_video_rate_base_init (gpointer g_class); static void gst_video_rate_class_init (GstVideoRateClass * klass); static void gst_video_rate_init (GstVideoRate * videorate); + +static void gst_video_rate_swap_prev (GstVideoRate * videorate, + GstBuffer * buffer, gint64 time); static gboolean gst_video_rate_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_video_rate_chain (GstPad * pad, GstBuffer * buffer); @@ -195,7 +197,7 @@ gst_video_rate_class_init (GstVideoRateClass * klass) DEFAULT_SILENT, G_PARAM_READWRITE)); g_object_class_install_property (object_class, ARG_NEW_PREF, g_param_spec_double ("new_pref", "New Pref", - "Value indicating how much to prefer new frames", + "Value indicating how much to prefer new frames (unused)", 0.0, 1.0, DEFAULT_NEW_PREF, G_PARAM_READWRITE)); element_class->change_state = gst_video_rate_change_state; @@ -264,12 +266,12 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps) GstPad *otherpad, *opeer; gint rate_numerator, rate_denominator; - videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad)); + videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad)); structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_fraction (structure, "framerate", &rate_numerator, &rate_denominator)) - goto done; + goto no_framerate; if (pad == videorate->srcpad) { videorate->to_rate_numerator = rate_numerator; @@ -297,7 +299,7 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps) /* see how we can transform the input caps */ if (!gst_video_rate_transformcaps (pad, caps, otherpad, &transform)) - goto done; + goto no_transform; /* see what the peer can do */ peercaps = gst_pad_get_caps (opeer); @@ -337,16 +339,26 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps) gst_object_unref (opeer); } done: + gst_object_unref (videorate); return ret; + +no_framerate: + { + GST_DEBUG_OBJECT (videorate, "no framerate specified"); + goto done; + } +no_transform: + { + GST_DEBUG_OBJECT (videorate, "no framerate transform possible"); + ret = FALSE; + goto done; + } } static void -gst_video_rate_blank_data (GstVideoRate * videorate) +gst_video_rate_reset (GstVideoRate * videorate) { GST_DEBUG ("resetting data"); - if (videorate->prevbuf) - gst_buffer_unref (videorate->prevbuf); - videorate->prevbuf = NULL; videorate->from_rate_numerator = 0; videorate->from_rate_denominator = 0; @@ -357,11 +369,9 @@ gst_video_rate_blank_data (GstVideoRate * videorate) videorate->drop = 0; videorate->dup = 0; videorate->next_ts = G_GINT64_CONSTANT (0); - videorate->prev_ts = G_GINT64_CONSTANT (0); + gst_video_rate_swap_prev (videorate, NULL, 0); - videorate->segment_start = 0; - videorate->segment_stop = 0; - videorate->segment_accum = 0; + gst_segment_init (&videorate->segment, GST_FORMAT_TIME); } static void @@ -382,57 +392,125 @@ gst_video_rate_init (GstVideoRate * videorate) gst_pad_set_getcaps_function (videorate->srcpad, gst_video_rate_getcaps); gst_pad_set_setcaps_function (videorate->srcpad, gst_video_rate_setcaps); - gst_video_rate_blank_data (videorate); + gst_video_rate_reset (videorate); videorate->silent = DEFAULT_SILENT; videorate->new_pref = DEFAULT_NEW_PREF; } +/* flush the oldest buffer */ +static GstFlowReturn +gst_video_rate_flush_prev (GstVideoRate * videorate) +{ + GstFlowReturn res; + GstBuffer *outbuf; + GstClockTime push_ts; + + /* make sure we can write to the metadata */ + outbuf = + gst_buffer_create_sub (videorate->prevbuf, 0, + GST_BUFFER_SIZE (videorate->prevbuf)); + + /* this is the timestamp we put on the buffer */ + push_ts = videorate->next_ts; + GST_BUFFER_TIMESTAMP (outbuf) = push_ts; + + videorate->out++; + if (videorate->to_rate_numerator) { + videorate->next_ts = + gst_util_uint64_scale (videorate->out, + videorate->to_rate_denominator * GST_SECOND, + videorate->to_rate_numerator); + GST_BUFFER_DURATION (outbuf) = + videorate->next_ts - GST_BUFFER_TIMESTAMP (outbuf); + } + /* adapt for looping, bring back to time in current segment. */ + GST_BUFFER_TIMESTAMP (outbuf) -= videorate->segment.accum; + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (videorate->srcpad)); + + GST_LOG_OBJECT (videorate, + "old is best, dup, pushing buffer outgoing ts %" GST_TIME_FORMAT, + GST_TIME_ARGS (push_ts)); + + if ((res = gst_pad_push (videorate->srcpad, outbuf)) != GST_FLOW_OK) + goto push_error; + + return res; + + /* ERRORS */ +push_error: + { + GST_WARNING_OBJECT (videorate, "couldn't push buffer on srcpad, reason %s", + gst_flow_get_name (res)); + return res; + } +} + +static void +gst_video_rate_swap_prev (GstVideoRate * videorate, GstBuffer * buffer, + gint64 time) +{ + if (videorate->prevbuf) + gst_buffer_unref (videorate->prevbuf); + videorate->prevbuf = buffer; + videorate->prev_ts = time; +} + static GstFlowReturn gst_video_rate_event (GstPad * pad, GstEvent * event) { GstVideoRate *videorate; - videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad)); + videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT: { - gint64 start, stop, base; + gint64 start, stop, time; gdouble rate; gboolean update; GstFormat format; gst_event_parse_new_segment (event, &update, &rate, &format, &start, - &stop, &base); + &stop, &time); - if (format != GST_FORMAT_TIME) { - GST_WARNING ("Got discont but doesn't have GST_FORMAT_TIME value"); - } else { - /* - We just want to update the accumulated stream_time. - */ - videorate->segment_accum += - videorate->segment_stop - videorate->segment_start; - videorate->segment_start = start; - videorate->segment_stop = stop; - GST_DEBUG_OBJECT (videorate, "Updated segment_accum:%" GST_TIME_FORMAT - " segment_start:%" GST_TIME_FORMAT " segment_stop:%" - GST_TIME_FORMAT, GST_TIME_ARGS (videorate->segment_accum), - GST_TIME_ARGS (videorate->segment_start), - GST_TIME_ARGS (videorate->segment_stop)); - } + if (format != videorate->segment.format) + goto format_error; + /* We just want to update the accumulated stream_time */ + gst_segment_set_newsegment (&videorate->segment, update, rate, + format, start, stop, time); + + GST_DEBUG_OBJECT (videorate, "Updated segment.accum:%" GST_TIME_FORMAT + " segment.start:%" GST_TIME_FORMAT " segment.stop:%" + GST_TIME_FORMAT, GST_TIME_ARGS (videorate->segment.accum), + GST_TIME_ARGS (videorate->segment.start), + GST_TIME_ARGS (videorate->segment.stop)); break; } + case GST_EVENT_EOS: + /* flush last queued frame */ + gst_video_rate_flush_prev (videorate); + break; case GST_EVENT_FLUSH_STOP: - { - gst_video_rate_blank_data (videorate); - } + /* also resets the segment */ + gst_video_rate_reset (videorate); + break; default: break; } +done: + gst_object_unref (videorate); + return gst_pad_event_default (pad, event); + + /* ERRORS */ +format_error: + { + GST_WARNING_OBJECT (videorate, + "Got segment but doesn't have GST_FORMAT_TIME value"); + goto done; + } } static GstFlowReturn @@ -440,31 +518,28 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer) { GstVideoRate *videorate; GstFlowReturn res = GST_FLOW_OK; + GstClockTime intime; - videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad)); + videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad)); + + /* make sure the denominators have to be != 0 */ + if (videorate->from_rate_denominator == 0 || + videorate->to_rate_denominator == 0) + goto not_negotiated; - if (videorate->from_rate_numerator == 0 || - videorate->from_rate_denominator == 0 || - videorate->to_rate_denominator == 0 || videorate->to_rate_numerator == 0) - return GST_FLOW_NOT_NEGOTIATED; + intime = gst_segment_to_running_time (&videorate->segment, + GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer)); /* pull in 2 buffers */ if (videorate->prevbuf == NULL) { - /* We're sure it's a GstBuffer here */ - videorate->prevbuf = buffer; - videorate->prev_ts = - GST_BUFFER_TIMESTAMP (buffer) - videorate->segment_start + - videorate->segment_accum; + gst_video_rate_swap_prev (videorate, buffer, intime); videorate->next_ts = 0; } else { - GstClockTime prevtime, intime; + GstClockTime prevtime; gint count = 0; gint64 diff1, diff2; prevtime = videorate->prev_ts; - intime = - GST_BUFFER_TIMESTAMP (buffer) - videorate->segment_start + - videorate->segment_accum; GST_LOG_OBJECT (videorate, "BEGINNING prev buf %" GST_TIME_FORMAT " new buf %" GST_TIME_FORMAT @@ -492,40 +567,11 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer) /* output first one when its the best */ if (diff1 < diff2) { - GstBuffer *outbuf; - GstClockTime push_ts; - count++; - outbuf = - gst_buffer_create_sub (videorate->prevbuf, 0, - GST_BUFFER_SIZE (videorate->prevbuf)); - GST_BUFFER_TIMESTAMP (outbuf) = videorate->next_ts; - push_ts = GST_BUFFER_TIMESTAMP (outbuf); - videorate->out++; - if (videorate->to_rate_numerator) { - videorate->next_ts = - gst_util_uint64_scale_int (videorate->out * GST_SECOND, - videorate->to_rate_denominator, videorate->to_rate_numerator); - GST_BUFFER_DURATION (outbuf) = - videorate->next_ts - GST_BUFFER_TIMESTAMP (outbuf); - } - /* adapt for looping */ - GST_BUFFER_TIMESTAMP (outbuf) -= videorate->segment_accum; - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (videorate->srcpad)); - - GST_LOG_OBJECT (videorate, - "old is best, dup, pushing buffer outgoing ts %" GST_TIME_FORMAT, - GST_TIME_ARGS (push_ts)); - - if ((res = gst_pad_push (videorate->srcpad, outbuf)) != GST_FLOW_OK) { - GST_WARNING_OBJECT (videorate, "couldn't push buffer on srcpad:%d", - res); - goto done; - } - GST_LOG_OBJECT (videorate, - "old is best, dup, pushed buffer outgoing ts %" GST_TIME_FORMAT, - GST_TIME_ARGS (push_ts)); + /* on error the _flush function posted a warning already */ + if ((res = gst_video_rate_flush_prev (videorate)) != GST_FLOW_OK) + goto done; } /* continue while the first one was the best */ } @@ -540,8 +586,10 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer) /* if we didn't output the first buffer, we have a drop */ else if (count == 0) { videorate->drop++; + if (!videorate->silent) g_object_notify (G_OBJECT (videorate), "drop"); + GST_LOG_OBJECT (videorate, "new is best, old never used, drop, outgoing ts %" GST_TIME_FORMAT, GST_TIME_ARGS (videorate->next_ts)); @@ -554,15 +602,19 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer) videorate->in, videorate->out, videorate->drop, videorate->dup); /* swap in new one when it's the best */ - gst_buffer_unref (videorate->prevbuf); - videorate->prevbuf = buffer; - videorate->prev_ts = - GST_BUFFER_TIMESTAMP (buffer) - videorate->segment_start + - videorate->segment_accum; + gst_video_rate_swap_prev (videorate, buffer, intime); } done: - + gst_object_unref (videorate); return res; + + /* ERRORS */ +not_negotiated: + { + GST_WARNING_OBJECT (videorate, "no framerate negotiated"); + res = GST_FLOW_NOT_NEGOTIATED; + goto done; + } } static void @@ -632,7 +684,7 @@ gst_video_rate_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_video_rate_blank_data (videorate); + gst_video_rate_reset (videorate); break; default: break; diff --git a/gst/videorate/gstvideorate.h b/gst/videorate/gstvideorate.h new file mode 100644 index 0000000..8780c11 --- /dev/null +++ b/gst/videorate/gstvideorate.h @@ -0,0 +1,74 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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 + +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__ */