V4L/DVB (10446): cx18: Finally get sliced VBI working - for 525 line 60 Hz systems at least
Sliced VBI, in the manner that ivtv implements it as a separate data stream, now works for 525 line 60 Hz systems like NTSC-M. It may work for 625 line 50 Hz systems, but I have more engineering work to do, to verify it is operating properly. Sliced data insertion into the MPEG PS should be working, but is untested. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Родитель
466df46484
Коммит
812b1f9d54
|
@ -172,11 +172,11 @@ static void cx18_av_initialize(struct cx18 *cx)
|
||||||
/*
|
/*
|
||||||
* Initial VBI setup
|
* Initial VBI setup
|
||||||
* VIP-1.1, 10 bit mode, enable Raw, disable sliced,
|
* VIP-1.1, 10 bit mode, enable Raw, disable sliced,
|
||||||
* don't clamp raw samples when codes are in use, 4 byte user D-words,
|
* don't clamp raw samples when codes are in use, 1 byte user D-words,
|
||||||
* programmed IDID, RP code V bit transition on VBLANK, data during
|
* IDID0 has line #, RP code V bit transition on VBLANK, data during
|
||||||
* blanking intervals
|
* blanking intervals
|
||||||
*/
|
*/
|
||||||
cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010252e);
|
cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4013252e);
|
||||||
|
|
||||||
/* Set the video input.
|
/* Set the video input.
|
||||||
The setting in MODE_CTRL gets lost when we do the above setup */
|
The setting in MODE_CTRL gets lost when we do the above setup */
|
||||||
|
@ -218,6 +218,7 @@ void cx18_av_std_setup(struct cx18 *cx)
|
||||||
cx18_av_write(cx, 0x49f, 0x14);
|
cx18_av_write(cx, 0x49f, 0x14);
|
||||||
|
|
||||||
if (std & V4L2_STD_625_50) {
|
if (std & V4L2_STD_625_50) {
|
||||||
|
/* FIXME - revisit these for Sliced VBI */
|
||||||
hblank = 132;
|
hblank = 132;
|
||||||
hactive = 720;
|
hactive = 720;
|
||||||
burst = 93;
|
burst = 93;
|
||||||
|
@ -241,13 +242,34 @@ void cx18_av_std_setup(struct cx18 *cx)
|
||||||
sc = 672351;
|
sc = 672351;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
|
* The following relationships of half line counts should hold:
|
||||||
|
* 525 = vsync + vactive + vblank656
|
||||||
|
* 12 = vblank656 - vblank
|
||||||
|
*
|
||||||
|
* vsync: always 6 half-lines of vsync pulses
|
||||||
|
* vactive: half lines of active video
|
||||||
|
* vblank656: half lines, after line 3, of blanked video
|
||||||
|
* vblank: half lines, after line 9, of blanked video
|
||||||
|
*
|
||||||
|
* vblank656 starts counting from the falling edge of the first
|
||||||
|
* vsync pulse (start of line 4)
|
||||||
|
* vblank starts counting from the after the 6 vsync pulses and
|
||||||
|
* 6 equalization pulses (start of line 10)
|
||||||
|
*
|
||||||
|
* For 525 line systems the driver will extract VBI information
|
||||||
|
* from lines 10 through 21. To avoid the EAV RP code from
|
||||||
|
* toggling at the start of hblank at line 22, where sliced VBI
|
||||||
|
* data from line 21 is stuffed, also treat line 22 as blanked.
|
||||||
|
*/
|
||||||
|
vblank656 = 38; /* lines 4 through 22 */
|
||||||
|
vblank = 26; /* lines 10 through 22 */
|
||||||
|
vactive = 481; /* lines 23 through 262.5 */
|
||||||
|
|
||||||
hactive = 720;
|
hactive = 720;
|
||||||
hblank = 122;
|
hblank = 122;
|
||||||
vactive = 487;
|
|
||||||
luma_lpf = 1;
|
luma_lpf = 1;
|
||||||
uv_lpf = 1;
|
uv_lpf = 1;
|
||||||
vblank = 26;
|
|
||||||
vblank656 = 26;
|
|
||||||
|
|
||||||
src_decimation = 0x21f;
|
src_decimation = 0x21f;
|
||||||
if (std == V4L2_STD_PAL_60) {
|
if (std == V4L2_STD_PAL_60) {
|
||||||
|
@ -330,14 +352,14 @@ void cx18_av_std_setup(struct cx18 *cx)
|
||||||
cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
|
cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
|
||||||
cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
|
cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
|
||||||
|
|
||||||
/* Sets VBI parameters */
|
|
||||||
if (std & V4L2_STD_625_50) {
|
if (std & V4L2_STD_625_50) {
|
||||||
cx18_av_write(cx, 0x47f, 0x01);
|
state->slicer_line_delay = 1;
|
||||||
state->vbi_line_offset = 5;
|
state->slicer_line_offset = (6 + state->slicer_line_delay - 2);
|
||||||
} else {
|
} else {
|
||||||
cx18_av_write(cx, 0x47f, 0x00);
|
state->slicer_line_delay = 0;
|
||||||
state->vbi_line_offset = 8;
|
state->slicer_line_offset = (10 + state->slicer_line_delay - 2);
|
||||||
}
|
}
|
||||||
|
cx18_av_write(cx, 0x47f, state->slicer_line_delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
|
@ -79,11 +79,28 @@ struct cx18_av_state {
|
||||||
enum cx18_av_audio_input aud_input;
|
enum cx18_av_audio_input aud_input;
|
||||||
u32 audclk_freq;
|
u32 audclk_freq;
|
||||||
int audmode;
|
int audmode;
|
||||||
int vbi_line_offset;
|
|
||||||
int default_volume;
|
int default_volume;
|
||||||
u32 id;
|
u32 id;
|
||||||
u32 rev;
|
u32 rev;
|
||||||
int is_initialized;
|
int is_initialized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The VBI slicer starts operating and counting lines, begining at
|
||||||
|
* slicer line count of 1, at D lines after the deassertion of VRESET
|
||||||
|
* This staring field line, S, is 6 or 10 for 625 or 525 line systems.
|
||||||
|
* Sliced ancillary data captured on VBI slicer line M is sent at the
|
||||||
|
* beginning of the next VBI slicer line, VBI slicer line count N = M+1.
|
||||||
|
* Thus when the VBI slicer reports a VBI slicer line number with
|
||||||
|
* ancillary data, the IDID0 byte indicates VBI slicer line N.
|
||||||
|
* The actual field line that the captured data comes from is
|
||||||
|
* L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2).
|
||||||
|
*
|
||||||
|
* D is the slicer_line_delay value programmed into register 0x47f.
|
||||||
|
* (S+D-2) is the slicer_line_offset used to convert slicer reported
|
||||||
|
* line counts to actual field lines.
|
||||||
|
*/
|
||||||
|
int slicer_line_delay;
|
||||||
|
int slicer_line_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,6 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||||
case VIDIOC_S_FMT:
|
case VIDIOC_S_FMT:
|
||||||
{
|
{
|
||||||
int is_pal = !(state->std & V4L2_STD_525_60);
|
int is_pal = !(state->std & V4L2_STD_525_60);
|
||||||
int vbi_offset = is_pal ? 1 : 0;
|
|
||||||
int i, x;
|
int i, x;
|
||||||
u8 lcr[24];
|
u8 lcr[24];
|
||||||
|
|
||||||
|
@ -199,7 +198,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||||
cx18_av_std_setup(cx);
|
cx18_av_std_setup(cx);
|
||||||
|
|
||||||
/* VBI Offset */
|
/* VBI Offset */
|
||||||
cx18_av_write(cx, 0x47f, vbi_offset);
|
cx18_av_write(cx, 0x47f, state->slicer_line_delay);
|
||||||
cx18_av_write(cx, 0x404, 0x2e);
|
cx18_av_write(cx, 0x404, 0x2e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -213,7 +212,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||||
/* Sliced VBI */
|
/* Sliced VBI */
|
||||||
cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
|
cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
|
||||||
cx18_av_write(cx, 0x406, 0x13);
|
cx18_av_write(cx, 0x406, 0x13);
|
||||||
cx18_av_write(cx, 0x47f, vbi_offset);
|
cx18_av_write(cx, 0x47f, state->slicer_line_delay);
|
||||||
|
|
||||||
/* Force impossible lines to 0 */
|
/* Force impossible lines to 0 */
|
||||||
if (is_pal) {
|
if (is_pal) {
|
||||||
|
@ -261,7 +260,8 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
cx18_av_write(cx, 0x43c, 0x16);
|
cx18_av_write(cx, 0x43c, 0x16);
|
||||||
cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22);
|
/* FIXME - should match vblank set in cx18_av_std_setup() */
|
||||||
|
cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||||
did = anc->did;
|
did = anc->did;
|
||||||
sdid = anc->sdid & 0xf;
|
sdid = anc->sdid & 0xf;
|
||||||
l = anc->idid[0] & 0x3f;
|
l = anc->idid[0] & 0x3f;
|
||||||
l += state->vbi_line_offset;
|
l += state->slicer_line_offset;
|
||||||
p = anc->payload;
|
p = anc->payload;
|
||||||
|
|
||||||
/* Decode the SDID set by the slicer */
|
/* Decode the SDID set by the slicer */
|
||||||
|
|
|
@ -633,7 +633,9 @@ static void __devinit cx18_init_struct2(struct cx18 *cx)
|
||||||
cx->av_state.aud_input = CX18_AV_AUDIO8;
|
cx->av_state.aud_input = CX18_AV_AUDIO8;
|
||||||
cx->av_state.audclk_freq = 48000;
|
cx->av_state.audclk_freq = 48000;
|
||||||
cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
|
cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
|
||||||
cx->av_state.vbi_line_offset = 8;
|
cx->av_state.slicer_line_delay = 0;
|
||||||
|
cx->av_state.slicer_line_offset =
|
||||||
|
(10 + cx->av_state.slicer_line_delay - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
|
static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
|
||||||
|
|
|
@ -360,9 +360,16 @@ static void cx18_vbi_setup(struct cx18_stream *s)
|
||||||
if (raw) {
|
if (raw) {
|
||||||
lines = cx->vbi.count * 2;
|
lines = cx->vbi.count * 2;
|
||||||
} else {
|
} else {
|
||||||
lines = cx->is_60hz ? 24 : 38;
|
/*
|
||||||
if (cx->is_60hz)
|
* For 525/60 systems, according to the VIP 2 & BT.656 std:
|
||||||
lines += 2;
|
* The EAV RP code's Field bit toggles on line 4, a few lines
|
||||||
|
* after the Vertcal Blank bit has already toggled.
|
||||||
|
* Tell the encoder to capture 21-4+1=18 lines per field,
|
||||||
|
* since we want lines 10 through 21.
|
||||||
|
*
|
||||||
|
* FIXME - revisit for 625/50 systems
|
||||||
|
*/
|
||||||
|
lines = cx->is_60hz ? (21 - 4 + 1) * 2 : 38;
|
||||||
}
|
}
|
||||||
|
|
||||||
data[0] = s->handle;
|
data[0] = s->handle;
|
||||||
|
@ -402,9 +409,13 @@ static void cx18_vbi_setup(struct cx18_stream *s)
|
||||||
*
|
*
|
||||||
* Since the V bit is only allowed to toggle in the EAV RP code,
|
* Since the V bit is only allowed to toggle in the EAV RP code,
|
||||||
* just before the first active region line, these two
|
* just before the first active region line, these two
|
||||||
* are problematic and we have to ignore them:
|
* are problematic:
|
||||||
* 0x90 (Task HorizontalBlank)
|
* 0x90 (Task HorizontalBlank)
|
||||||
* 0xd0 (Task EvenField HorizontalBlank)
|
* 0xd0 (Task EvenField HorizontalBlank)
|
||||||
|
*
|
||||||
|
* We have set the digitzer to consider the first active line
|
||||||
|
* as part of VerticalBlank as well so we don't have to look for
|
||||||
|
* these problem codes nor lose the last line of sliced data.
|
||||||
*/
|
*/
|
||||||
data[4] = 0xB0F0B0F0;
|
data[4] = 0xB0F0B0F0;
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -221,13 +221,22 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
|
||||||
|
|
||||||
pts = (be32_to_cpu(q[0] == 0x3fffffff)) ? be32_to_cpu(q[2]) : 0;
|
pts = (be32_to_cpu(q[0] == 0x3fffffff)) ? be32_to_cpu(q[2]) : 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For calls to compress_sliced_buf(), ensure there are an integral
|
||||||
|
* number of lines by shifting the real data up over the 12 bytes header
|
||||||
|
* that got stuffed in.
|
||||||
|
* FIXME - there's a smarter way to do this with pointers, but for some
|
||||||
|
* reason I can't get it to work correctly right now.
|
||||||
|
*/
|
||||||
|
memcpy(p, &buf->buf[12], size-12);
|
||||||
|
|
||||||
/* first field */
|
/* first field */
|
||||||
/* compress_sliced_buf() will skip the 12 bytes of header */
|
|
||||||
lines = compress_sliced_buf(cx, 0, p, size / 2, sliced_vbi_eav_rp[0]);
|
lines = compress_sliced_buf(cx, 0, p, size / 2, sliced_vbi_eav_rp[0]);
|
||||||
/* second field */
|
/*
|
||||||
/* experimentation shows that the second half does not always
|
* second field
|
||||||
begin at the exact address. So start a bit earlier
|
* In case the second half does not always begin at the exact address,
|
||||||
(hence 32). */
|
* start a bit earlier (hence 32).
|
||||||
|
*/
|
||||||
lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
|
lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
|
||||||
size / 2 + 32, sliced_vbi_eav_rp[1]);
|
size / 2 + 32, sliced_vbi_eav_rp[1]);
|
||||||
/* always return at least one empty line */
|
/* always return at least one empty line */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче