mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-13 07:02:53 +00:00
gst/: More work on the generic source base class, implement seeking, query.
Original commit message from CVS: * gst/base/README: * gst/base/gstbasesrc.c: (gst_basesrc_get_type), (gst_basesrc_init), (gst_basesrc_get_formats), (gst_basesrc_query), (gst_basesrc_get_event_mask), (gst_basesrc_do_seek), (gst_basesrc_event_handler), (gst_basesrc_get_range_unlocked), (gst_basesrc_check_get_range), (gst_basesrc_loop), (gst_basesrc_unlock), (gst_basesrc_get_size), (gst_basesrc_start), (gst_basesrc_stop), (gst_basesrc_activate), (gst_basesrc_change_state), (basesrc_find_peek), (basesrc_find_suggest), (gst_basesrc_type_find): * gst/base/gstbasesrc.h: * gst/elements/gstfilesrc.c: (gst_filesrc_base_init), (gst_filesrc_class_init), (gst_filesrc_init), (gst_filesrc_finalize), (gst_filesrc_set_location), (gst_filesrc_set_property), (gst_filesrc_get_property), (gst_filesrc_free_parent_mmap), (gst_filesrc_map_region), (gst_filesrc_map_small_region), (gst_filesrc_create_mmap), (gst_filesrc_create_read), (gst_filesrc_create), (gst_filesrc_get_size), (gst_filesrc_start), (gst_filesrc_stop): * gst/elements/gstfilesrc.h: * gst/gstelement.c: (gst_element_get_state_func), (gst_element_lost_state), (gst_element_pads_activate): * gst/gstpad.c: (gst_pad_set_active), (gst_pad_peer_set_active), (gst_pad_set_checkgetrange_function), (gst_pad_check_pull_range), (gst_pad_pull_range): * gst/gstpad.h: More work on the generic source base class, implement seeking, query. Make filesrc extend the base source class. Added gst_pad_set_checkgetrange_function to GstPad.
This commit is contained in:
parent
4c712824b9
commit
aa00eb872d
14 changed files with 1643 additions and 1494 deletions
33
ChangeLog
33
ChangeLog
|
@ -1,3 +1,36 @@
|
|||
2005-04-06 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/base/README:
|
||||
* gst/base/gstbasesrc.c: (gst_basesrc_get_type),
|
||||
(gst_basesrc_init), (gst_basesrc_get_formats), (gst_basesrc_query),
|
||||
(gst_basesrc_get_event_mask), (gst_basesrc_do_seek),
|
||||
(gst_basesrc_event_handler), (gst_basesrc_get_range_unlocked),
|
||||
(gst_basesrc_check_get_range), (gst_basesrc_loop),
|
||||
(gst_basesrc_unlock), (gst_basesrc_get_size), (gst_basesrc_start),
|
||||
(gst_basesrc_stop), (gst_basesrc_activate),
|
||||
(gst_basesrc_change_state), (basesrc_find_peek),
|
||||
(basesrc_find_suggest), (gst_basesrc_type_find):
|
||||
* gst/base/gstbasesrc.h:
|
||||
* gst/elements/gstfilesrc.c: (gst_filesrc_base_init),
|
||||
(gst_filesrc_class_init), (gst_filesrc_init),
|
||||
(gst_filesrc_finalize), (gst_filesrc_set_location),
|
||||
(gst_filesrc_set_property), (gst_filesrc_get_property),
|
||||
(gst_filesrc_free_parent_mmap), (gst_filesrc_map_region),
|
||||
(gst_filesrc_map_small_region), (gst_filesrc_create_mmap),
|
||||
(gst_filesrc_create_read), (gst_filesrc_create),
|
||||
(gst_filesrc_get_size), (gst_filesrc_start), (gst_filesrc_stop):
|
||||
* gst/elements/gstfilesrc.h:
|
||||
* gst/gstelement.c: (gst_element_get_state_func),
|
||||
(gst_element_lost_state), (gst_element_pads_activate):
|
||||
* gst/gstpad.c: (gst_pad_set_active), (gst_pad_peer_set_active),
|
||||
(gst_pad_set_checkgetrange_function), (gst_pad_check_pull_range),
|
||||
(gst_pad_pull_range):
|
||||
* gst/gstpad.h:
|
||||
More work on the generic source base class, implement seeking,
|
||||
query.
|
||||
Make filesrc extend the base source class.
|
||||
Added gst_pad_set_checkgetrange_function to GstPad.
|
||||
|
||||
2005-04-06 Andy Wingo <wingo@pobox.com>
|
||||
|
||||
* pkgconfig/gstreamer-base.pc.in:
|
||||
|
|
|
@ -33,3 +33,4 @@ GstBaseSrc
|
|||
- one sinkpad
|
||||
- handles state changes
|
||||
- pull/push mode
|
||||
- handles seeking/query
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
* 2000,2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstbasesrc.c:
|
||||
*
|
||||
|
@ -92,12 +91,20 @@ static gboolean gst_basesrc_query (GstPad * pad, GstQueryType type,
|
|||
GstFormat * format, gint64 * value);
|
||||
static const GstFormat *gst_basesrc_get_formats (GstPad * pad);
|
||||
|
||||
static gboolean gst_basesrc_unlock (GstBaseSrc * basesrc);
|
||||
static gboolean gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size);
|
||||
static gboolean gst_basesrc_start (GstBaseSrc * basesrc);
|
||||
static gboolean gst_basesrc_stop (GstBaseSrc * basesrc);
|
||||
|
||||
static GstElementStateReturn gst_basesrc_change_state (GstElement * element);
|
||||
|
||||
static void gst_basesrc_loop (GstPad * pad);
|
||||
static gboolean gst_basesrc_check_get_range (GstPad * pad);
|
||||
static GstFlowReturn gst_basesrc_get_range (GstPad * pad, guint64 offset,
|
||||
guint length, GstBuffer ** buf);
|
||||
|
||||
static GstCaps *gst_basesrc_type_find (GstBaseSrc * src);
|
||||
|
||||
static void
|
||||
gst_basesrc_base_init (gpointer g_class)
|
||||
{
|
||||
|
@ -145,12 +152,17 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
|
|||
gst_pad_set_query_type_function (pad, gst_basesrc_get_query_types);
|
||||
gst_pad_set_formats_function (pad, gst_basesrc_get_formats);
|
||||
gst_pad_set_loop_function (pad, gst_basesrc_loop);
|
||||
gst_pad_set_checkgetrange_function (pad, gst_basesrc_check_get_range);
|
||||
gst_pad_set_getrange_function (pad, gst_basesrc_get_range);
|
||||
/* hold ref to pad */
|
||||
basesrc->srcpad = pad;
|
||||
gst_element_add_pad (GST_ELEMENT (basesrc), pad);
|
||||
|
||||
basesrc->segment_start = -1;
|
||||
basesrc->segment_end = -1;
|
||||
basesrc->blocksize = DEFAULT_BLOCKSIZE;
|
||||
|
||||
GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
|
||||
}
|
||||
|
||||
static const GstFormat *
|
||||
|
@ -158,6 +170,7 @@ gst_basesrc_get_formats (GstPad * pad)
|
|||
{
|
||||
static const GstFormat formats[] = {
|
||||
GST_FORMAT_DEFAULT,
|
||||
GST_FORMAT_BYTES,
|
||||
0,
|
||||
};
|
||||
|
||||
|
@ -184,31 +197,156 @@ gst_basesrc_query (GstPad * pad, GstQueryType type,
|
|||
{
|
||||
GstBaseSrc *src = GST_BASESRC (GST_PAD_PARENT (pad));
|
||||
|
||||
if (*format == GST_FORMAT_DEFAULT)
|
||||
*format = GST_FORMAT_BYTES;
|
||||
|
||||
switch (type) {
|
||||
case GST_QUERY_TOTAL:
|
||||
switch (*format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
ret = gst_basesrc_get_size (src, value);
|
||||
GST_DEBUG ("getting length %d %lld", ret, *value);
|
||||
return ret;
|
||||
}
|
||||
case GST_FORMAT_PERCENT:
|
||||
*value = GST_FORMAT_PERCENT_MAX;
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case GST_QUERY_POSITION:
|
||||
switch (*format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
*value = src->offset;
|
||||
break;
|
||||
case GST_FORMAT_PERCENT:
|
||||
if (!gst_basesrc_get_size (src, value))
|
||||
return FALSE;
|
||||
*value = src->offset * GST_FORMAT_PERCENT_MAX / *value;
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case GST_QUERY_START:
|
||||
*value = src->segment_start;
|
||||
break;
|
||||
return TRUE;
|
||||
case GST_QUERY_SEGMENT_END:
|
||||
*value = src->segment_end;
|
||||
break;
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static const GstEventMask *
|
||||
gst_basesrc_get_event_mask (GstPad * pad)
|
||||
{
|
||||
static const GstEventMask masks[] = {
|
||||
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
|
||||
{GST_EVENT_SEEK, GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET |
|
||||
GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH |
|
||||
GST_SEEK_FLAG_SEGMENT_LOOP},
|
||||
{GST_EVENT_FLUSH, 0},
|
||||
{GST_EVENT_SIZE, 0},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
return masks;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_do_seek (GstBaseSrc * src, GstEvent * event)
|
||||
{
|
||||
GstFormat format;
|
||||
gint64 offset;
|
||||
|
||||
format = GST_EVENT_SEEK_FORMAT (event);
|
||||
|
||||
/* get seek format */
|
||||
if (format == GST_FORMAT_DEFAULT)
|
||||
format = GST_FORMAT_BYTES;
|
||||
/* we can only seek bytes */
|
||||
if (format != GST_FORMAT_BYTES)
|
||||
return FALSE;
|
||||
|
||||
/* get seek positions */
|
||||
offset = GST_EVENT_SEEK_OFFSET (event);
|
||||
src->segment_start = offset;
|
||||
src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
|
||||
src->segment_loop = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
|
||||
|
||||
/* send flush start */
|
||||
gst_pad_push_event (src->srcpad, gst_event_new_flush (FALSE));
|
||||
|
||||
/* unblock streaming thread */
|
||||
gst_basesrc_unlock (src);
|
||||
|
||||
/* grab streaming lock */
|
||||
GST_STREAM_LOCK (src->srcpad);
|
||||
|
||||
switch (GST_EVENT_SEEK_METHOD (event)) {
|
||||
case GST_SEEK_METHOD_SET:
|
||||
if (offset < 0)
|
||||
goto error;
|
||||
src->offset = MIN (offset, src->size);
|
||||
GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
|
||||
src->offset);
|
||||
break;
|
||||
case GST_SEEK_METHOD_CUR:
|
||||
offset += src->offset;
|
||||
src->offset = CLAMP (offset, 0, src->size);
|
||||
GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
|
||||
src->offset);
|
||||
break;
|
||||
case GST_SEEK_METHOD_END:
|
||||
if (offset > 0)
|
||||
goto error;
|
||||
offset = src->size + offset;
|
||||
src->offset = MAX (0, offset);
|
||||
GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
|
||||
src->offset);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
/* send flush end */
|
||||
gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
|
||||
|
||||
/* now send discont */
|
||||
{
|
||||
GstEvent *event;
|
||||
|
||||
event = gst_event_new_discontinuous (1.0,
|
||||
GST_FORMAT_TIME,
|
||||
(gint64) src->segment_start, (gint64) src->segment_end, NULL);
|
||||
|
||||
gst_pad_push_event (src->srcpad, event);
|
||||
}
|
||||
|
||||
/* and restart the task */
|
||||
if (GST_RPAD_TASK (src->srcpad)) {
|
||||
gst_task_start (GST_RPAD_TASK (src->srcpad));
|
||||
}
|
||||
GST_STREAM_UNLOCK (src->srcpad);
|
||||
|
||||
gst_event_unref (event);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERROR */
|
||||
error:
|
||||
{
|
||||
GST_DEBUG_OBJECT (src, "seek error");
|
||||
GST_STREAM_UNLOCK (src->srcpad);
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
|
@ -218,12 +356,26 @@ gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
|
|||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEEK:
|
||||
src->segment_start = GST_EVENT_SEEK_OFFSET (event);
|
||||
src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
|
||||
src->segment_loop =
|
||||
GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
|
||||
return gst_basesrc_do_seek (src, event);
|
||||
case GST_EVENT_SIZE:
|
||||
{
|
||||
GstFormat format;
|
||||
|
||||
format = GST_EVENT_SIZE_FORMAT (event);
|
||||
if (format == GST_FORMAT_DEFAULT)
|
||||
format = GST_FORMAT_BYTES;
|
||||
/* we can only accept bytes */
|
||||
if (format != GST_FORMAT_BYTES)
|
||||
return FALSE;
|
||||
|
||||
src->blocksize = GST_EVENT_SIZE_VALUE (event);
|
||||
g_object_notify (G_OBJECT (src), "blocksize");
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_FLUSH:
|
||||
/* cancel any blocking getrange */
|
||||
if (!GST_EVENT_FLUSH_DONE (event))
|
||||
gst_basesrc_unlock (src);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -280,12 +432,41 @@ gst_basesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
|
|||
src = GST_BASESRC (GST_OBJECT_PARENT (pad));
|
||||
bclass = GST_BASESRC_GET_CLASS (src);
|
||||
|
||||
if (bclass->create)
|
||||
ret = bclass->create (src, offset, length, buf);
|
||||
else
|
||||
ret = GST_FLOW_ERROR;
|
||||
if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED))
|
||||
goto not_started;
|
||||
|
||||
if (!bclass->create)
|
||||
goto no_function;
|
||||
|
||||
/* check size */
|
||||
if (src->size != -1) {
|
||||
if (offset + length > src->size) {
|
||||
if (bclass->get_size)
|
||||
bclass->get_size (src, &src->size);
|
||||
|
||||
if (offset + length > src->size) {
|
||||
length = src->size - offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (length == 0)
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
|
||||
ret = bclass->create (src, offset, length, buf);
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERROR */
|
||||
not_started:
|
||||
{
|
||||
GST_DEBUG_OBJECT (src, "getrange but not started");
|
||||
return GST_FLOW_WRONG_STATE;
|
||||
}
|
||||
no_function:
|
||||
{
|
||||
GST_DEBUG_OBJECT (src, "no create function");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
@ -303,6 +484,21 @@ gst_basesrc_get_range (GstPad * pad, guint64 offset, guint length,
|
|||
return fret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_check_get_range (GstPad * pad)
|
||||
{
|
||||
GstBaseSrc *src;
|
||||
|
||||
src = GST_BASESRC (GST_OBJECT_PARENT (pad));
|
||||
|
||||
if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED)) {
|
||||
gst_basesrc_start (src);
|
||||
gst_basesrc_stop (src);
|
||||
}
|
||||
|
||||
return src->seekable;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesrc_loop (GstPad * pad)
|
||||
{
|
||||
|
@ -314,11 +510,9 @@ gst_basesrc_loop (GstPad * pad)
|
|||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
ret =
|
||||
gst_basesrc_get_range_unlocked (pad, src->offset, DEFAULT_BLOCKSIZE,
|
||||
&buf);
|
||||
ret = gst_basesrc_get_range_unlocked (pad, src->offset, src->blocksize, &buf);
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto pause;
|
||||
goto eos;
|
||||
|
||||
src->offset += GST_BUFFER_SIZE (buf);
|
||||
|
||||
|
@ -329,22 +523,152 @@ gst_basesrc_loop (GstPad * pad)
|
|||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
|
||||
eos:
|
||||
{
|
||||
GST_DEBUG_OBJECT (src, "going to EOS");
|
||||
gst_task_pause (GST_RPAD_TASK (pad));
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
}
|
||||
pause:
|
||||
{
|
||||
GST_DEBUG_OBJECT (src, "pausing task");
|
||||
gst_task_pause (GST_RPAD_TASK (pad));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_unlock (GstBaseSrc * basesrc)
|
||||
{
|
||||
GstBaseSrcClass *bclass;
|
||||
gboolean result = FALSE;
|
||||
|
||||
bclass = GST_BASESRC_GET_CLASS (basesrc);
|
||||
if (bclass->unlock)
|
||||
result = bclass->unlock (basesrc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size)
|
||||
{
|
||||
GstBaseSrcClass *bclass;
|
||||
gboolean result = FALSE;
|
||||
|
||||
bclass = GST_BASESRC_GET_CLASS (basesrc);
|
||||
if (bclass->get_size)
|
||||
result = bclass->get_size (basesrc, size);
|
||||
|
||||
if (result)
|
||||
basesrc->size = *size;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_start (GstBaseSrc * basesrc)
|
||||
{
|
||||
GstBaseSrcClass *bclass;
|
||||
gboolean result;
|
||||
|
||||
if (GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
|
||||
return TRUE;
|
||||
|
||||
bclass = GST_BASESRC_GET_CLASS (basesrc);
|
||||
if (bclass->start)
|
||||
result = bclass->start (basesrc);
|
||||
else
|
||||
result = TRUE;
|
||||
|
||||
if (!result)
|
||||
goto could_not_start;
|
||||
|
||||
GST_FLAG_SET (basesrc, GST_BASESRC_STARTED);
|
||||
|
||||
/* start in the beginning */
|
||||
basesrc->offset = 0;
|
||||
basesrc->segment_start = 0;
|
||||
|
||||
/* figure out the size */
|
||||
if (bclass->get_size)
|
||||
result = bclass->get_size (basesrc, &basesrc->size);
|
||||
else
|
||||
result = FALSE;
|
||||
|
||||
GST_DEBUG ("size %lld", basesrc->size);
|
||||
|
||||
/* we always run to the end */
|
||||
basesrc->segment_end = -1;
|
||||
|
||||
/* check if we can seek */
|
||||
if (bclass->is_seekable)
|
||||
basesrc->seekable = bclass->is_seekable (basesrc);
|
||||
else
|
||||
basesrc->seekable = FALSE;
|
||||
|
||||
/* run typefind */
|
||||
if (basesrc->seekable) {
|
||||
GstCaps *caps;
|
||||
|
||||
caps = gst_basesrc_type_find (basesrc);
|
||||
gst_pad_set_caps (basesrc->srcpad, caps);
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
/* ERROR */
|
||||
could_not_start:
|
||||
{
|
||||
GST_DEBUG_OBJECT (basesrc, "could not start");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_stop (GstBaseSrc * basesrc)
|
||||
{
|
||||
GstBaseSrcClass *bclass;
|
||||
gboolean result = TRUE;
|
||||
|
||||
if (!GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
|
||||
return TRUE;
|
||||
|
||||
bclass = GST_BASESRC_GET_CLASS (basesrc);
|
||||
if (bclass->stop)
|
||||
result = bclass->stop (basesrc);
|
||||
|
||||
if (result)
|
||||
GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
gboolean result;
|
||||
GstBaseSrc *basesrc;
|
||||
|
||||
basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
|
||||
|
||||
/* prepare subclass first */
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
case GST_ACTIVATE_PULL:
|
||||
result = gst_basesrc_start (basesrc);
|
||||
break;
|
||||
default:
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
/* if that failed we can stop here */
|
||||
if (!result)
|
||||
goto error_start;
|
||||
|
||||
result = FALSE;
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
/* if we have a scheduler we can start the task */
|
||||
|
@ -379,6 +703,13 @@ gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
|
|||
break;
|
||||
}
|
||||
return result;
|
||||
|
||||
/* ERROR */
|
||||
error_start:
|
||||
{
|
||||
GST_DEBUG_OBJECT (basesrc, "failed to start");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
@ -396,10 +727,7 @@ gst_basesrc_change_state (GstElement * element)
|
|||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
{
|
||||
basesrc->offset = 0;
|
||||
break;
|
||||
}
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
default:
|
||||
|
@ -412,6 +740,7 @@ gst_basesrc_change_state (GstElement * element)
|
|||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
result = gst_basesrc_stop (basesrc);
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
|
@ -421,3 +750,100 @@ gst_basesrc_change_state (GstElement * element)
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* typefind code here
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GstBaseSrc *src;
|
||||
guint best_probability;
|
||||
GstCaps *caps;
|
||||
|
||||
GstBuffer *buffer;
|
||||
}
|
||||
BaseSrcTypeFind;
|
||||
|
||||
static guint8 *
|
||||
basesrc_find_peek (gpointer data, gint64 offset, guint size)
|
||||
{
|
||||
BaseSrcTypeFind *find;
|
||||
GstBuffer *buffer;
|
||||
GstBaseSrc *src;
|
||||
GstFlowReturn ret;
|
||||
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
find = (BaseSrcTypeFind *) data;
|
||||
src = find->src;
|
||||
|
||||
if (offset < 0) {
|
||||
offset += src->size;
|
||||
}
|
||||
|
||||
buffer = NULL;
|
||||
ret = gst_basesrc_get_range_unlocked (src->srcpad, offset, size, &buffer);
|
||||
|
||||
if (find->buffer) {
|
||||
gst_buffer_unref (find->buffer);
|
||||
find->buffer = NULL;
|
||||
}
|
||||
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto error;
|
||||
|
||||
find->buffer = buffer;
|
||||
|
||||
return GST_BUFFER_DATA (buffer);
|
||||
|
||||
error:
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
basesrc_find_suggest (gpointer data, guint probability, const GstCaps * caps)
|
||||
{
|
||||
BaseSrcTypeFind *find = (BaseSrcTypeFind *) data;
|
||||
|
||||
if (probability > find->best_probability) {
|
||||
gst_caps_replace (&find->caps, gst_caps_copy (caps));
|
||||
find->best_probability = probability;
|
||||
}
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_basesrc_type_find (GstBaseSrc * src)
|
||||
{
|
||||
GstTypeFind gst_find;
|
||||
BaseSrcTypeFind find;
|
||||
GList *walk, *type_list = NULL;
|
||||
GstCaps *result = NULL;
|
||||
|
||||
walk = type_list = gst_type_find_factory_get_list ();
|
||||
|
||||
find.src = src;
|
||||
find.best_probability = 0;
|
||||
find.caps = NULL;
|
||||
find.buffer = NULL;
|
||||
gst_find.data = &find;
|
||||
gst_find.peek = basesrc_find_peek;
|
||||
gst_find.suggest = basesrc_find_suggest;
|
||||
gst_find.get_length = NULL;
|
||||
|
||||
while (walk) {
|
||||
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
|
||||
|
||||
gst_type_find_factory_call_function (factory, &gst_find);
|
||||
if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
|
||||
break;
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
|
||||
if (find.best_probability > 0)
|
||||
result = find.caps;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -35,19 +35,30 @@ G_BEGIN_DECLS
|
|||
#define GST_IS_BASESRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASESRC))
|
||||
#define GST_IS_BASESRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASESRC))
|
||||
|
||||
typedef enum {
|
||||
GST_BASESRC_STARTED = GST_ELEMENT_FLAG_LAST,
|
||||
|
||||
GST_BASESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
|
||||
} GstFileSrcFlags;
|
||||
|
||||
|
||||
typedef struct _GstBaseSrc GstBaseSrc;
|
||||
typedef struct _GstBaseSrcClass GstBaseSrcClass;
|
||||
|
||||
struct _GstBaseSrc {
|
||||
GstElement element;
|
||||
|
||||
GstPad *srcpad;
|
||||
|
||||
gint blocksize;
|
||||
|
||||
gint64 segment_start;
|
||||
gint64 segment_end;
|
||||
gboolean segment_loop;
|
||||
|
||||
gboolean seekable;
|
||||
guint64 offset;
|
||||
guint64 size;
|
||||
};
|
||||
|
||||
struct _GstBaseSrcClass {
|
||||
|
@ -62,6 +73,11 @@ struct _GstBaseSrcClass {
|
|||
void (*get_times) (GstBaseSrc *src, GstBuffer *buffer,
|
||||
GstClockTime *start, GstClockTime *end);
|
||||
|
||||
gboolean (*get_size) (GstBaseSrc *src, guint64 *size);
|
||||
|
||||
gboolean (*is_seekable) (GstBaseSrc *src);
|
||||
gboolean (*unlock) (GstBaseSrc *src);
|
||||
|
||||
gboolean (*event) (GstBaseSrc *src, GstEvent *event);
|
||||
GstFlowReturn (*create) (GstBaseSrc *src, guint64 offset, guint size,
|
||||
GstBuffer **buf);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstfilesrc.h:
|
||||
*
|
||||
|
@ -20,16 +21,15 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_FILESRC_H__
|
||||
#define __GST_FILESRC_H__
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesrc.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_FILESRC \
|
||||
(gst_filesrc_get_type())
|
||||
|
@ -42,42 +42,29 @@ G_BEGIN_DECLS
|
|||
#define GST_IS_FILESRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FILESRC))
|
||||
|
||||
typedef enum {
|
||||
GST_FILESRC_OPEN = GST_ELEMENT_FLAG_LAST,
|
||||
|
||||
GST_FILESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
|
||||
} GstFileSrcFlags;
|
||||
|
||||
typedef struct _GstFileSrc GstFileSrc;
|
||||
typedef struct _GstFileSrcClass GstFileSrcClass;
|
||||
|
||||
struct _GstFileSrc {
|
||||
GstElement element;
|
||||
GstPad *srcpad;
|
||||
GstBaseSrc element;
|
||||
|
||||
guint pagesize; /* system page size*/
|
||||
|
||||
gchar *filename; /* filename */
|
||||
gchar *uri; /* caching the URI */
|
||||
gint fd; /* open file descriptor*/
|
||||
off_t filelen; /* what's the file length?*/
|
||||
guint64 read_position; /* position of fd */
|
||||
|
||||
off_t curoffset; /* current offset in file*/
|
||||
off_t block_size; /* bytes per read */
|
||||
gboolean touch; /* whether to touch every page */
|
||||
gboolean using_mmap; /* whether we opened it with mmap */
|
||||
gboolean is_regular; /* whether it's (symlink to)
|
||||
a regular file */
|
||||
|
||||
GstBuffer *mapbuf;
|
||||
size_t mapsize;
|
||||
|
||||
gint need_discont;
|
||||
gboolean need_flush;
|
||||
};
|
||||
|
||||
struct _GstFileSrcClass {
|
||||
GstElementClass parent_class;
|
||||
GstBaseSrcClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_filesrc_get_type(void);
|
||||
|
|
|
@ -1987,8 +1987,8 @@ restart:
|
|||
|
||||
/* see if the pad has a loop function and grab
|
||||
* the peer */
|
||||
pad_get = gst_pad_check_pull_range (pad);
|
||||
GST_LOCK (pad);
|
||||
pad_get = GST_RPAD_GETRANGEFUNC (pad) != NULL;
|
||||
pad_loop = GST_RPAD_LOOPFUNC (pad) != NULL;
|
||||
peer = GST_RPAD_PEER (pad);
|
||||
if (peer)
|
||||
|
@ -1999,7 +1999,7 @@ restart:
|
|||
gboolean peer_loop, peer_get;
|
||||
|
||||
/* see if the peer has a getrange function */
|
||||
peer_get = GST_RPAD_GETRANGEFUNC (peer) != NULL;
|
||||
peer_get = gst_pad_check_pull_range (pad);
|
||||
/* see if the peer has a loop function */
|
||||
peer_loop = GST_RPAD_LOOPFUNC (peer) != NULL;
|
||||
|
||||
|
|
55
gst/gstpad.c
55
gst/gstpad.c
|
@ -837,6 +837,27 @@ gst_pad_set_getrange_function (GstPad * pad, GstPadGetRangeFunction get)
|
|||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (get));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_pad_set_checkgetrange_function:
|
||||
* @pad: a real source #GstPad.
|
||||
* @check: the #GstPadCheckGetRangeFunction to set.
|
||||
*
|
||||
* Sets the given checkgetrange function for the pad. Implement this function on
|
||||
* a pad if you dynamically support getrange based scheduling on the pad.
|
||||
*/
|
||||
void
|
||||
gst_pad_set_checkgetrange_function (GstPad * pad,
|
||||
GstPadCheckGetRangeFunction check)
|
||||
{
|
||||
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
||||
g_return_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SRC);
|
||||
|
||||
GST_RPAD_CHECKGETRANGEFUNC (pad) = check;
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_PADS, "checkgetrangefunc for %s:%s set to %s",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (check));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_pad_set_event_function:
|
||||
* @pad: a real source #GstPad.
|
||||
|
@ -2980,11 +3001,11 @@ gst_pad_check_pull_range (GstPad * pad)
|
|||
gboolean ret;
|
||||
GstPadCheckGetRangeFunction checkgetrangefunc;
|
||||
|
||||
g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
|
||||
g_return_val_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK,
|
||||
GST_FLOW_ERROR);
|
||||
g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE);
|
||||
|
||||
GST_LOCK (pad);
|
||||
if (GST_RPAD_DIRECTION (pad) != GST_PAD_SINK)
|
||||
goto wrong_direction;
|
||||
|
||||
if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
|
||||
goto not_connected;
|
||||
|
@ -2993,33 +3014,31 @@ gst_pad_check_pull_range (GstPad * pad)
|
|||
GST_UNLOCK (pad);
|
||||
|
||||
/* see note in above function */
|
||||
if (G_UNLIKELY ((checkgetrangefunc = peer->checkgetrangefunc) == NULL))
|
||||
goto no_function;
|
||||
if (G_LIKELY ((checkgetrangefunc = peer->checkgetrangefunc) == NULL)) {
|
||||
ret = GST_RPAD_GETRANGEFUNC (peer) != NULL;
|
||||
} else {
|
||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||
"calling checkgetrangefunc %s of peer pad %s:%s",
|
||||
GST_DEBUG_FUNCPTR_NAME (checkgetrangefunc), GST_DEBUG_PAD_NAME (peer));
|
||||
|
||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||
"calling checkgetrangefunc %s of peer pad %s:%s",
|
||||
GST_DEBUG_FUNCPTR_NAME (checkgetrangefunc), GST_DEBUG_PAD_NAME (peer));
|
||||
|
||||
ret = checkgetrangefunc (GST_PAD_CAST (peer));
|
||||
ret = checkgetrangefunc (GST_PAD_CAST (peer));
|
||||
}
|
||||
|
||||
gst_object_unref (GST_OBJECT_CAST (peer));
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERROR recovery here */
|
||||
not_connected:
|
||||
wrong_direction:
|
||||
{
|
||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||
"checkinh pull range, but it was not linked");
|
||||
GST_UNLOCK (pad);
|
||||
return FALSE;
|
||||
}
|
||||
no_function:
|
||||
not_connected:
|
||||
{
|
||||
GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
|
||||
("pad %s:%s checked pull_range but the peer pad %s:%s has no checkgetrangefunction",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
|
||||
gst_object_unref (GST_OBJECT (peer));
|
||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||
"checking pull range, but it was not linked");
|
||||
GST_UNLOCK (pad);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -484,6 +484,7 @@ void gst_pad_set_activate_function (GstPad *pad, GstPadActivateFunction activ
|
|||
void gst_pad_set_loop_function (GstPad *pad, GstPadLoopFunction loop);
|
||||
void gst_pad_set_chain_function (GstPad *pad, GstPadChainFunction chain);
|
||||
void gst_pad_set_getrange_function (GstPad *pad, GstPadGetRangeFunction get);
|
||||
void gst_pad_set_checkgetrange_function (GstPad *pad, GstPadCheckGetRangeFunction check);
|
||||
void gst_pad_set_event_function (GstPad *pad, GstPadEventFunction event);
|
||||
void gst_pad_set_event_mask_function (GstPad *pad, GstPadEventMaskFunction mask_func);
|
||||
G_CONST_RETURN GstEventMask*
|
||||
|
|
|
@ -33,3 +33,4 @@ GstBaseSrc
|
|||
- one sinkpad
|
||||
- handles state changes
|
||||
- pull/push mode
|
||||
- handles seeking/query
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
* 2000,2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstbasesrc.c:
|
||||
*
|
||||
|
@ -92,12 +91,20 @@ static gboolean gst_basesrc_query (GstPad * pad, GstQueryType type,
|
|||
GstFormat * format, gint64 * value);
|
||||
static const GstFormat *gst_basesrc_get_formats (GstPad * pad);
|
||||
|
||||
static gboolean gst_basesrc_unlock (GstBaseSrc * basesrc);
|
||||
static gboolean gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size);
|
||||
static gboolean gst_basesrc_start (GstBaseSrc * basesrc);
|
||||
static gboolean gst_basesrc_stop (GstBaseSrc * basesrc);
|
||||
|
||||
static GstElementStateReturn gst_basesrc_change_state (GstElement * element);
|
||||
|
||||
static void gst_basesrc_loop (GstPad * pad);
|
||||
static gboolean gst_basesrc_check_get_range (GstPad * pad);
|
||||
static GstFlowReturn gst_basesrc_get_range (GstPad * pad, guint64 offset,
|
||||
guint length, GstBuffer ** buf);
|
||||
|
||||
static GstCaps *gst_basesrc_type_find (GstBaseSrc * src);
|
||||
|
||||
static void
|
||||
gst_basesrc_base_init (gpointer g_class)
|
||||
{
|
||||
|
@ -145,12 +152,17 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
|
|||
gst_pad_set_query_type_function (pad, gst_basesrc_get_query_types);
|
||||
gst_pad_set_formats_function (pad, gst_basesrc_get_formats);
|
||||
gst_pad_set_loop_function (pad, gst_basesrc_loop);
|
||||
gst_pad_set_checkgetrange_function (pad, gst_basesrc_check_get_range);
|
||||
gst_pad_set_getrange_function (pad, gst_basesrc_get_range);
|
||||
/* hold ref to pad */
|
||||
basesrc->srcpad = pad;
|
||||
gst_element_add_pad (GST_ELEMENT (basesrc), pad);
|
||||
|
||||
basesrc->segment_start = -1;
|
||||
basesrc->segment_end = -1;
|
||||
basesrc->blocksize = DEFAULT_BLOCKSIZE;
|
||||
|
||||
GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
|
||||
}
|
||||
|
||||
static const GstFormat *
|
||||
|
@ -158,6 +170,7 @@ gst_basesrc_get_formats (GstPad * pad)
|
|||
{
|
||||
static const GstFormat formats[] = {
|
||||
GST_FORMAT_DEFAULT,
|
||||
GST_FORMAT_BYTES,
|
||||
0,
|
||||
};
|
||||
|
||||
|
@ -184,31 +197,156 @@ gst_basesrc_query (GstPad * pad, GstQueryType type,
|
|||
{
|
||||
GstBaseSrc *src = GST_BASESRC (GST_PAD_PARENT (pad));
|
||||
|
||||
if (*format == GST_FORMAT_DEFAULT)
|
||||
*format = GST_FORMAT_BYTES;
|
||||
|
||||
switch (type) {
|
||||
case GST_QUERY_TOTAL:
|
||||
switch (*format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
ret = gst_basesrc_get_size (src, value);
|
||||
GST_DEBUG ("getting length %d %lld", ret, *value);
|
||||
return ret;
|
||||
}
|
||||
case GST_FORMAT_PERCENT:
|
||||
*value = GST_FORMAT_PERCENT_MAX;
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case GST_QUERY_POSITION:
|
||||
switch (*format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
*value = src->offset;
|
||||
break;
|
||||
case GST_FORMAT_PERCENT:
|
||||
if (!gst_basesrc_get_size (src, value))
|
||||
return FALSE;
|
||||
*value = src->offset * GST_FORMAT_PERCENT_MAX / *value;
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case GST_QUERY_START:
|
||||
*value = src->segment_start;
|
||||
break;
|
||||
return TRUE;
|
||||
case GST_QUERY_SEGMENT_END:
|
||||
*value = src->segment_end;
|
||||
break;
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static const GstEventMask *
|
||||
gst_basesrc_get_event_mask (GstPad * pad)
|
||||
{
|
||||
static const GstEventMask masks[] = {
|
||||
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
|
||||
{GST_EVENT_SEEK, GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET |
|
||||
GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH |
|
||||
GST_SEEK_FLAG_SEGMENT_LOOP},
|
||||
{GST_EVENT_FLUSH, 0},
|
||||
{GST_EVENT_SIZE, 0},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
return masks;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_do_seek (GstBaseSrc * src, GstEvent * event)
|
||||
{
|
||||
GstFormat format;
|
||||
gint64 offset;
|
||||
|
||||
format = GST_EVENT_SEEK_FORMAT (event);
|
||||
|
||||
/* get seek format */
|
||||
if (format == GST_FORMAT_DEFAULT)
|
||||
format = GST_FORMAT_BYTES;
|
||||
/* we can only seek bytes */
|
||||
if (format != GST_FORMAT_BYTES)
|
||||
return FALSE;
|
||||
|
||||
/* get seek positions */
|
||||
offset = GST_EVENT_SEEK_OFFSET (event);
|
||||
src->segment_start = offset;
|
||||
src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
|
||||
src->segment_loop = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
|
||||
|
||||
/* send flush start */
|
||||
gst_pad_push_event (src->srcpad, gst_event_new_flush (FALSE));
|
||||
|
||||
/* unblock streaming thread */
|
||||
gst_basesrc_unlock (src);
|
||||
|
||||
/* grab streaming lock */
|
||||
GST_STREAM_LOCK (src->srcpad);
|
||||
|
||||
switch (GST_EVENT_SEEK_METHOD (event)) {
|
||||
case GST_SEEK_METHOD_SET:
|
||||
if (offset < 0)
|
||||
goto error;
|
||||
src->offset = MIN (offset, src->size);
|
||||
GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
|
||||
src->offset);
|
||||
break;
|
||||
case GST_SEEK_METHOD_CUR:
|
||||
offset += src->offset;
|
||||
src->offset = CLAMP (offset, 0, src->size);
|
||||
GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
|
||||
src->offset);
|
||||
break;
|
||||
case GST_SEEK_METHOD_END:
|
||||
if (offset > 0)
|
||||
goto error;
|
||||
offset = src->size + offset;
|
||||
src->offset = MAX (0, offset);
|
||||
GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
|
||||
src->offset);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
/* send flush end */
|
||||
gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
|
||||
|
||||
/* now send discont */
|
||||
{
|
||||
GstEvent *event;
|
||||
|
||||
event = gst_event_new_discontinuous (1.0,
|
||||
GST_FORMAT_TIME,
|
||||
(gint64) src->segment_start, (gint64) src->segment_end, NULL);
|
||||
|
||||
gst_pad_push_event (src->srcpad, event);
|
||||
}
|
||||
|
||||
/* and restart the task */
|
||||
if (GST_RPAD_TASK (src->srcpad)) {
|
||||
gst_task_start (GST_RPAD_TASK (src->srcpad));
|
||||
}
|
||||
GST_STREAM_UNLOCK (src->srcpad);
|
||||
|
||||
gst_event_unref (event);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERROR */
|
||||
error:
|
||||
{
|
||||
GST_DEBUG_OBJECT (src, "seek error");
|
||||
GST_STREAM_UNLOCK (src->srcpad);
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
|
@ -218,12 +356,26 @@ gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
|
|||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEEK:
|
||||
src->segment_start = GST_EVENT_SEEK_OFFSET (event);
|
||||
src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
|
||||
src->segment_loop =
|
||||
GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
|
||||
return gst_basesrc_do_seek (src, event);
|
||||
case GST_EVENT_SIZE:
|
||||
{
|
||||
GstFormat format;
|
||||
|
||||
format = GST_EVENT_SIZE_FORMAT (event);
|
||||
if (format == GST_FORMAT_DEFAULT)
|
||||
format = GST_FORMAT_BYTES;
|
||||
/* we can only accept bytes */
|
||||
if (format != GST_FORMAT_BYTES)
|
||||
return FALSE;
|
||||
|
||||
src->blocksize = GST_EVENT_SIZE_VALUE (event);
|
||||
g_object_notify (G_OBJECT (src), "blocksize");
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_FLUSH:
|
||||
/* cancel any blocking getrange */
|
||||
if (!GST_EVENT_FLUSH_DONE (event))
|
||||
gst_basesrc_unlock (src);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -280,12 +432,41 @@ gst_basesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
|
|||
src = GST_BASESRC (GST_OBJECT_PARENT (pad));
|
||||
bclass = GST_BASESRC_GET_CLASS (src);
|
||||
|
||||
if (bclass->create)
|
||||
ret = bclass->create (src, offset, length, buf);
|
||||
else
|
||||
ret = GST_FLOW_ERROR;
|
||||
if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED))
|
||||
goto not_started;
|
||||
|
||||
if (!bclass->create)
|
||||
goto no_function;
|
||||
|
||||
/* check size */
|
||||
if (src->size != -1) {
|
||||
if (offset + length > src->size) {
|
||||
if (bclass->get_size)
|
||||
bclass->get_size (src, &src->size);
|
||||
|
||||
if (offset + length > src->size) {
|
||||
length = src->size - offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (length == 0)
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
|
||||
ret = bclass->create (src, offset, length, buf);
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERROR */
|
||||
not_started:
|
||||
{
|
||||
GST_DEBUG_OBJECT (src, "getrange but not started");
|
||||
return GST_FLOW_WRONG_STATE;
|
||||
}
|
||||
no_function:
|
||||
{
|
||||
GST_DEBUG_OBJECT (src, "no create function");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
@ -303,6 +484,21 @@ gst_basesrc_get_range (GstPad * pad, guint64 offset, guint length,
|
|||
return fret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_check_get_range (GstPad * pad)
|
||||
{
|
||||
GstBaseSrc *src;
|
||||
|
||||
src = GST_BASESRC (GST_OBJECT_PARENT (pad));
|
||||
|
||||
if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED)) {
|
||||
gst_basesrc_start (src);
|
||||
gst_basesrc_stop (src);
|
||||
}
|
||||
|
||||
return src->seekable;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesrc_loop (GstPad * pad)
|
||||
{
|
||||
|
@ -314,11 +510,9 @@ gst_basesrc_loop (GstPad * pad)
|
|||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
ret =
|
||||
gst_basesrc_get_range_unlocked (pad, src->offset, DEFAULT_BLOCKSIZE,
|
||||
&buf);
|
||||
ret = gst_basesrc_get_range_unlocked (pad, src->offset, src->blocksize, &buf);
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto pause;
|
||||
goto eos;
|
||||
|
||||
src->offset += GST_BUFFER_SIZE (buf);
|
||||
|
||||
|
@ -329,22 +523,152 @@ gst_basesrc_loop (GstPad * pad)
|
|||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
|
||||
eos:
|
||||
{
|
||||
GST_DEBUG_OBJECT (src, "going to EOS");
|
||||
gst_task_pause (GST_RPAD_TASK (pad));
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
}
|
||||
pause:
|
||||
{
|
||||
GST_DEBUG_OBJECT (src, "pausing task");
|
||||
gst_task_pause (GST_RPAD_TASK (pad));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_unlock (GstBaseSrc * basesrc)
|
||||
{
|
||||
GstBaseSrcClass *bclass;
|
||||
gboolean result = FALSE;
|
||||
|
||||
bclass = GST_BASESRC_GET_CLASS (basesrc);
|
||||
if (bclass->unlock)
|
||||
result = bclass->unlock (basesrc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size)
|
||||
{
|
||||
GstBaseSrcClass *bclass;
|
||||
gboolean result = FALSE;
|
||||
|
||||
bclass = GST_BASESRC_GET_CLASS (basesrc);
|
||||
if (bclass->get_size)
|
||||
result = bclass->get_size (basesrc, size);
|
||||
|
||||
if (result)
|
||||
basesrc->size = *size;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_start (GstBaseSrc * basesrc)
|
||||
{
|
||||
GstBaseSrcClass *bclass;
|
||||
gboolean result;
|
||||
|
||||
if (GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
|
||||
return TRUE;
|
||||
|
||||
bclass = GST_BASESRC_GET_CLASS (basesrc);
|
||||
if (bclass->start)
|
||||
result = bclass->start (basesrc);
|
||||
else
|
||||
result = TRUE;
|
||||
|
||||
if (!result)
|
||||
goto could_not_start;
|
||||
|
||||
GST_FLAG_SET (basesrc, GST_BASESRC_STARTED);
|
||||
|
||||
/* start in the beginning */
|
||||
basesrc->offset = 0;
|
||||
basesrc->segment_start = 0;
|
||||
|
||||
/* figure out the size */
|
||||
if (bclass->get_size)
|
||||
result = bclass->get_size (basesrc, &basesrc->size);
|
||||
else
|
||||
result = FALSE;
|
||||
|
||||
GST_DEBUG ("size %lld", basesrc->size);
|
||||
|
||||
/* we always run to the end */
|
||||
basesrc->segment_end = -1;
|
||||
|
||||
/* check if we can seek */
|
||||
if (bclass->is_seekable)
|
||||
basesrc->seekable = bclass->is_seekable (basesrc);
|
||||
else
|
||||
basesrc->seekable = FALSE;
|
||||
|
||||
/* run typefind */
|
||||
if (basesrc->seekable) {
|
||||
GstCaps *caps;
|
||||
|
||||
caps = gst_basesrc_type_find (basesrc);
|
||||
gst_pad_set_caps (basesrc->srcpad, caps);
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
/* ERROR */
|
||||
could_not_start:
|
||||
{
|
||||
GST_DEBUG_OBJECT (basesrc, "could not start");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_stop (GstBaseSrc * basesrc)
|
||||
{
|
||||
GstBaseSrcClass *bclass;
|
||||
gboolean result = TRUE;
|
||||
|
||||
if (!GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
|
||||
return TRUE;
|
||||
|
||||
bclass = GST_BASESRC_GET_CLASS (basesrc);
|
||||
if (bclass->stop)
|
||||
result = bclass->stop (basesrc);
|
||||
|
||||
if (result)
|
||||
GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
gboolean result;
|
||||
GstBaseSrc *basesrc;
|
||||
|
||||
basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
|
||||
|
||||
/* prepare subclass first */
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
case GST_ACTIVATE_PULL:
|
||||
result = gst_basesrc_start (basesrc);
|
||||
break;
|
||||
default:
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
/* if that failed we can stop here */
|
||||
if (!result)
|
||||
goto error_start;
|
||||
|
||||
result = FALSE;
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
/* if we have a scheduler we can start the task */
|
||||
|
@ -379,6 +703,13 @@ gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
|
|||
break;
|
||||
}
|
||||
return result;
|
||||
|
||||
/* ERROR */
|
||||
error_start:
|
||||
{
|
||||
GST_DEBUG_OBJECT (basesrc, "failed to start");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
@ -396,10 +727,7 @@ gst_basesrc_change_state (GstElement * element)
|
|||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
{
|
||||
basesrc->offset = 0;
|
||||
break;
|
||||
}
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
default:
|
||||
|
@ -412,6 +740,7 @@ gst_basesrc_change_state (GstElement * element)
|
|||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
result = gst_basesrc_stop (basesrc);
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
|
@ -421,3 +750,100 @@ gst_basesrc_change_state (GstElement * element)
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* typefind code here
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GstBaseSrc *src;
|
||||
guint best_probability;
|
||||
GstCaps *caps;
|
||||
|
||||
GstBuffer *buffer;
|
||||
}
|
||||
BaseSrcTypeFind;
|
||||
|
||||
static guint8 *
|
||||
basesrc_find_peek (gpointer data, gint64 offset, guint size)
|
||||
{
|
||||
BaseSrcTypeFind *find;
|
||||
GstBuffer *buffer;
|
||||
GstBaseSrc *src;
|
||||
GstFlowReturn ret;
|
||||
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
find = (BaseSrcTypeFind *) data;
|
||||
src = find->src;
|
||||
|
||||
if (offset < 0) {
|
||||
offset += src->size;
|
||||
}
|
||||
|
||||
buffer = NULL;
|
||||
ret = gst_basesrc_get_range_unlocked (src->srcpad, offset, size, &buffer);
|
||||
|
||||
if (find->buffer) {
|
||||
gst_buffer_unref (find->buffer);
|
||||
find->buffer = NULL;
|
||||
}
|
||||
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto error;
|
||||
|
||||
find->buffer = buffer;
|
||||
|
||||
return GST_BUFFER_DATA (buffer);
|
||||
|
||||
error:
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
basesrc_find_suggest (gpointer data, guint probability, const GstCaps * caps)
|
||||
{
|
||||
BaseSrcTypeFind *find = (BaseSrcTypeFind *) data;
|
||||
|
||||
if (probability > find->best_probability) {
|
||||
gst_caps_replace (&find->caps, gst_caps_copy (caps));
|
||||
find->best_probability = probability;
|
||||
}
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_basesrc_type_find (GstBaseSrc * src)
|
||||
{
|
||||
GstTypeFind gst_find;
|
||||
BaseSrcTypeFind find;
|
||||
GList *walk, *type_list = NULL;
|
||||
GstCaps *result = NULL;
|
||||
|
||||
walk = type_list = gst_type_find_factory_get_list ();
|
||||
|
||||
find.src = src;
|
||||
find.best_probability = 0;
|
||||
find.caps = NULL;
|
||||
find.buffer = NULL;
|
||||
gst_find.data = &find;
|
||||
gst_find.peek = basesrc_find_peek;
|
||||
gst_find.suggest = basesrc_find_suggest;
|
||||
gst_find.get_length = NULL;
|
||||
|
||||
while (walk) {
|
||||
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
|
||||
|
||||
gst_type_find_factory_call_function (factory, &gst_find);
|
||||
if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
|
||||
break;
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
|
||||
if (find.best_probability > 0)
|
||||
result = find.caps;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -35,19 +35,30 @@ G_BEGIN_DECLS
|
|||
#define GST_IS_BASESRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASESRC))
|
||||
#define GST_IS_BASESRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASESRC))
|
||||
|
||||
typedef enum {
|
||||
GST_BASESRC_STARTED = GST_ELEMENT_FLAG_LAST,
|
||||
|
||||
GST_BASESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
|
||||
} GstFileSrcFlags;
|
||||
|
||||
|
||||
typedef struct _GstBaseSrc GstBaseSrc;
|
||||
typedef struct _GstBaseSrcClass GstBaseSrcClass;
|
||||
|
||||
struct _GstBaseSrc {
|
||||
GstElement element;
|
||||
|
||||
GstPad *srcpad;
|
||||
|
||||
gint blocksize;
|
||||
|
||||
gint64 segment_start;
|
||||
gint64 segment_end;
|
||||
gboolean segment_loop;
|
||||
|
||||
gboolean seekable;
|
||||
guint64 offset;
|
||||
guint64 size;
|
||||
};
|
||||
|
||||
struct _GstBaseSrcClass {
|
||||
|
@ -62,6 +73,11 @@ struct _GstBaseSrcClass {
|
|||
void (*get_times) (GstBaseSrc *src, GstBuffer *buffer,
|
||||
GstClockTime *start, GstClockTime *end);
|
||||
|
||||
gboolean (*get_size) (GstBaseSrc *src, guint64 *size);
|
||||
|
||||
gboolean (*is_seekable) (GstBaseSrc *src);
|
||||
gboolean (*unlock) (GstBaseSrc *src);
|
||||
|
||||
gboolean (*event) (GstBaseSrc *src, GstEvent *event);
|
||||
GstFlowReturn (*create) (GstBaseSrc *src, guint64 offset, guint size,
|
||||
GstBuffer **buf);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstfilesrc.h:
|
||||
*
|
||||
|
@ -20,16 +21,15 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_FILESRC_H__
|
||||
#define __GST_FILESRC_H__
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesrc.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_FILESRC \
|
||||
(gst_filesrc_get_type())
|
||||
|
@ -42,42 +42,29 @@ G_BEGIN_DECLS
|
|||
#define GST_IS_FILESRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FILESRC))
|
||||
|
||||
typedef enum {
|
||||
GST_FILESRC_OPEN = GST_ELEMENT_FLAG_LAST,
|
||||
|
||||
GST_FILESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
|
||||
} GstFileSrcFlags;
|
||||
|
||||
typedef struct _GstFileSrc GstFileSrc;
|
||||
typedef struct _GstFileSrcClass GstFileSrcClass;
|
||||
|
||||
struct _GstFileSrc {
|
||||
GstElement element;
|
||||
GstPad *srcpad;
|
||||
GstBaseSrc element;
|
||||
|
||||
guint pagesize; /* system page size*/
|
||||
|
||||
gchar *filename; /* filename */
|
||||
gchar *uri; /* caching the URI */
|
||||
gint fd; /* open file descriptor*/
|
||||
off_t filelen; /* what's the file length?*/
|
||||
guint64 read_position; /* position of fd */
|
||||
|
||||
off_t curoffset; /* current offset in file*/
|
||||
off_t block_size; /* bytes per read */
|
||||
gboolean touch; /* whether to touch every page */
|
||||
gboolean using_mmap; /* whether we opened it with mmap */
|
||||
gboolean is_regular; /* whether it's (symlink to)
|
||||
a regular file */
|
||||
|
||||
GstBuffer *mapbuf;
|
||||
size_t mapsize;
|
||||
|
||||
gint need_discont;
|
||||
gboolean need_flush;
|
||||
};
|
||||
|
||||
struct _GstFileSrcClass {
|
||||
GstElementClass parent_class;
|
||||
GstBaseSrcClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_filesrc_get_type(void);
|
||||
|
|
Loading…
Reference in a new issue