Github https://github.com/gongluck/SDL2-study/tree/master/Csdl2 Csdl2.h #ifndef __CSDL2_H__#define __CSDL2_H__#include SDL.h#include string#include mutexclass Csdl2{public: // 状态 enum STATUS { STOP = 0b00, LOCKEDV = 0b01, LOCKEDA = 0b10
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; }