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 硬件编码推流场景。
相关推荐
A小辣椒2 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao3 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334663 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5203 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩4 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言