前言:本人的项目需要用到FFmpeg进行拉流,因此最近在学习FFmpeg,写下这篇博客记录自己的收获。整理了FFmpeg底层基础、核心结构体。
目录
[1.1 FFmpeg六大官方子库分工](#1.1 FFmpeg六大官方子库分工)
[1.2 FFmpeg版本兼容规则(官方标准)](#1.2 FFmpeg版本兼容规则(官方标准))
[二、流媒体核心概念:转封装 vs 转码](#二、流媒体核心概念:转封装 vs 转码)
[2.1 容器与编码格式通俗类比](#2.1 容器与编码格式通俗类比)
[2.2 转封装(Remux)VS 转码(Transcode)](#2.2 转封装(Remux)VS 转码(Transcode))
[3.1 AVFormatContext:容器总控上下文](#3.1 AVFormatContext:容器总控上下文)
[3.2 AVIOContext:底层IO读写层](#3.2 AVIOContext:底层IO读写层)
[3.3 AVStream:单条音视频轨道](#3.3 AVStream:单条音视频轨道)
[3.4 AVCodecParameters:编码参数结构体](#3.4 AVCodecParameters:编码参数结构体)
[3.5 AVPacket:压缩数据包](#3.5 AVPacket:压缩数据包)
[3.6 AVRational:分数时间基准(避坑重点)](#3.6 AVRational:分数时间基准(避坑重点))
[3.7 interrupt_callback:阻塞中断回调](#3.7 interrupt_callback:阻塞中断回调)
一、FFmpeg整体架构与六大核心子库
1.1 FFmpeg六大官方子库分工
FFmpeg不是单一库,而是一套模块化音视频工具库,不同子库各司其职,流媒体开发中按需引入即可,无需全部依赖:
| 子库名称 | 核心功能 | 常用开发场景 |
|---|---|---|
| libavformat | 音视频解封装、封装、IO流读写、协议解析(RTSP/HLS/HTTP) | 流媒体拉流、推流、文件读写、转封装(开发必用) |
| libavcodec | 音视频编解码、比特流过滤器BSF、码流格式转换 | 视频解码、编码、H264码流格式转换 |
| libavutil | 通用工具类:内存管理、时间基准、日志、中断回调、数据缓冲区 | 几乎所有FFmpeg开发都需要依赖 |
| libavfilter | 音视频滤镜:加水印、裁剪、混音、画面特效 | 需要画面处理、音频混音场景 |
| libswscale | 图像像素格式转换、画面分辨率缩放 | 视频画面裁剪、格式转换 |
| libswresample | 音频重采样、声道转换、音频混音 | 音频采样率、声道格式统一 |
1.2 FFmpeg版本兼容规则(官方标准)
FFmpeg每个子库都自带version.h版本头文件,分为主版本MAJOR、次版本MINOR、微版本MICRO,版本迭代规则如下:
-
主版本号MAJOR变更:发生不向前兼容的破坏性改动,比如删除公开API、调整结构体成员顺序,旧代码直接编译报错
-
次版本号MINOR变更:向前兼容,新增公开API、新增编解码器、新增功能特性,旧代码无感知
-
微版本号MICRO变更:小范围bug修复、未定义行为逻辑调整,不改动API接口
官方核心保障:只要子库主版本号不变,FFmpeg保证API、ABI完全向前兼容,无论是重新编译项目,还是动态替换FFmpeg库文件,原有业务代码无需任何修改即可正常运行。
二、流媒体核心概念:转封装 vs 转码
2.1 容器与编码格式通俗类比
-
编码格式(H264/H265/AAC):箱子里面的实物,是真正压缩后的音视频原始数据
-
容器格式(MP4/TS/FLV/MKV):外包装快递箱,负责打包音视频轨道、时间戳同步、文件索引,不改动内部视频画面
2.2 转封装(Remux)VS 转码(Transcode)
| 类型 | 原理 | 性能损耗 | 画质变化 | 适用场景 |
|---|---|---|---|---|
| 转封装Remux | 只更换外包装容器,不解码、不重新编码,直接拷贝原始压缩码流 | 极低,无CPU编解码开销 | 画质无损 | RTSP转HLS、MP4转TS、直播流分发 |
| 转码Transcode | 先解码原始码流→处理画面/音频→重新编码,改动视频原始数据 | 极高,占用大量CPU | 画质有损 | 分辨率缩放、码率压缩、编码格式切换(H264转H265) |
主流流媒体直播场景优先使用转封装,兼顾低延迟和服务器性能。
三、FFmpeg七大核心结构体详解
FFmpeg拉流、解封装、读写帧的完整链路:IO层(AVIOContext) → 容器总控(AVFormatContext) → 音视频轨道(AVStream) → 编码参数(AVCodecParameters) → 压缩数据包(AVPacket)
3.1 AVFormatContext:容器总控上下文
整个音视频流/文件的总管理者,打开流之后所有全局信息全部存在该结构体中,是FFmpeg开发最顶层对象。
AVFormatContext
├─ nb_streams // 音视频轨道总数量
├─ streams[] // 所有轨道数组(视频轨、音频轨、字幕轨)
├─ pb // 底层IO上下文,负责字节流读写
├─ duration // 媒体总时长(直播流无该字段)
├─ bit_rate // 整体码率
└─ interrupt_callback // 阻塞操作中断回调(解决ffmpeg卡死核心)
核心生命周期:分配上下文→打开流地址→探测流信息→循环读取帧→关闭释放资源
3.2 AVIOContext:底层IO读写层
FFmpeg不直接操作网络socket和文件,所有字节读写都经过AVIOContext,支持自定义IO拦截。
开发妙用:可以拦截原生读写回调,统计流量、检测断流时间、自定义数据读写逻辑,精准监控流状态。
3.3 AVStream:单条音视频轨道
一个视频流包含多条独立轨道,常见为1条视频轨+1条音频轨:
AVStream
├─ index // 当前轨道下标
├─ codecpar // 轨道编码参数(核心)
├─ time_base // 时间基准(时间戳换算核心)
├─ r_frame_rate // 视频帧率
└─ start_time // 轨道起始时间偏移
3.4 AVCodecParameters:编码参数结构体
保存当前轨道所有编解码配置,复制该结构体即可无损复制流参数,转封装开发核心依赖。
AVCodecParameters
├─ codec_type // 轨道类型:视频/音频/字幕
├─ codec_id // 编码类型:H264/H265/AAC
├─ width, height // 视频分辨率
├─ extradata // 编码额外配置数据(H264专属SPS/PPS)
└─ extradata_size // 额外数据长度
3.5 AVPacket:压缩数据包
解封装之后读取到的原始压缩码流包,未解码,转封装全程只操作AVPacket,不做解码。
AVPacket
├─ data // 压缩码流数据指针
├─ size // 数据包字节大小
├─ stream_index // 归属轨道下标
├─ pts // 显示时间戳
├─ dts // 解码时间戳
├─ flags // 帧标记,可判断是否为关键帧
└─ duration // 当前帧持续时间
3.6 AVRational:分数时间基准(避坑重点)
FFmpeg全程不用浮点数记录时间,采用分数结构体避免浮点精度误差:AVRational = num/den秒。
常见时间基准:
-
TS/HLS流媒体:1/90000(90kHz标准时钟)
-
音频流:1/采样率(44100/48000)
内置工具函数:av_q2d 快速将分数转为浮点数值。
3.7 interrupt_callback:阻塞中断回调
FFmpeg原生av_read_frame、avformat_open_input 都是阻塞接口,网络异常时会永久卡死。
通过中断回调可以实现:主动停止拉流、断流超时自动重连、读写超时强制退出,是流媒体服务稳定性优化的必备手段。