( bytes: Uint8Array, releaseCallback?: () => void, )
| 480 | } |
| 481 | |
| 482 | function queueFrameFromBytes( |
| 483 | bytes: Uint8Array, |
| 484 | releaseCallback?: () => void, |
| 485 | ): void { |
| 486 | const meta = parseFrameMetadata(bytes); |
| 487 | if (!meta) { |
| 488 | releaseCallback?.(); |
| 489 | return; |
| 490 | } |
| 491 | |
| 492 | const { width, height, frameNumber, targetTimeNs } = meta; |
| 493 | const timing: FrameTiming = { frameNumber, targetTimeNs }; |
| 494 | |
| 495 | if (renderMode === "webgpu" || renderMode === "pending") { |
| 496 | for (const queued of frameQueue) { |
| 497 | if (queued.mode === "webgpu" && queued.releaseCallback) { |
| 498 | queued.releaseCallback(); |
| 499 | } |
| 500 | } |
| 501 | frameQueue = frameQueue.filter((f) => f.mode !== "webgpu"); |
| 502 | |
| 503 | if (meta.format === "nv12") { |
| 504 | const frameData = new Uint8ClampedArray( |
| 505 | bytes.buffer, |
| 506 | bytes.byteOffset, |
| 507 | meta.totalSize, |
| 508 | ); |
| 509 | frameQueue.push({ |
| 510 | mode: "webgpu", |
| 511 | pixelFormat: "nv12", |
| 512 | data: frameData, |
| 513 | width, |
| 514 | height, |
| 515 | yStride: meta.yStride, |
| 516 | fullRange: meta.fullRange, |
| 517 | timing, |
| 518 | releaseCallback, |
| 519 | }); |
| 520 | } else { |
| 521 | const metadataSize = 24; |
| 522 | const frameData = new Uint8ClampedArray( |
| 523 | bytes.buffer, |
| 524 | bytes.byteOffset, |
| 525 | bytes.byteLength - metadataSize, |
| 526 | ); |
| 527 | frameQueue.push({ |
| 528 | mode: "webgpu", |
| 529 | pixelFormat: "rgba", |
| 530 | data: frameData.subarray(0, meta.availableLength), |
| 531 | width, |
| 532 | height, |
| 533 | strideBytes: meta.strideBytes, |
| 534 | timing, |
| 535 | releaseCallback, |
| 536 | }); |
| 537 | } |
| 538 | } else if (meta.format === "rgba") { |
| 539 | const expectedRowBytes = width * 4; |
no test coverage detected