/*
* libzvbi - WSS decoder
*
* Copyright (C) 2001, 2002 Michael H. Schimek
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: wss.c,v 1.3 2006/05/31 03:51:55 mschimek Exp $ */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "misc.h"
#include "vbi.h"
#include "hamm.h"
#include "wss.h"
void
vbi_decode_wss_625(vbi_decoder *vbi, uint8_t *buf, double time)
{
vbi_event e;
vbi_aspect_ratio *r = &e.ev.aspect;
int parity;
memset(&e, 0, sizeof(e));
/* Two producers... */
if (time < vbi->wss_time)
return;
vbi->wss_time = time;
if (buf[0] != vbi->wss_last[0]
|| buf[1] != vbi->wss_last[1]) {
vbi->wss_last[0] = buf[0];
vbi->wss_last[1] = buf[1];
vbi->wss_rep_ct = 0;
return;
}
if (++vbi->wss_rep_ct < 3)
return;
parity = buf[0] & 15;
parity ^= parity >> 2;
parity ^= parity >> 1;
if (!(parity & 1))
return;
r->ratio = 1.0;
switch (buf[0] & 7) {
case 0: /* 4:3 */
case 6: /* 14:9 soft matte */
r->first_line = 23;
r->last_line = 310;
break;
case 1: /* 14:9 */
r->first_line = 41;
r->last_line = 292;
break;
case 2: /* 14:9 top */
r->first_line = 23;
r->last_line = 274;
break;
case 3: /* 16:9 */
case 5: /* "Letterbox > 16:9" */
r->first_line = 59; // 59.5 ?
r->last_line = 273;
break;
case 4: /* 16:9 top */
r->first_line = 23;
r->last_line = 237;
break;
case 7: /* 16:9 anamorphic */
r->first_line = 23;
r->last_line = 310;
r->ratio = 3.0 / 4.0;
break;
}
r->film_mode = !!(buf[0] & 0x10);
switch ((buf[1] >> 1) & 3) {
case 0:
r->open_subtitles = VBI_SUBT_NONE;
break;
case 1:
r->open_subtitles = VBI_SUBT_ACTIVE;
break;
case 2:
r->open_subtitles = VBI_SUBT_MATTE;
break;
case 3:
r->open_subtitles = VBI_SUBT_UNKNOWN;
break;
}
if (memcmp(r, &vbi->prog_info[0].aspect, sizeof(*r)) != 0) {
vbi->prog_info[0].aspect = *r;
vbi->aspect_source = 1;
e.type = VBI_EVENT_ASPECT;
vbi_send_event(vbi, &e);
e.type = VBI_EVENT_PROG_INFO;
e.ev.prog_info = &vbi->prog_info[0];
vbi_send_event(vbi, &e);
}
if (0) {
static const char *formats[] = {
"Full format 4:3, 576 lines",
"Letterbox 14:9 centre, 504 lines",
"Letterbox 14:9 top, 504 lines",
"Letterbox 16:9 centre, 430 lines",
"Letterbox 16:9 top, 430 lines",
"Letterbox > 16:9 centre",
"Full format 14:9 centre, 576 lines",
"Anamorphic 16:9, 576 lines"
};
static const char *subtitles[] = {
"none",
"in active image area",
"out of active image area",
"?"
};
printf("WSS: %s; %s mode; %s color coding;\n"
" %s helper; reserved b7=%d; %s\n"
" open subtitles: %s; %scopyright %s; copying %s\n",
formats[buf[0] & 7],
(buf[0] & 0x10) ? "film" : "camera",
(buf[0] & 0x20) ? "MA/CP" : "standard",
(buf[0] & 0x40) ? "modulated" : "no",
!!(buf[0] & 0x80),
(buf[1] & 0x01) ? "have TTX subtitles; " : "",
subtitles[(buf[1] >> 1) & 3],
(buf[1] & 0x08) ? "surround sound; " : "",
(buf[1] & 0x10) ? "asserted" : "unknown",
(buf[1] & 0x20) ? "restricted" : "not restricted");
}
}
void
vbi_decode_wss_cpr1204(vbi_decoder *vbi, uint8_t *buf)
{
int b0 = buf[0] & 0x80;
int b1 = buf[0] & 0x40;
vbi_event e;
vbi_aspect_ratio *r = &e.ev.aspect;
memset(&e, 0, sizeof(e));
if (b1) {
r->first_line = 72; // wild guess
r->last_line = 212;
} else {
r->first_line = 22;
r->last_line = 262;
}
r->ratio = b0 ? 3.0 / 4.0 : 1.0;
r->film_mode = 0;
r->open_subtitles = VBI_SUBT_UNKNOWN;
if (memcmp(r, &vbi->prog_info[0].aspect, sizeof(*r)) != 0) {
vbi->prog_info[0].aspect = *r;
vbi->aspect_source = 2;
e.type = VBI_EVENT_ASPECT;
vbi_send_event(vbi, &e);
e.type = VBI_EVENT_PROG_INFO;
e.ev.prog_info = &vbi->prog_info[0];
vbi_send_event(vbi, &e);
}
if (0)
printf("CPR: %d %d\n", !!b0, !!b1);
}
#if 0 /* old stuff */
/* 0001 0100 000 000 == Full 4:3, PALPlus, other flags zero */
static const uint8_t
genuine_pal_wss_green[720] = {
54, 76, 92, 82, 81, 73, 63, 91,200,254,253,183,162,233,246,195,
190,224,247,237,203,150, 80, 23, 53,103, 93, 38, 61,172,244,243,
240,202,214,251,233,125, 44, 34, 59, 95, 86, 40, 54,149,235,255,
240,208,206,247,249,164, 67, 28, 38, 82,100, 49, 26,121,227,249,
240,206,203,242,248,182, 87, 26, 33, 82, 94, 51, 37,102,197,250,
251,222,205,226,247,210,118, 38, 41, 78, 91, 67, 55,103,190,254,
252,240,220,206,211,229,245,254,207,108, 28, 42, 93,100, 60, 21,
120,200,245,241,223,221,220,216,222,233,234,188, 97, 27, 30, 70,
70, 68, 67, 70, 71, 67, 58, 49, 77,159,240,248,226,203,211,227,
233,221,208,201,221,245,196, 99, 22, 39, 73, 88, 54, 34, 92,181,
243,246,217,186,212,245,192, 95, 23, 40, 72, 81, 46, 25, 84,170,
250,246,213,194,225,251,211,136, 22, 39, 73, 91, 62, 38, 84,157,
236,247,241,208,201,226,235,219,222,233,222,208,230,250,220,158,
54, 36, 42, 74, 79, 58, 56, 76, 72, 49, 53, 80, 65, 20, 35,107,
246,249,239,225,217,221,226,227,218,225,220,215,231,250,236,200,
68, 39, 31, 51, 71, 66, 53, 46, 63, 60, 58, 67, 70, 54, 50, 66,
194,245,246,209,193,228,240,219,116, 35, 8, 64, 93, 58, 39, 61,
170,232,249,234,210,224,237,231,127, 64, 27, 52, 84, 77, 56, 46,
136,224,245,233,196,198,240,240,162, 74, 20, 48, 84, 72, 49, 46,
126,200,246,242,205,202,227,245,172, 87, 19, 29, 72, 83, 59, 36,
89,186,249,244,196,192,229,250,202, 94, 24, 37, 76, 95, 82, 49,
71,171,251,251,203,189,221,253,220,123, 36, 31, 75, 96, 76, 49,
79,160,247,252,232,199,207,234,233,138, 44, 28, 66, 91, 76, 53,
59,148,229,252,240,202,202,241,252,165, 64, 20, 39, 72, 78, 65,
57, 62, 63, 62, 64, 67, 62, 54, 58, 67, 74, 72, 65, 63, 62, 64,
57, 68, 67, 55, 54, 66, 68, 57, 57, 56, 60, 63, 55, 50, 64
};
static void
wss_test_init(v4l_device *v4l)
{
static const int std_widths[] = {
768, 704, 640, 384, 352, 320, 192, 176, 160, -160
};
uint8_t *p = wss_test_data;
int i, j, g, width, spl, bpp = 0;
enum tveng_frame_pixformat fmt;
int sampling_rate;
fprintf(stderr, "WSS test enabled\n");
fmt = TVENG_PIX_RGB565; /* see below */
width = 352; /* pixels per line; assume a line length
of 52 usec, i.e. no clipping */
/* use this for capture widths reported by the driver, not scaled images */
for (i = 0; width < ((std_widths[i] + std_widths[i + 1]) >> 1); i++);
spl = std_widths[i]; /* samples in 52 usec */
sampling_rate = spl / 52.148e-6;
memset(wss_test_data, 0, sizeof wss_test_data);
for (i = 0; i < width; i++) {
double off = i * 704 / (double) spl;
j = off;
off -= j;
g = (genuine_pal_wss_green[j + 1] * off
+ genuine_pal_wss_green[j + 0] * (1 - off));
switch (fmt) {
case TVENG_PIX_RGB24:
case TVENG_PIX_BGR24:
*p++ = rand();
*p++ = g;
*p++ = rand();
bpp = 3;
break;
case TVENG_PIX_RGB32: /* RGBA / BGRA */
case TVENG_PIX_BGR32:
*p++ = rand();
*p++ = g;
*p++ = rand();
*p++ = rand();
bpp = 4;
break;
case TVENG_PIX_RGB565:
g <<= 3;
g ^= rand() & 0xF81F;
*p++ = g;
*p++ = g >> 8;
bpp = 2;
break;
case TVENG_PIX_RGB555:
g <<= 2;
g ^= rand() & 0xFC1F;
*p++ = g;
*p++ = g >> 8;
bpp = 2;
break;
case TVENG_PIX_YVU420:
case TVENG_PIX_YUV420:
*p++ = g;
bpp = 1;
break;
case TVENG_PIX_YUYV:
*p++ = g;
*p++ = rand();
bpp = 2;
break;
case TVENG_PIX_UYVY:
*p++ = rand();
*p++ = g;
bpp = 2;
break;
}
}
v4l->wss_slicer_fn =
init_bit_slicer(&v4l->wss_slicer,
width,
sampling_rate,
/* cri_rate */ 5000000,
/* bit_rate */ 833333,
/* cri_frc */ 0xC71E3C1F,
/* cri_mask */ 0x924C99CE,
/* cri_bits */ 32,
/* frc_bits */ 0,
/* payload */ 14 * 1,
MOD_BIPHASE_LSB_ENDIAN,
fmt);
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1