Skip to content

Commit

Permalink
优化
Browse files Browse the repository at this point in the history
  • Loading branch information
luohao committed Jan 15, 2021
1 parent bcda1ee commit 0a220e9
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 287 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,5 @@ dist

# TernJS port file
.tern-port

src/doc/video/
277 changes: 2 additions & 275 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,276 +1,3 @@
const { PPT2video } = require('./src/ppt2pdf.js');
const path = require('path');
const fs = require('fs');
const { spawnAsync, execAsync } = require('./src/lib.js');
const { PPT2video} = require('./src/ppt2pdf.js');

// const ppt2video = new PPT2video({
// pptPath: path.resolve('./src/doc/test.pptx')
// });
// const a = fs.statSync(path.resolve('./src/doc/audio/tip.mp3'));
// console.log(a);
const audioPath = path.resolve('./src/doc/audio/tip1.mp3');
// getDuration();
// ffprobe -v quiet -print_format json -show_format E:\work\bnu\code\ppt2video\src\doc\audio\tip1.mp3
// ffprobe -v quiet -print_format json -show_format=duration E:\work\bnu\code\ppt2video\src\doc\audio\tip1.mp3
// ffprobe E:\work\bnu\code\ppt2video\src\doc\audio\tip1.mp3
function getTransitionType(type) {
// 变换效果
const transitions = [
"fade" ,
"wipeleft" ,
"wiperight" ,
"wipeup" ,
"wipedown" ,
"slideleft" ,
"slideright" ,
"slideup" ,
"slidedown" ,
"circlecrop" ,
"rectcrop" ,
"distance" ,
"fadeblack" ,
"fadewhite" ,
"radial" ,
"smoothleft" ,
"smoothright" ,
"smoothup" ,
"smoothdown" ,
"circleopen" ,
"circleclose" ,
"vertopen" ,
"vertclose" ,
"horzopen" ,
"horzclose" ,
"dissolve" ,
"pixelize" ,
"diagtl" ,
"diagtr" ,
"diagbl" ,
"diagbr" ,
];
if (type && transitions.includes(type)) return type;
const random = Math.floor(Math.random() * 31);
return transitions[random];
}
function getSlideVideos() {
return new Promise(async (resolve, reject) => {
try {
const imgFolder = path.resolve('./src/doc/img');
const audioFolder = path.resolve('./src/doc/audio');
const imgList = fs.readdirSync(imgFolder);
const audioList = fs.readdirSync(audioFolder);
for (let i = 0; i < imgList.length; i++) {
console.log(`转换第${i}个`);
const imgPath = path.join(imgFolder, imgList[i]);
/**audio TODO//////////////////////////////////////// */
const audioPath = path.join(audioFolder, audioList[i]);
// const audioPath = audioList[i];
/**audio TODO//////////////////////////////////////// */
await img2video(imgPath, audioPath);
}
resolve();
} catch(err) {
console.log('errrrrrr', err);
reject(err);
}
});
}
function img2video(imgPath, audioPath) {
return new Promise(async (resolve, reject) => {
// ffmpeg -hide_banner -loglevel quiet -loop 1 -i 1.PNG -i tip1.mp3 -c:v libx264 -c:a copy -t 5 -pix_fmt yuv420p -y 1.mp4
try {
// tip:拼接命令时加空格,放在前一条的末尾处
let cmd = `ffmpeg -hide_banner -loop 1 -i ${imgPath} `;
let duration = 0;
// 有对应音频时,添加该音频,视频时长为音频时长
if (existPath(audioPath)) {
duration = await getDuration(audioPath);
cmd += `-i ${audioPath} -c:a copy `;
} else {
duration = 5;
cmd += '-f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100 ';
}
cmd += `-c:v libx264 -s 1920x1080 -pix_fmt yuv420p -t ${duration} -y `;
const videoName = path.basename(imgPath, path.extname(imgPath)) + '.mp4';
cmd += path.join(process.cwd(), videoName);
// 执行ffmpeg命令
await spawnAsync(cmd);
resolve();
} catch(err) {
return reject(err);
}
});
}
function existPath(path) {
try {
return fs.existsSync(path);
} catch(err) {
return false;
}
}
function getDuration(audioPath) {
return new Promise((resolve, reject) => {
// spawnAsync('ffmpeg', ['-hide_banner', '-i', audioPath]).then(data => {
// console.log(data.match(/^Duration: ([\d|:|\.]+),$/));
// }).catch(err => {
// console.log(err.match(/Duration: ([\d|:|\.]+),/));
// });
const cmd = `ffprobe -v quiet -print_format json -show_format ${audioPath}`;
spawnAsync(cmd).then(data => {
const time = JSON.parse(data).format.duration;
resolve(parseFloat(time));
}).catch(err => {
reject(err);
});
});
}

// 过滤videoFolder中非video文件
// -filter_complex_script 对应表达式
function createFilterScript(videoFolder, animate=false, animateDuration=1) {
return new Promise((resolve, reject) => {
let scriptText = '';
try {
const videoList = fs.readdirSync(videoFolder).filter(v => path.extname(v) === '.mp4');
if (!animate) {
// 没有转场动画,直接拼接
scriptText += videoList.map((v, i) => `[${i}:v][${i}:a]`).join('');
scriptText += `concat=n=${videoList.length}:v=1:a=1[video][audio]`;
return resolve(scriptText);
}
// 创建副本,准备用来制作转场动画的片段
videoList.forEach((v, i) => {
// 视频流创建2个副本,副本1用来最后的拼接,副本2用来制作转场动画
scriptText += `[${i}:v]split[v${i}][v${i}copy];`;
// 取副本2的其中animateDuration(即设置的转场动画时间)秒,这里从开头取,
// 如果取其他时间段,需要使用setpts=PTS-STARTPTS矫正时间戳
scriptText += `[v${i}copy]trim=0:${animateDuration}[v${i}1];`;
if (i > 0 && i < videoList.length - 1) {
// 非首尾的视频,创建animateDuration秒的两个副本,分别和前后制作转场动画
scriptText += `[v${i}1]split[v${i}10][v${i}11];`;
}
});
// 制作转场动画
videoList.forEach((v, i) => {
if (i < videoList.length - 1) {
const v1 = `[v${i}1${i > 0 ? 1 : ''}]`;//[v01],[v111],[v211]
const v2 = `[v${i + 1}1${i + 1 === videoList.length - 1 ? '' : 0}]`;//[v110],[v210],...[v81]
scriptText += `${v1}${v2}xfade=transition=${getTransitionType()}:duration=${animateDuration}:offset=0[vt${i}];`;
}
});
// 合并video和转场视频
// scriptText += `[v0][vt0][v1][vt1]...[v7][vt7][v8]concat=n=17[video];`;
scriptText += videoList.map((v, i) => {
if (i < videoList.length - 1) {
return `[v${i}][vt${i}]`;
} else {
return `[v${i}]concat=n=${2 * videoList.length - 1}[video];`;
}
}).join('');
// 合并audio,给转场动画添加空白音频
// 最后一个输入流是静音文件(即[videoList.length : a]),可供操作
// 取animateDuration秒静音,并创建videoList.length-1个副本
scriptText += `[${videoList.length}:a]atrim=0:1[asilent];`;
// [asilent]asplit=8[asilent0][asilent1]...[asilent8];
scriptText += `[asilent]asplit=${videoList.length - 1}`;
scriptText += videoList.slice(0, -1).map((v, i) => `[asilent${i}]`).join('');
scriptText += ';';
// 合并音频并插入静音音频,转场动画需要对应音频流,否则正常音频会提前播放,导致音视频不同步
scriptText += videoList.map((v, i) => {
if (i < videoList.length - 1) {
return `[${i}:a][asilent${i}]`;
} else {
return `[${i}:a]concat=n=${2 * videoList.length - 1}:v=0:a=1[audio]`;
}
}).join('');
resolve(scriptText);
} catch(err) {
reject(err);
}
});
}

function concatVideos(videoFolder, resultFolder) {
console.log('===================================================',videoFolder)
return new Promise(async (resolve, reject) => {
// -hide_banner
let cmd = 'ffmpeg ';
const videoList = fs.readdirSync(videoFolder).filter(v => path.extname(v) === '.mp4');
console.log(videoList)
// 输入文件
const inputFiles = videoList.map(v => `-i ${path.join(videoFolder, v)}`).join(' ');
cmd += `${inputFiles} `;
// 静音音频
cmd += '-f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100 ';
/*******-filter_complex_script "file.txt */
const scriptText = await createFilterScript(videoFolder, true);
const scriptPath = path.resolve('./src/doc/filter.txt');
console.log(scriptPath)
// scriptText += videoList.map((v, i) => {
// let char = 0;
// if ( i === videoList.length - 1) {
// char = '';
// }
// return `[${i}:a]atrim=0:${char}[a${i}];[${i}:v]split[v${i}00][v${i}10];`;
// }).join('');
fs.writeFileSync(scriptPath, scriptText);
cmd += `-safe 0 -filter_complex_script ${scriptPath} -vsync 0 `;
/*******-filter_complex_script "file.txt */
// settings -map [audio] -movflags +faststart
cmd += '-map [video] -map [audio] -movflags +faststart -y ';
// cmd += '-profile:v high -level 3.1 -preset:v veryfast -keyint_min 72 -g 72 -sc_threshold 0 ';
// cmd += '-b:v 3000k -minrate 3000k -maxrate 6000k -bufsize 6000k ';
// cmd += '-b:a 128k -avoid_negative_ts make_zero -fflags +genpts -y ';
cmd += path.join(resultFolder, 'out.mp4');
spawnAsync(cmd).then(data => {
resolve(data);
}).catch(err => {
reject(err);
});
// fs.writeFileSync(path.resolve('./doc/cmd.txt'), cmd);
});
}
const videoFolder = path.resolve('./src/doc/video');
const resultFolder = path.resolve('./src/doc');
// getSlideVideos().then(data => {
// console.log(data)
// }).catch(err => {
// console.log(err)
// });
// concatVideos(process.cwd(), resultFolder).then(data => {
// console.log(data);
// }).catch(err => {
// console.log(err);
// })
// getDuration(path.resolve(videoFolder, '../out.mp4')).then(data => {
// console.log(data);
// }).catch(err => {
// console.log(err);
// });
// const imgPath = path.resolve('./src/doc/img/1.PNG');
// const audioPathss = path.resolve('./src/doc/audio/tip2.mp3');
// img2video(imgPath, 'ddddd').then(data => {
// console.log(data);
// }).catch(err => {
// console.log(err);
// });

