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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox