多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

FFmpeg 的 bitstream filter:99% 的人用错了,但它真的在“救命”

FFmpeg 的 bitstream filter:99% 的人用错了,但它真的在“救命” 目录一、先划红线BSF ≠ Filter二、一张表看懂BSF 到底在干什么三、一个灵魂问题为什么 MP4 → RTSP 一定要 BSF因为 H264 有两种“方言”正确解法不是 hack四、BSF 在 FFmpeg 内部的真实位置非常重要五、用代码用明白 BSF新版 API① 初始化 BSF推荐 av_bsf_* API② demux → BSF → 用 packet六、最常用的 5 个 BSF逐个说人话1️. h264_mp4toannexb/ hevc_mp4toannexb2️. aac_adtstoasc3️. h264_metadata/ hevc_metadata真·狠活4️. extract_extradata5️. setts低延迟神器七、BSF 三大误区八、一个判断公式九、和 muxer 的边界感十、总结核心作用与机制典型应用场景觉得有用就请您帮忙点赞转发收藏吧您的鼓励是我创作的动力多谢看官。由于能力水平有限文中的错误或不严谨的地方在所难免还请批评指正。Bitstream Filter比特流滤波器是 FFmpeg 中用于在‌不解码‌的情况下直接操作编码媒体数据如 H.264、HEVC 等的工具。它主要作用于AVPacket层面常用于修改头部信息、转换封装格式或提取特定数据。如果你用过 FFmpeg 转封装 H264大概率见过这两行东西-bsf:v h264_mp4toannexb -bsf:a aac_adtstoasc然后你搜了一圈看到一句话“bitstream filter 是用来修正码流的”然后就没下文了。今天把这层窗户纸捅穿。一句话定义先给bitstream filterBSF不是滤镜不是编码器也不是 remux 工具​它是“在 AVPacket 还没进解码器 / 刚出编码器后对裸码流字节动手脚的整形手术刀”一、先划红线BSF ≠ Filter概念操作对象数据形态filterlibavfilterAVFrameYUV / PCMencoder / decoderFrame ↔ Packet像素↔压缩bitstream filter​AVPacket.data​NALU / ADTS / SEI 字节流​muxerAVPackettimestamp streamBSF 连像素都没见过二、一张表看懂BSF 到底在干什么场景问题本质BSF 名字MP4 → TS / RTSPH264 是 length-prefixed传输要 startcodeh264_mp4toannexbFLV / MP4 存 AAC缺 ADTS headeraac_adtstoasc/ 反向HEVC 推流花屏VPS/SPS/PPS 没塞进 IDRhevc_mp4toannexb抽 SPS 打印分辨率NALU 藏在 extradataextract_extradata去 B 帧GOP 太大没法低延迟h264_metadata改 profile / level设备不认 High5.1h264_metadata删 SEI海康摄像头 SEI 爆炸dump_extra抽 keyframe切 HLSsetts三、一个灵魂问题为什么 MP4 → RTSP 一定要 BSF因为 H264 有两种“方言”容器NALU 写法MP4 / MOV / FLV[size][nalu]AVCCTS / RTP / RTSP00 00 00 01 [nalu]AnnexBFFmpeg 内部MP4 demux → AVPacket.data size nalu RTSP mux → 要求 AnnexBmuxer 不管这事于是你得到non-existing PPS 0 referenced正确解法不是 hackffmpeg -i in.mp4 -c copy -bsf:v h264_mp4toannexb out.ts代码里也是同理const AVBitStreamFilter* bsf av_bsf_get_by_name(h264_mp4toannexb);四、BSF 在 FFmpeg 内部的真实位置非常重要demuxer ↓ AVPacket ↓ ←───────────────┐ encoder (output side) │ ↑ │ BSF 在这里 AVPacket → BSF → muxer│ ↓ │ decoder input │ ↓ └─→ extract_extradata / dump_extra AVFrame也就是说输入侧 BSFdemux 出来先修一遍MP4 → TS输出侧 BSFencode 完再补 headerFLV / RTMP五、用代码用明白 BSF新版 API① 初始化 BSF推荐 av_bsf_* APIconst AVBitStreamFilter* bsf_f av_bsf_get_by_name(h264_mp4toannexb); AVBSFContext* bsf_ctx nullptr; av_bsf_alloc(bsf_f, bsf_ctx); // 继承 codecpar关键 avcodec_parameters_copy(bsf_ctx-par_in, fmt_ctx-streams[v]-codecpar); av_bsf_init(bsf_ctx);② demux → BSF → 用 packetAVPacket* pkt av_packet_alloc(); while (av_read_frame(fmt_ctx, pkt) 0) { if (pkt-stream_index v_idx) { AVPacket* out av_packet_alloc(); av_bsf_send_packet(bsf_ctx, pkt); while (av_bsf_receive_packet(bsf_ctx, out) 0) { // out-data 已经是 AnnexB send_to_rtp(out); av_packet_unref(out); } } av_packet_unref(pkt); }不要直接改 pkt-data​BSF 会帮你 alloc / realloc六、最常用的 5 个 BSF逐个说人话1️.h264_mp4toannexb/hevc_mp4toannexbRTSP / UDP / TS 播放器保命符什么时候必加-f rtsp-f mpegts-f flvH2652️.aac_adtstoascMP4 / FLV 需要 ASCAudioSpecificConfig-bsf:a aac_adtstoasc⚠️ 方向搞反就炸MP4 → RTMPADTS → ASCRTMP dump → file反过来很少用3️.h264_metadata/hevc_metadata真·狠活-bsf:v h264_metadataaudremove:sei_user_dataremove能干的事删 AUD / SEI强制 idr_pic_id改 level/profile关 weighted pred海康 / 大华摄像头救星4️.extract_extradata-bsf:v extract_extradata用途不解码拿 SPS width/heightlibavformat 内部用得多自己写播放器抽信息5️.setts低延迟神器-bsf:v settsdts0:ptsN/N:tb1/1000RTMP / SRT 时间戳乱飞时强行重置 DTS/PTS防止 muxer 拒收七、BSF 三大误区误区后果BSF 能减延迟❌ 只能避免更大延迟-c copy不用 BSF❌ TS 推流必挂一个 BSF 修所有❌ 视频音频各一套多个 BSF 逗号拼✅ 可以但有顺序-bsf:v h264_mp4toannexb,dump_extrafreqkeyframe八、一个判断公式只要满足不改编码不改画面只是“容器不认码流” 90% 是 bitstream filter 的事九、和 muxer 的边界感谁负责举例muxer时间戳、track、header boxBSFNALU 格式、SEI、profile trickdecoderslice、宏块filterresize / denoisemuxer 永远假设你给的 packet 是“标准裸流”十、总结FFmpeg 里真正“不改画质、不改体积、但能救活一个流”的东西只有两个rtsp_flags bitstream filter核心作用与机制‌零损耗处理‌仅操作编码比特流如 H.264 NALU、AAC 帧跳过耗时的解码/编码过程保持画质音质无损且效率极高 。‌格式桥接‌解决不同容器对编码数据封装格式的差异如 MP4 的 AVCC 长度前缀格式转 TS 流的 Annex B 起始码格式。‌流结构优化‌移除冗余数据如重复 PPS、提取/注入参数集SPS/PPS、拆分或合并帧如 VP9 超帧。‌元数据控制‌修改或剥离流内嵌入的元数据如色彩空间、杜比视界 RPU、SEI 用户数据。‌‌典型应用场景‌容器转换兼容‌MP4/MKVAVCC 格式转 TS/裸流Annex B 格式时使用h264_mp4toannexb或hevc_mp4toannexb添加起始码 。‌音频封装适配‌将 AAC 的 ADTS 头转换为 MP4/FLV 所需的 ASC 格式使用aac_adtstoasc否则可能导致播放无声 。‌流修复与清洗‌移除冗余 PPS (h264_redundant_pps)、剥离特定 NALU 单元 (filter_units) 或清理填充数据 (chomp)。‌调试分析‌使用trace_headers打印码流头信息以诊断底层编码问题 。‌‌
返回列表