staging/easycap: Implement interlaced modes and reduced framerates

Interlaced modes are requested by tvtime.  Reduced framerates are
preferred by some userspace programs, e.g. astronomy applications.

Signed-off-by: Mike Thomas <rmthomas@sciolus.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Mike Thomas 2010-11-07 20:02:15 +00:00 committed by Greg Kroah-Hartman
parent f36bc37a48
commit 40b8d50ac9
4 changed files with 579 additions and 121 deletions

View file

@ -200,7 +200,17 @@
#define NTSC_M_JP 5
#define PAL_60 7
#define PAL_M 9
#define STANDARD_MANY 10
#define PAL_BGHIN_SLOW 10
#define PAL_Nc_SLOW 12
#define SECAM_SLOW 14
#define NTSC_N_SLOW 16
#define NTSC_N_443_SLOW 18
#define NTSC_M_SLOW 11
#define NTSC_443_SLOW 13
#define NTSC_M_JP_SLOW 15
#define PAL_60_SLOW 17
#define PAL_M_SLOW 19
#define STANDARD_MANY 20
/*---------------------------------------------------------------------------*/
/*
* ENUMS
@ -228,7 +238,6 @@ PIXELFORMAT_MANY
enum {
FIELD_NONE,
FIELD_INTERLACED,
FIELD_ALTERNATE,
INTERLACE_MANY
};
#define SETTINGS_MANY (STANDARD_MANY * \
@ -333,6 +342,8 @@ bool ntsc;
int fps;
int usec;
int tolerate;
int skip;
int skipped;
int merit[180];
struct timeval timeval0;
@ -399,7 +410,6 @@ int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF */
*/
/*---------------------------------------------------------------------------*/
__u32 pixelformat;
__u32 field;
int width;
int height;
int bytesperpixel;

View file

