ffmpeg 视频解码流程及主要API

视频解码流程主要分为**解封装(Demuxing)解码(Decode)**两个阶段。


一、视频解码流程

1. 初始化 FFmpeg 库
  • 注册组件
    调用 av_register_all() 注册所有编解码器和封装格式(FFmpeg 4.0+ 已弃用,但仍需初始化网络等模块)。
  • 网络初始化(可选):
    若处理网络流,需调用 avformat_network_init()
2. 打开输入文件
  • 创建格式上下文
    使用 avformat_alloc_context() 分配 AVFormatContext,存储文件格式信息。
  • 打开文件
    avformat_open_input(&fmt_ctx, filename, NULL, NULL) 打开文件并填充格式上下文。
3. 获取流信息
  • 解析流信息
    avformat_find_stream_info(fmt_ctx, NULL) 获取视频流的编码参数、时长等元数据。
4. 查找视频流
  • 遍历流索引
    通过 fmt_ctx->nb_streams 遍历,检查 stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO 确定视频流索引。
5. 初始化解码器
  • 查找解码器
    avcodec_find_decoder(stream->codecpar->codec_id) 根据编码格式(如 H.264)查找解码器。
  • 创建解码上下文
    avcodec_alloc_context3(codec) 分配 AVCodecContext,并通过 avcodec_parameters_to_context() 填充参数。
  • 打开解码器
    avcodec_open2(codec_ctx, codec, NULL) 初始化解码器。
6. 解码循环
  • 读取压缩数据包
    av_read_frame(fmt_ctx, &packet) 循环读取 AVPacket(压缩数据)。
  • 发送数据包
    avcodec_send_packet(codec_ctx, &packet) 将数据包送入解码器。
  • 接收解码帧
    avcodec_receive_frame(codec_ctx, frame) 获取解码后的 AVFrame(YUV/RGB 数据)。
  • 释放数据包
    每次循环后调用 av_packet_unref(&packet) 释放资源。
7. 释放资源
  • 关闭解码器:avcodec_close(codec_ctx)
  • 关闭输入文件:avformat_close_input(&fmt_ctx)
  • 释放帧和上下文:av_frame_free(&frame), avcodec_free_context(&codec_ctx)

二、核心 API 及数据结构

API/结构体作用
AVFormatContext存储封装格式的全局信息(如流数量、时长)。
AVCodecContext编解码器上下文,包含宽高、像素格式等参数。
AVPacket存储压缩编码数据(如 H.264 码流)。
AVFrame存储解码后的原始数据(YUV/RGB)。
avcodec_send_packet()将压缩数据发送给解码器。
avcodec_receive_frame()从解码器获取解码后的帧。
sws_scale()转换像素格式(如 YUV 转 RGB)。

三、完整流程示例

// 初始化
avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL);
avformat_find_stream_info(fmt_ctx, NULL);

// 查找视频流
int video_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);

// 初始化解码器
AVCodec *codec = avcodec_find_decoder(fmt_ctx->streams[video_idx]->codecpar->codec_id);
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_idx]->codecpar);
avcodec_open2(codec_ctx, codec, NULL);

// 解码循环
AVFrame *frame = av_frame_alloc();
AVPacket packet;
while (av_read_frame(fmt_ctx, &packet) >= 0) {
    if (packet.stream_index == video_idx) {
        avcodec_send_packet(codec_ctx, &packet);
        while (avcodec_receive_frame(codec_ctx, frame) == 0) {
            // 处理帧数据(如渲染或保存)
        }
    }
    av_packet_unref(&packet);
}
FFmpeg是一个强大的跨平台多媒体框架,它支持广泛的音频和视频文件处理,包括编码、解码、流媒体转换等。对于解码视频API的调用流程,通常分为以下几个步骤: 1. **初始化 FFmpeg**:首先需要包含FFmpeg库,并创建一个`avformat_context`结构体实例,这是FFmpeg的核心结构,用于存储解码器上下文信息。 ```c av_register_all(); avformat_network_init(); // 初始化网络模块 avformat_instance = avformat_alloc_context(); ``` 2. **打开输入文件**:通过`avformat_open_input`函数指定要解码的文件路径,并设置`avformat_instance`。 ```c if (avformat_open_input(&avformat_instance, input_filename, NULL, NULL) < 0) { // 处理错误 } ``` 3. **查找并注册解析器**:调用`avformat_find_stream_info`来获取文件的元数据,并自动注册相关的解析器。 ```c if (avformat_find_stream_info(avformat_instance, NULL) < 0) { // 处理错误 } ``` 4. **选择视频流**:遍历`avformat_instance->streams`,找到视频流并获取解码器上下文`avcodec_context`。 ```c for (int i = 0; i < avformat_instance->nb_streams; ++i) { if (avstream_is_video(avformat_instance->streams[i])) { video_codec_ctx = avformat_get.stream(i)->codec; break; } } ``` 5. **分配解码器和帧缓冲区**:初始化解码器并分配内存缓冲区用于存放解码后的像素数据。 ```c if (avcodec_open2(video_codec_ctx, avcodec_find_decoder(video_codec_ctx->codec_id), NULL) < 0) { // 处理错误 } frame = av_frame_alloc(); ``` 6. **解码视频帧**:调用`avcodec_decode_video2`函数,提供输入缓冲区和输出缓冲区,直到返回错误或者达到文件结束。 7. **播放/处理解码后的帧**:循环解码,可以对解码后的帧进行显示、分析或者其他操作。 8. **释放资源**:解码完成后,记得关闭解码器、释放帧,以及清理FFmpeg的其他资源。 ```c avcodec_close(video_codec_ctx); av_frame_free(&frame); avformat_close_input(&avformat_instance); ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值