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: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
4325dff220
commit
302df97021
@ -169,9 +169,14 @@ static void cx18_av_initialize(struct cx18 *cx)
|
||||
/* Set VGA_TRACK_RANGE to 0x20 */
|
||||
cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
|
||||
|
||||
/* Enable VBI capture */
|
||||
cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F);
|
||||
/* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */
|
||||
/*
|
||||
* Initial VBI setup
|
||||
* 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.
|
||||
The setting in MODE_CTRL gets lost when we do the above setup */
|
||||
|
@ -24,6 +24,52 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
c ^= (c >> 4);
|
||||
@ -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_WSS_625, 0, /* 4 */
|
||||
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
|
||||
};
|
||||
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)
|
||||
case VIDIOC_INT_DECODE_VBI_LINE:
|
||||
{
|
||||
struct v4l2_decode_vbi_line *vbi = arg;
|
||||
u8 *p = vbi->p;
|
||||
int id1, id2, l, err = 0;
|
||||
u8 *p;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
p += 4;
|
||||
id1 = p[-1];
|
||||
id2 = p[0] & 0xf;
|
||||
l = p[2] & 0x3f;
|
||||
did = anc->did;
|
||||
sdid = anc->sdid & 0xf;
|
||||
l = anc->idid[0] & 0x3f;
|
||||
l += state->vbi_line_offset;
|
||||
p += 4;
|
||||
p = anc->payload;
|
||||
|
||||
switch (id2) {
|
||||
/* Decode the SDID set by the slicer */
|
||||
switch (sdid) {
|
||||
case 1:
|
||||
id2 = V4L2_SLICED_TELETEXT_B;
|
||||
sdid = V4L2_SLICED_TELETEXT_B;
|
||||
break;
|
||||
case 4:
|
||||
id2 = V4L2_SLICED_WSS_625;
|
||||
sdid = V4L2_SLICED_WSS_625;
|
||||
break;
|
||||
case 6:
|
||||
id2 = V4L2_SLICED_CAPTION_525;
|
||||
sdid = V4L2_SLICED_CAPTION_525;
|
||||
err = !odd_parity(p[0]) || !odd_parity(p[1]);
|
||||
break;
|
||||
case 9:
|
||||
id2 = V4L2_SLICED_VPS;
|
||||
case 7: /* Differs from cx25840 */
|
||||
sdid = V4L2_SLICED_VPS;
|
||||
if (decode_vps(p, p) != 0)
|
||||
err = 1;
|
||||
break;
|
||||
default:
|
||||
id2 = 0;
|
||||
sdid = 0;
|
||||
err = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
vbi->type = err ? 0 : id2;
|
||||
vbi->type = err ? 0 : sdid;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
|
||||
static const struct cx18_card cx18_card_hvr1600_esmt = {
|
||||
.type = CX18_CARD_HVR_1600_ESMT,
|
||||
.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,
|
||||
.hw_audio_ctrl = CX18_HW_CX23418,
|
||||
.hw_muxer = CX18_HW_CS5345,
|
||||
@ -97,7 +97,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
|
||||
static const struct cx18_card cx18_card_hvr1600_samsung = {
|
||||
.type = CX18_CARD_HVR_1600_SAMSUNG,
|
||||
.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,
|
||||
.hw_audio_ctrl = CX18_HW_CX23418,
|
||||
.hw_muxer = CX18_HW_CS5345,
|
||||
@ -152,7 +152,7 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = {
|
||||
static const struct cx18_card cx18_card_h900 = {
|
||||
.type = CX18_CARD_COMPRO_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,
|
||||
.hw_audio_ctrl = CX18_HW_CX23418,
|
||||
.hw_all = CX18_HW_TUNER,
|
||||
@ -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 = {
|
||||
.type = CX18_CARD_CNXT_RAPTOR_PAL,
|
||||
.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,
|
||||
.hw_audio_ctrl = CX18_HW_CX23418,
|
||||
.hw_muxer = CX18_HW_GPIO,
|
||||
|
@ -49,8 +49,7 @@
|
||||
/* V4L2 capability aliases */
|
||||
#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
|
||||
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
|
||||
V4L2_CAP_VBI_CAPTURE)
|
||||
/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
|
||||
V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)
|
||||
|
||||
struct cx18_card_video_input {
|
||||
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
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CX18_VBI_FRAMES; i++) {
|
||||
/* Yuck, hardcoded. Needs to be a define */
|
||||
cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
|
||||
cx->vbi.sliced_mpeg_data[i] =
|
||||
kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL);
|
||||
if (cx->vbi.sliced_mpeg_data[i] == NULL) {
|
||||
while (--i >= 0) {
|
||||
kfree(cx->vbi.sliced_mpeg_data[i]);
|
||||
|
@ -586,7 +586,8 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
|
||||
(cx->params.video_temporal_filter_mode << 1) |
|
||||
(cx->params.video_median_filter_type << 2);
|
||||
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->mb_apu_waitq);
|
||||
init_waitqueue_head(&cx->mb_cpu_waitq);
|
||||
@ -596,49 +597,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
|
||||
cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -671,7 +629,6 @@ static void __devinit cx18_init_struct2(struct cx18 *cx)
|
||||
cx->av_state.aud_input = CX18_AV_AUDIO8;
|
||||
cx->av_state.audclk_freq = 48000;
|
||||
cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
|
||||
/* FIXME - 8 is NTSC value, investigate */
|
||||
cx->av_state.vbi_line_offset = 8;
|
||||
}
|
||||
|
||||
@ -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
|
||||
* 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;
|
||||
|
||||
if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0)
|
||||
|
@ -319,59 +319,121 @@ struct cx18_open_id {
|
||||
/* forward declaration of struct defined in cx18-cards.h */
|
||||
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
|
||||
|
||||
/* VBI data */
|
||||
struct vbi_info {
|
||||
u32 enc_size;
|
||||
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;
|
||||
/* Current state of v4l2 VBI settings for this device */
|
||||
struct v4l2_format in;
|
||||
/* convenience pointer to sliced struct in vbi_in union */
|
||||
struct v4l2_sliced_vbi_format *sliced_in;
|
||||
u32 service_set_in;
|
||||
struct v4l2_sliced_vbi_format *sliced_in; /* pointer to in.fmt.sliced */
|
||||
u32 count; /* Count of VBI data lines: 60 Hz: 12 or 50 Hz: 18 */
|
||||
u32 start[2]; /* First VBI data line per field: 10 & 273 or 6 & 318 */
|
||||
|
||||
u32 frame; /* Count of VBI buffers/frames received from Encoder */
|
||||
|
||||
/*
|
||||
* Vars for creation and insertion of MPEG Private Stream 1 packets
|
||||
* of sliced VBI data into an MPEG PS
|
||||
*/
|
||||
|
||||
/* Boolean: create and insert Private Stream 1 packets into the PS */
|
||||
int insert_mpeg;
|
||||
|
||||
/* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
|
||||
One for /dev/vbi0 and one for /dev/vbi8 */
|
||||
/*
|
||||
* 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];
|
||||
|
||||
/* Buffer for VBI data inserted into MPEG stream.
|
||||
The first byte is a dummy byte that's never used.
|
||||
The next 16 bytes contain the MPEG header for the VBI data,
|
||||
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
|
||||
pad the data until the 1 or 2 K boundary.
|
||||
|
||||
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];
|
||||
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 start[2], count;
|
||||
u32 raw_size;
|
||||
u32 sliced_size;
|
||||
/*
|
||||
* A dummy driver stream transfer buffer with a copy of the next
|
||||
* 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 */
|
||||
|
@ -176,6 +176,8 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
|
||||
*err = 0;
|
||||
while (1) {
|
||||
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))) {
|
||||
cx->dualwatch_jiffies = jiffies;
|
||||
@ -260,6 +262,20 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
|
||||
len = ucount;
|
||||
if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
|
||||
!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 *p = start + 1;
|
||||
const u8 *q;
|
||||
@ -267,38 +283,54 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
|
||||
int stuffing, i;
|
||||
|
||||
while (start + len > p) {
|
||||
/* Scan for a 0 to find a potential MPEG-2 start code */
|
||||
q = memchr(p, 0, start + len - p);
|
||||
if (q == NULL)
|
||||
break;
|
||||
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 ||
|
||||
q[1] != 0 || q[2] != 1 || q[3] != ch)
|
||||
continue;
|
||||
|
||||
/* If expecting the primary video PES */
|
||||
if (!cx->search_pack_header) {
|
||||
/* Continue if it couldn't be a PES packet */
|
||||
if ((q[6] & 0xc0) != 0x80)
|
||||
continue;
|
||||
if (((q[7] & 0xc0) == 0x80 &&
|
||||
(q[9] & 0xf0) == 0x20) ||
|
||||
((q[7] & 0xc0) == 0xc0 &&
|
||||
(q[9] & 0xf0) == 0x30)) {
|
||||
ch = 0xba;
|
||||
/* Check if a PTS or PTS & DTS follow */
|
||||
if (((q[7] & 0xc0) == 0x80 && /* PTS only */
|
||||
(q[9] & 0xf0) == 0x20) || /* PTS only */
|
||||
((q[7] & 0xc0) == 0xc0 && /* PTS & DTS */
|
||||
(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;
|
||||
p = q + 9;
|
||||
p = q + 9; /* Skip this video PES hdr */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We may have found a Program Pack start code */
|
||||
|
||||
/* Get the count of stuffing bytes & verify them */
|
||||
stuffing = q[13] & 7;
|
||||
/* all stuffing bytes must be 0xff */
|
||||
for (i = 0; i < stuffing; i++)
|
||||
if (q[14 + i] != 0xff)
|
||||
break;
|
||||
if (i == stuffing &&
|
||||
(q[4] & 0xc4) == 0x44 &&
|
||||
(q[12] & 3) == 3 &&
|
||||
q[14 + stuffing] == 0 &&
|
||||
if (i == stuffing && /* right number of stuffing bytes*/
|
||||
(q[4] & 0xc4) == 0x44 && /* marker check */
|
||||
(q[12] & 3) == 3 && /* marker check */
|
||||
q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */
|
||||
q[15 + stuffing] == 0 &&
|
||||
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;
|
||||
cx18_setup_sliced_vbi_buf(cx);
|
||||
break;
|
||||
|
@ -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)
|
||||
{
|
||||
@ -150,7 +163,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
|
||||
|
||||
vbifmt->sampling_rate = 27000000;
|
||||
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->start[0] = cx->vbi.start[0];
|
||||
vbifmt->start[1] = cx->vbi.start[1];
|
||||
@ -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,
|
||||
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,
|
||||
@ -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,
|
||||
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,
|
||||
@ -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,
|
||||
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,
|
||||
@ -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.start[0] = cx->is_50hz ? 6 : 10;
|
||||
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",
|
||||
(unsigned long long) cx->std);
|
||||
|
||||
@ -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,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -349,10 +349,6 @@ static void cx18_vbi_setup(struct cx18_stream *s)
|
||||
/* setup VBI registers */
|
||||
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) {
|
||||
lines = cx->vbi.count * 2;
|
||||
} else {
|
||||
@ -361,24 +357,53 @@ static void cx18_vbi_setup(struct cx18_stream *s)
|
||||
lines += 2;
|
||||
}
|
||||
|
||||
cx->vbi.enc_size = lines *
|
||||
(raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
|
||||
|
||||
data[0] = s->handle;
|
||||
/* Lines per field */
|
||||
data[1] = (lines / 2) | ((lines / 2) << 16);
|
||||
/* bytes per line */
|
||||
data[2] = (raw ? cx->vbi.raw_decoder_line_size
|
||||
: cx->vbi.sliced_decoder_line_size);
|
||||
data[2] = (raw ? vbi_active_samples
|
||||
: (cx->is_60hz ? vbi_hblank_samples_60Hz
|
||||
: vbi_hblank_samples_50Hz));
|
||||
/* Every X number of frames a VBI interrupt arrives
|
||||
(frames as in 25 or 30 fps) */
|
||||
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) {
|
||||
/*
|
||||
* Start codes for beginning of "active" line in vertical blank
|
||||
* 0x20 ( VerticalBlank )
|
||||
* 0x60 ( EvenField VerticalBlank )
|
||||
*/
|
||||
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;
|
||||
} 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;
|
||||
/*
|
||||
* Start codes for beginning of active line in vertical blank
|
||||
* 0xa0 (Task VerticalBlank )
|
||||
* 0xe0 (Task EvenField VerticalBlank )
|
||||
*/
|
||||
data[5] = 0xA0E0A0E0;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,16 @@
|
||||
#include "cx18-queue.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)
|
||||
{
|
||||
int line = 0;
|
||||
@ -34,10 +44,17 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
|
||||
u32 linemask[2] = { 0, 0 };
|
||||
unsigned short size;
|
||||
static const u8 mpeg_hdr_data[] = {
|
||||
0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
|
||||
0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
|
||||
0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
|
||||
0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
|
||||
/* MPEG-2 Program Pack */
|
||||
0x00, 0x00, 0x01, 0xba, /* Prog Pack start code */
|
||||
0x44, 0x00, 0x0c, 0x66, 0x24, 0x01, /* SCR, SCR Ext, markers */
|
||||
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 */
|
||||
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)
|
||||
memcpy(dst + sd + 4, dst + sd + 12, line * 43);
|
||||
size = 4 + ((43 * line + 3) & ~3);
|
||||
} else {
|
||||
memcpy(dst + sd, "cx0", 4);
|
||||
memcpy(dst + sd, "itv0", 4);
|
||||
memcpy(dst + sd + 4, &linemask[0], 8);
|
||||
size = 12 + ((43 * line + 3) & ~3);
|
||||
}
|
||||
@ -90,10 +107,10 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
|
||||
Returns new compressed 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;
|
||||
u8 sav1 = cx->vbi.raw_decoder_sav_odd_field;
|
||||
u8 sav2 = cx->vbi.raw_decoder_sav_even_field;
|
||||
u8 sav1 = raw_vbi_sav_rp[0];
|
||||
u8 sav2 = raw_vbi_sav_rp[1];
|
||||
u8 *q = buf;
|
||||
u8 *p;
|
||||
int i;
|
||||
@ -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
|
||||
Returns new compressed size */
|
||||
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;
|
||||
int i;
|
||||
u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz
|
||||
: vbi_hblank_samples_50Hz;
|
||||
|
||||
/* find the first valid line */
|
||||
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;
|
||||
}
|
||||
|
||||
@ -133,8 +151,8 @@ static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
|
||||
for (i = 0; i < size / line_size; i++) {
|
||||
u8 *p = buf + i * line_size;
|
||||
|
||||
/* Look for SAV code */
|
||||
if (p[0] != 0xff || p[1] || p[2] || p[3] != sav)
|
||||
/* Look for EAV code */
|
||||
if (p[0] != 0xff || p[1] || p[2] || p[3] != eav)
|
||||
continue;
|
||||
vbi.p = p + 4;
|
||||
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,
|
||||
if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
|
||||
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 */
|
||||
if (cx18_raw_vbi(cx)) {
|
||||
u8 type;
|
||||
@ -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);
|
||||
|
||||
/* 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
|
||||
compatibility of old VBI software. */
|
||||
p += size - 4;
|
||||
@ -187,14 +211,14 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
|
||||
cx18_buf_swap(buf);
|
||||
|
||||
/* first field */
|
||||
lines = compress_sliced_buf(cx, 0, p, size / 2,
|
||||
cx->vbi.sliced_decoder_sav_odd_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]);
|
||||
/* second field */
|
||||
/* experimentation shows that the second half does not always
|
||||
begin at the exact address. So start a bit earlier
|
||||
(hence 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 */
|
||||
if (lines == 0) {
|
||||
cx->vbi.sliced_data[0].id = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user