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:
Родитель
13071f0a58
Коммит
e5bd0260e7
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче