mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
asfdemux: Handle chained asfs on pull mode
Adds chained asfs handling to pull mode. It now checks if there is a new asf header after the last packet (when it is possible to know how many packets are) or it tries checking if a processed packet that fails is an header object. Fixes #599718
This commit is contained in:
parent
dc65baacf6
commit
a155733bff
2 changed files with 119 additions and 19 deletions
|
@ -225,8 +225,11 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
|
|||
--demux->num_streams;
|
||||
}
|
||||
memset (demux->stream, 0, sizeof (demux->stream));
|
||||
demux->num_audio_streams = 0;
|
||||
demux->num_video_streams = 0;
|
||||
if (!chain_reset) {
|
||||
/* do not remove those for not adding pads with same name */
|
||||
demux->num_audio_streams = 0;
|
||||
demux->num_video_streams = 0;
|
||||
}
|
||||
demux->num_streams = 0;
|
||||
demux->activated_streams = FALSE;
|
||||
demux->first_ts = GST_CLOCK_TIME_NONE;
|
||||
|
@ -255,6 +258,8 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
|
|||
demux->data_size = 0;
|
||||
demux->data_offset = 0;
|
||||
demux->index_offset = 0;
|
||||
} else {
|
||||
demux->base_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -782,6 +787,22 @@ asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asf_demux_release_old_pads (GstASFDemux * demux)
|
||||
{
|
||||
GST_DEBUG_OBJECT (demux, "Releasing old pads");
|
||||
|
||||
while (demux->old_num_streams > 0) {
|
||||
gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
|
||||
gst_event_new_eos ());
|
||||
gst_asf_demux_free_stream (demux,
|
||||
&demux->old_stream[demux->old_num_streams - 1]);
|
||||
--demux->old_num_streams;
|
||||
}
|
||||
memset (demux->old_stream, 0, sizeof (demux->old_stream));
|
||||
demux->old_num_streams = 0;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_asf_demux_chain_headers (GstASFDemux * demux)
|
||||
{
|
||||
|
@ -814,15 +835,7 @@ gst_asf_demux_chain_headers (GstASFDemux * demux)
|
|||
goto parse_failed;
|
||||
|
||||
/* release old pads (only happens on chained asfs) */
|
||||
while (demux->old_num_streams > 0) {
|
||||
gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
|
||||
gst_event_new_eos ());
|
||||
gst_asf_demux_free_stream (demux,
|
||||
&demux->old_stream[demux->old_num_streams - 1]);
|
||||
--demux->old_num_streams;
|
||||
}
|
||||
memset (demux->old_stream, 0, sizeof (demux->old_stream));
|
||||
demux->old_num_streams = 0;
|
||||
gst_asf_demux_release_old_pads (demux);
|
||||
|
||||
/* calculate where the packet data starts */
|
||||
demux->data_offset = obj.size + 50;
|
||||
|
@ -1028,7 +1041,7 @@ gst_asf_demux_pull_headers (GstASFDemux * demux)
|
|||
GST_LOG_OBJECT (demux, "reading headers");
|
||||
|
||||
/* pull HEADER object header, so we know its size */
|
||||
if (!gst_asf_demux_pull_data (demux, 0, 16 + 8, &buf, NULL))
|
||||
if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
|
||||
goto read_failed;
|
||||
|
||||
asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
|
||||
|
@ -1040,7 +1053,8 @@ gst_asf_demux_pull_headers (GstASFDemux * demux)
|
|||
GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
|
||||
|
||||
/* pull HEADER object */
|
||||
if (!gst_asf_demux_pull_data (demux, 0, obj.size, &buf, NULL))
|
||||
if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
|
||||
NULL))
|
||||
goto read_failed;
|
||||
|
||||
size = obj.size; /* don't want obj.size changed */
|
||||
|
@ -1052,11 +1066,15 @@ gst_asf_demux_pull_headers (GstASFDemux * demux)
|
|||
goto parse_failed;
|
||||
}
|
||||
|
||||
/* release old pads (only happens on chained asfs) */
|
||||
gst_asf_demux_release_old_pads (demux);
|
||||
|
||||
/* calculate where the packet data starts */
|
||||
demux->data_offset = obj.size + 50;
|
||||
demux->data_offset = demux->base_offset + obj.size + 50;
|
||||
|
||||
/* now pull beginning of DATA object before packet data */
|
||||
if (!gst_asf_demux_pull_data (demux, obj.size, 50, &buf, NULL))
|
||||
if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
|
||||
NULL))
|
||||
goto read_failed;
|
||||
|
||||
if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
|
||||
|
@ -1400,6 +1418,52 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
|
|||
return gst_asf_demux_aggregate_flow_return (demux);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
|
||||
{
|
||||
AsfObject obj;
|
||||
g_assert (buf != NULL);
|
||||
|
||||
GST_LOG_OBJECT (demux, "Checking if buffer is a header");
|
||||
|
||||
/* we return false on buffer too small */
|
||||
if (GST_BUFFER_SIZE (buf) < ASF_OBJECT_HEADER_SIZE)
|
||||
return FALSE;
|
||||
|
||||
/* check if it is a header */
|
||||
asf_demux_peek_object (demux, GST_BUFFER_DATA (buf),
|
||||
ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
|
||||
if (obj.id == ASF_OBJ_HEADER) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_asf_demux_check_chained_asf (GstASFDemux * demux)
|
||||
{
|
||||
guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstBuffer *buf = NULL;
|
||||
gboolean header = FALSE;
|
||||
|
||||
/* TODO maybe we should skip index objects after the data and look
|
||||
* further for a new header */
|
||||
if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
|
||||
g_assert (buf != NULL);
|
||||
/* check if it is a header */
|
||||
if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
|
||||
GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
|
||||
demux->base_offset = off;
|
||||
header = TRUE;
|
||||
}
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asf_demux_loop (GstASFDemux * demux)
|
||||
{
|
||||
|
@ -1442,8 +1506,20 @@ gst_asf_demux_loop (GstASFDemux * demux)
|
|||
if (G_LIKELY (demux->speed_packets == 1)) {
|
||||
/* FIXME: maybe we should just skip broken packets and error out only
|
||||
* after a few broken packets in a row? */
|
||||
if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf)))
|
||||
if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
|
||||
/* when we don't know when the data object ends, we should check
|
||||
* for a chained asf */
|
||||
if (demux->num_packets == 0) {
|
||||
if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
|
||||
GST_INFO_OBJECT (demux, "Chained asf found");
|
||||
demux->base_offset = off;
|
||||
gst_asf_demux_reset (demux, TRUE);
|
||||
gst_buffer_unref (buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
|
||||
|
||||
|
@ -1459,8 +1535,21 @@ gst_asf_demux_loop (GstASFDemux * demux)
|
|||
demux->packet_size);
|
||||
/* FIXME: maybe we should just skip broken packets and error out only
|
||||
* after a few broken packets in a row? */
|
||||
if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub)))
|
||||
if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub))) {
|
||||
/* when we don't know when the data object ends, we should check
|
||||
* for a chained asf */
|
||||
if (demux->num_packets == 0) {
|
||||
if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
|
||||
GST_INFO_OBJECT (demux, "Chained asf found");
|
||||
demux->base_offset = off + n * demux->packet_size;
|
||||
gst_asf_demux_reset (demux, TRUE);
|
||||
gst_buffer_unref (sub);
|
||||
gst_buffer_unref (buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
gst_buffer_unref (sub);
|
||||
|
||||
|
@ -1513,7 +1602,13 @@ eos:
|
|||
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
||||
gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
|
||||
stop));
|
||||
} else {
|
||||
} else if (flow != GST_FLOW_UNEXPECTED) {
|
||||
/* check if we have a chained asf, in case, we don't eos yet */
|
||||
if (gst_asf_demux_check_chained_asf (demux)) {
|
||||
GST_INFO_OBJECT (demux, "Chained ASF starting");
|
||||
gst_asf_demux_reset (demux, TRUE);
|
||||
return;
|
||||
}
|
||||
/* normal playback, send EOS to all linked pads */
|
||||
GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
|
||||
gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
|
||||
|
@ -3827,6 +3922,7 @@ gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
|
|||
demux->data_size = 0;
|
||||
demux->data_offset = 0;
|
||||
demux->index_offset = 0;
|
||||
demux->base_offset = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -132,7 +132,11 @@ struct _GstASFDemux {
|
|||
GstAdapter *adapter;
|
||||
GstTagList *taglist;
|
||||
GstAsfDemuxState state;
|
||||
|
||||
|
||||
/* byte offset where the asf starts, which might not be zero on chained
|
||||
* asfs, index_offset and data_offset already are 'offseted' by base_offset */
|
||||
guint64 base_offset;
|
||||
|
||||
guint64 index_offset; /* byte offset where index might be, or 0 */
|
||||
guint64 data_offset; /* byte offset where packets start */
|
||||
guint64 data_size; /* total size of packet data in bytes, or 0 */
|
||||
|
|
Loading…
Reference in a new issue