欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SDL2:封装媒体显示播放Csdl2

程序员文章站 2022-05-15 13:26:37
Github https://github.com/gongluck/SDL2 study/tree/master/Csdl2 Csdl2.h Csdl2.cpp 测试 C++ include "Csdl2.h" include include include define TESTCHECKRET ......

github

https://github.com/gongluck/sdl2-study/tree/master/csdl2

csdl2.h

#ifndef __csdl2_h__
#define __csdl2_h__

#include <sdl.h>
#include <string>
#include <mutex>

class csdl2
{
public:
    // 状态
    enum status { stop = 0b00, lockedv = 0b01, lockeda = 0b10, lockedboth = 0b11 };

    // 全局的初始化
    bool global_init(uint32 flags, std::string& err);
    // 全局的反初始化
    bool global_uninit(std::string& err);

    // 设置(windows)窗口
    bool set_window(const void* hwnd, std::string& err);
    // 设置图像格式(sdl_pixelformat_???)
    bool set_pix_fmt(uint32 fmt, int w, int h, std::string& err);
    // 渲染数据,pitch是图像一行的字节大小,rect是渲染目标矩形,angle旋转角度,center旋转中心(在rect,{0,0}为左上),flip翻转
    bool render(const void* data, int pitch, const sdl_rect* rect, 
        const double angle, const sdl_point* center, const sdl_rendererflip flip, std::string& err);
    // 清理图像格式资源
    bool clear_pix_fmt(std::string& err);
    // 销毁关联资源
    bool detach_window(std::string& err);

    // 设置音频格式和处理回调
    bool set_audio_fmt(int freq, sdl_audioformat fmt, uint8 channels, uint16 samples, sdl_audiocallback callback, void* userdata, std::string& err);
    // 开始音频播放
    bool start_audio(std::string& err);
    // 停止音频播放
    bool stop_audio(std::string& err);

private:
    status status_ = stop;
    std::recursive_mutex mutex_;

    sdl_window* win_ = nullptr;
    sdl_renderer* renderer_ = nullptr;
    sdl_texture* texture_ = nullptr;

    sdl_audiospec reqspec_ = { 0 };
    sdl_audiospec recspec_ = { 0 };
};

#endif//__csdl2_h__

csdl2.cpp

#include "csdl2.h"

// 递归锁
#define lockcsdl2() std::lock_guard<std::recursive_mutex> _lock(this->mutex_)

// 检查停止状态
#define checkcsdl2stop(err) \
if(this->status_ != stop)\
{\
    err = "status is not stop.";\
    return false;\
}
// 检查视频停止
#define checkcsdl2stopv(err) \
if(this->status_ & 1 != 0)\
{\
    err = "statusv is not stop.";\
    return false;\
}
// 检查音频停止
#define checkcsdl2stopa(err) \
if((this->status_ >> 1) & 1 != 0)\
{\
    err = "statusa is not stop.";\
    return false;\
}
// 检查视频未停止
#define checkcsdl2nstopv(err) \
if(this->status_ & 1 == 0)\
{\
    err = "statusv is stop.";\
    return false;\
}
// 检查音频未停止
#define checkcsdl2nstopa(err) \
if((this->status_ >> 1) & 1 == 0)\
{\
    err = "statusa is stop.";\
    return false;\
}

// 返回成功
#define optsucceed()\
{\
    err = "opt succeed.";\
    return true;\
}

// 返回失败
#define optfailed()\
{\
    err = sdl_geterror();\
    return false;\
 }

// 判断结果,并返回(必定退出函数!!!)
#define checksdlret(ret)\
if(ret == 0)\
{\
    optsucceed();\
}\
else\
{\
    optfailed();\
}

bool csdl2::global_init(uint32 flags, std::string& err)
{
    lockcsdl2();
    checkcsdl2stop(err);
    if (sdl_init(flags) < 0)
    {
        optfailed();
    }
    else
    {
        optsucceed();
    }
}

bool csdl2::global_uninit(std::string& err)
{
    lockcsdl2();
    checkcsdl2stop(err);
    sdl_quit();
    optsucceed();
}

bool csdl2::set_window(const void* hwnd, std::string& err)
{
    lockcsdl2();
    checkcsdl2stopv(err);
    detach_window(err);
    win_ = sdl_createwindowfrom(hwnd);
    if (win_ != nullptr)
    {
        renderer_ = sdl_createrenderer(win_, -1, sdl_renderer_accelerated | sdl_renderer_presentvsync);
        if (renderer_ != nullptr)
        {
            optsucceed();
        }
        else
        {
            std::string e;
            detach_window(e);
            optfailed();
        }
    }
    else
    {
        optfailed();
    }
}

bool csdl2::set_pix_fmt(uint32 fmt, int w, int h, std::string& err)
{
    lockcsdl2();
    checkcsdl2stopv(err);
    clear_pix_fmt(err);
    if (renderer_ == nullptr)
    {
        err = "renderer is nullptr.";
        return false;
    }
    texture_ = sdl_createtexture(renderer_, fmt, sdl_textureaccess_streaming, w, h);
    if (texture_ != nullptr)
    {
        status_ = static_cast<status>(static_cast<unsigned int>(status_) | lockedv);
        optsucceed();
    }
    else
    {
        optfailed();
    }
}

