Пример #1
0
    def checkBuffering(self, _arg):
	#exactly what we are doing?!?!?!?
        '''
        Checks if the playback is going to buffering.
        Estimates the time required to complete the download of the current segment and verifies that it is less than the playout buffer lenght.

        In the case of "warning buffering", it deletes the current segment download, calculates the control action and sets the new level.
        This feature is available only with persistent connection.
        '''
        #FIXME Can't use it without persistent connection
        if self.rate_calc.rate and self.cur_index > self.inactive_cycle:
            remaining_secs = float(self.remaining_data/self.rate_calc.rate)
            debug(DEBUG+1,"%s checkBuffering: rate %s/s, remaining_data %s, remaining_secs %.3f, queued_time %.2f ", self, 
                format_bytes(self.rate_calc.rate), format_bytes(self.remaining_data), remaining_secs, self.media_engine.getQueuedTime()) 
            #Can cancel download only if the current level is greater than 0
            if self.media_engine.getQueuedTime() < remaining_secs and self.getCurrentLevel() > 0: 
                self.connection.stop()
                self.stop_segment_request = time.time() #update stop reqest when warning buffering occurs
                self.bwe = self.rate_calc.rate
                #Passing player parameters at the controller to calculate the control action
                self.updateFeedback(flag_check_buffering=True)
                #calc control action
                self.controller.setControlAction(self.controller.calcControlAction())
                # set new level
                if self.cur_index > self.inactive_cycle:
                    self.setLevel(self.controller.getControlAction())
                    debug(0,"%s WARNING BUFFERING!!! Delete and reload segment at level: %d", self, self.getCurrentLevel())
        else:
            return
Пример #2
0
    def fetchNextSegment(self,calledWithPort): 
        '''
        Schedules the download of the next segment at current level
        '''
	#print ("MY PID IS "+str(os.getpid()))
	test=calledWithPort;
        playlist = self.parser.playlists[self.getCurrentLevel()]
        debug(DEBUG+1, '%s fetchNextSegment level: %d cur_index: %d', self, self.getCurrentLevel(), self.getCurrentSegmentIndex())
        #
        if self.getCurrentSegmentIndex() < playlist['start_index']:
            self.setCurrentSegmentIndex(playlist['start_index'])
        if self.getCurrentSegmentIndex() > playlist['end_index']:
            # else live video (ONLY HLS!!)
            if playlist['is_live'] and self.parser.getPlaylistType() == 'HLS':
                debug(DEBUG, '%s fetchNextSegment cur_index %d', self, self.getCurrentSegmentIndex())
                self.parser.updateLevelSegmentsList(self.getCurrentLevel()).addCallback(self._updatePlaylistDone)
            # if video is vod
            else:
                debug(DEBUG, '%s fetchNextSegment last index', self)
            return
        cur_index=self.getCurrentSegmentIndex()
        levels = self.parser.getLevels()
        url_segment = playlist['segments'][cur_index]['url']
        byterange = playlist['segments'][cur_index]['byterange']
        if byterange != '':
            debug(DEBUG, '%s fetchNextSegment level: %d (%s/s) %d/%d : %s (byterange=%s)', self,
                self.getCurrentLevel(), 
                format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
                self.getCurrentSegmentIndex(), 
                playlist['end_index'], url_segment, byterange)
        else:
            debug(DEBUG, '%s fetchNextSegment level: %d (%s/s) %d/%d : %s', self,
                self.getCurrentLevel(), 
                format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
                self.getCurrentSegmentIndex(), 
                playlist['end_index'], url_segment)
        if self.controller.isBuffering():
            idle_duration = 0.0 #fetch segment after the last segment download is completed
	    print colored('GETTING AN IDLE DURATION OF '+str(idle_duration),'green')
        else:
            #FIXME 
	    #uncomment idle_duration again!
	    #idle_duration =0.0 
	    idle_duration = self.controller.getIdleDuration()
	    print colored('GETTING AN IDLE DURATION OF '+str(idle_duration),'green')
        # load the next segment
	#if calledWithPort:
	 #   if calledWithPort==getLocalport():
	#	reactor.callLater(idle_duration, self.startDownload, url_segment, byterange)
	    #    print("port seen from fetchNextSegment= "+str(getLocalport()))
	   #     print('called with port was '+ str(getLocalport()))
	  #  else:
         #       print('RACE CONDITION!!!!!!')
	#	print("port seen from fetchNextSegment= "+str(getLocalport()))
	#	return

	#else:	
	#    print('fetchNextSegment was not called from ZMQ')
	print("calling start download with test= "+str(test))
        reactor.callLater(idle_duration, self.startDownload, url_segment, byterange)
Пример #3
0
 def _onDataReceiving(self, connection, data_diff, remaining_data):
     '''
     Does something before segment download is completed (used with persistent connection)
     '''
     self.remaining_data = remaining_data
     debug(DEBUG+1, '%s _onDataReceiving: %s %s', self, format_bytes(data_diff), format_bytes(remaining_data))
     self.rate_calc.update(data_diff)
    def calcControlAction(self):
        video_rates = self.feedback['rates']
        T_tilde = self.feedback['last_download_time']
        tau = self.feedback['fragment_duration']
        x_tilde = self.feedback['cur_rate'] * self.feedback[
            'fragment_duration'] / T_tilde  #bandwidth estimate sample on the last downloaded segment
        T_hat_old = self.getIdleDuration()
        #Actual inter-request time
        T = max(T_hat_old, T_tilde)
        self.T_old = T
        k = self.k
        w = self.w  #in B/s
        beta = self.beta

        x_hat = max(
            0,
            self.x_hat_last + T * k * (w - max(0, self.x_hat_last - x_tilde)))

        self.x_hat_last = x_hat
        control_action = self.__ewma_filter(x_hat)

        r = self.quantizeSpecialRate(control_action)
        B = self.feedback['queued_time']

        T_hat = r * float(tau) / control_action + beta * (float(B) -
                                                          float(self.Q))
        self.setIdleDuration(T_hat - T_tilde)
        debug(
            DEBUG,
            "%s calcControlAction: ca: %s/s r: %s/s x_tilde: %s/s x_hat: %s/s T_tilde: %.2f T_hat: %.2f T: %.2f",
            self, format_bytes(control_action), format_bytes(r),
            format_bytes(x_tilde), format_bytes(x_hat), T_tilde, T_hat, T)
        return r
