v4l2-ctl: Add support for crop and compose selection in streaming
PATCH v2 1/1 v4l2-ctl: Add support for crop and compose selection in streaming
Support crop and compose selection.
If the driver supports crop/compose then the raw frame is arranged inside a padded buffer.
--- utils/common/codec-fwht.patch | 8 +- utils/common/v4l-stream.c | 14 +-- utils/common/v4l-stream.h | 6 +- utils/qvidcap/capture.cpp | 2 + utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 137 ++++++++++++++++++++++++-- 5 files changed, 146 insertions(+), 21 deletions(-)
utils/common/codec-fwht.patch +5 -3
@@ -1,6 +1,6 @@ ---- a/utils/common/codec-fwht.h.old 2018-11-23 13:43:52.713731559 +0100 -+++ b/utils/common/codec-fwht.h 2018-11-23 13:47:55.484198283 +0100 -@@ -8,8 +8,24 @@ +--- a/utils/common/codec-fwht.h.old 2018-12-29 11:23:58.128328613 -0800 ++++ b/utils/common/codec-fwht.h 2018-12-29 11:24:16.099127560 -0800 +@@ -8,8 +8,26 @@ #define CODEC_FWHT_H #include <linux/types.h>
@@ -17,6 +17,8 @@ +#define GENMASK(h, l) \ + (((~0UL) - (1UL << (l)) + 1) & (~0UL >> ((8 * sizeof(long)) - 1 - (h)))) +#define pr_err(arg...) ++#define __round_mask(x, y) ((__typeof__(x))((y)-1)) ++#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) + + +typedef __u32 u32;
utils/common/v4l-stream.c +8 -6
@@ -171,25 +171,28 @@ unsigned rle_compress(__u8 *b, unsigned size, unsigned bpl)return (__u8 *)dst - b; } -struct codec_ctx *fwht_alloc (unsigned pixfmt,unsigned w,unsigned h, +struct codec_ctx *fwht_alloc (unsigned pixfmt,unsigned visible_width,unsigned visible_height, +unsigned coded_width,unsigned coded_height,unsigned field,unsigned colorspace,unsigned xfer_func,unsigned ycbcr_enc,unsigned quantization) {struct codec_ctx *ctx;const struct v4l2_fwht_pixfmt_info *info =v4l2_fwht_find_pixfmt (pixfmt);unsigned int chroma_div; -unsigned int size = w * h; +unsigned int size = coded_width * coded_height;// fwht expects macroblock alignment, check can be dropped once that // restriction is lifted. -if (!info || w %8 || h %8 ) +if (!info || coded_width %8 || coded_height %8 )return NULL ; ctx =malloc (sizeof (*ctx));if (!ctx)return NULL ; - ctx->state.width = w; - ctx->state.height = h; + ctx->state.coded_width = coded_width; + ctx->state.coded_height = coded_height; + ctx->state.visible_width = visible_width; + ctx->state.visible_height = visible_height; ctx->state.info = info; ctx->field = field; ctx->state.colorspace = colorspace;
@@ -208,7 +211,6 @@ struct codec_ctx *fwht_alloc(unsigned pixfmt, unsigned w, unsigned h,free (ctx);return NULL ; } - ctx->state.ref_frame.width = ctx->state.ref_frame.height =0 ; ctx->state.ref_frame.cb = ctx->state.ref_frame.luma + size; ctx->state.ref_frame.cr = ctx->state.ref_frame.cb + size / chroma_div; ctx->state.ref_frame.alpha = ctx->state.ref_frame.cr + size / chroma_div;
utils/common/v4l-stream.h +4 -2
@@ -9,12 +9,13 @@#define _V4L_STREAM_H_#include <linux/videodev2.h> -#include <codec-v4l2-fwht.h> #ifdef __cplusplusextern "C" {#endif /* __cplusplus */ +#include <codec-v4l2-fwht.h> +/* Default port */ #define V4L_STREAM_PORT 8362
@@ -145,7 +146,8 @@ struct codec_ctx {unsigned rle_compress (__u8 *buf,unsigned size,unsigned bytesperline);void rle_decompress (__u8 *buf,unsigned size,unsigned rle_size,unsigned bytesperline); -struct codec_ctx *fwht_alloc (unsigned pixfmt,unsigned w,unsigned h,unsigned field, +struct codec_ctx *fwht_alloc (unsigned pixfmt,unsigned visible_width,unsigned visible_height, +unsigned coded_width,unsigned coded_height,unsigned field,unsigned colorspace,unsigned xfer_func,unsigned ycbcr_enc,unsigned quantization);void fwht_free (struct codec_ctx *ctx);
utils/qvidcap/capture.cpp +2 -0
@@ -749,6 +749,7 @@ void CaptureWin::setModeSocket(int socket, int port) if (m_ctx) free(m_ctx); m_ctx = fwht_alloc(m_v4l_fmt.g_pixelformat(), m_v4l_fmt.g_width(), m_v4l_fmt.g_height(), + m_v4l_fmt.g_width(), m_v4l_fmt.g_height(), m_v4l_fmt.g_field(), m_v4l_fmt.g_colorspace(), m_v4l_fmt.g_xfer_func(), m_v4l_fmt.g_ycbcr_enc(), m_v4l_fmt.g_quantization());
@@ -1114,6 +1115,7 @@ void CaptureWin::listenForNewConnection() if (m_ctx) free(m_ctx); m_ctx = fwht_alloc(fmt.g_pixelformat(), fmt.g_width(), fmt.g_height(), + fmt.g_width(), fmt.g_height(), fmt.g_field(), fmt.g_colorspace(), fmt.g_xfer_func(), fmt.g_ycbcr_enc(), fmt.g_quantization()); setPixelAspect(pixelaspect);
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +127 -10
229 lines not on this page · raw message
Signature · 1 line
2.17.1
Quoted 144 lines · Dafna Hirschfeld
Support crop and compose selection.
If the driver supports crop/compose then the raw frame is arranged inside a padded buffer.Signed-off-by Dafna Hirschfeld <[email protected]>--- utils/common/codec-fwht.patch | 8 +- utils/common/v4l-stream.c | 14 +-- utils/common/v4l-stream.h | 6 +- utils/qvidcap/capture.cpp | 2 + utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 137 ++++++++++++++++++++++++-- 5 files changed, 146 insertions(+), 21 deletions(-)utils/common/codec-fwht.patch +5
-3@@ -1,6 +1,6 @@ ---- a/utils/common/codec-fwht.h.old 2018-11-23 13:43:52.713731559 +0100 -+++ b/utils/common/codec-fwht.h 2018-11-23 13:47:55.484198283 +0100 -@@ -8,8 +8,24 @@ +--- a/utils/common/codec-fwht.h.old 2018-12-29 11:23:58.128328613 -0800 ++++ b/utils/common/codec-fwht.h 2018-12-29 11:24:16.099127560 -0800 +@@ -8,8 +8,26 @@ #define CODEC_FWHT_H #include <linux/types.h>@@ -17,6 +17,8 @@ +#define GENMASK(h, l) \ + (((~0UL) - (1UL << (l)) + 1) & (~0UL >> ((8 * sizeof(long)) - 1 - (h)))) +#define pr_err(arg...) ++#define __round_mask(x, y) ((__typeof__(x))((y)-1)) ++#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) + + +typedef __u32 u32;utils/common/v4l-stream.c +8
-6@@ -171,25 +171,28 @@ unsigned rle_compress(__u8 *b, unsigned size, unsigned bpl)return (__u8 *)dst - b; } -struct codec_ctx *fwht_alloc (unsigned pixfmt,unsigned w,unsigned h, +struct codec_ctx *fwht_alloc (unsigned pixfmt,unsigned visible_width,unsigned visible_height, +unsigned coded_width,unsigned coded_height,unsigned field,unsigned colorspace,unsigned xfer_func,unsigned ycbcr_enc,unsigned quantization) {struct codec_ctx *ctx;const struct v4l2_fwht_pixfmt_info *info =v4l2_fwht_find_pixfmt (pixfmt);unsigned int chroma_div; -unsigned int size = w * h; +unsigned int size = coded_width * coded_height;// fwht expects macroblock alignment, check can be dropped once that // restriction is lifted. -if (!info || w %8 || h %8 ) +if (!info || coded_width %8 || coded_height %8 )return NULL ; ctx =malloc (sizeof (*ctx));if (!ctx)return NULL ; - ctx->state.width = w; - ctx->state.height = h; + ctx->state.coded_width = coded_width; + ctx->state.coded_height = coded_height; + ctx->state.visible_width = visible_width; + ctx->state.visible_height = visible_height; ctx->state.info = info; ctx->field = field; ctx->state.colorspace = colorspace;@@ -208,7 +211,6 @@ struct codec_ctx *fwht_alloc(unsigned pixfmt, unsigned w, unsigned h,free (ctx);return NULL ; } - ctx->state.ref_frame.width = ctx->state.ref_frame.height =0 ; ctx->state.ref_frame.cb = ctx->state.ref_frame.luma + size; ctx->state.ref_frame.cr = ctx->state.ref_frame.cb + size / chroma_div; ctx->state.ref_frame.alpha = ctx->state.ref_frame.cr + size / chroma_div;utils/common/v4l-stream.h +4
-2@@ -9,12 +9,13 @@#define _V4L_STREAM_H_#include <linux/videodev2.h> -#include <codec-v4l2-fwht.h> #ifdef __cplusplusextern "C" {#endif /* __cplusplus */ +#include <codec-v4l2-fwht.h> +/* Default port */ #define V4L_STREAM_PORT 8362@@ -145,7 +146,8 @@ struct codec_ctx {unsigned rle_compress (__u8 *buf,unsigned size,unsigned bytesperline);void rle_decompress (__u8 *buf,unsigned size,unsigned rle_size,unsigned bytesperline); -struct codec_ctx *fwht_alloc (unsigned pixfmt,unsigned w,unsigned h,unsigned field, +struct codec_ctx *fwht_alloc (unsigned pixfmt,unsigned visible_width,unsigned visible_height, +unsigned coded_width,unsigned coded_height,unsigned field,unsigned colorspace,unsigned xfer_func,unsigned ycbcr_enc,unsigned quantization);void fwht_free (struct codec_ctx *ctx);utils/qvidcap/capture.cpp +2
-0@@ -749,6 +749,7 @@ void CaptureWin::setModeSocket(int socket, int port) if (m_ctx) free(m_ctx); m_ctx = fwht_alloc(m_v4l_fmt.g_pixelformat(), m_v4l_fmt.g_width(), m_v4l_fmt.g_height(), + m_v4l_fmt.g_width(), m_v4l_fmt.g_height(), m_v4l_fmt.g_field(), m_v4l_fmt.g_colorspace(), m_v4l_fmt.g_xfer_func(), m_v4l_fmt.g_ycbcr_enc(), m_v4l_fmt.g_quantization());@@ -1114,6 +1115,7 @@ void CaptureWin::listenForNewConnection() if (m_ctx) free(m_ctx); m_ctx = fwht_alloc(fmt.g_pixelformat(), fmt.g_width(), fmt.g_height(), + fmt.g_width(), fmt.g_height(), fmt.g_field(), fmt.g_colorspace(), fmt.g_xfer_func(), fmt.g_ycbcr_enc(), fmt.g_quantization()); setPixelAspect(pixelaspect);utils/v4l2-ctl/v4l2-ctl-streaming.cpp +0
-1@@ -20,7 +20,6 @@ #include "v4l2-ctl.h" #include "v4l-stream.h" -#include "codec-fwht.h" extern "C" { #include "v4l2-tpg.h"
utils/v4l2-ctl/v4l2-ctl-streaming.cpp static unsigned bpl_out[VIDEO_MAX_PLANES]; · line 80
Quoted 9 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +6
-0@@ -73,6 +72,13 @@ static unsigned bpl_out[VIDEO_MAX_PLANES]; static bool last_buffer = false; static codec_ctx *ctx; +static unsigned int cropped_width = 0; +static unsigned int cropped_height = 0; +static unsigned int composed_width = 0; +static unsigned int composed_height = 0; +static bool support_cap_compose = false; +static bool support_out_crop = false;
No need to assign 0/false to these static globals. Statics are always initialized to 0.
utils/v4l2-ctl/v4l2-ctl-streaming.cpp void streaming_cmd(int ch, char *optarg) · line 666
Quoted 10 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +2
-1+ #define TS_WINDOW 241 #define FILE_HDR_ID v4l2_fourcc('V', 'h', 'd', 'r')@@ -657,7 +663,57 @@ void streaming_cmd(int ch, char *optarg) } } -static bool fill_buffer_from_file(cv4l_queue &q, cv4l_buffer &b, FILE *fin) +static void read_write_padded_frame(cv4l_fmt &fmt, unsigned char* buf, FILE *fpointer,
unsigned char *buf
Quoted 17 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +17
-0+ unsigned &sz, unsigned &len, bool is_read) +{ + const struct v4l2_fwht_pixfmt_info *vic_fmt = v4l2_fwht_find_pixfmt(fmt.g_pixelformat()); + unsigned coded_width = fmt.g_width(); + unsigned coded_height = fmt.g_height(); + unsigned real_width; + unsigned real_height; + unsigned char *buf_p = buf; + + if (is_read) { + real_width = cropped_width; + real_height = cropped_height; + } + else { + real_width = composed_width; + real_height = composed_height; + }
utils/v4l2-ctl/v4l2-ctl-streaming.cpp void streaming_cmd(int ch, char *optarg) · line 693
Quoted 10 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +10
-0+ + sz = 0; + len = real_width * real_height * vic_fmt->sizeimage_mult / vic_fmt->sizeimage_div; + + for (unsigned plane_idx = 0; plane_idx < vic_fmt->planes_num; plane_idx++) { + unsigned h_div = (plane_idx == 0 || plane_idx == 3) ? 1 : vic_fmt->height_div; + unsigned w_div = (plane_idx == 0 || plane_idx == 3) ? 1 : vic_fmt->width_div; + unsigned step = (plane_idx == 0 || plane_idx == 3) ? vic_fmt->luma_alpha_step : vic_fmt->chroma_step; + + for (unsigned i=0; i < real_height/h_div; i++) {
Add spaces around '=' and '/'. Remove duplicate space after '<'
utils/v4l2-ctl/v4l2-ctl-streaming.cpp void streaming_cmd(int ch, char *optarg) · line 704
Quoted 11 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +11
-0+ unsigned int wsz = 0; + unsigned int consume_sz = step * real_width / w_div; + + if (is_read) + wsz = fread(buf_p, 1, consume_sz, fpointer); + else + wsz = fwrite(buf_p, 1, consume_sz, fpointer); + if (wsz == 0 && i == 0 && plane_idx == 0) + break; + if (wsz != consume_sz) { + fprintf(stderr, "padding: needed %u bytes, got %u\n",consume_sz, wsz);
Add space before consume_sz.
utils/v4l2-ctl/v4l2-ctl-streaming.cpp void streaming_cmd(int ch, char *optarg) · line 711
Quoted 7 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +7
-0+ return; + } + sz += wsz; + buf_p += step * coded_width / w_div; + } + buf_p += (step * coded_width / w_div) * (coded_height - real_height) / h_div; + if(sz == 0)
Add space after 'if'.
utils/v4l2-ctl/v4l2-ctl-streaming.cpp restart: · line 835
Quoted 13 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +6
-0+ break; + } +} + +static bool fill_buffer_from_file(cv4l_fd &fd, cv4l_queue &q, cv4l_buffer &b, FILE *fin) { static bool first = true; static bool is_fwht = false;@@ -776,6 +832,8 @@ restart: void *buf = q.g_dataptr(b.g_index(), j); unsigned len = q.g_length(j); unsigned sz; + cv4l_fmt fmt;
Add newline.
utils/v4l2-ctl/v4l2-ctl-streaming.cpp restart: · line 848
Quoted 12 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +4
-1+ fd.g_fmt(fmt, q.g_type()); if (from_with_hdr) { len = read_u32(fin);@@ -785,7 +843,12 @@ restart: return false; } } - sz = fread(buf, 1, len, fin); + + if (support_out_crop && v4l2_fwht_find_pixfmt(fmt.g_pixelformat())) + read_write_padded_frame(fmt, (unsigned char*) buf, fin, sz, len, true);
(unsigned char *)buf
Quoted 25 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +5
-2+ else + sz = fread(buf, 1, len, fin); + if (first && sz != len) { fprintf(stderr, "Insufficient data\n"); return false;@@ -908,7 +971,7 @@ static int do_setup_out_buffers(cv4l_fd &fd, cv4l_queue &q, FILE *fin, bool qbuf tpg_fillbuffer(&tpg, stream_out_std, j, (u8 *)q.g_dataptr(i, j)); } } - if (fin && !fill_buffer_from_file(q, buf, fin)) + if (fin && !fill_buffer_from_file(fd, q, buf, fin)) return -2; if (qbuf) {@@ -926,7 +989,7 @@ static int do_setup_out_buffers(cv4l_fd &fd, cv4l_queue &q, FILE *fin, bool qbuf return 0; } -static void write_buffer_to_file(cv4l_queue &q, cv4l_buffer &buf, FILE *fout) +static void write_buffer_to_file(cv4l_fd &fd, cv4l_queue &q, cv4l_buffer &buf, FILE *fout) { #ifndef NO_STREAM_TO unsigned comp_size[VIDEO_MAX_PLANES];
utils/v4l2-ctl/v4l2-ctl-streaming.cpp static void write_buffer_to_file(cv4l_queue &q, cv4l_buffer &buf, FILE *fout) · line 1033
Quoted 4 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +1
-0@@ -967,6 +1030,8 @@ static void write_buffer_to_file(cv4l_queue &q, cv4l_buffer &buf, FILE *fout) __u32 used = buf.g_bytesused(); unsigned offset = buf.g_data_offset(); unsigned sz; + cv4l_fmt fmt;
newline
Quoted 64 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +18
-5+ fd.g_fmt(fmt, q.g_type()); if (offset > used) { // Should never happen@@ -985,6 +1050,9 @@ static void write_buffer_to_file(cv4l_queue &q, cv4l_buffer &buf, FILE *fout) } if (host_fd_to >= 0) sz = fwrite(comp_ptr[j] + offset, 1, used, fout); + else if (support_cap_compose && v4l2_fwht_find_pixfmt(fmt.g_pixelformat())) + read_write_padded_frame(fmt, (u8 *)q.g_dataptr(buf.g_index(), j) + offset, + fout, sz, used, false); else sz = fwrite((u8 *)q.g_dataptr(buf.g_index(), j) + offset, 1, used, fout);@@ -1036,7 +1104,7 @@ static int do_handle_cap(cv4l_fd &fd, cv4l_queue &q, FILE *fout, int *index, if (fout && (!stream_skip || ignore_count_skip) && buf.g_bytesused(0) && !(buf.g_flags() & V4L2_BUF_FLAG_ERROR)) - write_buffer_to_file(q, buf, fout); + write_buffer_to_file(fd, q, buf, fout); if (buf.g_flags() & V4L2_BUF_FLAG_KEYFRAME) ch = 'K';@@ -1135,7 +1203,7 @@ static int do_handle_out(cv4l_fd &fd, cv4l_queue &q, FILE *fin, cv4l_buffer *cap output_field = V4L2_FIELD_TOP; } - if (fin && !fill_buffer_from_file(q, buf, fin)) + if (fin && !fill_buffer_from_file(fd, q, buf, fin)) return -2; if (!fin && stream_out_refresh) {@@ -1333,10 +1401,15 @@ recover: write_u32(fout, cfmt.g_bytesperline(i)); bpl_cap[i] = rle_calc_bpl(cfmt.g_bytesperline(i), cfmt.g_pixelformat()); } - if (!host_lossless) - ctx = fwht_alloc(cfmt.g_pixelformat(), cfmt.g_width(), cfmt.g_height(), + if (!host_lossless) { + unsigned visible_width = support_cap_compose ? composed_width : cfmt.g_width(); + unsigned visible_height = support_cap_compose ? composed_height : cfmt.g_height(); + + ctx = fwht_alloc(cfmt.g_pixelformat(), visible_width, visible_height, + cfmt.g_width(), cfmt.g_height(), cfmt.g_field(), cfmt.g_colorspace(), cfmt.g_xfer_func(), cfmt.g_ycbcr_enc(), cfmt.g_quantization()); + } fflush(fout); } #endif@@ -1560,7 +1633,11 @@ static void streaming_set_out(cv4l_fd &fd) cfmt.s_quantization(read_u32(fin)); cfmt.s_xfer_func(read_u32(fin)); cfmt.s_flags(read_u32(fin)); - ctx = fwht_alloc(cfmt.g_pixelformat(), cfmt.g_width(), cfmt.g_height(), + unsigned visible_width = support_out_crop ? cropped_width : cfmt.g_width(); + unsigned visible_height = support_out_crop ? cropped_height : cfmt.g_height(); + + ctx = fwht_alloc(cfmt.g_pixelformat(), visible_width, visible_height, + cfmt.g_width(), cfmt.g_height(), cfmt.g_field(), cfmt.g_colorspace(), cfmt.g_xfer_func(), cfmt.g_ycbcr_enc(), cfmt.g_quantization());
utils/v4l2-ctl/v4l2-ctl-streaming.cpp done: · line 2109
Quoted 4 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +1
-0@@ -2029,6 +2106,43 @@ done: fclose(file[OUT]); } +static int is_support_compose_on_cap(cv4l_fd &fd) {
{ should be on its own line
This function also does more than just detect if compose is supported. Perhaps get_cap_compose_rect() is a better name.
Quoted 9 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +9
-0+ v4l2_selection sel; + + memset(&sel, 0, sizeof(sel)); + sel.type = vidcap_buftype; + sel.target = V4L2_SEL_TGT_COMPOSE; + + if (fd.g_selection(sel) == 0) { + support_cap_compose = true; + composed_width = sel.r.width;
utils/v4l2-ctl/v4l2-ctl-streaming.cpp done: · line 2128
Quoted 10 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +10
-0+ composed_height = sel.r.height; + return 0; + } + + support_cap_compose = false; + return 0; +} + + +static int is_support_crop_on_out(cv4l_fd &fd) {
Ditto.
Quoted 22 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +17
-0+ v4l2_selection sel; + + memset(&sel, 0, sizeof(sel)); + sel.type = vidout_buftype; + sel.target = V4L2_SEL_TGT_CROP; + + if (fd.g_selection(sel) == 0) { + support_out_crop = true; + cropped_width = sel.r.width; + cropped_height = sel.r.height; + return 0; + } + + support_out_crop = false; + return 0; +} + void streaming_set(cv4l_fd &fd, cv4l_fd &out_fd) { cv4l_disable_trace dt(fd);
utils/v4l2-ctl/v4l2-ctl-streaming.cpp void streaming_set(cv4l_fd &fd, cv4l_fd &out_fd) · line 2158
Quoted 9 lines
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +3
-0@@ -2036,6 +2150,9 @@ void streaming_set(cv4l_fd &fd, cv4l_fd &out_fd) int do_cap = options[OptStreamMmap] + options[OptStreamUser] + options[OptStreamDmaBuf]; int do_out = options[OptStreamOutMmap] + options[OptStreamOutUser] + options[OptStreamOutDmaBuf]; + is_support_crop_on_out(fd); + is_support_compose_on_cap(fd); + if (out_fd.g_fd() < 0) { out_capabilities = capabilities; out_priv_magic = priv_magic;
Regards,
Hans