@remotion/media-parser 4.0.267 → 4.0.268

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.
@@ -6,7 +6,6 @@ const traversal_1 = require("./containers/iso-base-media/traversal");
6
6
  const get_tracks_from_avi_1 = require("./containers/riff/get-tracks-from-avi");
7
7
  const get_tracks_1 = require("./containers/transport-stream/get-tracks");
8
8
  const get_ready_tracks_1 = require("./containers/webm/get-ready-tracks");
9
- const traversal_2 = require("./containers/webm/traversal");
10
9
  const getNumberOfTracks = (moovBox) => {
11
10
  const mvHdBox = (0, traversal_1.getMvhdBox)(moovBox);
12
11
  if (!mvHdBox) {
@@ -22,11 +21,7 @@ exports.isoBaseMediaHasTracks = isoBaseMediaHasTracks;
22
21
  const getHasTracks = (state) => {
23
22
  const structure = state.getStructure();
24
23
  if (structure.type === 'matroska') {
25
- const mainSegment = (0, traversal_2.getMainSegment)(structure.boxes);
26
- if (!mainSegment) {
27
- return false;
28
- }
29
- return (0, traversal_2.getTracksSegment)(mainSegment) !== null;
24
+ return (0, get_ready_tracks_1.matroskaHasTracks)(state);
30
25
  }
31
26
  if (structure.type === 'iso-base-media') {
32
27
  return (0, exports.isoBaseMediaHasTracks)(state);
@@ -55,16 +50,14 @@ const getHasTracks = (state) => {
55
50
  throw new Error('Unknown container ' + structure);
56
51
  };
57
52
  exports.getHasTracks = getHasTracks;
58
- const getTracksFromMa = (segments, state) => {
53
+ const getCategorizedTracksFromMatroska = (state) => {
59
54
  const videoTracks = [];
60
55
  const audioTracks = [];
61
56
  const otherTracks = [];
62
- const mainSegment = segments.find((s) => s.type === 'Segment');
63
- if (!mainSegment) {
64
- throw new Error('No main segment found');
65
- }
66
- const matroskaTracks = (0, get_ready_tracks_1.getTracksFromMatroska)(mainSegment, state.webm.getTimescale());
67
- for (const track of matroskaTracks) {
57
+ const { resolved } = (0, get_ready_tracks_1.getTracksFromMatroska)({
58
+ state,
59
+ });
60
+ for (const track of resolved) {
68
61
  if (track.type === 'video') {
69
62
  videoTracks.push(track);
70
63
  }
@@ -141,7 +134,7 @@ exports.defaultHasallTracks = defaultHasallTracks;
141
134
  const getTracks = (state) => {
142
135
  const structure = state.getStructure();
143
136
  if (structure.type === 'matroska') {
144
- return getTracksFromMa(structure.boxes, state);
137
+ return getCategorizedTracksFromMatroska(state);
145
138
  }
146
139
  if (structure.type === 'iso-base-media') {
147
140
  return (0, exports.getTracksFromIsoBaseMedia)(state);
@@ -107,8 +107,12 @@ const hasAllInfo = ({ fields, state, }) => {
107
107
  if (!Object.values(availableInfo).every(Boolean)) {
108
108
  return false;
109
109
  }
110
- const canSkipSamples = (0, may_skip_video_data_1.maySkipVideoData)({ state }) ||
111
- state.callbacks.canSkipTracksState.canSkipTracks();
112
- return canSkipSamples;
110
+ if ((0, may_skip_video_data_1.maySkipVideoData)({ state })) {
111
+ return true;
112
+ }
113
+ if (state.callbacks.canSkipTracksState.canSkipTracks()) {
114
+ return true;
115
+ }
116
+ return false;
113
117
  };
114
118
  exports.hasAllInfo = hasAllInfo;
package/dist/index.d.ts CHANGED
@@ -881,6 +881,8 @@ export declare const MediaParserInternals: {
881
881
  addCluster: (cluster: import("./state/webm").ClusterSection) => void;
882
882
  isInsideSegment: (iterator: import("./buffer-iterator").BufferIterator) => import("./state/webm").SegmentSection | null;
883
883
  isInsideCluster: (iterator: import("./buffer-iterator").BufferIterator) => import("./state/webm").ClusterSection | null;
884
+ setAvcProfileForTrackNumber: (trackNumber: number, avcProfile: import("./containers/avc/parse-avc").AvcProfileInfo) => void;
885
+ getAvcProfileForTrackNumber: (trackNumber: number) => import("./containers/avc/parse-avc").AvcProfileInfo | null;
884
886
  };
885
887
  iso: {
886
888
  flatSamples: {
@@ -895,6 +897,8 @@ export declare const MediaParserInternals: {
895
897
  mp3Info: {
896
898
  getMp3Info: () => import("./state/mp3").Mp3Info | null;
897
899
  setMp3Info: (info: import("./state/mp3").Mp3Info) => void;
900
+ getCbrMp3Info: () => import("./state/mp3").Mp3CbrInfo | null;
901
+ setCbrMp3Info: (info: import("./state/mp3").Mp3CbrInfo) => void;
898
902
  };
899
903
  aac: {
900
904
  addSample: ({ offset, size }: {
@@ -26,7 +26,7 @@ const internalParseMedia = async function ({ src, fields: _fieldsInReturnValue,
26
26
  log_1.Log.verbose(logLevel, `Reading ${typeof src === 'string' ? src : src.name}`);
27
27
  const { reader: readerInstance, contentLength, name, contentType, supportsContentRange, needsContentRange, } = await readerInterface.read({ src, range: null, controller });
28
28
  if (contentLength === null) {
29
- throw new Error('Cannot read media without a content length. This is currently not supported. Ensure the media has a "Content-Length" HTTP header.');
29
+ throw new Error(`Cannot read media ${src} without a content length. This is currently not supported. Ensure the media has a "Content-Length" HTTP header.`);
30
30
  }
31
31
  if (!supportsContentRange && needsContentRange) {
32
32
  throw new Error('Cannot read media without it supporting the "Content-Range" header. This is currently not supported. Ensure the media supports the "Content-Range" HTTP header.');
@@ -4,5 +4,10 @@ type ReturnType = {
4
4
  contentLength: number | null;
5
5
  needsContentRange: boolean;
6
6
  };
7
- export declare const getLengthAndReader: (endsWithM3u8: boolean, res: Response, ownController: AbortController) => Promise<ReturnType>;
7
+ export declare const getLengthAndReader: ({ canLiveWithoutContentLength, res, ownController, requestedWithoutRange, }: {
8
+ canLiveWithoutContentLength: boolean;
9
+ res: Response;
10
+ ownController: AbortController;
11
+ requestedWithoutRange: boolean;
12
+ }) => Promise<ReturnType>;
8
13
  export {};
@@ -1,10 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getLengthAndReader = void 0;
4
- const getLengthAndReader = async (endsWithM3u8, res, ownController) => {
5
- if (endsWithM3u8) {
6
- const text = await res.text();
7
- const encoded = new TextEncoder().encode(text);
4
+ const getLengthAndReader = async ({ canLiveWithoutContentLength, res, ownController, requestedWithoutRange, }) => {
5
+ const length = res.headers.get('content-length');
6
+ const contentLength = length === null ? null : parseInt(length, 10);
7
+ if (requestedWithoutRange ||
8
+ (canLiveWithoutContentLength && contentLength === null)) {
9
+ const buffer = await res.arrayBuffer();
10
+ const encoded = new Uint8Array(buffer);
8
11
  const stream = new ReadableStream({
9
12
  start(controller) {
10
13
  controller.enqueue(encoded);
@@ -22,8 +25,6 @@ const getLengthAndReader = async (endsWithM3u8, res, ownController) => {
22
25
  needsContentRange: false,
23
26
  };
24
27
  }
25
- const length = res.headers.get('content-length');
26
- const contentLength = length === null ? null : parseInt(length, 10);
27
28
  if (!res.body) {
28
29
  throw new Error('No body');
29
30
  }
@@ -27,7 +27,7 @@ function parseContentRange(input) {
27
27
  }
28
28
  return range;
29
29
  }
30
- const validateContentRangeAndDetectIfSupported = (actualRange, parsedContentRange, statusCode) => {
30
+ const validateContentRangeAndDetectIfSupported = ({ actualRange, parsedContentRange, statusCode, }) => {
31
31
  if (statusCode === 206) {
32
32
  return { supportsContentRange: true };
33
33
  }
@@ -66,8 +66,10 @@ exports.fetchReader = {
66
66
  : // Disable Next.js caching
67
67
  'no-store';
68
68
  const actualRange = range === null ? 0 : range;
69
- const endsWithM3u8 = (typeof resolvedUrl === 'string' ? resolvedUrl : resolvedUrl.pathname).endsWith('.m3u8');
70
- const headers = actualRange === 0 && endsWithM3u8
69
+ const asString = typeof resolvedUrl === 'string' ? resolvedUrl : resolvedUrl.pathname;
70
+ const requestWithoutRange = asString.endsWith('.m3u8');
71
+ const canLiveWithoutContentLength = asString.endsWith('.m3u8') || asString.endsWith('.ts');
72
+ const headers = actualRange === 0 && requestWithoutRange
71
73
  ? {}
72
74
  : typeof actualRange === 'number'
73
75
  ? {
@@ -85,7 +87,11 @@ exports.fetchReader = {
85
87
  const parsedContentRange = contentRange
86
88
  ? parseContentRange(contentRange)
87
89
  : null;
88
- const { supportsContentRange } = validateContentRangeAndDetectIfSupported(actualRange, parsedContentRange, res.status);
90
+ const { supportsContentRange } = validateContentRangeAndDetectIfSupported({
91
+ actualRange,
92
+ parsedContentRange,
93
+ statusCode: res.status,
94
+ });
89
95
  controller._internals.signal.addEventListener('abort', () => {
90
96
  ownController.abort(new errors_1.MediaParserAbortError('Aborted by user'));
91
97
  }, { once: true });
@@ -96,7 +102,12 @@ exports.fetchReader = {
96
102
  const contentDisposition = res.headers.get('content-disposition');
97
103
  const name = (_a = contentDisposition === null || contentDisposition === void 0 ? void 0 : contentDisposition.match(/filename="([^"]+)"/)) === null || _a === void 0 ? void 0 : _a[1];
98
104
  const fallbackName = src.split('/').pop();
99
- const { contentLength, needsContentRange, reader } = await (0, get_body_and_reader_1.getLengthAndReader)(endsWithM3u8, res, ownController);
105
+ const { contentLength, needsContentRange, reader } = await (0, get_body_and_reader_1.getLengthAndReader)({
106
+ canLiveWithoutContentLength,
107
+ res,
108
+ ownController,
109
+ requestedWithoutRange: requestWithoutRange,
110
+ });
100
111
  if (controller) {
101
112
  controller._internals.signal.addEventListener('abort', () => {
102
113
  reader.reader.cancel().catch(() => {
@@ -2,10 +2,14 @@ export type Mp3Info = {
2
2
  sampleRate: number;
3
3
  mpegVersion: 1 | 2;
4
4
  layer: number;
5
- bitrateKbit: number;
6
5
  startOfMpegStream: number;
7
6
  };
7
+ export type Mp3CbrInfo = {
8
+ bitrateKbit: number;
9
+ };
8
10
  export declare const makeMp3State: () => {
9
11
  getMp3Info: () => Mp3Info | null;
10
12
  setMp3Info: (info: Mp3Info) => void;
13
+ getCbrMp3Info: () => Mp3CbrInfo | null;
14
+ setCbrMp3Info: (info: Mp3CbrInfo) => void;
11
15
  };
package/dist/state/mp3.js CHANGED
@@ -3,11 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeMp3State = void 0;
4
4
  const makeMp3State = () => {
5
5
  let mp3Info = null;
6
+ // cbr = constant bit rate
7
+ let cbrMp3Info = null;
6
8
  return {
7
9
  getMp3Info: () => mp3Info,
8
10
  setMp3Info: (info) => {
9
11
  mp3Info = info;
10
12
  },
13
+ getCbrMp3Info: () => cbrMp3Info,
14
+ setCbrMp3Info: (info) => {
15
+ cbrMp3Info = info;
16
+ },
11
17
  };
12
18
  };
13
19
  exports.makeMp3State = makeMp3State;
@@ -168,6 +168,8 @@ export declare const makeParserState: ({ hasAudioTrackHandlers, hasVideoTrackHan
168
168
  addCluster: (cluster: import("./webm").ClusterSection) => void;
169
169
  isInsideSegment: (iterator: BufferIterator) => import("./webm").SegmentSection | null;
170
170
  isInsideCluster: (iterator: BufferIterator) => import("./webm").ClusterSection | null;
171
+ setAvcProfileForTrackNumber: (trackNumber: number, avcProfile: AvcProfileInfo) => void;
172
+ getAvcProfileForTrackNumber: (trackNumber: number) => AvcProfileInfo | null;
171
173
  };
172
174
  iso: {
173
175
  flatSamples: {
@@ -182,6 +184,8 @@ export declare const makeParserState: ({ hasAudioTrackHandlers, hasVideoTrackHan
182
184
  mp3Info: {
183
185
  getMp3Info: () => import("./mp3").Mp3Info | null;
184
186
  setMp3Info: (info: import("./mp3").Mp3Info) => void;
187
+ getCbrMp3Info: () => import("./mp3").Mp3CbrInfo | null;
188
+ setCbrMp3Info: (info: import("./mp3").Mp3CbrInfo) => void;
185
189
  };
186
190
  aac: {
187
191
  addSample: ({ offset, size }: {
@@ -1,4 +1,5 @@
1
1
  import type { BufferIterator } from '../buffer-iterator';
2
+ import type { AvcProfileInfo } from '../containers/avc/parse-avc';
2
3
  import type { OnTrackEntrySegment } from '../containers/webm/segments';
3
4
  import type { TrackInfo } from '../containers/webm/segments/track-entry';
4
5
  export type SegmentSection = {
@@ -23,4 +24,7 @@ export declare const webmState: () => {
23
24
  addCluster: (cluster: ClusterSection) => void;
24
25
  isInsideSegment: (iterator: BufferIterator) => SegmentSection | null;
25
26
  isInsideCluster: (iterator: BufferIterator) => ClusterSection | null;
27
+ setAvcProfileForTrackNumber: (trackNumber: number, avcProfile: AvcProfileInfo) => void;
28
+ getAvcProfileForTrackNumber: (trackNumber: number) => AvcProfileInfo | null;
26
29
  };
30
+ export type WebmState = ReturnType<typeof webmState>;
@@ -56,6 +56,14 @@ const webmState = () => {
56
56
  };
57
57
  const segments = [];
58
58
  const clusters = [];
59
+ const avcProfilesMap = {};
60
+ const setAvcProfileForTrackNumber = (trackNumber, avcProfile) => {
61
+ avcProfilesMap[trackNumber] = avcProfile;
62
+ };
63
+ const getAvcProfileForTrackNumber = (trackNumber) => {
64
+ var _a;
65
+ return (_a = avcProfilesMap[trackNumber]) !== null && _a !== void 0 ? _a : null;
66
+ };
59
67
  return {
60
68
  onTrackEntrySegment,
61
69
  getTrackInfoByNumber: (id) => trackEntries[id],
@@ -94,6 +102,8 @@ const webmState = () => {
94
102
  }
95
103
  return null;
96
104
  },
105
+ setAvcProfileForTrackNumber,
106
+ getAvcProfileForTrackNumber,
97
107
  };
98
108
  };
99
109
  exports.webmState = webmState;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "4.0.267";
1
+ export declare const VERSION = "4.0.268";
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.267';
5
+ exports.VERSION = '4.0.268';
package/package.json CHANGED
@@ -3,14 +3,14 @@
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.267",
6
+ "version": "4.0.268",
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
- "@remotion/example-videos": "4.0.267",
13
- "@remotion/eslint-config-internal": "4.0.267"
12
+ "@remotion/eslint-config-internal": "4.0.268",
13
+ "@remotion/example-videos": "4.0.268"
14
14
  },
15
15
  "publishConfig": {
16
16
  "access": "public"