mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 10:53:50 +02:00
Implement @mediabunny/prores extension, add onError callbacks to custom coders, fix visibleRect bug in VideoSample
This commit is contained in:
+55
-22
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import { registerProresDecoder } from '@mediabunny/prores';
|
||||
import { Input } from '../../src/input.js';
|
||||
import { BufferSource, UrlSource } from '../../src/source.js';
|
||||
import { ALL_FORMATS } from '../../src/input-format.js';
|
||||
@@ -7,28 +8,29 @@ import { MkvOutputFormat, MovOutputFormat } from '../../src/output-format.js';
|
||||
import { BufferTarget } from '../../src/target.js';
|
||||
import { Conversion } from '../../src/conversion.js';
|
||||
import { VideoSampleSink } from '../../src/media-sink.js';
|
||||
import { CustomVideoDecoder, registerDecoder } from '../../src/custom-coder.js';
|
||||
import { ProResDecoder } from '../../packages/prores-decoder/src/index.js';
|
||||
import { assert } from '../../src/misc.js';
|
||||
|
||||
const SAMPLE_URL = 'https://pub-1ee78aacb848486482b20a72b55b3121.r2.dev/turbores-sample.mov';
|
||||
|
||||
test.concurrent('ProRes MOV file reading', async () => {
|
||||
using input = new Input({
|
||||
source: new UrlSource('https://pub-cf9fcfcb5c0a44e9b1bb5ff890e041ae.r2.dev/IMG_0158-prores-log.MOV'),
|
||||
source: new UrlSource(SAMPLE_URL),
|
||||
formats: ALL_FORMATS,
|
||||
});
|
||||
|
||||
const videoTrack = (await input.getPrimaryVideoTrack())!;
|
||||
expect(videoTrack.codec).toBe('prores');
|
||||
expect(videoTrack.codedWidth).toBe(1920);
|
||||
expect(videoTrack.codedHeight).toBe(1080);
|
||||
expect(await videoTrack.getCodec()).toBe('prores');
|
||||
expect(await videoTrack.getCodedWidth()).toBe(1920);
|
||||
expect(await videoTrack.getCodedHeight()).toBe(1080);
|
||||
|
||||
const decoderConfig = (await videoTrack.getDecoderConfig())!;
|
||||
expect(decoderConfig.codec).toBe('apch');
|
||||
expect(decoderConfig.description).toBeUndefined();
|
||||
});
|
||||
|
||||
test.concurrent('ProRes transmuxing into MOV', { timeout: 60_000 }, async () => {
|
||||
test.concurrent('ProRes transmuxing into MOV', { timeout: 10_000 }, async () => {
|
||||
using input = new Input({
|
||||
source: new UrlSource('https://pub-cf9fcfcb5c0a44e9b1bb5ff890e041ae.r2.dev/IMG_0158-prores-log.MOV'),
|
||||
source: new UrlSource(SAMPLE_URL),
|
||||
formats: ALL_FORMATS,
|
||||
});
|
||||
|
||||
@@ -55,7 +57,7 @@ test.concurrent('ProRes transmuxing into MOV', { timeout: 60_000 }, async () =>
|
||||
});
|
||||
|
||||
const videoTrack = (await newInput.getPrimaryVideoTrack())!;
|
||||
expect(videoTrack.codec).toBe('prores');
|
||||
expect(await videoTrack.getCodec()).toBe('prores');
|
||||
expect((await videoTrack.computePacketStats()).packetCount).toBe(15);
|
||||
|
||||
const decoderConfig = (await videoTrack.getDecoderConfig())!;
|
||||
@@ -63,9 +65,9 @@ test.concurrent('ProRes transmuxing into MOV', { timeout: 60_000 }, async () =>
|
||||
expect(decoderConfig.description).toBeUndefined();
|
||||
});
|
||||
|
||||
test.concurrent('ProRes transmuxing into MKV', { timeout: 60_000 }, async () => {
|
||||
test.concurrent('ProRes transmuxing into MKV', { timeout: 10_000 }, async () => {
|
||||
using input = new Input({
|
||||
source: new UrlSource('https://pub-cf9fcfcb5c0a44e9b1bb5ff890e041ae.r2.dev/IMG_0158-prores-log.MOV'),
|
||||
source: new UrlSource(SAMPLE_URL),
|
||||
formats: ALL_FORMATS,
|
||||
});
|
||||
|
||||
@@ -77,9 +79,6 @@ test.concurrent('ProRes transmuxing into MKV', { timeout: 60_000 }, async () =>
|
||||
const conversion = await Conversion.init({
|
||||
input,
|
||||
output,
|
||||
video: {
|
||||
rotate: 270, // To undo the source rotation metadata so the copy path is taken
|
||||
},
|
||||
audio: {
|
||||
discard: true,
|
||||
},
|
||||
@@ -95,7 +94,7 @@ test.concurrent('ProRes transmuxing into MKV', { timeout: 60_000 }, async () =>
|
||||
});
|
||||
|
||||
const videoTrack = (await newInput.getPrimaryVideoTrack())!;
|
||||
expect(videoTrack.codec).toBe('prores');
|
||||
expect(await videoTrack.getCodec()).toBe('prores');
|
||||
expect((await videoTrack.computePacketStats()).packetCount).toBe(15);
|
||||
|
||||
const decoderConfig = (await videoTrack.getDecoderConfig())!;
|
||||
@@ -103,17 +102,51 @@ test.concurrent('ProRes transmuxing into MKV', { timeout: 60_000 }, async () =>
|
||||
expect(decoderConfig.description).toBeUndefined();
|
||||
});
|
||||
|
||||
test.concurrent.only('ProRes sample ahh', async () => {
|
||||
registerDecoder(ProResDecoder);
|
||||
|
||||
test('Custom coder registration', { timeout: 10_000 }, async () => {
|
||||
using input = new Input({
|
||||
source: new UrlSource('https://pub-cf9fcfcb5c0a44e9b1bb5ff890e041ae.r2.dev/IMG_0158-prores-log.MOV'),
|
||||
source: new UrlSource(SAMPLE_URL),
|
||||
formats: ALL_FORMATS,
|
||||
});
|
||||
|
||||
const videoTrack = (await input.getPrimaryVideoTrack())!;
|
||||
const sink = new VideoSampleSink(videoTrack);
|
||||
const sample = await sink.getSample(0);
|
||||
expect(await videoTrack.getCodec()).toBe('prores');
|
||||
|
||||
console.log(sample);
|
||||
// Without a registered decoder, there's no way to decode ProRes in this environment
|
||||
expect(await videoTrack.canDecode()).toBe(false);
|
||||
|
||||
registerProresDecoder();
|
||||
|
||||
expect(await videoTrack.canDecode()).toBe(true);
|
||||
});
|
||||
|
||||
test('ProRes decoding', { timeout: 10_000 }, async () => {
|
||||
registerProresDecoder();
|
||||
|
||||
using input = new Input({
|
||||
source: new UrlSource(SAMPLE_URL),
|
||||
formats: ALL_FORMATS,
|
||||
});
|
||||
|
||||
const videoTrack = (await input.getPrimaryVideoTrack())!;
|
||||
const firstTimestamp = await videoTrack.getFirstTimestamp();
|
||||
|
||||
const sink = new VideoSampleSink(videoTrack);
|
||||
using sample = await sink.getSample(firstTimestamp);
|
||||
assert(sample);
|
||||
|
||||
expect(sample.timestamp).toBe(firstTimestamp);
|
||||
expect(sample.duration).toBeGreaterThan(0);
|
||||
|
||||
expect(sample.displayWidth).toBe(await videoTrack.getDisplayWidth());
|
||||
expect(sample.displayHeight).toBe(await videoTrack.getDisplayHeight());
|
||||
expect(sample.codedWidth).toBe(1920);
|
||||
expect(sample.codedHeight).toBe(1080); // Technically a lie but the field is ill-defined
|
||||
expect(sample.format).toBe('I422P10');
|
||||
|
||||
const allocationSize = sample.allocationSize();
|
||||
expect(allocationSize).toBeGreaterThan(0);
|
||||
|
||||
const pixels = new Uint8Array(allocationSize);
|
||||
await sample.copyTo(pixels);
|
||||
expect(pixels.some(byte => byte !== 0)).toBe(true);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user