MythTV  0.26-pre
cc708decoder.cpp
Go to the documentation of this file.
00001 // -*- Mode: c++ -*-
00002 // Copyright (c) 2003-2005, Daniel Kristjansson
00003 
00004 #include <cstdlib>
00005 #include <stdio.h>
00006 
00007 #include "mythlogging.h"
00008 #include "cc708reader.h"
00009 #include "cc708decoder.h"
00010 
00011 #define LOC QString("CC708: ")
00012 
00013 #define DEBUG_CAPTIONS         0
00014 #define DEBUG_CC_SERVICE       0
00015 #define DEBUG_CC_SERVICE_2     0
00016 #define DEBUG_CC_RAWPACKET     0
00017 #define DEBUG_CC_VALIDPACKET   0
00018 #define DEBUG_CC_SERVICE_BLOCK 0
00019 
00020 typedef enum
00021 {
00022     NTSC_CC_f1         = 0,
00023     NTSC_CC_f2         = 1,
00024     DTVCC_PACKET_DATA  = 2,
00025     DTVCC_PACKET_START = 3,
00026 } kCCTypes;
00027 
00028 const char* cc_types[4] =
00029 {
00030     "NTSC line 21 field 1 closed captions"
00031     "NTSC line 21 field 2 closed captions"
00032     "DTVCC Channel Packet Data"
00033     "DTVCC Channel Packet Start"
00034 };
00035 
00036 static void parse_cc_packet(CC708Reader *cb_cbs, CaptionPacket *pkt,
00037                             time_t last_seen[64]);
00038 
00039 void CC708Decoder::decode_cc_data(uint cc_type, uint data1, uint data2)
00040 {
00041     if (DTVCC_PACKET_START == cc_type)
00042     {
00043 #if 0
00044         LOG(VB_VBI, LOG_DEBUG, LOC + QString("CC ST data(0x%1 0x%2)")
00045                 .arg(data1,0,16).arg(data2,0,16));
00046 #endif
00047 
00048         if (partialPacket.size && reader)
00049             parse_cc_packet(reader, &partialPacket, last_seen);
00050 
00051         partialPacket.data[0] = data1;
00052         partialPacket.data[1] = data2;
00053         partialPacket.size   = 2;
00054     }
00055     else if (DTVCC_PACKET_DATA == cc_type)
00056     {
00057 #if 0
00058         LOG(VB_VBI, LOG_DEBUG, LOC + QString("CC Ex data(0x%1 0x%2)")
00059                 .arg(data1,0,16).arg(data2,0,16));
00060 #endif
00061 
00062         partialPacket.data[partialPacket.size + 0] = data1;
00063         partialPacket.data[partialPacket.size + 1] = data2;
00064         partialPacket.size += 2;
00065     }
00066 }
00067 
00068 void CC708Decoder::decode_cc_null(void)
00069 {
00070     if (partialPacket.size && reader)
00071         parse_cc_packet(reader, &partialPacket, last_seen);
00072     partialPacket.size = 0;
00073 }
00074 
00075 void CC708Decoder::services(uint seconds, bool seen[64]) const
00076 {
00077     time_t now = time(NULL);
00078     time_t then = now - seconds;
00079 
00080     seen[0] = false; // service zero is not allowed in CEA-708-D
00081     for (uint i = 1; i < 64; i++)
00082         seen[i] = (last_seen[i] >= then);
00083 }
00084 
00085 typedef enum
00086 {
00087     NUL  = 0x00,
00088     ETX  = 0x03,
00089     BS   = 0x08,
00090     FF   = 0x0C,
00091     CR   = 0x0D,
00092     HCR  = 0x0E,
00093     EXT1 = 0x10,
00094     P16  = 0x18,
00095 } C0;
00096 
00097 typedef enum
00098 {
00099     CW0=0x80, CW1, CW2, CW3, CW4, CW5, CW6, CW7,
00100     CLW,      DSW, HDW, TGW, DLW, DLY, DLC, RST,
00101     SPA=0x90, SPC, SPL,                     SWA=0x97,
00102     DF0,      DF1, DF2, DF3, DF4, DF5, DF6, DF7,
00103 } C1;
00104 
00105 extern ushort CCtableG0[0x60];
00106 extern ushort CCtableG1[0x60];
00107 extern ushort CCtableG2[0x60];
00108 extern ushort CCtableG3[0x60];
00109 
00110 static void append_character(CC708Reader *cc, uint service_num, short ch);
00111 static void parse_cc_service_stream(CC708Reader *cc, uint service_num);
00112 static int handle_cc_c0_ext1_p16(CC708Reader *cc, uint service_num, int i);
00113 static int handle_cc_c1(CC708Reader *cc, uint service_num, int i);
00114 static int handle_cc_c2(CC708Reader *cc, uint service_num, int i);
00115 static int handle_cc_c3(CC708Reader *cc, uint service_num, int i);
00116 
00117 #define SEND_STR \
00118 do { \
00119     if (cc->temp_str_size[service_num]) \
00120     { \
00121         cc->TextWrite(service_num, \
00122                       cc->temp_str[service_num], \
00123                       cc->temp_str_size[service_num]); \
00124         cc->temp_str_size[service_num] = 0; \
00125     } \
00126 } while (0)
00127 
00128 static void parse_cc_service_stream(CC708Reader* cc, uint service_num)
00129 {
00130     const int blk_size = cc->buf_size[service_num];
00131     int blk_start = 0, dlc_loc = 0, rst_loc = 0, i = 0;
00132 
00133     // find last reset or delay cancel in buffer
00134     for (i = 0; i < blk_size; i++)
00135     {
00136         switch (cc->buf[service_num][i]) {
00137             // Skip over parameters, since their bytes may coincide
00138             // with RST or DLC
00139             case CLW:
00140             case DLW:
00141             case DSW:
00142             case HDW:
00143             case TGW:
00144             case DLY:
00145                 i += 1;
00146                 break;
00147             case SPA:
00148             case SPL:
00149                 i += 2;
00150                 break;
00151             case SPC:
00152                 i += 3;
00153                 break;
00154             case SWA:
00155                 i += 4;
00156                 break;
00157             case DF0:
00158             case DF1:
00159             case DF2:
00160             case DF3:
00161             case DF4:
00162             case DF5:
00163             case DF6:
00164             case DF7:
00165                 i += 6;
00166                 break;
00167             // Detect RST or DLC bytes
00168             case RST:
00169                 rst_loc = dlc_loc = i;
00170                 break;
00171             case DLC:
00172                 dlc_loc = i;
00173                 break;
00174         }
00175     }
00176 
00177     // reset, process only data after reset
00178     if (rst_loc)
00179     {
00180         cc->Reset(service_num);
00181         cc->delayed[service_num] = 0; // Reset implicitly cancels delay
00182         blk_start = rst_loc + 1;
00183     }
00184 
00185     // if we have a delay cancel, cancel any delay
00186     if (dlc_loc && cc->delayed[service_num])
00187     {
00188         cc->DelayCancel(service_num);
00189         cc->delayed[service_num] = 0;
00190     }
00191 
00192     // cancel delay if the buffer is full
00193     if (cc->delayed[service_num] && blk_size >= 126)
00194     {
00195         cc->DelayCancel(service_num);
00196         cc->delayed[service_num] = 0;
00197         dlc_loc = blk_size - 1;
00198     }
00199 
00200 #if 0
00201     LOG(VB_VBI, LOG_ERR,
00202         QString("cc_ss delayed(%1) blk_start(%2) blk_size(%3)")
00203             .arg(cc->delayed) .arg(blk_start) .arg(blk_size));
00204 #endif
00205 
00206     for (i = (cc->delayed[service_num]) ? blk_size : blk_start;
00207          i < blk_size; )
00208     {
00209         const int old_i = i;
00210         const int code = cc->buf[service_num][i];
00211         if (0x0 == code)
00212         {
00213             i++;
00214         }
00215         else if (code <= 0x1f)
00216         {
00217             // C0 code -- ASCII commands + ext1: C2,C3,G2,G3 + p16: 16 chars
00218             i = handle_cc_c0_ext1_p16(cc, service_num, i);
00219         }
00220         else if (code <= 0x7f)
00221         {
00222             // G0 code -- mostly ASCII printables
00223             short character = CCtableG0[code-0x20];
00224             append_character(cc, service_num, character);
00225             i++;
00226             SEND_STR;
00227         }
00228         else if (code <= 0x9f)
00229         {
00230             // C1 code -- caption control codes
00231             i = handle_cc_c1(cc, service_num, i);
00232         }
00233         else if (code <= 0xff)
00234         {
00235             // G1 code -- ISO 8859-1 Latin 1 characters
00236             short character = CCtableG1[code-0xA0];
00237             append_character(cc, service_num, character);
00238             i++;
00239         }
00240 
00241 #if DEBUG_CC_SERVICE
00242         LOG(VB_VBI, LOG_DEBUG, QString("i %1, blk_size %2").arg(i)
00243                 .arg(blk_size));
00244 #endif
00245 
00246         // loop continuation check
00247         if (old_i == i)
00248         {
00249 #if DEBUG_CC_SERVICE
00250             LOG(VB_VBI, LOG_DEBUG, QString("old_i == i == %1").arg(i));
00251             QString msg;
00252             for (int j = 0; j < blk_size; j++)
00253                 msg += QString("0x%1 ").arg(cc->buf[service_num][j], 0, 16);
00254             LOG(VB_VBI, LOG_DEBUG, msg);
00255 #endif
00256             if (blk_size - i > 10)
00257             {
00258                 LOG(VB_VBI, LOG_INFO, "eia-708 decoding error...");
00259                 cc->Reset(service_num);
00260                 cc->delayed[service_num] = 0;
00261                 i = cc->buf_size[service_num];
00262             }
00263             // There must be an incomplete code in buffer...
00264             break;
00265         }
00266         else if (cc->delayed[service_num] && dlc_loc < i)
00267         {
00268             // delay in effect
00269             break;
00270         }
00271         else if (cc->delayed[service_num])
00272         {
00273             // this delay has already been canceled..
00274             cc->DelayCancel(service_num);
00275             cc->delayed[service_num] = 0;
00276         }
00277     }
00278 
00279     // get rid of remaining bytes...
00280     if ((blk_size - i) > 0)
00281     {
00282         memmove(cc->buf[service_num], cc->buf[service_num] + i,
00283                 blk_size - i);
00284         cc->buf_size[service_num] -= i;
00285     }
00286     else
00287     {
00288         if (0 != (blk_size - i))
00289         {
00290             LOG(VB_VBI, LOG_ERR, QString("buffer error i(%1) buf_size(%2)")
00291                 .arg(i).arg(blk_size));
00292             QString msg;
00293             for (i=0; i < blk_size; i++)
00294                 msg += QString("0x%1 ").arg(cc->buf[service_num][i], 0, 16);
00295             LOG(VB_VBI, LOG_ERR, msg);
00296         }
00297         cc->buf_size[service_num] = 0;
00298     }
00299 }
00300 
00301 static int handle_cc_c0_ext1_p16(CC708Reader* cc, uint service_num, int i)
00302 {
00303     // C0 code -- subset of ASCII misc. control codes
00304     const int code = cc->buf[service_num][i];
00305     if (code<=0xf)
00306     {
00307         // single byte code
00308         if (ETX==code)
00309             SEND_STR;
00310         else if (BS==code)
00311             append_character(cc, service_num, 0x08);
00312         else if (FF==code)
00313             append_character(cc, service_num, 0x0c);
00314         else if (CR==code)
00315             append_character(cc, service_num, 0x0d);
00316         else if (HCR==code)
00317             append_character(cc, service_num, 0x0d);
00318         i++;
00319     }
00320     else if (code<=0x17)
00321     {
00322         // double byte code
00323         const int blk_size = cc->buf_size[service_num];
00324         if (EXT1==code && ((i+1)<blk_size))
00325         {
00326             const int code2 = cc->buf[service_num][i+1];
00327             if (code2<=0x1f)
00328             {
00329                 // C2 code -- nothing in EIA-708-A
00330                 i = handle_cc_c2(cc, service_num, i+1);
00331             }
00332             else if (code2<=0x7f)
00333             {
00334                 // G2 code -- fractions, drawing, symbols
00335                 append_character(cc, service_num, CCtableG2[code2-0x20]);
00336                 i+=2;
00337             }
00338             else if (code2<=0x9f)
00339             {
00340                 // C3 code -- nothing in EIA-708-A
00341                 i = handle_cc_c3(cc, service_num, i);
00342             }
00343             else if (code2<=0xff)
00344             {
00345                 // G3 code -- one symbol in EIA-708-A "[cc]"
00346                 append_character(cc, service_num, CCtableG3[code2-0xA0]);
00347                 i+=2;
00348             }
00349         }
00350         else if ((i+1)<blk_size)
00351             i+=2;
00352     }
00353     else if (code<=0x1f)
00354     {
00355         // triple byte code
00356         const int blk_size = cc->buf_size[service_num];
00357         if (P16==code && ((i+2)<blk_size))
00358         {
00359             // reserved for large alphabets, but not yet defined
00360         }
00361         if ((i+2)<blk_size)
00362             i+=3;
00363     }
00364     return i;
00365 }
00366 
00367 static int handle_cc_c1(CC708Reader* cc, uint service_num, int i)
00368 {
00369     const int blk_size = cc->buf_size[service_num];
00370     const int code = cc->buf[service_num][i];
00371 
00372     const unsigned char* blk_buf = cc->buf[service_num];
00373     if (code<=CW7)
00374     { // no paramaters
00375         SEND_STR;
00376         cc->SetCurrentWindow(service_num, code-0x80);
00377         i+=1;
00378     }
00379     else if (DLC == cc->buf[service_num][i])
00380     {
00381 /* processed out-of-band
00382         cc->DelayCancel(service_num);
00383         cc->delayed[service_num] = 0;
00384 */
00385         i+=1;
00386     }
00387     else if (code>=CLW && code<=DLY && ((i+1)<blk_size))
00388     { // 1 byte of paramaters
00389         int param1 = blk_buf[i+1];
00390         SEND_STR;
00391         if (CLW==code)
00392             cc->ClearWindows(service_num, param1);
00393         else if (DSW==code)
00394             cc->DisplayWindows(service_num, param1);
00395         else if (HDW==code)
00396             cc->HideWindows(service_num, param1);
00397         else if (TGW==code)
00398             cc->ToggleWindows(service_num, param1);
00399         else if (DLW==code)
00400             cc->DeleteWindows(service_num, param1);
00401         else if (DLY==code)
00402         {
00403             cc->Delay(service_num, param1);
00404             cc->delayed[service_num] = 1;
00405         }
00406         i+=2;
00407     }
00408     else if (SPA==code && ((i+2)<blk_size))
00409     {
00410         int pen_size  = (blk_buf[i+1]   ) & 0x3;
00411         int offset    = (blk_buf[i+1]>>2) & 0x3;
00412         int text_tag  = (blk_buf[i+1]>>4) & 0xf;
00413         int font_tag  = (blk_buf[i+2]   ) & 0x7;
00414         int edge_type = (blk_buf[i+2]>>3) & 0x7;
00415         int underline = (blk_buf[i+2]>>6) & 0x1;
00416         int italic    = (blk_buf[i+2]>>7) & 0x1;
00417         SEND_STR;
00418         cc->SetPenAttributes(service_num, pen_size, offset, text_tag,
00419                              font_tag, edge_type, underline, italic);
00420         i+=3;
00421     }
00422     else if (SPC==code && ((i+3)<blk_size))
00423     {
00424         int fg_color   = (blk_buf[i+1]   ) & 0x3f;
00425         int fg_opacity = (blk_buf[i+1]>>6) & 0x03;
00426         int bg_color   = (blk_buf[i+2]   ) & 0x3f;
00427         int bg_opacity = (blk_buf[i+2]>>6) & 0x03;
00428         int edge_color = (blk_buf[i+3]>>6) & 0x3f;
00429         SEND_STR;
00430         cc->SetPenColor(service_num, fg_color, fg_opacity,
00431                         bg_color, bg_opacity, edge_color);
00432         i+=4;
00433     }
00434     else if (SPL==code && ((i+2)<blk_size))
00435     {
00436         int row = blk_buf[i+1] & 0x0f;
00437         int col = blk_buf[i+2] & 0x3f;
00438         SEND_STR;
00439         cc->SetPenLocation(service_num, row, col);
00440         i+=3;
00441     }
00442     else if (SWA==code && ((i+4)<blk_size))
00443     {
00444         int fill_color    = (blk_buf[i+1]   ) & 0x3f;
00445         int fill_opacity  = (blk_buf[i+1]>>6) & 0x03;
00446         int border_color  = (blk_buf[i+2]   ) & 0x3f;
00447         int border_type01 = (blk_buf[i+2]>>6) & 0x03;
00448         int justify       = (blk_buf[i+3]   ) & 0x03;
00449         int scroll_dir    = (blk_buf[i+3]>>2) & 0x03;
00450         int print_dir     = (blk_buf[i+3]>>4) & 0x03;
00451         int word_wrap     = (blk_buf[i+3]>>6) & 0x01;
00452         int border_type   = (blk_buf[i+3]>>5) | border_type01;
00453         int display_eff   = (blk_buf[i+4]   ) & 0x03;
00454         int effect_dir    = (blk_buf[i+4]>>2) & 0x03;
00455         int effect_speed  = (blk_buf[i+4]>>4) & 0x0f;
00456         SEND_STR;
00457         cc->SetWindowAttributes(
00458             service_num, fill_color, fill_opacity, border_color, border_type,
00459             scroll_dir,     print_dir,    effect_dir,
00460             display_eff,    effect_speed, justify, word_wrap);
00461         i+=5;
00462     }
00463     else if ((code>=DF0) && (code<=DF7) && ((i+6)<blk_size))
00464     {
00465         // param1
00466         int priority = ( blk_buf[i+1]  ) & 0x7;
00467         int col_lock = (blk_buf[i+1]>>3) & 0x1;
00468         int row_lock = (blk_buf[i+1]>>4) & 0x1;
00469         int visible  = (blk_buf[i+1]>>5) & 0x1;
00470         // param2
00471         int anchor_vertical = blk_buf[i+2] & 0x7f;
00472         int relative_pos = (blk_buf[i+2]>>7);
00473         // param3
00474         int anchor_horizontal = blk_buf[i+3];
00475         // param4
00476         int row_count = blk_buf[i+4] & 0xf;
00477         int anchor_point = blk_buf[i+4]>>4;
00478         // param5
00479         int col_count = blk_buf[i+5] & 0x3f;
00480         // param6
00481         int pen_style = blk_buf[i+6] & 0x7;
00482         int win_style = (blk_buf[i+6]>>3) & 0x7;
00483         SEND_STR;
00484         cc->DefineWindow(service_num, code-0x98, priority, visible,
00485                          anchor_point, relative_pos,
00486                          anchor_vertical, anchor_horizontal,
00487                          row_count, col_count, row_lock, col_lock,
00488                          pen_style, win_style);
00489         i+=7;
00490     }
00491 #if DEBUG_CC_SERVICE
00492     else
00493     {
00494         LOG(VB_VBI, LOG_ERR, QString("handle_cc_c1: (NOT HANDLED) "
00495                 "code(0x%1) i(%2) blk_size(%3)").arg(code, 2, 16, '0')
00496                 .arg(i).arg(blk_size));
00497     }
00498 #endif
00499 
00500     return i;
00501 }
00502 
00503 static int handle_cc_c2(CC708Reader* cc, uint service_num, int i)
00504 {
00505     const int blk_size = cc->buf_size[service_num];
00506     const int code = cc->buf[service_num][i+1];
00507 
00508     if ((code<=0x7) && ((i+1)<blk_size)){
00509         i+=2;
00510         SEND_STR;
00511     }
00512     else if ((code<=0xf) && ((i+2)<blk_size))
00513     {
00514         i+=3;
00515         SEND_STR;
00516     }
00517     else if ((code<=0x17) && ((i+3)<blk_size))
00518     {
00519         i+=4;
00520         SEND_STR;
00521     }
00522     else if ((code<=0x1f) && ((i+4)<blk_size))
00523     {
00524         i+=5;
00525         SEND_STR;
00526     }
00527     return i;
00528 }
00529 
00530 static int handle_cc_c3(CC708Reader* cc, uint service_num, int i)
00531 {
00532     const unsigned char* blk_buf = cc->buf[service_num];
00533     const int blk_size = cc->buf_size[service_num];
00534     const int code = cc->buf[service_num][i+1];
00535 
00536     if ((code<=0x87) && ((i+5)<blk_size))
00537     {
00538         i+=6;
00539         SEND_STR;
00540     }
00541     else if ((code<=0x8f) && ((i+6)<blk_size))
00542     {
00543         i+=7;
00544         SEND_STR;
00545     }
00546     else if ((i+2)<blk_size)
00547     { // varible length commands
00548         int length = blk_buf[i+2]&0x3f;
00549         if ((i+length)<blk_size)
00550         {
00551             i+=1+length;
00552             SEND_STR;
00553         }
00554     }
00555     return i;
00556 }
00557 
00558 static void rightsize_buf(CC708Reader* cc, uint service_num, uint block_size)
00559 {
00560     uint min_new_size = block_size + cc->buf_size[service_num];
00561     if (min_new_size >= cc->buf_alloc[service_num])
00562     {
00563         uint new_alloc    = cc->buf_alloc[service_num];
00564         for (uint i = 0; (i < 32) && (new_alloc <= min_new_size); i++)
00565             new_alloc *= 2;
00566 
00567         cc->buf[service_num] =
00568             (unsigned char*) realloc(cc->buf[service_num], new_alloc);
00569         cc->buf_alloc[service_num] = (cc->buf[service_num]) ? new_alloc : 0;
00570 
00571 #if DEBUG_CC_SERVICE_2
00572         LOG(VB_VBI, LOG_DEBUG, QString("rightsize_buf: srv %1 to %1 bytes")
00573                 .arg(service_num) .arg(cc->buf_alloc[service_num]));
00574 #endif
00575     }
00576     if (min_new_size >= cc->buf_alloc[service_num])
00577         LOG(VB_VBI, LOG_ERR,
00578             QString("buffer resize error: min_new_size=%1, buf_alloc[%2]=%3")
00579             .arg(min_new_size)
00580             .arg(service_num)
00581             .arg(cc->buf_alloc[service_num]));
00582 }
00583 
00584 static void append_cc(CC708Reader* cc, uint service_num,
00585                       const unsigned char* blk_buf, int block_size)
00586 {
00587     rightsize_buf(cc, service_num, block_size);
00588 
00589     memcpy(cc->buf[service_num] + cc->buf_size[service_num],
00590            blk_buf, block_size);
00591 
00592     cc->buf_size[service_num] += block_size;
00593 #if DEBUG_CC_SERVICE_2
00594     {
00595         uint i;
00596         QString msg("append_cc: ");
00597         for (i = 0; i < cc->buf_size[service_num]; i++)
00598             msg += QString("0x%1").arg(cc->buf[service_num][i], 0, 16);
00599         LOG(VB_VBI, LOG_DEBUG, msg);
00600     }
00601 #endif
00602     parse_cc_service_stream(cc, service_num);
00603 }
00604 
00605 static void parse_cc_packet(CC708Reader* cb_cbs, CaptionPacket* pkt,
00606                             time_t last_seen[64])
00607 {
00608     const unsigned char* pkt_buf = pkt->data;
00609     const int pkt_size = pkt->size;
00610     int off = 1;
00611     int service_number = 0;
00612     int block_data_offset = 0;
00613     int len     = ((((int)pkt_buf[0]) & 0x3f)<<1) - 1;
00614     int seq_num = (((int)pkt_buf[0])>>6)&0x3;
00615 
00616     if (len < 0)
00617         return;
00618 
00619 #if DEBUG_CC_RAWPACKET
00620     if (1)
00621 #elif DEBUG_CAPTIONS
00622     if (len > pkt_size)
00623 #else
00624     if (0)
00625 #endif
00626     {
00627         int j;
00628         int srv = (pkt_buf[off]>>5) & 0x7;
00629         QString msg = QString("CC708 len %1 srv0 %2 seq %3 ").arg(len, 2)
00630                           .arg(srv) .arg(seq_num);
00631         for (j = 0; j < pkt_size; j++)
00632             msg += QString("0x%1").arg(pkt_buf[j], 0, 16);
00633         LOG(VB_VBI, LOG_DEBUG, msg);
00634     }
00635 
00636     if (pkt_size >= 127)
00637         LOG(VB_VBI, LOG_ERR,
00638             QString("Unexpected pkt_size=%1").arg(pkt_size));
00639 
00640     while (off < pkt_size && pkt_buf[off])
00641     { // service_block
00642         int block_size = pkt_buf[off] & 0x1f;
00643         service_number = (pkt_buf[off]>>5) & 0x7;
00644         block_data_offset = (0x7==service_number && block_size!=0) ?
00645             off+2 : off+1;
00646 #if DEBUG_CC_SERVICE_BLOCK
00647         LOG(VB_VBI, LOG_DEBUG, 
00648             QString("service_block size(%1) num(%2) off(%3)")
00649                 .arg(block_size) .arg(service_number) .arg(block_data_offset));
00650 #endif
00651         if (off+2 == block_data_offset)
00652         {
00653             int extended_service_number = pkt_buf[off+2] & 0x3f;
00654 #if DEBUG_CC_SERVICE_BLOCK
00655             LOG(VB_VBI, LOG_DEBUG, QString("ext_svc_num(%1)")
00656                    .arg(extended_service_number));
00657 #endif
00658             service_number =  extended_service_number;
00659         }
00660         if (service_number)
00661         {
00662 #if DEBUG_CC_SERVICE
00663             int i;
00664             if (!(2==block_size &&
00665                   0==pkt_buf[block_data_offset] &&
00666                   0==pkt_buf[block_data_offset+1]))
00667             {
00668                 QString msg = QString("service %1: ").arg(service_number);
00669                 for (i=0; i<block_size; i++)
00670                     msg += QString("0x%1 ")
00671                                .arg(pkt_buf[block_data_offset+i], 0, 16);
00672                 LOG(VB_VBI, LOG_DEBUG, msg);
00673             }
00674 #endif
00675             append_cc(cb_cbs, service_number,
00676                       &pkt_buf[block_data_offset], block_size);
00677 
00678             last_seen[service_number] = time(NULL);
00679         }
00680         off+=block_size+1;
00681     }
00682     if (off<pkt_size) // must end in null service block, if packet is not full.
00683     {
00684         if (pkt_buf[off] != 0)
00685             LOG(VB_VBI, LOG_ERR,
00686                 QString("CEA-708 packet error: pkt_size=%1, pkt_buf[%2]=%3")
00687                 .arg(pkt_size).arg(off).arg(pkt_buf[off]));
00688     }
00689 }
00690 
00691 static void append_character(CC708Reader *cc, uint service_num, short ch)
00692 {
00693     if (cc->temp_str_size[service_num]+2 > cc->temp_str_alloc[service_num])
00694     {
00695         int new_alloc = (cc->temp_str_alloc[service_num]) ?
00696             cc->temp_str_alloc[service_num] * 2 : 64;
00697 
00698         cc->temp_str[service_num] = (short*)
00699             realloc(cc->temp_str[service_num], new_alloc * sizeof(short));
00700 
00701         cc->temp_str_alloc[service_num] = new_alloc; // shorts allocated
00702     }
00703 
00704     if (cc->temp_str[service_num])
00705     {
00706         int i = cc->temp_str_size[service_num];
00707         cc->temp_str[service_num][i] = ch;
00708         cc->temp_str_size[service_num]++;
00709     }
00710     else
00711     {
00712         cc->temp_str_size[service_num] = 0;
00713         cc->temp_str_alloc[service_num]=0;
00714     }
00715 }
00716 
00717 ushort CCtableG0[0x60] =
00718 {
00719 //   0    1    2    3       4    5    6    7
00720 //   8    9    a    b       c    d    e    f
00721     ' ', '!','\"', '#',    '$', '%', '&', '\'', /* 0x20-0x27 */
00722     '(', ')', '*', '+',    ',', '-', '.', '/',  /* 0x28-0x2f */
00723     '0', '1', '2', '3',    '4', '5', '6', '7',  /* 0x30-0x37 */
00724     '8', '9', ':', ';',    '<', '=', '>', '?',  /* 0x38-0x3f */
00725 
00726     '@', 'A', 'B', 'C',    'D', 'E', 'F', 'G',  /* 0x40-0x47 */
00727     'H', 'I', 'J', 'K',    'L', 'M', 'N', 'O',  /* 0x48-0x4f */
00728     'P', 'Q', 'R', 'S',    'T', 'U', 'V', 'W',  /* 0x50-0x57 */
00729     'X', 'Y', 'Z', '[',    '\\',']', '^', '_',  /* 0x58-0x5f */
00730 
00731     '`', 'a', 'b', 'c',    'd', 'e', 'f', 'g',  /* 0x60-0x67 */
00732     'h', 'i', 'j', 'k',    'l', 'm', 'n', 'o',  /* 0x68-0x6f */
00733     'p', 'q', 'r', 's',    't', 'u', 'v', 'w',  /* 0x70-0x77 */
00734     'x', 'y', 'z', '{',    '|', '}', '~',  0x266a, // music note/* 0x78-0x7f */
00735 };
00736 
00737 ushort CCtableG1[0x60] =
00738 {
00739 //          0           1           2           3
00740 //          4           5           6           7
00741 //          8           9           a           b
00742 //          c           d           e           f
00743     0xA0, // unicode non-breaking space
00744                 (uchar)'¡', (uchar)'¢', (uchar)'£', /* 0xa0-0xa3 */
00745     (uchar)'¤', (uchar)'¥', (uchar)'¦', (uchar)'§', /* 0xa4-0xa7 */
00746     (uchar)'¨', (uchar)'©', (uchar)'ª', (uchar)'«', /* 0xa8-0xab */
00747     (uchar)'¬', (uchar)'­', (uchar)'®', (uchar)'¯', /* 0xac-0xaf */
00748     (uchar)'°', (uchar)'±', (uchar)'²', (uchar)'³', /* 0xb0-0xb3 */
00749     (uchar)'´', (uchar)'µ', (uchar)'¶', (uchar)'·', /* 0xb4-0xb7 */
00750     (uchar)'¸', (uchar)'¹', (uchar)'º', (uchar)'»', /* 0xb8-0xbb */
00751     (uchar)'¼', (uchar)'½', (uchar)'¾', (uchar)'¿', /* 0xbc-0xbf */
00752 
00753     (uchar)'À', (uchar)'Á', (uchar)'Â', (uchar)'Ã', /* 0xc0-0xc3 */
00754     (uchar)'Ä', (uchar)'Å', (uchar)'Æ', (uchar)'Ç', /* 0xc4-0xc7 */
00755     (uchar)'È', (uchar)'É', (uchar)'Ê', (uchar)'Ë', /* 0xc8-0xcb */
00756     (uchar)'Ì', (uchar)'Í', (uchar)'Î', (uchar)'Ï', /* 0xcc-0xcf */
00757     (uchar)'Ð', (uchar)'Ñ', (uchar)'Ò', (uchar)'Ó', /* 0xd0-0xd3 */
00758     (uchar)'Ô', (uchar)'Õ', (uchar)'Ö', (uchar)'×', /* 0xd4-0xd7 */
00759     (uchar)'Ø', (uchar)'Ù', (uchar)'Ú', (uchar)'Û', /* 0xd8-0xdb */
00760     (uchar)'Ü', (uchar)'Ý', (uchar)'Þ', (uchar)'ß', /* 0xdc-0xdf */
00761 
00762     (uchar)'à', (uchar)'á', (uchar)'â', (uchar)'ã', /* 0xe0-0xe3 */
00763     (uchar)'ä', (uchar)'å', (uchar)'æ', (uchar)'ç', /* 0xe4-0xe7 */
00764     (uchar)'è', (uchar)'é', (uchar)'ê', (uchar)'ë', /* 0xe8-0xeb */
00765     (uchar)'ì', (uchar)'í', (uchar)'î', (uchar)'ï', /* 0xec-0xef */
00766     (uchar)'ð', (uchar)'ñ', (uchar)'ò', (uchar)'ó', /* 0xf0-0xf3 */
00767     (uchar)'ô', (uchar)'õ', (uchar)'ö', (uchar)'÷', /* 0xf4-0xf7 */
00768     (uchar)'ø', (uchar)'ù', (uchar)'ú', (uchar)'û', /* 0xf8-0xfb */
00769     (uchar)'ü', (uchar)'ý', (uchar)'þ', (uchar)'ÿ', /* 0xfc-0xff */
00770 };
00771 
00772 ushort CCtableG2[0x60] =
00773 {
00774     ' ', /* transparent space */
00775                         0xA0, /* non-breaking transparent space */
00776     0,                  0,                     /* 0x20-0x23 */
00777     0,                  0x2026,/* elipsis */
00778     0,                  0,                     /* 0x24-0x27 */
00779     0,                  0,
00780     0x160,/*S under \/*/0,                     /* 0x28-0x2b */
00781     0x152, /* CE */     0,
00782     0,                  0,                     /* 0x2c-0x2f */
00783     0x2588,/*block*/    0x2018,/* open ' */
00784     0x2019,/*close ' */ 0x201c,/* open " */    /* 0x30-0x33 */
00785     0x201d,/*close " */ 0xB7,/* dot */
00786     0,                  0,                     /* 0x34-0x37 */
00787     0,                  0x2122,/* super TM */
00788     0x161,/*s under \/*/0,                     /* 0x38-0x3b */
00789     0x153, /* ce */     0x2120,/* super SM */
00790     0,                  0x178,/*Y w/umlout*/   /* 0x3c-0x3f */
00791 
00792 //  0         1         2         3
00793 //  4         5         6         7
00794 //  8         9         a         b
00795 //  c         d         e         f
00796     0,        0,        0,        0,
00797     0,        0,        0,        0, /* 0x40-0x47 */
00798     0,        0,        0,        0,
00799     0,        0,        0,        0, /* 0x48-0x4f */
00800 
00801     0,        0,        0,        0,
00802     0,        0,        0,        0, /* 0x50-0x57 */
00803     0,        0,        0,        0,
00804     0,        0,        0,        0, /* 0x58-0x5f */
00805 
00806     0,        0,        0,        0,
00807     0,        0,        0,        0, /* 0x60-0x67 */
00808     0,        0,        0,        0,
00809     0,        0,        0,        0, /* 0x68-0x6f */
00810 
00811     0,                  0,
00812     0,                  0,           /* 0x70-0x73 */
00813     0,                  0,
00814     0x215b, /* 1/8 */   0x215c, /* 3/8 */    /* 0x74-0x77 */
00815     0x215d, /* 5/8 */   0x215e, /* 7/8 */
00816     0x2502, /*line | */ 0x2510, /*line ~| */ /* 0x78-0x7b */
00817     0x2514, /*line |_*/ 0x2500, /*line -*/
00818     0x2518, /*line _|*/ 0x250c, /*line |~ */ /* 0x7c-0x7f */
00819 };
00820 
00821 ushort CCtableG3[0x60] =
00822 {
00823 //   0 1  2  3    4  5  6  7     8  9  a  b    c  d  e  f
00824     '#', /* [CC] closed captioning logo */
00825        0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xa0-0xaf */
00826     0, 0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xb0-0xbf */
00827 
00828     0, 0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xc0-0xcf */
00829     0, 0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xd0-0xdf */
00830 
00831     0, 0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xe0-0xff */
00832     0, 0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xf0-0xff */
00833 };
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends