+2007-03-19 Jan Schmidt <thaytan@mad.scientist.com>
+
+ * 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 <wim@fluendo.com>
Patch by: Evan Nemerson <evan at coeus dash group dot com>
gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad,
gboolean flushing)
{
+ GstBaseSinkClass *bclass;
- if (flushing) {
- GstBaseSinkClass *bclass;
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
+ bclass = GST_BASE_SINK_GET_CLASS (basesink);
+ if (flushing) {
/* 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)
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);
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);
* @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
/* 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);
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);
* 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));
result = gst_base_src_unlock (src);
break;
case GST_EVENT_FLUSH_STOP:
+ result = gst_base_src_unlock_stop (src);
+ break;
default:
result = TRUE;
break;
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
/* 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;
}
* @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.
/* 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);
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)
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,
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,
{
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)
{
if (new_fd < 0)
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);
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);
}
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;
}
{
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)
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;
{
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 *************************************************/