FFMPEG核心结构体

一、核心结构体:作用 + 必记成员

1. AVFormatContext(全局总管)

  • 核心作用:统领封装 / 解封装、流管理,是 FFmpeg 推流 / 拉流的 "总入口"。
  • 必记成员
    • iformat/oformat:输入 / 输出封装格式(推流用oformat)。
    • streams:音视频流列表(推流时存视频 / 音频流)。
    • nb_streams:流的数量(如 1 个视频流则为 1)。
    • pb:IO 上下文(关联 AVIOContext,负责数据读写)。
    • url:推流目标地址(如 RTMP://xxx)。

2. AVOutputFormat(输出格式器)

  • 核心作用:指定输出文件 / 流的封装格式(如 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:定位回调(推流场景较少用)。

二、推流场景核心逻辑链路(帮你串联结构体)

  1. 用AVFormatContext创建推流上下文,绑定AVOutputFormat(如 RTMP)和AVIOContext(网络 IO)。
  2. 用AVStream创建视频 / 音频流,通过codecpar配置分辨率、码率等参数。
  3. 用AVCodecContext初始化编解码器(如 H264),关联AVCodec。
  4. 原始数据(摄像头采集)存入AVFrame,调用encode2()编码为AVPacket。
  5. 给AVPacket设置pts/dts/stream_index,调用write_packet()推流。
  6. 推流结束,调用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 硬件编码推流场景。
相关推荐
山土成旧客2 小时前
【Python学习打卡-Day28】类的蓝图:从模板到对象的构建艺术
linux·python·学习
怀旧,2 小时前
【Linux系统编程】14. 库使用与原理(上)
linux·运维·服务器
QT 小鲜肉2 小时前
【Linux命令大全】001.文件管理之locate命令(实操篇)
linux·运维·服务器·chrome·笔记
嘻哈baby2 小时前
eBPF技术入门与实战:Linux内核黑科技
linux
风好衣轻2 小时前
Ubuntu单卡5090部署VeRL:从安装到运行
linux·运维·ubuntu
火柴棍mcu2 小时前
Ubuntu设备屏幕旋转、竖屏改横屏
linux·ubuntu·旋转·屏幕
amao99882 小时前
MITos2022--Lab2: system calls
linux
小码吃趴菜2 小时前
地址空间详解-fork复制进程
linux
Xの哲學2 小时前
Linux IPsec 深度解析: 架构, 原理与实战指南
linux·服务器·网络·算法·边缘计算