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进行简单的推流,看似简单几行代码没有官方的文档很吃力.并获取流的源代码:如 ...
随机推荐
- struts2 标签库使用
[引用]json 使用 [引用]struts2 标签库使用 2011-05-11 16:13:00| 分类: 默认分类 | 标签: |举报 |字号大中小 订阅 本文转载自kangzye<st ...
- ES6__数据结构 Map
/* 数据结构 Map */ /* * 字典:是用来存储不重复的key的hash结构.不同于集合(Set)的是,字典使用的是[键,值]的形式来储存数据的. *javaScript 的对象(Object ...
- php装饰者模式
php装饰者模式 装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 示例: A.B.C编辑同一篇文章. class ...
- Xcode 全局搜索失效的问题
早上手一快不知点了什么,然后全局搜索的功能就不起作用了.百度了一下才知道,原来把搜索范围给改了,改回来如下:
- POJ 2240 【这题貌似可以直接FLOYD 屌丝用SPFA通过枚举找正权值环 顺便学了下map】
题意: 给了n种硬币的名称,给了m种硬币间的转换关系. 从任意兑换地点开始兑换,看是否能够通过兑换的方式增加金钱. 思路: 用SPFA不断对各个点进行松弛操作,寻找正权值的环.如果找到则输出Yes. ...
- json转xml报[java.lang.NoClassDefFoundError: nu/xom/Serializer]
原文:http://blog.csdn.net/figo645/article/details/48413571 开始学习JSON了,那么很自然的,我开始要熟悉一些基本的JSON语法 {}代表对象,[ ...
- HTML5 <template>标签元素简介
一.HTML5 template元素初面 <template>元素,基本上可以确定是2013年才出现的.干嘛用的呢,顾名思意,就是用来声明是“模板元素”. 目前,我们在HTML中嵌入模板H ...
- C++设计模式之适配器模式(二)
3.Socket网络通信的设计与实现------类适配器 除了对象适配器模式之外.适配器模式另一种形式.那就是类适配器模式,类适配器模式和对象适配器模式最大的差别在于适配器和适配者之间的关系不同,对象 ...
- 有多个git项目要用多个秘钥
在~/.ssh文件夹下新建文件config,格式例如以下 Host "authmanage" HostName "code.csdn.net" User &qu ...
- Xpath—解决这个问题的良药
何为良药? 因为在XML中存在一些问题和缺陷,针对这些问题就产生了响应的解决方式.如: getElementById方法在解析XML时因为一些原因适不适合的: 首先XML中每一个元素节点不一定有id属 ...