面试题手册

梳理高频技术问题,帮助你按主题复习和查漏补缺。

服务端阅读 06月4日 13:52

FFmpeg Filter语法详解:缩放、裁剪、叠加和组合滤镜

FFmpeg 的 Filter 是它区别于其他转码工具的核心能力——不只是格式转换,而是对画面的像素、音频的采样点做任意变换。但 Filter 的语法是出了名的难读:方括号标签、分号逗号混用、多个输入输出的管线。这篇文章先把语法规则讲透,再按场景列举常用滤镜。Filter 语法:三分钟搞懂简单滤镜 vs 复杂滤镜-vf "滤镜链":简单视频滤镜,单个输入,单个输出-af "滤镜链":简单音频滤镜,同上-filter_complex "滤镜图":复杂滤镜,可以有多个输入输出、分支和合并能用 -vf/-af 解决的,不要用 -filter_complex——简单滤镜更快更不容易出错。语法规则# 逗号:串联同一链的滤镜,前一个的输出是后一个的输入-vf "scale=1280:720,crop=640:360"# 分号:分隔不同的滤镜链(用于 -filter_complex)-filter_complex "[0:v]scale=1280:720[v1];[1:v]scale=640:360[v2]"# 方括号标签:给输入/输出命名-filter_complex "[0:v]scale=1280:720[big];[1:v]scale=640:360[small];[big][small]overlay=10:10"[0:v] 表示第一个输入的视频流,[0:a] 表示第一个输入的音频流。[big]、[small] 是自定义标签,后续滤镜用这个标签引用。最常见的语法错误# 错误:简单滤镜里用了分号-vf "scale=1280:720;crop=640:360" # 报错# 正确:简单滤镜用逗号-vf "scale=1280:720,crop=640:360" # OK视频滤镜缩放(scale)# 固定分辨率ffmpeg -i input.mp4 -vf "scale=1280:720" output.mp4# 保持宽高比(只指定宽度,高度自动计算)ffmpeg -i input.mp4 -vf "scale=1280:-1" output.mp4# 等比缩小到一半ffmpeg -i input.mp4 -vf "scale=iw/2:ih/2" output.mp4# 限制最大尺寸(不超过 1280x720,小的保持原尺寸)ffmpeg -i input.mp4 -vf "scale='min(1280,iw)':'min(720,ih)'" output.mp4-1 是"自动计算"的写法,FFmpeg 根据原始宽高比算出高度。注意:某些编码器要求宽高都是偶数,如果算出来是奇数会报错,可以用 scale=1280:trunc(ow/2)*2 强制偶数。裁剪(crop)# 从中心裁剪 640x480(默认居中)ffmpeg -i input.mp4 -vf "crop=640:480" output.mp4# 指定裁剪起点(左上角偏移 100,50)ffmpeg -i input.mp4 -vf "crop=640:480:100:50" output.mp4# 自动检测黑边并裁掉ffmpeg -i input.mp4 -vf "cropdetect" -f null - 2>&1 | grep crop# 然后用输出的 crop 值ffmpeg -i input.mp4 -vf "crop=1920:800:0:140" output.mp4cropdetect 是调优利器——先跑一遍检测黑边参数,再用 crop 裁掉。叠加(overlay)给视频加 logo、画中画都用 overlay:# 左上角加 logoffmpeg -i video.mp4 -i logo.png -filter_complex "overlay=10:10" output.mp4# 右下角加 logo(W=视频宽, w=logo宽)ffmpeg -i video.mp4 -i logo.png -filter_complex "overlay=W-w-10:H-h-10" output.mp4# 居中画中画ffmpeg -i main.mp4 -i pip.mp4 -filter_complex "[1:v]scale=320:240[pip];[0:v][pip]overlay=(W-w)/2:(H-h)/2" output.mp4overlay 的坐标用 x:y 格式,支持表达式。W 和 H 是主视频的宽高,w 和 h 是叠加层的宽高。旋转(transpose)# 顺时针 90 度ffmpeg -i input.mp4 -vf "transpose=1" output.mp4# 逆时针 90 度ffmpeg -i input.mp4 -vf "transpose=2" output.mp4# 180 度(两次 90 度)ffmpeg -i input.mp4 -vf "transpose=1,transpose=1" output.mp4# 水平翻转(镜像)ffmpeg -i input.mp4 -vf "hflip" output.mp4旋转后分辨率会变(1080x1920 变 1920x1080),如果编码器有分辨率限制需要注意。文字水印(drawtext)# 静态文字ffmpeg -i input.mp4 -vf "drawtext=text='Hello':fontcolor=white:fontsize=24:x=10:y=10" output.mp3# 带阴影的文字(提高可读性)ffmpeg -i input.mp4 -vf "drawtext=text='Hello':fontcolor=white:fontsize=32:x=10:y=10:shadowcolor=black:shadowx=2:shadowy=2" output.mp4# 显示时间戳ffmpeg -i input.mp4 -vf "drawtext=text='%{pts\:hms}':fontcolor=white:fontsize=20:x=10:y=10" output.mp4drawtext 需要编译时启用 libfreetype。如果报 "Unknown filter 'drawtext'",说明你的 FFmpeg 没有这个支持。模糊和锐化# 高斯模糊ffmpeg -i input.mp4 -vf "gblur=sigma=2" output.mp4# 锐化ffmpeg -i input.mp4 -vf "unsharp=5:5:1.0" output.mp4模糊常用于背景虚化或隐私遮挡,锐化常用于低分辨率素材的提升(但过度锐化会产生光晕伪影)。音频滤镜音频滤镜用 -af,语法和视频一样:# 音量调整ffmpeg -i input.mp4 -af "volume=2.0" output.mp4# 淡入淡出ffmpeg -i input.mp4 -af "afade=t=in:st=0:d=3" output.mp4# 混合两路音频ffmpeg -i voice.mp3 -i bgm.mp3 -filter_complex "amix=inputs=2:duration=first" output.mp3# 延迟ffmpeg -i input.mp4 -af "adelay=500|500" output.mp4音频滤镜的详细用法参见"FFmpeg 音频处理"一文。组合滤镜实战四宫格ffmpeg -i v1.mp4 -i v2.mp4 -i v3.mp4 -i v4.mp4 -filter_complex "[0:v]scale=640:360[v0];[1:v]scale=640:360[v1];[2:v]scale=640:360[v2];[3:v]scale=640:360[v3]; [v0][v1]hstack[top];[v2][v3]hstack[bottom];[top][bottom]vstack" output.mp4hstack 水平拼接,vstack 垂直拼接。所有输入的分辨率必须一致。视频变速# 2 倍速ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" output.mp4# 0.5 倍速ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]" -map "[v]" -map "[a]" output.mp4视频用 setpts 调速(乘以系数),音频用 atempo。atempo 范围 0.5-2.0,超出要链式:atempo=2.0,atempo=2.0 达到 4 倍速。加 logo + 时间戳 + 淡入ffmpeg -i input.mp4 -i logo.png -filter_complex "[0:v]drawtext=text='%{pts\:hms}':fontcolor=white:fontsize=20:x=10:y=10[vt]; [vt][1:v]overlay=W-w-10:10" -af "afade=t=in:st=0:d=2" output.mp4性能提示滤镜是 CPU 密集操作,优化思路:滤镜顺序:先 crop 再 scale,减少处理的像素量GPU 滤镜:NVIDIA 用 scale_npp 替代 scale,hwupload_cuda 后在 GPU 上做滤镜避免不必要的滤镜:每个滤镜都增加一帧的处理时间,去掉不必要的预览时降低分辨率:调参时加 scale=640:360 加快迭代,确认效果后再用原始分辨率输出
服务端阅读 06月4日 13:51

FFmpeg性能优化:硬件加速对比、preset选择和实测数据

FFmpeg 默认配置偏保守,处理 1080p 视频可能只有 0.5x 实时速度——1 小时的视频要转 2 小时。但调整几个参数就能提到 5x 甚至 20x。这篇文章从硬件加速、编码参数、多线程三个层面讲优化,并给出不同场景的推荐配置。硬件加速方案对比四种主流硬件加速,按你的 GPU 选择:| 方案 | 适用硬件 | 编码器 | 解码参数 | 特点 ||------|----------|--------|----------|------|| NVENC/NVDEC | NVIDIA GPU | h264nvenc, hevcnvenc | -hwaccel cuda | 生态最成熟,质量接近 x264 medium || Intel QSV | Intel 集显/独显 | h264qsv, hevcqsv | -hwaccel qsv | 低延迟,适合转码服务器 || AMD AMF | AMD GPU | h264amf, hevcamf | -hwaccel d3d11va | Windows 为主 || VideoToolbox | Apple 芯片/Mac | h264_videotoolbox | -hwaccel videotoolbox | macOS 原生,M 系列芯片性能极强 |NVIDIA GPU 加速# GPU 解码 + GPU 编码(全程不经过 CPU,最快)ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -c:v h264_nvenc -preset fast -b:v 5M output.mp4# GPU 解码 + CPU 编码(质量要求高时)ffmpeg -hwaccel cuda -i input.mp4 -c:v libx264 -preset slow output.mp4# 指定使用哪块 GPU(多卡服务器)ffmpeg -hwaccel_device 0 -hwaccel cuda -i input.mp4 -c:v h264_nvenc output.mp4-hwaccel_output_format cuda 让解码后的帧留在 GPU 显存里,避免 GPU→CPU→GPU 的数据搬运。全程 GPU 处理比"GPU 解码 + CPU 编码"快 2-3 倍。Intel QSV 加速ffmpeg -hwaccel qsv -i input.mp4 -c:v h264_qsv -preset fast -b:v 5M output.mp4QSV 在 Intel 集显上性能不错,低功耗场景(如 NAS 转码)比 NVIDIA 方案更省电。但编码质量不如 NVENC。Apple VideoToolboxffmpeg -i input.mp4 -c:v h264_videotoolbox -b:v 5M output.mp4M1/M2/M3 芯片上 VideoToolbox 编码 4K 视频可以跑到实时 10x 以上。但 FFmpeg 对 VideoToolbox 的参数控制不如 NVENC 丰富。硬件加速的局限硬件编码器的 CRF 控制不如 x264 精细,同码率下质量通常比 x264 slow 低一档硬件编码器的 B 帧策略和参考帧数量受限,某些高级参数不支持如果要用滤镜(如 drawtext、overlay),帧通常需要从 GPU 搬回 CPU,抵消加速效果不同硬件编码器的输出比特率波动大,不适合对码率有严格要求的场景编码参数优化x264 preset 选择# 追求速度(实时转码、预览)ffmpeg -i input.mp4 -c:v libx264 -preset veryfast -crf 23 output.mp4# 平衡速度和质量(通用场景)ffmpeg -i input.mp4 -c:v libx264 -preset medium -crf 23 output.mp4# 追求质量(离线存档)ffmpeg -i input.mp4 -c:v libx264 -preset slow -crf 18 output.mp4实测数据(1080p 25fps,i7-12700K):| preset | 编码速度 | 相同 CRF 下的体积 ||--------|----------|-------------------|| ultrafast | 120fps (5x) | +40% || veryfast | 80fps (3x) | +20% || fast | 55fps (2x) | +10% || medium | 35fps (1.4x) | 基准 || slow | 12fps (0.5x) | -8% |从 veryfast 到 slow,速度差 7 倍但体积只省 20%。大多数场景选 veryfast 或 fast 就够了。CRF 值选择CRF(Constant Rate Factor)是 x264 的质量控制参数,0 是无损,51 是最差:| CRF | 质量 | 场景 ||-----|------|------|| 18 | 视觉无损 | 存档、后期素材 || 23 | 默认 | 通用 || 28 | 明显压缩痕 | 预览、小体积 || 32 | 画质差 | 仅可辨认内容 |CRF 和 preset 是独立的:CRF 控制质量目标,preset 控制达到该目标的效率。同一 CRF 下,slow preset 的文件更小但质量一样。线程数# 自动检测(推荐,通常等于 CPU 核心数)ffmpeg -i input.mp4 -threads 0 -c:v libx264 output.mp4# 手动指定(给其他任务留核心)ffmpeg -i input.mp4 -threads 4 -c:v libx264 output.mp4x264 的线程数不是越多越好——超过 16 线程后编码效率开始下降(切片并行导致的参考帧问题)。4K 视频推荐 8-16 线程,1080p 推荐 4-8 线程。批量处理GNU Parallel 多文件并行# 同时处理 4 个文件,每个占一个 GPUfind input/ -name "*.mp4" | parallel -j 4 ffmpeg -i {} -c:v h264_nvenc output/{/.}.mp4多文件并行比单文件多线程更高效——FFmpeg 单进程的线程扩展性有限,但多个进程各占一个核心/GPU 可以线性扩展。分段处理大文件# 先分成小段ffmpeg -i input.mp4 -c copy -f segment -segment_time 60 segment_%03d.mp4# 并行转码每一段for f in segment_*.mp4; do ffmpeg -i "$f" -c:v libx264 -preset fast transcoded_"$f" &donewait# 合并echo "$(for f in transcoded_segment_*.mp4; do echo "file '$PWD/$f'"; done)" | ffmpeg -f concat -safe 0 -i - -c copy output.mp4分段处理要确保每段都有关键帧开头(-c copy 分段依赖关键帧),否则合并不连续。内存优化处理超大文件(4K+ 长视频)时内存可能不够:# 限制缓冲区大小ffmpeg -i input.mp4 -c:v libx264 -bufsize 2M output.mp4# 流式处理(不落盘)ffmpeg -i rtmp://source/live -c:v libx264 -f flv rtmp://target/live推荐配置速查| 场景 | 命令 ||------|------|| 实时转码 | -c:v h264_nvenc -preset fast -b:v 4M || 离线高质量 | -c:v libx264 -preset slow -crf 18 || 批量转码 | -c:v libx264 -preset veryfast -crf 23 + GNU Parallel || 小体积 | -c:v libx264 -preset medium -crf 28 || Mac 本地 | -c:v h264_videotoolbox -b:v 5M |
服务端阅读 06月4日 13:49

