SDL2:封装媒体显示播放Csdl2
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;
}
SDL2:封装媒体显示播放Csdl2的更多相关文章
- 苹果平台上的媒体流播放技术HLS
近日在和朋友聊起媒体流的服务器端实时转码技术的时候,发现苹果的各种终端上的视频播放并未使用常见的基于UDP的RTSP/RTP,而强制使用了Http Live Stream技术,这里稍稍总结了如下. 苹 ...
- 示例:WPF中Slider控件封装的缓冲播放进度条控件
原文:示例:WPF中Slider控件封装的缓冲播放进度条控件 一.目的:模仿播放器播放进度条,支持缓冲任务功能 二.进度: 实现类似播放器中带缓存的播放样式(播放区域.缓冲区域.全部区域等样式) 实现 ...
- iOS开发拓展篇—封装音频文件播放工具类
iOS开发拓展篇—封装音频文件播放工具类 一.简单说明 1.关于音乐播放的简单说明 (1)音乐播放用到一个叫做AVAudioPlayer的类 (2)AVAudioPlayer常用方法 加载音乐文件 - ...
- C# 获取媒体文件播放时长
引用: Interop.Shell32.dll 方法: /// <summary> /// 获取媒体文件播放时长 /// </summary> /// <param na ...
- 使用Facebook开源代码FBShimmering封装进度显示的ShimmeCircleView
使用Facebook开源代码FBShimmering封装进度显示的ShimmeCircleView 效果图: 静态图: 源码: ShimmeCircleView.h 与 ShimmeCircleVie ...
- ffmpeg+SDL2实现的音频播放器V2.0(无杂音)
1. 前言 目前为止,学习了并记录了ffmpeg+SDL2显示视频以及事件(event)的内容. 这篇中记录ffmpeg+SDL2播放音频,没加入事件处理. 接下来加入事件处理并继续学习音视频同步,再 ...
- 了解实时媒体的播放(RTP/RTCP 和 RTSP)
http://blog.csdn.net/span76/article/details/12913307 RTP/RTCP RTP是基于 UDP协议的, UDP不用建立连接,效率更高:但允许丢包, 这 ...
- 演示基于SDL2.0+FFmpeg的播放器
SDL是一个跨平台的渲染组件,眼下已经推出到2.0.3版本号,支持Win/Linux/OSX/Android.网上非常多介绍大多是基于SDL1.2版本号的,与2.0版本号有一定的区别,本文演示怎样用S ...
- C#使用FFMPEG推流,并且获取流保存在本地,随时取媒体进行播放!
最近开发了基于C#的推流器一直不大理想,终于在不懈努力之后研究了一点成果,这边做个笔记:本文着重在于讲解下如何使用ffmpeg进行简单的推流,看似简单几行代码没有官方的文档很吃力.并获取流的源代码:如 ...
随机推荐
- 【模板】prim的heap优化
简单的代码.. 时间复杂度为O((n + m)logn) 大部分情况下还是跑不过kruskal的,慎用. #include <cstdio> #include <queue> ...
- 【树形DP】codeforces K. Send the Fool Further! (medium)
http://codeforces.com/contest/802/problem/K [题意] 给定一棵树,Heidi从根结点0出发沿着边走,每个结点最多经过k次,求这棵树的最大花费是多少(同一条边 ...
- PHP文件属性相关函数
<meta charset= "utf-8"><?php //获取文件属性的函数 function getFilePro($filename) { //检测文件是 ...
- JPos学习
基于JPos的消息交换系统 消息交换系统需求解读 消息交换系统不不是一个具体的业务系统,而是业务系统的运转的基础框架: 他的运转是体现在报文交换上的: 要定义一个可被不同业务系统使用的报文规范: 报文 ...
- 最小生成树求法 Prim + Kruskal
prim算法的思路 和dijkstra是一样的 每次选取一个最近的点 然后去向新的节点扩张 注意这里的扩张 不再是 以前求最短路时候的到新的节点的最短距离 而是因为要生成一棵树 所以是要连一根最短的连 ...
- [Android] 随时拍图像处理部分总结及源码分享
http://blog.csdn.net/eastmount/article/details/45492065#comments [Android] 图像各种处理系列文章合集 http://blog. ...
- gitlab上fork的项目如何获取源更新
1.添加上游项目地址 git remote add upstream URL 2.查看远程仓库信息 可以看到上游项目地址已经添加进来了 git remote -v 3.获取上游项目更新 获取到的更新会 ...
- 洛谷—— P1714 切蛋糕
https://www.luogu.org/problem/show?pid=1714 题目描述 今天是小Z的生日,同学们为他带来了一块蛋糕.这块蛋糕是一个长方体,被用不同色彩分成了N个相同的小块,每 ...
- codevs——3064 求和
3064 求和 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 青铜 Bronze 题解 查看运行结果 题目描述 Description 输入一个数x(x <= ...
- LinkedList总结
1,LinkedList也是继承了List的接口 所以在LinkedList中存储的也是有序的,不唯一的数据 它采用的是链表式储存,所以比较适合用来执行插入,删除等功能 2,LinkedList特有的 ...