generate both gif and pick smaller (+1 squashed commits)

Squashed commits:

[09122d052] generate both gif and pick the smaller one
This commit is contained in:
Concedo 2025-09-30 14:36:33 +08:00
parent 4117542eae
commit 9e4c29fda7
2 changed files with 122 additions and 3 deletions

View file

@ -7,6 +7,7 @@
#include <string.h>
#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, thats 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__

View file

@ -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");
}