Sergei Nikolaev 2 weeks ago committed by GitHub
commit 5518f43e4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1205,6 +1205,20 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'height': 1080,
}],
{},
), (
# https://github.com/yt-dlp/yt-dlp/pull/8711
'urls_with_ranges',
'http://unknown/manifest.mpd', # mpd_url
None, # mpd_base_url
[{
'fragments': [
{'byte_range': {'start': 0, 'end': 200000}},
{'byte_range': {'start': 200001, 'end': 300000}},
{'byte_range': {'start': 300000, 'end': 400000}},
{'byte_range': None},
]
}],
{},
), (
# https://github.com/ytdl-org/youtube-dl/issues/20346
# Media considered unfragmented even though it contains

@ -0,0 +1,18 @@
<?xml version="1.0" ?>
<MPD maxSegmentDuration="PT0H0M10.000S" mediaPresentationDuration="PT0H4M1.728S" minBufferTime="PT1.500S" profiles="urn:mpeg:dash:profile:isoff-main:2011" type="static" xmlns="urn:mpeg:dash:schema:mpd:2011">
<Period duration="PT0H4M1.728S">
<AdaptationSet bitstreamSwitching="true" lang="und" maxHeight="1080" maxWidth="1920" par="16:9" segmentAlignment="true">
<ContentComponent contentType="video" id="1"/>
<Representation audioSamplingRate="44100" bandwidth="200000" codecs="avc3.42c01e,mp4a.40.2" frameRate="25" height="144" id="h264_aac_144p_m4s" mimeType="video/mp4" sar="1:1" startWithSAP="1" width="256">
<SegmentList duration="10000" timescale="1000">
<Initialization sourceURL="../vd_5999c902ea707c67d8e267a9_1503250723/h264_aac_144p_m4s/0/432f65a0.m4s" range="0-999"/>
<SegmentURL media="../vd_5999c902ea707c67d8e267a9_1503250723/h264_aac_144p_m4s/0/432f65a0.m4s" mediaRange="1000-99999"/>
<SegmentURL media="../vd_5999c902ea707c67d8e267a9_1503250723/h264_aac_144p_m4s/0/432f65a0.m4s" mediaRange="100000-199999"/>
<SegmentURL media="../vd_5999c902ea707c67d8e267a9_1503250723/h264_aac_144p_m4s/0/432f65a0.m4s" mediaRange="200001-299999"/>
<SegmentURL media="../vd_5999c902ea707c67d8e267a9_1503250723/h264_aac_144p_m4s/1/432f65a0.m4s" mediaRange="300000-399999"/>
<SegmentURL media="../vd_5999c902ea707c67d8e267a9_1503250723/h264_aac_144p_m4s/2/432f65a0.m4s"/>
</SegmentList>
</Representation>
</AdaptationSet>
</Period>
</MPD>

@ -87,4 +87,5 @@ class DashSegmentsFD(FragmentFD):
'fragment_count': fragment.get('fragment_count'),
'index': i,
'url': fragment_url,
'byte_range': fragment.get('byte_range'),
}

