gst/realmedia/rmdemux.c: Real demuxer fixes. Make it more bulletproof against bad data, identify a few more stream ty...

Original commit message from CVS:
* gst/realmedia/rmdemux.c: (gst_rmdemux_src_event),
(gst_rmdemux_perform_seek), (gst_rmdemux_loop),
(gst_rmdemux_send_event), (gst_rmdemux_add_stream),
(gst_rmdemux_parse_mdpr), (gst_rmdemux_parse_packet):
Real demuxer fixes. Make it more bulletproof against bad data,
identify a few more stream types.
Fix seeking so that it works (at least with the seek example
program; it still fails with totem).
This commit is contained in:
Michael Smith 2005-09-29 13:44:15 +00:00
parent b293389291
commit 3dc55cb75e
2 changed files with 90 additions and 19 deletions

View file

@ -1,3 +1,14 @@
2005-09-29 Michael Smith <msmith@fluendo.com>
* gst/realmedia/rmdemux.c: (gst_rmdemux_src_event),
(gst_rmdemux_perform_seek), (gst_rmdemux_loop),
(gst_rmdemux_send_event), (gst_rmdemux_add_stream),
(gst_rmdemux_parse_mdpr), (gst_rmdemux_parse_packet):
Real demuxer fixes. Make it more bulletproof against bad data,
identify a few more stream types.
Fix seeking so that it works (at least with the seek example program;
it still fails with totem).
2005-09-26 Wim Taymans <wim@fluendo.com> 2005-09-26 Wim Taymans <wim@fluendo.com>
* gst/mpegaudioparse/gstmpegaudioparse.c: * gst/mpegaudioparse/gstmpegaudioparse.c:

View file

