update dvbapp.
authorhschang <chang@dev3>
Thu, 15 Oct 2015 07:56:10 +0000 (16:56 +0900)
committerhschang <chang@dev3>
Mon, 19 Oct 2015 09:38:38 +0000 (18:38 +0900)
  - support FBC Tuner.
  - Add MiniTV, BoxModeConfig, FastZapSupport.
  - Fix wrong nim config when multi tuner changed.
  - Update harddisk, devicemanager.
  - Support gstreamer 1.X.
  - Support HEVC.
  - Support 2160P. (videomode)

59 files changed:
configure.ac
data/startwizard.xml
lib/base/eptrlist.h
lib/dvb/Makefile.am
lib/dvb/decoder.cpp
lib/dvb/decoder.h
lib/dvb/dvb.cpp
lib/dvb/dvb.h
lib/dvb/fbc.cpp [new file with mode: 0644]
lib/dvb/fbc.h [new file with mode: 0644]
lib/dvb/frontend.cpp
lib/dvb/frontend.h
lib/dvb/pmt.cpp
lib/dvb/pmt.h
lib/dvb/scan.cpp
lib/dvb/sec.cpp
lib/dvb/sec.h
lib/gdi/epng.cpp
lib/gdi/picload.cpp
lib/python/Components/Harddisk.py
lib/python/Components/NimManager.py
lib/python/Components/ServiceList.py
lib/python/Plugins/Extensions/DLNAServer/Makefile.am
lib/python/Plugins/Extensions/DLNAServer/dlnaserver [deleted file]
lib/python/Plugins/Extensions/Makefile.am
lib/python/Plugins/Extensions/MiniTV/Makefile.am [new file with mode: 0644]
lib/python/Plugins/Extensions/MiniTV/__init__.py [new file with mode: 0644]
lib/python/Plugins/Extensions/MiniTV/meta/Makefile.am [new file with mode: 0644]
lib/python/Plugins/Extensions/MiniTV/meta/plugin_minitv.xml [new file with mode: 0644]
lib/python/Plugins/Extensions/MiniTV/plugin.py [new file with mode: 0644]
lib/python/Plugins/Plugin.py
lib/python/Plugins/SystemPlugins/3GModemManager/3gcommand [deleted file]
lib/python/Plugins/SystemPlugins/3GModemManager/Makefile.am
lib/python/Plugins/SystemPlugins/Blindscan/plugin.py
lib/python/Plugins/SystemPlugins/BoxModeConfig/Makefile.am [new file with mode: 0755]
lib/python/Plugins/SystemPlugins/BoxModeConfig/__init__.py [new file with mode: 0755]
lib/python/Plugins/SystemPlugins/BoxModeConfig/meta/Makefile.am [new file with mode: 0755]
lib/python/Plugins/SystemPlugins/BoxModeConfig/meta/plugin_boxmodeconfig.xml [new file with mode: 0755]
lib/python/Plugins/SystemPlugins/BoxModeConfig/plugin.py [new file with mode: 0755]
lib/python/Plugins/SystemPlugins/DeviceManager/plugin.py
lib/python/Plugins/SystemPlugins/FastZapSupport/Makefile.am [new file with mode: 0644]
lib/python/Plugins/SystemPlugins/FastZapSupport/__init__.py [new file with mode: 0644]
lib/python/Plugins/SystemPlugins/FastZapSupport/meta/Makefile.am [new file with mode: 0644]
lib/python/Plugins/SystemPlugins/FastZapSupport/meta/plugin_fastzapsupport.xml [new file with mode: 0644]
lib/python/Plugins/SystemPlugins/FastZapSupport/plugin.py [new file with mode: 0644]
lib/python/Plugins/SystemPlugins/Makefile.am
lib/python/Plugins/SystemPlugins/Videomode/VideoHardware.py
lib/python/Screens/About.py
lib/python/Screens/ChannelSelection.py
lib/python/Screens/InfoBarGenerics.py
lib/python/Screens/Satconfig.py
lib/python/Screens/ServiceInfo.py
lib/python/Screens/ServiceScan.py
lib/python/enigma_python.i
lib/service/listboxservice.cpp
lib/service/listboxservice.h
lib/service/servicedvbrecord.cpp
lib/service/servicemp3.cpp
lib/service/servicemp3.h

index d4071bb..bf4ad08 100644 (file)
@@ -30,7 +30,12 @@ TUXBOX_APPS_DVB
 AM_CONDITIONAL(HAVE_GIT_DIR, test -d "$srcdir/.git")
 AM_CONDITIONAL(HAVE_FAKE_GIT_DIR, test -f "$srcdir/.git/last_commit_info")
 
-PKG_CHECK_MODULES(BASE, [freetype2 fribidi gstreamer-0.10 gstreamer-pbutils-0.10 libdvbsi++ libpng libxml-2.0 sigc++-1.2 libssl libcrypto])
+dnl versions of gstreamer and plugins-base
+AC_ARG_WITH(gstversion,
+        AS_HELP_STRING([--with-gstversion],[use gstreamer version (major.minor)]),
+        [GST_MAJORMINOR=$withval],[GST_MAJORMINOR=0.10])
+
+PKG_CHECK_MODULES(BASE, [freetype2 fribidi gstreamer-$GST_MAJORMINOR gstreamer-pbutils-$GST_MAJORMINOR libdvbsi++ libpng libxml-2.0 sigc++-1.2 libssl libcrypto])
 PKG_CHECK_MODULES(LIBDDVD, libdreamdvd, HAVE_LIBDDVD="yes", HAVE_LIBDDVD="no")
 AM_CONDITIONAL(HAVE_LIBDDVD, test "$HAVE_LIBDDVD" = "yes")
 
@@ -210,6 +215,8 @@ lib/python/Plugins/Extensions/BackupSuiteUSB/Makefile
 lib/python/Plugins/Extensions/BackupSuiteUSB/meta/Makefile
 lib/python/Plugins/Extensions/SatipClient/Makefile
 lib/python/Plugins/Extensions/SatipClient/meta/Makefile
+lib/python/Plugins/Extensions/MiniTV/Makefile
+lib/python/Plugins/Extensions/MiniTV/meta/Makefile
 lib/python/Plugins/SystemPlugins/CleanupWizard/Makefile
 lib/python/Plugins/SystemPlugins/CleanupWizard/meta/Makefile
 lib/python/Plugins/SystemPlugins/CommonInterfaceAssignment/Makefile
@@ -295,6 +302,10 @@ lib/python/Plugins/SystemPlugins/AudioEffect/Makefile
 lib/python/Plugins/SystemPlugins/AudioEffect/meta/Makefile
 lib/python/Plugins/SystemPlugins/AnimationSetup/Makefile
 lib/python/Plugins/SystemPlugins/AnimationSetup/meta/Makefile
+lib/python/Plugins/SystemPlugins/FastZapSupport/Makefile
+lib/python/Plugins/SystemPlugins/FastZapSupport/meta/Makefile
+lib/python/Plugins/SystemPlugins/BoxModeConfig/Makefile
+lib/python/Plugins/SystemPlugins/BoxModeConfig/meta/Makefile
 lib/python/Tools/Makefile
 lib/service/Makefile
 lib/components/Makefile
index c13a502..db04392 100755 (executable)
@@ -48,7 +48,8 @@ self.selectKey("RIGHT")
                <step id="nimc">
                        <condition>
 from Components.NimManager import nimmanager
-self.condition = len(nimmanager.nim_slots) > 2 and not nimmanager.nim_slots[2].empty and config.misc.startwizard.shownimconfig.value
+from Screens.Satconfig import isFBCLink
+self.condition = len(nimmanager.nim_slots) > 2 and not nimmanager.nim_slots[2].empty and config.misc.startwizard.shownimconfig.value and not isFBCLink(nimmanager.nim_slots[2])
                        </condition>
                        <text value="Please set up tuner C" />
                        <config screen="NimSetup" module="Satconfig" args="2" type="ConfigList" />
@@ -61,7 +62,8 @@ self.selectKey("RIGHT")
                <step id="nimd">
                        <condition>
 from Components.NimManager import nimmanager
-self.condition = len(nimmanager.nim_slots) > 3 and not nimmanager.nim_slots[3].empty and config.misc.startwizard.shownimconfig.value
+from Screens.Satconfig import isFBCLink
+self.condition = len(nimmanager.nim_slots) > 3 and not nimmanager.nim_slots[3].empty and config.misc.startwizard.shownimconfig.value and not isFBCLink(nimmanager.nim_slots[3])
                        </condition>
                        <text value="Please set up tuner D" />
                        <config screen="NimSetup" module="Satconfig" args="3" type="ConfigList" />
@@ -71,6 +73,90 @@ self.selectKey("LEFT")
 self.selectKey("RIGHT")
                        </code>
                </step>
+               <step id="nime">
+                       <condition>
+from Components.NimManager import nimmanager
+from Screens.Satconfig import isFBCLink
+self.condition = len(nimmanager.nim_slots) > 4 and not nimmanager.nim_slots[4].empty and config.misc.startwizard.shownimconfig.value and not isFBCLink(nimmanager.nim_slots[4])
+                       </condition>
+                       <text value="Please set up tuner E" />
+                       <config screen="NimSetup" module="Satconfig" args="4" type="ConfigList" />
+                       <code>
+self.clearSelectedKeys()
+self.selectKey("LEFT")
+self.selectKey("RIGHT")
+                       </code>
+               </step>
+               <step id="nimf">
+                       <condition>
+from Components.NimManager import nimmanager
+from Screens.Satconfig import isFBCLink
+self.condition = len(nimmanager.nim_slots) > 5 and not nimmanager.nim_slots[5].empty and config.misc.startwizard.shownimconfig.value and not isFBCLink(nimmanager.nim_slots[5])
+                       </condition>
+                       <text value="Please set up tuner F" />
+                       <config screen="NimSetup" module="Satconfig" args="5" type="ConfigList" />
+                       <code>
+self.clearSelectedKeys()
+self.selectKey("LEFT")
+self.selectKey("RIGHT")
+                       </code>
+               </step>
+               <step id="nimg">
+                       <condition>
+from Components.NimManager import nimmanager
+from Screens.Satconfig import isFBCLink
+self.condition = len(nimmanager.nim_slots) > 6 and not nimmanager.nim_slots[6].empty and config.misc.startwizard.shownimconfig.value and not isFBCLink(nimmanager.nim_slots[6])
+                       </condition>
+                       <text value="Please set up tuner G" />
+                       <config screen="NimSetup" module="Satconfig" args="6" type="ConfigList" />
+                       <code>
+self.clearSelectedKeys()
+self.selectKey("LEFT")
+self.selectKey("RIGHT")
+                       </code>
+               </step>
+               <step id="nimh">
+                       <condition>
+from Components.NimManager import nimmanager
+from Screens.Satconfig import isFBCLink
+self.condition = len(nimmanager.nim_slots) > 7 and not nimmanager.nim_slots[7].empty and config.misc.startwizard.shownimconfig.value and not isFBCLink(nimmanager.nim_slots[7])
+                       </condition>
+                       <text value="Please set up tuner H" />
+                       <config screen="NimSetup" module="Satconfig" args="7" type="ConfigList" />
+                       <code>
+self.clearSelectedKeys()
+self.selectKey("LEFT")
+self.selectKey("RIGHT")
+                       </code>
+               </step>
+               <step id="nimi">
+                       <condition>
+from Components.NimManager import nimmanager
+from Screens.Satconfig import isFBCLink
+self.condition = len(nimmanager.nim_slots) > 8 and not nimmanager.nim_slots[8].empty and config.misc.startwizard.shownimconfig.value and not isFBCLink(nimmanager.nim_slots[8])
+                       </condition>
+                       <text value="Please set up tuner I" />
+                       <config screen="NimSetup" module="Satconfig" args="8" type="ConfigList" />
+                       <code>
+self.clearSelectedKeys()
+self.selectKey("LEFT")
+self.selectKey("RIGHT")
+                       </code>
+               </step>
+               <step id="nimj">
+                       <condition>
+from Components.NimManager import nimmanager
+from Screens.Satconfig import isFBCLink
+self.condition = len(nimmanager.nim_slots) > 9 and not nimmanager.nim_slots[9].empty and config.misc.startwizard.shownimconfig.value and not isFBCLink(nimmanager.nim_slots[9])
+                       </condition>
+                       <text value="Please set up tuner J" />
+                       <config screen="NimSetup" module="Satconfig" args="9" type="ConfigList" />
+                       <code>
+self.clearSelectedKeys()
+self.selectKey("LEFT")
+self.selectKey("RIGHT")
+                       </code>
+               </step>
                <step id="satlistsquestion">
                        <text value="Do you want to install default sat lists?" />
                        <condition>
index 0da46da..361323c 100644 (file)
@@ -174,7 +174,7 @@ public:
        {
                // added a new item to the list... in order
                // returns a iterator to the new item
-               return insert( std::lower_bound( std::list<T*>::begin(), std::list<T*>::end(), e, less()), e );
+               return this->insert( std::lower_bound( std::list<T*>::begin(), std::list<T*>::end(), e, less()), e );
        }
 
 };
@@ -804,7 +804,7 @@ public:
        {
                // added a new item to the list... in order
                // returns a iterator to the new item
-               return insert( std::lower_bound( std::list<ePtr<T> >::begin(), e, std::list<ePtr<T> >::end()), e );
+               return this->insert( std::lower_bound( std::list<ePtr<T> >::begin(), e, std::list<ePtr<T> >::end()), e );
        }
 
 };
index 9b33755..b185237 100644 (file)
@@ -30,7 +30,8 @@ libenigma_dvb_a_SOURCES = \
        subtitle.cpp \
        teletext.cpp \
        tstools.cpp \
-       volume.cpp
+       volume.cpp \
+       fbc.cpp
 
 dvbincludedir = $(pkgincludedir)/lib/dvb
 dvbinclude_HEADERS = \
@@ -61,4 +62,5 @@ dvbinclude_HEADERS = \
        subtitle.h \
        teletext.h \
        tstools.h \
-       volume.h
+       volume.h \
+       fbc.h
index 97cb99d..8a4a82d 100644 (file)
@@ -344,6 +344,7 @@ eDVBVideo::eDVBVideo(eDVBDemux *demux, int dev)
 #define VIDEO_STREAMTYPE_MPEG4_Part2 4
 #define VIDEO_STREAMTYPE_VC1_SM 5
 #define VIDEO_STREAMTYPE_MPEG1 6
+#define VIDEO_STREAMTYPE_H265_HEVC 7
 
 #if HAVE_DVB_API_VERSION < 3
 int eDVBVideo::setPid(int pid)
@@ -431,6 +432,9 @@ int eDVBVideo::startPid(int pid, int type)
        case VC1_SM:
                streamtype = VIDEO_STREAMTYPE_VC1_SM;
                break;
+       case H265_HEVC:
+               streamtype = VIDEO_STREAMTYPE_H265_HEVC;
+               break;
        }
 
        eDebugNoNewLine("VIDEO_SET_STREAMTYPE %d - ", streamtype);
index ed8b6c7..f0f8b2f 100644 (file)
@@ -49,7 +49,7 @@ private:
        Signal1<void, struct iTSMPEGDecoder::videoEvent> m_event;
        int m_width, m_height, m_framerate, m_aspect, m_progressive;
 public:
-       enum { MPEG2, MPEG4_H264, MPEG1, MPEG4_Part2, VC1, VC1_SM };
+       enum { MPEG2, MPEG4_H264, MPEG1, MPEG4_Part2, VC1, VC1_SM, H265_HEVC };
        eDVBVideo(eDVBDemux *demux, int dev);
        void stop();
 #if HAVE_DVB_API_VERSION < 3
index 62b01d2..0a371f0 100755 (executable)
@@ -6,6 +6,8 @@
 #include <lib/dvb/sec.h>
 #include <lib/dvb/specs.h>
 
+#include <lib/dvb/fbc.h>
+
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -26,6 +28,14 @@ eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(f
 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
 {
        m_fe->dec_use();
+       if (m_fe->m_frontend->is_FBCTuner())
+       {
+               eFBCTunerManager* fbcmng = eFBCTunerManager::getInstance();
+               if (fbcmng)
+               {
+                       fbcmng->unset(m_fe);
+               }
+       }
 }
 
 DEFINE_REF(eDVBAllocatedDemux);
@@ -422,13 +432,31 @@ void eDVBResourceManager::setFrontendType(int index, const char *type)
 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm, bool simulate)
 {
        eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
-       ePtr<eDVBRegisteredFrontend> best;
+//     ePtr<eDVBRegisteredFrontend> best;
+       eDVBRegisteredFrontend *best = NULL;
        int bestval = 0;
        int foundone = 0;
 
+       int check_fbc_linked = 0;
+       eDVBRegisteredFrontend *fbc_fe = NULL;
+       eDVBRegisteredFrontend *best_fbc_fe = NULL;
+       eFBCTunerManager* fbcmng = eFBCTunerManager::getInstance();
+
        for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
        {
-               int c = i->m_frontend->isCompatibleWith(feparm);
+               int c = 0;
+               fbc_fe = NULL;
+               if (!check_fbc_linked && i->m_frontend->is_FBCTuner() && fbcmng && fbcmng->canLink(*i))
+               {
+                       check_fbc_linked = 1;
+                       c = fbcmng->isCompatibleWith(feparm, *i, fbc_fe, simulate);
+
+//                     eDebug("[eDVBResourceManager::allocateFrontend] fbcmng->isCompatibleWith slotid : %p (%d), fbc_fe : %p (%d), score : %d", (eDVBRegisteredFrontend *)*i,  i->m_frontend->getSlotID(), fbc_fe, fbc_fe?fbc_fe->m_frontend->getSlotID():-1, c);                     
+               }
+               else
+               {
+                       c = i->m_frontend->isCompatibleWith(feparm);
+               }
 
                if (c)  /* if we have at least one frontend which is compatible with the source, flag this. */
                        foundone = 1;
@@ -439,15 +467,26 @@ RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, eP
                        if (c > bestval)
                        {
                                bestval = c;
-                               best = i;
+//                             best = i;
+                               best = *i;
+                               best_fbc_fe = fbc_fe;
                        }
                }
-//             else
+               else
+               {
 //                     eDebug("Slot %d, score %d... but BUSY!!!!!!!!!!!", i->m_frontend->getSlotID(), c);
+               }
+
+               eDVBRegisteredFrontend *tmp = *i;
        }
 
        if (best)
        {
+               if (fbcmng && best_fbc_fe)
+               {
+                       fbcmng->addLink(best, best_fbc_fe, simulate);
+               }
+
                fe = new eDVBAllocatedFrontend(best);
                return 0;
        }
@@ -667,12 +706,6 @@ RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
                if (!simulate) \
                        eDebug(x); \
        } while(0)
-//             else \
-//             { \
-//                     eDebugNoNewLine("SIMULATE:"); \
-//                     eDebug(x); \
-//             } \
-
 
 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel, bool simulate)
 {
@@ -877,14 +910,27 @@ int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &fepar
        eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
        ePtr<eDVBRegisteredFrontend> best;
        int bestval = 0;
+       int check_fbc_link = 0;
+       eFBCTunerManager *fbcmng = eFBCTunerManager::getInstance();
 
        for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
+       {
                if (!i->m_inuse)
                {
-                       int c = i->m_frontend->isCompatibleWith(feparm);
+                       int c = 0;
+                       if(fbcmng && i->m_frontend->is_FBCTuner() && fbcmng->canLink(*i) && !check_fbc_link)
+                       {
+                               check_fbc_link = 1;
+                               c = fbcmng->isCompatibleWith(feparm, *i, simulate);
+                       }
+                       else
+                       {
+                               c = i->m_frontend->isCompatibleWith(feparm);
+                       }
                        if (c > bestval)
                                bestval = c;
                }
+       }
        return bestval;
 }
 
index 10ad094..fa1e8a1 100644 (file)
@@ -12,6 +12,7 @@
 #include <lib/dvb/tstools.h>
 #include <lib/dvb/esection.h>
 #include <connection.h>
+#include <lib/dvb/fbc.h>
 
 #include <dvbsi++/service_description_section.h>
 
@@ -158,8 +159,9 @@ class eDVBResourceManager: public iObject, public Object
        ePtr<iDVBChannelList> m_list;
        ePtr<iDVBSatelliteEquipmentControl> m_sec;
        static eDVBResourceManager *instance;
-       
        friend class eDVBChannel;
+       friend class eFBCTunerManager;
        RESULT addChannel(const eDVBChannelID &chid, eDVBChannel *ch);
        RESULT removeChannel(eDVBChannel *ch);
 
