Skip to content

Commit

Permalink
#1957: pass bandwidth limit to video encoders
Browse files Browse the repository at this point in the history
git-svn-id: https://xpra.org/svn/Xpra/trunk@20399 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Sep 12, 2018
1 parent 09fae18 commit e498e12
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 10 deletions.
61 changes: 53 additions & 8 deletions src/xpra/codecs/enc_x264/encoder.pyx
Expand Up @@ -67,6 +67,10 @@ cdef extern from "x264.h":
int X264_CSP_BGRA
int X264_CSP_RGB

int X264_RC_CQP
int X264_RC_CRF
int X264_RC_ABR

int X264_B_ADAPT_NONE
int X264_B_ADAPT_FAST
int X264_B_ADAPT_TRELLIS
Expand Down Expand Up @@ -288,6 +292,12 @@ ADAPT_TYPES = {
X264_B_ADAPT_TRELLIS : "TRELLIS",
}

RC_TYPES = {
X264_RC_CQP : "CQP",
X264_RC_CRF : "CRF",
X264_RC_ABR : "ABR",
}

SLICE_TYPES = {
X264_TYPE_AUTO : "auto",
X264_TYPE_IDR : "IDR",
Expand Down Expand Up @@ -473,6 +483,7 @@ cdef class Encoder:
cdef int b_frames
cdef int delayed_frames
cdef int export_nals
cdef unsigned long bandwidth_limit
cdef unsigned long long bytes_in
cdef unsigned long long bytes_out
cdef object last_frame_times
Expand Down Expand Up @@ -507,6 +518,7 @@ cdef class Encoder:
self.last_frame_times = deque(maxlen=200)
self.time = 0
self.first_frame_timestamp = 0
self.bandwidth_limit = options.intget("bandwidth-limit", 0)
self.profile = self._get_profile(options, self.src_format)
self.export_nals = options.intget("h264.export-nals", 0)
if self.profile is not None and self.profile not in cs_info[2]:
Expand Down Expand Up @@ -562,6 +574,16 @@ cdef class Encoder:
param.b_open_gop = 1 #allow open gop
#param.b_opencl = self.opencl
param.i_bframe = self.b_frames
self.bandwidth_limit = 2*1000*1000
if self.bandwidth_limit>0 and self.bandwidth_limit<=5*1000*1000:
#CBR mode:
param.rc.i_rc_method = X264_RC_ABR
param.rc.i_bitrate = self.bandwidth_limit//1024
param.rc.i_vbv_max_bitrate = 2*self.bandwidth_limit//1024
param.rc.i_vbv_buffer_size = self.bandwidth_limit//1024
param.rc.f_vbv_buffer_init = 1
else:
param.rc.i_rc_method = X264_RC_CRF
param.rc.i_lookahead = min(param.rc.i_lookahead, self.b_frames-1)
param.b_vfr_input = 0
if not self.b_frames:
Expand Down Expand Up @@ -643,6 +665,7 @@ cdef class Encoder:
"version" : get_version(),
"frame-types" : self.frame_types,
"delayed" : self.delayed_frames,
"bandwidth-limit" : self.bandwidth_limit,
})
cdef x264_param_t param
x264_encoder_parameters(self.context, &param)
Expand Down Expand Up @@ -679,15 +702,9 @@ cdef class Encoder:

cdef get_param_info(self, x264_param_t *param):
return {
"me" : {
"type" : ME_TYPES.get(param.analyse.i_me_method, param.analyse.i_me_method),
"me-range" : param.analyse.i_me_range,
"mv-range" : param.analyse.i_mv_range,
"weighted-pred" : param.analyse.i_weighted_pred,
},
"me" : self.get_analyse_info(param),
"rc" : self.get_rc_info(param),
"vfr-input" : bool(param.b_vfr_input),
"lookahead" : param.rc.i_lookahead,
"mb-tree" : bool(param.rc.b_mb_tree),
"bframe-adaptive" : ADAPT_TYPES.get(param.i_bframe_adaptive, param.i_bframe_adaptive),
"open-gop" : bool(param.b_open_gop),
"bluray-compat" : bool(param.b_bluray_compat),
Expand All @@ -700,6 +717,34 @@ cdef class Encoder:
"sliced-threads" : bool(param.b_sliced_threads),
}

cdef get_analyse_info(self, x264_param_t *param):
return {
"type" : ME_TYPES.get(param.analyse.i_me_method, param.analyse.i_me_method),
"me-range" : param.analyse.i_me_range,
"mv-range" : param.analyse.i_mv_range,
"mv-range-thread" : param.analyse.i_mv_range_thread,
"subpel_refine" : param.analyse.i_subpel_refine,
"weighted-pred" : param.analyse.i_weighted_pred,
}

