Created
August 29, 2017 21:17
-
-
Save martastain/054871e95cb0bdf22738015275fb9c27 to your computer and use it in GitHub Desktop.
manifest_joiner
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os | |
import time | |
import rex | |
import datetime | |
from nxtools import * | |
from mpd import * | |
from isodate import * | |
MAP = [ | |
{ | |
"id" : "video", | |
"segmentAlignment" : True, | |
"maxWidth" : 960, | |
"maxHeight" : 540, | |
"maxFrameRate" : 25, | |
"bitstreamSwitching" : True, | |
"representations" : [ | |
{ | |
"manifest_name" : "demo_high", | |
"source_id" : "demo_high_H264", | |
"target_id" : "video_high", | |
}, | |
{ | |
"manifest_name" : "demo_low", | |
"source_id" : "demo_low_H264", | |
"target_id" : "video_low" | |
} | |
] | |
}, | |
{ | |
"id" : "audio_en", | |
"contentType" : "audio", | |
"segmentAlignment" : True, | |
"bitstreamSwitching" : True, | |
"lang" : "en", | |
"representations" : [ | |
{ | |
"manifest_name" : "demo_high", | |
"source_id" : "demo_high_AAC", | |
"target_id" : "audio_en", | |
} | |
] | |
}, | |
{ | |
"id" : "audio_it", | |
"contentType" : "audio", | |
"segmentAlignment" : "true", | |
"bitstreamSwitching" : "true", | |
"lang" : "it", | |
"representations" : [ | |
{ | |
"manifest_name" : "demo_low", | |
"source_id" : "demo_low_AAC", | |
"target_id" : "audio_it", | |
} | |
] | |
}, | |
] | |
NS="{urn:mpeg:dash:schema:mpd:2011}" | |
class MPDMerge(object): | |
def __init__(self, output_map, **kwargs): | |
self.output_map = output_map | |
self.source_manifests = {} | |
self.mpd_attrib = {} | |
self.settings = { | |
"mpd_dir" : "/mnt/cache/dash" | |
} | |
def get_source_manifest(self, manifest_name): | |
if not manifest_name in self.source_manifests: | |
logging.debug("Loading source manifest {}".format(manifest_name)) | |
manifest_path = os.path.join( | |
self.settings["mpd_dir"], | |
manifest_name + ".mpd" | |
) | |
manifest = xml(open(manifest_path).read()) | |
self.source_manifests[manifest_name] = manifest | |
if not self.mpd_attrib: | |
self.mpd_attrib = manifest.attrib | |
return self.source_manifests[manifest_name] | |
def get_representation(self, manifest_name, representation_id): | |
try: | |
manifest = self.get_source_manifest(manifest_name) | |
except Exception: | |
log_traceback() | |
return None | |
period = manifest.find(NS + "Period") | |
for adaptation_set in period.findall(NS + "AdaptationSet"): | |
for representation in adaptation_set.findall(NS + "Representation"): | |
if representation.attrib.get("id", False) == representation_id: | |
return representation | |
return None | |
def render(self, **kwargs): | |
mpd = None | |
period = None | |
ta_sets = {} | |
for ma in self.output_map: | |
for mr in ma["representations"]: | |
sr = self.get_representation( | |
mr["manifest_name"], | |
mr["source_id"] | |
) | |
if mpd is None: | |
if "mpd_attrib" in kwargs: | |
self.mpd_attrib.update(kwargs["mpd_attrib"]) | |
mpd = MPD(**self.mpd_attrib) | |
period = mpd.add_period() | |
ta_id = ma["id"] | |
if not ta_id in ta_sets: | |
a_attr = {k : ma[k] for k in ma if k != "representations"} | |
ta_sets[ta_id] = period.add_adaptation_set(**a_attr) | |
ta = ta_sets[ta_id] | |
tr = ta.add_representation(**sr.attrib) | |
tr["id"] = mr["target_id"] | |
tr.segment_template = SegmentTemplate( | |
**sr.find(NS+"SegmentTemplate").attrib | |
) | |
astart = parse_iso_datetime(mpd["availabilityStartTime"]) | |
astart += datetime.timedelta(seconds=10) | |
mpd["availabilityStartTime"] = astart.isoformat() | |
return mpd.xml | |
while True: | |
merger = MPDMerge(MAP) | |
data = merger.render(mpd_attrib={"suggestedPresentationDelay" : "PT5S"}) | |
with open("/mnt/cache/dash/demo.mpd", "w") as f: | |
f.write(data) | |
time.sleep(5) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment