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;
}