From 9fc9ee1b0d328d840877f42d0d99152bf984e906 Mon Sep 17 00:00:00 2001 From: Mark Kendall Date: Tue, 30 Nov 2010 03:32:38 +0000 Subject: [PATCH] Refactor TeletextDecoder and TeletextScreen and add a new TeletextReader class. This follows the approach used in the other subtitle and caption classes whereby the screen object handles OSD representation of the data, the reader object holds the state and data and the decoder object feeds new data into the reader. This simplifies setup and initialisation of the teletext objects and removes the requirement to lock the OSD from the decoder, which was causing endless problems. The previous behaviour of always decoding teletext packets is also reinstated which radically improves responsiveness. Actually decoding and parsing the packets is trivial for a modern processor and hence should have no impact on performance. I will backport to release-0-24-fixes in a few days if there are no reported problems. Refs #9271 git-svn-id: http://svn.mythtv.org/svn/trunk@27381 7dbf422c-18fa-0310-86e9-fd20926502f2 --- mythtv/libs/libmythtv/avformatdecoder.cpp | 9 +- mythtv/libs/libmythtv/avformatdecoder.h | 1 - mythtv/libs/libmythtv/decoderbase.h | 1 - mythtv/libs/libmythtv/libmythtv.pro | 4 +- mythtv/libs/libmythtv/mythplayer.cpp | 27 - mythtv/libs/libmythtv/mythplayer.h | 6 +- mythtv/libs/libmythtv/teletextdecoder.cpp | 63 +- mythtv/libs/libmythtv/teletextdecoder.h | 42 +- mythtv/libs/libmythtv/teletextreader.cpp | 609 +++++++++++++++++++ mythtv/libs/libmythtv/teletextreader.h | 162 ++++++ mythtv/libs/libmythtv/teletextscreen.cpp | 674 ++-------------------- mythtv/libs/libmythtv/teletextscreen.h | 153 +---- 12 files changed, 841 insertions(+), 910 deletions(-) create mode 100644 mythtv/libs/libmythtv/teletextreader.cpp create mode 100644 mythtv/libs/libmythtv/teletextreader.h diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp index 7c07634ec0e..6d9f8b4f640 100644 --- a/mythtv/libs/libmythtv/avformatdecoder.cpp +++ b/mythtv/libs/libmythtv/avformatdecoder.cpp @@ -28,6 +28,7 @@ using namespace std; #include "dvbdescriptors.h" #include "cc608decoder.h" #include "cc708decoder.h" +#include "teletextdecoder.h" #include "subtitlereader.h" #include "interactivetv.h" #include "DVDRingBuffer.h" @@ -277,7 +278,8 @@ AvFormatDecoder::AvFormatDecoder(MythPlayer *parent, // Closed Caption & Teletext decoders ccd608(new CC608Decoder(parent->GetCC608Reader())), ccd708(new CC708Decoder(parent->GetCC708Reader())), - ttd(new TeletextDecoder(parent)), subReader(parent->GetSubReader()), + ttd(new TeletextDecoder(parent->GetTeletextReader())), + subReader(parent->GetSubReader()), // Interactive TV itv(NULL), // Audio @@ -3511,11 +3513,6 @@ int AvFormatDecoder::GetTeletextDecoderType(void) const return ttd->GetDecoderType(); } -void AvFormatDecoder::SetTeletextDecoderViewer(TeletextViewer *view) -{ - ttd->SetViewer(view); -} - QString AvFormatDecoder::GetXDS(const QString &key) const { return ccd608->GetXDS(key); diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h index 487ab2bd84a..3400943c1f7 100644 --- a/mythtv/libs/libmythtv/avformatdecoder.h +++ b/mythtv/libs/libmythtv/avformatdecoder.h @@ -158,7 +158,6 @@ class AvFormatDecoder : public DecoderBase virtual int64_t NormalizeVideoTimecode(AVStream *st, int64_t timecode); virtual int GetTeletextDecoderType(void) const; - virtual void SetTeletextDecoderViewer(TeletextViewer*); virtual QString GetXDS(const QString&) const; diff --git a/mythtv/libs/libmythtv/decoderbase.h b/mythtv/libs/libmythtv/decoderbase.h index c143a8b8485..38826863199 100644 --- a/mythtv/libs/libmythtv/decoderbase.h +++ b/mythtv/libs/libmythtv/decoderbase.h @@ -188,7 +188,6 @@ class DecoderBase inline int NextTrack(uint type); virtual int GetTeletextDecoderType(void) const { return -1; } - virtual void SetTeletextDecoderViewer(TeletextViewer*) {;} virtual QString GetXDS(const QString&) const { return QString::null; } diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro index 17ceff29fdd..d404d129c69 100644 --- a/mythtv/libs/libmythtv/libmythtv.pro +++ b/mythtv/libs/libmythtv/libmythtv.pro @@ -197,8 +197,8 @@ HEADERS += datadirect.h SOURCES += datadirect.cpp # Teletext stuff -HEADERS += teletextdecoder.h vbilut.h -SOURCES += teletextdecoder.cpp vbilut.cpp +HEADERS += teletextdecoder.h teletextreader.h vbilut.h +SOURCES += teletextdecoder.cpp teletextreader.cpp vbilut.cpp # MPEG parsing stuff HEADERS += mpeg/tspacket.h mpeg/pespacket.h diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp index b9601fca7ec..198e1facbb5 100644 --- a/mythtv/libs/libmythtv/mythplayer.cpp +++ b/mythtv/libs/libmythtv/mythplayer.cpp @@ -210,7 +210,6 @@ MythPlayer::MythPlayer(bool muted) ttPageNum(0x888), // Support for captions, teletext, etc. decoded by libav textDesired(false), enableCaptions(false), disableCaptions(false), - initTeletext(false), // CC608/708 db_prefer708(true), cc608(this), cc708(this), // MHEG/MHI Interactive TV visible in OSD @@ -617,7 +616,6 @@ void MythPlayer::ReinitOSD(void) uint old = textDisplayMode; ToggleCaptions(old); osd->Reinit(visible, aspect); - SetupTeletextViewer(); EnableCaptions(old, false); } } @@ -1433,26 +1431,6 @@ bool MythPlayer::ToggleCaptions(uint type) return textDisplayMode; } -void MythPlayer::SetupTeletextViewer(void) -{ - if (QThread::currentThread() != playerThread) - { - initTeletext = true; - return; - } - - if (osd) - { - QMutexLocker locker(&osdLock); - TeletextViewer* ttview = (TeletextViewer*)osd->InitTeletext(); - if (ttview && decoder) - { - initTeletext = false; - decoder->SetTeletextDecoderViewer(ttview); - } - } -} - void MythPlayer::SetCaptionsEnabled(bool enable, bool osd_msg) { QMutexLocker locker(&osdLock); @@ -2050,7 +2028,6 @@ void MythPlayer::VideoStart(void) videoOutput->GetOSDBounds(total, visible, aspect, scaling, 1.0f); osd->Init(visible, aspect); videoOutput->InitOSD(osd); - SetupTeletextViewer(); osd->EnableSubtitles(kDisplayNone); #ifdef USING_MHEG @@ -2543,10 +2520,6 @@ void MythPlayer::EventLoop(void) if (disableCaptions) SetCaptionsEnabled(false, false); - // (re)initialise the teletext viewer - if (initTeletext) - SetupTeletextViewer(); - // refresh the position map for an in-progress recording while editing if (hasFullPositionMap && watchingrecording && player_ctx->recorder && player_ctx->recorder->IsValidRecorder() && deleteMap.IsEditing()) diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h index 325efee36df..d6760649e0a 100644 --- a/mythtv/libs/libmythtv/mythplayer.h +++ b/mythtv/libs/libmythtv/mythplayer.h @@ -15,7 +15,7 @@ #include "osd.h" #include "jitterometer.h" #include "videooutbase.h" -#include "teletextdecoder.h" +#include "teletextreader.h" #include "subtitlereader.h" #include "tv_play.h" #include "yuv2rgb.h" @@ -254,11 +254,11 @@ class MPUBLIC MythPlayer virtual bool PrepareAudioSample(int64_t &timecode); // Public Closed caption and teletext stuff - void SetupTeletextViewer(void); uint GetCaptionMode(void) const { return textDisplayMode; } CC708Reader* GetCC708Reader(void) { return &cc708; } CC608Reader* GetCC608Reader(void) { return &cc608; } SubtitleReader* GetSubReader(void) { return &subReader; } + TeletextReader* GetTeletextReader(void) { return &ttxReader; } // Public Audio/Subtitle/EIA-608/EIA-708 stream selection - thread safe void TracksChanged(uint trackType); @@ -634,12 +634,12 @@ class MPUBLIC MythPlayer // Support for captions, teletext, etc. decoded by libav SubtitleReader subReader; + TeletextReader ttxReader; /// This allows us to enable captions/subtitles later if the streams /// are not immediately available when the video starts playing. bool textDesired; bool enableCaptions; bool disableCaptions; - bool initTeletext; // CC608/708 bool db_prefer708; diff --git a/mythtv/libs/libmythtv/teletextdecoder.cpp b/mythtv/libs/libmythtv/teletextdecoder.cpp index f9db7fc2af9..88c9c458f7d 100644 --- a/mythtv/libs/libmythtv/teletextdecoder.cpp +++ b/mythtv/libs/libmythtv/teletextdecoder.cpp @@ -31,14 +31,10 @@ using namespace std; #include "osd.h" #include "teletextdecoder.h" +#include "teletextreader.h" #include "vbilut.h" -#include "mythplayer.h" #include "mythverbose.h" -/******************************************************************/ -//Decoder section -// - /** \fn TeletextDecoder::Decode(const unsigned char*, int) * \brief Decodes teletext data * @@ -50,36 +46,8 @@ void TeletextDecoder::Decode(const unsigned char *buf, int vbimode) int err = 0, latin1 = -1, zahl1, pagenum, subpagenum, lang, flags; uint magazine, packet, header; - if (!m_player) - return; - - int mode = m_player->GetCaptionMode(); - if (!((mode == kDisplayNUVTeletextCaptions) || - (mode == kDisplayTeletextCaptions) || - (mode == kDisplayTeletextMenu))) - { - return; - } - - if (!m_player->TryLockOSD()) - { - VERBOSE(VB_PLAYBACK, "TeletextDecoder: Failed to get OSD lock."); - return; - } - - if (!m_teletextviewer && m_player) - { - m_player->UnlockOSD(); - m_player->SetupTeletextViewer(); - return; - } - - if (!m_teletextviewer) - { - VERBOSE(VB_VBI, "TeletextDecoder: No Teletext Viewer defined!"); - m_player->UnlockOSD(); + if (!m_teletext_reader) return; - } m_decodertype = vbimode; @@ -89,10 +57,7 @@ void TeletextDecoder::Decode(const unsigned char *buf, int vbimode) header = hamm16(buf, &err); if (err & 0xf000) - { - m_player->UnlockOSD(); return; // error in data header - } magazine = header & 7; packet = (header >> 3) & 0x1f; @@ -125,16 +90,12 @@ void TeletextDecoder::Decode(const unsigned char *buf, int vbimode) packet += 16; if (err == 1) - { - m_player->UnlockOSD(); return; // error in data header - } buf += 2; break; default: - m_player->UnlockOSD(); return; // error in vbimode } @@ -150,10 +111,7 @@ void TeletextDecoder::Decode(const unsigned char *buf, int vbimode) b3 = hamm16(buf+4, &err);// subpage number + flags b4 = hamm16(buf+6, &err);// language code + more flags if (err & 0xf000) - { - m_player->UnlockOSD(); return; - } break; @@ -164,22 +122,14 @@ void TeletextDecoder::Decode(const unsigned char *buf, int vbimode) b3 = hamm84(buf+5, &err)*16+hamm84(buf+4, &err); b4 = hamm84(buf+7, &err)*16+hamm84(buf+6, &err); if (err == 1) - { - m_player->UnlockOSD(); return; - } break; default: - m_player->UnlockOSD(); return; // error in vbimode } - //VERBOSE(VB_VBI, QString("Page Header found: " - // "Magazine %1, Page Number %2") - // .arg(magazine).arg(b1)); - subpagenum= (b2 + b3 * 256) & 0x3f7f; pagenum = (magazine?:8)*256 + b1; @@ -187,15 +137,14 @@ void TeletextDecoder::Decode(const unsigned char *buf, int vbimode) flags = b4 & 0x1F; flags |= b3 & 0xC0; flags |= (b2 & 0x80) >> 2; - m_teletextviewer->AddPageHeader(pagenum, subpagenum, buf, - vbimode, lang, flags); + m_teletext_reader->AddPageHeader(pagenum, subpagenum, buf, + vbimode, lang, flags); break; default: // Page Data - m_teletextviewer->AddTeletextData((magazine?:8), packet, - buf, vbimode); + m_teletext_reader->AddTeletextData((magazine?:8), packet, + buf, vbimode); break; } - m_player->UnlockOSD(); } diff --git a/mythtv/libs/libmythtv/teletextdecoder.h b/mythtv/libs/libmythtv/teletextdecoder.h index 0cd2ed5da42..d7175d28caf 100644 --- a/mythtv/libs/libmythtv/teletextdecoder.h +++ b/mythtv/libs/libmythtv/teletextdecoder.h @@ -3,52 +3,20 @@ #include -class TeletextViewer -{ - public: - TeletextViewer() { } - virtual ~TeletextViewer() { } - - virtual void KeyPress(uint key) { (void) key; } - virtual void SetPage(int page, int subpage) { (void) page; (void) subpage; } - virtual void SetDisplaying(bool displaying) { (void) displaying; } - - virtual void Reset(void) = 0; - virtual void AddPageHeader(int page, int subpage, - const uint8_t *buf, int vbimode, - int lang, int flags) = 0; - virtual void AddTeletextData(int magazine, int row, - const uint8_t* buf, int vbimode) = 0; -}; - -class MythPlayer; +class TeletextReader; class TeletextDecoder { public: - TeletextDecoder(MythPlayer *player) - : m_player(player), m_teletextviewer(NULL), m_decodertype(-1) {} + TeletextDecoder(TeletextReader *reader) + : m_teletext_reader(reader), m_decodertype(-1) {} virtual ~TeletextDecoder() {} - /// Sets the TeletextViewer which will get the text from this decoder. - void SetViewer(TeletextViewer *viewer) - { m_teletextviewer = viewer; } - - /** - * \brief Returns the actual decoder type (DVB,IVTV,DVB_SUBTITLE...) - * - * This is used for the decision in NuppelVideoPlayer - * to this TeletextDecoder or the caption only decoder. - */ - int GetDecoderType(void) const - { return m_decodertype; } - + int GetDecoderType(void) const { return m_decodertype; } void Decode(const unsigned char *buf, int vbimode); private: - - MythPlayer *m_player; - TeletextViewer *m_teletextviewer; + TeletextReader *m_teletext_reader; int m_decodertype; }; diff --git a/mythtv/libs/libmythtv/teletextreader.cpp b/mythtv/libs/libmythtv/teletextreader.cpp new file mode 100644 index 00000000000..9d07c7dab4d --- /dev/null +++ b/mythtv/libs/libmythtv/teletextreader.cpp @@ -0,0 +1,609 @@ +#include "teletextreader.h" + +#include +#include "vbilut.h" + +#define MAGAZINE(page) (page / 256) + +TeletextReader::TeletextReader() + : m_curpage(0x100), m_cursubpage(-1), + m_curpage_showheader(true), m_curpage_issubtitle(false), + m_transparent(false), m_revealHidden(false), + m_header_changed(false), m_page_changed(false), + m_fetchpage(0), m_fetchsubpage(0) +{ + memset(m_pageinput, 0, sizeof(m_pageinput)); + memset(m_header, 0, sizeof(m_header)); + for (int i = 0; i < 256; i++) + { + m_bitswap[i] = 0; + for (int bit = 0; bit < 8; bit++) + if (i & (1 << bit)) + m_bitswap[i] |= (1 << (7-bit)); + } + Reset(); +} + +TeletextReader::~TeletextReader() +{ +} + +void TeletextReader::KeyPress(unsigned int key) +{ + int newPage = m_curpage; + int newSubPage = m_cursubpage; + bool numeric_input = false; + + TeletextSubPage *curpage = FindSubPage(m_curpage, m_cursubpage); + TeletextPage *page; + + switch (key) + { + case TTKey::k0 ... TTKey::k9: + numeric_input = true; + m_curpage_showheader = true; + if (m_pageinput[0] == ' ') + m_pageinput[0] = '0' + static_cast (key); + else if (m_pageinput[1] == ' ') + m_pageinput[1] = '0' + static_cast (key); + else if (m_pageinput[2] == ' ') + { + m_pageinput[2] = '0' + static_cast (key); + newPage = ((m_pageinput[0] - '0') * 256) + + ((m_pageinput[1] - '0') * 16) + + (m_pageinput[2] - '0'); + newSubPage = -1; + } + else + { + m_pageinput[0] = '0' + static_cast (key); + m_pageinput[1] = ' '; + m_pageinput[2] = ' '; + } + + PageUpdated(m_curpage, m_cursubpage); + break; + + case TTKey::kNextPage: + { + TeletextPage *ttpage = FindPage(m_curpage, 1); + if (ttpage) + newPage = ttpage->pagenum; + newSubPage = -1; + m_curpage_showheader = true; + break; + } + + case TTKey::kPrevPage: + { + TeletextPage *ttpage = FindPage(m_curpage, -1); + if (ttpage) + newPage = ttpage->pagenum; + newSubPage = -1; + m_curpage_showheader = true; + break; + } + + case TTKey::kNextSubPage: + { + TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage, 1); + if (ttpage) + newSubPage = ttpage->subpagenum; + m_curpage_showheader = true; + break; + } + + case TTKey::kPrevSubPage: + { + TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage, -1); + if (ttpage) + newSubPage = ttpage->subpagenum; + m_curpage_showheader = true; + break; + } + + case TTKey::kHold: + break; + + case TTKey::kTransparent: + m_transparent = !m_transparent; + PageUpdated(m_curpage, m_cursubpage); + break; + + case TTKey::kRevealHidden: + m_revealHidden = !m_revealHidden; + PageUpdated(m_curpage, m_cursubpage); + break; + + case TTKey::kFlofRed: + { + if (!curpage) + return; + + if ((page = FindPage(curpage->floflink[0])) != NULL) + { + newPage = page->pagenum; + newSubPage = -1; + m_curpage_showheader = true; + } + break; + } + + case TTKey::kFlofGreen: + { + if (!curpage) + return; + + if ((page = FindPage(curpage->floflink[1])) != NULL) + { + newPage = page->pagenum; + newSubPage = -1; + m_curpage_showheader = true; + } + break; + } + + case TTKey::kFlofYellow: + { + if (!curpage) + return; + + if ((page = FindPage(curpage->floflink[2])) != NULL) + { + newPage = page->pagenum; + newSubPage = -1; + m_curpage_showheader = true; + } + break; + } + + case TTKey::kFlofBlue: + { + if (!curpage) + return; + + if ((page = FindPage(curpage->floflink[3])) != NULL) + { + newPage = page->pagenum; + newSubPage = -1; + m_curpage_showheader = true; + } + break; + } + + case TTKey::kFlofWhite: + { + if (!curpage) + return; + + if ((page = FindPage(curpage->floflink[4])) != NULL) + { + newPage = page->pagenum; + newSubPage = -1; + m_curpage_showheader = true; + } + break; + } + } + + if (newPage < 0x100) + newPage = 0x100; + if (newPage > 0x899) + newPage = 0x899; + + if (!numeric_input) + { + m_pageinput[0] = (newPage / 256) + '0'; + m_pageinput[1] = ((newPage % 256) / 16) + '0'; + m_pageinput[2] = (newPage % 16) + '0'; + } + + if (newPage != m_curpage || newSubPage != m_cursubpage) + { + m_curpage = newPage; + m_cursubpage = newSubPage; + m_revealHidden = false; + PageUpdated(m_curpage, m_cursubpage); + } +} + +QString TeletextReader::GetPage(void) +{ + QString str = ""; + int mag = MAGAZINE(m_curpage); + if (mag > 8 || mag < 1) + return str; + + int count = 1, selected = 0; + const TeletextPage *page = FindPage(m_curpage); + if (page) + { + m_magazines[mag - 1].lock.lock(); + int_to_subpage_t::const_iterator subpageIter; + subpageIter = page->subpages.begin(); + while (subpageIter != page->subpages.end()) + { + const TeletextSubPage *subpage = &subpageIter->second; + + if (subpage->subpagenum == m_cursubpage) + { + selected = count; + str += "*"; + } + else + str += " "; + + str += QString().sprintf("%02X", subpage->subpagenum); + + ++subpageIter; + ++count; + } + m_magazines[mag - 1].lock.unlock(); + } + + if (str.isEmpty()) + return str; + + // if there are less than 9 subpages fill the empty slots with spaces + if (count < 10) + { + QString spaces; + spaces.fill(' ', 27 - str.length()); + str = " <" + str + spaces + " > "; + } + else + { + // try to centralize the selected sub page in the list + int startPos = selected - 5; + if (startPos < 0) + startPos = 0; + if (startPos + 9 >= count) + startPos = count - 10; + + str = " <" + str.mid(startPos * 3, 27) + " > "; + } + return str; +} + +void TeletextReader::SetPage(int page, int subpage) +{ + if (page < 0x100 || page > 0x899) + return; + + m_pageinput[0] = (page / 256) + '0'; + m_pageinput[1] = ((page % 256) / 16) + '0'; + m_pageinput[2] = (page % 16) + '0'; + + m_curpage = page; + m_cursubpage = subpage; + PageUpdated(m_curpage, m_cursubpage); +} + +void TeletextReader::Reset(void) +{ + for (uint mag = 0; mag < 8; mag++) + { + QMutexLocker lock(&m_magazines[mag].lock); + + // clear all sub pages in page + int_to_page_t::iterator iter; + iter = m_magazines[mag].pages.begin(); + while (iter != m_magazines[mag].pages.end()) + { + TeletextPage *page = &iter->second; + page->subpages.clear(); + ++iter; + } + + // clear pages + m_magazines[mag].pages.clear(); + m_magazines[mag].current_page = 0; + m_magazines[mag].current_subpage = 0; + m_magazines[mag].loadingpage.active = false; + } + memset(m_header, ' ', 40); + + m_curpage = 0x100; + m_cursubpage = -1; + m_curpage_showheader = true; + + m_pageinput[0] = '1'; + m_pageinput[1] = '0'; + m_pageinput[2] = '0'; +} + +void TeletextReader::AddPageHeader(int page, int subpage, const uint8_t *buf, + int vbimode, int lang, int flags) +{ + int magazine = MAGAZINE(page); + if (magazine < 1 || magazine > 8) + return; + int lastPage = m_magazines[magazine - 1].current_page; + int lastSubPage = m_magazines[magazine - 1].current_subpage; + + // update the last fetched page if the magazine is the same + // and the page no. is different + + if ((page != lastPage || subpage != lastSubPage) && + m_magazines[magazine - 1].loadingpage.active) + { + TeletextSubPage *ttpage = FindSubPage(lastPage, lastSubPage); + if (!ttpage) + { + ttpage = &(m_magazines[magazine - 1] + .pages[lastPage].subpages[lastSubPage]); + m_magazines[magazine - 1].pages[lastPage].pagenum = lastPage; + ttpage->subpagenum = lastSubPage; + } + + memcpy(ttpage, &m_magazines[magazine - 1].loadingpage, + sizeof(TeletextSubPage)); + + m_magazines[magazine - 1].loadingpage.active = false; + + PageUpdated(lastPage, lastSubPage); + } + + m_fetchpage = page; + m_fetchsubpage = subpage; + + TeletextSubPage *ttpage = &m_magazines[magazine - 1].loadingpage; + + m_magazines[magazine - 1].current_page = page; + m_magazines[magazine - 1].current_subpage = subpage; + + memset(ttpage->data, ' ', sizeof(ttpage->data)); + + ttpage->active = true; + ttpage->subpagenum = subpage; + + for (uint i = 0; i < 6; i++) + ttpage->floflink[i] = 0; + + ttpage->lang = lang; + ttpage->flags = flags; + ttpage->flof = 0; + + ttpage->subtitle = (vbimode == VBI_DVB_SUBTITLE); + + memset(ttpage->data[0], ' ', 8 * sizeof(uint8_t)); + + if (vbimode == VBI_DVB || vbimode == VBI_DVB_SUBTITLE) + { + for (uint j = 8; j < 40; j++) + ttpage->data[0][j] = m_bitswap[buf[j]]; + } + else + { + memcpy(ttpage->data[0]+0, buf, 40); + } + + if ( !(ttpage->flags & TP_INTERRUPTED_SEQ)) + { + memcpy(m_header, ttpage->data[0], 40); + HeaderUpdated(ttpage->data[0],ttpage->lang); + } +} + +void TeletextReader::AddTeletextData(int magazine, int row, + const uint8_t* buf, int vbimode) +{ + int b1, b2, b3, err = 0; + + if (magazine < 1 || magazine > 8) + return; + + int currentpage = m_magazines[magazine - 1].current_page; + if (!currentpage) + return; + + TeletextSubPage *ttpage = &m_magazines[magazine - 1].loadingpage; + + switch (row) + { + case 1 ... 24: // Page Data + if (vbimode == VBI_DVB || vbimode == VBI_DVB_SUBTITLE) + { + for (uint j = 0; j < 40; j++) + ttpage->data[row][j] = m_bitswap[buf[j]]; + } + else + { + memcpy(ttpage->data[row], buf, 40); + } + break; + case 26: + /* XXX TODO: Level 1.5, 2.5, 3.5 + * Character location & override + * Level 2.5, 3.5 + * Modifying display attributes + * All levels + * VCR Programming + * See 12.3 + */ + break; + case 27: // FLOF data (FastText) + switch (vbimode) + { + case VBI_IVTV: + b1 = hamm8(buf, &err); + b2 = hamm8(buf + 37, &err); + if (err & 0xF000) + return; + break; + case VBI_DVB: + case VBI_DVB_SUBTITLE: + b1 = hamm84(buf, &err); + b2 = hamm84(buf + 37, &err); + if (err == 1) + return; + break; + default: + return; + } + if (b1 != 0 || not(b2 & 8)) + return; + + for (int i = 0; i < 6; ++i) + { + err = 0; + switch (vbimode) + { + case VBI_IVTV: + b1 = hamm16(buf+1+6*i, &err); + b2 = hamm16(buf+3+6*i, &err); + b3 = hamm16(buf+5+6*i, &err); + if (err & 0xF000) + return; + break; + case VBI_DVB: + case VBI_DVB_SUBTITLE: + b1 = hamm84(buf+2+6*i, &err) * 16 + + hamm84(buf+1+6*i, &err); + b2 = hamm84(buf+4+6*i, &err) * 16 + + hamm84(buf+3+6*i, &err); + b3 = hamm84(buf+6+6*i, &err) * 16 + + hamm84(buf+5+6*i, &err); + if (err == 1) + return; + break; + default: + return; + } + + int x = (b2 >> 7) | ((b3 >> 5) & 0x06); + ttpage->floflink[i] = ((magazine ^ x) ?: 8) * 256 + b1; + ttpage->flof = 1; + } + break; + + case 31: // private streams + break; + + default: /// other packet codes... + break; + } +} + +void TeletextReader::PageUpdated(int page, int subpage) +{ + if (page != m_curpage) + return; + if (subpage != m_cursubpage && m_cursubpage != -1) + return; + m_page_changed = true; +} + +void TeletextReader::HeaderUpdated(uint8_t * page, int lang) +{ + (void)lang; + + if (page == NULL) + return; + + if (m_curpage_showheader == false) + return; + + m_header_changed = true; +} + +const TeletextPage *TeletextReader::FindPageInternal( + int page, int direction) const +{ + int mag = MAGAZINE(page); + + if (mag > 8 || mag < 1) + return NULL; + + QMutexLocker lock(&m_magazines[mag - 1].lock); + + int_to_page_t::const_iterator pageIter; + pageIter = m_magazines[mag - 1].pages.find(page); + if (pageIter == m_magazines[mag - 1].pages.end()) + return NULL; + + const TeletextPage *res = &pageIter->second; + if (direction == -1) + { + --pageIter; + if (pageIter == m_magazines[mag - 1].pages.end()) + { + int_to_page_t::const_reverse_iterator iter; + iter = m_magazines[mag - 1].pages.rbegin(); + res = &iter->second; + } + else + res = &pageIter->second; + } + + if (direction == 1) + { + ++pageIter; + if (pageIter == m_magazines[mag - 1].pages.end()) + { + pageIter = m_magazines[mag - 1].pages.begin(); + res = &pageIter->second; + } + else + res = &pageIter->second; + } + + return res; +} + +const TeletextSubPage *TeletextReader::FindSubPageInternal( + int page, int subpage, int direction) const +{ + int mag = MAGAZINE(page); + + if (mag > 8 || mag < 1) + return NULL; + + QMutexLocker lock(&m_magazines[mag - 1].lock); + + int_to_page_t::const_iterator pageIter; + pageIter = m_magazines[mag - 1].pages.find(page); + if (pageIter == m_magazines[mag - 1].pages.end()) + return NULL; + + const TeletextPage *ttpage = &(pageIter->second); + int_to_subpage_t::const_iterator subpageIter = + ttpage->subpages.begin(); + + // try to find the subpage given, or first if subpage == -1 + if (subpage != -1) + subpageIter = ttpage->subpages.find(subpage); + + if (subpageIter == ttpage->subpages.end()) + return NULL; + + if (subpage == -1) + return &(subpageIter->second); + + const TeletextSubPage *res = &(subpageIter->second); + if (direction == -1) + { + --subpageIter; + if (subpageIter == ttpage->subpages.end()) + { + int_to_subpage_t::const_reverse_iterator iter = + ttpage->subpages.rbegin(); + res = &(iter->second); + } + else + { + res = &(subpageIter->second); + } + } + + if (direction == 1) + { + ++subpageIter; + if (subpageIter == ttpage->subpages.end()) + subpageIter = ttpage->subpages.begin(); + + res = &(subpageIter->second); + } + + return res; +} diff --git a/mythtv/libs/libmythtv/teletextreader.h b/mythtv/libs/libmythtv/teletextreader.h new file mode 100644 index 00000000000..088abb0517b --- /dev/null +++ b/mythtv/libs/libmythtv/teletextreader.h @@ -0,0 +1,162 @@ +#ifndef TELETEXTREADER_H +#define TELETEXTREADER_H + +#include +#include + +#include +#include + +using namespace std; + +typedef enum +{ + kTTColorBlack = 0, + kTTColorRed = 1, + kTTColorGreen = 2, + kTTColorYellow = 3, + kTTColorBlue = 4, + kTTColorMagenta = 5, + kTTColorCyan = 6, + kTTColorWhite = 7, + kTTColorTransparent = 8, +} TTColor; + +class TTKey +{ + public: + static const uint k0 = 0; + static const uint k1 = 1; + static const uint k2 = 2; + static const uint k3 = 3; + static const uint k4 = 4; + static const uint k5 = 5; + static const uint k6 = 6; + static const uint k7 = 7; + static const uint k8 = 8; + static const uint k9 = 9; + static const uint kNextPage = 10; + static const uint kPrevPage = 11; + static const uint kNextSubPage = 12; + static const uint kPrevSubPage = 13; + static const uint kHold = 14; + static const uint kTransparent = 15; + static const uint kFlofRed = 16; + static const uint kFlofGreen = 17; + static const uint kFlofYellow = 18; + static const uint kFlofBlue = 19; + static const uint kFlofWhite = 20; + static const uint kRevealHidden = 21; +}; + +#define TP_SUPPRESS_HEADER 0x01 +#define TP_UPDATE_INDICATOR 0x02 +#define TP_INTERRUPTED_SEQ 0x04 +#define TP_INHIBIT_DISPLAY 0x08 +#define TP_MAGAZINE_SERIAL 0x10 +#define TP_ERASE_PAGE 0x20 +#define TP_NEWSFLASH 0x40 +#define TP_SUBTITLE 0x80 + +class TeletextSubPage +{ + public: + int pagenum; ///< the wanted page + int subpagenum; ///< the wanted subpage + int lang; ///< language code + int flags; ///< misc flags + uint8_t data[25][40]; ///< page data + int flof; ///< page has FastText links + int floflink[6]; ///< FastText links (FLOF) + bool subtitle; ///< page is subtitle page + bool active; ///< data has arrived since page last cleared +}; + +typedef map int_to_subpage_t; + +class TeletextPage +{ + public: + int pagenum; + int current_subpage; + int_to_subpage_t subpages; +}; +typedef map int_to_page_t; + +class TeletextMagazine +{ + public: + mutable QMutex lock; + int current_page; + int current_subpage; + TeletextSubPage loadingpage; + int_to_page_t pages; +}; + +class TeletextReader +{ + public: + TeletextReader(); + ~TeletextReader(); + + // OSD/Player methods + void Reset(void); + void KeyPress(uint key); + QString GetPage(void); + void SetPage(int page, int subpage); + void SetSubPage(int subpage) { m_cursubpage = subpage; } + bool PageChanged(void) { return m_page_changed; } + void SetPageChanged(bool changed) { m_page_changed = changed; } + void SetShowHeader(bool show) { m_curpage_showheader = show; } + void SetHeaderChanged(bool changed) { m_header_changed = changed; } + bool IsSubtitle(void) { return m_curpage_issubtitle; } + void SetIsSubtitle(bool sub) { m_curpage_issubtitle = sub; } + bool IsTransparent(void) { return m_transparent; } + bool RevealHidden(void) { return m_revealHidden; } + int GetPageInput(uint num) { return m_pageinput[num]; } + TeletextSubPage* FindSubPage(void) + { return FindSubPage(m_curpage, m_cursubpage); } + uint8_t* GetHeader(void) { return m_header; } + + // Decoder methods + void AddPageHeader(int page, int subpage, const uint8_t *buf, + int vbimode, int lang, int flags); + void AddTeletextData(int magazine, int row, + const uint8_t* buf, int vbimode); + + + private: + void NewsFlash(void) {}; + void PageUpdated(int page, int subpage); + void HeaderUpdated(uint8_t *page, int lang); + + const TeletextSubPage *FindSubPage(int page, int subpage, int dir=0) const + { return FindSubPageInternal(page, subpage, dir); } + TeletextSubPage *FindSubPage(int page, int subpage, int dir = 0) + { return (TeletextSubPage*) FindSubPageInternal(page, subpage, dir); } + + const TeletextPage *FindPage(int page, int dir = 0) const + { return (TeletextPage*) FindPageInternal(page, dir); } + TeletextPage *FindPage(int page, int dir = 0) + { return (TeletextPage*) FindPageInternal(page, dir); } + + const TeletextSubPage *FindSubPageInternal(int,int,int) const; + const TeletextPage *FindPageInternal(int,int) const; + + mutable int m_curpage; + mutable int m_cursubpage; + mutable bool m_curpage_showheader; + mutable bool m_curpage_issubtitle; + int m_pageinput[3]; + bool m_transparent; + bool m_revealHidden; + uint8_t m_header[40]; + mutable bool m_header_changed; + mutable bool m_page_changed; + TeletextMagazine m_magazines[8]; + unsigned char m_bitswap[256]; + int m_fetchpage; + int m_fetchsubpage; +}; + +#endif // TELETEXTREADER_H diff --git a/mythtv/libs/libmythtv/teletextscreen.cpp b/mythtv/libs/libmythtv/teletextscreen.cpp index 4be77e429ee..f1830d2b7c2 100644 --- a/mythtv/libs/libmythtv/teletextscreen.cpp +++ b/mythtv/libs/libmythtv/teletextscreen.cpp @@ -11,8 +11,7 @@ #include "mythpainter.h" #include "teletextscreen.h" -#define LOC QString("Teletext: ") -#define MAGAZINE(page) (page / 256) +#define LOC QString("TeletextScreen: ") const QColor TeletextScreen::kColorBlack = QColor( 0, 0, 0,255); const QColor TeletextScreen::kColorRed = QColor(255, 0, 0,255); @@ -42,28 +41,13 @@ static char cvt_char(char ch, int lang) TeletextScreen::TeletextScreen(MythPlayer *player, const char * name, int fontStretch) : MythScreenType((MythScreenType*)NULL, name), - m_player(player), m_safeArea(QRect()), + m_player(player), m_teletextReader(NULL), + m_safeArea(QRect()), m_colWidth(10), m_rowHeight(10), - m_fetchpage(0), m_fetchsubpage(0), m_bgColor(QColor(kColorBlack)), - m_curpage(0x100), m_cursubpage(-1), - m_curpage_showheader(true), m_curpage_issubtitle(false), - m_transparent(false), m_revealHidden(false), - m_displaying(false), m_header_changed(false), - m_page_changed(false), m_fontStretch(fontStretch), + m_displaying(false), m_fontStretch(fontStretch), m_fontHeight(10) { - memset(m_pageinput, 0, sizeof(m_pageinput)); - memset(m_header, 0, sizeof(m_header)); - for (int i = 0; i < 256; i++) - { - m_bitswap[i] = 0; - for (int bit = 0; bit < 8; bit++) - if (i & (1 << bit)) - m_bitswap[i] |= (1 << (7-bit)); - } - - Reset(); } TeletextScreen::~TeletextScreen() @@ -73,7 +57,9 @@ TeletextScreen::~TeletextScreen() bool TeletextScreen::Create(void) { - return m_player; + if (m_player) + m_teletextReader = m_player->GetTeletextReader(); + return m_player && m_teletextReader; } void TeletextScreen::CleanUp(void) @@ -173,7 +159,7 @@ void TeletextScreen::Pulse(void) if (oldsafe != m_safeArea) { - m_page_changed = true; + m_teletextReader->SetPageChanged(true); int max_width = (int)((float)m_colWidth * kTextPadding); m_fontHeight = (int)((float)m_rowHeight * kTextPadding); @@ -201,25 +187,23 @@ void TeletextScreen::Pulse(void) return; } - if (!m_page_changed) + if (!m_teletextReader->PageChanged()) return; - QMutexLocker locker(&m_lock); - CleanUp(); - const TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage); + const TeletextSubPage *ttpage = m_teletextReader->FindSubPage(); if (!ttpage) { // no page selected so show the header and a list of available pages DrawHeader(NULL, 0); - m_page_changed = false; + m_teletextReader->SetPageChanged(false); OptimiseDisplayedArea(); return; } - m_cursubpage = ttpage->subpagenum; + m_teletextReader->SetSubPage(ttpage->subpagenum); int a = 0; if ((ttpage->subtitle) || @@ -227,223 +211,34 @@ void TeletextScreen::Pulse(void) { a = 1; // when showing subtitles we don't want to see the teletext // header line, so we skip that line... - m_curpage_showheader = false; - m_curpage_issubtitle = true; + m_teletextReader->SetShowHeader(false); + m_teletextReader->SetIsSubtitle(true); } else { - m_curpage_issubtitle = false; - m_curpage_showheader = true; - DrawHeader(m_header, ttpage->lang); - - m_header_changed = false; + m_teletextReader->SetShowHeader(true); + m_teletextReader->SetIsSubtitle(false); + DrawHeader(m_teletextReader->GetHeader(), ttpage->lang); + m_teletextReader->SetHeaderChanged(false); } for (int y = kTeletextRows - a; y >= 2; y--) DrawLine(ttpage->data[y-1], y, ttpage->lang); - m_page_changed = false; + m_teletextReader->SetPageChanged(false); OptimiseDisplayedArea(); } void TeletextScreen::KeyPress(uint key) { - if (!m_displaying) - return; - - QMutexLocker locker(&m_lock); - - int newPage = m_curpage; - int newSubPage = m_cursubpage; - bool numeric_input = false; - - TeletextSubPage *curpage = FindSubPage(m_curpage, m_cursubpage); - TeletextPage *page; - - switch (key) - { - case TTKey::k0 ... TTKey::k9: - numeric_input = true; - m_curpage_showheader = true; - if (m_pageinput[0] == ' ') - m_pageinput[0] = '0' + static_cast (key); - else if (m_pageinput[1] == ' ') - m_pageinput[1] = '0' + static_cast (key); - else if (m_pageinput[2] == ' ') - { - m_pageinput[2] = '0' + static_cast (key); - newPage = ((m_pageinput[0] - '0') * 256) + - ((m_pageinput[1] - '0') * 16) + - (m_pageinput[2] - '0'); - newSubPage = -1; - } - else - { - m_pageinput[0] = '0' + static_cast (key); - m_pageinput[1] = ' '; - m_pageinput[2] = ' '; - } - - PageUpdated(m_curpage, m_cursubpage); - break; - - case TTKey::kNextPage: - { - TeletextPage *ttpage = FindPage(m_curpage, 1); - if (ttpage) - newPage = ttpage->pagenum; - newSubPage = -1; - m_curpage_showheader = true; - break; - } - - case TTKey::kPrevPage: - { - TeletextPage *ttpage = FindPage(m_curpage, -1); - if (ttpage) - newPage = ttpage->pagenum; - newSubPage = -1; - m_curpage_showheader = true; - break; - } - - case TTKey::kNextSubPage: - { - TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage, 1); - if (ttpage) - newSubPage = ttpage->subpagenum; - m_curpage_showheader = true; - break; - } - - case TTKey::kPrevSubPage: - { - TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage, -1); - if (ttpage) - newSubPage = ttpage->subpagenum; - m_curpage_showheader = true; - break; - } - - case TTKey::kHold: - break; - - case TTKey::kTransparent: - m_transparent = !m_transparent; - PageUpdated(m_curpage, m_cursubpage); - break; - - case TTKey::kRevealHidden: - m_revealHidden = !m_revealHidden; - PageUpdated(m_curpage, m_cursubpage); - break; - - case TTKey::kFlofRed: - { - if (!curpage) - return; - - if ((page = FindPage(curpage->floflink[0])) != NULL) - { - newPage = page->pagenum; - newSubPage = -1; - m_curpage_showheader = true; - } - break; - } - - case TTKey::kFlofGreen: - { - if (!curpage) - return; - - if ((page = FindPage(curpage->floflink[1])) != NULL) - { - newPage = page->pagenum; - newSubPage = -1; - m_curpage_showheader = true; - } - break; - } - - case TTKey::kFlofYellow: - { - if (!curpage) - return; - - if ((page = FindPage(curpage->floflink[2])) != NULL) - { - newPage = page->pagenum; - newSubPage = -1; - m_curpage_showheader = true; - } - break; - } - - case TTKey::kFlofBlue: - { - if (!curpage) - return; - - if ((page = FindPage(curpage->floflink[3])) != NULL) - { - newPage = page->pagenum; - newSubPage = -1; - m_curpage_showheader = true; - } - break; - } - - case TTKey::kFlofWhite: - { - if (!curpage) - return; - - if ((page = FindPage(curpage->floflink[4])) != NULL) - { - newPage = page->pagenum; - newSubPage = -1; - m_curpage_showheader = true; - } - break; - } - } - - if (newPage < 0x100) - newPage = 0x100; - if (newPage > 0x899) - newPage = 0x899; - - if (!numeric_input) - { - m_pageinput[0] = (newPage / 256) + '0'; - m_pageinput[1] = ((newPage % 256) / 16) + '0'; - m_pageinput[2] = (newPage % 16) + '0'; - } - - if (newPage != m_curpage || newSubPage != m_cursubpage) - { - m_curpage = newPage; - m_cursubpage = newSubPage; - m_revealHidden = false; - PageUpdated(m_curpage, m_cursubpage); - } + if (m_teletextReader) + m_teletextReader->KeyPress(key); } void TeletextScreen::SetPage(int page, int subpage) { - QMutexLocker locker(&m_lock); - - if (page < 0x100 || page > 0x899) - return; - - m_pageinput[0] = (page / 256) + '0'; - m_pageinput[1] = ((page % 256) / 16) + '0'; - m_pageinput[2] = (page % 16) + '0'; - - m_curpage = page; - m_cursubpage = subpage; - PageUpdated(m_curpage, m_cursubpage); + if (m_teletextReader) + m_teletextReader->SetPage(page, subpage); } void TeletextScreen::SetDisplaying(bool display) @@ -455,224 +250,8 @@ void TeletextScreen::SetDisplaying(bool display) void TeletextScreen::Reset(void) { - QMutexLocker locker(&m_lock); - - for (uint mag = 0; mag < 8; mag++) - { - QMutexLocker lock(&m_magazines[mag].lock); - - // clear all sub pages in page - int_to_page_t::iterator iter; - iter = m_magazines[mag].pages.begin(); - while (iter != m_magazines[mag].pages.end()) - { - TeletextPage *page = &iter->second; - page->subpages.clear(); - ++iter; - } - - // clear pages - m_magazines[mag].pages.clear(); - m_magazines[mag].current_page = 0; - m_magazines[mag].current_subpage = 0; - m_magazines[mag].loadingpage.active = false; - } - memset(m_header, ' ', 40); - - m_curpage = 0x100; - m_cursubpage = -1; - m_curpage_showheader = true; - - m_pageinput[0] = '1'; - m_pageinput[1] = '0'; - m_pageinput[2] = '0'; -} - -void TeletextScreen::AddPageHeader(int page, int subpage, - const uint8_t * buf, - int vbimode, int lang, int flags) -{ - if (!m_displaying) - return; - - QMutexLocker locker(&m_lock); - - int magazine = MAGAZINE(page); - if (magazine < 1 || magazine > 8) - return; - int lastPage = m_magazines[magazine - 1].current_page; - int lastSubPage = m_magazines[magazine - 1].current_subpage; - - // update the last fetched page if the magazine is the same - // and the page no. is different - - if ((page != lastPage || subpage != lastSubPage) && - m_magazines[magazine - 1].loadingpage.active) - { - TeletextSubPage *ttpage = FindSubPage(lastPage, lastSubPage); - if (!ttpage) - { - ttpage = &(m_magazines[magazine - 1] - .pages[lastPage].subpages[lastSubPage]); - m_magazines[magazine - 1].pages[lastPage].pagenum = lastPage; - ttpage->subpagenum = lastSubPage; - } - - memcpy(ttpage, &m_magazines[magazine - 1].loadingpage, - sizeof(TeletextSubPage)); - - m_magazines[magazine - 1].loadingpage.active = false; - - PageUpdated(lastPage, lastSubPage); - } - - m_fetchpage = page; - m_fetchsubpage = subpage; - - TeletextSubPage *ttpage = &m_magazines[magazine - 1].loadingpage; - - m_magazines[magazine - 1].current_page = page; - m_magazines[magazine - 1].current_subpage = subpage; - - memset(ttpage->data, ' ', sizeof(ttpage->data)); - - ttpage->active = true; - ttpage->subpagenum = subpage; - - for (uint i = 0; i < 6; i++) - ttpage->floflink[i] = 0; - - ttpage->lang = lang; - ttpage->flags = flags; - ttpage->flof = 0; - - ttpage->subtitle = (vbimode == VBI_DVB_SUBTITLE); - - memset(ttpage->data[0], ' ', 8 * sizeof(uint8_t)); - - if (vbimode == VBI_DVB || vbimode == VBI_DVB_SUBTITLE) - { - for (uint j = 8; j < 40; j++) - ttpage->data[0][j] = m_bitswap[buf[j]]; - } - else - { - memcpy(ttpage->data[0]+0, buf, 40); - } - - if ( !(ttpage->flags & TP_INTERRUPTED_SEQ)) - { - memcpy(m_header, ttpage->data[0], 40); - HeaderUpdated(ttpage->data[0],ttpage->lang); - } -} - -/** - * \brief Adds Teletext Data from TeletextDecoder - */ -void TeletextScreen::AddTeletextData(int magazine, int row, - const uint8_t * buf, int vbimode) -{ - if (!m_displaying) - return; - - QMutexLocker locker(&m_lock); - - int b1, b2, b3, err = 0; - - if (magazine < 1 || magazine > 8) - return; - - int currentpage = m_magazines[magazine - 1].current_page; - if (!currentpage) - return; - - TeletextSubPage *ttpage = &m_magazines[magazine - 1].loadingpage; - - switch (row) - { - case 1 ... 24: // Page Data - if (vbimode == VBI_DVB || vbimode == VBI_DVB_SUBTITLE) - { - for (uint j = 0; j < 40; j++) - ttpage->data[row][j] = m_bitswap[buf[j]]; - } - else - { - memcpy(ttpage->data[row], buf, 40); - } - break; - case 26: - /* XXX TODO: Level 1.5, 2.5, 3.5 - * Character location & override - * Level 2.5, 3.5 - * Modifying display attributes - * All levels - * VCR Programming - * See 12.3 - */ - break; - case 27: // FLOF data (FastText) - switch (vbimode) - { - case VBI_IVTV: - b1 = hamm8(buf, &err); - b2 = hamm8(buf + 37, &err); - if (err & 0xF000) - return; - break; - case VBI_DVB: - case VBI_DVB_SUBTITLE: - b1 = hamm84(buf, &err); - b2 = hamm84(buf + 37, &err); - if (err == 1) - return; - break; - default: - return; - } - if (b1 != 0 || not(b2 & 8)) - return; - - for (int i = 0; i < 6; ++i) - { - err = 0; - switch (vbimode) - { - case VBI_IVTV: - b1 = hamm16(buf+1+6*i, &err); - b2 = hamm16(buf+3+6*i, &err); - b3 = hamm16(buf+5+6*i, &err); - if (err & 0xF000) - return; - break; - case VBI_DVB: - case VBI_DVB_SUBTITLE: - b1 = hamm84(buf+2+6*i, &err) * 16 + - hamm84(buf+1+6*i, &err); - b2 = hamm84(buf+4+6*i, &err) * 16 + - hamm84(buf+3+6*i, &err); - b3 = hamm84(buf+6+6*i, &err) * 16 + - hamm84(buf+5+6*i, &err); - if (err == 1) - return; - break; - default: - return; - } - - int x = (b2 >> 7) | ((b3 >> 5) & 0x06); - ttpage->floflink[i] = ((magazine ^ x) ?: 8) * 256 + b1; - ttpage->flof = 1; - } - break; - - case 31: // private streams - break; - - default: /// other packet codes... - break; - } + if (m_teletextReader) + m_teletextReader->Reset(); } void TeletextScreen::DrawHeader(const uint8_t *page, int lang) @@ -758,7 +337,7 @@ void TeletextScreen::DrawLine(const uint8_t *page, uint row, int lang) uint newfgcolor = kTTColorWhite; uint newbgcolor = kTTColorBlack; - if (m_curpage_issubtitle || m_transparent) + if (m_teletextReader->IsSubtitle() || m_teletextReader->IsTransparent()) { bgcolor = kTTColorTransparent; newbgcolor = kTTColorTransparent; @@ -888,7 +467,7 @@ void TeletextScreen::DrawLine(const uint8_t *page, uint row, int lang) ch = ' '; // BAD_CHAR; break; default: - if (conceal && !m_revealHidden) + if (conceal && !m_teletextReader->RevealHidden()) ch = ' '; break; } @@ -896,8 +475,7 @@ void TeletextScreen::DrawLine(const uint8_t *page, uint row, int lang) // Hide FastText/FLOF menu characters if not available if (flof_link_count && (flof_link_count <= 6)) { - const TeletextSubPage *ttpage = - FindSubPage(m_curpage, m_cursubpage); + const TeletextSubPage *ttpage = m_teletextReader->FindSubPage(); if (ttpage) { @@ -913,7 +491,7 @@ void TeletextScreen::DrawLine(const uint8_t *page, uint row, int lang) SetBackgroundColor(newbgcolor); if ((row != 0) || (x > 7)) { - if (m_transparent) + if (m_teletextReader->IsTransparent()) SetBackgroundColor(kTTColorTransparent); DrawBackground(x, row); @@ -1036,26 +614,19 @@ void TeletextScreen::DrawStatus(void) SetForegroundColor(kTTColorWhite); SetBackgroundColor(kTTColorBlack); - if (!m_transparent) + if (!m_teletextReader->IsTransparent()) for (int i = 0; i < 40; ++i) DrawBackground(i, 0); DrawCharacter(1, 0, 'P', 0); - DrawCharacter(2, 0, m_pageinput[0], 0); - DrawCharacter(3, 0, m_pageinput[1], 0); - DrawCharacter(4, 0, m_pageinput[2], 0); + DrawCharacter(2, 0, m_teletextReader->GetPageInput(0), 0); + DrawCharacter(3, 0, m_teletextReader->GetPageInput(1), 0); + DrawCharacter(4, 0, m_teletextReader->GetPageInput(2), 0); - const TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage); + const TeletextSubPage *ttpage = m_teletextReader->FindSubPage(); if (!ttpage) { - SetBackgroundColor(kTTColorBlack); - SetForegroundColor(kTTColorWhite); - - if (!m_transparent) - for (int i = 7; i < 40; i++) - DrawBackground(i, 0); - QString str = QObject::tr("Page Not Available", "Requested Teletext page not available"); for (int i = 0; (i < 30) && i < str.length(); i++) @@ -1064,59 +635,14 @@ void TeletextScreen::DrawStatus(void) return; } - // get list of available sub pages - QString str = ""; - int count = 1, selected = 0; - const TeletextPage *page = FindPage(m_curpage); - if (page) - { - int_to_subpage_t::const_iterator subpageIter; - subpageIter = page->subpages.begin(); - while (subpageIter != page->subpages.end()) - { - const TeletextSubPage *subpage = &subpageIter->second; - - if (subpage->subpagenum == m_cursubpage) - { - selected = count; - str += "*"; - } - else - str += " "; - - str += QString().sprintf("%02X", subpage->subpagenum); - - ++subpageIter; - ++count; - } - } - + QString str = m_teletextReader->GetPage(); if (str.isEmpty()) return; - // if there are less than 9 subpages fill the empty slots with spaces - if (count < 10) - { - QString spaces; - spaces.fill(' ', 27 - str.length()); - str = " <" + str + spaces + " > "; - } - else - { - // try to centralize the selected sub page in the list - int startPos = selected - 5; - if (startPos < 0) - startPos = 0; - if (startPos + 9 >= count) - startPos = count - 10; - - str = " <" + str.mid(startPos * 3, 27) + " > "; - } - SetForegroundColor(kTTColorWhite); for (int x = 0; x < 11; x++) { - if (m_transparent) + if (m_teletextReader->IsTransparent()) SetBackgroundColor(kTTColorTransparent); else SetBackgroundColor(kTTColorBlack); @@ -1138,134 +664,6 @@ void TeletextScreen::DrawStatus(void) } } -void TeletextScreen::PageUpdated(int page, int subpage) -{ - if (!m_displaying) - return; - if (page != m_curpage) - return; - if (subpage != m_cursubpage && m_cursubpage != -1) - return; - m_page_changed = true; -} - -void TeletextScreen::HeaderUpdated(uint8_t * page, int lang) -{ - (void)lang; - - if (!m_displaying) - return; - - if (page == NULL) - return; - - if (m_curpage_showheader == false) - return; - - m_header_changed = true; -} - -const TeletextPage *TeletextScreen::FindPageInternal( - int page, int direction) const -{ - int mag = MAGAZINE(page); - - if (mag > 8 || mag < 1) - return NULL; - - QMutexLocker lock(&m_magazines[mag - 1].lock); - - int_to_page_t::const_iterator pageIter; - pageIter = m_magazines[mag - 1].pages.find(page); - if (pageIter == m_magazines[mag - 1].pages.end()) - return NULL; - - const TeletextPage *res = &pageIter->second; - if (direction == -1) - { - --pageIter; - if (pageIter == m_magazines[mag - 1].pages.end()) - { - int_to_page_t::const_reverse_iterator iter; - iter = m_magazines[mag - 1].pages.rbegin(); - res = &iter->second; - } - else - res = &pageIter->second; - } - - if (direction == 1) - { - ++pageIter; - if (pageIter == m_magazines[mag - 1].pages.end()) - { - pageIter = m_magazines[mag - 1].pages.begin(); - res = &pageIter->second; - } - else - res = &pageIter->second; - } - - return res; -} - -const TeletextSubPage *TeletextScreen::FindSubPageInternal( - int page, int subpage, int direction) const -{ - int mag = MAGAZINE(page); - - if (mag > 8 || mag < 1) - return NULL; - - QMutexLocker lock(&m_magazines[mag - 1].lock); - - int_to_page_t::const_iterator pageIter; - pageIter = m_magazines[mag - 1].pages.find(page); - if (pageIter == m_magazines[mag - 1].pages.end()) - return NULL; - - const TeletextPage *ttpage = &(pageIter->second); - int_to_subpage_t::const_iterator subpageIter = - ttpage->subpages.begin(); - - // try to find the subpage given, or first if subpage == -1 - if (subpage != -1) - subpageIter = ttpage->subpages.find(subpage); - - if (subpageIter == ttpage->subpages.end()) - return NULL; - - if (subpage == -1) - return &(subpageIter->second); - - const TeletextSubPage *res = &(subpageIter->second); - if (direction == -1) - { - --subpageIter; - if (subpageIter == ttpage->subpages.end()) - { - int_to_subpage_t::const_reverse_iterator iter = - ttpage->subpages.rbegin(); - res = &(iter->second); - } - else - { - res = &(subpageIter->second); - } - } - - if (direction == 1) - { - ++subpageIter; - if (subpageIter == ttpage->subpages.end()) - subpageIter = ttpage->subpages.begin(); - - res = &(subpageIter->second); - } - - return res; -} - bool TeletextScreen::InitialiseFont() { static bool initialised = false; diff --git a/mythtv/libs/libmythtv/teletextscreen.h b/mythtv/libs/libmythtv/teletextscreen.h index a876609de95..c20113c23aa 100644 --- a/mythtv/libs/libmythtv/teletextscreen.h +++ b/mythtv/libs/libmythtv/teletextscreen.h @@ -4,93 +4,10 @@ #include #include "mythscreentype.h" -#include "teletextdecoder.h" +#include "teletextreader.h" #include "mythplayer.h" -typedef enum -{ - kTTColorBlack = 0, - kTTColorRed = 1, - kTTColorGreen = 2, - kTTColorYellow = 3, - kTTColorBlue = 4, - kTTColorMagenta = 5, - kTTColorCyan = 6, - kTTColorWhite = 7, - kTTColorTransparent = 8, -} TTColor; - -class TTKey -{ - public: - static const uint k0 = 0; - static const uint k1 = 1; - static const uint k2 = 2; - static const uint k3 = 3; - static const uint k4 = 4; - static const uint k5 = 5; - static const uint k6 = 6; - static const uint k7 = 7; - static const uint k8 = 8; - static const uint k9 = 9; - static const uint kNextPage = 10; - static const uint kPrevPage = 11; - static const uint kNextSubPage = 12; - static const uint kPrevSubPage = 13; - static const uint kHold = 14; - static const uint kTransparent = 15; - static const uint kFlofRed = 16; - static const uint kFlofGreen = 17; - static const uint kFlofYellow = 18; - static const uint kFlofBlue = 19; - static const uint kFlofWhite = 20; - static const uint kRevealHidden = 21; -}; - -#define TP_SUPPRESS_HEADER 0x01 -#define TP_UPDATE_INDICATOR 0x02 -#define TP_INTERRUPTED_SEQ 0x04 -#define TP_INHIBIT_DISPLAY 0x08 -#define TP_MAGAZINE_SERIAL 0x10 -#define TP_ERASE_PAGE 0x20 -#define TP_NEWSFLASH 0x40 -#define TP_SUBTITLE 0x80 - -class TeletextSubPage -{ - public: - int pagenum; ///< the wanted page - int subpagenum; ///< the wanted subpage - int lang; ///< language code - int flags; ///< misc flags - uint8_t data[25][40]; ///< page data - int flof; ///< page has FastText links - int floflink[6]; ///< FastText links (FLOF) - bool subtitle; ///< page is subtitle page - bool active; ///< data has arrived since page last cleared -}; -typedef map int_to_subpage_t; - -class TeletextPage -{ - public: - int pagenum; - int current_subpage; - int_to_subpage_t subpages; -}; -typedef map int_to_page_t; - -class TeletextMagazine -{ - public: - mutable QMutex lock; - int current_page; - int current_subpage; - TeletextSubPage loadingpage; - int_to_page_t pages; -}; - -class TeletextScreen: public MythScreenType, public TeletextViewer +class TeletextScreen: public MythScreenType { static bool InitialiseFont(void); @@ -103,14 +20,10 @@ class TeletextScreen: public MythScreenType, public TeletextViewer virtual void Pulse(void); // TeletextViewer interface methods - virtual void KeyPress(uint key); - virtual void SetPage(int page, int subpage); - virtual void SetDisplaying(bool display); - virtual void Reset(void); - virtual void AddPageHeader(int page, int subpage, const uint8_t *buf, - int vbimode, int lang, int flags); - virtual void AddTeletextData(int magazine, int row, - const uint8_t* buf, int vbimode); + void KeyPress(uint key); + void SetPage(int page, int subpage); + void SetDisplaying(bool display); + void Reset(void); private: void CleanUp(); @@ -127,52 +40,16 @@ class TeletextScreen: public MythScreenType, public TeletextViewer void DrawStatus(void); void DrawPage(void); - void NewsFlash(void) {}; - void PageUpdated(int page, int subpage); - void HeaderUpdated(uint8_t *page, int lang); - - const TeletextSubPage *FindSubPage(int page, int subpage, int dir=0) const - { return FindSubPageInternal(page, subpage, dir); } - TeletextSubPage *FindSubPage(int page, int subpage, int dir = 0) - { return (TeletextSubPage*) FindSubPageInternal(page, subpage, dir); } - - const TeletextPage *FindPage(int page, int dir = 0) const - { return (TeletextPage*) FindPageInternal(page, dir); } - TeletextPage *FindPage(int page, int dir = 0) - { return (TeletextPage*) FindPageInternal(page, dir); } - - const TeletextSubPage *FindSubPageInternal(int,int,int) const; - const TeletextPage *FindPageInternal(int,int) const; - - MythPlayer *m_player; - QRect m_safeArea; - int m_colWidth; - int m_rowHeight; - - QMutex m_lock; - - int m_fetchpage; - int m_fetchsubpage; - QColor m_bgColor; - - // currently displayed page: - mutable int m_curpage; - mutable int m_cursubpage; - mutable bool m_curpage_showheader; - mutable bool m_curpage_issubtitle; - - int m_pageinput[3]; - bool m_transparent; - bool m_revealHidden; - bool m_displaying; - uint8_t m_header[40]; - mutable bool m_header_changed; - mutable bool m_page_changed; - TeletextMagazine m_magazines[8]; - unsigned char m_bitswap[256]; + MythPlayer *m_player; + TeletextReader *m_teletextReader; + QRect m_safeArea; + int m_colWidth; + int m_rowHeight; + QColor m_bgColor; + bool m_displaying; QHash m_rowImages; - int m_fontStretch; - int m_fontHeight; + int m_fontStretch; + int m_fontHeight; public: static const QColor kColorBlack;