Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

Fix publish time #44

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion dashlivesim/dashlib/configprocessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def update_with_modulo_period(self, modulo_period, seg_dur):
self.media_presentation_duration = modulo_period.media_presentation_duration
self.availability_end_time = modulo_period.availability_end_time
self.last_segment_numbers.append(modulo_period.calc_last_segment_number(seg_dur))
self.publish_time = modulo_period.publish_time

def update_with_aet(self, now_int, availability_end_times, media_presentation_durations):
"Find the proper availabilityEndTime and mediaPresentation duration for now and set in cfg."
Expand Down Expand Up @@ -397,9 +398,9 @@ def process_url(self, url_parts, now_int=0):
cfg.update_for_tfdt32(now_int)
if cont_update_flag:
cfg.update_for_cont_update(now_int)
cfg.update_publish_time(now_int)
if modulo_period is not None:
cfg.update_with_modulo_period(modulo_period, cfg.seg_duration)
cfg.update_publish_time(now_int)

#pylint: disable=no-self-use
def interpret_start_nr(self, value):
Expand Down
10 changes: 8 additions & 2 deletions dashlivesim/dashlib/dash_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class DashSegmentNotAvailableError(DashProxyError):
def generate_period_data(mpd_data, now, cfg):
"""Generate an array of period data depending on current time (now) and tsbd. 0 gives one period with start=1000h.

mpd_data is changed (minimumUpdatePeriod)."""
mpd_data is changed (minimumUpdatePeriod) and publish_time."""
# pylint: disable=too-many-locals

nr_periods_per_hour = min(mpd_data['periodsPerHour'], 60)
Expand All @@ -113,18 +113,20 @@ def generate_period_data(mpd_data, now, cfg):
if mpd_data['insertAd'] > 0:
ad_frequency = nr_periods_per_hour / mpd_data['xlinkPeriodsPerHour']

if nr_periods_per_hour == -1: # Just one period starting at at time start relative AST
if nr_periods_per_hour == -1: # Just one period starting at time start relative AST
start = 0
start_number = mpd_data['startNumber'] + start / seg_dur
data = {'id': "p0", 'start': 'PT%dS' % start, 'startNumber': str(start_number),
'duration': seg_dur, 'presentationTimeOffset': "%d" % mpd_data['presentationTimeOffset'],
'start_s' : start}
period_data.append(data)
cfg.publish_time = cfg.availability_start_time_in_s
elif nr_periods_per_hour == 0: # nrPeriodsPerHour == 0, make one old period but starting 1000h after AST
start = 3600 * 1000
data = {'id': "p0", 'start': 'PT%dS' % start, 'startNumber': "%d" % (start / seg_dur),
'duration': seg_dur, 'presentationTimeOffset': "%d" % start, 'start_s' : start}
period_data.append(data)
cfg.publish_time = cfg.availability_start_time_in_s
else: # nr_periods_per_hour > 0
period_duration = 3600 // nr_periods_per_hour
half_period_duration = period_duration // 2
Expand All @@ -136,6 +138,9 @@ def generate_period_data(mpd_data, now, cfg):
this_period_nr = now // period_duration
last_period_nr = (now + half_period_duration) // period_duration
this_period_start = this_period_nr * period_duration
publish_time = this_period_start - period_duration//2
cfg.publish_time = publish_time

first_period_nr = (now - mpd_data['timeShiftBufferDepthInS'] - seg_dur) // period_duration
counter = 0
for period_nr in range(first_period_nr, last_period_nr+1):
Expand Down Expand Up @@ -408,6 +413,7 @@ def generate_dynamic_mpd(self, cfg, mpd_filename, in_data, now):
'segtimeline': in_data['segtimeline'],
'utc_timing_methods': cfg.utc_timing_methods,
'utc_head_url': self.utc_head_url,
'publish_time': cfg.publish_time,
'now': now}
mpmod = mpdprocessor.MpdProcessor(mpd_filename, mpd_proc_cfg, cfg)
period_data = generate_period_data(mpd_data, now, cfg)
Expand Down
13 changes: 11 additions & 2 deletions dashlivesim/dashlib/moduloperiod.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@ def __init__(self, modulo_minutes, now):
self.percent = self.calc_percent()
self._availability_start_time = self.calc_availability_start_time()
self._minimum_update_period = self.mod_secs/20
self.publish_time = None
self._media_presentation_duration = self.calc_media_pres_dur()
self._availability_end_time = self._availability_start_time + self._media_presentation_duration +\
self._minimum_update_period
self._availability_end_time = (self._availability_start_time
+ self._media_presentation_duration
+self._minimum_update_period)

@property
def availability_start_time(self):
Expand Down Expand Up @@ -92,16 +94,23 @@ def calc_availability_start_time(self):

def calc_media_pres_dur(self):
"Calculate the media presentation duration."
ast = self._availability_start_time
if self.percent < 10:
mpd = 2*self.mod_secs/10
pub_time = ast - self.mod_secs/10
elif self.percent < 30:
mpd = 4*self.mod_secs/10
pub_time = ast + self.mod_secs/10
elif self.percent < 50:
mpd = 6*self.mod_secs/10
pub_time = ast + self.mod_secs*3/10
elif self.percent < 90:
mpd = 8*self.mod_secs/10
pub_time = ast + self.mod_secs*7/10
else:
mpd = 2*self.mod_secs/10 # This is in the next period
pub_time = ast - self.mod_secs/10
self.publish_time = pub_time
return mpd

def get_start_number(self, segment_duration):
Expand Down
20 changes: 16 additions & 4 deletions dashlivesim/dashlib/mpdprocessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# this list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
# * Neither the name of Dash Industry Forum nor the names of its
# contributors may be used to endorse or promote products derived from this software
# contributors ma y be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
Expand Down Expand Up @@ -78,13 +78,19 @@ def __init__(self, infile, mpd_proc_cfg, cfg=None):
self.cfg = cfg
self.root = self.tree.getroot()
self.availability_start_time_in_s = None
self.publish_time = None

def process(self, data, period_data):
"Top-level call to process the XML."
mpd = self.root
self.availability_start_time_in_s = data['availability_start_time_in_s']
self.process_mpd(mpd, data)
self.process_mpd_children(mpd, data, period_data)
self.publish_time = self.cfg.publish_time

def calculate_publishtime(self):
"Calculate the publishtime corresponding to the last segment change."
return self.mpd_proc_cfg['now']

def process_mpd(self, mpd, data):
"""Process the root element (MPD)"""
Expand All @@ -100,13 +106,12 @@ def process_mpd(self, mpd, data):
set_values_from_dict(mpd, key_list, data)
if mpd.attrib.has_key('mediaPresentationDuration') and not data.has_key('mediaPresentationDuration'):
del mpd.attrib['mediaPresentationDuration']
mpd.set('publishTime', make_timestamp(self.mpd_proc_cfg['now'])) #TODO Correlate time with change in MPD
mpd.set('id', 'Config part of url maybe?')
if self.segtimeline:
if mpd.attrib.has_key('maxSegmentDuration'):
del mpd.attrib['maxSegmentDuration']
mpd.set('minimumUpdatePeriod', "PT0S")

self.publish_time = self.cfg.publish_time

#pylint: disable = too-many-branches
def process_mpd_children(self, mpd, data, period_data):
Expand Down Expand Up @@ -163,6 +168,7 @@ def process_mpd_children(self, mpd, data, period_data):
mpd.insert(pos+i, new_period)
self.insert_utc_timings(mpd, pos+len(period_data))
self.update_periods(mpd, period_data, data['periodOffset'] >= 0)
mpd.set('publishTime', make_timestamp(self.publish_time))

def insert_baseurl(self, mpd, pos, new_baseurl, new_ato):
"Create and insert a new <BaseURL> element."
Expand All @@ -183,6 +189,10 @@ def insert_ato(self, baseurl_elem, new_ato):
"Add availabilityTimeOffset to BaseURL element"
baseurl_elem.set('availabilityTimeOffset', new_ato)

def update_publish_time(self, candidate_time_s):
if candidate_time_s > self.publish_time:
self.publish_time = candidate_time_s

#pylint: disable = too-many-statements
def update_periods(self, mpd, period_data, offset_at_period_level=False):
"Update periods to provide appropriate values."
Expand Down Expand Up @@ -267,6 +277,7 @@ def create_inline_mpdcallback_elem(BaseURLSegmented):
remove_attribs(seg_template, ['startNumber'])

if self.segtimeline:
seg_gen = segtimeline_generators[content_type]
# add SegmentTimeline block in SegmentTemplate with timescale and window.
now = self.mpd_proc_cfg['now']
tsbd = self.cfg.timeshift_buffer_depth_in_s
Expand All @@ -278,7 +289,7 @@ def create_inline_mpdcallback_elem(BaseURLSegmented):
end_time = now
start_time -= self.cfg.availability_start_time_in_s
end_time -= self.cfg.availability_start_time_in_s
seg_timeline = segtimeline_generators[content_type].create_segtimeline(start_time, end_time)
seg_timeline = seg_gen.create_segtimeline(start_time, end_time)
remove_attribs(seg_template, ['duration'])
remove_attribs(seg_template, ['startNumber'])
seg_template.set('timescale', str(self.cfg.media_data[content_type]['timescale']))
Expand All @@ -287,6 +298,7 @@ def create_inline_mpdcallback_elem(BaseURLSegmented):
seg_template.set('media', media_template)
seg_template.text = "\n"
seg_template.insert(0, seg_timeline)
self.update_publish_time(seg_gen.get_end_time_s())
last_period_id = pdata.get('id')

def create_descriptor_elem(self, name, scheme_id_uri, value=None, elem_id=None, messageData=None):
Expand Down
5 changes: 5 additions & 0 deletions dashlivesim/dashlib/segtimeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ def __init__(self, media_data, cfg):
data = ifh.read(12)
self.interval_starts = [std.start_time for std in self.segtimedata]
self.wrap_duration = cfg.vod_wrap_seconds * self.timescale
self.end_tics = None

def get_end_time_s(self):
return 1.0*self.end_tics/self.timescale

def create_segtimeline(self, start_time, end_time):
"Create and insert a new <SegmentTimeline> element and S entries for interval [now-tsbd, now]."
Expand Down Expand Up @@ -97,6 +101,7 @@ def create_segtimeline(self, start_time, end_time):
return (None, None, None)
end_tics = self.get_seg_endtime(end_wraps, end_index, end_repeats)

self.end_tics = end_tics
#print "end_time2 %d %d %d" % (end, end_tics, (end-end_tics)/(self.timescale*1.0))
#print "end time %d %d %d" % (end_index, end_repeats, end_wraps)

Expand Down
2 changes: 1 addition & 1 deletion dashlivesim/tests/test_moduloperiod.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def testMiddlePeriod(self):
self.assertEqual(mp._minimum_update_period, 30)
self.assertEqual(mp._availability_start_time, 1800)
self.assertEqual(mp._media_presentation_duration, 360)
self.assertEqual(mp._availability_end_time, 2190)
self.assertEqual(mp.publish_time, 1980)

def testEndOfMediaInPeriod(self):
mp = ModuloPeriod(5, 540)
Expand Down