From 97bc768092fa89635f9ac4bbab99d82ff6c82a08 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 17 Apr 2025 11:43:58 +0530 Subject: [PATCH] Sketch --- desktop/src/main/services/ffmpeg.ts | 2 - desktop/src/main/stream.ts | 8 ++- web/packages/gallery/services/ffmpeg/index.ts | 12 ++--- web/packages/gallery/services/video.ts | 18 +++---- web/packages/gallery/utils/native-stream.ts | 50 +++++++++++++------ 5 files changed, 54 insertions(+), 36 deletions(-) diff --git a/desktop/src/main/services/ffmpeg.ts b/desktop/src/main/services/ffmpeg.ts index 19e3f2a935..3252f3f445 100644 --- a/desktop/src/main/services/ffmpeg.ts +++ b/desktop/src/main/services/ffmpeg.ts @@ -106,8 +106,6 @@ const ffmpegBinaryPath = () => { * A variant of {@link ffmpegExec} adapted to work with streams so that it can * handle the MP4 conversion of large video files. * - * See: [Note: Convert to MP4] - * @param inputFilePath The path to a file on the user's local file system. This * is the video we want to convert. * diff --git a/desktop/src/main/stream.ts b/desktop/src/main/stream.ts index 9c23b49630..8421de0a25 100644 --- a/desktop/src/main/stream.ts +++ b/desktop/src/main/stream.ts @@ -68,9 +68,15 @@ const handleStreamRequest = async (request: Request): Promise => { case "write": return handleWrite(ensure(searchParams.get("path")), request); - case "convert-to-mp4": { + case "video": { const token = searchParams.get("token"); const done = searchParams.get("done") !== null; + const op = searchParams.get("op"); + + if (op && op != "convert-to-mp4") { + return new Response("", { status: 404 }); + } + return token ? done ? handleConvertToMP4ReadDone(token) diff --git a/web/packages/gallery/services/ffmpeg/index.ts b/web/packages/gallery/services/ffmpeg/index.ts index 08a380566b..1c8a08038d 100644 --- a/web/packages/gallery/services/ffmpeg/index.ts +++ b/web/packages/gallery/services/ffmpeg/index.ts @@ -7,9 +7,9 @@ import { type UploadItem, } from "ente-gallery/services/upload"; import { - readConvertToMP4Done, - readConvertToMP4Stream, - writeConvertToMP4Stream, + readVideoStream, + videoStreamDone, + writeVideoStream, } from "ente-gallery/utils/native-stream"; import { parseMetadataDate, @@ -266,8 +266,8 @@ export const convertToMP4 = async (blob: Blob): Promise => { }; const convertToMP4Native = async (electron: Electron, blob: Blob) => { - const token = await writeConvertToMP4Stream(electron, blob); - const mp4Blob = await readConvertToMP4Stream(electron, token); - await readConvertToMP4Done(electron, token); + const token = await writeVideoStream(electron, "convert-to-mp4", blob); + const mp4Blob = await readVideoStream(electron, token); + await videoStreamDone(electron, token); return mp4Blob; }; diff --git a/web/packages/gallery/services/video.ts b/web/packages/gallery/services/video.ts index 8f1fd9babd..88c4845004 100644 --- a/web/packages/gallery/services/video.ts +++ b/web/packages/gallery/services/video.ts @@ -10,7 +10,6 @@ import { gunzip } from "ente-new/photos/utils/gzip"; import { ensurePrecondition } from "ente-utils/ensure"; import { z } from "zod"; import { downloadManager } from "./download"; -import { generateVideoPreviewVariantWeb } from "./ffmpeg"; import { fetchFileData, fetchFilePreviewData } from "./file-data"; import type { UploadItem } from "./upload"; @@ -381,16 +380,13 @@ const processQueueItem = async ( log.debug(() => ["gen-hls", { file, uploadItem }]); const fileBlob = await fetchOriginalVideoBlob(file, uploadItem); - const previewFileData = await generateVideoPreviewVariantWeb(fileBlob); - const convertToMP4Native = async (electron: Electron, blob: Blob) => { - const token = await writeConvertToMP4Stream(electron, blob); - const mp4Blob = await readConvertToMP4Stream(electron, token); - await readConvertToMP4Done(electron, token); - return mp4Blob; - }; + // const token = await writeConvertToMP4Stream(electron, blob); + // const mp4Blob = await readConvertToMP4Stream(electron, token); + // await readConvertToMP4Done(electron, token); + // return mp4Blob; - console.log(previewFileData); + console.log(electron, fileBlob); await Promise.resolve(0); }; @@ -410,10 +406,10 @@ const processQueueItem = async ( const fetchOriginalVideoBlob = async ( file: EnteFile, uploadItem: UploadItem | undefined, -): Promise => +): Promise => uploadItem ? fetchOriginalVideoUploadItemBlob(file, uploadItem) - : await downloadManager.fileBlob(file); + : await downloadManager.fileStream(file); const fetchOriginalVideoUploadItemBlob = ( _: EnteFile, diff --git a/web/packages/gallery/utils/native-stream.ts b/web/packages/gallery/utils/native-stream.ts index ffee090ac5..aa82353d07 100644 --- a/web/packages/gallery/utils/native-stream.ts +++ b/web/packages/gallery/utils/native-stream.ts @@ -118,19 +118,38 @@ export const writeStream = async ( }; /** - * Variant of {@link writeStream} tailored for video conversion. + * One of the predefined operations to perform when invoking + * {@link writeVideoStream} or {@link readVideoStream}. * - * @param blob The video to convert. + * - "convert-to-mp4" (See: [Note: Convert to MP4]) * - * @returns a token that can then be passed to {@link readConvertToMP4Stream} to - * read back the converted video. See: [Note: Convert to MP4]. + * - "generate-hls" (See: [Note: Preview variant of videos]) */ -export const writeConvertToMP4Stream = async (_: Electron, blob: Blob) => { - const url = "stream://convert-to-mp4"; +type VideoStreamOp = "convert-to-mp4" | "generate-hls"; + +/** + * Variant of {@link writeStream} tailored for video processing operations. + * + * @param op The operation to perform on this video (the result can then be + * later read back in via {@link readVideoStream}, and the sequence ended by + * using {@link videoStreamDone}). + * + * @param video The video to convert, as a {@link Blob} or a + * {@link ReadableStream}. + * + * @returns a token that can then be passed to {@link readVideoStream} to read + * back the processed video. + */ +export const writeVideoStream = async ( + _: Electron, + op: VideoStreamOp, + video: Blob | ReadableStream, +) => { + const url = `stream://video?op=${op}`; const req = new Request(url, { method: "POST", - body: blob, + body: video, // @ts-expect-error TypeScript's libdom.d.ts does not include the // "duplex" parameter, e.g. see // https://github.com/node-fetch/node-fetch/issues/1769. @@ -148,16 +167,16 @@ export const writeConvertToMP4Stream = async (_: Electron, blob: Blob) => { /** * Variant of {@link readStream} tailored for video conversion. * - * @param token A token obtained from {@link writeConvertToMP4Stream}. + * @param token A token obtained from {@link writeVideoStream}. * - * @returns the contents of the converted video. See: [Note: Convert to MP4]. + * @returns the contents of the processed video. */ -export const readConvertToMP4Stream = async ( +export const readVideoStream = async ( _: Electron, token: string, ): Promise => { const params = new URLSearchParams({ token }); - const url = new URL(`stream://convert-to-mp4?${params.toString()}`); + const url = new URL(`stream://video?${params.toString()}`); const req = new Request(url, { method: "GET" }); @@ -172,18 +191,17 @@ export const readConvertToMP4Stream = async ( /** * Sibling of {@link readConvertToMP4Stream} to let the native side know when we - * are done reading the response, and they can dispose any temporary resources - * it was using. + * are done reading the response, so it can dispose any temporary resources. * - * @param token A token obtained from {@link writeConvertToMP4Stream}. + * @param token A token obtained from {@link writeVideoStream}. */ -export const readConvertToMP4Done = async ( +export const videoStreamDone = async ( _: Electron, token: string, ): Promise => { // The value for `done` is arbitrary, only its presence matters. const params = new URLSearchParams({ token, done: "1" }); - const url = new URL(`stream://convert-to-mp4?${params.toString()}`); + const url = new URL(`stream://video?${params.toString()}`); const req = new Request(url, { method: "GET" }); const res = await fetch(req);