V4L/DVB (5077): Bttv cropping support

Adds the missing VIDIOC_CROPCAP, G_CROP and S_CROP ioctls, permitting 
applications to capture or overlay a subsection of the picture or to 
extend the capture window beyond active video, into the VBI area and the 
horizontal blanking. VBI capturing can start and end on any line, 
including the picture area, and apps can capture different lines of each 
field and single fields.
For compatibility with existing applications, the open() function
resets the cropping and VBI capturing parameters and a VIDIOC_S_CROP
call is necessary to actually enable cropping. 
Regrettably in PAL-M, PAL-N, PAL-Nc and NTSC-JP mode the maximum image 
width will increase from 640 and 768 to 747 and 923 pixels respectively.
Like the VBI changes however, this should only affect applications which 
depend on former driver limitations, such as never getting more than 640 
pixels regardless of the requested width. 
Also, new freedoms require additional checks for conflicts and some 
applications may not expect an EBUSY error from the VIDIOC_QBUF and 
VIDIOCMCAPTURE ioctls. These errors should be rare though.
So far, the patch has been tested on a UP machine with a bt878 in PAL-
BGHI and NTSC-M mode using xawtv, tvtime, mplayer/mencoder, zapping/
libzvbi and these tools: http://zapping.sf.net/bttv-crop-test.tar.bz2
I'd be grateful about comments or bug reports.

