Screens/LocationBox.py: Get rid of "from Directories import *"
[openblackhole/openblackhole-enigma2.git] / lib / service / servicem2ts.cpp
index d4fc73b..9900919 100644 (file)
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <lib/base/init_num.h>
 #include <lib/base/init.h>
+#include <lib/dvb/metaparser.h>
 #include <lib/service/servicem2ts.h>
 
 DEFINE_REF(eServiceFactoryM2TS)
 
-class eM2TSFile: public iDataSource
+class eM2TSFile: public iTsSource
 {
        DECLARE_REF(eM2TSFile);
        eSingleLock m_lock;
 public:
-       eM2TSFile(const char *filename, bool cached=false);
+       eM2TSFile(const char *filename);
        ~eM2TSFile();
 
-       // iDataSource
-       off_t lseek(off_t offset, int whence);
+       // iTsSource
        ssize_t read(off_t offset, void *buf, size_t count);
        off_t length();
+       off_t offset();
        int valid();
 private:
-       int m_fd;     /* for uncached */
-       FILE *m_file; /* for cached */
-       off_t m_current_offset, m_length;
-       bool m_cached;
+       int m_sync_offset;
+       int m_fd;
+       off_t m_current_offset;
+       off_t m_length;
        off_t lseek_internal(off_t offset, int whence);
 };
 
-DEFINE_REF(eM2TSFile);
+class eStaticServiceM2TSInformation: public iStaticServiceInformation
+{
+       DECLARE_REF(eStaticServiceM2TSInformation);
+       eServiceReference m_ref;
+       eDVBMetaParser m_parser;
+public:
+       eStaticServiceM2TSInformation(const eServiceReference &ref);
+       RESULT getName(const eServiceReference &ref, std::string &name);
+       int getLength(const eServiceReference &ref);
+       RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
+       int isPlayable(const eServiceReference &ref, const eServiceReference &ignore, bool simulate) { return 1; }
+       int getInfo(const eServiceReference &ref, int w);
+       std::string getInfoString(const eServiceReference &ref,int w);
+       long long getFileSize(const eServiceReference &ref);
+};
+
+DEFINE_REF(eStaticServiceM2TSInformation);
 
-eM2TSFile::eM2TSFile(const char *filename, bool cached)
-       :m_lock(false), m_fd(-1), m_file(NULL), m_current_offset(0), m_length(0), m_cached(cached)
+eStaticServiceM2TSInformation::eStaticServiceM2TSInformation(const eServiceReference &ref)
 {
-       eDebug("eM2TSFile %p %s", this, filename);
-       if (!m_cached)
-               m_fd = ::open(filename, O_RDONLY | O_LARGEFILE);
+       m_ref = ref;
+       m_parser.parseFile(ref.path);
+}
+
+RESULT eStaticServiceM2TSInformation::getName(const eServiceReference &ref, std::string &name)
+{
+       ASSERT(ref == m_ref);
+       if (m_parser.m_name.size())
+               name = m_parser.m_name;
        else
-               m_file = ::fopen64(filename, "rb");
-       if (valid())
-               m_current_offset = m_length = lseek_internal(0, SEEK_END);
+       {
+               name = ref.path;
+               size_t n = name.rfind('/');
+               if (n != std::string::npos)
+                       name = name.substr(n + 1);
+       }
+       return 0;
 }
 
