- fix warning
[enigma2.git] / lib / dvb / demux.cpp
1 #include <config.h>
2 #include <stdio.h>
3 #include <fcntl.h>
4 #include <sys/ioctl.h>
5 #include <errno.h>
6 #include <unistd.h>
7 #include <signal.h>
8
9
10 #if HAVE_DVB_API_VERSION < 3
11 #include <ost/dmx.h>
12 #ifndef DMX_SET_NEGFILTER_MASK
13         #define DMX_SET_NEGFILTER_MASK   _IOW('o',48,uint8_t *)
14 #endif
15 #else
16 #include <linux/dvb/dmx.h>
17 #endif
18
19 #include "crc32.h"
20
21 #include <lib/base/eerror.h>
22 #include <lib/base/filepush.h>
23 #include <lib/dvb/idvb.h>
24 #include <lib/dvb/demux.h>
25 #include <lib/dvb/esection.h>
26 #include <lib/dvb/decoder.h>
27
28 eDVBDemux::eDVBDemux(int adapter, int demux): adapter(adapter), demux(demux)
29 {
30         m_dvr_busy = 0;
31 }
32
33 eDVBDemux::~eDVBDemux()
34 {
35 }
36
37 DEFINE_REF(eDVBDemux)
38
39 RESULT eDVBDemux::createSectionReader(eMainloop *context, ePtr<iDVBSectionReader> &reader)
40 {
41         RESULT res;
42         reader = new eDVBSectionReader(this, context, res);
43         if (res)
44                 reader = 0;
45         return res;
46 }
47
48 RESULT eDVBDemux::createTSRecorder(ePtr<iDVBTSRecorder> &recorder)
49 {
50         if (m_dvr_busy)
51                 return -EBUSY;
52         recorder = new eDVBTSRecorder(this);
53         return 0;
54 }
55
56 RESULT eDVBDemux::getMPEGDecoder(ePtr<iTSMPEGDecoder> &decoder)
57 {
58         decoder = new eTSMPEGDecoder(this, 0);
59         return 0;
60 }
61
62 void eDVBSectionReader::data(int)
63 {
64         __u8 data[4096]; // max. section size
65         int r;
66         r = ::read(fd, data, 4096);
67         if(r < 0)
68         {
69                 eWarning("ERROR reading section - %m\n");
70                 return;
71         }
72         if (checkcrc)
73         {
74                         // this check should never happen unless the driver is crappy!
75                 unsigned int c;
76                 if ((c = crc32((unsigned)-1, data, r)))
77                         eFatal("crc32 failed! is %x\n", c);
78         }
79         if (active)
80                 read(data);
81         else
82                 eDebug("data.. but not active");
83 }
84
85 eDVBSectionReader::eDVBSectionReader(eDVBDemux *demux, eMainloop *context, RESULT &res): demux(demux)
86 {
87         char filename[128];
88 #if HAVE_DVB_API_VERSION < 3
89         sprintf(filename, "/dev/dvb/card%d/demux%d", demux->adapter, demux->demux);
90 #else
91         sprintf(filename, "/dev/dvb/adapter%d/demux%d", demux->adapter, demux->demux);
92 #endif
93         fd = ::open(filename, O_RDWR);
94         
95         eDebug("eDVBSectionReader has fd %d", fd);
96         
97         if (fd >= 0)
98         {
99                 notifier=new eSocketNotifier(context, fd, eSocketNotifier::Read);
100                 CONNECT(notifier->activated, eDVBSectionReader::data);
101                 res = 0;
102         } else
103         {
104                 perror(filename);
105                 res = errno;
106         }
107 }
108
109 DEFINE_REF(eDVBSectionReader)
110
111 eDVBSectionReader::~eDVBSectionReader()
112 {
113         if (notifier)
114                 delete notifier;
115         if (fd >= 0)
116                 ::close(fd);
117 }
118
119 RESULT eDVBSectionReader::start(const eDVBSectionFilterMask &mask)
120 {
121         RESULT res;
122         if (fd < 0)
123                 return -ENODEV;
124
125 #if HAVE_DVB_API_VERSION < 3
126         dmxSctFilterParams sct;
127 #else
128         dmx_sct_filter_params sct;
129 #endif
130         sct.pid     = mask.pid;
131         sct.timeout = 0;
132 #if HAVE_DVB_API_VERSION < 3
133         sct.flags   = 0;
134 #else
135         sct.flags   = DMX_IMMEDIATE_START;
136 #endif
137         if (mask.flags & eDVBSectionFilterMask::rfCRC)
138         {
139                 sct.flags |= DMX_CHECK_CRC;
140                 checkcrc = 1;
141         } else
142                 checkcrc = 0;
143         
144         memcpy(sct.filter.filter, mask.data, DMX_FILTER_SIZE);
145         memcpy(sct.filter.mask, mask.mask, DMX_FILTER_SIZE);
146 #if HAVE_DVB_API_VERSION >= 3
147         memcpy(sct.filter.mode, mask.mode, DMX_FILTER_SIZE);
148 #endif
149         
150         res = ::ioctl(fd, DMX_SET_FILTER, &sct);
151         if (!res)
152         {
153 #if HAVE_DVB_API_VERSION < 3
154                 res = ::ioctl(fd, DMX_SET_NEGFILTER_MASK, mask.mode);
155                 if (!res)
156                 {
157                         res = ::ioctl(fd, DMX_START, 0);
158                         if (!res)
159                                 active = 1;
160                 }
161 #else
162                 active = 1;
163 #endif
164         }
165         return res;
166 }
167
168 RESULT eDVBSectionReader::stop()
169 {
170         if (!active)
171                 return -1;
172
173         active=0;
174         ::ioctl(fd, DMX_STOP);
175         
176         return 0;
177 }
178
179 RESULT eDVBSectionReader::connectRead(const Slot1<void,const __u8*> &r, ePtr<eConnection> &conn)
180 {
181         conn = new eConnection(this, read.connect(r));
182         return 0;
183 }
184
185 DEFINE_REF(eDVBTSRecorder);
186
187 eDVBTSRecorder::eDVBTSRecorder(eDVBDemux *demux): m_demux(demux)
188 {
189         m_running = 0;
190         m_format = 0;
191         m_target_fd = -1;
192         m_thread = new eFilePushThread();
193         m_demux->m_dvr_busy = 1;
194 }
195
196 eDVBTSRecorder::~eDVBTSRecorder()
197 {
198         stop();
199         delete m_thread;
200         m_demux->m_dvr_busy = 0;
201 }
202
203 RESULT eDVBTSRecorder::start()
204 {
205         if (m_running)
206                 return -1;
207         
208         if (m_target_fd == -1)
209                 return -2;
210                 
211         char filename[128];
212 #if HAVE_DVB_API_VERSION < 3
213         snprintf(filename, 128, "/dev/dvb/card%d/dvr%d", m_demux->adapter, m_demux->demux);
214 #else
215         snprintf(filename, 128, "/dev/dvb/adapter%d/dvr%d", m_demux->adapter, m_demux->demux);
216 #endif
217         m_source_fd = ::open(filename, O_RDONLY);
218         
219         if (m_source_fd < 0)
220         {
221                 eDebug("FAILED to open dvr (%s) in ts recoder (%m)", filename);
222                 return -3;
223         }
224         
225         m_thread->start(m_source_fd, m_target_fd);
226         m_running = 1;
227         
228         for (std::map<int,int>::iterator i(m_pids.begin()); i != m_pids.end(); ++i)
229                 startPID(i->first);
230         
231         return 0;
232 }
233
234 RESULT eDVBTSRecorder::addPID(int pid)
235 {
236         if (m_pids.find(pid) != m_pids.end())
237                 return -1;
238         
239         m_pids.insert(std::pair<int,int>(pid, -1));
240         if (m_running)
241                 startPID(pid);
242         return 0;
243 }
244
245 RESULT eDVBTSRecorder::removePID(int pid)
246 {
247         if (m_pids.find(pid) == m_pids.end())
248                 return -1;
249                 
250         if (m_running)
251                 stopPID(pid);
252         
253         m_pids.erase(pid);
254         return 0;
255 }
256
257 RESULT eDVBTSRecorder::setFormat(int format)
258 {
259         if (m_running)
260                 return -1;
261         m_format = format;
262         return 0;
263 }
264
265 RESULT eDVBTSRecorder::setTargetFD(int fd)
266 {
267         m_target_fd = fd;
268         return 0;
269 }
270
271 RESULT eDVBTSRecorder::setBoundary(off_t max)
272 {
273         return -1; // not yet implemented
274 }
275
276 RESULT eDVBTSRecorder::stop()
277 {
278         for (std::map<int,int>::iterator i(m_pids.begin()); i != m_pids.end(); ++i)
279                 stopPID(i->first);
280
281         if (!m_running)
282                 return -1;
283         m_thread->stop();
284         
285         close(m_source_fd);
286         
287         return 0;
288 }
289
290 RESULT eDVBTSRecorder::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn)
291 {
292         conn = new eConnection(this, m_event.connect(event));
293         return 0;
294 }
295
296 RESULT eDVBTSRecorder::startPID(int pid)
297 {
298         char filename[128];
299 #if HAVE_DVB_API_VERSION < 3
300         snprintf(filename, 128, "/dev/dvb/card%d/demux%d", m_demux->adapter, m_demux->demux);
301 #else
302         snprintf(filename, 128, "/dev/dvb/adapter%d/demux%d", m_demux->adapter, m_demux->demux);
303 #endif
304         int fd = ::open(filename, O_RDWR);
305         if (fd < 0)
306         {
307                 eDebug("FAILED to open demux (%s) in ts recoder (%m)", filename);
308                 return -1;
309         }
310
311 #if HAVE_DVB_API_VERSION < 3
312         dmxPesFilterParams flt;
313         
314         flt.pesType = DMX_PES_OTHER;
315 #else
316         dmx_pes_filter_params flt;
317         
318         flt.pes_type = DMX_PES_OTHER;
319 #endif
320
321         flt.pid     = pid;
322         flt.input   = DMX_IN_FRONTEND;
323         flt.output  = DMX_OUT_TS_TAP;
324         
325         flt.flags   = DMX_IMMEDIATE_START;
326
327         int res = ::ioctl(fd, DMX_SET_PES_FILTER, &flt);
328         if (res < 0)
329         {
330                 eDebug("set pes filter failed!");
331                 ::close(fd);
332                 return -1;
333         }
334         m_pids[pid] = fd;
335
336         return 0;
337 }
338
339 void eDVBTSRecorder::stopPID(int pid)
340 {
341         ::close(m_pids[pid]);
342         m_pids[pid] = -1;
343 }