Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# -*- coding: utf-8 -*- 

2# This file is part of Xpra. 

3# Copyright (C) 2012-2019 Antoine Martin <antoine@xpra.org> 

4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

5# later version. See the file COPYING for details. 

6 

7import weakref 

8 

9 

10#note: this is just for defining the order of encodings, 

11#so we have both core encodings (rgb24/rgb32) and regular encodings (rgb) in here: 

12PREFERRED_ENCODING_ORDER = ( 

13 "h264", "vp9", "vp8", "mpeg4", 

14 "mpeg4+mp4", "h264+mp4", "vp8+webm", "vp9+webm", 

15 "png", "png/P", "png/L", "webp", 

16 "rgb", "rgb24", "rgb32", "jpeg", 

17 "h265", "mpeg1", "mpeg2", 

18 "scroll", 

19 "grayscale", 

20 ) 

21#encoding order for edges (usually one pixel high or wide): 

22EDGE_ENCODING_ORDER = ( 

23 "rgb24", "rgb32", 

24 "png", "webp", 

25 "png/P", "png/L", "rgb", "jpeg", 

26 ) 

27 

28HELP_ORDER = ( 

29 "auto", 

30 "grayscale", 

31 "h264", "h265", "vp8", "vp9", "mpeg4", 

32 "png", "png/P", "png/L", "webp", 

33 "rgb", "jpeg", 

34 "scroll", 

35 ) 

36 

37#those are currently so useless that we don't want the user to select them by mistake 

38PROBLEMATIC_ENCODINGS = () 

39 

40 

41#value: how much smaller the output is 

42LOSSY_PIXEL_FORMATS = { 

43 "NV12" : 2, 

44 "YUV420P" : 2, 

45 "YUV422P" : 1.5, 

46 } 

47 

48PIXEL_SUBSAMPLING = { 

49 "NV12" : ((1, 1), (1, 2)), 

50 "YUV420P" : ((1, 1), (2, 2), (2, 2)), 

51 "YUV422P" : ((1, 1), (2, 1), (2, 1)), 

52 "YUV444P" : ((1, 1), (1, 1), (1, 1)), 

53 "GBRP" : ((1, 1), (1, 1), (1, 1)), 

54 "GBRP10" : ((1, 1), (1, 1), (1, 1)), 

55 "YUV444P10" : ((1, 1), (1, 1), (1, 1)), 

56 "YUV444P16" : ((1, 1), (1, 1), (1, 1)), 

57} 

58def get_subsampling_divs(pixel_format): 

59 # Return size dividers for the given pixel format 

60 # (Y_w, Y_h), (U_w, U_h), (V_w, V_h) 

61 if pixel_format not in PIXEL_SUBSAMPLING: 

62 raise Exception("invalid pixel format: %s" % pixel_format) 

63 return PIXEL_SUBSAMPLING.get(pixel_format) 

64 

65 

66RGB_FORMATS = ( 

67 "XRGB", 

68 "BGRX", 

69 "ARGB", 

70 "BGRA", 

71 "RGB", 

72 "BGR", 

73 "r210", 

74 ) 

75 

76 

77class TransientCodecException(Exception): 

78 pass 

79 

80class CodecStateException(Exception): 

81 pass 

82 

83 

84class _codec_spec: 

85 

86 #I can't imagine why someone would have more than this many 

87 #encoders or csc modules active at the same time! 

88 WARN_LIMIT = 25 

89 

90 def __init__(self, codec_class, codec_type="", 

91 quality=50, speed=50, 

92 size_efficiency=50, 

93 setup_cost=50, cpu_cost=100, gpu_cost=0, 

94 min_w=1, min_h=1, max_w=4*1024, max_h=4*1024, 

95 can_scale=False, 

96 score_boost=0, 

97 width_mask=0xFFFF, height_mask=0xFFFF): 

98 self.codec_class = codec_class #ie: xpra.codecs.enc_x264.encoder.Encoder 

99 self.codec_type = codec_type #ie: "nvenc" 

100 self.quality = quality 

101 self.speed = speed 

102 self.size_efficiency = size_efficiency 

103 self.setup_cost = setup_cost 

104 self.cpu_cost = cpu_cost 

105 self.gpu_cost = gpu_cost 

