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