add m2ts service
[enigma2.git] / lib / service / servicem2ts.cpp
1 #include <lib/base/init_num.h>
2 #include <lib/base/init.h>
3 #include <lib/service/servicem2ts.h>
4
5 DEFINE_REF(eServiceFactoryM2TS)
6
7 class eM2TSFile: public iDataSource
8 {
9         DECLARE_REF(eM2TSFile);
10         eSingleLock m_lock;
11 public:
12         eM2TSFile(const char *filename, bool cached=false);
13         ~eM2TSFile();
14
15         // iDataSource
16         off_t lseek(off_t offset, int whence);
17         ssize_t read(off_t offset, void *buf, size_t count);
18         off_t length();
19         int valid();
20 private:
21         int m_fd;     /* for uncached */
22         FILE *m_file; /* for cached */
23         off_t m_current_offset, m_length;
24         bool m_cached;
25         off_t lseek_internal(off_t offset, int whence);
26 };
27
28 DEFINE_REF(eM2TSFile);
29
30 eM2TSFile::eM2TSFile(const char *filename, bool cached)
31         :m_lock(false), m_fd(-1), m_file(NULL), m_current_offset(0), m_length(0), m_cached(cached)
32 {
33         eDebug("eM2TSFile %p %s", this, filename);
34         if (!m_cached)
35                 m_fd = ::open(filename, O_RDONLY | O_LARGEFILE);
36         else
37                 m_file = ::fopen64(filename, "rb");
38         if (valid())
39                 m_current_offset = m_length = lseek_internal(0, SEEK_END);
40 }
41
42 eM2TSFile::~eM2TSFile()
43 {
44         eDebug("~eM2TSFile %p", this);
45         if (m_cached)
46         {
47                 if (m_file)
48                 {
49                         ::fclose(m_file);
50                         m_file = 0;
51                 }
52         }
53         else
54         {
55                 if (m_fd >= 0)
56                         ::close(m_fd);
57                 m_fd = -1;
58         }
59 }
60
61 off_t eM2TSFile::lseek(off_t offset, int whence)
62 {
63         eSingleLocker l(m_lock);
64
65         offset = offset * 192 / 188;
66         ASSERT(!(offset % 192));
67
68         if (offset != m_current_offset)
69                 m_current_offset = lseek_internal(offset, whence);
70
71         return m_current_offset;
72 }
73
74 off_t eM2TSFile::lseek_internal(off_t offset, int whence)
75 {
76         off_t ret;
77
78         if (!m_cached)
79                 ret = ::lseek(m_fd, offset, whence);
80         else
81         {
82                 if (::fseeko(m_file, offset, whence) < 0)
83                         perror("fseeko");
84                 ret = ::ftello(m_file);
85         }
86         return ret <= 0 ? ret : ret*188/192;
87 }
88
89 ssize_t eM2TSFile::read(off_t offset, void *b, size_t count)
90 {
91         eSingleLocker l(m_lock);
92         unsigned char tmp[192];
93         unsigned char *buf = (unsigned char*)b;
94         size_t rd=0;
95
96         offset = offset * 192 / 188;
97         ASSERT(!(offset % 192));
98
99         ASSERT(!(count % 188));
100
101         if (offset != m_current_offset)
102         {
103                 m_current_offset = lseek_internal(offset, SEEK_SET);
104                 if (m_current_offset < 0)
105                         return m_current_offset;
106         }
107
108         while (rd < count) {
109                 size_t ret;
110                 if (!m_cached)
111                         ret = ::read(m_fd, tmp, 192);
112                 else
113                         ret = ::fread(tmp, 1, 192, m_file);
114                 if (ret > 0)
115                         m_current_offset += ret;
116                 if (ret < 0 || ret < 192)
117                         return rd ? rd : ret;
118                 memcpy(buf+rd, tmp+4, 188);
119                 rd += 188;
120         }
121
122         return rd;
123 }
124
125 int eM2TSFile::valid()
126 {
127         if (!m_cached)
128                 return m_fd != -1;
129         else
130                 return !!m_file;
131 }
132
133 off_t eM2TSFile::length()
134 {
135         return m_length;
136 }
137
138 eServiceFactoryM2TS::eServiceFactoryM2TS()
139 {
140         ePtr<eServiceCenter> sc;
141         eDebug("!!!!!!!!!!!!!!!!!!!eServiceFactoryM2TS");
142         eServiceCenter::getPrivInstance(sc);
143         if (sc)
144         {
145                 std::list<std::string> extensions;
146                 extensions.push_back("m2ts");
147                 extensions.push_back("mts");
148                 sc->addServiceFactory(eServiceFactoryM2TS::id, this, extensions);
149         }
150 }
151
152 eServiceFactoryM2TS::~eServiceFactoryM2TS()
153 {
154         ePtr<eServiceCenter> sc;
155         
156         eServiceCenter::getPrivInstance(sc);
157         if (sc)
158                 sc->removeServiceFactory(eServiceFactoryM2TS::id);
159 }
160
161 RESULT eServiceFactoryM2TS::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
162 {
163         ptr = new eServiceM2TS(ref);
164         return 0;
165 }
166
167 RESULT eServiceFactoryM2TS::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
168 {
169         ptr=0;
170         return -1;
171 }
172
173 RESULT eServiceFactoryM2TS::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
174 {
175         ptr=0;
176         return -1;
177 }
178
179 RESULT eServiceFactoryM2TS::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
180 {
181         return 0;
182 }
183
184 RESULT eServiceFactoryM2TS::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
185 {
186         ptr = 0;
187         return -1;
188 }
189
190 eServiceM2TS::eServiceM2TS(const eServiceReference &ref)
191         :eDVBServicePlay(ref, NULL)
192 {
193         eDebug("eServiceM2TS %p", this);
194 }
195
196 eServiceM2TS::~eServiceM2TS()
197 {
198         eDebug("~eServiceM2TS %p", this);
199 }
200
201 ePtr<iDataSource> eServiceM2TS::createDataSource(const eServiceReferenceDVB &ref)
202 {
203         ePtr<iDataSource> source = new eM2TSFile(ref.path.c_str());
204         return source;
205 }
206
207 eAutoInitPtr<eServiceFactoryM2TS> init_eServiceFactoryM2TS(eAutoInitNumbers::service+1, "eServiceFactoryM2TS");