generated from obsproject/obs-plugintemplate
-
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
443 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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]", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.