const ppt2video = new PPT2video({
pptPath: path.resolve('./src/doc/test.pptx'),
animate: {
use: true,
// type: 'vertclose',
type: 'inturn',
duration: 1
},
tmpdir: path.resolve('./temp'),
resultFolder: path.resolve('./result'),
audioFolder: path.resolve('./src/doc/audio'),
slideDuration: 3
});
console.log(1)
ppt2video.convert().then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
module.exports = PPT2video;
34 changes: 34 additions & 0 deletions src/example/eg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const { PPT2video } = require('../ppt2pdf.js');
const path = require('path');
const ppt2video = new PPT2video({
pptPath: path.resolve('../doc/test.pptx'),
animate: {
use: true,
// type: 'vertclose',
type: 'inturn',
duration: 1
},
tmpdir: path.resolve('./temp'),
resultFolder: path.resolve('./result'),
audioFolder: path.resolve('../doc/audio'),
slideDuration: 3
});

const imgFolder = path.resolve(__dirname, '../doc/img');
const audioFolder = path.resolve(__dirname, '../doc/audio');
const videoFolder = path.resolve(__dirname, '../doc/video');
// ppt2video.getSlideVideos(imgFolder, audioFolder, videoFolder).then(data => {
// console.log(data)
// }).catch(err => {
// console.log(err);
// });

ppt2video.concatVideos(videoFolder, path.dirname(videoFolder), {
resultName: 'hhhhhhhresult.mp4'
}, (a, b, c) =>{
console.log(a, b, c);
}).then(data => {
console.log(data)
}).catch(err => {
console.log(err);
});
1 change: 1 addition & 0 deletions src/example/temp/ppt2video/filterScript.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[0:v]split[v0][v0copy];[v0copy]trim=0:1[v01];[1:v]split[v1][v1copy];[v1copy]trim=0:1[v11];[v11]split[v110][v111];[2:v]split[v2][v2copy];[v2copy]trim=0:1[v21];[v21]split[v210][v211];[3:v]split[v3][v3copy];[v3copy]trim=0:1[v31];[v31]split[v310][v311];[4:v]split[v4][v4copy];[v4copy]trim=0:1[v41];[v41]split[v410][v411];[5:v]split[v5][v5copy];[v5copy]trim=0:1[v51];[v51]split[v510][v511];[6:v]split[v6][v6copy];[v6copy]trim=0:1[v61];[v61]split[v610][v611];[7:v]split[v7][v7copy];[v7copy]trim=0:1[v71];[v71]split[v710][v711];[8:v]split[v8][v8copy];[v8copy]trim=0:1[v81];[v01][v110]xfade=transition=fade:duration=1:offset=0[vt0];[v111][v210]xfade=transition=wipeleft:duration=1:offset=0[vt1];[v211][v310]xfade=transition=wiperight:duration=1:offset=0[vt2];[v311][v410]xfade=transition=wipeup:duration=1:offset=0[vt3];[v411][v510]xfade=transition=wipedown:duration=1:offset=0[vt4];[v511][v610]xfade=transition=slideleft:duration=1:offset=0[vt5];[v611][v710]xfade=transition=slideright:duration=1:offset=0[vt6];[v711][v81]xfade=transition=slideup:duration=1:offset=0[vt7];[v0][vt0][v1][vt1][v2][vt2][v3][vt3][v4][vt4][v5][vt5][v6][vt6][v7][vt7][v8]concat=n=17[video];[9:a]atrim=0:1[asilent];[asilent]asplit=8[asilent0][asilent1][asilent2][asilent3][asilent4][asilent5][asilent6][asilent7];[0:a][asilent0][1:a][asilent1][2:a][asilent2][3:a][asilent3][4:a][asilent4][5:a][asilent5][6:a][asilent6][7:a][asilent7][8:a]concat=n=17:v=0:a=1[audio]
Loading

0 comments on commit 0a220e9

Please sign in to comment.