diff --git a/lib/dvb/fbc.cpp b/lib/dvb/fbc.cpp
new file mode 100644 (file)
index 0000000..dc70c05
--- /dev/null
@@ -0,0 +1,880 @@
+/* FBC Manager */
+#include <lib/dvb/fbc.h>
+#include <lib/dvb/dvb.h>
+#include <lib/dvb/sec.h>
+#include <lib/base/object.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#define FE_SLOT_ID(fe) fe->m_frontend->getSlotID()
+
+//#define FBC_DEBUG
+
+#ifdef FBC_DEBUG
+#define eFecDebug(arg...) eDebug(arg)
+#else
+#define eFecDebug(arg...)
+#endif
+
+
+DEFINE_REF(eFBCTunerManager);
+
+bool eFBCTunerManager::isDestroyed = false;
+
+eFBCTunerManager::eFBCTunerManager()
+{
+       ePtr<eDVBResourceManager> res_mgr;
+       eDVBResourceManager::getInstance(res_mgr);
+       m_res_mgr = res_mgr;
+
+       /* num of fbc tuner in one set */
+       m_fbc_tuner_num = getFBCTunerNum();
+       procInit();
+}
+
+eFBCTunerManager::~eFBCTunerManager()
+{
+       isDestroyed = true;
+}
+
+void eFBCTunerManager::procInit()
+{
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
+
+       /* 1 FBC set has 8 tuners. */
+       /* 1st set : 0, 1, 2, 3, 4, 5, 6, 7 */
+       /* 2nd set : 8, 9, 10, 11, 12, 13, 14, 15 */
+       /* 1st, 2nd frontend is top on a set */
+
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               if (!it->m_frontend->is_FBCTuner())
+                       continue;
+
+               if (isRootFe(*it))
+               {
+                       setProcFBCID(FE_SLOT_ID(it), getFBCID(FE_SLOT_ID(it)));
+               }
+       }
+}
+
+int eFBCTunerManager::getFBCTunerNum()
+{
+       char tmp[255];
+       int fbc_tuner_num = 2;
+       int fd = open("/proc/stb/info/chipset", O_RDONLY);
+       if(fd < 0) {
+               eDebug("open failed, /proc/stb/info/chipset!");
+               fbc_tuner_num = 2;
+       }
+       else
+       {
+               read(fd, tmp, 255);
+               close(fd);
+
+               if (!!strstr(tmp, "7376"))
+                       fbc_tuner_num = 2;
+       }
+       return fbc_tuner_num;
+}
+
+int eFBCTunerManager::setProcFBCID(int fe_id, int fbc_id)
+{
+       eFecDebug("[*][eFBCTunerManager::setProcFBCID] %d -> %d %s", fe_id, fbc_id, !isRootFeSlot(fe_id)?"(linked)":"");
+       char filename[128];
+       char data[4];
+       sprintf(filename, "/proc/stb/frontend/%d/fbc_id", fe_id);
+       int fd = open(filename, O_RDWR);
+       if(fd < 0) {
+               eDebug("[*][eFBCTunerManager::setProcFBCID] open failed, %s: %m", filename);
+               return -1;
+       }
+       else
+       {
+               if(isLinkedByIndex(fe_id))
+                       fbc_id += 0x10; // 0x10 : isLinked, 0x01 : fbc_id
+
+               sprintf(data, "%x", fbc_id);
+               write(fd, data, strlen(data));
+               close(fd);
+       }
+       return 0;
+}
+
+bool eFBCTunerManager::isRootFeSlot(int fe_slot_id)
+{
+       return (fe_slot_id%8 < m_fbc_tuner_num) ? true : false;
+}
+
+
+bool eFBCTunerManager::isRootFe(eDVBRegisteredFrontend *fe)
+{
+       return isRootFeSlot(FE_SLOT_ID(fe));
+}
+
+bool eFBCTunerManager::isSameFbcSet(int a, int b)
+{
+       return (a/8) == (b/8) ? true : false;
+}
+
+bool eFBCTunerManager::isSupportDVBS(eDVBRegisteredFrontend *fe)
+{
+       return (fe->m_frontend->supportsDeliverySystem(SYS_DVBS, true) || fe->m_frontend->supportsDeliverySystem(SYS_DVBS2, true)) ? true : false;
+}
+
+int eFBCTunerManager::getFBCID(int top_fe_id)
+{
+       return 2*top_fe_id/8 + top_fe_id%8; /* (0,1,8,9,16,17...) -> (0,1,2,3,4,5...)*/
+}
+
+int eFBCTunerManager::setDefaultFBCID(eDVBRegisteredFrontend *fe)
+{
+       if (!isRootFe(fe))
+               return -1;
+
+       return setProcFBCID(FE_SLOT_ID(fe), getFBCID(FE_SLOT_ID(fe)));
+}
+
+void eFBCTunerManager::updateFBCID(eDVBRegisteredFrontend *next_fe, eDVBRegisteredFrontend *prev_fe)
+{
+       eDVBRegisteredFrontend *top_fe = getTop(prev_fe);
+       setProcFBCID(FE_SLOT_ID(next_fe), getFBCID(FE_SLOT_ID(top_fe)));
+}
+
+eDVBRegisteredFrontend *eFBCTunerManager::getPrev(eDVBRegisteredFrontend *fe)
+{
+       eDVBRegisteredFrontend *prev_fe = NULL;
+       long linked_prev_ptr = -1;
+       fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
+       if (linked_prev_ptr != -1)
+               prev_fe = (eDVBRegisteredFrontend *)linked_prev_ptr;
+       return prev_fe;
+}
+
+eDVBRegisteredFrontend *eFBCTunerManager::getNext(eDVBRegisteredFrontend *fe)
+{
+       eDVBRegisteredFrontend *next_fe = NULL;
+       long linked_next_ptr = -1;
+       fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
+       if (linked_next_ptr != -1)
+               next_fe = (eDVBRegisteredFrontend *)linked_next_ptr;
+       return next_fe;
+}
+
+eDVBRegisteredFrontend *eFBCTunerManager::getTop(eDVBRegisteredFrontend *fe)
+{
+       eDVBRegisteredFrontend *prev_fe = fe;
+       long linked_prev_ptr = -1;
+       fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
+       while(linked_prev_ptr != -1)
+       {
+               prev_fe = (eDVBRegisteredFrontend *)linked_prev_ptr;
+               prev_fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
+       }
+       return prev_fe;
+}
+
+eDVBRegisteredFrontend *eFBCTunerManager::getLast(eDVBRegisteredFrontend *fe)
+{
+       eDVBRegisteredFrontend *next_fe = fe;
+       long linked_next_ptr = -1;
+       fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
+       while(linked_next_ptr != -1)
+       {
+               next_fe = (eDVBRegisteredFrontend *)linked_next_ptr;
+               next_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
+       }
+       return next_fe;
+}
+
+bool eFBCTunerManager::isLinked(eDVBRegisteredFrontend *fe)
+{
+       return getPrev(fe) ? true:false;
+}
+
+bool eFBCTunerManager::isLinkedByIndex(int fe_idx)
+{
+       bool linked = false;
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
+
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               if (FE_SLOT_ID(it) == fe_idx)
+               {
+                       linked = isLinked(*it);
+                       break;
+               }
+       }
+       return linked;
+}
+
+bool eFBCTunerManager::checkTop(eDVBRegisteredFrontend *fe)
+{
+       return getPrev(fe) ? false:true;
+}
+
+int eFBCTunerManager::connectLinkByIndex(int link_fe_index, int prev_fe_index, int next_fe_index, bool simulate)
+{
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
+
+       eFecDebug("     [*][eFBCTunerManager::connectLinkByIndex] try to link %d->%d->%d %s", prev_fe_index, link_fe_index, next_fe_index, simulate?"(simulate)":"");
+
+       eDVBRegisteredFrontend *link_fe=NULL;
+       eDVBRegisteredFrontend *prev_fe=NULL;
+       eDVBRegisteredFrontend *next_fe=NULL;
+
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               if (FE_SLOT_ID(it) == prev_fe_index)
+               {
+                       prev_fe = *it;
+               }
+               else if (FE_SLOT_ID(it) == next_fe_index)
+               {
+                       next_fe = *it;
+               }
+               else if (FE_SLOT_ID(it) == link_fe_index)
+               {
+                       link_fe = *it;
+               }
+       }
+
+       if (prev_fe && next_fe && link_fe)
+       {
+               /* enable linked fe */
+               link_fe->m_frontend->setEnabled(true);
+
+               /* connect */
+               prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
+
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe);
+               next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)link_fe);
+       }
+       else
+       {
+               eDebug("        [*][eFBCTunerManager::connectLinkByIndex] connect failed! (prev_fe : %p, next_fe : %p, link_fe : %p, %s)", prev_fe, next_fe, link_fe, simulate?"simulate":"");
+               return -1;
+       }
+
+       return 0;
+}
+
+int eFBCTunerManager::connectLinkByIndex(int link_fe_index, int prev_fe_index, bool simulate)
+{
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
+
+       eFecDebug("     [*][eFBCTunerManager::connectLinkByIndex] try to link %d->%d %s", prev_fe_index, link_fe_index, simulate?"(simulate)":"");
+
+       eDVBRegisteredFrontend *link_fe=NULL;
+       eDVBRegisteredFrontend *prev_fe=NULL;
+
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               if (FE_SLOT_ID(it) == prev_fe_index)
+               {
+                       prev_fe = *it;
+               }
+               else if (FE_SLOT_ID(it) == link_fe_index)
+               {
+                       link_fe = *it;
+               }
+       }
+
+       if (prev_fe && link_fe)
+       {
+               /* enable linked fe */
+               link_fe->m_frontend->setEnabled(true);
+
+               /* connect */
+               prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
+       }
+       else
+       {
+               eDebug("        [*][eFBCTunerManager::connectLinkByIndex] connect failed! (prev_fe : %p, link_fe : %p, %s)", prev_fe, link_fe, simulate?"simulate":"");
+               return -1;
+       }
+
+       return 0;
+}
+
+int eFBCTunerManager::disconnectLinkByIndex(int link_fe_index, int prev_fe_index, int next_fe_index, bool simulate)
+{
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
+
+       eFecDebug("     [*][eFBCTunerManager::connectLinkByIndex] try to unlink %d->%d->%d %s", prev_fe_index, link_fe_index, next_fe_index, simulate?"(simulate)":"");
+
+       eDVBRegisteredFrontend *link_fe=NULL;
+       eDVBRegisteredFrontend *prev_fe=NULL;
+       eDVBRegisteredFrontend *next_fe=NULL;
+
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               if (FE_SLOT_ID(it) == prev_fe_index)
+               {
+                       prev_fe = *it;
+               }
+               else if (FE_SLOT_ID(it) == next_fe_index)
+               {
+                       next_fe = *it;
+               }
+               else if (FE_SLOT_ID(it) == link_fe_index)
+               {
+                       link_fe = *it;
+               }
+       }
+
+       if (prev_fe && next_fe && link_fe)
+       {
+               /* disconnect */
+               prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe);
+               next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
+
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
+
+               /* enable linked fe */
+               link_fe->m_frontend->setEnabled(false);
+       }
+       else
+       {
+               eDebug("        [*][eFBCTunerManager::disconnectLinkByIndex] disconnect failed! (prev_fe : %p, next_fe : %p, link_fe : %p, %s)", prev_fe, next_fe, link_fe, simulate?"simulate":"");
+               return -1;
+       }
+
+       return 0;
+}
+int eFBCTunerManager::disconnectLinkByIndex(int link_fe_index, int prev_fe_index, bool simulate)
+{
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
+
+       eFecDebug("     [*][eFBCTunerManager::connectLinkByIndex] try to unlink %d->%d %s", prev_fe_index, link_fe_index, simulate?"(simulate)":"");
+
+       eDVBRegisteredFrontend *link_fe=NULL;
+       eDVBRegisteredFrontend *prev_fe=NULL;
+
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               if (FE_SLOT_ID(it) == prev_fe_index)
+               {
+                       prev_fe = *it;
+               }
+               else if (FE_SLOT_ID(it) == link_fe_index)
+               {
+                       link_fe = *it;
+               }
+       }
+
+       if (prev_fe && link_fe)
+       {
+               /* disconnect */
+               prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
+
+               /* enable linked fe */
+               link_fe->m_frontend->setEnabled(false);
+       }
+       else
+       {
+               eDebug("        [*][eFBCTunerManager::disconnectLinkByIndex] disconnect failed! (prev_fe : %p, link_fe : %p, %s)", prev_fe, link_fe, simulate?"simulate":"");
+               return -1;
+       }
+
+       return 0;
+}
+
+int eFBCTunerManager::connectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate)
+{
+       eFecDebug("     [*][eFBCTunerManager::connectLink] try to link %d->%d->%d %s", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe), FE_SLOT_ID(next_fe), simulate?"(simulate)":"");
+       int ret = connectLinkByIndex(FE_SLOT_ID(link_fe), FE_SLOT_ID(prev_fe), FE_SLOT_ID(next_fe), !simulate);
+       if(!ret)
+       {
+               prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
+
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe);
+               next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)link_fe);
+
+               /* enable linked fe */
+               link_fe->m_frontend->setEnabled(true);  
+       }
+
+       return ret;
+}
+
+int eFBCTunerManager::connectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, bool simulate)
+{
+       eFecDebug("     [*][eFBCTunerManager::connectLink] try to link %d->%d %s", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe), simulate?"(simulate)":"");
+       int ret = connectLinkByIndex(FE_SLOT_ID(link_fe), FE_SLOT_ID(prev_fe), !simulate);
+       if(!ret)
+       {
+               prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
+
+               /* enable linked fe */
+               link_fe->m_frontend->setEnabled(true);
+       }
+
+       return ret;
+}
+
+int eFBCTunerManager::disconnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate)
+{
+       eFecDebug("     [*][eFBCTunerManager::disconnectLink] disconnect %d->%d->%d %s", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe), FE_SLOT_ID(next_fe), simulate?"(simulate)":"");
+       int ret = disconnectLinkByIndex(FE_SLOT_ID(link_fe), FE_SLOT_ID(prev_fe), FE_SLOT_ID(next_fe), !simulate);
+       if(!ret)
+       {
+               prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe);
+               next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
+
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
+
+               link_fe->m_frontend->setEnabled(false);
+       }
+
+       return ret;
+}
+
+int eFBCTunerManager::disconnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, bool simulate)
+{
+       eFecDebug("     [*][eFBCTunerManager::disconnectLink] disconnect %d->%d %s", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe), simulate?"(simulate)":"");
+       int ret = disconnectLinkByIndex(FE_SLOT_ID(link_fe), FE_SLOT_ID(prev_fe), !simulate);
+       if(!ret)
+       {
+               prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
+               link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
+
+               link_fe->m_frontend->setEnabled(false);
+       }
+
+       return ret;
+}
+
+/* no set pair simulate fe */
+/* no set proc fbc_id */
+void eFBCTunerManager::connectLinkNoSimulate(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe)
+{
+       eDVBRegisteredFrontend *last_fe = getLast(top_fe);
+
+       last_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
+       link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)last_fe);
+
+       /* enable linked fe */
+       link_fe->m_frontend->setEnabled(true);
+
+       /* add slot mask*/
+       updateLNBSlotMask(FE_SLOT_ID(link_fe), FE_SLOT_ID(top_fe), false);
+}
+
+/* no set pair simulate fe */
+/* no set proc fbc_id */
+void eFBCTunerManager::disconnectLinkNoSimulate(eDVBRegisteredFrontend *link_fe)
+{
+       if(getNext(link_fe))
+       {
+               eFecDebug("[*][eFBCTunerManager::disconnectLinkNoSimulate] link fe is no last.");
+               return;
+       }
+
+       eDVBRegisteredFrontend *prev_fe = getPrev(link_fe);
+
+       if(!prev_fe)
+       {
+               eFecDebug("[*][eFBCTunerManager::disconnectLinkNoSimulate] can not found prev fe.");
+               return;
+       }
+
+       prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
+       link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
+               
+       /* enable linked fe */
+       link_fe->m_frontend->setEnabled(false);
+
+       /* add slot mask*/
+       updateLNBSlotMask(FE_SLOT_ID(link_fe), FE_SLOT_ID(prev_fe), true);
+}
+
+bool eFBCTunerManager::checkUsed(eDVBRegisteredFrontend *fe, bool a_simulate)
+{
+       if (fe->m_inuse > 0)
+               return true;
+
+       bool simulate = !a_simulate;
+
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               if (FE_SLOT_ID(it) == FE_SLOT_ID(fe))
+               {
+                       return (it->m_inuse >0)?true:false;
+               }
+       }
+
+       eDebug("[*][eFBCTunerManager::checkUsed] ERROR! can not found fe ptr (feid : %d, simulate : %d)", FE_SLOT_ID(fe), simulate);
+       return false;
+}
+
+bool eFBCTunerManager::canLink(eDVBRegisteredFrontend *fe)
+{
+       if(isRootFe(fe))
+               return false;
+
+       if(getPrev(fe) || getNext(fe))
+               return false;
+
+       if(isUnicable(fe))
+               return false;
+
+       return true;
+}
+
+bool eFBCTunerManager::isUnicable(eDVBRegisteredFrontend *fe)
+{
+       int slot_idx = FE_SLOT_ID(fe);
+       bool is_unicable = false;
+
+       ePtr<eDVBSatelliteEquipmentControl> sec = eDVBSatelliteEquipmentControl::getInstance();
+       for (int idx=0; idx <= sec->m_lnbidx; ++idx )
+       {
+               eDVBSatelliteLNBParameters &lnb_param = sec->m_lnbs[idx];
+               if ( lnb_param.m_slot_mask & (1 << slot_idx) )
+               {
+                       is_unicable = lnb_param.SatCR_idx != -1;
+                       break;
+               }
+       }
+       return is_unicable;
+}
+
+int eFBCTunerManager::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm, eDVBRegisteredFrontend *link_fe, bool simulate)
+{
+       eDVBRegisteredFrontend *best_fbc_fe;
+       return isCompatibleWith(feparm, link_fe, best_fbc_fe, simulate);
+}
+
+int eFBCTunerManager::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm, eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *&fbc_fe, bool simulate)
+{
+       int best_score = 0;
+
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               if (!it->m_frontend->is_FBCTuner())
+                       continue;
+
+               if (!isRootFe(*it))
+                       continue;
+
+               if(!it->m_frontend->getEnabled())
+                       continue;
+
+               if(!isSameFbcSet(FE_SLOT_ID(link_fe), FE_SLOT_ID(it)))
+                       continue;
+
+               if(it->m_inuse == 0) // No link to a fe not in use.
+                       continue;
+
+               if(isLinked(*it)) // No link to a fe linked to another.
+                       continue;
+
+               if(isUnicable(*it))
+                       continue;
+
+               /* connect link */
+               connectLinkNoSimulate(link_fe, *it);
+
+               /* get score */
+               int c = link_fe->m_frontend->isCompatibleWith(feparm);
+               eFecDebug("[*][eFBCTunerManager::isCompatibleWith] score : %d (%d->%d)", c, FE_SLOT_ID(it), FE_SLOT_ID(link_fe));
+               if (c > best_score)
+               {
+                       best_score = c;
+                       fbc_fe = (eDVBRegisteredFrontend *)*it;
+               }
+
+               /* disconnect link */
+               disconnectLinkNoSimulate(link_fe);
+       }
+
+       eFecDebug("[*][eFBCTunerManager::isCompatibleWith] fe : %p(%d), score : %d %s", link_fe, FE_SLOT_ID(link_fe), best_score, simulate?"(simulate)":"");
+
+       return best_score;
+}
+
+void eFBCTunerManager::connectSortedLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe, bool simulate)
+{
+       int link_fe_id = FE_SLOT_ID(link_fe);
+       int top_fe_id = FE_SLOT_ID(top_fe);
+       int prev_fe_id = link_fe_id - 1;
+
+       eFecDebug("     [*][eFBCTunerManager::connectSortedLink] link_id : %d, top_id : %d %s", link_fe_id, top_fe_id, simulate?"(simulate)":"");
+
+       if (prev_fe_id < 0)
+       {
+               eFecDebug("     [*][eFBCTunerManager::connectSortedLink] link failed! link_id : %d, top_id : %d %s", link_fe_id, top_fe_id, simulate?"(simulate)":"");
+               return;
+       }
+
+       /* serach prev fe */
+       eDVBRegisteredFrontend *next_fe = top_fe;
+       long linked_next_ptr = -1;
+       top_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
+       while(linked_next_ptr != -1)
+       {
+               next_fe = (eDVBRegisteredFrontend *)linked_next_ptr;
+               next_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
+               if (FE_SLOT_ID(next_fe) == prev_fe_id)
+                       break;
+       }
+
+       eDVBRegisteredFrontend *prev_fe = next_fe;
+
+       /* get next fe */
+       next_fe = getNext(prev_fe);     
+
+       /* connect */
+       if (next_fe)
+       {
+               int res = connectLink(link_fe, prev_fe, next_fe, simulate);
+               if (res)
+               {
+                       eDebug("[*][eFBCTunerManager::connectSortedLink] ERROR! connect link failed! (%d->%d->%d)", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe), FE_SLOT_ID(next_fe));
+                       return;
+               }
+       }
+       else
+       {
+               int res = connectLink(link_fe, prev_fe, simulate);
+               if (res)
+               {
+                       eDebug("[*][eFBCTunerManager::connectSortedLink] ERROR! connect link failed! (%d->%d)", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe));
+                       return;
+               }
+       }
+
+       /* set proc fbc_id */
+       setProcFBCID(link_fe_id, getFBCID(top_fe_id));
+
+       /* add slot mask*/
+       updateLNBSlotMask(link_fe_id, top_fe_id, false);
+}
+
+/* attach link_fe to tail of fe linked list */
+void eFBCTunerManager::addLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe, bool simulate)
+{
+       eFecDebug("     [*][eFBCTunerManager::addLink] addLink : %p(%d)->%p(%d) %s", top_fe, FE_SLOT_ID(top_fe), link_fe, FE_SLOT_ID(link_fe), simulate?"(simulate)":"");
+
+       if (!isRootFe(top_fe))
+               return;
+
+//     eDVBRegisteredFrontend *top_fe = a_top_fe;
+//     if (!checkTop(top_fe))
+//             top_fe = getTop(top_fe);
+
+//     printLinks(top_fe);
+       connectSortedLink(link_fe, top_fe, simulate);
+//     printLinks(top_fe);
+}
+
+/* if fe, fe_simulated is unused, unlink current frontend from linked things. */
+/* all unused linked fbc fe must be unlinked! */
+void eFBCTunerManager::unset(eDVBRegisteredFrontend *fe)
+{
+       bool simulate = fe->m_frontend->is_simulate();
+
+       if (isRootFe(fe))
+               return;
+
+       if(checkUsed(fe, simulate))
+               return;
+
+       if(isUnicable(fe))
+               return;
+
+       eFecDebug("     [*][eFBCTunerManager::unset] fe id : %p(%d) %s", fe, FE_SLOT_ID(fe), simulate?"(simulate)":"");
+
+       
+//     printLinks(fe);
+
+       eDVBRegisteredFrontend *linked_prev_fe = getPrev(fe);
+       eDVBRegisteredFrontend *linked_next_fe = getNext(fe);
+
+       if (!linked_prev_fe)
+       {
+               eDebug("[*][eFBCTunerManager::unset] ERROR! can not found prev linked frontend (fe_id : %d)", FE_SLOT_ID(fe));
+               return;
+       }
+
+       if (linked_next_fe)
+       {
+               int res = disconnectLink(fe, linked_prev_fe, linked_next_fe, simulate);
+               if (res)
+               {
+                       eDebug("[*][eFBCTunerManager::unset] ERROR! disconnect link failed! (%d->%d->%d)", FE_SLOT_ID(linked_prev_fe), FE_SLOT_ID(fe), FE_SLOT_ID(linked_next_fe));
+                       return;
+               }
+       }
+       else
+       {
+               int res = disconnectLink(fe, linked_prev_fe, simulate);
+               if (res)
+               {
+                       eDebug("[*][eFBCTunerManager::unset] ERROR! disconnect link failed! (%d->%d)", FE_SLOT_ID(linked_prev_fe), FE_SLOT_ID(fe));
+                       return;
+               }
+       }
+
+       /* set proc fbc_id (skip) */
+
+       /* remove slot mask*/
+       updateLNBSlotMask(FE_SLOT_ID(fe), FE_SLOT_ID(linked_prev_fe), true);
+
+//     printLinks(fe);
+}
+
+bool eFBCTunerManager::canAllocateLink(eDVBRegisteredFrontend *fe, bool simulate)
+{
+       if (!isRootFe(fe))
+               return false;
+
+       if (isLinked(fe))
+               return false;
+
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               if (it->m_frontend->is_FBCTuner() && !isRootFe(*it) && isSameFbcSet(FE_SLOT_ID(fe), FE_SLOT_ID(it)) && !it->m_frontend->getEnabled() && !isLinked(*it))
+                       return true;
+       }
+
+       return false;
+}
+
+int eFBCTunerManager::updateLNBSlotMask(int dest_slot, int src_slot, bool remove)
+{
+       ePtr<eDVBSatelliteEquipmentControl> sec = eDVBSatelliteEquipmentControl::getInstance();
+
+       int sec_lnbidx = sec->m_lnbidx;
+
+       int found = 0;
+       for (int idx=0; idx <= sec_lnbidx; ++idx )
+       {
+               eDVBSatelliteLNBParameters &lnb_param = sec->m_lnbs[idx];
+               if ( lnb_param.m_slot_mask & (1 << src_slot) )
+               {
+                       eFecDebug("[*][eFBCTunerManager::updateLNBSlotMask] m_slot_mask : %d", lnb_param.m_slot_mask);
+
+                       if (!remove)
+                               lnb_param.m_slot_mask |= (1 << dest_slot);
+                       else
+                               lnb_param.m_slot_mask &= ~(1 << dest_slot);
+
+                       eFecDebug("[*][eFBCTunerManager::updateLNBSlotMask] changed m_slot_mask : %d", lnb_param.m_slot_mask);
+                       found = 1;
+               }
+       }
+
+       if (!found)
+               eFecDebug("[*][eFBCTunerManager::updateLNBSlotMask] src %d not found", src_slot);
+
+       return 0;
+}
+
+int eFBCTunerManager::getLinkedSlotID(int fe_id)
+{
+       int link = -1;
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               if(it->m_frontend->getSlotID() == fe_id)
+               {
+                       long prev_ptr = -1;
+                       it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr);
+                       if (prev_ptr != -1)
+                       {
+                               eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr;
+                               link = FE_SLOT_ID(prev_fe);
+                       }
+                       break;
+               }
+       }
+
+       eFecDebug(" [*][eFBCTunerManager::getLinkedSlotID] fe_id : %d, link : %d", fe_id, link);
+
+       return link;
+}
+
+void eFBCTunerManager::printLinks(eDVBRegisteredFrontend *fe)
+{
+       long linked_prev_ptr = -1;
+       eDVBRegisteredFrontend *linked_prev_fe = fe;
+       fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
+       while (linked_prev_ptr != -1)
+       {
+               linked_prev_fe = (eDVBRegisteredFrontend*) linked_prev_ptr;
+               linked_prev_fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, (long&)linked_prev_ptr);
+       }
+
+       long linked_next_ptr = -1;
+       eDVBRegisteredFrontend *linked_next_fe = linked_prev_fe;
+       eFecDebug("     [*][eFBCTunerManager::printLinks] fe id : %d (%p), inuse : %d, enabled : %d, fbc : %d", FE_SLOT_ID(linked_next_fe), linked_next_fe, linked_next_fe->m_inuse, linked_next_fe->m_frontend->getEnabled(), linked_next_fe->m_frontend->is_FBCTuner());
+       linked_prev_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
+       while (linked_next_ptr != -1)
+       {
+               linked_next_fe = (eDVBRegisteredFrontend*) linked_next_ptr;
+               eFecDebug("     [*][eFBCTunerManager::printLinks] fe id : %d (%p), inuse : %d, enabled : %d, fbc : %d", FE_SLOT_ID(linked_next_fe), linked_next_fe, linked_next_fe->m_inuse, linked_next_fe->m_frontend->getEnabled(), linked_next_fe->m_frontend->is_FBCTuner());
+               linked_next_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, (long&)linked_next_ptr);
+       }
+
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
+       {
+               int prev = -1;
+               int next = -1;
+               long prev_ptr = -1;
+               long next_ptr = -1;
+               it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr);
+               it->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, next_ptr);
+               if (prev_ptr != -1)
+               {
+                       eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr;
+                       prev = FE_SLOT_ID(prev_fe);
+               }
+
+               if (next_ptr != -1)
+               {
+                       eDVBRegisteredFrontend *next_fe = (eDVBRegisteredFrontend *)next_ptr;
+                       next = FE_SLOT_ID(next_fe);
+               }
+               
+               eFecDebug("     [*][eFBCTunerManager::printLinks] fe_id : %d, inuse : %d, enabled : %d, fbc : %d, prev : %d, next : %d", FE_SLOT_ID(it), it->m_inuse, it->m_frontend->getEnabled(), it->m_frontend->is_FBCTuner(), prev, next);
+       }
+
+       eSmartPtrList<eDVBRegisteredFrontend> &simulate_frontends = m_res_mgr->m_simulate_frontend;
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(simulate_frontends.begin()); it != simulate_frontends.end(); ++it)
+       {
+               int prev = -1;
+               int next = -1;
+               long prev_ptr = -1;
+               long next_ptr = -1;
+               it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr);
+               it->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, next_ptr);
+               if (prev_ptr != -1)
+               {
+                       eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr;
+                       prev = FE_SLOT_ID(prev_fe);
+               }
+
+               if (next_ptr != -1)
+               {
+                       eDVBRegisteredFrontend *next_fe = (eDVBRegisteredFrontend *)next_ptr;
+                       next = FE_SLOT_ID(next_fe);
+               }
+               
+               eFecDebug("     [*][eFBCTunerManager::printLinks] fe_id : %2d, inuse : %d, enabled : %d, fbc : %d, prev : %2d, cur : %2d, next : %2d (simulate)", FE_SLOT_ID(it), it->m_inuse, it->m_frontend->getEnabled(), it->m_frontend->is_FBCTuner(), prev, FE_SLOT_ID(it), next);
+       }
+}
+
diff --git a/lib/dvb/fbc.h b/lib/dvb/fbc.h
new file mode 100644 (file)
index 0000000..5f1afc1
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef __dvb_fbc_h
+#define __dvb_fbc_h
+
+/* FBC Manager */
+#include <lib/base/ebase.h>
+#include <lib/base/object.h>
+#include <lib/base/eptrlist.h>
+#include <lib/dvb/idvb.h>
+
+class eDVBResourceManager;
+class eDVBRegisteredFrontend;
+
+class eFBCTunerManager: public iObject, public Object
+{
+private:
+       DECLARE_REF(eFBCTunerManager);
+       ePtr<eDVBResourceManager> m_res_mgr;
+       int m_fbc_tuner_num;
+       static bool isDestroyed;
+
+       int getFBCTunerNum();
+       void procInit();
+       bool isSameFbcSet(int a, int b);
+       bool isSupportDVBS(eDVBRegisteredFrontend *fe);
+       int getFBCID(int root_fe_id);
+
+       eDVBRegisteredFrontend *getPrev(eDVBRegisteredFrontend *fe);
+       eDVBRegisteredFrontend *getNext(eDVBRegisteredFrontend *fe);
+       eDVBRegisteredFrontend *getTop(eDVBRegisteredFrontend *fe);
+       eDVBRegisteredFrontend *getLast(eDVBRegisteredFrontend *fe);
+       bool isLinked(eDVBRegisteredFrontend *fe);
+       bool isLinkedByIndex(int fe_idx);
+       bool checkTop(eDVBRegisteredFrontend *fe);
+       int connectLinkByIndex(int link_fe_index, int prev_fe_index, int next_fe_index, bool simulate);
+       int connectLinkByIndex(int link_fe_index, int prev_fe_index, bool simulate);
+       int disconnectLinkByIndex(int link_fe_index, int prev_fe_index, int next_fe_index, bool simulate);
+       int disconnectLinkByIndex(int link_fe_index, int prev_fe_index, bool simulate);
+       int connectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate);
+       int connectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, bool simulate);
+       int disconnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate);
+       int disconnectLink(eDVBRegisteredFrontend *linkable_fe, eDVBRegisteredFrontend *top_fe, bool simulate);
+       void connectLinkNoSimulate(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe);
+       void disconnectLinkNoSimulate(eDVBRegisteredFrontend *link_fe);
+
+       bool checkUsed(eDVBRegisteredFrontend *fe, bool a_simulate);
+       void connectSortedLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe, bool simulate);
+       int updateLNBSlotMask(int dest_slot, int src_slot, bool remove);
+       void printLinks(eDVBRegisteredFrontend *fe);
+
+public:
+       eFBCTunerManager();
+       virtual ~eFBCTunerManager();
+       int setProcFBCID(int fe_id, int fbc_id);
+       int setDefaultFBCID(eDVBRegisteredFrontend *fe);
+       void updateFBCID(eDVBRegisteredFrontend *next_fe, eDVBRegisteredFrontend *prev_fe);
+       bool isRootFeSlot(int fe_slot_id);
+       bool isRootFe(eDVBRegisteredFrontend *fe);
+       bool canLink(eDVBRegisteredFrontend *fe);
+       bool isUnicable(eDVBRegisteredFrontend *fe);
+       int isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm, eDVBRegisteredFrontend *link_fe, bool simulate);
+       int isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm, eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *&fbc_fe, bool simulate);
+       void addLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe, bool simulate);
+       void unset(eDVBRegisteredFrontend *fe);
+       bool canAllocateLink(eDVBRegisteredFrontend *fe, bool simulate);
+
+       static eFBCTunerManager* getInstance()
+       {
+               if (isDestroyed == true)
+               {
+                       eDebug("eFBCTunerManager is already destroyed!");
+                       return 0;
+               }
+               static eFBCTunerManager instance;
+               return &instance;
+       }
+
+       int getLinkedSlotID(int feid);
+};
+
+#endif /* __dvb_fbc_h */
\ No newline at end of file
index ae40483..1e7cb6b 100755 (executable)
@@ -502,7 +502,7 @@ int eDVBFrontend::PreferredFrontendIndex=-1;
 eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok, bool simulate, eDVBFrontend *simulate_fe)
        :m_simulate(simulate), m_enabled(false), m_simulate_fe(simulate_fe), m_dvbid(fe), m_slotid(fe)
        ,m_fd(-1), m_rotor_mode(false), m_need_rotor_workaround(false)
