GST_DEBUG ("No useful SegmentList node for the current Representation");
/* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0,
- PeriodEnd - PeriodStart, 0, PeriodEnd - PeriodStart)) {
+ PeriodEnd - PeriodStart, PeriodStart, PeriodEnd - PeriodStart)) {
return FALSE;
}
} else {
/* build segment list */
i = stream->cur_segment_list->MultSegBaseType->startNumber;
start = 0;
- start_time = 0;
+ start_time = PeriodStart;
GST_LOG ("Building media segment list using a SegmentList node");
if (stream->cur_segment_list->MultSegBaseType->SegmentTimeline) {
GstSegmentTimelineNode *timeline;
GstSNode *S;
GList *list;
-
+ GstClockTime presentationTimeOffset;
+ GstSegmentBaseType *segbase;
+
+ segbase = stream->cur_segment_list->MultSegBaseType->SegBaseType;
+ presentationTimeOffset =
+ gst_util_uint64_scale (segbase->presentationTimeOffset, GST_SECOND,
+ segbase->timescale);
+ GST_LOG ("presentationTimeOffset = %" G_GUINT64_FORMAT,
+ presentationTimeOffset);
timeline = stream->cur_segment_list->MultSegBaseType->SegmentTimeline;
for (list = g_queue_peek_head_link (&timeline->S); list;
list = g_list_next (list)) {
if (S->t > 0) {
start = S->t;
- start_time = gst_util_uint64_scale (S->t, GST_SECOND, timescale);
+ start_time = gst_util_uint64_scale (S->t, GST_SECOND, timescale)
+ + PeriodStart - presentationTimeOffset;
}
if (!SegmentURL) {
return FALSE;
}
} else {
+ GstClockTime presentationTimeOffset;
GstMultSegmentBaseType *mult_seg =
stream->cur_seg_template->MultSegBaseType;
+
+ presentationTimeOffset =
+ gst_util_uint64_scale (mult_seg->SegBaseType->presentationTimeOffset,
+ GST_SECOND, mult_seg->SegBaseType->timescale);
+ GST_LOG ("presentationTimeOffset = %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (presentationTimeOffset));
/* build segment list */
i = mult_seg->startNumber;
start = 0;
duration = gst_util_uint64_scale (S->d, GST_SECOND, timescale);
if (S->t > 0) {
start = S->t;
- start_time = gst_util_uint64_scale (S->t, GST_SECOND, timescale);
+ start_time = gst_util_uint64_scale (S->t, GST_SECOND, timescale)
+ + PeriodStart - presentationTimeOffset;
}
if (!gst_mpd_client_add_media_segment (stream, NULL, i, S->r, start,
GstMediaSegment *media_segment =
g_ptr_array_index (stream->segments, n);
if (media_segment) {
- if (media_segment->start + media_segment->duration >
- PeriodEnd - PeriodStart) {
- GstClockTime stop = PeriodEnd - PeriodStart;
+ if (media_segment->start + media_segment->duration > PeriodEnd) {
+ GstClockTime stop = PeriodEnd;
if (n < stream->segments->len - 1) {
GstMediaSegment *next_segment =
g_ptr_array_index (stream->segments, n + 1);
- if (next_segment && next_segment->start < PeriodEnd - PeriodStart)
+ if (next_segment && next_segment->start < PeriodEnd)
stop = next_segment->start;
}
media_segment->duration =
*ts = stream_period->start + stream_period->duration;
} else {
segment_idx = gst_mpd_client_get_segments_counts (client, stream) - 1;
+ if (segment_idx >= stream->segments->len) {
+ GST_WARNING ("Segment index %d is outside of segment list of length %d",
+ segment_idx, stream->segments->len);
+ return FALSE;
+ }
currentChunk = g_ptr_array_index (stream->segments, segment_idx);
if (currentChunk->repeat >= 0) {
{
GstDateTime *availability_start_time, *rv;
gint seg_idx;
- GstStreamPeriod *stream_period;
GstMediaSegment *segment;
GstClockTime segmentEndTime;
+ const GstStreamPeriod *stream_period;
+ GstClockTime period_start = 0;
g_return_val_if_fail (client != NULL, NULL);
g_return_val_if_fail (stream != NULL, NULL);
stream_period = gst_mpdparser_get_stream_period (client);
+ if (stream_period && stream_period->period) {
+ period_start = stream_period->start;
+ }
seg_idx = stream->segment_index;
g_ptr_array_index (stream->segments, seg_idx + 1);
segmentEndTime = next_segment->start;
} else {
- const GstStreamPeriod *stream_period;
- stream_period = gst_mpdparser_get_stream_period (client);
- segmentEndTime = stream_period->start + stream_period->duration;
+ g_return_val_if_fail (stream_period != NULL, NULL);
+ segmentEndTime = period_start + stream_period->duration;
}
} else {
GstClockTime seg_duration;
seg_duration = gst_mpd_client_get_segment_duration (client, stream, NULL);
if (seg_duration == 0)
return NULL;
- segmentEndTime = (1 + seg_idx) * seg_duration;
+ segmentEndTime = period_start + (1 + seg_idx) * seg_duration;
}
availability_start_time = gst_mpd_client_get_availability_start_time (client);
return NULL;
}
- if (stream_period && stream_period->period) {
- GstDateTime *t =
- gst_mpd_client_add_time_difference (availability_start_time,
- stream_period->start / GST_USECOND);
- gst_date_time_unref (availability_start_time);
- availability_start_time = t;
-
- if (availability_start_time == NULL) {
- GST_WARNING_OBJECT (client, "Failed to offset availability_start_time");
- return NULL;
- }
- }
-
rv = gst_mpd_client_add_time_difference (availability_start_time,
segmentEndTime / GST_USECOND);
gst_date_time_unref (availability_start_time);
GST_END_TEST;
/*
+ * Test parsing Period SegmentTemplate attributes where a
+ * presentationTimeOffset attribute has been specified
+ *
+ */
+GST_START_TEST (dash_mpdparser_period_segmentTemplateWithPresentationTimeOffset)
+{
+ const gchar *xml =
+ "<?xml version=\"1.0\"?>"
+ "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
+ " profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
+ " <Period start=\"PT1M\" duration=\"PT40S\">"
+ " <AdaptationSet"
+ " bitstreamSwitching=\"false\""
+ " mimeType=\"video/mp4\""
+ " contentType=\"video\">"
+ " <SegmentTemplate media=\"$RepresentationID$/TestMedia-$Time$.mp4\""
+ " index=\"$RepresentationID$/TestIndex.mp4\""
+ " timescale=\"100\""
+ " presentationTimeOffset=\"6000\""
+ " initialization=\"$RepresentationID$/TestInitialization\""
+ " bitstreamSwitching=\"true\">"
+ " <SegmentTimeline>"
+ " <S d=\"400\" r=\"9\" t=\"100\"/>"
+ " </SegmentTimeline></SegmentTemplate>"
+ " <Representation bandwidth=\"95866\" frameRate=\"90000/3600\""
+ " id=\"vrep\" /></AdaptationSet></Period></MPD>";
+
+ gboolean ret;
+ GList *adaptationSets;
+ GstAdaptationSetNode *adapt_set;
+ GstActiveStream *activeStream;
+ GstMediaFragmentInfo fragment;
+ GstClockTime expectedDuration;
+ GstClockTime expectedTimestamp;
+ GstMpdClient *mpdclient;
+ GstPeriodNode *periodNode;
+ GstSegmentTemplateNode *segmentTemplate;
+
+ mpdclient = gst_mpd_client_new ();
+ ret = gst_mpd_parse (mpdclient, xml, (gint) strlen (xml));
+ assert_equals_int (ret, TRUE);
+
+ ret =
+ gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
+ -1, NULL);
+ assert_equals_int (ret, TRUE);
+
+ periodNode =
+ (GstPeriodNode *) g_list_nth_data (mpdclient->mpd_node->Periods, 0);
+ fail_if (periodNode == NULL);
+
+ /* get the list of adaptation sets of the first period */
+ adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
+ fail_if (adaptationSets == NULL);
+
+ /* setup streaming from the first adaptation set */
+ adapt_set = (GstAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
+ fail_if (adapt_set == NULL);
+ ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
+ assert_equals_int (ret, TRUE);
+ activeStream = gst_mpdparser_get_active_stream_by_index (mpdclient, 0);
+ fail_if (activeStream == NULL);
+
+ segmentTemplate = adapt_set->SegmentTemplate;
+ fail_if (segmentTemplate == NULL);
+ assert_equals_string (segmentTemplate->media,
+ "$RepresentationID$/TestMedia-$Time$.mp4");
+ assert_equals_string (segmentTemplate->index,
+ "$RepresentationID$/TestIndex.mp4");
+ assert_equals_string (segmentTemplate->initialization,
+ "$RepresentationID$/TestInitialization");
+ assert_equals_string (segmentTemplate->bitstreamSwitching, "true");
+
+ ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
+ assert_equals_int (ret, TRUE);
+ expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 4, 0);
+ /* start = Period@start + S@t - presentationTimeOffset */
+ expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 1, 0);
+ assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
+ assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
+ /* the $Time$ expansion uses the @t value, without including
+ Period@start or presentationTimeOffset */
+ assert_equals_string (fragment.uri, "/vrep/TestMedia-100.mp4");
+ gst_media_fragment_info_clear (&fragment);
+
+ gst_mpd_client_free (mpdclient);
+}
+
+GST_END_TEST;
+
+/*
* Test parsing Period SegmentTemplate MultipleSegmentBaseType attributes
*
*/
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_segmentList_segmentURL);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_segmentTemplate);
tcase_add_test (tc_simpleMPD,
+ dash_mpdparser_period_segmentTemplateWithPresentationTimeOffset);
+ tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentBaseType);