UNPKG

@codenoobforreal/clitools

Version:

CLI tool for video processing (H.265/HEVC encoding & QuickTime compatibility) using FFmpeg, and batch lossless image compression with format preservation

100 lines 3.62 kB
import { FFprobeProcessError, KVError, RequiredFieldError, StringToNumberConvertError, } from "../../error.js"; import { runFFprobeCommand } from "../../libs/ffmpeg-executor.js"; import { tryConvertStringToNumber } from "../../utils/basic-convert.js"; import { FFprobeCommandBuilder } from "../ffmpeg/command-builder.js"; export async function getVideoMetadata(videoPath) { const getVideoMetaDataArgs = buildFFprobeMetadataArgs(videoPath); const { out, err } = await runFFprobeCommand(getVideoMetaDataArgs); // out will be empty string and err will be error message when ffprobe got error if (out === "") { throw new FFprobeProcessError("FFprobe handle error", new Error(err)); } return convertFFprobeResult(out); } // TODO: bit depth: bits_per_raw_sample=N/A export function convertFFprobeResult(result) { const resultObject = {}; const requiredFields = new Set([ "codec_name", "codec_tag_string", "width", "height", "pix_fmt", // "avg_frame_rate", "duration", // "bit_rate", "bits_per_raw_sample", ]); const parseKeyValue = (line) => { const eqIndex = line.indexOf("="); if (eqIndex === -1 || eqIndex === 0) { throw new KVError("Invalid key-value format", line); } return [line.slice(0, eqIndex), line.slice(eqIndex + 1)]; }; const validateNumber = (value, key) => { const num = tryConvertStringToNumber(value); if (!num) { throw new StringToNumberConvertError(`Invalid ${key} value`, value); } return num; }; for (const line of result.split("\n")) { const trimmed = line.trim(); if (!trimmed) continue; const [key, value] = parseKeyValue(trimmed); switch (key) { case "codec_name": case "codec_tag_string": case "pix_fmt": resultObject[key] = value; requiredFields.delete(key); break; case "width": case "height": case "duration": // case "bit_rate": resultObject[key] = validateNumber(value, key); requiredFields.delete(key); break; case "bits_per_raw_sample": { resultObject[key] = tryConvertStringToNumber(value) ?? 8; requiredFields.delete(key); break; // case "avg_frame_rate": // resultObject.avg_frame_rate = calcFFprobeFps(value); // requiredFields.delete("avg_frame_rate"); // break; } } } if (requiredFields.size > 0) { throw new RequiredFieldError("Missing required fields", [ ...requiredFields, ]); } return resultObject; } // special case: 33152000/1105061 export function calcFFprobeFps(fps) { const splits = fps.split("/"); const dividend = splits[0]; const divisor = splits[1]; const rawValue = divisor === "1" ? Number(dividend) : Number(dividend) / Number(divisor); const formatted = rawValue .toFixed(2) .replace(/(\.\d*?[1-9])0+$/, "$1") .replace(/\.$/, ""); return parseFloat(formatted); } export function buildFFprobeMetadataArgs(inputPath) { return new FFprobeCommandBuilder() .setLogLevel() .selectStream() .showEntries() .setOutputFormat("default=noprint_wrappers=1:nokey=0") .setInput(inputPath) .build(); } //# sourceMappingURL=metadata.js.map