Exemplo n.º 1
0
    def __reload_segment_playlist(self, start, stop, segment_size, duration):

        if not self.manifest_playlist.is_variant:
            return

        if duration > 0:
            decay = 0.80  # must be between 0 and 1 see: https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average

            # Calculate optimal bitrate
            elapsed = float(util.get_total_seconds_float(stop - start))
            current_segment_download_speed = float(segment_size) * 8 / elapsed

            self.log(
                "SEGMENT SIZE: %s | ELAPSED SEGMENT (%s sec) DOWNLOAD TIME: %s | BANDWIDTH: %s"
                % (segment_size, str(float(duration)), str(elapsed),
                   current_segment_download_speed))

            playlist = self.manifest_playlist.playlists[
                self.selected_bandwidth_index]

            real_measured_bandwidth = float(
                playlist.stream_info.bandwidth) * (float(duration) / elapsed)

            self.average_download_speed = self.__moving_average_bandwidth_calculator(
                self.average_download_speed, decay, real_measured_bandwidth)

            download_rate = real_measured_bandwidth / playlist.stream_info.bandwidth

            self.log("MAX CALCULATED BITRATE: %s" % real_measured_bandwidth)
            self.log("AVERAGE DOWNLOAD SPEED: %s" %
                     self.average_download_speed)
            self.log('DOWNLOAD RATE: %s' % download_rate)

            current_bandwidth_index = self.__find_bandwidth_index(
                self.manifest_playlist,
                min(self.maxbitrate, self.average_download_speed))

            current_bandwidth = playlist.stream_info.bandwidth
            playlist = self.manifest_playlist.playlists[
                current_bandwidth_index]
            selected_bandwidth = playlist.stream_info.bandwidth
            is_increasing_bandwidth = current_bandwidth < selected_bandwidth

            if current_bandwidth_index != self.selected_bandwidth_index and (
                    not is_increasing_bandwidth or download_rate > 1.3):
                self.log("CHANGING BANDWIDTH TO: %s" %
                         playlist.stream_info.bandwidth)
                self.selected_bandwidth_index = current_bandwidth_index
                self.media_list = self.__load_playlist_from_uri(
                    playlist.absolute_uri)
        else:
            self.media_list = self.__load_playlist_from_uri(
                self.manifest_playlist.playlists[
                    self.selected_bandwidth_index].absolute_uri)
    def __calculate_bitrate(self, start, stop, segment_size, duration):

        if not self.manifest_playlist.is_variant:
            return

        decay = 0.70  # must be between 0 and 1 see: https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average

        # Calculate optimal bitrate
        elapsed = float(util.get_total_seconds_float(stop - start))
        current_segment_download_speed = float(segment_size) / elapsed

        log("SEGMENT SIZE: %s" % segment_size)
        log("ELAPSED SEGMENT (%s sec) DOWNLOAD TIME: %s | BANDWIDTH: %s" %
            (str(float(duration)), str(elapsed),
             current_segment_download_speed))

        real_measured_bandwidth = float(
            self.manifest_playlist.playlists[self.selected_bandwidth_index].
            stream_info.bandwidth) * (float(duration) / elapsed)

        self.average_download_speed = self.moving_average_bandwidth_calculator(
            self.average_download_speed, decay, real_measured_bandwidth)

        log("MAX CALCULATED BITRATE: %s" % real_measured_bandwidth)
        log("AVERAGE DOWNLOAD SPEED: %s" % self.average_download_speed)

        if self.media_list.keys and len(
                self.media_list.keys) > 0 and self.media_list.keys[-1]:
            log("%s" % self.media_list.dumps())
            log("ENCRYPTED PLAYLIST, SKIPPING RELOADING...")
            return

        current_bandwidth_index = self.find_bandwidth_index(
            self.manifest_playlist,
            min(self.maxbitrate, self.average_download_speed))

        if current_bandwidth_index != self.selected_bandwidth_index:
            playlist = self.manifest_playlist.playlists[
                current_bandwidth_index]
            log("CHANGING BANDWIDTH TO: %s" % playlist.stream_info.bandwidth)
            self.selected_bandwidth_index = current_bandwidth_index
            self.media_list = self.load_playlist_from_uri(
                playlist.absolute_uri)
