1# -*- coding: utf-8 -*- 2# This file is part of Xpra. 3# Copyright (C) 2015-2020 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 7#pylint: disable=line-too-long 8 9import binascii 10 11from xpra.util import csv, typedict, roundup 12from xpra.log import Logger 13log = Logger("encoding") 14 15#Warning: many systems will fail above 8k because of memory constraints 16# encoders can allocate many times more memory to hold the frames.. 17TEST_LIMIT_W, TEST_LIMIT_H = 8192, 8192 18 19 20#this test data was generated using a 24x16 blank image as input 21TEST_COMPRESSED_DATA = { 22 "h264": { 23 "YUV420P" : binascii.unhexlify("000000016764000aacb317cbc2000003000200000300651e244cd00000000168e970312c8b0000010605ffff56dc45e9bde6d948b7962cd820d923eeef78323634202d20636f726520313432202d20482e3236342f4d5045472d342041564320636f646563202d20436f70796c65667420323030332d32303134202d20687474703a2f2f7777772e766964656f6c616e2e6f72672f783236342e68746d6c202d206f7074696f6e733a2063616261633d31207265663d35206465626c6f636b3d313a303a3020616e616c7973653d3078333a3078313133206d653d756d68207375626d653d38207073793d31207073795f72643d312e30303a302e3030206d697865645f7265663d31206d655f72616e67653d3136206368726f6d615f6d653d31207472656c6c69733d31203878386463743d312063716d3d3020646561647a6f6e653d32312c313120666173745f70736b69703d31206368726f6d615f71705f6f66667365743d2d3220746872656164733d31206c6f6f6b61686561645f746872656164733d3120736c696365645f746872656164733d30206e723d3020646563696d6174653d3120696e7465726c616365643d3020626c757261795f636f6d7061743d3020636f6e73747261696e65645f696e7472613d3020626672616d65733d3020776569676874703d32206b6579696e743d393939393939206b6579696e745f6d696e3d353030303030207363656e656375743d343020696e7472615f726566726573683d302072633d637266206d62747265653d30206372663d33382e322071636f6d703d302e36302071706d696e3d302071706d61783d3639207170737465703d342069705f726174696f3d312e34302061713d313a312e3030008000000165888404bffe841fc0a667f891ea1728763fecb5e1"), 24 "YUV422P" : binascii.unhexlify("00000001677a000abcb317cbc2000003000200000300651e244cd00000000168e970312c8b0000010605ffff56dc45e9bde6d948b7962cd820d923eeef78323634202d20636f726520313432202d20482e3236342f4d5045472d342041564320636f646563202d20436f70796c65667420323030332d32303134202d20687474703a2f2f7777772e766964656f6c616e2e6f72672f783236342e68746d6c202d206f7074696f6e733a2063616261633d31207265663d35206465626c6f636b3d313a303a3020616e616c7973653d3078333a3078313133206d653d756d68207375626d653d38207073793d31207073795f72643d312e30303a302e3030206d697865645f7265663d31206d655f72616e67653d3136206368726f6d615f6d653d31207472656c6c69733d31203878386463743d312063716d3d3020646561647a6f6e653d32312c313120666173745f70736b69703d31206368726f6d615f71705f6f66667365743d2d3220746872656164733d31206c6f6f6b61686561645f746872656164733d3120736c696365645f746872656164733d30206e723d3020646563696d6174653d3120696e7465726c616365643d3020626c757261795f636f6d7061743d3020636f6e73747261696e65645f696e7472613d3020626672616d65733d3020776569676874703d32206b6579696e743d393939393939206b6579696e745f6d696e3d353030303030207363656e656375743d343020696e7472615f726566726573683d302072633d637266206d62747265653d30206372663d33382e322071636f6d703d302e36302071706d696e3d302071706d61783d3639207170737465703d342069705f726174696f3d312e34302061713d313a312e3030008000000165888404bffe841fc0a667f891ec3d121e72aecb5f"), 25 "YUV444P" : binascii.unhexlify("0000000167f4000a919662f89e1000000300100000030328f12266800000000168e970311121100000010605ffff55dc45e9bde6d948b7962cd820d923eeef78323634202d20636f726520313432202d20482e3236342f4d5045472d342041564320636f646563202d20436f70796c65667420323030332d32303134202d20687474703a2f2f7777772e766964656f6c616e2e6f72672f783236342e68746d6c202d206f7074696f6e733a2063616261633d31207265663d35206465626c6f636b3d313a303a3020616e616c7973653d3078333a3078313133206d653d756d68207375626d653d38207073793d31207073795f72643d312e30303a302e3030206d697865645f7265663d31206d655f72616e67653d3136206368726f6d615f6d653d31207472656c6c69733d31203878386463743d312063716d3d3020646561647a6f6e653d32312c313120666173745f70736b69703d31206368726f6d615f71705f6f66667365743d3420746872656164733d31206c6f6f6b61686561645f746872656164733d3120736c696365645f746872656164733d30206e723d3020646563696d6174653d3120696e7465726c616365643d3020626c757261795f636f6d7061743d3020636f6e73747261696e65645f696e7472613d3020626672616d65733d3020776569676874703d32206b6579696e743d393939393939206b6579696e745f6d696e3d353030303030207363656e656375743d343020696e7472615f726566726573683d302072633d637266206d62747265653d30206372663d33382e322071636f6d703d302e36302071706d696e3d302071706d61783d3639207170737465703d342069705f726174696f3d312e34302061713d313a312e3030008000000165888404bffeeb1fc0a667f75e658f9a9fccb1f341ffff"), 26 }, 27 "vp8" : { 28 "YUV420P" : binascii.unhexlify("1003009d012a1800100000070885858899848800281013ad501fc01fd01050122780feffbb029ffffa2546bd18c06f7ffe8951fffe8951af46301bdfffa22a00"), 29 }, 30 "vp9" : { 31 "YUV420P" : binascii.unhexlify("8249834200017000f60038241c18000000200000047ffffffba9da00059fffffff753b413bffffffeea7680000"), 32 "YUV444P" : binascii.unhexlify("a249834200002e001ec007048383000000040000223fffffeea76800c7ffffffeea7680677ffffff753b40081000"), 33 }, 34} 35 36TEST_PICTURES = { 37 "png" : ( 38 "89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000002849444154785eedd08100000000c3a0f9531fe4855061c0800103060c183060c0800103060cbc0f0c102000013337932a0000000049454e44ae426082", 39 "89504e470d0a1a0a0000000d4948445200000020000000200802000000fc18eda30000002549444154785eedd03101000000c2a0f54fed610d884061c0800103060c183060c080810f0c0c20000174754ae90000000049454e44ae426082", 40 ), 41 "png/L" : ( 42 "89504e470d0a1a0a0000000d4948445200000020000000200800000000561125280000000274524e5300ff5b9122b50000002049444154785e63fccf801f3011906718550009a1d170180d07e4bc323cd20300a33d013f95f841e70000000049454e44ae426082", 43 "89504e470d0a1a0a0000000d4948445200000020000000200800000000561125280000001549444154785e63601805a321301a02a321803d0400042000017854be5c0000000049454e44ae426082", 44 ), 45 "png/P" : ( 46 "89504e470d0a1a0a0000000d494844520000002000000020080300000044a48ac600000300504c5445000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b330f4880000010074524e53ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0053f707250000001c49444154785e63f84f00308c2a0087c068384012c268388ca87000003f68fc2e077ed1070000000049454e44ae426082", 47 "89504e470d0a1a0a0000000d494844520000002000000020080300000044a48ac600000300504c5445000000000000000000000000000000000000000000000000000000000000000000330000660000990000cc0000ff0000003300333300663300993300cc3300ff3300006600336600666600996600cc6600ff6600009900339900669900999900cc9900ff990000cc0033cc0066cc0099cc00cccc00ffcc0000ff0033ff0066ff0099ff00ccff00ffff00000033330033660033990033cc0033ff0033003333333333663333993333cc3333ff3333006633336633666633996633cc6633ff6633009933339933669933999933cc9933ff993300cc3333cc3366cc3399cc33cccc33ffcc3300ff3333ff3366ff3399ff33ccff33ffff33000066330066660066990066cc0066ff0066003366333366663366993366cc3366ff3366006666336666666666996666cc6666ff6666009966339966669966999966cc9966ff996600cc6633cc6666cc6699cc66cccc66ffcc6600ff6633ff6666ff6699ff66ccff66ffff66000099330099660099990099cc0099ff0099003399333399663399993399cc3399ff3399006699336699666699996699cc6699ff6699009999339999669999999999cc9999ff999900cc9933cc9966cc9999cc99cccc99ffcc9900ff9933ff9966ff9999ff99ccff99ffff990000cc3300cc6600cc9900cccc00ccff00cc0033cc3333cc6633cc9933cccc33ccff33cc0066cc3366cc6666cc9966cccc66ccff66cc0099cc3399cc6699cc9999cccc99ccff99cc00cccc33cccc66cccc99ccccccccccffcccc00ffcc33ffcc66ffcc99ffccccffccffffcc0000ff3300ff6600ff9900ffcc00ffff00ff0033ff3333ff6633ff9933ffcc33ffff33ff0066ff3366ff6666ff9966ffcc66ffff66ff0099ff3399ff6699ff9999ffcc99ffff99ff00ccff33ccff66ccff99ccffccccffffccff00ffff33ffff66ffff99ffffccffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023faca40000001549444154785e63601805a321301a02a321803d0400042000017854be5c0000000049454e44ae426082", 48 ), 49 "jpeg" : ( 50 "ffd8ffe000104a46494600010100000100010000ffdb004300100b0c0e0c0a100e0d0e1211101318281a181616183123251d283a333d3c3933383740485c4e404457453738506d51575f626768673e4d71797064785c656763ffdb0043011112121815182f1a1a2f634238426363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363ffc00011080020002003012200021101031101ffc4001500010100000000000000000000000000000007ffc40014100100000000000000000000000000000000ffc40014010100000000000000000000000000000000ffc40014110100000000000000000000000000000000ffda000c03010002110311003f009f800000000000ffd9", 51 "ffd8ffe000104a46494600010100000100010000ffdb004300100b0c0e0c0a100e0d0e1211101318281a181616183123251d283a333d3c3933383740485c4e404457453738506d51575f626768673e4d71797064785c656763ffdb0043011112121815182f1a1a2f634238426363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363ffc00011080020002003012200021101031101ffc4001500010100000000000000000000000000000007ffc40014100100000000000000000000000000000000ffc40014010100000000000000000000000000000000ffc40014110100000000000000000000000000000000ffda000c03010002110311003f009f800000000000ffd9", 52 ), 53 "webp" : ( 54 "524946465c00000057454250565038580a000000100000001f00001f0000414c50480f00000001071011110012c2ffef7a44ff530f005650382026000000d002009d012a200020003ed162aa4fa825a3a2280801001a096900003da3a000fef39d800000", 55 "524946465c00000057454250565038580a000000100000001f00001f0000414c50480f00000001071011110012c2ffef7a44ff530f005650382026000000d002009d012a200020003ed162aa4fa825a3a2280801001a096900003da3a000fef39d800000", 56 ), 57 } 58 59 60def makebuf(size, b=0x20): 61 return (chr(b).encode())*size 62 63 64def make_test_image(pixel_format, w, h): 65 from xpra.codecs.image_wrapper import ImageWrapper 66 from xpra.codecs.codec_constants import get_subsampling_divs 67 #import time 68 #start = monotonic() 69 if pixel_format.startswith("YUV") or pixel_format.startswith("GBRP") or pixel_format=="NV12": 70 divs = get_subsampling_divs(pixel_format) 71 try: 72 depth = int(pixel_format.split("P")[1]) #ie: YUV444P10 -> 10 73 except (IndexError, ValueError): 74 depth = 8 75 Bpp = roundup(depth, 8)//8 76 nplanes = len(divs) 77 ydiv = divs[0] #always (1, 1) 78 y = makebuf(w//ydiv[0]*h//ydiv[1]*Bpp) 79 udiv = divs[1] 80 u = makebuf(w//udiv[0]*h//udiv[1]*Bpp) 81 planes = [y, u] 82 strides = [w//ydiv[0]*Bpp, w//udiv[0]*Bpp] 83 if nplanes==3: 84 vdiv = divs[2] 85 v = makebuf(w//vdiv[0]*h//vdiv[1]*Bpp) 86 planes.append(v) 87 strides.append(w//vdiv[0]*Bpp) 88 image = ImageWrapper(0, 0, w, h, planes, pixel_format, 32, strides, planes=nplanes, thread_safe=True) 89 #l = len(y)+len(u)+len(v) 90 elif pixel_format in ("RGB", "BGR", "RGBX", "BGRX", "XRGB", "BGRA", "RGBA", "r210", "BGR48"): 91 if pixel_format=="BGR48": 92 stride = w*6 93 else: 94 stride = w*len(pixel_format) 95 rgb_data = makebuf(stride*h) 96 image = ImageWrapper(0, 0, w, h, rgb_data, pixel_format, 32, stride, planes=ImageWrapper.PACKED, thread_safe=True) 97 #l = len(rgb_data) 98 else: 99 raise Exception("don't know how to create a %s image" % pixel_format) 100 #log("make_test_image%30s took %3ims for %6iMBytes", 101 # (pixel_format, w, h), 1000*(monotonic()-start), l//1024//1024) 102 return image 103 104 105def testdecoder(decoder_module, full): 106 codecs = list(decoder_module.get_encodings()) 107 for encoding in tuple(codecs): 108 try: 109 testdecoding(decoder_module, encoding, full) 110 except Exception as e: 111 log("%s: %s decoding failed", decoder_module.get_type(), encoding, exc_info=True) 112 log.warn("%s: %s decoding failed: %s", decoder_module.get_type(), encoding, e) 113 del e 114 codecs.remove(encoding) 115 if not codecs: 116 log.error("%s: all the codecs have failed! (%s)", 117 decoder_module.get_type(), csv(decoder_module.get_encodings())) 118 return tuple(codecs) 119 120def testdecoding(decoder_module, encoding, full): 121 W = 24 122 H = 16 123 test_data_set = TEST_COMPRESSED_DATA.get(encoding) 124 if not test_data_set: 125 log("%s: no test data for %s", decoder_module.get_type(), encoding) 126 return 127 for cs in decoder_module.get_input_colorspaces(encoding): 128 e = decoder_module.Decoder() 129 try: 130 e.init_context(encoding, W, H, cs) 131 test_data = test_data_set.get(cs) 132 if test_data: 133 log("%s: testing %s / %s with %s bytes of data", 134 decoder_module.get_type(), encoding, cs, len(test_data)) 135 image = e.decompress_image(test_data) 136 assert image is not None, "failed to decode test data for encoding '%s' with colorspace '%s'" % (encoding, cs) 137 assert image.get_width()==W, "expected image of width %s but got %s" % (W, image.get_width()) 138 assert image.get_height()==H, "expected image of height %s but got %s" % (H, image.get_height()) 139 if full: 140 log("%s: testing %s / %s with junk data", decoder_module.get_type(), encoding, cs) 141 #test failures: 142 try: 143 image = e.decompress_image(b"junk") 144 except Exception: 145 image = None 146 if image is not None: 147 raise Exception("decoding junk with %s should have failed, got %s instead" % (decoder_module.get_type(), image)) 148 finally: 149 e.clean() 150 151 152def testencoder(encoder_module, full): 153 codecs = list(encoder_module.get_encodings()) 154 for encoding in tuple(codecs): 155 try: 156 testencoding(encoder_module, encoding, full) 157 except Exception as e: 158 log("%s: %s encoding failed", encoder_module.get_type(), encoding, exc_info=True) 159 log.warn("%s: %s encoding failed: %s", encoder_module.get_type(), encoding, e) 160 del e 161 codecs.remove(encoding) 162 if not codecs: 163 log.error("%s: all the codecs have failed! (%s)", 164 encoder_module.get_type(), csv(encoder_module.get_encodings())) 165 return tuple(codecs) 166 167def testencoding(encoder_module, encoding, full): 168 #test a bit bigger so we exercise more code: 169 W = 64 170 H = 32 171 do_testencoding(encoder_module, encoding, W, H, full) 172 173def get_encoder_max_sizes(encoder_module): 174 w, h = TEST_LIMIT_W, TEST_LIMIT_H 175 for encoding in encoder_module.get_encodings(): 176 ew, eh = get_encoder_max_size(encoder_module, encoding) 177 w = min(w, ew) 178 h = min(h, eh) 179 return w, h 180 181def get_encoder_max_size(encoder_module, encoding, limit_w=TEST_LIMIT_W, limit_h=TEST_LIMIT_H): 182 #probe to find the max dimensions: 183 #(it may go higher but we don't care as windows can't) 184 def einfo(): 185 return "%s %s %s" % (encoder_module.get_type(), encoding, encoder_module.get_version()) 186 log("get_encoder_max_size%s", (encoder_module, encoding, limit_w, limit_h)) 187 maxw = w = 512 188 while w<=limit_w: 189 try: 190 do_testencoding(encoder_module, encoding, w, 128) 191 maxw = w 192 w *= 2 193 except Exception as e: 194 log("%s is limited to max width=%i for %s:", einfo(), maxw, encoding) 195 log(" %s", e) 196 del e 197 break 198 log("%s max width=%i", einfo(), maxw) 199 maxh = h = 512 200 while h<=limit_h: 201 try: 202 do_testencoding(encoder_module, encoding, 128, h) 203 maxh = h 204 h *= 2 205 except Exception as e: 206 log("%s is limited to max height=%i for %s:", einfo(), maxh, encoding) 207 log(" %s", e) 208 del e 209 break 210 log("%s max height=%i", einfo(), maxh) 211 #now try combining width and height 212 #as there might be a lower limit based on the total number of pixels: 213 MAX_WIDTH, MAX_HEIGHT = maxw, maxh 214 #start at half: 215 v = max(512, min(maxw, maxh)//2) 216 while v<max(limit_w, limit_h): 217 for tw, th in ((v, v), (v*2, v)): 218 if tw>limit_w or th>limit_h: 219 continue 220 try: 221 w = min(maxw, tw) 222 h = min(maxh, th) 223 do_testencoding(encoder_module, encoding, w, h) 224 log("%s can handle %ix%i for %s", einfo(), w, h, encoding) 225 MAX_WIDTH, MAX_HEIGHT = w, h 226 except Exception as e: 227 log("%s is limited to %ix%i for %s", einfo(), MAX_WIDTH, MAX_HEIGHT, encoding) 228 log(" %s", e) 229 del e 230 break 231 v *= 2 232 log("%s max dimensions for %s: %ix%i", einfo(), encoding, MAX_WIDTH, MAX_HEIGHT) 233 return MAX_WIDTH, MAX_HEIGHT 234 235 236def do_testencoding(encoder_module, encoding, W, H, full=False, limit_w=TEST_LIMIT_W, limit_h=TEST_LIMIT_H): 237 for cs_in in encoder_module.get_input_colorspaces(encoding): 238 for cs_out in encoder_module.get_output_colorspaces(encoding, cs_in): 239 e = encoder_module.Encoder() 240 try: 241 options = typedict({ 242 "b-frames" : True, 243 "dst-formats" : [cs_out], 244 "quality" : 50, 245 "speed" : 50, 246 }) 247 e.init_context(encoding, W, H, cs_in, options) 248 for i in range(2): 249 image = make_test_image(cs_in, W, H) 250 v = e.compress_image(image) 251 if v is None: 252 raise Exception("%s compression failed" % encoding) 253 data, meta = v 254 if not data: 255 delayed = meta.get("delayed", 0) 256 assert delayed>0, "data is empty and there are no delayed frames!" 257 if i>0: 258 #now we should get one: 259 data, meta = e.flush(delayed) 260 del image 261 assert data is not None, "None data for %s using %s encoding with %s / %s" % (encoder_module.get_type(), encoding, cs_in, cs_out) 262 assert data, "no compressed data for %s using %s encoding with %s / %s" % (encoder_module.get_type(), encoding, cs_in, cs_out) 263 assert meta is not None, "missing metadata for %s using %s encoding with %s / %s" % (encoder_module.get_type(), encoding, cs_in, cs_out) 264 log("%s: %s / %s / %s passed", encoder_module, encoding, cs_in, cs_out) 265 #print("test_encoder: %s.compress_image(%s)=%s" % (encoder_module.get_type(), image, (data, meta))) 266 #print("compressed data with %s: %s bytes (%s), metadata: %s" % (encoder_module.get_type(), len(data), type(data), meta)) 267 #print("compressed data(%s, %s)=%s" % (encoding, cs_in, binascii.hexlify(data))) 268 if full: 269 wrong_formats = [x for x in ("YUV420P", "YUV444P", "BGRX", "r210") if x!=cs_in] 270 #log("wrong formats (not %s): %s", cs_in, wrong_formats) 271 if wrong_formats: 272 wrong_format = wrong_formats[0] 273 try: 274 image = make_test_image(wrong_format, W, H) 275 out = e.compress_image(None, image, options=options) 276 except Exception: 277 out = None 278 assert out is None, "encoder %s should have failed using %s encoding with %s instead of %s / %s" % (encoder_module.get_type(), encoding, wrong_format, cs_in, cs_out) 279 for w,h in ((W//2, H//2), (W*2, H//2), (W//2, H**2)): 280 if w>limit_w or h>limit_h: 281 continue 282 try: 283 image = make_test_image(cs_in, w, h) 284 out = e.compress_image(None, image, options=options) 285 except Exception: 286 out = None 287 assert out is None, "encoder %s, info=%s should have failed using %s encoding with invalid size %ix%i vs %ix%i" % (encoder_module.get_type(), e.get_info(), encoding, w, h, W, H) 288 finally: 289 e.clean() 290 291 292def testcsc(csc_module, scaling=True, full=False, test_cs_in=None, test_cs_out=None): 293 W = 48 294 H = 32 295 log("test_csc(%s, %s, %s, %s)", csc_module, full, test_cs_in, test_cs_out) 296 do_testcsc(csc_module, W, H, W, H, full, test_cs_in, test_cs_out) 297 if full and scaling: 298 do_testcsc(csc_module, W, H, W*2, H*2, full, test_cs_in, test_cs_out) 299 do_testcsc(csc_module, W, H, W//2, H//2, full, test_cs_in, test_cs_out) 300 301def get_csc_max_size(colorspace_converter, test_cs_in=None, test_cs_out=None, limit_w=TEST_LIMIT_W, limit_h=TEST_LIMIT_H): 302 #probe to find the max dimensions: 303 #(it may go higher but we don't care as windows can't) 304 MAX_WIDTH, MAX_HEIGHT = 512, 512 305 #as there might be a lower limit based on the total number of pixels: 306 v = 512 307 while v<=min(limit_w, limit_h): 308 for tw, th in ((v, v), (v*2, v)): 309 if tw>limit_w or th>limit_h: 310 break 311 try: 312 do_testcsc(colorspace_converter, tw, th, tw, th, False, test_cs_in, test_cs_out, limit_w, limit_h) 313 log("%s can handle %ix%i", colorspace_converter, tw, th) 314 MAX_WIDTH, MAX_HEIGHT = tw, th 315 except Exception: 316 log("%s is limited to %ix%i for %s", 317 colorspace_converter, MAX_WIDTH, MAX_HEIGHT, (test_cs_in, test_cs_out), exc_info=True) 318 break 319 v *= 2 320 log("%s max dimensions: %ix%i", colorspace_converter, MAX_WIDTH, MAX_HEIGHT) 321 return MAX_WIDTH, MAX_HEIGHT 322 323 324def do_testcsc(csc_module, iw, ih, ow, oh, full=False, test_cs_in=None, test_cs_out=None, limit_w=TEST_LIMIT_W, limit_h=TEST_LIMIT_H): 325 log("do_testcsc%s", (csc_module, iw, ih, ow, oh, full, test_cs_in, test_cs_out, TEST_LIMIT_W, TEST_LIMIT_H)) 326 cs_in_list = test_cs_in 327 if cs_in_list is None: 328 cs_in_list = csc_module.get_input_colorspaces() 329 for cs_in in cs_in_list: 330 cs_out_list = test_cs_out 331 if cs_out_list is None: 332 cs_out_list = csc_module.get_output_colorspaces(cs_in) 333 for cs_out in cs_out_list: 334 log("%s: testing %s / %s", csc_module.get_type(), cs_in, cs_out) 335 e = csc_module.ColorspaceConverter() 336 try: 337 e.init_context(iw, ih, cs_in, ow, oh, cs_out) 338 image = make_test_image(cs_in, iw, ih) 339 out = e.convert_image(image) 340 #print("convert_image(%s)=%s" % (image, out)) 341 assert out.get_width()==ow, "expected image of width %s but got %s" % (ow, out.get_width()) 342 assert out.get_height()==oh, "expected image of height %s but got %s" % (oh, out.get_height()) 343 assert out.get_pixel_format()==cs_out, "expected pixel format %s but got %s" % (cs_out, out.get_pixel_format()) 344 if full: 345 for w,h in ((iw*2, ih//2), (iw//2, ih**2)): 346 if w>limit_w or h>limit_h: 347 continue 348 try: 349 image = make_test_image(cs_in, w, h) 350 out = e.convert_image(image) 351 except Exception: 352 out = None 353 if out is not None: 354 raise Exception("converting an image of a smaller size with %s should have failed, got %s instead" % (csc_module.get_type(), out)) 355 finally: 356 e.clean() 357