Skip to content

Commit

Permalink
#800: allow us to switch to "video" + "b-frames" at runtime without r…
Browse files Browse the repository at this point in the history
…e-creating the encoder (implemented for x264)

git-svn-id: https://xpra.org/svn/Xpra/trunk@13775 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Sep 17, 2016
1 parent 62b8d53 commit 0cf3bf8
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 21 deletions.
39 changes: 24 additions & 15 deletions src/xpra/codecs/enc_x264/encoder.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -799,33 +808,33 @@ cdef class Encoder:
self.tune = self.get_tune()
x264_param_default_preset(&param, get_preset_names()[new_preset], self.tune)
#ensure quality remains what it was:
set_f_rf(&param, get_x264_quality(self.quality, self.profile))
self.tune_param(&param)
#apply it:
x264_param_apply_profile(&param, self.profile)
if x264_encoder_reconfig(self.context, &param)!=0:
raise Exception("x264_encoder_reconfig failed for speed=%s" % pct)
self.do_reconfig_tune(&param)
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, &param)
self.do_reconfig_tune(&param)

cdef do_reconfig_tune(self, x264_param_t *param):
assert self.context!=NULL, "context is closed!"
#adjust quality:
set_f_rf(&param, get_x264_quality(self.quality, self.profile))
self.tune_param(&param)
set_f_rf(param, get_x264_quality(self.quality, self.profile))
self.tune_param(param)
#apply it:
if x264_encoder_reconfig(self.context, &param)!=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):
Expand Down
18 changes: 12 additions & 6 deletions src/xpra/server/window/window_video_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 0cf3bf8

Please sign in to comment.