dvb.cpp: add demux policy for dm800/500hd
[enigma2.git] / lib / dvb / demux.cpp
1 #include <stdio.h>
2 #include <fcntl.h>
3 #include <sys/ioctl.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <signal.h>
7
8 // #define FUZZING 1
9
10 #if FUZZING
11                 /* change every 1:FUZZING_PROPABILITY byte */
12 #define FUZZING_PROPABILITY 100
13 #endif
14
15 #if HAVE_DVB_API_VERSION < 3
16 #include <ost/dmx.h>
17
18 #ifndef DMX_SET_NEGFILTER_MASK
19         #define DMX_SET_NEGFILTER_MASK   _IOW('o',48,uint8_t *)
20 #endif
21
22 #ifndef DMX_GET_STC
23         struct dmx_stc
24         {
25                 unsigned int num;       /* input : which STC? O..N */
26                 unsigned int base;      /* output: divisor for stc to get 90 kHz clock */
27                 unsigned long long stc; /* output: src in 'base'*90 kHz units */
28         };
29         #define DMX_GET_STC             _IOR('o', 50, struct dmx_stc)
30 #endif
31
32 #else
33 #include <linux/dvb/dmx.h>
34
35 #define HAVE_ADD_PID
36
37 #ifdef HAVE_ADD_PID
38 #define DMX_ADD_PID              _IO('o', 51)
39 #define DMX_REMOVE_PID           _IO('o', 52)
40
41 typedef enum {
42         DMX_TAP_TS = 0,
43         DMX_TAP_PES = DMX_PES_OTHER, /* for backward binary compat. */
44 } dmx_tap_type_t;
45
46 #endif
47
48 #endif
49
50 #include "crc32.h"
51
52 #include <lib/base/eerror.h>
53 #include <lib/base/filepush.h>
54 #include <lib/dvb/idvb.h>
55 #include <lib/dvb/demux.h>
56 #include <lib/dvb/esection.h>
57 #include <lib/dvb/decoder.h>
58 #include <lib/dvb/pvrparse.h>
59
60 eDVBDemux::eDVBDemux(int adapter, int demux): adapter(adapter), demux(demux)
61 {
62         m_dvr_busy = 0;
63 }
64
65 eDVBDemux::~eDVBDemux()
66 {
67 }
68
69 int eDVBDemux::openDemux(void)
70 {
71         char filename[128];
72 #if HAVE_DVB_API_VERSION < 3
73         snprintf(filename, 128, "/dev/dvb/card%d/demux%d", adapter, demux);
74 #else
75         snprintf(filename, 128, "/dev/dvb/adapter%d/demux%d", adapter, demux);
76 #endif
77         return ::open(filename, O_RDWR);
78 }
79
80 DEFINE_REF(eDVBDemux)
81
82 RESULT eDVBDemux::setSourceFrontend(int fenum)
83 {
84 #if HAVE_DVB_API_VERSION >= 3
85         int fd = openDemux();
86         int n = DMX_SOURCE_FRONT0 + fenum;
87         int res = ::ioctl(fd, DMX_SET_SOURCE, &n);
88         if (res)
89                 eDebug("DMX_SET_SOURCE failed! - %m");
90         else
91                 source = fenum;
92         ::close(fd);
93         return res;
94 #endif
95         return 0;
96 }
97
98 RESULT eDVBDemux::setSourcePVR(int pvrnum)
99 {
100 #if HAVE_DVB_API_VERSION >= 3
101         int fd = openDemux();
102         int n = DMX_SOURCE_DVR0 + pvrnum;
103         int res = ::ioctl(fd, DMX_SET_SOURCE, &n);
104         source = -1;
105         ::close(fd);
106         return res;
107 #endif
108         return 0;
109 }
110
111 RESULT eDVBDemux::createSectionReader(eMainloop *context, ePtr<iDVBSectionReader> &reader)
112 {
113         RESULT res;
114         reader = new eDVBSectionReader(this, context, res);
115         if (res)
116                 reader = 0;
117         return res;
118 }
119
120 RESULT eDVBDemux::createPESReader(eMainloop *context, ePtr<iDVBPESReader> &reader)
121 {
122         RESULT res;
123         reader = new eDVBPESReader(this, context, res);
124         if (res)
125                 reader = 0;
126         return res;
127 }
128
129 RESULT eDVBDemux::createTSRecorder(ePtr<iDVBTSRecorder> &recorder)
130 {
131         if (m_dvr_busy)
132                 return -EBUSY;
133         recorder = new eDVBTSRecorder(this);
134         return 0;
135 }
136
137 RESULT eDVBDemux::getMPEGDecoder(ePtr<iTSMPEGDecoder> &decoder, int primary)
138 {
139         decoder = new eTSMPEGDecoder(this, primary ? 0 : 1);
140         return 0;
141 }
142
143 RESULT eDVBDemux::getSTC(pts_t &pts, int num)
144 {
145         int fd = openDemux();
146         
147         if (fd < 0)
148                 return -ENODEV;
149
150         struct dmx_stc stc;
151         stc.num = num;
152         stc.base = 1;
153         
154         if (ioctl(fd, DMX_GET_STC, &stc) < 0)
155         {
156                 eDebug("DMX_GET_STC failed!");
157                 ::close(fd);
158                 return -1;
159         }
160         
161         pts = stc.stc;
162         
163         eDebug("DMX_GET_STC - %lld", pts);
164         
165         ::close(fd);
166         return 0;
167 }
168
169 RESULT eDVBDemux::flush()
170 {
171         // FIXME: implement flushing the PVR queue here.
172         
173         m_event(evtFlush);
174         return 0;
175 }
176
177 RESULT eDVBDemux::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn)
178 {
179         conn = new eConnection(this, m_event.connect(event));
180         return 0;
181 }
182
183 void eDVBSectionReader::data(int)
184 {
185         __u8 data[4096]; // max. section size
186         int r;
187         r = ::read(fd, data, 4096);
188 #if FUZZING
189         int j;
190         for (j = 0; j < r; ++j)
191         {
192                 if (!(rand()%FUZZING_PROPABILITY))
193                         data[j] ^= rand();
194         }
195 #endif  
196         if(r < 0)
197         {
198                 eWarning("ERROR reading section - %m\n");
199                 return;
200         }
201         if (checkcrc)
202         {
203                         // this check should never happen unless the driver is crappy!
204                 unsigned int c;
205                 if ((c = crc32((unsigned)-1, data, r)))
206                 {
207                         eDebug("crc32 failed! is %x\n", c);
208                         return;
209                 }
210         }
211         if (active)
212                 read(data);
213         else
214                 eDebug("data.. but not active");
215 }
216
217 eDVBSectionReader::eDVBSectionReader(eDVBDemux *demux, eMainloop *context, RESULT &res): demux(demux)
218 {
219         char filename[128];
220         fd = demux->openDemux();
221         
222         if (fd >= 0)
223         {
224                 notifier=eSocketNotifier::create(context, fd, eSocketNotifier::Read, false);
225                 CONNECT(notifier->activated, eDVBSectionReader::data);
226                 res = 0;
227         } else
228         {
229                 perror(filename);
230                 res = errno;
231         }
232 }
233
234 DEFINE_REF(eDVBSectionReader)
235
236 eDVBSectionReader::~eDVBSectionReader()
237 {
238         if (fd >= 0)
239                 ::close(fd);
240 }
241
242 RESULT eDVBSectionReader::start(const eDVBSectionFilterMask &mask)
243 {
244         RESULT res;
245         if (fd < 0)
246                 return -ENODEV;
247
248         notifier->start();
249 #if HAVE_DVB_API_VERSION < 3
250         dmxSctFilterParams sct;
251 #else
252         dmx_sct_filter_params sct;
253 #endif
254         sct.pid     = mask.pid;
255         sct.timeout = 0;
256 #if HAVE_DVB_API_VERSION < 3
257         sct.flags   = 0;
258 #else
259         sct.flags   = DMX_IMMEDIATE_START;
260 #endif
261 #if !FUZZING
262         if (mask.flags & eDVBSectionFilterMask::rfCRC)
263         {
264                 sct.flags |= DMX_CHECK_CRC;
265                 checkcrc = 1;
266         } else
267 #endif
268                 checkcrc = 0;
269         
270         memcpy(sct.filter.filter, mask.data, DMX_FILTER_SIZE);
271         memcpy(sct.filter.mask, mask.mask, DMX_FILTER_SIZE);
272 #if HAVE_DVB_API_VERSION >= 3
273         memcpy(sct.filter.mode, mask.mode, DMX_FILTER_SIZE);
274         if (::ioctl(fd, DMX_SET_BUFFER_SIZE, 8192*8) < 0)
275                 eDebug("DMX_SET_BUFFER_SIZE failed(%m)");
276 #endif
277         
278         res = ::ioctl(fd, DMX_SET_FILTER, &sct);
279         if (!res)
280         {
281 #if HAVE_DVB_API_VERSION < 3
282                 res = ::ioctl(fd, DMX_SET_NEGFILTER_MASK, mask.mode);
283                 if (!res)
284                 {
285                         res = ::ioctl(fd, DMX_START, 0);
286                         if (!res)
287                                 active = 1;
288                 }
289 #else
290                 active = 1;
291 #endif
292         }
293         return res;
294 }
295
296 RESULT eDVBSectionReader::stop()
297 {
298         if (!active)
299                 return -1;
300
301         active=0;
302         ::ioctl(fd, DMX_STOP);
303         notifier->stop();
304
305         return 0;
306 }
307
308 RESULT eDVBSectionReader::connectRead(const Slot1<void,const __u8*> &r, ePtr<eConnection> &conn)
309 {
310         conn = new eConnection(this, read.connect(r));
311         return 0;
312 }
313
314 void eDVBPESReader::data(int)
315 {
316         while (1)
317         {
318                 __u8 buffer[16384];
319                 int r;
320                 r = ::read(m_fd, buffer, 16384);
321                 if (!r)
322                         return;
323                 if(r < 0)
324                 {
325                         if (errno == EAGAIN || errno == EINTR) /* ok */
326                                 return;
327                         eWarning("ERROR reading PES (fd=%d) - %m", m_fd);
328                         return;
329                 }
330
331                 if (m_active)
332                         m_read(buffer, r);
333                 else
334                         eWarning("PES reader not active");
335                 if (r != 16384)
336                         break;
337         }
338 }
339
340 eDVBPESReader::eDVBPESReader(eDVBDemux *demux, eMainloop *context, RESULT &res): m_demux(demux)
341 {
342         char filename[128];
343         m_fd = m_demux->openDemux();
344         
345         if (m_fd >= 0)
346         {
347                 ::ioctl(m_fd, DMX_SET_BUFFER_SIZE, 64*1024);
348                 ::fcntl(m_fd, F_SETFL, O_NONBLOCK);
349                 m_notifier = eSocketNotifier::create(context, m_fd, eSocketNotifier::Read, false);
350                 CONNECT(m_notifier->activated, eDVBPESReader::data);
351                 res = 0;
352         } else
353         {
354                 perror(filename);
355                 res = errno;
356         }
357 }
358
359 DEFINE_REF(eDVBPESReader)
360
361 eDVBPESReader::~eDVBPESReader()
362 {
363         if (m_fd >= 0)
364                 ::close(m_fd);
365 }
366
367 RESULT eDVBPESReader::start(int pid)
368 {
369         RESULT res;
370         if (m_fd < 0)
371                 return -ENODEV;
372
373         m_notifier->start();
374
375 #if HAVE_DVB_API_VERSION < 3
376         dmxPesFilterParams flt;
377         
378         flt.pesType = DMX_PES_OTHER;
379 #else
380         dmx_pes_filter_params flt;
381         
382         flt.pes_type = DMX_PES_OTHER;
383 #endif
384
385         flt.pid     = pid;
386         flt.input   = DMX_IN_FRONTEND;
387         flt.output  = DMX_OUT_TAP;
388         
389         flt.flags   = DMX_IMMEDIATE_START;
390
391         res = ::ioctl(m_fd, DMX_SET_PES_FILTER, &flt);
392         
393         if (res)
394                 eWarning("PES filter: DMX_SET_PES_FILTER - %m");
395         if (!res)
396                 m_active = 1;
397         return res;
398 }
399
400 RESULT eDVBPESReader::stop()
401 {
402         if (!m_active)
403                 return -1;
404
405         m_active=0;
406         ::ioctl(m_fd, DMX_STOP);
407         m_notifier->stop();
408
409         return 0;
410 }
411
412 RESULT eDVBPESReader::connectRead(const Slot2<void,const __u8*,int> &r, ePtr<eConnection> &conn)
413 {
414         conn = new eConnection(this, m_read.connect(r));
415         return 0;
416 }
417
418 class eDVBRecordFileThread: public eFilePushThread
419 {
420 public:
421         eDVBRecordFileThread();
422         void setTimingPID(int pid, int type);
423         
424         void startSaveMetaInformation(const std::string &filename);
425         void stopSaveMetaInformation();
426         int getLastPTS(pts_t &pts);
427 protected:
428         int filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining);
429 private:
430         eMPEGStreamParserTS m_ts_parser;
431         eMPEGStreamInformation m_stream_info;
432         off_t m_current_offset;
433         pts_t m_last_pcr; /* very approximate.. */
434         int m_pid;
435 };
436
437 eDVBRecordFileThread::eDVBRecordFileThread()
438         :eFilePushThread(IOPRIO_CLASS_RT, 7), m_ts_parser(m_stream_info)
439 {
440         m_current_offset = 0;
441 }
442
443 void eDVBRecordFileThread::setTimingPID(int pid, int type)
444 {
445         m_ts_parser.setPid(pid, type);
446 }
447
448 void eDVBRecordFileThread::startSaveMetaInformation(const std::string &filename)
449 {
450         m_stream_info.startSave(filename.c_str());
451 }
452
453 void eDVBRecordFileThread::stopSaveMetaInformation()
454 {
455         m_stream_info.stopSave();
456 }
457
458 int eDVBRecordFileThread::getLastPTS(pts_t &pts)
459 {
460         return m_ts_parser.getLastPTS(pts);
461 }
462
463 int eDVBRecordFileThread::filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining)
464 {
465         m_ts_parser.parseData(m_current_offset, data, len);
466         
467         m_current_offset += len;
468         
469         return len;
470 }
471
472 DEFINE_REF(eDVBTSRecorder);
473
474 eDVBTSRecorder::eDVBTSRecorder(eDVBDemux *demux): m_demux(demux)
475 {
476         m_running = 0;
477         m_target_fd = -1;
478         m_thread = new eDVBRecordFileThread();
479   CONNECT(m_thread->m_event, eDVBTSRecorder::filepushEvent);
480 #ifndef HAVE_ADD_PID
481         m_demux->m_dvr_busy = 1;
482 #endif
483 }
484
485 eDVBTSRecorder::~eDVBTSRecorder()
486 {
487         stop();
488         delete m_thread;
489 #ifndef HAVE_ADD_PID
490         m_demux->m_dvr_busy = 0;
491 #endif
492 }
493
494 RESULT eDVBTSRecorder::start()
495 {
496         if (m_running)
497                 return -1;
498         
499         if (m_target_fd == -1)
500                 return -2;
501
502         char filename[128];
503 #ifndef HAVE_ADD_PID
504 #if HAVE_DVB_API_VERSION < 3
505         snprintf(filename, 128, "/dev/dvb/card%d/dvr%d", m_demux->adapter, m_demux->demux);
506 #else
507         snprintf(filename, 128, "/dev/dvb/adapter%d/dvr%d", m_demux->adapter, m_demux->demux);
508 #endif
509         m_source_fd = ::open(filename, O_RDONLY);
510         
511         if (m_source_fd < 0)
512         {
513                 eDebug("FAILED to open dvr (%s) in ts recoder (%m)", filename);
514                 return -3;
515         }
516 #else
517         snprintf(filename, 128, "/dev/dvb/adapter%d/demux%d", m_demux->adapter, m_demux->demux);
518
519         m_source_fd = ::open(filename, O_RDONLY);
520         
521         if (m_source_fd < 0)
522         {
523                 eDebug("FAILED to open demux (%s) in ts recoder (%m)", filename);
524                 return -3;
525         }
526         
527         ::ioctl(m_source_fd, DMX_SET_BUFFER_SIZE, 1024*1024);
528
529         dmx_pes_filter_params flt;
530         flt.pes_type = (dmx_pes_type_t)DMX_TAP_TS;
531         flt.pid     = (__u16)-1;
532         flt.input   = DMX_IN_FRONTEND;
533         flt.output  = DMX_OUT_TAP;
534         flt.flags   = 0;
535         int res = ::ioctl(m_source_fd, DMX_SET_PES_FILTER, &flt);
536         if (res)
537         {
538                 eDebug("DMX_SET_PES_FILTER: %m");
539                 ::close(m_source_fd);
540                 return -3;
541         }
542         
543         ::ioctl(m_source_fd, DMX_START);
544         
545 #endif
546
547         if (m_target_filename != "")
548                 m_thread->startSaveMetaInformation(m_target_filename);
549         
550         m_thread->start(m_source_fd, m_target_fd);
551         m_running = 1;
552         
553         for (std::map<int,int>::iterator i(m_pids.begin()); i != m_pids.end(); ++i)
554                 startPID(i->first);
555         
556         return 0;
557 }
558
559 RESULT eDVBTSRecorder::addPID(int pid)
560 {
561         if (m_pids.find(pid) != m_pids.end())
562                 return -1;
563         
564         m_pids.insert(std::pair<int,int>(pid, -1));
565         if (m_running)
566                 startPID(pid);
567         return 0;
568 }
569
570 RESULT eDVBTSRecorder::removePID(int pid)
571 {
572         if (m_pids.find(pid) == m_pids.end())
573                 return -1;
574                 
575         if (m_running)
576                 stopPID(pid);
577         
578         m_pids.erase(pid);
579         return 0;
580 }
581
582 RESULT eDVBTSRecorder::setTimingPID(int pid, int type)
583 {
584         if (m_running)
585                 return -1;
586         m_thread->setTimingPID(pid, type);
587         return 0;
588 }
589
590 RESULT eDVBTSRecorder::setTargetFD(int fd)
591 {
592         m_target_fd = fd;
593         return 0;
594 }
595
596 RESULT eDVBTSRecorder::setTargetFilename(const char *filename)
597 {
598         m_target_filename = filename;
599         return 0;
600 }
601
602 RESULT eDVBTSRecorder::setBoundary(off_t max)
603 {
604         return -1; // not yet implemented
605 }
606
607 RESULT eDVBTSRecorder::stop()
608 {
609         for (std::map<int,int>::iterator i(m_pids.begin()); i != m_pids.end(); ++i)
610                 stopPID(i->first);
611
612         if (!m_running)
613                 return -1;
614         m_thread->stop();
615         
616         close(m_source_fd);
617         m_source_fd = -1;
618         
619         m_thread->stopSaveMetaInformation();
620         
621         return 0;
622 }
623
624 RESULT eDVBTSRecorder::getCurrentPCR(pts_t &pcr)
625 {
626         if (!m_running)
627                 return 0;
628         if (!m_thread)
629                 return 0;
630                 /* XXX: we need a lock here */
631
632                         /* we don't filter PCR data, so just use the last received PTS, which is not accurate, but better than nothing */
633         return m_thread->getLastPTS(pcr);
634 }
635
636 RESULT eDVBTSRecorder::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn)
637 {
638         conn = new eConnection(this, m_event.connect(event));
639         return 0;
640 }
641
642 RESULT eDVBTSRecorder::startPID(int pid)
643 {
644 #ifndef HAVE_ADD_PID
645         int fd = m_demux->openDemux();
646         if (fd < 0)
647         {
648                 eDebug("FAILED to open demux in ts recoder (%m)");
649                 return -1;
650         }
651
652 #if HAVE_DVB_API_VERSION < 3
653         dmxPesFilterParams flt;
654         
655         flt.pesType = DMX_PES_OTHER;
656 #else
657         dmx_pes_filter_params flt;
658         
659         flt.pes_type = DMX_PES_OTHER;
660 #endif
661
662         flt.pid     = pid;
663         flt.input   = DMX_IN_FRONTEND;
664         flt.output  = DMX_OUT_TS_TAP;
665         
666         flt.flags   = DMX_IMMEDIATE_START;
667
668         int res = ::ioctl(fd, DMX_SET_PES_FILTER, &flt);
669         if (res < 0)
670         {
671                 eDebug("set pes filter failed!");
672                 ::close(fd);
673                 return -1;
674         }
675         m_pids[pid] = fd;
676 #else
677         while(true) {
678                 if (::ioctl(m_source_fd, DMX_ADD_PID, pid) < 0) {
679                         perror("DMX_ADD_PID");
680                         if (errno == EAGAIN || errno == EINTR) {
681                                 eDebug("retry!");
682                                 continue;
683                         }
684                 } else
685                         m_pids[pid] = 1;
686                 break;
687         }
688 #endif
689         return 0;
690 }
691
692 void eDVBTSRecorder::stopPID(int pid)
693 {
694 #ifndef HAVE_ADD_PID
695         if (m_pids[pid] != -1)
696                 ::close(m_pids[pid]);
697 #else
698         if (m_pids[pid] != -1)
699         {
700                 while(true) {
701                         if (::ioctl(m_source_fd, DMX_REMOVE_PID, pid) < 0) {
702                                 perror("DMX_REMOVE_PID");
703                                 if (errno == EAGAIN || errno == EINTR) {
704                                         eDebug("retry!");
705                                         continue;
706                                 }
707                         }
708                         break;
709                 }
710         }
711 #endif
712         m_pids[pid] = -1;
713 }
714
715 void eDVBTSRecorder::filepushEvent(int event)
716 {
717         switch (event)
718         {
719         case eFilePushThread::evtWriteError:
720                 m_event(eventWriteError);
721                 break;
722         }
723 }