Пример #5
0
    def playNextGotRequest(self, data, factory):
        '''
        Updates feedbacks, calculates the control action and sets level of the next segment.

        :param data: downloaded data
        :param factory: the twisted factory (used without persistent connection)
        '''
        self.stop_segment_request = time.time()
        download_time = (self.stop_segment_request - self.start_segment_request)
        self.last_downloaded_time = download_time
        self.bwe = len(data)/download_time
        self.last_fragment_size = len(data)
        self.downloaded_bytes += len(data)
        self.downloaded_segments += 1
        debug(DEBUG, '%s __got_request: bwe: %s/s (fragment size: %s)', self, 
            format_bytes(self.bwe), format_bytes(len(data)))
        self.queuedTime = self.media_engine.getQueuedTime() + self.parser.getFragmentDuration()
        self.queuedBytes = self.media_engine.getQueuedBytes() + len(data)
        self.media_engine.pushData(data, self.parser.getFragmentDuration(), self.getCurrentLevel(), self.parser._getCapsDemuxer())
        del data
        self.cur_index += 1
        #Do something before calculating new control action
        self._onNewSegment()
        #Passing player parameters at the controller to calculate the control action
        self.updateFeedback(flag_check_buffering=False)
        #calc control action
        self.controller.setControlAction(self.controller.calcControlAction())
        # set new level
        if self.getDownloadedSegments() > self.getInactiveCycles():
            if self.enable_stress_test:
                self.stressTest()
            else:
                self.setLevel(self.controller.getControlAction())
        self.fetchNextSegment()
Пример #6
0
    def checkBuffering(self, _arg):
        '''
        Checks if the playback is going to buffering.
        Estimates the time required to complete the download of the current segment and verifies that it is less than the playout buffer lenght.

        In the case of "warning buffering", it deletes the current segment download, calculates the control action and sets the new level.
        This feature is available only with persistent connection.
        '''
        #FIXME Can't use it without persistent connection
        if self.rate_calc.rate and self.cur_index > self.inactive_cycle:
            remaining_secs = float(self.remaining_data/self.rate_calc.rate)
            debug(DEBUG+1,"%s checkBuffering: rate %s/s, remaining_data %s, remaining_secs %.3f, queued_time %.2f ", self, 
                format_bytes(self.rate_calc.rate), format_bytes(self.remaining_data), remaining_secs, self.media_engine.getQueuedTime()) 
            #Can cancel download only if the current level is greater than 0
            if self.media_engine.getQueuedTime() < remaining_secs and self.getCurrentLevel() > 0: 
                self.connection.stop()
                self.stop_segment_request = time.time() #update stop reqest when warning buffering occurs
                self.bwe = self.rate_calc.rate
                #Passing player parameters at the controller to calculate the control action
                self.updateFeedback(flag_check_buffering=True)
                #calc control action
                self.controller.setControlAction(self.controller.calcControlAction())
                # set new level
                if self.cur_index > self.inactive_cycle:
                    self.setLevel(self.controller.getControlAction())
                    debug(0,"%s WARNING BUFFERING!!! Delete and reload segment at level: %d", self, self.getCurrentLevel())
        else:
            return
Пример #7
0
 def _onDataReceiving(self, connection, data_diff, remaining_data):
     '''
     Does something before segment download is completed (used with persistent connection)
     '''
     self.remaining_data = remaining_data
     debug(DEBUG+1, '%s _onDataReceiving: %s %s', self, format_bytes(data_diff), format_bytes(remaining_data))
     self.rate_calc.update(data_diff)
Пример #8
0
 def fetchNextSegment(self):
     '''
     Schedules the download of the next segment at current level
     '''
     playlist = self.parser.playlists[self.getCurrentLevel()]
     debug(DEBUG + 1, '%s fetchNextSegment level: %d cur_index: %d', self,
           self.getCurrentLevel(), self.getCurrentSegmentIndex())
     #
     if self.getCurrentSegmentIndex() < playlist['start_index']:
         self.setCurrentSegmentIndex(playlist['start_index'])
     if self.getCurrentSegmentIndex() > playlist['end_index']:
         # else live video (ONLY HLS!!)
         if playlist['is_live'] and self.parser.getPlaylistType() == 'HLS':
             debug(DEBUG, '%s fetchNextSegment cur_index %d', self,
                   self.getCurrentSegmentIndex())
             self.parser.updateLevelSegmentsList(
                 self.getCurrentLevel()).addCallback(
                     self._updatePlaylistDone)
         # if video is vod
         else:
             debug(DEBUG, '%s fetchNextSegment last index', self)
             self.terminated = True
             #process = subprocess.Popen(os.getpid())
             #process.send_signal(signal.SIGINT)
             #sys.exit()
         return
     cur_index = self.getCurrentSegmentIndex()
     levels = self.parser.getLevels()
     url_segment = playlist['segments'][cur_index]['url']
     byterange = playlist['segments'][cur_index]['byterange']
     if byterange != '':
         debug(
             DEBUG,
             '%s fetchNextSegment level: %d (%s/s) %d/%d : %s (byterange=%s)',
             self, self.getCurrentLevel(),
             format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
             self.getCurrentSegmentIndex(), playlist['end_index'],
             url_segment, byterange)
     else:
         debug(DEBUG, '%s fetchNextSegment level: %d (%s/s) %d/%d : %s',
               self, self.getCurrentLevel(),
               format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
               self.getCurrentSegmentIndex(), playlist['end_index'],
               url_segment)
     if self.controller.feedback['queued_time'] < self.controller.feedback[
             'max_buffer_time']:
         idle_duration = 0.0  #fetch segment after the last segment download is completed
     else:
         idle_duration = max(
             0.0, self.controller.feedback['queued_time'] -
             self.controller.feedback['max_buffer_time'] -
             self.controller.feedback['last_download_time'])
     # if bandwidth is varried per segment set new bandwidth
     if self.mu is not None and self.sigma is not None:
         self.setNewBandwidth()
     # load the next segment
     reactor.callLater(idle_duration, self.startDownload, url_segment,
                       cur_index, byterange)
