This commit is contained in:
Manav Rathi 2024-04-30 11:01:50 +05:30
parent a5177a3742
commit 68f3f1e714
No known key found for this signature in database
4 changed files with 44 additions and 28 deletions

View file

@ -10,7 +10,11 @@ import {
import { NULL_LOCATION } from "constants/upload";
import type { ParsedExtractedMetadata } from "types/metadata";
import type { DedicatedFFmpegWorker } from "worker/ffmpeg.worker";
import type { UploadItem } from "./upload/types";
import {
toDataOrPathOrZipEntry,
type DesktopUploadItem,
type UploadItem,
} from "./upload/types";
/**
* Generate a thumbnail for the given video using a wasm FFmpeg running in a web
@ -59,12 +63,12 @@ const _generateVideoThumbnail = async (
*/
export const generateVideoThumbnailNative = async (
electron: Electron,
dataOrPath: Uint8Array | string,
desktopUploadItem: DesktopUploadItem,
) =>
_generateVideoThumbnail((seekTime: number) =>
electron.ffmpegExec(
makeGenThumbnailCommand(seekTime),
dataOrPath,
toDataOrPathOrZipEntry(desktopUploadItem),
"jpeg",
0,
),
@ -104,21 +108,16 @@ export const extractVideoMetadata = async (
const outputData =
uploadItem instanceof File
? await ffmpegExecWeb(command, uploadItem, "txt", 0)
: await electron.ffmpegExec(command, forE(uploadItem), "txt", 0);
: await electron.ffmpegExec(
command,
toDataOrPathOrZipEntry(uploadItem),
"txt",
0,
);
return parseFFmpegExtractedMetadata(outputData);
};
/**
* For each of cases of {@link UploadItem} that apply when we're running in the
* context of our desktop app, return a value that can be passed to
* {@link Electron}'s {@link ffmpegExec} over IPC.
*/
const forE = (desktopUploadItem: Exclude<UploadItem, File>) =>
typeof desktopUploadItem == "string" || Array.isArray(desktopUploadItem)
? desktopUploadItem
: desktopUploadItem.path;
// Options:
//
// - `-c [short for codex] copy`

View file

@ -4,6 +4,7 @@ import { type Electron } from "@/next/types/ipc";
import { withTimeout } from "@ente/shared/utils";
import * as ffmpeg from "services/ffmpeg";
import { heicToJPEG } from "services/heic-convert";
import { toDataOrPathOrZipEntry, type DesktopUploadItem } from "./types";
/** Maximum width or height of the generated thumbnail */
const maxThumbnailDimension = 720;
@ -189,16 +190,16 @@ const percentageSizeDiff = (
*/
export const generateThumbnailNative = async (
electron: Electron,
dataOrPath: Uint8Array | string,
desktopUploadItem: DesktopUploadItem,
fileTypeInfo: FileTypeInfo,
): Promise<Uint8Array> =>
fileTypeInfo.fileType === FILE_TYPE.IMAGE
? await electron.generateImageThumbnail(
dataOrPath,
toDataOrPathOrZipEntry(desktopUploadItem),
maxThumbnailDimension,
maxThumbnailSize,
)
: ffmpeg.generateVideoThumbnailNative(electron, dataOrPath);
: ffmpeg.generateVideoThumbnailNative(electron, desktopUploadItem);
/**
* A fallback, black, thumbnail for use in cases where thumbnail generation

View file

@ -29,3 +29,19 @@ import type { ZipItem } from "@/next/types/ipc";
* Also see: [Note: Reading a UploadItem].
*/
export type UploadItem = File | FileAndPath | string | ZipItem;
/**
* The of cases of {@link UploadItem} that apply when we're running in the
* context of our desktop app.
*/
export type DesktopUploadItem = Exclude<UploadItem, File>;
/**
* For each of cases of {@link UploadItem} that apply when we're running in the
* context of our desktop app, return a value that can be passed to
* {@link Electron} functions over IPC.
*/
export const toDataOrPathOrZipEntry = (desktopUploadItem: DesktopUploadItem) =>
typeof desktopUploadItem == "string" || Array.isArray(desktopUploadItem)
? desktopUploadItem
: desktopUploadItem.path;

View file

@ -1012,14 +1012,12 @@ const withThumbnail = async (
fileTypeInfo.fileType == FILE_TYPE.IMAGE &&
moduleState.isNativeImageThumbnailGenerationNotAvailable;
// 1. Native thumbnail generation using file's path.
if (electron && !notAvailable) {
// 1. Native thumbnail generation using items's (effective) path.
if (electron && !notAvailable && !(uploadItem instanceof File)) {
try {
// When running in the context of our desktop app, File paths will
// be absolute. See: [Note: File paths when running under Electron].
thumbnail = await generateThumbnailNative(
electron,
uploadItem instanceof File ? uploadItem["path"] : uploadItem,
uploadItem,
fileTypeInfo,
);
} catch (e) {
@ -1051,12 +1049,14 @@ const withThumbnail = async (
// The fallback in this case involves reading the entire stream into
// memory, and passing that data across the IPC boundary in a single
// go (i.e. not in a streaming manner). This is risky for videos of
// unbounded sizes, plus that isn't the expected scenario. So
// instead of trying to cater for arbitrary exceptions, we only run
// this fallback to cover for the case where thumbnail generation
// was not available for an image file on Windows. If/when we add
// support of native thumbnailing on Windows too, this entire branch
// can be removed.
// unbounded sizes, plus we shouldn't even be getting here unless
// something went wrong.
//
// So instead of trying to cater for arbitrary exceptions, we only
// run this fallback to cover for the case where thumbnail
// generation was not available for an image file on Windows.
// If/when we add support of native thumbnailing on Windows too,
// this entire branch can be removed.
if (fileTypeInfo.fileType == FILE_TYPE.IMAGE) {
const data = await readEntireStream(fileStream.stream);