| #!/usr/bin/env python3 | |
| import argparse | |
| import gi | |
| import os | |
| import sys | |
| gi.require_version("Gst", "1.0") | |
| gi.require_version("GstVideo", "1.0") | |
| from gi.repository import GLib | |
| from gi.repository import Gst, GstVideo | |
| def video_format_exists(f): | |
| return GstVideo.video_format_from_string(f) != GstVideo.VideoFormat.UNKNOWN | |
| def video_format_info_from_string(s): | |
| f = GstVideo.video_format_from_string(s) | |
| return GstVideo.video_format_get_info(f) | |
| def parse_format_from_c(token, filename): | |
| code = open(filename).read().splitlines() | |
| token_found = False | |
| formats = None | |
| for idx, line in enumerate(code): | |
| if formats is None: | |
| match = f"#define {token}" | |
| if line.startswith(match): | |
| formats = [] | |
| line = line[len(match):] | |
| else: | |
| continue | |
| tmp = line.replace("\\", "")\ | |
| .replace("\"", "")\ | |
| .replace(",", " ")\ | |
| .replace("{", " ")\ | |
| .replace("}", " ")\ | |
| .split() | |
| for f in tmp: | |
| if not video_format_exists(f): | |
| basename = os.path.basename(filename) | |
| print(f"WARNING: {basename}:{idx}: unknown format {f}") | |
| formats += tmp | |
| if line[-1] != "\\": | |
| break | |
| if formats is None: | |
| print(f"Define for {token} not found in {filename}") | |
| return None | |
| formats = list(filter(video_format_exists, formats)) | |
| return [video_format_info_from_string(f) for f in formats] | |
| def score_endian(fmt, endian): | |
| native_endianness = [GstVideo.VideoFormat.ARGB64, GstVideo.VideoFormat.AYUV64] | |
| if fmt.format in native_endianness: | |
| return -1 | |
| score = 0 | |
| if fmt.flags & GstVideo.VideoFormatFlags.LE: | |
| score = 1 | |
| if endian == "LE": | |
| return -score | |
| else: | |
| return score | |
| def score_pixel_stride(fmt): | |
| # Prefer power-of-two strides over odd ones, e.g. xRGB over RGB | |
| def scale_non_power_of_two(x): | |
| if (x & (x - 1) == 0) and x != 0: | |
| return x | |
| else: | |
| return x * 100 | |
| return [scale_non_power_of_two(x) for x in fmt.pixel_stride] | |
| def sort_video_formats(formats, endian): | |
| return sorted(formats, key=lambda x: (-x.n_components, | |
| [-d for d in x.depth], | |
| x.w_sub, | |
| x.h_sub, | |
| -x.n_planes, | |
| score_endian(x, endian), | |
| (x.flags & GstVideo.VideoFormatFlags.COMPLEX), | |
| not (x.flags & GstVideo.VideoFormatFlags.YUV), | |
| score_pixel_stride(x), | |
| [s for s in x.pixel_stride], | |
| [o for o in x.poffset], | |
| x.name)) | |
| def video_formats_to_c(token, formats, bracket): | |
| s = [f'#define {token} "'] | |
| if bracket: | |
| s[-1] += "{ " | |
| for f in formats: | |
| if len(s[-1]) > 80 - len(f.name) - len(', " \\'): | |
| s[-1] += ', " \\' | |
| s.append(' "') | |
| if s[-1][-2:] not in (' "', '{ '): | |
| s[-1] += ", " | |
| s[-1] += f.name | |
| if bracket: | |
| s[-1] += " }" | |
| s[-1] += '"' | |
| return s | |
| def generate_c_code(token, formats_be, formats_le, bracket): | |
| s = ["#if G_BYTE_ORDER == G_BIG_ENDIAN"] | |
| s += video_formats_to_c(token, formats_be, bracket) | |
| s += ["#elif G_BYTE_ORDER == G_LITTLE_ENDIAN"] | |
| s += video_formats_to_c(token, formats_le, bracket) | |
| s += ["#endif"] | |
| return s | |
| def main(args): | |
| formats = parse_format_from_c(args.token, args.filename) | |
| if formats is None: | |
| return 1 | |
| formats_be = sort_video_formats(formats, "BE") | |
| formats_le = sort_video_formats(formats, "LE") | |
| # We only check BE order as the list are now generated | |
| if formats_be == formats: | |
| print("Formats are properly ordered.") | |
| return 0 | |
| basename = os.path.basename(args.filename) | |
| print(f"ERROR: Formats order differ for {args.token} in {args.filename}") | |
| print("This can be fixed by replacing the define with:\n") | |
| for c_line in generate_c_code(args.token, formats_be, formats_le, | |
| args.bracket): | |
| print(c_line) | |
| return 1 | |
| if __name__ == '__main__': | |
| Gst.init(None) | |
| parser = argparse.ArgumentParser(prog='sort_video_formats', | |
| description='Sort video formats list') | |
| parser.add_argument('token') | |
| parser.add_argument('filename') | |
| parser.add_argument('-b', '--bracket', action='store_true') | |
| args = parser.parse_args() | |
| sys.exit(main(args)) |