Пример #9
0
 def calcControlAction(self):    
     T = self.feedback['last_download_time']
     cur = self.feedback['cur_rate']
     tau = self.feedback['fragment_duration']
     x = cur * tau / T
     y = self.__ewma_filter(x) 
     self.setIdleDuration(tau-T)
     debug(DEBUG, "%s calcControlAction: y: %s/s x: %s/s T: %.2f", self, 
         format_bytes(y), format_bytes(x), T)
     return y
Пример #10
0
 def calcControlAction(self):    
     T = self.feedback['last_download_time']
     cur = self.feedback['cur_rate']
     tau = self.feedback['fragment_duration']
     x = cur * tau / T
     y = self.__ewma_filter(x) 
     self.setIdleDuration(tau-T)
     debug(DEBUG, "%s calcControlAction: y: %s/s x: %s/s T: %.2f", self, 
         format_bytes(y), format_bytes(x), T)
     return y
Пример #11
0
    def fetchNextSegment(self):
        '''
        Schedules the download of the next segment at current level
        '''

        playlist = self.parser.playlists[self.getCurrentLevel()]
        debug(DEBUG + 1, '%s fetchNextSegment level: %d cur_index: %d', self,
              self.getCurrentLevel(), self.getCurrentSegmentIndex())
        #
        if self.getCurrentSegmentIndex() < playlist['start_index']:
            self.setCurrentSegmentIndex(playlist['start_index'])
        if self.getCurrentSegmentIndex() > playlist['end_index']:
            # else live video (ONLY HLS!!)
            if playlist['is_live'] and self.parser.getPlaylistType() == 'HLS':
                debug(DEBUG, '%s fetchNextSegment cur_index %d', self,
                      self.getCurrentSegmentIndex())
                self.parser.updateLevelSegmentsList(
                    self.getCurrentLevel()).addCallback(
                        self._updatePlaylistDone)
            # if video is vod
            else:
                debug(DEBUG, '%s fetchNextSegment last index', self)
            return
        cur_index = self.getCurrentSegmentIndex()
        levels = self.parser.getLevels()
        url_segment = playlist['segments'][cur_index]['url']
        byterange = playlist['segments'][cur_index]['byterange']
        if byterange != '':
            debug(
                DEBUG,
                '%s fetchNextSegment level: %d (%s/s) %d/%d : %s (byterange=%s)',
                self, self.getCurrentLevel(),
                format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
                self.getCurrentSegmentIndex(), playlist['end_index'],
                url_segment, byterange)
        else:
            debug(DEBUG, '%s fetchNextSegment level: %d (%s/s) %d/%d : %s',
                  self, self.getCurrentLevel(),
                  format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
                  self.getCurrentSegmentIndex(), playlist['end_index'],
                  url_segment)
        if self.controller.isBuffering():
            idle_duration = 0.0  #fetch segment after the last segment download is completed
        else:
            idle_duration = self.controller.getIdleDuration()
        # load the next segment
        reactor.callLater(idle_duration, self.startDownload, url_segment,
                          byterange)
Пример #12
0
 def pushData(self, data, fragment_duration, level, caps_data):
     debug(DEBUG, '%s pushData: pushed %s of data for level %s', self,
           format_bytes(len(data)), level)
     self.queue['byte'] += len(data)
     self.queue['sec'] += fragment_duration
     self.pushed_segments.append(
         dict(len_segment=len(data), dur_segment=fragment_duration))
Пример #13
0
 def pushData(self, data, fragment_duration, level, caps_data):
     debug(DEBUG, '%s pushData: pushed %s of data for level %s', self, 
         format_bytes(len(data)),
         level)
     self.queue['byte']+=len(data)
     self.queue['sec']+=fragment_duration
     self.pushed_segments.append(dict(len_segment=len(data),dur_segment=fragment_duration))
 def __harmonic_mean(v):
     '''Computes the harmonic mean of vector v'''
     x = numpy.array(v)
     debug(DEBUG+1, "%s __harmonic_mean: Bwe vect: %s", self, str(x))
     m =  1.0/(sum(1.0/x)/len(x))
     debug(DEBUG, "%s__harmonic_mean: Harmonic mean: %s/s", self, format_bytes(m))
     return m
Пример #15
0
    def _onDataReceived(self, connection, data):
        '''
        Does something when segment download is completed (used with persistent connection)
        '''

        debug(DEBUG+1, '%s _onDataReceived: %s', self, format_bytes(len(data)))  
        self.playNextGotRequest(data, None)
Пример #16
0
    def _onDataReceived(self, connection, data):
        '''
        Does something when segment download is completed (used with persistent connection)
        '''

        debug(DEBUG+1, '%s _onDataReceived: %s', self, format_bytes(len(data)))  
        self.playNextGotRequest(data, None)
Пример #17
0
 def pushData(self, data, fragment_duration, level, view, caps_data):
     debug(DEBUG, '%s pushData: pushed %s of data for level %s', self, 
         format_bytes(len(data)),
         level)
     self.evicted_segment = 0
     self.checkGstbuffer()
     
     # check view change for playout buffer eviction
     if (view != self.current_view):
         # check if gstreamer has enough data (for limiting rebuffering events)
         self.checkGstbuffer()
         # flush playout buffer
         byte = 0
         sec  = 0
         self.evicted_segment = len(self.pushed_segments)
         for segment in self.pushed_segments:
             byte += segment["len_segment"]
             sec  += segment["dur_segment"]
             
         self.queue['byte']   -= byte
         self.queue['sec']    -= sec
         del self.pushed_segments
         self.pushed_segments  = []
         self.playtime        -= sec
         
         # set new current view
         self.current_view = view
     
     # fill playout buffer
     self.queue['byte'] +=len(data)
     self.queue['sec']  +=fragment_duration
     self.pushed_segments.append(dict(len_segment=len(data), dur_segment=fragment_duration, data=data))
