前言
前面几节的学习都是通过SDL 播放 YUV 文件, 或者 一张图片
实际开发中,我们并不一定使用SDL 来完成播放的操作,还可以通过opengl 或者其他第三方的来播放。
因此我们这里有了一个想法:可以封装一套 videoview 的播放API ,让SDL 或者 OpenGL 都来继承这些 API以及具体的实现。
这样的好处是:这一套 动态库 或者 静态库 可以用到很多项目中,而不是只能用于SDL 中,如果后续用OpenGL 实现,只需要写一个OpenGL的实现即可
零,工厂模式回顾
一,定义父类以及 接口
父类名为 XVideoView:
包含了 多个需要子类实现的 纯虚函数。
1.1 第一个对外接口 -让user选择哪种子类实现 视频文件的显示
static XVideoView* create(ViewType type = SDL_TYPE);
该方法需要在XVideoView.cpp中实现,传递不同的ViewType,就生成不同的
////////////////////////////////////////////////////
///ViewType 是自定义的枚举类型, 包含支持的类型,比如说SDL, OPENGL,这一步让user 选择使用SDL 显示,还是使用 其他方式显示
///默认参数是SDL_TYPE,如果不传递参数,默认就是使用SDL 渲染图像
static XVideoView* create(ViewType type = SDL_TYPE);
1.2 第二个对外接口-初始化渲染窗口函数,这个是要具体的子类实现的。
virtual bool Init(int width, int height, Format fmt = RGBA8888, void* winid = nullptr) = 0;
因此该函数的设计必须是纯虚函数。且要保证线程安全。
//////////////////////
/// 纯虚函数,初始化渲染窗口 线程安全
/// 子类必须实现,如果子类是XSDL,那么init方法里面就需要完成关于sdl的初始化实现
/// @param width 视频文件的分辨率 ,例如 1080 * 720,width的值就是1080
/// @param height 视频文件的分辨率 ,例如 1080 * 720,height的值就是720
/// @param fmt 类似 RGB888,YUV420P ,表示的是绘制的格式
/// @param winid 窗口句柄,如果为空,创建新窗口
/// @return 是否创建成功
///
virtual bool Init(int width, int height, Format fmt = RGBA8888, void* winid = nullptr) = 0;
1.3第三个对外接口 - 渲染图像函数,这个是要具体的子类实现的。
因此该函数的设计必须是纯虚函数。且要保证线程安全。
virtual bool Draw(const unsigned char* data, int linesize = 0) = 0;
//////////////////////////////////////////////////
/// 渲染图像 线程安全
///@para data 渲染的二进制数据
///@para linesize 一行数据的字节数,对于YUV420P就是Y一行字节数
/// linesize<=0 就根据宽度和像素格式自动算出大小
/// @return 渲染是否成功
virtual bool Draw(const unsigned char* data, int linesize = 0) = 0;
1.4 第四个对外接口 - 清理所有申请的资源函数,这个是要具体的子类实现的。
virtual void Close() = 0;
//清理所有申请的资源,包括关闭窗口
virtual void Close() = 0;
1.5 第五个对外接口,记录当前 包裹 视频文件 UI组件的宽和高
我们的视频文件在实际开发中一般显示 在一个 ui 组件中,当user 将整个界面放大,缩小,全屏的情况下,包裹视频文件的UI组件也会跟着变大,变小,因此我们需要记录 包裹UI 组件的大小。,这样就可以 让 视频填充 的时候,知道 包裹 UI的大小。
void setscaleLable(int labelwidth, int lableheight);
//当我们将widget的大小变化的时候,存放视频的 lable 控件的大小也要跟着变化,我们需要记录 lable的宽和高
void setscaleLable(int labelwidth, int lableheight);
1.6 第六个对外接口,该函数主要是为了不使用winid创建的 窗口,如何关闭问题,一般开发中不会使用到。
/// 处理窗口退出事件,这个方法主要是为了在不使用qt的windows的情况下,意味着创建的显示sdl的window是和 label没有关系的
/// 那么这个窗口的关闭是要接受 sdl的quit_event 事件,即:我们在 isexit 内部实现中调用 SDL_WaitEventTimeout
/// 那么在什么时候调用这个isexit方法呢?在qt的 timeevent中调用就OK了
virtual bool IsExit() = 0;

1.6 测试说明:main.cpp中调用 XVideoViewRefactory.cpp 显示,

main.cpp,中调用 xvideoviewrefactory.cpp 显示
二 父类关键变量说明,以及父类的创建子类的函数实现
关键变量 和 枚举
protected:
int width_ = 0; //视频文件的分辨率 例如 1080 * 720,width_的值就是1080
int height_ = 0; //视频文件的分辨率 例如 1080 * 720,height_的值就是720
Format fmt_ = RGBA8888; //视频文件的像素格式
std::mutex mtx_; //确保线程安全
int lablewidth_ = 0; //放置 视频的 lable 的宽和高
int lableheight_ = 0;
void* winid_ = nullptr;
public:
enum Format{
RGBA8888 = 0, // sdl 对应格式为 SDL_PIXELFORMAT_RGBA8888,OPENGL对应格式为xxxxx
ARGB8888, // sdl 对应格式为 SDL_PIXELFORMAT_ARGB8888,OPENGL对应格式为xxxxx
YUV420P // sdl 对应格式为 SDL_PIXELFORMAT_IYUV,OPENGL对应格式为xxxxx
};
enum ViewType {
SDL_TYPE,
OPENGL_TYPE
};
创建子类的函数实现
XVideoView* XVideoView::create(ViewType type)
{
switch (type)
{
case XVideoView::ViewType::SDL_TYPE:
qDebug() << "XVideoView create XSDL.class";
return new XSDL();
break;
default:
break;
}
return nullptr;
}
void

最低0.47元/天 解锁文章
3万+

被折叠的 条评论
为什么被折叠?



