diff --git a/packages/prores/src/index.ts b/packages/prores/src/index.ts index 381ec9d..40cce24 100644 --- a/packages/prores/src/index.ts +++ b/packages/prores/src/index.ts @@ -118,25 +118,52 @@ class ProresDecoder extends CustomVideoDecoder { this.trimCodedHeightToVisibleHeight(result); } - const sample = new VideoSample(result.frameData, { - format: result.pixelFormat, - codedWidth: result.codedWidth, - codedHeight: result.codedHeight, - visibleRect: { - left: 0, - top: 0, - width: result.visibleWidth, - height: result.visibleHeight, - }, - timestamp: packet.timestamp, - duration: packet.duration, - colorSpace: { - primaries: result.colorPrimariesString as VideoColorPrimaries | undefined, - matrix: result.colorMatrixString as VideoMatrixCoefficients | undefined, - transfer: result.colorTransferString as VideoTransferCharacteristics | undefined, - fullRange: result.colorRangeFull, - }, - }); + const colorSpaceInit = { + primaries: result.colorPrimariesString as VideoColorPrimaries | undefined, + matrix: result.colorMatrixString as VideoMatrixCoefficients | undefined, + transfer: result.colorTransferString as VideoTransferCharacteristics | undefined, + fullRange: result.colorRangeFull, + }; + + let sample: VideoSample; + if (typeof VideoFrame !== 'undefined') { + // Create a VideoFrame directly; this avoids the frame data being copied twice + const frame = new VideoFrame(result.frameData, { + format: result.pixelFormat as VideoPixelFormat, + codedWidth: result.codedWidth, + codedHeight: result.codedHeight, + visibleRect: { + x: 0, + y: 0, + width: result.visibleWidth, + height: result.visibleHeight, + }, + timestamp: packet.microsecondTimestamp, + duration: packet.microsecondDuration, + colorSpace: colorSpaceInit, + }); + + sample = new VideoSample(frame, { + timestamp: packet.timestamp, + duration: packet.duration, + }); + } else { + sample = new VideoSample(result.frameData, { + format: result.pixelFormat, + codedWidth: result.codedWidth, + codedHeight: result.codedHeight, + visibleRect: { + left: 0, + top: 0, + width: result.visibleWidth, + height: result.visibleHeight, + }, + timestamp: packet.timestamp, + duration: packet.duration, + colorSpace: colorSpaceInit, + }); + } + this.onSample(sample); } diff --git a/src/matroska/matroska-muxer.ts b/src/matroska/matroska-muxer.ts index ddfbc43..1ea6bae 100644 --- a/src/matroska/matroska-muxer.ts +++ b/src/matroska/matroska-muxer.ts @@ -844,7 +844,7 @@ export class MatroskaMuxer extends Muxer { }, chunkQueue: [], lastWrittenMsTimestamp: null, - codecPrivate: meta.decoderConfig.description ?? null, + codecPrivate: decoderConfig.description ?? null, closed: false, }; diff --git a/src/sample.ts b/src/sample.ts index 8c0cdb1..0c4a633 100644 --- a/src/sample.ts +++ b/src/sample.ts @@ -469,41 +469,10 @@ export class VideoSample implements Disposable { this.squarePixelHeight = this.visibleRect.height; } - // If VideoFrame is available, route through it directly instead of holding onto the buffer. Going - // buffer -> VideoSample -> VideoFrame would copy the data twice (once here, once in toVideoFrame); - // building the VideoFrame now means it's only ever copied once. - if (typeof VideoFrame !== 'undefined' && !init._doNotCopy) { - let videoFrame: VideoFrame | null = null; - - try { - videoFrame = new VideoFrame(toUint8Array(data), { - format: init.format as VideoPixelFormat, - codedWidth: init.codedWidth!, - codedHeight: init.codedHeight!, - layout, - colorSpace: colorSpaceInit, - visibleRect: { - x: this.visibleRect.left, - y: this.visibleRect.top, - width: this.visibleRect.width, - height: this.visibleRect.height, - }, - displayWidth: this.squarePixelWidth, - displayHeight: this.squarePixelHeight, - timestamp: Math.trunc(init.timestamp! * SECOND_TO_MICROSECOND_FACTOR), - // Drag 0 to undefined - duration: Math.trunc((init.duration ?? 0) * SECOND_TO_MICROSECOND_FACTOR) || undefined, - }); - } catch { - // Ignore the error and move on like it didn't happen. We don't want errors caused by the local - // VideoFrame implementation to prevent us from creating the VideoSample. Errors, for example, could - // be caused by an unsupported pixel format. - } - - if (videoFrame) { - return new VideoSample(videoFrame, init); - } - } + // As an optimization, one could check if VideoFrame is defined and if it is, create a VideoFrame here from + // the data. Since VideoFrames are typically needed anyway, doing it this way would avoid an additional + // copy of the frame data. But due to https://issues.chromium.org/issues/529413114, this is currently + // not done. this._data = init._doNotCopy ? toUint8Array(data)