Пример #18
0
 def on_data_received(self, connection, data, level):
     debug(DEBUG+1, '%s on_data_received: %s', self, format_bytes(len(data)))
     self.fd[level] = StringIO.StringIO(data)
     #print "level", level
     self.playlists[level]["header_data"]=data
     self.parse_atom(0,len(data)-1, level)
     self.deferredList[level].callback(1)
     self.connection_list[level].stop()
Пример #19
0
 def pushData(self, data, fragment_duration, level, caps_data):
     buf = gst.Buffer(data)
     buf.duration = long(fragment_duration * 1e9)
     debug(DEBUG,
           '%s pushData: pushed %s of data (duration= %.2fs) for level %s',
           self, format_bytes(len(data)), fragment_duration, level)
     self.pipeline.get_by_name('src').emit('push-buffer', buf)
     del buf
Пример #20
0
 def on_data_received(self, connection, data, level):
     debug(DEBUG+1, '%s on_data_received: %s', self, format_bytes(len(data)))
     self.fd[level] = StringIO.StringIO(data)
     #print "level", level
     self.playlists[level]["header_data"]=data
     self.parse_atom(0,len(data)-1, level)
     self.deferredList[level].callback(1)
     self.connection_list[level].stop()
Пример #21
0
    def playNextGotRequest(self, data, factory):
        '''
        Updates feedbacks, calculates the control action and sets level of the next segment.

        :param data: downloaded data
        :param factory: the twisted factory (used without persistent connection)
        '''
        self.stop_segment_request = time.time()
        download_time = (self.stop_segment_request -
                         self.start_segment_request)
        self.last_downloaded_time = download_time
        self.bwe = len(data) / download_time
        self.last_fragment_size = len(data)
        self.downloaded_bytes += len(data)
        self.downloaded_segments += 1
        real_seg_dur = self.parser.getRealSegmentDuration(self.cur_index)
        debug(DEBUG, '%s __got_request: bwe: %s/s (fragment size: %s)', self,
              format_bytes(self.bwe), format_bytes(len(data)))
        playlist = self.parser.playlists[self.getCurrentLevel()]
        #self.queuedTime = self.media_engine.getQueuedTime() + self.parser.getFragmentDuration()
        self.queuedTime = self.media_engine.getQueuedTime(
        ) + self.parser.getRealSegmentDuration(self.cur_index)
        self.queuedBytes = self.media_engine.getQueuedBytes() + len(data)
        self.media_engine.pushData(
            data, self.parser.getRealSegmentDuration(self.cur_index),
            self.getCurrentLevel(), self.parser._getCapsDemuxer())
        del data

        if self.getCurrentSegmentIndex() <= playlist['end_index']:
            self.setCurrentSegmentDuration(
                playlist['segments'][self.getCurrentSegmentIndex()]['dur'])
        #Do something before calculating new control action
        self._onNewSegment()
        #Passing player parameters at the controller to calculate the control action
        self.updateFeedback(flag_check_buffering=False)
        self.cur_index += 1
        #calc control action
        self.controller.setControlAction(self.controller.calcControlAction())
        # set new level
        if self.getDownloadedSegments() > self.getInactiveCycles():
            if self.enable_stress_test:
                self.stressTest()
            else:
                self.setLevel(self.controller.getControlAction())
        self.fetchNextSegment()
Пример #22
0
 def pushData(self, data, fragment_duration, level, caps_data):
     buf = gst.Buffer(data)
     buf.duration = long(fragment_duration*1e9)
     debug(DEBUG, '%s pushData: pushed %s of data (duration= %ds) for level %s', self, 
         format_bytes(len(data)),
         fragment_duration,
         level)
     self.pipeline.get_by_name('src').emit('push-buffer', buf)
     del buf
Пример #23
0
 def quantizeRate(self,rate):
     video_rates = self.feedback['rates']
     cur = self.feedback['cur_rate'] 
     level = self.feedback['level']
     D_up = self.eps*rate
     D_down = 0
     
     r_up = self.__levelLessThanRate(rate - D_up)
     r_down = self.__levelLessThanRate(rate - D_down)
     new_level = 0
     if level < r_up:
         new_level = r_up
     elif r_up <= level and level <= r_down:
         new_level = level
     else:
         new_level = r_down
     debug(DEBUG, "%s quantizeRate: rate: %s/s cur: %s/s D_up: %s/s D_down: %s/s r_up: %d r_down: %d new_level: %d", self, 
         format_bytes(rate), format_bytes(cur), format_bytes(D_up), format_bytes(D_down), r_up, r_down, new_level)
     debug(DEBUG, "%s quantizeRate: rates: %s", self, video_rates)
     return new_level
Пример #24
0
 def quantizeRate(self,rate):
     video_rates = self.feedback['rates']
     cur = self.feedback['cur_rate'] 
     level = self.feedback['level']
     D_up = self.eps*rate
     D_down = 0
     
     r_up = self.__levelLessThanRate(rate - D_up)
     r_down = self.__levelLessThanRate(rate - D_down)
     new_level = 0
     if level < r_up:
         new_level = r_up
     elif r_up <= level and level <= r_down:
         new_level = level
     else:
         new_level = r_down
     debug(DEBUG, "%s quantizeRate: rate: %s/s cur: %s/s D_up: %s/s D_down: %s/s r_up: %d r_down: %d new_level: %d", self, 
         format_bytes(rate), format_bytes(cur), format_bytes(D_up), format_bytes(D_down), r_up, r_down, new_level)
     debug(DEBUG, "%s quantizeRate: rates: %s", self, video_rates)
     return new_level
