Dimensions
This commit is contained in:
@@ -246,7 +246,7 @@ const handleConvertToMP4Write = async (request: Request) => {
|
||||
|
||||
const token = randomUUID();
|
||||
pendingVideoResults.set(token, outputTempFilePath);
|
||||
return new Response(JSON.stringify([token]), { status: 200 });
|
||||
return new Response(token, { status: 200 });
|
||||
};
|
||||
|
||||
const handleVideoRead = async (token: string) => {
|
||||
@@ -277,17 +277,17 @@ const handleVideoDone = async (token: string) => {
|
||||
* The difference here is that we the conversion generates two streams - one for
|
||||
* the HLS playlist itself, and one for the file containing the encrypted and
|
||||
* transcoded video chunks. So instead of returning a single token, we return a
|
||||
* JSON array containing two tokens so that the renderer can read them off
|
||||
* separately.
|
||||
* JSON object containing two tokens (aand other metadata) so that the renderer
|
||||
* can read them off separately.
|
||||
*/
|
||||
const handleGenerateHLSWrite = async (request: Request) => {
|
||||
const inputTempFilePath = await makeTempFilePath();
|
||||
await writeStream(inputTempFilePath, request.body!);
|
||||
|
||||
const outputFilePathPrefix = await makeTempFilePath();
|
||||
let paths: FFmpegGenerateHLSPlaylistAndSegmentsResult;
|
||||
let result: FFmpegGenerateHLSPlaylistAndSegmentsResult;
|
||||
try {
|
||||
paths = await ffmpegGenerateHLSPlaylistAndSegments(
|
||||
result = await ffmpegGenerateHLSPlaylistAndSegments(
|
||||
inputTempFilePath,
|
||||
outputFilePathPrefix,
|
||||
);
|
||||
@@ -297,9 +297,12 @@ const handleGenerateHLSWrite = async (request: Request) => {
|
||||
|
||||
const playlistToken = randomUUID();
|
||||
const videoToken = randomUUID();
|
||||
pendingVideoResults.set(playlistToken, paths.playlistPath);
|
||||
pendingVideoResults.set(videoToken, paths.videoPath);
|
||||
return new Response(JSON.stringify([playlistToken, videoToken]), {
|
||||
status: 200,
|
||||
});
|
||||
pendingVideoResults.set(playlistToken, result.playlistPath);
|
||||
pendingVideoResults.set(videoToken, result.videoPath);
|
||||
|
||||
const { dimensions } = result;
|
||||
return new Response(
|
||||
JSON.stringify({ playlistToken, videoToken, dimensions }),
|
||||
{ status: 200 },
|
||||
);
|
||||
};
|
||||
|
||||
@@ -266,8 +266,8 @@ export const convertToMP4 = async (blob: Blob): Promise<Blob | Uint8Array> => {
|
||||
};
|
||||
|
||||
const convertToMP4Native = async (electron: Electron, blob: Blob) => {
|
||||
const tokens = await writeVideoStream(electron, "convert-to-mp4", blob);
|
||||
const token = tokens[0]!;
|
||||
const res = await writeVideoStream(electron, "convert-to-mp4", blob);
|
||||
const token = await res.text();
|
||||
const mp4Blob = await readVideoStream(electron, token).then((res) =>
|
||||
res.blob(),
|
||||
);
|
||||
|
||||
@@ -13,6 +13,7 @@ import { gunzip, gzip } from "ente-new/photos/utils/gzip";
|
||||
import { ensurePrecondition } from "ente-utils/ensure";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
GenerateHLSResult,
|
||||
readVideoStream,
|
||||
videoStreamDone,
|
||||
writeVideoStream,
|
||||
@@ -399,11 +400,13 @@ const processQueueItem = async (
|
||||
) => {
|
||||
log.debug(() => ["gen-hls", { file, uploadItem }]);
|
||||
|
||||
// TODO(HLS):
|
||||
const fileBlob = await fetchOriginalVideoBlob(file, uploadItem);
|
||||
|
||||
// TODO(HLS):
|
||||
const tokens = await writeVideoStream(electron, "generate-hls", fileBlob!);
|
||||
const [playlistToken, videoToken] = [tokens[0]!, tokens[1]!];
|
||||
const res = await writeVideoStream(electron, "generate-hls", fileBlob!);
|
||||
const { playlistToken, videoToken, dimensions } = GenerateHLSResult.parse(
|
||||
await res.json(),
|
||||
);
|
||||
|
||||
try {
|
||||
const playlistBlob = await readVideoStream(
|
||||
@@ -431,10 +434,7 @@ const processQueueItem = async (
|
||||
const playlistData = await encodePlaylistJSON({
|
||||
type: "hls_video",
|
||||
playlist: await playlistBlob.text(),
|
||||
// TODO(HLS): Critical, fix this before any use.
|
||||
width: 1280,
|
||||
// TODO(HLS): Critical, fix this before any use.
|
||||
height: 720,
|
||||
...dimensions,
|
||||
size: objectSize,
|
||||
});
|
||||
|
||||
|
||||
@@ -128,6 +128,27 @@ export const writeStream = async (
|
||||
*/
|
||||
type VideoStreamOp = "convert-to-mp4" | "generate-hls";
|
||||
|
||||
/**
|
||||
* The contents of the {@link Response} body returned by
|
||||
* {@link writeVideoStream} for op "generate-hls".
|
||||
*/
|
||||
export const GenerateHLSResult = z.object({
|
||||
/**
|
||||
* A token that can be used to passed to {@link readVideoStream} to retrieve
|
||||
* the generated HLS playlist.
|
||||
*/
|
||||
playlistToken: z.string(),
|
||||
/**
|
||||
* A token that can be used to passed to {@link readVideoStream} to retrieve
|
||||
* the video segments.
|
||||
*/
|
||||
videoToken: z.string(),
|
||||
/**
|
||||
* The dimensions (width and height in pixels) of the generated video stream.
|
||||
*/
|
||||
dimensions: z.object({ width: z.number(), height: z.number() }),
|
||||
});
|
||||
|
||||
/**
|
||||
* Variant of {@link writeStream} tailored for video processing operations.
|
||||
*
|
||||
@@ -138,22 +159,23 @@ type VideoStreamOp = "convert-to-mp4" | "generate-hls";
|
||||
* @param video The video to convert, as a {@link Blob} or a
|
||||
* {@link ReadableStream}.
|
||||
*
|
||||
* @returns an array of token that can then be passed to {@link readVideoStream}
|
||||
* to read back the processed video. The count (and semantics) of the tokens are
|
||||
* @returns the successful (2xx) HTTP response received from the node side (An
|
||||
* exception is thrown otherwise). The contents of the response body are
|
||||
* dependent on the operation:
|
||||
*
|
||||
* - "convert-to-mp4" returns a single token (which can be used to retrieve the
|
||||
* converted MP4 file).
|
||||
* - "convert-to-mp4" returns a plain string which is a token that can then be
|
||||
* passed to {@link readVideoStream} to retrieve the converted MP4 file.
|
||||
*
|
||||
* - "generate-hls" returns two tokens, first one that can be used to retrieve
|
||||
* the generated HLS playlist, and the second one that can be used to retrieve
|
||||
* the video (segments).
|
||||
* the video (segments). It also returns the dimensions of the generated
|
||||
* video. See {@link GenerateHLSResult}.
|
||||
*/
|
||||
export const writeVideoStream = async (
|
||||
_: Electron,
|
||||
op: VideoStreamOp,
|
||||
video: Blob | ReadableStream,
|
||||
): Promise<string[]> => {
|
||||
): Promise<Response> => {
|
||||
const url = `stream://video?op=${op}`;
|
||||
|
||||
const req = new Request(url, {
|
||||
@@ -169,7 +191,7 @@ export const writeVideoStream = async (
|
||||
if (!res.ok)
|
||||
throw new Error(`Failed to write stream to ${url}: HTTP ${res.status}`);
|
||||
|
||||
return z.array(z.string()).parse(await res.json());
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user