Changeset View
Standalone View
tests/python/ffmpeg_tests.py
- This file was added.
| Property | Old Value | New Value |
|---|---|---|
| File Mode | null | 100755 |
| #!/usr/bin/env python3 | |||||
| # ##### BEGIN GPL LICENSE BLOCK ##### | |||||
| # | |||||
| # This program is free software; you can redistribute it and/or | |||||
| # modify it under the terms of the GNU General Public License | |||||
| # as published by the Free Software Foundation; either version 2 | |||||
| # of the License, or (at your option) any later version. | |||||
| # | |||||
| # This program is distributed in the hope that it will be useful, | |||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # GNU General Public License for more details. | |||||
| # | |||||
| # You should have received a copy of the GNU General Public License | |||||
| # along with this program; if not, write to the Free Software Foundation, | |||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
| # | |||||
| # ##### END GPL LICENSE BLOCK ##### | |||||
| # <pep8 compliant> | |||||
| import argparse | |||||
| import functools | |||||
| import shutil | |||||
| import pathlib | |||||
| import subprocess | |||||
| import sys | |||||
| import tempfile | |||||
| import unittest | |||||
| from modules.test_utils import AbstractBlenderRunnerTest | |||||
| class AbstractFFmpegTest(AbstractBlenderRunnerTest): | |||||
| @classmethod | |||||
| def setUpClass(cls): | |||||
| cls.blender = args.blender | |||||
| cls.testdir = pathlib.Path(args.testdir) | |||||
sybren: unused import | |||||
| class AbstractFFmpegSequencerTest(AbstractFFmpegTest): | |||||
| def get_script_for_file(self, filename: pathlib.Path) -> str: | |||||
| movie = self.testdir / filename | |||||
| return \ | |||||
| "import bpy; " \ | |||||
Done Inline ActionsUse PEP 8 for naming (yes this is inconsistent even in Python stdlib, but that's no excuse for us), so get_script_for_file or just script_for_file. You may also want to declare parameter type (filename: pathlib.Path) and return type -> str. Since using pathlib is relatively new in Blender's Python code, I would at least do the former. sybren: Use PEP 8 for naming (yes this is inconsistent even in Python stdlib, but that's no excuse for… | |||||
| "bpy.context.scene.sequence_editor_create(); " \ | |||||
| "strip = bpy.context.scene.sequence_editor.sequences.new_movie(" \ | |||||
| "'test_movie', %r, channel=1, frame_start=1); " \ | |||||
| "print(f'fps:{strip.fps}')" % movie.as_posix() | |||||
| def get_movie_file_fps(self, filename: pathlib.Path) -> float: | |||||
Done Inline ActionsReplace '%s' with %r. This will use single quotes, unless there is a single quote in the string, then it'll use double quotes. If both single and double quotes are there, it'll also escape the filename properly. Alternatively, do an assert "'" not in str(movie), 'Filename should not contain a single quote: %r' % movie before the return statement. sybren: Replace `'%s'` with `%r`. This will use single quotes, unless there is a single quote in the… | |||||
Not Done Inline ActionsYou'll want to look into alembic_tests.py for that. sergey: You'll want to look into alembic_tests.py for that. | |||||
| script = self.get_script_for_file(filename) | |||||
Done Inline ActionsSince this'll probably just be in master, you can use the new format string syntax introduced in Python 3.6: print(f'fps:{strip.fps}')) sybren: Since this'll probably just be in master, you can use the new format string syntax introduced… | |||||
Not Done Inline ActionsPHP-like string formatting, yay! Finally! sergey: PHP-like string formatting, yay! Finally! | |||||
| output = self.run_blender('', script) | |||||
| for line in output.splitlines(): | |||||
| if line.startswith('fps:'): | |||||
| return float(line.split(':')[1]) | |||||
| return 0.0 | |||||
Not Done Inline Actionsdon’t understand why you use collections.deque here? why not directly iterate over output.split() result? mont29: don’t understand why you use collections.deque here? why not directly iterate over `output. | |||||
| class FPSDetectionTest(AbstractFFmpegSequencerTest): | |||||
Done Inline ActionsWhy not simply use return round(fps, 2)? sybren: Why not simply use `return round(fps, 2)`? | |||||
| def test_T51153(self): | |||||
| self.assertAlmostEqual( | |||||
| self.get_movie_file_fps('T51153_bad_clip_2.mts'), | |||||
| 29.97, | |||||
Not Done Inline ActionsNew insight: maybe trade the round(fps, 2) call above for using self.assertAlmostEqual() here? That way you are also certain that there won't be any nasty decimal-to-binary errors creeping in and causing false failures. sybren: New insight: maybe trade the `round(fps, 2)` call above for using `self.assertAlmostEqual()`… | |||||
| places=2) | |||||
| def test_T53857(self): | |||||
| self.assertAlmostEqual( | |||||
| self.get_movie_file_fps('T53857_2018-01-22_15-30-49.mkv'), | |||||
| 30.0, | |||||
| places=2) | |||||
| def test_T54148(self): | |||||
| self.assertAlmostEqual( | |||||
| self.get_movie_file_fps('T54148_magn_0.mkv'), | |||||
| 1.0, | |||||
| places=2) | |||||
| if __name__ == '__main__': | |||||
| parser = argparse.ArgumentParser() | |||||
| parser.add_argument('--blender', required=True) | |||||
| parser.add_argument('--testdir', required=True) | |||||
| args, remaining = parser.parse_known_args() | |||||
| unittest.main(argv=sys.argv[0:1] + remaining) | |||||
unused import