Ejemplo n.º 1
0
    def test_dash_manifest_generator_should_combine_multiple_manifest_and(self, mock_open):
        manifest_generator = DashManifestGenerator(self.output.job)

        with open("tests/jobs/data/output.mpd", "r") as fp:
            expected_mpd = MPEGDASHParser().parse(fp.read())
            actual_mpd = MPEGDASHParser().parse(manifest_generator.merge())
            self.assertEqual(
                MPEGDASHParser.get_as_doc(expected_mpd).toxml(), MPEGDASHParser.get_as_doc(actual_mpd).toxml()
            )
Ejemplo n.º 2
0
 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'))
Ejemplo n.º 3
0
    def test_mpd2xml_with_marlin(self):
        mpd = MPEGDASHParser.parse('./tests/mpd-samples/marlin.mpd')
        print(MPEGDASHParser.to_xmlstring(mpd))

        all_marlin_kid = []
        for period in mpd.periods:
            for adapt_set in period.adaptation_sets:
                for content_protection in adapt_set.content_protections:
                    if content_protection.marlin_content_ids != None:
                        for marlin_content_ids in content_protection.marlin_content_ids:
                            for marlin_content_id in marlin_content_ids.marlin_content_id:
                                all_marlin_kid.append(marlin_content_id.value)

        self.assertTrue(len(all_marlin_kid) == 2)
Ejemplo n.º 4
0
 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)
