( frame: VideoFramePolyfill, format: VideoPixelFormat, colorSpace?: PredefinedColorSpace, )
| 539 | }; |
| 540 | |
| 541 | const ConvertToRGBFrame = async ( |
| 542 | frame: VideoFramePolyfill, |
| 543 | format: VideoPixelFormat, |
| 544 | colorSpace?: PredefinedColorSpace, |
| 545 | ): Promise<VideoFramePolyfill> => { |
| 546 | // 1. Let convertedFrame be a new VideoFrame... |
| 547 | // (We construct it at the end, but we prepare the resource here) |
| 548 | |
| 549 | const width = frame.visibleRect!.width; |
| 550 | const height = frame.visibleRect!.height; |
| 551 | |
| 552 | const scaler = new SoftwareScaleContext(); |
| 553 | const srcFmt = fromPixelFormat(frame.format!); |
| 554 | const dstFmt = fromPixelFormat(format); |
| 555 | |
| 556 | // Configure scaling: Source -> Destination (Visible Size) |
| 557 | scaler.getContext( |
| 558 | width, height, srcFmt, |
| 559 | width, height, dstFmt, |
| 560 | SWS_BILINEAR, |
| 561 | ); |
| 562 | |
| 563 | // Allocate destination frame |
| 564 | const dstFrame = new Frame(); |
| 565 | dstFrame.width = width; |
| 566 | dstFrame.height = height; |
| 567 | dstFrame.format = dstFmt; |
| 568 | dstFrame.alloc(); |
| 569 | dstFrame.allocBuffer(); |
| 570 | |
| 571 | // Apply destination color space settings to dstFrame |
| 572 | // If colorSpace is not provided, srgb is used |
| 573 | const targetColorSpace = colorSpace || 'srgb'; |
| 574 | if (targetColorSpace === 'srgb') { |
| 575 | dstFrame.colorPrimaries = AVCOL_PRI_BT709; |
| 576 | dstFrame.colorTrc = AVCOL_TRC_IEC61966_2_1; |
| 577 | dstFrame.colorSpace = AVCOL_SPC_RGB; |
| 578 | dstFrame.colorRange = AVCOL_RANGE_JPEG; |
| 579 | } else if (targetColorSpace === 'display-p3') { |
| 580 | dstFrame.colorPrimaries = AVCOL_PRI_SMPTE432; |
| 581 | dstFrame.colorTrc = AVCOL_TRC_IEC61966_2_1; |
| 582 | dstFrame.colorSpace = AVCOL_SPC_RGB; |
| 583 | dstFrame.colorRange = AVCOL_RANGE_JPEG; |
| 584 | } |
| 585 | |
| 586 | let srcFrame: Frame; |
| 587 | let tempSrcFrame: Frame | null = null; |
| 588 | |
| 589 | // Determine if we need a temp frame due to flat buffer source or cropping |
| 590 | const isFlatBuffer = !(frame.data instanceof Frame); |
| 591 | const isCropped = frame.visibleRect!.x !== 0 || frame.visibleRect!.y !== 0 |
| 592 | || frame.visibleRect!.width !== frame.codedWidth || frame.visibleRect!.height !== frame.codedHeight; |
| 593 | |
| 594 | if (isFlatBuffer || isCropped) { |
| 595 | // Allocate temp frame for the visible region |
| 596 | tempSrcFrame = new Frame(); |
| 597 | tempSrcFrame.width = width; |
| 598 | tempSrcFrame.height = height; |
no test coverage detected