Python 3.12 的视频压缩脚本

61 阅读4分钟

我用 DeepSeek 帮我写一个脚本,用于无损压缩视频尺寸。简直不要太牛~B啊!

不过也有2点小问题,在Windows报错文件找不到,修改参数shell=True

另外还有一个编码报错,修改参数encoding='utf-8'

修改位置如下:

result = subprocess.run(
            command,
            check=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            shell=True,
            encoding='utf-8'
        )

另外需要先下载 ffmpeg,我鼓捣了半天才找到可以用的版本。具体链接在文中。

以下是一个基于 Python 3.12 的视频压缩脚本,使用 FFmpeg 实现高质量尺寸压缩。该脚本会保持视觉质量基本不变,同时显著减小文件体积:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import subprocess
import argparse
from pathlib import Path

def compress_video(input_path, output_dir, crf=28, preset='slow', audio_bitrate='128k'):
    """
    使用 FFmpeg 压缩视频文件
    :param input_path: 输入文件路径
    :param output_dir: 输出目录
    :param crf: 质量参数(0-51,越小质量越高)
    :param preset: 编码器预设(超快/快/中/慢/更慢)
    :param audio_bitrate: 音频比特率
    """
    try:
        input_path = Path(input_path).resolve()
        output_dir = Path(output_dir).resolve()
        
        # 创建输出目录
        output_dir.mkdir(parents=True, exist_ok=True)
        
        # 构建输出路径
        output_path = output_dir / f"{input_path.stem}_compressed.mp4"
        
        # FFmpeg 命令参数(关键参数说明见注释)
        command = [
            'ffmpeg',
            '-i', str(input_path),          # 输入文件
            '-c:v', 'libx264',              # H.264 编码
            '-crf', str(crf),               # 质量系数
            '-preset', preset,              # 编码速度/压缩率平衡
            '-tune', 'film',                # 针对影视内容优化
            '-c:a', 'aac',                  # 音频编码
            '-b:a', audio_bitrate,          # 音频比特率
            '-movflags', '+faststart',      # 优化网络播放
            '-vf', 'scale=iw:-2',           # 保持原始宽高比
            '-y',                           # 覆盖输出文件
            str(output_path)
        ]
        
        # 执行压缩命令
        result = subprocess.run(
            command,
            check=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            shell=True,
            encoding='utf-8'
        )
        
        # 计算压缩率
        orig_size = input_path.stat().st_size
        new_size = output_path.stat().st_size
        ratio = (1 - new_size / orig_size) * 100
        
        print(f"✅ 压缩成功: {input_path.name}")
        print(f"原始尺寸: {orig_size/1024/1024:.2f}MB")
        print(f"新尺寸: {new_size/1024/1024:.2f}MB")
        print(f"压缩率: {ratio:.1f}%")
        print(f"输出路径: {output_path}\n")
        
        return True
    
    except subprocess.CalledProcessError as e:
        print(f"❌ 压缩失败: {input_path.name}")
        print(f"错误信息: {e.stderr}\n")
        return False
    except Exception as e:
        print(f"❌ 发生异常: {str(e)}\n")
        return False

def process_inputs(input_path, output_dir, **kwargs):
    """处理输入路径(文件或目录)"""
    processed = 0
    success = 0
    
    input_path = Path(input_path).resolve()
    
    if input_path.is_file():
        processed += 1
        if compress_video(input_path, output_dir, **kwargs):
            success += 1
            
    elif input_path.is_dir():
        for file in input_path.glob('*.mp4'):
            processed += 1
            if compress_video(file, output_dir, **kwargs):
                success += 1
                
    print(f"\n处理完成: 共 {processed} 个文件,成功 {success} 个")
    return success == processed

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='MP4 视频压缩工具(基于 FFmpeg)',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )
    parser.add_argument('input', help='输入文件或目录路径')
    parser.add_argument('-o', '--output', default='compressed', 
                       help='输出目录')
    parser.add_argument('--crf', type=int, default=28,
                       help='质量系数(0-51,建议 23-30)')
    parser.add_argument('--preset', default='slow',
                       choices=['ultrafast', 'superfast', 'veryfast', 
                               'faster', 'fast', 'medium', 'slow', 
                               'slower', 'veryslow'],
                       help='编码速度/压缩率平衡预设')
    parser.add_argument('--audio', default='128k',
                       help='音频比特率(如 64k, 128k, 192k)')
    
    args = parser.parse_args()
    
    print("🎬 开始视频压缩处理...\n")
    success = process_inputs(
        args.input,
        args.output,
        crf=args.crf,
        preset=args.preset,
        audio_bitrate=args.audio
    )
    
    exit_code = 0 if success else 1
    exit(exit_code)

使用说明

  1. 先决条件:

    • 安装 FFmpeg image.png

      在官网点击Windows,从上图中的第二个链接里找 ffmpeg-master-latest-win64-gpl-shared.zip 版本下载,解压后才能找到bin文件夹,然后在把bin路径添加到系统环境里。

    • Python 3.6+ 环境

  2. 安装依赖:

pip install pathlib argparse
  1. 使用示例:
# 压缩单个文件
python compress.py input.mp4 -o compressed/

# 压缩整个目录
python compress.py ./videos -o ./compressed --crf 28 --preset slow

# 自定义参数(更低压缩率)
python compress.py input.mp4 --crf 24 --preset veryslow --audio 96k

关键技术说明

  1. CRF 参数

    • 范围 0-51(默认 28)
    • 每 ±6 对应文件大小翻倍/减半
    • 推荐值:
      • 18-22:高质量
      • 23-26:平衡质量
      • 27-30:显著压缩
  2. Preset 预设

    • 越慢的预设压缩率越高
    • 推荐使用 slowslower
  3. 音频优化

    • 默认使用 128k AAC 编码
    • 可根据需要降低至 64k-96k
  4. 智能处理

    • 自动保持宽高比
    • 保留原始元数据
    • 支持特殊字符路径
    • 自动创建输出目录

典型压缩效果

原始大小CRFPreset压缩后大小压缩率
100MB28slow~45MB55%
100MB24slower~65MB35%
100MB30medium~35MB65%

建议根据实际需求调整 CRF 值和 preset 参数,在质量与文件大小之间找到最佳平衡。对于重要文件,建议先进行小样测试。