FFmpeg C API集成:解码、编码和最容易踩的坑

FFmpeg 的命令行工具够用的话,没人愿意碰它的 C API——函数多、生命周期复杂、版本间 API 变动频繁。但当你要做实时流处理、自定义滤镜链、或者把音视频能力嵌入产品时,命令行就不够了。这篇文章把 FFmpeg API 集成的核心流程讲清楚:从打开文件到解码、从编码到输出,以及最容易踩的坑。核心库和职责| 库 | 职责 | 你什么时候会用到 ||---|---|---|| libavformat | 封装格式(容器)读写 | 打开文件、读写 MP4/MKV/FLV 等 || libavcodec | 编解码 | 解码 H.264/AAC,编码 H.265/Opus || libavutil | 工具函数 | 内存分配、数学运算、日志 || libswscale | 图像缩放和色彩转换 | YUV → RGB、分辨率缩放 || libswresample | 音频重采样 | 采样率转换、声道布局转换 || libavfilter | 滤镜 | 视频加水印、音频降噪 |不需要全部链接,按需引入。只做解码的话,libavformat + libavcodec + libavutil 就够。解码流程:从文件到原始帧1. 初始化#include <libavformat/avformat.h>#include <libavcodec/avcodec.h>// FFmpeg 4.0+ 不需要手动注册,老版本需要:// av_register_all();avformat_network_init(); // 如果要处理网络流(RTMP/HLS)版本差异是最大的坑之一。FFmpeg 4.0 废弃了 av_register_all(),5.0 废弃了 avcodec_register_all(),新版自动注册所有内置编解码器。如果你的代码还要兼容 3.x,加版本判断:#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 0, 0) av_register_all();#endif2. 打开文件、找流AVFormatContext *fmt_ctx = NULL;int ret = avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL);if (ret < 0) { char errbuf[128]; av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "无法打开文件: %s\n", errbuf); return -1;}avformat_find_stream_info(fmt_ctx, NULL);avformat_open_input 只打开文件头,不读帧数据。avformat_find_stream_info 读几帧探测流信息(编码器、分辨率、帧率),如果省略这步,后续 codecpar 里的信息可能不完整。3. 找视频流、打开解码器// 找第一个视频流int video_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);if (video_idx < 0) { fprintf(stderr, "没找到视频流\n"); return -1;}// 打开解码器AVCodecParameters *codecpar = fmt_ctx->streams[video_idx]->codecpar;const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);avcodec_parameters_to_context(codec_ctx, codecpar);avcodec_open2(codec_ctx, codec, NULL);av_find_best_stream 比 手动遍历 nb_streams 更好——它会根据流的质量和语言偏好选最优的。4. 读取和解码帧FFmpeg 3.1+ 使用 send/receive 模型:AVPacket *pkt = av_packet_alloc();AVFrame *frame = av_frame_alloc();while (av_read_frame(fmt_ctx, pkt) >= 0) { if (pkt->stream_index != video_idx) { av_packet_unref(pkt); continue; } ret = avcodec_send_packet(codec_ctx, pkt); if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { break; } while (ret >= 0) { ret = avcodec_receive_frame(codec_ctx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; if (ret < 0) break; // frame->data[0] 就是 YUV 数据 // frame->width, frame->height, frame->format 可用 process_frame(frame); } av_packet_unref(pkt);}send/receive 是异步的:一个 packet 可能产生多个 frame(如 B 帧重排序),也可能多个 packet 才产出一个 frame(音频解码缓冲)。EAGAIN 不是错误,意思是"再发一个 packet 过来"。5. 冲刷解码器读取完所有帧后,解码器里可能还缓存着几帧,需要冲刷:avcodec_send_packet(codec_ctx, NULL); // NULL 触发冲刷while (avcodec_receive_frame(codec_ctx, frame) != AVERROR_EOF) { process_frame(frame);}编码流程:从原始帧到文件编码是解码的逆过程,但多了输出容器的初始化:// 创建输出上下文AVFormatContext *out_ctx = NULL;avformat_alloc_output_context2(&out_ctx, NULL, NULL, "output.mp4");// 添加视频流AVStream *out_stream = avformat_new_stream(out_ctx, NULL);const AVCodec *encoder = avcodec_find_encoder(AV_CODEC_ID_H264);AVCodecContext *enc_ctx = avcodec_alloc_context3(encoder);enc_ctx->width = 1280;enc_ctx->height = 720;enc_ctx->time_base = (AVRational){1, 25}; // 时间基准enc_ctx->framerate = (AVRational){25, 1};enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;enc_ctx->gop_size = 10;enc_ctx->max_b_frames = 1;// 如果输出是 MP4,需要把编码器参数拷到流里avcodec_open2(enc_ctx, encoder, NULL);avcodec_parameters_from_context(out_stream->codecpar, enc_ctx);// 打开输出文件avio_open(&out_ctx->pb, "output.mp4", AVIO_FLAG_WRITE);avformat_write_header(out_ctx, NULL);编码帧和写文件:AVPacket *enc_pkt = av_packet_alloc();// 对每个帧:avcodec_send_frame(enc_ctx, frame);while (avcodec_receive_packet(enc_ctx, enc_pkt) == 0) { enc_pkt->stream_index = out_stream->index; av_interleaved_write_frame(out_ctx, enc_pkt); av_packet_unref(enc_pkt);}// 冲刷编码器avcodec_send_frame(enc_ctx, NULL);while (avcodec_receive_packet(enc_ctx, enc_pkt) == 0) { enc_pkt->stream_index = out_stream->index; av_interleaved_write_frame(out_ctx, enc_pkt); av_packet_unref(enc_pkt);}// 写文件尾av_write_trailer(out_ctx);av_interleaved_write_frame 会自动按 DTS 排序后写入,比 av_write_frame 更安全。如果你不确定 DTS/PTS 的关系,用 interleaved 版本。资源释放FFmpeg 的资源释放顺序不能乱——先释放依赖项,再释放容器:av_frame_free(&frame);av_packet_free(&pkt);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx); // 输入avcodec_free_context(&enc_ctx);av_write_trailer(out_ctx);avformat_close_input(&out_ctx); // 输出(如果用 avformat_close_input)// 或者:avio_closep(&out_ctx->pb);avformat_free_context(out_ctx);忘写 av_write_trailer 的话,MP4 文件的 moov atom 不会被写入,播放器无法打开。错误处理的正确姿势FFmpeg 的错误码是负数,用 av_strerror 转成可读字符串:char errbuf[AV_ERROR_MAX_STRING_SIZE] = {0};if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "错误: %s (code=%d)\n", errbuf, ret);}常见错误码:AVERROR(EAGAIN) — 需要更多输入,不是真错误AVERROR_EOF — 流结束,正常退出条件AVERROR(EINVAL) — 参数无效,检查传参AVERROR(ENOMEM) — 内存不足,检查是否有泄漏AVERROR_EXIT — 被 callback 终止线程安全FFmpeg API 大部分不是线程安全的。多线程环境下:每个 AVCodecContext 只能被一个线程使用AVFormatContext 的读写操作需要加锁av_log 是线程安全的,可以放心在多线程中使用推荐模式:一个线程负责读取和解码,通过队列把帧传给另一个线程编码编译链接# 查看链接需要的库pkg-config --libs libavformat libavcodec libavutil# 典型编译命令gcc -o myapp myapp.c $(pkg-config --cflags --libs libavformat libavcodec libavutil libswscale)静态链接时注意依赖顺序:libavformat 依赖 libavcodec,libavcodec 依赖 libavutil,链接顺序要反过来写。
服务端阅读 06月4日 13:48

FFmpeg报错怎么排查?编码、格式和推流问题解决方案

用 FFmpeg 处理音视频,报错信息常常一句话带过,搜索引擎给你的答案又是"试试这条命令"却不解释原因。这篇文章按错误类型分类,每个问题先说原因再说解决方案。编码问题"Error while opening encoder"——编码器不可用原因:FFmpeg 编译时没包含该编码器,或者编码器名称拼写错了。# 先确认编码器是否可用ffmpeg -encoders | grep h264如果列表里没有 libx264,说明编译时没加 --enable-libx264。解决方案:重新编译 FFmpeg 或安装完整版。Ubuntu 上 sudo apt install ffmpeg 通常包含常用编码器;如果是从源码编译的,需要手动 enable。检查编码器名称也容易出错:NVIDIA GPU 编码器叫 h264_nvenc 不是 nvenc_h264,Intel QSV 叫 h264_qsv 不是 qsv_h264。编码速度太慢原因:默认 preset 是 medium,追求质量但速度一般。# 优先速度,牺牲一点质量ffmpeg -i input.mp4 -c:v libx264 -preset veryfast output.mp4# 极速(质量明显下降,适合预览)ffmpeg -i input.mp4 -c:v libx264 -preset ultrafast output.mp4# 有 GPU 的话直接用硬件编码ffmpeg -hwaccel cuda -i input.mp4 -c:v h264_nvenc output.mp4preset 从快到慢:ultrafast → veryfast → fast → medium → slow → veryslow。越慢质量越好、文件越小,但收益递减——slow 比 medium 慢 2-3 倍但只省 5-10% 体积。一般选 veryfast 或 fast 就够。音视频不同步原因通常是三种:源文件本身时间戳不对、编码时帧率设置错误、或者 -async 没处理音频漂移。# 方案一:强制音频同步(简单粗暴)ffmpeg -i input.mp4 -async 1 output.mp4# 方案二:重新编码音视频(更可靠)ffmpeg -i input.mp4 -c:v libx264 -c:a aac output.mp4# 方案三:指定正确帧率ffmpeg -i input.mp4 -r 25 output.mp4-async 1 让音频时间戳强制对齐到视频,简单有效但可能引入音频跳变。如果源文件 PTS(Presentation Time Stamp)本身错乱,需要用 -vsync cfr 强制固定帧率。格式问题"Unsupported codec"——格式不支持# 查看 FFmpeg 支持的所有格式ffmpeg -formats# 查看某格式支持的编码器ffmpeg -encoders | grep mp4最常见的场景:MKV 转 MP4 时 MKV 里有字幕流或特殊编码,MP4 容器不支持。解决方案是只保留音视频流:ffmpeg -i input.mkv -c:v libx264 -c:a aac -map 0:v:0 -map 0:a:0 output.mp4-map 手动选择要保留的流,忽略字幕等不兼容的。播放器兼容性差某些播放器(特别是老款电视、浏览器)对 MP4 的 H.264 profile 和 level 有要求:# 生成最大兼容性的 MP4ffmpeg -i input.mp4 -c:v libx264 -profile:v baseline -level 3.0 -c:a aac output.mp4baseline profile 去掉了 B 帧和高级编码特性,几乎所有设备都能播。代价是同质量下文件更大。加上 -movflags +faststart 让 moov atom 移到文件头部,网页播放不用等下载完:ffmpeg -i input.mp4 -c:v libx264 -c:a aac -movflags +faststart output.mp4流媒体问题RTMP 推流失败常见原因:网络不通、推流地址格式错误、编码格式不兼容。# 先确认网络连通ping rtmp.server.com# 推流时加 -re 按实际帧率发送(否则一口气全推出去,服务器跟不上)ffmpeg -re -i input.mp4 -c copy -f flv rtmp://server/live/stream_key# 加超时避免卡死ffmpeg -re -i input.mp4 -timeout 5000000 -c copy -f flv rtmp://server/live/stream_key-re 是推流的关键参数——不加的话 FFmpeg 会以最快速度把所有帧塞过去,服务器和观众端都会缓冲溢出。HLS 播放卡顿# 增加分片时长(默认 2 秒太短,改 10 秒减少请求次数)ffmpeg -i input.mp4 -f hls -hls_time 10 output.m3u8# 缩短 GOP(关键帧间隔),确保每个分片都有关键帧ffmpeg -i input.mp4 -c:v libx264 -g 25 -f hls -hls_time 10 output.m3u8-g 25 每 25 帧一个关键帧(25fps 下就是 1 秒一个),确保 HLS 分片边界对齐关键帧,否则切分时会出现花屏。滤镜问题"Invalid filterchain"——滤镜语法错误滤镜语法是 FFmpeg 里最容易出错的部分。简单滤镜用 -vf/-af,复杂滤镜用 -filter_complex:# 简单滤镜:单个输入ffmpeg -i input.mp4 -vf "scale=1280:720" output.mp4# 复杂滤镜:多个输入或需要中间标签ffmpeg -i input.mp4 -filter_complex "[0:v]scale=1280:720[v]" -map "[v]" output.mp4常见语法错误:标签没对应(定义了 [v] 但 -map 里写成 [out])、分号和逗号混用(逗号连接同一链内的滤镜,分号分隔不同链)。滤镜处理后速度变慢原因:滤镜是纯 CPU 计算,有些滤镜(如去隔行、缩放)非常吃资源。# 用 GPU 加速的缩放滤镜(NVIDIA)ffmpeg -hwaccel cuda -i input.mp4 -vf "scale_npp=1280:720" output.mp4# 优化滤镜顺序:先裁剪再缩放(处理更少的像素)ffmpeg -i input.mp4 -vf "crop=640:480,scale=320:240" output.mp4调试方法遇到问题先看详细日志:# 详细日志(看编码器选择、流信息)ffmpeg -v verbose -i input.mp4 output.mp4# 调试日志(看每一帧的处理)ffmpeg -v debug -i input.mp4 output.mp4# 只分析不编码(快速检查输入文件信息)ffmpeg -i input.mp4 -f null -性能基准测试:# 测试解码速度ffmpeg -benchmark -i input.mp4 -f null -# 测试编码速度ffmpeg -benchmark -i input.mp4 -c:v libx264 -f null --benchmark 会输出 utime(用户态耗时)、stime(内核态耗时)、rtime(实际耗时),用来对比不同参数的性能差异。
服务端阅读 06月4日 13:47