Exemplo n.º 3
0
def download_internal(url, queue, maxbitrate=0, stopEvent=None):
    global average_download_speed

    if stopEvent and stopEvent.isSet():
        return

    # max_buffer_size = 4 * 1024 *1024 #4MB

    decay = 0.85  #must be between 0 and 1 see: https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average

    average_download_speed = min(maxbitrate, average_download_speed)

    log("STARTING MEDIA DOWNLOAD WITH AVERAGE SPEED: %s" %
        average_download_speed)

    manifest_playlist = load_playlist_from_uri(url)

    current_bandwidth_index = find_bandwidth_index(manifest_playlist,
                                                   average_download_speed)
    old_bandwidth_index = current_bandwidth_index

    if manifest_playlist.is_variant:
        log("SELECTING VARIANT PLAYLIST: %s" % manifest_playlist.
            playlists[current_bandwidth_index].stream_info.bandwidth)
        playlist = manifest_playlist.playlists[current_bandwidth_index]
    else:
        playlist = manifest_playlist

    played_segments = []

    while not stopEvent.isSet():

        media_list = load_playlist_from_uri(playlist.absolute_uri)

        is_bitrate_change = False
        segment_key = None

        for segment_index, segment in enumerate(media_list.segments):

            if stopEvent and stopEvent.isSet():
                return

            segment_number = segment.uri.split('-')[-1:][0].split('.')[0]

            if played_segments.__contains__(segment_number):
                # log("SKIPPING SEGMENT %s" % segment_number)
                continue

            log("PLAYING SEGMENT %s | URI: %s" %
                (segment_number, segment.absolute_uri))

            try:
                start = datetime.datetime.now()
                played_segments.append(segment_number)

                if segment.key and segment_key != segment.key.uri:
                    segment_key = segment.key.uri
                    # average_download_speed = 0.0
                    # if media_list.faxs.absolute_uri
                    log("MEDIA ENCRYPTED, KEY URI: %s" %
                        segment.key.absolute_uri)
                    segment.key.key_value = ''.join(
                        download_chunks(segment.key.absolute_uri))
                    log("KEY CONTENT: %s" % repr(segment.key.key_value))

                    key = segment.key.key_value
                    iv_data = segment.key.iv or media_list.media_sequence
                    iv = get_key_iv(segment.key, iv_data)

                    decryptor = AES.new(key, AES.MODE_CBC, iv)

                segment_size = 0.0
                chunk_size = 2048 if not segment.key else int(
                    playlist.stream_info.bandwidth)
                for chunk_index, chunk in enumerate(
                        download_chunks(segment.absolute_uri,
                                        chunk_size=chunk_size)):
                    if stopEvent and stopEvent.isSet():
                        return

                    segment_size = segment_size + len(chunk)

                    if segment.key:  #decrypt chunk
                        chunk = decryptor.decrypt(chunk)

                    # log("ENQUEUING CHUNK %s FROM SEGMENT %s" % (chunk_index, segment_number))
                    queue.put(chunk)

                elapsed = float(
                    util.get_total_seconds_float(datetime.datetime.now() -
                                                 start))
                current_segment_download_speed = float(segment_size) / elapsed

                log("SEGMENT SIZE: %s" % segment_size)
                log("ELAPSED SEGMENT (%s sec) DOWNLOAD TIME: %s | BANDWIDTH: %s"
                    % (str(float(segment.duration)), str(elapsed),
                       current_segment_download_speed))

                real_measured_bandwidth = float(
                    manifest_playlist.playlists[current_bandwidth_index].
                    stream_info.bandwidth) * (float(segment.duration) /
                                              elapsed)

                average_download_speed = movingAvgBandwidthCalculator(
                    average_download_speed, decay, real_measured_bandwidth)

                log("MAX CALCULATED BITRATE: %s" % real_measured_bandwidth)
                log("AVERAGE DOWNLOAD SPEED: %s" % average_download_speed)

                if manifest_playlist.is_variant and old_bandwidth_index == current_bandwidth_index:
                    log("SELECTING NEW BITRATE. MAXBITRATE: %s" % maxbitrate)
                    current_bandwidth_index = find_bandwidth_index(
                        manifest_playlist,
                        min(maxbitrate, average_download_speed))
                    playlist = manifest_playlist.playlists[
                        current_bandwidth_index]

                    if old_bandwidth_index != current_bandwidth_index:
                        log("BANDWIDTH CHANGED TO: %s" %
                            playlist.stream_info.bandwidth)
                        old_bandwidth_index = current_bandwidth_index
                        is_bitrate_change = True
                        break

            except Exception:
                traceback.print_exc()
                log_error('ERROR PROCESSING SEGMENT %s: %s' %
                          (segment_number, Exception.message))
                pass

        if media_list.is_endlist and not is_bitrate_change:
            log("IS END LIST. BYE...")
            return
