"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.canDoQuickAudioTranscode = exports.canDoQuickVideoTranscode = exports.canDoQuickTranscode = exports.getVideoFileBitrate = exports.computeLowerResolutionsToTranscode = exports.getClosestFramerateStandard = exports.ffprobePromise = exports.getVideoFileFPS = exports.computeFPS = exports.getAudioStream = exports.getDurationFromVideoFile = exports.getVideoStreamFromFile = exports.getMaxAudioBitrate = exports.getMetadataFromFile = exports.getVideoFileResolution = exports.getVideoStreamSize = exports.getAudioStreamCodec = exports.getVideoStreamCodec = void 0;
const tslib_1 = require("tslib");
const core_utils_1 = require("../../shared/core-utils");
const config_1 = require("../initializers/config");
const constants_1 = require("../initializers/constants");
const logger_1 = require("./logger");
const ffprobe_1 = require("../../shared/extra-utils/ffprobe");
Object.defineProperty(exports, "canDoQuickAudioTranscode", { enumerable: true, get: function () { return ffprobe_1.canDoQuickAudioTranscode; } });
Object.defineProperty(exports, "ffprobePromise", { enumerable: true, get: function () { return ffprobe_1.ffprobePromise; } });
Object.defineProperty(exports, "getDurationFromVideoFile", { enumerable: true, get: function () { return ffprobe_1.getDurationFromVideoFile; } });
Object.defineProperty(exports, "getAudioStream", { enumerable: true, get: function () { return ffprobe_1.getAudioStream; } });
Object.defineProperty(exports, "getMaxAudioBitrate", { enumerable: true, get: function () { return ffprobe_1.getMaxAudioBitrate; } });
Object.defineProperty(exports, "getMetadataFromFile", { enumerable: true, get: function () { return ffprobe_1.getMetadataFromFile; } });
Object.defineProperty(exports, "getVideoFileBitrate", { enumerable: true, get: function () { return ffprobe_1.getVideoFileBitrate; } });
Object.defineProperty(exports, "getVideoFileFPS", { enumerable: true, get: function () { return ffprobe_1.getVideoFileFPS; } });
Object.defineProperty(exports, "getVideoFileResolution", { enumerable: true, get: function () { return ffprobe_1.getVideoFileResolution; } });
Object.defineProperty(exports, "getVideoStreamFromFile", { enumerable: true, get: function () { return ffprobe_1.getVideoStreamFromFile; } });
Object.defineProperty(exports, "getVideoStreamSize", { enumerable: true, get: function () { return ffprobe_1.getVideoStreamSize; } });
function getVideoStreamCodec(path) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        const videoStream = yield (0, ffprobe_1.getVideoStreamFromFile)(path);
        if (!videoStream)
            return '';
        const videoCodec = videoStream.codec_tag_string;
        if (videoCodec === 'vp09')
            return 'vp09.00.50.08';
        if (videoCodec === 'hev1')
            return 'hev1.1.6.L93.B0';
        const baseProfileMatrix = {
            avc1: {
                High: '6400',
                Main: '4D40',
                Baseline: '42E0'
            },
            av01: {
                High: '1',
                Main: '0',
                Professional: '2'
            }
        };
        let baseProfile = baseProfileMatrix[videoCodec][videoStream.profile];
        if (!baseProfile) {
            logger_1.logger.warn('Cannot get video profile codec of %s.', path, { videoStream });
            baseProfile = baseProfileMatrix[videoCodec]['High'];
        }
        if (videoCodec === 'av01') {
            const level = videoStream.level;
            return `${videoCodec}.${baseProfile}.${level}M.08`;
        }
        let level = videoStream.level.toString(16);
        if (level.length === 1)
            level = `0${level}`;
        return `${videoCodec}.${baseProfile}${level}`;
    });
}
exports.getVideoStreamCodec = getVideoStreamCodec;
function getAudioStreamCodec(path, existingProbe) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        const { audioStream } = yield (0, ffprobe_1.getAudioStream)(path, existingProbe);
        if (!audioStream)
            return '';
        const audioCodecName = audioStream.codec_name;
        if (audioCodecName === 'opus')
            return 'opus';
        if (audioCodecName === 'vorbis')
            return 'vorbis';
        if (audioCodecName === 'aac')
            return 'mp4a.40.2';
        logger_1.logger.warn('Cannot get audio codec of %s.', path, { audioStream });
        return 'mp4a.40.2';
    });
}
exports.getAudioStreamCodec = getAudioStreamCodec;
function computeLowerResolutionsToTranscode(videoFileResolution, type) {
    const configResolutions = type === 'vod'
        ? config_1.CONFIG.TRANSCODING.RESOLUTIONS
        : config_1.CONFIG.LIVE.TRANSCODING.RESOLUTIONS;
    const resolutionsEnabled = [];
    const resolutions = [
        0,
        480,
        360,
        720,
        240,
        144,
        1080,
        1440,
        2160
    ];
    for (const resolution of resolutions) {
        if (configResolutions[resolution + 'p'] === true && videoFileResolution > resolution) {
            resolutionsEnabled.push(resolution);
        }
    }
    return resolutionsEnabled;
}
exports.computeLowerResolutionsToTranscode = computeLowerResolutionsToTranscode;
function canDoQuickTranscode(path) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        if (config_1.CONFIG.TRANSCODING.PROFILE !== 'default')
            return false;
        const probe = yield (0, ffprobe_1.ffprobePromise)(path);
        return (yield canDoQuickVideoTranscode(path, probe)) &&
            (yield (0, ffprobe_1.canDoQuickAudioTranscode)(path, probe));
    });
}
exports.canDoQuickTranscode = canDoQuickTranscode;
function canDoQuickVideoTranscode(path, probe) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        const videoStream = yield (0, ffprobe_1.getVideoStreamFromFile)(path, probe);
        const fps = yield (0, ffprobe_1.getVideoFileFPS)(path, probe);
        const bitRate = yield (0, ffprobe_1.getVideoFileBitrate)(path, probe);
        const resolutionData = yield (0, ffprobe_1.getVideoFileResolution)(path, probe);
        if (!bitRate)
            return false;
        if (videoStream == null)
            return false;
        if (videoStream['codec_name'] !== 'h264')
            return false;
        if (videoStream['pix_fmt'] !== 'yuv420p')
            return false;
        if (fps < constants_1.VIDEO_TRANSCODING_FPS.MIN || fps > constants_1.VIDEO_TRANSCODING_FPS.MAX)
            return false;
        if (bitRate > (0, core_utils_1.getMaxBitrate)(Object.assign(Object.assign({}, resolutionData), { fps })))
            return false;
        return true;
    });
}
exports.canDoQuickVideoTranscode = canDoQuickVideoTranscode;
function getClosestFramerateStandard(fps, type) {
    return constants_1.VIDEO_TRANSCODING_FPS[type].slice(0)
        .sort((a, b) => fps % a - fps % b)[0];
}
exports.getClosestFramerateStandard = getClosestFramerateStandard;
function computeFPS(fpsArg, resolution) {
    let fps = fpsArg;
    if (resolution !== undefined &&
        resolution < constants_1.VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN &&
        fps > constants_1.VIDEO_TRANSCODING_FPS.AVERAGE) {
        fps = getClosestFramerateStandard(fps, 'STANDARD');
    }
    if (fps > constants_1.VIDEO_TRANSCODING_FPS.MAX)
        fps = getClosestFramerateStandard(fps, 'HD_STANDARD');
    if (fps < constants_1.VIDEO_TRANSCODING_FPS.MIN) {
        throw new Error(`Cannot compute FPS because ${fps} is lower than our minimum value ${constants_1.VIDEO_TRANSCODING_FPS.MIN}`);
    }
    return fps;
}
exports.computeFPS = computeFPS;
//# sourceMappingURL=ffprobe-utils.js.map