Signed-off-by: Michael H. Schimek <mschimek@gmx.at>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
Michael Schimek 2007-01-18 16:17:39 -03:00 committed by Mauro Carvalho Chehab
parent 13071f0a58
commit e5bd0260e7
4 changed files with 1278 additions and 238 deletions

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,8 @@ int
bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int offset, unsigned int bpl,
unsigned int padding, unsigned int lines)
unsigned int padding, unsigned int skip_lines,
unsigned int store_lines)
{
u32 instructions,line,todo;
struct scatterlist *sg;
@ -54,9 +55,11 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
one write per scan line + sync + jump (all 2 dwords). padding
can cause next bpl to start close to a page border. First DMA
region may be smaller than PAGE_SIZE */
instructions = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
instructions = skip_lines * 4;
instructions += (1 + ((bpl + padding) * store_lines)
/ PAGE_SIZE + store_lines) * 8;
instructions += 2 * 8;
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
return rc;
/* sync instruction */
@ -64,11 +67,16 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(rp++) = cpu_to_le32(0);
while (skip_lines-- > 0) {
*(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
BT848_RISC_EOL | bpl);
}
/* scan lines */
sg = sglist;
for (line = 0; line < lines; line++) {
for (line = 0; line < store_lines; line++) {
if ((btv->opt_vcr_hack) &&
(line >= (lines - VCR_HACK_LINES)))
(line >= (store_lines - VCR_HACK_LINES)))
continue;
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
@ -130,7 +138,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
/* estimate risc mem: worst case is one write per page border +
one write per scan line (5 dwords)
plus sync + jump (2 dwords) */
instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
instructions = ((3 + (ybpl + ypadding) * ylines * 2)
/ PAGE_SIZE) + ylines;
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
return rc;
@ -317,10 +326,10 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
/* ---------------------------------------------------------- */
static void
bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
int width, int height, int interleaved, int norm)
bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
int width, int height, int interleaved,
const struct bttv_tvnorm *tvnorm)
{
const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
u32 xsf, sr;
int vdelay;
@ -360,6 +369,62 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
}
}
static void
bttv_calc_geo (struct bttv * btv,
struct bttv_geometry * geo,
unsigned int width,
unsigned int height,
int both_fields,
const struct bttv_tvnorm * tvnorm,
const struct v4l2_rect * crop)
{
unsigned int c_width;
unsigned int c_height;
u32 sr;
if ((crop->left == tvnorm->cropcap.defrect.left
&& crop->top == tvnorm->cropcap.defrect.top
&& crop->width == tvnorm->cropcap.defrect.width
&& crop->height == tvnorm->cropcap.defrect.height
&& width <= tvnorm->swidth /* see PAL-Nc et al */)
|| bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
bttv_calc_geo_old(btv, geo, width, height,
both_fields, tvnorm);
return;
}
/* For bug compatibility the image size checks permit scale
factors > 16. See bttv_crop_calc_limits(). */
c_width = min((unsigned int) crop->width, width * 16);
c_height = min((unsigned int) crop->height, height * 16);
geo->width = width;
geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
/* Even to store Cb first, odd for Cr. */
geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
geo->sheight = c_height;
geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
sr = c_height >> !both_fields;
sr = (sr * 512U + (height >> 1)) / height - 512;
geo->vscale = (0x10000UL - sr) & 0x1fff;
geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
geo->vtotal = tvnorm->vtotal;
geo->crop = (((geo->width >> 8) & 0x03) |
((geo->hdelay >> 6) & 0x0c) |
((geo->sheight >> 4) & 0x30) |
((geo->vdelay >> 2) & 0xc0));
if (btv->opt_combfilter) {
geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
geo->comb = (width < 769) ? 1 : 0;
} else {
geo->vtc = 0;
geo->comb = 0;
}
}
static void
bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
{
@ -522,16 +587,51 @@ int
bttv_buffer_activate_vbi(struct bttv *btv,
struct bttv_buffer *vbi)
{
/* vbi capture */
struct btcx_riscmem *top;
struct btcx_riscmem *bottom;
int top_irq_flags;
int bottom_irq_flags;
top = NULL;
bottom = NULL;
top_irq_flags = 0;
bottom_irq_flags = 0;
if (vbi) {
unsigned int crop, vdelay;
vbi->vb.state = STATE_ACTIVE;
list_del(&vbi->vb.queue);
bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
} else {
bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
/* VDELAY is start of video, end of VBI capturing. */
crop = btread(BT848_E_CROP);
vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
if (vbi->geo.vdelay > vdelay) {
vdelay = vbi->geo.vdelay & 0xfe;
crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
btwrite(vdelay, BT848_E_VDELAY_LO);
btwrite(crop, BT848_E_CROP);
btwrite(vdelay, BT848_O_VDELAY_LO);
btwrite(crop, BT848_O_CROP);
}
if (vbi->vbi_count[0] > 0) {
top = &vbi->top;
top_irq_flags = 4;
}
if (vbi->vbi_count[1] > 0) {
top_irq_flags = 0;
bottom = &vbi->bottom;
bottom_irq_flags = 4;
}
}
bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
return 0;
}
@ -611,28 +711,31 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
int bpf = bpl * (buf->vb.height >> 1);
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
V4L2_FIELD_HAS_BOTH(buf->vb.field),
tvnorm,&buf->crop);
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
0,bpl,0,buf->vb.height);
/* offset */ 0,bpl,
/* padding */ 0,/* skip_lines */ 0,
buf->vb.height);
break;
case V4L2_FIELD_BOTTOM:
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
0,bpl,0,buf->vb.height);
0,bpl,0,0,buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
0,bpl,bpl,buf->vb.height >> 1);
0,bpl,bpl,0,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
bpl,bpl,bpl,buf->vb.height >> 1);
bpl,bpl,bpl,0,buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
0,bpl,0,buf->vb.height >> 1);
0,bpl,0,0,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
bpf,bpl,0,buf->vb.height >> 1);
bpf,bpl,0,0,buf->vb.height >> 1);
break;
default:
BUG();
@ -662,7 +765,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,0,buf->tvnorm);
buf->vb.height,/* both_fields */ 0,
tvnorm,&buf->crop);
bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
@ -670,7 +774,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_BOTTOM:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,0,buf->tvnorm);
buf->vb.height,0,
tvnorm,&buf->crop);
bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
@ -678,7 +783,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_INTERLACED:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,1,buf->tvnorm);
buf->vb.height,1,
tvnorm,&buf->crop);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
@ -700,7 +806,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_SEQ_TB:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,1,buf->tvnorm);
buf->vb.height,1,
tvnorm,&buf->crop);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
@ -731,11 +838,12 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
/* build risc code */
buf->vb.field = V4L2_FIELD_SEQ_TB;
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
1,buf->tvnorm);
1,tvnorm,&buf->crop);
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
0, RAW_BPL, 0, RAW_LINES);
/* offset */ 0, RAW_BPL, /* padding */ 0,
/* skip_lines */ 0, RAW_LINES);
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
}
/* copy format info */
@ -761,7 +869,8 @@ bttv_overlay_risc(struct bttv *btv,
/* calculate geometry */
bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
V4L2_FIELD_HAS_BOTH(ov->field),
&bttv_tvnorms[ov->tvnorm],&buf->crop);
/* build risc code */
switch (ov->field) {

View File

@ -5,6 +5,9 @@
(c) 2002 Gerd Knorr <kraxel@bytesex.org>
Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
Sponsored by OPQ Systems AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@ -41,8 +44,15 @@
to be about 244. */
#define VBI_OFFSET 244
/* 2048 for compatibility with earlier driver versions. The driver
really stores 1024 + tvnorm->vbipack * 4 samples per line in the
buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI
is 0x1FF DWORDs) and VBI read()s store a frame counter in the last
four bytes of the VBI image. */
#define VBI_BPL 2048
/* Compatibility. */
#define VBI_DEFLINES 16
#define VBI_MAXLINES 32
static unsigned int vbibufs = 4;
static unsigned int vbi_debug = 0;
@ -58,21 +68,12 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
#define dprintk(fmt, arg...) if (vbi_debug) \
printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg)
#define IMAGE_SIZE(fmt) \
(((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line)
/* ----------------------------------------------------------------------- */
/* vbi risc code + mm */
static int
vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines)
{
int bpl = 2048;
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
0, bpl-4, 4, lines);
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
lines * bpl, bpl-4, 4, lines);
return 0;
}
static int vbi_buffer_setup(struct videobuf_queue *q,
unsigned int *count, unsigned int *size)
{
@ -81,8 +82,16 @@ static int vbi_buffer_setup(struct videobuf_queue *q,
if (0 == *count)
*count = vbibufs;
*size = fh->lines * 2 * 2048;
dprintk("setup: lines=%d\n",fh->lines);
*size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
fh->vbi_fmt.fmt.samples_per_line,
fh->vbi_fmt.fmt.start[0],
fh->vbi_fmt.fmt.start[1],
fh->vbi_fmt.fmt.count[0],
fh->vbi_fmt.fmt.count[1]);
return 0;
}
@ -93,18 +102,93 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
struct bttv_fh *fh = q->priv_data;
struct bttv *btv = fh->btv;
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
const struct bttv_tvnorm *tvnorm;
unsigned int skip_lines0, skip_lines1, min_vdelay;
int redo_dma_risc;
int rc;
buf->vb.size = fh->lines * 2 * 2048;
buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
tvnorm = fh->vbi_fmt.tvnorm;
/* There's no VBI_VDELAY register, RISC must skip the lines
we don't want. With default parameters we skip zero lines
as earlier driver versions did. The driver permits video
standard changes while capturing, so we use vbi_fmt.tvnorm
instead of btv->tvnorm to skip zero lines after video
standard changes as well. */
skip_lines0 = 0;
skip_lines1 = 0;
if (fh->vbi_fmt.fmt.count[0] > 0)
skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
- tvnorm->vbistart[0]));
if (fh->vbi_fmt.fmt.count[1] > 0)
skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
- tvnorm->vbistart[1]));
redo_dma_risc = 0;
if (buf->vbi_skip[0] != skip_lines0 ||
buf->vbi_skip[1] != skip_lines1 ||
buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
buf->vbi_skip[0] = skip_lines0;
buf->vbi_skip[1] = skip_lines1;
buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
redo_dma_risc = 1;
}
if (STATE_NEEDS_INIT == buf->vb.state) {
redo_dma_risc = 1;
if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
goto fail;
if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
goto fail;
}
if (redo_dma_risc) {
unsigned int bpl, padding, offset;
bpl = 2044; /* max. vbipack */
padding = VBI_BPL - bpl;
if (fh->vbi_fmt.fmt.count[0] > 0) {
rc = bttv_risc_packed(btv, &buf->top,
buf->vb.dma.sglist,
/* offset */ 0, bpl,
padding, skip_lines0,
fh->vbi_fmt.fmt.count[0]);
if (0 != rc)
goto fail;
}
if (fh->vbi_fmt.fmt.count[1] > 0) {
offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
rc = bttv_risc_packed(btv, &buf->bottom,
buf->vb.dma.sglist,
offset, bpl,
padding, skip_lines1,
fh->vbi_fmt.fmt.count[1]);
if (0 != rc)
goto fail;
}
}
/* VBI capturing ends at VDELAY, start of video capturing,
no matter where the RISC program ends. VDELAY minimum is 2,
bounds.top is the corresponding first field line number
times two. VDELAY counts half field lines. */
min_vdelay = MIN_VDELAY;
if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;
/* For bttv_buffer_activate_vbi(). */
buf->geo.vdelay = min_vdelay;
buf->vb.state = STATE_PREPARED;
buf->vb.field = field;
dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
@ -152,69 +236,215 @@ struct videobuf_queue_ops bttv_vbi_qops = {
/* ----------------------------------------------------------------------- */
void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
static int
try_fmt (struct v4l2_vbi_format * f,
const struct bttv_tvnorm * tvnorm,
__s32 crop_start)
{
int vdelay;
__s32 min_start, max_start, max_end, f2_offset;
unsigned int i;
if (lines < 1)
lines = 1;
if (lines > VBI_MAXLINES)
lines = VBI_MAXLINES;
fh->lines = lines;
/* For compatibility with earlier driver versions we must pretend
the VBI and video capture window may overlap. In reality RISC
magic aborts VBI capturing at the first line of video capturing,
leaving the rest of the buffer unchanged, usually all zero.
VBI capturing must always start before video capturing. >> 1
because cropping counts field lines times two. */
min_start = tvnorm->vbistart[0];
max_start = (crop_start >> 1) - 1;
max_end = (tvnorm->cropcap.bounds.top
+ tvnorm->cropcap.bounds.height) >> 1;
vdelay = btread(BT848_E_VDELAY_LO);
if (vdelay < lines*2) {
vdelay = lines*2;
btwrite(vdelay,BT848_E_VDELAY_LO);
btwrite(vdelay,BT848_O_VDELAY_LO);
if (min_start > max_start)
return -EBUSY;
BUG_ON(max_start >= max_end);
f->sampling_rate = tvnorm->Fsc;
f->samples_per_line = VBI_BPL;
f->sample_format = V4L2_PIX_FMT_GREY;
f->offset = VBI_OFFSET;
f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0];
for (i = 0; i < 2; ++i) {
if (0 == f->count[i]) {
/* No data from this field. We leave f->start[i]
alone because VIDIOCSVBIFMT is w/o and EINVALs
when a driver does not support exactly the
requested parameters. */
} else {
s64 start, count;
start = clamp(f->start[i], min_start, max_start);
/* s64 to prevent overflow. */
count = (s64) f->start[i] + f->count[i] - start;
f->start[i] = start;
f->count[i] = clamp(count, (s64) 1,
max_end - start);
}
min_start += f2_offset;
max_start += f2_offset;
max_end += f2_offset;
}
if (0 == (f->count[0] | f->count[1])) {
/* As in earlier driver versions. */
f->start[0] = tvnorm->vbistart[0];
f->start[1] = tvnorm->vbistart[1];
f->count[0] = 1;
f->count[1] = 1;
}
f->flags = 0;
f->reserved[0] = 0;
f->reserved[1] = 0;
return 0;
}
int
bttv_vbi_try_fmt (struct bttv_fh * fh,
struct v4l2_vbi_format * f)
{
struct bttv *btv = fh->btv;
const struct bttv_tvnorm *tvnorm;
__s32 crop_start;
mutex_lock(&btv->lock);
tvnorm = &bttv_tvnorms[btv->tvnorm];
crop_start = btv->crop_start;
mutex_unlock(&btv->lock);
return try_fmt(f, tvnorm, crop_start);
}
int
bttv_vbi_set_fmt (struct bttv_fh * fh,
struct v4l2_vbi_format * f)
{
struct bttv *btv = fh->btv;
const struct bttv_tvnorm *tvnorm;
__s32 start1, end;
int rc;
mutex_lock(&btv->lock);
rc = -EBUSY;
if (fh->resources & RESOURCE_VBI)
goto fail;
tvnorm = &bttv_tvnorms[btv->tvnorm];
rc = try_fmt(f, tvnorm, btv->crop_start);
if (0 != rc)
goto fail;
start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
/* First possible line of video capturing. Should be
max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
when capturing both fields. But for compatibility we must
pretend the VBI and video capture window may overlap,
so end = start + 1, the lowest possible value, times two
because vbi_fmt.end counts field lines times two. */
end = max(f->start[0], start1) * 2 + 2;
mutex_lock(&fh->vbi.lock);
fh->vbi_fmt.fmt = *f;
fh->vbi_fmt.tvnorm = tvnorm;
fh->vbi_fmt.end = end;
mutex_unlock(&fh->vbi.lock);
rc = 0;
fail:
mutex_unlock(&btv->lock);
return rc;
}
void
bttv_vbi_get_fmt (struct bttv_fh * fh,
struct v4l2_vbi_format * f)
{
const struct bttv_tvnorm *tvnorm;
*f = fh->vbi_fmt.fmt;
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
if (tvnorm != fh->vbi_fmt.tvnorm) {
__s32 max_end;
unsigned int i;
/* As in vbi_buffer_prepare() this imitates the
behaviour of earlier driver versions after video
standard changes, with default parameters anyway. */
max_end = (tvnorm->cropcap.bounds.top
+ tvnorm->cropcap.bounds.height) >> 1;
f->sampling_rate = tvnorm->Fsc;
for (i = 0; i < 2; ++i) {
__s32 new_start;
new_start = f->start[i]
+ tvnorm->vbistart[i]
- fh->vbi_fmt.tvnorm->vbistart[i];
f->start[i] = min(new_start, max_end - 1);
f->count[i] = min((__s32) f->count[i],
max_end - f->start[i]);
max_end += tvnorm->vbistart[1]
- tvnorm->vbistart[0];
}
}
}
void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
void
bttv_vbi_fmt_reset (struct bttv_vbi_fmt * f,
int norm)
{
const struct bttv_tvnorm *tvnorm;
s64 count0,count1,count;
unsigned int real_samples_per_line;
unsigned int real_count;
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = tvnorm->Fsc;
f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = VBI_OFFSET;
f->fmt.vbi.flags = 0;
tvnorm = &bttv_tvnorms[norm];
/* s64 to prevent overflow. */
count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
- tvnorm->vbistart[0];
count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
- tvnorm->vbistart[1];
count = clamp (max (count0, count1), (s64) 1, (s64) VBI_MAXLINES);
f->fmt.sampling_rate = tvnorm->Fsc;
f->fmt.samples_per_line = VBI_BPL;
f->fmt.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.offset = VBI_OFFSET;
f->fmt.start[0] = tvnorm->vbistart[0];
f->fmt.start[1] = tvnorm->vbistart[1];
f->fmt.count[0] = VBI_DEFLINES;
f->fmt.count[1] = VBI_DEFLINES;
f->fmt.flags = 0;
f->fmt.reserved[0] = 0;
f->fmt.reserved[1] = 0;
f->fmt.vbi.start[0] = tvnorm->vbistart[0];
f->fmt.vbi.start[1] = tvnorm->vbistart[1];
f->fmt.vbi.count[0] = count;
f->fmt.vbi.count[1] = count;
/* For compatibility the buffer size must be 2 * VBI_DEFLINES *
VBI_BPL regardless of the current video standard. */
real_samples_per_line = 1024 + tvnorm->vbipack * 4;
real_count = ((tvnorm->cropcap.defrect.top >> 1)
- tvnorm->vbistart[0]);
f->fmt.vbi.reserved[0] = 0;
f->fmt.vbi.reserved[1] = 0;
}
BUG_ON(real_samples_per_line > VBI_BPL);
BUG_ON(real_count > VBI_DEFLINES);
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
{
const struct bttv_tvnorm *tvnorm;
f->tvnorm = tvnorm;
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
memset(f,0,sizeof(*f));
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = tvnorm->Fsc;
f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = VBI_OFFSET;
f->fmt.vbi.start[0] = tvnorm->vbistart[0];
f->fmt.vbi.start[1] = tvnorm->vbistart[1];
f->fmt.vbi.count[0] = fh->lines;
f->fmt.vbi.count[1] = fh->lines;
f->fmt.vbi.flags = 0;
/* See bttv_vbi_fmt_set(). */
f->end = tvnorm->vbistart[0] * 2 + 2;
}
/* ----------------------------------------------------------------------- */

View File

@ -26,7 +26,7 @@
#define _BTTVP_H_
#include <linux/version.h>
#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16)
#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17)
#include <linux/types.h>
#include <linux/wait.h>
@ -66,14 +66,22 @@
#define RISC_SLOT_LOOP 14
#define RESOURCE_OVERLAY 1
#define RESOURCE_VIDEO 2
#define RESOURCE_VIDEO_STREAM 2
#define RESOURCE_VBI 4
#define RESOURCE_VIDEO_READ 8
#define RAW_LINES 640
#define RAW_BPL 1024
#define UNSET (-1U)
/* Min. value in VDELAY register. */
#define MIN_VDELAY 2
/* Even to get Cb first, odd for Cr. */
#define MAX_HDELAY (0x3FF & -2)
/* Limits scaled width, which must be a multiple of 4. */
#define MAX_HACTIVE (0x3FF & -4)
#define clamp(x, low, high) min (max (low, x), high)
/* ---------------------------------------------------------- */
@ -92,8 +100,13 @@ struct bttv_tvnorm {
u16 vtotal;
int sram;
/* ITU-R frame line number of the first VBI line we can
capture, of the first and second field. */
capture, of the first and second field. The last possible line
is determined by cropcap.bounds. */
u16 vbistart[2];
/* Horizontally this counts fCLKx1 samples following the leading
edge of the horizontal sync pulse, vertically ITU-R frame line
numbers of the first field times two (2, 4, 6, ... 524 or 624). */
struct v4l2_cropcap cropcap;
};
extern const struct bttv_tvnorm bttv_tvnorms[];
@ -128,6 +141,9 @@ struct bttv_buffer {
struct bttv_geometry geo;
struct btcx_riscmem top;
struct btcx_riscmem bottom;
struct v4l2_rect crop;
unsigned int vbi_skip[2];
unsigned int vbi_count[2];
};
struct bttv_buffer_set {
@ -146,6 +162,34 @@ struct bttv_overlay {
int setup_ok;
};
struct bttv_vbi_fmt {
struct v4l2_vbi_format fmt;
/* fmt.start[] and count[] refer to this video standard. */
const struct bttv_tvnorm *tvnorm;
/* Earliest possible start of video capturing with this
v4l2_vbi_format, in struct bttv_crop.rect units. */
__s32 end;
};
/* bttv-vbi.c */
void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm);
struct bttv_crop {
/* A cropping rectangle in struct bttv_tvnorm.cropcap units. */
struct v4l2_rect rect;
/* Scaled image size limits with this crop rect. Divide
max_height, but not min_height, by two when capturing
single fields. See also bttv_crop_reset() and
bttv_crop_adjust() in bttv-driver.c. */
__s32 min_scaled_width;
__s32 min_scaled_height;
__s32 max_scaled_width;
__s32 max_scaled_height;
};
struct bttv_fh {
struct bttv *btv;
int resources;
@ -160,13 +204,19 @@ struct bttv_fh {
int width;
int height;
/* current settings */
/* video overlay */
const struct bttv_format *ovfmt;
struct bttv_overlay ov;
/* video overlay */
/* Application called VIDIOC_S_CROP. */
int do_crop;
/* vbi capture */
struct videobuf_queue vbi;
int lines;
/* Current VBI capture window as seen through this fh (cannot
be global for compatibility with earlier drivers). Protected
by struct bttv.lock and struct bttv_fh.vbi.lock. */
struct bttv_vbi_fmt vbi_fmt;
};
/* ---------------------------------------------------------- */
@ -176,7 +226,8 @@ struct bttv_fh {
int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int offset, unsigned int bpl,
unsigned int pitch, unsigned int lines);
unsigned int pitch, unsigned int skip_lines,
unsigned int store_lines);
/* control dma register + risc main loop */
void bttv_set_dma(struct bttv *btv, int override);
@ -202,9 +253,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
/* ---------------------------------------------------------- */
/* bttv-vbi.c */
void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f);
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f);
void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
extern struct videobuf_queue_ops bttv_vbi_qops;
@ -233,7 +284,6 @@ extern int fini_bttv_i2c(struct bttv *btv);
#define d2printk if (bttv_debug >= 2) printk
#define BTTV_MAX_FBUF 0x208000
#define VBIBUF_SIZE (2048*VBI_MAXLINES*2)
#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */
#define BTTV_FREE_IDLE (HZ) /* one second */
@ -314,7 +364,6 @@ struct bttv {
spinlock_t s_lock;
struct mutex lock;
int resources;
struct mutex reslock;
#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
#endif
@ -384,6 +433,21 @@ struct bttv {
unsigned int users;
struct bttv_fh init;
/* Default (0) and current (1) video capturing and overlay
cropping parameters in bttv_tvnorm.cropcap units. Protected
by bttv.lock. */
struct bttv_crop crop[2];
/* Earliest possible start of video capturing in
bttv_tvnorm.cropcap line units. Set by check_alloc_btres()
and free_btres(). Protected by bttv.lock. */
__s32 vbi_end;
/* Latest possible end of VBI capturing (= crop[x].rect.top when
VIDEO_RESOURCES are locked). Set by check_alloc_btres()
and free_btres(). Protected by bttv.lock. */
__s32 crop_start;
};
/* our devices */