#javascript #node.js #video #ffmpeg #fluent-ffmpeg
Вопрос:
Я создал видеоредактор, и мне нужно вырезать несколько разделов в видео с помощью fluent-ffmpeg на узле. Я получаю эту ошибку при редактировании видео…
error3: Error: ffmpeg exited with code 1: Cannot find a matching stream for unlabeled input pad 1 on filter Parsed_concat_0
at ChildProcess.<anonymous> (/Users/xbotpc/Work/[client_name]/[client_project_name]/node_modules/fluent-ffmpeg/lib/processor.js:182:22)
at ChildProcess.emit (events.js:198:13)
at ChildProcess.EventEmitter.emit (domain.js:466:23)
at Process.ChildProcess._handle.onexit (internal/child_process.js:248:12)
Я получаю эту ошибку, когда редактирую выходное видео во второй раз.
Весь вывод выглядит так…
source /Users/xbotpc/Work/[client_name]/[client_project_name]/video_files/raw_1800150.mp4
outputVideoFilePath /Users/xbotpc/Work/[client_name]/[client_project_name]/video_files/OUTPUT_VIDEO_FILE_raw_1800150.mp4
Video Cut 1
Video Cut 2
Video stitched
startTime, endTime 1s 4s
source /Users/xbotpc/Work/[client_name]/[client_project_name]/video_files/OUTPUT_VIDEO_FILE_raw_1800150.mp4
outputVideoFilePath /Users/xbotpc/Work/[client_name]/[client_project_name]/video_files/OUTPUT_VIDEO_FILE_raw_1800150.mp4
Video Cut 1
Video Cut 2
error3: Error: ffmpeg exited with code 1: Cannot find a matching stream for unlabeled input pad 1 on filter Parsed_concat_0
at ChildProcess.<anonymous> (/Users/xbotpc/Work/[client_name]/[client_project_name]/node_modules/fluent-ffmpeg/lib/processor.js:182:22)
at ChildProcess.emit (events.js:198:13)
at ChildProcess.EventEmitter.emit (domain.js:466:23)
at Process.ChildProcess._handle.onexit (internal/child_process.js:248:12)
Video stitched error rimRafError null
deleteSection error ERROR3
Следующая моя реализация…
const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path;
const ffmpeg = require('fluent-ffmpeg');
const fs = require('fs');
const rimraf = require('rimraf');
const isEmpty = require('./isEmpty');
const path = require('path');
const ffprobePath = require('ffprobe-static').path;
const { VIDEO_EDITING_FILES_DIRECTORY } = process.env;
/**
* @typedef {Object} VideoEdit
* @property {Function} VideoEdit.deleteSection
* @property {Function} VideoEdit.generateScreenshots
*/
/**
* Video Editing function
* @param {Object} EditVideo input
* @param {string} EditVideo.inputVideoFileName input file name.
* @param {string} EditVideo.outputVideoFileName output file name.
* @returns {Promise<VideoEdit>} VideoEdit
*/
function videoEdit({ inputVideoFileName, outputVideoFileName }) {
// Setting the path of libraries.
ffmpeg.setFfmpegPath(ffmpegPath);
ffmpeg.setFfprobePath(ffprobePath);
const outputFolder = VIDEO_EDITING_FILES_DIRECTORY;
if (isEmpty(outputVideoFileName)) {
outputVideoFileName = `OUTPUT_VIDEO_FILE_${inputVideoFileName}`;
}
const inputVideoFilePath = path.join(__dirname, `${VIDEO_EDITING_FILES_DIRECTORY}/${inputVideoFileName}`);
let outputVideoFilePath = path.join(__dirname, `${VIDEO_EDITING_FILES_DIRECTORY}/${outputVideoFileName}`);
return new Promise((resolve, reject) => {
// ffprobe gets the metadata of file
ffmpeg.ffprobe(inputVideoFilePath, (err, data) => {
const duration = data.format.duration;
resolve({
/**
* Deletes a section of video.
* @param {Object} DeleteOptions Deletion options
* @param {string} DeleteOptions.startTime Time to start deleting
* @param {string} DeleteOptions.endTime Time to end deleting
* @returns {Promise<'DONE' | 'ERROR'>}
*/
deleteSection: ({ startTime, endTime }) => {
return new Promise((resolve1, reject1) => {
const fStartTime = '0';
const fDuration = startTime;
const sStartTime = endTime;
const sDuration = (duration - parseInt(endTime, 10)).toString();
const tempFolder = path.join(__dirname, `${outputFolder}/temp`);
fs.mkdirSync(tempFolder);
const firstHalfFileName = `${tempFolder}/temp_first_half.mp4`;
const secondHalfFileName = `${tempFolder}/temp_second_half.mp4`;
const source = fs.existsSync(outputVideoFilePath) ? outputVideoFilePath : inputVideoFilePath;
const firstHalf = new ffmpeg({
source
})
firstHalf
.setStartTime(fStartTime)
.setDuration(fDuration)
.on('end', (err) => {
if (!err) {
console.log('Video Cut 1')
const secondHalf = new ffmpeg({
source
});
secondHalf
.setStartTime(sStartTime)
.setDuration(sDuration)
.on('end', (err) => {
if (!err) {
console.log('Video Cut 2');
new ffmpeg()
.input(firstHalfFileName)
.input(secondHalfFileName)
.on('end', (err) => {
if (!err) {
console.log('Video stitched');
console.log('startTime, endTime', startTime, endTime)
rimraf(tempFolder, (rimRafError) => {
if (rimRafError) {
console.error('rimRafError', rimRafError);
reject1('ERROR3');
} else {
resolve1('DONE')
}
});
}
})
.on('error', (err) => {
console.log('error3: ', err);
rimraf(tempFolder, (rimRafError) => {
console.error('Video stitched error rimRafError', rimRafError);
reject1('ERROR3');
});
})
.mergeToFile(outputVideoFilePath, outputFolder);
} else {
console.log('error2.1: ', err);
reject('ERROR2.1');
rimraf(tempFolder, (rimRafError) => {
console.error('rimRafError', rimRafError);
});
}
})
.on('error', (err) => {
console.log('error2: ', err);
reject('ERROR2');
rimraf(tempFolder, (rimRafError) => {
console.error('rimRafError', rimRafError);
});
})
.output(secondHalfFileName)
.run();
}
})
.on('error', (err) => {
console.log('error1: ', err);
reject('ERROR1');
rimraf(tempFolder, (rimRafError) => {
console.error('rimRafError', rimRafError);
});
})
.output(firstHalfFileName)
.run();
});
},
})
});
})
}
module.exports = videoEdit;
Я вызываю функцию удаления в цикле, чтобы удалить несколько частей видео. Вызывающая функция выглядит так.
const videoEdit = require('../../../utils/videoEdit');
const deleteSection = async (params) => {
try {
const inputVideoFileName = `raw_${params.content_id}.mp4`;
const videoInstance = await videoEdit({
inputVideoFileName,
// outputVideoFileName: 'output_video.mp4'
});
const sectionDeletionData = [
{
"startTime": "1s",
"endTime": "4s"
},
{
"startTime": "5s",
"endTime": "8s"
}
];
for (let i = 0; i < sectionDeletionData.length; i ) {
await videoInstance.deleteSection({
startTime: sectionDeletionData[i].startTime,
endTime: sectionDeletionData[i].endTime
});
}
console.log('end?');
} catch (error) {
console.error('deleteSection error', error)
return [];
}
}