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 "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_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 std::array<const std::string, 4> cc_types =
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 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  if (code<=0xf)
311  {
312  // single byte code
313  if (ETX==code)
314  SEND_STR;
315  else if (BS==code)
316  append_character(cc, service_num, 0x08);
317  else if (FF==code)
318  append_character(cc, service_num, 0x0c);
319  else if ((CR==code) || (HCR==code))
320  append_character(cc, service_num, 0x0d);
321  i++;
322  }
323  else if (code<=0x17)
324  {
325  // double byte code
326  const int blk_size = cc->m_bufSize[service_num];
327  if (EXT1==code && ((i+1)<blk_size))
328  {
329  const int code2 = cc->m_buf[service_num][i+1];
330  if (code2<=0x1f)
331  {
332  // C2 code -- nothing in EIA-708-A
333  i = handle_cc_c2(cc, service_num, i);
334  }
335  else if (code2<=0x7f)
336  {
337  // G2 code -- fractions, drawing, symbols
338  append_character(cc, service_num, CCtableG2[code2-0x20]);
339  i+=2;
340  }
341  else if (code2<=0x9f)
342  {
343  // C3 code -- nothing in EIA-708-A
344  i = handle_cc_c3(cc, service_num, i);
345  }
346  else if (code2<=0xff)
347  {
348  // G3 code -- one symbol in EIA-708-A "[cc]"
349  append_character(cc, service_num, CCtableG3[code2-0xA0]);
350  i+=2;
351  }
352  }
353  else if ((i+1)<blk_size)
354  i+=2;
355  }
356  else if (code<=0x1f)
357  {
358  // triple byte code
359  const int blk_size = cc->m_bufSize[service_num];
360  if (P16==code && ((i+2)<blk_size))
361  {
362  // reserved for large alphabets, but not yet defined
363  }
364  if ((i+2)<blk_size)
365  i+=3;
366  }
367  return i;
368 }
369 
370 static int handle_cc_c1(CC708Reader* cc, uint service_num, int i)
371 {
372  const int blk_size = cc->m_bufSize[service_num];
373  const int code = cc->m_buf[service_num][i];
374 
375  const unsigned char* blk_buf = cc->m_buf[service_num];
376  if (code<=CW7)
377  { // no paramaters
378  SEND_STR;
379  cc->SetCurrentWindow(service_num, code-0x80);
380  i+=1;
381  }
382  else if (DLC == cc->m_buf[service_num][i])
383  {
384 /* processed out-of-band
385  cc->DelayCancel(service_num);
386  cc->m_delayed[service_num] = 0;
387 */
388  i+=1;
389  }
390  else if (code>=CLW && code<=DLY && ((i+1)<blk_size))
391  { // 1 byte of paramaters
392  int param1 = blk_buf[i+1];
393  SEND_STR;
394  if (CLW==code)
395  cc->ClearWindows(service_num, param1);
396  else if (DSW==code)
397  cc->DisplayWindows(service_num, param1);
398  else if (HDW==code)
399  cc->HideWindows(service_num, param1);
400  else if (TGW==code)
401  cc->ToggleWindows(service_num, param1);
402  else if (DLW==code)
403  cc->DeleteWindows(service_num, param1);
404  else if (DLY==code)
405  {
406  cc->Delay(service_num, param1);
407  cc->m_delayed[service_num] = true;
408  }
409  i+=2;
410  }
411  else if (SPA==code && ((i+2)<blk_size))
412  {
413  int pen_size = (blk_buf[i+1] ) & 0x3;
414  int offset = (blk_buf[i+1]>>2) & 0x3;
415  int text_tag = (blk_buf[i+1]>>4) & 0xf;
416  int font_tag = (blk_buf[i+2] ) & 0x7;
417  int edge_type = (blk_buf[i+2]>>3) & 0x7;
418  int underline = (blk_buf[i+2]>>6) & 0x1;
419  int italic = (blk_buf[i+2]>>7) & 0x1;
420  SEND_STR;
421  cc->SetPenAttributes(service_num, pen_size, offset, text_tag,
422  font_tag, edge_type, underline, italic);
423  i+=3;
424  }
425  else if (SPC==code && ((i+3)<blk_size))
426  {
427  int fg_color = (blk_buf[i+1] ) & 0x3f;
428  int fg_opacity = (blk_buf[i+1]>>6) & 0x03;
429  int bg_color = (blk_buf[i+2] ) & 0x3f;
430  int bg_opacity = (blk_buf[i+2]>>6) & 0x03;
431  int edge_color = (blk_buf[i+3]>>6) & 0x3f;
432  SEND_STR;
433  cc->SetPenColor(service_num, fg_color, fg_opacity,
434  bg_color, bg_opacity, edge_color);
435  i+=4;
436  }
437  else if (SPL==code && ((i+2)<blk_size))
438  {
439  int row = blk_buf[i+1] & 0x0f;
440  int col = blk_buf[i+2] & 0x3f;
441  SEND_STR;
442  cc->SetPenLocation(service_num, row, col);
443  i+=3;
444  }
445  else if (SWA==code && ((i+4)<blk_size))
446  {
447  int fill_color = (blk_buf[i+1] ) & 0x3f;
448  int fill_opacity = (blk_buf[i+1]>>6) & 0x03;
449  int border_color = (blk_buf[i+2] ) & 0x3f;
450  int border_type01 = (blk_buf[i+2]>>6) & 0x03;
451  int justify = (blk_buf[i+3] ) & 0x03;
452  int scroll_dir = (blk_buf[i+3]>>2) & 0x03;
453  int print_dir = (blk_buf[i+3]>>4) & 0x03;
454  int word_wrap = (blk_buf[i+3]>>6) & 0x01;
455  int border_type = (blk_buf[i+3]>>5) | border_type01;
456  int display_eff = (blk_buf[i+4] ) & 0x03;
457  int effect_dir = (blk_buf[i+4]>>2) & 0x03;
458  int effect_speed = (blk_buf[i+4]>>4) & 0x0f;
459  SEND_STR;
460  cc->SetWindowAttributes(
461  service_num, fill_color, fill_opacity, border_color, border_type,
462  scroll_dir, print_dir, effect_dir,
463  display_eff, effect_speed, justify, word_wrap);
464  i+=5;
465  }
466  else if ((code>=DF0) && (code<=DF7) && ((i+6)<blk_size))
467  {
468  // param1
469  int priority = ( blk_buf[i+1] ) & 0x7;
470  int col_lock = (blk_buf[i+1]>>3) & 0x1;
471  int row_lock = (blk_buf[i+1]>>4) & 0x1;
472  bool visible = ((blk_buf[i+1]>>5) & 0x1) != 0;
473  // param2
474  int anchor_vertical = blk_buf[i+2] & 0x7f;
475  int relative_pos = (blk_buf[i+2]>>7);
476  // param3
477  int anchor_horizontal = blk_buf[i+3];
478  // param4
479  int row_count = blk_buf[i+4] & 0xf;
480  int anchor_point = blk_buf[i+4]>>4;
481  // param5
482  int col_count = blk_buf[i+5] & 0x3f;
483  // param6
484  int pen_style = blk_buf[i+6] & 0x7;
485  int win_style = (blk_buf[i+6]>>3) & 0x7;
486  SEND_STR;
487  cc->DefineWindow(service_num, code-0x98, priority, visible,
488  anchor_point, relative_pos,
489  anchor_vertical, anchor_horizontal,
490  row_count, col_count, row_lock, col_lock,
491  pen_style, win_style);
492  i+=7;
493  }
494 #if DEBUG_CC_SERVICE
495  else
496  {
497  LOG(VB_VBI, LOG_ERR, QString("handle_cc_c1: (NOT HANDLED) "
498  "code(0x%1) i(%2) blk_size(%3)").arg(code, 2, 16, QLatin1Char('0'))
499  .arg(i).arg(blk_size));
500  }
501 #endif
502 
503  return i;
504 }
505 
506 static int handle_cc_c2(CC708Reader* cc, uint service_num, int i)
507 {
508  const int blk_size = cc->m_bufSize[service_num];
509  const int code = cc->m_buf[service_num][i+1];
510 
511  if ((code<=0x7) && ((i+1)<blk_size)){
512  i+=2;
513  SEND_STR;
514  }
515  else if ((code<=0xf) && ((i+2)<blk_size))
516  {
517  i+=3;
518  SEND_STR;
519  }
520  else if ((code<=0x17) && ((i+3)<blk_size))
521  {
522  i+=4;
523  SEND_STR;
524  }
525  else if ((code<=0x1f) && ((i+4)<blk_size))
526  {
527  i+=5;
528  SEND_STR;
529  }
530  return i;
531 }
532 
533 static int handle_cc_c3(CC708Reader* cc, uint service_num, int i)
534 {
535  const unsigned char* blk_buf = cc->m_buf[service_num];
536  const int blk_size = cc->m_bufSize[service_num];
537  const int code = cc->m_buf[service_num][i+1];
538 
539  if ((code<=0x87) && ((i+5)<blk_size))
540  {
541  i+=6;
542  SEND_STR;
543  }
544  else if ((code<=0x8f) && ((i+6)<blk_size))
545  {
546  i+=7;
547  SEND_STR;
548  }
549  else if ((i+2)<blk_size)
550  { // varible length commands
551  int length = blk_buf[i+2]&0x3f;
552  if ((i+length)<blk_size)
553  {
554  i+=1+length;
555  SEND_STR;
556  }
557  }
558  return i;
559 }
560 
561 static bool rightsize_buf(CC708Reader* cc, uint service_num, uint block_size)
562 {
563  size_t min_new_size = block_size + cc->m_bufSize[service_num];
564  bool ret = true;
565  if (min_new_size >= cc->m_bufAlloc[service_num])
566  {
567  size_t new_alloc = cc->m_bufAlloc[service_num];
568  for (uint i = 0; (i < 32) && (new_alloc <= min_new_size); i++)
569  new_alloc *= 2;
570  void *new_buf = realloc(cc->m_buf[service_num], new_alloc);
571  if (new_buf)
572  {
573  cc->m_buf[service_num] = (uchar *)new_buf;
574  cc->m_bufAlloc[service_num] = new_alloc;
575  }
576  else
577  {
578  ret = false;
579  }
580 
581 #if DEBUG_CC_SERVICE_2
582  LOG(VB_VBI, LOG_DEBUG, QString("rightsize_buf: srv %1 to %1 bytes")
583  .arg(service_num) .arg(cc->m_bufAlloc[service_num]));
584 #endif
585  }
586  if (min_new_size >= cc->m_bufAlloc[service_num])
587  {
588  LOG(VB_VBI, LOG_ERR,
589  QString("buffer resize error: min_new_size=%1, buf_alloc[%2]=%3")
590  .arg(min_new_size)
591  .arg(service_num)
592  .arg(cc->m_bufAlloc[service_num]));
593  }
594  return ret;
595 }
596 
597 static void append_cc(CC708Reader* cc, uint service_num,
598  const unsigned char* blk_buf, int block_size)
599 {
600  if (!rightsize_buf(cc, service_num, block_size))
601  {
602  // The buffer resize failed. Drop the new data.
603  return;
604  }
605 
606  memcpy(cc->m_buf[service_num] + cc->m_bufSize[service_num],
607  blk_buf, block_size);
608 
609  cc->m_bufSize[service_num] += block_size;
610 #if DEBUG_CC_SERVICE_2
611  {
612  uint i;
613  QString msg("append_cc: ");
614  for (i = 0; i < cc->m_bufSize[service_num]; i++)
615  msg += QString("0x%1").arg(cc->m_buf[service_num][i], 0, 16);
616  LOG(VB_VBI, LOG_DEBUG, msg);
617  }
618 #endif
619  parse_cc_service_stream(cc, service_num);
620 }
621 
622 static void parse_cc_packet(CC708Reader* cb_cbs, CaptionPacket* pkt,
623  time_t last_seen[64])
624 {
625  const unsigned char* pkt_buf = pkt->data;
626  const int pkt_size = pkt->size;
627  int off = 1;
628  int len = ((((int)pkt_buf[0]) & 0x3f)<<1) - 1;
629 
630  if (len < 0)
631  return;
632 
633 #if DEBUG_CC_RAWPACKET
634  if (true)
635 #elif DEBUG_CAPTIONS
636  if (len > pkt_size)
637 #else
638  if (false) // NOLINT(readability-simplify-boolean-expr)
639 #endif
640  {
641  int srv = (pkt_buf[off]>>5) & 0x7;
642  int seq_num = (((int)pkt_buf[0])>>6)&0x3;
643  QString msg = QString("CC708 len %1 srv0 %2 seq %3 ").arg(len, 2)
644  .arg(srv) .arg(seq_num);
645  for (int j = 0; j < pkt_size; j++)
646  msg += QString("0x%1").arg(pkt_buf[j], 0, 16);
647  LOG(VB_VBI, LOG_DEBUG, msg);
648  }
649 
650  if (pkt_size >= 127)
651  LOG(VB_VBI, LOG_ERR,
652  QString("Unexpected pkt_size=%1").arg(pkt_size));
653 
654  while (off < pkt_size && pkt_buf[off])
655  { // service_block
656  int block_size = pkt_buf[off] & 0x1f;
657  int service_number = (pkt_buf[off]>>5) & 0x7;
658  int block_data_offset = (0x7==service_number && block_size!=0) ?
659  off+2 : off+1;
660 #if DEBUG_CC_SERVICE_BLOCK
661  LOG(VB_VBI, LOG_DEBUG,
662  QString("service_block size(%1) num(%2) off(%3)")
663  .arg(block_size) .arg(service_number) .arg(block_data_offset));
664 #endif
665  if (off+2 == block_data_offset)
666  {
667  int extended_service_number = pkt_buf[off+2] & 0x3f;
668 #if DEBUG_CC_SERVICE_BLOCK
669  LOG(VB_VBI, LOG_DEBUG, QString("ext_svc_num(%1)")
670  .arg(extended_service_number));
671 #endif
672  service_number = extended_service_number;
673  }
674  if (service_number)
675  {
676 #if DEBUG_CC_SERVICE
677  int i;
678  if (!(2==block_size &&
679  0==pkt_buf[block_data_offset] &&
680  0==pkt_buf[block_data_offset+1]))
681  {
682  QString msg = QString("service %1: ").arg(service_number);
683  for (i=0; i<block_size; i++)
684  msg += QString("0x%1 ")
685  .arg(pkt_buf[block_data_offset+i], 0, 16);
686  LOG(VB_VBI, LOG_DEBUG, msg);
687  }
688 #endif
689  append_cc(cb_cbs, service_number,
690  &pkt_buf[block_data_offset], block_size);
691 
692  last_seen[service_number] = time(nullptr);
693  }
694  off+=block_size+1;
695  }
696  if (off<pkt_size) // must end in null service block, if packet is not full.
697  {
698  if (pkt_buf[off] != 0)
699  {
700  LOG(VB_VBI, LOG_ERR,
701  QString("CEA-708 packet error: pkt_size=%1, pkt_buf[%2]=%3")
702  .arg(pkt_size).arg(off).arg(pkt_buf[off]));
703  }
704  }
705 }
706 
707 static void append_character(CC708Reader *cc, uint service_num, short ch)
708 {
709  if (cc->m_tempStrSize[service_num]+2 > cc->m_tempStrAlloc[service_num])
710  {
711  int new_alloc = (cc->m_tempStrAlloc[service_num]) ?
712  cc->m_tempStrAlloc[service_num] * 2 : 64;
713 
714  cc->m_tempStr[service_num] = (short*)
715  realloc(cc->m_tempStr[service_num], new_alloc * sizeof(short));
716 
717  cc->m_tempStrAlloc[service_num] = new_alloc; // shorts allocated
718  }
719 
720  if (cc->m_tempStr[service_num])
721  {
722  int i = cc->m_tempStrSize[service_num];
723  cc->m_tempStr[service_num][i] = ch;
724  cc->m_tempStrSize[service_num]++;
725  }
726  else
727  {
728  cc->m_tempStrSize[service_num] = 0;
729  cc->m_tempStrAlloc[service_num]=0;
730  }
731 }
732 
734 {
735 // 0 1 2 3 4 5 6 7
736 // 8 9 a b c d e f
737  ' ', '!','\"', '#', '$', '%', '&', '\'', /* 0x20-0x27 */
738  '(', ')', '*', '+', ',', '-', '.', '/', /* 0x28-0x2f */
739  '0', '1', '2', '3', '4', '5', '6', '7', /* 0x30-0x37 */
740  '8', '9', ':', ';', '<', '=', '>', '?', /* 0x38-0x3f */
741 
742  '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 0x40-0x47 */
743  'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 0x48-0x4f */
744  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 0x50-0x57 */
745  'X', 'Y', 'Z', '[', '\\',']', '^', '_', /* 0x58-0x5f */
746 
747  '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 0x60-0x67 */
748  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 0x68-0x6f */
749  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 0x70-0x77 */
750  'x', 'y', 'z', '{', '|', '}', '~', 0x266a, // music note/* 0x78-0x7f */
751 };
752 
754 {
755 // 0 1 2 3
756 // 4 5 6 7
757 // 8 9 a b
758 // c d e f
759  0xA0, // unicode non-breaking space
760  0xA1 /* ¡ */, 0xA2 /* ¢ */, 0xA3 /* £ */,
761  0xA4 /* ¤ */, 0xA5 /* ¥ */, 0xA6 /* ¦ */, 0xA7 /* § */,
762  0xA8 /* ¨ */, 0xA9 /* © */, 0xAA /* ª */, 0xAB /* « */,
763  0xAC /* ¬ */, 0xAD /* ­ */, 0xAE /* ® */, 0xAF /* ¯ */,
764  0xB0 /* ° */, 0xB1 /* ± */, 0xB2 /* ² */, 0xB3 /* ³ */,
765  0xB4 /* ´ */, 0xB5 /* µ */, 0xB6 /* ¶ */, 0xB7 /* · */,
766  0xB8 /* ¸ */, 0xB9 /* ¹ */, 0xBA /* º */, 0xBB /* » */,
767  0xBC /* ¼ */, 0xBD /* ½ */, 0xBE /* ¾ */, 0xBF /* ¿ */,
768 
769  0xC0 /* À */, 0xC1 /* Á */, 0xC2 /* Â */, 0xC3 /* Ã */,
770  0xC4 /* Ä */, 0xC5 /* Å */, 0xC6 /* Æ */, 0xC7 /* Ç */,
771  0xC8 /* È */, 0xC9 /* É */, 0xCA /* Ê */, 0xCB /* Ë */,
772  0xCC /* Ì */, 0xCD /* Í */, 0xCE /* Î */, 0xCF /* Ï */,
773  0xD0 /* Ð */, 0xD1 /* Ñ */, 0xD2 /* Ò */, 0xD3 /* Ó */,
774  0xD4 /* Ô */, 0xD5 /* Õ */, 0xD6 /* Ö */, 0xD7 /* × */,
775  0xD8 /* Ø */, 0xD9 /* Ù */, 0xDA /* Ú */, 0xDB /* Û */,
776  0xDC /* Ü */, 0xDD /* Ý */, 0xDE /* Þ */, 0xDF /* ß */,
777 
778  0xE0 /* à */, 0xE1 /* á */, 0xE2 /* â */, 0xE3 /* ã */,
779  0xE4 /* ä */, 0xE5 /* å */, 0xE6 /* æ */, 0xE7 /* ç */,
780  0xE8 /* è */, 0xE9 /* é */, 0xEA /* ê */, 0xEB /* ë */,
781  0xEC /* ì */, 0xED /* í */, 0xEE /* î */, 0xEF /* ï */,
782  0xF0 /* ð */, 0xF1 /* ñ */, 0xF2 /* ò */, 0xF3 /* ó */,
783  0xF4 /* ô */, 0xF5 /* õ */, 0xF6 /* ö */, 0xF7 /* ÷ */,
784  0xF8 /* ø */, 0xF9 /* ù */, 0xFA /* ú */, 0xFB /* û */,
785  0xFC /* ü */, 0xFD /* ý */, 0xFE /* þ */, 0xFF /* ÿ */,
786 };
787 
789 {
790  ' ', /* transparent space */
791  0xA0, /* non-breaking transparent space */
792  0, 0, /* 0x20-0x23 */
793  0, 0x2026,/* elipsis */
794  0, 0, /* 0x24-0x27 */
795  0, 0,
796  0x160,/*S under \/ */0, /* 0x28-0x2b */
797  0x152, /* CE */ 0,
798  0, 0, /* 0x2c-0x2f */
799  0x2588,/*block*/ 0x2018,/* open ' */
800  0x2019,/*close ' */ 0x201c,/* open " */ /* 0x30-0x33 */
801  0x201d,/*close " */ 0xB7,/* dot */
802  0, 0, /* 0x34-0x37 */
803  0, 0x2122,/* super TM */
804  0x161,/*s under \/ */0, /* 0x38-0x3b */
805  0x153, /* ce */ 0x2120,/* super SM */
806  0, 0x178,/*Y w/umlout*/ /* 0x3c-0x3f */
807 
808 // 0 1 2 3
809 // 4 5 6 7
810 // 8 9 a b
811 // c d e f
812  0, 0, 0, 0,
813  0, 0, 0, 0, /* 0x40-0x47 */
814  0, 0, 0, 0,
815  0, 0, 0, 0, /* 0x48-0x4f */
816 
817  0, 0, 0, 0,
818  0, 0, 0, 0, /* 0x50-0x57 */
819  0, 0, 0, 0,
820  0, 0, 0, 0, /* 0x58-0x5f */
821 
822  0, 0, 0, 0,
823  0, 0, 0, 0, /* 0x60-0x67 */
824  0, 0, 0, 0,
825  0, 0, 0, 0, /* 0x68-0x6f */
826 
827  0, 0,
828  0, 0, /* 0x70-0x73 */
829  0, 0,
830  0x215b, /* 1/8 */ 0x215c, /* 3/8 */ /* 0x74-0x77 */
831  0x215d, /* 5/8 */ 0x215e, /* 7/8 */
832  0x2502, /*line | */ 0x2510, /*line ~| */ /* 0x78-0x7b */
833  0x2514, /*line |_*/ 0x2500, /*line -*/
834  0x2518, /*line _|*/ 0x250c, /*line |~ */ /* 0x7c-0x7f */
835 };
836 
838 {
839 // 0 1 2 3 4 5 6 7 8 9 a b c d e f
840  '#', /* [CC] closed captioning logo */
841  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xaf */
842  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0-0xbf */
843 
844  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0-0xcf */
845  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0-0xdf */
846 
847  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0-0xff */
848  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0-0xff */
849 };
C0
C0
Definition: cc708decoder.cpp:87
FF
@ FF
Definition: cc708decoder.cpp:91
CCtableG3
const cc_table CCtableG3
Definition: cc708decoder.cpp:837
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:561
HCR
@ HCR
Definition: cc708decoder.cpp:93
CLW
@ CLW
Definition: cc708decoder.cpp:101
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:506
parse_cc_packet
static void parse_cc_packet(CC708Reader *cb_cbs, CaptionPacket *pkt, time_t last_seen[64])
Definition: cc708decoder.cpp:622
cc708decoder.h
BS
@ BS
Definition: cc708decoder.cpp:90
NTSC_CC_f1
@ NTSC_CC_f1
Definition: cc708decoder.cpp:23
cc_types
const std::array< const std::string, 4 > cc_types
Definition: cc708decoder.cpp:29
cc
Definition: cc.h:10
arg
arg(title).arg(filename).arg(doDelete))
CC708Decoder::services
void services(uint seconds, bool seen[64]) const
Definition: cc708decoder.cpp:76
kCCTypes
kCCTypes
Definition: cc708decoder.cpp:22
x0
static int x0
Definition: mythsocket.cpp:59
CC708Decoder::decode_cc_data
void decode_cc_data(uint cc_type, uint data1, uint data2)
Definition: cc708decoder.cpp:40
x3
static int x3
Definition: mythsocket.cpp:62
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
ETX
@ ETX
Definition: cc708decoder.cpp:89
CW5
@ CW5
Definition: cc708decoder.cpp:100
CC708Decoder::m_lastSeen
time_t m_lastSeen[64]
Definition: cc708decoder.h:43
DTVCC_PACKET_DATA
@ DTVCC_PACKET_DATA
Definition: cc708decoder.cpp:25
SPC
@ SPC
Definition: cc708decoder.cpp:102
DSW
@ DSW
Definition: cc708decoder.cpp:101
CCtableG0
const cc_table CCtableG0
Definition: cc708decoder.cpp:733
cc_table
std::array< const uint16_t, 0x60 > cc_table
Definition: cc708decoder.cpp:106
CC708Decoder::m_reader
CC708Reader * m_reader
Definition: cc708decoder.h:42
append_cc
static void append_cc(CC708Reader *cc, uint service_num, const unsigned char *blk_buf, int block_size)
Definition: cc708decoder.cpp:597
CW4
@ CW4
Definition: cc708decoder.cpp:100
mythlogging.h
SPA
@ SPA
Definition: cc708decoder.cpp:102
CaptionPacket::size
int size
Definition: cc708decoder.h:18
DF6
@ DF6
Definition: cc708decoder.cpp:103
x1
static int x1
Definition: mythsocket.cpp:60
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
C1
C1
Definition: cc708decoder.cpp:99
CC708Decoder::m_partialPacket
CaptionPacket m_partialPacket
Definition: cc708decoder.h:41
CCtableG2
const cc_table CCtableG2
Definition: cc708decoder.cpp:788
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:140
NTSC_CC_f2
@ NTSC_CC_f2
Definition: cc708decoder.cpp:24
LOC
#define LOC
Definition: cc708decoder.cpp:11
block_size
unsigned int block_size
Definition: freesurround.cpp:48
CR
@ CR
Definition: cc708decoder.cpp:92
CaptionPacket::data
unsigned char data[128+16]
Definition: cc708decoder.h:17
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:533
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:707
CW1
@ CW1
Definition: cc708decoder.cpp:100
CC708Decoder::decode_cc_null
void decode_cc_null(void)
Definition: cc708decoder.cpp:69
CCtableG1
const cc_table CCtableG1
Definition: cc708decoder.cpp:753
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
handle_cc_c1
static int handle_cc_c1(CC708Reader *cc, uint service_num, int i)
Definition: cc708decoder.cpp:370
CaptionPacket
EIA-708-A closed caption packet.
Definition: cc708decoder.h:16
CW3
@ CW3
Definition: cc708decoder.cpp:100
CC708Reader
Definition: cc708reader.h:17
DTVCC_PACKET_START
@ DTVCC_PACKET_START
Definition: cc708decoder.cpp:26
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