Commit f5df0b7f authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] solo6x10: clean up motion detection handling

An earlier patch temporarily disabled regional motion detection. This patch
adds it back: the 'Motion Detection Enable' control is now a 'Motion Detection Mode'.
And to set/get the regional thresholds two new ioctls were added to get/set those
thresholds.
The BUF_FLAG constants were also updated to prevent clashing with existing buffer
flags.
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 69996873
...@@ -201,31 +201,22 @@ int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) ...@@ -201,31 +201,22 @@ int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
val, SOLO_MOT_THRESH_SIZE); val, SOLO_MOT_THRESH_SIZE);
} }
int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
u16 block) const struct solo_motion_thresholds *thresholds)
{ {
u16 buf[64]; u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
u32 addr; u16 buf[SOLO_MOTION_SZ];
int re; int x, y;
int ret = 0;
addr = SOLO_MOTION_EXT_ADDR(solo_dev) +
SOLO_MOT_FLAG_AREA +
(SOLO_MOT_THRESH_SIZE * 2 * ch) +
(block * 2);
/* Read and write only on a 128-byte boundary; 4-byte writes with
solo_p2m_dma silently failed. Bluecherry bug #908. */
re = solo_p2m_dma(solo_dev, 0, &buf, addr & ~0x7f, sizeof(buf), 0, 0);
if (re)
return re;
buf[(addr & 0x7f) / 2] = val;
re = solo_p2m_dma(solo_dev, 1, &buf, addr & ~0x7f, sizeof(buf), 0, 0);
if (re)
return re;
return 0; for (y = 0; y < SOLO_MOTION_SZ; y++) {
for (x = 0; x < SOLO_MOTION_SZ; x++)
buf[x] = cpu_to_le16(thresholds->thresholds[y][x]);
ret |= solo_p2m_dma(solo_dev, 1, buf,
SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * sizeof(buf),
sizeof(buf), 0, 0);
}
return ret;
} }
/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
......
...@@ -98,16 +98,30 @@ ...@@ -98,16 +98,30 @@
#define SOLO_DEFAULT_QP 3 #define SOLO_DEFAULT_QP 3
#ifndef V4L2_BUF_FLAG_MOTION_ON #ifndef V4L2_BUF_FLAG_MOTION_ON
#define V4L2_BUF_FLAG_MOTION_ON 0x0400 #define V4L2_BUF_FLAG_MOTION_ON 0x10000
#define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800 #define V4L2_BUF_FLAG_MOTION_DETECTED 0x20000
#endif #endif
#define SOLO_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) #define SOLO_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
#define V4L2_CID_MOTION_ENABLE (SOLO_CID_CUSTOM_BASE+0) #define V4L2_CID_MOTION_MODE (SOLO_CID_CUSTOM_BASE+0)
#define V4L2_CID_MOTION_THRESHOLD (SOLO_CID_CUSTOM_BASE+1) #define V4L2_CID_MOTION_THRESHOLD (SOLO_CID_CUSTOM_BASE+1)
#define V4L2_CID_MOTION_TRACE (SOLO_CID_CUSTOM_BASE+2) #define V4L2_CID_MOTION_TRACE (SOLO_CID_CUSTOM_BASE+2)
#define V4L2_CID_OSD_TEXT (SOLO_CID_CUSTOM_BASE+3) #define V4L2_CID_OSD_TEXT (SOLO_CID_CUSTOM_BASE+3)
/*
* Motion thresholds are in a table of 64x64 samples, with
* each sample representing 16x16 pixels of the source. In
* effect, 44x30 samples are used for NTSC, and 44x36 for PAL.
* The 5th sample on the 10th row is (10*64)+5 = 645.
*/
#define SOLO_MOTION_SZ (64)
struct solo_motion_thresholds {
__u16 thresholds[SOLO_MOTION_SZ][SOLO_MOTION_SZ];
};
#define SOLO_IOC_G_MOTION_THRESHOLDS _IOR('V', BASE_VIDIOC_PRIVATE+0, struct solo_motion_thresholds)
#define SOLO_IOC_S_MOTION_THRESHOLDS _IOW('V', BASE_VIDIOC_PRIVATE+1, struct solo_motion_thresholds)
enum SOLO_I2C_STATE { enum SOLO_I2C_STATE {
IIC_STATE_IDLE, IIC_STATE_IDLE,
IIC_STATE_START, IIC_STATE_START,
...@@ -157,6 +171,9 @@ struct solo_enc_dev { ...@@ -157,6 +171,9 @@ struct solo_enc_dev {
u8 mode, gop, qp, interlaced, interval; u8 mode, gop, qp, interlaced, interval;
u8 bw_weight; u8 bw_weight;
u16 motion_thresh; u16 motion_thresh;
struct solo_motion_thresholds motion_thresholds;
bool motion_global;
bool motion_enabled;
u16 width; u16 width;
u16 height; u16 height;
...@@ -381,8 +398,8 @@ void solo_update_mode(struct solo_enc_dev *solo_enc); ...@@ -381,8 +398,8 @@ void solo_update_mode(struct solo_enc_dev *solo_enc);
/* Set the threshold for motion detection */ /* Set the threshold for motion detection */
int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val); int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val);
int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
u16 block); const struct solo_motion_thresholds *thresholds);
#define SOLO_DEF_MOT_THRESH 0x0300 #define SOLO_DEF_MOT_THRESH 0x0300
/* Write text on OSD */ /* Write text on OSD */
......
...@@ -511,6 +511,8 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, ...@@ -511,6 +511,8 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
int ret; int ret;
/* Check for motion flags */ /* Check for motion flags */
vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_MOTION_ON |
V4L2_BUF_FLAG_MOTION_DETECTED);
if (solo_is_motion_on(solo_enc)) { if (solo_is_motion_on(solo_enc)) {
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON; vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON;
if (enc_buf->motion) if (enc_buf->motion)
...@@ -1018,6 +1020,31 @@ static int solo_s_parm(struct file *file, void *priv, ...@@ -1018,6 +1020,31 @@ static int solo_s_parm(struct file *file, void *priv,
return 0; return 0;
} }
static long solo_enc_default(struct file *file, void *fh,
bool valid_prio, int cmd, void *arg)
{
struct solo_enc_dev *solo_enc = video_drvdata(file);
struct solo_dev *solo_dev = solo_enc->solo_dev;
struct solo_motion_thresholds *thresholds = arg;
switch (cmd) {
case SOLO_IOC_G_MOTION_THRESHOLDS:
*thresholds = solo_enc->motion_thresholds;
return 0;
case SOLO_IOC_S_MOTION_THRESHOLDS:
if (!valid_prio)
return -EBUSY;
solo_enc->motion_thresholds = *thresholds;
if (solo_enc->motion_enabled && !solo_enc->motion_global)
return solo_set_motion_block(solo_dev, solo_enc->ch,
&solo_enc->motion_thresholds);
return 0;
default:
return -ENOTTY;
}
}
static int solo_s_ctrl(struct v4l2_ctrl *ctrl) static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
{ {
struct solo_enc_dev *solo_enc = struct solo_enc_dev *solo_enc =
...@@ -1036,28 +1063,22 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl) ...@@ -1036,28 +1063,22 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_GOP_SIZE: case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
solo_enc->gop = ctrl->val; solo_enc->gop = ctrl->val;
return 0; return 0;
case V4L2_CID_MOTION_THRESHOLD: { case V4L2_CID_MOTION_THRESHOLD:
u16 block = (ctrl->val >> 16) & 0xffff; solo_enc->motion_thresh = ctrl->val;
u16 value = ctrl->val & 0xffff; if (!solo_enc->motion_global || !solo_enc->motion_enabled)
return 0;
/* Motion thresholds are in a table of 64x64 samples, with return solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->val);
* each sample representing 16x16 pixels of the source. In case V4L2_CID_MOTION_MODE:
* effect, 44x30 samples are used for NTSC, and 44x36 for PAL. solo_enc->motion_global = ctrl->val == 1;
* The 5th sample on the 10th row is (10*64)+5 = 645. solo_enc->motion_enabled = ctrl->val > 0;
* if (ctrl->val) {
* Block is 0 to set the threshold globally, or any positive if (solo_enc->motion_global)
* number under 2049 to set block-1 individually. */ solo_set_motion_threshold(solo_dev, solo_enc->ch,
/* Currently we limit support to block 0 only. A later patch solo_enc->motion_thresh);
* will add a new ioctl to set all other blocks. */ else
if (block == 0) { solo_set_motion_block(solo_dev, solo_enc->ch,
solo_enc->motion_thresh = value; &solo_enc->motion_thresholds);
return solo_set_motion_threshold(solo_dev,
solo_enc->ch, value);
} }
return solo_set_motion_block(solo_dev, solo_enc->ch,
value, block - 1);
}
case V4L2_CID_MOTION_ENABLE:
solo_motion_toggle(solo_enc, ctrl->val); solo_motion_toggle(solo_enc, ctrl->val);
return 0; return 0;
case V4L2_CID_OSD_TEXT: case V4L2_CID_OSD_TEXT:
...@@ -1111,6 +1132,7 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { ...@@ -1111,6 +1132,7 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
.vidioc_log_status = v4l2_ctrl_log_status, .vidioc_log_status = v4l2_ctrl_log_status,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
.vidioc_default = solo_enc_default,
}; };
static const struct video_device solo_enc_template = { static const struct video_device solo_enc_template = {
...@@ -1137,13 +1159,20 @@ static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = { ...@@ -1137,13 +1159,20 @@ static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = {
.flags = V4L2_CTRL_FLAG_SLIDER, .flags = V4L2_CTRL_FLAG_SLIDER,
}; };
static const char * const solo_motion_mode_menu[] = {
"Disabled",
"Global Threshold",
"Regional Threshold",
NULL
};
static const struct v4l2_ctrl_config solo_motion_enable_ctrl = { static const struct v4l2_ctrl_config solo_motion_enable_ctrl = {
.ops = &solo_ctrl_ops, .ops = &solo_ctrl_ops,
.id = V4L2_CID_MOTION_ENABLE, .id = V4L2_CID_MOTION_MODE,
.name = "Motion Detection Enable", .name = "Motion Detection Mode",
.type = V4L2_CTRL_TYPE_BOOLEAN, .type = V4L2_CTRL_TYPE_MENU,
.max = 1, .qmenu = solo_motion_mode_menu,
.step = 1, .max = 2,
}; };
static const struct v4l2_ctrl_config solo_osd_text_ctrl = { static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
...@@ -1161,6 +1190,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, ...@@ -1161,6 +1190,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
struct solo_enc_dev *solo_enc; struct solo_enc_dev *solo_enc;
struct v4l2_ctrl_handler *hdl; struct v4l2_ctrl_handler *hdl;
int ret; int ret;
int x, y;
solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL); solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
if (!solo_enc) if (!solo_enc)
...@@ -1201,7 +1231,12 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, ...@@ -1201,7 +1231,12 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
solo_enc->gop = solo_dev->fps; solo_enc->gop = solo_dev->fps;
solo_enc->interval = 1; solo_enc->interval = 1;
solo_enc->mode = SOLO_ENC_MODE_CIF; solo_enc->mode = SOLO_ENC_MODE_CIF;
solo_enc->motion_global = true;
solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
for (y = 0; y < SOLO_MOTION_SZ; y++)
for (x = 0; x < SOLO_MOTION_SZ; x++)
solo_enc->motion_thresholds.thresholds[y][x] =
SOLO_DEF_MOT_THRESH;
solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment