gst/: Handle and adjust new-segment events so that downstream really sees a stream with the tag pieces stripped off t...
Original commit message from CVS: * gst/id3demux/gstid3demux.c: (gst_id3demux_reset), (gst_id3demux_send_new_segment), (gst_id3demux_chain), (gst_id3demux_sink_event): * gst/id3demux/gstid3demux.h: * gst/apetag/gsttagdemux.c: (gst_tag_demux_reset), (gst_tag_demux_chain), (gst_tag_demux_sink_event), (gst_tag_demux_send_new_segment): Handle and adjust new-segment events so that downstream really sees a stream with the tag pieces stripped off the front and back. Fixes strangeness in seeking when mp3 decoders use the new-segment byte position to estimate their current playback position timestamp and then the arriving buffers don't match up.
This commit is contained in:
parent
465a740bbf
commit
4a7ecfb814
15
ChangeLog
15
ChangeLog
@ -1,3 +1,18 @@
|
|||||||
|
2007-05-25 Jan Schmidt <thaytan@mad.scientist.com>
|
||||||
|
|
||||||
|
* gst/id3demux/gstid3demux.c: (gst_id3demux_reset),
|
||||||
|
(gst_id3demux_send_new_segment), (gst_id3demux_chain),
|
||||||
|
(gst_id3demux_sink_event):
|
||||||
|
* gst/id3demux/gstid3demux.h:
|
||||||
|
* gst/apetag/gsttagdemux.c: (gst_tag_demux_reset),
|
||||||
|
(gst_tag_demux_chain), (gst_tag_demux_sink_event),
|
||||||
|
(gst_tag_demux_send_new_segment):
|
||||||
|
Handle and adjust new-segment events so that downstream really
|
||||||
|
sees a stream with the tag pieces stripped off the front and back.
|
||||||
|
Fixes strangeness in seeking when mp3 decoders use the new-segment
|
||||||
|
byte position to estimate their current playback position timestamp
|
||||||
|
and then the arriving buffers don't match up.
|
||||||
|
|
||||||
2007-05-25 Jan Schmidt <thaytan@mad.scientist.com>
|
2007-05-25 Jan Schmidt <thaytan@mad.scientist.com>
|
||||||
|
|
||||||
* gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_detect):
|
* gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_detect):
|
||||||
|
@ -107,6 +107,10 @@ struct _GstTagDemuxPrivate
|
|||||||
GstTagList *event_tags;
|
GstTagList *event_tags;
|
||||||
GstTagList *parsed_tags;
|
GstTagList *parsed_tags;
|
||||||
gboolean send_tag_event;
|
gboolean send_tag_event;
|
||||||
|
|
||||||
|
GstSegment segment;
|
||||||
|
gboolean need_newseg;
|
||||||
|
gboolean newseg_update;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Require at least 8kB of data before we attempt typefind.
|
/* Require at least 8kB of data before we attempt typefind.
|
||||||
@ -151,6 +155,7 @@ static gboolean gst_tag_demux_pad_query (GstPad * pad, GstQuery * query);
|
|||||||
static const GstQueryType *gst_tag_demux_get_query_types (GstPad * pad);
|
static const GstQueryType *gst_tag_demux_get_query_types (GstPad * pad);
|
||||||
static gboolean gst_tag_demux_get_upstream_size (GstTagDemux * tagdemux);
|
static gboolean gst_tag_demux_get_upstream_size (GstTagDemux * tagdemux);
|
||||||
static void gst_tag_demux_send_tag_event (GstTagDemux * tagdemux);
|
static void gst_tag_demux_send_tag_event (GstTagDemux * tagdemux);
|
||||||
|
static gboolean gst_tag_demux_send_new_segment (GstTagDemux * tagdemux);
|
||||||
|
|
||||||
static void gst_tag_demux_base_init (gpointer g_class);
|
static void gst_tag_demux_base_init (gpointer g_class);
|
||||||
static void gst_tag_demux_class_init (gpointer g_class, gpointer d);
|
static void gst_tag_demux_class_init (gpointer g_class, gpointer d);
|
||||||
@ -236,6 +241,10 @@ gst_tag_demux_reset (GstTagDemux * tagdemux)
|
|||||||
gst_tag_list_free (tagdemux->priv->parsed_tags);
|
gst_tag_list_free (tagdemux->priv->parsed_tags);
|
||||||
tagdemux->priv->parsed_tags = NULL;
|
tagdemux->priv->parsed_tags = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_segment_init (&tagdemux->priv->segment, GST_FORMAT_UNDEFINED);
|
||||||
|
tagdemux->priv->need_newseg = TRUE;
|
||||||
|
tagdemux->priv->newseg_update = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -548,6 +557,18 @@ gst_tag_demux_chain (GstPad * pad, GstBuffer * buf)
|
|||||||
demux = GST_TAG_DEMUX (GST_PAD_PARENT (pad));
|
demux = GST_TAG_DEMUX (GST_PAD_PARENT (pad));
|
||||||
g_return_val_if_fail (GST_IS_TAG_DEMUX (demux), GST_FLOW_ERROR);
|
g_return_val_if_fail (GST_IS_TAG_DEMUX (demux), GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
/* Update our segment last_stop info */
|
||||||
|
if (demux->priv->segment.format == GST_FORMAT_BYTES) {
|
||||||
|
if (GST_BUFFER_OFFSET_IS_VALID (buf))
|
||||||
|
demux->priv->segment.last_stop = GST_BUFFER_OFFSET (buf);
|
||||||
|
demux->priv->segment.last_stop += GST_BUFFER_SIZE (buf);
|
||||||
|
} else if (demux->priv->segment.format == GST_FORMAT_TIME) {
|
||||||
|
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf))
|
||||||
|
demux->priv->segment.last_stop = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
if (GST_BUFFER_DURATION_IS_VALID (buf))
|
||||||
|
demux->priv->segment.last_stop += GST_BUFFER_DURATION (buf);
|
||||||
|
}
|
||||||
|
|
||||||
if (demux->priv->collect == NULL) {
|
if (demux->priv->collect == NULL) {
|
||||||
demux->priv->collect = buf;
|
demux->priv->collect = buf;
|
||||||
} else {
|
} else {
|
||||||
@ -647,6 +668,15 @@ gst_tag_demux_chain (GstPad * pad, GstBuffer * buf)
|
|||||||
outbuf = gst_buffer_make_metadata_writable (outbuf);
|
outbuf = gst_buffer_make_metadata_writable (outbuf);
|
||||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->priv->srcpad));
|
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->priv->srcpad));
|
||||||
|
|
||||||
|
/* Might need a new segment before the buffer */
|
||||||
|
if (demux->priv->need_newseg) {
|
||||||
|
if (!gst_tag_demux_send_new_segment (demux)) {
|
||||||
|
GST_DEBUG_OBJECT (demux, "Failed to send new segment event");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
demux->priv->need_newseg = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
return gst_pad_push (demux->priv->srcpad, outbuf);
|
return gst_pad_push (demux->priv->srcpad, outbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -675,6 +705,22 @@ gst_tag_demux_sink_event (GstPad * pad, GstEvent * event)
|
|||||||
}
|
}
|
||||||
ret = gst_pad_event_default (pad, event);
|
ret = gst_pad_event_default (pad, event);
|
||||||
break;
|
break;
|
||||||
|
case GST_EVENT_NEWSEGMENT:{
|
||||||
|
gboolean update;
|
||||||
|
gdouble rate, arate;
|
||||||
|
GstFormat format;
|
||||||
|
gint64 start, stop, position;
|
||||||
|
|
||||||
|
gst_event_parse_new_segment_full (event, &update, &rate, &arate,
|
||||||
|
&format, &start, &stop, &position);
|
||||||
|
|
||||||
|
gst_segment_set_newsegment_full (&demux->priv->segment, update, rate,
|
||||||
|
arate, format, start, stop, position);
|
||||||
|
demux->priv->newseg_update = update;
|
||||||
|
demux->priv->need_newseg = TRUE;
|
||||||
|
ret = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ret = gst_pad_event_default (pad, event);
|
ret = gst_pad_event_default (pad, event);
|
||||||
break;
|
break;
|
||||||
@ -1343,3 +1389,83 @@ gst_tag_demux_send_tag_event (GstTagDemux * demux)
|
|||||||
gst_pad_push_event (demux->priv->srcpad, event);
|
gst_pad_push_event (demux->priv->srcpad, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_tag_demux_send_new_segment (GstTagDemux * tagdemux)
|
||||||
|
{
|
||||||
|
GstEvent *event;
|
||||||
|
gint64 start, stop, position;
|
||||||
|
GstSegment *seg = &tagdemux->priv->segment;
|
||||||
|
|
||||||
|
if (seg->format == GST_FORMAT_UNDEFINED) {
|
||||||
|
GST_LOG_OBJECT (tagdemux,
|
||||||
|
"No new segment received before first buffer. Using default");
|
||||||
|
gst_segment_set_newsegment (seg, FALSE, 1.0,
|
||||||
|
GST_FORMAT_BYTES, tagdemux->priv->strip_start, -1,
|
||||||
|
tagdemux->priv->strip_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can't adjust segments in non-BYTES formats */
|
||||||
|
if (tagdemux->priv->segment.format != GST_FORMAT_BYTES) {
|
||||||
|
event = gst_event_new_new_segment_full (tagdemux->priv->newseg_update,
|
||||||
|
seg->rate, seg->applied_rate, seg->format, seg->start,
|
||||||
|
seg->stop, seg->time);
|
||||||
|
return gst_pad_push_event (tagdemux->priv->srcpad, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
start = seg->start;
|
||||||
|
stop = seg->stop;
|
||||||
|
position = seg->time;
|
||||||
|
|
||||||
|
g_return_val_if_fail (start != -1, FALSE);
|
||||||
|
g_return_val_if_fail (position != -1, FALSE);
|
||||||
|
|
||||||
|
if (tagdemux->priv->strip_end > 0) {
|
||||||
|
if (gst_tag_demux_get_upstream_size (tagdemux)) {
|
||||||
|
guint64 v1tag_offset =
|
||||||
|
tagdemux->priv->upstream_size - tagdemux->priv->strip_end;
|
||||||
|
|
||||||
|
if (start >= v1tag_offset) {
|
||||||
|
/* Segment is completely within the ID3v1 tag, output an open-ended
|
||||||
|
* segment, even though all the buffers will get trimmed away */
|
||||||
|
start = v1tag_offset;
|
||||||
|
stop = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stop != -1 && stop >= v1tag_offset) {
|
||||||
|
GST_DEBUG_OBJECT (tagdemux,
|
||||||
|
"Segment crosses the ID3v1 tag. Trimming end");
|
||||||
|
stop = v1tag_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tagdemux->priv->strip_start > 0) {
|
||||||
|
if (start > tagdemux->priv->strip_start)
|
||||||
|
start -= tagdemux->priv->strip_start;
|
||||||
|
else
|
||||||
|
start = 0;
|
||||||
|
|
||||||
|
if (position > tagdemux->priv->strip_start)
|
||||||
|
position -= tagdemux->priv->strip_start;
|
||||||
|
else
|
||||||
|
position = 0;
|
||||||
|
|
||||||
|
if (stop != -1) {
|
||||||
|
if (stop > tagdemux->priv->strip_start)
|
||||||
|
stop -= tagdemux->priv->strip_start;
|
||||||
|
else
|
||||||
|
stop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (tagdemux,
|
||||||
|
"Sending new segment update %d, rate %g, format %d, "
|
||||||
|
"start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", position %"
|
||||||
|
G_GINT64_FORMAT, tagdemux->priv->newseg_update, seg->rate, seg->format,
|
||||||
|
start, stop, position);
|
||||||
|
|
||||||
|
event = gst_event_new_new_segment_full (tagdemux->priv->newseg_update,
|
||||||
|
seg->rate, seg->applied_rate, seg->format, start, stop, position);
|
||||||
|
return gst_pad_push_event (tagdemux->priv->srcpad, event);
|
||||||
|
}
|
||||||
|
@ -117,6 +117,7 @@ static gboolean gst_id3demux_pad_query (GstPad * pad, GstQuery * query);
|
|||||||
static const GstQueryType *gst_id3demux_get_query_types (GstPad * pad);
|
static const GstQueryType *gst_id3demux_get_query_types (GstPad * pad);
|
||||||
static gboolean id3demux_get_upstream_size (GstID3Demux * id3demux);
|
static gboolean id3demux_get_upstream_size (GstID3Demux * id3demux);
|
||||||
static void gst_id3demux_send_tag_event (GstID3Demux * id3demux);
|
static void gst_id3demux_send_tag_event (GstID3Demux * id3demux);
|
||||||
|
static gboolean gst_id3demux_send_new_segment (GstID3Demux * id3demux);
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
static GstElementClass *parent_class = NULL;
|
||||||
|
|
||||||
@ -206,6 +207,88 @@ gst_id3demux_reset (GstID3Demux * id3demux)
|
|||||||
id3demux->parsed_tags = NULL;
|
id3demux->parsed_tags = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_segment_init (&id3demux->segment, GST_FORMAT_UNDEFINED);
|
||||||
|
id3demux->need_newseg = TRUE;
|
||||||
|
id3demux->newseg_update = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_id3demux_send_new_segment (GstID3Demux * id3demux)
|
||||||
|
{
|
||||||
|
GstEvent *event;
|
||||||
|
gint64 start, stop, position;
|
||||||
|
GstSegment *seg = &id3demux->segment;
|
||||||
|
|
||||||
|
if (seg->format == GST_FORMAT_UNDEFINED) {
|
||||||
|
GST_LOG_OBJECT (id3demux,
|
||||||
|
"No new segment received before first buffer. Using default");
|
||||||
|
gst_segment_set_newsegment (seg, FALSE, 1.0,
|
||||||
|
GST_FORMAT_BYTES, id3demux->strip_start, -1, id3demux->strip_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can't adjust segments in non-BYTES formats */
|
||||||
|
if (id3demux->segment.format != GST_FORMAT_BYTES) {
|
||||||
|
event = gst_event_new_new_segment_full (id3demux->newseg_update,
|
||||||
|
seg->rate, seg->applied_rate, seg->format, seg->start,
|
||||||
|
seg->stop, seg->time);
|
||||||
|
return gst_pad_push_event (id3demux->srcpad, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
start = seg->start;
|
||||||
|
stop = seg->stop;
|
||||||
|
position = seg->time;
|
||||||
|
|
||||||
|
g_return_val_if_fail (start != -1, FALSE);
|
||||||
|
g_return_val_if_fail (position != -1, FALSE);
|
||||||
|
|
||||||
|
if (id3demux->strip_end > 0) {
|
||||||
|
if (id3demux_get_upstream_size (id3demux)) {
|
||||||
|
guint64 v1tag_offset = id3demux->upstream_size - id3demux->strip_end;
|
||||||
|
|
||||||
|
if (start >= v1tag_offset) {
|
||||||
|
/* Segment is completely within the ID3v1 tag, output an open-ended
|
||||||
|
* segment, even though all the buffers will get trimmed away */
|
||||||
|
start = v1tag_offset;
|
||||||
|
stop = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stop != -1 && stop >= v1tag_offset) {
|
||||||
|
GST_DEBUG_OBJECT (id3demux,
|
||||||
|
"Segment crosses the ID3v1 tag. Trimming end");
|
||||||
|
stop = v1tag_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id3demux->strip_start > 0) {
|
||||||
|
if (start > id3demux->strip_start)
|
||||||
|
start -= id3demux->strip_start;
|
||||||
|
else
|
||||||
|
start = 0;
|
||||||
|
|
||||||
|
if (position > id3demux->strip_start)
|
||||||
|
position -= id3demux->strip_start;
|
||||||
|
else
|
||||||
|
position = 0;
|
||||||
|
|
||||||
|
if (stop != -1) {
|
||||||
|
if (stop > id3demux->strip_start)
|
||||||
|
stop -= id3demux->strip_start;
|
||||||
|
else
|
||||||
|
stop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (id3demux,
|
||||||
|
"Sending new segment update %d, rate %g, format %d, "
|
||||||
|
"start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", position %"
|
||||||
|
G_GINT64_FORMAT, id3demux->newseg_update, seg->rate, seg->format,
|
||||||
|
start, stop, position);
|
||||||
|
|
||||||
|
event = gst_event_new_new_segment_full (id3demux->newseg_update,
|
||||||
|
seg->rate, seg->applied_rate, seg->format, start, stop, position);
|
||||||
|
|
||||||
|
return gst_pad_push_event (id3demux->srcpad, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -409,6 +492,18 @@ gst_id3demux_chain (GstPad * pad, GstBuffer * buf)
|
|||||||
id3demux = GST_ID3DEMUX (GST_PAD_PARENT (pad));
|
id3demux = GST_ID3DEMUX (GST_PAD_PARENT (pad));
|
||||||
g_return_val_if_fail (GST_IS_ID3DEMUX (id3demux), GST_FLOW_ERROR);
|
g_return_val_if_fail (GST_IS_ID3DEMUX (id3demux), GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
/* Update our segment last_stop info */
|
||||||
|
if (id3demux->segment.format == GST_FORMAT_BYTES) {
|
||||||
|
if (GST_BUFFER_OFFSET_IS_VALID (buf))
|
||||||
|
id3demux->segment.last_stop = GST_BUFFER_OFFSET (buf);
|
||||||
|
id3demux->segment.last_stop += GST_BUFFER_SIZE (buf);
|
||||||
|
} else if (id3demux->segment.format == GST_FORMAT_TIME) {
|
||||||
|
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf))
|
||||||
|
id3demux->segment.last_stop = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
if (GST_BUFFER_DURATION_IS_VALID (buf))
|
||||||
|
id3demux->segment.last_stop += GST_BUFFER_DURATION (buf);
|
||||||
|
}
|
||||||
|
|
||||||
if (id3demux->collect == NULL) {
|
if (id3demux->collect == NULL) {
|
||||||
id3demux->collect = buf;
|
id3demux->collect = buf;
|
||||||
} else {
|
} else {
|
||||||
@ -549,6 +644,15 @@ gst_id3demux_chain (GstPad * pad, GstBuffer * buf)
|
|||||||
outbuf = gst_buffer_make_metadata_writable (outbuf);
|
outbuf = gst_buffer_make_metadata_writable (outbuf);
|
||||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (id3demux->srcpad));
|
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (id3demux->srcpad));
|
||||||
|
|
||||||
|
/* Might need a new segment before the buffer */
|
||||||
|
if (id3demux->need_newseg) {
|
||||||
|
if (!gst_id3demux_send_new_segment (id3demux)) {
|
||||||
|
GST_DEBUG_OBJECT (id3demux, "Failed to send new segment event");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
id3demux->need_newseg = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
return gst_pad_push (id3demux->srcpad, outbuf);
|
return gst_pad_push (id3demux->srcpad, outbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -577,6 +681,22 @@ gst_id3demux_sink_event (GstPad * pad, GstEvent * event)
|
|||||||
}
|
}
|
||||||
ret = gst_pad_event_default (pad, event);
|
ret = gst_pad_event_default (pad, event);
|
||||||
break;
|
break;
|
||||||
|
case GST_EVENT_NEWSEGMENT:{
|
||||||
|
gboolean update;
|
||||||
|
gdouble rate, arate;
|
||||||
|
GstFormat format;
|
||||||
|
gint64 start, stop, position;
|
||||||
|
|
||||||
|
gst_event_parse_new_segment_full (event, &update, &rate, &arate,
|
||||||
|
&format, &start, &stop, &position);
|
||||||
|
|
||||||
|
gst_segment_set_newsegment_full (&demux->segment, update, rate,
|
||||||
|
arate, format, start, stop, position);
|
||||||
|
demux->newseg_update = update;
|
||||||
|
demux->need_newseg = TRUE;
|
||||||
|
ret = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ret = gst_pad_event_default (pad, event);
|
ret = gst_pad_event_default (pad, event);
|
||||||
break;
|
break;
|
||||||
|
@ -65,6 +65,10 @@ struct _GstID3Demux
|
|||||||
GstTagList *event_tags;
|
GstTagList *event_tags;
|
||||||
GstTagList *parsed_tags;
|
GstTagList *parsed_tags;
|
||||||
gboolean send_tag_event;
|
gboolean send_tag_event;
|
||||||
|
|
||||||
|
GstSegment segment;
|
||||||
|
gboolean need_newseg;
|
||||||
|
gboolean newseg_update;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstID3DemuxClass
|
struct _GstID3DemuxClass
|
||||||
|
Loading…
x
Reference in New Issue
Block a user