2 Vertical Blank Interval support functions
3 Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "ivtv-driver.h"
22 #include "ivtv-ioctl.h"
23 #include "ivtv-queue.h"
26 static void ivtv_set_vps(struct ivtv *itv, int enabled)
28 struct v4l2_sliced_vbi_data data;
30 if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
32 data.id = V4L2_SLICED_VPS;
34 data.line = enabled ? 16 : 0;
35 data.data[2] = itv->vbi.vps_payload.data[0];
36 data.data[8] = itv->vbi.vps_payload.data[1];
37 data.data[9] = itv->vbi.vps_payload.data[2];
38 data.data[10] = itv->vbi.vps_payload.data[3];
39 data.data[11] = itv->vbi.vps_payload.data[4];
40 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
43 static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
45 struct v4l2_sliced_vbi_data data;
47 if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
49 data.id = V4L2_SLICED_CAPTION_525;
51 data.line = (mode & 1) ? 21 : 0;
52 data.data[0] = cc->odd[0];
53 data.data[1] = cc->odd[1];
54 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
56 data.line = (mode & 2) ? 21 : 0;
57 data.data[0] = cc->even[0];
58 data.data[1] = cc->even[1];
59 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
62 static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
64 struct v4l2_sliced_vbi_data data;
66 if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
68 /* When using a 50 Hz system, always turn on the
69 wide screen signal with 4x3 ratio as the default.
70 Turning this signal on and off can confuse certain
71 TVs. As far as I can tell there is no reason not to
72 transmit this signal. */
73 if ((itv->std & V4L2_STD_625_50) && !enabled) {
75 mode = 0x08; /* 4x3 full format */
77 data.id = V4L2_SLICED_WSS_625;
79 data.line = enabled ? 23 : 0;
80 data.data[0] = mode & 0xff;
81 data.data[1] = (mode >> 8) & 0xff;
82 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
85 static int odd_parity(u8 c)
94 void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt)
96 struct vbi_info *vi = &itv->vbi;
97 struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
101 for (i = 0; i < cnt; i++) {
102 const struct v4l2_sliced_vbi_data *d = sliced + i;
104 if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
106 cc.even[0] = d->data[0];
107 cc.even[1] = d->data[1];
109 cc.odd[0] = d->data[0];
110 cc.odd[1] = d->data[1];
114 else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
117 vps.data[0] = d->data[2];
118 vps.data[1] = d->data[8];
119 vps.data[2] = d->data[9];
120 vps.data[3] = d->data[10];
121 vps.data[4] = d->data[11];
122 if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) {
123 vi->vps_payload = vps;
124 set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
127 else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) {
128 int wss = d->data[0] | d->data[1] << 8;
130 if (vi->wss_payload != wss) {
131 vi->wss_payload = wss;
132 set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
136 if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) {
137 vi->cc_payload[vi->cc_payload_idx++] = cc;
138 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
142 static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
146 u32 linemask[2] = { 0, 0 };
148 static const u8 mpeg_hdr_data[] = {
149 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
150 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
151 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
152 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
154 const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */
155 int idx = itv->vbi.frame % IVTV_VBI_FRAMES;
156 u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0];
158 for (i = 0; i < lines; i++) {
161 if (itv->vbi.sliced_data[i].id == 0)
164 l = itv->vbi.sliced_data[i].line - 6;
165 f = itv->vbi.sliced_data[i].field;
169 linemask[0] |= (1 << l);
171 linemask[1] |= (1 << (l - 32));
172 dst[sd + 12 + line * 43] =
173 ivtv_service2vbi(itv->vbi.sliced_data[i].id);
174 memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42);
177 memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data));
179 /* All lines are used, so there is no space for the linemask
180 (the max size of the VBI data is 36 * 43 + 4 bytes).
181 So in this case we use the magic number 'ITV0'. */
182 memcpy(dst + sd, "ITV0", 4);
183 memcpy(dst + sd + 4, dst + sd + 12, line * 43);
184 size = 4 + ((43 * line + 3) & ~3);
186 memcpy(dst + sd, "itv0", 4);
187 memcpy(dst + sd + 4, &linemask[0], 8);
188 size = 12 + ((43 * line + 3) & ~3);
190 dst[4+16] = (size + 10) >> 8;
191 dst[5+16] = (size + 10) & 0xff;
192 dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6);
193 dst[10+16] = (pts_stamp >> 22) & 0xff;
194 dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff);
195 dst[12+16] = (pts_stamp >> 7) & 0xff;
196 dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1);
197 itv->vbi.sliced_mpeg_size[idx] = sd + size;
200 static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
206 if (!memcmp(p, "itv0", 4)) {
207 memcpy(linemask, p + 4, 8);
209 } else if (!memcmp(p, "ITV0", 4)) {
210 linemask[0] = 0xffffffff;
214 /* unknown VBI data, convert to empty VBI frame */
215 linemask[0] = linemask[1] = 0;
217 for (i = 0; i < 36; i++) {
220 if (i < 32 && !(linemask[0] & (1 << i)))
222 if (i >= 32 && !(linemask[1] & (1 << (i - 32))))
226 case IVTV_SLICED_TYPE_TELETEXT_B:
227 id2 = V4L2_SLICED_TELETEXT_B;
229 case IVTV_SLICED_TYPE_CAPTION_525:
230 id2 = V4L2_SLICED_CAPTION_525;
231 err = !odd_parity(p[1]) || !odd_parity(p[2]);
233 case IVTV_SLICED_TYPE_VPS:
234 id2 = V4L2_SLICED_VPS;
236 case IVTV_SLICED_TYPE_WSS_625:
237 id2 = V4L2_SLICED_WSS_625;
244 l = (i < 18) ? i + 6 : i - 18 + 6;
245 itv->vbi.sliced_dec_data[line].line = l;
246 itv->vbi.sliced_dec_data[line].field = i >= 18;
247 itv->vbi.sliced_dec_data[line].id = id2;
248 memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42);
254 itv->vbi.sliced_dec_data[line].id = 0;
255 itv->vbi.sliced_dec_data[line].line = 0;
256 itv->vbi.sliced_dec_data[line].field = 0;
259 return line * sizeof(itv->vbi.sliced_dec_data[0]);
262 /* Compress raw VBI format, removes leading SAV codes and surplus space after the
264 Returns new compressed size. */
265 static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size)
267 u32 line_size = itv->vbi.raw_decoder_line_size;
268 u32 lines = itv->vbi.count;
269 u8 sav1 = itv->vbi.raw_decoder_sav_odd_field;
270 u8 sav2 = itv->vbi.raw_decoder_sav_even_field;
275 for (i = 0; i < lines; i++) {
276 p = buf + i * line_size;
278 /* Look for SAV code */
279 if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) {
282 memcpy(q, p + 4, line_size - 4);
285 return lines * (line_size - 4);
289 /* Compressed VBI format, all found sliced blocks put next to one another
290 Returns new compressed size */
291 static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav)
293 u32 line_size = itv->vbi.sliced_decoder_line_size;
294 struct v4l2_decode_vbi_line vbi;
297 /* find the first valid line */
298 for (i = 0; i < size; i++, buf++) {
299 if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
304 if (size < line_size) {
307 for (i = 0; i < size / line_size; i++) {
308 u8 *p = buf + i * line_size;
310 /* Look for SAV code */
311 if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) {
315 itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
317 itv->vbi.sliced_data[line].id = vbi.type;
318 itv->vbi.sliced_data[line].field = vbi.is_second_field;
319 itv->vbi.sliced_data[line].line = vbi.line;
320 memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42);
327 void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
328 u64 pts_stamp, int streamtype)
330 u8 *p = (u8 *) buf->buf;
331 u32 size = buf->bytesused;
335 if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set == 0) {
342 size = buf->bytesused = compress_raw_buf(itv, p, size);
344 /* second field of the frame? */
345 if (type == itv->vbi.raw_decoder_sav_even_field) {
346 /* Dirty hack needed for backwards
347 compatibility of old VBI software. */
349 memcpy(p, &itv->vbi.frame, 4);
355 /* Sliced VBI data with data insertion */
356 if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) {
362 lines = compress_sliced_buf(itv, 0, p, size / 2,
363 itv->vbi.sliced_decoder_sav_odd_field);
365 /* experimentation shows that the second half does not always begin
366 at the exact address. So start a bit earlier (hence 32). */
367 lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32,
368 itv->vbi.sliced_decoder_sav_even_field);
369 /* always return at least one empty line */
371 itv->vbi.sliced_data[0].id = 0;
372 itv->vbi.sliced_data[0].line = 0;
373 itv->vbi.sliced_data[0].field = 0;
376 buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]);
377 memcpy(p, &itv->vbi.sliced_data[0], size);
379 if (itv->vbi.insert_mpeg) {
380 copy_vbi_data(itv, lines, pts_stamp);
386 /* Sliced VBI re-inserted from an MPEG stream */
387 if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
388 /* If the size is not 4-byte aligned, then the starting address
389 for the swapping is also shifted. After swapping the data the
390 real start address of the VBI data is exactly 4 bytes after the
391 original start. It's a bit fiddly but it works like a charm.
392 Non-4-byte alignment happens when an lseek is done on the input
393 mpeg file to a non-4-byte aligned position. So on arrival here
394 the VBI data is also non-4-byte aligned. */
395 int offset = size & 3;
402 for (y = 0; y < size; y += 4) {
403 swab32s((u32 *)(p + y));
406 cnt = ivtv_convert_ivtv_vbi(itv, p + offset);
407 memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
408 buf->bytesused = cnt;
410 ivtv_write_vbi(itv, itv->vbi.sliced_dec_data,
411 cnt / sizeof(itv->vbi.sliced_dec_data[0]));
416 void ivtv_disable_cc(struct ivtv *itv)
418 struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
420 clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
421 ivtv_set_cc(itv, 0, &cc);
422 itv->vbi.cc_payload_idx = 0;
426 void ivtv_vbi_work_handler(struct ivtv *itv)
428 struct vbi_info *vi = &itv->vbi;
429 struct v4l2_sliced_vbi_data data;
430 struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
433 if (itv->output_mode == OUT_PASSTHROUGH) {
435 data.id = V4L2_SLICED_WSS_625;
438 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
439 ivtv_set_wss(itv, 1, data.data[0] & 0xf);
440 vi->wss_missing_cnt = 0;
441 } else if (vi->wss_missing_cnt == 4) {
442 ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */
444 vi->wss_missing_cnt++;
450 data.id = V4L2_SLICED_CAPTION_525;
452 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
454 cc.odd[0] = data.data[0];
455 cc.odd[1] = data.data[1];
458 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
460 cc.even[0] = data.data[0];
461 cc.even[1] = data.data[1];
464 vi->cc_missing_cnt = 0;
465 ivtv_set_cc(itv, mode, &cc);
466 } else if (vi->cc_missing_cnt == 4) {
467 ivtv_set_cc(itv, 0, &cc);
469 vi->cc_missing_cnt++;
475 if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) {
476 ivtv_set_wss(itv, 1, vi->wss_payload & 0xf);
479 if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
480 if (vi->cc_payload_idx == 0) {
481 clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
482 ivtv_set_cc(itv, 3, &cc);
484 while (vi->cc_payload_idx) {
485 cc = vi->cc_payload[0];
487 memcpy(vi->cc_payload, vi->cc_payload + 1,
488 sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0]));
489 vi->cc_payload_idx--;
490 if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80)
493 ivtv_set_cc(itv, 3, &cc);
498 if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) {
499 ivtv_set_vps(itv, 1);