Modifier la fonction createVideoWithList pour utiliser spawn au lieu de execSync pour l'exécution de ffmpeg en arrière-plan

This commit is contained in:
2025-03-10 17:31:11 +01:00
parent 848c50bf33
commit 7baac5dcb7

View File

@@ -1,6 +1,6 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { execSync } = require('child_process'); const { spawn } = require('child_process');
const serverError = require('../../utils/serverError'); const serverError = require('../../utils/serverError');
const db = require('../../db'); const db = require('../../db');
@@ -28,13 +28,9 @@ async function deleteVideoProject(videoId) {
} }
async function createVideoWithList(projectId, pathList, duration) { async function createVideoWithList(projectId, pathList, duration) {
//pathList étant la liste des chemins déjà triés
const tempFile = path.join('temp.txt'); const tempFile = path.join('temp.txt');
try { try {
// Trouver tous les fichiers image pour le projet donné
const workdir = path.join(PROJECTS_DIR, 'storage', `${projectId}`); const workdir = path.join(PROJECTS_DIR, 'storage', `${projectId}`);
const dir = path.join(PROJECTS_DIR, 'storage', `${projectId}`, 'images');
console.log('dir:', dir);
const images = pathList; const images = pathList;
console.log('images:', images); console.log('images:', images);
@@ -45,38 +41,50 @@ async function createVideoWithList(projectId, pathList, duration) {
return numA - numB; return numA - numB;
}); });
// En déduire l'id de la première et dernière image utilisée // Déterminer l'id de la première et la dernière image utilisée
const firstImageId = parseInt(path.basename(sortedImages[0]).match(/\d+/)[0], 10); const firstImageId = parseInt(path.basename(sortedImages[0]).match(/\d+/)[0], 10);
const lastImageId = parseInt(path.basename(sortedImages[sortedImages.length - 1]).match(/\d+/)[0], 10); const lastImageId = parseInt(path.basename(sortedImages[sortedImages.length - 1]).match(/\d+/)[0], 10);
console.log('firstImageId:', firstImageId); console.log('firstImageId:', firstImageId);
console.log('lastImageId:', lastImageId); console.log('lastImageId:', lastImageId);
// Créer un fichier temporaire pour la liste des images // Créer le fichier temporaire pour la liste des images
fs.writeFileSync(tempFile, sortedImages.map(image => `file '${image}'`).join('\n')); fs.writeFileSync(tempFile, sortedImages.map(image => `file '${image}'`).join('\n'));
const frameRate = Math.ceil(sortedImages.length / parseInt(duration)); const frameRate = Math.ceil(sortedImages.length / parseInt(duration));
// le fichier final prend cette forme : {projectId}_{firstImageId}_{lastImageId}-{timestamp}.mp4
const timestamp = new Date().getTime(); const timestamp = new Date().getTime();
const outputVideo = path.join(workdir, `${projectId}_${firstImageId}_${lastImageId}-${timestamp}.mp4`); const outputVideo = path.join(workdir, `${projectId}_${firstImageId}_${lastImageId}-${timestamp}.mp4`);
// Commande ffmpeg pour créer la vidéo // Préparer les arguments pour ffmpeg
const ffmpegCommand = `ffmpeg -r ${frameRate} -f concat -safe 0 -i ${tempFile} -vsync vfr -pix_fmt yuv420p ${outputVideo}`; const ffmpegArgs = [
console.log('Running ffmpeg command:', ffmpegCommand); '-r', frameRate.toString(),
try { '-f', 'concat',
execSync(ffmpegCommand, { stdio: 'ignore', detached: true }); '-safe', '0',
'-i', tempFile,
'-vsync', 'vfr',
'-pix_fmt', 'yuv420p',
outputVideo
];
console.log('Lancement de ffmpeg en arrière-plan avec les arguments:', ffmpegArgs);
// Lancer ffmpeg en mode détaché
const child = spawn('ffmpeg', ffmpegArgs, {
detached: true,
stdio: 'ignore'
});
// Permettre au processus ffmpeg de continuer même si le parent se termine
child.unref();
console.log('Video creation started in background:', outputVideo); console.log('Video creation started in background:', outputVideo);
} catch (error) {
console.error('ffmpeg command failed:', error);
serverError.sendError(error);
}
return outputVideo; return outputVideo;
} catch (error) { } catch (error) {
console.error('Error creating video:', error); console.error('Error creating video:', error);
serverError.sendError(error); serverError.sendError(error);
} finally { } finally {
// Supprimer le fichier temporaire // Attention : supprimer le fichier temporaire immédiatement pourrait poser problème
// si ffmpeg n'a pas encore fini de le lire. Envisagez un délai ou un mécanisme de nettoyage
if (fs.existsSync(tempFile)) { if (fs.existsSync(tempFile)) {
fs.unlinkSync(tempFile); fs.unlinkSync(tempFile);
console.log('Temporary file deleted:', tempFile); console.log('Temporary file deleted:', tempFile);
@@ -117,7 +125,7 @@ async function createVideo(projectId) {
// Commande ffmpeg pour créer la vidéo // Commande ffmpeg pour créer la vidéo
const ffmpegCommand = `ffmpeg -r ${frameRate} -f concat -safe 0 -i ${tempFile} -vsync vfr -pix_fmt yuv420p ${outputVideo}`; const ffmpegCommand = `ffmpeg -r ${frameRate} -f concat -safe 0 -i ${tempFile} -vsync vfr -pix_fmt yuv420p ${outputVideo}`;
console.log('Running ffmpeg command:', ffmpegCommand); console.log('Running ffmpeg command:', ffmpegCommand);
execSync(ffmpegCommand); spawn(ffmpegCommand);
console.log('Video created successfully:', outputVideo); console.log('Video created successfully:', outputVideo);
} catch (error) { } catch (error) {
console.error('Error creating video:', error); console.error('Error creating video:', error);