From 7b5579c5aac63a59dedb20067562ff097da5b1f3 Mon Sep 17 00:00:00 2001 From: ghost Date: Thu, 11 Nov 2010 13:52:52 +0100 Subject: add m2ts service --- lib/service/servicem2ts.cpp | 207 ++++++++++++++++++++++++++++++++++++++++++++ lib/service/servicem2ts.h | 32 +++++++ 2 files changed, 239 insertions(+) create mode 100644 lib/service/servicem2ts.cpp create mode 100644 lib/service/servicem2ts.h diff --git a/lib/service/servicem2ts.cpp b/lib/service/servicem2ts.cpp new file mode 100644 index 00000000..d4fc73b0 --- /dev/null +++ b/lib/service/servicem2ts.cpp @@ -0,0 +1,207 @@ +#include +#include +#include + +DEFINE_REF(eServiceFactoryM2TS) + +class eM2TSFile: public iDataSource +{ + DECLARE_REF(eM2TSFile); + eSingleLock m_lock; +public: + eM2TSFile(const char *filename, bool cached=false); + ~eM2TSFile(); + + // iDataSource + 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_fd; /* for uncached */ + FILE *m_file; /* for cached */ + off_t m_current_offset, m_length; + bool m_cached; + off_t lseek_internal(off_t offset, int whence); +}; + +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) +{ + eDebug("eM2TSFile %p %s", this, filename); + if (!m_cached) + m_fd = ::open(filename, O_RDONLY | O_LARGEFILE); + else + m_file = ::fopen64(filename, "rb"); + if (valid()) + m_current_offset = m_length = lseek_internal(0, SEEK_END); +} + +eM2TSFile::~eM2TSFile() +{ + eDebug("~eM2TSFile %p", this); + if (m_cached) + { + if (m_file) + { + ::fclose(m_file); + m_file = 0; + } + } + else + { + if (m_fd >= 0) + ::close(m_fd); + m_fd = -1; + } +} + +off_t eM2TSFile::lseek(off_t offset, int whence) +{ + eSingleLocker l(m_lock); + + offset = offset * 192 / 188; + ASSERT(!(offset % 192)); + + if (offset != m_current_offset) + m_current_offset = lseek_internal(offset, whence); + + return m_current_offset; +} + +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; +} + +ssize_t eM2TSFile::read(off_t offset, void *b, size_t count) +{ + eSingleLocker l(m_lock); + unsigned char tmp[192]; + unsigned char *buf = (unsigned char*)b; + size_t rd=0; + + offset = offset * 192 / 188; + ASSERT(!(offset % 192)); + + ASSERT(!(count % 188)); + + if (offset != m_current_offset) + { + m_current_offset = lseek_internal(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; + if (ret < 0 || ret < 192) + return rd ? rd : ret; + memcpy(buf+rd, tmp+4, 188); + rd += 188; + } + + return rd; +} + +int eM2TSFile::valid() +{ + if (!m_cached) + return m_fd != -1; + else + return !!m_file; +} + +off_t eM2TSFile::length() +{ + return m_length; +} + +eServiceFactoryM2TS::eServiceFactoryM2TS() +{ + ePtr sc; + eDebug("!!!!!!!!!!!!!!!!!!!eServiceFactoryM2TS"); + eServiceCenter::getPrivInstance(sc); + if (sc) + { + std::list extensions; + extensions.push_back("m2ts"); + extensions.push_back("mts"); + sc->addServiceFactory(eServiceFactoryM2TS::id, this, extensions); + } +} + +eServiceFactoryM2TS::~eServiceFactoryM2TS() +{ + ePtr sc; + + eServiceCenter::getPrivInstance(sc); + if (sc) + sc->removeServiceFactory(eServiceFactoryM2TS::id); +} + +RESULT eServiceFactoryM2TS::play(const eServiceReference &ref, ePtr &ptr) +{ + ptr = new eServiceM2TS(ref); + return 0; +} + +RESULT eServiceFactoryM2TS::record(const eServiceReference &ref, ePtr &ptr) +{ + ptr=0; + return -1; +} + +RESULT eServiceFactoryM2TS::list(const eServiceReference &ref, ePtr &ptr) +{ + ptr=0; + return -1; +} + +RESULT eServiceFactoryM2TS::info(const eServiceReference &ref, ePtr &ptr) +{ + return 0; +} + +RESULT eServiceFactoryM2TS::offlineOperations(const eServiceReference &ref, ePtr &ptr) +{ + ptr = 0; + return -1; +} + +eServiceM2TS::eServiceM2TS(const eServiceReference &ref) + :eDVBServicePlay(ref, NULL) +{ + eDebug("eServiceM2TS %p", this); +} + +eServiceM2TS::~eServiceM2TS() +{ + eDebug("~eServiceM2TS %p", this); +} + +ePtr eServiceM2TS::createDataSource(const eServiceReferenceDVB &ref) +{ + ePtr source = new eM2TSFile(ref.path.c_str()); + return source; +} + +eAutoInitPtr init_eServiceFactoryM2TS(eAutoInitNumbers::service+1, "eServiceFactoryM2TS"); diff --git a/lib/service/servicem2ts.h b/lib/service/servicem2ts.h new file mode 100644 index 00000000..2b05f076 --- /dev/null +++ b/lib/service/servicem2ts.h @@ -0,0 +1,32 @@ +#ifndef __servicem2ts_h +#define __servicem2ts_h + +#include + +class eServiceFactoryM2TS: public iServiceHandler +{ + DECLARE_REF(eServiceFactoryM2TS); +public: + eServiceFactoryM2TS(); + virtual ~eServiceFactoryM2TS(); + enum { id = 0x3 }; + + // iServiceHandler + RESULT play(const eServiceReference &, ePtr &ptr); + RESULT record(const eServiceReference &, ePtr &ptr); + RESULT list(const eServiceReference &, ePtr &ptr); + RESULT info(const eServiceReference &, ePtr &ptr); + RESULT offlineOperations(const eServiceReference &, ePtr &ptr); +}; + +class eServiceM2TS: public eDVBServicePlay +{ + friend class eServiceFactoryM2TS; +protected: + eServiceM2TS(const eServiceReference &ref); + ePtr createDataSource(const eServiceReferenceDVB &ref); +public: + ~eServiceM2TS(); +}; + +#endif -- cgit v1.2.3 From a543d670adf570b5ca49e48cdac5a22f2f0c48e7 Mon Sep 17 00:00:00 2001 From: ghost Date: Tue, 23 Nov 2010 12:37:16 +0100 Subject: more work on servicem2ts --- lib/service/servicem2ts.cpp | 167 ++++++++++++++++++++++++++++++++++++++++---- lib/service/servicem2ts.h | 7 +- 2 files changed, 156 insertions(+), 18 deletions(-) diff --git a/lib/service/servicem2ts.cpp b/lib/service/servicem2ts.cpp index d4fc73b0..a86642c3 100644 --- a/lib/service/servicem2ts.cpp +++ b/lib/service/servicem2ts.cpp @@ -1,5 +1,6 @@ #include #include +#include #include DEFINE_REF(eServiceFactoryM2TS) @@ -25,12 +26,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) { - eDebug("eM2TSFile %p %s", this, filename); if (!m_cached) m_fd = ::open(filename, O_RDONLY | O_LARGEFILE); else @@ -41,7 +179,6 @@ eM2TSFile::eM2TSFile(const char *filename, bool cached) eM2TSFile::~eM2TSFile() { - eDebug("~eM2TSFile %p", this); if (m_cached) { if (m_file) @@ -62,7 +199,7 @@ off_t eM2TSFile::lseek(off_t offset, int whence) { eSingleLocker l(m_lock); - offset = offset * 192 / 188; + offset = (offset * 192) / 188; ASSERT(!(offset % 192)); if (offset != m_current_offset) @@ -83,7 +220,7 @@ 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*188)/192; } ssize_t eM2TSFile::read(off_t offset, void *b, size_t count) @@ -93,9 +230,8 @@ ssize_t eM2TSFile::read(off_t offset, void *b, size_t count) unsigned char *buf = (unsigned char*)b; size_t rd=0; - offset = offset * 192 / 188; + offset = (offset * 192) / 188; ASSERT(!(offset % 192)); - ASSERT(!(count % 188)); if (offset != m_current_offset) @@ -111,12 +247,14 @@ 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; memcpy(buf+rd, tmp+4, 188); + + ASSERT(buf[rd] == 0x47); + rd += 188; + m_current_offset += 188; } return rd; @@ -138,7 +276,6 @@ off_t eM2TSFile::length() eServiceFactoryM2TS::eServiceFactoryM2TS() { ePtr sc; - eDebug("!!!!!!!!!!!!!!!!!!!eServiceFactoryM2TS"); eServiceCenter::getPrivInstance(sc); if (sc) { @@ -178,6 +315,7 @@ RESULT eServiceFactoryM2TS::list(const eServiceReference &ref, ePtr &ptr) { + ptr=new eStaticServiceM2TSInformation(ref); return 0; } @@ -190,18 +328,17 @@ RESULT eServiceFactoryM2TS::offlineOperations(const eServiceReference &ref, ePtr eServiceM2TS::eServiceM2TS(const eServiceReference &ref) :eDVBServicePlay(ref, NULL) { - eDebug("eServiceM2TS %p", this); } -eServiceM2TS::~eServiceM2TS() +ePtr eServiceM2TS::createDataSource(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"); diff --git a/lib/service/servicem2ts.h b/lib/service/servicem2ts.h index 2b05f076..a53f731f 100644 --- a/lib/service/servicem2ts.h +++ b/lib/service/servicem2ts.h @@ -24,9 +24,10 @@ class eServiceM2TS: public eDVBServicePlay friend class eServiceFactoryM2TS; protected: eServiceM2TS(const eServiceReference &ref); - ePtr createDataSource(const eServiceReferenceDVB &ref); -public: - ~eServiceM2TS(); + ePtr createDataSource(eServiceReferenceDVB &ref); + + // iSeekableService + RESULT isCurrentlySeekable(); }; #endif -- cgit v1.2.3 From fc8be0878f710d73f3d1c1b1ed308ad27c5ddb15 Mon Sep 17 00:00:00 2001 From: ghost Date: Tue, 23 Nov 2010 12:40:13 +0100 Subject: use service_id and pmtpid from PAT when only one PAT entry is exist --- lib/dvb/pmt.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index 7b799662..0d2f85c4 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -131,6 +131,8 @@ void eDVBServicePMTHandler::PATready(int) ePtr > ptr; if (!m_PAT.getCurrent(ptr)) { + int service_id_single = -1; + int pmtpid_single = -1; int pmtpid = -1; std::vector::const_iterator i; for (i = ptr->getSections().begin(); pmtpid == -1 && i != ptr->getSections().end(); ++i) @@ -138,8 +140,22 @@ void eDVBServicePMTHandler::PATready(int) const ProgramAssociationSection &pat = **i; ProgramAssociationConstIterator program; for (program = pat.getPrograms()->begin(); pmtpid == -1 && program != pat.getPrograms()->end(); ++program) + { if (eServiceID((*program)->getProgramNumber()) == m_reference.getServiceID()) pmtpid = (*program)->getProgramMapPid(); + if (pmtpid_single == -1 && pmtpid == -1) + { + pmtpid_single = (*program)->getProgramMapPid(); + service_id_single = (*program)->getProgramNumber(); + } + else + pmtpid_single = service_id_single = -1; + } + } + if (pmtpid_single != -1) // only one PAT entry .. so we use this one + { + m_reference.setServiceID(eServiceID(service_id_single)); + pmtpid = pmtpid_single; } if (pmtpid == -1) serviceEvent(eventNoPATEntry); -- cgit v1.2.3 From 6a243eb89df7c0afd159a0820c897a8b5fcd8211 Mon Sep 17 00:00:00 2001 From: ghost Date: Tue, 23 Nov 2010 12:40:58 +0100 Subject: enable m2ts file extension --- lib/python/Components/FileList.py | 3 ++- lib/python/Plugins/Extensions/MediaPlayer/plugin.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/python/Components/FileList.py b/lib/python/Components/FileList.py index 1d71514b..1b7e81f5 100755 --- a/lib/python/Components/FileList.py +++ b/lib/python/Components/FileList.py @@ -28,7 +28,8 @@ EXTENSIONS = { "mpeg": "movie", "mkv": "movie", "mp4": "movie", - "mov": "movie" + "mov": "movie", + "m2ts": "movie", } def FileEntryComponent(name, absolute = None, isDir = False): diff --git a/lib/python/Plugins/Extensions/MediaPlayer/plugin.py b/lib/python/Plugins/Extensions/MediaPlayer/plugin.py index 9ae886fc..d61dbc76 100755 --- a/lib/python/Plugins/Extensions/MediaPlayer/plugin.py +++ b/lib/python/Plugins/Extensions/MediaPlayer/plugin.py @@ -110,7 +110,7 @@ class MediaPlayer(Screen, InfoBarBase, InfoBarSeek, InfoBarAudioSelection, InfoB # 'None' is magic to start at the list of mountpoints defaultDir = config.mediaplayer.defaultDir.getValue() - self.filelist = FileList(defaultDir, matchingPattern = "(?i)^.*\.(mp2|mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob|avi|divx|m4v|mkv|mp4|m4a|dat|flac|mov)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls") + self.filelist = FileList(defaultDir, matchingPattern = "(?i)^.*\.(mp2|mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob|avi|divx|m4v|mkv|mp4|m4a|dat|flac|mov|m2ts)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls") self["filelist"] = self.filelist self.playlist = MyPlayList() -- cgit v1.2.3 From 96ecbe2e2c2bcd048d1158b3d093732198475b07 Mon Sep 17 00:00:00 2001 From: ghost Date: Wed, 24 Nov 2010 16:07:23 +0100 Subject: follow iDataSource -> iTsSource name change --- lib/service/servicem2ts.cpp | 10 +++++----- lib/service/servicem2ts.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/service/servicem2ts.cpp b/lib/service/servicem2ts.cpp index a86642c3..67bc08cf 100644 --- a/lib/service/servicem2ts.cpp +++ b/lib/service/servicem2ts.cpp @@ -5,7 +5,7 @@ DEFINE_REF(eServiceFactoryM2TS) -class eM2TSFile: public iDataSource +class eM2TSFile: public iTsSource { DECLARE_REF(eM2TSFile); eSingleLock m_lock; @@ -13,7 +13,7 @@ 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(); @@ -75,7 +75,7 @@ int eStaticServiceM2TSInformation::getLength(const eServiceReference &ref) stat(ref.path.c_str(), &s); eM2TSFile *file = new eM2TSFile(ref.path.c_str()); - ePtr source = file; + ePtr source = file; if (!source->valid()) return 0; @@ -330,9 +330,9 @@ eServiceM2TS::eServiceM2TS(const eServiceReference &ref) { } -ePtr eServiceM2TS::createDataSource(eServiceReferenceDVB &ref) +ePtr eServiceM2TS::createTsSource(eServiceReferenceDVB &ref) { - ePtr source = new eM2TSFile(ref.path.c_str()); + ePtr source = new eM2TSFile(ref.path.c_str()); return source; } diff --git a/lib/service/servicem2ts.h b/lib/service/servicem2ts.h index a53f731f..bfa4f7d9 100644 --- a/lib/service/servicem2ts.h +++ b/lib/service/servicem2ts.h @@ -24,7 +24,7 @@ class eServiceM2TS: public eDVBServicePlay friend class eServiceFactoryM2TS; protected: eServiceM2TS(const eServiceReference &ref); - ePtr createDataSource(eServiceReferenceDVB &ref); + ePtr createTsSource(eServiceReferenceDVB &ref); // iSeekableService RESULT isCurrentlySeekable(); -- cgit v1.2.3 From 2d6c63801efcd62d89890e8e6143ab43bf87deca Mon Sep 17 00:00:00 2001 From: ghost Date: Wed, 24 Nov 2010 23:08:01 +0100 Subject: servicem2ts.cpp: resync on corrupt data --- lib/service/servicem2ts.cpp | 62 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/lib/service/servicem2ts.cpp b/lib/service/servicem2ts.cpp index 67bc08cf..e79907dd 100644 --- a/lib/service/servicem2ts.cpp +++ b/lib/service/servicem2ts.cpp @@ -19,6 +19,7 @@ public: 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; @@ -167,7 +168,7 @@ RESULT eStaticServiceM2TSInformation::getEvent(const eServiceReference &ref, ePt 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) { if (!m_cached) m_fd = ::open(filename, O_RDONLY | O_LARGEFILE); @@ -199,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); @@ -220,23 +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; } @@ -249,14 +249,50 @@ ssize_t eM2TSFile::read(off_t offset, void *b, size_t count) ret = ::fread(tmp, 1, 192, m_file); if (ret < 0 || ret < 192) return rd ? rd : ret; - memcpy(buf+rd, tmp+4, 188); - ASSERT(buf[rd] == 0x47); + 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; } -- cgit v1.2.3 From 8682ee11e24311ae3ae84665cd2da0075a0cf413 Mon Sep 17 00:00:00 2001 From: ghost Date: Wed, 24 Nov 2010 23:08:53 +0100 Subject: compile servicem2ts.cpp --- lib/service/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/service/Makefile.am b/lib/service/Makefile.am index ed09d73d..795900a6 100644 --- a/lib/service/Makefile.am +++ b/lib/service/Makefile.am @@ -5,5 +5,4 @@ noinst_LIBRARIES = libenigma_service.a libenigma_service_a_SOURCES = \ listboxservice.cpp service.cpp servicemp3.cpp servicedvb.cpp servicefs.cpp \ - event.cpp servicedvbrecord.cpp - + servicem2ts.cpp event.cpp servicedvbrecord.cpp -- cgit v1.2.3 From 266943db269293b00a9f2b59338b81cca5a928be Mon Sep 17 00:00:00 2001 From: ghost Date: Wed, 24 Nov 2010 23:09:52 +0100 Subject: add DTS-HD as known audio format, add detection to pmt parser (no hardware support for DTS-HD yet) --- lib/dvb/decoder.cpp | 3 +++ lib/dvb/decoder.h | 2 +- lib/dvb/idvb.h | 2 +- lib/dvb/pmt.cpp | 7 +++++++ lib/dvb/pmt.h | 2 +- lib/dvb/tstools.cpp | 2 ++ lib/service/servicedvb.cpp | 2 ++ 7 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/dvb/decoder.cpp b/lib/dvb/decoder.cpp index 88cd3ee1..8ed9f43f 100644 --- a/lib/dvb/decoder.cpp +++ b/lib/dvb/decoder.cpp @@ -203,6 +203,9 @@ int eDVBAudio::startPid(int pid, int type) case aLPCM: bypass = 6; break; + case aDTSHD: + bypass = 0x10; + break; } eDebugNoNewLine("AUDIO_SET_BYPASS(%d) - ", bypass); diff --git a/lib/dvb/decoder.h b/lib/dvb/decoder.h index 3a0fbac1..7610b654 100644 --- a/lib/dvb/decoder.h +++ b/lib/dvb/decoder.h @@ -13,7 +13,7 @@ private: ePtr m_demux; int m_fd, m_fd_demux, m_dev, m_is_freezed; public: - enum { aMPEG, aAC3, aDTS, aAAC, aAACHE, aLPCM }; + enum { aMPEG, aAC3, aDTS, aAAC, aAACHE, aLPCM, aDTSHD }; eDVBAudio(eDVBDemux *demux, int dev); enum { aMonoLeft, aStereo, aMonoRight }; void setChannel(int channel); diff --git a/lib/dvb/idvb.h b/lib/dvb/idvb.h index f15cd04e..e56a2c7b 100644 --- a/lib/dvb/idvb.h +++ b/lib/dvb/idvb.h @@ -650,7 +650,7 @@ public: /** Set Displayed Video PID and type */ virtual RESULT setVideoPID(int vpid, int type)=0; - enum { af_MPEG, af_AC3, af_DTS, af_AAC }; + enum { af_MPEG, af_AC3, af_DTS, af_AAC, af_DTSHD }; /** Set Displayed Audio PID and type */ virtual RESULT setAudioPID(int apid, int type)=0; diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index e54601cf..0b3e34a3 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -305,6 +305,13 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) isaudio = 1; audio.type = audioStream::atDTS; } + case 0x86: // Blueray DTS-HD (dvb user private...) + case 0xA6: // Blueray secondary DTS-HD + if (!isvideo && !isaudio) + { + isaudio = 1; + audio.type = audioStream::atDTSHD; + } case 0x06: // PES Private case 0xEA: // TS_PSI_ST_SMPTE_VC1 { diff --git a/lib/dvb/pmt.h b/lib/dvb/pmt.h index de0de052..e61f8713 100644 --- a/lib/dvb/pmt.h +++ b/lib/dvb/pmt.h @@ -144,7 +144,7 @@ public: { int pid, rdsPid; // hack for some radio services which transmit radiotext on different pid (i.e. harmony fm, HIT RADIO FFH, ...) - enum { atMPEG, atAC3, atDTS, atAAC, atAACHE, atLPCM }; + enum { atMPEG, atAC3, atDTS, atAAC, atAACHE, atLPCM, atDTSHD }; int type; // mpeg2, ac3, dts, ... int component_tag; diff --git a/lib/dvb/tstools.cpp b/lib/dvb/tstools.cpp index cfea3fdd..e93cfc0a 100644 --- a/lib/dvb/tstools.cpp +++ b/lib/dvb/tstools.cpp @@ -212,6 +212,8 @@ int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed) break; case 0x71: // AC3 / DTS break; + case 0x72: // DTS - HD + break; default: eDebug("skip unknwn stream_id_extension %02x\n", payload[9+offs]); continue; diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp index 0d617c30..0a2146db 100644 --- a/lib/service/servicedvb.cpp +++ b/lib/service/servicedvb.cpp @@ -1797,6 +1797,8 @@ RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int info.m_description = "AAC-HE"; else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS) info.m_description = "DTS"; + else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTSHD) + info.m_description = "DTS-HD"; else info.m_description = "???"; -- cgit v1.2.3 From 070b9256befecb72bbdc7052aef61e5f2f0b9515 Mon Sep 17 00:00:00 2001 From: ghost Date: Fri, 26 Nov 2010 01:36:09 +0100 Subject: pmt.cpp: only detect bluray streams when the HDMV descriptor is seen --- lib/dvb/pmt.cpp | 53 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index 0b3e34a3..d44766f1 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -229,8 +229,26 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i) { const ProgramMapSection &pmt = **i; + int is_hdmv = 0; + program.pcrPid = pmt.getPcrPid(); + for (DescriptorConstIterator desc = pmt.getDescriptors()->begin(); + desc != pmt.getDescriptors()->end(); ++desc) + { + if ((*desc)->getTag() == CA_DESCRIPTOR) + { + CaDescriptor *descr = (CaDescriptor*)(*desc); + program.caids.insert(descr->getCaSystemId()); + } + else if ((*desc)->getTag() == REGISTRATION_DESCRIPTOR) + { + RegistrationDescriptor *d = (RegistrationDescriptor*)(*desc); + if (d->getFormatIdentifier() == 0x48444d56) // HDMV + is_hdmv = 1; + } + } + ElementaryStreamInfoConstIterator es; for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es) { @@ -286,28 +304,30 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) audio.type = audioStream::atAACHE; forced_audio = 1; } - case 0x80: // user private ... but blueray LPCM - if (!isvideo && !isaudio) + case 0x80: // user private ... but bluray LPCM + case 0xA0: // bluray secondary LPCM + if (!isvideo && !isaudio && is_hdmv) { isaudio = 1; audio.type = audioStream::atLPCM; } - case 0x81: // user private ... but blueray AC3 - if (!isvideo && !isaudio) + case 0x81: // user private ... but bluray AC3 + case 0xA1: // bluray secondary AC3 + if (!isvideo && !isaudio && is_hdmv) { isaudio = 1; audio.type = audioStream::atAC3; } - case 0x82: // Blueray DTS (dvb user private...) - case 0xA2: // Blueray secondary DTS - if (!isvideo && !isaudio) + case 0x82: // bluray DTS (dvb user private...) + case 0xA2: // bluray secondary DTS + if (!isvideo && !isaudio && is_hdmv) { isaudio = 1; audio.type = audioStream::atDTS; } - case 0x86: // Blueray DTS-HD (dvb user private...) - case 0xA6: // Blueray secondary DTS-HD - if (!isvideo && !isaudio) + case 0x86: // bluray DTS-HD (dvb user private...) + case 0xA6: // bluray secondary DTS-HD + if (!isvideo && !isaudio && is_hdmv) { isaudio = 1; audio.type = audioStream::atDTSHD; @@ -500,9 +520,9 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) default: break; } - if (isteletext && (isaudio || isvideo)) + if (isteletext && (isaudio || isvideo)) { - eDebug("ambiguous streamtype for PID %04x detected.. forced as teletext!", (*es)->getPid()); + eDebug("ambiguous streamtype for PID %04x detected.. forced as teletext!", (*es)->getPid()); continue; // continue with next PID } else if (issubtitle && (isaudio || isvideo)) @@ -540,15 +560,6 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) else continue; } - for (DescriptorConstIterator desc = pmt.getDescriptors()->begin(); - desc != pmt.getDescriptors()->end(); ++desc) - { - if ((*desc)->getTag() == CA_DESCRIPTOR) - { - CaDescriptor *descr = (CaDescriptor*)(*desc); - program.caids.insert(descr->getCaSystemId()); - } - } } ret = 0; -- cgit v1.2.3 From 356d37043cbe1265a83c985e2cef7185daf74cb9 Mon Sep 17 00:00:00 2001 From: ghost Date: Mon, 29 Nov 2010 09:52:58 +0100 Subject: fixes PMT pid searching for TS files without meta file and sid in servicref (this fixes SID not found in PAT messages) refs #124 --- lib/dvb/pmt.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index d44766f1..cb80b00f 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -742,13 +742,12 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem { if (!ref.getServiceID().get() /* incorrect sid in meta file or recordings.epl*/ ) { - eWarning("no .meta file found, trying to find PMT pid"); eDVBTSTools tstools; + bool b = source || !tstools.openFile(ref.path.c_str(), 1); + eWarning("no .meta file found, trying to find PMT pid"); if (source) - tstools.setSource(source, streaminfo_file ? streaminfo_file : ref.path.c_str()); - else if (tstools.openFile(ref.path.c_str())) - eWarning("failed to open file"); - else + tstools.setSource(source, NULL); + if (b) { int service_id, pmt_pid; if (!tstools.findPMT(pmt_pid, service_id)) @@ -758,6 +757,8 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem m_pmt_pid = pmt_pid; } } + else + eWarning("no valid source to find PMT pid!"); } eDebug("alloc PVR"); /* allocate PVR */ -- cgit v1.2.3 From 654e9f170ac0db764a865f41983c925269d5c188 Mon Sep 17 00:00:00 2001 From: ghost Date: Thu, 2 Dec 2010 17:58:15 +0100 Subject: lib/dvb/esection.h: add handling for broken table version handling --- lib/dvb/esection.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/dvb/esection.h b/lib/dvb/esection.h index 2bb17a98..b4782f81 100644 --- a/lib/dvb/esection.h +++ b/lib/dvb/esection.h @@ -100,6 +100,10 @@ class eAUTable: public eAUGTable int first; ePtr m_demux; eMainloop *ml; + + /* needed to detect broken table version handling (seen on some m2ts files) */ + struct timespec m_prev_table_update; + int m_table_cnt; public: eAUTable() @@ -119,6 +123,7 @@ public: int begin(eMainloop *m, const eDVBTableSpec &spec, ePtr demux) { + m_table_cnt = 0; ml = m; m_demux = demux; first= 1; @@ -197,6 +202,24 @@ public: if (current && (!current->getSpec(spec))) { + /* detect broken table version handling (seen on some m2ts files) */ + if (m_table_cnt) + { + if (abs(timeout_usec(m_prev_table_update)) > 500000) + m_table_cnt = -1; + else if (m_table_cnt > 1) // two pmt update within one second + { + eDebug("Seen two consecutive table version changes within 500ms. " + "This seems broken, so auto update for pid %04x, table %02x is now disabled!!", + spec.pid, spec.tid); + m_table_cnt = 0; + return; + } + } + + ++m_table_cnt; + clock_gettime(CLOCK_MONOTONIC, &m_prev_table_update); + next = new Table(); CONNECT(next->tableReady, eAUTable::slotTableReady); spec.flags &= ~(eDVBTableSpec::tfAnyVersion|eDVBTableSpec::tfThisVersion|eDVBTableSpec::tfHaveTimeout); -- cgit v1.2.3 From 266b7db4f7e4a369206551e62df43e9a29edbeff Mon Sep 17 00:00:00 2001 From: ghost Date: Tue, 21 Dec 2010 11:46:49 +0100 Subject: fixed single pat entry workaround, add delayed "no pat entry" handling to fix some ts files with incorrect pat on start refs #124 --- lib/dvb/pmt.cpp | 29 ++++++++++++++++++++++------- lib/dvb/pmt.h | 2 ++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index cb80b00f..dc2e9a88 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -20,13 +20,14 @@ #include eDVBServicePMTHandler::eDVBServicePMTHandler() - :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF) + :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF), m_no_pat_entry_delay(eTimer::create()) { m_use_decode_demux = 0; m_pmt_pid = -1; eDVBResourceManager::getInstance(m_resourceManager); CONNECT(m_PMT.tableReady, eDVBServicePMTHandler::PMTready); CONNECT(m_PAT.tableReady, eDVBServicePMTHandler::PATready); + CONNECT(m_no_pat_entry_delay->timeout, eDVBServicePMTHandler::sendEventNoPatEntry); } eDVBServicePMTHandler::~eDVBServicePMTHandler() @@ -126,14 +127,21 @@ void eDVBServicePMTHandler::PMTready(int error) } } +void eDVBServicePMTHandler::sendEventNoPatEntry() +{ + serviceEvent(eventNoPATEntry); +} + void eDVBServicePMTHandler::PATready(int) { + eDebug("PATready"); ePtr > ptr; if (!m_PAT.getCurrent(ptr)) { int service_id_single = -1; int pmtpid_single = -1; int pmtpid = -1; + int cnt=0; std::vector::const_iterator i; for (i = ptr->getSections().begin(); pmtpid == -1 && i != ptr->getSections().end(); ++i) { @@ -141,9 +149,10 @@ void eDVBServicePMTHandler::PATready(int) ProgramAssociationConstIterator program; for (program = pat.getPrograms()->begin(); pmtpid == -1 && program != pat.getPrograms()->end(); ++program) { + ++cnt; if (eServiceID((*program)->getProgramNumber()) == m_reference.getServiceID()) pmtpid = (*program)->getProgramMapPid(); - if (pmtpid_single == -1 && pmtpid == -1) + if (++cnt == 1 && pmtpid_single == -1 && pmtpid == -1) { pmtpid_single = (*program)->getProgramMapPid(); service_id_single = (*program)->getProgramNumber(); @@ -152,15 +161,21 @@ void eDVBServicePMTHandler::PATready(int) pmtpid_single = service_id_single = -1; } } - if (pmtpid_single != -1) // only one PAT entry .. so we use this one + if (pmtpid_single != -1) // only one PAT entry .. and not valid pmtpid found { + eDebug("use single pat entry!"); m_reference.setServiceID(eServiceID(service_id_single)); pmtpid = pmtpid_single; } - if (pmtpid == -1) - serviceEvent(eventNoPATEntry); - else + if (pmtpid == -1) { + eDebug("no PAT entry found.. start delay"); + m_no_pat_entry_delay->start(1000, true); + } + else { + eDebug("use pmtpid %04x for service_id %04x", pmtpid, m_reference.getServiceID().get()); + m_no_pat_entry_delay->stop(); m_PMT.begin(eApp, eDVBPMTSpec(pmtpid, m_reference.getServiceID().get()), m_demux); + } } else serviceEvent(eventNoPAT); } @@ -717,8 +732,8 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem { RESULT res=0; m_reference = ref; - m_use_decode_demux = use_decode_demux; + m_no_pat_entry_delay->stop(); /* use given service as backup. This is used for timeshift where we want to clone the live stream using the cache, but in fact have a PVR channel */ m_service = service; diff --git a/lib/dvb/pmt.h b/lib/dvb/pmt.h index e61f8713..e9816b49 100644 --- a/lib/dvb/pmt.h +++ b/lib/dvb/pmt.h @@ -102,6 +102,7 @@ class eDVBServicePMTHandler: public Object int m_use_decode_demux; uint8_t m_decode_demux_num; + ePtr m_no_pat_entry_delay; public: eDVBServicePMTHandler(); ~eDVBServicePMTHandler(); @@ -204,6 +205,7 @@ public: int getPMT(ePtr > &ptr) { return m_PMT.getCurrent(ptr); } int getChannel(eUsePtr &channel); void resetCachedProgram() { m_have_cached_program = false; } + void sendEventNoPatEntry(); /* deprecated interface */ int tune(eServiceReferenceDVB &ref, int use_decode_demux, eCueSheet *sg=0, bool simulate=false, eDVBService *service = 0); -- cgit v1.2.3