返回

FFmpeg流媒体基础知识:深入解析AVFormatContext、AVIOContext和AVStream

Android

FFmpeg流媒体入门:三大核心结构体

在音视频编解码领域,FFmpeg库是一个强大的工具,深受业界欢迎。在音视频处理过程中,涉及到三个至关重要的结构体:AVFormatContext、AVIOContext和AVStream。

AVFormatContext:总揽全局的格式上下文

AVFormatContext是FFmpeg编解码的基础结构体。它保存了音视频文件的基本信息,例如文件格式、持续时间、比特率等,就像一张文件的身份信息卡。它充当桥梁,连接音视频文件和解码器或编码器,为音视频处理提供必要的基础。

AVIOContext:灵活多样的输入输出上下文

AVIOContext结构体主要负责文件的输入和输出,扮演着传输员的角色。它提供了一个抽象层,让FFmpeg库能够以统一的方式处理不同类型的文件,如本地文件、网络流媒体和内存缓冲区。无论文件存储在哪种介质中,AVIOContext都能从中读取或写入数据,让音视频处理变得更加灵活高效。

AVStream:多路复用与解复用的基石

AVStream结构体是音视频文件中的媒体流,是音视频处理中的最小单元。它包含了媒体流的编解码器信息、分辨率、采样率等属性,就像每条流的专属标签。每个AVStream代表一个媒体流,例如视频流、音频流或字幕流,为多路复用和解复用奠定基础。

深入理解三大结构体

1. AVFormatContext:解析文件格式,获取全局信息

AVFormatContext是解析音视频文件格式的舵手。它能够读取文件头信息,获取文件的基本信息,例如文件格式、持续时间和比特率,就像一本文件的护照。

2. AVIOContext:灵活处理输入输出,实现跨平台兼容

AVIOContext是音视频处理过程中的传输员。它负责文件的输入和输出,提供了一个抽象层,让FFmpeg库能够以统一的方式处理不同类型的文件,例如本地文件、网络流媒体和内存缓冲区,就像一个兼容多平台的文件管家。

3. AVStream:管理媒体流,分离音视频数据

AVStream是音视频文件中的媒体流管理者。它包含了媒体流的编解码器信息、分辨率和采样率等属性,就像每条流的专属标签。有了AVStream,音视频处理可以针对不同的媒体流进行操作,例如解码视频流或编码音频流。

实例解析:三大结构体在音视频编解码中的应用

以下代码示例演示了如何使用三大结构体进行音视频解码:

#include <stdio.h>
#include <libavformat/avformat.h>

int main() {
    // 打开音视频文件
    AVFormatContext *fmt_ctx = NULL;
    avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL);

    // 读取文件头信息
    avformat_find_stream_info(fmt_ctx, NULL);

    // 查找视频流和音频流
    int video_stream_index = -1;
    int audio_stream_index = -1;
    for (int i = 0; i < fmt_ctx->nb_streams; i++) {
        if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_index = i;
        } else if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            audio_stream_index = i;
        }
    }

    // 打开视频解码器和音频解码器
    AVCodecContext *video_dec_ctx = avcodec_alloc_context3(NULL);
    AVCodecContext *audio_dec_ctx = avcodec_alloc_context3(NULL);
    avcodec_parameters_to_context(video_dec_ctx, fmt_ctx->streams[video_stream_index]->codecpar);
    avcodec_parameters_to_context(audio_dec_ctx, fmt_ctx->streams[audio_stream_index]->codecpar);
    avcodec_open2(video_dec_ctx, NULL, NULL);
    avcodec_open2(audio_dec_ctx, NULL, NULL);

    // 准备AVPacket和AVFrame
    AVPacket pkt;
    av_init_packet(&pkt);

    AVFrame *video_frame = av_frame_alloc();
    AVFrame *audio_frame = av_frame_alloc();

    // 开始解码
    while (av_read_frame(fmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == video_stream_index) {
            // 解码视频帧
            int got_frame = 0;
            avcodec_decode_video2(video_dec_ctx, video_frame, &got_frame, &pkt);
            if (got_frame) {
                // 处理视频帧
            }
        } else if (pkt.stream_index == audio_stream_index) {
            // 解码音频帧
            int got_frame = 0;
            avcodec_decode_audio4(audio_dec_ctx, audio_frame, &got_frame, &pkt);
            if (got_frame) {
                // 处理音频帧
            }
        }
        av_packet_unref(&pkt);
    }

    // 释放资源
    av_frame_free(&video_frame);
    av_frame_free(&audio_frame);
    avcodec_close(video_dec_ctx);
    avcodec_close(audio_dec_ctx);
    avformat_close_input(&fmt_ctx);

    return 0;
}

常见问题解答

1. AVFormatContext、AVIOContext和AVStream之间的关系是什么?

AVFormatContext是总控,管理整个音视频文件,AVIOContext负责文件的输入输出,AVStream则是媒体流的管理者。

2. 如何使用AVFormatContext获取文件基本信息?

通过调用avformat_find_stream_info()函数,可以获取文件头信息,包括文件格式、持续时间和比特率等。

3. 如何使用AVIOContext读取文件数据?

通过调用avio_read()函数,可以从文件中读取数据。

4. 如何使用AVStream解码媒体流?

通过调用avcodec_decode_video2()或avcodec_decode_audio4()函数,可以解码视频流或音频流。

5. 如何释放FFmpeg分配的资源?

使用av_frame_free()函数释放AVFrame,使用avcodec_close()函数释放AVCodecContext,使用avformat_close_input()函数释放AVFormatContext。