@intactfile/engines 0.1.0
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 +68 -0
- package/dist/archive/diagnose.d.ts +37 -0
- package/dist/archive/diagnose.d.ts.map +1 -0
- package/dist/archive/diagnose.js +165 -0
- package/dist/archive/diagnose.js.map +1 -0
- package/dist/archive/format.d.ts +52 -0
- package/dist/archive/format.d.ts.map +1 -0
- package/dist/archive/format.js +87 -0
- package/dist/archive/format.js.map +1 -0
- package/dist/archive/host.d.ts +83 -0
- package/dist/archive/host.d.ts.map +1 -0
- package/dist/archive/host.js +92 -0
- package/dist/archive/host.js.map +1 -0
- package/dist/archive/index.d.ts +22 -0
- package/dist/archive/index.d.ts.map +1 -0
- package/dist/archive/index.js +19 -0
- package/dist/archive/index.js.map +1 -0
- package/dist/archive/salvage.d.ts +73 -0
- package/dist/archive/salvage.d.ts.map +1 -0
- package/dist/archive/salvage.js +210 -0
- package/dist/archive/salvage.js.map +1 -0
- package/dist/byte-source.d.ts +19 -0
- package/dist/byte-source.d.ts.map +1 -0
- package/dist/byte-source.js +16 -0
- package/dist/byte-source.js.map +1 -0
- package/dist/bytesource/blob.d.ts +14 -0
- package/dist/bytesource/blob.d.ts.map +1 -0
- package/dist/bytesource/blob.js +23 -0
- package/dist/bytesource/blob.js.map +1 -0
- package/dist/crc32.d.ts +2 -0
- package/dist/crc32.d.ts.map +1 -0
- package/dist/crc32.js +18 -0
- package/dist/crc32.js.map +1 -0
- package/dist/detect/index.d.ts +16 -0
- package/dist/detect/index.d.ts.map +1 -0
- package/dist/detect/index.js +159 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/jpeg/browser-loader.d.ts +21 -0
- package/dist/jpeg/browser-loader.d.ts.map +1 -0
- package/dist/jpeg/browser-loader.js +28 -0
- package/dist/jpeg/browser-loader.js.map +1 -0
- package/dist/jpeg/diagnose.d.ts +50 -0
- package/dist/jpeg/diagnose.d.ts.map +1 -0
- package/dist/jpeg/diagnose.js +124 -0
- package/dist/jpeg/diagnose.js.map +1 -0
- package/dist/jpeg/exif.d.ts +11 -0
- package/dist/jpeg/exif.d.ts.map +1 -0
- package/dist/jpeg/exif.js +50 -0
- package/dist/jpeg/exif.js.map +1 -0
- package/dist/jpeg/format.d.ts +106 -0
- package/dist/jpeg/format.d.ts.map +1 -0
- package/dist/jpeg/format.js +248 -0
- package/dist/jpeg/format.js.map +1 -0
- package/dist/jpeg/index.d.ts +18 -0
- package/dist/jpeg/index.d.ts.map +1 -0
- package/dist/jpeg/index.js +14 -0
- package/dist/jpeg/index.js.map +1 -0
- package/dist/jpeg/mozjpeg-host.d.ts +60 -0
- package/dist/jpeg/mozjpeg-host.d.ts.map +1 -0
- package/dist/jpeg/mozjpeg-host.js +138 -0
- package/dist/jpeg/mozjpeg-host.js.map +1 -0
- package/dist/jpeg/repair.d.ts +89 -0
- package/dist/jpeg/repair.d.ts.map +1 -0
- package/dist/jpeg/repair.js +216 -0
- package/dist/jpeg/repair.js.map +1 -0
- package/dist/node.d.ts +11 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +29 -0
- package/dist/node.js.map +1 -0
- package/dist/pdf/browser-loader.d.ts +30 -0
- package/dist/pdf/browser-loader.d.ts.map +1 -0
- package/dist/pdf/browser-loader.js +21 -0
- package/dist/pdf/browser-loader.js.map +1 -0
- package/dist/pdf/diagnose.d.ts +23 -0
- package/dist/pdf/diagnose.d.ts.map +1 -0
- package/dist/pdf/diagnose.js +113 -0
- package/dist/pdf/diagnose.js.map +1 -0
- package/dist/pdf/format.d.ts +61 -0
- package/dist/pdf/format.d.ts.map +1 -0
- package/dist/pdf/format.js +150 -0
- package/dist/pdf/format.js.map +1 -0
- package/dist/pdf/index.d.ts +17 -0
- package/dist/pdf/index.d.ts.map +1 -0
- package/dist/pdf/index.js +12 -0
- package/dist/pdf/index.js.map +1 -0
- package/dist/pdf/qpdf-host.d.ts +66 -0
- package/dist/pdf/qpdf-host.d.ts.map +1 -0
- package/dist/pdf/qpdf-host.js +149 -0
- package/dist/pdf/qpdf-host.js.map +1 -0
- package/dist/pdf/rebuild.d.ts +32 -0
- package/dist/pdf/rebuild.d.ts.map +1 -0
- package/dist/pdf/rebuild.js +90 -0
- package/dist/pdf/rebuild.js.map +1 -0
- package/dist/pdf/repair.d.ts +61 -0
- package/dist/pdf/repair.d.ts.map +1 -0
- package/dist/pdf/repair.js +167 -0
- package/dist/pdf/repair.js.map +1 -0
- package/dist/png/diagnose.d.ts +50 -0
- package/dist/png/diagnose.d.ts.map +1 -0
- package/dist/png/diagnose.js +261 -0
- package/dist/png/diagnose.js.map +1 -0
- package/dist/png/format.d.ts +133 -0
- package/dist/png/format.d.ts.map +1 -0
- package/dist/png/format.js +350 -0
- package/dist/png/format.js.map +1 -0
- package/dist/png/index.d.ts +13 -0
- package/dist/png/index.d.ts.map +1 -0
- package/dist/png/index.js +10 -0
- package/dist/png/index.js.map +1 -0
- package/dist/png/repair.d.ts +31 -0
- package/dist/png/repair.d.ts.map +1 -0
- package/dist/png/repair.js +335 -0
- package/dist/png/repair.js.map +1 -0
- package/dist/sqlite/diagnose.d.ts +31 -0
- package/dist/sqlite/diagnose.d.ts.map +1 -0
- package/dist/sqlite/diagnose.js +169 -0
- package/dist/sqlite/diagnose.js.map +1 -0
- package/dist/sqlite/format.d.ts +103 -0
- package/dist/sqlite/format.d.ts.map +1 -0
- package/dist/sqlite/format.js +237 -0
- package/dist/sqlite/format.js.map +1 -0
- package/dist/sqlite/index.d.ts +24 -0
- package/dist/sqlite/index.d.ts.map +1 -0
- package/dist/sqlite/index.js +19 -0
- package/dist/sqlite/index.js.map +1 -0
- package/dist/sqlite/recover.d.ts +66 -0
- package/dist/sqlite/recover.d.ts.map +1 -0
- package/dist/sqlite/recover.js +305 -0
- package/dist/sqlite/recover.js.map +1 -0
- package/dist/sqlite/scan.d.ts +94 -0
- package/dist/sqlite/scan.d.ts.map +1 -0
- package/dist/sqlite/scan.js +356 -0
- package/dist/sqlite/scan.js.map +1 -0
- package/dist/sqlite/sqlite-host.d.ts +37 -0
- package/dist/sqlite/sqlite-host.d.ts.map +1 -0
- package/dist/sqlite/sqlite-host.js +80 -0
- package/dist/sqlite/sqlite-host.js.map +1 -0
- package/dist/sqlite/wal.d.ts +14 -0
- package/dist/sqlite/wal.d.ts.map +1 -0
- package/dist/sqlite/wal.js +79 -0
- package/dist/sqlite/wal.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/video/diagnose.d.ts +41 -0
- package/dist/video/diagnose.d.ts.map +1 -0
- package/dist/video/diagnose.js +188 -0
- package/dist/video/diagnose.js.map +1 -0
- package/dist/video/format.d.ts +87 -0
- package/dist/video/format.d.ts.map +1 -0
- package/dist/video/format.js +273 -0
- package/dist/video/format.js.map +1 -0
- package/dist/video/index.d.ts +21 -0
- package/dist/video/index.d.ts.map +1 -0
- package/dist/video/index.js +17 -0
- package/dist/video/index.js.map +1 -0
- package/dist/video/libav-host.d.ts +88 -0
- package/dist/video/libav-host.d.ts.map +1 -0
- package/dist/video/libav-host.js +66 -0
- package/dist/video/libav-host.js.map +1 -0
- package/dist/video/mp4-rebuild.d.ts +167 -0
- package/dist/video/mp4-rebuild.d.ts.map +1 -0
- package/dist/video/mp4-rebuild.js +270 -0
- package/dist/video/mp4-rebuild.js.map +1 -0
- package/dist/video/mp4box-host.d.ts +62 -0
- package/dist/video/mp4box-host.d.ts.map +1 -0
- package/dist/video/mp4box-host.js +209 -0
- package/dist/video/mp4box-host.js.map +1 -0
- package/dist/video/reconstruct.d.ts +97 -0
- package/dist/video/reconstruct.d.ts.map +1 -0
- package/dist/video/reconstruct.js +271 -0
- package/dist/video/reconstruct.js.map +1 -0
- package/dist/video/remux.d.ts +85 -0
- package/dist/video/remux.d.ts.map +1 -0
- package/dist/video/remux.js +350 -0
- package/dist/video/remux.js.map +1 -0
- package/dist/zip/diagnose.d.ts +22 -0
- package/dist/zip/diagnose.d.ts.map +1 -0
- package/dist/zip/diagnose.js +126 -0
- package/dist/zip/diagnose.js.map +1 -0
- package/dist/zip/format.d.ts +79 -0
- package/dist/zip/format.d.ts.map +1 -0
- package/dist/zip/format.js +129 -0
- package/dist/zip/format.js.map +1 -0
- package/dist/zip/repair.d.ts +32 -0
- package/dist/zip/repair.d.ts.map +1 -0
- package/dist/zip/repair.js +82 -0
- package/dist/zip/repair.js.map +1 -0
- package/dist/zip/salvage.d.ts +23 -0
- package/dist/zip/salvage.d.ts.map +1 -0
- package/dist/zip/salvage.js +140 -0
- package/dist/zip/salvage.js.map +1 -0
- package/dist/zip/scan.d.ts +64 -0
- package/dist/zip/scan.d.ts.map +1 -0
- package/dist/zip/scan.js +386 -0
- package/dist/zip/scan.js.map +1 -0
- package/dist/zip/writer.d.ts +14 -0
- package/dist/zip/writer.d.ts.map +1 -0
- package/dist/zip/writer.js +131 -0
- package/dist/zip/writer.js.map +1 -0
- package/package.json +71 -0
- package/src/archive/LICENSE-unrar.txt +53 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Video container diagnosis via pure own parsing — no wasm anywhere in this
|
|
3
|
+
* import chain, so it is safe in the browser-facing root export.
|
|
4
|
+
*
|
|
5
|
+
* MP4/MOV: top-level box walk (ftyp/moov/mdat presence, order, sizes, 64-bit
|
|
6
|
+
* largesize, junk between boxes) plus a moov-integrity child walk.
|
|
7
|
+
* MKV/WebM: EBML header + lightweight scan for Tracks/Cluster/Cues.
|
|
8
|
+
* AVI: RIFF structure + idx1 presence.
|
|
9
|
+
*
|
|
10
|
+
* Honesty rules (docs/03 §4): a file that was never finalized (no moov) is
|
|
11
|
+
* NOT repairable by a stream-copy remux, and the diagnosis says so before any
|
|
12
|
+
* repair is attempted.
|
|
13
|
+
*/
|
|
14
|
+
import type { ByteSource } from '../byte-source.js';
|
|
15
|
+
import type { Confidence } from '../types.js';
|
|
16
|
+
export type VideoContainer = 'mp4' | 'mov' | 'mkv' | 'webm' | 'avi' | 'unknown';
|
|
17
|
+
export type VideoDamageClass = 'none' | 'missing-moov' | 'broken-index' | 'truncated-mdat' | 'garbage-prefix' | 'missing-cues' | 'missing-index' | 'not-video' | 'unknown';
|
|
18
|
+
export interface VideoBoxInfo {
|
|
19
|
+
type: string;
|
|
20
|
+
offset: number;
|
|
21
|
+
size: number;
|
|
22
|
+
largesize: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface VideoDiagnosis {
|
|
25
|
+
container: VideoContainer;
|
|
26
|
+
damageClass: VideoDamageClass;
|
|
27
|
+
confidence: Confidence;
|
|
28
|
+
notes: string[];
|
|
29
|
+
/**
|
|
30
|
+
* Whether a stream-copy remux can plausibly help. 'missing-moov' is
|
|
31
|
+
* honestly false: rebuilding the index needs moov reconstruction, which is
|
|
32
|
+
* a different (future) engine.
|
|
33
|
+
*/
|
|
34
|
+
remuxRepairable: boolean;
|
|
35
|
+
/** Offset of the real container data; > 0 means a garbage prefix to strip. */
|
|
36
|
+
dataOffset: number;
|
|
37
|
+
/** MP4/MOV top-level boxes that parsed (empty for other containers). */
|
|
38
|
+
boxes: VideoBoxInfo[];
|
|
39
|
+
}
|
|
40
|
+
export declare function diagnoseVideo(src: ByteSource): Promise<VideoDiagnosis>;
|
|
41
|
+
//# sourceMappingURL=diagnose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../../src/video/diagnose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAc9C,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AAEhF,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,cAAc,GACd,cAAc,GACd,gBAAgB,GAChB,gBAAgB,GAChB,cAAc,GACd,eAAe,GACf,WAAW,GACX,SAAS,CAAC;AAEd,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,cAAc,CAAC;IAC1B,WAAW,EAAE,gBAAgB,CAAC;IAC9B,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAID,wBAAsB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAqE5E"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { EBML_MAGIC, checkMoovIntegrity, findEbmlResync, findMp4Resync, findRiffResync, fourcc, latin1, scanAvi, scanMkv, scanMp4Boxes, } from './format.js';
|
|
2
|
+
const MP4_START_TYPES = new Set(['ftyp', 'moov', 'mdat', 'free', 'skip', 'wide', 'styp']);
|
|
3
|
+
export async function diagnoseVideo(src) {
|
|
4
|
+
const notes = [];
|
|
5
|
+
const base = {
|
|
6
|
+
notes,
|
|
7
|
+
dataOffset: 0,
|
|
8
|
+
boxes: [],
|
|
9
|
+
};
|
|
10
|
+
const done = (container, damageClass, confidence, remuxRepairable) => ({ container, damageClass, confidence, remuxRepairable, ...base });
|
|
11
|
+
if (src.size < 12) {
|
|
12
|
+
notes.push('file too small to be a video container');
|
|
13
|
+
return done('unknown', 'not-video', 'high', false);
|
|
14
|
+
}
|
|
15
|
+
const head = await src.read(0, 16);
|
|
16
|
+
// --- Matroska / WebM ---
|
|
17
|
+
if (head[0] === EBML_MAGIC[0] && head[1] === EBML_MAGIC[1] && head[2] === EBML_MAGIC[2] && head[3] === EBML_MAGIC[3]) {
|
|
18
|
+
return diagnoseMkv(src, 0, base, done);
|
|
19
|
+
}
|
|
20
|
+
// --- AVI ---
|
|
21
|
+
if (fourcc(head, 0) === 'RIFF') {
|
|
22
|
+
return diagnoseAvi(src, 0, base, done);
|
|
23
|
+
}
|
|
24
|
+
// --- MP4 / MOV ---
|
|
25
|
+
const firstType = fourcc(head, 4);
|
|
26
|
+
if (MP4_START_TYPES.has(firstType)) {
|
|
27
|
+
const container = sniffMp4Family(head, firstType);
|
|
28
|
+
return diagnoseMp4(src, 0, container, base, done);
|
|
29
|
+
}
|
|
30
|
+
// Nothing recognizable at offset 0: look for a signature behind a prefix.
|
|
31
|
+
const mp4At = await findMp4Resync(src);
|
|
32
|
+
if (mp4At > 0) {
|
|
33
|
+
base.dataOffset = mp4At;
|
|
34
|
+
notes.push(`MP4/MOV box structure found at offset ${mp4At} (garbage prefix)`);
|
|
35
|
+
const inner = await diagnoseMp4(src, mp4At, 'mp4', base, done);
|
|
36
|
+
if (inner.damageClass === 'not-video')
|
|
37
|
+
return inner;
|
|
38
|
+
// The prefix is the primary damage; keep the deeper findings as notes.
|
|
39
|
+
if (inner.damageClass !== 'none') {
|
|
40
|
+
notes.push(`after the prefix, the container also diagnoses as: ${inner.damageClass}`);
|
|
41
|
+
return done('mp4', 'garbage-prefix', 'medium', inner.remuxRepairable);
|
|
42
|
+
}
|
|
43
|
+
return done(inner.container, 'garbage-prefix', 'high', true);
|
|
44
|
+
}
|
|
45
|
+
const ebmlAt = await findEbmlResync(src);
|
|
46
|
+
if (ebmlAt > 0) {
|
|
47
|
+
base.dataOffset = ebmlAt;
|
|
48
|
+
notes.push(`EBML header found at offset ${ebmlAt} (garbage prefix)`);
|
|
49
|
+
const inner = await diagnoseMkv(src, ebmlAt, base, done);
|
|
50
|
+
return done(inner.container, 'garbage-prefix', inner.damageClass === 'none' ? 'high' : 'medium', inner.remuxRepairable);
|
|
51
|
+
}
|
|
52
|
+
const riffAt = await findRiffResync(src);
|
|
53
|
+
if (riffAt > 0) {
|
|
54
|
+
base.dataOffset = riffAt;
|
|
55
|
+
notes.push(`RIFF/AVI header found at offset ${riffAt} (garbage prefix)`);
|
|
56
|
+
const inner = await diagnoseAvi(src, riffAt, base, done);
|
|
57
|
+
return done(inner.container, 'garbage-prefix', inner.damageClass === 'none' ? 'high' : 'medium', inner.remuxRepairable);
|
|
58
|
+
}
|
|
59
|
+
notes.push('no MP4/MOV, Matroska/WebM or AVI signature found');
|
|
60
|
+
return done('unknown', 'not-video', src.size > 64 * 1024 ? 'medium' : 'high', false);
|
|
61
|
+
}
|
|
62
|
+
function sniffMp4Family(head, firstType) {
|
|
63
|
+
if (firstType === 'ftyp') {
|
|
64
|
+
const brand = latin1(head.subarray(8, 12));
|
|
65
|
+
return brand.startsWith('qt') ? 'mov' : 'mp4';
|
|
66
|
+
}
|
|
67
|
+
// Old MOV files may start with moov/mdat/wide/free directly.
|
|
68
|
+
return 'mov';
|
|
69
|
+
}
|
|
70
|
+
async function diagnoseMp4(src, start, container, base, done) {
|
|
71
|
+
const notes = base.notes;
|
|
72
|
+
const scan = await scanMp4Boxes(src, start);
|
|
73
|
+
base.boxes = scan.boxes.map((b) => ({ type: b.type, offset: b.offset, size: b.size, largesize: b.largesize }));
|
|
74
|
+
if (scan.boxes.length === 0) {
|
|
75
|
+
notes.push('no parsable MP4/MOV boxes');
|
|
76
|
+
return done(container, 'not-video', 'medium', false);
|
|
77
|
+
}
|
|
78
|
+
for (const b of scan.boxes) {
|
|
79
|
+
if (b.largesize)
|
|
80
|
+
notes.push(`box "${b.type}" uses a 64-bit largesize (${b.size} bytes)`);
|
|
81
|
+
}
|
|
82
|
+
if (scan.junkSkipped) {
|
|
83
|
+
notes.push(`unreadable bytes at offset ${scan.unparsableAtOffset}; resynced on a later box`);
|
|
84
|
+
}
|
|
85
|
+
// No moov anywhere: the file was never finalized (or its index was
|
|
86
|
+
// destroyed in place). A stream copy has nothing to copy from.
|
|
87
|
+
if (!scan.hasMoov) {
|
|
88
|
+
if (scan.hasMdat) {
|
|
89
|
+
notes.push('no moov box: the file was never finalized (or the index was overwritten). ' +
|
|
90
|
+
'Stream-copy remux cannot repair this; it needs moov reconstruction from the raw mdat ' +
|
|
91
|
+
'(a future, separate repair engine).');
|
|
92
|
+
const cutInMdat = scan.truncatedBox?.type === 'mdat';
|
|
93
|
+
if (cutInMdat)
|
|
94
|
+
notes.push('mdat is also cut short — consistent with an interrupted recording');
|
|
95
|
+
return done(container, 'missing-moov', 'high', false);
|
|
96
|
+
}
|
|
97
|
+
notes.push('neither moov nor mdat found');
|
|
98
|
+
return done(container, scan.hasFtyp ? 'missing-moov' : 'not-video', scan.hasFtyp ? 'medium' : 'medium', false);
|
|
99
|
+
}
|
|
100
|
+
const moov = scan.boxes.find((b) => b.type === 'moov');
|
|
101
|
+
// moov truncated: the declared size runs past the end of the file.
|
|
102
|
+
if (scan.truncatedBox?.type === 'moov') {
|
|
103
|
+
notes.push(`moov declares ${moov.size} bytes but the file ends at ${src.size} — index truncated or size field corrupt`);
|
|
104
|
+
return done(container, 'broken-index', 'high', true);
|
|
105
|
+
}
|
|
106
|
+
// moov fully inside the file: check internal consistency.
|
|
107
|
+
const integrity = await checkMoovIntegrity(src, moov);
|
|
108
|
+
if (!integrity.consistent) {
|
|
109
|
+
notes.push(`moov is present but inconsistent: ${integrity.problem}`);
|
|
110
|
+
return done(container, 'broken-index', 'high', true);
|
|
111
|
+
}
|
|
112
|
+
if (scan.truncatedBox !== null) {
|
|
113
|
+
// Some non-moov box (almost always mdat) is cut short.
|
|
114
|
+
notes.push(`"${scan.truncatedBox.type}" declares ${scan.truncatedBox.size} bytes at offset ${scan.truncatedBox.offset} ` +
|
|
115
|
+
`but the file ends at ${src.size}: media data is truncated`);
|
|
116
|
+
notes.push('a remux can salvage the frames before the cut; frames past it are physically gone');
|
|
117
|
+
return done(container, 'truncated-mdat', 'high', true);
|
|
118
|
+
}
|
|
119
|
+
if (!scan.hasMdat) {
|
|
120
|
+
notes.push('moov parses but no mdat box was found: media data is missing entirely');
|
|
121
|
+
return done(container, 'truncated-mdat', 'medium', true);
|
|
122
|
+
}
|
|
123
|
+
if (scan.junkSkipped) {
|
|
124
|
+
notes.push('moov and mdat both parse; the junk between boxes will be dropped by a remux');
|
|
125
|
+
return done(container, 'none', 'medium', true);
|
|
126
|
+
}
|
|
127
|
+
if (scan.moovAfterMdat) {
|
|
128
|
+
notes.push('moov is after mdat (not faststart): valid, but a remux will move the index to the front');
|
|
129
|
+
}
|
|
130
|
+
return done(container, 'none', 'high', true);
|
|
131
|
+
}
|
|
132
|
+
async function diagnoseMkv(src, start, base, done) {
|
|
133
|
+
const notes = base.notes;
|
|
134
|
+
const scan = await scanMkv(src, start);
|
|
135
|
+
if (!scan.hasEbmlHeader) {
|
|
136
|
+
notes.push('EBML magic not found where expected');
|
|
137
|
+
return done('unknown', 'not-video', 'medium', false);
|
|
138
|
+
}
|
|
139
|
+
const container = scan.docType === 'webm' ? 'webm' : 'mkv';
|
|
140
|
+
if (scan.docType === null)
|
|
141
|
+
notes.push('EBML DocType not readable in the header window');
|
|
142
|
+
if (!scan.hasSegment) {
|
|
143
|
+
notes.push('no Segment element: the file ends right after the EBML header');
|
|
144
|
+
return done(container, 'truncated-mdat', 'medium', false);
|
|
145
|
+
}
|
|
146
|
+
if (!scan.hasTracks) {
|
|
147
|
+
notes.push('no Tracks element found: track metadata is missing or destroyed');
|
|
148
|
+
return done(container, 'broken-index', 'medium', false);
|
|
149
|
+
}
|
|
150
|
+
if (!scan.hasCluster) {
|
|
151
|
+
notes.push('Tracks present but no Cluster found: media data is missing or cut before the first cluster');
|
|
152
|
+
return done(container, 'truncated-mdat', 'medium', true);
|
|
153
|
+
}
|
|
154
|
+
if (!scan.hasCues) {
|
|
155
|
+
notes.push('no Cues (seek index) found: playable but not seekable; a remux rebuilds the index');
|
|
156
|
+
return done(container, 'missing-cues', 'high', true);
|
|
157
|
+
}
|
|
158
|
+
return done(container, 'none', 'high', true);
|
|
159
|
+
}
|
|
160
|
+
async function diagnoseAvi(src, start, base, done) {
|
|
161
|
+
const notes = base.notes;
|
|
162
|
+
const scan = await scanAvi(src, start);
|
|
163
|
+
if (!scan.isAvi) {
|
|
164
|
+
notes.push('RIFF container but not AVI (could be WAV or another RIFF format)');
|
|
165
|
+
return done('unknown', 'not-video', 'high', false);
|
|
166
|
+
}
|
|
167
|
+
if (!scan.hasHdrl) {
|
|
168
|
+
notes.push('no hdrl header list: AVI stream metadata is missing');
|
|
169
|
+
return done('avi', 'broken-index', 'medium', false);
|
|
170
|
+
}
|
|
171
|
+
if (!scan.hasMovi) {
|
|
172
|
+
notes.push('no movi list: media data is missing');
|
|
173
|
+
return done('avi', 'truncated-mdat', 'medium', false);
|
|
174
|
+
}
|
|
175
|
+
const available = src.size - start;
|
|
176
|
+
if (scan.declaredSize !== null && scan.declaredSize > available + 8) {
|
|
177
|
+
notes.push(`RIFF declares ${scan.declaredSize} bytes but only ${available} are present: truncated`);
|
|
178
|
+
if (!scan.hasIdx1)
|
|
179
|
+
notes.push('idx1 index is also missing (it sits at the end of the file)');
|
|
180
|
+
return done('avi', 'truncated-mdat', 'high', true);
|
|
181
|
+
}
|
|
182
|
+
if (!scan.hasIdx1) {
|
|
183
|
+
notes.push('no idx1 index chunk: seeking is broken; a remux with ignore-index semantics rebuilds it');
|
|
184
|
+
return done('avi', 'missing-index', 'high', true);
|
|
185
|
+
}
|
|
186
|
+
return done('avi', 'none', 'high', true);
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=diagnose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../../src/video/diagnose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure container-structure parsing for the video engines: MP4/MOV top-level
|
|
3
|
+
* box walk, lightweight Matroska/WebM EBML probing, and AVI RIFF probing.
|
|
4
|
+
* Everything reads through ByteSource in bounded chunks — RAM stays flat with
|
|
5
|
+
* respect to file size and no wasm is involved.
|
|
6
|
+
*/
|
|
7
|
+
import type { ByteSource } from '../byte-source.js';
|
|
8
|
+
/** How far into the file we look for a real signature behind a garbage prefix. */
|
|
9
|
+
export declare const VIDEO_PREFIX_SCAN_WINDOW: number;
|
|
10
|
+
export declare function fourcc(bytes: Uint8Array, offset: number): string;
|
|
11
|
+
export declare function readU32(bytes: Uint8Array, offset: number): number;
|
|
12
|
+
export declare function readU32le(bytes: Uint8Array, offset: number): number;
|
|
13
|
+
export declare function readU64(bytes: Uint8Array, offset: number): number;
|
|
14
|
+
export interface Mp4Box {
|
|
15
|
+
type: string;
|
|
16
|
+
offset: number;
|
|
17
|
+
/** Declared size in bytes (header included). */
|
|
18
|
+
size: number;
|
|
19
|
+
/** True when the size came from a 64-bit largesize field. */
|
|
20
|
+
largesize: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface Mp4Scan {
|
|
23
|
+
boxes: Mp4Box[];
|
|
24
|
+
hasFtyp: boolean;
|
|
25
|
+
hasMoov: boolean;
|
|
26
|
+
hasMdat: boolean;
|
|
27
|
+
/** Box whose declared size runs past the end of the file, if any. */
|
|
28
|
+
truncatedBox: Mp4Box | null;
|
|
29
|
+
/** First offset where a box header should be but is unparsable, if any. */
|
|
30
|
+
unparsableAtOffset: number | null;
|
|
31
|
+
/** True when unparsable bytes were skipped and the walk resynced on a later box. */
|
|
32
|
+
junkSkipped: boolean;
|
|
33
|
+
/** moov appears after mdat (valid, but not streamable/faststart). */
|
|
34
|
+
moovAfterMdat: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Walk top-level MP4/MOV boxes from `start`. On unparsable data the walk
|
|
38
|
+
* records the offset and scans forward (bounded) for a known top-level box to
|
|
39
|
+
* resync on, so a zeroed/overwritten region does not hide the boxes behind it.
|
|
40
|
+
*/
|
|
41
|
+
export declare function scanMp4Boxes(src: ByteSource, start?: number): Promise<Mp4Scan>;
|
|
42
|
+
/**
|
|
43
|
+
* Walk the children of a moov box and report whether the index looks
|
|
44
|
+
* internally consistent (child boxes parse, at least one trak, an mvhd).
|
|
45
|
+
* The moov must be fully inside the file.
|
|
46
|
+
*/
|
|
47
|
+
export declare function checkMoovIntegrity(src: ByteSource, moov: Mp4Box): Promise<{
|
|
48
|
+
consistent: boolean;
|
|
49
|
+
hasTrak: boolean;
|
|
50
|
+
hasMvhd: boolean;
|
|
51
|
+
problem: string | null;
|
|
52
|
+
}>;
|
|
53
|
+
/** Search a window for an MP4 box signature preceded by junk (garbage prefix). */
|
|
54
|
+
export declare function findMp4Resync(src: ByteSource): Promise<number>;
|
|
55
|
+
export declare const EBML_MAGIC: Uint8Array<ArrayBuffer>;
|
|
56
|
+
export interface MkvScan {
|
|
57
|
+
hasEbmlHeader: boolean;
|
|
58
|
+
docType: 'matroska' | 'webm' | null;
|
|
59
|
+
hasSegment: boolean;
|
|
60
|
+
hasTracks: boolean;
|
|
61
|
+
hasCluster: boolean;
|
|
62
|
+
hasCues: boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Lightweight Matroska probe: EBML magic + byte scan for the Segment, Tracks,
|
|
66
|
+
* Cluster and Cues element IDs. Deliberately not a full EBML parse — payload
|
|
67
|
+
* bytes can in principle alias an ID, which is acceptable for a diagnosis
|
|
68
|
+
* that the remux engine then verifies for real.
|
|
69
|
+
*/
|
|
70
|
+
export declare function scanMkv(src: ByteSource, start?: number): Promise<MkvScan>;
|
|
71
|
+
/** Find the EBML magic at offset > 0 (garbage prefix detection). */
|
|
72
|
+
export declare function findEbmlResync(src: ByteSource): Promise<number>;
|
|
73
|
+
/** Find a RIFF/AVI signature at offset > 0 (garbage prefix detection). */
|
|
74
|
+
export declare function findRiffResync(src: ByteSource): Promise<number>;
|
|
75
|
+
export interface AviScan {
|
|
76
|
+
isRiff: boolean;
|
|
77
|
+
isAvi: boolean;
|
|
78
|
+
/** RIFF-declared total size (payload + 8), or null when unreadable. */
|
|
79
|
+
declaredSize: number | null;
|
|
80
|
+
hasHdrl: boolean;
|
|
81
|
+
hasMovi: boolean;
|
|
82
|
+
hasIdx1: boolean;
|
|
83
|
+
}
|
|
84
|
+
/** Lightweight AVI probe: RIFF/AVI header plus a scan for hdrl/movi/idx1. */
|
|
85
|
+
export declare function scanAvi(src: ByteSource, start?: number): Promise<AviScan>;
|
|
86
|
+
export declare function latin1(bytes: Uint8Array): string;
|
|
87
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/video/format.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAKpD,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,QAAa,CAAC;AAKnD,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAIhE;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGjE;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,qEAAqE;IACrE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,2EAA2E;IAC3E,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,oFAAoF;IACpF,WAAW,EAAE,OAAO,CAAC;IACrB,qEAAqE;IACrE,aAAa,EAAE,OAAO,CAAC;CACxB;AA4BD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,SAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAgD/E;AAqBD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CA0B9F;AAED,kFAAkF;AAClF,wBAAsB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpE;AAMD,eAAO,MAAM,UAAU,yBAA2C,CAAC;AAMnE,MAAM,WAAW,OAAO;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB;AAYD;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,SAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CA4B1E;AAED,oEAAoE;AACpE,wBAAsB,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAIrE;AAED,0EAA0E;AAC1E,wBAAsB,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAUrE;AAMD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,uEAAuE;IACvE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,6EAA6E;AAC7E,wBAAsB,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,SAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAoB1E;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAOhD"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/** Printable-ASCII fourcc — anything else is not a box/chunk type. */
|
|
2
|
+
const FOURCC_RE = /^[\x20-\x7e]{4}$/;
|
|
3
|
+
/** How far into the file we look for a real signature behind a garbage prefix. */
|
|
4
|
+
export const VIDEO_PREFIX_SCAN_WINDOW = 256 * 1024;
|
|
5
|
+
/** Top-level box types that mark a plausible MP4/MOV resync point. */
|
|
6
|
+
const MP4_RESYNC_TYPES = new Set(['ftyp', 'moov', 'mdat', 'free', 'skip', 'wide', 'uuid', 'moof', 'mfra', 'meta', 'styp', 'sidx']);
|
|
7
|
+
export function fourcc(bytes, offset) {
|
|
8
|
+
let out = '';
|
|
9
|
+
for (let i = 0; i < 4; i += 1)
|
|
10
|
+
out += String.fromCharCode(bytes[offset + i]);
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
13
|
+
export function readU32(bytes, offset) {
|
|
14
|
+
return ((bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]) >>> 0;
|
|
15
|
+
}
|
|
16
|
+
export function readU32le(bytes, offset) {
|
|
17
|
+
return (bytes[offset] | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24)) >>> 0;
|
|
18
|
+
}
|
|
19
|
+
export function readU64(bytes, offset) {
|
|
20
|
+
// Box sizes fit in a JS double for any realistic file (< 2^53).
|
|
21
|
+
return readU32(bytes, offset) * 0x1_0000_0000 + readU32(bytes, offset + 4);
|
|
22
|
+
}
|
|
23
|
+
/** True when a 16-byte window at `offset` looks like a top-level MP4 box header. */
|
|
24
|
+
function parseBoxHeader(header, offset, fileSize) {
|
|
25
|
+
if (header.length < 8)
|
|
26
|
+
return null;
|
|
27
|
+
const size32 = readU32(header, 0);
|
|
28
|
+
const type = fourcc(header, 4);
|
|
29
|
+
if (!FOURCC_RE.test(type))
|
|
30
|
+
return null;
|
|
31
|
+
let size;
|
|
32
|
+
let largesize = false;
|
|
33
|
+
if (size32 === 0) {
|
|
34
|
+
size = fileSize - offset; // extends to end of file
|
|
35
|
+
}
|
|
36
|
+
else if (size32 === 1) {
|
|
37
|
+
if (header.length < 16)
|
|
38
|
+
return null;
|
|
39
|
+
size = readU64(header, 8);
|
|
40
|
+
largesize = true;
|
|
41
|
+
if (size < 16)
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
size = size32;
|
|
46
|
+
}
|
|
47
|
+
if (size < 8)
|
|
48
|
+
return null;
|
|
49
|
+
return { type, size, largesize };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Walk top-level MP4/MOV boxes from `start`. On unparsable data the walk
|
|
53
|
+
* records the offset and scans forward (bounded) for a known top-level box to
|
|
54
|
+
* resync on, so a zeroed/overwritten region does not hide the boxes behind it.
|
|
55
|
+
*/
|
|
56
|
+
export async function scanMp4Boxes(src, start = 0) {
|
|
57
|
+
const scan = {
|
|
58
|
+
boxes: [],
|
|
59
|
+
hasFtyp: false,
|
|
60
|
+
hasMoov: false,
|
|
61
|
+
hasMdat: false,
|
|
62
|
+
truncatedBox: null,
|
|
63
|
+
unparsableAtOffset: null,
|
|
64
|
+
junkSkipped: false,
|
|
65
|
+
moovAfterMdat: false,
|
|
66
|
+
};
|
|
67
|
+
const fileSize = src.size;
|
|
68
|
+
let offset = start;
|
|
69
|
+
let sawMdat = false;
|
|
70
|
+
while (offset + 8 <= fileSize) {
|
|
71
|
+
const header = await src.read(offset, 16);
|
|
72
|
+
const parsed = parseBoxHeader(header, offset, fileSize);
|
|
73
|
+
if (parsed === null) {
|
|
74
|
+
if (scan.unparsableAtOffset === null)
|
|
75
|
+
scan.unparsableAtOffset = offset;
|
|
76
|
+
const resync = await findNextBox(src, offset + 1, fileSize);
|
|
77
|
+
if (resync === -1)
|
|
78
|
+
break;
|
|
79
|
+
scan.junkSkipped = true;
|
|
80
|
+
offset = resync;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const box = { type: parsed.type, offset, size: parsed.size, largesize: parsed.largesize };
|
|
84
|
+
scan.boxes.push(box);
|
|
85
|
+
if (parsed.type === 'ftyp')
|
|
86
|
+
scan.hasFtyp = true;
|
|
87
|
+
if (parsed.type === 'mdat') {
|
|
88
|
+
scan.hasMdat = true;
|
|
89
|
+
sawMdat = true;
|
|
90
|
+
}
|
|
91
|
+
if (parsed.type === 'moov') {
|
|
92
|
+
scan.hasMoov = true;
|
|
93
|
+
if (sawMdat)
|
|
94
|
+
scan.moovAfterMdat = true;
|
|
95
|
+
}
|
|
96
|
+
if (offset + parsed.size > fileSize) {
|
|
97
|
+
scan.truncatedBox = box;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
offset += parsed.size;
|
|
101
|
+
}
|
|
102
|
+
return scan;
|
|
103
|
+
}
|
|
104
|
+
/** Bounded forward scan for the next plausible top-level box header. */
|
|
105
|
+
async function findNextBox(src, from, fileSize) {
|
|
106
|
+
const limit = Math.min(fileSize, from + VIDEO_PREFIX_SCAN_WINDOW);
|
|
107
|
+
const CHUNK = 64 * 1024;
|
|
108
|
+
let base = from;
|
|
109
|
+
while (base < limit) {
|
|
110
|
+
const chunk = await src.read(base, Math.min(CHUNK + 16, limit - base + 16));
|
|
111
|
+
for (let i = 0; i + 8 <= chunk.length && base + i < limit; i += 1) {
|
|
112
|
+
const type = fourcc(chunk, i + 4);
|
|
113
|
+
if (!MP4_RESYNC_TYPES.has(type))
|
|
114
|
+
continue;
|
|
115
|
+
const header = chunk.subarray(i, i + 16);
|
|
116
|
+
const parsed = parseBoxHeader(header.length >= 16 ? header : await src.read(base + i, 16), base + i, fileSize);
|
|
117
|
+
if (parsed !== null && parsed.type === type)
|
|
118
|
+
return base + i;
|
|
119
|
+
}
|
|
120
|
+
base += CHUNK;
|
|
121
|
+
}
|
|
122
|
+
return -1;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Walk the children of a moov box and report whether the index looks
|
|
126
|
+
* internally consistent (child boxes parse, at least one trak, an mvhd).
|
|
127
|
+
* The moov must be fully inside the file.
|
|
128
|
+
*/
|
|
129
|
+
export async function checkMoovIntegrity(src, moov) {
|
|
130
|
+
const headerSize = moov.largesize ? 16 : 8;
|
|
131
|
+
const end = moov.offset + moov.size;
|
|
132
|
+
let offset = moov.offset + headerSize;
|
|
133
|
+
let hasTrak = false;
|
|
134
|
+
let hasMvhd = false;
|
|
135
|
+
let problem = null;
|
|
136
|
+
while (offset + 8 <= end) {
|
|
137
|
+
const header = await src.read(offset, 16);
|
|
138
|
+
const parsed = parseBoxHeader(header, offset, src.size);
|
|
139
|
+
if (parsed === null) {
|
|
140
|
+
problem = `unparsable child box inside moov at offset ${offset}`;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
if (offset + parsed.size > end) {
|
|
144
|
+
problem = `moov child "${parsed.type}" overflows the moov box`;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
if (parsed.type === 'trak')
|
|
148
|
+
hasTrak = true;
|
|
149
|
+
if (parsed.type === 'mvhd')
|
|
150
|
+
hasMvhd = true;
|
|
151
|
+
offset += parsed.size;
|
|
152
|
+
}
|
|
153
|
+
if (problem === null && !hasTrak)
|
|
154
|
+
problem = 'moov contains no trak (no track index)';
|
|
155
|
+
return { consistent: problem === null && hasTrak, hasTrak, hasMvhd, problem };
|
|
156
|
+
}
|
|
157
|
+
/** Search a window for an MP4 box signature preceded by junk (garbage prefix). */
|
|
158
|
+
export async function findMp4Resync(src) {
|
|
159
|
+
return findNextBox(src, 1, src.size);
|
|
160
|
+
}
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
// Matroska / WebM
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
export const EBML_MAGIC = new Uint8Array([0x1a, 0x45, 0xdf, 0xa3]);
|
|
165
|
+
const ID_SEGMENT = [0x18, 0x53, 0x80, 0x67];
|
|
166
|
+
const ID_TRACKS = [0x16, 0x54, 0xae, 0x6b];
|
|
167
|
+
const ID_CLUSTER = [0x1f, 0x43, 0xb6, 0x75];
|
|
168
|
+
const ID_CUES = [0x1c, 0x53, 0xbb, 0x6b];
|
|
169
|
+
function indexOfSeq(haystack, needle, from = 0) {
|
|
170
|
+
outer: for (let i = from; i + needle.length <= haystack.length; i += 1) {
|
|
171
|
+
for (let j = 0; j < needle.length; j += 1) {
|
|
172
|
+
if (haystack[i + j] !== needle[j])
|
|
173
|
+
continue outer;
|
|
174
|
+
}
|
|
175
|
+
return i;
|
|
176
|
+
}
|
|
177
|
+
return -1;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Lightweight Matroska probe: EBML magic + byte scan for the Segment, Tracks,
|
|
181
|
+
* Cluster and Cues element IDs. Deliberately not a full EBML parse — payload
|
|
182
|
+
* bytes can in principle alias an ID, which is acceptable for a diagnosis
|
|
183
|
+
* that the remux engine then verifies for real.
|
|
184
|
+
*/
|
|
185
|
+
export async function scanMkv(src, start = 0) {
|
|
186
|
+
const scan = {
|
|
187
|
+
hasEbmlHeader: false,
|
|
188
|
+
docType: null,
|
|
189
|
+
hasSegment: false,
|
|
190
|
+
hasTracks: false,
|
|
191
|
+
hasCluster: false,
|
|
192
|
+
hasCues: false,
|
|
193
|
+
};
|
|
194
|
+
const head = await src.read(start, Math.min(4096, src.size - start));
|
|
195
|
+
if (indexOfSeq(head, [...EBML_MAGIC]) !== 0)
|
|
196
|
+
return scan;
|
|
197
|
+
scan.hasEbmlHeader = true;
|
|
198
|
+
const headText = latin1(head.subarray(0, 128));
|
|
199
|
+
if (headText.includes('webm'))
|
|
200
|
+
scan.docType = 'webm';
|
|
201
|
+
else if (headText.includes('matroska'))
|
|
202
|
+
scan.docType = 'matroska';
|
|
203
|
+
const CHUNK = 256 * 1024;
|
|
204
|
+
let offset = start;
|
|
205
|
+
while (offset < src.size && !(scan.hasSegment && scan.hasTracks && scan.hasCluster && scan.hasCues)) {
|
|
206
|
+
const chunk = await src.read(offset, Math.min(CHUNK + 4, src.size - offset));
|
|
207
|
+
if (!scan.hasSegment && indexOfSeq(chunk, ID_SEGMENT) !== -1)
|
|
208
|
+
scan.hasSegment = true;
|
|
209
|
+
if (!scan.hasTracks && indexOfSeq(chunk, ID_TRACKS) !== -1)
|
|
210
|
+
scan.hasTracks = true;
|
|
211
|
+
if (!scan.hasCluster && indexOfSeq(chunk, ID_CLUSTER) !== -1)
|
|
212
|
+
scan.hasCluster = true;
|
|
213
|
+
if (!scan.hasCues && indexOfSeq(chunk, ID_CUES) !== -1)
|
|
214
|
+
scan.hasCues = true;
|
|
215
|
+
offset += CHUNK;
|
|
216
|
+
}
|
|
217
|
+
return scan;
|
|
218
|
+
}
|
|
219
|
+
/** Find the EBML magic at offset > 0 (garbage prefix detection). */
|
|
220
|
+
export async function findEbmlResync(src) {
|
|
221
|
+
const window = await src.read(1, Math.min(VIDEO_PREFIX_SCAN_WINDOW, src.size - 1));
|
|
222
|
+
const at = indexOfSeq(window, [...EBML_MAGIC]);
|
|
223
|
+
return at === -1 ? -1 : at + 1;
|
|
224
|
+
}
|
|
225
|
+
/** Find a RIFF/AVI signature at offset > 0 (garbage prefix detection). */
|
|
226
|
+
export async function findRiffResync(src) {
|
|
227
|
+
const window = await src.read(1, Math.min(VIDEO_PREFIX_SCAN_WINDOW, src.size - 1));
|
|
228
|
+
const riff = [0x52, 0x49, 0x46, 0x46]; // 'RIFF'
|
|
229
|
+
let from = 0;
|
|
230
|
+
for (;;) {
|
|
231
|
+
const at = indexOfSeq(window, riff, from);
|
|
232
|
+
if (at === -1)
|
|
233
|
+
return -1;
|
|
234
|
+
if (at + 12 <= window.length && latin1(window.subarray(at + 8, at + 12)) === 'AVI ')
|
|
235
|
+
return at + 1;
|
|
236
|
+
from = at + 1;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/** Lightweight AVI probe: RIFF/AVI header plus a scan for hdrl/movi/idx1. */
|
|
240
|
+
export async function scanAvi(src, start = 0) {
|
|
241
|
+
const scan = { isRiff: false, isAvi: false, declaredSize: null, hasHdrl: false, hasMovi: false, hasIdx1: false };
|
|
242
|
+
const head = await src.read(start, Math.min(64, src.size - start));
|
|
243
|
+
if (head.length < 12 || fourcc(head, 0) !== 'RIFF')
|
|
244
|
+
return scan;
|
|
245
|
+
scan.isRiff = true;
|
|
246
|
+
scan.declaredSize = readU32le(head, 4) + 8;
|
|
247
|
+
if (fourcc(head, 8) !== 'AVI ')
|
|
248
|
+
return scan;
|
|
249
|
+
scan.isAvi = true;
|
|
250
|
+
const CHUNK = 256 * 1024;
|
|
251
|
+
let offset = start;
|
|
252
|
+
while (offset < src.size && !(scan.hasHdrl && scan.hasMovi && scan.hasIdx1)) {
|
|
253
|
+
const chunk = await src.read(offset, Math.min(CHUNK + 4, src.size - offset));
|
|
254
|
+
const text = latin1(chunk);
|
|
255
|
+
if (!scan.hasHdrl && text.includes('hdrl'))
|
|
256
|
+
scan.hasHdrl = true;
|
|
257
|
+
if (!scan.hasMovi && text.includes('movi'))
|
|
258
|
+
scan.hasMovi = true;
|
|
259
|
+
if (!scan.hasIdx1 && text.includes('idx1'))
|
|
260
|
+
scan.hasIdx1 = true;
|
|
261
|
+
offset += CHUNK;
|
|
262
|
+
}
|
|
263
|
+
return scan;
|
|
264
|
+
}
|
|
265
|
+
export function latin1(bytes) {
|
|
266
|
+
let out = '';
|
|
267
|
+
const CHUNK = 8192;
|
|
268
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
269
|
+
out += String.fromCharCode(...bytes.subarray(i, Math.min(i + CHUNK, bytes.length)));
|
|
270
|
+
}
|
|
271
|
+
return out;
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/video/format.ts"],"names":[],"mappings":"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"}
|