FFmpeg 多媒体处理教程 / 批量处理
批量处理
概述
批量处理(Batch Processing)是指对大量多媒体文件进行自动化处理的技术。本章介绍如何使用 FFmpeg 进行高效的批量处理,包括脚本编写、并行处理、进度监控和错误处理。
基础脚本
简单批量转码
#!/bin/bash
# simple_batch.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
echo "处理: $filename"
ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output"
done
echo "批量处理完成"
带进度显示的批量脚本
#!/bin/bash
# batch_with_progress.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
mkdir -p "$OUTPUT_DIR"
# 统计文件数量
total=$(find "$INPUT_DIR" -name "*.mp4" | wc -l)
current=0
for file in "$INPUT_DIR"/*.mp4; do
current=$((current + 1))
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
echo "[$current/$total] 处理: $filename"
ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null
if [ $? -eq 0 ]; then
echo " ✓ 成功"
else
echo " ✗ 失败"
fi
done
echo "批量处理完成"
格式转换批量脚本
#!/bin/bash
# batch_convert.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
INPUT_FORMAT=${3:-avi}
OUTPUT_FORMAT=${4:-mp4}
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*."$INPUT_FORMAT"; do
filename=$(basename "$file" ".$INPUT_FORMAT")
output="$OUTPUT_DIR/${filename}.${OUTPUT_FORMAT}"
echo "转换: $filename"
ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output"
done
并行处理
使用 GNU Parallel
#!/bin/bash
# parallel_batch.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
MAX_JOBS=${3:-4}
mkdir -p "$OUTPUT_DIR"
# 定义处理函数
process_file() {
local file=$1
local filename=$(basename "$file")
local output="$OUTPUT_DIR/$filename"
ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null
if [ $? -eq 0 ]; then
echo "✓ $filename"
else
echo "✗ $filename"
fi
}
export -f process_file
export OUTPUT_DIR
# 使用 GNU Parallel 并行处理
find "$INPUT_DIR" -name "*.mp4" | parallel -j "$MAX_JOBS" process_file
echo "并行处理完成"
使用 xargs 并行
#!/bin/bash
# xargs_parallel.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
MAX_JOBS=${3:-4}
mkdir -p "$OUTPUT_DIR"
process_file() {
local file=$1
local filename=$(basename "$file")
local output="$OUTPUT_DIR/$filename"
ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null
echo "完成: $filename"
}
export -f process_file
export OUTPUT_DIR
find "$INPUT_DIR" -name "*.mp4" -print0 | xargs -0 -P "$MAX_JOBS" -I {} bash -c 'process_file "$@"' _ {}
使用后台进程
#!/bin/bash
# background_jobs.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
MAX_JOBS=${3:-4}
mkdir -p "$OUTPUT_DIR"
job_count=0
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
# 后台处理
(
ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null
echo "完成: $filename"
) &
job_count=$((job_count + 1))
# 限制并发数
if [ $job_count -ge $MAX_JOBS ]; then
wait -n
job_count=$((job_count - 1))
fi
done
# 等待所有任务完成
wait
echo "并行处理完成"
进度监控
使用 FFmpeg 进度输出
#!/bin/bash
# progress_monitor.sh
INPUT=$1
OUTPUT=$2
# 获取视频时长
duration=$(ffprobe -v quiet -show_entries format=duration -of csv=p=0 "$INPUT")
ffmpeg -y -i "$INPUT" -c:v libx264 -crf 23 -c:a aac "$OUTPUT" 2>&1 | while read line; do
if echo "$line" | grep -q "time="; then
# 提取当前时间
current_time=$(echo "$line" | grep -oP 'time=\K[0-9:\.]+')
# 转换为秒
current_seconds=$(echo "$current_time" | awk -F: '{print $1*3600+$2*60+$3}')
# 计算进度百分比
progress=$(echo "scale=2; $current_seconds / $duration * 100" | bc)
echo -ne "\r进度: ${progress}%"
fi
done
echo ""
echo "处理完成"
使用 tqdm 进度条
#!/bin/bash
# tqdm_progress.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
mkdir -p "$OUTPUT_DIR"
# 安装 tqdm(如果未安装)
# pip install tqdm
# 创建文件列表
find "$INPUT_DIR" -name "*.mp4" > /tmp/file_list.txt
# 使用 tqdm 显示进度
cat /tmp/file_list.txt | while read file; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null
echo "$filename" >> /tmp/processed.txt
done | tqdm --total=$(wc -l < /tmp/file_list.txt) --unit=文件
rm -f /tmp/file_list.txt /tmp/processed.txt
日志记录
#!/bin/bash
# logging_batch.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
LOG_FILE=${3:-batch.log}
mkdir -p "$OUTPUT_DIR"
# 初始化日志
echo "批量处理开始: $(date)" > "$LOG_FILE"
echo "输入目录: $INPUT_DIR" >> "$LOG_FILE"
echo "输出目录: $OUTPUT_DIR" >> "$LOG_FILE"
echo "---" >> "$LOG_FILE"
success_count=0
fail_count=0
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
echo "处理: $filename" >> "$LOG_FILE"
if ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>>"$LOG_FILE"; then
echo " ✓ 成功" >> "$LOG_FILE"
success_count=$((success_count + 1))
else
echo " ✗ 失败" >> "$LOG_FILE"
fail_count=$((fail_count + 1))
fi
done
echo "---" >> "$LOG_FILE"
echo "批量处理完成: $(date)" >> "$LOG_FILE"
echo "成功: $success_count" >> "$LOG_FILE"
echo "失败: $fail_count" >> "$LOG_FILE"
echo "日志文件: $LOG_FILE"
错误处理
基本错误处理
#!/bin/bash
# error_handling.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
# 检查输入文件是否存在
if [ ! -f "$file" ]; then
echo "错误: 文件不存在 - $filename"
continue
fi
# 检查文件大小
if [ ! -s "$file" ]; then
echo "错误: 文件为空 - $filename"
continue
fi
# 处理文件
if ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null; then
echo "✓ $filename"
else
echo "✗ $filename"
fi
done
重试机制
#!/bin/bash
# retry_mechanism.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
MAX_RETRIES=${3:-3}
mkdir -p "$OUTPUT_DIR"
process_with_retry() {
local file=$1
local output=$2
local retries=0
while [ $retries -lt $MAX_RETRIES ]; do
if ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null; then
return 0
fi
retries=$((retries + 1))
echo " 重试 $retries/$MAX_RETRIES"
sleep 1
done
return 1
}
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
echo "处理: $filename"
if process_with_retry "$file" "$output"; then
echo " ✓ 成功"
else
echo " ✗ 失败(已重试 $MAX_RETRIES 次)"
fi
done
超时处理
#!/bin/bash
# timeout_handling.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
TIMEOUT=${3:-300} # 5 分钟超时
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
echo "处理: $filename"
# 使用 timeout 命令
if timeout "$TIMEOUT" ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null; then
echo " ✓ 成功"
else
exit_code=$?
if [ $exit_code -eq 124 ]; then
echo " ✗ 超时(${TIMEOUT}秒)"
rm -f "$output" # 删除不完整的输出
else
echo " ✗ 失败"
fi
fi
done
断点续传
#!/bin/bash
# resume_batch.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
CHECKPOINT_FILE=${3:-checkpoint.txt}
mkdir -p "$OUTPUT_DIR"
# 加载检查点
if [ -f "$CHECKPOINT_FILE" ]; then
echo "加载检查点: $CHECKPOINT_FILE"
processed_files=$(cat "$CHECKPOINT_FILE")
else
processed_files=""
fi
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
# 检查是否已处理
if echo "$processed_files" | grep -q "$filename"; then
echo "跳过: $filename(已处理)"
continue
fi
echo "处理: $filename"
if ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null; then
echo " ✓ 成功"
echo "$filename" >> "$CHECKPOINT_FILE"
else
echo " ✗ 失败"
fi
done
echo "批量处理完成"
高级批量处理
多格式输出
#!/bin/bash
# multi_format_output.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
mkdir -p "$OUTPUT_DIR/mp4" "$OUTPUT_DIR/webm" "$OUTPUT_DIR/avi"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file" .mp4)
echo "处理: $filename"
# MP4 输出
ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$OUTPUT_DIR/mp4/${filename}.mp4" 2>/dev/null
# WebM 输出
ffmpeg -y -i "$file" -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus "$OUTPUT_DIR/webm/${filename}.webm" 2>/dev/null
# AVI 输出
ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a libmp3lame "$OUTPUT_DIR/avi/${filename}.avi" 2>/dev/null
done
多分辨率输出
#!/bin/bash
# multi_resolution.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
mkdir -p "$OUTPUT_DIR/1080p" "$OUTPUT_DIR/720p" "$OUTPUT_DIR/480p"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
echo "处理: $filename"
# 1080p
ffmpeg -y -i "$file" -vf scale=1920:1080 -c:v libx264 -crf 23 -c:a aac "$OUTPUT_DIR/1080p/$filename" 2>/dev/null
# 720p
ffmpeg -y -i "$file" -vf scale=1280:720 -c:v libx264 -crf 23 -c:a aac "$OUTPUT_DIR/720p/$filename" 2>/dev/null
# 480p
ffmpeg -y -i "$file" -vf scale=854:480 -c:v libx264 -crf 23 -c:a aac "$OUTPUT_DIR/480p/$filename" 2>/dev/null
done
带滤镜的批量处理
#!/bin/bash
# batch_with_filter.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
FILTER=${3:-"scale=1280:720"}
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
echo "处理: $filename"
ffmpeg -y -i "$file" -vf "$FILTER" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null
done
批量添加水印
#!/bin/bash
# batch_watermark.sh
INPUT_DIR=${1:-.}
WATERMARK=${2:-watermark.png}
OUTPUT_DIR=${3:-output}
POSITION=${4:-"W-w-10:H-h-10"} # 右下角
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
echo "添加水印: $filename"
ffmpeg -y -i "$file" -i "$WATERMARK" \
-filter_complex "[0:v][1:v]overlay=$POSITION[v]" \
-map "[v]" -map 0:a \
-c:v libx264 -crf 23 -c:a copy \
"$output" 2>/dev/null
done
批量提取音频
#!/bin/bash
# batch_extract_audio.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-audio}
FORMAT=${3:-mp3}
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file" .mp4)
output="$OUTPUT_DIR/${filename}.${FORMAT}"
echo "提取音频: $filename"
case $FORMAT in
mp3)
ffmpeg -y -i "$file" -vn -c:a libmp3lame -q:a 2 "$output" 2>/dev/null
;;
aac)
ffmpeg -y -i "$file" -vn -c:a aac -b:a 192k "$output" 2>/dev/null
;;
wav)
ffmpeg -y -i "$file" -vn -c:a pcm_s16le "$output" 2>/dev/null
;;
flac)
ffmpeg -y -i "$file" -vn -c:a flac "$output" 2>/dev/null
;;
esac
done
批量提取缩略图
#!/bin/bash
# batch_thumbnail.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-thumbnails}
INTERVAL=${3:-10} # 每 10 秒提取一帧
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file" .mp4)
mkdir -p "$OUTPUT_DIR/$filename"
echo "提取缩略图: $filename"
ffmpeg -y -i "$file" -vf "fps=1/$INTERVAL" \
"$OUTPUT_DIR/$filename/thumb_%04d.jpg" 2>/dev/null
done
批量视频拼接
#!/bin/bash
# batch_concat.sh
INPUT_DIR=${1:-.}
OUTPUT=${2:-output.mp4}
# 创建文件列表
cat > /tmp/concat_list.txt << EOF
EOF
for file in "$INPUT_DIR"/*.mp4; do
echo "file '$(realpath "$file")'" >> /tmp/concat_list.txt
done
echo "拼接视频..."
ffmpeg -y -f concat -safe 0 -i /tmp/concat_list.txt -c copy "$OUTPUT"
rm -f /tmp/concat_list.txt
echo "拼接完成: $OUTPUT"
配置文件驱动
使用配置文件
#!/bin/bash
# config_driven_batch.sh
CONFIG_FILE=${1:-config.json}
# 读取配置
INPUT_DIR=$(jq -r '.input_dir' "$CONFIG_FILE")
OUTPUT_DIR=$(jq -r '.output_dir' "$CONFIG_FILE")
CODEC=$(jq -r '.codec' "$CONFIG_FILE")
CRF=$(jq -r '.crf' "$CONFIG_FILE")
PRESET=$(jq -r '.preset' "$CONFIG_FILE")
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
echo "处理: $filename"
ffmpeg -y -i "$file" -c:v "$CODEC" -crf "$CRF" -preset "$PRESET" -c:a aac "$output"
done
配置文件示例(config.json):
{
"input_dir": "./input",
"output_dir": "./output",
"codec": "libx264",
"crf": 23,
"preset": "medium",
"audio_codec": "aac",
"audio_bitrate": "128k"
}
YAML 配置
# config.yaml
input_dir: ./input
output_dir: ./output
video:
codec: libx264
crf: 23
preset: medium
max_bitrate: 5M
audio:
codec: aac
bitrate: 128k
sample_rate: 44100
#!/bin/bash
# yaml_config_batch.sh
CONFIG_FILE=${1:-config.yaml}
# 安装 yq(如果未安装)
# sudo apt install yq
INPUT_DIR=$(yq -r '.input_dir' "$CONFIG_FILE")
OUTPUT_DIR=$(yq -r '.output_dir' "$CONFIG_FILE")
CODEC=$(yq -r '.video.codec' "$CONFIG_FILE")
CRF=$(yq -r '.video.crf' "$CONFIG_FILE")
PRESET=$(yq -r '.video.preset' "$CONFIG_FILE")
AUDIO_CODEC=$(yq -r '.audio.codec' "$CONFIG_FILE")
AUDIO_BITRATE=$(yq -r '.audio.bitrate' "$CONFIG_FILE")
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
echo "处理: $filename"
ffmpeg -y -i "$file" \
-c:v "$CODEC" -crf "$CRF" -preset "$PRESET" \
-c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" \
"$output"
done
监控与报告
生成处理报告
#!/bin/bash
# batch_with_report.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
REPORT_FILE=${3:-report.html}
mkdir -p "$OUTPUT_DIR"
# 初始化报告
cat > "$REPORT_FILE" << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>批量处理报告</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #4CAF50; color: white; }
tr:nth-child(even) { background-color: #f2f2f2; }
.success { color: green; }
.failed { color: red; }
</style>
</head>
<body>
<h1>批量处理报告</h1>
<p>开始时间: $(date)</p>
<table>
<tr>
<th>文件名</th>
<th>原始大小</th>
<th>输出大小</th>
<th>压缩率</th>
<th>状态</th>
</tr>
EOF
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
original_size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null)
if ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null; then
output_size=$(stat -f%z "$output" 2>/dev/null || stat -c%s "$output" 2>/dev/null)
compression=$(echo "scale=2; (1 - $output_size / $original_size) * 100" | bc)
cat >> "$REPORT_FILE" << EOF
<tr>
<td>$filename</td>
<td>$(numfmt --to=iec $original_size)</td>
<td>$(numfmt --to=iec $output_size)</td>
<td>${compression}%</td>
<td class="success">✓ 成功</td>
</tr>
EOF
else
cat >> "$REPORT_FILE" << EOF
<tr>
<td>$filename</td>
<td>$(numfmt --to=iec $original_size)</td>
<td>-</td>
<td>-</td>
<td class="failed">✗ 失败</td>
</tr>
EOF
fi
done
# 完成报告
cat >> "$REPORT_FILE" << 'EOF'
</table>
<p>结束时间: $(date)</p>
</body>
</html>
EOF
echo "报告生成: $REPORT_FILE"
统计信息
#!/bin/bash
# batch_statistics.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
mkdir -p "$OUTPUT_DIR"
total_files=0
success_files=0
failed_files=0
total_input_size=0
total_output_size=0
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
total_files=$((total_files + 1))
original_size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null)
total_input_size=$((total_input_size + original_size))
if ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac "$output" 2>/dev/null; then
success_files=$((success_files + 1))
output_size=$(stat -f%z "$output" 2>/dev/null || stat -c%s "$output" 2>/dev/null)
total_output_size=$((total_output_size + output_size))
else
failed_files=$((failed_files + 1))
fi
done
echo "=== 批量处理统计 ==="
echo "总文件数: $total_files"
echo "成功: $success_files"
echo "失败: $failed_files"
echo "原始总大小: $(numfmt --to=iec $total_input_size)"
echo "输出总大小: $(numfmt --to=iec $total_output_size)"
echo "压缩率: $(echo "scale=2; (1 - $total_output_size / $total_input_size) * 100" | bc)%"
注意事项
- 资源管理:并行处理时注意 CPU 和内存使用
- 磁盘空间:确保有足够的磁盘空间存储输出文件
- 错误处理:完善的错误处理可以避免处理中断
- 日志记录:记录处理日志便于问题排查
- 断点续传:大批量处理时使用断点续传功能
业务场景
场景 1:视频网站批量转码
#!/bin/bash
# video_site_transcode.sh
INPUT_DIR=$1
OUTPUT_DIR=$2
MAX_JOBS=${3:-8}
mkdir -p "$OUTPUT_DIR/1080p" "$OUTPUT_DIR/720p" "$OUTPUT_DIR/480p"
transcode() {
local file=$1
local filename=$(basename "$file" .mp4)
# 1080p
ffmpeg -y -i "$file" -vf scale=1920:1080 \
-c:v libx264 -preset fast -crf 23 \
-c:a aac -b:a 192k \
"$OUTPUT_DIR/1080p/${filename}.mp4" 2>/dev/null
# 720p
ffmpeg -y -i "$file" -vf scale=1280:720 \
-c:v libx264 -preset fast -crf 23 \
-c:a aac -b:a 128k \
"$OUTPUT_DIR/720p/${filename}.mp4" 2>/dev/null
# 480p
ffmpeg -y -i "$file" -vf scale=854:480 \
-c:v libx264 -preset fast -crf 23 \
-c:a aac -b:a 96k \
"$OUTPUT_DIR/480p/${filename}.mp4" 2>/dev/null
echo "完成: $filename"
}
export -f transcode
export OUTPUT_DIR
find "$INPUT_DIR" -name "*.mp4" | parallel -j "$MAX_JOBS" transcode
场景 2:监控录像批量处理
#!/bin/bash
# surveillance_batch.sh
INPUT_DIR=$1
OUTPUT_DIR=$2
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/$filename"
# 压缩并添加时间戳
ffmpeg -y -i "$file" \
-vf "scale=640:360,drawtext=text='%{localtime\:%Y-%m-%d %H\\\:%M\\\:%S}':x=10:y=10:fontsize=16:fontcolor=white" \
-c:v libx264 -preset fast -crf 28 \
-an \
"$output" 2>/dev/null
done
场景 3:社交媒体批量发布
#!/bin/bash
# social_media_batch.sh
INPUT_DIR=$1
OUTPUT_DIR=$2
mkdir -p "$OUTPUT_DIR/instagram" "$OUTPUT_DIR/tiktok" "$OUTPUT_DIR/youtube"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file" .mp4)
# Instagram (1:1)
ffmpeg -y -i "$file" \
-vf "scale=1080:1080:force_original_aspect_ratio=decrease,pad=1080:1080:(ow-iw)/2:(oh-ih)/2" \
-c:v libx264 -crf 23 -c:a aac \
"$OUTPUT_DIR/instagram/${filename}.mp4" 2>/dev/null
# TikTok (9:16)
ffmpeg -y -i "$file" \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2" \
-c:v libx264 -crf 23 -c:a aac \
"$OUTPUT_DIR/tiktok/${filename}.mp4" 2>/dev/null
# YouTube (16:9)
ffmpeg -y -i "$file" \
-vf scale=1920:1080 \
-c:v libx264 -crf 23 -c:a aac \
"$OUTPUT_DIR/youtube/${filename}.mp4" 2>/dev/null
done
扩展阅读
总结
本章介绍了 FFmpeg 的批量处理技术,包括:
- 基础批量脚本
- 并行处理方法
- 进度监控技巧
- 错误处理机制
- 高级批量处理功能
掌握批量处理技术可以大幅提高视频处理效率,特别适合需要处理大量视频的场景。