Skip to content
Open
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
8 changes: 5 additions & 3 deletions libobs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,10 @@ target_sources(
graphics/image-file.c
graphics/image-file.h
graphics/input.h
graphics/libnsgif/libnsgif.c
graphics/libnsgif/libnsgif.h
graphics/libnsgif/gif.c
graphics/libnsgif/lzw.c
graphics/libnsgif/lzw.h
graphics/libnsgif/nsgif.h
graphics/math-defs.h
graphics/math-extra.c
graphics/math-extra.h
Expand Down Expand Up @@ -295,7 +297,7 @@ set(
graphics/graphics.h
graphics/image-file.h
graphics/input.h
graphics/libnsgif/libnsgif.h
graphics/libnsgif/nsgif.h
graphics/math-defs.h
graphics/math-extra.h
graphics/matrix3.h
Expand Down
8 changes: 8 additions & 0 deletions libobs/cmake/os-windows.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ set_source_files_properties(
PROPERTIES COMPILE_DEFINITIONS OBS_VERSION="${OBS_VERSION_CANONICAL}"
)

set_source_files_properties(
graphics/libnsgif/gif.c
graphics/libnsgif/lzw.c
graphics/libnsgif/lzw.h
graphics/libnsgif/nsgif.h
PROPERTIES COMPILE_OPTIONS "/wd4244;/wd4267"
)

target_link_libraries(
libobs
PRIVATE Avrt Dwmapi Dxgi winmm Rpcrt4 OBS::obfuscate OBS::winhandle OBS::COMutils
Expand Down
88 changes: 51 additions & 37 deletions libobs/graphics/image-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ static void bi_def_bitmap_modified(void *bitmap)

static inline int get_full_decoded_gif_size(gs_image_file_t *image)
{
return image->gif.width * image->gif.height * 4 * image->gif.frame_count;
return image->gif_info->width * image->gif_info->height * 4 * image->gif_info->frame_count;
}

static inline void *alloc_mem(gs_image_file_t *image, uint64_t *mem_usage, size_t size)
Expand All @@ -73,19 +73,20 @@ static bool init_animated_gif(gs_image_file_t *image, const char *path, uint64_t
enum gs_image_alpha_mode alpha_mode)
{
bool is_animated_gif = true;
gif_result result;
nsgif_error result;
uint64_t max_size;
size_t size, size_read;
FILE *file;
nsgif_bitmap_t *bitmap;

image->bitmap_callbacks.bitmap_create = bi_def_bitmap_create;
image->bitmap_callbacks.bitmap_destroy = bi_def_bitmap_destroy;
image->bitmap_callbacks.bitmap_get_buffer = bi_def_bitmap_get_buffer;
image->bitmap_callbacks.bitmap_modified = bi_def_bitmap_modified;
image->bitmap_callbacks.bitmap_set_opaque = bi_def_bitmap_set_opaque;
image->bitmap_callbacks.bitmap_test_opaque = bi_def_bitmap_test_opaque;
image->bitmap_callbacks.create = bi_def_bitmap_create;
image->bitmap_callbacks.destroy = bi_def_bitmap_destroy;
image->bitmap_callbacks.get_buffer = bi_def_bitmap_get_buffer;
image->bitmap_callbacks.modified = bi_def_bitmap_modified;
image->bitmap_callbacks.set_opaque = bi_def_bitmap_set_opaque;
image->bitmap_callbacks.test_opaque = bi_def_bitmap_test_opaque;

gif_create(&image->gif, &image->bitmap_callbacks);
nsgif_create(&image->bitmap_callbacks, NSGIF_BITMAP_FMT_R8G8B8A8, &image->gif);

file = os_fopen(path, "rb");
if (!file) {
Expand All @@ -105,47 +106,56 @@ static bool init_animated_gif(gs_image_file_t *image, const char *path, uint64_t
}

do {
result = gif_initialise(&image->gif, size, image->gif_data);
result = nsgif_data_scan(image->gif, size, image->gif_data);
if (result < 0) {
blog(LOG_WARNING,
"Failed to initialize gif '%s', "
"possible file corruption",
path);
goto fail;
}
} while (result != GIF_OK);
} while (result != NSGIF_OK);

if (image->gif.width > 4096 || image->gif.height > 4096) {
blog(LOG_WARNING, "Bad texture dimensions (%dx%d) in '%s'", image->gif.width, image->gif.height, path);
nsgif_data_complete(image->gif);

image->gif_info = nsgif_get_info(image->gif);

if (image->gif_info->width > 4096 || image->gif_info->height > 4096) {
blog(LOG_WARNING, "Bad texture dimensions (%dx%d) in '%s'", image->gif_info->width,
image->gif_info->height, path);
goto fail;
}

max_size = (uint64_t)image->gif.width * (uint64_t)image->gif.height * (uint64_t)image->gif.frame_count * 4LLU;
max_size = (uint64_t)image->gif_info->width * (uint64_t)image->gif_info->height *
(uint64_t)image->gif_info->frame_count * 4LLU;

if ((uint64_t)get_full_decoded_gif_size(image) != max_size) {
blog(LOG_WARNING, "Gif '%s' overflowed maximum pointer size", path);
goto fail;
}

image->is_animated_gif = (image->gif.frame_count > 1 && result >= 0);
image->is_animated_gif = (image->gif_info->frame_count > 1 && result >= 0);
if (image->is_animated_gif) {
gif_decode_frame(&image->gif, 0);
nsgif_frame_decode(image->gif, 0, &bitmap);

image->animation_frame_cache = alloc_mem(image, mem_usage, image->gif.frame_count * sizeof(uint8_t *));
image->animation_frame_cache =
alloc_mem(image, mem_usage, image->gif_info->frame_count * sizeof(uint8_t *));
image->animation_frame_data = alloc_mem(image, mem_usage, get_full_decoded_gif_size(image));

for (unsigned int i = 0; i < image->gif.frame_count; i++) {
if (gif_decode_frame(&image->gif, i) != GIF_OK)
for (unsigned int i = 0; i < image->gif_info->frame_count; i++) {
if (nsgif_frame_decode(image->gif, i, &bitmap) != NSGIF_OK)
blog(LOG_WARNING,
"Couldn't decode frame %u "
"of '%s'",
i, path);
}

gif_decode_frame(&image->gif, 0);
nsgif_frame_decode(image->gif, 0, &bitmap);

image->cx = (uint32_t)image->gif.width;
image->cy = (uint32_t)image->gif.height;
image->gif_frame_image = (const uint8_t *)bitmap;

image->cx = (uint32_t)image->gif_info->width;
image->cy = (uint32_t)image->gif_info->height;
image->format = GS_RGBA;

if (mem_usage) {
Expand All @@ -154,12 +164,12 @@ static bool init_animated_gif(gs_image_file_t *image, const char *path, uint64_t
}

if (alpha_mode == GS_IMAGE_ALPHA_PREMULTIPLY_SRGB) {
gs_premultiply_xyza_srgb_loop(image->gif.frame_image, (size_t)image->cx * image->cy);
gs_premultiply_xyza_srgb_loop((uint8_t *)bitmap, (size_t)image->cx * image->cy);
} else if (alpha_mode == GS_IMAGE_ALPHA_PREMULTIPLY) {
gs_premultiply_xyza_loop(image->gif.frame_image, (size_t)image->cx * image->cy);
gs_premultiply_xyza_loop((uint8_t *)bitmap, (size_t)image->cx * image->cy);
}
} else {
gif_finalise(&image->gif);
nsgif_destroy(image->gif);
bfree(image->gif_data);
image->gif_data = NULL;
is_animated_gif = false;
Expand Down Expand Up @@ -226,7 +236,7 @@ void gs_image_file_free(gs_image_file_t *image)

if (image->loaded) {
if (image->is_animated_gif) {
gif_finalise(&image->gif);
nsgif_destroy(image->gif);
bfree(image->animation_frame_cache);
bfree(image->animation_frame_data);
}
Expand Down Expand Up @@ -266,7 +276,7 @@ void gs_image_file_init_texture(gs_image_file_t *image)

if (image->is_animated_gif) {
image->texture = gs_texture_create(image->cx, image->cy, image->format, 1,
(const uint8_t **)&image->gif.frame_image, GS_DYNAMIC);
(const uint8_t **)&image->gif_frame_image, GS_DYNAMIC);

} else {
image->texture = gs_texture_create(image->cx, image->cy, image->format, 1,
Expand All @@ -278,7 +288,8 @@ void gs_image_file_init_texture(gs_image_file_t *image)

static inline uint64_t get_time(gs_image_file_t *image, int i)
{
uint64_t val = (uint64_t)image->gif.frames[i].frame_delay * 10000000ULL;
const nsgif_frame_info_t *gif_frame_info = nsgif_get_frame_info(image->gif, i);
uint64_t val = (uint64_t)gif_frame_info->delay * 10000000ULL;
if (!val)
val = 100000000;
return val;
Expand All @@ -295,7 +306,7 @@ static inline int calculate_new_frame(gs_image_file_t *image, uint64_t elapsed_t
break;

image->cur_time -= t;
if ((unsigned int)++new_frame == image->gif.frame_count) {
if ((unsigned int)++new_frame == image->gif_info->frame_count) {
if (!loops || ++image->cur_loop < loops) {
new_frame = 0;
} else if (image->cur_loop == loops) {
Expand All @@ -312,29 +323,32 @@ static void decode_new_frame(gs_image_file_t *image, int new_frame, enum gs_imag
{
if (!image->animation_frame_cache[new_frame]) {
int last_frame;
nsgif_bitmap_t *bitmap;

/* if looped, decode frame 0 */
last_frame = (new_frame < image->last_decoded_frame) ? 0 : image->last_decoded_frame + 1;

/* decode missed frames */
for (int i = last_frame; i < new_frame; i++) {
if (gif_decode_frame(&image->gif, i) != GIF_OK)
if (nsgif_frame_decode(image->gif, i, &bitmap) != NSGIF_OK)
return;
}

/* decode actual desired frame */
if (gif_decode_frame(&image->gif, new_frame) == GIF_OK) {
const size_t area = (size_t)image->gif.width * image->gif.height;
if (nsgif_frame_decode(image->gif, new_frame, &bitmap) == NSGIF_OK) {
const size_t area = (size_t)image->gif_info->width * image->gif_info->height;
size_t pos = new_frame * area * 4;
image->animation_frame_cache[new_frame] = image->animation_frame_data + pos;

if (alpha_mode == GS_IMAGE_ALPHA_PREMULTIPLY_SRGB) {
gs_premultiply_xyza_srgb_loop(image->gif.frame_image, area);
gs_premultiply_xyza_srgb_loop((uint8_t *)bitmap, area);
} else if (alpha_mode == GS_IMAGE_ALPHA_PREMULTIPLY) {
gs_premultiply_xyza_loop(image->gif.frame_image, area);
gs_premultiply_xyza_loop((uint8_t *)bitmap, area);
}

memcpy(image->animation_frame_cache[new_frame], image->gif.frame_image, area * 4);
image->gif_frame_image = (const uint8_t *)bitmap;

memcpy(image->animation_frame_cache[new_frame], (const uint8_t *)bitmap, area * 4);

image->last_decoded_frame = new_frame;
}
Expand All @@ -351,7 +365,7 @@ static bool gs_image_file_tick_internal(gs_image_file_t *image, uint64_t elapsed
if (!image->is_animated_gif || !image->loaded)
return false;

loops = image->gif.loop_count;
loops = image->gif_info->loop_max;
if (loops >= 0xFFFF)
loops = 0;

Expand Down Expand Up @@ -395,7 +409,7 @@ static void gs_image_file_update_texture_internal(gs_image_file_t *image, enum g
if (!image->animation_frame_cache[image->cur_frame])
decode_new_frame(image, image->cur_frame, alpha_mode);

gs_texture_set_image(image->texture, image->animation_frame_cache[image->cur_frame], image->gif.width * 4,
gs_texture_set_image(image->texture, image->animation_frame_cache[image->cur_frame], image->gif_info->width * 4,
false);
}

Expand Down
8 changes: 5 additions & 3 deletions libobs/graphics/image-file.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#pragma once

#include "graphics.h"
#include "libnsgif/libnsgif.h"
#include "libnsgif/nsgif.h"

#ifdef __cplusplus
extern "C" {
Expand All @@ -33,8 +33,10 @@ struct gs_image_file {
bool frame_updated;
bool loaded;

gif_animation gif;
nsgif_t *gif;
const nsgif_info_t *gif_info;
uint8_t *gif_data;
const uint8_t *gif_frame_image;
uint8_t **animation_frame_cache;
uint8_t *animation_frame_data;
uint64_t cur_time;
Expand All @@ -43,7 +45,7 @@ struct gs_image_file {
int last_decoded_frame;

uint8_t *texture_data;
gif_bitmap_callback_vt bitmap_callbacks;
nsgif_bitmap_cb_vt bitmap_callbacks;
};

struct gs_image_file2 {
Expand Down
Loading