diff --git a/src/xpra/codecs/enc_x264/encoder.pyx b/src/xpra/codecs/enc_x264/encoder.pyx index bc213eb629..e2fa38210c 100644 --- a/src/xpra/codecs/enc_x264/encoder.pyx +++ b/src/xpra/codecs/enc_x264/encoder.pyx @@ -680,6 +680,15 @@ cdef class Encoder: if self.first_frame_timestamp==0: self.first_frame_timestamp = image.get_timestamp() + source = options.get("source", "unknown") + b_frames = options.get("b-frames", 0) + if source!=self.source or self.b_frames!=b_frames: + #some options have changed: + log("compress_image: reconfig b-frames=%s, source=%s (from %s, %s)", b_frames, source, self.b_frames, self.source) + self.source = source + self.b_frames = b_frames + self.reconfig_tune() + pixels = image.get_pixels() istrides = image.get_rowstride() assert pixels, "failed to get pixels from %s" % image @@ -799,33 +808,33 @@ cdef class Encoder: self.tune = self.get_tune() x264_param_default_preset(¶m, get_preset_names()[new_preset], self.tune) #ensure quality remains what it was: - set_f_rf(¶m, get_x264_quality(self.quality, self.profile)) - self.tune_param(¶m) - #apply it: - x264_param_apply_profile(¶m, self.profile) - if x264_encoder_reconfig(self.context, ¶m)!=0: - raise Exception("x264_encoder_reconfig failed for speed=%s" % pct) + self.do_reconfig_tune(¶m) self.preset = new_preset def set_encoding_quality(self, int pct): assert pct>=0 and pct<=100, "invalid percentage: %s" % pct - assert self.context!=NULL, "context is closed!" if self.quality==pct: return if abs(self.quality - pct)<=4 and pct!=100 and self.quality!=100: #not enough of a change to bother (but always change to/from 100) return - cdef x264_param_t param #@DuplicatedSignature - #only f_rf_constant is changing - #retrieve current parameters: + #adjust quality: + self.quality = pct + self.reconfig_tune() + + def reconfig_tune(self): + cdef x264_param_t param x264_encoder_parameters(self.context, ¶m) + self.do_reconfig_tune(¶m) + + cdef do_reconfig_tune(self, x264_param_t *param): + assert self.context!=NULL, "context is closed!" #adjust quality: - set_f_rf(¶m, get_x264_quality(self.quality, self.profile)) - self.tune_param(¶m) + set_f_rf(param, get_x264_quality(self.quality, self.profile)) + self.tune_param(param) #apply it: - if x264_encoder_reconfig(self.context, ¶m)!=0: - raise Exception("x264_encoder_reconfig failed for quality=%s" % pct) - self.quality = pct + if x264_encoder_reconfig(self.context, param)!=0: + raise Exception("x264_encoder_reconfig failed") def selftest(full=False): diff --git a/src/xpra/server/window/window_video_source.py b/src/xpra/server/window/window_video_source.py index 5ea657c63d..d7b9744ee3 100644 --- a/src/xpra/server/window/window_video_source.py +++ b/src/xpra/server/window/window_video_source.py @@ -1322,12 +1322,7 @@ def setup_pipeline_option(self, width, height, src_format, dst_formats = self.full_csc_modes.get(encoder_spec.encoding) ve = encoder_spec.make_instance() options = self.encoding_options.copy() - #tweaks for "real" video: - if self.matches_video_subregion(width, height) and self.subregion_is_video(): - options["source"] = "video" - if encoder_spec.encoding in self.supports_video_b_frames: - #could take av-sync into account here to choose the number of b-frames: - options["b-frames"] = 1 + options.update(self.get_video_encoder_options(encoder_spec.encoding, width, height)) ve.init_context(enc_width, enc_height, enc_in_format, dst_formats, encoder_spec.encoding, quality, speed, encoder_scaling, options) #record new actual limits: self.actual_scaling = scaling @@ -1345,6 +1340,16 @@ def setup_pipeline_option(self, width, height, src_format, scalinglog("setup_pipeline: scaling=%s, encoder_scaling=%s", scaling, encoder_scaling) return True + def get_video_encoder_options(self, encoding, width, height): + #tweaks for "real" video: + if self.matches_video_subregion(width, height) and self.subregion_is_video(): + return { + "source" : "video", + #could take av-sync into account here to choose the number of b-frames: + "b-frames" : int(encoding in self.supports_video_b_frames), + } + return {} + def encode_scrolling(self, image, distances, old_csums, csums, options): tstart = time.time() @@ -1539,6 +1544,7 @@ def video_fallback(): start = time.time() quality = max(0, min(100, self._current_quality)) speed = max(0, min(100, self._current_speed)) + options.update(self.get_video_encoder_options(ve.get_encoding(), width, height)) ret = ve.compress_image(csc_image, quality, speed, options) if ret is None: videolog.error("video_encode: ouch, %s compression failed", encoding)