X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=blobdiff_plain;f=lib%2Fservice%2Fservicem2ts.cpp;h=e79907dd7f195f2a84977e380187fa0ece646e6c;hp=d4fc73b0595f3df6a3ddc0d96c5b72bff84aa7d5;hb=ba5ec76317a3bd96895506159b0d5bc1a1a6eecc;hpb=1f221785b20603329bce01a88c30a70271998fe1 diff --git a/lib/service/servicem2ts.cpp b/lib/service/servicem2ts.cpp index d4fc73b..e79907d 100644 --- a/lib/service/servicem2ts.cpp +++ b/lib/service/servicem2ts.cpp @@ -1,10 +1,11 @@ #include #include +#include #include DEFINE_REF(eServiceFactoryM2TS) -class eM2TSFile: public iDataSource +class eM2TSFile: public iTsSource { DECLARE_REF(eM2TSFile); eSingleLock m_lock; @@ -12,12 +13,13 @@ public: eM2TSFile(const char *filename, bool cached=false); ~eM2TSFile(); - // iDataSource + // iTsSource off_t lseek(off_t offset, int whence); ssize_t read(off_t offset, void *buf, size_t count); off_t length(); int valid(); private: + int m_sync_offset; int m_fd; /* for uncached */ FILE *m_file; /* for cached */ off_t m_current_offset, m_length; @@ -25,12 +27,149 @@ private: off_t lseek_internal(off_t offset, int whence); }; +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 &SWIG_OUTPUT, time_t start_time); + int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; } + int getInfo(const eServiceReference &ref, int w); + std::string getInfoString(const eServiceReference &ref,int w); + PyObject *getInfoObject(const eServiceReference &r, int what); +}; + +DEFINE_REF(eStaticServiceM2TSInformation); + +eStaticServiceM2TSInformation::eStaticServiceM2TSInformation(const eServiceReference &ref) +{ + 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 + { + name = ref.path; + size_t n = name.rfind('/'); + if (n != std::string::npos) + name = name.substr(n + 1); + } + return 0; +} + +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 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) +{ + switch (w) + { + 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; + } +} + +std::string eStaticServiceM2TSInformation::getInfoString(const eServiceReference &ref,int w) +{ + switch (w) + { + 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 ""; + } +} + +PyObject *eStaticServiceM2TSInformation::getInfoObject(const eServiceReference &r, int what) +{ + switch (what) + { + case iServiceInformation::sFileSize: + return PyLong_FromLongLong(m_parser.m_filesize); + default: + Py_RETURN_NONE; + } +} + +RESULT eStaticServiceM2TSInformation::getEvent(const eServiceReference &ref, ePtr &evt, time_t start_time) +{ + if (!ref.path.empty()) + { + ePtr 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; +} + DEFINE_REF(eM2TSFile); 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) + :m_lock(false), m_sync_offset(0), m_fd(-1), m_file(NULL), m_current_offset(0), m_length(0), m_cached(cached) { - eDebug("eM2TSFile %p %s", this, filename); if (!m_cached) m_fd = ::open(filename, O_RDONLY | O_LARGEFILE); else @@ -41,7 +180,6 @@ eM2TSFile::eM2TSFile(const char *filename, bool cached) eM2TSFile::~eM2TSFile() { - eDebug("~eM2TSFile %p", this); if (m_cached) { if (m_file) @@ -62,8 +200,7 @@ off_t eM2TSFile::lseek(off_t offset, int whence) { eSingleLocker l(m_lock); - offset = offset * 192 / 188; - ASSERT(!(offset % 192)); + offset = (offset % 188) + (offset * 192) / 188; if (offset != m_current_offset) m_current_offset = lseek_internal(offset, whence); @@ -83,24 +220,23 @@ off_t eM2TSFile::lseek_internal(off_t offset, int whence) perror("fseeko"); ret = ::ftello(m_file); } - return ret <= 0 ? ret : ret*188/192; + 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("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; } @@ -111,14 +247,52 @@ ssize_t eM2TSFile::read(off_t offset, void *b, size_t count) ret = ::read(m_fd, tmp, 192); else ret = ::fread(tmp, 1, 192, m_file); - if (ret > 0) - m_current_offset += ret; if (ret < 0 || ret < 192) return rd ? rd : ret; + + if (tmp[4] != 0x47) + { + if (rd > 0) { + eDebug("short read at pos %lld async!!", m_current_offset); + return rd; + } + else { + int x=0; + if (!m_cached) + ret = ::read(m_fd, tmp+192, 384); + else + ret = ::fread(tmp+192, 1, 384, m_file); + +#if 0 + eDebugNoNewLine("m2ts out of sync at pos %lld, real %lld:", offset + m_sync_offset, m_current_offset); + for (; x < 192; ++x) + eDebugNoNewLine(" %02x", tmp[x]); + eDebug(""); + x=0; +#else + eDebug("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("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; } @@ -138,7 +312,6 @@ off_t eM2TSFile::length() eServiceFactoryM2TS::eServiceFactoryM2TS() { ePtr sc; - eDebug("!!!!!!!!!!!!!!!!!!!eServiceFactoryM2TS"); eServiceCenter::getPrivInstance(sc); if (sc) { @@ -178,6 +351,7 @@ RESULT eServiceFactoryM2TS::list(const eServiceReference &ref, ePtr &ptr) { + ptr=new eStaticServiceM2TSInformation(ref); return 0; } @@ -190,18 +364,17 @@ RESULT eServiceFactoryM2TS::offlineOperations(const eServiceReference &ref, ePtr eServiceM2TS::eServiceM2TS(const eServiceReference &ref) :eDVBServicePlay(ref, NULL) { - eDebug("eServiceM2TS %p", this); } -eServiceM2TS::~eServiceM2TS() +ePtr eServiceM2TS::createTsSource(eServiceReferenceDVB &ref) { - eDebug("~eServiceM2TS %p", this); + ePtr source = new eM2TSFile(ref.path.c_str()); + return source; } -ePtr eServiceM2TS::createDataSource(const eServiceReferenceDVB &ref) +RESULT eServiceM2TS::isCurrentlySeekable() { - ePtr 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 init_eServiceFactoryM2TS(eAutoInitNumbers::service+1, "eServiceFactoryM2TS");