pax_global_header00006660000000000000000000000064142105347040014512gustar00rootroot0000000000000052 comment=48b52122cdbcaebe1804b79f77d05dfc1ce32900 python-mpegdash-0.3.1/000077500000000000000000000000001421053470400146225ustar00rootroot00000000000000python-mpegdash-0.3.1/.github/000077500000000000000000000000001421053470400161625ustar00rootroot00000000000000python-mpegdash-0.3.1/.github/workflows/000077500000000000000000000000001421053470400202175ustar00rootroot00000000000000python-mpegdash-0.3.1/.github/workflows/build-status.yml000066400000000000000000000026341421053470400233670ustar00rootroot00000000000000# This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Build Status on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest strategy: matrix: # <=2.6 and 2.8 isn't available: https://github.com/actions/python-versions/blob/main/versions-manifest.json python-version: ['2.7', '3.x'] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install build flake8 python -m pip install -r requirements.txt - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Run tests run: | python -m unittest discover - name: Build run: | python -m build python-mpegdash-0.3.1/.github/workflows/release-packager.yml000066400000000000000000000015221421053470400241350ustar00rootroot00000000000000# This workflows will upload a Python Package using Twine when a release is created # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries name: Release Packager on: release: types: [published] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.9' - name: Install dependencies run: | python -m pip install --upgrade pip pip install build setuptools wheel twine - name: Build and publish env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | python -m build twine upload dist/* python-mpegdash-0.3.1/.gitignore000066400000000000000000000026001421053470400166100ustar00rootroot00000000000000# python-mpegdash specific *.sw[op] tests/mpd-samples/output.mpd # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # JetBrains project settings .idea # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ python-mpegdash-0.3.1/.travis.yml000066400000000000000000000001241421053470400167300ustar00rootroot00000000000000language: python python: - "2.7" - "3.4" - "3.5" script: python setup.py test python-mpegdash-0.3.1/LICENSE000066400000000000000000000020671421053470400156340ustar00rootroot00000000000000The 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. python-mpegdash-0.3.1/README.md000066400000000000000000000036361421053470400161110ustar00rootroot00000000000000 # python-mpegdash MPEG-DASH MPD (Media Presentation Description) Parser compatible with Python 2.6+ and Python 3. [![Build Status](https://img.shields.io/github/workflow/status/sangwonl/python-mpegdash/Build%20Status?label=Python%202.7%2B%20builds)](https://github.com/sangwonl/python-mpegdash/actions?query=workflow%3A%22Build+Status%22) [![License](https://img.shields.io/github/license/sangwonl/python-mpegdash?style=flat)](https://github.com/sangwonl/python-mpegdash/blob/master/LICENSE) * * * ## Installation ```bash $ pip install mpegdash ``` * * * ## Test ```bash $ python -m unittest discover $ python3 -m unittest discover ``` * * * ## Usage ```py 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 = ''' motion-20120802-89.mp4 ''' mpd = MPEGDASHParser.parse(mpd_string) # Write to xml file MPEGDASHParser.write(mpd, './tests/mpd-samples/output.mpd') ``` * * * ## License This project is released under the MIT license. Please read and agree to the license before use, it can be found in the [LICENSE](LICENSE) file. python-mpegdash-0.3.1/mpegdash/000077500000000000000000000000001421053470400164125ustar00rootroot00000000000000python-mpegdash-0.3.1/mpegdash/__init__.py000066400000000000000000000000001421053470400205110ustar00rootroot00000000000000python-mpegdash-0.3.1/mpegdash/nodes.py000066400000000000000000001220301421053470400200720ustar00rootroot00000000000000from 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 XsStringElement(XMLNode): def __init__(self): self.text = None def parse(self, xmlnode): self.text = parse_node_value(xmlnode, str) def write(self, xmlnode): write_node_value(xmlnode, self.text) 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', XsStringElement) self.sources = parse_child_nodes(xmlnode, 'Source', XsStringElement) self.copyrights = parse_child_nodes(xmlnode, 'Copyright', XsStringElement) 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.end_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.end_number = parse_attr_value(xmlnode, 'endNumber', 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_attr_value(xmlnode, 'endNumber', self.end_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.message_data = 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.message_data = parse_attr_value(xmlnode, 'messageData', 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, 'messageData', self.message_data) 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 PSSH(XMLNode): def __init__(self): self.pssh = None def parse(self, xmlnode): self.pssh = parse_node_value(xmlnode, str) def write(self, xmlnode): write_node_value(xmlnode, self.pssh) class ContentProtection(XMLNode): def __init__(self): self.scheme_id_uri = "" # xs:anyURI (required) self.value = None # xs:string self.id = None # xs:string self.pssh = None # PSSH self.default_key_id = None # xs:string self.ns2_key_id = None # xs:string self.cenc_default_kid = 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) self.default_key_id = parse_attr_value(xmlnode, "default_KID", str) self.ns2_key_id = parse_attr_value(xmlnode, "ns2:default_KID", str) self.cenc_default_kid = parse_attr_value(xmlnode, "cenc:default_KID", str) self.pssh = parse_child_nodes(xmlnode, "cenc:pssh", PSSH) 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) write_attr_value(xmlnode, "default_KID", self.default_key_id) write_attr_value(xmlnode, "ns2:default_KID", self.ns2_key_id) write_attr_value(xmlnode, "cenc:default_KID", self.cenc_default_kid) write_child_node(xmlnode, "cenc:pssh", self.pssh) 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.profile = None # xs:string 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 # ContentProtection* self.essential_properties = None # DescriptorType* self.supplemental_properties = None # DescriptorType* self.inband_event_streams = None # DescriptorType* def parse(self, xmlnode): self.profile = parse_attr_value(xmlnode, 'profile', str) self.profiles = parse_attr_value(xmlnode, 'profiles', 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', ContentProtection) 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.profile) write_attr_value(xmlnode, 'profiles', 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.label = None # xs:string 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.selection_priority = None # xs:unsignedInt 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.label = parse_attr_value(xmlnode, 'label', 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.selection_priority = parse_attr_value(xmlnode, 'selectionPriority', int) 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, 'label', self.label) write_attr_value(xmlnode, 'contentType', self.content_type) 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, 'selectionPriority', self.selection_priority) 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.cenc = None # xs:string 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* self.utc_timings = None # DescriptorType* 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.cenc = parse_attr_value(xmlnode, "xmlns:cenc", 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', XsStringElement) self.periods = parse_child_nodes(xmlnode, 'Period', Period) self.metrics = parse_child_nodes(xmlnode, 'Metrics', Metrics) self.utc_timings = parse_child_nodes(xmlnode, 'UTCTiming', Descriptor) 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, "xmlns:cenc", self.cenc) 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) write_child_node(xmlnode, 'UTCTiming', self.utc_timings) python-mpegdash-0.3.1/mpegdash/parser.py000066400000000000000000000024671421053470400202710ustar00rootroot00000000000000from xml.dom import minidom # python3 support try: from urllib2 import urlopen except ImportError: from urllib.request import urlopen from mpegdash.nodes import MPEGDASH from mpegdash.utils import parse_child_nodes, write_child_node from mpegdash.prettyprinter import pretty_print class MPEGDASHParser(object): @classmethod def load_xmldom(cls, string_or_url): if ']*>$', line): # single line text element, don't change indentation addition = 0 elif re.match(r'^ 0: # end of element and have padding, decrement indentation by one current[0] -= 1 elif re.match(r'^<\w[^>]*[^/]>.*$', line): # start of element, increment indentation by one addition = 1 else: # single line element, don't change indentation addition = 0 # update and store current indentation in outer function current[0] += addition # pad the line and return return (indent * (current[0] - addition)) + line # split the document into lines, indent each line, then rejoin lines return line_break.join( map( indent_line, re.sub('(>)(<)(/*)', r'\1\n\2\3', xmlstr).split('\n') ) ) python-mpegdash-0.3.1/mpegdash/schema/000077500000000000000000000000001421053470400176525ustar00rootroot00000000000000python-mpegdash-0.3.1/mpegdash/schema/dash-mpd.xsd000066400000000000000000000474361421053470400221050ustar00rootroot00000000000000 Media Presentation Description This Schema defines the Media Presentation Description for MPEG-DASH. python-mpegdash-0.3.1/mpegdash/utils.py000066400000000000000000000045601421053470400201310ustar00rootroot00000000000000from past.builtins import unicode # python3 compat from xml.dom import minidom import re def _find_child_nodes_by_name(parent, name): nodes = [] for node in parent.childNodes: if node.nodeType == node.ELEMENT_NODE and (node.localName == name or node.nodeName == name): nodes.append(node) return nodes def parse_child_nodes(xmlnode, tag_name, node_type): elements = _find_child_nodes_by_name(xmlnode, tag_name) if not elements: return None nodes = [] for elem in elements: if node_type in (unicode, str): node = xmlnode.firstChild.nodeValue else: node = node_type() node.parse(elem) nodes.append(node) return nodes def parse_node_value(xmlnode, value_type): node_val = xmlnode.firstChild.nodeValue if xmlnode.firstChild else None if node_val: return value_type(node_val) return None def parse_attr_value(xmlnode, attr_name, value_type): if attr_name not in xmlnode.attributes.keys(): return None attr_val = xmlnode.attributes[attr_name].nodeValue if isinstance(value_type, list): attr_type = value_type[0] if len(value_type) > 0 else str return [attr_type(elem) for elem in re.split(r'[, ]', attr_val)] return value_type(attr_val) def write_child_node(xmlnode, tag_name, node): if node: xmldoc = xmlnode if isinstance(xmlnode, minidom.Document) else xmlnode.ownerDocument if isinstance(node, list): for n in node: new_elem = xmldoc.createElement(tag_name) n.write(new_elem) xmlnode.appendChild(new_elem) else: new_elem = xmldoc.createElement(tag_name) node.write(new_elem) xmlnode.appendChild(new_elem) def write_node_value(xmlnode, node_val): if node_val: xmldoc = xmlnode if isinstance(xmlnode, minidom.Document) else xmlnode.ownerDocument text_node = xmldoc.createTextNode(str(node_val)) xmlnode.appendChild(text_node) def write_attr_value(xmlnode, attr_name, attr_val): if attr_name and attr_val is not None: if isinstance(type(attr_val), list): attr_val = ' '.join([str(val) for val in attr_val]) val = str(attr_val) if type(attr_val) is bool: val = val.lower() xmlnode.setAttribute(attr_name, val) python-mpegdash-0.3.1/requirements.txt000066400000000000000000000000071421053470400201030ustar00rootroot00000000000000future python-mpegdash-0.3.1/setup.py000066400000000000000000000017421421053470400163400ustar00rootroot00000000000000from os.path import exists from setuptools import setup long_description = None if exists("README.md"): long_description = open("README.md").read() setup( name="mpegdash", packages=["mpegdash"], description="MPEG-DASH MPD(Media Presentation Description) Parser", long_description=long_description, long_description_content_type='text/markdown', author="sangwonl", author_email="gamzabaw@gmail.com", version="0.3.1", license="MIT", zip_safe=False, include_package_data=True, install_requires=["future"], url="https://github.com/sangwonl/python-mpegdash", tests_require=["unittest2"], test_suite="tests.my_module_suite", classifiers=[ "Programming Language :: Python", "Programming Language :: Python :: 3", "Environment :: Other Environment", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Topic :: Software Development :: Libraries :: Python Modules", ], ) python-mpegdash-0.3.1/tests/000077500000000000000000000000001421053470400157645ustar00rootroot00000000000000python-mpegdash-0.3.1/tests/__init__.py000066400000000000000000000003251421053470400200750ustar00rootroot00000000000000try: import unittest except ImportError: import unittest2 as unittest def my_module_suite(): loader = unittest.TestLoader() suite = loader.discover('tests', pattern='test_*.py') return suite python-mpegdash-0.3.1/tests/mpd-samples/000077500000000000000000000000001421053470400202065ustar00rootroot00000000000000python-mpegdash-0.3.1/tests/mpd-samples/360p_speciment_dash.mpd000066400000000000000000000027021421053470400244470ustar00rootroot00000000000000 360p_speciment_dash.mpd generated by GPAC 360p_speciment_dashinit.mp4 python-mpegdash-0.3.1/tests/mpd-samples/motion-20120802-manifest.mpd000066400000000000000000000054761421053470400247310ustar00rootroot00000000000000 motion-20120802-89.mp4 motion-20120802-88.mp4 motion-20120802-87.mp4 motion-20120802-86.mp4 motion-20120802-85.mp4 motion-20120802-8c.mp4 motion-20120802-8d.mp4 motion-20120802-8b.mp4 python-mpegdash-0.3.1/tests/mpd-samples/oops-20120802-manifest.mpd000066400000000000000000000054611421053470400243760ustar00rootroot00000000000000 oops-20120802-89.mp4 oops-20120802-88.mp4 oops-20120802-87.mp4 oops-20120802-86.mp4 oops-20120802-85.mp4 oops-20120802-8c.mp4 oops-20120802-8d.mp4 oops-20120802-8b.mp4 python-mpegdash-0.3.1/tests/mpd-samples/sample-001.mpd000066400000000000000000000101441421053470400224670ustar00rootroot00000000000000 ad/ 720p.ts 1080p.ts main/ video/ 720p/ 1080/ audio/ python-mpegdash-0.3.1/tests/mpd-samples/utc_timing.mpd000066400000000000000000000013031421053470400230470ustar00rootroot00000000000000 http://www.example.com/location.mpd Test Title Test Source python-mpegdash-0.3.1/tests/mpd-samples/with_content_protection.mpd000066400000000000000000000027161421053470400256710ustar00rootroot00000000000000 AAAAWnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADoiMjc2NjQ2ZjYzNjk3MDY4NjU3MjBlNWZhZjdmODhiOTQ1ZWJhYmYzOWM2MTc4ZmFkNTc2SOPclZsG python-mpegdash-0.3.1/tests/mpd-samples/with_event_message_data.mpd000066400000000000000000000037571421053470400255750ustar00rootroot00000000000000 Some Random Event Text python-mpegdash-0.3.1/tests/test_mpdtoxml.py000066400000000000000000000041331421053470400212420ustar00rootroot00000000000000try: import unittest except ImportError: import unittest2 as unittest from sys import version_info from mpegdash.parser import MPEGDASHParser class MPD2XMLTestCase(unittest.TestCase): def test_mpd2xml(self): mpd = MPEGDASHParser.parse('./tests/mpd-samples/sample-001.mpd') MPEGDASHParser.write(mpd, './tests/mpd-samples/output.mpd') mpd2 = MPEGDASHParser.parse('./tests/mpd-samples/output.mpd') all_reprs = [] for period in mpd.periods: for adapt_set in period.adaptation_sets: for repr in adapt_set.representations: all_reprs.append(repr) all_reprs2 = [] for period in mpd2.periods: for adapt_set in period.adaptation_sets: for repr in adapt_set.representations: all_reprs2.append(repr) self.assertTrue(len(all_reprs) == 5) self.assertTrue(len(all_reprs) == len(all_reprs2)) def test_mpd2xml_boolean_casing(self): mpd = MPEGDASHParser.parse('./tests/mpd-samples/with_event_message_data.mpd') MPEGDASHParser.write(mpd, './tests/mpd-samples/output.mpd') with open('./tests/mpd-samples/output.mpd') as f: regex = r'segmentAlignment=\"true\"' # assertRegexpMatches is deprecated in 3, assertRegex not in 2 if version_info > (3, 1,): self.assertRegex(f.read(), regex) else: self.assertRegexpMatches(f.read(), regex) def test_mpd2xmlstr(self): # set maxDiff to None for Python2.6 self.maxDiff = None with open('./tests/mpd-samples/sample-001.mpd') as f: # read the test MPD mpd = MPEGDASHParser.parse(f.read()) # get the MPD as an XML string xmlstrout = MPEGDASHParser.toprettyxml(mpd) # then parse that string mpd2 = MPEGDASHParser.parse(xmlstrout) # get the reparsed MPD as a string xmlstrout2 = MPEGDASHParser.toprettyxml(mpd2) # and check the are equal self.assertEqual(xmlstrout, xmlstrout2) python-mpegdash-0.3.1/tests/test_xmltompd.py000066400000000000000000000114671421053470400212520ustar00rootroot00000000000000try: import unittest except ImportError: import unittest2 as unittest from mpegdash.parser import MPEGDASHParser class XML2MPDTestCase(unittest.TestCase): def test_xml2mpd_from_string(self): mpd_string = ''' motion-20120802-89.mp4 ''' self.assert_mpd(MPEGDASHParser.parse(mpd_string)) def test_xml2mpd_from_file(self): self.assert_mpd(MPEGDASHParser.parse('./tests/mpd-samples/sample-001.mpd')) self.assert_mpd(MPEGDASHParser.parse('./tests/mpd-samples/motion-20120802-manifest.mpd')) self.assert_mpd(MPEGDASHParser.parse('./tests/mpd-samples/oops-20120802-manifest.mpd')) self.assert_mpd(MPEGDASHParser.parse('./tests/mpd-samples/360p_speciment_dash.mpd')) def test_xml2mpd_from_url(self): mpd_url = 'http://yt-dash-mse-test.commondatastorage.googleapis.com/media/motion-20120802-manifest.mpd' self.assert_mpd(MPEGDASHParser.parse(mpd_url)) def test_xml2mpd_from_file_with_utc_timing(self): mpd = MPEGDASHParser.parse('./tests/mpd-samples/utc_timing.mpd') self.assertEqual(mpd.utc_timings[0].scheme_id_uri, 'urn:mpeg:dash:utc:http-iso:2014') self.assertEqual(mpd.utc_timings[0].value, 'https://time.akamai.com/?iso') def test_xml2mpd_from_file_with_event_messagedata(self): mpd = MPEGDASHParser.parse('./tests/mpd-samples/with_event_message_data.mpd') self.assertTrue(mpd.periods[0].event_streams[0].events[0].message_data is not None) self.assertTrue(mpd.periods[0].event_streams[0].events[0].event_value is None) self.assertTrue(mpd.periods[0].event_streams[0].events[1].message_data is None) self.assertEqual(mpd.periods[0].event_streams[0].events[1].event_value, "Some Random Event Text") def test_xml2mpd_parse_vector_type_attributes(self): mpd_string = ''' motion-20120802-89.mp4 ''' mpd = MPEGDASHParser.parse(mpd_string) self.assert_mpd(mpd) sub_rep = mpd.periods[0].adaptation_sets[0].representations[0].sub_representations[0] self.assertEqual(len(sub_rep.content_component), 2) self.assertEqual(sub_rep.content_component[0], '102') self.assertEqual(sub_rep.content_component[1], '104') def test_xml2mpd_from_file_with_content_protection(self): mpd = MPEGDASHParser.parse('./tests/mpd-samples/with_content_protection.mpd') self.assertEqual( "6c28b624-5854-5b8c-8033-9d61ac0c039c", mpd.periods[0].adaptation_sets[0].content_protections[0].cenc_default_kid ) self.assertEqual( "urn:mpeg:dash:mp4protection:2011", mpd.periods[0].adaptation_sets[0].content_protections[0].scheme_id_uri ) self.assertTrue(mpd.periods[0].adaptation_sets[0].content_protections[1].pssh[0].pssh is not None) def assert_mpd(self, mpd): self.assertTrue(mpd is not None) self.assertTrue(len(mpd.periods) > 0) self.assertTrue(mpd.periods[0].adaptation_sets is not None) self.assertTrue(len(mpd.periods[0].adaptation_sets) > 0) self.assertTrue(mpd.periods[0].adaptation_sets[0].representations is not None) self.assertTrue(len(mpd.periods[0].adaptation_sets[0].representations) > 0) self.assertTrue(len(mpd.periods[0].adaptation_sets[0].representations[0].id) > 0)