@ -2710,10 +2710,20 @@ class InfoExtractor:
if segment_duration:
ms_info['segment_duration'] = float(segment_duration)
def parse_range(byte_range):
if isinstance(byte_range, str):
split_byte_range = byte_range.split('-')
if len(split_byte_range) == 2:
return {
'start': int(split_byte_range[0]),
'end': int(split_byte_range[1]) + 1,
}
def extract_Initialization(source):
initialization = source.find(_add_ns('Initialization'))
if initialization is not None:
ms_info['initialization_url'] = initialization.attrib['sourceURL']
ms_info['initialization_byte_range'] = parse_range(initialization.attrib.get('range'))
segment_list = element.find(_add_ns('SegmentList'))
if segment_list is not None:
@ -2721,7 +2731,10 @@ class InfoExtractor:
extract_Initialization(segment_list)
segment_urls_e = segment_list.findall(_add_ns('SegmentURL'))
if segment_urls_e:
ms_info['segment_urls'] = [segment.attrib['media'] for segment in segment_urls_e]
ms_info['segments'] = [{
'url': segment.attrib['media'],
'byte_range': parse_range(segment.attrib.get('mediaRange')),
} for segment in segment_urls_e]
else:
segment_template = element.find(_add_ns('SegmentTemplate'))
if segment_template is not None:
@ -2880,7 +2893,7 @@ class InfoExtractor:
def location_key(location):
return 'url' if re.match(r'^https?://', location) else 'path'
if 'segment_urls' not in representation_ms_info and 'media' in representation_ms_info:
if 'segments' not in representation_ms_info and 'media' in representation_ms_info:
media_template = prepare_template('media', ('Number', 'Bandwidth', 'Time'))
media_location_key = location_key(media_template)
@ -2932,38 +2945,63 @@ class InfoExtractor:
add_segment_url()
segment_number += 1
segment_time += segment_d
elif 'segment_urls' in representation_ms_info and 's' in representation_ms_info:
elif 'segments' in representation_ms_info and 's' in representation_ms_info:
# No media template,
# e.g. https://www.youtube.com/watch?v=iXZV5uAYMJI
# or any YouTube dashsegments video
fragments = []
fragment = None
segment_index = 0
timescale = representation_ms_info['timescale']
for s in representation_ms_info['s']:
duration = float_or_none(s['d'], timescale)
for r in range(s.get('r', 0) + 1):
segment_uri = representation_ms_info['segment_urls'][segment_index]
fragments.append({
location_key(segment_uri): segment_uri,
'duration': duration,
})
segment = representation_ms_info['segments'][segment_index]
segment_url = segment['url']
fragment_location_key = location_key(segment_url)
if (fragment is not None and fragment.get(fragment_location_key) == segment_url
and fragment['byte_range'] is not None and segment['byte_range'] is not None
and fragment['byte_range']['end'] == segment['byte_range']['start']
and ((fragment['duration'] is not None and duration is not None)
or (fragment['duration'] is None and duration is None))):
fragment['byte_range']['end'] = segment['byte_range']['end']
if duration:
fragment['duration'] += duration
else:
fragment = {
fragment_location_key: segment_url,
'byte_range': segment['byte_range'],
'duration': duration,
}
fragments.append(fragment)
segment_index += 1
representation_ms_info['fragments'] = fragments
elif 'segment_urls' in representation_ms_info:
elif 'segments' in representation_ms_info:
# Segment URLs with no SegmentTimeline
# E.g. https://www.seznam.cz/zpravy/clanek/cesko-zasahne-vitr-o-sile-vichrice-muze-byt-i-zivotu-nebezpecny-39091
# https://github.com/ytdl-org/youtube-dl/pull/14844
fragments = []
fragment = None
segment_duration = float_or_none(
representation_ms_info['segment_duration'],
representation_ms_info['timescale']) if 'segment_duration' in representation_ms_info else None
for segment_url in representation_ms_info['segment_urls']:
fragment = {
location_key(segment_url): segment_url,
}
if segment_duration:
fragment['duration'] = segment_duration
fragments.append(fragment)
for segment in representation_ms_info['segments']:
segment_url = segment['url']
fragment_location_key = location_key(segment_url)
if (fragment is not None and fragment.get(fragment_location_key) == segment_url
and fragment['byte_range'] is not None and segment['byte_range'] is not None
and fragment['byte_range']['end'] == segment['byte_range']['start']):
fragment['byte_range']['end'] = segment['byte_range']['end']
if segment_duration:
fragment['duration'] += segment_duration
else:
fragment = {
fragment_location_key: segment_url,
'byte_range': segment['byte_range'],
}
if segment_duration:
fragment['duration'] = segment_duration
fragments.append(fragment)
representation_ms_info['fragments'] = fragments
# If there is a fragments key available then we correctly recognized fragmented media.
# Otherwise we will assume unfragmented media with direct access. Technically, such
@ -2981,7 +3019,19 @@ class InfoExtractor:
initialization_url = representation_ms_info['initialization_url']
if not f.get('url'):
f['url'] = initialization_url
f['fragments'].append({location_key(initialization_url): initialization_url})
initialization_byte_range = representation_ms_info.get('initialization_byte_range')
fragments = representation_ms_info['fragments']
fragment = fragments[0] if len(fragments) > 0 else None
fragment_location_key = location_key(initialization_url)
if (fragment is not None and initialization_url == fragment.get(fragment_location_key)
and initialization_byte_range is not None and fragment['byte_range'] is not None
and initialization_byte_range['end'] == fragment['byte_range']['start']):
fragment['byte_range']['start'] = initialization_byte_range['start']
else:
f['fragments'].append({
fragment_location_key: initialization_url,
'byte_range': initialization_byte_range,
})
f['fragments'].extend(representation_ms_info['fragments'])
if not period_duration:
period_duration = try_get(

Loading…
Cancel
Save