已完成前端,如何在服务器端压缩用户上传的视频?
嘿,看来你前端已经把视频上传的交互搞定了,接下来咱们聚焦服务器端的视频压缩逻辑就行!核心工具我推荐FFmpeg——这是目前最成熟的音视频处理工具,几乎所有后端语言都能调用它,压缩效果和可控性都拉满。下面我给你一步步讲明白怎么实现:
第一步:先在服务器上安装FFmpeg
不管你用什么后端语言,第一步必须先把FFmpeg装上:
- Ubuntu/Debian系统:执行
sudo apt-get install ffmpeg - CentOS/RHEL系统:执行
sudo yum install ffmpeg - Windows系统:下载FFmpeg压缩包解压后,把bin目录添加到系统环境变量里
第二步:后端接收并压缩视频(附两种常用后端示例)
我给你准备了Node.js(Express)和Python(Flask)的代码示例,你可以根据自己的技术栈选:
示例1:Node.js + Express框架
先装依赖:
npm install express multer fluent-ffmpeg
然后写核心代码:
const express = require('express'); const multer = require('multer'); const ffmpeg = require('fluent-ffmpeg'); const path = require('path'); const fs = require('fs'); const app = express(); // 配置multer处理文件上传,限制10MB const upload = multer({ dest: 'uploads/', // 临时存储上传的原文件 limits: { fileSize: 10 * 1024 * 1024 } }); // 处理上传请求的接口 app.post('/upload-video', upload.single('video'), (req, res) => { if (!req.file) { return res.status(400).send('请选择要上传的视频文件!'); } const inputPath = req.file.path; const outputPath = path.join('compressed', `${Date.now()}_compressed.mp4`); // 确保压缩后的文件存储目录存在 if (!fs.existsSync('compressed')) { fs.mkdirSync('compressed'); } // 用FFmpeg执行压缩逻辑 ffmpeg(inputPath) .outputOptions([ '-vcodec libx264', // 用H.264编码,压缩率高且兼容性好 '-crf 28', // CRF值越大压缩率越高,28是质量和大小的平衡点 '-preset medium', // 编码速度,medium兼顾速度和压缩效果 '-maxrate 500k', // 限制视频最大码率 '-bufsize 1000k', // 码率缓冲大小 '-acodec aac', // 音频用AAC编码 '-ab 128k' // 音频码率,降低音频码率也能减小文件 ]) .save(outputPath) .on('end', () => { // 检查压缩后的文件是否符合5MB要求 const stats = fs.statSync(outputPath); const fileSizeMB = stats.size / (1024 * 1024); if (fileSizeMB > 5) { fs.unlinkSync(outputPath); fs.unlinkSync(inputPath); return res.status(400).send('压缩后文件仍超5MB,建议上传更短的视频哦!'); } // 删除临时原文件,节省服务器空间 fs.unlinkSync(inputPath); res.send(`视频压缩完成!已保存到服务器:${outputPath}`); }) .on('error', (err) => { fs.unlinkSync(inputPath); res.status(500).send(`压缩失败啦:${err.message}`); }); }); app.listen(3000, () => { console.log('服务器跑起来啦:http://localhost:3000'); });
示例2:Python + Flask框架
先装依赖:
pip install flask flask-ffmpeg
核心代码如下:
from flask import Flask, request, jsonify from flask_ffmpeg import FlaskFFmpeg import os import time app = Flask(__name__) ffmpeg = FlaskFFmpeg(app) # 配置目录和大小限制 UPLOAD_TEMP = 'uploads' COMPRESSED_DIR = 'compressed' MAX_UPLOAD_SIZE = 10 * 1024 * 1024 # 10MB MAX_COMPRESSED_SIZE = 5 * 1024 * 1024 # 5MB # 自动创建目录 os.makedirs(UPLOAD_TEMP, exist_ok=True) os.makedirs(COMPRESSED_DIR, exist_ok=True) @app.route('/upload-video', methods=['POST']) def upload_and_compress(): if 'video' not in request.files: return jsonify({'error': '请选择要上传的视频文件!'}), 400 video_file = request.files['video'] if video_file.filename == '': return jsonify({'error': '没选到文件呀!'}), 400 # 检查原文件大小 video_file.seek(0, os.SEEK_END) file_size = video_file.tell() video_file.seek(0) if file_size > MAX_UPLOAD_SIZE: return jsonify({'error': '文件超10MB限制啦!'}), 400 # 保存临时原文件 temp_filename = f'{time.time()}_{video_file.filename}' temp_path = os.path.join(UPLOAD_TEMP, temp_filename) video_file.save(temp_path) # 配置FFmpeg压缩参数 output_filename = f'{time.time()}_compressed.mp4' output_path = os.path.join(COMPRESSED_DIR, output_filename) ffmpeg_options = [ '-vcodec', 'libx264', '-crf', '28', '-preset', 'medium', '-maxrate', '500k', '-bufsize', '1000k', '-acodec', 'aac', '-ab', '128k' ] try: # 执行压缩 ffmpeg.run(temp_path, output_path, options=ffmpeg_options) except Exception as e: os.remove(temp_path) return jsonify({'error': f'压缩失败:{str(e)}'}), 500 # 检查压缩后文件大小 compressed_size = os.path.getsize(output_path) if compressed_size > MAX_COMPRESSED_SIZE: os.remove(output_path) os.remove(temp_path) return jsonify({'error': '压缩后仍超5MB,建议上传更短的视频!'}), 400 # 删除临时文件 os.remove(temp_path) return jsonify({'message': '视频压缩完成!', 'file_path': output_path}), 200 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)
第三步:关键参数调优(确保压缩到5MB以内)
如果压缩后的文件还是超5MB,可以调整这些参数:
- CRF值:把28调到30/32,值越大压缩率越高,但视频质量会略有下降
- 分辨率:加参数
-vf scale=1280:-1(保持宽高比,把宽度缩到1280),高分辨率视频缩分辨率能大幅减小体积 - 码率:把
-maxrate调到400k甚至300k,进一步限制码率
第四步:前端对接后端接口
前端的上传逻辑里,把请求指向你的后端接口就行,比如用Fetch的示例:
const fileInput = document.getElementById('video-input'); const uploadBtn = document.getElementById('upload-btn'); uploadBtn.addEventListener('click', async () => { if (!fileInput.files[0]) { alert('请先选择视频文件!'); return; } const formData = new FormData(); formData.append('video', fileInput.files[0]); try { const response = await fetch('/upload-video', { method: 'POST', body: formData }); const result = await response.text(); alert(result); } catch (err) { alert('上传失败:' + err.message); } });
内容的提问来源于stack exchange,提问作者Saris
相关产品推荐
相关产品推荐