bool csdl2::render(const void* data, int pitch, const sdl_rect* rect, 
    const double angle, const sdl_point* center, const sdl_rendererflip flip, 
    std::string& err)
{
    lockcsdl2();
    checkcsdl2nstopv(err);
    if (texture_ == nullptr || renderer_ == nullptr)
    {
        err = texture_ == nullptr ? "texture is nullptr." : "renderer is nullptr.";
        return false;
    }
    if (sdl_updatetexture(texture_, nullptr, data, pitch) != 0)
    {
        optfailed();
    }
    else
    {
        if (sdl_renderclear(renderer_) != 0)
        {
            optfailed();
        }
        else
        {
            if (sdl_rendercopyex(renderer_, texture_, nullptr, rect, angle, center, flip) != 0)
            {
                optfailed();
            }
            else
            {
                sdl_renderpresent(renderer_);
                optsucceed();
            }
        }
    }
}

bool csdl2::clear_pix_fmt(std::string& err)
{
    lockcsdl2();
    if (texture_ != nullptr)
    {
        sdl_destroytexture(texture_);
        texture_ = nullptr;
    }
    status_ = static_cast<status>(static_cast<unsigned int>(status_) & ~lockedv);
    optsucceed();
}

bool csdl2::detach_window(std::string& err)
{
    lockcsdl2();
    checkcsdl2stopv(err);
    if (renderer_ != nullptr)
    {
        sdl_destroyrenderer(renderer_);
        renderer_ = nullptr;
    }
    if (win_ != nullptr)
    {
        sdl_destroywindow(win_);
        win_ = nullptr;
    }
    optsucceed();
}

bool csdl2::set_audio_fmt(int freq, sdl_audioformat fmt, uint8 channels, uint16 samples, sdl_audiocallback callback, void* userdata, std::string& err)
{
    lockcsdl2();
    checkcsdl2stopa(err);
    reqspec_ = { 0 };
    recspec_ = { 0 };
    reqspec_.freq = freq;
    reqspec_.format = fmt;
    reqspec_.channels = channels;
    reqspec_.samples = samples;
    reqspec_.callback = callback;
    reqspec_.userdata = userdata;
    if (sdl_openaudio(&reqspec_, &recspec_) != 0)
    {
        optfailed();
    }
    else
    {
        status_ = static_cast<status>(static_cast<unsigned int>(status_) | lockeda);
        optsucceed();
    }
}

bool csdl2::start_audio(std::string& err)
{
    lockcsdl2();
    checkcsdl2nstopa(err);
    sdl_pauseaudio(0);
    optsucceed();
}

bool csdl2::stop_audio(std::string& err)
{
    lockcsdl2();
    checkcsdl2nstopa(err);
    sdl_pauseaudio(1);
    status_ = static_cast<status>(static_cast<unsigned int>(status_) & ~lockeda);
    optsucceed();
}

测试

#include "csdl2.h"
#include <iostream>
#include <fstream>
#include <windows.h>

#define testcheckret(ret)\
if(!ret)\
{\
    std::cerr << err << std::endl;\
    std::cout << "input to end." << std::endl;\
    getchar();\
    return sdl_error(sdl_lasterror);\
}

csdl2 g_test;
void sdlcall sdl_audiocb(void* userdata, uint8* stream, int len)
{
    static std::ifstream f("in.pcm", std::ios::binary);
    sdl_memset(stream, 0, len);
    void* buf = malloc(len);
    f.read((char*)buf, len);
    sdl_mixaudio(stream, (const uint8*)buf, len, sdl_mix_maxvolume);
    free(buf);
    if (f.eof())
    {
        std::cout << "end" << std::endl;
        f.close();
        std::string err;
        g_test.stop_audio(err);
    }    
}

int main(int argc, char* argv[])
{
    std::string err;
    rect rect = { 0 };
    sdl_point p = { 0, 50 };
    std::ifstream file("in.rgb", std::ios::binary);
    if (!file.is_open())
    {
        std::cerr << "open file failed " << std::endl;
        getchar();
        return 0;
    }
    int size = 320 * 240 * 3;
    void* buf = malloc(size);

    file.read(static_cast<char*>(buf), size);

    testcheckret(g_test.global_init(sdl_init_video | sdl_init_audio, err));

    hwnd hwnd = createwindow(text("static"), text("test csdl2"), ws_visible,
        cw_usedefault, cw_usedefault, 800, 500, nullptr, nullptr, getmodulehandle(nullptr), nullptr);
    //sdl_window* hwnd = sdl_createwindow("test csdl2", sdl_windowpos_undefined, sdl_windowpos_undefined, 320, 240, sdl_window_shown);
    if (hwnd == nullptr)
    {
        std::cerr << "create window failed " << getlasterror() << std::endl;
        goto end;
    }
    testcheckret(g_test.set_window(hwnd, err));
    testcheckret(g_test.set_pix_fmt(sdl_pixelformat_rgb24, 320, 240, err));
    testcheckret(g_test.render(buf, size / 240, nullptr, 2, &p, sdl_flip_none, err));
    std::cout << "render succeed." << std::endl;

    testcheckret(g_test.set_audio_fmt(44100, audio_f32, 2, 1024, sdl_audiocb, nullptr, err));
    testcheckret(g_test.start_audio(err));
    std::cout << "open audio succeed." << std::endl;

end:
    std::cout << "input to end." << std::endl;
    getchar();
    testcheckret(g_test.clear_pix_fmt(err));
    testcheckret(g_test.detach_window(err));
    if (hwnd != nullptr)
    {
        destroywindow(hwnd);
        hwnd = nullptr;
    }
    testcheckret(g_test.stop_audio(err));
    testcheckret(g_test.global_uninit(err));
    if (buf != nullptr)
    {
        free(buf);
        buf = nullptr;
    }
    return 0;
}