Skip to content

Commit ff49db7

Browse files
committed
utils: test_convert: Update for new buffer API
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
1 parent e187cc8 commit ff49db7

1 file changed

Lines changed: 140 additions & 19 deletions

File tree

utils/test_convert.py

Lines changed: 140 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@
1818

1919

2020
class ConvertTester:
21-
def __init__(self, convert_binary, output_dir=None, input_dir=None, reference_dir=None):
21+
def __init__(self, convert_binary, output_dir=None, input_dir=None, reference_dir=None, use_gstreamer=False, gst_plugin_path=None):
2222
"""Initialize the tester with the path to the convert binary."""
2323
self.convert_binary = convert_binary
2424
self.output_dir = output_dir
2525
self.input_dir = input_dir
2626
self.reference_dir = reference_dir
27-
if not os.path.exists(convert_binary):
27+
self.use_gstreamer = use_gstreamer
28+
self.gst_plugin_path = gst_plugin_path
29+
30+
if not use_gstreamer and not os.path.exists(convert_binary):
2831
raise FileNotFoundError(f"Convert binary not found: {convert_binary}")
2932

3033
# Test cases: (input_file, output_file, input_format, output_format, reference_file)
@@ -34,25 +37,104 @@ def __init__(self, convert_binary, output_dir=None, input_dir=None, reference_di
3437
"output_file": "out_4056x3050_12168s_rgb888.rgb",
3538
"input_format": "4056:3040:4056:YUV420P",
3639
"output_format": "4056:3040:12168:RGB888",
37-
"reference_file": "ref_4056x3050_12168s_rgb888.rgb"
40+
"reference_file": "ref_4056x3050_12168s_rgb888.rgb",
41+
"skip_gst": False
3842
},
3943
{
4044
"input_file": "conv_800x600_1200s_422_yuyv.yuv",
4145
"output_file": "out_1600x1200_422p.yuv",
4246
"input_format": "800:600:1600:YUYV",
4347
"output_format": "1600:1200:1600:YUV422P",
44-
"reference_file": "ref_1600x1200_422p.yuv"
48+
"reference_file": "ref_1600x1200_1600_422p.yuv",
49+
"skip_gst": False
4550
},
4651
{
4752
"input_file": "conv_rgb888_800x600_2432s.rgb",
4853
"output_file": "out_4000x3000_4032s.yuv",
4954
"input_format": "800:600:2432:RGB888",
50-
"output_format": "4000:3000:0:YUV444P",
51-
"reference_file": "ref_4000x3000_4032s.yuv"
55+
"output_format": "4000:3000:4032:YUV444P",
56+
"reference_file": "ref_4000x3000_4032s.yuv",
57+
"skip_gst": True
5258
},
5359
# Add more test cases here as needed
5460
]
5561

62+
def _parse_format(self, format_str):
63+
"""Parse format string like '4056:3040:4056:YUV420P' into components."""
64+
parts = format_str.split(':')
65+
if len(parts) != 4:
66+
raise ValueError(f"Invalid format string: {format_str}")
67+
return {
68+
'width': int(parts[0]),
69+
'height': int(parts[1]),
70+
'stride': int(parts[2]),
71+
'format': parts[3]
72+
}
73+
74+
def _pisp_to_gst_format(self, pisp_format):
75+
"""Convert PiSP format to GStreamer format string."""
76+
format_map = {
77+
'YUV420P': 'I420',
78+
'YVU420P': 'YV12',
79+
'YUV422P': 'Y42B',
80+
'YUV444P': 'Y444',
81+
'YUYV': 'YUY2',
82+
'UYVY': 'UYVY',
83+
'RGB888': 'RGB',
84+
}
85+
return format_map.get(pisp_format, pisp_format)
86+
87+
def run_gstreamer(self, input_file, output_file, input_format, output_format):
88+
"""Run GStreamer pipeline with pispconvert."""
89+
# Use input directory if specified
90+
if self.input_dir:
91+
input_file = os.path.join(self.input_dir, input_file)
92+
93+
# Use output directory if specified
94+
if self.output_dir:
95+
output_file = os.path.join(self.output_dir, output_file)
96+
97+
# Parse format strings
98+
in_fmt = self._parse_format(input_format)
99+
out_fmt = self._parse_format(output_format)
100+
101+
# Convert to GStreamer format names
102+
gst_in_format = self._pisp_to_gst_format(in_fmt['format'])
103+
gst_out_format = self._pisp_to_gst_format(out_fmt['format'])
104+
105+
# Build GStreamer pipeline
106+
pipeline = [
107+
'gst-launch-1.0',
108+
'filesrc', f'location={input_file}', '!',
109+
'rawvideoparse',
110+
f'width={in_fmt["width"]}',
111+
f'height={in_fmt["height"]}',
112+
f'format={gst_in_format.lower()}',
113+
'framerate=30/1', '!',
114+
'pispconvert', '!',
115+
f'video/x-raw,format={gst_out_format},width={out_fmt["width"]},height={out_fmt["height"]}', '!',
116+
'filesink', f'location={output_file}'
117+
]
118+
119+
print(f"Running GStreamer pipeline:")
120+
print(' '.join(pipeline))
121+
122+
# Set GST_PLUGIN_PATH environment variable if specified
123+
env = os.environ.copy()
124+
if self.gst_plugin_path:
125+
env['GST_PLUGIN_PATH'] = self.gst_plugin_path
126+
print(f"GST_PLUGIN_PATH={self.gst_plugin_path}")
127+
128+
try:
129+
result = subprocess.run(pipeline, capture_output=True, text=True, check=True, env=env)
130+
print("GStreamer pipeline completed successfully")
131+
return True
132+
except subprocess.CalledProcessError as e:
133+
print(f"GStreamer pipeline failed with exit code {e.returncode}")
134+
print(f"stdout: {e.stdout}")
135+
print(f"stderr: {e.stderr}")
136+
return False
137+
56138
def run_convert(self, input_file, output_file, input_format, output_format):
57139
"""Run the convert utility with the specified parameters."""
58140
# Use input directory if specified
@@ -137,13 +219,26 @@ def run_test_case(self, test_case):
137219
print(f"Error: Input file {input_file} does not exist")
138220
return False
139221