FFmpeg音频处理速查:格式转换、调音量、剪辑混音和降噪

FFmpeg 做音频处理,不需要打开 DAW,一条命令就能完成格式转换、音量调整、剪辑拼接、降噪混音。但很多教程只是罗列命令,参数什么意思、什么场景该选什么参数,一笔带过。这篇文章把常用音频操作按场景分类,每个命令都解释关键参数。提取和格式转换从视频里提取音频ffmpeg -i video.mp4 -vn -acodec copy audio.aac-vn 禁用视频流,-acodec copy 音频直接拷贝不重编码(速度极快,但输出格式必须和源一致)。如果要转格式,就不能 copy:ffmpeg -i video.mp4 -vn -c:a libmp3lame -b:a 192k audio.mp3-c:a 指定音频编码器,-b:a 指定比特率。192k 是 MP3 的甜点比特率,音质和体积平衡。常见格式互转# WAV → MP3(有损压缩,体积缩小约 10 倍)ffmpeg -i input.wav -c:a libmp3lame -b:a 192k output.mp3# FLAC → MP3(无损转有损,建议 320k 减少质量损失)ffmpeg -i input.flac -c:a libmp3lame -b:a 320k output.mp3# WAV → AAC(iOS/YouTube 常用)ffmpeg -i input.wav -c:a aac -b:a 128k output.m4a# WAV → Opus(同等音质下比特率最低,WebRTC 常用)ffmpeg -i input.wav -c:a libopus -b:a 64k output.opus选编码器的原则:兼容性选 AAC,体积最小选 Opus,无损存档选 FLAC,通用分享选 MP3。音量调整直接调整ffmpeg -i input.mp3 -af "volume=2.0" output.mp3 # 音量翻倍ffmpeg -i input.mp3 -af "volume=0.5" output.mp3 # 音量减半分贝调整ffmpeg -i input.mp3 -af "volume=3dB" output.mp3 # 增加 3dBffmpeg -i input.mp3 -af "volume=-3dB" output.mp3 # 减少 3dB分贝调整比倍数调整更直观——人耳对音量的感知是对数的,3dB 大约是"刚能听出差别"的增量。响度归一化ffmpeg -i input.mp3 -af "loudnorm" output.mp3loudnorm 把音频响度标准化到 EBU R128 标准(-16 LUFS)。批量处理多个文件时,用这个保证所有文件响度一致,避免切歌时音量忽大忽小。播客和音乐平台的响度标准都用它。采样率和声道调整采样率ffmpeg -i input.wav -ar 44100 output.wav # CD 音质ffmpeg -i input.wav -ar 48000 output.wav # 视频标准ffmpeg -i input.wav -ar 16000 output.wav # 语音识别常用(够用且省空间)采样率只能往下降不能无损往上升——44.1k 升 48k 不会凭空多出高频信息,反而可能引入重采样噪声。声道操作# 立体声转单声道ffmpeg -i input.mp3 -ac 1 output.mp3# 单声道转立体声(只是复制一份,不是真正的立体声)ffmpeg -i input.mp3 -ac 2 output.mp3# 提取左声道ffmpeg -i input.mp3 -af "pan=mono|c0=c0" output.mp3# 提取右声道ffmpeg -i input.mp3 -af "pan=mono|c0=c1" output.mp3剪辑和拼接按时间剪辑# 从第 10 秒开始,截取 30 秒ffmpeg -i input.mp3 -ss 00:00:10 -t 00:00:30 -c copy output.mp3# 从第 1 分钟到第 3 分钟ffmpeg -i input.mp3 -ss 00:01:00 -to 00:03:00 -c copy output.mp3-c copy 不重编码,秒级精度。如果需要帧级精度(某些格式),去掉 -c copy 让 FFmpeg 重编码,但速度会慢很多。拼接多个音频最可靠的方式是 concat 协议——先把文件列表写到文本里:echo "file 'part1.mp3'" > filelist.txtecho "file 'part2.mp3'" >> filelist.txtffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mp3前提:所有片段的编码参数必须一致(采样率、声道数、编码器)。不一致的话用 -c copy 会出问题,去掉 copy 让 FFmpeg 重编码即可。音频特效淡入淡出# 开头淡入 3 秒ffmpeg -i input.mp3 -af "afade=t=in:st=0:d=3" output.mp3# 5 秒处开始淡出 3 秒ffmpeg -i input.mp3 -af "afade=t=out:st=5:d=3" output.mp3# 同时淡入淡出ffmpeg -i input.mp3 -af "afade=t=in:st=0:d=3,afade=t=out:st=7:d=3" output.mp3st 是起始时间,d 是持续时间。注意两个 afade 用逗号连在同一条 -af 里。混音# 两个音频混合,以第一个的时长为准ffmpeg -i bgm.mp3 -i voice.mp3 -filter_complex "amix=inputs=2:duration=first" output.mp3混合时音量会叠加,容易爆音。建议先降低各路音量再混合:ffmpeg -i bgm.mp3 -i voice.mp3 -filter_complex "[0:a]volume=0.3[bgm];[1:a]volume=1.0[voice];[bgm][voice]amix=inputs=2" output.mp3背景音乐 0.3 倍音量,人声 1.0 倍——播客和视频解说的典型配比。变速# 1.5 倍速ffmpeg -i input.mp3 -af "atempo=1.5" output.mp3# 0.75 倍速(慢放)ffmpeg -i input.mp3 -af "atempo=0.75" output.mp3atempo 的范围是 0.5 到 2.0。超出这个范围需要链式调用:# 4 倍速 = 2.0 × 2.0ffmpeg -i input.mp3 -af "atempo=2.0,atempo=2.0" output.mp3很多人不知道这个限制,直接写 atempo=4.0 会报错。降噪简单的滤波降噪:# 去除 200Hz 以下的低频噪声(电流声、风声)ffmpeg -i input.mp3 -af "highpass=f=200" output.mp3# 去除 3000Hz 以上的高频噪声(嘶嘶声)ffmpeg -i input.mp3 -af "lowpass=f=3000" output.mp3# 保留 200-3000Hz 的人声频段ffmpeg -i input.mp3 -af "highpass=f=200,lowpass=f=3000" output.mp3这种方式简单但粗糙——会把有效频段也一起砍掉。专业降噪需要用 Audition 或 RNNoise,FFmpeg 的滤波只能做初步处理。音频信息查看# 查看完整音频信息ffprobe -i input.mp3 -show_streams -select_streams a# 检测音量峰值和均值ffmpeg -i input.mp3 -af "volumedetect" -f null -volumedetect 输出 max_volume 和 mean_volume,用来判断是否需要调整音量。如果 max_volume 接近 0dB,说明已经接近削波,不要再增加音量。中间处理用无损格式多次处理同一个音频时(先调音量、再剪辑、再混音),每轮有损编码都会损失质量。正确做法:中间步骤用 WAV 或 FLAC,最后一步才转 MP3/AAC。# 第一步:调音量,输出无损 WAVffmpeg -i input.mp3 -af "volume=2.0" intermediate.wav# 第二步:剪辑 WAVffmpeg -i intermediate.wav -ss 10 -t 30 intermediate2.wav# 第三步:最终转 MP3ffmpeg -i intermediate2.wav -c:a libmp3lame -b:a 192k output.mp3
服务端阅读 06月2日 00:01

FFmpeg 是什么?能做什么?核心组件和常用命令入门

FFmpeg 是音视频领域的瑞士军刀——转码、剪辑、录屏、推流、截图、质量分析,一条命令搞定。它不是带界面的软件,而是命令行工具集,所有操作都在终端完成。OBS、VLC、YouTube 后台都用到了 FFmpeg。FFmpeg 能做什么转码:AVI 转 MP4、H.264 转 H.265、4K 降 1080p剪辑:截取视频片段、合并多个视频、去掉静音段录屏:录制屏幕和摄像头(macOS/Linux/Windows)推流:RTMP 直播推流、生成 HLS 流媒体截图:截取视频帧、批量生成缩略图分析:用 ffprobe 查看视频信息、用 PSNR/SSIM 评估画质核心组件FFmpeg 项目包含一组命令行工具和底层库:| 工具 | 用途 ||------|------|| ffmpeg | 转码、剪辑、推流(最常用) || ffprobe | 查看音视频文件信息(不转码,只分析) || ffplay | 简易播放器(调试用) |底层库(开发者在自己的程序中调用):| 库 | 功能 ||------|------|| libavformat | 处理封装格式(MP4、MKV、FLV…) || libavcodec | 编解码(H.264、AAC、VP9…) || libavutil | 通用工具函数 || libswscale | 图像缩放和色彩空间转换 || libswresample | 音频重采样 |日常只用 ffmpeg 和 ffprobe 两个命令。库是给开发者写程序用的,普通用户不用管。最常用的 5 条命令1. 格式转换ffmpeg -i input.avi -c:v libx264 -c:a aac output.mp42. 视频剪辑ffmpeg -ss 00:01:00 -i input.mp4 -t 30 -c copy output.mp4从 1 分钟处截取 30 秒,-c copy 不重编码,秒级完成。3. 视频截图ffmpeg -i input.mp4 -ss 00:00:05 -vframes 1 screenshot.jpg截取第 5 秒的一帧。4. 查看视频信息ffprobe -v quiet -print_format json -show_format -show_streams input.mp4输出分辨率、码率、时长、编码格式等所有信息,JSON 格式方便脚本解析。5. 压缩视频ffmpeg -i input.mp4 -c:v libx264 -crf 28 -preset slow output.mp4CRF 28 比默认的 23 压得更狠,-preset slow 用更多编码时间换取更小的文件。安装# macOSbrew install ffmpeg# Ubuntu/Debiansudo apt install ffmpeg# Windows# 从 ffmpeg.org 下载,解压后把 bin 目录加到 PATH安装后跑 ffmpeg -version 确认可用。注意某些发行版的 FFmpeg 可能缺少某些编码器(如 libx265),需要从第三方源安装或自行编译。命令语法模式FFmpeg 命令的通用结构:ffmpeg [全局选项] [输入选项] -i 输入文件 [输出选项] 输出文件关键概念:选项的位置很重要。-ss 放在 -i 前面是快速跳转(不精确),放在后面是精确跳转(慢)。-c:v 和 -c:a 是输出选项,必须放在输出文件前面。
服务端阅读 06月2日 00:00

FFmpeg 视频转码怎么做?常用格式转换命令和参数详解

