如何在应用程序中集成 FFmpeg?常用的 API 函数有哪些?
FFmpeg 不仅提供命令行工具,还提供了丰富的 C/C++ API,允许开发者将音视频处理功能集成到自己的应用程序中。核心库介绍FFmpeg 主要包含以下核心库:| 库名 | 功能 | 用途 || ------------- | ------ | ------------ || libavformat | 封装格式处理 | 读写各种音视频容器格式 || libavcodec | 编解码器 | 音视频编解码 || libavutil | 工具函数 | 通用工具和辅助函数 || libswscale | 图像缩放 | 图像缩放和色彩空间转换 || libswresample | 音频重采样 | 音频采样率转换和格式转换 || libavfilter | 滤镜处理 | 音视频滤镜效果 || libavdevice | 设备支持 | 摄像头、麦克风等设备访问 |基本开发流程初始化 FFmpeg#include <libavformat/avformat.h>#include <libavcodec/avcodec.h>// 注册所有编解码器和封装格式av_register_all();avformat_network_init();// FFmpeg 4.0+ 不需要显式注册打开输入文件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) { // 处理错误}查找视频流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; }}初始化解码器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) { // 处理错误}读取和解码帧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);}编码输出// 初始化编码器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);}资源清理av_frame_free(&frame);av_packet_free(&packet);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);常用 API 函数格式处理// 打开输入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);编解码// 查找解码器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);图像处理// 分配图像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[]);错误处理// 获取错误描述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) // 内存不足最佳实践资源管理:使用 RAII 模式管理资源,确保正确释放错误处理:检查所有 API 调用的返回值线程安全:FFmpeg API 大部分不是线程安全的,需要适当的同步性能优化:使用硬件加速、多线程处理内存管理:及时释放不再使用的资源FFmpeg API 功能强大但复杂,建议从简单的示例开始,逐步掌握各个模块的使用方法。