diff --git a/CMakeLists.txt b/CMakeLists.txt index 043483b..d565e90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,15 +5,94 @@ set(CMAKE_C_STANDARD 11) # Use the package PkgConfig to detect GTK+ headers/library files FIND_PACKAGE(PkgConfig REQUIRED) -PKG_CHECK_MODULES(GTK3 REQUIRED gtk+-3.0) +PKG_CHECK_MODULES(GTK4 REQUIRED gtk4) +PKG_CHECK_MODULES(FEEDBACK REQUIRED libfeedback-0.0) +PKG_CHECK_MODULES(TIFF REQUIRED libtiff-4) +PKG_CHECK_MODULES(ZBAR REQUIRED zbar) +PKG_CHECK_MODULES(EPOXY REQUIRED epoxy) +PKG_CHECK_MODULES(MEGAPIXELS REQUIRED libmegapixels) +PKG_CHECK_MODULES(XLIB REQUIRED x11) +PKG_CHECK_MODULES(XRANDR REQUIRED xrandr) +PKG_CHECK_MODULES(WAYLAND REQUIRED wayland-client) # Setup CMake to use GTK+, tell the compiler where to look for headers # and to the linker where to look for libraries -INCLUDE_DIRECTORIES(${GTK3_INCLUDE_DIRS}) -LINK_DIRECTORIES(${GTK3_LIBRARY_DIRS}) +INCLUDE_DIRECTORIES( + ${GTK4_INCLUDE_DIRS} + ${FEEDBACK_INCLUDE_DIRS} + ${TIFF_INCLUDE_DIRS} + ${ZBAR_INCLUDE_DIRS} + ${EPOXY_INCLUDE_DIRS} + ${MEGAPIXELS_INCLUDE_DIRS} + ${XLIB_INCLUDE_DIRS} + ${XRANDR_INCLUDE_DIRS} + ${WAYLAND_INCLUDE_DIRS} +) +LINK_DIRECTORIES( + ${GTK4_LIBRARY_DIRS} + ${FEEDBACK_LIBRARY_DIRS} + ${TIFF_LIBRARY_DIRS} + ${ZBAR_LIBRARY_DIRS} + ${EPOXY_LIBRARY_DIRS} + ${MEGAPIXELS_LIBRARY_DIRS} + ${XLIB_LIBRARY_DIRS} + ${XRANDR_LIBRARY_DIRS} + ${WAYLAND_LIBRARY_DIRS} +) # Add other flags to the compiler -ADD_DEFINITIONS(${GTK3_CFLAGS_OTHER}) +ADD_DEFINITIONS( + ${GTK4_CFLAGS_OTHER} + ${FEEDBACK_CFLAGS_OTHER} + ${TIFF_CFLAGS_OTHER} + ${ZBAR_CFLAGS_OTHER} + ${EPOXY_CFLAGS_OTHER} + ${MEGAPIXELS_CFLAGS_OTHER} + ${XLIB_CFLAGS_OTHER} + ${XRANDR_CFLAGS_OTHER} + ${WAYLAND_CFLAGS_OTHER} +) -add_executable(megapixels main.c ini.c ini.h bayer.c bayer.h) -target_link_libraries(megapixels ${GTK3_LIBRARIES}) +find_program(GLIB_COMPILE_RESOURCES NAMES glib-compile-resources REQUIRED) +set(GRESOURCE_C megapixels.gresource.c) +set(GRESOURCE_XML data/org.postmarketos.Megapixels.gresource.xml) + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data + COMMAND ${GLIB_COMPILE_RESOURCES} + ARGS + --generate-source + --target=${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} + ../${GRESOURCE_XML} + VERBATIM + MAIN_DEPENDENCY ${GRESOURCE_XML} +) + +add_custom_target( + dummy-resource + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} +) + +file(GLOB srcs src/*.c src/*h) +add_executable(megapixels-gtk ${srcs} ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C}) +set_source_files_properties( + ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} + PROPERTIES GENERATED TRUE +) +add_dependencies(megapixels-gtk dummy-resource) +target_link_libraries(megapixels-gtk + ${GTK4_LIBRARIES} + ${FEEDBACK_LIBRARIES} + ${TIFF_LIBRARIES} + ${ZBAR_LIBRARIES} + ${EPOXY_LIBRARIES} + ${MEGAPIXELS_LIBRARIES} + ${XLIB_LIBRARIES} + ${XRANDR_LIBRARIES} + ${WAYLAND_LIBRARIES} + ) + +add_compile_definitions(VERSION="${PROJECT_VERSION}") +add_compile_definitions(SYSCONFDIR="/etc") +add_compile_definitions(DATADIR="/usr/share") \ No newline at end of file diff --git a/include/libmegapixels.h b/include/libmegapixels.h new file mode 100644 index 0000000..305d324 --- /dev/null +++ b/include/libmegapixels.h @@ -0,0 +1 @@ +extern int libmegapixels_find_config(char *configfile); \ No newline at end of file diff --git a/libmegapixels/CMakeLists.txt b/libmegapixels/CMakeLists.txt new file mode 100644 index 0000000..95a3764 --- /dev/null +++ b/libmegapixels/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(megapixels SHARED libmegapixels/findconfig.c ../include/libmegapixels.h) +set_target_properties(megapixels PROPERTIES VERSION 1) +set_target_properties(megapixels PROPERTIES SOVERSION 1) \ No newline at end of file diff --git a/libmegapixels/findconfig.c b/libmegapixels/findconfig.c new file mode 100644 index 0000000..70fc440 --- /dev/null +++ b/libmegapixels/findconfig.c @@ -0,0 +1,60 @@ +#include +#include + +#ifndef SYSCONFDIR +#define SYSCONFDIR "/etc" +#endif +#ifndef DATADIR +#define DATADIR "/usr/share" +#endif + +static int +find_device_by_model(char *conffile, char *model) +{ + // Check config/%model.conf in the current working directory + sprintf(conffile, "config/%s.conf", model); + if (access(conffile, F_OK) != -1) { + return 1; + } + + // Check user overridden /etc/megapixels/config/%model.conf + sprintf(conffile, "%s/megapixels/config/%s.conf", SYSCONFDIR, model); + if (access(conffile, F_OK) != -1) { + return 1; + } + + // Check packaged /usr/share/megapixels/config/%model.conf + sprintf(conffile, "%s/megapixels/config/%s.conf", DATADIR, model); + if (access(conffile, F_OK) != -1) { + return 1; + } + return 0; +} + +int +libmegapixels_find_config(char *configfile) +{ + char model[512]; + FILE *fp; + + if (access("/proc/device-tree/compatible", F_OK) == -1) { + return -1; + } + fp = fopen("/proc/device-tree/compatible", "r"); + char *modelptr = model; + while (1) { + int c = fgetc(fp); + if (c == EOF) { + *(modelptr) = '\0'; + return find_device_by_model(configfile, model); + } + *(modelptr++) = (char)c; + if (c == 0) { + if (find_device_by_model(configfile, model)) { + return 0; + } + modelptr = model; + } + } + return -1; +} \ No newline at end of file diff --git a/libmegapixels/meson.build b/libmegapixels/meson.build new file mode 100644 index 0000000..2fc0b8a --- /dev/null +++ b/libmegapixels/meson.build @@ -0,0 +1,24 @@ +libmegapixels_sources = [ + 'findconfig.c', +] + + +# We use libtool-version numbers because it's easier to understand. +# Before making a release, the libruntime_so_* +# numbers should be modified. The components are of the form C:R:A. +# a) If binary compatibility has been broken (eg removed or changed interfaces) +# change to C+1:0:0. +# b) If interfaces have been changed or added, but binary compatibility has +# been preserved, change to C+1:0:A+1 +# c) If the interface is the same as the previous version, change to C:R+1:A +libmegapixels_lt_c=1 +libmegapixels_lt_r=0 +libmegapixels_lt_a=0 + +libmegapixels_so_version = '@0@.@1@.@2@'.format((libmegapixels_lt_c - libmegapixels_lt_a), + libmegapixels_lt_a, + libmegapixels_lt_r) + +libmegapixels = shared_library('libmegapixels', libmegapixels_sources, + version:libmegapixels_so_version, + install: true) diff --git a/meson.build b/meson.build index 2c9bb10..61b2df2 100644 --- a/meson.build +++ b/meson.build @@ -9,6 +9,8 @@ threads = dependency('threads') # gl = dependency('gl') epoxy = dependency('epoxy') +libmp = dependency('libmegapixels') + # We only build in support for Wayland/X11 if GTK did so optdeps = [] if gtkdep.get_variable('targets').contains('wayland') @@ -48,8 +50,6 @@ endif executable('megapixels', 'src/camera.c', - 'src/camera_config.c', - 'src/device.c', 'src/flash.c', 'src/gl_util.c', 'src/gles2_debayer.c', @@ -57,14 +57,13 @@ executable('megapixels', 'src/io_pipeline.c', 'src/main.c', 'src/matrix.c', - 'src/mode.c', 'src/pipeline.c', 'src/process_pipeline.c', 'src/zbar_pipeline.c', 'src/dcp.c', resources, include_directories: 'src/', - dependencies: [gtkdep, libfeedback, libm, tiff, zbar, threads, epoxy] + optdeps, + dependencies: [gtkdep, libfeedback, libm, tiff, zbar, threads, epoxy, libmp] + optdeps, install: true, link_args: '-Wl,-ldl') @@ -80,24 +79,6 @@ install_data( ], install_dir: get_option('datadir') / 'megapixels/config/') -# Tools -executable('megapixels-list-devices', - 'tools/list_devices.c', - 'src/device.c', - 'src/mode.c', - include_directories: 'src/', - dependencies: [gtkdep], - install: true) - -executable('megapixels-camera-test', - 'tools/camera_test.c', - 'src/camera.c', - 'src/device.c', - 'src/mode.c', - include_directories: 'src/', - dependencies: [gtkdep], - install: true) - # Formatting clang_format = find_program('clang-format-14', required: false) if clang_format.found() diff --git a/src/camera.c b/src/camera.c index 5519bbd..4617635 100644 --- a/src/camera.c +++ b/src/camera.c @@ -1,9 +1,9 @@ #include "camera.h" -#include "mode.h" #include #include #include +#include #include #include #include @@ -11,9 +11,6 @@ #include #include -#define MAX_VIDEO_BUFFERS 20 -#define MAX_BG_TASKS 8 - static void errno_printerr(const char *s) { @@ -37,12 +34,7 @@ struct video_buffer { }; struct _MPCamera { - int video_fd; - int subdev_fd; - int bridge_fd; - - bool has_set_mode; - MPMode current_mode; + libmegapixels_camera *camera; struct video_buffer buffers[MAX_VIDEO_BUFFERS]; uint32_t num_buffers; @@ -54,13 +46,12 @@ struct _MPCamera { }; MPCamera * -mp_camera_new(int video_fd, int subdev_fd, int bridge_fd) +mp_camera_new(libmegapixels_camera *camera) { - g_return_val_if_fail(video_fd != -1, NULL); - + libmegapixels_open(camera); // Query capabilities struct v4l2_capability cap; - if (xioctl(video_fd, VIDIOC_QUERYCAP, &cap) == -1) { + if (xioctl(camera->video_fd, VIDIOC_QUERYCAP, &cap) == -1) { return NULL; } @@ -73,31 +64,14 @@ mp_camera_new(int video_fd, int subdev_fd, int bridge_fd) } else { return NULL; } + libmegapixels_close(camera); - MPCamera *camera = malloc(sizeof(MPCamera)); - camera->video_fd = video_fd; - camera->subdev_fd = subdev_fd; - camera->bridge_fd = bridge_fd; - camera->has_set_mode = false; - camera->num_buffers = 0; - camera->use_mplane = use_mplane; - memset(camera->child_bg_pids, - 0, - sizeof(camera->child_bg_pids[0]) * MAX_BG_TASKS); - return camera; -} - -void -mp_camera_free(MPCamera *camera) -{ - mp_camera_wait_bg_tasks(camera); - - g_warn_if_fail(camera->num_buffers == 0); - if (camera->num_buffers != 0) { - mp_camera_stop_capture(camera); - } - - free(camera); + MPCamera *cam = malloc(sizeof(MPCamera)); + cam->camera = camera; + cam->num_buffers = 0; + cam->use_mplane = use_mplane; + memset(cam->child_bg_pids, 0, sizeof(cam->child_bg_pids[0]) * MAX_BG_TASKS); + return cam; } void @@ -180,22 +154,10 @@ mp_camera_check_task_complete(MPCamera *camera, pid_t pid) } } -bool -mp_camera_is_subdev(MPCamera *camera) -{ - return camera->subdev_fd != -1; -} - int mp_camera_get_video_fd(MPCamera *camera) { - return camera->video_fd; -} - -int -mp_camera_get_subdev_fd(MPCamera *camera) -{ - return camera->subdev_fd; + return camera->camera->video_fd; } static enum v4l2_buf_type @@ -207,151 +169,9 @@ get_buf_type(MPCamera *camera) return V4L2_BUF_TYPE_VIDEO_CAPTURE; } -static bool -camera_mode_impl(MPCamera *camera, int request, MPMode *mode) -{ - uint32_t pixfmt = mp_pixel_format_to_v4l_pixel_format(mode->pixel_format); - struct v4l2_format fmt = {}; - if (camera->use_mplane) { - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - fmt.fmt.pix_mp.width = mode->width; - fmt.fmt.pix_mp.height = mode->height; - fmt.fmt.pix_mp.pixelformat = pixfmt; - fmt.fmt.pix_mp.field = V4L2_FIELD_ANY; - } else { - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = mode->width; - fmt.fmt.pix.height = mode->height; - fmt.fmt.pix.pixelformat = pixfmt; - fmt.fmt.pix.field = V4L2_FIELD_ANY; - } - - if (xioctl(camera->video_fd, request, &fmt) == -1) { - return false; - } - - if (camera->use_mplane) { - mode->width = fmt.fmt.pix_mp.width; - mode->height = fmt.fmt.pix_mp.height; - mode->pixel_format = mp_pixel_format_from_v4l_pixel_format( - fmt.fmt.pix_mp.pixelformat); - } else { - mode->width = fmt.fmt.pix.width; - mode->height = fmt.fmt.pix.height; - mode->pixel_format = mp_pixel_format_from_v4l_pixel_format( - fmt.fmt.pix.pixelformat); - } - - return true; -} - -bool -mp_camera_try_mode(MPCamera *camera, MPMode *mode) -{ - if (!camera_mode_impl(camera, VIDIOC_TRY_FMT, mode)) { - errno_printerr("VIDIOC_S_FMT"); - return false; - } - return true; -} - -const MPMode * -mp_camera_get_mode(const MPCamera *camera) -{ - return &camera->current_mode; -} - -bool -mp_camera_set_mode(MPCamera *camera, MPMode *mode) -{ - // Set the mode in the subdev the camera is one - if (mp_camera_is_subdev(camera)) { - struct v4l2_subdev_frame_interval interval = {}; - interval.pad = 0; - interval.interval = mode->frame_interval; - if (xioctl(camera->subdev_fd, - VIDIOC_SUBDEV_S_FRAME_INTERVAL, - &interval) == -1) { - errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL"); - } - - bool did_set_frame_rate = interval.interval.numerator == - mode->frame_interval.numerator && - interval.interval.denominator == - mode->frame_interval.denominator; - - struct v4l2_subdev_format fmt = {}; - fmt.pad = 0; - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - fmt.format.width = mode->width; - fmt.format.height = mode->height; - fmt.format.code = - mp_pixel_format_to_v4l_bus_code(mode->pixel_format); - fmt.format.field = V4L2_FIELD_ANY; - if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FMT, &fmt) == -1) { - errno_printerr("VIDIOC_SUBDEV_S_FMT"); - return false; - } - - // sun6i-csi-bridge will return EINVAL when trying to read - // frames if the resolution it's configured with doesn't match - // the resolution of its input. - if (camera->bridge_fd > 0) { - struct v4l2_subdev_format bridge_fmt = fmt; - - if (xioctl(camera->bridge_fd, - VIDIOC_SUBDEV_S_FMT, - &bridge_fmt) == -1) { - errno_printerr("VIDIOC_SUBDEV_S_FMT"); - return false; - } - - if (fmt.format.width != bridge_fmt.format.width || - fmt.format.height != bridge_fmt.format.height) { - g_printerr("Bridge format resolution mismatch\n"); - return false; - } - } - - // Some drivers like ov5640 don't allow you to set the frame format - // with too high a frame-rate, but that means the frame-rate won't be - // set after the format change. So we need to try again here if we - // didn't succeed before. Ideally we'd be able to set both at once. - if (!did_set_frame_rate) { - interval.interval = mode->frame_interval; - if (xioctl(camera->subdev_fd, - VIDIOC_SUBDEV_S_FRAME_INTERVAL, - &interval) == -1) { - errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL"); - } - } - - // Update the mode - mode->pixel_format = - mp_pixel_format_from_v4l_bus_code(fmt.format.code); - mode->frame_interval = interval.interval; - mode->width = fmt.format.width; - mode->height = fmt.format.height; - } - - // Set the mode for the video device - { - if (!camera_mode_impl(camera, VIDIOC_S_FMT, mode)) { - errno_printerr("VIDIOC_S_FMT"); - return false; - } - } - - camera->has_set_mode = true; - camera->current_mode = *mode; - - return true; -} - bool mp_camera_start_capture(MPCamera *camera) { - g_return_val_if_fail(camera->has_set_mode, false); g_return_val_if_fail(camera->num_buffers == 0, false); const enum v4l2_buf_type buftype = get_buf_type(camera); @@ -362,7 +182,7 @@ mp_camera_start_capture(MPCamera *camera) req.type = buftype; req.memory = V4L2_MEMORY_MMAP; - if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) { + if (xioctl(camera->camera->video_fd, VIDIOC_REQBUFS, &req) == -1) { errno_printerr("VIDIOC_REQBUFS"); return false; } @@ -388,7 +208,7 @@ mp_camera_start_capture(MPCamera *camera) buf.length = 1; } - if (xioctl(camera->video_fd, VIDIOC_QUERYBUF, &buf) == -1) { + if (xioctl(camera->camera->video_fd, VIDIOC_QUERYBUF, &buf) == -1) { errno_printerr("VIDIOC_QUERYBUF"); break; } @@ -399,7 +219,7 @@ mp_camera_start_capture(MPCamera *camera) planes[0].length, PROT_READ, MAP_SHARED, - camera->video_fd, + camera->camera->video_fd, planes[0].m.mem_offset); } else { camera->buffers[i].length = buf.length; @@ -407,7 +227,7 @@ mp_camera_start_capture(MPCamera *camera) buf.length, PROT_READ, MAP_SHARED, - camera->video_fd, + camera->camera->video_fd, buf.m.offset); } @@ -420,7 +240,7 @@ mp_camera_start_capture(MPCamera *camera) .type = buftype, .index = i, }; - if (xioctl(camera->video_fd, VIDIOC_EXPBUF, &expbuf) == -1) { + if (xioctl(camera->camera->video_fd, VIDIOC_EXPBUF, &expbuf) == -1) { errno_printerr("VIDIOC_EXPBUF"); break; } @@ -449,7 +269,7 @@ mp_camera_start_capture(MPCamera *camera) } // Queue the buffer for capture - if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) { + if (xioctl(camera->camera->video_fd, VIDIOC_QBUF, &buf) == -1) { errno_printerr("VIDIOC_QBUF"); goto error; } @@ -457,7 +277,7 @@ mp_camera_start_capture(MPCamera *camera) // Start capture enum v4l2_buf_type type = buftype; - if (xioctl(camera->video_fd, VIDIOC_STREAMON, &type) == -1) { + if (xioctl(camera->camera->video_fd, VIDIOC_STREAMON, &type) == -1) { errno_printerr("VIDIOC_STREAMON"); goto error; } @@ -485,7 +305,7 @@ error: req.type = buftype; req.memory = V4L2_MEMORY_MMAP; - if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) { + if (xioctl(camera->camera->video_fd, VIDIOC_REQBUFS, &req) == -1) { errno_printerr("VIDIOC_REQBUFS"); } } @@ -501,7 +321,7 @@ mp_camera_stop_capture(MPCamera *camera) const enum v4l2_buf_type buftype = get_buf_type(camera); enum v4l2_buf_type type = buftype; - if (xioctl(camera->video_fd, VIDIOC_STREAMOFF, &type) == -1) { + if (xioctl(camera->camera->video_fd, VIDIOC_STREAMOFF, &type) == -1) { errno_printerr("VIDIOC_STREAMOFF"); } @@ -523,7 +343,7 @@ mp_camera_stop_capture(MPCamera *camera) req.count = 0; req.type = buftype; req.memory = V4L2_MEMORY_MMAP; - if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) { + if (xioctl(camera->camera->video_fd, VIDIOC_REQBUFS, &req) == -1) { errno_printerr("VIDIOC_REQBUFS"); } @@ -551,7 +371,7 @@ mp_camera_capture_buffer(MPCamera *camera, MPBuffer *buffer) buf.length = 1; } - if (xioctl(camera->video_fd, VIDIOC_DQBUF, &buf) == -1) { + if (xioctl(camera->camera->video_fd, VIDIOC_DQBUF, &buf) == -1) { switch (errno) { case EAGAIN: return true; @@ -565,9 +385,9 @@ mp_camera_capture_buffer(MPCamera *camera, MPBuffer *buffer) } } - uint32_t pixel_format = camera->current_mode.pixel_format; - uint32_t width = camera->current_mode.width; - uint32_t height = camera->current_mode.height; + int format = camera->camera->current_mode->format; + uint32_t width = camera->camera->current_mode->width; + uint32_t height = camera->camera->current_mode->height; uint32_t bytesused; if (camera->use_mplane) { @@ -576,8 +396,8 @@ mp_camera_capture_buffer(MPCamera *camera, MPBuffer *buffer) bytesused = buf.bytesused; } - assert(bytesused == (mp_pixel_format_width_to_bytes(pixel_format, width) + - mp_pixel_format_width_to_padding(pixel_format, width)) * + assert(bytesused == (libmegapixels_mode_width_to_bytes(format, width) + + libmegapixels_mode_width_to_padding(format, width)) * height); assert(bytesused == camera->buffers[buf.index].length); @@ -604,243 +424,13 @@ mp_camera_release_buffer(MPCamera *camera, uint32_t buffer_index) buf.length = 1; } - if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) { + if (xioctl(camera->camera->video_fd, VIDIOC_QBUF, &buf) == -1) { errno_printerr("VIDIOC_QBUF"); return false; } return true; } -static MPModeList * -get_subdev_modes(MPCamera *camera, bool (*check)(MPCamera *, MPMode *)) -{ - MPModeList *item = NULL; - - for (uint32_t fmt_index = 0;; ++fmt_index) { - struct v4l2_subdev_mbus_code_enum fmt = {}; - fmt.index = fmt_index; - fmt.pad = 0; - fmt.which = V4L2_SUBDEV_FORMAT_TRY; - if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &fmt) == - -1) { - if (errno != EINVAL) { - errno_printerr("VIDIOC_SUBDEV_ENUM_MBUS_CODE"); - } - break; - } - - // Skip unsupported formats - uint32_t format = mp_pixel_format_from_v4l_bus_code(fmt.code); - if (format == MP_PIXEL_FMT_UNSUPPORTED) { - continue; - } - - for (uint32_t frame_index = 0;; ++frame_index) { - struct v4l2_subdev_frame_size_enum frame = {}; - frame.index = frame_index; - frame.pad = 0; - frame.code = fmt.code; - frame.which = V4L2_SUBDEV_FORMAT_TRY; - if (xioctl(camera->subdev_fd, - VIDIOC_SUBDEV_ENUM_FRAME_SIZE, - &frame) == -1) { - if (errno != EINVAL) { - errno_printerr( - "VIDIOC_SUBDEV_ENUM_FRAME_SIZE"); - } - break; - } - - // TODO: Handle other types - if (frame.min_width != frame.max_width || - frame.min_height != frame.max_height) { - break; - } - - for (uint32_t interval_index = 0;; ++interval_index) { - struct v4l2_subdev_frame_interval_enum interval = {}; - interval.index = interval_index; - interval.pad = 0; - interval.code = fmt.code; - interval.width = frame.max_width; - interval.height = frame.max_height; - interval.which = V4L2_SUBDEV_FORMAT_TRY; - if (xioctl(camera->subdev_fd, - VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, - &interval) == -1) { - if (errno != EINVAL) { - errno_printerr( - "VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL"); - } - break; - } - - MPMode mode = { - .pixel_format = format, - .frame_interval = interval.interval, - .width = frame.max_width, - .height = frame.max_height, - }; - - if (!check(camera, &mode)) { - continue; - } - - MPModeList *new_item = malloc(sizeof(MPModeList)); - new_item->mode = mode; - new_item->next = item; - item = new_item; - } - } - } - - return item; -} - -static MPModeList * -get_video_modes(MPCamera *camera, bool (*check)(MPCamera *, MPMode *)) -{ - const enum v4l2_buf_type buftype = get_buf_type(camera); - - MPModeList *item = NULL; - - for (uint32_t fmt_index = 0;; ++fmt_index) { - struct v4l2_fmtdesc fmt = {}; - fmt.index = fmt_index; - fmt.type = buftype; - if (xioctl(camera->video_fd, VIDIOC_ENUM_FMT, &fmt) == -1) { - if (errno != EINVAL) { - errno_printerr("VIDIOC_ENUM_FMT"); - } - break; - } - - // Skip unsupported formats - uint32_t format = - mp_pixel_format_from_v4l_pixel_format(fmt.pixelformat); - if (format == MP_PIXEL_FMT_UNSUPPORTED) { - continue; - } - - for (uint32_t frame_index = 0;; ++frame_index) { - struct v4l2_frmsizeenum frame = {}; - frame.index = frame_index; - frame.pixel_format = fmt.pixelformat; - if (xioctl(camera->video_fd, - VIDIOC_ENUM_FRAMESIZES, - &frame) == -1) { - if (errno != EINVAL) { - errno_printerr("VIDIOC_ENUM_FRAMESIZES"); - } - break; - } - - // TODO: Handle other types - if (frame.type != V4L2_FRMSIZE_TYPE_DISCRETE) { - break; - } - - for (uint32_t interval_index = 0;; ++interval_index) { - struct v4l2_frmivalenum interval = {}; - interval.index = interval_index; - interval.pixel_format = fmt.pixelformat; - interval.width = frame.discrete.width; - interval.height = frame.discrete.height; - if (xioctl(camera->video_fd, - VIDIOC_ENUM_FRAMEINTERVALS, - &interval) == -1) { - if (errno != EINVAL) { - errno_printerr( - "VIDIOC_ENUM_FRAMESIZES"); - } - break; - } - - // TODO: Handle other types - if (interval.type != V4L2_FRMIVAL_TYPE_DISCRETE) { - break; - } - - MPMode mode = { - .pixel_format = format, - .frame_interval = interval.discrete, - .width = frame.discrete.width, - .height = frame.discrete.height, - }; - - if (!check(camera, &mode)) { - continue; - } - - MPModeList *new_item = malloc(sizeof(MPModeList)); - new_item->mode = mode; - new_item->next = item; - item = new_item; - } - } - } - - return item; -} - -static bool -all_modes(MPCamera *camera, MPMode *mode) -{ - return true; -} - -static bool -available_modes(MPCamera *camera, MPMode *mode) -{ - MPMode attempt = *mode; - return mp_camera_try_mode(camera, &attempt) && - mp_mode_is_equivalent(mode, &attempt); -} - -MPModeList * -mp_camera_list_supported_modes(MPCamera *camera) -{ - if (mp_camera_is_subdev(camera)) { - return get_subdev_modes(camera, all_modes); - } else { - return get_video_modes(camera, all_modes); - } -} - -MPModeList * -mp_camera_list_available_modes(MPCamera *camera) -{ - if (mp_camera_is_subdev(camera)) { - return get_subdev_modes(camera, available_modes); - } else { - return get_video_modes(camera, available_modes); - } -} - -MPMode * -mp_camera_mode_list_get(MPModeList *list) -{ - g_return_val_if_fail(list, NULL); - return &list->mode; -} - -MPModeList * -mp_camera_mode_list_next(MPModeList *list) -{ - g_return_val_if_fail(list, NULL); - return list->next; -} - -void -mp_camera_mode_list_free(MPModeList *list) -{ - while (list) { - MPModeList *tmp = list; - list = tmp->next; - free(tmp); - } -} - struct int_str_pair { uint32_t value; const char *str; @@ -1010,24 +600,15 @@ struct _MPControlList { MPControlList *next; }; -static int -control_fd(MPCamera *camera) -{ - if (camera->subdev_fd != -1) { - return camera->subdev_fd; - } - return camera->video_fd; -} - MPControlList * -mp_camera_list_controls(MPCamera *camera) +mp_camera_list_controls(libmegapixels_camera *camera) { MPControlList *item = NULL; struct v4l2_query_ext_ctrl ctrl = {}; ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND; while (true) { - if (xioctl(control_fd(camera), VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) { + if (xioctl(camera->sensor_fd, VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) { if (errno != EINVAL) { errno_printerr("VIDIOC_QUERY_EXT_CTRL"); } @@ -1090,11 +671,13 @@ mp_control_list_free(MPControlList *list) } bool -mp_camera_query_control(MPCamera *camera, uint32_t id, MPControl *control) +mp_camera_query_control(libmegapixels_camera *camera, + uint32_t id, + MPControl *control) { struct v4l2_query_ext_ctrl ctrl = {}; ctrl.id = id; - if (xioctl(control_fd(camera), VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) { + if (xioctl(camera->sensor_fd, VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) { if (errno != EINVAL) { errno_printerr("VIDIOC_QUERY_EXT_CTRL"); } @@ -1121,7 +704,10 @@ mp_camera_query_control(MPCamera *camera, uint32_t id, MPControl *control) } static bool -control_impl_int32(MPCamera *camera, uint32_t id, int request, int32_t *value) +control_impl_int32(libmegapixels_camera *camera, + uint32_t id, + int request, + int32_t *value) { struct v4l2_ext_control ctrl = {}; ctrl.id = id; @@ -1133,7 +719,7 @@ control_impl_int32(MPCamera *camera, uint32_t id, int request, int32_t *value) .count = 1, .controls = &ctrl, }; - if (xioctl(control_fd(camera), request, &ctrls) == -1) { + if (xioctl(camera->sensor_fd, request, &ctrls) == -1) { return false; } @@ -1142,7 +728,7 @@ control_impl_int32(MPCamera *camera, uint32_t id, int request, int32_t *value) } pid_t -mp_camera_control_set_int32_bg(MPCamera *camera, uint32_t id, int32_t v) +mp_camera_control_set_int32_bg(libmegapixels_camera *camera, uint32_t id, int32_t v) { struct v4l2_ext_control ctrl = {}; ctrl.id = id; @@ -1155,7 +741,7 @@ mp_camera_control_set_int32_bg(MPCamera *camera, uint32_t id, int32_t v) .controls = &ctrl, }; - int fd = control_fd(camera); + int fd = camera->sensor_fd; // fork only after all the memory has been read pid_t pid = fork(); @@ -1174,19 +760,19 @@ mp_camera_control_set_int32_bg(MPCamera *camera, uint32_t id, int32_t v) } bool -mp_camera_control_try_int32(MPCamera *camera, uint32_t id, int32_t *v) +mp_camera_control_try_int32(libmegapixels_camera *camera, uint32_t id, int32_t *v) { return control_impl_int32(camera, id, VIDIOC_TRY_EXT_CTRLS, v); } bool -mp_camera_control_set_int32(MPCamera *camera, uint32_t id, int32_t v) +mp_camera_control_set_int32(libmegapixels_camera *camera, uint32_t id, int32_t v) { return control_impl_int32(camera, id, VIDIOC_S_EXT_CTRLS, &v); } int32_t -mp_camera_control_get_int32(MPCamera *camera, uint32_t id) +mp_camera_control_get_int32(libmegapixels_camera *camera, uint32_t id) { int32_t v = 0; control_impl_int32(camera, id, VIDIOC_G_EXT_CTRLS, &v); @@ -1194,7 +780,7 @@ mp_camera_control_get_int32(MPCamera *camera, uint32_t id) } bool -mp_camera_control_try_boolean(MPCamera *camera, uint32_t id, bool *v) +mp_camera_control_try_boolean(libmegapixels_camera *camera, uint32_t id, bool *v) { int32_t value = *v; bool s = control_impl_int32(camera, id, VIDIOC_TRY_EXT_CTRLS, &value); @@ -1203,14 +789,14 @@ mp_camera_control_try_boolean(MPCamera *camera, uint32_t id, bool *v) } bool -mp_camera_control_set_bool(MPCamera *camera, uint32_t id, bool v) +mp_camera_control_set_bool(libmegapixels_camera *camera, uint32_t id, bool v) { int32_t value = v; return control_impl_int32(camera, id, VIDIOC_S_EXT_CTRLS, &value); } bool -mp_camera_control_get_bool(MPCamera *camera, uint32_t id) +mp_camera_control_get_bool(libmegapixels_camera *camera, uint32_t id) { int32_t v = false; control_impl_int32(camera, id, VIDIOC_G_EXT_CTRLS, &v); @@ -1218,7 +804,7 @@ mp_camera_control_get_bool(MPCamera *camera, uint32_t id) } pid_t -mp_camera_control_set_bool_bg(MPCamera *camera, uint32_t id, bool v) +mp_camera_control_set_bool_bg(libmegapixels_camera *camera, uint32_t id, bool v) { int32_t value = v; return mp_camera_control_set_int32_bg(camera, id, value); diff --git a/src/camera.h b/src/camera.h index ebf7af0..f03a5fa 100644 --- a/src/camera.h +++ b/src/camera.h @@ -1,11 +1,14 @@ #pragma once -#include "mode.h" - +#include +#include #include #include #include +#define MAX_VIDEO_BUFFERS 20 +#define MAX_BG_TASKS 8 + typedef struct { uint32_t index; @@ -15,33 +18,20 @@ typedef struct { typedef struct _MPCamera MPCamera; -MPCamera *mp_camera_new(int video_fd, int subdev_fd, int bridge_fd); -void mp_camera_free(MPCamera *camera); +MPCamera *mp_camera_new(libmegapixels_camera *camera); void mp_camera_add_bg_task(MPCamera *camera, pid_t pid); void mp_camera_wait_bg_tasks(MPCamera *camera); bool mp_camera_check_task_complete(MPCamera *camera, pid_t pid); -bool mp_camera_is_subdev(MPCamera *camera); int mp_camera_get_video_fd(MPCamera *camera); -int mp_camera_get_subdev_fd(MPCamera *camera); -const MPMode *mp_camera_get_mode(const MPCamera *camera); -bool mp_camera_try_mode(MPCamera *camera, MPMode *mode); - -bool mp_camera_set_mode(MPCamera *camera, MPMode *mode); bool mp_camera_start_capture(MPCamera *camera); bool mp_camera_stop_capture(MPCamera *camera); bool mp_camera_is_capturing(MPCamera *camera); bool mp_camera_capture_buffer(MPCamera *camera, MPBuffer *buffer); bool mp_camera_release_buffer(MPCamera *camera, uint32_t buffer_index); -MPModeList *mp_camera_list_supported_modes(MPCamera *camera); -MPModeList *mp_camera_list_available_modes(MPCamera *camera); -MPMode *mp_camera_mode_list_get(MPModeList *list); -MPModeList *mp_camera_mode_list_next(MPModeList *list); -void mp_camera_mode_list_free(MPModeList *list); - typedef struct { uint32_t id; uint32_t type; @@ -65,21 +55,21 @@ const char *mp_control_type_to_str(uint32_t type); typedef struct _MPControlList MPControlList; -MPControlList *mp_camera_list_controls(MPCamera *camera); +MPControlList *mp_camera_list_controls(libmegapixels_camera *camera); MPControl *mp_control_list_get(MPControlList *list); MPControlList *mp_control_list_next(MPControlList *list); void mp_control_list_free(MPControlList *list); -bool mp_camera_query_control(MPCamera *camera, uint32_t id, MPControl *control); +bool mp_camera_query_control(libmegapixels_camera *camera, uint32_t id, MPControl *control); -bool mp_camera_control_try_int32(MPCamera *camera, uint32_t id, int32_t *v); -bool mp_camera_control_set_int32(MPCamera *camera, uint32_t id, int32_t v); -int32_t mp_camera_control_get_int32(MPCamera *camera, uint32_t id); +bool mp_camera_control_try_int32(libmegapixels_camera *camera, uint32_t id, int32_t *v); +bool mp_camera_control_set_int32(libmegapixels_camera *camera, uint32_t id, int32_t v); +int32_t mp_camera_control_get_int32(libmegapixels_camera *camera, uint32_t id); // set the value in the background, discards result -pid_t mp_camera_control_set_int32_bg(MPCamera *camera, uint32_t id, int32_t v); +pid_t mp_camera_control_set_int32_bg(libmegapixels_camera *camera, uint32_t id, int32_t v); -bool mp_camera_control_try_bool(MPCamera *camera, uint32_t id, bool *v); -bool mp_camera_control_set_bool(MPCamera *camera, uint32_t id, bool v); -bool mp_camera_control_get_bool(MPCamera *camera, uint32_t id); +bool mp_camera_control_try_bool(libmegapixels_camera *camera, uint32_t id, bool *v); +bool mp_camera_control_set_bool(libmegapixels_camera *camera, uint32_t id, bool v); +bool mp_camera_control_get_bool(libmegapixels_camera *camera, uint32_t id); // set the value in the background, discards result -pid_t mp_camera_control_set_bool_bg(MPCamera *camera, uint32_t id, bool v); +pid_t mp_camera_control_set_bool_bg(libmegapixels_camera *camera, uint32_t id, bool v); diff --git a/src/camera_config.c b/src/camera_config.c deleted file mode 100644 index 8b2ad1e..0000000 --- a/src/camera_config.c +++ /dev/null @@ -1,379 +0,0 @@ -#include "camera_config.h" - -#include "config.h" -#include "ini.h" -#include "matrix.h" -#include -#include -#include -#include -#include -#include - -static struct mp_camera_config cameras[MP_MAX_CAMERAS]; -static size_t num_cameras = 0; - -static char *exif_make; -static char *exif_model; - -static bool -find_config(char *conffile) -{ - char buf[512]; - FILE *fp; - - if (access("/proc/device-tree/compatible", F_OK) != -1) { - // Reads to compatible string of the current device tree, looks like: - // pine64,pinephone-1.2\0allwinner,sun50i-a64\0 - fp = fopen("/proc/device-tree/compatible", "r"); - fgets(buf, 512, fp); - fclose(fp); - - // Check config/%dt.ini in the current working directory - sprintf(conffile, "config/%s.ini", buf); - if (access(conffile, F_OK) != -1) { - printf("Found config file at %s\n", conffile); - return true; - } - - // Check for a config file in XDG_CONFIG_HOME - sprintf(conffile, - "%s/megapixels/config/%s.ini", - g_get_user_config_dir(), - buf); - if (access(conffile, F_OK) != -1) { - printf("Found config file at %s\n", conffile); - return true; - } - - // Check user overridden /etc/megapixels/config/$dt.ini - sprintf(conffile, "%s/megapixels/config/%s.ini", SYSCONFDIR, buf); - if (access(conffile, F_OK) != -1) { - printf("Found config file at %s\n", conffile); - return true; - } - // Check packaged /usr/share/megapixels/config/$dt.ini - sprintf(conffile, "%s/megapixels/config/%s.ini", DATADIR, buf); - if (access(conffile, F_OK) != -1) { - printf("Found config file at %s\n", conffile); - return true; - } - printf("%s not found\n", conffile); - } else { - printf("Could not read device name from device tree\n"); - } - - // If all else fails, fall back to /etc/megapixels.ini - sprintf(conffile, "/etc/megapixels.ini"); - if (access(conffile, F_OK) != -1) { - printf("Found config file at %s\n", conffile); - return true; - } - - return false; -} - -static bool -find_calibration_by_model(char *conffile, char *model, const char *sensor) -{ - // Check config/%model,%sensor.dcp in the current working directory - sprintf(conffile, "config/%s,%s.dcp", model, sensor); - if (access(conffile, F_OK) != -1) { - printf("Found calibration file at %s\n", conffile); - return true; - } - - // Check for a calibration file in XDG_CONFIG_HOME - sprintf(conffile, - "%s/megapixels/config/%s,%s.dcp", - g_get_user_config_dir(), - model, - sensor); - if (access(conffile, F_OK) != -1) { - printf("Found calibration file at %s\n", conffile); - return true; - } - - // Check user overridden /etc/megapixels/config/%model,%sensor.dcp - sprintf(conffile, - "%s/megapixels/config/%s,%s.dcp", - SYSCONFDIR, - model, - sensor); - if (access(conffile, F_OK) != -1) { - printf("Found calibration file at %s\n", conffile); - return true; - } - - // Check packaged /usr/share/megapixels/config/%model,%sensor.ini - sprintf(conffile, "%s/megapixels/config/%s,%s.dcp", DATADIR, model, sensor); - if (access(conffile, F_OK) != -1) { - printf("Found calibration file at %s\n", conffile); - return true; - } - printf("No calibration found for %s,%s\n", model, sensor); - return false; -} - -static bool -find_calibration(char *conffile, const char *sensor) -{ - char model[512]; - FILE *fp; - - if (access("/proc/device-tree/compatible", F_OK) == -1) { - return false; - } - fp = fopen("/proc/device-tree/compatible", "r"); - char *modelptr = model; - while (1) { - int c = fgetc(fp); - if (c == EOF) { - *(modelptr) = '\0'; - return find_calibration_by_model(conffile, model, sensor); - } - *(modelptr++) = (char)c; - if (c == 0) { - bool res = - find_calibration_by_model(conffile, model, sensor); - if (res) { - return true; - } - modelptr = model; - } - } -} - -static int -strtoint(const char *nptr, char **endptr, int base) -{ - long x = strtol(nptr, endptr, base); - assert(x <= INT_MAX); - return (int)x; -} - -static bool -config_handle_camera_mode(const char *prefix, - MPMode *mode, - const char *name, - const char *value) -{ - int prefix_length = strlen(prefix); - if (strncmp(prefix, name, prefix_length) != 0) - return false; - - name += prefix_length; - - if (strcmp(name, "width") == 0) { - mode->width = strtoint(value, NULL, 10); - } else if (strcmp(name, "height") == 0) { - mode->height = strtoint(value, NULL, 10); - } else if (strcmp(name, "rate") == 0) { - mode->frame_interval.numerator = 1; - mode->frame_interval.denominator = strtoint(value, NULL, 10); - } else if (strcmp(name, "fmt") == 0) { - mode->pixel_format = mp_pixel_format_from_str(value); - if (mode->pixel_format == MP_PIXEL_FMT_UNSUPPORTED) { - g_printerr("Unsupported pixelformat %s\n", value); - exit(1); - } - } else { - return false; - } - return true; -} - -static int -config_ini_handler(void *user, - const char *section, - const char *name, - const char *value) -{ - if (strcmp(section, "device") == 0) { - if (strcmp(name, "make") == 0) { - exif_make = strdup(value); - } else if (strcmp(name, "model") == 0) { - exif_model = strdup(value); - } else { - g_printerr("Unknown key '%s' in [device]\n", name); - exit(1); - } - } else { - if (num_cameras == MP_MAX_CAMERAS) { - g_printerr("More cameras defined than NUM_CAMERAS\n"); - exit(1); - } - - size_t index = 0; - for (; index < num_cameras; ++index) { - if (strcmp(cameras[index].cfg_name, section) == 0) { - break; - } - } - - if (index == num_cameras) { - printf("Adding camera %s from config\n", section); - ++num_cameras; - - cameras[index].index = index; - strcpy(cameras[index].cfg_name, section); - - char cal_path[512]; - if (find_calibration(cal_path, section)) { - cameras[index].calibration = - parse_calibration_file(cal_path); - } - } - - struct mp_camera_config *cc = &cameras[index]; - - if (config_handle_camera_mode( - "capture-", &cc->capture_mode, name, value)) { - } else if (config_handle_camera_mode( - "preview-", &cc->preview_mode, name, value)) { - } else if (strcmp(name, "rotate") == 0) { - cc->rotate = strtoint(value, NULL, 10); - } else if (strcmp(name, "mirrored") == 0) { - cc->mirrored = strcmp(value, "true") == 0; - } else if (strcmp(name, "driver") == 0) { - strcpy(cc->dev_name, value); - } else if (strcmp(name, "media-driver") == 0) { - strcpy(cc->media_dev_name, value); - } else if (strcmp(name, "media-links") == 0) { - char **linkdefs = g_strsplit(value, ",", 0); - - for (int i = 0; i < MP_MAX_LINKS && linkdefs[i] != NULL; - ++i) { - char **linkdef = g_strsplit(linkdefs[i], "->", 2); - char **porta = g_strsplit(linkdef[0], ":", 2); - char **portb = g_strsplit(linkdef[1], ":", 2); - - strcpy(cc->media_links[i].source_name, porta[0]); - strcpy(cc->media_links[i].target_name, portb[0]); - cc->media_links[i].source_port = - strtoint(porta[1], NULL, 10); - cc->media_links[i].target_port = - strtoint(portb[1], NULL, 10); - - g_strfreev(portb); - g_strfreev(porta); - g_strfreev(linkdef); - ++cc->num_media_links; - } - g_strfreev(linkdefs); - } else if (strcmp(name, "colormatrix") == 0) { - sscanf(value, - "%f,%f,%f,%f,%f,%f,%f,%f,%f", - cc->colormatrix + 0, - cc->colormatrix + 1, - cc->colormatrix + 2, - cc->colormatrix + 3, - cc->colormatrix + 4, - cc->colormatrix + 5, - cc->colormatrix + 6, - cc->colormatrix + 7, - cc->colormatrix + 8); - } else if (strcmp(name, "forwardmatrix") == 0) { - sscanf(value, - "%f,%f,%f,%f,%f,%f,%f,%f,%f", - cc->forwardmatrix + 0, - cc->forwardmatrix + 1, - cc->forwardmatrix + 2, - cc->forwardmatrix + 3, - cc->forwardmatrix + 4, - cc->forwardmatrix + 5, - cc->forwardmatrix + 6, - cc->forwardmatrix + 7, - cc->forwardmatrix + 8); - } else if (strcmp(name, "whitelevel") == 0) { - cc->whitelevel = strtoint(value, NULL, 10); - } else if (strcmp(name, "blacklevel") == 0) { - cc->blacklevel = strtoint(value, NULL, 10); - } else if (strcmp(name, "focallength") == 0) { - cc->focallength = strtof(value, NULL); - } else if (strcmp(name, "cropfactor") == 0) { - cc->cropfactor = strtof(value, NULL); - } else if (strcmp(name, "fnumber") == 0) { - cc->fnumber = strtod(value, NULL); - } else if (strcmp(name, "iso-min") == 0) { - cc->iso_min = strtod(value, NULL); - } else if (strcmp(name, "iso-max") == 0) { - cc->iso_max = strtod(value, NULL); - } else if (strcmp(name, "flash-path") == 0) { - strcpy(cc->flash_path, value); - cc->has_flash = true; - } else if (strcmp(name, "flash-display") == 0) { - cc->flash_display = strcmp(value, "true") == 0; - - if (cc->flash_display) { - cc->has_flash = true; - } - } else { - g_printerr("Unknown key '%s' in [%s]\n", name, section); - exit(1); - } - } - return 1; -} - -void -calculate_matrices() -{ - for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) { - if (cameras[i].colormatrix != NULL && - cameras[i].forwardmatrix != NULL) { - multiply_matrices(cameras[i].colormatrix, - cameras[i].forwardmatrix, - cameras[i].previewmatrix); - } - } -} - -bool -mp_load_config() -{ - char file[512]; - if (!find_config(file)) { - g_printerr("Could not find any config file\n"); - return false; - } - - int result = ini_parse(file, config_ini_handler, NULL); - if (result == -1) { - g_printerr("Config file not found\n"); - return false; - } - if (result == -2) { - g_printerr("Could not allocate memory to parse config file\n"); - return false; - } - if (result != 0) { - g_printerr("Could not parse config file\n"); - return false; - } - - calculate_matrices(); - - return true; -} - -const char * -mp_get_device_make() -{ - return exif_make; -} - -const char * -mp_get_device_model() -{ - return exif_model; -} - -const struct mp_camera_config * -mp_get_camera_config(size_t index) -{ - if (index >= num_cameras) - return NULL; - - return &cameras[index]; -} diff --git a/src/camera_config.h b/src/camera_config.h deleted file mode 100644 index eb060e4..0000000 --- a/src/camera_config.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "dcp.h" -#include "mode.h" - -#include -#include - -#define MP_MAX_CAMERAS 5 -#define MP_MAX_LINKS 10 - -struct mp_media_link_config { - char source_name[100]; - char target_name[100]; - int source_port; - int target_port; -}; - -struct mp_camera_config { - size_t index; - - char cfg_name[100]; - char dev_name[260]; - char media_dev_name[260]; - - MPMode capture_mode; - MPMode preview_mode; - int rotate; - bool mirrored; - - struct mp_media_link_config media_links[MP_MAX_LINKS]; - int num_media_links; - - float colormatrix[9]; - float forwardmatrix[9]; - float previewmatrix[9]; - int blacklevel; - int whitelevel; - - struct MPCameraCalibration calibration; - - float focallength; - float cropfactor; - double fnumber; - int iso_min; - int iso_max; - - char flash_path[260]; - bool flash_display; - bool has_flash; -}; - -bool mp_load_config(); - -const char *mp_get_device_make(); -const char *mp_get_device_model(); -const struct mp_camera_config *mp_get_camera_config(size_t index); diff --git a/src/device.c b/src/device.c deleted file mode 100644 index b4d5f80..0000000 --- a/src/device.c +++ /dev/null @@ -1,536 +0,0 @@ -#include "device.h" -#include "mode.h" - -#include -#include -#include -#include -#include -#include -#include - -bool -mp_find_device_path(struct media_v2_intf_devnode devnode, char *path, int length) -{ - char uevent_path[256]; - snprintf(uevent_path, - 256, - "/sys/dev/char/%d:%d/uevent", - devnode.major, - devnode.minor); - - FILE *f = fopen(uevent_path, "r"); - if (!f) { - return false; - } - - char line[512]; - while (fgets(line, 512, f)) { - if (strncmp(line, "DEVNAME=", 8) == 0) { - // Drop newline - int length = strlen(line); - if (line[length - 1] == '\n') - line[length - 1] = '\0'; - - snprintf(path, length, "/dev/%s", line + 8); - return true; - } - } - - fclose(f); - - return false; -} - -struct _MPDevice { - int fd; - - struct media_device_info info; - - struct media_v2_entity *entities; - size_t num_entities; - struct media_v2_interface *interfaces; - size_t num_interfaces; - struct media_v2_pad *pads; - size_t num_pads; - struct media_v2_link *links; - size_t num_links; -}; - -static void -errno_printerr(const char *s) -{ - g_printerr("MPDevice: %s error %d, %s\n", s, errno, strerror(errno)); -} - -static int -xioctl(int fd, int request, void *arg) -{ - int r; - do { - r = ioctl(fd, request, arg); - } while (r == -1 && errno == EINTR); - return r; -} - -MPDevice * -mp_device_find(const char *driver_name, const char *dev_name) -{ - MPDeviceList *list = mp_device_list_new(); - - MPDevice *found_device = - mp_device_list_find_remove(&list, driver_name, dev_name); - - mp_device_list_free(list); - - return found_device; -} - -MPDevice * -mp_device_open(const char *path) -{ - int fd = open(path, O_RDWR); - if (fd == -1) { - errno_printerr("open"); - return NULL; - } - - return mp_device_new(fd); -} - -MPDevice * -mp_device_new(int fd) -{ - // Get the topology of the media device - struct media_v2_topology topology = {}; - if (xioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology) == -1 || - topology.num_entities == 0) { - close(fd); - return NULL; - } - - // Create the device - MPDevice *device = calloc(1, sizeof(MPDevice)); - device->fd = fd; - device->entities = - calloc(topology.num_entities, sizeof(struct media_v2_entity)); - device->num_entities = topology.num_entities; - device->interfaces = - calloc(topology.num_interfaces, sizeof(struct media_v2_interface)); - device->num_interfaces = topology.num_interfaces; - device->pads = calloc(topology.num_pads, sizeof(struct media_v2_pad)); - device->num_pads = topology.num_pads; - device->links = calloc(topology.num_links, sizeof(struct media_v2_link)); - device->num_links = topology.num_links; - - // Get the actual devices and interfaces - topology.ptr_entities = (uint64_t)device->entities; - topology.ptr_interfaces = (uint64_t)device->interfaces; - topology.ptr_pads = (uint64_t)device->pads; - topology.ptr_links = (uint64_t)device->links; - if (xioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology) == -1) { - errno_printerr("MEDIA_IOC_G_TOPOLOGY"); - mp_device_close(device); - return NULL; - } - - // Get device info - if (xioctl(fd, MEDIA_IOC_DEVICE_INFO, &device->info) == -1) { - errno_printerr("MEDIA_IOC_DEVICE_INFO"); - mp_device_close(device); - return NULL; - } - - return device; -} - -void -mp_device_close(MPDevice *device) -{ - close(device->fd); - free(device->entities); - free(device->interfaces); - free(device->pads); - free(device->links); - free(device); -} - -int -mp_device_get_fd(const MPDevice *device) -{ - return device->fd; -} - -bool -mp_device_setup_entity_link(MPDevice *device, - uint32_t source_entity_id, - uint32_t sink_entity_id, - uint32_t source_index, - uint32_t sink_index, - bool enabled) -{ - struct media_link_desc link = {}; - link.flags = enabled ? MEDIA_LNK_FL_ENABLED : 0; - link.source.entity = source_entity_id; - link.source.index = source_index; - link.sink.entity = sink_entity_id; - link.sink.index = sink_index; - if (xioctl(device->fd, MEDIA_IOC_SETUP_LINK, &link) == -1) { - errno_printerr("MEDIA_IOC_SETUP_LINK"); - return false; - } - - return true; -} - -bool -mp_device_setup_link(MPDevice *device, - uint32_t source_pad_id, - uint32_t sink_pad_id, - bool enabled) -{ - const struct media_v2_pad *source_pad = - mp_device_get_pad(device, source_pad_id); - g_return_val_if_fail(source_pad, false); - - const struct media_v2_pad *sink_pad = mp_device_get_pad(device, sink_pad_id); - g_return_val_if_fail(sink_pad, false); - - return mp_device_setup_entity_link( - device, source_pad->entity_id, sink_pad->entity_id, 0, 0, enabled); -} - -bool -mp_entity_pad_set_format(MPDevice *device, - const struct media_v2_entity *entity, - uint32_t pad, - MPMode *mode) -{ - const struct media_v2_interface *interface = - mp_device_find_entity_interface(device, entity->id); - char path[260]; - if (!mp_find_device_path(interface->devnode, path, 260)) { - g_printerr("Could not find path to %s\n", entity->name); - return false; - } - - int fd = open(path, O_WRONLY); - if (fd == -1) { - errno_printerr("open"); - return false; - } - - struct v4l2_subdev_format fmt = {}; - fmt.pad = pad; - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - fmt.format.width = mode->width; - fmt.format.height = mode->height; - fmt.format.code = mp_pixel_format_to_v4l_bus_code(mode->pixel_format); - fmt.format.field = V4L2_FIELD_ANY; - if (xioctl(fd, VIDIOC_SUBDEV_S_FMT, &fmt) == -1) { - errno_printerr("VIDIOC_SUBDEV_S_FMT"); - return false; - } - - close(fd); - - return true; -} - -const struct media_v2_entity * -mp_device_find_entity(const MPDevice *device, const char *driver_name) -{ - int length = strlen(driver_name); - - // Find the entity from the name - for (uint32_t i = 0; i < device->num_entities; ++i) { - if (strncmp(device->entities[i].name, driver_name, length) == 0) { - return &device->entities[i]; - } - } - return NULL; -} - -const struct media_v2_entity * -mp_device_find_entity_type(const MPDevice *device, const uint32_t type) -{ - // Find the entity from the entity type - for (uint32_t i = 0; i < device->num_entities; ++i) { - if (device->entities[i].function == type) { - return &device->entities[i]; - } - } - return NULL; -} - -const struct media_device_info * -mp_device_get_info(const MPDevice *device) -{ - return &device->info; -} - -const struct media_v2_entity * -mp_device_get_entity(const MPDevice *device, uint32_t id) -{ - for (int i = 0; i < device->num_entities; ++i) { - if (device->entities[i].id == id) { - return &device->entities[i]; - } - } - return NULL; -} - -const struct media_v2_entity * -mp_device_get_entities(const MPDevice *device) -{ - return device->entities; -} - -size_t -mp_device_get_num_entities(const MPDevice *device) -{ - return device->num_entities; -} - -const struct media_v2_interface * -mp_device_find_entity_interface(const MPDevice *device, uint32_t entity_id) -{ - // Find the interface through the link - const struct media_v2_link *link = mp_device_find_link_to(device, entity_id); - if (!link) { - return NULL; - } - return mp_device_get_interface(device, link->source_id); -} - -const struct media_v2_interface * -mp_device_get_interface(const MPDevice *device, uint32_t id) -{ - for (int i = 0; i < device->num_interfaces; ++i) { - if (device->interfaces[i].id == id) { - return &device->interfaces[i]; - } - } - return NULL; -} - -const struct media_v2_interface * -mp_device_get_interfaces(const MPDevice *device) -{ - return device->interfaces; -} - -size_t -mp_device_get_num_interfaces(const MPDevice *device) -{ - return device->num_interfaces; -} - -const struct media_v2_pad * -mp_device_get_pad_from_entity(const MPDevice *device, uint32_t entity_id) -{ - for (int i = 0; i < device->num_pads; ++i) { - if (device->pads[i].entity_id == entity_id) { - return &device->pads[i]; - } - } - return NULL; -} - -const struct media_v2_pad * -mp_device_get_pad(const MPDevice *device, uint32_t id) -{ - for (int i = 0; i < device->num_pads; ++i) { - if (device->pads[i].id == id) { - return &device->pads[i]; - } - } - return NULL; -} - -const struct media_v2_pad * -mp_device_get_pads(const MPDevice *device) -{ - return device->pads; -} - -size_t -mp_device_get_num_pads(const MPDevice *device) -{ - return device->num_pads; -} - -const struct media_v2_link * -mp_device_find_entity_link(const MPDevice *device, uint32_t entity_id) -{ - const struct media_v2_pad *pad = - mp_device_get_pad_from_entity(device, entity_id); - const struct media_v2_link *link = mp_device_find_link_to(device, pad->id); - if (link) { - return link; - } - return mp_device_find_link_from(device, pad->id); -} - -const struct media_v2_link * -mp_device_find_link_from(const MPDevice *device, uint32_t source) -{ - for (int i = 0; i < device->num_links; ++i) { - if (device->links[i].source_id == source) { - return &device->links[i]; - } - } - return NULL; -} - -const struct media_v2_link * -mp_device_find_link_to(const MPDevice *device, uint32_t sink) -{ - for (int i = 0; i < device->num_links; ++i) { - if (device->links[i].sink_id == sink) { - return &device->links[i]; - } - } - return NULL; -} - -const struct media_v2_link * -mp_device_find_link_between(const MPDevice *device, uint32_t source, uint32_t sink) -{ - for (int i = 0; i < device->num_links; ++i) { - if (device->links[i].source_id == source && - device->links[i].sink_id == sink) { - return &device->links[i]; - } - } - return NULL; -} - -const struct media_v2_link * -mp_device_get_link(const MPDevice *device, uint32_t id) -{ - for (int i = 0; i < device->num_links; ++i) { - if (device->links[i].id == id) { - return &device->links[i]; - } - } - return NULL; -} - -const struct media_v2_link * -mp_device_get_links(const MPDevice *device) -{ - return device->links; -} - -size_t -mp_device_get_num_links(const MPDevice *device) -{ - return device->num_links; -} - -struct _MPDeviceList { - MPDevice *device; - MPDeviceList *next; - char path[PATH_MAX]; -}; - -MPDeviceList * -mp_device_list_new() -{ - MPDeviceList *current = NULL; - - // Enumerate media device files - struct dirent *dir; - DIR *d = opendir("/dev"); - while ((dir = readdir(d)) != NULL) { - if (strncmp(dir->d_name, "media", 5) == 0) { - char path[PATH_MAX]; - snprintf(path, PATH_MAX, "/dev/%s", dir->d_name); - - MPDevice *device = mp_device_open(path); - - if (device) { - MPDeviceList *next = malloc(sizeof(MPDeviceList)); - next->device = device; - next->next = current; - memcpy(next->path, path, sizeof(path)); - current = next; - } - } - } - closedir(d); - - return current; -} - -void -mp_device_list_free(MPDeviceList *device_list) -{ - while (device_list) { - MPDeviceList *tmp = device_list; - device_list = tmp->next; - - mp_device_close(tmp->device); - free(tmp); - } -} - -MPDevice * -mp_device_list_find_remove(MPDeviceList **list, - const char *driver_name, - const char *dev_name) -{ - MPDevice *found_device = NULL; - int length = strlen(driver_name); - - while (*list) { - MPDevice *device = mp_device_list_get(*list); - const struct media_device_info *info = mp_device_get_info(device); - - if (strncmp(info->driver, driver_name, length) == 0 && - mp_device_find_entity(device, dev_name)) { - found_device = mp_device_list_remove(list); - break; - } - - list = &(*list)->next; - } - - return found_device; -} - -MPDevice * -mp_device_list_remove(MPDeviceList **device_list) -{ - MPDevice *device = (*device_list)->device; - - if ((*device_list)->next) { - MPDeviceList *tmp = (*device_list)->next; - **device_list = *tmp; - free(tmp); - } else { - free(*device_list); - *device_list = NULL; - } - - return device; -} - -MPDevice * -mp_device_list_get(const MPDeviceList *device_list) -{ - return device_list->device; -} - -const char * -mp_device_list_get_path(const MPDeviceList *device_list) -{ - return device_list->path; -} - -MPDeviceList * -mp_device_list_next(const MPDeviceList *device_list) -{ - return device_list->next; -} diff --git a/src/device.h b/src/device.h deleted file mode 100644 index 1894c67..0000000 --- a/src/device.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -#include "mode.h" - -#include -#include -#include -#include - -bool -mp_find_device_path(struct media_v2_intf_devnode devnode, char *path, int length); - -typedef struct _MPDevice MPDevice; - -MPDevice *mp_device_find(const char *driver_name, const char *dev_name); -MPDevice *mp_device_open(const char *path); -MPDevice *mp_device_new(int fd); -void mp_device_close(MPDevice *device); - -int mp_device_get_fd(const MPDevice *device); - -bool mp_device_setup_entity_link(MPDevice *device, - uint32_t source_entity_id, - uint32_t sink_entity_id, - uint32_t source_index, - uint32_t sink_index, - bool enabled); - -bool mp_device_setup_link(MPDevice *device, - uint32_t source_pad_id, - uint32_t sink_pad_id, - bool enabled); - -bool mp_entity_pad_set_format(MPDevice *device, - const struct media_v2_entity *entity, - uint32_t pad, - MPMode *mode); - -const struct media_device_info *mp_device_get_info(const MPDevice *device); -const struct media_v2_entity *mp_device_find_entity(const MPDevice *device, - const char *driver_name); -const struct media_v2_entity *mp_device_find_entity_type(const MPDevice *device, - const uint32_t type); -const struct media_v2_entity *mp_device_get_entity(const MPDevice *device, - uint32_t id); -const struct media_v2_entity *mp_device_get_entities(const MPDevice *device); -size_t mp_device_get_num_entities(const MPDevice *device); -const struct media_v2_interface * -mp_device_find_entity_interface(const MPDevice *device, uint32_t entity_id); -const struct media_v2_interface *mp_device_get_interface(const MPDevice *device, - uint32_t id); -const struct media_v2_interface *mp_device_get_interfaces(const MPDevice *device); -size_t mp_device_get_num_interfaces(const MPDevice *device); -const struct media_v2_pad *mp_device_get_pad_from_entity(const MPDevice *device, - uint32_t entity_id); -const struct media_v2_pad *mp_device_get_pad(const MPDevice *device, uint32_t id); -const struct media_v2_pad *mp_device_get_pads(const MPDevice *device); -size_t mp_device_get_num_pads(const MPDevice *device); -const struct media_v2_link *mp_device_find_entity_link(const MPDevice *device, - uint32_t entity_id); -const struct media_v2_link *mp_device_find_link_from(const MPDevice *device, - uint32_t source); -const struct media_v2_link *mp_device_find_link_to(const MPDevice *device, - uint32_t sink); -const struct media_v2_link * -mp_device_find_link_between(const MPDevice *device, uint32_t source, uint32_t sink); -const struct media_v2_link *mp_device_get_link(const MPDevice *device, uint32_t id); -const struct media_v2_link *mp_device_get_links(const MPDevice *device); -size_t mp_device_get_num_links(const MPDevice *device); - -typedef struct _MPDeviceList MPDeviceList; - -MPDeviceList *mp_device_list_new(); -void mp_device_list_free(MPDeviceList *device_list); - -MPDevice *mp_device_list_find_remove(MPDeviceList **device_list, - const char *driver_name, - const char *dev_name); -MPDevice *mp_device_list_remove(MPDeviceList **device_list); - -MPDevice *mp_device_list_get(const MPDeviceList *device_list); -const char *mp_device_list_get_path(const MPDeviceList *device_list); -MPDeviceList *mp_device_list_next(const MPDeviceList *device_list); diff --git a/src/gles2_debayer.c b/src/gles2_debayer.c index db56207..75d84ee 100644 --- a/src/gles2_debayer.c +++ b/src/gles2_debayer.c @@ -8,7 +8,7 @@ #define TEX_COORD_ATTRIBUTE 1 struct _GLES2Debayer { - MPPixelFormat format; + int format; GLuint frame_buffer; GLuint program; @@ -23,12 +23,13 @@ struct _GLES2Debayer { }; GLES2Debayer * -gles2_debayer_new(MPPixelFormat format) +gles2_debayer_new(int format) { - if (format != MP_PIXEL_FMT_BGGR8 && format != MP_PIXEL_FMT_GBRG8 && - format != MP_PIXEL_FMT_GRBG8 && format != MP_PIXEL_FMT_RGGB8 && - format != MP_PIXEL_FMT_BGGR10P && format != MP_PIXEL_FMT_GBRG10P && - format != MP_PIXEL_FMT_GRBG10P && format != MP_PIXEL_FMT_RGGB10P) { + uint32_t pixfmt = libmegapixels_format_to_v4l_pixfmt(format); + if (pixfmt != V4L2_PIX_FMT_SBGGR8 && pixfmt != V4L2_PIX_FMT_SGBRG8 && + pixfmt != V4L2_PIX_FMT_SGRBG8 && pixfmt != V4L2_PIX_FMT_SRGGB8 && + pixfmt != V4L2_PIX_FMT_SBGGR10P && pixfmt != V4L2_PIX_FMT_SGBRG10P && + pixfmt != V4L2_PIX_FMT_SGRBG10P && pixfmt != V4L2_PIX_FMT_SRGGB10P) { return NULL; } @@ -40,8 +41,8 @@ gles2_debayer_new(MPPixelFormat format) snprintf(format_def, 64, "#define CFA_%s\n#define BITS_%d\n", - mp_pixel_format_cfa(format), - mp_pixel_format_bits_per_pixel(format)); + libmegapixels_format_cfa_pattern(format), + libmegapixels_format_bits_per_pixel(format)); const GLchar *def[1] = { format_def }; @@ -74,7 +75,7 @@ gles2_debayer_new(MPPixelFormat format) self->uniform_texture = glGetUniformLocation(self->program, "texture"); self->uniform_color_matrix = glGetUniformLocation(self->program, "color_matrix"); - if (mp_pixel_format_bits_per_pixel(self->format) == 10) + if (libmegapixels_format_bits_per_pixel(self->format) == 10) self->uniform_row_length = glGetUniformLocation(self->program, "row_length"); check_gl(); @@ -97,6 +98,7 @@ gles2_debayer_free(GLES2Debayer *self) void gles2_debayer_use(GLES2Debayer *self) { + assert(self != NULL); glUseProgram(self->program); check_gl(); @@ -159,15 +161,15 @@ gles2_debayer_configure(GLES2Debayer *self, } check_gl(); - GLuint row_length = mp_pixel_format_width_to_bytes(self->format, src_width); - if (mp_pixel_format_bits_per_pixel(self->format) == 10) { + GLuint row_length = libmegapixels_mode_width_to_bytes(self->format, src_width); + if (libmegapixels_format_bits_per_pixel(self->format) == 10) { assert(src_width % 4 == 0); glUniform1f(self->uniform_row_length, row_length); check_gl(); } GLuint padding_bytes = - mp_pixel_format_width_to_padding(self->format, src_width); + libmegapixels_mode_width_to_padding(self->format, src_width); GLfloat padding_ratio = (float)row_length / (row_length + padding_bytes); glUniform1f(self->uniform_padding_ratio, padding_ratio); } diff --git a/src/gles2_debayer.h b/src/gles2_debayer.h index 6984596..330190b 100644 --- a/src/gles2_debayer.h +++ b/src/gles2_debayer.h @@ -5,7 +5,7 @@ typedef struct _GLES2Debayer GLES2Debayer; -GLES2Debayer *gles2_debayer_new(MPPixelFormat format); +GLES2Debayer *gles2_debayer_new(int format); void gles2_debayer_free(GLES2Debayer *self); void gles2_debayer_use(GLES2Debayer *self); diff --git a/src/io_pipeline.c b/src/io_pipeline.c index a94bf3b..edaa097 100644 --- a/src/io_pipeline.c +++ b/src/io_pipeline.c @@ -1,7 +1,6 @@ #include "io_pipeline.h" #include "camera.h" -#include "device.h" #include "flash.h" #include "pipeline.h" #include "process_pipeline.h" @@ -14,62 +13,10 @@ #include #include -struct media_link_info { - unsigned int source_entity_id; - unsigned int target_entity_id; - char source_fname[260]; - char target_fname[260]; -}; - -struct camera_info { - size_t device_index; - - unsigned int pad_id; - - char dev_fname[260]; - int fd; - - MPCamera *camera; - - MPFlash *flash; - - int gain_ctrl; - int gain_max; - - bool has_auto_focus_continuous; - bool has_auto_focus_start; - - // unsigned int entity_id; - // enum v4l2_buf_type type; - - // char media_dev_fname[260]; - // char video_dev_fname[260]; - // int media_fd; - - // struct mp_media_link media_links[MP_MAX_LINKS]; - // int num_media_links; - - // int gain_ctrl; -}; - -struct device_info { - const char *media_dev_name; // owned by camera config - const char *dev_name; // owned by camera config - - MPDevice *device; - - unsigned int interface_pad_id; - - int video_fd; -}; - -static struct camera_info cameras[MP_MAX_CAMERAS]; - -static struct device_info devices[MP_MAX_CAMERAS]; -static size_t num_devices = 0; - -static const struct mp_camera_config *camera = NULL; -static MPMode mode; +libmegapixels_camera *io_camera = NULL; +libmegapixels_mode *mode_capture = NULL; +libmegapixels_mode *mode_preview = NULL; +MPCamera *mpcamera = NULL; static bool just_switched_mode = false; static int blank_frame_count = 0; @@ -100,240 +47,10 @@ static bool want_focus = false; static MPPipeline *pipeline; static GSource *capture_source; -static void -mp_setup_media_link_pad_formats(struct device_info *dev_info, - const struct mp_media_link_config media_links[], - int num_media_links, - MPMode *mode) -{ - const struct media_v2_entity *entities[2]; - int ports[2]; - for (int i = 0; i < num_media_links; i++) { - entities[0] = mp_device_find_entity( - dev_info->device, (const char *)media_links[i].source_name); - entities[1] = mp_device_find_entity( - dev_info->device, (const char *)media_links[i].target_name); - ports[0] = media_links[i].source_port; - ports[1] = media_links[i].target_port; - - for (int j = 0; j < 2; j++) - if (!mp_entity_pad_set_format( - dev_info->device, entities[j], ports[j], mode)) { - g_printerr("Failed to set %s:%d format\n", - entities[j]->name, - ports[j]); - exit(EXIT_FAILURE); - } - } -} - -static int -get_bridge_fd(const MPDevice *device) -{ - const struct media_v2_entity *bridge = - mp_device_find_entity_type(device, MEDIA_ENT_F_VID_IF_BRIDGE); - if (!bridge) { - g_printerr("Could not find device bridge entity\n"); - return -1; - } - - const struct media_v2_interface *bridge_interface = - mp_device_find_entity_interface(device, bridge->id); - char dev_name[260]; - if (!mp_find_device_path(bridge_interface->devnode, dev_name, 260)) { - g_printerr("Could not find bridge path\n"); - return -1; - } - - int bridge_fd = open(dev_name, O_RDWR); - if (bridge_fd == -1) { - g_printerr("Could not open %s: %s\n", dev_name, strerror(errno)); - } - - return bridge_fd; -} - -static void -setup_camera(MPDeviceList **device_list, const struct mp_camera_config *config) -{ - // Find device info - size_t device_index = 0; - for (; device_index < num_devices; ++device_index) { - if ((strcmp(config->media_dev_name, - devices[device_index].media_dev_name) == 0) && - (strcmp(config->dev_name, devices[device_index].dev_name) == - 0)) { - break; - } - } - - if (device_index == num_devices) { - device_index = num_devices; - - // Initialize new device - struct device_info *info = &devices[device_index]; - info->media_dev_name = config->media_dev_name; - info->dev_name = config->dev_name; - info->device = mp_device_list_find_remove( - device_list, info->media_dev_name, info->dev_name); - if (!info->device) { - g_printerr("Could not find /dev/media* node matching '%s'\n", - info->media_dev_name); - exit(EXIT_FAILURE); - } - - const struct media_v2_entity *entity = - mp_device_find_entity_type(info->device, MEDIA_ENT_F_IO_V4L); - if (!entity) { - g_printerr("Could not find device video entity\n"); - exit(EXIT_FAILURE); - } - - const struct media_v2_entity *bridge = mp_device_find_entity_type( - info->device, MEDIA_ENT_F_VID_IF_BRIDGE); - if (!bridge) { - g_printerr("Could not find device bridge entity\n"); - bridge = entity; - } - - const struct media_v2_pad *pad = - mp_device_get_pad_from_entity(info->device, bridge->id); - info->interface_pad_id = pad->id; - - const struct media_v2_interface *interface = - mp_device_find_entity_interface(info->device, entity->id); - char dev_name[260]; - if (!mp_find_device_path(interface->devnode, dev_name, 260)) { - g_printerr("Could not find video path\n"); - exit(EXIT_FAILURE); - } - - info->video_fd = open(dev_name, O_RDWR); - if (info->video_fd == -1) { - g_printerr("Could not open %s: %s\n", - dev_name, - strerror(errno)); - exit(EXIT_FAILURE); - } - - ++num_devices; - } - - { - struct camera_info *info = &cameras[config->index]; - struct device_info *dev_info = &devices[device_index]; - - info->device_index = device_index; - - const struct media_v2_entity *entity = - mp_device_find_entity(dev_info->device, config->dev_name); - if (!entity) { - g_printerr("Could not find camera entity matching '%s'\n", - config->dev_name); - exit(EXIT_FAILURE); - } - - const struct media_v2_pad *pad = - mp_device_get_pad_from_entity(dev_info->device, entity->id); - - info->pad_id = pad->id; - - // Make sure the camera starts out as disabled - mp_device_setup_link(dev_info->device, - info->pad_id, - dev_info->interface_pad_id, - false); - - const struct media_v2_interface *interface = - mp_device_find_entity_interface(dev_info->device, - entity->id); - - if (!mp_find_device_path(interface->devnode, info->dev_fname, 260)) { - g_printerr("Could not find camera device path\n"); - exit(EXIT_FAILURE); - } - - info->fd = open(info->dev_fname, O_RDWR); - if (info->fd == -1) { - g_printerr("Could not open %s: %s\n", - info->dev_fname, - strerror(errno)); - exit(EXIT_FAILURE); - } - - int bridge_fd = get_bridge_fd(dev_info->device); - info->camera = - mp_camera_new(dev_info->video_fd, info->fd, bridge_fd); - - // Start with the capture format, this works around a bug with - // the ov5640 driver where it won't allow setting the preview - // format initially. - MPMode mode = config->capture_mode; - if (config->num_media_links) - mp_setup_media_link_pad_formats(dev_info, - config->media_links, - config->num_media_links, - &mode); - mp_camera_set_mode(info->camera, &mode); - - // Trigger continuous auto focus if the sensor supports it - if (mp_camera_query_control( - info->camera, V4L2_CID_FOCUS_AUTO, NULL)) { - info->has_auto_focus_continuous = true; - mp_camera_control_set_bool_bg( - info->camera, V4L2_CID_FOCUS_AUTO, true); - } - if (mp_camera_query_control( - info->camera, V4L2_CID_AUTO_FOCUS_START, NULL)) { - info->has_auto_focus_start = true; - } - - MPControl control; - if (mp_camera_query_control(info->camera, V4L2_CID_GAIN, &control)) { - info->gain_ctrl = V4L2_CID_GAIN; - info->gain_max = control.max; - } else if (mp_camera_query_control( - info->camera, V4L2_CID_ANALOGUE_GAIN, &control)) { - info->gain_ctrl = V4L2_CID_ANALOGUE_GAIN; - info->gain_max = control.max; - } - - // Setup flash - if (config->flash_path[0]) { - info->flash = mp_led_flash_from_path(config->flash_path); - } else if (config->flash_display) { - info->flash = mp_create_display_flash(); - } else { - info->flash = NULL; - } - } -} - static void setup(MPPipeline *pipeline, const void *data) { - for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) { - const struct mp_camera_config *config = mp_get_camera_config(i); - if (!config) { - break; - } - - MPDeviceList *device_list = mp_device_list_new(); - setup_camera(&device_list, config); - mp_device_list_free(device_list); - } -} - -static void -clean_cameras() -{ - for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) { - struct camera_info *info = &cameras[i]; - if (info->camera) { - mp_camera_free(info->camera); - info->camera = NULL; - } - } + return; } void @@ -353,8 +70,6 @@ mp_io_pipeline_stop() g_source_destroy(capture_source); } - clean_cameras(); - mp_pipeline_free(pipeline); mp_process_pipeline_stop(); @@ -363,21 +78,22 @@ mp_io_pipeline_stop() static void update_process_pipeline() { - struct camera_info *info = &cameras[camera->index]; - // Grab the latest control values if (!current_controls.gain_is_manual) { - current_controls.gain = - mp_camera_control_get_int32(info->camera, info->gain_ctrl); + // current_controls.gain = + // mp_camera_control_get_int32(info->camera, + // info->gain_ctrl); } if (!current_controls.exposure_is_manual) { - current_controls.exposure = - mp_camera_control_get_int32(info->camera, V4L2_CID_EXPOSURE); + // current_controls.exposure = + // mp_camera_control_get_int32(info->camera, + // V4L2_CID_EXPOSURE); } MPControl control; float balance_red = 1.0f; float balance_blue = 1.0f; + /* if (mp_camera_query_control(info->camera, V4L2_CID_RED_BALANCE, &control)) { int red = mp_camera_control_get_int32(info->camera, V4L2_CID_RED_BALANCE); @@ -386,23 +102,23 @@ update_process_pipeline() balance_red = (float)red / (float)control.max; balance_blue = (float)blue / (float)control.max; } + */ struct mp_process_pipeline_state pipeline_state = { - .camera = camera, - .mode = mode, + .camera = io_camera, .burst_length = burst_length, .preview_width = preview_width, .preview_height = preview_height, .device_rotation = device_rotation, .gain_is_manual = current_controls.gain_is_manual, .gain = current_controls.gain, - .gain_max = info->gain_max, + .gain_max = 1, // TODO: Fix .balance_red = balance_red, .balance_blue = balance_blue, .exposure_is_manual = current_controls.exposure_is_manual, .exposure = current_controls.exposure, - .has_auto_focus_continuous = info->has_auto_focus_continuous, - .has_auto_focus_start = info->has_auto_focus_start, + .has_auto_focus_continuous = false, // TODO: fix + .has_auto_focus_start = false, // TODO: fix .flash_enabled = flash_enabled, }; mp_process_pipeline_update_state(&pipeline_state); @@ -423,44 +139,39 @@ mp_io_pipeline_focus() static void capture(MPPipeline *pipeline, const void *data) { - struct camera_info *info = &cameras[camera->index]; - struct device_info *dev_info = &devices[info->device_index]; uint32_t gain; float gain_norm; // Disable the autogain/exposure while taking the burst + /* TODO: Fix mp_camera_control_set_int32(info->camera, V4L2_CID_AUTOGAIN, 0); mp_camera_control_set_int32( info->camera, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL); + */ // Get current gain to calculate a burst length; // with low gain there's 3, with the max automatic gain of the ov5640 // the value seems to be 248 which creates a 5 frame burst // for manual gain you can go up to 11 frames - gain = mp_camera_control_get_int32(info->camera, V4L2_CID_GAIN); - gain_norm = (float)gain / (float)info->gain_max; - burst_length = (int)fmax(sqrt(gain_norm) * 10, 2) + 1; + gain = mp_camera_control_get_int32(io_camera, V4L2_CID_GAIN); + // gain_norm = (float)gain / (float)mpcamera.gain_max; + // burst_length = (int)fmax(sqrt(gain_norm) * 10, 2) + 1; captures_remaining = burst_length; // Change camera mode for capturing mp_process_pipeline_sync(); - mp_camera_stop_capture(info->camera); - - mode = camera->capture_mode; - if (camera->num_media_links) - mp_setup_media_link_pad_formats(dev_info, - camera->media_links, - camera->num_media_links, - &mode); - mp_camera_set_mode(info->camera, &mode); + mp_camera_stop_capture(mpcamera); + libmegapixels_select_mode(io_camera, mode_capture); just_switched_mode = true; - mp_camera_start_capture(info->camera); + mp_camera_start_capture(mpcamera); // Enable flash + /* TODO: implement if (info->flash && flash_enabled) { mp_flash_enable(info->flash); } + */ update_process_pipeline(); @@ -476,9 +187,7 @@ mp_io_pipeline_capture() static void release_buffer(MPPipeline *pipeline, const uint32_t *buffer_index) { - struct camera_info *info = &cameras[camera->index]; - - mp_camera_release_buffer(info->camera, *buffer_index); + mp_camera_release_buffer(mpcamera, *buffer_index); } void @@ -493,20 +202,22 @@ mp_io_pipeline_release_buffer(uint32_t buffer_index) static pid_t focus_continuous_task = 0; static pid_t start_focus_task = 0; static void -start_focus(struct camera_info *info) +start_focus() { // only run 1 manual focus at once - if (!mp_camera_check_task_complete(info->camera, start_focus_task) || - !mp_camera_check_task_complete(info->camera, focus_continuous_task)) + if (!mp_camera_check_task_complete(mpcamera, start_focus_task) || + !mp_camera_check_task_complete(mpcamera, focus_continuous_task)) return; - if (info->has_auto_focus_continuous) { + /* TODO: implement + if (mpcamera.has_auto_focus_continuous) { focus_continuous_task = mp_camera_control_set_bool_bg( info->camera, V4L2_CID_FOCUS_AUTO, 1); } else if (info->has_auto_focus_start) { start_focus_task = mp_camera_control_set_bool_bg( info->camera, V4L2_CID_AUTO_FOCUS_START, 1); } + */ } static void @@ -516,11 +227,9 @@ update_controls() if (captures_remaining > 0) { return; } - - struct camera_info *info = &cameras[camera->index]; - + /* TODO: implement if (want_focus) { - start_focus(info); + start_focus(mpcamera); want_focus = false; } @@ -552,6 +261,7 @@ update_controls() } current_controls = desired_controls; + */ } static void @@ -565,8 +275,8 @@ on_frame(MPBuffer buffer, void *_data) if (just_switched_mode) { if (blank_frame_count < 20) { // Only check a 10x10 area - size_t test_size = - MIN(10, mode.width) * MIN(10, mode.height); + size_t test_size = MIN(10, io_camera->current_mode->width) * + MIN(10, io_camera->current_mode->height); bool image_is_blank = true; for (size_t i = 0; i < test_size; ++i) { @@ -594,67 +304,41 @@ on_frame(MPBuffer buffer, void *_data) --captures_remaining; if (captures_remaining == 0) { - struct camera_info *info = &cameras[camera->index]; - struct device_info *dev_info = &devices[info->device_index]; - // Restore the auto exposure and gain if needed if (!current_controls.exposure_is_manual) { mp_camera_control_set_int32_bg( - info->camera, + io_camera, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_AUTO); } + /* TODO: implement if (!current_controls.gain_is_manual) { mp_camera_control_set_bool_bg( info->camera, V4L2_CID_AUTOGAIN, true); } + */ // Go back to preview mode mp_process_pipeline_sync(); - mp_camera_stop_capture(info->camera); - - mode = camera->preview_mode; - if (camera->num_media_links) - mp_setup_media_link_pad_formats( - dev_info, - camera->media_links, - camera->num_media_links, - &mode); - mp_camera_set_mode(info->camera, &mode); + mp_camera_stop_capture(mpcamera); + libmegapixels_select_mode(io_camera, mode_preview); just_switched_mode = true; - mp_camera_start_capture(info->camera); + mp_camera_start_capture(mpcamera); // Disable flash + /* TODO: implement if (info->flash && flash_enabled) { mp_flash_disable(info->flash); } + */ update_process_pipeline(); } } } -static void -mp_setup_media_link(struct device_info *dev_info, - const struct mp_media_link_config *cfg, - bool enable) -{ - const struct media_v2_entity *source_entity = - mp_device_find_entity(dev_info->device, cfg->source_name); - - const struct media_v2_entity *target_entity = - mp_device_find_entity(dev_info->device, cfg->target_name); - - mp_device_setup_entity_link(dev_info->device, - source_entity->id, - target_entity->id, - cfg->source_port, - cfg->target_port, - enable); -} - static void update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state) { @@ -662,24 +346,13 @@ update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state) // whether this state change actually changes anything. bool has_changed = false; - if (camera != state->camera) { + if (io_camera != state->camera) { has_changed = true; - if (camera) { - struct camera_info *info = &cameras[camera->index]; - struct device_info *dev_info = &devices[info->device_index]; - + if (io_camera != NULL) { mp_process_pipeline_sync(); - mp_camera_stop_capture(info->camera); - mp_device_setup_link(dev_info->device, - info->pad_id, - dev_info->interface_pad_id, - false); - - // Disable media links - for (int i = 0; i < camera->num_media_links; i++) - mp_setup_media_link( - dev_info, &camera->media_links[i], false); + mp_camera_stop_capture(mpcamera); + libmegapixels_close(io_camera); } if (capture_source) { @@ -687,47 +360,52 @@ update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state) capture_source = NULL; } - camera = state->camera; + io_camera = state->camera; + if (io_camera) { + libmegapixels_open(io_camera); + mpcamera = mp_camera_new(io_camera); + mode_preview = NULL; + mode_capture = NULL; + for (int m = 0; m < io_camera->num_modes; m++) { + if (io_camera->modes[m]->rate > 29) { + mode_preview = io_camera->modes[m]; + break; + } + } + long area = 0; + for (int m = 0; m < io_camera->num_modes; m++) { + long this_pixels = io_camera->modes[m]->width * + io_camera->modes[m]->height; - if (camera) { - struct camera_info *info = &cameras[camera->index]; - struct device_info *dev_info = &devices[info->device_index]; + if (this_pixels > area) { + area = this_pixels; + mode_capture = io_camera->modes[m]; + } + } + if (mode_preview != NULL) { + if (io_camera->video_fd == 0) { + libmegapixels_open(io_camera); + } + libmegapixels_select_mode(io_camera, mode_preview); + } - mp_device_setup_link(dev_info->device, - info->pad_id, - dev_info->interface_pad_id, - true); - - // Enable media links - for (int i = 0; i < camera->num_media_links; i++) - mp_setup_media_link( - dev_info, &camera->media_links[i], true); - - mode = camera->preview_mode; - if (camera->num_media_links) - mp_setup_media_link_pad_formats( - dev_info, - camera->media_links, - camera->num_media_links, - &mode); - mp_camera_set_mode(info->camera, &mode); - - mp_camera_start_capture(info->camera); + mp_camera_start_capture(mpcamera); capture_source = mp_pipeline_add_capture_source( - pipeline, info->camera, on_frame, NULL); + pipeline, mpcamera, on_frame, NULL); current_controls.gain_is_manual = - mp_camera_control_get_bool(info->camera, + mp_camera_control_get_bool(io_camera, V4L2_CID_AUTOGAIN) == 0; - current_controls.gain = mp_camera_control_get_int32( - info->camera, info->gain_ctrl); + // current_controls.gain = + // mp_camera_control_get_int32(camera, + // info->gain_ctrl); - current_controls.exposure_is_manual = - mp_camera_control_get_int32( - info->camera, V4L2_CID_EXPOSURE_AUTO) == - V4L2_EXPOSURE_MANUAL; - current_controls.exposure = mp_camera_control_get_int32( - info->camera, V4L2_CID_EXPOSURE); + // current_controls.exposure_is_manual = + // mp_camera_control_get_int32( + // info->camera, V4L2_CID_EXPOSURE_AUTO) == + // V4L2_EXPOSURE_MANUAL; + // current_controls.exposure = mp_camera_control_get_int32( + // info->camera, V4L2_CID_EXPOSURE); } } @@ -741,7 +419,7 @@ update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state) preview_height = state->preview_height; device_rotation = state->device_rotation; - if (camera) { + if (io_camera) { struct control_state previous_desired = desired_controls; desired_controls.gain_is_manual = state->gain_is_manual; diff --git a/src/io_pipeline.h b/src/io_pipeline.h index 00671c5..9928e90 100644 --- a/src/io_pipeline.h +++ b/src/io_pipeline.h @@ -1,9 +1,11 @@ #pragma once -#include "camera_config.h" +#include +#include +#include struct mp_io_pipeline_state { - const struct mp_camera_config *camera; + libmegapixels_camera *camera; int burst_length; diff --git a/src/main.c b/src/main.c index b2f983b..6602dc3 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,5 @@ #include "main.h" -#include "camera_config.h" #include "flash.h" #include "gl_util.h" #include "io_pipeline.h" @@ -21,6 +20,7 @@ #include #include #endif +#include #include #include #include @@ -47,9 +47,12 @@ RENDERDOC_API_1_1_2 *rdoc_api = NULL; enum user_control { USER_CONTROL_ISO, USER_CONTROL_SHUTTER }; +libmegapixels_devconfig *configuration = { 0 }; +libmegapixels_camera *camera = NULL; +int current_camera_index = 0; + static bool camera_is_initialized = false; -static const struct mp_camera_config *camera = NULL; -static MPMode mode; +struct mp_main_state current_state = { 0 }; static int preview_width = -1; static int preview_height = -1; @@ -128,7 +131,8 @@ update_io_pipeline() mp_io_pipeline_update_state(&io_state); // Make the right settings available for the camera - gtk_widget_set_visible(flash_button, camera->has_flash); + // TODO: Implement flash again + gtk_widget_set_visible(flash_button, false); } static bool @@ -138,8 +142,8 @@ update_state(const struct mp_main_state *state) camera_is_initialized = true; } - if (camera == state->camera) { - mode = state->mode; + if (current_state.camera == state->camera) { + current_state.mode = state->mode; if (!gain_is_manual) { gain = state->gain; @@ -154,8 +158,8 @@ update_state(const struct mp_main_state *state) has_auto_focus_start = state->has_auto_focus_start; } - preview_buffer_width = state->image_width; - preview_buffer_height = state->image_height; + preview_buffer_width = state->mode->width; + preview_buffer_height = state->mode->height; return false; } @@ -693,16 +697,11 @@ preview_pressed(GtkGestureClick *gesture, int n_press, double x, double y) static void run_camera_switch_action(GSimpleAction *action, GVariant *param, gpointer user_data) { - size_t next_index = camera->index + 1; - const struct mp_camera_config *next_camera = - mp_get_camera_config(next_index); - - if (!next_camera) { - next_index = 0; - next_camera = mp_get_camera_config(next_index); + current_camera_index++; + if (current_camera_index > configuration->count) { + current_camera_index = 0; } - - camera = next_camera; + camera = configuration->cameras[current_camera_index]; update_io_pipeline(); } @@ -828,11 +827,14 @@ open_iso_controls(GtkWidget *button, gpointer user_data) static void set_shutter(double value) { + // TODO: Implement shutter in libmegapixels + /* int new_exposure = (int)(value / 360.0 * camera->capture_mode.height); if (new_exposure != exposure) { exposure = new_exposure; update_io_pipeline(); } + */ } static void @@ -874,7 +876,8 @@ on_realize(GtkWidget *window, gpointer *data) GtkNative *native = gtk_widget_get_native(window); mp_process_pipeline_init_gl(gtk_native_get_surface(native)); - camera = mp_get_camera_config(0); + current_camera_index = 0; + camera = configuration->cameras[0]; update_io_pipeline(); } @@ -1338,9 +1341,19 @@ main(int argc, char *argv[]) } } #endif - - if (!mp_load_config()) - return 1; + char configfile[PATH_MAX]; + libmegapixels_init(&configuration); + if (libmegapixels_find_config(configfile)) { + if (!libmegapixels_load_file(configuration, configfile)) { + fprintf(stderr, "Could not load config\n"); + return 1; + } + } else { + if (!libmegapixels_load_uvc(configuration)) { + fprintf(stderr, "No config found\n"); + return 1; + } + } setenv("LC_NUMERIC", "C", 1); diff --git a/src/main.h b/src/main.h index b2df652..d3f5783 100644 --- a/src/main.h +++ b/src/main.h @@ -1,16 +1,12 @@ #pragma once -#include "camera_config.h" #include "gtk/gtk.h" #include "process_pipeline.h" #include "zbar_pipeline.h" struct mp_main_state { const struct mp_camera_config *camera; - MPMode mode; - - int image_width; - int image_height; + libmegapixels_mode *mode; bool gain_is_manual; int gain; diff --git a/src/mode.c b/src/mode.c deleted file mode 100644 index d4f9f7e..0000000 --- a/src/mode.c +++ /dev/null @@ -1,276 +0,0 @@ -#include "mode.h" - -#include -#include -#include -#include - -static const char *pixel_format_names[MP_PIXEL_FMT_MAX] = { - "unsupported", "BGGR8", "GBRG8", "GRBG8", "RGGB8", "BGGR10P", - "GBRG10P", "GRBG10P", "RGGB10P", "UYVY", "YUYV", -}; - -const char * -mp_pixel_format_to_str(uint32_t pixel_format) -{ - g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, "INVALID"); - return pixel_format_names[pixel_format]; -} - -MPPixelFormat -mp_pixel_format_from_str(const char *name) -{ - for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) { - if (strcasecmp(pixel_format_names[i], name) == 0) { - return i; - } - } - g_return_val_if_reached(MP_PIXEL_FMT_UNSUPPORTED); -} - -static const uint32_t pixel_format_v4l_pixel_formats[MP_PIXEL_FMT_MAX] = { - 0, - V4L2_PIX_FMT_SBGGR8, - V4L2_PIX_FMT_SGBRG8, - V4L2_PIX_FMT_SGRBG8, - V4L2_PIX_FMT_SRGGB8, - V4L2_PIX_FMT_SBGGR10P, - V4L2_PIX_FMT_SGBRG10P, - V4L2_PIX_FMT_SGRBG10P, - V4L2_PIX_FMT_SRGGB10P, - V4L2_PIX_FMT_UYVY, - V4L2_PIX_FMT_YUYV, -}; - -uint32_t -mp_pixel_format_to_v4l_pixel_format(MPPixelFormat pixel_format) -{ - g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0); - return pixel_format_v4l_pixel_formats[pixel_format]; -} - -MPPixelFormat -mp_pixel_format_from_v4l_pixel_format(uint32_t v4l_pixel_format) -{ - for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) { - if (pixel_format_v4l_pixel_formats[i] == v4l_pixel_format) { - return i; - } - } - return MP_PIXEL_FMT_UNSUPPORTED; -} - -static const uint32_t pixel_format_v4l_bus_codes[MP_PIXEL_FMT_MAX] = { - 0, - MEDIA_BUS_FMT_SBGGR8_1X8, - MEDIA_BUS_FMT_SGBRG8_1X8, - MEDIA_BUS_FMT_SGRBG8_1X8, - MEDIA_BUS_FMT_SRGGB8_1X8, - MEDIA_BUS_FMT_SBGGR10_1X10, - MEDIA_BUS_FMT_SGBRG10_1X10, - MEDIA_BUS_FMT_SGRBG10_1X10, - MEDIA_BUS_FMT_SRGGB10_1X10, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, -}; - -uint32_t -mp_pixel_format_to_v4l_bus_code(MPPixelFormat pixel_format) -{ - g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0); - return pixel_format_v4l_bus_codes[pixel_format]; -} - -MPPixelFormat -mp_pixel_format_from_v4l_bus_code(uint32_t v4l_bus_code) -{ - for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) { - if (pixel_format_v4l_bus_codes[i] == v4l_bus_code) { - return i; - } - } - return MP_PIXEL_FMT_UNSUPPORTED; -} - -uint32_t -mp_pixel_format_bits_per_pixel(MPPixelFormat pixel_format) -{ - g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0); - switch (pixel_format) { - case MP_PIXEL_FMT_BGGR8: - case MP_PIXEL_FMT_GBRG8: - case MP_PIXEL_FMT_GRBG8: - case MP_PIXEL_FMT_RGGB8: - return 8; - case MP_PIXEL_FMT_BGGR10P: - case MP_PIXEL_FMT_GBRG10P: - case MP_PIXEL_FMT_GRBG10P: - case MP_PIXEL_FMT_RGGB10P: - return 10; - case MP_PIXEL_FMT_UYVY: - case MP_PIXEL_FMT_YUYV: - return 16; - default: - return 0; - } -} - -uint32_t -mp_pixel_format_pixel_depth(MPPixelFormat pixel_format) -{ - g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0); - switch (pixel_format) { - case MP_PIXEL_FMT_BGGR8: - case MP_PIXEL_FMT_GBRG8: - case MP_PIXEL_FMT_GRBG8: - case MP_PIXEL_FMT_RGGB8: - case MP_PIXEL_FMT_UYVY: - case MP_PIXEL_FMT_YUYV: - return 8; - case MP_PIXEL_FMT_GBRG10P: - case MP_PIXEL_FMT_GRBG10P: - case MP_PIXEL_FMT_RGGB10P: - case MP_PIXEL_FMT_BGGR10P: - return 10; - default: - return 0; - } -} - -const char * -mp_pixel_format_cfa(MPPixelFormat pixel_format) -{ - g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0); - switch (pixel_format) { - case MP_PIXEL_FMT_BGGR8: - case MP_PIXEL_FMT_BGGR10P: - return "BGGR"; - break; - case MP_PIXEL_FMT_GBRG8: - case MP_PIXEL_FMT_GBRG10P: - return "GBRG"; - break; - case MP_PIXEL_FMT_GRBG8: - case MP_PIXEL_FMT_GRBG10P: - return "GRBG"; - break; - case MP_PIXEL_FMT_RGGB8: - case MP_PIXEL_FMT_RGGB10P: - return "RGGB"; - break; - case MP_PIXEL_FMT_UYVY: - return "UYUV"; - break; - case MP_PIXEL_FMT_YUYV: - return "YUYV"; - break; - default: - return "unsupported"; - } -} - -const char * -mp_pixel_format_cfa_pattern(MPPixelFormat pixel_format) -{ - g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0); - switch (pixel_format) { - case MP_PIXEL_FMT_BGGR8: - case MP_PIXEL_FMT_BGGR10P: - return "\002\001\001\000"; - break; - case MP_PIXEL_FMT_GBRG8: - case MP_PIXEL_FMT_GBRG10P: - return "\001\002\000\001"; - break; - case MP_PIXEL_FMT_GRBG8: - case MP_PIXEL_FMT_GRBG10P: - return "\001\000\002\001"; - break; - case MP_PIXEL_FMT_RGGB8: - case MP_PIXEL_FMT_RGGB10P: - return "\000\001\001\002"; - break; - default: - return NULL; - } -} - -uint32_t -mp_pixel_format_width_to_bytes(MPPixelFormat pixel_format, uint32_t width) -{ - uint32_t bits_per_pixel = mp_pixel_format_bits_per_pixel(pixel_format); - uint64_t bits_per_width = width * (uint64_t)bits_per_pixel; - - uint64_t remainder = bits_per_width % 8; - if (remainder == 0) - return bits_per_width / 8; - - return (bits_per_width + 8 - remainder) / 8; -} - -uint32_t -mp_pixel_format_width_to_padding(MPPixelFormat pixel_format, uint32_t width) -{ - uint64_t bytes_per_width = - mp_pixel_format_width_to_bytes(pixel_format, width); - - uint64_t remainder = bytes_per_width % 8; - if (remainder == 0) - return remainder; - - return 8 - remainder; -} - -uint32_t -mp_pixel_format_width_to_colors(MPPixelFormat pixel_format, uint32_t width) -{ - g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0); - switch (pixel_format) { - case MP_PIXEL_FMT_BGGR8: - case MP_PIXEL_FMT_GBRG8: - case MP_PIXEL_FMT_GRBG8: - case MP_PIXEL_FMT_RGGB8: - return width / 2; - case MP_PIXEL_FMT_BGGR10P: - case MP_PIXEL_FMT_GBRG10P: - case MP_PIXEL_FMT_GRBG10P: - case MP_PIXEL_FMT_RGGB10P: - return width / 2 * 5; - case MP_PIXEL_FMT_UYVY: - case MP_PIXEL_FMT_YUYV: - return width; - default: - return 0; - } -} - -uint32_t -mp_pixel_format_height_to_colors(MPPixelFormat pixel_format, uint32_t height) -{ - g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0); - switch (pixel_format) { - case MP_PIXEL_FMT_BGGR8: - case MP_PIXEL_FMT_GBRG8: - case MP_PIXEL_FMT_GRBG8: - case MP_PIXEL_FMT_RGGB8: - case MP_PIXEL_FMT_BGGR10P: - case MP_PIXEL_FMT_GBRG10P: - case MP_PIXEL_FMT_GRBG10P: - case MP_PIXEL_FMT_RGGB10P: - return height / 2; - case MP_PIXEL_FMT_UYVY: - case MP_PIXEL_FMT_YUYV: - return height; - default: - return 0; - } -} - -bool -mp_mode_is_equivalent(const MPMode *m1, const MPMode *m2) -{ - return m1->pixel_format == m2->pixel_format && - m1->frame_interval.numerator == m2->frame_interval.numerator && - m1->frame_interval.denominator == m2->frame_interval.denominator && - m1->width == m2->width && m1->height == m2->height; -} diff --git a/src/mode.h b/src/mode.h deleted file mode 100644 index 6cdfb7a..0000000 --- a/src/mode.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include -#include - -typedef enum { - MP_PIXEL_FMT_UNSUPPORTED, - MP_PIXEL_FMT_BGGR8, - MP_PIXEL_FMT_GBRG8, - MP_PIXEL_FMT_GRBG8, - MP_PIXEL_FMT_RGGB8, - MP_PIXEL_FMT_BGGR10P, - MP_PIXEL_FMT_GBRG10P, - MP_PIXEL_FMT_GRBG10P, - MP_PIXEL_FMT_RGGB10P, - MP_PIXEL_FMT_UYVY, - MP_PIXEL_FMT_YUYV, - - MP_PIXEL_FMT_MAX, -} MPPixelFormat; - -const char *mp_pixel_format_to_str(MPPixelFormat pixel_format); -MPPixelFormat mp_pixel_format_from_str(const char *str); - -MPPixelFormat mp_pixel_format_from_v4l_pixel_format(uint32_t v4l_pixel_format); -MPPixelFormat mp_pixel_format_from_v4l_bus_code(uint32_t v4l_bus_code); -uint32_t mp_pixel_format_to_v4l_pixel_format(MPPixelFormat pixel_format); -uint32_t mp_pixel_format_to_v4l_bus_code(MPPixelFormat pixel_format); - -uint32_t mp_pixel_format_bits_per_pixel(MPPixelFormat pixel_format); -uint32_t mp_pixel_format_pixel_depth(MPPixelFormat pixel_format); -const char *mp_pixel_format_cfa(MPPixelFormat pixel_format); -const char *mp_pixel_format_cfa_pattern(MPPixelFormat pixel_format); -uint32_t mp_pixel_format_width_to_bytes(MPPixelFormat pixel_format, uint32_t width); -uint32_t mp_pixel_format_width_to_padding(MPPixelFormat pixel_format, - uint32_t width); -uint32_t mp_pixel_format_width_to_colors(MPPixelFormat pixel_format, uint32_t width); -uint32_t mp_pixel_format_height_to_colors(MPPixelFormat pixel_format, - uint32_t height); - -typedef struct { - MPPixelFormat pixel_format; - - struct v4l2_fract frame_interval; - uint32_t width; - uint32_t height; -} MPMode; - -bool mp_mode_is_equivalent(const MPMode *m1, const MPMode *m2); - -typedef struct _MPModeList MPModeList; - -struct _MPModeList { - MPMode mode; - MPModeList *next; -}; diff --git a/src/pipeline.h b/src/pipeline.h index 7a3c27a..6fa92fb 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -1,7 +1,6 @@ #pragma once #include "camera.h" -#include "device.h" #include typedef struct _MPPipeline MPPipeline; diff --git a/src/process_pipeline.c b/src/process_pipeline.c index c6c37eb..2ddf30b 100644 --- a/src/process_pipeline.c +++ b/src/process_pipeline.c @@ -1,6 +1,5 @@ #include "process_pipeline.h" -#include "config.h" #include "gles2_debayer.h" #include "io_pipeline.h" #include "main.h" @@ -10,15 +9,20 @@ #include #include #include +#ifndef SYSCONFDIR +#include "config.h" +#endif +#include "dcp.h" #include "gl_util.h" #include #define TIFFTAG_FORWARDMATRIX1 50964 #define TIFFTAG_FORWARDMATRIX2 50965 -static const float colormatrix_srgb[] = { 3.2409, -1.5373, -0.4986, -0.9692, 1.8759, - 0.0415, 0.0556, -0.2039, 1.0569 }; +static const float colormatrix_srgb[] = { 3.2409f, -1.5373f, -0.4986f, + -0.9692f, 1.8759f, 0.0415f, + 0.0556f, -0.2039f, 1.0569f }; static MPPipeline *pipeline; @@ -28,10 +32,10 @@ static volatile bool is_capturing = false; static volatile int frames_processed = 0; static volatile int frames_received = 0; -static const struct mp_camera_config *camera; -static int camera_rotation; +libmegapixels_camera *pr_camera; +libmegapixels_mode *mode; -static MPMode mode; +static int camera_rotation; static int burst_length; static int captures_remaining = 0; @@ -281,17 +285,19 @@ mp_process_pipeline_buffer_get_texture_id(MPProcessPipelineBuffer *buf) } static void -repack_image_sequencial(const uint8_t *src_buf, uint8_t *dst_buf, MPMode *mode) +repack_image_sequencial(const uint8_t *src_buf, + uint8_t *dst_buf, + libmegapixels_mode *mode) { uint16_t pixels[4]; uint32_t row_length = - mp_pixel_format_width_to_bytes(mode->pixel_format, mode->width); + libmegapixels_mode_width_to_bytes(mode->format, mode->width); uint32_t padding_bytes = - mp_pixel_format_width_to_padding(mode->pixel_format, mode->width); + libmegapixels_mode_width_to_padding(mode->format, mode->width); size_t si = 0; // Image data must be 10-bit packed - assert(mp_pixel_format_bits_per_pixel(mode->pixel_format) == 10); + assert(libmegapixels_format_bits_per_pixel(mode->format) == 10); /* * Repack 40 bits stored in sensor format into sequencial format @@ -439,10 +445,10 @@ process_image_for_preview(const uint8_t *image) glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, - mp_pixel_format_width_to_bytes(mode.pixel_format, mode.width) + - mp_pixel_format_width_to_padding(mode.pixel_format, - mode.width), - mode.height, + libmegapixels_mode_width_to_bytes(mode->format, mode->width) + + libmegapixels_mode_width_to_padding(mode->format, + mode->width), + mode->height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, @@ -535,26 +541,26 @@ process_image_for_capture(const uint8_t *image, int count) // Define TIFF thumbnail TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 1); - TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, mode.width >> 4); - TIFFSetField(tif, TIFFTAG_IMAGELENGTH, mode.height >> 4); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, mode->width >> 4); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, mode->height >> 4); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); - TIFFSetField(tif, TIFFTAG_MAKE, mp_get_device_make()); - TIFFSetField(tif, TIFFTAG_MODEL, mp_get_device_model()); + TIFFSetField(tif, TIFFTAG_MAKE, "MAKE"); // TODO: fix + TIFFSetField(tif, TIFFTAG_MODEL, "MODEL"); uint16_t orientation; if (camera_rotation == 0) { - orientation = camera->mirrored ? ORIENTATION_TOPRIGHT : - ORIENTATION_TOPLEFT; + orientation = + mode->mirrored ? ORIENTATION_TOPRIGHT : ORIENTATION_TOPLEFT; } else if (camera_rotation == 90) { - orientation = camera->mirrored ? ORIENTATION_RIGHTBOT : - ORIENTATION_LEFTBOT; + orientation = + mode->mirrored ? ORIENTATION_RIGHTBOT : ORIENTATION_LEFTBOT; } else if (camera_rotation == 180) { - orientation = camera->mirrored ? ORIENTATION_BOTLEFT : - ORIENTATION_BOTRIGHT; + orientation = + mode->mirrored ? ORIENTATION_BOTLEFT : ORIENTATION_BOTRIGHT; } else { - orientation = camera->mirrored ? ORIENTATION_LEFTTOP : - ORIENTATION_RIGHTTOP; + orientation = + mode->mirrored ? ORIENTATION_LEFTTOP : ORIENTATION_RIGHTTOP; } TIFFSetField(tif, TIFFTAG_ORIENTATION, orientation); TIFFSetField(tif, TIFFTAG_DATETIME, datetime); @@ -568,96 +574,98 @@ process_image_for_capture(const uint8_t *image, int count) char uniquecameramodel[255]; sprintf(uniquecameramodel, "%s %s", - mp_get_device_make(), - mp_get_device_model()); + "MAKE", // TODO: fix + "MODEL"); TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, uniquecameramodel); // Color matrices - if (camera->calibration.color_matrix_1[0]) { + /* + if (pr_camera->calibration.color_matrix_1[0]) { TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, - camera->calibration.color_matrix_1); - } else if (camera->colormatrix[0]) { - TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, camera->colormatrix); + pr_camera->calibration.color_matrix_1); + } else if (pr_camera->colormatrix[0]) { + TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, pr_camera->colormatrix); } else { TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, colormatrix_srgb); } - if (camera->calibration.color_matrix_2[0]) { + if (pr_camera->calibration.color_matrix_2[0]) { TIFFSetField(tif, TIFFTAG_COLORMATRIX2, 9, - camera->calibration.color_matrix_2); + pr_camera->calibration.color_matrix_2); } - if (camera->calibration.forward_matrix_1[0]) { + if (pr_camera->calibration.forward_matrix_1[0]) { TIFFSetField(tif, TIFFTAG_FORWARDMATRIX1, 9, - camera->calibration.forward_matrix_1); - } else if (camera->forwardmatrix[0]) { - TIFFSetField(tif, TIFFTAG_FORWARDMATRIX1, 9, camera->forwardmatrix); + pr_camera->calibration.forward_matrix_1); + } else if (pr_camera->forwardmatrix[0]) { + TIFFSetField(tif, TIFFTAG_FORWARDMATRIX1, 9, + pr_camera->forwardmatrix); } - if (camera->calibration.forward_matrix_2[0]) { + if (pr_camera->calibration.forward_matrix_2[0]) { TIFFSetField(tif, TIFFTAG_FORWARDMATRIX2, 9, - camera->calibration.forward_matrix_2); + pr_camera->calibration.forward_matrix_2); } static const float neutral[] = { 1.0, 1.0, 1.0 }; TIFFSetField(tif, TIFFTAG_ASSHOTNEUTRAL, 3, neutral); - if (camera->calibration.illuminant_1) { + if (pr_camera->calibration.illuminant_1) { TIFFSetField(tif, TIFFTAG_CALIBRATIONILLUMINANT1, - camera->calibration.illuminant_1); + pr_camera->calibration.illuminant_1); } else { TIFFSetField(tif, TIFFTAG_CALIBRATIONILLUMINANT1, 21); } - if (camera->calibration.illuminant_2) { + if (pr_camera->calibration.illuminant_2) { TIFFSetField(tif, TIFFTAG_CALIBRATIONILLUMINANT2, - camera->calibration.illuminant_2); + pr_camera->calibration.illuminant_2); } - if (camera->calibration.tone_curve_length) { + if (pr_camera->calibration.tone_curve_length) { TIFFSetField(tif, DCPTAG_PROFILE_TONE_CURVE, - camera->calibration.tone_curve_length, - camera->calibration.tone_curve); + pr_camera->calibration.tone_curve_length, + pr_camera->calibration.tone_curve); } - if (camera->calibration.hue_sat_map_dims[0]) { + if (pr_camera->calibration.hue_sat_map_dims[0]) { TIFFSetField(tif, DCPTAG_PROFILE_HUE_SAT_MAP_DIMS, 3, - camera->calibration.hue_sat_map_dims); + pr_camera->calibration.hue_sat_map_dims); TIFFSetField(tif, DCPTAG_PROFILE_HUE_SAT_MAP_DATA_1, - camera->calibration.hue_sat_map_dims[0] * - camera->calibration.hue_sat_map_dims[1] * - camera->calibration.hue_sat_map_dims[2] * 3, - camera->calibration.hue_sat_map_data_1); - if (camera->calibration.hue_sat_map_data_2 != NULL) { + pr_camera->calibration.hue_sat_map_dims[0] * + pr_camera->calibration.hue_sat_map_dims[1] * + pr_camera->calibration.hue_sat_map_dims[2] * 3, + pr_camera->calibration.hue_sat_map_data_1); + if (pr_camera->calibration.hue_sat_map_data_2 != NULL) { TIFFSetField( tif, DCPTAG_PROFILE_HUE_SAT_MAP_DATA_2, - camera->calibration.hue_sat_map_dims[0] * - camera->calibration.hue_sat_map_dims[1] * - camera->calibration.hue_sat_map_dims[2] * 3, - camera->calibration.hue_sat_map_data_2); + pr_camera->calibration.hue_sat_map_dims[0] * + pr_camera->calibration.hue_sat_map_dims[1] * + pr_camera->calibration.hue_sat_map_dims[2] * + 3, pr_camera->calibration.hue_sat_map_data_2); } } - + */ TIFFSetField(tif, TIFFTAG_ANALOGBALANCE, 3, balance); // Write black thumbnail, only windows uses this { unsigned char *buf = - (unsigned char *)calloc(1, (mode.width >> 4) * 3); - for (int row = 0; row < (mode.height >> 4); row++) { + (unsigned char *)calloc(1, (mode->width >> 4) * 3); + for (int row = 0; row < (mode->height >> 4); row++) { TIFFWriteScanline(tif, buf, row, 0); } free(buf); @@ -666,11 +674,11 @@ process_image_for_capture(const uint8_t *image, int count) // Define main photo TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0); - TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, mode.width); - TIFFSetField(tif, TIFFTAG_IMAGELENGTH, mode.height); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, mode->width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, mode->height); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, - mp_pixel_format_bits_per_pixel(mode.pixel_format)); + libmegapixels_format_bits_per_pixel(mode->format)); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA); TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); @@ -684,41 +692,33 @@ process_image_for_capture(const uint8_t *image, int count) TIFFSetField(tif, TIFFTAG_CFAPATTERN, 4, - mp_pixel_format_cfa_pattern(mode.pixel_format)); + libmegapixels_format_cfa_pattern(mode->format)); #endif printf("TIFF version %d\n", TIFFLIB_VERSION); - int whitelevel = camera->whitelevel; - if (!whitelevel) { - whitelevel = - (1 << mp_pixel_format_pixel_depth(mode.pixel_format)) - 1; - } + int whitelevel = + (1 << libmegapixels_format_bits_per_pixel(mode->format)) - 1; TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, &whitelevel); - if (camera->blacklevel) { - const float blacklevel = camera->blacklevel; - TIFFSetField(tif, TIFFTAG_BLACKLEVEL, 1, &blacklevel); - } TIFFCheckpointDirectory(tif); printf("Writing frame to %s\n", fname); uint8_t *output_image = (uint8_t *)image; // Repack 10-bit image from sensor format into a sequencial format - if (mp_pixel_format_bits_per_pixel(mode.pixel_format) == 10) { - output_image = malloc(mp_pixel_format_width_to_bytes( - mode.pixel_format, mode.width) * - mode.height); + if (libmegapixels_format_bits_per_pixel(mode->format) == 10) { + output_image = malloc(libmegapixels_mode_width_to_bytes( + mode->format, mode->width) * + mode->height); - repack_image_sequencial(image, output_image, &mode); + repack_image_sequencial(image, output_image, mode); } - for (int row = 0; row < mode.height; row++) { - TIFFWriteScanline( - tif, - (void *)output_image + - (row * mp_pixel_format_width_to_bytes( - mode.pixel_format, mode.width)), - row, - 0); + for (int row = 0; row < mode->height; row++) { + TIFFWriteScanline(tif, + (void *)output_image + + (row * libmegapixels_mode_width_to_bytes( + mode->format, mode->width)), + row, + 0); } TIFFWriteDirectory(tif); @@ -734,17 +734,20 @@ process_image_for_capture(const uint8_t *image, int count) TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 1); } + /* TIFFSetField(tif, EXIFTAG_EXPOSURETIME, (mode.frame_interval.numerator / (float)mode.frame_interval.denominator) / ((float)mode.height / (float)exposure)); - if (camera->iso_min && camera->iso_max) { + + if (pr_camera->iso_min && pr_camera->iso_max) { uint16_t isospeed = remap( - gain - 1, 0, gain_max, camera->iso_min, camera->iso_max); - TIFFSetField(tif, EXIFTAG_ISOSPEEDRATINGS, 1, &isospeed); + gain - 1, 0, gain_max, pr_camera->iso_min, + pr_camera->iso_max); TIFFSetField(tif, EXIFTAG_ISOSPEEDRATINGS, 1, + &isospeed); } - if (!camera->has_flash) { + if (!pr_camera->has_flash) { // No flash function TIFFSetField(tif, EXIFTAG_FLASH, 0x20); } else if (flash_enabled) { @@ -754,20 +757,24 @@ process_image_for_capture(const uint8_t *image, int count) // Flash present but not fired TIFFSetField(tif, EXIFTAG_FLASH, 0x0); } + */ TIFFSetField(tif, EXIFTAG_DATETIMEORIGINAL, datetime); TIFFSetField(tif, EXIFTAG_DATETIMEDIGITIZED, datetime); - if (camera->fnumber) { - TIFFSetField(tif, EXIFTAG_FNUMBER, camera->fnumber); + /* + if (pr_camera->fnumber) { + TIFFSetField(tif, EXIFTAG_FNUMBER, pr_camera->fnumber); } - if (camera->focallength) { - TIFFSetField(tif, EXIFTAG_FOCALLENGTH, camera->focallength); + if (pr_camera->focallength) { + TIFFSetField(tif, EXIFTAG_FOCALLENGTH, pr_camera->focallength); } - if (camera->focallength && camera->cropfactor) { + if (pr_camera->focallength && pr_camera->cropfactor) { TIFFSetField(tif, EXIFTAG_FOCALLENGTHIN35MMFILM, - (short)(camera->focallength * camera->cropfactor)); + (short)(pr_camera->focallength * + pr_camera->cropfactor)); } + */ uint64_t exif_offset = 0; TIFFWriteCustomDirectory(tif, &exif_offset); TIFFFreeDirectory(tif); @@ -870,19 +877,19 @@ process_image(MPPipeline *pipeline, const MPBuffer *buffer) #endif size_t size = - (mp_pixel_format_width_to_bytes(mode.pixel_format, mode.width) + - mp_pixel_format_width_to_padding(mode.pixel_format, mode.width)) * - mode.height; + (libmegapixels_mode_width_to_bytes(mode->format, mode->width) + + libmegapixels_mode_width_to_padding(mode->format, mode->width)) * + mode->height; uint8_t *image = malloc(size); memcpy(image, buffer->data, size); mp_io_pipeline_release_buffer(buffer->index); MPZBarImage *zbar_image = mp_zbar_image_new(image, - mode.pixel_format, - mode.width, - mode.height, + mode->format, + mode->width, + mode->height, camera_rotation, - camera->mirrored); + mode->mirrored); mp_zbar_pipeline_process_image(mp_zbar_image_ref(zbar_image)); #ifdef PROFILE_PROCESS @@ -968,10 +975,10 @@ mp_process_pipeline_capture() static void on_output_changed(bool format_changed) { - output_buffer_width = mode.width / 2; - output_buffer_height = mode.height / 2; + output_buffer_width = mode->width / 2; + output_buffer_height = mode->height / 2; - if (camera->rotate != 0 || camera->rotate != 180) { + if (mode->rotation != 0 || mode->rotation != 180) { int tmp = output_buffer_width; output_buffer_width = output_buffer_height; output_buffer_height = tmp; @@ -997,22 +1004,21 @@ on_output_changed(bool format_changed) if (gles2_debayer) gles2_debayer_free(gles2_debayer); - gles2_debayer = gles2_debayer_new(mode.pixel_format); + gles2_debayer = gles2_debayer_new(mode->format); check_gl(); gles2_debayer_use(gles2_debayer); } - gles2_debayer_configure( - gles2_debayer, - output_buffer_width, - output_buffer_height, - mode.width, - mode.height, - camera->rotate, - camera->mirrored, - camera->previewmatrix[0] == 0 ? NULL : camera->previewmatrix, - camera->blacklevel); + gles2_debayer_configure(gles2_debayer, + output_buffer_width, + output_buffer_height, + mode->width, + mode->height, + mode->rotation, + 0, + NULL, + 0); } static int @@ -1025,15 +1031,24 @@ mod(int a, int b) static void update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state) { - const bool output_changed = !mp_mode_is_equivalent(&mode, &state->mode) || - preview_width != state->preview_width || - preview_height != state->preview_height || - device_rotation != state->device_rotation; + const bool output_changed = + !libmegapixels_mode_equals(mode, state->camera->current_mode) || + preview_width != state->preview_width || + preview_height != state->preview_height || + device_rotation != state->device_rotation; - const bool format_changed = mode.pixel_format != state->mode.pixel_format; + bool format_changed = mode == NULL; - camera = state->camera; - mode = state->mode; + if (!format_changed && + mode->v4l_pixfmt != state->camera->current_mode->v4l_pixfmt) { + format_changed = true; + } + if (mode == NULL) { + mode = state->camera->current_mode; + } + + pr_camera = state->camera; + mode = state->camera->current_mode; preview_width = state->preview_width; preview_height = state->preview_height; @@ -1052,16 +1067,14 @@ update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state exposure = state->exposure; if (output_changed) { - camera_rotation = mod(camera->rotate - device_rotation, 360); + camera_rotation = mod(mode->rotation - device_rotation, 360); on_output_changed(format_changed); } struct mp_main_state main_state = { - .camera = camera, + .camera = pr_camera, .mode = mode, - .image_width = output_buffer_width, - .image_height = output_buffer_height, .gain_is_manual = state->gain_is_manual, .gain = gain, .gain_max = gain_max, diff --git a/src/process_pipeline.h b/src/process_pipeline.h index c3b8eac..705f257 100644 --- a/src/process_pipeline.h +++ b/src/process_pipeline.h @@ -1,14 +1,12 @@ #pragma once #include "camera.h" -#include "camera_config.h" #include typedef struct _GdkSurface GdkSurface; struct mp_process_pipeline_state { - const struct mp_camera_config *camera; - MPMode mode; + libmegapixels_camera *camera; int burst_length; diff --git a/src/zbar_pipeline.c b/src/zbar_pipeline.c index ba88f20..7d76fed 100644 --- a/src/zbar_pipeline.c +++ b/src/zbar_pipeline.c @@ -8,7 +8,7 @@ struct _MPZBarImage { uint8_t *data; - MPPixelFormat pixel_format; + int format; int width; int height; int rotation; @@ -171,15 +171,6 @@ process_image(MPPipeline *pipeline, MPZBarImage **_image) { MPZBarImage *image = *_image; - assert(image->pixel_format == MP_PIXEL_FMT_BGGR8 || - image->pixel_format == MP_PIXEL_FMT_GBRG8 || - image->pixel_format == MP_PIXEL_FMT_GRBG8 || - image->pixel_format == MP_PIXEL_FMT_RGGB8 || - image->pixel_format == MP_PIXEL_FMT_BGGR10P || - image->pixel_format == MP_PIXEL_FMT_GBRG10P || - image->pixel_format == MP_PIXEL_FMT_GRBG10P || - image->pixel_format == MP_PIXEL_FMT_RGGB10P); - // Create a grayscale image for scanning from the current preview. // Rotate/mirror correctly. int width = image->width / 2; @@ -187,11 +178,12 @@ process_image(MPPipeline *pipeline, MPZBarImage **_image) uint8_t *data = malloc(width * height * sizeof(uint8_t)); size_t row_length = - mp_pixel_format_width_to_bytes(image->pixel_format, image->width); + libmegapixels_mode_width_to_bytes(image->format, image->width); int padding_bytes = - mp_pixel_format_width_to_padding(image->pixel_format, image->width); + libmegapixels_mode_width_to_padding(image->format, image->width); size_t i = 0, padding_offset = 0; size_t offset; + /* TODO: implement switch (image->pixel_format) { case MP_PIXEL_FMT_BGGR8: case MP_PIXEL_FMT_GBRG8: @@ -267,6 +259,7 @@ process_image(MPPipeline *pipeline, MPZBarImage **_image) mp_zbar_image_unref(image); ++frames_processed; + */ } void @@ -288,7 +281,7 @@ mp_zbar_pipeline_process_image(MPZBarImage *image) MPZBarImage * mp_zbar_image_new(uint8_t *data, - MPPixelFormat pixel_format, + int format, int width, int height, int rotation, @@ -296,7 +289,7 @@ mp_zbar_image_new(uint8_t *data, { MPZBarImage *image = malloc(sizeof(MPZBarImage)); image->data = data; - image->pixel_format = pixel_format; + image->format = format; image->width = width; image->height = height; image->rotation = rotation; diff --git a/src/zbar_pipeline.h b/src/zbar_pipeline.h index cab39a0..92d048a 100644 --- a/src/zbar_pipeline.h +++ b/src/zbar_pipeline.h @@ -1,6 +1,7 @@ #pragma once -#include "camera_config.h" +#include +#include typedef struct _MPZBarImage MPZBarImage; @@ -22,7 +23,7 @@ void mp_zbar_pipeline_stop(); void mp_zbar_pipeline_process_image(MPZBarImage *image); MPZBarImage *mp_zbar_image_new(uint8_t *data, - MPPixelFormat pixel_format, + int format, int width, int height, int rotation,