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进行简单的推流,看似简单几行代码没有官方的文档很吃力.并获取流的源代码:如 ...
随机推荐
- PHP目录文件遍历
<meta charset="utf-8"><?php //遍历文件中的所有文件名称 foreach(glob("phpmyadmin/*") ...
- Scrapy的log日志功能
Logging Scrapy提供了log功能,可以通过 logging 模块使用 可以修改配置文件settings.py,任意位置添加下面两行 LOG_FILE = "mySpider.lo ...
- [转]Android SDK下载和更新失败的解决方法
今天更新sdk,遇到了更新下载失败问题: Fetching https://dl-ssl.google.com/android/repository/addons_list-2.xmlFetched ...
- ORACLE备份、恢复、常用查询
--第一,启动服务,(如果数据库处于启动状态,那么略过这一步) 打开命令行执行以下语句 net start OracleServiceORCL net start OracleOraDb10g_ ...
- java基础 4 继承(3)this 与 super关键字
this用来指向当前实例对象,用来区别成员变量与方法的形参 super可以用来访问父类的方法或成员变量,当子类构造函数需要显示的调用父类的构造函数时,super()必须为构造函数中的第一条语句.
- FIREDAC保存ORACLE的BLOB字段数据
FIREDAC默认识别ORACLE的BLOB字段为HUGEBLOB,需要将HBLOB映射为BLOB,才可以保存ORACLE的BLOB字段的数据.
- bufferevent 与 socket
http://blog.sina.com.cn/s/blog_56dee71a0100qx4s.html 很多时候,除了响应事件之外,应用还希望做一定的数据缓冲.比如说,写入数据的时候,通常的运行模式 ...
- notepad++ 查找引用(Find Reference)(适用于c c++及各类脚本比方lua、python等)
在程序开发过程中,程序猿经经常使用到的一个功能就是查找引用(Find Reference).Visual Studio里面的相应功能是"查找全部引用"(Find All Refer ...
- anaconda中新rdkit安装
1. 执行 conda create -c rdkit -n my-rdkit-env rdkit 该步骤经测试发现需FQ,而模拟器无法完成FQ(至少我不知道方法), 因此在本机上配置好环境后复制粘贴 ...
- 2016/05/16 UEditor 文本编辑器 使用教程与使用方法
第一:百度UEditor编辑器的官方下载地址 ueditor 官方地址:http://ueditor.baidu.com/website/index.html 开发文档地址:http://uedito ...