Ejemplo n.º 5
0
def manifest_parser(mpd_url):
    manifest = requests.get(mpd_url).text
    with open("manifest.mpd", 'w') as manifest_handler:
        manifest_handler.write(manifest)
    mpd = MPEGDASHParser.parse("./manifest.mpd")
    audio = []
    video = []
    for period in mpd.periods:
        for adapt_set in period.adaptation_sets:
            content_type = adapt_set.content_type
            for repr in adapt_set.representations:
                base_url = repr.base_urls[0].base_url_value
                if (content_type == "audio"):
                    audio.append(base_url)
                elif (content_type == "video" and repr.height == quality):
                    video.append(base_url)
            for prot in adapt_set.content_protections:
                if (prot.value == "cenc"):
                    kId = prot.key_id.replace('-', '')
                    if (content_type == "audio"):
                        audio.append(kId)
                    elif (content_type == "video" and repr.height == quality):
                        video.append(kId)
                    break
    return video + audio
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    def test_xml2mpd_parse_vector_type_attributes(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">
                <SubRepresentation bandwidth="117600" codecs="mp4a.40.5" contentComponent="102 104"></SubRepresentation>
                <BaseURL>motion-20120802-89.mp4</BaseURL>
                <SegmentBase indexRange="674-981">
                  <Initialization range="0-673" />
                </SegmentBase>
              </Representation>
            </AdaptationSet>
          </Period>
        </MPD>
        '''
        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')
Ejemplo n.º 8
0
def process_mpd(url):
    global gSegments
    base_url = url.rstrip('manifest.mpd')
    pp = pprint.PrettyPrinter(indent=3)
    mpd = MPEGDASHParser.parse(url)
    Periods = mpd.periods
    for period in Periods:
        ad_sets = period.adaptation_sets
        for ad_set in ad_sets:
            mime_strs = ad_set.mime_type.split('/')
            mtype = mime_strs[0]
            if mtype == 'video':
                ext = 'm4v'
            elif mtype == 'audio':
                ext = 'm4a'
            elif mtype == 'text':
                ext = 'vtt'

            reps = ad_set.representations
            seg_templates = ad_set.segment_templates
            repr_ids = []
            for r in reps:
                repr_ids.append(r.id)
            for rid in repr_ids:
                for st in seg_templates:
                    list = gen_playlist(st, r.id, ext, base_url)
                    if mtype == 'video':
                        gSegments['video'].extend(list)
                    elif mtype == 'audio':
                        gSegments['audio'].extend(list)
                    elif mtype == 'text':
                        gSegments['text'].extend(list)

                    print("Type: {0}".format(mtype))
                    pp.pprint(list)
Ejemplo n.º 9
0
    def on_get(self, req, resp, mpd_id):
        """
        GET /mpds/{mpd_id}
        """
        mode = ''
        for key, value in req.params.items():
            if key == 'mode':
                mode = value

        base_url = BaseURL()
        if mode == 'proxy':
            base_url.base_url_value = "/proxy{}".format(
                MPDS['mpds'][str(mpd_id)]['base_url'])
        elif mode == 'simulation':
            base_url.base_url_value = "/simulation{}".format(
                MPDS['mpds'][str(mpd_id)]['base_url'])
        elif mode == 'validation':
            base_url.base_url_value = "/validation{}".format(
                MPDS['mpds'][str(mpd_id)]['base_url'])
        else:
            LOGGER.error('No mode provided as query string.')
            resp.status = falcon.HTTP_400
            resp.body = json.dumps({
                'message':
                'Please provide a mode in the request '
                'as query string: mode=proxy|simulation|validation.'
            })
            return

        mpd_response = requests.get(MPDS['mpds'][str(mpd_id)]['url'])
        resp.content_type = 'application/dash+xml'
        mpd = MPEGDASHParser.parse(mpd_response.text)
        mpd.base_urls = []

        # Add the custome base urls
        mpd.base_urls.append(base_url)

        # Add TAC signalling
        if mode != 'proxy':
            tac = DescriptorWithExtUrlQuery()
            tac.scheme_id_uri = 'urn:mpeg:dash:urlparam:2016:querystring'
            url_query_info = ExtUrlQueryInfo()
            url_query_info.include_in_requests = 'mpd segment'
            url_query_info.query_string = 'token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEQVNILUlGIENvbmZvcm1hbmNlIiwiY2RuaXN0dCI6Mn0.QjVVZGUXOsFPiHCTax_I14su5rppK-yWPQXrkcI1gQI'
            url_query_info.query_template = 'dash-if-ietf-token=$query:token$'
            tac.ext_url_query_info = url_query_info
            for period in mpd.periods:
                for adaptation_set in period.adaptation_sets:
                    if not adaptation_set.essential_properties:
                        adaptation_set.essential_properties = []
                    adaptation_set.essential_properties.append(tac)

        # Serialize MPD to XML
        xml_doc = minidom.Document()
        write_child_node(xml_doc, 'MPD', mpd)
        resp.body = xml_doc.toprettyxml(indent='    ', newl='\n')
Ejemplo n.º 10
0
 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 dash_parse(self, reschedule=True):
     """
     Parse Manifest file to MPEGDASHParser
     """
     logger.info("Obtained MPD body ")
     if self.mpd_body is not None:
         self.mpd_object = MPEGDASHParser.parse(self.mpd_body)
         print(f"self.mpd_object: {self.mpd_object}")
     else:
         # self.interrupt()
         pass
Ejemplo n.º 12
0
    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))
Ejemplo n.º 13
0
 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)
Ejemplo n.º 14
0
    def download_and_save(self, output_dir=streambot._OUTPUT_DIR):
        '''
        download and save playlist
        also parse media playlists
        '''
        self.local = streambot.download_and_save_to(self.uri, output_dir, True)
        logger.debug(
            'stream playlist is saved as: {local}'.format(local=self.local))

        with open(self.local, 'r') as f:
            content = f.read()
            self.mpd = MPEGDASHParser.parse(content)
Ejemplo n.º 15
0
def main():
    pp = pprint.PrettyPrinter(indent=3)
    mpd_url = sys.argv[1]
    mpd = MPEGDASHParser.parse(mpd_url)
    #for name, data in inspect.getmembers(MPEGDASHParser):
    #	if name == '__builtins__':
    #		continue
    #	print '%s :' % name, repr(data)

    print "MPD:"
    pp.pprint(mpd.__dict__)
    pObj = mpd.periods
    pp.pprint(pObj[0].__dict__)
    asets = pObj[0].adaptation_sets

    print("\n\n{0} Adaptation Sets :\n").format(len(asets))

    #pp.pprint( asets[0].__dict__)
    #pp.pprint(asets[0].representations[0].__dict__)

    for aset in asets:
        print "\nAdaptation Set:"
        pp.pprint(aset.__dict__)
        reps = aset.representations
        sts = aset.segment_templates
        cps = aset.content_protections
        ies = aset.inband_event_streams
        if ies:
            print "\nInband event:"
            for ie in ies:
                print("	scheme_id_uri:{0} value: {1} id: {2}".format(
                    ie.scheme_id_uri, ie.value, ie.id))
        if cps:
            print "\nContent protection Info:"
            for cp in cps:
                print(" 	uri:{0} value:{1} id:{2}".format(
                    cp.scheme_id_uri, cp.value, cp.id))
        for r in reps:
            print "\nBitrate Representation"
            pp.pprint(r.__dict__)
        for st in sts:
            print "\nSegment Template"
            pp.pprint(st.__dict__)
            stls = st.segment_timelines
            for stl in stls:
                print "\ntimeline"
                for tl in stl.Ss:
                    print("t ={0}, d = {1}  r = {2}".format(tl.t, tl.d, tl.r))
Ejemplo n.º 16
0
def check_valid_mpd(file="", exp_reps=1):
    """
    checks if given file is a valid MPD(MPEG-DASH Manifest file)
    """
    if not file or not os.path.isfile(file):
        return False
    try:
        mpd = MPEGDASHParser.parse(file)
        all_reprs = []
        for period in mpd.periods:
            for adapt_set in period.adaptation_sets:
                for rep in adapt_set.representations:
                    all_reprs.append(rep)
    except Exception as e:
        logger.error(str(e))
        return False
    return True if (len(all_reprs) >= exp_reps) else False
Ejemplo n.º 17
0
 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))
Ejemplo n.º 18
0
    def get_tracks(self, paths):
        video_representations = []
        audio_representations = []
        for i, path in enumerate(paths):
            manifest_path = self.job.output_url + path + self.OUTPUT_FILE_NAME
            mpd = MPEGDASHParser.parse(self.read_file(manifest_path))
            modified_representations = self.modify_video_representations(
                mpd, path)
            modified_audio_representations = self.modify_audio_representations(
                mpd, path)
            video_representations.extend(modified_representations)
            audio_representations.extend(modified_audio_representations)

        for i, representation in enumerate(audio_representations):
            representation.id = i
        for i, representation in enumerate(video_representations):
            representation.id = i
        return {"audio": audio_representations, "video": video_representations}
Ejemplo n.º 19
0
def get_best_representation(mpd_data):
    best_video = None
    best_video_res = 0
    best_audio = None
    best_audio_sample = 0
    mpd = MPEGDASHParser.parse(mpd_data)
    for period in mpd.periods:
        for adaptationset in period.adaptation_sets:
            for rep in adaptationset.representations:
                if rep.height == None:
                    if int(rep.audio_sampling_rate) >= best_audio_sample:
                        best_audio = rep
                        best_audio_sample = int(rep.audio_sampling_rate)
                else:
                    if int(rep.height) >= best_video_res:
                        best_video = rep
                        best_video_res = int(rep.height)
    return best_video, best_audio
Ejemplo n.º 20
0
 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.assertMPD(MPEGDASHParser.parse(mpd_string))
Ejemplo n.º 21
0
def manifest_parser(mpd_url):
    video = []
    audio = []
    manifest = requests.get(mpd_url).text
    with open("manifest.mpd", 'w') as manifest_handler:
        manifest_handler.write(manifest)
    mpd = MPEGDASHParser.parse("./manifest.mpd")
    running_time = durationtoseconds(mpd.media_presentation_duration)
    for period in mpd.periods:
        for adapt_set in period.adaptation_sets:
            print(adapt_set.mime_type)
            content_type = adapt_set.mime_type
            repr = adapt_set.representations[-1]  # Max Quality
            for segment in repr.segment_templates:
                if (segment.duration):
                    print("Media segments are of equal timeframe")
                    segment_time = segment.duration / segment.timescale
                    total_segments = running_time / segment_time
                else:
                    print("Media segments are of inequal timeframe")
                    print(segment.media)
                    approx_no_segments = int(
                        running_time // 10)  # aproximate of 10 sec per segment
                    print("Expected No of segments:", approx_no_segments)
                    if (content_type == "audio/mp4"):
                        segment_extension = segment.media.split(".")[-1]
                        audio.append(approx_no_segments)
                        audio.append(segment.media)
                        audio.append(segment_extension)
                    elif (content_type == "video/mp4"):
                        segment_extension = segment.media.split(".")[-1]
                        video.append(approx_no_segments)
                        video.append(segment.media)
                        video.append(segment_extension)
            for prot in repr.content_protections:
                if (prot.value == "cenc"):
                    kId = prot.key_id.replace('-', '')
                    if (content_type == "audio/mp4"):
                        audio.append(kId)
                    elif (content_type == "video/mp4"):
                        video.append(kId)
    return video + audio
Ejemplo n.º 22
0
 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')
Ejemplo n.º 23
0
 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))
Ejemplo n.º 24
0
 def dash_parse(self):
     """
     Parse Manifest file to MPEGDASHParser
     """
     self.mpd_object = MPEGDASHParser.parse(self.mpd_body)
 def dash_parse(self):
     """
     Parse Manifest file to MPEGDASHParser
     """
     logger.info("Obtained MPD body ")
     self.mpd_object = MPEGDASHParser.parse(self.mpd_body)
Ejemplo n.º 26
0
 def test_xml2mpd_from_file(self):
     self.assertMPD(MPEGDASHParser.parse('./tests/mpd-samples/sample-001.mpd'))
     self.assertMPD(MPEGDASHParser.parse('./tests/mpd-samples/motion-20120802-manifest.mpd'))
     self.assertMPD(MPEGDASHParser.parse('./tests/mpd-samples/oops-20120802-manifest.mpd'))
     self.assertMPD(MPEGDASHParser.parse('./tests/mpd-samples/360p_speciment_dash.mpd'))
Ejemplo n.º 27
0
def manifest_parser(mpd_url):
    video = []
    audio = []
    manifest = requests.get(mpd_url).text
    with open("manifest.mpd", 'w') as manifest_handler:
        manifest_handler.write(manifest)
    mpd = MPEGDASHParser.parse("./manifest.mpd")
    running_time = durationtoseconds(mpd.media_presentation_duration)
    for period in mpd.periods:
        for adapt_set in period.adaptation_sets:
            print("Processing " + adapt_set.mime_type)
            content_type = adapt_set.mime_type
            if quality and content_type == "video/mp4":
                print(adapt_set.representations[0].height, quality)
                repr = next((x for x in adapt_set.representations
                             if x.height == quality), None)
                if not repr:
                    qualities = []
                    for rep in adapt_set.representations:
                        qualities.append(rep.height)
                    print(quality, qualities)
                    if quality < qualities[0]:
                        # they want a lower quality than whats available
                        repr = adapt_set.representations[0]  # Lowest Quality
                    elif quality > qualities[-1]:
                        # they want a higher quality than whats available
                        repr = adapt_set.representations[-1]  # Max Quality
                    print(
                        "> Could not find video with requested quality, falling back to closest!"
                    )
                    print("> Using quality of %s" % repr.height)
                else:
                    print("> Found MPD representation with quality %s" %
                          repr.height)
            else:
                repr = adapt_set.representations[-1]  # Max Quality
                print("> Using max quality of %s" % repr.height)
            for segment in repr.segment_templates:
                if (segment.duration):
                    print("Media segments are of equal timeframe")
                    segment_time = segment.duration / segment.timescale
                    total_segments = running_time / segment_time
                else:
                    print("Media segments are of inequal timeframe")

                    approx_no_segments = round(
                        running_time /
                        6) + 10  # aproximate of 6 sec per segment
                    print("Expected No of segments:", approx_no_segments)
                    if (content_type == "audio/mp4"):
                        segment_extension = segment.media.split(".")[-1]
                        audio.append(approx_no_segments)
                        audio.append(segment.media)
                        audio.append(segment.initialization)
                        audio.append(segment_extension)
                    elif (content_type == "video/mp4"):
                        segment_extension = segment.media.split(".")[-1]
                        video.append(approx_no_segments)
                        video.append(segment.media)
                        video.append(segment.initialization)
                        video.append(segment_extension)
    return video + audio
Ejemplo n.º 28
0
from mpegdash.parser import MPEGDASHParser

mpd_url = 'http://dash.akamaized.net/dash264/TestCases/1a/netflix/exMPD_BIP_TC1.mpd'
mpd = MPEGDASHParser.parse(mpd_url)
print('==== MPD ====')
print(mpd.__dict__)
print(mpd.base_urls[0].__dict__)
for p in mpd.periods:
    print('==== Period ====')
    print(p.__dict__)
    for s in p.adaptation_sets:
        print('==== adaptation set ====')
        print(s.__dict__)
        for r in s.representations:
            print('==== Representation ====')
            print(r.__dict__)
            for b in r.base_urls:
                print(b.__dict__)
Ejemplo n.º 29
0
 def merge(self):
     manifest_paths = self.get_relative_manifest_paths()
     initial_manifest = self.clone_manifest(manifest_paths[0])
     tracks_dict = self.get_tracks(manifest_paths)
     self.add_tracks_to_manifest(tracks_dict, initial_manifest)
     return MPEGDASHParser.get_as_doc(initial_manifest).toprettyxml()
Ejemplo n.º 30
0
 def test_xml2mpd_from_url(self):
     mpd_url = 'http://yt-dash-mse-test.commondatastorage.googleapis.com/media/motion-20120802-manifest.mpd'
     self.assertMPD(MPEGDASHParser.parse(mpd_url))
Ejemplo n.º 31
0
 def clone_manifest(self, manifest_path):
     initial_manifest_path = self.job.output_url + manifest_path + self.OUTPUT_FILE_NAME
     return MPEGDASHParser.parse(self.read_file(initial_manifest_path))
Ejemplo n.º 32
0
async def get_streams_from_program_data(
    program_data: ProgramData, session: ClientSession
) -> Tuple[List[VideoStream], List[AudioStream], List[SubtitleStream]]:
    async def fetch(url: str) -> str:
        async with session.get(url) as response:
            return await response.text()

    manifest_list = await asyncio_gather(*[
        fetch(url=video_reference['url'])
        for video_reference in program_data['videoReferences']
    ])

    streams = []

    for manifest, video_reference in zip(manifest_list,
                                         program_data['videoReferences']):
        parsed_url: ParseResult = urlparse(url=video_reference['url'])
        base_url: str = parsed_url._replace(path=str(
            PurePath(parsed_url.path).parent),
                                            query=None).geturl()

        if video_reference['format'] in {'hls'}:
            m3u8_object = m3u8_loads(content=manifest)

            for media in m3u8_object.media:
                streams.append(
                    HLSStream.from_media(media=media, base_url=base_url))

            for playlist in m3u8_object.playlists:
                streams.append(
                    HLSVideoStream(m3u8_playlist_uri=playlist.uri,
                                   base_url=base_url,
                                   resolution=playlist.stream_info.resolution))

        elif video_reference['format'] in {'dash264', 'dashhbbtv'}:
            for adaptation_set in next(
                    iter(MPEGDASHParser.parse(
                        string_or_url=manifest).periods)).adaptation_sets:
                for representation in adaptation_set.representations:
                    streams.append(
                        DashStream.from_representation(
                            representation=representation,
                            base_url=base_url,
                            adaptation_set=adaptation_set))

        else:
            a = 3
            ...

    video_streams: List[VideoStream] = []
    audio_streams: List[AudioStream] = []
    subtitle_streams: List[SubtitleStream] = []

    while len(streams) > 0:
        stream = streams.pop()
        if isinstance(stream, VideoStream):
            video_streams.append(stream)
        elif isinstance(stream, AudioStream):
            audio_streams.append(stream)
        elif isinstance(stream, SubtitleStream):
            subtitle_streams.append(stream)
        else:
            raise ValueError('dog')

    return video_streams, audio_streams, subtitle_streams