Пример #25
0
 def fetchNextSegment(self): 
     '''
     Schedules the download of the next segment at current level
     '''
     playlist = self.parser.playlists[self.getCurrentLevel()]
     debug(DEBUG+1, '%s fetchNextSegment level: %d cur_index: %d', self, self.getCurrentLevel(), self.getCurrentSegmentIndex())
     #
     if self.getCurrentSegmentIndex() < playlist['start_index']:
         self.setCurrentSegmentIndex(playlist['start_index'])
     if self.getCurrentSegmentIndex() > playlist['end_index']:
         # else live video (ONLY HLS!!)
         if playlist['is_live'] and self.parser.getPlaylistType() == 'HLS':
             debug(DEBUG, '%s fetchNextSegment cur_index %d', self, self.getCurrentSegmentIndex())
             self.parser.updateLevelSegmentsList(self.getCurrentLevel()).addCallback(self._updatePlaylistDone)
         # if video is vod
         else:
             debug(DEBUG, '%s fetchNextSegment last index', self)
         return
     cur_index=self.getCurrentSegmentIndex()
     levels = self.parser.getLevels()
     url_segment = playlist['segments'][cur_index]['url']
     byterange = playlist['segments'][cur_index]['byterange']
     if byterange != '':
         debug(DEBUG, '%s fetchNextSegment level: %d (%s/s) %d/%d : %s (byterange=%s)', self,
             self.getCurrentLevel(), 
             format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
             self.getCurrentSegmentIndex(), 
             playlist['end_index'], url_segment, byterange)
     else:
         debug(DEBUG, '%s fetchNextSegment level: %d (%s/s) %d/%d : %s', self,
             self.getCurrentLevel(), 
             format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
             self.getCurrentSegmentIndex(), 
             playlist['end_index'], url_segment)
     if self.controller.isBuffering():
         idle_duration = 0.0 #fetch segment after the last segment download is completed
     else:
         idle_duration = self.controller.getIdleDuration()
     # load the next segment
     reactor.callLater(idle_duration, self.startDownload, url_segment, byterange)
Пример #26
0
    def playNextGotRequest(self, data, factory):
        '''
        Updates feedbacks, calculates the control action and sets level of the next segment.

        :param data: downloaded data
        :param factory: the twisted factory (used without persistent connection)
        '''
        self.stop_segment_request = time.time()
        download_time = (self.stop_segment_request - self.start_segment_request)
	print("DOWNLOAD COMPLETED AFTER "+str(download_time)+" SECONDS")
        self.last_downloaded_time = download_time
        self.bwe = len(data)/download_time
        self.last_fragment_size = len(data)
        self.downloaded_bytes += len(data)
        self.downloaded_segments += 1
        debug(DEBUG, '%s __got_request: bwe: %s/s (fragment size: %s)', self, 
            format_bytes(self.bwe), format_bytes(len(data)))
        self.queuedTime = self.media_engine.getQueuedTime() + self.parser.getFragmentDuration()
        self.queuedBytes = self.media_engine.getQueuedBytes() + len(data)
        self.media_engine.pushData(data, self.parser.getFragmentDuration(), self.getCurrentLevel(), self.parser._getCapsDemuxer())
        del data
        self.cur_index += 1
        #Do something before calculating new control action
        self._onNewSegment()
        #Passing player parameters at the controller to calculate the control action
        self.updateFeedback(flag_check_buffering=False)
        #calc control action
        self.controller.setControlAction(self.controller.calcControlAction())
        # set new level
        if self.getDownloadedSegments() > self.getInactiveCycles():
            if self.enable_stress_test:
                self.stressTest()
            else:
                self.setLevel(self.controller.getControlAction())
	print colored("[playNextGotRequest()] I called makeRequest() [1]",'red');
        self.makeRequest()
    def __evalRefLevel(self, bwe_filt):
        cur = self.feedback['cur_rate']
        cur_idx = self.feedback['level']
        new_idx = cur_idx
        
        video_rates = self.feedback['rates']

        debug(DEBUG, "%s __evalRefLevel: vrates: %s", self, str(video_rates))
        if cur > 0.85*bwe_filt:
            new_idx = cur_idx - 1
        else:
            for i in range(0,len(video_rates) - 1):
                if bwe_filt >= video_rates[i]:
                    debug(DEBUG, "%s __evalRefLevel: Bwe: %s/s vrate: %s/s", self, format_bytes(bwe_filt), format_bytes(video_rates[i]))
                    new_idx = i
        
        new_idx = min(max(new_idx,0), len(video_rates) -1)
        debug(DEBUG, "%s __evalRefLevel: Cur_idx: %d new_idx: %d", self, cur_idx, new_idx)
        return video_rates[new_idx] 
Пример #28
0
    def pushData(self, data, fragment_duration, level, caps_data):
        try:
            #f= open("{}.mp4".format(self.ind),"w+")
            #f.write(data)
            #self.ind += 1
            #f.close()

            buf = gst.Buffer(data)
            buf.duration = long(fragment_duration * 1e9)
            #print(">>>>>>>>>>>>> Push data", level, fragment_duration, len(data), len(buf))
            debug(
                DEBUG,
                '%s pushData: pushed %s of data (duration= %ds) for level %s',
                self, format_bytes(len(data)), fragment_duration, level)

            self.pipeline.get_by_name('src').emit('push-buffer', buf)
            del buf
        except Exception, e:
            print(">>>>>>>>>>>> EXCEPTION: " + str(e))
            sys.exit(1)  #HARD, better to do return
