Skip to content

Commit 7c96f01

Browse files
authored
Merge pull request #5320 from remotion-dev/create-decoder
2 parents 8522ced + 1d42ea5 commit 7c96f01

16 files changed

+391
-40
lines changed

packages/docs/docs/media-parser/samples.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
---
2+
image: /generated/articles-docs-media-parser-samples.png
23
id: samples
34
title: Extract samples
45
slug: /media-parser/samples

packages/docs/docs/webcodecs/TableOfContents.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,22 @@ export const TableOfContents: React.FC = () => {
106106
<TOCItem link="/docs/webcodecs/convert-audiodata">
107107
<strong>{'convertAudioData()'}</strong>
108108
<div>
109-
Change the format or sample rate of an <code>AudioData</code>
109+
Change the format or sample rate of an <code>AudioData</code>{' '}
110110
object.
111111
</div>
112112
</TOCItem>
113+
<TOCItem link="/docs/webcodecs/create-audio-decoder">
114+
<strong>{'createAudioDecoder()'}</strong>
115+
<div>
116+
Create an <code>AudioDecoder</code> object.
117+
</div>
118+
</TOCItem>
119+
<TOCItem link="/docs/webcodecs/create-video-decoder">
120+
<strong>{'createVideoDecoder()'}</strong>
121+
<div>
122+
Create a <code>VideoDecoder</code> object.
123+
</div>
124+
</TOCItem>
113125
</Grid>
114126
</div>
115127
);
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
---
2+
image: /generated/articles-docs-webcodecs-create-audio-decoder.png
3+
sidebar_label: createAudioDecoder()
4+
title: createAudioDecoder()
5+
slug: /webcodecs/create-audio-decoder
6+
crumb: '@remotion/webcodecs'
7+
---
8+
9+
import {UnstableDisclaimer} from './UnstableDisclaimer';
10+
11+
:::warning
12+
13+
<UnstableDisclaimer />
14+
:::
15+
16+
# createAudioDecoder()<AvailableFrom v="4.0.307" />
17+
18+
This function is a wrapper around the [`AudioDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder) Web API.
19+
20+
```tsx twoslash title="Create an audio decoder"
21+
import type {MediaParserAudioTrack} from '@remotion/media-parser';
22+
23+
const track = {} as unknown as MediaParserAudioTrack;
24+
25+
// ---cut---
26+
27+
import {createAudioDecoder} from '@remotion/webcodecs';
28+
29+
const decoder = createAudioDecoder({
30+
track,
31+
onFrame: console.log,
32+
onError: console.error,
33+
});
34+
```
35+
36+
## Differences to `AudioDecoder`
37+
38+
- Samples with a `codec` of `pcm-s16` are accepted and passed through, even if the `AudioDecoder` object does not exist or support it.
39+
- Two new methods are added: [`.waitForQueueToBeLessThan()`](#waitforqueuetobelessthanqueue-size-number) and [`.waitForFinish()`](#waitforfinish).
40+
- The [`dequeue`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder/dequeue_event) event is not supported as it is not reliable across browsers.
41+
- In addition to [`EncodedAudioChunk`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedAudioChunk), [`EncodedAudioChunkInit`](https://www.w3.org/TR/webcodecs/#dictdef-encodedaudiochunkinit) objects are also accepted for [`.decode()`](#decode).
42+
- A [`webcodecsController()`](/docs/webcodecs/webcodecs-controller) instance can be passed in to the function, allowing for decoding to be paused, resumed and aborted.
43+
- [`.decode()`](#decode) is async, and returns a promise, allowing for a halt if the decoder is paused.
44+
- Only samples with a size of 16 bytes or more are actually being input, [to avoid a bug in Chrome](https://github.com/remotion-dev/remotion/blob/c7f18a85bcb1bc58d3811efcd9e68c96ff38ccae/packages/webcodecs/src/create-audio-decoder.ts#L121-L129).
45+
- A [`logLevel`](#loglevel) can be passed in to the function, allowing the queue to be debugged.
46+
- The [`onFrame`](#onframe) callback is being awaited. When rejected, the error lands in the [`onError`](#onerror) callback. When resolved, only then the queue size counter will be decreased.
47+
48+
## API
49+
50+
Takes an object with the following properties:
51+
52+
### `track`
53+
54+
An [`AudioDecoderConfig`](https://www.w3.org/TR/webcodecs/#dictdef-audiodecoderconfig) object.
55+
You may pass a [`MediaParserAudioTrack`](/docs/media-parser/types#mediaparseraudiotrack) object from [`parseMedia()`](/docs/media-parser/parse-media), which also is an `AudioDecoderConfig` object.
56+
57+
### `onFrame`
58+
59+
A callback that is called when a frame is decoded.
60+
61+
Takes a single argument, which is an [`AudioData`](https://developer.mozilla.org/en-US/docs/Web/API/AudioData) object.
62+
63+
Only once the callback resolves, the queue size counter will be decreased.
64+
65+
### `onError`
66+
67+
A callback that is called when an error occurs or the decode is aborted through the controller.
68+
69+
Takes a single argument, which is an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object.
70+
71+
### `controller?`
72+
73+
A [`webcodecsController()`](/docs/webcodecs/webcodecs-controller) instance.
74+
75+
If provided, you can call [`.pause()`](/docs/webcodecs/webcodecs-controller#pause), [`.resume()`](/docs/webcodecs/webcodecs-controller#resume) and [`.abort()`](/docs/webcodecs/webcodecs-controller#abort) on the controller to pause, resume and abort the decoding.
76+
77+
78+
### `logLevel?`
79+
80+
_string_ <TsType type="LogLevel" source="@remotion/media-parser"/>
81+
82+
One of `"error"`, `"warn"`, `"info"`, `"debug"`, `"trace"`.
83+
Default value: `"info"`, which logs only important information.
84+
85+
## Return type
86+
87+
Returns an object with the following properties:
88+
89+
90+
### `decode(sample: EncodedAudioChunkInit | EncodedAudioChunk)`
91+
92+
Decodes a sample. Same as [`AudioDecoder.decode()`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder/decode).
93+
You can pass in a [`MediaParserAudioSample`](/docs/media-parser/types#mediaparseraudiosample) object from [`parseMedia()`](/docs/media-parser/parse-media), which also satisfies the [`EncodedAudioChunkInit`](https://www.w3.org/TR/webcodecs/#dictdef-encodedaudiochunkinit) interface.
94+
95+
96+
### `waitForQueueToBeLessThan(queueSize: number)`
97+
98+
A promise that resolves when the queue size is less than the given number.
99+
The queue is only decremented when the[ `onFrame`](#onframe) callback resolves.
100+
101+
### `waitForFinish()`
102+
103+
A promise that resolves when the decoder is finished.
104+
105+
### `flush()`
106+
107+
Flushes the decoder. Same as [`AudioDecoder.flush()`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder/flush).
108+
109+
### `close()`
110+
111+
Closes the decoder. Same as [`AudioDecoder.close()`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder/close).
112+
113+
## Example usage with `@remotion/media-parser`
114+
115+
In this example, the whole audio track is decoded and the decoder is closed when the track is done.
116+
By using `async` / `await`, the [`parseMedia()`](/docs/media-parser/parse-media) call is artificially slowed down to not flood the `AudioDecoder` and cause much memory to be allocated.
117+
118+
```tsx twoslash title="Decode an audio track"
119+
import {parseMedia} from '@remotion/media-parser';
120+
import {createAudioDecoder} from '@remotion/webcodecs';
121+
122+
await parseMedia({
123+
src: 'https://parser.media/video.mp4',
124+
onAudioTrack: ({track, container}) => {
125+
const decoder = createAudioDecoder({
126+
track,
127+
onFrame: console.log,
128+
onError: console.error,
129+
});
130+
131+
return async (sample) => {
132+
// Called on every sample
133+
await decoder.waitForQueueToBeLessThan(10);
134+
await decoder.decode(sample);
135+
136+
return async () => {
137+
// Called when the track is done
138+
await decoder.flush();
139+
await decoder.waitForFinish();
140+
decoder.close()
141+
};
142+
};
143+
},
144+
});
145+
```
146+
147+
148+
## See also
149+
150+
- [Source code for this function](https://github.com/remotion-dev/remotion/blob/main/packages/webcodecs/src/create-audio-decoder.ts)
151+
- [`@remotion/webcodecs`](/docs/webcodecs)
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
---
2+
image: /generated/articles-docs-webcodecs-create-video-decoder.png
3+
sidebar_label: createVideoDecoder()
4+
title: createVideoDecoder()
5+
slug: /webcodecs/create-video-decoder
6+
crumb: '@remotion/webcodecs'
7+
---
8+
9+
import {UnstableDisclaimer} from './UnstableDisclaimer';
10+
11+
:::warning
12+
13+
<UnstableDisclaimer />
14+
:::
15+
16+
# createVideoDecoder()<AvailableFrom v="4.0.307" />
17+
18+
This function is a wrapper around the [`VideoDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder) Web API.
19+
20+
```tsx twoslash title="Create a video decoder"
21+
import type {MediaParserVideoTrack} from '@remotion/media-parser';
22+
23+
const track = {} as unknown as MediaParserVideoTrack;
24+
25+
// ---cut---
26+
27+
import {createVideoDecoder} from '@remotion/webcodecs';
28+
29+
const decoder = createVideoDecoder({
30+
track,
31+
onFrame: console.log,
32+
onError: console.error,
33+
});
34+
```
35+
36+
## Differences to `VideoDecoder`
37+
38+
- Two new methods are added: [`.waitForQueueToBeLessThan()`](#waitforqueuetobelessthanqueue-size-number) and [`.waitForFinish()`](#waitforfinish).
39+
- The [`dequeue`](https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder/dequeue_event) event is not supported as it is not reliable across browsers.
40+
- In addition to [`EncodedVideoChunk`](https://developer.mozilla.org/en-US/docs/Web/API/EncodedVideoChunk), [`EncodedVideoChunkInit`](https://www.w3.org/TR/webcodecs/#dictdef-encodedvideochunkinit) objects are also accepted for [`.decode()`](#decode).
41+
- A [`webcodecsController()`](/docs/webcodecs/webcodecs-controller) instance can be passed in to the function, allowing for decoding to be paused, resumed and aborted.
42+
- [`.decode()`](#decode) is async, and returns a promise, allowing for a halt if the decoder is paused.
43+
- A [`logLevel`](#loglevel) can be passed in to the function, allowing the queue to be debugged.
44+
- The [`onFrame`](#onframe) callback is being awaited. When rejected, the error lands in the [`onError`](#onerror) callback. When resolved, only then the queue size counter will be decreased.
45+
46+
## API
47+
48+
Takes an object with the following properties:
49+
50+
### `track`
51+
52+
An [`VideoDecoderConfig`](https://www.w3.org/TR/webcodecs/#dictdef-videodecoderconfig) object.
53+
You may pass a [`MediaParserVideoTrack`](/docs/media-parser/types#mediaparservideotrack) object from [`parseMedia()`](/docs/media-parser/parse-media), which also is an `VideoDecoderConfig` object.
54+
55+
### `onFrame`
56+
57+
A callback that is called when a frame is decoded.
58+
59+
Takes a single argument, which is a [`VideoFrame`](https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame) object.
60+
61+
Only once the callback resolves, the queue size counter will be decreased.
62+
63+
### `onError`
64+
65+
A callback that is called when an error occurs or the decode is aborted through the controller.
66+
67+
Takes a single argument, which is an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object.
68+
69+
### `controller?`
70+
71+
A [`webcodecsController()`](/docs/webcodecs/webcodecs-controller) instance.
72+
73+
If provided, you can call [`.pause()`](/docs/webcodecs/webcodecs-controller#pause), [`.resume()`](/docs/webcodecs/webcodecs-controller#resume) and [`.abort()`](/docs/webcodecs/webcodecs-controller#abort) on the controller to pause, resume and abort the decoding.
74+
75+
### `logLevel?`
76+
77+
_string_ <TsType type="LogLevel" source="@remotion/media-parser"/>
78+
79+
One of `"error"`, `"warn"`, `"info"`, `"debug"`, `"trace"`.
80+
Default value: `"info"`, which logs only important information.
81+
82+
## Return type
83+
84+
Returns an object with the following properties:
85+
86+
### `waitForQueueToBeLessThan(queueSize: number)`
87+
88+
A promise that resolves when the queue size is less than the given number.
89+
The queue is only decremented when the[ `onFrame`](#onframe) callback resolves.
90+
91+
### `waitForFinish()`
92+
93+
A promise that resolves when the decoder is finished.
94+
95+
### `flush()`
96+
97+
Flushes the decoder. Same as [`AudioDecoder.flush()`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder/flush).
98+
99+
### `close()`
100+
101+
Closes the decoder. Same as [`AudioDecoder.close()`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder/close).
102+
103+
## Example usage with `@remotion/media-parser`
104+
105+
```tsx twoslash title="Decode a video track"
106+
import {parseMedia} from '@remotion/media-parser';
107+
import {createVideoDecoder} from '@remotion/webcodecs';
108+
109+
await parseMedia({
110+
src: 'https://parser.media/video.mp4',
111+
onVideoTrack: ({track, container}) => {
112+
const decoder = createVideoDecoder({
113+
track,
114+
onFrame: console.log,
115+
onError: console.error,
116+
});
117+
118+
return async (sample) => {
119+
// Called on every sample
120+
await decoder.waitForQueueToBeLessThan(10);
121+
await decoder.decode(sample);
122+
123+
return async () => {
124+
// Called when the track is done
125+
await decoder.flush();
126+
await decoder.waitForFinish();
127+
decoder.close();
128+
};
129+
};
130+
},
131+
});
132+
```
133+
134+
## See also
135+
136+
- [Source code for this function](https://github.com/remotion-dev/remotion/blob/main/packages/webcodecs/src/create-video-decoder.ts)
137+
- [`@remotion/webcodecs`](/docs/webcodecs)

packages/docs/sidebars.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,8 @@ module.exports = {
683683
'webcodecs/get-available-audio-codecs',
684684
'webcodecs/get-available-video-codecs',
685685
'webcodecs/convert-audiodata',
686+
'webcodecs/create-audio-decoder',
687+
'webcodecs/create-video-decoder',
686688
],
687689
},
688690
{

packages/docs/src/data/articles.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2888,6 +2888,15 @@ export const articles = [
28882888
noAi: false,
28892889
slug: 'media-parser/runtime-support',
28902890
},
2891+
{
2892+
id: 'samples',
2893+
title: 'Extract samples',
2894+
relativePath: 'docs/media-parser/samples.mdx',
2895+
compId: 'articles-docs-media-parser-samples',
2896+
crumb: '@remotion/media-parser',
2897+
noAi: false,
2898+
slug: 'media-parser/samples',
2899+
},
28912900
{
28922901
id: 'seeking-hints',
28932902
title: 'Seeking Hints',
@@ -6000,6 +6009,24 @@ export const articles = [
60006009
noAi: false,
60016010
slug: 'webcodecs/convert-media',
60026011
},
6012+
{
6013+
id: 'webcodecs/create-audio-decoder',
6014+
title: 'createAudioDecoder()',
6015+
relativePath: 'docs/webcodecs/create-audio-decoder.mdx',
6016+
compId: 'articles-docs-webcodecs-create-audio-decoder',
6017+
crumb: '@remotion/webcodecs',
6018+
noAi: false,
6019+
slug: 'webcodecs/create-audio-decoder',
6020+
},
6021+
{
6022+
id: 'webcodecs/create-video-decoder',
6023+
title: 'createVideoDecoder()',
6024+
relativePath: 'docs/webcodecs/create-video-decoder.mdx',
6025+
compId: 'articles-docs-webcodecs-create-video-decoder',
6026+
crumb: '@remotion/webcodecs',
6027+
noAi: false,
6028+
slug: 'webcodecs/create-video-decoder',
6029+
},
60036030
{
60046031
id: 'default-on-audio-track-handler',
60056032
title: 'defaultOnAudioTrackHandler()',
Loading
Loading
Loading

packages/media-parser/src/webcodec-sample-types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import type {MediaParserContainer} from './options';
33

44
export type MediaParserOnAudioSample = (
55
sample: MediaParserAudioSample,
6-
) => void | Promise<void> | OnTrackDoneCallback;
6+
) => void | Promise<void> | OnTrackDoneCallback | Promise<OnTrackDoneCallback>;
77

88
export type MediaParserOnVideoSample = (
99
sample: MediaParserVideoSample,
10-
) => void | Promise<void> | OnTrackDoneCallback;
10+
) => void | Promise<void> | OnTrackDoneCallback | Promise<OnTrackDoneCallback>;
1111

1212
export type OnTrackDoneCallback = () => void | Promise<void>;
1313

0 commit comments

Comments
 (0)