MythTV  master
cc708decoder.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 // Copyright (c) 2003-2005, Daniel Kristjansson
3 
4 #include <cstdio>
5 #include <cstdlib>
6 
7 #include "mythlogging.h"
8 #include "cc708reader.h"
9 #include "cc708decoder.h"
10 
11 #define LOC QString("CC708: ")
12 
13 #define DEBUG_CAPTIONS 0
14 #define DEBUG_CC_SERVICE 0
15 #define DEBUG_CC_SERVICE_2 0
16 #define DEBUG_CC_RAWPACKET 0
17 #define DEBUG_CC_VALIDPACKET 0
18 #define DEBUG_CC_DECODE 0
19 #define DEBUG_CC_PARSE 0
20 
22 {
27 };
28 
29 const char* cc_types[4] =
30 {
31  "NTSC line 21 field 1 closed captions"
32  "NTSC line 21 field 2 closed captions"
33  "DTVCC Channel Packet Data"
34  "DTVCC Channel Packet Start"
35 };
36 
37 static void parse_cc_packet(CC708Reader *cb_cbs, CaptionPacket *pkt,
38  time_t last_seen[64]);
39 
40 void CC708Decoder::decode_cc_data(uint cc_type, uint data1, uint data2)
41 {
42  if (DTVCC_PACKET_START == cc_type)
43  {
44 #if DEBUG_CC_DECODE
45  LOG(VB_VBI, LOG_DEBUG, LOC + QString("CC ST data(0x%1 0x%2)")
46  .arg(data1,0,16).arg(data2,0,16));
47 #endif
48 
51 
52  m_partialPacket.data[0] = data1;
53  m_partialPacket.data[1] = data2;
55  }
56  else if (DTVCC_PACKET_DATA == cc_type)
57  {
58 #if DEBUG_CC_DECODE
59  LOG(VB_VBI, LOG_DEBUG, LOC + QString("CC Ex data(0x%1 0x%2)")
60  .arg(data1,0,16).arg(data2,0,16));
61 #endif
62 
65  m_partialPacket.size += 2;
66  }
67 }
68 
70 {
74 }
75 
76 void CC708Decoder::services(uint seconds, bool seen[64]) const
77 {
78  time_t now = time(nullptr);
79  time_t then = now - seconds;
80 
81  seen[0] = false; // service zero is not allowed in CEA-708-D
82  for (uint i = 1; i < 64; i++)
83  seen[i] = (m_lastSeen[i] >= then);
84 }
85 
86 enum C0
87 {
88  NUL = 0x00,
89  ETX = 0x03,
90  BS = 0x08,
91  FF = 0x0C,
92  CR = 0x0D,
93  HCR = 0x0E,
94  EXT1 = 0x10,
95  P16 = 0x18,
96 };
97 
98 enum C1
99 {
100  CW0=0x80, CW1, CW2, CW3, CW4, CW5, CW6, CW7,
102  SPA=0x90, SPC, SPL, SWA=0x97,
104 };
105 
106 extern ushort CCtableG0[0x60];
107 extern ushort CCtableG1[0x60];
108 extern ushort CCtableG2[0x60];
109 extern ushort CCtableG3[0x60];
110 
111 static void append_character(CC708Reader *cc, uint service_num, short ch);
112 static void parse_cc_service_stream(CC708Reader *cc, uint service_num);
113 static int handle_cc_c0_ext1_p16(CC708Reader *cc, uint service_num, int i);
114 static int handle_cc_c1(CC708Reader *cc, uint service_num, int i);
115 static int handle_cc_c2(CC708Reader *cc, uint service_num, int i);
116 static int handle_cc_c3(CC708Reader *cc, uint service_num, int i);
117 
118 #define SEND_STR \
119 do { \
120  if (cc->m_tempStrSize[service_num]) \
121  { \
122  cc->TextWrite(service_num, \
123  cc->m_tempStr[service_num], \
124  cc->m_tempStrSize[service_num]); \
125  cc->m_tempStrSize[service_num] = 0; \
126  } \
127 } while (false)
128 
129 static void parse_cc_service_stream(CC708Reader* cc, uint service_num)
130 {
131  const int blk_size = cc->m_bufSize[service_num];
132  int blk_start = 0;
133  int dlc_loc = 0;
134  int rst_loc = 0;
135  int i = 0;
136 
137  // find last reset or delay cancel in buffer
138  for (i = 0; i < blk_size; i++)
139  {
140  switch (cc->m_buf[service_num][i]) {
141  // Skip over parameters, since their bytes may coincide
142  // with RST or DLC
143  case CLW:
144  case DLW:
145  case DSW:
146  case HDW:
147  case TGW:
148  case DLY:
149  i += 1;
150  break;
151  case SPA:
152  case SPL:
153  i += 2;
154  break;
155  case SPC:
156  i += 3;
157  break;
158  case SWA:
159  i += 4;
160  break;
161  case DF0:
162  case DF1:
163  case DF2:
164  case DF3:
165  case DF4:
166  case DF5:
167  case DF6:
168  case DF7:
169  i += 6;
170  break;
171  // Detect RST or DLC bytes
172  case RST:
173  rst_loc = dlc_loc = i;
174  break;
175  case DLC:
176  dlc_loc = i;
177  break;
178  }
179  }
180 
181  // reset, process only data after reset
182  if (rst_loc)
183  {
184  cc->Reset(service_num);
185  cc->m_delayed[service_num] = false; // Reset implicitly cancels delay
186  blk_start = rst_loc + 1;
187  }
188 
189  // if we have a delay cancel, cancel any delay
190  if (dlc_loc && cc->m_delayed[service_num])
191  {
192  cc->DelayCancel(service_num);
193  cc->m_delayed[service_num] = false;
194  }
195 
196  // cancel delay if the buffer is full
197  if (cc->m_delayed[service_num] && blk_size >= 126)
198  {
199  cc->DelayCancel(service_num);
200  cc->m_delayed[service_num] = false;
201  dlc_loc = blk_size - 1;
202  }
203 
204 #if DEBUG_CC_PARSE
205  LOG(VB_VBI, LOG_ERR,
206  QString("cc_ss delayed(%1) blk_start(%2) blk_size(%3)")
207  .arg(cc->m_delayed[service_num]) .arg(blk_start) .arg(blk_size));
208 #endif
209 
210  for (i = (cc->m_delayed[service_num]) ? blk_size : blk_start;
211  i < blk_size; )
212  {
213  const int old_i = i;
214  const int code = cc->m_buf[service_num][i];
215  if (0x0 == code)
216  {
217  i++;
218  }
219  else if (code <= 0x1f)
220  {
221  // C0 code -- ASCII commands + ext1: C2,C3,G2,G3 + p16: 16 chars
222  i = handle_cc_c0_ext1_p16(cc, service_num, i);
223  }
224  else if (code <= 0x7f)
225  {
226  // G0 code -- mostly ASCII printables
227  short character = CCtableG0[code-0x20];
228  append_character(cc, service_num, character);
229  i++;
230  SEND_STR;
231  }
232  else if (code <= 0x9f)
233  {
234  // C1 code -- caption control codes
235  i = handle_cc_c1(cc, service_num, i);
236  }
237  else if (code <= 0xff)
238  {
239  // G1 code -- ISO 8859-1 Latin 1 characters
240  short character = CCtableG1[code-0xA0];
241  append_character(cc, service_num, character);
242  i++;
243  }
244 
245 #if DEBUG_CC_SERVICE
246  LOG(VB_VBI, LOG_DEBUG, QString("i %1, blk_size %2").arg(i)
247  .arg(blk_size));
248 #endif
249 
250  // loop continuation check
251  if (old_i == i)
252  {
253 #if DEBUG_CC_SERVICE
254  LOG(VB_VBI, LOG_DEBUG, QString("old_i == i == %1").arg(i));
255  QString msg;
256  for (int j = 0; j < blk_size; j++)
257  msg += QString("0x%1 ").arg(cc->m_buf[service_num][j], 0, 16);
258  LOG(VB_VBI, LOG_DEBUG, msg);
259 #endif
260  if (blk_size - i > 10)
261  {
262  LOG(VB_VBI, LOG_INFO, "eia-708 decoding error...");
263  cc->Reset(service_num);
264  cc->m_delayed[service_num] = false;
265  i = cc->m_bufSize[service_num];
266  }
267  // There must be an incomplete code in buffer...
268  break;
269  }
270  if (cc->m_delayed[service_num] && dlc_loc < i)
271  {
272  // delay in effect
273  break;
274  }
275  if (cc->m_delayed[service_num])
276  {
277  // this delay has already been canceled..
278  cc->DelayCancel(service_num);
279  cc->m_delayed[service_num] = false;
280  }
281  }
282 
283  // get rid of remaining bytes...
284  if ((blk_size - i) > 0)
285  {
286  memmove(cc->m_buf[service_num], cc->m_buf[service_num] + i,
287  blk_size - i);
288  cc->m_bufSize[service_num] -= i;
289  }
290  else
291  {
292  if (0 != (blk_size - i))
293  {
294  LOG(VB_VBI, LOG_ERR, QString("buffer error i(%1) buf_size(%2)")
295  .arg(i).arg(blk_size));
296  QString msg;
297  for (i=0; i < blk_size; i++)
298  msg += QString("0x%1 ").arg(cc->m_buf[service_num][i], 0, 16);
299  LOG(VB_VBI, LOG_ERR, msg);
300  }
301  cc->m_bufSize[service_num] = 0;
302  }
303 }
304 
305 static int handle_cc_c0_ext1_p16(CC708Reader* cc, uint service_num, int i)
306 {
307  // C0 code -- subset of ASCII misc. control codes
308  const int code = cc->m_buf[service_num][i];
309  if (code<=0xf)
310  {
311  // single byte code
312  if (ETX==code)
313  SEND_STR;
314  else if (BS==code)
315  append_character(cc, service_num, 0x08);
316  else if (FF==code)
317  append_character(cc, service_num, 0x0c);
318  else if ((CR==code) || (HCR==code))
319  append_character(cc, service_num, 0x0d);
320  i++;
321  }
322  else if (code<=0x17)
323  {
324  // double byte code
325  const int blk_size = cc->m_bufSize[service_num];
326  if (EXT1==code && ((i+1)<blk_size))
327  {
328  const int code2 = cc->m_buf[service_num][i+1];
329  if (code2<=0x1f)
330  {
331  // C2 code -- nothing in EIA-708-A
332  i = handle_cc_c2(cc, service_num, i);
333  }
334  else if (code2<=0x7f)
335  {
336  // G2 code -- fractions, drawing, symbols
337  append_character(cc, service_num, CCtableG2[code2-0x20]);
338  i+=2;
339  }
340  else if (code2<=0x9f)
341  {
342  // C3 code -- nothing in EIA-708-A
343  i = handle_cc_c3(cc, service_num, i);
344  }
345  else if (code2<=0xff)
346  {
347  // G3 code -- one symbol in EIA-708-A "[cc]"
348  append_character(cc, service_num, CCtableG3[code2-0xA0]);
349  i+=2;
350  }
351  }
352  else if ((i+1)<blk_size)
353  i+=2;
354  }
355  else if (code<=0x1f)
356  {
357  // triple byte code
358  const int blk_size = cc->m_bufSize[service_num];
359  if (P16==code && ((i+2)<blk_size))
360  {
361  // reserved for large alphabets, but not yet defined
362  }
363  if ((i+2)<blk_size)
364  i+=3;
365  }
366  return i;
367 }
368 
369 static int handle_cc_c1(CC708Reader* cc, uint service_num, int i)
370 {
371  const int blk_size = cc->m_bufSize[service_num];
372  const int code = cc->m_buf[service_num][i];
373 
374  const unsigned char* blk_buf = cc->m_buf[service_num];
375  if (code<=CW7)
376  { // no paramaters
377  SEND_STR;
378  cc->SetCurrentWindow(service_num, code-0x80);
379  i+=1;
380  }
381  else if (DLC == cc->m_buf[service_num][i])
382  {
383 /* processed out-of-band
384  cc->DelayCancel(service_num);
385  cc->m_delayed[service_num] = 0;
386 */
387  i+=1;
388  }
389  else if (code>=CLW && code<=DLY && ((i+1)<blk_size))
390  { // 1 byte of paramaters
391  int param1 = blk_buf[i+1];
392  SEND_STR;
393  if (CLW==code)
394  cc->ClearWindows(service_num, param1);
395  else if (DSW==code)
396  cc->DisplayWindows(service_num, param1);
397  else if (HDW==code)
398  cc->HideWindows(service_num, param1);
399  else if (TGW==code)
400  cc->ToggleWindows(service_num, param1);
401  else if (DLW==code)
402  cc->DeleteWindows(service_num, param1);
403  else if (DLY==code)
404  {
405  cc->Delay(service_num, param1);
406  cc->m_delayed[service_num] = true;
407  }
408  i+=2;
409  }
410  else if (SPA==code && ((i+2)<blk_size))
411  {
412  int pen_size = (blk_buf[i+1] ) & 0x3;
413  int offset = (blk_buf[i+1]>>2) & 0x3;
414  int text_tag = (blk_buf[i+1]>>4) & 0xf;
415  int font_tag = (blk_buf[i+2] ) & 0x7;
416  int edge_type = (blk_buf[i+2]>>3) & 0x7;
417  int underline = (blk_buf[i+2]>>6) & 0x1;
418  int italic = (blk_buf[i+2]>>7) & 0x1;
419  SEND_STR;
420  cc->SetPenAttributes(service_num, pen_size, offset, text_tag,
421  font_tag, edge_type, underline, italic);
422  i+=3;
423  }
424  else if (SPC==code && ((i+3)<blk_size))
425  {
426  int fg_color = (blk_buf[i+1] ) & 0x3f;
427  int fg_opacity = (blk_buf[i+1]>>6) & 0x03;
428  int bg_color = (blk_buf[i+2] ) & 0x3f;
429  int bg_opacity = (blk_buf[i+2]>>6) & 0x03;
430  int edge_color = (blk_buf[i+3]>>6) & 0x3f;
431  SEND_STR;
432  cc->SetPenColor(service_num, fg_color, fg_opacity,
433  bg_color, bg_opacity, edge_color);
434  i+=4;
435  }
436  else if (SPL==code && ((i+2)<blk_size))
437  {
438  int row = blk_buf[i+1] & 0x0f;
439  int col = blk_buf[i+2] & 0x3f;
440  SEND_STR;
441  cc->SetPenLocation(service_num, row, col);
442  i+=3;
443  }
444  else if (SWA==code && ((i+4)<blk_size))
445  {
446  int fill_color = (blk_buf[i+1] ) & 0x3f;
447  int fill_opacity = (blk_buf[i+1]>>6) & 0x03;
448  int border_color = (blk_buf[i+2] ) & 0x3f;
449  int border_type01 = (blk_buf[i+2]>>6) & 0x03;
450  int justify = (blk_buf[i+3] ) & 0x03;
451  int scroll_dir = (blk_buf[i+3]>>2) & 0x03;
452  int print_dir = (blk_buf[i+3]>>4) & 0x03;
453  int word_wrap = (blk_buf[i+3]>>6) & 0x01;
454  int border_type = (blk_buf[i+3]>>5) | border_type01;
455  int display_eff = (blk_buf[i+4] ) & 0x03;
456  int effect_dir = (blk_buf[i+4]>>2) & 0x03;
457  int effect_speed = (blk_buf[i+4]>>4) & 0x0f;
458  SEND_STR;
459  cc->SetWindowAttributes(
460  service_num, fill_color, fill_opacity, border_color, border_type,
461  scroll_dir, print_dir, effect_dir,
462  display_eff, effect_speed, justify, word_wrap);
463  i+=5;
464  }
465  else if ((code>=DF0) && (code<=DF7) && ((i+6)<blk_size))
466  {
467  // param1
468  int priority = ( blk_buf[i+1] ) & 0x7;
469  int col_lock = (blk_buf[i+1]>>3) & 0x1;
470  int row_lock = (blk_buf[i+1]>>4) & 0x1;
471  bool visible = ((blk_buf[i+1]>>5) & 0x1) != 0;
472  // param2
473  int anchor_vertical = blk_buf[i+2] & 0x7f;
474  int relative_pos = (blk_buf[i+2]>>7);
475  // param3
476  int anchor_horizontal = blk_buf[i+3];
477  // param4
478  int row_count = blk_buf[i+4] & 0xf;
479  int anchor_point = blk_buf[i+4]>>4;
480  // param5
481  int col_count = blk_buf[i+5] & 0x3f;
482  // param6
483  int pen_style = blk_buf[i+6] & 0x7;
484  int win_style = (blk_buf[i+6]>>3) & 0x7;
485  SEND_STR;
486  cc->DefineWindow(service_num, code-0x98, priority, visible,
487  anchor_point, relative_pos,
488  anchor_vertical, anchor_horizontal,
489  row_count, col_count, row_lock, col_lock,
490  pen_style, win_style);
491  i+=7;
492  }
493 #if DEBUG_CC_SERVICE
494  else
495  {
496  LOG(VB_VBI, LOG_ERR, QString("handle_cc_c1: (NOT HANDLED) "
497  "code(0x%1) i(%2) blk_size(%3)").arg(code, 2, 16, QLatin1Char('0'))
498  .arg(i).arg(blk_size));
499  }
500 #endif
501 
502  return i;
503 }
504 
505 static int handle_cc_c2(CC708Reader* cc, uint service_num, int i)
506 {
507  const int blk_size = cc->m_bufSize[service_num];
508  const int code = cc->m_buf[service_num][i+1];
509 
510  if ((code<=0x7) && ((i+1)<blk_size)){
511  i+=2;
512  SEND_STR;
513  }
514  else if ((code<=0xf) && ((i+2)<blk_size))
515  {
516  i+=3;
517  SEND_STR;
518  }
519  else if ((code<=0x17) && ((i+3)<blk_size))
520  {
521  i+=4;
522  SEND_STR;
523  }
524  else if ((code<=0x1f) && ((i+4)<blk_size))
525  {
526  i+=5;
527  SEND_STR;
528  }
529  return i;
530 }
531 
532 static int handle_cc_c3(CC708Reader* cc, uint service_num, int i)
533 {
534  const unsigned char* blk_buf = cc->m_buf[service_num];
535  const int blk_size = cc->m_bufSize[service_num];
536  const int code = cc->m_buf[service_num][i+1];
537 
538  if ((code<=0x87) && ((i+5)<blk_size))
539  {
540  i+=6;
541  SEND_STR;
542  }
543  else if ((code<=0x8f) && ((i+6)<blk_size))
544  {
545  i+=7;
546  SEND_STR;
547  }
548  else if ((i+2)<blk_size)
549  { // varible length commands
550  int length = blk_buf[i+2]&0x3f;
551  if ((i+length)<blk_size)
552  {
553  i+=1+length;
554  SEND_STR;
555  }
556  }
557  return i;
558 }
559 
560 static bool rightsize_buf(CC708Reader* cc, uint service_num, uint block_size)
561 {
562  size_t min_new_size = block_size + cc->m_bufSize[service_num];
563  bool ret = true;
564  if (min_new_size >= cc->m_bufAlloc[service_num])
565  {
566  size_t new_alloc = cc->m_bufAlloc[service_num];
567  for (uint i = 0; (i < 32) && (new_alloc <= min_new_size); i++)
568  new_alloc *= 2;
569  void *new_buf = realloc(cc->m_buf[service_num], new_alloc);
570  if (new_buf)
571  {
572  cc->m_buf[service_num] = (uchar *)new_buf;
573  cc->m_bufAlloc[service_num] = new_alloc;
574  }
575  else
576  {
577  ret = false;
578  }
579 
580 #if DEBUG_CC_SERVICE_2
581  LOG(VB_VBI, LOG_DEBUG, QString("rightsize_buf: srv %1 to %1 bytes")
582  .arg(service_num) .arg(cc->m_bufAlloc[service_num]));
583 #endif
584  }
585  if (min_new_size >= cc->m_bufAlloc[service_num])
586  {
587  LOG(VB_VBI, LOG_ERR,
588  QString("buffer resize error: min_new_size=%1, buf_alloc[%2]=%3")
589  .arg(min_new_size)
590  .arg(service_num)
591  .arg(cc->m_bufAlloc[service_num]));
592  }
593  return ret;
594 }
595 
596 static void append_cc(CC708Reader* cc, uint service_num,
597  const unsigned char* blk_buf, int block_size)
598 {
599  if (!rightsize_buf(cc, service_num, block_size))
600  {
601  // The buffer resize failed. Drop the new data.
602  return;
603  }
604 
605  memcpy(cc->m_buf[service_num] + cc->m_bufSize[service_num],
606  blk_buf, block_size);
607 
608  cc->m_bufSize[service_num] += block_size;
609 #if DEBUG_CC_SERVICE_2
610  {
611  uint i;
612  QString msg("append_cc: ");
613  for (i = 0; i < cc->m_bufSize[service_num]; i++)
614  msg += QString("0x%1").arg(cc->m_buf[service_num][i], 0, 16);
615  LOG(VB_VBI, LOG_DEBUG, msg);
616  }
617 #endif
618  parse_cc_service_stream(cc, service_num);
619 }
620 
621 static void parse_cc_packet(CC708Reader* cb_cbs, CaptionPacket* pkt,
622  time_t last_seen[64])
623 {
624  const unsigned char* pkt_buf = pkt->data;
625  const int pkt_size = pkt->size;
626  int off = 1;
627  int len = ((((int)pkt_buf[0]) & 0x3f)<<1) - 1;
628 
629  if (len < 0)
630  return;
631 
632 #if DEBUG_CC_RAWPACKET
633  if (true)
634 #elif DEBUG_CAPTIONS
635  if (len > pkt_size)
636 #else
637  if (false) // NOLINT(readability-simplify-boolean-expr)
638 #endif
639  {
640  int srv = (pkt_buf[off]>>5) & 0x7;
641  int seq_num = (((int)pkt_buf[0])>>6)&0x3;
642  QString msg = QString("CC708 len %1 srv0 %2 seq %3 ").arg(len, 2)
643  .arg(srv) .arg(seq_num);
644  for (int j = 0; j < pkt_size; j++)
645  msg += QString("0x%1").arg(pkt_buf[j], 0, 16);
646  LOG(VB_VBI, LOG_DEBUG, msg);
647  }
648 
649  if (pkt_size >= 127)
650  LOG(VB_VBI, LOG_ERR,
651  QString("Unexpected pkt_size=%1").arg(pkt_size));
652 
653  while (off < pkt_size && pkt_buf[off])
654  { // service_block
655  int block_size = pkt_buf[off] & 0x1f;
656  int service_number = (pkt_buf[off]>>5) & 0x7;
657  int block_data_offset = (0x7==service_number && block_size!=0) ?
658  off+2 : off+1;
659 #if DEBUG_CC_SERVICE_BLOCK
660  LOG(VB_VBI, LOG_DEBUG,
661  QString("service_block size(%1) num(%2) off(%3)")
662  .arg(block_size) .arg(service_number) .arg(block_data_offset));
663 #endif
664  if (off+2 == block_data_offset)
665  {
666  int extended_service_number = pkt_buf[off+2] & 0x3f;
667 #if DEBUG_CC_SERVICE_BLOCK
668  LOG(VB_VBI, LOG_DEBUG, QString("ext_svc_num(%1)")
669  .arg(extended_service_number));
670 #endif
671  service_number = extended_service_number;
672  }
673  if (service_number)
674  {
675 #if DEBUG_CC_SERVICE
676  int i;
677  if (!(2==block_size &&
678  0==pkt_buf[block_data_offset] &&
679  0==pkt_buf[block_data_offset+1]))
680  {
681  QString msg = QString("service %1: ").arg(service_number);
682  for (i=0; i<block_size; i++)
683  msg += QString("0x%1 ")
684  .arg(pkt_buf[block_data_offset+i], 0, 16);
685  LOG(VB_VBI, LOG_DEBUG, msg);
686  }
687 #endif
688  append_cc(cb_cbs, service_number,
689  &pkt_buf[block_data_offset], block_size);
690 
691  last_seen[service_number] = time(nullptr);
692  }
693  off+=block_size+1;
694  }
695  if (off<pkt_size) // must end in null service block, if packet is not full.
696  {
697  if (pkt_buf[off] != 0)
698  {
699  LOG(VB_VBI, LOG_ERR,
700  QString("CEA-708 packet error: pkt_size=%1, pkt_buf[%2]=%3")
701  .arg(pkt_size).arg(off).arg(pkt_buf[off]));
702  }
703  }
704 }
705 
706 static void append_character(CC708Reader *cc, uint service_num, short ch)
707 {
708  if (cc->m_tempStrSize[service_num]+2 > cc->m_tempStrAlloc[service_num])
709  {
710  int new_alloc = (cc->m_tempStrAlloc[service_num]) ?
711  cc->m_tempStrAlloc[service_num] * 2 : 64;
712 
713  cc->m_tempStr[service_num] = (short*)
714  realloc(cc->m_tempStr[service_num], new_alloc * sizeof(short));
715 
716  cc->m_tempStrAlloc[service_num] = new_alloc; // shorts allocated
717  }
718 
719  if (cc->m_tempStr[service_num])
720  {
721  int i = cc->m_tempStrSize[service_num];
722  cc->m_tempStr[service_num][i] = ch;
723  cc->m_tempStrSize[service_num]++;
724  }
725  else
726  {
727  cc->m_tempStrSize[service_num] = 0;
728  cc->m_tempStrAlloc[service_num]=0;
729  }
730 }
731 
732 ushort CCtableG0[0x60] =
733 {
734 // 0 1 2 3 4 5 6 7
735 // 8 9 a b c d e f
736  ' ', '!','\"', '#', '$', '%', '&', '\'', /* 0x20-0x27 */
737  '(', ')', '*', '+', ',', '-', '.', '/', /* 0x28-0x2f */
738  '0', '1', '2', '3', '4', '5', '6', '7', /* 0x30-0x37 */
739  '8', '9', ':', ';', '<', '=', '>', '?', /* 0x38-0x3f */
740 
741  '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 0x40-0x47 */
742  'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 0x48-0x4f */
743  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 0x50-0x57 */
744  'X', 'Y', 'Z', '[', '\\',']', '^', '_', /* 0x58-0x5f */
745 
746  '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 0x60-0x67 */
747  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 0x68-0x6f */
748  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 0x70-0x77 */
749  'x', 'y', 'z', '{', '|', '}', '~', 0x266a, // music note/* 0x78-0x7f */
750 };
751 
752 ushort CCtableG1[0x60] =
753 {
754 // 0 1 2 3
755 // 4 5 6 7
756 // 8 9 a b
757 // c d e f
758  0xA0, // unicode non-breaking space
759  0xA1 /* ¡ */, 0xA2 /* ¢ */, 0xA3 /* £ */,
760  0xA4 /* ¤ */, 0xA5 /* ¥ */, 0xA6 /* ¦ */, 0xA7 /* § */,
761  0xA8 /* ¨ */, 0xA9 /* © */, 0xAA /* ª */, 0xAB /* « */,
762  0xAC /* ¬ */, 0xAD /* ­ */, 0xAE /* ® */, 0xAF /* ¯ */,
763  0xB0 /* ° */, 0xB1 /* ± */, 0xB2 /* ² */, 0xB3 /* ³ */,
764  0xB4 /* ´ */, 0xB5 /* µ */, 0xB6 /* ¶ */, 0xB7 /* · */,
765  0xB8 /* ¸ */, 0xB9 /* ¹ */, 0xBA /* º */, 0xBB /* » */,
766  0xBC /* ¼ */, 0xBD /* ½ */, 0xBE /* ¾ */, 0xBF /* ¿ */,
767 
768  0xC0 /* À */, 0xC1 /* Á */, 0xC2 /* Â */, 0xC3 /* Ã */,
769  0xC4 /* Ä */, 0xC5 /* Å */, 0xC6 /* Æ */, 0xC7 /* Ç */,
770  0xC8 /* È */, 0xC9 /* É */, 0xCA /* Ê */, 0xCB /* Ë */,
771  0xCC /* Ì */, 0xCD /* Í */, 0xCE /* Î */, 0xCF /* Ï */,
772  0xD0 /* Ð */, 0xD1 /* Ñ */, 0xD2 /* Ò */, 0xD3 /* Ó */,
773  0xD4 /* Ô */, 0xD5 /* Õ */, 0xD6 /* Ö */, 0xD7 /* × */,
774  0xD8 /* Ø */, 0xD9 /* Ù */, 0xDA /* Ú */, 0xDB /* Û */,
775  0xDC /* Ü */, 0xDD /* Ý */, 0xDE /* Þ */, 0xDF /* ß */,
776 
777  0xE0 /* à */, 0xE1 /* á */, 0xE2 /* â */, 0xE3 /* ã */,
778  0xE4 /* ä */, 0xE5 /* å */, 0xE6 /* æ */, 0xE7 /* ç */,
779  0xE8 /* è */, 0xE9 /* é */, 0xEA /* ê */, 0xEB /* ë */,
780  0xEC /* ì */, 0xED /* í */, 0xEE /* î */, 0xEF /* ï */,
781  0xF0 /* ð */, 0xF1 /* ñ */, 0xF2 /* ò */, 0xF3 /* ó */,
782  0xF4 /* ô */, 0xF5 /* õ */, 0xF6 /* ö */, 0xF7 /* ÷ */,
783  0xF8 /* ø */, 0xF9 /* ù */, 0xFA /* ú */, 0xFB /* û */,
784  0xFC /* ü */, 0xFD /* ý */, 0xFE /* þ */, 0xFF /* ÿ */,
785 };
786 
787 ushort CCtableG2[0x60] =
788 {
789  ' ', /* transparent space */
790  0xA0, /* non-breaking transparent space */
791  0, 0, /* 0x20-0x23 */
792  0, 0x2026,/* elipsis */
793  0, 0, /* 0x24-0x27 */
794  0, 0,
795  0x160,/*S under \/ */0, /* 0x28-0x2b */
796  0x152, /* CE */ 0,
797  0, 0, /* 0x2c-0x2f */
798  0x2588,/*block*/ 0x2018,/* open ' */
799  0x2019,/*close ' */ 0x201c,/* open " */ /* 0x30-0x33 */
800  0x201d,/*close " */ 0xB7,/* dot */
801  0, 0, /* 0x34-0x37 */
802  0, 0x2122,/* super TM */
803  0x161,/*s under \/ */0, /* 0x38-0x3b */
804  0x153, /* ce */ 0x2120,/* super SM */
805  0, 0x178,/*Y w/umlout*/ /* 0x3c-0x3f */
806 
807 // 0 1 2 3
808 // 4 5 6 7
809 // 8 9 a b
810 // c d e f
811  0, 0, 0, 0,
812  0, 0, 0, 0, /* 0x40-0x47 */
813  0, 0, 0, 0,
814  0, 0, 0, 0, /* 0x48-0x4f */
815 
816  0, 0, 0, 0,
817  0, 0, 0, 0, /* 0x50-0x57 */
818  0, 0, 0, 0,
819  0, 0, 0, 0, /* 0x58-0x5f */
820 
821  0, 0, 0, 0,
822  0, 0, 0, 0, /* 0x60-0x67 */
823  0, 0, 0, 0,
824  0, 0, 0, 0, /* 0x68-0x6f */
825 
826  0, 0,
827  0, 0, /* 0x70-0x73 */
828  0, 0,
829  0x215b, /* 1/8 */ 0x215c, /* 3/8 */ /* 0x74-0x77 */
830  0x215d, /* 5/8 */ 0x215e, /* 7/8 */
831  0x2502, /*line | */ 0x2510, /*line ~| */ /* 0x78-0x7b */
832  0x2514, /*line |_*/ 0x2500, /*line -*/
833  0x2518, /*line _|*/ 0x250c, /*line |~ */ /* 0x7c-0x7f */
834 };
835 
836 ushort CCtableG3[0x60] =
837 {
838 // 0 1 2 3 4 5 6 7 8 9 a b c d e f
839  '#', /* [CC] closed captioning logo */
840  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xaf */
841  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0-0xbf */
842 
843  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0-0xcf */
844  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0-0xdf */
845 
846  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0-0xff */
847  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0-0xff */
848 };
ushort CCtableG0[0x60]
Definition: cc.h:13
void services(uint seconds, bool seen[64]) const
time_t m_lastSeen[64]
Definition: cc708decoder.h:43
CaptionPacket m_partialPacket
Definition: cc708decoder.h:41
kCCTypes
const char * cc_types[4]
C0
EIA-708-A closed caption packet.
Definition: cc708decoder.h:15
#define LOC
unsigned char data[128+16]
Definition: cc708decoder.h:17
static int handle_cc_c1(CC708Reader *cc, uint service_num, int i)
#define SEND_STR
C1
static int handle_cc_c2(CC708Reader *cc, uint service_num, int i)
ushort CCtableG1[0x60]
unsigned int block_size
static void parse_cc_service_stream(CC708Reader *cc, uint service_num)
static int handle_cc_c0_ext1_p16(CC708Reader *cc, uint service_num, int i)
CC708Reader * m_reader
Definition: cc708decoder.h:42
ushort CCtableG2[0x60]
void decode_cc_null(void)
unsigned int uint
Definition: compat.h:140
ushort CCtableG3[0x60]
static bool rightsize_buf(CC708Reader *cc, uint service_num, uint block_size)
void decode_cc_data(uint cc_type, uint data1, uint data2)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static int x0
Definition: mythsocket.cpp:59
static void append_cc(CC708Reader *cc, uint service_num, const unsigned char *blk_buf, int block_size)
static void append_character(CC708Reader *cc, uint service_num, short ch)
static int handle_cc_c3(CC708Reader *cc, uint service_num, int i)
static int x3
Definition: mythsocket.cpp:62
static void parse_cc_packet(CC708Reader *cb_cbs, CaptionPacket *pkt, time_t last_seen[64])
static int x1
Definition: mythsocket.cpp:60