"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.canDoQuickAudioTranscode = exports.canDoQuickVideoTranscode = exports.canDoQuickTranscode = exports.computeResolutionsToTranscode = exports.getClosestFramerateStandard = exports.computeFPS = exports.getAudioStreamCodec = exports.getVideoStreamCodec = exports.getVideoStreamBitrate = exports.ffprobePromise = exports.getVideoStreamFPS = exports.hasAudioStream = exports.getAudioStream = exports.getVideoStreamDuration = exports.getVideoStream = exports.getMaxAudioBitrate = exports.buildFileMetadata = exports.getVideoStreamDimensionsInfo = void 0;
const tslib_1 = require("tslib");
const core_utils_1 = require("../../../shared/core-utils");
const ffprobe_1 = require("../../../shared/extra-utils/ffprobe");
Object.defineProperty(exports, "buildFileMetadata", { enumerable: true, get: function () { return ffprobe_1.buildFileMetadata; } });
Object.defineProperty(exports, "ffprobePromise", { enumerable: true, get: function () { return ffprobe_1.ffprobePromise; } });
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, "getVideoStream", { enumerable: true, get: function () { return ffprobe_1.getVideoStream; } });
Object.defineProperty(exports, "getVideoStreamBitrate", { enumerable: true, get: function () { return ffprobe_1.getVideoStreamBitrate; } });
Object.defineProperty(exports, "getVideoStreamDimensionsInfo", { enumerable: true, get: function () { return ffprobe_1.getVideoStreamDimensionsInfo; } });
Object.defineProperty(exports, "getVideoStreamDuration", { enumerable: true, get: function () { return ffprobe_1.getVideoStreamDuration; } });
Object.defineProperty(exports, "getVideoStreamFPS", { enumerable: true, get: function () { return ffprobe_1.getVideoStreamFPS; } });
Object.defineProperty(exports, "hasAudioStream", { enumerable: true, get: function () { return ffprobe_1.hasAudioStream; } });
const config_1 = require("../../initializers/config");
const constants_1 = require("../../initializers/constants");
const core_utils_2 = require("../core-utils");
const logger_1 = require("../logger");
function getVideoStreamCodec(path) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const videoStream = yield (0, ffprobe_1.getVideoStream)(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') {
            let level = videoStream.level.toString();
            if (level.length === 1)
                level = `0${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 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';
        if (audioCodecName === 'mp3')
            return 'mp4a.40.34';
        logger_1.logger.warn('Cannot get audio codec of %s.', path, { audioStream });
        return 'mp4a.40.2';
    });
}
exports.getAudioStreamCodec = getAudioStreamCodec;
function computeResolutionsToTranscode(options) {
    const { input, type, includeInput, strictLower, hasAudio } = options;
    const configResolutions = type === 'vod'
        ? config_1.CONFIG.TRANSCODING.RESOLUTIONS
        : config_1.CONFIG.LIVE.TRANSCODING.RESOLUTIONS;
    const resolutionsEnabled = new Set();
    const availableResolutions = [
        0,
        480,
        360,
        720,
        240,
        144,
        1080,
        1440,
        2160
    ];
    for (const resolution of availableResolutions) {
        if (configResolutions[resolution + 'p'] !== true)
            continue;
        if (input < resolution)
            continue;
        if (strictLower && input === resolution)
            continue;
        if (resolution === 0 && !hasAudio)
            continue;
        resolutionsEnabled.add(resolution);
    }
    if (includeInput) {
        resolutionsEnabled.add((0, core_utils_2.toEven)(input));
    }
    return Array.from(resolutionsEnabled);
}
exports.computeResolutionsToTranscode = computeResolutionsToTranscode;
function canDoQuickTranscode(path) {
    return 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 canDoQuickAudioTranscode(path, probe));
    });
}
exports.canDoQuickTranscode = canDoQuickTranscode;
function canDoQuickAudioTranscode(path, probe) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const parsedAudio = yield (0, ffprobe_1.getAudioStream)(path, probe);
        if (!parsedAudio.audioStream)
            return true;
        if (parsedAudio.audioStream['codec_name'] !== 'aac')
            return false;
        const audioBitrate = parsedAudio.bitrate;
        if (!audioBitrate)
            return false;
        const maxAudioBitrate = (0, ffprobe_1.getMaxAudioBitrate)('aac', audioBitrate);
        if (maxAudioBitrate !== -1 && audioBitrate > maxAudioBitrate)
            return false;
        const channelLayout = parsedAudio.audioStream['channel_layout'];
        if (!channelLayout || channelLayout === 'unknown' || channelLayout === 'quad')
            return false;
        return true;
    });
}
exports.canDoQuickAudioTranscode = canDoQuickAudioTranscode;
function canDoQuickVideoTranscode(path, probe) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const videoStream = yield (0, ffprobe_1.getVideoStream)(path, probe);
        const fps = yield (0, ffprobe_1.getVideoStreamFPS)(path, probe);
        const bitRate = yield (0, ffprobe_1.getVideoStreamBitrate)(path, probe);
        const resolutionData = yield (0, ffprobe_1.getVideoStreamDimensionsInfo)(path, probe);
        if (!bitRate)
            return false;
        if (!videoStream)
            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