FFMPEG api使用

发布于:2025-08-31 ⋅ 阅读:(29) ⋅ 点赞:(0)

一、播放音视频

1.1 整体架构

1.2 具体代码

1. 创建一个媒体句柄AVFormatContext,这个句柄里面存储了 流信息、视频信息 或 音频信息

AVFormatContext *fmt_ctx = NULL;

// 1. 分配上下文
fmt_ctx = avformat_alloc_context();
if (!fmt_ctx) {
    // 处理内存分配失败
}

// 2. 打开文件并填充上下文
if (avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL) != 0) {
    // 处理打开失败
}

// 3. 使用上下文进行操作(如查找流信息等)

// 4. 关闭文件并释放资源
avformat_close_input(&fmt_ctx);

avformat_alloc_context 和 avformat_free_context 配对使用

avformat_open_input 和 avformat_close_input 配对使用

注意可以不使用avformat_alloc_context()分配内存后再使用avformat_open_input()打开文件。只要传入的fmt_ctx==NULL,就会自动创建

使用avformat_close_input关闭解复用器器后,就不用使用avformat_free_context释放AVFormatContext

2. 查看AVFormatContext里面有哪些媒体流

// 获取流的信息
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
    fprintf(stderr, "无法获取流信息\n");
    avformat_close_input(&fmt_ctx);
    return -1;
}

// 获取了信息才能使用下面方法找流
for (int i = 0; i < fmt_ctx->nb_streams; i++) {
    if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        target_stream_index = i;
        printf("找到视频流,索引:%d\n", target_stream_index);
        break;
    }
}

使用avformat_find_stream_info()可以获取视频文件信息

3. 从AVFormatContext里面获取一个包AVPacket

AVPacket * packet = av_packet_alloc();

while ((ret = av_read_frame(fmt_ctx, packet)) == 0) {
    // 判断当前包是否属于目标流
    if (packet->stream_index == target_stream_index) {
        // 处理目标流的数据包(例如解码、打印信息等)
        printf("处理视频流数据,PTS: %lld\n", packet->pts);
    }
    // 无论是否处理,都需要释放数据包的引用
    av_packet_unref(packet);
}

avformat_seek_file()定位到音视频文件的位置

4. 常见解码

视频:H.264 -> YUV

音频:AAC -> PCM

通过下面的函数将AVPacket转成AVFrame

// 获取解码参数
AVCodecParameters * codec_par = fmt_ctx->streams[video_stream_idx]->codecpar;
// 根据解码器ID获取解码器
AVCodec * dec = avcodec_find_decoder(codec_par->codec_id);
// 根据解码器创建上下文结构体
AVCodecContext * dec_ctx = avcodec_alloc_context3(dec);

int decode_video_packet(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt) {
    int ret;

    // 发送数据包到解码器
    if (avcodec_send_packet(dec_ctx, pkt) < 0) {
        fprintf(stderr, "发送视频数据包失败\n");
        return -1;
    }

    // 接收解码后的帧
    ret = avcodec_receive_frame(dec_ctx, frame);
    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
        return 0;
    if (ret < 0) {
        fprintf(stderr, "视频解码失败\n");
        return -1;
    }

    // 简单处理:打印视频帧信息
    printf("视频帧 - 宽: %d, 高: %d, PTS: %lld\n", 
           frame->width, frame->height, frame->pts);

    av_frame_unref(frame);
    return 0;
}
AVCodecParameters *codec_par = fmt_ctx->streams[audio_stream_idx]->codecpar;
AVCodec * dec = avcodec_find_decoder(codec_par->codec_id);
AVCodecContext * dec_ctx = avcodec_alloc_context3(dec);

int decode_audio_packet(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt) {
    int ret;

    // 发送数据包到解码器
    if (avcodec_send_packet(dec_ctx, pkt) < 0) {
        fprintf(stderr, "发送音频数据包失败\n");
        return -1;
    }

    // 接收解码后的帧
    ret = avcodec_receive_frame(dec_ctx, frame);
    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
        return 0;
    if (ret < 0) {
        fprintf(stderr, "音频解码失败\n");
        return -1;
    }

    // 简单处理:打印音频帧信息
    printf("音频帧 - 采样率: %d, 声道数: %d, 样本数: %d\n",
           dec_ctx->sample_rate, dec_ctx->channels, frame->nb_samples);

    av_frame_unref(frame);
    return 0;
}

二、FFMPEG整体架构

上层应用(最顶部)

ffplay:一个简单的媒体播放器,基于 FFmpeg 库实现音视频的播放功能,可用于测试和简单的播放场景。

ffprobe:用于查看媒体文件的信息,比如流的类型、编码格式、时长、比特率等元数据,帮助开发者或用户了解媒体文件的详细结构。

ffmpeg:FFmpeg 最核心的命令行工具,集音视频的录制、转换、编码、解码等多种功能于一体,可对媒体文件进行各种复杂的处理操作。

核心库(中间层)

libavutil:提供了一些通用的工具函数,如内存管理、数学运算、数据结构等,是其他 FFmpeg 库的基础支撑库。

libavformat:负责媒体文件的格式处理,包括封装和解封装操作。比如读取 MP4、MKV 等格式的文件,解析出其中的音视频流;或者将编码后的音视频流封装成特定格式的文件。

libavcodec:音视频编解码的核心库,包含了各种音视频编解码器的实现(如 H.264、AAC 等编解码器),用于将压缩的音视频数据解码为原始数据,或者将原始数据编码为压缩格式。

libswscale:主要用于视频像素格式的转换和图像缩放。例如将 YUV 格式的视频帧转换为 RGB 格式,或者对视频图像进行缩放操作,以适配不同的显示需求。

libswresample:专注于音频重采样和格式转换。可以调整音频的采样率、声道数、采样格式等,使音频在不同的设备或场景下能够正常播放。

libavfilter:提供了各种音视频滤镜功能,用于对音视频进行特效处理。比如给视频添加模糊、锐化效果,对音频进行降噪、均衡等处理。

libpostproc:用于对视频进行后期处理,比如去块效应等,提升视频的视觉质量。

编解码器(底层)

fdk - aac:是一种 AAC 音频编解码器,用于 AAC 格式音频的编码和解码,能提供高质量的 AAC 音频编码。

voaac_enc:也是 AAC 音频编码器,用于将原始音频数据编码为 AAC 格式。

x264:非常知名的 H.264 视频编码器,可将原始视频数据高效地编码为 H.264 格式的视频流,在视频压缩领域应用广泛。

三、AVPacket

1.1 AVPacket引用计数

AVPacket *pkt1 = av_packet_alloc();
AVPacket *pkt2 = av_packet_alloc();
// 假设pkt1已经填充好数据
av_packet_ref(pkt2, pkt1);

av_packet_ref(pkt2, pkt1) 后,pkt1 和 pkt2 共享 pkt1 原来指向的数据内存。引用计数+1,当引用技术减少为0的时候就释放内存

有下面的一些函数:

av_init_packet(AVPacket *pkt) 初始化一个已经分配好内存的 AVPacket 结构体。它主要是将 AVPacket 结构体中的成员变量设置为默认的初始状态,如将 pts、dts 设为 AV_NOPTS_VALUE ,将 data 设为 NULL,将数据大小 size 设为 0 等。但它不会为 AVPacket 结构体分配内存,只是对传入的 AVPacket 结构体进行状态初始化。


网站公告

今日签到

点亮在社区的每一天
去签到