一、下载和配置ffmpeg所需环境
1.下载ffmpeg
对于Windows,最推荐的来源是 gyan.dev
打开浏览器,访问 https://www.gyan.dev/ffmpeg/builds/
选择并下载文件:
您会看到多个版本。请在 “release builds” 部分找到名为 ffmpeg-release-full.7z 的文件并点击下载。这个“full”版本包含了所有常用的库和功能。
2.解压文件:
下载的是一个 .7z 压缩包,您可能需要安装 7-Zip 或 Bandizip 等免费解压软件来打开它。
将压缩包解压到一个永久、简单的位置。例如,直接解压到 C: 盘根目录,并将其重命名为 ffmpeg。
最终,您的 ffmpeg.exe 文件应该位于类似 C:\ffmpeg\bin\ffmpeg.exe 的路径下。
3.配置环境变量 (最关键的一步):
为了能在任何位置使用 ffmpeg 命令,您需要将它所在的 bin 文件夹路径添加到系统环境变量中。
按下键盘上的 Win 键,直接输入“环境变量”,然后选择“编辑系统环境变量”。
在弹出的“系统属性”窗口中,点击右下角的“环境变量…”按钮。
在下方的“系统变量”区域里,找到并双击名为 Path 的变量。
在弹出的“编辑环境变量”窗口中,点击右上角的“新建”。
将您刚才解压的 bin 文件夹的完整路径(例如 C:\ffmpeg\bin)粘贴进去。
一路点击“确定”保存所有窗口。
4.验证安装:
重新打开一个新的命令提示符(CMD)或 PowerShell 窗口(注意:必须是新的,旧的窗口不会加载新的环境变量)。
输入以下命令并按回车:
ffmpeg -version
如果您看到一大段关于 ffmpeg 版本和库的信息输出,而不是“不是内部或外部命令”,那么恭喜您,安装成功!
二、使用Powershell执行脚本(脚本如下,记得修改用户配置区域)
1.批量m4a转mp3
# ===================================================================
# --- 用户配置区域 ---
# ===================================================================
# 1. 【请修改这里】指定您存放音视频文件的【源文件夹】路径
$sourceFolder = “源文件夹路径”
# 2. 【请修改这里】指定您希望存放 MP3 文件的【输出文件夹】路径
$outputFolder = “目标文件夹路径”
# 3. 【新增可选修改】是否要压缩源文件夹中已存在的 MP3 文件?
# 设置为 $true - 脚本会处理 .m4a 和 .mp3 文件,将它们统一转换为目标质量的 MP3。
# 设置为 $false - 脚本将只转换 .m4a 文件,忽略所有 .mp3 文件 (原始功能)。
$processExistingMP3s = $true
# 4. 【新增可选修改】设置输出 MP3 的质量参数 (此设置对 M4A 转换和 MP3 压缩同时生效)
# 方案A (推荐, 动态比特率): 使用 -q:a 4 到 -q:a 6 之间的值。数值越大,文件越小,音质越低。
# “-q:a 5” (约 130kbps) 是音质和体积的绝佳平衡点。
# 方案B (固定比特率): 使用 “-b:a 128k”, “-b:a 192k” 等。
$ffmpegQualityArgs = “-q:a 5”
# 5. 【可选修改】在这里设置你想同时运行的线程数 (推荐设置为您的 CPU 核心数)
$maxJobs = 4
# ===================================================================
# --- 脚本主体 (以下部分无需修改) ---
# ===================================================================
# 检查源文件夹是否存在
if (-not (Test-Path -Path $sourceFolder -PathType Container)) {
Write-Host “错误:指定的源文件夹不存在,请检查路径: $sourceFolder” -ForegroundColor Red
Read-Host “按回车键退出”
exit
}
# 检查输出文件夹是否存在,如果不存在则创建它
if (-not (Test-Path -Path $outputFolder -PathType Container)) {
Write-Host “指定的输出文件夹不存在,将自动创建: $outputFolder” -ForegroundColor Yellow
try {
New-Item -ItemType Directory -Path $outputFolder -ErrorAction Stop | Out-Null
} catch {
Write-Host “错误:无法创建输出文件夹,请检查路径或权限。” -ForegroundColor Red
Read-Host “按回车键退出”
exit
}
}
# 【新增安全检查】如果处理 MP3 且源和输出文件夹相同,则停止以防覆盖
if ($processExistingMP3s -and ($sourceFolder.TrimEnd(’\’) -eq $outputFolder.TrimEnd(’\’))) {
Write-Host “错误:为了防止意外覆盖原始文件,当 ’`$processExistingMP3s’ 设置为 `$true 时,” -ForegroundColor Red
Write-Host “【源文件夹】和【输出文件夹】不能是同一个路径。” -ForegroundColor Red
Read-Host “按回车键退出”
exit
}
# 根据配置获取要处理的文件列表
$fileTypes = @(“*.m4a”)
$modeMessage = “模式:仅转换 M4A 文件”
if ($processExistingMP3s) {
$fileTypes += “*.mp3”
$modeMessage = “模式:转换 M4A 文件并压缩 MP3 文件”
}
Write-Host $modeMessage -ForegroundColor Cyan
$files = Get-ChildItem -Path (Join-Path -Path $sourceFolder -ChildPath ’*’) -File -Include $fileTypes
# 检查是否有文件需要处理
if ($files.Count -eq 0) {
Write-Host “在指定的源文件夹中没有找到任何需要处理的文件。” -ForegroundColor Yellow
Read-Host “按回车键退出”
exit
}
Write-Host “找到 $($files.Count) 个文件,准备开始处理…”
# 循环处理文件
foreach ($file in $files) {
$outputName = Join-Path -Path $outputFolder -ChildPath ($file.BaseName + “.mp3”)
if (Test-Path -Path $outputName) {
Write-Host “跳过,目标文件已存在: $($outputName)” -ForegroundColor Gray
continue
}
while (@(Get-Job -State Running).Count -ge $maxJobs) {
Start-Sleep -Seconds 1
}
Write-Host “开始处理: $($file.Name)” -ForegroundColor Green
# 【已修正】使用 ArgumentList 和 param 块来稳定地向后台任务传递参数
Start-Job -ScriptBlock {
param(
$p_inputFile,
$p_outputFile,
$p_qualityArgs
)
# 将质量参数字符串分割成数组,以便正确传递给 ffmpeg.exe
$ffmpegParams = $p_qualityArgs.Split(’ ’)
# -y: 覆盖, -i: 输入, -vn: 无视频, -acodec libmp3lame: MP3编码器, -loglevel error: 精简输出
ffmpeg -y -i “$p_inputFile” -vn -acodec libmp3lame $ffmpegParams “$p_outputFile” -loglevel error
} -ArgumentList $file.FullName, $outputName, $ffmpegQualityArgs
}
# 等待所有剩余的任务完成
Write-Host “所有任务已启动,正在后台处理,请稍候…”
while (Get-Job) {
Get-Job | Wait-Job -Any | ForEach-Object {
# 检查任务是否有错误输出
if ($.State -eq ‘Failed’ -or $.ChildJobs[0].Error.Count -gt 0) {
# 从 Job 的 Name 属性中提取原始文件名 (这是一个小技巧,因为 Start-Job 默认用 JobN 命名)
# 我们在处理循环中没有给Job命名,所以这个方法无效,但保留错误输出依然重要。
Write-Host “一个任务处理失败:” -ForegroundColor Red
# 输出详细错误
$_ | Receive-Job | ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
Write-Host $_.ToString() -ForegroundColor Red
}
}
}
# 接收并移除任务
Receive-Job $_ | Out-Null
Remove-Job $_
}
}
Write-Host “全部处理完成!转换/压缩后的 MP3 文件已保存在 ‘$outputFolder’ 文件夹中。” -ForegroundColor Magenta
Read-Host “按回车键退出” #===================================================================
2.批量m4a转flac
# =================================================================== # --- 用户配置区域 --- # ===================================================================
# 1. 【请修改这里】指定您存放m4a文件的【源文件夹】路径 $sourceFolder = “请在这里粘贴您的源文件夹路径”
# 2. 【请修改这里】指定您希望存放FLAC文件的【输出文件夹】路径 $outputFolder = “请在这里粘贴您的输出文件夹路径”
# 3. 【可选修改】在这里设置你想同时运行的线程数 (推荐设置为您的CPU核心数) $maxJobs = 4
# =================================================================== # --- 脚本主体 (以下部分无需修改) --- # ===================================================================
# 检查源文件夹是否存在 if (-not (Test-Path -Path $sourceFolder -PathType Container)) { Write-Host “错误:指定的源文件夹不存在,请检查路径: $sourceFolder” -ForegroundColor Red Read-Host “按回车键退出” exit }
# 检查输出文件夹是否存在,如果不存在则创建它 if (-not (Test-Path -Path $outputFolder -PathType Container)) { Write-Host “指定的输出文件夹不存在,将自动创建: $outputFolder” -ForegroundColor Yellow try { New-Item -ItemType Directory -Path $outputFolder -ErrorAction Stop | Out-Null } catch { Write-Host “错误:无法创建输出文件夹,请检查路径或权限。” -ForegroundColor Red Read-Host “按回车键退出” exit } }
# 获取所有m4a文件 $files = Get-ChildItem -Path $sourceFolder -Filter *.m4a
# 检查是否有m4a文件需要转换 if ($files.Count -eq 0) { Write-Host “在指定的源文件夹中没有找到任何 .m4a 文件。” -ForegroundColor Yellow Read-Host “按回车键退出” exit }
Write-Host “找到 $($files.Count) 个 .m4a 文件,准备开始转换为 FLAC…”
# 循环处理文件 foreach ($file in $files) { # 构造输出文件名 $outputName = Join-Path -Path $outputFolder -ChildPath ($file.BaseName + “.flac”)
# 如果同名的flac文件已经存在,则跳过 if (Test-Path -Path $outputName) { Write-Host “跳过已存在的文件: $($file.Name)” -ForegroundColor Cyan continue }
# 等待直到当前运行的任务数小于最大值 while (@(Get-Job -State Running).Count -ge $maxJobs) { Start-Sleep -Seconds 1 }
# 在后台启动一个新的ffmpeg转换任务 Write-Host “开始转换: $($file.Name) -> $($outputName)” -ForegroundColor Green Start-Job -ScriptBlock { # 接收传递过来的参数 param($inputFile, $outputFile) # 执行ffmpeg命令,-y 参数可以覆盖不完整的旧文件,-vn 移除视频流 # -acodec flac 指定使用flac编码器 # -loglevel error 只显示错误信息,让界面更干净 ffmpeg -y -i “$inputFile” -vn -acodec flac “$outputFile” -loglevel error } -ArgumentList $file.FullName, $outputName }
# 等待所有剩余的任务完成 Write-Host “所有任务已启动,正在后台处理,请稍候…” while (@(Get-Job).Count -gt 0) { # 等待任务完成,然后接收并移除,释放内存 Get-Job | Wait-Job -Any | Receive-Job # 移除已完成或失败的任务 Get-Job | Where-Object { $_.State -ne ‘Running’ } | Remove-Job }
Write-Host “全部转换完成!转换后的FLAC文件已保存在 ‘$outputFolder’ 文件夹中。” -ForegroundColor Magenta Read-Host “按回车键退出”