- add flushing support in demux / decoder
[enigma2.git] / lib / dvb / decoder.cpp
1 #include <config.h>
2 #include <lib/base/eerror.h>
3 #include <lib/dvb/decoder.h>
4 #if HAVE_DVB_API_VERSION < 3 
5 #define audioStatus audio_status
6 #define videoStatus video_status
7 #define pesType pes_type
8 #define playState play_state
9 #define audioStreamSource_t audio_stream_source_t
10 #define videoStreamSource_t video_stream_source_t
11 #define streamSource stream_source
12 #define dmxPesFilterParams dmx_pes_filter_params
13 #define DMX_PES_VIDEO DMX_PES_VIDEO0
14 #define DMX_PES_AUDIO DMX_PES_AUDIO0
15 #include <ost/dmx.h>
16 #include <ost/video.h>
17 #include <ost/audio.h>
18 #else
19 #include <linux/dvb/audio.h>
20 #include <linux/dvb/video.h>
21 #include <linux/dvb/dmx.h>
22 #endif
23
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <sys/ioctl.h>
27 #include <errno.h>
28
29 DEFINE_REF(eDVBAudio);
30
31 eDVBAudio::eDVBAudio(eDVBDemux *demux, int dev): m_demux(demux)
32 {
33         char filename[128];
34 #if HAVE_DVB_API_VERSION < 3
35         sprintf(filename, "/dev/dvb/card%d/audio%d", demux->adapter, dev);      
36 #else
37         sprintf(filename, "/dev/dvb/adapter%d/audio%d", demux->adapter, dev);
38 #endif
39         m_fd = ::open(filename, O_RDWR);
40         if (m_fd < 0)
41                 eWarning("%s: %m", filename);
42 #if HAVE_DVB_API_VERSION < 3
43         sprintf(filename, "/dev/dvb/card%d/demux%d", demux->adapter, demux->demux);
44 #else
45         sprintf(filename, "/dev/dvb/adapter%d/demux%d", demux->adapter, demux->demux);
46 #endif  
47         m_fd_demux = ::open(filename, O_RDWR);
48         if (m_fd_demux < 0)
49                 eWarning("%s: %m", filename);
50 }
51         
52 int eDVBAudio::startPid(int pid)
53 {       
54         eDebug("setting audio pid to %x", pid);
55         if ((m_fd < 0) || (m_fd_demux < 0))
56                 return -1;
57         dmx_pes_filter_params pes;
58         pes.pid      = pid;
59         pes.input    = DMX_IN_FRONTEND;
60         pes.output   = DMX_OUT_DECODER;
61         pes.pes_type = DMX_PES_AUDIO;  // DMX_PES_AUDIO0
62         pes.flags    = 0;
63         if (::ioctl(m_fd_demux, DMX_SET_PES_FILTER, &pes) < 0)
64         {
65                 eWarning("audio: DMX_SET_PES_FILTER: %m");
66                 return -errno;
67         }
68         if (::ioctl(m_fd_demux, DMX_START) < 0)
69         {
70                 eWarning("audio: DMX_START: %m");
71                 return -errno;
72         }
73         if (::ioctl(m_fd, AUDIO_PLAY) < 0)
74                 eWarning("audio: AUDIO_PLAY: %m");
75         return 0;
76 }
77         
78 void eDVBAudio::stop()
79 {
80         if (::ioctl(m_fd, AUDIO_STOP) < 0)
81                 eWarning("audio: AUDIO_STOP: %m");
82 #if HAVE_DVB_API_VERSION > 2
83         if (::ioctl(m_fd_demux, DMX_STOP) < 0)
84                 eWarning("audio: DMX_STOP: %m");
85 #endif
86 }
87         
88 #if HAVE_DVB_API_VERSION < 3
89 void eDVBAudio::stopPid()
90 {
91         if (::ioctl(m_fd_demux, DMX_STOP) < 0)
92                 eWarning("audio: DMX_STOP: %m");
93 }
94 #endif
95
96 void eDVBAudio::flush()
97 {
98         if (::ioctl(m_fd, AUDIO_CLEAR_BUFFER) < 0)
99                 eDebug("audio: AUDIO_CLEAR_BUFFER: %m");
100 }
101         
102 eDVBAudio::~eDVBAudio()
103 {
104         if (m_fd >= 0)
105                 ::close(m_fd);
106         if (m_fd_demux >= 0)
107                 ::close(m_fd_demux);
108 }
109
110 DEFINE_REF(eDVBVideo);
111
112 eDVBVideo::eDVBVideo(eDVBDemux *demux, int dev): m_demux(demux)
113 {
114         char filename[128];
115 #if HAVE_DVB_API_VERSION < 3
116         sprintf(filename, "/dev/dvb/card%d/video%d", demux->adapter, dev);
117 #else
118         sprintf(filename, "/dev/dvb/adapter%d/video%d", demux->adapter, dev);
119 #endif
120         m_fd = ::open(filename, O_RDWR);
121         if (m_fd < 0)
122                 eWarning("%s: %m", filename);
123 #if HAVE_DVB_API_VERSION < 3
124         sprintf(filename, "/dev/dvb/card%d/demux%d", demux->adapter, demux->demux);
125 #else
126         sprintf(filename, "/dev/dvb/adapter%d/demux%d", demux->adapter, demux->demux);
127 #endif
128         m_fd_demux = ::open(filename, O_RDWR);
129         if (m_fd_demux < 0)
130                 eWarning("%s: %m", filename);
131 }
132         
133 int eDVBVideo::startPid(int pid)
134 {       
135         eDebug("setting video pid to %x", pid);
136         if ((m_fd < 0) || (m_fd_demux < 0))
137                 return -1;
138         dmx_pes_filter_params pes;
139         
140         pes.pid      = pid;
141         pes.input    = DMX_IN_FRONTEND;
142         pes.output   = DMX_OUT_DECODER;
143         pes.pes_type = DMX_PES_VIDEO;
144         pes.flags    = 0;
145         if (::ioctl(m_fd_demux, DMX_SET_PES_FILTER, &pes) < 0)
146         {
147                 eWarning("video: DMX_SET_PES_FILTER: %m");
148                 return -errno;
149         }
150         if (::ioctl(m_fd_demux, DMX_START) < 0)
151         {
152                 eWarning("video: DMX_START: %m");
153                 return -errno;
154         }
155         if (::ioctl(m_fd, VIDEO_PLAY) < 0)
156                 eWarning("video: VIDEO_PLAY: %m");
157         else
158                 eDebug("video ok");
159         return 0;
160 }
161         
162 void eDVBVideo::stop()
163 {
164         if (::ioctl(m_fd, VIDEO_STOP) < 0)
165                 eWarning("video: VIDEO_STOP: %m");
166 #if HAVE_DVB_API_VERSION > 2
167         if (::ioctl(m_fd_demux, DMX_STOP) < 0)
168                 eWarning("video: DMX_STOP: %m");
169 #endif
170 }
171
172 #if HAVE_DVB_API_VERSION < 3
173 void eDVBVideo::stopPid()
174 {
175         if (::ioctl(m_fd_demux, DMX_STOP) < 0)
176                 eWarning("video: DMX_STOP: %m");
177 }
178 #endif
179
180 void eDVBVideo::flush()
181 {
182         if (::ioctl(m_fd, VIDEO_CLEAR_BUFFER) < 0)
183                 eDebug("video: VIDEO_CLEAR_BUFFER: %m");
184 }
185         
186 eDVBVideo::~eDVBVideo()
187 {
188         if (m_fd >= 0)
189                 ::close(m_fd);
190         if (m_fd_demux >= 0)
191                 ::close(m_fd_demux);
192 }
193
194 DEFINE_REF(eDVBPCR);
195
196 eDVBPCR::eDVBPCR(eDVBDemux *demux): m_demux(demux)
197 {
198         char filename[128];
199 #if HAVE_DVB_API_VERSION < 3
200         sprintf(filename, "/dev/dvb/card%d/demux%d", demux->adapter, demux->demux);
201 #else
202         sprintf(filename, "/dev/dvb/adapter%d/demux%d", demux->adapter, demux->demux);
203 #endif
204         m_fd_demux = ::open(filename, O_RDWR);
205         if (m_fd_demux < 0)
206                 eWarning("%s: %m", filename);
207 }
208
209 int eDVBPCR::startPid(int pid)
210 {
211         eDebug("setting pcr pid to %x", pid);
212         if (m_fd_demux < 0)
213                 return -1;
214         dmx_pes_filter_params pes;
215
216         pes.pid      = pid;
217         pes.input    = DMX_IN_FRONTEND;
218         pes.output   = DMX_OUT_DECODER;
219         pes.pes_type = DMX_PES_PCR;
220         pes.flags    = 0;
221         if (::ioctl(m_fd_demux, DMX_SET_PES_FILTER, &pes) < 0)
222         {
223                 eWarning("video: DMX_SET_PES_FILTER: %m");
224                 return -errno;
225         }
226         if (::ioctl(m_fd_demux, DMX_START) < 0)
227         {
228                 eWarning("video: DMX_START: %m");
229                 return -errno;
230         }
231         return 0;
232 }
233
234 void eDVBPCR::stop()
235 {
236         if (::ioctl(m_fd_demux, DMX_STOP) < 0)
237                 eWarning("video: DMX_STOP: %m");
238 }
239
240 eDVBPCR::~eDVBPCR()
241 {
242         if (m_fd_demux >= 0)
243                 ::close(m_fd_demux);
244 }
245
246 DEFINE_REF(eTSMPEGDecoder);
247
248 int eTSMPEGDecoder::setState()
249 {
250         int res = 0;
251         eDebug("changed %x", m_changed);
252 #if HAVE_DVB_API_VERSION < 3
253         if (m_changed & changeAudio && m_audio)
254                 m_audio->stopPid();
255         if (m_changed & changeVideo && m_video)
256                 m_video->stopPid();
257         if (m_changed & changePCR && m_pcr)
258         {
259                 m_pcr->stop();
260                 m_pcr=0;
261         }
262         if (m_changed & changeAudio && m_audio)
263         {
264                 m_audio->stop();
265                 m_audio=0;
266         }
267         if (m_changed & changeVideo && m_video)
268         {
269                 m_video->stop();
270                 m_video=0;
271         }
272         if (m_changed & changePCR)
273         {
274                 m_pcr = new eDVBPCR(m_demux);
275                 if (m_pcr->startPid(m_pcrpid))
276                 {
277                         eWarning("video: startpid failed!");
278                         res = -1;
279                 }
280                 m_changed &= ~changePCR;
281         }
282         if (m_changed & changeVideo)
283         {
284                 m_video = new eDVBVideo(m_demux, 0);
285                 if (m_video->startPid(m_vpid))
286                 {
287                         eWarning("video: startpid failed!");
288                         res = -1;
289                 }
290                 m_changed &= ~changeVideo;
291         }
292         if (m_changed & changeAudio)
293         {
294                 m_audio = new eDVBAudio(m_demux, 0);
295                 if (m_audio->startPid(m_apid))
296                 {
297                         eWarning("audio: startpid failed!");
298                         res = -1;
299                 }
300                 m_changed &= ~changeAudio;
301         }
302 #else
303         if (m_changed & changePCR)
304         {
305                 if (m_pcr)
306                         m_pcr->stop();
307                 m_pcr = 0;
308                 if ((m_pcrpid >= 0) && (m_pcrpid < 0x1FFF))
309                 {
310                         m_pcr = new eDVBPCR(m_demux);
311                         if (m_pcr->startPid(m_pcrpid))
312                         {
313                                 eWarning("video: startpid failed!");
314                                 res = -1;
315                         }
316                 }
317                 m_changed &= ~changePCR;
318         }
319         if (m_changed & changeVideo)
320         {
321                 if (m_video)
322                         m_video->stop();
323                 m_video = 0;
324                 if ((m_vpid >= 0) && (m_vpid < 0x1FFF))
325                 {
326                         m_video = new eDVBVideo(m_demux, 0);
327                         if (m_video->startPid(m_vpid))
328                         {
329                                 eWarning("video: startpid failed!");
330                                 res = -1;
331                         }
332                 }
333                 m_changed &= ~changeVideo;
334         }
335         if (m_changed & changeAudio)
336         {
337                 if (m_audio)
338                         m_audio->stop();
339                 m_audio = 0;
340                 if ((m_apid >= 0) && (m_apid < 0x1FFF))
341                 {
342                         m_audio = new eDVBAudio(m_demux, 0);
343                         if (m_audio->startPid(m_apid))
344                         {
345                                 eWarning("audio: startpid failed!");
346                                 res = -1;
347                         }
348                 }
349                 m_changed &= ~changeAudio;
350         }
351 #endif
352         return res;
353 }
354
355 eTSMPEGDecoder::eTSMPEGDecoder(eDVBDemux *demux, int decoder): m_demux(demux), m_changed(0)
356 {
357         demux->connectEvent(slot(*this, &eTSMPEGDecoder::demux_event), m_demux_event);
358 }
359
360 eTSMPEGDecoder::~eTSMPEGDecoder()
361 {
362         m_vpid = m_apid = m_pcrpid = pidNone;
363         m_changed = -1;
364         setState();
365 }
366
367 RESULT eTSMPEGDecoder::setVideoPID(int vpid)
368 {
369         if (m_vpid != vpid)
370         {
371                 m_changed |= changeVideo;
372                 m_vpid = vpid;
373         }
374         return 0;
375 }
376
377 RESULT eTSMPEGDecoder::setAudioPID(int apid, int type)
378 {
379         if ((m_apid != apid) || (m_atype != type))
380         {
381                 m_changed |= changeAudio;
382                 m_atype = type;
383                 m_apid = apid;
384         }
385         return 0;
386 }
387
388 RESULT eTSMPEGDecoder::setSyncPCR(int pcrpid)
389 {
390         if (m_pcrpid != pcrpid)
391         {
392                 m_changed |= changePCR;
393                 m_pcrpid = pcrpid;
394         }
395         return 0;
396 }
397
398 RESULT eTSMPEGDecoder::setSyncMaster(int who)
399 {
400         return -1;
401 }
402
403 RESULT eTSMPEGDecoder::start()
404 {
405         return setState();
406 }
407
408 RESULT eTSMPEGDecoder::freeze(int cont)
409 {
410         return -1;
411 }
412
413 RESULT eTSMPEGDecoder::unfreeze()
414 {
415         return -1;
416 }
417
418 RESULT eTSMPEGDecoder::setSinglePictureMode(int when)
419 {
420         return -1;
421 }
422
423 RESULT eTSMPEGDecoder::setPictureSkipMode(int what)
424 {
425         return -1;
426 }
427
428 RESULT eTSMPEGDecoder::setSlowMotion(int repeat)
429 {
430         return -1;
431 }
432
433 RESULT eTSMPEGDecoder::setZoom(int what)
434 {
435         return -1;
436 }
437
438 RESULT eTSMPEGDecoder::flush()
439 {
440         if (m_audio)
441                 m_audio->flush();
442         if (m_video)
443                 m_video->flush();
444         return 0;
445 }
446
447 void eTSMPEGDecoder::demux_event(int event)
448 {
449         switch (event)
450         {
451         case eDVBDemux::evtFlush:
452                 flush();
453                 break;
454         default:
455                 break;
456         }
457 }