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

[media] go7007: add motion detection support

This patch adds motion detection support to the go7007 driver using the new
motion detection controls, events.

The global motion detection works fine, but the regional motion detection
support probably needs more work. There seems to be some interaction between
regions that makes setting correct thresholds difficult. The exact meaning of
the thresholds isn't entirely clear either.

I do not have any documentation, the only information I have is the custom code
in the driver and a modet.c application.
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent c5b250ad
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <media/tuner.h> #include <media/tuner.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include "go7007-priv.h" #include "go7007-priv.h"
...@@ -332,20 +333,33 @@ EXPORT_SYMBOL(go7007_register_encoder); ...@@ -332,20 +333,33 @@ EXPORT_SYMBOL(go7007_register_encoder);
int go7007_start_encoder(struct go7007 *go) int go7007_start_encoder(struct go7007 *go)
{ {
u8 *fw; u8 *fw;
int fw_len, rv = 0, i; int fw_len, rv = 0, i, x, y;
u16 intr_val, intr_data; u16 intr_val, intr_data;
go->modet_enable = 0; go->modet_enable = 0;
if (!go->dvd_mode) for (i = 0; i < 4; i++)
for (i = 0; i < 4; ++i) { go->modet[i].enable = 0;
if (go->modet[i].enable) {
switch (v4l2_ctrl_g_ctrl(go->modet_mode)) {
case V4L2_DETECT_MD_MODE_GLOBAL:
memset(go->modet_map, 0, sizeof(go->modet_map));
go->modet[0].enable = 1;
go->modet_enable = 1; go->modet_enable = 1;
continue; break;
case V4L2_DETECT_MD_MODE_REGION_GRID:
for (y = 0; y < go->height / 16; y++) {
for (x = 0; x < go->width / 16; x++) {
int idx = y * go->width / 16 + x;
go->modet[go->modet_map[idx]].enable = 1;
} }
go->modet[i].pixel_threshold = 32767;
go->modet[i].motion_threshold = 32767;
go->modet[i].mb_threshold = 32767;
} }
go->modet_enable = 1;
break;
}
if (go->dvd_mode)
go->modet_enable = 0;
if (go7007_construct_fw_image(go, &fw, &fw_len) < 0) if (go7007_construct_fw_image(go, &fw, &fw_len) < 0)
return -1; return -1;
...@@ -383,25 +397,78 @@ static inline void store_byte(struct go7007_buffer *vb, u8 byte) ...@@ -383,25 +397,78 @@ static inline void store_byte(struct go7007_buffer *vb, u8 byte)
} }
} }
static void go7007_set_motion_regions(struct go7007 *go, struct go7007_buffer *vb,
u32 motion_regions)
{
if (motion_regions != go->modet_event_status) {
struct v4l2_event ev = {
.type = V4L2_EVENT_MOTION_DET,
.u.motion_det = {
.flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
.frame_sequence = vb->vb.v4l2_buf.sequence,
.region_mask = motion_regions,
},
};
v4l2_event_queue(&go->vdev, &ev);
go->modet_event_status = motion_regions;
}
}
/* /*
* Deliver the last video buffer and get a new one to start writing to. * Determine regions with motion and send a motion detection event
* in case of changes.
*/ */
static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buffer *vb) static void go7007_motion_regions(struct go7007 *go, struct go7007_buffer *vb)
{ {
struct go7007_buffer *vb_tmp = NULL;
u32 *bytesused = &vb->vb.v4l2_planes[0].bytesused; u32 *bytesused = &vb->vb.v4l2_planes[0].bytesused;
unsigned motion[4] = { 0, 0, 0, 0 };
u32 motion_regions = 0;
unsigned stride = (go->width + 7) >> 3;
unsigned x, y;
int i; int i;
if (vb) {
if (vb->modet_active) {
if (*bytesused + 216 < GO7007_BUF_SIZE) {
for (i = 0; i < 216; ++i) for (i = 0; i < 216; ++i)
store_byte(vb, go->active_map[i]); store_byte(vb, go->active_map[i]);
for (y = 0; y < go->height / 16; y++) {
for (x = 0; x < go->width / 16; x++) {
if (!(go->active_map[y * stride + (x >> 3)] & (1 << (x & 7))))
continue;
motion[go->modet_map[y * (go->width / 16) + x]]++;
}
}
motion_regions = ((motion[0] > 0) << 0) |
((motion[1] > 0) << 1) |
((motion[2] > 0) << 2) |
((motion[3] > 0) << 3);
*bytesused -= 216; *bytesused -= 216;
} else go7007_set_motion_regions(go, vb, motion_regions);
vb->modet_active = 0; }
/*
* Deliver the last video buffer and get a new one to start writing to.
*/
static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buffer *vb)
{
u32 *bytesused = &vb->vb.v4l2_planes[0].bytesused;
struct go7007_buffer *vb_tmp = NULL;
if (vb == NULL) {
spin_lock(&go->spinlock);
if (!list_empty(&go->vidq_active))
vb = go->active_buf =
list_first_entry(&go->vidq_active, struct go7007_buffer, list);
spin_unlock(&go->spinlock);
go->next_seq++;
return vb;
} }
vb->vb.v4l2_buf.sequence = go->next_seq++; vb->vb.v4l2_buf.sequence = go->next_seq++;
if (vb->modet_active && *bytesused + 216 < GO7007_BUF_SIZE)
go7007_motion_regions(go, vb);
else
go7007_set_motion_regions(go, vb, 0);
v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp); v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp);
vb_tmp = vb; vb_tmp = vb;
spin_lock(&go->spinlock); spin_lock(&go->spinlock);
...@@ -414,14 +481,6 @@ static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buf ...@@ -414,14 +481,6 @@ static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buf
spin_unlock(&go->spinlock); spin_unlock(&go->spinlock);
vb2_buffer_done(&vb_tmp->vb, VB2_BUF_STATE_DONE); vb2_buffer_done(&vb_tmp->vb, VB2_BUF_STATE_DONE);
return vb; return vb;
}
spin_lock(&go->spinlock);
if (!list_empty(&go->vidq_active))
vb = go->active_buf =
list_first_entry(&go->vidq_active, struct go7007_buffer, list);
spin_unlock(&go->spinlock);
go->next_seq++;
return vb;
} }
static void write_bitmap_word(struct go7007 *go) static void write_bitmap_word(struct go7007 *go)
......
...@@ -1432,22 +1432,26 @@ static int audio_to_package(struct go7007 *go, __le16 *code, int space) ...@@ -1432,22 +1432,26 @@ static int audio_to_package(struct go7007 *go, __le16 *code, int space)
static int modet_to_package(struct go7007 *go, __le16 *code, int space) static int modet_to_package(struct go7007 *go, __le16 *code, int space)
{ {
bool has_modet0 = go->modet[0].enable;
bool has_modet1 = go->modet[1].enable;
bool has_modet2 = go->modet[2].enable;
bool has_modet3 = go->modet[3].enable;
int ret, mb, i, addr, cnt = 0; int ret, mb, i, addr, cnt = 0;
u16 pack[32]; u16 pack[32];
u16 thresholds[] = { u16 thresholds[] = {
0x200e, 0, 0x200e, 0,
0xbf82, go->modet[0].pixel_threshold, 0xbf82, has_modet0 ? go->modet[0].pixel_threshold : 32767,
0xbf83, go->modet[1].pixel_threshold, 0xbf83, has_modet1 ? go->modet[1].pixel_threshold : 32767,
0xbf84, go->modet[2].pixel_threshold, 0xbf84, has_modet2 ? go->modet[2].pixel_threshold : 32767,
0xbf85, go->modet[3].pixel_threshold, 0xbf85, has_modet3 ? go->modet[3].pixel_threshold : 32767,
0xbf86, go->modet[0].motion_threshold, 0xbf86, has_modet0 ? go->modet[0].motion_threshold : 32767,
0xbf87, go->modet[1].motion_threshold, 0xbf87, has_modet1 ? go->modet[1].motion_threshold : 32767,
0xbf88, go->modet[2].motion_threshold, 0xbf88, has_modet2 ? go->modet[2].motion_threshold : 32767,
0xbf89, go->modet[3].motion_threshold, 0xbf89, has_modet3 ? go->modet[3].motion_threshold : 32767,
0xbf8a, go->modet[0].mb_threshold, 0xbf8a, has_modet0 ? go->modet[0].mb_threshold : 32767,
0xbf8b, go->modet[1].mb_threshold, 0xbf8b, has_modet1 ? go->modet[1].mb_threshold : 32767,
0xbf8c, go->modet[2].mb_threshold, 0xbf8c, has_modet2 ? go->modet[2].mb_threshold : 32767,
0xbf8d, go->modet[3].mb_threshold, 0xbf8d, has_modet3 ? go->modet[3].mb_threshold : 32767,
0xbf8e, 0, 0xbf8e, 0,
0xbf8f, 0, 0xbf8f, 0,
0, 0, 0, 0,
......
...@@ -75,6 +75,20 @@ struct go7007; ...@@ -75,6 +75,20 @@ struct go7007;
#define GO7007_AUDIO_I2S_MASTER (1<<16) #define GO7007_AUDIO_I2S_MASTER (1<<16)
#define GO7007_AUDIO_OKI_MODE (1<<17) #define GO7007_AUDIO_OKI_MODE (1<<17)
#define GO7007_CID_CUSTOM_BASE (V4L2_CID_DETECT_CLASS_BASE + 0x1000)
#define V4L2_CID_PIXEL_THRESHOLD0 (GO7007_CID_CUSTOM_BASE+1)
#define V4L2_CID_MOTION_THRESHOLD0 (GO7007_CID_CUSTOM_BASE+2)
#define V4L2_CID_MB_THRESHOLD0 (GO7007_CID_CUSTOM_BASE+3)
#define V4L2_CID_PIXEL_THRESHOLD1 (GO7007_CID_CUSTOM_BASE+4)
#define V4L2_CID_MOTION_THRESHOLD1 (GO7007_CID_CUSTOM_BASE+5)
#define V4L2_CID_MB_THRESHOLD1 (GO7007_CID_CUSTOM_BASE+6)
#define V4L2_CID_PIXEL_THRESHOLD2 (GO7007_CID_CUSTOM_BASE+7)
#define V4L2_CID_MOTION_THRESHOLD2 (GO7007_CID_CUSTOM_BASE+8)
#define V4L2_CID_MB_THRESHOLD2 (GO7007_CID_CUSTOM_BASE+9)
#define V4L2_CID_PIXEL_THRESHOLD3 (GO7007_CID_CUSTOM_BASE+10)
#define V4L2_CID_MOTION_THRESHOLD3 (GO7007_CID_CUSTOM_BASE+11)
#define V4L2_CID_MB_THRESHOLD3 (GO7007_CID_CUSTOM_BASE+12)
struct go7007_board_info { struct go7007_board_info {
unsigned int flags; unsigned int flags;
int hpi_buffer_cap; int hpi_buffer_cap;
...@@ -168,6 +182,7 @@ struct go7007 { ...@@ -168,6 +182,7 @@ struct go7007 {
struct v4l2_ctrl *mpeg_video_aspect_ratio; struct v4l2_ctrl *mpeg_video_aspect_ratio;
struct v4l2_ctrl *mpeg_video_b_frames; struct v4l2_ctrl *mpeg_video_b_frames;
struct v4l2_ctrl *mpeg_video_rep_seqheader; struct v4l2_ctrl *mpeg_video_rep_seqheader;
struct v4l2_ctrl *modet_mode;
enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status;
spinlock_t spinlock; spinlock_t spinlock;
struct mutex hw_lock; struct mutex hw_lock;
...@@ -216,6 +231,7 @@ struct go7007 { ...@@ -216,6 +231,7 @@ struct go7007 {
} modet[4]; } modet[4];
unsigned char modet_map[1624]; unsigned char modet_map[1624];
unsigned char active_map[216]; unsigned char active_map[216];
u32 modet_event_status;
/* Video streaming */ /* Video streaming */
struct mutex queue_lock; struct mutex queue_lock;
......
This diff is collapsed.
/*
* Copyright (C) 2005-2006 Micronas USA Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and the associated README documentation file (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
struct go7007_md_params {
__u16 region;
__u16 trigger;
__u16 pixel_threshold;
__u16 motion_threshold;
__u32 reserved[8];
};
struct go7007_md_region {
__u16 region;
__u16 flags;
struct v4l2_clip *clips;
__u32 reserved[8];
};
#define GO7007IOC_S_MD_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 6, \
struct go7007_md_params)
#define GO7007IOC_G_MD_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 7, \
struct go7007_md_params)
#define GO7007IOC_S_MD_REGION _IOW('V', BASE_VIDIOC_PRIVATE + 8, \
struct go7007_md_region)
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include "saa7134.h" #include "saa7134.h"
#include "saa7134-reg.h" #include "saa7134-reg.h"
#include "go7007.h"
#include "go7007-priv.h" #include "go7007-priv.h"
/*#define GO7007_HPI_DEBUG*/ /*#define GO7007_HPI_DEBUG*/
......
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