Browse Source

Implement flash LED/V4L support, LED being copied partially from Megapixels

Kristian Vos 11 tháng trước cách đây
mục cha
commit
9b522a982b
10 tập tin đã thay đổi với 164 bổ sung6 xóa
  1. 1 1
      CMakeLists.txt
  2. 0 1
      config/pine64,pinephone-pro.conf
  3. 6 0
      include/libmegapixels.h
  4. 1 0
      meson.build
  5. 56 0
      src/flash.c
  6. 7 0
      src/flash.h
  7. 11 2
      src/parse.c
  8. 13 0
      src/pipeline.c
  9. 65 1
      src/util.c
  10. 4 1
      src/util.h

+ 1 - 1
CMakeLists.txt

@@ -7,7 +7,7 @@ set(LIBRARY_VERSION_STRING 0.1)
 set(CMAKE_C_STANDARD 23)
 set(CMAKE_C_VISIBILITY_PRESET hidden)
 
-add_library(megapixels SHARED include/libmegapixels.h src/findconfig.c src/parse.c src/mode.c src/pipeline.c src/log.c src/util.c src/convert.c src/aaa.c config.h)
+add_library(megapixels SHARED include/libmegapixels.h src/findconfig.c src/parse.c src/mode.c src/pipeline.c src/log.c src/util.c src/convert.c src/aaa.c src/flash.c config.h)
 set_target_properties(megapixels PROPERTIES
         VERSION ${LIBRARY_VERSION_STRING}
         SOVERSION ${LIBRARY_VERSION_MAJOR}

+ 0 - 1
config/pine64,pinephone-pro.conf

@@ -5,7 +5,6 @@ Model: "PinePhone Pro";
 Rear: {
     SensorDriver: "imx258";
     BridgeDriver: "rkisp1";
-    FlashPath: "/sys/class/leds/white:flash";
 
     Modes: (
         {

+ 6 - 0
include/libmegapixels.h

@@ -204,4 +204,10 @@ libmegapixels_aaa_set_matrix(libmegapixels_aaa_stats *stats, const float matrix1
 EXPORT void
 libmegapixels_aaa_software_statistics(libmegapixels_aaa_stats *stats, const unsigned int *frame, int width, int height);
 
+EXPORT void
+libmegapixels_flash_on(libmegapixels_camera *camera);
+
+EXPORT void
+libmegapixels_flash_off(libmegapixels_camera *camera);
+
 #endif

+ 1 - 0
meson.build

@@ -32,6 +32,7 @@ lib_src = [
     'src/parse.c',
     'src/pipeline.c',
     'src/aaa.c',
+    'src/flash.c',
 ]
 libmegapixels = shared_library('megapixels', lib_src,
     version: libmegapixels_so_version,

+ 56 - 0
src/flash.c

@@ -0,0 +1,56 @@
+#include <libmegapixels.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "flash.h"
+#include "util.h"
+
+// Flash path is used for both the V4L path, and the LED path, and can be overwritten by a later stage, so memory is first freed
+void
+libmegapixels_flash_cleanup_flash_path(libmegapixels_camera *camera)
+{
+	if (camera->flash_path != NULL) {
+		free(camera->flash_path);
+		camera->flash_path = NULL;
+	}
+}
+
+// Given the LED path (e.g., /sys/class/leds/white:flash), it'll append /flash_strobe at the end
+char *
+libmegapixels_flash_get_led_path(const char *path)
+{
+	char *result = malloc(PATH_MAX);
+	if (result == NULL) {
+		return NULL;
+	}
+
+	snprintf(result, PATH_MAX, "%s/flash_strobe", path);
+
+	return result;
+}
+
+// Turns on the LED/V4L flash/strobe
+void
+libmegapixels_flash_on(libmegapixels_camera *camera)
+{
+	if (camera->flash_type == LIBMEGAPIXELS_FLASH_LED) {
+		lseek(camera->flash_fd, 0, SEEK_SET);
+		dprintf(camera->flash_fd, "1\n");
+	} else if (camera->flash_type == LIBMEGAPIXELS_FLASH_V4L) {
+		// Mode must be flash, and strobe source must be software, for strobe to be possible
+		// Strobe source may not exist, which is fine, we ignore the result
+		set_control(camera->flash_fd, V4L2_CID_FLASH_LED_MODE, V4L2_FLASH_LED_MODE_FLASH);
+		set_control(camera->flash_fd, V4L2_CID_FLASH_STROBE_SOURCE, V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
+
+		// Starts the flash strobe. It will automatically stop
+		set_control(camera->flash_fd, V4L2_CID_FLASH_STROBE, 1);
+	}
+}
+
+// Turns off the LED/V4L flash/strobe, where applicable
+void
+libmegapixels_flash_off(libmegapixels_camera *camera)
+{
+	// Neither LED nor V4L currently needs any action in here, but in the future those or a different method may need to turn flash off here
+	// For example, if flash strobe doesn't work, and we need to manually turn on/off torch mode
+}

+ 7 - 0
src/flash.h

@@ -0,0 +1,7 @@
+#include <libmegapixels.h>
+
+char *
+libmegapixels_flash_get_led_path(const char *path);
+
+void
+libmegapixels_flash_cleanup_flash_path(libmegapixels_camera *camera);

+ 11 - 2
src/parse.c

@@ -15,6 +15,7 @@
 #include "mode.h"
 #include "util.h"
 #include "log.h"
+#include "flash.h"
 
 char *
 find_path_for_devnode(struct media_v2_intf_devnode devnode)
@@ -265,14 +266,22 @@ load_camera(libmegapixels_devconfig *config, config_t *cfg, const char *name, in
 	config->cameras[config->count++] = camera;
 
 	if (config_setting_lookup_string(root, "FlashPath", &flashpath)) {
-		camera->flash_path = strdup(flashpath);
 		camera->flash_type = LIBMEGAPIXELS_FLASH_LED;
+		libmegapixels_flash_cleanup_flash_path(camera);
+		camera->flash_path = libmegapixels_flash_get_led_path(flashpath);
+
+		if (camera->flash_path == NULL) {
+			log_error("Failed to get LED flash path\n");
+			return -1;
+		}
 	}
+
+	// You do not need to set FlashDisplay in device config files, unless for some reason there's a V4L flash device that isn't meant to be there
 	int flashDisplay = 0;
 	if (config_setting_lookup_bool(root, "FlashDisplay", &flashDisplay)) {
 		if (flashDisplay) {
-			camera->flash_path = NULL;
 			camera->flash_type = LIBMEGAPIXELS_FLASH_SCREEN;
+			libmegapixels_flash_cleanup_flash_path(camera);
 		}
 	}
 

+ 13 - 0
src/pipeline.c

@@ -151,6 +151,15 @@ libmegapixels_open(libmegapixels_camera *camera)
 		}
 	}
 
+	// Flash path can be either the v4l device path, or the /sys/class/leds/... path
+	if (camera->flash_path) {
+		camera->flash_fd = open(camera->flash_path, O_RDWR);
+		if (camera->flash_fd < 0) {
+			log_error("Could not open %s: %s\n", camera->flash_path, strerror(errno));
+			return -1;
+		}
+	}
+
 	camera->video_fd = open(camera->video_path, O_RDWR);
 	if (camera->video_fd < 0) {
 		log_error("Could not open %s: %s\n", camera->video_path, strerror(errno));
@@ -195,6 +204,10 @@ libmegapixels_close(libmegapixels_camera *camera)
 		close(camera->video_fd);
 		camera->video_fd = 0;
 	}
+	if (camera->flash_fd != 0) {
+		close(camera->flash_fd);
+		camera->flash_fd = 0;
+	}
 
 	for (int i = 0; i < camera->num_handles; i++) {
 		if (camera->handles[i]->fd != 0) {

+ 65 - 1
src/util.c

@@ -1,6 +1,9 @@
 #include <sys/ioctl.h>
 #include <errno.h>
+#include <linux/v4l2-subdev.h>
+#include <stdio.h>
 #include "util.h"
+#include "log.h"
 
 int
 xioctl(int fd, int request, void *arg)
@@ -10,4 +13,65 @@ xioctl(int fd, int request, void *arg)
 		r = ioctl(fd, request, arg);
 	} while (r == -1 && errno == EINTR);
 	return r;
-}
+}
+
+// Copied from drivers/media/v4l2-core/v4l2-ctrls-defs.c, trimmed down
+const char
+*
+v4l2_ctrl_get_name(unsigned int id)
+{
+	switch (id) {
+		case V4L2_CID_FLASH_LED_MODE:
+			return "LED Mode";
+		case V4L2_CID_FLASH_STROBE_SOURCE:
+			return "Strobe Source";
+		case V4L2_CID_FLASH_STROBE:
+			return "Strobe";
+		default:
+			return "Unknown";
+	}
+}
+
+// Copied from drivers/media/v4l2-core/v4l2-ctrls-defs.c, trimmed down and slightly modified
+const char
+*
+v4l2_ctrl_get_menu_value(unsigned int id, signed int val)
+{
+	static const char *const flash_led_mode[] = {
+		"Off",
+		"Flash",
+		"Torch",
+		NULL,
+	};
+	static const char *const flash_strobe_source[] = {
+		"Software",
+		"External",
+		NULL,
+	};
+
+	switch (id) {
+		case V4L2_CID_FLASH_LED_MODE:
+			return flash_led_mode[val];
+		case V4L2_CID_FLASH_STROBE_SOURCE:
+			return flash_strobe_source[val];
+		default:
+			return "None/Unknown";
+	}
+}
+
+// Set a control value, but ignore if it fails
+void
+set_control(int fd, unsigned int ctrl_id, signed int ctrl_val)
+{
+	struct v4l2_control ctrl;
+	ctrl.id = ctrl_id;
+	ctrl.value = ctrl_val;
+	int res = xioctl(fd, VIDIOC_S_CTRL, &ctrl);
+	if (res == -1) {
+		log_debug(
+			"Failed to set %s to %s for flash.\n",
+			v4l2_ctrl_get_name(ctrl_id),
+			v4l2_ctrl_get_menu_value(ctrl_id, ctrl_val)
+		);
+	}
+}

+ 4 - 1
src/util.h

@@ -1,4 +1,7 @@
 #pragma once
 
 int
-xioctl(int fd, int request, void *arg);
+xioctl(int fd, int request, void *arg);
+
+void
+set_control(int fd, unsigned int ctrl_id, signed int ctrl_val);