Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/codecs/codec_constants.py : 61%
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.
7import weakref
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 )
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 )
37#those are currently so useless that we don't want the user to select them by mistake
38PROBLEMATIC_ENCODINGS = ()
41#value: how much smaller the output is
42LOSSY_PIXEL_FORMATS = {
43 "NV12" : 2,
44 "YUV420P" : 2,
45 "YUV422P" : 1.5,
46 }
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)
66RGB_FORMATS = (
67 "XRGB",
68 "BGRX",
69 "ARGB",
70 "BGRA",
71 "RGB",
72 "BGR",
73 "r210",
74 )
77class TransientCodecException(Exception):
78 pass
80class CodecStateException(Exception):
81 pass
84class _codec_spec:
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
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"]
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
142 def get_instance_count(self) -> int:
143 return len(self.instances)
145 def to_dict(self) -> dict:
146 d = {}
147 for k in self._exported_fields:
148 d[k] = getattr(self, k)
149 return d
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
166class video_spec(_codec_spec):
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"]
177 def __repr__(self):
178 return "%s(%s to %s)" % (self.codec_type, self.input_colorspace, self.encoding)
181class csc_spec(_codec_spec):
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"]
189 def __repr__(self):
190 return "%s(%s to %s)" % (self.codec_type, self.input_colorspace, self.output_colorspace)
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)
206if __name__ == "__main__":
207 main()