视频转码 = 解码 + 重新编码。最简单的形式是换个容器(MP4 转 MKV),最复杂的是同时改编码器、分辨率、码率、帧率。FFmpeg 一条命令搞定。最基本的转码# 让 FFmpeg 自动选择编码器(按输出文件后缀推断)ffmpeg -i input.avi output.mp4这样 FFmpeg 会自动把 AVI 里的 MPEG-4 视频转成 H.264,音频转成 AAC。简单但不可控——你不知道它选了什么参数。明确指定编码器:ffmpeg -i input.avi -c:v libx264 -c:a aac output.mp4-c:v 指定视频编码器,-c:a 指定音频编码器。这是转码命令的基本骨架,所有高级参数都加在这个基础上。常见转码场景AVI/MKV 转 MP4(最常见)ffmpeg -i input.mkv -c:v libx264 -crf 23 -c:a aac -b:a 128k output.mp4如果原视频已经是 H.264 编码,不需要重编码视频流,只换个容器:ffmpeg -i input.mkv -c:v copy -c:a aac -b:a 128k output.mp4-c:v copy 直接拷贝视频流,几秒完成。但 MKV 支持的编码器比 MP4 多——如果 MKV 里是 H.265 或 VP9,copy 到 MP4 后部分播放器可能不兼容。转 WebM(网页视频)ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus output.webmVP9 编码必须用 -b:v 0 配合 CRF 模式,否则 CRF 不生效。Opus 是 WebM 的标准音频编码器,音质优于 AAC。转 H.265(省空间)ffmpeg -i input.mp4 -c:v libx265 -crf 28 -c:a aac -b:a 128k output.mp4H.265 的 CRF 28 大约等于 H.264 的 CRF 23,文件小 30-50%。编码慢 3-5 倍,老设备可能播不了。只转视频或只转音频# 只转视频,音频原样拷贝ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a copy output.mp4# 只转音频,视频原样拷贝ffmpeg -i input.mp4 -c:v copy -c:a aac -b:a 128k output.mp4# 去掉视频只保留音频ffmpeg -i input.mp4 -vn -c:a aac -b:a 128k output.aac-vn 去掉视频,-an 去掉音频,-sn 去掉字幕。转码时去掉不需要的流可以节省时间。硬件加速转码CPU 编码太慢?用 GPU 加速:# NVIDIA GPU(NVENC)ffmpeg -hwaccel cuda -i input.mp4 -c:v h264_nvenc -preset p4 -cq 23 -c:a aac output.mp4# Intel GPU(QSV)ffmpeg -hwaccel qsv -i input.mp4 -c:v h264_qsv -preset medium -c:a aac output.mp4# Apple Silicon(VideoToolbox)ffmpeg -hwaccel videotoolbox -i input.mp4 -c:v h264_videotoolbox -b:v 5M -c:a aac output.mp4硬件编码速度是 CPU 的 5-10 倍,但同码率下画质略差(约 5-10%)。如果追求极致画质用 CPU libx264,追求速度用 NVENC。-preset p4 是 NVENC 的质量档位,p1 最快 p7 最慢质量最好。转码时调分辨率和帧率# 1080p 转 720pffmpeg -i input.mp4 -vf "scale=1280:720" -c:v libx264 -crf 23 -c:a copy output.mp4# 保持宽高比,只限宽度ffmpeg -i input.mp4 -vf "scale=1280:-2" -c:v libx264 -crf 23 -c:a copy output.mp4# 降帧率 60fps -> 30fpsffmpeg -i input.mp4 -r 30 -c:v libx264 -crf 23 -c:a copy output.mp4-2 让 FFmpeg 自动计算高度保持比例,必须用偶数(有些编码器要求宽高都是偶数)。两遍编码:精确控制文件大小CRF 模式无法精确控制输出文件大小。如果需要视频刚好 100MB:# 第一遍:分析(不输出视频)ffmpeg -i input.mp4 -c:v libx264 -b:v 1500k -pass 1 -an -f null /dev/null# 第二遍:实际编码ffmpeg -i input.mp4 -c:v libx264 -b:v 1500k -pass 2 -c:a aac -b:a 128k output.mp4第一遍分析视频复杂度分布,第二遍据此分配码率。两遍编码比单遍 CRF 质量稍好,但编码时间翻倍。通常只在需要精确文件大小(如 DVD/蓝光)时才用。
服务端阅读 06月2日 00:00

FFmpeg 视频剪辑、合并和截图怎么做?常用命令速查

视频剪辑、合并、截图是 FFmpeg 最高频的日常操作。核心命令不多,但参数位置有讲究——放错位置效果完全不同。视频剪辑:截取片段最常用的剪辑命令# 从第 10 秒开始,截取 30 秒ffmpeg -ss 00:00:10 -i input.mp4 -t 30 -c copy output.mp4# 从 1:30 截到 3:00ffmpeg -ss 00:01:30 -to 00:03:00 -i input.mp4 -c copy output.mp4-c copy 直接拷贝音视频流,不重新编码,速度极快(几秒搞定),但切割点可能不精确——因为视频是按关键帧压缩的,-c copy 只能在关键帧处切开。结果可能是你想从 10 秒切,实际从 8 秒的关键帧开始了。精确剪辑需要精确到帧的剪辑,必须重新编码:ffmpeg -i input.mp4 -ss 00:00:10 -t 30 -c:v libx264 -crf 23 -c:a aac output.mp4去掉 -c copy,让 FFmpeg 重新编码。速度慢很多但切割点精确。-ss 放在 -i 前面还是后面?-ss 在 -i 前面:FFmpeg 先跳到指定时间再开始解码(seek 模式),速度快但可能不精确-ss 在 -i 后面:FFmpeg 从头解码到指定时间,精确但慢最佳实践:先放前面快速定位,再精确微调。对于长视频(>10 分钟),放前面能省很多时间。视频合并:拼接多个片段concat 协议(最快,要求格式完全一致)# 先创建文件列表echo "file 'part1.mp4'" > list.txtecho "file 'part2.mp4'" >> list.txtecho "file 'part3.mp4'" >> list.txt# 合并ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4-c copy 不重编码,秒级完成。但要求所有片段的编码参数(分辨率、帧率、编码器)完全一致,否则合并后可能花屏或播放异常。格式不一致时:先统一再合并# 先把所有片段转成统一格式for f in part*.mp4; do ffmpeg -i "$f" -c:v libx264 -crf 23 -c:a aac -b:a 128k -vf "scale=1920:1080" -r 30 "normalized_$f"done# 再用 concat 合并echo "file 'normalized_part1.mp4'" > list.txtecho "file 'normalized_part2.mp4'" >> list.txtffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4filter 复杂合并(加转场等效果)# 两个视频左右并排ffmpeg -i left.mp4 -i right.mp4 -filter_complex "[0:v][1:v]hstack=inputs=2" output.mp4# 上下并排ffmpeg -i top.mp4 -i bottom.mp4 -filter_complex "[0:v][1:v]vstack=inputs=2" output.mp4filter 合并必须重编码,速度慢但能做各种效果。视频截图# 截取第 5 秒的一帧ffmpeg -i input.mp4 -ss 00:00:05 -vframes 1 screenshot.jpg# 每隔 10 秒截一张ffmpeg -i input.mp4 -vf "fps=1/10" screenshot_%04d.jpg# 截取多张(前 60 秒,每秒 1 帧)ffmpeg -i input.mp4 -t 60 -vf "fps=1" frame_%04d.jpgfps=1/10 表示每 10 秒一帧。%04d 是序号占位符,生成 screenshot0001.jpg、screenshot0002.jpg…截图的质量参数:-q:v 2(1 最好,31 最差,2 近乎无损)。ffmpeg -i input.mp4 -ss 00:00:05 -vframes 1 -q:v 2 screenshot.jpg实用技巧去除视频静音段:用 silenceremove 滤镜自动剪掉没有声音的部分,适合处理会议录像。加速/减速视频:-vf "setpts=0.5*PTS" 2 倍速,-vf "setpts=2*PTS" 半速。音频也要对应调整:-af "atempo=2.0"(atempo 范围 0.5-2.0,超出需要串联)。旋转视频:-vf "transpose=1" 顺时针 90 度。手机竖拍视频在电脑上横着显示时用这个修正。
服务端阅读 06月1日 23:59

FFmpeg 直播推流怎么配?RTMP 推流和 HLS/DASH 流媒体生成实战

FFmpeg 是直播推流的核心工具——OBS 底层也是调用 FFmpeg 做编码和推流。直接用 FFmpeg 推流更轻量、更灵活,适合服务器端自动化场景。RTMP 推流:最常用的直播协议RTMP 是直播平台(B站、斗鱼、YouTube)的标准推流协议。核心命令:ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -b:v 2500k -c:a aac -b:a 128k -f flv rtmp://server/live/stream_key关键参数:-re:按原始帧率读取输入,不加这个 FFmpeg 会以最快速度把文件读完然后全推出去,直播就变成了快进-preset veryfast:实时编码必须用快 preset,slow 的话编码速度跟不上帧率,画面会卡顿-b:v 2500k:固定码率 2.5Mbps,直播平台通常有码率上限(B站 6000k,YouTube 5100k)-f flv:RTMP 推流必须用 FLV 容器格式摄像头实时推流# macOS 摄像头 + 麦克风推流ffmpeg -f avfoundation -i "0:0" -c:v libx264 -preset veryfast -b:v 2500k -c:a aac -b:a 128k -f flv rtmp://server/live/stream_key# Linux 摄像头推流ffmpeg -f v4l2 -i /dev/video0 -f alsa -i hw:0 -c:v libx264 -preset veryfast -b:v 2500k -c:a aac -b:a 128k -f flv rtmp://server/live/stream_key摄像头推流比推文件更需要注意编码速度——如果 CPU 不够快,需要降低分辨率或码率:-vf "scale=1280:720" 降到 720p。HLS:苹果系的流媒体方案HLS 把视频切成小片段(.ts),通过 .m3u8 播放列表索引。延迟较高(通常 10-30 秒),但兼容性最好——所有浏览器和 iOS 设备都支持。ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -b:v 2500k -c:a aac -b:a 128k -f hls -hls_time 6 -hls_list_size 0 -hls_segment_filename "seg_%03d.ts" stream.m3u8关键参数:-hls_time 6:每个切片 6 秒,越短延迟越低但碎片越多-hls_list_size 0:播放列表包含所有切片(0 = 不限制),直播场景可以设成 5-10 只保留最近几个-hls_segment_filename:切片文件命名模板HLS 文件是纯静态文件,用 Nginx 或任何 HTTP 服务器托管就行,不需要专门的流媒体服务器。DASH:开源的流媒体方案DASH 和 HLS 类似,但基于 MPEG 标准,没有苹果的专利限制。浏览器支持不如 HLS(Safari 不原生支持 DASH),但功能更灵活。ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -b:v 2500k -c:a aac -b:a 128k -f dash -seg_duration 6 -out output.mpd实际上 DASH 在国内使用较少,大部分场景用 HLS 或 RTMP 就够了。多码率自适应推流给不同网速的用户提供不同清晰度——3G 用户看 480p,WiFi 用户看 1080p。用 -var_stream_map 生成多码率 HLS:ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -b:v:0 5000k -s:v:0 1920x1080 -b:v:1 2500k -s:v:1 1280x720 -b:v:2 1000k -s:v:2 854x480 -c:a aac -b:a 128k -var_stream_map "v:0,a:0 v:1,a:0 v:2,a:0" -f hls -hls_time 6 -master_pl_name master.m3u8 "stream_%v.m3u8"播放器会根据带宽自动切换码率,用户看到的效果就是网速慢时自动降清晰度。常见问题推流中断:网络波动导致 RTMP 连接断开。加 -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 让 FFmpeg 自动重连,但不是所有版本都支持。延迟太高:HLS 延迟 10-30 秒是正常的。要低延迟用 RTMP 直推或 WebRTC(FFmpeg 不直接支持 WebRTC,需要 mediamtx 等中间件)。音视频不同步:通常是编码速度跟不上导致帧被丢弃。降低分辨率/码率,或者用更快的 preset。
服务端阅读 06月1日 23:57

FFmpeg 怎么录屏和录制摄像头?macOS/Linux/Windows 命令详解

FFmpeg 可以直接从屏幕或摄像头捕获视频,不需要额外安装录屏软件。命令行录制的好处是可以精确控制编码参数、方便脚本化、资源占用低。坏处是参数复杂,初次配置容易踩坑。macOS 录屏macOS 用 avfoundation 设备采集:# 列出可用设备(先看看屏幕和摄像头编号)ffmpeg -f avfoundation -list_devices true -i ""# 录制整个屏幕(假设屏幕编号是 1)ffmpeg -f avfoundation -i "1" -r 30 -c:v libx264 -preset ultrafast -crf 23 output.mp4# 录制屏幕 + 系统音频ffmpeg -f avfoundation -i "1:0" -r 30 -c:v libx264 -preset ultrafast -crf 23 -c:a aac output.mp4-preset ultrafast 是录屏必备——实时编码用 slow 的话 CPU 扛不住,画面会卡。录完之后如果觉得文件太大,可以再用 slow preset 重新转码一遍。Linux 录屏Linux 用 x11grab 采集 X11 桌面:# 录制 1080p 屏幕ffmpeg -f x11grab -video_size 1920x1080 -framerate 30 -i :0.0 -c:v libx264 -preset ultrafast -crf 23 output.mp4# 录制指定区域(从坐标 100,100 开始,宽 800 高 600)ffmpeg -f x11grab -video_size 800x600 -framerate 30 -i :0.0+100,100 -c:v libx264 -preset ultrafast -crf 23 output.mp4# Wayland 用户用 wf-recorder 更方便,ffmpeg 对 Wayland 支持不完善:0.0 是 DISPLAY 环境变量的值,多显示器时可能需要调整。Wayland 下 x11grab 可能不工作,需要装 xdotool 或者换用 wf-recorder。Windows 录屏Windows 用 gdigrab 或 dshow:# gdigrab 录制整个桌面ffmpeg -f gdigrab -framerate 30 -i desktop -c:v libx264 -preset ultrafast -crf 23 output.mp4# 录制指定窗口ffmpeg -f gdigrab -framerate 30 -i title="Window Title" -c:v libx264 -preset ultrafast -crf 23 output.mp4Windows 10+ 也可以用 -f dshow 配合摄像头设备名录制。摄像头录制# macOS:列出设备后用摄像头编号(通常是 0)ffmpeg -f avfoundation -i "0" -r 30 -c:v libx264 -preset ultrafast -crf 23 output.mp4# Linux:用 v4l2ffmpeg -f v4l2 -video_size 640x480 -framerate 30 -i /dev/video0 -c:v libx264 -preset ultrafast -crf 23 output.mp4# 摄像头 + 麦克风ffmpeg -f avfoundation -i "0:0" -r 30 -c:v libx264 -preset ultrafast -crf 23 -c:a aac -b:a 128k output.mp4摄像头编号需要先 -list_devices true 查一下,不同机器编号可能不同。录屏实战技巧1. 录制时显示光标:默认录屏可能看不到鼠标光标。macOS 下加 -capture_cursor 1,Linux 下 x11grab 默认会包含光标。2. 控制录制时长:-t 60 只录 60 秒。方便做定时录制,不用手动按 Ctrl+C。3. 停止录制:按 Ctrl+C。有时候 ffmpeg 不会正常写入 MP4 尾部,导致文件打不开。解决办法:改用 MKV 容器(output.mkv),MKV 即使没正常关闭也能播放;或者事后修复 MP4:ffmpeg -i broken.mp4 -c copy fixed.mp44. 同时录屏和摄像头画中画:高级场景,用 overlay 滤镜把摄像头画面叠到屏幕录制上。这比纯录屏复杂很多,如果需要画中画效果,OBS 可能更合适。
服务端阅读 06月1日 23:56