-eM2TSFile::~eM2TSFile()
+int eStaticServiceM2TSInformation::getLength(const eServiceReference &ref)
+{
+       ASSERT(ref == m_ref);
+
+       eDVBTSTools tstools;
+
+       struct stat s;
+       stat(ref.path.c_str(), &s);
+
+       eM2TSFile *file = new eM2TSFile(ref.path.c_str());
+       ePtr<iTsSource> source = file;
+
+       if (!source->valid())
+               return 0;
+
+       tstools.setSource(source);
+
+                       /* check if cached data is still valid */
+       if (m_parser.m_data_ok && (s.st_size == m_parser.m_filesize) && (m_parser.m_length))
+               return m_parser.m_length / 90000;
+
+       /* open again, this time with stream info */
+       tstools.setSource(source, ref.path.c_str());
+
+                       /* otherwise, re-calc length and update meta file */
+       pts_t len;
+       if (tstools.calcLen(len))
+               return 0;
+
+       m_parser.m_length = len;
+       m_parser.m_filesize = s.st_size;
+       m_parser.updateMeta(ref.path);
+       return m_parser.m_length / 90000;
+}
+
+int eStaticServiceM2TSInformation::getInfo(const eServiceReference &ref, int w)
 {
-       eDebug("~eM2TSFile %p", this);
-       if (m_cached)
+       switch (w)
        {
-               if (m_file)
-               {
-                       ::fclose(m_file);
-                       m_file = 0;
-               }
+       case iServiceInformation::sDescription:
+               return iServiceInformation::resIsString;
+       case iServiceInformation::sServiceref:
+               return iServiceInformation::resIsString;
+       case iServiceInformation::sFileSize:
+               return m_parser.m_filesize;
+       case iServiceInformation::sTimeCreate:
+               if (m_parser.m_time_create)
+                       return m_parser.m_time_create;
+               else
+                       return iServiceInformation::resNA;
+       default:
+               return iServiceInformation::resNA;
        }
-       else
+}
+
+std::string eStaticServiceM2TSInformation::getInfoString(const eServiceReference &ref,int w)
+{
+       switch (w)
        {
-               if (m_fd >= 0)
-                       ::close(m_fd);
-               m_fd = -1;
+       case iServiceInformation::sDescription:
+               return m_parser.m_description;
+       case iServiceInformation::sServiceref:
+               return m_parser.m_ref.toString();
+       case iServiceInformation::sTags:
+               return m_parser.m_tags;
+       default:
+               return "";
        }
 }
 
-off_t eM2TSFile::lseek(off_t offset, int whence)
+long long eStaticServiceM2TSInformation::getFileSize(const eServiceReference &ref)
 {
-       eSingleLocker l(m_lock);
+       return m_parser.m_filesize;
+}
 
-       offset = offset * 192 / 188;
-       ASSERT(!(offset % 192));
+RESULT eStaticServiceM2TSInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
+{
+       if (!ref.path.empty())
+       {
+               ePtr<eServiceEvent> event = new eServiceEvent;
+               std::string filename = ref.path;
+               filename.erase(filename.length()-4, 2);
+               filename+="eit";
+               if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
+               {
+                       evt = event;
+                       return 0;
+               }
+       }
+       evt = 0;
+       return -1;
+}
 
-       if (offset != m_current_offset)
-               m_current_offset = lseek_internal(offset, whence);
+DEFINE_REF(eM2TSFile);
 
-       return m_current_offset;
+eM2TSFile::eM2TSFile(const char *filename):
+       m_lock(),
+       m_sync_offset(0),
+       m_fd(::open(filename, O_RDONLY | O_LARGEFILE | O_CLOEXEC)),
+       m_current_offset(0),
+       m_length(0)
+{
+       if (m_fd != -1)
+               m_current_offset = m_length = lseek_internal(0, SEEK_END);
+}
+
+eM2TSFile::~eM2TSFile()
+{
+       if (m_fd != -1)
+               ::close(m_fd);
 }
 
 off_t eM2TSFile::lseek_internal(off_t offset, int whence)
 {
        off_t ret;
 
-       if (!m_cached)
-               ret = ::lseek(m_fd, offset, whence);
-       else
-       {
-               if (::fseeko(m_file, offset, whence) < 0)
-                       perror("fseeko");
-               ret = ::ftello(m_file);
-       }
-       return ret <= 0 ? ret : ret*188/192;
+       ret = ::lseek(m_fd, offset, whence);
+       return ret <= 0 ? ret : (ret % 192) + (ret*188) / 192;
 }
 
 ssize_t eM2TSFile::read(off_t offset, void *b, size_t count)
 {
        eSingleLocker l(m_lock);
-       unsigned char tmp[192];
+       unsigned char tmp[192*3];
        unsigned char *buf = (unsigned char*)b;
-       size_t rd=0;
-
-       offset = offset * 192 / 188;
-       ASSERT(!(offset % 192));
 
-       ASSERT(!(count % 188));
+       size_t rd=0;
+       offset = (offset % 188) + (offset * 192) / 188;
 
-       if (offset != m_current_offset)
+sync:
+       if ((offset+m_sync_offset) != m_current_offset)
        {
-               m_current_offset = lseek_internal(offset, SEEK_SET);
+//             eDebug("[eM2TSFile] seekTo %lld", offset+m_sync_offset);
+               m_current_offset = lseek_internal(offset+m_sync_offset, SEEK_SET);
                if (m_current_offset < 0)
                        return m_current_offset;
        }
 
        while (rd < count) {
                size_t ret;
-               if (!m_cached)
-                       ret = ::read(m_fd, tmp, 192);
-               else
-                       ret = ::fread(tmp, 1, 192, m_file);
-               if (ret > 0)
-                       m_current_offset += ret;
+               ret = ::read(m_fd, tmp, 192);
                if (ret < 0 || ret < 192)
                        return rd ? rd : ret;
+
+               if (tmp[4] != 0x47)
+               {
+                       if (rd > 0) {
+                               eDebug("[eM2TSFile] short read at pos %lld async!!", m_current_offset);
+                               return rd;
+                       }
+                       else {
+                               int x=0;
+                               ret = ::read(m_fd, tmp+192, 384);
+
+#if 0
+                               eDebugNoNewLineStart("[eM2TSFile] m2ts out of sync at pos %lld, real %lld:", offset + m_sync_offset, m_current_offset);
+                               for (; x < 192; ++x)
+                                       eDebugNoNewLine(" %02x", tmp[x]);
+                               eDebugNoNewLine("\n");
+                               x=0;
+#else
+                               eDebug("[eM2TSFile] m2ts out of sync at pos %lld, real %lld", offset + m_sync_offset, m_current_offset);
+#endif
+                               for (; x < 192; ++x)
+                               {
+                                       if (tmp[x] == 0x47 && tmp[x+192] == 0x47)
+                                       {
+                                               int add_offs = (x - 4);
+                                               eDebug("[eM2TSFile] sync found at pos %d, sync_offset is now %d, old was %d", x, add_offs + m_sync_offset, m_sync_offset);
+                                               m_sync_offset += add_offs;
+                                               goto sync;
+                                       }
+                               }
+                       }
+               }
+
                memcpy(buf+rd, tmp+4, 188);
+
                rd += 188;
+               m_current_offset += 188;
        }
 
+       m_sync_offset %= 188;
+
        return rd;
 }
 
 int eM2TSFile::valid()
 {
-       if (!m_cached)
-               return m_fd != -1;
-       else
-               return !!m_file;
+       return m_fd != -1;
 }
 
 off_t eM2TSFile::length()
@@ -135,10 +264,14 @@ off_t eM2TSFile::length()
        return m_length;
 }
 
+off_t eM2TSFile::offset()
+{
+       return m_current_offset;
+}
+
 eServiceFactoryM2TS::eServiceFactoryM2TS()
 {
        ePtr<eServiceCenter> sc;
-       eDebug("!!!!!!!!!!!!!!!!!!!eServiceFactoryM2TS");
        eServiceCenter::getPrivInstance(sc);
        if (sc)
        {
@@ -152,7 +285,7 @@ eServiceFactoryM2TS::eServiceFactoryM2TS()
 eServiceFactoryM2TS::~eServiceFactoryM2TS()
 {
        ePtr<eServiceCenter> sc;
-       
+
        eServiceCenter::getPrivInstance(sc);
        if (sc)
                sc->removeServiceFactory(eServiceFactoryM2TS::id);
@@ -178,6 +311,7 @@ RESULT eServiceFactoryM2TS::list(const eServiceReference &ref, ePtr<iListableSer
 
 RESULT eServiceFactoryM2TS::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
 {
+       ptr=new eStaticServiceM2TSInformation(ref);
        return 0;
 }
 
@@ -190,18 +324,17 @@ RESULT eServiceFactoryM2TS::offlineOperations(const eServiceReference &ref, ePtr
 eServiceM2TS::eServiceM2TS(const eServiceReference &ref)
        :eDVBServicePlay(ref, NULL)
 {
-       eDebug("eServiceM2TS %p", this);
 }
 
-eServiceM2TS::~eServiceM2TS()
+ePtr<iTsSource> eServiceM2TS::createTsSource(eServiceReferenceDVB &ref, int packetsize)
 {
-       eDebug("~eServiceM2TS %p", this);
+       ePtr<iTsSource> source = new eM2TSFile(ref.path.c_str());
+       return source;
 }
 
-ePtr<iDataSource> eServiceM2TS::createDataSource(const eServiceReferenceDVB &ref)
+RESULT eServiceM2TS::isCurrentlySeekable()
 {
-       ePtr<iDataSource> source = new eM2TSFile(ref.path.c_str());
-       return source;
+       return 1; // for fast winding we need index files... so only skip forward/backward yet
 }
 
 eAutoInitPtr<eServiceFactoryM2TS> init_eServiceFactoryM2TS(eAutoInitNumbers::service+1, "eServiceFactoryM2TS");