Express.js视频处理:视频上传与转码处理
Express.js视频处理:视频上传与转码处理
【免费下载链接】express 项目地址: https://gitcode.com/gh_mirrors/exp/express
你还在为视频上传速度慢、转码效率低而烦恼吗?本文将带你使用Express.js构建一个高效的视频处理系统,从文件上传到格式转码,全程手把手教学,让你轻松应对各类视频处理需求。读完本文,你将掌握:视频上传的核心原理、大文件分片上传技巧、基于FFmpeg的视频转码实现以及处理进度监控方法。
视频上传基础
在Express.js中实现文件上传,通常需要借助中间件来处理multipart/form-data类型的请求。虽然官方示例中没有直接提供视频上传的代码,但我们可以参考下载功能示例的文件处理逻辑,结合第三方上传中间件来实现视频上传功能。
以下是一个基础的视频上传实现,使用multer中间件处理文件上传:
const express = require('express');
const multer = require('multer');
const app = express();
// 配置存储引擎
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
// 为视频文件生成唯一文件名
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, file.fieldname + '-' + uniqueSuffix + '.mp4');
}
});
// 文件过滤,只允许视频文件
const fileFilter = (req, file, cb) => {
if (file.mimetype.startsWith('video/')) {
cb(null, true);
} else {
cb(new Error('只允许上传视频文件!'), false);
}
};
const upload = multer({ storage: storage, fileFilter: fileFilter });
// 视频上传接口
app.post('/upload', upload.single('video'), (req, res) => {
res.json({
message: '视频上传成功',
file: req.file
});
});
app.listen(3000, () => {
console.log('视频上传服务器启动,端口3000');
});
大文件分片上传
对于大型视频文件,直接上传容易出现超时或失败的情况。实现分片上传可以有效解决这一问题,将大文件分割成多个小片段分别上传,最后在服务器端合并。
// 分片上传实现示例
const fs = require('fs');
const path = require('path');
const { createWriteStream } = require('fs');
const { Readable } = require('stream');
// 合并分片
const mergeChunks = async (filePath, chunksDir, totalChunks) => {
const writeStream = createWriteStream(filePath);
for (let i = 0; i < totalChunks; i++) {
const chunkPath = path.join(chunksDir, `${i}`);
const chunk = fs.readFileSync(chunkPath);
await new Promise(resolve => {
Readable.from(chunk).pipe(writeStream, { end: false });
writeStream.once('finish', resolve);
});
fs.unlinkSync(chunkPath);
}
fs.rmdirSync(chunksDir);
writeStream.end();
};
// 分片上传接口
app.post('/upload/chunk', upload.single('chunk'), (req, res) => {
const { filename, chunkIndex, totalChunks } = req.body;
const chunksDir = path.join(__dirname, 'chunks', filename);
if (!fs.existsSync(chunksDir)) {
fs.mkdirSync(chunksDir, { recursive: true });
}
const chunkPath = path.join(chunksDir, chunkIndex);
fs.renameSync(req.file.path, chunkPath);
// 检查是否所有分片都已上传
const uploadedChunks = fs.readdirSync(chunksDir).length;
if (uploadedChunks === parseInt(totalChunks)) {
const finalPath = path.join(__dirname, 'uploads', filename);
mergeChunks(finalPath, chunksDir, totalChunks);
res.json({ message: '文件合并完成' });
} else {
res.json({ message: '分片上传成功', uploaded: uploadedChunks });
}
});
视频转码处理
视频转码是视频处理中的关键环节,我们可以使用FFmpeg工具来实现视频格式转换、分辨率调整等功能。以下是一个基于Express.js和FFmpeg的视频转码实现:
const { exec } = require('child_process');
const path = require('path');
// 视频转码函数
const transcodeVideo = (inputPath, outputPath, options, callback) => {
const command = `ffmpeg -i ${inputPath} ${options} ${outputPath}`;
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`转码错误: ${error.message}`);
return callback(error);
}
if (stderr) {
console.log(`转码输出: ${stderr}`);
}
callback(null, outputPath);
});
};
// 转码接口
app.post('/transcode', (req, res) => {
const { inputFile, format = 'mp4', quality = '720p' } = req.body;
const inputPath = path.join(__dirname, 'uploads', inputFile);
// 根据质量设置转码参数
let options = '';
switch(quality) {
case '1080p':
options = '-s 1920x1080 -b:v 5000k';
break;
case '720p':
options = '-s 1280x720 -b:v 2500k';
break;
case '480p':
options = '-s 854x480 -b:v 1000k';
break;
default:
options = '-s 1280x720 -b:v 2500k';
}
const outputFile = `${path.parse(inputFile).name}_${quality}.${format}`;
const outputPath = path.join(__dirname, 'transcoded', outputFile);
transcodeVideo(inputPath, outputPath, options, (error, result) => {
if (error) {
return res.status(500).json({ error: error.message });
}
res.json({
message: '视频转码成功',
outputFile: outputFile,
path: outputPath
});
});
});
完整视频处理流程
将上传和转码功能结合起来,我们可以构建一个完整的视频处理流程:
// 完整视频处理流程
app.post('/process-video', upload.single('video'), (req, res) => {
const inputFile = req.file.filename;
const inputPath = req.file.path;
// 转码为多种分辨率
const qualities = ['480p', '720p', '1080p'];
const transcodingPromises = qualities.map(quality => {
return new Promise((resolve, reject) => {
const outputFile = `${path.parse(inputFile).name}_${quality}.mp4`;
const outputPath = path.join(__dirname, 'transcoded', outputFile);
const options = quality === '1080p' ?
'-s 1920x1080 -b:v 5000k' :
quality === '720p' ? '-s 1280x720 -b:v 2500k' :
'-s 854x480 -b:v 1000k';
transcodeVideo(inputPath, outputPath, options, (error, result) => {
if (error) reject(error);
else resolve(outputFile);
});
});
});
Promise.all(transcodingPromises)
.then(outputFiles => {
res.json({
message: '视频处理完成',
originalFile: inputFile,
transcodedFiles: outputFiles
});
})
.catch(error => {
res.status(500).json({ error: error.message });
});
});
进度监控与错误处理
为提升用户体验,我们需要实现视频处理进度监控和完善的错误处理机制:
// 进度监控实现
const { spawn } = require('child_process');
const transcodeWithProgress = (inputPath, outputPath, options, onProgress, callback) => {
const command = `ffmpeg -i ${inputPath} ${options} ${outputPath}`;
const ffmpeg = spawn('ffmpeg', ['-i', inputPath, ...options.split(' '), outputPath]);
ffmpeg.stderr.on('data', (data) => {
const output = data.toString();
// 解析转码进度
const match = output.match(/time=(\d+:\d+:\d+\.\d+)/);
if (match) {
const time = match[1];
// 估算进度百分比
const totalSeconds = parseTimeToSeconds(time);
const progress = Math.min(Math.round(totalSeconds / 600 * 100), 100); // 假设视频时长约10分钟
onProgress(progress);
}
});
ffmpeg.on('close', (code) => {
if (code !== 0) {
return callback(new Error(`FFmpeg进程退出,代码: ${code}`));
}
callback(null, outputPath);
});
};
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
error: '服务器内部错误',
message: err.message,
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
});
});
部署与优化建议
在实际部署视频处理服务时,需要考虑性能优化和资源管理:
-
使用队列系统:将视频处理任务加入队列,避免长时间请求阻塞,可以使用Bull等队列库实现。
-
水平扩展:将视频处理服务与Web服务分离,独立部署转码服务器,通过消息队列实现任务分发。
-
存储优化:对于大量视频文件,建议使用对象存储服务,如AWS S3或阿里云OSS。
-
缓存策略:对热门视频进行缓存,减少重复转码,提高响应速度。
-
资源限制:限制同时处理的视频数量,避免服务器资源耗尽。
通过本文介绍的方法,你可以构建一个功能完善的视频处理系统。结合Express.js的灵活性和FFmpeg的强大功能,无论是简单的视频格式转换还是复杂的视频处理流程,都能轻松应对。如果你想进一步优化,可以研究分布式转码、GPU加速等高级技术,不断提升系统性能和用户体验。
参考项目中的下载示例可以帮助你实现视频文件的下载功能,将处理完成的视频提供给用户访问。同时,错误处理示例展示了如何优雅地处理各类异常情况,确保系统稳定运行。
希望本文对你构建视频处理系统有所帮助,如有任何问题,欢迎查阅Express.js官方文档或项目中的示例代码获取更多灵感。
【免费下载链接】express 项目地址: https://gitcode.com/gh_mirrors/exp/express
火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。
更多推荐
所有评论(0)