├── .all-contributorsrc ├── .gitchangelog.rc ├── .gitchangelog.tpl ├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md └── workflows │ └── python-package.yml ├── .gitignore ├── CHANGELOG.md ├── DEVELOPERS.md ├── Dockerfile ├── README.md ├── VERSION ├── docker_run.sh ├── docs ├── ffmpeg_quality_metrics.html ├── index.html └── search.js ├── ffmpeg_quality_metrics ├── __init__.py ├── __main__.py ├── ffmpeg_quality_metrics.py ├── log.py ├── py.typed ├── utils.py └── vmaf_models │ ├── LICENSE │ ├── vmaf_4k_v0.6.1.json │ ├── vmaf_v0.6.1.json │ └── vmaf_v0.6.1neg.json ├── requirements.dev.txt ├── requirements.txt ├── setup.cfg ├── setup.py └── test ├── dist-854x480.mkv ├── example.json ├── ref-1280x720.mkv ├── response.json └── test.py /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "commitConvention": "angular", 8 | "contributors": [ 9 | { 10 | "login": "OrkunKocyigit", 11 | "name": "Orkun Koçyiğit", 12 | "avatar_url": "https://avatars.githubusercontent.com/u/10797423?v=4", 13 | "profile": "https://github.com/OrkunKocyigit", 14 | "contributions": [ 15 | "code" 16 | ] 17 | }, 18 | { 19 | "login": "CrypticSignal", 20 | "name": "Hamas Shafiq", 21 | "avatar_url": "https://avatars.githubusercontent.com/u/48166845?v=4", 22 | "profile": "https://github.com/CrypticSignal", 23 | "contributions": [ 24 | "code" 25 | ] 26 | }, 27 | { 28 | "login": "cdgriffith", 29 | "name": "Chris Griffith", 30 | "avatar_url": "https://avatars.githubusercontent.com/u/3275435?v=4", 31 | "profile": "http://codecalamity.com/", 32 | "contributions": [ 33 | "code" 34 | ] 35 | }, 36 | { 37 | "login": "Sorkanius", 38 | "name": "Ignacio Peletier", 39 | "avatar_url": "https://avatars.githubusercontent.com/u/17472224?v=4", 40 | "profile": "http://codecalamity.com/", 41 | "contributions": [ 42 | "code" 43 | ] 44 | }, 45 | { 46 | "login": "nav9", 47 | "name": "Nav", 48 | "avatar_url": "https://avatars.githubusercontent.com/u/2093933?v=4", 49 | "profile": "https://github.com/nav9", 50 | "contributions": [ 51 | "bug" 52 | ] 53 | } 54 | ], 55 | "contributorsPerLine": 7, 56 | "skipCi": true, 57 | "repoType": "github", 58 | "repoHost": "https://github.com", 59 | "projectName": "ffmpeg-quality-metrics", 60 | "projectOwner": "slhck" 61 | } 62 | -------------------------------------------------------------------------------- /.gitchangelog.rc: -------------------------------------------------------------------------------- 1 | output_engine = mustache(".gitchangelog.tpl") 2 | 3 | section_regexps = [ 4 | ('', None) 5 | ] 6 | 7 | subject_process = (strip | ucfirst | final_dot) 8 | 9 | tag_filter_regexp = r'^v[0-9]+\.[0-9]+(\.[0-9]+)?$' 10 | 11 | ignore_regexps = [ 12 | r'^Bump version to' 13 | ] 14 | -------------------------------------------------------------------------------- /.gitchangelog.tpl: -------------------------------------------------------------------------------- 1 | {{#general_title}} 2 | # {{{title}}} 3 | 4 | {{/general_title}} 5 | 6 | {{#versions}} 7 | ## {{{label}}} 8 | 9 | {{#sections}} 10 | {{#commits}} 11 | * {{{subject}}} 12 | {{#body}} 13 | 14 | {{{body_indented}}} 15 | {{/body}} 16 | 17 | {{/commits}} 18 | {{/sections}} 19 | 20 | {{/versions}} -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Features and Bugfixes 2 | 3 | If you want to contribute a new feature or fix, please: 4 | 5 | - Check if there isn't any open issue for the same problem 6 | - Fork the project 7 | - Implement your feature or fix 8 | - Bonus points if you provide a test case in `test/test.py` 9 | - Provide a commit for the change you want to make (one feature per commit, please) 10 | - Create a pull request 11 | 12 | ## Issues and Questions 13 | 14 | If you simply have a question or want to raise an issue, head to the issue tracker. There's a template there that you're kindly asked to fill out. It helps me understand what the problem might be. -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: slhck # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: I ran across an error or bug in the program 4 | 5 | --- 6 | 7 | **:warning: Please read this carefully and edit the example responses! If you do not fill out this information, your bug report may be closed without comment.** 8 | 9 | **Checklist** (please tick all boxes) 10 | - [ ] I am using the latest version of `ffmpeg-quality-metrics` (run `pip3 install --upgrade ffmpeg-quality-metrics`) 11 | - [ ] I am using the latest stable version of `ffmpeg` or a recent build from Git master 12 | 13 | **Expected behavior** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **Actual behavior** 17 | What happened? 18 | 19 | **Command** 20 | The exact command you were trying to run: 21 | 22 | ``` 23 | 24 | ``` 25 | 26 | Any output you get when running the command with the `-v` flag: 27 | 28 | ``` 29 | 30 | ``` 31 | 32 | **Environment (please complete the following information):** 33 | - [ ] Your operating system 34 | - [ ] Your Python version / distribution (`python3 --version` or `python --version`) 35 | - [ ] Your ffmpeg version (`ffmpeg -version`) 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: I want to suggest an idea for this project 4 | 5 | --- 6 | 7 | **:warning: Please read this carefully and edit the example responses! If you do not fill out this information, your feature request may be closed without comment.** 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. E.g. “I'm always frustrated when [...]” 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question/Support 3 | about: I am stuck with something and need help (not a bug or error) 4 | 5 | --- 6 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | name: Test Package 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | FFMPEG_VERSION: "7.1" 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] 18 | 19 | steps: 20 | - uses: actions/checkout@v3 21 | - name: Set up Python ${{ matrix.python-version }} 22 | uses: actions/setup-python@v4 23 | with: 24 | python-version: ${{ matrix.python-version }} 25 | - name: Cache ffmpeg download 26 | uses: actions/cache@v3 27 | id: cache-ffmpeg 28 | with: 29 | path: /opt/ffmpeg/ffmpeg-n${{ env.FFMPEG_VERSION }}-latest-linux64-gpl-${{ env.FFMPEG_VERSION }}.tar.xz 30 | key: ${{ runner.os }}-ffmpeg 31 | - name: Download ffmpeg if not cached 32 | if: steps.cache-ffmpeg.outputs.cache-hit != 'true' 33 | run: | 34 | echo "Downloading ffmpeg ${FFMPEG_VERSION}" 35 | wget -q https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-n${{ env.FFMPEG_VERSION }}-latest-linux64-gpl-${{ env.FFMPEG_VERSION }}.tar.xz -P /opt/ffmpeg 36 | echo "Extracting ffmpeg ${FFMPEG_VERSION}" 37 | tar --strip-components 1 -xvf /opt/ffmpeg/ffmpeg-n${{ env.FFMPEG_VERSION }}-latest-linux64-gpl-${{ env.FFMPEG_VERSION }}.tar.xz -C /opt/ffmpeg 38 | echo "Installing ffmpeg ${FFMPEG_VERSION}" 39 | sudo cp /opt/ffmpeg/bin/ffmpeg /usr/bin/ffmpeg 40 | - name: Install dependencies 41 | run: | 42 | python -m pip install --upgrade pip 43 | pip install flake8 mypy==0.991 44 | pip install -r requirements.txt 45 | pip install -r requirements.dev.txt 46 | - name: Lint with flake8 47 | run: | 48 | # stop the build if there are Python syntax errors or undefined names 49 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 50 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 51 | flake8 . --count --exit-zero --max-line-length=127 --ignore=W503,W504,C901 52 | - name: Type check with mypy 53 | run: | 54 | mypy --no-namespace-packages --ignore-missing-imports ffmpeg_quality_metrics 55 | - name: Test with pytest 56 | run: | 57 | pytest test/test.py 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | 7 | # Distribution / packaging 8 | .Python 9 | env/ 10 | build/ 11 | develop-eggs/ 12 | dist/ 13 | downloads/ 14 | eggs/ 15 | .eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | wheels/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # virtualenv 27 | .venv 28 | venv/ 29 | ENV/ 30 | .vscode 31 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | ## v3.5.0 (2025-03-31) 5 | 6 | * Add MSAD support, fixes #31. 7 | 8 | 9 | ## v3.4.2 (2025-03-31) 10 | 11 | * Change CI ffmpeg bin. 12 | 13 | * Fix ffmpeg version parsing. 14 | 15 | * Update readme. 16 | 17 | * Update ci pipeline. 18 | 19 | 20 | ## v3.4.1 (2025-03-18) 21 | 22 | * Fix version parsing. 23 | 24 | 25 | ## v3.4.0 (2025-03-18) 26 | 27 | * Fix handling for ffmpeg 7.1, remove python 3.8 support. 28 | 29 | 30 | ## v3.3.1 (2024-03-05) 31 | 32 | * Update readme. 33 | 34 | * Add error for raw YUV files. 35 | 36 | * Remove deprecated methods. 37 | 38 | 39 | ## v3.3.0 (2023-07-18) 40 | 41 | * Add dist-delay option. 42 | 43 | * Add encoding to setup.py for windows compat. 44 | 45 | * Add encoding to setup.py for windows compat. 46 | 47 | 48 | ## v3.2.1 (2023-03-06) 49 | 50 | * Check for existing files before running. 51 | 52 | * Fix executable name in CLI help, again. 53 | 54 | 55 | ## v3.2.0 (2023-03-06) 56 | 57 | * Allow overriding temp dir. 58 | 59 | * Fix executable name in CLI help. 60 | 61 | * Link to VMAF docs. 62 | 63 | * Fix formatting. 64 | 65 | * Update README with more features. 66 | 67 | * Add warning for same file input, fixes #59. 68 | 69 | * Update contributors. 70 | 71 | 72 | ## v3.1.7 (2023-02-20) 73 | 74 | * Fix readme example, fixes #58. 75 | 76 | 77 | ## v3.1.6 (2023-02-19) 78 | 79 | * Update README and docs. 80 | 81 | * Remove stalebot. 82 | 83 | * Update README. 84 | 85 | 86 | ## v3.1.5 (2023-01-04) 87 | 88 | * Fix keep-tmp option. 89 | 90 | * Update docker instructions. 91 | 92 | * Fix github workflows. 93 | 94 | * Add workflow badge. 95 | 96 | * Update python metadata, remove old console script. 97 | 98 | * Minor code formatting. 99 | 100 | * Add github workflows. 101 | 102 | * Fix type error. 103 | 104 | 105 | ## v3.1.4 (2023-01-03) 106 | 107 | * Remove MANIFEST.in. 108 | 109 | * Fix API import. 110 | 111 | * Sort imports. 112 | 113 | 114 | ## v3.1.3 (2022-12-23) 115 | 116 | * Fix finding version in setup.py. 117 | 118 | 119 | ## v3.1.2 (2022-12-23) 120 | 121 | * Format with black. 122 | 123 | * Improve types. 124 | 125 | 126 | ## v3.1.1 (2022-12-18) 127 | 128 | * Improve typing support. 129 | 130 | * Add contributor manually. 131 | 132 | * Docs: update .all-contributorsrc [skip ci] 133 | 134 | * Docs: update README.md [skip ci] 135 | 136 | * Docs: update .all-contributorsrc [skip ci] 137 | 138 | * Docs: update README.md [skip ci] 139 | 140 | * Docs: create .all-contributorsrc [skip ci] 141 | 142 | * Docs: update README.md [skip ci] 143 | 144 | * Add contributors template. 145 | 146 | 147 | ## v3.1.0 (2022-12-11) 148 | 149 | * Fix VMAF model path error on Windows, fixes #42. 150 | 151 | * Fix flaky tests. 152 | 153 | * Fix AVTB setting, see #39. 154 | 155 | * Fix default docker image name. 156 | 157 | * Fix docs link. 158 | 159 | * Add explicit return type for calculate() function. 160 | 161 | * Decrease max width of args, update README. 162 | 163 | * Update tests. 164 | 165 | 166 | ## v3.0.0 (2022-08-08) 167 | 168 | * Support for VMAF 2.0 only. 169 | 170 | * Update copyright. 171 | 172 | * Remove warning for libvmaf in johnvansickle builds. 173 | 174 | * Use latest linux build instead of release builds. 175 | 176 | 177 | ## v2.3.0 (2021-12-22) 178 | 179 | * Update docs. 180 | 181 | * Update README. 182 | 183 | * Remove unneeded warning. 184 | 185 | * Print stdout on error to help with debugging. 186 | 187 | * Reomve underline from log. 188 | 189 | * Add better logging capabilities. 190 | 191 | * Normalize time base for comparison. 192 | 193 | see https://trac.ffmpeg.org/ticket/9560 194 | 195 | * Fix default model path selection for VMAF. 196 | 197 | * Update test vector values. 198 | 199 | * Filter out LICENSE in model path. 200 | 201 | 202 | ## v2.2.0 (2021-05-31) 203 | 204 | * Fix detection of libvmaf model dir, fixes #34. 205 | 206 | * Re-add old PKL models. 207 | 208 | * Make docker a bit more quiet. 209 | 210 | 211 | ## v2.1.0 (2021-05-27) 212 | 213 | * Add option to keep temporary files. 214 | 215 | * Always pick latest dockerfile version for docker_run script. 216 | 217 | * Improve dockerfile build. 218 | 219 | * Create FUNDING.yml. 220 | 221 | * Update badge link. 222 | 223 | 224 | ## v2.0.3 (2021-03-10) 225 | 226 | * Add python_requires to setup.py. 227 | 228 | 229 | ## v2.0.2 (2021-03-10) 230 | 231 | * Fix README. 232 | 233 | 234 | ## v2.0.1 (2021-03-10) 235 | 236 | * Fix README. 237 | 238 | 239 | ## v2.0.0 (2021-03-10) 240 | 241 | * Change CLI syntax, add VIF filter. 242 | 243 | Move CLI syntax to a more flexible format for selecting metrics. 244 | This is not backwards-compatible, so a major release. 245 | Add the VIF filter. 246 | 247 | * Fix bug if VMAF is the only metric. 248 | 249 | * Update docs. 250 | 251 | 252 | ## v1.2.0 (2021-03-10) 253 | 254 | * Update docs. 255 | 256 | * Deprecate old API. 257 | 258 | * Add single calc() function, fixes #32. 259 | 260 | * Add dev requirements. 261 | 262 | * Explicitly call VMAF model in test. 263 | 264 | * Support Python 3.9. 265 | 266 | * Fix flake8 errors. 267 | 268 | * Simplify VMAF function. 269 | 270 | * Detect available filters. 271 | 272 | * Note how to update docs. 273 | 274 | * Update docs. 275 | 276 | * Remove release script. 277 | 278 | 279 | ## v1.1.3 (2021-03-06) 280 | 281 | * Update ffmpeg-progress-yield requirement. 282 | 283 | * Format setup.py. 284 | 285 | 286 | ## v1.1.2 (2021-03-06) 287 | 288 | * Add missing CLI option to readme. 289 | 290 | 291 | ## v1.1.1 (2021-03-06) 292 | 293 | * Fix long description content type. 294 | 295 | 296 | ## v1.1.0 (2021-03-06) 297 | 298 | * Add progress bar, fixes #12. 299 | 300 | * Add vscode to gitignore. 301 | 302 | * Add VMAF unit test. 303 | 304 | * Improve README. 305 | 306 | 307 | ## v1.0.1 (2021-03-01) 308 | 309 | * Fix setup.py file. 310 | 311 | 312 | ## v1.0.0 (2021-03-01) 313 | 314 | * Allow top-level import. 315 | 316 | * Update badge URL. 317 | 318 | 319 | ## v0.12.1 (2021-02-12) 320 | 321 | * Update changelog format, release script. 322 | 323 | * Fix docs link, again. 324 | 325 | 326 | ## v0.12.0 (2021-02-12) 327 | 328 | * Improve VMAF model selection, fixes #30. 329 | 330 | 331 | ## v0.11.1 (2021-02-11) 332 | 333 | * Fix readme. 334 | 335 | * Fix docs link. 336 | 337 | 338 | ## v0.11.0 (2021-02-11) 339 | 340 | * Add API docs. 341 | 342 | * Convert into library, fixes #29. 343 | 344 | 345 | ## v0.10.0 (2021-02-10) 346 | 347 | * Do not freeze pandas requirement, it does not matter. 348 | 349 | * Improve help output from docker_run.sh. 350 | 351 | * Update Dockerfile to use static build. 352 | 353 | 354 | ## v0.9.0 (2021-02-09) 355 | 356 | * Add a note for Homebrew users. 357 | 358 | * Fix possibly unbound variables. 359 | 360 | * Remove unused variable. 361 | 362 | * Improve default model file lookup; minor style fixes. 363 | 364 | * [libvmaf] use vmaf_models/vmaf_v0.6.1.json by default. 365 | 366 | * Include the model files. 367 | 368 | * Add model files. 369 | 370 | * Detect whether used ffmpeg is from Homebrew. 371 | 372 | * Add placeholder and instructions for model path, addresses #19. 373 | 374 | * Change n_threads to int, minor fixes. 375 | 376 | * Remove program name. 377 | 378 | * Remove a duplicate line. 379 | 380 | * No need to include the default value in the help msg as ArgumentDefaultsHelpFormatter takes care of this. 381 | 382 | * Add option to set the value of libvmaf's n_threads option. 383 | 384 | 385 | ## v0.8.0 (2021-01-22) 386 | 387 | * Document threads option. 388 | 389 | * Change default threads to 0. 390 | 391 | * Added option for selecting number of threads (#26) 392 | 393 | * Added option for selecting number of threads 394 | 395 | * convert threads to str 396 | 397 | * change default threads CLI arg to int 398 | 399 | 400 | ## v0.7.1 (2021-01-09) 401 | 402 | * Remove color support. 403 | 404 | * Merge pull request #24 from slhck/fix-windows-paths. 405 | 406 | fix Windows paths, fixes #23 407 | 408 | * Fix Windows paths, fixes #23. 409 | 410 | 411 | ## v0.7.0 (2021-01-07) 412 | 413 | * Do not try to convert while getting fps, addresses #22. 414 | 415 | * Add colorama support for Windows ANSI escapes, fixes #21. 416 | 417 | * Properly handle dry run, fixes #20. 418 | 419 | 420 | ## v0.6.2 (2020-10-22) 421 | 422 | * Update readme, fixes #18. 423 | 424 | 425 | ## v0.6.1 (2020-10-01) 426 | 427 | * Merge pull request #16 from dpasqualin/issue_15. 428 | 429 | Closes #15: fix 'print_stderr' is not defined 430 | 431 | * Closes #15: fix 'print_stderr' is not defined. 432 | 433 | * Improve readme. 434 | 435 | 436 | ## v0.6.0 (2020-07-21) 437 | 438 | * Improve warnings and messages, add -r parameter. 439 | 440 | 441 | ## v0.5.1 (2020-07-21) 442 | 443 | * Merge pull request #14 from BassThatHertz/master. 444 | 445 | Prevent users on Windows from seeing an "UnboundLocalError" 446 | 447 | * Add sys.exit(1) to prevent users on Windows from seeing "UnboundLocalError: local variable 'model_path' referenced before assignment" 448 | 449 | 450 | ## v0.5.0 (2020-07-21) 451 | 452 | * Set PTS and framerate for input files. 453 | 454 | * Apply black formatting. 455 | 456 | 457 | ## v0.4.0 (2020-07-17) 458 | 459 | * Add global statistics, fixes #13. 460 | 461 | 462 | ## v0.3.12 (2020-07-15) 463 | 464 | * Apply windows path modifications to VMAF model. 465 | 466 | 467 | ## v0.3.11 (2020-07-13) 468 | 469 | * Update Dockerfile Homebrew tag. 470 | 471 | * Update README. 472 | 473 | * Show error if using Windows and VMAF, fixes #10. 474 | 475 | * Update test values, add almost equal comparison. 476 | 477 | * Remove unused import. 478 | 479 | * Remove unused import. 480 | 481 | 482 | ## v0.3.10 (2020-04-08) 483 | 484 | * Show all commits in release. 485 | 486 | * Check for brew before setting model path, fixes #9. 487 | 488 | 489 | ## v0.3.9 (2020-03-15) 490 | 491 | * Update release script. 492 | 493 | * Rename CHANGELOG. 494 | 495 | 496 | ## v0.3.8 (2020-03-15) 497 | 498 | * Version bump to 0.3.8. 499 | 500 | * Compatibility with python 3.8. 501 | 502 | 503 | ## v0.3.7 (2020-01-08) 504 | 505 | * Version bump to 0.3.7. 506 | 507 | * Change image to official homebrew/brew. 508 | 509 | * Pin pandas. 510 | 511 | 512 | ## v0.3.6 (2019-10-15) 513 | 514 | * Version bump to 0.3.6. 515 | 516 | * Fix string. 517 | 518 | 519 | ## v0.3.5 (2019-09-09) 520 | 521 | * Version bump to 0.3.5. 522 | 523 | * Switch Homebrew tap. 524 | 525 | * Fix Dockerfile. 526 | 527 | 528 | ## v0.3.4 (2019-06-07) 529 | 530 | * Version bump to 0.3.4. 531 | 532 | * Clarify instructions. 533 | 534 | * Merge pull request #7 from cdgriffith/development. 535 | 536 | Windows fixes 537 | 538 | * Fixing windows path issue for ffmpeg Fixing VMAF model automatic finding via brew broken for windows. 539 | 540 | 541 | ## v0.3.3 (2019-05-25) 542 | 543 | * Version bump to 0.3.3. 544 | 545 | * Add missing pandas dependency. 546 | 547 | * Fix dockerfile entry point, fixes #4. 548 | 549 | 550 | ## v0.3.2 (2019-05-25) 551 | 552 | * Version bump to 0.3.2. 553 | 554 | * Fix python compatibility. 555 | 556 | * Remove old python script. 557 | 558 | * Update gitignore. 559 | 560 | * Add PyPI badge. 561 | 562 | 563 | ## v0.3.1 (2019-05-25) 564 | 565 | * Version bump to 0.3.1. 566 | 567 | * Fix URL and description in setup file. 568 | 569 | 570 | ## v0.3 (2019-05-25) 571 | 572 | * Version bump to 0.3. 573 | 574 | * Make a package. 575 | 576 | 577 | ## v0.2 (2019-04-19) 578 | 579 | * Version bump to 0.2. 580 | 581 | * Add input file paths to output. 582 | 583 | * Update README.md. 584 | 585 | * Update readme. 586 | 587 | explain simple usage 588 | 589 | * Update readme. 590 | 591 | 592 | ## v0.1.2 (2019-04-18) 593 | 594 | * Version bump to 0.1.2. 595 | 596 | * Simplify lookup of latest share path. 597 | 598 | * Fix README. 599 | 600 | 601 | ## v0.1.1 (2019-04-15) 602 | 603 | * Version bump to 0.1.1. 604 | 605 | * Add initial version. 606 | 607 | 608 | ## v0.1.0 (2019-04-13) 609 | 610 | * WIP: add VMAF. 611 | 612 | * Fix entrypoint. 613 | 614 | * Add Dockerfile. 615 | 616 | * Fix program name. 617 | 618 | * Return stdout/stderr. 619 | 620 | * Error handling for empty data. 621 | 622 | * Add verbose/dry flags. 623 | 624 | * Add choice for scaling algos. 625 | 626 | * Initial commit. 627 | 628 | 629 | -------------------------------------------------------------------------------- /DEVELOPERS.md: -------------------------------------------------------------------------------- 1 | # Developer Guide 2 | 3 | ## Updating Documentation 4 | 5 | ``` 6 | PYTHONPATH=. pdoc -o docs --docformat google ffmpeg_quality_metrics 7 | ``` 8 | 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.11-slim 2 | LABEL maintainer="Werner Robitza " 3 | LABEL name="ffmpeg_quality_metrics" 4 | 5 | RUN apt-get update -qq -y && apt-get install -qq -y \ 6 | wget \ 7 | xz-utils \ 8 | python3-pandas \ 9 | --no-install-recommends && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 10 | 11 | RUN wget -q https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz && \ 12 | tar --strip-components 1 -xf ffmpeg-git-amd64-static.tar.xz && \ 13 | cp ffmpeg /usr/bin/ffmpeg && \ 14 | cp -R model /usr/local/share/ && \ 15 | rm ffmpeg-git-amd64-static.tar.xz 16 | 17 | COPY requirements.txt . 18 | RUN pip3 install -r requirements.txt 19 | 20 | COPY ffmpeg_quality_metrics ffmpeg_quality_metrics 21 | 22 | CMD ["python3", "-m", "ffmpeg_quality_metrics"] 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FFmpeg Quality Metrics 2 | 3 | 4 | [![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors-) 5 | 6 | 7 | [![PyPI version](https://img.shields.io/pypi/v/ffmpeg-quality-metrics.svg)](https://pypi.org/project/ffmpeg-quality-metrics) 8 | 9 | [![Python package](https://github.com/slhck/ffmpeg-quality-metrics/actions/workflows/python-package.yml/badge.svg)](https://github.com/slhck/ffmpeg-quality-metrics/actions/workflows/python-package.yml) 10 | 11 | Calculate various video quality metrics with FFmpeg. 12 | 13 | Currently supports: 14 | 15 | - ✅ PSNR 16 | - ✅ SSIM 17 | - ✅ VIF 18 | - ✅ MSAD 19 | - ✅ VMAF 20 | 21 | It will output: 22 | 23 | - the per-frame metrics 24 | - global statistics (min/max/average/standard deviation) 25 | 26 | Author: Werner Robitza 27 | 28 | > [!NOTE] 29 | > 30 | > Previous versions installed a `ffmpeg_quality_metrics` executable. To harmonize it with other tools, now the executable is called `ffmpeg-quality-metrics`. Please ensure you remove the old executable (e.g. run `which ffmpeg_quality_metrics` and remove the file). 31 | 32 | **Contents:** 33 | 34 | - [Requirements](#requirements) 35 | - [Usage](#usage) 36 | - [Metrics](#metrics) 37 | - [Extended Options](#extended-options) 38 | - [VMAF-specific Settings](#vmaf-specific-settings) 39 | - [Examples](#examples) 40 | - [Running with Docker](#running-with-docker) 41 | - [Output](#output) 42 | - [JSON Output](#json-output) 43 | - [CSV Output](#csv-output) 44 | - [API](#api) 45 | - [Contributors](#contributors) 46 | - [License](#license) 47 | 48 | ------ 49 | 50 | ## Requirements 51 | 52 | What you need: 53 | 54 | - OS: Linux, macOS, Windows 55 | - Python 3.9 or higher 56 | - FFmpeg 7.1 or higher is recommended: 57 | - **Linux:** Download a build matching your platform from [here](https://github.com/BtbN/FFmpeg-Builds/releases/tag/latest). 58 | - **macOS:** Download the *snapshot* build from [here](https://evermeet.cx/ffmpeg/) or install via `brew install ffmpeg`. 59 | - **Windows:** Download an FFmpeg binary from [here](https://www.gyan.dev/ffmpeg/builds/). The `git essentials` build will suffice. 60 | 61 | Put the `ffmpeg` executable in your `$PATH`, e.g. `/usr/local/bin/ffmpeg`. 62 | 63 | If you want to calculate VMAF, your ffmpeg build should include `libvmaf`. You also need the VMAF model files, which we bundle with this package, or you can download them from the [VMAF GitHub](https://github.com/Netflix/vmaf/tree/master/model). 64 | 65 | Using pip: 66 | 67 | ```bash 68 | pip3 install ffmpeg-quality-metrics 69 | ``` 70 | 71 | Or clone this repository, then run the tool with `python3 -m ffmpeg_quality_metrics`. 72 | 73 | ## Usage 74 | 75 | In the simplest case, if you have a distorted (encoded, maybe scaled) version and the reference: 76 | 77 | ```bash 78 | ffmpeg-quality-metrics distorted.mp4 reference.y4m 79 | ``` 80 | 81 | The distorted file will be automatically scaled to the resolution of the reference, and the default metrics (PSNR, SSIM) will be computed. 82 | 83 | Note that if your distorted file is not in time sync with the reference, you can use the `--dist-delay` option to delay the distorted file by a certain amount of seconds (positive or negative). 84 | 85 | > [!NOTE] 86 | > Raw YUV files cannot be read with this tool. We should all be using lossless containers like Y4M or FFV1. If you have a raw YUV file, you can use FFmpeg to convert it to a format that this tool can read. Adjust the options as needed. 87 | > 88 | > ```bash 89 | > ffmpeg -framerate 24 -video_size 1920x1080 -pix_fmt yuv420p -i input.yuv output.y4m 90 | > ``` 91 | 92 | ### Metrics 93 | 94 | The following metrics are available in this tool: 95 | 96 | | Metric | Description | Scale | Components/Submetrics | Calculated by default? | 97 | | ------ | -------------------------------------------------------------------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | 98 | | PSNR | [Peak Signal to Noise Ratio](https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio) | dB (higher is better) | `mse_avg`
`mse_y`
`mse_u`
`mse_v`
`psnr_avg`
`psnr_y`
`psnr_u`
`psnr_v` | ✔️ | 99 | | SSIM | [Structural Similarity](https://en.wikipedia.org/wiki/Structural_similarity) | 0-100 (higher is better) | `ssim_y`
`ssim_u`
`ssim_v`
`ssim_avg` | ✔️ | 100 | | VMAF | [Video Multi-Method Assessment Fusion](https://github.com/Netflix/vmaf) | 0-100 (higher is better) | `vmaf`
`integer_adm2`
`integer_adm_scale0`
`integer_adm_scale1`
`integer_adm_scale2`
`integer_adm_scale3`
`integer_motion2`
`integer_motion`
`integer_vif_scale0`
`integer_vif_scale1`
`integer_vif_scale2`
`integer_vif_scale3` | No | 101 | | VIF | Visual Information Fidelity | 0-100 (higher is better) | `scale_0`
`scale_1`
`scale_2`
`scale_3` | No | 102 | | MSAD | Mean Sum of Absolute Differences | depends on input video, minimum is 0 (higher is worse) | `msad_y`
`msad_u`
`msad_v`
`msad_avg` | No | 103 | 104 | As shown in the table, every metric can have more than one submetric computed, and they will be printed in the output. 105 | 106 | If you want to calculate additional metrics, enable them with the `--metrics` option: 107 | 108 | ``` 109 | ffmpeg-quality-metrics distorted.mp4 reference.avi --metrics psnr ssim vmaf 110 | ``` 111 | 112 | Specify multiple metrics by separating them with a space (e.g., in the above example, `psnr ssim vmaf`). 113 | 114 | Here, VMAF uses the default model. You can specify a different model with the [`--vmaf-model` option](#specifying-vmaf-model). VMAF also allows you to calculate even [more additional features](https://github.com/Netflix/vmaf/blob/master/resource/doc/features.md) as submetrics. You can enable these with the [`--vmaf-features` option](#specifying-vmaf-model-params). 115 | 116 | ### Extended Options 117 | 118 | You can configure additional options related to scaling, speed etc. 119 | 120 | See `ffmpeg-quality-metrics -h`: 121 | 122 | ``` 123 | usage: ffmpeg-quality-metrics [-h] [-n] [-v] [-p] [-k] [--tmp-dir TMP_DIR] 124 | [-m {vmaf,psnr,ssim,vif,msad} [{vmaf,psnr,ssim,vif,msad} ...]] 125 | [-s {fast_bilinear,bilinear,bicubic,experimental,neighbor,area,bicublin,gauss,sinc,lanczos,spline}] 126 | [-r FRAMERATE] [--dist-delay DIST_DELAY] [-t THREADS] [-of {json,csv}] 127 | [--vmaf-model-path VMAF_MODEL_PATH] 128 | [--vmaf-model-params VMAF_MODEL_PARAMS [VMAF_MODEL_PARAMS ...]] 129 | [--vmaf-threads VMAF_THREADS] [--vmaf-subsample VMAF_SUBSAMPLE] 130 | [--vmaf-features VMAF_FEATURES [VMAF_FEATURES ...]] 131 | dist ref 132 | 133 | ffmpeg-quality-metrics v3.4.2 134 | 135 | positional arguments: 136 | dist input file, distorted 137 | ref input file, reference 138 | 139 | options: 140 | -h, --help show this help message and exit 141 | 142 | General options: 143 | -n, --dry-run Do not run commands, just show what would be done (default: 144 | False) 145 | -v, --verbose Show verbose output (default: False) 146 | -p, --progress Show a progress bar (default: False) 147 | -k, --keep-tmp Keep temporary files for debugging purposes (default: False) 148 | --tmp-dir TMP_DIR Directory to store temporary files in (will use system 149 | default if not specified) (default: None) 150 | 151 | Metric options: 152 | -m {vmaf,psnr,ssim,vif,msad} [{vmaf,psnr,ssim,vif,msad} ...], --metrics {vmaf,psnr,ssim,vif,msad} [{vmaf,psnr,ssim,vif,msad} ...] 153 | Metrics to calculate. Specify multiple metrics like '-- 154 | metrics ssim vmaf' (default: ['psnr', 'ssim']) 155 | 156 | FFmpeg options: 157 | -s {fast_bilinear,bilinear,bicubic,experimental,neighbor,area,bicublin,gauss,sinc,lanczos,spline}, --scaling-algorithm {fast_bilinear,bilinear,bicubic,experimental,neighbor,area,bicublin,gauss,sinc,lanczos,spline} 158 | Scaling algorithm for ffmpeg (default: bicubic) 159 | -r FRAMERATE, --framerate FRAMERATE Force an input framerate (default: None) 160 | --dist-delay DIST_DELAY Delay the distorted video against the reference by this many 161 | seconds (default: 0.0) 162 | -t THREADS, --threads THREADS Number of threads to do the calculations (default: 0) 163 | 164 | Output options: 165 | -of {json,csv}, --output-format {json,csv} 166 | Output format for the metrics (default: json) 167 | 168 | VMAF options: 169 | --vmaf-model-path VMAF_MODEL_PATH Use a specific VMAF model file. If none is chosen, picks a 170 | default model. You can also specify one of the following 171 | built-in models: ['vmaf_v0.6.1.json', 'vmaf_4k_v0.6.1.json', 172 | 'vmaf_v0.6.1neg.json'] (default: /opt/homebrew/opt/libvmaf/s 173 | hare/libvmaf/model/vmaf_v0.6.1.json) 174 | --vmaf-model-params VMAF_MODEL_PARAMS [VMAF_MODEL_PARAMS ...] 175 | A list of params to pass to the VMAF model, specified as 176 | key=value. Specify multiple params like '--vmaf-model-params 177 | enable_transform=true enable_conf_interval=true' (default: 178 | None) 179 | --vmaf-threads VMAF_THREADS Set the value of libvmaf's n_threads option. This determines 180 | the number of threads that are used for VMAF calculation. 181 | Set to 0 for auto. (default: 0) 182 | --vmaf-subsample VMAF_SUBSAMPLE Set the value of libvmaf's n_subsample option. This is the 183 | subsampling interval, so set to 1 for default behavior. 184 | (default: 1) 185 | --vmaf-features VMAF_FEATURES [VMAF_FEATURES ...] 186 | A list of feature to enable. Pass the names of the features 187 | and any optional params. See https://github.com/Netflix/vmaf 188 | /blob/master/resource/doc/features.md for a list of 189 | available features. Params must be specified as 'key=value'. 190 | Multiple params must be separated by ':'. Specify multiple 191 | features like '--vmaf-features cambi:full_ref=true ciede' 192 | (default: None) 193 | ``` 194 | 195 | ### VMAF-specific Settings 196 | 197 | As VMAF is more complex than the other metrics, it has a few more options. 198 | 199 | #### Specifying VMAF Model 200 | 201 | Use the `--vmaf-model-path` option to set the path to a different VMAF model file. The default is `vmaf_v0.6.1.json`. 202 | 203 | `libvmaf` version 2.x supports JSON-based model files only. This program has built-in support for the following models: 204 | 205 | ``` 206 | vmaf_v0.6.1.json 207 | vmaf_4k_v0.6.1.json 208 | vmaf_v0.6.1neg.json 209 | ``` 210 | 211 | Use the `4k` version if you have a 4K reference sample. The `neg` version [is explained here](https://netflixtechblog.com/toward-a-better-quality-metric-for-the-video-community-7ed94e752a30). 212 | 213 | You can either specify an absolute path to an existing model, e.g.: 214 | 215 | ``` 216 | /usr/local/opt/libvmaf/share/model/vmaf_v0.6.1neg.json 217 | ``` 218 | 219 | Or pass the file name to the built-in model. So all of these work: 220 | 221 | ```bash 222 | # use a downloaded JSON model for libvmaf 2.x 223 | ffmpeg-quality-metrics dist.mkv ref.mkv -m vmaf --vmaf-model-path vmaf_v0.6.1neg.json 224 | 225 | # use a different path for models on your system 226 | ffmpeg-quality-metrics dist.mkv ref.mkv -m vmaf --vmaf-model-path /usr/local/opt/libvmaf/share/model/vmaf_v0.6.1neg.json 227 | ``` 228 | 229 | #### Specifying VMAF Features 230 | 231 | VMAF includes several metrics, each of which correspond to a feature name. By default, only three core features are used. Use the `--vmaf-features` option to enable additional features on top of the core features. 232 | 233 | The following table shows the available features: 234 | 235 | | Metric | Feature name | Core feature in VMAF? | 236 | | --------- | --------------- | --------------------- | 237 | | PSNR | `psnr` | | 238 | | PSNR-HVS | `psnr_hvs` | | 239 | | CIEDE2000 | `ciede` | | 240 | | CAMBI | `cambi` | | 241 | | VIF | `vif` | ✔️ | 242 | | ADM | `adm` | ✔️ | 243 | | Motion | `motion` | ✔️ | 244 | | SSIM | `float_ssim` | | 245 | | MS-SSIM | `float_ms_ssim` | | 246 | 247 | To find out more about the features, check out the [VMAF documentation](https://github.com/Netflix/vmaf/blob/master/resource/doc/features.md). 248 | 249 | For example, to enable the CAMBI feature, use: 250 | 251 | ```bash 252 | ffmpeg-quality-metrics dist.mkv ref.mkv -m vmaf --vmaf-features cambi 253 | ``` 254 | 255 | To enable more than one feature, separate them with a space: 256 | 257 | ```bash 258 | ffmpeg-quality-metrics dist.mkv ref.mkv -m vmaf --vmaf-features cambi psnr 259 | ``` 260 | 261 | #### VMAF Feature Parameters 262 | 263 | Some features additionally take a number of optional parameters. The following table shows the available parameters for each feature: 264 | 265 | | Feature | Parameter | Default | Description | 266 | | --------- | ------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------- | 267 | | `adm` | `adm_csf_mode` | `0` | Contrast sensitivity function | 268 | | `adm` | `adm_enhn_gain_limit` | `100.0` | Enhancement gain imposed on adm, must be >= 1.0, where 1.0 means the gain is completely disabled | 269 | | `adm` | `adm_norm_view_dist` | `3.0` | Normalized viewing distance = viewing distance / ref display's physical height | 270 | | `adm` | `adm_ref_display_height` | `1080` | Reference display height in pixels | 271 | | `adm` | `debug` | `false` | Debug mode: enable additional output | 272 | | `cambi` | `enc_bitdepth` | | Encoding bitdepth. | 273 | | `cambi` | `enc_height` | | Encoding height. | 274 | | `cambi` | `enc_width` | | Encoding width. | 275 | | `cambi` | `eotf` | `bt1886` | Determines the EOTF used to compute the visibility thresholds. | 276 | | `cambi` | `full_ref` | `false` | Set to `true` to enable full-reference CAMBI calculation. | 277 | | `cambi` | `heatmaps_path` | | Set to a target folder where the CAMBI heatmaps will be stored as `.gray` files | 278 | | `cambi` | `max_log_contrast` | `2` | Maximum contrast in log luma level (2^max_log_contrast) at 10-bits. | 279 | | `cambi` | `src_height` | | Source height. Only used when full_ref=true. | 280 | | `cambi` | `src_width` | | Source width. Only used when full_ref=true. | 281 | | `cambi` | `topk` | `0.2` | Ratio of pixels for the spatial pooling computation. | 282 | | `cambi` | `tvi_threshold` | `0.75` | Visibility threshold for luminance ΔL < tvi_threshold*L_mean. | 283 | | `cambi` | `window_size` | `63` | Window size to compute CAMBI: 63 corresponds to ~1 degree at 4k. | 284 | | `motion` | `debug` | `true` | Enable additional output for debugging. | 285 | | `motion` | `motion_force_zero` | `false` | Force the motion score to be zero. This parameter is a feature-specific parameter. | 286 | | `ms_ssim` | `clip_db` | `false` | Clip dB scores | 287 | | `ms_ssim` | `enable_db` | `false` | Write MS-SSIM values as dB | 288 | | `ms_ssim` | `enable_lcs` | `false` | Enable luminance, contrast and structure intermediate output | 289 | | `ssim` | `clip_db` | `false` | Clip dB scores | 290 | | `ssim` | `enable_db` | `false` | Write SSIM values as dB | 291 | | `ssim` | `enable_lcs` | `false` | Enable luminance, contrast and structure intermediate output | 292 | | `vif` | `debug` | `false` | Debug mode: enable additional output | 293 | | `vif` | `vif_enhn_gain_limit` | `100.0` | Enhancement gain imposed on vif, must be >= 1.0, where 1.0 means the gain is completely disabled | 294 | | `vif` | `vif_kernelscale` | `1.0` | Scaling factor for the gaussian kernel (2.0 means multiplying the standard deviation by 2 and enlarge the kernel size accordingly) | 295 | 296 | The parameters are specified as `key=value` pairs, separated by `:`. For example, to enable the full-reference CAMBI calculation, use: 297 | 298 | ```bash 299 | ffmpeg-quality-metrics dist.mkv ref.mkv -m vmaf --vmaf-features cambi:full_ref=true 300 | ``` 301 | 302 | To generate the CAMBI heatmaps, use: 303 | 304 | ```bash 305 | ffmpeg-quality-metrics dist.mkv ref.mkv -m vmaf --vmaf-features cambi:heatmaps_path=/tmp/cambi 306 | ``` 307 | 308 | #### VMAF Model Parameters 309 | 310 | These parameters control the VMAF model itself (not the features). 311 | 312 | | Parameter | Description | Default | 313 | | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | 314 | | `enable_transform` | Enable the transform feature, which transforms the scores to represent quality as perceived on a phone ([used to be called `phone_model`](https://github.com/Netflix/vmaf/blob/master/resource/doc/models.md#predict-quality-on-a-cellular-phone-screen)) | `false` | 315 | | `enable_conf_interval` | Enable the [confidence interval calculation](https://github.com/Netflix/vmaf/blob/master/resource/doc/conf_interval.md) | `false` | 316 | 317 | To specify these parameters, use the `--vmaf-model-params` option, and separate each parameter with a space. For example: 318 | 319 | ```bash 320 | ffmpeg-quality-metrics dist.mkv ref.mkv -m vmaf --vmaf-model-params enable_transform=true enable_conf_interval=true 321 | ``` 322 | 323 | > [!NOTE] 324 | > 325 | > The `enable_conf_interval` parameter currently does not change the output. 326 | 327 | ## Examples 328 | 329 | Run PSNR, SSIM, VMAF and VIF at the same time: 330 | 331 | ```bash 332 | ffmpeg-quality-metrics dist.mkv ref.mkv \ 333 | -m psnr ssim vmaf vif 334 | ``` 335 | 336 | Run VMAF with all the features: 337 | 338 | ```bash 339 | ffmpeg-quality-metrics dist.mkv ref.mkv \ 340 | -m vmaf \ 341 | --vmaf-features ciede cambi psnr psnr_hvs motion adm vif 342 | ``` 343 | 344 | Enable feature options for CAMBI full-reference calculation: 345 | 346 | ```bash 347 | ffmpeg-quality-metrics dist.mkv ref.mkv \ 348 | -m vmaf \ 349 | --vmaf-features cambi:full_ref=true 350 | ``` 351 | 352 | ## Running with Docker 353 | 354 | If you don't want to deal with dependencies, build the image with Docker: 355 | 356 | ``` 357 | docker build -t ffmpeg-quality-metrics . 358 | ``` 359 | 360 | This takes a few minutes and installs the latest `ffmpeg` [as a static build](https://johnvansickle.com/ffmpeg/). 361 | 362 | You can then run the container, which basically calls the Python script. To help you with mounting the volumes (since your videos are not stored in the container), you can run a helper script: 363 | 364 | ```bash 365 | ./docker_run.sh [OPTIONS] 366 | ``` 367 | 368 | Check the output of `./docker_run.sh` for more help. 369 | 370 | For example, to run the tool with the bundled test videos and enable VMAF calculation: 371 | 372 | ```bash 373 | ./docker_run.sh test/dist-854x480.mkv test/ref-1280x720.mkv -m vmaf 374 | ``` 375 | 376 | ## Output 377 | 378 | This tool supports JSON or CSV output, including individual fields for planes/components/submetrics, and global statistics, as well as frame numbers (`n`). 379 | 380 | ### JSON Output 381 | 382 | The JSON output will include a key for each metric, and the value will be a list of values for each frame. Each frame is a dictionary with individual metrics per frame. 383 | 384 | For instance, PSNR and SSIM output averages as well as per-component metrics. VMAF outputs different metrics depending on the enabled features. 385 | 386 | The `global` key contains global statistics for each metric and its submetrics. 387 | 388 | See the [`example.json`](test/example.json) file for an example of the output. 389 | 390 | ### CSV Output 391 | 392 | CSV output is using the [tidy data](https://cran.r-project.org/web/packages/tidyr/vignettes/tidy-data.html) principle, using one column per feature and one line per frame (observation). 393 | 394 | Example: 395 | 396 | ```csv 397 | n,adm2,motion2,ms_ssim,psnr,ssim,vif_scale0,vif_scale1,vif_scale2,vif_scale3,vmaf,mse_avg,mse_u,mse_v,mse_y,psnr_avg,psnr_u,psnr_v,psnr_y,ssim_avg,ssim_u,ssim_v,ssim_y,input_file_dist,input_file_ref 398 | 1,0.70704,0.0,0.89698,18.58731,0.92415,0.53962,0.71805,0.75205,0.77367,15.44212,536.71,234.48,475.43,900.22,20.83,24.43,21.36,18.59,0.945,0.96,0.942,0.934,test/dist-854x480.mkv,test/ref-1280x720.mkv 399 | 2,0.7064,0.35975,0.89806,18.60299,0.9247,0.54025,0.71961,0.75369,0.77607,15.85038,535.29,239.4,469.49,896.98,20.84,24.34,21.41,18.6,0.946,0.96,0.943,0.934,test/dist-854x480.mkv,test/ref-1280x720.mkv 400 | 3,0.70505,0.35975,0.89879,18.6131,0.92466,0.5391,0.71869,0.75344,0.77616,15.63546,535.04,245.8,464.43,894.89,20.85,24.22,21.46,18.61,0.945,0.959,0.943,0.934,test/dist-854x480.mkv,test/ref-1280x720.mkv 401 | ``` 402 | 403 | As there is no tidy way to represent global data in the same CSV file, you can use other tools to aggregate the data. 404 | 405 | ## API 406 | 407 | The program exposes an API that you can use yourself: 408 | 409 | ```python 410 | from ffmpeg_quality_metrics import FfmpegQualityMetrics 411 | 412 | ffqm = FfmpegQualityMetrics("path/to/reference-video.mp4", "path/to/distorted-video.mp4") 413 | 414 | metrics = ffqm.calculate(["ssim", "psnr"]) 415 | 416 | # check the available metrics 417 | print(metrics.keys()) 418 | # ['ssim', 'psnr'] 419 | 420 | # get the SSIM values for the first frame 421 | print(metrics["ssim"][0]) 422 | # {'n': 1, 'ssim_y': 0.934, 'ssim_u': 0.96, 'ssim_v': 0.942, 'ssim_avg': 0.945} 423 | 424 | # average the ssim_y values over all frames 425 | print(sum([frame["ssim_y"] for frame in metrics["ssim"]]) / len(metrics["ssim"])) 426 | 427 | # or just get the global stats 428 | print(ffqm.get_global_stats()["ssim"]["ssim_y"]["average"]) 429 | ``` 430 | 431 | For more usage please read [the docs](https://htmlpreview.github.io/?https://github.com/slhck/ffmpeg-quality-metrics/blob/master/docs/ffmpeg_quality_metrics.html). 432 | 433 | ## Contributors 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 |
Orkun Koçyiğit
Orkun Koçyiğit

💻
Hamas Shafiq
Hamas Shafiq

💻
Chris Griffith
Chris Griffith

💻
Ignacio Peletier
Ignacio Peletier

💻
Nav
Nav

🐛
449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | ## License 463 | 464 | ffmpeg-quality-metrics, Copyright (c) 2019-2024 Werner Robitza 465 | 466 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 467 | 468 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 469 | 470 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 471 | 472 | For VMAF models, see `ffmpeg_quality_metrics/vmaf_models/LICENSE`. 473 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.3.8 2 | -------------------------------------------------------------------------------- /docker_run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Helper script to run Docker container 4 | 5 | py_usage() { 6 | docker run \ 7 | -t ffmpeg-quality-metrics:latest \ 8 | python3 -m ffmpeg_quality_metrics -h 9 | } 10 | 11 | usage() { 12 | echo "Usage: $0 [OPTIONS]" 13 | echo 14 | echo " -- distorted video" 15 | echo " -- reference video" 16 | echo " [OPTIONS] -- further options passed to ffmpeg_quality_metrics.py, see below" 17 | echo 18 | py_usage 19 | exit 1 20 | } 21 | 22 | if [ $# -lt 2 ]; then 23 | usage 24 | fi 25 | 26 | distFile="$1" 27 | refFile="$2" 28 | 29 | distFileBasename="$(basename $1)" 30 | refFileBasename="$(basename $2)" 31 | 32 | distDir="$(realpath "$(dirname "$1")")" 33 | refDir="$(realpath "$(dirname "$2")")" 34 | 35 | shift; shift 36 | 37 | if ! docker image inspect ffmpeg-quality-metrics:latest > /dev/null 2>&1; then 38 | echo "Image 'ffmpeg-quality-metrics:latest' not found, building it first ..." 39 | docker build -t ffmpeg-quality-metrics:latest . 40 | fi 41 | 42 | docker run \ 43 | --rm \ 44 | -v "$distDir":"/tmp/dist" \ 45 | -v "$refDir":"/tmp/ref" \ 46 | -t ffmpeg-quality-metrics:latest \ 47 | python3 -m ffmpeg_quality_metrics \ 48 | "/tmp/dist/$distFileBasename" \ 49 | "/tmp/ref/$refFileBasename" \ 50 | "$@" 51 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ffmpeg_quality_metrics/__init__.py: -------------------------------------------------------------------------------- 1 | from .ffmpeg_quality_metrics import ( 2 | FfmpegQualityMetrics, 3 | FfmpegQualityMetricsError, 4 | GlobalStats, 5 | GlobalStatsData, 6 | MetricData, 7 | MetricName, 8 | SingleMetricData, 9 | VmafOptions, 10 | ) 11 | 12 | __version__ = "3.5.0" 13 | __all__ = [ 14 | "FfmpegQualityMetrics", 15 | "FfmpegQualityMetricsError", 16 | "VmafOptions", 17 | "MetricName", 18 | "SingleMetricData", 19 | "GlobalStatsData", 20 | "GlobalStats", 21 | "MetricData", 22 | "__version__", 23 | ] 24 | -------------------------------------------------------------------------------- /ffmpeg_quality_metrics/__main__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # ffmpeg-quality-metrics 4 | # Author: Werner Robitza 5 | # License: MIT 6 | 7 | import argparse 8 | import logging 9 | import sys 10 | import traceback 11 | 12 | from .__init__ import __version__ as version 13 | from .ffmpeg_quality_metrics import FfmpegQualityMetrics, VmafOptions 14 | from .log import CustomLogFormatter 15 | 16 | logger = logging.getLogger("ffmpeg-quality-metrics") 17 | 18 | 19 | def setup_logger(level: int = logging.INFO) -> logging.Logger: 20 | logger = logging.getLogger("ffmpeg-quality-metrics") 21 | logger.setLevel(level) 22 | 23 | ch = logging.StreamHandler(sys.stderr) 24 | ch.setLevel(level) 25 | 26 | ch.setFormatter(CustomLogFormatter()) 27 | 28 | logger.addHandler(ch) 29 | 30 | return logger 31 | 32 | 33 | def main() -> None: 34 | parser = argparse.ArgumentParser( 35 | formatter_class=lambda prog: argparse.ArgumentDefaultsHelpFormatter( 36 | prog, max_help_position=40, width=100 37 | ), 38 | description="ffmpeg-quality-metrics v" + version, 39 | prog="ffmpeg-quality-metrics", 40 | ) 41 | parser.add_argument("dist", help="input file, distorted") 42 | parser.add_argument("ref", help="input file, reference") 43 | 44 | general_opts = parser.add_argument_group("General options") 45 | 46 | general_opts.add_argument( 47 | "-n", 48 | "--dry-run", 49 | action="store_true", 50 | help="Do not run commands, just show what would be done", 51 | ) 52 | general_opts.add_argument( 53 | "-v", "--verbose", action="store_true", help="Show verbose output" 54 | ) 55 | general_opts.add_argument( 56 | "-p", "--progress", action="store_true", help="Show a progress bar" 57 | ) 58 | general_opts.add_argument( 59 | "-k", 60 | "--keep-tmp", 61 | action="store_true", 62 | help="Keep temporary files for debugging purposes", 63 | ) 64 | general_opts.add_argument( 65 | "--tmp-dir", 66 | type=str, 67 | default=None, 68 | help="Directory to store temporary files in (will use system default if not specified)", 69 | ) 70 | 71 | metric_options = parser.add_argument_group("Metric options") 72 | 73 | metric_options.add_argument( 74 | "-m", 75 | "--metrics", 76 | default=["psnr", "ssim"], 77 | help="Metrics to calculate. Specify multiple metrics like '--metrics ssim vmaf'", 78 | nargs="+", 79 | choices=FfmpegQualityMetrics.METRIC_TO_FILTER_MAP.keys(), 80 | ) 81 | 82 | ffmpeg_opts = parser.add_argument_group("FFmpeg options") 83 | 84 | ffmpeg_opts.add_argument( 85 | "-s", 86 | "--scaling-algorithm", 87 | default="bicubic", 88 | choices=FfmpegQualityMetrics.ALLOWED_SCALERS, 89 | help="Scaling algorithm for ffmpeg", 90 | ) 91 | 92 | ffmpeg_opts.add_argument( 93 | "-r", 94 | "--framerate", 95 | type=float, 96 | help="Force an input framerate", 97 | ) 98 | 99 | ffmpeg_opts.add_argument( 100 | "--dist-delay", 101 | type=float, 102 | default=0.0, 103 | help="Delay the distorted video against the reference by this many seconds", 104 | ) 105 | 106 | ffmpeg_opts.add_argument( 107 | "-t", 108 | "--threads", 109 | type=int, 110 | default=FfmpegQualityMetrics.DEFAULT_THREADS, 111 | help="Number of threads to do the calculations", 112 | ) 113 | 114 | output_opts = parser.add_argument_group("Output options") 115 | 116 | output_opts.add_argument( 117 | "-of", 118 | "--output-format", 119 | type=str, 120 | default="json", 121 | choices=["json", "csv"], 122 | help="Output format for the metrics", 123 | ) 124 | 125 | vmaf_opts = parser.add_argument_group("VMAF options") 126 | 127 | vmaf_opts.add_argument( 128 | "--vmaf-model-path", 129 | type=str, 130 | default=FfmpegQualityMetrics.get_default_vmaf_model_path(), 131 | help="Use a specific VMAF model file. If none is chosen, picks a default model. " 132 | f"You can also specify one of the following built-in models: {FfmpegQualityMetrics.get_supplied_vmaf_models()}", 133 | ) 134 | 135 | vmaf_opts.add_argument( 136 | "--vmaf-model-params", 137 | type=str, 138 | nargs="+", 139 | help="A list of params to pass to the VMAF model, specified as key=value. " 140 | "Specify multiple params like '--vmaf-model-params enable_transform=true enable_conf_interval=true'", 141 | ) 142 | 143 | vmaf_opts.add_argument( 144 | "--vmaf-threads", 145 | type=int, 146 | default=FfmpegQualityMetrics.DEFAULT_VMAF_THREADS, 147 | help="Set the value of libvmaf's n_threads option. " 148 | "This determines the number of threads that are used for VMAF calculation. " 149 | "Set to 0 for auto.", 150 | ) 151 | 152 | vmaf_opts.add_argument( 153 | "--vmaf-subsample", 154 | type=int, 155 | default=FfmpegQualityMetrics.DEFAULT_VMAF_SUBSAMPLE, 156 | help="Set the value of libvmaf's n_subsample option. " 157 | "This is the subsampling interval, so set to 1 for default behavior.", 158 | ) 159 | 160 | vmaf_opts.add_argument( 161 | "--vmaf-features", 162 | type=str, 163 | nargs="+", 164 | help="A list of feature to enable. Pass the names of the features and any optional params. " 165 | "See https://github.com/Netflix/vmaf/blob/master/resource/doc/features.md for a list of available features. " 166 | "Params must be specified as 'key=value'. " 167 | "Multiple params must be separated by ':'. " 168 | "Specify multiple features like '--vmaf-features cambi:full_ref=true ciede'", 169 | ) 170 | 171 | cli_args = parser.parse_args() 172 | 173 | setup_logger(logging.DEBUG if cli_args.verbose else logging.INFO) 174 | 175 | ffqm = FfmpegQualityMetrics( 176 | ref=cli_args.ref, 177 | dist=cli_args.dist, 178 | scaling_algorithm=cli_args.scaling_algorithm, 179 | framerate=cli_args.framerate, 180 | dist_delay=cli_args.dist_delay, 181 | dry_run=cli_args.dry_run, 182 | verbose=cli_args.verbose, 183 | threads=cli_args.threads, 184 | progress=cli_args.progress, 185 | keep_tmp_files=cli_args.keep_tmp, 186 | tmp_dir=cli_args.tmp_dir, 187 | ) 188 | 189 | metrics = cli_args.metrics 190 | 191 | if "vmaf" in metrics: 192 | vmaf_options: VmafOptions = { 193 | "model_path": cli_args.vmaf_model_path, 194 | "model_params": cli_args.vmaf_model_params, 195 | "n_threads": cli_args.vmaf_threads, 196 | "n_subsample": cli_args.vmaf_subsample, 197 | "features": cli_args.vmaf_features, 198 | } 199 | ffqm.calculate(metrics, vmaf_options=vmaf_options) 200 | else: 201 | ffqm.calculate(metrics) 202 | 203 | if cli_args.dry_run: 204 | logger.warning("Dry run specified, exiting without computing stats") 205 | return 206 | 207 | if cli_args.output_format == "json": 208 | print(ffqm.get_results_json()) 209 | elif cli_args.output_format == "csv": 210 | print(ffqm.get_results_csv()) 211 | else: 212 | logger.error("Wrong output format chosen, use 'json' or 'csv'") 213 | sys.exit(1) 214 | 215 | 216 | if __name__ == "__main__": 217 | try: 218 | main() 219 | except Exception as e: 220 | logger.error(f"General exception: {e}") 221 | # print a stacktrace 222 | traceback.print_exc() 223 | sys.exit(1) 224 | -------------------------------------------------------------------------------- /ffmpeg_quality_metrics/ffmpeg_quality_metrics.py: -------------------------------------------------------------------------------- 1 | # ffmpeg-quality-metrics 2 | # Author: Werner Robitza 3 | # License: MIT 4 | 5 | import json 6 | import logging 7 | import os 8 | import re 9 | import tempfile 10 | from functools import reduce 11 | from typing import Dict, List, Literal, Optional, Tuple, TypedDict, Union, cast 12 | 13 | import numpy as np 14 | import pandas as pd 15 | from ffmpeg_progress_yield import FfmpegProgress 16 | from packaging.version import Version 17 | from packaging.version import parse as parse_version 18 | from tqdm import tqdm 19 | 20 | from .utils import ( 21 | NUL, 22 | ffmpeg_is_from_brew, 23 | has_brew, 24 | quoted_cmd, 25 | run_command, 26 | win_path_check, 27 | win_vmaf_model_path_check, 28 | ) 29 | 30 | logger = logging.getLogger("ffmpeg-quality-metrics") 31 | 32 | # ===================================================================================================================== 33 | # TYPE DEFINITIONS 34 | 35 | 36 | class VmafOptions(TypedDict): 37 | """ 38 | VMAF-specific options. 39 | """ 40 | 41 | model_path: Union[str, None] 42 | """Use a specific VMAF model file. If none is chosen, picks a default model.""" 43 | model_params: List[str] 44 | """A list of params to pass to the VMAF model, specified as key=value.""" 45 | n_threads: Union[int, None] 46 | """Number of threads to use. Defaults to 0 (auto).""" 47 | n_subsample: Union[int, None] 48 | """Subsampling interval. Defaults to 1.""" 49 | features: List[str] 50 | """ 51 | List of features to enable in addition to the default features. 52 | Each entry must be a string beginning with name=feature_name, and additional parameters can be specified as 53 | key=value, separated by colons. 54 | """ 55 | 56 | 57 | MetricName = Literal["psnr", "ssim", "vmaf", "vif", "msad"] 58 | """The name of a metric.""" 59 | 60 | FilterName = Literal["psnr", "ssim", "libvmaf", "vif", "msad"] 61 | """The name of an ffmpeg filter used for that metric.""" 62 | 63 | SingleMetricData = List[Dict[str, float]] 64 | """A per-frame list of metric values.""" 65 | 66 | GlobalStatsData = Dict[str, float] 67 | """A dict of global stats for a metric.""" 68 | 69 | GlobalStats = Dict[MetricName, Dict[str, GlobalStatsData]] 70 | """A dict of global stats for all metrics.""" 71 | 72 | MetricData = Dict[MetricName, SingleMetricData] 73 | """A dict of per-frame metric values for all metrics.""" 74 | 75 | 76 | # ===================================================================================================================== 77 | # MAIN CLASSES 78 | 79 | 80 | class FfmpegQualityMetricsError(Exception): 81 | pass 82 | 83 | 84 | class FfmpegQualityMetrics: 85 | """ 86 | A class to calculate quality metrics with FFmpeg 87 | """ 88 | 89 | ALLOWED_SCALERS = [ 90 | "fast_bilinear", 91 | "bilinear", 92 | "bicubic", 93 | "experimental", 94 | "neighbor", 95 | "area", 96 | "bicublin", 97 | "gauss", 98 | "sinc", 99 | "lanczos", 100 | "spline", 101 | ] 102 | DEFAULT_SCALER = "bicubic" 103 | DEFAULT_THREADS = 0 104 | 105 | DEFAULT_VMAF_THREADS = 0 # used to be os.cpu_count(), now auto 106 | DEFAULT_VMAF_SUBSAMPLE = 1 # sample every frame 107 | DEFAULT_VMAF_MODEL_DIRECTORY = os.path.join( 108 | os.path.dirname(__file__), "vmaf_models" 109 | ) 110 | DEFAULT_VMAF_OPTIONS: VmafOptions = { 111 | "model_path": None, 112 | "model_params": [], 113 | "n_threads": DEFAULT_VMAF_THREADS, 114 | "n_subsample": DEFAULT_VMAF_SUBSAMPLE, 115 | "features": [], 116 | } 117 | POSSIBLE_FILTERS: List[FilterName] = [ 118 | "libvmaf", 119 | "psnr", 120 | "ssim", 121 | "vif", 122 | "msad", 123 | ] 124 | METRIC_TO_FILTER_MAP: Dict[MetricName, FilterName] = { 125 | "vmaf": "libvmaf", 126 | "psnr": "psnr", 127 | "ssim": "ssim", 128 | "vif": "vif", 129 | "msad": "msad", 130 | } 131 | 132 | def __init__( 133 | self, 134 | ref: str, 135 | dist: str, 136 | scaling_algorithm: str = DEFAULT_SCALER, 137 | framerate: Union[float, None] = None, 138 | dist_delay: float = 0, 139 | dry_run: Union[bool, None] = False, 140 | verbose: Union[bool, None] = False, 141 | threads: int = DEFAULT_THREADS, 142 | progress: Union[bool, None] = False, 143 | keep_tmp_files: Union[bool, None] = False, 144 | tmp_dir: Union[str, None] = None, 145 | ): 146 | """Instantiate a new FfmpegQualityMetrics 147 | 148 | Args: 149 | ref (str): reference file 150 | dist (str): distorted file 151 | scaling_algorithm (str, optional): A scaling algorithm. Must be one of the following: ["fast_bilinear", "bilinear", "bicubic", "experimental", "neighbor", "area", "bicublin", "gauss", "sinc", "lanczos", "spline"]. Defaults to "bicubic" 152 | framerate (float, optional): Force a frame rate. Defaults to None. 153 | dist_delay (float): Delay the distorted file against the reference by this amount of seconds. Defaults to 0. 154 | dry_run (bool, optional): Don't run anything, just print commands. Defaults to False. 155 | verbose (bool, optional): Show more output. Defaults to False. 156 | threads (int, optional): Number of ffmpeg threads. Defaults to 0 (auto). 157 | progress (bool, optional): Show a progress bar. Defaults to False. 158 | keep_tmp_files (bool, optional): Keep temporary files for debugging purposes. Defaults to False. 159 | tmp_dir (str, optional): Directory to store temporary files. Will use system default if not specified. Defaults to None. 160 | 161 | Raises: 162 | FfmpegQualityMetricsError: A generic error 163 | """ 164 | self.ref = str(ref) 165 | self.dist = str(dist) 166 | self.scaling_algorithm = str(scaling_algorithm) 167 | self.framerate = float(framerate) if framerate is not None else None 168 | self.dist_delay = float(dist_delay) 169 | self.dry_run = bool(dry_run) 170 | self.verbose = bool(verbose) 171 | self.threads = int(threads) 172 | self.progress = bool(progress) 173 | self.keep_tmp_files = bool(keep_tmp_files) 174 | self.tmp_dir = str(tmp_dir) if tmp_dir is not None else tempfile.gettempdir() 175 | 176 | if not os.path.isfile(self.ref): 177 | raise FfmpegQualityMetricsError(f"Reference file not found: {self.ref}") 178 | if not os.path.isfile(self.dist): 179 | raise FfmpegQualityMetricsError(f"Distorted file not found: {self.dist}") 180 | 181 | if self.ref == self.dist: 182 | logger.warning( 183 | "Reference and distorted files are the same! This may lead to unexpected results or numerical issues." 184 | ) 185 | 186 | if ref.endswith(".yuv") or dist.endswith(".yuv"): 187 | raise FfmpegQualityMetricsError( 188 | "YUV files are not supported, please convert to a format that ffmpeg can read natively, such as Y4M or FFV1." 189 | ) 190 | 191 | self.data: MetricData = { 192 | "vmaf": [], 193 | "psnr": [], 194 | "ssim": [], 195 | "vif": [], 196 | "msad": [], 197 | } 198 | 199 | self.available_filters: List[str] = [] 200 | 201 | self.global_stats: GlobalStats = {} 202 | 203 | if not os.path.isdir(self.tmp_dir): 204 | logger.debug(f"Creating temporary directory: {self.tmp_dir}") 205 | os.makedirs(self.tmp_dir) 206 | self.temp_files: Dict[FilterName, str] = {} 207 | 208 | for filter_name in self.POSSIBLE_FILTERS: 209 | suffix = "txt" if filter_name != "libvmaf" else "json" 210 | 211 | self.temp_files[cast(FilterName, filter_name)] = os.path.join( 212 | self.tmp_dir, 213 | f"ffmpeg_quality_metrics_{filter_name}_{os.path.basename(self.ref)}_{os.path.basename(self.dist)}.{suffix}", 214 | ) 215 | logger.debug( 216 | f"Writing temporary {filter_name.upper()} information to: {self.temp_files[cast(FilterName, filter_name)]}" 217 | ) 218 | 219 | if scaling_algorithm not in self.ALLOWED_SCALERS: 220 | raise FfmpegQualityMetricsError( 221 | f"Allowed scaling algorithms: {self.ALLOWED_SCALERS}" 222 | ) 223 | 224 | self._check_available_filters() 225 | 226 | def _check_available_filters(self): 227 | """ 228 | Check which filters are available 229 | """ 230 | cmd = ["ffmpeg", "-filters"] 231 | stdout, _ = run_command(cmd) 232 | filter_list = [] 233 | for line in stdout.split("\n"): 234 | line = line.strip() 235 | if line == "": 236 | continue 237 | cols = line.split(" ") 238 | if len(cols) > 1: 239 | filter_name = cols[1] 240 | filter_list.append(filter_name) 241 | 242 | for key in FfmpegQualityMetrics.POSSIBLE_FILTERS: 243 | if key in filter_list: 244 | self.available_filters.append(key) 245 | 246 | logger.debug(f"Available filters: {self.available_filters}") 247 | 248 | @staticmethod 249 | def get_ffmpeg_version() -> Optional[Version]: 250 | """ 251 | Get the version of ffmpeg 252 | """ 253 | cmd = ["ffmpeg", "-version"] 254 | stdout, _ = run_command(cmd) 255 | # $ ffmpeg -version 256 | # ffmpeg version 7.1.1 Copyright (c) 2000-2025 the FFmpeg developers 257 | # ... 258 | # 259 | # or sometimes: 260 | # ffmpeg version n7.1-latest-linux64-gpl-7.1 261 | version_str = stdout.split("\n")[0].split(" ")[2] 262 | 263 | # Clean the version string by removing the "-static" suffix if it exists 264 | version_str = version_str.split("-")[0] 265 | 266 | # Clean a "n" at the beginning of the version string if it exists 267 | version_str = version_str.lstrip("n") 268 | 269 | try: 270 | return parse_version(version_str) 271 | except Exception: 272 | logger.warning(f"Could not parse ffmpeg version: {version_str}") 273 | return None 274 | 275 | @staticmethod 276 | def get_framerate(input_file: str) -> float: 277 | """Parse the FPS from the input file. 278 | 279 | Args: 280 | input_file (str): Input file path 281 | 282 | Raises: 283 | FfmpegQualityMetricsError: A generic error 284 | 285 | Returns: 286 | float: The FPS parsed 287 | """ 288 | cmd = ["ffmpeg", "-nostdin", "-y", "-i", input_file] 289 | 290 | output = run_command(cmd, allow_error=True) 291 | pattern = re.compile(r"(\d+(\.\d+)?) fps") 292 | try: 293 | if pattern_ret := pattern.search(str(output)): 294 | match = pattern_ret.groups()[0] 295 | return float(match) 296 | except Exception: 297 | pass 298 | 299 | raise FfmpegQualityMetricsError(f"could not parse FPS from file {input_file}!") 300 | 301 | def _get_framerates(self) -> Tuple[float, float]: 302 | """ 303 | Get the framerates of the reference and distorted files. 304 | 305 | Returns: 306 | Tuple[float, float]: The framerates of the reference and distorted files 307 | """ 308 | ref_framerate = FfmpegQualityMetrics.get_framerate(self.ref) 309 | dist_framerate = FfmpegQualityMetrics.get_framerate(self.dist) 310 | 311 | if ref_framerate != dist_framerate: 312 | logger.warning( 313 | f"ref, dist framerates differ: {ref_framerate}, {dist_framerate}. " 314 | "This may result in inaccurate quality metrics. Force an input framerate via the -r option." 315 | ) 316 | 317 | return ref_framerate, dist_framerate 318 | 319 | def _get_filter_opts(self, filter_name: FilterName) -> str: 320 | """ 321 | Returns: 322 | str: Specific ffmpeg filter options for a chosen metric filter. 323 | """ 324 | if filter_name in ["ssim", "psnr"]: 325 | return f"{filter_name}='{win_path_check(self.temp_files[filter_name])}'" 326 | elif filter_name == "libvmaf": 327 | return f"libvmaf='{self._get_libvmaf_filter_opts()}'" 328 | elif filter_name == "vif": 329 | return "vif,metadata=mode=print" 330 | elif filter_name == "msad": 331 | return "msad,metadata=mode=print" 332 | else: 333 | raise FfmpegQualityMetricsError(f"Unknown filter {filter_name}!") 334 | 335 | def calculate( 336 | self, 337 | metrics: List[MetricName] = ["ssim", "psnr"], 338 | vmaf_options: Union[VmafOptions, None] = None, 339 | ) -> Dict[MetricName, SingleMetricData]: 340 | """Calculate one or more metrics. 341 | 342 | Args: 343 | metrics (list, optional): A list of metrics to calculate. 344 | Possible values are ["ssim", "psnr", "vmaf"]. 345 | Defaults to ["ssim", "psnr"]. 346 | vmaf_options (dict, optional): VMAF-specific options. Uses defaults if not specified. 347 | 348 | Raises: 349 | FfmpegQualityMetricsError: In case of an error 350 | e: A generic error 351 | 352 | Returns: 353 | dict: A dictionary of per-frame info, with the key being the metric name and the value being a dict of frame numbers ('n') and metric values. 354 | """ 355 | if not metrics: 356 | raise FfmpegQualityMetricsError("No metrics specified!") 357 | 358 | # check available metrics 359 | for metric_name in metrics: 360 | filter_name = self.METRIC_TO_FILTER_MAP.get(metric_name, None) 361 | if filter_name not in self.POSSIBLE_FILTERS: 362 | raise FfmpegQualityMetricsError(f"No such metric '{metric_name}'") 363 | if filter_name not in self.available_filters: 364 | raise FfmpegQualityMetricsError( 365 | f"Your ffmpeg version does not have the filter '{filter_name}'" 366 | ) 367 | 368 | # set VMAF options specifically 369 | if "vmaf" in metrics: 370 | self._check_libvmaf_availability() 371 | self.vmaf_options = self.DEFAULT_VMAF_OPTIONS 372 | # override with user-supplied options 373 | if vmaf_options: 374 | for key, value in vmaf_options.items(): 375 | if value is not None: 376 | self.vmaf_options[key] = value # type: ignore 377 | self._set_vmaf_model_path(self.vmaf_options["model_path"]) 378 | 379 | ffmpeg_version = FfmpegQualityMetrics.get_ffmpeg_version() 380 | if ffmpeg_version is None or ffmpeg_version < parse_version("7.1"): 381 | logger.warning( 382 | "FFmpeg version is less than 7.1. Using deprecated scale2ref filter. Please update to 7.1 or higher." 383 | ) 384 | filter_chains = [ 385 | f"[1][0]scale2ref=flags={self.scaling_algorithm}[dist][ref]", 386 | "[dist]settb=AVTB,setpts=PTS-STARTPTS[distpts]", 387 | "[ref]settb=AVTB,setpts=PTS-STARTPTS[refpts]", 388 | ] 389 | else: 390 | # ffmpeg 7.1 or higher: scale2ref filter is deprecated 391 | # input 0: ref, input 1: dist --> swapped for scale filter 392 | filter_chains = [ 393 | f"[1][0]scale=rw:rh:flags={self.scaling_algorithm}[dist]", 394 | "[dist]settb=AVTB,setpts=PTS-STARTPTS[distpts]", 395 | "[0]settb=AVTB,setpts=PTS-STARTPTS[refpts]", 396 | ] 397 | 398 | # generate split filters depending on the number of models 399 | n_splits = len(metrics) 400 | if n_splits > 1: 401 | for source in ["dist", "ref"]: 402 | suffixes = "".join([f"[{source}{n}]" for n in range(1, n_splits + 1)]) 403 | filter_chains.extend( 404 | [ 405 | f"[{source}pts]split={n_splits}{suffixes}", 406 | ] 407 | ) 408 | 409 | # special case, only one metric: 410 | if n_splits == 1: 411 | metric_name = metrics[0] 412 | filter_chains.extend( 413 | [ 414 | f"[distpts][refpts]{self._get_filter_opts(self.METRIC_TO_FILTER_MAP[metric_name])}" 415 | ] 416 | ) 417 | # all other cases: 418 | else: 419 | for n, metric_name in zip(range(1, n_splits + 1), metrics): 420 | filter_chains.extend( 421 | [ 422 | f"[dist{n}][ref{n}]{self._get_filter_opts(self.METRIC_TO_FILTER_MAP[metric_name])}" 423 | ] 424 | ) 425 | 426 | try: 427 | output = self._run_ffmpeg_command(filter_chains, desc=", ".join(metrics)) 428 | self._read_temp_files(metrics) 429 | if output: 430 | self._read_ffmpeg_output(output, metrics) 431 | else: 432 | raise FfmpegQualityMetricsError("ffmpeg output is empty!") 433 | except Exception as e: 434 | raise e 435 | finally: 436 | self._cleanup_temp_files() 437 | 438 | # return only those data entries containing values 439 | return cast( 440 | Dict[MetricName, SingleMetricData], 441 | {k: v for k, v in self.data.items() if v}, 442 | ) 443 | 444 | def _get_libvmaf_filter_opts(self) -> str: 445 | """ 446 | Returns: 447 | 448 | str: A string to use for VMAF in ffmpeg filter chain 449 | """ 450 | # we only have one model, and its path parameter is not optional 451 | all_model_params: Dict[str, str] = { 452 | "path": win_vmaf_model_path_check(self.vmaf_model_path) 453 | } 454 | 455 | # add further model parameters 456 | for model_param in self.vmaf_options["model_params"]: 457 | key, value = model_param.split("=") 458 | all_model_params[key] = value 459 | 460 | all_model_params_str = "\\:".join( 461 | f"{k}={v}" for k, v in all_model_params.items() 462 | ) 463 | 464 | vmaf_opts: Dict[str, str] = { 465 | "model": all_model_params_str, 466 | "log_path": win_path_check(self.temp_files["libvmaf"]), 467 | "log_fmt": "json", 468 | "n_threads": str(self.vmaf_options["n_threads"]), 469 | "n_subsample": str(self.vmaf_options["n_subsample"]), 470 | } 471 | 472 | if self.vmaf_options["features"]: 473 | features = [] 474 | for feature in self.vmaf_options["features"]: 475 | if not feature.startswith("name"): 476 | feature = f"name={feature}" 477 | features.append(feature.replace(":", "\\:")) 478 | vmaf_opts["feature"] = "|".join(features) 479 | 480 | vmaf_opts_string = ":".join( 481 | f"{k}={v}" for k, v in vmaf_opts.items() if v is not None 482 | ) 483 | 484 | return vmaf_opts_string 485 | 486 | def _check_libvmaf_availability(self) -> None: 487 | if "libvmaf" not in self.available_filters: 488 | raise FfmpegQualityMetricsError( 489 | "Your ffmpeg build does not have support for VMAF. " 490 | "Make sure you download or build a version compiled with --enable-libvmaf!" 491 | ) 492 | 493 | def _set_vmaf_model_path(self, model_path: Union[str, None] = None) -> None: 494 | """ 495 | Logic to set the model path depending on the default or the user-supplied string 496 | """ 497 | if model_path is None: 498 | self.vmaf_model_path = FfmpegQualityMetrics.get_default_vmaf_model_path() 499 | else: 500 | self.vmaf_model_path = str(model_path) 501 | 502 | supplied_models = FfmpegQualityMetrics.get_supplied_vmaf_models() 503 | 504 | if not os.path.isfile(self.vmaf_model_path): 505 | # check if this is one of the supplied ones? e.g. user passed only a filename 506 | if self.vmaf_model_path in supplied_models: 507 | self.vmaf_model_path = os.path.join( 508 | FfmpegQualityMetrics.DEFAULT_VMAF_MODEL_DIRECTORY, 509 | self.vmaf_model_path, 510 | ) 511 | else: 512 | raise FfmpegQualityMetricsError( 513 | f"Could not find model at {self.vmaf_model_path}. " 514 | "Please set --model-path to a valid VMAF .json model file." 515 | ) 516 | 517 | def _read_vmaf_temp_file(self) -> None: 518 | """ 519 | Read the VMAF temp file and append the data to the data dict. 520 | """ 521 | with open(self.temp_files["libvmaf"], "r") as in_vmaf: 522 | vmaf_log = json.load(in_vmaf) 523 | logger.debug(f"VMAF log: {json.dumps(vmaf_log, indent=4)}") 524 | for frame_data in vmaf_log["frames"]: 525 | # append frame number, increase +1 526 | frame_data["metrics"]["n"] = int(frame_data["frameNum"]) + 1 527 | self.data["vmaf"].append(frame_data["metrics"]) 528 | 529 | def _read_ffmpeg_output(self, ffmpeg_output: str, metrics=[]) -> None: 530 | """ 531 | Read the metric values from ffmpeg's stderr, for those that don't output 532 | to a file. 533 | """ 534 | if self.dry_run: 535 | return 536 | if "vif" in metrics: 537 | self._parse_ffmpeg_metadata_output(ffmpeg_output, "vif") 538 | if "msad" in metrics: 539 | self._parse_ffmpeg_metadata_output(ffmpeg_output, "msad") 540 | 541 | def _parse_ffmpeg_metadata_output( 542 | self, ffmpeg_output: str, metric_name: Literal["vif", "msad"] 543 | ) -> None: 544 | """ 545 | Parse the filter output written to ffmpeg's metadata output 546 | 547 | Args: 548 | ffmpeg_output (str): The output of ffmpeg's stderr 549 | metric_name (Literal["vif", "msad"]): The name of the metric to parse 550 | """ 551 | # Example for VIF: 552 | # 553 | # [Parsed_metadata_4 @ 0x7f995cd08640] frame:1 pts:1 pts_time:0.0401x 554 | # [Parsed_metadata_4 @ 0x7f995cd08640] lavfi.vif.scale.0=0.263582 555 | # [Parsed_metadata_4 @ 0x7f995cd08640] lavfi.vif.scale.1=0.560129 556 | # [Parsed_metadata_4 @ 0x7f995cd08640] lavfi.vif.scale.2=0.626596 557 | # [Parsed_metadata_4 @ 0x7f995cd08640] lavfi.vif.scale.3=0.682183 558 | # 559 | # Example for MSAD: 560 | # 561 | # [Parsed_metadata_6 @ 0x10ad04ea0] lavfi.msad.msad.Y=0.029998 562 | # [Parsed_metadata_6 @ 0x10ad04ea0] lavfi.msad.msad.U=0.019501 563 | # [Parsed_metadata_6 @ 0x10ad04ea0] lavfi.msad.msad.V=0.026455 564 | # [Parsed_metadata_6 @ 0x10ad04ea0] lavfi.msad.msad_avg=0.025318 565 | 566 | lines = [line.strip() for line in ffmpeg_output.split("\n")] 567 | current_frame = None 568 | frame_data: Dict[str, float] = {} 569 | 570 | for line in lines: 571 | if not line.startswith("[Parsed_metadata"): 572 | continue 573 | 574 | fields = line.split(" ") 575 | 576 | # a new frame appears 577 | if fields[3].startswith("frame"): 578 | # if we have data already 579 | if frame_data: 580 | self.data[metric_name].append(frame_data) 581 | 582 | # get the frame number and reset the frame data 583 | current_frame = int(fields[3].split(":")[1]) 584 | frame_data = {"n": current_frame} 585 | continue 586 | 587 | # no frame was set, or no VIF info present 588 | if current_frame is None or not fields[3].startswith( 589 | f"lavfi.{metric_name}" 590 | ): 591 | continue 592 | 593 | # we have a frame 594 | key, value = fields[3].split("=") 595 | key = key.replace(f"lavfi.{metric_name}.", "").replace(".", "_").lower() 596 | frame_data[key] = round(float(value), 3) 597 | 598 | # append final frame data 599 | if frame_data: 600 | self.data[metric_name].append(frame_data) 601 | 602 | def _read_temp_files(self, metrics=[]): 603 | """ 604 | Read the data from multiple temp files 605 | """ 606 | if self.dry_run: 607 | return 608 | if "vmaf" in metrics: 609 | self._read_vmaf_temp_file() 610 | if "ssim" in metrics: 611 | self._read_ssim_temp_file() 612 | if "psnr" in metrics: 613 | self._read_psnr_temp_file() 614 | 615 | def _run_ffmpeg_command( 616 | self, filter_chains: List[str] = [], desc: str = "" 617 | ) -> Union[str, None]: 618 | """ 619 | Run the ffmpeg command to get the quality metrics. 620 | The filter chains must be specified manually. 621 | 'desc' can be a human readable description for the progress bar. 622 | 623 | Returns: 624 | Union[str, None]: The output of ffmpeg's stderr 625 | """ 626 | if not self.framerate: 627 | ref_framerate, dist_framerate = self._get_framerates() 628 | else: 629 | ref_framerate = self.framerate 630 | dist_framerate = self.framerate 631 | 632 | cmd = [ 633 | "ffmpeg", 634 | "-nostdin", 635 | "-nostats", 636 | "-y", 637 | "-threads", 638 | str(self.threads), 639 | "-r", 640 | str(ref_framerate), 641 | "-i", 642 | self.ref, 643 | "-itsoffset", 644 | str(self.dist_delay), 645 | "-r", 646 | str(dist_framerate), 647 | "-i", 648 | self.dist, 649 | "-filter_complex", 650 | ";".join(filter_chains), 651 | "-an", 652 | "-f", 653 | "null", 654 | NUL, 655 | ] 656 | 657 | if self.progress: 658 | logger.debug(quoted_cmd(cmd)) 659 | ff = FfmpegProgress(cmd, self.dry_run) 660 | with tqdm(total=100, position=1, desc=desc) as pbar: 661 | for progress in ff.run_command_with_progress(): 662 | pbar.update(progress - pbar.n) 663 | return ff.stderr 664 | else: 665 | _, stderr = run_command(cmd, dry_run=self.dry_run) 666 | return stderr 667 | 668 | def _cleanup_temp_files(self) -> None: 669 | """ 670 | Remove the temporary files 671 | """ 672 | for temp_file in self.temp_files.values(): 673 | if os.path.isfile(temp_file): 674 | if self.keep_tmp_files: 675 | logger.debug(f"Keeping temp file {temp_file}") 676 | else: 677 | os.remove(temp_file) 678 | 679 | def _read_psnr_temp_file(self) -> None: 680 | """ 681 | Parse the PSNR generated logfile 682 | """ 683 | with open(self.temp_files["psnr"], "r") as in_psnr: 684 | # n:1 mse_avg:529.52 mse_y:887.00 mse_u:233.33 mse_v:468.25 psnr_avg:20.89 psnr_y:18.65 psnr_u:24.45 psnr_v:21.43 685 | lines = in_psnr.readlines() 686 | for line in lines: 687 | line = line.strip() 688 | fields = line.split(" ") 689 | frame_data = {} 690 | for field in fields: 691 | k, v = field.split(":") 692 | frame_data[k] = round(float(v), 3) if k != "n" else int(v) 693 | self.data["psnr"].append(frame_data) 694 | 695 | def _read_ssim_temp_file(self) -> None: 696 | """ 697 | Parse the SSIM generated logfile 698 | """ 699 | with open(self.temp_files["ssim"], "r") as in_ssim: 700 | # n:1 Y:0.937213 U:0.961733 V:0.945788 All:0.948245 (12.860441)\n 701 | lines = in_ssim.readlines() 702 | for line in lines: 703 | line = line.strip().split(" (")[0] # remove excess 704 | fields = line.split(" ") 705 | frame_data = {} 706 | for field in fields: 707 | k, v = field.split(":") 708 | if k != "n": 709 | # make psnr and ssim keys the same 710 | k = "ssim_" + k.lower() 711 | k = k.replace("all", "avg") 712 | frame_data[k] = round(float(v), 3) if k != "n" else int(v) 713 | self.data["ssim"].append(frame_data) 714 | 715 | @staticmethod 716 | def get_brewed_vmaf_model_path() -> Union[str, None]: 717 | """ 718 | Hack to get path for VMAF model from Homebrew or Linuxbrew. 719 | This works for libvmaf 2.x 720 | 721 | Returns: 722 | str or None: the path or None if not found 723 | """ 724 | stdout, _ = run_command(["brew", "--prefix", "libvmaf"]) 725 | cellar_path = stdout.strip() 726 | 727 | model_path = os.path.join(cellar_path, "share", "libvmaf", "model") 728 | 729 | if not os.path.isdir(model_path): 730 | logger.warning( 731 | f"{model_path} does not exist. " 732 | "Are you sure you have installed the most recent version of libvmaf with Homebrew?" 733 | ) 734 | return None 735 | 736 | return model_path 737 | 738 | @staticmethod 739 | def get_default_vmaf_model_path() -> str: 740 | """ 741 | Return the default model path depending on whether the user is running Homebrew 742 | or has a static build. 743 | 744 | Returns: 745 | str: the path 746 | """ 747 | if has_brew() and ffmpeg_is_from_brew(): 748 | # If the user installed ffmpeg using homebrew 749 | model_path = FfmpegQualityMetrics.get_brewed_vmaf_model_path() 750 | if model_path is not None: 751 | return os.path.join( 752 | model_path, 753 | "vmaf_v0.6.1.json", 754 | ) 755 | 756 | share_path = os.path.join("/usr", "local", "share", "model") 757 | if os.path.isdir(share_path): 758 | return os.path.join(share_path, "vmaf_v0.6.1.json") 759 | else: 760 | # return the bundled file as a fallback 761 | return os.path.join( 762 | FfmpegQualityMetrics.DEFAULT_VMAF_MODEL_DIRECTORY, "vmaf_v0.6.1.json" 763 | ) 764 | 765 | @staticmethod 766 | def get_supplied_vmaf_models() -> List[str]: 767 | """ 768 | Return a list of VMAF models supplied with the software. 769 | 770 | Returns: 771 | List[str]: A list of VMAF model names 772 | """ 773 | return [ 774 | f 775 | for f in os.listdir(FfmpegQualityMetrics.DEFAULT_VMAF_MODEL_DIRECTORY) 776 | if f.endswith(".json") 777 | ] 778 | 779 | def get_global_stats(self) -> GlobalStats: 780 | """ 781 | Return a dictionary for each calculated metric, with different statstics 782 | 783 | Returns: 784 | dict: A dictionary with stats, each key being a metric name and each value being a dictionary with the stats for every submetric. The stats are: 'average', 'median', 'stdev', 'min', 'max'. 785 | """ 786 | for metric_name in self.data: 787 | logger.debug(f"Aggregating stats for {metric_name}") 788 | metric_data = cast(SingleMetricData, self.data[metric_name]) # type: ignore 789 | if len(metric_data) == 0: 790 | continue 791 | submetric_keys = [k for k in metric_data[0].keys() if k != "n"] 792 | 793 | stats: Dict[str, GlobalStatsData] = {} 794 | for submetric_key in submetric_keys: 795 | values = [float(frame[submetric_key]) for frame in metric_data] 796 | stats[submetric_key] = { 797 | "average": round(float(np.average(values)), 3), 798 | "median": round(float(np.median(values)), 3), 799 | "stdev": round(float(np.std(values)), 3), 800 | "min": round(np.min(values), 3), 801 | "max": round(np.max(values), 3), 802 | } 803 | self.global_stats[metric_name] = stats # type: ignore 804 | 805 | return self.global_stats 806 | 807 | def get_results_csv(self) -> str: 808 | """ 809 | Return a CSV string with the data 810 | 811 | Returns: 812 | str: The CSV string 813 | """ 814 | all_dfs = [] 815 | 816 | for metric_data in self.data.values(): 817 | if not metric_data: 818 | continue 819 | all_dfs.append(pd.DataFrame(cast(SingleMetricData, metric_data))) 820 | 821 | if not all_dfs: 822 | raise FfmpegQualityMetricsError("No data calculated!") 823 | 824 | try: 825 | df = reduce(lambda x, y: pd.merge(x, y, on="n"), all_dfs) 826 | 827 | df["input_file_dist"] = self.dist 828 | df["input_file_ref"] = self.ref 829 | 830 | cols = df.columns.tolist() 831 | cols.insert(0, cols.pop(cols.index("n"))) 832 | df = df.reindex(columns=cols) 833 | return df.to_csv(index=False) 834 | except Exception as e: 835 | raise FfmpegQualityMetricsError(f"Error merging data to CSV: {e}") 836 | 837 | def get_results_json(self) -> str: 838 | """ 839 | Return the results as JSON string 840 | 841 | Returns: 842 | str: The JSON string 843 | """ 844 | ret: Dict = {} 845 | for key in self.data: 846 | metric_data = cast(SingleMetricData, self.data[key]) # type: ignore 847 | if len(metric_data) == 0: 848 | continue 849 | ret[key] = metric_data 850 | ret["global"] = self.get_global_stats() 851 | ret["input_file_dist"] = self.dist 852 | ret["input_file_ref"] = self.ref 853 | 854 | return json.dumps(ret, indent=4) 855 | -------------------------------------------------------------------------------- /ffmpeg_quality_metrics/log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | class CustomLogFormatter(logging.Formatter): 5 | """ 6 | https://stackoverflow.com/a/56944256/435093 7 | """ 8 | 9 | grey = "\x1b[38;20m" 10 | yellow = "\x1b[33;20m" 11 | red = "\x1b[31;20m" 12 | bold_red = "\x1b[31;1m" 13 | reset = "\x1b[0m" 14 | # strformat = ( 15 | # "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" 16 | # ) 17 | strformat = "%(levelname)s - %(message)s" 18 | 19 | FORMATS = { 20 | logging.DEBUG: grey + strformat + reset, 21 | logging.INFO: grey + strformat + reset, 22 | logging.WARNING: yellow + strformat + reset, 23 | logging.ERROR: red + strformat + reset, 24 | logging.CRITICAL: bold_red + strformat + reset, 25 | } 26 | 27 | def format(self, record) -> str: 28 | log_fmt = self.FORMATS.get(record.levelno) 29 | formatter = logging.Formatter(log_fmt) 30 | return formatter.format(record) 31 | -------------------------------------------------------------------------------- /ffmpeg_quality_metrics/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slhck/ffmpeg-quality-metrics/42aad7ad0e88f024777ea47c47c80dc0080bc104/ffmpeg_quality_metrics/py.typed -------------------------------------------------------------------------------- /ffmpeg_quality_metrics/utils.py: -------------------------------------------------------------------------------- 1 | # ffmpeg-quality-metrics 2 | # Author: Werner Robitza 3 | # License: MIT 4 | 5 | import logging 6 | import os 7 | import shlex 8 | import subprocess 9 | from platform import system 10 | from shutil import which 11 | from typing import List, Tuple 12 | 13 | IS_WIN = system() in ["Windows", "cli"] 14 | NUL = "NUL" if IS_WIN else "/dev/null" 15 | 16 | logger = logging.getLogger("ffmpeg-quality-metrics") 17 | 18 | 19 | def win_path_check(path: str) -> str: 20 | """ 21 | Format a file path correctly for Windows 22 | 23 | Args: 24 | path (str): The path to format 25 | 26 | Returns: 27 | str: The formatted path 28 | """ 29 | if IS_WIN: 30 | return path.replace("\\", "/").replace(":", "\\:") 31 | return path 32 | 33 | 34 | def win_vmaf_model_path_check(path: str) -> str: 35 | """ 36 | Format vmaf model file path correctly for Windows 37 | 38 | Args: 39 | path (str): The path to format 40 | 41 | Returns: 42 | str: The formatted path 43 | """ 44 | if IS_WIN: 45 | return win_path_check(path).replace("\\", "\\\\\\") 46 | return path 47 | 48 | 49 | def has_brew() -> bool: 50 | """ 51 | Check if the user has Homebrew installed 52 | 53 | Returns: 54 | bool: True if Homebrew is installed, False otherwise 55 | """ 56 | return which("brew") is not None 57 | 58 | 59 | def ffmpeg_is_from_brew() -> bool: 60 | """ 61 | Is the used ffmpeg from Homebrew? 62 | 63 | Returns: 64 | bool: True if ffmpeg is from Homebrew, False otherwise 65 | """ 66 | ffmpeg_path = which("ffmpeg") 67 | if ffmpeg_path is None: 68 | return False 69 | 70 | return os.path.islink(ffmpeg_path) and "Cellar/ffmpeg" in os.readlink(ffmpeg_path) 71 | 72 | 73 | def quoted_cmd(cmd: List[str]) -> str: 74 | """ 75 | Quote a command for printing. 76 | 77 | Args: 78 | cmd (list): The command to quote 79 | 80 | Returns: 81 | str: The quoted command 82 | """ 83 | return " ".join([shlex.quote(c) for c in cmd]) 84 | 85 | 86 | def run_command( 87 | cmd, dry_run: bool = False, allow_error: bool = False 88 | ) -> Tuple[str, str]: 89 | """ 90 | Run a command directly 91 | """ 92 | logger.debug(quoted_cmd(cmd)) 93 | if dry_run: 94 | return "", "" 95 | 96 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 97 | stdout, stderr = process.communicate() 98 | 99 | if allow_error or process.returncode == 0: 100 | return stdout.decode("utf-8"), stderr.decode("utf-8") 101 | else: 102 | raise RuntimeError( 103 | f"error running command: {quoted_cmd(cmd)}\n{stdout.decode('utf-8')}\n{stderr.decode('utf-8')}" 104 | ) 105 | -------------------------------------------------------------------------------- /ffmpeg_quality_metrics/vmaf_models/LICENSE: -------------------------------------------------------------------------------- 1 | LICENSE - BSD+Patent 2 | SPDX short identifier: BSD-2-Clause-Patent 3 | 4 | Note: This license is designed to provide: a) a simple permissive license; b) that is compatible with the GNU General 5 | Public License (GPL), version 2; and c) which also has an express patent grant included. 6 | 7 | Copyright (c) 2020 Netflix, Inc. 8 | 9 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 10 | following conditions are met: 11 | 12 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following 13 | disclaimer. 14 | 15 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 16 | disclaimer in the documentation and/or other materials provided with the distribution. 17 | 18 | Subject to the terms and conditions of this license, each copyright holder and contributor hereby grants to those 19 | receiving rights under this license a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except 20 | for failure to satisfy the conditions of this license) patent license to make, have made, use, offer to sell, sell, 21 | import, and otherwise transfer this software, where such license applies only to those patent claims, already acquired 22 | or hereafter acquired, licensable by such copyright holder or contributor that are necessarily infringed by: 23 | 24 | (a) their Contribution(s) (the licensed copyrights of copyright holders and non-copyrightable additions of contributors, 25 | in source or binary form) alone; or 26 | 27 | (b) combination of their Contribution(s) with the work of authorship to which such Contribution(s) was added by such 28 | copyright holder or contributor, if, at the time the Contribution is added, such addition causes such combination to be 29 | necessarily infringed. The patent license shall not apply to any other combinations which include the Contribution. 30 | 31 | Except as expressly stated above, no rights or licenses from any copyright holder or contributor is granted under this 32 | license, whether expressly, by implication, estoppel or otherwise. 33 | 34 | DISCLAIMER 35 | 36 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 37 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 40 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 41 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 42 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /ffmpeg_quality_metrics/vmaf_models/vmaf_4k_v0.6.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "param_dict": { 3 | "norm_type": "clip_0to1", 4 | "score_clip": [ 5 | 0.0, 6 | 100.0 7 | ], 8 | "C": 4.0, 9 | "nu": 0.9, 10 | "gamma": 0.04 11 | }, 12 | "model_dict": { 13 | "model": "svm_type nu_svr\nkernel_type rbf\ngamma 0.04\nnr_class 2\ntotal_sv 262\nrho -2.30449\nSV\n4 1:0.99939284 2:0.050988098 3:0.99999956 4:0.99999701 5:0.9999947 6:0.99999444 \n-4 1:0.99939284 2:0.71982347 3:0.99999932 4:0.99999929 5:0.99999902 6:0.9999986 \n4 1:0.99939284 2:0.066104402 3:0.99999363 4:0.99999023 5:0.9999835 6:0.99998197 \n4 1:0.99939284 2:0.021298217 3:0.99999905 4:0.99999854 5:0.99999742 6:0.9999955 \n-4 1:0.99939284 2:0.4219157 3:1 4:1 5:1 6:1 \n-4 1:0.99939284 2:0.41153394 3:0.99999809 4:0.99999407 5:0.999992 6:0.99999118 \n-4 1:0.99939284 2:0.17755989 3:0.99999975 4:0.99999351 5:0.99998797 6:0.99998744 \n-4 1:0.99939284 2:1 3:0.99999853 4:0.99999797 5:0.99999707 6:0.99999697 \n4 1:0.99939284 2:0.067429096 3:0.99999826 4:0.99999612 5:0.99999354 6:0.99999337 \n-4 1:0.99939284 2:0.41032924 3:0.99999923 4:0.99999861 5:0.99999718 6:0.99999652 \n4 1:0.99939284 2:0.064778982 3:0.99999965 4:0.99999001 5:0.99998599 6:0.99998452 \n4 1:0.99939284 3:0.99999976 4:0.99999986 5:0.99999981 6:0.99999912 \n-4 1:0.99939284 2:0.14610739 3:0.99999926 4:0.99999442 5:0.99999157 6:0.99999139 \n4 1:0.97067067 2:0.050988098 3:0.49543962 4:0.9490745 5:0.97475171 6:0.98472179 \n4 1:0.96418744 2:0.050988098 3:0.46988192 4:0.92383404 5:0.95757873 6:0.97233463 \n4 1:0.9377329 2:0.050988098 3:0.45140723 4:0.91821601 5:0.9544047 6:0.97006662 \n4 1:0.92797904 2:0.050988098 3:0.42756389 4:0.88415491 5:0.92731024 6:0.947393 \n-4 1:0.9116005 2:0.050988098 3:0.4013622 4:0.8417096 5:0.88934565 6:0.91268991 \n4 1:0.90408239 2:0.050988098 3:0.42837654 4:0.89330043 5:0.9381379 6:0.95747194 \n-4 1:0.89392463 2:0.050988098 3:0.40580803 4:0.85450813 5:0.90414358 6:0.92789549 \n-4 1:0.87860187 2:0.050988098 3:0.38181902 4:0.8098155 5:0.86047538 6:0.8864857 \n-4 1:0.84912189 2:0.050988098 3:0.40304721 4:0.85597966 5:0.91737096 6:0.94451916 \n-4 1:0.83864962 2:0.050988098 3:0.38405986 4:0.81919138 5:0.8810097 6:0.9109596 \n-4 1:0.82264009 2:0.050988098 3:0.35981237 4:0.77013967 5:0.82806852 6:0.85777151 \n-4 1:0.72530266 2:0.050988098 3:0.36509103 4:0.7803563 5:0.85121225 6:0.90847043 \n-4 1:0.71395913 2:0.050988098 3:0.35076533 4:0.74960971 5:0.81479928 6:0.86738588 \n-4 1:0.69835377 2:0.050988098 3:0.33114525 4:0.70635463 5:0.76097853 6:0.8040479 \n-4 1:0.57536217 2:0.050988098 3:0.33608994 4:0.71362303 5:0.76736581 6:0.82220476 \n-4 1:0.56279868 2:0.050988098 3:0.3242142 4:0.68621629 5:0.73148001 6:0.77845387 \n-4 1:0.54413788 2:0.050988098 3:0.30829451 4:0.65018018 5:0.68403685 6:0.71900287 \n-4 1:0.44593277 2:0.050988098 3:0.31899854 4:0.67259186 5:0.70967941 6:0.7722768 \n-4 1:0.43671916 2:0.050988098 3:0.30969518 4:0.65136495 5:0.68132238 6:0.73261178 \n-4 1:0.42693909 2:0.050988098 3:0.29609478 4:0.62046105 5:0.64002486 6:0.67430791 \n-4 1:0.86629362 2:0.71982347 3:0.48704318 4:0.79897775 5:0.87428887 6:0.91698512 \n-4 1:0.86629362 2:0.71982347 3:0.48704318 4:0.79897775 5:0.87428887 6:0.91698512 \n-4 1:0.81132964 2:0.71982347 3:0.40069978 4:0.68226748 5:0.77591641 6:0.83959232 \n-4 1:0.83930799 2:0.71982347 3:0.43685332 4:0.73078798 5:0.82569797 6:0.88313372 \n-4 1:0.82104472 2:0.71982347 3:0.40784454 4:0.6870597 5:0.78745308 6:0.85289277 \n4 1:0.74699836 2:0.71982347 3:0.31844762 4:0.53709426 5:0.6345148 6:0.71373411 \n-4 1:0.81333039 2:0.71982347 3:0.43098515 4:0.72394543 5:0.82486183 6:0.88337434 \n4 1:0.7567244 2:0.71982347 3:0.34895637 4:0.58582297 5:0.69322753 6:0.77472255 \n4 1:0.66873968 2:0.71982347 3:0.26759387 4:0.43612997 5:0.51903634 6:0.59741799 \n-4 1:0.73878903 2:0.71982347 3:0.36112988 4:0.62230674 5:0.75026901 6:0.8339499 \n-4 1:0.6832086 2:0.71982347 3:0.29503172 4:0.49646552 5:0.60960086 6:0.70454744 \n4 1:0.60246526 2:0.71982347 3:0.22993127 4:0.37032595 5:0.45049262 6:0.53353221 \n-4 1:0.56179559 2:0.71982347 3:0.24308411 4:0.41261968 5:0.54180311 6:0.69179288 \n-4 1:0.5113668 2:0.71982347 3:0.2024429 4:0.32849939 5:0.42162036 6:0.54644452 \n-4 1:0.43448252 2:0.71982347 3:0.15539012 4:0.23356514 5:0.28327683 6:0.36722447 \n-4 1:0.3778537 2:0.71982347 3:0.16549547 4:0.2611707 5:0.3403477 6:0.46036189 \n-4 1:0.33784752 2:0.71982347 3:0.13817483 4:0.20458733 5:0.2516001 6:0.34154118 \n-4 1:0.27170374 2:0.71982347 3:0.10540751 4:0.13933699 5:0.15095506 6:0.19817438 \n3.844294796952767 1:0.2331476 2:0.71982347 3:0.11204632 4:0.15703824 5:0.18727069 6:0.28587565 \n-4 1:0.19847267 2:0.71982347 3:0.092940166 4:0.11828028 5:0.1248167 6:0.18078381 \n-4 1:0.13919934 2:0.71982347 3:0.067437816 4:0.068775313 5:0.047314055 6:0.053241443 \n4 1:0.93416822 2:0.066104402 3:0.78940676 4:0.94766693 5:0.97049944 6:0.98007081 \n4 1:0.91129907 2:0.066104402 3:0.75598257 4:0.92233159 5:0.95186961 6:0.96556305 \n4 1:0.88059412 2:0.066104402 3:0.71656123 4:0.88582657 5:0.92135563 6:0.93892845 \n4 1:0.90889954 2:0.066104402 3:0.73107539 4:0.91167914 5:0.94403922 6:0.95868361 \n4 1:0.87711044 2:0.066104402 3:0.69546312 4:0.87200488 5:0.90999902 6:0.92841888 \n4 1:0.88034823 2:0.066104402 3:0.69789972 4:0.87983058 5:0.91913978 6:0.93738624 \n-4 1:0.84332172 2:0.066104402 3:0.66221738 4:0.8330874 5:0.87381425 6:0.89425692 \n-4 1:0.7947559 2:0.066104402 3:0.62943841 4:0.78442623 5:0.81961037 6:0.83588208 \n-4 1:0.80750528 2:0.066104402 3:0.63895062 4:0.80166112 5:0.84609333 6:0.86486365 \n-4 1:0.75551102 2:0.066104402 3:0.60539321 4:0.75077297 5:0.78607721 6:0.79724688 \n1.791949006599779 1:0.76045302 2:0.066104402 3:0.64179152 4:0.79440383 5:0.84810636 6:0.88090735 \n-4 1:0.72233742 2:0.066104402 3:0.6111271 4:0.75016894 5:0.79398174 6:0.81321126 \n-4 1:0.67315793 2:0.066104402 3:0.58060257 4:0.70437387 5:0.73465103 6:0.73523596 \n-4 1:0.6723527 2:0.066104402 3:0.62006113 4:0.75287675 5:0.79557065 6:0.84205178 \n-4 1:0.63675161 2:0.066104402 3:0.59379594 4:0.71425087 5:0.74517244 6:0.77487561 \n-4 1:0.59242211 2:0.066104402 3:0.5636273 4:0.6689991 5:0.68518093 6:0.69076381 \n-4 1:0.5922744 2:0.066104402 3:0.60324622 4:0.72279409 5:0.75399448 6:0.80004372 \n-4 1:0.56164749 2:0.066104402 3:0.58086179 4:0.68984664 5:0.71004316 6:0.73622079 \n-4 1:0.52270076 2:0.066104402 3:0.55139557 4:0.64656965 5:0.65206052 6:0.65203367 \n4 1:0.97683514 2:0.021298217 3:0.79006309 4:0.96543498 5:0.98286137 6:0.98970893 \n4 1:0.96917374 2:0.021298217 3:0.73829188 4:0.94562107 5:0.9720532 6:0.9827408 \n4 1:0.95871969 2:0.021298217 3:0.68499274 4:0.91613875 5:0.9539741 6:0.97047879 \n4 1:0.96082897 2:0.021298217 3:0.71750756 4:0.95076843 5:0.97548069 6:0.98526422 \n4 1:0.95164281 2:0.021298217 3:0.6658229 4:0.91863413 5:0.95575768 6:0.97210294 \n-4 1:0.93237214 2:0.021298217 3:0.58347155 4:0.85481826 5:0.91374583 6:0.94325142 \n-4 1:0.86241747 2:0.021298217 3:0.47931708 4:0.7776951 5:0.86801434 6:0.910233 \n4 1:0.7980028 2:0.021298217 3:0.46673975 4:0.79695862 5:0.92218079 6:0.96750104 \n-4 1:0.78576115 2:0.021298217 3:0.43553076 4:0.7460098 5:0.87803168 6:0.93469599 \n-4 1:0.76605196 2:0.021298217 3:0.39315849 4:0.66848161 5:0.80255256 6:0.87361428 \n-4 1:0.58665967 2:0.021298217 3:0.3220426 4:0.54484412 5:0.7193025 6:0.88036572 \n-4 1:0.57643091 2:0.021298217 3:0.30580604 4:0.51190629 5:0.67579634 6:0.83081105 \n-4 1:0.55885972 2:0.021298217 3:0.28190551 4:0.46007761 5:0.60264024 6:0.74348398 \n4 1:0.35873577 2:0.021298217 3:0.24431536 4:0.37994438 5:0.50206362 6:0.64244093 \n4 1:0.35180843 2:0.021298217 3:0.2349948 4:0.36009808 5:0.47156276 6:0.60596511 \n4 1:0.19466612 2:0.021298217 3:0.2006595 4:0.28475881 5:0.35586074 6:0.51761911 \n4 1:0.18965751 2:0.021298217 3:0.19488505 4:0.27271641 5:0.33648612 6:0.48447905 \n4 1:0.1814951 2:0.021298217 3:0.18573864 4:0.25287656 5:0.30301198 6:0.42421488 \n4 1:0.91141884 2:0.4219157 3:0.51488117 4:0.85936589 5:0.92126637 6:0.9509564 \n4 1:0.91050791 2:0.4219157 3:0.51170081 4:0.85742154 5:0.92017755 6:0.95028867 \n4 1:0.88595276 2:0.4219157 3:0.44052173 4:0.80179187 5:0.88580681 6:0.92820352 \n4 1:0.89351476 2:0.4219157 3:0.46719499 4:0.84064804 5:0.91220882 6:0.94578215 \n4 1:0.87606982 2:0.4219157 3:0.42043726 4:0.79317785 5:0.88213449 6:0.92622089 \n4 1:0.83041563 2:0.4219157 3:0.33320494 4:0.67165697 5:0.7906166 6:0.86070638 \n4 1:0.81048328 2:0.4219157 3:0.3381176 4:0.76378989 5:0.88522402 6:0.93052674 \n4 1:0.77358122 2:0.4219157 3:0.28271443 4:0.65320093 5:0.79807098 6:0.8696108 \n4 1:0.72162639 2:0.4219157 3:0.22235436 4:0.5223276 5:0.67415206 6:0.77142043 \n4 1:0.68842583 2:0.4219157 3:0.22275829 4:0.58336434 5:0.78879637 6:0.88983521 \n4 1:0.6526809 2:0.4219157 3:0.1861581 4:0.48473563 5:0.67986667 6:0.80207435 \n4 1:0.5997337 2:0.4219157 3:0.14502789 4:0.37458805 5:0.5431471 6:0.67665606 \n4 1:0.45510711 2:0.4219157 3:0.10494997 4:0.29538479 5:0.49160337 6:0.71662671 \n-4 1:0.41748398 2:0.4219157 3:0.084767542 4:0.23463647 5:0.39118915 6:0.59179152 \n4 1:0.35974355 2:0.4219157 3:0.060748299 4:0.16481355 5:0.27425611 6:0.43460248 \n4 1:0.23169409 2:0.4219157 3:0.048508288 4:0.13768591 5:0.24707533 6:0.40719122 \n4 1:0.20260612 2:0.4219157 3:0.036631159 4:0.102091 5:0.18145932 6:0.31803017 \n4 1:0.15560078 2:0.4219157 3:0.022332774 4:0.060770097 5:0.10624488 6:0.20706242 \n-0.04742554821603767 1:0.07072824 2:0.4219157 3:0.018298168 4:0.05227841 5:0.098051849 6:0.23169122 \n4 1:1.110223e-16 2:0.4219157 3:-1.3877788e-17 4:-2.7755576e-17 6:0.048728064 \n-4 1:0.91005179 2:0.17755989 3:0.24323732 4:0.70234527 5:0.8362572 6:0.90187908 \n4 1:0.88256545 2:0.17755989 3:0.15914187 4:0.55559405 5:0.71345251 6:0.80791685 \n-4 1:0.90419278 2:0.17755989 3:0.20481669 4:0.64392636 5:0.79442969 6:0.87497932 \n4 1:0.87829669 2:0.17755989 3:0.13872696 4:0.51358873 5:0.67488416 6:0.77600855 \n1.697384149096087 1:0.84542326 2:0.17755989 3:0.10437835 4:0.43810307 5:0.59082415 6:0.69314276 \n4 1:0.86603509 2:0.17755989 3:0.15113761 4:0.53857524 5:0.70165231 6:0.80180281 \n4 1:0.83995428 2:0.17755989 3:0.11205502 4:0.45141136 5:0.60876051 6:0.7150352 \n-4 1:0.80377521 2:0.17755989 3:0.088196383 4:0.39371713 5:0.53694408 6:0.63485159 \n4 1:0.81385195 2:0.17755989 3:0.12620028 4:0.48485111 5:0.64894062 6:0.75467438 \n-0.4488405748991944 1:0.78603394 2:0.17755989 3:0.099154008 4:0.41891421 5:0.57038625 6:0.67485233 \n-4 1:0.74608925 2:0.17755989 3:0.077679983 4:0.36403126 5:0.49643237 6:0.5866 \n4 1:0.67021959 2:0.17755989 3:0.10106749 4:0.42493279 5:0.58169808 6:0.69537149 \n4 1:0.64185148 2:0.17755989 3:0.083254507 4:0.37713697 5:0.51413321 6:0.61155168 \n-4 1:0.60166239 2:0.17755989 3:0.066162412 4:0.33103444 5:0.44584 6:0.5191942 \n4 1:0.50596606 2:0.17755989 3:0.086479478 4:0.38777983 5:0.5308163 6:0.63660165 \n4 1:0.47859936 2:0.17755989 3:0.072687526 4:0.34936144 5:0.47239557 6:0.5559507 \n4 1:0.43845677 2:0.17755989 3:0.0580781 4:0.30930574 5:0.41085136 6:0.46717424 \n4 1:0.36280896 2:0.17755989 3:0.076394495 4:0.36116467 5:0.49086262 6:0.5863048 \n4 1:0.339869 2:0.17755989 3:0.065775733 4:0.33141351 5:0.44429517 6:0.51614837 \n4 1:0.30203933 2:0.17755989 3:0.052980146 4:0.29595567 5:0.38900859 6:0.43266074 \n-4 1:0.83817724 2:1 3:0.48211034 4:0.67164548 5:0.74684182 6:0.80144501 \n4 1:0.83817724 2:1 3:0.48211034 4:0.67164548 5:0.74684182 6:0.80144501 \n3.578142440445044 1:0.70376868 2:1 3:0.3003252 4:0.39047192 5:0.43165029 6:0.47109673 \n4 1:0.79827724 2:1 3:0.42095183 4:0.57898312 5:0.67201591 6:0.73979589 \n4 1:0.72627998 2:1 3:0.33468753 4:0.43786041 5:0.49854834 6:0.55141858 \n4 1:0.64522624 2:1 3:0.33533743 4:0.42400651 5:0.4895503 6:0.572323 \n4 1:0.57474363 2:1 3:0.26878017 4:0.31350754 5:0.33529491 6:0.37251888 \n-2.810859235621974 1:0.47520203 2:1 3:0.20793711 4:0.21420053 5:0.19540816 6:0.18220079 \n4 1:0.47142758 2:1 3:0.27819932 4:0.32101893 5:0.34502997 6:0.38578806 \n-4 1:0.32605309 2:1 3:0.17816529 4:0.16093999 5:0.11686383 6:0.06853313 \n4 1:0.31129079 2:1 3:0.24354672 4:0.25922218 5:0.25276742 6:0.27267936 \n4 1:0.26050571 2:1 3:0.20191772 4:0.19422711 5:0.16030609 6:0.13256762 \n-4 1:0.1875636 2:1 3:0.16020164 4:0.13034576 5:0.070806091 \n4 1:0.92043781 2:0.064778982 3:0.10731312 4:0.92865048 5:0.96616172 6:0.97870032 \n4 1:0.89332398 2:0.064778982 3:0.081553072 4:0.88356542 5:0.93679165 6:0.95607085 \n4 1:0.86104377 2:0.064778982 3:0.063594449 4:0.83329523 5:0.89705938 6:0.92172879 \n4 1:0.86887317 2:0.064778982 3:0.080783435 4:0.8868064 5:0.93958114 6:0.95873325 \n4 1:0.8407759 2:0.064778982 3:0.064276214 4:0.83712744 5:0.90102313 6:0.9260964 \n-4 1:0.8033305 2:0.064778982 3:0.048493857 4:0.78247464 5:0.8514111 6:0.87935001 \n4 1:0.81084152 2:0.064778982 3:0.066615908 4:0.85255528 5:0.91699879 6:0.94147769 \n4 1:0.78294588 2:0.064778982 3:0.052801797 4:0.79905896 5:0.86924403 6:0.89848251 \n-4 1:0.74279413 2:0.064778982 3:0.038810404 4:0.7430212 5:0.81108068 6:0.83919241 \n4 1:0.7535469 2:0.064778982 3:0.0553861 4:0.81573181 5:0.89228763 6:0.92360272 \n-3.934747494551165 1:0.72656633 2:0.064778982 3:0.043258869 4:0.76460435 5:0.83920864 6:0.87155626 \n-4 1:0.68726622 2:0.064778982 3:0.030922104 4:0.71254668 5:0.77850594 6:0.80498778 \n4 1:0.63349803 2:0.064778982 3:0.038013615 4:0.75176999 5:0.83528432 6:0.88215862 \n-4 1:0.60394824 2:0.064778982 3:0.03004494 4:0.71400524 5:0.78578757 6:0.82308143 \n-4 1:0.56241959 2:0.064778982 3:0.02136261 4:0.67291865 5:0.72892243 6:0.74881646 \n-4 1:0.50818128 2:0.064778982 3:0.028808053 4:0.71172156 5:0.78465896 6:0.82722602 \n-4 1:0.47829471 2:0.064778982 3:0.022946892 4:0.68323749 5:0.74386141 6:0.77269399 \n-4 1:0.43957805 2:0.064778982 3:0.015447998 4:0.64780359 5:0.69255168 6:0.70091868 \n4 1:0.40154084 2:0.064778982 3:0.022697618 4:0.68415777 5:0.74445841 6:0.78162172 \n-4 1:0.3439641 2:0.064778982 3:0.011635393 4:0.63097298 5:0.66613358 6:0.66379079 \n3.88822960690639 1:0.91491234 2:0.41153394 3:0.38096487 4:0.89889761 5:0.95038406 6:0.97192506 \n4 1:0.88655237 2:0.41153394 3:0.32747681 4:0.82957396 5:0.90234555 6:0.93753935 \n-4 1:0.85734964 2:0.41153394 3:0.28689298 4:0.75950394 5:0.84227294 6:0.88860939 \n4 1:0.87917131 2:0.41153394 3:0.31836031 4:0.81090768 5:0.887565 6:0.92590615 \n4 1:0.85010476 2:0.41153394 3:0.28280816 4:0.74746763 5:0.83272303 6:0.8801866 \n-4 1:0.81463536 2:0.41153394 3:0.24667002 4:0.67362352 5:0.75792704 6:0.81078305 \n4 1:0.84346189 2:0.41153394 3:0.29695396 4:0.76665422 5:0.85020434 6:0.8951033 \n-4 1:0.81160508 2:0.41153394 3:0.26264354 4:0.69736365 5:0.7831915 6:0.83531288 \n-4 1:0.77231516 2:0.41153394 3:0.22613832 4:0.61849783 5:0.69510002 6:0.74611821 \n-4 1:0.79826801 2:0.41153394 3:0.27610067 4:0.72574042 5:0.81561441 6:0.86703542 \n-4 1:0.76319665 2:0.41153394 3:0.24391634 4:0.65464587 5:0.73815109 6:0.79216889 \n-4 1:0.72069133 2:0.41153394 3:0.20960427 4:0.57721443 5:0.64402187 6:0.68939383 \n-4 1:0.68179043 2:0.41153394 3:0.23792453 4:0.64146311 5:0.729184 6:0.79705189 \n-4 1:0.64834555 2:0.41153394 3:0.21497621 4:0.58612074 5:0.65621763 6:0.70995949 \n-4 1:0.6030635 2:0.41153394 3:0.18639866 4:0.5184118 5:0.56298176 6:0.58999882 \n-4 1:0.56116305 2:0.41153394 3:0.211298 4:0.57777075 5:0.64729662 6:0.70904305 \n-4 1:0.52853073 2:0.41153394 3:0.19342012 4:0.53427881 5:0.58548314 6:0.62583696 \n-4 1:0.49283025 2:0.41153394 3:0.17138706 4:0.48192745 5:0.50981682 6:0.51812264 \n-4 1:0.45849528 2:0.41153394 3:0.1933288 4:0.53432693 5:0.58602965 6:0.63438973 \n-4 1:0.43100316 2:0.41153394 3:0.17890259 4:0.49936733 5:0.53431359 6:0.55603396 \n-4 1:0.39598444 2:0.41153394 3:0.16109051 4:0.45685412 5:0.47167834 6:0.46174802 \n4 1:0.97539925 2:0.067429096 3:0.646082 4:0.95530639 5:0.9767318 6:0.9857173 \n4 1:0.96522613 2:0.067429096 3:0.61691633 4:0.93120782 5:0.96017845 6:0.97392814 \n-4 1:0.95031972 2:0.067429096 3:0.57888699 4:0.89204371 5:0.92938039 6:0.94906265 \n4 1:0.91931216 2:0.067429096 3:0.59158726 4:0.92239172 5:0.95405147 6:0.96924055 \n4 1:0.90510334 2:0.067429096 3:0.5543729 4:0.88103934 5:0.92151244 6:0.94339816 \n-4 1:0.88176654 2:0.067429096 3:0.51021121 4:0.82348961 5:0.87083012 6:0.89896825 \n4 1:0.86485312 2:0.067429096 3:0.5609934 4:0.89174108 5:0.93509159 6:0.95402597 \n-4 1:0.85006491 2:0.067429096 3:0.52208828 4:0.83957283 5:0.88962492 6:0.9155692 \n-4 1:0.82840588 2:0.067429096 3:0.47898696 4:0.77590082 5:0.82767172 6:0.85864944 \n4 1:0.78384486 2:0.067429096 3:0.52761112 4:0.84813033 5:0.90853934 6:0.93801948 \n-4 1:0.76794198 2:0.067429096 3:0.49155575 4:0.79297779 5:0.85408909 6:0.88775992 \n-4 1:0.74071295 2:0.067429096 3:0.44850836 4:0.72304483 5:0.77871009 6:0.81240572 \n4 1:0.63682623 2:0.067429096 3:0.47643242 4:0.76493774 5:0.83497363 6:0.89569946 \n-4 1:0.61909458 2:0.067429096 3:0.44811738 4:0.71722262 5:0.77852333 6:0.83338043 \n-4 1:0.598791 2:0.067429096 3:0.41455634 4:0.65898565 5:0.7066917 6:0.74905326 \n-4 1:0.45610548 2:0.067429096 3:0.43433493 4:0.68980457 5:0.74420076 6:0.80465634 \n-4 1:0.42128521 2:0.067429096 3:0.41290869 4:0.6515686 5:0.69403079 6:0.74177718 \n-4 1:0.3973199 2:0.067429096 3:0.38324463 4:0.59899705 5:0.62542129 6:0.65364255 \n4 1:0.33929266 2:0.067429096 3:0.40196048 4:0.63234535 5:0.67000461 6:0.73359019 \n4 1:0.30717303 2:0.067429096 3:0.36080477 4:0.55822348 5:0.57073663 6:0.59274921 \n4 1:0.93399065 2:0.41032924 3:0.59783417 4:0.84190929 5:0.89750138 6:0.92595957 \n-4 1:0.90595546 2:0.41032924 3:0.52675557 4:0.75232557 5:0.81678388 6:0.85451254 \n4 1:0.86884349 2:0.41032924 3:0.54882568 4:0.79721591 5:0.86027193 6:0.89474014 \n4 1:0.83688316 2:0.41032924 3:0.48353911 4:0.70508019 5:0.770587 6:0.80951258 \n-4 1:0.79909048 2:0.41032924 3:0.42019162 4:0.60634089 5:0.66016059 6:0.69152126 \n4 1:0.81190475 2:0.41032924 3:0.49259836 4:0.7117051 5:0.78203532 6:0.82516406 \n4 1:0.74851584 2:0.41032924 3:0.45030562 4:0.6405497 5:0.71098466 6:0.75519602 \n-0.1291220645620671 1:0.70811815 2:0.41032924 3:0.38732716 4:0.54017845 5:0.59142454 6:0.62173185 \n-4 1:0.65812028 2:0.41032924 3:0.32785534 4:0.44278414 5:0.46803981 6:0.47218162 \n4 1:0.61340029 2:0.41032924 3:0.39943043 4:0.54621466 5:0.59971792 6:0.64499079 \n4 1:0.56718004 2:0.41032924 3:0.34225148 4:0.45255833 5:0.47917361 6:0.49550478 \n-4 1:0.51323626 2:0.41032924 3:0.28723094 4:0.3630784 5:0.36155632 6:0.34265877 \n4 1:0.46393127 2:0.41032924 3:0.36091767 4:0.47414782 5:0.50203091 6:0.5272931 \n4 1:0.41890265 2:0.41032924 3:0.30897915 4:0.3896105 5:0.39059442 6:0.38221519 \n-4 1:0.36224567 2:0.41032924 3:0.25797424 4:0.30816486 5:0.2829338 6:0.23861234 \n4 1:0.34347502 2:0.41032924 3:0.33118399 4:0.42270482 5:0.43137066 6:0.43794074 \n4 1:0.303906 2:0.41032924 3:0.28516121 4:0.34844872 5:0.33277335 6:0.30318849 \n4 1:0.25451112 2:0.41032924 3:0.239294 4:0.27618757 5:0.23743598 6:0.17354124 \n4 1:1 3:0.98241836 4:0.99754447 5:0.99837843 6:0.99879687 \n4 1:0.99927781 3:0.97396968 4:0.99499278 5:0.99653001 6:0.99752536 \n4 1:0.99807987 3:0.96785094 4:0.99313412 5:0.99514902 6:0.99653825 \n4 1:0.92550928 3:0.88463259 4:0.98984367 5:0.99445867 6:0.99599134 \n4 1:0.92248998 3:0.88269439 4:0.98579001 5:0.9917863 6:0.99411831 \n4 1:0.91252277 3:0.87943561 4:0.97844374 5:0.98618184 6:0.99029255 \n-4 1:0.85667795 3:0.86407181 4:0.96026885 5:0.98853248 6:0.99389802 \n-4 1:0.84996215 3:0.86241965 4:0.95421974 5:0.98239426 6:0.99048125 \n-4 1:0.82797239 3:0.85970304 4:0.94347269 5:0.97198968 6:0.98376521 \n-4 1:0.78359349 3:0.85232352 4:0.9205106 5:0.9639259 6:0.98760506 \n-4 1:0.7740968 3:0.85087015 4:0.91651049 5:0.95906687 6:0.98343256 \n-4 1:0.76412341 3:0.84902131 4:0.91055943 5:0.94944204 6:0.97481363 \n-4 1:0.61337431 3:0.83940428 4:0.87369959 5:0.90465003 6:0.96092101 \n-4 1:0.59932186 3:0.83841839 4:0.8712363 5:0.90033732 6:0.95480352 \n-4 1:0.58537358 3:0.83696642 4:0.86758813 5:0.893872 6:0.94383497 \n-3.429005082149631 1:0.42062928 3:0.82941095 4:0.83902061 5:0.84510353 6:0.87138257 \n-4 1:0.4002542 3:0.82840514 4:0.8368136 5:0.84093631 6:0.8674834 \n4 1:0.3094628 3:0.82716541 4:0.83024299 5:0.82796719 6:0.86356706 \n4 1:0.29001316 3:0.82647757 4:0.82867904 5:0.8248098 6:0.86408434 \n4 1:0.27710266 3:0.8257051 4:0.82728426 5:0.82235905 6:0.85969923 \n-4 1:0.90663913 2:0.14610739 3:0.43817477 4:0.82784627 5:0.90710157 6:0.94001176 \n4 1:0.90426096 2:0.14610739 3:0.43326406 4:0.82123487 5:0.9021133 6:0.93612907 \n-4 1:0.87301894 2:0.14610739 3:0.38374963 4:0.74222319 5:0.83336461 6:0.87727214 \n4 1:0.86811426 2:0.14610739 3:0.40559067 4:0.79104253 5:0.88029881 6:0.91964051 \n4 1:0.83600801 2:0.14610739 3:0.36858627 4:0.72304979 5:0.81750507 6:0.86398873 \n-4 1:0.79303316 2:0.14610739 3:0.33543633 4:0.65617509 5:0.74453253 6:0.78951163 \n4 1:0.82226065 2:0.14610739 3:0.37726233 4:0.73857387 5:0.83579524 6:0.88322128 \n-4 1:0.78986743 2:0.14610739 3:0.34480055 4:0.67269731 5:0.7665205 6:0.81617937 \n-4 1:0.74513395 2:0.14610739 3:0.31379389 4:0.60684271 5:0.68827333 6:0.72971662 \n4 1:0.75127417 2:0.14610739 3:0.35645593 4:0.69561666 5:0.79695173 6:0.84926516 \n-4 1:0.66677794 2:0.14610739 3:0.29749496 4:0.56835508 5:0.64245656 6:0.67864295 \n4 1:0.62293836 2:0.14610739 3:0.32749068 4:0.63131327 5:0.72687613 6:0.78818537 \n-4 1:0.58735044 2:0.14610739 3:0.30296925 4:0.57601896 5:0.65321265 6:0.69799032 \n-4 1:0.54225634 2:0.14610739 3:0.27770782 4:0.51923537 5:0.57477828 6:0.59501544 \n4 1:0.47989563 2:0.14610739 3:0.30820332 4:0.58503378 5:0.66456631 6:0.7174928 \n4 1:0.4414077 2:0.14610739 3:0.28822665 4:0.53887566 5:0.59925188 6:0.62987117 \n-4 1:0.39949501 2:0.14610739 3:0.26598279 4:0.48912153 5:0.52873127 6:0.53229307 \n4 1:0.39206975 2:0.14610739 3:0.29566289 4:0.55497136 5:0.62126765 6:0.66418112 \n4 1:0.36544059 2:0.14610739 3:0.2785156 4:0.5155536 5:0.56455807 6:0.58211923 \n", 14 | "norm_type": "linear_rescale", 15 | "score_clip": [ 16 | 0.0, 17 | 100.0 18 | ], 19 | "feature_names": [ 20 | "VMAF_integer_feature_adm2_score", 21 | "VMAF_integer_feature_motion2_score", 22 | "VMAF_integer_feature_vif_scale0_score", 23 | "VMAF_integer_feature_vif_scale1_score", 24 | "VMAF_integer_feature_vif_scale2_score", 25 | "VMAF_integer_feature_vif_scale3_score" 26 | ], 27 | "intercepts": [ 28 | -0.31191973282964003, 29 | -0.8536192302086182, 30 | -0.01336836451078975, 31 | -0.09603743694887917, 32 | -0.21890356649141152, 33 | -0.35835059999617175, 34 | -0.5373563330683786 35 | ], 36 | "model_type": "LIBSVMNUSVR", 37 | "slopes": [ 38 | 0.012388059998472608, 39 | 1.853012066458466, 40 | 0.05141551931924402, 41 | 1.0960374437054892, 42 | 1.2189036205165853, 43 | 1.3583508615652835, 44 | 1.5373567703674345 45 | ], 46 | "feature_dict": { 47 | "VMAF_integer_feature": [ 48 | "vif_scale0", 49 | "vif_scale1", 50 | "vif_scale2", 51 | "vif_scale3", 52 | "adm2", 53 | "motion2" 54 | ] 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /ffmpeg_quality_metrics/vmaf_models/vmaf_v0.6.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "param_dict": { 3 | "C": 4.0, 4 | "score_transform": { 5 | "p2": -0.00705305, 6 | "out_gte_in": "true", 7 | "p0": 1.70674692, 8 | "p1": 1.72643844 9 | }, 10 | "norm_type": "clip_0to1", 11 | "score_clip": [ 12 | 0.0, 13 | 100.0 14 | ], 15 | "nu": 0.9, 16 | "gamma": 0.04 17 | }, 18 | "model_dict": { 19 | "model": "svm_type nu_svr\nkernel_type rbf\ngamma 0.04\nnr_class 2\ntotal_sv 211\nrho -1.33133\nSV\n-4 1:0.65734273 2:0.34681232 3:0.093755557 4:0.60913934 5:0.69117362 6:0.73495824 \n4 1:0.8727433 2:0.49612229 3:0.59146724 4:0.78105663 5:0.84916292 6:0.8882561 \n4 1:0.89890005 2:0.49612229 3:0.66823667 4:0.86050887 5:0.90873162 6:0.93335071 \n4 1:0.20371751 2:0.49612229 3:0.10534315 4:-1.110223e-16 6:2.220446e-16 \n4 1:0.33913836 2:0.49612229 3:0.14024497 4:0.074708413 5:0.10231651 6:0.1259153 \n4 1:0.66426757 2:0.49612229 3:0.35268026 4:0.4805681 5:0.59603341 6:0.67408692 \n4 1:0.59561632 2:0.49612229 3:0.27561601 4:0.33977371 5:0.4325213 6:0.50244952 \n4 1:0.50821444 2:0.49612229 3:0.20276685 4:0.2004308 5:0.25758651 6:0.30054029 \n4 1:0.77877298 2:0.49612229 3:0.444392 4:0.61630491 5:0.71210086 6:0.77386496 \n4 1:0.71666017 2:0.49612229 3:0.35967401 4:0.47825205 5:0.57045236 6:0.63752441 \n4 1:0.64025669 2:0.49612229 3:0.27766156 4:0.33407105 5:0.40732401 6:0.46359154 \n4 1:0.88343983 2:0.23066177 3:0.65873851 4:0.86090402 5:0.90661213 6:0.93008753 \n4 1:0.90822691 2:0.23066177 3:0.71439481 4:0.90904598 5:0.94146542 6:0.95674338 \n-4 1:0.49037399 2:0.23066177 3:0.32329421 4:0.33686197 5:0.39456977 6:0.44944683 \n-4 1:0.69044383 2:0.23066177 3:0.43933868 4:0.56327049 5:0.65339511 6:0.71348696 \n-4 1:0.62390093 2:0.23066177 3:0.3800888 4:0.44927578 5:0.52327759 6:0.57907725 \n4 1:0.81887942 2:0.23066177 3:0.56208506 4:0.76164281 5:0.83176644 6:0.86914911 \n4 1:0.77189471 2:0.23066177 3:0.50145055 4:0.66525882 5:0.74327951 6:0.79017822 \n4 1:0.71405433 2:0.23066177 3:0.43952897 4:0.55736023 5:0.63319876 6:0.68402869 \n4 1:0.92114073 3:0.45198963 4:0.97703695 5:0.9907273 6:0.99510256 \n4 1:1 3:0.83319067 4:0.98956086 5:0.99577089 6:0.99784595 \n4 4:0.10344019 5:0.34323945 6:0.63855969 \n4 1:0.19531482 3:0.034330388 4:0.25480402 5:0.54197045 6:0.78020579 \n4 1:0.48394064 3:0.11866359 4:0.58816959 5:0.86435738 6:0.96191842 \n4 1:0.47628079 3:0.11185039 4:0.56180003 5:0.83415721 6:0.93617329 \n4 1:0.46278632 3:0.10308547 4:0.52247575 5:0.78583924 6:0.89392193 \n4 1:0.7038079 3:0.2174879 4:0.84423613 5:0.9662906 6:0.98430594 \n4 1:0.69596686 3:0.20657211 4:0.81196884 5:0.94140702 6:0.96680805 \n4 1:0.68404358 3:0.19261438 4:0.76066415 5:0.89973293 6:0.93660362 \n4 1:0.84073022 2:0.34681232 3:0.22411304 4:0.88845644 5:0.94169671 6:0.96221395 \n-4 1:0.33900937 2:0.34681232 3:0.027607294 4:0.40659646 5:0.45456869 6:0.48256597 \n-4 1:0.44593129 2:0.34681232 3:0.041939301 4:0.45284872 5:0.5157613 6:0.55335821 \n-4 1:0.67301747 2:0.34681232 3:0.11526222 4:0.68549511 5:0.78556255 6:0.83507583 \n-4 1:0.62833533 2:0.34681232 3:0.092281981 4:0.61278125 5:0.70626575 6:0.75613977 \n-4 1:0.57196879 2:0.34681232 3:0.067548447 4:0.53383404 5:0.61287548 6:0.65468717 \n-0.3312466607741135 1:0.75125028 2:0.34681232 3:0.1457048 4:0.75791308 5:0.84155109 6:0.88132116 \n-4 1:0.71121936 2:0.34681232 3:0.12095689 4:0.68834617 5:0.77453583 6:0.81892861 \n-4 1:0.80269544 2:0.25207203 3:0.3681723 4:0.80658472 5:0.8702283 6:0.90583519 \n-4 1:0.86095387 2:0.25207203 3:0.52475418 4:0.85053413 5:0.90454501 6:0.93093678 \n-4 1:0.5008963 2:0.25207203 3:0.2005129 4:0.41516485 5:0.45282017 6:0.47396143 \n-4 1:0.56977992 2:0.25207203 3:0.21631076 4:0.45848604 5:0.51102137 6:0.53823055 \n-4 1:0.72779828 2:0.25207203 3:0.3051639 4:0.67537297 5:0.75767261 6:0.80327187 \n-4 1:0.68848569 2:0.25207203 3:0.27393051 4:0.60399854 5:0.68000038 6:0.72275152 \n-4 1:0.64121401 2:0.25207203 3:0.23994344 4:0.52538719 5:0.5891732 6:0.62164073 \n-4 1:0.76673633 2:0.25207203 3:0.33053889 4:0.73085549 5:0.80341439 6:0.84546456 \n-4 1:0.73041172 2:0.25207203 3:0.29691153 4:0.66166141 5:0.73408074 6:0.77757209 \n-4 1:0.68529047 2:0.25207203 3:0.26283557 4:0.58611788 5:0.65192525 6:0.69015011 \n4 1:0.86902267 2:0.48885268 3:0.5143645 4:0.8587242 5:0.91841685 6:0.94498293 \n4 1:0.89266106 2:0.48885268 3:0.55208861 4:0.89938377 5:0.94642982 6:0.96615102 \n-4 1:0.42554844 2:0.48885268 3:0.2554221 4:0.36916892 5:0.43100226 6:0.50888404 \n-4 1:0.52520274 2:0.48885268 3:0.27824915 4:0.42915458 5:0.50850476 6:0.58585271 \n-4 1:0.69357445 2:0.48885268 3:0.35289928 4:0.61359907 5:0.7217863 6:0.78790011 \n-4 1:0.64679648 2:0.48885268 3:0.31268451 4:0.5167094 5:0.61224976 6:0.68477529 \n4 1:0.80595874 2:0.48885268 3:0.44075432 4:0.7803455 5:0.86328719 6:0.90222545 \n-4 1:0.7715192 2:0.48885268 3:0.4012577 4:0.70792536 5:0.80063653 6:0.85083872 \n4 1:0.82199966 2:0.20629643 3:0.30562098 4:0.80541317 5:0.89285836 6:0.92907353 \n-4 1:0.84774006 2:0.20629643 3:0.36755712 4:0.8681203 5:0.93297792 6:0.95700049 \n4 1:0.26631905 2:0.20629643 3:0.076468978 4:0.29833807 5:0.37989948 6:0.4576277 \n-4 1:0.65439648 2:0.20629643 3:0.19487894 4:0.63045155 5:0.76931142 6:0.83706632 \n4 1:0.55295603 2:0.20629643 3:0.13877412 4:0.4724047 5:0.59295828 6:0.66834832 \n4 1:0.75448924 2:0.20629643 3:0.24707248 4:0.72284103 5:0.83178838 6:0.88053503 \n4 1:0.83852041 2:0.15600331 3:0.1625414 4:0.81948421 5:0.90185357 6:0.9347395 \n4 1:0.85805266 2:0.15600331 3:0.19693206 4:0.86294641 5:0.92990351 6:0.95498998 \n-4 1:0.43384835 2:0.15600331 3:0.030541611 4:0.37279112 5:0.4588284 6:0.52004828 \n-4 1:0.72588966 2:0.48885268 3:0.35394597 4:0.61189191 5:0.70897304 6:0.77099691 \n-4 1:0.65865915 2:0.20629643 3:0.1796405 4:0.56432133 5:0.68049028 6:0.74616621 \n-4 1:0.53095193 2:0.15600331 3:0.046271684 4:0.4328793 5:0.5309142 6:0.59282089 \n-4 1:0.71891465 2:0.15600331 3:0.11085278 4:0.68794624 5:0.80350923 6:0.85660483 \n-4 1:0.68635753 2:0.15600331 3:0.091457045 4:0.60849701 5:0.72282659 6:0.78137183 \n-4 1:0.64162333 2:0.15600331 3:0.068820233 4:0.51732819 5:0.62198733 6:0.67977328 \n4 1:0.78395225 2:0.15600331 3:0.13401869 4:0.75274384 5:0.8506531 6:0.89321405 \n-4 1:0.75276337 2:0.15600331 3:0.11289462 4:0.67598462 5:0.78117168 6:0.83259364 \n-4 1:0.71345342 2:0.15600331 3:0.089218917 4:0.58797907 5:0.69284768 6:0.74971699 \n4 1:0.93500967 2:0.08765484 3:0.72226864 4:0.93291747 5:0.960644 6:0.97304054 \n4 1:0.95150668 2:0.08765484 3:0.77391346 4:0.95596295 5:0.97544784 6:0.98405871 \n-4 1:0.48148634 2:0.08765484 3:0.36628046 4:0.45852823 5:0.56005228 6:0.65708595 \n-4 1:0.59853216 2:0.08765484 3:0.42071301 4:0.56376512 5:0.66454599 6:0.741236 \n-4 1:0.79297271 2:0.08765484 3:0.5597726 4:0.80653689 5:0.88996341 6:0.92691132 \n-4 1:0.76798941 2:0.08765484 3:0.52069978 4:0.74484555 5:0.83431246 6:0.87935204 \n-4 1:0.73225133 2:0.08765484 3:0.47011786 4:0.66069877 5:0.75226598 6:0.80539407 \n-4 1:0.87240592 2:0.08765484 3:0.62680052 4:0.88208508 5:0.93041565 6:0.9505376 \n-4 1:0.84834872 2:0.08765484 3:0.58154998 4:0.82429855 5:0.8858516 6:0.91563291 \n-4 1:0.84365382 2:0.93973481 3:0.36718425 4:0.81512123 5:0.88887359 6:0.92320992 \n-4 1:0.89242364 2:0.93973481 3:0.41336953 4:0.88038833 5:0.93688884 6:0.95992879 \n-4 1:0.31373571 2:0.93973481 3:0.18757116 4:0.34864297 5:0.3777168 6:0.38922611 \n-4 1:0.42490775 2:0.93973481 3:0.20295859 4:0.39290035 5:0.43632323 6:0.45871216 \n-4 1:0.66865444 2:0.93973481 3:0.28594627 4:0.63969879 5:0.73360583 6:0.78380069 \n-4 1:0.62642524 2:0.93973481 3:0.26141889 4:0.56602175 5:0.64775366 6:0.69263211 \n-4 1:0.57430455 2:0.93973481 3:0.23537634 4:0.48984694 5:0.55363885 6:0.5853905 \n-4 1:0.76178555 2:0.93973481 3:0.32205372 4:0.7176044 5:0.80237787 6:0.84588741 \n-4 1:0.72282163 2:0.93973481 3:0.29554025 4:0.64471949 5:0.72634443 6:0.77062686 \n-4 1:0.67693861 2:0.93973481 3:0.2669659 4:0.56720118 5:0.63868728 6:0.67673331 \n4 1:0.86023804 2:0.49739676 3:0.53966638 4:0.77392585 5:0.84784447 6:0.89031641 \n1.296591709971377 1:0.31779385 2:0.49739676 3:0.17094319 4:0.12195679 5:0.13277563 6:0.14165413 \n4 1:0.68317784 2:0.49739676 3:0.37192301 4:0.52750491 5:0.62426522 6:0.6929947 \n4 1:0.55611181 2:0.49739676 3:0.24752355 4:0.28326524 5:0.33261781 6:0.37104424 \n4 1:0.7772257 2:0.49739676 3:0.43832146 4:0.63397606 5:0.7240692 6:0.78367237 \n4 1:0.66186286 2:0.49739676 3:0.30599867 4:0.39201262 5:0.45927759 6:0.51239284 \n4 1:0.94601776 2:0.04579546 3:0.69472114 4:0.97790884 5:0.9891237 6:0.993277 \n4 1:0.98838404 2:0.04579546 3:0.90293444 4:0.99181622 5:0.99642641 6:0.9978864 \n4 1:0.30006056 2:0.04579546 3:0.31879 4:0.45852885 5:0.59717781 6:0.71487885 \n-4 1:0.44902891 2:0.04579546 3:0.35412414 4:0.55926446 5:0.70175505 6:0.79649177 \n-4 1:0.69856222 2:0.04579546 3:0.45989947 4:0.82115248 5:0.92520734 6:0.9594384 \n-4 1:0.67730161 2:0.04579546 3:0.44400319 4:0.77920819 5:0.88713866 6:0.92903178 \n-4 1:0.64419192 2:0.04579546 3:0.42297435 4:0.72390263 5:0.83364665 6:0.88344569 \n-4 1:0.80781899 2:0.04579546 3:0.52334234 4:0.88859427 5:0.94013924 6:0.95946903 \n-4 1:0.78080761 2:0.04579546 3:0.499439 4:0.84012074 5:0.90229375 6:0.92936693 \n4 1:0.97128596 2:0.014623935 3:0.90135809 4:0.99584619 5:0.9970631 6:0.99757649 \n4 1:0.99645027 2:0.014623935 3:1 4:1 5:1 6:1 \n-4 1:0.5326065 2:0.014623935 3:0.75468972 4:0.76017077 5:0.83753774 6:0.92265059 \n-4 1:0.62757004 2:0.014623935 3:0.77708563 4:0.84258654 5:0.91016348 6:0.95440359 \n-4 1:0.79306842 2:0.014623935 3:0.78900741 4:0.90386551 5:0.96905764 6:0.98466408 \n-4 1:0.77722867 2:0.014623935 3:0.78701408 4:0.89679281 5:0.96056131 6:0.977629 \n-4 1:0.75934622 2:0.014623935 3:0.78422805 4:0.88268036 5:0.94383829 6:0.96596858 \n-4 1:0.8878718 2:0.014623935 3:0.81445984 4:0.96615706 5:0.98858241 6:0.99176534 \n-4 1:0.88211614 2:0.014623935 3:0.81253935 4:0.95982371 5:0.98309178 6:0.9870796 \n4 1:0.83805466 2:0.22767235 3:0.31750162 4:0.85145925 5:0.9121085 6:0.93772147 \n4 1:0.86620985 2:0.22767235 3:0.35742938 4:0.89821492 5:0.94339974 6:0.96076173 \n4 1:0.39289606 2:0.22767235 3:0.12019254 4:0.3951559 5:0.44657802 6:0.46771549 \n4 1:0.48692411 2:0.22767235 3:0.13362033 4:0.43434224 5:0.49900609 6:0.53177669 \n4 1:0.69743918 2:0.22767235 3:0.2263303 4:0.68859985 5:0.78706365 6:0.83662428 \n4 1:0.65237548 2:0.22767235 3:0.19328493 4:0.60107975 5:0.69684945 6:0.74949279 \n4 1:0.59461718 2:0.22767235 3:0.15963705 4:0.51010642 5:0.59283393 6:0.63883591 \n4 1:0.77302727 2:0.22767235 3:0.26078021 4:0.76359704 5:0.8470807 6:0.8858359 \n4 1:0.72953038 2:0.22767235 3:0.22331233 4:0.67735915 5:0.77029889 6:0.81802539 \n4 1:0.87210923 2:0.16787772 3:0.69408521 4:0.91495146 5:0.94890261 6:0.96269344 \n-4 1:0.81595959 2:0.08765484 3:0.52947327 4:0.7501341 5:0.82294191 6:0.86264385 \n4 1:0.72562415 2:0.49739676 3:0.37130724 4:0.51472366 5:0.59961357 6:0.66258291 \n-4 1:0.87135693 2:0.014623935 3:0.80905852 4:0.94637428 5:0.97242826 6:0.97946694 \n-4 1:0.48910215 2:0.16787772 3:0.49792761 4:0.59161372 5:0.62979552 6:0.64254584 \n-4 1:0.5685964 2:0.16787772 3:0.5149767 4:0.63026581 5:0.67890679 6:0.69964851 \n-4 1:0.75935478 2:0.16787772 3:0.60695536 4:0.80906778 5:0.87125816 6:0.89810007 \n-4 1:0.71788601 2:0.16787772 3:0.57600091 4:0.75310216 5:0.81471966 6:0.84249923 \n-4 1:0.66516668 2:0.16787772 3:0.54473368 4:0.69254626 5:0.74796983 6:0.77177867 \n4 1:0.81880869 2:0.16787772 3:0.64309172 4:0.86078024 5:0.90892223 6:0.92908907 \n-4 1:0.78054558 2:0.16787772 3:0.60849279 4:0.80724494 5:0.86183239 6:0.88618408 \n4 1:0.95353512 2:0.055921852 3:0.61526026 4:0.94655706 5:0.97211195 6:0.98210701 \n4 1:0.98368527 2:0.055921852 3:0.7405327 4:0.96928567 5:0.9853799 6:0.99080378 \n4 1:0.11318821 2:0.055921852 3:0.1590151 4:0.30536689 5:0.48614515 6:0.64344462 \n4 1:0.30298819 2:0.055921852 3:0.19401703 4:0.41679982 5:0.61495039 6:0.74140301 \n4 1:0.60614412 2:0.055921852 3:0.31791569 4:0.72365433 5:0.88324129 6:0.93484545 \n4 1:0.58738733 2:0.055921852 3:0.29301498 4:0.67070014 5:0.83429953 6:0.89348041 \n4 1:0.79496816 2:0.055921852 3:0.42192974 4:0.86711004 5:0.94030868 6:0.96084539 \n4 1:0.77749763 2:0.055921852 3:0.38714172 4:0.81340799 5:0.90059649 6:0.93006702 \n4 1:0.75215882 2:0.055921852 3:0.34721658 4:0.73960747 5:0.84370247 6:0.88485372 \n4 1:0.89732805 2:0.58937038 3:0.58823535 4:0.80035053 5:0.86988422 6:0.90533033 \n-4 1:0.9228759 2:0.58937038 3:0.65797705 4:0.87169952 5:0.92200942 6:0.94454256 \n4 1:0.19504362 2:0.58937038 3:0.21585801 4:0.1754362 5:0.20844015 6:0.23846443 \n4 1:0.34425894 2:0.58937038 3:0.24672569 4:0.24188506 5:0.29544562 6:0.33843061 \n4 1:0.66407117 2:0.58937038 3:0.40045124 4:0.55415203 5:0.66628031 6:0.73418465 \n4 1:0.60780044 2:0.58937038 3:0.34931828 4:0.4519606 5:0.54893247 6:0.61355219 \n4 1:0.53476258 2:0.58937038 3:0.29851601 4:0.34826788 5:0.42168642 6:0.47203603 \n4 1:0.79195776 2:0.58937038 3:0.47493233 4:0.66775916 5:0.76196439 6:0.81489875 \n4 1:0.7415564 2:0.58937038 3:0.41507439 4:0.56413083 5:0.65815516 6:0.7166999 \n4 1:0.82021207 2:1 3:0.37381485 4:0.7891612 5:0.87031145 6:0.90944281 \n-3.795805084530972 1:0.85903236 2:1 3:0.43235998 4:0.86707094 5:0.92632217 6:0.95151451 \n-4 1:0.25243046 2:1 3:0.084027451 4:0.15537936 5:0.17410072 6:0.17212333 \n-4 1:0.35643487 2:1 3:0.10644455 4:0.21484368 5:0.25587544 6:0.27527817 \n-4 1:0.57605414 2:1 3:0.19031962 4:0.43030863 5:0.5277316 6:0.59069772 \n-4 1:0.49071444 2:1 3:0.14452095 4:0.31406915 5:0.38353445 6:0.42653517 \n4 1:0.73255545 2:1 3:0.28883701 4:0.65284485 5:0.75623242 6:0.81297442 \n0.4082706381617505 1:0.67015395 2:1 3:0.2367756 4:0.5367057 5:0.64063877 6:0.70451767 \n-4 1:0.84450653 2:0.083369236 3:0.57279245 4:0.85249389 5:0.91751611 6:0.94621989 \n-4 1:0.39559773 2:0.083369236 3:0.28184137 4:0.37025203 5:0.46733936 6:0.53517338 \n-4 1:0.70621493 2:0.083369236 3:0.42718441 4:0.69347659 5:0.81124449 6:0.87136343 \n-4 1:0.65615861 2:0.083369236 3:0.37833052 4:0.59301482 5:0.71772587 6:0.7905538 \n-4 1:0.58837863 2:0.083369236 3:0.33229353 4:0.48675881 5:0.60141743 6:0.67458413 \n-4 1:0.77687144 2:0.083369236 3:0.48094343 4:0.76665994 5:0.86191893 6:0.90760934 \n-1.966116876631112 1:0.72849768 2:0.083369236 3:0.42082971 4:0.66591147 5:0.77995959 6:0.84260661 \n-3.906831378063804 1:0.66320082 2:0.083369236 3:0.36350305 4:0.54888271 5:0.66506794 6:0.73685112 \n4 1:0.84500499 2:0.42532178 3:0.43562507 4:0.80721931 5:0.87934044 6:0.91434143 \n4 1:0.8874543 2:0.42532178 3:0.50912639 4:0.87959883 5:0.93223488 6:0.95450335 \n4 1:0.31032192 2:0.42532178 3:0.18976794 4:0.30662908 5:0.34637104 6:0.3661022 \n4 1:0.41026349 2:0.42532178 3:0.20589097 4:0.35241209 5:0.40358156 6:0.42577381 \n4 1:0.67552108 2:0.42532178 3:0.30879992 4:0.60375124 5:0.70097073 6:0.75507206 \n4 1:0.62772585 2:0.42532178 3:0.27349745 4:0.5196735 5:0.60339149 6:0.65103342 \n4 1:0.5741386 2:0.42532178 3:0.24033766 4:0.43855753 5:0.50243186 6:0.53322825 \n4 1:0.7629976 2:0.42532178 3:0.35347476 4:0.69239941 5:0.78245146 6:0.83117443 \n4 1:0.71746409 2:0.42532178 3:0.31296983 4:0.60525302 5:0.69243388 6:0.7432587 \n-4 1:0.73137955 2:0.16787772 3:0.57222383 4:0.74405775 5:0.79993424 6:0.82484891 \n4 1:0.67383121 2:0.58937038 3:0.35481019 4:0.45269287 5:0.53578336 6:0.59116487 \n4 1:0.5905971 2:1 3:0.18559792 4:0.41535212 5:0.50422336 6:0.56173557 \n4 1:0.66157018 2:0.42532178 3:0.27479904 4:0.51802649 5:0.59270541 6:0.63560969 \n-4 1:0.66827754 2:0.54342577 3:0.18169339 4:0.50290989 5:0.59875259 6:0.65332628 \n4 1:0.85027066 2:0.20820673 3:0.40997978 4:0.82462749 5:0.89794736 6:0.93142825 \n4 1:0.87892054 2:0.20820673 3:0.45891267 4:0.87823329 5:0.93535353 6:0.95883927 \n4 1:0.3986268 2:0.20820673 3:0.17753958 4:0.33495583 5:0.39777832 6:0.44399359 \n-4 1:0.48997993 2:0.20820673 3:0.20172681 4:0.39715881 5:0.47368229 6:0.52781628 \n4 1:0.7022939 2:0.20820673 3:0.31094767 4:0.6676259 5:0.77726116 6:0.83518027 \n-4 1:0.65773092 2:0.20820673 3:0.27420721 4:0.57889989 5:0.68485118 6:0.74837036 \n0.2951376518668717 1:0.60031736 2:0.20820673 3:0.23419121 4:0.48018865 5:0.57200972 6:0.63197473 \n4 1:0.77623676 2:0.20820673 3:0.3510016 4:0.74206651 5:0.83508543 6:0.88101902 \n4 1:0.73562396 2:0.20820673 3:0.31004997 4:0.6557112 5:0.75585014 6:0.81164989 \n-4 1:0.67923081 2:0.20820673 3:0.26679137 4:0.55816547 5:0.65579282 6:0.71593631 \n4 1:0.83968539 2:0.54342577 3:0.32439292 4:0.78747769 5:0.87303614 6:0.91271252 \n4 1:0.86656342 2:0.54342577 3:0.37898741 4:0.85252726 5:0.92049615 6:0.94848246 \n-4 1:0.42728303 2:0.54342577 3:0.10123262 4:0.31581962 5:0.38571265 6:0.42827036 \n-4 1:0.63194526 2:0.54342577 3:0.18169045 4:0.51611903 5:0.62179755 6:0.68216176 \n4 1:0.56954706 2:0.54342577 3:0.14271477 4:0.41491191 5:0.50173488 6:0.55220392 \n4 1:0.76753176 2:0.54342577 3:0.26295318 4:0.6905031 5:0.79291823 6:0.84469464 \n-4 1:0.72348649 2:0.54342577 3:0.22334634 4:0.60145902 5:0.70573225 6:0.76318544 \n4 1:0.83584492 2:0.047285912 3:0.53826775 4:0.933335 5:0.95948954 6:0.96870909 \n4 1:0.85530855 2:0.047285912 3:0.55323777 4:0.95113339 5:0.97249918 6:0.9795177 \n-4 1:0.53835734 2:0.047285912 3:0.41965074 4:0.71632669 5:0.73953043 6:0.73487553 \n-4 1:0.59175144 2:0.047285912 3:0.43113594 4:0.74141738 5:0.76929188 6:0.77018949 \n-4 1:0.75962366 2:0.047285912 3:0.49613729 4:0.87838146 5:0.91688438 6:0.93150362 \n-4 1:0.72043129 2:0.047285912 3:0.47217411 4:0.83138845 5:0.8704229 6:0.88419439 \n-4 1:0.67287449 2:0.047285912 3:0.44652268 4:0.77691812 5:0.81043483 6:0.8177009 \n-4 1:0.8023177 2:0.047285912 3:0.51559706 4:0.90512389 5:0.93743101 6:0.9492968 \n-4 1:0.76751376 2:0.047285912 3:0.49225957 4:0.86357299 5:0.89948127 6:0.91221155 \n-4 1:0.72124785 2:0.047285912 3:0.46606653 4:0.81323145 5:0.84847474 6:0.85892657 \n", 20 | "score_transform": { 21 | "p2": -0.00705305, 22 | "out_gte_in": "true", 23 | "p0": 1.70674692, 24 | "p1": 1.72643844 25 | }, 26 | "norm_type": "linear_rescale", 27 | "score_clip": [ 28 | 0.0, 29 | 100.0 30 | ], 31 | "feature_names": [ 32 | "VMAF_integer_feature_adm2_score", 33 | "VMAF_integer_feature_motion2_score", 34 | "VMAF_integer_feature_vif_scale0_score", 35 | "VMAF_integer_feature_vif_scale1_score", 36 | "VMAF_integer_feature_vif_scale2_score", 37 | "VMAF_integer_feature_vif_scale3_score" 38 | ], 39 | "intercepts": [ 40 | -0.3092981927591963, 41 | -1.7993968597186747, 42 | -0.003017198086831897, 43 | -0.1728125095425364, 44 | -0.5294309090081222, 45 | -0.7577185792093722, 46 | -1.083428597549764 47 | ], 48 | "model_type": "LIBSVMNUSVR", 49 | "slopes": [ 50 | 0.012020766332648465, 51 | 2.8098077502505414, 52 | 0.06264407466686016, 53 | 1.222763456258933, 54 | 1.5360318811084146, 55 | 1.7620864995501058, 56 | 2.08656468286432 57 | ], 58 | "feature_dict": { 59 | "VMAF_integer_feature": [ 60 | "vif_scale0", 61 | "vif_scale1", 62 | "vif_scale2", 63 | "vif_scale3", 64 | "adm2", 65 | "motion2" 66 | ] 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /ffmpeg_quality_metrics/vmaf_models/vmaf_v0.6.1neg.json: -------------------------------------------------------------------------------- 1 | { 2 | "param_dict": { 3 | "C": 4.0, 4 | "score_transform": { 5 | "p2": -0.00705305, 6 | "out_gte_in": "true", 7 | "p0": 1.70674692, 8 | "p1": 1.72643844 9 | }, 10 | "norm_type": "clip_0to1", 11 | "score_clip": [ 12 | 0.0, 13 | 100.0 14 | ], 15 | "nu": 0.9, 16 | "gamma": 0.04 17 | }, 18 | "model_dict": { 19 | "slopes": [ 20 | 0.012020766332648465, 21 | 2.8098077502505414, 22 | 0.06264407466686016, 23 | 1.222763456258933, 24 | 1.5360318811084146, 25 | 1.7620864995501058, 26 | 2.08656468286432 27 | ], 28 | "score_transform": { 29 | "p2": -0.00705305, 30 | "out_gte_in": "true", 31 | "p0": 1.70674692, 32 | "p1": 1.72643844 33 | }, 34 | "feature_opts_dicts": [ 35 | { 36 | "adm_enhn_gain_limit": 1.0 37 | }, 38 | {}, 39 | { 40 | "vif_enhn_gain_limit": 1.0 41 | }, 42 | { 43 | "vif_enhn_gain_limit": 1.0 44 | }, 45 | { 46 | "vif_enhn_gain_limit": 1.0 47 | }, 48 | { 49 | "vif_enhn_gain_limit": 1.0 50 | } 51 | ], 52 | "norm_type": "linear_rescale", 53 | "score_clip": [ 54 | 0.0, 55 | 100.0 56 | ], 57 | "feature_names": [ 58 | "VMAF_integer_feature_adm2_score", 59 | "VMAF_integer_feature_motion2_score", 60 | "VMAF_integer_feature_vif_scale0_score", 61 | "VMAF_integer_feature_vif_scale1_score", 62 | "VMAF_integer_feature_vif_scale2_score", 63 | "VMAF_integer_feature_vif_scale3_score" 64 | ], 65 | "intercepts": [ 66 | -0.3092981927591963, 67 | -1.7993968597186747, 68 | -0.003017198086831897, 69 | -0.1728125095425364, 70 | -0.5294309090081222, 71 | -0.7577185792093722, 72 | -1.083428597549764 73 | ], 74 | "model_type": "LIBSVMNUSVR", 75 | "model": "svm_type nu_svr\nkernel_type rbf\ngamma 0.04\nnr_class 2\ntotal_sv 211\nrho -1.33133\nSV\n-4 1:0.65734273 2:0.34681232 3:0.093755557 4:0.60913934 5:0.69117362 6:0.73495824 \n4 1:0.8727433 2:0.49612229 3:0.59146724 4:0.78105663 5:0.84916292 6:0.8882561 \n4 1:0.89890005 2:0.49612229 3:0.66823667 4:0.86050887 5:0.90873162 6:0.93335071 \n4 1:0.20371751 2:0.49612229 3:0.10534315 4:-1.110223e-16 6:2.220446e-16 \n4 1:0.33913836 2:0.49612229 3:0.14024497 4:0.074708413 5:0.10231651 6:0.1259153 \n4 1:0.66426757 2:0.49612229 3:0.35268026 4:0.4805681 5:0.59603341 6:0.67408692 \n4 1:0.59561632 2:0.49612229 3:0.27561601 4:0.33977371 5:0.4325213 6:0.50244952 \n4 1:0.50821444 2:0.49612229 3:0.20276685 4:0.2004308 5:0.25758651 6:0.30054029 \n4 1:0.77877298 2:0.49612229 3:0.444392 4:0.61630491 5:0.71210086 6:0.77386496 \n4 1:0.71666017 2:0.49612229 3:0.35967401 4:0.47825205 5:0.57045236 6:0.63752441 \n4 1:0.64025669 2:0.49612229 3:0.27766156 4:0.33407105 5:0.40732401 6:0.46359154 \n4 1:0.88343983 2:0.23066177 3:0.65873851 4:0.86090402 5:0.90661213 6:0.93008753 \n4 1:0.90822691 2:0.23066177 3:0.71439481 4:0.90904598 5:0.94146542 6:0.95674338 \n-4 1:0.49037399 2:0.23066177 3:0.32329421 4:0.33686197 5:0.39456977 6:0.44944683 \n-4 1:0.69044383 2:0.23066177 3:0.43933868 4:0.56327049 5:0.65339511 6:0.71348696 \n-4 1:0.62390093 2:0.23066177 3:0.3800888 4:0.44927578 5:0.52327759 6:0.57907725 \n4 1:0.81887942 2:0.23066177 3:0.56208506 4:0.76164281 5:0.83176644 6:0.86914911 \n4 1:0.77189471 2:0.23066177 3:0.50145055 4:0.66525882 5:0.74327951 6:0.79017822 \n4 1:0.71405433 2:0.23066177 3:0.43952897 4:0.55736023 5:0.63319876 6:0.68402869 \n4 1:0.92114073 3:0.45198963 4:0.97703695 5:0.9907273 6:0.99510256 \n4 1:1 3:0.83319067 4:0.98956086 5:0.99577089 6:0.99784595 \n4 4:0.10344019 5:0.34323945 6:0.63855969 \n4 1:0.19531482 3:0.034330388 4:0.25480402 5:0.54197045 6:0.78020579 \n4 1:0.48394064 3:0.11866359 4:0.58816959 5:0.86435738 6:0.96191842 \n4 1:0.47628079 3:0.11185039 4:0.56180003 5:0.83415721 6:0.93617329 \n4 1:0.46278632 3:0.10308547 4:0.52247575 5:0.78583924 6:0.89392193 \n4 1:0.7038079 3:0.2174879 4:0.84423613 5:0.9662906 6:0.98430594 \n4 1:0.69596686 3:0.20657211 4:0.81196884 5:0.94140702 6:0.96680805 \n4 1:0.68404358 3:0.19261438 4:0.76066415 5:0.89973293 6:0.93660362 \n4 1:0.84073022 2:0.34681232 3:0.22411304 4:0.88845644 5:0.94169671 6:0.96221395 \n-4 1:0.33900937 2:0.34681232 3:0.027607294 4:0.40659646 5:0.45456869 6:0.48256597 \n-4 1:0.44593129 2:0.34681232 3:0.041939301 4:0.45284872 5:0.5157613 6:0.55335821 \n-4 1:0.67301747 2:0.34681232 3:0.11526222 4:0.68549511 5:0.78556255 6:0.83507583 \n-4 1:0.62833533 2:0.34681232 3:0.092281981 4:0.61278125 5:0.70626575 6:0.75613977 \n-4 1:0.57196879 2:0.34681232 3:0.067548447 4:0.53383404 5:0.61287548 6:0.65468717 \n-0.3312466607741135 1:0.75125028 2:0.34681232 3:0.1457048 4:0.75791308 5:0.84155109 6:0.88132116 \n-4 1:0.71121936 2:0.34681232 3:0.12095689 4:0.68834617 5:0.77453583 6:0.81892861 \n-4 1:0.80269544 2:0.25207203 3:0.3681723 4:0.80658472 5:0.8702283 6:0.90583519 \n-4 1:0.86095387 2:0.25207203 3:0.52475418 4:0.85053413 5:0.90454501 6:0.93093678 \n-4 1:0.5008963 2:0.25207203 3:0.2005129 4:0.41516485 5:0.45282017 6:0.47396143 \n-4 1:0.56977992 2:0.25207203 3:0.21631076 4:0.45848604 5:0.51102137 6:0.53823055 \n-4 1:0.72779828 2:0.25207203 3:0.3051639 4:0.67537297 5:0.75767261 6:0.80327187 \n-4 1:0.68848569 2:0.25207203 3:0.27393051 4:0.60399854 5:0.68000038 6:0.72275152 \n-4 1:0.64121401 2:0.25207203 3:0.23994344 4:0.52538719 5:0.5891732 6:0.62164073 \n-4 1:0.76673633 2:0.25207203 3:0.33053889 4:0.73085549 5:0.80341439 6:0.84546456 \n-4 1:0.73041172 2:0.25207203 3:0.29691153 4:0.66166141 5:0.73408074 6:0.77757209 \n-4 1:0.68529047 2:0.25207203 3:0.26283557 4:0.58611788 5:0.65192525 6:0.69015011 \n4 1:0.86902267 2:0.48885268 3:0.5143645 4:0.8587242 5:0.91841685 6:0.94498293 \n4 1:0.89266106 2:0.48885268 3:0.55208861 4:0.89938377 5:0.94642982 6:0.96615102 \n-4 1:0.42554844 2:0.48885268 3:0.2554221 4:0.36916892 5:0.43100226 6:0.50888404 \n-4 1:0.52520274 2:0.48885268 3:0.27824915 4:0.42915458 5:0.50850476 6:0.58585271 \n-4 1:0.69357445 2:0.48885268 3:0.35289928 4:0.61359907 5:0.7217863 6:0.78790011 \n-4 1:0.64679648 2:0.48885268 3:0.31268451 4:0.5167094 5:0.61224976 6:0.68477529 \n4 1:0.80595874 2:0.48885268 3:0.44075432 4:0.7803455 5:0.86328719 6:0.90222545 \n-4 1:0.7715192 2:0.48885268 3:0.4012577 4:0.70792536 5:0.80063653 6:0.85083872 \n4 1:0.82199966 2:0.20629643 3:0.30562098 4:0.80541317 5:0.89285836 6:0.92907353 \n-4 1:0.84774006 2:0.20629643 3:0.36755712 4:0.8681203 5:0.93297792 6:0.95700049 \n4 1:0.26631905 2:0.20629643 3:0.076468978 4:0.29833807 5:0.37989948 6:0.4576277 \n-4 1:0.65439648 2:0.20629643 3:0.19487894 4:0.63045155 5:0.76931142 6:0.83706632 \n4 1:0.55295603 2:0.20629643 3:0.13877412 4:0.4724047 5:0.59295828 6:0.66834832 \n4 1:0.75448924 2:0.20629643 3:0.24707248 4:0.72284103 5:0.83178838 6:0.88053503 \n4 1:0.83852041 2:0.15600331 3:0.1625414 4:0.81948421 5:0.90185357 6:0.9347395 \n4 1:0.85805266 2:0.15600331 3:0.19693206 4:0.86294641 5:0.92990351 6:0.95498998 \n-4 1:0.43384835 2:0.15600331 3:0.030541611 4:0.37279112 5:0.4588284 6:0.52004828 \n-4 1:0.72588966 2:0.48885268 3:0.35394597 4:0.61189191 5:0.70897304 6:0.77099691 \n-4 1:0.65865915 2:0.20629643 3:0.1796405 4:0.56432133 5:0.68049028 6:0.74616621 \n-4 1:0.53095193 2:0.15600331 3:0.046271684 4:0.4328793 5:0.5309142 6:0.59282089 \n-4 1:0.71891465 2:0.15600331 3:0.11085278 4:0.68794624 5:0.80350923 6:0.85660483 \n-4 1:0.68635753 2:0.15600331 3:0.091457045 4:0.60849701 5:0.72282659 6:0.78137183 \n-4 1:0.64162333 2:0.15600331 3:0.068820233 4:0.51732819 5:0.62198733 6:0.67977328 \n4 1:0.78395225 2:0.15600331 3:0.13401869 4:0.75274384 5:0.8506531 6:0.89321405 \n-4 1:0.75276337 2:0.15600331 3:0.11289462 4:0.67598462 5:0.78117168 6:0.83259364 \n-4 1:0.71345342 2:0.15600331 3:0.089218917 4:0.58797907 5:0.69284768 6:0.74971699 \n4 1:0.93500967 2:0.08765484 3:0.72226864 4:0.93291747 5:0.960644 6:0.97304054 \n4 1:0.95150668 2:0.08765484 3:0.77391346 4:0.95596295 5:0.97544784 6:0.98405871 \n-4 1:0.48148634 2:0.08765484 3:0.36628046 4:0.45852823 5:0.56005228 6:0.65708595 \n-4 1:0.59853216 2:0.08765484 3:0.42071301 4:0.56376512 5:0.66454599 6:0.741236 \n-4 1:0.79297271 2:0.08765484 3:0.5597726 4:0.80653689 5:0.88996341 6:0.92691132 \n-4 1:0.76798941 2:0.08765484 3:0.52069978 4:0.74484555 5:0.83431246 6:0.87935204 \n-4 1:0.73225133 2:0.08765484 3:0.47011786 4:0.66069877 5:0.75226598 6:0.80539407 \n-4 1:0.87240592 2:0.08765484 3:0.62680052 4:0.88208508 5:0.93041565 6:0.9505376 \n-4 1:0.84834872 2:0.08765484 3:0.58154998 4:0.82429855 5:0.8858516 6:0.91563291 \n-4 1:0.84365382 2:0.93973481 3:0.36718425 4:0.81512123 5:0.88887359 6:0.92320992 \n-4 1:0.89242364 2:0.93973481 3:0.41336953 4:0.88038833 5:0.93688884 6:0.95992879 \n-4 1:0.31373571 2:0.93973481 3:0.18757116 4:0.34864297 5:0.3777168 6:0.38922611 \n-4 1:0.42490775 2:0.93973481 3:0.20295859 4:0.39290035 5:0.43632323 6:0.45871216 \n-4 1:0.66865444 2:0.93973481 3:0.28594627 4:0.63969879 5:0.73360583 6:0.78380069 \n-4 1:0.62642524 2:0.93973481 3:0.26141889 4:0.56602175 5:0.64775366 6:0.69263211 \n-4 1:0.57430455 2:0.93973481 3:0.23537634 4:0.48984694 5:0.55363885 6:0.5853905 \n-4 1:0.76178555 2:0.93973481 3:0.32205372 4:0.7176044 5:0.80237787 6:0.84588741 \n-4 1:0.72282163 2:0.93973481 3:0.29554025 4:0.64471949 5:0.72634443 6:0.77062686 \n-4 1:0.67693861 2:0.93973481 3:0.2669659 4:0.56720118 5:0.63868728 6:0.67673331 \n4 1:0.86023804 2:0.49739676 3:0.53966638 4:0.77392585 5:0.84784447 6:0.89031641 \n1.296591709971377 1:0.31779385 2:0.49739676 3:0.17094319 4:0.12195679 5:0.13277563 6:0.14165413 \n4 1:0.68317784 2:0.49739676 3:0.37192301 4:0.52750491 5:0.62426522 6:0.6929947 \n4 1:0.55611181 2:0.49739676 3:0.24752355 4:0.28326524 5:0.33261781 6:0.37104424 \n4 1:0.7772257 2:0.49739676 3:0.43832146 4:0.63397606 5:0.7240692 6:0.78367237 \n4 1:0.66186286 2:0.49739676 3:0.30599867 4:0.39201262 5:0.45927759 6:0.51239284 \n4 1:0.94601776 2:0.04579546 3:0.69472114 4:0.97790884 5:0.9891237 6:0.993277 \n4 1:0.98838404 2:0.04579546 3:0.90293444 4:0.99181622 5:0.99642641 6:0.9978864 \n4 1:0.30006056 2:0.04579546 3:0.31879 4:0.45852885 5:0.59717781 6:0.71487885 \n-4 1:0.44902891 2:0.04579546 3:0.35412414 4:0.55926446 5:0.70175505 6:0.79649177 \n-4 1:0.69856222 2:0.04579546 3:0.45989947 4:0.82115248 5:0.92520734 6:0.9594384 \n-4 1:0.67730161 2:0.04579546 3:0.44400319 4:0.77920819 5:0.88713866 6:0.92903178 \n-4 1:0.64419192 2:0.04579546 3:0.42297435 4:0.72390263 5:0.83364665 6:0.88344569 \n-4 1:0.80781899 2:0.04579546 3:0.52334234 4:0.88859427 5:0.94013924 6:0.95946903 \n-4 1:0.78080761 2:0.04579546 3:0.499439 4:0.84012074 5:0.90229375 6:0.92936693 \n4 1:0.97128596 2:0.014623935 3:0.90135809 4:0.99584619 5:0.9970631 6:0.99757649 \n4 1:0.99645027 2:0.014623935 3:1 4:1 5:1 6:1 \n-4 1:0.5326065 2:0.014623935 3:0.75468972 4:0.76017077 5:0.83753774 6:0.92265059 \n-4 1:0.62757004 2:0.014623935 3:0.77708563 4:0.84258654 5:0.91016348 6:0.95440359 \n-4 1:0.79306842 2:0.014623935 3:0.78900741 4:0.90386551 5:0.96905764 6:0.98466408 \n-4 1:0.77722867 2:0.014623935 3:0.78701408 4:0.89679281 5:0.96056131 6:0.977629 \n-4 1:0.75934622 2:0.014623935 3:0.78422805 4:0.88268036 5:0.94383829 6:0.96596858 \n-4 1:0.8878718 2:0.014623935 3:0.81445984 4:0.96615706 5:0.98858241 6:0.99176534 \n-4 1:0.88211614 2:0.014623935 3:0.81253935 4:0.95982371 5:0.98309178 6:0.9870796 \n4 1:0.83805466 2:0.22767235 3:0.31750162 4:0.85145925 5:0.9121085 6:0.93772147 \n4 1:0.86620985 2:0.22767235 3:0.35742938 4:0.89821492 5:0.94339974 6:0.96076173 \n4 1:0.39289606 2:0.22767235 3:0.12019254 4:0.3951559 5:0.44657802 6:0.46771549 \n4 1:0.48692411 2:0.22767235 3:0.13362033 4:0.43434224 5:0.49900609 6:0.53177669 \n4 1:0.69743918 2:0.22767235 3:0.2263303 4:0.68859985 5:0.78706365 6:0.83662428 \n4 1:0.65237548 2:0.22767235 3:0.19328493 4:0.60107975 5:0.69684945 6:0.74949279 \n4 1:0.59461718 2:0.22767235 3:0.15963705 4:0.51010642 5:0.59283393 6:0.63883591 \n4 1:0.77302727 2:0.22767235 3:0.26078021 4:0.76359704 5:0.8470807 6:0.8858359 \n4 1:0.72953038 2:0.22767235 3:0.22331233 4:0.67735915 5:0.77029889 6:0.81802539 \n4 1:0.87210923 2:0.16787772 3:0.69408521 4:0.91495146 5:0.94890261 6:0.96269344 \n-4 1:0.81595959 2:0.08765484 3:0.52947327 4:0.7501341 5:0.82294191 6:0.86264385 \n4 1:0.72562415 2:0.49739676 3:0.37130724 4:0.51472366 5:0.59961357 6:0.66258291 \n-4 1:0.87135693 2:0.014623935 3:0.80905852 4:0.94637428 5:0.97242826 6:0.97946694 \n-4 1:0.48910215 2:0.16787772 3:0.49792761 4:0.59161372 5:0.62979552 6:0.64254584 \n-4 1:0.5685964 2:0.16787772 3:0.5149767 4:0.63026581 5:0.67890679 6:0.69964851 \n-4 1:0.75935478 2:0.16787772 3:0.60695536 4:0.80906778 5:0.87125816 6:0.89810007 \n-4 1:0.71788601 2:0.16787772 3:0.57600091 4:0.75310216 5:0.81471966 6:0.84249923 \n-4 1:0.66516668 2:0.16787772 3:0.54473368 4:0.69254626 5:0.74796983 6:0.77177867 \n4 1:0.81880869 2:0.16787772 3:0.64309172 4:0.86078024 5:0.90892223 6:0.92908907 \n-4 1:0.78054558 2:0.16787772 3:0.60849279 4:0.80724494 5:0.86183239 6:0.88618408 \n4 1:0.95353512 2:0.055921852 3:0.61526026 4:0.94655706 5:0.97211195 6:0.98210701 \n4 1:0.98368527 2:0.055921852 3:0.7405327 4:0.96928567 5:0.9853799 6:0.99080378 \n4 1:0.11318821 2:0.055921852 3:0.1590151 4:0.30536689 5:0.48614515 6:0.64344462 \n4 1:0.30298819 2:0.055921852 3:0.19401703 4:0.41679982 5:0.61495039 6:0.74140301 \n4 1:0.60614412 2:0.055921852 3:0.31791569 4:0.72365433 5:0.88324129 6:0.93484545 \n4 1:0.58738733 2:0.055921852 3:0.29301498 4:0.67070014 5:0.83429953 6:0.89348041 \n4 1:0.79496816 2:0.055921852 3:0.42192974 4:0.86711004 5:0.94030868 6:0.96084539 \n4 1:0.77749763 2:0.055921852 3:0.38714172 4:0.81340799 5:0.90059649 6:0.93006702 \n4 1:0.75215882 2:0.055921852 3:0.34721658 4:0.73960747 5:0.84370247 6:0.88485372 \n4 1:0.89732805 2:0.58937038 3:0.58823535 4:0.80035053 5:0.86988422 6:0.90533033 \n-4 1:0.9228759 2:0.58937038 3:0.65797705 4:0.87169952 5:0.92200942 6:0.94454256 \n4 1:0.19504362 2:0.58937038 3:0.21585801 4:0.1754362 5:0.20844015 6:0.23846443 \n4 1:0.34425894 2:0.58937038 3:0.24672569 4:0.24188506 5:0.29544562 6:0.33843061 \n4 1:0.66407117 2:0.58937038 3:0.40045124 4:0.55415203 5:0.66628031 6:0.73418465 \n4 1:0.60780044 2:0.58937038 3:0.34931828 4:0.4519606 5:0.54893247 6:0.61355219 \n4 1:0.53476258 2:0.58937038 3:0.29851601 4:0.34826788 5:0.42168642 6:0.47203603 \n4 1:0.79195776 2:0.58937038 3:0.47493233 4:0.66775916 5:0.76196439 6:0.81489875 \n4 1:0.7415564 2:0.58937038 3:0.41507439 4:0.56413083 5:0.65815516 6:0.7166999 \n4 1:0.82021207 2:1 3:0.37381485 4:0.7891612 5:0.87031145 6:0.90944281 \n-3.795805084530972 1:0.85903236 2:1 3:0.43235998 4:0.86707094 5:0.92632217 6:0.95151451 \n-4 1:0.25243046 2:1 3:0.084027451 4:0.15537936 5:0.17410072 6:0.17212333 \n-4 1:0.35643487 2:1 3:0.10644455 4:0.21484368 5:0.25587544 6:0.27527817 \n-4 1:0.57605414 2:1 3:0.19031962 4:0.43030863 5:0.5277316 6:0.59069772 \n-4 1:0.49071444 2:1 3:0.14452095 4:0.31406915 5:0.38353445 6:0.42653517 \n4 1:0.73255545 2:1 3:0.28883701 4:0.65284485 5:0.75623242 6:0.81297442 \n0.4082706381617505 1:0.67015395 2:1 3:0.2367756 4:0.5367057 5:0.64063877 6:0.70451767 \n-4 1:0.84450653 2:0.083369236 3:0.57279245 4:0.85249389 5:0.91751611 6:0.94621989 \n-4 1:0.39559773 2:0.083369236 3:0.28184137 4:0.37025203 5:0.46733936 6:0.53517338 \n-4 1:0.70621493 2:0.083369236 3:0.42718441 4:0.69347659 5:0.81124449 6:0.87136343 \n-4 1:0.65615861 2:0.083369236 3:0.37833052 4:0.59301482 5:0.71772587 6:0.7905538 \n-4 1:0.58837863 2:0.083369236 3:0.33229353 4:0.48675881 5:0.60141743 6:0.67458413 \n-4 1:0.77687144 2:0.083369236 3:0.48094343 4:0.76665994 5:0.86191893 6:0.90760934 \n-1.966116876631112 1:0.72849768 2:0.083369236 3:0.42082971 4:0.66591147 5:0.77995959 6:0.84260661 \n-3.906831378063804 1:0.66320082 2:0.083369236 3:0.36350305 4:0.54888271 5:0.66506794 6:0.73685112 \n4 1:0.84500499 2:0.42532178 3:0.43562507 4:0.80721931 5:0.87934044 6:0.91434143 \n4 1:0.8874543 2:0.42532178 3:0.50912639 4:0.87959883 5:0.93223488 6:0.95450335 \n4 1:0.31032192 2:0.42532178 3:0.18976794 4:0.30662908 5:0.34637104 6:0.3661022 \n4 1:0.41026349 2:0.42532178 3:0.20589097 4:0.35241209 5:0.40358156 6:0.42577381 \n4 1:0.67552108 2:0.42532178 3:0.30879992 4:0.60375124 5:0.70097073 6:0.75507206 \n4 1:0.62772585 2:0.42532178 3:0.27349745 4:0.5196735 5:0.60339149 6:0.65103342 \n4 1:0.5741386 2:0.42532178 3:0.24033766 4:0.43855753 5:0.50243186 6:0.53322825 \n4 1:0.7629976 2:0.42532178 3:0.35347476 4:0.69239941 5:0.78245146 6:0.83117443 \n4 1:0.71746409 2:0.42532178 3:0.31296983 4:0.60525302 5:0.69243388 6:0.7432587 \n-4 1:0.73137955 2:0.16787772 3:0.57222383 4:0.74405775 5:0.79993424 6:0.82484891 \n4 1:0.67383121 2:0.58937038 3:0.35481019 4:0.45269287 5:0.53578336 6:0.59116487 \n4 1:0.5905971 2:1 3:0.18559792 4:0.41535212 5:0.50422336 6:0.56173557 \n4 1:0.66157018 2:0.42532178 3:0.27479904 4:0.51802649 5:0.59270541 6:0.63560969 \n-4 1:0.66827754 2:0.54342577 3:0.18169339 4:0.50290989 5:0.59875259 6:0.65332628 \n4 1:0.85027066 2:0.20820673 3:0.40997978 4:0.82462749 5:0.89794736 6:0.93142825 \n4 1:0.87892054 2:0.20820673 3:0.45891267 4:0.87823329 5:0.93535353 6:0.95883927 \n4 1:0.3986268 2:0.20820673 3:0.17753958 4:0.33495583 5:0.39777832 6:0.44399359 \n-4 1:0.48997993 2:0.20820673 3:0.20172681 4:0.39715881 5:0.47368229 6:0.52781628 \n4 1:0.7022939 2:0.20820673 3:0.31094767 4:0.6676259 5:0.77726116 6:0.83518027 \n-4 1:0.65773092 2:0.20820673 3:0.27420721 4:0.57889989 5:0.68485118 6:0.74837036 \n0.2951376518668717 1:0.60031736 2:0.20820673 3:0.23419121 4:0.48018865 5:0.57200972 6:0.63197473 \n4 1:0.77623676 2:0.20820673 3:0.3510016 4:0.74206651 5:0.83508543 6:0.88101902 \n4 1:0.73562396 2:0.20820673 3:0.31004997 4:0.6557112 5:0.75585014 6:0.81164989 \n-4 1:0.67923081 2:0.20820673 3:0.26679137 4:0.55816547 5:0.65579282 6:0.71593631 \n4 1:0.83968539 2:0.54342577 3:0.32439292 4:0.78747769 5:0.87303614 6:0.91271252 \n4 1:0.86656342 2:0.54342577 3:0.37898741 4:0.85252726 5:0.92049615 6:0.94848246 \n-4 1:0.42728303 2:0.54342577 3:0.10123262 4:0.31581962 5:0.38571265 6:0.42827036 \n-4 1:0.63194526 2:0.54342577 3:0.18169045 4:0.51611903 5:0.62179755 6:0.68216176 \n4 1:0.56954706 2:0.54342577 3:0.14271477 4:0.41491191 5:0.50173488 6:0.55220392 \n4 1:0.76753176 2:0.54342577 3:0.26295318 4:0.6905031 5:0.79291823 6:0.84469464 \n-4 1:0.72348649 2:0.54342577 3:0.22334634 4:0.60145902 5:0.70573225 6:0.76318544 \n4 1:0.83584492 2:0.047285912 3:0.53826775 4:0.933335 5:0.95948954 6:0.96870909 \n4 1:0.85530855 2:0.047285912 3:0.55323777 4:0.95113339 5:0.97249918 6:0.9795177 \n-4 1:0.53835734 2:0.047285912 3:0.41965074 4:0.71632669 5:0.73953043 6:0.73487553 \n-4 1:0.59175144 2:0.047285912 3:0.43113594 4:0.74141738 5:0.76929188 6:0.77018949 \n-4 1:0.75962366 2:0.047285912 3:0.49613729 4:0.87838146 5:0.91688438 6:0.93150362 \n-4 1:0.72043129 2:0.047285912 3:0.47217411 4:0.83138845 5:0.8704229 6:0.88419439 \n-4 1:0.67287449 2:0.047285912 3:0.44652268 4:0.77691812 5:0.81043483 6:0.8177009 \n-4 1:0.8023177 2:0.047285912 3:0.51559706 4:0.90512389 5:0.93743101 6:0.9492968 \n-4 1:0.76751376 2:0.047285912 3:0.49225957 4:0.86357299 5:0.89948127 6:0.91221155 \n-4 1:0.72124785 2:0.047285912 3:0.46606653 4:0.81323145 5:0.84847474 6:0.85892657 \n", 76 | "feature_dict": { 77 | "VMAF_integer_feature": [ 78 | "vif_scale0", 79 | "vif_scale1", 80 | "vif_scale2", 81 | "vif_scale3", 82 | "adm2", 83 | "motion2" 84 | ] 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /requirements.dev.txt: -------------------------------------------------------------------------------- 1 | pytest>=6.2.2 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pandas 2 | ffmpeg-progress-yield>=0.3.0 3 | tqdm 4 | packaging 5 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [mypy] 2 | namespace_packages = False 3 | mypy_path = ffmpeg_quality_metrics 4 | exclude = build 5 | 6 | [wheel] 7 | universal = 1 8 | 9 | [flake8] 10 | ignore = E226,E302,E41 11 | max-line-length = 160 12 | max-complexity = 10 13 | 14 | [pep8] 15 | ignore = E226,E302,E41,E402 16 | max-line-length = 160 17 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Always prefer setuptools over distutils 2 | import os 3 | 4 | from setuptools import setup 5 | 6 | here = os.path.abspath(os.path.dirname(__file__)) 7 | 8 | # Versioning 9 | with open( 10 | os.path.join(here, "ffmpeg_quality_metrics", "__init__.py"), encoding="utf-8" 11 | ) as version_file: 12 | # parse the string that looks like '__version__ = "3.1.2"' 13 | for line in version_file: 14 | if line.startswith("__version__"): 15 | version = line.split("=")[1].strip().strip('"') 16 | break 17 | 18 | # Get the long description from the README file 19 | with open(os.path.join(here, "README.md"), encoding="utf-8") as f: 20 | long_description = f.read() 21 | 22 | setup( 23 | name="ffmpeg_quality_metrics", 24 | version=version, 25 | description="Calculate video quality metrics with FFmpeg (SSIM, PSNR, VMAF)", 26 | long_description=long_description, 27 | long_description_content_type="text/markdown", 28 | url="https://github.com/slhck/ffmpeg-quality-metrics", 29 | author="Werner Robitza", 30 | author_email="werner.robitza@gmail.com", 31 | license="MIT", 32 | install_requires=["pandas", "tqdm", "ffmpeg-progress-yield>=0.3.0", "packaging"], 33 | classifiers=[ 34 | "Development Status :: 4 - Beta", 35 | "Intended Audience :: Developers", 36 | "Topic :: Multimedia :: Video", 37 | "License :: OSI Approved :: MIT License", 38 | "Programming Language :: Python :: 3", 39 | "Programming Language :: Python :: 3.9", 40 | "Programming Language :: Python :: 3.10", 41 | "Programming Language :: Python :: 3.11", 42 | "Programming Language :: Python :: 3.12", 43 | "Programming Language :: Python :: 3.13", 44 | ], 45 | python_requires=">=3.8", 46 | packages=["ffmpeg_quality_metrics"], 47 | include_package_data=True, 48 | package_data={"ffmpeg_quality_metrics": ["vmaf_models/*.json", "py.typed"]}, 49 | entry_points={ 50 | "console_scripts": [ 51 | "ffmpeg-quality-metrics=ffmpeg_quality_metrics.__main__:main", 52 | ], 53 | }, 54 | ) 55 | -------------------------------------------------------------------------------- /test/dist-854x480.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slhck/ffmpeg-quality-metrics/42aad7ad0e88f024777ea47c47c80dc0080bc104/test/dist-854x480.mkv -------------------------------------------------------------------------------- /test/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "vmaf": [ 3 | { 4 | "integer_adm2": 0.699075, 5 | "integer_adm_scale0": 0.708874, 6 | "integer_adm_scale1": 0.733523, 7 | "integer_adm_scale2": 0.718368, 8 | "integer_adm_scale3": 0.672973, 9 | "integer_motion2": 0.0, 10 | "integer_motion": 0.0, 11 | "integer_vif_scale0": 0.53943, 12 | "integer_vif_scale1": 0.717914, 13 | "integer_vif_scale2": 0.751785, 14 | "integer_vif_scale3": 0.77342, 15 | "vmaf": 14.051072, 16 | "n": 1 17 | }, 18 | { 19 | "integer_adm2": 0.698627, 20 | "integer_adm_scale0": 0.70731, 21 | "integer_adm_scale1": 0.732094, 22 | "integer_adm_scale2": 0.718446, 23 | "integer_adm_scale3": 0.672873, 24 | "integer_motion2": 0.359752, 25 | "integer_motion": 0.368929, 26 | "integer_vif_scale0": 0.540013, 27 | "integer_vif_scale1": 0.719462, 28 | "integer_vif_scale2": 0.753449, 29 | "integer_vif_scale3": 0.775636, 30 | "vmaf": 14.480823, 31 | "n": 2 32 | }, 33 | { 34 | "integer_adm2": 0.697117, 35 | "integer_adm_scale0": 0.706941, 36 | "integer_adm_scale1": 0.731659, 37 | "integer_adm_scale2": 0.716069, 38 | "integer_adm_scale3": 0.671182, 39 | "integer_motion2": 0.359752, 40 | "integer_motion": 0.359752, 41 | "integer_vif_scale0": 0.538908, 42 | "integer_vif_scale1": 0.718575, 43 | "integer_vif_scale2": 0.753169, 44 | "integer_vif_scale3": 0.775781, 45 | "vmaf": 14.241643, 46 | "n": 3 47 | } 48 | ], 49 | "global": { 50 | "vmaf": { 51 | "integer_adm2": { 52 | "average": 0.698, 53 | "median": 0.699, 54 | "stdev": 0.001, 55 | "min": 0.697, 56 | "max": 0.699 57 | }, 58 | "integer_adm_scale0": { 59 | "average": 0.708, 60 | "median": 0.707, 61 | "stdev": 0.001, 62 | "min": 0.707, 63 | "max": 0.709 64 | }, 65 | "integer_adm_scale1": { 66 | "average": 0.732, 67 | "median": 0.732, 68 | "stdev": 0.001, 69 | "min": 0.732, 70 | "max": 0.734 71 | }, 72 | "integer_adm_scale2": { 73 | "average": 0.718, 74 | "median": 0.718, 75 | "stdev": 0.001, 76 | "min": 0.716, 77 | "max": 0.718 78 | }, 79 | "integer_adm_scale3": { 80 | "average": 0.672, 81 | "median": 0.673, 82 | "stdev": 0.001, 83 | "min": 0.671, 84 | "max": 0.673 85 | }, 86 | "integer_motion2": { 87 | "average": 0.24, 88 | "median": 0.36, 89 | "stdev": 0.17, 90 | "min": 0.0, 91 | "max": 0.36 92 | }, 93 | "integer_motion": { 94 | "average": 0.243, 95 | "median": 0.36, 96 | "stdev": 0.172, 97 | "min": 0.0, 98 | "max": 0.369 99 | }, 100 | "integer_vif_scale0": { 101 | "average": 0.539, 102 | "median": 0.539, 103 | "stdev": 0.0, 104 | "min": 0.539, 105 | "max": 0.54 106 | }, 107 | "integer_vif_scale1": { 108 | "average": 0.719, 109 | "median": 0.719, 110 | "stdev": 0.001, 111 | "min": 0.718, 112 | "max": 0.719 113 | }, 114 | "integer_vif_scale2": { 115 | "average": 0.753, 116 | "median": 0.753, 117 | "stdev": 0.001, 118 | "min": 0.752, 119 | "max": 0.753 120 | }, 121 | "integer_vif_scale3": { 122 | "average": 0.775, 123 | "median": 0.776, 124 | "stdev": 0.001, 125 | "min": 0.773, 126 | "max": 0.776 127 | }, 128 | "vmaf": { 129 | "average": 14.258, 130 | "median": 14.242, 131 | "stdev": 0.176, 132 | "min": 14.051, 133 | "max": 14.481 134 | } 135 | } 136 | }, 137 | "input_file_dist": "test/dist-854x480.mkv", 138 | "input_file_ref": "test/ref-1280x720.mkv" 139 | } 140 | -------------------------------------------------------------------------------- /test/ref-1280x720.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slhck/ffmpeg-quality-metrics/42aad7ad0e88f024777ea47c47c80dc0080bc104/test/ref-1280x720.mkv -------------------------------------------------------------------------------- /test/response.json: -------------------------------------------------------------------------------- 1 | { 2 | "vmaf": [ 3 | { 4 | "integer_adm2": 0.699075, 5 | "integer_adm_scale0": 0.708874, 6 | "integer_adm_scale1": 0.733523, 7 | "integer_adm_scale2": 0.718368, 8 | "integer_adm_scale3": 0.672973, 9 | "integer_motion2": 0.0, 10 | "integer_motion": 0.0, 11 | "integer_vif_scale0": 0.53943, 12 | "integer_vif_scale1": 0.717914, 13 | "integer_vif_scale2": 0.751785, 14 | "integer_vif_scale3": 0.77342, 15 | "vmaf": 14.051072, 16 | "n": 1 17 | }, 18 | { 19 | "integer_adm2": 0.698627, 20 | "integer_adm_scale0": 0.70731, 21 | "integer_adm_scale1": 0.732094, 22 | "integer_adm_scale2": 0.718446, 23 | "integer_adm_scale3": 0.672873, 24 | "integer_motion2": 0.359752, 25 | "integer_motion": 0.368929, 26 | "integer_vif_scale0": 0.540013, 27 | "integer_vif_scale1": 0.719462, 28 | "integer_vif_scale2": 0.753449, 29 | "integer_vif_scale3": 0.775636, 30 | "vmaf": 14.480823, 31 | "n": 2 32 | }, 33 | { 34 | "integer_adm2": 0.697117, 35 | "integer_adm_scale0": 0.706941, 36 | "integer_adm_scale1": 0.731659, 37 | "integer_adm_scale2": 0.716069, 38 | "integer_adm_scale3": 0.671182, 39 | "integer_motion2": 0.359752, 40 | "integer_motion": 0.359752, 41 | "integer_vif_scale0": 0.538908, 42 | "integer_vif_scale1": 0.718575, 43 | "integer_vif_scale2": 0.753169, 44 | "integer_vif_scale3": 0.775781, 45 | "vmaf": 14.241643, 46 | "n": 3 47 | } 48 | ], 49 | "psnr": [ 50 | { 51 | "n": 1, 52 | "mse_avg": 536.66, 53 | "mse_y": 900.29, 54 | "mse_u": 234.46, 55 | "mse_v": 475.24, 56 | "psnr_avg": 20.83, 57 | "psnr_y": 18.59, 58 | "psnr_u": 24.43, 59 | "psnr_v": 21.36 60 | }, 61 | { 62 | "n": 2, 63 | "mse_avg": 535.24, 64 | "mse_y": 897.04, 65 | "mse_u": 239.35, 66 | "mse_v": 469.35, 67 | "psnr_avg": 20.85, 68 | "psnr_y": 18.6, 69 | "psnr_u": 24.34, 70 | "psnr_v": 21.42 71 | }, 72 | { 73 | "n": 3, 74 | "mse_avg": 534.98, 75 | "mse_y": 894.97, 76 | "mse_u": 245.74, 77 | "mse_v": 464.21, 78 | "psnr_avg": 20.85, 79 | "psnr_y": 18.61, 80 | "psnr_u": 24.23, 81 | "psnr_v": 21.46 82 | } 83 | ], 84 | "ssim": [ 85 | { 86 | "n": 1, 87 | "ssim_y": 0.934, 88 | "ssim_u": 0.96, 89 | "ssim_v": 0.942, 90 | "ssim_avg": 0.945 91 | }, 92 | { 93 | "n": 2, 94 | "ssim_y": 0.934, 95 | "ssim_u": 0.96, 96 | "ssim_v": 0.943, 97 | "ssim_avg": 0.946 98 | }, 99 | { 100 | "n": 3, 101 | "ssim_y": 0.934, 102 | "ssim_u": 0.959, 103 | "ssim_v": 0.943, 104 | "ssim_avg": 0.945 105 | } 106 | ], 107 | "vif": [ 108 | { 109 | "n": 0, 110 | "scale_0": 0.262, 111 | "scale_1": 0.557, 112 | "scale_2": 0.624, 113 | "scale_3": 0.679 114 | }, 115 | { 116 | "n": 1, 117 | "scale_0": 0.263, 118 | "scale_1": 0.56, 119 | "scale_2": 0.626, 120 | "scale_3": 0.682 121 | }, 122 | { 123 | "n": 2, 124 | "scale_0": 0.262, 125 | "scale_1": 0.559, 126 | "scale_2": 0.626, 127 | "scale_3": 0.682 128 | } 129 | ], 130 | "global": { 131 | "vmaf": { 132 | "integer_adm2": { 133 | "average": 0.698, 134 | "median": 0.699, 135 | "stdev": 0.001, 136 | "min": 0.697, 137 | "max": 0.699 138 | }, 139 | "integer_adm_scale0": { 140 | "average": 0.708, 141 | "median": 0.707, 142 | "stdev": 0.001, 143 | "min": 0.707, 144 | "max": 0.709 145 | }, 146 | "integer_adm_scale1": { 147 | "average": 0.732, 148 | "median": 0.732, 149 | "stdev": 0.001, 150 | "min": 0.732, 151 | "max": 0.734 152 | }, 153 | "integer_adm_scale2": { 154 | "average": 0.718, 155 | "median": 0.718, 156 | "stdev": 0.001, 157 | "min": 0.716, 158 | "max": 0.718 159 | }, 160 | "integer_adm_scale3": { 161 | "average": 0.672, 162 | "median": 0.673, 163 | "stdev": 0.001, 164 | "min": 0.671, 165 | "max": 0.673 166 | }, 167 | "integer_motion2": { 168 | "average": 0.24, 169 | "median": 0.36, 170 | "stdev": 0.17, 171 | "min": 0.0, 172 | "max": 0.36 173 | }, 174 | "integer_motion": { 175 | "average": 0.243, 176 | "median": 0.36, 177 | "stdev": 0.172, 178 | "min": 0.0, 179 | "max": 0.369 180 | }, 181 | "integer_vif_scale0": { 182 | "average": 0.539, 183 | "median": 0.539, 184 | "stdev": 0.0, 185 | "min": 0.539, 186 | "max": 0.54 187 | }, 188 | "integer_vif_scale1": { 189 | "average": 0.719, 190 | "median": 0.719, 191 | "stdev": 0.001, 192 | "min": 0.718, 193 | "max": 0.719 194 | }, 195 | "integer_vif_scale2": { 196 | "average": 0.753, 197 | "median": 0.753, 198 | "stdev": 0.001, 199 | "min": 0.752, 200 | "max": 0.753 201 | }, 202 | "integer_vif_scale3": { 203 | "average": 0.775, 204 | "median": 0.776, 205 | "stdev": 0.001, 206 | "min": 0.773, 207 | "max": 0.776 208 | }, 209 | "vmaf": { 210 | "average": 14.258, 211 | "median": 14.242, 212 | "stdev": 0.176, 213 | "min": 14.051, 214 | "max": 14.481 215 | } 216 | }, 217 | "psnr": { 218 | "mse_avg": { 219 | "average": 535.627, 220 | "median": 535.24, 221 | "stdev": 0.738, 222 | "min": 534.98, 223 | "max": 536.66 224 | }, 225 | "mse_y": { 226 | "average": 897.433, 227 | "median": 897.04, 228 | "stdev": 2.19, 229 | "min": 894.97, 230 | "max": 900.29 231 | }, 232 | "mse_u": { 233 | "average": 239.85, 234 | "median": 239.35, 235 | "stdev": 4.619, 236 | "min": 234.46, 237 | "max": 245.74 238 | }, 239 | "mse_v": { 240 | "average": 469.6, 241 | "median": 469.35, 242 | "stdev": 4.506, 243 | "min": 464.21, 244 | "max": 475.24 245 | }, 246 | "psnr_avg": { 247 | "average": 20.843, 248 | "median": 20.85, 249 | "stdev": 0.009, 250 | "min": 20.83, 251 | "max": 20.85 252 | }, 253 | "psnr_y": { 254 | "average": 18.6, 255 | "median": 18.6, 256 | "stdev": 0.008, 257 | "min": 18.59, 258 | "max": 18.61 259 | }, 260 | "psnr_u": { 261 | "average": 24.333, 262 | "median": 24.34, 263 | "stdev": 0.082, 264 | "min": 24.23, 265 | "max": 24.43 266 | }, 267 | "psnr_v": { 268 | "average": 21.413, 269 | "median": 21.42, 270 | "stdev": 0.041, 271 | "min": 21.36, 272 | "max": 21.46 273 | } 274 | }, 275 | "ssim": { 276 | "ssim_y": { 277 | "average": 0.934, 278 | "median": 0.934, 279 | "stdev": 0.0, 280 | "min": 0.934, 281 | "max": 0.934 282 | }, 283 | "ssim_u": { 284 | "average": 0.96, 285 | "median": 0.96, 286 | "stdev": 0.0, 287 | "min": 0.959, 288 | "max": 0.96 289 | }, 290 | "ssim_v": { 291 | "average": 0.943, 292 | "median": 0.943, 293 | "stdev": 0.0, 294 | "min": 0.942, 295 | "max": 0.943 296 | }, 297 | "ssim_avg": { 298 | "average": 0.945, 299 | "median": 0.945, 300 | "stdev": 0.0, 301 | "min": 0.945, 302 | "max": 0.946 303 | } 304 | }, 305 | "vif": { 306 | "scale_0": { 307 | "average": 0.262, 308 | "median": 0.262, 309 | "stdev": 0.0, 310 | "min": 0.262, 311 | "max": 0.263 312 | }, 313 | "scale_1": { 314 | "average": 0.559, 315 | "median": 0.559, 316 | "stdev": 0.001, 317 | "min": 0.557, 318 | "max": 0.56 319 | }, 320 | "scale_2": { 321 | "average": 0.625, 322 | "median": 0.626, 323 | "stdev": 0.001, 324 | "min": 0.624, 325 | "max": 0.626 326 | }, 327 | "scale_3": { 328 | "average": 0.681, 329 | "median": 0.682, 330 | "stdev": 0.001, 331 | "min": 0.679, 332 | "max": 0.682 333 | } 334 | } 335 | }, 336 | "input_file_dist": "test/dist-854x480.mkv", 337 | "input_file_ref": "test/ref-1280x720.mkv" 338 | } -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | import os 5 | import sys 6 | from typing import cast 7 | 8 | sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + "/../")) 9 | 10 | from ffmpeg_quality_metrics import FfmpegQualityMetrics as ffqm # noqa E402 11 | from ffmpeg_quality_metrics import VmafOptions # noqa E402 12 | 13 | DIST = os.path.join(os.path.dirname(__file__), "dist-854x480.mkv") 14 | REF = os.path.join(os.path.dirname(__file__), "ref-1280x720.mkv") 15 | 16 | with open(os.path.join(os.path.dirname(__file__), "response.json"), "r") as f: 17 | EXPECTED = json.load(f) 18 | GLOBAL = EXPECTED["global"] 19 | 20 | THRESHOLD = ( 21 | 0.1 # we need some threshold here because exact reproductions are not guaranteed 22 | ) 23 | 24 | 25 | class TestMetrics: 26 | def test_all(self): 27 | run_ret_1 = ffqm(REF, DIST).calculate(metrics=["ssim"]) 28 | run_ret_2 = ffqm(REF, DIST).calculate(metrics=["ssim", "psnr"]) 29 | run_ret_3 = ffqm(REF, DIST).calculate(metrics=["ssim", "psnr", "vmaf"]) 30 | 31 | assert len(run_ret_1) == 1 32 | assert len(run_ret_2) == 2 33 | assert len(run_ret_3) == 3 34 | 35 | for data in [run_ret_1, run_ret_2, run_ret_3]: 36 | for key, run_ret in data.items(): 37 | self._test_frame_by_frame(EXPECTED[key], run_ret) 38 | 39 | def test_ssim(self): 40 | run_ret = ffqm(REF, DIST).calculate(["ssim"])["ssim"] 41 | self._test_frame_by_frame(EXPECTED["ssim"], run_ret) 42 | 43 | def test_psnr(self): 44 | run_ret = ffqm(REF, DIST).calculate(["psnr"])["psnr"] 45 | self._test_frame_by_frame(EXPECTED["psnr"], run_ret) 46 | 47 | def test_vmaf(self): 48 | vmaf_opts = {"model_path": "vmaf_v0.6.1.json"} 49 | run_ret = ffqm(REF, DIST).calculate( 50 | ["vmaf"], vmaf_options=cast(VmafOptions, vmaf_opts) 51 | )["vmaf"] 52 | self._test_frame_by_frame(EXPECTED["vmaf"], run_ret) 53 | 54 | def test_vmaf_features(self): 55 | vmaf_opts = { 56 | "features": [ 57 | "cambi", 58 | "ciede", 59 | "vif", 60 | "adm", 61 | "motion", 62 | "float_ssim", 63 | "float_ms_ssim", 64 | ] 65 | } 66 | run_ret = ffqm(REF, DIST).calculate( 67 | ["vmaf"], vmaf_options=cast(VmafOptions, vmaf_opts) 68 | )["vmaf"] 69 | 70 | assert list(run_ret[0].keys()) == [ 71 | "integer_adm2", 72 | "integer_adm_scale0", 73 | "integer_adm_scale1", 74 | "integer_adm_scale2", 75 | "integer_adm_scale3", 76 | "integer_motion2", 77 | "integer_motion", 78 | "integer_vif_scale0", 79 | "integer_vif_scale1", 80 | "integer_vif_scale2", 81 | "integer_vif_scale3", 82 | "cambi", 83 | "ciede2000", 84 | "float_ssim", 85 | "float_ms_ssim", 86 | "vmaf", 87 | "n", 88 | ] 89 | 90 | def test_vmaf_feature_options(self): 91 | vmaf_opts = { 92 | "features": [ 93 | "cambi:full_ref=true", 94 | ] 95 | } 96 | run_ret = ffqm(REF, DIST).calculate( 97 | ["vmaf"], vmaf_options=cast(VmafOptions, vmaf_opts) 98 | )["vmaf"] 99 | 100 | assert list(run_ret[0].keys()) == [ 101 | "integer_adm2", 102 | "integer_adm_scale0", 103 | "integer_adm_scale1", 104 | "integer_adm_scale2", 105 | "integer_adm_scale3", 106 | "integer_motion2", 107 | "integer_motion", 108 | "integer_vif_scale0", 109 | "integer_vif_scale1", 110 | "integer_vif_scale2", 111 | "integer_vif_scale3", 112 | "cambi", 113 | "cambi_source", 114 | "cambi_full_reference", 115 | "vmaf", 116 | "n", 117 | ] 118 | 119 | def test_vif(self): 120 | run_ret = ffqm(REF, DIST).calculate(["vif"])["vif"] 121 | self._test_frame_by_frame(EXPECTED["vif"], run_ret) 122 | 123 | def _test_frame_by_frame(self, expected, run_ret): 124 | for expected_frame, actual_frame in zip(expected, run_ret): 125 | for key in expected_frame.keys(): 126 | assert abs(expected_frame[key] - actual_frame[key]) < THRESHOLD 127 | 128 | def test_global(self): 129 | f = ffqm(REF, DIST) 130 | f.calculate(metrics=["ssim", "psnr", "vmaf", "vif"]) 131 | run_ret = f.get_global_stats() 132 | for key in GLOBAL.keys(): 133 | for subkey in GLOBAL[key].keys(): 134 | print(key, subkey) 135 | for metric in GLOBAL[key][subkey].keys(): 136 | assert ( 137 | abs(GLOBAL[key][subkey][metric] - run_ret[key][subkey][metric]) 138 | < THRESHOLD 139 | ) 140 | --------------------------------------------------------------------------------