@remotion/media-parser 4.0.295 → 4.0.297

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.
@@ -27,12 +27,29 @@ const parseMdatSection = async (state) => {
27
27
  if (mfra) {
28
28
  const lastMoof = (0, last_moof_box_1.getLastMoofBox)(mfra);
29
29
  if (lastMoof && lastMoof > endOfMdat) {
30
- log_1.Log.verbose(state.logLevel, 'Skipping to last moof', lastMoof, 'end of mdat', endOfMdat);
30
+ log_1.Log.verbose(state.logLevel, 'Skipping to last moof', lastMoof);
31
31
  return (0, skip_1.makeSkip)(lastMoof);
32
32
  }
33
33
  }
34
34
  return (0, skip_1.makeSkip)(endOfMdat);
35
35
  }
36
+ // if we only need the first and last sample, we may skip over the samples in the middle
37
+ // this logic skips the samples in the middle for a fragmented mp4
38
+ if ((0, may_skip_video_data_1.maySkipOverSamplesInTheMiddle)({ state })) {
39
+ const mfra = state.iso.mfra.getIfAlreadyLoaded();
40
+ if (mfra) {
41
+ const lastMoof = (0, last_moof_box_1.getLastMoofBox)(mfra);
42
+ // we require that all moof boxes of both tracks have been processed, for correct duration calculation
43
+ const firstMax = (0, last_moof_box_1.getMaxFirstMoofOffset)(mfra);
44
+ const mediaSectionsBiggerThanMoof = state.mediaSection
45
+ .getMediaSections()
46
+ .filter((m) => m.start > firstMax).length;
47
+ if (mediaSectionsBiggerThanMoof > 1 && lastMoof && lastMoof > endOfMdat) {
48
+ log_1.Log.verbose(state.logLevel, 'Skipping to last moof because only first and last samples are needed');
49
+ return (0, skip_1.makeSkip)(lastMoof);
50
+ }
51
+ }
52
+ }
36
53
  const alreadyHasMoov = (0, get_tracks_1.getHasTracks)(state, true);
