summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorhschang <chang@dev3>2016-05-16 07:51:49 (GMT)
committerhschang <chang@dev3>2016-05-16 07:51:49 (GMT)
commit27e06ba9c8b055c20ea8c70a405deb0e4019edc5 (patch)
treed44d65aa4e81951fa783718cbfe1815c72e4bdc5 /lib
parent004d6db4a1dda8f08f5ce63f30c102c81b7b0693 (diff)
Support fast channel change.
Diffstat (limited to 'lib')
-rw-r--r--lib/dvb/Makefile.am8
-rw-r--r--lib/dvb/decoder.cpp264
-rw-r--r--lib/dvb/decoder.h31
-rwxr-xr-xlib/dvb/dvb.cpp65
-rw-r--r--lib/dvb/fcc.cpp335
-rw-r--r--lib/dvb/fcc.h67
-rw-r--r--lib/dvb/fccdecoder.cpp75
-rw-r--r--lib/dvb/fccdecoder.h28
-rw-r--r--lib/dvb/idvb.h9
-rw-r--r--lib/dvb/pmt.cpp39
-rw-r--r--lib/dvb/pmt.h8
-rw-r--r--lib/nav/core.cpp17
-rw-r--r--lib/nav/core.h5
-rw-r--r--lib/python/Components/ServiceList.py3
-rwxr-xr-xlib/python/Plugins/Plugin.py6
-rw-r--r--lib/python/Plugins/SystemPlugins/FastChannelChange/Makefile.am7
-rw-r--r--lib/python/Plugins/SystemPlugins/FastChannelChange/__init__.py2
-rw-r--r--lib/python/Plugins/SystemPlugins/FastChannelChange/meta/Makefile.am3
-rw-r--r--lib/python/Plugins/SystemPlugins/FastChannelChange/meta/plugin_fastchannelchange.xml16
-rw-r--r--lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py589
-rwxr-xr-xlib/python/Plugins/SystemPlugins/Makefile.am2
-rw-r--r--lib/python/Screens/Satconfig.py3
-rw-r--r--lib/python/Screens/ServiceScan.py5
-rwxr-xr-xlib/python/enigma_python.i12
-rw-r--r--lib/service/Makefile.am2
-rw-r--r--lib/service/iservice.h5
-rw-r--r--lib/service/listboxservice.cpp11
-rw-r--r--lib/service/listboxservice.h1
-rwxr-xr-xlib/service/servicedvb.cpp20
-rw-r--r--lib/service/servicedvb.h4
-rw-r--r--lib/service/servicedvbfcc.cpp446
-rw-r--r--lib/service/servicedvbfcc.h47
-rw-r--r--lib/service/servicedvbrecord.cpp4
33 files changed, 2099 insertions, 40 deletions
diff --git a/lib/dvb/Makefile.am b/lib/dvb/Makefile.am
index b185237..f4216d9 100644
--- a/lib/dvb/Makefile.am
+++ b/lib/dvb/Makefile.am
@@ -31,7 +31,9 @@ libenigma_dvb_a_SOURCES = \
teletext.cpp \
tstools.cpp \
volume.cpp \
- fbc.cpp
+ fbc.cpp \
+ fcc.cpp \
+ fccdecoder.cpp
dvbincludedir = $(pkgincludedir)/lib/dvb
dvbinclude_HEADERS = \
@@ -63,4 +65,6 @@ dvbinclude_HEADERS = \
teletext.h \
tstools.h \
volume.h \
- fbc.h
+ fbc.h \
+ fcc.h \
+ fccdecoder.h
diff --git a/lib/dvb/decoder.cpp b/lib/dvb/decoder.cpp
index 8a4a82d..e3d97af 100644
--- a/lib/dvb/decoder.cpp
+++ b/lib/dvb/decoder.cpp
@@ -34,6 +34,8 @@
#include <sys/stat.h>
#include <errno.h>
+#include <lib/dvb/fccdecoder.h>
+
/* these are quite new... */
#ifndef AUDIO_GET_PTS
#define AUDIO_GET_PTS _IOR('o', 19, __u64)
@@ -206,9 +208,9 @@ int eDVBAudio::startPid(int pid, int type)
case aDTSHD:
bypass = 0x10;
break;
- case aDDP:
- bypass = 0x22;
- break;
+ case aDDP:
+ bypass = 0x22;
+ break;
}
@@ -304,8 +306,8 @@ eDVBAudio::~eDVBAudio()
DEFINE_REF(eDVBVideo);
-eDVBVideo::eDVBVideo(eDVBDemux *demux, int dev)
- : m_demux(demux), m_dev(dev),
+eDVBVideo::eDVBVideo(eDVBDemux *demux, int dev, bool fcc_enable)
+ : m_demux(demux), m_dev(dev), m_fcc_enable(fcc_enable),
m_width(-1), m_height(-1), m_framerate(-1), m_aspect(-1), m_progressive(-1)
{
char filename[128];
@@ -408,6 +410,9 @@ int eDVBVideo::startPid(int pid, int type)
{
int streamtype = VIDEO_STREAMTYPE_MPEG2;
+ if (m_fcc_enable)
+ return 0;
+
if ((m_fd < 0) || (m_fd_demux < 0))
return -1;
dmx_pes_filter_params pes;
@@ -474,6 +479,9 @@ int eDVBVideo::startPid(int pid, int type)
void eDVBVideo::stop()
{
+ if (m_fcc_enable)
+ return;
+
#if HAVE_DVB_API_VERSION > 2
eDebugNoNewLine("DEMUX_STOP - video - ");
if (::ioctl(m_fd_demux, DMX_STOP) < 0)
@@ -996,7 +1004,7 @@ int eTSMPEGDecoder::setState()
{
if ((m_vpid >= 0) && (m_vpid < 0x1FFF))
{
- m_video = new eDVBVideo(m_demux, m_decoder);
+ m_video = new eDVBVideo(m_demux, m_decoder, m_fcc_enable);
m_video->connectEvent(slot(*this, &eTSMPEGDecoder::video_event), m_video_event_conn);
if (m_video->startPid(m_vpid, m_vtype))
res = -1;
@@ -1102,7 +1110,8 @@ RESULT eTSMPEGDecoder::setAC3Delay(int delay)
eTSMPEGDecoder::eTSMPEGDecoder(eDVBDemux *demux, int decoder)
: m_demux(demux),
m_vpid(-1), m_vtype(-1), m_apid(-1), m_atype(-1), m_pcrpid(-1), m_textpid(-1),
- m_changed(0), m_decoder(decoder), m_video_clip_fd(-1), m_showSinglePicTimer(eTimer::create(eApp))
+ m_changed(0), m_decoder(decoder), m_video_clip_fd(-1), m_showSinglePicTimer(eTimer::create(eApp)),
+ m_fcc_fd(-1), m_fcc_enable(false), m_fcc_state(fcc_state_stop), m_fcc_feid(-1), m_fcc_vpid(-1), m_fcc_vtype(-1), m_fcc_pcrpid(-1)
{
demux->connectEvent(slot(*this, &eTSMPEGDecoder::demux_event), m_demux_event_conn);
CONNECT(m_showSinglePicTimer->timeout, eTSMPEGDecoder::finishShowSinglePic);
@@ -1115,6 +1124,8 @@ eTSMPEGDecoder::~eTSMPEGDecoder()
m_vpid = m_apid = m_pcrpid = m_textpid = pidNone;
m_changed = -1;
setState();
+ fccStop();
+ fccFreeFD();
}
RESULT eTSMPEGDecoder::setVideoPID(int vpid, int type)
@@ -1421,3 +1432,242 @@ int eTSMPEGDecoder::getVideoAspect()
return m_video->getAspect();
return -1;
}
+
+#define FCC_SET_VPID 100
+#define FCC_SET_APID 101
+#define FCC_SET_PCRPID 102
+#define FCC_SET_VCODEC 103
+#define FCC_SET_ACODEC 104
+#define FCC_SET_FRONTEND_ID 105
+#define FCC_START 106
+#define FCC_STOP 107
+#define FCC_DECODER_START 108
+#define FCC_DECODER_STOP 109
+
+RESULT eTSMPEGDecoder::prepareFCC(int fe_id, int vpid, int vtype, int pcrpid)
+{
+ //eDebug("[eTSMPEGDecoder::prepareFCC] vp : %d, vt : %d, pp : %d, fe : %d", vpid, vtype, pcrpid, fe_id);
+
+ if ((fccGetFD() == -1) || (fccSetPids(fe_id, vpid, vtype, pcrpid) < 0) || (fccStart() < 0))
+ {
+ fccFreeFD();
+ return -1;
+ }
+
+ m_fcc_enable = true;
+
+ return 0;
+}
+
+RESULT eTSMPEGDecoder::fccDecoderStart()
+{
+ if (m_fcc_fd == -1)
+ return -1;
+
+ if (m_fcc_state != fcc_state_ready)
+ {
+ eDebug("FCC decoder is already in decoding state.");
+ return 0;
+ }
+
+ if (ioctl(m_fcc_fd, FCC_DECODER_START) < 0)
+ {
+ eDebug("ioctl FCC_DECODER_START failed! (%m)");
+ return -1;
+ }
+
+ m_fcc_state = fcc_state_decoding;
+
+ eDebug("[eTSMPEGDecoder] FCC_DECODER_START OK!");
+ return 0;
+}
+
+RESULT eTSMPEGDecoder::fccDecoderStop()
+{
+ if (m_fcc_fd == -1)
+ return -1;
+
+ if (m_fcc_state != fcc_state_decoding)
+ {
+ eDebug("FCC decoder is not in decoding state.");
+ }
+ else if (ioctl(m_fcc_fd, FCC_DECODER_STOP) < 0)
+ {
+ eDebug("ioctl FCC_DECODER_STOP failed! (%m)");
+ return -1;
+ }
+
+ m_fcc_state = fcc_state_ready;
+
+ /* stop pcr, video, audio, text */
+ finishShowSinglePic();
+
+ m_vpid = m_apid = m_pcrpid = m_textpid = pidNone;
+ m_changed = -1;
+ setState();
+
+ eDebug("[eTSMPEGDecoder] FCC_DECODER_STOP OK!");
+ return 0;
+}
+
+RESULT eTSMPEGDecoder::fccUpdatePids(int fe_id, int vpid, int vtype, int pcrpid)
+{
+ //eDebug("[eTSMPEGDecoder] vp : %d, vt : %d, pp : %d, fe : %d", vpid, vtype, pcrpid, fe_id);
+
+ if ((fe_id != m_fcc_feid) || (vpid != m_fcc_vpid) || (vtype != m_fcc_vtype) || (pcrpid != m_fcc_pcrpid))
+ {
+ int cur_fcc_state = m_fcc_state;
+ fccStop();
+ if (prepareFCC(fe_id, vpid, vtype, pcrpid))
+ {
+ eDebug("[eTSMPEGDecoder] prepare FCC failed!");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+RESULT eTSMPEGDecoder::fccStart()
+{
+ if (m_fcc_fd == -1)
+ return -1;
+
+ if (m_fcc_state != fcc_state_stop)
+ {
+ eDebug("[eTSMPEGDecoder] FCC is already started!");
+ return 0;
+ }
+ else if (ioctl(m_fcc_fd, FCC_START) < 0)
+ {
+ eDebug("ioctl FCC_START failed! (%m)");
+ return -1;
+ }
+
+ eDebug("[eTSMPEGDecoder] FCC_START OK!");
+
+ m_fcc_state = fcc_state_ready;
+ return 0;
+}
+
+RESULT eTSMPEGDecoder::fccStop()
+{
+ if (m_fcc_fd == -1)
+ return -1;
+
+ if (m_fcc_state == fcc_state_stop)
+ {
+ eDebug("[eTSMPEGDecoder] FCC is already stopped!");
+ return 0;
+ }
+
+ else if (m_fcc_state == fcc_state_decoding)
+ {
+ fccDecoderStop();
+ }
+
+ if (ioctl(m_fcc_fd, FCC_STOP) < 0)
+ {
+ eDebug("ioctl FCC_STOP failed! (%m)");
+ return -1;
+ }
+
+ m_fcc_state = fcc_state_stop;
+
+ eDebug("[eTSMPEGDecoder] FCC_STOP OK!");
+ return 0;
+}
+
+RESULT eTSMPEGDecoder::fccSetPids(int fe_id, int vpid, int vtype, int pcrpid)
+{
+ int streamtype = VIDEO_STREAMTYPE_MPEG2;
+
+ if (m_fcc_fd == -1)
+ return -1;
+
+ if (ioctl(m_fcc_fd, FCC_SET_FRONTEND_ID, fe_id) < 0)
+ {
+ eDebug("[eTSMPEGDecoder] FCC_SET_FRONTEND_ID failed! (%m)");
+ return -1;
+ }
+
+ else if(ioctl(m_fcc_fd, FCC_SET_PCRPID, pcrpid) < 0)
+ {
+ eDebug("[eTSMPEGDecoder] FCC_SET_PCRPID failed! (%m)");
+ return -1;
+ }
+
+ else if (ioctl(m_fcc_fd, FCC_SET_VPID, vpid) < 0)
+ {
+ eDebug("[eTSMPEGDecoder] FCC_SET_VPID failed! (%m)");
+ return -1;
+ }
+
+ switch(vtype)
+ {
+ default:
+ case eDVBVideo::MPEG2:
+ break;
+ case eDVBVideo::MPEG4_H264:
+ streamtype = VIDEO_STREAMTYPE_MPEG4_H264;
+ break;
+ case eDVBVideo::MPEG1:
+ streamtype = VIDEO_STREAMTYPE_MPEG1;
+ break;
+ case eDVBVideo::MPEG4_Part2:
+ streamtype = VIDEO_STREAMTYPE_MPEG4_Part2;
+ break;
+ case eDVBVideo::VC1:
+ streamtype = VIDEO_STREAMTYPE_VC1;
+ break;
+ case eDVBVideo::VC1_SM:
+ streamtype = VIDEO_STREAMTYPE_VC1_SM;
+ break;
+ case eDVBVideo::H265_HEVC:
+ streamtype = VIDEO_STREAMTYPE_H265_HEVC;
+ break;
+ }
+
+ if(ioctl(m_fcc_fd, FCC_SET_VCODEC, streamtype) < 0)
+ {
+ eDebug("[eTSMPEGDecoder] FCC_SET_VCODEC failed! (%m)");
+ return -1;
+ }
+
+ m_fcc_feid = fe_id;
+ m_fcc_vpid = vpid;
+ m_fcc_vtype = vtype;
+ m_fcc_pcrpid = pcrpid;
+
+ //eDebug("[eTSMPEGDecoder] SET PIDS OK!");
+ return 0;
+}
+
+RESULT eTSMPEGDecoder::fccGetFD()
+{
+ if (m_fcc_fd == -1)
+ {
+ eFCCDecoder* fcc = eFCCDecoder::getInstance();
+ if (fcc != NULL)
+ {
+ m_fcc_fd = fcc->allocateFcc();
+ }
+ }
+
+ return m_fcc_fd;
+}
+
+RESULT eTSMPEGDecoder::fccFreeFD()
+{
+ if (m_fcc_fd != -1)
+ {
+ eFCCDecoder* fcc = eFCCDecoder::getInstance();
+ if (fcc != NULL)
+ {
+ fcc->freeFcc(m_fcc_fd);
+ m_fcc_fd = -1;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/lib/dvb/decoder.h b/lib/dvb/decoder.h
index f0f8b2f..0636516 100644
--- a/lib/dvb/decoder.h
+++ b/lib/dvb/decoder.h
@@ -40,6 +40,7 @@ class eDVBVideo: public iObject, public Object
private:
ePtr<eDVBDemux> m_demux;
int m_fd, m_fd_demux, m_dev;
+ bool m_fcc_enable;
#if HAVE_DVB_API_VERSION < 3
m_fd_video;
#endif
@@ -50,7 +51,7 @@ private:
int m_width, m_height, m_framerate, m_aspect, m_progressive;
public:
enum { MPEG2, MPEG4_H264, MPEG1, MPEG4_Part2, VC1, VC1_SM, H265_HEVC };
- eDVBVideo(eDVBDemux *demux, int dev);
+ eDVBVideo(eDVBDemux *demux, int dev, bool fcc_enable=false);
void stop();
#if HAVE_DVB_API_VERSION < 3
int setPid(int pid);
@@ -120,6 +121,16 @@ private:
ePtr<eDVBPCR> m_pcr;
ePtr<eDVBTText> m_text;
int m_vpid, m_vtype, m_apid, m_atype, m_pcrpid, m_textpid;
+
+ int m_fcc_fd;
+ bool m_fcc_enable;
+ int m_fcc_state;
+
+ int m_fcc_feid;
+ int m_fcc_vpid;
+ int m_fcc_vtype;
+ int m_fcc_pcrpid;
+
enum
{
changeVideo = 1,
@@ -167,6 +178,7 @@ public:
- trickmode, highspeed reverse: data source fast forwards / reverses, decoder just displays frames as fast as it can
- slow motion: decoder displays frames multiple times
*/
+
enum {
stateStop,
statePause,
@@ -195,6 +207,23 @@ public:
int getVideoAspect();
static RESULT setHwPCMDelay(int delay);
static RESULT setHwAC3Delay(int delay);
+
+ enum
+ {
+ fcc_state_stop,
+ fcc_state_ready,
+ fcc_state_decoding
+ };
+
+ RESULT prepareFCC(int fe_id, int vpid, int vtype, int pcrpid);
+ RESULT fccStart();
+ RESULT fccStop();
+ RESULT fccDecoderStart();
+ RESULT fccDecoderStop();
+ RESULT fccUpdatePids(int fe_id, int vpid, int vtype, int pcrpid);
+ RESULT fccSetPids(int fe_id, int vpid, int vtype, int pcrpid);
+ RESULT fccGetFD();
+ RESULT fccFreeFD();
};
#endif
diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp
index 0a371f0..72d4687 100755
--- a/lib/dvb/dvb.cpp
+++ b/lib/dvb/dvb.cpp
@@ -7,6 +7,7 @@
#include <lib/dvb/specs.h>
#include <lib/dvb/fbc.h>
+#include <lib/dvb/fcc.h>
#include <errno.h>
#include <sys/types.h>
@@ -988,6 +989,56 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
int *decremented_cached_channel_fe_usecount=NULL,
*decremented_fe_usecount=NULL;
+ /* check FCC channels */
+ std::vector<int*> fcc_decremented_fe_usecounts;
+ std::map<eDVBChannelID, int> fcc_chids;
+ int apply_to_ignore = 0;
+ if (!eFCCServiceManager::getFCCChannelID(fcc_chids))
+ {
+ for (std::map<eDVBChannelID, int>::iterator i(fcc_chids.begin()); i != fcc_chids.end(); ++i)
+ {
+ //eDebug("[eDVBResourceManager::canAllocateChannel] FCC NS : %08x, TSID : %04x, ONID : %04x", i->first.dvbnamespace.get(), i->first.transport_stream_id.get(), i->first.original_network_id.get());
+ if (ignore == i->first)
+ {
+ apply_to_ignore = i->second;
+ continue;
+ }
+ for (std::list<active_channel>::iterator ii(active_channels.begin()); ii != active_channels.end(); ++ii)
+ {
+ eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
+ if (ii->m_channel_id == i->first)
+ {
+ eDVBChannel *channel = (eDVBChannel*) &(*ii->m_channel);
+
+ int check_usecount = channel == &(*m_cached_channel) ? 1 : 0;
+ check_usecount += i->second * 2; // one is used in eDVBServicePMTHandler and another is used in eDVBScan.
+ //eDebug("[eDVBResourceManager::canAllocateChannel] channel->getUseCount() : %d , check_usecount : %d (cached : %d)", channel->getUseCount(), check_usecount, channel == &(*m_cached_channel));
+ if (channel->getUseCount() == check_usecount)
+ {
+ ePtr<iDVBFrontend> fe;
+ if (!ii->m_channel->getFrontend(fe))
+ {
+ for (eSmartPtrList<eDVBRegisteredFrontend>::iterator iii(frontends.begin()); iii != frontends.end(); ++iii)
+ {
+ if ( &(*fe) == &(*iii->m_frontend) )
+ {
+ //eDebug("[eDVBResourceManager::canAllocateChannel] fcc : decrease fcc fe use_count! feid : %d (%d -> %d)", iii->m_frontend->getSlotID(), iii->m_inuse, iii->m_inuse-1);
+ --iii->m_inuse;
+ int *tmp_decremented_fe_usecount = &iii->m_inuse;
+ fcc_decremented_fe_usecounts.push_back(tmp_decremented_fe_usecount);
+ if (channel == &(*m_cached_channel))
+ decremented_cached_channel_fe_usecount = tmp_decremented_fe_usecount;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
{
eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
@@ -999,7 +1050,10 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
// another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
// so we must check here if usecount is 3 (when the channel is equal to the cached channel)
// or 2 when the cached channel is not equal to the compared channel
- if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2) // channel only used once..
+ int check_usecount = channel == &(*m_cached_channel) ? 1 : 0;
+ check_usecount += (apply_to_ignore+1) * 2; // one is used in eDVBServicePMTHandler and another is used in eDVBScan.
+ //eDebug("[eDVBResourceManager::canAllocateChannel] channel->getUseCount() : %d , check_usecount : %d (cached : %d)", channel->getUseCount(), check_usecount, channel == &(*m_cached_channel));
+ if (channel->getUseCount() == check_usecount) // channel only used once..(except fcc)
{
ePtr<iDVBFrontend> fe;
if (!i->m_channel->getFrontend(fe))
@@ -1008,6 +1062,7 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
{
if ( &(*fe) == &(*ii->m_frontend) )
{
+ //eDebug("[eDVBResourceManager::canAllocateChannel] ignore : decrease fcc fe use_count! feid : %d (%d -> %d)", ii->m_frontend->getSlotID(), ii->m_inuse, ii->m_inuse-1);
--ii->m_inuse;
decremented_fe_usecount = &ii->m_inuse;
if (channel == &(*m_cached_channel))
@@ -1070,6 +1125,14 @@ error:
++(*decremented_fe_usecount);
if (decremented_cached_channel_fe_usecount)
++(*decremented_cached_channel_fe_usecount);
+ if (fcc_decremented_fe_usecounts.size())
+ {
+ for (std::vector<int*>::iterator i(fcc_decremented_fe_usecounts.begin()); i != fcc_decremented_fe_usecounts.end(); ++i)
+ {
+ //eDebug("[eDVBResourceManager::canAllocateChannel] fcc : increase fcc fe use_count!");
+ ++(**i);
+ }
+ }
return ret;
}
diff --git a/lib/dvb/fcc.cpp b/lib/dvb/fcc.cpp
new file mode 100644
index 0000000..614340b
--- /dev/null
+++ b/lib/dvb/fcc.cpp
@@ -0,0 +1,335 @@
+#include <lib/dvb/fcc.h>
+#include <lib/nav/core.h>
+#include <lib/base/nconfig.h>
+#include <lib/base/eerror.h>
+#include <lib/python/python.h>
+
+//#define FCC_DEBUG
+
+void FCCServiceChannels::addFCCService(const eServiceReference &service)
+{
+ eDVBChannelID fcc_chid;
+
+ ((const eServiceReferenceDVB&)service).getChannelID(fcc_chid);
+
+ if (m_fcc_chids.find(fcc_chid) != m_fcc_chids.end())
+ m_fcc_chids[fcc_chid] += 1;
+ else
+ m_fcc_chids[fcc_chid] = 1;
+}
+
+void FCCServiceChannels::removeFCCService(const eServiceReference &service)
+{
+ eDVBChannelID fcc_chid;
+ ((const eServiceReferenceDVB&)service).getChannelID(fcc_chid);
+
+ if (m_fcc_chids.find(fcc_chid) != m_fcc_chids.end())
+ {
+ m_fcc_chids[fcc_chid] -= 1;
+
+ if (m_fcc_chids[fcc_chid] == 0)
+ m_fcc_chids.erase(fcc_chid);
+ }
+}
+
+int FCCServiceChannels::getFCCChannelID(std::map<eDVBChannelID, int> &fcc_chids)
+{
+ if (!m_fcc_chids.size()) return -1;
+
+ fcc_chids = m_fcc_chids;
+ return 0;
+}
+
+eFCCServiceManager *eFCCServiceManager::m_instance = (eFCCServiceManager*)0;
+
+eFCCServiceManager* eFCCServiceManager::getInstance()
+{
+ return m_instance;
+}
+
+eFCCServiceManager::eFCCServiceManager(eNavigation *navptr)
+ :m_core(navptr), m_fcc_enable(false)
+{
+ if (!m_instance)
+ {
+ m_instance = this;
+ }
+}
+
+eFCCServiceManager::~eFCCServiceManager()
+{
+ if (m_instance == this)
+ {
+ m_instance = 0;
+ }
+}
+
+RESULT eFCCServiceManager::playFCCService(const eServiceReference &ref, ePtr<iPlayableService> &service)
+{
+ std::map< ePtr<iPlayableService>, FCCServiceElem >::iterator it = m_FCCServices.begin();
+ for (;it != m_FCCServices.end();++it)
+ {
+ ASSERT (ref != it->second.m_service_reference);
+ }
+
+ ASSERT(m_core->m_servicehandler);
+ RESULT res = m_core->m_servicehandler->play(ref, service);
+ if (res)
+ service = 0;
+ else
+ {
+ ePtr<eConnection> conn;
+ service->connectEvent(slot(*this, &eFCCServiceManager::FCCEvent), conn);
+
+ FCCServiceElem elem = {ref, conn, fcc_state_preparing};
+ m_FCCServices[service] = elem;
+
+ res = service->start();
+ }
+
+ printFCCServices();
+
+ return res;
+}
+
+void eFCCServiceManager::FCCEvent(iPlayableService* service, int event)
+{
+ std::map<ePtr<iPlayableService>, FCCServiceElem >::iterator it = m_FCCServices.find(service);
+ if (it == m_FCCServices.end())
+ {
+ eDebug("[eFCCServiceManager] event for non registered FCC service");
+ return;
+ }
+
+ switch (event)
+ {
+ case iPlayableService::evStart:
+ {
+ m_fccServiceChannels.addFCCService(it->second.m_service_reference);
+ break;
+ }
+ case iPlayableService::evStopped:
+ {
+ m_fccServiceChannels.removeFCCService(it->second.m_service_reference);
+ break;
+ }
+ case iPlayableService::evTuneFailed:
+ case iPlayableService::evFccFailed:
+ {
+ eDebug("[eFCCServiceManager][%s] set service to state failed.", it->second.m_service_reference.toString().c_str());
+ it->second.m_state = fcc_state_failed;
+ break;
+ }
+ }
+ m_fcc_event(event);
+}
+
+RESULT eFCCServiceManager::cleanupFCCService()
+{
+ if (m_FCCServices.size())
+ {
+ std::map<ePtr<iPlayableService>, FCCServiceElem >::iterator it = m_FCCServices.begin();
+ for (;it != m_FCCServices.end();++it)
+ {
+ eDebug("[eFCCServiceManager] stop FCC service sref : %s", it->second.m_service_reference.toString().c_str());
+ it->first->stop();
+ }
+
+ m_FCCServices.clear();
+ }
+ return 0;
+}
+
+RESULT eFCCServiceManager::stopFCCService(const eServiceReference &sref)
+{
+ if (m_FCCServices.size())
+ {
+ std::map<ePtr<iPlayableService>, FCCServiceElem >::iterator it = m_FCCServices.begin();
+ for (; it != m_FCCServices.end();)
+ {
+ if (it->second.m_service_reference == sref)
+ {
+ eDebug("[eFCCServiceManager] stop FCC service sref : %s", it->second.m_service_reference.toString().c_str());
+ it->first->stop();
+ m_FCCServices.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ printFCCServices();
+ }
+ return 0;
+}
+
+RESULT eFCCServiceManager::stopFCCService()
+{
+ if (m_FCCServices.size())
+ {
+ std::map<ePtr<iPlayableService>, FCCServiceElem >::iterator it = m_FCCServices.begin();
+ for (; it != m_FCCServices.end();)
+ {
+ if (it->second.m_state == fcc_state_failed)
+ {
+ eDebug("[eFCCServiceManager] stop FCC service sref : %s", it->second.m_service_reference.toString().c_str());
+ it->first->stop();
+ m_FCCServices.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ printFCCServices();
+ }
+ return 0;
+}
+
+RESULT eFCCServiceManager::tryFCCService(const eServiceReference &sref, ePtr<iPlayableService> &service)
+{
+ ePtr<iPlayableService> new_service = 0;
+
+ printFCCServices();
+
+ int get_fcc_decoding = 0;
+
+ /* stop previous decoding service */
+ std::map< ePtr<iPlayableService>, FCCServiceElem >::iterator it;
+ for (it = m_FCCServices.begin();it != m_FCCServices.end();++it)
+ {
+ if (it->second.m_state == fcc_state_decoding)
+ {
+ ASSERT(get_fcc_decoding == 0);
+ get_fcc_decoding = 1;
+
+ /* send end event */
+ m_core->m_event(iPlayableService::evEnd);
+
+ /* kill service and event */
+ m_core->m_service_event_conn = 0;
+ m_core->m_runningService = 0;
+
+ /* connect to fcc event */
+ ePtr<eConnection> conn;
+ it->first->connectEvent(slot(*this, &eFCCServiceManager::FCCEvent), conn);
+ it->second.m_service_event_conn = conn;
+ it->second.m_state = fcc_state_preparing;
+
+ /* switch to FCC prepare state */
+ it->first->start();
+
+ /* update FCCServiceChannels */
+ m_fccServiceChannels.addFCCService(it->second.m_service_reference);
+ }
+ }
+
+ /* search new service */
+ for (it = m_FCCServices.begin();it != m_FCCServices.end();++it)
+ {
+ if (it->second.m_service_reference == sref)
+ {
+ eDebug("[eFCCServiceManager] use FCC service sref : %s", it->second.m_service_reference.toString().c_str());
+ it->second.m_service_event_conn = 0; /* disconnect FCC event */
+ it->second.m_state = fcc_state_decoding;
+ new_service = it->first;
+ m_fccServiceChannels.removeFCCService(it->second.m_service_reference);
+ break;
+ }
+ }
+
+ if (new_service)
+ {
+ service = new_service;
+ }
+
+ else /* If new service is not found in FCC service list, cleanup all FCC prepared services and get new FCC service. */
+ {
+ cleanupFCCService();
+ m_core->stopService();
+ if (eFCCServiceManager::checkAvailable(sref))
+ {
+ ASSERT(m_core->m_servicehandler);
+ m_core->m_servicehandler->play(sref, service);
+
+ if (service)
+ {
+ FCCServiceElem elem = {sref, 0, fcc_state_decoding};
+ m_FCCServices[service] = elem;
+ service->start(); // do FCC preparing
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ printFCCServices();
+
+ return 0;
+}
+
+int eFCCServiceManager::isLocked(ePtr<iPlayableService> service)
+{
+ ePtr<iFrontendInformation> ptr;
+ service->frontendInfo(ptr);
+ return ptr->getFrontendInfo(iDVBFrontend_ENUMS::locked);
+}
+
+PyObject *eFCCServiceManager::getFCCServiceList()
+{
+ ePyObject dest = PyDict_New();
+ if (dest)
+ {
+ std::map< ePtr<iPlayableService>, FCCServiceElem >::iterator it = m_FCCServices.begin();
+ for (;it != m_FCCServices.end();++it)
+ {
+ ePyObject tplist = PyList_New(0);
+ PyList_Append(tplist, PyInt_FromLong((long)it->second.m_state));
+ PyList_Append(tplist, PyInt_FromLong((long)isLocked(it->first)));
+ PyDict_SetItemString(dest, it->second.m_service_reference.toString().c_str(), tplist);
+ Py_DECREF(tplist);
+ }
+ }
+
+ else
+ Py_RETURN_NONE;
+ return dest;
+}
+
+void eFCCServiceManager::printFCCServices()
+{
+#ifdef FCC_DEBUG
+ eDebug(" [eFCCServiceManager::printFCCServices][*] total size : %d", m_FCCServices.size());
+
+ std::map< ePtr<iPlayableService>, FCCServiceElem >::iterator it = m_FCCServices.begin();
+ for (;it != m_FCCServices.end();++it)
+ {
+ eDebug(" [eFCCServiceManager::printFCCServices][*] sref : %s, state : %d, tune : %d", it->second.m_service_reference.toString().c_str(), it->second.m_state, isLocked(it->first));
+ }
+#else
+ ;
+#endif
+}
+
+int eFCCServiceManager::getFCCChannelID(std::map<eDVBChannelID, int> &fcc_chids)
+{
+ eFCCServiceManager *fcc_mng = eFCCServiceManager::getInstance();
+ if (!fcc_mng) return -1;
+ return fcc_mng->m_fccServiceChannels.getFCCChannelID(fcc_chids);
+}
+
+bool eFCCServiceManager::checkAvailable(const eServiceReference &ref)
+{
+ int serviceType = ref.getData(0);
+ eFCCServiceManager *fcc_mng = eFCCServiceManager::getInstance();
+
+ if (ref.path.empty() && (serviceType != 2) && (serviceType != 10) && fcc_mng) // no PVR, streaming, radio channel..
+ return fcc_mng->isEnable();
+ return false;
+}
+
+DEFINE_REF(eFCCServiceManager);
+
diff --git a/lib/dvb/fcc.h b/lib/dvb/fcc.h
new file mode 100644
index 0000000..aacd9d8
--- /dev/null
+++ b/lib/dvb/fcc.h
@@ -0,0 +1,67 @@
+#ifndef __dvb_fcc_h
+#define __dvb_fcc_h
+
+#include <lib/dvb/idvb.h>
+#include <lib/base/object.h>
+#include <lib/service/iservice.h>
+#include <connection.h>
+
+class eNavigation;
+
+class FCCServiceChannels
+{
+private:
+ std::map<eDVBChannelID, int> m_fcc_chids;
+
+public:
+ void addFCCService(const eServiceReference &service);
+ void removeFCCService(const eServiceReference &service);
+ int getFCCChannelID(std::map<eDVBChannelID, int> &fcc_chids);
+};
+
+typedef struct _tagFccElem
+{
+ eServiceReference m_service_reference;
+ ePtr<eConnection> m_service_event_conn;
+ int m_state;
+}FCCServiceElem;
+
+class eFCCServiceManager: public iObject, public Object
+{
+ DECLARE_REF(eFCCServiceManager);
+private:
+ eNavigation *m_core;
+ static eFCCServiceManager* m_instance;
+ std::map<ePtr<iPlayableService>, FCCServiceElem, std::less<iPlayableService*> > m_FCCServices;
+ FCCServiceChannels m_fccServiceChannels;
+
+ bool m_fcc_enable;
+
+ void FCCEvent(iPlayableService* service, int event);
+public:
+ PSignal1<void, int> m_fcc_event;
+ static eFCCServiceManager* getInstance();
+ eFCCServiceManager(eNavigation *navptr);
+ ~eFCCServiceManager();
+
+ enum
+ {
+ fcc_state_preparing,
+ fcc_state_decoding,
+ fcc_state_failed
+ };
+ SWIG_VOID(RESULT) playFCCService(const eServiceReference &ref, ePtr<iPlayableService> &SWIG_OUTPUT);
+ RESULT stopFCCService(const eServiceReference &sref);
+ RESULT stopFCCService();
+ RESULT cleanupFCCService();
+ RESULT tryFCCService(const eServiceReference &service, ePtr<iPlayableService> &ptr);
+ int isLocked(ePtr<iPlayableService> service);
+ PyObject *getFCCServiceList();
+ void printFCCServices();
+ static int getFCCChannelID(std::map<eDVBChannelID, int> &fcc_chids);
+ static bool checkAvailable(const eServiceReference &ref);
+ void setFCCEnable(int enable) { m_fcc_enable = (enable != 0); }
+ bool isEnable() { return m_fcc_enable; }
+};
+
+#endif /* __dvb_fcc_h */
diff --git a/lib/dvb/fccdecoder.cpp b/lib/dvb/fccdecoder.cpp
new file mode 100644
index 0000000..c408c1a
--- /dev/null
+++ b/lib/dvb/fccdecoder.cpp
@@ -0,0 +1,75 @@
+#include <lib/dvb/fccdecoder.h>
+#include <lib/base/eerror.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+bool eFCCDecoder::isDestroyed = false;
+eFCCDecoder::eFCCDecoder()
+{
+ int index = 0;
+
+ eDebug("[eFCCDecoder] scanning for FCC device files..");
+ while(1)
+ {
+ struct stat s;
+ char filename[128];
+ sprintf(filename, "/dev/fcc%d", index);
+ if (stat(filename, &s))
+ break;
+
+ eDebug("[eFCCDecoder] %s found..", filename);
+ m_fccs.push_back(-1);
+ index++;
+ }
+}
+
+eFCCDecoder::~eFCCDecoder()
+{
+ isDestroyed = true;
+}
+
+int eFCCDecoder::allocateFcc()
+{
+ int fccFd = -1;
+ for(unsigned int i = 0; i < m_fccs.size(); i++)
+ {
+ if (m_fccs[i]== -1)
+ {
+ char filename[128];
+ sprintf(filename, "/dev/fcc%d", i);
+
+ fccFd = ::open(filename, O_RDWR);
+ if (fccFd < 0)
+ eDebug("[eFCCDecoder] open %s failed!", filename);
+
+ else
+ eDebug("[eFCCDecoder] alloc %s", filename);
+
+ m_fccs[i] = fccFd;
+ break;
+ }
+ }
+
+ return fccFd;
+}
+
+void eFCCDecoder::freeFcc(int fccFd)
+{
+ if (fccFd < 0)
+ return;
+
+ for(unsigned int i = 0; i < m_fccs.size(); i++)
+ {
+ if (m_fccs[i]== fccFd)
+ {
+ m_fccs[i] = -1;
+ eDebug("[eFCCDecoder] close /dev/fcc%d", i);
+ ::close(fccFd);
+ break;
+ }
+ }
+}
+
diff --git a/lib/dvb/fccdecoder.h b/lib/dvb/fccdecoder.h
new file mode 100644
index 0000000..c7b57c5
--- /dev/null
+++ b/lib/dvb/fccdecoder.h
@@ -0,0 +1,28 @@
+#ifndef __dvb_fcc_decoder_h
+#define __dvb_fcc_decoder_h
+
+#include <vector>
+
+class eFCCDecoder
+{
+ std::vector<int> m_fccs;
+ static eFCCDecoder *instance;
+ static bool isDestroyed;
+
+public:
+ eFCCDecoder();
+ ~eFCCDecoder();
+ int allocateFcc();
+ void freeFcc(int fccFd);
+
+ static eFCCDecoder* getInstance()
+ {
+ if (isDestroyed)
+ return NULL;
+
+ static eFCCDecoder instance;
+ return &instance;
+ }
+};
+
+#endif /* __dvb_fcc_decoder_h */
diff --git a/lib/dvb/idvb.h b/lib/dvb/idvb.h
index 2c11ff8..d0d1043 100644
--- a/lib/dvb/idvb.h
+++ b/lib/dvb/idvb.h
@@ -636,6 +636,7 @@ public:
virtual RESULT getCADemuxID(uint8_t &id)=0;
virtual RESULT flush()=0;
virtual int openDVR(int flags)=0;
+ virtual int getSource()=0;
};
#if HAVE_DVB_API_VERSION < 3 && !defined(VIDEO_EVENT_SIZE_CHANGED)
@@ -690,6 +691,14 @@ public:
/** Display any complete data as fast as possible */
virtual RESULT setTrickmode()=0;
+
+ virtual RESULT prepareFCC(int fe_id, int vpid, int vtype, int pcrpid)=0;
+
+ virtual RESULT fccDecoderStart()=0;
+
+ virtual RESULT fccDecoderStop()=0;
+
+ virtual RESULT fccUpdatePids(int fe_id, int vpid, int vtype, int pcrpid)=0;
virtual RESULT getPTS(int what, pts_t &pts) = 0;
diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp
index b3e8aeb..5132b38 100644
--- a/lib/dvb/pmt.cpp
+++ b/lib/dvb/pmt.cpp
@@ -33,6 +33,8 @@ eDVBServicePMTHandler::eDVBServicePMTHandler()
m_pmt_pid = -1;
m_dsmcc_pid = -1;
m_isstreamclient = false;
+ m_ca_disabled = false;
+ m_pmt_ready = false;
eDVBResourceManager::getInstance(m_resourceManager);
CONNECT(m_PMT.tableReady, eDVBServicePMTHandler::PMTready);
CONNECT(m_PAT.tableReady, eDVBServicePMTHandler::PATready);
@@ -115,6 +117,7 @@ void eDVBServicePMTHandler::PMTready(int error)
serviceEvent(eventNoPMT);
else
{
+ m_pmt_ready = true;
m_have_cached_program = false;
serviceEvent(eventNewProgramInfo);
mDemuxId = m_decode_demux_num;
@@ -132,9 +135,11 @@ void eDVBServicePMTHandler::PMTready(int error)
else
demuxes[1]=demuxes[0];
eDVBCAService::register_service(m_reference, demuxes, m_ca_servicePtr);
- eDVBCIInterfaces::getInstance()->recheckPMTHandlers();
+ if (!m_ca_disabled)
+ eDVBCIInterfaces::getInstance()->recheckPMTHandlers();
}
- eDVBCIInterfaces::getInstance()->gotPMT(this);
+ if (!m_ca_disabled)
+ eDVBCIInterfaces::getInstance()->gotPMT(this);
}
if (m_ca_servicePtr)
{
@@ -504,6 +509,8 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
program.pmtPid = -1;
program.textPid = -1;
program.aitPid = -1;
+ program.isCached = false;
+ program.pmtVersion = -1;
int first_ac3 = -1;
program.defaultAudioStream = 0;
@@ -532,6 +539,7 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
eDVBTableSpec table_spec;
ptr->getSpec(table_spec);
program.pmtPid = table_spec.pid < 0x1fff ? table_spec.pid : -1;
+ program.pmtVersion = table_spec.version;
std::vector<ProgramMapSection*>::const_iterator i;
for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
{
@@ -955,6 +963,9 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
int cached_pcrpid = m_service->getCacheEntry(eDVBService::cPCRPID),
vpidtype = m_service->getCacheEntry(eDVBService::cVTYPE),
cnt=0;
+
+ program.isCached = true;
+
if ( vpidtype == -1 )
vpidtype = videoStream::vtMPEG2;
if ( cached_vpid != -1 )
@@ -1139,7 +1150,7 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem
if (!m_resourceManager->getChannelList(db))
db->getService((eServiceReferenceDVB&)m_reference, m_service);
- if (!res && !simulate)
+ if (!res && !simulate && !m_ca_disabled)
eDVBCIInterfaces::getInstance()->addPMTHandler(this);
} else if (!simulate) // no simulation of playback services
{
@@ -1266,6 +1277,28 @@ void eDVBServicePMTHandler::free()
m_demux = 0;
}
+void eDVBServicePMTHandler::addCaHandler()
+{
+ m_ca_disabled = false;
+ if (m_channel)
+ {
+ eDVBCIInterfaces::getInstance()->addPMTHandler(this);
+ if (m_pmt_ready)
+ {
+ eDVBCIInterfaces::getInstance()->recheckPMTHandlers();
+ eDVBCIInterfaces::getInstance()->gotPMT(this);
+ }
+ }
+}
+
+void eDVBServicePMTHandler::removeCaHandler()
+{
+ m_ca_disabled = true;
+ if (m_channel)
+ eDVBCIInterfaces::getInstance()->removePMTHandler(this);
+}
+
+
CAServiceMap eDVBCAService::exist;
ChannelMap eDVBCAService::exist_channels;
ePtr<eConnection> eDVBCAService::m_chanAddedConn;
diff --git a/lib/dvb/pmt.h b/lib/dvb/pmt.h
index b15c95b..b2fc68f 100644
--- a/lib/dvb/pmt.h
+++ b/lib/dvb/pmt.h
@@ -158,6 +158,9 @@ class eDVBServicePMTHandler: public Object
uint8_t m_decode_demux_num;
ePtr<eTimer> m_no_pat_entry_delay;
uint8_t mDemuxId;
+
+ bool m_pmt_ready;
+ bool m_ca_disabled;
public:
eDVBServicePMTHandler();
~eDVBServicePMTHandler();
@@ -254,6 +257,8 @@ public:
int pmtPid;
int textPid;
int aitPid;
+ int pmtVersion;
+ bool isCached;
bool isCrypted() { return !caids.empty(); }
PyObject *createPythonObject();
};
@@ -274,6 +279,7 @@ public:
void getHBBTVUrl(std::string &ret) { ret = m_HBBTVUrl; }
void getDemuxID(int &id) { id = mDemuxId; }
+ void setCaDisable(bool disable) { m_ca_disabled = disable; }
/* deprecated interface */
int tune(eServiceReferenceDVB &ref, int use_decode_demux, eCueSheet *sg=0, bool simulate=false, eDVBService *service = 0);
@@ -282,6 +288,8 @@ public:
int tuneExt(eServiceReferenceDVB &ref, int use_decode_demux, ePtr<iTsSource> &, const char *streaminfo_file, eCueSheet *sg=0, bool simulate=false, eDVBService *service = 0, bool isstreamclient=false);
void free();
+ void addCaHandler();
+ void removeCaHandler();
private:
bool m_have_cached_program;
program m_cached_program;
diff --git a/lib/nav/core.cpp b/lib/nav/core.cpp
index ad77766..2e54d87 100644
--- a/lib/nav/core.cpp
+++ b/lib/nav/core.cpp
@@ -1,6 +1,7 @@
#include <lib/nav/core.h>
#include <lib/base/eerror.h>
#include <lib/python/python.h>
+#include <lib/dvb/fcc.h>
void eNavigation::serviceEvent(iPlayableService* service, int event)
{
@@ -24,10 +25,15 @@ void eNavigation::recordEvent(iRecordableService* service, int event)
RESULT eNavigation::playService(const eServiceReference &service)
{
- stopService();
-
- ASSERT(m_servicehandler);
- RESULT res = m_servicehandler->play(service, m_runningService);
+ RESULT res = -1;
+
+ if (m_fccmgr->tryFCCService(service, m_runningService) == -1)
+ {
+ stopService();
+ ASSERT(m_servicehandler);
+ res = m_servicehandler->play(service, m_runningService);
+ }
+
if (m_runningService)
{
m_runningService->connectEvent(slot(*this, &eNavigation::serviceEvent), m_service_event_conn);
@@ -69,6 +75,8 @@ RESULT eNavigation::stopService(void)
/* kill service. */
m_service_event_conn = 0;
+
+ m_fccmgr->cleanupFCCService();
return 0;
}
@@ -150,6 +158,7 @@ eNavigation::eNavigation(iServiceHandler *serviceHandler)
{
ASSERT(serviceHandler);
m_servicehandler = serviceHandler;
+ m_fccmgr = new eFCCServiceManager(this);
}
eNavigation::~eNavigation()
diff --git a/lib/nav/core.h b/lib/nav/core.h
index 9f7be88..a4906c1 100644
--- a/lib/nav/core.h
+++ b/lib/nav/core.h
@@ -6,6 +6,7 @@
#include <connection.h>
#include <map>
#include <set>
+#include <lib/dvb/fcc.h>
class eNavigation: public iObject, public Object
{
@@ -22,6 +23,10 @@ class eNavigation: public iObject, public Object
Signal2<void,ePtr<iRecordableService>,int> m_record_event;
void recordEvent(iRecordableService* service, int event);
+
+ friend class eFCCServiceManager;
+ ePtr<eFCCServiceManager> m_fccmgr;
+
public:
RESULT playService(const eServiceReference &service);
diff --git a/lib/python/Components/ServiceList.py b/lib/python/Components/ServiceList.py
index 3930c07..6972d91 100644
--- a/lib/python/Components/ServiceList.py
+++ b/lib/python/Components/ServiceList.py
@@ -123,6 +123,9 @@ class ServiceList(HTMLComponent, GUIComponent):
self.l.getNext(r)
return r
+ def getList(self):
+ return self.l.getList()
+
def atBegin(self):
return self.instance.atBegin()
diff --git a/lib/python/Plugins/Plugin.py b/lib/python/Plugins/Plugin.py
index 2137d0e..d19ec26 100755
--- a/lib/python/Plugins/Plugin.py
+++ b/lib/python/Plugins/Plugin.py
@@ -60,11 +60,7 @@ class PluginDescriptor:
# should be provided to name and describe the new menu entry.
WHERE_SOFTWAREMANAGER = 14
- WHERE_SATCONFIGCHANGED = 15
-
- WHERE_SERVICESCAN = 16
-
- WHERE_EXTENSIONSINGLE = 17
+ WHERE_EXTENSIONSINGLE = 15
def __init__(self, name = "Plugin", where = [ ], description = "", icon = None, fnc = None, wakeupfnc = None, needsRestart = None, internal = False, weight = 0):
diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/Makefile.am b/lib/python/Plugins/SystemPlugins/FastChannelChange/Makefile.am
new file mode 100644
index 0000000..ae91ed5
--- /dev/null
+++ b/lib/python/Plugins/SystemPlugins/FastChannelChange/Makefile.am
@@ -0,0 +1,7 @@
+installdir = $(pkglibdir)/python/Plugins/SystemPlugins/FastChannelChange
+
+SUBDIRS = meta
+
+install_PYTHON = \
+ __init__.py \
+ plugin.py
diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/__init__.py b/lib/python/Plugins/SystemPlugins/FastChannelChange/__init__.py
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/lib/python/Plugins/SystemPlugins/FastChannelChange/__init__.py
@@ -0,0 +1,2 @@
+
+
diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/Makefile.am b/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/Makefile.am
new file mode 100644
index 0000000..4e3b9e9
--- /dev/null
+++ b/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/Makefile.am
@@ -0,0 +1,3 @@
+installdir = $(datadir)/meta
+
+dist_install_DATA = plugin_fastchannelchange.xml
diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/plugin_fastchannelchange.xml b/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/plugin_fastchannelchange.xml
new file mode 100644
index 0000000..cf4571a
--- /dev/null
+++ b/lib/python/Plugins/SystemPlugins/FastChannelChange/meta/plugin_fastchannelchange.xml
@@ -0,0 +1,16 @@
+<default>
+ <prerequisites>
+ <tag type="System" />
+ </prerequisites>
+ <info>
+ <author>hschang</author>
+ <name>FastChannelChange</name>
+ <packagename>enigma2-plugin-systemplugins-fastchannelchange</packagename>
+ <shortdescription>Fast Channel Change of your VU+</shortdescription>
+ <description>Fast Channel Change of your VU+</description>
+ </info>
+
+ <files type="package"> <!-- without version, without .ipk -->
+ <file type="package" name="enigma2-plugin-systemplugins-fastchannelchange" />
+ </files>
+</default>
diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py b/lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py
new file mode 100644
index 0000000..7c3b2cc
--- /dev/null
+++ b/lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py
@@ -0,0 +1,589 @@
+
+from Plugins.Plugin import PluginDescriptor
+import NavigationInstance
+
+from Screens.Screen import Screen
+from Screens.InfoBar import InfoBar
+from Screens.MessageBox import MessageBox
+
+from Components.NimManager import nimmanager
+from Components.config import config, getConfigListEntry, ConfigSubsection, ConfigYesNo, ConfigSelection
+from Components.ConfigList import ConfigListScreen
+from Components.ActionMap import ActionMap
+from Components.Sources.StaticText import StaticText
+from Components.ServiceEventTracker import ServiceEventTracker
+
+from enigma import iPlayableService, iServiceInformation, eEnv, eTimer, eServiceReference, iRecordableService
+
+import os
+import glob
+
+from enigma import eFCCServiceManager
+
+g_max_fcc = len(glob.glob('/dev/fcc?'))
+g_default_fcc = (g_max_fcc) > 5 and 5 or g_max_fcc
+
+config.plugins.fccsetup = ConfigSubsection()
+config.plugins.fccsetup.activate = ConfigYesNo(default = False)
+config.plugins.fccsetup.maxfcc = ConfigSelection(default = str(g_default_fcc), choices = list((str(n), str(n)) for n in range(2, g_max_fcc+1)))
+config.plugins.fccsetup.zapupdown = ConfigYesNo(default = True)
+config.plugins.fccsetup.history = ConfigYesNo(default = False)
+config.plugins.fccsetup.priority = ConfigSelection(default = "zapupdown", choices = { "zapupdown" : _("Zap Up/Down"), "historynextback" : _("History Prev/Next") })
+config.plugins.fccsetup.disableforrec = ConfigYesNo(default = True)
+
+FccInstance = None
+
+def FCCChanged():
+ if FccInstance:
+ FccInstance.FCCSetupChanged()
+
+def checkSupportFCC():
+ global g_max_fcc
+ return bool(g_max_fcc)
+
+class FCCSupport:
+ def __init__(self, session):
+ self.session = session
+
+ self.fccmgr = eFCCServiceManager.getInstance();
+
+ self.fccList = []
+
+ self.createListTimer = eTimer()
+ self.createListTimer.callback.append(self.FCCCreateList)
+
+ self.getSrefTimer = eTimer()
+ self.getSrefTimer.callback.append(self.FCCGetCurSref)
+
+ self.eventList = []
+ self.fccEventTimer = eTimer()
+ self.fccEventTimer.callback.append(self.FCCApplyEvent)
+
+ self.fccForceStartTimer = eTimer()
+ self.fccForceStartTimer.callback.append(self.FCCForceStartForREC)
+
+ self.fccResetTimer = eTimer()
+ self.fccResetTimer.callback.append(self.FCCResetTimerForREC)
+
+ self.activating = False
+
+ self.fccSetupActivate = checkSupportFCC() and config.plugins.fccsetup.activate.value
+ self.maxFCC = int(config.plugins.fccsetup.maxfcc.value)
+ self.zapdownEnable = config.plugins.fccsetup.zapupdown.value
+ self.historyEnable = config.plugins.fccsetup.history.value
+ self.priority = config.plugins.fccsetup.priority.value
+ self.disableforrec = config.plugins.fccsetup.disableforrec.value
+ self.fccmgr.setFCCEnable(int(self.fccSetupActivate))
+
+ self.setProcFCC(self.fccSetupActivate)
+ self.fccTimeoutTimer = eTimer()
+ self.fccTimeoutTimer.callback.append(self.FCCTimeout)
+ self.fccTimeoutEventCode = 0x102
+ self.fccTimeoutWait = None
+
+ self.fccmgr.m_fcc_event.get().append(self.FCCGetEvent)
+
+ self.getRecordings()
+
+ self.__event_tracker = None
+ self.onClose = []
+ self.changeEventTracker()
+
+ def setProcFCC(self, value):
+ procPath = "/proc/stb/frontend/fbc/fcc"
+ if os.access(procPath, os.W_OK):
+ fd = open(procPath,'w')
+ fd.write(value and "enable" or "disable")
+ fd.close()
+ else:
+ print "[FCCSupport] write fail! : ", procPath
+
+ def gotRecordEvent(self, service, event):
+ if self.disableforrec:
+ if (not self.recordings) and (event == iRecordableService.evTuneStart):
+ self.getRecordings()
+ if self.recordings:
+ self.FCCForceStopForREC()
+
+ elif event == iRecordableService.evEnd:
+ self.getRecordings()
+ if not self.recordings:
+ self.FCCForceStartForREC()
+ else:
+ if event == iRecordableService.evTuneStart:
+ self.fccResetTimer.stop()
+ self.FCCForceStopForREC()
+ self.fccForceStartTimer.start(2000, True)
+
+ elif event == iRecordableService.evEnd:
+ self.fccForceStartTimer.stop()
+ self.fccResetTimer.start(2000, True)
+
+ def FCCForceStopForREC(self):
+ self.enableEventTracker(False)
+ self.FCCDisableServices()
+ self.FCCStopAllServices()
+
+ def FCCForceStartForREC(self):
+ self.enableEventTracker(True)
+ self.FCCForceStart()
+
+ def FCCResetTimerForREC(self):
+ self.FCCForceStopForREC()
+ self.FCCForceStartForREC()
+
+ def FCCSetupChanged(self):
+ fcc_changed = False
+
+ newFccSetupActivate = checkSupportFCC() and config.plugins.fccsetup.activate.value
+ if self.fccSetupActivate != newFccSetupActivate:
+ self.fccSetupActivate = newFccSetupActivate
+ self.setProcFCC(self.fccSetupActivate)
+ fcc_changed = True
+
+ if int(config.plugins.fccsetup.maxfcc.value) != self.maxFCC:
+ self.maxFCC = int(config.plugins.fccsetup.maxfcc.value)
+ fcc_changed = True
+
+ if self.zapdownEnable != config.plugins.fccsetup.zapupdown.value:
+ self.zapdownEnable = config.plugins.fccsetup.zapupdown.value
+ fcc_changed = True
+
+ if self.historyEnable != config.plugins.fccsetup.history.value:
+ self.historyEnable = config.plugins.fccsetup.history.value
+ fcc_changed = True
+
+ if self.priority != config.plugins.fccsetup.priority.value:
+ self.priority = config.plugins.fccsetup.priority.value
+ fcc_changed = True
+
+ if self.disableforrec != config.plugins.fccsetup.disableforrec.value:
+ self.disableforrec = config.plugins.fccsetup.disableforrec.value
+ fcc_changed = True
+
+ self.getRecordings()
+ self.changeEventTracker()
+
+ if (not self.fccSetupActivate) or (self.disableforrec and self.recordings):
+ self.FCCDisableServices()
+
+ if fcc_changed:
+ self.fccmgr.setFCCEnable(int(self.fccSetupActivate))
+ curPlaying = self.session.nav.getCurrentlyPlayingServiceReference()
+ if curPlaying:
+ self.session.nav.stopService()
+ self.session.nav.playService(curPlaying)
+
+ # get current recording state
+ def getRecordings(self):
+ self.recordings = bool(self.session.nav.getRecordings())
+
+ def addRecordEventCallback(self, enable=True):
+ if enable:
+ if self.gotRecordEvent not in self.session.nav.record_event:
+ self.session.nav.record_event.append(self.gotRecordEvent)
+ else:
+ if self.gotRecordEvent in self.session.nav.record_event:
+ self.session.nav.record_event.remove(self.gotRecordEvent)
+
+ def changeEventTracker(self):
+ if self.fccSetupActivate:
+ self.addRecordEventCallback(True)
+ if self.disableforrec and self.recordings:
+ self.enableEventTracker(False)
+ else:
+ self.enableEventTracker(True)
+ else:
+ self.addRecordEventCallback(False)
+ self.enableEventTracker(False)
+
+ def enableEventTracker(self, activate):
+ if activate:
+ if not self.__event_tracker:
+ self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+ {
+ iPlayableService.evStart: self.getEvStart,
+ iPlayableService.evEnd: self.getEvEnd,
+ iPlayableService.evTunedIn: self.getEvTunedIn,
+ iPlayableService.evTuneFailed: self.getEvTuneFailed
+ })
+
+ elif self.__event_tracker:
+ # run ServiceEventTracker.__del_event()
+ for x in self.onClose:
+ x()
+
+ self.onClose = []
+ self.__event_tracker = None
+
+ def getEvStart(self):
+ self.createListTimer.start(0,True)
+
+ def getEvEnd(self):
+ self.FCCDisableServices()
+
+ def getEvTunedIn(self):
+ self.FCCTryStart()
+
+ def getEvTuneFailed(self):
+ self.FCCTryStart()
+
+ def isPlayableFCC(self, sref):
+ playable = True
+ if isinstance(sref, str):
+ sref = eServiceReference(sref)
+
+ if sref.getPath(): # is PVR? or streaming?
+ playable = False
+
+ if int(sref.getData(0)) in (2, 10): # is RADIO?
+ playable = False
+
+ return playable
+
+ def getZapUpDownList(self):
+ fccZapUpDownList = []
+ serviceList = InfoBar.instance.servicelist.servicelist.getList()
+ curServiceRef = InfoBar.instance.servicelist.servicelist.getCurrent().toString()
+
+ serviceRefList = []
+ for idx in range(len(serviceList)):
+ sref = serviceList[idx].toString()
+ if (sref.split(':')[1] == '0') and self.isPlayableFCC(sref) : # remove marker
+ serviceRefList.append(sref)
+
+ if curServiceRef in serviceRefList:
+ serviceRefListSize = len(serviceRefList)
+ curServiceIndex = serviceRefList.index(curServiceRef)
+
+ for x in range(self.maxFCC-1):
+ if x > (serviceRefListSize-2): # if not ((x+1) <= (serviceRefListSize-1))
+ break
+
+ idx = (x / 2) + 1
+ if x % 2:
+ idx *= -1 # idx : [ 1, -1, 2, -2, 3, -3, 4, -4 ....]
+ idx = (curServiceIndex+idx) % serviceRefListSize # calc wraparound
+ try:
+ fccZapUpDownList.append(serviceRefList[idx])
+ except:
+ print "[FCCCreateList] append error, idx : %d" % idx
+ break
+
+ return fccZapUpDownList
+
+ def getHistoryPrevNextList(self):
+ historyList = []
+ history = InfoBar.instance.servicelist.history[:]
+ history_pos = InfoBar.instance.servicelist.history_pos
+ history_len = len(history)
+
+ if history_len > 1 and history_pos > 0:
+ historyPrev = history[history_pos-1][:][-1].toString()
+ if self.isPlayableFCC(historyPrev):
+ historyList.append(historyPrev)
+
+ if history_len > 1 and history_pos < (history_len-1):
+ historyNext = history[history_pos+1][:][-1].toString()
+ if self.isPlayableFCC(historyNext):
+ historyList.append(historyNext)
+
+ return historyList
+
+ def FCCCreateList(self):
+ if (not self.fccSetupActivate) or (self.disableforrec and self.recordings):
+ return
+
+ if InfoBar.instance:
+ self.fccList = []
+ fccZapUpDownList = []
+ historyList = []
+
+ if self.zapdownEnable:
+ fccZapUpDownList = self.getZapUpDownList()
+
+ if self.historyEnable:
+ historyList = self.getHistoryPrevNextList()
+
+ if self.priority == "zapupdown":
+ fccZapDownLen = len(fccZapUpDownList)
+ if fccZapDownLen:
+ size = fccZapDownLen > 2 and 2 or fccZapDownLen
+ self.fccList = fccZapUpDownList[:size]
+ fccZapUpDownList = fccZapUpDownList[size:]
+
+ self.addFCCList(historyList)
+ self.addFCCList(fccZapUpDownList)
+ else:
+ self.addFCCList(historyList)
+ self.addFCCList(fccZapUpDownList)
+
+ self.FCCReconfigureFccList()
+
+ def addFCCList(self, newlist):
+ fccListMaxLen = self.maxFCC-1
+ for sref in newlist:
+ if len(self.fccList) >= fccListMaxLen:
+ break
+
+ if sref not in self.fccList:
+ self.fccList.append(sref)
+
+ def FCCReconfigureFccList(self):
+ stopFCCList = []
+ currentFCCList = self.fccmgr.getFCCServiceList()
+
+ for (sref, value) in currentFCCList.items():
+ state = value[0]
+
+ if state == 2: # fcc_state_failed
+ stopFCCList.append(sref)
+
+ elif sref in self.fccList: # check conflict FCC channel (decoder/prepare)
+ self.fccList.remove(sref)
+
+ elif state == 0: # fcc_state_preparing
+ stopFCCList.append(sref)
+
+ for sref in stopFCCList:
+ self.fccmgr.stopFCCService(eServiceReference(sref))
+
+ def FCCTryStart(self):
+ self.getSrefTimer.start(0, True)
+
+ def FCCGetCurSref(self):
+ if (not self.fccSetupActivate) or (self.disableforrec and self.recordings):
+ return
+
+ if self.createListTimer.isActive():
+ self.createListTimer.stop()
+ self.FCCCreateList()
+
+ curSref = self.session.nav.getCurrentlyPlayingServiceReference()
+
+ if curSref and self.isPlayableFCC(curSref):
+ self.FCCStart()
+ else:
+ print "[FCCSupport][FCCGetCurSref] get current serviceReference failed!!"
+
+ def FCCStart(self):
+ self.activating = True
+ self.FCCGetEvent(iPlayableService.evTunedIn)
+
+ def FCCGetEvent(self, event):
+ if self.activating and event in (iPlayableService.evTunedIn, iPlayableService.evTuneFailed, iPlayableService.evFccFailed, self.fccTimeoutEventCode):
+ self.eventList.append(event)
+ self.fccEventTimer.start(0, True)
+
+ def FCCApplyEvent(self):
+ if not self.activating:
+ return
+
+ while self.eventList:
+ event = self.eventList.pop(0)
+
+ self.FCCTimeoutTimerStop()
+
+ if event in (iPlayableService.evTuneFailed, iPlayableService.evFccFailed):
+ self.fccmgr.stopFCCService() # stop FCC Services in failed state
+
+ if not self.FCCCheckAndTimerStart() and len(self.fccList):
+ sref = self.fccList.pop(0)
+ if self.isPlayableFCC(sref): # remove PVR, streaming, radio channels
+ self.fccmgr.playFCCService(eServiceReference(sref))
+ self.FCCTimeoutTimerStart(sref)
+
+ def FCCStopAllServices(self):
+ self.FCCTimeoutTimerStop()
+ fccServiceList = self.fccmgr.getFCCServiceList()
+ for (sref, value) in fccServiceList.items():
+ state = value[0]
+ if state != 1 : # 1 : fcc_state_decoding
+ self.fccmgr.stopFCCService(eServiceReference(sref))
+
+ def FCCDisableServices(self):
+ self.FCCTimeoutTimerStop()
+ self.getSrefTimer.stop()
+ self.activating = False
+ self.fccList = []
+
+ self.fccEventTimer.stop()
+ self.fccmgr.stopFCCService()
+ self.eventList = []
+
+ def FCCForceStart(self):
+ self.getEvStart()
+ self.getEvTunedIn()
+
+ def FCCCheckNoLocked(self):
+ for (sref, value) in self.fccmgr.getFCCServiceList().items():
+ state = value[0]
+ locked = value[1]
+ if state != 1 and locked == 0: # no fcc decoding and no locked
+ return sref
+ return None
+
+ def FCCTimeout(self):
+ sref = self.FCCCheckNoLocked()
+ if sref and sref == self.fccTimeoutWait:
+ self.fccmgr.stopFCCService(eServiceReference(sref))
+ self.FCCGetEvent(self.fccTimeoutEventCode)
+
+ def FCCCheckAndTimerStart(self):
+ sref = self.FCCCheckNoLocked()
+ if sref:
+ self.FCCTimeoutTimerStart(sref)
+ return True
+ return False
+
+ def FCCTimeoutTimerStart(self, sref):
+ self.fccTimeoutWait = sref
+ self.fccTimeoutTimer.start(5000, True)
+
+ def FCCTimeoutTimerStop(self):
+ self.fccTimeoutWait = None
+ self.fccTimeoutTimer.stop()
+
+class FCCSetup(Screen, ConfigListScreen):
+ skin = """
+ <screen position="center,center" size="590,320" >
+ <ePixmap pixmap="skin_default/buttons/red.png" position="90,15" size="140,40" alphatest="on" />
+ <ePixmap pixmap="skin_default/buttons/green.png" position="360,15" size="140,40" alphatest="on" />
+ <widget source="key_red" render="Label" position="90,15" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" foregroundColor="#ffffff" transparent="1" />
+ <widget source="key_green" render="Label" position="360,15" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" foregroundColor="#ffffff" transparent="1" />
+ <widget name="config" zPosition="2" position="15,80" size="560,140" scrollbarMode="showOnDemand" transparent="1" />
+ <widget source="description" render="Label" position="30,240" size="530,60" font="Regular;24" halign="center" valign="center" />
+ </screen>
+ """
+
+ def __init__(self,session):
+ Screen.__init__(self,session)
+ self.title = _("Fast Channel Change Setup")
+ self.session = session
+ self["shortcuts"] = ActionMap(["ShortcutActions", "SetupActions" ],
+ {
+ "ok": self.keySave,
+ "cancel": self.keyCancel,
+ "red": self.keyCancel,
+ "green": self.keySave,
+ }, -2)
+ self.list = []
+ ConfigListScreen.__init__(self, self.list,session = self.session)
+ self["key_red"] = StaticText(_("Cancel"))
+ self["key_green"] = StaticText(_("Save"))
+
+ self.isSupport = checkSupportFCC()
+
+ if self.isSupport:
+ self["description"] = StaticText("")
+ self.createConfig()
+ self.createSetup()
+ else:
+ self["description"] = StaticText(_("Box or driver is not support FCC."))
+
+ def createConfig(self):
+ self.enableEntry = getConfigListEntry(_("FCC enabled"), config.plugins.fccsetup.activate)
+ self.fccmaxEntry = getConfigListEntry(_("Max Channels"), config.plugins.fccsetup.maxfcc)
+ self.zapupdownEntry = getConfigListEntry(_("Zap Up/Down"), config.plugins.fccsetup.zapupdown)
+ self.historyEntry = getConfigListEntry(_("History Prev/Next"), config.plugins.fccsetup.history)
+ self.priorityEntry = getConfigListEntry(_("priority"), config.plugins.fccsetup.priority)
+ self.recEntry = getConfigListEntry(_("Disable FCC during recordings"), config.plugins.fccsetup.disableforrec)
+
+ def createSetup(self):
+ self.list = []
+ self.list.append( self.enableEntry )
+ if self.enableEntry[1].value:
+ self.list.append( self.fccmaxEntry )
+ self.list.append( self.zapupdownEntry )
+ self.list.append( self.historyEntry )
+ if self.zapupdownEntry[1].value and self.historyEntry[1].value:
+ self.list.append( self.priorityEntry )
+ self.list.append(self.recEntry)
+
+ self["config"].list = self.list
+ self["config"].l.setList(self.list)
+
+ def keyLeft(self):
+ ConfigListScreen.keyLeft(self)
+ self.setupChanged()
+
+ def keyRight(self):
+ ConfigListScreen.keyRight(self)
+ self.setupChanged()
+
+ def setupChanged(self):
+ currentEntry = self["config"].getCurrent()
+ if currentEntry in (self.zapupdownEntry, self.historyEntry, self.enableEntry):
+ if not (self.zapupdownEntry[1].value or self.historyEntry[1].value):
+ if currentEntry == self.historyEntry:
+ self.zapupdownEntry[1].value = True
+ else:
+ self.historyEntry[1].value = True
+ elif self.zapupdownEntry[1].value and self.historyEntry[1].value:
+ if int(self.fccmaxEntry[1].value) < 5:
+ if g_max_fcc < 5:
+ self.fccmaxEntry[1].value = str(g_max_fcc)
+ else:
+ self.fccmaxEntry[1].value = str(5)
+
+ self.createSetup()
+
+ def keySave(self):
+ if not self.isSupport:
+ self.keyCancel()
+ return
+
+ ConfigListScreen.keySave(self)
+ FCCChanged()
+
+def getExtensionName():
+ if config.plugins.fccsetup.activate.value:
+ return _("Disable FastChannelChange")
+
+ return _("Enable FastChannelChange")
+
+def ToggleUpdate():
+ if config.plugins.fccsetup.activate.value:
+ config.plugins.fccsetup.activate.value = False
+ else:
+ config.plugins.fccsetup.activate.value = True
+ config.plugins.fccsetup.activate.save()
+ FCCChanged()
+
+def FCCSupportInit(reason, **kwargs):
+ if kwargs.has_key("session"):
+ global FccInstance
+ FccInstance = FCCSupport(kwargs["session"])
+
+def addExtentions(infobarExtensions):
+ infobarExtensions.addExtension((getExtensionName, ToggleUpdate, lambda: True), None)
+
+def main(session, **kwargs):
+ session.open(FCCSetup)
+
+def Plugins(**kwargs):
+ list = []
+
+ global g_max_fcc
+ if g_max_fcc:
+ list.append(
+ PluginDescriptor(name="FCCSupport",
+ description="Fast Channel Change Support",
+ where = [PluginDescriptor.WHERE_SESSIONSTART],
+ fnc = FCCSupportInit))
+
+ list.append(
+ PluginDescriptor(name="FCCExtensionMenu",
+ description="Fast Channel Change Extension Menu",
+ where = [PluginDescriptor.WHERE_EXTENSIONSINGLE],
+ fnc = addExtentions))
+
+ list.append(
+ PluginDescriptor(name=_("FCCSetup"),
+ description=_("Fast Channel Change Setup"),
+ where = [PluginDescriptor.WHERE_PLUGINMENU],
+ needsRestart = False,
+ fnc = main))
+
+ return list
+
diff --git a/lib/python/Plugins/SystemPlugins/Makefile.am b/lib/python/Plugins/SystemPlugins/Makefile.am
index 3a16f5f..950b50e 100755
--- a/lib/python/Plugins/SystemPlugins/Makefile.am
+++ b/lib/python/Plugins/SystemPlugins/Makefile.am
@@ -8,7 +8,7 @@ SUBDIRS = SoftwareManager FrontprocessorUpgrade PositionerSetup Satfinder \
Blindscan RemoteControlCode UI3DSetup UIPositionSetup HDMICEC LEDBrightnessSetup \
FirmwareUpgrade CrashReport 3GModemManager WirelessAccessPoint ZappingModeSelection \
DeviceManager TransCodingSetup WOLSetup NetDrive AudioEffect AnimationSetup \
- BoxModeConfig Solo4kMiscControl
+ BoxModeConfig Solo4kMiscControl FastChannelChange
install_PYTHON = \
__init__.py
diff --git a/lib/python/Screens/Satconfig.py b/lib/python/Screens/Satconfig.py
index 48b580c..3b75e46 100644
--- a/lib/python/Screens/Satconfig.py
+++ b/lib/python/Screens/Satconfig.py
@@ -544,9 +544,6 @@ class NimSetup(Screen, ConfigListScreen, ServiceStopScreen):
self.nimConfig.connectedTo.setChoices(choices)
for x in self["config"].list:
x[1].save()
-
- for p in plugins.getPlugins(PluginDescriptor.WHERE_SATCONFIGCHANGED):
- p()
def cancelConfirm(self, result):
if not result:
diff --git a/lib/python/Screens/ServiceScan.py b/lib/python/Screens/ServiceScan.py
index efa218b..d333230 100644
--- a/lib/python/Screens/ServiceScan.py
+++ b/lib/python/Screens/ServiceScan.py
@@ -62,11 +62,6 @@ class ServiceScan(Screen):
})
self.onFirstExecBegin.append(self.doServiceScan)
- self.onClose.append(self.doPluginCB)
-
- def doPluginCB(self):
- for p in plugins.getPlugins(PluginDescriptor.WHERE_SERVICESCAN):
- p()
def doServiceScan(self):
self["scan"] = CScan(self["scan_progress"], self["scan_state"], self["servicelist"], self["pass"], self.scanList, self["network"], self["transponder"], self["FrontendInfo"], self.session.summary)
diff --git a/lib/python/enigma_python.i b/lib/python/enigma_python.i
index 6a25592..158c986 100755
--- a/lib/python/enigma_python.i
+++ b/lib/python/enigma_python.i
@@ -100,6 +100,7 @@ is usually caused by not marking PSignals as immutable.
#include <lib/dvb_ci/dvbci_ui.h>
#include <lib/python/python.h>
#include <lib/gdi/picload.h>
+#include <lib/dvb/fcc.h>
%}
%feature("ref") iObject "$this->AddRef(); /* eDebug(\"AddRef (%s:%d)!\", __FILE__, __LINE__); */ "
@@ -163,6 +164,7 @@ typedef long time_t;
%immutable eHdmiCEC::messageReceivedKey;
%immutable ePythonMessagePump::recv_msg;
%immutable eDVBLocalTimeHandler::m_timeUpdated;
+%immutable eFCCServiceManager::m_fcc_event;
%include <lib/base/message.h>
%include <lib/base/etpm.h>
%include <lib/base/nconfig.h>
@@ -221,6 +223,7 @@ typedef long time_t;
%include <lib/dvb/db.h>
%include <lib/python/python.h>
%include <lib/gdi/picload.h>
+%include <lib/dvb/fcc.h>
/************** eptr **************/
/************** signals **************/
@@ -344,6 +347,15 @@ int getLinkedSlotID(int fe)
}
%}
+void setFCCEnable(int);
+%{
+void setFCCEnable(int enable)
+{
+ eFCCServiceManager *fcc_mng = eFCCServiceManager::getInstance();
+ if (fcc_mng) setFCCEnable(enable);
+}
+%}
+
/************** temp *****************/
/* need a better place for this, i agree. */
diff --git a/lib/service/Makefile.am b/lib/service/Makefile.am
index 9f956b6..2df1dd9 100644
--- a/lib/service/Makefile.am
+++ b/lib/service/Makefile.am
@@ -15,6 +15,7 @@ libenigma_service_a_SOURCES = \
service.cpp \
servicedvb.cpp \
servicedvbrecord.cpp \
+ servicedvbfcc.cpp \
servicefs.cpp \
servicemp3.cpp \
servicem2ts.cpp
@@ -27,6 +28,7 @@ serviceinclude_HEADERS = \
service.h \
servicedvb.h \
servicedvbrecord.h \
+ servicedvbfcc.h \
servicefs.h \
servicemp3.h \
servicem2ts.h
diff --git a/lib/service/iservice.h b/lib/service/iservice.h
index 7099d7d..f0be087 100644
--- a/lib/service/iservice.h
+++ b/lib/service/iservice.h
@@ -841,6 +841,8 @@ public:
evStopped,
evHBBTVInfo,
+ evFccFailed,
+
evUser = 0x100
};
};
@@ -896,7 +898,8 @@ public:
evNewProgramInfo,
evRecordFailed,
evRecordWriteError,
- evNewEventInfo
+ evNewEventInfo,
+ evTuneStart,
};
enum {
NoError=0,
diff --git a/lib/service/listboxservice.cpp b/lib/service/listboxservice.cpp
index cd65f35..7944503 100644
--- a/lib/service/listboxservice.cpp
+++ b/lib/service/listboxservice.cpp
@@ -130,6 +130,17 @@ void eListboxServiceContent::getNext(eServiceReference &ref)
ref = eServiceReference();
}
+PyObject *eListboxServiceContent::getList()
+{
+ ePyObject result = PyList_New(m_list.size());
+ int pos=0;
+ for (list::iterator it(m_list.begin()); it != m_list.end(); ++it)
+ {
+ PyList_SET_ITEM(result, pos++, NEW_eServiceReference(*it));
+ }
+ return result;
+}
+
int eListboxServiceContent::getNextBeginningWithChar(char c)
{
// printf("Char: %c\n", c);
diff --git a/lib/service/listboxservice.h b/lib/service/listboxservice.h
index ab5bd20..ee28c49 100644
--- a/lib/service/listboxservice.h
+++ b/lib/service/listboxservice.h
@@ -21,6 +21,7 @@ public:
void getCurrent(eServiceReference &ref);
void getPrev(eServiceReference &ref);
void getNext(eServiceReference &ref);
+ PyObject *getList();
int getNextBeginningWithChar(char c);
int getPrevMarkerPos();
diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp
index 3f580fe..c3abb81 100755
--- a/lib/service/servicedvb.cpp
+++ b/lib/service/servicedvb.cpp
@@ -19,6 +19,8 @@
#include <lib/base/nconfig.h> // access to python config
#include <lib/base/httpstream.h>
+#include <lib/service/servicedvbfcc.h>
+
/* for subtitles */
#include <lib/gui/esubtitle.h>
@@ -28,6 +30,8 @@
#include <byteswap.h>
#include <netinet/in.h>
+#include <lib/dvb/fcc.h>
+
#ifndef BYTE_ORDER
#error no byte order defined!
#endif
@@ -814,11 +818,15 @@ RESULT eDVBServiceList::setListName(const std::string &name)
RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
{
ePtr<eDVBService> service;
+
int r = lookupService(service, ref);
if (r)
service = 0;
// check resources...
- ptr = new eDVBServicePlay(ref, service);
+ if (eFCCServiceManager::checkAvailable(ref))
+ ptr = new eDVBServiceFCCPlay(ref, service);
+ else
+ ptr = new eDVBServicePlay(ref, service);
return 0;
}
@@ -933,17 +941,19 @@ RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServ
return 0;
}
-eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
+eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service, bool connect_event):
m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
{
m_is_primary = 1;
m_is_stream = m_reference.path.substr(0, 7) == "http://";
m_is_pvr = (!m_reference.path.empty() && !m_is_stream);
-
+
m_timeshift_enabled = m_timeshift_active = 0, m_timeshift_changed = 0;
m_skipmode = m_fastforward = m_slowmotion = 0;
-
- CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
+
+ if (connect_event)
+ CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
+
CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
diff --git a/lib/service/servicedvb.h b/lib/service/servicedvb.h
index 6971545..7ded16a 100644
--- a/lib/service/servicedvb.h
+++ b/lib/service/servicedvb.h
@@ -202,7 +202,7 @@ protected:
int m_current_audio_pid;
int m_current_video_pid_type;
- eDVBServicePlay(const eServiceReference &ref, eDVBService *service);
+ eDVBServicePlay(const eServiceReference &ref, eDVBService *service, bool connect_event=true);
/* events */
void gotNewEvent();
@@ -230,7 +230,7 @@ protected:
std::set<int> m_pids_active;
void updateTimeshiftPids();
- void switchToLive();
+ virtual void switchToLive();
void resetTimeshift(int start);
void switchToTimeshift();
diff --git a/lib/service/servicedvbfcc.cpp b/lib/service/servicedvbfcc.cpp
new file mode 100644
index 0000000..610ccc4
--- /dev/null
+++ b/lib/service/servicedvbfcc.cpp
@@ -0,0 +1,446 @@
+#include <lib/service/servicedvbfcc.h>
+#include <lib/components/file_eraser.h>
+#include <lib/dvb/decoder.h>
+#include <lib/base/nconfig.h>
+
+eDVBServiceFCCPlay::eDVBServiceFCCPlay(const eServiceReference &ref, eDVBService *service)
+ :eDVBServicePlay(ref, service, false), m_fcc_flag(0), m_fcc_mode(fcc_mode_preparing), m_fcc_mustplay(false),
+ m_pmtVersion(-1)
+{
+ CONNECT(m_service_handler.serviceEvent, eDVBServiceFCCPlay::serviceEvent);
+}
+
+eDVBServiceFCCPlay::~eDVBServiceFCCPlay()
+{
+}
+
+void eDVBServiceFCCPlay::serviceEvent(int event)
+{
+ if (!m_is_primary) // PIP mode
+ {
+ eDVBServicePlay::serviceEvent(event);
+ return;
+ }
+
+ m_tune_state = event;
+
+ switch (event)
+ {
+ case eDVBServicePMTHandler::eventTuned:
+ {
+ eDVBServicePlay::serviceEvent(event);
+ pushbackFCCEvents(evTunedIn);
+ break;
+ }
+ case eDVBServicePMTHandler::eventNoResources:
+ case eDVBServicePMTHandler::eventNoPAT:
+ case eDVBServicePMTHandler::eventNoPATEntry:
+ case eDVBServicePMTHandler::eventNoPMT:
+ case eDVBServicePMTHandler::eventTuneFailed:
+ case eDVBServicePMTHandler::eventMisconfiguration:
+ {
+ eDVBServicePlay::serviceEvent(event);
+ pushbackFCCEvents(evTuneFailed);
+ break;
+ }
+ case eDVBServicePMTHandler::eventNewProgramInfo:
+ {
+ eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
+ if (m_timeshift_enabled)
+ updateTimeshiftPids();
+
+ if (!m_timeshift_active)
+ processNewProgramInfo();
+
+ if (!m_timeshift_active)
+ {
+ m_event((iPlayableService*)this, evUpdatedInfo);
+ pushbackFCCEvents(evUpdatedInfo);
+ }
+ break;
+ }
+ case eDVBServicePMTHandler::eventPreStart:
+ case eDVBServicePMTHandler::eventEOF:
+ case eDVBServicePMTHandler::eventSOF:
+ {
+ eDVBServicePlay::serviceEvent(event);
+ break;
+ }
+ case eDVBServicePMTHandler::eventHBBTVInfo:
+ {
+ eDVBServicePlay::serviceEvent(event);
+ pushbackFCCEvents(evHBBTVInfo);
+ break;
+ }
+ }
+}
+
+RESULT eDVBServiceFCCPlay::start()
+{
+ if (!m_is_primary) // PIP mode
+ {
+ eDVBServicePlay::start();
+ return 0;
+ }
+
+ if (m_fcc_flag & fcc_start) // already started
+ {
+ changeFCCMode();
+ }
+ else
+ {
+ m_fcc_flag |= fcc_start;
+ pushbackFCCEvents(evStart);
+
+ /* disable CA Interfaces on fcc_mode_preparing */
+ m_service_handler.setCaDisable(true);
+ eDVBServicePlay::start();
+ }
+ return 0;
+}
+
+void eDVBServiceFCCPlay::pushbackFCCEvents(int event)
+{
+ if (event == evTuneFailed)
+ m_fcc_flag |= fcc_tune_failed;
+ m_fcc_events.push_back(event);
+}
+
+void eDVBServiceFCCPlay::popFCCEvents()
+{
+ m_fcc_events.unique(); // remove duplicate evUpdatedInfo
+ for (std::list<int>::iterator it = m_fcc_events.begin(); it != m_fcc_events.end(); ++it)
+ {
+ if (*it == evUpdatedInfo)
+ {
+ updateFCCDecoder();
+ break;
+ }
+ }
+
+ /* add CaHandler */
+ m_service_handler.addCaHandler();
+
+ /* send events */
+ for (std::list<int>::iterator it = m_fcc_events.begin(); it != m_fcc_events.end(); ++it)
+ {
+ int event = *it;
+// eDebug("[eDVBServiceFCCPlay::popFCCEvents][%s] send event : %s", m_reference.toString().c_str(), eventDesc[event]);
+ m_event((iPlayableService*)this, event);
+ }
+}
+
+void eDVBServiceFCCPlay::changeFCCMode()
+{
+ if (m_fcc_mode == fcc_mode_decoding)
+ {
+ eDebug("[eDVBServiceFCCPlay::changeFCCMode][%s] disable FCC decoding.", m_reference.toString().c_str());
+ m_fcc_mode = fcc_mode_preparing;
+
+ /* remove CaHandler */
+ m_service_handler.removeCaHandler();
+
+ if (m_fcc_flag & fcc_tune_failed)
+ m_event((iPlayableService*)this, evTuneFailed);
+
+ else if (m_fcc_flag & fcc_failed)
+ m_event((iPlayableService*)this, evFccFailed);
+
+ FCCDecoderStop();
+ }
+ else
+ {
+ eDebug("[eDVBServiceFCCPlay::changeFCCMode][%s] enable FCC decoding.", m_reference.toString().c_str());
+ m_fcc_mode = fcc_mode_decoding;
+ popFCCEvents();
+ }
+}
+
+void eDVBServiceFCCPlay::processNewProgramInfo(bool toLive)
+{
+ updateFCCDecoder(toLive);
+
+ if (m_fcc_flag & fcc_failed)
+ {
+ m_event((iPlayableService*)this, evFccFailed);
+ }
+}
+
+void eDVBServiceFCCPlay::updateFCCDecoder(bool sendSeekableStateChanged)
+{
+ eDebug("[eDVBServiceFCCPlay::updateFCCDecoder][%s]", m_reference.toString().c_str());
+ int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
+ bool isProgramInfoCached = false;
+ bool pmtVersionChanged = false;
+
+ eDVBServicePMTHandler &h = m_service_handler;
+
+ eDVBServicePMTHandler::program program;
+ if (h.getProgramInfo(program))
+ eDebug("getting program info failed.");
+ else
+ {
+ eDebugNoNewLine("have %zd video stream(s)", program.videoStreams.size());
+ if (!program.videoStreams.empty())
+ {
+ eDebugNoNewLine(" (");
+ for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
+ i(program.videoStreams.begin());
+ i != program.videoStreams.end(); ++i)
+ {
+ if (vpid == -1)
+ {
+ vpid = i->pid;
+ vpidtype = i->type;
+ }
+ if (i != program.videoStreams.begin())
+ eDebugNoNewLine(", ");
+ eDebugNoNewLine("%04x", i->pid);
+ }
+ eDebugNoNewLine(")");
+ }
+ eDebugNoNewLine(", and %zd audio stream(s)", program.audioStreams.size());
+ if (!program.audioStreams.empty())
+ {
+ eDebugNoNewLine(" (");
+ for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
+ i(program.audioStreams.begin());
+ i != program.audioStreams.end(); ++i)
+ {
+ if (i != program.audioStreams.begin())
+ eDebugNoNewLine(", ");
+ eDebugNoNewLine("%04x", i->pid);
+ }
+ eDebugNoNewLine(")");
+ }
+ eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
+ pcrpid = program.pcrPid;
+ eDebugNoNewLine(", and the text pid is %04x", program.textPid);
+ tpid = program.textPid;
+ eDebug(" %s", program.isCached ? "(Cached)":"");
+ isProgramInfoCached = program.isCached;
+ if (m_pmtVersion != program.pmtVersion)
+ {
+ if (m_pmtVersion != -1)
+ pmtVersionChanged = true;
+ m_pmtVersion = program.pmtVersion;
+ //eDebug("[eDVBServiceFCCPlay::updateFCCDecoder] pmt version : %d", m_pmtVersion);
+ }
+ }
+
+ if (!m_decoder)
+ {
+ h.getDecodeDemux(m_decode_demux);
+ if (m_decode_demux)
+ {
+ m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
+ if (m_decoder)
+ m_decoder->connectVideoEvent(slot(*this, &eDVBServiceFCCPlay::video_event), m_video_event_connection);
+ }
+ m_fcc_mustplay = true;
+ }
+
+ if (m_decoder)
+ {
+ if (!((m_fcc_flag & fcc_ready)||(m_fcc_flag & fcc_novideo)))
+ {
+ if (vpid == -1)
+ {
+ if (!isProgramInfoCached)
+ m_fcc_flag |= fcc_novideo;
+ }
+ else if ((vpidtype == -1) || (pcrpid== -1))
+ {
+ if (!isProgramInfoCached)
+ m_fcc_flag |= fcc_failed;
+ }
+ else if (!m_decoder->prepareFCC(m_decode_demux->getSource(), vpid, vpidtype, pcrpid))
+ m_fcc_flag |= fcc_ready;
+ else
+ m_fcc_flag |= fcc_failed;
+ }
+ else if (pmtVersionChanged)
+ {
+ m_decoder->fccUpdatePids(m_decode_demux->getSource(), vpid, vpidtype, pcrpid);
+ m_fcc_flag &=~fcc_decoding;
+ }
+ }
+
+ if (m_fcc_mode != fcc_mode_decoding)
+ return;
+
+ /* fcc_mode_decoding */
+ if (!(m_fcc_flag & fcc_ready) && !(m_fcc_flag & fcc_novideo))
+ {
+ eDebug("[eDVBServiceFCCPlay::updateFCCDecoder] fcc is not ready.");
+ return;
+ }
+
+ if (m_decode_demux)
+ {
+ if (m_is_primary)
+ {
+ m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
+ m_teletext_parser->connectNewPage(slot(*this, &eDVBServiceFCCPlay::newSubtitlePage), m_new_subtitle_page_connection);
+ m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
+ m_subtitle_parser->connectNewPage(slot(*this, &eDVBServiceFCCPlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
+ if (m_timeshift_changed)
+ {
+ ePyObject subs = getCachedSubtitle();
+ if (subs != Py_None)
+ {
+ int type = PyInt_AsLong(PyTuple_GET_ITEM(subs, 0)),
+ pid = PyInt_AsLong(PyTuple_GET_ITEM(subs, 1)),
+ comp_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 2)), // ttx page
+ anc_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 3)); // ttx magazine
+ if (type == 0) // dvb
+ m_subtitle_parser->start(pid, comp_page, anc_page);
+ else if (type == 1) // ttx
+ m_teletext_parser->setPageAndMagazine(comp_page, anc_page);
+ }
+ Py_DECREF(subs);
+ }
+ }
+ }
+
+ m_timeshift_changed = 0;
+
+ if (m_decoder)
+ {
+ bool wasSeekable = m_decoder->getVideoProgressive() != -1;
+
+ if (m_dvb_service)
+ {
+ achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
+ ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
+ pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
+ }
+ else // subservice
+ {
+ eServiceReferenceDVB ref;
+ m_service_handler.getServiceReference(ref);
+ eServiceReferenceDVB parent = ref.getParentServiceReference();
+ if (!parent)
+ parent = ref;
+ if (parent)
+ {
+ ePtr<eDVBResourceManager> res_mgr;
+ if (!eDVBResourceManager::getInstance(res_mgr))
+ {
+ ePtr<iDVBChannelList> db;
+ if (!res_mgr->getChannelList(db))
+ {
+ ePtr<eDVBService> origService;
+ if (!db->getService(parent, origService))
+ {
+ ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
+ pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
+ }
+ }
+ }
+ }
+ }
+
+ setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
+ setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
+
+ m_decoder->setVideoPID(vpid, vpidtype);
+ selectAudioStream();
+
+ if (!(m_is_pvr || m_is_stream || m_timeshift_active))
+ m_decoder->setSyncPCR(pcrpid);
+ else
+ m_decoder->setSyncPCR(-1);
+
+ if (m_is_primary)
+ {
+ m_decoder->setTextPID(tpid);
+ m_teletext_parser->start(program.textPid);
+ }
+
+ if (vpid > 0 && vpid < 0x2000)
+ ;
+ else
+ {
+ std::string radio_pic;
+ if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
+ m_decoder->setRadioPic(radio_pic);
+ }
+
+ /* fcc stop and decoder start */
+ if (!(m_fcc_flag & fcc_novideo))
+ {
+ if (m_fcc_flag & fcc_decoding)
+ ;
+ else if(!m_decoder->fccDecoderStart())
+ m_fcc_flag |= fcc_decoding;
+ }
+
+ if (m_fcc_mustplay)
+ {
+ m_fcc_mustplay = false;
+ m_decoder->play();
+ }
+ else
+ {
+ m_decoder->set();
+ }
+
+ m_decoder->setAudioChannel(achannel);
+
+ /* don't worry about non-existing services, nor pvr services */
+ if (m_dvb_service)
+ {
+ /* (audio pid will be set in selectAudioTrack */
+ m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
+ m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
+ m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
+ m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
+ }
+ if (!sendSeekableStateChanged && (m_decoder->getVideoProgressive() != -1) != wasSeekable)
+ sendSeekableStateChanged = true;
+ }
+ m_have_video_pid = (vpid > 0 && vpid < 0x2000);
+
+ if (sendSeekableStateChanged)
+ m_event((iPlayableService*)this, evSeekableStatusChanged);
+}
+
+void eDVBServiceFCCPlay::FCCDecoderStop()
+{
+ eDebug("[eDVBServiceFCCPlay::FCCDecoderStop][%s]", m_reference.toString().c_str());
+
+ if ((m_fcc_flag & fcc_ready) && m_decoder)
+ {
+ m_teletext_parser = 0;
+ m_new_subtitle_page_connection = 0;
+ m_subtitle_parser = 0;
+ m_new_dvb_subtitle_page_connection = 0;
+
+ m_decoder->fccDecoderStop();
+ m_fcc_flag &=~fcc_decoding;
+ }
+}
+
+void eDVBServiceFCCPlay::switchToLive()
+{
+ if (!m_timeshift_active)
+ return;
+
+ eDebug("eDVBServiceFCCPlay::SwitchToLive");
+
+ resetTimeshift(0);
+
+ m_is_paused = m_skipmode = m_fastforward = m_slowmotion = 0; /* not supported in live mode */
+
+ /* free the timeshift service handler, we need the resources */
+ m_service_handler_timeshift.free();
+
+ //updateDecoder(true);
+ m_fcc_flag &=~fcc_ready;
+ m_fcc_flag &=~fcc_decoding;
+ processNewProgramInfo(true);
+}
+
+DEFINE_REF(eDVBServiceFCCPlay)
+
diff --git a/lib/service/servicedvbfcc.h b/lib/service/servicedvbfcc.h
new file mode 100644
index 0000000..54a0dca
--- /dev/null
+++ b/lib/service/servicedvbfcc.h
@@ -0,0 +1,47 @@
+#ifndef __servicedvbfcc_h
+#define __servicedvbfcc_h
+
+#include <lib/service/servicedvb.h>
+#include <list>
+
+class eDVBServiceFCCPlay: public eDVBServicePlay
+{
+ DECLARE_REF(eDVBServiceFCCPlay);
+public:
+ eDVBServiceFCCPlay(const eServiceReference &ref, eDVBService *service);
+ virtual ~eDVBServiceFCCPlay();
+ void serviceEvent(int event);
+ RESULT start();
+protected:
+ void pushbackFCCEvents(int event);
+ void popFCCEvents();
+ void changeFCCMode();
+ void processNewProgramInfo(bool toLive=false);
+ void updateFCCDecoder(bool sendSeekableStateChanged=false);
+ void FCCDecoderStop();
+ void switchToLive();
+
+ bool m_fcc_enable;
+
+ enum {
+ fcc_start = 1,
+ fcc_tune_failed = 2,
+ fcc_failed = 4,
+ fcc_ready = 8,
+ fcc_decoding = 16,
+ fcc_novideo = 32,
+ };
+ int m_fcc_flag;
+
+ enum {
+ fcc_mode_preparing,
+ fcc_mode_decoding
+ };
+ int m_fcc_mode;
+
+ bool m_fcc_mustplay;
+ std::list<int> m_fcc_events;
+ int m_pmtVersion;
+};
+
+#endif /* __servicedvbfcc_h */ \ No newline at end of file
diff --git a/lib/service/servicedvbrecord.cpp b/lib/service/servicedvbrecord.cpp
index dc1b22e..4af0320 100644
--- a/lib/service/servicedvbrecord.cpp
+++ b/lib/service/servicedvbrecord.cpp
@@ -255,6 +255,10 @@ int eDVBServiceRecord::doPrepare()
source = ePtr<iTsSource>(f);
}
}
+ else
+ {
+ m_event((iRecordableService*)this, evTuneStart);
+ }
return m_service_handler.tuneExt(m_ref, 0, source, m_ref.path.c_str(), 0, m_simulate, 0, isstreamclient);
}
return 0;