Sketch
This commit is contained in:
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user