fix(streaming): fix nvidia hwdownload compat with ffmpeg 7.2

Closes #1252
This commit is contained in:
Christian Benincasa
2025-07-03 11:45:34 -04:00
parent d31919c1b0
commit 6ae437f909
3 changed files with 48 additions and 2 deletions

View File

@@ -51,4 +51,26 @@ describe('ScaleCudaFilter', () => {
new PixelFormatP010(),
);
});
test('format only, 10-bit, passthrough', () => {
const currentState = new FrameState({
isAnamorphic: false,
paddedSize: FrameSize.withDimensions(1920, 1080),
scaledSize: FrameSize.withDimensions(1920, 1080),
frameDataLocation: FrameDataLocation.Hardware,
pixelFormat: new PixelFormatYuv420P10Le(),
});
// sizes are equal
const filter = ScaleCudaFilter.formatOnly(
currentState,
new PixelFormatP010(),
true,
);
expect(filter.filter).to.eq('scale_cuda=format=p010:passthrough=1');
expect(filter.nextState(currentState).pixelFormat).toMatchPixelFormat(
new PixelFormatP010(),
);
});
});

View File

@@ -25,16 +25,22 @@ export class ScaleCudaFilter extends FilterOption {
private currentState: FrameState,
private scaledSize: FrameSize,
private paddedSize: FrameSize,
private passthrough: boolean = false,
) {
super();
this.filter = this.generateFilter();
}
static formatOnly(currentState: FrameState, targetPixelFormat: PixelFormat) {
static formatOnly(
currentState: FrameState,
targetPixelFormat: PixelFormat,
passthrough: boolean = false,
) {
return new ScaleCudaFilter(
currentState.update({ pixelFormat: targetPixelFormat }),
currentState.scaledSize,
currentState.paddedSize,
passthrough,
);
}
@@ -63,7 +69,8 @@ export class ScaleCudaFilter extends FilterOption {
if (this.currentState.scaledSize.equals(this.scaledSize)) {
const targetPixelFormat = this.supportedPixelFormat;
if (targetPixelFormat) {
scale = `${this.filterName}=format=${targetPixelFormat.name}`;
const passthrough = this.passthrough ? ':passthrough=1' : '';
scale = `${this.filterName}=format=${targetPixelFormat.name}${passthrough}`;
}
} else {
let aspectRatio = '';

View File

@@ -49,6 +49,7 @@ import { WatermarkOpacityFilter } from '../../filter/watermark/WatermarkOpacityF
import { WatermarkScaleFilter } from '../../filter/watermark/WatermarkScaleFilter.ts';
import {
PixelFormatNv12,
PixelFormatP010,
PixelFormatYuv420P,
PixelFormatYuv420P10Le,
PixelFormatYuva420P,
@@ -155,6 +156,22 @@ export class NvidiaPipelineBuilder extends SoftwarePipelineBuilder {
currentState = this.decoder?.nextState(currentState) ?? currentState;
this.videoInputSource.frameDataLocation = currentState.frameDataLocation;
// Workaround change to required pixel format from https://github.com/FFmpeg/FFmpeg/commit/30e6effff94c6f4310aa2db571917bb2952f4d9e
// Specifically, CUDA pixel formats use 16-bit (p016) internally starting on 7.2 it seems. Preemptively convert
// to p010 here to avoid potential hwdownload issues later in pipeline.
if (
this.decoder instanceof ImplicitNvidiaDecoder &&
videoStream.bitDepth() === 10
) {
const filter = ScaleCudaFilter.formatOnly(
currentState,
new PixelFormatP010(),
true,
);
currentState = filter.nextState(currentState);
this.videoInputSource.addFilter(filter);
}
currentState = this.setDeinterlace(currentState);
currentState = this.setScale(currentState);
currentState = this.setPad(currentState);