From 27e2e60547ff7e633a914251e7b06232e7dcb44c Mon Sep 17 00:00:00 2001 From: Ju/TroisYaourts Date: Thu, 18 Aug 2016 12:51:46 +0200 Subject: [PATCH 1/4] Support for roles in multi-stream mp4. Specify either via --role-map or --role-map-file --- Source/Python/utils/mp4-dash.py | 34 +++++++++++++++++++++++++++++++++ Source/Python/utils/mp4utils.py | 1 + 2 files changed, 35 insertions(+) diff --git a/Source/Python/utils/mp4-dash.py b/Source/Python/utils/mp4-dash.py index 439e33656..68797edad 100755 --- a/Source/Python/utils/mp4-dash.py +++ b/Source/Python/utils/mp4-dash.py @@ -81,6 +81,7 @@ CENC_2013_NAMESPACE = 'urn:mpeg:cenc:2013' DASH_DEFAULT_ROLE_NAMESPACE = 'urn:mpeg:dash:role:2011' +DASH_DEFAULT_ROLE = 'main' DASH_MEDIA_SEGMENT_URL_PATTERN_SMOOTH = "/QualityLevels($Bandwidth$)/Fragments(%s=$Time$)" DASH_MEDIA_SEGMENT_URL_PATTERN_HIPPO = '%s/Bitrate($Bandwidth$)/Fragment($Time$)' @@ -440,6 +441,10 @@ def OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets, if options.encryption_key or options.marlin or options.playready or options.widevine: AddContentProtection(options, adaptation_set, audio_tracks) + if len(adaptation_set_name) == 4: + role = adaptation_set_name[3] + AddDescriptor(adaptation_set, {"audio":{'Role':role}}, 'audio/' + language, 'audio') + if not options.on_demand: if options.split: init_segment_url = '$RepresentationID$/' + SPLIT_INIT_SEGMENT_NAME @@ -950,6 +955,12 @@ def SelectTracks(options, media_sources): elif options.language_map and language in options.language_map: language = options.language_map[language] track.language = language + + track.role = DASH_DEFAULT_ROLE + if options.role_map: + track.role = options.role_map.get(track.id, DASH_DEFAULT_ROLE) + if track.role : + print "Adding role",track.role,"to",track # video scan type if track.type == 'video': @@ -958,6 +969,8 @@ def SelectTracks(options, media_sources): # process audio tracks for track in [t for t in tracks if t.type == 'audio']: adaptation_set_name = ('audio', track.language, track.codec_family) + if track.role: + adaptation_set_name += (track.role,) adaptation_set = audio_adaptation_sets.get(adaptation_set_name, []) audio_adaptation_sets[adaptation_set_name] = adaptation_set @@ -1097,6 +1110,11 @@ def main(): help="Max Playout Rate setting strategy for trick-play support. Supported strategies: lowest:X"), parser.add_option('', "--language-map", dest="language_map", metavar=":[,...]", help="Remap language code to . Multiple mappings can be specified, separated by ','") + parser.add_option('', "--role-map", dest="role_map_raw", metavar=":[,...]", + help="Map role for stream to . Multiple mappings can be specified, separated by ','. "+ + "Supersede contents of --role-map-file if both specified.") + parser.add_option('', "--role-map-file", dest="role_map_file", metavar=".json", + help="JSON mapping of roles for streams.") parser.add_option('', "--always-output-lang", dest="always_output_lang", action='store_true', default=False, help="Always output an @lang attribute for audio tracks even when the language is undefined"), parser.add_option('', "--subtitles", dest="subtitles", action="store_true", default=False, @@ -1174,6 +1192,7 @@ def main(): # set some synthetic (not from command line) options options.on_demand = False + options.role_map = {} # check the consistency of the options if options.smooth: @@ -1279,6 +1298,21 @@ def main(): from_lang, to_lang = mapping.split(':') options.language_map[from_lang] = to_lang + # process role map options + if options.role_map_file: + fp = open(options.role_map_file) + mappings = json.load(fp) + for stream_id,mapping in mappings.items(): + role = mapping.get('role') + if role : + options.role_map[int(stream_id)] = role + + if options.role_map_raw: + mappings = options.role_map_raw.split(',') + for mapping in mappings: + stream_id, role = mapping.split(':') + options.role_map[int(stream_id)] = role + # parse the attributes definitions set_attributes = {} for set_attributes_spec in options.attributes: diff --git a/Source/Python/utils/mp4utils.py b/Source/Python/utils/mp4utils.py index ca63f17ed..b0a7bee69 100644 --- a/Source/Python/utils/mp4utils.py +++ b/Source/Python/utils/mp4utils.py @@ -360,6 +360,7 @@ def __init__(self, parent, info): self.max_segment_bitrate = 0 self.bandwidth = 0 self.language = '' + self.role = 'main' self.order_index = 0 self.id = info['id'] if info['type'] == 'Audio': From eab0de1c78e83c8406c90825a9a24180af694171 Mon Sep 17 00:00:00 2001 From: Ju/TroisYaourts Date: Thu, 18 Aug 2016 13:07:17 +0200 Subject: [PATCH 2/4] display roles only if verbose --- Source/Python/utils/mp4-dash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Python/utils/mp4-dash.py b/Source/Python/utils/mp4-dash.py index 68797edad..0f6e0f5a8 100755 --- a/Source/Python/utils/mp4-dash.py +++ b/Source/Python/utils/mp4-dash.py @@ -959,7 +959,7 @@ def SelectTracks(options, media_sources): track.role = DASH_DEFAULT_ROLE if options.role_map: track.role = options.role_map.get(track.id, DASH_DEFAULT_ROLE) - if track.role : + if track.role and options.verbose:: print "Adding role",track.role,"to",track # video scan type From 6d11699f6543039fd80478f982033b44fcb44f71 Mon Sep 17 00:00:00 2001 From: Ju/TroisYaourts Date: Thu, 18 Aug 2016 17:04:17 +0200 Subject: [PATCH 3/4] syntax error --- Source/Python/utils/mp4-dash.py | 2 +- Source/Python/utils/mp4utils.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Python/utils/mp4-dash.py b/Source/Python/utils/mp4-dash.py index 0f6e0f5a8..c0459bd91 100755 --- a/Source/Python/utils/mp4-dash.py +++ b/Source/Python/utils/mp4-dash.py @@ -959,7 +959,7 @@ def SelectTracks(options, media_sources): track.role = DASH_DEFAULT_ROLE if options.role_map: track.role = options.role_map.get(track.id, DASH_DEFAULT_ROLE) - if track.role and options.verbose:: + if track.role and options.verbose: print "Adding role",track.role,"to",track # video scan type diff --git a/Source/Python/utils/mp4utils.py b/Source/Python/utils/mp4utils.py index b0a7bee69..6262de3aa 100644 --- a/Source/Python/utils/mp4utils.py +++ b/Source/Python/utils/mp4utils.py @@ -261,6 +261,7 @@ def Bento4Command(options, name, *args, **kwargs): print 'COMMAND: ', cmd try: try: + print os.getcwd() return check_output(cmd) except OSError as e: if options.debug: @@ -270,7 +271,7 @@ def Bento4Command(options, name, *args, **kwargs): except CalledProcessError as e: message = "binary tool failed with error %d" % e.returncode if options.verbose: - message += " - " + str(cmd) + message += " - " + str(cmd) + " - " + str(e.output) raise Exception(message) except OSError as e: raise Exception('executable "'+name+'" not found, ensure that it is in your path or in the directory '+options.exec_dir) From 49a86d3634766adc0f86ec6686558f7fd4b69640 Mon Sep 17 00:00:00 2001 From: Ju/TroisYaourts Date: Wed, 4 Sep 2019 18:29:40 +0200 Subject: [PATCH 4/4] latest EME system id --- Source/Python/utils/mp4-dash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Python/utils/mp4-dash.py b/Source/Python/utils/mp4-dash.py index abf945399..7c2d1258a 100755 --- a/Source/Python/utils/mp4-dash.py +++ b/Source/Python/utils/mp4-dash.py @@ -71,8 +71,8 @@ MPEG_COMMON_ENCRYPTION_SCHEME_ID_URI = 'urn:mpeg:dash:mp4protection:2011' -EME_COMMON_ENCRYPTION_PSSH_SYSTEM_ID = '1077efecc0b24d02ace33c1e52e2fb4b' -EME_COMMON_ENCRYPTION_SCHEME_ID_URI = 'urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b' +EME_COMMON_ENCRYPTION_PSSH_SYSTEM_ID = 'e2719d58a985b3c9781ab030af78d30e' +EME_COMMON_ENCRYPTION_SCHEME_ID_URI = 'urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e' SMOOTH_DEFAULT_TIMESCALE = 10000000