ffmpeg组件化再封装(一)

博客介绍了作者在学习FFmpeg时,为解决示例代码长且复杂以及重复代码多的问题,采用C++对FFmpeg进行组件化的封装过程。通过FFmpegs.h、ScaleResampleHelpFunc.h和CodecHelpFunc.h等文件,实现了视频帧格式转换、音频帧重采样及编解码器操作的简化。提供了相应的创建、转换和释放函数,以提高代码的可读性和复用性。
摘要由CSDN通过智能技术生成

        一开始学习ffmpeg的时候,看着示例代码中长长的c函数,心里总是莫名地升起几分烦躁,觉得代码梳理起来实在有点费劲。等到对ffmpeg的API有了一定的了解后,再看一些示例,又觉得其中重复地代码非常的多,于是有了用C++对ffmpeg进行组件化的想法,后来慢慢动手,一点点添加代码,修改代码,测试,终于磨出来了一个基本的实现。

        首先,说明一下封装的目的:1、代码复用;2、组件化后,可以简化代码结构。

        全部代码已上传CSDN,链接如下:

                FFmpegTools.rar

        简单说明一下自己的实现,随后会有利用这些组件来处理媒体的例子。

        首先说明几个准备文件:

        第一个是FFmpegs.h文件,它用于引入要使用的ffmpeg头文件,然后其他文件引用它来间接引入ffmpeg。

#ifndef FFMPEGS_H
#define FFMPEGS_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "libavutil/audio_fifo.h"
#include "libavutil/avstring.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/dict.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/avassert.h"
#include "libavutil/time.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavcodec/avfft.h"
#include "libswresample/swresample.h"
#include <libavutil/channel_layout.h>
#include <libavutil/timestamp.h>
#include <libavutil/avutil.h>
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>

typedef uint64_t u_int64_t;

#ifdef __cplusplus
}
#endif

#endif // FFMPEGS_H

         第二个是ScaleResampleHelpFunc.h,它对视频帧的格式转化和音频帧的重采样进行了封装,非常简单,代码中有相关注释。

#ifndef AVSWSSWR_H
#define AVSWSSWR_H

#include "FFmpegs.h"

#ifdef __cplusplus
extern "C"
{
#endif

/*
 * c接口,对音频帧和视频帧以及其转化和重采样提供了方便函数。
*/

/*
 * 这里将视频帧和音频帧所需的基本参数进行抽象,定义了VideoFrameBaseParam和AudioFrameBaseParam。
 * 接着进一步对视频帧转化和音频帧重采样进行了抽象。
*/

typedef struct VideoFrameBaseParam
{
    uint32_t                nWidth;
    uint32_t                nHeight;
    enum AVPixelFormat      sPixFmt;
}VideoFrameBaseParam;

typedef struct VideoFrameScaler
{
    VideoFrameBaseParam     sSrcParam;
    VideoFrameBaseParam     sDstParam;
    struct SwsContext       *pSwsContext;
}VideoFrameScaler;

typedef struct AudioFrameBaseParam
{
    enum AVSampleFormat     sSampleFmt;
    uint64_t                sChannelLayout;
    uint32_t                nSampleRate;
    uint32_t                nSampleNum;
}AudioFrameBaseParam;

typedef struct AudioFrameResampler
{
    AudioFrameBaseParam     sSrcParam;
    AudioFrameBaseParam     sDstParam;
    struct SwrContext       *pSwrContext;
}AudioFrameResampler;

//提供了一组返回BaseParam的方便函数
VideoFrameBaseParam CreateVideoFrameBaseParam(uint32_t nWidth,uint32_t nHeight,enum AVPixelFormat sPixFmt);

AudioFrameBaseParam CreateAudioFrameBaseParam(enum AVSampleFormat sSampleFmt,uint64_t sChannelLayout,
                                                     uint32_t nSampleRate,uint32_t nSampleNum);

VideoFrameBaseParam CreateVideoFrameBaseParamByAVFrame(AVFrame *piFrame);

AudioFrameBaseParam CreateAudioFrameBaseParamByAVFrame(AVFrame *piFrame);

VideoFrameBaseParam CreateVideoFrameBaseParamByCoderCxt(AVCodecContext *piCodecCxt);

AudioFrameBaseParam CreateAudioFrameBaseParamByCoderCxt(AVCodecContext *piCodecCxt);

/*
 * 在有些时候,有这样的需要:我们要将一个视频帧的像素格式转化为YUV420P格式,其他的参数则不变,
 * 这个时候,我们不需要知道源视频帧的详细参数,仅需指定想要修改的部分参数即可:
 *
 *      即,如果sDst中的字段未指定,那么使用sSrc中对应字段的值
 *
 * sSrc:源参数,这个参数里必须指定全部字段
 * dDst:目标参数,这个参数里仅需指定部分字段,其他的设置为默认值,表示它使用sSrc对应的值
 * 返回值:对dDst参数进行填充后的结果值
 *
 * VideoFrameBaseParam中,按照字段顺序,默认值为 0,0,AV_PIX_FMT_NONE
 * AudioFrameBaseParam中,按照字段顺序,默认值为AV_SAMPLE_FMT_NONE,0,0,0
 *
*/
VideoFrameBaseParam GetRealVideoParamByFirst(VideoFrameBaseParam sSrc,VideoFrameBaseParam sDst);

AudioFrameBaseParam GetRealAudioParamByFirst(AudioFrameBaseParam sSrc,AudioFrameBaseParam sDst);


/*
 * 按照指定参数,分配AVFrame并为其开辟相关的内存
*/
AVFrame *CreateAudioFrameAndBuffered(AudioFrameBaseParam sParam);

AVFrame *CreateVideoFrameAndBuffered(VideoFrameBaseParam sParam);

//scaler和resampler的接口,非常简单
VideoFrameScaler *CreateVideoFrameScaler(VideoFrameBaseParam sSrcParam,VideoFrameBaseParam sDstParam);

AudioFrameResampler *CreateAudioFrameResampler(AudioFrameBaseParam sSrcParam,AudioFrameBaseParam sDstParam);

void FreeVideoFrameScaler(VideoFrameScaler **piScaler);

void FreeAudioFrameResampler(AudioFrameResampler **piResampler);

int ScaleVideo(VideoFrameScaler *piScaler,AVFrame *pSrc,AVFrame *pDst);

int ResampleAudio(AudioFrameResampler *piResampler,AVFrame *pSrc,AVFrame *pDst);

#ifdef __cplusplus
}
#endif

