ffmpeg stream test util

This commit is contained in:
Christian Benincasa
2025-06-06 15:43:07 -04:00
parent 2d052f751e
commit b8c8d28105
4 changed files with 105 additions and 32 deletions

View File

@@ -1,4 +1,8 @@
import { FileStreamSource } from '../../../../stream/types.ts';
import {
FfmpegStateVersion702,
h2641080pVideoStream,
} from '../../../../testing/ffmpegTestUtil.ts';
import { FfmpegCapabilities } from '../../capabilities/FfmpegCapabilities.ts';
import { NvidiaHardwareCapabilities } from '../../capabilities/NvidiaHardwareCapabilities.ts';
import { PixelFormatYuv420P } from '../../format/PixelFormat.ts';
@@ -11,6 +15,7 @@ import {
SubtitleMethods,
VideoStream,
} from '../../MediaStream.ts';
import { KnownFfmpegFilters } from '../../options/KnownFfmpegOptions.ts';
import { FfmpegState } from '../../state/FfmpegState.ts';
import { FrameState } from '../../state/FrameState.ts';
import { FrameSize } from '../../types.ts';
@@ -103,14 +108,7 @@ describe('NvidiaPipelineBuilder', () => {
const video = VideoInputSource.withStream(
videoSource,
VideoStream.create({
codec: 'h264',
displayAspectRatio: '16:9',
frameSize: FrameSize.FHD,
index: 0,
pixelFormat: new PixelFormatYuv420P(),
sampleAspectRatio: null,
}),
h2641080pVideoStream(),
);
const watermark = new WatermarkInputSource(
@@ -144,19 +142,8 @@ describe('NvidiaPipelineBuilder', () => {
),
);
const state = FfmpegState.create({
version: {
versionString: 'n7.0.2-15-g0458a86656-20240904',
majorVersion: 7,
minorVersion: 0,
patchVersion: 2,
isUnknown: false,
},
// start: +dayjs.duration(0),
});
const out = builder.build(
state,
FfmpegStateVersion702(),
new FrameState({
isAnamorphic: false,
scaledSize: video.streams[0].squarePixelFrameSize(FrameSize.FHD),
@@ -168,4 +155,64 @@ describe('NvidiaPipelineBuilder', () => {
console.log(out.getCommandArgs().join(' '));
});
test('updates pixel format when overlaying subtitles after a scale', () => {
const capabilities = new NvidiaHardwareCapabilities('RTX 2080 Ti', 75);
const binaryCapabilities = new FfmpegCapabilities(
new Set(),
new Map(),
new Set([KnownFfmpegFilters.ScaleNpp]),
);
const videoSource = new FileStreamSource('/path/to/video.mkv');
const video = VideoInputSource.withStream(
videoSource,
h2641080pVideoStream(),
);
const watermark = new WatermarkInputSource(
new FileStreamSource('/path/to/watermark.jpg'),
StillImageStream.create({
frameSize: FrameSize.withDimensions(800, 600),
index: 0,
}),
{
duration: 5,
enabled: true,
horizontalMargin: 5,
opacity: 100,
position: 'bottom-right',
verticalMargin: 5,
width: 10,
},
);
const builder = new NvidiaPipelineBuilder(
capabilities,
binaryCapabilities,
video,
null,
null,
null,
new SubtitlesInputSource(
videoSource,
[new EmbeddedSubtitleStream('pgs', 5, SubtitleMethods.Burn)],
SubtitleMethods.Burn,
),
);
const out = builder.build(
FfmpegStateVersion702(),
new FrameState({
isAnamorphic: false,
scaledSize: video.streams[0].squarePixelFrameSize(FrameSize.FourK),
paddedSize: FrameSize.FourK,
pixelFormat: new PixelFormatYuv420P(),
deinterlace: false,
}),
);
console.log(out.getCommandArgs().join(' '));
});
});

View File

@@ -179,7 +179,7 @@ export class NvidiaPipelineBuilder extends SoftwarePipelineBuilder {
!isNil(currentState.pixelFormat) &&
!desiredPixelFormat.equals(currentState.pixelFormat)
) {
this.logger.trace('adding pixel filter format for watermark!!!');
this.logger.trace('adding pixel filter format for overlay!!!');
if (currentState.frameDataLocation === FrameDataLocation.Software) {
const pixelFormatFilter = new PixelFormatFilter(desiredPixelFormat);
currentState = pixelFormatFilter.nextState(currentState);

View File

@@ -1,11 +0,0 @@
import type { PixelFormat } from '@/ffmpeg/builder/format/PixelFormat.js';
import 'vitest';
interface CustomMatchers<R = unknown> {
toMatchPixelFormat: (expected: PixelFormat) => R;
}
declare module 'bun:test' {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface Matchers<R = unknown> extends CustomMatchers<R> {}
}

View File

@@ -0,0 +1,37 @@
import { PixelFormatYuv420P } from '../ffmpeg/builder/format/PixelFormat.ts';
import { VideoStream } from '../ffmpeg/builder/MediaStream.ts';
import { FfmpegState } from '../ffmpeg/builder/state/FfmpegState.ts';
import { FrameSize } from '../ffmpeg/builder/types.ts';
export const FfmpegStateVersion702 = () =>
FfmpegState.create({
version: {
versionString: 'n7.0.2-15-g0458a86656-20240904',
majorVersion: 7,
minorVersion: 0,
patchVersion: 2,
isUnknown: false,
},
});
export const h2641080pVideoStream = () =>
VideoStream.create({
codec: 'h264',
displayAspectRatio: '16:9',
frameSize: FrameSize.FHD,
index: 0,
pixelFormat: new PixelFormatYuv420P(),
sampleAspectRatio: '1:1',
frameRate: '23.98',
});
export const h264FourKVideoStream = () =>
VideoStream.create({
codec: 'h264',
displayAspectRatio: '16:9',
frameSize: FrameSize.FourK,
index: 0,
pixelFormat: new PixelFormatYuv420P(),
sampleAspectRatio: '1:1',
frameRate: '23.98',
});