From 4e8acf371ff4733a8d9307dda378c07513e6df36 Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Thu, 11 Jan 2024 22:46:56 +0200 Subject: [PATCH] Issue #252: YVYU support --- man/ustreamer.1 | 2 +- src/libs/frame.c | 1 + src/ustreamer/device.c | 1 + src/ustreamer/device.h | 2 +- src/ustreamer/encoders/cpu/encoder.c | 35 ++++++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/man/ustreamer.1 b/man/ustreamer.1 index 4895259..b687011 100644 --- a/man/ustreamer.1 +++ b/man/ustreamer.1 @@ -52,7 +52,7 @@ Initial image resolution. Default: 640x480. .TP .BR \-m\ \fIfmt ", " \-\-format\ \fIfmt Image format. -Available: YUYV, UYVY, RGB565, RGB24, JPEG; default: YUYV. +Available: YUYV, YVYU, UYVY, RGB565, RGB24, JPEG; default: YUYV. .TP .BR \-a\ \fIstd ", " \-\-tv\-standard\ \fIstd Force TV standard. diff --git a/src/libs/frame.c b/src/libs/frame.c index d2de28d..9a82559 100644 --- a/src/libs/frame.c +++ b/src/libs/frame.c @@ -73,6 +73,7 @@ unsigned us_frame_get_padding(const us_frame_s *frame) { unsigned bytes_per_pixel = 0; switch (frame->format) { case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_RGB565: bytes_per_pixel = 2; break; case V4L2_PIX_FMT_BGR24: diff --git a/src/ustreamer/device.c b/src/ustreamer/device.c index 1f305a1..22f2ff9 100644 --- a/src/ustreamer/device.c +++ b/src/ustreamer/device.c @@ -38,6 +38,7 @@ static const struct { const unsigned format; // cppcheck-suppress unusedStructMember } _FORMATS[] = { {"YUYV", V4L2_PIX_FMT_YUYV}, + {"YVYU", V4L2_PIX_FMT_YVYU}, {"UYVY", V4L2_PIX_FMT_UYVY}, {"RGB565", V4L2_PIX_FMT_RGB565}, {"RGB24", V4L2_PIX_FMT_RGB24}, diff --git a/src/ustreamer/device.h b/src/ustreamer/device.h index bb2d18f..7316d91 100644 --- a/src/ustreamer/device.h +++ b/src/ustreamer/device.h @@ -61,7 +61,7 @@ #define US_STANDARDS_STR "PAL, NTSC, SECAM" #define US_FORMAT_UNKNOWN -1 -#define US_FORMATS_STR "YUYV, UYVY, RGB565, RGB24, BGR24, MJPEG, JPEG" +#define US_FORMATS_STR "YUYV, YVYU, UYVY, RGB565, RGB24, BGR24, MJPEG, JPEG" #define US_IO_METHOD_UNKNOWN -1 #define US_IO_METHODS_STR "MMAP, USERPTR" diff --git a/src/ustreamer/encoders/cpu/encoder.c b/src/ustreamer/encoders/cpu/encoder.c index d3075be..a5af917 100644 --- a/src/ustreamer/encoders/cpu/encoder.c +++ b/src/ustreamer/encoders/cpu/encoder.c @@ -38,6 +38,7 @@ typedef struct { static void _jpeg_set_dest_frame(j_compress_ptr jpeg, us_frame_s *frame); static void _jpeg_write_scanlines_yuyv(struct jpeg_compress_struct *jpeg, const us_frame_s *frame); +static void _jpeg_write_scanlines_yvyu(struct jpeg_compress_struct *jpeg, const us_frame_s *frame); static void _jpeg_write_scanlines_uyvy(struct jpeg_compress_struct *jpeg, const us_frame_s *frame); static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, const us_frame_s *frame); static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame); @@ -77,6 +78,7 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q switch (src->format) { // https://www.fourcc.org/yuv.php WRITE_SCANLINES(V4L2_PIX_FMT_YUYV, _jpeg_write_scanlines_yuyv); + WRITE_SCANLINES(V4L2_PIX_FMT_YVYU, _jpeg_write_scanlines_yvyu); WRITE_SCANLINES(V4L2_PIX_FMT_UYVY, _jpeg_write_scanlines_uyvy); WRITE_SCANLINES(V4L2_PIX_FMT_RGB565, _jpeg_write_scanlines_rgb565); WRITE_SCANLINES(V4L2_PIX_FMT_RGB24, _jpeg_write_scanlines_rgb24); @@ -141,6 +143,39 @@ static void _jpeg_write_scanlines_yuyv(struct jpeg_compress_struct *jpeg, const free(line_buf); } +static void _jpeg_write_scanlines_yvyu(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) { + uint8_t *line_buf; + US_CALLOC(line_buf, frame->width * 3); + + const unsigned padding = us_frame_get_padding(frame); + const uint8_t *data = frame->data; + + while (jpeg->next_scanline < frame->height) { + uint8_t *ptr = line_buf; + + for (unsigned x = 0; x < frame->width; ++x) { + // See also: https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-yuyv.html + const bool is_odd_pixel = x & 1; + const uint8_t y = data[is_odd_pixel ? 2 : 0]; + const uint8_t u = data[3]; + const uint8_t v = data[1]; + + ptr[0] = y; + ptr[1] = u; + ptr[2] = v; + ptr += 3; + + data += (is_odd_pixel ? 4 : 0); + } + data += padding; + + JSAMPROW scanlines[1] = {line_buf}; + jpeg_write_scanlines(jpeg, scanlines, 1); + } + + free(line_buf); +} + static void _jpeg_write_scanlines_uyvy(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) { uint8_t *line_buf; US_CALLOC(line_buf, frame->width * 3);