00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <cmath>
00022
00023 #include <qmutex.h>
00024
00025 #include "osd.h"
00026 #include "osdsurface.h"
00027 #include "osdtypes.h"
00028 #include "osdtypeteletext.h"
00029 #include "ttfont.h"
00030 #include "vbilut.h"
00031
00032 const QColor OSDTypeTeletext::kColorBlack = QColor( 0, 0, 0);
00033 const QColor OSDTypeTeletext::kColorRed = QColor(255, 0, 0);
00034 const QColor OSDTypeTeletext::kColorGreen = QColor( 0,255, 0);
00035 const QColor OSDTypeTeletext::kColorYellow = QColor(255,255, 0);
00036 const QColor OSDTypeTeletext::kColorBlue = QColor( 0, 0,255);
00037 const QColor OSDTypeTeletext::kColorMagenta = QColor(255, 0,255);
00038 const QColor OSDTypeTeletext::kColorCyan = QColor( 0,255,255);
00039 const QColor OSDTypeTeletext::kColorWhite = QColor(255,255,255);
00040 const int OSDTypeTeletext::kTeletextColumns = 40;
00041 const int OSDTypeTeletext::kTeletextRows = 26;
00042
00043
00044 OSDTypeTeletext::OSDTypeTeletext(const QString &name, TTFFont *font,
00045 QRect displayrect, float wmult, float hmult,
00046 OSD *osd)
00047 : OSDType(name),
00048 m_lock(true),
00049 m_displayrect(displayrect), m_unbiasedrect(0,0,0,0),
00050 m_box(NULL),
00051
00052 m_tt_colspace(m_displayrect.width() / kTeletextColumns),
00053 m_tt_rowspace(m_displayrect.height() / kTeletextRows),
00054
00055
00056 m_fetchpage(0), m_fetchsubpage(0),
00057
00058
00059 m_font(font),
00060
00061
00062 m_bgcolor_y(0), m_bgcolor_u(0),
00063 m_bgcolor_v(0), m_bgcolor_a(0),
00064
00065
00066 m_curpage(0x100), m_cursubpage(-1),
00067 m_curpage_showheader(true), m_curpage_issubtitle(false),
00068
00069 m_transparent(false), m_revealHidden(false),
00070 m_displaying(false), m_osd(osd),
00071 m_header_changed(false), m_page_changed(false),
00072 m_osd_changed(false)
00073 {
00074 m_unbiasedrect = bias(m_displayrect, wmult, hmult);
00075
00076
00077 for (int i = 0; i < 256; i++)
00078 {
00079 m_bitswap[i] = 0;
00080 for (int bit = 0; bit < 8; bit++)
00081 if (i & (1 << bit))
00082 m_bitswap[i] |= (1 << (7-bit));
00083 }
00084
00085 Reset();
00086 }
00087
00091 void OSDTypeTeletext::Reset(void)
00092 {
00093 OSDUpdateLocker locker(&m_lock, this);
00094
00095 for (uint mag = 0; mag < 8; mag++)
00096 {
00097 QMutexLocker lock(&m_magazines[mag].lock);
00098
00099
00100 int_to_page_t::iterator iter;
00101 iter = m_magazines[mag].pages.begin();
00102 while (iter != m_magazines[mag].pages.end())
00103 {
00104 TeletextPage *page = &iter->second;
00105 page->subpages.clear();
00106 ++iter;
00107 }
00108
00109
00110 m_magazines[mag].pages.clear();
00111 m_magazines[mag].current_page = 0;
00112 m_magazines[mag].current_subpage = 0;
00113 m_magazines[mag].loadingpage.active = false;
00114 }
00115 memset(m_header, ' ', 40);
00116
00117 m_curpage = 0x100;
00118 m_cursubpage = -1;
00119 m_curpage_showheader = true;
00120
00121 m_pageinput[0] = '1';
00122 m_pageinput[1] = '0';
00123 m_pageinput[2] = '0';
00124 }
00125
00129 void OSDTypeTeletext::AddPageHeader(int page, int subpage,
00130 const unsigned char* buf,
00131 int vbimode, int lang, int flags)
00132 {
00133 OSDUpdateLocker locker(&m_lock, this);
00134
00135 int magazine = MAGAZINE(page);
00136 if (magazine < 1 || magazine > 8)
00137 return;
00138 int lastPage = m_magazines[magazine - 1].current_page;
00139 int lastSubPage = m_magazines[magazine - 1].current_subpage;
00140
00141
00142
00143
00144 if ((page != lastPage || subpage != lastSubPage) &&
00145 m_magazines[magazine - 1].loadingpage.active)
00146 {
00147 TeletextSubPage *ttpage = FindSubPage(lastPage, lastSubPage);
00148 if (!ttpage)
00149 {
00150 ttpage = &(m_magazines[magazine - 1]
00151 .pages[lastPage].subpages[lastSubPage]);
00152 m_magazines[magazine - 1].pages[lastPage].pagenum = lastPage;
00153 ttpage->subpagenum = lastSubPage;
00154 }
00155
00156 memcpy(ttpage, &m_magazines[magazine - 1].loadingpage,
00157 sizeof(TeletextSubPage));
00158
00159 m_magazines[magazine - 1].loadingpage.active = false;
00160
00161 PageUpdated(lastPage, lastSubPage);
00162 }
00163
00164 m_fetchpage = page;
00165 m_fetchsubpage = subpage;
00166
00167 TeletextSubPage *ttpage = &m_magazines[magazine - 1].loadingpage;
00168
00169 m_magazines[magazine - 1].current_page = page;
00170 m_magazines[magazine - 1].current_subpage = subpage;
00171
00172 memset(ttpage->data, ' ', sizeof(ttpage->data));
00173
00174 ttpage->active = true;
00175 ttpage->subpagenum = subpage;
00176
00177 for (uint i = 0; i < 6; i++)
00178 ttpage->floflink[i] = 0;
00179
00180 ttpage->lang = lang;
00181 ttpage->flags = flags;
00182 ttpage->flof = 0;
00183
00184 ttpage->subtitle = (vbimode == VBI_DVB_SUBTITLE);
00185
00186 memset(ttpage->data[0], ' ', 8 * sizeof(uint8_t));
00187
00188 if (vbimode == VBI_DVB || vbimode == VBI_DVB_SUBTITLE)
00189 {
00190 for (uint j = 8; j < 40; j++)
00191 ttpage->data[0][j] = m_bitswap[buf[j]];
00192 }
00193 else
00194 {
00195 memcpy(ttpage->data[0]+0, buf, 40);
00196 }
00197
00198 if ( !(ttpage->flags & TP_INTERRUPTED_SEQ))
00199 {
00200 memcpy(m_header, ttpage->data[0], 40);
00201 HeaderUpdated(ttpage->data[0],ttpage->lang);
00202 }
00203 }
00204
00208 void OSDTypeTeletext::AddTeletextData(int magazine, int row,
00209 const unsigned char* buf, int vbimode)
00210 {
00211 OSDUpdateLocker locker(&m_lock, this);
00212
00213 int b1, b2, b3, err;
00214
00215 if (magazine < 1 || magazine > 8)
00216 return;
00217
00218 int currentpage = m_magazines[magazine - 1].current_page;
00219 if (!currentpage)
00220 return;
00221
00222 TeletextSubPage *ttpage = &m_magazines[magazine - 1].loadingpage;
00223
00224 switch (row)
00225 {
00226 case 1 ... 24:
00227 if (vbimode == VBI_DVB || vbimode == VBI_DVB_SUBTITLE)
00228 {
00229 for (uint j = 0; j < 40; j++)
00230 ttpage->data[row][j] = m_bitswap[buf[j]];
00231 }
00232 else
00233 {
00234 memcpy(ttpage->data[row], buf, 40);
00235 }
00236 break;
00237 case 26:
00238
00239
00240
00241
00242
00243
00244
00245
00246 break;
00247 case 27:
00248 switch (vbimode)
00249 {
00250 case VBI_IVTV:
00251 b1 = hamm8(buf, &err);
00252 b2 = hamm8(buf + 37, &err);
00253 if (err & 0xF000)
00254 return;
00255 break;
00256 case VBI_DVB:
00257 case VBI_DVB_SUBTITLE:
00258 b1 = hamm84(buf, &err);
00259 b2 = hamm84(buf + 37, &err);
00260 if (err == 1)
00261 return;
00262 break;
00263 default:
00264 return;
00265 }
00266 if (b1 != 0 || not(b2 & 8))
00267 return;
00268
00269 for (int i = 0; i < 6; ++i)
00270 {
00271 err = 0;
00272 switch (vbimode)
00273 {
00274 case VBI_IVTV:
00275 b1 = hamm16(buf+1+6*i, &err);
00276 b2 = hamm16(buf+3+6*i, &err);
00277 b3 = hamm16(buf+5+6*i, &err);
00278 if (err & 0xF000)
00279 return;
00280 break;
00281 case VBI_DVB:
00282 case VBI_DVB_SUBTITLE:
00283 b1 = hamm84(buf+2+6*i, &err) * 16 +
00284 hamm84(buf+1+6*i, &err);
00285 b2 = hamm84(buf+4+6*i, &err) * 16 +
00286 hamm84(buf+3+6*i, &err);
00287 b3 = hamm84(buf+6+6*i, &err) * 16 +
00288 hamm84(buf+5+6*i, &err);
00289 if (err == 1)
00290 return;
00291 break;
00292 default:
00293 return;
00294 }
00295
00296 int x = (b2 >> 7) | ((b3 >> 5) & 0x06);
00297 ttpage->floflink[i] = ((magazine ^ x) ?: 8) * 256 + b1;
00298 ttpage->flof = 1;
00299 }
00300 break;
00301
00302 case 31:
00303 break;
00304
00305 default:
00306 break;
00307 }
00308 }
00309
00314 void OSDTypeTeletext::PageUpdated(int page, int subpage)
00315 {
00316 if (!m_displaying)
00317 return;
00318
00319 if (page != m_curpage)
00320 return;
00321
00322 if (subpage != m_cursubpage && m_cursubpage != -1)
00323 return;
00324
00325 m_page_changed = true;
00326 m_osd_changed = true;
00327 }
00328
00336 void OSDTypeTeletext::HeaderUpdated(unsigned char *page, int lang)
00337 {
00338 (void)lang;
00339
00340 if (!m_displaying)
00341 return;
00342
00343 if (page == NULL)
00344 return;
00345
00346 if (m_curpage_showheader == false)
00347 return;
00348
00349 m_header_changed = true;
00350
00351
00352
00353
00354
00355
00356 }
00357
00365 const TeletextPage *OSDTypeTeletext::FindPageInternal(
00366 int page, int direction) const
00367 {
00368 int mag = MAGAZINE(page);
00369
00370 if (mag > 8 || mag < 1)
00371 return NULL;
00372
00373 QMutexLocker lock(&m_magazines[mag - 1].lock);
00374
00375 int_to_page_t::const_iterator pageIter;
00376 pageIter = m_magazines[mag - 1].pages.find(page);
00377 if (pageIter == m_magazines[mag - 1].pages.end())
00378 return NULL;
00379
00380 const TeletextPage *res = &pageIter->second;
00381 if (direction == -1)
00382 {
00383 --pageIter;
00384 if (pageIter == m_magazines[mag - 1].pages.end())
00385 {
00386 int_to_page_t::const_reverse_iterator iter;
00387 iter = m_magazines[mag - 1].pages.rbegin();
00388 res = &iter->second;
00389 }
00390 else
00391 res = &pageIter->second;
00392 }
00393
00394 if (direction == 1)
00395 {
00396 ++pageIter;
00397 if (pageIter == m_magazines[mag - 1].pages.end())
00398 {
00399 pageIter = m_magazines[mag - 1].pages.begin();
00400 res = &pageIter->second;
00401 }
00402 else
00403 res = &pageIter->second;
00404 }
00405
00406 return res;
00407 }
00408
00418 const TeletextSubPage *OSDTypeTeletext::FindSubPageInternal(
00419 int page, int subpage, int direction) const
00420 {
00421 int mag = MAGAZINE(page);
00422
00423 if (mag > 8 || mag < 1)
00424 return NULL;
00425
00426 QMutexLocker lock(&m_magazines[mag - 1].lock);
00427
00428 int_to_page_t::const_iterator pageIter;
00429 pageIter = m_magazines[mag - 1].pages.find(page);
00430 if (pageIter == m_magazines[mag - 1].pages.end())
00431 return NULL;
00432
00433 const TeletextPage *ttpage = &(pageIter->second);
00434 int_to_subpage_t::const_iterator subpageIter =
00435 ttpage->subpages.begin();
00436
00437
00438 if (subpage != -1)
00439 subpageIter = ttpage->subpages.find(subpage);
00440
00441 if (subpageIter == ttpage->subpages.end())
00442 return NULL;
00443
00444 if (subpage == -1)
00445 return &(subpageIter->second);
00446
00447 const TeletextSubPage *res = &(subpageIter->second);
00448 if (direction == -1)
00449 {
00450 --subpageIter;
00451 if (subpageIter == ttpage->subpages.end())
00452 {
00453 int_to_subpage_t::const_reverse_iterator iter =
00454 ttpage->subpages.rbegin();
00455 res = &(iter->second);
00456 }
00457 else
00458 {
00459 res = &(subpageIter->second);
00460 }
00461 }
00462
00463 if (direction == 1)
00464 {
00465 ++subpageIter;
00466 if (subpageIter == ttpage->subpages.end())
00467 subpageIter = ttpage->subpages.begin();
00468
00469 res = &(subpageIter->second);
00470 }
00471
00472 return res;
00473 }
00474
00481 void OSDTypeTeletext::KeyPress(uint key)
00482 {
00483 OSDUpdateLocker locker(&m_lock, this);
00484
00485 int newPage = m_curpage;
00486 int newSubPage = m_cursubpage;
00487 bool numeric_input = false;
00488
00489 TeletextSubPage *curpage = FindSubPage(m_curpage, m_cursubpage);
00490 TeletextPage *page;
00491
00492 switch (key)
00493 {
00494 case TTKey::k0 ... TTKey::k9:
00495 numeric_input = true;
00496 m_curpage_showheader = true;
00497 if (m_pageinput[0] == ' ')
00498 m_pageinput[0] = '0' + static_cast<int> (key);
00499 else if (m_pageinput[1] == ' ')
00500 m_pageinput[1] = '0' + static_cast<int> (key);
00501 else if (m_pageinput[2] == ' ')
00502 {
00503 m_pageinput[2] = '0' + static_cast<int> (key);
00504 newPage = ((m_pageinput[0] - '0') * 256) +
00505 ((m_pageinput[1] - '0') * 16) +
00506 (m_pageinput[2] - '0');
00507 newSubPage = -1;
00508 }
00509 else
00510 {
00511 m_pageinput[0] = '0' + static_cast<int> (key);
00512 m_pageinput[1] = ' ';
00513 m_pageinput[2] = ' ';
00514 }
00515
00516 PageUpdated(m_curpage, m_cursubpage);
00517 break;
00518
00519 case TTKey::kNextPage:
00520 {
00521 TeletextPage *ttpage = FindPage(m_curpage, 1);
00522 if (ttpage)
00523 newPage = ttpage->pagenum;
00524 newSubPage = -1;
00525 m_curpage_showheader = true;
00526 break;
00527 }
00528
00529 case TTKey::kPrevPage:
00530 {
00531 TeletextPage *ttpage = FindPage(m_curpage, -1);
00532 if (ttpage)
00533 newPage = ttpage->pagenum;
00534 newSubPage = -1;
00535 m_curpage_showheader = true;
00536 break;
00537 }
00538
00539 case TTKey::kNextSubPage:
00540 {
00541 TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage, 1);
00542 if (ttpage)
00543 newSubPage = ttpage->subpagenum;
00544 m_curpage_showheader = true;
00545 break;
00546 }
00547
00548 case TTKey::kPrevSubPage:
00549 {
00550 TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage, -1);
00551 if (ttpage)
00552 newSubPage = ttpage->subpagenum;
00553 m_curpage_showheader = true;
00554 break;
00555 }
00556
00557 case TTKey::kHold:
00558 break;
00559
00560 case TTKey::kTransparent:
00561 m_transparent = !m_transparent;
00562 PageUpdated(m_curpage, m_cursubpage);
00563 break;
00564
00565 case TTKey::kRevealHidden:
00566 m_revealHidden = !m_revealHidden;
00567 PageUpdated(m_curpage, m_cursubpage);
00568 break;
00569
00570 case TTKey::kFlofRed:
00571 {
00572 if (!curpage)
00573 return;
00574
00575 if ((page = FindPage(curpage->floflink[0])) != NULL)
00576 {
00577 newPage = page->pagenum;
00578 newSubPage = -1;
00579 m_curpage_showheader = true;
00580 }
00581 break;
00582 }
00583
00584 case TTKey::kFlofGreen:
00585 {
00586 if (!curpage)
00587 return;
00588
00589 if ((page = FindPage(curpage->floflink[1])) != NULL)
00590 {
00591 newPage = page->pagenum;
00592 newSubPage = -1;
00593 m_curpage_showheader = true;
00594 }
00595 break;
00596 }
00597
00598 case TTKey::kFlofYellow:
00599 {
00600 if (!curpage)
00601 return;
00602
00603 if ((page = FindPage(curpage->floflink[2])) != NULL)
00604 {
00605 newPage = page->pagenum;
00606 newSubPage = -1;
00607 m_curpage_showheader = true;
00608 }
00609 break;
00610 }
00611
00612 case TTKey::kFlofBlue:
00613 {
00614 if (!curpage)
00615 return;
00616
00617 if ((page = FindPage(curpage->floflink[3])) != NULL)
00618 {
00619 newPage = page->pagenum;
00620 newSubPage = -1;
00621 m_curpage_showheader = true;
00622 }
00623 break;
00624 }
00625
00626 case TTKey::kFlofWhite:
00627 {
00628 if (!curpage)
00629 return;
00630
00631 if ((page = FindPage(curpage->floflink[4])) != NULL)
00632 {
00633 newPage = page->pagenum;
00634 newSubPage = -1;
00635 m_curpage_showheader = true;
00636 }
00637 break;
00638 }
00639 }
00640
00641 if (newPage < 0x100)
00642 newPage = 0x100;
00643 if (newPage > 0x899)
00644 newPage = 0x899;
00645
00646 if (!numeric_input)
00647 {
00648 m_pageinput[0] = (newPage / 256) + '0';
00649 m_pageinput[1] = ((newPage % 256) / 16) + '0';
00650 m_pageinput[2] = (newPage % 16) + '0';
00651 }
00652
00653 if (newPage != m_curpage || newSubPage != m_cursubpage)
00654 {
00655 m_curpage = newPage;
00656 m_cursubpage = newSubPage;
00657 m_revealHidden = false;
00658 PageUpdated(m_curpage, m_cursubpage);
00659 }
00660 }
00661
00667 void OSDTypeTeletext::SetPage(int page, int subpage)
00668 {
00669 OSDUpdateLocker locker(&m_lock, this);
00670
00671 if (page < 0x100 || page > 0x899)
00672 return;
00673
00674 m_pageinput[0] = (page / 256) + '0';
00675 m_pageinput[1] = ((page % 256) / 16) + '0';
00676 m_pageinput[2] = (page % 16) + '0';
00677
00678 m_curpage = page;
00679 m_cursubpage = subpage;
00680 PageUpdated(m_curpage, m_cursubpage);
00681 }
00682
00683 QColor color_tt2qt(int ttcolor)
00684 {
00685 QColor color;
00686
00687 switch (ttcolor & ~kTTColorTransparent)
00688 {
00689 case kTTColorBlack: color = OSDTypeTeletext::kColorBlack; break;
00690 case kTTColorRed: color = OSDTypeTeletext::kColorRed; break;
00691 case kTTColorGreen: color = OSDTypeTeletext::kColorGreen; break;
00692 case kTTColorYellow: color = OSDTypeTeletext::kColorYellow; break;
00693 case kTTColorBlue: color = OSDTypeTeletext::kColorBlue; break;
00694 case kTTColorMagenta: color = OSDTypeTeletext::kColorMagenta; break;
00695 case kTTColorCyan: color = OSDTypeTeletext::kColorCyan; break;
00696 case kTTColorWhite: color = OSDTypeTeletext::kColorWhite; break;
00697 }
00698
00699 return color;
00700 }
00701
00708 void OSDTypeTeletext::SetForegroundColor(int ttcolor) const
00709 {
00710 m_font->setColor(color_tt2qt(ttcolor));
00711 m_font->setShadow(0,0);
00712 m_font->setOutline(0);
00713 }
00714
00720 void OSDTypeTeletext::SetBackgroundColor(int ttcolor) const
00721 {
00722 const QColor color = color_tt2qt(ttcolor);
00723
00724 const int r = color.red();
00725 const int g = color.green();
00726 const int b = color.blue();
00727
00728 const float y = (0.299*r) + (0.587*g) + (0.114*b);
00729 const float u = (0.564*(b - y));
00730 const float v = (0.713*(r - y));
00731
00732 m_bgcolor_y = (uint8_t)(y);
00733 m_bgcolor_u = (uint8_t)(127 + u);
00734 m_bgcolor_v = (uint8_t)(127 + v);
00735 m_bgcolor_a = (ttcolor & kTTColorTransparent) ? 0x00 : 0xff;
00736 }
00737
00744 void OSDTypeTeletext::DrawBackground(OSDSurface *surface, int x, int y) const
00745 {
00746 x *= m_tt_colspace;
00747 x += m_displayrect.left();
00748
00749 y *= m_tt_rowspace;
00750 y += m_displayrect.top();
00751
00752 DrawRect(surface, QRect(x, y, m_tt_colspace, m_tt_rowspace));
00753 }
00754
00758 void OSDTypeTeletext::DrawRect(OSDSurface *surface, const QRect rect) const
00759 {
00760 QRect tmp = rect;
00761 surface->AddRect(tmp);
00762
00763 const int luma_stride = surface->width;
00764 const int chroma_stride = surface->width >> 1;
00765 const int y = rect.top(), x = rect.left();
00766 const int dy = rect.height(), dx = rect.width();
00767 const int ye = y + dy;
00768
00769 unsigned char *buf_y = surface->y + (luma_stride * y) + x;
00770 unsigned char *buf_u = surface->u + (chroma_stride * (y>>1)) + (x>>1);
00771 unsigned char *buf_v = surface->v + (chroma_stride * (y>>1)) + (x>>1);
00772 unsigned char *buf_a = surface->alpha + (luma_stride * y) + x;
00773
00774 for (int j = y; j < ye; j++)
00775 {
00776 for (int i = 0; i < dx; i++)
00777 {
00778 buf_y[i] = m_bgcolor_y;
00779 buf_a[i] = m_bgcolor_a;
00780 }
00781
00782 if (!(j & 1))
00783 {
00784 for (int k = 0; k < dx; k++)
00785 {
00786 buf_u[k>>1] = m_bgcolor_u;
00787 buf_v[k>>1] = m_bgcolor_v;
00788 }
00789
00790 buf_u += chroma_stride;
00791 buf_v += chroma_stride;
00792 }
00793
00794 buf_y += luma_stride;
00795 buf_a += luma_stride;
00796 }
00797 }
00798
00807 void OSDTypeTeletext::DrawCharacter(OSDSurface *surface,
00808 int x, int y,
00809 QChar ch, int doubleheight) const
00810 {
00811 if (!m_font)
00812 return;
00813
00814 QString line = ch;
00815
00816 x *= m_tt_colspace;
00817 x += m_displayrect.left();
00818
00819 y *= m_tt_rowspace;
00820 y += m_displayrect.top();
00821
00822 m_font->DrawString(surface, x, y, line,
00823 surface->width, surface->height,
00824 255, doubleheight);
00825 }
00826
00835 void OSDTypeTeletext::DrawMosaic(OSDSurface *surface, int x, int y,
00836 int code, int doubleheight) const
00837 {
00838 x *= m_tt_colspace;
00839 x += m_displayrect.left();
00840
00841 y *= m_tt_rowspace;
00842 y += m_displayrect.top();
00843
00844 int dx = (int)round(m_tt_colspace / 2) + 1;
00845 int dy = (int)round(m_tt_rowspace / 3) + 1;
00846 dy = (doubleheight) ? (2 * dy) : dy;
00847
00848 if (code & 0x10)
00849 DrawRect(surface, QRect(x, y + 2*dy, dx, dy));
00850 if (code & 0x40)
00851 DrawRect(surface, QRect(x + dx, y + 2*dy, dx, dy));
00852 if (code & 0x01)
00853 DrawRect(surface, QRect(x, y, dx, dy));
00854 if (code & 0x02)
00855 DrawRect(surface, QRect(x + dx, y, dx, dy));
00856 if (code & 0x04)
00857 DrawRect(surface, QRect(x, y + dy, dx, dy));
00858 if (code & 0x08)
00859 DrawRect(surface, QRect(x + dx, y + dy, dx, dy));
00860 }
00861
00865 static char cvt_char(char ch, int lang)
00866 {
00867 int c = 0;
00868 for (int j = 0; j < 14; j++)
00869 {
00870 c = ch & 0x7F;
00871 if (c == lang_chars[0][j])
00872 ch = lang_chars[lang + 1][j];
00873 }
00874 return ch;
00875 }
00876
00877 void OSDTypeTeletext::DrawLine(OSDSurface *surface, const unsigned char *page,
00878 uint row, int lang) const
00879 {
00880 bool mosaic;
00881 bool conceal;
00882 bool seperation;
00883 bool flash;
00884 bool doubleheight;
00885 bool blink;
00886 bool hold;
00887 bool endbox;
00888 bool startbox;
00889
00890 char last_ch = ' ';
00891 char ch;
00892
00893 uint fgcolor = kTTColorWhite;
00894 uint bgcolor = kTTColorBlack;
00895 uint newfgcolor = kTTColorWhite;
00896 uint newbgcolor = kTTColorBlack;
00897
00898 if (m_curpage_issubtitle || m_transparent)
00899 {
00900 bgcolor = kTTColorTransparent;
00901 newbgcolor = kTTColorTransparent;
00902
00903
00904
00905 bool isBlank = true;
00906 for (uint i = (row == 1 ? 8 : 0); i < (uint) kTeletextColumns; i++)
00907 {
00908 ch = page[i] & 0x7F;
00909 if (ch != ' ')
00910 {
00911 isBlank = false;
00912 break;
00913 }
00914 }
00915
00916 if (isBlank)
00917 return;
00918 }
00919
00920 SetForegroundColor(fgcolor);
00921 SetBackgroundColor(bgcolor);
00922
00923 mosaic = false;
00924 seperation = false;
00925 conceal = false;
00926 flash = false;
00927 doubleheight = false;
00928 blink = false;
00929 hold = false;
00930 endbox = false;
00931 startbox = false;
00932 uint flof_link_count = 0;
00933
00934 if (row == 1)
00935 {
00936 for (uint x = 0; x < 8; x++)
00937 DrawBackground(surface, x, 1);
00938 }
00939
00940 for (uint x = (row == 1 ? 8 : 0); x < (uint)kTeletextColumns; ++x)
00941 {
00942 if (startbox)
00943 {
00944 bgcolor = kTTColorBlack;
00945 startbox = false;
00946 }
00947
00948 if (endbox)
00949 {
00950 bgcolor = kTTColorTransparent;
00951 endbox = false;
00952 }
00953
00954 SetForegroundColor(fgcolor);
00955 SetBackgroundColor(bgcolor);
00956
00957 ch = page[x] & 0x7F;
00958 switch (ch)
00959 {
00960 case 0x00 ... 0x07:
00961 fgcolor = ch & 7;
00962 mosaic = false;
00963 conceal = false;
00964
00965 flof_link_count += (row == 25) ? 1 : 0;
00966 goto ctrl;
00967 case 0x08:
00968
00969 goto ctrl;
00970 case 0x09:
00971 flash = false;
00972 goto ctrl;
00973 case 0x0a:
00974 endbox = true;
00975 goto ctrl;
00976 case 0x0b:
00977 if (x < kTeletextColumns - 1 && ((page[x + 1] & 0x7F) != 0x0b))
00978 startbox = true;
00979 goto ctrl;
00980 case 0x0c:
00981 doubleheight = false;
00982 goto ctrl;
00983 case 0x0d:
00984 doubleheight = row < kTeletextRows-1;
00985 goto ctrl;
00986 case 0x10 ... 0x17:
00987 fgcolor = ch & 7;
00988 mosaic = true;
00989 conceal = false;
00990 goto ctrl;
00991 case 0x18:
00992 conceal = true;
00993 goto ctrl;
00994 case 0x19:
00995 seperation = false;
00996 goto ctrl;
00997 case 0x1a:
00998 seperation = true;
00999 goto ctrl;
01000 case 0x1c:
01001 bgcolor = kTTColorBlack;
01002 goto ctrl;
01003 case 0x1d:
01004 bgcolor = fgcolor;
01005 goto ctrl;
01006 case 0x1e:
01007 hold = true;
01008 goto ctrl;
01009 case 0x1f:
01010 hold = false;
01011 goto ctrl;
01012 case 0x0e:
01013 case 0x0f:
01014 case 0x1b:
01015 ch = ' ';
01016 break;
01017 ctrl:
01018 ch = ' ';
01019 if (hold && mosaic)
01020 ch = last_ch;
01021 break;
01022
01023 case 0x80 ... 0x9f:
01024 ch = ' ';
01025 break;
01026 default:
01027 if (conceal && !m_revealHidden)
01028 ch = ' ';
01029 break;
01030 }
01031
01032
01033 if (flof_link_count && (flof_link_count <= 6))
01034 {
01035 const TeletextSubPage *ttpage =
01036 FindSubPage(m_curpage, m_cursubpage);
01037
01038 if (ttpage)
01039 {
01040 bool has_flof = ttpage->floflink[flof_link_count - 1];
01041 ch = (has_flof) ? ch : ' ';
01042 }
01043 }
01044
01045 newfgcolor = fgcolor;
01046 newbgcolor = bgcolor;
01047
01048 SetForegroundColor(newfgcolor);
01049 SetBackgroundColor(newbgcolor);
01050 if ((row != 0) || (x > 7))
01051 {
01052 if (m_transparent)
01053 SetBackgroundColor(kTTColorTransparent);
01054
01055 DrawBackground(surface, x, row);
01056 if (doubleheight && row < (uint)kTeletextRows)
01057 DrawBackground(surface, x, row + 1);
01058
01059 if ((mosaic) && (ch < 0x40 || ch > 0x5F))
01060 {
01061 SetBackgroundColor(newfgcolor);
01062 DrawMosaic(surface, x, row, ch, doubleheight);
01063 }
01064 else
01065 {
01066 char c2 = cvt_char(ch, lang);
01067 bool dh = doubleheight && row < (uint)kTeletextRows;
01068 int rw = (dh) ? row + 1 : row;
01069 DrawCharacter(surface, x, rw, c2, dh);
01070 }
01071 }
01072 }
01073 }
01074
01075 void OSDTypeTeletext::DrawHeader(OSDSurface *surface,
01076 const unsigned char* page, int lang) const
01077 {
01078 if (!m_displaying)
01079 return;
01080
01081 if (page != NULL)
01082 DrawLine(surface, page, 1, lang);
01083
01084 DrawStatus(surface);
01085 }
01086
01087 void OSDTypeTeletext::DrawPage(OSDSurface *surface) const
01088 {
01089 if (!m_displaying)
01090 return;
01091
01092 const TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage);
01093
01094 if (!ttpage)
01095 {
01096
01097 DrawHeader(surface, NULL, 0);
01098 return;
01099 }
01100
01101 m_cursubpage = ttpage->subpagenum;
01102
01103 int a = 0;
01104 if ((ttpage->subtitle) ||
01105 (ttpage->flags & (TP_SUPPRESS_HEADER | TP_NEWSFLASH | TP_SUBTITLE)))
01106 {
01107 a = 1;
01108
01109 m_curpage_showheader = false;
01110 m_curpage_issubtitle = true;
01111 }
01112 else
01113 {
01114 m_curpage_issubtitle = false;
01115 m_curpage_showheader = true;
01116 DrawHeader(surface, m_header, ttpage->lang);
01117
01118 m_header_changed = false;
01119 }
01120
01121 for (int y = kTeletextRows - a; y >= 2; y--)
01122 DrawLine(surface, ttpage->data[y-1], y, ttpage->lang);
01123
01124 m_page_changed = false;
01125 }
01126
01127 void OSDTypeTeletext::Reinit(float wmult, float hmult)
01128 {
01129 OSDUpdateLocker locker(&m_lock, this);
01130
01131 m_displayrect = bias(m_unbiasedrect, wmult, hmult);
01132 m_tt_colspace = m_displayrect.width() / kTeletextColumns;
01133 m_tt_rowspace = m_displayrect.height() / kTeletextRows;
01134 }
01135
01136 void OSDTypeTeletext::Draw(OSDSurface *surface,
01137 int , int ,
01138 int , int )
01139 {
01140 QMutexLocker locker(&m_lock);
01141
01142 DrawPage(surface);
01143 }
01144
01145 void OSDTypeTeletext::DrawStatus(OSDSurface *surface) const
01146 {
01147 SetForegroundColor(kTTColorWhite);
01148 SetBackgroundColor(kTTColorBlack);
01149
01150 if (!m_transparent)
01151 for (int i = 0; i < 40; ++i)
01152 DrawBackground(surface, i, 0);
01153
01154 DrawCharacter(surface, 1, 0, 'P', 0);
01155 DrawCharacter(surface, 2, 0, m_pageinput[0], 0);
01156 DrawCharacter(surface, 3, 0, m_pageinput[1], 0);
01157 DrawCharacter(surface, 4, 0, m_pageinput[2], 0);
01158
01159 const TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage);
01160
01161 if (!ttpage)
01162 {
01163 SetBackgroundColor(kTTColorBlack);
01164 SetForegroundColor(kTTColorWhite);
01165
01166 if (!m_transparent)
01167 for (int i = 7; i < 40; i++)
01168 DrawBackground(surface, i, 0);
01169
01170 QString str = QObject::tr("Page Not Available",
01171 "Requested Teletext page not available");
01172 for (uint i = 0; (i < 30) && i < str.length(); i++)
01173 DrawCharacter(surface, i+10, 0, str[i], 0);
01174
01175 return;
01176 }
01177
01178
01179 QString str = "";
01180 int count = 1, selected = 0;
01181 const TeletextPage *page = FindPage(m_curpage);
01182 if (page)
01183 {
01184 int_to_subpage_t::const_iterator subpageIter;
01185 subpageIter = page->subpages.begin();
01186 while (subpageIter != page->subpages.end())
01187 {
01188 const TeletextSubPage *subpage = &subpageIter->second;
01189
01190 if (subpage->subpagenum == m_cursubpage)
01191 {
01192 selected = count;
01193 str += "*";
01194 }
01195 else
01196 str += " ";
01197
01198 str += QString().sprintf("%02X", subpage->subpagenum);
01199
01200 ++subpageIter;
01201 ++count;
01202 }
01203 }
01204
01205 if (str.isEmpty())
01206 return;
01207
01208
01209 if (count < 10)
01210 {
01211 QString spaces;
01212 spaces.fill(' ', 27 - str.length());
01213 str = " <" + str + spaces + " > ";
01214 }
01215 else
01216 {
01217
01218 int startPos = selected - 5;
01219 if (startPos < 0)
01220 startPos = 0;
01221 if (startPos + 9 >= count)
01222 startPos = count - 10;
01223
01224 str = " <" + str.mid(startPos * 3, 27) + " > ";
01225 }
01226
01227 SetForegroundColor(kTTColorWhite);
01228 for (int x = 0; x < 11; x++)
01229 {
01230 if (m_transparent)
01231 SetBackgroundColor(kTTColorTransparent);
01232 else
01233 SetBackgroundColor(kTTColorBlack);
01234
01235 DrawBackground(surface, x * 3 + 7, 0);
01236
01237 if (str[x * 3] == '*')
01238 {
01239 str[x * 3] = ' ';
01240 SetBackgroundColor(kTTColorRed);
01241 }
01242
01243 DrawBackground(surface, x * 3 + 8, 0);
01244 DrawBackground(surface, x * 3 + 9, 0);
01245
01246 DrawCharacter(surface, x * 3 + 7, 0, str[x * 3], 0);
01247 DrawCharacter(surface, x * 3 + 8, 0, str[x * 3 + 1], 0);
01248 DrawCharacter(surface, x * 3 + 9, 0, str[x * 3 + 2], 0);
01249 }
01250 }
01251
01281 OSDUpdateLocker::OSDUpdateLocker(QMutex *lock, OSDTypeTeletext *parent) :
01282 m_lock(lock), m_parent(parent)
01283 {
01284 m_lock->lock();
01285 }
01286
01287 OSDUpdateLocker::~OSDUpdateLocker(void)
01288 {
01289
01290 if (m_parent->m_osd_changed)
01291 {
01292 m_parent->m_osd_changed = false;
01293 m_lock->unlock();
01294
01295
01296 m_parent->m_osd->UpdateTeletext();
01297 }
01298 else
01299 {
01300
01301 m_lock->unlock();
01302 }
01303 }