浏览代码

convert to mp4

Manav Rathi 1 年之前
父节点
当前提交
42b0b6e9bb

+ 6 - 10
web/apps/photos/src/services/download/index.ts

@@ -10,7 +10,7 @@ import { Events, eventBus } from "@ente/shared/events";
 import { isPlaybackPossible } from "@ente/shared/media/video-playback";
 import { isPlaybackPossible } from "@ente/shared/media/video-playback";
 import { Remote } from "comlink";
 import { Remote } from "comlink";
 import isElectron from "is-electron";
 import isElectron from "is-electron";
-import * as ffmpegService from "services/ffmpeg";
+import * as ffmpeg from "services/ffmpeg";
 import { EnteFile } from "types/file";
 import { EnteFile } from "types/file";
 import { generateStreamFromArrayBuffer, getRenderableImage } from "utils/file";
 import { generateStreamFromArrayBuffer, getRenderableImage } from "utils/file";
 import { PhotosDownloadClient } from "./clients/photos";
 import { PhotosDownloadClient } from "./clients/photos";
@@ -610,17 +610,13 @@ async function getPlayableVideo(
             if (!forceConvert && !runOnWeb && !isElectron()) {
             if (!forceConvert && !runOnWeb && !isElectron()) {
                 return null;
                 return null;
             }
             }
-            log.info(
-                `video format not supported, converting it name: ${videoNameTitle}`,
-            );
-            const mp4ConvertedVideo = await ffmpegService.convertToMP4(
-                new File([videoBlob], videoNameTitle),
-            );
-            log.info(`video successfully converted ${videoNameTitle}`);
-            return new Blob([mp4ConvertedVideo]);
+            // TODO(MR): This might not work for very large (~ GB) videos. Test.
+            log.info(`Converting video ${videoNameTitle} to mp4`);
+            const convertedVideoData = await ffmpeg.convertToMP4(videoBlob);
+            return new Blob([convertedVideoData]);
         }
         }
     } catch (e) {
     } catch (e) {
-        log.error("video conversion failed", e);
+        log.error("Video conversion failed", e);
         return null;
         return null;
     }
     }
 }
 }

+ 36 - 56
web/apps/photos/src/services/ffmpeg.ts

@@ -1,4 +1,3 @@
-import { ElectronFile } from "@/next/types/file";
 import type { Electron } from "@/next/types/ipc";
 import type { Electron } from "@/next/types/ipc";
 import { ComlinkWorker } from "@/next/worker/comlink-worker";
 import { ComlinkWorker } from "@/next/worker/comlink-worker";
 import { validateAndGetCreationUnixTimeInMicroSeconds } from "@ente/shared/time";
 import { validateAndGetCreationUnixTimeInMicroSeconds } from "@ente/shared/time";
@@ -200,23 +199,6 @@ function parseCreationTime(creationTime: string) {
     return dateTime;
     return dateTime;
 }
 }
 
 
-/** Called when viewing a file */
-export async function convertToMP4(file: File) {
-    return await ffmpegExec2(
-        [
-            ffmpegPathPlaceholder,
-            "-i",
-            inputPathPlaceholder,
-            "-preset",
-            "ultrafast",
-            outputPathPlaceholder,
-        ],
-        file,
-        "mp4",
-        30 * 1000,
-    );
-}
-
 /**
 /**
  * Run the given FFmpeg command using a wasm FFmpeg running in a web worker.
  * Run the given FFmpeg command using a wasm FFmpeg running in a web worker.
  *
  *
@@ -234,55 +216,53 @@ const ffmpegExecWeb = async (
 };
 };
 
 
 /**
 /**
- * Run the given FFmpeg command using a native FFmpeg binary bundled with our
- * desktop app.
+ * Convert a video from a format that is not supported in the browser to MP4.
+ *
+ * This function is called when the user views a video or a live photo, and we
+ * want to play it back. The idea is to convert it to MP4 which has much more
+ * universal support in browsers.
+ *
+ * @param blob The video blob.
+ *
+ * @returns The mp4 video data.
+ */
+export const convertToMP4 = async (blob: Blob) =>
+    ffmpegExecNativeOrWeb(
+        [
+            ffmpegPathPlaceholder,
+            "-i",
+            inputPathPlaceholder,
+            "-preset",
+            "ultrafast",
+            outputPathPlaceholder,
+        ],
+        blob,
+        "mp4",
+        30 * 1000,
+    );
+
+/**
+ * Run the given FFmpeg command using a native FFmpeg binary when we're running
+ * in the context of our desktop app, otherwise using the browser based wasm
+ * FFmpeg implemenation.
  *
  *
  * See also: {@link ffmpegExecWeb}.
  * See also: {@link ffmpegExecWeb}.
  */
  */
-/*
-TODO(MR): Remove me
-const ffmpegExecNative = async (
-    electron: Electron,
+const ffmpegExecNativeOrWeb = async (
     command: string[],
     command: string[],
     blob: Blob,
     blob: Blob,
-    timeoutMs: number = 0,
-) => {
-    const electron = globalThis.electron;
-    if (electron) {
-        const data = new Uint8Array(await blob.arrayBuffer());
-        return await electron.ffmpegExec(command, data, timeoutMs);
-    } else {
-        const worker = await workerFactory.lazy();
-        return await worker.exec(command, blob, timeoutMs);
-    }
-};
-*/
-
-const ffmpegExec2 = async (
-    command: string[],
-    inputFile: File | ElectronFile,
     outputFileExtension: string,
     outputFileExtension: string,
-    timeoutMS: number = 0,
+    timeoutMs: number,
 ) => {
 ) => {
     const electron = globalThis.electron;
     const electron = globalThis.electron;
-    if (electron || false) {
-        throw new Error("WIP");
-        // return electron.ffmpegExec(
-        //     command,
-        //     /* TODO(MR): ElectronFile changes */
-        //     inputFile as unknown as string,
-        //     outputFileName,
-        //     timeoutMS,
-        // );
-    } else {
-        /* TODO(MR): ElectronFile changes */
-        return ffmpegExecWeb(
+    if (electron)
+        return electron.ffmpegExec(
             command,
             command,
-            inputFile as File,
+            new Uint8Array(await blob.arrayBuffer()),
             outputFileExtension,
             outputFileExtension,
-            timeoutMS,
+            timeoutMs,
         );
         );
-    }
+    else return ffmpegExecWeb(command, blob, outputFileExtension, timeoutMs);
 };
 };
 
 
 /** Lazily create a singleton instance of our worker */
 /** Lazily create a singleton instance of our worker */

+ 1 - 1
web/packages/shared/hooks/useFileInput.tsx

@@ -1,6 +1,6 @@
 import { useCallback, useRef, useState } from "react";
 import { useCallback, useRef, useState } from "react";
 
 
-/*
+/**
  * TODO (MR): Understand how this is happening, and validate it further (on
  * TODO (MR): Understand how this is happening, and validate it further (on
  * first glance this is correct).
  * first glance this is correct).
  *
  *