FFmpeg 怎么批量转码?Shell 脚本和 Python 并行处理实战

单个文件用一条 ffmpeg 命令就行,但处理几十上百个文件就需要脚本了。批量处理的核心思路:用 Shell 循环遍历文件,用 GNU Parallel 做并行加速,用 Python 处理更复杂的逻辑。Shell 脚本:最简单的批量转码#!/bin/bash# 批量把 AVI 转成 MP4for file in *.avi; do ffmpeg -i "$file" -c:v libx264 -crf 23 -c:a aac "${file%.avi}.mp4"done${file%.avi} 是 Shell 的字符串截断——去掉 .avi 后缀,换成 .mp4。这个模式够用 80% 的批量场景。递归处理子目录里的文件:find /path/to/videos -name "*.mkv" | while read file; do ffmpeg -i "$file" -c:v libx264 -crf 23 -c:a aac "${file%.mkv}.mp4"donefind 递归搜索,while read 逐行读取文件路径。比 -exec 更灵活,可以在循环里加更多逻辑。并行加速:别让 CPU 闲着单线程循环太慢——4 核 CPU 只用了 1 核。用 GNU Parallel 让多个 ffmpeg 同时跑:# 4 个 ffmpeg 并行转码find . -name "*.avi" | parallel -j 4 ffmpeg -i {} -c:v libx264 -crf 23 -c:a aac {.}.mp4{} 是输入文件名,{.} 是去掉后缀的文件名。-j 4 限制并发数——设成 CPU 核心数就行,太多会抢 IO 反而变慢。没有 GNU Parallel?用 xargs 也能并行:find . -name "*.avi" | xargs -P 4 -I {} sh -c 'ffmpeg -i "$1" -c:v libx264 -crf 23 -c:a aac "${1%.avi}.mp4"' _ {}-P 4 控制并发数,-I {} 指定占位符。Python:更灵活的批量处理Shell 脚本能做的事 Python 都能做,而且更容易处理错误和复杂逻辑:import subprocess, os, globinput_dir = "raw"output_dir = "compressed"os.makedirs(output_dir, exist_ok=True)for path in glob.glob(f"{input_dir}/*.mp4"): name = os.path.basename(path) output = os.path.join(output_dir, name) cmd = ["ffmpeg", "-i", path, "-c:v", "libx264", "-crf", "23", "-c:a", "aac", "-b:a", "128k", "-movflags", "+faststart", output] result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode == 0: print(f"OK {name}") else: print(f"FAIL {name}: {result.stderr[:200]}")Python 的优势:可以记录成功/失败、跳过已处理文件、按条件选不同参数。Shell 脚本做这些需要大量 if-else,可读性差。进阶:按条件选择不同参数不同类型的视频用不同的压缩策略——教学录屏用高 CRF + stillimage,电影用低 CRF + film:#!/bin/bashfor file in *.mp4; do duration=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$file" | cut -d. -f1) if [ "$duration" -lt 300 ]; then ffmpeg -i "$file" -c:v libx264 -crf 28 -tune stillimage -c:a aac "compressed_$file" else ffmpeg -i "$file" -c:v libx264 -crf 23 -tune film -c:a aac "compressed_$file" fidone跳过已处理文件批量中断后重跑,不想重复处理已经转好的文件:for file in *.mp4; do output="output/$file" [ -f "$output" ] && continue ffmpeg -i "$file" -c:v libx264 -crf 23 -c:a aac "$output"done一行判断搞定断点续传。Python 版可以用 os.path.exists() 做同样的事。
服务端阅读 06月1日 23:26

FFmpeg 视频格式和编解码器怎么选?MP4、MKV、WebM 各适合什么场景?

选视频格式就是选容器(封装格式),选编解码器就是选压缩算法。容器决定兼容性和功能(能不能塞字幕、多音轨),编解码器决定画质和文件大小。两者要分开想。容器格式:MP4、MKV、WebM 怎么选MP4:万能格式,所有设备都能播。缺点是只支持有限的编解码器,多音轨多字幕支持弱。网络视频、手机分享、社交媒体一律选 MP4,不会有兼容性问题。MKV:万能容器,什么编解码器都能塞,支持无限音轨和字幕轨。缺点是某些老旧设备和播放器不支持(特别是智能电视和游戏机)。本地收藏、多语言视频、高清片源选 MKV。WebM:Google 推的 Web 专用格式,基于 VP8/VP9/AV1 编码。所有主流浏览器支持,不需要插件。网页嵌入视频选 WebM,或者直接用 MP4(浏览器也支持)。MOV:Apple 的格式,QuickTime 原生支持。在 Mac 生态里很方便,但 Windows 上不如 MP4 通用。视频剪辑工作流里常见(Final Cut Pro 默认输出 MOV)。编解码器:H.264、H.265、AV1 怎么选H.264(AVC):兼容性之王,所有设备都支持。压缩效率中等,是目前的默认选择。如果你不确定该用什么,用 H.264 不会错。ffmpeg -i input.avi -c:v libx264 -crf 23 -c:a aac output.mp4H.265(HEVC):比 H.264 同画质小 30-50%,但编码慢 3-5 倍。兼容性不如 H.264——老手机、老浏览器可能播不了。4K 视频和存档用 H.265,因为省的空间很可观。Windows 10+ 和近三年的手机基本都支持了。ffmpeg -i input.mp4 -c:v libx265 -crf 28 -c:a aac output.mp4AV1:新一代编码,比 H.265 还能再省 20-30%。开源免专利费,YouTube 和 Netflix 都在用。但编码极慢(libaom-av1 比 libx265 慢 10 倍以上),播放需要较新的硬件/软件。2025 年的 AV1 已经可以在最新设备上流畅播放,但离全面普及还有距离。如果追求极致压缩且目标平台新,可以试试。ffmpeg -i input.mp4 -c:v libaom-av1 -crf 30 -c:a libopus output.webm音频编解码器视频里的音频也别忽略:AAC:通用选择,所有设备支持,128kbps 够听Opus:开源编码器,同码率音质优于 AAC,WebM 默认音频编码MP3:老旧但兼容性极好,新项目不需要用了# 视频 H.264 + 音频 AAC(最通用组合)ffmpeg -i input.mkv -c:v libx264 -crf 23 -c:a aac -b:a 128k output.mp4# 只转音频,视频直接拷贝ffmpeg -i input.mp4 -c:v copy -c:a aac -b:a 128k output.mp4选择决策流程目标平台是什么?网页 → MP4/WebM,手机分享 → MP4,本地存档 → MKV需要兼容老设备吗?是 → H.264,否 → H.265/AV1对文件大小敏感吗?是 → H.265 CRF 28,否 → H.264 CRF 23需要多音轨/多字幕吗?是 → MKV,否 → MP4最常见组合:H.264 + AAC 封装成 MP4,覆盖 99% 的播放场景。
服务端阅读 06月1日 23:25

FFmpeg 怎么查看视频信息?ffprobe 命令和视频质量分析实战

获取视频信息用 ffprobe(FFmpeg 自带的探测工具),不需要转码,秒出结果。分析视频质量用 PSNR/SSIM 等指标,对比编码前后的画质差异。ffprobe:一行命令看透视频最常用的命令:# 查看所有信息(人类可读)ffprobe input.mp4# JSON 格式输出(方便脚本解析)ffprobe -v quiet -print_format json -show_format -show_streams input.mp4日常只需要几个关键字段:| 字段 | 含义 | 查看命令 ||------|------|----------|| 分辨率 | 视频宽高 | ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 input.mp4 || 时长 | 视频长度(秒) | ffprobe -v error -show_entries format=duration -of csv=p=0 input.mp4 || 码率 | 比特率 | ffprobe -v error -show_entries format=bit_rate -of csv=p=0 input.mp4 || 帧率 | 每秒帧数 | ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of csv=p=0 input.mp4 || 编码器 | 编解码格式 | ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of csv=p=0 input.mp4 |这些命令看着长,但本质都是 -show_entries 指定要哪个字段 + -of 指定输出格式。记住模式就行,不用背命令。提取关键信息的快捷脚本# 一行获取:分辨率 帧率 编码 时长 码率ffprobe -v error -select_streams v:0 \ -show_entries stream=width,height,codec_name,r_frame_rate \ -show_entries format=duration,bit_rate \ -of default=noprint_wrappers=1 input.mp4在 Python 里调用 ffprobe:import subprocess, jsondef get_video_info(path): cmd = ["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", path] result = subprocess.run(cmd, capture_output=True, text=True) return json.loads(result.stdout)info = get_video_info("input.mp4")video = info["streams"][0] # 第一个视频流print(f"分辨率: {video["width"]}x{video["height"]}")print(f"编码: {video["codec_name"]}")print(f"时长: {float(info["format"]["duration"]):.1f}秒")视频质量分析:量化编码损失压缩视频后想知道画质损失了多少,用 PSNR 和 SSIM 两个指标。PSNR(峰值信噪比):数值越高画质越好,30dB 以下明显有损,40dB 以上视觉无损。ffmpeg -i original.mp4 -i compressed.mp4 -lavfi psnr -f null -SSIM(结构相似度):0-1 之间,越接近 1 越相似。SSIM 比 PSNR 更接近人眼感知——PSNR 只看像素差异,SSIM 看结构变化。实际评估画质优先看 SSIM。ffmpeg -i original.mp4 -i compressed.mp4 -lavfi ssim -f null -两个命令都会逐帧计算并输出平均值。VMAF 是 Netflix 提出的更先进的质量指标,更接近人类主观评分,但 FFmpeg 原生不支持(需要额外编译 libvmaf)。常见问题排查视频打不开:先跑 ffprobe input.mp4,看报错信息。常见原因:文件损坏、编码不支持、容器格式错误。ffprobe 比任何播放器都能更快定位问题。码率异常:如果视频文件很大但画质一般,用 ffprobe 看码率——可能是编码效率低(用了老编码器)或码率设置过高。转成 H.264/265 + 合理 CRF 通常能大幅缩小。音视频不同步:ffprobe 看 start_time 差异——音频和视频的起始时间不一致就会导致不同步。
服务端阅读 06月1日 23:24

FFmpeg 视频压缩怎么选参数?CRF、preset 和 tune 实战指南

