gst/asfdemux/gstasfdemux.*: Don't crash in the seek event handling code when playtime is 0, as may be the case with l...

Original commit message from CVS:
* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_handle_seek_event),
(gst_asf_demux_process_data), (gst_asf_demux_process_file),
(gst_asf_demux_handle_src_query), (gst_asf_demux_change_state):
* gst/asfdemux/gstasfdemux.h:
Don't crash in the seek event handling code when playtime is 0,
as may be the case with live streams (#386218). Implement SEEKING
query so applications can query seekability without second-guessing
based on whether we have a duration or not.
This commit is contained in:
Tim-Philipp Müller 2006-12-15 17:54:48 +00:00
parent b4a1a4cda2
commit 7e1371c41e
3 changed files with 77 additions and 24 deletions

View file

@ -1,3 +1,14 @@
2006-12-15 Tim-Philipp Müller <tim at centricular dot net>
* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_handle_seek_event),
(gst_asf_demux_process_data), (gst_asf_demux_process_file),
(gst_asf_demux_handle_src_query), (gst_asf_demux_change_state):
* gst/asfdemux/gstasfdemux.h:
Don't crash in the seek event handling code when playtime is 0,
as may be the case with live streams (#386218). Implement SEEKING
query so applications can query seekability without second-guessing
based on whether we have a duration or not.
2006-12-15 Thomas Vander Stichele <thomas at apestaart dot org> 2006-12-15 Thomas Vander Stichele <thomas at apestaart dot org>
* Makefile.am: * Makefile.am:

View file

@ -227,18 +227,25 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
gdouble rate; gdouble rate;
gint64 cur, stop; gint64 cur, stop;
gint64 seek_offset; gint64 seek_offset;
gint64 seek_time;
guint64 seek_packet; guint64 seek_packet;
if (demux->seekable == FALSE || demux->packet_size == 0 ||
demux->num_packets == 0 || demux->play_time == 0) {
GST_LOG_OBJECT (demux, "stream is not seekable");
return FALSE;
}
gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
&stop_type, &stop); &stop_type, &stop);
if (format != GST_FORMAT_TIME) { if (format != GST_FORMAT_TIME) {
GST_LOG ("seeking is only supported in TIME format"); GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
return FALSE; return FALSE;
} }
if (rate <= 0.0) { if (rate <= 0.0) {
GST_LOG ("backward playback is not supported yet"); GST_LOG_OBJECT (demux, "backward playback is not supported yet");
return FALSE; return FALSE;
} }
@ -260,31 +267,24 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
GST_DEBUG ("trying to seek to time %" GST_TIME_FORMAT, GST_DEBUG ("trying to seek to time %" GST_TIME_FORMAT,
GST_TIME_ARGS (segment.start)); GST_TIME_ARGS (segment.start));
if (demux->packet_size > 0) { seek_time = segment.start;
gint64 seek_time = segment.start;
/* Hackety hack, this sucks. We just seek to an earlier position /* Hackety hack, this sucks. We just seek to an earlier position
* and let the sinks throw away the stuff before the segment start */ * and let the sinks throw away the stuff before the segment start */
if (flush && (accurate || keyunit_sync)) { if (flush && (accurate || keyunit_sync)) {
seek_time -= 5 * GST_SECOND; seek_time -= 5 * GST_SECOND;
if (seek_time < 0) if (seek_time < 0)
seek_time = 0; seek_time = 0;
}
seek_packet = demux->num_packets * seek_time / demux->play_time;
if (seek_packet > demux->num_packets)
seek_packet = demux->num_packets;
seek_offset = seek_packet * demux->packet_size + demux->data_offset;
/* demux->next_byte_offset will be set via newsegment event */
} else {
/* FIXME */
g_message ("IMPLEMENT ME: seeking for packet_size == 0 (asfdemux)");
ret = FALSE;
goto done;
} }
seek_packet = demux->num_packets * seek_time / demux->play_time;
if (seek_packet > demux->num_packets)
seek_packet = demux->num_packets;
seek_offset = seek_packet * demux->packet_size + demux->data_offset;
/* demux->next_byte_offset will be set via newsegment event */
GST_LOG ("seeking to byte offset %" G_GINT64_FORMAT, seek_offset); GST_LOG ("seeking to byte offset %" G_GINT64_FORMAT, seek_offset);
ret = gst_pad_push_event (demux->sinkpad, ret = gst_pad_push_event (demux->sinkpad,
@ -1407,6 +1407,9 @@ gst_asf_demux_process_data (GstASFDemux * demux, guint64 object_size,
demux->packet = 0; demux->packet = 0;
demux->num_packets = data_object.packets; demux->num_packets = data_object.packets;
if (demux->num_packets == 0)
demux->seekable = FALSE;
/* minus object header and data object header */ /* minus object header and data object header */
demux->data_size = demux->data_size =
object_size - ASF_DEMUX_OBJECT_HEADER_SIZE - (16 + 8 + 1 + 1); object_size - ASF_DEMUX_OBJECT_HEADER_SIZE - (16 + 8 + 1 + 1);
@ -1451,22 +1454,40 @@ gst_asf_demux_process_file (GstASFDemux * demux, guint8 ** p_data,
guint64 * p_size) guint64 * p_size)
{ {
asf_obj_file object; asf_obj_file object;
gboolean broadcast;
/* Get the rest of the header's header */ /* Get the rest of the header's header */
if (!gst_asf_demux_get_obj_file (&object, p_data, p_size)) if (!gst_asf_demux_get_obj_file (&object, p_data, p_size))
return ASF_FLOW_NEED_MORE_DATA; return ASF_FLOW_NEED_MORE_DATA;
broadcast = !!(object.flags & 0x01);
demux->seekable = !!(object.flags & 0x02);
GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", broadcast);
GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
if (broadcast) {
/* these fields are invalid if the broadcast flag is set */
object.play_time = 0;
object.file_size = 0;
}
if (object.min_pktsize == object.max_pktsize) { if (object.min_pktsize == object.max_pktsize) {
demux->packet_size = object.max_pktsize; demux->packet_size = object.max_pktsize;
} else { } else {
demux->packet_size = (guint32) - 1; demux->packet_size = (guint32) - 1;
GST_WARNING ("Non-const packet size, seeking disabled"); GST_WARNING ("Non-const packet size, seeking disabled");
demux->seekable = FALSE;
} }
/* FIXME: do we need object.send_time as well? what is it? */ /* FIXME: do we need object.send_time as well? what is it? */
demux->play_time = (guint64) object.play_time * (GST_SECOND / 10000000); demux->play_time = (guint64) object.play_time * (GST_SECOND / 10000000);
demux->preroll = object.preroll; demux->preroll = object.preroll;
if (demux->play_time == 0)
demux->seekable = FALSE;
GST_DEBUG_OBJECT (demux, GST_DEBUG_OBJECT (demux,
"play_time %" GST_TIME_FORMAT " preroll %" GST_TIME_FORMAT, "play_time %" GST_TIME_FORMAT " preroll %" GST_TIME_FORMAT,
GST_TIME_ARGS (demux->play_time), GST_TIME_ARGS (demux->preroll)); GST_TIME_ARGS (demux->play_time), GST_TIME_ARGS (demux->preroll));
@ -2788,6 +2809,24 @@ gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
break; break;
} }
case GST_QUERY_SEEKING:{
GstFormat format;
gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
if (format == GST_FORMAT_TIME) {
gint64 duration;
GST_OBJECT_LOCK (demux);
duration = demux->segment.duration;
GST_OBJECT_UNLOCK (demux);
gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable,
0, duration);
res = TRUE;
}
break;
}
default: default:
res = gst_pad_query_default (pad, query); res = gst_pad_query_default (pad, query);
break; break;
@ -2838,6 +2877,7 @@ gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
g_slist_free (demux->ext_stream_props); g_slist_free (demux->ext_stream_props);
demux->ext_stream_props = NULL; demux->ext_stream_props = NULL;
memset (demux->stream, 0, sizeof (demux->stream)); memset (demux->stream, 0, sizeof (demux->stream));
demux->seekable = FALSE;
break; break;
} }
default: default:

View file

@ -116,6 +116,8 @@ struct _GstASFDemux {
guint64 preroll; guint64 preroll;
guint64 pts; guint64 pts;
gboolean seekable;
/* expected byte offset of next buffer to be received by chain /* expected byte offset of next buffer to be received by chain
* function. Used to calculate the current byte offset into the * function. Used to calculate the current byte offset into the
* file from the adapter state and the data parser state */ * file from the adapter state and the data parser state */