出于兼容性原因,我尝试将导入的音乐集转换为 flac。无论如何,我使用以下命令进行转换:
ffmpeg -i file.m4a file.flac
现在从技术上讲,这可以正常工作,并将文件转换为 flac,但研究输出时我注意到原始文件(在此示例中,实际数量因音轨而异)显示音频流为:
Audio: alac (alac / 0x63616C61), 44100 Hz, stereo, s16p, 968 kb/s (default)
而新 flac 版本显示音频流为:
Audio: flac, 44100 Hz, stereo, s16, 128 kb/s (default)
我注意到两件事:第一是“s16p”已更改为“s16”,虽然我不知道这是什么意思,也不太在意,但让我困扰的是比特率大幅降低!从 968 降至 128。现在,每个音轨的比特率略有不同,但最终都输出为 128。这是 flac 的限制吗?如果不是,那么我该如何指示 ffmpeg 以原始比特率输出?
另外,如果它影响质量,那么 s16 和 s16p 指的是什么?
编辑:从技术上讲我得到了我想要的东西,但我仍然不知道 s16 是什么意思,而且我不能 100%确定我所做的是否正常,请查看我的答案以获取解释。
答案1
转换期间,不要留意输出显示的比特率 - 这仅当编码器的速率控制方法以比特率为目标时才有意义。FLAC 编码器则不然。在生成输出文件后,对其运行 ffprobe。它将显示实际编码的比特率。
FLAC 是一种无损编解码器,因此无论获得的比特率如何,它都是无损的,即相对于源具有相同的质量。
s16
并s16p
参考 ffmpeg 解码器为这些格式生成的样本格式。s16p
表示解码后的样本是有符号的 16 位整数,每个通道位于单独的平面中,即C1 C1 C1 C1
,C2 C2 C2 C2
而在 中s16
,它们以交错方式存储为C1 C2 C1 C2 C1 C2 C1 C2
。澄清一下,这是解码器生成的未压缩输出的布局和格式。文件中的实际数据是经过编码的(因此术语编码)。
答案2
我花了几个小时研究,发现了 ffprobe,一开始我忽略了它,因为我知道我写的命令最终会很长,但别无选择,我向你展示了我最终的、有效的 powershell 命令。当然,如果有人发现这可能会有问题,请告诉我,我不保证,但这是我想到的(这会递归转换当前目录中的所有 m4a alac 文件):
Get-ChildItem -Path . -filter *.m4a | ForEach-Object -Process {[System.IO.Path]::GetFileNameWithoutExtension($_)} | ForEach-Object -Process {ffmpeg.exe -i "$($_).m4a" -ab $(ffprobe -v error -i "$($_).m4a" -select_streams a:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1).replace("bit_rate=","") "$($_).flac"}
解释一下这个乱码是什么,试图帮助任何读到它的人:
Get-ChildItem -Path . -filter *.m4a
这本质上类似于 dir 命令,但它仅显示以 .m4a 结尾的文件。这将被导入:ForEach-Object -Process {[System.IO.Path]::GetFileNameWithoutExtensions($_)}
这将获取所有这些文件名并删除 .m4a。然后将其输入到:ForEach-Object -Process {ffmpeg -i "$($_).m4a"
这只是 ffmpeg 命令的开始,其中传递了文件名,并添加了 .m4a 扩展名-ab $(ffprobe -v error -i "$($_).m4a" -select_streams a:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1).replace("bit_rate=","")
这会将 m4a 文件发送到 ffprobe,后者输出bit_rate=aNumber
,然后从字符串中删除“bit_rate=”"$($_).flac"}
最后,再次将文件名提供给 ffmpeg,但这次使用 flac 扩展名作为输出文件。最后
再说一遍:我不能保证此命令会完全按照预期执行,我所知道的是,现在输出的 flac 文件的比特率与原始文件匹配,s16p 仍然更改为 s16,据我所知,一些元数据可能会丢失,还有其他可能性。