-       ,m_state(stateClosed), m_timeout(0), m_tuneTimer(0)
+       ,m_state(stateClosed), m_timeout(0), m_tuneTimer(0), m_fbc(false)
 #if HAVE_DVB_API_VERSION < 3
        ,m_secfd(-1)
 #endif
@@ -525,6 +525,11 @@ eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok, bool simulate, eDVBFronten
 
        m_idleInputpower[0]=m_idleInputpower[1]=0;
 
+       char fileName[32] = {0};
+       sprintf(fileName, "/proc/stb/frontend/%d/fbc_id", m_slotid);
+       if (access(fileName, F_OK) == 0)
+               m_fbc = true;
+
        ok = !openFrontend();
        closeFrontend();
 }
@@ -2961,7 +2966,6 @@ RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateCh
 
 RESULT eDVBFrontend::setVoltage(int voltage)
 {
-
 #if HAVE_DVB_API_VERSION < 3
        secVoltage vlt;
 #else
@@ -3050,6 +3054,7 @@ RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
 {
        if (m_simulate)
                return 0;
+
 #if HAVE_DVB_API_VERSION < 3
        struct secCommand cmd;
        cmd.type = SEC_CMDTYPE_DISEQC_RAW;
@@ -3269,7 +3274,7 @@ bool eDVBFrontend::setSlotInfo(ePyObject obj)
 //                     m_slotid, m_description);
                return false;
        }
-       m_enabled = Enabled == Py_True;
+       m_enabled = (Enabled == Py_True);
        // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
        m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
                !!strstr(m_description, "Alps BSBE2") ||
@@ -3285,8 +3290,9 @@ bool eDVBFrontend::setSlotInfo(ePyObject obj)
                /* HACK for legacy dvb api without DELSYS support */
                m_delsys[SYS_DVBT2] = true;
        }
+
        eDebugNoSimulate("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s, DVB-T2 %s",
-               m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled == Py_True ? "Yes" : "No", IsDVBS2 == Py_True ? "Yes" : "No", IsDVBT2 == Py_True ? "Yes" : "No" );
+               m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", Enabled == Py_True ? "Yes" : "No", IsDVBS2 == Py_True ? "Yes" : "No", IsDVBT2 == Py_True ? "Yes" : "No" );
        return true;
 arg_error:
        PyErr_SetString(PyExc_StandardError,
index 11c5dfd..e6e3aea 100644 (file)
@@ -73,6 +73,7 @@ private:
        DECLARE_REF(eDVBFrontend);
        bool m_simulate;
        bool m_enabled;
+       bool m_fbc;
        eDVBFrontend *m_simulate_fe; // only used to set frontend type in dvb.cpp
        int m_dvbid;
        int m_slotid;
@@ -146,6 +147,7 @@ public:
        static int getTypePriorityOrder() { return PriorityOrder; }
        static void setPreferredFrontend(int index) { PreferredFrontendIndex = index; }
        static int getPreferredFrontend() { return PreferredFrontendIndex; }
+
        bool supportsDeliverySystem(const fe_delivery_system_t &sys, bool obeywhitelist);
        void setDeliverySystemWhitelist(const std::vector<fe_delivery_system_t> &whitelist);
 
@@ -154,6 +156,9 @@ public:
        int closeFrontend(bool force=false, bool no_delayed=false);
        const char *getDescription() const { return m_description; }
        bool is_simulate() const { return m_simulate; }
+       bool is_FBCTuner() { return m_fbc; }
+       bool getEnabled() { return m_enabled; }
+       void setEnabled(bool enable) { m_enabled = enable; }
 };
 
 #endif // SWIG
index febfd78..6f0c9ee 100644 (file)
@@ -268,7 +268,7 @@ void eDVBServicePMTHandler::AITready(int error)
                                std::string boundaryExtension = "";
                                
                                int controlCode = (*i)->getApplicationControlCode();
-                               ApplicationIdentifier * applicationIdentifier = (*i)->getApplicationIdentifier();
+                               const ApplicationIdentifier * applicationIdentifier = (*i)->getApplicationIdentifier();
                                profilecode = 0;
                                orgid = applicationIdentifier->getOrganisationId();
                                appid = applicationIdentifier->getApplicationId();
@@ -285,7 +285,7 @@ void eDVBServicePMTHandler::AITready(int error)
                                                case APPLICATION_DESCRIPTOR:
                                                {
                                                        ApplicationDescriptor* applicationDescriptor = (ApplicationDescriptor*)(*desc);
-                                                       ApplicationProfileList* applicationProfiles = applicationDescriptor->getApplicationProfiles();
+                                                       const ApplicationProfileList* applicationProfiles = applicationDescriptor->getApplicationProfiles();
                                                        ApplicationProfileConstIterator interactionit = applicationProfiles->begin();
                                                        for(; interactionit != applicationProfiles->end(); ++interactionit)
                                                        {
@@ -353,7 +353,7 @@ void eDVBServicePMTHandler::AITready(int error)
                                }
                                if(!hbbtvUrl.empty())
                                {
-                                       char* uu = hbbtvUrl.c_str();
+                                       const char* uu = hbbtvUrl.c_str();
                                        if(!strncmp(uu, "http://", 7) || !strncmp(uu, "dvb://", 6) || !strncmp(uu, "https://", 8))
                                        {
                                                if(controlCode == 1) m_HBBTVUrl = hbbtvUrl;
@@ -420,7 +420,7 @@ void eDVBServicePMTHandler::OCready(int error)
        {
                for (std::vector<OCSection*>::const_iterator it = ptr->getSections().begin(); it != ptr->getSections().end(); ++it)
                {
-                       unsigned char* sectionData = (*it)->getData();
+                       unsigned char* sectionData = (unsigned char*)(*it)->getData();
                }
        }
        /* for now, do not keep listening for table updates */
@@ -571,6 +571,13 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                                                video.type = videoStream::vtMPEG4_H264;
                                                isvideo = 1;
                                                //break; fall through !!!
+                                       case 0x24: // H265 HEVC
+                                               if (!isvideo)
+                                               {
+                                                       video.type = videoStream::vtH265_HEVC;
+                                                       isvideo = 1;
+                                               }
+                                               //break; fall through !!!
                                        case 0x10: // MPEG 4 Part 2
                                                if (!isvideo)
                                                {
index 98ace2b..b15c95b 100644 (file)
@@ -194,7 +194,7 @@ public:
        {
                int pid;
                int component_tag;
-               enum { vtMPEG2, vtMPEG4_H264, vtMPEG1, vtMPEG4_Part2, vtVC1, vtVC1_SM };
+               enum { vtMPEG2, vtMPEG4_H264, vtMPEG1, vtMPEG4_Part2, vtVC1, vtVC1_SM, vtH265_HEVC };
                int type;
        };
        
index fb6f204..969ed9f 100644 (file)
@@ -381,6 +381,7 @@ void eDVBScan::PMTready(int err)
                                switch ((*es)->getType())
                                {
                                case 0x1b: // AVC Video Stream (MPEG4 H264)
+                               case 0x24: // H265 HEVC
                                case 0x10: // MPEG 4 Part 2
                                case 0x01: // MPEG 1 video
                                case 0x02: // MPEG 2 video
index 08976ef..d1567ba 100644 (file)
@@ -49,11 +49,6 @@ eDVBSatelliteEquipmentControl::eDVBSatelliteEquipmentControl(eSmartPtrList<eDVBR
                if (!simulate) \
                        eSecDebug(x); \
        } while(0)
-//             else \
-//             { \
-//                     eDebugNoNewLine("SIMULATE:"); \
-//                     eDebug(x); \
-//             } \
 
 int eDVBSatelliteEquipmentControl::canTune(const eDVBFrontendParametersSatellite &sat, iDVBFrontend *fe, int slot_id, int *highest_score_lnb)
 {
@@ -279,11 +274,6 @@ bool need_turn_fast(int turn_speed)
                if (!simulate) \
                        eDebug(x); \
        } while(0)
-//             else \
-//             { \
-//                     eDebugNoNewLine("SIMULATE:"); \
-//                     eDebug(x); \
-//             } \
 
 RESULT eDVBSatelliteEquipmentControl::prepare(iDVBFrontend &frontend, FRONTENDPARAMETERS &parm, const eDVBFrontendParametersSatellite &sat, int slot_id, unsigned int tunetimeout)
 {
@@ -1166,6 +1156,13 @@ RESULT eDVBSatelliteEquipmentControl::clear()
                it->m_frontend->setData(eDVBFrontend::ROTOR_POS, -1);
                it->m_frontend->setData(eDVBFrontend::ROTOR_CMD, -1);
                it->m_frontend->setData(eDVBFrontend::SATCR, -1);
+
+               if (it->m_frontend->is_FBCTuner())
+               {
+                       eFBCTunerManager *fbcmng = eFBCTunerManager::getInstance();
+                       if (fbcmng)
+                               fbcmng->setDefaultFBCID(*it);
+               }
        }
 
        for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(m_avail_simulate_frontends.begin()); it != m_avail_simulate_frontends.end(); ++it)
@@ -1610,6 +1607,12 @@ RESULT eDVBSatelliteEquipmentControl::setTunerLinked(int tu1, int tu2)
                        char c;
                        p1->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)p2);
                        p2->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)p1);
+
+                       eFBCTunerManager *fbcmng = eFBCTunerManager::getInstance();
+                       if (p1->m_frontend->is_FBCTuner() && fbcmng)
+                       {
+                               fbcmng->updateFBCID(p1, p2);
+                       }
                }
 
                p1=p2=NULL;
index ca3e7f2..d176498 100644 (file)
@@ -4,6 +4,8 @@
 #include <lib/dvb/idvb.h>
 #include <list>
 
+#include <lib/dvb/fbc.h>
+
 #ifndef SWIG
 class eSecCommand
 {
@@ -379,6 +381,8 @@ public:
        void setRotorMoving(int, bool); // called from the frontend's
        bool isRotorMoving();
        bool canMeasureInputPower() { return m_canMeasureInputPower; }
+
+       friend class eFBCTunerManager;
 };
 
 #endif
index fd33298..e0da3eb 100644 (file)
@@ -1,4 +1,5 @@
 #define PNG_SKIP_SETJMP_CHECK
+#include <zlib.h>
 #include <png.h>
 #include <stdio.h>
 #include <lib/gdi/epng.h>
@@ -52,7 +53,7 @@ int loadPNG(ePtr<gPixmap> &result, const char *filename)
                fclose(fp);
                return 0;
         }
