diff options
Diffstat (limited to 'apps/web/src/lib/fps')
| -rw-r--r-- | apps/web/src/lib/fps/__tests__/fps.test.ts | 65 | ||||
| -rw-r--r-- | apps/web/src/lib/fps/defaults.ts | 3 | ||||
| -rw-r--r-- | apps/web/src/lib/fps/presets.ts | 7 | ||||
| -rw-r--r-- | apps/web/src/lib/fps/utils.ts | 95 |
4 files changed, 0 insertions, 170 deletions
diff --git a/apps/web/src/lib/fps/__tests__/fps.test.ts b/apps/web/src/lib/fps/__tests__/fps.test.ts deleted file mode 100644 index 10eed8d9..00000000 --- a/apps/web/src/lib/fps/__tests__/fps.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { describe, expect, test } from "bun:test"; -import { - getHighestImportedVideoFps, - getRaisedProjectFpsForImportedMedia, -} from "@/lib/fps/utils"; - -describe("getHighestImportedVideoFps", () => { - test("returns the highest valid video fps", () => { - expect( - getHighestImportedVideoFps({ - mediaAssets: [ - { type: "audio" }, - { type: "video", fps: 30 }, - { type: "image", fps: 120 }, - { type: "video", fps: 60 }, - ], - }), - ).toBe(60); - }); - - test("ignores missing and invalid fps values", () => { - expect( - getHighestImportedVideoFps({ - mediaAssets: [ - { type: "video" }, - { type: "video", fps: 0 }, - { type: "video", fps: -10 }, - { type: "audio", fps: 120 }, - ], - }), - ).toBeNull(); - }); -}); - -describe("getRaisedProjectFpsForImportedMedia", () => { - test("raises the project fps to match a higher-fps import", () => { - expect( - getRaisedProjectFpsForImportedMedia({ - currentFps: { numerator: 30, denominator: 1 }, - importedAssets: [{ type: "video", fps: 60 }], - }), - ).toEqual({ numerator: 60, denominator: 1 }); - }); - - test("does not lower the project fps for lower-fps imports", () => { - expect( - getRaisedProjectFpsForImportedMedia({ - currentFps: { numerator: 60, denominator: 1 }, - importedAssets: [{ type: "video", fps: 10 }], - }), - ).toBeNull(); - }); - - test("ignores non-video imports", () => { - expect( - getRaisedProjectFpsForImportedMedia({ - currentFps: { numerator: 30, denominator: 1 }, - importedAssets: [ - { type: "image", fps: 60 }, - { type: "audio", fps: 120 }, - ], - }), - ).toBeNull(); - }); -}); diff --git a/apps/web/src/lib/fps/defaults.ts b/apps/web/src/lib/fps/defaults.ts deleted file mode 100644 index 66bf0b1c..00000000 --- a/apps/web/src/lib/fps/defaults.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { FrameRate } from "opencut-wasm"; - -export const DEFAULT_FPS: FrameRate = { numerator: 30, denominator: 1 }; diff --git a/apps/web/src/lib/fps/presets.ts b/apps/web/src/lib/fps/presets.ts deleted file mode 100644 index b09920d4..00000000 --- a/apps/web/src/lib/fps/presets.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const FPS_PRESETS = [ - { value: "24", label: "24 fps" }, - { value: "25", label: "25 fps" }, - { value: "30", label: "30 fps" }, - { value: "60", label: "60 fps" }, - { value: "120", label: "120 fps" }, -] as const; diff --git a/apps/web/src/lib/fps/utils.ts b/apps/web/src/lib/fps/utils.ts deleted file mode 100644 index 932788c4..00000000 --- a/apps/web/src/lib/fps/utils.ts +++ /dev/null @@ -1,95 +0,0 @@ -import type { FrameRate } from "opencut-wasm"; -import type { MediaAsset } from "@/lib/media/types"; - -type MediaAssetFpsInput = Pick<MediaAsset, "type" | "fps">; - -const STANDARD_FRAME_RATES: Array<{ value: number; rate: FrameRate }> = [ - { value: 24_000 / 1_001, rate: { numerator: 24_000, denominator: 1_001 } }, - { value: 24, rate: { numerator: 24, denominator: 1 } }, - { value: 25, rate: { numerator: 25, denominator: 1 } }, - { value: 30_000 / 1_001, rate: { numerator: 30_000, denominator: 1_001 } }, - { value: 30, rate: { numerator: 30, denominator: 1 } }, - { value: 48, rate: { numerator: 48, denominator: 1 } }, - { value: 50, rate: { numerator: 50, denominator: 1 } }, - { value: 60_000 / 1_001, rate: { numerator: 60_000, denominator: 1_001 } }, - { value: 60, rate: { numerator: 60, denominator: 1 } }, - { value: 120, rate: { numerator: 120, denominator: 1 } }, -]; - -const STANDARD_FRAME_RATE_TOLERANCE = 0.01; - -export function frameRateToFloat(rate: FrameRate): number { - return rate.numerator / rate.denominator; -} - -export function frameRatesEqual(a: FrameRate, b: FrameRate): boolean { - return a.numerator === b.numerator && a.denominator === b.denominator; -} - -export function floatToFrameRate(fps: number): FrameRate { - const standard = STANDARD_FRAME_RATES.find( - (candidate) => Math.abs(fps - candidate.value) <= STANDARD_FRAME_RATE_TOLERANCE, - ); - if (standard) return standard.rate; - - if (Number.isInteger(fps)) { - return { numerator: fps, denominator: 1 }; - } - - const ARBITRARY_DENOMINATOR = 1_000_000; - const scaledNumerator = Math.round(fps * ARBITRARY_DENOMINATOR); - const divisor = gcd(scaledNumerator, ARBITRARY_DENOMINATOR); - return { - numerator: scaledNumerator / divisor, - denominator: ARBITRARY_DENOMINATOR / divisor, - }; -} - -function gcd(left: number, right: number): number { - let a = Math.abs(left); - let b = Math.abs(right); - while (b !== 0) { - const remainder = a % b; - a = b; - b = remainder; - } - return a || 1; -} - -export function getHighestImportedVideoFps({ - mediaAssets, -}: { - mediaAssets: MediaAssetFpsInput[]; -}): number | null { - let highestFps: number | null = null; - - for (const asset of mediaAssets) { - const fps = asset.fps ?? Number.NaN; - if (asset.type !== "video") continue; - if (!Number.isFinite(fps) || fps <= 0) continue; - - highestFps = highestFps === null ? fps : Math.max(highestFps, fps); - } - - return highestFps; -} - -export function getRaisedProjectFpsForImportedMedia({ - currentFps, - importedAssets, -}: { - currentFps: FrameRate; - importedAssets: MediaAssetFpsInput[]; -}): FrameRate | null { - const highestImportedVideoFps = getHighestImportedVideoFps({ - mediaAssets: importedAssets, - }); - - const currentFpsFloat = frameRateToFloat(currentFps); - - if (highestImportedVideoFps === null || highestImportedVideoFps <= currentFpsFloat) { - return null; - } - - return floatToFrameRate(highestImportedVideoFps); -} |
