Skip to content
Snippets Groups Projects
Commit 3c765104 authored by Ondřej Kobližek's avatar Ondřej Kobližek
Browse files

import python-mpegdash-0.1.0.orig.tar.gz

parents
No related branches found
Tags upstream/0.1.0
No related merge requests found
Showing with 950 additions and 0 deletions
*.py[co]
*.sw[op]
*.ropeproject
tests/mpd-samples/output.mpd
language: python
python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"
- "3.5"
script: python setup.py test
LICENSE 0 → 100644
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.
[![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')
This diff is collapsed.
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')
<?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"/>
<xs:attribute name="value" type="xs:string"/>
<xs:attribute name="timescale" type="xs:unsignedInt"/>
</xs:complexType>
<!-- Event -->
<xs:complexType name="EventType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="presentationTime" type="xs:unsignedLong" default="0"/>
<xs:attribute name="duration" type="xs:unsignedLong"/>
<xs:attribute name="id" type="xs:unsignedInt"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Adaptation Set -->
<xs:complexType name="AdaptationSetType">
<xs:complexContent>
<xs:extension base="RepresentationBaseType">
<xs:sequence>
<xs:element name="Accessibility" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Role" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Rating" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Viewpoint" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="ContentComponent" type="ContentComponentType" minOccurs="0" maxOccurs="unbounded"/>
<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="Representation" type="RepresentationType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute ref="xlink:href"/>
<xs:attribute ref="xlink:actuate" default="onRequest"/>
<xs:attribute name="id" type="xs:unsignedInt"/>
<xs:attribute name="group" type="xs:unsignedInt"/>
<xs:attribute name="lang" type="xs:language"/>
<xs:attribute name="contentType" type="xs:string"/>
<xs:attribute name="par" type="RatioType"/>
<xs:attribute name="minBandwidth" type="xs:unsignedInt"/>
<xs:attribute name="maxBandwidth" type="xs:unsignedInt"/>
<xs:attribute name="minWidth" type="xs:unsignedInt"/>
<xs:attribute name="maxWidth" type="xs:unsignedInt"/>
<xs:attribute name="minHeight" type="xs:unsignedInt"/>
<xs:attribute name="maxHeight" type="xs:unsignedInt"/>
<xs:attribute name="minFrameRate" type="FrameRateType"/>
<xs:attribute name="maxFrameRate" type="FrameRateType"/>
<xs:attribute name="segmentAlignment" type="ConditionalUintType" default="false"/>
<xs:attribute name="subsegmentAlignment" type="ConditionalUintType" default="false"/>
<xs:attribute name="subsegmentStartsWithSAP" type="SAPType" default="0"/>
<xs:attribute name="bitstreamSwitching" type="xs:boolean"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- Ratio Type for sar and par -->
<xs:simpleType name="RatioType">
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]*:[0-9]*"/>
</xs:restriction>
</xs:simpleType>
<!-- Type for Frame Rate -->
<xs:simpleType name="FrameRateType">
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]*[0-9](/[0-9]*[0-9])?"/>
</xs:restriction>
</xs:simpleType>
<!-- Conditional Unsigned Integer (unsignedInt or boolean) -->
<xs:simpleType name="ConditionalUintType">
<xs:union memberTypes="xs:unsignedInt xs:boolean"/>
</xs:simpleType>
<!-- Content Component -->
<xs:complexType name="ContentComponentType">
<xs:sequence>
<xs:element name="Accessibility" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Role" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Rating" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Viewpoint" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="id" type="xs:unsignedInt"/>
<xs:attribute name="lang" type="xs:language"/>
<xs:attribute name="contentType" type="xs:string"/>
<xs:attribute name="par" type="RatioType"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<!-- Representation -->
<xs:complexType name="RepresentationType">
<xs:complexContent>
<xs:extension base="RepresentationBaseType">
<xs:sequence>
<xs:element name="BaseURL" type="BaseURLType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="SubRepresentation" type="SubRepresentationType" 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:sequence>
<xs:attribute name="id" type="StringNoWhitespaceType" use="required"/>
<xs:attribute name="bandwidth" type="xs:unsignedInt" use="required"/>
<xs:attribute name="qualityRanking" type="xs:unsignedInt"/>
<xs:attribute name="dependencyId" type="StringVectorType"/>
<xs:attribute name="mediaStreamStructureId" type="StringVectorType"/>
<xs:attribute name="numChannels" type="xs:unsignedInt"/>
<xs:attribute name="sampleRate" type="xs:unsignedLong"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- String without white spaces -->
<xs:simpleType name="StringNoWhitespaceType">
<xs:restriction base="xs:string">
<xs:pattern value="[^\r\n\t \p{Z}]*"/>
</xs:restriction>
</xs:simpleType>
<!-- SubRepresentation -->
<xs:complexType name="SubRepresentationType">
<xs:complexContent>
<xs:extension base="RepresentationBaseType">
<xs:attribute name="level" type="xs:unsignedInt"/>
<xs:attribute name="dependencyLevel" type="UIntVectorType"/>
<xs:attribute name="bandwidth" type="xs:unsignedInt"/>
<xs:attribute name="contentComponent" type="StringVectorType"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- Representation base (common attributes and elements) -->
<xs:complexType name="RepresentationBaseType">
<xs:sequence>
<xs:element name="FramePacking" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="AudioChannelConfiguration" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="ContentProtection" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="EssentialProperty" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="SupplementalProperty" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="InbandEventStream" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="profiles" type="xs:string"/>
<xs:attribute name="width" type="xs:unsignedInt"/>
<xs:attribute name="height" type="xs:unsignedInt"/>
<xs:attribute name="sar" type="RatioType"/>
<xs:attribute name="frameRate" type="FrameRateType"/>
<xs:attribute name="audioSamplingRate" type="xs:string"/>
<xs:attribute name="mimeType" type="xs:string"/>
<xs:attribute name="segmentProfiles" type="xs:string"/>
<xs:attribute name="codecs" type="xs:string"/>
<xs:attribute name="maximumSAPPeriod" type="xs:double"/>
<xs:attribute name="startWithSAP" type="SAPType"/>
<xs:attribute name="maxPlayoutRate" type="xs:double"/>
<xs:attribute name="codingDependency" type="xs:boolean"/>
<xs:attribute name="scanType" type="VideoScanType"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<!-- Stream Access Point type enumeration -->
<xs:simpleType name="SAPType">
<xs:restriction base="xs:unsignedInt">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="6"/>
</xs:restriction>
</xs:simpleType>
<!-- Video Scan type enumeration -->
<xs:simpleType name="VideoScanType">
<xs:restriction base="xs:string">
<xs:enumeration value="progressive"/>
<xs:enumeration value="interlaced"/>
<xs:enumeration value="unknown"/>
</xs:restriction>
</xs:simpleType>
<!-- Subset -->
<xs:complexType name="SubsetType">
<xs:attribute name="contains" type="UIntVectorType" use="required"/>
<xs:attribute name="id" type="xs:string"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<!-- Segment information base -->
<xs:complexType name="SegmentBaseType">
<xs:sequence>
<xs:element name="Initialization" type="URLType" minOccurs="0"/>
<xs:element name="RepresentationIndex" type="URLType" minOccurs="0"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="timescale" type="xs:unsignedInt"/>
<xs:attribute name="presentationTimeOffset" type="xs:unsignedLong"/>
<xs:attribute name="indexRange" type="xs:string"/>
<xs:attribute name="indexRangeExact" type="xs:boolean" default="false"/>
<xs:attribute name="availabilityTimeOffset" type="xs:double"/>
<xs:attribute name="availabilityTimeComplete" type="xs:boolean"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<!-- Multiple Segment information base -->
<xs:complexType name="MultipleSegmentBaseType">
<xs:complexContent>
<xs:extension base="SegmentBaseType">
<xs:sequence>
<xs:element name="SegmentTimeline" type="SegmentTimelineType" minOccurs="0"/>
<xs:element name="BitstreamSwitching" type="URLType" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="duration" type="xs:unsignedInt"/>
<xs:attribute name="startNumber" type="xs:unsignedInt"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- Segment Info item URL/range -->
<xs:complexType name="URLType">
<xs:sequence>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="sourceURL" type="xs:anyURI"/>
<xs:attribute name="range" type="xs:string"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<!-- Segment List -->
<xs:complexType name="SegmentListType">
<xs:complexContent>
<xs:extension base="MultipleSegmentBaseType">
<xs:sequence>
<xs:element name="SegmentURL" type="SegmentURLType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute ref="xlink:href"/>
<xs:attribute ref="xlink:actuate" default="onRequest"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- Segment URL -->
<xs:complexType name="SegmentURLType">
<xs:sequence>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="media" type="xs:anyURI"/>
<xs:attribute name="mediaRange" type="xs:string"/>
<xs:attribute name="index" type="xs:anyURI"/>
<xs:attribute name="indexRange" type="xs:string"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<!-- Segment Template -->
<xs:complexType name="SegmentTemplateType">
<xs:complexContent>
<xs:extension base="MultipleSegmentBaseType">
<xs:attribute name="media" type="xs:string"/>
<xs:attribute name="index" type="xs:string"/>
<xs:attribute name="initialization" type="xs:string"/>
<xs:attribute name="bitstreamSwitching" type="xs:string"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- Segment Timeline -->
<xs:complexType name="SegmentTimelineType">
<xs:sequence>
<xs:element name="S" minOccurs="1" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="t" type="xs:unsignedLong"/>
<xs:attribute name="d" type="xs:unsignedLong" use="required"/>
<xs:attribute name="r" type="xs:integer" use="optional" default="0"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
</xs:element>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<!-- Whitespace-separated list of strings -->
<xs:simpleType name="StringVectorType">
<xs:list itemType="xs:string"/>
</xs:simpleType>
<!-- Whitespace-separated list of unsigned integers -->
<xs:simpleType name="UIntVectorType">
<xs:list itemType="xs:unsignedInt"/>
</xs:simpleType>
<!-- Base URL -->
<xs:complexType name="BaseURLType">
<xs:simpleContent>
<xs:extension base="xs:anyURI">
<xs:attribute name="serviceLocation" type="xs:string"/>
<xs:attribute name="byteRange" type="xs:string"/>
<xs:attribute name="availabilityTimeOffset" type="xs:double"/>
<xs:attribute name="availabilityTimeComplete" type="xs:boolean"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Program Information -->
<xs:complexType name="ProgramInformationType">
<xs:sequence>
<xs:element name="Title" type="xs:string" minOccurs="0"/>
<xs:element name="Source" type="xs:string" minOccurs="0"/>
<xs:element name="Copyright" type="xs:string" minOccurs="0"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="lang" type="xs:language"/>
<xs:attribute name="moreInformationURL" type="xs:anyURI"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<!-- Descriptor -->
<xs:complexType name="DescriptorType">
<xs:sequence>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="schemeIdUri" type="xs:anyURI" use="required"/>
<xs:attribute name="value" type="xs:string"/>
<xs:attribute name="id" type="xs:string"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<!-- Metrics -->
<xs:complexType name="MetricsType">
<xs:sequence>
<xs:element name="Reporting" type="DescriptorType" maxOccurs="unbounded"/>
<xs:element name="Range" type="RangeType" minOccurs="0" maxOccurs="unbounded"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="metrics" type="xs:string" use="required"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<!-- Metrics Range -->
<xs:complexType name="RangeType">
<xs:attribute name="starttime" type="xs:duration"/>
<xs:attribute name="duration" type="xs:duration"/>
</xs:complexType>
</xs:schema>
from 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:
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 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 = 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])
xmlnode.setAttribute(attr_name, str(attr_val))
setup.py 0 → 100644
from os.path import dirname, abspath, join, exists
from setuptools import setup
long_description = None
if exists("README.md"):
long_description = open("README.md").read()
install_reqs = [req for req in open(abspath(join(dirname(__file__), 'requirements.txt')))]
tests_reqs = [req for req in open(abspath(join(dirname(__file__), 'test-requirements.txt')))]
setup(
name="mpegdash",
packages=["mpegdash"],
description="MPEG-DASH MPD(Media Presentation Description) Parser",
long_description=long_description,
author="supercast",
author_email="gamzabaw@gmail.com",
version="0.1.0",
license="MIT",
zip_safe=False,
include_package_data=True,
install_requires=install_reqs,
url="https://github.com/caststack/python-mpegdash",
tests_require=tests_reqs,
test_suite="tests.my_module_suite",
)
try:
import unittest2 as unittest
except:
import unittest
def my_module_suite():
loader = unittest.TestLoader()
suite = loader.discover('tests', pattern='test_*.py')
return suite
<?xml version="1.0"?>
<!-- MPD file Generated with GPAC version 0.6.1-revUNKNOWN_REV at 2016-04-29T07:40:49.201Z-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500S" type="static" mediaPresentationDuration="PT0H0M22.959S" maxSegmentDuration="PT0H0M10.000S" profiles="urn:mpeg:dash:profile:isoff-main:2011">
<ProgramInformation moreInformationURL="http://gpac.sourceforge.net">
<Title>360p_speciment_dash.mpd generated by GPAC</Title>
</ProgramInformation>
<Period duration="PT0H0M22.959S">
<AdaptationSet segmentAlignment="true" maxWidth="864" maxHeight="360" maxFrameRate="24" par="864:360" lang="eng">
<ContentComponent id="1" contentType="video" />
<ContentComponent id="2" contentType="audio" />
<Representation id="1" mimeType="video/mp4" codecs="avc3.42c01e,mp4a.40.2" width="864" height="360" frameRate="24" sar="1:1" audioSamplingRate="32000" startWithSAP="1" bandwidth="708622">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
<BaseURL>360p_speciment_dashinit.mp4</BaseURL>
<SegmentList timescale="1000" duration="10000">
<Initialization range="0-1391"/>
<SegmentURL mediaRange="1392-840737" indexRange="1392-1663"/>
<SegmentURL mediaRange="840738-1763124" indexRange="840738-841009"/>
<SegmentURL mediaRange="1763125-2037996" indexRange="1763125-1763228"/>
</SegmentList>
</Representation>
</AdaptationSet>
</Period>
</MPD>
\ No newline at end of file
<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>
<Representation bandwidth="2073921" codecs="avc1.4d401f" height="720" id="2" mimeType="video/mp4" width="1280">
<BaseURL>motion-20120802-88.mp4</BaseURL>
<SegmentBase indexRange="672-979">
<Initialization range="0-671" />
</SegmentBase>
</Representation>
<Representation bandwidth="869460" codecs="avc1.4d401e" height="480" id="3" mimeType="video/mp4" width="854">
<BaseURL>motion-20120802-87.mp4</BaseURL>
<SegmentBase indexRange="672-979">
<Initialization range="0-671" />
</SegmentBase>
</Representation>
<Representation bandwidth="686521" codecs="avc1.4d401e" height="360" id="4" mimeType="video/mp4" width="640">
<BaseURL>motion-20120802-86.mp4</BaseURL>
<SegmentBase indexRange="672-979">
<Initialization range="0-671" />
</SegmentBase>
</Representation>
<Representation bandwidth="264835" codecs="avc1.4d4015" height="240" id="5" mimeType="video/mp4" width="426">
<BaseURL>motion-20120802-85.mp4</BaseURL>
<SegmentBase indexRange="672-979">
<Initialization range="0-671" />
</SegmentBase>
</Representation>
</AdaptationSet>
<AdaptationSet>
<ContentComponent contentType="audio" id="2" />
<Representation bandwidth="127236" codecs="mp4a.40.02" id="6" mimeType="audio/mp4" numChannels="2" sampleRate="44100">
<BaseURL>motion-20120802-8c.mp4</BaseURL>
<SegmentBase indexRange="592-767">
<Initialization range="0-591" />
</SegmentBase>
</Representation>
<Representation bandwidth="255236" codecs="mp4a.40.02" id="7" mimeType="audio/mp4" numChannels="2" sampleRate="44100">
<BaseURL>motion-20120802-8d.mp4</BaseURL>
<SegmentBase indexRange="592-767">
<Initialization range="0-591" />
</SegmentBase>
</Representation>
<Representation bandwidth="31749" codecs="mp4a.40.03" id="8" mimeType="audio/mp4" numChannels="1" sampleRate="22050">
<BaseURL>motion-20120802-8b.mp4</BaseURL>
<SegmentBase indexRange="592-767">
<Initialization range="0-591" />
</SegmentBase>
</Representation>
</AdaptationSet>
</Period>
</MPD>
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" mediaPresentationDuration="PT0H4M2.93S" minBufferTime="PT1.5S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011"
type="static">
<Period duration="PT0H4M2.93S" start="PT0S">
<AdaptationSet>
<ContentComponent contentType="video" id="1" />
<Representation bandwidth="4190760" codecs="avc1.640028" height="1080" id="1" mimeType="video/mp4" width="1920">
<BaseURL>oops-20120802-89.mp4</BaseURL>
<SegmentBase indexRange="674-1293">
<Initialization range="0-673" />
</SegmentBase>
</Representation>
<Representation bandwidth="2073921" codecs="avc1.4d401f" height="720" id="2" mimeType="video/mp4" width="1280">
<BaseURL>oops-20120802-88.mp4</BaseURL>
<SegmentBase indexRange="672-1291">
<Initialization range="0-671" />
</SegmentBase>
</Representation>
<Representation bandwidth="869460" codecs="avc1.4d401e" height="480" id="3" mimeType="video/mp4" width="854">
<BaseURL>oops-20120802-87.mp4</BaseURL>
<SegmentBase indexRange="672-1291">
<Initialization range="0-671" />
</SegmentBase>
</Representation>
<Representation bandwidth="686521" codecs="avc1.4d401e" height="360" id="4" mimeType="video/mp4" width="640">
<BaseURL>oops-20120802-86.mp4</BaseURL>
<SegmentBase indexRange="672-1291">
<Initialization range="0-671" />
</SegmentBase>
</Representation>
<Representation bandwidth="264835" codecs="avc1.4d4015" height="240" id="5" mimeType="video/mp4" width="426">
<BaseURL>oops-20120802-85.mp4</BaseURL>
<SegmentBase indexRange="672-1291">
<Initialization range="0-671" />
</SegmentBase>
</Representation>
</AdaptationSet>
<AdaptationSet>
<ContentComponent contentType="audio" id="2" />
<Representation bandwidth="127236" codecs="mp4a.40.02" id="6" mimeType="audio/mp4" numChannels="2" sampleRate="44100">
<BaseURL>oops-20120802-8c.mp4</BaseURL>
<SegmentBase indexRange="592-923">
<Initialization range="0-591" />
</SegmentBase>
</Representation>
<Representation bandwidth="255236" codecs="mp4a.40.02" id="7" mimeType="audio/mp4" numChannels="2" sampleRate="44100">
<BaseURL>oops-20120802-8d.mp4</BaseURL>
<SegmentBase indexRange="592-923">
<Initialization range="0-591" />
</SegmentBase>
</Representation>
<Representation bandwidth="31749" codecs="mp4a.40.03" id="8" mimeType="audio/mp4" numChannels="1" sampleRate="22050">
<BaseURL>oops-20120802-8b.mp4</BaseURL>
<SegmentBase indexRange="592-923">
<Initialization range="0-591" />
</SegmentBase>
</Representation>
</AdaptationSet>
</Period>
</MPD>
<?xml version="1.0"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" profiles="urn:mpeg:dash:profile:full:2011" minBufferTime="PT1.5S">
<!-- Ad -->
<Period duration="PT30S">
<BaseURL>ad/</BaseURL>
<!-- Everything in one Adaptation Set -->
<AdaptationSet mimeType="video/mp2t">
<!-- 720p Representation at 3.2 Mbps -->
<Representation id="720p" bandwidth="3200000" width="1280" height="720">
<!-- Just use one segment, since the ad is only 30 seconds long -->
<BaseURL>720p.ts</BaseURL>
<SegmentBase>
<RepresentationIndex sourceURL="720p.sidx"/>
</SegmentBase>
</Representation>
<!-- 1080p Representation at 6.8 Mbps -->
<Representation id="1080p" bandwidth="6800000" width="1920" height="1080">
<BaseURL>1080p.ts</BaseURL>
<SegmentBase>
<RepresentationIndex sourceURL="1080p.sidx"/>
</SegmentBase>
</Representation>
</AdaptationSet>
</Period>
<!-- Normal Content -->
<Period duration="PT5M">
<BaseURL>main/</BaseURL>
<!-- Just the video -->
<AdaptationSet mimeType="video/mp2t">
<BaseURL>video/</BaseURL>
<!-- 720p Representation at 3.2 Mbps -->
<Representation id="720p" bandwidth="3200000" width="1280" height="720">
<BaseURL>720p/</BaseURL>
<!-- First, we'll just list all of the segments -->
<!-- Timescale is "ticks per second", so each segment is 1 minute long -->
<SegmentList timescale="90000" duration="5400000">
<RepresentationIndex sourceURL="representation-index.sidx"/>
<SegmentURL media="segment-1.ts"/>
<SegmentURL media="segment-2.ts"/>
<SegmentURL media="segment-3.ts"/>
<SegmentURL media="segment-4.ts"/>
<SegmentURL media="segment-5.ts"/>
<SegmentURL media="segment-6.ts"/>
<SegmentURL media="segment-7.ts"/>
<SegmentURL media="segment-8.ts"/>
<SegmentURL media="segment-9.ts"/>
<SegmentURL media="segment-10.ts"/>
</SegmentList>
</Representation>
<!-- 1080p Representation at 6.8 Mbps -->
<Representation id="1080p" bandwidth="6800000" width="1920" height="1080">
<BaseURL>1080/</BaseURL>
<!-- Since all of our segments have similar names, this time we'll use a SegmentTemplate -->
<SegmentTemplate media="segment-$Number$.ts" timescale="90000">
<RepresentationIndex sourceURL="representation-index.sidx"/>
<!-- Let's add a SegmentTimeline so the client can easily see how many segments there are
-->
<SegmentTimeline>
<!-- This reads: Starting from time 0, there are 10 segments with a duration of
(5400000 / @timescale) seconds -->
<S t="0" r="10" d="5400000"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
<!-- Just the audio -->
<AdaptationSet mimeType="audio/mp2t">
<BaseURL>audio/</BaseURL>
<!-- We're just going to offer one audio representation, since audio bandwidth isn't very
important. -->
<Representation id="audio" bandwidth="128000">
<SegmentTemplate media="segment-$Number$.ts" timescale="90000">
<RepresentationIndex sourceURL="representation-index.sidx"/>
<SegmentTimeline>
<S t="0" r="10" d="5400000"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
</MPD>
\ No newline at end of file
try:
import unittest2 as unittest
except:
import unittest
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))
try:
import unittest2 as unittest
except:
import unittest
from mpegdash.parser import MPEGDASHParser
class XML2MPDTestCase(unittest.TestCase):
def test_xml2mpd_from_string(self):
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>
'''
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 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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment