Node.js结合ytdl与FFmpeg处理视频下载合并问题求助
Node.js ytdl+FFmpeg 合并视频音频的问题排查与修复
问题1:视频时长超出正常范围
原因
当前代码仅监听音频流的finish事件就触发合并操作,但视频流的下载是独立的异步任务,此时视频文件大概率还未完全写入磁盘。合并未完成的视频文件会导致媒体时长解析异常,甚至生成损坏的文件。
修复方案
用Promise封装视频和音频的下载流程,等待两者都完成后再执行合并。
问题2:fluent-ffmpeg提示找不到FFmpeg
原因
fluent-ffmpeg只是Node.js的FFmpeg封装库,本身不包含FFmpeg二进制程序。必须在系统中单独安装FFmpeg,并确保Node.js进程能访问到其可执行文件路径。
修复方案
- 安装FFmpeg
- Windows:下载FFmpeg二进制包,解压后将
ffmpeg.exe所在目录添加到系统PATH环境变量; - macOS:通过Homebrew执行
brew install ffmpeg; - Linux:通过系统包管理器安装,例如Ubuntu执行
sudo apt install ffmpeg。
- Windows:下载FFmpeg二进制包,解压后将
- 代码中指定FFmpeg路径(可选)
如果环境变量配置后仍无法识别,可在代码开头手动指定路径:ffmpeg.setFfmpegPath('/usr/local/bin/ffmpeg'); // 替换为你的FFmpeg实际路径
修复后的完整代码
const fs = require('fs'); const ytdl = require('ytdl-core'); const ffmpeg = require('fluent-ffmpeg'); // 可选:手动指定FFmpeg路径,根据你的系统调整 // ffmpeg.setFfmpegPath('/usr/local/bin/ffmpeg'); // 封装下载流为Promise function downloadStream(stream, outputPath) { return new Promise((resolve, reject) => { stream.pipe(fs.createWriteStream(outputPath)) .on('finish', resolve) .on('error', reject); }); } // Function to download the youtube video function download() { const linkInput = document.getElementById('linkInp'); const resolution = document.getElementById('resolution'); const videoTitle = document.getElementById('videoTitle'); const videoAuthor = document.getElementById('videoAuthor'); const videoUploadDate = document.getElementById('videoUploadDate'); const videoPicture = document.getElementById('videoPic'); const link = linkInput.value; console.log('Downloading following video from link: ', link, ' with resolution id: ', resolution.value); ytdl.getInfo(link).then(async (info) => { const format = ytdl.chooseFormat(info.formats, { quality: `${resolution.value}` }); const videoFilePath = `${info.videoDetails.title}.${format.container}`; const audioFilePath = `${info.videoDetails.title}.mp3`; // 填充元数据 videoTitle.innerHTML = info.videoDetails.title; videoAuthor.innerHTML = info.videoDetails.author.name; videoUploadDate.innerHTML = info.videoDetails.uploadDate; videoPicture.src = info.videoDetails.thumbnails[0].url; // 同时下载视频和音频,等待两者完成 try { await Promise.all([ downloadStream(ytdl.downloadFromInfo(info, { format: format }), videoFilePath), downloadStream(ytdl.downloadFromInfo(info, { filter: 'audioonly' }), audioFilePath) ]); // 合并视频和音频 ffmpeg() .input(videoFilePath) .input(audioFilePath) .videoCodec('copy') .audioCodec('copy') .save(`${info.videoDetails.title}_with_audio.${format.container}`) .on('end', () => { console.log('Video with audio merged successfully!'); // 删除临时文件 fs.unlink(videoFilePath, (err) => err && console.error(err)); fs.unlink(audioFilePath, (err) => err && console.error(err)); }) .on('error', (err) => console.error('Merge error:', err)); } catch (err) { console.error('Download error:', err); document.getElementById('msg').style.display = 'block'; document.getElementById('message').innerHTML = err; } }).catch((err) => { console.error(err); document.getElementById('msg').style.display = 'block'; document.getElementById('message').innerHTML = err; }); }
内容的提问来源于stack exchange,提问作者zlElo
相关产品推荐
相关产品推荐

