用 ffmpeg 转换常见格式音频为 mp3
1. 起因
我们下载的 wma 格式的音频,在安卓下不可见,但是在 windows 上能播放
[滤镜使用列表]
(1) Built-in ASF/WMV Source
(2) Built-in Audio Codec/Transform
(3) DirectSound Audio Renderer
[音频信息]
音频编码: WMA V2(0x161) - OpenCodec(System DMO Decoder)
采样率: 44100 -> 44100 Hz
位率: 16 -> 16 位
声道数: 2 -> 2 声道
Bitrate: 128 kbps
安卓下没有正式授权的wma解码器
2. ffmpeg 转换
以下脚本都在 linux 下运行
2.1. 常见的音频转换脚本
这个脚本是放在一个文件夹下去使用
#!/bin/bash
# 确保ffmpeg已安装
if ! command -v ffmpeg &> /dev/null; then
echo "ffmpeg not found. Please install ffmpeg first."
exit 1
fi
# 遍历目录下所有常见的音频文件
for i in *.wav *.wma *.aac *.flac *.ogg; do
# 检查文件是否存在
if [ -f "$i" ]; then
# 构建输出文件名,保留原文件名并替换扩展名为.mp3
output="${i%.*}.mp3"
# 使用ffmpeg转换音频文件为MP3
ffmpeg -i "$i" -vn -ab 128k -ar 44100 "$output"
# 检查转换是否成功
if [ $? -eq 0 ]; then
echo "Converted '$i' to '$output'"
else
echo "Failed to convert '$i'"
fi
fi
done
echo "All supported audio files have been converted to MP3."
2.2. 自定义mp3 参数脚本
这个脚本可以处理包含非常多子目录的文件夹,需要传递一个要转换文件夹的路径参数作为参数。
#!/bin/bash
# 定义ffmpeg的转换参数
FFMPEG_ARGS="-ab 128k -ar 44100 -acodec libmp3lame"
# 检查是否提供了目录参数
if [ "$#" -ne 1 ]; then
echo "Usage: $0 /path/to/your/audio/files"
exit 1
fi
# 获取传入的目录参数
AUDIO_DIR="$1"
# 使用find和ffmpeg命令进行转换和删除
find "$AUDIO_DIR" -type f \( -name "*.wav" -o -name "*.wma" -o -name "*.aac" -o -name "*.flac" -o -name "*.ogg" \) -exec bash -c '
input="$1"
output="${input%.*}.mp3"
ffmpeg -i "$input" $FFMPEG_ARGS "$output" &&
rm "$input"
' bash {} \;
echo "Conversion and cleanup complete."
3. 视频转换举例
for i in *.avi; do ffmpeg -i"$i""${i%.*}.mp4"; done
这个shell脚本段落的目的是批量将当前目录下的所有.avi
格式的视频文件转换为.mp4
格式。下面是逐部分的详细分析:
-
for i in *.avi; do
: 这是一个循环开始的声明,它遍历当前目录下所有扩展名为.avi
的文件。i
是循环变量,它在每次循环中会依次取到一个.avi
文件的名字。 -
ffmpeg -i "$i"
: 这一行是调用ffmpeg
命令,-i "$i"
表示将$i
(即当前循环中的.avi
文件)作为输入文件。 -
"${i%.*}.mp4"
: 这里是对变量$i
进行字符串操作,${i%.*}
会移除变量i
中从最后一个.
(点)开始到字符串结束的所有内容,也就是移除文件的扩展名。然后紧跟上.mp4
,从而形成一个新的文件名,即原始文件名去掉.avi
后加上.mp4
,作为输出文件名。 -
; done
: 这标志着循环的结束。;
用来分隔命令,而done
则告诉shell循环至此结束。
整个脚本的逻辑是:对于当前目录下的每一个.avi
文件,使用FFmpeg命令将其转换为同名的.mp4
文件。例如,如果目录中有文件example.avi
,这个脚本就会执行ffmpeg -i example.avi example.mp4
,将example.avi
转换为example.mp4
。这样的脚本极大地简化了对多个文件进行相同操作的任务。
好的,让我们一步步解析这个字符串操作表达式 ${i%.*}.mp4
:
-
变量引用: 首先,
${i}
是引用变量i
的值。在这个上下文中,i
代表循环中当前处理的.avi
文件的名称,比如movie1.avi
。 -
参数扩展操作符
%
:${i%pattern}
是Shell中的参数扩展操作符之一,称为“从尾部删除最短匹配”。这里的pattern
是.*
。当这个操作应用于变量i
的值时,它会寻找变量值中与pattern
匹配的部分,并从该匹配部分的最右边开始删除直到字符串末尾。- 在我们的例子中,
.*
匹配的是从最后一个.
开始直到字符串结束的任何字符序列。因此,对于movie1.avi
,.*
匹配的是.avi
。
- 在我们的例子中,
-
移除扩展名: 应用这个操作后,
${i%.*}
就会移除movie1.avi
中的.avi
部分,只剩下movie1
。 -
添加新扩展名: 紧接着,我们在移除扩展名后的结果后面直接加上
.mp4
,即形成了新的文件名movie1.mp4
。这就是转换后的目标文件名。
综上所述,${i%.*}.mp4
这个表达式的作用是,对于变量 i
中的每个文件名,它首先移除原有的 .avi
扩展名,然后添加上新的 .mp4
扩展名,从而生成一个新的文件名,用于指定 FFmpeg 转换后的输出文件名。这样,原始的 movie1.avi
文件在转换后会被保存为 movie1.mp4
。