@editframe/assets 0.40.0 → 0.40.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/dist/Probe.cjs +28 -9
- package/dist/Probe.cjs.map +1 -1
- package/dist/Probe.d.cts +27 -26
- package/dist/Probe.d.ts +27 -26
- package/dist/Probe.js +29 -9
- package/dist/Probe.js.map +1 -1
- package/dist/VideoRenderOptions.d.cts +48 -48
- package/dist/VideoRenderOptions.d.ts +48 -48
- package/dist/generateFragmentIndex.cjs +39 -26
- package/dist/generateFragmentIndex.cjs.map +1 -1
- package/dist/generateFragmentIndex.d.cts +5 -1
- package/dist/generateFragmentIndex.d.ts +5 -1
- package/dist/generateFragmentIndex.js +35 -27
- package/dist/generateFragmentIndex.js.map +1 -1
- package/dist/generateSingleTrack.cjs.map +1 -1
- package/dist/generateSingleTrack.js.map +1 -1
- package/dist/idempotentTask.cjs +58 -6
- package/dist/idempotentTask.cjs.map +1 -1
- package/dist/idempotentTask.js +58 -7
- package/dist/idempotentTask.js.map +1 -1
- package/dist/tasks/findOrCreateCaptions.cjs +13 -6
- package/dist/tasks/findOrCreateCaptions.cjs.map +1 -1
- package/dist/tasks/findOrCreateCaptions.js +13 -6
- package/dist/tasks/findOrCreateCaptions.js.map +1 -1
- package/dist/tasks/generateScrubTrack.cjs +1 -11
- package/dist/tasks/generateScrubTrack.cjs.map +1 -1
- package/dist/tasks/generateScrubTrack.js +1 -11
- package/dist/tasks/generateScrubTrack.js.map +1 -1
- package/dist/tasks/generateTrackFragmentIndex.cjs +22 -28
- package/dist/tasks/generateTrackFragmentIndex.cjs.map +1 -1
- package/dist/tasks/generateTrackFragmentIndex.js +22 -28
- package/dist/tasks/generateTrackFragmentIndex.js.map +1 -1
- package/package.json +1 -1
package/dist/Probe.d.ts
CHANGED
|
@@ -93,8 +93,6 @@ declare const VideoStreamSchema: z$1.ZodObject<{
|
|
|
93
93
|
bit_rate: z$1.ZodOptional<z$1.ZodString>;
|
|
94
94
|
disposition: z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>;
|
|
95
95
|
}, "strip", z$1.ZodTypeAny, {
|
|
96
|
-
width: number;
|
|
97
|
-
height: number;
|
|
98
96
|
index: number;
|
|
99
97
|
codec_name: string;
|
|
100
98
|
codec_long_name: string;
|
|
@@ -105,6 +103,8 @@ declare const VideoStreamSchema: z$1.ZodObject<{
|
|
|
105
103
|
avg_frame_rate: string;
|
|
106
104
|
time_base: string;
|
|
107
105
|
disposition: Record<string, unknown>;
|
|
106
|
+
width: number;
|
|
107
|
+
height: number;
|
|
108
108
|
coded_width: number;
|
|
109
109
|
coded_height: number;
|
|
110
110
|
start_pts?: number | undefined;
|
|
@@ -115,8 +115,6 @@ declare const VideoStreamSchema: z$1.ZodObject<{
|
|
|
115
115
|
profile?: string | undefined;
|
|
116
116
|
level?: number | undefined;
|
|
117
117
|
}, {
|
|
118
|
-
width: number;
|
|
119
|
-
height: number;
|
|
120
118
|
index: number;
|
|
121
119
|
codec_name: string;
|
|
122
120
|
codec_long_name: string;
|
|
@@ -127,6 +125,8 @@ declare const VideoStreamSchema: z$1.ZodObject<{
|
|
|
127
125
|
avg_frame_rate: string;
|
|
128
126
|
time_base: string;
|
|
129
127
|
disposition: Record<string, unknown>;
|
|
128
|
+
width: number;
|
|
129
|
+
height: number;
|
|
130
130
|
coded_width: number;
|
|
131
131
|
coded_height: number;
|
|
132
132
|
start_pts?: number | undefined;
|
|
@@ -227,8 +227,6 @@ declare const StreamSchema: z$1.ZodDiscriminatedUnion<"codec_type", [z$1.ZodObje
|
|
|
227
227
|
bit_rate: z$1.ZodOptional<z$1.ZodString>;
|
|
228
228
|
disposition: z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>;
|
|
229
229
|
}, "strip", z$1.ZodTypeAny, {
|
|
230
|
-
width: number;
|
|
231
|
-
height: number;
|
|
232
230
|
index: number;
|
|
233
231
|
codec_name: string;
|
|
234
232
|
codec_long_name: string;
|
|
@@ -239,6 +237,8 @@ declare const StreamSchema: z$1.ZodDiscriminatedUnion<"codec_type", [z$1.ZodObje
|
|
|
239
237
|
avg_frame_rate: string;
|
|
240
238
|
time_base: string;
|
|
241
239
|
disposition: Record<string, unknown>;
|
|
240
|
+
width: number;
|
|
241
|
+
height: number;
|
|
242
242
|
coded_width: number;
|
|
243
243
|
coded_height: number;
|
|
244
244
|
start_pts?: number | undefined;
|
|
@@ -249,8 +249,6 @@ declare const StreamSchema: z$1.ZodDiscriminatedUnion<"codec_type", [z$1.ZodObje
|
|
|
249
249
|
profile?: string | undefined;
|
|
250
250
|
level?: number | undefined;
|
|
251
251
|
}, {
|
|
252
|
-
width: number;
|
|
253
|
-
height: number;
|
|
254
252
|
index: number;
|
|
255
253
|
codec_name: string;
|
|
256
254
|
codec_long_name: string;
|
|
@@ -261,6 +259,8 @@ declare const StreamSchema: z$1.ZodDiscriminatedUnion<"codec_type", [z$1.ZodObje
|
|
|
261
259
|
avg_frame_rate: string;
|
|
262
260
|
time_base: string;
|
|
263
261
|
disposition: Record<string, unknown>;
|
|
262
|
+
width: number;
|
|
263
|
+
height: number;
|
|
264
264
|
coded_width: number;
|
|
265
265
|
coded_height: number;
|
|
266
266
|
start_pts?: number | undefined;
|
|
@@ -380,8 +380,6 @@ declare const ProbeSchema: z$1.ZodObject<{
|
|
|
380
380
|
bit_rate: z$1.ZodOptional<z$1.ZodString>;
|
|
381
381
|
disposition: z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>;
|
|
382
382
|
}, "strip", z$1.ZodTypeAny, {
|
|
383
|
-
width: number;
|
|
384
|
-
height: number;
|
|
385
383
|
index: number;
|
|
386
384
|
codec_name: string;
|
|
387
385
|
codec_long_name: string;
|
|
@@ -392,6 +390,8 @@ declare const ProbeSchema: z$1.ZodObject<{
|
|
|
392
390
|
avg_frame_rate: string;
|
|
393
391
|
time_base: string;
|
|
394
392
|
disposition: Record<string, unknown>;
|
|
393
|
+
width: number;
|
|
394
|
+
height: number;
|
|
395
395
|
coded_width: number;
|
|
396
396
|
coded_height: number;
|
|
397
397
|
start_pts?: number | undefined;
|
|
@@ -402,8 +402,6 @@ declare const ProbeSchema: z$1.ZodObject<{
|
|
|
402
402
|
profile?: string | undefined;
|
|
403
403
|
level?: number | undefined;
|
|
404
404
|
}, {
|
|
405
|
-
width: number;
|
|
406
|
-
height: number;
|
|
407
405
|
index: number;
|
|
408
406
|
codec_name: string;
|
|
409
407
|
codec_long_name: string;
|
|
@@ -414,6 +412,8 @@ declare const ProbeSchema: z$1.ZodObject<{
|
|
|
414
412
|
avg_frame_rate: string;
|
|
415
413
|
time_base: string;
|
|
416
414
|
disposition: Record<string, unknown>;
|
|
415
|
+
width: number;
|
|
416
|
+
height: number;
|
|
417
417
|
coded_width: number;
|
|
418
418
|
coded_height: number;
|
|
419
419
|
start_pts?: number | undefined;
|
|
@@ -512,8 +512,6 @@ declare const ProbeSchema: z$1.ZodObject<{
|
|
|
512
512
|
start_pts?: number | undefined;
|
|
513
513
|
start_time?: number | undefined;
|
|
514
514
|
} | {
|
|
515
|
-
width: number;
|
|
516
|
-
height: number;
|
|
517
515
|
index: number;
|
|
518
516
|
codec_name: string;
|
|
519
517
|
codec_long_name: string;
|
|
@@ -524,6 +522,8 @@ declare const ProbeSchema: z$1.ZodObject<{
|
|
|
524
522
|
avg_frame_rate: string;
|
|
525
523
|
time_base: string;
|
|
526
524
|
disposition: Record<string, unknown>;
|
|
525
|
+
width: number;
|
|
526
|
+
height: number;
|
|
527
527
|
coded_width: number;
|
|
528
528
|
coded_height: number;
|
|
529
529
|
start_pts?: number | undefined;
|
|
@@ -576,8 +576,6 @@ declare const ProbeSchema: z$1.ZodObject<{
|
|
|
576
576
|
start_pts?: number | undefined;
|
|
577
577
|
start_time?: number | undefined;
|
|
578
578
|
} | {
|
|
579
|
-
width: number;
|
|
580
|
-
height: number;
|
|
581
579
|
index: number;
|
|
582
580
|
codec_name: string;
|
|
583
581
|
codec_long_name: string;
|
|
@@ -588,6 +586,8 @@ declare const ProbeSchema: z$1.ZodObject<{
|
|
|
588
586
|
avg_frame_rate: string;
|
|
589
587
|
time_base: string;
|
|
590
588
|
disposition: Record<string, unknown>;
|
|
589
|
+
width: number;
|
|
590
|
+
height: number;
|
|
591
591
|
coded_width: number;
|
|
592
592
|
coded_height: number;
|
|
593
593
|
start_pts?: number | undefined;
|
|
@@ -757,8 +757,6 @@ declare const PacketProbeSchema: z$1.ZodObject<{
|
|
|
757
757
|
bit_rate: z$1.ZodOptional<z$1.ZodString>;
|
|
758
758
|
disposition: z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>;
|
|
759
759
|
}, "strip", z$1.ZodTypeAny, {
|
|
760
|
-
width: number;
|
|
761
|
-
height: number;
|
|
762
760
|
index: number;
|
|
763
761
|
codec_name: string;
|
|
764
762
|
codec_long_name: string;
|
|
@@ -769,6 +767,8 @@ declare const PacketProbeSchema: z$1.ZodObject<{
|
|
|
769
767
|
avg_frame_rate: string;
|
|
770
768
|
time_base: string;
|
|
771
769
|
disposition: Record<string, unknown>;
|
|
770
|
+
width: number;
|
|
771
|
+
height: number;
|
|
772
772
|
coded_width: number;
|
|
773
773
|
coded_height: number;
|
|
774
774
|
start_pts?: number | undefined;
|
|
@@ -779,8 +779,6 @@ declare const PacketProbeSchema: z$1.ZodObject<{
|
|
|
779
779
|
profile?: string | undefined;
|
|
780
780
|
level?: number | undefined;
|
|
781
781
|
}, {
|
|
782
|
-
width: number;
|
|
783
|
-
height: number;
|
|
784
782
|
index: number;
|
|
785
783
|
codec_name: string;
|
|
786
784
|
codec_long_name: string;
|
|
@@ -791,6 +789,8 @@ declare const PacketProbeSchema: z$1.ZodObject<{
|
|
|
791
789
|
avg_frame_rate: string;
|
|
792
790
|
time_base: string;
|
|
793
791
|
disposition: Record<string, unknown>;
|
|
792
|
+
width: number;
|
|
793
|
+
height: number;
|
|
794
794
|
coded_width: number;
|
|
795
795
|
coded_height: number;
|
|
796
796
|
start_pts?: number | undefined;
|
|
@@ -865,8 +865,6 @@ declare const PacketProbeSchema: z$1.ZodObject<{
|
|
|
865
865
|
start_pts?: number | undefined;
|
|
866
866
|
start_time?: number | undefined;
|
|
867
867
|
} | {
|
|
868
|
-
width: number;
|
|
869
|
-
height: number;
|
|
870
868
|
index: number;
|
|
871
869
|
codec_name: string;
|
|
872
870
|
codec_long_name: string;
|
|
@@ -877,6 +875,8 @@ declare const PacketProbeSchema: z$1.ZodObject<{
|
|
|
877
875
|
avg_frame_rate: string;
|
|
878
876
|
time_base: string;
|
|
879
877
|
disposition: Record<string, unknown>;
|
|
878
|
+
width: number;
|
|
879
|
+
height: number;
|
|
880
880
|
coded_width: number;
|
|
881
881
|
coded_height: number;
|
|
882
882
|
start_pts?: number | undefined;
|
|
@@ -939,8 +939,6 @@ declare const PacketProbeSchema: z$1.ZodObject<{
|
|
|
939
939
|
start_pts?: number | undefined;
|
|
940
940
|
start_time?: number | undefined;
|
|
941
941
|
} | {
|
|
942
|
-
width: number;
|
|
943
|
-
height: number;
|
|
944
942
|
index: number;
|
|
945
943
|
codec_name: string;
|
|
946
944
|
codec_long_name: string;
|
|
@@ -951,6 +949,8 @@ declare const PacketProbeSchema: z$1.ZodObject<{
|
|
|
951
949
|
avg_frame_rate: string;
|
|
952
950
|
time_base: string;
|
|
953
951
|
disposition: Record<string, unknown>;
|
|
952
|
+
width: number;
|
|
953
|
+
height: number;
|
|
954
954
|
coded_width: number;
|
|
955
955
|
coded_height: number;
|
|
956
956
|
start_pts?: number | undefined;
|
|
@@ -1039,8 +1039,6 @@ declare abstract class ProbeBase {
|
|
|
1039
1039
|
start_pts?: number | undefined;
|
|
1040
1040
|
start_time?: number | undefined;
|
|
1041
1041
|
} | {
|
|
1042
|
-
width: number;
|
|
1043
|
-
height: number;
|
|
1044
1042
|
index: number;
|
|
1045
1043
|
codec_name: string;
|
|
1046
1044
|
codec_long_name: string;
|
|
@@ -1051,6 +1049,8 @@ declare abstract class ProbeBase {
|
|
|
1051
1049
|
avg_frame_rate: string;
|
|
1052
1050
|
time_base: string;
|
|
1053
1051
|
disposition: Record<string, unknown>;
|
|
1052
|
+
width: number;
|
|
1053
|
+
height: number;
|
|
1054
1054
|
coded_width: number;
|
|
1055
1055
|
coded_height: number;
|
|
1056
1056
|
start_pts?: number | undefined;
|
|
@@ -1089,6 +1089,7 @@ declare abstract class ProbeBase {
|
|
|
1089
1089
|
get isMp3(): boolean;
|
|
1090
1090
|
get isVideoOnly(): boolean;
|
|
1091
1091
|
get mustProcess(): boolean;
|
|
1092
|
+
get startTimeOffsetMs(): number | undefined;
|
|
1092
1093
|
get audioTimebase(): {
|
|
1093
1094
|
num: number;
|
|
1094
1095
|
den: number;
|
package/dist/Probe.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { truncateDecimal } from "./truncateDecimal.js";
|
|
2
|
-
import {
|
|
3
|
-
import { promisify } from "node:util";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
4
3
|
import { createReadStream } from "node:fs";
|
|
5
4
|
import * as z$1 from "zod";
|
|
6
5
|
import debug from "debug";
|
|
7
6
|
|
|
8
7
|
//#region src/Probe.ts
|
|
9
|
-
const execPromise = promisify(exec);
|
|
10
8
|
const log = debug("ef:assets:probe");
|
|
11
9
|
const AudioStreamSchema = z$1.object({
|
|
12
10
|
index: z$1.number(),
|
|
@@ -111,12 +109,29 @@ const buildProbeArgs = (options) => {
|
|
|
111
109
|
};
|
|
112
110
|
var FFProbeRunner = class {
|
|
113
111
|
static async probePath(absolutePath, includePackets) {
|
|
114
|
-
const
|
|
115
|
-
log("Probing",
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
112
|
+
const args = [...buildProbeArgs({ showPackets: includePackets }), absolutePath];
|
|
113
|
+
log("Probing", "ffprobe", args);
|
|
114
|
+
const probe = spawn("ffprobe", args, { stdio: [
|
|
115
|
+
"ignore",
|
|
116
|
+
"pipe",
|
|
117
|
+
"pipe"
|
|
118
|
+
] });
|
|
119
|
+
const stdoutChunks = [];
|
|
120
|
+
const stderrChunks = [];
|
|
121
|
+
probe.stdout.on("data", (data) => stdoutChunks.push(data));
|
|
122
|
+
probe.stderr.on("data", (data) => stderrChunks.push(data));
|
|
123
|
+
await new Promise((resolve, reject) => {
|
|
124
|
+
probe.on("error", reject);
|
|
125
|
+
probe.on("close", (code) => {
|
|
126
|
+
if (code !== 0) {
|
|
127
|
+
const stderr = Buffer.concat(stderrChunks).toString("utf8");
|
|
128
|
+
reject(/* @__PURE__ */ new Error(`ffprobe exited with code ${code}: ${stderr}`));
|
|
129
|
+
} else resolve();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
const stdout = Buffer.concat(stdoutChunks).toString("utf8");
|
|
133
|
+
log("Probe result", stdout);
|
|
134
|
+
return JSON.parse(stdout);
|
|
120
135
|
}
|
|
121
136
|
static async probeStream(stream, includePackets) {
|
|
122
137
|
const probe = spawn("ffprobe", [
|
|
@@ -210,6 +225,11 @@ var ProbeBase = class {
|
|
|
210
225
|
get mustProcess() {
|
|
211
226
|
return this.mustReencodeAudio || this.mustReencodeVideo || this.mustRemux;
|
|
212
227
|
}
|
|
228
|
+
get startTimeOffsetMs() {
|
|
229
|
+
if (this.data.format.start_time && Number(this.data.format.start_time) !== 0) return Number(this.data.format.start_time) * 1e3;
|
|
230
|
+
const videoStream = this.videoStreams[0];
|
|
231
|
+
if (videoStream?.start_time && Number(videoStream.start_time) !== 0) return Number(videoStream.start_time) * 1e3;
|
|
232
|
+
}
|
|
213
233
|
get audioTimebase() {
|
|
214
234
|
const audioStream = this.audioStreams[0];
|
|
215
235
|
if (!audioStream) return null;
|
package/dist/Probe.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Probe.js","names":["z","chunks: Uint8Array[]","absolutePath: string"],"sources":["../src/Probe.ts"],"sourcesContent":["import { exec, spawn } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { createReadStream } from \"node:fs\";\n\nimport * as z from \"zod\";\nimport debug from \"debug\";\nimport type { Readable } from \"node:stream\";\nimport { truncateDecimal } from \"./truncateDecimal\";\n\nconst execPromise = promisify(exec);\n\nconst log = debug(\"ef:assets:probe\");\n\nexport const AudioStreamSchema = z.object({\n index: z.number(),\n codec_name: z.string(),\n codec_long_name: z.string(),\n codec_type: z.literal(\"audio\"),\n codec_tag_string: z.string(),\n codec_tag: z.string(),\n sample_fmt: z.string(),\n sample_rate: z.string(),\n channels: z.number(),\n channel_layout: z.string().optional(),\n bits_per_sample: z.number(),\n initial_padding: z.number().optional(),\n r_frame_rate: z.string(),\n avg_frame_rate: z.string(),\n time_base: z.string(),\n start_pts: z.number().optional(),\n start_time: z.coerce.number().optional(),\n duration_ts: z.number(),\n duration: z.coerce.number(),\n bit_rate: z.string(),\n disposition: z.record(z.unknown()),\n});\n\nexport type AudioStreamSchema = z.infer<typeof AudioStreamSchema>;\n\nexport const VideoStreamSchema = z.object({\n index: z.number(),\n codec_name: z.string(),\n codec_long_name: z.string(),\n codec_type: z.literal(\"video\"),\n codec_tag_string: z.string(),\n codec_tag: z.string(),\n profile: z.string().optional(),\n level: z.number().optional(),\n width: z.number(),\n height: z.number(),\n coded_width: z.number(),\n coded_height: z.number(),\n r_frame_rate: z.string(),\n avg_frame_rate: z.string(),\n time_base: z.string(),\n start_pts: z.number().optional(),\n start_time: z.coerce.number().optional(),\n duration_ts: z.number().optional(),\n duration: z.coerce.number().optional(),\n bit_rate: z.string().optional(),\n disposition: z.record(z.unknown()),\n});\n\nexport type VideoStreamSchema = z.infer<typeof VideoStreamSchema>;\n\nconst ProbeFormatSchema = z.object({\n filename: z.string(),\n nb_streams: z.number(),\n nb_programs: z.number(),\n format_name: z.string(),\n format_long_name: z.string(),\n start_time: z.string().optional(),\n duration: z.string().optional(),\n size: z.string().optional(),\n bit_rate: z.string().optional(),\n probe_score: z.number(),\n});\n\nexport const DataStreamSchema = z.object({\n index: z.number(),\n codec_type: z.literal(\"data\"),\n duration: z.string().optional(),\n duration_ts: z.number().optional(),\n start_pts: z.number().optional(),\n});\n\nexport type DataStreamSchema = z.infer<typeof DataStreamSchema>;\n\nconst StreamSchema = z.discriminatedUnion(\"codec_type\", [\n AudioStreamSchema,\n VideoStreamSchema,\n DataStreamSchema,\n]);\n\nexport type StreamSchema = z.infer<typeof StreamSchema>;\n\nconst PacketSchema = z.object({\n stream_index: z.number(),\n pts: z.number(),\n pts_time: z.coerce.number(),\n dts: z.number(),\n dts_time: z.coerce.number(),\n duration: z.coerce.number().optional(),\n pos: z.coerce.number().optional(),\n flags: z.string().optional(),\n});\n\nexport type PacketSchema = z.infer<typeof PacketSchema>;\n\nconst ProbeSchema = z.object({\n streams: z.array(StreamSchema),\n format: ProbeFormatSchema,\n});\n\nconst PacketProbeSchema = z.object({\n packets: z.array(PacketSchema),\n format: ProbeFormatSchema,\n streams: z.array(StreamSchema),\n});\n\nexport type ProbeSchema = z.infer<typeof ProbeSchema>;\nexport type PacketProbeSchema = z.infer<typeof PacketProbeSchema>;\n\nexport interface TrackSegment {\n cts: number;\n dts: number;\n duration: number;\n offset: number;\n size: number;\n}\n\nexport interface AudioTrackFragmentIndex {\n track: number;\n type: \"audio\";\n timescale: number;\n duration: number;\n channel_count: number;\n sample_rate: number;\n sample_size: number;\n sample_count: number;\n codec: string;\n startTimeOffsetMs?: number;\n initSegment: {\n offset: 0;\n size: number;\n };\n segments: Array<TrackSegment>;\n}\n\nexport interface VideoTrackFragmentIndex {\n track: number;\n type: \"video\";\n timescale: number;\n duration: number;\n width: number;\n height: number;\n sample_count: number;\n codec: string;\n startTimeOffsetMs?: number;\n initSegment: {\n offset: 0;\n size: number;\n };\n segments: Array<TrackSegment>;\n}\n\nexport type TrackFragmentIndex =\n | AudioTrackFragmentIndex\n | VideoTrackFragmentIndex;\n\nconst buildProbeArgs = (options: { showPackets?: boolean }) => {\n const streamEntries =\n \"stream=index,codec_name,codec_long_name,codec_type,codec_tag_string,codec_tag,profile,level,width,height,coded_width,coded_height,r_frame_rate,avg_frame_rate,time_base,start_pts,start_time,duration_ts,duration,bit_rate,sample_fmt,sample_rate,channels,channel_layout,bits_per_sample,initial_padding,disposition\";\n const packetEntries =\n \"packet=stream_index,pts,pts_time,dts,dts_time,duration,pos,flags\";\n\n return [\n \"-v\",\n \"error\",\n \"-show_format\",\n \"-show_streams\",\n \"-of\",\n \"json\",\n ...(options.showPackets\n ? [\"-show_entries\", `${streamEntries}:${packetEntries}`]\n : [\"-show_entries\", streamEntries]),\n ];\n};\n\nclass FFProbeRunner {\n static async probePath(\n absolutePath: string,\n includePackets: boolean,\n ): Promise<any> {\n const probeCommand = `ffprobe ${buildProbeArgs({ showPackets: includePackets }).join(\" \")} ${absolutePath}`;\n log(\"Probing\", probeCommand);\n const probeResult = await execPromise(probeCommand);\n log(\"Probe result\", probeResult.stdout);\n log(\"Probe stderr\", probeResult.stderr);\n return JSON.parse(probeResult.stdout);\n }\n\n static async probeStream(\n stream: Readable,\n includePackets: boolean,\n ): Promise<any> {\n const probe = spawn(\n \"ffprobe\",\n [\"-i\", \"-\", ...buildProbeArgs({ showPackets: includePackets })],\n { stdio: [\"pipe\", \"pipe\", \"pipe\"] },\n );\n\n const chunks: Uint8Array[] = [];\n\n // Handle process exit/error before data processing\n const processExit = new Promise<never>((_, reject) => {\n probe.on(\"exit\", (code) => {\n if (code !== 0) {\n reject(new Error(`ffprobe exited with code ${code}`));\n }\n });\n probe.on(\"error\", (err) => reject(err));\n });\n\n probe.stderr.on(\"data\", (data) => {\n log(data.toString());\n });\n\n probe.stdout.on(\"data\", (data) => {\n chunks.push(data);\n });\n\n // Handle pipe errors\n probe.stdin.on(\"error\", (error: NodeJS.ErrnoException) => {\n if (error.code === \"EPIPE\") {\n log(\"ffprobe closed input pipe\");\n return;\n }\n log(\"ffprobe stdin error\", error);\n });\n\n stream.pipe(probe.stdin);\n\n try {\n const json = await Promise.race([\n new Promise<any>((resolve, reject) => {\n probe.stdout.on(\"end\", () => {\n try {\n const buffer = Buffer.concat(chunks).toString(\"utf8\");\n resolve(JSON.parse(buffer));\n } catch (error) {\n reject(error);\n }\n });\n }),\n processExit,\n ]);\n\n return json;\n } finally {\n // Clean up regardless of success or failure\n stream.unpipe(probe.stdin);\n probe.stdin.end();\n stream.destroy();\n }\n }\n}\n\nabstract class ProbeBase {\n abstract data: ProbeSchema | PacketProbeSchema;\n\n get audioStreams() {\n return this.data.streams.filter(\n (stream) => stream.codec_type === \"audio\",\n ) as AudioStreamSchema[];\n }\n\n get videoStreams() {\n return this.data.streams.filter(\n (stream) => stream.codec_type === \"video\",\n ) as VideoStreamSchema[];\n }\n\n get streams() {\n return this.data.streams;\n }\n\n get format() {\n return this.data.format;\n }\n\n get mustReencodeAudio() {\n return this.audioStreams.some((stream) => stream.codec_name !== \"aac\");\n }\n\n get mustReencodeVideo() {\n return false;\n }\n\n get mustRemux() {\n return (\n this.format.format_name !== \"mp4\" ||\n this.data.streams.some(\n (stream) =>\n stream.codec_type !== \"audio\" && stream.codec_type !== \"video\",\n )\n );\n }\n\n get hasNonAudioOrVideoStreams() {\n return this.data.streams.some(\n (stream) =>\n stream.codec_type !== \"audio\" && stream.codec_type !== \"video\",\n );\n }\n\n get hasAudio() {\n return this.audioStreams.length > 0;\n }\n\n get hasVideo() {\n return this.videoStreams.length > 0;\n }\n\n get isAudioOnly() {\n return this.audioStreams.length > 0 && this.videoStreams.length === 0;\n }\n\n get isMp3() {\n return this.audioStreams.some((stream) => stream.codec_name === \"mp3\");\n }\n\n get isVideoOnly() {\n return this.audioStreams.length === 0 && this.videoStreams.length > 0;\n }\n\n get mustProcess() {\n return this.mustReencodeAudio || this.mustReencodeVideo || this.mustRemux;\n }\n\n get audioTimebase() {\n const audioStream = this.audioStreams[0];\n if (!audioStream) {\n return null;\n }\n const [num, den] = audioStream.time_base.split(\"/\").map(Number);\n if (num === undefined || den === undefined) {\n return null;\n }\n return { num, den };\n }\n\n get videoTimebase() {\n const videoStream = this.videoStreams[0];\n if (!videoStream) {\n return null;\n }\n const [num, den] = videoStream.time_base.split(\"/\").map(Number);\n if (num === undefined || den === undefined) {\n return null;\n }\n return { num, den };\n }\n\n get ffmpegAudioInputOptions() {\n if (!this.hasAudio) {\n return [];\n }\n if (this.isMp3) {\n return [\"-c:a\", \"mp3\"];\n }\n return [];\n }\n\n get ffmpegVideoInputOptions() {\n return [];\n }\n\n get ffmpegAudioOutputOptions() {\n if (!this.hasAudio) {\n return [];\n }\n if (this.mustReencodeAudio) {\n // biome-ignore format: keep cli argument paired together\n return [\"-c:a\", \"aac\", \"-b:a\", \"192k\", \"-ar\", \"48000\"];\n }\n return [\"-c:a\", \"copy\"];\n }\n\n get ffmpegVideoOutputOptions() {\n if (!this.hasVideo) {\n return [];\n }\n if (this.mustReencodeVideo) {\n // biome-ignore format: keep cli argument paired together\n return [\n \"-c:v\",\n \"h264\",\n // Filter out SEI NAL units that aren't supported by the webcodecs decoder\n \"-bsf:v\",\n \"filter_units=remove_types=6\",\n \"-pix_fmt\",\n \"yuv420p\",\n ];\n }\n // biome-ignore format: keep cli argument paired together\n return [\n \"-c:v\",\n \"copy\",\n // Filter out SEI NAL units that aren't supported by the webcodecs decoder\n \"-bsf:v\",\n \"filter_units=remove_types=6\",\n ];\n }\n\n protected constructor(protected absolutePath: string) {}\n\n createConformingReadstream() {\n if (this.absolutePath === \"pipe:0\") {\n throw new Error(\"Cannot create conforming readstream from pipe\");\n }\n if (!this.mustProcess) {\n return createReadStream(this.absolutePath);\n }\n\n const fragmenterArgs = this.isAudioOnly\n ? [\n \"-movflags\",\n \"frag_keyframe\",\n \"-frag_duration\",\n \"4000000\", // Fragment every 4 seconds (in microseconds)\n ]\n : [\"-movflags\", \"frag_keyframe\"];\n\n // biome-ignore format: keep cli argument paired together\n const ffmpegConformanceArgs = [\n ...this.ffmpegAudioInputOptions,\n ...this.ffmpegVideoInputOptions,\n \"-i\",\n this.absolutePath,\n ...this.ffmpegAudioOutputOptions,\n ...this.ffmpegVideoOutputOptions,\n \"-f\",\n \"mp4\",\n \"-bitexact\", // Ensure deterministic output\n ...fragmenterArgs,\n \"pipe:1\",\n ];\n\n log(\"Running ffmpeg\", ffmpegConformanceArgs);\n\n const ffmpegConformer = spawn(\"ffmpeg\", ffmpegConformanceArgs, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n ffmpegConformer.stderr.on(\"data\", (data) => {\n log(\"CONFORMER: \", data.toString());\n });\n\n // biome-ignore format: keep cli argument paired together\n const ffmpegFragmentArgs = [\n \"-i\",\n \"-\",\n \"-c\",\n \"copy\",\n \"-f\",\n \"mp4\",\n \"-bitexact\", // Ensure deterministic output\n ...fragmenterArgs,\n \"pipe:1\",\n ];\n\n log(\"Running ffmpeg\", ffmpegFragmentArgs);\n\n const ffmpegFragmenter = spawn(\"ffmpeg\", ffmpegFragmentArgs, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n ffmpegConformer.stdout.pipe(ffmpegFragmenter.stdin);\n ffmpegFragmenter.stderr.on(\"data\", (data) => {\n log(\"FRAGMENTER: \", data.toString());\n });\n\n ffmpegConformer.on(\"error\", (error) => {\n ffmpegFragmenter.stdout.emit(\"error\", error);\n });\n\n ffmpegFragmenter.on(\"error\", (error) => {\n ffmpegFragmenter.stdout.emit(\"error\", error);\n });\n\n return ffmpegFragmenter.stdout;\n }\n\n createTrackReadstream(trackIndex: number) {\n if (this.absolutePath === \"pipe:0\") {\n throw new Error(\"Cannot create track readstream from pipe\");\n }\n\n const track = this.data.streams[trackIndex];\n if (!track) {\n throw new Error(`Track ${trackIndex} not found`);\n }\n\n const isAudioTrack = track.codec_type === \"audio\";\n const isVideoTrack = track.codec_type === \"video\";\n\n if (!isAudioTrack && !isVideoTrack) {\n throw new Error(`Track ${trackIndex} is not audio or video`);\n }\n\n const fragmenterArgs = isAudioTrack\n ? [\n \"-movflags\",\n \"empty_moov+default_base_moof\",\n \"-frag_duration\",\n \"4000000\", // Fragment every 4 seconds (in microseconds)\n ]\n : [\"-movflags\", \"frag_keyframe+empty_moov+default_base_moof\"];\n\n // Create single-track MP4 with proper fragmentation\n // Use conforming stream system to handle codec compatibility\n const codecOptions =\n isAudioTrack && this.mustReencodeAudio\n ? this.ffmpegAudioOutputOptions\n : [\"-c\", \"copy\"];\n\n // Filter out SEI NAL units (type 6) for video tracks\n // These can cause WebCodecs VideoDecoder to hang or crash in some browsers/Electron\n const bitstreamFilter = isVideoTrack\n ? [\"-bsf:v\", \"filter_units=remove_types=6\"]\n : [];\n\n const ffmpegArgs = [\n ...this.ffmpegAudioInputOptions,\n ...this.ffmpegVideoInputOptions,\n \"-i\",\n this.absolutePath,\n \"-map\",\n `0:${trackIndex}`, // Select only this track\n ...codecOptions, // Use conforming stream codec options\n ...bitstreamFilter, // Remove SEI NAL units that cause WebCodecs issues\n \"-f\",\n \"mp4\",\n \"-bitexact\", // Ensure deterministic output\n ...fragmenterArgs,\n \"pipe:1\",\n ];\n\n log(\"Creating track stream\", ffmpegArgs);\n\n const ffmpegProcess = spawn(\"ffmpeg\", ffmpegArgs, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n ffmpegProcess.stderr.on(\"data\", (data) => {\n log(`TRACK ${trackIndex}: `, data.toString());\n });\n\n ffmpegProcess.on(\"error\", (error) => {\n ffmpegProcess.stdout.emit(\"error\", error);\n });\n\n return ffmpegProcess.stdout;\n }\n\n createScrubTrackReadstream() {\n if (this.absolutePath === \"pipe:0\") {\n throw new Error(\"Cannot create scrub track readstream from pipe\");\n }\n\n const videoStream = this.videoStreams[0];\n if (!videoStream) {\n throw new Error(\"No video stream found for scrub track generation\");\n }\n\n // Calculate proportional height for 320px width\n const targetWidth = 320;\n const aspectRatio = videoStream.height / videoStream.width;\n const targetHeight = Math.round(targetWidth * aspectRatio);\n // Ensure height is even (required for H.264)\n const scrubHeight =\n targetHeight % 2 === 0 ? targetHeight : targetHeight + 1;\n\n // Parse frame rate from r_frame_rate (e.g., \"30/1\" or \"30000/1001\")\n const [fpsNum, fpsDen] = videoStream.r_frame_rate.split(\"/\").map(Number);\n const frameRate = fpsNum && fpsDen ? `${fpsNum}/${fpsDen}` : \"30/1\";\n\n // Scrub track uses 30-second fragments with keyframes every 10 frames for fast seeking.\n // NOTE: Do NOT use frag_keyframe - it would create a fragment at every keyframe.\n // We want multiple keyframes within a single 30-second fragment (single trun with many samples).\n const fragmenterArgs = [\n \"-movflags\",\n \"empty_moov+default_base_moof\",\n \"-frag_duration\",\n \"30000000\", // 30 seconds in microseconds\n ];\n\n // Transcode to low-res H.264 with keyframes every 10 frames for fast seeking\n const ffmpegArgs = [\n ...this.ffmpegAudioInputOptions,\n ...this.ffmpegVideoInputOptions,\n \"-i\",\n this.absolutePath,\n \"-map\",\n \"0:v:0\", // Select first video stream only (no audio for scrub)\n \"-c:v\",\n \"libx264\", // Encode to H.264\n \"-preset\",\n \"ultrafast\", // Fast encoding for scrub track\n \"-crf\",\n \"28\", // Lower quality for smaller file size\n \"-vf\",\n `scale=${targetWidth}:${scrubHeight}`, // Scale to scrub resolution\n \"-r\",\n frameRate, // Maintain native FPS\n \"-g\",\n \"10\", // Keyframe every 10 frames for fast seeking within fragments\n \"-f\",\n \"mp4\",\n \"-bitexact\", // Ensure deterministic output\n ...fragmenterArgs,\n \"pipe:1\",\n ];\n\n log(\"Creating scrub track stream\", ffmpegArgs);\n\n const ffmpegProcess = spawn(\"ffmpeg\", ffmpegArgs, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n ffmpegProcess.stderr.on(\"data\", (data) => {\n log(\"SCRUB TRACK: \", data.toString());\n });\n\n ffmpegProcess.on(\"error\", (error) => {\n ffmpegProcess.stdout.emit(\"error\", error);\n });\n\n // Handle FFmpeg process exit\n ffmpegProcess.on(\"exit\", (code, signal) => {\n if (code !== 0 && code !== null) {\n const error = new Error(\n `FFmpeg scrub track process exited with code ${code}${signal ? ` and signal ${signal}` : \"\"}`,\n );\n ffmpegProcess.stdout.emit(\"error\", error);\n }\n });\n\n return ffmpegProcess.stdout;\n }\n}\n\nexport class Probe extends ProbeBase {\n data: ProbeSchema;\n\n static async probePath(absolutePath: string): Promise<Probe> {\n const json = await FFProbeRunner.probePath(absolutePath, false);\n return new Probe(absolutePath, json);\n }\n\n static async probeStream(stream: Readable): Promise<Probe> {\n const json = await FFProbeRunner.probeStream(stream, false);\n return new Probe(\"pipe:0\", json);\n }\n\n constructor(absolutePath: string, rawData: any) {\n super(absolutePath);\n this.data = ProbeSchema.parse(rawData);\n }\n}\n\nexport class PacketProbe extends ProbeBase {\n data: PacketProbeSchema;\n\n static async probePath(absolutePath: string): Promise<PacketProbe> {\n const json = await FFProbeRunner.probePath(absolutePath, true);\n return new PacketProbe(absolutePath, json);\n }\n\n static async probeStream(stream: Readable): Promise<PacketProbe> {\n const json = await FFProbeRunner.probeStream(stream, true);\n return new PacketProbe(\"pipe:0\", json);\n }\n\n constructor(absolutePath: string, rawData: any) {\n super(absolutePath);\n this.data = PacketProbeSchema.parse(rawData);\n }\n\n get packets() {\n return this.data.packets;\n }\n\n get bestEffortAudioDuration() {\n const stream = this.audioStreams[0];\n if (!stream) {\n throw new Error(\"No audio stream found\");\n }\n return truncateDecimal(\n ((stream.duration_ts ?? 0) - (stream.start_pts ?? 0)) /\n (this.audioTimebase?.den ?? 0),\n 5,\n );\n }\n\n get videoPacketDuration() {\n const videoStream = this.videoStreams[0];\n if (!videoStream) {\n return [];\n }\n const videoPackets = this.packets.filter(\n (packet) => packet.stream_index === videoStream.index,\n );\n\n const frameRate = videoStream.r_frame_rate;\n const [num, den] = frameRate.split(\"/\").map(Number);\n if (!num || !den) {\n return [];\n }\n const packetDuration = den / num;\n\n // Calculate duration using actual packet PTS timing data\n if (videoPackets.length === 0) {\n return [];\n }\n\n const ptsTimes = videoPackets.map((p) => p.pts_time);\n const minPts = Math.min(...ptsTimes);\n const maxPts = Math.max(...ptsTimes);\n const totalDuration = maxPts - minPts + packetDuration;\n\n return truncateDecimal(Math.round(totalDuration * 10000) / 10000, 5);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Probe.js","names":["z","stdoutChunks: Buffer[]","stderrChunks: Buffer[]","chunks: Uint8Array[]","absolutePath: string"],"sources":["../src/Probe.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { createReadStream } from \"node:fs\";\n\nimport * as z from \"zod\";\nimport debug from \"debug\";\nimport type { Readable } from \"node:stream\";\nimport { truncateDecimal } from \"./truncateDecimal\";\n\nconst log = debug(\"ef:assets:probe\");\n\nexport const AudioStreamSchema = z.object({\n index: z.number(),\n codec_name: z.string(),\n codec_long_name: z.string(),\n codec_type: z.literal(\"audio\"),\n codec_tag_string: z.string(),\n codec_tag: z.string(),\n sample_fmt: z.string(),\n sample_rate: z.string(),\n channels: z.number(),\n channel_layout: z.string().optional(),\n bits_per_sample: z.number(),\n initial_padding: z.number().optional(),\n r_frame_rate: z.string(),\n avg_frame_rate: z.string(),\n time_base: z.string(),\n start_pts: z.number().optional(),\n start_time: z.coerce.number().optional(),\n duration_ts: z.number(),\n duration: z.coerce.number(),\n bit_rate: z.string(),\n disposition: z.record(z.unknown()),\n});\n\nexport type AudioStreamSchema = z.infer<typeof AudioStreamSchema>;\n\nexport const VideoStreamSchema = z.object({\n index: z.number(),\n codec_name: z.string(),\n codec_long_name: z.string(),\n codec_type: z.literal(\"video\"),\n codec_tag_string: z.string(),\n codec_tag: z.string(),\n profile: z.string().optional(),\n level: z.number().optional(),\n width: z.number(),\n height: z.number(),\n coded_width: z.number(),\n coded_height: z.number(),\n r_frame_rate: z.string(),\n avg_frame_rate: z.string(),\n time_base: z.string(),\n start_pts: z.number().optional(),\n start_time: z.coerce.number().optional(),\n duration_ts: z.number().optional(),\n duration: z.coerce.number().optional(),\n bit_rate: z.string().optional(),\n disposition: z.record(z.unknown()),\n});\n\nexport type VideoStreamSchema = z.infer<typeof VideoStreamSchema>;\n\nconst ProbeFormatSchema = z.object({\n filename: z.string(),\n nb_streams: z.number(),\n nb_programs: z.number(),\n format_name: z.string(),\n format_long_name: z.string(),\n start_time: z.string().optional(),\n duration: z.string().optional(),\n size: z.string().optional(),\n bit_rate: z.string().optional(),\n probe_score: z.number(),\n});\n\nexport const DataStreamSchema = z.object({\n index: z.number(),\n codec_type: z.literal(\"data\"),\n duration: z.string().optional(),\n duration_ts: z.number().optional(),\n start_pts: z.number().optional(),\n});\n\nexport type DataStreamSchema = z.infer<typeof DataStreamSchema>;\n\nconst StreamSchema = z.discriminatedUnion(\"codec_type\", [\n AudioStreamSchema,\n VideoStreamSchema,\n DataStreamSchema,\n]);\n\nexport type StreamSchema = z.infer<typeof StreamSchema>;\n\nconst PacketSchema = z.object({\n stream_index: z.number(),\n pts: z.number(),\n pts_time: z.coerce.number(),\n dts: z.number(),\n dts_time: z.coerce.number(),\n duration: z.coerce.number().optional(),\n pos: z.coerce.number().optional(),\n flags: z.string().optional(),\n});\n\nexport type PacketSchema = z.infer<typeof PacketSchema>;\n\nconst ProbeSchema = z.object({\n streams: z.array(StreamSchema),\n format: ProbeFormatSchema,\n});\n\nconst PacketProbeSchema = z.object({\n packets: z.array(PacketSchema),\n format: ProbeFormatSchema,\n streams: z.array(StreamSchema),\n});\n\nexport type ProbeSchema = z.infer<typeof ProbeSchema>;\nexport type PacketProbeSchema = z.infer<typeof PacketProbeSchema>;\n\nexport interface TrackSegment {\n cts: number;\n dts: number;\n duration: number;\n offset: number;\n size: number;\n}\n\nexport interface AudioTrackFragmentIndex {\n track: number;\n type: \"audio\";\n timescale: number;\n duration: number;\n channel_count: number;\n sample_rate: number;\n sample_size: number;\n sample_count: number;\n codec: string;\n startTimeOffsetMs?: number;\n initSegment: {\n offset: 0;\n size: number;\n };\n segments: Array<TrackSegment>;\n}\n\nexport interface VideoTrackFragmentIndex {\n track: number;\n type: \"video\";\n timescale: number;\n duration: number;\n width: number;\n height: number;\n sample_count: number;\n codec: string;\n startTimeOffsetMs?: number;\n initSegment: {\n offset: 0;\n size: number;\n };\n segments: Array<TrackSegment>;\n}\n\nexport type TrackFragmentIndex =\n | AudioTrackFragmentIndex\n | VideoTrackFragmentIndex;\n\nconst buildProbeArgs = (options: { showPackets?: boolean }) => {\n const streamEntries =\n \"stream=index,codec_name,codec_long_name,codec_type,codec_tag_string,codec_tag,profile,level,width,height,coded_width,coded_height,r_frame_rate,avg_frame_rate,time_base,start_pts,start_time,duration_ts,duration,bit_rate,sample_fmt,sample_rate,channels,channel_layout,bits_per_sample,initial_padding,disposition\";\n const packetEntries =\n \"packet=stream_index,pts,pts_time,dts,dts_time,duration,pos,flags\";\n\n return [\n \"-v\",\n \"error\",\n \"-show_format\",\n \"-show_streams\",\n \"-of\",\n \"json\",\n ...(options.showPackets\n ? [\"-show_entries\", `${streamEntries}:${packetEntries}`]\n : [\"-show_entries\", streamEntries]),\n ];\n};\n\nclass FFProbeRunner {\n static async probePath(\n absolutePath: string,\n includePackets: boolean,\n ): Promise<any> {\n const args = [\n ...buildProbeArgs({ showPackets: includePackets }),\n absolutePath,\n ];\n log(\"Probing\", \"ffprobe\", args);\n\n const probe = spawn(\"ffprobe\", args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n probe.stdout.on(\"data\", (data: Buffer) => stdoutChunks.push(data));\n probe.stderr.on(\"data\", (data: Buffer) => stderrChunks.push(data));\n\n await new Promise<void>((resolve, reject) => {\n probe.on(\"error\", reject);\n probe.on(\"close\", (code) => {\n if (code !== 0) {\n const stderr = Buffer.concat(stderrChunks).toString(\"utf8\");\n reject(new Error(`ffprobe exited with code ${code}: ${stderr}`));\n } else {\n resolve();\n }\n });\n });\n\n const stdout = Buffer.concat(stdoutChunks).toString(\"utf8\");\n log(\"Probe result\", stdout);\n return JSON.parse(stdout);\n }\n\n static async probeStream(\n stream: Readable,\n includePackets: boolean,\n ): Promise<any> {\n const probe = spawn(\n \"ffprobe\",\n [\"-i\", \"-\", ...buildProbeArgs({ showPackets: includePackets })],\n { stdio: [\"pipe\", \"pipe\", \"pipe\"] },\n );\n\n const chunks: Uint8Array[] = [];\n\n // Handle process exit/error before data processing\n const processExit = new Promise<never>((_, reject) => {\n probe.on(\"exit\", (code) => {\n if (code !== 0) {\n reject(new Error(`ffprobe exited with code ${code}`));\n }\n });\n probe.on(\"error\", (err) => reject(err));\n });\n\n probe.stderr.on(\"data\", (data) => {\n log(data.toString());\n });\n\n probe.stdout.on(\"data\", (data) => {\n chunks.push(data);\n });\n\n // Handle pipe errors\n probe.stdin.on(\"error\", (error: NodeJS.ErrnoException) => {\n if (error.code === \"EPIPE\") {\n log(\"ffprobe closed input pipe\");\n return;\n }\n log(\"ffprobe stdin error\", error);\n });\n\n stream.pipe(probe.stdin);\n\n try {\n const json = await Promise.race([\n new Promise<any>((resolve, reject) => {\n probe.stdout.on(\"end\", () => {\n try {\n const buffer = Buffer.concat(chunks).toString(\"utf8\");\n resolve(JSON.parse(buffer));\n } catch (error) {\n reject(error);\n }\n });\n }),\n processExit,\n ]);\n\n return json;\n } finally {\n // Clean up regardless of success or failure\n stream.unpipe(probe.stdin);\n probe.stdin.end();\n stream.destroy();\n }\n }\n}\n\nabstract class ProbeBase {\n abstract data: ProbeSchema | PacketProbeSchema;\n\n get audioStreams() {\n return this.data.streams.filter(\n (stream) => stream.codec_type === \"audio\",\n ) as AudioStreamSchema[];\n }\n\n get videoStreams() {\n return this.data.streams.filter(\n (stream) => stream.codec_type === \"video\",\n ) as VideoStreamSchema[];\n }\n\n get streams() {\n return this.data.streams;\n }\n\n get format() {\n return this.data.format;\n }\n\n get mustReencodeAudio() {\n return this.audioStreams.some((stream) => stream.codec_name !== \"aac\");\n }\n\n get mustReencodeVideo() {\n return false;\n }\n\n get mustRemux() {\n return (\n this.format.format_name !== \"mp4\" ||\n this.data.streams.some(\n (stream) =>\n stream.codec_type !== \"audio\" && stream.codec_type !== \"video\",\n )\n );\n }\n\n get hasNonAudioOrVideoStreams() {\n return this.data.streams.some(\n (stream) =>\n stream.codec_type !== \"audio\" && stream.codec_type !== \"video\",\n );\n }\n\n get hasAudio() {\n return this.audioStreams.length > 0;\n }\n\n get hasVideo() {\n return this.videoStreams.length > 0;\n }\n\n get isAudioOnly() {\n return this.audioStreams.length > 0 && this.videoStreams.length === 0;\n }\n\n get isMp3() {\n return this.audioStreams.some((stream) => stream.codec_name === \"mp3\");\n }\n\n get isVideoOnly() {\n return this.audioStreams.length === 0 && this.videoStreams.length > 0;\n }\n\n get mustProcess() {\n return this.mustReencodeAudio || this.mustReencodeVideo || this.mustRemux;\n }\n\n get startTimeOffsetMs(): number | undefined {\n if (\n this.data.format.start_time &&\n Number(this.data.format.start_time) !== 0\n ) {\n return Number(this.data.format.start_time) * 1000;\n }\n const videoStream = this.videoStreams[0];\n if (videoStream?.start_time && Number(videoStream.start_time) !== 0) {\n return Number(videoStream.start_time) * 1000;\n }\n return undefined;\n }\n\n get audioTimebase() {\n const audioStream = this.audioStreams[0];\n if (!audioStream) {\n return null;\n }\n const [num, den] = audioStream.time_base.split(\"/\").map(Number);\n if (num === undefined || den === undefined) {\n return null;\n }\n return { num, den };\n }\n\n get videoTimebase() {\n const videoStream = this.videoStreams[0];\n if (!videoStream) {\n return null;\n }\n const [num, den] = videoStream.time_base.split(\"/\").map(Number);\n if (num === undefined || den === undefined) {\n return null;\n }\n return { num, den };\n }\n\n get ffmpegAudioInputOptions() {\n if (!this.hasAudio) {\n return [];\n }\n if (this.isMp3) {\n return [\"-c:a\", \"mp3\"];\n }\n return [];\n }\n\n get ffmpegVideoInputOptions() {\n return [];\n }\n\n get ffmpegAudioOutputOptions() {\n if (!this.hasAudio) {\n return [];\n }\n if (this.mustReencodeAudio) {\n // biome-ignore format: keep cli argument paired together\n return [\"-c:a\", \"aac\", \"-b:a\", \"192k\", \"-ar\", \"48000\"];\n }\n return [\"-c:a\", \"copy\"];\n }\n\n get ffmpegVideoOutputOptions() {\n if (!this.hasVideo) {\n return [];\n }\n if (this.mustReencodeVideo) {\n // biome-ignore format: keep cli argument paired together\n return [\n \"-c:v\",\n \"h264\",\n // Filter out SEI NAL units that aren't supported by the webcodecs decoder\n \"-bsf:v\",\n \"filter_units=remove_types=6\",\n \"-pix_fmt\",\n \"yuv420p\",\n ];\n }\n // biome-ignore format: keep cli argument paired together\n return [\n \"-c:v\",\n \"copy\",\n // Filter out SEI NAL units that aren't supported by the webcodecs decoder\n \"-bsf:v\",\n \"filter_units=remove_types=6\",\n ];\n }\n\n protected constructor(protected absolutePath: string) {}\n\n createConformingReadstream() {\n if (this.absolutePath === \"pipe:0\") {\n throw new Error(\"Cannot create conforming readstream from pipe\");\n }\n if (!this.mustProcess) {\n return createReadStream(this.absolutePath);\n }\n\n const fragmenterArgs = this.isAudioOnly\n ? [\n \"-movflags\",\n \"frag_keyframe\",\n \"-frag_duration\",\n \"4000000\", // Fragment every 4 seconds (in microseconds)\n ]\n : [\"-movflags\", \"frag_keyframe\"];\n\n // biome-ignore format: keep cli argument paired together\n const ffmpegConformanceArgs = [\n ...this.ffmpegAudioInputOptions,\n ...this.ffmpegVideoInputOptions,\n \"-i\",\n this.absolutePath,\n ...this.ffmpegAudioOutputOptions,\n ...this.ffmpegVideoOutputOptions,\n \"-f\",\n \"mp4\",\n \"-bitexact\", // Ensure deterministic output\n ...fragmenterArgs,\n \"pipe:1\",\n ];\n\n log(\"Running ffmpeg\", ffmpegConformanceArgs);\n\n const ffmpegConformer = spawn(\"ffmpeg\", ffmpegConformanceArgs, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n ffmpegConformer.stderr.on(\"data\", (data) => {\n log(\"CONFORMER: \", data.toString());\n });\n\n // biome-ignore format: keep cli argument paired together\n const ffmpegFragmentArgs = [\n \"-i\",\n \"-\",\n \"-c\",\n \"copy\",\n \"-f\",\n \"mp4\",\n \"-bitexact\", // Ensure deterministic output\n ...fragmenterArgs,\n \"pipe:1\",\n ];\n\n log(\"Running ffmpeg\", ffmpegFragmentArgs);\n\n const ffmpegFragmenter = spawn(\"ffmpeg\", ffmpegFragmentArgs, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n ffmpegConformer.stdout.pipe(ffmpegFragmenter.stdin);\n ffmpegFragmenter.stderr.on(\"data\", (data) => {\n log(\"FRAGMENTER: \", data.toString());\n });\n\n ffmpegConformer.on(\"error\", (error) => {\n ffmpegFragmenter.stdout.emit(\"error\", error);\n });\n\n ffmpegFragmenter.on(\"error\", (error) => {\n ffmpegFragmenter.stdout.emit(\"error\", error);\n });\n\n return ffmpegFragmenter.stdout;\n }\n\n createTrackReadstream(trackIndex: number) {\n if (this.absolutePath === \"pipe:0\") {\n throw new Error(\"Cannot create track readstream from pipe\");\n }\n\n const track = this.data.streams[trackIndex];\n if (!track) {\n throw new Error(`Track ${trackIndex} not found`);\n }\n\n const isAudioTrack = track.codec_type === \"audio\";\n const isVideoTrack = track.codec_type === \"video\";\n\n if (!isAudioTrack && !isVideoTrack) {\n throw new Error(`Track ${trackIndex} is not audio or video`);\n }\n\n const fragmenterArgs = isAudioTrack\n ? [\n \"-movflags\",\n \"empty_moov+default_base_moof\",\n \"-frag_duration\",\n \"4000000\", // Fragment every 4 seconds (in microseconds)\n ]\n : [\"-movflags\", \"frag_keyframe+empty_moov+default_base_moof\"];\n\n // Create single-track MP4 with proper fragmentation\n // Use conforming stream system to handle codec compatibility\n const codecOptions =\n isAudioTrack && this.mustReencodeAudio\n ? this.ffmpegAudioOutputOptions\n : [\"-c\", \"copy\"];\n\n // Filter out SEI NAL units (type 6) for video tracks\n // These can cause WebCodecs VideoDecoder to hang or crash in some browsers/Electron\n const bitstreamFilter = isVideoTrack\n ? [\"-bsf:v\", \"filter_units=remove_types=6\"]\n : [];\n\n const ffmpegArgs = [\n ...this.ffmpegAudioInputOptions,\n ...this.ffmpegVideoInputOptions,\n \"-i\",\n this.absolutePath,\n \"-map\",\n `0:${trackIndex}`, // Select only this track\n ...codecOptions, // Use conforming stream codec options\n ...bitstreamFilter, // Remove SEI NAL units that cause WebCodecs issues\n \"-f\",\n \"mp4\",\n \"-bitexact\", // Ensure deterministic output\n ...fragmenterArgs,\n \"pipe:1\",\n ];\n\n log(\"Creating track stream\", ffmpegArgs);\n\n const ffmpegProcess = spawn(\"ffmpeg\", ffmpegArgs, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n ffmpegProcess.stderr.on(\"data\", (data) => {\n log(`TRACK ${trackIndex}: `, data.toString());\n });\n\n ffmpegProcess.on(\"error\", (error) => {\n ffmpegProcess.stdout.emit(\"error\", error);\n });\n\n return ffmpegProcess.stdout;\n }\n\n createScrubTrackReadstream() {\n if (this.absolutePath === \"pipe:0\") {\n throw new Error(\"Cannot create scrub track readstream from pipe\");\n }\n\n const videoStream = this.videoStreams[0];\n if (!videoStream) {\n throw new Error(\"No video stream found for scrub track generation\");\n }\n\n // Calculate proportional height for 320px width\n const targetWidth = 320;\n const aspectRatio = videoStream.height / videoStream.width;\n const targetHeight = Math.round(targetWidth * aspectRatio);\n // Ensure height is even (required for H.264)\n const scrubHeight =\n targetHeight % 2 === 0 ? targetHeight : targetHeight + 1;\n\n // Parse frame rate from r_frame_rate (e.g., \"30/1\" or \"30000/1001\")\n const [fpsNum, fpsDen] = videoStream.r_frame_rate.split(\"/\").map(Number);\n const frameRate = fpsNum && fpsDen ? `${fpsNum}/${fpsDen}` : \"30/1\";\n\n // Scrub track uses 30-second fragments with keyframes every 10 frames for fast seeking.\n // NOTE: Do NOT use frag_keyframe - it would create a fragment at every keyframe.\n // We want multiple keyframes within a single 30-second fragment (single trun with many samples).\n const fragmenterArgs = [\n \"-movflags\",\n \"empty_moov+default_base_moof\",\n \"-frag_duration\",\n \"30000000\", // 30 seconds in microseconds\n ];\n\n // Transcode to low-res H.264 with keyframes every 10 frames for fast seeking\n const ffmpegArgs = [\n ...this.ffmpegAudioInputOptions,\n ...this.ffmpegVideoInputOptions,\n \"-i\",\n this.absolutePath,\n \"-map\",\n \"0:v:0\", // Select first video stream only (no audio for scrub)\n \"-c:v\",\n \"libx264\", // Encode to H.264\n \"-preset\",\n \"ultrafast\", // Fast encoding for scrub track\n \"-crf\",\n \"28\", // Lower quality for smaller file size\n \"-vf\",\n `scale=${targetWidth}:${scrubHeight}`, // Scale to scrub resolution\n \"-r\",\n frameRate, // Maintain native FPS\n \"-g\",\n \"10\", // Keyframe every 10 frames for fast seeking within fragments\n \"-f\",\n \"mp4\",\n \"-bitexact\", // Ensure deterministic output\n ...fragmenterArgs,\n \"pipe:1\",\n ];\n\n log(\"Creating scrub track stream\", ffmpegArgs);\n\n const ffmpegProcess = spawn(\"ffmpeg\", ffmpegArgs, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n ffmpegProcess.stderr.on(\"data\", (data) => {\n log(\"SCRUB TRACK: \", data.toString());\n });\n\n ffmpegProcess.on(\"error\", (error) => {\n ffmpegProcess.stdout.emit(\"error\", error);\n });\n\n // Handle FFmpeg process exit\n ffmpegProcess.on(\"exit\", (code, signal) => {\n if (code !== 0 && code !== null) {\n const error = new Error(\n `FFmpeg scrub track process exited with code ${code}${signal ? ` and signal ${signal}` : \"\"}`,\n );\n ffmpegProcess.stdout.emit(\"error\", error);\n }\n });\n\n return ffmpegProcess.stdout;\n }\n}\n\nexport class Probe extends ProbeBase {\n data: ProbeSchema;\n\n static async probePath(absolutePath: string): Promise<Probe> {\n const json = await FFProbeRunner.probePath(absolutePath, false);\n return new Probe(absolutePath, json);\n }\n\n static async probeStream(stream: Readable): Promise<Probe> {\n const json = await FFProbeRunner.probeStream(stream, false);\n return new Probe(\"pipe:0\", json);\n }\n\n constructor(absolutePath: string, rawData: any) {\n super(absolutePath);\n this.data = ProbeSchema.parse(rawData);\n }\n}\n\nexport class PacketProbe extends ProbeBase {\n data: PacketProbeSchema;\n\n static async probePath(absolutePath: string): Promise<PacketProbe> {\n const json = await FFProbeRunner.probePath(absolutePath, true);\n return new PacketProbe(absolutePath, json);\n }\n\n static async probeStream(stream: Readable): Promise<PacketProbe> {\n const json = await FFProbeRunner.probeStream(stream, true);\n return new PacketProbe(\"pipe:0\", json);\n }\n\n constructor(absolutePath: string, rawData: any) {\n super(absolutePath);\n this.data = PacketProbeSchema.parse(rawData);\n }\n\n get packets() {\n return this.data.packets;\n }\n\n get bestEffortAudioDuration() {\n const stream = this.audioStreams[0];\n if (!stream) {\n throw new Error(\"No audio stream found\");\n }\n return truncateDecimal(\n ((stream.duration_ts ?? 0) - (stream.start_pts ?? 0)) /\n (this.audioTimebase?.den ?? 0),\n 5,\n );\n }\n\n get videoPacketDuration() {\n const videoStream = this.videoStreams[0];\n if (!videoStream) {\n return [];\n }\n const videoPackets = this.packets.filter(\n (packet) => packet.stream_index === videoStream.index,\n );\n\n const frameRate = videoStream.r_frame_rate;\n const [num, den] = frameRate.split(\"/\").map(Number);\n if (!num || !den) {\n return [];\n }\n const packetDuration = den / num;\n\n // Calculate duration using actual packet PTS timing data\n if (videoPackets.length === 0) {\n return [];\n }\n\n const ptsTimes = videoPackets.map((p) => p.pts_time);\n const minPts = Math.min(...ptsTimes);\n const maxPts = Math.max(...ptsTimes);\n const totalDuration = maxPts - minPts + packetDuration;\n\n return truncateDecimal(Math.round(totalDuration * 10000) / 10000, 5);\n }\n}\n"],"mappings":"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"}
|
|
@@ -76,6 +76,19 @@ declare const VideoRenderOptions: z.ZodObject<{
|
|
|
76
76
|
numberOfChannels: number;
|
|
77
77
|
}>;
|
|
78
78
|
}, "strip", z.ZodTypeAny, {
|
|
79
|
+
audio: {
|
|
80
|
+
codec: string;
|
|
81
|
+
bitrate: number;
|
|
82
|
+
sampleRate: number;
|
|
83
|
+
numberOfChannels: number;
|
|
84
|
+
};
|
|
85
|
+
video: {
|
|
86
|
+
width: number;
|
|
87
|
+
height: number;
|
|
88
|
+
framerate: number;
|
|
89
|
+
codec: string;
|
|
90
|
+
bitrate: number;
|
|
91
|
+
};
|
|
79
92
|
sequenceNumber: number;
|
|
80
93
|
keyframeIntervalMs: number;
|
|
81
94
|
fromMs: number;
|
|
@@ -85,6 +98,15 @@ declare const VideoRenderOptions: z.ZodObject<{
|
|
|
85
98
|
alignedFromUs: number;
|
|
86
99
|
alignedToUs: number;
|
|
87
100
|
isInitSegment: boolean;
|
|
101
|
+
noVideo?: boolean | undefined;
|
|
102
|
+
noAudio?: boolean | undefined;
|
|
103
|
+
}, {
|
|
104
|
+
audio: {
|
|
105
|
+
codec: string;
|
|
106
|
+
bitrate: number;
|
|
107
|
+
sampleRate: number;
|
|
108
|
+
numberOfChannels: number;
|
|
109
|
+
};
|
|
88
110
|
video: {
|
|
89
111
|
width: number;
|
|
90
112
|
height: number;
|
|
@@ -92,15 +114,6 @@ declare const VideoRenderOptions: z.ZodObject<{
|
|
|
92
114
|
codec: string;
|
|
93
115
|
bitrate: number;
|
|
94
116
|
};
|
|
95
|
-
audio: {
|
|
96
|
-
codec: string;
|
|
97
|
-
bitrate: number;
|
|
98
|
-
sampleRate: number;
|
|
99
|
-
numberOfChannels: number;
|
|
100
|
-
};
|
|
101
|
-
noVideo?: boolean | undefined;
|
|
102
|
-
noAudio?: boolean | undefined;
|
|
103
|
-
}, {
|
|
104
117
|
sequenceNumber: number;
|
|
105
118
|
keyframeIntervalMs: number;
|
|
106
119
|
fromMs: number;
|
|
@@ -110,19 +123,6 @@ declare const VideoRenderOptions: z.ZodObject<{
|
|
|
110
123
|
alignedFromUs: number;
|
|
111
124
|
alignedToUs: number;
|
|
112
125
|
isInitSegment: boolean;
|
|
113
|
-
video: {
|
|
114
|
-
width: number;
|
|
115
|
-
height: number;
|
|
116
|
-
framerate: number;
|
|
117
|
-
codec: string;
|
|
118
|
-
bitrate: number;
|
|
119
|
-
};
|
|
120
|
-
audio: {
|
|
121
|
-
codec: string;
|
|
122
|
-
bitrate: number;
|
|
123
|
-
sampleRate: number;
|
|
124
|
-
numberOfChannels: number;
|
|
125
|
-
};
|
|
126
126
|
noVideo?: boolean | undefined;
|
|
127
127
|
noAudio?: boolean | undefined;
|
|
128
128
|
}>;
|
|
@@ -131,6 +131,19 @@ declare const VideoRenderOptions: z.ZodObject<{
|
|
|
131
131
|
mode: "canvas" | "screenshot";
|
|
132
132
|
strategy: "v1" | "v2";
|
|
133
133
|
encoderOptions: {
|
|
134
|
+
audio: {
|
|
135
|
+
codec: string;
|
|
136
|
+
bitrate: number;
|
|
137
|
+
sampleRate: number;
|
|
138
|
+
numberOfChannels: number;
|
|
139
|
+
};
|
|
140
|
+
video: {
|
|
141
|
+
width: number;
|
|
142
|
+
height: number;
|
|
143
|
+
framerate: number;
|
|
144
|
+
codec: string;
|
|
145
|
+
bitrate: number;
|
|
146
|
+
};
|
|
134
147
|
sequenceNumber: number;
|
|
135
148
|
keyframeIntervalMs: number;
|
|
136
149
|
fromMs: number;
|
|
@@ -140,19 +153,6 @@ declare const VideoRenderOptions: z.ZodObject<{
|
|
|
140
153
|
alignedFromUs: number;
|
|
141
154
|
alignedToUs: number;
|
|
142
155
|
isInitSegment: boolean;
|
|
143
|
-
video: {
|
|
144
|
-
width: number;
|
|
145
|
-
height: number;
|
|
146
|
-
framerate: number;
|
|
147
|
-
codec: string;
|
|
148
|
-
bitrate: number;
|
|
149
|
-
};
|
|
150
|
-
audio: {
|
|
151
|
-
codec: string;
|
|
152
|
-
bitrate: number;
|
|
153
|
-
sampleRate: number;
|
|
154
|
-
numberOfChannels: number;
|
|
155
|
-
};
|
|
156
156
|
noVideo?: boolean | undefined;
|
|
157
157
|
noAudio?: boolean | undefined;
|
|
158
158
|
};
|
|
@@ -163,6 +163,19 @@ declare const VideoRenderOptions: z.ZodObject<{
|
|
|
163
163
|
mode: "canvas" | "screenshot";
|
|
164
164
|
strategy: "v1" | "v2";
|
|
165
165
|
encoderOptions: {
|
|
166
|
+
audio: {
|
|
167
|
+
codec: string;
|
|
168
|
+
bitrate: number;
|
|
169
|
+
sampleRate: number;
|
|
170
|
+
numberOfChannels: number;
|
|
171
|
+
};
|
|
172
|
+
video: {
|
|
173
|
+
width: number;
|
|
174
|
+
height: number;
|
|
175
|
+
framerate: number;
|
|
176
|
+
codec: string;
|
|
177
|
+
bitrate: number;
|
|
178
|
+
};
|
|
166
179
|
sequenceNumber: number;
|
|
167
180
|
keyframeIntervalMs: number;
|
|
168
181
|
fromMs: number;
|
|
@@ -172,19 +185,6 @@ declare const VideoRenderOptions: z.ZodObject<{
|
|
|
172
185
|
alignedFromUs: number;
|
|
173
186
|
alignedToUs: number;
|
|
174
187
|
isInitSegment: boolean;
|
|
175
|
-
video: {
|
|
176
|
-
width: number;
|
|
177
|
-
height: number;
|
|
178
|
-
framerate: number;
|
|
179
|
-
codec: string;
|
|
180
|
-
bitrate: number;
|
|
181
|
-
};
|
|
182
|
-
audio: {
|
|
183
|
-
codec: string;
|
|
184
|
-
bitrate: number;
|
|
185
|
-
sampleRate: number;
|
|
186
|
-
numberOfChannels: number;
|
|
187
|
-
};
|
|
188
188
|
noVideo?: boolean | undefined;
|
|
189
189
|
noAudio?: boolean | undefined;
|
|
190
190
|
};
|