对ffmpeg中的sws_scale的封装类

本文提供了一个封装类,简化了使用ffmpeg中的sws_scale进行常见图像格式转换和缩放的操作。封装了设置输入输出图像格式及尺度算法的步骤,并实现了图像缩放功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文转载至: http://www.cnblogs.com/acloud/archive/2011/10/29/2228626.html


直接使用ffmpeg中的sws_scale虽然已经不太复杂,但每次的手动初始化等操作,毕竟不够方便。我对这部分代码进行了封装。平时常见的需要处理的图像格式无非就是YUV420和RGB24、RGB32等格式,我的封装仅仅对它们进行。blog好像不能上传附件,因此我没法把ffmpeg的scale相关的静态库lib(静态库携带比动态库方便^_^)等上传了(发了一份给自己的qq邮箱留作备份了,发现这儿可以上传附件,全部源码也上传一份好了)。

下面的代码,可能需要ffmpeg的相关头文件支持,我对它们进行了一些精简,只需要一个头文件"swscale.h"即可。

  

FFScale.h源码如下:

 

/***************************************************************************//**
* 版权所有 (C)
*
* 文件名称: FFScale.h
* 文件标识:
* 内容摘要: 使用ffmpeg中的sws_scale进行图片格式转换和resize的封装类。
* 其它说明: 本模块仅仅对常见的图像格式进行了转换,更多的图像格式,请直接使用
* ffmepg中的sws_scale。
*
* 本封装类使用方法如下:
* 1、定义一个CFFScale对象;
* 2、调用该对象的SetAttribut函数,设置输入输出图像的格式和Scale算法;
* 3、调用该对象的Scale函数,进行Scale操作。
*
* 注意:本模块假定YUV图像格式采用的连续的内存空间进行的图像存储,如
* 实际情况并非如此,则本模块不适应这种场合。
* 当前版本: V1.0
* 作 者: Cloud
* 完成日期: 2011-10-28
*******************************************************************************/

#pragmaonce


//Scale算法
enumSwsAlogrithm
{
    SWS_SA_FAST_BILINEAR    = 0
x1,

    SWS_SA_BILINEAR            = 0x2,

    SWS_SA_BICUBIC            = 0x4,

    SWS_SA_X                = 0x8,
    SWS_SA_POINT            = 0x10,
    SWS_SA_AREA                = 0x20,
    SWS_SA_BICUBLIN            = 0x40,
    SWS_SA_GAUSS            = 0x80,
    SWS_SA_SINC                = 0x100,
    SWS_SA_LANCZOS            = 0x200,
    SWS_SA_SPLINE            = 0x400,
};

//视频图像格式
enumPicFormat
{
    SWS_PF_NONE            = PIX_FMT_NONE,

    SWS_PF_YUV420P        = PIX_FMT_YUV420P,

    SWS_PF_RGB24        = PIX_FMT_RGB24,
    SWS_PF_BGR24        = PIX_FMT_BGR24,
    SWS_PF_ARGB            = PIX_FMT_ARGB,
    SWS_PF_RGBA            = PIX_FMT_RGBA,
    SWS_PF_ABGR            = PIX_FMT_ABGR,
    SWS_PF_BGRA            = PIX_FMT_BGRA,
};


classCFFScale
{
public:
    CFFScale(void);
    ~CFFScale(void);

    //设置输入输出图片属性以及Scale算法
    voidSetAttribute(PicFormatsrcFormat, PicFormatdstFormat, SwsAlogrithmenAlogrithm = SWS_SA_FAST_BILINEAR);

    //Scale
    BOOLScale(
        byte *pSrc, intnSrcW, intnSrcH, intnSrcPicth,
        byte *pDst, intnDstW, intnDstH, intnDstPicth
        );

private:

    //初始化
    BOOLInit();

    //反初始化
    voidDeInit();

    SwsContext*    m_pSwsContext;        //SWS对象
    PicFormatm_srcFormat;            //源像素格式
    PicFormatm_dstFormat;            //目标像素格式
    SwsAlogrithmm_enAlogrithm;        //Resize算法

    intm_nSrcW, m_nSrcH;            //源图像宽高
    intm_nSrcPicth;                //源图像第一行数据的长度
    intm_nSrcSlice[4];                //源图像各分量数据起始地址偏移
    intm_nSrcStride[4];            //源图像各分量一行数据的长度

    intm_nDstW, m_nDstH;            //目标图像宽高
    intm_nDstPicth;                //目标图像第一行数据的长度
    intm_nDstSlice[4];                //目标图像各分量数据起始地址偏移
    intm_nDstStride[4];            //目标图像各分量一行数据的长度

};

