gstreamer/scripts/sort_video_formats.py

163 lines
4.7 KiB
Python
Executable file

#!/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))