初步学习FFmpeg

前言:本人的项目需要用到FFmpeg进行拉流,因此最近在学习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))

三、FFmpeg七大核心结构体详解

[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 都是阻塞接口,网络异常时会永久卡死。

通过中断回调可以实现:主动停止拉流、断流超时自动重连、读写超时强制退出,是流媒体服务稳定性优化的必备手段。