From c248d1dba018f9512f0268947129580718c5f753 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 19 Mar 2007 15:01:40 +0000 Subject: [PATCH] libs/gst/base/: Add ::unlock_stop to basesrc and basesink. This allows an opportunity for sub-classes to correctly cl... Original commit message from CVS: * libs/gst/base/gstbasesink.c: (gst_base_sink_set_flushing), (gst_base_sink_change_state): * libs/gst/base/gstbasesink.h: * libs/gst/base/gstbasesrc.c: (gst_base_src_perform_seek), (gst_base_src_default_event), (gst_base_src_unlock_stop), (gst_base_src_deactivate): * libs/gst/base/gstbasesrc.h: Add ::unlock_stop to basesrc and basesink. This allows an opportunity for sub-classes to correctly clear any state they set trying to unlock, such as clearing out unlock commands from a command fd. * plugins/elements/gstfdsink.c: (gst_fd_sink_class_init), (gst_fd_sink_render), (gst_fd_sink_unlock), (gst_fd_sink_unlock_stop): * plugins/elements/gstfdsrc.c: (gst_fd_src_class_init), (gst_fd_src_init), (gst_fd_src_unlock), (gst_fd_src_unlock_stop), (gst_fd_src_create), (gst_fd_src_get_size), (gst_fd_src_do_seek): Implement unlock_stop in fdsrc and fdsink. Implement seeking in fdsrc when a seekable fd is passed, as in gst-launch-0.10 fdsrc ! ... ! xvimagesink < /path/to/file --- ChangeLog | 24 +++++++++++ libs/gst/base/gstbasesink.c | 17 +++++--- libs/gst/base/gstbasesink.h | 9 ++++- libs/gst/base/gstbasesrc.c | 31 +++++++++++++++ libs/gst/base/gstbasesrc.h | 7 +++- plugins/elements/gstfdsink.c | 41 ++++++++++++------- plugins/elements/gstfdsrc.c | 77 +++++++++++++++++++++++++++--------- 7 files changed, 167 insertions(+), 39 deletions(-) diff --git a/ChangeLog b/ChangeLog index 15cca404bc..891631b4ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2007-03-19 Jan Schmidt + + * libs/gst/base/gstbasesink.c: (gst_base_sink_set_flushing), + (gst_base_sink_change_state): + * libs/gst/base/gstbasesink.h: + * libs/gst/base/gstbasesrc.c: (gst_base_src_perform_seek), + (gst_base_src_default_event), (gst_base_src_unlock_stop), + (gst_base_src_deactivate): + * libs/gst/base/gstbasesrc.h: + Add ::unlock_stop to basesrc and basesink. This allows an opportunity + for sub-classes to correctly clear any state they set trying to + unlock, such as clearing out unlock commands from a command fd. + + * plugins/elements/gstfdsink.c: (gst_fd_sink_class_init), + (gst_fd_sink_render), (gst_fd_sink_unlock), + (gst_fd_sink_unlock_stop): + * plugins/elements/gstfdsrc.c: (gst_fd_src_class_init), + (gst_fd_src_init), (gst_fd_src_unlock), (gst_fd_src_unlock_stop), + (gst_fd_src_create), (gst_fd_src_get_size), (gst_fd_src_do_seek): + + Implement unlock_stop in fdsrc and fdsink. + Implement seeking in fdsrc when a seekable fd is passed, as in + gst-launch-0.10 fdsrc ! ... ! xvimagesink < /path/to/file + 2007-03-19 Wim Taymans Patch by: Evan Nemerson diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index 3ac30de8f9..b375caf515 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -2245,12 +2245,11 @@ static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad, gboolean flushing) { + GstBaseSinkClass *bclass; + + bclass = GST_BASE_SINK_GET_CLASS (basesink); if (flushing) { - GstBaseSinkClass *bclass; - - bclass = GST_BASE_SINK_GET_CLASS (basesink); - /* unlock any subclasses, we need to do this before grabbing the * PREROLL_LOCK since we hold this lock before going into ::render. */ if (bclass->unlock) @@ -2260,7 +2259,11 @@ gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad, GST_PAD_PREROLL_LOCK (pad); basesink->flushing = flushing; if (flushing) { - /* step 1, unblock clock sync (if any) or any other blocking thing */ + /* step 1, now that we have the PREROLL lock, clear our unlock request */ + if (bclass->unlock_stop) + bclass->unlock_stop (basesink); + + /* step 2, unblock clock sync (if any) or any other blocking thing */ basesink->need_preroll = TRUE; if (basesink->clock_id) { gst_clock_id_unschedule (basesink->clock_id); @@ -2868,6 +2871,10 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) bclass->unlock (basesink); GST_PAD_PREROLL_LOCK (basesink->sinkpad); + /* now that we have the PREROLL lock, clear our unlock request */ + if (bclass->unlock_stop) + bclass->unlock_stop (basesink); + basesink->need_preroll = TRUE; if (basesink->clock_id) { gst_clock_id_unschedule (basesink->clock_id); diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h index 417c5a0c75..84073ae026 100644 --- a/libs/gst/base/gstbasesink.h +++ b/libs/gst/base/gstbasesink.h @@ -114,6 +114,8 @@ struct _GstBaseSink { * @stop: Stop processing. Subclasses should use this to close resources. * @unlock: Unlock any pending access to the resource. Subclasses should * unblock any blocked function ASAP + * @unlock_stop: Clear the previous unlock request. Subclasses should clear + * any state they set during unlock(), such as clearing command queues. * @event: Override this to handle events arriving on the sink pad * @preroll: Called to present the preroll buffer if desired * @render: Called when a buffer should be presented or output, at the @@ -174,8 +176,13 @@ struct _GstBaseSinkClass { /* fixate sink caps during pull-mode negotiation */ void (*fixate) (GstBaseSink *sink, GstCaps *caps); + /* Clear a previously indicated unlock request not that unlocking is + * complete. Sub-classes should clear any command queue or indicator they + * set during unlock */ + gboolean (*unlock_stop) (GstBaseSink *sink); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-3]; + gpointer _gst_reserved[GST_PADDING_LARGE-4]; }; GType gst_base_sink_get_type(void); diff --git a/libs/gst/base/gstbasesrc.c b/libs/gst/base/gstbasesrc.c index 88385a6af7..f090a14677 100644 --- a/libs/gst/base/gstbasesrc.c +++ b/libs/gst/base/gstbasesrc.c @@ -290,6 +290,7 @@ static gboolean gst_base_src_default_do_seek (GstBaseSrc * src, static gboolean gst_base_src_default_query (GstBaseSrc * src, GstQuery * query); static gboolean gst_base_src_unlock (GstBaseSrc * basesrc); +static gboolean gst_base_src_unlock_stop (GstBaseSrc * basesrc); static gboolean gst_base_src_start (GstBaseSrc * basesrc); static gboolean gst_base_src_stop (GstBaseSrc * basesrc); @@ -910,6 +911,9 @@ gst_base_src_perform_seek (GstBaseSrc * src, GstEvent * event, gboolean unlock) * because our peer is flushing. */ GST_PAD_STREAM_LOCK (src->srcpad); + if (unlock) + gst_base_src_unlock_stop (src); + /* make copy into temp structure, we can only update the main one * when the subclass actually could do the seek. */ memcpy (&seeksegment, &src->segment, sizeof (GstSegment)); @@ -1110,6 +1114,8 @@ gst_base_src_default_event (GstBaseSrc * src, GstEvent * event) result = gst_base_src_unlock (src); break; case GST_EVENT_FLUSH_STOP: + result = gst_base_src_unlock_stop (src); + break; default: result = TRUE; break; @@ -1687,6 +1693,28 @@ gst_base_src_unlock (GstBaseSrc * basesrc) return result; } +/* this will always be called between start() and stop(). So you can rely on + * resources allocated by start() and freed from stop(). This needs to be added + * to the docs at some point. */ +static gboolean +gst_base_src_unlock_stop (GstBaseSrc * basesrc) +{ + GstBaseSrcClass *bclass; + gboolean result = TRUE; + + GST_DEBUG_OBJECT (basesrc, "unlock stop"); + + /* Finish a previous unblock request, allowing subclasses to flush command + * queues or whatever they need to do */ + bclass = GST_BASE_SRC_GET_CLASS (basesrc); + if (bclass->unlock_stop) + result = bclass->unlock_stop (basesrc); + + GST_DEBUG_OBJECT (basesrc, "unlock stop done"); + + return result; +} + /* default negotiation code. * * Take intersection between src and sink pads, take first @@ -1906,6 +1934,9 @@ gst_base_src_deactivate (GstBaseSrc * basesrc, GstPad * pad) /* step 2, make sure streaming finishes */ result &= gst_pad_stop_task (pad); + /* step 3, clear the unblock condition */ + result &= gst_base_src_unlock_stop (basesrc); + return result; } diff --git a/libs/gst/base/gstbasesrc.h b/libs/gst/base/gstbasesrc.h index fc9ed50152..0acf741332 100644 --- a/libs/gst/base/gstbasesrc.h +++ b/libs/gst/base/gstbasesrc.h @@ -132,6 +132,8 @@ struct _GstBaseSrc { * @is_seekable: Check if the source can seek * @unlock: Unlock any pending access to the resource. Subclasses should * unblock any blocked function ASAP + * @unlock_stop: Clear the previous unlock request. Subclasses should clear + * any state they set during unlock(), such as clearing command queues. * @event: Override this to implement custom event handling. * @create: Ask the subclass to create a buffer with offset and size. * @do_seek: Perform seeking on the resource to the indicated segment. @@ -208,8 +210,11 @@ struct _GstBaseSrcClass { /* called if, in negotation, caps need fixating */ void (*fixate) (GstBaseSrc *src, GstCaps *caps); + /* Clear any pending unlock request, as we succeeded in unlocking */ + gboolean (*unlock_stop) (GstBaseSrc *src); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE - 4]; + gpointer _gst_reserved[GST_PADDING_LARGE - 5]; }; GType gst_base_src_get_type (void); diff --git a/plugins/elements/gstfdsink.c b/plugins/elements/gstfdsink.c index e9f398e3c4..9c3789efc7 100644 --- a/plugins/elements/gstfdsink.c +++ b/plugins/elements/gstfdsink.c @@ -141,6 +141,7 @@ static GstFlowReturn gst_fd_sink_render (GstBaseSink * sink, static gboolean gst_fd_sink_start (GstBaseSink * basesink); static gboolean gst_fd_sink_stop (GstBaseSink * basesink); static gboolean gst_fd_sink_unlock (GstBaseSink * basesink); +static gboolean gst_fd_sink_unlock_stop (GstBaseSink * basesink); static void gst_fd_sink_base_init (gpointer g_class) @@ -170,6 +171,7 @@ gst_fd_sink_class_init (GstFdSinkClass * klass) gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_fd_sink_start); gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_fd_sink_stop); gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock); + gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock_stop); gstbasesink_class->event = NULL; g_object_class_install_property (gobject_class, ARG_FD, @@ -272,21 +274,8 @@ again: if (retval == -1) goto select_error; - if (FD_ISSET (READ_SOCKET (fdsink), &readfds)) { - /* read all stop commands */ - while (TRUE) { - gchar command; - int res; - - READ_COMMAND (fdsink, command, res); - if (res < 0) { - GST_LOG_OBJECT (fdsink, "no more commands"); - /* no more commands */ - break; - } - } + if (FD_ISSET (READ_SOCKET (fdsink), &readfds)) goto stopped; - } #endif GST_DEBUG_OBJECT (fdsink, "writing %d bytes to file descriptor %d", size, @@ -437,11 +426,35 @@ gst_fd_sink_unlock (GstBaseSink * basesink) { GstFdSink *fdsink = GST_FD_SINK (basesink); + GST_LOG_OBJECT (fdsink, "Sending unlock command to queue"); SEND_COMMAND (fdsink, CONTROL_STOP); return TRUE; } +static gboolean +gst_fd_sink_unlock_stop (GstBaseSink * basesink) +{ + GstFdSink *fdsink = GST_FD_SINK (basesink); + + /* read all stop commands */ + GST_LOG_OBJECT (fdsink, "Clearing unlock command queue"); + + while (TRUE) { + gchar command; + int res; + + READ_COMMAND (fdsink, command, res); + if (res < 0) { + GST_LOG_OBJECT (fdsink, "no more commands"); + /* no more commands */ + break; + } + } + + return TRUE; +} + static gboolean gst_fd_sink_update_fd (GstFdSink * fdsink, int new_fd) { diff --git a/plugins/elements/gstfdsrc.c b/plugins/elements/gstfdsrc.c index 39615551e7..c8941ca620 100644 --- a/plugins/elements/gstfdsrc.c +++ b/plugins/elements/gstfdsrc.c @@ -119,8 +119,10 @@ static void gst_fd_src_dispose (GObject * obj); static gboolean gst_fd_src_start (GstBaseSrc * bsrc); static gboolean gst_fd_src_stop (GstBaseSrc * bsrc); static gboolean gst_fd_src_unlock (GstBaseSrc * bsrc); +static gboolean gst_fd_src_unlock_stop (GstBaseSrc * bsrc); static gboolean gst_fd_src_is_seekable (GstBaseSrc * bsrc); static gboolean gst_fd_src_get_size (GstBaseSrc * src, guint64 * size); +static gboolean gst_fd_src_do_seek (GstBaseSrc * src, GstSegment * segment); static GstFlowReturn gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf); @@ -160,8 +162,10 @@ gst_fd_src_class_init (GstFdSrcClass * klass) gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_fd_src_start); gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_fd_src_stop); gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_src_unlock); + gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_fd_src_unlock_stop); gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fd_src_is_seekable); gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_fd_src_get_size); + gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_fd_src_do_seek); gstpush_src_class->create = GST_DEBUG_FUNCPTR (gst_fd_src_create); } @@ -169,10 +173,10 @@ gst_fd_src_class_init (GstFdSrcClass * klass) static void gst_fd_src_init (GstFdSrc * fdsrc, GstFdSrcClass * klass) { - fdsrc->fd = 0; + fdsrc->fd = -1; fdsrc->new_fd = 0; fdsrc->seekable_fd = FALSE; - fdsrc->uri = g_strdup_printf ("fd://%d", fdsrc->fd); + fdsrc->uri = g_strdup_printf ("fd://0"); fdsrc->curoffset = 0; } @@ -268,11 +272,37 @@ gst_fd_src_unlock (GstBaseSrc * bsrc) { GstFdSrc *src = GST_FD_SRC (bsrc); + GST_LOG_OBJECT (src, "sending unlock command"); SEND_COMMAND (src, CONTROL_STOP); return TRUE; } +static gboolean +gst_fd_src_unlock_stop (GstBaseSrc * bsrc) +{ + GstFdSrc *src = GST_FD_SRC (bsrc); + + GST_LOG_OBJECT (src, "clearing unlock command queue"); + + /* read all stop commands */ + while (TRUE) { + gchar command; + int res; + + GST_LOG_OBJECT (src, "reading command"); + + READ_COMMAND (src, command, res); + if (res < 0) { + GST_LOG_OBJECT (src, "no more commands"); + /* no more commands */ + break; + } + } + + return TRUE; +} + static void gst_fd_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -343,23 +373,8 @@ gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf) if (retval == -1) goto select_error; - if (FD_ISSET (READ_SOCKET (src), &readfds)) { - /* read all stop commands */ - while (TRUE) { - gchar command; - int res; - - GST_LOG_OBJECT (src, "reading command"); - - READ_COMMAND (src, command, res); - if (res < 0) { - GST_LOG_OBJECT (src, "no more commands"); - /* no more commands */ - break; - } - } + if (FD_ISSET (READ_SOCKET (src), &readfds)) goto stopped; - } #endif blocksize = GST_BASE_SRC (src)->blocksize; @@ -453,7 +468,33 @@ could_not_stat: { return FALSE; } +} +gboolean +gst_fd_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment) +{ + gint res; + gint64 offset; + GstFdSrc *src = GST_FD_SRC (bsrc); + + offset = segment->start; + + /* No need to seek to the current position */ + if (offset == src->curoffset) + return TRUE; + + res = lseek (src->fd, offset, SEEK_SET); + if (G_UNLIKELY (res < 0 || res != offset)) + goto seek_failed; + + segment->last_stop = segment->start; + segment->time = segment->start; + + return TRUE; + +seek_failed: + GST_DEBUG_OBJECT (src, "lseek returned %" G_GINT64_FORMAT, offset); + return FALSE; } /*** GSTURIHANDLER INTERFACE *************************************************/