-       if (setjmp(png_ptr->jmpbuf))
+       if ( setjmp(png_jmpbuf(png_ptr)) )
        {
                eDebug("das war wohl nix");
                png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
@@ -262,7 +263,7 @@ int savePNG(const char *filename, gPixmap *pixmap)
                PNG_COLOR_TYPE_RGB_ALPHA, 
                PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
 
-       if (setjmp(png_ptr->jmpbuf))
+       if ( setjmp(png_jmpbuf(png_ptr)) )
        {
                eDebug("error :/");
                png_destroy_write_struct(&png_ptr, &info_ptr);
index 2afebd5..ab7a0b5 100644 (file)
@@ -280,7 +280,7 @@ static unsigned char *png_load(const char *file, int *ox, int *oy, int *_bypp)
                return NULL;
        }
 
-       if (setjmp(png_ptr->jmpbuf))
+       if (setjmp(png_jmpbuf(png_ptr)))
        {
                png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
                fclose(fh);
index ca4ef9e..1221f8f 100755 (executable)
@@ -29,6 +29,33 @@ def getProcMounts():
                item[1] = item[1].replace('\\040', ' ')
        return result
 
+def CheckSfdiskVer():
+       cmd = 'sfdisk --version'
+       lines = popen(cmd).readlines()
+       for l in lines:
+               if l.find("sfdisk from util-linux") != -1:
+                       ver = l.split()[-1].strip()
+                       break
+       try:
+               vs = ver.split('.')
+               if len(vs) > 2:
+                       ver = '.'.join(vs[:2])
+
+               ver = float(ver)
+       except:
+               print "[CheckSfdiskVer] check parted version Failed!"
+               return 0
+       return ver
+
+def enableUdevEvent(enable = True):
+       if enable:
+               option = '--start-exec-queue'
+       else:
+               option = '--stop-exec-queue'
+       cmd = "udevadm control %s" % option
+       print "CMD : ", cmd
+       system(cmd)
+
 DEVTYPE_UDEV = 0
 DEVTYPE_DEVFS = 1
 
@@ -225,6 +252,7 @@ class Harddisk:
                                pass
 
                res = system(cmd)
+               print "CMD : ", cmd
                return (res >> 8)
 
         def checkPartionPath(self, path):
@@ -235,6 +263,22 @@ class Harddisk:
                         time.sleep(1)
                 return False
 
+       def updatePartition(self):
+               sfdiskVer = CheckSfdiskVer()
+               if sfdiskVer < 2.26: # sfdisk -R option is deprecated at sfdiskVer >= 2.26
+                       cmd = 'sfdisk -R %s; sleep 5' % (self.disk_path)
+               elif path.exists('/usr/sbin/partprobe'):
+                       cmd = 'partprobe %s; sleep 5' % (self.disk_path)
+               elif path.exists('/usr/sbin/partx'):
+                       cmd = 'partx -u %s' % (self.disk_path)
+               else:
+                       return -1
+
+               print "CMD : ", cmd
+               res = system(cmd)
+
+               return (res >> 8)
+
        def createPartition(self):
                def CheckPartedVer():
                        cmd = 'parted --version'
@@ -260,9 +304,15 @@ class Harddisk:
                        cmd = 'parted %s %s --script mklabel gpt mkpart disk ext2 0%% 100%%' % ( setAlign, self.disk_path )
 
                else:
-                       cmd = 'printf "8,\n;0,0\n;0,0\n;0,0\ny\n" | sfdisk -f -uS ' + self.disk_path
+                       sfdiskVer = CheckSfdiskVer()
+                       if sfdiskVer <= 2.21:
+                               cmd = 'printf "8,\n;0,0\n;0,0\n;0,0\ny\n" | sfdisk -f -uS ' + self.disk_path
+                       else:
+                               cmd = 'printf "8,\nquit\nY\n" | sfdisk -f -uS ' + self.disk_path
 
+               print "CMD : ", cmd
                res = system(cmd)
+
                if not self.checkPartionPath(self.partitionPath("1")):
                        print "no exist : ", self.partitionPath("1")
                        return 1
@@ -273,6 +323,7 @@ class Harddisk:
                if self.diskSize() > 4 * 1024:
                        cmd += "-T largefile "
                cmd += "-m0 -O dir_index " + self.partitionPath("1")
+               print "CMD : ", cmd
                res = system(cmd)
                return (res >> 8)
 
@@ -286,20 +337,33 @@ class Harddisk:
                fstab.close()
 
                res = -1
+               mount_point = None
                for line in lines:
                        parts = line.strip().split(" ")
-                        real_path = path.realpath(parts[0])                                                 
-                        if not real_path[-1].isdigit():                                                     
-                                continue                                                                    
-                        try:                                                                                
-                                if MajorMinor(real_path) == MajorMinor(self.partitionPath(real_path[-1])):
-                                       cmd = "mount -t ext3 " + parts[0]
-                                       res = system(cmd)
+                       real_path = path.realpath(parts[0])
+                       if not real_path[-1].isdigit():
+                               continue
+                       try:
+                               if MajorMinor(real_path) == MajorMinor(self.partitionPath(real_path[-1])):
+                                       mount_point = parts[0]
                                        break
                        except OSError:
                                pass
 
-               return (res >> 8)
+               if mount_point is None:
+                       return 0
+
+               cmd = "mount -t ext3 " + mount_point
+               print "CMD : ", cmd
+               res = system(cmd)
+
+               if (res >> 8) != 0:
+                       return -3
+
+               if self.createMovieFolder() != 0:
+                       return -4
+
+               return 0
 
        def createMovieFolder(self):
                try:
@@ -324,15 +388,17 @@ class Harddisk:
 
                if access(part, 0):
                        cmd = 'dd bs=512 count=3 if=/dev/zero of=' + part
+                       print "CMD : ", cmd
                        res = system(cmd)
                else:
                        res = 0
 
                return (res >> 8)
 
-       errorList = [ _("Everything is fine"), _("Creating partition failed"), _("Mkfs failed"), _("Mount failed"), _("Create movie folder failed"), _("Fsck failed"), _("Please Reboot"), _("Filesystem contains uncorrectable errors"), _("Unmount failed")]
+       errorList = [ _("Everything is fine"), _("Creating partition failed"), _("Mkfs failed"), _("Mount failed"), _("Create movie folder failed"), _("Fsck failed"), _("Please Reboot"), _("Filesystem contains uncorrectable errors"), _("Unmount failed"), _("partx failed")]
 
        def initialize(self):
+               enableUdevEvent(False)
                self.unmount()
 
                # Udev tries to mount the partition immediately if there is an
@@ -342,19 +408,23 @@ class Harddisk:
                # ext3 at least.
                self.killPartition("1")
 
-               if self.createPartition() != 0:
-                       return -1
+               if self.updatePartition() != 0:
+                       res = -9
 
-               if self.mkfs() != 0:
-                       return -2
+               elif self.createPartition() != 0:
+                       res = -1
 
-               if self.mount() != 0:
-                       return -3
+               elif self.updatePartition() != 0:
+                       res = -9
 
-               if self.createMovieFolder() != 0:
-                       return -4
+               elif self.mkfs() != 0:
+                       res = -2
 
-               return 0
+               else:
+                       res = self.mount()
+
+               enableUdevEvent(True)
+               return res
 
        def check(self):
                self.unmount()
@@ -571,7 +641,7 @@ class HarddiskManager:
                try:
                        removable = bool(int(readFile(devpath + "/removable")))
                        dev = int(readFile(devpath + "/dev").split(':')[0])
-                       if dev in (7, 31): # loop, mtdblock
+                       if dev in (7, 31, 179): # loop, mtdblock, mmcblock
                                blacklisted = True
                        if blockdev[0:2] == 'sr':
                                is_cdrom = True
index ce063b4..2a40aed 100755 (executable)
@@ -59,10 +59,10 @@ class SecConfigure:
                sec.setLNBLOFL(9750000)
                sec.setLNBLOFH(10600000)
                sec.setLNBThreshold(11700000)
-               sec.setLNBIncreasedVoltage(lnbParam.OFF)
+               sec.setLNBIncreasedVoltage(False)
                sec.setRepeats(0)
                sec.setFastDiSEqC(fastDiSEqC)
-               sec.setSeqRepeat(0)
+               sec.setSeqRepeat(False)
                sec.setCommandOrder(0)
 
                #user values
@@ -369,9 +369,9 @@ class SecConfigure:
 #                                      pass # nyi in drivers
 
                                if currLnb.increased_voltage.value:
-                                       sec.setLNBIncreasedVoltage(lnbParam.ON)
+                                       sec.setLNBIncreasedVoltage(True)
                                else:
-                                       sec.setLNBIncreasedVoltage(lnbParam.OFF)
+                                       sec.setLNBIncreasedVoltage(False)
 
                                dm = currLnb.diseqcMode.value
                                if dm == "none":
@@ -1116,7 +1116,7 @@ def InitSecParams():
 # the C(++) part should can handle this
 # the configElement should be only visible when diseqc 1.2 is disabled
 
-def InitNimManager(nimmgr):
+def InitNimManager(nimmgr, update_slots = []):
        hw = HardwareInfo()
        addNimConfig = False
        try:
@@ -1646,6 +1646,9 @@ def InitNimManager(nimmgr):
                x = slot.slot
                nim = config.Nims[x]
 
+               if update_slots and (x not in update_slots):
+                       continue
+
                if slot.isCompatible("DVB-S"):
                        createSatConfig(nim, x, empty_slots)
                        config_mode_choices = [ ("nothing", _("nothing connected")),
index cd055a8..3930c07 100644 (file)
@@ -113,6 +113,16 @@ class ServiceList(HTMLComponent, GUIComponent):
                self.l.getCurrent(r)
                return r
 
+       def getPrev(self):
+               r = eServiceReference()
+               self.l.getPrev(r)
+               return r
+
+       def getNext(self):
+               r = eServiceReference()
+               self.l.getNext(r)
+               return r
+
        def atBegin(self):
                return self.instance.atBegin()
 
index 8d8805f..821fe1d 100644 (file)
@@ -3,10 +3,6 @@ installdir = $(pkglibdir)/python/Plugins/Extensions/DLNAServer
 SUBDIRS = meta 
 
 install_PYTHON = \
-       dlnaserver \
        __init__.py \
        plugin.py 
 
-install-data-hook:
-       @chmod +x $(DESTDIR)$(installdir)/dlnaserver
-
diff --git a/lib/python/Plugins/Extensions/DLNAServer/dlnaserver b/lib/python/Plugins/Extensions/DLNAServer/dlnaserver
deleted file mode 100755 (executable)
index 4fad9ab..0000000
Binary files a/lib/python/Plugins/Extensions/DLNAServer/dlnaserver and /dev/null differ
index 9dd4299..d94b791 100755 (executable)
@@ -1,7 +1,7 @@
 installdir = $(pkglibdir)/python/Plugins/Extensions
 
 SUBDIRS = TuxboxPlugins CutListEditor PicturePlayer MediaScanner MediaPlayer GraphMultiEPG SocketMMI DVDBurn Modem WebBrowser \
-       StreamTV DLNABrowser DLNAServer HbbTV BackupSuiteUSB BackupSuiteHDD SatipClient
+       StreamTV DLNABrowser DLNAServer HbbTV BackupSuiteUSB BackupSuiteHDD SatipClient MiniTV
 
 if HAVE_LIBDDVD
 SUBDIRS += DVDPlayer
diff --git a/lib/python/Plugins/Extensions/MiniTV/Makefile.am b/lib/python/Plugins/Extensions/MiniTV/Makefile.am
new file mode 100644 (file)
index 0000000..98f2931
--- /dev/null
@@ -0,0 +1,7 @@
+installdir = $(pkglibdir)/python/Plugins/Extensions/MiniTV
+
+SUBDIRS = meta
+
+install_PYTHON =       \
+       __init__.py \
+       plugin.py
diff --git a/lib/python/Plugins/Extensions/MiniTV/__init__.py b/lib/python/Plugins/Extensions/MiniTV/__init__.py
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/lib/python/Plugins/Extensions/MiniTV/meta/Makefile.am b/lib/python/Plugins/Extensions/MiniTV/meta/Makefile.am
new file mode 100644 (file)
index 0000000..2d31de6
--- /dev/null
@@ -0,0 +1,3 @@
+installdir = $(datadir)/meta
+
+dist_install_DATA = plugin_minitv.xml
diff --git a/lib/python/Plugins/Extensions/MiniTV/meta/plugin_minitv.xml b/lib/python/Plugins/Extensions/MiniTV/meta/plugin_minitv.xml
new file mode 100644 (file)
index 0000000..d7dbe58
--- /dev/null
@@ -0,0 +1,17 @@
+<default>
+         <prerequisites>
+                    <tag type="Display" />
+                    <tag type="System" />
+         </prerequisites>
+          <info>
+                    <author>hschang</author>
+                    <name>MiniTV</name>
+                    <packagename>enigma2-plugin-extensions-minitv</packagename>
+                    <shortdescription>Support MiniTV of your VU+</shortdescription>
+                    <description>Support MiniTV of your VU+</description>
+          </info>
+
+         <files type="package"> <!-- without version, without .ipk -->
+               <file type="package" name="enigma2-plugin-extensions-minitv" />
+       </files>
+</default>
diff --git a/lib/python/Plugins/Extensions/MiniTV/plugin.py b/lib/python/Plugins/Extensions/MiniTV/plugin.py
new file mode 100644 (file)
index 0000000..1bf8a4a
--- /dev/null
@@ -0,0 +1,66 @@
+from Plugins.Plugin import PluginDescriptor
+from Components.PluginComponent import plugins
+from Components.config import config, ConfigSubsection, ConfigSelection
+from enigma import eDBoxLCD
+
+config.plugins.minitv = ConfigSubsection()
+config.plugins.minitv.enable = ConfigSelection(default = "disable", choices = [ ("enable", "enable"), ("disable", "disable")])
+
+class MiniTV:
+       def __init__(self):
+               config.plugins.minitv.enable.addNotifier(self.miniTVChanged, initial_call = True)
+               config.misc.standbyCounter.addNotifier(self.standbyCounterChanged, initial_call = False)
+
+       def getExtensionName(self):
+               if config.plugins.minitv.enable.value == "enable":
+                       return _("Disable MiniTV")
+
+               return _("Enable MiniTV")
+
+       def showMiniTV(self):
+               old_value = config.plugins.minitv.enable.value
+               config.plugins.minitv.enable.value = (old_value == "enable") and "disable" or "enable"
+               config.plugins.minitv.enable.save()
+
+       def miniTVChanged(self, configElement):
+               self.setMiniTV(configElement.value)
+
+       def setMiniTV(self, value):
+               cur_value = open("/proc/stb/lcd/live_enable", "r").read().strip()
+               if cur_value != value:
+                       open("/proc/stb/lcd/live_enable", "w").write(value)
+
+       def standbyCounterChanged(self, configElement):
+               from Screens.Standby import inStandby
+               if self.leaveStandby not in inStandby.onClose:
+                       inStandby.onClose.append(self.leaveStandby)
+
+               self.setMiniTV("disable")
+
+       def leaveStandby(self):
+               self.setMiniTV(config.plugins.minitv.enable.value)
+
+minitv_instance = MiniTV()
+
+def addExtentions(infobarExtensions):
+       infobarExtensions.addExtension((minitv_instance.getExtensionName, minitv_instance.showMiniTV, lambda: True), None)
+
+def autoStart(reason, **kwargs):
+       if reason == 1:
+               minitv_instance.setMiniTV("standby")
+
+def Plugins(**kwargs):
+       list = []
+       list.append(
+               PluginDescriptor(name="MiniTV",
+               description="MiniTV",
+               where = [PluginDescriptor.WHERE_EXTENSIONSINGLE],
+               fnc = addExtentions))
+
+       list.append(
+               PluginDescriptor(
+               where = [PluginDescriptor.WHERE_AUTOSTART],
+               fnc = autoStart))
+
+       return list
+
index d87e6e9..2137d0e 100755 (executable)
@@ -60,6 +60,12 @@ 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
+
 
        def __init__(self, name = "Plugin", where = [ ], description = "", icon = None, fnc = None, wakeupfnc = None, needsRestart = None, internal = False, weight = 0):
                self.name = name
diff --git a/lib/python/Plugins/SystemPlugins/3GModemManager/3gcommand b/lib/python/Plugins/SystemPlugins/3GModemManager/3gcommand
deleted file mode 100755 (executable)
index ae61799..0000000
Binary files a/lib/python/Plugins/SystemPlugins/3GModemManager/3gcommand and /dev/null differ
index 962f84c..0ac90e0 100644 (file)
@@ -5,9 +5,5 @@ SUBDIRS = meta script
 install_PYTHON = \
        __init__.py \
        plugin.py \
-       apnlist.xml \
-       3gcommand 
-
-install-data-hook:
-       @chmod +x $(DESTDIR)$(installdir)/3gcommand
+       apnlist.xml
 
index 40a349e..82ce819 100644 (file)
@@ -149,9 +149,7 @@ class Blindscan(ConfigListScreen, Screen):
                else:   self.i2c_mapping_table = {0:2, 1:3, 2:1, 3:0}
 
        def getNimSocket(self, slot_number):
-               if slot_number < 0 or slot_number > 3:
-                       return -1
-               return self.i2c_mapping_table[slot_number]
+               return self.i2c_mapping_table.get(slot_number, -1)
 
        def keyNone(self):
                None
diff --git a/lib/python/Plugins/SystemPlugins/BoxModeConfig/Makefile.am b/lib/python/Plugins/SystemPlugins/BoxModeConfig/Makefile.am
new file mode 100755 (executable)
index 0000000..a7c22ea
--- /dev/null
@@ -0,0 +1,7 @@
+installdir = $(pkglibdir)/python/Plugins/SystemPlugins/BoxModeConfig
+
+SUBDIRS = meta
+
+install_PYTHON = \
+       __init__.py \
+       plugin.py
diff --git a/lib/python/Plugins/SystemPlugins/BoxModeConfig/__init__.py b/lib/python/Plugins/SystemPlugins/BoxModeConfig/__init__.py
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/lib/python/Plugins/SystemPlugins/BoxModeConfig/meta/Makefile.am b/lib/python/Plugins/SystemPlugins/BoxModeConfig/meta/Makefile.am
new file mode 100755 (executable)
index 0000000..8cd9a96
--- /dev/null
@@ -0,0 +1,3 @@
+installdir = $(datadir)/meta
+
+dist_install_DATA = plugin_boxmodeconfig.xml
diff --git a/lib/python/Plugins/SystemPlugins/BoxModeConfig/meta/plugin_boxmodeconfig.xml b/lib/python/Plugins/SystemPlugins/BoxModeConfig/meta/plugin_boxmodeconfig.xml
new file mode 100755 (executable)
index 0000000..67ce9d4
--- /dev/null
@@ -0,0 +1,16 @@
+<default>
+         <prerequisites>
+                    <tag type="System" />
+         </prerequisites>
+          <info>
+                    <author>hschang</author>
+                    <name>BoxModeConfig</name>
+                    <packagename>enigma2-plugin-systemplugins-boxmodeconfig</packagename>
+                    <shortdescription>configuration boxmode.</shortdescription>
+                    <description>configuration boxmode.</description>
+          </info>
+
+         <files type="package"> <!-- without version, without .ipk -->
+               <file type="package" name="enigma2-plugin-systemplugins-boxmodeconfig" />
+       </files>
+</default>
diff --git a/lib/python/Plugins/SystemPlugins/BoxModeConfig/plugin.py b/lib/python/Plugins/SystemPlugins/BoxModeConfig/plugin.py
new file mode 100755 (executable)
index 0000000..abda052
--- /dev/null
@@ -0,0 +1,121 @@
+from Screens.Screen import Screen
+from Components.ConfigList import ConfigListScreen
+from Components.config import ConfigSelection, getConfigListEntry
+from Components.Sources.StaticText import StaticText
+from Screens.MessageBox import MessageBox
+from Screens.Standby import TryQuitMainloop
+import os
+
+BOXMODE_BINNAME = "/usr/bin/nvram"
+
+description_list = {}
+description_list["1"] = "current box mode : 1"
+description_list["2"] = "current box mode : 2"
+description_list["3"] = "current box mode : 3"
+description_list["4"] = "current box mode : 4"
+description_list["5"] = "current box mode : 5"
+
+class BoxModeConfig(Screen, ConfigListScreen):
+       skin =  """
+               <screen position="center,center" size="400,190" title="BoxModeConfig" >
+                       <ePixmap pixmap="skin_default/buttons/red.png" position="30,10" size="140,40" alphatest="on" />
+                       <ePixmap pixmap="skin_default/buttons/green.png" position="230,10" size="140,40" alphatest="on" />
+
+                       <widget source="key_red" render="Label" position="30,10" 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="230,10" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" foregroundColor="#ffffff" transparent="1" />
+
+                       <widget name="config" zPosition="2" position="5,70" size="380,90" scrollbarMode="showOnDemand" transparent="1" />
+                       <widget source="description" render="Label" position="30,160" size="380,30" font="Regular;24" halign="center" valign="center" />
+               </screen>
+               """
+
+       def __init__(self, session):
+               self.skin = BoxModeConfig.skin
+               Screen.__init__(self, session)
+
+               from Components.ActionMap import ActionMap
+               from Components.Button import Button
+               self["key_red"] = StaticText(_("Cancel"))
+               self["key_green"] = StaticText(_("Save"))
+               self["description"] = StaticText(_("starting..."))
+
+               self["actions"] = ActionMap(["SetupActions", "ColorActions"],
+               {
+                       "ok": self.keyOk,
+                       "save": self.keyOk,
+                       "cancel": self.keyCancel,
+                       "green": self.keyOk,
+                       "red": self.keyCancel,
+               }, -2)
+
+               self.list = []
+               ConfigListScreen.__init__(self, self.list, session = self.session)
+               setmodelist = [ ("1", "1 "), ("2", "2 "), ("3", "3 "), ("4", "4 "), ("5", "5 ") ]
+               self.oldconfig = self.getCurrentValue()
+               self.boxmode = ConfigSelection(choices = setmodelist, default = self.oldconfig)
+               self.list.append(getConfigListEntry(_("BoxMode : "), self.boxmode))
+               self["config"].list = self.list
+               self["config"].l.setList(self.list)
+
+               if not self.showDescription in self["config"].onSelectionChanged:
+                       self["config"].onSelectionChanged.append(self.showDescription)
+
+       def getCurrentValue(self):
+               global BOXMODE_BINNAME
+               cmd = "%s getenv BOXMODE" % (BOXMODE_BINNAME)
+               print "CMD : ", cmd
+               current_value = os.popen(cmd).read().strip()
+               try:
+                       if int(current_value) < 1:
+                               current_value = "1"
+                       elif int(current_value) > 5:
+                               current_value = "5"
+               except:
+                       print '%s -> failed, force to set "3"' % cmd
+                       current_value = "3"
+               return current_value
+
+       def showDescription(self):
+               global description_list
+               current_value = self["config"].getCurrent()[1].value
+               if current_value:
+                       text = description_list[current_value]
+                       self["description"].setText( _(text) )
+
+       def keyLeft(self):
+               ConfigListScreen.keyLeft(self)
+               self.showDescription()
+
+       def keyRight(self):
+               ConfigListScreen.keyRight(self)
+               self.showDescription()
+
+       def keyOk(self):
+               current_value = self["config"].getCurrent()[1].value
+               if self.oldconfig != current_value:             
+                       cmd = "%s setenv BOXMODE %s" % (BOXMODE_BINNAME, current_value)
+                       print "CMD : ", cmd
+                       os.system(cmd)
+
+                       msg = "You should reboot your STB now.\n Press OK Button."
+                       self.session.openWithCallback(self.doReboot, MessageBox, _(msg), type = MessageBox.TYPE_INFO)
+               else:
+                       self.close()
+
+       def doReboot(self, res = None):
+               self.session.open(TryQuitMainloop, 2)
+
+       def keyCancel(self):
+               self.close()
+
+def main(session, **kwargs):
+       session.open(BoxModeConfig)
+
+def Plugins(**kwargs):
+       descriptors = []
+       from os import path
+       global BOXMODE_BINNAME
+       if path.exists(BOXMODE_BINNAME):
+               from Plugins.Plugin import PluginDescriptor
+               descriptors.append(PluginDescriptor(name = "BoxModeConfig", description = _("BoxMode Configuration."), where = PluginDescriptor.WHERE_PLUGINMENU, fnc = main))
+       return descriptors
\ No newline at end of file
index 6d5860f..41c6905 100755 (executable)
@@ -4,7 +4,7 @@ from Components.config import config, ConfigSelection, getConfigListEntry, Confi
 from Components.ConfigList import ConfigListScreen
 from Components.Console import Console
 from Components.GUIComponent import GUIComponent
-from Components.Harddisk import harddiskmanager
+from Components.Harddisk import harddiskmanager, CheckSfdiskVer, enableUdevEvent
 from Components.MenuList import MenuList
 from Components.Pixmap import Pixmap, MultiPixmap
 from Components.Sources.List import List
@@ -549,8 +549,10 @@ class DeviceInit(Screen):
                self.maxPartNum = 4
                self.inputbox_partitionSizeRemain = self.inputbox_partitionSizeTotal
                self.unit = "MB"
+               self.onClose.append(enableUdevEvent)
 
        def timerStart(self):
+               enableUdevEvent(False)
                self.initStartTimer.start(100,True)
 
        def confirmMessage(self):
@@ -680,62 +682,66 @@ class DeviceInit(Screen):
                        try:
                                ver = float(ver)
                        except:
-                               print "[CheckPartedVer] check parted version Failed!"
+                               print "[DeviceManager] check parted version Failed!"
                                return 0
                        return ver
 
                partitions = len(self.inputbox_partitionSizeList) # get num of partition
                set = ""
-               if self.partitionType == "MBR":
-                       if partitions == 1:
-                               cmd = 'printf "8,\n;0,0\n;0,0\n;0,0\ny\n" | sfdisk -f -uS /dev/' + self.device
+
+               setAlign = ""
+               partedVer = CheckPartedVer()
+               if partedVer >= 2.1: # align option is supported in version 2.1 or later
+                       setAlign = "--align optimal"
+                       if self.devicesize < 1024 * 1000 * 1000: # 1GB
+                               setAlign = "-a min"
                        else:
-                               for p in range(4):
-                                       if partitions > p+1:
-                                               set += ",%s\n"%(self.inputbox_partitionSizeList[p])
-                                       else:
-                                               set +=";\n"
-                               set+="y\n"
-                               cmd = 'printf "%s" | sfdisk -f -uM /dev/%s'%(set,self.device)
-
-               elif self.partitionType == "GPT": # partition type is GPT
-                       setAlign = ""
-                       partedVer = CheckPartedVer()
-                       if partedVer >= 2.1: # align option is supported in version 2.1 or later
-                               setAlign = "--align optimal"
-
-                       if partitions == 1:
-                               cmd = 'parted %s /dev/%s --script mklabel gpt mkpart disk ext2 0%% 100%%' % (setAlign, self.device)
-                       else: # has multiple partitions
-                               p_current = 0
-                               for p in range(partitions):
-                                       if p == 0:
-                                               p_start = p_current
-                                               p_end = int( (long(self.inputbox_partitionSizeList[p]) * 100) / 100 )
-                                               p_current = p_end
-                                       elif p > 0 and partitions > (p + 1):
-                                               p_start = p_current
-                                               p_end = int( (long(self.inputbox_partitionSizeList[p]) * 100) / 100 )+ p_start
-                                               p_current = p_end
-                                       elif partitions == (p + 1):
-                                               p_start = p_current
-                                               p_end = 100
-                                       if p_start == p_end:
-                                               p_end +=1
-                                       if p_end > 100:
-                                               continue
-                                       set += 'mkpart disk%d ext2 %d%% %d%% ' % (p + 1, p_start, p_end)
-                               cmd = 'parted %s /dev/%s --script mklabel gpt %s' % (setAlign, self.device, set)
+                               setAlign = "-a opt"
+
+               if self.partitionType == "GPT": # partition type is GPT
+                       parttype = 'gpt'
                else:
-                       errorMsg = "Invalid partitioning type"
-                       self.msgWaiting.run_close(False, errorMsg)
-                       return
+                       parttype = 'msdos'
+
+               if partitions == 1:
+                       cmd = 'parted %s /dev/%s --script mklabel %s mkpart primary 0%% 100%%' % (setAlign, self.device, parttype)
+               else: # has multiple partitions
+                       p_current = 0
+                       for p in range(partitions):
+                               if p == 0:
+                                       p_start = p_current
+                                       p_end = int( (long(self.inputbox_partitionSizeList[p]) * 100) / self.inputbox_partitionSizeTotal )
+                                       p_current = p_end
+                               elif p > 0 and partitions > (p + 1):
+                                       p_start = p_current
+                                       p_end = int( (long(self.inputbox_partitionSizeList[p]) * 100) / self.inputbox_partitionSizeTotal )+ p_start
+                                       p_current = p_end
+                               elif partitions == (p + 1):
+                                       p_start = p_current
+                                       p_end = 100
+
+                               if p_start == p_end:
+                                       p_end +=1
+                               if p_end > 100:
+                                       continue
+
+                               set += 'mkpart primary ext2 %d%% %d%% ' % (p_start, p_end)
+                       cmd = 'parted %s /dev/%s --script mklabel %s %s' % (setAlign, self.device, parttype, set)
+
                self.deviceInitConsole.ePopen(cmd, self.initInitializeFinished)
 
        def initInitializeFinished(self, result, retval, extra_args = None):
                if retval == 0:
                        if self.partitionType == "MBR":
-                               cmd = "sfdisk -R /dev/%s ; sleep 5" % (self.device)
+                               sfdiskVer = CheckSfdiskVer()
+                               if sfdiskVer < 2.26: # sfdisk -R option is deprecated at sfdiskVer >= 2.26
+                                       cmd = 'sfdisk -R /dev/%s; sleep 5' % (self.device)
+                               elif path.exists('/usr/sbin/partprobe'):
+                                       cmd = 'partprobe /dev/%s; sleep 5' % (self.device)
+                               elif path.exists('/usr/sbin/partx'):
+                                       cmd = 'partx -u /dev/%s; sleep 5' % (self.device)
+                               else:
+                                       cmd = 'sfdisk -R /dev/%s; sleep 5' % (self.device)
                        else: # is GPT
                                cmd = "sleep 5"
                        self.deviceInitConsole.ePopen(cmd, self.initInitializingRefreshFinished)
@@ -780,25 +786,25 @@ class DeviceInit(Screen):
                partitions.close()
 
                if self.fstype == "ext4":
-                       cmd = "/sbin/mkfs.ext4 -F "
+                       cmd = "mkfs.ext4 -F "
                        if partitionsize > 2 * 1024 * 1024: # 2GB
                                cmd += "-T largefile "
                        cmd += "-O extent,flex_bg,large_file,uninit_bg -m1 " + fulldevicename
                elif self.fstype == "ext3":
-                       cmd = "/sbin/mkfs.ext3 -F "
+                       cmd = "mkfs.ext3 -F "
                        if partitionsize > 2 * 1024 * 1024:
                                cmd += "-T largefile "
                        cmd += "-m0 " + fulldevicename
                elif self.fstype == "ext2":
-                       cmd = "/sbin/mkfs.ext2 -F "
+                       cmd = "mkfs.ext2 -F "
                        if partitionsize > 2 * 1024 * 1024:
                                cmd += "-T largefile "
                        cmd += "-m0 " + fulldevicename
                elif self.fstype == "vfat":
                        if partitionsize > 4 * 1024 * 1024 * 1024:
-                               cmd = "/usr/sbin/mkfs.vfat -I -S4096 " + fulldevicename
+                               cmd = "mkfs.vfat -I -S4096 " + fulldevicename
                        else:
-                               cmd = "/usr/sbin/mkfs.vfat -I " + fulldevicename
+                               cmd = "mkfs.vfat -I " + fulldevicename
                                if partitionsize > 2 * 1024 * 1024: # if partiton size larger then 2GB, use FAT32
                                        cmd += " -F 32"
 
@@ -990,8 +996,10 @@ class DeviceFormat(Screen):
                self.setHotplugDisabled = False
                self.umountTimer = eTimer()
                self.umountTimer.callback.append(self.doUnmount)
+               self.onClose.append(enableUdevEvent)
 
        def timerStart(self):
+               enableUdevEvent(False)
                self.formatStartTimer.start(100,True)
 
        def DeviceFormatStart(self):
@@ -1041,7 +1049,12 @@ class DeviceFormat(Screen):
                        if oldfstype == newfstype:
                                self.changePartitionIDFinished("NORESULT", 0)
                        else:
-                               cmd = "sfdisk --change-id /dev/%s %s" % (partition[:3], partition[3:])
+                               sfdiskVer = CheckSfdiskVer()
+                               if sfdiskVer >= 2.26:
+                                       cmd = "sfdisk --part-type /dev/%s %s" % (partition[:3], partition[3:])
+                               else:
+                                       cmd = "sfdisk --change-id /dev/%s %s" % (partition[:3], partition[3:])
+
                                if newfstype[:3] == "ext":
                                        cmd += " 83"
                                else:
@@ -1060,7 +1073,16 @@ class DeviceFormat(Screen):
                        if oldfstype == newfstype:
                                self.refreshPartitionFinished("NORESULT", 0)
                        else:
-                               cmd = "sfdisk -R /dev/%s; sleep 5"%(device)
+                               sfdiskVer = CheckSfdiskVer()
+                               if sfdiskVer < 2.26: # sfdisk -R option is deprecated at sfdiskVer >= 2.26
+                                       cmd = "sfdisk -R /dev/%s; sleep 5" % (device)
+                               elif path.exists('/usr/sbin/partprobe'):
+                                       cmd = 'partprobe /dev/%s; sleep 5' % (device)
+                               elif path.exists('/usr/sbin/partx'):
+                                       cmd = 'partx -u /dev/%s; sleep 5' % (device)
+                               else:
+                                       cmd = "sfdisk -R /dev/%s; sleep 5" % (device)
+
                                self.deviceFormatConsole.ePopen(cmd, self.refreshPartitionFinished)
                else:
                        if result and result.find("Use GNU Parted") > 0:
@@ -1079,25 +1101,25 @@ class DeviceFormat(Screen):
                newfstype = self.newfstype
                if retval == 0:
                        if newfstype == "ext4":
-                               cmd = "/sbin/mkfs.ext4 -F "
+                               cmd = "mkfs.ext4 -F "
                                if size > 2 * 1024:
                                        cmd += "-T largefile "
                                cmd += "-O extent,flex_bg,large_file,uninit_bg -m1 /dev/" + partition
                        elif newfstype == "ext3":
-                               cmd = "/sbin/mkfs.ext3 -F "
+                               cmd = "mkfs.ext3 -F "
                                if size > 2 * 1024:
                                        cmd += "-T largefile "
                                cmd += "-m0 /dev/" + partition
                        elif newfstype == "ext2":
-                               cmd = "/sbin/mkfs.ext2 -F "
+                               cmd = "mkfs.ext2 -F "
                                if size > 2 * 1024:
                                        cmd += "-T largefile "
                                cmd += "-m0 /dev/" + partition
                        elif newfstype == "vfat":
                                if size > 4 * 1024 * 1024:
-                                       cmd = "/usr/sbin/mkfs.vfat -I -S4096 /dev/" + partition
+                                       cmd = "mkfs.vfat -I -S4096 /dev/" + partition
                                else:
-                                       cmd = "/usr/sbin/mkfs.vfat -I /dev/" + partition
+                                       cmd = "mkfs.vfat -I /dev/" + partition
                                        if size > 2 * 1024: # if partiton size larger then 2GB, use FAT32
                                                cmd += " -F 32"
                        self.deviceFormatConsole.ePopen(cmd, self.mkfsFinished)
@@ -1668,6 +1690,28 @@ class deviceManagerHotplug:
                        self.doMount(uuid, devpath, mountpoint, filesystem)
 
        def removeHotplugDevice(self, partition):
+               device = partition.device
+               devpath = "/dev/"+device
+# get BlkidInfo
+               (uuid, filesystem) = deviceinfo.getPartitionBlkidInfo(device)
+               if uuid == "":
+# retry..
+                       os.system("sleep 1")
+                       (uuid, filesystem) = deviceinfo.getPartitionBlkidInfo(device)
+               if uuid == "":
+                       print "[DeviceManagerHotplug] getBlkidInfo failed!"
+                       return
+# get configList
+               devicemanagerconfig.loadConfig()
+               configList = devicemanagerconfig.getConfigList()
+               mountpoint = None
+               for line in configList:
+                       if uuid == line[0].strip():
+                               mountpoint = line[1].strip()
+                               break
+               if mountpoint is None:
+                       return
+# do umount
                self.doUmount(partition.device, partition.mountpoint)
 
        def getHotplugAction(self, action, partition):
diff --git a/lib/python/Plugins/SystemPlugins/FastZapSupport/Makefile.am b/lib/python/Plugins/SystemPlugins/FastZapSupport/Makefile.am
new file mode 100644 (file)
index 0000000..fd9599d
--- /dev/null
@@ -0,0 +1,7 @@
+installdir = $(pkglibdir)/python/Plugins/SystemPlugins/FastZapSupport
+
+SUBDIRS = meta
+
+install_PYTHON =       \
+       __init__.py \
+       plugin.py
diff --git a/lib/python/Plugins/SystemPlugins/FastZapSupport/__init__.py b/lib/python/Plugins/SystemPlugins/FastZapSupport/__init__.py
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/lib/python/Plugins/SystemPlugins/FastZapSupport/meta/Makefile.am b/lib/python/Plugins/SystemPlugins/FastZapSupport/meta/Makefile.am
new file mode 100644 (file)
index 0000000..78678fe
--- /dev/null
@@ -0,0 +1,3 @@
+installdir = $(datadir)/meta
+
+dist_install_DATA = plugin_fastzapsupport.xml
diff --git a/lib/python/Plugins/SystemPlugins/FastZapSupport/meta/plugin_fastzapsupport.xml b/lib/python/Plugins/SystemPlugins/FastZapSupport/meta/plugin_fastzapsupport.xml
new file mode 100644 (file)
index 0000000..064496e
--- /dev/null
@@ -0,0 +1,16 @@
+<default>
+         <prerequisites>
+                    <tag type="System" />
+         </prerequisites>
+          <info>
+                    <author>hschang</author>
+                    <name>FastZapSupport</name>
+                    <packagename>enigma2-plugin-systemplugins-fastzapsupport</packagename>
+                    <shortdescription>Support FastZapping of your VU+</shortdescription>
+                    <description>Support FastZapping of your VU+</description>
+          </info>
+
+         <files type="package"> <!-- without version, without .ipk -->
+               <file type="package" name="enigma2-plugin-systemplugins-fastzapsupport" />
+       </files>
+</default>
diff --git a/lib/python/Plugins/SystemPlugins/FastZapSupport/plugin.py b/lib/python/Plugins/SystemPlugins/FastZapSupport/plugin.py
new file mode 100644 (file)
index 0000000..542531e
--- /dev/null
@@ -0,0 +1,488 @@
+
+from Plugins.Plugin import PluginDescriptor
+import NavigationInstance
+
+from Tools import Notifications
+from Screens.MessageBox import MessageBox
+
+from enigma import iPlayableService, iServiceInformation, eEnv
+
+import struct
+import os
+import re
+
+from Components.NimManager import nimmanager
+from Components.config import ConfigNothing, config
+
+from Components.ServiceEventTracker import ServiceEventTracker
+
+from enigma import iPlayableService
+from Screens.InfoBar import InfoBar
+
+fast_zap_support = None
+
+LANEDB_PATH = eEnv.resolve("${sysconfdir}/enigma2/") + "lamedb"
+
+FAVOURITES_PATH = eEnv.resolve("${sysconfdir}/enigma2/") + "userbouquet.favourites.tv"
+
+PROC_FBC_PATH = "/proc/stb/frontend/fbc"
+
+#PROC_FBC_PATH = "/home/root/fbc"
+
+def strToHex(s):
+               return hex(int(s, 16))
+
+class FastZapSupport:
+       def __init__(self, session):
+               self.session = session
+               self.onClose = [ ] # hack
+
+               self.channelList = []
+#              self.srefList = []
+               self.channelData = []
+               self.procData = {}
+
+               self.parseChannelDB()
+               srefList = self.getSrefList()
+               self.channelData = self.makeChannelData(srefList)
+
+               self.parseNimConfiguration()
+               self.writeDataProc(self.channelData)
+
+               self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+               {
+                       iPlayableService.evStart: self.serviceStarted,
+               })
+
+       def serviceStarted(self):
+               if InfoBar.instance:
+                       channelList = InfoBar.instance.servicelist
+
+                       prevService = channelList.servicelist.getPrev().toString()
+                       curService = channelList.servicelist.getCurrent().toString()
+                       nextService = channelList.servicelist.getNext().toString()
+                       
+#                      print "[FastZapSupport] PREV : ", prevService
+#                      print "[FastZapSupport] CUR : ", curService
+#                      print "[FastZapSupport] NEXT : ", nextService
+
+                       srefList = []
+                       srefList.append(prevService)
+                       srefList.append(nextService)
+
+                       # sref
+                       # type:flags:stype:sid:tsid:onid:namespace:psid:ptsid:
+
+                       channelData = self.makeChannelData(srefList)
+                       self.writeDataProc(channelData)
+
+       def python_scanf(self, my_str, pattern):
+               D = ('%d',      '(\d+?)')
+               F = ('%f', '(\d+\.\d+?)')
+               S = ('%s',       '(.+?)')
+               re_pattern = pattern.replace(*D).replace(*F).replace(*S)
+               match = re.match(re_pattern, my_str)
+               if match:
+                       return match.groups()
+               raise ValueError("String doesn't match pattern")
+
+       def parseChannelDB(self):
+               global LANEDB_PATH
+
+               if not os.access(LANEDB_PATH, os.R_OK):
+                       return
+
+               channelList = []
+               f = open(LANEDB_PATH, "r")
+               line = f.readline()
+
+               try:
+                       version = self.python_scanf(line, "eDVB services /%d/")
+                       if len(version)!=1 or version[0] != '4':
+#                              print "invalid version"
+                               return None
+               except Exception, ex:
+#                      print "[fastzapsupport] exception error : ", ex
+                       return None
+
+               line = f.readline()
+
+               if line != "transponders\n":
+#                      print "[FastZapSupport] no transponders"
+                       return None
+
+               channel_idx = 0
+
+               while 1:
+                       line = f.readline()
+                       if not line:
+                               break
+                       if line == "end\n":
+                               break
+                       tmp = line.strip('\n').split(':')
+                       if len(tmp) != 3:
+                               continue
+
+                       channelID = {}
+                       channelID["namespace"] = tmp[0]
+                       channelID["tsid"] = tmp[1]
+                       channelID["onid"] = tmp[2]
+
+                       feParms = {}
+                       feParms["frequency"] = None
+                       feParms["symbol_rate"] = None
+                       feParms["polarisation"] = None
+                       feParms["fec"] = None
+                       feParms["orbital_position"] = None
+                       feParms["inversion"] = None
+                       feParms["flags"] = None
+                       feParms["system"] = None
+                       feParms["modulation"] = None
+                       feParms["rolloff"] = None
+                       feParms["pilot"] = None
+
+                       while 1:
+                               line = f.readline()
+                               if line == "/\n":
+                                       break
+                               if line[1] == 's':
+                                       s = line[3:].strip('\n').split(':')
+                                       if len(s) >= 7:
+                                               ss = s[:7]
+                                               feParms["frequency"], feParms["symbol_rate"], feParms["polarisation"], feParms["fec"], feParms["orbital_position"], feParms["inversion"], feParms["flags"] = ss
+                                               if feParms["polarisation"] < 0:
+                                                       feParms["polarisation"] += 3600
+
+                                               feParms["system"] = '0' # DVB-S
+                                               feParms["modulation"] = '1' # QPSK
+                                               feParms["rolloff"] = '0' # 0.35
+                                               feParms["pilot"] = '2' # unknown
+
+                                       if len(s) >= 8:
+                                               ss = s[7:]
+                                               feParms["system"], feParms["modulation"], feParms["rolloff"], feParms["pilot"] = ss
+
+                       if feParms["frequency"] is None:
+                               continue
+
+                       channel = {}
+                       channel["channelID"] = channelID
+                       channel["feParms"] = feParms
+                       channel["idx"] = channel_idx
+                       channelList.append(channel)
+                       channel_idx += 1
+
+#              print "[FastZapSupport] %d transponders" % len(channelList)
+               self.channelList = channelList
+
+       def parseNimConfiguration(self):
+               self.diseqc_position = {}
+               for x in nimmanager.nim_slots:
+                       nimConfig = nimmanager.getNimConfig(x.slot)
+
+                       if x.isCompatible("DVB-S"):
+                               if nimConfig.configMode.value == "simple":
+#                                      print "[FastZapSupport] nimConfig.diseqcMode.value : ", nimConfig.diseqcMode.value
+                                       if nimConfig.diseqcMode.value == "single" and not nimConfig.simpleSingleSendDiSEqC.value:                                       
+                                               continue
+
+                                       elif nimConfig.diseqcMode.value == "diseqc_a_b" or nimConfig.diseqcMode.value == "diseqc_a_b_c_d":
+                                               pass
+
+                                       else:
+                                               continue
+
+                                       if nimConfig.diseqcA.orbital_position != 3601: # 3601: nothing connected
+                                               if not self.diseqc_position.has_key(nimConfig.diseqcA.orbital_position):
+                                                       self.diseqc_position[nimConfig.diseqcA.orbital_position] = {"pos" : "AA", "lofth" : 11700000}
+
+                                       if nimConfig.diseqcB.orbital_position != 3601:
+                                               if not self.diseqc_position.has_key(nimConfig.diseqcB.orbital_position):
+                                                       self.diseqc_position[nimConfig.diseqcB.orbital_position] = {"pos" : "AB", "lofth" : 11700000}
+
+                                       if nimConfig.diseqcC.orbital_position != 3601:
+                                               if not self.diseqc_position.has_key(nimConfig.diseqcC.orbital_position):
+                                                       self.diseqc_position[nimConfig.diseqcC.orbital_position] = {"pos" : "BA", "lofth" : 11700000}
+
+                                       if nimConfig.diseqcD.orbital_position != 3601:
+                                               if not self.diseqc_position.has_key(nimConfig.diseqcD.orbital_position):
+                                                       self.diseqc_position[nimConfig.diseqcD.orbital_position] = {"pos" : "BB", "lofth": 11700000}
+
+                               elif nimConfig.configMode.value == "advanced":
+                                       if nimConfig.advanced.sats.orbital_position is None:
+                                               continue
+
+                                       cur_orb_pos = nimConfig.advanced.sats.orbital_position
+                                       satlist = nimConfig.advanced.sat.keys()
+
+                                       if cur_orb_pos not in satlist:
+                                               cur_orb_pos = satlist[0]
+
+                                       currSat = nimConfig.advanced.sat[cur_orb_pos]
+                                       lnbnum = int(currSat.lnb.value)
+                                       currLnb = nimConfig.advanced.lnb[lnbnum]
+
+                                       if isinstance(currLnb, ConfigNothing):
+                                               continue
+
+                                       if currLnb.lof.value == "universal_lnb":
+                                               lofth = 11700000
+
+                                       elif currLnb.lof.value == "user_defined":
+                                               lofth = int(currLnb.threshold.value) * 1000
+                                       else:
+                                               continue
+
+                                       if currLnb.diseqcMode.value == "none":
+                                               continue
+
+                                       if currLnb.commitedDiseqcCommand.value == "none":
+                                               continue
+
+                                       if currLnb.commitedDiseqcCommand.value in ["AA", "AB", "BA", "BB"]:
+                                               position = currLnb.commitedDiseqcCommand.value
+
+                                       else:
+                                               position = "AA"
+
+                                       self.diseqc_position[cur_orb_pos] = {"pos" : position, "lofth" : lofth}
+
+       def getTone(self, frequency, orbital_position):
+               tone = "low"
+               lofth = 11700000
+
+               if self.diseqc_position.has_key(orbital_position):
+                       lofth = self.diseqc_position[orbital_position]["lofth"]
+
+               if frequency > lofth:
+                       tone = "high"
+
+               return tone
+
+       def getPosition(self, orbital_position):
+               if self.diseqc_position.has_key(orbital_position):
+                       return self.diseqc_position[orbital_position]["pos"]
+
+               return None
+
+       def getSrefList(self):
+               srefList = []
+
+               global FAVOURITES_PATH
+
+               if not os.access(FAVOURITES_PATH, os.R_OK):
+#                      print "[FastZapSupport] Error, %s not found." % FAVOURITES_PATH
+                       return
+
+               f = open(FAVOURITES_PATH, "r")
+               while 1:
+                       line = f.readline()
+                       if not line:
+                               break
+
+                       if not line.startswith("#SERVICE"):
+                               continue
+
+                       data = line.split(' ')
+                       if (len(data) != 2):
+                               continue
+
+                       res = re.search("\d+:\d+:\w+:\w+:\w+:\w+:\w+:\w+:\w+:\w+:", data[1])
+
+                       if res:
+                               sref = res.group()
+                               sref_split = sref.split(":")
+                               type = int(sref_split[0])
+                               flag = int(sref_split[1])
+                               stype = int(sref_split[2], 16) # hex to int
+                               if type != 1 or flag != 0:
+                                       continue
+
+                               # VIDEO : 1, 17, 22, 25, 134, 195
+                               # AUDIO : 2, 10
+                               # HEVC : 31
+                               if not stype in (1, 17, 22, 25, 134, 195, 2, 10, 31):
+                                       continue # unknown service type
+
+                               if sref not in srefList:
+                                       srefList.append(sref)
+
+#              print "[FastZapSupport] TOTAL %d Services" % len(srefList)
+
+               return srefList
+
+       def getChannel(self, sref):
+               sref_tsid = strToHex(sref.split(":")[4])
+               sref_onid = strToHex(sref.split(":")[5])
+               sref_namespace = strToHex(sref.split(":")[6])
+               for channel in self.channelList:
+                       channel_tsid = strToHex(channel["channelID"]["tsid"])
+                       channel_onid = strToHex(channel["channelID"]["onid"])
+                       channel_namespace = strToHex(channel["channelID"]["namespace"])
+                       if (sref_tsid == channel_tsid) and (sref_onid == channel_onid) and (sref_namespace == channel_namespace):
+                               return channel
+
+               return None
+
+       def makeChannelData(self, srefList):
+               channelData = []
+               for sref in srefList:
+                       channel = self.getChannel(sref)
+                       if channel is None:
+                               continue
+
+                       if channel not in channelData:
+                               channelData.append((channel, sref))
+
+#              print "[FastZapSupport] TOTAL %d channels" % len(channelData)
+
+               return channelData
+
+       def writeDataProc(self, channelData):
+               global PROC_FBC_PATH
+
+               if not os.access(PROC_FBC_PATH, os.F_OK):
+#                      print "[FastZapSupport] Error, %s not found!" % PROC_FBC_PATH
+                       return
+
+               fbc_proc_list = ["frequency", "symbolrate", "polarisation", "fec", "inv", "system", "modulation", "rolloff", "pilot", "tone", "position", "sid"]
+               procData = {}
+
+               for c in fbc_proc_list:
+                       procData[c] = []
+
+               pol_table = ["h", "v"]
+               fec_table = ["auto", "12", "23", "34", "56", "78", "89", "35", "45", "910", "none"]
+               inv_table = ["on", "off", "auto"]
+               system_table = ["dvbs", "dvbs2"]
+               modulation_table = ["auto", "qpsk", "8psk", "qam16"]
+               rolloff_table = ["0_35", "0_25", "0_20"]
+               pilot_table = ["off", "on", "auto"]
+               position_table = {"AA" : "a", "AB" : "b", "BA" : "c", "BB" : "d"}
+
+               for (channel, sref) in channelData:
+                       feParms = channel["feParms"]
+
+                       position = self.getPosition(int(feParms["orbital_position"]))
+                       if position is None:
+                               continue
+
+                       procData["position"].append(position_table[position]) # aa, ab, ba, bb
+
+                       procData["frequency"].append(str(feParms["frequency"]))
+                       procData["symbolrate"].append(str(feParms["symbol_rate"]))
+                       procData["polarisation"].append(pol_table[int(feParms["polarisation"])])
+                       procData["fec"].append(fec_table[int(feParms["fec"])])
+                       procData["inv"].append(inv_table[int(feParms["inversion"])])
+                       procData["system"].append(system_table[int(feParms["system"])])
+
+                       if system_table[int(feParms["system"])] == "dvbs2":
+                               procData["modulation"].append( modulation_table[int(feParms["modulation"])] )
+                               procData["rolloff"].append(  rolloff_table[int(feParms["rolloff"])] )
+                               procData["pilot"].append( pilot_table[int(feParms["pilot"])] )
+
+                       else:
+                               procData["modulation"].append("none")
+                               procData["rolloff"].append("none")
+                               procData["pilot"].append("none")
+
+                       procData["tone"].append(self.getTone(int(feParms["frequency"]), int(feParms["orbital_position"]))) # low or high
+
+                       sid = str(int(sref.split(":")[3], 16))
+                       procData["sid"].append(sid)
+
+               total = len(procData["position"])
+               for c in fbc_proc_list:
+                       if self.procData.get(c, []) != procData[c]:
+                               procPath = "%s/%s" % (PROC_FBC_PATH, c)
+
+                               data = str(total) + " " + ','.join(procData[c])
+                               if not os.access(procPath, os.W_OK):
+#                                      print "[FastZapSupport] %s not found, skip write (data : %s)" % (procPath, data)
+                                       continue
+
+#                              print "[FastZapSupport] %s data updated" % procPath
+
+                               open("%s/%s" % (PROC_FBC_PATH, c) , "w").write(data)
+
+                               self.procData[c] = procData[c]
+
+def FastZapSupportInit(reason, **kwargs):
+       if kwargs.has_key("session"):
+               session = kwargs["session"]
+               global fast_zap_support
+               fast_zap_support = FastZapSupport(session)
+
+def SatConfigChanged():
+       global fast_zap_support
+       fast_zap_support.parseNimConfiguration()
+       fast_zap_support.writeDataProc(fast_zap_support.channelData)
+
+def lamedbChanged():
+       global fast_zap_support
+       fast_zap_support.parseChannelDB()
+
+from Components.config import config, ConfigSubsection, ConfigBoolean
+config.plugins.fastzapsetup = ConfigSubsection()
+config.plugins.fastzapsetup.activate = ConfigBoolean(default = False)
+
+class FastZapSetup:
+       def __init__(self):
+               config.plugins.fastzapsetup.activate.addNotifier(self.updateProc)
+
+       def getExtensionName(self):
+               if config.plugins.fastzapsetup.activate.value:
+                       return _("Disable FastZapping")
+
+               return _("Enable FastZapping")
+
+       def updateToggle(self):
+               if config.plugins.fastzapsetup.activate.value:
+                       config.plugins.fastzapsetup.activate.value = False
+               else:
+                       config.plugins.fastzapsetup.activate.value = True
+
+       def updateProc(self, configElement):
+               val = configElement.value and "enable" or "disable"
+               try:
+                       global PROC_FBC_PATH
+                       procPath = "%s/fcc" % PROC_FBC_PATH
+                       print "[FastZapSetup] write %s to %s" % (val ,procPath)
+                       open(procPath, "w").write(val)
+
+               except Exception, ex:
+                       print "[FastZapSetup] exception error : ", ex
+
+               configElement.save()
+
+fastzapsetup_instance = FastZapSetup()
+def addExtentions(infobarExtensions):
+       infobarExtensions.addExtension((fastzapsetup_instance.getExtensionName, fastzapsetup_instance.updateToggle, lambda: True), None)
+
+def Plugins(**kwargs):
+       list = []
+       list.append(
+               PluginDescriptor(name="FastZapSupport",
+               description="FastZapSupport",
+               where = [PluginDescriptor.WHERE_SESSIONSTART],
+               fnc = FastZapSupportInit))
+
+       list.append(
+               PluginDescriptor(name="FastZapSupport",
+               description="FastZapSupport",
+               where = [PluginDescriptor.WHERE_SATCONFIGCHANGED],
+               fnc = SatConfigChanged))
+
+       list.append(
+               PluginDescriptor(name="FastZapSupport",
+               description="FastZapSupport",
+               where = [PluginDescriptor.WHERE_SERVICESCAN],
+               fnc = lamedbChanged))
+
+       list.append(
+               PluginDescriptor(name="FastZapSetup",
+               description="FastZapSetup",
+               where = [PluginDescriptor.WHERE_EXTENSIONSINGLE],
+               fnc = addExtentions))
+
+       return list
index cf3498b..72a7d0a 100755 (executable)
@@ -7,7 +7,8 @@ SUBDIRS = SoftwareManager FrontprocessorUpgrade PositionerSetup Satfinder \
        TempFanControl Fancontrol FPGAUpgrade WirelessLanSetup ManualFancontrol \
        Blindscan RemoteControlCode UI3DSetup UIPositionSetup HDMICEC LEDBrightnessSetup \
        FirmwareUpgrade CrashReport 3GModemManager WirelessAccessPoint ZappingModeSelection \
-       DeviceManager TransCodingSetup WOLSetup NetDrive AudioEffect AnimationSetup
+       DeviceManager TransCodingSetup WOLSetup NetDrive AudioEffect AnimationSetup FastZapSupport \
+       BoxModeConfig
 
 install_PYTHON =       \
        __init__.py
index 346c3b8..802c0b6 100644 (file)
@@ -38,6 +38,11 @@ class VideoHardware:
                        "60Hz" : {60: "1080p"},
                        "multi": {50: "1080p50", 60: "1080p"}
                },
+               "2160p": {
+                       "50Hz" : {50: "2160p50"},
+                       "60Hz" : {60: "2160p"},
+                       "multi": {50: "2160p50", 60: "2160p"}
+               },
                "PC": {
                        "1024x768": {60: "1024x768"},
                        "800x600" : {60: "800x600"},
@@ -55,11 +60,11 @@ class VideoHardware:
                }
        }
 
