Index: libs/libmythtv/NuppelVideoPlayer.cpp =================================================================== --- libs/libmythtv/NuppelVideoPlayer.cpp (revision 9715) +++ libs/libmythtv/NuppelVideoPlayer.cpp (working copy) @@ -41,6 +41,7 @@ #include "DVDRingBuffer.h" #include "NuppelVideoRecorder.h" #include "tv_play.h" +#include "interactivetv.h" extern "C" { #include "vbitext/vbi.h" @@ -176,6 +177,8 @@ // MHEG/MHI Interactive TV visible in OSD itvVisible(false), + interactiveTV(NULL), + itvEnabled(false), // OSD stuff osd(NULL), timedisplay(NULL), @@ -293,6 +296,9 @@ delete [] txtbuffers[i].buffer; } + if (interactiveTV) + delete interactiveTV; + SetDecoder(NULL); if (FiltMan) @@ -318,6 +324,13 @@ ShutdownYUVResize(); } + +InteractiveTV *NuppelVideoPlayer::GetInteractiveTV(void) +{ + if (!interactiveTV && osd && itvEnabled) + interactiveTV = new InteractiveTV(this); + return interactiveTV; +} void NuppelVideoPlayer::SetWatchingRecording(bool mode) { @@ -524,6 +537,8 @@ SetCaptionsEnabled(gContext->GetNumSetting("DefaultCCMode")); + itvEnabled = gContext->GetNumSetting("EnableMHEG"); + return true; } @@ -536,9 +551,9 @@ videoOutput->GetOSDBounds(total, visible, aspect, scaling); if (osd) osd->Reinit(total, frame_interval, visible, aspect, scaling); - if (decoder) + if (GetInteractiveTV()) { - decoder->ITVReset(total, visible); + GetInteractiveTV()->Reinit(total); itvVisible = false; } } @@ -2325,7 +2340,7 @@ DisplayDVDButton(); // handle Interactive TV - if ((textDisplayMode & kDisplayITV) && GetDecoder()) + if (GetInteractiveTV() && GetDecoder()) itvVisible = GetDecoder()->ITVUpdate(itvVisible); // handle EIA-608 and Teletext @@ -2885,6 +2900,9 @@ tt_view->SetDisplaying(false); } GetOSD()->HideSet("teletext"); + + if (GetInteractiveTV()) + GetInteractiveTV()->Reinit(total); } playing = true; @@ -5482,7 +5500,7 @@ bool NuppelVideoPlayer::ITVHandleAction(const QString &action) { - if (!(textDisplayMode & kDisplayITV)) + if (! GetInteractiveTV()) return false; if (GetDecoder()) @@ -5491,10 +5509,10 @@ return false; } -/* \fn NuppelVideoPlayer::ITVRestart(bool isLive) +/* \fn NuppelVideoPlayer::ITVRestart(uint chanid, int cardid, bool isLive) * \brief Restart the MHEG/MHP engine. */ -void NuppelVideoPlayer::ITVRestart(uint chanid, bool isLiveTV) +void NuppelVideoPlayer::ITVRestart(uint chanid, int cardid, bool isLiveTV) { OSD *osd = GetOSD(); if (!GetDecoder() || !osd) @@ -5507,7 +5525,7 @@ return; } - GetDecoder()->ITVRestart(chanid, isLiveTV); + GetDecoder()->ITVRestart(chanid, cardid, isLiveTV); osd->ClearAll("interactive"); itvosd->Display(); Index: libs/libmythtv/avformatdecoder.cpp =================================================================== --- libs/libmythtv/avformatdecoder.cpp (revision 9715) +++ libs/libmythtv/avformatdecoder.cpp (working copy) @@ -275,7 +275,7 @@ ccd708(new CC708Decoder(parent)), ttd(new TeletextDecoder()), // Interactive TV - itv(new InteractiveTV(parent)), + itv(NULL), selectedVideoIndex(-1), // Audio audioSamples(new short int[AVCODEC_MAX_AUDIO_FRAME_SIZE]), @@ -298,8 +298,8 @@ #ifdef CONFIG_DTS allow_dts_passthru = gContext->GetNumSetting("DTSPassThru", false); #endif - audioIn.sample_size = -32; // force SetupAudioStream to run once + itv = GetNVP()->GetInteractiveTV(); } AvFormatDecoder::~AvFormatDecoder() @@ -316,7 +316,6 @@ delete ccd608; delete ccd708; delete ttd; - delete itv; delete d; if (audioSamples) delete [] audioSamples; @@ -814,7 +813,8 @@ { int initialAudio = -1, initialVideo = -1; - itv->GetInitialStreams(initialAudio, initialVideo); + if (itv != NULL) + itv->GetInitialStreams(initialAudio, initialVideo); if (initialAudio >= 0) SetAudioByComponentTag(initialAudio); if (initialVideo >= 0) @@ -2107,12 +2107,6 @@ return ccd608->GetXDS(key); } -void AvFormatDecoder::ITVReset(const QRect &total, const QRect &visible) -{ - (void) visible; - itv->Reinit(total); -} - bool AvFormatDecoder::ITVUpdate(bool itvVisible) { QMutexLocker locker(&itvLock); @@ -2125,6 +2119,9 @@ if (!itvosd) return itvVisible; + if (itv == NULL) + return itvVisible; + bool visible = false; if (itv->ImageHasChanged() || !itvVisible) { @@ -2142,17 +2139,21 @@ bool AvFormatDecoder::ITVHandleAction(const QString &action) { QMutexLocker locker(&itvLock); - return itv->OfferKey(action); + if (itv) + return itv->OfferKey(action); + else + return false; } -/* \fn AvFormatDecoder::ITVRestart(bool isLive) +/* \fn AvFormatDecoder::ITVRestart(uint chanid, int cardid, bool isLive) * \brief Restart the MHEG/MHP engine. */ -void AvFormatDecoder::ITVRestart(uint chanid, bool isLiveTV) +void AvFormatDecoder::ITVRestart(uint chanid, int cardid, bool isLiveTV) { QMutexLocker locker(&itvLock); - QString chanidStr = (chanid) ? QString::number(chanid) : "-1"; - itv->Restart(chanidStr, isLiveTV); + itv = GetNVP()->GetInteractiveTV(); + if (itv) + itv->Restart(chanid, cardid, isLiveTV); } bool AvFormatDecoder::SetAudioByComponentTag(int tag) Index: libs/libmythtv/decoderbase.h =================================================================== --- libs/libmythtv/decoderbase.h (revision 9715) +++ libs/libmythtv/decoderbase.h (working copy) @@ -129,10 +129,9 @@ virtual QString GetXDS(const QString&) const { return QString::null; } // MHEG/MHI stuff - virtual void ITVReset(const QRect& /*total*/, const QRect& /*visible*/) {} virtual bool ITVUpdate(bool /*visible*/) { return false; } virtual bool ITVHandleAction(const QString& /*action*/) { return false; } - virtual void ITVRestart(uint /*chanid*/, bool /*livetv*/) {} + virtual void ITVRestart(uint /*chanid*/, int /*cardid*/, bool /*livetv*/) {} virtual bool SetAudioByComponentTag(int) { return false; } virtual bool SetVideoByComponentTag(int) { return false; } Index: libs/libmythtv/interactivetv.cpp =================================================================== --- libs/libmythtv/interactivetv.cpp (revision 9715) +++ libs/libmythtv/interactivetv.cpp (working copy) @@ -17,7 +17,7 @@ InteractiveTV::InteractiveTV(NuppelVideoPlayer *nvp) : m_context(new MHIContext(this)), m_nvp(nvp) { - Restart("", false); + Restart(-1, 0, false); if (print_verbose_messages & VB_MHEG) { @@ -35,9 +35,9 @@ } // Start or restart the MHEG engine. -void InteractiveTV::Restart(QString chanid, bool isLive) +void InteractiveTV::Restart(uint chanid, int cardid, bool isLive) { - m_context->Restart(chanid, isLive); + m_context->Restart(chanid, cardid, isLive); } // Called by the video player to see if the image needs to be updated Index: libs/libmythtv/NuppelVideoPlayer.h =================================================================== --- libs/libmythtv/NuppelVideoPlayer.h (revision 9715) +++ libs/libmythtv/NuppelVideoPlayer.h (working copy) @@ -92,7 +92,7 @@ kDisplayCC708 = 0x10, kDisplayNUVCaptions = kDisplayNUVTeletextCaptions | kDisplayCC608, kDisplayAllCaptions = 0x1f, - kDisplayITV = 0x20, +// kDisplayITV = 0x20, kDisplayTeletextMenu = 0x40, }; @@ -209,6 +209,7 @@ char *GetScreenGrab(int secondsin, int &buflen, int &vw, int &vh, float &ar); LiveTVChain *GetTVChain(void) { return livetvchain; } + InteractiveTV *GetInteractiveTV(void); // Start/Reset/Stop playing void StartPlaying(void); @@ -348,7 +349,7 @@ // MHEG/MHI stream selection bool ITVHandleAction(const QString &action); - void ITVRestart(uint chanid, bool isLiveTV); + void ITVRestart(uint chanid, int cardid, bool isLiveTV); bool SetAudioByComponentTag(int tag); bool SetVideoByComponentTag(int tag); @@ -617,6 +618,8 @@ // Support for MHEG/MHI bool itvVisible; + InteractiveTV *interactiveTV; + bool itvEnabled; // OSD stuff OSD *osd; Index: libs/libmythtv/tv_play.cpp =================================================================== --- libs/libmythtv/tv_play.cpp (revision 9715) +++ libs/libmythtv/tv_play.cpp (working copy) @@ -210,6 +210,7 @@ REG_KEY("ITV Menu", "MENUYELLOW", "Menu Yellow", "F4"); REG_KEY("ITV Menu", "MENUBLUE", "Menu Blue", "F5"); REG_KEY("ITV Menu", "TEXTEXIT", "Menu Exit", "F6"); + REG_KEY("ITV Menu", "MENUTEXT", "Menu Text", "F7"); /* keys already used: @@ -234,7 +235,7 @@ Global: F1, Playback: Ctrl-B, F7,F8,F9,F10,F11 Teletext F2,F3,F4,F5,F6,F7,F8 - ITV F2,F3,F4,F5,F6 + ITV F2,F3,F4,F5,F6,F7 */ } @@ -1925,7 +1926,7 @@ } // Interactive television - if (activenvp && (activenvp->GetCaptionMode() == kDisplayITV)) + if (activenvp && activenvp->GetInteractiveTV()) { QStringList itv_actions; if (gContext->GetMainWindow()->TranslateKeyPress( @@ -3766,6 +3767,8 @@ // If activenvp is main nvp, show input in on-screen-display if (nvp && activenvp == nvp) UpdateOSDInput(); + + ITVRestart(true); } void TV::ToggleInputs(void) @@ -7054,6 +7057,7 @@ void TV::ITVRestart(bool isLive) { uint chanid = 0; + int cardid = 0; if (activenvp != nvp || paused || !GetOSD()) return; @@ -7061,9 +7065,13 @@ pbinfoLock.lock(); if (playbackinfo) chanid = playbackinfo->chanid.toUInt(); + + if (activerecorder) + cardid = activerecorder->GetRecorderNumber(); + pbinfoLock.unlock(); - nvp->ITVRestart(chanid, isLive); + nvp->ITVRestart(chanid, cardid, isLive); } /* vim: set expandtab tabstop=4 shiftwidth=4: */ Index: libs/libmythtv/mhi.h =================================================================== --- libs/libmythtv/mhi.h (revision 9715) +++ libs/libmythtv/mhi.h (working copy) @@ -45,7 +45,7 @@ void QueueDSMCCPacket(unsigned char *data, int length, int componentTag, unsigned carouselId, int dataBroadcastId); /// Restart the MHEG engine. - void Restart(QString chanid, bool isLive); + void Restart(uint chanid, int cardid, bool isLive); // Offer a key press. Returns true if it accepts it. // This will depend on the current profile. bool OfferKey(QString key); @@ -164,6 +164,7 @@ int m_currentChannel; bool m_isLive; + int m_currentCard; int m_audioTag; int m_videoTag; Index: libs/libmythtv/interactivetv.h =================================================================== --- libs/libmythtv/interactivetv.h (revision 9715) +++ libs/libmythtv/interactivetv.h (working copy) @@ -15,7 +15,7 @@ InteractiveTV(NuppelVideoPlayer *nvp); virtual ~InteractiveTV(); - void Restart(QString chanid, bool isLive); + void Restart(uint chanid, int cardid, bool isLive); // Process an incoming DSMCC packet. void ProcessDSMCCSection(unsigned char *data, int length, int componentTag, unsigned carouselId, Index: libs/libmythtv/avformatdecoder.h =================================================================== --- libs/libmythtv/avformatdecoder.h (revision 9715) +++ libs/libmythtv/avformatdecoder.h (working copy) @@ -136,10 +136,9 @@ virtual QString GetXDS(const QString&) const; // MHEG stuff - virtual void ITVReset(const QRect &total, const QRect& visible); virtual bool ITVUpdate(bool itvVisible); virtual bool ITVHandleAction(const QString&); - virtual void ITVRestart(uint /*chanid*/, bool /*livetv*/); + virtual void ITVRestart(uint /*chanid*/, int cardid, bool /*livetv*/); virtual bool SetAudioByComponentTag(int tag); virtual bool SetVideoByComponentTag(int tag); Index: libs/libmythtv/mhi.cpp =================================================================== --- libs/libmythtv/mhi.cpp (revision 9715) +++ libs/libmythtv/mhi.cpp (working copy) @@ -27,8 +27,9 @@ m_stopped(false), m_updated(false), m_displayWidth(StdDisplayWidth), m_displayHeight(StdDisplayHeight), m_face_loaded(false), m_currentChannel(-1), - m_isLive(false), m_audioTag(-1), - m_videoTag(-1), m_tuningTo(-1) + m_isLive(false), m_currentCard(0), + m_audioTag(-1), m_videoTag(-1), + m_tuningTo(-1) { m_display.setAutoDelete(true); m_dsmccQueue.setAutoDelete(true); @@ -100,12 +101,10 @@ // Start or restart the MHEG engine. -void MHIContext::Restart(QString chanid, bool isLive) +void MHIContext::Restart(uint chanid, int cardid, bool isLive) { - bool ok = false; - m_currentChannel = chanid.toInt(&ok, 10); - if (!ok) - m_currentChannel = -1; + m_currentChannel = chanid; + m_currentCard = cardid; if (m_currentChannel == m_tuningTo && m_currentChannel != -1) { @@ -191,6 +190,8 @@ // Run the engine and find out how long to pause. toWait = m_engine->RunAll(); + if (toWait < 0) + return; } while (key != 0); if (toWait > 1000 || toWait == 0) @@ -329,7 +330,7 @@ action = 102; else if (key == "MENUBLUE") action = 103; - else if (key == "TOGGLECC") + else if (key == "MENUTEXT") action = 104; if (action != 0) @@ -473,14 +474,18 @@ int serviceID = list[2].toInt(&ok, 16); if (!ok) return -1; + // We only return channels that match the current capture card. if (list[1].isEmpty()) // TransportID is not specified { query.prepare( "SELECT chanid " - "FROM channel, dtv_multiplex " - "WHERE networkid = :NETID AND" - " channel.mplexid = dtv_multiplex.mplexid AND " - " serviceid = :SERVICEID"); + "FROM channel, dtv_multiplex, cardinput, capturecard " + "WHERE networkid = :NETID AND" + " channel.mplexid = dtv_multiplex.mplexid AND " + " serviceid = :SERVICEID AND " + " channel.sourceid = cardinput.sourceid AND " + " cardinput.cardid = capturecard.cardid AND " + " cardinput.cardid = :CARDID"); } else { @@ -489,15 +494,19 @@ return -1; query.prepare( "SELECT chanid " - "FROM channel, dtv_multiplex " - "WHERE networkid = :NETID AND" - " channel.mplexid = dtv_multiplex.mplexid AND " - " serviceid = :SERVICEID AND " - " transportid = :TRANSID"); + "FROM channel, dtv_multiplex, cardinput, capturecard " + "WHERE networkid = :NETID AND" + " channel.mplexid = dtv_multiplex.mplexid AND " + " serviceid = :SERVICEID AND " + " transportid = :TRANSID AND " + " channel.sourceid = cardinput.sourceid AND " + " cardinput.cardid = capturecard.cardid AND " + " cardinput.cardid = :CARDID"); query.bindValue(":TRANSID", transportID); } query.bindValue(":NETID", netID); query.bindValue(":SERVICEID", serviceID); + query.bindValue(":CARDID", m_currentCard); if (query.exec() && query.isActive() && query.next()) { int nResult = query.value(0).toInt(); @@ -512,9 +521,13 @@ if (!ok) return -1; MSqlQuery query(MSqlQuery::InitCon()); query.prepare("SELECT chanid " - "FROM channel " - "WHERE channum = :CHAN"); + "FROM channel, cardinput, capturecard " + "WHERE channum = :CHAN AND " + " channel.sourceid = cardinput.sourceid AND " + " cardinput.cardid = capturecard.cardid AND " + " cardinput.cardid = :CARDID"); query.bindValue(":CHAN", channelNo); + query.bindValue(":CARDID", m_currentCard); if (query.exec() && query.isActive() && query.next()) return query.value(0).toInt(); } Index: libs/libmythfreemheg/Engine.cpp =================================================================== --- libs/libmythfreemheg/Engine.cpp (revision 9715) +++ libs/libmythfreemheg/Engine.cpp (working copy) @@ -81,9 +81,12 @@ // if one of the containing directories is updated. if (! Launch(startObj)) { - startObj.m_GroupId.Copy(MHOctetString("~//startup")); - if (! Launch(startObj)) - return CONTENT_CHECK_TIME; // Perhaps we should return failure here. + startObj.m_GroupId.Copy(MHOctetString("~//startup")); + if (! Launch(startObj)) + { + MHLOG(MHLogError, "Unable to launch application"); + return -1; + } } m_fBooting = false; } @@ -188,40 +191,46 @@ if (! m_Context->GetCarouselData(csPath, text)) return false; m_fInTransition = true; // Starting a transition - if (CurrentApp()) { - if (fIsSpawn) { // Run the CloseDown actions. - AddActions(CurrentApp()->m_CloseDown); - RunActions(); + try { + if (CurrentApp()) { + if (fIsSpawn) { // Run the CloseDown actions. + AddActions(CurrentApp()->m_CloseDown); + RunActions(); + } + if (CurrentScene()) CurrentScene()->Destruction(this); + CurrentApp()->Destruction(this); + if (! fIsSpawn) m_ApplicationStack.remove(); // Pop and delete the current app. } - if (CurrentScene()) CurrentScene()->Destruction(this); - CurrentApp()->Destruction(this); - if (! fIsSpawn) m_ApplicationStack.remove(); // Pop and delete the current app. - } - MHApplication *pProgram = (MHApplication*)ParseProgram(text); + MHApplication *pProgram = (MHApplication*)ParseProgram(text); - if ((__mhlogoptions & MHLogScenes) && __mhlogStream != 0) { // Print it so we know what's going on. - pProgram->PrintMe(__mhlogStream, 0); - } + if ((__mhlogoptions & MHLogScenes) && __mhlogStream != 0) { // Print it so we know what's going on. + pProgram->PrintMe(__mhlogStream, 0); + } - if (! pProgram->m_fIsApp) MHERROR("Expected an application"); + if (! pProgram->m_fIsApp) MHERROR("Expected an application"); - // Save the path we use for this app. - pProgram->m_Path = csPath; // Record the path - int nPos = pProgram->m_Path.findRev('/'); - if (nPos < 0) pProgram->m_Path = ""; - else pProgram->m_Path = pProgram->m_Path.left(nPos); - // Have now got the application. - m_ApplicationStack.push(pProgram); + // Save the path we use for this app. + pProgram->m_Path = csPath; // Record the path + int nPos = pProgram->m_Path.findRev('/'); + if (nPos < 0) pProgram->m_Path = ""; + else pProgram->m_Path = pProgram->m_Path.left(nPos); + // Have now got the application. + m_ApplicationStack.push(pProgram); - // This isn't in the standard as far as I can tell but we have to do this because - // we may have events referring to the old application. - m_EventQueue.clear(); + // This isn't in the standard as far as I can tell but we have to do this because + // we may have events referring to the old application. + m_EventQueue.clear(); - // Activate the application. .... - CurrentApp()->Activation(this); - m_fInTransition = false; // The transition is complete - return true; + // Activate the application. .... + CurrentApp()->Activation(this); + m_fInTransition = false; // The transition is complete + return true; + } + catch (...) { + m_fInTransition = false; // The transition is complete + return false; + } } void MHEngine::Quit() @@ -579,6 +588,7 @@ // Redraw an area of the display. This will be called via the context from Redraw. void MHEngine::DrawDisplay(QRegion toDraw) { + if (m_fBooting) return; int nTopStack = CurrentApp() == NULL ? -1 : CurrentApp()->m_DisplayStack.Size()-1; DrawRegion(toDraw, nTopStack); } Index: libs/libmythfreemheg/Logging.h =================================================================== --- libs/libmythfreemheg/Logging.h (revision 9715) +++ libs/libmythfreemheg/Logging.h (working copy) @@ -28,25 +28,8 @@ #undef ASSERT #endif -#ifdef _DEBUG - -#define THIS_FILE __FILE__ -#define ASSERT(f) \ - do \ - { \ - if (!(f)) { Q_ASSERT(f); _asm { int 3 } } \ - } while (0) \ - -#define VERIFY(f) ASSERT(f) -#else #define ASSERT(f) Q_ASSERT(f) -#define VERIFY(f) ((void)(f)) -#endif -// A number of MHEG actions do not appear to actually be used. ASSERT(UNTESTED("Action name")) is used to give -// some idea of those that still need to be tested. -#define UNTESTED(x) (false) - extern int __mhlogoptions; extern void __mhlog(QString logtext); extern FILE *__mhlogStream; @@ -61,7 +44,6 @@ do { \ if (MHLogError & __mhlogoptions) \ __mhlog(__text); \ - ASSERT(false); \ throw "Failed"; \ } while (0) Index: programs/mythfrontend/globalsettings.cpp =================================================================== --- programs/mythfrontend/globalsettings.cpp (revision 9715) +++ programs/mythfrontend/globalsettings.cpp (working copy) @@ -1080,6 +1080,18 @@ return gc; } +static HostCheckBox *EnableMHEG() +{ + HostCheckBox *gc = new HostCheckBox("EnableMHEG"); + gc->setLabel(QObject::tr("Enable Interactive TV")); + gc->setValue(false); + gc->setHelpText(QObject::tr( + "If enabled, interactive TV applications (MHEG) will " + "be activated. This is used for teletext and logos for " + "radio and channels that are currently off-air.")); + return gc; +} + static HostCheckBox *PersistentBrowseMode() { HostCheckBox *gc = new HostCheckBox("PersistentBrowseMode"); @@ -3327,6 +3339,7 @@ osd->addChild(CCBackground()); osd->addChild(DefaultCCMode()); osd->addChild(PersistentBrowseMode()); + osd->addChild(EnableMHEG()); addChild(osd); addChild(OSDCC708Settings());