专栏首页C++FFmpeg4.0笔记:封装ffmpeg的视频帧转换功能类CSws

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

Github

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

CSws.h

#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:
    ~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);
    // 转换
    bool 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

#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);
    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);
    dst_pix_fmt_ = pixfmt;
    dst_w_ = w;
    dst_h_ = h;
    return true;
}

bool CSws::lock_opt(std::string& err)
{
    LOCK();
    CHECKSTOP(err);
    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(src_w_, src_h_, src_pix_fmt_, dst_w_, dst_h_, dst_pix_fmt_, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr) return nullptr.";
        return false;
    }
    status_ = LOCKED;
    return true;
}

bool CSws::unlock_opt(std::string& err)
{
    LOCK();
    sws_freeContext(swsctx_);
    swsctx_ = nullptr;
    status_ = STOP;
    src_w_ = 0;
    src_h_ = 0;
    dst_w_ = 0;
    dst_h_ = 0;
    return true;
}

bool 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);
    int ret = sws_scale(swsctx_, srcSlice, srcStride, srcSliceY, srcSliceH, dst, dstStride);
    CHECKFFRET(ret);
    return true;
}

测试

#include "CDecode.h"
#include "CSws.h"
#include <iostream>
#include <fstream>

CSws g_sws;
uint8_t* g_pointers[4] = { 0 };
int g_linesizes[4] = { 0 };

void DecStatusCB(CDecode::STATUS status, std::string err, void* param)
{
    std::cout << std::this_thread::get_id() << " got a status " << status << std::endl;
}

void DecFrameCB(const AVFrame* frame, CDecode::FRAMETYPE frametype, void* param)
{
    //std::cout << std::this_thread::get_id() << " got a frame." << frametype << std::endl;
    if (frametype == CDecode::FRAMETYPE::VIDEO)
    {
        if (frame->format == AV_PIX_FMT_YUV420P)
        {
            static std::ofstream video("out.rgb", std::ios::binary | std::ios::trunc);
            static int i = 0;
            if (++i > 9)
                return; 

            /*
            video.write(reinterpret_cast<const char*>(frame->data[0]), frame->linesize[0] * frame->height);
            video.write(reinterpret_cast<const char*>(frame->data[1]), frame->linesize[1] * frame->height / 2);
            video.write(reinterpret_cast<const char*>(frame->data[2]), frame->linesize[2] * frame->height / 2);
            */

            std::string err;
            // 将输出翻转
            g_pointers[0] += g_linesizes[0] * (240 - 1);
            g_linesizes[0] *= -1;
            // 转换
            g_sws.scale(frame->data, frame->linesize, 0, frame->height, g_pointers, g_linesizes, err);
            // 还原指针,以便拷贝数据
            g_linesizes[0] *= -1;
            g_pointers[0] -= g_linesizes[0] * (240 - 1);
            video.write(reinterpret_cast<const char*>(g_pointers[0]), g_linesizes[0] * 240);
        }
    }
}

int main(int argc, char* argv[])
{
    std::string err;
    bool ret = false;

    ret = g_sws.set_src_opt(AV_PIX_FMT_YUV420P, 576, 432, err);
    ret = g_sws.set_dst_opt(AV_PIX_FMT_RGB24, 320, 240, err);
    ret = g_sws.lock_opt(err);
    int size = av_image_alloc(g_pointers, g_linesizes, 320, 240, AV_PIX_FMT_RGB24, 1);

    CDecode decode;
    ret = decode.set_input("in.flv", err);
    ret = decode.set_dec_callback(DecFrameCB, nullptr, err);
    ret = decode.set_dec_status_callback(DecStatusCB, nullptr, err);

    int i = 0;
    while (i++ < 1)
    {
        ret = decode.begindecode(err);

        std::cout << "input to stop decoding." << std::endl;
        getchar();

        ret = decode.stopdecode(err);
    }

    ret = g_sws.unlock_opt(err);
    av_freep(&g_pointers[0]);

    return 0;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • FFmpeg4.0笔记:封装ffmpeg的音频重采样功能类CSwr

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

    gongluck
  • Windows核心编程:第8章 用户模式下的线程同步

    https://github.com/gongluck/Windows-Core-Program.git

    gongluck
  • Windows核心编程:第3章 内核对象

    gongluck
  • 图论--SCC缩点--Tarjan

    风骨散人Chiam
  • 云+社区技术沙龙第24期回顾-物联网技术与应用(文末附PPT)

    2019年7月27日,由云+社区主办的第24期云+社区技术沙龙“物联网技术及应用”,在深圳腾讯滨海大厦举行,本期沙龙邀请了腾讯云技术专家分享关于腾讯云物联网平台...

    云加社区技术沙龙
  • 图论--SCC强连通缩点--Tarjan

    强连通缩点与双连通缩点大同小异,也就是说将强连通分支缩成一个点之后,没有强连通,成为有向无环图,在对图进行题目的操作。

    风骨散人Chiam
  • 一个故事告诉你和运营大牛的区别——运营小白上班记

    今天是我在这家手游公司上班的第一天,老板就交给我一件特别重要!重要!重要的事! 他特别关照我所有COO和运营总监都是从做这件事开始的,那就是“整理公司游戏在A...

    WeTest质量开放平台团队
  • 案例研究:Workiva

    “通过OpenTracing,我的团队能够查看跟踪而向其他团队提出优化建议,无需查看他们的代码。”

    CNCF
  • ESLint 工作原理探讨

    ESLint 可谓是现代前端开发过程中必备的工具了。其用法简单,作用却很大,使用过程中不知曾帮我减少过多少次可能的 bug。其实仔细想想前端开发过程中的必备工具...

    Fundebug
  • 在windows下安装Python(Python入门教程)

    在搭建自己博客的过程之中,对于一个零基础的小白来说,其实要做的东西非常多,我把这个过程之中遇到的一些东西都写在了这个专题里面。今天之所以安装Python,是打算...

    王小婷

扫码关注云+社区

领取腾讯云代金券