h264-to-h265/index.js

94 lines
3.5 KiB
JavaScript
Raw Normal View History

2022-11-06 19:48:32 +08:00
const fs = require('fs-extra');
const path = require('path');
const cmd = require('child_process');
2022-11-07 10:53:55 +08:00
const hardTypeSet = new Set("none", "qsv", "cuda");
const supportVideoTypeSet = new Set("mkv", "mp4");
2022-11-06 19:48:32 +08:00
2022-11-07 10:53:55 +08:00
/**
*
* @param {*} basePath 处理路径
* @param {int} maxBitRate 最大码率,默认2500
* @param {boolean} changeName 是否改名true会将h264x264变更为h265,或者在文件结尾插入h265,其他名称相同额文件也会处理
* @param {*} hardType 硬件加速类型/none不使用加速qsv:使用intel核显qsv加速cuda:使用nvdia cuda加速
* @returns
*/
async function deal (basePath, maxBitRate = 2500, changeName = false, hardType) {
let hwType = hardType == 'qsv' ? "-hwaccel qsv" : hardType == 'cuda' ? "-hwaccel cuda" : "";
let decodeType = hardType == 'qsv' ? "-c:v h264_qsv" : hardType == 'cuda' ? "-c:v hevc_qsv" : "";
let encodeType = hardType == 'qsv' ? "-c:v h264_cuvid" : hardType == 'cuda' ? "-c:v hevc_nvenc" : "";
if (!hardType && !hardTypeSet.has(hardType)) {
throw new Error("不支持的加速方案:" + hardType + ",仅支持:空," + JSON.stringify(hardTypeSet));
}
2022-11-06 19:48:32 +08:00
let fileList = fs.readdirSync(basePath);
for (let i in fileList) {
let name = fileList[i];
2022-11-07 10:53:55 +08:00
let filePath = path.join(basePath, name);
if (fs.statSync(filePath).isDirectory) {
//如果为文件夹递归处理
deal(filePath, maxBitRate, hardType);
}
if (!supportVideoTypeSet.has(name.substring(name.lastIndexOf(".") + 1))) {
2022-11-06 19:48:32 +08:00
continue;
}
console.log("---------开始处理:" + name);
let res = JSON.parse(cmd.execSync(`ffprobe.exe "${filePath}" -show_streams -select_streams v -show_format -print_format json`, { encoding: 'utf-8' }));
if (!res.format || !res.streams || res.streams.length == 0) {
console.log("无法识别的格式:" + JSON.stringify(res));
continue;
}
let isH264 = res.streams.filter(item => item.codec_name === 'h264').length > 0;
if (!isH264) {
console.log("非h264,不处理");
continue;
}
let bitRate = res.format.bit_rate;
if (!bitRate) {
console.log("未获取到帧率,不处理", JSON.stringify(res));
continue;
}
bitRate = Math.round(parseInt(bitRate) / 1000);
2022-11-07 10:53:55 +08:00
bitRate = bitRate > maxBitRate ? maxBitRate : bitRate;
2022-11-06 19:48:32 +08:00
let newName;
if (name.indexOf("h264") > -1) {
newName = name.replace('h264', 'h265');
} else if (name.indexOf('H264') > -1) {
newName = name.replace('H264', 'H265');
} else {
let index = name.lastIndexOf('.');
newName = name.substr(0, index) + ".h265" + name.substr(index);
}
2022-11-06 19:50:51 +08:00
let newFilePath = path.join(basePath, newName);
2022-11-07 10:53:55 +08:00
let cmdStr = `ffmpeg.exe ${hwType} ${decodeType} -i "${filePath}" ${encodeType} -maxrate ${bitRate}K -c:a copy "${newFilePath}"`;
2022-11-06 19:48:32 +08:00
console.log(cmdStr);
let changeRes = cmd.execSync(cmdStr, { encoding: 'utf-8' });
console.log(changeRes);
2022-11-06 19:50:51 +08:00
if (!fs.existsSync(newFilePath)) {
console.log("未知错误,文件转换失败");
return;
}
2022-11-07 10:53:55 +08:00
if (changeName) {
//字幕nfo文件重命名
let namePart1 = name.substr(0, name.lastIndexOf('.'));
let newNamePart1 = newName.substr(0, newName.lastIndexOf('.'));
fileList.forEach(item => {
if (item.startsWith(namePart1) && (item.endsWith('.nfo') || item.endsWith('.srt') || item.endsWith('.ass'))) {
let temp = item.replace(namePart1, newNamePart1);
if (item != temp) {
fs.renameSync(path.join(basePath, item), path.join(basePath, temp));
}
2022-11-06 19:48:32 +08:00
}
2022-11-07 10:53:55 +08:00
})
}
2022-11-06 19:48:32 +08:00
fs.removeSync(filePath);
2022-11-07 10:53:55 +08:00
if (!changeName) {
fs.moveSync(newFilePath, filePath);
}
2022-11-06 19:48:32 +08:00
}
}
(async () => {
2022-11-07 10:53:55 +08:00
await deal("要处理的文件夹", 2500, true, "cuda");
2022-11-06 19:48:32 +08:00
})();