FFmpeg 压缩视频的核心就三个参数:-crf 控制质量,-preset 控制编码速度和压缩率的平衡,-tune 针对特定内容类型优化。理解这三个参数,就能应对 90% 的压缩场景。CRF:画质旋钮CRF(Constant Rate Factor)是 H.264/H.265 的质量控制参数,范围 0-51。数字越小质量越高文件越大,数字越大质量越低文件越小。关键参考值:18:视觉无损,和原片几乎看不出差别,文件很大23:默认值,质量和体积的平衡点,大多数场景够用28:明显有损但能看,适合手机端播放30+:质量较差,只在极端节省空间时使用ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4CRF 是感知质量恒定——运动多的场景自动多分配码率,静态场景少分配。所以同一个 CRF 值,不同视频的文件大小可能差很多。如果需要精确控制文件大小,得用两遍编码(two-pass)或指定码率。Preset:时间换空间Preset 控制编码器用多少计算时间来寻找更优的压缩方案。越慢的 preset 压缩率越高(同画质文件更小),但编码时间越长。| Preset | 编码速度 | 同 CRF 文件大小 | 适用场景 ||--------|----------|-----------------|----------|| ultrafast | 最快 | 最大(约 2x) | 实时流媒体 || veryfast | 很快 | 较大 | 直播推流 || fast | 快 | 中等 | 日常快转 || medium | 中等(默认) | 基准 | 一般用途 || slow | 慢(约 3x 时间) | 较小(约 -15%) | 离线转码 || veryslow | 很慢(约 6x) | 更小(约 -25%) | 归档存储 |实际建议:离线处理用 slow,实时场景用 veryfast,不确定就用 medium。ultraslow 不存在,veryslow 已经是极限了。从 medium 切到 slow,编码时间翻 3 倍但文件只小 15%——值不值看你的需求。# 离线高质量压缩ffmpeg -i input.mp4 -c:v libx264 -crf 20 -preset slow output.mp4# 快速压缩(直播/即时预览)ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset veryfast output.mp4Tune:针对性优化Tune 让编码器针对特定内容类型调整策略:film:电影/真人视频,去胶片颗粒感,优化暗部细节animation:动画片,优化大面积色块和平滑区域stillimage:PPT 录屏/幻灯片,优化静态画面fastdecode:牺牲一点压缩率换取更快解码速度(低端设备播放)zerolatency:零延迟,实时流媒体和直播专用大部分情况不加 tune 就行。加错了反而比不加差——对真人视频用 animation,细节会糊掉。# 压缩电影ffmpeg -i movie.mkv -c:v libx264 -crf 20 -preset slow -tune film output.mp4# 压缩动画ffmpeg -i anime.mkv -c:v libx264 -crf 20 -preset slow -tune animation output.mp4# 压缩录屏教程ffmpeg -i screen.mp4 -c:v libx264 -crf 23 -preset medium -tune stillimage output.mp4H.265 压缩:省空间但要考虑兼容性H.265(HEVC)比 H.264 同画质文件小 30-50%,但编码慢 3-5 倍,且老设备可能不支持播放。如果目标平台是手机/智能电视/浏览器,H.264 兼容性最好。如果目标是存档或只在 PC 上播放,H.265 更划算。ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset slow output.mp4注意 H.265 的 CRF 值不能和 H.264 直接对比——H.265 的 CRF 28 大致对应 H.264 的 CRF 23,因为 H.265 的范围和感知曲线不同。两个常见坑1. 忘了 -movflags +faststart:MP4 文件的元数据(moov atom)默认放在文件末尾,浏览器必须下载完整个文件才能开始播放。加 -movflags +faststart 把元数据移到开头,允许边下载边播放。网络视频必加。2. 音频不要忘:压缩视频时音频默认也会被重编码。如果只是压缩视频不想动音频,加 -c:a copy 直接拷贝音频流。要压缩音频就用 -c:a aac -b:a 128k,128kbps 对大多数内容够用。
前端阅读 05月29日 00:25

FFmpeg支持哪些常见的音视频格式?

FFmpeg支持100+容器格式和200+编解码器,需区分容器和编码两层。容器层主流格式:MP4(兼容性最广)、MKV(多音轨/字幕)、WebM(Web优化)、MOV(Apple生态)、FLV(直播推流)、TS(HLS切片)。视频编码:H.264/AVC(最通用)、H.265/HEVC(同质量体积减半)、VP9(WebM默认)、AV1(开源下一代,FFmpeg 5.0+支持)。音频编码:AAC(流媒体标配)、Opus(低延迟实时通信最优)、MP3(兼容旧设备)、FLAC(无损)。关键认知:容器决定封装结构,编码决定压缩算法,同一容器可装不同编码(如MP4可装H.264或H.265)。用ffmpeg -encoders查看本地支持的编码器列表。追问H.264和H.265在FFmpeg中用什么编码器?libx264和h264_nvenc性能差多少?MP4容器能装VP9视频吗?为什么WebM比MP4更适合Web场景?Opus相比AAC在延迟和码率上有什么优势?为什么WebRTC选Opus?FLV容器为什么逐步被淘汰?HLS的TS切片方案解决了FLV的什么问题?ffmpeg -codecs和ffmpeg -encoders输出有什么区别?写段代码# 查看本地支持的所有H.265编码器ffmpeg -encoders 2>/dev/null | grep 265# MP4转WebM(VP9+Opus)ffmpeg -i in.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus out.webm
前端阅读 05月29日 00:24

FFmpeg的核心组件包括哪些?分别有什么作用?

FFmpeg的核心组件分为库和命令行工具两大类。库层面:libavcodec负责音视频编解码(H.264/H.265/AAC等),libavformat处理容器封装与解封装(MP4/MKV/FLV),libavfilter实现滤镜链(缩放/旋转/叠加),libswscale做像素格式转换(YUV↔RGB),libswresample处理音频重采样与通道转换,libavutil提供通用数据结构(AVPacket/AVFrame)和工具函数,libavdevice抽象硬件设备交互。工具层面:ffmpeg是转码命令行入口,ffprobe探测媒体流信息,ffplay轻量播放器。转码流水线为:demux(libavformat)→ decode(libavcodec)→ filter(libavfilter)→ encode(libavcodec)→ mux(libavformat)。追问libavcodec和libavformat的职责边界在哪?为什么要把编解码和容器处理拆成两个库?转码时用-c copy跳过了流水线中哪些环节?为什么能实现无损且秒级完成?libswscale和libavfilter的scale滤镜功能重叠,实际项目中该用哪个?ffprobe如何快速获取视频时长和码率?底层调用了libavformat的哪个接口?硬件加速编解码(NVENC/QSV)在组件架构中如何接入?是否绕过了libavcodec?写段代码# 查看视频流信息ffprobe -v quiet -print_format json -show_streams input.mp4# H.264转H.265,音频直接拷贝ffmpeg -i input.mp4 -c:v libx265 -crf 28 -c:a copy output.mp4
前端阅读 05月28日 02:01

FFmpeg是否提供API?如何在C/C++项目中集成FFmpeg?

FFmpeg 提供了完整的 C 语言 API,这是面试中经常被问到的基础知识。核心 API 分布在 libavformat、libavcodec、libavutil、libswscale、libswresample 五个库中,C/C++ 项目可以直接链接这些库来调用编解码、封装解封装、格式转换等全部功能,无需通过命令行进程通信。FFmpeg 有哪些核心库?各自的职责是什么?这是理解 FFmpeg API 的起点。FFmpeg 的模块化设计体现在每个库各司其职:libavformat:处理容器格式的读取与写入。MP4、MKV、FLV 等文件的打开、流信息解析、数据包读写都由它负责。核心函数包括 avformat_open_input()、av_read_frame()、avformat_write_header()。libavcodec:编解码器的核心。H.264、H.265、AAC、OPUS 等编解码器都封装在这里。avcodec_find_decoder()、avcodec_send_packet()、avcodec_receive_frame() 是解码的关键调用链。libavutil:公共工具库,提供内存管理(av_malloc/av_free)、数学运算(av_clip)、日志(av_log)、字典(AVDictionary)等基础设施。其他库都依赖它。libswscale:图像缩放和像素格式转换。将 YUV 数据转为 RGB、调整分辨率等场景必须用它,核心函数是 sws_scale()。libswresample:音频重采样、声道布局转换、采样格式转换。处理音频数据时不可或缺,核心函数是 swr_convert()。面试追问:为什么 FFmpeg 要拆成这么多库而不是一个整体?答案是模块化链接——如果你的项目只需要解码不需要缩放,可以只链接 libavcodec 和 libavformat,不链接 libswscale,减小二进制体积。这在嵌入式和移动端尤其重要。如何在 C/C++ 项目中集成 FFmpeg?集成分为三步:安装开发包、配置构建系统、链接库文件。安装开发包不同平台的安装方式:# Ubuntu/Debiansudo apt install libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev# macOSbrew install ffmpeg# Windows(推荐 vcpkg)vcpkg install ffmpeg安装后确认头文件存在:/usr/include/libavcodec/avcodec.h(Linux)或 $(brew --prefix ffmpeg)/include/libavcodec/avcodec.h(macOS)。如果头文件找不到,说明装的是运行时包而非开发包。配置 CMake 构建CMake 是最常用的构建方式。关键在于 find_package 和正确的链接顺序:cmake_minimum_required(VERSION 3.10)project(FFmpegApp)# 方式一:使用 CMake 内置的 FindFFmpeg 模块find_package(FFmpeg REQUIRED COMPONENTS avformat avcodec avutil swscale swresample)add_executable(main main.cpp)target_include_directories(main PRIVATE ${FFMPEG_INCLUDE_DIRS})target_link_libraries(main PRIVATE ${FFMPEG_LIBAVFORMAT_LIBRARIES} ${FFMPEG_LIBAVCODEC_LIBRARIES} ${FFMPEG_LIBAVUTIL_LIBRARIES} ${FFMPEG_LIBSWSCALE_LIBRARIES} ${FFMPEG_LIBSWRESAMPLE_LIBRARIES})如果你的 CMake 版本不支持 FindFFmpeg,可以用 pkg-config:find_package(PkgConfig REQUIRED)pkg_check_modules(AVFORMAT REQUIRED libavformat)pkg_check_modules(AVCODEC REQUIRED libavcodec)pkg_check_modules(AVUTIL REQUIRED libavutil)add_executable(main main.cpp)target_compile_options(main PRIVATE ${AVFORMAT_CFLAGS} ${AVCODEC_CFLAGS})target_link_libraries(main PRIVATE ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${AVUTIL_LIBRARIES})链接顺序与常见错误链接顺序是集成的最大坑。FFmpeg 库之间存在依赖关系,必须按依赖顺序从左到右排列:-lavformat -lavcodec -lswscale -lswresample -lavutil -lm -lz -lpthreadlibavformat 依赖 libavcodec,libavcodec 依赖 libavutil,所以 libavformat 必须在前面。如果顺序反了,会报 undefined reference to avformat_open_input 之类的错误。Windows 上额外注意:需要把 FFmpeg 的 bin 目录加到 PATH,或在项目属性中设置 LIBRARY_PATH 和 INCLUDE 环境变量。如何用 FFmpeg API 解码视频帧?这是最常考的代码题。解码流程分五步:打开文件 → 查找流 → 打开解码器 → 读包解码 → 释放资源。#include <libavformat/avformat.h>#include <libavcodec/avcodec.h>int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s <input>\n", argv[0]); return 1; } // 1. 打开输入文件 AVFormatContext *fmt_ctx = NULL; if (avformat_open_input(&fmt_ctx, argv[1], NULL, NULL) < 0) { fprintf(stderr, "Cannot open input\n"); return 1; } avformat_find_stream_info(fmt_ctx, NULL); // 2. 查找视频流 int video_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); if (video_idx < 0) { fprintf(stderr, "No video stream\n"); avformat_close_input(&fmt_ctx); return 1; } // 3. 打开解码器 const AVCodec *codec = avcodec_find_decoder(fmt_ctx->streams[video_idx]->codecpar->codec_id); AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_idx]->codecpar); avcodec_open2(codec_ctx, codec, NULL); // 4. 读包解码 AVPacket *pkt = av_packet_alloc(); AVFrame *frame = av_frame_alloc(); while (av_read_frame(fmt_ctx, pkt) >= 0) { if (pkt->stream_index != video_idx) { av_packet_unref(pkt); continue; } if (avcodec_send_packet(codec_ctx, pkt) < 0) { av_packet_unref(pkt); continue; } while (avcodec_receive_frame(codec_ctx, frame) == 0) { printf("Frame %d: %dx%d fmt=%d\n", codec_ctx->frame_number, frame->width, frame->height, frame->format); } av_packet_unref(pkt); } // 5. 刷新解码器(处理缓存的帧) avcodec_send_packet(codec_ctx, NULL); while (avcodec_receive_frame(codec_ctx, frame) == 0) { printf("Flushed frame %d\n", codec_ctx->frame_number); } // 6. 释放资源 av_frame_free(&frame); av_packet_free(&pkt); avcodec_free_context(&codec_ctx); avformat_close_input(&fmt_ctx); return 0;}几个关键细节:avformat_find_stream_info() 不能省略,它填充流信息,否则 codecpar 中的字段可能不完整。av_find_best_stream() 比手动遍历流更可靠,它能处理多视频流的情况。解码结束后必须发送 NULL 包来刷新解码器,否则最后几帧会丢失。使用 av_packet_alloc() 而不是栈上的 AVPacket,这是 FFmpeg 新版推荐的写法。如何用 FFmpeg API 编码视频?解码的反向过程——编码同样高频出现。核心差异在于需要手动设置编码参数、管理时间戳。// 编码器初始化const AVCodec *encoder = avcodec_find_encoder(AV_CODEC_ID_H264);AVCodecContext *enc_ctx = avcodec_alloc_context3(encoder);enc_ctx->bit_rate = 400000;enc_ctx->width = 1920;enc_ctx->height = 1080;enc_ctx->time_base = (AVRational){1, 25};enc_ctx->framerate = (AVRational){25, 1};enc_ctx->gop_size = 10;enc_ctx->max_b_frames = 1;enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;// H.264 特定选项AVDictionary *opts = NULL;av_dict_set(&opts, "preset", "medium", 0);avcodec_open2(enc_ctx, encoder, &opts);av_dict_free(&opts);// 编码循环AVPacket *pkt = av_packet_alloc();for (int i = 0; i < frame_count; i++) { // ... 准备 frame 数据 ... frame->pts = i; avcodec_send_frame(enc_ctx, frame); while (avcodec_receive_packet(enc_ctx, pkt) == 0) { // 将 pkt 写入输出文件 av_packet_unref(pkt); }}// 刷新编码器avcodec_send_frame(enc_ctx, NULL);while (avcodec_receive_packet(enc_ctx, pkt) == 0) { av_packet_unref(pkt);}编码时最容易踩的坑是 PTS(显示时间戳)。每一帧必须设置递增的 PTS,否则输出文件的时间轴会混乱。时间基 time_base 决定了 PTS 的单位,{1, 25} 表示每秒 25 个单位。内存管理有哪些容易忽略的要点?FFmpeg 的 API 是纯 C 设计,没有自动内存管理。每个分配操作都有对应的释放操作,遗漏任何一步都会导致内存泄漏。| 分配函数 | 释放函数 | 说明 ||---------|---------|------|| avformat_open_input() | avformat_close_input() | 关闭输入并释放上下文 || avcodec_alloc_context3() | avcodec_free_context() | 释放解码器上下文 || av_frame_alloc() | av_frame_free() | 释放帧 || av_packet_alloc() | av_packet_free() | 释放包 || av_malloc() | av_free() | 通用内存分配 || sws_getContext() | sws_freeContext() | 释放缩放上下文 || swr_alloc() | swr_free() | 释放重采样上下文 |特别容易忽略的是 av_packet_unref()。每次 av_read_frame() 后,包内部的数据缓冲区被引用计数加一,必须调用 av_packet_unref() 减引用,否则数据缓冲区永远不会被释放。这不是 C++ 的 RAII,必须手动管理。另一个常见问题是 avformat_close_input() 会释放 AVFormatContext,之后不要再对它调用 av_free(),否则 double free。多线程解码需要注意什么?FFmpeg 支持线程级并行解码,但默认不开启。设置方式:enc_ctx->thread_count = 4; // 使用 4 个线程enc_ctx->thread_type = FF_THREAD_FRAME; // 帧级并行thread_type 有两个选项:FF_THREAD_SLICE:片级并行,一帧内多个 slice 并行解码。兼容性好但加速有限。FF_THREAD_FRAME:帧级并行,多帧同时解码。加速明显但延迟更高,需要更多内存缓存帧。实际使用中,FF_THREAD_FRAME 加速效果更好,但实时场景(如视频会议)应选 FF_THREAD_SLICE 降低延迟。注意:thread_count 的值不要超过 CPU 核心数,设置为 0 表示 FFmpeg 自动选择。常见集成问题排查Q: 编译报 undefined reference to av_xxxA: 99% 是链接顺序问题。确保 -lavformat 在 -lavcodec 前面,-lavcodec 在 -lavutil 前面。用 pkg-config --libs libavformat 查看正确的链接顺序。Q: 运行时报 Cannot open input fileA: 检查文件路径是否正确。Windows 上注意反斜杠问题,建议统一用正斜杠。另外确认文件格式是否被 FFmpeg 支持:ffmpeg -formats | grep mp4。Q: 解码出的帧颜色不对A: 缺少像素格式转换。解码输出通常是 YUV 格式,显示需要 RGB。用 libswscale 的 sws_scale() 转换。Q: 音视频不同步A: 时间戳管理问题。必须用 av_packet_rescale_ts() 在编码/复用时重新计算时间基,不能直接用解码帧的 PTS。实际项目中的最佳实践错误处理不能偷懒:每个 FFmpeg API 调用的返回值都要检查。生产环境建议封装统一的错误处理宏:#define CHECK_ERR(ret, msg) do { \ if (ret < 0) { \ char errbuf[128]; \ av_strerror(ret, errbuf, sizeof(errbuf)); \ fprintf(stderr, "%s: %s\n", msg, errbuf); \ goto cleanup; \ } \} while(0)日志分级:开发阶段设 av_log_set_level(AV_LOG_DEBUG),生产环境设 AV_LOG_WARNING 或 AV_LOG_ERROR。FFmpeg 默认日志级别太低,会输出大量信息。资源释放用 goto 模式:C 语言没有 defer,用 goto cleanup 是 FFmpeg 社区推荐的方式,确保任何错误路径都能正确释放已分配的资源。API 版本兼容:FFmpeg 不同版本之间 API 有变化。用 LIBAVCODEC_VERSION_MAJOR 等宏做版本判断,或在 CMake 中检测。FFmpeg 6.0 之后 avcodec_find_decoder() 返回 const AVCodec*,之前是非 const。避免在热路径中分配内存:av_frame_alloc() 和 av_packet_alloc() 应在循环外调用,循环内用 av_frame_unref() 和 av_packet_unref() 重置后复用。
前端阅读 05月28日 01:59

