validate:launcher: Add a generator to generate test for frame accurate seeking

This commit is contained in:
Thibault Saunier 2020-01-08 15:26:41 -03:00
parent 30ceb4ef40
commit 0b41b8a8c0
3 changed files with 1269 additions and 9 deletions

View file

@ -27,7 +27,9 @@ import socket
import subprocess import subprocess
import configparser import configparser
import json import json
from launcher.loggable import Loggable import glob
import math
from launcher.loggable import Loggable, error
from launcher.baseclasses import GstValidateTest, Test, \ from launcher.baseclasses import GstValidateTest, Test, \
ScenarioManager, NamedDic, GstValidateTestsGenerator, \ ScenarioManager, NamedDic, GstValidateTestsGenerator, \
@ -36,7 +38,8 @@ from launcher.baseclasses import GstValidateTest, Test, \
from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \ from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \
GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file, \ GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file, \
kill_subprocess, format_config_template, get_fakesink_for_media_type kill_subprocess, format_config_template, get_fakesink_for_media_type, \
parse_gsttimeargs, GstCaps
# #
# Private global variables # # Private global variables #
@ -337,6 +340,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator):
scenarios_to_iterate = scenarios scenarios_to_iterate = scenarios
config_files = extra_data.get('config_files') config_files = extra_data.get('config_files')
mediainfo = extra_data.get(
'media_info', FakeMediaDescriptor(extra_data, pipeline))
for scenario in scenarios_to_iterate: for scenario in scenarios_to_iterate:
if isinstance(scenario, str): if isinstance(scenario, str):
tmpscenario = self.test_manager.scenarios_manager.get_scenario( tmpscenario = self.test_manager.scenarios_manager.get_scenario(
@ -345,7 +350,6 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator):
raise RuntimeError("Could not find scenario file: %s" % scenario) raise RuntimeError("Could not find scenario file: %s" % scenario)
scenario = tmpscenario scenario = tmpscenario
mediainfo = FakeMediaDescriptor(extra_data, pipeline)
if not mediainfo.is_compatible(scenario): if not mediainfo.is_compatible(scenario):
continue continue
@ -470,6 +474,98 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator):
rtsp2=True)) rtsp2=True))
class GstValidateCheckAccurateSeekingTestGenerator(GstValidatePipelineTestsGenerator):
def __new__(cls, name, test_manager, media_infos, extra_data=None):
pipelines = {}
for path, reference_frame_dir in media_infos:
media_info = GstValidateMediaDescriptor(path)
media_info.set_protocol("file")
if not media_info:
error("GstValidateCheckAccurateSeekingTestGenerator",
"Could not create a media info file from %s" % path)
continue
if media_info.is_image():
error("GstValidateCheckAccurateSeekingTestGenerator",
"%s is an image, can't run accurate seeking tests" % path)
continue
if media_info.get_num_tracks("video") < 1:
error("GstValidateCheckAccurateSeekingTestGenerator",
"%s is not a video, can't run accurate seeking tests" % path)
continue
if media_info.get_num_tracks("video") < 1:
error("GstValidateCheckAccurateSeekingTestGenerator",
"No video track, can't run accurate seeking tests" % path)
continue
if test_manager.options.validate_generate_ssim_reference_files:
scenario = None
test_name = media_info.get_clean_name() + '.generate_reference_files'
config = [
'validatessim, element-name="videoconvert", output-dir="%s"' % reference_frame_dir]
else:
test_name = media_info.get_clean_name()
framerate, scenario = cls.generate_scenario(test_manager.options, reference_frame_dir, media_info)
if scenario is None:
error("GstValidateCheckAccurateSeekingTestGenerator",
"Could not generate test for media info: %s" % path)
continue
config = [
'%(ssim)s, element-name="videoconvert", reference-images-dir="' + \
reference_frame_dir + '", framerate=%d/%d' % (framerate.numerator, framerate.denominator)
]
pipelines[test_name] = {
"pipeline": "uridecodebin uri=" + media_info.get_uri() + " ! deinterlace ! video/x-raw,interlace-mode=progressive ! videoconvert name=videoconvert ! %(videosink)s",
"media_info": media_info,
"config": config,
}
if scenario:
pipelines[test_name]["scenarios"] = [scenario]
return GstValidatePipelineTestsGenerator.from_dict(test_manager, name, pipelines, extra_data=extra_data)
@classmethod
def generate_scenario(cls, options, reference_frame_dir, media_info):
actions = [
"description, seek=true, handles-states=true, needs_preroll=true",
"pause",
]
framerate = None
for track_type, caps in media_info.get_tracks_caps():
if track_type == 'video':
for struct, _ in GstCaps.new_from_str(caps):
framerate = struct["framerate"]
if framerate:
break
assert framerate
n_frames = int((media_info.get_duration() * framerate.numerator) / (GST_SECOND * framerate.denominator))
frames_timestamps = [math.ceil(i * framerate.denominator * GST_SECOND / framerate.numerator) for i in range(n_frames)]
# Ensure tests are not longer than long_limit, empirically considering we take 0.2 secs per frames.
acceptable_n_frames = options.long_limit * 5
if n_frames > acceptable_n_frames:
n_frames_per_groups = int(acceptable_n_frames / 3)
frames_timestamps = frames_timestamps[0:n_frames_per_groups] \
+ frames_timestamps[int(n_frames / 2 - int(n_frames_per_groups / 2)):int(n_frames / 2 + int(n_frames_per_groups / 2))] \
+ frames_timestamps[-n_frames_per_groups:n_frames]
actions += ['seek, flags=flush+accurate, start=(guint64)%s' % ts for ts in frames_timestamps]
actions += ['stop']
return framerate, {
"name": "check_accurate_seek",
"actions": actions,
}
class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator):
def __init__(self, name, test_manager, mixer, media_type, converter="", def __init__(self, name, test_manager, mixer, media_type, converter="",
@ -837,6 +933,7 @@ class GstValidateTestManager(GstValidateBaseTestManager):
GstValidatePipelineTestsGenerator = GstValidatePipelineTestsGenerator GstValidatePipelineTestsGenerator = GstValidatePipelineTestsGenerator
GstValidatePlaybinTestsGenerator = GstValidatePlaybinTestsGenerator GstValidatePlaybinTestsGenerator = GstValidatePlaybinTestsGenerator
GstValidateMixerTestsGenerator = GstValidateMixerTestsGenerator GstValidateMixerTestsGenerator = GstValidateMixerTestsGenerator
GstValidateCheckAccurateSeekingTestGenerator = GstValidateCheckAccurateSeekingTestGenerator
GstValidateLaunchTest = GstValidateLaunchTest GstValidateLaunchTest = GstValidateLaunchTest
GstValidateMediaCheckTest = GstValidateMediaCheckTest GstValidateMediaCheckTest = GstValidateMediaCheckTest
GstValidateTranscodingTest = GstValidateTranscodingTest GstValidateTranscodingTest = GstValidateTranscodingTest
@ -875,6 +972,9 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""")
group.add_argument("--validate-enable-iqa-tests", dest="validate_enable_iqa_tests", group.add_argument("--validate-enable-iqa-tests", dest="validate_enable_iqa_tests",
help="Enable Image Quality Assessment validation tests.", help="Enable Image Quality Assessment validation tests.",
default=False, action='store_true') default=False, action='store_true')
group.add_argument("--validate-generate-ssim-reference-files",
help="(re)generate ssim reference image files.",
default=False, action='store_true')
def print_valgrind_bugs(self): def print_valgrind_bugs(self):
# Look for all the 'pending' bugs in our supp file # Look for all the 'pending' bugs in our supp file
@ -972,10 +1072,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""")
if is_push or is_skipped: if is_push or is_skipped:
if not os.path.exists(media_info): if not os.path.exists(media_info):
continue continue
if is_push: if is_push:
uri = "push" + uri uri = "push" + uri
args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ")
args.append(uri) args.append(uri)
if os.path.isfile(media_info) and not self.options.update_media_info and not is_skipped: if os.path.isfile(media_info) and not self.options.update_media_info and not is_skipped:
@ -1076,7 +1174,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""")
except ValueError: except ValueError:
pass pass
if options.validate_uris: if options.validate_uris or options.validate_generate_ssim_reference_files:
self.check_testslist = False self.check_testslist = False
super(GstValidateTestManager, self).set_settings( super(GstValidateTestManager, self).set_settings(

View file

@ -2537,7 +2537,6 @@ class GstValidateMediaDescriptor(MediaDescriptor):
for stream in streams: for stream in streams:
self._track_caps.append( self._track_caps.append(
(stream.attrib["type"], stream.attrib["caps"])) (stream.attrib["type"], stream.attrib["caps"]))
self._uri = media_xml.attrib["uri"]
self._skip_parsers = bool(int(media_xml.attrib.get('skip-parsers', 0))) self._skip_parsers = bool(int(media_xml.attrib.get('skip-parsers', 0)))
self._has_frames = bool(int(media_xml.attrib["frame-detection"])) self._has_frames = bool(int(media_xml.attrib["frame-detection"]))
self._duration = int(media_xml.attrib["duration"]) self._duration = int(media_xml.attrib["duration"])
@ -2682,7 +2681,8 @@ class GstValidateMediaDescriptor(MediaDescriptor):
def get_clean_name(self): def get_clean_name(self):
name = os.path.basename(self.get_path()) name = os.path.basename(self.get_path())
name = re.sub("\.stream_info|\.media_info", "", name) regex = '|'.join(['\\.%s$' % ext for ext in [self.SKIPPED_MEDIA_INFO_EXT, self.MEDIA_INFO_EXT, self.PUSH_MEDIA_INFO_EXT, self.STREAM_INFO_EXT]])
name = re.sub(regex, "", name)
return name.replace('.', "_") return name.replace('.', "_")

File diff suppressed because it is too large Load diff