乐闻世界logo
搜索文章和话题

如何在应用程序中集成 FFmpeg?常用的 API 函数有哪些?

2月18日 11:11

FFmpeg 不仅提供命令行工具,还提供了丰富的 C/C++ API,允许开发者将音视频处理功能集成到自己的应用程序中。

核心库介绍

FFmpeg 主要包含以下核心库:

库名功能用途
libavformat封装格式处理读写各种音视频容器格式
libavcodec编解码器音视频编解码
libavutil工具函数通用工具和辅助函数
libswscale图像缩放图像缩放和色彩空间转换
libswresample音频重采样音频采样率转换和格式转换
libavfilter滤镜处理音视频滤镜效果
libavdevice设备支持摄像头、麦克风等设备访问

基本开发流程

初始化 FFmpeg

c
#include <libavformat/avformat.h> #include <libavcodec/avcodec.h> // 注册所有编解码器和封装格式 av_register_all(); avformat_network_init(); // FFmpeg 4.0+ 不需要显式注册

打开输入文件

c
AVFormatContext *fmt_ctx = NULL; int ret = avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL); if (ret < 0) { // 处理错误 } // 获取流信息 ret = avformat_find_stream_info(fmt_ctx, NULL); if (ret < 0) { // 处理错误 }

查找视频流

c
int video_stream_index = -1; for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) { if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; break; } }

初始化解码器

c
AVCodecParameters *codec_par = fmt_ctx->streams[video_stream_index]->codecpar; const AVCodec *codec = avcodec_find_decoder(codec_par->codec_id); AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codec_ctx, codec_par); ret = avcodec_open2(codec_ctx, codec, NULL); if (ret < 0) { // 处理错误 }

读取和解码帧

c
AVPacket *packet = av_packet_alloc(); AVFrame *frame = av_frame_alloc(); while (av_read_frame(fmt_ctx, packet) >= 0) { if (packet->stream_index == video_stream_index) { ret = avcodec_send_packet(codec_ctx, packet); if (ret < 0) { // 处理错误 } while (ret >= 0) { ret = avcodec_receive_frame(codec_ctx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { // 处理错误 } // 处理解码后的帧 process_frame(frame); } } av_packet_unref(packet); }

编码输出

c
// 初始化编码器 const AVCodec *encoder = avcodec_find_encoder(AV_CODEC_ID_H264); AVCodecContext *enc_ctx = avcodec_alloc_context3(encoder); enc_ctx->width = 1280; enc_ctx->height = 720; enc_ctx->time_base = (AVRational){1, 25}; enc_ctx->framerate = (AVRational){25, 1}; enc_ctx->gop_size = 10; enc_ctx->max_b_frames = 1; enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P; ret = avcodec_open2(enc_ctx, encoder, NULL); if (ret < 0) { // 处理错误 } // 编码帧 AVPacket *enc_packet = av_packet_alloc(); ret = avcodec_send_frame(enc_ctx, frame); if (ret < 0) { // 处理错误 } while (ret >= 0) { ret = avcodec_receive_packet(enc_ctx, enc_packet); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { // 处理错误 } // 写入输出文件 av_interleaved_write_frame(out_fmt_ctx, enc_packet); av_packet_unref(enc_packet); }

资源清理

c
av_frame_free(&frame); av_packet_free(&packet); avcodec_free_context(&codec_ctx); avformat_close_input(&fmt_ctx);

常用 API 函数

格式处理

c
// 打开输入 int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options); // 查找流信息 int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); // 读取帧 int av_read_frame(AVFormatContext *s, AVPacket *pkt); // 写入帧 int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);

编解码

c
// 查找解码器 const AVCodec *avcodec_find_decoder(enum AVCodecID id); // 查找编码器 const AVCodec *avcodec_find_encoder(enum AVCodecID id); // 打开编解码器 int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); // 发送包到解码器 int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt); // 从解码器接收帧 int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame); // 发送帧到编码器 int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame); // 从编码器接收包 int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);

图像处理

c
// 分配图像 AVFrame *av_frame_alloc(void); // 分配图像数据 int av_frame_get_buffer(AVFrame *frame, int align); // 图像缩放 struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param); int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[]);

错误处理

c
// 获取错误描述 char errbuf[AV_ERROR_MAX_STRING_SIZE]; av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE); fprintf(stderr, "Error: %s\n", errbuf); // 常见错误码 AVERROR(EAGAIN) // 需要更多输入/输出 AVERROR_EOF // 文件结束 AVERROR(EINVAL) // 无效参数 AVERROR(ENOMEM) // 内存不足

最佳实践

  1. 资源管理:使用 RAII 模式管理资源,确保正确释放
  2. 错误处理:检查所有 API 调用的返回值
  3. 线程安全:FFmpeg API 大部分不是线程安全的,需要适当的同步
  4. 性能优化:使用硬件加速、多线程处理
  5. 内存管理:及时释放不再使用的资源

FFmpeg API 功能强大但复杂,建议从简单的示例开始,逐步掌握各个模块的使用方法。

标签:FFmpeg