如何用FFmpeg调整视频的码率、分辨率和帧率?

在视频处理中,调整码率、分辨率和帧率是最常见的需求。无论是压缩视频体积、适配不同设备,还是优化流媒体传输,FFmpeg 都能通过命令行参数精确控制这三个核心参数。但参数设置不当容易导致画质劣化、播放卡顿甚至编码失败,所以需要理解每个参数的含义和适用场景。码率调整:控制视频体积与画质的平衡码率(bitrate)决定视频每秒的数据量,单位为 kbit/s 或 Mbit/s。码率越高画质越好,但文件体积也越大。FFmpeg 提供三种码率控制模式,适用场景各不相同。CBR:恒定码率CBR 保持码率不变,适合直播等对带宽要求稳定的场景:ffmpeg -i input.mp4 -c:v libx264 -b:v 5000k -minrate 5000k -maxrate 5000k -bufsize 10000k output.mp4将 -minrate、-maxrate 设为相同值即为 CBR 模式。-bufsize 设为码率的 2 倍可以保证码率稳定。VBR:可变码率VBR 根据画面复杂度动态调整码率,简单场景省码率、复杂场景多分配,适合点播和本地存储:ffmpeg -i input.mp4 -c:v libx264 -b:v 5000k -maxrate 8000k -bufsize 10000k output.mp4-b:v 设定平均码率,-maxrate 限制峰值码率防止突发流量。CRF:恒定质量(推荐)CRF(Constant Rate Factor)是 libx264/libx265 最推荐的码率控制方式,它按目标画质自动分配码率,无需手动指定码率值:ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium output.mp4CRF 取值范围 0-51,默认 23。常用范围:18-22:高质量,接近视觉无损23-28:质量与体积的平衡点,日常使用推荐28-32:明显压缩,适合对体积敏感的场景-preset 控制编码速度与压缩效率的平衡,从快到慢:ultrafast < superfast < veryfast < faster < fast < medium < slow < slower < veryslow。slow 压缩率更高但编码更慢,fast 编码快但文件更大。两遍编码(Two-Pass)对体积有严格要求的场景(如视频网站),使用两遍编码可以在精确控制文件大小的同时获得最佳画质:# 第一遍:分析视频内容ffmpeg -i input.mp4 -c:v libx264 -b:v 5000k -pass 1 -an -f null /dev/null# 第二遍:基于分析结果编码ffmpeg -i input.mp4 -c:v libx264 -b:v 5000k -pass 2 -c:a aac -b:a 128k output.mp4码率参考值不同分辨率下的推荐码率(H.264 编码):| 分辨率 | 建议码率范围 | 适用场景 ||--------|-------------|---------|| 480p (854x480) | 1000-2000 kbit/s | 移动端低清 || 720p (1280x720) | 2500-5000 kbit/s | 移动端高清 || 1080p (1920x1080) | 5000-8000 kbit/s | PC 端高清 || 4K (3840x2160) | 15000-30000 kbit/s | 大屏/专业用途 |分辨率调整:适配不同设备与带宽分辨率即画面的宽高像素数,直接影响清晰度。调整分辨率有两种方式,推荐使用滤镜方式。使用 scale 滤镜(推荐)# 固定分辨率ffmpeg -i input.mp4 -vf "scale=1280:720" -c:v libx264 -crf 23 output.mp4# 指定高度,宽度自动计算(保持宽高比)ffmpeg -i input.mp4 -vf "scale=-2:720" -c:v libx264 -crf 23 output.mp4-2 表示自动计算,保证宽度为偶数(编码器要求)。推荐这种写法,避免画面变形。使用 lanczos 算法提升缩放质量ffmpeg -i input.mp4 -vf "scale=1280:720:flags=lanczos" -c:v libx264 -crf 23 output.mp4lanczos 是高质量的缩放算法,下采样时比默认的 bicubic 更清晰,适合降低分辨率的场景。保持宽高比并补黑边目标容器有固定尺寸但不想裁剪画面时:ffmpeg -i input.mp4 -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" -c:v libx264 -crf 23 output.mp4使用 -s 参数(不推荐)ffmpeg -i input.mp4 -s 1280x720 -c:v libx264 -crf 23 output.mp4-s 直接指定分辨率,但无法保持宽高比,容易导致画面拉伸变形。仅在源视频比例已知时使用。帧率调整:匹配播放场景的需求帧率(fps)影响画面流畅度。常见帧率:24fps(电影)、25fps(PAL 制式)、30fps(网络视频)、60fps(游戏/运动画面)。直接设置帧率ffmpeg -i input.mp4 -r 24 -c:v libx264 -crf 23 output.mp4-r 直接指定输出帧率,FFmpeg 会自动丢帧或复制帧来匹配目标帧率。使用 fps 滤镜(推荐降帧场景)ffmpeg -i input.mp4 -vf "fps=24" -c:v libx264 -crf 23 output.mp4fps 滤镜比 -r 更精确,会均匀选取帧而非简单丢弃,画面过渡更平滑。使用 setpts 调整播放速度# 1.5 倍速播放(帧率相应提高)ffmpeg -i input.mp4 -vf "setpts=PTS/1.5" -c:v libx264 -crf 23 output.mp4# 0.5 倍速播放(慢放)ffmpeg -i input.mp4 -vf "setpts=2*PTS" -c:v libx264 -crf 23 output.mp4setpts 改变帧的时间戳,实现变速效果。注意变速时音频也需要同步处理(使用 atempo 滤镜)。使用 -vsync 控制同步模式ffmpeg -i input.mp4 -r 24 -vsync cfr -c:v libx264 -crf 23 output.mp4cfr:恒定帧率,不足的帧会复制,多余的帧丢弃,输出帧率严格恒定vfr:可变帧率,保持原始时间戳,不插帧不丢帧auto:根据输入自动选择(默认)直播和流媒体推荐 cfr,保证播放器解码稳定。查看视频信息:调整前先了解源文件调整参数前,先用 ffprobe 查看源视频信息:# 查看完整流信息ffprobe -v error -show_streams input.mp4# 只看码率ffprobe -v error -select_streams v:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1 input.mp4# 只看分辨率和帧率ffprobe -v error -select_streams v:0 -show_entries stream=width,height,r_frame_rate -of default=noprint_wrappers=1 input.mp4组合使用:常见场景的完整命令压缩视频体积(保持画质)ffmpeg -i input.mp4 -c:v libx264 -crf 28 -preset slow -c:a aac -b:a 128k output.mp4适配移动端(720p + 适中码率)ffmpeg -i input.mp4 -vf "scale=-2:720" -c:v libx264 -crf 26 -preset medium -c:a aac -b:a 128k output.mp4流媒体推送(固定码率 + 720p + 30fps)ffmpeg -i input.mp4 -vf "scale=-2:720" -c:v libx264 -b:v 3000k -maxrate 3500k -bufsize 6000k -r 30 -vsync cfr -c:a aac -b:a 128k output.mp4H.265 编码(同画质体积减半)ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset medium -c:a aac -b:a 128k output.mp4H.265/HEVC 比 H.264 在同等画质下节省约 40-50% 码率,但编码速度慢、兼容性稍差。常见问题调整后画质明显下降码率不足是主因。如果是用 -b:v 控制码率,尝试提高码率或改用 CRF 模式(-crf 23)。降分辨率时指定 lanczos 算法可以减少模糊。分辨率调整后画面变形没有保持宽高比。用 scale=-2:720 替代 scale=1280:720,让宽度自动计算。-2 保证宽度为偶数,满足编码器要求。帧率调整后播放抖动源帧率与目标帧率不匹配导致丢帧不均匀。使用 fps 滤镜(-vf "fps=24")替代 -r 参数,前者会均匀选帧;或加 -vsync cfr 强制恒定帧率输出。编码速度太慢降低 -preset 参数值(如从 slow 改为 fast),或使用硬件加速编码器(如 -c:v h264_videotoolbox macOS / -c:v h264_nvenc NVIDIA / -c:v h264_qsv Intel)。-vbr 参数不生效libx264 不支持 -vbr 参数。码率控制应使用 -crf(推荐)、-b:v + -maxrate(VBR 限峰)或两遍编码(-pass)。-vbr 仅适用于部分编码器(如 libvpx)。
前端阅读 05月28日 01:59

如何用FFmpeg实现直播推流?需要哪些命令和参数?

