Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for YUV420 and YVU variants. #276

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/libs/capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ static const struct {
{"BGR24", V4L2_PIX_FMT_BGR24},
{"MJPEG", V4L2_PIX_FMT_MJPEG},
{"JPEG", V4L2_PIX_FMT_JPEG},
{"YU12", V4L2_PIX_FMT_YUV420},
{"YV12", V4L2_PIX_FMT_YVU420},
};

static const struct {
Expand Down Expand Up @@ -416,8 +418,10 @@ int us_capture_hwbuf_grab(us_capture_s *cap, us_capture_hwbuf_s **hw) {
_v4l2_buffer_copy(&buf, &(*hw)->buf);
(*hw)->raw.grab_ts = (ldf)((buf.timestamp.tv_sec * (u64)1000) + (buf.timestamp.tv_usec / 1000)) / 1000;

_LOG_DEBUG("Grabbed HW buffer=%u: bytesused=%u, grab_ts=%.3Lf, latency=%.3Lf, skipped=%u",
buf.index, buf.bytesused, (*hw)->raw.grab_ts, us_get_now_monotonic() - (*hw)->raw.grab_ts, skipped);
_LOG_DEBUG("Grabbed HW buffer=%u: bytesused=%u, length=%u, grab_ts=%.3Lf, latency=%.3Lf, skipped=%u, "
"width=%u, height=%u, stride=%u",
buf.index, buf.bytesused, buf.length, (*hw)->raw.grab_ts, us_get_now_monotonic() - (*hw)->raw.grab_ts, skipped,
(*hw)->raw.width, (*hw)->raw.height, (*hw)->raw.stride);
return buf.index;
}

Expand Down
3 changes: 2 additions & 1 deletion src/libs/capture.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
#define US_VIDEO_MAX_FPS ((uint)120)

#define US_STANDARDS_STR "PAL, NTSC, SECAM"
#define US_FORMATS_STR "YUYV, YVYU, UYVY, RGB565, RGB24, BGR24, MJPEG, JPEG"
#define US_FORMATS_STR "YUYV, YVYU, UYVY, YU12, YV12,"
#define US_FORMATS2_STR "RGB565, RGB24, BGR24, MJPEG, JPEG"
#define US_IO_METHODS_STR "MMAP, USERPTR"


Expand Down
2 changes: 2 additions & 0 deletions src/libs/frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ bool us_frame_compare(const us_frame_s *a, const us_frame_s *b) {
uint us_frame_get_padding(const us_frame_s *frame) {
uint bytes_per_pixel = 0;
switch (frame->format) {
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUV420: bytes_per_pixel = 1; break;
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_UYVY:
Expand Down
69 changes: 65 additions & 4 deletions src/ustreamer/encoders/cpu/encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@


#include "encoder.h"

#include "../../../libs/logging.h"

typedef struct {
struct jpeg_destination_mgr mgr; // Default manager
Expand All @@ -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_yuv(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
static void _jpeg_write_scanlines_yuv_planar(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);
#ifndef JCS_EXTENSIONS
Expand Down Expand Up @@ -69,9 +70,11 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q
switch (src->format) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_UYVY: jpeg.in_color_space = JCS_YCbCr; break;
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420: jpeg.in_color_space = JCS_YCbCr; break;
# ifdef JCS_EXTENSIONS
case V4L2_PIX_FMT_BGR24: jpeg.in_color_space = JCS_EXT_BGR; break;
case V4L2_PIX_FMT_BGR24: jpeg.in_color_space = JCS_EXT_BGR; break;
# endif
default: jpeg.in_color_space = JCS_RGB; break;
}
Expand All @@ -85,7 +88,9 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q
// https://www.fourcc.org/yuv.php
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_UYVY: _jpeg_write_scanlines_yuv(&jpeg, src); break;
case V4L2_PIX_FMT_UYVY: _jpeg_write_scanlines_yuv(&jpeg, src); break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420: _jpeg_write_scanlines_yuv_planar(&jpeg, src); break;
case V4L2_PIX_FMT_RGB565: _jpeg_write_scanlines_rgb565(&jpeg, src); break;
case V4L2_PIX_FMT_RGB24: _jpeg_write_scanlines_rgb24(&jpeg, src); break;
case V4L2_PIX_FMT_BGR24:
Expand Down Expand Up @@ -167,6 +172,62 @@ static void _jpeg_write_scanlines_yuv(struct jpeg_compress_struct *jpeg, const u
free(line_buf);
}

static void _jpeg_write_scanlines_yuv_planar(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
uint8_t *line_buf;
US_CALLOC(line_buf, frame->width * 3);

US_LOG_DEBUG("Using Planar Encoder");
const unsigned padding = us_frame_get_padding(frame);
const uint image_size = frame->width * frame->height;
const uint chroma_array_size = (frame->used - image_size) / 2;
const uint chroma_matrix_order = (image_size / chroma_array_size) == 16 ? 4 : 2;
US_LOG_DEBUG("Planar data: Image Size %u, Chroma Array Size %u, Chroma Matrix Order %u", image_size, chroma_array_size, chroma_matrix_order);
const uint8_t *data = frame->data;
const uint8_t *chroma1_data = frame->data + image_size;
const uint8_t *chroma2_data = frame->data + image_size + chroma_array_size;

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-yuv420.html
uint8_t y = data[x], u, v;
uint chroma_position = x / chroma_matrix_order;

switch (frame->format) {
case V4L2_PIX_FMT_YUV420:
u = chroma1_data[chroma_position];
v = chroma2_data[chroma_position];
break;
case V4L2_PIX_FMT_YVU420:
u = chroma2_data[chroma_position];
v = chroma1_data[chroma_position];
break;
default:
assert(0 && "Unsupported pixel format");
return; // Makes linter happy
}

ptr[0] = y;
ptr[1] = u;
ptr[2] = v;
ptr += 3;
}

data += frame->width + padding;

if( jpeg->next_scanline > 0 && jpeg->next_scanline % chroma_matrix_order == 0 ){
chroma1_data += (frame->width + padding) / chroma_matrix_order;
chroma2_data += (frame->width + padding) / chroma_matrix_order;
}

JSAMPROW scanlines[1] = {line_buf};
jpeg_write_scanlines(jpeg, scanlines, 1);
}

free(line_buf);
}

static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
uint8_t *line_buf;
US_CALLOC(line_buf, frame->width * 3);
Expand Down
6 changes: 4 additions & 2 deletions src/ustreamer/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ int options_parse(us_options_s *options, us_capture_s *cap, us_encoder_s *enc, u
case _O_RESOLUTION: OPT_RESOLUTION("--resolution", cap->width, cap->height, true);
# pragma GCC diagnostic ignored "-Wsign-compare"
# pragma GCC diagnostic push
case _O_FORMAT: OPT_PARSE_ENUM("pixel format", cap->format, us_capture_parse_format, US_FORMATS_STR);
case _O_FORMAT: OPT_PARSE_ENUM("pixel format", cap->format, us_capture_parse_format, US_FORMATS_STR " " US_FORMATS2_STR);
# pragma GCC diagnostic pop
case _O_FORMAT_SWAP_RGB: OPT_SET(cap->format_swap_rgb, true);
case _O_TV_STANDARD: OPT_PARSE_ENUM("TV standard", cap->standard, us_capture_parse_standard, US_STANDARDS_STR);
Expand Down Expand Up @@ -621,7 +621,9 @@ static void _help(FILE *fp, const us_capture_s *cap, const us_encoder_s *enc, co
SAY(" -i|--input <N> ────────────────────── Input channel. Default: %u.\n", cap->input);
SAY(" -r|--resolution <WxH> ─────────────── Initial image resolution. Default: %ux%u.\n", cap->width, cap->height);
SAY(" -m|--format <fmt> ─────────────────── Image format.");
SAY(" Available: %s; default: YUYV.\n", US_FORMATS_STR);
SAY(" Available: %s", US_FORMATS_STR);
SAY(" %s;", US_FORMATS2_STR);
SAY(" Default: YUYV.\n");
SAY(" --format-swap-rgb ──────────────── Enable R-G-B order swapping: RGB to BGR and vice versa.");
SAY(" Default: disabled.\n");
SAY(" -a|--tv-standard <std> ────────────── Force TV standard.");
Expand Down