Exemplo n.º 4
0
def download_segment_media(segment_uri,
                           stream,
                           stopEvent,
                           queue,
                           maxbitrate=0):
    global average_download_speed
    global media_list
    global manifest_playlist
    global selected_bandwidth_index

    if stopEvent and stopEvent.isSet():
        return

    decay = 0.80  # must be between 0 and 1 see: https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average

    log("STARTING MEDIA DOWNLOAD WITH AVERAGE SPEED: %s" %
        average_download_speed)

    segment_size = 0.0

    segment_number = get_segment_number(segment_uri)

    log("SEGMENT NUMBER: %s" % segment_number)

    segment = filter(lambda k: get_segment_number(k.uri) == segment_number,
                     media_list.segments)[0]

    log("SEGMENT URL: %s" % segment.absolute_uri)

    start = datetime.datetime.now()
    for chunk in download_chunks(segment.absolute_uri):
        if stopEvent and stopEvent.isSet():
            return

        segment_size = segment_size + len(chunk)

        stream.write(chunk)

    stream.flush()

    elapsed = float(
        util.get_total_seconds_float(datetime.datetime.now() - start))
    current_segment_download_speed = float(segment_size) / elapsed

    log("SEGMENT SIZE: %s" % segment_size)
    log("ELAPSED SEGMENT (%s sec) DOWNLOAD TIME: %s | BANDWIDTH: %s" %
        (str(float(
            segment.duration)), str(elapsed), current_segment_download_speed))

    real_measured_bandwidth = float(
        manifest_playlist.playlists[selected_bandwidth_index].stream_info.
        bandwidth) * (float(segment.duration) / elapsed)

    average_download_speed = movingAvgBandwidthCalculator(
        average_download_speed, decay, real_measured_bandwidth)

    log("MAX CALCULATED BITRATE: %s" % real_measured_bandwidth)
    log("AVERAGE DOWNLOAD SPEED: %s" % average_download_speed)

    if manifest_playlist.is_variant:
        current_bandwidth_index = find_bandwidth_index(
            manifest_playlist, min(maxbitrate, average_download_speed))
        if current_bandwidth_index != selected_bandwidth_index:
            playlist = manifest_playlist.playlists[current_bandwidth_index]
            log("CHANGING BANDWIDTH TO: %s" % playlist.stream_info.bandwidth)
            queue.put(playlist.absolute_uri)
    def download_loop(self, url, queue, maxbitrate=0, stopEvent=None):
        if stopEvent and stopEvent.isSet():
            return

        decay = 0.80  # must be between 0 and 1 see: https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average

        segment_buffer = b''
        segment_count = 0
        is_playing = self.pre_buffer_segments <= 0

        self.average_download_speed = min(
            maxbitrate, self.average_download_speed) if is_playing else 0.0

        self.log("STARTING MEDIA DOWNLOAD WITH AVERAGE SPEED: %s" %
                 self.average_download_speed)

        manifest_playlist = self.load_playlist_from_uri(url)

        current_bandwidth_index = self.find_bandwidth_index(
            manifest_playlist,
            self.average_download_speed if is_playing else maxbitrate)
        old_bandwidth_index = current_bandwidth_index

        if manifest_playlist.is_variant:
            self.log("SELECTING VARIANT PLAYLIST: %s" % manifest_playlist.
                     playlists[current_bandwidth_index].stream_info.bandwidth)
            playlist = manifest_playlist.playlists[current_bandwidth_index]
        else:
            playlist = manifest_playlist

        starting = True

        media_segment_time = None

        while not stopEvent.isSet():

            media_list = self.load_playlist_from_uri(playlist.absolute_uri)

            is_vod = (media_list.playlist_type or '').lower() == 'vod'

            self.log("MEDIA LIST IS VOD: %s" % is_vod)

            is_playing = is_playing or is_vod

            is_bitrate_change = False
            segment_key = None

            segments = media_list.segments

            if not is_vod and starting:
                self.log("STARTING PROGRAM DATE TIME: %s" %
                         media_list.program_date_time)
                media_segment_time = media_list.program_date_time
                #starts to play on last 3 segments as described in https://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-6.3.3
                # mark previous segments as played
                for segment in media_list.segments[:-3]:
                    media_segment_time += datetime.timedelta(
                        seconds=segment.duration)

            starting = False

            current_segment_program_date = media_list.program_date_time

            if not is_vod:
                self.log("ATTEMPTING TO PLAY SEGMENT ON TIME %s" %
                         media_segment_time)

            for segment_index, segment in enumerate(
                    segments):  # segment_index starts at 0 (zero)

                if stopEvent and stopEvent.isSet():
                    return

                if segment_index > 0 and not is_vod:
                    current_segment_program_date += datetime.timedelta(
                        seconds=segments[segment_index - 1].duration)

                if not is_vod:
                    if current_segment_program_date < media_segment_time:
                        self.log("SKIPPING SEGMENT %s (%s)" %
                                 (segment.uri, current_segment_program_date))
                        continue
                    else:
                        media_segment_time += datetime.timedelta(
                            seconds=segment.duration)

                    media_segment_time = current_segment_program_date

                self.log("PLAYING SEGMENT %s (%s)" %
                         (segment.absolute_uri, current_segment_program_date))

                try:
                    start = datetime.datetime.now()

                    if segment.key and segment_key != segment.key.uri:
                        segment_key = segment.key.uri
                        # average_download_speed = 0.0
                        # if media_list.faxs.absolute_uri
                        self.log("MEDIA ENCRYPTED, KEY URI: %s" %
                                 segment.key.absolute_uri)
                        segment.key.key_value = ''.join(
                            self.download_chunks(segment.key.absolute_uri))
                        self.log("KEY CONTENT: %s" %
                                 repr(segment.key.key_value))

                        key = segment.key.key_value
                        iv_data = segment.key.iv or media_list.media_sequence
                        iv = self.get_key_iv(segment.key, iv_data)

                        decryptor = AES.new(key, AES.MODE_CBC, iv)

                    segment_size = 0.0
                    chunk_size = int(playlist.stream_info.bandwidth)
                    queue_time = 0.0
                    for chunk_index, chunk in enumerate(
                            self.download_chunks(segment.absolute_uri,
                                                 chunk_size=chunk_size)):
                        if stopEvent and stopEvent.isSet():
                            return

                        segment_size = segment_size + len(chunk)

                        if segment.key:  # decrypt chunk
                            chunk = decryptor.decrypt(chunk)

                        queue_start = datetime.datetime.now()
                        if is_playing:
                            queue.put(chunk)
                        else:
                            segment_buffer += chunk
                        queue_time_end = datetime.datetime.now()
                        queue_time += float(
                            util.get_total_seconds_float(queue_time_end -
                                                         queue_start))

                    end_download = datetime.datetime.now()
                    segment_count += 1
                    if not is_playing and segment_count == self.pre_buffer_segments:
                        is_playing = True
                        queue.put(segment_buffer)

                    elapsed = float(
                        util.get_total_seconds_float(end_download - start) -
                        queue_time)
                    current_segment_download_speed = float(
                        segment_size) / elapsed

                    self.log("SEGMENT SIZE: %s" % segment_size)
                    self.log(
                        "ELAPSED SEGMENT (%s sec) DOWNLOAD TIME: %s | BANDWIDTH: %s"
                        % (str(float(segment.duration)), str(elapsed),
                           current_segment_download_speed))

                    real_measured_bandwidth = float(
                        manifest_playlist.playlists[current_bandwidth_index].
                        stream_info.bandwidth) * (float(segment.duration) /
                                                  elapsed)

                    self.average_download_speed = self.moving_average_bandwidth_calculator(
                        self.average_download_speed, decay,
                        real_measured_bandwidth)

                    download_rate = real_measured_bandwidth / playlist.stream_info.bandwidth

                    self.log("MAX CALCULATED BITRATE: %.4f" %
                             real_measured_bandwidth)
                    self.log("AVERAGE DOWNLOAD SPEED: %.4f" %
                             self.average_download_speed)

                    self.log('DOWNLOAD RATE: %s' % download_rate)
                    self.log('CURRENT QUEUE SIZE: %s' % queue.qsize())

                    done_playing = (media_list.is_endlist or is_vod
                                    ) and len(segments) == segment_index + 1

                    if manifest_playlist.is_variant and old_bandwidth_index == current_bandwidth_index and is_playing and not done_playing:
                        current_bandwidth = playlist.stream_info.bandwidth
                        self.log("CURRENT BANDWIDTH: %s" % current_bandwidth)
                        self.log("SELECTING NEW BITRATE. MAXBITRATE: %s" %
                                 maxbitrate)

                        if download_rate < 1 and queue.qsize() == 0:
                            self.average_download_speed = min(
                                self.average_download_speed,
                                real_measured_bandwidth) * float(
                                    download_rate) / 1.3
                            self.log(
                                "CHANGING AVERAGE DOWNLOAD SPEED TO (DUE TO LOW BUFFER): %s"
                                % self.average_download_speed)

                        current_bandwidth_index = self.find_bandwidth_index(
                            manifest_playlist,
                            min(maxbitrate, self.average_download_speed))
                        new_playlist = manifest_playlist.playlists[
                            current_bandwidth_index]
                        selected_bandwidth = new_playlist.stream_info.bandwidth

                        is_increasing_bandwidth = current_bandwidth < selected_bandwidth

                        if old_bandwidth_index != current_bandwidth_index and (
                                not is_increasing_bandwidth
                                or download_rate > 1.3):
                            self.log("BANDWIDTH CHANGED TO: %s" %
                                     selected_bandwidth)
                            old_bandwidth_index = current_bandwidth_index
                            is_bitrate_change = True
                            playlist = new_playlist
                            break

                except Exception as ex:
                    self.log_error('ERROR PROCESSING SEGMENT %s: %s' %
                                   (segment.absolute_uri, repr(ex)))
                    traceback.print_exc()

            if (media_list.is_endlist or is_vod) and not is_bitrate_change:
                self.log("IS END LIST. BYE...")
                return