@ -40,6 +40,7 @@
* peasycap->fps
* peasycap->usec
* peasycap->tolerate
* peasycap->skip
*/
/*---------------------------------------------------------------------------*/
int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
@ -60,10 +61,18 @@ if ((struct usb_device *)NULL == peasycap->pusb_device) {
}
peasycap_standard = &easycap_standard[0];
while (0xFFFF != peasycap_standard->mask) {
if (std_id & peasycap_standard->v4l2_standard.id)
if (std_id == peasycap_standard->v4l2_standard.id)
break;
peasycap_standard++;
}
if (0xFFFF == peasycap_standard->mask) {
peasycap_standard = &easycap_standard[0];
while (0xFFFF != peasycap_standard->mask) {
if (std_id & peasycap_standard->v4l2_standard.id)
break;
peasycap_standard++;
}
}
if (0xFFFF == peasycap_standard->mask) {
SAM("ERROR: 0x%08X=std_id: standard not found\n", \
(unsigned int)std_id);
@ -92,10 +101,12 @@ if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \
peasycap_standard->v4l2_standard.frameperiod.numerator;
switch (peasycap->fps) {
case 6:
case 30: {
peasycap->ntsc = true;
break;
}
case 5:
case 25: {
peasycap->ntsc = false;
break;
@ -106,9 +117,15 @@ default: {
}
}
JOM(8, "%i frames-per-second\n", peasycap->fps);
peasycap->usec = 1000000 / (2 * peasycap->fps);
peasycap->tolerate = 1000 * (25 / peasycap->fps);
if (0x8000 & peasycap_standard->mask) {
peasycap->skip = 5;
peasycap->usec = 1000000 / (2 * (5 * peasycap->fps));
peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps));
} else {
peasycap->skip = 0;
peasycap->usec = 1000000 / (2 * peasycap->fps);
peasycap->tolerate = 1000 * (25 / peasycap->fps);
}
if (peasycap->video_isoc_streaming) {
resubmit = true;
kill_video_urbs(peasycap);
@ -311,7 +328,6 @@ return 0;
* peasycap->format_offset
* peasycap->inputset[peasycap->input].format_offset
* peasycap->pixelformat
* peasycap->field
* peasycap->height
* peasycap->width
* peasycap->bytesperpixel
@ -333,7 +349,7 @@ struct easycap_format *peasycap_format, *peasycap_best_format;
__u16 mask;
struct usb_device *p;
int miss, multiplier, best, k;
char bf[5], *pc;
char bf[5], fo[32], *pc;
__u32 uc;
bool resubmit;
@ -351,13 +367,62 @@ if ((struct usb_device *)NULL == p) {
return -EFAULT;
}
pc = &bf[0];
uc = pixelformat; memcpy((void *)pc, (void *)(&uc), 4); bf[4] = 0;
mask = easycap_standard[peasycap->standard_offset].mask;
uc = pixelformat;
memcpy((void *)pc, (void *)(&uc), 4);
bf[4] = 0;
mask = 0xFF & easycap_standard[peasycap->standard_offset].mask;
SAM("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \
width, height, pc, pixelformat, field, mask);
switch (field) {
case V4L2_FIELD_ANY: {
strcpy(&fo[0], "V4L2_FIELD_ANY ");
break;
}
case V4L2_FIELD_NONE: {
strcpy(&fo[0], "V4L2_FIELD_NONE");
break;
}
case V4L2_FIELD_TOP: {
strcpy(&fo[0], "V4L2_FIELD_TOP");
break;
}
case V4L2_FIELD_BOTTOM: {
strcpy(&fo[0], "V4L2_FIELD_BOTTOM");
break;
}
case V4L2_FIELD_INTERLACED: {
strcpy(&fo[0], "V4L2_FIELD_INTERLACED");
break;
}
case V4L2_FIELD_SEQ_TB: {
strcpy(&fo[0], "V4L2_FIELD_SEQ_TB");
break;
}
case V4L2_FIELD_SEQ_BT: {
strcpy(&fo[0], "V4L2_FIELD_SEQ_BT");
break;
}
case V4L2_FIELD_ALTERNATE: {
strcpy(&fo[0], "V4L2_FIELD_ALTERNATE");
break;
}
case V4L2_FIELD_INTERLACED_TB: {
strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB");
break;
}
case V4L2_FIELD_INTERLACED_BT: {
strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT");
break;
}
default: {
strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN ");
break;
}
}
SAM("sought: %s\n", &fo[0]);
if (V4L2_FIELD_ANY == field) {
field = V4L2_FIELD_INTERLACED;
SAM("prefer: V4L2_FIELD_INTERLACED=field, was V4L2_FIELD_ANY\n");
field = V4L2_FIELD_NONE;
SAM("prefer: V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n");
}
peasycap_best_format = (struct easycap_format *)NULL;
peasycap_format = &easycap_format[0];
@ -369,7 +434,7 @@ while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
peasycap_format->v4l2_format.fmt.pix.width,
peasycap_format->v4l2_format.fmt.pix.height);
if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && \
(peasycap_format->v4l2_format.fmt.pix.field == field) && \
(peasycap_format->v4l2_format.fmt.pix.pixelformat == \
pixelformat) && \
@ -385,7 +450,7 @@ if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
width, height, mask);
peasycap_format = &easycap_format[0]; best = -1;
while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && \
(peasycap_format->v4l2_format.fmt.pix\
.field == field) && \
(peasycap_format->v4l2_format.fmt.pix\
@ -432,7 +497,6 @@ SAM("actioning: %ix%i %s\n", \
peasycap->height = peasycap_format->v4l2_format.fmt.pix.height;
peasycap->width = peasycap_format->v4l2_format.fmt.pix.width;
peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat;
peasycap->field = peasycap_format->v4l2_format.fmt.pix.field;
peasycap->format_offset = (int)(peasycap_format - &easycap_format[0]);
@ -451,11 +515,15 @@ if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
peasycap->bytesperpixel = (0x00F0 & peasycap_format->mask) >> 4 ;
peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ;
if (0x0100 & peasycap_format->mask)
peasycap->byteswaporder = true;
else
peasycap->byteswaporder = false;
if (0x0200 & peasycap_format->mask)
peasycap->skip = 5;
else
peasycap->skip = 0;
if (0x0800 & peasycap_format->mask)
peasycap->decimatepixel = true;
else
@ -472,24 +540,6 @@ peasycap->videofieldamount = multiplier * peasycap->width * \
multiplier * peasycap->height;
peasycap->frame_buffer_used = peasycap->bytesperpixel * \
peasycap->width * peasycap->height;
if (true == peasycap->offerfields) {
SAM("WARNING: %i=peasycap->field is untested: " \
"please report problems\n", peasycap->field);
/*
* FIXME ---- THIS IS UNTESTED, MAY BE (AND PROBABLY IS) INCORRECT:
*
* peasycap->frame_buffer_used = peasycap->frame_buffer_used / 2;
*
* SO DO NOT RISK IT YET.
*
*/
}
if (peasycap->video_isoc_streaming) {
resubmit = true;
kill_video_urbs(peasycap);
@ -1386,13 +1436,191 @@ case VIDIOC_ENUM_FMT: {
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE
* THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE.
*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUM_FRAMESIZES: {
JOM(8, "VIDIOC_ENUM_FRAMESIZES unsupported\n");
return -EINVAL;
__u32 index;
struct v4l2_frmsizeenum v4l2_frmsizeenum;
JOM(8, "VIDIOC_ENUM_FRAMESIZES\n");
if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, \
sizeof(struct v4l2_frmsizeenum)))
return -EFAULT;
index = v4l2_frmsizeenum.index;
v4l2_frmsizeenum.type = (__u32) V4L2_FRMSIZE_TYPE_DISCRETE;
if (true == peasycap->ntsc) {
switch (index) {
case 0: {
v4l2_frmsizeenum.discrete.width = 640;
v4l2_frmsizeenum.discrete.height = 480;
JOM(8, "%i=index: %ix%i\n", index, \
(int)(v4l2_frmsizeenum.\
discrete.width), \
(int)(v4l2_frmsizeenum.\
discrete.height));
break;
}
case 1: {
v4l2_frmsizeenum.discrete.width = 320;
v4l2_frmsizeenum.discrete.height = 240;
JOM(8, "%i=index: %ix%i\n", index, \
(int)(v4l2_frmsizeenum.\
discrete.width), \
(int)(v4l2_frmsizeenum.\
discrete.height));
break;
}
case 2: {
v4l2_frmsizeenum.discrete.width = 720;
v4l2_frmsizeenum.discrete.height = 480;
JOM(8, "%i=index: %ix%i\n", index, \
(int)(v4l2_frmsizeenum.\
discrete.width), \
(int)(v4l2_frmsizeenum.\
discrete.height));
break;
}
case 3: {
v4l2_frmsizeenum.discrete.width = 360;
v4l2_frmsizeenum.discrete.height = 240;
JOM(8, "%i=index: %ix%i\n", index, \
(int)(v4l2_frmsizeenum.\
discrete.width), \
(int)(v4l2_frmsizeenum.\
discrete.height));
break;
}
default: {
JOM(8, "%i=index: exhausts framesizes\n", index);
return -EINVAL;
}
}
} else {
switch (index) {
case 0: {
v4l2_frmsizeenum.discrete.width = 640;
v4l2_frmsizeenum.discrete.height = 480;
JOM(8, "%i=index: %ix%i\n", index, \
(int)(v4l2_frmsizeenum.\
discrete.width), \
(int)(v4l2_frmsizeenum.\
discrete.height));
break;
}
case 1: {
v4l2_frmsizeenum.discrete.width = 320;
v4l2_frmsizeenum.discrete.height = 240;
JOM(8, "%i=index: %ix%i\n", index, \
(int)(v4l2_frmsizeenum.\
discrete.width), \
(int)(v4l2_frmsizeenum.\
discrete.height));
break;
}
case 2: {
v4l2_frmsizeenum.discrete.width = 704;
v4l2_frmsizeenum.discrete.height = 576;
JOM(8, "%i=index: %ix%i\n", index, \
(int)(v4l2_frmsizeenum.\
discrete.width), \
(int)(v4l2_frmsizeenum.\
discrete.height));
break;
}
case 3: {
v4l2_frmsizeenum.discrete.width = 720;
v4l2_frmsizeenum.discrete.height = 576;
JOM(8, "%i=index: %ix%i\n", index, \
(int)(v4l2_frmsizeenum.\
discrete.width), \
(int)(v4l2_frmsizeenum.\
discrete.height));
break;
}
case 4: {
v4l2_frmsizeenum.discrete.width = 360;
v4l2_frmsizeenum.discrete.height = 288;
JOM(8, "%i=index: %ix%i\n", index, \
(int)(v4l2_frmsizeenum.\
discrete.width), \
(int)(v4l2_frmsizeenum.\
discrete.height));
break;
}
default: {
JOM(8, "%i=index: exhausts framesizes\n", index);
return -EINVAL;
}
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_frmsizeenum, \
sizeof(struct v4l2_frmsizeenum)))
return -EFAULT;
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE
* THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE.
*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUM_FRAMEINTERVALS: {
JOM(8, "VIDIOC_ENUM_FRAME_INTERVALS unsupported\n");
return -EINVAL;
__u32 index;
int denominator;
struct v4l2_frmivalenum v4l2_frmivalenum;
JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n");
if (peasycap->fps)
denominator = peasycap->fps;
else {
if (true == peasycap->ntsc)
denominator = 30;
else
denominator = 25;
}
if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, \
sizeof(struct v4l2_frmivalenum)))
return -EFAULT;
index = v4l2_frmivalenum.index;
v4l2_frmivalenum.type = (__u32) V4L2_FRMIVAL_TYPE_DISCRETE;
switch (index) {
case 0: {
v4l2_frmivalenum.discrete.numerator = 1;
v4l2_frmivalenum.discrete.denominator = denominator;
JOM(8, "%i=index: %i/%i\n", index, \
(int)(v4l2_frmivalenum.discrete.numerator), \
(int)(v4l2_frmivalenum.discrete.denominator));
break;
}
case 1: {
v4l2_frmivalenum.discrete.numerator = 1;
v4l2_frmivalenum.discrete.denominator = denominator/5;
JOM(8, "%i=index: %i/%i\n", index, \
(int)(v4l2_frmivalenum.discrete.numerator), \
(int)(v4l2_frmivalenum.discrete.denominator));
break;
}
default: {
JOM(8, "%i=index: exhausts frameintervals\n", index);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_frmivalenum, \
sizeof(struct v4l2_frmivalenum)))
return -EFAULT;
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_FMT: {
@ -1603,6 +1831,10 @@ case VIDIOC_S_STD: {
sizeof(v4l2_std_id)))
return -EFAULT;
JOM(8, "User requests standard: 0x%08X%08X\n", \
(int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32), \
(int)(std_id & ((v4l2_std_id)0xFFFFFFFF)));
rc = adjust_standard(peasycap, std_id);
if (0 > rc) {
JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
@ -1675,7 +1907,7 @@ case VIDIOC_QUERYBUF: {
v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | \
peasycap->done[index] | \
peasycap->queued[index];
v4l2_buffer.field = peasycap->field;
v4l2_buffer.field = V4L2_FIELD_NONE;
v4l2_buffer.memory = V4L2_MEMORY_MMAP;
v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
v4l2_buffer.length = FRAME_BUFFER_SIZE;
@ -1762,6 +1994,24 @@ case VIDIOC_DQBUF:
if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (true == peasycap->offerfields) {
/*-----------------------------------------------------------*/
/*
* IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST
* V4L2_FIELD_BOTTOM
*/
/*-----------------------------------------------------------*/
if (V4L2_FIELD_TOP == v4l2_buffer.field)
JOM(8, "user wants V4L2_FIELD_TOP\n");
else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field)
JOM(8, "user wants V4L2_FIELD_BOTTOM\n");
else if (V4L2_FIELD_ANY == v4l2_buffer.field)
JOM(8, "user wants V4L2_FIELD_ANY\n");
else
JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n", \
v4l2_buffer.field);
}
if (!peasycap->video_isoc_streaming) {
JOM(16, "returning -EIO because video urbs not streaming\n");
return -EIO;
@ -1811,11 +2061,10 @@ case VIDIOC_DQBUF:
v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_buffer.bytesused = peasycap->frame_buffer_used;
v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
v4l2_buffer.field = peasycap->field;
if (V4L2_FIELD_ALTERNATE == v4l2_buffer.field)
v4l2_buffer.field = \
0x000F & (peasycap->\
frame_buffer[peasycap->frame_read][0].kount);
if (true == peasycap->offerfields)
v4l2_buffer.field = V4L2_FIELD_BOTTOM;
else
v4l2_buffer.field = V4L2_FIELD_NONE;
do_gettimeofday(&timeval);
timeval2 = timeval;
@ -1876,10 +2125,6 @@ case VIDIOC_DQBUF:
sizeof(struct v4l2_buffer)))
return -EFAULT;
JOM(8, "..... user is offered frame buffer %i\n", \
peasycap->frame_read);
peasycap->frame_lock = 1;
input = peasycap->frame_buffer[peasycap->frame_read][0].input;
if (0x08 & input) {
JOM(8, "user is offered frame buffer %i, input %i\n", \
@ -1956,7 +2201,6 @@ case VIDIOC_G_PARM: {
v4l2_streamparm.parm.capture.capability = 0;
v4l2_streamparm.parm.capture.capturemode = 0;
v4l2_streamparm.parm.capture.timeperframe.numerator = 1;
v4l2_streamparm.parm.capture.timeperframe.denominator = 30;
if (peasycap->fps) {
v4l2_streamparm.parm.capture.timeperframe.\

View file

@ -471,7 +471,7 @@ if (NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
return -ENODEV;
}
rc = usb_set_interface(peasycap->pusb_device, \
rc = usb_set_interface(peasycap->pusb_device,
peasycap->video_interface, \
peasycap->video_altsetting_off);
if (0 != rc) {
@ -1103,7 +1103,7 @@ else
int
easycap_dqbuf(struct easycap *peasycap, int mode)
{
int miss, rc;
int ifield, miss, rc;
JOT(8, "\n");
@ -1111,16 +1111,18 @@ if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
ifield = 0;
JOM(8, "%i=ifield\n", ifield);
/*---------------------------------------------------------------------------*/
/*
* WAIT FOR FIELD 0
* WAIT FOR FIELD ifield (0 => TOP, 1 => BOTTOM)
*/
/*---------------------------------------------------------------------------*/
miss = 0;
while ((peasycap->field_read == peasycap->field_fill) || \
(0 != (0xFF00 & peasycap->field_buffer\
[peasycap->field_read][0].kount)) || \
(0 != (0x00FF & peasycap->field_buffer\
(ifield != (0x00FF & peasycap->field_buffer\
[peasycap->field_read][0].kount))) {
if (mode)
return -EAGAIN;
@ -1134,7 +1136,7 @@ while ((peasycap->field_read == peasycap->field_fill) || \
((peasycap->field_read != peasycap->field_fill) && \
(0 == (0xFF00 & peasycap->field_buffer\
[peasycap->field_read][0].kount)) && \
(0 == (0x00FF & peasycap->field_buffer\
(ifield == (0x00FF & peasycap->field_buffer\
[peasycap->field_read][0].kount))))))) {
SAM("aborted by signal\n");
return -EIO;
@ -1176,33 +1178,20 @@ JOM(8, "first awakening on wq_video after %i waits\n", miss);
rc = field2frame(peasycap);
if (0 != rc)
SAM("ERROR: field2frame() returned %i\n", rc);
if (true == peasycap->offerfields) {
peasycap->frame_read = peasycap->frame_fill;
(peasycap->frame_fill)++;
if (peasycap->frame_buffer_many <= peasycap->frame_fill)
peasycap->frame_fill = 0;
if (0x01 & easycap_standard[peasycap->standard_offset].mask) {
peasycap->frame_buffer[peasycap->frame_read][0].kount = \
V4L2_FIELD_BOTTOM;
} else {
peasycap->frame_buffer[peasycap->frame_read][0].kount = \
V4L2_FIELD_TOP;
}
JOM(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read);
JOM(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill);
}
/*---------------------------------------------------------------------------*/
/*
* WAIT FOR FIELD 1
* WAIT FOR THE OTHER FIELD
*/
/*---------------------------------------------------------------------------*/
if (ifield)
ifield = 0;
else
ifield = 1;
miss = 0;
while ((peasycap->field_read == peasycap->field_fill) || \
(0 != (0xFF00 & peasycap->field_buffer\
[peasycap->field_read][0].kount)) || \
(0 == (0x00FF & peasycap->field_buffer\
(ifield != (0x00FF & peasycap->field_buffer\
[peasycap->field_read][0].kount))) {
if (mode)
return -EAGAIN;
@ -1215,8 +1204,9 @@ while ((peasycap->field_read == peasycap->field_fill) || \
((peasycap->field_read != peasycap->field_fill) && \
(0 == (0xFF00 & peasycap->field_buffer\
[peasycap->field_read][0].kount)) && \
(0 != (0x00FF & peasycap->field_buffer\
[peasycap->field_read][0].kount))))))) {
(ifield == (0x00FF & peasycap->field_buffer\
[peasycap->field_read][0].\
kount))))))) {
SAM("aborted by signal\n");
return -EIO;
}
@ -1257,7 +1247,18 @@ JOM(8, "second awakening on wq_video after %i waits\n", miss);
rc = field2frame(peasycap);
if (0 != rc)
SAM("ERROR: field2frame() returned %i\n", rc);
/*---------------------------------------------------------------------------*/
/*
* WASTE THIS FRAME
*/
/*---------------------------------------------------------------------------*/
if (0 != peasycap->skip) {
peasycap->skipped++;
if (peasycap->skip != peasycap->skipped)
return peasycap->skip - peasycap->skipped;
peasycap->skipped = 0;
}
/*---------------------------------------------------------------------------*/
peasycap->frame_read = peasycap->frame_fill;
peasycap->queued[peasycap->frame_read] = 0;
peasycap->done[peasycap->frame_read] = V4L2_BUF_FLAG_DONE;
@ -1289,8 +1290,7 @@ return 0;
* odd==false IS TRANSFERRED TO THE FRAME BUFFER.
*
* THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM
* CHOOSES THE OPTION V4L2_FIELD_ALTERNATE. NO USERSPACE PROGRAM TESTED
* TO DATE HAS DONE THIS. BUGS ARE LIKELY.
* CHOOSES THE OPTION V4L2_FIELD_INTERLACED.
*/
/*---------------------------------------------------------------------------*/
int
@ -1315,8 +1315,10 @@ if ((struct easycap *)NULL == peasycap) {
badinput = false;
JOM(8, "===== parity %i, field buffer %i --> frame buffer %i\n", \
JOM(8, "===== parity %i, input 0x%02X, field buffer %i --> " \
"frame buffer %i\n", \
peasycap->field_buffer[peasycap->field_read][0].kount,\
peasycap->field_buffer[peasycap->field_read][0].input,\
peasycap->field_read, peasycap->frame_fill);
JOM(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel);
if (true == peasycap->offerfields)
@ -1374,7 +1376,7 @@ if (peasycap->field_buffer[kex][0].kount)
else
odd = false;
if ((true == odd) && (false == offerfields) &&(false == decimatepixel)) {
if ((true == odd) && (false == decimatepixel)) {
JOM(8, " initial skipping %4i bytes p.%4i\n", \
w3/multiplier, mad);
pad += (w3 / multiplier); rad -= (w3 / multiplier);
@ -1494,7 +1496,7 @@ while (cz < wz) {
* UNLESS IT IS THE LAST LINE OF AN ODD FRAME
*/
/*---------------------------------------------------------------------------*/
if (((false == odd) || (cz != wz))&&(false == offerfields)) {
if ((false == odd) || (cz != wz)) {
over = w3;
do {
if (!rad) {
@ -3162,6 +3164,15 @@ if (purb->status) {
[peasycap->field_page];
pfield_buffer->pto = \
pfield_buffer->pgo;
pfield_buffer->input = 0x08 | \
(0x07 & peasycap->input);
if ((peasycap->field_buffer[peasycap->\
field_fill][0]).\
input != \
pfield_buffer->input)
(peasycap->field_buffer\
[peasycap->field_fill]\
[0]).kount |= 0x1000;
}
much = PAGE_SIZE - (int)(pfield_buffer->pto - \
@ -3441,7 +3452,6 @@ if (0 == bInterfaceNumber) {
break;
}
}
if (DONGLE_MANY <= dongle_this) {
SAM("ERROR: too many dongles\n");
return -ENOMEM;
@ -3481,6 +3491,8 @@ if (0 == bInterfaceNumber) {
peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
peasycap->skip = 0;
peasycap->skipped = 0;
peasycap->offerfields = 0;
/*---------------------------------------------------------------------------*/
/*

View file

@ -33,11 +33,15 @@
* THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
* 0 => 25 fps
* 1 => 30 fps
*
* THE MOST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
* 0 => full framerate
* 1 => 20% framerate
*/
/*---------------------------------------------------------------------------*/
const struct easycap_standard easycap_standard[] = {
{
.mask = 0x000F & PAL_BGHIN ,
.mask = 0x00FF & PAL_BGHIN ,
.v4l2_standard = {
.index = PAL_BGHIN,
.id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \
@ -50,7 +54,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x000F & NTSC_N_443 ,
.mask = 0x00FF & NTSC_N_443 ,
.v4l2_standard = {
.index = NTSC_N_443,
.id = V4L2_STD_UNKNOWN,
@ -62,7 +66,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x000F & PAL_Nc ,
.mask = 0x00FF & PAL_Nc ,
.v4l2_standard = {
.index = PAL_Nc,
.id = V4L2_STD_PAL_Nc,
@ -74,7 +78,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x000F & NTSC_N ,
.mask = 0x00FF & NTSC_N ,
.v4l2_standard = {
.index = NTSC_N,
.id = V4L2_STD_UNKNOWN,
@ -86,7 +90,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x000F & SECAM ,
.mask = 0x00FF & SECAM ,
.v4l2_standard = {
.index = SECAM,
.id = V4L2_STD_SECAM,
@ -98,7 +102,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x000F & NTSC_M ,
.mask = 0x00FF & NTSC_M ,
.v4l2_standard = {
.index = NTSC_M,
.id = V4L2_STD_NTSC_M,
@ -110,7 +114,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x000F & NTSC_M_JP ,
.mask = 0x00FF & NTSC_M_JP ,
.v4l2_standard = {
.index = NTSC_M_JP,
.id = V4L2_STD_NTSC_M_JP,
@ -122,7 +126,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x000F & PAL_60 ,
.mask = 0x00FF & PAL_60 ,
.v4l2_standard = {
.index = PAL_60,
.id = V4L2_STD_PAL_60,
@ -134,7 +138,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x000F & NTSC_443 ,
.mask = 0x00FF & NTSC_443 ,
.v4l2_standard = {
.index = NTSC_443,
.id = V4L2_STD_NTSC_443,
@ -146,7 +150,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x000F & PAL_M ,
.mask = 0x00FF & PAL_M ,
.v4l2_standard = {
.index = PAL_M,
.id = V4L2_STD_PAL_M,
@ -158,6 +162,128 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x8000 | (0x00FF & PAL_BGHIN_SLOW),
.v4l2_standard = {
.index = PAL_BGHIN_SLOW,
.id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \
V4L2_STD_PAL_I | V4L2_STD_PAL_N | \
(((v4l2_std_id)0x01) << 32)),
.name = "PAL_BGHIN_SLOW",
.frameperiod = {1, 5},
.framelines = 625,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x8000 | (0x00FF & NTSC_N_443_SLOW),
.v4l2_standard = {
.index = NTSC_N_443_SLOW,
.id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x11) << 32)),
.name = "NTSC_N_443_SLOW",
.frameperiod = {1, 5},
.framelines = 480,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x8000 | (0x00FF & PAL_Nc_SLOW),
.v4l2_standard = {
.index = PAL_Nc_SLOW,
.id = (V4L2_STD_PAL_Nc | (((v4l2_std_id)0x01) << 32)),
.name = "PAL_Nc_SLOW",
.frameperiod = {1, 5},
.framelines = 625,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x8000 | (0x00FF & NTSC_N_SLOW),
.v4l2_standard = {
.index = NTSC_N_SLOW,
.id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x21) << 32)),
.name = "NTSC_N_SLOW",
.frameperiod = {1, 5},
.framelines = 525,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x8000 | (0x00FF & SECAM_SLOW),
.v4l2_standard = {
.index = SECAM_SLOW,
.id = (V4L2_STD_SECAM | (((v4l2_std_id)0x01) << 32)),
.name = "SECAM_SLOW",
.frameperiod = {1, 5},
.framelines = 625,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x8000 | (0x00FF & NTSC_M_SLOW),
.v4l2_standard = {
.index = NTSC_M_SLOW,
.id = (V4L2_STD_NTSC_M | (((v4l2_std_id)0x01) << 32)),
.name = "NTSC_M_SLOW",
.frameperiod = {1, 6},
.framelines = 525,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x8000 | (0x00FF & NTSC_M_JP_SLOW),
.v4l2_standard = {
.index = NTSC_M_JP_SLOW,
.id = (V4L2_STD_NTSC_M_JP | (((v4l2_std_id)0x01) << 32)),
.name = "NTSC_M_JP_SLOW",
.frameperiod = {1, 6},
.framelines = 525,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x8000 | (0x00FF & PAL_60_SLOW),
.v4l2_standard = {
.index = PAL_60_SLOW,
.id = (V4L2_STD_PAL_60 | (((v4l2_std_id)0x01) << 32)),
.name = "PAL_60_SLOW",
.frameperiod = {1, 6},
.framelines = 525,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x8000 | (0x00FF & NTSC_443_SLOW),
.v4l2_standard = {
.index = NTSC_443_SLOW,
.id = (V4L2_STD_NTSC_443 | (((v4l2_std_id)0x01) << 32)),
.name = "NTSC_443_SLOW",
.frameperiod = {1, 6},
.framelines = 525,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x8000 | (0x00FF & PAL_M_SLOW),
.v4l2_standard = {
.index = PAL_M_SLOW,
.id = (V4L2_STD_PAL_M | (((v4l2_std_id)0x01) << 32)),
.name = "PAL_M_SLOW",
.frameperiod = {1, 6},
.framelines = 525,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0xFFFF
}
};
@ -165,15 +291,16 @@ const struct easycap_standard easycap_standard[] = {
/*
* THE 16-BIT easycap_format.mask HAS MEANING:
* (least significant) BIT 0: 0 => PAL, 25 FPS; 1 => NTSC, 30 FPS
* BITS 1-3: RESERVED FOR DIFFERENTIATING STANDARDS
* BITS 4-7: NUMBER OF BYTES PER PIXEL
* BITS 2-4: RESERVED FOR DIFFERENTIATING STANDARDS
* BITS 5-7: NUMBER OF BYTES PER PIXEL
* BIT 8: 0 => NATIVE BYTE ORDER; 1 => SWAPPED
* BITS 9-10: RESERVED FOR OTHER BYTE PERMUTATIONS
* BIT 11: 0 => UNDECIMATED; 1 => DECIMATED
* BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS
* (most significant) BITS 13-15: RESERVED FOR OTHER FIELD ORDER OPTIONS
* BIT 11: 0 => UNDECIMATED; 1 => DECIMATED
* BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS
* BIT 13: 0 => FULL FRAMERATE; 1 => REDUCED
* (most significant) BITS 14-15: RESERVED FOR OTHER FIELD/FRAME OPTIONS
* IT FOLLOWS THAT:
* bytesperpixel IS ((0x00F0 & easycap_format.mask) >> 4)
* bytesperpixel IS ((0x00E0 & easycap_format.mask) >> 5)
* byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask))
*
* decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask))
@ -197,65 +324,135 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) {
mask1 = 0x0000;
switch (i) {
case PAL_BGHIN: {
mask1 = PAL_BGHIN;
mask1 = 0x1F & PAL_BGHIN;
strcpy(&name1[0], "PAL_BGHIN");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case SECAM: {
mask1 = SECAM;
mask1 = 0x1F & SECAM;
strcpy(&name1[0], "SECAM");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_Nc: {
mask1 = PAL_Nc;
mask1 = 0x1F & PAL_Nc;
strcpy(&name1[0], "PAL_Nc");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_60: {
mask1 = PAL_60;
mask1 = 0x1F & PAL_60;
strcpy(&name1[0], "PAL_60");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_M: {
mask1 = PAL_M;
mask1 = 0x1F & PAL_M;
strcpy(&name1[0], "PAL_M");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case NTSC_M: {
mask1 = NTSC_M;
mask1 = 0x1F & NTSC_M;
strcpy(&name1[0], "NTSC_M");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_443: {
mask1 = NTSC_443;
mask1 = 0x1F & NTSC_443;
strcpy(&name1[0], "NTSC_443");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_M_JP: {
mask1 = NTSC_M_JP;
mask1 = 0x1F & NTSC_M_JP;
strcpy(&name1[0], "NTSC_M_JP");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_N: {
mask1 = NTSC_M;
mask1 = 0x1F & NTSC_M;
strcpy(&name1[0], "NTSC_N");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_N_443: {
mask1 = NTSC_N_443;
mask1 = 0x1F & NTSC_N_443;
strcpy(&name1[0], "NTSC_N_443");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case PAL_BGHIN_SLOW: {
mask1 = 0x001F & PAL_BGHIN_SLOW;
mask1 |= 0x0200;
strcpy(&name1[0], "PAL_BGHIN_SLOW");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case SECAM_SLOW: {
mask1 = 0x001F & SECAM_SLOW;
mask1 |= 0x0200;
strcpy(&name1[0], "SECAM_SLOW");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_Nc_SLOW: {
mask1 = 0x001F & PAL_Nc_SLOW;
mask1 |= 0x0200;
strcpy(&name1[0], "PAL_Nc_SLOW");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_60_SLOW: {
mask1 = 0x001F & PAL_60_SLOW;
mask1 |= 0x0200;
strcpy(&name1[0], "PAL_60_SLOW");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_M_SLOW: {
mask1 = 0x001F & PAL_M_SLOW;
mask1 |= 0x0200;
strcpy(&name1[0], "PAL_M_SLOW");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case NTSC_M_SLOW: {
mask1 = 0x001F & NTSC_M_SLOW;
mask1 |= 0x0200;
strcpy(&name1[0], "NTSC_M_SLOW");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_443_SLOW: {
mask1 = 0x001F & NTSC_443_SLOW;
mask1 |= 0x0200;
strcpy(&name1[0], "NTSC_443_SLOW");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_M_JP_SLOW: {
mask1 = 0x001F & NTSC_M_JP_SLOW;
mask1 |= 0x0200;
strcpy(&name1[0], "NTSC_M_JP_SLOW");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_N_SLOW: {
mask1 = 0x001F & NTSC_N_SLOW;
mask1 |= 0x0200;
strcpy(&name1[0], "NTSC_N_SLOW");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_N_443_SLOW: {
mask1 = 0x001F & NTSC_N_443_SLOW;
mask1 |= 0x0200;
strcpy(&name1[0], "NTSC_N_443_SLOW");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
default:
return -1;
}
@ -311,39 +508,39 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) {
case FMT_UYVY: {
strcpy(&name3[0], "_" STRINGIZE(FMT_UYVY));
pixelformat = V4L2_PIX_FMT_UYVY;
mask3 |= (0x02 << 4);
mask3 |= (0x02 << 5);
break;
}
case FMT_YUY2: {
strcpy(&name3[0], "_" STRINGIZE(FMT_YUY2));
pixelformat = V4L2_PIX_FMT_YUYV;
mask3 |= (0x02 << 4);
mask3 |= (0x02 << 5);
mask3 |= 0x0100;
break;
}
case FMT_RGB24: {
strcpy(&name3[0], "_" STRINGIZE(FMT_RGB24));
pixelformat = V4L2_PIX_FMT_RGB24;
mask3 |= (0x03 << 4);
mask3 |= (0x03 << 5);
break;
}
case FMT_RGB32: {
strcpy(&name3[0], "_" STRINGIZE(FMT_RGB32));
pixelformat = V4L2_PIX_FMT_RGB32;
mask3 |= (0x04 << 4);
mask3 |= (0x04 << 5);
break;
}
case FMT_BGR24: {
strcpy(&name3[0], "_" STRINGIZE(FMT_BGR24));
pixelformat = V4L2_PIX_FMT_BGR24;
mask3 |= (0x03 << 4);
mask3 |= (0x03 << 5);
mask3 |= 0x0100;
break;
}
case FMT_BGR32: {
strcpy(&name3[0], "_" STRINGIZE(FMT_BGR32));
pixelformat = V4L2_PIX_FMT_BGR32;
mask3 |= (0x04 << 4);
mask3 |= (0x04 << 5);
mask3 |= 0x0100;
break;
}
@ -363,13 +560,8 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) {
}
case FIELD_INTERLACED: {
strcpy(&name4[0], "-i");
field = V4L2_FIELD_INTERLACED;
break;
}
case FIELD_ALTERNATE: {
strcpy(&name4[0], "-a");
mask4 |= 0x1000;
field = V4L2_FIELD_ALTERNATE;
field = V4L2_FIELD_INTERLACED;
break;
}
default: