You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已完成前端,如何在服务器端压缩用户上传的视频?

嘿,看来你前端已经把视频上传的交互搞定了,接下来咱们聚焦服务器端的视频压缩逻辑就行!核心工具我推荐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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:42:08