-       widescreen_modes = set(["720p", "1080i", "1080p"])
-       hdmi_hw_types = set(["dm500", "dm800se", "dm7020hd", "bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose", "zero"])
-       hdmi_pc_hw_types = set(["dm500", "dm800se", "dm7020hd", "bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose", "zero"])
-       noscart_hw_types = set(["zero"])
-       noypbpr_hw_types = set(["solose", "zero"])
+       widescreen_modes = set(["720p", "1080i", "1080p", "2160p"])
+       hdmi_hw_types = set(["dm500", "dm800se", "dm7020hd", "bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose", "zero", "solo4k"])
+       hdmi_pc_hw_types = set(["dm500", "dm800se", "dm7020hd", "bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose", "zero", "solo4k"])
+       noscart_hw_types = set(["zero", "solo4k"])
+       noypbpr_hw_types = set(["solose", "zero", "solo4k"])
 
        def getDeviceName(self):
                device_name = "unknown"
@@ -74,7 +79,10 @@ class VideoHardware:
                return device_name
 
        def isVumodel(self, hw_type):
-               return hw_type in set(["bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose", "zero"])
+               return hw_type in set(["bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose", "zero", "solo4k"])
+
+       def isVumodel4K(self, hw_type):
+               return hw_type in set(["solo4k"])
 
        # re-define AVSwitch.getOutputAspect
        def getOutputAspect(self):
