diff --git a/.vscode/settings.json b/.vscode/settings.json index a4e4497..0d0d3b3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,6 +65,9 @@ "thread": "cpp", "cinttypes": "cpp", "typeinfo": "cpp", - "fourcc.h": "c" + "fourcc.h": "c", + "device.h": "c", + "log.h": "c", + "buffer_list.h": "c" } } diff --git a/device/camera/camera.c b/device/camera/camera.c index 9e6288a..c01e83c 100644 --- a/device/camera/camera.c +++ b/device/camera/camera.c @@ -6,10 +6,25 @@ #include "opts/log.h" #include "opts/fourcc.h" -void camera_init(camera_t *camera) +camera_t *camera_open(camera_options_t *options) { - memset(camera, 0, sizeof(*camera)); + camera_t *camera = calloc(1, sizeof(camera_t)); camera->name = "CAMERA"; + camera->options = *options; + + if (camera_configure_input(camera) < 0) { + goto error; + } + + if (camera_set_params(camera) < 0) { + goto error; + } + + return camera; + +error: + camera_close(camera); + return NULL; } void camera_close(camera_t *camera) @@ -34,38 +49,32 @@ void camera_close(camera_t *camera) free(camera); } -camera_t *camera_open(camera_options_t *options) +link_t *camera_ensure_capture(camera_t *camera, buffer_list_t *capture) { - camera_t *camera = calloc(1, sizeof(camera_t)); - camera->name = "CAMERA"; - camera->options = *options; - - switch (camera->options.type) { - case CAMERA_V4L2: - if (camera_configure_v4l2(camera) < 0) { - goto error; + for (int i = 0; i < camera->nlinks; i++) { + if (camera->links[i].source == capture) { + return &camera->links[i]; } - break; - - case CAMERA_LIBCAMERA: - if (camera_configure_libcamera(camera) < 0) { - goto error; - } - break; - - default: - LOG_ERROR(camera, "Unsupported camera type"); } - if (camera_set_params(camera) < 0) { - goto error; - } + link_t *link = &camera->links[camera->nlinks++]; + link->source = capture; + return link; +} - return camera; +void camera_capture_add_output(camera_t *camera, buffer_list_t *capture, buffer_list_t *output) +{ + link_t *link = camera_ensure_capture(camera, capture); -error: - camera_close(camera); - return NULL; + int nsinks; + for (nsinks = 0; link->sinks[nsinks]; nsinks++); + link->sinks[nsinks] = output; +} + +void camera_capture_set_callbacks(camera_t *camera, buffer_list_t *capture, link_callbacks_t callbacks) +{ + link_t *link = camera_ensure_capture(camera, capture); + link->callbacks = callbacks; } int camera_set_params(camera_t *camera) @@ -76,6 +85,7 @@ int camera_set_params(camera_t *camera) // Set some defaults for (int i = 0; i < 2; i++) { + device_set_option_list(camera->legacy_isp[2], camera->options.isp.options); device_set_option_string(camera->codec_jpeg[i], "compression_quality", "80"); device_set_option_string(camera->codec_h264[i], "video_bitrate_mode", "0"); device_set_option_string(camera->codec_h264[i], "video_bitrate", "5000000"); @@ -88,16 +98,6 @@ int camera_set_params(camera_t *camera) device_set_option_list(camera->codec_jpeg[i], camera->options.jpeg.options); device_set_option_list(camera->codec_h264[i], camera->options.h264.options); } - - // DEVICE_SET_OPTION(camera->camera, EXPOSURE, 2684); - // DEVICE_SET_OPTION(camera->camera, ANALOGUE_GAIN, 938); - // DEVICE_SET_OPTION(camera->camera, DIGITAL_GAIN, 512); - // DEVICE_SET_OPTION(camera->camera, VBLANK, 1636); - // DEVICE_SET_OPTION(camera->camera, HBLANK, 6906); - - // DEVICE_SET_OPTION(camera->isp_srgb, RED_BALANCE, 2120); - // DEVICE_SET_OPTION(camera->isp_srgb, BLUE_BALANCE, 1472); - // DEVICE_SET_OPTION(camera->isp_srgb, DIGITAL_GAIN, 1007); return 0; } @@ -105,4 +105,4 @@ int camera_run(camera_t *camera) { bool running = false; return links_loop(camera->links, &running); -} \ No newline at end of file +} diff --git a/device/camera/camera.h b/device/camera/camera.h index cad82a7..1446b0c 100644 --- a/device/camera/camera.h +++ b/device/camera/camera.h @@ -70,10 +70,10 @@ link_t *camera_ensure_capture(camera_t *camera, buffer_list_t *capture); void camera_capture_add_output(camera_t *camera, buffer_list_t *capture, buffer_list_t *output); void camera_capture_set_callbacks(camera_t *camera, buffer_list_t *capture, link_callbacks_t callbacks); -int camera_configure_output(camera_t *camera, buffer_list_t *src_capture, int res); +int camera_configure_input(camera_t *camera); int camera_configure_decoder(camera_t *camera, buffer_list_t *src_capture); +int camera_configure_output_rescaler(camera_t *camera, buffer_list_t *src_capture, float high_div, float low_div); +int camera_configure_output(camera_t *camera, buffer_list_t *src_capture, int res); -int camera_configure_v4l2(camera_t *camera); -int camera_configure_libcamera(camera_t *camera); int camera_configure_isp(camera_t *camera, buffer_list_t *src, float high_div, float low_div); int camera_configure_legacy_isp(camera_t *camera, buffer_list_t *src, float div, int res); diff --git a/device/camera/camera_decoder.c b/device/camera/camera_decoder.c index f75e7af..5721bd6 100644 --- a/device/camera/camera_decoder.c +++ b/device/camera/camera_decoder.c @@ -22,20 +22,6 @@ int camera_configure_decoder(camera_t *camera, buffer_list_t *src_capture) camera_capture_add_output(camera, src_capture, decoder_output); - if (camera_configure_output(camera, decoder_capture, 0) < 0) { - return -1; - } - - if (camera->options.low_res_factor > 1) { - float div = camera->options.low_res_factor / camera->options.high_res_factor; - - if (camera_configure_legacy_isp(camera, decoder_capture, div, 1) < 0) { - return -1; - } - } - - if (device_set_decoder_start(camera->decoder, true) < 0) { - return -1; - } - return 0; + return camera_configure_output_rescaler(camera, decoder_capture, + camera->options.high_res_factor, camera->options.low_res_factor); } diff --git a/device/camera/camera_input.c b/device/camera/camera_input.c new file mode 100644 index 0000000..1d21d7f --- /dev/null +++ b/device/camera/camera_input.c @@ -0,0 +1,104 @@ +#include "camera.h" + +#include "device/buffer.h" +#include "device/buffer_list.h" +#include "device/device.h" +#include "device/links.h" +#include "opts/log.h" +#include "opts/fourcc.h" + +static int camera_configure_input_v4l2(camera_t *camera) +{ + camera->camera = device_v4l2_open(camera->name, camera->options.path); + if (!camera->camera) { + return -1; + } + + camera->camera->opts.allow_dma = camera->options.allow_dma; + + if (strstr(camera->camera->bus_info, "usb")) { + LOG_INFO(camera, "Disabling DMA since device uses USB (which is likely not working properly)."); + camera->camera->opts.allow_dma = false; + } + + buffer_list_t *camera_capture = device_open_buffer_list(camera->camera, true, camera->options.width, camera->options.height, camera->options.format, 0, camera->options.nbufs, true); + if (!camera_capture) { + return -1; + } + camera_capture->do_timestamps = true; + + if (camera->options.fps > 0) { + camera_capture->fmt.interval_us = 1000 * 1000 / camera->options.fps; + } + + switch (camera_capture->fmt.format) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB24: + if (camera->options.high_res_factor > 1) { + // Use ISP, as there are two resolutions + return camera_configure_isp(camera, camera_capture, + camera->options.high_res_factor, camera->options.low_res_factor); + } else { + // Use direct approach, as there's likely low frequently used low resolution + return camera_configure_output_rescaler(camera, camera_capture, + camera->options.high_res_factor, camera->options.low_res_factor); + } + + case V4L2_PIX_FMT_MJPEG: + case V4L2_PIX_FMT_H264: + return camera_configure_decoder(camera, camera_capture); + + case V4L2_PIX_FMT_SRGGB10P: + return camera_configure_isp(camera, camera_capture, + camera->options.high_res_factor, camera->options.low_res_factor); + + default: + LOG_INFO(camera, "Unsupported camera format=%s", + fourcc_to_string(camera_capture->fmt.format).buf); + return -1; + } +} + +static int camera_configure_input_libcamera(camera_t *camera) +{ + camera->camera = device_libcamera_open(camera->name, camera->options.path); + if (!camera->camera) { + return -1; + } + + camera->camera->opts.allow_dma = camera->options.allow_dma; + + buffer_list_t *camera_capture = device_open_buffer_list( + camera->camera, true, camera->options.width / camera->options.high_res_factor, camera->options.height / camera->options.high_res_factor, camera->options.format, 0, camera->options.nbufs, true); + if (!camera_capture) { + return -1; + } + camera_capture->do_timestamps = true; + + if (camera->options.fps > 0) { + camera_capture->fmt.interval_us = 1000 * 1000 / camera->options.fps; + } + + return camera_configure_output_rescaler(camera, camera_capture, + 1.0, camera->options.low_res_factor / camera->options.high_res_factor); +} + +int camera_configure_input(camera_t *camera) +{ + switch (camera->options.type) { + case CAMERA_V4L2: + return camera_configure_input_v4l2(camera); + + case CAMERA_LIBCAMERA: + return camera_configure_input_libcamera(camera); + + default: + LOG_INFO(camera, "Unsupported camera type"); + return -1; + } +} diff --git a/device/camera/camera_legacy_isp.c b/device/camera/camera_legacy_isp.c index aa02b55..ca1316a 100644 --- a/device/camera/camera_legacy_isp.c +++ b/device/camera/camera_legacy_isp.c @@ -9,9 +9,14 @@ #include "device/buffer_list.h" #include "http/http.h" +static const char *isp_names[2] = { + "ISP", + "ISP-LOW" +}; + int camera_configure_legacy_isp(camera_t *camera, buffer_list_t *src_capture, float div, int res) { - camera->legacy_isp[res] = device_v4l2_open("ISP", "/dev/video12"); + camera->legacy_isp[res] = device_v4l2_open(isp_names[res], "/dev/video12"); buffer_list_t *isp_output = device_open_buffer_list_output( camera->legacy_isp[res], src_capture); diff --git a/device/camera/camera_libcamera.c b/device/camera/camera_libcamera.c deleted file mode 100644 index 47b63a0..0000000 --- a/device/camera/camera_libcamera.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "camera.h" - -#include "device/buffer.h" -#include "device/buffer_list.h" -#include "device/device.h" -#include "device/links.h" -#include "opts/log.h" -#include "opts/fourcc.h" - -int camera_configure_libcamera(camera_t *camera) -{ - camera->camera = device_libcamera_open(camera->name, camera->options.path); - if (!camera->camera) { - goto error; - } - - camera->camera->opts.allow_dma = camera->options.allow_dma; - - buffer_list_t *camera_capture = device_open_buffer_list( - camera->camera, true, camera->options.width / camera->options.high_res_factor, camera->options.height / camera->options.high_res_factor, camera->options.format, 0, camera->options.nbufs, true); - if (!camera_capture) { - goto error; - } - camera_capture->do_timestamps = true; - - if (camera->options.fps > 0) { - camera_capture->fmt.interval_us = 1000 * 1000 / camera->options.fps; - } - - if (camera_configure_output(camera, camera_capture, 0) < 0) { - goto error; - } - - if (camera->options.low_res_factor > 1) { - float div = camera->options.low_res_factor / camera->options.high_res_factor; - - if (camera_configure_legacy_isp(camera, camera_capture, div, 1) < 0) { - return -1; - } - } - - return 0; - -error: - return -1; -} \ No newline at end of file diff --git a/device/camera/camera_links.c b/device/camera/camera_links.c deleted file mode 100644 index 7e2b900..0000000 --- a/device/camera/camera_links.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "camera.h" - -#include "device/buffer.h" -#include "device/buffer_list.h" -#include "device/device.h" -#include "device/links.h" -#include "opts/log.h" -#include "opts/fourcc.h" -#include "device/buffer_list.h" -#include "http/http.h" - -link_t *camera_ensure_capture(camera_t *camera, buffer_list_t *capture) -{ - for (int i = 0; i < camera->nlinks; i++) { - if (camera->links[i].source == capture) { - return &camera->links[i]; - } - } - - link_t *link = &camera->links[camera->nlinks++]; - link->source = capture; - return link; -} - -void camera_capture_add_output(camera_t *camera, buffer_list_t *capture, buffer_list_t *output) -{ - link_t *link = camera_ensure_capture(camera, capture); - - int nsinks; - for (nsinks = 0; link->sinks[nsinks]; nsinks++); - link->sinks[nsinks] = output; -} - -void camera_capture_set_callbacks(camera_t *camera, buffer_list_t *capture, link_callbacks_t callbacks) -{ - link_t *link = camera_ensure_capture(camera, capture); - link->callbacks = callbacks; -} diff --git a/device/camera/camera_output.c b/device/camera/camera_output.c index 1f3dd01..4e3d2dc 100644 --- a/device/camera/camera_output.c +++ b/device/camera/camera_output.c @@ -76,3 +76,28 @@ int camera_configure_output(camera_t *camera, buffer_list_t *src_capture, int re return camera_configure_h264_output(camera, src_capture, res) == 0 && camera_configure_jpeg_output(camera, src_capture, res) == 0; } + +int camera_configure_output_rescaler(camera_t *camera, buffer_list_t *src_capture, float high_div, float low_div) +{ + if (high_div > 1) { + if (camera_configure_legacy_isp(camera, src_capture, high_div, 0) < 0) { + return -1; + } + } else if (high_div > 0) { + if (camera_configure_output(camera, src_capture, 0) < 0) { + return -1; + } + } + + if (low_div > 1) { + if (camera_configure_legacy_isp(camera, src_capture, low_div, 1) < 0) { + return -1; + } + } else if (low_div > 0) { + if (camera_configure_output(camera, src_capture, 1) < 0) { + return -1; + } + } + + return 0; +} \ No newline at end of file diff --git a/device/camera/camera_v4l2.c b/device/camera/camera_v4l2.c deleted file mode 100644 index 456b68c..0000000 --- a/device/camera/camera_v4l2.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "camera.h" - -#include "device/buffer.h" -#include "device/buffer_list.h" -#include "device/device.h" -#include "device/links.h" -#include "opts/log.h" -#include "opts/fourcc.h" - -int camera_configure_v4l2(camera_t *camera) -{ - camera->camera = device_v4l2_open(camera->name, camera->options.path); - if (!camera->camera) { - goto error; - } - - camera->camera->opts.allow_dma = camera->options.allow_dma; - - if (strstr(camera->camera->bus_info, "usb")) { - LOG_INFO(camera, "Disabling DMA since device uses USB (which is likely not working properly)."); - camera->camera->opts.allow_dma = false; - } - - buffer_list_t *camera_capture = device_open_buffer_list(camera->camera, true, camera->options.width, camera->options.height, camera->options.format, 0, camera->options.nbufs, true); - if (!camera_capture) { - goto error; - } - camera_capture->do_timestamps = true; - - if (camera->options.fps > 0) { - camera_capture->fmt.interval_us = 1000 * 1000 / camera->options.fps; - } - - switch (camera_capture->fmt.format) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB24: - if (camera_configure_output(camera, camera_capture, 0) < 0) { - goto error; - } - break; - - case V4L2_PIX_FMT_MJPEG: - case V4L2_PIX_FMT_H264: - if (camera_configure_decoder(camera, camera_capture) < 0) { - goto error; - } - break; - - case V4L2_PIX_FMT_SRGGB10P: -#if 1 - if (camera_configure_isp(camera, camera_capture, camera->options.high_res_factor, camera->options.low_res_factor) < 0) { - goto error; - } -#else - if (camera_configure_legacy_isp(camera, camera_capture, camera->options.high_res_factor, 0) < 0) { - goto error; - } -#endif - break; - - default: - LOG_ERROR(camera, "Unsupported camera format=%s", - fourcc_to_string(camera_capture->fmt.format).buf); - break; - } - - return 0; - -error: - return -1; -} \ No newline at end of file