FFProbe封装函数输出乱序及FLAC文件元数据丢失问题排查
嘿,看起来你在封装FFProbe的时候遇到了几个头疼的问题,我来帮你逐一拆解解决:
一、Windows CMD与Git Bash下的乱码、输出顺序错乱问题
这个问题本质上是编码不匹配和子进程流交错导致的,咱们一步步来修复:
1. 乱码问题根源与解决
Windows CMD默认使用GBK编码,而Git Bash采用UTF-8编码,FFProbe默认输出是UTF-8格式,直接在CMD里读取就会出现乱码。另外如果捕获子进程输出时不指定编码,Python(假设你用的是Python)会用系统默认编码解码,自然就乱了。
解决办法很直接:强制FFProbe输出UTF-8,并在读取时明确指定编码,同时处理无法解码的字符:
import subprocess import json def get_ffprobe_metadata(file_path): # 用列表传参避免路径特殊字符解析错误 ffprobe_cmd = [ "ffprobe", "-v", "quiet", # 关闭冗余日志 "-print_format", "json", # 输出结构化JSON,避免文本解析的顺序问题 "-show_format", # 获取文件格式信息 "-show_streams", # 获取流信息 "-hide_banner", file_path ] # 明确指定编码为UTF-8,errors='replace'替换无法解码的字符 result = subprocess.run( ffprobe_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8", errors="replace" ) # 单独处理错误输出,避免和正常输出混在一起导致顺序错乱 if result.stderr: print(f"FFProbe警告: {result.stderr.strip()}") # 解析JSON输出,直接得到结构化字典 try: return json.loads(result.stdout) except json.JSONDecodeError as e: print(f"解析FFProbe输出失败: {str(e)}") return None
2. 输出顺序错乱的修复
顺序混乱大多是因为子进程的stdout(正常输出)和stderr(错误/警告)是两个独立的流,打印时会交错。上面的代码已经把两个流分开捕获,只在有错误时单独打印,就能避免顺序混乱。另外用JSON格式输出,直接转成字典,你后续打印字典的时候也不会有顺序问题(Python 3.7+字典默认保留插入顺序)。
二、特定FLAC文件元数据丢失问题
针对你提到的那个FLAC文件,先从这几个方向排查:
1. 先手动验证FFProbe是否能读取该文件
打开终端(CMD或Git Bash),直接运行以下命令,看看输出里有没有元数据:
ffprobe -v quiet -print_format json -show_format -show_streams "Imagine Dragons - Hit Parade_ Best of the Dance Music Charts\80 - Beazz - Lime (Extended Mix).flac"
如果手动运行也没有元数据,那要么是这个文件的元数据本身损坏/不存在,要么是FFProbe版本太老不支持它的元数据格式。如果手动运行能拿到元数据,那就是你的封装函数有问题(比如路径解析错误)。
2. 路径特殊字符的处理
你的文件路径里有空格、下划线、括号这些特殊字符,一定要用列表形式传参(像上面代码里的ffprobe_cmd那样),不要用字符串拼接命令,否则会导致FFProbe无法正确识别文件路径。
3. 强制读取所有元数据标签
有些FLAC文件的元数据可能存在于非默认读取的字段里,你可以加上-show_entries参数强制读取所有标签:
修改ffprobe_cmd为:
ffprobe_cmd = [ "ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", "-show_entries", "format_tags:stream_tags", # 强制读取所有格式和流的标签 "-hide_banner", file_path ]
4. 更新FFProbe版本
旧版本的FFProbe对某些FLAC的VorbisComment元数据支持可能不完善,去FFmpeg官网下载最新的Windows版本替换现有工具,再试试读取。
内容的提问来源于stack exchange,提问作者Jacob Birkett

