FFmpeg4.0笔记:封装ffmpeg的视频帧转换功能类CSws

Github

https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cff

CSws.h

/*******************************************************************
*  Copyright(c) 2019
*  All rights reserved.
*
*  文件名称:    CSws.h
*  简要描述:    帧转换
*
*  作者:  gongluck
*  说明:
*
*******************************************************************/

#ifndef __CSWS_H__
#define __CSWS_H__

#ifdef __cplusplus
extern "C"
{
#endif

#include <libswscale/swscale.h>
#include <libavutil/imgutils.h> // av_image_alloc

#ifdef __cplusplus
}
#endif

#include <string>
#include <mutex>

class CSws
{
public:
    virtual ~CSws();

    // 状态
    enum STATUS { STOP, LOCKED };
    // 设置源参数
    bool set_src_opt(AVPixelFormat pixfmt, int w, int h, std::string& err);
    // 设置目标参数
    bool set_dst_opt(AVPixelFormat pixfmt, int w, int h, std::string& err);
    // 锁定设置
    bool lock_opt(std::string& err);
    // 解除锁定
    bool unlock_opt(std::string& err);
    // 转换
    int scale(const uint8_t* const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t* const dst[], const int dstStride[], std::string& err);

private:
    STATUS status_ = STOP;
    std::recursive_mutex mutex_;

    SwsContext* swsctx_ = nullptr;

    AVPixelFormat src_pix_fmt_ = AV_PIX_FMT_NONE;
    AVPixelFormat dst_pix_fmt_ = AV_PIX_FMT_NONE;
    int src_w_ = 0;
    int src_h_ = 0;
    int dst_w_ = 0;
    int dst_h_ = 0;
};

#endif//__CSWS_H__

CSws.cpp

/*******************************************************************
*  Copyright(c) 2019
*  All rights reserved.
*
*  文件名称:    CSws.cpp
*  简要描述:    帧转换
*
*  作者:  gongluck
*  说明:
*
*******************************************************************/

#include "common.h"
#include "CSws.h"

CSws::~CSws()
{
    std::string err;
    unlock_opt(err);
}

bool CSws::set_src_opt(AVPixelFormat pixfmt, int w, int h, std::string& err)
{
    LOCK();
    CHECKSTOP(err);
    err = "opt succeed.";

    src_pix_fmt_ = pixfmt;
    src_w_ = w;
    src_h_ = h;

    return true;
}

bool CSws::set_dst_opt(AVPixelFormat pixfmt, int w, int h, std::string& err)
{
    LOCK();
    CHECKSTOP(err);
    err = "opt succeed.";

    dst_pix_fmt_ = pixfmt;
    dst_w_ = w;
    dst_h_ = h;

    return true;
}

bool CSws::lock_opt(std::string& err)
{
    LOCK();
    CHECKSTOP(err);
    err = "opt succeed.";

    swsctx_ = sws_getContext(src_w_, src_h_, src_pix_fmt_, dst_w_, dst_h_, dst_pix_fmt_, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
    if (swsctx_ == nullptr)
    {
        err = "sws_getContext return nullptr.";
        return false;
    }
    status_ = LOCKED;

    return true;
}

bool CSws::unlock_opt(std::string& err)
{
    LOCK();
    err = "opt succeed.";

    sws_freeContext(swsctx_);
    swsctx_ = nullptr;
    status_ = STOP;
    src_w_ = 0;
    src_h_ = 0;
    dst_w_ = 0;
    dst_h_ = 0;

    return true;
}

int CSws::scale(const uint8_t* const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t* const dst[], const int dstStride[], std::string& err)
{
    LOCK();
    CHECKNOTSTOP(err);
    err = "opt succeed.";

    int ret = sws_scale(swsctx_, srcSlice, srcStride, srcSliceY, srcSliceH, dst, dstStride);
    CHECKFFRET(ret);

    return ret;
}

测试

// 视频帧转换
void test_sws()
{
    bool ret = false;
    std::string err;
    std::ifstream yuv("in.yuv", std::ios::binary);
    CSws sws;

    // 分配图像数据内存
    uint8_t* src[4] = { 0 };
    int srclinesize[4] = { 0 };
    uint8_t* dst[4] = { 0 };
    int dstlinesize[4] = { 0 };

    int srcsize = av_image_alloc(src, srclinesize, 640, 432, AV_PIX_FMT_YUV420P, 1);
    int dstsize = av_image_alloc(dst, dstlinesize, 320, 240, AV_PIX_FMT_BGR24, 1);
    yuv.read(reinterpret_cast<char*>(src[0]), 640 * 432);
    yuv.read(reinterpret_cast<char*>(src[1]), 640 * 432 / 4);
    yuv.read(reinterpret_cast<char*>(src[2]), 640 * 432 / 4);

    ret = sws.set_src_opt(AV_PIX_FMT_YUV420P, 640, 432, err);
    TESTCHECKRET(ret);
    ret = sws.set_dst_opt(AV_PIX_FMT_BGR24, 320, 240, err);
    TESTCHECKRET(ret);
    ret = sws.lock_opt(err);
    TESTCHECKRET(ret);
    int size = sws.scale(src, srclinesize, 0, 432, dst, dstlinesize, err);
    std::cout << "sws " << size << " line" << std::endl;
    std::ofstream bgr("out.bgr", std::ios::binary);
    bgr.write(reinterpret_cast<char*>(dst[0]), dstsize);
    ret = sws.unlock_opt(err);
    TESTCHECKRET(ret);

    // 清理
    if (src != nullptr)
    {
        av_freep(&src[0]);
    }
    av_freep(&src);
    if (dst != nullptr)
    {
        av_freep(&dst[0]);
    }
    av_freep(&dst);
}
posted @ 2019-06-14 10:58  gongluck  阅读(522)  评论(0编辑  收藏  举报