1 #include <math.h>
2
3 #define AMP 110
4 #define DC 60
5
6 static vbi_raw_decoder sim;
7 static double sim_time;
8
9 static inline double
10 shape(double ph)
11 {
12 double x = sin(ph);
13
14 return x * x;
15 }
16
17 /*
18 * Closed Caption Signal Simulator
19 */
20
21 static inline double
22 cc_sim(double t, double F, unsigned char b1, unsigned char b2)
23 {
24 int bits = (b2 << 10) + (b1 << 2) + 2; /* start bit 0 -> 1 */
25 double t1 = 10.5e-6 - .25 / F;
26 double t2 = t1 + 7 / F; /* CRI 7 cycles */
27 double t3 = t2 + 1.5 / F;
28 double t4 = t3 + 18 / F; /* 17 bits + raise and fall time */
29 double ph;
30
31 if (t < t1) {
32 return 0.0;
33 } else if (t < t2) {
34 t -= t2;
35 ph = M_PI * 2 * t * F - (M_PI * .5);
36 return sin(ph) / 2 + .5;
37 } else if (t < t3) {
38 return 0.0;
39 } else if (t < t4) {
40 int i, n;
41
42 t -= t3;
43 i = (t * F - .0);
44 n = (bits >> i) & 3; /* low = 0, up, down, high */
45 if (n == 0)
46 return 0.0;
47 else if (n == 3)
48 return 1.0;
49
50 if ((n ^ i) & 1) /* down */
51 ph = M_PI * 2 * (t - 1 / F) * F / 4;
52 else /* up */
53 ph = M_PI * 2 * (t - 0 / F) * F / 4;
54
55 return shape(ph);
56 } else {
57 return 0.0;
58 }
59 }
60
61 /*
62 * Wide Screen Signalling Simulator
63 */
64
65 static inline double
66 wss625_sim(double t, double F, unsigned int bits)
67 {
68 static int twobit[] = { 0xE38, 0xE07, 0x1F8, 0x1C7 };
69 static char frame[] =
70 "\0"
71 "\1\1\1\1\1\0\0\0\1\1\1\0\0\0"
72 "\1\1\1\0\0\0\1\1\1\0\0\0\1\1\1"
73 "\0\0\0\1\1\1\1\0\0\0\1\1\1\1\0\0\0\0\0\1\1\1\1\1"
74 "x";
75 double t1 = 11.0e-6 - .5 / F;
76 double t4 = t1 + (29 + 24 + 84) / F;
77 double ph;
78 int i, j, n;
79
80 frame[1 + 29 + 24] = bits & 1;
81
82 if (t < t1) {
83 return 0.0;
84 } else if (t < t4) {
85 t -= t1;
86 i = (t * F - .0);
87 if (i < 29 + 24) {
88 n = frame[i] + 2 * frame[i + 1];
89 } else {
90 j = i - 29 - 24;
91 n = twobit[(bits >> (j / 6)) & 3];
92 n = (n >> (j % 6)) & 3;
93 }
94
95 /* low = 0, down, up, high */
96 if (n == 0)
97 return 0.0;
98 else if (n == 3)
99 return 1.0;
100 if ((n ^ i) & 1)
101 ph = M_PI * 2 * (t - 1 / F) * F / 4;
102 else /* down */
103 ph = M_PI * 2 * (t - 0 / F) * F / 4;
104
105 return shape(ph);
106 } else {
107 return 0.0;
108 }
109 }
110
111 static inline double
112 wss525_sim(double t, double F, unsigned int bits)
113 {
114 double t1 = 11.2e-6 - .5 / F;
115 double t4 = t1 + (2 + 14 + 6 + 1) / F;
116 double ph;
117 int i, n;
118
119 bits = bits * 2 + (2 << 21); /* start bits 10, stop 0 */
120
121 if (t < t1) {
122 return 0.0;
123 } else if (t < t4) {
124 t -= t1;
125 i = (t * F - .0);
126 n = (bits >> (22 - i)) & 3; /* low = 0, up, down, high */
127
128 if (n == 0)
129 return 0.0;
130 else if (n == 3)
131 return 1.0;
132 if ((n ^ i) & 1)
133 ph = M_PI * 2 * (t - 0 / F) * F / 4;
134 else /* down */
135 ph = M_PI * 2 * (t - 1 / F) * F / 4;
136
137 return shape(ph);
138 } else
139 return 0.0;
140 }
141
142 /*
143 * Teletext Signal Simulator
144 */
145
146 static inline double
147 ttx_sim(double t, double F, const uint8_t *text)
148 {
149 double t1 = 10.3e-6 - .5 / F;
150 double t2 = t1 + (45 * 8 + 1) / F; /* 45 bytes + raise and fall time */
151 double ph;
152
153 if (t < t1) {
154 return 0.0;
155 } else if (t < t2) {
156 int i, j, n;
157
158 t -= t1;
159 i = (t * F);
160 j = i >> 3;
161 i &= 7;
162
163 if (j == 0)
164 n = ((text[0] * 2) >> i) & 3;
165 else
166 n = (((text[j - 1] >> 7) + text[j] * 2) >> i) & 3;
167
168 if (n == 0) {
169 return 0.0;
170 } else if (n == 3) {
171 return 1.0;
172 } else if ((n ^ i) & 1) {
173 ph = M_PI * 2 * (t - 1 / F) * F / 4;
174 return shape(ph);
175 } else { /* up */
176 ph = M_PI * 2 * (t - 0 / F) * F / 4;
177 return shape(ph);
178 }
179 } else {
180 return 0.0;
181 }
182
183 if (t < t1) {
184 return 0.0;
185 } else if (t < t2) {
186 int i, j, n;
187
188 t -= t1;
189 i = (t * F - .0);
190 j = i >> 3;
191 if (j < 44)
192 n = ((text[j + 1] * 256 + text[j]) >> i) & 3;
193 else
194 n = (text[i] >> i) & 3;
195
196 return shape(ph);
197 }
198 }
199
200 static unsigned int caption_i = 0;
201 static const uint8_t caption_text[] = {
202 0x14, 0x25, 0x14, 0x25, 'L', 'I', 'B', 'Z',
203 'V', 'B', 'I', ' ', 'C', 'A', 'P', 'T',
204 'I', 'O', 'N', ' ', 'S', 'I', 'M', 'U',
205 'L', 'A', 'T', 'I', 'O', 'N', 0x14, 0x2D,
206 0x14, 0x2D /* even size please, add 0 if neccessary */
207 };
208
209 static inline int
210 odd(int c)
211 {
212 int n;
213
214 n = c ^ (c >> 4);
215 n = n ^ (n >> 2);
216 n = n ^ (n >> 1);
217
218 if (!(n & 1))
219 c |= 0x80;
220
221 return c;
222 }
223
224 static uint8_t *
225 ttx_next(void)
226 {
227 static uint8_t s1[2][10] = {
228 { 0x02, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15 },
229 { 0x02, 0x15, 0x02, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15 }
230 };
231 static uint8_t s2[32] = "100\2LIBZVBI\7 00:00:00";
232 static uint8_t s3[40] = " LIBZVBI TELETEXT SIMULATION ";
233 static uint8_t s4[40] = " Page 100 ";
234 static uint8_t s5[10][42] = {
235 { 0x02, 0x2f, 0x97, 0x20, 0x37, 0x23, 0x23, 0x23, 0x23, 0x23,
236 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
237 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
238 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
239 0xb5, 0x20 },
240 { 0xc7, 0x2f, 0x97, 0x0d, 0xb5, 0x04, 0x20, 0x9d, 0x83, 0x8c,
241 0x08, 0x2a, 0x2a, 0x2a, 0x89, 0x20, 0x20, 0x0d, 0x54, 0x45,
242 0xd3, 0x54, 0x20, 0xd0, 0xc1, 0xc7, 0x45, 0x8c, 0x20, 0x20,
243 0x08, 0x2a, 0x2a, 0x2a, 0x89, 0x0d, 0x20, 0x20, 0x1c, 0x97,
244 0xb5, 0x20 },
245 { 0x02, 0xd0, 0x97, 0x20, 0xb5, 0x20, 0x20, 0x20, 0x20, 0x20,
246 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
247 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
248 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
249 0xea, 0x20 },
250 { 0xc7, 0xd0, 0x97, 0x20, 0xb5, 0x20, 0x20, 0x20, 0x20, 0x20,
251 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
252 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
253 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
254 0xb5, 0x20 },
255 { 0x02, 0xc7, 0x97, 0x20, 0xb5, 0x20, 0x20, 0x20, 0x20, 0x20,
256 0x20, 0x15, 0x1a, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
257 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
258 0x2c, 0x2c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x97, 0x19,
259 0xb5, 0x20 },
260 { 0xc7, 0xc7, 0x97, 0x20, 0xb5, 0x20, 0x20, 0x20, 0x20, 0x20,
261 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
262 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
263 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
264 0xb5, 0x20 },
265 { 0x02, 0x8c, 0x97, 0x9e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x13,
266 0x7f, 0x7f, 0x7f, 0x7f, 0x16, 0x7f, 0x7f, 0x7f, 0x7f, 0x92,
267 0x7f, 0x92, 0x7f, 0x7f, 0x15, 0x7f, 0x7f, 0x15, 0x7f, 0x91,
268 0x91, 0x7f, 0x7f, 0x91, 0x94, 0x7f, 0x94, 0x7f, 0x94, 0x97,
269 0xb5, 0x20 },
270 { 0xc7, 0x8c, 0x97, 0x9e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x13,
271 0x7f, 0x7f, 0x7f, 0x7f, 0x16, 0x7f, 0x7f, 0x7f, 0x7f, 0x92,
272 0x7f, 0x7f, 0x7f, 0x7f, 0x15, 0x7f, 0x7f, 0x7f, 0x7f, 0x91,
273 0x7f, 0x7f, 0x7f, 0x7f, 0x94, 0x7f, 0x7f, 0x7f, 0x7f, 0x97,
274 0xb5, 0x20 },
275 { 0x02, 0x9b, 0x97, 0x9e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x13,
276 0x7f, 0x7f, 0x7f, 0x7f, 0x16, 0x7f, 0x7f, 0x7f, 0x7f, 0x92,
277 0x7f, 0x7f, 0x7f, 0x7f, 0x15, 0x7f, 0x7f, 0x7f, 0x7f, 0x91,
278 0x7f, 0x7f, 0x7f, 0x7f, 0x94, 0x7f, 0x7f, 0x7f, 0x7f, 0x97,
279 0xb5, 0x20 },
280 { 0xc7, 0x9b, 0x97, 0x20, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
281 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
282 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
283 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
284 0xa1, 0x20 }
285 };
286 static uint8_t buf[45];
287 static int row = 0, page = 0;
288 int i;
289
290 buf[0] = 0x55;
291 buf[1] = 0x55;
292 buf[2] = 0x27;
293
294 if (row == 0) {
295 memcpy(buf + 3, s1[page], 10);
296 page ^= 1;
297 for (i = 0; i < 32; i++)
298 buf[13 + i] = odd(s2[i]);
299 } else if (row == 1) {
300 buf[3] = 0x02; buf[4] = 0x02;
301 for (i = 0; i < 40; i++)
302 buf[5 + i] = odd(s3[i]);
303 } else if (row == 2) {
304 buf[3] = 0x02; buf[4] = 0x49;
305 for (i = 0; i < 40; i++)
306 buf[5 + i] = odd(s4[i]);
307 } else {
308 memcpy(buf + 3, s5[row - 3], 42);
309 }
310
311 if (++row >= 13) row = 0;
312
313 return buf;
314 }
315
316 static void
317 read_sim(uint8_t *raw_data, vbi_sliced *sliced_data,
318 int *lines, double *timestamp)
319 {
320 uint8_t *buf;
321 double start, inc;
322 int i;
323
324 memset(raw_data, 0, (sim.count[0] + sim.count[1])
325 * sim.bytes_per_line);
326
327 *timestamp = sim_time;
328
329 if (sim.scanning == 525)
330 sim_time += 1001 / 30000.0;
331 else
332 sim_time += 1 / 25.0;
333
334 start = sim.offset / (double) sim.sampling_rate;
335 inc = 1 / (double) sim.sampling_rate;
336
337 if (sim.scanning == 525) {
338 /* Closed Caption */
339 {
340 buf = raw_data + (21 - sim.start[0])
341 * sim.bytes_per_line;
342
343 for (i = 0; i < sim.bytes_per_line; i++)
344 buf[i] = cc_sim(start + i * inc, 15734 * 32,
345 odd(caption_text[caption_i]),
346 odd(caption_text[caption_i + 1]))
347 * AMP + DC;
348
349 if ((caption_i += 2) > sizeof(caption_text))
350 caption_i = 0;
351 }
352
353 /* WSS NTSC-Japan */
354 {
355 const int poly = (1 << 6) + (1 << 1) + 1;
356 int b0 = 1, b1 = 1;
357 int bits = (b0 << 13) + (b1 << 12);
358 int crc, j;
359
360 crc = (((1 << 6) - 1) << (14 + 6)) + (bits << 6);
361
362 for (j = 14 + 6 - 1; j >= 0; j--) {
363 if (crc & ((1 << 6) << j))
364 crc ^= poly << j;
365 }
366
367 bits <<= 6;
368 bits |= crc;
369
370 /* fprintf(stderr, "WSS CPR << %08x\n", bits); */
371
372 buf = raw_data + (20 - sim.start[0])
373 * sim.bytes_per_line;
374
375 for (i = 0; i < sim.bytes_per_line; i++)
376 buf[i] = wss525_sim(start + i * inc,
377 447443, bits)
378 * AMP + DC;
379 }
380 } else {
381 /* Closed Caption */
382 {
383 buf = raw_data + (22 - sim.start[0])
384 * sim.bytes_per_line;
385
386 for (i = 0; i < sim.bytes_per_line; i++)
387 buf[i] = cc_sim(start + i * inc, 15625 * 32,
388 odd(caption_text[caption_i]),
389 odd(caption_text[caption_i + 1]))
390 * AMP + DC;
391
392 if ((caption_i += 2) > sizeof(caption_text))
393 caption_i = 0;
394 }
395
396 /* WSS PAL */
397 {
398 int g0 = 1, g1 = 2, g2 = 3, g3 = 4;
399 int bits = (g3 << 11) + (g2 << 8) + (g1 << 4) + g0;
400
401 buf = raw_data + (23 - sim.start[0])
402 * sim.bytes_per_line;
403
404 for (i = 0; i < sim.bytes_per_line; i++)
405 buf[i] = wss625_sim(start + i * inc, 15625 * 320,
406 bits) * AMP + DC;
407 }
408
409 /* Teletext */
410 {
411 int line, count;
412 uint8_t *text;
413
414 buf = raw_data;
415
416 for (line = sim.start[0], count = sim.count[0];
417 count > 0; line++, count--, buf += sim.bytes_per_line)
418 if ((line >= 7 && line <= 15)
419 || (line >= 19 && line <= 21)) {
420 text = ttx_next();
421 for (i = 0; i < sim.bytes_per_line; i++) {
422 buf[i] = ttx_sim(start + i * inc,
423 15625 * 444,
424 text) * AMP + DC;
425 }
426 }
427 for (line = sim.start[1], count = sim.count[1];
428 count > 0; line++, count--, buf += sim.bytes_per_line)
429 if ((line >= 320 && line <= 328)
430 || (line >= 332 && line <= 335)) {
431 text = ttx_next();
432 for (i = 0; i < sim.bytes_per_line; i++) {
433 buf[i] = ttx_sim(start + i * inc,
434 15625 * 444,
435 text) * AMP + DC;
436 }
437 }
438 }
439 }
440
441 *lines = vbi_raw_decode(&sim, raw_data, sliced_data);
442 }
443
444 static vbi_raw_decoder *
445 init_sim(int scanning, unsigned int services)
446 {
447 vbi_raw_decoder_init(&sim);
448
449 sim.scanning = scanning;
450 sim.sampling_format = VBI_PIXFMT_YUV420;
451 sim.sampling_rate = 2 * 13500000;
452 sim.bytes_per_line = 1440;
453 sim.offset = 9.7e-6 * sim.sampling_rate;
454 sim.interlaced = FALSE;
455 sim.synchronous = TRUE;
456
457 if (scanning == 525) {
458 sim.start[0] = 10;
459 sim.count[0] = 21 - 10 + 1;
460 sim.start[1] = 272;
461 sim.count[1] = 285 - 272 + 1;
462 } else if (scanning == 625) {
463 sim.start[0] = 6;
464 sim.count[0] = 23 - 6 + 1;
465 sim.start[1] = 318;
466 sim.count[1] = 335 - 318 + 1;
467 } else
468 assert(!"invalid scanning value");
469
470 sim_time = 0.0;
471
472 vbi_raw_decoder_add_services(&sim, services, 0);
473
474 return ∼
475 }
476
|
This page was automatically generated by the
LXR engine.
|