Пример #29
0
    def quantizeSpecialRate(self, rate):
        video_rates = self.feedback['rates']
        cur = self.feedback['cur_rate']
        #D_up = self.w + self.eps*rate
        #D_down = self.w
        D_up = self.eps * rate
        D_down = 0

        r_up = video_rates[self.__levelLessThanRate(rate - D_up)]
        r_down = video_rates[self.__levelLessThanRate(rate - D_down)]
        new_level = 0
        if cur < r_up:
            new_level = r_up
        elif r_up <= cur and cur <= r_down:
            new_level = cur
        else:
            new_level = r_down
        debug(
            DEBUG,
            "%s quantizeRate: rate: %s/s D_up: %s/s D_down: %s/s r_up: %s/s r_down: %s/s new_level_rate: %s/s",
            self, format_bytes(rate), format_bytes(D_up), format_bytes(D_down),
            format_bytes(r_up), format_bytes(r_down), format_bytes(new_level))
        debug(DEBUG, "%s quantizeRate: rates: %s", self, video_rates)
        return new_level
Пример #30
0
    def playNextGotRequest(self, data, factory):
        '''
        Updates feedbacks, calculates the control action and sets level of the next segment.

        :param data: downloaded data
        :param factory: the twisted factory (used without persistent connection)
        '''

        self.stop_segment_request = time.time()
        download_time = (self.stop_segment_request -
                         self.start_segment_request)
        self.last_downloaded_time = download_time
        self.bwe = len(data) / download_time
        self.last_fragment_size = len(data)
        self.downloaded_bytes += len(data)
        self.downloaded_segments += 1
        debug(DEBUG, '%s __got_request: bwe: %s/s (fragment size: %s)', self,
              format_bytes(self.bwe), format_bytes(len(data)))

        self.queuedTime = self.media_engine.getQueuedTime(
        ) + self.parser.getFragmentDuration()
        #print ">>>>>>>>>>>>>>>>>>>>>>>>>> TAPAS QUEUE TIME: " + str(self.queuedTime)
        self.queuedBytes = self.media_engine.getQueuedBytes() + len(data)

        playlist = self.parser.getSinglePlaylist(self.getCurrentLevel(),
                                                 self.getCurrentView())
        if ("initURL" in playlist):
            #download init segment (DASH BASED CODING)
            if ("initSegment" in playlist):
                #push next segment
                print "THERE'S INIT"
                print "LEVEL " + str(self.cur_level) + "\nURL:   " + str(
                    playlist["initURL"]) + "\nINDEX: " + str(self.cur_index)
                self.media_engine.pushData(playlist["initSegment"] + data,
                                           self.parser.getFragmentDuration(),
                                           self.getCurrentLevel(),
                                           self.parser._getCapsDemuxer())

                #if (self.cur_index == 0):
                #print "INIT + DATA"
                #self.media_engine.pushData(playlist["initSegment"] + data, self.parser.getFragmentDuration(), self.getCurrentLevel(), self.parser._getCapsDemuxer())
                #else:
                #print "ONLY DATA"
                #self.media_engine.pushData(data, self.parser.getFragmentDuration(), self.getCurrentLevel(), self.parser._getCapsDemuxer())
            else:
                # ERROR
                print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ERROR <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
        else:
            #push next segment
            print "THERE ISN'T INIT"
            self.media_engine.pushData(data, self.parser.getFragmentDuration(),
                                       self.getCurrentLevel(),
                                       self.parser._getCapsDemuxer())

        #self.media_engine.pushData(data, self.parser.getFragmentDuration(), self.getCurrentLevel(), self.parser._getCapsDemuxer())
        del data
        self.cur_index += 1
        #Do something before calculating new control action
        self._onNewSegment()
        #Passing player parameters at the controller to calculate the control action
        self.updateFeedback(flag_check_buffering=False)
        #calc control action
        self.controller.setControlAction(self.controller.calcControlAction())
        # set new level
        if self.getDownloadedSegments() > self.getInactiveCycles():
            if (self.getNumViews() > 1):
                self.setView()
            if self.enable_stress_test:
                self.stressTest()
            else:
                self.setLevel(self.controller.getControlAction())
        self.fetchNextSegment()
