Skip to content

Commit 0dee35b

Browse files
committed
fix(media): floor the scaled concat axes so the area bound actually holds
The scale factor lands both axes on a product of exactly the budget, so an axis allowed to round up can put the pair back over it — and when both round up and both land even, nothing pulls them back. A brute force over every dimension pair in 16..4096 finds 219,280 that violate the bound under round-to-even, worst 2694x3520 -> 2688x3512, 3072 pixels over. Under floor-to-even: none. Flooring keeps each axis at or below its exact target, so the product cannot exceed the budget. Probed dimensions are already integers, so this changes only the scaled path.
1 parent 627509f commit 0dee35b

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

apps/sim/lib/media/ffmpeg.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,21 @@ describe('runFfmpegOperation concat normalization target', () => {
204204
expect(width).toBe(height)
205205
})
206206

207+
it('holds the area bound for dimensions that round up on both axes', async () => {
208+
// 2694x3520 is the worst case in the whole dimension space: the scale factor
209+
// lands both axes on .5, and rounding both up to an even number put the pair
210+
// 3072 pixels back over the budget it had just been scaled into.
211+
probeReport.json = JSON.stringify({
212+
streams: [{ codec_type: 'video', codec_name: 'h264', width: 2694, height: 3520 }],
213+
format: { duration: '2', format_name: 'mp4' },
214+
})
215+
216+
await runFfmpegOperation('concat', [videoInput, videoInput])
217+
218+
const target = capturedVideoFilters[0].match(/scale=(\d+):(\d+):/)
219+
expect(Number(target![1]) * Number(target![2])).toBeLessThanOrEqual(4096 * 2304)
220+
})
221+
207222
it('emits even dimensions, which yuv420p requires', async () => {
208223
probeReport.json = JSON.stringify({
209224
streams: [{ codec_type: 'video', codec_name: 'h264', width: 1919, height: 1081 }],

apps/sim/lib/media/ffmpeg.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,8 +645,17 @@ function clampProbedFrame(width: number, height: number): { width: number; heigh
645645
return { width: w, height: h }
646646
}
647647

648+
/**
649+
* Floors rather than rounds, which is what makes the area bound hold.
650+
*
651+
* The scale factor lands both axes on a product of exactly the budget, so any
652+
* axis allowed to round *up* can put the pair back over it — and when both round
653+
* up and both land even, nothing pulls them back. Flooring keeps each axis at or
654+
* below its exact target, so the product cannot exceed the budget. Probed
655+
* dimensions are already integers, so this only ever bites on the scaled path.
656+
*/
648657
function clampProbedAxis(value: number): number {
649-
const bounded = Math.min(Math.max(Math.round(value), MIN_SCALE_DIMENSION), MAX_SCALE_DIMENSION)
658+
const bounded = Math.min(Math.max(Math.floor(value), MIN_SCALE_DIMENSION), MAX_SCALE_DIMENSION)
650659
return bounded - (bounded % 2)
651660
}
652661

0 commit comments

Comments
 (0)