FFmpeg日志系统基于递增数值级别(如AV_LOG_INFO为默认),按严重程度过滤输出。从致命错误(FATAL)到极细追踪(TRACE),级别越高越详尽。命令行通过
-loglevel控制,生产环境推荐使用ERROR或WARNING,调试时启用VERBOSE/DEBUG,避免日志洪泛。自定义回调可集成至统一日志系统,实现高效问题排查与工程化管理。
一、核心设计:数值化的日志门槛
FFmpeg 的日志系统定义在 libavutil/log.h中,所有级别本质上是递增的整数常量 。其过滤逻辑非常直白:设置一个阈值 L,只有 level <= L的日志才会被输出。数值越小,严重程度越高;数值越大,信息越详尽。
| 级别宏 | 数值 | 定位 |
|---|---|---|
AV_LOG_QUIET |
-8 | 完全静默 |
AV_LOG_PANIC |
0 | 系统级崩溃,即将异常退出 |
AV_LOG_FATAL |
8 | 致命错误,流程无法继续 |
AV_LOG_ERROR |
16 | 可感知的错误,但后续流程可能继续 |
AV_LOG_WARNING |
24 | 可疑但不致命的异常 |
AV_LOG_INFO |
32 | 默认级别,常规运行信息 |
AV_LOG_VERBOSE |
40 | 详细信息,比 INFO 多一层 |
AV_LOG_DEBUG |
48 | 开发者级调试信息 |
AV_LOG_TRACE |
56 | 极细粒度追踪,日志量巨大 |
设计规律 :相邻级别间隔为 8,形成清晰的严重度梯度。FFmpeg 命令行工具的默认级别是
AV_LOG_INFO,这也是大多数用户日常看到的输出量。
二、关键级别逐一拆解
AV_LOG_FATAL --- 流程终结者
AV_LOG_FATAL不是"有错误",而是"没法往下走了"。它意味着当前执行上下文已经处于不可恢复状态:
-
输出格式强依赖的头部信息缺失(如 FLV header 损坏)
-
参数组合在逻辑上完全非法(如不存在的像素格式 + 硬件编码器组合)
-
关键资源分配彻底失败(如连最基础的上下文都无法创建)
出现 FATAL级日志后,程序通常会直接退出,不存在"降级继续"的可能。在自定义日志回调中,这个级别往往对应 exit(1)或抛出异常。
AV_LOG_ERROR --- 局部失败,全局尚可
与 FATAL不同,ERROR表示某一步操作失败,但解码器/编码器/复用器整体还能继续运转:
-
单个数据包解封装失败,但后续包可能正常
-
某路流被丢弃,其余流仍可处理
-
单帧解码损坏,但参考帧链未断裂
生产环境中,至少应保留 ERROR级别,它是发现数据异常的第一道防线。
AV_LOG_INFO --- 默认的信息基线
这是 FFmpeg 命令行不指定 -loglevel时的输出级别,面向的是"正常使用的人需要知道什么":
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'in.mp4':
Duration: 00:02:30.45, start: 0.000000, bitrate: 3245 kb/s
Stream #0:0(und): Video: h264, yuv420p, 1920x1080, 3000 kb/s
Stream #0:1(und): Audio: aac, 48000 Hz, stereo, 128 kb/s
流参数、编码映射、整体进度------这些信息足以确认"任务在正常推进",但又不会刷屏。
AV_LOG_VERBOSE --- INFO 的加长版
VERBOSE在 INFO 的基础上增加了内部状态和参数细节,适合排查"为什么选了这个编码器""为什么探测到这些流""滤镜图是怎么构建的":
-
探测阶段的候选格式列表
-
编码器参数协商的完整过程
-
滤镜链中每个节点的输入输出格式
它比 DEBUG 克制,不会深入到帧/包级别的细节,但已经足够排查大部分配置类问题。
AV_LOG_DEBUG --- 帧级与包级的内部视角
DEBUG面向的是"改 FFmpeg 源码、写封装层、调滤镜和编解码参数"的开发者:
-
每个数据包的大小、flags、pts/dts
-
选项是否真正生效(很多选项会被覆盖或忽略,DEBUG 日志会告诉你)
-
各模块内部的分支走向
日志量已经很大,生产环境不应常开,但在排查花屏、丢帧、时间戳异常时不可或缺。
AV_LOG_TRACE --- 函数级的状态机追踪
TRACE是比 DEBUG更极端的级别,会输出函数进出、状态机转换、底层循环级信息。基本只用于 libavcodec/ libavformat开发者定位极端边界 bug,日常开发中几乎不需要。
三、命令行控制
FFmpeg 提供了 -loglevel(简写 -v)来控制日志门槛:
ffmpeg -loglevel error -i in.mp4 out.mp4 # 只输出错误
ffmpeg -loglevel warning -i in.mp4 out.mp4 # 错误 + 警告
ffmpeg -loglevel info -i in.mp4 out.mp4 # 默认,常规信息
ffmpeg -loglevel verbose -i in.mp4 out.mp4 # 详细信息
ffmpeg -loglevel debug -i in.mp4 out.mp4 # 调试信息
ffmpeg -loglevel trace -i in.mp4 out.mp4 # 极详细追踪
还可以叠加输出修饰符:
ffmpeg -loglevel repeat+level+verbose -i in.mp4 out.mp4
-
repeat:重复日志只打印一次(去重) -
level:每行日志前显示级别前缀 -
level+verbose:同时显示级别且使用 verbose 门槛
-report是一个特殊选项,会自动以 DEBUG级别将完整日志写入当前目录下的 ffmpeg-YYYYMMDD-HHMMSS.log文件,专门用于提交 bug report。
四、代码中使用
设置全局日志级别
#include <libavutil/log.h>
av_log_set_level(AV_LOG_INFO); // 全局阈值
输出日志
av_log(NULL, AV_LOG_ERROR, "decode failed at pts %" PRId64 "\n", pts);
av_log(ctx, AV_LOG_DEBUG, "packet size=%d, flags=%d\n", pkt.size, pkt.flags);
第一个参数是 AVClass指针(用于标识日志来源),传 NULL则使用全局上下文。
自定义日志回调
在库或服务中,通常需要将 FFmpeg 的日志接入自己的日志系统:
static void my_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
if (level > av_log_get_level()) return;
char buf[1024];
vsnprintf(buf, sizeof(buf), fmt, vl);
switch (level) {
case AV_LOG_FATAL: syslog(LOG_CRIT, "[ffmpeg] %s", buf); break;
case AV_LOG_ERROR: syslog(LOG_ERR, "[ffmpeg] %s", buf); break;
case AV_LOG_WARNING: syslog(LOG_WARNING, "[ffmpeg] %s", buf); break;
case AV_LOG_INFO: syslog(LOG_INFO, "[ffmpeg] %s", buf); break;
default: syslog(LOG_DEBUG, "[ffmpeg] %s", buf); break;
}
}
av_log_set_callback(my_log_callback);
五、实战选型矩阵
| 场景 | 推荐级别 | 理由 |
|---|---|---|
| 线上转码服务 | error |
只关注真正影响输出的问题,避免日志 I/O 成为瓶颈 |
| 批量处理脚本 | warning |
兼顾异常发现与日志量控制 |
| 普通用户转文件 | 默认 info |
确认参数正确、进度可见 |
| 排查流被丢弃/编码器选错 | verbose |
看到参数协商和流映射全貌 |
| 花屏/丢帧/时间戳异常 | debug |
帧级和包级细节是定位关键 |
| libav 源码级 bug | trace |
函数级追踪,仅限开发环境 |
| 自动化 CI/CD | quiet |
只关心退出码,减少噪音 |
典型排查命令:
# 只关心真出错,适合 cron / systemd 定时任务
ffmpeg -loglevel error -i in.mp4 -c copy out.mp4
# 排查为什么没有音轨
ffmpeg -loglevel verbose -i in.mp4
# 深度排查滤镜或解码问题,重定向到文件
ffmpeg -loglevel debug -i in.mp4 -vf scale=1280:720 out.mp4 2>debug.log
六、总结
FFmpeg 的日志级别体系遵循一个简单的原则:数值越小越严重,数值越大越详尽。理解每个级别的定位,核心在于区分"流程是否还能继续":
-
FATAL和ERROR回答的是"出事了没有" -
INFO和VERBOSE回答的是"正在干什么" -
DEBUG和TRACE回答的是"内部到底发生了什么"
合理设置日志级别,既能保证问题可排查,又能避免日志洪泛拖垮系统。在封装 FFmpeg 的服务中,通过 av_log_set_callback将日志接入统一系统,再配合级别路由,是工程化的最佳实践。