[Python-modules-commits] [python-mpegdash] 01/06: import python-mpegdash-0.1.0.orig.tar.gz
Ondrej Koblizek
kobla-guest at moszumanska.debian.org
Wed May 18 14:13:16 UTC 2016
This is an automated email from the git hooks/post-receive script.
kobla-guest pushed a commit to branch master
in repository python-mpegdash.
commit 3c76510490e17c427b7f54e3d106ba2efee697a6
Author: Ondrej Koblizek <ondrej.koblizek at firma.seznam.cz>
Date: Wed May 18 15:22:46 2016 +0200
import python-mpegdash-0.1.0.orig.tar.gz
---
.gitignore | 4 +
.travis.yml | 8 +
LICENSE | 21 +
README.md | 42 ++
mpegdash/__init__.py | 0
mpegdash/nodes.py | 736 +++++++++++++++++++++++++
mpegdash/parser.py | 37 ++
mpegdash/schema/dash-mpd.xsd | 424 ++++++++++++++
mpegdash/utils.py | 76 +++
requirements.txt | 1 +
setup.py | 26 +
test-requirements.txt | 1 +
tests/__init__.py | 10 +
tests/mpd-samples/360p_speciment_dash.mpd | 24 +
tests/mpd-samples/motion-20120802-manifest.mpd | 59 ++
tests/mpd-samples/oops-20120802-manifest.mpd | 59 ++
tests/mpd-samples/sample-001.mpd | 81 +++
tests/test_mpdtoxml.py | 29 +
tests/test_xmltompd.py | 46 ++
19 files changed, 1684 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ff8af56
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.py[co]
+*.sw[op]
+*.ropeproject
+tests/mpd-samples/output.mpd
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..e0b640f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: python
+python:
+ - "2.6"
+ - "2.7"
+ - "3.3"
+ - "3.4"
+ - "3.5"
+script: python setup.py test
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5ab8f19
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 supercast-tv
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..73eedfb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,42 @@
+[![Build Status](https://travis-ci.org/caststack/python-mpegdash.svg?branch=master)](https://travis-ci.org/caststack/python-mpegdash)
+
+# python-mpegdash
+MPEG-DASH MPD(Media Presentation Description) Parser
+compatible with Python2.6+ and Python3
+
+## Test
+ $ python -m unittest discover
+ $ python3 -m unittest discover
+
+## Usage
+ from mpegdash.parser import MPEGDASHParser
+
+ # Parse from file path
+ mpd_path = './tests/mpd-samples/sample-001.mpd'
+ mpd = MPEGDASHParser.parse(mpd_path)
+
+ # Parse from url
+ mpd_url = 'http://yt-dash-mse-test.commondatastorage.googleapis.com/media/motion-20120802-manifest.mpd'
+ mpd = MPEGDASHParser.parse(mpd_url)
+
+ # Parse from string
+ mpd_string = '''
+ <MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" mediaPresentationDuration="PT0H1M52.43S" minBufferTime="PT1.5S"
+ profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" type="static">
+ <Period duration="PT0H1M52.43S" start="PT0S">
+ <AdaptationSet>
+ <ContentComponent contentType="video" id="1" />
+ <Representation bandwidth="4190760" codecs="avc1.640028" height="1080" id="1" mimeType="video/mp4" width="1920">
+ <BaseURL>motion-20120802-89.mp4</BaseURL>
+ <SegmentBase indexRange="674-981">
+ <Initialization range="0-673" />
+ </SegmentBase>
+ </Representation>
+ </AdaptationSet>
+ </Period>
+ </MPD>
+ '''
+ mpd = MPEGDASHParser.parse(mpd_string)
+
+ # Write to xml file
+ MPEGDASHParser.write(mpd, './tests/mpd-samples/output.mpd')
diff --git a/mpegdash/__init__.py b/mpegdash/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/mpegdash/nodes.py b/mpegdash/nodes.py
new file mode 100644
index 0000000..857974f
--- /dev/null
+++ b/mpegdash/nodes.py
@@ -0,0 +1,736 @@
+from mpegdash.utils import (
+ parse_attr_value, parse_child_nodes, parse_node_value,
+ write_attr_value, write_child_node, write_node_value
+)
+
+
+class XMLNode(object):
+ def parse(self, xmlnode):
+ raise NotImplementedError('Should have implemented this')
+
+ def write(self, xmlnode):
+ raise NotImplementedError('Should have implemented this')
+
+
+class Subset(XMLNode):
+ def __init__(self):
+ self.id = None # xs:string
+ self.contains = [] # UIntVectorType (required)
+
+ def parse(self, xmlnode):
+ self.id = parse_attr_value(xmlnode, 'id', str)
+ self.contains = parse_attr_value(xmlnode, 'contains', [int])
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'id', self.id)
+ write_attr_value(xmlnode, 'contains', self.contains)
+
+
+class URL(XMLNode):
+ def __init__(self):
+ self.source_url = None # xs:anyURI
+ self.range = None # xs:string
+
+ def parse(self, xmlnode):
+ self.source_url = parse_attr_value(xmlnode, 'sourceURL', str)
+ self.range = parse_attr_value(xmlnode, 'range', str)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'sourceURL', self.source_url)
+ write_attr_value(xmlnode, 'range', self.range)
+
+
+class BaseURL(XMLNode):
+ def __init__(self):
+ self.base_url_value = None # xs:anyURI
+
+ self.service_location = None # xs:string
+ self.byte_range = None # xs:string
+ self.availability_time_offset = None # xs:double
+ self.availability_time_complete = None # xs:boolean
+
+ def parse(self, xmlnode):
+ self.base_url_value = parse_node_value(xmlnode, str)
+
+ self.service_location = parse_attr_value(xmlnode, 'serviceLocation', str)
+ self.byte_range = parse_attr_value(xmlnode, 'byteRange', str)
+ self.availability_time_offset = parse_attr_value(xmlnode, 'availabilityTimeOffset', float)
+ self.availability_time_complete = parse_attr_value(xmlnode, 'availabilityTimeComplete', bool)
+
+ def write(self, xmlnode):
+ write_node_value(xmlnode, self.base_url_value)
+
+ write_attr_value(xmlnode, 'serviceLocation', self.service_location)
+ write_attr_value(xmlnode, 'byteRange', self.byte_range)
+ write_attr_value(xmlnode, 'availabilityTimeOffset', self.availability_time_offset)
+ write_attr_value(xmlnode, 'availabilityTimeComplete', self.availability_time_complete)
+
+
+class ProgramInformation(XMLNode):
+ def __init__(self):
+ self.lang = None # xs:language
+ self.more_information_url = None # xs:anyURI
+
+ self.titles = None # xs:string*
+ self.sources = None # xs:string*
+ self.copyrights = None # xs:string*
+
+ def parse(self, xmlnode):
+ self.lang = parse_attr_value(xmlnode, 'lang', str)
+ self.more_information_url = parse_attr_value(xmlnode, 'moreInformationURL', str)
+
+ self.titles = parse_child_nodes(xmlnode, 'Title', str)
+ self.sources = parse_child_nodes(xmlnode, 'Source', str)
+ self.copyrights = parse_child_nodes(xmlnode, 'Copyright', str)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'lang', self.lang)
+ write_attr_value(xmlnode, 'moreInformationURL', self.more_information_url)
+
+ write_child_node(xmlnode, 'Title', self.titles)
+ write_child_node(xmlnode, 'Source', self.sources)
+ write_child_node(xmlnode, 'Copyright', self.copyrights)
+
+
+class Metrics(XMLNode):
+ def __init__(self):
+ self.metrics = '' # xs:string (required)
+
+ self.reportings = None # DescriptorType*
+ self.ranges = None # RangeType*
+
+ def parse(self, xmlnode):
+ self.metrics = parse_attr_value(xmlnode, 'metrics', str)
+
+ self.reportings = parse_child_nodes(xmlnode, 'Reporting', Descriptor)
+ self.ranges = parse_child_nodes(xmlnode, 'Range', Range)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'metrics', self.metrics)
+
+ write_child_node(xmlnode, 'Reporting', self.reportings)
+ write_child_node(xmlnode, 'Range', self.ranges)
+
+
+class Range(XMLNode):
+ def __init__(self):
+ self.starttime = None # xs:duration
+ self.duration = None # xs:duration
+
+ def parse(self, xmlnode):
+ self.starttime = parse_attr_value(xmlnode, 'starttime', str)
+ self.duration = parse_attr_value(xmlnode, 'duration', str)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'starttime', self.starttime)
+ write_attr_value(xmlnode, 'duration', self.duration)
+
+
+class SegmentURL(XMLNode):
+ def __init__(self):
+ self.media = None # xs:anyURI
+ self.media_range = None # xs:string
+ self.index = None # xs:anyURI
+ self.index_range = None # xs:string
+
+ def parse(self, xmlnode):
+ self.media = parse_attr_value(xmlnode, 'media', str)
+ self.media_range = parse_attr_value(xmlnode, 'mediaRange', str)
+ self.index = parse_attr_value(xmlnode, 'index', str)
+ self.index_range = parse_attr_value(xmlnode, 'indexRange', str)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'media', self.media)
+ write_attr_value(xmlnode, 'mediaRange', self.media_range)
+ write_attr_value(xmlnode, 'index', self.index)
+ write_attr_value(xmlnode, 'indexRange', self.index_range)
+
+
+class S(XMLNode):
+ def __init__(self):
+ self.t = None # xs:unsignedLong
+ self.d = 0 # xs:unsignedLong (required)
+ self.r = None # xml:integer
+
+ def parse(self, xmlnode):
+ self.t = parse_attr_value(xmlnode, 't', int)
+ self.d = parse_attr_value(xmlnode, 'd', int)
+ self.r = parse_attr_value(xmlnode, 'r', int)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 't', self.t)
+ write_attr_value(xmlnode, 'd', self.d)
+ write_attr_value(xmlnode, 'r', self.r)
+
+
+class SegmentTimeline(XMLNode):
+ def __init__(self):
+ self.Ss = None # xs:complexType+
+
+ def parse(self, xmlnode):
+ self.Ss = parse_child_nodes(xmlnode, 'S', S)
+
+ def write(self, xmlnode):
+ write_child_node(xmlnode, 'S', self.Ss)
+
+
+class SegmentBase(XMLNode):
+ def __init__(self):
+ self.timescale = None # xs:unsignedInt
+ self.index_range = None # xs:string
+ self.index_range_exact = None # xs:boolean
+ self.presentation_time_offset = None # xs:unsignedLong
+ self.availability_time_offset = None # xs:double
+ self.availability_time_complete = None # xs:boolean
+
+ self.initializations = None # URLType*
+ self.representation_indexes = None # URLType*
+
+ def parse(self, xmlnode):
+ self.timescale = parse_attr_value(xmlnode, 'timescale', int)
+ self.index_range = parse_attr_value(xmlnode, 'indexRange', str)
+ self.index_range_exact = parse_attr_value(xmlnode, 'indexRangeExact', bool)
+ self.presentation_time_offset = parse_attr_value(xmlnode, 'presentationTimeOffset', int)
+ self.availability_time_offset = parse_attr_value(xmlnode, 'availabilityTimeOffset', float)
+ self.availability_time_complete = parse_attr_value(xmlnode, 'availabilityTimeComplete', bool)
+
+ self.initializations = parse_child_nodes(xmlnode, 'Initialization', URL)
+ self.representation_indexes = parse_child_nodes(xmlnode, 'RepresentationIndex', URL)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'timescale', self.timescale)
+ write_attr_value(xmlnode, 'indexRange', self.index_range)
+ write_attr_value(xmlnode, 'indexRangeExact', self.index_range_exact)
+ write_attr_value(xmlnode, 'presentationTimeOffset', self.presentation_time_offset)
+ write_attr_value(xmlnode, 'availabilityTimeOffset', self.availability_time_offset)
+ write_attr_value(xmlnode, 'availabilityTimeComplete', self.availability_time_complete)
+
+ write_child_node(xmlnode, 'Initialization', self.initializations)
+ write_child_node(xmlnode, 'RepresentationIndex', self.representation_indexes)
+
+
+class MultipleSegmentBase(SegmentBase):
+ def __init__(self):
+ SegmentBase.__init__(self)
+
+ self.duration = None # xs:unsignedInt
+ self.start_number = None # xs:unsignedInt
+
+ self.segment_timelines = None # SegmentTimelineType*
+ self.bitstream_switchings = None # URLType*
+
+ def parse(self, xmlnode):
+ SegmentBase.parse(self, xmlnode)
+
+ self.duration = parse_attr_value(xmlnode, 'duration', int)
+ self.start_number = parse_attr_value(xmlnode, 'startNumber', int)
+
+ self.segment_timelines = parse_child_nodes(xmlnode, 'SegmentTimeline', SegmentTimeline)
+ self.bitstream_switchings = parse_child_nodes(xmlnode, 'BitstreamSwitching', URL)
+
+ def write(self, xmlnode):
+ SegmentBase.write(self, xmlnode)
+
+ write_attr_value(xmlnode, 'duration', self.duration)
+ write_attr_value(xmlnode, 'startNumber', self.start_number)
+
+ write_child_node(xmlnode, 'SegmentTimeline', self.segment_timelines)
+ write_child_node(xmlnode, 'BitstreamSwitching', self.bitstream_switchings)
+
+
+class SegmentTemplate(MultipleSegmentBase):
+ def __init__(self):
+ MultipleSegmentBase.__init__(self)
+
+ self.media = None # xs:string
+ self.index = None # xs:string
+ self.initialization = None # xs:string
+ self.bitstream_switching = None # xs:string
+
+ def parse(self, xmlnode):
+ MultipleSegmentBase.parse(self, xmlnode)
+
+ self.media = parse_attr_value(xmlnode, 'media', str)
+ self.index = parse_attr_value(xmlnode, 'index', str)
+ self.initialization = parse_attr_value(xmlnode, 'initialization', str)
+ self.bitstream_switching = parse_attr_value(xmlnode, 'bitstreamSwitching', str)
+
+ def write(self, xmlnode):
+ MultipleSegmentBase.write(self, xmlnode)
+
+ write_attr_value(xmlnode, 'media', self.media)
+ write_attr_value(xmlnode, 'index', self.index)
+ write_attr_value(xmlnode, 'initialization', self.initialization)
+ write_attr_value(xmlnode, 'bitstreamSwitching', self.bitstream_switching)
+
+
+class SegmentList(MultipleSegmentBase):
+ def __init__(self):
+ MultipleSegmentBase.__init__(self)
+
+ self.segment_urls = None # SegmentURLType
+
+ def parse(self, xmlnode):
+ MultipleSegmentBase.parse(self, xmlnode)
+
+ self.segment_urls = parse_child_nodes(xmlnode, 'SegmentURL', SegmentURL)
+
+ def write(self, xmlnode):
+ MultipleSegmentBase.write(self, xmlnode)
+
+ write_child_node(xmlnode, 'SegmentURL', self.segment_urls)
+
+
+class Event(XMLNode):
+ def __init__(self):
+ self.event_value = None # xs:string
+ self.presentation_time = None # xs:unsignedLong
+ self.duration = None # xs:unsignedLong
+ self.id = None # xs:unsignedInt
+
+ def parse(self, xmlnode):
+ self.event_value = parse_node_value(xmlnode, str)
+ self.presentation_time = parse_attr_value(xmlnode, 'presentationTime', int)
+ self.duration = parse_attr_value(xmlnode, 'duration', int)
+ self.id = parse_attr_value(xmlnode, 'id', int)
+
+ def write(self, xmlnode):
+ write_node_value(xmlnode, self.event_value)
+ write_attr_value(xmlnode, 'presentationTime', self.presentation_time)
+ write_attr_value(xmlnode, 'duration', self.duration)
+ write_attr_value(xmlnode, 'id', self.id)
+
+
+class Descriptor(XMLNode):
+ def __init__(self):
+ self.scheme_id_uri = '' # xs:anyURI (required)
+ self.value = None # xs:string
+ self.id = None # xs:string
+
+ def parse(self, xmlnode):
+ self.scheme_id_uri = parse_attr_value(xmlnode, 'schemeIdUri', str)
+ self.value = parse_attr_value(xmlnode, 'value', str)
+ self.id = parse_attr_value(xmlnode, 'id', str)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'schemeIdUri', self.scheme_id_uri)
+ write_attr_value(xmlnode, 'value', self.value)
+ write_attr_value(xmlnode, 'id', self.id)
+
+
+class ContentComponent(XMLNode):
+ def __init__(self):
+ self.id = None # xs:unsigendInt
+ self.lang = None # xs:language
+ self.content_type = None # xs:string
+ self.par = None # RatioType
+
+ self.accessibilities = None # DescriptorType*
+ self.roles = None # DescriptorType*
+ self.ratings = None # DescriptorType*
+ self.viewpoints = None # DescriptorType*
+
+ def parse(self, xmlnode):
+ self.id = parse_attr_value(xmlnode, 'id', int)
+ self.lang = parse_attr_value(xmlnode, 'lang', str)
+ self.content_type = parse_attr_value(xmlnode, 'contentType', str)
+ self.par = parse_attr_value(xmlnode, 'par', str)
+
+ self.accessibilities = parse_child_nodes(xmlnode, 'Accessibility', Descriptor)
+ self.roles = parse_child_nodes(xmlnode, 'Role', Descriptor)
+ self.ratings = parse_child_nodes(xmlnode, 'Rating', Descriptor)
+ self.viewpoints = parse_child_nodes(xmlnode, 'Viewpoint', Descriptor)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'id', self.id)
+ write_attr_value(xmlnode, 'lang', self.lang)
+ write_attr_value(xmlnode, 'contentType', self.content_type)
+ write_attr_value(xmlnode, 'par', self.par)
+
+ write_child_node(xmlnode, 'Accessibility', self.accessibilities)
+ write_child_node(xmlnode, 'Role', self.roles)
+ write_child_node(xmlnode, 'Rating', self.ratings)
+ write_child_node(xmlnode, 'Viewpoint', self.viewpoints)
+
+
+class RepresentationBase(XMLNode):
+ def __init__(self):
+ self.profiles = None # xs:string
+ self.width = None # xs:unsigendInt
+ self.height = None # xs:unsigendInt
+ self.sar = None # RatioType
+ self.frame_rate = None # FrameRateType
+ self.audio_sampling_rate = None # xs:string
+ self.mime_type = None # xs:string
+ self.segment_profiles = None # xs:string
+ self.codecs = None # xs:string
+ self.maximum_sap_period = None # xs:double
+ self.start_with_sap = None # SAPType
+ self.max_playout_rate = None # xs:double
+ self.coding_dependency = None # xs:boolean
+ self.scan_type = None # VideoScanType
+
+ self.frame_packings = None # DescriptorType*
+ self.audio_channel_configurations = None # DescriptorType*
+ self.content_protections = None # DescriptorType*
+ self.essential_properties = None # DescriptorType*
+ self.supplemental_properties = None # DescriptorType*
+ self.inband_event_streams = None # DescriptorType*
+
+ def parse(self, xmlnode):
+ self.profiles = parse_attr_value(xmlnode, 'profile', str)
+ self.width = parse_attr_value(xmlnode, 'width', int)
+ self.height = parse_attr_value(xmlnode, 'height', int)
+ self.sar = parse_attr_value(xmlnode, 'sar', str)
+ self.frame_rate = parse_attr_value(xmlnode, 'frameRate', str)
+ self.audio_sampling_rate = parse_attr_value(xmlnode, 'audioSamplingRate', str)
+ self.mime_type = parse_attr_value(xmlnode, 'mimeType', str)
+ self.segment_profiles = parse_attr_value(xmlnode, 'segmentProfiles', str)
+ self.codecs = parse_attr_value(xmlnode, 'codecs', str)
+ self.maximum_sap_period = parse_attr_value(xmlnode, 'maximumSAPPeriod', float)
+ self.start_with_sap = parse_attr_value(xmlnode, 'startWithSAP', int)
+ self.max_playout_rate = parse_attr_value(xmlnode, 'maxPlayoutRate', float)
+ self.coding_dependency = parse_attr_value(xmlnode, 'codingDependency', bool)
+ self.scan_type = parse_attr_value(xmlnode, 'scanType', str)
+
+ self.frame_packings = parse_child_nodes(xmlnode, 'FramePacking', Descriptor)
+ self.audio_channel_configurations = parse_child_nodes(xmlnode, 'AudioChannelConfiguration', Descriptor)
+ self.content_protections = parse_child_nodes(xmlnode, 'ContentProtection', Descriptor)
+ self.essential_properties = parse_child_nodes(xmlnode, 'EssentialProperty', Descriptor)
+ self.supplemental_properties = parse_child_nodes(xmlnode, 'SupplementalProperty', Descriptor)
+ self.inband_event_streams = parse_child_nodes(xmlnode, 'InbandEventStream', Descriptor)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'profile', self.profiles)
+ write_attr_value(xmlnode, 'width', self.width)
+ write_attr_value(xmlnode, 'height', self.height)
+ write_attr_value(xmlnode, 'sar', self.sar)
+ write_attr_value(xmlnode, 'frameRate', self.frame_rate)
+ write_attr_value(xmlnode, 'audioSamplingRate', self.audio_sampling_rate)
+ write_attr_value(xmlnode, 'mimeType', self.mime_type)
+ write_attr_value(xmlnode, 'segmentProfiles', self.segment_profiles)
+ write_attr_value(xmlnode, 'codecs', self.codecs)
+ write_attr_value(xmlnode, 'maximumSAPPeriod', self.maximum_sap_period)
+ write_attr_value(xmlnode, 'startWithSAP', self.start_with_sap)
+ write_attr_value(xmlnode, 'maxPlayoutRate', self.max_playout_rate)
+ write_attr_value(xmlnode, 'codingDependency', self.coding_dependency)
+ write_attr_value(xmlnode, 'scanType', self.scan_type)
+
+ write_child_node(xmlnode, 'FramePacking', self.frame_packings)
+ write_child_node(xmlnode, 'AudioChannelConfiguration', self.audio_channel_configurations)
+ write_child_node(xmlnode, 'ContentProtection', self.content_protections)
+ write_child_node(xmlnode, 'EssentialProperty', self.essential_properties)
+ write_child_node(xmlnode, 'SupplementalProperty', self.supplemental_properties)
+ write_child_node(xmlnode, 'InbandEventStream', self.inband_event_streams)
+
+
+class Representation(RepresentationBase):
+ def __init__(self):
+ RepresentationBase.__init__(self)
+
+ self.id = '' # StringNoWhitespaceType (Required)
+ self.bandwidth = 0 # xs:unsignedInt (required)
+ self.quality_ranking = None # xs:unsignedInt
+ self.dependency_id = None # StringVectorType
+ self.num_channels = None # xs:unsignedInt
+ self.sample_rate = None # xs:unsignedLong
+
+ self.base_urls = None # BaseURLType*
+ self.segment_bases = None # SegmentBaseType*
+ self.segment_lists = None # SegmentListType*
+ self.segment_templates = None # SegmentTemplateType*
+ self.sub_representations = None # SubRepresentationType*
+
+ def parse(self, xmlnode):
+ RepresentationBase.parse(self, xmlnode)
+
+ self.id = parse_attr_value(xmlnode, 'id', str)
+ self.bandwidth = parse_attr_value(xmlnode, 'bandwidth', int)
+ self.quality_ranking = parse_attr_value(xmlnode, 'qualityRanking', int)
+ self.dependency_id = parse_attr_value(xmlnode, 'dependencyId', [str])
+ self.num_channels = parse_attr_value(xmlnode, 'numChannels', int)
+ self.sample_rate = parse_attr_value(xmlnode, 'sampleRate', int)
+
+ self.base_urls = parse_child_nodes(xmlnode, 'BaseURL', BaseURL)
+ self.segment_bases = parse_child_nodes(xmlnode, 'SegmentBase', SegmentBase)
+ self.segment_lists = parse_child_nodes(xmlnode, 'SegmentList', SegmentList)
+ self.segment_templates = parse_child_nodes(xmlnode, 'SegmentTemplate', SegmentTemplate)
+ self.sub_representations = parse_child_nodes(xmlnode, 'SubRepresentation', SubRepresentation)
+
+ def write(self, xmlnode):
+ RepresentationBase.write(self, xmlnode)
+
+ write_attr_value(xmlnode, 'id', self.id)
+ write_attr_value(xmlnode, 'width', self.width)
+ write_attr_value(xmlnode, 'height', self.height)
+ write_attr_value(xmlnode, 'bandwidth', self.bandwidth)
+ write_attr_value(xmlnode, 'mimeType', self.mime_type)
+ write_attr_value(xmlnode, 'codecs', self.codecs)
+
+ write_child_node(xmlnode, 'BaseURL', self.base_urls)
+ write_child_node(xmlnode, 'SegmentBase', self.segment_bases)
+ write_child_node(xmlnode, 'SegmentList', self.segment_lists)
+ write_child_node(xmlnode, 'SegmentTemplate', self.segment_templates)
+ write_child_node(xmlnode, 'SubRepresentation', self.sub_representations)
+
+
+class SubRepresentation(RepresentationBase):
+ def __init__(self):
+ RepresentationBase.__init__(self)
+
+ self.level = None # xs:unsigendInt
+ self.bandwidth = None # xs:unsignedInt
+ self.dependency_level = None # UIntVectorType
+ self.content_component = None # StringVectorType
+
+ def parse(self, xmlnode):
+ RepresentationBase.parse(self, xmlnode)
+
+ self.level = parse_attr_value(xmlnode, 'level', int)
+ self.bandwidth = parse_attr_value(xmlnode, 'bandwidth', int)
+ self.dependency_level = parse_attr_value(xmlnode, 'dependencyLevel', [int])
+ self.content_component = parse_attr_value(xmlnode, 'contentComponent', [str])
+
+ def write(self, xmlnode):
+ RepresentationBase.write(self, xmlnode)
+
+ write_attr_value(xmlnode, 'level', self.level)
+ write_attr_value(xmlnode, 'bandwidth', self.bandwidth)
+ write_attr_value(xmlnode, 'dependencyLevel', self.dependency_level)
+ write_attr_value(xmlnode, 'contentComponent', self.content_component)
+
+
+class AdaptationSet(RepresentationBase):
+ def __init__(self):
+ RepresentationBase.__init__(self)
+
+ self.id = None # xs:unsignedInt
+ self.group = None # xs:unsignedInt
+ self.lang = None # xs:language
+ self.content_type = None # xs:string
+ self.par = None # RatioType
+ self.min_bandwidth = None # xs:unsignedInt
+ self.max_bandwidth = None # xs:unsignedInt
+ self.min_width = None # xs:unsignedInt
+ self.max_width = None # xs:unsignedInt
+ self.min_height = None # xs:unsignedInt
+ self.max_height = None # xs:unsignedInt
+ self.min_frame_rate = None # FrameRateType
+ self.max_frame_rate = None # FrameRateType
+ self.segment_alignment = None # ConditionalUintType
+ self.subsegment_alignment = None # ConditionalUintType
+ self.subsegment_starts_with_sap = None # SAPType
+ self.bitstream_switching = None # xs:boolean
+
+ self.accessibilities = None # DescriptorType*
+ self.roles = None # DescriptorType*
+ self.ratings = None # DescriptorType*
+ self.viewpoints = None # DescriptorType*
+ self.content_components = None # DescriptorType*
+ self.base_urls = None # BaseURLType*
+ self.segment_bases = None # SegmentBase*
+ self.segment_lists = None # SegmentListType*
+ self.segment_templates = None # SegmentTemplateType*
+ self.representations = None # RepresentationType*
+
+ def parse(self, xmlnode):
+ RepresentationBase.parse(self, xmlnode)
+
+ self.id = parse_attr_value(xmlnode, 'id', int)
+ self.group = parse_attr_value(xmlnode, 'group', int)
+ self.lang = parse_attr_value(xmlnode, 'lang', str)
+ self.content_type = parse_attr_value(xmlnode, 'contentType', str)
+ self.par = parse_attr_value(xmlnode, 'par', str)
+ self.min_bandwidth = parse_attr_value(xmlnode, 'minBandwidth', int)
+ self.max_bandwidth = parse_attr_value(xmlnode, 'maxBandwidth', int)
+ self.min_width = parse_attr_value(xmlnode, 'minWidth', int)
+ self.max_width = parse_attr_value(xmlnode, 'maxWidth', int)
+ self.min_height = parse_attr_value(xmlnode, 'minHeight', int)
+ self.max_height = parse_attr_value(xmlnode, 'maxHeight', int)
+ self.min_frame_rate = parse_attr_value(xmlnode, 'minFrameRate', str)
+ self.max_frame_rate = parse_attr_value(xmlnode, 'maxFrameRate', str)
+ self.segment_alignment = parse_attr_value(xmlnode, 'segmentAlignment', bool)
+ self.subsegment_alignment = parse_attr_value(xmlnode, 'subsegmentAlignment', bool)
+ self.subsegment_starts_with_sap = parse_attr_value(xmlnode, 'subsegmentStartsWithSAP', int)
+ self.bitstream_switching = parse_attr_value(xmlnode, 'bitstreamSwitching', bool)
+
+ self.accessibilities = parse_child_nodes(xmlnode, 'Accessibility', Descriptor)
+ self.roles = parse_child_nodes(xmlnode, 'Role', Descriptor)
+ self.ratings = parse_child_nodes(xmlnode, 'Rating', Descriptor)
+ self.viewpoints = parse_child_nodes(xmlnode, 'Viewpoint', Descriptor)
+ self.content_components = parse_child_nodes(xmlnode, 'ContentComponent', ContentComponent)
+ self.base_urls = parse_child_nodes(xmlnode, 'BaseURL', BaseURL)
+ self.segment_bases = parse_child_nodes(xmlnode, 'SegmentBase', SegmentBase)
+ self.segment_lists = parse_child_nodes(xmlnode, 'SegmentList', SegmentList)
+ self.segment_templates = parse_child_nodes(xmlnode, 'SegmentTemplate', SegmentTemplate)
+ self.representations = parse_child_nodes(xmlnode, 'Representation', Representation)
+
+ def write(self, xmlnode):
+ RepresentationBase.write(self, xmlnode)
+
+ write_attr_value(xmlnode, 'id', self.id)
+ write_attr_value(xmlnode, 'group', self.group)
+ write_attr_value(xmlnode, 'lang', self.lang)
+ write_attr_value(xmlnode, 'contentType', self.lang)
+ write_attr_value(xmlnode, 'par', self.par)
+ write_attr_value(xmlnode, 'minBandwidth', self.min_bandwidth)
+ write_attr_value(xmlnode, 'maxBandwidth', self.max_bandwidth)
+ write_attr_value(xmlnode, 'minWidth', self.min_width)
+ write_attr_value(xmlnode, 'maxWidth', self.max_width)
+ write_attr_value(xmlnode, 'minHeight', self.min_height)
+ write_attr_value(xmlnode, 'maxHeight', self.max_height)
+ write_attr_value(xmlnode, 'minFrameRate', self.min_frame_rate)
+ write_attr_value(xmlnode, 'maxFrameRate', self.max_frame_rate)
+ write_attr_value(xmlnode, 'segmentAlignment', self.segment_alignment)
+ write_attr_value(xmlnode, 'subsegmentAlignment', self.subsegment_alignment)
+ write_attr_value(xmlnode, 'subsegmentStartsWithSAP', self.subsegment_starts_with_sap)
+ write_attr_value(xmlnode, 'bitstreamSwitching', self.bitstream_switching)
+
+ write_child_node(xmlnode, 'Accessibility', self.accessibilities)
+ write_child_node(xmlnode, 'Role', self.roles)
+ write_child_node(xmlnode, 'Rating', self.ratings)
+ write_child_node(xmlnode, 'Viewpoint', self.viewpoints)
+ write_child_node(xmlnode, 'ContentComponent', self.content_components)
+ write_child_node(xmlnode, 'BaseURL', self.base_urls)
+ write_child_node(xmlnode, 'SegmentBase', self.segment_bases)
+ write_child_node(xmlnode, 'SegmentList', self.segment_lists)
+ write_child_node(xmlnode, 'SegmentTemplate', self.segment_templates)
+ write_child_node(xmlnode, 'Representation', self.representations)
+
+
+class EventStream(XMLNode):
+ def __init__(self):
+ self.scheme_id_uri = None # xs:anyURI (required)
+ self.value = None # xs:string
+ self.timescale = None # xs:unsignedInt
+
+ self.events = None # EventType*
+
+ def parse(self, xmlnode):
+ self.scheme_id_uri = parse_attr_value(xmlnode, 'schemeIdUri', str)
+ self.value = parse_attr_value(xmlnode, 'value', str)
+ self.timescale = parse_attr_value(xmlnode, 'timescale', int)
+
+ self.events = parse_child_nodes(xmlnode, 'Event', Event)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'schemeIdUri', self.scheme_id_uri)
+ write_attr_value(xmlnode, 'value', self.value)
+ write_attr_value(xmlnode, 'timescale', self.timescale)
+
+ write_child_node(xmlnode, 'Event', self.events)
+
+
+class Period(XMLNode):
+ def __init__(self):
+ self.id = None # xs:string
+ self.start = None # xs:duration
+ self.duration = None # xs:duration
+ self.bitstream_switching = None # xs:boolean
+
+ self.base_urls = None # BaseURLType*
+ self.segment_bases = None # SegmentBaseType*
+ self.segment_lists = None # SegmentListType*
+ self.segment_templates = None # SegmentTemplateType*
+ self.asset_identifiers = None # DescriptorType*
+ self.event_streams = None # EventStreamType*
+ self.adaptation_sets = None # AdaptationSetType*
+ self.subsets = None # SubsetType*
+
+ def parse(self, xmlnode):
+ self.id = parse_attr_value(xmlnode, 'id', str)
+ self.start = parse_attr_value(xmlnode, 'start', str)
+ self.duration = parse_attr_value(xmlnode, 'duration', str)
+ self.bitstream_switching = parse_attr_value(xmlnode, 'bitstreamSwitching', bool)
+
+ self.base_urls = parse_child_nodes(xmlnode, 'BaseURL', BaseURL)
+ self.segment_bases = parse_child_nodes(xmlnode, 'SegmentBase', SegmentBase)
+ self.segment_lists = parse_child_nodes(xmlnode, 'SegmentList', SegmentList)
+ self.segment_templates = parse_child_nodes(xmlnode, 'SegmentTemplate', SegmentTemplate)
+ self.asset_identifiers = parse_child_nodes(xmlnode, 'AssetIdentifier', Descriptor)
+ self.event_streams = parse_child_nodes(xmlnode, 'EventStream', EventStream)
+ self.adaptation_sets = parse_child_nodes(xmlnode, 'AdaptationSet', AdaptationSet)
+ self.subsets = parse_child_nodes(xmlnode, 'Subset', Subset)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'id', self.id)
+ write_attr_value(xmlnode, 'start', self.start)
+ write_attr_value(xmlnode, 'duration', self.duration)
+ write_attr_value(xmlnode, 'bitstreamSwitching', self.bitstream_switching)
+
+ write_child_node(xmlnode, 'BaseURL', self.base_urls)
+ write_child_node(xmlnode, 'SegmentBase', self.segment_bases)
+ write_child_node(xmlnode, 'SegmentList', self.segment_lists)
+ write_child_node(xmlnode, 'SegmentTemplate', self.segment_templates)
+ write_child_node(xmlnode, 'AssetIdentifier', self.asset_identifiers)
+ write_child_node(xmlnode, 'EventStream', self.event_streams)
+ write_child_node(xmlnode, 'AdaptationSet', self.adaptation_sets)
+ write_child_node(xmlnode, 'Subset', self.subsets)
+
+
+class MPEGDASH(XMLNode):
+ def __init__(self):
+ self.xmlns = None # xmlns
+ self.id = None # xs:string
+ self.type = None # PresentationType
+ self.profiles = '' # xs:string (required)
+ self.availability_start_time = None # xs:dateTime
+ self.availability_end_time = None # xs:dateTime
+ self.publish_time = None # xs:dateTime
+ self.media_presentation_duration = None # xs:duration
+ self.minimum_update_period = None # xs:duration
+ self.min_buffer_time = None # xs:duration
+ self.time_shift_buffer_depth = None # xs:duration
+ self.suggested_presentation_delay = None # xs:duration
+ self.max_segment_duration = None # xs:duration
+ self.max_subsegment_duration = None # xs:duration
+
+ self.program_informations = None # ProgramInformationType*
+ self.base_urls = None # BaseURLType*
+ self.locations = None # xs:anyURI*
+ self.periods = None # PeriodType+
+ self.metrics = None # MetricsType*
+
+ def parse(self, xmlnode):
+ self.xmlns = parse_attr_value(xmlnode, 'xmlns', str)
+ self.id = parse_attr_value(xmlnode, 'id', str)
+ self.type = parse_attr_value(xmlnode, 'type', str)
+ self.profiles = parse_attr_value(xmlnode, 'profiles', str)
+ self.availability_start_time = parse_attr_value(xmlnode, 'availabilityStartTime', str)
+ self.availability_end_time = parse_attr_value(xmlnode, 'availabilityEndTime', str)
+ self.publish_time = parse_attr_value(xmlnode, 'publishTime', str)
+ self.media_presentation_duration = parse_attr_value(xmlnode, 'mediaPresentationDuration', str)
+ self.minimum_update_period = parse_attr_value(xmlnode, 'minimumUpdatePeriod', str)
+ self.min_buffer_time = parse_attr_value(xmlnode, 'minBufferTime', str)
+ self.time_shift_buffer_depth = parse_attr_value(xmlnode, 'timeShiftBufferDepth', str)
+ self.suggested_presentation_delay = parse_attr_value(xmlnode, 'suggestedPresentationDelay', str)
+ self.max_segment_duration = parse_attr_value(xmlnode, 'maxSegmentDuration', str)
+ self.max_subsegment_duration = parse_attr_value(xmlnode, 'maxSubsegmentDuration', str)
+
+ self.program_informations = parse_child_nodes(xmlnode, 'ProgramInformation', ProgramInformation)
+ self.base_urls = parse_child_nodes(xmlnode, 'BaseURL', BaseURL)
+ self.locations = parse_child_nodes(xmlnode, 'Location', str)
+ self.periods = parse_child_nodes(xmlnode, 'Period', Period)
+ self.metrics = parse_child_nodes(xmlnode, 'Metrics', Metrics)
+
+ def write(self, xmlnode):
+ write_attr_value(xmlnode, 'xmlns', self.xmlns)
+ write_attr_value(xmlnode, 'id', self.id)
+ write_attr_value(xmlnode, 'type', self.type)
+ write_attr_value(xmlnode, 'profiles', self.profiles)
+ write_attr_value(xmlnode, 'availabilityStartTime', self.availability_start_time)
+ write_attr_value(xmlnode, 'availabilityEndTime', self.availability_end_time)
+ write_attr_value(xmlnode, 'publishTime', self.publish_time)
+ write_attr_value(xmlnode, 'mediaPresentationDuration', self.media_presentation_duration)
+ write_attr_value(xmlnode, 'minimumUpdatePeriod', self.minimum_update_period)
+ write_attr_value(xmlnode, 'minBufferTime', self.min_buffer_time)
+ write_attr_value(xmlnode, 'timeShiftBufferDepth', self.time_shift_buffer_depth)
+ write_attr_value(xmlnode, 'suggestedPresentationDelay', self.suggested_presentation_delay)
+ write_attr_value(xmlnode, 'maxSegmentDuration', self.max_segment_duration)
+ write_attr_value(xmlnode, 'maxSubsegmentDuration', self.max_subsegment_duration)
+
+ write_child_node(xmlnode, 'ProgramInformation', self.program_informations)
+ write_child_node(xmlnode, 'BaseURL', self.base_urls)
+ write_child_node(xmlnode, 'Location', self.locations)
+ write_child_node(xmlnode, 'Period', self.periods)
+ write_child_node(xmlnode, 'Metrics', self.metrics)
diff --git a/mpegdash/parser.py b/mpegdash/parser.py
new file mode 100644
index 0000000..9b9638d
--- /dev/null
+++ b/mpegdash/parser.py
@@ -0,0 +1,37 @@
+from xml.dom import minidom
+
+# python3 support
+try:
+ from urllib2 import urlopen
+except:
+ from urllib.request import urlopen
+
+from mpegdash.nodes import MPEGDASH
+from mpegdash.utils import parse_child_nodes, write_child_node
+
+
+class MPEGDASHParser(object):
+ @classmethod
+ def load_xmldom(cls, string_or_url):
+ if '<MPD' in string_or_url:
+ mpd_string = string_or_url
+ else:
+ try:
+ mpd_string = urlopen(string_or_url).read()
+ except ValueError:
+ with open(string_or_url, 'r') as f:
+ mpd_string = f.read()
+
+ return minidom.parseString(mpd_string)
+
+ @classmethod
+ def parse(cls, string_or_url):
+ xml_root_node = cls.load_xmldom(string_or_url)
+ return parse_child_nodes(xml_root_node, 'MPD', MPEGDASH)[0]
+
+ @classmethod
+ def write(cls, mpd, filepath):
+ xml_doc = minidom.Document()
+ write_child_node(xml_doc, 'MPD', mpd)
+ with open(filepath, 'w') as f:
+ xml_doc.writexml(f, indent=' ', addindent=' ', newl='\n')
diff --git a/mpegdash/schema/dash-mpd.xsd b/mpegdash/schema/dash-mpd.xsd
new file mode 100644
index 0000000..f78a89f
--- /dev/null
+++ b/mpegdash/schema/dash-mpd.xsd
@@ -0,0 +1,424 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema targetNamespace="urn:mpeg:DASH:schema:MPD:2011" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="urn:mpeg:DASH:schema:MPD:2011">
+
+ <xs:import namespace="http://www.w3.org/1999/xlink" schemaLocation="xlink.xsd"/>
+
+ <xs:annotation>
+ <xs:appinfo>Media Presentation Description</xs:appinfo>
+ <xs:documentation xml:lang="en">
+ This Schema defines the Media Presentation Description for MPEG-DASH.
+ </xs:documentation>
+ </xs:annotation>
+
+ <!-- MPD: main element -->
+ <xs:element name="MPD" type="MPDtype"/>
+
+ <!-- MPD Type -->
+ <xs:complexType name="MPDtype">
+ <xs:sequence>
+ <xs:element name="ProgramInformation" type="ProgramInformationType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="BaseURL" type="BaseURLType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="Location" type="xs:anyURI" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="Period" type="PeriodType" maxOccurs="unbounded"/>
+ <xs:element name="Metrics" type="MetricsType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="id" type="xs:string"/>
+ <xs:attribute name="profiles" type="xs:string" use="required"/>
+ <xs:attribute name="type" type="PresentationType" default="static"/>
+ <xs:attribute name="availabilityStartTime" type="xs:dateTime"/>
+ <xs:attribute name="availabilityEndTime" type="xs:dateTime"/>
+ <xs:attribute name="publishTime" type="xs:dateTime"/>
+ <xs:attribute name="mediaPresentationDuration" type="xs:duration"/>
+ <xs:attribute name="minimumUpdatePeriod" type="xs:duration"/>
+ <xs:attribute name="minBufferTime" type="xs:duration" use="required"/>
+ <xs:attribute name="timeShiftBufferDepth" type="xs:duration"/>
+ <xs:attribute name="suggestedPresentationDelay" type="xs:duration"/>
+ <xs:attribute name="maxSegmentDuration" type="xs:duration"/>
+ <xs:attribute name="maxSubsegmentDuration" type="xs:duration"/>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+
+ <!-- Presentation Type enumeration -->
+ <xs:simpleType name="PresentationType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="static"/>
+ <xs:enumeration value="dynamic"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <!-- Period -->
+ <xs:complexType name="PeriodType">
+ <xs:sequence>
+ <xs:element name="BaseURL" type="BaseURLType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="SegmentBase" type="SegmentBaseType" minOccurs="0"/>
+ <xs:element name="SegmentList" type="SegmentListType" minOccurs="0"/>
+ <xs:element name="SegmentTemplate" type="SegmentTemplateType" minOccurs="0"/>
+ <xs:element name="AssetIdentifier" type="DescriptorType" minOccurs="0"/>
+ <xs:element name="EventStream" type="EventStreamType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="AdaptationSet" type="AdaptationSetType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="Subset" type="SubsetType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute ref="xlink:href"/>
+ <xs:attribute ref="xlink:actuate" default="onRequest"/>
+ <xs:attribute name="id" type="xs:string"/>
+ <xs:attribute name="start" type="xs:duration"/>
+ <xs:attribute name="duration" type="xs:duration"/>
+ <xs:attribute name="bitstreamSwitching" type="xs:boolean" default="false"/>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+
+ <!-- Event Stream -->
+ <xs:complexType name="EventStreamType">
+ <xs:sequence>
+ <xs:element name="Event" type="EventType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute ref="xlink:href"/>
+ <xs:attribute ref="xlink:actuate" default="onRequest"/>
+ <xs:attribute name="schemeIdUri" type="xs:anyURI" use="required"/>
... 824 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-mpegdash.git
More information about the Python-modules-commits
mailing list