@ -311,8 +311,33 @@ gst_rmdemux_src_event (GstPad * pad, GstEvent * event)
GST_DEBUG ("can only seek on TIME"); GST_DEBUG ("can only seek on TIME");
goto done_unref; goto done_unref;
} }
rmdemux->segment_start = cur;
rmdemux->segment_stop = stop; GST_LOCK (rmdemux);
if (cur_type == GST_SEEK_TYPE_SET)
rmdemux->segment_start = cur;
else if (cur_type == GST_SEEK_TYPE_CUR)
rmdemux->segment_start += cur;
else if (cur_type == GST_SEEK_TYPE_END)
rmdemux->segment_start = rmdemux->duration + cur;
if (stop_type == GST_SEEK_TYPE_SET)
rmdemux->segment_stop = stop;
else if (cur_type == GST_SEEK_TYPE_CUR)
rmdemux->segment_stop += cur;
else if (cur_type == GST_SEEK_TYPE_END)
rmdemux->segment_stop = rmdemux->duration + cur;
/* Now do a sanity-check */
if (rmdemux->segment_stop < rmdemux->segment_start) {
GST_UNLOCK (rmdemux);
ret = FALSE;
GST_DEBUG_OBJECT (rmdemux, "Seek had stop " G_GUINT64_FORMAT " < start "
G_GUINT64_FORMAT ", cannot perform seek",
rmdemux->segment_stop, rmdemux->segment_start);
goto done_unref;
}
rmdemux->segment_play = !!(flags & GST_SEEK_FLAG_SEGMENT); rmdemux->segment_play = !!(flags & GST_SEEK_FLAG_SEGMENT);
flush = !!(flags & GST_SEEK_FLAG_FLUSH); flush = !!(flags & GST_SEEK_FLAG_FLUSH);
gst_event_unref (event); gst_event_unref (event);
@ -322,7 +347,6 @@ gst_rmdemux_src_event (GstPad * pad, GstEvent * event)
GST_TIME_ARGS (rmdemux->segment_stop)); GST_TIME_ARGS (rmdemux->segment_stop));
/* check if we can do the seek now */ /* check if we can do the seek now */
GST_LOCK (rmdemux);
running = rmdemux->running; running = rmdemux->running;
GST_UNLOCK (rmdemux); GST_UNLOCK (rmdemux);
@ -360,12 +384,21 @@ gst_rmdemux_perform_seek (GstRMDemux * rmdemux, gboolean flush)
rmdemux->segment_stop = CLAMP (rmdemux->segment_stop, 0, rmdemux->duration); rmdemux->segment_stop = CLAMP (rmdemux->segment_stop, 0, rmdemux->duration);
/* first step is to unlock the streaming thread if it is /* first step is to unlock the streaming thread if it is
* blocked in a chain call, we do this by starting the flush. because * blocked in a chain call, we do this by starting the flush. */
* we cannot yet hold any streaming lock, we have to protect the chains
* with their own lock. */
if (flush) { if (flush) {
gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_start ()); gboolean res;
gst_rmdemux_send_event (rmdemux, gst_event_new_flush_start ());
GST_DEBUG_OBJECT (rmdemux, "About to send flush_start events");
res = gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_start ());
if (!res) {
GST_WARNING_OBJECT (rmdemux, "Failed to push event upstream!");
}
res = gst_rmdemux_send_event (rmdemux, gst_event_new_flush_start ());
if (!res) {
GST_WARNING_OBJECT (rmdemux, "Failed to push event downstream!");
}
GST_DEBUG_OBJECT (rmdemux, "Sent flush_start events");
} else { } else {
gst_pad_pause_task (rmdemux->sinkpad); gst_pad_pause_task (rmdemux->sinkpad);
} }
@ -374,10 +407,12 @@ gst_rmdemux_perform_seek (GstRMDemux * rmdemux, gboolean flush)
* non flushing seeks when the element is in PAUSED this could block * non flushing seeks when the element is in PAUSED this could block
* forever. */ * forever. */
GST_STREAM_LOCK (rmdemux->sinkpad); GST_STREAM_LOCK (rmdemux->sinkpad);
GST_DEBUG_OBJECT (rmdemux, "Taken stream lock on sinkpad!");
/* we need to stop flushing on the srcpad as we're going to use it /* we need to stop flushing on the sinkpad as we're going to use it
* next. We can do this as we have the STREAM lock now. */ * next. We can do this as we have the STREAM lock now. */
gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_stop ()); gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_stop ());
GST_DEBUG_OBJECT (rmdemux, "Sent flush_stop downstream");
/* Find the new offset */ /* Find the new offset */
/* Get the video stream */ /* Get the video stream */
@ -612,7 +647,7 @@ gst_rmdemux_loop (GstPad * pad)
{ {
GstRMDemux *rmdemux; GstRMDemux *rmdemux;
GstBuffer *buffer; GstBuffer *buffer;
GstFlowReturn ret; GstFlowReturn ret = GST_FLOW_OK;
guint size; guint size;
rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad)); rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
@ -633,6 +668,8 @@ gst_rmdemux_loop (GstPad * pad)
case RMDEMUX_STATE_EOS: case RMDEMUX_STATE_EOS:
goto need_pause; goto need_pause;
default: default:
GST_LOG_OBJECT (rmdemux, "Default: requires %d bytes",
(int) rmdemux->size);
size = rmdemux->size; size = rmdemux->size;
} }
@ -649,8 +686,9 @@ gst_rmdemux_loop (GstPad * pad)
return; return;
} else { } else {
GST_DEBUG_OBJECT (rmdemux, GST_DEBUG_OBJECT (rmdemux,
"Unable to pull data at offset %p (pull_range returned %d)", "Unable to pull %d bytes at offset %p (pull_range returned %d, state is %d)",
rmdemux->offset, ret); (int) size, rmdemux->offset, ret, GST_STATE (rmdemux));
ret = GST_FLOW_ERROR;
goto need_pause; goto need_pause;
} }
} }
@ -658,7 +696,8 @@ gst_rmdemux_loop (GstPad * pad)
size = GST_BUFFER_SIZE (buffer); size = GST_BUFFER_SIZE (buffer);
/* Defer to the chain function */ /* Defer to the chain function */
if (gst_rmdemux_chain (pad, buffer) != GST_FLOW_OK) { ret = gst_rmdemux_chain (pad, buffer);
if (ret != GST_FLOW_OK) {
GST_DEBUG_OBJECT (rmdemux, "Chain flow failed at %p", rmdemux->offset); GST_DEBUG_OBJECT (rmdemux, "Chain flow failed at %p", rmdemux->offset);
goto need_pause; goto need_pause;
} }
@ -698,6 +737,11 @@ need_pause:
{ {
GST_LOG_OBJECT (rmdemux, "pausing task"); GST_LOG_OBJECT (rmdemux, "pausing task");
gst_pad_pause_task (pad); gst_pad_pause_task (pad);
if (GST_FLOW_IS_FATAL (ret)) {
gst_rmdemux_send_event (rmdemux, gst_event_new_eos ());
GST_ELEMENT_ERROR (rmdemux, STREAM, STOPPED, (NULL),
("stream stopped, reason %d", ret));
}
return; return;
} }
} }
@ -968,6 +1012,7 @@ static gboolean
gst_rmdemux_send_event (GstRMDemux * rmdemux, GstEvent * event) gst_rmdemux_send_event (GstRMDemux * rmdemux, GstEvent * event)
{ {
int i; int i;
gboolean ret = TRUE;
for (i = 0; i < rmdemux->n_streams; i++) { for (i = 0; i < rmdemux->n_streams; i++) {
GstRMDemuxStream *stream; GstRMDemuxStream *stream;
@ -977,11 +1022,13 @@ gst_rmdemux_send_event (GstRMDemux * rmdemux, GstEvent * event)
GST_DEBUG_OBJECT (rmdemux, "Pushing event to stream %d", i); GST_DEBUG_OBJECT (rmdemux, "Pushing event to stream %d", i);
gst_event_ref (event); gst_event_ref (event);
gst_pad_push_event (stream->pad, event); ret = gst_pad_push_event (stream->pad, event);
if (!ret)
break;
} }
gst_event_unref (event); gst_event_unref (event);
return TRUE; return ret;
} }
void void
@ -1033,6 +1080,8 @@ gst_rmdemux_add_stream (GstRMDemux * rmdemux, GstRMDemuxStream * stream)
gst_pad_new_from_template (gst_static_pad_template_get gst_pad_new_from_template (gst_static_pad_template_get
(&gst_rmdemux_audiosrc_template), g_strdup_printf ("audio_%02d", (&gst_rmdemux_audiosrc_template), g_strdup_printf ("audio_%02d",
rmdemux->n_audio_streams)); rmdemux->n_audio_streams));
GST_LOG_OBJECT (rmdemux, "Created audio pad \"%s\"",
gst_pad_get_name (stream->pad));
switch (stream->fourcc) { switch (stream->fourcc) {
/* Older RealAudio Codecs */ /* Older RealAudio Codecs */
case GST_RM_AUD_14_4: case GST_RM_AUD_14_4:
@ -1074,6 +1123,7 @@ gst_rmdemux_add_stream (GstRMDemux * rmdemux, GstRMDemuxStream * stream)
/* RALF is lossless */ /* RALF is lossless */
case GST_RM_AUD_RALF: case GST_RM_AUD_RALF:
GST_DEBUG_OBJECT (rmdemux, "RALF");
stream->caps = gst_caps_new_simple ("audio/x-ralf-mpeg4-generic", NULL); stream->caps = gst_caps_new_simple ("audio/x-ralf-mpeg4-generic", NULL);
break; break;
@ -1084,7 +1134,8 @@ gst_rmdemux_add_stream (GstRMDemux * rmdemux, GstRMDemuxStream * stream)
default: default:
GST_WARNING_OBJECT (rmdemux, GST_WARNING_OBJECT (rmdemux,
"Unknown audio FOURCC code " GST_FOURCC_FORMAT, stream->fourcc); "Unknown audio FOURCC code \"" GST_FOURCC_FORMAT "\"",
stream->fourcc);
break; break;
} }
@ -1116,7 +1167,7 @@ gst_rmdemux_add_stream (GstRMDemux * rmdemux, GstRMDemuxStream * stream)
rmdemux->n_streams++; rmdemux->n_streams++;
GST_LOG_OBJECT (rmdemux, "n_streams is now %d", rmdemux->n_streams); GST_LOG_OBJECT (rmdemux, "n_streams is now %d", rmdemux->n_streams);
if (stream->pad) { if (stream->pad && stream->caps) {
GST_DEBUG_OBJECT (rmdemux, "setting caps: %p", stream->caps); GST_DEBUG_OBJECT (rmdemux, "setting caps: %p", stream->caps);
gst_pad_set_caps (stream->pad, stream->caps); gst_pad_set_caps (stream->pad, stream->caps);
@ -1145,8 +1196,8 @@ gst_rmdemux_add_stream (GstRMDemux * rmdemux, GstRMDemuxStream * stream)
if (gst_pad_alloc_buffer (stream->pad, GST_BUFFER_OFFSET_NONE, if (gst_pad_alloc_buffer (stream->pad, GST_BUFFER_OFFSET_NONE,
stream->extra_data_size, stream->caps, &buffer) != GST_FLOW_OK) { stream->extra_data_size, stream->caps, &buffer) != GST_FLOW_OK) {
GST_WARNING_OBJECT (rmdemux, "failed to alloc src buffer for stream %d", GST_WARNING_OBJECT (rmdemux, "failed to alloc extra_data src "
stream->id); "buffer for stream %d", stream->id);
return; return;
} }
@ -1284,6 +1335,9 @@ gst_rmdemux_parse_mdpr (GstRMDemux * rmdemux, const void *data, int length)
stream_type = GST_RMDEMUX_STREAM_VIDEO; stream_type = GST_RMDEMUX_STREAM_VIDEO;
} else if (strcmp (stream2_type_string, "audio/x-pn-realaudio") == 0) { } else if (strcmp (stream2_type_string, "audio/x-pn-realaudio") == 0) {
stream_type = GST_RMDEMUX_STREAM_AUDIO; stream_type = GST_RMDEMUX_STREAM_AUDIO;
} else if (strcmp (stream2_type_string, "audio/x-ralf-mpeg4-generic") == 0) {
/* Another audio type found in the real testsuite */
stream_type = GST_RMDEMUX_STREAM_AUDIO;
} else if (strcmp (stream1_type_string, "") == 0 && } else if (strcmp (stream1_type_string, "") == 0 &&
strcmp (stream2_type_string, "logical-fileinfo") == 0) { strcmp (stream2_type_string, "logical-fileinfo") == 0) {
stream_type = GST_RMDEMUX_STREAM_FILEINFO; stream_type = GST_RMDEMUX_STREAM_FILEINFO;
@ -1490,6 +1544,12 @@ gst_rmdemux_parse_packet (GstRMDemux * rmdemux, const void *data,
stream = gst_rmdemux_get_stream_by_id (rmdemux, id); stream = gst_rmdemux_get_stream_by_id (rmdemux, id);
if (!stream) {
GST_WARNING_OBJECT (rmdemux, "No stream for stream id %d in parsing "
"data packet", id);
return;
}
if ((rmdemux->offset + packet_size) > stream->seek_offset) { if ((rmdemux->offset + packet_size) > stream->seek_offset) {
if (gst_pad_alloc_buffer (stream->pad, GST_BUFFER_OFFSET_NONE, if (gst_pad_alloc_buffer (stream->pad, GST_BUFFER_OFFSET_NONE,
packet_size, stream->caps, &buffer) != GST_FLOW_OK) { packet_size, stream->caps, &buffer) != GST_FLOW_OK) {