FFScale.cpp源码如下:

 

#include "StdAfx.h"
#include "FFScale.h"

#pragma comment(lib, "Scale/libavutil.lib")
#pragma comment(lib, "Scale/libswscale.lib")
#pragma comment(lib, "Scale/libgcc.lib")
#pragma comment(lib, "Scale/libmingwex.lib")


//构造
CFFScale::CFFScale(void)
{

    m_pSwsContext = NULL;

    m_srcFormat = SWS_PF_NONE;    

    m_dstFormat = SWS_PF_NONE;    
    m_enAlogrithm = SWS_SA_FAST_BILINEAR;

    m_nSrcW = m_nSrcH = 0;            
    m_nSrcPicth = 0;                
    m_nDstW = m_nDstH = 0;
    m_nDstPicth = 0;
    for (inti=0; i<4; i++)
    {
        m_nSrcSlice[i] = -1;
        m_nSrcStride[i] = 0;
        m_nDstSlice[i] = -1;
        m_nDstStride[i] = 0;
    }
}

//析构
CFFScale::~CFFScale(void)
{

    DeInit();

}


/***************************************************************************//**
* 函数名称:    SetAttribute
* 功能描述:    设置输入输出图片属性以及Scale算法。
* 参 数:    srcFormat    >> 源图像格式;
* 参 数:    dstFormat    >> 目标图像格式;
* 参 数:    enAlogrithm    >> Scale算法;
* 返回值:    
* 其它说明:    
* 修改日期        修改人            修改内容
* ------------------------------------------------------------------------------
* 2011-10-28    Cloud         创建
*******************************************************************************/
voidCFFScale::SetAttribute(PicFormatsrcFormat, PicFormatdstFormat, SwsAlogrithmenAlogrithm)
{

    m_srcFormat = srcFormat;

    m_dstFormat = dstFormat;

    m_enAlogrithm = enAlogrithm;

    DeInit();

}


/***************************************************************************//**
* 函数名称:    Init
* 功能描述:    初始化。
* 返回值:    执行成功返回TRUE,否则返回FALSE。
* 其它说明:    
* 修改日期        修改人            修改内容
* ------------------------------------------------------------------------------
* 2011-10-28    Cloud         创建
*******************************************************************************/
BOOLCFFScale::Init()
{

    //必须预先设置过输入输出格式
    if (SWS_PF_NONE
== m_srcFormat || SWS_PF_NONE == m_dstFormat)

    {

        returnFALSE;

    }

    //反初始化
    DeInit();

    //创建sws对象
    m_pSwsContext = sws_getContext(
        m_nSrcW,
        m_nSrcH,
        (PixelFormat)m_srcFormat,
        m_nDstW,
        m_nDstH,
        (PixelFormat)m_dstFormat,
        (int)m_enAlogrithm,
        NULL,
        NULL,
        NULL);
    if (NULL == m_pSwsContext)
    {
        returnFALSE;
    }

    //初始化源Slice和Stride
    if (m_srcFormat == SWS_PF_YUV420P)
    {
        m_nSrcSlice[0] = 0;
        m_nSrcSlice[1] = m_nSrcW * m_nSrcH;
        m_nSrcSlice[2] = m_nSrcW * m_nSrcH * 5 / 4;
        m_nSrcSlice[3] = -1;

        m_nSrcStride[0] = m_nSrcW;
        m_nSrcStride[1] = m_nSrcW / 2;
        m_nSrcStride[2] = m_nSrcW / 2;
        m_nSrcStride[3] = 0;

    }
    else
    {
        m_nSrcSlice[0] = 0;
        m_nSrcSlice[1] = -1;
        m_nSrcSlice[2] = -1;
        m_nSrcSlice[3] = -1;

        m_nSrcStride[0] = m_nSrcPicth;
        m_nSrcStride[1] = 0;
        m_nSrcStride[2] = 0;
        m_nSrcStride[3] = 0;
    }

    //初始化目标Slice和Stride
    if (m_dstFormat == SWS_PF_YUV420P)
    {
        m_nDstSlice[0] = 0;
        m_nDstSlice[1] = m_nDstW * m_nDstH;
        m_nDstSlice[2] = m_nDstW * m_nDstH * 5 / 4;
        m_nDstSlice[3] = -1;

        m_nDstStride[0] = m_nDstW;
        m_nDstStride[1] = m_nDstW / 2;
        m_nDstStride[2] = m_nDstW / 2;
        m_nDstStride[3] = 0;

    }
    else
    {
        m_nDstSlice[0] = 0;
        m_nDstSlice[1] = -1;
        m_nDstSlice[2] = -1;
        m_nDstSlice[3] = -1;

        m_nDstStride[0] = m_nDstPicth;
        m_nDstStride[1] = 0;
        m_nDstStride[2] = 0;
        m_nDstStride[3] = 0;
    }
    returnTRUE;
}

