mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-20 12:11:20 -08:00
feat: batch video upscaling with folder upload, directory save, and result comparison (#1051)
* feat: support batch video upscaling with folder upload and directory save - Add multi-file selection and entire folder upload (webkitdirectory) - Support drag & drop of both files and folders via FileSystemEntry API - Add save directory picker using File System Access API (showDirectoryPicker) - Process videos sequentially with per-file progress and status tracking - Add right-side result list with click-to-compare functionality - Add per-video duration and total batch duration display - Add retry button for failed items with error detail display - Remove auto-play on comparison viewer load - Fix worker error handling: handle "error" command to reject stale promises - Fix event listener accumulation in video comparison (AbortController) - Fix XSS risk by escaping HTML in all innerHTML injections - Fix URL revocation timing in download to prevent large file truncation - Extract writeToSaveDirectory and truncateName helpers to reduce duplication - Add Usage Guide panel explaining single/multiple/folder upload options Files changed: docs/upscaler/index.html (+1110/-181) docs/upscaler/upscaler.js (+110) * fix: prevent auto-play and resource consumption during upscaling - Set preload="metadata" on preview and comparison video elements - Explicitly pause preview video after setting src in showVideoPreview - Remove preview video seek sync from batch processing progress callbacks (was causing continuous decode during upscaling, wasting GPU resources) - Remove preview video seek sync from retry progress callback - All videos now require manual play; no background resource usage * fix: improve upscaled video quality with higher bitrate and codec support - Raise base bitrate from 2.5 Mbps (25e5) to 8 Mbps (8e6) for standard and firefox processors, preventing quality loss when source videos have high bitrates (e.g. 720p @ 16.7 Mbps was producing 1440p @ 10 Mbps, smaller than the original file) - Double the bitrate for mediabunny processor (X.n1 * 2) to account for the 4x pixel increase from 2x upscaling - Add H.264 Level 5.1 (avc1.640033) and Level 5.2 (avc1.640034) codecs to the fallback lists, since Level 4.0 (avc1.640028, ~24.6 Mbps) cannot support the higher bitrates for 1440p+ outputs - Add latencyMode: "quality" to VideoEncoder configs for both standard and firefox processors, prioritizing encoding quality over latency (suitable for offline processing) * feat: add video data comparison panel for original vs upscaled metrics - Add a comparison data table below the file info bar showing 6 metrics: Resolution, File Size, Duration, Est. Bitrate, Pixels, Process Time - Display per-metric change percentage with color-coded indicators: green (↑) for improvements, red (↓) for regressions, gray for neutral - Estimated bitrate calculated from file size × 8 / video duration - Table renders after both original and upscaled video metadata loads - Auto-hide panel on reset * fix: make video data comparison panel full-width and responsive - Move comparison data table from inside the left column to the full-width area below the left/right layout, so it is no longer constrained by the comparison viewer column width - Remove table-fixed colgroup and overflow-x-auto that caused horizontal scrolling on smaller screens - Table now uses w-full auto-layout, displaying all 4 columns (Metric, Original, Upscaled, Change) without requiring horizontal scrolling --------- Co-authored-by: rionzhao <rionzhao@tencent.com>
This commit is contained in:
1 parent
bb82f899ff
commit
40fcda6a37
3 files changed
+1290
-203
No files matched your search
@@ -1764,7 +1764,7 @@ self.onmessage = async (event) => {
|
||||
: { width: 2 * h.width, height: 2 * h.height };
|
||||
let y,
|
||||
U,
|
||||
C = (b.width * b.height * 25e5) / 921600;
|
||||
C = (b.width * b.height * 8e6) / 921600;
|
||||
const R = await E(r);
|
||||
if (t || a) {
|
||||
const e = a ? w : h;
|
||||
@@ -1836,7 +1836,7 @@ self.onmessage = async (event) => {
|
||||
});
|
||||
const z = new B.fX(D);
|
||||
let I = b.width * b.height > 921600 ? "avc1.42003e" : "avc1.42001f",
|
||||
O = ["avc1.640028", "avc1.64001e", "avc1.42003e", "avc1.42001f"];
|
||||
O = ["avc1.640033", "avc1.640028", "avc1.64001e", "avc1.640034", "avc1.42003e", "avc1.42001f"];
|
||||
"firefox" === q && (O = ["avc1.42003e", "avc1.42001f"]);
|
||||
for (const e of O) {
|
||||
const t = {
|
||||
@@ -1857,6 +1857,7 @@ self.onmessage = async (event) => {
|
||||
height: b.height,
|
||||
bitrate: Math.round(C),
|
||||
framerate: 1e6 / F[0].duration,
|
||||
latencyMode: "quality",
|
||||
},
|
||||
N = [],
|
||||
V = {},
|
||||
@@ -2147,7 +2148,7 @@ self.onmessage = async (event) => {
|
||||
: { width: 2 * d.width, height: 2 * d.height };
|
||||
let w,
|
||||
b,
|
||||
y = (g.width * g.height * 25e5) / 921600;
|
||||
y = (g.width * g.height * 8e6) / 921600;
|
||||
const k = await E(r);
|
||||
if (t || a) {
|
||||
const e = a ? v : d;
|
||||
@@ -2207,8 +2208,10 @@ self.onmessage = async (event) => {
|
||||
const L = new B.fX(F);
|
||||
let M = g.width * g.height > 921600 ? "avc1.42003e" : "avc1.42001f";
|
||||
const G = [
|
||||
"avc1.640033",
|
||||
"avc1.640028",
|
||||
"avc1.64001e",
|
||||
"avc1.640034",
|
||||
"avc1.42003e",
|
||||
"avc1.42001f",
|
||||
];
|
||||
@@ -2231,6 +2234,7 @@ self.onmessage = async (event) => {
|
||||
height: g.height,
|
||||
bitrate: Math.round(y),
|
||||
framerate: 1e6 / w.encoded_chunks[0].duration,
|
||||
latencyMode: "quality",
|
||||
},
|
||||
D = [],
|
||||
z = new VideoDecoder({
|
||||
@@ -2523,7 +2527,7 @@ self.onmessage = async (event) => {
|
||||
const B = new W.r({ format: new N.E1(), target: k }),
|
||||
E = new V.D0(f, {
|
||||
codec: "avc",
|
||||
bitrate: X.n1,
|
||||
bitrate: Math.round(X.n1 * 2),
|
||||
keyFrameInterval: 60,
|
||||
}),
|
||||
U = await w.getPrimaryVideoTrack();
|
||||
@@ -2675,7 +2679,7 @@ self.onmessage = async (event) => {
|
||||
U = performance.now();
|
||||
console.log("Time to get WebSR: " + (U - g));
|
||||
const C = new W.r({ format: new N.E1(), target: E }),
|
||||
P = new V.Dg({ codec: "avc", bitrate: X.n1, keyFrameInterval: 60 }),
|
||||
P = new V.Dg({ codec: "avc", bitrate: Math.round(X.n1 * 2), keyFrameInterval: 60 }),
|
||||
R = await y.getPrimaryVideoTrack();
|
||||
if (!R && !R)
|
||||
return postMessage({
|
||||
|
||||
Reference in new issue
Block a user