From: Dafna Hirschfeld <dafna3@gmail.com>
To: linux-media@vger.kernel.org
Cc: hverkuil@xs4all.nl, helen.koike@collabora.com,
Dafna Hirschfeld <dafna3@gmail.com>
Subject: [PATCH v4l-utils] v4l2-ctl: Add support for CROP selection in m2m streaming
Date: Tue, 18 Dec 2018 03:11:40 -0800 [thread overview]
Message-ID: <20181218111140.90645-1-dafna3@gmail.com> (raw)
Add support for crop in the selection api for m2m encoder.
This includes reading and writing raw frames with padding.
Signed-off-by: Dafna Hirschfeld <dafna3@gmail.com>
---
Tested with the jellyfish video, with this script:
https://github.com/kamomil/outreachy/blob/master/test-v4l2-utils-with-jelly.sh
Tested on formats yuv420, rgb24, nv12
utils/common/v4l-stream.h | 2 +-
utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 257 +++++++++++++++++++++++++-
utils/v4l2-ctl/v4l2-ctl-vidcap.cpp | 6 +
utils/v4l2-ctl/v4l2-ctl-vidout.cpp | 5 +
utils/v4l2-ctl/v4l2-ctl.h | 2 +
5 files changed, 261 insertions(+), 11 deletions(-)
diff --git a/utils/common/v4l-stream.h b/utils/common/v4l-stream.h
index c235150b..a03d4790 100644
--- a/utils/common/v4l-stream.h
+++ b/utils/common/v4l-stream.h
@@ -9,11 +9,11 @@
#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
diff --git a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
index dee104d7..759577dd 100644
--- a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
@@ -20,9 +20,9 @@
#include "v4l2-ctl.h"
#include "v4l-stream.h"
-#include "codec-fwht.h"
extern "C" {
+#include "codec-v4l2-fwht.h"
#include "v4l2-tpg.h"
}
@@ -73,6 +73,12 @@ static unsigned bpl_out[VIDEO_MAX_PLANES];
static bool last_buffer = false;
static codec_ctx *ctx;
+static unsigned int visible_width = 0;
+static unsigned int visible_height = 0;
+static unsigned int frame_width = 0;
+static unsigned int frame_height = 0;
+bool is_m2m_enc = false;
+
#define TS_WINDOW 241
#define FILE_HDR_ID v4l2_fourcc('V', 'h', 'd', 'r')
@@ -108,6 +114,84 @@ public:
unsigned dropped();
};
+static int get_codec_type(int fd, bool &is_enc) {
+ struct v4l2_capability vcap;
+
+ memset(&vcap,0,sizeof(vcap));
+
+ int ret = ioctl(fd, VIDIOC_QUERYCAP, &vcap);
+ if(ret) {
+ fprintf(stderr, "get_codec_type: VIDIOC_QUERYCAP failed: %d\n", ret);
+ return ret;
+ }
+ unsigned int caps = vcap.capabilities;
+ if (caps & V4L2_CAP_DEVICE_CAPS)
+ caps = vcap.device_caps;
+ if(!(caps & V4L2_CAP_VIDEO_M2M) && !(caps & V4L2_CAP_VIDEO_M2M_MPLANE)) {
+ is_enc = false;
+ fprintf(stderr,"get_codec_type: not an M2M device\n");
+ return -1;
+ }
+
+ struct v4l2_fmtdesc fmt;
+ memset(&fmt,0,sizeof(fmt));
+ fmt.index = 0;
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmt)) == 0) {
+ if((fmt.flags & V4L2_FMT_FLAG_COMPRESSED) == 0)
+ break;
+ fmt.index++;
+ }
+ if (ret) {
+ is_enc = true;
+ return 0;
+ }
+ memset(&fmt,0,sizeof(fmt));
+ fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmt)) == 0) {
+ if((fmt.flags & V4L2_FMT_FLAG_COMPRESSED) == 0)
+ break;
+ fmt.index++;
+ }
+ if (ret) {
+ is_enc = false;
+ return 0;
+ }
+ fprintf(stderr, "get_codec_type: could no determine codec type\n");
+ return -1;
+}
+
+static void get_frame_dims(unsigned int &frame_width, unsigned int &frame_height) {
+
+ if(is_m2m_enc)
+ vidout_get_orig_from_set(frame_width, frame_height);
+ else
+ vidcap_get_orig_from_set(frame_width, frame_height);
+}
+
+static int get_visible_format(int fd, unsigned int &width, unsigned int &height) {
+ int ret = 0;
+ if(is_m2m_enc) {
+ struct v4l2_selection in_selection;
+
+ in_selection.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ in_selection.target = V4L2_SEL_TGT_CROP;
+
+ if ( (ret = ioctl(fd, VIDIOC_G_SELECTION, &in_selection)) != 0) {
+ fprintf(stderr,"get_visible_format: error in g_selection ioctl: %d\n",ret);
+ return ret;
+ }
+ width = in_selection.r.width;
+ height = in_selection.r.height;
+ }
+ else { //TODO - g_selection with COMPOSE should be used here when implemented in driver
+ vidcap_get_orig_from_set(width, height);
+ }
+ return 0;
+}
+
+
void fps_timestamps::determine_field(int fd, unsigned type)
{
struct v4l2_format fmt = { };
@@ -419,7 +503,6 @@ static void print_buffer(FILE *f, struct v4l2_buffer &buf)
fprintf(f, "\t\tData Offset: %u\n", p->data_offset);
}
}
-
fprintf(f, "\n");
}
@@ -657,7 +740,131 @@ void streaming_cmd(int ch, char *optarg)
}
}
-static bool fill_buffer_from_file(cv4l_queue &q, cv4l_buffer &b, FILE *fin)
+bool padding(cv4l_fd &fd, cv4l_queue &q, unsigned char* buf, FILE *fpointer, unsigned &sz, unsigned &len, bool is_read)
+{
+ cv4l_fmt fmt(q.g_type());
+ fd.g_fmt(fmt, q.g_type());
+ 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 = (unsigned char*) buf;
+
+ if(is_read) {
+ real_width = frame_width;
+ real_height = frame_height;
+ }
+ else {
+ real_width = visible_width;
+ real_height = visible_height;
+ }
+ sz = 0;
+ len = real_width * real_height * vic_fmt->sizeimage_mult / vic_fmt->sizeimage_div;
+ switch(vic_fmt->id) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_HSV24:
+ case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_XRGB32:
+ case V4L2_PIX_FMT_HSV32:
+ case V4L2_PIX_FMT_BGR32:
+ case V4L2_PIX_FMT_XBGR32:
+ case V4L2_PIX_FMT_ARGB32:
+ case V4L2_PIX_FMT_ABGR32:
+ for(unsigned i=0; i < real_height; i++) {
+ unsigned int consume_sz = vic_fmt->bytesperline_mult*real_width;
+ unsigned int wsz = 0;
+ if(is_read)
+ wsz = fread(buf_p, 1, consume_sz, fpointer);
+ else
+ wsz = fwrite(buf_p, 1, consume_sz, fpointer);
+ sz += wsz;
+ if(wsz == 0 && i == 0)
+ break;
+ if(wsz != consume_sz) {
+ fprintf(stderr, "padding: needed %u bytes, got %u\n",consume_sz, wsz);
+ return false;
+ }
+ buf_p += vic_fmt->chroma_step*coded_width;
+ }
+ break;
+
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV24:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_NV42:
+ for(unsigned plane_idx = 0; plane_idx < 2; plane_idx++) {
+ unsigned h_div = (plane_idx == 0) ? 1 : vic_fmt->height_div;
+ unsigned w_div = (plane_idx == 0) ? 1 : vic_fmt->width_div;
+ unsigned step = (plane_idx == 0) ? vic_fmt->luma_alpha_step : vic_fmt->chroma_step;
+
+ 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(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);
+ return true;
+ }
+ sz += wsz;
+ buf_p += step*coded_width/w_div;
+ }
+ buf_p += (coded_width / w_div) * (coded_height - real_height) / h_div;
+
+ if(sz == 0)
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_GREY:
+ for(unsigned comp_idx = 0; comp_idx < vic_fmt->components_num; comp_idx++) {
+ unsigned h_div = (comp_idx == 0) ? 1 : vic_fmt->height_div;
+ unsigned w_div = (comp_idx == 0) ? 1 : vic_fmt->width_div;
+
+ for(unsigned i=0; i < real_height/h_div; i++) {
+ unsigned int wsz = 0;
+ unsigned int consume_sz = 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 && comp_idx == 0)
+ break;
+ if(wsz != consume_sz) {
+ fprintf(stderr, "padding: needed %u bytes, got %u\n",consume_sz, wsz);
+ return true;
+ }
+ sz += wsz;
+ buf_p += coded_width/w_div;
+ }
+ buf_p += (coded_width / w_div) * (coded_height - real_height) / h_div;
+
+ if(sz == 0)
+ break;
+ }
+ break;
+ default:
+ fprintf(stderr,"the format is not supported yet\n");
+ return false;
+ }
+ return true;
+}
+
+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;
@@ -785,7 +992,15 @@ restart:
return false;
}
}
- sz = fread(buf, 1, len, fin);
+
+ if(is_m2m_enc) {
+ if(!padding(fd, q, (unsigned char*) buf, fin, sz, len, true))
+ return false;
+ }
+ else {
+ sz = fread(buf, 1, len, fin);
+ }
+
if (first && sz != len) {
fprintf(stderr, "Insufficient data\n");
return false;
@@ -908,7 +1123,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) {
@@ -960,7 +1175,7 @@ static int do_handle_cap(cv4l_fd &fd, cv4l_queue &q, FILE *fout, int *index,
if (fd.qbuf(buf))
return -1;
}
-
+
double ts_secs = buf.g_timestamp().tv_sec + buf.g_timestamp().tv_usec / 1000000.0;
fps_ts.add_ts(ts_secs, buf.g_sequence(), buf.g_field());
@@ -1023,8 +1238,15 @@ static int do_handle_cap(cv4l_fd &fd, cv4l_queue &q, FILE *fout, int *index,
}
if (host_fd_to >= 0)
sz = fwrite(comp_ptr[j] + offset, 1, used, fout);
- else
- sz = fwrite((u8 *)q.g_dataptr(buf.g_index(), j) + offset, 1, used, fout);
+ else {
+ if(!is_m2m_enc) {
+ if(!padding(fd, q, (u8 *)q.g_dataptr(buf.g_index(), j) + offset, fout, sz, used, false))
+ return false;
+ }
+ else {
+ sz = fwrite((u8 *)q.g_dataptr(buf.g_index(), j) + offset, 1, used, fout);
+ }
+ }
if (sz != used)
fprintf(stderr, "%u != %u\n", sz, used);
@@ -1130,7 +1352,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) {
@@ -1227,7 +1449,7 @@ static void streaming_set_cap(cv4l_fd &fd)
}
break;
}
-
+
memset(&sub, 0, sizeof(sub));
sub.type = V4L2_EVENT_EOS;
fd.subscribe_event(sub);
@@ -2031,6 +2253,21 @@ 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];
+ int r = get_codec_type(fd.g_fd(), is_m2m_enc);
+ if(r) {
+ fprintf(stderr, "error checking codec type\n");
+ return;
+ }
+
+ r = get_visible_format(fd.g_fd(), visible_width, visible_height);
+
+ if(r) {
+ fprintf(stderr, "error getting the visible width\n");
+ return;
+ }
+
+ get_frame_dims(frame_width, frame_height);
+
if (out_fd.g_fd() < 0) {
out_capabilities = capabilities;
out_priv_magic = priv_magic;
diff --git a/utils/v4l2-ctl/v4l2-ctl-vidcap.cpp b/utils/v4l2-ctl/v4l2-ctl-vidcap.cpp
index dc17a868..932f1fd2 100644
--- a/utils/v4l2-ctl/v4l2-ctl-vidcap.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-vidcap.cpp
@@ -244,6 +244,12 @@ void vidcap_get(cv4l_fd &fd)
}
}
+void vidcap_get_orig_from_set(unsigned int &r_width, unsigned int &r_height) {
+ r_height = height;
+ r_width = width;
+}
+
+
void vidcap_list(cv4l_fd &fd)
{
if (options[OptListFormats]) {
diff --git a/utils/v4l2-ctl/v4l2-ctl-vidout.cpp b/utils/v4l2-ctl/v4l2-ctl-vidout.cpp
index 5823df9c..05bd43ed 100644
--- a/utils/v4l2-ctl/v4l2-ctl-vidout.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-vidout.cpp
@@ -208,6 +208,11 @@ void vidout_get(cv4l_fd &fd)
}
}
+void vidout_get_orig_from_set(unsigned int &r_width, unsigned int &r_height) {
+ r_height = height;
+ r_width = width;
+}
+
void vidout_list(cv4l_fd &fd)
{
if (options[OptListOutFormats]) {
diff --git a/utils/v4l2-ctl/v4l2-ctl.h b/utils/v4l2-ctl/v4l2-ctl.h
index 5a52a0a4..ab2994b2 100644
--- a/utils/v4l2-ctl/v4l2-ctl.h
+++ b/utils/v4l2-ctl/v4l2-ctl.h
@@ -357,6 +357,8 @@ void vidout_cmd(int ch, char *optarg);
void vidout_set(cv4l_fd &fd);
void vidout_get(cv4l_fd &fd);
void vidout_list(cv4l_fd &fd);
+void vidcap_get_orig_from_set(unsigned int &r_width, unsigned int &r_height);
+void vidout_get_orig_from_set(unsigned int &r_width, unsigned int &r_height);
// v4l2-ctl-overlay.cpp
void overlay_usage(void);
--
2.17.1
next reply other threads:[~2018-12-18 11:12 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-12-18 11:11 Dafna Hirschfeld [this message]
2018-12-18 12:43 ` [PATCH v4l-utils] v4l2-ctl: Add support for CROP selection in m2m streaming Hans Verkuil
2018-12-19 8:34 ` Dafna Hirschfeld
2018-12-19 10:03 ` Hans Verkuil
2018-12-19 13:32 ` Dafna Hirschfeld
2018-12-20 9:45 ` Hans Verkuil
[not found] ` <CAJ1myNSeybTSGQo9wc9FnJsYqVOdTxwtaxK4tFZrc41A4NiTjw@mail.gmail.com>
2018-12-21 12:31 ` Hans Verkuil
2018-12-22 9:03 ` Dafna Hirschfeld
2018-12-22 10:50 ` Hans Verkuil
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181218111140.90645-1-dafna3@gmail.com \
--to=dafna3@gmail.com \
--cc=helen.koike@collabora.com \
--cc=hverkuil@xs4all.nl \
--cc=linux-media@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.