@doedja/scenecut 1.0.0 → 1.0.2
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 +331 -280
- package/bin/cli.js +359 -293
- package/dist/decoder/ffmpeg-decoder.d.ts +15 -3
- package/dist/decoder/ffmpeg-decoder.d.ts.map +1 -1
- package/dist/decoder/ffmpeg-decoder.js +138 -15
- package/dist/decoder/ffmpeg-decoder.js.map +1 -1
- package/dist/detection/detector.d.ts.map +1 -1
- package/dist/detection/detector.js +134 -17
- package/dist/detection/detector.js.map +1 -1
- package/dist/detection/temporal-smoother.d.ts +32 -0
- package/dist/detection/temporal-smoother.d.ts.map +1 -0
- package/dist/detection/temporal-smoother.js +88 -0
- package/dist/detection/temporal-smoother.js.map +1 -0
- package/dist/detection/wasm-bridge.d.ts +26 -23
- package/dist/detection/wasm-bridge.d.ts.map +1 -1
- package/dist/detection/wasm-bridge.js +107 -62
- package/dist/detection/wasm-bridge.js.map +1 -1
- package/dist/detection.wasm.js +2 -2
- package/dist/detection.wasm.wasm +0 -0
- package/dist/index.d.ts +13 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -1
- package/dist/index.js.map +1 -1
- package/dist/keyframes.cjs.js +492 -95
- package/dist/keyframes.cjs.js.map +1 -1
- package/dist/keyframes.esm.js +490 -96
- package/dist/keyframes.esm.js.map +1 -1
- package/dist/types/index.d.ts +36 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +79 -77
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal Smoother - Sliding window filter to reduce false positives
|
|
3
|
+
*
|
|
4
|
+
* Three rules:
|
|
5
|
+
* 1. Minimum gap: Suppress detections within minConsecutive frames of each other (keep highest confidence)
|
|
6
|
+
* 2. Flash suppression: Isolated single-frame detections with low confidence are suppressed
|
|
7
|
+
* 3. Cluster merging: Consecutive triggered frames (common in dissolves) keep only highest-confidence one
|
|
8
|
+
*/
|
|
9
|
+
export class TemporalSmoother {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
// Sliding window of recent detections
|
|
12
|
+
this.recentDetections = [];
|
|
13
|
+
// Last confirmed scene change frame
|
|
14
|
+
this.lastConfirmedFrame = 0;
|
|
15
|
+
// Buffer for cluster detection
|
|
16
|
+
this.pendingCluster = [];
|
|
17
|
+
this.nonDetectionCount = 0;
|
|
18
|
+
// Flash suppression: minimum confidence for isolated detections
|
|
19
|
+
this.flashConfidenceThreshold = 0.4;
|
|
20
|
+
this.windowSize = config.windowSize;
|
|
21
|
+
this.minConsecutive = config.minConsecutive;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Process a frame's detection result through temporal smoothing
|
|
25
|
+
*/
|
|
26
|
+
process(frameNumber, rawIsSceneChange, rawConfidence) {
|
|
27
|
+
// If no detection, track gap and possibly flush pending cluster
|
|
28
|
+
if (!rawIsSceneChange) {
|
|
29
|
+
this.nonDetectionCount++;
|
|
30
|
+
// If we had a pending cluster and enough non-detections have passed,
|
|
31
|
+
// emit the best detection from the cluster
|
|
32
|
+
if (this.pendingCluster.length > 0 && this.nonDetectionCount >= 2) {
|
|
33
|
+
const best = this.flushCluster();
|
|
34
|
+
if (best) {
|
|
35
|
+
return best;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return { isSceneChange: false, confidence: 0 };
|
|
39
|
+
}
|
|
40
|
+
// We have a detection
|
|
41
|
+
this.nonDetectionCount = 0;
|
|
42
|
+
// Rule 1: Minimum gap enforcement
|
|
43
|
+
if (frameNumber - this.lastConfirmedFrame < this.minConsecutive) {
|
|
44
|
+
// Too close to last confirmed scene change
|
|
45
|
+
// If this has higher confidence, replace pending, but don't emit yet
|
|
46
|
+
if (this.pendingCluster.length > 0) {
|
|
47
|
+
const best = this.pendingCluster.reduce((a, b) => a.confidence > b.confidence ? a : b);
|
|
48
|
+
if (rawConfidence > best.confidence) {
|
|
49
|
+
// Replace entire cluster with this better detection
|
|
50
|
+
this.pendingCluster = [{ frameNumber, confidence: rawConfidence }];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { isSceneChange: false, confidence: 0 };
|
|
54
|
+
}
|
|
55
|
+
// Rule 3: Cluster merging - add to pending cluster
|
|
56
|
+
this.pendingCluster.push({ frameNumber, confidence: rawConfidence });
|
|
57
|
+
// Don't emit immediately; wait to see if more consecutive detections follow
|
|
58
|
+
return { isSceneChange: false, confidence: 0 };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Flush the pending cluster, emitting the highest-confidence detection
|
|
62
|
+
*/
|
|
63
|
+
flushCluster() {
|
|
64
|
+
if (this.pendingCluster.length === 0) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
// Find the detection with highest confidence
|
|
68
|
+
const best = this.pendingCluster.reduce((a, b) => a.confidence > b.confidence ? a : b);
|
|
69
|
+
// Rule 2: Flash suppression - isolated single-frame detections with low confidence
|
|
70
|
+
if (this.pendingCluster.length === 1 && best.confidence < this.flashConfidenceThreshold) {
|
|
71
|
+
this.pendingCluster = [];
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
// Confirm this detection
|
|
75
|
+
this.lastConfirmedFrame = best.frameNumber;
|
|
76
|
+
this.recentDetections.push(best);
|
|
77
|
+
// Keep sliding window bounded
|
|
78
|
+
while (this.recentDetections.length > this.windowSize) {
|
|
79
|
+
this.recentDetections.shift();
|
|
80
|
+
}
|
|
81
|
+
this.pendingCluster = [];
|
|
82
|
+
return {
|
|
83
|
+
isSceneChange: true,
|
|
84
|
+
confidence: best.confidence
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=temporal-smoother.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temporal-smoother.js","sourceRoot":"","sources":["../../src/detection/temporal-smoother.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,15 +6,22 @@
|
|
|
6
6
|
* - Memory allocation and management
|
|
7
7
|
* - Calling WASM functions
|
|
8
8
|
* - Data marshalling between JS and WASM
|
|
9
|
+
* - Double-buffering to avoid redundant frame copies
|
|
9
10
|
*/
|
|
10
11
|
import { RawFrame } from '../types';
|
|
12
|
+
export interface SceneChangeResult {
|
|
13
|
+
isSceneChange: boolean;
|
|
14
|
+
confidence: number;
|
|
15
|
+
}
|
|
11
16
|
export declare class WasmBridge {
|
|
12
17
|
private module;
|
|
13
18
|
private initialized;
|
|
14
|
-
private
|
|
15
|
-
private
|
|
16
|
-
private
|
|
17
|
-
private
|
|
19
|
+
private slotARawPtr;
|
|
20
|
+
private slotBRawPtr;
|
|
21
|
+
private slotAPaddedPtr;
|
|
22
|
+
private slotBPaddedPtr;
|
|
23
|
+
private prevIsSlotA;
|
|
24
|
+
private prevSlotPadded;
|
|
18
25
|
private allocatedFrameSize;
|
|
19
26
|
private allocatedPaddedSize;
|
|
20
27
|
/**
|
|
@@ -26,40 +33,36 @@ export declare class WasmBridge {
|
|
|
26
33
|
*/
|
|
27
34
|
private ensureInitialized;
|
|
28
35
|
/**
|
|
29
|
-
* Pre-allocate WASM buffers for frame processing
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* @param width Frame width
|
|
33
|
-
* @param height Frame height
|
|
36
|
+
* Pre-allocate WASM buffers for frame processing.
|
|
37
|
+
* Allocates double-buffered raw + padded slots and pre-allocates the MB array.
|
|
34
38
|
*/
|
|
35
39
|
allocateBuffers(width: number, height: number): void;
|
|
36
40
|
/**
|
|
37
|
-
* Detect scene change between two frames
|
|
41
|
+
* Detect scene change between two frames using double-buffering.
|
|
38
42
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
43
|
+
* On first call, both frames are copied and padded.
|
|
44
|
+
* On subsequent calls, only the new current frame is copied and padded;
|
|
45
|
+
* the previous frame is already in WASM memory from the last call.
|
|
41
46
|
*
|
|
42
47
|
* @param prevFrame Previous frame
|
|
43
48
|
* @param curFrame Current frame
|
|
44
49
|
* @param intraCount Number of consecutive non-scene-change frames
|
|
45
|
-
* @param fcode Motion search range parameter
|
|
46
|
-
* @
|
|
50
|
+
* @param fcode Motion search range parameter
|
|
51
|
+
* @param intraThresh Primary intra threshold
|
|
52
|
+
* @param intraThresh2 Secondary intra threshold (sSAD comparison)
|
|
53
|
+
* @returns Scene change result with confidence score
|
|
54
|
+
*/
|
|
55
|
+
detectSceneChange(prevFrame: RawFrame, curFrame: RawFrame, intraCount: number, fcode?: number, intraThresh?: number, intraThresh2?: number): SceneChangeResult;
|
|
56
|
+
/**
|
|
57
|
+
* Reset double-buffer state (e.g., after a seek or when starting fresh)
|
|
47
58
|
*/
|
|
48
|
-
|
|
59
|
+
resetBufferState(): void;
|
|
49
60
|
/**
|
|
50
61
|
* Calculate required buffer size for a padded frame
|
|
51
|
-
*
|
|
52
|
-
* @param width Original frame width
|
|
53
|
-
* @param height Original frame height
|
|
54
|
-
* @returns Required buffer size in bytes
|
|
55
62
|
*/
|
|
56
63
|
calculatePaddedSize(width: number, height: number): number;
|
|
57
64
|
/**
|
|
58
65
|
* Get macroblock parameters for a given frame size
|
|
59
|
-
*
|
|
60
|
-
* @param width Frame width
|
|
61
|
-
* @param height Frame height
|
|
62
|
-
* @returns Macroblock parameters
|
|
63
66
|
*/
|
|
64
67
|
getMBParam(width: number, height: number): {
|
|
65
68
|
width: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasm-bridge.d.ts","sourceRoot":"","sources":["../../src/detection/wasm-bridge.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"wasm-bridge.d.ts","sourceRoot":"","sources":["../../src/detection/wasm-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAc,QAAQ,EAAE,MAAM,UAAU,CAAC;AAIhD,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,WAAW,CAAkB;IAIrC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,WAAW,CAAa;IAEhC,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,cAAc,CAAa;IAEnC,OAAO,CAAC,WAAW,CAAiB;IAEpC,OAAO,CAAC,cAAc,CAAkB;IAExC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,mBAAmB,CAAa;IAIxC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB3B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;;OAGG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAqCpD;;;;;;;;;;;;;;OAcG;IACH,iBAAiB,CACf,SAAS,EAAE,QAAQ,EACnB,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAU,EACjB,WAAW,GAAE,MAAa,EAC1B,YAAY,GAAE,MAAW,GACxB,iBAAiB;IAqEpB;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAKxB;;OAEG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAK1D;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;;IAgBxC;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,OAAO,IAAI,IAAI;CAuBhB"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* - Memory allocation and management
|
|
7
7
|
* - Calling WASM functions
|
|
8
8
|
* - Data marshalling between JS and WASM
|
|
9
|
+
* - Double-buffering to avoid redundant frame copies
|
|
9
10
|
*/
|
|
10
11
|
import * as path from 'path';
|
|
11
12
|
import * as fs from 'fs';
|
|
@@ -13,14 +14,21 @@ export class WasmBridge {
|
|
|
13
14
|
constructor() {
|
|
14
15
|
this.module = null;
|
|
15
16
|
this.initialized = false;
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
20
|
-
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
17
|
+
// Double-buffered WASM pointers for frame processing
|
|
18
|
+
// Slot A and Slot B raw frame buffers
|
|
19
|
+
this.slotARawPtr = 0;
|
|
20
|
+
this.slotBRawPtr = 0;
|
|
21
|
+
// Slot A and Slot B padded frame buffers
|
|
22
|
+
this.slotAPaddedPtr = 0;
|
|
23
|
+
this.slotBPaddedPtr = 0;
|
|
24
|
+
// Which slot currently holds the "previous" frame (true = A, false = B)
|
|
25
|
+
this.prevIsSlotA = true;
|
|
26
|
+
// Whether the previous slot has valid padded data
|
|
27
|
+
this.prevSlotPadded = false;
|
|
28
|
+
this.allocatedFrameSize = 0;
|
|
29
|
+
this.allocatedPaddedSize = 0;
|
|
23
30
|
}
|
|
31
|
+
// Frame dimensions (reserved for future use in validation/resizing)
|
|
24
32
|
/**
|
|
25
33
|
* Initialize the WASM module
|
|
26
34
|
*/
|
|
@@ -53,11 +61,8 @@ export class WasmBridge {
|
|
|
53
61
|
}
|
|
54
62
|
}
|
|
55
63
|
/**
|
|
56
|
-
* Pre-allocate WASM buffers for frame processing
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* @param width Frame width
|
|
60
|
-
* @param height Frame height
|
|
64
|
+
* Pre-allocate WASM buffers for frame processing.
|
|
65
|
+
* Allocates double-buffered raw + padded slots and pre-allocates the MB array.
|
|
61
66
|
*/
|
|
62
67
|
allocateBuffers(width, height) {
|
|
63
68
|
this.ensureInitialized();
|
|
@@ -65,63 +70,104 @@ export class WasmBridge {
|
|
|
65
70
|
const paddedSize = this.module._calculate_padded_size(width, height);
|
|
66
71
|
// Allocate or re-allocate raw frame buffers if size changed
|
|
67
72
|
if (frameSize !== this.allocatedFrameSize) {
|
|
68
|
-
if (this.
|
|
69
|
-
this.module._free(this.
|
|
70
|
-
if (this.
|
|
71
|
-
this.module._free(this.
|
|
72
|
-
this.
|
|
73
|
-
this.
|
|
73
|
+
if (this.slotARawPtr)
|
|
74
|
+
this.module._free(this.slotARawPtr);
|
|
75
|
+
if (this.slotBRawPtr)
|
|
76
|
+
this.module._free(this.slotBRawPtr);
|
|
77
|
+
this.slotARawPtr = this.module._malloc(frameSize);
|
|
78
|
+
this.slotBRawPtr = this.module._malloc(frameSize);
|
|
74
79
|
this.allocatedFrameSize = frameSize;
|
|
75
80
|
}
|
|
76
81
|
// Allocate or re-allocate padded frame buffers if size changed
|
|
77
82
|
if (paddedSize !== this.allocatedPaddedSize) {
|
|
78
|
-
if (this.
|
|
79
|
-
this.module._free(this.
|
|
80
|
-
if (this.
|
|
81
|
-
this.module._free(this.
|
|
82
|
-
this.
|
|
83
|
-
this.
|
|
83
|
+
if (this.slotAPaddedPtr)
|
|
84
|
+
this.module._free(this.slotAPaddedPtr);
|
|
85
|
+
if (this.slotBPaddedPtr)
|
|
86
|
+
this.module._free(this.slotBPaddedPtr);
|
|
87
|
+
this.slotAPaddedPtr = this.module._malloc(paddedSize);
|
|
88
|
+
this.slotBPaddedPtr = this.module._malloc(paddedSize);
|
|
84
89
|
this.allocatedPaddedSize = paddedSize;
|
|
85
90
|
}
|
|
91
|
+
// Reset double-buffer state
|
|
92
|
+
this.prevIsSlotA = true;
|
|
93
|
+
this.prevSlotPadded = false;
|
|
94
|
+
// Pre-allocate macroblock array in WASM
|
|
95
|
+
const mbResult = this.module._allocate_mb_array(width, height);
|
|
96
|
+
if (mbResult === 0) {
|
|
97
|
+
throw new Error('Failed to pre-allocate macroblock array in WASM');
|
|
98
|
+
}
|
|
86
99
|
}
|
|
87
100
|
/**
|
|
88
|
-
* Detect scene change between two frames
|
|
101
|
+
* Detect scene change between two frames using double-buffering.
|
|
89
102
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
103
|
+
* On first call, both frames are copied and padded.
|
|
104
|
+
* On subsequent calls, only the new current frame is copied and padded;
|
|
105
|
+
* the previous frame is already in WASM memory from the last call.
|
|
92
106
|
*
|
|
93
107
|
* @param prevFrame Previous frame
|
|
94
108
|
* @param curFrame Current frame
|
|
95
109
|
* @param intraCount Number of consecutive non-scene-change frames
|
|
96
|
-
* @param fcode Motion search range parameter
|
|
97
|
-
* @
|
|
110
|
+
* @param fcode Motion search range parameter
|
|
111
|
+
* @param intraThresh Primary intra threshold
|
|
112
|
+
* @param intraThresh2 Secondary intra threshold (sSAD comparison)
|
|
113
|
+
* @returns Scene change result with confidence score
|
|
98
114
|
*/
|
|
99
|
-
detectSceneChange(prevFrame, curFrame, intraCount, fcode = 4) {
|
|
115
|
+
detectSceneChange(prevFrame, curFrame, intraCount, fcode = 4, intraThresh = 2000, intraThresh2 = 90) {
|
|
100
116
|
this.ensureInitialized();
|
|
101
117
|
// Validate inputs
|
|
102
118
|
if (prevFrame.width !== curFrame.width || prevFrame.height !== curFrame.height) {
|
|
103
119
|
throw new Error('Frame dimensions must match');
|
|
104
120
|
}
|
|
105
|
-
// Ensure buffers are allocated
|
|
106
|
-
if (!this.
|
|
121
|
+
// Ensure buffers are allocated
|
|
122
|
+
if (!this.slotARawPtr || this.allocatedFrameSize !== prevFrame.data.length) {
|
|
107
123
|
this.allocateBuffers(prevFrame.width, prevFrame.height);
|
|
108
124
|
}
|
|
109
|
-
//
|
|
110
|
-
this.
|
|
111
|
-
this.
|
|
112
|
-
|
|
113
|
-
this.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
125
|
+
// Determine which slot is "prev" and which is "cur"
|
|
126
|
+
const prevRawPtr = this.prevIsSlotA ? this.slotARawPtr : this.slotBRawPtr;
|
|
127
|
+
const prevPaddedPtr = this.prevIsSlotA ? this.slotAPaddedPtr : this.slotBPaddedPtr;
|
|
128
|
+
const curRawPtr = this.prevIsSlotA ? this.slotBRawPtr : this.slotARawPtr;
|
|
129
|
+
const curPaddedPtr = this.prevIsSlotA ? this.slotBPaddedPtr : this.slotAPaddedPtr;
|
|
130
|
+
// Copy and pad previous frame only if not already valid in WASM
|
|
131
|
+
if (!this.prevSlotPadded) {
|
|
132
|
+
this.module.HEAPU8.set(prevFrame.data, prevRawPtr);
|
|
133
|
+
this.module._pad_frame(prevRawPtr, prevPaddedPtr, prevFrame.width, prevFrame.height);
|
|
134
|
+
}
|
|
135
|
+
// Always copy and pad the new current frame
|
|
136
|
+
this.module.HEAPU8.set(curFrame.data, curRawPtr);
|
|
137
|
+
this.module._pad_frame(curRawPtr, curPaddedPtr, curFrame.width, curFrame.height);
|
|
138
|
+
// Run motion estimation with parameterized thresholds
|
|
139
|
+
const rawScore = this.module._MEanalysis_js(prevPaddedPtr, curPaddedPtr, prevFrame.width, prevFrame.height, intraCount, fcode, intraThresh, intraThresh2);
|
|
140
|
+
// Check for WASM error
|
|
141
|
+
if (rawScore === -1) {
|
|
142
|
+
throw new Error('WASM memory allocation failed during scene detection. ' +
|
|
143
|
+
`Frame size: ${prevFrame.width}x${prevFrame.height}. ` +
|
|
144
|
+
'The video resolution may be too high for available WASM memory.');
|
|
145
|
+
}
|
|
146
|
+
// Swap roles: current slot becomes previous for next call
|
|
147
|
+
this.prevIsSlotA = !this.prevIsSlotA;
|
|
148
|
+
this.prevSlotPadded = true;
|
|
149
|
+
// Determine scene change and confidence
|
|
150
|
+
const isSceneChange = rawScore >= intraThresh2;
|
|
151
|
+
// Normalize confidence: 0 when at threshold, 1 at 2x threshold
|
|
152
|
+
// For non-scene-changes, confidence represents "how close" (0 = very far from threshold)
|
|
153
|
+
let confidence;
|
|
154
|
+
if (isSceneChange) {
|
|
155
|
+
confidence = Math.min(1.0, rawScore / (intraThresh2 * 2));
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
confidence = intraThresh2 > 0 ? Math.min(1.0, rawScore / intraThresh2) : 0;
|
|
159
|
+
}
|
|
160
|
+
return { isSceneChange, confidence };
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Reset double-buffer state (e.g., after a seek or when starting fresh)
|
|
164
|
+
*/
|
|
165
|
+
resetBufferState() {
|
|
166
|
+
this.prevIsSlotA = true;
|
|
167
|
+
this.prevSlotPadded = false;
|
|
118
168
|
}
|
|
119
169
|
/**
|
|
120
170
|
* Calculate required buffer size for a padded frame
|
|
121
|
-
*
|
|
122
|
-
* @param width Original frame width
|
|
123
|
-
* @param height Original frame height
|
|
124
|
-
* @returns Required buffer size in bytes
|
|
125
171
|
*/
|
|
126
172
|
calculatePaddedSize(width, height) {
|
|
127
173
|
this.ensureInitialized();
|
|
@@ -129,10 +175,6 @@ export class WasmBridge {
|
|
|
129
175
|
}
|
|
130
176
|
/**
|
|
131
177
|
* Get macroblock parameters for a given frame size
|
|
132
|
-
*
|
|
133
|
-
* @param width Frame width
|
|
134
|
-
* @param height Frame height
|
|
135
|
-
* @returns Macroblock parameters
|
|
136
178
|
*/
|
|
137
179
|
getMBParam(width, height) {
|
|
138
180
|
const mb_width = Math.ceil(width / 16);
|
|
@@ -158,23 +200,26 @@ export class WasmBridge {
|
|
|
158
200
|
* Clean up resources
|
|
159
201
|
*/
|
|
160
202
|
destroy() {
|
|
161
|
-
// Free pre-allocated WASM buffers
|
|
162
203
|
if (this.module) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
204
|
+
// Free pre-allocated macroblock array
|
|
205
|
+
this.module._free_mb_array();
|
|
206
|
+
// Free double-buffered WASM frame buffers
|
|
207
|
+
if (this.slotARawPtr)
|
|
208
|
+
this.module._free(this.slotARawPtr);
|
|
209
|
+
if (this.slotBRawPtr)
|
|
210
|
+
this.module._free(this.slotBRawPtr);
|
|
211
|
+
if (this.slotAPaddedPtr)
|
|
212
|
+
this.module._free(this.slotAPaddedPtr);
|
|
213
|
+
if (this.slotBPaddedPtr)
|
|
214
|
+
this.module._free(this.slotBPaddedPtr);
|
|
171
215
|
}
|
|
172
|
-
this.
|
|
173
|
-
this.
|
|
174
|
-
this.
|
|
175
|
-
this.
|
|
216
|
+
this.slotARawPtr = 0;
|
|
217
|
+
this.slotBRawPtr = 0;
|
|
218
|
+
this.slotAPaddedPtr = 0;
|
|
219
|
+
this.slotBPaddedPtr = 0;
|
|
176
220
|
this.allocatedFrameSize = 0;
|
|
177
221
|
this.allocatedPaddedSize = 0;
|
|
222
|
+
this.prevSlotPadded = false;
|
|
178
223
|
this.module = null;
|
|
179
224
|
this.initialized = false;
|
|
180
225
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasm-bridge.js","sourceRoot":"","sources":["../../src/detection/wasm-bridge.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"wasm-bridge.js","sourceRoot":"","sources":["../../src/detection/wasm-bridge.ts"],"names":[],"mappings":"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"}
|
package/dist/detection.wasm.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var createWasmModule=(()=>{var _scriptName=globalThis.document?.currentScript?.src;return async function(moduleArg={}){var moduleRtn;var Module=moduleArg;var ENVIRONMENT_IS_WEB=!!globalThis.window;var ENVIRONMENT_IS_WORKER=!!globalThis.WorkerGlobalScope;var ENVIRONMENT_IS_NODE=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};if(typeof __filename!="undefined"){_scriptName=__filename}else if(ENVIRONMENT_IS_WORKER){_scriptName=self.location.href}var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=async url=>{if(isFileURI(url)){return new Promise((resolve,reject)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){resolve(xhr.response);return}reject(xhr.status)};xhr.onerror=reject;xhr.send(null)})}var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;var isFileURI=filename=>filename.startsWith("file://");var readyPromiseResolve,readyPromiseReject;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;var HEAP64,HEAPU64;var runtimeInitialized=false;function updateMemoryViews(){var b=wasmMemory.buffer;HEAP8=new Int8Array(b);HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);HEAPU16=new Uint16Array(b);HEAP32=new Int32Array(b);HEAPU32=new Uint32Array(b);HEAPF32=new Float32Array(b);HEAPF64=new Float64Array(b);HEAP64=new BigInt64Array(b);HEAPU64=new BigUint64Array(b)}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;wasmExports["c"]()}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(onPostRuns)}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject?.(e);throw e}var wasmBinaryFile;function findWasmBinary(){return locateFile("detection.wasm.wasm")}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();if(Module["instantiateWasm"]){return new Promise((resolve,reject)=>{Module["instantiateWasm"](info,(inst,mod)=>{resolve(receiveInstance(inst,mod))})})}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var addOnPostRun=cb=>onPostRuns.push(cb);var onPreRuns=[];var addOnPreRun=cb=>onPreRuns.push(cb);function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr];case"i8":return HEAP8[ptr];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP64[ptr>>3];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`)}}var noExitRuntime=true;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr]=value;break;case"i8":HEAP8[ptr]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":HEAP64[ptr>>3]=BigInt(value);break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`)}}var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var lengthBytesUTF8=str=>{var len=0;for(var i=0;i<str.length;++i){var c=str.charCodeAt(i);if(c<=127){len++}else if(c<=2047){len+=2}else if(c>=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.codePointAt(i);if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;i++}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var UTF8Decoder=globalThis.TextDecoder&&new TextDecoder;var findStringEnd=(heapOrArray,idx,maxBytesToRead,ignoreNul)=>{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx<endPtr){var u0=heapOrArray[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heapOrArray[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heapOrArray[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heapOrArray[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func(...cArgs);function onDone(ret){if(stack!==0)stackRestore(stack);return convertReturnValue(ret)}ret=onDone(ret);return ret};var cwrap=(ident,returnType,argTypes,opts)=>{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].shift()()}}}Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["setValue"]=setValue;Module["getValue"]=getValue;var _MEanalysis_js,_free,_calculate_padded_size,_pad_frame,_malloc,__emscripten_stack_restore,__emscripten_stack_alloc,_emscripten_stack_get_current,memory,__indirect_function_table,wasmMemory;function assignWasmExports(wasmExports){_MEanalysis_js=Module["_MEanalysis_js"]=wasmExports["d"];_free=Module["_free"]=wasmExports["e"];_calculate_padded_size=Module["_calculate_padded_size"]=wasmExports["f"];_pad_frame=Module["_pad_frame"]=wasmExports["g"];_malloc=Module["_malloc"]=wasmExports["h"];__emscripten_stack_restore=wasmExports["i"];__emscripten_stack_alloc=wasmExports["j"];_emscripten_stack_get_current=wasmExports["k"];memory=wasmMemory=wasmExports["b"];__indirect_function_table=wasmExports["__indirect_function_table"]}var wasmImports={a:_emscripten_resize_heap};function run(){preRun();function doRun(){Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve?.(Module);Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}var wasmExports;wasmExports=await (createWasm());run();if(runtimeInitialized){moduleRtn=Module}else{moduleRtn=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject})}
|
|
2
|
-
;return moduleRtn}})();if(typeof exports==="object"&&typeof module==="object"){module.exports=createWasmModule;module.exports.default=createWasmModule}else if(typeof define==="function"&&define["amd"])define([],()=>createWasmModule);
|
|
1
|
+
var createWasmModule=(()=>{var _scriptName=globalThis.document?.currentScript?.src;return async function(moduleArg={}){var moduleRtn;var Module=moduleArg;var ENVIRONMENT_IS_WEB=!!globalThis.window;var ENVIRONMENT_IS_WORKER=!!globalThis.WorkerGlobalScope;var ENVIRONMENT_IS_NODE=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};if(typeof __filename!="undefined"){_scriptName=__filename}else if(ENVIRONMENT_IS_WORKER){_scriptName=self.location.href}var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("node:fs");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=async url=>{if(isFileURI(url)){return new Promise((resolve,reject)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){resolve(xhr.response);return}reject(xhr.status)};xhr.onerror=reject;xhr.send(null)})}var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;var isFileURI=filename=>filename.startsWith("file://");var readyPromiseResolve,readyPromiseReject;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;var HEAP64,HEAPU64;var runtimeInitialized=false;function updateMemoryViews(){var b=wasmMemory.buffer;HEAP8=new Int8Array(b);HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);HEAPU16=new Uint16Array(b);HEAP32=new Int32Array(b);HEAPU32=new Uint32Array(b);HEAPF32=new Float32Array(b);HEAPF64=new Float64Array(b);HEAP64=new BigInt64Array(b);HEAPU64=new BigUint64Array(b)}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;wasmExports["c"]()}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(onPostRuns)}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject?.(e);throw e}var wasmBinaryFile;function findWasmBinary(){return locateFile("detection.wasm.wasm")}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();if(Module["instantiateWasm"]){return new Promise((resolve,reject)=>{Module["instantiateWasm"](info,(inst,mod)=>{resolve(receiveInstance(inst,mod))})})}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var addOnPostRun=cb=>onPostRuns.push(cb);var onPreRuns=[];var addOnPreRun=cb=>onPreRuns.push(cb);function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr];case"i8":return HEAP8[ptr];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP64[ptr>>3];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`)}}var noExitRuntime=true;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr]=value;break;case"i8":HEAP8[ptr]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":HEAP64[ptr>>3]=BigInt(value);break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`)}}var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var lengthBytesUTF8=str=>{var len=0;for(var i=0;i<str.length;++i){var c=str.charCodeAt(i);if(c<=127){len++}else if(c<=2047){len+=2}else if(c>=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.codePointAt(i);if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;i++}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var UTF8Decoder=globalThis.TextDecoder&&new TextDecoder;var findStringEnd=(heapOrArray,idx,maxBytesToRead,ignoreNul)=>{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx<endPtr){var u0=heapOrArray[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heapOrArray[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heapOrArray[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heapOrArray[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func(...cArgs);function onDone(ret){if(stack!==0)stackRestore(stack);return convertReturnValue(ret)}ret=onDone(ret);return ret};var cwrap=(ident,returnType,argTypes,opts)=>{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].shift()()}}}Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["setValue"]=setValue;Module["getValue"]=getValue;var _allocate_mb_array,_free,_malloc,_free_mb_array,_MEanalysis_js,_calculate_padded_size,_pad_frame,__emscripten_stack_restore,__emscripten_stack_alloc,_emscripten_stack_get_current,memory,__indirect_function_table,wasmMemory;function assignWasmExports(wasmExports){_allocate_mb_array=Module["_allocate_mb_array"]=wasmExports["d"];_free=Module["_free"]=wasmExports["e"];_malloc=Module["_malloc"]=wasmExports["f"];_free_mb_array=Module["_free_mb_array"]=wasmExports["g"];_MEanalysis_js=Module["_MEanalysis_js"]=wasmExports["h"];_calculate_padded_size=Module["_calculate_padded_size"]=wasmExports["i"];_pad_frame=Module["_pad_frame"]=wasmExports["j"];__emscripten_stack_restore=wasmExports["k"];__emscripten_stack_alloc=wasmExports["l"];_emscripten_stack_get_current=wasmExports["m"];memory=wasmMemory=wasmExports["b"];__indirect_function_table=wasmExports["__indirect_function_table"]}var wasmImports={a:_emscripten_resize_heap};function run(){preRun();function doRun(){Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve?.(Module);Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}var wasmExports;wasmExports=await (createWasm());run();if(runtimeInitialized){moduleRtn=Module}else{moduleRtn=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject})}
|
|
2
|
+
;return moduleRtn}})();if(typeof exports==="object"&&typeof module==="object"){module.exports=createWasmModule;module.exports.default=createWasmModule}else if(typeof define==="function"&&define["amd"])define([],()=>createWasmModule);
|
package/dist/detection.wasm.wasm
CHANGED
|
Binary file
|
package/dist/index.d.ts
CHANGED
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
export { SceneDetector } from './detection/detector';
|
|
8
8
|
export { FFmpegDecoder } from './decoder/ffmpeg-decoder';
|
|
9
9
|
export { WasmBridge } from './detection/wasm-bridge';
|
|
10
|
+
export { TemporalSmoother } from './detection/temporal-smoother';
|
|
10
11
|
export { FrameBuffer } from './decoder/frame-buffer';
|
|
11
12
|
export { BufferPool } from './utils/buffer-pool';
|
|
12
|
-
export type { DetectionOptions, DetectionResult, SceneInfo, VideoMetadata, DetectionStats, Progress, RawFrame, SensitivityLevel, SearchRange, CustomThresholds, TemporalSmoothing, ProgressiveProcessing, FrameExtractionOptions } from './types';
|
|
13
|
+
export type { DetectionOptions, DetectionResult, SceneInfo, VideoMetadata, DetectionStats, Progress, RawFrame, SensitivityLevel, SearchRange, CustomThresholds, TemporalSmoothing, ProgressiveProcessing, FrameExtractionOptions, FrameImageOptions } from './types';
|
|
13
14
|
export { formatTimecode, calculateFcode, calculateThresholds, validateFrame, validateFrameDimensions, calculateMBParam, calculateFrameMemory, estimateProcessingTime } from './utils/frame-processor';
|
|
14
|
-
import { DetectionOptions, DetectionResult } from './types';
|
|
15
|
+
import { DetectionOptions, DetectionResult, FrameImageOptions } from './types';
|
|
15
16
|
/**
|
|
16
17
|
* Detect scene changes in a video file (simple API)
|
|
17
18
|
*
|
|
@@ -27,11 +28,20 @@ import { DetectionOptions, DetectionResult } from './types';
|
|
|
27
28
|
* console.log(`Found ${results.scenes.length} scenes`);
|
|
28
29
|
*
|
|
29
30
|
* results.scenes.forEach(scene => {
|
|
30
|
-
* console.log(`Scene at ${scene.timecode}`);
|
|
31
|
+
* console.log(`Scene at ${scene.timecode} (confidence: ${scene.confidence})`);
|
|
31
32
|
* });
|
|
32
33
|
* ```
|
|
33
34
|
*/
|
|
34
35
|
export declare function detectSceneChanges(videoPath: string, options?: DetectionOptions): Promise<DetectionResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Extract scene thumbnail images from a video
|
|
38
|
+
*
|
|
39
|
+
* @param videoPath Path to video file
|
|
40
|
+
* @param options Detection options
|
|
41
|
+
* @param imageOptions Image extraction options
|
|
42
|
+
* @returns Detection results (images are written to disk)
|
|
43
|
+
*/
|
|
44
|
+
export declare function extractSceneImages(videoPath: string, options?: DetectionOptions, imageOptions?: FrameImageOptions): Promise<DetectionResult>;
|
|
35
45
|
/**
|
|
36
46
|
* Version information
|
|
37
47
|
*/
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,aAAa,EACb,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,aAAa,EACb,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE/E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,eAAe,CAAC,CAS1B;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,gBAAgB,EAC1B,YAAY,CAAC,EAAE,iBAAiB,GAC/B,OAAO,CAAC,eAAe,CAAC,CAiB1B;AAED;;GAEG;AACH,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B;;GAEG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;CAWhB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
export { SceneDetector } from './detection/detector';
|
|
8
8
|
export { FFmpegDecoder } from './decoder/ffmpeg-decoder';
|
|
9
9
|
export { WasmBridge } from './detection/wasm-bridge';
|
|
10
|
+
export { TemporalSmoother } from './detection/temporal-smoother';
|
|
10
11
|
export { FrameBuffer } from './decoder/frame-buffer';
|
|
11
12
|
export { BufferPool } from './utils/buffer-pool';
|
|
12
13
|
// Export utilities
|
|
13
14
|
export { formatTimecode, calculateFcode, calculateThresholds, validateFrame, validateFrameDimensions, calculateMBParam, calculateFrameMemory, estimateProcessingTime } from './utils/frame-processor';
|
|
14
15
|
import { SceneDetector } from './detection/detector';
|
|
16
|
+
import { FFmpegDecoder } from './decoder/ffmpeg-decoder';
|
|
15
17
|
/**
|
|
16
18
|
* Detect scene changes in a video file (simple API)
|
|
17
19
|
*
|
|
@@ -27,7 +29,7 @@ import { SceneDetector } from './detection/detector';
|
|
|
27
29
|
* console.log(`Found ${results.scenes.length} scenes`);
|
|
28
30
|
*
|
|
29
31
|
* results.scenes.forEach(scene => {
|
|
30
|
-
* console.log(`Scene at ${scene.timecode}`);
|
|
32
|
+
* console.log(`Scene at ${scene.timecode} (confidence: ${scene.confidence})`);
|
|
31
33
|
* });
|
|
32
34
|
* ```
|
|
33
35
|
*/
|
|
@@ -41,6 +43,30 @@ export async function detectSceneChanges(videoPath, options) {
|
|
|
41
43
|
detector.destroy();
|
|
42
44
|
}
|
|
43
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Extract scene thumbnail images from a video
|
|
48
|
+
*
|
|
49
|
+
* @param videoPath Path to video file
|
|
50
|
+
* @param options Detection options
|
|
51
|
+
* @param imageOptions Image extraction options
|
|
52
|
+
* @returns Detection results (images are written to disk)
|
|
53
|
+
*/
|
|
54
|
+
export async function extractSceneImages(videoPath, options, imageOptions) {
|
|
55
|
+
const detector = new SceneDetector(options);
|
|
56
|
+
try {
|
|
57
|
+
const results = await detector.detect(videoPath);
|
|
58
|
+
if (imageOptions) {
|
|
59
|
+
const decoder = new FFmpegDecoder(videoPath);
|
|
60
|
+
const frameNumbers = results.scenes.map(s => s.frameNumber);
|
|
61
|
+
await decoder.extractFrameImages(frameNumbers, imageOptions);
|
|
62
|
+
decoder.destroy();
|
|
63
|
+
}
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
detector.destroy();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
44
70
|
/**
|
|
45
71
|
* Version information
|
|
46
72
|
*/
|