1 #include <lib/base/init_num.h>
2 #include <lib/base/init.h>
3 #include <lib/dvb/metaparser.h>
4 #include <lib/service/servicem2ts.h>
6 DEFINE_REF(eServiceFactoryM2TS)
8 class eM2TSFile: public iTsSource
10 DECLARE_REF(eM2TSFile);
13 eM2TSFile(const char *filename, bool cached=false);
17 off_t lseek(off_t offset, int whence);
18 ssize_t read(off_t offset, void *buf, size_t count);
24 int m_fd; /* for uncached */
25 FILE *m_file; /* for cached */
26 off_t m_current_offset, m_length;
28 off_t lseek_internal(off_t offset, int whence);
31 class eStaticServiceM2TSInformation: public iStaticServiceInformation
33 DECLARE_REF(eStaticServiceM2TSInformation);
34 eServiceReference m_ref;
35 eDVBMetaParser m_parser;
37 eStaticServiceM2TSInformation(const eServiceReference &ref);
38 RESULT getName(const eServiceReference &ref, std::string &name);
39 int getLength(const eServiceReference &ref);
40 RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
41 int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; }
42 int getInfo(const eServiceReference &ref, int w);
43 std::string getInfoString(const eServiceReference &ref,int w);
44 PyObject *getInfoObject(const eServiceReference &r, int what);
47 DEFINE_REF(eStaticServiceM2TSInformation);
49 eStaticServiceM2TSInformation::eStaticServiceM2TSInformation(const eServiceReference &ref)
52 m_parser.parseFile(ref.path);
55 RESULT eStaticServiceM2TSInformation::getName(const eServiceReference &ref, std::string &name)
58 if (m_parser.m_name.size())
59 name = m_parser.m_name;
63 size_t n = name.rfind('/');
64 if (n != std::string::npos)
65 name = name.substr(n + 1);
70 int eStaticServiceM2TSInformation::getLength(const eServiceReference &ref)
77 stat(ref.path.c_str(), &s);
79 eM2TSFile *file = new eM2TSFile(ref.path.c_str());
80 ePtr<iTsSource> source = file;
85 tstools.setSource(source);
87 /* check if cached data is still valid */
88 if (m_parser.m_data_ok && (s.st_size == m_parser.m_filesize) && (m_parser.m_length))
89 return m_parser.m_length / 90000;
91 /* open again, this time with stream info */
92 tstools.setSource(source, ref.path.c_str());
94 /* otherwise, re-calc length and update meta file */
96 if (tstools.calcLen(len))
99 m_parser.m_length = len;
100 m_parser.m_filesize = s.st_size;
101 m_parser.updateMeta(ref.path);
102 return m_parser.m_length / 90000;
105 int eStaticServiceM2TSInformation::getInfo(const eServiceReference &ref, int w)
109 case iServiceInformation::sDescription:
110 return iServiceInformation::resIsString;
111 case iServiceInformation::sServiceref:
112 return iServiceInformation::resIsString;
113 case iServiceInformation::sFileSize:
114 return m_parser.m_filesize;
115 case iServiceInformation::sTimeCreate:
116 if (m_parser.m_time_create)
117 return m_parser.m_time_create;
119 return iServiceInformation::resNA;
121 return iServiceInformation::resNA;
125 std::string eStaticServiceM2TSInformation::getInfoString(const eServiceReference &ref,int w)
129 case iServiceInformation::sDescription:
130 return m_parser.m_description;
131 case iServiceInformation::sServiceref:
132 return m_parser.m_ref.toString();
133 case iServiceInformation::sTags:
134 return m_parser.m_tags;
140 PyObject *eStaticServiceM2TSInformation::getInfoObject(const eServiceReference &r, int what)
144 case iServiceInformation::sFileSize:
145 return PyLong_FromLongLong(m_parser.m_filesize);
151 RESULT eStaticServiceM2TSInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
153 if (!ref.path.empty())
155 ePtr<eServiceEvent> event = new eServiceEvent;
156 std::string filename = ref.path;
157 filename.erase(filename.length()-4, 2);
159 if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
169 DEFINE_REF(eM2TSFile);
171 eM2TSFile::eM2TSFile(const char *filename, bool cached)
172 :m_lock(false), m_sync_offset(0), m_fd(-1), m_file(NULL), m_current_offset(0), m_length(0), m_cached(cached)
175 m_fd = ::open(filename, O_RDONLY | O_LARGEFILE);
177 m_file = ::fopen64(filename, "rb");
179 m_current_offset = m_length = lseek_internal(0, SEEK_END);
182 eM2TSFile::~eM2TSFile()
200 off_t eM2TSFile::lseek(off_t offset, int whence)
202 eSingleLocker l(m_lock);
204 offset = (offset % 188) + (offset * 192) / 188;
206 if (offset != m_current_offset)
207 m_current_offset = lseek_internal(offset, whence);
209 return m_current_offset;
212 off_t eM2TSFile::lseek_internal(off_t offset, int whence)
217 ret = ::lseek(m_fd, offset, whence);
220 if (::fseeko(m_file, offset, whence) < 0)
222 ret = ::ftello(m_file);
224 return ret <= 0 ? ret : (ret % 192) + (ret*188) / 192;
227 ssize_t eM2TSFile::read(off_t offset, void *b, size_t count)
229 eSingleLocker l(m_lock);
230 unsigned char tmp[192*3];
231 unsigned char *buf = (unsigned char*)b;
234 offset = (offset % 188) + (offset * 192) / 188;
237 if ((offset+m_sync_offset) != m_current_offset)
239 // eDebug("seekTo %lld", offset+m_sync_offset);
240 m_current_offset = lseek_internal(offset+m_sync_offset, SEEK_SET);
241 if (m_current_offset < 0)
242 return m_current_offset;
248 ret = ::read(m_fd, tmp, 192);
250 ret = ::fread(tmp, 1, 192, m_file);
251 if (ret < 0 || ret < 192)
252 return rd ? rd : ret;
257 eDebug("short read at pos %lld async!!", m_current_offset);
263 ret = ::read(m_fd, tmp+192, 384);
265 ret = ::fread(tmp+192, 1, 384, m_file);
268 eDebugNoNewLine("m2ts out of sync at pos %lld, real %lld:", offset + m_sync_offset, m_current_offset);
270 eDebugNoNewLine(" %02x", tmp[x]);
274 eDebug("m2ts out of sync at pos %lld, real %lld", offset + m_sync_offset, m_current_offset);
278 if (tmp[x] == 0x47 && tmp[x+192] == 0x47)
280 int add_offs = (x - 4);
281 eDebug("sync found at pos %d, sync_offset is now %d, old was %d", x, add_offs + m_sync_offset, m_sync_offset);
282 m_sync_offset += add_offs;
289 memcpy(buf+rd, tmp+4, 188);
292 m_current_offset += 188;
295 m_sync_offset %= 188;
300 int eM2TSFile::valid()
308 off_t eM2TSFile::length()
313 off_t eM2TSFile::offset()
315 return m_current_offset;
318 eServiceFactoryM2TS::eServiceFactoryM2TS()
320 ePtr<eServiceCenter> sc;
321 eServiceCenter::getPrivInstance(sc);
324 std::list<std::string> extensions;
325 extensions.push_back("m2ts");
326 extensions.push_back("mts");
327 sc->addServiceFactory(eServiceFactoryM2TS::id, this, extensions);
331 eServiceFactoryM2TS::~eServiceFactoryM2TS()
333 ePtr<eServiceCenter> sc;
335 eServiceCenter::getPrivInstance(sc);
337 sc->removeServiceFactory(eServiceFactoryM2TS::id);
340 RESULT eServiceFactoryM2TS::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
342 ptr = new eServiceM2TS(ref);
346 RESULT eServiceFactoryM2TS::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
352 RESULT eServiceFactoryM2TS::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
358 RESULT eServiceFactoryM2TS::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
360 ptr=new eStaticServiceM2TSInformation(ref);
364 RESULT eServiceFactoryM2TS::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
370 eServiceM2TS::eServiceM2TS(const eServiceReference &ref)
371 :eDVBServicePlay(ref, NULL)
375 ePtr<iTsSource> eServiceM2TS::createTsSource(eServiceReferenceDVB &ref)
377 ePtr<iTsSource> source = new eM2TSFile(ref.path.c_str());
381 RESULT eServiceM2TS::isCurrentlySeekable()
383 return 1; // for fast winding we need index files... so only skip forward/backward yet
386 eAutoInitPtr<eServiceFactoryM2TS> init_eServiceFactoryM2TS(eAutoInitNumbers::service+1, "eServiceFactoryM2TS");