FFmpeg 推流的核心就三步:指定输入源、设置编码参数、指向推流地址。掌握这几个环节的组合方式,就能应对绝大多数直播推流场景。FFmpeg 推流的基本命令结构一条完整的推流命令长这样:ffmpeg -i input.mp4 -c:v libx264 -preset fast -crf 23 -c:a aac -b:a 128k -f flv rtmp://server/live/stream拆开来看:-i:输入源,可以是本地文件、摄像头设备或网络流-c:v / -c:a:视频/音频编码器,直播场景下视频常用 libx264,音频常用 aac-f flv:输出封装格式,RTMP 推流必须用 FLV最后的 URL:推流地址,格式为 rtmp://服务器地址/应用名/流名 -re 参数在推本地文件时必须加,它让 FFmpeg 按原始帧率读取输入,否则会以最快速度推完。推摄像头或 RTSP 等实时源时不需要加。视频编码参数怎么选?编码器与预设-c:v libx264 -preset veryfast -tune zerolatency-preset 控制编码速度与压缩率的平衡,从慢到快依次为 slow → medium → fast → veryfast → ultrafast。直播场景建议 veryfast 或 ultrafast,优先保证低延迟-tune zerolatency 关闭前瞻分析,进一步降低延迟,互动直播必加码率与质量控制两种控制方式选其一:方式一:CRF 恒定质量(适合带宽充足的场景)-crf 23 -maxrate 2500k -bufsize 5000kCRF 值越低质量越高,直播推荐 18-28。配合 -maxrate 和 -bufsize 设置上限,防止码率飙升导致卡顿。方式二:CBR 恒定码率(适合带宽受限的场景)-b:v 1500k -maxrate 1500k -bufsize 3000k码率固定,网络波动时更稳定。bufsize 通常设为 maxrate 的 2 倍。分辨率与帧率-s 1280x720 -r 25 -g 50 -keyint_min 25-g 设置 GOP 大小(关键帧间隔),建议等于帧率的 2 倍,方便客户端随时切入-keyint_min 设置最小关键帧间隔,与 -g 保持一致可确保关键帧间隔均匀音频编码参数怎么配?-c:a aac -b:a 128k -ar 44100 -ac 2-b:a 128k:音频码率,语音直播 96k 足够,音乐直播建议 128-192k-ar 44100:采样率,44100Hz 是标准值-ac 2:双声道,单声道直播可设为 1 如果遇到音画不同步,加 -async 1 强制音频同步,或用 -vsync cfr 固定视频帧率。常见推流场景的完整命令本地文件推流到 RTMP 服务器ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -crf 23 -maxrate 2500k -bufsize 5000k -c:a aac -b:a 128k -f flv rtmp://your-server.com/live/stream关键点:-re 按原始帧率推流,-crf 23 平衡质量与码率。摄像头实时推流(低延迟)ffmpeg -f v4l2 -i /dev/video0 -f alsa -i default -c:v libx264 -preset ultrafast -tune zerolatency -crf 28 -c:a aac -b:a 128k -f flv rtmp://server/live/low-latency关键点:-f v4l2 捕获 Linux 摄像头,macOS 用 -f avfoundation -i "0",Windows 用 -f dshow -i video="摄像头名称"。ultrafast + zerolatency 追求最低延迟。循环推流(24小时轮播)ffmpeg -re -stream_loop -1 -i input.mp4 -c:v libx264 -preset fast -b:v 1500k -c:a aac -b:a 128k -f flv rtmp://server/live/loop关键点:-stream_loop -1 无限循环,适合轮播场景。RTSP 转 RTMP 推流ffmpeg -rtsp_transport tcp -i rtsp://camera-ip/stream -c:v libx264 -preset veryfast -b:v 2000k -c:a aac -b:a 128k -f flv rtmp://server/live/camera关键点:-rtsp_transport tcp 用 TCP 拉取 RTSP 流,避免 UDP 丢包。如果 RTSP 源已经是 H.264 编码,可以用 -c:v copy 直接复制视频流,省去重编码开销。SRT 协议推流ffmpeg -re -i input.mp4 -c:v libx264 -preset fast -b:v 2500k -c:a aac -b:a 128k -f mpegts 'srt://server:9000?streamid=live/stream'关键点:SRT 在弱网环境下比 RTMP 更稳定,支持加密传输。输出格式用 mpegts 而非 flv。多路推流(同时推到多个平台)ffmpeg -re -i input.mp4 -c:v libx264 -preset fast -b:v 2000k -c:a aac -b:a 128k -f flv rtmp://platform-a.com/live/stream1 -c:v libx264 -preset fast -b:v 1500k -c:a aac -b:a 128k -f flv rtmp://platform-b.com/live/stream2关键点:每个输出地址前指定独立的编码参数,可实现不同平台推不同画质。硬件加速推流CPU 编码吃满时可以用 GPU 加速:# NVIDIA GPUffmpeg -hwaccel cuda -i input.mp4 -c:v h264_nvenc -preset p4 -b:v 2500k -c:a aac -b:a 128k -f flv rtmp://server/live/gpu# Intel GPU (VAAPI,Linux)ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -i input.mp4 -c:v h264_vaapi -b:v 2500k -c:a aac -b:a 128k -f flv rtmp://server/live/gpu# macOS (VideoToolbox)ffmpeg -hwaccel videotoolbox -i input.mp4 -c:v h264_videotoolbox -b:v 2500k -c:a aac -b:a 128k -f flv rtmp://server/live/gpu硬件编码延迟更低、吞吐更高,但画质略逊于 libx264 的 slow 预设。实际选择取决于业务优先级:画质选软编,性能选硬编。推流常见问题排查推流失败:Connection refused检查 RTMP 服务器地址和端口是否正确,确认服务器防火墙放行了 1935 端口。用 telnet server 1935 快速验证网络连通性。视频卡顿:帧率不稳或画面跳跃降低视频码率(-b:v 从 2500k 降到 1500k)增大缓冲区(-bufsize 设为 -maxrate 的 2-3 倍)换更快的编码预设(-preset ultrafast)音画不同步加 -async 1 强制音频同步加 -vsync cfr 固定视频帧率检查输入源本身是否同步(用 ffprobe 查看 PTS 信息)推流延迟过高加 -tune zerolatency 关闭前瞻减小 GOP 大小(-g 25)用 -preset ultrafast 加快编码考虑换 SRT 协议,弱网下延迟更低推流过程中断流加自动重连参数:ffmpeg -re -rtmp_live live -timeout 10000000 -i input.mp4 -c:v libx264 -preset fast -b:v 1500k -c:a aac -b:a 128k -f flv rtmp://server/live/stream配合 shell 脚本实现断线自动重启:while true; do ffmpeg -re -i input.mp4 -c:v libx264 -preset fast -b:v 1500k -c:a aac -b:a 128k -f flv rtmp://server/live/stream sleep 2done推流参数速查表| 场景 | 编码预设 | 码率 | CRF | GOP | 特殊参数 ||------|---------|------|-----|-----|---------|| 互动直播 | ultrafast + zerolatency | 1500-2500k | 28 | 50 | -tune zerolatency || 高清直播 | fast | 3000-6000k | 23 | 50 | -maxrate + -bufsize || 弱网推流 | veryfast | 800-1500k | 28 | 25 | SRT 协议 || 轮播推流 | fast | 1500-2500k | 23 | 50 | -stream_loop -1 || GPU 加速 | N/A (硬件编码) | 2500-4000k | N/A | 50 | -hwaccel cuda/vaapi |实际推流时没有万能参数组合,需要根据网络带宽、服务器配置和画质要求调整。建议先在测试环境用 ffmpeg -loglevel verbose 跑一遍,观察实际码率和丢帧情况再上线。
前端阅读 05月28日 00:29

遇到FFmpeg转码失败,如何定位和排查问题?

FFmpeg转码失败是视频工程中最头疼的问题之一——报错信息往往一大堆,但真正有用的线索却很难找。这篇文章整理了一套从快速定位到深层排查的实战方法,覆盖输入文件异常、编码器限制、资源瓶颈、硬件加速冲突等常见场景,帮你把排查时间从小时级压缩到分钟级。转码失败的三大典型原因转码失败看似千奇百怪,但归类下来逃不出这三类:输入文件有问题:容器格式损坏(比如MP4里嵌了非标准时间戳)、编码参数冲突(H.264流里包含不支持的B帧)、文件权限不足。跑一下ffmpeg -i corrupt.mp4,如果输出Invalid data found when processing input,就是文件结构本身有问题。编码器不兼容:不同编码器对输入码流有硬性要求。输入视频是10bit YUV420,目标编码器只支持8bit,就会报Encoder init failed。再比如输入是H.265流但系统没装libx265,也会直接报错。系统资源不够:低内存服务器跑4K转码,容易出现Out of memory或CPU过载。Docker容器里还可能遇到GPU设备未正确挂载的问题。先用ffprobe做个快速预检:ffprobe -v error -show_streams -show_format input.mp4如果Stream #0:0显示codec_name=unknown,容器大概率损坏了;如果SAR/DAR值为负数,得先修元数据再转码。四步排查法:从快到慢定位问题第一步:看错误日志,锁定方向别用默认日志级别,信息太多反而干扰。直接开error级别:ffmpeg -v error -i input.mp4 -c:v libx264 output.mp4常见错误信号:| 错误信息 | 含义 ||---------|------|| Invalid NAL unit | H.264流损坏 || 1 output(s) and 0 input(s) are available | 滤镜链配置错误 || Encoder init failed | 编码器不支持输入格式 || frame size mismatch | 输入帧大小不一致 || Permission denied | 文件路径或写入权限问题 |第二步:隔离输入文件,确认源是否正常用ffplay试播一下:ffplay -v error -i input.mp4播不了就先解决输入文件的问题。能播但转码失败,问题大概率在编码器参数或资源限制上。第三步:最小化命令测试,排除参数干扰把复杂参数全去掉,先跑最基础的转码:ffmpeg -v error -i input.mp4 -c:v copy -c:a aac output.mp4成功了说明输入文件没问题,故障在编码器参数上。这时逐步加参数,每次加一个,出错了就知道是哪个参数惹的祸。如果连-c:v copy都失败,那就是输入文件本身有问题,回到第二步。第四步:开debug日志,深挖根因前三步还没定位到?上debug级别日志:ffmpeg -loglevel debug -report -i input.mp4 -c:v libx264 -crf 23 output.mp4-report会生成详细日志文件,里面记录了每一步的处理过程。日志里出现encoding pass 1但后面没有pass 2,说明输入流中途断了。用grep快速过滤关键错误:cat ffmpeg-*.log | grep -i 'error\|fail\|invalid'生产环境高频踩坑场景硬件加速转码失败用VAAPI或NVENC做硬件加速转码时,失败率比纯软件编码高得多:VAAPI初始化失败:检查/sys/kernel/debug/dri/路径是否存在,Docker容器里需要把GPU设备正确挂载进去(--device /dev/dri:/dev/dri)NVENC报错:确认驱动版本和nvidia-container-toolkit是否匹配,驱动太老会直接初始化失败Intel低功耗编码:GuC和HuC固件是否正常运行,sudo cat /sys/kernel/debug/dri/0/i915_guc_info可以确认排查思路:先用纯软件编码测试,成功后再切换硬件加速,这样能快速判断是硬件环境的问题还是命令参数的问题。Docker容器里转码异常Docker是转码问题的高发地带,常见坑:GPU设备没挂载,硬件加速不可用容器内FFmpeg版本和宿主机不一致,编码器支持列表不同/etc/ld.so.conf.d/里缺少库路径配置,动态链接找不到编解码库容器内存限制太紧,转码4K视频时OOM建议在Dockerfile里明确安装需要的编解码库,别依赖基础镜像自带的。版本兼容性问题FFmpeg不同版本差异很大:老版本的-autorotate参数在新版本被废弃了,会直接报错某些编码器只在特定编译配置下可用(ffmpeg -encoders查看当前支持的编码器列表)从源码编译时如果没加--enable-libx265,HEVC编码就不可用关键操作:转码前先确认环境,跑一下ffmpeg -version和ffmpeg -encoders | grep libx265。自动化排查脚本日常巡检可以跑这个脚本,批量检查输入文件是否有效:#!/bin/bashfor file in *.mp4; do if ! ffprobe -v error -i "$file" &>/dev/null; then echo "[INVALID] $file" else codec=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of csv=p=0 "$file") echo "[OK] $file - codec: $codec" fidone转码任务建议加上资源监控,内存超过80%就该报警了:ffmpeg -i input.mp4 -c:v libx264 output.mp4 &PID=$!while kill -0 $PID 2>/dev/null; do mem=$(ps -o %mem -p $PID --no-headers | tr -d ' ') if (( $(echo "$mem > 80" | bc -l) )); then echo "WARNING: Memory usage ${mem}%" fi sleep 5done常见错误速查表| 报错信息 | 原因 | 解决方法 ||---------|------|---------|| Invalid data found when processing input | 输入文件损坏 | 用ffprobe检查,尝试用mkvtoolnix修复 || Encoder init failed | 编码器不支持输入格式 | 安装对应编码库或转换输入格式 || Invalid NAL unit | H.264流损坏 | 尝试-c:v copy跳过重编码 || frame size mismatch | 输入帧大小不一致 | 加-s 1920x1080强制统一 || Out of memory | 内存不足 | 降低分辨率或增加交换空间 || Unknown encoder 'libx265' | 编码库未安装 | sudo apt install libx265-dev重新编译 || Permission denied | 文件权限问题 | 检查路径权限和磁盘空间 || SAR/DAR negative value | 元数据异常 | 用mkvtoolnix重封装修复 |排查FFmpeg转码问题,核心就是"先隔离再定位":先确认输入文件正常,再用最小命令验证基础链路,最后才上复杂参数。生产环境里,日志监控(比如ELK Stack采集FFmpeg日志)和资源告警比事后排查更重要——转码失败往往不是单一原因,而是输入格式、编码器配置、系统资源多维叠加的结果,实时监控能在问题扩散前就抓住线索。