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