Commit 302df970 authored by Andy Walls's avatar Andy Walls Committed by Mauro Carvalho Chehab

V4L/DVB (10439): cx18: Clean-up and enable sliced VBI handling

Removed legacy ivtv state variables, added comments, and cleaned
up sliced VBI related code.  Enabled sliced VBI.
Signed-off-by: default avatarAndy Walls <awalls@radix.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 4325dff2
...@@ -169,9 +169,14 @@ static void cx18_av_initialize(struct cx18 *cx) ...@@ -169,9 +169,14 @@ static void cx18_av_initialize(struct cx18 *cx)
/* Set VGA_TRACK_RANGE to 0x20 */ /* Set VGA_TRACK_RANGE to 0x20 */
cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000); cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
/* Enable VBI capture */ /*
cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F); * Initial VBI setup
/* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */ * 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,
* programmed IDID, RP code V bit transition on VBLANK, data during
* blanking intervals
*/
cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010252e);
/* 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 */
......
...@@ -24,6 +24,52 @@ ...@@ -24,6 +24,52 @@
#include "cx18-driver.h" #include "cx18-driver.h"
/*
* For sliced VBI output, we set up to use VIP-1.1, 10-bit mode,
* NN counts 4 bytes Dwords, an IDID of 0x00 0x80 or one with the VBI line #.
* Thus, according to the VIP-2 Spec, our VBI ancillary data lines
* (should!) look like:
* 4 byte EAV code: 0xff 0x00 0x00 0xRP
* unknown number of possible idle bytes
* 3 byte Anc data preamble: 0x00 0xff 0xff
* 1 byte data identifier: ne010iii (parity bits, 010, DID bits)
* 1 byte secondary data id: nessssss (parity bits, SDID bits)
* 1 byte data word count: necccccc (parity bits, NN Dword count)
* 2 byte Internal DID: 0x00 0x80 (programmed value)
* 4*NN data bytes
* 1 byte checksum
* Fill bytes needed to fil out to 4*NN bytes of payload
*
* The RP codes for EAVs when in VIP-1.1 mode, not in raw mode, &
* in the vertical blanking interval are:
* 0xb0 (Task 0 VerticalBlank HorizontalBlank 0 0 0 0)
* 0xf0 (Task EvenField VerticalBlank HorizontalBlank 0 0 0 0)
*
* Since the V bit is only allowed to toggle in the EAV RP code, just
* before the first active region line and for active lines, they are:
* 0x90 (Task 0 0 HorizontalBlank 0 0 0 0)
* 0xd0 (Task EvenField 0 HorizontalBlank 0 0 0 0)
*
* The user application DID bytes we care about are:
* 0x91 (1 0 010 0 !ActiveLine AncDataPresent)
* 0x55 (0 1 010 2ndField !ActiveLine AncDataPresent)
*
*/
static const u8 sliced_vbi_did[2] = { 0x91, 0x55 };
struct vbi_anc_data {
/* u8 eav[4]; */
/* u8 idle[]; Variable number of idle bytes */
u8 preamble[3];
u8 did;
u8 sdid;
u8 data_count;
u8 idid[2];
u8 payload[1]; /* 4*data_count of payload */
/* u8 checksum; */
/* u8 fill[]; Variable number of fill bytes */
};
static int odd_parity(u8 c) static int odd_parity(u8 c)
{ {
c ^= (c >> 4); c ^= (c >> 4);
...@@ -96,7 +142,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg) ...@@ -96,7 +142,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
0, V4L2_SLICED_WSS_625, 0, /* 4 */ 0, V4L2_SLICED_WSS_625, 0, /* 4 */
V4L2_SLICED_CAPTION_525, /* 6 */ V4L2_SLICED_CAPTION_525, /* 6 */
0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 - unlike cx25840 */
0, 0, 0, 0 0, 0, 0, 0
}; };
int is_pal = !(state->std & V4L2_STD_525_60); int is_pal = !(state->std & V4L2_STD_525_60);
...@@ -220,47 +266,53 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg) ...@@ -220,47 +266,53 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
case VIDIOC_INT_DECODE_VBI_LINE: case VIDIOC_INT_DECODE_VBI_LINE:
{ {
struct v4l2_decode_vbi_line *vbi = arg; struct v4l2_decode_vbi_line *vbi = arg;
u8 *p = vbi->p; u8 *p;
int id1, id2, l, err = 0; struct vbi_anc_data *anc = (struct vbi_anc_data *) vbi->p;
int did, sdid, l, err = 0;
if (p[0] || p[1] != 0xff || p[2] != 0xff ||
(p[3] != 0x55 && p[3] != 0x91)) { /*
* Check for the ancillary data header for sliced VBI
*/
if (anc->preamble[0] ||
anc->preamble[1] != 0xff || anc->preamble[2] != 0xff ||
(anc->did != sliced_vbi_did[0] &&
anc->did != sliced_vbi_did[1])) {
vbi->line = vbi->type = 0; vbi->line = vbi->type = 0;
break; break;
} }
p += 4; did = anc->did;
id1 = p[-1]; sdid = anc->sdid & 0xf;
id2 = p[0] & 0xf; l = anc->idid[0] & 0x3f;
l = p[2] & 0x3f;
l += state->vbi_line_offset; l += state->vbi_line_offset;
p += 4; p = anc->payload;
switch (id2) { /* Decode the SDID set by the slicer */
switch (sdid) {
case 1: case 1:
id2 = V4L2_SLICED_TELETEXT_B; sdid = V4L2_SLICED_TELETEXT_B;
break; break;
case 4: case 4:
id2 = V4L2_SLICED_WSS_625; sdid = V4L2_SLICED_WSS_625;
break; break;
case 6: case 6:
id2 = V4L2_SLICED_CAPTION_525; sdid = V4L2_SLICED_CAPTION_525;
err = !odd_parity(p[0]) || !odd_parity(p[1]); err = !odd_parity(p[0]) || !odd_parity(p[1]);
break; break;
case 9: case 7: /* Differs from cx25840 */
id2 = V4L2_SLICED_VPS; sdid = V4L2_SLICED_VPS;
if (decode_vps(p, p) != 0) if (decode_vps(p, p) != 0)
err = 1; err = 1;
break; break;
default: default:
id2 = 0; sdid = 0;
err = 1; err = 1;
break; break;
} }
vbi->type = err ? 0 : id2; vbi->type = err ? 0 : sdid;
vbi->line = err ? 0 : l; vbi->line = err ? 0 : l;
vbi->is_second_field = err ? 0 : (id1 == 0x55); vbi->is_second_field = err ? 0 : (did == sliced_vbi_did[1]);
vbi->p = p; vbi->p = p;
break; break;
} }
......
...@@ -51,7 +51,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = { ...@@ -51,7 +51,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
static const struct cx18_card cx18_card_hvr1600_esmt = { static const struct cx18_card cx18_card_hvr1600_esmt = {
.type = CX18_CARD_HVR_1600_ESMT, .type = CX18_CARD_HVR_1600_ESMT,
.name = "Hauppauge HVR-1600", .name = "Hauppauge HVR-1600",
.comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .comment = "Simultaneous Digital and Analog TV capture supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER, .v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418, .hw_audio_ctrl = CX18_HW_CX23418,
.hw_muxer = CX18_HW_CS5345, .hw_muxer = CX18_HW_CS5345,
...@@ -97,7 +97,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = { ...@@ -97,7 +97,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
static const struct cx18_card cx18_card_hvr1600_samsung = { static const struct cx18_card cx18_card_hvr1600_samsung = {
.type = CX18_CARD_HVR_1600_SAMSUNG, .type = CX18_CARD_HVR_1600_SAMSUNG,
.name = "Hauppauge HVR-1600 (Preproduction)", .name = "Hauppauge HVR-1600 (Preproduction)",
.comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .comment = "Simultaneous Digital and Analog TV capture supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER, .v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418, .hw_audio_ctrl = CX18_HW_CX23418,
.hw_muxer = CX18_HW_CS5345, .hw_muxer = CX18_HW_CS5345,
...@@ -152,7 +152,7 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = { ...@@ -152,7 +152,7 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = {
static const struct cx18_card cx18_card_h900 = { static const struct cx18_card cx18_card_h900 = {
.type = CX18_CARD_COMPRO_H900, .type = CX18_CARD_COMPRO_H900,
.name = "Compro VideoMate H900", .name = "Compro VideoMate H900",
.comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .comment = "Analog TV capture supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER, .v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418, .hw_audio_ctrl = CX18_HW_CX23418,
.hw_all = CX18_HW_TUNER, .hw_all = CX18_HW_TUNER,
...@@ -249,7 +249,7 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = { ...@@ -249,7 +249,7 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
static const struct cx18_card cx18_card_cnxt_raptor_pal = { static const struct cx18_card cx18_card_cnxt_raptor_pal = {
.type = CX18_CARD_CNXT_RAPTOR_PAL, .type = CX18_CARD_CNXT_RAPTOR_PAL,
.name = "Conexant Raptor PAL/SECAM", .name = "Conexant Raptor PAL/SECAM",
.comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .comment = "Analog TV capture supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER, .v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418, .hw_audio_ctrl = CX18_HW_CX23418,
.hw_muxer = CX18_HW_GPIO, .hw_muxer = CX18_HW_GPIO,
......
...@@ -49,8 +49,7 @@ ...@@ -49,8 +49,7 @@
/* V4L2 capability aliases */ /* V4L2 capability aliases */
#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ #define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
V4L2_CAP_VBI_CAPTURE) V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)
/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
struct cx18_card_video_input { struct cx18_card_video_input {
u8 video_type; /* video input type */ u8 video_type; /* video input type */
......
...@@ -178,8 +178,8 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt ...@@ -178,8 +178,8 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
int i; int i;
for (i = 0; i < CX18_VBI_FRAMES; i++) { for (i = 0; i < CX18_VBI_FRAMES; i++) {
/* Yuck, hardcoded. Needs to be a define */ cx->vbi.sliced_mpeg_data[i] =
cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL);
if (cx->vbi.sliced_mpeg_data[i] == NULL) { if (cx->vbi.sliced_mpeg_data[i] == NULL) {
while (--i >= 0) { while (--i >= 0) {
kfree(cx->vbi.sliced_mpeg_data[i]); kfree(cx->vbi.sliced_mpeg_data[i]);
......
...@@ -586,7 +586,8 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) ...@@ -586,7 +586,8 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
(cx->params.video_temporal_filter_mode << 1) | (cx->params.video_temporal_filter_mode << 1) |
(cx->params.video_median_filter_type << 2); (cx->params.video_median_filter_type << 2);
cx->params.port = CX2341X_PORT_MEMORY; cx->params.port = CX2341X_PORT_MEMORY;
cx->params.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_AC3; cx->params.capabilities =
CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_AC3 | CX2341X_CAP_HAS_SLICED_VBI;
init_waitqueue_head(&cx->cap_w); init_waitqueue_head(&cx->cap_w);
init_waitqueue_head(&cx->mb_apu_waitq); init_waitqueue_head(&cx->mb_apu_waitq);
init_waitqueue_head(&cx->mb_cpu_waitq); init_waitqueue_head(&cx->mb_cpu_waitq);
...@@ -596,49 +597,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) ...@@ -596,49 +597,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
/*
* The VBI line sizes depend on the pixel clock and the horiz rate
*
* (1/Fh)*(2*Fp) = Samples/line
* = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
*
* Sliced VBI is sent as ancillary data during horizontal blanking
* Raw VBI is sent as active video samples during vertcal blanking
*
* We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
* length of 720 pixels @ 4:2:2 sampling. Thus...
*
* For systems that use a 15.734 kHz horizontal rate, such as
* NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
*
* (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
* 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
*
* For systems that use a 15.625 kHz horizontal rate, such as
* PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
*
* (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
* 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
*
*/
/* FIXME: init these based on tuner std & modify when std changes */
/* CX18-AV-Core number of VBI samples output per horizontal line */
cx->vbi.raw_decoder_line_size = 1444; /* 4 byte SAV + 2 * 720 */
cx->vbi.sliced_decoder_line_size = 272; /* 60 Hz: 268+4, 50 Hz: 280+4 */
/* CX18-AV-Core VBI samples/line possibly rounded up */
cx->vbi.raw_size = 1444; /* Real max size is 1444 */
cx->vbi.sliced_size = 284; /* Real max size is 284 */
/*
* CX18-AV-Core SAV/EAV RP codes in VIP 1.x mode
* Task Field VerticalBlank HorizontalBlank 0 0 0 0
*/
cx->vbi.raw_decoder_sav_odd_field = 0x20; /* V */
cx->vbi.raw_decoder_sav_even_field = 0x60; /* FV */
cx->vbi.sliced_decoder_sav_odd_field = 0xB0; /* T VH - actually EAV */
cx->vbi.sliced_decoder_sav_even_field = 0xF0; /* TFVH - actually EAV */
return 0; return 0;
} }
...@@ -671,7 +629,6 @@ static void __devinit cx18_init_struct2(struct cx18 *cx) ...@@ -671,7 +629,6 @@ 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;
/* FIXME - 8 is NTSC value, investigate */
cx->av_state.vbi_line_offset = 8; cx->av_state.vbi_line_offset = 8;
} }
...@@ -936,7 +893,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, ...@@ -936,7 +893,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
* suboptimal, as the CVBS and SVideo inputs could use a different std * suboptimal, as the CVBS and SVideo inputs could use a different std
* and the buffer could end up being too small in that case. * and the buffer could end up being too small in that case.
*/ */
vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2; vbi_buf_size = vbi_active_samples * (cx->is_60hz ? 24 : 36) / 2;
cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0) if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0)
......
...@@ -319,59 +319,121 @@ struct cx18_open_id { ...@@ -319,59 +319,121 @@ struct cx18_open_id {
/* forward declaration of struct defined in cx18-cards.h */ /* forward declaration of struct defined in cx18-cards.h */
struct cx18_card; struct cx18_card;
/*
* A note about "sliced" VBI data as implemented in this driver:
*
* Currently we collect the sliced VBI in the form of Ancillary Data
* packets, inserted by the AV core decoder/digitizer/slicer in the
* horizontal blanking region of the VBI lines, in "raw" mode as far as
* the Encoder is concerned. We don't ever tell the Encoder itself
* to provide sliced VBI. (AV Core: sliced mode - Encoder: raw mode)
*
* We then process the ancillary data ourselves to send the sliced data
* to the user application directly or build up MPEG-2 private stream 1
* packets to splice into (only!) MPEG-2 PS streams for the user app.
*
* (That's how ivtv essentially does it.)
*
* The Encoder should be able to extract certain sliced VBI data for
* us and provide it in a separate stream or splice it into any type of
* MPEG PS or TS stream, but this isn't implemented yet.
*/
/*
* Number of "raw" VBI samples per horizontal line we tell the Encoder to
* grab from the decoder/digitizer/slicer output for raw or sliced VBI.
* It depends on the pixel clock and the horiz rate:
*
* (1/Fh)*(2*Fp) = Samples/line
* = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
*
* Sliced VBI data is sent as ancillary data during horizontal blanking
* Raw VBI is sent as active video samples during vertcal blanking
*
* We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
* length of 720 pixels @ 4:2:2 sampling. Thus...
*
* For systems that use a 15.734 kHz horizontal rate, such as
* NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
*
* (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
* 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
*
* For systems that use a 15.625 kHz horizontal rate, such as
* PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
*
* (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
* 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
*/
static const u32 vbi_active_samples = 1444; /* 4 byte SAV + 720 Y + 720 U/V */
static const u32 vbi_hblank_samples_60Hz = 272; /* 4 byte EAV + 268 anc/fill */
static const u32 vbi_hblank_samples_50Hz = 284; /* 4 byte EAV + 280 anc/fill */
#define CX18_VBI_FRAMES 32 #define CX18_VBI_FRAMES 32
/* VBI data */
struct vbi_info { struct vbi_info {
u32 enc_size; /* Current state of v4l2 VBI settings for this device */
u32 frame;
u8 cc_data_odd[256];
u8 cc_data_even[256];
int cc_pos;
u8 cc_no_update;
u8 vps[5];
u8 vps_found;
int wss;
u8 wss_found;
u8 wss_no_update;
u32 raw_decoder_line_size;
u8 raw_decoder_sav_odd_field;
u8 raw_decoder_sav_even_field;
u32 sliced_decoder_line_size;
u8 sliced_decoder_sav_odd_field;
u8 sliced_decoder_sav_even_field;
struct v4l2_format in; struct v4l2_format in;
/* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; /* pointer to in.fmt.sliced */
struct v4l2_sliced_vbi_format *sliced_in; u32 count; /* Count of VBI data lines: 60 Hz: 12 or 50 Hz: 18 */
u32 service_set_in; u32 start[2]; /* First VBI data line per field: 10 & 273 or 6 & 318 */
int insert_mpeg;
/* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. u32 frame; /* Count of VBI buffers/frames received from Encoder */
One for /dev/vbi0 and one for /dev/vbi8 */
struct v4l2_sliced_vbi_data sliced_data[36];
/* Buffer for VBI data inserted into MPEG stream. /*
The first byte is a dummy byte that's never used. * Vars for creation and insertion of MPEG Private Stream 1 packets
The next 16 bytes contain the MPEG header for the VBI data, * of sliced VBI data into an MPEG PS
the remainder is the actual VBI data. */
The max size accepted by the MPEG VBI reinsertion turns out
to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
a single line header byte and 2 * 18 is the number of VBI lines per frame.
However, it seems that the data must be 1K aligned, so we have to /* Boolean: create and insert Private Stream 1 packets into the PS */
pad the data until the 1 or 2 K boundary. int insert_mpeg;
/*
* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
* Used in cx18-vbi.c only for collecting sliced data, and as a source
* during conversion of sliced VBI data into MPEG Priv Stream 1 packets.
* We don't need to save state here, but the array may have been a bit
* too big (2304 bytes) to alloc from the stack.
*/
struct v4l2_sliced_vbi_data sliced_data[36];
This pointer array will allocate 2049 bytes to store each VBI frame. */ /*
* A ring buffer of driver-generated MPEG-2 PS
* Program Pack/Private Stream 1 packets for sliced VBI data insertion
* into the MPEG PS stream.
*
* In each sliced_mpeg_data[] buffer is:
* 16 byte MPEG-2 PS Program Pack Header
* 16 byte MPEG-2 Private Stream 1 PES Header
* 4 byte magic number: "itv0" or "ITV0"
* 4 byte first field line mask, if "itv0"
* 4 byte second field line mask, if "itv0"
* 36 lines, if "ITV0"; or <36 lines, if "itv0"; of sliced VBI data
*
* Each line in the payload is
* 1 byte line header derived from the SDID (WSS, CC, VPS, etc.)
* 42 bytes of line data
*
* That's a maximum 1552 bytes of payload in the Private Stream 1 packet
* which is the payload size a PVR-350 (CX23415) MPEG decoder will
* accept for VBI data. So, including the headers, it's a maximum 1584
* bytes total.
*/
#define CX18_SLICED_MPEG_DATA_MAXSZ 1584
/* copy_vbi_buf() needs 8 temp bytes on the end for the worst case */
#define CX18_SLICED_MPEG_DATA_BUFSZ (CX18_SLICED_MPEG_DATA_MAXSZ+8)
u8 *sliced_mpeg_data[CX18_VBI_FRAMES]; u8 *sliced_mpeg_data[CX18_VBI_FRAMES];
u32 sliced_mpeg_size[CX18_VBI_FRAMES]; u32 sliced_mpeg_size[CX18_VBI_FRAMES];
struct cx18_buffer sliced_mpeg_buf;
/* Count of Program Pack/Program Stream 1 packets inserted into PS */
u32 inserted_frame; u32 inserted_frame;
u32 start[2], count; /*
u32 raw_size; * A dummy driver stream transfer buffer with a copy of the next
u32 sliced_size; * sliced_mpeg_data[] buffer for output to userland apps.
* Only used in cx18-fileops.c, but its state needs to persist at times.
*/
struct cx18_buffer sliced_mpeg_buf;
}; };
/* Per cx23418, per I2C bus private algo callback data */ /* Per cx23418, per I2C bus private algo callback data */
......
...@@ -176,6 +176,8 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, ...@@ -176,6 +176,8 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
*err = 0; *err = 0;
while (1) { while (1) {
if (s->type == CX18_ENC_STREAM_TYPE_MPG) { if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
/* Process pending program info updates and pending
VBI data */
if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) { if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
cx->dualwatch_jiffies = jiffies; cx->dualwatch_jiffies = jiffies;
...@@ -260,6 +262,20 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s, ...@@ -260,6 +262,20 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
len = ucount; len = ucount;
if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
!cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) { !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {
/*
* Try to find a good splice point in the PS, just before
* an MPEG-2 Program Pack start code, and provide only
* up to that point to the user, so it's easy to insert VBI data
* the next time around.
*/
/* FIXME - This only works for an MPEG-2 PS, not a TS */
/*
* An MPEG-2 Program Stream (PS) is a series of
* MPEG-2 Program Packs terminated by an
* MPEG Program End Code after the last Program Pack.
* A Program Pack may hold a PS System Header packet and any
* number of Program Elementary Stream (PES) Packets
*/
const char *start = buf->buf + buf->readpos; const char *start = buf->buf + buf->readpos;
const char *p = start + 1; const char *p = start + 1;
const u8 *q; const u8 *q;
...@@ -267,38 +283,54 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s, ...@@ -267,38 +283,54 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
int stuffing, i; int stuffing, i;
while (start + len > p) { while (start + len > p) {
/* Scan for a 0 to find a potential MPEG-2 start code */
q = memchr(p, 0, start + len - p); q = memchr(p, 0, start + len - p);
if (q == NULL) if (q == NULL)
break; break;
p = q + 1; p = q + 1;
/*
* Keep looking if not a
* MPEG-2 Pack header start code: 0x00 0x00 0x01 0xba
* or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0
*/
if ((char *)q + 15 >= buf->buf + buf->bytesused || if ((char *)q + 15 >= buf->buf + buf->bytesused ||
q[1] != 0 || q[2] != 1 || q[3] != ch) q[1] != 0 || q[2] != 1 || q[3] != ch)
continue; continue;
/* If expecting the primary video PES */
if (!cx->search_pack_header) { if (!cx->search_pack_header) {
/* Continue if it couldn't be a PES packet */
if ((q[6] & 0xc0) != 0x80) if ((q[6] & 0xc0) != 0x80)
continue; continue;
if (((q[7] & 0xc0) == 0x80 && /* Check if a PTS or PTS & DTS follow */
(q[9] & 0xf0) == 0x20) || if (((q[7] & 0xc0) == 0x80 && /* PTS only */
((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x20) || /* PTS only */
(q[9] & 0xf0) == 0x30)) { ((q[7] & 0xc0) == 0xc0 && /* PTS & DTS */
ch = 0xba; (q[9] & 0xf0) == 0x30)) { /* DTS follows */
/* Assume we found the video PES hdr */
ch = 0xba; /* next want a Program Pack*/
cx->search_pack_header = 1; cx->search_pack_header = 1;
p = q + 9; p = q + 9; /* Skip this video PES hdr */
} }
continue; continue;
} }
/* We may have found a Program Pack start code */
/* Get the count of stuffing bytes & verify them */
stuffing = q[13] & 7; stuffing = q[13] & 7;
/* all stuffing bytes must be 0xff */ /* all stuffing bytes must be 0xff */
for (i = 0; i < stuffing; i++) for (i = 0; i < stuffing; i++)
if (q[14 + i] != 0xff) if (q[14 + i] != 0xff)
break; break;
if (i == stuffing && if (i == stuffing && /* right number of stuffing bytes*/
(q[4] & 0xc4) == 0x44 && (q[4] & 0xc4) == 0x44 && /* marker check */
(q[12] & 3) == 3 && (q[12] & 3) == 3 && /* marker check */
q[14 + stuffing] == 0 && q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */
q[15 + stuffing] == 0 && q[15 + stuffing] == 0 &&
q[16 + stuffing] == 1) { q[16 + stuffing] == 1) {
cx->search_pack_header = 0; /* We declare we actually found a Program Pack*/
cx->search_pack_header = 0; /* expect vid PES */
len = (char *)q - start; len = (char *)q - start;
cx18_setup_sliced_vbi_buf(cx); cx18_setup_sliced_vbi_buf(cx);
break; break;
......
...@@ -102,6 +102,19 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) ...@@ -102,6 +102,19 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
} }
} }
static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
{
int f, l;
u16 set = 0;
for (f = 0; f < 2; f++) {
for (l = 0; l < 24; l++) {
fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
set |= fmt->service_lines[f][l];
}
}
return set != 0;
}
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
{ {
...@@ -150,7 +163,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, ...@@ -150,7 +163,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
vbifmt->sampling_rate = 27000000; vbifmt->sampling_rate = 27000000;
vbifmt->offset = 248; vbifmt->offset = 248;
vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4; vbifmt->samples_per_line = vbi_active_samples - 4;
vbifmt->sample_format = V4L2_PIX_FMT_GREY; vbifmt->sample_format = V4L2_PIX_FMT_GREY;
vbifmt->start[0] = cx->vbi.start[0]; vbifmt->start[0] = cx->vbi.start[0];
vbifmt->start[1] = cx->vbi.start[1]; vbifmt->start[1] = cx->vbi.start[1];
...@@ -164,7 +177,17 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, ...@@ -164,7 +177,17 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
struct v4l2_format *fmt) struct v4l2_format *fmt)
{ {
return -EINVAL; struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
vbifmt->reserved[0] = 0;
vbifmt->reserved[1] = 0;
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
vbifmt->service_set = cx18_get_service_set(vbifmt);
return 0;
} }
static int cx18_try_fmt_vid_cap(struct file *file, void *fh, static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
...@@ -194,7 +217,18 @@ static int cx18_try_fmt_vbi_cap(struct file *file, void *fh, ...@@ -194,7 +217,18 @@ static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
struct v4l2_format *fmt) struct v4l2_format *fmt)
{ {
return -EINVAL; struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
vbifmt->reserved[0] = 0;
vbifmt->reserved[1] = 0;
if (vbifmt->service_set)
cx18_expand_service_set(vbifmt, cx->is_50hz);
check_service_set(vbifmt, cx->is_50hz);
vbifmt->service_set = cx18_get_service_set(vbifmt);
return 0;
} }
static int cx18_s_fmt_vid_cap(struct file *file, void *fh, static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
...@@ -250,7 +284,28 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, ...@@ -250,7 +284,28 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
struct v4l2_format *fmt) struct v4l2_format *fmt)
{ {
return -EINVAL; struct cx18_open_id *id = fh;
struct cx18 *cx = id->cx;
int ret;
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
ret = v4l2_prio_check(&cx->prio, &id->prio);
if (ret)
return ret;
ret = cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
if (ret)
return ret;
if (check_service_set(vbifmt, cx->is_50hz) == 0)
return -EINVAL;
if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
return 0;
} }
static int cx18_g_chip_ident(struct file *file, void *fh, static int cx18_g_chip_ident(struct file *file, void *fh,
...@@ -548,7 +603,6 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) ...@@ -548,7 +603,6 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
cx->vbi.count = cx->is_50hz ? 18 : 12; cx->vbi.count = cx->is_50hz ? 18 : 12;
cx->vbi.start[0] = cx->is_50hz ? 6 : 10; cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
cx->vbi.start[1] = cx->is_50hz ? 318 : 273; cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
CX18_DEBUG_INFO("Switching standard to %llx.\n", CX18_DEBUG_INFO("Switching standard to %llx.\n",
(unsigned long long) cx->std); (unsigned long long) cx->std);
...@@ -599,6 +653,19 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) ...@@ -599,6 +653,19 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
struct v4l2_sliced_vbi_cap *cap) struct v4l2_sliced_vbi_cap *cap)
{ {
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
int f, l;
if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
for (f = 0; f < 2; f++) {
for (l = 0; l < 24; l++) {
if (valid_service_line(f, l, cx->is_50hz))
cap->service_lines[f][l] = set;
}
}
return 0;
}
return -EINVAL; return -EINVAL;
} }
......
...@@ -349,10 +349,6 @@ static void cx18_vbi_setup(struct cx18_stream *s) ...@@ -349,10 +349,6 @@ static void cx18_vbi_setup(struct cx18_stream *s)
/* setup VBI registers */ /* setup VBI registers */
cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
/* determine number of lines and total number of VBI bytes.
A raw line takes 1444 bytes: 4 byte SAV code + 2 * 720
A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
header, 42 data bytes + checksum (to be confirmed) */
if (raw) { if (raw) {
lines = cx->vbi.count * 2; lines = cx->vbi.count * 2;
} else { } else {
...@@ -361,24 +357,53 @@ static void cx18_vbi_setup(struct cx18_stream *s) ...@@ -361,24 +357,53 @@ static void cx18_vbi_setup(struct cx18_stream *s)
lines += 2; lines += 2;
} }
cx->vbi.enc_size = lines *
(raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
data[0] = s->handle; data[0] = s->handle;
/* Lines per field */ /* Lines per field */
data[1] = (lines / 2) | ((lines / 2) << 16); data[1] = (lines / 2) | ((lines / 2) << 16);
/* bytes per line */ /* bytes per line */
data[2] = (raw ? cx->vbi.raw_decoder_line_size data[2] = (raw ? vbi_active_samples
: cx->vbi.sliced_decoder_line_size); : (cx->is_60hz ? vbi_hblank_samples_60Hz
: vbi_hblank_samples_50Hz));
/* Every X number of frames a VBI interrupt arrives /* Every X number of frames a VBI interrupt arrives
(frames as in 25 or 30 fps) */ (frames as in 25 or 30 fps) */
data[3] = 1; data[3] = 1;
/* Setup VBI for the cx25840 digitizer */ /*
* Set the SAV/EAV RP codes to look for as start/stop points
* when in VIP-1.1 mode
*/
if (raw) { if (raw) {
/*
* Start codes for beginning of "active" line in vertical blank
* 0x20 ( VerticalBlank )
* 0x60 ( EvenField VerticalBlank )
*/
data[4] = 0x20602060; data[4] = 0x20602060;
/*
* End codes for end of "active" raw lines and regular lines
* 0x30 ( VerticalBlank HorizontalBlank)
* 0x70 ( EvenField VerticalBlank HorizontalBlank)
* 0x90 (Task HorizontalBlank)
* 0xd0 (Task EvenField HorizontalBlank)
*/
data[5] = 0x307090d0; data[5] = 0x307090d0;
} else { } else {
/*
* End codes for active video, we want data in the hblank region
* 0xb0 (Task 0 VerticalBlank HorizontalBlank)
* 0xf0 (Task EvenField VerticalBlank HorizontalBlank)
*
* Since the V bit is only allowed to toggle in the EAV RP code,
* just before the first active region line, these two
* are problematic and we have to ignore them:
* 0x90 (Task HorizontalBlank)
* 0xd0 (Task EvenField HorizontalBlank)
*/
data[4] = 0xB0F0B0F0; data[4] = 0xB0F0B0F0;
/*
* Start codes for beginning of active line in vertical blank
* 0xa0 (Task VerticalBlank )
* 0xe0 (Task EvenField VerticalBlank )
*/
data[5] = 0xA0E0A0E0; data[5] = 0xA0E0A0E0;
} }
......
...@@ -27,6 +27,16 @@ ...@@ -27,6 +27,16 @@
#include "cx18-queue.h" #include "cx18-queue.h"
#include "cx18-av-core.h" #include "cx18-av-core.h"
/*
* Raster Reference/Protection (RP) bytes, used in Start/End Active
* Video codes emitted from the digitzer in VIP 1.x mode, that flag the start
* of VBI sample or VBI ancilliary data regions in the digitial ratser line.
*
* Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0
*/
static const u8 raw_vbi_sav_rp[2] = { 0x20, 0x60 }; /* __V_, _FV_ */
static const u8 sliced_vbi_eav_rp[2] = { 0xb0, 0xf0 }; /* T_VH, TFVH */
static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
{ {
int line = 0; int line = 0;
...@@ -34,10 +44,17 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) ...@@ -34,10 +44,17 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
u32 linemask[2] = { 0, 0 }; u32 linemask[2] = { 0, 0 };
unsigned short size; unsigned short size;
static const u8 mpeg_hdr_data[] = { static const u8 mpeg_hdr_data[] = {
0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66, /* MPEG-2 Program Pack */
0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x01, 0xba, /* Prog Pack start code */
0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80, 0x44, 0x00, 0x0c, 0x66, 0x24, 0x01, /* SCR, SCR Ext, markers */
0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff 0x01, 0xd1, 0xd3, /* Mux Rate, markers */
0xfa, 0xff, 0xff, /* Res, Suff cnt, Stuff */
/* MPEG-2 Private Stream 1 PES Packet */
0x00, 0x00, 0x01, 0xbd, /* Priv Stream 1 start */
0x00, 0x1a, /* length */
0x84, 0x80, 0x07, /* flags, hdr data len */
0x21, 0x00, 0x5d, 0x63, 0xa7, /* PTS, markers */
0xff, 0xff /* stuffing */
}; };
const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */
int idx = cx->vbi.frame % CX18_VBI_FRAMES; int idx = cx->vbi.frame % CX18_VBI_FRAMES;
...@@ -71,7 +88,7 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) ...@@ -71,7 +88,7 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
memcpy(dst + sd + 4, dst + sd + 12, line * 43); memcpy(dst + sd + 4, dst + sd + 12, line * 43);
size = 4 + ((43 * line + 3) & ~3); size = 4 + ((43 * line + 3) & ~3);
} else { } else {
memcpy(dst + sd, "cx0", 4); memcpy(dst + sd, "itv0", 4);
memcpy(dst + sd + 4, &linemask[0], 8); memcpy(dst + sd + 4, &linemask[0], 8);
size = 12 + ((43 * line + 3) & ~3); size = 12 + ((43 * line + 3) & ~3);
} }
...@@ -90,10 +107,10 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) ...@@ -90,10 +107,10 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
Returns new compressed size. */ Returns new compressed size. */
static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size) static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
{ {
u32 line_size = cx->vbi.raw_decoder_line_size; u32 line_size = vbi_active_samples;
u32 lines = cx->vbi.count; u32 lines = cx->vbi.count;
u8 sav1 = cx->vbi.raw_decoder_sav_odd_field; u8 sav1 = raw_vbi_sav_rp[0];
u8 sav2 = cx->vbi.raw_decoder_sav_even_field; u8 sav2 = raw_vbi_sav_rp[1];
u8 *q = buf; u8 *q = buf;
u8 *p; u8 *p;
int i; int i;
...@@ -115,15 +132,16 @@ static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size) ...@@ -115,15 +132,16 @@ static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
/* Compressed VBI format, all found sliced blocks put next to one another /* Compressed VBI format, all found sliced blocks put next to one another
Returns new compressed size */ Returns new compressed size */
static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf, static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
u32 size, u8 sav) u32 size, u8 eav)
{ {
u32 line_size = cx->vbi.sliced_decoder_line_size;
struct v4l2_decode_vbi_line vbi; struct v4l2_decode_vbi_line vbi;
int i; int i;
u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz
: vbi_hblank_samples_50Hz;
/* find the first valid line */ /* find the first valid line */
for (i = 0; i < size; i++, buf++) { for (i = 0; i < size; i++, buf++) {
if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == eav)
break; break;
} }
...@@ -133,8 +151,8 @@ static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf, ...@@ -133,8 +151,8 @@ static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
for (i = 0; i < size / line_size; i++) { for (i = 0; i < size / line_size; i++) {
u8 *p = buf + i * line_size; u8 *p = buf + i * line_size;
/* Look for SAV code */ /* Look for EAV code */
if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) if (p[0] != 0xff || p[1] || p[2] || p[3] != eav)
continue; continue;
vbi.p = p + 4; vbi.p = p + 4;
cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi); cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
...@@ -159,6 +177,12 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, ...@@ -159,6 +177,12 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
if (streamtype != CX18_ENC_STREAM_TYPE_VBI) if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
return; return;
/*
* Note the CX23418 provides a 12 byte header, in it's raw VBI
* buffers to us, that we currently throw away:
* 0x3fffffff [4 bytes of something] [4 byte timestamp]
*/
/* Raw VBI data */ /* Raw VBI data */
if (cx18_raw_vbi(cx)) { if (cx18_raw_vbi(cx)) {
u8 type; u8 type;
...@@ -173,7 +197,7 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, ...@@ -173,7 +197,7 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
size = buf->bytesused = compress_raw_buf(cx, p, size); size = buf->bytesused = compress_raw_buf(cx, p, size);
/* second field of the frame? */ /* second field of the frame? */
if (type == cx->vbi.raw_decoder_sav_even_field) { if (type == raw_vbi_sav_rp[1]) {
/* Dirty hack needed for backwards /* Dirty hack needed for backwards
compatibility of old VBI software. */ compatibility of old VBI software. */
p += size - 4; p += size - 4;
...@@ -187,14 +211,14 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, ...@@ -187,14 +211,14 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
cx18_buf_swap(buf); cx18_buf_swap(buf);
/* first field */ /* first field */
lines = compress_sliced_buf(cx, 0, p, size / 2, /* compress_sliced_buf() will skip the 12 bytes of header */
cx->vbi.sliced_decoder_sav_odd_field); lines = compress_sliced_buf(cx, 0, p, size / 2, sliced_vbi_eav_rp[0]);
/* second field */ /* second field */
/* experimentation shows that the second half does not always /* experimentation shows that the second half does not always
begin at the exact address. So start a bit earlier begin at the exact address. So start a bit earlier
(hence 32). */ (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, cx->vbi.sliced_decoder_sav_even_field); size / 2 + 32, sliced_vbi_eav_rp[1]);
/* always return at least one empty line */ /* always return at least one empty line */
if (lines == 0) { if (lines == 0) {
cx->vbi.sliced_data[0].id = 0; cx->vbi.sliced_data[0].id = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment