diff --git a/otherarch/sdcpp/avi_writer.h b/otherarch/sdcpp/avi_writer.h index f35ac02d6..b416f14aa 100644 --- a/otherarch/sdcpp/avi_writer.h +++ b/otherarch/sdcpp/avi_writer.h @@ -7,6 +7,7 @@ #include #include "stable-diffusion.h" +#include "./gif.h" // charlietangora/gif-h #ifndef MSF_GIF_IMPL #define MSF_GIF_IMPL @@ -401,7 +402,7 @@ int create_mjpg_avi_membuf_from_sd_images(sd_image_t* images, int num_images, in // ---------------- Helper: create_gif_buf_from_sd_images ---------------- // Builds a GIF in memory from an array of sd_image_t. Returns 0 on success, -1 on failure. // Caller must free(*out_data) when done. -int create_gif_buf_from_sd_images(sd_image_t* images, int num_images, int fps, uint8_t** out_data, size_t *out_len) +int create_gif_buf_from_sd_images_msf(sd_image_t* images, int num_images, int fps, uint8_t** out_data, size_t *out_len) { if(!images || num_images <= 0 || !out_data || !out_len) return -1; @@ -471,4 +472,96 @@ int create_gif_buf_from_sd_images(sd_image_t* images, int num_images, int fps, return 0; } +int create_gif_buf_from_sd_images_gifh(sd_image_t* images, int num_images, int fps, uint8_t** out_data, size_t *out_len) +{ + if(!images || num_images <= 0 || !out_data || !out_len) return -1; + + // basic parameter heuristics + if(fps <= 0) fps = 16; + uint32_t delay = (uint32_t)(100 / fps); // hundredths of a second per frame + + int bitDepth = 8; + bool dither = false; + + // assume all images same size; use first + uint32_t width = images[0].width; + uint32_t height = images[0].height; + + GifWriter gw; + memset(&gw, 0, sizeof(gw)); + + if(!GifBegin(&gw, width, height, delay, bitDepth, dither)) + { + if(gw.oldImage) GIF_FREE(gw.oldImage); + + fprintf(stderr, "Error: GifBegin failed.\n"); + return -1; + } + + // Feed frames + for (int i = 0; i < num_images; i++) + { + sd_image_t* img = &images[i]; + + if (img->width != width || img->height != height) { + fprintf(stderr, "Frame %d has mismatched dimensions.\n", i); + GifEnd(&gw); + memfile_free(&gw.mem); + return -1; + } + + // gif-h expects 4 channels (RGBA) or 3 channels (RGB). It quantizes internally. + // If your images have 3 channels, that’s fine. If 4 channels, it also works. + int channels = img->channel; + if (channels != 3 && channels != 4) { + fprintf(stderr, "Unsupported channel count: %d\n", channels); + GifEnd(&gw); + memfile_free(&gw.mem); + return -1; + } + + // gif-h requires 4 channels (RGBA). If you only have RGB, add opaque alpha. + uint8_t* frame_rgba = NULL; + if (channels == 3) { + frame_rgba = (uint8_t*)malloc(width * height * 4); + for (int p = 0; p < width * height; p++) { + frame_rgba[p*4+0] = img->data[p*3+0]; + frame_rgba[p*4+1] = img->data[p*3+1]; + frame_rgba[p*4+2] = img->data[p*3+2]; + frame_rgba[p*4+3] = 255; + } + } else { + frame_rgba = img->data; // already RGBA + } + + if(!GifWriteFrame(&gw, frame_rgba, width, height, delay, bitDepth, dither)) + { + fprintf(stderr, "GIF Write Failed\n"); + GifEnd(&gw); + memfile_free(&gw.mem); + return -1; + } + + if (channels == 3) { + free(frame_rgba); + } + } + + if(!GifEnd(&gw)) + { + memfile_free(&gw.mem); + return -1; + } + + uint8_t* buf = memfile_detach(&gw.mem, out_len); + if(!buf) + { + memfile_free(&gw.mem); + return -1; + } + + *out_data = buf; + return 0; +} + #endif // __AVI_WRITER_H__ \ No newline at end of file diff --git a/otherarch/sdcpp/sdtype_adapter.cpp b/otherarch/sdcpp/sdtype_adapter.cpp index d60ea5d51..c95ed0a64 100644 --- a/otherarch/sdcpp/sdtype_adapter.cpp +++ b/otherarch/sdcpp/sdtype_adapter.cpp @@ -944,20 +944,46 @@ sd_generation_outputs sdtype_generate(const sd_generation_inputs inputs) uint8_t * out_data = nullptr; size_t out_len = 0; int status = 0; + if(vid_req_avi==1) { status = create_mjpg_avi_membuf_from_sd_images(results, generated_num_results, 16, 40, &out_data,&out_len); } else { - status = create_gif_buf_from_sd_images(results, generated_num_results, 16, &out_data,&out_len); + uint8_t * out_data_a = nullptr; + uint8_t * out_data_b = nullptr; + int status_a = 0; + int status_b = 0; + size_t out_len_a = 0; + size_t out_len_b = 0; + status_a = create_gif_buf_from_sd_images_gifh(results, generated_num_results, 16, &out_data_a,&out_len_a); + status_b = create_gif_buf_from_sd_images_msf(results, generated_num_results, 16, &out_data_b,&out_len_b); + if(!sd_is_quiet && sddebugmode==1) + { + printf("GIF-H Len: %zu, MSF Len: %zu\n",out_len_a,out_len_b); + } + if(status_a==0 && out_len_a < out_len_b) + { + free(out_data_b); + out_len = out_len_a; + out_data = out_data_a; + status = status_a; + } + else + { + free(out_data_a); + out_len = out_len_b; + out_data = out_data_b; + status = status_b; + } } if(!sd_is_quiet && sddebugmode==1) { if(status==0) { - printf("Video Saved (Len %d)!\n",out_len); + printf("Video Saved (Len %zu)!\n",out_len); }else{ printf("Save Failed!\n"); }