@@ -232,6 +240,9 @@ class VideoHardware:
                # vu+ support 1080p
                if self.isVumodel(hw_type):
                        self.modes["DVI"].insert(self.modes["DVI"].index("1080i")+1, "1080p")
+                       # 4K support 2160p
+                       if self.isVumodel4K(hw_type):
+                               self.modes["DVI"].insert(self.modes["DVI"].index("1080p")+1, "2160p")
 
                portlist = [ ]
                port_choices = self.getPortList()
index a274010..328d98d 100644 (file)
@@ -25,11 +25,37 @@ class About(Screen):
                self["FPVersion"] = StaticText(fp_version)
 
                nims = nimmanager.nimList()
-               for count in (0, 1, 2, 3):
-                       if count < len(nims):
-                               self["Tuner" + str(count)] = StaticText(nims[count])
-                       else:
-                               self["Tuner" + str(count)] = StaticText("")
+               if len(nims) <= 4 :
+                       for count in (0, 1, 2, 3):
+                               if count < len(nims):
+                                       self["Tuner" + str(count)] = StaticText(nims[count])
+                               else:
+                                       self["Tuner" + str(count)] = StaticText("")
+               else:
+                       desc_list = []
+                       count = 0
+                       cur_idx = -1
+                       while count < len(nims):
+                               data = nims[count].split(":")
+                               idx = data[0].strip('Tuner').strip()
+                               desc = data[1].strip()
+                               if desc_list and desc_list[cur_idx]['desc'] == desc:
+                                       desc_list[cur_idx]['end'] = idx
+                               else:
+                                       desc_list.append({'desc' : desc, 'start' : idx, 'end' : idx})
+                                       cur_idx += 1
+                               count += 1
+
+                       for count in (0, 1, 2, 3):
+                               if count < len(desc_list):
+                                       if desc_list[count]['start'] == desc_list[count]['end']:
+                                               text = "Tuner %s: %s" % (desc_list[count]['start'], desc_list[count]['desc'])
+                                       else:
+                                               text = "Tuner %s-%s: %s" % (desc_list[count]['start'], desc_list[count]['end'], desc_list[count]['desc'])
+                               else:
+                                       text = ""
+
+                               self["Tuner" + str(count)] = StaticText(text)
 
                self["HDDHeader"] = StaticText(_("Detected HDD:"))
                hddlist = harddiskmanager.HDDList()
index 6813381..fc176a7 100755 (executable)
@@ -719,8 +719,9 @@ MODE_RADIO = 1
 # type 27 = advanced codec HD NVOD reference service (NYI)
 # type 2 = digital radio sound service
 # type 10 = advanced codec digital radio sound service
+# type 31 = High Efficiency Video Coing digital television
 
-service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 22) || (type == 25) || (type == 134) || (type == 195)'
+service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 22) || (type == 25) || (type == 31) || (type == 134) || (type == 195)'
 service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2) || (type == 10)'
 
 class ChannelSelectionBase(Screen):
index 78d9984..c5f72e2 100755 (executable)
@@ -1322,6 +1322,9 @@ class InfoBarExtensions:
                                "extensions": (self.showExtensionSelection, _("view extensions...")),
                        }, 1) # lower priority
 
+               for p in plugins.getPlugins(PluginDescriptor.WHERE_EXTENSIONSINGLE):
+                       p(self)
+
        def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
                self.list.append((type, extension, key))
 
index c5366f9..48b580c 100644 (file)
@@ -15,6 +15,24 @@ from Screens.ServiceStopScreen import ServiceStopScreen
 from time import mktime, localtime
 from datetime import datetime
 
+from Components.PluginComponent import plugins
+from Plugins.Plugin import PluginDescriptor
+
+def isFBCTuner(nim):
+       if nim.description.find("FBC") == -1:
+               return False
+       return True
+
+def isFBCRoot(nim):
+       if nim.slot %8 < 2:
+               return True
+       return False
+
+def isFBCLink(nim):
+       if isFBCTuner(nim) and not isFBCRoot(nim):
+               return True
+       return False
+
 class NimSetup(Screen, ConfigListScreen, ServiceStopScreen):
        def createSimpleSetup(self, list, mode):
                nim = self.nimConfig
@@ -70,6 +88,9 @@ class NimSetup(Screen, ConfigListScreen, ServiceStopScreen):
                                choices["satposdepends"] = _("second cable of motorized LNB")
                        if len(nimmanager.canConnectTo(self.slotid)) > 0:
                                choices["loopthrough"] = _("loopthrough to")
+                       if isFBCLink(self.nim):
+                               choices = { "nothing": _("not configured"),
+                                               "advanced": _("advanced")}
                        self.nimConfig.configMode.setChoices(choices, default = "nothing")
 
        def createSetup(self):
@@ -210,8 +231,9 @@ class NimSetup(Screen, ConfigListScreen, ServiceStopScreen):
                        self.advancedType, self.advancedSCR, self.advancedDiction, self.advancedManufacturer, self.advancedUnicable, self.advancedConnected, \
                        self.uncommittedDiseqcCommand, self.cableScanType, self.multiType)
                if self["config"].getCurrent() == self.multiType:
+                       update_slots = [self.slotid]
                        from Components.NimManager import InitNimManager
-                       InitNimManager(nimmanager)
+                       InitNimManager(nimmanager, update_slots)
                        self.nim = nimmanager.nim_slots[self.slotid]
                        self.nimConfig = self.nim.config
                        
@@ -246,6 +268,10 @@ class NimSetup(Screen, ConfigListScreen, ServiceStopScreen):
                self.list.append(self.advancedLnbsEntry)
 
                if currLnb:
+                       if isFBCLink(self.nim):
+                               if currLnb.lof.value != "unicable":
+                                       currLnb.lof.value = "unicable"
+
                        self.list.append(getConfigListEntry(_("Priority"), currLnb.prio))
                        self.advancedLof = getConfigListEntry(_("LOF"), currLnb.lof)
                        self.list.append(self.advancedLof)
@@ -310,6 +336,10 @@ class NimSetup(Screen, ConfigListScreen, ServiceStopScreen):
                                for id in connectable:
                                        choices.append((str(id), nimmanager.getNimDescription(id)))
                                if len(choices):
+                                       if isFBCLink(self.nim):
+                                               if self.nimConfig.advanced.unicableconnected.value != True:
+                                                       self.nimConfig.advanced.unicableconnected.value = True
+
                                        self.advancedConnected = getConfigListEntry(_("connected"), self.nimConfig.advanced.unicableconnected)
                                        self.list.append(self.advancedConnected)
                                        if self.nimConfig.advanced.unicableconnected.value == True:
@@ -479,10 +509,22 @@ class NimSetup(Screen, ConfigListScreen, ServiceStopScreen):
                self.createSetup()
 
        def keyLeft(self):
+               if isFBCLink(self.nim):
+                       checkList = (self.advancedLof, self.advancedConnected)
+                       curEntry = self["config"].getCurrent()
+                       if curEntry in checkList:
+                               return
+
                ConfigListScreen.keyLeft(self)
                self.newConfig()
 
        def keyRight(self):
+               if isFBCLink(self.nim):
+                       checkList = (self.advancedLof, self.advancedConnected)
+                       curEntry = self["config"].getCurrent()
+                       if curEntry in checkList:
+                               return
+
                ConfigListScreen.keyRight(self)
                self.newConfig()
                
@@ -502,6 +544,9 @@ 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:
@@ -517,13 +562,14 @@ class NimSetup(Screen, ConfigListScreen, ServiceStopScreen):
                if type(self["config"].getCurrent()[1]) is ConfigSatlist:
                        self["config"].getCurrent()[1].setValue("3601")
                        self["config"].invalidateCurrent()
-                       
+
 class NimSelection(Screen):
        def __init__(self, session):
                Screen.__init__(self, session)
                
                self.list = [None] * nimmanager.getSlotCount()
                self["nimlist"] = List(self.list)
+               self.loadFBCLinks()
                self.updateList()
                
                self.setResultClass()
@@ -533,6 +579,23 @@ class NimSelection(Screen):
                        "ok": self.okbuttonClick ,
                        "cancel": self.close
                }, -2)
+
+       def loadFBCLinks(self):
+               for x in nimmanager.nim_slots:
+                       slotid = x.slot
+                       nimConfig = nimmanager.getNimConfig(x.slot)
+                       configMode = nimConfig.configMode.value
+                       if self.showNim(x):
+                               if x.isCompatible("DVB-S"):
+                                       if isFBCLink(x) and configMode != "advanced":
+                                               from enigma import getLinkedSlotID
+                                               link = getLinkedSlotID(x.slot)
+
+                                               if link == -1:
+                                                       nimConfig.configMode.value = "nothing"
+                                               else:
+                                                       nimConfig.configMode.value = "loopthrough"
+                                                       nimConfig.connectedTo.value = str(link)
                
        def setResultClass(self):
                self.resultclass = NimSetup
@@ -540,8 +603,17 @@ class NimSelection(Screen):
        def okbuttonClick(self):
                nim = self["nimlist"].getCurrent()
                nim = nim and nim[3]
+
+               nimConfig = nimmanager.getNimConfig(nim.slot)
+               if isFBCLink(nim) and nimConfig.configMode.value == "loopthrough":
+                       return
+
                if nim is not None and not nim.empty and nim.isSupported():
-                       self.session.openWithCallback(self.updateList, self.resultclass, nim.slot)
+                       self.session.openWithCallback(self.NimSetupCB, self.resultclass, nim.slot)
+
+       def NimSetupCB(self):
+               self.loadFBCLinks()
+               self.updateList()
                        
        def showNim(self, nim):
                return True
@@ -558,7 +630,7 @@ class NimSelection(Screen):
                                                text = { "loopthrough": _("loopthrough to"),
                                                                 "equal": _("equal to"),
                                                                 "satposdepends": _("second cable of motorized LNB") } [nimConfig.configMode.value]
-                                               text += " " + _("Tuner") + " " + ["A", "B", "C", "D"][int(nimConfig.connectedTo.value)]
+                                               text += " " + _("Tuner") + " " + chr(ord('A')+int(nimConfig.connectedTo.value))
                                        elif nimConfig.configMode.value == "nothing":
                                                text = _("not configured")
                                        elif nimConfig.configMode.value == "simple":
@@ -592,6 +664,8 @@ class NimSelection(Screen):
                                                        text = _("simple")
                                        elif nimConfig.configMode.value == "advanced":
                                                text = _("advanced")
+                                       if isFBCLink(x) and nimConfig.configMode.value != "advanced":
+                                               text += _("\n<This tuner is configured automatically>")
                                elif x.isCompatible("DVB-T") or x.isCompatible("DVB-C"):
                                        if nimConfig.configMode.value == "nothing":
                                                text = _("nothing connected")
@@ -605,3 +679,4 @@ class NimSelection(Screen):
                                self.list.append((slotid, x.friendly_full_description, text, x))
                self["nimlist"].setList(self.list)
                self["nimlist"].updateList(self.list)
+
index bc0968e..da534ec 100644 (file)
@@ -182,7 +182,7 @@ class ServiceInfo(Screen):
                if frontendDataOrg and len(frontendDataOrg):
                        frontendData = ConvertToHumanReadable(frontendDataOrg)
                        if frontendDataOrg["tuner_type"] == "DVB-S":
