Adds deinterlacer after-filters

This commit is contained in:
Javanaut
2026-06-22 12:57:29 +02:00
parent f9d9db5871
commit dd810ed41f
3 changed files with 146 additions and 31 deletions

View File

@@ -1,5 +1,7 @@
import unittest
import click
from ffx.cli import convert
from ffx.filter.deinterlace_filter import DeinterlaceFilter
from ffx.filter.filter import Filter
@@ -24,7 +26,7 @@ class DeinterlaceFilterTest(unittest.TestCase):
self.assertEqual(['bwdif=mode=1'], payload['tokens'])
def test_up_down_mode_yields_lanczos_scales_after_bwdif(self):
payload = self.getPayload(DeinterlaceFilter.UP_DOWN_MODE)
payload = self.getPayload('up_down')
self.assertEqual(
[
@@ -36,7 +38,7 @@ class DeinterlaceFilterTest(unittest.TestCase):
)
def test_temp_mode_yields_hqdn3d_after_bwdif(self):
payload = self.getPayload(DeinterlaceFilter.TEMP_MODE)
payload = self.getPayload('temp')
self.assertEqual(
['bwdif=mode=1', 'hqdn3d=1.5:1.5:3:3'],
@@ -44,7 +46,7 @@ class DeinterlaceFilterTest(unittest.TestCase):
)
def test_up_down_temp_mode_yields_combined_filters_after_bwdif(self):
payload = self.getPayload(DeinterlaceFilter.UP_DOWN_TEMP_MODE)
payload = self.getPayload('up_down_temp')
self.assertEqual(
[
@@ -56,10 +58,59 @@ class DeinterlaceFilterTest(unittest.TestCase):
payload['tokens'],
)
def test_explicit_scale_factors_and_filter_order_are_preserved(self):
payload = self.getPayload('up4_temp3366_down4')
self.assertEqual(
[
'bwdif=mode=1',
'scale=iw*4:ih*4:flags=lanczos',
'hqdn3d=1.5:1.5:3:3',
'scale=iw/4:ih/4:flags=lanczos',
],
payload['tokens'],
)
def test_temporal_digits_are_divided_by_two(self):
payload = self.getPayload('temp0044_up2_down2')
self.assertEqual(
[
'bwdif=mode=1',
'hqdn3d=0:0:2:2',
'scale=iw*2:ih*2:flags=lanczos',
'scale=iw/2:ih/2:flags=lanczos',
],
payload['tokens'],
)
def test_each_component_uses_its_default_when_parameters_are_omitted(self):
payload = self.getPayload('up_temp_down')
self.assertEqual(
[
'bwdif=mode=1',
'scale=iw*2:ih*2:flags=lanczos',
'hqdn3d=1.5:1.5:3:3',
'scale=iw/2:ih/2:flags=lanczos',
],
payload['tokens'],
)
def test_unknown_mode_is_rejected(self):
with self.assertRaisesRegex(ValueError, 'Unknown deinterlace mode: other'):
with self.assertRaisesRegex(
ValueError,
"Unknown deinterlace component: 'other'",
):
DeinterlaceFilter(mode='other')
def test_invalid_parameters_are_rejected(self):
invalidModes = ('up0', 'down5', 'temp123', 'up__down')
for mode in invalidModes:
with self.subTest(mode=mode), self.assertRaises(ValueError):
DeinterlaceFilter(mode=mode)
def test_cli_accepts_named_modes_and_preserves_bare_flag_behavior(self):
upDownContext = convert.make_context(
'convert',
@@ -73,15 +124,27 @@ class DeinterlaceFilterTest(unittest.TestCase):
'convert',
['--deinterlace', 'up_down_temp'],
)
complexContext = convert.make_context(
'convert',
['--deinterlace', 'up4_temp3366_down4'],
)
bareFlagContext = convert.make_context('convert', ['--deinterlace'])
omittedContext = convert.make_context('convert', [])
self.assertEqual('up_down', upDownContext.params['deinterlace'])
self.assertEqual('temp', tempContext.params['deinterlace'])
self.assertEqual('up_down_temp', combinedContext.params['deinterlace'])
self.assertEqual(
'up4_temp3366_down4',
complexContext.params['deinterlace'],
)
self.assertEqual('default', bareFlagContext.params['deinterlace'])
self.assertEqual('none', omittedContext.params['deinterlace'])
def test_cli_rejects_an_invalid_specification(self):
with self.assertRaises(click.BadParameter):
convert.make_context('convert', ['--deinterlace', 'temp123'])
if __name__ == '__main__':
unittest.main()