本文目录导读:

我来分享几个Python视频转码的实用案例,主要使用moviepy和ffmpeg-python库。
基础环境安装
pip install moviepy ffmpeg-python # 还需要安装FFmpeg(系统层面)
使用moviepy进行视频格式转换
基础转换案例
from moviepy.editor import VideoFileClip
import os
def convert_video_basic(input_path, output_path):
"""
基础视频格式转换
"""
try:
# 加载视频
video = VideoFileClip(input_path)
# 转换并保存
video.write_videofile(
output_path,
codec='libx264', # 视频编码
audio_codec='aac', # 音频编码
fps=30, # 帧率
bitrate='2000k' # 比特率
)
video.close()
print(f"转换完成: {output_path}")
except Exception as e:
print(f"转换失败: {e}")
# 使用示例
convert_video_basic('input.avi', 'output.mp4')
批量转换案例
import glob
from moviepy.editor import VideoFileClip
from concurrent.futures import ThreadPoolExecutor
import os
def batch_convert_videos(input_dir, output_dir, target_format='mp4'):
"""
批量转换视频格式
"""
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 获取所有视频文件
video_extensions = ['*.avi', '*.mov', '*.mkv', '*.flv', '*.wmv']
video_files = []
for ext in video_extensions:
video_files.extend(glob.glob(os.path.join(input_dir, ext)))
def convert_single(video_path):
try:
# 生成输出文件名
filename = os.path.basename(video_path)
name_without_ext = os.path.splitext(filename)[0]
output_path = os.path.join(output_dir, f"{name_without_ext}.{target_format}")
# 转换视频
video = VideoFileClip(video_path)
video.write_videofile(
output_path,
codec='libx264',
audio_codec='aac',
preset='medium',
logger=None # 关闭日志
)
video.close()
print(f"转换成功: {filename}")
except Exception as e:
print(f"转换失败 {video_path}: {e}")
# 多线程处理
with ThreadPoolExecutor(max_workers=4) as executor:
executor.map(convert_single, video_files)
# 使用示例
batch_convert_videos('./input_videos/', './output_videos/')
使用ffmpeg-python进行转换
高级转换案例
import ffmpeg
import os
def convert_video_ffmpeg(input_path, output_path, options=None):
"""
使用ffmpeg进行高级视频转换
"""
if options is None:
options = {
'vcodec': 'libx264',
'acodec': 'aac',
'b:v': '2000k',
'b:a': '192k',
'vf': 'scale=1920:1080', # 调整分辨率
'r': 30 # 帧率
}
try:
# 构建ffmpeg命令
stream = ffmpeg.input(input_path)
# 应用输出选项
stream = ffmpeg.output(stream, output_path, **options)
# 执行转换
ffmpeg.run(stream, overwrite_output=True, capture_stderr=True)
print(f"转换完成: {output_path}")
except ffmpeg.Error as e:
print(f"FFmpeg错误: {e.stderr.decode()}")
# 使用示例
options = {
'vcodec': 'libx264', # 视频编码
'acodec': 'aac', # 音频编码
'b:v': '3000k', # 视频比特率
'b:a': '192k', # 音频比特率
'vf': 'scale=-2:720', # 保持宽高比缩放到720p
'r': 24, # 帧率
'preset': 'fast', # 编码速度
'crf': 23 # 质量(0-51, 越低越好)
}
convert_video_ffmpeg('input.mp4', 'output.mkv', options)
视频压缩案例
def compress_video(input_path, output_path, target_size_mb=100):
"""
压缩视频到目标大小
"""
try:
# 获取原视频信息
probe = ffmpeg.probe(input_path)
video_info = next(s for s in probe['streams'] if s['codec_type'] == 'video')
# 获取视频时长
duration = float(probe['format']['duration'])
# 计算目标比特率
total_bits = target_size_mb * 8 * 1024 * 1024
video_bitrate = int((total_bits / duration) * 0.9) # 90%给视频
# 构建压缩参数
output_params = {
'vcodec': 'libx264',
'acodec': 'aac',
'b:v': f'{video_bitrate}k',
'maxrate': f'{int(video_bitrate * 1.5)}k',
'bufsize': f'{int(video_bitrate * 2)}k',
'preset': 'slow',
'crf': 28
}
# 执行压缩
stream = ffmpeg.output(
ffmpeg.input(input_path),
output_path,
**output_params
)
ffmpeg.run(stream, overwrite_output=True)
# 显示压缩结果
original_size = os.path.getsize(input_path) / (1024 * 1024)
compressed_size = os.path.getsize(output_path) / (1024 * 1024)
ratio = (1 - compressed_size / original_size) * 100
print(f"原视频大小: {original_size:.2f} MB")
print(f"压缩后大小: {compressed_size:.2f} MB")
print(f"压缩率: {ratio:.1f}%")
except Exception as e:
print(f"压缩失败: {e}")
# 使用示例
compress_video('input.mp4', 'compressed.mp4', target_size_mb=50)
实用工具函数
def get_video_info(filepath):
"""
获取视频信息
"""
try:
video = VideoFileClip(filepath)
info = {
'filename': os.path.basename(filepath),
'duration': video.duration,
'size': os.path.getsize(filepath) / (1024 * 1024), # MB
'width': video.size[0],
'height': video.size[1],
'fps': video.fps,
'audio': video.audio is not None
}
video.close()
return info
except Exception as e:
return {'error': str(e)}
def supported_formats():
"""
返回支持转换的格式列表
"""
return {
'输入格式': ['mp4', 'avi', 'mov', 'mkv', 'flv', 'wmv', 'webm'],
'输出格式': ['mp4', 'avi', 'mov', 'mkv', 'webm', 'gif'],
'推荐编码': {
'mp4': 'libx264 + aac',
'webm': 'libvpx + libvorbis',
'avi': 'mpeg4 + mp3'
}
}
# 使用示例
print(get_video_info('input.mp4'))
print(supported_formats())
完整示例:GUI版本
import tkinter as tk
from tkinter import filedialog, ttk
import threading
from moviepy.editor import VideoFileClip
class VideoConverterGUI:
def __init__(self, root):
self.root = root
self.root.title("视频格式转换工具")
self.root.geometry("500x400")
# 创建界面元素
self.create_widgets()
def create_widgets(self):
# 文件选择
tk.Label(self.root, text="选择视频文件:").pack(pady=10)
self.file_path = tk.StringVar()
tk.Entry(self.root, textvariable=self.file_path, width=50).pack(padx=20)
tk.Button(self.root, text="浏览", command=self.select_file).pack(pady=5)
# 输出格式选择
tk.Label(self.root, text="输出格式:").pack(pady=10)
self.output_format = tk.StringVar(value="mp4")
formats = ["mp4", "avi", "mov", "mkv", "webm"]
ttk.Combobox(self.root, textvariable=self.output_format,
values=formats, state="readonly").pack()
# 质量设置
tk.Label(self.root, text="视频质量:").pack(pady=10)
self.quality = tk.IntVar(value=50)
quality_scale = tk.Scale(self.root, from_=10, to=100,
variable=self.quality, orient=tk.HORIZONTAL,
length=300)
quality_scale.pack()
# 转换按钮
self.convert_btn = tk.Button(self.root, text="开始转换",
command=self.start_conversion)
self.convert_btn.pack(pady=20)
# 进度条
self.progress = ttk.Progressbar(self.root, length=300, mode='determinate')
self.progress.pack(pady=10)
# 状态显示
self.status_label = tk.Label(self.root, text="就绪")
self.status_label.pack()
def select_file(self):
filename = filedialog.askopenfilename(
title="选择视频文件",
filetypes=[("视频文件", "*.mp4 *.avi *.mov *.mkv *.flv *.wmv")]
)
if filename:
self.file_path.set(filename)
def start_conversion(self):
if not self.file_path.get():
self.status_label.config(text="请先选择视频文件")
return
# 在新线程中执行转换
thread = threading.Thread(target=self.convert_video)
thread.daemon = True
thread.start()
def convert_video(self):
try:
self.convert_btn.config(state="disabled")
self.status_label.config(text="正在转换...")
input_path = self.file_path.get()
base_name = os.path.splitext(input_path)[0]
output_path = f"{base_name}.{self.output_format.get()}"
# 根据质量设置比特率
bitrate = f"{self.quality.get() * 100}k"
video = VideoFileClip(input_path)
video.write_videofile(
output_path,
codec='libx264',
audio_codec='aac',
bitrate=bitrate,
logger=None
)
video.close()
self.status_label.config(text=f"转换完成: {os.path.basename(output_path)}")
except Exception as e:
self.status_label.config(text=f"转换失败: {str(e)}")
finally:
self.convert_btn.config(state="normal")
self.progress['value'] = 100
if __name__ == "__main__":
root = tk.Tk()
app = VideoConverterGUI(root)
root.mainloop()
性能优化建议
-
使用硬件加速:
options = { 'vcodec': 'h264_nvenc', # NVIDIA GPU加速 # 或 'vcodec': 'h264_amf' # AMD GPU加速 } -
多线程处理:
def convert_batch(input_files): with ThreadPoolExecutor(max_workers=4) as executor: list(executor.map(process_video, input_files)) -
内存优化:
# 处理大文件时分段读取 video = VideoFileClip(input_path, audio=True, target_resolution=(1080, 1920))
这些案例涵盖了从基础到高级的视频转码需求,你可以根据具体需求选择合适的实现方式,需要注意的是,视频转码是计算密集型任务,建议对处理时间有合理预期。