2 Commits

Author SHA1 Message Date
Michael Fabian 'Xaymar' Dirks 9431689ac8 1.1.0: Percentiles for JSON logs
- Adds 50th, 75th, 90th, 95th, 99th and 99.9th percentile to the calculations in the JSON log output.
- Fixes being forced to calculate the vmaf_v0.6.1 model.
- Flips the order for scaling reference files.
2022-12-27 16:09:48 +01:00
Michael Fabian 'Xaymar' Dirks 611157ec67 Don't always print arguments to output 2022-12-27 16:08:30 +01:00
4 changed files with 96 additions and 29 deletions
+19
View File
@@ -0,0 +1,19 @@
# js-vmaf: Simple, but effective VMAF comparison tool
This is a simple wrapper around FFmpeg and VMAF to handle comparison of files.
## Installing
```
npm install
npm run build
```
## Usage
```
node . --help
```
## Examples
### Compare all files in a directory
```
node . --ffmpeg ./ffmpeg --ffprobe ./ffprobe -r /mnt/usb0/reference.mp4 /mnt/usb1/
```
+14 -3
View File
@@ -1,15 +1,16 @@
{
"name": "js-vmaf",
"version": "0.0.0",
"version": "1.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "js-vmaf",
"version": "0.0.0",
"version": "1.0.1",
"license": "BSD 3-Clause \"New\" or \"Revised\" License",
"dependencies": {
"argparse": "^2.0.1"
"argparse": "^2.0.1",
"percentile": "^1.6.0"
},
"devDependencies": {
"@types/argparse": "^2.0.10",
@@ -1266,6 +1267,11 @@
"node": ">=8"
}
},
"node_modules/percentile": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/percentile/-/percentile-1.6.0.tgz",
"integrity": "sha512-8vSyjdzwxGDHHwH+cSGch3A9Uj2On3UpgOWxWXMKwUvoAbnujx6DaqmV1duWXNiH/oEWpyVd6nSQccix6DM3Ng=="
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -2499,6 +2505,11 @@
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
},
"percentile": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/percentile/-/percentile-1.6.0.tgz",
"integrity": "sha512-8vSyjdzwxGDHHwH+cSGch3A9Uj2On3UpgOWxWXMKwUvoAbnujx6DaqmV1duWXNiH/oEWpyVd6nSQccix6DM3Ng=="
},
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "js-vmaf",
"version": "1.0.0",
"version": "1.1.0",
"description": "A simple tool to quickly and correctly compare a reference file with a distorted file using VMAF.",
"main": "generated/index.js",
"scripts": {
@@ -21,6 +21,7 @@
"typescript": "^4.9.4"
},
"dependencies": {
"argparse": "^2.0.1"
"argparse": "^2.0.1",
"percentile": "^1.6.0"
}
}
+60 -24
View File
@@ -8,6 +8,7 @@ import CHILD_PROCESS from "node:child_process";
import PROCESS from "node:process";
import PATH from "node:path";
import FS from "node:fs";
import PERCENTILE from "percentile";
function valueOrDefault(value : any, fallback : any) : any {
if (value === undefined) {
@@ -119,7 +120,7 @@ class App {
this._argparse.add_argument("-m", "--model", {
type: "str",
action: "append",
default: [ "version=vmaf_v0.6.1" ],
default: [],
help: "Enable (and configure) a model"
});
@@ -224,9 +225,15 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AN
}
async compare(path : string) {
if (!this._args.quiet) console.log(`'${path}' Comparing...`);
if (!this._args.quiet) console.log(`Comparing '${path}'...`);
const cmp = this.FFprobe([path]);
let cmp;
try {
cmp = this.FFprobe([path]);
} catch {
console.error("Not a video file.");
return;
}
if (cmp.video.length == 0) {
console.error(`'${path}' Missing video track.`);
return;
@@ -250,6 +257,25 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AN
chain.push(`fps=${valueOrDefault(this._args.fps, fref.video[0].r_framerate)}`);
}
// Scale
if (this._args.width
|| this._args.height) {
chain.push(
`scale=w=${valueOrDefault(this._args.width, -1)}`+
`:h=${valueOrDefault(this._args.height, -1)}`+
":flags=bicubic+full_chroma_inp+full_chroma_int"+
":force_original_aspect_ratio=0"
);
} else if ((this._ref.video[0].width !== fref.video[0].width)
|| (this._ref.video[0].height !== fref.video[0].height)) {
chain.push(
`scale=w=${valueOrDefault(fref.video[0].width, this._ref.video[0].width)}`+
`:h=${valueOrDefault(fref.video[0].height, this._ref.video[0].height)}`+
":flags=bicubic+full_chroma_inp+full_chroma_int"+
":force_original_aspect_ratio=0"
);
}
// Convert format and color.
if (this._args.color_space
|| this._args.color_primaries
@@ -272,25 +298,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AN
`:format=${valueOrDefault(this._args.format, valueOrDefault(fref.video[0].pix_fmt, "yuv420p"))}`);
}
// Scale
if (this._args.width
|| this._args.height) {
chain.push(
`scale=w=${valueOrDefault(this._args.width, -1)}`+
`:h=${valueOrDefault(this._args.height, -1)}`+
":flags=bicubic+full_chroma_inp+full_chroma_int"+
":force_original_aspect_ratio=0"
);
} else if ((this._ref.video[0].width !== fref.video[0].width)
|| (this._ref.video[0].height !== fref.video[0].height)) {
chain.push(
`scale=w=${valueOrDefault(fref.video[0].width, this._ref.video[0].width)}`+
`:h=${valueOrDefault(fref.video[0].height, this._ref.video[0].height)}`+
":flags=bicubic+full_chroma_inp+full_chroma_int"+
":force_original_aspect_ratio=0"
);
}
filters.push(`[0:v:0]${chain.join(",")}[ref]`);
}
{ // Adjust distorted to the expected format.
@@ -365,7 +372,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AN
const proc = this.FFmpeg([
"-hide_banner",
"-v", "info",
"-v", "quiet",
"-stats",
"-hwaccel", "auto",
@@ -421,6 +428,35 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AN
});
});
}
if (PATH.extname(log) === ".json") {
// Post-process the JSON file so we get more useful metrics.
const data = JSON.parse(FS.readFileSync(log).toString("utf-8"));
const prc = [50, 75, 90, 99, 99.9];
const frames : any = {};
for (const metric in data.pooled_metrics) {
frames[metric] = [];
}
for (const frame of data.frames) {
for (const metric in frame.metrics) {
frames[metric].push(frame.metrics[metric]);
}
}
for (const metric in data.pooled_metrics) {
for (const p in prc) {
data.pooled_metrics[metric][`${prc[p]}th %ile`] = PERCENTILE(
100 - prc[p],
frames[metric]
);
}
}
FS.writeFileSync(log, JSON.stringify(data, undefined, "\t"));
}
}
public async run() : Promise<number> {
@@ -428,7 +464,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AN
this.license();
this._args = this._argparse.parse_args();
if (!this._args.quiet) console.dir(this._args);
//if (!this._args.quiet) console.dir(this._args);
// Probe information (color, fps, ...) about the reference file.
try {