Desktop side

This commit is contained in:
Manav Rathi 2024-04-22 16:32:04 +05:30
parent 4750caf156
commit 4461775283
No known key found for this signature in database
8 changed files with 42 additions and 58 deletions

View file

@ -156,10 +156,9 @@ export const attachIPCHandlers = () => {
(
_,
command: string[],
inputDataOrPath: Uint8Array | string,
outputFileName: string,
dataOrPath: Uint8Array | string,
timeoutMS: number,
) => ffmpegExec(command, inputDataOrPath, outputFileName, timeoutMS),
) => ffmpegExec(command, dataOrPath, timeoutMS),
);
// - ML

View file

@ -14,7 +14,7 @@ export const convertToJPEG = async (
imageData: Uint8Array,
): Promise<Uint8Array> => {
const inputFilePath = await makeTempFilePath(fileName);
const outputFilePath = await makeTempFilePath("output.jpeg");
const outputFilePath = await makeTempFilePath(".jpeg");
// Construct the command first, it may throw on NotAvailable on win32.
const command = convertToJPEGCommand(inputFilePath, outputFilePath);
@ -150,7 +150,7 @@ async function generateImageThumbnail_(
let tempOutputFilePath: string;
let quality = MAX_QUALITY;
try {
tempOutputFilePath = await makeTempFilePath("thumb.jpeg");
tempOutputFilePath = await makeTempFilePath(".jpeg");
let thumbnail: Uint8Array;
do {
await execAsync(

View file

@ -37,8 +37,7 @@ const outputPathPlaceholder = "OUTPUT";
*/
export const ffmpegExec = async (
command: string[],
inputDataOrPath: Uint8Array | string,
outputFileName: string,
dataOrPath: Uint8Array | string,
timeoutMS: number,
): Promise<Uint8Array> => {
// TODO (MR): This currently copies files for both input and output. This
@ -47,18 +46,18 @@ export const ffmpegExec = async (
let inputFilePath: string;
let isInputFileTemporary: boolean;
if (typeof inputDataOrPath == "string") {
inputFilePath = inputDataOrPath;
if (typeof dataOrPath == "string") {
inputFilePath = dataOrPath;
isInputFileTemporary = false;
} else {
inputFilePath = await makeTempFilePath("input" /* arbitrary */);
inputFilePath = await makeTempFilePath(".in");
isInputFileTemporary = true;
await fs.writeFile(inputFilePath, inputDataOrPath);
await fs.writeFile(inputFilePath, dataOrPath);
}
let outputFilePath: string | undefined;
try {
outputFilePath = await makeTempFilePath(outputFileName);
outputFilePath = await makeTempFilePath(".out");
const cmd = substitutePlaceholders(
command,

View file

@ -20,7 +20,7 @@ const cachedCLIPImageSession = makeCachedInferenceSession(
);
export const clipImageEmbedding = async (jpegImageData: Uint8Array) => {
const tempFilePath = await makeTempFilePath("");
const tempFilePath = await makeTempFilePath();
const imageStream = new Response(jpegImageData.buffer).body;
await writeStream(tempFilePath, imageStream);
try {

View file

@ -25,20 +25,21 @@ const randomPrefix = () => {
};
/**
* Return the path to a temporary file with the given {@link formatSuffix}.
* Return the path to a temporary file with the given {@link suffix}.
*
* The function returns the path to a file in the system temp directory (in an
* Ente specific folder therin) with a random prefix and the given
* {@link formatSuffix}. It ensures that there is no existing file with the same
* name already.
* Ente specific folder therin) with a random prefix and an (optional)
* {@link suffix}.
*
* It ensures that there is no existing file with the same name already.
*
* Use {@link deleteTempFile} to remove this file when you're done.
*/
export const makeTempFilePath = async (formatSuffix: string) => {
export const makeTempFilePath = async (suffix?: string) => {
const tempDir = await enteTempDirPath();
let result: string;
do {
result = path.join(tempDir, randomPrefix() + "-" + formatSuffix);
result = path.join(tempDir, `${randomPrefix()}${suffix ?? ""}`);
} while (existsSync(result));
return result;
};

View file

@ -144,17 +144,10 @@ const generateImageThumbnail = (
const ffmpegExec = (
command: string[],
inputDataOrPath: Uint8Array | string,
outputFileName: string,
dataOrPath: Uint8Array | string,
timeoutMS: number,
): Promise<Uint8Array> =>
ipcRenderer.invoke(
"ffmpegExec",
command,
inputDataOrPath,
outputFileName,
timeoutMS,
);
ipcRenderer.invoke("ffmpegExec", command, dataOrPath, timeoutMS);
// - ML

View file

@ -36,7 +36,6 @@ export const generateVideoThumbnail = async (blob: Blob) => {
outputPathPlaceholder,
],
blob,
"thumb.jpeg",
);
try {
@ -161,27 +160,25 @@ export async function convertToMP4(file: File) {
* Run the given FFmpeg command.
*
* If we're running in the context of our desktop app, use the FFmpeg binary we
* bundle with our desktop app to run the command. Otherwise fallback to using
* the wasm FFmpeg we link to from our web app in a web worker.
* bundle with our desktop app to run the command. Otherwise fallback to using a
* wasm FFmpeg in a web worker.
*
* As a rough ballpark, the native FFmpeg integration in the desktop app is
* 10-20x faster than the wasm one currently. See: [Note: FFmpeg in Electron].
* As a rough ballpark, currently the native FFmpeg integration in the desktop
* app is 10-20x faster than the wasm one. See: [Note: FFmpeg in Electron].
*/
const ffmpegExec = async (
command: string[],
blob: Blob,
outputFileName: string,
timeoutMs: number = 0,
): Promise<Uint8Array> => {
) => {
const electron = globalThis.electron;
if (electron)
return electron.ffmpegExec(command, blob, outputFileName, timeoutMs);
else
return workerFactory
.lazy()
.then((worker) =>
worker.exec(command, blob, outputFileName, timeoutMs),
);
if (electron) {
const data = new Uint8Array(await blob.arrayBuffer());
return await electron.ffmpegExec(command, data, timeoutMs);
} else {
const worker = await workerFactory.lazy()
return await worker.exec(command, blob, timeoutMs);
}
};
const ffmpegExec2 = async (

View file

@ -237,11 +237,11 @@ export interface Electron {
) => Promise<Uint8Array>;
/**
* Execute a ffmpeg {@link command}.
* Execute a FFmpeg {@link command} on the given {@link dataOrPath}.
*
* This executes the command using the ffmpeg executable we bundle with our
* desktop app. There is also a ffmpeg wasm implementation that we use when
* running on the web, it also has a sibling function with the same
* This executes the command using a FFmpeg executable we bundle with our
* desktop app. We also have a wasm FFmpeg wasm implementation that we use
* when running on the web, which has a sibling function with the same
* parameters. See [Note: ffmpeg in Electron].
*
* @param command An array of strings, each representing one positional
@ -250,25 +250,20 @@ export interface Electron {
* (respectively {@link inputPathPlaceholder},
* {@link outputPathPlaceholder}, {@link ffmpegPathPlaceholder}).
*
* @param inputDataOrPath The bytes of the input file, or the path to the
* input file on the user's local disk. In both cases, the data gets
* serialized to a temporary file, and then that path gets substituted in
* the ffmpeg {@link command} by {@link inputPathPlaceholder}.
*
* @param outputFileName The name of the file we instruct ffmpeg to produce
* when giving it the given {@link command}. The contents of this file get
* returned as the result.
* @param dataOrPath The bytes of the input file, or the path to the input
* file on the user's local disk. In both cases, the data gets serialized to
* a temporary file, and then that path gets substituted in the FFmpeg
* {@link command} in lieu of {@link inputPathPlaceholder}.
*
* @param timeoutMS If non-zero, then abort and throw a timeout error if the
* ffmpeg command takes more than the given number of milliseconds.
*
* @returns The contents of the output file produced by the ffmpeg command
* at {@link outputFileName}.
* (specified as {@link outputPathPlaceholder} in {@link command}).
*/
ffmpegExec: (
command: string[],
inputDataOrPath: Uint8Array | string,
outputFileName: string,
dataOrPath: Uint8Array | string,
timeoutMS: number,
) => Promise<Uint8Array>;