This commit is contained in:
Manav Rathi
2025-04-17 11:43:58 +05:30
parent cdb81c621d
commit 97bc768092
5 changed files with 54 additions and 36 deletions

View File

@@ -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.
*

View File

@@ -68,9 +68,15 @@ const handleStreamRequest = async (request: Request): Promise<Response> => {
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)

View File

@@ -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<Blob | Uint8Array> => {
};
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;
};

View File

@@ -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<Blob> =>
): Promise<Blob | ReadableStream | null> =>
uploadItem
? fetchOriginalVideoUploadItemBlob(file, uploadItem)
: await downloadManager.fileBlob(file);
: await downloadManager.fileStream(file);
const fetchOriginalVideoUploadItemBlob = (
_: EnteFile,

View File

@@ -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<Blob> => {
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<void> => {
// 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);