conv
This commit is contained in:
parent
c76b2f0794
commit
3c7c14e11c
3 changed files with 45 additions and 59 deletions
|
@ -114,47 +114,26 @@ const ffmpegBinaryPath = () => {
|
|||
* handle the MP4 conversion of large video files.
|
||||
*
|
||||
* See: [Note: Convert to MP4]
|
||||
*
|
||||
* @param command
|
||||
* @param dataOrPathOrZipItem
|
||||
* @param outputFileExtension
|
||||
* @param timeoutMS
|
||||
* @returns
|
||||
|
||||
* @param inputFilePath The path to a file on the user's local file system. This
|
||||
* is the video we want to convert.
|
||||
* @param inputFilePath The path to a file on the user's local file system where
|
||||
* we should write the converted MP4 video.
|
||||
*/
|
||||
export const ffmpegConvertToMP4 = async (
|
||||
command: string[],
|
||||
dataOrPathOrZipItem: Uint8Array | string | ZipItem,
|
||||
outputFileExtension: string,
|
||||
timeoutMS: number,
|
||||
): Promise<Uint8Array> => {
|
||||
// TODO (MR): This currently copies files for both input (when
|
||||
// dataOrPathOrZipItem is data) and output. This needs to be tested
|
||||
// extremely large video files when invoked downstream of `convertToMP4` in
|
||||
// the web code.
|
||||
inputFilePath: string,
|
||||
outputFilePath: string,
|
||||
): Promise<void> => {
|
||||
const command = [
|
||||
ffmpegPathPlaceholder,
|
||||
"-i",
|
||||
inputPathPlaceholder,
|
||||
"-preset",
|
||||
"ultrafast",
|
||||
outputPathPlaceholder,
|
||||
];
|
||||
|
||||
const {
|
||||
path: inputFilePath,
|
||||
isFileTemporary: isInputFileTemporary,
|
||||
writeToTemporaryFile: writeToTemporaryInputFile,
|
||||
} = await makeFileForDataOrPathOrZipItem(dataOrPathOrZipItem);
|
||||
const cmd = substitutePlaceholders(command, inputFilePath, outputFilePath);
|
||||
|
||||
const outputFilePath = await makeTempFilePath(outputFileExtension);
|
||||
try {
|
||||
await writeToTemporaryInputFile();
|
||||
|
||||
const cmd = substitutePlaceholders(
|
||||
command,
|
||||
inputFilePath,
|
||||
outputFilePath,
|
||||
);
|
||||
|
||||
if (timeoutMS) await withTimeout(execAsync(cmd), timeoutMS);
|
||||
else await execAsync(cmd);
|
||||
|
||||
return fs.readFile(outputFilePath);
|
||||
} finally {
|
||||
if (isInputFileTemporary)
|
||||
await deleteTempFileIgnoringErrors(inputFilePath);
|
||||
await deleteTempFileIgnoringErrors(outputFilePath);
|
||||
}
|
||||
await withTimeout(execAsync(cmd), 30 * 1000);
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@ import { Readable } from "node:stream";
|
|||
import { ReadableStream } from "node:stream/web";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import log from "./log";
|
||||
import { ffmpegConvertToMP4 } from "./services/ffmpeg";
|
||||
import { ensure } from "./utils/common";
|
||||
import {
|
||||
deleteTempFile,
|
||||
|
@ -158,7 +159,7 @@ const handleWrite = async (path: string, request: Request) => {
|
|||
*
|
||||
* The returned promise resolves when the write completes.
|
||||
*
|
||||
* @param filePath The local filesystem path where the file should be written.
|
||||
* @param filePath The local file system path where the file should be written.
|
||||
*
|
||||
* @param readableStream A web
|
||||
* [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream).
|
||||
|
@ -233,9 +234,9 @@ const handleConvertToMP4Write = async (request: Request) => {
|
|||
const inputTempFilePath = await makeTempFilePath();
|
||||
await writeStream(inputTempFilePath, ensure(request.body));
|
||||
|
||||
const outputTempFilePath = await makeTempFilePath();
|
||||
const outputTempFilePath = await makeTempFilePath("mp4");
|
||||
try {
|
||||
//
|
||||
await ffmpegConvertToMP4(inputTempFilePath, outputTempFilePath);
|
||||
} catch (e) {
|
||||
await deleteTempFileIgnoringErrors(inputTempFilePath);
|
||||
await deleteTempFileIgnoringErrors(outputTempFilePath);
|
||||
|
|
|
@ -98,8 +98,8 @@ const makeGenThumbnailCommand = (seekTime: number) => [
|
|||
* of videos that the user is uploading.
|
||||
*
|
||||
* @param uploadItem A {@link File}, or the absolute path to a file on the
|
||||
* user's local filesytem. A path can only be provided when we're running in the
|
||||
* context of our desktop app.
|
||||
* user's local file sytem. A path can only be provided when we're running in
|
||||
* the context of our desktop app.
|
||||
*/
|
||||
export const extractVideoMetadata = async (
|
||||
uploadItem: UploadItem,
|
||||
|
@ -234,22 +234,28 @@ const ffmpegExecWeb = async (
|
|||
*
|
||||
* @param blob The video blob.
|
||||
*
|
||||
* @returns The mp4 video data.
|
||||
* @returns The mp4 video blob.
|
||||
*/
|
||||
export const convertToMP4 = async (blob: Blob) =>
|
||||
ffmpegExecNativeOrWeb(
|
||||
[
|
||||
ffmpegPathPlaceholder,
|
||||
"-i",
|
||||
inputPathPlaceholder,
|
||||
"-preset",
|
||||
"ultrafast",
|
||||
outputPathPlaceholder,
|
||||
],
|
||||
blob,
|
||||
"mp4",
|
||||
30 * 1000,
|
||||
);
|
||||
export const convertToMP4 = async (blob: Blob) => {
|
||||
const electron = globalThis.electron;
|
||||
if (electron) {
|
||||
//
|
||||
} else {
|
||||
return ffmpegExecWeb(
|
||||
[
|
||||
ffmpegPathPlaceholder,
|
||||
"-i",
|
||||
inputPathPlaceholder,
|
||||
"-preset",
|
||||
"ultrafast",
|
||||
outputPathPlaceholder,
|
||||
],
|
||||
blob,
|
||||
"mp4",
|
||||
30 * 1000,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Run the given FFmpeg command using a native FFmpeg binary when we're running
|
||||
|
|
Loading…
Add table
Reference in a new issue