diff --git a/CMakeLists.txt b/CMakeLists.txt
index 72a50f33..25b85464 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -128,6 +128,8 @@ target_sources(
src/utils/Obs_VolumeMeter_Helpers.h
src/utils/Platform.cpp
src/utils/Platform.h
+ src/utils/SourceScreenshot.cpp
+ src/utils/SourceScreenshot.h
src/utils/Utils.h)
configure_file(src/plugin-macros.h.in plugin-macros.generated.h)
diff --git a/src/requesthandler/RequestHandler_Sources.cpp b/src/requesthandler/RequestHandler_Sources.cpp
index 857a1ce9..cfc63aa6 100644
--- a/src/requesthandler/RequestHandler_Sources.cpp
+++ b/src/requesthandler/RequestHandler_Sources.cpp
@@ -25,84 +25,7 @@ with this program. If not, see
#include "RequestHandler.h"
#include "../utils/ImageFormat.h"
-
-QImage TakeSourceScreenshot(obs_source_t *source, bool &success, uint32_t requestedWidth = 0, uint32_t requestedHeight = 0)
-{
- // Get info about the requested source
- const uint32_t sourceWidth = obs_source_get_width(source);
- const uint32_t sourceHeight = obs_source_get_height(source);
- const double sourceAspectRatio = ((double)sourceWidth / (double)sourceHeight);
-
- uint32_t imgWidth = sourceWidth;
- uint32_t imgHeight = sourceHeight;
-
- // Determine suitable image width
- if (requestedWidth) {
- imgWidth = requestedWidth;
-
- if (!requestedHeight)
- imgHeight = ((double)imgWidth / sourceAspectRatio);
- }
-
- // Determine suitable image height
- if (requestedHeight) {
- imgHeight = requestedHeight;
-
- if (!requestedWidth)
- imgWidth = ((double)imgHeight * sourceAspectRatio);
- }
-
- // Create final image texture
- QImage ret(imgWidth, imgHeight, QImage::Format::Format_RGBA8888);
- ret.fill(0);
-
- // Video image buffer
- uint8_t *videoData = nullptr;
- uint32_t videoLinesize = 0;
-
- // Enter graphics context
- obs_enter_graphics();
-
- gs_texrender_t *texRender = gs_texrender_create(GS_RGBA, GS_ZS_NONE);
- gs_stagesurf_t *stageSurface = gs_stagesurface_create(imgWidth, imgHeight, GS_RGBA);
-
- success = false;
- gs_texrender_reset(texRender);
- if (gs_texrender_begin(texRender, imgWidth, imgHeight)) {
- vec4 background;
- vec4_zero(&background);
-
- gs_clear(GS_CLEAR_COLOR, &background, 0.0f, 0);
- gs_ortho(0.0f, (float)sourceWidth, 0.0f, (float)sourceHeight, -100.0f, 100.0f);
-
- gs_blend_state_push();
- gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);
-
- obs_source_inc_showing(source);
- obs_source_video_render(source);
- obs_source_dec_showing(source);
-
- gs_blend_state_pop();
- gs_texrender_end(texRender);
-
- gs_stage_texture(stageSurface, gs_texrender_get_texture(texRender));
- if (gs_stagesurface_map(stageSurface, &videoData, &videoLinesize)) {
- int lineSize = ret.bytesPerLine();
- for (uint y = 0; y < imgHeight; y++) {
- memcpy(ret.scanLine(y), videoData + (y * videoLinesize), lineSize);
- }
- gs_stagesurface_unmap(stageSurface);
- success = true;
- }
- }
-
- gs_stagesurface_destroy(stageSurface);
- gs_texrender_destroy(texRender);
-
- obs_leave_graphics();
-
- return ret;
-}
+#include "../utils/SourceScreenshot.h"
bool IsImageFormatValid(std::string format)
{
@@ -214,7 +137,7 @@ RequestResult RequestHandler::GetSourceScreenshot(const Request &request)
}
bool success;
- QImage renderedImage = TakeSourceScreenshot(source, success, requestedWidth, requestedHeight);
+ QImage renderedImage = Utils::TakeSourceScreenshot(source, success, requestedWidth, requestedHeight);
if (!success)
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Failed to render screenshot.");
@@ -309,7 +232,7 @@ RequestResult RequestHandler::SaveSourceScreenshot(const Request &request)
}
bool success;
- QImage renderedImage = TakeSourceScreenshot(source, success, requestedWidth, requestedHeight);
+ QImage renderedImage = Utils::TakeSourceScreenshot(source, success, requestedWidth, requestedHeight);
if (!success)
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Failed to render screenshot.");
diff --git a/src/utils/SourceScreenshot.cpp b/src/utils/SourceScreenshot.cpp
new file mode 100644
index 00000000..80a2cddf
--- /dev/null
+++ b/src/utils/SourceScreenshot.cpp
@@ -0,0 +1,112 @@
+/*
+obs-websocket
+Copyright (C) 2016-2021 Stephane Lepin
+Copyright (C) 2020-2021 Kyle Manning
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see
+*/
+
+#include
+
+#include "SourceScreenshot.h"
+
+QImage Utils::TakeSourceScreenshot(obs_source_t *source, bool &success, uint32_t requestedWidth, uint32_t requestedHeight)
+{
+ // Get info about the requested source
+ const uint32_t sourceWidth = obs_source_get_width(source);
+ const uint32_t sourceHeight = obs_source_get_height(source);
+ const double sourceAspectRatio = ((double)sourceWidth / (double)sourceHeight);
+
+ uint32_t imgWidth = sourceWidth;
+ uint32_t imgHeight = sourceHeight;
+
+ // Determine suitable image width
+ if (requestedWidth) {
+ imgWidth = requestedWidth;
+
+ if (!requestedHeight)
+ imgHeight = ((double)imgWidth / sourceAspectRatio);
+ }
+
+ // Determine suitable image height
+ if (requestedHeight) {
+ imgHeight = requestedHeight;
+
+ if (!requestedWidth)
+ imgWidth = ((double)imgHeight * sourceAspectRatio);
+ }
+
+ // Create final image texture
+ QImage ret(imgWidth, imgHeight, QImage::Format::Format_RGBA8888);
+ ret.fill(0);
+
+ // Video image buffer
+ uint8_t *videoData = nullptr;
+ uint32_t videoLinesize = 0;
+
+ // Enter graphics context
+ obs_enter_graphics();
+
+ gs_texrender_t *texRender = gs_texrender_create(GS_RGBA, GS_ZS_NONE);
+ gs_stagesurf_t *stageSurface = gs_stagesurface_create(imgWidth, imgHeight, GS_RGBA);
+
+ success = false;
+ gs_texrender_reset(texRender);
+ if (gs_texrender_begin(texRender, imgWidth, imgHeight)) {
+ vec4 background;
+ vec4_zero(&background);
+
+ gs_clear(GS_CLEAR_COLOR, &background, 0.0f, 0);
+ gs_ortho(0.0f, (float)sourceWidth, 0.0f, (float)sourceHeight, -100.0f, 100.0f);
+
+ gs_blend_state_push();
+ gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);
+
+ // libobs keeps high-bit-depth sources (P010, I010, I210, I412: HEVC Main10, ProRes, 10-bit
+ // capture cards) as linear float. Scenes and the frontend previews draw with linear sRGB
+ // on, which encodes them to sRGB in an 8-bit target; without it the screenshot is stored
+ // linear and comes out too dark. 8-bit sRGB sources keep the direct path, so their pixels
+ // and straight alpha stay as they were.
+ const enum gs_color_space preferredSpaces[] = {GS_CS_SRGB, GS_CS_SRGB_16F, GS_CS_709_EXTENDED};
+ const enum gs_color_space sourceSpace =
+ obs_source_get_color_space(source, OBS_COUNTOF(preferredSpaces), preferredSpaces);
+ const bool previousLinearSrgb = gs_set_linear_srgb(sourceSpace != GS_CS_SRGB);
+
+ obs_source_inc_showing(source);
+ obs_source_video_render(source);
+ obs_source_dec_showing(source);
+
+ gs_set_linear_srgb(previousLinearSrgb);
+
+ gs_blend_state_pop();
+ gs_texrender_end(texRender);
+
+ gs_stage_texture(stageSurface, gs_texrender_get_texture(texRender));
+ if (gs_stagesurface_map(stageSurface, &videoData, &videoLinesize)) {
+ int lineSize = ret.bytesPerLine();
+ for (uint y = 0; y < imgHeight; y++) {
+ memcpy(ret.scanLine(y), videoData + (y * videoLinesize), lineSize);
+ }
+ gs_stagesurface_unmap(stageSurface);
+ success = true;
+ }
+ }
+
+ gs_stagesurface_destroy(stageSurface);
+ gs_texrender_destroy(texRender);
+
+ obs_leave_graphics();
+
+ return ret;
+}
diff --git a/src/utils/SourceScreenshot.h b/src/utils/SourceScreenshot.h
new file mode 100644
index 00000000..a275bb95
--- /dev/null
+++ b/src/utils/SourceScreenshot.h
@@ -0,0 +1,29 @@
+/*
+obs-websocket
+Copyright (C) 2016-2021 Stephane Lepin
+Copyright (C) 2020-2021 Kyle Manning
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see
+*/
+
+#pragma once
+
+#include
+#include
+
+namespace Utils {
+ // Renders the source on its own into an 8-bit RGBA image of the requested size (0: the
+ // source's own width or height, keeping its aspect ratio). Enters the graphics context.
+ QImage TakeSourceScreenshot(obs_source_t *source, bool &success, uint32_t requestedWidth = 0, uint32_t requestedHeight = 0);
+}