@editframe/assets 0.12.0-beta.2 → 0.12.0-beta.21

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.
@@ -13,7 +13,7 @@ var __decorateClass = (decorators, target, key, kind) => {
13
13
  return result;
14
14
  };
15
15
  const log = debug("ef:av");
16
- const BUFFER_SIZE = 10;
16
+ const BUFFER_SIZE = 30;
17
17
  class AssetNotAvailableLocally extends Error {
18
18
  }
19
19
  class FileAsset {
@@ -232,6 +232,10 @@ const _VideoAsset = class _VideoAsset2 extends ISOFileAsset {
232
232
  duration: sample.duration,
233
233
  type: sample.is_sync ? "key" : "delta"
234
234
  });
235
+ if (this.videoDecoder.state === "closed") {
236
+ console.info("Decoder closed, skipping decode");
237
+ continue;
238
+ }
235
239
  this.videoDecoder.decode(chunk);
236
240
  const nextSample = this.defaultVideoTrak?.samples?.[i + 1];
237
241
  if (nextSample === void 0) {
package/dist/MP4File.d.ts CHANGED
@@ -10,7 +10,6 @@ export declare class MP4File extends MP4Box.ISOFile {
10
10
  track: number;
11
11
  segment: "init";
12
12
  data: ArrayBuffer;
13
- complete: false;
14
13
  cts?: undefined;
15
14
  dts?: undefined;
16
15
  duration?: undefined;
@@ -18,7 +17,6 @@ export declare class MP4File extends MP4Box.ISOFile {
18
17
  track: number;
19
18
  segment: number;
20
19
  data: ArrayBuffer;
21
- complete: boolean;
22
20
  cts: number;
23
21
  dts: number;
24
22
  duration: number;
package/dist/MP4File.js CHANGED
@@ -40,13 +40,13 @@ class MP4File extends MP4Box.ISOFile {
40
40
  await this.readyPromise;
41
41
  const trackInfo = {};
42
42
  for (const videoTrack of this.getInfo().videoTracks) {
43
- trackInfo[videoTrack.id] = { index: 0, complete: false };
43
+ trackInfo[videoTrack.id] = { index: 0 };
44
44
  this.setSegmentOptions(videoTrack.id, null, {
45
45
  rapAlignement: true
46
46
  });
47
47
  }
48
48
  for (const audioTrack of this.getInfo().audioTracks) {
49
- trackInfo[audioTrack.id] = { index: 0, complete: false };
49
+ trackInfo[audioTrack.id] = { index: 0 };
50
50
  const sampleRate = audioTrack.audio.sample_rate;
51
51
  const probablePacketSize = 1024;
52
52
  const probableFourSecondsOfSamples = Math.ceil(
@@ -61,21 +61,12 @@ class MP4File extends MP4Box.ISOFile {
61
61
  yield {
62
62
  track: initSegment.id,
63
63
  segment: "init",
64
- data: initSegment.buffer,
65
- complete: false
64
+ data: initSegment.buffer
66
65
  };
67
66
  }
68
67
  const fragmentStartSamples = {};
69
68
  let finishedReading = false;
70
- const allTracksFinished = () => {
71
- for (const fragmentedTrack of this.fragmentedTracks) {
72
- if (!trackInfo[fragmentedTrack.id]?.complete) {
73
- return false;
74
- }
75
- }
76
- return true;
77
- };
78
- while (!(finishedReading && allTracksFinished())) {
69
+ do {
79
70
  for (const fragTrak of this.fragmentedTracks) {
80
71
  const trak = fragTrak.trak;
81
72
  if (trak.nextSample === void 0) {
@@ -84,6 +75,8 @@ class MP4File extends MP4Box.ISOFile {
84
75
  if (trak.samples === void 0) {
85
76
  throw new Error("trak.samples is undefined");
86
77
  }
78
+ log("trak.nextSample", fragTrak.id, trak.nextSample);
79
+ log("trak.samples.length", fragTrak.id, trak.samples.length);
87
80
  while (trak.nextSample < trak.samples.length) {
88
81
  let result = void 0;
89
82
  const fragTrakNextSample = trak.samples[trak.nextSample];
@@ -120,9 +113,6 @@ class MP4File extends MP4Box.ISOFile {
120
113
  if (!trackInfoForFrag) {
121
114
  throw new Error("trackInfoForFrag is undefined");
122
115
  }
123
- if (trak.nextSample >= trak.samples.length) {
124
- trackInfoForFrag.complete = true;
125
- }
126
116
  const startSample = fragmentStartSamples[fragTrak.id];
127
117
  const endSample = trak.samples[trak.nextSample - 1];
128
118
  if (!startSample || !endSample) {
@@ -137,7 +127,6 @@ class MP4File extends MP4Box.ISOFile {
137
127
  track: fragTrak.id,
138
128
  segment: trackInfoForFrag.index,
139
129
  data: fragTrak.segmentStream.buffer,
140
- complete: trackInfoForFrag.complete,
141
130
  cts: startSample.cts,
142
131
  dts: startSample.dts,
143
132
  duration: endSample.cts - startSample.cts + endSample.duration
@@ -149,6 +138,68 @@ class MP4File extends MP4Box.ISOFile {
149
138
  }
150
139
  }
151
140
  finishedReading = await this.waitForMoreSamples();
141
+ } while (!finishedReading);
142
+ for (const fragTrak of this.fragmentedTracks) {
143
+ const trak = fragTrak.trak;
144
+ if (trak.nextSample === void 0) {
145
+ throw new Error("trak.nextSample is undefined");
146
+ }
147
+ if (trak.samples === void 0) {
148
+ throw new Error("trak.samples is undefined");
149
+ }
150
+ while (trak.nextSample < trak.samples.length) {
151
+ let result = void 0;
152
+ try {
153
+ result = this.createFragment(
154
+ fragTrak.id,
155
+ trak.nextSample,
156
+ fragTrak.segmentStream
157
+ );
158
+ } catch (error) {
159
+ console.error("Failed to createFragment", error);
160
+ }
161
+ if (result) {
162
+ fragTrak.segmentStream = result;
163
+ trak.nextSample++;
164
+ } else {
165
+ finishedReading = await this.waitForMoreSamples();
166
+ break;
167
+ }
168
+ const nextSample = trak.samples[trak.nextSample];
169
+ const emitSegment = (
170
+ // if rapAlignement is true, we emit a fragment when we have a rap sample coming up next
171
+ fragTrak.rapAlignement === true && nextSample?.is_sync || // if rapAlignement is false, we emit a fragment when we have the required number of samples
172
+ !fragTrak.rapAlignement && trak.nextSample % fragTrak.nb_samples === 0 || // if we have more samples than the number of samples requested, we emit the fragment
173
+ trak.nextSample >= trak.samples.length
174
+ );
175
+ if (emitSegment) {
176
+ const trackInfoForFrag = trackInfo[fragTrak.id];
177
+ if (!trackInfoForFrag) {
178
+ throw new Error("trackInfoForFrag is undefined");
179
+ }
180
+ const startSample = fragmentStartSamples[fragTrak.id];
181
+ const endSample = trak.samples[trak.nextSample - 1];
182
+ if (!startSample || !endSample) {
183
+ throw new Error("startSample or endSample is undefined");
184
+ }
185
+ log(
186
+ `Yielding fragment #${trackInfoForFrag.index} for track=${fragTrak.id}`,
187
+ `startTime=${startSample.cts}`,
188
+ `endTime=${endSample.cts + endSample.duration}`
189
+ );
190
+ yield {
191
+ track: fragTrak.id,
192
+ segment: trackInfoForFrag.index,
193
+ data: fragTrak.segmentStream.buffer,
194
+ cts: startSample.cts,
195
+ dts: startSample.dts,
196
+ duration: endSample.cts - startSample.cts + endSample.duration
197
+ };
198
+ trackInfoForFrag.index += 1;
199
+ fragTrak.segmentStream = null;
200
+ delete fragmentStartSamples[fragTrak.id];
201
+ }
202
+ }
152
203
  }
153
204
  }
154
205
  waitForMoreSamples() {
package/dist/Probe.d.ts CHANGED
@@ -130,6 +130,20 @@ export declare const VideoStreamSchema: z.ZodObject<{
130
130
  bit_rate?: string | undefined;
131
131
  }>;
132
132
  export type VideoStreamSchema = z.infer<typeof VideoStreamSchema>;
133
+ export declare const DataStreamSchema: z.ZodObject<{
134
+ index: z.ZodNumber;
135
+ codec_type: z.ZodLiteral<"data">;
136
+ duration: z.ZodOptional<z.ZodString>;
137
+ }, "strip", z.ZodTypeAny, {
138
+ index: number;
139
+ codec_type: "data";
140
+ duration?: string | undefined;
141
+ }, {
142
+ index: number;
143
+ codec_type: "data";
144
+ duration?: string | undefined;
145
+ }>;
146
+ export type DataStreamSchema = z.infer<typeof DataStreamSchema>;
133
147
  declare const StreamSchema: z.ZodDiscriminatedUnion<"codec_type", [z.ZodObject<{
134
148
  index: z.ZodNumber;
135
149
  codec_name: z.ZodString;
@@ -256,6 +270,18 @@ declare const StreamSchema: z.ZodDiscriminatedUnion<"codec_type", [z.ZodObject<{
256
270
  start_time?: number | undefined;
257
271
  duration_ts?: number | undefined;
258
272
  bit_rate?: string | undefined;
273
+ }>, z.ZodObject<{
274
+ index: z.ZodNumber;
275
+ codec_type: z.ZodLiteral<"data">;
276
+ duration: z.ZodOptional<z.ZodString>;
277
+ }, "strip", z.ZodTypeAny, {
278
+ index: number;
279
+ codec_type: "data";
280
+ duration?: string | undefined;
281
+ }, {
282
+ index: number;
283
+ codec_type: "data";
284
+ duration?: string | undefined;
259
285
  }>]>;
260
286
  export type StreamSchema = z.infer<typeof StreamSchema>;
261
287
  declare const ProbeSchema: z.ZodObject<{
@@ -385,6 +411,18 @@ declare const ProbeSchema: z.ZodObject<{
385
411
  start_time?: number | undefined;
386
412
  duration_ts?: number | undefined;
387
413
  bit_rate?: string | undefined;
414
+ }>, z.ZodObject<{
415
+ index: z.ZodNumber;
416
+ codec_type: z.ZodLiteral<"data">;
417
+ duration: z.ZodOptional<z.ZodString>;
418
+ }, "strip", z.ZodTypeAny, {
419
+ index: number;
420
+ codec_type: "data";
421
+ duration?: string | undefined;
422
+ }, {
423
+ index: number;
424
+ codec_type: "data";
425
+ duration?: string | undefined;
388
426
  }>]>, "many">;
389
427
  format: z.ZodObject<{
390
428
  filename: z.ZodString;
@@ -475,6 +513,10 @@ declare const ProbeSchema: z.ZodObject<{
475
513
  start_time?: number | undefined;
476
514
  duration_ts?: number | undefined;
477
515
  bit_rate?: string | undefined;
516
+ } | {
517
+ index: number;
518
+ codec_type: "data";
519
+ duration?: string | undefined;
478
520
  })[];
479
521
  }, {
480
522
  format: {
@@ -531,8 +573,13 @@ declare const ProbeSchema: z.ZodObject<{
531
573
  start_time?: number | undefined;
532
574
  duration_ts?: number | undefined;
533
575
  bit_rate?: string | undefined;
576
+ } | {
577
+ index: number;
578
+ codec_type: "data";
579
+ duration?: string | undefined;
534
580
  })[];
535
581
  }>;
582
+ export type ProbeSchema = z.infer<typeof ProbeSchema>;
536
583
  export interface TrackSegment {
537
584
  cts: number;
538
585
  dts: number;
@@ -574,7 +621,7 @@ export interface VideoTrackFragmentIndex {
574
621
  export type TrackFragmentIndex = AudioTrackFragmentIndex | VideoTrackFragmentIndex;
575
622
  export declare class Probe {
576
623
  private absolutePath;
577
- data: z.infer<typeof ProbeSchema>;
624
+ data: ProbeSchema;
578
625
  static probePath(absolutePath: string): Promise<Probe>;
579
626
  static probeStream(stream: Readable): Promise<Probe>;
580
627
  constructor(absolutePath: string, rawData: any);
@@ -622,6 +669,10 @@ export declare class Probe {
622
669
  start_time?: number | undefined;
623
670
  duration_ts?: number | undefined;
624
671
  bit_rate?: string | undefined;
672
+ } | {
673
+ index: number;
674
+ codec_type: "data";
675
+ duration?: string | undefined;
625
676
  })[];
626
677
  get format(): {
627
678
  filename: string;
@@ -638,6 +689,7 @@ export declare class Probe {
638
689
  get mustReencodeAudio(): boolean;
639
690
  get mustReencodeVideo(): boolean;
640
691
  get mustRemux(): boolean;
692
+ get hasNonAudioOrVideoStreams(): boolean;
641
693
  get hasAudio(): boolean;
642
694
  get hasVideo(): boolean;
643
695
  get isAudioOnly(): boolean;
package/dist/Probe.js CHANGED
@@ -61,9 +61,15 @@ const ProbeFormatSchema = z.object({
61
61
  bit_rate: z.string().optional(),
62
62
  probe_score: z.number()
63
63
  });
64
+ const DataStreamSchema = z.object({
65
+ index: z.number(),
66
+ codec_type: z.literal("data"),
67
+ duration: z.string().optional()
68
+ });
64
69
  const StreamSchema = z.discriminatedUnion("codec_type", [
65
70
  AudioStreamSchema,
66
- VideoStreamSchema
71
+ VideoStreamSchema,
72
+ DataStreamSchema
67
73
  ]);
68
74
  const ProbeSchema = z.object({
69
75
  streams: z.array(StreamSchema),
@@ -166,7 +172,12 @@ class Probe {
166
172
  return false;
167
173
  }
168
174
  get mustRemux() {
169
- return this.format.format_name !== "mp4";
175
+ return this.format.format_name !== "mp4" || this.data.streams.some((stream) => stream.codec_type !== "audio" && stream.codec_type !== "video");
176
+ }
177
+ get hasNonAudioOrVideoStreams() {
178
+ return this.data.streams.some(
179
+ (stream) => stream.codec_type !== "audio" && stream.codec_type !== "video"
180
+ );
170
181
  }
171
182
  get hasAudio() {
172
183
  return this.audioStreams.length > 0;
@@ -266,6 +277,7 @@ class Probe {
266
277
  }
267
278
  export {
268
279
  AudioStreamSchema,
280
+ DataStreamSchema,
269
281
  Probe,
270
282
  VideoStreamSchema
271
283
  };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { AudioStreamSchema, VideoStreamSchema, Probe } from './Probe.ts';
2
- export type { StreamSchema, TrackSegment, TrackFragmentIndex, AudioTrackFragmentIndex, VideoTrackFragmentIndex, } from './Probe.ts';
3
- export { md5FilePath, md5Directory, md5ReadStream, md5Buffer } from './md5.ts';
4
- export { generateTrackFragmentIndex, generateTrackFragmentIndexFromPath, } from './tasks/generateTrackFragmentIndex.ts';
5
- export { generateTrack, generateTrackFromPath } from './tasks/generateTrack.ts';
6
- export { findOrCreateCaptions, generateCaptionDataFromPath, } from './tasks/findOrCreateCaptions.ts';
7
- export { cacheImage } from './tasks/cacheImage.ts';
8
- export type { TaskResult } from './idempotentTask.ts';
9
- export { VideoRenderOptions } from './VideoRenderOptions.ts';
1
+ export type { StreamSchema, AudioStreamSchema, VideoStreamSchema, TrackSegment, TrackFragmentIndex, AudioTrackFragmentIndex, VideoTrackFragmentIndex, } from './Probe.js';
2
+ export { Probe } from './Probe.js';
3
+ export { md5FilePath, md5Directory, md5ReadStream, md5Buffer } from './md5.js';
4
+ export { generateTrackFragmentIndex, generateTrackFragmentIndexFromPath, } from './tasks/generateTrackFragmentIndex.js';
5
+ export { generateTrack, generateTrackFromPath } from './tasks/generateTrack.js';
6
+ export { findOrCreateCaptions, generateCaptionDataFromPath, } from './tasks/findOrCreateCaptions.js';
7
+ export { cacheImage } from './tasks/cacheImage.js';
8
+ export type { TaskResult } from './idempotentTask.js';
9
+ export { VideoRenderOptions } from './VideoRenderOptions.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AudioStreamSchema, Probe, VideoStreamSchema } from "./Probe.js";
1
+ import { Probe } from "./Probe.js";
2
2
  import { md5Buffer, md5Directory, md5FilePath, md5ReadStream } from "./md5.js";
3
3
  import { generateTrackFragmentIndex, generateTrackFragmentIndexFromPath } from "./tasks/generateTrackFragmentIndex.js";
4
4
  import { generateTrack, generateTrackFromPath } from "./tasks/generateTrack.js";
@@ -6,10 +6,8 @@ import { findOrCreateCaptions, generateCaptionDataFromPath } from "./tasks/findO
6
6
  import { cacheImage } from "./tasks/cacheImage.js";
7
7
  import { VideoRenderOptions } from "./VideoRenderOptions.js";
8
8
  export {
9
- AudioStreamSchema,
10
9
  Probe,
11
10
  VideoRenderOptions,
12
- VideoStreamSchema,
13
11
  cacheImage,
14
12
  findOrCreateCaptions,
15
13
  generateCaptionDataFromPath,
@@ -1,3 +1,3 @@
1
1
  import { Writable } from 'node:stream';
2
- import { MP4File } from './MP4File.ts';
2
+ import { MP4File } from './MP4File.js';
3
3
  export declare const mp4FileWritable: (mp4File: MP4File) => Writable;
@@ -1 +1 @@
1
- export declare const cacheImage: (cacheRoot: string, absolutePath: string) => Promise<import('../idempotentTask.ts').TaskResult>;
1
+ export declare const cacheImage: (cacheRoot: string, absolutePath: string) => Promise<import('../idempotentTask.js').TaskResult>;
@@ -1,2 +1,2 @@
1
1
  export declare const generateCaptionDataFromPath: (absolutePath: string) => Promise<string>;
2
- export declare const findOrCreateCaptions: (cacheRoot: string, absolutePath: string) => Promise<import('../idempotentTask.ts').TaskResult>;
2
+ export declare const findOrCreateCaptions: (cacheRoot: string, absolutePath: string) => Promise<import('../idempotentTask.js').TaskResult>;
@@ -1,4 +1,4 @@
1
1
  import { PassThrough } from 'node:stream';
2
2
  export declare const generateTrackFromPath: (absolutePath: string, trackId: number) => Promise<PassThrough>;
3
- export declare const generateTrackTask: (rootDir: string, absolutePath: string, trackId: number) => Promise<import('../idempotentTask.ts').TaskResult>;
4
- export declare const generateTrack: (cacheRoot: string, absolutePath: string, url: string) => Promise<import('../idempotentTask.ts').TaskResult>;
3
+ export declare const generateTrackTask: (rootDir: string, absolutePath: string, trackId: number) => Promise<import('../idempotentTask.js').TaskResult>;
4
+ export declare const generateTrack: (cacheRoot: string, absolutePath: string, url: string) => Promise<import('../idempotentTask.js').TaskResult>;
@@ -1,3 +1,3 @@
1
- import { TrackFragmentIndex } from '../Probe.ts';
1
+ import { TrackFragmentIndex } from '../Probe.js';
2
2
  export declare const generateTrackFragmentIndexFromPath: (absolutePath: string) => Promise<Record<number, TrackFragmentIndex>>;
3
- export declare const generateTrackFragmentIndex: (cacheRoot: string, absolutePath: string) => Promise<import('../idempotentTask.ts').TaskResult>;
3
+ export declare const generateTrackFragmentIndex: (cacheRoot: string, absolutePath: string) => Promise<import('../idempotentTask.js').TaskResult>;
package/package.json CHANGED
@@ -1,26 +1,33 @@
1
1
  {
2
2
  "name": "@editframe/assets",
3
- "version": "0.12.0-beta.2",
3
+ "version": "0.12.0-beta.21",
4
4
  "description": "",
5
5
  "exports": {
6
6
  ".": {
7
- "types": "./dist/index.d.ts",
8
- "import": "./dist/index.js"
7
+ "import": {
8
+ "types": "./dist/index.d.ts",
9
+ "default": "./dist/index.js"
10
+ }
9
11
  },
10
12
  "./EncodedAsset.js": {
11
- "types": "./dist/EncodedAsset.d.ts",
12
- "import": "./dist/EncodedAsset.js"
13
+ "import": {
14
+ "types": "./dist/EncodedAsset.d.ts",
15
+ "default": "./dist/EncodedAsset.js"
16
+ }
13
17
  },
14
18
  "./MP4File.js": {
15
- "types": "./dist/MP4File.d.ts",
16
- "import": "./dist/MP4File.js"
19
+ "import": {
20
+ "types": "./dist/MP4File.d.ts",
21
+ "default": "./dist/MP4File.js"
22
+ }
17
23
  }
18
24
  },
19
25
  "type": "module",
20
26
  "scripts": {
21
27
  "typecheck": "tsc --noEmit --emitDeclarationOnly false",
22
28
  "build": "vite build",
23
- "build:watch": "vite build --watch"
29
+ "build:watch": "vite build --watch",
30
+ "typedoc": "typedoc --json ../../docs/assets.json --plugin typedoc-plugin-zod --excludeExternals ./src"
24
31
  },
25
32
  "author": "",
26
33
  "license": "UNLICENSED",
@@ -1,4 +1,4 @@
1
- import { idempotentTask } from "../idempotentTask.ts";
1
+ import { idempotentTask } from "../idempotentTask.js";
2
2
  import { createReadStream } from "node:fs";
3
3
 
4
4
  import path from "node:path";
@@ -4,7 +4,7 @@ import { exec } from "node:child_process";
4
4
 
5
5
  import debug from "debug";
6
6
 
7
- import { idempotentTask } from "../idempotentTask.ts";
7
+ import { idempotentTask } from "../idempotentTask.js";
8
8
 
9
9
  const execPromise = promisify(exec);
10
10
 
@@ -1,10 +1,10 @@
1
- import { idempotentTask } from "../idempotentTask.ts";
2
- import { MP4File } from "../MP4File.ts";
1
+ import { idempotentTask } from "../idempotentTask.js";
2
+ import { MP4File } from "../MP4File.js";
3
3
  import debug from "debug";
4
- import { mp4FileWritable } from "../mp4FileWritable.ts";
4
+ import { mp4FileWritable } from "../mp4FileWritable.js";
5
5
  import { PassThrough } from "node:stream";
6
6
  import { basename } from "node:path";
7
- import { Probe } from "../Probe.ts";
7
+ import { Probe } from "../Probe.js";
8
8
 
9
9
  export const generateTrackFromPath = async (
10
10
  absolutePath: string,
@@ -1,9 +1,9 @@
1
- import { idempotentTask } from "../idempotentTask.ts";
2
- import { MP4File } from "../MP4File.ts";
1
+ import { idempotentTask } from "../idempotentTask.js";
2
+ import { MP4File } from "../MP4File.js";
3
3
  import debug from "debug";
4
- import { mp4FileWritable } from "../mp4FileWritable.ts";
4
+ import { mp4FileWritable } from "../mp4FileWritable.js";
5
5
  import { basename } from "node:path";
6
- import { Probe, type TrackFragmentIndex } from "../Probe.ts";
6
+ import { Probe, type TrackFragmentIndex } from "../Probe.js";
7
7
 
8
8
  export const generateTrackFragmentIndexFromPath = async (
9
9
  absolutePath: string,