refactor: update media processing to use width and height instead of aspect ratio
This commit is contained in:
@ -5,7 +5,11 @@ import {
|
|||||||
type TimelineClip,
|
type TimelineClip,
|
||||||
type TimelineTrack,
|
type TimelineTrack,
|
||||||
} from "@/stores/timeline-store";
|
} 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 { usePlaybackStore } from "@/stores/playback-store";
|
||||||
import { useEditorStore } from "@/stores/editor-store";
|
import { useEditorStore } from "@/stores/editor-store";
|
||||||
import { VideoPlayer } from "@/components/ui/video-player";
|
import { VideoPlayer } from "@/components/ui/video-player";
|
||||||
@ -262,7 +266,7 @@ function PreviewToolbar({ hasAnyClips }: { hasAnyClips: boolean }) {
|
|||||||
mediaItem &&
|
mediaItem &&
|
||||||
(mediaItem.type === "video" || mediaItem.type === "image")
|
(mediaItem.type === "video" || mediaItem.type === "image")
|
||||||
) {
|
) {
|
||||||
return mediaItem.aspectRatio || 16 / 9; // Default to 16:9 if aspectRatio not available
|
return getMediaAspectRatio(mediaItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
getFileType,
|
getFileType,
|
||||||
generateVideoThumbnail,
|
generateVideoThumbnail,
|
||||||
getMediaDuration,
|
getMediaDuration,
|
||||||
getImageAspectRatio,
|
getImageDimensions,
|
||||||
type MediaItem,
|
type MediaItem,
|
||||||
} from "@/stores/media-store";
|
} from "@/stores/media-store";
|
||||||
// import { generateThumbnail, getVideoInfo } from "./ffmpeg-utils"; // Temporarily disabled
|
// import { generateThumbnail, getVideoInfo } from "./ffmpeg-utils"; // Temporarily disabled
|
||||||
@ -31,20 +31,23 @@ export async function processMediaFiles(
|
|||||||
const url = URL.createObjectURL(file);
|
const url = URL.createObjectURL(file);
|
||||||
let thumbnailUrl: string | undefined;
|
let thumbnailUrl: string | undefined;
|
||||||
let duration: number | undefined;
|
let duration: number | undefined;
|
||||||
let aspectRatio: number = 16 / 9; // Default fallback
|
let width: number | undefined;
|
||||||
|
let height: number | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (fileType === "image") {
|
if (fileType === "image") {
|
||||||
// Get image aspect ratio
|
// Get image dimensions
|
||||||
aspectRatio = await getImageAspectRatio(file);
|
const dimensions = await getImageDimensions(file);
|
||||||
|
width = dimensions.width;
|
||||||
|
height = dimensions.height;
|
||||||
} else if (fileType === "video") {
|
} else if (fileType === "video") {
|
||||||
// Use basic thumbnail generation for now
|
// Use basic thumbnail generation for now
|
||||||
const videoResult = await generateVideoThumbnail(file);
|
const videoResult = await generateVideoThumbnail(file);
|
||||||
thumbnailUrl = videoResult.thumbnailUrl;
|
thumbnailUrl = videoResult.thumbnailUrl;
|
||||||
aspectRatio = videoResult.aspectRatio;
|
width = videoResult.width;
|
||||||
|
height = videoResult.height;
|
||||||
} else if (fileType === "audio") {
|
} else if (fileType === "audio") {
|
||||||
// For audio, use a square aspect ratio
|
// For audio, we don't set width/height (they'll be undefined)
|
||||||
aspectRatio = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get duration for videos and audio (if not already set by FFmpeg)
|
// Get duration for videos and audio (if not already set by FFmpeg)
|
||||||
@ -59,7 +62,8 @@ export async function processMediaFiles(
|
|||||||
url,
|
url,
|
||||||
thumbnailUrl,
|
thumbnailUrl,
|
||||||
duration,
|
duration,
|
||||||
aspectRatio,
|
width,
|
||||||
|
height,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Yield back to the event loop to keep the UI responsive
|
// Yield back to the event loop to keep the UI responsive
|
||||||
|
@ -94,7 +94,8 @@ class StorageService {
|
|||||||
type: mediaItem.type,
|
type: mediaItem.type,
|
||||||
size: mediaItem.file.size,
|
size: mediaItem.file.size,
|
||||||
lastModified: mediaItem.file.lastModified,
|
lastModified: mediaItem.file.lastModified,
|
||||||
aspectRatio: mediaItem.aspectRatio,
|
width: mediaItem.width,
|
||||||
|
height: mediaItem.height,
|
||||||
duration: mediaItem.duration,
|
duration: mediaItem.duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -118,7 +119,8 @@ class StorageService {
|
|||||||
type: metadata.type,
|
type: metadata.type,
|
||||||
file,
|
file,
|
||||||
url,
|
url,
|
||||||
aspectRatio: metadata.aspectRatio,
|
width: metadata.width,
|
||||||
|
height: metadata.height,
|
||||||
duration: metadata.duration,
|
duration: metadata.duration,
|
||||||
// thumbnailUrl would need to be regenerated or cached separately
|
// thumbnailUrl would need to be regenerated or cached separately
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,8 @@ export interface MediaFileData {
|
|||||||
type: "image" | "video" | "audio";
|
type: "image" | "video" | "audio";
|
||||||
size: number;
|
size: number;
|
||||||
lastModified: number;
|
lastModified: number;
|
||||||
aspectRatio: number;
|
width?: number;
|
||||||
|
height?: number;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
// File will be stored separately in OPFS
|
// File will be stored separately in OPFS
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,8 @@ export interface MediaItem {
|
|||||||
url: string; // Object URL for preview
|
url: string; // Object URL for preview
|
||||||
thumbnailUrl?: string; // For video thumbnails
|
thumbnailUrl?: string; // For video thumbnails
|
||||||
duration?: number; // For video/audio duration
|
duration?: number; // For video/audio duration
|
||||||
aspectRatio: number; // width / height
|
width?: number; // For video/image width
|
||||||
|
height?: number; // For video/image height
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MediaStore {
|
interface MediaStore {
|
||||||
@ -40,14 +41,17 @@ export const getFileType = (file: File): "image" | "video" | "audio" | null => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to get image aspect ratio
|
// Helper function to get image dimensions
|
||||||
export const getImageAspectRatio = (file: File): Promise<number> => {
|
export const getImageDimensions = (
|
||||||
|
file: File
|
||||||
|
): Promise<{ width: number; height: number }> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
|
|
||||||
img.addEventListener("load", () => {
|
img.addEventListener("load", () => {
|
||||||
const aspectRatio = img.naturalWidth / img.naturalHeight;
|
const width = img.naturalWidth;
|
||||||
resolve(aspectRatio);
|
const height = img.naturalHeight;
|
||||||
|
resolve({ width, height });
|
||||||
img.remove();
|
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 = (
|
export const generateVideoThumbnail = (
|
||||||
file: File
|
file: File
|
||||||
): Promise<{ thumbnailUrl: string; aspectRatio: number }> => {
|
): Promise<{ thumbnailUrl: string; width: number; height: number }> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const video = document.createElement("video");
|
const video = document.createElement("video");
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
@ -85,9 +89,10 @@ export const generateVideoThumbnail = (
|
|||||||
video.addEventListener("seeked", () => {
|
video.addEventListener("seeked", () => {
|
||||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||||
const thumbnailUrl = canvas.toDataURL("image/jpeg", 0.8);
|
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
|
// Cleanup
|
||||||
video.remove();
|
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) => ({
|
export const useMediaStore = create<MediaStore>((set, get) => ({
|
||||||
mediaItems: [],
|
mediaItems: [],
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import type { TrackType } from "@/types/timeline";
|
import type { TrackType } from "@/types/timeline";
|
||||||
import { useEditorStore } from "./editor-store";
|
import { useEditorStore } from "./editor-store";
|
||||||
import { useMediaStore } from "./media-store";
|
import { useMediaStore, getMediaAspectRatio } from "./media-store";
|
||||||
import { toast } from "sonner";
|
|
||||||
|
|
||||||
// Helper function to manage clip naming with suffixes
|
// Helper function to manage clip naming with suffixes
|
||||||
const getClipNameWithSuffix = (
|
const getClipNameWithSuffix = (
|
||||||
@ -232,7 +231,9 @@ export const useTimelineStore = create<TimelineStore>((set, get) => ({
|
|||||||
(mediaItem.type === "image" || mediaItem.type === "video")
|
(mediaItem.type === "image" || mediaItem.type === "video")
|
||||||
) {
|
) {
|
||||||
const editorStore = useEditorStore.getState();
|
const editorStore = useEditorStore.getState();
|
||||||
editorStore.setCanvasSizeFromAspectRatio(mediaItem.aspectRatio);
|
editorStore.setCanvasSizeFromAspectRatio(
|
||||||
|
getMediaAspectRatio(mediaItem)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user