FFmpeg流媒体基础知识:深入解析AVFormatContext、AVIOContext和AVStream
2022-12-18 08:10:20
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。