Add scale support
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
project(obs-webkit-browser VERSION 1.1.0 LANGUAGES C CXX)
|
project(obs-webkit-browser VERSION 1.2.0 LANGUAGES C CXX)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
@@ -79,6 +79,10 @@ if(BUILD_TESTING)
|
|||||||
COMMAND renderer-smoke-test $<TARGET_FILE:obs-webkit-renderer> opaque)
|
COMMAND renderer-smoke-test $<TARGET_FILE:obs-webkit-renderer> opaque)
|
||||||
set_tests_properties(renderer-opaque-smoke-test PROPERTIES TIMEOUT 20 SKIP_RETURN_CODE 77)
|
set_tests_properties(renderer-opaque-smoke-test PROPERTIES TIMEOUT 20 SKIP_RETURN_CODE 77)
|
||||||
|
|
||||||
|
add_test(NAME renderer-zoom-smoke-test
|
||||||
|
COMMAND renderer-smoke-test $<TARGET_FILE:obs-webkit-renderer> zoom)
|
||||||
|
set_tests_properties(renderer-zoom-smoke-test PROPERTIES TIMEOUT 20 SKIP_RETURN_CODE 77)
|
||||||
|
|
||||||
add_executable(renderer-fps-test tests/renderer-fps-test.c)
|
add_executable(renderer-fps-test tests/renderer-fps-test.c)
|
||||||
target_compile_features(renderer-fps-test PRIVATE c_std_11)
|
target_compile_features(renderer-fps-test PRIVATE c_std_11)
|
||||||
target_compile_definitions(renderer-fps-test PRIVATE _GNU_SOURCE)
|
target_compile_definitions(renderer-fps-test PRIVATE _GNU_SOURCE)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ DMA-BUF. Кадры передаются в OBS напрямую как BGRA, б
|
|||||||
- HTTP/HTTPS, `data:` URL и локальные HTML-файлы;
|
- HTTP/HTTPS, `data:` URL и локальные HTML-файлы;
|
||||||
- прозрачный фон с alpha-каналом;
|
- прозрачный фон с alpha-каналом;
|
||||||
- пользовательский CSS;
|
- пользовательский CSS;
|
||||||
|
- масштаб страницы 25–500% с сохранением в настройках источника или web-панели;
|
||||||
- размер 2–8192 px и 1–60 FPS;
|
- размер 2–8192 px и 1–60 FPS;
|
||||||
- аппаратный WebKit compositor через DRM/DMA-BUF (Mesa `radeonsi` на AMD);
|
- аппаратный WebKit compositor через DRM/DMA-BUF (Mesa `radeonsi` на AMD);
|
||||||
- прямой XComposite/XShm-захват скомпозированного GPU-кадра с alpha;
|
- прямой XComposite/XShm-захват скомпозированного GPU-кадра с alpha;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ URL="URL or local HTML file"
|
|||||||
Width="Width"
|
Width="Width"
|
||||||
Height="Height"
|
Height="Height"
|
||||||
FPS="Frames per second"
|
FPS="Frames per second"
|
||||||
|
PageZoom="Page zoom (%)"
|
||||||
Transparent="Transparent background"
|
Transparent="Transparent background"
|
||||||
CustomCSS="Custom CSS"
|
CustomCSS="Custom CSS"
|
||||||
ShutdownWhenHidden="Shut down renderer when source is hidden"
|
ShutdownWhenHidden="Shut down renderer when source is hidden"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ URL="URL или локальный HTML-файл"
|
|||||||
Width="Ширина"
|
Width="Ширина"
|
||||||
Height="Высота"
|
Height="Высота"
|
||||||
FPS="Кадров в секунду"
|
FPS="Кадров в секунду"
|
||||||
|
PageZoom="Масштаб страницы (%)"
|
||||||
Transparent="Прозрачный фон"
|
Transparent="Прозрачный фон"
|
||||||
CustomCSS="Пользовательский CSS"
|
CustomCSS="Пользовательский CSS"
|
||||||
ShutdownWhenHidden="Останавливать рендерер, когда источник скрыт"
|
ShutdownWhenHidden="Останавливать рендерер, когда источник скрыт"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QShowEvent>
|
#include <QShowEvent>
|
||||||
#include <QSocketNotifier>
|
#include <QSocketNotifier>
|
||||||
|
#include <QSpinBox>
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
@@ -108,11 +109,13 @@ struct DockDefinition {
|
|||||||
QString id;
|
QString id;
|
||||||
QString title;
|
QString title;
|
||||||
QString url;
|
QString url;
|
||||||
|
int zoomPercent = 100;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebPanel final : public QWidget {
|
class WebPanel final : public QWidget {
|
||||||
public:
|
public:
|
||||||
explicit WebPanel(QString url, QWidget *parent = nullptr) : QWidget(parent), url_(std::move(url))
|
explicit WebPanel(QString url, int zoomPercent, QWidget *parent = nullptr)
|
||||||
|
: QWidget(parent), url_(std::move(url)), zoomPercent_(zoomPercent)
|
||||||
{
|
{
|
||||||
setFocusPolicy(Qt::StrongFocus);
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
@@ -127,11 +130,13 @@ public:
|
|||||||
|
|
||||||
~WebPanel() override { stopRenderer(); }
|
~WebPanel() override { stopRenderer(); }
|
||||||
|
|
||||||
void setUrl(const QString &url)
|
void setConfiguration(const QString &url, int zoomPercent)
|
||||||
{
|
{
|
||||||
if (url_ == url)
|
zoomPercent = std::clamp(zoomPercent, 25, 500);
|
||||||
|
if (url_ == url && zoomPercent_ == zoomPercent)
|
||||||
return;
|
return;
|
||||||
url_ = url;
|
url_ = url;
|
||||||
|
zoomPercent_ = zoomPercent;
|
||||||
if (isVisible())
|
if (isVisible())
|
||||||
restartRenderer();
|
restartRenderer();
|
||||||
}
|
}
|
||||||
@@ -343,6 +348,7 @@ private:
|
|||||||
header.width = static_cast<uint32_t>(renderWidth_);
|
header.width = static_cast<uint32_t>(renderWidth_);
|
||||||
header.height = static_cast<uint32_t>(renderHeight_);
|
header.height = static_cast<uint32_t>(renderHeight_);
|
||||||
header.fps = 30;
|
header.fps = 30;
|
||||||
|
header.zoom_percent = static_cast<uint32_t>(zoomPercent_);
|
||||||
header.transparent = 0;
|
header.transparent = 0;
|
||||||
header.hardware_acceleration = 1;
|
header.hardware_acceleration = 1;
|
||||||
header.url_length = static_cast<uint32_t>(url.size());
|
header.url_length = static_cast<uint32_t>(url.size());
|
||||||
@@ -569,6 +575,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString url_;
|
QString url_;
|
||||||
|
int zoomPercent_ = 100;
|
||||||
QString status_;
|
QString status_;
|
||||||
QImage frame_;
|
QImage frame_;
|
||||||
QTimer resizeTimer_;
|
QTimer resizeTimer_;
|
||||||
@@ -732,6 +739,7 @@ private:
|
|||||||
obs_data_set_string(item, "id", definition.id.toUtf8().constData());
|
obs_data_set_string(item, "id", definition.id.toUtf8().constData());
|
||||||
obs_data_set_string(item, "title", definition.title.toUtf8().constData());
|
obs_data_set_string(item, "title", definition.title.toUtf8().constData());
|
||||||
obs_data_set_string(item, "url", definition.url.toUtf8().constData());
|
obs_data_set_string(item, "url", definition.url.toUtf8().constData());
|
||||||
|
obs_data_set_int(item, "zoom", definition.zoomPercent);
|
||||||
obs_data_array_push_back(array, item);
|
obs_data_array_push_back(array, item);
|
||||||
obs_data_release(item);
|
obs_data_release(item);
|
||||||
}
|
}
|
||||||
@@ -750,7 +758,11 @@ private:
|
|||||||
QString::fromUtf8(obs_data_get_string(item, "id")),
|
QString::fromUtf8(obs_data_get_string(item, "id")),
|
||||||
QString::fromUtf8(obs_data_get_string(item, "title")),
|
QString::fromUtf8(obs_data_get_string(item, "title")),
|
||||||
QString::fromUtf8(obs_data_get_string(item, "url")),
|
QString::fromUtf8(obs_data_get_string(item, "url")),
|
||||||
|
static_cast<int>(obs_data_get_int(item, "zoom")),
|
||||||
};
|
};
|
||||||
|
if (definition.zoomPercent == 0)
|
||||||
|
definition.zoomPercent = 100;
|
||||||
|
definition.zoomPercent = std::clamp(definition.zoomPercent, 25, 500);
|
||||||
if (definition.id.isEmpty())
|
if (definition.id.isEmpty())
|
||||||
definition.id = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
definition.id = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||||
if (!definition.title.trimmed().isEmpty() && !definition.url.trimmed().isEmpty())
|
if (!definition.title.trimmed().isEmpty() && !definition.url.trimmed().isEmpty())
|
||||||
@@ -780,11 +792,12 @@ private:
|
|||||||
}
|
}
|
||||||
for (const DockDefinition &definition : definitions_) {
|
for (const DockDefinition &definition : definitions_) {
|
||||||
if (panels_.contains(definition.id) && panels_[definition.id]) {
|
if (panels_.contains(definition.id) && panels_[definition.id]) {
|
||||||
panels_[definition.id]->setUrl(definition.url);
|
panels_[definition.id]->setConfiguration(definition.url,
|
||||||
|
definition.zoomPercent);
|
||||||
panels_[definition.id]->setDockTitle(definition.title);
|
panels_[definition.id]->setDockTitle(definition.title);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto *panel = new WebPanel(definition.url);
|
auto *panel = new WebPanel(definition.url, definition.zoomPercent);
|
||||||
QByteArray id = dockId(definition.id).toUtf8();
|
QByteArray id = dockId(definition.id).toUtf8();
|
||||||
QByteArray title = definition.title.toUtf8();
|
QByteArray title = definition.title.toUtf8();
|
||||||
if (obs_frontend_add_dock_by_id(id.constData(), title.constData(), panel))
|
if (obs_frontend_add_dock_by_id(id.constData(), title.constData(), panel))
|
||||||
@@ -802,10 +815,11 @@ private:
|
|||||||
dialog.resize(720, 360);
|
dialog.resize(720, 360);
|
||||||
auto *layout = new QVBoxLayout(&dialog);
|
auto *layout = new QVBoxLayout(&dialog);
|
||||||
layout->addWidget(new QLabel(text("CustomBrowserDocksDescription"), &dialog));
|
layout->addWidget(new QLabel(text("CustomBrowserDocksDescription"), &dialog));
|
||||||
auto *table = new QTableWidget(0, 2, &dialog);
|
auto *table = new QTableWidget(0, 3, &dialog);
|
||||||
table->setHorizontalHeaderLabels({text("PanelName"), text("URL")});
|
table->setHorizontalHeaderLabels({text("PanelName"), text("URL"), text("PageZoom")});
|
||||||
table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||||
table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
|
table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||||
|
table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
|
||||||
table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
table->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
table->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
layout->addWidget(table);
|
layout->addWidget(table);
|
||||||
@@ -817,6 +831,12 @@ private:
|
|||||||
title->setData(Qt::UserRole, definition.id);
|
title->setData(Qt::UserRole, definition.id);
|
||||||
table->setItem(row, 0, title);
|
table->setItem(row, 0, title);
|
||||||
table->setItem(row, 1, new QTableWidgetItem(definition.url));
|
table->setItem(row, 1, new QTableWidgetItem(definition.url));
|
||||||
|
auto *zoom = new QSpinBox(table);
|
||||||
|
zoom->setRange(25, 500);
|
||||||
|
zoom->setSingleStep(5);
|
||||||
|
zoom->setSuffix("%");
|
||||||
|
zoom->setValue(definition.zoomPercent);
|
||||||
|
table->setCellWidget(row, 2, zoom);
|
||||||
};
|
};
|
||||||
for (const DockDefinition &definition : definitions_)
|
for (const DockDefinition &definition : definitions_)
|
||||||
appendRow(definition);
|
appendRow(definition);
|
||||||
@@ -829,7 +849,7 @@ private:
|
|||||||
rowButtons->addStretch();
|
rowButtons->addStretch();
|
||||||
layout->addLayout(rowButtons);
|
layout->addLayout(rowButtons);
|
||||||
QObject::connect(add, &QPushButton::clicked, table, [table, appendRow] {
|
QObject::connect(add, &QPushButton::clicked, table, [table, appendRow] {
|
||||||
appendRow({QUuid::createUuid().toString(QUuid::WithoutBraces), QString(), "https://"});
|
appendRow({QUuid::createUuid().toString(QUuid::WithoutBraces), QString(), "https://", 100});
|
||||||
int row = table->rowCount() - 1;
|
int row = table->rowCount() - 1;
|
||||||
table->setCurrentCell(row, 0);
|
table->setCurrentCell(row, 0);
|
||||||
table->editItem(table->item(row, 0));
|
table->editItem(table->item(row, 0));
|
||||||
@@ -856,6 +876,7 @@ private:
|
|||||||
for (int row = 0; row < table->rowCount(); ++row) {
|
for (int row = 0; row < table->rowCount(); ++row) {
|
||||||
QString title = table->item(row, 0) ? table->item(row, 0)->text().trimmed() : QString();
|
QString title = table->item(row, 0) ? table->item(row, 0)->text().trimmed() : QString();
|
||||||
QString url = table->item(row, 1) ? table->item(row, 1)->text().trimmed() : QString();
|
QString url = table->item(row, 1) ? table->item(row, 1)->text().trimmed() : QString();
|
||||||
|
auto *zoom = qobject_cast<QSpinBox *>(table->cellWidget(row, 2));
|
||||||
if (title.isEmpty() || url.isEmpty()) {
|
if (title.isEmpty() || url.isEmpty()) {
|
||||||
QMessageBox::warning(&dialog, text("CustomBrowserDocks"), text("PanelFieldsRequired"));
|
QMessageBox::warning(&dialog, text("CustomBrowserDocks"), text("PanelFieldsRequired"));
|
||||||
return;
|
return;
|
||||||
@@ -868,7 +889,7 @@ private:
|
|||||||
QString id = table->item(row, 0)->data(Qt::UserRole).toString();
|
QString id = table->item(row, 0)->data(Qt::UserRole).toString();
|
||||||
if (id.isEmpty())
|
if (id.isEmpty())
|
||||||
id = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
id = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||||
updated.push_back({id, title, url});
|
updated.push_back({id, title, url, zoom ? zoom->value() : 100});
|
||||||
}
|
}
|
||||||
definitions_ = std::move(updated);
|
definitions_ = std::move(updated);
|
||||||
reconcile();
|
reconcile();
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ struct browser_source {
|
|||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
uint32_t fps;
|
uint32_t fps;
|
||||||
|
uint32_t zoom_percent;
|
||||||
bool transparent;
|
bool transparent;
|
||||||
bool shutdown_when_hidden;
|
bool shutdown_when_hidden;
|
||||||
bool visible;
|
bool visible;
|
||||||
@@ -255,6 +256,7 @@ static bool send_initial_config(struct browser_source *browser, struct renderer_
|
|||||||
.width = browser->width,
|
.width = browser->width,
|
||||||
.height = browser->height,
|
.height = browser->height,
|
||||||
.fps = browser->fps,
|
.fps = browser->fps,
|
||||||
|
.zoom_percent = browser->zoom_percent,
|
||||||
.transparent = browser->transparent,
|
.transparent = browser->transparent,
|
||||||
.hardware_acceleration = true,
|
.hardware_acceleration = true,
|
||||||
.url_length = (uint32_t)url_length,
|
.url_length = (uint32_t)url_length,
|
||||||
@@ -434,6 +436,7 @@ static void browser_update(void *data, obs_data_t *settings)
|
|||||||
browser->width = setting_u32(settings, "width", 2, 8192);
|
browser->width = setting_u32(settings, "width", 2, 8192);
|
||||||
browser->height = setting_u32(settings, "height", 2, 8192);
|
browser->height = setting_u32(settings, "height", 2, 8192);
|
||||||
browser->fps = setting_u32(settings, "fps", 1, 60);
|
browser->fps = setting_u32(settings, "fps", 1, 60);
|
||||||
|
browser->zoom_percent = setting_u32(settings, "zoom", 25, 500);
|
||||||
browser->transparent = obs_data_get_bool(settings, "transparent");
|
browser->transparent = obs_data_get_bool(settings, "transparent");
|
||||||
browser->shutdown_when_hidden = obs_data_get_bool(settings, "shutdown_when_hidden");
|
browser->shutdown_when_hidden = obs_data_get_bool(settings, "shutdown_when_hidden");
|
||||||
stop_renderer_locked(browser);
|
stop_renderer_locked(browser);
|
||||||
@@ -479,6 +482,7 @@ static void browser_defaults(obs_data_t *settings)
|
|||||||
obs_data_set_default_int(settings, "width", 1280);
|
obs_data_set_default_int(settings, "width", 1280);
|
||||||
obs_data_set_default_int(settings, "height", 720);
|
obs_data_set_default_int(settings, "height", 720);
|
||||||
obs_data_set_default_int(settings, "fps", 30);
|
obs_data_set_default_int(settings, "fps", 30);
|
||||||
|
obs_data_set_default_int(settings, "zoom", 100);
|
||||||
obs_data_set_default_bool(settings, "transparent", true);
|
obs_data_set_default_bool(settings, "transparent", true);
|
||||||
obs_data_set_default_bool(settings, "shutdown_when_hidden", false);
|
obs_data_set_default_bool(settings, "shutdown_when_hidden", false);
|
||||||
}
|
}
|
||||||
@@ -498,6 +502,7 @@ static obs_properties_t *browser_properties(void *data)
|
|||||||
obs_properties_add_int(props, "width", obs_module_text("Width"), 2, 8192, 1);
|
obs_properties_add_int(props, "width", obs_module_text("Width"), 2, 8192, 1);
|
||||||
obs_properties_add_int(props, "height", obs_module_text("Height"), 2, 8192, 1);
|
obs_properties_add_int(props, "height", obs_module_text("Height"), 2, 8192, 1);
|
||||||
obs_properties_add_int(props, "fps", obs_module_text("FPS"), 1, 60, 1);
|
obs_properties_add_int(props, "fps", obs_module_text("FPS"), 1, 60, 1);
|
||||||
|
obs_properties_add_int_slider(props, "zoom", obs_module_text("PageZoom"), 25, 500, 5);
|
||||||
obs_properties_add_bool(props, "transparent", obs_module_text("Transparent"));
|
obs_properties_add_bool(props, "transparent", obs_module_text("Transparent"));
|
||||||
obs_properties_add_text(props, "css", obs_module_text("CustomCSS"), OBS_TEXT_MULTILINE);
|
obs_properties_add_text(props, "css", obs_module_text("CustomCSS"), OBS_TEXT_MULTILINE);
|
||||||
obs_properties_add_bool(props, "shutdown_when_hidden", obs_module_text("ShutdownWhenHidden"));
|
obs_properties_add_bool(props, "shutdown_when_hidden", obs_module_text("ShutdownWhenHidden"));
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#define OWB_CONFIG_MAGIC 0x4f574243u /* OWBC */
|
#define OWB_CONFIG_MAGIC 0x4f574243u /* OWBC */
|
||||||
#define OWB_COMMAND_MAGIC 0x4f574245u /* OWBE */
|
#define OWB_COMMAND_MAGIC 0x4f574245u /* OWBE */
|
||||||
#define OWB_PROTOCOL_VERSION 2u
|
#define OWB_PROTOCOL_VERSION 3u
|
||||||
#define OWB_MAX_STRING (16u * 1024u * 1024u)
|
#define OWB_MAX_STRING (16u * 1024u * 1024u)
|
||||||
#define OWB_SHARED_MAGIC 0x4f574246u /* OWBF */
|
#define OWB_SHARED_MAGIC 0x4f574246u /* OWBF */
|
||||||
#define OWB_SHARED_FRAME_FD 198
|
#define OWB_SHARED_FRAME_FD 198
|
||||||
@@ -17,6 +17,7 @@ struct owb_config_header {
|
|||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
uint32_t fps;
|
uint32_t fps;
|
||||||
|
uint32_t zoom_percent;
|
||||||
uint32_t transparent;
|
uint32_t transparent;
|
||||||
uint32_t hardware_acceleration;
|
uint32_t hardware_acceleration;
|
||||||
uint32_t url_length;
|
uint32_t url_length;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ struct config {
|
|||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
uint32_t fps;
|
uint32_t fps;
|
||||||
|
uint32_t zoom_percent;
|
||||||
bool transparent;
|
bool transparent;
|
||||||
char *url;
|
char *url;
|
||||||
char *css;
|
char *css;
|
||||||
@@ -107,13 +108,15 @@ static bool read_config(int fd, struct config *config)
|
|||||||
if (!read_exact(fd, &header, sizeof(header)) || header.magic != OWB_CONFIG_MAGIC ||
|
if (!read_exact(fd, &header, sizeof(header)) || header.magic != OWB_CONFIG_MAGIC ||
|
||||||
header.version != OWB_PROTOCOL_VERSION || header.width < 2 || header.height < 2 ||
|
header.version != OWB_PROTOCOL_VERSION || header.width < 2 || header.height < 2 ||
|
||||||
header.width > 8192 || header.height > 8192 || header.fps < 1 || header.fps > 60 ||
|
header.width > 8192 || header.height > 8192 || header.fps < 1 || header.fps > 60 ||
|
||||||
|
header.zoom_percent < 25 || header.zoom_percent > 500 ||
|
||||||
header.url_length > OWB_MAX_STRING || header.css_length > OWB_MAX_STRING)
|
header.url_length > OWB_MAX_STRING || header.css_length > OWB_MAX_STRING)
|
||||||
return false;
|
return false;
|
||||||
config->width = header.width;
|
config->width = header.width;
|
||||||
config->height = header.height;
|
config->height = header.height;
|
||||||
config->fps = header.fps;
|
config->fps = header.fps;
|
||||||
|
config->zoom_percent = header.zoom_percent;
|
||||||
config->transparent = header.transparent != 0;
|
config->transparent = header.transparent != 0;
|
||||||
/* Protocol v2 retains this legacy flag, but this renderer always enables the
|
/* The protocol retains this legacy flag, but this renderer always enables the
|
||||||
* WebKit compositor. */
|
* WebKit compositor. */
|
||||||
(void)header.hardware_acceleration;
|
(void)header.hardware_acceleration;
|
||||||
config->url = calloc((size_t)header.url_length + 1, 1);
|
config->url = calloc((size_t)header.url_length + 1, 1);
|
||||||
@@ -709,6 +712,8 @@ static struct renderer *create_renderer(int client_fd, const int descriptors[4])
|
|||||||
webkit_settings_set_media_playback_requires_user_gesture(settings, FALSE);
|
webkit_settings_set_media_playback_requires_user_gesture(settings, FALSE);
|
||||||
webkit_settings_set_hardware_acceleration_policy(settings,
|
webkit_settings_set_hardware_acceleration_policy(settings,
|
||||||
WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS);
|
WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS);
|
||||||
|
webkit_web_view_set_zoom_level(renderer->web_view,
|
||||||
|
(double)renderer->config.zoom_percent / 100.0);
|
||||||
webkit_web_view_set_is_muted(renderer->web_view, TRUE);
|
webkit_web_view_set_is_muted(renderer->web_view, TRUE);
|
||||||
GdkRGBA background = renderer->config.transparent ? (GdkRGBA){0, 0, 0, 0} : (GdkRGBA){1, 1, 1, 1};
|
GdkRGBA background = renderer->config.transparent ? (GdkRGBA){0, 0, 0, 0} : (GdkRGBA){1, 1, 1, 1};
|
||||||
webkit_web_view_set_background_color(renderer->web_view, &background);
|
webkit_web_view_set_background_color(renderer->web_view, &background);
|
||||||
@@ -776,10 +781,10 @@ static struct renderer *create_renderer(int client_fd, const int descriptors[4])
|
|||||||
g_source_remove(idle_source);
|
g_source_remove(idle_source);
|
||||||
idle_source = 0;
|
idle_source = 0;
|
||||||
}
|
}
|
||||||
renderer_log(renderer, "Ready: WebKitGTK %u.%u.%u, %ux%u@%u, shared profile, GPU DMA-BUF, XComposite/XShm capture\n",
|
renderer_log(renderer, "Ready: WebKitGTK %u.%u.%u, %ux%u@%u, zoom %u%%, shared profile, GPU DMA-BUF, XComposite/XShm capture\n",
|
||||||
webkit_get_major_version(),
|
webkit_get_major_version(),
|
||||||
webkit_get_minor_version(), webkit_get_micro_version(), renderer->config.width,
|
webkit_get_minor_version(), webkit_get_micro_version(), renderer->config.width,
|
||||||
renderer->config.height, renderer->config.fps);
|
renderer->config.height, renderer->config.fps, renderer->config.zoom_percent);
|
||||||
return renderer;
|
return renderer;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ int main(int argc, char **argv)
|
|||||||
obs_data_set_int(settings, "width", 64);
|
obs_data_set_int(settings, "width", 64);
|
||||||
obs_data_set_int(settings, "height", 64);
|
obs_data_set_int(settings, "height", 64);
|
||||||
obs_data_set_int(settings, "fps", 10);
|
obs_data_set_int(settings, "fps", 10);
|
||||||
|
obs_data_set_int(settings, "zoom", 175);
|
||||||
obs_data_set_bool(settings, "transparent", true);
|
obs_data_set_bool(settings, "transparent", true);
|
||||||
obs_data_set_bool(settings, "hardware_acceleration", false);
|
obs_data_set_bool(settings, "hardware_acceleration", false);
|
||||||
obs_source_t *source = obs_source_create_private("webkit_browser_source", "smoke", settings);
|
obs_source_t *source = obs_source_create_private("webkit_browser_source", "smoke", settings);
|
||||||
@@ -61,6 +62,16 @@ int main(int argc, char **argv)
|
|||||||
fprintf(stderr, "source lifecycle setup failed\n");
|
fprintf(stderr, "source lifecycle setup failed\n");
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
|
obs_properties_t *properties = source ? obs_source_properties(source) : NULL;
|
||||||
|
obs_property_t *zoom = properties ? obs_properties_get(properties, "zoom") : NULL;
|
||||||
|
if (!zoom || obs_property_get_type(zoom) != OBS_PROPERTY_INT ||
|
||||||
|
obs_property_int_type(zoom) != OBS_NUMBER_SLIDER || obs_property_int_min(zoom) != 25 ||
|
||||||
|
obs_property_int_max(zoom) != 500 || obs_property_int_step(zoom) != 5) {
|
||||||
|
fprintf(stderr, "page zoom property is missing or invalid\n");
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
if (properties)
|
||||||
|
obs_properties_destroy(properties);
|
||||||
if (source) {
|
if (source) {
|
||||||
usleep(500000);
|
usleep(500000);
|
||||||
obs_source_release(source);
|
obs_source_release(source);
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
assert(sizeof(struct owb_config_header) == 36);
|
assert(sizeof(struct owb_config_header) == 40);
|
||||||
|
assert(offsetof(struct owb_config_header, zoom_percent) == 20);
|
||||||
assert(sizeof(struct owb_command) == 100);
|
assert(sizeof(struct owb_command) == 100);
|
||||||
assert(offsetof(struct owb_shared_frames, pixels) == 40);
|
assert(offsetof(struct owb_shared_frames, pixels) == 40);
|
||||||
assert(owb_shared_size(2, 2) == 72);
|
assert(owb_shared_size(2, 2) == 72);
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ int main(int argc, char **argv)
|
|||||||
struct owb_config_header config = {
|
struct owb_config_header config = {
|
||||||
.magic = OWB_CONFIG_MAGIC, .version = OWB_PROTOCOL_VERSION,
|
.magic = OWB_CONFIG_MAGIC, .version = OWB_PROTOCOL_VERSION,
|
||||||
.width = width, .height = height, .fps = requested_fps, .transparent = 1,
|
.width = width, .height = height, .fps = requested_fps, .transparent = 1,
|
||||||
|
.zoom_percent = 100,
|
||||||
.hardware_acceleration = 1,
|
.hardware_acceleration = 1,
|
||||||
.url_length = sizeof(url) - 1, .css_length = (uint32_t)css_length,
|
.url_length = sizeof(url) - 1, .css_length = (uint32_t)css_length,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,12 +56,13 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
if (argc < 2 || argc > 4) {
|
if (argc < 2 || argc > 4) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"usage: %s /path/to/obs-webkit-renderer [opaque | opaque-url URL]\n",
|
"usage: %s /path/to/obs-webkit-renderer [opaque | zoom | opaque-url URL]\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
bool external_url = argc == 4 && strcmp(argv[2], "opaque-url") == 0;
|
bool external_url = argc == 4 && strcmp(argv[2], "opaque-url") == 0;
|
||||||
bool opaque = external_url || (argc == 3 && strcmp(argv[2], "opaque") == 0);
|
bool zoom = argc == 3 && strcmp(argv[2], "zoom") == 0;
|
||||||
|
bool opaque = external_url || zoom || (argc == 3 && strcmp(argv[2], "opaque") == 0);
|
||||||
int control[2];
|
int control[2];
|
||||||
int frames[2];
|
int frames[2];
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, control) || pipe(frames)) {
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, control) || pipe(frames)) {
|
||||||
@@ -108,14 +109,18 @@ int main(int argc, char **argv)
|
|||||||
const char opaque_css[] = "html,body{margin:0;background:rgb(7,19,31)!important}"
|
const char opaque_css[] = "html,body{margin:0;background:rgb(7,19,31)!important}"
|
||||||
"#box{position:fixed;left:16px;top:16px;width:32px;height:32px;"
|
"#box{position:fixed;left:16px;top:16px;width:32px;height:32px;"
|
||||||
"background:rgb(241,23,17);transform:translateZ(0);filter:blur(.1px)}";
|
"background:rgb(241,23,17);transform:translateZ(0);filter:blur(.1px)}";
|
||||||
|
const char zoom_css[] = "html,body{margin:0;background:rgb(7,19,31)!important}"
|
||||||
|
"#box{position:fixed;left:0;top:0;width:10px;height:10px;"
|
||||||
|
"background:rgb(241,23,17)}";
|
||||||
const char *url = external_url ? argv[3] : internal_url;
|
const char *url = external_url ? argv[3] : internal_url;
|
||||||
const char *css = external_url ? "" : opaque ? opaque_css : transparent_css;
|
const char *css = external_url ? "" : zoom ? zoom_css : opaque ? opaque_css : transparent_css;
|
||||||
struct owb_config_header config = {
|
struct owb_config_header config = {
|
||||||
.magic = OWB_CONFIG_MAGIC,
|
.magic = OWB_CONFIG_MAGIC,
|
||||||
.version = OWB_PROTOCOL_VERSION,
|
.version = OWB_PROTOCOL_VERSION,
|
||||||
.width = width,
|
.width = width,
|
||||||
.height = height,
|
.height = height,
|
||||||
.fps = 10,
|
.fps = 10,
|
||||||
|
.zoom_percent = zoom ? 200 : 100,
|
||||||
.transparent = opaque ? 0 : 1,
|
.transparent = opaque ? 0 : 1,
|
||||||
/* GPU rendering must still produce an invisible captured frame. */
|
/* GPU rendering must still produce an invisible captured frame. */
|
||||||
.hardware_acceleration = 1,
|
.hardware_acceleration = 1,
|
||||||
@@ -158,10 +163,17 @@ int main(int argc, char **argv)
|
|||||||
nonuniform ? "content" : "uniform");
|
nonuniform ? "content" : "uniform");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
size_t center = ((size_t)(height / 2) * width + width / 2) * 4;
|
size_t center = zoom ? ((size_t)5 * width + 15) * 4
|
||||||
|
: ((size_t)(height / 2) * width + width / 2) * 4;
|
||||||
memcpy(last_bgra, frame + center, sizeof(last_bgra));
|
memcpy(last_bgra, frame + center, sizeof(last_bgra));
|
||||||
memcpy(last_corner_bgra, frame, sizeof(last_corner_bgra));
|
size_t corner = zoom ? ((size_t)5 * width + 25) * 4 : 0;
|
||||||
bool expected = opaque
|
memcpy(last_corner_bgra, frame + corner, sizeof(last_corner_bgra));
|
||||||
|
bool expected = zoom
|
||||||
|
? last_bgra[0] < 32 && last_bgra[1] < 40 && last_bgra[2] > 210 &&
|
||||||
|
last_bgra[3] == 255 && last_corner_bgra[0] > 20 &&
|
||||||
|
last_corner_bgra[1] < 32 && last_corner_bgra[2] < 32 &&
|
||||||
|
last_corner_bgra[3] == 255
|
||||||
|
: opaque
|
||||||
? last_bgra[0] < 32 && last_bgra[1] < 40 && last_bgra[2] > 210 &&
|
? last_bgra[0] < 32 && last_bgra[1] < 40 && last_bgra[2] > 210 &&
|
||||||
last_bgra[3] == 255
|
last_bgra[3] == 255
|
||||||
: last_bgra[0] < 8 && last_bgra[1] < 8 && last_bgra[2] > 248 &&
|
: last_bgra[0] < 8 && last_bgra[1] < 8 && last_bgra[2] > 248 &&
|
||||||
@@ -192,7 +204,8 @@ int main(int argc, char **argv)
|
|||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"renderer did not produce the expected %s red BGRA frame "
|
"renderer did not produce the expected %s red BGRA frame "
|
||||||
"(center BGRA=%u,%u,%u,%u; corner BGRA=%u,%u,%u,%u)\n",
|
"(center BGRA=%u,%u,%u,%u; corner BGRA=%u,%u,%u,%u)\n",
|
||||||
opaque ? "opaque" : "transparent", last_bgra[0], last_bgra[1],
|
zoom ? "200%-zoomed" : opaque ? "opaque" : "transparent",
|
||||||
|
last_bgra[0], last_bgra[1],
|
||||||
last_bgra[2], last_bgra[3], last_corner_bgra[0], last_corner_bgra[1],
|
last_bgra[2], last_bgra[3], last_corner_bgra[0], last_corner_bgra[1],
|
||||||
last_corner_bgra[2], last_corner_bgra[3]);
|
last_corner_bgra[2], last_corner_bgra[3]);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ static bool start_view(struct view *view, const char *renderer, const char *url)
|
|||||||
struct owb_config_header config = {
|
struct owb_config_header config = {
|
||||||
.magic = OWB_CONFIG_MAGIC, .version = OWB_PROTOCOL_VERSION,
|
.magic = OWB_CONFIG_MAGIC, .version = OWB_PROTOCOL_VERSION,
|
||||||
.width = width, .height = height, .fps = 20, .transparent = 0,
|
.width = width, .height = height, .fps = 20, .transparent = 0,
|
||||||
|
.zoom_percent = 100,
|
||||||
.hardware_acceleration = 1, .url_length = (uint32_t)strlen(url), .css_length = 0,
|
.hardware_acceleration = 1, .url_length = (uint32_t)strlen(url), .css_length = 0,
|
||||||
};
|
};
|
||||||
return write_all(view->control, &config, sizeof(config)) &&
|
return write_all(view->control, &config, sizeof(config)) &&
|
||||||
|
|||||||
Reference in New Issue
Block a user