diff --git a/camera.c b/camera.c index 20362b9..64e3493 100644 --- a/camera.c +++ b/camera.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,12 @@ static const char *pixel_format_names[MP_PIXEL_FMT_MAX] = { "GBRG8", "GRBG8", "RGGB8", + "BGGR10P", + "GBRG10P", + "GRBG10P", + "RGGB10P", + "UYVY", + "YUYV", }; const char *mp_pixel_format_to_str(uint32_t pixel_format) @@ -38,6 +45,12 @@ static const uint32_t pixel_format_v4l_pixel_formats[MP_PIXEL_FMT_MAX] = { 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) @@ -62,6 +75,12 @@ static const uint32_t pixel_format_v4l_bus_codes[MP_PIXEL_FMT_MAX] = { 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) @@ -80,14 +99,68 @@ MPPixelFormat mp_pixel_format_from_v4l_bus_code(uint32_t v4l_bus_code) return MP_PIXEL_FMT_UNSUPPORTED; } -uint32_t mp_pixel_format_bytes_per_pixel(MPPixelFormat pixel_format) +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 1; + 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_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_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; } } @@ -427,7 +500,7 @@ bool mp_camera_capture_image(MPCamera *camera, void (*callback)(MPImage, void *) uint32_t width = camera->current_mode.width; uint32_t height = camera->current_mode.height; - assert(buf.bytesused == mp_pixel_format_bytes_per_pixel(pixel_format) * width * height); + assert(buf.bytesused == mp_pixel_format_width_to_bytes(pixel_format, width) * height); assert(buf.bytesused == camera->buffers[buf.index].length); MPImage image = { diff --git a/camera.h b/camera.h index 7be616c..50f2d61 100644 --- a/camera.h +++ b/camera.h @@ -10,6 +10,12 @@ typedef enum { 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; @@ -22,7 +28,10 @@ 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_bytes_per_pixel(MPPixelFormat pixel_format); +uint32_t mp_pixel_format_bits_per_pixel(MPPixelFormat pixel_format); +uint32_t mp_pixel_format_width_to_bytes(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; diff --git a/device.c b/device.c index 99634d7..ff1c0de 100644 --- a/device.c +++ b/device.c @@ -67,20 +67,10 @@ static int xioctl(int fd, int request, void *arg) MPDevice *mp_device_find(const char *driver_name) { - MPDevice *found_device = NULL; - - int length = strlen(driver_name); MPDeviceList *list = mp_device_list_new(); - for (MPDeviceList *item = list; item; item = mp_device_list_next(item)) { - MPDevice *device = mp_device_list_get(item); - const struct media_device_info *info = mp_device_get_info(device); + MPDevice *found_device = mp_device_list_find_remove(&list, driver_name); - if (strncmp(info->driver, driver_name, length) == 0) { - found_device = mp_device_list_remove(&item); - break; - } - } mp_device_list_free(list); @@ -375,6 +365,26 @@ void mp_device_list_free(MPDeviceList *device_list) } } +MPDevice *mp_device_list_find_remove(MPDeviceList **list, const char *driver_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) { + 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; diff --git a/device.h b/device.h index 0276da8..86644af 100644 --- a/device.h +++ b/device.h @@ -42,6 +42,7 @@ 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); MPDevice *mp_device_list_remove(MPDeviceList **device_list); MPDevice *mp_device_list_get(const MPDeviceList *device_list); diff --git a/pipeline.c b/pipeline.c index 3acc6e3..42ac8f1 100644 --- a/pipeline.c +++ b/pipeline.c @@ -32,7 +32,7 @@ MPPipeline *mp_pipeline_new() struct invoke_args { MPPipeline *pipeline; - void (*callback)(MPPipeline *, void *); + MPPipelineCallback callback; }; static bool invoke_impl(struct invoke_args *args) @@ -41,7 +41,7 @@ static bool invoke_impl(struct invoke_args *args) return false; } -void mp_pipeline_invoke(MPPipeline *pipeline, MPPipelineCallback callback, void *data, size_t size) +void mp_pipeline_invoke(MPPipeline *pipeline, MPPipelineCallback callback, const void *data, size_t size) { if (pthread_self() != pipeline->thread) { struct invoke_args *args = malloc(sizeof(struct invoke_args) + size); @@ -75,63 +75,34 @@ void mp_pipeline_free(MPPipeline *pipeline) free(pipeline); } -struct _MPPipelineCapture { - MPPipeline *pipeline; +struct capture_source_args +{ MPCamera *camera; - void (*callback)(MPImage, void *); void *user_data; - GSource *video_source; }; -static bool on_capture(int fd, GIOCondition condition, MPPipelineCapture *capture) +static bool on_capture(int fd, GIOCondition condition, struct capture_source_args *args) { - mp_camera_capture_image(capture->camera, capture->callback, capture->user_data); + mp_camera_capture_image(args->camera, args->callback, args->user_data); return true; } -static void capture_start_impl(MPPipeline *pipeline, MPPipelineCapture **_capture) +// Not thread safe +GSource *mp_pipeline_add_capture_source(MPPipeline *pipeline, MPCamera *camera, void (*callback)(MPImage, void *), void *user_data) { - MPPipelineCapture *capture = *_capture; + int video_fd = mp_camera_get_video_fd(camera); + GSource *video_source = g_unix_fd_source_new(video_fd, G_IO_IN); - mp_camera_start_capture(capture->camera); - - // Start watching for new captures - int video_fd = mp_camera_get_video_fd(capture->camera); - capture->video_source = g_unix_fd_source_new(video_fd, G_IO_IN); + struct capture_source_args *args = malloc(sizeof(struct capture_source_args)); + args->camera = camera; + args->callback = callback; + args->user_data = user_data; g_source_set_callback( - capture->video_source, + video_source, (GSourceFunc)on_capture, - capture, - NULL); - g_source_attach(capture->video_source, capture->pipeline->main_context); -} - -MPPipelineCapture *mp_pipeline_capture_start(MPPipeline *pipeline, MPCamera *camera, void (*callback)(MPImage, void *), void *user_data) -{ - MPPipelineCapture *capture = malloc(sizeof(MPPipelineCapture)); - capture->pipeline = pipeline; - capture->camera = camera; - capture->callback = callback; - capture->user_data = user_data; - capture->video_source = NULL; - - mp_pipeline_invoke(pipeline, (MPPipelineCallback)capture_start_impl, &capture, sizeof(MPPipelineCapture *)); - - return capture; -} - -static void capture_end_impl(MPPipeline *pipeline, MPPipelineCapture **_capture) -{ - MPPipelineCapture *capture = *_capture; - - mp_camera_stop_capture(capture->camera); - g_source_destroy(capture->video_source); - - free(capture); -} - -void mp_pipeline_capture_end(MPPipelineCapture *capture) -{ - mp_pipeline_invoke(capture->pipeline, (MPPipelineCallback)capture_end_impl, &capture, sizeof(MPPipelineCapture *)); + args, + free); + g_source_attach(video_source, pipeline->main_context); + return video_source; } diff --git a/pipeline.h b/pipeline.h index a552b26..b40f572 100644 --- a/pipeline.h +++ b/pipeline.h @@ -2,16 +2,14 @@ #include "camera.h" #include "device.h" +#include typedef struct _MPPipeline MPPipeline; -typedef void (*MPPipelineCallback)(MPPipeline *, void *); +typedef void (*MPPipelineCallback)(MPPipeline *, const void *); MPPipeline *mp_pipeline_new(); -void mp_pipeline_invoke(MPPipeline *pipeline, MPPipelineCallback callback, void *data, size_t size); +void mp_pipeline_invoke(MPPipeline *pipeline, MPPipelineCallback callback, const void *data, size_t size); void mp_pipeline_free(MPPipeline *pipeline); -typedef struct _MPPipelineCapture MPPipelineCapture; - -MPPipelineCapture *mp_pipeline_capture_start(MPPipeline *pipeline, MPCamera *camera, void (*capture)(MPImage, void *), void *data); -void mp_pipeline_capture_end(MPPipelineCapture *capture); +GSource *mp_pipeline_add_capture_source(MPPipeline *pipeline, MPCamera *camera, void (*callback)(MPImage, void *), void *user_data);