@vpalmisano/webrtcperf 4.1.1 → 4.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/app.min.js +1 -1
- package/build/src/app.js +63 -61
- package/build/src/app.js.map +1 -1
- package/build/src/config.d.ts +1 -0
- package/build/src/config.js +8 -1
- package/build/src/config.js.map +1 -1
- package/build/src/session.js +9 -0
- package/build/src/session.js.map +1 -1
- package/build/src/vmaf.d.ts +5 -3
- package/build/src/vmaf.js +23 -14
- package/build/src/vmaf.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/app.ts +69 -61
- package/src/config.ts +8 -1
- package/src/session.ts +12 -0
- package/src/vmaf.ts +25 -14
package/build/src/vmaf.d.ts
CHANGED
|
@@ -29,8 +29,9 @@ export declare function prepareVideo({ vmafPrepareVideo, vmafVideoCrop, videoWid
|
|
|
29
29
|
* @param fpath The input video file path.
|
|
30
30
|
* @param crop The crop filter.
|
|
31
31
|
* @param keepSourceFile If the source file should be kept.
|
|
32
|
+
* @param skipDuplicated If the duplicated recognized frames should be skipped.
|
|
32
33
|
*/
|
|
33
|
-
export declare function convertToIvf(fpath: string, crop?: string, keepSourceFile?: boolean): Promise<void>;
|
|
34
|
+
export declare function convertToIvf(fpath: string, crop?: string, keepSourceFile?: boolean, skipDuplicated?: boolean): Promise<void>;
|
|
34
35
|
/**
|
|
35
36
|
* It recognizes the frames of a video file using OCR.
|
|
36
37
|
* @param fpath The input video file path.
|
|
@@ -45,11 +46,11 @@ export declare function recognizeFrames(fpath: string, recover?: boolean, debug?
|
|
|
45
46
|
frames: Map<number, number>;
|
|
46
47
|
participantDisplayName: string;
|
|
47
48
|
}>;
|
|
48
|
-
export declare function fixIvfFrames(filePath: string, keepSourceFile?: boolean): Promise<{
|
|
49
|
+
export declare function fixIvfFrames(filePath: string, keepSourceFile?: boolean, skipDuplicated?: boolean): Promise<{
|
|
49
50
|
participantDisplayName: string;
|
|
50
51
|
outFilePath: string;
|
|
51
52
|
}>;
|
|
52
|
-
export declare function fixIvfFiles(directory: string, keepSourceFiles?: boolean): Promise<{
|
|
53
|
+
export declare function fixIvfFiles(directory: string, keepSourceFiles?: boolean, skipDuplicated?: boolean): Promise<{
|
|
53
54
|
reference: Map<string, string>;
|
|
54
55
|
degraded: Map<string, string[]>;
|
|
55
56
|
}>;
|
|
@@ -78,6 +79,7 @@ interface VmafConfig {
|
|
|
78
79
|
vmafKeepIntermediateFiles: boolean;
|
|
79
80
|
vmafKeepSourceFiles: boolean;
|
|
80
81
|
vmafCrop?: string;
|
|
82
|
+
vmafSkipDuplicated?: boolean;
|
|
81
83
|
}
|
|
82
84
|
export declare function calculateVmafScore(config: VmafConfig): Promise<VmafScore[]>;
|
|
83
85
|
export {};
|
package/build/src/vmaf.js
CHANGED
|
@@ -57,7 +57,7 @@ async function prepareVideo({ vmafPrepareVideo, vmafVideoCrop, videoWidth, video
|
|
|
57
57
|
const filter = vmafVideoCrop ? cropFilter(json5_1.default.parse(vmafVideoCrop), 0, ',') : '';
|
|
58
58
|
await (0, utils_1.runShellCommand)(`ffmpeg -hide_banner -loglevel warning -threads ${Math.min(cpus, 16)} \
|
|
59
59
|
${videoDuration ? `-t ${videoDuration}` : ''} \
|
|
60
|
-
-i ${fpath} \
|
|
60
|
+
-stream_loop -1 -i ${fpath} \
|
|
61
61
|
-filter_complex "[0:v]scale=w=${videoWidth || width}:h=${videoHeight || height},fps=${videoFramerate || frameRate},${filter}\
|
|
62
62
|
drawbox=x=0:y=0:w=iw:h=${textHeight}:color=black:t=fill,\
|
|
63
63
|
drawtext=fontfile=/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf:text='${id || 0}-%{eif\\:t*1000\\:u}':fontcolor=white:fontsize=${fontsize}:x=(w-text_w)/2:y=(${textHeight}-text_h)/2[out]" \
|
|
@@ -72,8 +72,9 @@ drawtext=fontfile=/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf:text='${id
|
|
|
72
72
|
* @param fpath The input video file path.
|
|
73
73
|
* @param crop The crop filter.
|
|
74
74
|
* @param keepSourceFile If the source file should be kept.
|
|
75
|
+
* @param skipDuplicated If the duplicated recognized frames should be skipped.
|
|
75
76
|
*/
|
|
76
|
-
async function convertToIvf(fpath, crop, keepSourceFile = true) {
|
|
77
|
+
async function convertToIvf(fpath, crop, keepSourceFile = true, skipDuplicated = false) {
|
|
77
78
|
const { width, height, frameRate } = await parseVideo(fpath);
|
|
78
79
|
const outputPath = fpath.replace(/\.[^.]+$/, '.ivf.raw');
|
|
79
80
|
log.debug(`convertToIvf ${fpath} ${width}x${height}@${frameRate} -> ${outputPath} crop:`, crop);
|
|
@@ -82,7 +83,10 @@ async function convertToIvf(fpath, crop, keepSourceFile = true) {
|
|
|
82
83
|
-c:v vp8 -quality best -cpu-used 0 -crf 1 -b:v 20M -qmin 1 -qmax 10 \
|
|
83
84
|
-g 1 -threads ${Math.min(cpus, 16)} ${filter} -an \
|
|
84
85
|
-f ivf ${outputPath}`, true);
|
|
85
|
-
|
|
86
|
+
if (!keepSourceFile) {
|
|
87
|
+
await fs_1.default.promises.unlink(fpath);
|
|
88
|
+
}
|
|
89
|
+
await fixIvfFrames(outputPath, false, skipDuplicated);
|
|
86
90
|
}
|
|
87
91
|
/**
|
|
88
92
|
* It recognizes the frames of a video file using OCR.
|
|
@@ -186,7 +190,7 @@ async function parseIvf(fpath, runRecognizer = false) {
|
|
|
186
190
|
log.warn(`IVF file ${fname}: pts ${pts} <= prev ${ptsIndex[ptsIndex.length - 1]}`)
|
|
187
191
|
} */
|
|
188
192
|
if (frames.has(pts)) {
|
|
189
|
-
|
|
193
|
+
log.debug(`IVF file ${fname}: pts ${pts} already present, skipping`);
|
|
190
194
|
skipped++;
|
|
191
195
|
}
|
|
192
196
|
else {
|
|
@@ -221,8 +225,9 @@ ts: ${firstTimestamp.toFixed(2)}-${lastTimestamp.toFixed(2)} (${(lastTimestamp -
|
|
|
221
225
|
participantDisplayName,
|
|
222
226
|
};
|
|
223
227
|
}
|
|
224
|
-
async function fixIvfFrames(filePath, keepSourceFile = true) {
|
|
228
|
+
async function fixIvfFrames(filePath, keepSourceFile = true, skipDuplicated = false) {
|
|
225
229
|
const fname = path_1.default.basename(filePath);
|
|
230
|
+
log.debug(`fixIvfFrames ${fname} keepSourceFile=${keepSourceFile} skipDuplicated=${skipDuplicated}`);
|
|
226
231
|
const dirPath = path_1.default.dirname(filePath);
|
|
227
232
|
if (!fname.endsWith('.ivf.raw')) {
|
|
228
233
|
throw new Error(`fixIvfFrames ${fname}: invalid file extension, expected ".ivf.raw"`);
|
|
@@ -265,12 +270,15 @@ async function fixIvfFrames(filePath, keepSourceFile = true) {
|
|
|
265
270
|
if (nextFrame?.recognizedPts && (nextFrame?.recognizedPts || 0) < frame.recognizedPts) {
|
|
266
271
|
continue;
|
|
267
272
|
}
|
|
268
|
-
//
|
|
273
|
+
// Duplicated recognized frame.
|
|
269
274
|
if (prevFrame?.recognizedPts && frame.recognizedPts === prevFrame.recognizedPts) {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
275
|
+
log.debug(`${fname}: duplicate recognized frame pts=${pts}:${frame.recognizedPts} prev=${prevFrame.pts}:${prevFrame.recognizedPts} next=${nextFrame?.pts}:${nextFrame?.recognizedPts} (${skipDuplicated ? 'skipped' : 'fixed'})`);
|
|
276
|
+
if (skipDuplicated) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
frame.recognizedPts += frame.pts - prevFrame.pts;
|
|
281
|
+
}
|
|
274
282
|
}
|
|
275
283
|
const frameView = new DataView(new ArrayBuffer(frame.size));
|
|
276
284
|
await fd.read(frameView, 0, frame.size, frame.position);
|
|
@@ -290,7 +298,8 @@ async function fixIvfFrames(filePath, keepSourceFile = true) {
|
|
|
290
298
|
}
|
|
291
299
|
return { participantDisplayName, outFilePath };
|
|
292
300
|
}
|
|
293
|
-
async function fixIvfFiles(directory, keepSourceFiles = true) {
|
|
301
|
+
async function fixIvfFiles(directory, keepSourceFiles = true, skipDuplicated = false) {
|
|
302
|
+
log.debug(`fixIvfFiles ${directory} keepSourceFiles=${keepSourceFiles} skipDuplicated=${skipDuplicated}`);
|
|
294
303
|
const reference = new Map();
|
|
295
304
|
const degraded = new Map();
|
|
296
305
|
const addFile = (participantDisplayName, outFilePath) => {
|
|
@@ -322,7 +331,7 @@ async function fixIvfFiles(directory, keepSourceFiles = true) {
|
|
|
322
331
|
log.debug(`processing ${rawFiles.length} raw ivf files`);
|
|
323
332
|
const results = await (0, utils_1.chunkedPromiseAll)(rawFiles, async (filePath) => {
|
|
324
333
|
try {
|
|
325
|
-
const { participantDisplayName, outFilePath } = await fixIvfFrames(filePath, keepSourceFiles);
|
|
334
|
+
const { participantDisplayName, outFilePath } = await fixIvfFrames(filePath, keepSourceFiles, skipDuplicated);
|
|
326
335
|
return { participantDisplayName, outFilePath };
|
|
327
336
|
}
|
|
328
337
|
catch (err) {
|
|
@@ -546,12 +555,12 @@ const splitFilter = (outputs, suffix = '') => {
|
|
|
546
555
|
return `split=${outputs.length}${out}${suffix}`;
|
|
547
556
|
};
|
|
548
557
|
async function calculateVmafScore(config) {
|
|
549
|
-
const { vmafPath, vmafPreview, vmafKeepIntermediateFiles, vmafKeepSourceFiles, vmafCrop } = config;
|
|
558
|
+
const { vmafPath, vmafPreview, vmafKeepIntermediateFiles, vmafKeepSourceFiles, vmafCrop, vmafSkipDuplicated } = config;
|
|
550
559
|
if (!fs_1.default.existsSync(config.vmafPath)) {
|
|
551
560
|
throw new Error(`VMAF path ${config.vmafPath} does not exist`);
|
|
552
561
|
}
|
|
553
562
|
log.debug(`calculateVmafScore referencePath=${vmafPath}`);
|
|
554
|
-
const { reference, degraded } = await fixIvfFiles(vmafPath, vmafKeepSourceFiles);
|
|
563
|
+
const { reference, degraded } = await fixIvfFiles(vmafPath, vmafKeepSourceFiles, vmafSkipDuplicated);
|
|
555
564
|
const crop = vmafCrop ? json5_1.default.parse(vmafCrop) : undefined;
|
|
556
565
|
const ret = [];
|
|
557
566
|
for (const participantDisplayName of reference.keys()) {
|
package/build/src/vmaf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vmaf.js","sourceRoot":"","sources":["../../src/vmaf.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs'\nimport json5 from 'json5'\nimport path from 'path'\nimport os from 'os'\n\nimport { FFProbeProcess, analyzeColors, chunkedPromiseAll, ffprobe, getFiles, logger, runShellCommand } from './utils'\nimport { FastStats } from './stats'\n\nconst log = logger('webrtcperf:vmaf')\n\nconst cpus = os.cpus().length\n\nexport interface IvfFrame {\n pts: number\n recognizedPts?: number\n index: number\n position: number\n size: number\n}\n\nexport async function parseVideo(fpath: string) {\n let width = 0\n let height = 0\n let frameRate = 0\n await ffprobe(fpath, 'video', 'frame=pts,width,height,duration_time', '', frame => {\n const w = parseInt(frame.width)\n const h = parseInt(frame.height)\n if (w > width) width = w\n if (h > height) height = h\n const duration = parseFloat(frame.duration_time)\n if (duration) {\n frameRate = Math.max(Math.round(1 / duration), frameRate)\n }\n return FFProbeProcess.Skip\n })\n return { width, height, frameRate }\n}\n\n/**\n * It prepares a video file for VMAF evaluation applying a timestamp video overlay.\n * @param name The input video file path with the output id (e.g `filename.flv,1`).\n * @param crop If the video should be cropped.\n * @param keepSourceFile If the source file should be kept.\n */\nexport async function prepareVideo(\n {\n vmafPrepareVideo,\n vmafVideoCrop,\n videoWidth,\n videoHeight,\n videoFramerate,\n videoDuration,\n }: {\n vmafPrepareVideo: string\n vmafVideoCrop?: string\n videoWidth: number\n videoHeight: number\n videoFramerate: number\n videoDuration: number\n },\n keepSourceFile = true,\n) {\n const [fpath, id] = vmafPrepareVideo.split(',')\n const outputPath = path.join(path.dirname(fpath), `${id}_send.mp4`)\n if (fs.existsSync(outputPath)) {\n throw new Error(`Output file ${outputPath} already exists`)\n }\n const { width, height, frameRate } = await parseVideo(fpath)\n log.info(\n `prepareVideo ${fpath} ${width}x${height}@${frameRate} -> ${outputPath} ${vmafVideoCrop && `crop: ${vmafVideoCrop}`}`,\n )\n const fontsize = Math.round((videoHeight || height) / 18)\n const textHeight = Math.round(fontsize * 1.2)\n const filter = vmafVideoCrop ? cropFilter(json5.parse(vmafVideoCrop), 0, ',') : ''\n await runShellCommand(\n `ffmpeg -hide_banner -loglevel warning -threads ${Math.min(cpus, 16)} \\\n${videoDuration ? `-t ${videoDuration}` : ''} \\\n-i ${fpath} \\\n-filter_complex \"[0:v]scale=w=${videoWidth || width}:h=${videoHeight || height},fps=${videoFramerate || frameRate},${filter}\\\ndrawbox=x=0:y=0:w=iw:h=${textHeight}:color=black:t=fill,\\\ndrawtext=fontfile=/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf:text='${id || 0}-%{eif\\\\:t*1000\\\\:u}':fontcolor=white:fontsize=${fontsize}:x=(w-text_w)/2:y=(${textHeight}-text_h)/2[out]\" \\\n-map [out] -fps_mode vfr -c:v libx264 -crf 10 -an \\\n-f mp4 -movflags +faststart ${outputPath}`,\n true,\n )\n\n if (!keepSourceFile) {\n await fs.promises.unlink(fpath)\n }\n}\n\n/**\n * It converts a video file to VP8/IVF format.\n * @param fpath The input video file path.\n * @param crop The crop filter.\n * @param keepSourceFile If the source file should be kept.\n */\nexport async function convertToIvf(fpath: string, crop?: string, keepSourceFile = true) {\n const { width, height, frameRate } = await parseVideo(fpath)\n const outputPath = fpath.replace(/\\.[^.]+$/, '.ivf.raw')\n log.debug(`convertToIvf ${fpath} ${width}x${height}@${frameRate} -> ${outputPath} crop:`, crop)\n\n const filter = crop ? `-vf '${cropFilter(json5.parse(crop))}'` : ''\n await runShellCommand(\n `ffmpeg -y -hide_banner -y -loglevel warning -i ${fpath} -map 0:v \\\n -c:v vp8 -quality best -cpu-used 0 -crf 1 -b:v 20M -qmin 1 -qmax 10 \\\n -g 1 -threads ${Math.min(cpus, 16)} ${filter} -an \\\n -f ivf ${outputPath}`,\n true,\n )\n\n await fixIvfFrames(outputPath, keepSourceFile)\n}\n\n/**\n * It recognizes the frames of a video file using OCR.\n * @param fpath The input video file path.\n * @param recover If missing frames should be recovered.\n * @param crop If the video should be cropped.\n * @param debug Enable debug logging.\n */\nexport async function recognizeFrames(fpath: string, recover = false, debug = false) {\n const { width, height, frameRate } = await parseVideo(fpath)\n const fname = path.basename(fpath)\n const frames = new Map<number, number>()\n let skipped = 0\n let failed = 0\n let recovered = 0\n let firstTimestamp = 0\n let lastTimestamp = 0\n let participantDisplayName = ''\n const regExp = /(?<name>[0-9]{1,6})-(?<time>[0-9]{1,13})/\n await ffprobe(\n fpath,\n 'video',\n 'frame=pts,frame_tags=lavfi.ocr.text,lavfi.ocr.confidence',\n `scale=w=1280:h=-1:flags=bicubic,crop=w=min(iw\\\\,ih):h=max((ih/15)\\\\,32):x=(iw-ow)/2:y=0:exact=1,ocr=whitelist=0123456789-`,\n frame => {\n const pts = parseInt(frame.pts)\n if ((!frames.has(pts) || !frames.get(pts)) && frameRate) {\n const confidence = parseFloat(frame.tag_lavfi_ocr_confidence?.trim() || '0')\n const textMatch = regExp.exec(frame.tag_lavfi_ocr_text?.trim() || '')\n if (confidence > 0 && textMatch) {\n const { name, time } = textMatch.groups as { name: string; time: string }\n participantDisplayName = `Participant-${name.padStart(6, '0')}`\n const recognizedTime = parseInt(time)\n const recognizedPts = Math.round((frameRate * recognizedTime) / 1000)\n if (debug) {\n log.debug(\n `recognized frame ${fname} confidence=${confidence} pts=${pts} name=${name} time=${time} recognized=${recognizedPts}`,\n )\n }\n frames.set(pts, recognizedPts)\n if (!firstTimestamp) firstTimestamp = recognizedPts / frameRate\n lastTimestamp = recognizedPts / frameRate\n } else {\n if (recover) frames.set(pts, 0)\n failed++\n }\n } else {\n skipped++\n }\n return FFProbeProcess.Skip\n },\n )\n\n if (recover) {\n const ptsIndex = Array.from(frames.keys()).sort((a, b) => a - b)\n for (const [i, pts] of ptsIndex.entries()) {\n const recognizedPts = frames.get(pts)\n if (!recognizedPts && i) {\n const prevRecognizedPts = frames.get(ptsIndex[i - 1])\n if (prevRecognizedPts) {\n frames.set(pts, prevRecognizedPts + pts - ptsIndex[i - 1])\n recovered++\n } else {\n frames.delete(pts)\n }\n }\n }\n }\n\n log.info(\n `recognizeFrames ${fname} ${width}x${height}@${frameRate} \"${participantDisplayName}\" frames: ${frames.size} skipped: ${skipped} recovered: ${recovered} failed: ${failed} \\\nts: ${firstTimestamp.toFixed(2)}-${lastTimestamp.toFixed(2)} (${(lastTimestamp - firstTimestamp).toFixed(2)})`,\n )\n return { width, height, frameRate, frames, participantDisplayName }\n}\n\nasync function parseIvf(fpath: string, runRecognizer = false) {\n const { width, height } = await parseVideo(fpath)\n const fname = path.basename(fpath)\n const fd = await fs.promises.open(fpath, 'r')\n const headerData = new ArrayBuffer(32)\n const headerView = new DataView(headerData)\n const ret = await fd.read(headerView, 0, 32, 0)\n if (ret.bytesRead !== 32) {\n await fd.close()\n throw new Error('Invalid IVF file')\n }\n const den = headerView.getUint32(16, true)\n const num = headerView.getUint32(20, true)\n const frameRate = den / num\n let participantDisplayName = ''\n let skipped = 0\n\n const frameHeaderView = new DataView(new ArrayBuffer(12))\n let index = 0\n let position = 32\n let bytesRead = 0\n const frames = new Map<number, IvfFrame>()\n let firstTimestamp = 0\n let lastTimestamp = 0\n do {\n const ret = await fd.read(frameHeaderView, 0, frameHeaderView.byteLength, position)\n bytesRead = ret.bytesRead\n if (bytesRead !== 12) {\n break\n }\n const size = frameHeaderView.getUint32(0, true)\n const pts = Number(frameHeaderView.getBigUint64(4, true))\n /* if (pts <= ptsIndex[ptsIndex.length - 1]) {\n log.warn(`IVF file ${fname}: pts ${pts} <= prev ${ptsIndex[ptsIndex.length - 1]}`)\n } */\n if (frames.has(pts)) {\n /* log.debug(`IVF file ${fname}: pts ${pts} already present, skipping`) */\n skipped++\n } else {\n frames.set(pts, { pts, index, position, size: size + 12 })\n index++\n if (!firstTimestamp) {\n firstTimestamp = pts / frameRate\n }\n lastTimestamp = pts / frameRate\n }\n position += size + 12\n } while (bytesRead === 12)\n await fd.close()\n\n log.debug(\n `parseIvf ${fname}: ${width}x${height}@${frameRate} \\\nframes: ${frames.size} skipped: ${skipped} \\\nts: ${firstTimestamp.toFixed(2)}-${lastTimestamp.toFixed(2)} (${(lastTimestamp - firstTimestamp).toFixed(2)}s)`,\n )\n\n if (runRecognizer) {\n const { frames: ptsToRecognized, participantDisplayName: name } = await recognizeFrames(fpath)\n participantDisplayName = name\n for (const [pts, frame] of frames.entries()) {\n const recognizedPts = ptsToRecognized.get(pts)\n if (!recognizedPts) continue\n frame.recognizedPts = recognizedPts\n }\n }\n\n return {\n width,\n height,\n frameRate,\n frames,\n participantDisplayName,\n }\n}\n\nexport async function fixIvfFrames(filePath: string, keepSourceFile = true) {\n const fname = path.basename(filePath)\n const dirPath = path.dirname(filePath)\n if (!fname.endsWith('.ivf.raw')) {\n throw new Error(`fixIvfFrames ${fname}: invalid file extension, expected \".ivf.raw\"`)\n }\n const { width, height, frames, participantDisplayName } = await parseIvf(filePath, true)\n if (!participantDisplayName) {\n throw new Error(`fixIvfFrames ${fname}: no participant name found`)\n }\n if (!frames.size) {\n throw new Error(`fixIvfFrames ${fname}: no frames found`)\n }\n log.debug(`fixIvfFrames ${fname} width=${width} height=${height} (${frames.size} frames)`)\n const fd = await fs.promises.open(filePath, 'r')\n\n const parts = path.basename(filePath).split('_')\n if (!parts[1].startsWith('send') && !parts[1].startsWith('recv')) {\n throw new Error(`fixIvfFrames ${fname}: invalid file name, expected \"<name>_send\" or \"<name>_recv\"`)\n }\n const outFilePath = path.join(\n dirPath,\n parts[1].startsWith('send') ? `${participantDisplayName}.ivf` : `${participantDisplayName}_recv-by_${parts[0]}.ivf`,\n )\n\n const fixedFd = await fs.promises.open(outFilePath, 'w')\n const headerView = new DataView(new ArrayBuffer(32))\n await fd.read(headerView, 0, headerView.byteLength, 0)\n\n let position = 32\n let writtenFrames = 0\n\n const ptsIndex = Array.from(frames.keys())\n .filter(pts => frames.get(pts)?.recognizedPts)\n .sort((a, b) => {\n if (a === b) return (frames.get(a)?.recognizedPts || 0) - (frames.get(b)?.recognizedPts || 0)\n return a - b\n })\n for (const [i, pts] of ptsIndex.entries()) {\n const frame = frames.get(pts)\n if (!frame || !frame.recognizedPts) {\n log.warn(`fixIvfFrames ${fname}: pts ${pts} not found, skipping`)\n continue\n }\n\n const prevFrame = frames.get(ptsIndex[i - 1])\n const nextFrame = frames.get(ptsIndex[i + 1])\n // Skip frames that are not in the correct order.\n if (nextFrame?.recognizedPts && (nextFrame?.recognizedPts || 0) < frame.recognizedPts) {\n continue\n }\n // Keep duplicated frames.\n if (prevFrame?.recognizedPts && frame.recognizedPts === prevFrame.recognizedPts) {\n /* log.warn(\n `${frame.index} pts=${pts}:${frame.recognizedPts} prev ${prevFrame.pts}(${pts - prevFrame.pts}):${prevFrame.recognizedPts}(${frame.recognizedPts - prevFrame.recognizedPts}) next ${nextFrame?.pts}(${(nextFrame?.pts || 0) - pts}):${nextFrame?.recognizedPts}(${(nextFrame?.recognizedPts || 0) - frame.recognizedPts})`,\n ) */\n frame.recognizedPts = prevFrame.recognizedPts + 1\n }\n const frameView = new DataView(new ArrayBuffer(frame.size))\n await fd.read(frameView, 0, frame.size, frame.position)\n frameView.setBigUint64(4, BigInt(frame.recognizedPts), true)\n await fixedFd.write(new Uint8Array(frameView.buffer), 0, frameView.byteLength, position)\n position += frameView.byteLength\n writtenFrames++\n }\n\n headerView.setUint16(12, width, true)\n headerView.setUint16(14, height, true)\n headerView.setUint32(24, writtenFrames, true)\n await fixedFd.write(new Uint8Array(headerView.buffer), 0, headerView.byteLength, 0)\n\n await fd.close()\n await fixedFd.close()\n\n if (!keepSourceFile) {\n await fs.promises.unlink(filePath)\n }\n\n return { participantDisplayName, outFilePath }\n}\n\nexport async function fixIvfFiles(directory: string, keepSourceFiles = true) {\n const reference = new Map<string, string>()\n const degraded = new Map<string, string[]>()\n\n const addFile = (participantDisplayName: string, outFilePath: string) => {\n if (outFilePath.includes('_recv-by_')) {\n if (!degraded.has(participantDisplayName)) {\n degraded.set(participantDisplayName, [])\n }\n degraded.get(participantDisplayName)?.push(outFilePath)\n } else {\n reference.set(participantDisplayName, outFilePath)\n }\n }\n\n const ivfFiles = await getFiles(directory, '.ivf')\n if (ivfFiles.length) {\n log.debug(`using existing ${ivfFiles.length} ivf files`)\n for (const outFilePath of ivfFiles) {\n try {\n const participantDisplayName = path.basename(outFilePath).replace('.ivf', '').split('_')[0]\n addFile(participantDisplayName, outFilePath)\n } catch (err) {\n log.error(`fixIvfFrames error: ${(err as Error).stack}`)\n }\n }\n }\n\n const rawFiles = await getFiles(directory, '.ivf.raw')\n if (rawFiles.length) {\n log.debug(`processing ${rawFiles.length} raw ivf files`)\n const results = await chunkedPromiseAll<\n string,\n { participantDisplayName: string; outFilePath: string } | undefined\n >(\n rawFiles,\n async filePath => {\n try {\n const { participantDisplayName, outFilePath } = await fixIvfFrames(filePath, keepSourceFiles)\n return { participantDisplayName, outFilePath }\n } catch (err) {\n log.error(`fixIvfFrames error: ${(err as Error).stack}`)\n }\n },\n Math.ceil(cpus / 4),\n )\n for (const res of results) {\n if (!res) continue\n const { participantDisplayName, outFilePath } = res\n addFile(participantDisplayName, outFilePath)\n }\n }\n\n return { reference, degraded }\n}\n\nasync function filterIvfFrames(fpath: string, frames: IvfFrame[]) {\n const outFilePath = fpath.replace('.ivf', '.filtered.ivf')\n const fd = await fs.promises.open(fpath, 'r')\n const fixedFd = await fs.promises.open(outFilePath, 'w')\n const headerView = new DataView(new ArrayBuffer(32))\n await fd.read(headerView, 0, headerView.byteLength, 0)\n\n let position = 32\n let writtenFrames = 0\n for (const frame of frames.values()) {\n const frameView = new DataView(new ArrayBuffer(frame.size))\n await fd.read(frameView, 0, frame.size, frame.position)\n await fixedFd.write(new Uint8Array(frameView.buffer), 0, frameView.byteLength, position)\n position += frameView.byteLength\n writtenFrames++\n }\n\n headerView.setUint32(24, writtenFrames, true)\n await fixedFd.write(new Uint8Array(headerView.buffer), 0, headerView.byteLength, 0)\n\n await fd.close()\n await fixedFd.close()\n return outFilePath\n}\n\nexport interface VmafScore {\n sender: string\n receiver: string\n min: number\n max: number\n mean: number\n harmonic_mean: number\n}\n\nexport async function runVmaf(\n referencePath: string,\n degradedPath: string,\n preview: boolean,\n cropConfig: VmafCrop = {},\n cropTimeOverlay = false,\n) {\n const comparisonDir = path.dirname(degradedPath)\n const comparisonName = path.basename(degradedPath.replace(/\\.[^.]+$/, ''))\n const cropDest = cropConfig[comparisonName]\n const crop = { ref: fixCrop(cropDest?.ref), deg: fixCrop(cropDest?.deg) }\n\n log.info('runVmaf', { referencePath, degradedPath, preview, crop })\n await fs.promises.mkdir(path.join(comparisonDir, comparisonName), { recursive: true })\n const vmafLogPath = path.join(comparisonDir, comparisonName, 'vmaf-log.json')\n const psnrLogPath = path.join(comparisonDir, comparisonName, 'psnr.log')\n const comparisonPath = path.join(comparisonDir, comparisonName, 'comparison.mp4')\n\n const sender = path.basename(referencePath).replace('.ivf', '')\n const receiver = path.basename(degradedPath).replace('.ivf', '').split('_recv-by_')[1]\n\n const { frameRate: refFrameRate, frames: refFrames } = await parseIvf(referencePath, false)\n const {\n width: degWidth,\n height: degHeight,\n frameRate: degFrameRate,\n frames: degFrames,\n } = await parseIvf(degradedPath, false)\n\n const textHeight = cropTimeOverlay ? '(ih/15)' : ''\n if (textHeight) {\n crop.ref.h = `${crop.ref.h}-${textHeight}`\n crop.ref.y = `${crop.ref.y}+${textHeight}`\n\n crop.deg.h = `${crop.deg.h}-${textHeight}`\n crop.deg.y = `${crop.deg.y}+${textHeight}`\n }\n\n if (refFrameRate !== degFrameRate) {\n throw new Error(`runVmaf: frame rates do not match: ref=${refFrameRate} deg=${degFrameRate}`)\n }\n\n // Find common frames.\n const commonRefFrames = []\n const commonDegFrames = []\n let firstPts = 0\n let lastPts = 0\n for (const [pts, refFrame] of refFrames.entries()) {\n const degFrame = degFrames.get(pts)\n if (degFrame) {\n commonRefFrames.push(refFrame)\n commonDegFrames.push(degFrame)\n if (!firstPts) {\n firstPts = pts\n }\n lastPts = pts\n }\n }\n const duration = (lastPts - firstPts) / refFrameRate\n\n referencePath = await filterIvfFrames(referencePath, commonRefFrames)\n degradedPath = await filterIvfFrames(degradedPath, commonDegFrames)\n log.debug(\n `common frames: ${commonRefFrames.length} ref: ${refFrames.size} deg: ${degFrames.size} duration: ${duration}s`,\n {\n crop,\n },\n )\n\n const ffmpegCmd = `ffmpeg -hide_banner -loglevel warning -y -threads ${Math.min(cpus, 16)} \\\n-i ${degradedPath} \\\n-i ${referencePath} \\\n`\n\n const filter = `\\\n[0:v]\\\nscale=w=-1:h=${degHeight}:flags=bicubic,\\\n${cropFilter(crop.deg, 0, ',')}\\\n${splitFilter(['deg_vmaf', 'deg_psnr', preview ? 'deg_preview' : ''])};\\\n[1:v]\\\nscale=w=-1:h=${degHeight}:flags=bicubic,crop=w=${degWidth}:x=(iw-${degWidth})/2,\\\n${cropFilter(crop.ref, 0, ',')}\\\n${splitFilter(['ref_vmaf', 'ref_psnr', preview ? 'ref_preview' : ''])};\\\n[deg_vmaf][ref_vmaf]libvmaf=model='path=/usr/share/model/vmaf_v0.6.1.json':log_fmt=json:log_path=${vmafLogPath}:n_subsample=1:n_threads=${cpus}:shortest=1[vmaf];\\\n[deg_psnr][ref_psnr]psnr=stats_file=${psnrLogPath}[psnr]\\\n`\n\n const cmd = preview\n ? `${ffmpegCmd} \\\n-filter_complex \"${filter};[ref_preview][deg_preview]hstack[stacked]\" \\\n-map [vmaf] -f null - \\\n-map [psnr] -f null - \\\n-map [stacked] -fps_mode vfr -c:v libx264 -crf 10 -f mp4 -movflags +faststart ${comparisonPath} \\\n`\n : `${ffmpegCmd} \\\n-filter_complex \"${filter}\" \\\n-map [vmaf] -f null - \\\n-map [psnr] -f null - \\\n`\n\n log.debug('runVmaf', cmd)\n try {\n const { stdout, stderr } = await runShellCommand(cmd)\n\n const vmafLog = JSON.parse(await fs.promises.readFile(vmafLogPath, 'utf-8'))\n log.debug('runVmaf', {\n stdout,\n stderr,\n })\n const metrics = {\n sender,\n receiver,\n\n ...vmafLog.pooled_metrics.vmaf,\n } as VmafScore\n\n log.info(`VMAF metrics ${vmafLogPath}:`, metrics)\n\n try {\n await writeGraph(vmafLogPath)\n } catch (err) {\n log.error(`writeGraph error: ${(err as Error).stack}`)\n }\n\n return metrics\n } finally {\n await fs.promises.unlink(degradedPath)\n await fs.promises.unlink(referencePath)\n }\n}\n\nasync function writeGraph(vmafLogPath: string) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { ChartJSNodeCanvas } = require('chartjs-node-canvas')\n\n const vmafLog = JSON.parse(await fs.promises.readFile(vmafLogPath, 'utf-8')) as {\n frames: {\n frameNum: number\n metrics: { vmaf: number }\n }[]\n pooled_metrics: {\n vmaf: { min: number; max: number; mean: number; harmonic_mean: number }\n }\n }\n const { min, max, mean } = vmafLog.pooled_metrics.vmaf\n\n const fpath = vmafLogPath.replace('.json', '.png')\n\n const decimation = Math.ceil(vmafLog.frames.length / 500)\n const stats = new FastStats()\n const data = vmafLog.frames\n .reduce(\n (prev, cur) => {\n if (cur.frameNum % decimation === 0) {\n prev.push({\n x: cur.frameNum,\n y: cur.metrics.vmaf,\n count: 1,\n })\n } else {\n prev[prev.length - 1].y += cur.metrics.vmaf\n prev[prev.length - 1].count++\n }\n stats.push(cur.metrics.vmaf)\n return prev\n },\n [] as { x: number; y: number; count: 1 }[],\n )\n .map(d => ({ x: d.x, y: d.y / d.count }))\n\n const chartJSNodeCanvas = new ChartJSNodeCanvas({\n width: 1280,\n height: 720,\n backgroundColour: 'white',\n })\n\n const buffer = await chartJSNodeCanvas.renderToBuffer({\n type: 'line',\n data: {\n labels: data.map(d => d.x),\n datasets: [\n {\n label: `VMAF score (min: ${min.toFixed(2)}, max: ${max.toFixed(\n 2,\n )}, mean: ${mean.toFixed(2)}, P5: ${stats.percentile(5).toFixed(2)})`,\n data: data.map(d => d.y),\n fill: false,\n borderColor: 'rgb(0, 0, 0)',\n borderWidth: 1,\n pointRadius: 0,\n },\n ],\n },\n options: {\n plugins: {\n title: {\n display: true,\n text: path.basename(vmafLogPath).replace('.vmaf.json', '').replace(/_/g, ' '),\n },\n },\n scales: {\n y: {\n min: 0,\n max: 100,\n },\n },\n },\n })\n\n await fs.promises.writeFile(fpath, buffer)\n}\n\ninterface Crop {\n w: string\n h: string\n x: string\n y: string\n}\n\ntype VmafCrop = Record<\n string,\n {\n ref?: Crop\n deg?: Crop\n }\n>\n\nconst fixCrop = (c?: Crop) => {\n return {\n w: c?.w ?? 'iw',\n h: c?.h ?? 'ih',\n x: c?.x ?? '0',\n y: c?.y ?? '0',\n }\n}\n\nconst cropFilter = (crop: Crop, exact = 0, suffix = '') => {\n const { w, h, x, y } = crop\n if (!x && !w && !x && !y) return ''\n return `crop=w=${w}:h=${h}:x=${x}:y=${y}:exact=${exact}${suffix}`\n}\n\nconst splitFilter = (outputs: string[], suffix = '') => {\n const out = outputs\n .filter(o => !!o)\n .map(o => `[${o}]`)\n .join('')\n if (!out) return ''\n return `split=${outputs.length}${out}${suffix}`\n}\n\ninterface VmafConfig {\n vmafPath: string\n vmafPreview: boolean\n vmafKeepIntermediateFiles: boolean\n vmafKeepSourceFiles: boolean\n vmafCrop?: string\n}\n\nexport async function calculateVmafScore(config: VmafConfig): Promise<VmafScore[]> {\n const { vmafPath, vmafPreview, vmafKeepIntermediateFiles, vmafKeepSourceFiles, vmafCrop } = config\n if (!fs.existsSync(config.vmafPath)) {\n throw new Error(`VMAF path ${config.vmafPath} does not exist`)\n }\n log.debug(`calculateVmafScore referencePath=${vmafPath}`)\n\n const { reference, degraded } = await fixIvfFiles(vmafPath, vmafKeepSourceFiles)\n\n const crop: VmafCrop | undefined = vmafCrop ? json5.parse(vmafCrop) : undefined\n\n const ret: VmafScore[] = []\n for (const participantDisplayName of reference.keys()) {\n const vmafReferencePath = reference.get(participantDisplayName)\n if (!vmafReferencePath) continue\n for (const degradedPath of degraded.get(participantDisplayName) ?? []) {\n try {\n const metrics = await runVmaf(vmafReferencePath, degradedPath, vmafPreview, crop)\n ret.push(metrics)\n } catch (err) {\n log.error(`runVmaf error: ${(err as Error).message}`)\n } finally {\n if (!vmafKeepIntermediateFiles) {\n await fs.promises.unlink(degradedPath)\n }\n }\n }\n if (!vmafKeepIntermediateFiles) {\n await fs.promises.unlink(vmafReferencePath)\n }\n }\n await fs.promises.writeFile(path.join(vmafPath, 'vmaf.json'), JSON.stringify(ret, undefined, 2))\n\n return ret\n}\n\nif (require.main === module) {\n ;(async (): Promise<void> => {\n switch (process.argv[2]) {\n case 'convert':\n await convertToIvf(process.argv[3], process.argv[4], false)\n break\n case 'parse': {\n const { frames } = await parseIvf(process.argv[3], true)\n console.log(frames)\n break\n }\n case 'fix':\n await fixIvfFrames(process.argv[3], true)\n break\n case 'analyze':\n console.log(JSON.stringify(await analyzeColors(process.argv[3]), null, 2))\n break\n case 'graph':\n await writeGraph(process.argv[3])\n break\n case 'vmaf':\n await calculateVmafScore({\n vmafPath: process.argv[3],\n vmafPreview: true,\n vmafKeepIntermediateFiles: true,\n vmafKeepSourceFiles: true,\n vmafCrop: json5.stringify({\n 'Participant-000001_recv-by_Participant-000000': {\n ref: { w: '', h: '', x: '', y: '' },\n deg: { w: '', h: '', x: '', y: '' },\n },\n }),\n })\n break\n default:\n throw new Error(`Invalid command: ${process.argv[2]}`)\n }\n })()\n .catch(err => console.error(err))\n .finally(() => process.exit(0))\n}\n"]}
|
|
1
|
+
{"version":3,"file":"vmaf.js","sourceRoot":"","sources":["../../src/vmaf.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs'\nimport json5 from 'json5'\nimport path from 'path'\nimport os from 'os'\n\nimport { FFProbeProcess, analyzeColors, chunkedPromiseAll, ffprobe, getFiles, logger, runShellCommand } from './utils'\nimport { FastStats } from './stats'\n\nconst log = logger('webrtcperf:vmaf')\n\nconst cpus = os.cpus().length\n\nexport interface IvfFrame {\n pts: number\n recognizedPts?: number\n index: number\n position: number\n size: number\n}\n\nexport async function parseVideo(fpath: string) {\n let width = 0\n let height = 0\n let frameRate = 0\n await ffprobe(fpath, 'video', 'frame=pts,width,height,duration_time', '', frame => {\n const w = parseInt(frame.width)\n const h = parseInt(frame.height)\n if (w > width) width = w\n if (h > height) height = h\n const duration = parseFloat(frame.duration_time)\n if (duration) {\n frameRate = Math.max(Math.round(1 / duration), frameRate)\n }\n return FFProbeProcess.Skip\n })\n return { width, height, frameRate }\n}\n\n/**\n * It prepares a video file for VMAF evaluation applying a timestamp video overlay.\n * @param name The input video file path with the output id (e.g `filename.flv,1`).\n * @param crop If the video should be cropped.\n * @param keepSourceFile If the source file should be kept.\n */\nexport async function prepareVideo(\n {\n vmafPrepareVideo,\n vmafVideoCrop,\n videoWidth,\n videoHeight,\n videoFramerate,\n videoDuration,\n }: {\n vmafPrepareVideo: string\n vmafVideoCrop?: string\n videoWidth: number\n videoHeight: number\n videoFramerate: number\n videoDuration: number\n },\n keepSourceFile = true,\n) {\n const [fpath, id] = vmafPrepareVideo.split(',')\n const outputPath = path.join(path.dirname(fpath), `${id}_send.mp4`)\n if (fs.existsSync(outputPath)) {\n throw new Error(`Output file ${outputPath} already exists`)\n }\n const { width, height, frameRate } = await parseVideo(fpath)\n log.info(\n `prepareVideo ${fpath} ${width}x${height}@${frameRate} -> ${outputPath} ${vmafVideoCrop && `crop: ${vmafVideoCrop}`}`,\n )\n const fontsize = Math.round((videoHeight || height) / 18)\n const textHeight = Math.round(fontsize * 1.2)\n const filter = vmafVideoCrop ? cropFilter(json5.parse(vmafVideoCrop), 0, ',') : ''\n await runShellCommand(\n `ffmpeg -hide_banner -loglevel warning -threads ${Math.min(cpus, 16)} \\\n${videoDuration ? `-t ${videoDuration}` : ''} \\\n-stream_loop -1 -i ${fpath} \\\n-filter_complex \"[0:v]scale=w=${videoWidth || width}:h=${videoHeight || height},fps=${videoFramerate || frameRate},${filter}\\\ndrawbox=x=0:y=0:w=iw:h=${textHeight}:color=black:t=fill,\\\ndrawtext=fontfile=/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf:text='${id || 0}-%{eif\\\\:t*1000\\\\:u}':fontcolor=white:fontsize=${fontsize}:x=(w-text_w)/2:y=(${textHeight}-text_h)/2[out]\" \\\n-map [out] -fps_mode vfr -c:v libx264 -crf 10 -an \\\n-f mp4 -movflags +faststart ${outputPath}`,\n true,\n )\n\n if (!keepSourceFile) {\n await fs.promises.unlink(fpath)\n }\n}\n\n/**\n * It converts a video file to VP8/IVF format.\n * @param fpath The input video file path.\n * @param crop The crop filter.\n * @param keepSourceFile If the source file should be kept.\n * @param skipDuplicated If the duplicated recognized frames should be skipped.\n */\nexport async function convertToIvf(fpath: string, crop?: string, keepSourceFile = true, skipDuplicated = false) {\n const { width, height, frameRate } = await parseVideo(fpath)\n const outputPath = fpath.replace(/\\.[^.]+$/, '.ivf.raw')\n log.debug(`convertToIvf ${fpath} ${width}x${height}@${frameRate} -> ${outputPath} crop:`, crop)\n\n const filter = crop ? `-vf '${cropFilter(json5.parse(crop))}'` : ''\n await runShellCommand(\n `ffmpeg -y -hide_banner -y -loglevel warning -i ${fpath} -map 0:v \\\n -c:v vp8 -quality best -cpu-used 0 -crf 1 -b:v 20M -qmin 1 -qmax 10 \\\n -g 1 -threads ${Math.min(cpus, 16)} ${filter} -an \\\n -f ivf ${outputPath}`,\n true,\n )\n if (!keepSourceFile) {\n await fs.promises.unlink(fpath)\n }\n\n await fixIvfFrames(outputPath, false, skipDuplicated)\n}\n\n/**\n * It recognizes the frames of a video file using OCR.\n * @param fpath The input video file path.\n * @param recover If missing frames should be recovered.\n * @param crop If the video should be cropped.\n * @param debug Enable debug logging.\n */\nexport async function recognizeFrames(fpath: string, recover = false, debug = false) {\n const { width, height, frameRate } = await parseVideo(fpath)\n const fname = path.basename(fpath)\n const frames = new Map<number, number>()\n let skipped = 0\n let failed = 0\n let recovered = 0\n let firstTimestamp = 0\n let lastTimestamp = 0\n let participantDisplayName = ''\n const regExp = /(?<name>[0-9]{1,6})-(?<time>[0-9]{1,13})/\n await ffprobe(\n fpath,\n 'video',\n 'frame=pts,frame_tags=lavfi.ocr.text,lavfi.ocr.confidence',\n `scale=w=1280:h=-1:flags=bicubic,crop=w=min(iw\\\\,ih):h=max((ih/15)\\\\,32):x=(iw-ow)/2:y=0:exact=1,ocr=whitelist=0123456789-`,\n frame => {\n const pts = parseInt(frame.pts)\n if ((!frames.has(pts) || !frames.get(pts)) && frameRate) {\n const confidence = parseFloat(frame.tag_lavfi_ocr_confidence?.trim() || '0')\n const textMatch = regExp.exec(frame.tag_lavfi_ocr_text?.trim() || '')\n if (confidence > 0 && textMatch) {\n const { name, time } = textMatch.groups as { name: string; time: string }\n participantDisplayName = `Participant-${name.padStart(6, '0')}`\n const recognizedTime = parseInt(time)\n const recognizedPts = Math.round((frameRate * recognizedTime) / 1000)\n if (debug) {\n log.debug(\n `recognized frame ${fname} confidence=${confidence} pts=${pts} name=${name} time=${time} recognized=${recognizedPts}`,\n )\n }\n frames.set(pts, recognizedPts)\n if (!firstTimestamp) firstTimestamp = recognizedPts / frameRate\n lastTimestamp = recognizedPts / frameRate\n } else {\n if (recover) frames.set(pts, 0)\n failed++\n }\n } else {\n skipped++\n }\n return FFProbeProcess.Skip\n },\n )\n\n if (recover) {\n const ptsIndex = Array.from(frames.keys()).sort((a, b) => a - b)\n for (const [i, pts] of ptsIndex.entries()) {\n const recognizedPts = frames.get(pts)\n if (!recognizedPts && i) {\n const prevRecognizedPts = frames.get(ptsIndex[i - 1])\n if (prevRecognizedPts) {\n frames.set(pts, prevRecognizedPts + pts - ptsIndex[i - 1])\n recovered++\n } else {\n frames.delete(pts)\n }\n }\n }\n }\n\n log.info(\n `recognizeFrames ${fname} ${width}x${height}@${frameRate} \"${participantDisplayName}\" frames: ${frames.size} skipped: ${skipped} recovered: ${recovered} failed: ${failed} \\\nts: ${firstTimestamp.toFixed(2)}-${lastTimestamp.toFixed(2)} (${(lastTimestamp - firstTimestamp).toFixed(2)})`,\n )\n return { width, height, frameRate, frames, participantDisplayName }\n}\n\nasync function parseIvf(fpath: string, runRecognizer = false) {\n const { width, height } = await parseVideo(fpath)\n const fname = path.basename(fpath)\n const fd = await fs.promises.open(fpath, 'r')\n const headerData = new ArrayBuffer(32)\n const headerView = new DataView(headerData)\n const ret = await fd.read(headerView, 0, 32, 0)\n if (ret.bytesRead !== 32) {\n await fd.close()\n throw new Error('Invalid IVF file')\n }\n const den = headerView.getUint32(16, true)\n const num = headerView.getUint32(20, true)\n const frameRate = den / num\n let participantDisplayName = ''\n let skipped = 0\n\n const frameHeaderView = new DataView(new ArrayBuffer(12))\n let index = 0\n let position = 32\n let bytesRead = 0\n const frames = new Map<number, IvfFrame>()\n let firstTimestamp = 0\n let lastTimestamp = 0\n do {\n const ret = await fd.read(frameHeaderView, 0, frameHeaderView.byteLength, position)\n bytesRead = ret.bytesRead\n if (bytesRead !== 12) {\n break\n }\n const size = frameHeaderView.getUint32(0, true)\n const pts = Number(frameHeaderView.getBigUint64(4, true))\n /* if (pts <= ptsIndex[ptsIndex.length - 1]) {\n log.warn(`IVF file ${fname}: pts ${pts} <= prev ${ptsIndex[ptsIndex.length - 1]}`)\n } */\n if (frames.has(pts)) {\n log.debug(`IVF file ${fname}: pts ${pts} already present, skipping`)\n skipped++\n } else {\n frames.set(pts, { pts, index, position, size: size + 12 })\n index++\n if (!firstTimestamp) {\n firstTimestamp = pts / frameRate\n }\n lastTimestamp = pts / frameRate\n }\n position += size + 12\n } while (bytesRead === 12)\n await fd.close()\n\n log.debug(\n `parseIvf ${fname}: ${width}x${height}@${frameRate} \\\nframes: ${frames.size} skipped: ${skipped} \\\nts: ${firstTimestamp.toFixed(2)}-${lastTimestamp.toFixed(2)} (${(lastTimestamp - firstTimestamp).toFixed(2)}s)`,\n )\n\n if (runRecognizer) {\n const { frames: ptsToRecognized, participantDisplayName: name } = await recognizeFrames(fpath)\n participantDisplayName = name\n for (const [pts, frame] of frames.entries()) {\n const recognizedPts = ptsToRecognized.get(pts)\n if (!recognizedPts) continue\n frame.recognizedPts = recognizedPts\n }\n }\n\n return {\n width,\n height,\n frameRate,\n frames,\n participantDisplayName,\n }\n}\n\nexport async function fixIvfFrames(filePath: string, keepSourceFile = true, skipDuplicated = false) {\n const fname = path.basename(filePath)\n log.debug(`fixIvfFrames ${fname} keepSourceFile=${keepSourceFile} skipDuplicated=${skipDuplicated}`)\n const dirPath = path.dirname(filePath)\n if (!fname.endsWith('.ivf.raw')) {\n throw new Error(`fixIvfFrames ${fname}: invalid file extension, expected \".ivf.raw\"`)\n }\n const { width, height, frames, participantDisplayName } = await parseIvf(filePath, true)\n if (!participantDisplayName) {\n throw new Error(`fixIvfFrames ${fname}: no participant name found`)\n }\n if (!frames.size) {\n throw new Error(`fixIvfFrames ${fname}: no frames found`)\n }\n log.debug(`fixIvfFrames ${fname} width=${width} height=${height} (${frames.size} frames)`)\n const fd = await fs.promises.open(filePath, 'r')\n\n const parts = path.basename(filePath).split('_')\n if (!parts[1].startsWith('send') && !parts[1].startsWith('recv')) {\n throw new Error(`fixIvfFrames ${fname}: invalid file name, expected \"<name>_send\" or \"<name>_recv\"`)\n }\n const outFilePath = path.join(\n dirPath,\n parts[1].startsWith('send') ? `${participantDisplayName}.ivf` : `${participantDisplayName}_recv-by_${parts[0]}.ivf`,\n )\n\n const fixedFd = await fs.promises.open(outFilePath, 'w')\n const headerView = new DataView(new ArrayBuffer(32))\n await fd.read(headerView, 0, headerView.byteLength, 0)\n\n let position = 32\n let writtenFrames = 0\n\n const ptsIndex = Array.from(frames.keys())\n .filter(pts => frames.get(pts)?.recognizedPts)\n .sort((a, b) => {\n if (a === b) return (frames.get(a)?.recognizedPts || 0) - (frames.get(b)?.recognizedPts || 0)\n return a - b\n })\n for (const [i, pts] of ptsIndex.entries()) {\n const frame = frames.get(pts)\n if (!frame || !frame.recognizedPts) {\n log.warn(`fixIvfFrames ${fname}: pts ${pts} not found, skipping`)\n continue\n }\n\n const prevFrame = frames.get(ptsIndex[i - 1])\n const nextFrame = frames.get(ptsIndex[i + 1])\n // Skip frames that are not in the correct order.\n if (nextFrame?.recognizedPts && (nextFrame?.recognizedPts || 0) < frame.recognizedPts) {\n continue\n }\n // Duplicated recognized frame.\n if (prevFrame?.recognizedPts && frame.recognizedPts === prevFrame.recognizedPts) {\n log.debug(\n `${fname}: duplicate recognized frame pts=${pts}:${frame.recognizedPts} prev=${prevFrame.pts}:${prevFrame.recognizedPts} next=${nextFrame?.pts}:${nextFrame?.recognizedPts} (${skipDuplicated ? 'skipped' : 'fixed'})`,\n )\n if (skipDuplicated) {\n continue\n } else {\n frame.recognizedPts += frame.pts - prevFrame.pts\n }\n }\n const frameView = new DataView(new ArrayBuffer(frame.size))\n await fd.read(frameView, 0, frame.size, frame.position)\n frameView.setBigUint64(4, BigInt(frame.recognizedPts), true)\n await fixedFd.write(new Uint8Array(frameView.buffer), 0, frameView.byteLength, position)\n position += frameView.byteLength\n writtenFrames++\n }\n\n headerView.setUint16(12, width, true)\n headerView.setUint16(14, height, true)\n headerView.setUint32(24, writtenFrames, true)\n await fixedFd.write(new Uint8Array(headerView.buffer), 0, headerView.byteLength, 0)\n\n await fd.close()\n await fixedFd.close()\n\n if (!keepSourceFile) {\n await fs.promises.unlink(filePath)\n }\n\n return { participantDisplayName, outFilePath }\n}\n\nexport async function fixIvfFiles(directory: string, keepSourceFiles = true, skipDuplicated = false) {\n log.debug(`fixIvfFiles ${directory} keepSourceFiles=${keepSourceFiles} skipDuplicated=${skipDuplicated}`)\n const reference = new Map<string, string>()\n const degraded = new Map<string, string[]>()\n\n const addFile = (participantDisplayName: string, outFilePath: string) => {\n if (outFilePath.includes('_recv-by_')) {\n if (!degraded.has(participantDisplayName)) {\n degraded.set(participantDisplayName, [])\n }\n degraded.get(participantDisplayName)?.push(outFilePath)\n } else {\n reference.set(participantDisplayName, outFilePath)\n }\n }\n\n const ivfFiles = await getFiles(directory, '.ivf')\n if (ivfFiles.length) {\n log.debug(`using existing ${ivfFiles.length} ivf files`)\n for (const outFilePath of ivfFiles) {\n try {\n const participantDisplayName = path.basename(outFilePath).replace('.ivf', '').split('_')[0]\n addFile(participantDisplayName, outFilePath)\n } catch (err) {\n log.error(`fixIvfFrames error: ${(err as Error).stack}`)\n }\n }\n }\n\n const rawFiles = await getFiles(directory, '.ivf.raw')\n if (rawFiles.length) {\n log.debug(`processing ${rawFiles.length} raw ivf files`)\n const results = await chunkedPromiseAll<\n string,\n { participantDisplayName: string; outFilePath: string } | undefined\n >(\n rawFiles,\n async filePath => {\n try {\n const { participantDisplayName, outFilePath } = await fixIvfFrames(filePath, keepSourceFiles, skipDuplicated)\n return { participantDisplayName, outFilePath }\n } catch (err) {\n log.error(`fixIvfFrames error: ${(err as Error).stack}`)\n }\n },\n Math.ceil(cpus / 4),\n )\n for (const res of results) {\n if (!res) continue\n const { participantDisplayName, outFilePath } = res\n addFile(participantDisplayName, outFilePath)\n }\n }\n\n return { reference, degraded }\n}\n\nasync function filterIvfFrames(fpath: string, frames: IvfFrame[]) {\n const outFilePath = fpath.replace('.ivf', '.filtered.ivf')\n const fd = await fs.promises.open(fpath, 'r')\n const fixedFd = await fs.promises.open(outFilePath, 'w')\n const headerView = new DataView(new ArrayBuffer(32))\n await fd.read(headerView, 0, headerView.byteLength, 0)\n\n let position = 32\n let writtenFrames = 0\n for (const frame of frames.values()) {\n const frameView = new DataView(new ArrayBuffer(frame.size))\n await fd.read(frameView, 0, frame.size, frame.position)\n await fixedFd.write(new Uint8Array(frameView.buffer), 0, frameView.byteLength, position)\n position += frameView.byteLength\n writtenFrames++\n }\n\n headerView.setUint32(24, writtenFrames, true)\n await fixedFd.write(new Uint8Array(headerView.buffer), 0, headerView.byteLength, 0)\n\n await fd.close()\n await fixedFd.close()\n return outFilePath\n}\n\nexport interface VmafScore {\n sender: string\n receiver: string\n min: number\n max: number\n mean: number\n harmonic_mean: number\n}\n\nexport async function runVmaf(\n referencePath: string,\n degradedPath: string,\n preview: boolean,\n cropConfig: VmafCrop = {},\n cropTimeOverlay = false,\n) {\n const comparisonDir = path.dirname(degradedPath)\n const comparisonName = path.basename(degradedPath.replace(/\\.[^.]+$/, ''))\n const cropDest = cropConfig[comparisonName]\n const crop = { ref: fixCrop(cropDest?.ref), deg: fixCrop(cropDest?.deg) }\n\n log.info('runVmaf', { referencePath, degradedPath, preview, crop })\n await fs.promises.mkdir(path.join(comparisonDir, comparisonName), { recursive: true })\n const vmafLogPath = path.join(comparisonDir, comparisonName, 'vmaf-log.json')\n const psnrLogPath = path.join(comparisonDir, comparisonName, 'psnr.log')\n const comparisonPath = path.join(comparisonDir, comparisonName, 'comparison.mp4')\n\n const sender = path.basename(referencePath).replace('.ivf', '')\n const receiver = path.basename(degradedPath).replace('.ivf', '').split('_recv-by_')[1]\n\n const { frameRate: refFrameRate, frames: refFrames } = await parseIvf(referencePath, false)\n const {\n width: degWidth,\n height: degHeight,\n frameRate: degFrameRate,\n frames: degFrames,\n } = await parseIvf(degradedPath, false)\n\n const textHeight = cropTimeOverlay ? '(ih/15)' : ''\n if (textHeight) {\n crop.ref.h = `${crop.ref.h}-${textHeight}`\n crop.ref.y = `${crop.ref.y}+${textHeight}`\n\n crop.deg.h = `${crop.deg.h}-${textHeight}`\n crop.deg.y = `${crop.deg.y}+${textHeight}`\n }\n\n if (refFrameRate !== degFrameRate) {\n throw new Error(`runVmaf: frame rates do not match: ref=${refFrameRate} deg=${degFrameRate}`)\n }\n\n // Find common frames.\n const commonRefFrames = []\n const commonDegFrames = []\n let firstPts = 0\n let lastPts = 0\n for (const [pts, refFrame] of refFrames.entries()) {\n const degFrame = degFrames.get(pts)\n if (degFrame) {\n commonRefFrames.push(refFrame)\n commonDegFrames.push(degFrame)\n if (!firstPts) {\n firstPts = pts\n }\n lastPts = pts\n }\n }\n const duration = (lastPts - firstPts) / refFrameRate\n\n referencePath = await filterIvfFrames(referencePath, commonRefFrames)\n degradedPath = await filterIvfFrames(degradedPath, commonDegFrames)\n log.debug(\n `common frames: ${commonRefFrames.length} ref: ${refFrames.size} deg: ${degFrames.size} duration: ${duration}s`,\n {\n crop,\n },\n )\n\n const ffmpegCmd = `ffmpeg -hide_banner -loglevel warning -y -threads ${Math.min(cpus, 16)} \\\n-i ${degradedPath} \\\n-i ${referencePath} \\\n`\n\n const filter = `\\\n[0:v]\\\nscale=w=-1:h=${degHeight}:flags=bicubic,\\\n${cropFilter(crop.deg, 0, ',')}\\\n${splitFilter(['deg_vmaf', 'deg_psnr', preview ? 'deg_preview' : ''])};\\\n[1:v]\\\nscale=w=-1:h=${degHeight}:flags=bicubic,crop=w=${degWidth}:x=(iw-${degWidth})/2,\\\n${cropFilter(crop.ref, 0, ',')}\\\n${splitFilter(['ref_vmaf', 'ref_psnr', preview ? 'ref_preview' : ''])};\\\n[deg_vmaf][ref_vmaf]libvmaf=model='path=/usr/share/model/vmaf_v0.6.1.json':log_fmt=json:log_path=${vmafLogPath}:n_subsample=1:n_threads=${cpus}:shortest=1[vmaf];\\\n[deg_psnr][ref_psnr]psnr=stats_file=${psnrLogPath}[psnr]\\\n`\n\n const cmd = preview\n ? `${ffmpegCmd} \\\n-filter_complex \"${filter};[ref_preview][deg_preview]hstack[stacked]\" \\\n-map [vmaf] -f null - \\\n-map [psnr] -f null - \\\n-map [stacked] -fps_mode vfr -c:v libx264 -crf 10 -f mp4 -movflags +faststart ${comparisonPath} \\\n`\n : `${ffmpegCmd} \\\n-filter_complex \"${filter}\" \\\n-map [vmaf] -f null - \\\n-map [psnr] -f null - \\\n`\n\n log.debug('runVmaf', cmd)\n try {\n const { stdout, stderr } = await runShellCommand(cmd)\n\n const vmafLog = JSON.parse(await fs.promises.readFile(vmafLogPath, 'utf-8'))\n log.debug('runVmaf', {\n stdout,\n stderr,\n })\n const metrics = {\n sender,\n receiver,\n\n ...vmafLog.pooled_metrics.vmaf,\n } as VmafScore\n\n log.info(`VMAF metrics ${vmafLogPath}:`, metrics)\n\n try {\n await writeGraph(vmafLogPath)\n } catch (err) {\n log.error(`writeGraph error: ${(err as Error).stack}`)\n }\n\n return metrics\n } finally {\n await fs.promises.unlink(degradedPath)\n await fs.promises.unlink(referencePath)\n }\n}\n\nasync function writeGraph(vmafLogPath: string) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { ChartJSNodeCanvas } = require('chartjs-node-canvas')\n\n const vmafLog = JSON.parse(await fs.promises.readFile(vmafLogPath, 'utf-8')) as {\n frames: {\n frameNum: number\n metrics: { vmaf: number }\n }[]\n pooled_metrics: {\n vmaf: { min: number; max: number; mean: number; harmonic_mean: number }\n }\n }\n const { min, max, mean } = vmafLog.pooled_metrics.vmaf\n\n const fpath = vmafLogPath.replace('.json', '.png')\n\n const decimation = Math.ceil(vmafLog.frames.length / 500)\n const stats = new FastStats()\n const data = vmafLog.frames\n .reduce(\n (prev, cur) => {\n if (cur.frameNum % decimation === 0) {\n prev.push({\n x: cur.frameNum,\n y: cur.metrics.vmaf,\n count: 1,\n })\n } else {\n prev[prev.length - 1].y += cur.metrics.vmaf\n prev[prev.length - 1].count++\n }\n stats.push(cur.metrics.vmaf)\n return prev\n },\n [] as { x: number; y: number; count: 1 }[],\n )\n .map(d => ({ x: d.x, y: d.y / d.count }))\n\n const chartJSNodeCanvas = new ChartJSNodeCanvas({\n width: 1280,\n height: 720,\n backgroundColour: 'white',\n })\n\n const buffer = await chartJSNodeCanvas.renderToBuffer({\n type: 'line',\n data: {\n labels: data.map(d => d.x),\n datasets: [\n {\n label: `VMAF score (min: ${min.toFixed(2)}, max: ${max.toFixed(\n 2,\n )}, mean: ${mean.toFixed(2)}, P5: ${stats.percentile(5).toFixed(2)})`,\n data: data.map(d => d.y),\n fill: false,\n borderColor: 'rgb(0, 0, 0)',\n borderWidth: 1,\n pointRadius: 0,\n },\n ],\n },\n options: {\n plugins: {\n title: {\n display: true,\n text: path.basename(vmafLogPath).replace('.vmaf.json', '').replace(/_/g, ' '),\n },\n },\n scales: {\n y: {\n min: 0,\n max: 100,\n },\n },\n },\n })\n\n await fs.promises.writeFile(fpath, buffer)\n}\n\ninterface Crop {\n w: string\n h: string\n x: string\n y: string\n}\n\ntype VmafCrop = Record<\n string,\n {\n ref?: Crop\n deg?: Crop\n }\n>\n\nconst fixCrop = (c?: Crop) => {\n return {\n w: c?.w ?? 'iw',\n h: c?.h ?? 'ih',\n x: c?.x ?? '0',\n y: c?.y ?? '0',\n }\n}\n\nconst cropFilter = (crop: Crop, exact = 0, suffix = '') => {\n const { w, h, x, y } = crop\n if (!x && !w && !x && !y) return ''\n return `crop=w=${w}:h=${h}:x=${x}:y=${y}:exact=${exact}${suffix}`\n}\n\nconst splitFilter = (outputs: string[], suffix = '') => {\n const out = outputs\n .filter(o => !!o)\n .map(o => `[${o}]`)\n .join('')\n if (!out) return ''\n return `split=${outputs.length}${out}${suffix}`\n}\n\ninterface VmafConfig {\n vmafPath: string\n vmafPreview: boolean\n vmafKeepIntermediateFiles: boolean\n vmafKeepSourceFiles: boolean\n vmafCrop?: string\n vmafSkipDuplicated?: boolean\n}\n\nexport async function calculateVmafScore(config: VmafConfig): Promise<VmafScore[]> {\n const { vmafPath, vmafPreview, vmafKeepIntermediateFiles, vmafKeepSourceFiles, vmafCrop, vmafSkipDuplicated } = config\n if (!fs.existsSync(config.vmafPath)) {\n throw new Error(`VMAF path ${config.vmafPath} does not exist`)\n }\n log.debug(`calculateVmafScore referencePath=${vmafPath}`)\n\n const { reference, degraded } = await fixIvfFiles(vmafPath, vmafKeepSourceFiles, vmafSkipDuplicated)\n\n const crop: VmafCrop | undefined = vmafCrop ? json5.parse(vmafCrop) : undefined\n\n const ret: VmafScore[] = []\n for (const participantDisplayName of reference.keys()) {\n const vmafReferencePath = reference.get(participantDisplayName)\n if (!vmafReferencePath) continue\n for (const degradedPath of degraded.get(participantDisplayName) ?? []) {\n try {\n const metrics = await runVmaf(vmafReferencePath, degradedPath, vmafPreview, crop)\n ret.push(metrics)\n } catch (err) {\n log.error(`runVmaf error: ${(err as Error).message}`)\n } finally {\n if (!vmafKeepIntermediateFiles) {\n await fs.promises.unlink(degradedPath)\n }\n }\n }\n if (!vmafKeepIntermediateFiles) {\n await fs.promises.unlink(vmafReferencePath)\n }\n }\n await fs.promises.writeFile(path.join(vmafPath, 'vmaf.json'), JSON.stringify(ret, undefined, 2))\n\n return ret\n}\n\nif (require.main === module) {\n ;(async (): Promise<void> => {\n switch (process.argv[2]) {\n case 'convert':\n await convertToIvf(process.argv[3], process.argv[4], false)\n break\n case 'parse': {\n const { frames } = await parseIvf(process.argv[3], true)\n console.log(frames)\n break\n }\n case 'fix':\n await fixIvfFrames(process.argv[3], true)\n break\n case 'analyze':\n console.log(JSON.stringify(await analyzeColors(process.argv[3]), null, 2))\n break\n case 'graph':\n await writeGraph(process.argv[3])\n break\n case 'vmaf':\n await calculateVmafScore({\n vmafPath: process.argv[3],\n vmafPreview: true,\n vmafKeepIntermediateFiles: true,\n vmafKeepSourceFiles: true,\n vmafCrop: json5.stringify({\n 'Participant-000001_recv-by_Participant-000000': {\n ref: { w: '', h: '', x: '', y: '' },\n deg: { w: '', h: '', x: '', y: '' },\n },\n }),\n })\n break\n default:\n throw new Error(`Invalid command: ${process.argv[2]}`)\n }\n })()\n .catch(err => console.error(err))\n .finally(() => process.exit(0))\n}\n"]}
|