37
54
  if (!alreadyHasMoov) {
38
55
  const moov = await (0, get_moov_atom_1.getMoovAtom)({
@@ -1,7 +1,7 @@
1
1
  import type { BufferIterator } from '../../../iterator/buffer-iterator';
2
2
  import type { BaseBox } from '../base-type';
3
3
  type IlstEntry = {
4
- index: number;
4
+ index: string;
5
5
  wellKnownType: number;
6
6
  type: string;
7
7
  value: Value;
@@ -58,9 +58,21 @@ const parseIlstBox = ({ iterator, size, offset, }) => {
58
58
  while (iterator.counter.getOffset() < size + offset) {
59
59
  // metadata size
60
60
  const metadataSize = iterator.getUint32();
61
- const index = iterator.getUint32();
62
- // "skip" as a number
63
- if (index === 1936419184) {
61
+ const index = iterator.getAtom();
62
+ // this can be of a different type
63
+ if (!index.startsWith('�') && !index.startsWith('\u0000')) {
64
+ // "skip" as a number
65
+ if (index === 'skip') {
66
+ iterator.discard(metadataSize - 8);
67
+ continue;
68
+ }
69
+ // "----" atom in m4a files
70
+ // iTunes adds it for .m4a files
71
+ // not very interesting data, so we don't parse them
72
+ if (index === '----') {
73
+ iterator.discard(metadataSize - 8);
74
+ continue;
75
+ }
64
76
  iterator.discard(metadataSize - 8);
65
77
  continue;
66
78
  }
@@ -4162,8 +4162,16 @@ var parseIlstBox = ({
4162
4162
  const entries = [];
4163
4163
  while (iterator.counter.getOffset() < size + offset) {
4164
4164
  const metadataSize = iterator.getUint32();
4165
- const index = iterator.getUint32();
4166
- if (index === 1936419184) {
4165
+ const index = iterator.getAtom();
4166
+ if (!index.startsWith("�") && !index.startsWith("\x00")) {
4167
+ if (index === "skip") {
4168
+ iterator.discard(metadataSize - 8);
4169
+ continue;
4170
+ }
4171
+ if (index === "----") {
4172
+ iterator.discard(metadataSize - 8);
4173
+ continue;
4174
+ }
4167
4175
  iterator.discard(metadataSize - 8);
4168
4176
  continue;
4169
4177
  }
@@ -7503,40 +7511,40 @@ var getMetadataFromWav = (structure) => {
7503
7511
 
7504
7512
  // src/metadata/metadata-from-iso.ts
7505
7513
  var mapToKey = (index) => {
7506
- if (index === 2839630420) {
7514
+ if (index === "�ART") {
7507
7515
  return "artist";
7508
7516
  }
7509
- if (index === 2841734242) {
7517
+ if (index === "�alb") {
7510
7518
  return "album";
7511
7519
  }
7512
- if (index === 2841865588) {
7520
+ if (index === "�cmt") {
7513
7521
  return "comment";
7514
7522
  }
7515
- if (index === 2841928057) {
7523
+ if (index === "�day") {
7516
7524
  return "releaseDate";
7517
7525
  }
7518
- if (index === 2842125678) {
7526
+ if (index === "�gen") {
7519
7527
  return "genre";
7520
7528
  }
7521
- if (index === 2842583405) {
7529
+ if (index === "�nam") {
7522
7530
  return "title";
7523
7531
  }
7524
- if (index === 2842980207) {
7532
+ if (index === "�too") {
7525
7533
  return "encoder";
7526
7534
  }
7527
- if (index === 2843177588) {
7535
+ if (index === "�wrt") {
7528
7536
  return "writer";
7529
7537
  }
7530
- if (index === 2841866361) {
7538
+ if (index === "�cpy") {
7531
7539
  return "copyright";
7532
7540
  }
7533
- if (index === 2841930098) {
7541
+ if (index === "�dir") {
7534
7542
  return "director";
7535
7543
  }
7536
- if (index === 2842718820) {
7544
+ if (index === "�prd") {
7537
7545
  return "producer";
7538
7546
  }
7539
- if (index === 2841929075) {
7547
+ if (index === "�des") {
7540
7548
  return "description";
7541
7549
  }
7542
7550
  return null;
@@ -9320,6 +9328,18 @@ var needsToIterateOverSamples = ({
9320
9328
  const selectedKeys = keys.filter((k) => fields[k]);
9321
9329
  return selectedKeys.some((k) => fieldsNeedSamplesMap[k] && !emittedFields[k]);
9322
9330
  };
9331
+ var fieldsNeedEverySampleMap = {
9332
+ ...fieldsNeedSamplesMap,
9333
+ slowDurationInSeconds: false
9334
+ };
9335
+ var needsToIterateOverEverySample = ({
9336
+ fields,
9337
+ emittedFields
9338
+ }) => {
9339
+ const keys = Object.keys(fields ?? {});
9340
+ const selectedKeys = keys.filter((k) => fields[k]);
9341
+ return selectedKeys.some((k) => fieldsNeedEverySampleMap[k] && !emittedFields[k]);
9342
+ };
9323
9343
 
9324
9344
  // src/disallow-forward-seek-if-samples-are-needed.ts
9325
9345
  var disallowForwardSeekIfSamplesAreNeeded = ({
@@ -10015,11 +10035,26 @@ var emitAvailableInfo = async ({
10015
10035
  };
10016
10036
 
10017
10037
  // src/state/may-skip-video-data.ts
10018
- var maySkipVideoData = ({ state }) => {
10019
- const hasAllTracksAndNoCallbacks = state.callbacks.tracks.hasAllTracks() && Object.values(state.callbacks.videoSampleCallbacks).length === 0 && Object.values(state.callbacks.audioSampleCallbacks).length === 0;
10038
+ var getHasCallbacks = (state) => {
10020
10039
  const hasNoTrackHandlers = !state.callbacks.hasAudioTrackHandlers && !state.callbacks.hasVideoTrackHandlers;
10021
- const noCallbacksNeeded = hasNoTrackHandlers || hasAllTracksAndNoCallbacks;
10022
- return noCallbacksNeeded && !needsToIterateOverSamples({
10040
+ if (hasNoTrackHandlers) {
10041
+ return false;
10042
+ }
10043
+ const hasAllTracksAndNoCallbacks = !state.callbacks.tracks.hasAllTracks() || Object.values(state.callbacks.videoSampleCallbacks).length > 0 || Object.values(state.callbacks.audioSampleCallbacks).length > 0;
10044
+ return hasAllTracksAndNoCallbacks;
10045
+ };
10046
+ var maySkipVideoData = ({ state }) => {
10047
+ const hasCallbacks = getHasCallbacks(state);
10048
+ return !hasCallbacks && !needsToIterateOverSamples({
10049
+ emittedFields: state.emittedFields,
10050
+ fields: state.fields
10051
+ });
10052
+ };
10053
+ var maySkipOverSamplesInTheMiddle = ({
10054
+ state
10055
+ }) => {
10056
+ const hasCallbacks = getHasCallbacks(state);
10057
+ return !hasCallbacks && !needsToIterateOverEverySample({
10023
10058
  emittedFields: state.emittedFields,
10024
10059
  fields: state.fields
10025
10060
  });
@@ -10097,7 +10132,7 @@ var getAvailableInfo = ({
10097
10132
  if (key === "m3uStreams") {
10098
10133
  return m3uHasStreams(state);
10099
10134
  }
10100
- throw new Error(`Unknown key: ${key}`);
10135
+ throw new Error(`Unknown field passed: ${key}. Available fields: ${Object.keys(state.fields).join(", ")}`);
10101
10136
  });
10102
10137
  const entries = [];
10103
10138
  let i = 0;
@@ -10780,6 +10815,13 @@ var getLastMoofBox = (boxes) => {
10780
10815
  return null;
10781
10816
  }
10782
10817
  };
10818
+ var getMaxFirstMoofOffset = (boxes) => {
10819
+ const tfras = boxes.filter((b) => b.type === "tfra-box");
10820
+ const firstMoofOffsets = tfras.map((f) => {
10821
+ return f.entries[0].moofOffset;
10822
+ });
10823
+ return Math.max(...firstMoofOffsets.filter(truthy));
10824
+ };
10783
10825
 
10784
10826
  // src/state/can-skip-tracks.ts
10785
10827
  var needsTracksForField = ({
@@ -11181,12 +11223,24 @@ var parseMdatSection = async (state) => {
11181
11223
  if (mfra) {
11182
11224
  const lastMoof = getLastMoofBox(mfra);
11183
11225
  if (lastMoof && lastMoof > endOfMdat) {
11184
- Log.verbose(state.logLevel, "Skipping to last moof", lastMoof, "end of mdat", endOfMdat);
11226
+ Log.verbose(state.logLevel, "Skipping to last moof", lastMoof);
11185
11227
  return makeSkip(lastMoof);
11186
11228
  }
11187
11229
  }
11188
11230
  return makeSkip(endOfMdat);
11189
11231
  }
11232
+ if (maySkipOverSamplesInTheMiddle({ state })) {
11233
+ const mfra = state.iso.mfra.getIfAlreadyLoaded();
11234
+ if (mfra) {
11235
+ const lastMoof = getLastMoofBox(mfra);
11236
+ const firstMax = getMaxFirstMoofOffset(mfra);
11237
+ const mediaSectionsBiggerThanMoof = state.mediaSection.getMediaSections().filter((m) => m.start > firstMax).length;
11238
+ if (mediaSectionsBiggerThanMoof > 1 && lastMoof && lastMoof > endOfMdat) {
11239
+ Log.verbose(state.logLevel, "Skipping to last moof because only first and last samples are needed");
11240
+ return makeSkip(lastMoof);
11241
+ }
11242
+ }
11243
+ }
11190
11244
  const alreadyHasMoov = getHasTracks(state, true);
11191
11245
  if (!alreadyHasMoov) {
11192
11246
  const moov = await getMoovAtom({
@@ -16411,29 +16465,25 @@ var samplesObservedState = () => {
16411
16465
  const videoSamples = new Map;
16412
16466
  const audioSamples = new Map;
16413
16467
  const getSlowVideoDurationInSeconds = () => {
16414
- let videoDuration = null;
16415
- if (smallestVideoSample !== undefined && largestVideoSample !== undefined) {
16416
- const startingTimestampDifference = largestVideoSample - smallestVideoSample;
16417
- const timeBetweenSamples = startingTimestampDifference / (videoSamples.size - 1);
16418
- videoDuration = timeBetweenSamples * videoSamples.size;
16419
- }
16420
- return videoDuration;
16468
+ return (largestVideoSample ?? 0) - (smallestVideoSample ?? 0);
16469
+ };
16470
+ const getSlowAudioDurationInSeconds = () => {
16471
+ return (largestAudioSample ?? 0) - (smallestAudioSample ?? 0);
16421
16472
  };
16422
16473
  const getSlowDurationInSeconds = () => {
16423
- const videoDuration = getSlowVideoDurationInSeconds();
16424
- let audioDuration = null;
16425
- if (smallestAudioSample !== undefined && largestAudioSample !== undefined) {
16426
- const startingTimestampDifferenceAudio = largestAudioSample - smallestAudioSample;
16427
- const timeBetweenSamplesAudio = startingTimestampDifferenceAudio / (audioSamples.size - 1);
16428
- audioDuration = timeBetweenSamplesAudio * audioSamples.size;
16474
+ const smallestSample = Math.min(smallestAudioSample ?? Infinity, smallestVideoSample ?? Infinity);
16475
+ const largestSample = Math.max(largestAudioSample ?? 0, largestVideoSample ?? 0);
16476
+ if (smallestSample === Infinity || largestSample === Infinity) {
16477
+ return 0;
16429
16478
  }
16430
- return Math.max(videoDuration ?? 0, audioDuration ?? 0);
16479
+ return largestSample - smallestSample;
16431
16480
  };
16432
16481
  const addVideoSample = (videoSample) => {
16433
16482
  videoSamples.set(videoSample.cts, videoSample.data.byteLength);
16434
16483
  const presentationTimeInSeconds = videoSample.cts / videoSample.timescale;
16484
+ const duration2 = (videoSample.duration ?? 0) / videoSample.timescale;
16435
16485
  if (largestVideoSample === undefined || presentationTimeInSeconds > largestVideoSample) {
16436
- largestVideoSample = presentationTimeInSeconds;
16486
+ largestVideoSample = presentationTimeInSeconds + duration2;
16437
16487
  }
16438
16488
  if (smallestVideoSample === undefined || presentationTimeInSeconds < smallestVideoSample) {
16439
16489
  smallestVideoSample = presentationTimeInSeconds;
@@ -16442,23 +16492,24 @@ var samplesObservedState = () => {
16442
16492
  const addAudioSample = (audioSample) => {
16443
16493
  audioSamples.set(audioSample.cts, audioSample.data.byteLength);
16444
16494
  const presentationTimeInSeconds = audioSample.cts / audioSample.timescale;
16495
+ const duration2 = (audioSample.duration ?? 0) / audioSample.timescale;
16445
16496
  if (largestAudioSample === undefined || presentationTimeInSeconds > largestAudioSample) {
16446
- largestAudioSample = presentationTimeInSeconds;
16497
+ largestAudioSample = presentationTimeInSeconds + duration2;
16447
16498
  }
16448
16499
  if (smallestAudioSample === undefined || presentationTimeInSeconds < smallestAudioSample) {
16449
16500
  smallestAudioSample = presentationTimeInSeconds;
16450
16501
  }
16451
16502
  };
16452
16503
  const getFps2 = () => {
16453
- const videoDuration = getSlowVideoDurationInSeconds() ?? 0;
16504
+ const videoDuration = (largestVideoSample ?? 0) - (smallestVideoSample ?? 0);
16454
16505
  if (videoDuration === 0) {
16455
16506
  return 0;
16456
16507
  }
16457
- return videoSamples.size / videoDuration;
16508
+ return (videoSamples.size - 1) / videoDuration;
16458
16509
  };
16459
16510
  const getSlowNumberOfFrames = () => videoSamples.size;
16460
16511
  const getAudioBitrate = () => {
16461
- const audioDuration = getSlowDurationInSeconds();
16512
+ const audioDuration = getSlowAudioDurationInSeconds();
16462
16513
  if (audioDuration === 0 || audioSamples.size === 0) {
16463
16514
  return null;
16464
16515
  }
@@ -16466,7 +16517,7 @@ var samplesObservedState = () => {
16466
16517
  return audioSizesInBytes * 8 / audioDuration;
16467
16518
  };
16468
16519
  const getVideoBitrate = () => {
16469
- const videoDuration = getSlowDurationInSeconds();
16520
+ const videoDuration = getSlowVideoDurationInSeconds();
16470
16521
  if (videoDuration === 0 || videoSamples.size === 0) {
16471
16522
  return null;
16472
16523
  }
@@ -16486,7 +16537,8 @@ var samplesObservedState = () => {
16486
16537
  getAudioBitrate,
16487
16538
  getVideoBitrate,
16488
16539
  getLastSampleObserved,
16489
- setLastSampleObserved
16540
+ setLastSampleObserved,
16541
+ getAmountOfSamplesObserved: () => videoSamples.size + audioSamples.size
16490
16542
  };
16491
16543
  };
16492
16544
 
@@ -16977,7 +17029,7 @@ var downloadAndParseMedia = async (options) => {
16977
17029
  return returnValue;
16978
17030
  };
16979
17031
  // src/version.ts
16980
- var VERSION = "4.0.295";
17032
+ var VERSION = "4.0.297";
16981
17033
 
16982
17034
  // src/index.ts
16983
17035
  var MediaParserInternals = {
package/dist/esm/node.mjs CHANGED
@@ -24,6 +24,9 @@ var nodeReadContent = ({ src, range, controller }) => {
24
24
  c.enqueue(chunk);
25
25
  });
26
26
  stream.on("end", () => {
27
+ if (readerCancelled) {
28
+ return;
29
+ }
27
30
  c.close();
28
31
  });
29
32
  stream.on("error", (err) => {
@@ -334,6 +334,9 @@ var nodeReadContent = ({ src, range, controller }) => {
334
334
  c.enqueue(chunk);
335
335
  });
336
336
  stream.on("end", () => {
337
+ if (readerCancelled) {
338
+ return;
339
+ }
337
340
  c.close();
338
341
  });
339
342
  stream.on("error", (err) => {
@@ -425,6 +425,9 @@ var nodeReadContent = ({ src, range, controller }) => {
425
425
  c.enqueue(chunk);
426
426
  });
427
427
  stream.on("end", () => {
428
+ if (readerCancelled) {
429
+ return;
430
+ }
428
431
  c.close();
429
432
  });
430
433
  stream.on("error", (err) => {
@@ -5383,40 +5386,40 @@ var getMetadataFromWav = (structure) => {
5383
5386
 
5384
5387
  // src/metadata/metadata-from-iso.ts
5385
5388
  var mapToKey = (index) => {
5386
- if (index === 2839630420) {
5389
+ if (index === "�ART") {
5387
5390
  return "artist";
5388
5391
  }
5389
- if (index === 2841734242) {
5392
+ if (index === "�alb") {
5390
5393
  return "album";
5391
5394
  }
5392
- if (index === 2841865588) {
5395
+ if (index === "�cmt") {
5393
5396
  return "comment";
5394
5397
  }
5395
- if (index === 2841928057) {
5398
+ if (index === "�day") {
5396
5399
  return "releaseDate";
5397
5400
  }
5398
- if (index === 2842125678) {
5401
+ if (index === "�gen") {
5399
5402
  return "genre";
5400
5403
  }
5401
- if (index === 2842583405) {
5404
+ if (index === "�nam") {
5402
5405
  return "title";
5403
5406
  }
5404
- if (index === 2842980207) {
5407
+ if (index === "�too") {
5405
5408
  return "encoder";
5406
5409
  }
5407
- if (index === 2843177588) {
5410
+ if (index === "�wrt") {
5408
5411
  return "writer";
5409
5412
  }
5410
- if (index === 2841866361) {
5413
+ if (index === "�cpy") {
5411
5414
  return "copyright";
5412
5415
  }
5413
- if (index === 2841930098) {
5416
+ if (index === "�dir") {
5414
5417
  return "director";
5415
5418
  }
5416
- if (index === 2842718820) {
5419
+ if (index === "�prd") {
5417
5420
  return "producer";
5418
5421
  }
5419
- if (index === 2841929075) {
5422
+ if (index === "�des") {
5420
5423
  return "description";
5421
5424
  }
5422
5425
  return null;
@@ -7499,6 +7502,18 @@ var needsToIterateOverSamples = ({
7499
7502
  const selectedKeys = keys.filter((k) => fields[k]);
7500
7503
  return selectedKeys.some((k) => fieldsNeedSamplesMap[k] && !emittedFields[k]);
7501
7504
  };
7505
+ var fieldsNeedEverySampleMap = {
7506
+ ...fieldsNeedSamplesMap,
7507
+ slowDurationInSeconds: false
7508
+ };
7509
+ var needsToIterateOverEverySample = ({
7510
+ fields,
7511
+ emittedFields
7512
+ }) => {
7513
+ const keys = Object.keys(fields ?? {});
7514
+ const selectedKeys = keys.filter((k) => fields[k]);
7515
+ return selectedKeys.some((k) => fieldsNeedEverySampleMap[k] && !emittedFields[k]);
7516
+ };
7502
7517
 
7503
7518
  // src/disallow-forward-seek-if-samples-are-needed.ts
7504
7519
  var disallowForwardSeekIfSamplesAreNeeded = ({
@@ -8194,11 +8209,26 @@ var emitAvailableInfo = async ({
8194
8209
  };
8195
8210
 
8196
8211
  // src/state/may-skip-video-data.ts
8197
- var maySkipVideoData = ({ state }) => {
8198
- const hasAllTracksAndNoCallbacks = state.callbacks.tracks.hasAllTracks() && Object.values(state.callbacks.videoSampleCallbacks).length === 0 && Object.values(state.callbacks.audioSampleCallbacks).length === 0;
8212
+ var getHasCallbacks = (state) => {
8199
8213
  const hasNoTrackHandlers = !state.callbacks.hasAudioTrackHandlers && !state.callbacks.hasVideoTrackHandlers;
8200
- const noCallbacksNeeded = hasNoTrackHandlers || hasAllTracksAndNoCallbacks;
8201
- return noCallbacksNeeded && !needsToIterateOverSamples({
8214
+ if (hasNoTrackHandlers) {
8215
+ return false;
8216
+ }
8217
+ const hasAllTracksAndNoCallbacks = !state.callbacks.tracks.hasAllTracks() || Object.values(state.callbacks.videoSampleCallbacks).length > 0 || Object.values(state.callbacks.audioSampleCallbacks).length > 0;
8218
+ return hasAllTracksAndNoCallbacks;
8219
+ };
8220
+ var maySkipVideoData = ({ state }) => {
8221
+ const hasCallbacks = getHasCallbacks(state);
8222
+ return !hasCallbacks && !needsToIterateOverSamples({
8223
+ emittedFields: state.emittedFields,
8224
+ fields: state.fields
8225
+ });
8226
+ };
8227
+ var maySkipOverSamplesInTheMiddle = ({
8228
+ state
8229
+ }) => {
8230
+ const hasCallbacks = getHasCallbacks(state);
8231
+ return !hasCallbacks && !needsToIterateOverEverySample({
8202
8232
  emittedFields: state.emittedFields,
8203
8233
  fields: state.fields
8204
8234
  });
@@ -8276,7 +8306,7 @@ var getAvailableInfo = ({
8276
8306
  if (key === "m3uStreams") {
8277
8307
  return m3uHasStreams(state);
8278
8308
  }
8279
- throw new Error(`Unknown key: ${key}`);
8309
+ throw new Error(`Unknown field passed: ${key}. Available fields: ${Object.keys(state.fields).join(", ")}`);
8280
8310
  });
8281
8311
  const entries = [];
8282
8312
  let i = 0;
@@ -8969,6 +8999,13 @@ var getLastMoofBox = (boxes) => {
8969
8999
  return null;
8970
9000
  }
8971
9001
  };
9002
+ var getMaxFirstMoofOffset = (boxes) => {
9003
+ const tfras = boxes.filter((b) => b.type === "tfra-box");
9004
+ const firstMoofOffsets = tfras.map((f) => {
9005
+ return f.entries[0].moofOffset;
9006
+ });
9007
+ return Math.max(...firstMoofOffsets.filter(truthy));
9008
+ };
8972
9009
 
8973
9010
  // src/state/can-skip-tracks.ts
8974
9011
  var needsTracksForField = ({
@@ -9429,8 +9466,16 @@ var parseIlstBox = ({
9429
9466
  const entries = [];
9430
9467
  while (iterator.counter.getOffset() < size + offset) {
9431
9468
  const metadataSize = iterator.getUint32();
9432
- const index = iterator.getUint32();
9433
- if (index === 1936419184) {
9469
+ const index = iterator.getAtom();
9470
+ if (!index.startsWith("�") && !index.startsWith("\x00")) {
9471
+ if (index === "skip") {
9472
+ iterator.discard(metadataSize - 8);
9473
+ continue;
9474
+ }
9475
+ if (index === "----") {
9476
+ iterator.discard(metadataSize - 8);
9477
+ continue;
9478
+ }
9434
9479
  iterator.discard(metadataSize - 8);
9435
9480
  continue;
9436
9481
  }
@@ -11273,12 +11318,24 @@ var parseMdatSection = async (state) => {
11273
11318
  if (mfra) {
11274
11319
  const lastMoof = getLastMoofBox(mfra);
11275
11320
  if (lastMoof && lastMoof > endOfMdat) {
11276
- Log.verbose(state.logLevel, "Skipping to last moof", lastMoof, "end of mdat", endOfMdat);
11321
+ Log.verbose(state.logLevel, "Skipping to last moof", lastMoof);
11277
11322
  return makeSkip(lastMoof);
11278
11323
  }
11279
11324
  }
11280
11325
  return makeSkip(endOfMdat);
11281
11326
  }
11327
+ if (maySkipOverSamplesInTheMiddle({ state })) {
11328
+ const mfra = state.iso.mfra.getIfAlreadyLoaded();
11329
+ if (mfra) {
11330
+ const lastMoof = getLastMoofBox(mfra);
11331
+ const firstMax = getMaxFirstMoofOffset(mfra);
11332
+ const mediaSectionsBiggerThanMoof = state.mediaSection.getMediaSections().filter((m) => m.start > firstMax).length;
11333
+ if (mediaSectionsBiggerThanMoof > 1 && lastMoof && lastMoof > endOfMdat) {
11334
+ Log.verbose(state.logLevel, "Skipping to last moof because only first and last samples are needed");
11335
+ return makeSkip(lastMoof);
11336
+ }
11337
+ }
11338
+ }
11282
11339
  const alreadyHasMoov = getHasTracks(state, true);
11283
11340
  if (!alreadyHasMoov) {
11284
11341
  const moov = await getMoovAtom({
@@ -16524,29 +16581,25 @@ var samplesObservedState = () => {
16524
16581
  const videoSamples = new Map;
16525
16582
  const audioSamples = new Map;
16526
16583
  const getSlowVideoDurationInSeconds = () => {
16527
- let videoDuration = null;
16528
- if (smallestVideoSample !== undefined && largestVideoSample !== undefined) {
16529
- const startingTimestampDifference = largestVideoSample - smallestVideoSample;
16530
- const timeBetweenSamples = startingTimestampDifference / (videoSamples.size - 1);
16531
- videoDuration = timeBetweenSamples * videoSamples.size;
16532
- }
16533
- return videoDuration;
16584
+ return (largestVideoSample ?? 0) - (smallestVideoSample ?? 0);
16585
+ };
16586
+ const getSlowAudioDurationInSeconds = () => {
16587
+ return (largestAudioSample ?? 0) - (smallestAudioSample ?? 0);
16534
16588
  };
16535
16589
  const getSlowDurationInSeconds = () => {
16536
- const videoDuration = getSlowVideoDurationInSeconds();
16537
- let audioDuration = null;
16538
- if (smallestAudioSample !== undefined && largestAudioSample !== undefined) {
16539
- const startingTimestampDifferenceAudio = largestAudioSample - smallestAudioSample;
16540
- const timeBetweenSamplesAudio = startingTimestampDifferenceAudio / (audioSamples.size - 1);
16541
- audioDuration = timeBetweenSamplesAudio * audioSamples.size;
16590
+ const smallestSample = Math.min(smallestAudioSample ?? Infinity, smallestVideoSample ?? Infinity);
16591
+ const largestSample = Math.max(largestAudioSample ?? 0, largestVideoSample ?? 0);
16592
+ if (smallestSample === Infinity || largestSample === Infinity) {
16593
+ return 0;
16542
16594
  }
16543
- return Math.max(videoDuration ?? 0, audioDuration ?? 0);
16595
+ return largestSample - smallestSample;
16544
16596
  };
16545
16597
  const addVideoSample = (videoSample) => {
16546
16598
  videoSamples.set(videoSample.cts, videoSample.data.byteLength);
16547
16599
  const presentationTimeInSeconds = videoSample.cts / videoSample.timescale;
16600
+ const duration2 = (videoSample.duration ?? 0) / videoSample.timescale;
16548
16601
  if (largestVideoSample === undefined || presentationTimeInSeconds > largestVideoSample) {
16549
- largestVideoSample = presentationTimeInSeconds;
16602
+ largestVideoSample = presentationTimeInSeconds + duration2;
16550
16603
  }
16551
16604
  if (smallestVideoSample === undefined || presentationTimeInSeconds < smallestVideoSample) {
16552
16605
  smallestVideoSample = presentationTimeInSeconds;
@@ -16555,23 +16608,24 @@ var samplesObservedState = () => {
16555
16608
  const addAudioSample = (audioSample) => {
16556
16609
  audioSamples.set(audioSample.cts, audioSample.data.byteLength);
16557
16610
  const presentationTimeInSeconds = audioSample.cts / audioSample.timescale;
16611
+ const duration2 = (audioSample.duration ?? 0) / audioSample.timescale;
16558
16612
  if (largestAudioSample === undefined || presentationTimeInSeconds > largestAudioSample) {
16559
- largestAudioSample = presentationTimeInSeconds;
16613
+ largestAudioSample = presentationTimeInSeconds + duration2;
16560
16614
  }
16561
16615
  if (smallestAudioSample === undefined || presentationTimeInSeconds < smallestAudioSample) {
16562
16616
  smallestAudioSample = presentationTimeInSeconds;
16563
16617
  }
16564
16618
  };
16565
16619
  const getFps2 = () => {
16566
- const videoDuration = getSlowVideoDurationInSeconds() ?? 0;
16620
+ const videoDuration = (largestVideoSample ?? 0) - (smallestVideoSample ?? 0);
16567
16621
  if (videoDuration === 0) {
16568
16622
  return 0;
16569
16623
  }
16570
- return videoSamples.size / videoDuration;
16624
+ return (videoSamples.size - 1) / videoDuration;
16571
16625
  };
16572
16626
  const getSlowNumberOfFrames = () => videoSamples.size;
16573
16627
  const getAudioBitrate = () => {
16574
- const audioDuration = getSlowDurationInSeconds();
16628
+ const audioDuration = getSlowAudioDurationInSeconds();
16575
16629
  if (audioDuration === 0 || audioSamples.size === 0) {
16576
16630
  return null;
16577
16631
  }
@@ -16579,7 +16633,7 @@ var samplesObservedState = () => {
16579
16633
  return audioSizesInBytes * 8 / audioDuration;
16580
16634
  };
16581
16635
  const getVideoBitrate = () => {
16582
- const videoDuration = getSlowDurationInSeconds();
16636
+ const videoDuration = getSlowVideoDurationInSeconds();
16583
16637
  if (videoDuration === 0 || videoSamples.size === 0) {
16584
16638
  return null;
16585
16639
  }
@@ -16599,7 +16653,8 @@ var samplesObservedState = () => {
16599
16653
  getAudioBitrate,
16600
16654
  getVideoBitrate,
16601
16655
  getLastSampleObserved,
16602
- setLastSampleObserved
16656
+ setLastSampleObserved,
16657
+ getAmountOfSamplesObserved: () => videoSamples.size + audioSamples.size
16603
16658
  };
16604
16659
  };
16605
16660
 
@@ -5295,40 +5295,40 @@ var getMetadataFromWav = (structure) => {
5295
5295
 
5296
5296
  // src/metadata/metadata-from-iso.ts
5297
5297
  var mapToKey = (index) => {
5298
- if (index === 2839630420) {
5298
+ if (index === "�ART") {
5299
5299
  return "artist";
5300
5300
  }
5301
- if (index === 2841734242) {
5301
+ if (index === "�alb") {
5302
5302
  return "album";
5303
5303
  }
5304
- if (index === 2841865588) {
5304
+ if (index === "�cmt") {
5305
5305
  return "comment";
5306
5306
  }
5307
- if (index === 2841928057) {
5307
+ if (index === "�day") {
5308
5308
  return "releaseDate";
5309
5309
  }
5310
- if (index === 2842125678) {
5310
+ if (index === "�gen") {
5311
5311
  return "genre";
5312
5312
  }
5313
- if (index === 2842583405) {
5313
+ if (index === "�nam") {
5314
5314
  return "title";
5315
5315
  }
5316
- if (index === 2842980207) {
5316
+ if (index === "�too") {
5317
5317
  return "encoder";
5318
5318
  }
5319
- if (index === 2843177588) {
5319
+ if (index === "�wrt") {
5320
5320
  return "writer";
5321
5321
  }
5322
- if (index === 2841866361) {
5322
+ if (index === "�cpy") {
5323
5323
  return "copyright";
5324
5324
  }
5325
- if (index === 2841930098) {
5325
+ if (index === "�dir") {
5326
5326
  return "director";
5327
5327
  }
5328
- if (index === 2842718820) {
5328
+ if (index === "�prd") {
5329
5329
  return "producer";
5330
5330
  }
5331
- if (index === 2841929075) {
5331
+ if (index === "�des") {
5332
5332
  return "description";
5333
5333
  }
5334
5334
  return null;
@@ -7411,6 +7411,18 @@ var needsToIterateOverSamples = ({
7411
7411
  const selectedKeys = keys.filter((k) => fields[k]);
7412
7412
  return selectedKeys.some((k) => fieldsNeedSamplesMap[k] && !emittedFields[k]);
7413
7413
  };
7414
+ var fieldsNeedEverySampleMap = {
7415
+ ...fieldsNeedSamplesMap,
7416
+ slowDurationInSeconds: false
7417
+ };
7418
+ var needsToIterateOverEverySample = ({
7419
+ fields,
7420
+ emittedFields
7421
+ }) => {
7422
+ const keys = Object.keys(fields ?? {});
7423
+ const selectedKeys = keys.filter((k) => fields[k]);
7424
+ return selectedKeys.some((k) => fieldsNeedEverySampleMap[k] && !emittedFields[k]);
7425
+ };
7414
7426
 
7415
7427
  // src/disallow-forward-seek-if-samples-are-needed.ts
7416
7428
  var disallowForwardSeekIfSamplesAreNeeded = ({
@@ -8106,11 +8118,26 @@ var emitAvailableInfo = async ({
8106
8118
  };
8107
8119
 
8108
8120
  // src/state/may-skip-video-data.ts
8109
- var maySkipVideoData = ({ state }) => {
8110
- const hasAllTracksAndNoCallbacks = state.callbacks.tracks.hasAllTracks() && Object.values(state.callbacks.videoSampleCallbacks).length === 0 && Object.values(state.callbacks.audioSampleCallbacks).length === 0;
8121
+ var getHasCallbacks = (state) => {
8111
8122
  const hasNoTrackHandlers = !state.callbacks.hasAudioTrackHandlers && !state.callbacks.hasVideoTrackHandlers;
8112
- const noCallbacksNeeded = hasNoTrackHandlers || hasAllTracksAndNoCallbacks;
8113
- return noCallbacksNeeded && !needsToIterateOverSamples({
8123
+ if (hasNoTrackHandlers) {
8124
+ return false;
8125
+ }
8126
+ const hasAllTracksAndNoCallbacks = !state.callbacks.tracks.hasAllTracks() || Object.values(state.callbacks.videoSampleCallbacks).length > 0 || Object.values(state.callbacks.audioSampleCallbacks).length > 0;
8127
+ return hasAllTracksAndNoCallbacks;
8128
+ };
8129
+ var maySkipVideoData = ({ state }) => {
8130
+ const hasCallbacks = getHasCallbacks(state);
8131
+ return !hasCallbacks && !needsToIterateOverSamples({
8132
+ emittedFields: state.emittedFields,
8133
+ fields: state.fields
8134
+ });
8135
+ };
8136
+ var maySkipOverSamplesInTheMiddle = ({
8137
+ state
8138
+ }) => {
8139
+ const hasCallbacks = getHasCallbacks(state);
8140
+ return !hasCallbacks && !needsToIterateOverEverySample({
8114
8141
  emittedFields: state.emittedFields,
8115
8142
  fields: state.fields
8116
8143
  });
@@ -8188,7 +8215,7 @@ var getAvailableInfo = ({
8188
8215
  if (key === "m3uStreams") {
8189
8216
  return m3uHasStreams(state);
8190
8217
  }
8191
- throw new Error(`Unknown key: ${key}`);
8218
+ throw new Error(`Unknown field passed: ${key}. Available fields: ${Object.keys(state.fields).join(", ")}`);
8192
8219
  });
8193
8220
  const entries = [];
8194
8221
  let i = 0;
@@ -8881,6 +8908,13 @@ var getLastMoofBox = (boxes) => {
8881
8908
  return null;
8882
8909
  }
8883
8910
  };
8911
+ var getMaxFirstMoofOffset = (boxes) => {
8912
+ const tfras = boxes.filter((b) => b.type === "tfra-box");
8913
+ const firstMoofOffsets = tfras.map((f) => {
8914
+ return f.entries[0].moofOffset;
8915
+ });
8916
+ return Math.max(...firstMoofOffsets.filter(truthy));
8917
+ };
8884
8918
 
8885
8919
  // src/state/can-skip-tracks.ts
8886
8920
  var needsTracksForField = ({
@@ -9341,8 +9375,16 @@ var parseIlstBox = ({
9341
9375
  const entries = [];
9342
9376
  while (iterator.counter.getOffset() < size + offset) {
9343
9377
  const metadataSize = iterator.getUint32();
9344
- const index = iterator.getUint32();
9345
- if (index === 1936419184) {
9378
+ const index = iterator.getAtom();
9379
+ if (!index.startsWith("�") && !index.startsWith("\x00")) {
9380
+ if (index === "skip") {
9381
+ iterator.discard(metadataSize - 8);
9382
+ continue;
9383
+ }
9384
+ if (index === "----") {
9385
+ iterator.discard(metadataSize - 8);
9386
+ continue;
9387
+ }
9346
9388
  iterator.discard(metadataSize - 8);
9347
9389
  continue;
9348
9390
  }
@@ -11185,12 +11227,24 @@ var parseMdatSection = async (state) => {
11185
11227
  if (mfra) {
11186
11228
  const lastMoof = getLastMoofBox(mfra);
11187
11229
  if (lastMoof && lastMoof > endOfMdat) {
11188
- Log.verbose(state.logLevel, "Skipping to last moof", lastMoof, "end of mdat", endOfMdat);
11230
+ Log.verbose(state.logLevel, "Skipping to last moof", lastMoof);
11189
11231
  return makeSkip(lastMoof);
11190
11232
  }
11191
11233
  }
11192
11234
  return makeSkip(endOfMdat);
11193
11235
  }
11236
+ if (maySkipOverSamplesInTheMiddle({ state })) {
11237
+ const mfra = state.iso.mfra.getIfAlreadyLoaded();
11238
+ if (mfra) {
11239
+ const lastMoof = getLastMoofBox(mfra);
11240
+ const firstMax = getMaxFirstMoofOffset(mfra);
11241
+ const mediaSectionsBiggerThanMoof = state.mediaSection.getMediaSections().filter((m) => m.start > firstMax).length;
11242
+ if (mediaSectionsBiggerThanMoof > 1 && lastMoof && lastMoof > endOfMdat) {
11243
+ Log.verbose(state.logLevel, "Skipping to last moof because only first and last samples are needed");
11244
+ return makeSkip(lastMoof);
11245
+ }
11246
+ }
11247
+ }
11194
11248
  const alreadyHasMoov = getHasTracks(state, true);
11195
11249
  if (!alreadyHasMoov) {
11196
11250
  const moov = await getMoovAtom({
@@ -16408,29 +16462,25 @@ var samplesObservedState = () => {
16408
16462
  const videoSamples = new Map;
16409
16463
  const audioSamples = new Map;
16410
16464
  const getSlowVideoDurationInSeconds = () => {
16411
- let videoDuration = null;
16412
- if (smallestVideoSample !== undefined && largestVideoSample !== undefined) {
16413
- const startingTimestampDifference = largestVideoSample - smallestVideoSample;
16414
- const timeBetweenSamples = startingTimestampDifference / (videoSamples.size - 1);
16415
- videoDuration = timeBetweenSamples * videoSamples.size;
16416
- }
16417
- return videoDuration;
16465
+ return (largestVideoSample ?? 0) - (smallestVideoSample ?? 0);
16466
+ };
16467
+ const getSlowAudioDurationInSeconds = () => {
16468
+ return (largestAudioSample ?? 0) - (smallestAudioSample ?? 0);
16418
16469
  };
16419
16470
  const getSlowDurationInSeconds = () => {
16420
- const videoDuration = getSlowVideoDurationInSeconds();
16421
- let audioDuration = null;
16422
- if (smallestAudioSample !== undefined && largestAudioSample !== undefined) {
16423
- const startingTimestampDifferenceAudio = largestAudioSample - smallestAudioSample;
16424
- const timeBetweenSamplesAudio = startingTimestampDifferenceAudio / (audioSamples.size - 1);
16425
- audioDuration = timeBetweenSamplesAudio * audioSamples.size;
16471
+ const smallestSample = Math.min(smallestAudioSample ?? Infinity, smallestVideoSample ?? Infinity);
16472
+ const largestSample = Math.max(largestAudioSample ?? 0, largestVideoSample ?? 0);
16473
+ if (smallestSample === Infinity || largestSample === Infinity) {
16474
+ return 0;
16426
16475
  }
16427
- return Math.max(videoDuration ?? 0, audioDuration ?? 0);
16476
+ return largestSample - smallestSample;
16428
16477
  };
16429
16478
  const addVideoSample = (videoSample) => {
16430
16479
  videoSamples.set(videoSample.cts, videoSample.data.byteLength);
16431
16480
  const presentationTimeInSeconds = videoSample.cts / videoSample.timescale;
16481
+ const duration2 = (videoSample.duration ?? 0) / videoSample.timescale;
16432
16482
  if (largestVideoSample === undefined || presentationTimeInSeconds > largestVideoSample) {
16433
- largestVideoSample = presentationTimeInSeconds;
16483
+ largestVideoSample = presentationTimeInSeconds + duration2;
16434
16484
  }
16435
16485
  if (smallestVideoSample === undefined || presentationTimeInSeconds < smallestVideoSample) {
16436
16486
  smallestVideoSample = presentationTimeInSeconds;
@@ -16439,23 +16489,24 @@ var samplesObservedState = () => {
16439
16489
  const addAudioSample = (audioSample) => {
16440
16490
  audioSamples.set(audioSample.cts, audioSample.data.byteLength);
16441
16491
  const presentationTimeInSeconds = audioSample.cts / audioSample.timescale;
16492
+ const duration2 = (audioSample.duration ?? 0) / audioSample.timescale;
16442
16493
  if (largestAudioSample === undefined || presentationTimeInSeconds > largestAudioSample) {
16443
- largestAudioSample = presentationTimeInSeconds;
16494
+ largestAudioSample = presentationTimeInSeconds + duration2;
16444
16495
  }
16445
16496
  if (smallestAudioSample === undefined || presentationTimeInSeconds < smallestAudioSample) {
16446
16497
  smallestAudioSample = presentationTimeInSeconds;
16447
16498
  }
16448
16499
  };
16449
16500
  const getFps2 = () => {
16450
- const videoDuration = getSlowVideoDurationInSeconds() ?? 0;
16501
+ const videoDuration = (largestVideoSample ?? 0) - (smallestVideoSample ?? 0);
16451
16502
  if (videoDuration === 0) {
16452
16503
  return 0;
16453
16504
  }
16454
- return videoSamples.size / videoDuration;
16505
+ return (videoSamples.size - 1) / videoDuration;
16455
16506
  };
16456
16507
  const getSlowNumberOfFrames = () => videoSamples.size;
16457
16508
  const getAudioBitrate = () => {
16458
- const audioDuration = getSlowDurationInSeconds();
16509
+ const audioDuration = getSlowAudioDurationInSeconds();
16459
16510
  if (audioDuration === 0 || audioSamples.size === 0) {
16460
16511
  return null;
16461
16512
  }
@@ -16463,7 +16514,7 @@ var samplesObservedState = () => {
16463
16514
  return audioSizesInBytes * 8 / audioDuration;
16464
16515
  };
16465
16516
  const getVideoBitrate = () => {
16466
- const videoDuration = getSlowDurationInSeconds();
16517
+ const videoDuration = getSlowVideoDurationInSeconds();
16467
16518
  if (videoDuration === 0 || videoSamples.size === 0) {
16468
16519
  return null;
16469
16520
  }
@@ -16483,7 +16534,8 @@ var samplesObservedState = () => {
16483
16534
  getAudioBitrate,
16484
16535
  getVideoBitrate,
16485
16536
  getLastSampleObserved,
16486
- setLastSampleObserved
16537
+ setLastSampleObserved,
16538
+ getAmountOfSamplesObserved: () => videoSamples.size + audioSamples.size
16487
16539
  };
16488
16540
  };
16489
16541
 
@@ -90,7 +90,7 @@ const getAvailableInfo = ({ state, }) => {
90
90
  if (key === 'm3uStreams') {
91
91
  return (0, get_streams_1.m3uHasStreams)(state);
92
92
  }
93
- throw new Error(`Unknown key: ${key}`);
93
+ throw new Error(`Unknown field passed: ${key}. Available fields: ${Object.keys(state.fields).join(', ')}`);
94
94
  });
95
95
  const entries = [];
96
96
  let i = 0;
package/dist/index.d.ts CHANGED
@@ -1039,6 +1039,7 @@ export declare const MediaParserInternals: {
1039
1039
  getVideoBitrate: () => number | null;
1040
1040
  getLastSampleObserved: () => boolean;
1041
1041
  setLastSampleObserved: () => void;
1042
+ getAmountOfSamplesObserved: () => number;
1042
1043
  };
1043
1044
  contentLength: number;
1044
1045
  images: {
@@ -31,40 +31,40 @@ const truthy_1 = require("../truthy");
31
31
  ▪ Hex: A9 64 65 73
32
32
  */
33
33
  const mapToKey = (index) => {
34
- if (index === 0xa9415254) {
34
+ if (index === '�ART') {
35
35
  return 'artist';
36
36
  }
37
- if (index === 0xa9616c62) {
37
+ if (index === '�alb') {
38
38
  return 'album';
39
39
  }
40
- if (index === 0xa9636d74) {
40
+ if (index === '�cmt') {
41
41
  return 'comment';
42
42
  }
43
- if (index === 0xa9646179) {
43
+ if (index === '�day') {
44
44
  return 'releaseDate';
45
45
  }
46
- if (index === 0xa967656e) {
46
+ if (index === '�gen') {
47
47
  return 'genre';
48
48
  }
49
- if (index === 0xa96e616d) {
49
+ if (index === '�nam') {
50
50
  return 'title';
51
51
  }
52
- if (index === 0xa9746f6f) {
52
+ if (index === '�too') {
53
53
  return 'encoder';
54
54
  }
55
- if (index === 0xa9777274) {
55
+ if (index === '�wrt') {
56
56
  return 'writer';
57
57
  }
58
- if (index === 0xa9637079) {
58
+ if (index === '�cpy') {
59
59
  return 'copyright';
60
60
  }
61
- if (index === 0xa9646972) {
61
+ if (index === '�dir') {
62
62
  return 'director';
63
63
  }
64
- if (index === 0xa9707264) {
64
+ if (index === '�prd') {
65
65
  return 'producer';
66
66
  }
67
- if (index === 0xa9646573) {
67
+ if (index === '�des') {
68
68
  return 'description';
69
69
  }
70
70
  return null;
@@ -30,6 +30,9 @@ const nodeReadContent = ({ src, range, controller }) => {
30
30
  c.enqueue(chunk);
31
31
  });
32
32
  stream.on('end', () => {
33
+ if (readerCancelled) {
34
+ return;
35
+ }
33
36
  c.close();
34
37
  });
35
38
  stream.on('error', (err) => {
@@ -1,2 +1,3 @@
1
1
  import type { IsoBaseMediaBox } from '../../containers/iso-base-media/base-media-box';
2
2
  export declare const getLastMoofBox: (boxes: IsoBaseMediaBox[]) => number | null | undefined;
3
+ export declare const getMaxFirstMoofOffset: (boxes: IsoBaseMediaBox[]) => number;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getLastMoofBox = void 0;
3
+ exports.getMaxFirstMoofOffset = exports.getLastMoofBox = void 0;
4
4
  const truthy_1 = require("../../truthy");
5
5
  const getLastMoofBox = (boxes) => {
6
6
  if (boxes) {
@@ -19,3 +19,11 @@ const getLastMoofBox = (boxes) => {
19
19
  }
20
20
  };
21
21
  exports.getLastMoofBox = getLastMoofBox;
22
+ const getMaxFirstMoofOffset = (boxes) => {
23
+ const tfras = boxes.filter((b) => b.type === 'tfra-box');
24
+ const firstMoofOffsets = tfras.map((f) => {
25
+ return f.entries[0].moofOffset;
26
+ });
27
+ return Math.max(...firstMoofOffsets.filter(truthy_1.truthy));
28
+ };
29
+ exports.getMaxFirstMoofOffset = getMaxFirstMoofOffset;
@@ -2,3 +2,6 @@ import type { ParserState } from './parser-state';
2
2
  export declare const maySkipVideoData: ({ state }: {
3
3
  state: ParserState;
4
4
  }) => boolean;
5
+ export declare const maySkipOverSamplesInTheMiddle: ({ state, }: {
6
+ state: ParserState;
7
+ }) => boolean;
@@ -1,18 +1,33 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.maySkipVideoData = void 0;
3
+ exports.maySkipOverSamplesInTheMiddle = exports.maySkipVideoData = void 0;
4
4
  const need_samples_for_fields_1 = require("./need-samples-for-fields");
5
- const maySkipVideoData = ({ state }) => {
6
- const hasAllTracksAndNoCallbacks = state.callbacks.tracks.hasAllTracks() &&
7
- Object.values(state.callbacks.videoSampleCallbacks).length === 0 &&
8
- Object.values(state.callbacks.audioSampleCallbacks).length === 0;
5
+ const getHasCallbacks = (state) => {
9
6
  const hasNoTrackHandlers = !state.callbacks.hasAudioTrackHandlers &&
10
7
  !state.callbacks.hasVideoTrackHandlers;
11
- const noCallbacksNeeded = hasNoTrackHandlers || hasAllTracksAndNoCallbacks;
12
- return (noCallbacksNeeded &&
8
+ if (hasNoTrackHandlers) {
9
+ return false;
10
+ }
11
+ const hasAllTracksAndNoCallbacks = !state.callbacks.tracks.hasAllTracks() ||
12
+ Object.values(state.callbacks.videoSampleCallbacks).length > 0 ||
13
+ Object.values(state.callbacks.audioSampleCallbacks).length > 0;
14
+ return hasAllTracksAndNoCallbacks;
15
+ };
16
+ const maySkipVideoData = ({ state }) => {
17
+ const hasCallbacks = getHasCallbacks(state);
18
+ return (!hasCallbacks &&
13
19
  !(0, need_samples_for_fields_1.needsToIterateOverSamples)({
14
20
  emittedFields: state.emittedFields,
15
21
  fields: state.fields,
16
22
  }));
17
23
  };
18
24
  exports.maySkipVideoData = maySkipVideoData;
25
+ const maySkipOverSamplesInTheMiddle = ({ state, }) => {
26
+ const hasCallbacks = getHasCallbacks(state);
27
+ return (!hasCallbacks &&
28
+ !(0, need_samples_for_fields_1.needsToIterateOverEverySample)({
29
+ emittedFields: state.emittedFields,
30
+ fields: state.fields,
31
+ }));
32
+ };
33
+ exports.maySkipOverSamplesInTheMiddle = maySkipOverSamplesInTheMiddle;
@@ -4,3 +4,7 @@ export declare const needsToIterateOverSamples: ({ fields, emittedFields, }: {
4
4
  fields: Options<ParseMediaFields>;
5
5
  emittedFields: AllOptions<ParseMediaFields>;
6
6
  }) => boolean;
7
+ export declare const needsToIterateOverEverySample: ({ fields, emittedFields, }: {
8
+ fields: Options<ParseMediaFields>;
9
+ emittedFields: AllOptions<ParseMediaFields>;
10
+ }) => boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.needsToIterateOverSamples = exports.fieldsNeedSamplesMap = void 0;
3
+ exports.needsToIterateOverEverySample = exports.needsToIterateOverSamples = exports.fieldsNeedSamplesMap = void 0;
4
4
  exports.fieldsNeedSamplesMap = {
5
5
  slowDurationInSeconds: true,
6
6
  slowFps: true,
@@ -37,3 +37,14 @@ const needsToIterateOverSamples = ({ fields, emittedFields, }) => {
37
37
  return selectedKeys.some((k) => exports.fieldsNeedSamplesMap[k] && !emittedFields[k]);
38
38
  };
39
39
  exports.needsToIterateOverSamples = needsToIterateOverSamples;
40
+ // For duration, we only need the first and last sample
41
+ const fieldsNeedEverySampleMap = {
42
+ ...exports.fieldsNeedSamplesMap,
43
+ slowDurationInSeconds: false,
44
+ };
45
+ const needsToIterateOverEverySample = ({ fields, emittedFields, }) => {
46
+ const keys = Object.keys(fields !== null && fields !== void 0 ? fields : {});
47
+ const selectedKeys = keys.filter((k) => fields[k]);
48
+ return selectedKeys.some((k) => fieldsNeedEverySampleMap[k] && !emittedFields[k]);
49
+ };
50
+ exports.needsToIterateOverEverySample = needsToIterateOverEverySample;
@@ -316,6 +316,7 @@ export declare const makeParserState: ({ hasAudioTrackHandlers, hasVideoTrackHan
316
316
  getVideoBitrate: () => number | null;
317
317
  getLastSampleObserved: () => boolean;
318
318
  setLastSampleObserved: () => void;
319
+ getAmountOfSamplesObserved: () => number;
319
320
  };
320
321
  contentLength: number;
321
322
  images: {
@@ -9,5 +9,6 @@ export declare const samplesObservedState: () => {
9
9
  getVideoBitrate: () => number | null;
10
10
  getLastSampleObserved: () => boolean;
11
11
  setLastSampleObserved: () => void;
12
+ getAmountOfSamplesObserved: () => number;
12
13
  };
13
14
  export type SamplesObservedState = ReturnType<typeof samplesObservedState>;
@@ -10,30 +10,27 @@ const samplesObservedState = () => {
10
10
  const videoSamples = new Map();
11
11
  const audioSamples = new Map();
12
12
  const getSlowVideoDurationInSeconds = () => {
13
- let videoDuration = null;
14
- if (smallestVideoSample !== undefined && largestVideoSample !== undefined) {
15
- const startingTimestampDifference = largestVideoSample - smallestVideoSample;
16
- const timeBetweenSamples = startingTimestampDifference / (videoSamples.size - 1);
17
- videoDuration = timeBetweenSamples * videoSamples.size;
18
- }
19
- return videoDuration;
13
+ return (largestVideoSample !== null && largestVideoSample !== void 0 ? largestVideoSample : 0) - (smallestVideoSample !== null && smallestVideoSample !== void 0 ? smallestVideoSample : 0);
14
+ };
15
+ const getSlowAudioDurationInSeconds = () => {
16
+ return (largestAudioSample !== null && largestAudioSample !== void 0 ? largestAudioSample : 0) - (smallestAudioSample !== null && smallestAudioSample !== void 0 ? smallestAudioSample : 0);
20
17
  };
21
18
  const getSlowDurationInSeconds = () => {
22
- const videoDuration = getSlowVideoDurationInSeconds();
23
- let audioDuration = null;
24
- if (smallestAudioSample !== undefined && largestAudioSample !== undefined) {
25
- const startingTimestampDifferenceAudio = largestAudioSample - smallestAudioSample;
26
- const timeBetweenSamplesAudio = startingTimestampDifferenceAudio / (audioSamples.size - 1);
27
- audioDuration = timeBetweenSamplesAudio * audioSamples.size;
19
+ const smallestSample = Math.min(smallestAudioSample !== null && smallestAudioSample !== void 0 ? smallestAudioSample : Infinity, smallestVideoSample !== null && smallestVideoSample !== void 0 ? smallestVideoSample : Infinity);
20
+ const largestSample = Math.max(largestAudioSample !== null && largestAudioSample !== void 0 ? largestAudioSample : 0, largestVideoSample !== null && largestVideoSample !== void 0 ? largestVideoSample : 0);
21
+ if (smallestSample === Infinity || largestSample === Infinity) {
22
+ return 0;
28
23
  }
29
- return Math.max(videoDuration !== null && videoDuration !== void 0 ? videoDuration : 0, audioDuration !== null && audioDuration !== void 0 ? audioDuration : 0);
24
+ return largestSample - smallestSample;
30
25
  };
31
26
  const addVideoSample = (videoSample) => {
27
+ var _a;
32
28
  videoSamples.set(videoSample.cts, videoSample.data.byteLength);
33
29
  const presentationTimeInSeconds = videoSample.cts / videoSample.timescale;
30
+ const duration = ((_a = videoSample.duration) !== null && _a !== void 0 ? _a : 0) / videoSample.timescale;
34
31
  if (largestVideoSample === undefined ||
35
32
  presentationTimeInSeconds > largestVideoSample) {
36
- largestVideoSample = presentationTimeInSeconds;
33
+ largestVideoSample = presentationTimeInSeconds + duration;
37
34
  }
38
35
  if (smallestVideoSample === undefined ||
39
36
  presentationTimeInSeconds < smallestVideoSample) {
@@ -41,11 +38,13 @@ const samplesObservedState = () => {
41
38
  }
42
39
  };
43
40
  const addAudioSample = (audioSample) => {
41
+ var _a;
44
42
  audioSamples.set(audioSample.cts, audioSample.data.byteLength);
45
43
  const presentationTimeInSeconds = audioSample.cts / audioSample.timescale;
44
+ const duration = ((_a = audioSample.duration) !== null && _a !== void 0 ? _a : 0) / audioSample.timescale;
46
45
  if (largestAudioSample === undefined ||
47
46
  presentationTimeInSeconds > largestAudioSample) {
48
- largestAudioSample = presentationTimeInSeconds;
47
+ largestAudioSample = presentationTimeInSeconds + duration;
49
48
  }
50
49
  if (smallestAudioSample === undefined ||
51
50
  presentationTimeInSeconds < smallestAudioSample) {
@@ -53,16 +52,15 @@ const samplesObservedState = () => {
53
52
  }
54
53
  };
55
54
  const getFps = () => {
56
- var _a;
57
- const videoDuration = (_a = getSlowVideoDurationInSeconds()) !== null && _a !== void 0 ? _a : 0;
55
+ const videoDuration = (largestVideoSample !== null && largestVideoSample !== void 0 ? largestVideoSample : 0) - (smallestVideoSample !== null && smallestVideoSample !== void 0 ? smallestVideoSample : 0);
58
56
  if (videoDuration === 0) {
59
57
  return 0;
60
58
  }
61
- return videoSamples.size / videoDuration;
59
+ return (videoSamples.size - 1) / videoDuration;
62
60
  };
63
61
  const getSlowNumberOfFrames = () => videoSamples.size;
64
62
  const getAudioBitrate = () => {
65
- const audioDuration = getSlowDurationInSeconds();
63
+ const audioDuration = getSlowAudioDurationInSeconds();
66
64
  if (audioDuration === 0 || audioSamples.size === 0) {
67
65
  return null;
68
66
  }
@@ -70,7 +68,7 @@ const samplesObservedState = () => {
70
68
  return (audioSizesInBytes * 8) / audioDuration;
71
69
  };
72
70
  const getVideoBitrate = () => {
73
- const videoDuration = getSlowDurationInSeconds();
71
+ const videoDuration = getSlowVideoDurationInSeconds();
74
72
  if (videoDuration === 0 || videoSamples.size === 0) {
75
73
  return null;
76
74
  }
@@ -91,6 +89,7 @@ const samplesObservedState = () => {
91
89
  getVideoBitrate,
92
90
  getLastSampleObserved,
93
91
  setLastSampleObserved,
92
+ getAmountOfSamplesObserved: () => videoSamples.size + audioSamples.size,
94
93
  };
95
94
  };
96
95
  exports.samplesObservedState = samplesObservedState;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "4.0.295";
1
+ export declare const VERSION = "4.0.297";
package/dist/version.js CHANGED
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  // Automatically generated on publish
5
- exports.VERSION = '4.0.295';
5
+ exports.VERSION = '4.0.297';
package/package.json CHANGED
@@ -3,15 +3,15 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/media-parser"
4
4
  },
5
5
  "name": "@remotion/media-parser",
6
- "version": "4.0.295",
6
+ "version": "4.0.297",
7
7
  "main": "dist/index.js",
8
8
  "sideEffects": false,
9
9
  "devDependencies": {
10
10
  "@types/wicg-file-system-access": "2023.10.5",
11
11
  "eslint": "9.19.0",
12
12
  "@types/bun": "1.2.8",
13
- "@remotion/example-videos": "4.0.295",
14
- "@remotion/eslint-config-internal": "4.0.295"
13
+ "@remotion/example-videos": "4.0.297",
14
+ "@remotion/eslint-config-internal": "4.0.297"
15
15
  },
16
16
  "publishConfig": {
17
17
  "access": "public"