Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
83 changes: 3 additions & 80 deletions src/requesthandler/RequestHandler_Sources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,84 +25,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>

#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)
{
Expand Down Expand Up @@ -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.");
Expand Down Expand Up @@ -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.");
Expand Down
112 changes: 112 additions & 0 deletions src/utils/SourceScreenshot.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
obs-websocket
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>

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 <https://www.gnu.org/licenses/>
*/

#include <string.h>

#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;
}
29 changes: 29 additions & 0 deletions src/utils/SourceScreenshot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
obs-websocket
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>

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 <https://www.gnu.org/licenses/>
*/

#pragma once

#include <QImage>
#include <obs.h>

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);
}
Loading