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 { NULL_LOCATION } from "constants/upload";
|
||||||
import type { ParsedExtractedMetadata } from "types/metadata";
|
import type { ParsedExtractedMetadata } from "types/metadata";
|
||||||
import type { DedicatedFFmpegWorker } from "worker/ffmpeg.worker";
|
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
|
* 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 (
|
export const generateVideoThumbnailNative = async (
|
||||||
electron: Electron,
|
electron: Electron,
|
||||||
dataOrPath: Uint8Array | string,
|
desktopUploadItem: DesktopUploadItem,
|
||||||
) =>
|
) =>
|
||||||
_generateVideoThumbnail((seekTime: number) =>
|
_generateVideoThumbnail((seekTime: number) =>
|
||||||
electron.ffmpegExec(
|
electron.ffmpegExec(
|
||||||
makeGenThumbnailCommand(seekTime),
|
makeGenThumbnailCommand(seekTime),
|
||||||
dataOrPath,
|
toDataOrPathOrZipEntry(desktopUploadItem),
|
||||||
"jpeg",
|
"jpeg",
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
|
@ -104,21 +108,16 @@ export const extractVideoMetadata = async (
|
||||||
const outputData =
|
const outputData =
|
||||||
uploadItem instanceof File
|
uploadItem instanceof File
|
||||||
? await ffmpegExecWeb(command, uploadItem, "txt", 0)
|
? 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);
|
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:
|
// Options:
|
||||||
//
|
//
|
||||||
// - `-c [short for codex] copy`
|
// - `-c [short for codex] copy`
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { type Electron } from "@/next/types/ipc";
|
||||||
import { withTimeout } from "@ente/shared/utils";
|
import { withTimeout } from "@ente/shared/utils";
|
||||||
import * as ffmpeg from "services/ffmpeg";
|
import * as ffmpeg from "services/ffmpeg";
|
||||||
import { heicToJPEG } from "services/heic-convert";
|
import { heicToJPEG } from "services/heic-convert";
|
||||||
|
import { toDataOrPathOrZipEntry, type DesktopUploadItem } from "./types";
|
||||||
|
|
||||||
/** Maximum width or height of the generated thumbnail */
|
/** Maximum width or height of the generated thumbnail */
|
||||||
const maxThumbnailDimension = 720;
|
const maxThumbnailDimension = 720;
|
||||||
|
@ -189,16 +190,16 @@ const percentageSizeDiff = (
|
||||||
*/
|
*/
|
||||||
export const generateThumbnailNative = async (
|
export const generateThumbnailNative = async (
|
||||||
electron: Electron,
|
electron: Electron,
|
||||||
dataOrPath: Uint8Array | string,
|
desktopUploadItem: DesktopUploadItem,
|
||||||
fileTypeInfo: FileTypeInfo,
|
fileTypeInfo: FileTypeInfo,
|
||||||
): Promise<Uint8Array> =>
|
): Promise<Uint8Array> =>
|
||||||
fileTypeInfo.fileType === FILE_TYPE.IMAGE
|
fileTypeInfo.fileType === FILE_TYPE.IMAGE
|
||||||
? await electron.generateImageThumbnail(
|
? await electron.generateImageThumbnail(
|
||||||
dataOrPath,
|
toDataOrPathOrZipEntry(desktopUploadItem),
|
||||||
maxThumbnailDimension,
|
maxThumbnailDimension,
|
||||||
maxThumbnailSize,
|
maxThumbnailSize,
|
||||||
)
|
)
|
||||||
: ffmpeg.generateVideoThumbnailNative(electron, dataOrPath);
|
: ffmpeg.generateVideoThumbnailNative(electron, desktopUploadItem);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fallback, black, thumbnail for use in cases where thumbnail generation
|
* 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].
|
* Also see: [Note: Reading a UploadItem].
|
||||||
*/
|
*/
|
||||||
export type UploadItem = File | FileAndPath | string | ZipItem;
|
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 &&
|
fileTypeInfo.fileType == FILE_TYPE.IMAGE &&
|
||||||
moduleState.isNativeImageThumbnailGenerationNotAvailable;
|
moduleState.isNativeImageThumbnailGenerationNotAvailable;
|
||||||
|
|
||||||
// 1. Native thumbnail generation using file's path.
|
// 1. Native thumbnail generation using items's (effective) path.
|
||||||
if (electron && !notAvailable) {
|
if (electron && !notAvailable && !(uploadItem instanceof File)) {
|
||||||
try {
|
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(
|
thumbnail = await generateThumbnailNative(
|
||||||
electron,
|
electron,
|
||||||
uploadItem instanceof File ? uploadItem["path"] : uploadItem,
|
uploadItem,
|
||||||
fileTypeInfo,
|
fileTypeInfo,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1051,12 +1049,14 @@ const withThumbnail = async (
|
||||||
// The fallback in this case involves reading the entire stream into
|
// The fallback in this case involves reading the entire stream into
|
||||||
// memory, and passing that data across the IPC boundary in a single
|
// 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
|
// go (i.e. not in a streaming manner). This is risky for videos of
|
||||||
// unbounded sizes, plus that isn't the expected scenario. So
|
// unbounded sizes, plus we shouldn't even be getting here unless
|
||||||
// instead of trying to cater for arbitrary exceptions, we only run
|
// something went wrong.
|
||||||
// this fallback to cover for the case where thumbnail generation
|
//
|
||||||
// was not available for an image file on Windows. If/when we add
|
// So instead of trying to cater for arbitrary exceptions, we only
|
||||||
// support of native thumbnailing on Windows too, this entire branch
|
// run this fallback to cover for the case where thumbnail
|
||||||
// can be removed.
|
// 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) {
|
if (fileTypeInfo.fileType == FILE_TYPE.IMAGE) {
|
||||||
const data = await readEntireStream(fileStream.stream);
|
const data = await readEntireStream(fileStream.stream);
|
||||||
|
|
Loading…
Reference in a new issue