Пример #31
0
    def calcControlAction(self):
        if self.maliciousFlag == 1:
        	self.setIdleDuration(0.0)
		y = float(self.feedback['max_rate']*1.5)
                debug(DEBUG, "MALICIOUS USER!!!")
		debug(DEBUG, "%s calcControlAction: y: %s/s", self, format_bytes(y))
		return y
	else:
		self.bwe_vec.add(self.feedback['bwe'])
		def __harmonic_mean(v):
		    '''Computes the harmonic mean of vector v'''
		    #x = numarray.array(v)
		    x = numpy.array(v)
		    debug(DEBUG+2, "%s __harmonic_mean: Bwe vect: %s", self, str(x))
		    m =  1.0/(sum(1.0/x)/len(x))
		    debug(DEBUG, "%s__harmonic_mean: Harmonic mean: %s/s", self, format_bytes(m))
		    return m
		self.bwe_filt = __harmonic_mean(self.bwe_vec.getBuffer())
		e = self.__getError()
		if e == 0:                             #this "if" sets the flag zero_int_err to nullify the integral error when entering q > q_H or q < q_L
		    self.prec_state = 1
		    zero_int_error = 1
		elif e > 0 and self.prec_state == 0: 
		    self.prec_state = 2
		    zero_int_error = 1
		elif e < 0 and self.prec_state == 2:
		    self.prec_state = 0
		    zero_int_error = 1
		else: 
		    zero_int_error = 0

		max_rate = self.feedback['max_rate']
		min_rate = self.feedback['min_rate']
		d = self.feedback['player_status']
		if self.t_last < 0:
		    delta_t = 0
		    self.int_error = e
		else:
		    delta_t = time.time() - self.t_last
		    if zero_int_error == 1:                         #flag to nullify the integral error when entering q > q_H or q < q_L
			#DEBUG && log('Force integral error == 0');
			self.int_error = 0
		    self.int_error += delta_t * e

		self.t_last = time.time()
		q = self.feedback['queued_time']
		if q < self.__getQueueLowWM() or q > self.__getQueueHighWM() or self.feedback['is_check_buffering']:
		    '''The control law is b / ( 1 - k1 e - k2 ei)'''
		    den = 1 - self.k1*e - self.k2*self.int_error
		    if self.feedback['is_check_buffering']:
			bwe = self.feedback['bwe']
		    else:
			bwe = self.bwe_filt
		    u = bwe/den
		    if den <= 0 or u >= max_rate:
			u = max_rate + 2000 # Make sure that the maximum rate can be selected
			debug(DEBUG, '%s calcControlAction: Max rate reached. Anti windup active',self)
			self.__resetIntegralError(delta_t * e)
		    elif u <= min_rate:
			u = min_rate 
			self.__resetIntegralError(delta_t * e)
			debug(DEBUG, '%s calcControlAction: Min rate reached. Anti windup active',self)
		else:
		    u = self.feedback['cur_rate']
		
		level_u = self.quantizeRate(u)
		if q > self.__getQueueHighWM() and level_u < self.last_level:
		    u = self.feedback['cur_rate']
		    level_u =  self.last_level
		    debug(DEBUG, '%s Prevented switch down when q > q_H',self)
		self.last_level = level_u
		debug(DEBUG, '%s calcControlAction: u: %s/s q: %.2f e: %.2f int_err: %.2f delta_t: %.2f level_u: %d',  self, 
		    format_bytes(u), q, e, self.int_error, delta_t, level_u)
		return u
    def calcControlAction(self):
        self.iteration += 1
        self.bwe_vec.add(self.feedback['bwe'])
       
        level = self.feedback['cur_rate']

        def __harmonic_mean(v):
            '''Computes the harmonic mean of vector v'''
            x = numpy.array(v)
            debug(DEBUG+1, "%s __harmonic_mean: Bwe vect: %s", self, str(x))
            m =  1.0/(sum(1.0/x)/len(x))
            debug(DEBUG, "%s__harmonic_mean: Harmonic mean: %s/s", self, format_bytes(m))
            return m
        w = __harmonic_mean(self.bwe_vec.getBuffer())
        debug(DEBUG, "%s calcControlAction: iteration %d", self, self.iteration)
        if self.iteration >= self.horizon:
            q = self.feedback['queued_time']
            delta = self.feedback['fragment_duration']

            randbuf = random.uniform(self.target_buf - delta, self.target_buf + delta) 
            
            b_ref = self.__evalRefLevel(w)
            b_cur = self.feedback['cur_rate']
            n = sum(self.switches.getBuffer())

            debug(DEBUG, "%s q: %.2f randbuf: %.2f b_ref: %.2f b_cur: %s/s n: %d", self, q, randbuf, b_ref, format_bytes(b_cur), n)
            if self.__evalScore(b_ref, b_ref, w, n) < self.__evalScore(b_cur, b_ref, w,n):
                self.switches.add(1)
                level = b_ref + 1000.0
            else:
                self.switches.add(0)
                level = b_cur + 1000.0

            #Randomized scheduling
            if q < randbuf:
                self.setIdleDuration(0.0)
            else:
                self.setIdleDuration(q - randbuf)
        return level
Пример #33
0
    def fetchNextSegment(self):
        '''
        Schedules the download of the next segment at current level and view
        '''
        playlist = self.parser.getSinglePlaylist(self.getCurrentLevel(),
                                                 self.getCurrentView())
        debug(
            DEBUG + 1,
            '%s fetchNextSegment level: %d angles: %d view: %d cur_index: %d',
            self.getCurrentLevel(),
            self.getCurrentAngles()[0], self.getCurrentView(),
            self.getCurrentSegmentIndex())
        #
        #print str("self.getCurrentSegmentIndex = {}, playlist = {}".format(self.getCurrentSegmentIndex(), playlist['start_index']))

        if self.getCurrentSegmentIndex() < playlist['start_index']:
            self.setCurrentSegmentIndex(playlist['start_index'])

        if self.getCurrentSegmentIndex() > playlist['end_index']:
            # else live video (ONLY HLS!!)
            if playlist['is_live'] and self.parser.getPlaylistType() == 'HLS':
                print("playlist['is_live'] :" + str(playlist['is_live']))
                debug(DEBUG, '%s fetchNextSegment cur_index %d', self,
                      self.getCurrentSegmentIndex())
                self.parser.updateLevelSegmentsList(
                    self.getCurrentLevel(), self.getCurrentView()).addCallback(
                        self._updatePlaylistDone)
            # if video is vod
            else:
                debug(DEBUG, '%s fetchNextSegment last index', self)

            # set max video duration for stopping media_engine
            self.media_engine.setVideoDuration(playlist['duration'])
            #print("STOP PLAYING.")
            return

        cur_index = self.getCurrentSegmentIndex()
        levels = self.parser.getLevels()
        url_segment = playlist['segments'][cur_index]['url']
        byterange = playlist['segments'][cur_index]['byterange']
        if byterange != '':
            debug(
                DEBUG,
                '%s fetchNextSegment level: %d (%s/s) %d/%d : %s (byterange=%s) angles:%d view: %d',
                self, self.getCurrentLevel(),
                format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
                self.getCurrentSegmentIndex(), playlist['end_index'],
                url_segment, byterange, self.getCurrentAngles(),
                self.getCurrentView())
        else:
            debug(
                DEBUG,
                '%s fetchNextSegment level: %d (%s/s) %d/%d angles:%d view %d: %s',
                self, self.getCurrentLevel(),
                format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
                self.getCurrentSegmentIndex(), playlist['end_index'],
                self.getCurrentAngles()[0], self.getCurrentView(), url_segment)

        if self.controller.isBuffering():
            idle_duration = 0.0  #fetch segment after the last segment download is completed
        else:
            idle_duration = self.controller.getIdleDuration()
        # load the next segment
        if self.last_redirect_host:
            host, port, path = parse_url(url_segment)
            url_segment = 'http://' + self.last_redirect_host + path

        reactor.callLater(idle_duration, self.startDownload, url_segment,
                          byterange)