cdef get_rc_info(self, x264_param_t *param):
return {
"rc-method" : RC_TYPES.get(param.rc.i_rc_method, param.rc.i_rc_method),
"qp_constant" : param.rc.i_qp_constant,
"qp_min" : param.rc.i_qp_min,
"qp_max" : param.rc.i_qp_max,
"qp_step" : param.rc.i_qp_step,
"bitrate" : param.rc.i_bitrate,
"vbv_max_bitrate" : param.rc.i_vbv_max_bitrate,
"vbv_buffer_size" : param.rc.i_vbv_buffer_size,
"vbv_buffer_init" : param.rc.f_vbv_buffer_init,
"vbv_max_bitrate" : param.rc.i_vbv_max_bitrate,

"mb-tree" : bool(param.rc.b_mb_tree),
"lookahead" : param.rc.i_lookahead,
}


def __repr__(self):
if self.src_format is None:
return "x264_encoder(uninitialized)"
Expand Down
15 changes: 13 additions & 2 deletions src/xpra/codecs/vpx/encoder.pyx
Expand Up @@ -344,6 +344,7 @@ cdef class Encoder:
cdef int width
cdef int height
cdef int max_threads
cdef unsigned long bandwidth_limit
cdef double initial_bitrate_per_pixel
cdef object encoding
cdef object src_format
Expand All @@ -370,6 +371,7 @@ cdef class Encoder:
self.height = height
self.speed = speed
self.quality = quality
self.bandwidth_limit = options.get("bandwidth-limit", 0)
self.lossless = 0
self.frames = 0
self.last_frame_times = deque(maxlen=200)
Expand Down Expand Up @@ -461,8 +463,12 @@ cdef class Encoder:
cdef update_cfg(self):
self.cfg.rc_undershoot_pct = 100
self.cfg.rc_overshoot_pct = 100
self.cfg.rc_target_bitrate = max(16, min(15000, int(self.width * self.height * self.initial_bitrate_per_pixel)))
log("update_cfg() bitrate(%i,%i,%.3f)=%i", self.width, self.height, self.initial_bitrate_per_pixel, self.cfg.rc_target_bitrate)
bitrate_kbps = int(self.width * self.height * self.initial_bitrate_per_pixel)
if self.bandwidth_limit>0:
#vpx bitrate values are in Kbps:
bitrate_kbps = min(self.bandwidth_limit//1024, bitrate_kbps)
self.cfg.rc_target_bitrate = max(16, min(15000, bitrate_kbps))
log("update_cfg() bitrate(%i,%i,%.3f,%i)=%iKbps", self.width, self.height, self.initial_bitrate_per_pixel, self.bandwidth_limit, bitrate_kbps)
self.cfg.g_threads = self.max_threads
self.cfg.rc_min_quantizer = MAX(0, MIN(63, int((80-self.quality) * 0.63)))
self.cfg.rc_max_quantizer = MAX(self.cfg.rc_min_quantizer, MIN(63, int((100-self.quality) * 0.63)))
Expand All @@ -483,6 +489,7 @@ cdef class Encoder:
"encoding" : self.encoding,
"src_format": self.src_format,
"max_threads": self.max_threads,
"bandwidth-limit" : self.bandwidth_limit,
})
#calculate fps:
cdef unsigned int f = 0
Expand Down Expand Up @@ -564,6 +571,10 @@ cdef class Encoder:
assert object_as_buffer(pixels[i], <const void**> &pic_buf, &pic_buf_len)==0
pic_in[i] = pic_buf
strides[i] = istrides[i]
cdef unsigned long bandwidth_limit = options.get("bandwidth-limit", self.bandwidth_limit)
if bandwidth_limit!=self.bandwidth_limit:
self.bandwidth_limit = bandwidth_limit
self.update_cfg()
if speed>=0:
self.set_encoding_speed(speed)
if quality>=0:
Expand Down
4 changes: 4 additions & 0 deletions src/xpra/server/window/window_video_source.py
Expand Up @@ -1565,6 +1565,10 @@ def setup_pipeline_option(self, width, height, src_format,
def get_video_encoder_options(self, encoding, width, height):
#tweaks for "real" video:
opts = {}
if not self._fixed_quality and not self._fixed_speed and self._fixed_min_quality<50:
#only allow bandwidth to drive video encoders
#when we don't have strict quality or speed requirements:
opts["bandwidth-limit"] = self.bandwidth_limit
if self.matches_video_subregion(width, height) and self.subregion_is_video() and (monotonic_time()-self.last_scroll_time)>5:
opts.update({
"content-type" : "video",
Expand Down

0 comments on commit e498e12

Please sign in to comment.