在步入正题之前,大家可以先了解一下obs的预览框显示相关内容:
一.投屏理念与方法
我们先实际操作一下,看看投屏后效果是什么?
原来是新建了一个界面容器,并在那个画面上绘图啊。
我们都知道,obs的预览框是通过OBSQTDisplay这个类实现的,这个类继承了QWidget,也就是说他也是一个QWidget。
在不看代码的情况下,根据猜测,我们可以猜测出,应该是新建了一个QWidget,并将OBSQTDisplay插入进去,或者干脆直接就是一个OBSQTDisplay。
我们可以通过OBS源码使用学习(二)之预览框显示 中提到方法,自己写一个QWidget,然后把预览框加进去实现效果,或者再次拿出我们系列的老本行——借鉴源码。
二.修改OBS投屏的相关源码
投屏相关的源码,是window-projector.hpp和window-projector.cpp,通过代码我们可以看出,这个代码中的类OBSProjector,就是继承了OBSQTDisplay
我们直接将源代码添加进自己的工程文件即可,当然,并不是里面所有的都需要,我们需要的仅仅是投屏而已,因此,裁剪后的代码如下:
#include <QAction>
#include <QGuiApplication>
#include <QMouseEvent>
#include <QMenu>
#include <QScreen>
#include "window-projector.hpp"
OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,ProjectorType type_)
: OBSQTDisplay(widget, Qt::Window),
source(source_),
removedSignal(obs_source_get_signal_handler(source), "remove",
OBSSourceRemoved, this)
{
source = source_;
type_ = ProjectorType::Source;
SetMonitor(monitor);
auto addDrawCallback = [this]() {
obs_display_add_draw_callback(GetDisplay(), &OBSRender,this);
obs_display_set_background_color(GetDisplay(), 0x000000);
};
connect(this, &OBSQTDisplay::DisplayCreated, addDrawCallback);
if (source)
obs_source_inc_showing(source);
ready = true;
show();
activateWindow();
}
OBSProjector::~OBSProjector()
{
auto addDrawCallback = [this]() {
obs_display_remove_draw_callback(GetDisplay(), &OBSRender,this);
obs_display_set_background_color(GetDisplay(), 0x000000);
};
connect(this, &OBSQTDisplay::destroyed, addDrawCallback);
if (source)
obs_source_dec_showing(source);
}
static inline void startRegion(int vX, int vY, int vCX, int vCY, float oL,
float oR, float oT, float oB)
{
gs_projection_push();
gs_viewport_push();
gs_set_viewport(vX, vY, vCX, vCY);
gs_ortho(oL, oR, oT, oB, -100.0f, 100.0f);
}
static inline void endRegion()
{
gs_viewport_pop();
gs_projection_pop();
}
void OBSProjector::OBSSourceRemoved(void *data, calldata_t *params)
{
OBSProjector *window = reinterpret_cast<OBSProjector *>(data);
}
void OBSProjector::SetMonitor(int monitor)
{
savedMonitor = monitor;
screen = QGuiApplication::screens()[monitor];
setGeometry(screen->geometry());
showFullScreen();
SetHideCursor();
}
void OBSProjector::SetHideCursor()
{
setCursor(Qt::BlankCursor);
}
void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy)
{
OBSProjector *window = reinterpret_cast<OBSProjector *>(data);
OBSSource source = window->source;
uint32_t targetCX;
uint32_t targetCY;
int x, y;
int newCX, newCY;
float scale;
if (source) {
targetCX = std::max(obs_source_get_width(source), 1u);
targetCY = std::max(obs_source_get_height(source), 1u);
} else {
struct obs_video_info ovi;
ovi.fps_num = 30;
ovi.fps_den = 1;
obs_get_video_info(&ovi);
targetCX = ovi.base_width;
targetCY = ovi.base_height;
}
GetScaleAndCenterPos(targetCX, targetCY, cx, cy, x, y, scale);
newCX = int(scale * float(targetCX));
newCY = int(scale * float(targetCY));
startRegion(x, y, newCX, newCY, 0.0f, float(targetCX), 0.0f,
float(targetCY));
if (source)
//将所要预览的源添加在obs_source_video_render函数
obs_source_video_render(source);
else
obs_render_main_texture();
endRegion();
}
三.使用OBSProjector
话不多说,直接上代码:
QList<QScreen*> screen_list = QGuiApplication::screens();
//获取屏幕
if (screen_list.count() > 1)
{
projector = new OBSProjector(this, source, 1, ProjectorType::Source);
//obs类的老传统,直接实例化就能用,连方法都不用调用,直接实例化就能搞定
}
else
{
QMessageBox::information(this, "提示","没有配置第二屏幕");
}
这个类的第二个参数就是源,第三个就是屏幕号, 0号是主屏,1号是外接屏1,以此类推。
输入不同的源,就能得到不同的投屏效果,我们可以投不同的源,投到不同的屏幕。