00001 #include "teletextreader.h"
00002 #include "mythlogging.h"
00003
00004 #include <string.h>
00005 #include "vbilut.h"
00006 #include "tv.h"
00007
00008 #define MAGAZINE(page) (page / 256)
00009
00010 TeletextReader::TeletextReader()
00011 : m_curpage(0x100), m_cursubpage(-1),
00012 m_curpage_showheader(true), m_curpage_issubtitle(false),
00013 m_transparent(false), m_revealHidden(false),
00014 m_header_changed(false), m_page_changed(false),
00015 m_fetchpage(0), m_fetchsubpage(0)
00016 {
00017 memset(m_pageinput, 0, sizeof(m_pageinput));
00018 memset(m_header, 0, sizeof(m_header));
00019 for (int i = 0; i < 256; i++)
00020 {
00021 m_bitswap[i] = 0;
00022 for (int bit = 0; bit < 8; bit++)
00023 if (i & (1 << bit))
00024 m_bitswap[i] |= (1 << (7-bit));
00025 }
00026 Reset();
00027 }
00028
00029 TeletextReader::~TeletextReader()
00030 {
00031 }
00032
00033 bool TeletextReader::KeyPress(const QString &key)
00034 {
00035 int newPage = m_curpage;
00036 int newSubPage = m_cursubpage;
00037 bool numeric_input = false;
00038
00039 TeletextSubPage *curpage = FindSubPage(m_curpage, m_cursubpage);
00040 TeletextPage *page;
00041
00042 if (key == ACTION_0 || key == ACTION_1 || key == ACTION_2 ||
00043 key == ACTION_3 || key == ACTION_4 || key == ACTION_5 ||
00044 key == ACTION_6 || key == ACTION_7 || key == ACTION_8 ||
00045 key == ACTION_9)
00046 {
00047 numeric_input = true;
00048 m_curpage_showheader = true;
00049 if (m_pageinput[0] == ' ')
00050 m_pageinput[0] = '0' + key.toInt();
00051 else if (m_pageinput[1] == ' ')
00052 m_pageinput[1] = '0' + key.toInt();
00053 else if (m_pageinput[2] == ' ')
00054 {
00055 m_pageinput[2] = '0' + key.toInt();
00056 newPage = ((m_pageinput[0] - '0') * 256) +
00057 ((m_pageinput[1] - '0') * 16) +
00058 (m_pageinput[2] - '0');
00059 newSubPage = -1;
00060 }
00061 else
00062 {
00063 m_pageinput[0] = '0' + key.toInt();
00064 m_pageinput[1] = ' ';
00065 m_pageinput[2] = ' ';
00066 }
00067
00068 PageUpdated(m_curpage, m_cursubpage);
00069 }
00070 else if (key == ACTION_NEXTPAGE)
00071 {
00072 TeletextPage *ttpage = FindPage(m_curpage, 1);
00073 if (ttpage)
00074 newPage = ttpage->pagenum;
00075 newSubPage = -1;
00076 m_curpage_showheader = true;
00077 }
00078 else if (key == ACTION_PREVPAGE)
00079 {
00080 TeletextPage *ttpage = FindPage(m_curpage, -1);
00081 if (ttpage)
00082 newPage = ttpage->pagenum;
00083 newSubPage = -1;
00084 m_curpage_showheader = true;
00085 }
00086 else if (key == ACTION_NEXTSUBPAGE)
00087 {
00088 TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage, 1);
00089 if (ttpage)
00090 newSubPage = ttpage->subpagenum;
00091 m_curpage_showheader = true;
00092 }
00093 else if (key == ACTION_PREVSUBPAGE)
00094 {
00095 TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage, -1);
00096 if (ttpage)
00097 newSubPage = ttpage->subpagenum;
00098 m_curpage_showheader = true;
00099 }
00100 else if (key == ACTION_TOGGLEBACKGROUND)
00101 {
00102 m_transparent = !m_transparent;
00103 PageUpdated(m_curpage, m_cursubpage);
00104 }
00105 else if (key == ACTION_REVEAL)
00106 {
00107 m_revealHidden = !m_revealHidden;
00108 PageUpdated(m_curpage, m_cursubpage);
00109 }
00110 else if (key == ACTION_MENURED)
00111 {
00112 if (!curpage)
00113 return true;
00114
00115 if ((page = FindPage(curpage->floflink[0])) != NULL)
00116 {
00117 newPage = page->pagenum;
00118 newSubPage = -1;
00119 m_curpage_showheader = true;
00120 }
00121 }
00122 else if (key == ACTION_MENUGREEN)
00123 {
00124 if (!curpage)
00125 return true;
00126
00127 if ((page = FindPage(curpage->floflink[1])) != NULL)
00128 {
00129 newPage = page->pagenum;
00130 newSubPage = -1;
00131 m_curpage_showheader = true;
00132 }
00133 }
00134 else if (key == ACTION_MENUYELLOW)
00135 {
00136 if (!curpage)
00137 return true;
00138
00139 if ((page = FindPage(curpage->floflink[2])) != NULL)
00140 {
00141 newPage = page->pagenum;
00142 newSubPage = -1;
00143 m_curpage_showheader = true;
00144 }
00145 }
00146 else if (key == ACTION_MENUBLUE)
00147 {
00148 if (!curpage)
00149 return true;
00150
00151 if ((page = FindPage(curpage->floflink[3])) != NULL)
00152 {
00153 newPage = page->pagenum;
00154 newSubPage = -1;
00155 m_curpage_showheader = true;
00156 }
00157 }
00158 else if (key == ACTION_MENUWHITE)
00159 {
00160 if (!curpage)
00161 return true;
00162
00163 if ((page = FindPage(curpage->floflink[4])) != NULL)
00164 {
00165 newPage = page->pagenum;
00166 newSubPage = -1;
00167 m_curpage_showheader = true;
00168 }
00169 }
00170 else
00171 return false;
00172
00173 if (newPage < 0x100)
00174 newPage = 0x100;
00175 if (newPage > 0x899)
00176 newPage = 0x899;
00177
00178 if (!numeric_input)
00179 {
00180 m_pageinput[0] = (newPage / 256) + '0';
00181 m_pageinput[1] = ((newPage % 256) / 16) + '0';
00182 m_pageinput[2] = (newPage % 16) + '0';
00183 }
00184
00185 if (newPage != m_curpage || newSubPage != m_cursubpage)
00186 {
00187 m_curpage = newPage;
00188 m_cursubpage = newSubPage;
00189 m_revealHidden = false;
00190 PageUpdated(m_curpage, m_cursubpage);
00191 }
00192
00193 return true;
00194 }
00195
00196 QString TeletextReader::GetPage(void)
00197 {
00198 QString str = "";
00199 int mag = MAGAZINE(m_curpage);
00200 if (mag > 8 || mag < 1)
00201 return str;
00202
00203 int count = 1, selected = 0;
00204 const TeletextPage *page = FindPage(m_curpage);
00205 if (page)
00206 {
00207 m_magazines[mag - 1].lock.lock();
00208 int_to_subpage_t::const_iterator subpageIter;
00209 subpageIter = page->subpages.begin();
00210 while (subpageIter != page->subpages.end())
00211 {
00212 const TeletextSubPage *subpage = &subpageIter->second;
00213
00214 if (subpage->subpagenum == m_cursubpage)
00215 {
00216 selected = count;
00217 str += "*";
00218 }
00219 else
00220 str += " ";
00221
00222 str += QString().sprintf("%02X", subpage->subpagenum);
00223
00224 ++subpageIter;
00225 ++count;
00226 }
00227 m_magazines[mag - 1].lock.unlock();
00228 }
00229
00230 if (str.isEmpty())
00231 return str;
00232
00233
00234 if (count < 10)
00235 {
00236 QString spaces;
00237 spaces.fill(' ', 27 - str.length());
00238 str = " <" + str + spaces + " > ";
00239 }
00240 else
00241 {
00242
00243 int startPos = selected - 5;
00244 if (startPos < 0)
00245 startPos = 0;
00246 if (startPos + 9 >= count)
00247 startPos = count - 10;
00248
00249 str = " <" + str.mid(startPos * 3, 27) + " > ";
00250 }
00251 return str;
00252 }
00253
00254 void TeletextReader::SetPage(int page, int subpage)
00255 {
00256 if (page < 0x100 || page > 0x899)
00257 return;
00258
00259 m_pageinput[0] = (page / 256) + '0';
00260 m_pageinput[1] = ((page % 256) / 16) + '0';
00261 m_pageinput[2] = (page % 16) + '0';
00262
00263 m_curpage = page;
00264 m_cursubpage = subpage;
00265 PageUpdated(m_curpage, m_cursubpage);
00266 }
00267
00268 void TeletextReader::Reset(void)
00269 {
00270 for (uint mag = 0; mag < 8; mag++)
00271 {
00272 QMutexLocker lock(&m_magazines[mag].lock);
00273
00274
00275 int_to_page_t::iterator iter;
00276 iter = m_magazines[mag].pages.begin();
00277 while (iter != m_magazines[mag].pages.end())
00278 {
00279 TeletextPage *page = &iter->second;
00280 page->subpages.clear();
00281 ++iter;
00282 }
00283
00284
00285 m_magazines[mag].pages.clear();
00286 m_magazines[mag].current_page = 0;
00287 m_magazines[mag].current_subpage = 0;
00288 m_magazines[mag].loadingpage.active = false;
00289 }
00290 memset(m_header, ' ', 40);
00291
00292 m_curpage = 0x100;
00293 m_cursubpage = -1;
00294 m_curpage_showheader = true;
00295
00296 m_pageinput[0] = '1';
00297 m_pageinput[1] = '0';
00298 m_pageinput[2] = '0';
00299 }
00300
00301 void TeletextReader::AddPageHeader(int page, int subpage, const uint8_t *buf,
00302 int vbimode, int lang, int flags)
00303 {
00304
00305
00306
00307 int magazine = MAGAZINE(page);
00308 if (magazine < 1 || magazine > 8)
00309 return;
00310 int lastPage = m_magazines[magazine - 1].current_page;
00311 int lastSubPage = m_magazines[magazine - 1].current_subpage;
00312
00313
00314
00315
00316 if ((page != lastPage || subpage != lastSubPage) &&
00317 m_magazines[magazine - 1].loadingpage.active)
00318 {
00319 TeletextSubPage *ttpage = FindSubPage(lastPage, lastSubPage);
00320 if (!ttpage)
00321 {
00322 ttpage = &(m_magazines[magazine - 1]
00323 .pages[lastPage].subpages[lastSubPage]);
00324 m_magazines[magazine - 1].pages[lastPage].pagenum = lastPage;
00325 ttpage->subpagenum = lastSubPage;
00326 }
00327
00328 memcpy(ttpage, &m_magazines[magazine - 1].loadingpage,
00329 sizeof(TeletextSubPage));
00330
00331 m_magazines[magazine - 1].loadingpage.active = false;
00332
00333 PageUpdated(lastPage, lastSubPage);
00334 }
00335
00336 m_fetchpage = page;
00337 m_fetchsubpage = subpage;
00338
00339 TeletextSubPage *ttpage = &m_magazines[magazine - 1].loadingpage;
00340
00341 m_magazines[magazine - 1].current_page = page;
00342 m_magazines[magazine - 1].current_subpage = subpage;
00343
00344 memset(ttpage->data, ' ', sizeof(ttpage->data));
00345
00346 ttpage->active = true;
00347 ttpage->subpagenum = subpage;
00348
00349 for (uint i = 0; i < 6; i++)
00350 ttpage->floflink[i] = 0;
00351
00352 ttpage->lang = lang;
00353 ttpage->flags = flags;
00354 ttpage->flof = 0;
00355
00356 ttpage->subtitle = (vbimode == VBI_DVB_SUBTITLE);
00357
00358 memset(ttpage->data[0], ' ', 8 * sizeof(uint8_t));
00359
00360 if (vbimode == VBI_DVB || vbimode == VBI_DVB_SUBTITLE)
00361 {
00362 for (uint j = 8; j < 40; j++)
00363 ttpage->data[0][j] = m_bitswap[buf[j]];
00364 }
00365 else
00366 {
00367 memcpy(ttpage->data[0]+0, buf, 40);
00368 }
00369
00370 if ( !(ttpage->flags & TP_INTERRUPTED_SEQ))
00371 {
00372 memcpy(m_header, ttpage->data[0], 40);
00373 HeaderUpdated(page, subpage, ttpage->data[0],ttpage->lang);
00374 }
00375 }
00376
00377 void TeletextReader::AddTeletextData(int magazine, int row,
00378 const uint8_t* buf, int vbimode)
00379 {
00380
00381
00382
00383 int b1, b2, b3, err = 0;
00384
00385 if (magazine < 1 || magazine > 8)
00386 return;
00387
00388 int currentpage = m_magazines[magazine - 1].current_page;
00389 if (!currentpage)
00390 return;
00391
00392 TeletextSubPage *ttpage = &m_magazines[magazine - 1].loadingpage;
00393
00394 switch (row)
00395 {
00396 case 26:
00397
00398
00399
00400
00401
00402
00403
00404
00405 break;
00406 case 27:
00407 switch (vbimode)
00408 {
00409 case VBI_IVTV:
00410 b1 = hamm8(buf, &err);
00411 b2 = hamm8(buf + 37, &err);
00412 if (err & 0xF000)
00413 return;
00414 break;
00415 case VBI_DVB:
00416 case VBI_DVB_SUBTITLE:
00417 b1 = hamm84(buf, &err);
00418 b2 = hamm84(buf + 37, &err);
00419 if (err == 1)
00420 return;
00421 break;
00422 default:
00423 return;
00424 }
00425 if (b1 != 0 || !(b2 & 8))
00426 return;
00427
00428 for (int i = 0; i < 6; ++i)
00429 {
00430 err = 0;
00431 switch (vbimode)
00432 {
00433 case VBI_IVTV:
00434 b1 = hamm16(buf+1+6*i, &err);
00435 b2 = hamm16(buf+3+6*i, &err);
00436 b3 = hamm16(buf+5+6*i, &err);
00437 if (err & 0xF000)
00438 return;
00439 break;
00440 case VBI_DVB:
00441 case VBI_DVB_SUBTITLE:
00442 b1 = hamm84(buf+2+6*i, &err) * 16 +
00443 hamm84(buf+1+6*i, &err);
00444 b2 = hamm84(buf+4+6*i, &err) * 16 +
00445 hamm84(buf+3+6*i, &err);
00446 b3 = hamm84(buf+6+6*i, &err) * 16 +
00447 hamm84(buf+5+6*i, &err);
00448 if (err == 1)
00449 return;
00450 break;
00451 default:
00452 return;
00453 }
00454
00455 int x = (b2 >> 7) | ((b3 >> 5) & 0x06);
00456 int nTmp = (magazine ^ x);
00457 ttpage->floflink[i] = ( nTmp ? nTmp : 8) * 256 + b1;
00458 ttpage->flof = 1;
00459 }
00460 break;
00461
00462 case 31:
00463 break;
00464
00465 default:
00466
00467 if (( row >= 1 ) && ( row <= 24 ))
00468 {
00469 if (vbimode == VBI_DVB || vbimode == VBI_DVB_SUBTITLE)
00470 {
00471 for (uint j = 0; j < 40; j++)
00472 ttpage->data[row][j] = m_bitswap[buf[j]];
00473 }
00474 else
00475 {
00476 memcpy(ttpage->data[row], buf, 40);
00477 }
00478 }
00479
00480 break;
00481 }
00482 }
00483
00484 void TeletextReader::PageUpdated(int page, int subpage)
00485 {
00486 if (page != m_curpage)
00487 return;
00488 if (subpage != m_cursubpage && m_cursubpage != -1)
00489 return;
00490 m_page_changed = true;
00491 }
00492
00493 void TeletextReader::HeaderUpdated(
00494 int page, int subpage, uint8_t *page_ptr, int lang)
00495 {
00496 (void)page;
00497 (void)subpage;
00498 (void)lang;
00499
00500 if (page_ptr == NULL)
00501 return;
00502
00503 if (m_curpage_showheader == false)
00504 return;
00505
00506 m_header_changed = true;
00507 }
00508
00509 const TeletextPage *TeletextReader::FindPageInternal(
00510 int page, int direction) const
00511 {
00512 int mag = MAGAZINE(page);
00513
00514 if (mag > 8 || mag < 1)
00515 return NULL;
00516
00517 QMutexLocker lock(&m_magazines[mag - 1].lock);
00518
00519 int_to_page_t::const_iterator pageIter;
00520 pageIter = m_magazines[mag - 1].pages.find(page);
00521 if (pageIter == m_magazines[mag - 1].pages.end())
00522 return NULL;
00523
00524 const TeletextPage *res = &pageIter->second;
00525 if (direction == -1)
00526 {
00527 --pageIter;
00528 if (pageIter == m_magazines[mag - 1].pages.end())
00529 {
00530 int_to_page_t::const_reverse_iterator iter;
00531 iter = m_magazines[mag - 1].pages.rbegin();
00532 res = &iter->second;
00533 }
00534 else
00535 res = &pageIter->second;
00536 }
00537
00538 if (direction == 1)
00539 {
00540 ++pageIter;
00541 if (pageIter == m_magazines[mag - 1].pages.end())
00542 {
00543 pageIter = m_magazines[mag - 1].pages.begin();
00544 res = &pageIter->second;
00545 }
00546 else
00547 res = &pageIter->second;
00548 }
00549
00550 return res;
00551 }
00552
00553 const TeletextSubPage *TeletextReader::FindSubPageInternal(
00554 int page, int subpage, int direction) const
00555 {
00556 int mag = MAGAZINE(page);
00557
00558 if (mag > 8 || mag < 1)
00559 return NULL;
00560
00561 QMutexLocker lock(&m_magazines[mag - 1].lock);
00562
00563 int_to_page_t::const_iterator pageIter;
00564 pageIter = m_magazines[mag - 1].pages.find(page);
00565 if (pageIter == m_magazines[mag - 1].pages.end())
00566 return NULL;
00567
00568 const TeletextPage *ttpage = &(pageIter->second);
00569 int_to_subpage_t::const_iterator subpageIter =
00570 ttpage->subpages.begin();
00571
00572
00573 if (subpage != -1)
00574 subpageIter = ttpage->subpages.find(subpage);
00575
00576 if (subpageIter == ttpage->subpages.end())
00577 return NULL;
00578
00579 if (subpage == -1)
00580 return &(subpageIter->second);
00581
00582 const TeletextSubPage *res = &(subpageIter->second);
00583 if (direction == -1)
00584 {
00585 --subpageIter;
00586 if (subpageIter == ttpage->subpages.end())
00587 {
00588 int_to_subpage_t::const_reverse_iterator iter =
00589 ttpage->subpages.rbegin();
00590 res = &(iter->second);
00591 }
00592 else
00593 {
00594 res = &(subpageIter->second);
00595 }
00596 }
00597
00598 if (direction == 1)
00599 {
00600 ++subpageIter;
00601 if (subpageIter == ttpage->subpages.end())
00602 subpageIter = ttpage->subpages.begin();
00603
00604 res = &(subpageIter->second);
00605 }
00606
00607 return res;
00608 }