void gs_image_file_init(gs_image_file_t *image, const char *file) { size_t len; if (!image) return; memset(image, 0, sizeof(*image)); if (!file) return; len = strlen(file); if (len > 4 && strcmp(file + len - 4, ".gif") == 0) { if (init_animated_gif(image, file)) return; } image->texture_data = gs_create_texture_file_data(file, &image->format, &image->cx, &image->cy); image->loaded = !!image->texture_data; if (!image->loaded) { blog(LOG_WARNING, "Failed to load file '%s'", file); gs_image_file_free(image); } }
static void color_grade_filter_update(void *data, obs_data_t *settings) { struct lut_filter_data *filter = data; const char *path = obs_data_get_string(settings, SETTING_IMAGE_PATH); double clut_amount = obs_data_get_double(settings, SETTING_CLUT_AMOUNT); bfree(filter->file); if (path) filter->file = bstrdup(path); obs_enter_graphics(); gs_image_file_free(&filter->image); obs_leave_graphics(); gs_image_file_init(&filter->image, path); obs_enter_graphics(); gs_image_file_init_texture(&filter->image); filter->target = filter->image.texture; filter->clut_amount = (float)clut_amount; char *effect_path = obs_module_file("color_grade_filter.effect"); gs_effect_destroy(filter->effect); filter->effect = gs_effect_create_from_file(effect_path, NULL); bfree(effect_path); obs_leave_graphics(); }
static void color_grade_filter_destroy(void *data) { struct lut_filter_data *filter = data; obs_enter_graphics(); gs_effect_destroy(filter->effect); gs_image_file_free(&filter->image); obs_leave_graphics(); bfree(filter->file); bfree(filter); }
static void image_source_load(struct image_source *context) { char *file = context->file; obs_enter_graphics(); gs_image_file_free(&context->image); obs_leave_graphics(); if (file && *file) { debug("loading texture '%s'", file); context->file_timestamp = get_modified_timestamp(file); gs_image_file_init(&context->image, file); context->update_time_elapsed = 0; obs_enter_graphics(); gs_image_file_init_texture(&context->image); obs_leave_graphics(); if (!context->image.loaded) warn("failed to load texture '%s'", file); } }
static bool init_animated_gif(gs_image_file_t *image, const char *path) { bool is_animated_gif = true; gif_result result; uint64_t max_size; size_t size; FILE *file; 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; gif_create(&image->gif, &image->bitmap_callbacks); file = os_fopen(path, "rb"); if (!file) { blog(LOG_WARNING, "Failed to open file '%s'", path); goto fail; } fseek(file, 0, SEEK_END); size = (size_t)os_ftelli64(file); fseek(file, 0, SEEK_SET); image->gif_data = bmalloc(size); fread(image->gif_data, 1, size, file); do { result = gif_initialise(&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); 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); goto fail; } max_size = (uint64_t)image->gif.width * (uint64_t)image->gif.height * (uint64_t)image->gif.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); if (image->is_animated_gif) { gif_decode_frame(&image->gif, 0); image->animation_frame_cache = bzalloc( image->gif.frame_count * sizeof(uint8_t*)); image->animation_frame_data = bzalloc( 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) blog(LOG_WARNING, "Couldn't decode frame %u " "of '%s'", i, path); } gif_decode_frame(&image->gif, 0); image->cx = (uint32_t)image->gif.width; image->cy = (uint32_t)image->gif.height; image->format = GS_RGBA; } else { gif_finalise(&image->gif); bfree(image->gif_data); image->gif_data = NULL; is_animated_gif = false; goto not_animated; } image->loaded = true; fail: if (!image->loaded) gs_image_file_free(image); not_animated: if (file) fclose(file); return is_animated_gif; }
static void image_source_unload(struct image_source *context) { obs_enter_graphics(); gs_image_file_free(&context->image); obs_leave_graphics(); }