#endif // AVSWSSWR_H

        第三个文件是CodecHelpFunc.h,它针对编解码器封装了一些函数,代码中有解释。

#ifndef AVCODECSS_H
#define AVCODECSS_H

#include "FFmpegs.h"

#ifdef __cplusplus
extern "C"
{
#endif

/*
 *  c函数,为codec封装了一些操作。
*/

/*
 * 以下五个函数是codec相关的参数查询函数:
 *
 * SampleFormatIsSupportedByCodec:codec是否支持某一个采样格式
 * SampleRateIsSupportedByCodec:codec是否支持某一个采样频率
 * SelectSampleFormat:从codec支持的采样格式中选择一个最合适的
 * SelectSampleRate:从codec支持的采样频率中选择一个最合适的
 * SelectChannelLayout:从codec支持的channelLayout中选择一个最合适的
*/

int SampleFormatIsSupportedByCodec(const AVCodec *codec, enum AVSampleFormat sample_fmt);

int SampleRateIsSupportedByCodec(const AVCodec *codec, const int sample_rate);

enum AVSampleFormat SelectSampleFormat(const AVCodec *codec);

int SelectSampleRate(const AVCodec *codec);

u_int64_t SelectChannelLayout(const AVCodec *codec);

//从一个AVStream中打开一个Decoder
AVCodecContext *CreateAndOpenDecoderByAVStream(AVStream *piStream,AVDictionary *piOpenCodecCtxDict);

/*
 * 当从一个AVStream打开一个Decoder时,所需的信息大多数情况下都由AVStream提供,一般不需要我们指定额外参数
 *
 * 而当打开一个Encoder时,就需要我们手动指定很多的参数,因此这里将其整个过程拆分为了三个函数,按照以下顺序使用:
 *
 *  1. NewEncoderByID:分配一个指定类型的Encoder
 *  2. SetEncoderParamByDefault:为新分配的Encoder设置所需的默认的参数
 *  3. 如果有额外需要,可以修改第二步设置的默认参数
 *  4. OpenEncoder:经过上述步骤配置好参数后,打开Encoder
 *
 * EncoderHandler类中使用了这些函数
*/
AVCodecContext *NewEncoderByID(enum AVCodecID sEncodeID);

void SetEncoderParamByDefault(AVCodecContext *piCodecCxt,AVFormatContext *piFmtCxt);

int OpenEncoder(AVCodecContext *piCodecCxt,AVDictionary *piOpenCodecCtxDict);


#ifdef __cplusplus
}
#endif

#endif // AVCODEC_H

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值