refactor: update media processing to use width and height instead of aspect ratio

This commit is contained in:
Maze Winther
2025-07-01 01:13:14 +02:00
parent 9b37ce6610
commit 1a01871cfc
6 changed files with 335 additions and 310 deletions

View File

@ -5,7 +5,11 @@ import {
type TimelineClip,
type TimelineTrack,
} from "@/stores/timeline-store";
import { useMediaStore, type MediaItem } from "@/stores/media-store";
import {
useMediaStore,
type MediaItem,
getMediaAspectRatio,
} from "@/stores/media-store";
import { usePlaybackStore } from "@/stores/playback-store";
import { useEditorStore } from "@/stores/editor-store";
import { VideoPlayer } from "@/components/ui/video-player";
@ -262,7 +266,7 @@ function PreviewToolbar({ hasAnyClips }: { hasAnyClips: boolean }) {
mediaItem &&
(mediaItem.type === "video" || mediaItem.type === "image")
) {
return mediaItem.aspectRatio || 16 / 9; // Default to 16:9 if aspectRatio not available
return getMediaAspectRatio(mediaItem);
}
}
}

View File

@ -3,7 +3,7 @@ import {
getFileType,
generateVideoThumbnail,
getMediaDuration,
getImageAspectRatio,
getImageDimensions,
type MediaItem,
} from "@/stores/media-store";
// import { generateThumbnail, getVideoInfo } from "./ffmpeg-utils"; // Temporarily disabled
@ -31,20 +31,23 @@ export async function processMediaFiles(
const url = URL.createObjectURL(file);
let thumbnailUrl: string | undefined;
let duration: number | undefined;
let aspectRatio: number = 16 / 9; // Default fallback
let width: number | undefined;
let height: number | undefined;
try {
if (fileType === "image") {
// Get image aspect ratio
aspectRatio = await getImageAspectRatio(file);
// Get image dimensions
const dimensions = await getImageDimensions(file);
width = dimensions.width;
height = dimensions.height;
} else if (fileType === "video") {
// Use basic thumbnail generation for now
const videoResult = await generateVideoThumbnail(file);
thumbnailUrl = videoResult.thumbnailUrl;
aspectRatio = videoResult.aspectRatio;
width = videoResult.width;
height = videoResult.height;
} else if (fileType === "audio") {
// For audio, use a square aspect ratio
aspectRatio = 1;
// For audio, we don't set width/height (they'll be undefined)
}
// Get duration for videos and audio (if not already set by FFmpeg)
@ -59,7 +62,8 @@ export async function processMediaFiles(
url,
thumbnailUrl,
duration,
aspectRatio,
width,
height,
});
// Yield back to the event loop to keep the UI responsive

View File

@ -94,7 +94,8 @@ class StorageService {
type: mediaItem.type,
size: mediaItem.file.size,
lastModified: mediaItem.file.lastModified,
aspectRatio: mediaItem.aspectRatio,
width: mediaItem.width,
height: mediaItem.height,
duration: mediaItem.duration,
};
@ -118,7 +119,8 @@ class StorageService {
type: metadata.type,
file,
url,
aspectRatio: metadata.aspectRatio,
width: metadata.width,
height: metadata.height,
duration: metadata.duration,
// thumbnailUrl would need to be regenerated or cached separately
};

View File

@ -14,7 +14,8 @@ export interface MediaFileData {
type: "image" | "video" | "audio";
size: number;
lastModified: number;
aspectRatio: number;
width?: number;
height?: number;
duration?: number;
// File will be stored separately in OPFS
}

View File

@ -9,7 +9,8 @@ export interface MediaItem {
url: string; // Object URL for preview
thumbnailUrl?: string; // For video thumbnails
duration?: number; // For video/audio duration
aspectRatio: number; // width / height
width?: number; // For video/image width
height?: number; // For video/image height
}
interface MediaStore {
@ -40,14 +41,17 @@ export const getFileType = (file: File): "image" | "video" | "audio" | null => {
return null;
};
// Helper function to get image aspect ratio
export const getImageAspectRatio = (file: File): Promise<number> => {
// Helper function to get image dimensions
export const getImageDimensions = (
file: File
): Promise<{ width: number; height: number }> => {
return new Promise((resolve, reject) => {
const img = new Image();
img.addEventListener("load", () => {
const aspectRatio = img.naturalWidth / img.naturalHeight;
resolve(aspectRatio);
const width = img.naturalWidth;
const height = img.naturalHeight;
resolve({ width, height });
img.remove();
});
@ -60,10 +64,10 @@ export const getImageAspectRatio = (file: File): Promise<number> => {
});
};
// Helper function to generate video thumbnail and get aspect ratio
// Helper function to generate video thumbnail and get dimensions
export const generateVideoThumbnail = (
file: File
): Promise<{ thumbnailUrl: string; aspectRatio: number }> => {
): Promise<{ thumbnailUrl: string; width: number; height: number }> => {
return new Promise((resolve, reject) => {
const video = document.createElement("video");
const canvas = document.createElement("canvas");
@ -85,9 +89,10 @@ export const generateVideoThumbnail = (
video.addEventListener("seeked", () => {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const thumbnailUrl = canvas.toDataURL("image/jpeg", 0.8);
const aspectRatio = video.videoWidth / video.videoHeight;
const width = video.videoWidth;
const height = video.videoHeight;
resolve({ thumbnailUrl, aspectRatio });
resolve({ thumbnailUrl, width, height });
// Cleanup
video.remove();
@ -127,6 +132,14 @@ export const getMediaDuration = (file: File): Promise<number> => {
});
};
// Helper to get aspect ratio from MediaItem
export const getMediaAspectRatio = (item: MediaItem): number => {
if (item.width && item.height) {
return item.width / item.height;
}
return 16 / 9; // Default aspect ratio
};
export const useMediaStore = create<MediaStore>((set, get) => ({
mediaItems: [],
isLoading: false,

View File

@ -1,8 +1,7 @@
import { create } from "zustand";
import type { TrackType } from "@/types/timeline";
import { useEditorStore } from "./editor-store";
import { useMediaStore } from "./media-store";
import { toast } from "sonner";
import { useMediaStore, getMediaAspectRatio } from "./media-store";
// Helper function to manage clip naming with suffixes
const getClipNameWithSuffix = (
@ -232,7 +231,9 @@ export const useTimelineStore = create<TimelineStore>((set, get) => ({
(mediaItem.type === "image" || mediaItem.type === "video")
) {
const editorStore = useEditorStore.getState();
editorStore.setCanvasSizeFromAspectRatio(mediaItem.aspectRatio);
editorStore.setCanvasSizeFromAspectRatio(
getMediaAspectRatio(mediaItem)
);
}
}