From dbacf8a00531696c7761e39d0a96b3eca90d7832 Mon Sep 17 00:00:00 2001 From: Martijn Braam Date: Thu, 18 Jan 2024 03:12:57 +0100 Subject: [PATCH] Write YUV frames to jpeg directly instead of DNG --- CMakeLists.txt | 5 ++ meson.build | 3 +- src/process_pipeline.c | 104 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 983502f..bf4f917 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ PKG_CHECK_MODULES(DNG REQUIRED libdng) PKG_CHECK_MODULES(XLIB REQUIRED x11) PKG_CHECK_MODULES(XRANDR REQUIRED xrandr) PKG_CHECK_MODULES(WAYLAND REQUIRED wayland-client) +PKG_CHECK_MODULES(JPEG REQUIRED libjpeg) # Setup CMake to use GTK+, tell the compiler where to look for headers # and to the linker where to look for libraries @@ -28,6 +29,7 @@ INCLUDE_DIRECTORIES( ${XLIB_INCLUDE_DIRS} ${XRANDR_INCLUDE_DIRS} ${WAYLAND_INCLUDE_DIRS} + ${JPEG_INCLUDE_DIRS} ) LINK_DIRECTORIES( ${GTK4_LIBRARY_DIRS} @@ -39,6 +41,7 @@ LINK_DIRECTORIES( ${XLIB_LIBRARY_DIRS} ${XRANDR_LIBRARY_DIRS} ${WAYLAND_LIBRARY_DIRS} + ${JPEG_DIRS} ) # Add other flags to the compiler @@ -52,6 +55,7 @@ ADD_DEFINITIONS( ${XLIB_CFLAGS_OTHER} ${XRANDR_CFLAGS_OTHER} ${WAYLAND_CFLAGS_OTHER} + ${JPEG_OTHER} ) find_program(GLIB_COMPILE_RESOURCES NAMES glib-compile-resources REQUIRED) @@ -93,6 +97,7 @@ target_link_libraries(megapixels-gtk ${XLIB_LIBRARIES} ${XRANDR_LIBRARIES} ${WAYLAND_LIBRARIES} + ${JPEG_LIBRARIES} ) add_compile_definitions(VERSION="${PROJECT_VERSION}") diff --git a/meson.build b/meson.build index 504791b..5711d5a 100644 --- a/meson.build +++ b/meson.build @@ -4,6 +4,7 @@ gnome = import('gnome') gtkdep = dependency('gtk4') libfeedback = dependency('libfeedback-0.0') zbar = dependency('zbar') +jpeg = dependency('libjpeg') threads = dependency('threads') # gl = dependency('gl') epoxy = dependency('epoxy') @@ -63,7 +64,7 @@ executable('megapixels', 'src/dcp.c', resources, include_directories: 'src/', - dependencies: [gtkdep, libfeedback, libm, zbar, threads, epoxy, libmp, libdng] + optdeps, + dependencies: [gtkdep, libfeedback, libm, zbar, threads, epoxy, libmp, libdng, jpeg] + optdeps, install: true, link_args: '-Wl,-ldl') diff --git a/src/process_pipeline.c b/src/process_pipeline.c index 1abaa07..d198877 100644 --- a/src/process_pipeline.c +++ b/src/process_pipeline.c @@ -16,6 +16,7 @@ #include "dcp.h" #include "gl_util.h" #include "libdng.h" +#include #include #include @@ -481,7 +482,92 @@ process_image_for_preview(const uint8_t *image) } static void -process_image_for_capture(const uint8_t *image, int count) +process_image_for_capture_yuv(const uint8_t *image, int count) +{ + char fname[255]; + sprintf(fname, "%s/%d.jpg", burst_dir, count); + FILE *outfile; + if ((outfile = fopen(fname, "wb")) == NULL) { + g_printerr("jpeg open %s: error %d, %s\n", + fname, + errno, + strerror(errno)); + return; + } + int width = state_proc.mode->width; + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, outfile); + + cinfo.image_width = state_proc.mode->width & -1; + cinfo.image_height = state_proc.mode->height & -1; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_YCbCr; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, 92, TRUE); + jpeg_start_compress(&cinfo, TRUE); + uint8_t *row = malloc(width * 3); + JSAMPROW row_pointer[1]; + row_pointer[0] = row; + + unsigned int y1 = 0; + unsigned int u = 1; + unsigned int y2 = 2; + unsigned int v = 3; + + switch (state_proc.mode->v4l_pixfmt) { + case V4L2_PIX_FMT_UYVY: + u = 0; + y1 = 1; + v = 2; + y2 = 3; + break; + case V4L2_PIX_FMT_YUYV: + y1 = 0; + u = 1; + y2 = 2; + v = 3; + break; + case V4L2_PIX_FMT_YVYU: + y1 = 0; + v = 1; + y2 = 2; + u = 3; + break; + case V4L2_PIX_FMT_VYUY: + v = 0; + y1 = 1; + u = 2; + y2 = 3; + break; + } + + while (cinfo.next_scanline < cinfo.image_height) { + unsigned int i, j = 0; + unsigned int offset = cinfo.next_scanline * cinfo.image_width * 2; + for (i = 0; i < cinfo.image_width * 2; i += 4) { + row[j + 0] = image[offset + i + y1]; + row[j + 1] = image[offset + i + u]; + row[j + 2] = image[offset + i + v]; + row[j + 3] = image[offset + i + y2]; + row[j + 4] = image[offset + i + u]; + row[j + 5] = image[offset + i + v]; + j += 6; + } + jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + jpeg_finish_compress(&cinfo); + fclose(outfile); + jpeg_destroy_compress(&cinfo); +} + +static void +process_image_for_capture_bayer(const uint8_t *image, int count) { char fname[255]; sprintf(fname, "%s/%d.dng", burst_dir, count); @@ -580,6 +666,22 @@ process_image_for_capture(const uint8_t *image, int count) */ } +static void +process_image_for_capture(const uint8_t *image, int count) +{ + switch (state_proc.mode->v4l_pixfmt) { + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + process_image_for_capture_yuv(image, count); + break; + default: + process_image_for_capture_bayer(image, count); + break; + } +} + static void post_process_finished(GSubprocess *proc, GAsyncResult *res, GdkTexture *thumb) {