SDL2:封裝媒體顯示播放Csdl2

来源:https://www.cnblogs.com/gongluck/archive/2019/06/21/11066398.html
-Advertisement-
Play Games

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

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 正則表達式基礎以及Java中使用正則查找 定義: 正則表達式是一些用來匹配和處理文本的字元串 正則的基礎(先大致瞭解下) 1. 正則表達式的作用 1. 查找特定的信息(搜索) 2. 替換一些文本(替換) 2. 正則基礎知識 1. 元字元 . 匹配除換行符(\n)以外的任何單個字元 w 匹配字母、數字 ...
  • 6.8 包的使用 包就是一個包含有init.py文件的文件夾,所以其實我們創建包的目的就是為了用文件夾將文件/模塊組織起來 強調: 在python3中,即使包下沒有__init__.py文件,import 包仍然不會報錯,而在python2中,包下一定要有該文件,否則import 包報錯 包以及包所 ...
  • 6.21自我總結 一.爬取鬥圖網 1.摘要 2.爬取代碼 ...
  • 迴圈結構 :for 迴圈四要素: 1.初始化條件 2.迴圈條件 3.迴圈體 4.迭代條件 格式: for(初始化條件;迴圈條件;迭代條件){ 迴圈體; } 執行順序 :1 -> 2 -> 3 -> 4 ->2 -> 3 -> 4 ...... 2 說明: 1.初始化條件只執行一次 2.迴圈條件的結果 ...
  • 迴圈結構 :do-while 迴圈四要素: 1.初始化條件 2.迴圈條件 3.迴圈體 4.迭代條件 格式: 1.初始化條件 do{ 3.迴圈體 4.迭代條件 }while(2.迴圈條件); do-while和while的區別? ...
  • ``` Date: 表示特定的瞬間,精確到毫秒,通過方法設定自己所表示的時間,可以表示任意的時間 System.currentTimeMillis() :返回的當前系統時間, 1970-1-1 至今的毫秒數 SimpleDateFormat sdf = new SimpleDateFormat("y... ...
  • 1.遍歷key值 同理,可把下列代碼的d改為d.keys() notice:python2除了上述兩種方法外,還可以寫為d.iterkeys() 2.遍歷value值 同理,可把下列代碼的d改為d.values() notice:python2除了上述兩種方法外,還可以寫為d.itervalues( ...
  • 容器可設置佈局管理器,管理容器中組件的佈局: container.setLayout(new XxxLayout()); Java有6種佈局管理器,AWT提供了5種: FlowLayout BorderLayout GridLayout GridBagLayout CradLayout Swing還 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...