Compare commits
3 Commits
b40ae34387
...
7e3424c0f2
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e3424c0f2 | |||
| 07746c7bd5 | |||
| 0f101df575 |
90
bin/cli.js
90
bin/cli.js
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@gromlab/create-vod",
|
"name": "@gromlab/create-vod",
|
||||||
"author": "Gromov Sergei",
|
"author": "Gromov Sergei",
|
||||||
"version": "0.1.15",
|
"version": "0.1.17",
|
||||||
"description": "DASH/HLS video converter with hardware acceleration (NVENC/QSV/AMF/VAAPI), thumbnails and poster generation",
|
"description": "DASH/HLS video converter with hardware acceleration (NVENC/QSV/AMF/VAAPI), thumbnails and poster generation",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
|
|||||||
@@ -98,6 +98,11 @@ export function selectProfiles(
|
|||||||
sourceBitrate?: number
|
sourceBitrate?: number
|
||||||
): VideoProfile[] {
|
): VideoProfile[] {
|
||||||
const profiles: VideoProfile[] = [];
|
const profiles: VideoProfile[] = [];
|
||||||
|
const aspect = inputWidth / inputHeight;
|
||||||
|
const isNear = (value: number, target: number, eps: number = 0.01) =>
|
||||||
|
Math.abs(value - target) < eps;
|
||||||
|
const isNear16x9 = isNear(aspect, 16 / 9);
|
||||||
|
const isNear4x3 = isNear(aspect, 4 / 3);
|
||||||
|
|
||||||
// Standard 30 FPS profiles (always created)
|
// Standard 30 FPS profiles (always created)
|
||||||
const baseProfiles = DEFAULT_PROFILES.filter(profile => {
|
const baseProfiles = DEFAULT_PROFILES.filter(profile => {
|
||||||
@@ -106,9 +111,21 @@ export function selectProfiles(
|
|||||||
|
|
||||||
// Add standard 30fps profiles with bitrate limit
|
// Add standard 30fps profiles with bitrate limit
|
||||||
for (const profile of baseProfiles) {
|
for (const profile of baseProfiles) {
|
||||||
|
// Сохраняем соотношение сторон: при типовом 16:9 оставляем штатную ширину,
|
||||||
|
// иначе рассчитываем по исходному AR (и делаем ширину чётной)
|
||||||
|
const height = profile.height;
|
||||||
|
let width = profile.width;
|
||||||
|
if (!isNear16x9 && !isNear4x3) {
|
||||||
|
width = Math.round(height * aspect);
|
||||||
|
if (width % 2 !== 0) width -= 1; // чётные для кодека
|
||||||
|
if (width < 2) width = 2;
|
||||||
|
}
|
||||||
|
|
||||||
profiles.push({
|
profiles.push({
|
||||||
...profile,
|
...profile,
|
||||||
videoBitrate: calculateBitrate(profile.width, profile.height, 30, sourceBitrate),
|
width,
|
||||||
|
height,
|
||||||
|
videoBitrate: calculateBitrate(width, height, 30, sourceBitrate),
|
||||||
fps: 30
|
fps: 30
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,10 +163,10 @@ export async function encodeProfileToMP4(
|
|||||||
|
|
||||||
const useCudaScale = decoderAccel === 'nvenc';
|
const useCudaScale = decoderAccel === 'nvenc';
|
||||||
if (useCudaScale) {
|
if (useCudaScale) {
|
||||||
// CUDA path: вписываем в профиль с сохранением исходного AR
|
// CUDA path: keep frames on GPU
|
||||||
filters.push(`scale_cuda=${targetWidth}:${targetHeight}:force_original_aspect_ratio=decrease:force_divisible_by=2`);
|
filters.push(`scale_cuda=${profile.width}:${profile.height}`);
|
||||||
} else {
|
} else {
|
||||||
filters.push(`scale=${targetWidth}:${targetHeight}:force_original_aspect_ratio=decrease:force_divisible_by=2`);
|
filters.push(`scale=${profile.width}:${profile.height}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply optimizations (for future use)
|
// Apply optimizations (for future use)
|
||||||
|
|||||||
Reference in New Issue
Block a user