Compare commits

...
4 Commits
7 changed files with 33 additions and 39 deletions
+1
View File
@@ -116,6 +116,7 @@ const sponsors = {
{ image: 'https://avatars.githubusercontent.com/u/2698271', name: 'Matthew Gardner', url: 'https://github.com/spheric' }, { image: 'https://avatars.githubusercontent.com/u/2698271', name: 'Matthew Gardner', url: 'https://github.com/spheric' },
{ image: 'https://avatars.githubusercontent.com/u/5475819', name: 'AJ Funk', url: 'https://github.com/AJFunk' }, { image: 'https://avatars.githubusercontent.com/u/5475819', name: 'AJ Funk', url: 'https://github.com/AJFunk' },
{ image: 'https://avatars.githubusercontent.com/u/30229596', name: 'Pablo Bonilla', url: 'https://github.com/devPablo' }, { image: 'https://avatars.githubusercontent.com/u/30229596', name: 'Pablo Bonilla', url: 'https://github.com/devPablo' },
{ image: 'https://avatars.githubusercontent.com/u/139718', name: 'Anton Kosiakin', url: 'https://github.com/deil' },
{ image: 'https://avatars.githubusercontent.com/u/56988069', name: 'SyhabouthAlex', url: 'https://github.com/SyhabouthAlex' }, { image: 'https://avatars.githubusercontent.com/u/56988069', name: 'SyhabouthAlex', url: 'https://github.com/SyhabouthAlex' },
{ image: 'https://avatars.githubusercontent.com/u/38181164', name: 'wcw', url: 'https://github.com/asd55667' }, { image: 'https://avatars.githubusercontent.com/u/38181164', name: 'wcw', url: 'https://github.com/asd55667' },
{ image: 'https://avatars.githubusercontent.com/u/1836701', name: 'Bean Deng', url: 'https://github.com/HADB' }, { image: 'https://avatars.githubusercontent.com/u/1836701', name: 'Bean Deng', url: 'https://github.com/HADB' },
+6 -6
View File
@@ -1,12 +1,12 @@
{ {
"name": "mediabunny", "name": "mediabunny",
"version": "1.27.3", "version": "1.27.4",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "mediabunny", "name": "mediabunny",
"version": "1.27.3", "version": "1.27.4",
"license": "MPL-2.0", "license": "MPL-2.0",
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
@@ -7739,9 +7739,9 @@
} }
}, },
"node_modules/mediabunny": { "node_modules/mediabunny": {
"version": "1.27.2", "version": "1.27.3",
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.27.2.tgz", "resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.27.3.tgz",
"integrity": "sha512-0g/vmb6X0xmnzqW0U44weF9CmzcUFFQRHrjzoVpSL2KXuhWIWcW3u9wIcohHiTY78jfr0SauYKLxjOQReaMxXQ==", "integrity": "sha512-hlzmgzMznp9DhA5fMJKS5yEAyfCUMxAc+DbSPxD4J1J2cYVl1L+pZLndkt5xLlD5aB5eHEnphHMW14ammMlUXg==",
"license": "MPL-2.0", "license": "MPL-2.0",
"peer": true, "peer": true,
"workspaces": [ "workspaces": [
@@ -12065,7 +12065,7 @@
}, },
"packages/mp3-encoder": { "packages/mp3-encoder": {
"name": "@mediabunny/mp3-encoder", "name": "@mediabunny/mp3-encoder",
"version": "1.27.3", "version": "1.27.4",
"license": "MPL-2.0", "license": "MPL-2.0",
"devDependencies": { "devDependencies": {
"@types/emscripten": "^1.40.1" "@types/emscripten": "^1.40.1"
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "mediabunny", "name": "mediabunny",
"author": "Vanilagy", "author": "Vanilagy",
"version": "1.27.3", "version": "1.27.4",
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.", "description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
"type": "module", "type": "module",
"workspaces": [ "workspaces": [
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "@mediabunny/mp3-encoder", "name": "@mediabunny/mp3-encoder",
"author": "Vanilagy", "author": "Vanilagy",
"version": "1.27.3", "version": "1.27.4",
"description": "MP3 encoder extension for Mediabunny, based on LAME.", "description": "MP3 encoder extension for Mediabunny, based on LAME.",
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs", "main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs", "module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
+7 -17
View File
@@ -480,23 +480,13 @@ export abstract class BaseMediaSampleSink<
let currentPacket: EncodedPacket | null = keyPacket; let currentPacket: EncodedPacket | null = keyPacket;
let endPacket: EncodedPacket | undefined = undefined; // B-frames make it exceedingly difficult to properly define an upper bound for packet iteration if an end
if (endTimestamp < Infinity) { // timestamp is set, so we just don't do it. The case that makes it especially tricky is when the frames
// When an end timestamp is set, we cannot simply use that for the packet iterator due to out-of-order // following a key frame have a lower timestamp than the keyframe; something that quite frequently happens
// frames (B-frames). Instead, we'll need to keep decoding packets until we get a frame that exceeds // in HEVC streams. The price to pay for not upper-bounding the packet iterator is a slight increase in
// this end time. However, we can still put a bound on it: Since key frames are by definition never // decoder work at the end of the range, but the added correctness and reliability makes this tradeoff worth
// out of order, we can stop at the first key frame after the end timestamp. // it.
const packet = await packetSink.getPacket(endTimestamp); const endPacket = undefined;
const keyPacket = !packet
? null
: packet.type === 'key' && packet.timestamp === endTimestamp
? packet
: await packetSink.getNextKeyPacket(packet, { verifyKeyPackets: true });
if (keyPacket) {
endPacket = keyPacket;
}
}
const packets = packetSink.packets(keyPacket ?? undefined, endPacket); const packets = packetSink.packets(keyPacket ?? undefined, endPacket);
await packets.next(); // Skip the start packet as we already have it await packets.next(); // Skip the start packet as we already have it
+10 -14
View File
@@ -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`; * 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.
*/ */
allocationSize(options: VideoFrameCopyToOptions = {}): number { allocationSize(options: VideoFrameCopyToOptions = {}): number {
validateVideoFrameCopyToOptions(options); validateVideoFrameCopyToOptions(options);
@@ -455,11 +454,10 @@ export class VideoSample implements Disposable {
if (this._closed) { if (this._closed) {
throw new Error('VideoSample is closed.'); throw new Error('VideoSample is closed.');
} }
if ((options.format ?? this.format) === null) { if (this.format === null) {
throw new Error( // https://github.com/Vanilagy/mediabunny/issues/267
'Cannot get allocation size when format is null. Please manually provide an RGB pixel format in the' // https://github.com/w3c/webcodecs/issues/920
+ ' options instead.', throw new Error('Cannot get allocation size when format is null. Sorry!');
);
} }
assert(this._data !== null); assert(this._data !== null);
@@ -472,6 +470,7 @@ export class VideoSample implements Disposable {
|| options.rect || options.rect
) { ) {
// Temporarily convert to VideoFrame to get it done // Temporarily convert to VideoFrame to get it done
// TODO: Compute this directly without needing to go through VideoFrame
const videoFrame = this.toVideoFrame(); const videoFrame = this.toVideoFrame();
const size = videoFrame.allocationSize(options); const size = videoFrame.allocationSize(options);
videoFrame.close(); 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`; * 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.
* @returns The byte layout of the planes of the copied data. * @returns The byte layout of the planes of the copied data.
*/ */
async copyTo(destination: AllowSharedBufferSource, options: VideoFrameCopyToOptions = {}): Promise<PlaneLayout[]> { async copyTo(destination: AllowSharedBufferSource, options: VideoFrameCopyToOptions = {}): Promise<PlaneLayout[]> {
@@ -503,11 +501,8 @@ export class VideoSample implements Disposable {
if (this._closed) { if (this._closed) {
throw new Error('VideoSample is closed.'); throw new Error('VideoSample is closed.');
} }
if ((options.format ?? this.format) === null) { if (this.format === null) {
throw new Error( throw new Error('Cannot copy video sample data when format is null. Sorry!');
'Cannot copy video sample data when format is null. Please manually provide an RGB pixel format in the'
+ ' options instead.',
);
} }
assert(this._data !== null); assert(this._data !== null);
@@ -520,6 +515,7 @@ export class VideoSample implements Disposable {
|| options.rect || options.rect
) { ) {
// Temporarily convert to VideoFrame to get it done // Temporarily convert to VideoFrame to get it done
// TODO: Do this directly without needing to go through VideoFrame
const videoFrame = this.toVideoFrame(); const videoFrame = this.toVideoFrame();
const layout = await videoFrame.copyTo(destination, options); const layout = await videoFrame.copyTo(destination, options);
videoFrame.close(); videoFrame.close();
+7
View File
@@ -201,6 +201,12 @@ test('null format', async () => {
expect(() => sample.allocationSize()).toThrow('when format is null'); expect(() => sample.allocationSize()).toThrow('when format is null');
await expect(async () => sample.copyTo(new ArrayBuffer())).rejects.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' }); const size = sample.allocationSize({ format: 'RGBA' });
expect(size).toBe(1280 * 720 * 4); expect(size).toBe(1280 * 720 * 4);
const buffer = new ArrayBuffer(size); const buffer = new ArrayBuffer(size);
@@ -217,4 +223,5 @@ test('null format', async () => {
await sample.copyTo(buffer, { format: 'RGBX' }); await sample.copyTo(buffer, { format: 'RGBX' });
await sample.copyTo(buffer, { format: 'BGRA' }); await sample.copyTo(buffer, { format: 'BGRA' });
await sample.copyTo(buffer, { format: 'BGRX' }); await sample.copyTo(buffer, { format: 'BGRX' });
*/
}); });