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