diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2013-03-18 07:43:14 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-25 07:51:50 -0400 |
commit | f5df0b7ff57732f938373f49e89ca219d4717836 (patch) | |
tree | d252e97ccf1f235be73c9213dcbe3a9d4229c2ee | |
parent | 69996873478d75381d14abbc9e768cc38d82e94b (diff) |
[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: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/staging/media/solo6x10/disp.c | 37 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/solo6x10.h | 27 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/v4l2-enc.c | 87 |
3 files changed, 97 insertions, 54 deletions
diff --git a/drivers/staging/media/solo6x10/disp.c b/drivers/staging/media/solo6x10/disp.c index 7007006e9638..78070c843f90 100644 --- a/drivers/staging/media/solo6x10/disp.c +++ b/drivers/staging/media/solo6x10/disp.c | |||
@@ -201,31 +201,22 @@ int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) | |||
201 | val, SOLO_MOT_THRESH_SIZE); | 201 | val, SOLO_MOT_THRESH_SIZE); |
202 | } | 202 | } |
203 | 203 | ||
204 | int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, | 204 | int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, |
205 | u16 block) | 205 | const struct solo_motion_thresholds *thresholds) |
206 | { | 206 | { |
207 | u16 buf[64]; | 207 | u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2; |
208 | u32 addr; | 208 | u16 buf[SOLO_MOTION_SZ]; |
209 | int re; | 209 | int x, y; |
210 | 210 | int ret = 0; | |
211 | addr = SOLO_MOTION_EXT_ADDR(solo_dev) + | ||
212 | SOLO_MOT_FLAG_AREA + | ||
213 | (SOLO_MOT_THRESH_SIZE * 2 * ch) + | ||
214 | (block * 2); | ||
215 | |||
216 | /* Read and write only on a 128-byte boundary; 4-byte writes with | ||
217 | solo_p2m_dma silently failed. Bluecherry bug #908. */ | ||
218 | re = solo_p2m_dma(solo_dev, 0, &buf, addr & ~0x7f, sizeof(buf), 0, 0); | ||
219 | if (re) | ||
220 | return re; | ||
221 | |||
222 | buf[(addr & 0x7f) / 2] = val; | ||
223 | |||
224 | re = solo_p2m_dma(solo_dev, 1, &buf, addr & ~0x7f, sizeof(buf), 0, 0); | ||
225 | if (re) | ||
226 | return re; | ||
227 | 211 | ||
228 | return 0; | 212 | for (y = 0; y < SOLO_MOTION_SZ; y++) { |
213 | for (x = 0; x < SOLO_MOTION_SZ; x++) | ||
214 | buf[x] = cpu_to_le16(thresholds->thresholds[y][x]); | ||
215 | ret |= solo_p2m_dma(solo_dev, 1, buf, | ||
216 | SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * sizeof(buf), | ||
217 | sizeof(buf), 0, 0); | ||
218 | } | ||
219 | return ret; | ||
229 | } | 220 | } |
230 | 221 | ||
231 | /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k | 222 | /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k |
diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index 94ac294fb048..da7611ea0e7e 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h | |||
@@ -98,16 +98,30 @@ | |||
98 | #define SOLO_DEFAULT_QP 3 | 98 | #define SOLO_DEFAULT_QP 3 |
99 | 99 | ||
100 | #ifndef V4L2_BUF_FLAG_MOTION_ON | 100 | #ifndef V4L2_BUF_FLAG_MOTION_ON |
101 | #define V4L2_BUF_FLAG_MOTION_ON 0x0400 | 101 | #define V4L2_BUF_FLAG_MOTION_ON 0x10000 |
102 | #define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800 | 102 | #define V4L2_BUF_FLAG_MOTION_DETECTED 0x20000 |
103 | #endif | 103 | #endif |
104 | 104 | ||
105 | #define SOLO_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) | 105 | #define SOLO_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) |
106 | #define V4L2_CID_MOTION_ENABLE (SOLO_CID_CUSTOM_BASE+0) | 106 | #define V4L2_CID_MOTION_MODE (SOLO_CID_CUSTOM_BASE+0) |
107 | #define V4L2_CID_MOTION_THRESHOLD (SOLO_CID_CUSTOM_BASE+1) | 107 | #define V4L2_CID_MOTION_THRESHOLD (SOLO_CID_CUSTOM_BASE+1) |
108 | #define V4L2_CID_MOTION_TRACE (SOLO_CID_CUSTOM_BASE+2) | 108 | #define V4L2_CID_MOTION_TRACE (SOLO_CID_CUSTOM_BASE+2) |
109 | #define V4L2_CID_OSD_TEXT (SOLO_CID_CUSTOM_BASE+3) | 109 | #define V4L2_CID_OSD_TEXT (SOLO_CID_CUSTOM_BASE+3) |
110 | 110 | ||
111 | /* | ||
112 | * Motion thresholds are in a table of 64x64 samples, with | ||
113 | * each sample representing 16x16 pixels of the source. In | ||
114 | * effect, 44x30 samples are used for NTSC, and 44x36 for PAL. | ||
115 | * The 5th sample on the 10th row is (10*64)+5 = 645. | ||
116 | */ | ||
117 | #define SOLO_MOTION_SZ (64) | ||
118 | struct solo_motion_thresholds { | ||
119 | __u16 thresholds[SOLO_MOTION_SZ][SOLO_MOTION_SZ]; | ||
120 | }; | ||
121 | |||
122 | #define SOLO_IOC_G_MOTION_THRESHOLDS _IOR('V', BASE_VIDIOC_PRIVATE+0, struct solo_motion_thresholds) | ||
123 | #define SOLO_IOC_S_MOTION_THRESHOLDS _IOW('V', BASE_VIDIOC_PRIVATE+1, struct solo_motion_thresholds) | ||
124 | |||
111 | enum SOLO_I2C_STATE { | 125 | enum SOLO_I2C_STATE { |
112 | IIC_STATE_IDLE, | 126 | IIC_STATE_IDLE, |
113 | IIC_STATE_START, | 127 | IIC_STATE_START, |
@@ -157,6 +171,9 @@ struct solo_enc_dev { | |||
157 | u8 mode, gop, qp, interlaced, interval; | 171 | u8 mode, gop, qp, interlaced, interval; |
158 | u8 bw_weight; | 172 | u8 bw_weight; |
159 | u16 motion_thresh; | 173 | u16 motion_thresh; |
174 | struct solo_motion_thresholds motion_thresholds; | ||
175 | bool motion_global; | ||
176 | bool motion_enabled; | ||
160 | u16 width; | 177 | u16 width; |
161 | u16 height; | 178 | u16 height; |
162 | 179 | ||
@@ -381,8 +398,8 @@ void solo_update_mode(struct solo_enc_dev *solo_enc); | |||
381 | 398 | ||
382 | /* Set the threshold for motion detection */ | 399 | /* Set the threshold for motion detection */ |
383 | int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val); | 400 | int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val); |
384 | int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, | 401 | int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, |
385 | u16 block); | 402 | const struct solo_motion_thresholds *thresholds); |
386 | #define SOLO_DEF_MOT_THRESH 0x0300 | 403 | #define SOLO_DEF_MOT_THRESH 0x0300 |
387 | 404 | ||
388 | /* Write text on OSD */ | 405 | /* Write text on OSD */ |
diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 0efb6237f685..b1fa78b2eaff 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c | |||
@@ -511,6 +511,8 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, | |||
511 | int ret; | 511 | int ret; |
512 | 512 | ||
513 | /* Check for motion flags */ | 513 | /* Check for motion flags */ |
514 | vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_MOTION_ON | | ||
515 | V4L2_BUF_FLAG_MOTION_DETECTED); | ||
514 | if (solo_is_motion_on(solo_enc)) { | 516 | if (solo_is_motion_on(solo_enc)) { |
515 | vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON; | 517 | vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON; |
516 | if (enc_buf->motion) | 518 | if (enc_buf->motion) |
@@ -1018,6 +1020,31 @@ static int solo_s_parm(struct file *file, void *priv, | |||
1018 | return 0; | 1020 | return 0; |
1019 | } | 1021 | } |
1020 | 1022 | ||
1023 | static long solo_enc_default(struct file *file, void *fh, | ||
1024 | bool valid_prio, int cmd, void *arg) | ||
1025 | { | ||
1026 | struct solo_enc_dev *solo_enc = video_drvdata(file); | ||
1027 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1028 | struct solo_motion_thresholds *thresholds = arg; | ||
1029 | |||
1030 | switch (cmd) { | ||
1031 | case SOLO_IOC_G_MOTION_THRESHOLDS: | ||
1032 | *thresholds = solo_enc->motion_thresholds; | ||
1033 | return 0; | ||
1034 | |||
1035 | case SOLO_IOC_S_MOTION_THRESHOLDS: | ||
1036 | if (!valid_prio) | ||
1037 | return -EBUSY; | ||
1038 | solo_enc->motion_thresholds = *thresholds; | ||
1039 | if (solo_enc->motion_enabled && !solo_enc->motion_global) | ||
1040 | return solo_set_motion_block(solo_dev, solo_enc->ch, | ||
1041 | &solo_enc->motion_thresholds); | ||
1042 | return 0; | ||
1043 | default: | ||
1044 | return -ENOTTY; | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1021 | static int solo_s_ctrl(struct v4l2_ctrl *ctrl) | 1048 | static int solo_s_ctrl(struct v4l2_ctrl *ctrl) |
1022 | { | 1049 | { |
1023 | struct solo_enc_dev *solo_enc = | 1050 | struct solo_enc_dev *solo_enc = |
@@ -1036,28 +1063,22 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl) | |||
1036 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | 1063 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: |
1037 | solo_enc->gop = ctrl->val; | 1064 | solo_enc->gop = ctrl->val; |
1038 | return 0; | 1065 | return 0; |
1039 | case V4L2_CID_MOTION_THRESHOLD: { | 1066 | case V4L2_CID_MOTION_THRESHOLD: |
1040 | u16 block = (ctrl->val >> 16) & 0xffff; | 1067 | solo_enc->motion_thresh = ctrl->val; |
1041 | u16 value = ctrl->val & 0xffff; | 1068 | if (!solo_enc->motion_global || !solo_enc->motion_enabled) |
1042 | 1069 | return 0; | |
1043 | /* Motion thresholds are in a table of 64x64 samples, with | 1070 | return solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->val); |
1044 | * each sample representing 16x16 pixels of the source. In | 1071 | case V4L2_CID_MOTION_MODE: |
1045 | * effect, 44x30 samples are used for NTSC, and 44x36 for PAL. | 1072 | solo_enc->motion_global = ctrl->val == 1; |
1046 | * The 5th sample on the 10th row is (10*64)+5 = 645. | 1073 | solo_enc->motion_enabled = ctrl->val > 0; |
1047 | * | 1074 | if (ctrl->val) { |
1048 | * Block is 0 to set the threshold globally, or any positive | 1075 | if (solo_enc->motion_global) |
1049 | * number under 2049 to set block-1 individually. */ | 1076 | solo_set_motion_threshold(solo_dev, solo_enc->ch, |
1050 | /* Currently we limit support to block 0 only. A later patch | 1077 | solo_enc->motion_thresh); |
1051 | * will add a new ioctl to set all other blocks. */ | 1078 | else |
1052 | if (block == 0) { | 1079 | solo_set_motion_block(solo_dev, solo_enc->ch, |
1053 | solo_enc->motion_thresh = value; | 1080 | &solo_enc->motion_thresholds); |
1054 | return solo_set_motion_threshold(solo_dev, | ||
1055 | solo_enc->ch, value); | ||
1056 | } | 1081 | } |
1057 | return solo_set_motion_block(solo_dev, solo_enc->ch, | ||
1058 | value, block - 1); | ||
1059 | } | ||
1060 | case V4L2_CID_MOTION_ENABLE: | ||
1061 | solo_motion_toggle(solo_enc, ctrl->val); | 1082 | solo_motion_toggle(solo_enc, ctrl->val); |
1062 | return 0; | 1083 | return 0; |
1063 | case V4L2_CID_OSD_TEXT: | 1084 | case V4L2_CID_OSD_TEXT: |
@@ -1111,6 +1132,7 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { | |||
1111 | .vidioc_log_status = v4l2_ctrl_log_status, | 1132 | .vidioc_log_status = v4l2_ctrl_log_status, |
1112 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | 1133 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
1113 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | 1134 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
1135 | .vidioc_default = solo_enc_default, | ||
1114 | }; | 1136 | }; |
1115 | 1137 | ||
1116 | static const struct video_device solo_enc_template = { | 1138 | static const struct video_device solo_enc_template = { |
@@ -1137,13 +1159,20 @@ static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = { | |||
1137 | .flags = V4L2_CTRL_FLAG_SLIDER, | 1159 | .flags = V4L2_CTRL_FLAG_SLIDER, |
1138 | }; | 1160 | }; |
1139 | 1161 | ||
1162 | static const char * const solo_motion_mode_menu[] = { | ||
1163 | "Disabled", | ||
1164 | "Global Threshold", | ||
1165 | "Regional Threshold", | ||
1166 | NULL | ||
1167 | }; | ||
1168 | |||
1140 | static const struct v4l2_ctrl_config solo_motion_enable_ctrl = { | 1169 | static const struct v4l2_ctrl_config solo_motion_enable_ctrl = { |
1141 | .ops = &solo_ctrl_ops, | 1170 | .ops = &solo_ctrl_ops, |
1142 | .id = V4L2_CID_MOTION_ENABLE, | 1171 | .id = V4L2_CID_MOTION_MODE, |
1143 | .name = "Motion Detection Enable", | 1172 | .name = "Motion Detection Mode", |
1144 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 1173 | .type = V4L2_CTRL_TYPE_MENU, |
1145 | .max = 1, | 1174 | .qmenu = solo_motion_mode_menu, |
1146 | .step = 1, | 1175 | .max = 2, |
1147 | }; | 1176 | }; |
1148 | 1177 | ||
1149 | static const struct v4l2_ctrl_config solo_osd_text_ctrl = { | 1178 | 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 | struct solo_enc_dev *solo_enc; | 1190 | struct solo_enc_dev *solo_enc; |
1162 | struct v4l2_ctrl_handler *hdl; | 1191 | struct v4l2_ctrl_handler *hdl; |
1163 | int ret; | 1192 | int ret; |
1193 | int x, y; | ||
1164 | 1194 | ||
1165 | solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL); | 1195 | solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL); |
1166 | if (!solo_enc) | 1196 | if (!solo_enc) |
@@ -1201,7 +1231,12 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, | |||
1201 | solo_enc->gop = solo_dev->fps; | 1231 | solo_enc->gop = solo_dev->fps; |
1202 | solo_enc->interval = 1; | 1232 | solo_enc->interval = 1; |
1203 | solo_enc->mode = SOLO_ENC_MODE_CIF; | 1233 | solo_enc->mode = SOLO_ENC_MODE_CIF; |
1234 | solo_enc->motion_global = true; | ||
1204 | solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; | 1235 | solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; |
1236 | for (y = 0; y < SOLO_MOTION_SZ; y++) | ||
1237 | for (x = 0; x < SOLO_MOTION_SZ; x++) | ||
1238 | solo_enc->motion_thresholds.thresholds[y][x] = | ||
1239 | SOLO_DEF_MOT_THRESH; | ||
1205 | 1240 | ||
1206 | solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1241 | solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1207 | solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; | 1242 | solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; |