|
MythTV
0.26-pre
|
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 };
1.7.6.1