/***************************************************************************//**
* 函数名称:    DeInit
* 功能描述:    反初始化。
* 返回值:    
* 其它说明:    
* 修改日期        修改人            修改内容
* ------------------------------------------------------------------------------
* 2011-10-28    Cloud         创建
*******************************************************************************/
voidCFFScale::DeInit()
{

    if (NULL != m_pSwsContext)

    {

        sws_freeContext(m_pSwsContext);
    }
    m_pSwsContext = NULL;
}

/***************************************************************************//**
* 函数名称:    Scale
* 功能描述:    Scale
* 参 数:    pSrc            >> 源图像内存起始地址;
* 参 数:    nSrcW            >> 源图像宽度;
* 参 数:    nSrcH            >> 源图像高度;
* 参 数:    nSrcPicth        >> 源图像每行数据的长度(YUV格式的该值不被采纳);
* 参 数:    pDst            << 目标图像内存起始地址;
* 参 数:    nDstW            >> 目标图像宽度;
* 参 数:    nDstH            >> 目标图像高度;
* 参 数:    nDstPicth        >> 目标图像每行数据的长度(YUV格式的该值不被采纳);
* 返回值:    执行成功返回TRUE,否则返回FALSE。
* 其它说明:    
* 修改日期        修改人            修改内容
* ------------------------------------------------------------------------------
* 2011-10-28    Cloud         创建
*******************************************************************************/
BOOLCFFScale::Scale(byte *pSrc, intnSrcW, intnSrcH, intnSrcPicth, byte *pDst, intnDstW, intnDstH, intnDstPicth)
{

    //如果任何参数发生变化,则需要重新初始化
    if (nSrcW
!= m_nSrcW || nSrcH != m_nSrcH || m_nSrcPicth != m_nSrcPicth
        ||
nDstW != m_nDstW || nDstH != m_nDstH || m_nDstPicth != m_nDstPicth)

    {

        m_nSrcW = nSrcW;

        m_nSrcH
= nSrcH;

        m_nSrcPicth = nSrcPicth;

        m_nDstW = nDstW;

        m_nDstH = nDstH;

        m_nDstPicth = nDstPicth;

        DeInit();

    }


    //如果未能成功初始化,返回失败
    if (NULL
== m_pSwsContext && !Init())

    {

        returnFALSE;

    }


    //真正的Scale操作
    byte *srcSlice[4], *dstSlice[4];
    for (inti=0; i<4; i++)
    {
        srcSlice[i] = m_nSrcSlice[i] < 0 ? NULL : (pSrc + m_nSrcSlice[i]);
        dstSlice[i] = m_nDstSlice[i] < 0 ? NULL : (pDst + m_nDstSlice[i]);
    }
    returnsws_scale
        (
        m_pSwsContext,
        srcSlice,
        m_nSrcStride,
        0,
        m_nSrcH,
        dstSlice,
        m_nDstStride
        ) == m_nSrcH;
}



