Merge pull request #6436 from jpark37/jxr-wic
libobs,image-source,UI: Add JXR support on Windows
This commit is contained in:
commit
f2ea473373
@ -17,8 +17,11 @@ using namespace std;
|
||||
|
||||
static const char *textExtensions[] = {"txt", "log", nullptr};
|
||||
|
||||
static const char *imageExtensions[] = {"bmp", "tga", "png", "jpg",
|
||||
"jpeg", "gif", "webp", nullptr};
|
||||
static const char *imageExtensions[] = {"bmp", "gif", "jpeg", "jpg",
|
||||
#ifdef _WIN32
|
||||
"jxr",
|
||||
#endif
|
||||
"png", "tga", "webp", nullptr};
|
||||
|
||||
static const char *htmlExtensions[] = {"htm", "html", nullptr};
|
||||
|
||||
|
@ -1,12 +1,20 @@
|
||||
#include "graphics.h"
|
||||
|
||||
#include "half.h"
|
||||
#include "srgb.h"
|
||||
#include <obs-ffmpeg-compat.h>
|
||||
#include <util/dstr.h>
|
||||
#include <util/platform.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
#include "../obs-ffmpeg-compat.h"
|
||||
#include "srgb.h"
|
||||
#ifdef _WIN32
|
||||
#include <wincodec.h>
|
||||
#pragma comment(lib, "windowscodecs.lib")
|
||||
#endif
|
||||
|
||||
struct ffmpeg_image {
|
||||
const char *file;
|
||||
@ -644,10 +652,230 @@ uint8_t *gs_create_texture_file_data(const char *file,
|
||||
return data;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static float pq_to_linear(float u)
|
||||
{
|
||||
const float common = powf(u, 1.f / 78.84375f);
|
||||
return powf(fabsf(max(common - 0.8359375f, 0.f) /
|
||||
(18.8515625f - 18.6875f * common)),
|
||||
1.f / 0.1593017578f);
|
||||
}
|
||||
|
||||
static void convert_pq_to_cccs(const BYTE *intermediate,
|
||||
const UINT intermediate_size, BYTE *bytes)
|
||||
{
|
||||
const BYTE *src_cursor = intermediate;
|
||||
const BYTE *src_cursor_end = src_cursor + intermediate_size;
|
||||
BYTE *dst_cursor = bytes;
|
||||
uint32_t rgb10;
|
||||
struct half rgba16[4];
|
||||
rgba16[3].u = 0x3c00;
|
||||
while (src_cursor < src_cursor_end) {
|
||||
memcpy(&rgb10, src_cursor, sizeof(rgb10));
|
||||
const float blue = (float)(rgb10 & 0x3ff) / 1023.f;
|
||||
const float green = (float)((rgb10 >> 10) & 0x3ff) / 1023.f;
|
||||
const float red = (float)((rgb10 >> 20) & 0x3ff) / 1023.f;
|
||||
const float red2020 = pq_to_linear(red);
|
||||
const float green2020 = pq_to_linear(green);
|
||||
const float blue2020 = pq_to_linear(blue);
|
||||
const float red709 = 1.6604910f * red2020 -
|
||||
0.5876411f * green2020 -
|
||||
0.0728499f * blue2020;
|
||||
const float green709 = -0.1245505f * red2020 +
|
||||
1.1328999f * green2020 -
|
||||
0.0083494f * blue2020;
|
||||
const float blue709 = -0.0181508f * red2020 -
|
||||
0.1005789f * green2020 +
|
||||
1.1187297f * blue2020;
|
||||
rgba16[0] = half_from_float(red709 * 125.f);
|
||||
rgba16[1] = half_from_float(green709 * 125.f);
|
||||
rgba16[2] = half_from_float(blue709 * 125.f);
|
||||
memcpy(dst_cursor, &rgba16, sizeof(rgba16));
|
||||
src_cursor += 4;
|
||||
dst_cursor += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void *wic_image_init_internal(const char *file,
|
||||
IWICBitmapFrameDecode *pFrame,
|
||||
enum gs_color_format *format,
|
||||
uint32_t *cx_out, uint32_t *cy_out,
|
||||
enum gs_color_space *space)
|
||||
{
|
||||
BYTE *bytes = NULL;
|
||||
|
||||
WICPixelFormatGUID pixelFormat;
|
||||
HRESULT hr = pFrame->lpVtbl->GetPixelFormat(pFrame, &pixelFormat);
|
||||
if (SUCCEEDED(hr)) {
|
||||
const bool scrgb = memcmp(&pixelFormat,
|
||||
&GUID_WICPixelFormat64bppRGBAHalf,
|
||||
sizeof(pixelFormat)) == 0;
|
||||
const bool pq10 = memcmp(&pixelFormat,
|
||||
&GUID_WICPixelFormat32bppBGR101010,
|
||||
sizeof(pixelFormat)) == 0;
|
||||
if (scrgb || pq10) {
|
||||
UINT width, height;
|
||||
hr = pFrame->lpVtbl->GetSize(pFrame, &width, &height);
|
||||
if (SUCCEEDED(hr)) {
|
||||
const UINT pitch = 8 * width;
|
||||
const UINT size = pitch * height;
|
||||
bytes = bmalloc(size);
|
||||
if (bytes) {
|
||||
bool success = false;
|
||||
if (pq10) {
|
||||
const UINT intermediate_pitch =
|
||||
4 * width;
|
||||
const UINT intermediate_size =
|
||||
intermediate_pitch *
|
||||
height;
|
||||
BYTE *intermediate = bmalloc(
|
||||
intermediate_size);
|
||||
if (intermediate) {
|
||||
hr = pFrame->lpVtbl->CopyPixels(
|
||||
pFrame, NULL,
|
||||
intermediate_pitch,
|
||||
intermediate_size,
|
||||
intermediate);
|
||||
success = SUCCEEDED(hr);
|
||||
if (success) {
|
||||
convert_pq_to_cccs(
|
||||
intermediate,
|
||||
intermediate_size,
|
||||
bytes);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"WIC: Failed to CopyPixels intermediate for file: %s",
|
||||
file);
|
||||
}
|
||||
|
||||
bfree(intermediate);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"WIC: Failed to allocate intermediate for file: %s",
|
||||
file);
|
||||
}
|
||||
} else {
|
||||
hr = pFrame->lpVtbl->CopyPixels(
|
||||
pFrame, NULL, pitch,
|
||||
size, bytes);
|
||||
success = SUCCEEDED(hr);
|
||||
if (!success) {
|
||||
blog(LOG_WARNING,
|
||||
"WIC: Failed to CopyPixels for file: %s",
|
||||
file);
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
*format = GS_RGBA16F;
|
||||
*cx_out = width;
|
||||
*cy_out = height;
|
||||
*space = GS_CS_709_SCRGB;
|
||||
} else {
|
||||
bfree(bytes);
|
||||
bytes = NULL;
|
||||
}
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"WIC: Failed to allocate for file: %s",
|
||||
file);
|
||||
}
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"WIC: Failed to GetSize of frame for file: %s",
|
||||
file);
|
||||
}
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"WIC: Only handle GUID_WICPixelFormat32bppBGR101010 and GUID_WICPixelFormat64bppRGBAHalf for now");
|
||||
}
|
||||
} else {
|
||||
blog(LOG_WARNING, "WIC: Failed to GetPixelFormat for file: %s",
|
||||
file);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static void *wic_image_init(const struct ffmpeg_image *info, const char *file,
|
||||
enum gs_color_format *format, uint32_t *cx_out,
|
||||
uint32_t *cy_out, enum gs_color_space *space)
|
||||
{
|
||||
const size_t len = strlen(file);
|
||||
if (len <= 4 && astrcmpi(file + len - 4, ".jxr") != 0) {
|
||||
blog(LOG_WARNING,
|
||||
"WIC: Only handle JXR for WIC images for now");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BYTE *bytes = NULL;
|
||||
|
||||
wchar_t *file_w = NULL;
|
||||
os_utf8_to_wcs_ptr(file, 0, &file_w);
|
||||
if (file_w) {
|
||||
IWICImagingFactory *pFactory = NULL;
|
||||
HRESULT hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
&IID_IWICImagingFactory,
|
||||
&pFactory);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IWICBitmapDecoder *pDecoder = NULL;
|
||||
hr = pFactory->lpVtbl->CreateDecoderFromFilename(
|
||||
pFactory, file_w, NULL, GENERIC_READ,
|
||||
WICDecodeMetadataCacheOnDemand, &pDecoder);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IWICBitmapFrameDecode *pFrame = NULL;
|
||||
hr = pDecoder->lpVtbl->GetFrame(pDecoder, 0,
|
||||
&pFrame);
|
||||
if (SUCCEEDED(hr)) {
|
||||
bytes = wic_image_init_internal(
|
||||
file, pFrame, format, cx_out,
|
||||
cy_out, space);
|
||||
|
||||
pFrame->lpVtbl->Release(pFrame);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"WIC: Failed to create IWICBitmapFrameDecode from file: %s",
|
||||
file);
|
||||
}
|
||||
|
||||
pDecoder->lpVtbl->Release(pDecoder);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"WIC: Failed to create IWICBitmapDecoder from file: %s",
|
||||
file);
|
||||
}
|
||||
|
||||
pFactory->lpVtbl->Release(pFactory);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"WIC: Failed to create IWICImagingFactory");
|
||||
}
|
||||
|
||||
bfree(file_w);
|
||||
} else {
|
||||
blog(LOG_WARNING, "WIC: Failed to widen file name: %s", file);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t *gs_create_texture_file_data2(const char *file,
|
||||
enum gs_image_alpha_mode alpha_mode,
|
||||
enum gs_color_format *format,
|
||||
uint32_t *cx_out, uint32_t *cy_out)
|
||||
{
|
||||
enum gs_color_space unused;
|
||||
return gs_create_texture_file_data3(file, alpha_mode, format, cx_out,
|
||||
cy_out, &unused);
|
||||
}
|
||||
|
||||
uint8_t *gs_create_texture_file_data3(const char *file,
|
||||
enum gs_image_alpha_mode alpha_mode,
|
||||
enum gs_color_format *format,
|
||||
uint32_t *cx_out, uint32_t *cy_out,
|
||||
enum gs_color_space *space)
|
||||
{
|
||||
struct ffmpeg_image image;
|
||||
uint8_t *data = NULL;
|
||||
@ -658,10 +886,18 @@ uint8_t *gs_create_texture_file_data2(const char *file,
|
||||
*format = convert_format(image.format);
|
||||
*cx_out = (uint32_t)image.cx;
|
||||
*cy_out = (uint32_t)image.cy;
|
||||
*space = GS_CS_SRGB;
|
||||
}
|
||||
|
||||
ffmpeg_image_free(&image);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (data == NULL) {
|
||||
data = wic_image_init(&image, file, format, cx_out, cy_out,
|
||||
space);
|
||||
}
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -593,6 +593,11 @@ EXPORT uint8_t *gs_create_texture_file_data(const char *file,
|
||||
EXPORT uint8_t *gs_create_texture_file_data2(
|
||||
const char *file, enum gs_image_alpha_mode alpha_mode,
|
||||
enum gs_color_format *format, uint32_t *cx, uint32_t *cy);
|
||||
EXPORT uint8_t *
|
||||
gs_create_texture_file_data3(const char *file,
|
||||
enum gs_image_alpha_mode alpha_mode,
|
||||
enum gs_color_format *format, uint32_t *cx,
|
||||
uint32_t *cy, enum gs_color_space *space);
|
||||
|
||||
#define GS_FLIP_U (1 << 0)
|
||||
#define GS_FLIP_V (1 << 1)
|
||||
|
@ -193,6 +193,7 @@ not_animated:
|
||||
|
||||
static void gs_image_file_init_internal(gs_image_file_t *image,
|
||||
const char *file, uint64_t *mem_usage,
|
||||
enum gs_color_space *space,
|
||||
enum gs_image_alpha_mode alpha_mode)
|
||||
{
|
||||
size_t len;
|
||||
@ -213,8 +214,9 @@ static void gs_image_file_init_internal(gs_image_file_t *image,
|
||||
}
|
||||
}
|
||||
|
||||
image->texture_data = gs_create_texture_file_data2(
|
||||
file, alpha_mode, &image->format, &image->cx, &image->cy);
|
||||
image->texture_data =
|
||||
gs_create_texture_file_data3(file, alpha_mode, &image->format,
|
||||
&image->cx, &image->cy, space);
|
||||
|
||||
if (mem_usage) {
|
||||
*mem_usage += image->cx * image->cy *
|
||||
@ -230,7 +232,9 @@ static void gs_image_file_init_internal(gs_image_file_t *image,
|
||||
|
||||
void gs_image_file_init(gs_image_file_t *image, const char *file)
|
||||
{
|
||||
gs_image_file_init_internal(image, file, NULL, GS_IMAGE_ALPHA_STRAIGHT);
|
||||
enum gs_color_space unused;
|
||||
gs_image_file_init_internal(image, file, NULL, &unused,
|
||||
GS_IMAGE_ALPHA_STRAIGHT);
|
||||
}
|
||||
|
||||
void gs_image_file_free(gs_image_file_t *image)
|
||||
@ -255,18 +259,30 @@ void gs_image_file_free(gs_image_file_t *image)
|
||||
|
||||
void gs_image_file2_init(gs_image_file2_t *if2, const char *file)
|
||||
{
|
||||
gs_image_file_init_internal(&if2->image, file, &if2->mem_usage,
|
||||
enum gs_color_space unused;
|
||||
gs_image_file_init_internal(&if2->image, file, &if2->mem_usage, &unused,
|
||||
GS_IMAGE_ALPHA_STRAIGHT);
|
||||
}
|
||||
|
||||
void gs_image_file3_init(gs_image_file3_t *if3, const char *file,
|
||||
enum gs_image_alpha_mode alpha_mode)
|
||||
{
|
||||
enum gs_color_space unused;
|
||||
gs_image_file_init_internal(&if3->image2.image, file,
|
||||
&if3->image2.mem_usage, alpha_mode);
|
||||
&if3->image2.mem_usage, &unused,
|
||||
alpha_mode);
|
||||
if3->alpha_mode = alpha_mode;
|
||||
}
|
||||
|
||||
void gs_image_file4_init(gs_image_file4_t *if4, const char *file,
|
||||
enum gs_image_alpha_mode alpha_mode)
|
||||
{
|
||||
gs_image_file_init_internal(&if4->image3.image2.image, file,
|
||||
&if4->image3.image2.mem_usage, &if4->space,
|
||||
alpha_mode);
|
||||
if4->image3.alpha_mode = alpha_mode;
|
||||
}
|
||||
|
||||
void gs_image_file_init_texture(gs_image_file_t *image)
|
||||
{
|
||||
if (!image->loaded)
|
||||
@ -404,6 +420,13 @@ bool gs_image_file3_tick(gs_image_file3_t *if3, uint64_t elapsed_time_ns)
|
||||
if3->alpha_mode);
|
||||
}
|
||||
|
||||
bool gs_image_file4_tick(gs_image_file4_t *if4, uint64_t elapsed_time_ns)
|
||||
{
|
||||
return gs_image_file_tick_internal(&if4->image3.image2.image,
|
||||
elapsed_time_ns,
|
||||
if4->image3.alpha_mode);
|
||||
}
|
||||
|
||||
static void
|
||||
gs_image_file_update_texture_internal(gs_image_file_t *image,
|
||||
enum gs_image_alpha_mode alpha_mode)
|
||||
@ -434,3 +457,9 @@ void gs_image_file3_update_texture(gs_image_file3_t *if3)
|
||||
gs_image_file_update_texture_internal(&if3->image2.image,
|
||||
if3->alpha_mode);
|
||||
}
|
||||
|
||||
void gs_image_file4_update_texture(gs_image_file4_t *if4)
|
||||
{
|
||||
gs_image_file_update_texture_internal(&if4->image3.image2.image,
|
||||
if4->image3.alpha_mode);
|
||||
}
|
||||
|
@ -56,9 +56,15 @@ struct gs_image_file3 {
|
||||
enum gs_image_alpha_mode alpha_mode;
|
||||
};
|
||||
|
||||
struct gs_image_file4 {
|
||||
struct gs_image_file3 image3;
|
||||
enum gs_color_space space;
|
||||
};
|
||||
|
||||
typedef struct gs_image_file gs_image_file_t;
|
||||
typedef struct gs_image_file2 gs_image_file2_t;
|
||||
typedef struct gs_image_file3 gs_image_file3_t;
|
||||
typedef struct gs_image_file4 gs_image_file4_t;
|
||||
|
||||
EXPORT void gs_image_file_init(gs_image_file_t *image, const char *file);
|
||||
EXPORT void gs_image_file_free(gs_image_file_t *image);
|
||||
@ -81,6 +87,13 @@ EXPORT bool gs_image_file3_tick(gs_image_file3_t *if3,
|
||||
uint64_t elapsed_time_ns);
|
||||
EXPORT void gs_image_file3_update_texture(gs_image_file3_t *if3);
|
||||
|
||||
EXPORT void gs_image_file4_init(gs_image_file4_t *if4, const char *file,
|
||||
enum gs_image_alpha_mode alpha_mode);
|
||||
|
||||
EXPORT bool gs_image_file4_tick(gs_image_file4_t *if4,
|
||||
uint64_t elapsed_time_ns);
|
||||
EXPORT void gs_image_file4_update_texture(gs_image_file4_t *if4);
|
||||
|
||||
static void gs_image_file2_free(gs_image_file2_t *if2)
|
||||
{
|
||||
gs_image_file_free(&if2->image);
|
||||
@ -102,6 +115,16 @@ static void gs_image_file3_init_texture(gs_image_file3_t *if3)
|
||||
gs_image_file2_init_texture(&if3->image2);
|
||||
}
|
||||
|
||||
static void gs_image_file4_free(gs_image_file4_t *if4)
|
||||
{
|
||||
gs_image_file3_free(&if4->image3);
|
||||
}
|
||||
|
||||
static void gs_image_file4_init_texture(gs_image_file4_t *if4)
|
||||
{
|
||||
gs_image_file3_init_texture(&if4->image3);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -832,12 +832,8 @@ void obs_transition_video_render2(
|
||||
static enum gs_color_space mix_spaces(enum gs_color_space a,
|
||||
enum gs_color_space b)
|
||||
{
|
||||
assert((a == GS_CS_SRGB) || (a == GS_CS_SRGB_16F) ||
|
||||
(a == GS_CS_709_EXTENDED));
|
||||
assert((b == GS_CS_SRGB) || (b == GS_CS_SRGB_16F) ||
|
||||
(b == GS_CS_709_EXTENDED));
|
||||
|
||||
if ((a == GS_CS_709_EXTENDED) || (b == GS_CS_709_EXTENDED))
|
||||
if ((a == GS_CS_709_EXTENDED) || (a == GS_CS_709_SCRGB) ||
|
||||
(b == GS_CS_709_EXTENDED) || (b == GS_CS_709_SCRGB))
|
||||
return GS_CS_709_EXTENDED;
|
||||
if ((a == GS_CS_SRGB_16F) || (b == GS_CS_SRGB_16F))
|
||||
return GS_CS_SRGB_16F;
|
||||
|
@ -24,7 +24,7 @@ struct image_source {
|
||||
bool active;
|
||||
bool restart_gif;
|
||||
|
||||
gs_image_file3_t if3;
|
||||
gs_image_file4_t if4;
|
||||
};
|
||||
|
||||
static time_t get_modified_timestamp(const char *filename)
|
||||
@ -46,23 +46,23 @@ static void image_source_load(struct image_source *context)
|
||||
char *file = context->file;
|
||||
|
||||
obs_enter_graphics();
|
||||
gs_image_file3_free(&context->if3);
|
||||
gs_image_file4_free(&context->if4);
|
||||
obs_leave_graphics();
|
||||
|
||||
if (file && *file) {
|
||||
debug("loading texture '%s'", file);
|
||||
context->file_timestamp = get_modified_timestamp(file);
|
||||
gs_image_file3_init(&context->if3, file,
|
||||
gs_image_file4_init(&context->if4, file,
|
||||
context->linear_alpha
|
||||
? GS_IMAGE_ALPHA_PREMULTIPLY_SRGB
|
||||
: GS_IMAGE_ALPHA_PREMULTIPLY);
|
||||
context->update_time_elapsed = 0;
|
||||
|
||||
obs_enter_graphics();
|
||||
gs_image_file3_init_texture(&context->if3);
|
||||
gs_image_file4_init_texture(&context->if4);
|
||||
obs_leave_graphics();
|
||||
|
||||
if (!context->if3.image2.image.loaded)
|
||||
if (!context->if4.image3.image2.image.loaded)
|
||||
warn("failed to load texture '%s'", file);
|
||||
}
|
||||
}
|
||||
@ -70,7 +70,7 @@ static void image_source_load(struct image_source *context)
|
||||
static void image_source_unload(struct image_source *context)
|
||||
{
|
||||
obs_enter_graphics();
|
||||
gs_image_file3_free(&context->if3);
|
||||
gs_image_file4_free(&context->if4);
|
||||
obs_leave_graphics();
|
||||
}
|
||||
|
||||
@ -120,13 +120,13 @@ static void restart_gif(void *data)
|
||||
{
|
||||
struct image_source *context = data;
|
||||
|
||||
if (context->if3.image2.image.is_animated_gif) {
|
||||
context->if3.image2.image.cur_frame = 0;
|
||||
context->if3.image2.image.cur_loop = 0;
|
||||
context->if3.image2.image.cur_time = 0;
|
||||
if (context->if4.image3.image2.image.is_animated_gif) {
|
||||
context->if4.image3.image2.image.cur_frame = 0;
|
||||
context->if4.image3.image2.image.cur_loop = 0;
|
||||
context->if4.image3.image2.image.cur_time = 0;
|
||||
|
||||
obs_enter_graphics();
|
||||
gs_image_file3_update_texture(&context->if3);
|
||||
gs_image_file4_update_texture(&context->if4);
|
||||
obs_leave_graphics();
|
||||
|
||||
context->restart_gif = false;
|
||||
@ -162,20 +162,22 @@ static void image_source_destroy(void *data)
|
||||
static uint32_t image_source_getwidth(void *data)
|
||||
{
|
||||
struct image_source *context = data;
|
||||
return context->if3.image2.image.cx;
|
||||
return context->if4.image3.image2.image.cx;
|
||||
}
|
||||
|
||||
static uint32_t image_source_getheight(void *data)
|
||||
{
|
||||
struct image_source *context = data;
|
||||
return context->if3.image2.image.cy;
|
||||
return context->if4.image3.image2.image.cy;
|
||||
}
|
||||
|
||||
static void image_source_render(void *data, gs_effect_t *effect)
|
||||
{
|
||||
struct image_source *context = data;
|
||||
|
||||
if (!context->if3.image2.image.texture)
|
||||
struct gs_image_file *const image = &context->if4.image3.image2.image;
|
||||
gs_texture_t *const texture = image->texture;
|
||||
if (!texture)
|
||||
return;
|
||||
|
||||
const bool previous = gs_framebuffer_srgb_enabled();
|
||||
@ -185,11 +187,9 @@ static void image_source_render(void *data, gs_effect_t *effect)
|
||||
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
|
||||
|
||||
gs_eparam_t *const param = gs_effect_get_param_by_name(effect, "image");
|
||||
gs_effect_set_texture_srgb(param, context->if3.image2.image.texture);
|
||||
gs_effect_set_texture_srgb(param, texture);
|
||||
|
||||
gs_draw_sprite(context->if3.image2.image.texture, 0,
|
||||
context->if3.image2.image.cx,
|
||||
context->if3.image2.image.cy);
|
||||
gs_draw_sprite(texture, 0, image->cx, image->cy);
|
||||
|
||||
gs_blend_state_pop();
|
||||
|
||||
@ -216,7 +216,7 @@ static void image_source_tick(void *data, float seconds)
|
||||
|
||||
if (obs_source_showing(context->source)) {
|
||||
if (!context->active) {
|
||||
if (context->if3.image2.image.is_animated_gif)
|
||||
if (context->if4.image3.image2.image.is_animated_gif)
|
||||
context->last_time = frame_time;
|
||||
context->active = true;
|
||||
}
|
||||
@ -233,13 +233,14 @@ static void image_source_tick(void *data, float seconds)
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->last_time && context->if3.image2.image.is_animated_gif) {
|
||||
if (context->last_time &&
|
||||
context->if4.image3.image2.image.is_animated_gif) {
|
||||
uint64_t elapsed = frame_time - context->last_time;
|
||||
bool updated = gs_image_file3_tick(&context->if3, elapsed);
|
||||
bool updated = gs_image_file4_tick(&context->if4, elapsed);
|
||||
|
||||
if (updated) {
|
||||
obs_enter_graphics();
|
||||
gs_image_file3_update_texture(&context->if3);
|
||||
gs_image_file4_update_texture(&context->if4);
|
||||
obs_leave_graphics();
|
||||
}
|
||||
}
|
||||
@ -248,11 +249,18 @@ static void image_source_tick(void *data, float seconds)
|
||||
}
|
||||
|
||||
static const char *image_filter =
|
||||
#ifdef _WIN32
|
||||
"All formats (*.bmp *.tga *.png *.jpeg *.jpg *.jxr *.gif *.psd *.webp);;"
|
||||
#else
|
||||
"All formats (*.bmp *.tga *.png *.jpeg *.jpg *.gif *.psd *.webp);;"
|
||||
#endif
|
||||
"BMP Files (*.bmp);;"
|
||||
"Targa Files (*.tga);;"
|
||||
"PNG Files (*.png);;"
|
||||
"JPEG Files (*.jpeg *.jpg);;"
|
||||
#ifdef _WIN32
|
||||
"JXR Files (*.jxr);;"
|
||||
#endif
|
||||
"GIF Files (*.gif);;"
|
||||
"PSD Files (*.psd);;"
|
||||
"WebP Files (*.webp);;"
|
||||
@ -289,7 +297,7 @@ static obs_properties_t *image_source_properties(void *data)
|
||||
uint64_t image_source_get_memory_usage(void *data)
|
||||
{
|
||||
struct image_source *s = data;
|
||||
return s->if3.image2.mem_usage;
|
||||
return s->if4.image3.image2.mem_usage;
|
||||
}
|
||||
|
||||
static void missing_file_callback(void *src, const char *new_path, void *data)
|
||||
@ -323,6 +331,15 @@ static obs_missing_files_t *image_source_missingfiles(void *data)
|
||||
return files;
|
||||
}
|
||||
|
||||
static enum gs_color_space
|
||||
image_source_get_color_space(void *data, size_t count,
|
||||
const enum gs_color_space *preferred_spaces)
|
||||
{
|
||||
struct image_source *const s = data;
|
||||
gs_image_file4_t *const if4 = &s->if4;
|
||||
return if4->image3.image2.image.texture ? if4->space : GS_CS_SRGB;
|
||||
}
|
||||
|
||||
static struct obs_source_info image_source_info = {
|
||||
.id = "image_source",
|
||||
.type = OBS_SOURCE_TYPE_INPUT,
|
||||
@ -342,6 +359,7 @@ static struct obs_source_info image_source_info = {
|
||||
.get_properties = image_source_properties,
|
||||
.icon_type = OBS_ICON_TYPE_IMAGE,
|
||||
.activate = image_source_activate,
|
||||
.video_get_color_space = image_source_get_color_space,
|
||||
};
|
||||
|
||||
OBS_DECLARE_MODULE()
|
||||
|
Loading…
x
Reference in New Issue
Block a user