'Parse formats from MPD manifest.
References:
1. MPEG-DASH Standard, ISO/IEC 23009-1:2014(E),
http://standards.iso.org/ittf/PubliclyAvailableStandards/c065274_ISO_IEC_23009-1_2014.zip
2. https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP'

def _parse_mpd_formats(self, mpd_doc, mpd_id=None, mpd_base_url=u'', formats_dict={}, mpd_url=None):

    if (mpd_doc.get(u'type') == u'dynamic'):
        return []
    namespace = self._search_regex(u'(?i)^{([^}]+)?}MPD$', mpd_doc.tag, u'namespace', default=None)
    def _add_ns(path):
        return self._xpath_ns(path, namespace)
    def is_drm_protected(element):
        return (element.find(_add_ns(u'ContentProtection')) is not None)
    def extract_multisegment_info(element, ms_parent_info):
        ms_info = ms_parent_info.copy()
        def extract_common(source):
            segment_timeline = source.find(_add_ns(u'SegmentTimeline'))
            if (segment_timeline is not None):
                s_e = segment_timeline.findall(_add_ns(u'S'))
                if s_e:
                    ms_info[u'total_number'] = 0
                    ms_info[u's'] = []
                    for s in s_e:
                        r = int(s.get(u'r', 0))
                        ms_info[u'total_number'] += (1 + r)
                        ms_info[u's'].append({u't': int(s.get(u't', 0)), u'd': int(s.attrib[u'd']), u'r': r})
            start_number = source.get(u'startNumber')
            if start_number:
                ms_info[u'start_number'] = int(start_number)
            timescale = source.get(u'timescale')
            if timescale:
                ms_info[u'timescale'] = int(timescale)
            segment_duration = source.get(u'duration')
            if segment_duration:
                ms_info[u'segment_duration'] = int(segment_duration)
        def extract_Initialization(source):
            initialization = source.find(_add_ns(u'Initialization'))
            if (initialization is not None):
                ms_info[u'initialization_url'] = initialization.attrib[u'sourceURL']
        segment_list = element.find(_add_ns(u'SegmentList'))
        if (segment_list is not None):
            extract_common(segment_list)
            extract_Initialization(segment_list)
            segment_urls_e = segment_list.findall(_add_ns(u'SegmentURL'))
            if segment_urls_e:
                ms_info[u'segment_urls'] = [segment.attrib[u'media'] for segment in segment_urls_e]
        else:
            segment_template = element.find(_add_ns(u'SegmentTemplate'))
            if (segment_template is not None):
                extract_common(segment_template)
                media = segment_template.get(u'media')
                if media:
                    ms_info[u'media'] = media
                initialization = segment_template.get(u'initialization')
                if initialization:
                    ms_info[u'initialization'] = initialization
                else:
                    extract_Initialization(segment_template)
        return ms_info
    mpd_duration = parse_duration(mpd_doc.get(u'mediaPresentationDuration'))
    formats = []
    for period in mpd_doc.findall(_add_ns(u'Period')):
        period_duration = (parse_duration(period.get(u'duration')) or mpd_duration)
        period_ms_info = extract_multisegment_info(period, {u'start_number': 1, u'timescale': 1})
        for adaptation_set in period.findall(_add_ns(u'AdaptationSet')):
            if is_drm_protected(adaptation_set):
                continue
            adaption_set_ms_info = extract_multisegment_info(adaptation_set, period_ms_info)
            for representation in adaptation_set.findall(_add_ns(u'Representation')):
                if is_drm_protected(representation):
                    continue
                representation_attrib = adaptation_set.attrib.copy()
                representation_attrib.update(representation.attrib)
                mime_type = representation_attrib[u'mimeType']
                content_type = mime_type.split(u'/')[0]
                if (content_type == u'text'):
                    pass
                elif (content_type in (u'video', u'audio')):
                    base_url = u''
                    for element in (representation, adaptation_set, period, mpd_doc):
                        base_url_e = element.find(_add_ns(u'BaseURL'))
                        if (base_url_e is not None):
                            base_url = (base_url_e.text + base_url)
                            if re.match(u'^https?://', base_url):
                                break
                    if (mpd_base_url and (not re.match(u'^https?://', base_url))):
                        if ((not mpd_base_url.endswith(u'/')) and (not base_url.startswith(u'/'))):
                            mpd_base_url += u'/'
                        base_url = (mpd_base_url + base_url)
                    representation_id = representation_attrib.get(u'id')
                    lang = representation_attrib.get(u'lang')
                    url_el = representation.find(_add_ns(u'BaseURL'))
                    filesize = int_or_none((url_el.attrib.get(u'{http://youtube.com/yt/2012/10/10}contentLength') if (url_el is not None) else None))
                    bandwidth = int_or_none(representation_attrib.get(u'bandwidth'))
                    f = {u'format_id': ((u'%s-%s' % (mpd_id, representation_id)) if mpd_id else representation_id), u'url': base_url, u'manifest_url': mpd_url, u'ext': mimetype2ext(mime_type), u'width': int_or_none(representation_attrib.get(u'width')), u'height': int_or_none(representation_attrib.get(u'height')), u'tbr': float_or_none(bandwidth, 1000), u'asr': int_or_none(representation_attrib.get(u'audioSamplingRate')), u'fps': int_or_none(representation_attrib.get(u'frameRate')), u'language': (lang if (lang not in (u'mul', u'und', u'zxx', u'mis')) else None), u'format_note': (u'DASH    %s' % content_type), u'filesize': filesize}
                    f.update(parse_codecs(representation_attrib.get(u'codecs')))
                    representation_ms_info = extract_multisegment_info(representation, adaption_set_ms_info)
                    def prepare_template(template_name, identifiers):
                        t = representation_ms_info[template_name]
                        t = t.replace(u'$RepresentationID$', representation_id)
                        t = re.sub((u'\\$(%s)\\$' % u'|'.join(identifiers)), u'%(\\1)d', t)
                        t = re.sub((u'\\$(%s)%%([^$]+)\\$' % u'|'.join(identifiers)), u'%(\\1)\\2', t)
                        t.replace(u'$$', u'$')
                        return t
                    if (u'initialization' in representation_ms_info):
                        initialization_template = prepare_template(u'initialization', (u'Bandwidth',))
                        representation_ms_info[u'initialization_url'] = (initialization_template % {u'Bandwidth': bandwidth})
                    def location_key(location):
                        return (u'url' if re.match(u'^https?://', location) else u'path')
                    if ((u'segment_urls' not in representation_ms_info) and (u'media' in representation_ms_info)):
                        media_template = prepare_template(u'media', (u'Number', u'Bandwidth', u'Time'))
                        media_location_key = location_key(media_template)
                        if ((u'%(Number' in media_template) and (u's' not in representation_ms_info)):
                            segment_duration = None
                            if ((u'total_number' not in representation_ms_info) and u'segment_duration'):
                                segment_duration = float_or_none(representation_ms_info[u'segment_duration'], representation_ms_info[u'timescale'])
                                representation_ms_info[u'total_number'] = int(math.ceil((float(period_duration) / segment_duration)))
                            representation_ms_info[u'fragments'] = [{media_location_key: (media_template % {u'Number': segment_number, u'Bandwidth': bandwidth}), u'duration': segment_duration} for segment_number in range(representation_ms_info[u'start_number'], (representation_ms_info[u'total_number'] + representation_ms_info[u'start_number']))]
                        else:
                            representation_ms_info[u'fragments'] = []
                            segment_time = 0
                            segment_d = None
                            segment_number = representation_ms_info[u'start_number']
                            def add_segment_url():
                                segment_url = (media_template % {u'Time': segment_time, u'Bandwidth': bandwidth, u'Number': segment_number})
                                representation_ms_info[u'fragments'].append({media_location_key: segment_url, u'duration': float_or_none(segment_d, representation_ms_info[u'timescale'])})
                            for (num, s) in enumerate(representation_ms_info[u's']):
                                segment_time = (s.get(u't') or segment_time)
                                segment_d = s[u'd']
                                add_segment_url()
                                segment_number += 1
                                for r in range(s.get(u'r', 0)):
                                    segment_time += segment_d
                                    add_segment_url()
                                    segment_number += 1
                                segment_time += segment_d
                    elif ((u'segment_urls' in representation_ms_info) and (u's' in representation_ms_info)):
                        fragments = []
                        segment_index = 0
                        timescale = representation_ms_info[u'timescale']
                        for s in representation_ms_info[u's']:
                            duration = float_or_none(s[u'd'], timescale)
                            for r in range((s.get(u'r', 0) + 1)):
                                segment_uri = representation_ms_info[u'segment_urls'][segment_index]
                                fragments.append({location_key(segment_uri): segment_uri, u'duration': duration})
                                segment_index += 1
                        representation_ms_info[u'fragments'] = fragments
                    if (u'fragments' in representation_ms_info):
                        f.update({u'fragment_base_url': base_url, u'fragments': [], u'protocol': u'http_dash_segments'})
                        if (u'initialization_url' in representation_ms_info):
                            initialization_url = representation_ms_info[u'initialization_url']
                            if (not f.get(u'url')):
                                f[u'url'] = initialization_url
                            f[u'fragments'].append({location_key(initialization_url): initialization_url})
                        f[u'fragments'].extend(representation_ms_info[u'fragments'])
                    try:
                        existing_format = next((fo for fo in formats if (fo[u'format_id'] == representation_id)))
                    except StopIteration:
                        full_info = formats_dict.get(representation_id, {}).copy()
                        full_info.update(f)
                        formats.append(full_info)
                    else:
                        existing_format.update(f)
                else:
                    self.report_warning((u'Unknown    MIME    type    %s    in    DASH    manifest' % mime_type))
    return formats
