From 8f43086e3de07863a3b96f81f3814b64fcf7c511 Mon Sep 17 00:00:00 2001 From: Vanilagy <1696106+Vanilagy@users.noreply.github.com> Date: Mon, 5 Jan 2026 11:07:32 +0100 Subject: [PATCH] Make allocationSize and copyTo always throw if internal format is null (closes #267) --- src/sample.ts | 24 ++++++++++-------------- test/browser/video-samples.test.ts | 7 +++++++ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/sample.ts b/src/sample.ts index 84c1bca..0caf6c5 100644 --- a/src/sample.ts +++ b/src/sample.ts @@ -446,8 +446,7 @@ export class VideoSample implements Disposable { } /** - * Returns the number of bytes required to hold this video sample's pixel data. Throws if `format` is `null`; - * specify an explicit RGB format in the options in this case. + * Returns the number of bytes required to hold this video sample's pixel data. Throws if `format` is `null`. */ allocationSize(options: VideoFrameCopyToOptions = {}): number { validateVideoFrameCopyToOptions(options); @@ -455,11 +454,10 @@ export class VideoSample implements Disposable { if (this._closed) { throw new Error('VideoSample is closed.'); } - if ((options.format ?? this.format) === null) { - throw new Error( - 'Cannot get allocation size when format is null. Please manually provide an RGB pixel format in the' - + ' options instead.', - ); + if (this.format === null) { + // https://github.com/Vanilagy/mediabunny/issues/267 + // https://github.com/w3c/webcodecs/issues/920 + throw new Error('Cannot get allocation size when format is null. Sorry!'); } assert(this._data !== null); @@ -472,6 +470,7 @@ export class VideoSample implements Disposable { || options.rect ) { // Temporarily convert to VideoFrame to get it done + // TODO: Compute this directly without needing to go through VideoFrame const videoFrame = this.toVideoFrame(); const size = videoFrame.allocationSize(options); videoFrame.close(); @@ -490,8 +489,7 @@ export class VideoSample implements Disposable { } /** - * Copies this video sample's pixel data to an ArrayBuffer or ArrayBufferView. Throws if `format` is `null`; - * specify an explicit RGB format in the options in this case. + * Copies this video sample's pixel data to an ArrayBuffer or ArrayBufferView. Throws if `format` is `null`. * @returns The byte layout of the planes of the copied data. */ async copyTo(destination: AllowSharedBufferSource, options: VideoFrameCopyToOptions = {}): Promise { @@ -503,11 +501,8 @@ export class VideoSample implements Disposable { if (this._closed) { throw new Error('VideoSample is closed.'); } - if ((options.format ?? this.format) === null) { - throw new Error( - 'Cannot copy video sample data when format is null. Please manually provide an RGB pixel format in the' - + ' options instead.', - ); + if (this.format === null) { + throw new Error('Cannot copy video sample data when format is null. Sorry!'); } assert(this._data !== null); @@ -520,6 +515,7 @@ export class VideoSample implements Disposable { || options.rect ) { // Temporarily convert to VideoFrame to get it done + // TODO: Do this directly without needing to go through VideoFrame const videoFrame = this.toVideoFrame(); const layout = await videoFrame.copyTo(destination, options); videoFrame.close(); diff --git a/test/browser/video-samples.test.ts b/test/browser/video-samples.test.ts index b0c12e6..8f080dc 100644 --- a/test/browser/video-samples.test.ts +++ b/test/browser/video-samples.test.ts @@ -201,6 +201,12 @@ test('null format', async () => { expect(() => sample.allocationSize()).toThrow('when format is null'); await expect(async () => sample.copyTo(new ArrayBuffer())).rejects.toThrow('when format is null'); + // Even this throws :( + // See https://github.com/Vanilagy/mediabunny/issues/267 + expect(() => sample.allocationSize({ format: 'RGBA' })).toThrow('when format is null'); + + // Uncomment this if the RGBA conversion works again: + /* const size = sample.allocationSize({ format: 'RGBA' }); expect(size).toBe(1280 * 720 * 4); const buffer = new ArrayBuffer(size); @@ -217,4 +223,5 @@ test('null format', async () => { await sample.copyTo(buffer, { format: 'RGBX' }); await sample.copyTo(buffer, { format: 'BGRA' }); await sample.copyTo(buffer, { format: 'BGRX' }); + */ });