On 01/04/2019 09:20 PM, Dafna Hirschfeld wrote:
> 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 <daf...@gmail.com>
> ---
> Chnages from v2:
> 1. cleanups
> 2. change the code of read_write_padded_frame to use bytesperline as
> a stride
> 
>  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 | 140 ++++++++++++++++++++++++--
>  5 files changed, 149 insertions(+), 21 deletions(-)
> 
> diff --git a/utils/common/codec-fwht.patch b/utils/common/codec-fwht.patch
> index 4d41225b..37ac4672 100644
> --- a/utils/common/codec-fwht.patch
> +++ b/utils/common/codec-fwht.patch
> @@ -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;
> diff --git a/utils/common/v4l-stream.c b/utils/common/v4l-stream.c
> index 9f842e21..a1cabadb 100644
> --- a/utils/common/v4l-stream.c
> +++ b/utils/common/v4l-stream.c
> @@ -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;
> diff --git a/utils/common/v4l-stream.h b/utils/common/v4l-stream.h
> index c235150b..fe5dfe90 100644
> --- a/utils/common/v4l-stream.h
> +++ b/utils/common/v4l-stream.h
> @@ -9,12 +9,13 @@
>  #define _V4L_STREAM_H_
>  
>  #include <linux/videodev2.h>
> -#include <codec-v4l2-fwht.h>
>  
>  #ifdef __cplusplus
>  extern "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);
> diff --git a/utils/qvidcap/capture.cpp b/utils/qvidcap/capture.cpp
> index 8c11ac53..e04db6be 100644
> --- a/utils/qvidcap/capture.cpp
> +++ b/utils/qvidcap/capture.cpp
> @@ -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);
> diff --git a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp 
> b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
> index 79e015ce..651bf2ce 100644
> --- a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
> +++ b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
> @@ -20,7 +20,6 @@
>  
>  #include "v4l2-ctl.h"
>  #include "v4l-stream.h"
> -#include "codec-fwht.h"
>  
>  extern "C" {
>  #include "v4l2-tpg.h"
> @@ -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;
> +static unsigned int cropped_height;
> +static unsigned int composed_width;
> +static unsigned int composed_height;
> +static bool support_cap_compose;
> +static bool support_out_crop;
> +
>  #define TS_WINDOW 241
>  #define FILE_HDR_ID                  v4l2_fourcc('V', 'h', 'd', 'r')
>  
> @@ -657,7 +663,59 @@ 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 &sz,
> +                                 unsigned &len, bool is_read)
> +{
> +     const struct v4l2_fwht_pixfmt_info *vic_fmt = 
> v4l2_fwht_find_pixfmt(fmt.g_pixelformat());
> +     unsigned coded_height = fmt.g_height();
> +     unsigned real_width;
> +     unsigned real_height;
> +     unsigned char *plane_p = buf;
> +     unsigned char *row_p;
> +
> +     if (is_read) {
> +             real_width  = cropped_width;
> +             real_height = cropped_height;
> +     } else {
> +             real_width  = composed_width;
> +             real_height = composed_height;
> +     }
> +
> +     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++) {

I would add a:

                bool is_chroma_plane = plane_idx == 1 || plane_idx == 2;

and use is_chroma_plane in the three line below.

> +             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;
> +             unsigned stride_div = (vic_fmt->planes_num == 3 && plane_idx > 
> 0) ? 2 : 1;
> +
> +             row_p = plane_p;
> +             for (unsigned i = 0; i < real_height / h_div; i++) {
> +                     unsigned int wsz = 0;
> +                     unsigned int consume_sz = step * real_width / w_div;
> +
> +                     if (is_read)
> +                             wsz = fread(row_p, 1, consume_sz, fpointer);
> +                     else
> +                             wsz = fwrite(row_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);
> +                             return;
> +                     }
> +                     sz += wsz;
> +                     row_p += fmt.g_bytesperline() / stride_div;
> +             }
> +             plane_p += (fmt.g_bytesperline() / stride_div) * (coded_height 
> / h_div);
> +             if (sz == 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,7 +834,9 @@ restart:
>               void *buf = q.g_dataptr(b.g_index(), j);
>               unsigned len = q.g_length(j);
>               unsigned sz;
> +             cv4l_fmt fmt;
>  
> +             fd.g_fmt(fmt, q.g_type());
>               if (from_with_hdr) {
>                       len = read_u32(fin);
>                       if (len > q.g_length(j)) {
> @@ -785,7 +845,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);
> +             else
> +                     sz = fread(buf, 1, len, fin);
> +
>               if (first && sz != len) {
>                       fprintf(stderr, "Insufficient data\n");
>                       return false;
> @@ -908,7 +973,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 +991,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];
> @@ -967,7 +1032,9 @@ 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;
>  
> +             fd.g_fmt(fmt, q.g_type());
>               if (offset > used) {
>                       // Should never happen
>                       fprintf(stderr, "offset %d > used %d!\n",
> @@ -985,6 +1052,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 +1106,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 +1205,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 +1403,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 +1635,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());
>  
> @@ -2029,6 +2108,44 @@ done:
>               fclose(file[OUT]);
>  }
>  
> +static int get_cap_compose_rect(cv4l_fd &fd)
> +{
> +     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;
> +             composed_height = sel.r.height;
> +             return 0;
> +     }
> +
> +     support_cap_compose = false;
> +     return 0;
> +}
> +
> +static int get_out_crop_rect(cv4l_fd &fd)
> +{
> +     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);
> @@ -2036,6 +2153,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];
>  
> +     get_cap_compose_rect(fd);
> +     get_out_crop_rect(fd);
> +
>       if (out_fd.g_fd() < 0) {
>               out_capabilities = capabilities;
>               out_priv_magic = priv_magic;
> 

Regards,

        Hans

Reply via email to