dashdemux: Store parsed moof and extract offsets of sync samples in it

https://bugzilla.gnome.org/show_bug.cgi?id=741104
This commit is contained in:
Sebastian Dröge 2016-05-30 11:15:03 +03:00
parent 6dbfb1133c
commit 5b943135ac
2 changed files with 213 additions and 26 deletions

View file

@ -216,6 +216,12 @@ struct _GstDashDemuxClockDrift
GstClock *ntp_clock; GstClock *ntp_clock;
}; };
typedef struct
{
guint64 start_offset, end_offset;
/* TODO: Timestamp and duration */
} GstDashStreamSyncSample;
/* GObject */ /* GObject */
static void gst_dash_demux_set_property (GObject * object, guint prop_id, static void gst_dash_demux_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec); const GValue * value, GParamSpec * pspec);
@ -1172,6 +1178,13 @@ gst_dash_demux_stream_seek (GstAdaptiveDemuxStream * stream, gboolean forward,
GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream; GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux); GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
if (dashstream->moof)
gst_isoff_moof_box_free (dashstream->moof);
dashstream->moof = NULL;
if (dashstream->moof_sync_samples)
g_array_free (dashstream->moof_sync_samples, TRUE);
dashstream->moof_sync_samples = NULL;
if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) { if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
if (dashstream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) { if (dashstream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
gst_dash_demux_stream_sidx_seek (dashstream, forward, flags, ts, gst_dash_demux_stream_sidx_seek (dashstream, forward, flags, ts,
@ -1266,6 +1279,13 @@ gst_dash_demux_clear_pending_stream_data (GstDashDemux * dashdemux,
dashstream->isobmff_parser.current_start_offset = 0; dashstream->isobmff_parser.current_start_offset = 0;
dashstream->isobmff_parser.current_offset = 0; dashstream->isobmff_parser.current_offset = 0;
dashstream->isobmff_parser.current_size = 0; dashstream->isobmff_parser.current_size = 0;
if (dashstream->moof)
gst_isoff_moof_box_free (dashstream->moof);
dashstream->moof = NULL;
if (dashstream->moof_sync_samples)
g_array_free (dashstream->moof_sync_samples, TRUE);
dashstream->moof_sync_samples = NULL;
} }
static GstFlowReturn static GstFlowReturn
@ -1276,12 +1296,29 @@ gst_dash_demux_stream_advance_fragment (GstAdaptiveDemuxStream * stream)
GST_DEBUG_OBJECT (stream->pad, "Advance fragment"); GST_DEBUG_OBJECT (stream->pad, "Advance fragment");
if (dashstream->isobmff_adapter)
gst_adapter_clear (dashstream->isobmff_adapter);
dashstream->isobmff_parser.current_fourcc = 0;
dashstream->isobmff_parser.current_start_offset = 0;
dashstream->isobmff_parser.current_offset = 0;
dashstream->isobmff_parser.current_size = 0;
if (dashstream->moof)
gst_isoff_moof_box_free (dashstream->moof);
dashstream->moof = NULL;
if (dashstream->moof_sync_samples)
g_array_free (dashstream->moof_sync_samples, TRUE);
dashstream->moof_sync_samples = NULL;
if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) { if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
if (gst_dash_demux_stream_advance_subfragment (stream)) if (gst_dash_demux_stream_advance_subfragment (stream))
return GST_FLOW_OK; return GST_FLOW_OK;
} }
gst_dash_demux_clear_pending_stream_data (dashdemux, dashstream); gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
gst_isoff_sidx_parser_init (&dashstream->sidx_parser);
if (dashstream->sidx_adapter)
gst_adapter_clear (dashstream->sidx_adapter);
return gst_mpd_client_advance_segment (dashdemux->client, return gst_mpd_client_advance_segment (dashdemux->client,
dashstream->active_stream, stream->demux->segment.rate > 0.0); dashstream->active_stream, stream->demux->segment.rate > 0.0);
@ -1805,12 +1842,13 @@ gst_dash_demux_parse_isobmff (GstAdaptiveDemux * demux,
if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MOOF) { if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MOOF) {
GstByteReader sub_reader; GstByteReader sub_reader;
GstMoofBox *moof;
g_assert (dash_stream->moof == NULL);
g_assert (dash_stream->moof_sync_samples == NULL);
gst_byte_reader_get_sub_reader (&reader, &sub_reader, size - header_size); gst_byte_reader_get_sub_reader (&reader, &sub_reader, size - header_size);
moof = gst_isoff_moof_box_parse (&sub_reader); dash_stream->moof = gst_isoff_moof_box_parse (&sub_reader);
/* TODO: Do something with this */ dash_stream->moof_offset =
gst_isoff_moof_box_free (moof); dash_stream->isobmff_parser.current_start_offset;
} else { } else {
gst_byte_reader_skip (&reader, size - header_size); gst_byte_reader_skip (&reader, size - header_size);
} }
@ -1871,6 +1909,132 @@ gst_dash_demux_parse_isobmff (GstAdaptiveDemux * demux,
return NULL; return NULL;
} }
static gboolean
gst_dash_demux_find_sync_samples (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream)
{
GstDashDemuxStream *dash_stream = (GstDashDemuxStream *) stream;
guint i;
guint32 track_id = 0;
guint64 prev_traf_end;
if (!dash_stream->moof)
return FALSE;
dash_stream->moof_sync_samples =
g_array_new (FALSE, FALSE, sizeof (GstDashStreamSyncSample));
prev_traf_end = dash_stream->moof_offset;
/* generate table of keyframes and offsets */
for (i = 0; i < dash_stream->moof->traf->len; i++) {
GstTrafBox *traf = &g_array_index (dash_stream->moof->traf, GstTrafBox, i);
guint64 traf_offset = 0, prev_trun_end;
guint j;
if (i == 0) {
track_id = traf->tfhd.track_id;
} else if (track_id != traf->tfhd.track_id) {
GST_ERROR_OBJECT (stream->pad,
"moof with trafs of different track ids (%u != %u)", track_id,
traf->tfhd.track_id);
g_array_free (dash_stream->moof_sync_samples, TRUE);
dash_stream->moof_sync_samples = NULL;
return FALSE;
}
if (traf->tfhd.flags & GST_TFHD_FLAGS_BASE_DATA_OFFSET_PRESENT) {
traf_offset = traf->tfhd.base_data_offset;
} else if (traf->tfhd.flags & GST_TFHD_FLAGS_DEFAULT_BASE_IS_MOOF) {
traf_offset = dash_stream->moof_offset;
} else {
traf_offset = prev_traf_end;
}
prev_trun_end = traf_offset;
for (j = 0; j < traf->trun->len; j++) {
GstTrunBox *trun = &g_array_index (traf->trun, GstTrunBox, j);
guint64 trun_offset, prev_sample_end;
guint k;
if (trun->flags & GST_TRUN_FLAGS_DATA_OFFSET_PRESENT) {
trun_offset = traf_offset + trun->data_offset;
} else {
trun_offset = prev_trun_end;
}
prev_sample_end = trun_offset;
for (k = 0; k < trun->samples->len; k++) {
GstTrunSample *sample =
&g_array_index (trun->samples, GstTrunSample, k);
guint64 sample_offset;
guint32 sample_flags;
#if 0
guint32 sample_duration;
#endif
sample_offset = prev_sample_end;
if (trun->flags & GST_TRUN_FLAGS_SAMPLE_FLAGS_PRESENT) {
sample_flags = sample->sample_flags;
} else if ((trun->flags & GST_TRUN_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT)
&& k == 0) {
sample_flags = trun->first_sample_flags;
} else if (traf->
tfhd.flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT) {
sample_flags = traf->tfhd.default_sample_flags;
} else {
GST_ERROR_OBJECT (stream->pad, "Sample flags given by trex");
g_array_free (dash_stream->moof_sync_samples, TRUE);
dash_stream->moof_sync_samples = NULL;
return FALSE;
}
#if 0
if (trun->flags & GST_TRUN_FLAGS_SAMPLE_DURATION_PRESENT) {
sample_duration = sample->sample_duration;
} else if (traf->
tfhd.flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT) {
sample_duration = traf->tfhd.default_sample_duration;
} else {
GST_ERROR_OBJECT (stream->pad, "Sample duration given by trex");
g_array_free (dash_stream->moof_sync_samples, TRUE);
dash_stream->moof_sync_samples = NULL;
return FALSE;
}
#endif
if (trun->flags & GST_TRUN_FLAGS_SAMPLE_SIZE_PRESENT) {
prev_sample_end += sample->sample_size;
} else if (traf->
tfhd.flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT) {
prev_sample_end += traf->tfhd.default_sample_size;
} else {
GST_ERROR_OBJECT (stream->pad, "Sample size given by trex");
g_array_free (dash_stream->moof_sync_samples, TRUE);
dash_stream->moof_sync_samples = NULL;
return FALSE;
}
/* Non-non-sync sample aka sync sample */
if (!GST_ISOFF_SAMPLE_FLAGS_SAMPLE_IS_NON_SYNC_SAMPLE (sample_flags)) {
GstDashStreamSyncSample sync_sample =
{ sample_offset, prev_sample_end - 1 };
/* TODO: need timestamps so we can decide to download or not */
g_array_append_val (dash_stream->moof_sync_samples, sync_sample);
}
}
prev_trun_end = prev_sample_end;
}
prev_traf_end = prev_trun_end;
}
return TRUE;
}
static GstFlowReturn static GstFlowReturn
gst_dash_demux_data_received (GstAdaptiveDemux * demux, gst_dash_demux_data_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream, GstBuffer * buffer) GstAdaptiveDemuxStream * stream, GstBuffer * buffer)
@ -1891,13 +2055,21 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
buffer)) != GST_FLOW_OK) buffer)) != GST_FLOW_OK)
return ret; return ret;
if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT) {
&& gst_adapter_available (dash_stream->isobmff_adapter) > 0) { gst_dash_demux_find_sync_samples (demux, stream);
if (gst_adapter_available (dash_stream->isobmff_adapter) > 0) {
buffer = buffer =
gst_adapter_take_buffer (dash_stream->isobmff_adapter, gst_adapter_take_buffer (dash_stream->isobmff_adapter,
gst_adapter_available (dash_stream->isobmff_adapter)); gst_adapter_available (dash_stream->isobmff_adapter));
GST_BUFFER_OFFSET (buffer) =
dash_stream->isobmff_parser.current_offset;
dash_stream->isobmff_parser.current_offset +=
gst_buffer_get_size (buffer);
GST_BUFFER_OFFSET_END (buffer) =
dash_stream->isobmff_parser.current_offset;
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer); ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
} }
}
return ret; return ret;
} }
@ -2004,8 +2176,9 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
/* Leftover in the adapter is actual mdat data if any */ /* Leftover in the adapter is actual mdat data if any */
if (dash_stream->isobmff_parser.current_fourcc == if (dash_stream->isobmff_parser.current_fourcc ==
GST_ISOFF_FOURCC_MDAT GST_ISOFF_FOURCC_MDAT) {
&& gst_adapter_available (dash_stream->isobmff_adapter) > 0) { gst_dash_demux_find_sync_samples (demux, stream);
if (gst_adapter_available (dash_stream->isobmff_adapter) > 0) {
GstBuffer *buffer2 = GstBuffer *buffer2 =
gst_adapter_take_buffer (dash_stream->isobmff_adapter, gst_adapter_take_buffer (dash_stream->isobmff_adapter,
gst_adapter_available (dash_stream->isobmff_adapter)); gst_adapter_available (dash_stream->isobmff_adapter));
@ -2015,6 +2188,7 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
else else
buffer = buffer2; buffer = buffer2;
} }
}
g_assert (buffer || !advance); g_assert (buffer || !advance);
} }
@ -2054,13 +2228,22 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
buffer)) != GST_FLOW_OK) buffer)) != GST_FLOW_OK)
return ret; return ret;
if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT) {
&& gst_adapter_available (dash_stream->isobmff_adapter) > 0) { gst_dash_demux_find_sync_samples (demux, stream);
if (gst_adapter_available (dash_stream->isobmff_adapter) > 0) {
buffer = buffer =
gst_adapter_take_buffer (dash_stream->isobmff_adapter, gst_adapter_take_buffer (dash_stream->isobmff_adapter,
gst_adapter_available (dash_stream->isobmff_adapter)); gst_adapter_available (dash_stream->isobmff_adapter));
GST_BUFFER_OFFSET (buffer) =
dash_stream->isobmff_parser.current_offset;
dash_stream->isobmff_parser.current_offset +=
gst_buffer_get_size (buffer);
GST_BUFFER_OFFSET_END (buffer) =
dash_stream->isobmff_parser.current_offset;
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer); ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
} }
}
return ret; return ret;
} }

View file

@ -88,6 +88,10 @@ struct _GstDashDemuxStream
guint64 current_offset; guint64 current_offset;
guint64 current_size; guint64 current_size;
} isobmff_parser; } isobmff_parser;
GstMoofBox *moof;
guint64 moof_offset;
GArray *moof_sync_samples;
}; };
/** /**