Skip to content

Commit

Permalink
add image grab (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
royshil committed Nov 17, 2023
1 parent 6ae490d commit 4bd32a0
Show file tree
Hide file tree
Showing 8 changed files with 443 additions and 162 deletions.
11 changes: 9 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,15 @@ target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE liblexbor_internal)

target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE vendor/nlohmann-json)

target_sources(${CMAKE_PROJECT_NAME} PRIVATE src/plugin-main.c src/url-source.cpp src/ui/RequestBuilder.cpp
src/request-data.cpp src/ui/text-render-helper.cpp src/url-source-info.c)
target_sources(
${CMAKE_PROJECT_NAME}
PRIVATE src/plugin-main.c
src/url-source.cpp
src/ui/RequestBuilder.cpp
src/request-data.cpp
src/ui/text-render-helper.cpp
src/url-source-info.c
src/obs-source-util.cpp)
add_subdirectory(src/parsers)

set_target_properties_plugin(${CMAKE_PROJECT_NAME} PROPERTIES OUTPUT_NAME ${_name})
2 changes: 1 addition & 1 deletion buildspec.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
}
},
"name": "obs-urlsource",
"version": "0.2.1",
"version": "0.2.3",
"author": "Roy Shilkrot",
"website": "https://github.com/royshil/obs-urlsource",
"email": "[email protected]",
Expand Down
130 changes: 130 additions & 0 deletions src/obs-source-util.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@

#include "obs-source-util.h"
#include "plugin-support.h"

#include <obs-module.h>

#include <QBuffer>
#include <QImage>

#include <nlohmann/json.hpp>

void init_source_render_data(source_render_data *tf)
{
tf->texrender = gs_texrender_create(GS_BGRA, GS_ZS_NONE);
tf->stagesurface = nullptr;
}

void destroy_source_render_data(source_render_data *tf)
{
if (tf->texrender) {
gs_texrender_destroy(tf->texrender);
tf->texrender = nullptr;
}
if (tf->stagesurface) {
gs_stagesurface_destroy(tf->stagesurface);
tf->stagesurface = nullptr;
}
}

/**
* @brief Get RGBA from the stage surface
*
* @param tf The filter data
* @param width The width of the stage surface (output)
* @param height The height of the stage surface (output)
* @return true if successful
* @return false if unsuccessful
*/
std::vector<uint8_t> get_rgba_from_source_render(obs_source_t *source, source_render_data *tf,
uint32_t &width, uint32_t &height)
{
if (!obs_source_enabled(source)) {
obs_log(LOG_ERROR, "Source is not enabled");
return std::vector<uint8_t>();
}

width = obs_source_get_base_width(source);
height = obs_source_get_base_height(source);
if (width == 0 || height == 0) {
obs_log(LOG_ERROR, "Width or height is 0");
return std::vector<uint8_t>();
}

// enter graphics context
obs_enter_graphics();

gs_texrender_reset(tf->texrender);
if (!gs_texrender_begin(tf->texrender, width, height)) {
obs_log(LOG_ERROR, "Could not begin texrender");
return std::vector<uint8_t>();
}
struct vec4 background;
vec4_zero(&background);
gs_clear(GS_CLEAR_COLOR, &background, 0.0f, 0);
gs_ortho(0.0f, static_cast<float>(width), 0.0f, static_cast<float>(height), -100.0f,
100.0f);
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);
obs_source_video_render(source);
gs_blend_state_pop();
gs_texrender_end(tf->texrender);

if (tf->stagesurface) {
uint32_t stagesurf_width = gs_stagesurface_get_width(tf->stagesurface);
uint32_t stagesurf_height = gs_stagesurface_get_height(tf->stagesurface);
if (stagesurf_width != width || stagesurf_height != height) {
gs_stagesurface_destroy(tf->stagesurface);
tf->stagesurface = nullptr;
}
}
if (!tf->stagesurface) {
tf->stagesurface = gs_stagesurface_create(width, height, GS_BGRA);
}
gs_stage_texture(tf->stagesurface, gs_texrender_get_texture(tf->texrender));
uint8_t *video_data;
uint32_t linesize;
if (!gs_stagesurface_map(tf->stagesurface, &video_data, &linesize)) {
obs_log(LOG_ERROR, "Cannot map stage surface");
return std::vector<uint8_t>();
}
obs_log(LOG_INFO, "linesize: %d, width: %d, height: %d", linesize, width, height);
if (linesize != width * 4) {
obs_log(LOG_WARNING, "linesize %d != width %d * 4", linesize, width);
}
std::vector<uint8_t> rgba(width * height * 4);
for (uint32_t i = 0; i < height; i++) {
memcpy(rgba.data() + i * width * 4, video_data + i * linesize, width * 4);
}

gs_stagesurface_unmap(tf->stagesurface);

// leave graphics context
obs_leave_graphics();

return rgba;
}

std::string convert_rgba_buffer_to_png_base64(const std::vector<uint8_t> &rgba, uint32_t width,
uint32_t height)
{
// use Qt to convert the RGBA buffer to an encoded image buffer
QImage image(rgba.data(), width, height, QImage::Format_RGBA8888);
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "PNG");
buffer.close();

// convert the encoded image buffer to a base64 string
QByteArray base64 = ba.toBase64();
std::string base64_str = base64.toStdString();

// json string escape
nlohmann::json j(base64_str);
std::string escaped = j.dump();
// remove the quotes
escaped = escaped.substr(1, escaped.size() - 2);

return escaped;
}
38 changes: 38 additions & 0 deletions src/obs-source-util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef OBS_SOURCE_UTIL_H
#define OBS_SOURCE_UTIL_H

#include <obs.h>

#include <string>
#include <vector>

inline bool is_obs_source_text(obs_source_t *source)
{
const auto source_id = obs_source_get_id(source);
return strcmp(source_id, "text_ft2_source_v2") == 0 ||
strcmp(source_id, "text_gdiplus_v2") == 0;
}

inline bool is_obs_source_text(const std::string &source_name)
{
obs_source_t *source = obs_get_source_by_name(source_name.c_str());
const bool is_text = is_obs_source_text(source);
obs_source_release(source);
return is_text;
}

struct source_render_data {
gs_texrender_t *texrender;
gs_stagesurf_t *stagesurface;
};

void init_source_render_data(source_render_data *tf);
void destroy_source_render_data(source_render_data *tf);

std::vector<uint8_t> get_rgba_from_source_render(obs_source_t *source, source_render_data *tf,
uint32_t &width, uint32_t &height);

std::string convert_rgba_buffer_to_png_base64(const std::vector<uint8_t> &rgba, uint32_t width,
uint32_t height);

#endif // OBS_SOURCE_UTIL_H
Loading

0 comments on commit 4bd32a0

Please sign in to comment.