1cc1dc7a3Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0 2cc1dc7a3Sopenharmony_ci# ----------------------------------------------------------------------------- 3cc1dc7a3Sopenharmony_ci# Copyright 2019-2023 Arm Limited 4cc1dc7a3Sopenharmony_ci# 5cc1dc7a3Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6cc1dc7a3Sopenharmony_ci# use this file except in compliance with the License. You may obtain a copy 7cc1dc7a3Sopenharmony_ci# of the License at: 8cc1dc7a3Sopenharmony_ci# 9cc1dc7a3Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 10cc1dc7a3Sopenharmony_ci# 11cc1dc7a3Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software 12cc1dc7a3Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13cc1dc7a3Sopenharmony_ci# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14cc1dc7a3Sopenharmony_ci# License for the specific language governing permissions and limitations 15cc1dc7a3Sopenharmony_ci# under the License. 16cc1dc7a3Sopenharmony_ci# ----------------------------------------------------------------------------- 17cc1dc7a3Sopenharmony_ci""" 18cc1dc7a3Sopenharmony_ciThese classes provide an abstraction around the astcenc command line tool, 19cc1dc7a3Sopenharmony_ciallowing the rest of the image test suite to ignore changes in the command line 20cc1dc7a3Sopenharmony_ciinterface. 21cc1dc7a3Sopenharmony_ci""" 22cc1dc7a3Sopenharmony_ci 23cc1dc7a3Sopenharmony_ciimport os 24cc1dc7a3Sopenharmony_ciimport re 25cc1dc7a3Sopenharmony_ciimport subprocess as sp 26cc1dc7a3Sopenharmony_ciimport sys 27cc1dc7a3Sopenharmony_ci 28cc1dc7a3Sopenharmony_ci 29cc1dc7a3Sopenharmony_ciclass EncoderBase(): 30cc1dc7a3Sopenharmony_ci """ 31cc1dc7a3Sopenharmony_ci This class is a Python wrapper for the `astcenc` binary, providing an 32cc1dc7a3Sopenharmony_ci abstract means to set command line options and parse key results. 33cc1dc7a3Sopenharmony_ci 34cc1dc7a3Sopenharmony_ci This is an abstract base class providing some generic helper functionality 35cc1dc7a3Sopenharmony_ci used by concrete instantiations of subclasses. 36cc1dc7a3Sopenharmony_ci 37cc1dc7a3Sopenharmony_ci Attributes: 38cc1dc7a3Sopenharmony_ci binary: The encoder binary path. 39cc1dc7a3Sopenharmony_ci variant: The encoder SIMD variant being tested. 40cc1dc7a3Sopenharmony_ci name: The encoder name to use in reports. 41cc1dc7a3Sopenharmony_ci VERSION: The encoder version or branch. 42cc1dc7a3Sopenharmony_ci SWITCHES: Dict of switch replacements for different color formats. 43cc1dc7a3Sopenharmony_ci OUTPUTS: Dict of output file extensions for different color formats. 44cc1dc7a3Sopenharmony_ci """ 45cc1dc7a3Sopenharmony_ci 46cc1dc7a3Sopenharmony_ci VERSION = None 47cc1dc7a3Sopenharmony_ci SWITCHES = None 48cc1dc7a3Sopenharmony_ci OUTPUTS = None 49cc1dc7a3Sopenharmony_ci 50cc1dc7a3Sopenharmony_ci def __init__(self, name, variant, binary): 51cc1dc7a3Sopenharmony_ci """ 52cc1dc7a3Sopenharmony_ci Create a new encoder instance. 53cc1dc7a3Sopenharmony_ci 54cc1dc7a3Sopenharmony_ci Args: 55cc1dc7a3Sopenharmony_ci name (str): The name of the encoder. 56cc1dc7a3Sopenharmony_ci variant (str): The SIMD variant of the encoder. 57cc1dc7a3Sopenharmony_ci binary (str): The path to the binary on the file system. 58cc1dc7a3Sopenharmony_ci """ 59cc1dc7a3Sopenharmony_ci self.name = name 60cc1dc7a3Sopenharmony_ci self.variant = variant 61cc1dc7a3Sopenharmony_ci self.binary = binary 62cc1dc7a3Sopenharmony_ci 63cc1dc7a3Sopenharmony_ci def build_cli(self, image, blockSize="6x6", preset="-thorough", 64cc1dc7a3Sopenharmony_ci keepOutput=True, threads=None): 65cc1dc7a3Sopenharmony_ci """ 66cc1dc7a3Sopenharmony_ci Build the command line needed for the given test. 67cc1dc7a3Sopenharmony_ci 68cc1dc7a3Sopenharmony_ci Args: 69cc1dc7a3Sopenharmony_ci image (TestImage): The test image to compress. 70cc1dc7a3Sopenharmony_ci blockSize (str): The block size to use. 71cc1dc7a3Sopenharmony_ci preset (str): The quality-performance preset to use. 72cc1dc7a3Sopenharmony_ci keepOutput (bool): Should the test preserve output images? This is 73cc1dc7a3Sopenharmony_ci only a hint and discarding output may be ignored if the encoder 74cc1dc7a3Sopenharmony_ci version used can't do it natively. 75cc1dc7a3Sopenharmony_ci threads (int or None): The thread count to use. 76cc1dc7a3Sopenharmony_ci 77cc1dc7a3Sopenharmony_ci Returns: 78cc1dc7a3Sopenharmony_ci list(str): A list of command line arguments. 79cc1dc7a3Sopenharmony_ci """ 80cc1dc7a3Sopenharmony_ci # pylint: disable=unused-argument,no-self-use,redundant-returns-doc 81cc1dc7a3Sopenharmony_ci assert False, "Missing subclass implementation" 82cc1dc7a3Sopenharmony_ci 83cc1dc7a3Sopenharmony_ci def execute(self, command): 84cc1dc7a3Sopenharmony_ci """ 85cc1dc7a3Sopenharmony_ci Run a subprocess with the specified command. 86cc1dc7a3Sopenharmony_ci 87cc1dc7a3Sopenharmony_ci Args: 88cc1dc7a3Sopenharmony_ci command (list(str)): The list of command line arguments. 89cc1dc7a3Sopenharmony_ci 90cc1dc7a3Sopenharmony_ci Returns: 91cc1dc7a3Sopenharmony_ci list(str): The output log (stdout) split into lines. 92cc1dc7a3Sopenharmony_ci """ 93cc1dc7a3Sopenharmony_ci # pylint: disable=no-self-use 94cc1dc7a3Sopenharmony_ci try: 95cc1dc7a3Sopenharmony_ci result = sp.run(command, stdout=sp.PIPE, stderr=sp.PIPE, 96cc1dc7a3Sopenharmony_ci check=True, universal_newlines=True) 97cc1dc7a3Sopenharmony_ci except (OSError, sp.CalledProcessError): 98cc1dc7a3Sopenharmony_ci print("ERROR: Test run failed") 99cc1dc7a3Sopenharmony_ci print(" + %s" % " ".join(command)) 100cc1dc7a3Sopenharmony_ci qcommand = ["\"%s\"" % x for x in command] 101cc1dc7a3Sopenharmony_ci print(" + %s" % ", ".join(qcommand)) 102cc1dc7a3Sopenharmony_ci sys.exit(1) 103cc1dc7a3Sopenharmony_ci 104cc1dc7a3Sopenharmony_ci return result.stdout.splitlines() 105cc1dc7a3Sopenharmony_ci 106cc1dc7a3Sopenharmony_ci def parse_output(self, image, output): 107cc1dc7a3Sopenharmony_ci """ 108cc1dc7a3Sopenharmony_ci Parse the log output for PSNR and performance metrics. 109cc1dc7a3Sopenharmony_ci 110cc1dc7a3Sopenharmony_ci Args: 111cc1dc7a3Sopenharmony_ci image (TestImage): The test image to compress. 112cc1dc7a3Sopenharmony_ci output (list(str)): The output log from the compression process. 113cc1dc7a3Sopenharmony_ci 114cc1dc7a3Sopenharmony_ci Returns: 115cc1dc7a3Sopenharmony_ci tuple(float, float, float): PSNR in dB, TotalTime in seconds, and 116cc1dc7a3Sopenharmony_ci CodingTime in seconds. 117cc1dc7a3Sopenharmony_ci """ 118cc1dc7a3Sopenharmony_ci # Regex pattern for image quality 119cc1dc7a3Sopenharmony_ci patternPSNR = re.compile(self.get_psnr_pattern(image)) 120cc1dc7a3Sopenharmony_ci patternTTime = re.compile(self.get_total_time_pattern()) 121cc1dc7a3Sopenharmony_ci patternCTime = re.compile(self.get_coding_time_pattern()) 122cc1dc7a3Sopenharmony_ci patternCRate = re.compile(self.get_coding_rate_pattern()) 123cc1dc7a3Sopenharmony_ci 124cc1dc7a3Sopenharmony_ci # Extract results from the log 125cc1dc7a3Sopenharmony_ci runPSNR = None 126cc1dc7a3Sopenharmony_ci runTTime = None 127cc1dc7a3Sopenharmony_ci runCTime = None 128cc1dc7a3Sopenharmony_ci runCRate = None 129cc1dc7a3Sopenharmony_ci 130cc1dc7a3Sopenharmony_ci for line in output: 131cc1dc7a3Sopenharmony_ci match = patternPSNR.match(line) 132cc1dc7a3Sopenharmony_ci if match: 133cc1dc7a3Sopenharmony_ci runPSNR = float(match.group(1)) 134cc1dc7a3Sopenharmony_ci 135cc1dc7a3Sopenharmony_ci match = patternTTime.match(line) 136cc1dc7a3Sopenharmony_ci if match: 137cc1dc7a3Sopenharmony_ci runTTime = float(match.group(1)) 138cc1dc7a3Sopenharmony_ci 139cc1dc7a3Sopenharmony_ci match = patternCTime.match(line) 140cc1dc7a3Sopenharmony_ci if match: 141cc1dc7a3Sopenharmony_ci runCTime = float(match.group(1)) 142cc1dc7a3Sopenharmony_ci 143cc1dc7a3Sopenharmony_ci match = patternCRate.match(line) 144cc1dc7a3Sopenharmony_ci if match: 145cc1dc7a3Sopenharmony_ci runCRate = float(match.group(1)) 146cc1dc7a3Sopenharmony_ci 147cc1dc7a3Sopenharmony_ci stdout = "\n".join(output) 148cc1dc7a3Sopenharmony_ci assert runPSNR is not None, "No coding PSNR found %s" % stdout 149cc1dc7a3Sopenharmony_ci assert runTTime is not None, "No total time found %s" % stdout 150cc1dc7a3Sopenharmony_ci assert runCTime is not None, "No coding time found %s" % stdout 151cc1dc7a3Sopenharmony_ci assert runCRate is not None, "No coding rate found %s" % stdout 152cc1dc7a3Sopenharmony_ci return (runPSNR, runTTime, runCTime, runCRate) 153cc1dc7a3Sopenharmony_ci 154cc1dc7a3Sopenharmony_ci def get_psnr_pattern(self, image): 155cc1dc7a3Sopenharmony_ci """ 156cc1dc7a3Sopenharmony_ci Get the regex pattern to match the image quality metric. 157cc1dc7a3Sopenharmony_ci 158cc1dc7a3Sopenharmony_ci Note, while this function is called PSNR for some images we may choose 159cc1dc7a3Sopenharmony_ci to match another metric (e.g. mPSNR for HDR images). 160cc1dc7a3Sopenharmony_ci 161cc1dc7a3Sopenharmony_ci Args: 162cc1dc7a3Sopenharmony_ci image (TestImage): The test image we are compressing. 163cc1dc7a3Sopenharmony_ci 164cc1dc7a3Sopenharmony_ci Returns: 165cc1dc7a3Sopenharmony_ci str: The string for a regex pattern. 166cc1dc7a3Sopenharmony_ci """ 167cc1dc7a3Sopenharmony_ci # pylint: disable=unused-argument,no-self-use,redundant-returns-doc 168cc1dc7a3Sopenharmony_ci assert False, "Missing subclass implementation" 169cc1dc7a3Sopenharmony_ci 170cc1dc7a3Sopenharmony_ci def get_total_time_pattern(self): 171cc1dc7a3Sopenharmony_ci """ 172cc1dc7a3Sopenharmony_ci Get the regex pattern to match the total compression time. 173cc1dc7a3Sopenharmony_ci 174cc1dc7a3Sopenharmony_ci Returns: 175cc1dc7a3Sopenharmony_ci str: The string for a regex pattern. 176cc1dc7a3Sopenharmony_ci """ 177cc1dc7a3Sopenharmony_ci # pylint: disable=unused-argument,no-self-use,redundant-returns-doc 178cc1dc7a3Sopenharmony_ci assert False, "Missing subclass implementation" 179cc1dc7a3Sopenharmony_ci 180cc1dc7a3Sopenharmony_ci def get_coding_time_pattern(self): 181cc1dc7a3Sopenharmony_ci """ 182cc1dc7a3Sopenharmony_ci Get the regex pattern to match the coding compression time. 183cc1dc7a3Sopenharmony_ci 184cc1dc7a3Sopenharmony_ci Returns: 185cc1dc7a3Sopenharmony_ci str: The string for a regex pattern. 186cc1dc7a3Sopenharmony_ci """ 187cc1dc7a3Sopenharmony_ci # pylint: disable=unused-argument,no-self-use,redundant-returns-doc 188cc1dc7a3Sopenharmony_ci assert False, "Missing subclass implementation" 189cc1dc7a3Sopenharmony_ci 190cc1dc7a3Sopenharmony_ci def run_test(self, image, blockSize, preset, testRuns, keepOutput=True, 191cc1dc7a3Sopenharmony_ci threads=None): 192cc1dc7a3Sopenharmony_ci """ 193cc1dc7a3Sopenharmony_ci Run the test N times. 194cc1dc7a3Sopenharmony_ci 195cc1dc7a3Sopenharmony_ci Args: 196cc1dc7a3Sopenharmony_ci image (TestImage): The test image to compress. 197cc1dc7a3Sopenharmony_ci blockSize (str): The block size to use. 198cc1dc7a3Sopenharmony_ci preset (str): The quality-performance preset to use. 199cc1dc7a3Sopenharmony_ci testRuns (int): The number of test runs. 200cc1dc7a3Sopenharmony_ci keepOutput (bool): Should the test preserve output images? This is 201cc1dc7a3Sopenharmony_ci only a hint and discarding output may be ignored if the encoder 202cc1dc7a3Sopenharmony_ci version used can't do it natively. 203cc1dc7a3Sopenharmony_ci threads (int or None): The thread count to use. 204cc1dc7a3Sopenharmony_ci 205cc1dc7a3Sopenharmony_ci Returns: 206cc1dc7a3Sopenharmony_ci tuple(float, float, float, float): Returns the best results from 207cc1dc7a3Sopenharmony_ci the N test runs, as PSNR (dB), total time (seconds), coding time 208cc1dc7a3Sopenharmony_ci (seconds), and coding rate (M pixels/s). 209cc1dc7a3Sopenharmony_ci """ 210cc1dc7a3Sopenharmony_ci # pylint: disable=assignment-from-no-return 211cc1dc7a3Sopenharmony_ci command = self.build_cli(image, blockSize, preset, keepOutput, threads) 212cc1dc7a3Sopenharmony_ci 213cc1dc7a3Sopenharmony_ci # Execute test runs 214cc1dc7a3Sopenharmony_ci bestPSNR = 0 215cc1dc7a3Sopenharmony_ci bestTTime = sys.float_info.max 216cc1dc7a3Sopenharmony_ci bestCTime = sys.float_info.max 217cc1dc7a3Sopenharmony_ci bestCRate = 0 218cc1dc7a3Sopenharmony_ci 219cc1dc7a3Sopenharmony_ci for _ in range(0, testRuns): 220cc1dc7a3Sopenharmony_ci output = self.execute(command) 221cc1dc7a3Sopenharmony_ci result = self.parse_output(image, output) 222cc1dc7a3Sopenharmony_ci 223cc1dc7a3Sopenharmony_ci # Keep the best results (highest PSNR, lowest times, highest rate) 224cc1dc7a3Sopenharmony_ci bestPSNR = max(bestPSNR, result[0]) 225cc1dc7a3Sopenharmony_ci bestTTime = min(bestTTime, result[1]) 226cc1dc7a3Sopenharmony_ci bestCTime = min(bestCTime, result[2]) 227cc1dc7a3Sopenharmony_ci bestCRate = max(bestCRate, result[3]) 228cc1dc7a3Sopenharmony_ci 229cc1dc7a3Sopenharmony_ci return (bestPSNR, bestTTime, bestCTime, bestCRate) 230cc1dc7a3Sopenharmony_ci 231cc1dc7a3Sopenharmony_ci 232cc1dc7a3Sopenharmony_ciclass Encoder2x(EncoderBase): 233cc1dc7a3Sopenharmony_ci """ 234cc1dc7a3Sopenharmony_ci This class wraps the latest `astcenc` 2.x series binaries from main branch. 235cc1dc7a3Sopenharmony_ci """ 236cc1dc7a3Sopenharmony_ci VERSION = "main" 237cc1dc7a3Sopenharmony_ci 238cc1dc7a3Sopenharmony_ci SWITCHES = { 239cc1dc7a3Sopenharmony_ci "ldr": "-tl", 240cc1dc7a3Sopenharmony_ci "ldrs": "-ts", 241cc1dc7a3Sopenharmony_ci "hdr": "-th", 242cc1dc7a3Sopenharmony_ci "hdra": "-tH" 243cc1dc7a3Sopenharmony_ci } 244cc1dc7a3Sopenharmony_ci 245cc1dc7a3Sopenharmony_ci OUTPUTS = { 246cc1dc7a3Sopenharmony_ci "ldr": ".png", 247cc1dc7a3Sopenharmony_ci "ldrs": ".png", 248cc1dc7a3Sopenharmony_ci "hdr": ".exr", 249cc1dc7a3Sopenharmony_ci "hdra": ".exr" 250cc1dc7a3Sopenharmony_ci } 251cc1dc7a3Sopenharmony_ci 252cc1dc7a3Sopenharmony_ci def __init__(self, variant, binary=None): 253cc1dc7a3Sopenharmony_ci name = "astcenc-%s-%s" % (variant, self.VERSION) 254cc1dc7a3Sopenharmony_ci 255cc1dc7a3Sopenharmony_ci if binary is None: 256cc1dc7a3Sopenharmony_ci if variant != "universal": 257cc1dc7a3Sopenharmony_ci binary = f"./bin/astcenc-{variant}" 258cc1dc7a3Sopenharmony_ci else: 259cc1dc7a3Sopenharmony_ci binary = "./bin/astcenc" 260cc1dc7a3Sopenharmony_ci 261cc1dc7a3Sopenharmony_ci if os.name == 'nt': 262cc1dc7a3Sopenharmony_ci binary = f"{binary}.exe" 263cc1dc7a3Sopenharmony_ci 264cc1dc7a3Sopenharmony_ci super().__init__(name, variant, binary) 265cc1dc7a3Sopenharmony_ci 266cc1dc7a3Sopenharmony_ci def build_cli(self, image, blockSize="6x6", preset="-thorough", 267cc1dc7a3Sopenharmony_ci keepOutput=True, threads=None): 268cc1dc7a3Sopenharmony_ci opmode = self.SWITCHES[image.colorProfile] 269cc1dc7a3Sopenharmony_ci srcPath = image.filePath 270cc1dc7a3Sopenharmony_ci 271cc1dc7a3Sopenharmony_ci if keepOutput: 272cc1dc7a3Sopenharmony_ci dstPath = image.outFilePath + self.OUTPUTS[image.colorProfile] 273cc1dc7a3Sopenharmony_ci dstDir = os.path.dirname(dstPath) 274cc1dc7a3Sopenharmony_ci dstFile = os.path.basename(dstPath) 275cc1dc7a3Sopenharmony_ci dstPath = os.path.join(dstDir, self.name, preset[1:], blockSize, dstFile) 276cc1dc7a3Sopenharmony_ci 277cc1dc7a3Sopenharmony_ci dstDir = os.path.dirname(dstPath) 278cc1dc7a3Sopenharmony_ci os.makedirs(dstDir, exist_ok=True) 279cc1dc7a3Sopenharmony_ci elif sys.platform == "win32": 280cc1dc7a3Sopenharmony_ci dstPath = "nul" 281cc1dc7a3Sopenharmony_ci else: 282cc1dc7a3Sopenharmony_ci dstPath = "/dev/null" 283cc1dc7a3Sopenharmony_ci 284cc1dc7a3Sopenharmony_ci command = [ 285cc1dc7a3Sopenharmony_ci self.binary, opmode, srcPath, dstPath, 286cc1dc7a3Sopenharmony_ci blockSize, preset, "-silent" 287cc1dc7a3Sopenharmony_ci ] 288cc1dc7a3Sopenharmony_ci 289cc1dc7a3Sopenharmony_ci if image.colorFormat == "xy": 290cc1dc7a3Sopenharmony_ci command.append("-normal") 291cc1dc7a3Sopenharmony_ci 292cc1dc7a3Sopenharmony_ci if image.isAlphaScaled: 293cc1dc7a3Sopenharmony_ci command.append("-a") 294cc1dc7a3Sopenharmony_ci command.append("1") 295cc1dc7a3Sopenharmony_ci 296cc1dc7a3Sopenharmony_ci if threads is not None: 297cc1dc7a3Sopenharmony_ci command.append("-j") 298cc1dc7a3Sopenharmony_ci command.append("%u" % threads) 299cc1dc7a3Sopenharmony_ci 300cc1dc7a3Sopenharmony_ci return command 301cc1dc7a3Sopenharmony_ci 302cc1dc7a3Sopenharmony_ci def get_psnr_pattern(self, image): 303cc1dc7a3Sopenharmony_ci if image.colorProfile != "hdr": 304cc1dc7a3Sopenharmony_ci if image.colorFormat != "rgba": 305cc1dc7a3Sopenharmony_ci patternPSNR = r"\s*PSNR \(LDR-RGB\):\s*([0-9.]*) dB" 306cc1dc7a3Sopenharmony_ci else: 307cc1dc7a3Sopenharmony_ci patternPSNR = r"\s*PSNR \(LDR-RGBA\):\s*([0-9.]*) dB" 308cc1dc7a3Sopenharmony_ci else: 309cc1dc7a3Sopenharmony_ci patternPSNR = r"\s*mPSNR \(RGB\)(?: \[.*?\] )?:\s*([0-9.]*) dB.*" 310cc1dc7a3Sopenharmony_ci return patternPSNR 311cc1dc7a3Sopenharmony_ci 312cc1dc7a3Sopenharmony_ci def get_total_time_pattern(self): 313cc1dc7a3Sopenharmony_ci return r"\s*Total time:\s*([0-9.]*) s" 314cc1dc7a3Sopenharmony_ci 315cc1dc7a3Sopenharmony_ci def get_coding_time_pattern(self): 316cc1dc7a3Sopenharmony_ci return r"\s*Coding time:\s*([0-9.]*) s" 317cc1dc7a3Sopenharmony_ci 318cc1dc7a3Sopenharmony_ci def get_coding_rate_pattern(self): 319cc1dc7a3Sopenharmony_ci return r"\s*Coding rate:\s*([0-9.]*) MT/s" 320cc1dc7a3Sopenharmony_ci 321cc1dc7a3Sopenharmony_ci 322cc1dc7a3Sopenharmony_ciclass Encoder2xRel(Encoder2x): 323cc1dc7a3Sopenharmony_ci """ 324cc1dc7a3Sopenharmony_ci This class wraps a released 2.x series binary. 325cc1dc7a3Sopenharmony_ci """ 326cc1dc7a3Sopenharmony_ci def __init__(self, version, variant): 327cc1dc7a3Sopenharmony_ci 328cc1dc7a3Sopenharmony_ci self.VERSION = version 329cc1dc7a3Sopenharmony_ci 330cc1dc7a3Sopenharmony_ci if variant != "universal": 331cc1dc7a3Sopenharmony_ci binary = f"./Binaries/{version}/astcenc-{variant}" 332cc1dc7a3Sopenharmony_ci else: 333cc1dc7a3Sopenharmony_ci binary = f"./Binaries/{version}/astcenc" 334cc1dc7a3Sopenharmony_ci 335cc1dc7a3Sopenharmony_ci if os.name == 'nt': 336cc1dc7a3Sopenharmony_ci binary = f"{binary}.exe" 337cc1dc7a3Sopenharmony_ci 338cc1dc7a3Sopenharmony_ci super().__init__(variant, binary) 339cc1dc7a3Sopenharmony_ci 340cc1dc7a3Sopenharmony_ci 341cc1dc7a3Sopenharmony_ciclass Encoder1_7(EncoderBase): 342cc1dc7a3Sopenharmony_ci """ 343cc1dc7a3Sopenharmony_ci This class wraps the 1.7 series binaries. 344cc1dc7a3Sopenharmony_ci """ 345cc1dc7a3Sopenharmony_ci VERSION = "1.7" 346cc1dc7a3Sopenharmony_ci 347cc1dc7a3Sopenharmony_ci SWITCHES = { 348cc1dc7a3Sopenharmony_ci "ldr": "-tl", 349cc1dc7a3Sopenharmony_ci "ldrs": "-ts", 350cc1dc7a3Sopenharmony_ci "hdr": "-t" 351cc1dc7a3Sopenharmony_ci } 352cc1dc7a3Sopenharmony_ci 353cc1dc7a3Sopenharmony_ci OUTPUTS = { 354cc1dc7a3Sopenharmony_ci "ldr": ".tga", 355cc1dc7a3Sopenharmony_ci "ldrs": ".tga", 356cc1dc7a3Sopenharmony_ci "hdr": ".htga" 357cc1dc7a3Sopenharmony_ci } 358cc1dc7a3Sopenharmony_ci 359cc1dc7a3Sopenharmony_ci def __init__(self): 360cc1dc7a3Sopenharmony_ci name = "astcenc-%s" % self.VERSION 361cc1dc7a3Sopenharmony_ci if os.name == 'nt': 362cc1dc7a3Sopenharmony_ci binary = "./Binaries/1.7/astcenc.exe" 363cc1dc7a3Sopenharmony_ci else: 364cc1dc7a3Sopenharmony_ci binary = "./Binaries/1.7/astcenc" 365cc1dc7a3Sopenharmony_ci 366cc1dc7a3Sopenharmony_ci super().__init__(name, None, binary) 367cc1dc7a3Sopenharmony_ci 368cc1dc7a3Sopenharmony_ci def build_cli(self, image, blockSize="6x6", preset="-thorough", 369cc1dc7a3Sopenharmony_ci keepOutput=True, threads=None): 370cc1dc7a3Sopenharmony_ci 371cc1dc7a3Sopenharmony_ci if preset == "-fastest": 372cc1dc7a3Sopenharmony_ci preset = "-fast" 373cc1dc7a3Sopenharmony_ci 374cc1dc7a3Sopenharmony_ci opmode = self.SWITCHES[image.colorProfile] 375cc1dc7a3Sopenharmony_ci srcPath = image.filePath 376cc1dc7a3Sopenharmony_ci 377cc1dc7a3Sopenharmony_ci dstPath = image.outFilePath + self.OUTPUTS[image.colorProfile] 378cc1dc7a3Sopenharmony_ci dstDir = os.path.dirname(dstPath) 379cc1dc7a3Sopenharmony_ci dstFile = os.path.basename(dstPath) 380cc1dc7a3Sopenharmony_ci dstPath = os.path.join(dstDir, self.name, preset[1:], blockSize, dstFile) 381cc1dc7a3Sopenharmony_ci 382cc1dc7a3Sopenharmony_ci dstDir = os.path.dirname(dstPath) 383cc1dc7a3Sopenharmony_ci os.makedirs(dstDir, exist_ok=True) 384cc1dc7a3Sopenharmony_ci 385cc1dc7a3Sopenharmony_ci command = [ 386cc1dc7a3Sopenharmony_ci self.binary, opmode, srcPath, dstPath, 387cc1dc7a3Sopenharmony_ci blockSize, preset, "-silentmode", "-time", "-showpsnr" 388cc1dc7a3Sopenharmony_ci ] 389cc1dc7a3Sopenharmony_ci 390cc1dc7a3Sopenharmony_ci if image.colorFormat == "xy": 391cc1dc7a3Sopenharmony_ci command.append("-normal_psnr") 392cc1dc7a3Sopenharmony_ci 393cc1dc7a3Sopenharmony_ci if image.colorProfile == "hdr": 394cc1dc7a3Sopenharmony_ci command.append("-hdr") 395cc1dc7a3Sopenharmony_ci 396cc1dc7a3Sopenharmony_ci if image.isAlphaScaled: 397cc1dc7a3Sopenharmony_ci command.append("-alphablend") 398cc1dc7a3Sopenharmony_ci 399cc1dc7a3Sopenharmony_ci if threads is not None: 400cc1dc7a3Sopenharmony_ci command.append("-j") 401cc1dc7a3Sopenharmony_ci command.append("%u" % threads) 402cc1dc7a3Sopenharmony_ci 403cc1dc7a3Sopenharmony_ci return command 404cc1dc7a3Sopenharmony_ci 405cc1dc7a3Sopenharmony_ci def get_psnr_pattern(self, image): 406cc1dc7a3Sopenharmony_ci if image.colorProfile != "hdr": 407cc1dc7a3Sopenharmony_ci if image.colorFormat != "rgba": 408cc1dc7a3Sopenharmony_ci patternPSNR = r"PSNR \(LDR-RGB\):\s*([0-9.]*) dB" 409cc1dc7a3Sopenharmony_ci else: 410cc1dc7a3Sopenharmony_ci patternPSNR = r"PSNR \(LDR-RGBA\):\s*([0-9.]*) dB" 411cc1dc7a3Sopenharmony_ci else: 412cc1dc7a3Sopenharmony_ci patternPSNR = r"mPSNR \(RGB\)(?: \[.*?\] )?:\s*([0-9.]*) dB.*" 413cc1dc7a3Sopenharmony_ci return patternPSNR 414cc1dc7a3Sopenharmony_ci 415cc1dc7a3Sopenharmony_ci def get_total_time_pattern(self): 416cc1dc7a3Sopenharmony_ci # Pattern match on a new pattern for a 2.1 compatible variant 417cc1dc7a3Sopenharmony_ci # return r"Elapsed time:\s*([0-9.]*) seconds.*" 418cc1dc7a3Sopenharmony_ci return r"\s*Total time:\s*([0-9.]*) s" 419cc1dc7a3Sopenharmony_ci 420cc1dc7a3Sopenharmony_ci def get_coding_time_pattern(self): 421cc1dc7a3Sopenharmony_ci # Pattern match on a new pattern for a 2.1 compatible variant 422cc1dc7a3Sopenharmony_ci # return r".* coding time: \s*([0-9.]*) seconds" 423cc1dc7a3Sopenharmony_ci return r"\s*Coding time:\s*([0-9.]*) s" 424cc1dc7a3Sopenharmony_ci 425cc1dc7a3Sopenharmony_ci def get_coding_rate_pattern(self): 426cc1dc7a3Sopenharmony_ci # Pattern match on a new pattern for a 2.1 compatible variant 427cc1dc7a3Sopenharmony_ci return r"\s*Coding rate:\s*([0-9.]*) MT/s" 428