### 如何在QT中集成或使用FFmpeg 要在QT项目中集成或使用FFmpeg,可以采用多种方法实现视频处理功能。以下是几种常见的技术路径: #### 方法一:通过命令行调用FFmpeg 可以直接利用系统的`QProcess`类来执行FFmpeg命令行工具。这种方式简单易用,适合不需要频繁交互的应用场景。 ```cpp #include <QCoreApplication> #include <QProcess> void runFfmpegCommand() { QProcess process; QStringList arguments; arguments << "-i" << "/tmp/test%d.Y" << "/tmp/out.mpg"; // 使用YUV文件作为输入[^2] process.start("ffmpeg", arguments); if (!process.waitForStarted()) { qDebug() << "Failed to start FFmpeg"; return; } if (!process.waitForFinished()) { qDebug() << "FFmpeg execution failed:" << process.errorString(); return; } qDebug() << "FFmpeg output:" << process.readAllStandardOutput(); } ``` 这种方法的优点在于无需编译FFmpeg库到应用程序中,缺点是性能可能不如直接链接动态库的方式高效。 --- #### 方法二:静态/动态链接FFmpeg库 如果需要更高效的控制和更高的灵活性,可以选择将FFmpeg库嵌入到QT应用中。这通常涉及以下几个步骤: 1. **下载并安装FFmpeg** 需要先获取FFmpeg源码并构建共享库或静态库。可以通过官方文档指导完成此操作[^1]。 2. **配置Qt Creator工程文件(.pro)** 将FFmpeg库添加至项目的`.pro`文件中以便于链接。 ```plaintext INCLUDEPATH += /path/to/ffmpeg/include LIBS += -L/path/to/ffmpeg/lib -lavformat -lavcodec -lswscale -lavutil ``` 3. **编写C++代码加载FFmpeg功能** 下面是一个简单的例子展示如何读取视频帧数据并通过OpenCV显示出来(假设已成功部署模型API接口[^3])。 ```cpp extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> } void decodeVideo(const char *filename) { AVFormatContext *pFormatCtx = nullptr; int videoStream; av_register_all(); // 注册所有可用的解码器、编码器和其他组件 if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0){ fprintf(stderr, "Couldn't open file\n"); return; // 打开失败退出程序运行 } if(avfindstreaminfo(pFormatCtx)<0){ printf("Didn't find stream information.\n"); return ; } videoStream=ff_find_stream_info(pFormatCtx); AVCodecParameters *codecpar=pFormatCtx->streams[videoStream]->codecpar; const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id); if(!codec){ fprintf(stderr,"Unsupported codec!\n"); return ; } AVFrame *frame,*rgb_frame; struct SwsContext *img_convert_ctx=NULL; uint8_t *out_buffer; frame=av_frame_alloc(); rgb_frame=av_frame_alloc(); img_convert_ctx=sws_getContext( pFormatCtx->streams[videoStream]->width, pFormatCtx->streams[videoStream]->height, codecpar->format, pFormatCtx->streams[videoStream]->width, pFormatCtx->streams[videoStream]->height, AV_PIX_FMT_RGB24, SWS_BILINEAR,NULL,NULL,NULL); out_buffer=(uint8_t*)av_malloc( av_image_get_buffer_size(AV_PIX_FMT_RGB24,pFormatCtx->streams[videoStream]->width, pFormatCtx->streams[videoStream]->height,1)); av_image_fill_arrays(rgb_frame->data,rgb_frame->linesize,out_buffer, AV_PIX_FMT_RGB24,pFormatCtx->streams[videoStream]->width, pFormatCtx->streams[videoStream]->height,1); AVPacket packet; while(av_read_frame(pFormatCtx,&packet)>=0){ if(packet.stream_index==videoStream){ int ret=avcodec_send_packet(codecctx,&packet); if(ret<0){ continue; } while(ret>=0){ ret=avcodec_receive_frame(codecctx,frame); if(ret==AVERROR(EAGAIN)||ret==AVERROR_EOF) break; else if(ret<0){ fprintf(stderr,"Error during decoding\n"); exit(1); } sws_scale(img_convert_ctx,(const uint8_t* const *)frame->data, frame->linesize,0,frame->height, rgb_frame->data,rgb_frame->linesize); QImage image((uchar*)rgb_frame->data[0],pFormatCtx->streams[videoStream]->width, pFormatCtx->streams[videoStream]->height,QImage::Format_RGB888); QLabel label; QPixmap pixmap=QPixmap::fromImage(image); label.setPixmap(pixmap.scaled(label.size(), Qt::KeepAspectRatio)); } } av_packet_unref(&packet); } } ``` 上述代码片段展示了如何解析视频流并将每一帧转换成RGB图像格式供进一步处理或者渲染。 --- #### 方法三:借助第三方封装库简化开发流程 对于不想深入研究底层细节的情况,可考虑引入一些基于FFmpeg二次开发而成的高级框架,比如QtAV 或者 VLC-Qt 。这些库提供了更加友好的界面以及跨平台支持能力,能够显著减少工作量。 --- ### 总结 无论采取哪种方式,在实际运用过程中都需要充分考虑到目标设备架构差异所带来的兼容性挑战;另外还需注意版权许可方面的要求以免触犯法律风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值