summaryrefslogtreecommitdiff
path: root/utils/tuning/libtuning/generators/raspberrypi_output.py
blob: 47b4905914c8f9fe2132265b52b79e620d9a11b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright 2022 Raspberry Pi Ltd
#
# Generate tuning file in Raspberry Pi's json format
#
# (Copied from ctt_pretty_print_json.py)

from .generator import Generator

import json
from pathlib import Path
import textwrap


class Encoder(json.JSONEncoder):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.indentation_level = 0
        self.hard_break = 120
        self.custom_elems = {
            'table': 16,
            'luminance_lut': 16,
            'ct_curve': 3,
            'ccm': 3,
            'gamma_curve': 2,
            'y_target': 2,
            'prior': 2
        }

    def encode(self, o, node_key=None):
        if isinstance(o, (list, tuple)):
            # Check if we are a flat list of numbers.
            if not any(isinstance(el, (list, tuple, dict)) for el in o):
                s = ', '.join(json.dumps(el) for el in o)
                if node_key in self.custom_elems.keys():
                    # Special case handling to specify number of elements in a row for tables, ccm, etc.
                    self.indentation_level += 1
                    sl = s.split(', ')
                    num = self.custom_elems[node_key]
                    chunk = [self.indent_str + ', '.join(sl[x:x + num]) for x in range(0, len(sl), num)]
                    t = ',\n'.join(chunk)
                    self.indentation_level -= 1
                    output = f'\n{self.indent_str}[\n{t}\n{self.indent_str}]'
                elif len(s) > self.hard_break - len(self.indent_str):
                    # Break a long list with wraps.
                    self.indentation_level += 1
                    t = textwrap.fill(s, self.hard_break, break_long_words=False,
                                      initial_indent=self.indent_str, subsequent_indent=self.indent_str)
                    self.indentation_level -= 1
                    output = f'\n{self.indent_str}[\n{t}\n{self.indent_str}]'
                else:
                    # Smaller lists can remain on a single line.
                    output = f' [ {s} ]'
                return output
            else:
                # Sub-structures in the list case.
                self.indentation_level += 1
                output = [self.indent_str + self.encode(el) for el in o]
                self.indentation_level -= 1
                output = ',\n'.join(output)
                return f' [\n{output}\n{self.indent_str}]'

        elif isinstance(o, dict):
            self.indentation_level += 1
            output = []
            for k, v in o.items():
                if isinstance(v, dict) and len(v) == 0:
                    # Empty config block special case.
                    output.append(self.indent_str + f'{json.dumps(k)}: {{ }}')
                else:
                    # Only linebreak if the next node is a config block.
                    sep = f'\n{self.indent_str}' if isinstance(v, dict) else ''
                    output.append(self.indent_str + f'{json.dumps(k)}:{sep}{self.encode(v, k)}')
            output = ',\n'.join(output)
            self.indentation_level -= 1
            return f'{{\n{output}\n{self.indent_str}}}'

        else:
            return ' ' + json.dumps(o)

    @property
    def indent_str(self) -> str:
        return ' ' * self.indentation_level * self.indent

    def iterencode(self, o, **kwargs):
        return self.encode(o)


class RaspberryPiOutput(Generator):
    def __init__(self):
        super().__init__()

    def _pretty_print(self, in_json: dict) -> str:

        if 'version' not in in_json or \
           'target' not in in_json or \
           'algorithms' not in in_json or \
           in_json['version'] < 2.0:
            raise RuntimeError('Incompatible JSON dictionary has been provided')

        return json.dumps(in_json, cls=Encoder, indent=4, sort_keys=False)

    def write(self, output_file: Path, output_dict: dict, output_order: list):
        # Write json dictionary to file using ctt's version 2 format
        out_json = {
            "version": 2.0,
            'target': 'bcm2835',
            "algorithms": [{f'{module.out_name}': output_dict[module]} for module in output_order]
        }

        with open(output_file, 'w') as f:
            f.write(self._pretty_print(out_json))
: 0.01 } }, { "rpi.agc": { "metering_modes": { "centre-weighted": { "weights": [ 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0 ] }, "spot": { "weights": [ 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] }, "matrix": { "weights": [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ] } }, "exposure_modes": { "normal": { "shutter": [ 100, 10000, 30000, 60000, 120000 ], "gain": [ 1.0, 2.0, 4.0, 6.0, 6.0 ] }, "short": { "shutter": [ 100, 5000, 10000, 20000, 120000 ], "gain": [ 1.0, 2.0, 4.0, 6.0, 6.0 ] } }, "constraint_modes": { "normal": [ { "bound": "LOWER", "q_lo": 0.98, "q_hi": 1.0, "y_target": [ 0, 0.5, 1000, 0.5 ] } ], "highlight": [ { "bound": "LOWER", "q_lo": 0.98, "q_hi": 1.0, "y_target": [ 0, 0.5, 1000, 0.5 ] }, { "bound": "UPPER", "q_lo": 0.98, "q_hi": 1.0, "y_target": [ 0, 0.8, 1000, 0.8 ] } ] }, "y_target": [ 0, 0.16, 1000, 0.165, 10000, 0.17 ] } }, { "rpi.alsc": { "omega": 1.3, "n_iter": 100, "luminance_strength": 0.7 } }, { "rpi.contrast": { "ce_enable": 1, "gamma_curve": [ 0, 0, 1024, 5040, 2048, 9338, 3072, 12356, 4096, 15312, 5120, 18051, 6144, 20790, 7168, 23193, 8192, 25744, 9216, 27942, 10240, 30035, 11264, 32005, 12288, 33975, 13312, 35815, 14336, 37600, 15360, 39168, 16384, 40642, 18432, 43379, 20480, 45749, 22528, 47753, 24576, 49621, 26624, 51253, 28672, 52698, 30720, 53796, 32768, 54876, 36864, 57012, 40960, 58656, 45056, 59954, 49152, 61183, 53248, 62355, 57344, 63419, 61440, 64476, 65535, 65535 ] } }, { "rpi.ccm": { "ccms": [ { "ct": 2213, "ccm": [ 1.91264, -0.27609, -0.63655, -0.65708, 2.11718, -0.46009, 0.03629, -1.38441, 2.34811 ] }, { "ct": 2255, "ccm": [ 1.90369, -0.29309, -0.61059, -0.64693, 2.08169, -0.43476, 0.04086, -1.29999, 2.25914 ] }, { "ct": 2259, "ccm": [ 1.92762, -0.35134, -0.57628, -0.63523, 2.08481, -0.44958, 0.06754, -1.32953, 2.26199 ] }, { "ct": 5313, "ccm": [ 1.75924, -0.54053, -0.21871, -0.38159, 1.88671, -0.50511, -0.00747, -0.53492, 1.54239 ] }, { "ct": 6237, "ccm": [ 2.19299, -0.74764, -0.44536, -0.51678, 2.27651, -0.75972, -0.06498, -0.74269, 1.80767 ] } ] } }, { "rpi.sharpen": { } } ] }