more
This commit is contained in:
parent
a5177a3742
commit
68f3f1e714
4 changed files with 44 additions and 28 deletions
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue