diff --git a/doc/changes/auxiliary/mr.665.md b/doc/changes/auxiliary/mr.665.md new file mode 100644 index 000000000..fb95621d3 --- /dev/null +++ b/doc/changes/auxiliary/mr.665.md @@ -0,0 +1 @@ +u/sink: Add Bayer format converter. diff --git a/src/xrt/auxiliary/util/u_sink.h b/src/xrt/auxiliary/util/u_sink.h index 74948f49b..44558fc74 100644 --- a/src/xrt/auxiliary/util/u_sink.h +++ b/src/xrt/auxiliary/util/u_sink.h @@ -44,6 +44,15 @@ u_sink_create_to_r8g8b8_or_l8(struct xrt_frame_context *xfctx, struct xrt_frame_sink *downstream, struct xrt_frame_sink **out_xfs); +/*! + * @relatesalso xrt_frame_sink + * @relates xrt_frame_context + */ +void +u_sink_create_to_r8g8b8_bayer_or_l8(struct xrt_frame_context *xfctx, + struct xrt_frame_sink *downstream, + struct xrt_frame_sink **out_xfs); + /*! * @relatesalso xrt_frame_sink * @relates xrt_frame_context diff --git a/src/xrt/auxiliary/util/u_sink_converter.c b/src/xrt/auxiliary/util/u_sink_converter.c index 2437fb2ad..89f6b5e48 100644 --- a/src/xrt/auxiliary/util/u_sink_converter.c +++ b/src/xrt/auxiliary/util/u_sink_converter.c @@ -341,6 +341,44 @@ from_MJPEG_to_YUV888(struct xrt_frame *dst_frame, size_t size, const uint8_t *da #endif +/* + * + * Bayer + * + */ + +static void +from_BAYER_GR8_to_R8G8B8(struct xrt_frame *dst_frame, uint32_t w, uint32_t h, size_t stride, const uint8_t *data) +{ + const uint8_t *src_data = data; + uint32_t src_stride = stride; + + uint8_t *dst_data = dst_frame->data; + uint32_t dst_stride = dst_frame->stride; + + for (uint32_t y = 0; y < h; y++) { + const uint8_t *src0 = src_data + (y * 2) * src_stride; + const uint8_t *src1 = src_data + (y * 2 + 1) * src_stride; + uint8_t *dst = dst_data + (y * dst_stride); + + for (uint32_t x = 0; x < w; x++) { + uint8_t g0 = src0[0]; + uint8_t r = src0[1]; + uint8_t b = src1[0]; + uint8_t g1 = src1[1]; + + dst[0] = r; + dst[1] = (g0 + g1) / 2; + dst[2] = b; + + src0 += 2; + src1 += 2; + dst += 3; + } + } +} + + /* * * Misc functions. @@ -349,15 +387,16 @@ from_MJPEG_to_YUV888(struct xrt_frame *dst_frame, size_t size, const uint8_t *da /*! - * Creates a frame that the conversion should happen to. + * Creates a frame that the conversion should happen to, allows to set the size. * * @todo Allocate from a pool of frames. */ static bool -create_frame_with_format(struct xrt_frame *xf, enum xrt_format format, struct xrt_frame **out_frame) +create_frame_with_format_of_size( + struct xrt_frame *xf, uint32_t w, uint32_t h, enum xrt_format format, struct xrt_frame **out_frame) { struct xrt_frame *frame = NULL; - u_frame_create_one_off(format, xf->width, xf->height, &frame); + u_frame_create_one_off(format, w, h, &frame); if (frame == NULL) { U_LOG_E("Failed to create target frame!"); *out_frame = NULL; @@ -375,6 +414,15 @@ create_frame_with_format(struct xrt_frame *xf, enum xrt_format format, struct xr return true; } +/*! + * Creates a frame that the conversion should happen to. + */ +static bool +create_frame_with_format(struct xrt_frame *xf, enum xrt_format format, struct xrt_frame **out_frame) +{ + return create_frame_with_format_of_size(xf, xf->width, xf->height, format, out_frame); +} + static void receive_frame_r8g8b8_or_l8(struct xrt_frame_sink *xs, struct xrt_frame *xf) { @@ -385,6 +433,62 @@ receive_frame_r8g8b8_or_l8(struct xrt_frame_sink *xs, struct xrt_frame *xf) switch (xf->format) { case XRT_FORMAT_L8: case XRT_FORMAT_R8G8B8: s->downstream->push_frame(s->downstream, xf); return; + case XRT_FORMAT_BAYER_GR8:; + uint32_t w = xf->width / 2; + uint32_t h = xf->height / 2; + if (!create_frame_with_format_of_size(xf, w, h, XRT_FORMAT_R8G8B8, &converted)) { + return; + } + from_BAYER_GR8_to_R8G8B8(converted, w, h, xf->stride, xf->data); + break; + case XRT_FORMAT_YUYV422: + if (!create_frame_with_format(xf, XRT_FORMAT_R8G8B8, &converted)) { + return; + } + from_YUYV422_to_R8G8B8(converted, xf->width, xf->height, xf->stride, xf->data); + break; + case XRT_FORMAT_UYVY422: + if (!create_frame_with_format(xf, XRT_FORMAT_R8G8B8, &converted)) { + return; + } + from_UYVY422_to_R8G8B8(converted, xf->width, xf->height, xf->stride, xf->data); + break; + case XRT_FORMAT_YUV888: + if (!create_frame_with_format(xf, XRT_FORMAT_R8G8B8, &converted)) { + return; + } + from_YUV888_to_R8G8B8(converted, xf->width, xf->height, xf->stride, xf->data); + break; +#ifdef XRT_HAVE_JPEG + case XRT_FORMAT_MJPEG: + if (!create_frame_with_format(xf, XRT_FORMAT_R8G8B8, &converted)) { + return; + } + if (!from_MJPEG_to_R8G8B8(converted, xf->size, xf->data)) { + return; + } + break; +#endif + default: U_LOG_E("Can not convert from '%s' to R8G8B8 or L8!", u_format_str(xf->format)); return; + } + + s->downstream->push_frame(s->downstream, converted); + + // Refcount in case it's being held downstream. + xrt_frame_reference(&converted, NULL); +} + +static void +receive_frame_r8g8b8_bayer_or_l8(struct xrt_frame_sink *xs, struct xrt_frame *xf) +{ + struct u_sink_converter *s = (struct u_sink_converter *)xs; + + struct xrt_frame *converted = NULL; + + switch (xf->format) { + case XRT_FORMAT_L8: + case XRT_FORMAT_R8G8B8: + case XRT_FORMAT_BAYER_GR8:; s->downstream->push_frame(s->downstream, xf); return; case XRT_FORMAT_YUYV422: if (!create_frame_with_format(xf, XRT_FORMAT_R8G8B8, &converted)) { return; @@ -431,6 +535,14 @@ receive_frame_r8g8b8(struct xrt_frame_sink *xs, struct xrt_frame *xf) switch (xf->format) { case XRT_FORMAT_R8G8B8: s->downstream->push_frame(s->downstream, xf); return; + case XRT_FORMAT_BAYER_GR8:; + uint32_t w = xf->width / 2; + uint32_t h = xf->height / 2; + if (!create_frame_with_format_of_size(xf, w, h, XRT_FORMAT_R8G8B8, &converted)) { + return; + } + from_BAYER_GR8_to_R8G8B8(converted, w, h, xf->stride, xf->data); + break; case XRT_FORMAT_YUYV422: if (!create_frame_with_format(xf, XRT_FORMAT_R8G8B8, &converted)) { return; @@ -533,6 +645,27 @@ receive_frame_yuv_or_yuyv(struct xrt_frame_sink *xs, struct xrt_frame *xf) xrt_frame_reference(&converted, NULL); } +XRT_MAYBE_UNUSED static void +receive_frame_bayer(struct xrt_frame_sink *xs, struct xrt_frame *xf) +{ + struct u_sink_converter *s = (struct u_sink_converter *)xs; + + uint32_t w = xf->width / 2; + uint32_t h = xf->height / 2; + struct xrt_frame *converted = NULL; + + if (!create_frame_with_format_of_size(xf, w, h, XRT_FORMAT_R8G8B8, &converted)) { + return; + } + + from_BAYER_GR8_to_R8G8B8(converted, w, h, xf->stride, xf->data); + + s->downstream->push_frame(s->downstream, converted); + + // Refcount in case it's being held downstream. + xrt_frame_reference(&converted, NULL); +} + static void break_apart(struct xrt_frame_node *node) {} @@ -598,6 +731,23 @@ u_sink_create_to_r8g8b8_or_l8(struct xrt_frame_context *xfctx, *out_xfs = &s->base; } +void +u_sink_create_to_r8g8b8_bayer_or_l8(struct xrt_frame_context *xfctx, + struct xrt_frame_sink *downstream, + struct xrt_frame_sink **out_xfs) +{ + struct u_sink_converter *s = U_TYPED_CALLOC(struct u_sink_converter); + s->base.push_frame = receive_frame_r8g8b8_bayer_or_l8; + s->node.break_apart = break_apart; + s->node.destroy = destroy; + s->downstream = downstream; + + xrt_frame_context_add(xfctx, &s->node); + + *out_xfs = &s->base; +} + + void u_sink_create_to_yuv_yuyv_uyvy_or_l8(struct xrt_frame_context *xfctx, struct xrt_frame_sink *downstream,