This commit is contained in:
Manav Rathi 2024-04-25 14:38:08 +05:30
parent c8542211b4
commit 3ac81df561
No known key found for this signature in database
2 changed files with 60 additions and 32 deletions

View file

@ -26,11 +26,11 @@ import { type DedicatedFFmpegWorker } from "worker/ffmpeg.worker";
* See also {@link generateVideoThumbnailNative}.
*/
export const generateVideoThumbnailWeb = async (blob: Blob) =>
generateVideoThumbnail((seekTime: number) =>
ffmpegExecWeb(genThumbnailCommand(seekTime), blob, "jpeg", 0),
_generateVideoThumbnail((seekTime: number) =>
ffmpegExecWeb(makeGenThumbnailCommand(seekTime), blob, "jpeg", 0),
);
const generateVideoThumbnail = async (
const _generateVideoThumbnail = async (
thumbnailAtTime: (seekTime: number) => Promise<Uint8Array>,
) => {
try {
@ -61,16 +61,16 @@ export const generateVideoThumbnailNative = async (
electron: Electron,
dataOrPath: Uint8Array | string,
) =>
generateVideoThumbnail((seekTime: number) =>
_generateVideoThumbnail((seekTime: number) =>
electron.ffmpegExec(
genThumbnailCommand(seekTime),
makeGenThumbnailCommand(seekTime),
dataOrPath,
"jpeg",
0,
),
);
const genThumbnailCommand = (seekTime: number) => [
const makeGenThumbnailCommand = (seekTime: number) => [
ffmpegPathPlaceholder,
"-i",
inputPathPlaceholder,
@ -83,30 +83,58 @@ const genThumbnailCommand = (seekTime: number) => [
outputPathPlaceholder,
];
/** Called during upload */
export async function extractVideoMetadata(file: File | ElectronFile) {
// https://stackoverflow.com/questions/9464617/retrieving-and-saving-media-metadata-using-ffmpeg
// -c [short for codex] copy[(stream_specifier)[ffmpeg.org/ffmpeg.html#Stream-specifiers]] => copies all the stream without re-encoding
// -map_metadata [http://ffmpeg.org/ffmpeg.html#Advanced-options search for map_metadata] => copies all stream metadata to the out
// -f ffmetadata [https://ffmpeg.org/ffmpeg-formats.html#Metadata-1] => dump metadata from media files into a simple UTF-8-encoded INI-like text file
const metadata = await ffmpegExec2(
[
ffmpegPathPlaceholder,
"-i",
inputPathPlaceholder,
"-c",
"copy",
"-map_metadata",
"0",
"-f",
"ffmetadata",
outputPathPlaceholder,
],
file,
"txt",
);
return parseFFmpegExtractedMetadata(metadata);
}
/**
* Extract metadata from the given video
*
* When we're running in the context of our desktop app _and_ we're passed a
* file path , this uses the native FFmpeg bundled with our desktop app.
* Otherwise it uses a wasm FFmpeg running in a web worker.
*
* This function is called during upload, when we need to extract the metadata
* of videos that the user is uploading.
*
* @param fileOrPath 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.
*/
export const extractVideoMetadata = async (
fileOrPath: File | string,
): Promise<ParsedExtractedMetadata> => {
const command = extractVideoMetadataCommand;
const outputData =
fileOrPath instanceof File
? await ffmpegExecWeb(command, fileOrPath, "txt", 0)
: await electron.ffmpegExec(command, fileOrPath, "txt", 0);
return parseFFmpegExtractedMetadata(outputData);
};
// Options:
//
// - `-c [short for codex] copy`
// - copy is the [stream_specifier](ffmpeg.org/ffmpeg.html#Stream-specifiers)
// - copies all the stream without re-encoding
//
// - `-map_metadata`
// - http://ffmpeg.org/ffmpeg.html#Advanced-options (search for map_metadata)
// - copies all stream metadata to the output
//
// - `-f ffmetadata`
// - https://ffmpeg.org/ffmpeg-formats.html#Metadata-1
// - dump metadata from media files into a simple INI-like utf-8 text file
//
const extractVideoMetadataCommand = [
ffmpegPathPlaceholder,
"-i",
inputPathPlaceholder,
"-c",
"copy",
"-map_metadata",
"0",
"-f",
"ffmetadata",
outputPathPlaceholder,
];
enum MetadataTags {
CREATION_TIME = "creation_time",

View file

@ -22,7 +22,7 @@ import {
} from "constants/upload";
import { addToCollection } from "services/collectionService";
import { parseImageMetadata } from "services/exif";
import * as ffmpegService from "services/ffmpeg";
import * as ffmpeg from "services/ffmpeg";
import {
EnteFile,
type FilePublicMagicMetadata,
@ -680,7 +680,7 @@ async function tryExtractImageMetadata(
const tryExtractVideoMetadata = async (fileOrPath: File | string) => {
try {
return await ffmpegService.extractVideoMetadata(fileOrPath);
return await ffmpeg.extractVideoMetadata(fileOrPath);
} catch (e) {
log.error(`Failed to extract video metadata for ${fileOrPath}`, e);
return undefined;