fix: Замена кодека при GPU скейлинге на nv12
fix: Исправлена проблема с звуком и телепортами по частям видео
This commit is contained in:
@@ -282,7 +282,7 @@ console.log(` File: ${input}`);
|
|||||||
console.log(` Size: ${fileSizeMB} MB`);
|
console.log(` Size: ${fileSizeMB} MB`);
|
||||||
console.log(` Resolution: ${metadata.width}x${metadata.height}`);
|
console.log(` Resolution: ${metadata.width}x${metadata.height}`);
|
||||||
console.log(` FPS: ${metadata.fps.toFixed(2)}`);
|
console.log(` FPS: ${metadata.fps.toFixed(2)}`);
|
||||||
console.log(` Duration: ${Math.floor(metadata.duration / 60)}m ${Math.floor(metadata.duration % 60)}s`);
|
console.log(` Duration: ${metadata.duration.toFixed(2)}s`);
|
||||||
console.log(` Codec: ${metadata.codec}`);
|
console.log(` Codec: ${metadata.codec}`);
|
||||||
if (metadata.videoBitrate) {
|
if (metadata.videoBitrate) {
|
||||||
console.log(` Video Bitrate: ${(metadata.videoBitrate / 1000).toFixed(2)} Mbps`);
|
console.log(` Video Bitrate: ${(metadata.videoBitrate / 1000).toFixed(2)} Mbps`);
|
||||||
@@ -313,7 +313,7 @@ if (customProfiles && customProfiles.length > 0) {
|
|||||||
profileResult.warnings.forEach(warn => console.warn(` - ${warn}`));
|
profileResult.warnings.forEach(warn => console.warn(` - ${warn}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
displayProfiles = profileResult.profiles.map(p => p.name);
|
displayProfiles = profileResult.profiles.map(p => p.fps ? `${p.name}@${p.fps}` : p.name);
|
||||||
} else {
|
} else {
|
||||||
const autoProfiles = selectProfiles(
|
const autoProfiles = selectProfiles(
|
||||||
metadata.width,
|
metadata.width,
|
||||||
@@ -321,7 +321,7 @@ if (customProfiles && customProfiles.length > 0) {
|
|||||||
metadata.fps,
|
metadata.fps,
|
||||||
metadata.videoBitrate
|
metadata.videoBitrate
|
||||||
);
|
);
|
||||||
displayProfiles = autoProfiles.map(p => p.name);
|
displayProfiles = autoProfiles.map(p => p.fps ? `${p.name}@${p.fps}` : p.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const manifestDesc = [
|
const manifestDesc = [
|
||||||
|
|||||||
@@ -161,7 +161,8 @@ export async function encodeProfileToMP4(
|
|||||||
const targetWidth = profile.width;
|
const targetWidth = profile.width;
|
||||||
const targetHeight = profile.height;
|
const targetHeight = profile.height;
|
||||||
|
|
||||||
if (decoderAccel === 'nvenc') {
|
const useCudaScale = decoderAccel === 'nvenc';
|
||||||
|
if (useCudaScale) {
|
||||||
// CUDA path: вписываем в профиль с сохранением исходного AR
|
// CUDA path: вписываем в профиль с сохранением исходного AR
|
||||||
filters.push(`scale_cuda=${targetWidth}:${targetHeight}:force_original_aspect_ratio=decrease:force_divisible_by=2`);
|
filters.push(`scale_cuda=${targetWidth}:${targetHeight}:force_original_aspect_ratio=decrease:force_divisible_by=2`);
|
||||||
} else {
|
} else {
|
||||||
@@ -181,24 +182,32 @@ export async function encodeProfileToMP4(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Если использовали GPU-скейл, возвращаем кадры в системную память перед CPU-фильтрами
|
||||||
|
if (useCudaScale) {
|
||||||
|
filters.push('hwdownload', 'format=nv12');
|
||||||
|
}
|
||||||
|
|
||||||
// Центрируем кадр, чтобы браузеры (Firefox/videotoolbox) не игнорировали PAR
|
// Центрируем кадр, чтобы браузеры (Firefox/videotoolbox) не игнорировали PAR
|
||||||
filters.push(
|
filters.push(`pad=${targetWidth}:${targetHeight}:(ow-iw)/2:(oh-ih)/2`, 'setsar=1');
|
||||||
`pad=${targetWidth}:${targetHeight}:(ow-iw)/2:(oh-ih)/2`,
|
|
||||||
'setsar=1'
|
|
||||||
);
|
|
||||||
|
|
||||||
args.push('-vf', filters.join(','));
|
args.push('-vf', filters.join(','));
|
||||||
|
|
||||||
if (!muted) {
|
if (!muted) {
|
||||||
// Audio encoding
|
// Audio encoding с нормализацией таймингов и автоподпаддингом тишиной
|
||||||
const targetAudioBitrate = parseInt(profile.audioBitrate) || 256;
|
const targetAudioBitrate = parseInt(profile.audioBitrate) || 256;
|
||||||
const optimalAudioBitrate = selectAudioBitrate(sourceAudioBitrate, targetAudioBitrate);
|
const optimalAudioBitrate = selectAudioBitrate(sourceAudioBitrate, targetAudioBitrate);
|
||||||
args.push('-c:a', 'aac', '-b:a', optimalAudioBitrate);
|
args.push('-c:a', 'aac', '-b:a', optimalAudioBitrate);
|
||||||
|
|
||||||
// Audio optimizations
|
const targetDur = duration.toFixed(3);
|
||||||
|
const audioFilters: string[] = [
|
||||||
|
'aresample=async=1:min_hard_comp=0.1:first_pts=0',
|
||||||
|
`apad=whole_dur=${targetDur}`,
|
||||||
|
`atrim=0:${targetDur}`
|
||||||
|
];
|
||||||
if (optimizations?.audioNormalize) {
|
if (optimizations?.audioNormalize) {
|
||||||
args.push('-af', 'loudnorm');
|
audioFilters.push('loudnorm');
|
||||||
}
|
}
|
||||||
|
args.push('-af', audioFilters.join(','));
|
||||||
} else {
|
} else {
|
||||||
args.push('-an'); // без аудио дорожки
|
args.push('-an'); // без аудио дорожки
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user