
在多媒体时代,每天都需要处理大量的音视频文件:格式转换、压缩、剪辑、提取音频……如果手动操作,不仅效率低下,还容易出错。而将FFmpeg与Shell脚本结合,就像是给多媒体处理装上了火箭发动机——一个命令即可批量处理上千文件,自动化完成复杂任务。
本文将带你从入门到精通,掌握Shell脚本中FFmpeg的实战技巧,构建属于自己的多媒体处理流水线。
FFmpeg是开源的多媒体处理框架,被誉为多媒体领域的"瑞士军刀"。它能解码、编码、转码、封装、解封装、流媒体、过滤和播放几乎所有格式的音视频文件。
ffmpeg [全局选项] {[输入文件选项] -i 输入文件} ... {[输出文件选项] 输出文件} ...四大核心工具:
ffmpeg:核心转码工具ffplay:简易播放器(测试用)ffprobe:媒体信息分析工具ffserver:流媒体服务器(已废弃)#!/bin/bash# 动态输入输出input_file="video.mp4"output_file="output.avi"ffmpeg -i "$input_file""$output_file"最佳实践: 始终用双引号包裹变量,防止文件名含空格导致失败!
# 批量转换mp4到webmfor video in *.mp4; do ffmpeg -i "$video""${video%.mp4}.webm"done技巧:${video%.mp4} 是Shell的参数扩展语法,删除文件名末尾的.mp4。
# 利用所有CPU核心并行转码ls *.mov | xargs -P$(nproc) -I{} ffmpeg -i {} {}.mp4-P$(nproc) 自动检测CPU核心数,实现真正的并行处理!
ffmpeg -i input.mp4 output.mp4 2>&1 | grep --line-buffered -o "time=[0-9:.]*" | whileread -r line; doecho"处理进度: $line"done#!/bin/bashset -e # 遇到错误立即退出if ! ffmpeg -i "$1" -c:v libx264 "$2"; thenecho"错误:转码失败!" >&2exit 1fi#!/bin/bash# 智能压缩视频,保持可接受的质量compress_video() {local input="$1"local output="${input%.mp4}_compressed.mp4" ffmpeg -i "$input" \ -c:v libx264 -crf 28 -preset medium \ -c:a aac -b:a 128k \ -movflags +faststart \"$output"echo"✅ 压缩完成:$output"}# 批量压缩for f in *.mp4; do compress_video "$f"; done参数解析:
-crf 28:恒定质量模式,28是性价比平衡点(0-51,越低质量越好)-preset medium:编码速度与压缩率的平衡-movflags +faststart:网页边下边播必备#!/bin/bash# 从视频中提取12张截图并拼接成网格create_thumbnail_grid() {local video="$1"local duration=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$video")local interval=$(echo"$duration / 12" | bc -l)# 提取帧 ffmpeg -i "$video" -vf "fps=1/$interval" -vframes 12 thumbnails_%03d.png# 拼接成网格(4x3) montage thumbnails_*.png -tile 4x3 -geometry +2+2 grid_"$video".png# 清理临时文件rm thumbnails_*.pngecho"🖼️ 缩略图网格已生成:grid_$video.png"}#!/bin/bash# 每10分钟保存一段,自动删除旧文件whiletrue; do timestamp=$(date +%Y%m%d_%H%M%S) ffmpeg -i rtsp://camera_ip:554/stream \ -c:v copy -c:a copy \ -f segment -segment_time 600 \ -reset_timestamps 1 \ -strftime 1 \"record_%Y%m%d_%H%M%S.mp4" &# 只保留最近24小时的文件 find . -name "record_*.mp4" -mtime +1 -deletesleep 600done#!/bin/bash# 批量提取音频、降噪、加淡入淡出process_audio() {local video="$1"local audio="${video%.mp4}.wav"# 提取音频 ffmpeg -i "$video" -vn -acodec pcm_s16le "$audio"# 降噪(需要提前采样噪音) sox "$audio""${audio%.wav}_clean.wav" noisered noise.prof 0.21# 加淡入淡出(各2秒) sox "${audio%.wav}_clean.wav""${audio%.wav}_final.wav" fade t 2 0 2echo"🎵 音频处理完成:${audio%.wav}_final.wav"}#!/bin/bash# 从视频中提取精彩片段生成GIFvideo_to_gif() {local video="$1"local start_time="$2"# 00:01:30local duration="$3"# 5秒local width=480 # 宽度 ffmpeg -ss "$start_time" -t "$duration" -i "$video" \ -vf "fps=15,scale=${width}:-1:flags=lanczos, split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \ -loop 0 \"${video%.mp4}.gif"echo"🎬 GIF生成完成:${video%.mp4}.gif"}# 使用示例video_to_gig "funny.mp4""00:00:10""3"# 同时实现:缩放、加水印、调亮度ffmpeg -i input.mp4 -vf " scale=1280:-1, movie=logo.png[watermark];[in][watermark]overlay=main_w-overlay_w-10:10, eq=brightness=0.1:saturation=1.2" output.mp4#!/bin/bashdetect_and_convert() {local file="$1"local codec=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of csv=p=0 "$file")case"$codec"in"h264") echo"已是H.264格式,无需转换" ;;"hevc") ffmpeg -i "$file" -c:v libx264 "${file%.*}_h264.mp4" ;; *) ffmpeg -i "$file" -c:v libx264 "${file%.*}_converted.mp4" ;;esac}# 生成详细日志并统计处理时长process_with_log() {local start_time=$(date +%s) ffmpeg -i "$1" -c:v libx264 "$2" -loglevel info -report 2> ffmpeg_$(date +%Y%m%d).loglocal end_time=$(date +%s)echo"处理耗时:$((end_time - start_time))秒" >> process.log}# 创建预设配置文件 ~/.ffmpeg-presets# [mobile]# vcodec=libx264# crf=30# preset=fast# acodec=aac# ab=96k# 使用预设ffmpeg -i input.mp4 $(cat ~/.ffmpeg-presets | sed -n '/\[mobile\]/,/\[/p' | grep -v '[') output.mp4# Intel QSV加速ffmpeg -hwaccel qsv -i input.mp4 -c:v h264_qsv output.mp4# NVIDIA NVENC加速ffmpeg -hwaccel cuda -i input.mp4 -c:v h264_nvenc output.mp4# AMD AMF加速ffmpeg -hwaccel d3d11va -i input.mp4 -c:v h264_amf output.mp4# 限制内存使用(适合服务器环境)ffmpeg -i input.mp4 -max_alloc 20971520 -threads 2 output.mp4# 避免文件名注入攻击# 错误示范:ffmpeg -i $user_input # 危险!# 正确做法:ffmpeg -i "$(printf '%q' "$user_input")" output.mp4#!/bin/bash# watch_and_convert.sh - 监控目录自动转码WATCH_DIR="/mnt/media/upload"PROCESSED_DIR="/mnt/media/converted"inotifywait -m -e create --format '%w%f'"$WATCH_DIR" | whileread NEW_FILE; doecho"检测到新文件:$NEW_FILE"# 等待文件写入完成while lsof "$NEW_FILE" > /dev/null 2>&1; dosleep 1done# 根据文件类型处理case"$NEW_FILE"in *.mp4|*.mov|*.avi) ffmpeg -i "$NEW_FILE" -c:v libx264 -preset fast "$PROCESSED_DIR/$(basename "$NEW_FILE" | cut -d. -f1).mp4" & ;; *.wav|*.flac) ffmpeg -i "$NEW_FILE" -c:a libmp3lame -b:a 320k "$PROCESSED_DIR/$(basename "$NEW_FILE" | cut -d. -f1).mp3" & ;;esacdone启动服务:
nohup ./watch_and_convert.sh > media_service.log 2>&1 &Unknown encoder 'libx264' | sudo apt-get install libx264-dev | |
Invalid data found | ffprobe检查文件完整性 | |
-async 1 -vsync 1参数 | ||
-max_alloc限制内存 |
通过本文的学习,你已经掌握了:
下一步行动:
parallel命令替代xargs获得更强并行能力记住,优秀的Shell脚本不仅是工具,更是艺术品。它能让你的多媒体处理工作从繁琐的重复劳动中解放出来,专注于创造更大的价值。
现在,打开终端,开始你的FFmpeg Shell编程之旅吧!🚀


"那个改变我一生的回车键":Shell中rm命令的毁灭性灾难实录与生存指南
Music拒绝付费!用Shell加mpv打造Linux终端音乐播放器,实现真正的听歌自由
Shell函数还能当参数?这3个用法让我的运维脚本效率提升5倍





点分享

点收藏

点点赞

点推荐