aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/image_writer.c
diff options
context:
space:
mode:
authorMaria Lisina <sekoohaka.sarisan@gmail.com>2026-07-16 13:13:41 +0300
committerMaria Lisina <sekoohaka.sarisan@gmail.com>2026-07-16 13:13:41 +0300
commitecc949ce290ea5770c8abc4abc973ff072b9b033 (patch)
treecd22dd66836fcbc2d9f14c03813dfbbe7e75e94e /src/image_writer.c
parentff8c3b1dd6fbd7107867e0cef6556e52c7ede6cb (diff)
parent3bdc117b311b787b85e2ab6af1b3d63fcef00e49 (diff)
Merge tag '5.15.1' of https://repo.dec05eba.com/gpu-screen-recorder
Diffstat (limited to 'src/image_writer.c')
-rw-r--r--src/image_writer.c58
1 files changed, 57 insertions, 1 deletions
diff --git a/src/image_writer.c b/src/image_writer.c
index afa9744..0b3028d 100644
--- a/src/image_writer.c
+++ b/src/image_writer.c
@@ -9,6 +9,60 @@
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
+#include <dlfcn.h>
+
+#define TJPF_RGBA 7
+#define TJSAMP_420 2
+
+typedef void* tjhandle;
+typedef tjhandle (*FUNC_tjInitCompress)(void);
+typedef int (*FUNC_tjCompress2)(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height, int pixelFormat,
+ unsigned char **jpegBuf, unsigned long *jpegSize,
+ int jpegSubsamp, int jpegQual, int flags);
+typedef int (*FUNC_tjDestroy)(tjhandle handle);
+typedef void (*FUNC_tjFree)(unsigned char *buffer);
+
+static bool write_buffer_to_file(const char *filepath, const unsigned char *data, unsigned long size) {
+ FILE *file = fopen(filepath, "wb");
+ if(!file)
+ return false;
+
+ const bool success = fwrite(data, size, 1, file) == 1;
+ fclose(file);
+ return success;
+}
+
+static bool write_jpeg_with_libturbojpeg(const char *filepath, int width, int height, const void *data, int quality) {
+ void *libturbojpeg_lib = dlopen("libturbojpeg.so.0", RTLD_LAZY);
+ if(!libturbojpeg_lib)
+ return false;
+
+ bool success = false;
+ const FUNC_tjInitCompress tjInitCompress_func = (FUNC_tjInitCompress)dlsym(libturbojpeg_lib, "tjInitCompress");
+ const FUNC_tjCompress2 tjCompress2_func = (FUNC_tjCompress2)dlsym(libturbojpeg_lib, "tjCompress2");
+ const FUNC_tjDestroy tjDestroy_func = (FUNC_tjDestroy)dlsym(libturbojpeg_lib, "tjDestroy");
+ const FUNC_tjFree tjFree_func = (FUNC_tjFree)dlsym(libturbojpeg_lib, "tjFree");
+ if(!tjInitCompress_func || !tjCompress2_func || !tjDestroy_func || !tjFree_func) {
+ dlclose(libturbojpeg_lib);
+ return false;
+ }
+
+ tjhandle compressor = tjInitCompress_func();
+ if(compressor) {
+ unsigned char *jpeg_data = NULL;
+ unsigned long jpeg_size = 0;
+ if(tjCompress2_func(compressor, data, width, width * 4, height, TJPF_RGBA, &jpeg_data, &jpeg_size, TJSAMP_420, quality, 0) == 0)
+ success = write_buffer_to_file(filepath, jpeg_data, jpeg_size);
+
+ if(jpeg_data)
+ tjFree_func(jpeg_data);
+ tjDestroy_func(compressor);
+ }
+
+ dlclose(libturbojpeg_lib);
+ return success;
+}
/* TODO: Support hdr/10-bit */
bool gsr_image_writer_init_opengl(gsr_image_writer *self, gsr_egl *egl, int width, int height) {
@@ -40,7 +94,9 @@ static bool gsr_image_writer_write_memory_to_file(gsr_image_writer *self, const
bool success = false;
switch(image_format) {
case GSR_IMAGE_FORMAT_JPEG:
- success = stbi_write_jpg(filepath, self->width, self->height, 4, data, quality);
+ success = write_jpeg_with_libturbojpeg(filepath, self->width, self->height, data, quality);
+ if(!success)
+ success = stbi_write_jpg(filepath, self->width, self->height, 4, data, quality);
break;
case GSR_IMAGE_FORMAT_PNG:
success = stbi_write_png(filepath, self->width, self->height, 4, data, 0);