106 self.score_boost = score_boost 

107 self.min_w = min_w 

108 self.min_h = min_h 

109 self.max_w = max_w 

110 self.max_h = max_h 

111 self.width_mask = width_mask 

112 self.height_mask = height_mask 

113 self.can_scale = can_scale 

114 self.max_instances = 0 

115 self._exported_fields = ["codec_class", "codec_type", 

116 "quality", "speed", 

117 "setup_cost", "cpu_cost", "gpu_cost", "score_boost", 

118 "min_w", "min_h", "max_w", "max_h", 

119 "width_mask", "height_mask", 

120 "can_scale", 

121 "max_instances"] 

122 #not exported: 

123 self.instances = weakref.WeakKeyDictionary() 

124 self._all_fields = list(self._exported_fields)+["instances"] 

125 

126 

127 def make_instance(self): 

128 from xpra.log import Logger 

129 log = Logger("encoding") 

130 cur = self.get_instance_count() 

131 if (self.max_instances>0 and cur>=self.max_instances) or cur>=_codec_spec.WARN_LIMIT: 

132 instances = tuple(self.instances.keys()) 

133 log.warn("Warning: already %s active instances of %s: %s", 

134 cur, self.codec_class, instances) 

135 else: 

136 log("make_instance() %s - instance count=%s", self.codec_type, cur) 

137 v = self.codec_class() 

138 self.instances[v] = True 

139 return v 

140 

141 

142 def get_instance_count(self) -> int: 

143 return len(self.instances) 

144 

145 def to_dict(self) -> dict: 

146 d = {} 

147 for k in self._exported_fields: 

148 d[k] = getattr(self, k) 

149 return d 

150 

151 def get_runtime_factor(self) -> float: 

152 #a cost multiplier that some encoder may want to override 

153 #1.0 means no change: 

154 mi = self.max_instances 

155 ic = len(self.instances) 

156 if ic==0 or mi==0: 

157 return 1.0 #no problem 

158 if ic>=mi: 

159 return 0 #not possible 

160 if mi>0 and ic>0: 

161 #squared slope: 50% utilisation -> value=0.75 

162 return max(0, 1.0 - (1.0*ic/mi)**2) 

163 return 1.0 

164 

165 

166class video_spec(_codec_spec): 

167 

168 def __init__(self, encoding, input_colorspace, output_colorspaces, has_lossless_mode, 

169 codec_class, codec_type, **kwargs): 

170 self.encoding = encoding #ie: "h264" 

171 self.input_colorspace = input_colorspace 

172 self.output_colorspaces = output_colorspaces #ie: ["YUV420P" : "YUV420P", ...] 

173 self.has_lossless_mode = has_lossless_mode 

174 super().__init__(codec_class, codec_type, **kwargs) 

175 self._exported_fields += ["encoding", "input_colorspace", "output_colorspaces", "has_lossless_mode"] 

176 

177 def __repr__(self): 

178 return "%s(%s to %s)" % (self.codec_type, self.input_colorspace, self.encoding) 

179 

180 

181class csc_spec(_codec_spec): 

182 

183 def __init__(self, input_colorspace, output_colorspace, codec_class, codec_type, **kwargs): 

184 self.input_colorspace = input_colorspace 

185 self.output_colorspace = output_colorspace 

186 super().__init__(codec_class, codec_type, **kwargs) 

187 self._exported_fields += ["input_colorspace", "output_colorspace"] 

188 

189 def __repr__(self): 

190 return "%s(%s to %s)" % (self.codec_type, self.input_colorspace, self.output_colorspace) 

191 

192 

193def main(): 

194 from xpra.platform import program_context 

195 with program_context("Codec-Constants", "Codec Constants Info"): 

196 import sys 

197 from xpra.log import Logger 

198 log = Logger("encoding") 

199 if "-v" in sys.argv or "--verbose" in sys.argv: 

200 log.enable_debug() 

201 log.info("LOSSY_PIXEL_FORMATS=%s", LOSSY_PIXEL_FORMATS) 

202 log.info("PIXEL_SUBSAMPLING=%s", PIXEL_SUBSAMPLING) 

203 log.info("RGB_FORMATS=%s", RGB_FORMATS) 

204 

205 

206if __name__ == "__main__": 

207 main()