Пример #34
0
    def fetchNextSegment(self):
        '''
        Schedules the download of the next segment at current level
        '''
        print("FETCH THE NEXT SEGMENT IN LEVEL: " +
              str(self.getCurrentLevel()))
        #print ("MY PID IS "+str(os.getpid()))

        playlist = self.parser.playlists[self.getCurrentLevel()]
        debug(DEBUG + 1, '%s fetchNextSegment level: %d cur_index: %d', self,
              self.getCurrentLevel(), self.getCurrentSegmentIndex())
        #
        if self.getCurrentSegmentIndex() < playlist['start_index']:
            self.setCurrentSegmentIndex(playlist['start_index'])
        if self.getCurrentSegmentIndex() > playlist['end_index']:
            # else live video (ONLY HLS!!)
            if playlist['is_live'] and self.parser.getPlaylistType() == 'HLS':
                debug(DEBUG, '%s fetchNextSegment cur_index %d', self,
                      self.getCurrentSegmentIndex())
                self.parser.updateLevelSegmentsList(
                    self.getCurrentLevel()).addCallback(
                        self._updatePlaylistDone)
            # if video is vod
            else:
                debug(DEBUG, '%s fetchNextSegment last index', self)
            return
        cur_index = self.getCurrentSegmentIndex()
        levels = self.parser.getLevels()
        url_segment = playlist['segments'][cur_index]['url']
        byterange = playlist['segments'][cur_index]['byterange']
        if byterange != '':
            debug(
                DEBUG,
                '%s fetchNextSegment level: %d (%s/s) %d/%d : %s (byterange=%s)',
                self, self.getCurrentLevel(),
                format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
                self.getCurrentSegmentIndex(), playlist['end_index'],
                url_segment, byterange)
        else:
            debug(DEBUG, '%s fetchNextSegment level: %d (%s/s) %d/%d : %s',
                  self, self.getCurrentLevel(),
                  format_bytes(float(levels[self.getCurrentLevel()]['rate'])),
                  self.getCurrentSegmentIndex(), playlist['end_index'],
                  url_segment)
        if self.controller.isBuffering():
            idle_duration = 0.0  #fetch segment after the last segment download is completed
        else:
            idle_duration = self.controller.getIdleDuration()
        # load the next segment
        clientInfo = socket.gethostbyname(socket.gethostname())
        segSize = float(float(self.getLastFragmentBytes() * 8)) / 1000
        print["MESSAGE SEND TO ORCHESTRATOR"]
        print colored("[delegated level is ]" + str(self.delegatedLevel),
                      'green')
        if self.first == 1:
            socket_send_app_param.send_string(
                "%s %s %s %s %s %s" %
                ("2", "start", str(clientInfo), str(
                    getLocalport()), str(os.getpid()), "1080p"))
            self.first = 0

        else:
            socket_send_app_param.send_string(
                "%s %s %s %s %s %s" %
                ("2", "client_update", str(clientInfo), str(
                    getLocalport()), str(os.getpid()), "1080p"))
        print("sent info to zmq-entity")
        reactor.callLater(idle_duration, self.startDownload, url_segment,
                          byterange)
Пример #35
0
    def playNextGotRequest(self, data, factory):
        '''
        Updates feedbacks, calculates the control action and sets level of the next segment.

        :param data: downloaded data
        :param factory: the twisted factory (used without persistent connection)
        '''

        self.stop_segment_request = time.time()
        download_time = (self.stop_segment_request -
                         self.start_segment_request)
        self.last_downloaded_time = download_time
        self.bwe = len(data) / download_time
        self.last_fragment_size = len(data)
        self.downloaded_bytes += len(data)
        self.downloaded_segments += 1
        debug(DEBUG, '%s __got_request: bwe: %s/s (fragment size: %s)', self,
              format_bytes(self.bwe), format_bytes(len(data)))

        self.queuedTime = self.media_engine.getQueuedTime(
        ) + self.parser.getFragmentDuration()
        self.queuedBytes = self.media_engine.getQueuedBytes() + len(data)

        playlist = self.parser.getSinglePlaylist(self.getCurrentLevel(),
                                                 self.getCurrentView())
        if ("initURL" in playlist):
            #print("HLS on mp4")
            # download init segment (DASH BASED CODING)
            if ("initSegment" in playlist):
                #push next segment
                #print("LEVEL: " + str(self.cur_level) + "\nVIEW: " + str(self.cur_view) + "\nInit URL:   " + str(playlist["initURL"]) + "\nFragment Id: " + str(self.cur_index))
                self.media_engine.setOriginalSideWidth(
                    playlist['central_width'])
                self.media_engine.setScaledSideWidth(playlist['side_width'])
                self.media_engine.pushData(playlist["initSegment"] + data,
                                           self.parser.getFragmentDuration(),
                                           self.getCurrentLevel(),
                                           self.getCurrentView(),
                                           self.parser._getCapsDemuxer())

            else:
                # ERROR
                print("ERROR: missing init file")
        else:
            # push next segment
            #print("HLS on mpegts")
            self.media_engine.pushData(data, self.parser.getFragmentDuration(),
                                       self.getCurrentLevel(),
                                       self.getCurrentView(),
                                       self.parser._getCapsDemuxer())

        # flush segment on file
        if (self.save_chunks):
            filename = "{0!s}_{1!s}_{2!s}.mp4".format(self.downloaded_segments,
                                                      self.getCurrentLevel(),
                                                      self.getCurrentView())
            self.logger.logData(filename, data)

        del data
        self.cur_index = self.media_engine.getNextVideoSegmentToBeFetched(
            self.cur_index)
        #Do something before calculating new control action
        self._onNewSegment()
        #Passing player parameters at the controller to calculate the control action
        self.updateFeedback(flag_check_buffering=False)
        #calc control action
        self.controller.setControlAction(self.controller.calcControlAction())
        # set new level
        if self.getDownloadedSegments() > self.getInactiveCycles():
            if (self.getNumViews() > 1):
                self.setView()
            if self.enable_stress_test:
                self.stressTest()
            else:
                self.setLevel(self.controller.getControlAction())
        self.fetchNextSegment()