-                               return ((_("NIM"), ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H')[frontendData["tuner_number"]], TYPE_TEXT),
+                               return ((_("NIM"), chr(ord('A')+int(frontendData["tuner_number"])), TYPE_TEXT),
                                                (_("Type"), frontendData["tuner_type"], TYPE_TEXT),
                                                (_("System"), frontendData["system"], TYPE_TEXT),
                                                (_("Modulation"), frontendData["modulation"], TYPE_TEXT),
@@ -195,7 +195,7 @@ class ServiceInfo(Screen):
                                                (_("Pilot"), frontendData.get("pilot", None), TYPE_TEXT),
                                                (_("Roll-off"), frontendData.get("rolloff", None), TYPE_TEXT))
                        elif frontendDataOrg["tuner_type"] == "DVB-C":
-                               return ((_("NIM"), ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H')[frontendData["tuner_number"]], TYPE_TEXT),
+                               return ((_("NIM"), chr(ord('A')+int(frontendData["tuner_number"])), TYPE_TEXT),
                                                (_("Type"), frontendData["tuner_type"], TYPE_TEXT),
                                                (_("Modulation"), frontendData["modulation"], TYPE_TEXT),
                                                (_("Frequency"), frontendData["frequency"], TYPE_VALUE_DEC),
@@ -203,7 +203,7 @@ class ServiceInfo(Screen):
                                                (_("Inversion"), frontendData["inversion"], TYPE_TEXT),
                                                (_("FEC"), frontendData["fec_inner"], TYPE_TEXT))
                        elif frontendDataOrg["tuner_type"] == "DVB-T":
-                               data = ((_("NIM"), ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H')[frontendData["tuner_number"]], TYPE_TEXT),
+                               data = ((_("NIM"), chr(ord('A')+int(frontendData["tuner_number"])), TYPE_TEXT),
                                                (_("Type"), frontendData["tuner_type"], TYPE_TEXT),
                                                (_("System"), frontendData["system"], TYPE_TEXT),
                                                (_("Frequency"), frontendData["frequency"], TYPE_VALUE_DEC),
index 6be08d4..efa218b 100644 (file)
@@ -5,6 +5,8 @@ from Components.Label import Label
 from Components.ActionMap import ActionMap
 from Components.FIFOList import FIFOList
 from Components.Sources.FrontendInfo import FrontendInfo
+from Components.PluginComponent import plugins
+from Plugins.Plugin import PluginDescriptor
 
 class ServiceScanSummary(Screen):
        skin = """
@@ -60,6 +62,11 @@ 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)
index 9891fb3..6a25592 100755 (executable)
@@ -334,6 +334,16 @@ void setPreferredTuner(int index)
 }
 %}
 
+int getLinkedSlotID(int);
+%{
+int getLinkedSlotID(int fe)
+{
+        eFBCTunerManager *mgr = eFBCTunerManager::getInstance();
+        if (mgr) return mgr->getLinkedSlotID(fe);
+        return -1;
+}
+%}
+
 /************** temp *****************/
 
        /* need a better place for this, i agree. */
index cc8c32b..cd65f35 100644 (file)
@@ -99,6 +99,37 @@ void eListboxServiceContent::getCurrent(eServiceReference &ref)
                ref = eServiceReference();
 }
 
+void eListboxServiceContent::getPrev(eServiceReference &ref)
+{
+       if (cursorValid())
+       {
+               list::iterator cursor(m_cursor);
+               if (cursor == m_list.begin())
+               {
+                       cursor = m_list.end();
+               }
+               ref = *(--cursor);
+       }
+       else
+               ref = eServiceReference();
+}
+
+void eListboxServiceContent::getNext(eServiceReference &ref)
+{
+       if (cursorValid())
+       {
+               list::iterator cursor(m_cursor);
+               cursor++;
+               if (cursor == m_list.end())
+               {
+                       cursor = m_list.begin();
+               }
+               ref = *(cursor);
+       }
+       else
+               ref = eServiceReference();
+}
+
 int eListboxServiceContent::getNextBeginningWithChar(char c)
 {
 //     printf("Char: %c\n", c);
index 589afba..ab5bd20 100644 (file)
@@ -19,6 +19,8 @@ public:
        void setIgnoreService( const eServiceReference &service );
        void setRoot(const eServiceReference &ref, bool justSet=false);
        void getCurrent(eServiceReference &ref);
+       void getPrev(eServiceReference &ref);
+       void getNext(eServiceReference &ref);
        
        int getNextBeginningWithChar(char c);
        int getPrevMarkerPos();
index 0287acf..dc1b22e 100644 (file)
@@ -15,7 +15,7 @@
 
 DEFINE_REF(eDVBServiceRecord);
 
-eDVBServiceRecord::eDVBServiceRecord(const eServiceReferenceDVB &ref, bool isstreamclient = false):
+eDVBServiceRecord::eDVBServiceRecord(const eServiceReferenceDVB &ref, bool isstreamclient):
        m_ref(ref),m_is_stream_client(isstreamclient)
 {
        CONNECT(m_service_handler.serviceEvent, eDVBServiceRecord::serviceEvent);
index e79be09..8e8f190 100755 (executable)
 #include <gst/pbutils/missing-plugins.h>
 #include <sys/stat.h>
 
+#define GSTREAMER_SUBTITLE_SYNC_MODE_BUG
+
+#define SUBTITLE_DEBUG
+
 #define HTTP_TIMEOUT 10
 
+typedef enum
+{
+       GST_PLAY_FLAG_VIDEO         = 0x00000001,
+       GST_PLAY_FLAG_AUDIO         = 0x00000002,
+       GST_PLAY_FLAG_TEXT          = 0x00000004,
+       GST_PLAY_FLAG_VIS           = 0x00000008,
+       GST_PLAY_FLAG_SOFT_VOLUME   = 0x00000010,
+       GST_PLAY_FLAG_NATIVE_AUDIO  = 0x00000020,
+       GST_PLAY_FLAG_NATIVE_VIDEO  = 0x00000040,
+       GST_PLAY_FLAG_DOWNLOAD      = 0x00000080,
+       GST_PLAY_FLAG_BUFFERING     = 0x00000100
+} GstPlayFlags;
+
 // eServiceFactoryMP3
 
 eServiceFactoryMP3::eServiceFactoryMP3()
@@ -223,15 +240,13 @@ int eServiceMP3::ac3_delay,
 eServiceMP3::eServiceMP3(eServiceReference ref)
        :m_ref(ref), m_pump(eApp, 1)
 {
-       m_seekTimeout = eTimer::create(eApp);
        m_subtitle_sync_timer = eTimer::create(eApp);
        m_streamingsrc_timeout = 0;
        m_stream_tags = 0;
        m_currentAudioStream = -1;
-       m_currentSubtitleStream = 0;
+       m_currentSubtitleStream = -1;
        m_subtitle_widget = 0;
-       m_currentTrickRatio = 0;
-       m_subs_to_pull = 0;
+       m_currentTrickRatio = 1.0;
        m_buffer_size = 1*1024*1024;
        m_prev_decoder_time = -1;
        m_decoder_time_valid_state = 0;
@@ -239,8 +254,6 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
        //vuplus
        m_is_hls_stream = 0;
        audioSink = videoSink = NULL;
-
-       CONNECT(m_seekTimeout->timeout, eServiceMP3::seekTimeoutCB);
        CONNECT(m_subtitle_sync_timer->timeout, eServiceMP3::pushSubtitles);
        CONNECT(m_pump.recv_msg, eServiceMP3::gstPoll);
        m_aspect = m_width = m_height = m_framerate = m_progressive = -1;
@@ -251,7 +264,7 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
        const char *filename = m_ref.path.c_str();
        const char *ext = strrchr(filename, '.');
        if (!ext)
-               ext = filename;
+               ext = filename + strlen(filename);
 
        m_sourceinfo.is_video = FALSE;
        m_sourceinfo.audiotype = atUnknown;
@@ -312,7 +325,7 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
                                ePythonConfigQuery::getConfigValue("config.mediaplayer.alternateUserAgent", m_useragent);
                }
                if ( m_useragent.length() == 0 )
-                       m_useragent = "Dream Multimedia Dreambox Enigma2 Mediaplayer";
+                       m_useragent = "Enigma2 Mediaplayer";
        }
        else if ( m_sourceinfo.containertype == ctCDA )
        {
@@ -334,38 +347,45 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
 
                uri = g_filename_to_uri(filename, NULL, NULL);
 
-       //eDebug("eServiceMP3::playbin2 uri=%s", uri);
-       eDebug("eServiceMP3::playbin2");
+       eDebug("eServiceMP3::playbin uri=%s", uri);
 
+#if GST_VERSION_MAJOR < 1
        m_gst_playbin = gst_element_factory_make("playbin2", "playbin");
-       if (!m_gst_playbin)
-               m_errorInfo.error_message = "failed to create GStreamer pipeline!\n";
-
-       g_object_set (G_OBJECT (m_gst_playbin), "uri", uri, NULL);
-
-       int flags = 0x47; // ( GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_TEXT );
-       g_object_set (G_OBJECT (m_gst_playbin), "flags", flags, NULL);
-
-       g_free(uri);
-
-       GstElement *subsink = gst_element_factory_make("appsink", "subtitle_sink");
-       if (!subsink)
-               eDebug("eServiceMP3::sorry, can't play: missing gst-plugin-appsink");
-       else
-       {
-               m_subs_to_pull_handler_id = g_signal_connect (subsink, "new-buffer", G_CALLBACK (gstCBsubtitleAvail), this);
-               g_object_set (G_OBJECT (subsink), "caps", gst_caps_from_string("text/plain; text/x-plain; text/x-pango-markup; video/x-dvd-subpicture; subpicture/x-pgs"), NULL);
-               g_object_set (G_OBJECT (m_gst_playbin), "text-sink", subsink, NULL);
-               
-       }
+#else
+       m_gst_playbin = gst_element_factory_make("playbin", "playbin");
+#endif 
 
        if ( m_gst_playbin )
        {
-               gst_bus_set_sync_handler(gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin)), gstBusSyncHandler, this);
-               char srt_filename[strlen(filename)+1];
-               strncpy(srt_filename,filename,strlen(filename)-3);
-               srt_filename[strlen(filename)-3]='\0';
-               strcat(srt_filename, "srt");
+               int flags;
+               g_object_get(G_OBJECT (m_gst_playbin), "flags", &flags, NULL);
+               flags |= GST_PLAY_FLAG_NATIVE_VIDEO;
+               flags &= ~GST_PLAY_FLAG_SOFT_VOLUME;
+               g_object_set (G_OBJECT (m_gst_playbin), "flags", flags, NULL);
+               g_object_set (G_OBJECT (m_gst_playbin), "uri", uri, NULL);
+               g_free(uri);
+
+               GstElement *subsink = gst_element_factory_make("subsink", "subtitle_sink");
+               if (!subsink)
+                       eDebug("eServiceMP3::sorry, can't play: missing gst-plugin-subsink");
+               else
+               {
+                       m_subs_to_pull_handler_id = g_signal_connect (subsink, "new-buffer", G_CALLBACK (gstCBsubtitleAvail), this);
+                       g_object_set (G_OBJECT (subsink), "caps", gst_caps_from_string("text/plain; text/x-plain; text/x-raw; text/x-pango-markup; video/x-dvd-subpicture; subpicture/x-pgs"), NULL);
+                       g_object_set (G_OBJECT (m_gst_playbin), "text-sink", subsink, NULL);
+                       g_object_set (G_OBJECT (m_gst_playbin), "current-text", m_currentSubtitleStream, NULL);
+               }
+               GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin));
+#if GST_VERSION_MAJOR < 1
+               gst_bus_set_sync_handler(bus, gstBusSyncHandler, this);
+#else
+               gst_bus_set_sync_handler(bus, gstBusSyncHandler, this, NULL);
+#endif
+               gst_object_unref(bus);
+               char srt_filename[ext - filename + 5];
+               strncpy(srt_filename, filename, ext - filename);
+               srt_filename[ext - filename]='\0';
+               strcat(srt_filename, ".srt");
                struct stat buffer;
                if (stat(srt_filename, &buffer) == 0)
                {
@@ -383,6 +403,7 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
                if (m_gst_playbin)
                        gst_object_unref(GST_OBJECT(m_gst_playbin));
 
+               m_errorInfo.error_message = "failed to create GStreamer pipeline!\n";
                eDebug("eServiceMP3::sorry, can't play: %s",m_errorInfo.error_message.c_str());
                m_gst_playbin = 0;
        }
@@ -393,18 +414,28 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
 eServiceMP3::~eServiceMP3()
 {
        // disconnect subtitle callback
-       GstElement *appsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
+       GstElement *subsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
 
-       if (appsink)
+       if (subsink)
        {
-               g_signal_handler_disconnect (appsink, m_subs_to_pull_handler_id);
-               gst_object_unref(appsink);
+               g_signal_handler_disconnect (subsink, m_subs_to_pull_handler_id);
+               gst_object_unref(subsink);
        }
 
-       delete m_subtitle_widget;
+       if (m_subtitle_widget)
+               delete m_subtitle_widget;
 
-       // disconnect sync handler callback
-       gst_bus_set_sync_handler(gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin)), NULL, NULL);
+       if (m_gst_playbin)
+       {
+               // disconnect sync handler callback
+               GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin));
+#if GST_VERSION_MAJOR < 1
+               gst_bus_set_sync_handler(bus, NULL, NULL);
+#else
+               gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
+#endif
+               gst_object_unref(bus);
+       }
 
        if (m_state == stRunning)
                stop();
@@ -470,7 +501,6 @@ RESULT eServiceMP3::stop()
        //GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(m_gst_playbin),GST_DEBUG_GRAPH_SHOW_ALL,"e2-playbin");
 
        //eDebug("eServiceMP3::stop %s", m_ref.path.c_str());
-       eDebug("eServiceMP3::stop service..");
        gst_element_set_state(m_gst_playbin, GST_STATE_NULL);
        m_state = stStopped;
 
@@ -493,7 +523,7 @@ RESULT eServiceMP3::setSlowMotion(int ratio)
        if (!ratio)
                return 0;
        eDebug("eServiceMP3::setSlowMotion ratio=%f",1/(float)ratio);
-       return trickSeek(1/(float)ratio);
+       return trickSeek(1.0/(gdouble)ratio);
 }
 
 RESULT eServiceMP3::setFastForward(int ratio)
@@ -502,28 +532,6 @@ RESULT eServiceMP3::setFastForward(int ratio)
        return trickSeek(ratio);
 }
 
-void eServiceMP3::seekTimeoutCB()
-{
-       pts_t ppos, len;
-       getPlayPosition(ppos);
-       getLength(len);
-       ppos += 90000*m_currentTrickRatio;
-       
-       if (ppos < 0)
-       {
-               ppos = 0;
-               m_seekTimeout->stop();
-       }
-       if (ppos > len)
-       {
-               ppos = 0;
-               stop();
-               m_seekTimeout->stop();
-               return;
-       }
-       seekTo(ppos);
-}
-
                // iPausableService
 RESULT eServiceMP3::pause()
 {
@@ -540,6 +548,9 @@ RESULT eServiceMP3::unpause()
        if (!m_gst_playbin || m_state != stRunning)
                return -1;
 
+       if (m_currentTrickRatio != 1.0)
+               trickSeek(1.0);
+
        gst_element_set_state(m_gst_playbin, GST_STATE_PLAYING);
 
        return 0;
@@ -562,12 +573,15 @@ RESULT eServiceMP3::getLength(pts_t &pts)
 
        GstFormat fmt = GST_FORMAT_TIME;
        gint64 len;
-       
+#if GST_VERSION_MAJOR < 1      
        if (!gst_element_query_duration(m_gst_playbin, &fmt, &len))
+#else
+       if (!gst_element_query_duration(m_gst_playbin, fmt, &len))
+#endif
                return -1;
                /* len is in nanoseconds. we have 90 000 pts per second. */
        
-       pts = len / 11111;
+       pts = len / 11111LL;
        return 0;
 }
 
@@ -575,9 +589,15 @@ RESULT eServiceMP3::seekToImpl(pts_t to)
 {
                /* convert pts to nanoseconds */
        gint64 time_nanoseconds = to * 11111LL;
-       if (!gst_element_seek (m_gst_playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+#if GST_VERSION_MAJOR < 1
+       if (!gst_element_seek (m_gst_playbin, m_currentTrickRatio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH),
                GST_SEEK_TYPE_SET, time_nanoseconds,
                GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
+#else
+       if (!gst_element_seek (m_gst_playbin, m_currentTrickRatio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
+               GST_SEEK_TYPE_SET, time_nanoseconds,
+               GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
+#endif
        {
                eDebug("eServiceMP3::seekTo failed");
                return -1;
@@ -591,14 +611,11 @@ RESULT eServiceMP3::seekTo(pts_t to)
        RESULT ret = -1;
 
        if (m_gst_playbin) {
-               eSingleLocker l(m_subs_to_pull_lock); // this is needed to dont handle incomming subtitles during seek!
-               if (!(ret = seekToImpl(to)))
-               {
-                       m_subtitle_pages.clear();
-                       m_prev_decoder_time = -1;
-                       m_decoder_time_valid_state = 0;
-                       m_subs_to_pull = 0;
-               }
+               m_subtitle_sync_timer->stop();
+               m_subtitle_pages.clear();
+               m_prev_decoder_time = -1;
+               m_decoder_time_valid_state = 0;
+               ret = seekToImpl(to);
        }
 
        return ret;
@@ -616,33 +633,50 @@ RESULT eServiceMP3::trickSeek(gdouble ratio)
        int flags;
        flags = GST_SEEK_FLAG_NONE;
        flags |= GST_SEEK_FLAG_FLUSH;
-//     flags |= GstSeekFlags (GST_SEEK_FLAG_ACCURATE);
+#if GST_VERSION_MAJOR >= 1
        flags |= GST_SEEK_FLAG_KEY_UNIT;
-//     flags |= GstSeekFlags (GST_SEEK_FLAG_SEGMENT);
-//     flags |= GstSeekFlags (GST_SEEK_FLAG_SKIP);
+#endif
 
        GstFormat fmt = GST_FORMAT_TIME;
-       gint64 pos, len;
+       bool validposition = false;
+       pts_t pos;
+       gint64 len;
+       
+#if GST_VERSION_MAJOR < 1
        gst_element_query_duration(m_gst_playbin, &fmt, &len);
-       gst_element_query_position(m_gst_playbin, &fmt, &pos);
-
-       if ( ratio >= 0 )
-       {
-               s_event = gst_event_new_seek (ratio, GST_FORMAT_TIME, (GstSeekFlags)flags, GST_SEEK_TYPE_SET, pos, GST_SEEK_TYPE_SET, len);
+#else
+       gst_element_query_duration(m_gst_playbin, fmt, &len);
+#endif
 
-               eDebug("eServiceMP3::trickSeek with rate %lf to %" GST_TIME_FORMAT " ", ratio, GST_TIME_ARGS (pos));
-       }
-       else
+       if (getPlayPosition(pos) >= 0)
        {
-               s_event = gst_event_new_seek (ratio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_SKIP|GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1);
+               validposition = true;
+               pos = pos * 11111LL;
        }
 
-       if (!gst_element_send_event ( GST_ELEMENT (m_gst_playbin), s_event))
+       if ( validposition )
        {
-               eDebug("eServiceMP3::trickSeek failed");
-               return -1;
-       }
+               if ( ratio >= 0.0 )
+               {
+                       s_event = gst_event_new_seek (ratio, GST_FORMAT_TIME, (GstSeekFlags)flags, GST_SEEK_TYPE_SET, pos, GST_SEEK_TYPE_SET, len);
 
+                       eDebug("eServiceMP3::trickSeek with rate %lf to %" GST_TIME_FORMAT " ", ratio, GST_TIME_ARGS (pos));
+               }
+               else
+               {
+                       s_event = gst_event_new_seek (ratio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_SKIP|GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1);
+               }
+
+               if (!gst_element_send_event ( GST_ELEMENT (m_gst_playbin), s_event))
+               {
+                       eDebug("eServiceMP3::trickSeek failed");
+                       return -1;
+               }
+       }
+       m_subtitle_pages.clear();
+       m_prev_decoder_time = -1;
+       m_decoder_time_valid_state = 0;
+       m_currentTrickRatio = ratio;
        return 0;
 }
 
@@ -653,13 +687,15 @@ RESULT eServiceMP3::seekRelative(int direction, pts_t to)
                return -1;
 
        pts_t ppos;
-       getPlayPosition(ppos);
+
+       if (getPlayPosition(ppos) < 0 )
+               return -1;
+
        ppos += to * direction;
        if (ppos < 0)
                ppos = 0;
-       seekTo(ppos);
        
-       return 0;
+       return seekTo(ppos);
 }
 
 RESULT eServiceMP3::getPlayPosition(pts_t &pts)
@@ -681,7 +717,11 @@ RESULT eServiceMP3::getPlayPosition(pts_t &pts)
        }
        else
        {
+#if GST_VERSION_MAJOR < 1
                if(!gst_element_query_position(m_gst_playbin, &fmt, &pos))
+#else
+               if(!gst_element_query_position(m_gst_playbin, fmt, &pos))
+#endif
                {
                        eDebug("gst_element_query_position failed in getPlayPosition");
                        return -1;
@@ -689,8 +729,8 @@ RESULT eServiceMP3::getPlayPosition(pts_t &pts)
        }
 
        /* pos is in nanoseconds. we have 90 000 pts per second. */
-       pts = pos / 11111;
-//     eDebug("gst_element_query_position %lld pts (%lld ms)", pts, pos/1000000);
+       pts = pos / 11111LL;
+//     eDebug("gst_element_query_position %lld pts (%lld ms)", pts, pos/1000000LL);
        return 0;
 }
 
@@ -877,12 +917,28 @@ std::string eServiceMP3::getInfoString(int w)
                break;
        case sTagDate:
                GDate *date;
+#if GST_VERSION_MAJOR >= 1
+               GstDateTime *date_time;
+#endif
                if (gst_tag_list_get_date(m_stream_tags, GST_TAG_DATE, &date))
                {
                        gchar res[5];
                        g_date_strftime (res, sizeof(res), "%Y-%M-%D", date); 
                        return (std::string)res;
                }
+#if GST_VERSION_MAJOR >= 1
+               else if (gst_tag_list_get_date_time(m_stream_tags, GST_TAG_DATE_TIME, &date_time))
+               {
+                       if (gst_date_time_has_year(date_time))
+                       {
+                               gchar res[5];
+                               snprintf(res, sizeof(res), "%04d", gst_date_time_get_year(date_time));
+                               gst_date_time_unref(date_time);
+                               return (std::string)res;
+                       }
+                       gst_date_time_unref(date_time);
+               }
+#endif
                break;
        case sTagComposer:
                tag = GST_TAG_COMPOSER;
@@ -1007,24 +1063,42 @@ PyObject *eServiceMP3::getInfoObject(int w)
                        break;
        }
 
-       if ( isBuffer )
+       if (m_stream_tags && tag)
        {
-               const GValue *gv_buffer = gst_tag_list_get_value_index(m_stream_tags, tag, 0);
-               if ( gv_buffer )
+               if ( isBuffer )
                {
-                       GstBuffer *buffer;
-                       buffer = gst_value_get_buffer (gv_buffer);
-                       return PyBuffer_FromMemory(GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
+                       const GValue *gv_buffer = gst_tag_list_get_value_index(m_stream_tags, tag, 0);
+                       if ( gv_buffer )
+                       {
+                               GstBuffer *buffer;
+                               unsigned char *bufferData;
+                               unsigned int bufferSize;
+                               buffer = gst_value_get_buffer (gv_buffer);
+#if GST_VERSION_MAJOR < 1
+                               bufferData = GST_BUFFER_DATA(buffer);
+                               bufferSize = GST_BUFFER_SIZE(buffer);
+#else
+                               GstMapInfo map;
+                               gst_buffer_map(buffer, &map, GST_MAP_READ);
+                               bufferData = map.data;
+                               bufferSize = map.size;
+#endif
+                               PyObject *ret = PyBuffer_FromMemory(bufferData, bufferSize);
+#if GST_VERSION_MAJOR >= 1
+                               gst_buffer_unmap(buffer, &map);
+#endif
+                               return ret;
+                       }
+               }
+               else
+               {
+                       gdouble value = 0.0;
+                       gst_tag_list_get_double(m_stream_tags, tag, &value);
+                       return PyFloat_FromDouble(value);
                }
-       }
-       else
-       {
-               gdouble value = 0.0;
-               gst_tag_list_get_double(m_stream_tags, tag, &value);
-               return PyFloat_FromDouble(value);
        }
 
-       return 0;
+       Py_RETURN_NONE;
 }
 
 RESULT eServiceMP3::audioChannel(ePtr<iAudioChannelSelection> &ptr)
@@ -1065,16 +1139,23 @@ int eServiceMP3::getCurrentTrack()
 
 RESULT eServiceMP3::selectTrack(unsigned int i)
 {
+       bool validposition = false;
        pts_t ppos;
-       getPlayPosition(ppos);
-       ppos -= 90000;
-       if (ppos < 0)
-               ppos = 0;
+       if (getPlayPosition(ppos) >= 0)
+       {
+               validposition = true;
+               ppos -= 90000;
+               if (ppos < 0)
+                       ppos = 0;
+       }
 
        int ret = selectAudioStream(i);
        if (!ret) {
-               /* flush */
-               seekTo(ppos);
+               if (validposition)
+               {
+                       /* flush */
+                       seekTo(ppos);
+               }
        }
 
        return ret;
@@ -1136,14 +1217,17 @@ RESULT eServiceMP3::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
 subtype_t getSubtitleType(GstPad* pad, gchar *g_codec=NULL)
 {
        subtype_t type = stUnknown;
+#if GST_VERSION_MAJOR < 1
        GstCaps* caps = gst_pad_get_negotiated_caps(pad);
-
+#else
+       GstCaps* caps = gst_pad_get_current_caps(pad);
+#endif
        if (!caps && !g_codec)
        {
                caps = gst_pad_get_allowed_caps(pad);
        }
 
-       if ( caps )
+       if ( caps && !gst_caps_is_empty(caps))
        {
                GstStructure* str = gst_caps_get_structure(caps, 0);
                const gchar *g_type = gst_structure_get_name(str);
@@ -1153,7 +1237,7 @@ subtype_t getSubtitleType(GstPad* pad, gchar *g_codec=NULL)
                        type = stVOB;
                else if ( !strcmp(g_type, "text/x-pango-markup") )
                        type = stSSA;
-               else if ( !strcmp(g_type, "text/plain") )
+               else if ( !strcmp(g_type, "text/plain") || !strcmp(g_type, "text/x-plain") || !strcmp(g_type, "text/x-raw"))
                        type = stPlainText;
                else if ( !strcmp(g_type, "subpicture/x-pgs") )
                        type = stPGS;
@@ -1180,10 +1264,18 @@ subtype_t getSubtitleType(GstPad* pad, gchar *g_codec=NULL)
        return type;
 }
 
+#if GST_VERSION_MAJOR < 1
 gint eServiceMP3::match_sinktype(GstElement *element, gpointer type)
 {
        return strcmp(g_type_name(G_OBJECT_TYPE(element)), (const char*)type);
 }
+#else
+gint eServiceMP3::match_sinktype(const GValue *velement, const gchar *type)
+{
+       GstElement *element = GST_ELEMENT_CAST(g_value_get_object(velement));
+       return strcmp(g_type_name(G_OBJECT_TYPE(element)), type);
+}
+#endif
 
 void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
 {
@@ -1239,15 +1331,17 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                                }       break;
                                case GST_STATE_CHANGE_READY_TO_PAUSED:
                                {
+#if GST_VERSION_MAJOR >= 1
+                                       GValue result = { 0, };
+#endif
                                        GstIterator *children;
-                                       GstElement *appsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
-                                       if (appsink)
+                                       GstElement *subsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
+                                       if (subsink)
                                        {
-                                               g_object_set (G_OBJECT (appsink), "max-buffers", 2, NULL);
-                                               g_object_set (G_OBJECT (appsink), "sync", FALSE, NULL);
-                                               g_object_set (G_OBJECT (appsink), "emit-signals", TRUE, NULL);
-                                               eDebug("eServiceMP3::appsink properties set!");
-                                               gst_object_unref(appsink);
+#ifdef GSTREAMER_SUBTITLE_SYNC_MODE_BUG
+                                               g_object_set (G_OBJECT (subsink), "sync", FALSE, NULL);
+#endif
+                                               gst_object_unref(subsink);
                                        }
 
                                        if (audioSink)
@@ -1262,11 +1356,27 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                                        }
 
                                        children = gst_bin_iterate_recurse(GST_BIN(m_gst_playbin));
+#if GST_VERSION_MAJOR < 1
                                        audioSink = GST_ELEMENT_CAST(gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, (gpointer)"GstDVBAudioSink"));
+#else
+                                       if (gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, &result, (gpointer)"GstDVBAudioSink"))
+                                       {
+                                               audioSink = GST_ELEMENT_CAST(g_value_dup_object(&result));
+                                               g_value_unset(&result);
+                                       }
+#endif
                                        gst_iterator_free(children);
 
                                        children = gst_bin_iterate_recurse(GST_BIN(m_gst_playbin));
+#if GST_VERSION_MAJOR < 1
                                        videoSink = GST_ELEMENT_CAST(gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, (gpointer)"GstDVBVideoSink"));
+#else
+                                       if (gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, &result, (gpointer)"GstDVBVideoSink"))
+                                       {
+                                               videoSink = GST_ELEMENT_CAST(g_value_dup_object(&result));
+                                               g_value_unset(&result);
+                                       }
+#endif
                                        gst_iterator_free(children);
 
                                        setAC3Delay(ac3_delay);
@@ -1356,11 +1466,35 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                        if ( gv_image )
                        {
                                GstBuffer *buf_image;
+#if GST_VERSION_MAJOR < 1
                                buf_image = gst_value_get_buffer (gv_image);
+#else
+                               GstSample *sample;
+                               sample = (GstSample *)g_value_get_boxed(gv_image);
+                               buf_image = gst_sample_get_buffer(sample);
+#endif
                                int fd = open("/tmp/.id3coverart", O_CREAT|O_WRONLY|O_TRUNC, 0644);
-                               int ret = write(fd, GST_BUFFER_DATA(buf_image), GST_BUFFER_SIZE(buf_image));
-                               close(fd);
-                               eDebug("eServiceMP3::/tmp/.id3coverart %d bytes written ", ret);
+                               if (fd >= 0)
+                               {
+                                       guint8 *data;
+                                       gsize size;
+                                       int ret;
+#if GST_VERSION_MAJOR < 1
+                                       data = GST_BUFFER_DATA(buf_image);
+                                       size = GST_BUFFER_SIZE(buf_image);
+#else
+                                       GstMapInfo map;
+                                       gst_buffer_map(buf_image, &map, GST_MAP_READ);
+                                       data = map.data;
+                                       size = map.size;
+#endif
+                                       ret = write(fd, data, size);
+#if GST_VERSION_MAJOR >= 1
+                                       gst_buffer_unmap(buf_image, &map);
+#endif
+                                       close(fd);
+                                       eDebug("eServiceMP3::/tmp/.id3coverart %d bytes written ", ret);
+                               }
                                m_event((iPlayableService*)this, evUser+13);
                        }
                        gst_tag_list_free(tags);
@@ -1372,8 +1506,7 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                        if(GST_MESSAGE_SRC(msg) != GST_OBJECT(m_gst_playbin))
                                break;
 
-                       GstTagList *tags;
-                       gint i, active_idx, n_video = 0, n_audio = 0, n_text = 0;
+                       gint i, n_video = 0, n_audio = 0, n_text = 0;
 
                        g_object_get (m_gst_playbin, "n-video", &n_video, NULL);
                        g_object_get (m_gst_playbin, "n-audio", &n_audio, NULL);
@@ -1384,8 +1517,6 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                        if ( n_video + n_audio <= 0 )
                                stop();
 
-                       active_idx = 0;
-
                        m_audioStreams.clear();
                        m_subtitleStreams.clear();
 
@@ -1393,9 +1524,14 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                        {
                                audioStream audio;
                                gchar *g_codec, *g_lang;
+                               GstTagList *tags = NULL;
                                GstPad* pad = 0;
                                g_signal_emit_by_name (m_gst_playbin, "get-audio-pad", i, &pad);
+#if GST_VERSION_MAJOR < 1
                                GstCaps* caps = gst_pad_get_negotiated_caps(pad);
+#else
+                               GstCaps* caps = gst_pad_get_current_caps(pad);
+#endif
                                if (!caps)
                                        continue;
                                GstStructure* str = gst_caps_get_structure(caps, 0);
@@ -1404,7 +1540,11 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                                g_codec = g_strdup(g_type);
                                g_lang = g_strdup_printf ("und");
                                g_signal_emit_by_name (m_gst_playbin, "get-audio-tags", i, &tags);
+#if GST_VERSION_MAJOR < 1
                                if ( tags && gst_is_tag_list(tags) )
+#else
+                               if ( tags && GST_IS_TAG_LIST(tags) )
+#endif
                                {
                                        gst_tag_list_get_string(tags, GST_TAG_AUDIO_CODEC, &g_codec);
                                        gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang);
@@ -1422,12 +1562,17 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                        for (i = 0; i < n_text; i++)
                        {
                                gchar *g_codec = NULL, *g_lang = NULL;
+                               GstTagList *tags = NULL;
                                g_signal_emit_by_name (m_gst_playbin, "get-text-tags", i, &tags);
                                subtitleStream subs;
 //                             int ret;
 
                                g_lang = g_strdup_printf ("und");
+#if GST_VERSION_MAJOR < 1
                                if ( tags && gst_is_tag_list(tags) )
+#else
+                               if ( tags && GST_IS_TAG_LIST(tags) )
+#endif
                                {
                                        gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang);
                                        gst_tag_list_get_string(tags, GST_TAG_SUBTITLE_CODEC, &g_codec);
@@ -1608,7 +1753,11 @@ audiotype_t eServiceMP3::gstCheckAudioPad(GstStructure* structure)
                return atAC3;
        else if ( gst_structure_has_name (structure, "audio/x-dts") || gst_structure_has_name (structure, "audio/dts") )
                return atDTS;
+#if GST_VERSION_MAJOR < 1
        else if ( gst_structure_has_name (structure, "audio/x-raw-int") )
+#else
+       else if ( gst_structure_has_name (structure, "audio/x-raw") )
+#endif
                return atPCM;
 
        return atUnknown;
@@ -1616,32 +1765,51 @@ audiotype_t eServiceMP3::gstCheckAudioPad(GstStructure* structure)
 
 void eServiceMP3::gstPoll(const Message &msg)
 {
-       if (msg.type == 1)
+       switch(msg.type)
        {
-               GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin));
-               GstMessage *message;
-               while ((message = gst_bus_pop(bus)))
+               case 1:
                {
-                       gstBusCall(bus, message);
-                       gst_message_unref (message);
+                       GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin));
+                       GstMessage *message;
+                       while ((message = gst_bus_pop(bus)))
+                       {
+                               gstBusCall(bus, message);
+                               gst_message_unref (message);
+                       }
+                       gst_object_unref(bus);
+                       break;
+               }
+               case 2:
+               {
+                       pullSubtitle(msg.d.buffer);
+                       gst_buffer_unref(msg.d.buffer);
+                       break;
+               }
+               case 3:
+               {
+                       gstTextpadHasCAPS_synced(msg.d.pad);
+                       gst_object_unref(msg.d.pad);
+                       break;
+               }
+               default:
+               {
+                       eDebug("gstPoll unhandled Message %d\n", msg.type);
+                       break;
                }
        }
-       else if (msg.type == 2)
-               pullSubtitle();
-       else if (msg.type == 3)
-               gstTextpadHasCAPS_synced(msg.d.pad);
-       else
-               eDebug("gstPoll unhandled Message %d\n", msg.type);
 }
 
 eAutoInitPtr<eServiceFactoryMP3> init_eServiceFactoryMP3(eAutoInitNumbers::service+1, "eServiceFactoryMP3");
 
-void eServiceMP3::gstCBsubtitleAvail(GstElement *appsink, gpointer user_data)
+void eServiceMP3::gstCBsubtitleAvail(GstElement *subsink, GstBuffer *buffer, gpointer user_data)
 {
-       eServiceMP3 *_this = (eServiceMP3*)user_data;   
-       eSingleLocker l(_this->m_subs_to_pull_lock);
-       ++_this->m_subs_to_pull;
-       _this->m_pump.send(Message(2));
+       eServiceMP3 *_this = (eServiceMP3*)user_data;
+       if (_this->m_currentSubtitleStream < 0)
+       {
+               if (buffer) gst_buffer_unref(buffer);
+               return;
+       }
+       _this->m_pump.send(Message(2, buffer));
 }
 
 void eServiceMP3::gstTextpadHasCAPS(GstPad *pad, GParamSpec * unused, gpointer user_data)
@@ -1668,7 +1836,7 @@ void eServiceMP3::gstTextpadHasCAPS_synced(GstPad *pad)
 
 //             eDebug("gstGhostpadHasCAPS_synced %p %d", pad, m_subtitleStreams.size());
 
-               if (!m_subtitleStreams.empty())
+               if (m_currentSubtitleStream >= 0 && m_currentSubtitleStream < (int)m_subtitleStreams.size())
                        subs = m_subtitleStreams[m_currentSubtitleStream];
                else {
                        subs.type = stUnknown;
@@ -1677,20 +1845,22 @@ void eServiceMP3::gstTextpadHasCAPS_synced(GstPad *pad)
 
                if ( subs.type == stUnknown )
                {
-                       GstTagList *tags;
-//                     eDebug("gstGhostpadHasCAPS::m_subtitleStreams[%i].type == stUnknown...", m_currentSubtitleStream);
-
+                       GstTagList *tags = NULL;
                        gchar *g_lang;
                        g_signal_emit_by_name (m_gst_playbin, "get-text-tags", m_currentSubtitleStream, &tags);
 
                        g_lang = g_strdup_printf ("und");
+#if GST_VERSION_MAJOR < 1
                        if ( tags && gst_is_tag_list(tags) )
+#else
+                       if ( tags && GST_IS_TAG_LIST(tags) )
+#endif
                                gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang);
 
                        subs.language_code = std::string(g_lang);
                        subs.type = getSubtitleType(pad);
 
-                       if (!m_subtitleStreams.empty())
+                       if (m_currentSubtitleStream >= 0 && m_currentSubtitleStream < (int)m_subtitleStreams.size())
                                m_subtitleStreams[m_currentSubtitleStream] = subs;
                        else
                                m_subtitleStreams.push_back(subs);
@@ -1702,74 +1872,77 @@ void eServiceMP3::gstTextpadHasCAPS_synced(GstPad *pad)
 
                gst_caps_unref (caps);
        }
-
-       gst_object_unref (pad);
 }
 
-void eServiceMP3::pullSubtitle()
+void eServiceMP3::pullSubtitle(GstBuffer *buffer)
 {
-       GstElement *sink;
-       g_object_get (G_OBJECT (m_gst_playbin), "text-sink", &sink, NULL);
-       
-       if (sink)
+       if (buffer && m_currentSubtitleStream >= 0 && m_currentSubtitleStream < (int)m_subtitleStreams.size())
        {
-               while (m_subs_to_pull && m_subtitle_pages.size() < 2)
+#if GST_VERSION_MAJOR < 1
+               gint64 buf_pos = GST_BUFFER_TIMESTAMP(buffer);
+               size_t len = GST_BUFFER_SIZE(buffer);
+#else
+               GstMapInfo map;
+               if(!gst_buffer_map(buffer, &map, GST_MAP_READ))
+               {
+                       eDebug("eServiceMP3::pullSubtitle gst_buffer_map failed");
+                       gst_buffer_unref(buffer);
+                       return;
+               }
+               gint64 buf_pos = GST_BUFFER_PTS(buffer);
+               size_t len = map.size;
+//             eDebug("gst_buffer_get_size %zu map.size %zu", gst_buffer_get_size(buffer), len);
+#endif
+               gint64 duration_ns = GST_BUFFER_DURATION(buffer);
+               int subType = m_subtitleStreams[m_currentSubtitleStream].type;
+#ifdef SUBTITLE_DEBUG
+               eDebug("pullSubtitle type = %i" ,subType);
+#endif                         
+               if (subType)
                {
-                       GstBuffer *buffer;
+                       if ( subType < stVOB )
                        {
-                               eSingleLocker l(m_subs_to_pull_lock);
-                               --m_subs_to_pull;
-                               g_signal_emit_by_name (sink, "pull-buffer", &buffer);
+                               unsigned char line[len+1];
+                               SubtitlePage page;
+#if GST_VERSION_MAJOR < 1
+                               memcpy(line, GST_BUFFER_DATA(buffer), len);
+#else
+                               memcpy(line, map.data, len);
+#endif
+                               line[len] = 0;
+#ifdef SUBTITLE_DEBUG
+                               eDebug("got new text subtitle @ buf_pos = %lld ns (in pts=%lld), dur=%lld: '%s' ", buf_pos, buf_pos/11111LL, duration_ns, line);
+#endif
+                               gRGB rgbcol(0xD0,0xD0,0xD0);
+                               page.type = SubtitlePage::Pango;
+                               page.pango_page.m_elements.push_back(ePangoSubtitlePageElement(rgbcol, (const char*)line));
+                               page.pango_page.m_show_pts = buf_pos / 11111LL;
+                               page.pango_page.m_timeout = duration_ns / 1000000;
+                               m_subtitle_pages.push_back(page);
+                               m_subtitle_sync_timer->start(1, true);
                        }
-                       if (buffer)
+                       else
                        {
-                               gint64 buf_pos = GST_BUFFER_TIMESTAMP(buffer);
-                               gint64 duration_ns = GST_BUFFER_DURATION(buffer);
-                               size_t len = GST_BUFFER_SIZE(buffer);
-                               eDebug("pullSubtitle m_subtitleStreams[m_currentSubtitleStream].type=%i",m_subtitleStreams[m_currentSubtitleStream].type);
-                               
-                               if ( m_subtitleStreams[m_currentSubtitleStream].type )
-                               {
-                                       if ( m_subtitleStreams[m_currentSubtitleStream].type < stVOB )
-                                       {
-                                               unsigned char line[len+1];
-                                               SubtitlePage page;
-                                               memcpy(line, GST_BUFFER_DATA(buffer), len);
-                                               line[len] = 0;
-                                               eDebug("got new text subtitle @ buf_pos = %lld ns (in pts=%lld): '%s' ", buf_pos, buf_pos/11111, line);
-                                               gRGB rgbcol(0xD0,0xD0,0xD0);
-                                               page.type = SubtitlePage::Pango;
-                                               page.pango_page.m_elements.push_back(ePangoSubtitlePageElement(rgbcol, (const char*)line));
-                                               page.pango_page.m_show_pts = buf_pos / 11111L;
-                                               page.pango_page.m_timeout = duration_ns / 1000000;
-                                               m_subtitle_pages.push_back(page);
-                                               if (m_subtitle_pages.size()==1)
-                                                       pushSubtitles();
-                                       }
-                                       else
-                                       {
-                                               eDebug("unsupported subpicture... ignoring");
-                                       }
-                               }
-                               gst_buffer_unref(buffer);
+                               eDebug("unsupported subpicture... ignoring");
                        }
                }
-               gst_object_unref(sink);
+#if GST_VERSION_MAJOR >= 1
+               gst_buffer_unmap(buffer, &map);
+#endif
        }
-       else
-               eDebug("no subtitle sink!");
 }
 
 void eServiceMP3::pushSubtitles()
 {
+       long next_timer = 0;
        while ( !m_subtitle_pages.empty() )
        {
-               SubtitlePage &frontpage = m_subtitle_pages.front();
                pts_t running_pts;
                gint64 diff_ms = 0;
                gint64 show_pts = 0;
 
-               getPlayPosition(running_pts);
+               if (getPlayPosition(running_pts) < 0)
+                       m_decoder_time_valid_state = 0;
 
                if (m_decoder_time_valid_state < 4) {
                        ++m_decoder_time_valid_state;
@@ -1780,34 +1953,54 @@ void eServiceMP3::pushSubtitles()
 //                                     eDebug("%d: decoder time not valid! prev %lld, now %lld\n", m_decoder_time_valid_state, m_prev_decoder_time/90, running_pts/90);
 //                             else
 //                                     eDebug("%d: decoder time not valid! now %lld\n", m_decoder_time_valid_state, running_pts/90);
-                               m_subtitle_sync_timer->start(25, true);
+                               next_timer = 25;
                                m_prev_decoder_time = running_pts;
                                break;
                        }
                }
 
+               SubtitlePage &frontpage = m_subtitle_pages.front();
                if (frontpage.type == SubtitlePage::Pango)
                        show_pts = frontpage.pango_page.m_show_pts;
 
                diff_ms = ( show_pts - running_pts ) / 90;
-               eDebug("check subtitle: decoder: %lld, show_pts: %lld, diff: %lld ms", running_pts/90, show_pts/90, diff_ms);
+
+#ifdef SUBTITLE_DEBUG
+               int32_t decoder_ms, start_ms, end_ms, diff_start_ms, diff_end_ms;
+               ePangoSubtitlePageElement &element = frontpage.pango_page.m_elements[0];
+               std::string text = element.m_pango_line;
+               decoder_ms = running_pts / 90;
+               start_ms = show_pts/ 90;
+               end_ms = start_ms + frontpage.pango_page.m_timeout;
+               diff_start_ms = start_ms - decoder_ms;
+               diff_end_ms = end_ms - decoder_ms;
+
+               eDebug("*** next subtitle: decoder: %d, start: %d, end: %d, duration_ms: %d, diff_start: %d, diff_end: %d : %s",
+                       decoder_ms, start_ms, end_ms, end_ms - start_ms, diff_start_ms, diff_end_ms, text.c_str());
+#endif
 
                if ( diff_ms < -100 )
                {
+#ifdef SUBTITLE_DEBUG
                        eDebug("subtitle too late... drop");
+#endif
                        m_subtitle_pages.pop_front();
                }
                else if ( diff_ms > 20 )
                {
-                       eDebug("start timer");
-                       m_subtitle_sync_timer->start(diff_ms, true);
+#ifdef SUBTITLE_DEBUG
+                       eDebug("*** current sub in the future, start timer, %d\n", diff_start_ms);
+#endif
+                       next_timer = diff_ms;
                        break;
                }
                else // immediate show
                {
                        if ( m_subtitle_widget )
                        {
-                               eDebug("show!\n");
+#ifdef SUBTITLE_DEBUG
+                               eDebug("*** current sub actual, show!");
+#endif
                                if ( frontpage.type == SubtitlePage::Pango)
                                        m_subtitle_widget->setPage(frontpage.pango_page);
                                m_subtitle_widget->show();
@@ -1815,8 +2008,11 @@ void eServiceMP3::pushSubtitles()
                        m_subtitle_pages.pop_front();
                }
        }
-       if (m_subtitle_pages.empty())
-               pullSubtitle();
+       if (!next_timer)
+       {
+               next_timer = 1000;
+       }
+       m_subtitle_sync_timer->start(next_timer, true);
 }
 
 
@@ -1827,7 +2023,6 @@ RESULT eServiceMP3::enableSubtitles(eWidget *parent, ePyObject tuple)
        int tuplesize = PyTuple_Size(tuple);
        int pid, type;
        gint text_pid = 0;
-       eSingleLocker l(m_subs_to_pull_lock);
 
 //     GstPad *pad = 0;
 //     g_signal_emit_by_name (m_gst_playbin, "get-text-pad", m_currentSubtitleStream, &pad);
@@ -1849,12 +2044,14 @@ RESULT eServiceMP3::enableSubtitles(eWidget *parent, ePyObject tuple)
 
        if (m_currentSubtitleStream != pid)
        {
-               g_object_set (G_OBJECT (m_gst_playbin), "current-text", pid, NULL);
-               eDebug ("eServiceMP3::enableSubtitles g_object_set current-text = %i", pid);
-               m_currentSubtitleStream = pid;
-               m_subs_to_pull = 0;
-               m_prev_decoder_time = -1;
+               g_object_set (G_OBJECT (m_gst_playbin), "current-text", -1, NULL);
+               m_subtitle_sync_timer->stop();
                m_subtitle_pages.clear();
+               m_prev_decoder_time = -1;
+               m_decoder_time_valid_state = 0;
+               m_currentSubtitleStream = pid;
+               g_object_set (G_OBJECT (m_gst_playbin), "current-text", m_currentSubtitleStream, NULL);
+               eDebug ("eServiceMP3::enableSubtitles g_object_set current-text = %i", pid);
        }
 
        m_subtitle_widget = 0;
@@ -1866,6 +2063,14 @@ RESULT eServiceMP3::enableSubtitles(eWidget *parent, ePyObject tuple)
        eDebug ("eServiceMP3::switched to subtitle stream %i", text_pid);
 //     gst_pad_remove_buffer_probe (pad, subprobe_handler_id);
 
+#ifdef GSTREAMER_SUBTITLE_SYNC_MODE_BUG
+                       /*
+                        * when we're running the subsink in sync=false mode,
+                        * we have to force a seek, before the new subtitle stream will start
+                        */
+                       seekRelative(-1, 90000);
+#endif
+
        m_event((iPlayableService*)this, evUpdatedInfo);
 
        return 0;
@@ -1878,9 +2083,15 @@ error_out:
 
 RESULT eServiceMP3::disableSubtitles(eWidget *parent)
 {
+       m_currentSubtitleStream = -1;
+       g_object_set (G_OBJECT (m_gst_playbin), "current-text", m_currentSubtitleStream, NULL);
        eDebug("eServiceMP3::disableSubtitles");
+       m_subtitle_sync_timer->stop();
        m_subtitle_pages.clear();
-       delete m_subtitle_widget;
+       m_prev_decoder_time = -1;
+       m_decoder_time_valid_state = 0;
+       if (m_subtitle_widget)
+               delete m_subtitle_widget;
        m_subtitle_widget = 0;
        return 0;
 }
index 41aec13..156400d 100644 (file)
@@ -189,8 +189,6 @@ private:
        std::vector<subtitleStream> m_subtitleStreams;
        eSubtitleWidget *m_subtitle_widget;
        int m_currentTrickRatio;
-       ePtr<eTimer> m_seekTimeout;
-       void seekTimeoutCB();
        friend class eServiceFactoryMP3;
        eServiceReference m_ref;
        int m_buffer_size;
@@ -222,9 +220,15 @@ private:
                 {
                         d.pad=pad;
                 }
+                               Message(int type, GstBuffer *buffer)
+                        :type(type)
+                {
+                        d.buffer=buffer;
+                }
 
                 int type;
                 union {
+                        GstBuffer *buffer; // for msg type 2
                         GstPad *pad; // for msg type 3
                 } d;
         };
@@ -232,12 +236,16 @@ private:
         eFixedMessagePump<Message> m_pump;
 
         audiotype_t gstCheckAudioPad(GstStructure* structure);
+#if GST_VERSION_MAJOR < 1
         static gint match_sinktype(GstElement *element, gpointer type);
+#else
+        static gint match_sinktype(const GValue *velement, const gchar *type);
+#endif
         void gstBusCall(GstBus *bus, GstMessage *msg);
         static GstBusSyncReply gstBusSyncHandler(GstBus *bus, GstMessage *message, gpointer user_data);
        static void gstTextpadHasCAPS(GstPad *pad, GParamSpec * unused, gpointer user_data);
        void gstTextpadHasCAPS_synced(GstPad *pad);
-        static void gstCBsubtitleAvail(GstElement *element, gpointer user_data);
+        static void gstCBsubtitleAvail(GstElement *element, GstBuffer *buffer, gpointer user_data);
         GstPad* gstCreateSubtitleSink(eServiceMP3* _this, subtype_t type);
        void gstPoll(const Message&);
         static void gstHTTPSourceSetAgent(GObject *source, GParamSpec *unused, gpointer user_data);
@@ -257,11 +265,9 @@ private:
         int m_decoder_time_valid_state;
 
         void pushSubtitles();
-        void pullSubtitle();
+        void pullSubtitle(GstBuffer *buffer);
         void sourceTimeout();
-        int m_subs_to_pull;
         sourceStream m_sourceinfo;
-       eSingleLock m_subs_to_pull_lock;
        gulong m_subs_to_pull_handler_id;
 
        RESULT seekToImpl(pts_t to);