summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.com>2023-09-07 17:05:35 -0400
committerNicolas Dufresne <nicolas.dufresne@collabora.com>2023-09-10 19:06:06 -0400
commit63b8a5f22d1833711339cf0d42680598638270a5 (patch)
treeb9cbc4db1fd0ed5e1d664c76aab82d4075f10e92 /scripts
parentb7ded81f7b53cb18f7e450770ba128e53bda8568 (diff)
scripts: Add a script to validate video formats list
These lists have complex ordering and are error prone even for trained reviewers. This tool will parse the specified define in the specified file and determin if there is any error, unknown formats or miss-ordering. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5304>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/sort_video_formats.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/scripts/sort_video_formats.py b/scripts/sort_video_formats.py
new file mode 100755
index 0000000000..903425793e
--- /dev/null
+++ b/scripts/sort_video_formats.py
@@ -0,0 +1,145 @@
+#!/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):
+ score = 0
+ if fmt.flags & GstVideo.VideoFormatFlags.LE:
+ score = 1
+ if endian == "LE":
+ return -score
+ else:
+ return score
+
+
+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),
+ [-s for s in x.pixel_stride],
+ (x.flags & GstVideo.VideoFormatFlags.COMPLEX),
+ not (x.flags & GstVideo.VideoFormatFlags.YUV),
+ 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))