一、核心结构体:作用 + 必记成员
1. AVFormatContext(全局总管)
- 核心作用:统领封装 / 解封装、流管理,是 FFmpeg 推流 / 拉流的 "总入口"。
- 必记成员 :
iformat/oformat:输入 / 输出封装格式(推流用oformat)。
streams:音视频流列表(推流时存视频 / 音频流)。
nb_streams:流的数量(如 1 个视频流则为 1)。
pb:IO 上下文(关联 AVIOContext,负责数据读写)。
url:推流目标地址(如 RTMP://xxx)。
- 核心作用:指定输出文件 / 流的封装格式(如 RTMP、MP4),提供写数据接口。
- 必记成员 :
name:格式名称(如 "rtmp""mp4")。
video_codec/audio_codec:默认视频 / 音频编解码器 ID(如 H264、AAC)。
write_header():写封装头(推流前必须调用)。
write_packet():写编码后的数据包(推流核心接口)。
write_trailer():写封装尾(推流结束调用)。
3. AVStream(流容器)
- 核心作用:存储单个音视频流的完整信息(如视频分辨率、音频采样率)。
- 必记成员 :
index:流索引(推流时区分视频流 0 / 音频流 1)。
time_base:流的时间基(将 PTS/DTS 转换为实际时间,如 1/90000)。
duration:流总时长(以 time_base 为单位)。
codecpar:编解码参数(存分辨率、码率等,替代旧版codec)。
avg_frame_rate:平均帧率(视频流专用)。
4. AVCodec(编解码器实体)
- 核心作用:封装具体编解码算法(如 H264 编码器、AAC 解码器)。
- 必记成员 :
name:编码器名称(如 "h264""aac")。
type:媒体类型(AVMEDIA_TYPE_VIDEO/AUDIO)。
id:编解码器 ID(AV_CODEC_ID_H264/AV_CODEC_ID_AAC)。
encode2():编码接口(将 AVFrame 转为 AVPacket)。
decode():解码接口(将 AVPacket 转为 AVFrame)。
5. AVCodecContext(编解码上下文)
- 核心作用:配置编解码参数、管理编解码过程的 "环境变量"。
- 必记成员 :
codec:关联的 AVCodec(指定用哪个编解码器)。
width/height:视频分辨率(编码前必须设置)。
bit_rate:编码码率(如 1000000=1Mbps)。
pix_fmt:视频像素格式(如AV_PIX_FMT_YUV420P)。
sample_rate/channels:音频采样率 / 声道数。
time_base:编解码时间基(需与 AVStream 对应)。
6. AVPacket(编码数据包)
- 核心作用:存储编解码后的压缩数据(推流传输的核心数据载体)。
- 必记成员 :
data:压缩数据缓冲区(如 H264 裸流、AAC 帧)。
size:压缩数据长度(字节数)。
pts:显示时间戳(控制播放顺序,需按 time_base 转换)。
dts:解码时间戳(控制解码顺序)。
stream_index:所属流索引(标记是视频流还是音频流)。
flags:标记(AV_PKT_FLAG_KEY表示关键帧)。
7. AVFrame(原始数据帧)
- 核心作用:存储解码后的原始数据(如视频 YUV、音频 PCM)。
- 必记成员 :
data:原始数据缓冲区(视频 YUV 分 3 个平面,音频 PCM 存 1 个平面)。
width/height:视频帧分辨率。
nb_samples:音频帧采样数。
format:原始数据格式(视频AV_PIX_FMT_YUV420P,音频AV_SAMPLE_FMT_S16)。
key_frame:是否为关键帧(1 = 是,0 = 否)。
pts:显示时间戳(继承自 AVPacket)。
8. AVIOContext(IO 上下文)
- 核心作用:管理 FFmpeg 的输入 / 输出 IO(如网络推流、文件读写)。
- 必记成员 :
buffer:IO 缓存区(临时存储待读写数据)。
buf_ptr/buf_end:缓存区当前位置 / 结束位置。
opaque:私有指针(关联 URLContext,处理协议逻辑)。
read_packet/write_packet:读写数据回调(推流用write_packet)。
seek:定位回调(推流场景较少用)。
二、推流场景核心逻辑链路(帮你串联结构体)
- 用AVFormatContext创建推流上下文,绑定AVOutputFormat(如 RTMP)和AVIOContext(网络 IO)。
- 用AVStream创建视频 / 音频流,通过codecpar配置分辨率、码率等参数。
- 用AVCodecContext初始化编解码器(如 H264),关联AVCodec。
- 原始数据(摄像头采集)存入AVFrame,调用encode2()编码为AVPacket。
- 给AVPacket设置pts/dts/stream_index,调用write_packet()推流。
- 推流结束,调用write_trailer()关闭上下文。
FFmpeg 推流:结构体 + 代码调用对应表(直接套用)
按推流流程拆解,每个步骤明确核心结构体、关键成员及实战代码,贴合 RV1126 硬件编码推流场景:
一、初始化推流上下文(核心:AVFormatContext + AVOutputFormat)
关联结构体及核心成员
| 结构体 |
核心成员 |
作用 |
| AVFormatContext |
oformat、pb、url、streams |
统领推流全局,绑定输出格式和 IO |
| AVOutputFormat |
name、video_codec |
指定推流封装格式(如 RTMP) |
关键代码
cpp
复制代码
// 1. 分配AVFormatContext(推流核心上下文)
AVFormatContext *fmt_ctx = avformat_alloc_context();
// 2. 指定输出格式(RTMP为例,对应AVOutputFormat)
fmt_ctx->oformat = av_guess_format("flv", "rtmp://xxx", NULL); // flv是RTMP封装格式
fmt_ctx->url = av_strdup("rtmp://your_server/stream"); // 推流地址
// 3. 打开IO上下文(关联AVIOContext,负责网络读写)
if (avio_open(&fmt_ctx->pb, fmt_ctx->url, AVIO_FLAG_WRITE) < 0) {
printf("IO打开失败\n");
return -1;
}
二、创建视频流 + 配置编解码(核心:AVStream + AVCodecContext + AVCodec)
关联结构体及核心成员
| 结构体 |
核心成员 |
作用 |
| AVStream |
index、time_base、codecpar |
存储视频流参数 |
| AVCodecContext |
codec、width、height、pix_fmt、bit_rate |
编解码配置(分辨率、码率等) |
| AVCodec |
id、type |
绑定硬件 / 软件编码器(如 H264) |
关键代码
cpp
复制代码
// 1. 创建视频流(关联AVStream)
AVStream *video_stream = avformat_new_stream(fmt_ctx, NULL);
video_stream->index = 0; // 视频流索引(音频流设为1)
video_stream->time_base = (AVRational){1, 25}; // 时间基:25帧/秒
// 2. 配置编解码参数(AVCodecContext + AVCodec)
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264); // H264编码器
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
codec_ctx->codec = codec;
codec_ctx->width = 1920; // 1080P
codec_ctx->height = 1080;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; // 像素格式
codec_ctx->bit_rate = 2000000; // 2Mbps码率
codec_ctx->time_base = video_stream->time_base;
// 3. 绑定编解码参数到流(codecpar替代旧版codec成员)
avcodec_parameters_from_context(video_stream->codecpar, codec_ctx);
// 4. 打开编码器
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
printf("编码器打开失败\n");
return -1;
}
三、写入封装头(核心:AVFormatContext + AVOutputFormat)
关联结构体及核心成员
| 结构体 |
核心成员 |
作用 |
| AVFormatContext |
oformat、priv_data |
传递配置给输出格式 |
| AVOutputFormat |
write_header() |
生成封装头(推流必需步骤) |
关键代码
cpp
复制代码
// 写入RTMP/flv封装头(调用AVOutputFormat的write_header回调)
if (avformat_write_header(fmt_ctx, NULL) < 0) {
printf("封装头写入失败\n");
return -1;
}
四、编码 + 推流(核心:AVFrame + AVPacket)
关联结构体及核心成员
| 结构体 |
核心成员 |
作用 |
| AVFrame |
data、width、height、format、pts |
存储 RV1126 硬件编码前的 YUV 数据 |
| AVPacket |
data、size、pts、dts、stream_index、flags |
存储编码后的 H264 码流,用于推流 |
关键代码(RV1126 硬件编码适配)
cpp
复制代码
AVFrame *frame = av_frame_alloc();
AVPacket *pkt = av_packet_alloc();
// 1. 填充RV1126采集的YUV数据(frame为原始数据,对应AVFrame核心成员)
frame->data[0] = yuv_buf; // Y分量数据
frame->data[1] = yuv_buf + width*height; // U分量
frame->data[2] = yuv_buf + width*height*5/4; // V分量
frame->linesize[0] = width;
frame->width = width;
frame->height = height;
frame->format = AV_PIX_FMT_YUV420P;
frame->pts = frame_idx * av_q2d(video_stream->time_base) * AV_TIME_BASE; // 计算PTS
// 2. 发送帧到编码器编码(RV1126可替换为硬件编码接口)
avcodec_send_frame(codec_ctx, frame);
// 3. 接收编码后的数据包(AVPacket为推流数据载体)
while (avcodec_receive_packet(codec_ctx, pkt) == 0) {
// 绑定数据包到视频流(stream_index对应AVStream的index)
pkt->stream_index = video_stream->index;
pkt->pts = av_rescale_q(pkt->pts, codec_ctx->time_base, video_stream->time_base); // 时间基转换
pkt->dts = av_rescale_q(pkt->dts, codec_ctx->time_base, video_stream->time_base);
pkt->flags |= AV_PKT_FLAG_KEY; // 关键帧标记(必加,否则无法解码)
// 4. 推流核心:写入数据包(调用AVOutputFormat的write_packet)
av_interleaved_write_frame(fmt_ctx, pkt);
av_packet_unref(pkt); // 释放数据包
}
av_frame_unref(frame);
五、推流收尾(核心:AVFormatContext)
关联结构体及核心成员
| 结构体 |
核心成员 |
作用 |
| AVFormatContext |
oformat、pb |
写入封装尾 + 关闭 IO |
| AVOutputFormat |
write_trailer() |
生成封装尾,结束推流 |
关键代码
cpp
复制代码
// 1. 写入封装尾
av_write_trailer(fmt_ctx);
// 2. 释放资源(按顺序释放,避免内存泄漏)
avcodec_close(codec_ctx);
avcodec_free_context(&codec_ctx);
avio_close(fmt_ctx->pb);
avformat_free_context(fmt_ctx);
av_packet_free(&pkt);
av_frame_free(&frame);
核心总结
- 推流的核心逻辑:
AVFrame(原始数据)→ 编码 → AVPacket(压缩数据)→ AVFormatContext(封装)→ AVIOContext(推流)
- 每个结构体各司其职:Context 类(AVFormatContext、AVCodecContext)管配置,数据类(AVFrame、AVPacket)存数据,Format 类(AVOutputFormat)管封装
- 直接套用上述代码,替换推流地址、分辨率、码率,即可适配 RV1126 硬件编码推流场景。