xpra icon
Bug tracker and wiki

Ticket #981: sync-paint-with-video.patch

File sync-paint-with-video.patch, 7.8 KB (added by Antoine Martin, 5 years ago)

attempt at implementing this

  • xpra/client/gl/gl_window_backing_base.py

     
    454454        glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, self.shaders[YUV2RGB_SHADER])
    455455
    456456    def present_fbo(self, x, y, w, h, flush=0):
    457         log("present_fbo: adding %s to pending paint list, flush=%s", (x, y, w, h), flush)
     457        log.info("present_fbo: adding %s to pending paint list, flush=%s", (x, y, w, h), flush)
    458458        self.pending_fbo_paint.append((x, y, w, h))
    459459        if not self.paint_screen:
    460460            return
  • xpra/server/window_source.py

     
    11161116        if not self.is_cancelled():
    11171117            self.do_send_delayed_regions(damage_time, window, regions, coding, options)
    11181118
    1119     def do_send_delayed_regions(self, damage_time, window, regions, coding, options, exclude_region=None, get_best_encoding=None):
     1119    def do_send_delayed_regions(self, damage_time, window, regions, coding, options, exclude_region=None, get_best_encoding=None, flush_offset=0):
    11201120        ww,wh = window.get_dimensions()
    11211121        speed = options.get("speed") or self._current_speed
    11221122        quality = options.get("quality") or self._current_quality
     
    11841184                log("send_delayed_regions: %s regions with %s pixels (encoding=%s, actual=%s)", len(regions), pixel_count, coding, actual_encoding)
    11851185                if pixel_count>=ww*wh or self.must_encode_full_frame(window, actual_encoding):
    11861186                    #use full screen dimensions:
    1187                     self.process_damage_region(damage_time, window, 0, 0, ww, wh, actual_encoding, options)
     1187                    self.process_damage_region(damage_time, window, 0, 0, ww, wh, actual_encoding, options, flush=flush_offset)
    11881188                    return
    11891189
    11901190        #we're processing a number of regions separately,
     
    11961196                self.process_damage_region(damage_time, window, 0, 0, ww, wh, actual_encoding, options)
    11971197                #we can stop here (full screen update will include the other regions)
    11981198                return
    1199             i_reg_enc.append((i, region, actual_encoding))
     1199            i_reg_enc.append((flush_offset+i, region, actual_encoding))
    12001200
    12011201        #reversed so that i=0 is last for flushing
    12021202        for i, region, actual_encoding in reversed(i_reg_enc):
  • xpra/server/window_video_source.py

     
    434434    def must_batch(self, delay):
    435435        #force batching when using video region
    436436        #because the video region code is in the send_delayed path
     437        #and because we want to flush all the paints with the video
    437438        return self.video_subregion.rectangle is not None or WindowSource.must_batch(self, delay)
    438439
    439440
     
    519520        """
    520521        #overrides the default method for finding the encoding of a region
    521522        #so we can ensure we don't use the video encoder when we don't want to:
    522         def send_nonvideo(regions=regions, encoding=coding, exclude_region=None, get_best_encoding=self.get_best_nonvideo_encoding):
    523             WindowSource.do_send_delayed_regions(self, damage_time, window, regions, encoding, options, exclude_region=exclude_region, get_best_encoding=get_best_encoding)
     523        def send_nonvideo(regions=regions, encoding=coding, exclude_region=None, get_best_encoding=self.get_best_nonvideo_encoding, flush_offset=0):
     524            WindowSource.do_send_delayed_regions(self, damage_time, window, regions, encoding, options, exclude_region=exclude_region, get_best_encoding=get_best_encoding, flush_offset=flush_offset)
    524525
    525526        if self.is_tray:
    526527            sublog("BUG? video for tray - don't use video region!")
     
    574575            return send_nonvideo(encoding=None)
    575576
    576577        #found the video region:
    577         #send this using the video encoder:
    578         video_options = options.copy()
    579         video_options["av-sync"] = True
    580         self.process_damage_region(damage_time, window, actual_vr.x, actual_vr.y, actual_vr.width, actual_vr.height, coding, video_options, 0)
    581 
    582         #now substract this region from the rest:
     578        #send it with to flush at the end
     579        #substract this region from the rest:
    583580        trimmed = []
    584581        for r in regions:
    585582            trimmed += r.substract_rect(actual_vr)
    586583        if len(trimmed)==0:
    587584            sublog("send_delayed_regions: nothing left after removing video region %s", actual_vr)
    588             return
    589         sublog("send_delayed_regions: substracted %s from %s gives us %s", actual_vr, regions, trimmed)
     585        else:
     586            sublog("send_delayed_regions: substracted %s from %s gives us %s", actual_vr, regions, trimmed)
     587            #decide if we want to send the rest now or delay some more:
     588            event_count = max(0, self.statistics.damage_events_count - self.video_subregion.set_at)
     589            #only delay once the video encoder has dealt with a few frames:
     590            if event_count>100:
     591                elapsed = int(1000.0*(time.time()-damage_time)) + self.video_subregion.non_waited
     592                if elapsed>=self.video_subregion.non_max_wait:
     593                    #send now, reset delay:
     594                    sublog("send_delayed_regions: non video regions have waited %sms already, sending", elapsed)
     595                    self.video_subregion.non_waited = 0
     596                else:
     597                    #delay further: just create new delayed region:
     598                    sublog("send_delayed_regions: delaying non video regions some more")
     599                    self._damage_delayed = time.time(), window, trimmed, coding, options or {}
     600                    delay = self.video_subregion.non_max_wait-elapsed
     601                    self.expire_timer = self.timeout_add(int(delay), self.expire_delayed_region, delay)
     602                    trimmed = None
     603            if trimmed:
     604                send_nonvideo(regions=trimmed, encoding=None, exclude_region=actual_vr, flush_offset=1)
    590605
    591         #decide if we want to send the rest now or delay some more:
    592         event_count = max(0, self.statistics.damage_events_count - self.video_subregion.set_at)
    593         #only delay once the video encoder has dealt with a few frames:
    594         if event_count>100:
    595             elapsed = int(1000.0*(time.time()-damage_time)) + self.video_subregion.non_waited
    596             if elapsed>=self.video_subregion.non_max_wait:
    597                 #send now, reset delay:
    598                 sublog("send_delayed_regions: non video regions have waited %sms already, sending", elapsed)
    599                 self.video_subregion.non_waited = 0
    600             else:
    601                 #delay further: just create new delayed region:
    602                 sublog("send_delayed_regions: delaying non video regions some more")
    603                 self._damage_delayed = time.time(), window, trimmed, coding, options or {}
    604                 delay = self.video_subregion.non_max_wait-elapsed
    605                 self.expire_timer = self.timeout_add(int(delay), self.expire_delayed_region, delay)
    606                 return
    607         send_nonvideo(regions=trimmed, encoding=None, exclude_region=actual_vr)
     606        #now send this using the video encoder and flush=0
     607        video_options = options.copy()
     608        video_options["av-sync"] = True
     609        self.process_damage_region(damage_time, window, actual_vr.x, actual_vr.y, actual_vr.width, actual_vr.height, coding, video_options, flush=0)
    608610
    609611
    610612    def process_damage_region(self, damage_time, window, x, y, w, h, coding, options, flush=None):