140-
# Run the convert utility
141-
success = self.run_convert(
142-
test_case['input_file'],
143-
test_case['output_file'],
144-
test_case['input_format'],
145-
test_case['output_format']
146-
)
222+
# Skip GStreamer test if marked to skip
223+
if self.use_gstreamer and test_case.get('skip_gst', False):
224+
print(f"SKIPPED: Test case marked as skip_gst=True")
225+
return None # Return None to indicate skipped
226+
227+
# Run the convert utility or GStreamer pipeline
228+
if self.use_gstreamer:
229+
success = self.run_gstreamer(
230+
test_case['input_file'],
231+
test_case['output_file'],
232+
test_case['input_format'],
233+
test_case['output_format']
234+
)
235+
else:
236+
success = self.run_convert(
237+
test_case['input_file'],
238+
test_case['output_file'],
239+
test_case['input_format'],
240+
test_case['output_format']
241+
)
147242

148243
if not success:
149244
return False
@@ -161,12 +256,17 @@ def run_test_case(self, test_case):
161256
output_file = os.path.join(self.output_dir, test_case['output_file'])
162257
return self.compare_files(output_file, reference_file)
163258
else:
164-
print(f"Reference file {reference_file} not found, skipping comparison")
165-
return True
259+
print(f"Reference file {reference_file} not found")
260+
return False
166261

167262
def run_all_tests(self):
168263
"""Run all test cases."""
169-
print(f"Testing convert utility: {self.convert_binary}")
264+
if self.use_gstreamer:
265+
print("Testing with GStreamer pispconvert plugin")
266+
if self.gst_plugin_path:
267+
print(f"GST_PLUGIN_PATH: {self.gst_plugin_path}")
268+
else:
269+
print(f"Testing convert utility: {self.convert_binary}")
170270
if self.input_dir:
171271
print(f"Input directory: {self.input_dir}")
172272
if self.output_dir:
@@ -177,11 +277,16 @@ def run_all_tests(self):
177277

178278
passed = 0
179279
failed = 0
280+
skipped = 0
180281

181282
for i, test_case in enumerate(self.test_cases, 1):
182283
print(f"\n--- Test case {i}/{len(self.test_cases)} ---")
183284

184-
if self.run_test_case(test_case):
285+
result = self.run_test_case(test_case)
286+
if result is None:
287+
skipped += 1
288+
print("⊘ Test SKIPPED")
289+
elif result:
185290
passed += 1
186291
print("✓ Test PASSED")
187292
else:
@@ -191,23 +296,39 @@ def run_all_tests(self):
191296
print(f"\n=== Test Summary ===")
192297
print(f"Passed: {passed}")
193298
print(f"Failed: {failed}")
299+
print(f"Skipped: {skipped}")
194300
print(f"Total: {len(self.test_cases)}")
195301

196302
return failed == 0
197303

198304

199305
def main():
200306
parser = argparse.ArgumentParser(description="Test script for libpisp convert utility")
201-
parser.add_argument("convert_binary", help="Path to the convert binary")
307+
parser.add_argument("convert_binary", nargs='?', default=None, help="Path to the convert binary (not needed with --gst-plugin-path)")
202308
parser.add_argument("--test-dir", help="Directory containing test files")
203309
parser.add_argument("--in", dest="input_dir", help="Directory containing input files")
204310
parser.add_argument("--out", help="Directory where output files will be written")
205311
parser.add_argument("--ref", help="Directory containing reference files")
312+
parser.add_argument("--gst-plugin-path", help="Path to GStreamer plugin directory (enables GStreamer testing)")
206313

207314
args = parser.parse_args()
208315

209316
try:
210-
tester = ConvertTester(args.convert_binary, args.out, args.input_dir, args.ref)
317+
# Determine if using GStreamer based on --gst-plugin-path
318+
use_gstreamer = args.gst_plugin_path is not None
319+
320+
# Validate arguments
321+
if not use_gstreamer and not args.convert_binary:
322+
parser.error("convert_binary is required unless --gst-plugin-path is specified")
323+
324+
tester = ConvertTester(
325+
args.convert_binary,
326+
args.out,
327+
args.input_dir,
328+
args.ref,
329+
use_gstreamer=use_gstreamer,
330+
gst_plugin_path=args.gst_plugin_path
331+
)
211332

212333
# Change to test directory if specified
213334
if args.test_dir:

0 commit comments

Comments
 (0)