11 #include <lib/gdi/gfbdc.h>
12 #include <lib/dvb/decoder.h>
13 #include <lib/gui/eskin.h>
16 #if HAVE_DVB_API_VERSION < 3
18 #include <ost/video.h>
19 #include <ost/audio.h>
20 #define VIDEO_DEV "/dev/dvb/card0/video0"
21 #define AUDIO_DEV "/dev/dvb/card0/audio0"
22 #define DEMUX_DEV "/dev/dvb/card0/demux0"
24 #include <linux/dvb/dmx.h>
25 #include <linux/dvb/video.h>
26 #include <linux/dvb/audio.h>
27 #define VIDEO_DEV "/dev/dvb/adapter0/video0"
28 #define AUDIO_DEV "/dev/dvb/adapter0/audio0"
29 #define DEMUX_DEV "/dev/dvb/adapter0/demux0"
30 #define audioStatus audio_status
31 #define videoStatus video_status
32 #define pesType pes_type
33 #define playState play_state
34 #define audioStreamSource_t audio_stream_source_t
35 #define videoStreamSource_t video_stream_source_t
36 #define streamSource stream_source
37 #define dmxPesFilterParams dmx_pes_filter_params
40 #include <lib/dvb/subtitling.h>
42 #ifndef TUXTXT_CFG_STANDALONE
43 #include <tuxtxt/tuxtxt_def.h>
44 extern "C" tstPageinfo
* tuxtxt_DecodePage(int showl25
, unsigned char* page_char
, tstPageAttr
*page_atrb
, int hintmode
, int showflof
);
45 extern "C" void tuxtxt_RenderPage(tstRenderInfo
* renderinfo
);
46 extern "C" int tuxtxt_SetRenderingDefaults(tstRenderInfo
* renderinfo
);
47 extern "C" tuxtxt_cache_struct tuxtxt_cache
;
48 extern "C" int tuxtxt_InitRendering(tstRenderInfo
* renderinfo
,int setTVFormat
);
49 extern "C" void tuxtxt_EndRendering(tstRenderInfo
* renderinfo
);
50 tstRenderInfo renderinfo
;
53 eSubtitleWidget
*eSubtitleWidget::instance
;
55 static int extractPTS(unsigned long long &pts
, unsigned char *pkt
)
60 pkt
++; // header length
62 if (flags
& 0x80) /* PTS present? */
65 pts
= ((unsigned long long)(((pkt
[0] >> 1) & 7))) << 30;
67 pts
|= (pkt
[2]>>1) << 15;
76 void eSubtitleWidget::processPESPacket(unsigned char *pkt
, int len
)
78 unsigned long long current
= 0;
79 if (Decoder::getSTC(current
))
80 eDebug("bloed, going unsyced");
81 eDebug("DEMUX STC: %08llx", current
);
83 unsigned long long pts
= 0;
85 int enqueue
= !queue
.empty();
87 if (!extractPTS(pts
, pkt
))
89 eDebug("PES STC: %08llx", pts
);
90 signed long long int diff
= pts
- current
;
91 eDebug(" diff: %lld(%lldms)", diff
, diff
/90);
94 else if (enqueue
) // this should not happen !!
96 eDebug("showing instantly, diff small enough... but queue not empy!!!!");
100 eDebug("showing instantly, diff small enough...!");
105 int wasempty
= queue
.empty();
106 struct pes_packet_s pes
;
108 pes
.pkt
= new unsigned char[len
];
109 memcpy(pes
.pkt
, pkt
, len
);
115 eDebug("setting timer to %lld ms!\n", (pes
.pts
- current
) / 90);
116 timer
.start((pes
.pts
- current
) / 90, 1);
123 subtitle_process_pes(subtitle
, pesbuffer
, peslen
);
126 void eSubtitleWidget::displaying_timeout()
128 eDebug("displaying timeout reached... hide visible subtitles");
129 subtitle_reset(subtitle
);
131 subtitle_clear_screen(subtitle
);
134 void eSubtitleWidget::processNext()
136 #ifndef TUXTXT_CFG_STANDALONE
137 if (ttx_running
) // using teletext subtitles
139 renderinfo
.pageinfo
= tuxtxt_DecodePage(0,renderinfo
.page_char
,renderinfo
.page_atrb
,0,0);
140 if (renderinfo
.pageinfo
)
142 tuxtxt_RenderPage(&renderinfo
);
149 eWarning("Subtitle queue is empty, but timer was called!");
153 unsigned long long fpts
=0;
155 while (!queue
.empty())
157 pes_packet_s pes
= queue
.front();
158 if (pes
.pts
&& !first
)
165 subtitle_process_pes(subtitle
, pes
.pkt
, pes
.len
);
170 unsigned long long current
= 0;
172 if (Decoder::getSTC(current
))
174 eWarning("getSTC failed, dropping all Subtitle packets!");
175 while (!queue
.empty())
177 pes_packet_s pkt
= queue
.front();
184 eDebug("by the way, actual delay was %lld(%lld msek)", current
- fpts
, (current
-fpts
)/90 );
186 if (!queue
.empty()) {
187 signed long long int diff
= queue
.front().pts
- current
;
188 timer
.start(diff
/ 90, 1);
189 eDebug("setting timer to %lld ms!\n", diff
/ 90);
195 void eSubtitleWidget::gotData(int what
)
199 unsigned char packet
[1024];
201 l
=::read(fd
, packet
, 1024);
205 unsigned char *p
= packet
;
209 if (pos
>= 6) // length ok?
211 int max
= peslen
- pos
;
214 memcpy(pesbuffer
+ pos
, p
, max
);
222 processPESPacket(pesbuffer
, pos
);
228 if (*p
!= "\x00\x00\x01\xbd"[pos
])
235 pesbuffer
[pos
++] = *p
++; l
--;
238 peslen
= ((pesbuffer
[4] << 8) | pesbuffer
[5]) + 6;
245 int eSubtitleWidget::eventHandler(const eWidgetEvent
&event
)
249 case eWidgetEvent::willShow
:
250 // eDebug("willShow!!!");
251 #ifndef TUXTXT_CFG_STANDALONE
255 subtitle_screen_enable(subtitle
, 1);
257 case eWidgetEvent::willHide
:
258 // eDebug("willHide!!!");
259 #ifndef TUXTXT_CFG_STANDALONE
264 subtitle_screen_enable(subtitle
, 0);
265 //restore old palette
266 eSkin::getActive()->setPalette(gFBDC::getInstance());
269 return eWidget::eventHandler(event
);;
274 #ifndef TUXTXT_CFG_STANDALONE
275 void eSubtitleWidget::startttx(int page
)
277 if (page
== 0|| ttx_running
) return;
278 if (page
< 0) page
= ttxpage
;
279 if (page
== 0) return;
280 eDebug("Starting teletext subtitling:%x",page
);
283 subtitle_screen_enable(subtitle
, 1);
284 rememberttxpage
= tuxtxt_cache
.page
;
285 rememberttxsubpage
= tuxtxt_cache
.subpage
;
286 tuxtxt_cache
.page
= ttxpage
= page
;
288 this->pid
= -ttxpage
;
289 tuxtxt_cache
.subpage
= 0;
290 tuxtxt_SetRenderingDefaults(&renderinfo
);
291 int left
=20, top
=20, right
=699, bottom
=555;
292 eConfig::getInstance()->getKey("/enigma/plugins/needoffsets/left", left
);
293 eConfig::getInstance()->getKey("/enigma/plugins/needoffsets/top", top
);
294 eConfig::getInstance()->getKey("/enigma/plugins/needoffsets/right", right
);
295 eConfig::getInstance()->getKey("/enigma/plugins/needoffsets/bottom", bottom
);
296 renderinfo
.sx
= left
;
298 renderinfo
.ex
= right
;
299 renderinfo
.ey
= bottom
;
300 renderinfo
.fb
=fbClass::getInstance()->lock();
301 if (tuxtxt_InitRendering(&renderinfo
,0))
303 renderinfo
.pageinfo
= tuxtxt_DecodePage(0,renderinfo
.page_char
,renderinfo
.page_atrb
,0,0);
304 if (renderinfo
.pageinfo
)
306 tuxtxt_cache
.pageupdate
=1; // force complete redraw of page
307 tuxtxt_RenderPage(&renderinfo
);
309 timer
.start(250, false);
313 void eSubtitleWidget::start(int pid
, const std::set
<int> &ppageids
)
318 subtitle_screen_enable(subtitle
, 1);
319 fd
= open(DEMUX_DEV
, O_RDWR
|O_NONBLOCK
);
322 eWarning("failed to open " DEMUX_DEV
": %m");
326 sn
= new eSocketNotifier(eApp
, fd
, eSocketNotifier::Read
);
327 CONNECT(sn
->activated
, eSubtitleWidget::gotData
);
329 struct dmxPesFilterParams f
;
330 this->pid
= f
.pid
= pid
;
331 f
.input
= DMX_IN_FRONTEND
;
332 f
.output
= DMX_OUT_TAP
;
333 f
.pesType
= DMX_PES_OTHER
;
334 f
.flags
= DMX_IMMEDIATE_START
;
335 if (::ioctl(fd
, DMX_SET_PES_FILTER
, &f
) == -1)
336 eWarning("DMX_SET_PES_FILTER: %m (subtitling)");
338 eDebug("started subtitling filter..");
343 static void subtitle_set_palette(struct subtitle_clut
*pal
)
345 static gRGB def_palette
[16];
346 static bool def_palette_initialized
;
348 gPainter
p(*gFBDC::getInstance());
349 if ( !pal
)// use default pallette
351 if ( !def_palette_initialized
) // fill default palette
353 for (int i
=0; i
< 16; ++i
)
356 def_palette
[i
].a
= 0xFF;
360 def_palette
[i
].r
= 0x80;
362 def_palette
[i
].g
= 0x80;
364 def_palette
[i
].b
= 0x80;
369 def_palette
[i
].r
= 0xFF;
371 def_palette
[i
].g
= 0xFF;
373 def_palette
[i
].b
= 0xFF;
375 // eDebug("%d %02x%02x%02x%02x",
376 // i, def_palette[i].r, def_palette[i].g, def_palette[i].b, def_palette[i].a);
378 def_palette_initialized
=1;
380 p
.setPalette(def_palette
, 240, 16);
384 // eDebug("updating palette!");
385 gRGB palette
[pal
->size
];
387 for (int i
=0; i
<pal
->size
; ++i
)
389 int y
= pal
->entries
[i
].Y
, cr
= pal
->entries
[i
].Cr
, cb
= pal
->entries
[i
].Cb
;
397 // let's try a bit different conversion method
398 palette
[i
].r
= MAX(MIN(((298 * y
+ 460 * cr
) / 256), 255), 0);
399 palette
[i
].g
= MAX(MIN(((298 * y
- 55 * cb
- 137 * cr
) / 256), 255), 0);
400 palette
[i
].b
= MAX(MIN(((298 * y
+ 543 * cb
) / 256), 255), 0);
402 palette
[i
].r
= ((1164 * y
+ 1596 * cr
) + 500) / 1000;
403 palette
[i
].g
= ((1164 * y
- 813 * cr
- 392 * cb
) + 500) / 1000;
404 palette
[i
].b
= ((1164 * y
+ 2017 * cb
) + 500) / 1000;
406 palette
[i
].a
= (pal
->entries
[i
].T
) & 0xFF;
414 // eDebug("%d: %d %d %d %d", i, palette[i].r, palette[i].g, palette[i].b, palette[i].a);
416 p
.setPalette(palette
, 240, pal
->size
);
418 // eDebug("palette changed");
421 eSubtitleWidget::eSubtitleWidget()
422 :timer(eApp
), timeout(eApp
)
427 #ifndef TUXTXT_CFG_STANDALONE
431 subtitle
= new subtitle_ctx
;
433 subtitle
->bbox_left
= 0;
434 subtitle
->bbox_right
= 0;
435 subtitle
->bbox_top
= 0;
436 subtitle
->bbox_bottom
= 0;
437 subtitle
->screen_enabled
= 0;
438 subtitle
->timeout_timer
= &timeout
;
440 gFBDC
*fbdc
= gFBDC::getInstance();
441 gPixmap
*pixmap
= &fbdc
->getPixmap();
443 subtitle
->screen_width
= pixmap
->x
;
444 subtitle
->screen_height
= pixmap
->y
;
445 subtitle
->screen_buffer
= (__u8
*)pixmap
->data
;
446 subtitle
->set_palette
= subtitle_set_palette
;
448 CONNECT(timer
.timeout
, eSubtitleWidget::processNext
);
449 CONNECT(timeout
.timeout
, eSubtitleWidget::displaying_timeout
);
450 CONNECT(eWidget::globalFocusChanged
, eSubtitleWidget::globalFocusHasChanged
);
453 eSubtitleWidget::~eSubtitleWidget()
459 int eSubtitleWidget::getCurPid()
464 void eSubtitleWidget::stop()
466 //eDebug("stopping subtitling, queue size:%d",queue.size());
467 while (!queue
.empty())
469 pes_packet_s pkt
= queue
.front();
478 subtitle_screen_enable(subtitle
, 0);
479 subtitle_reset(subtitle
);
485 eSkin::getActive()->setPalette(gFBDC::getInstance());
487 #ifndef TUXTXT_CFG_STANDALONE
494 #ifndef TUXTXT_CFG_STANDALONE
495 void eSubtitleWidget::stopttx()
499 eDebug("Stopping teletext subtitling:%x",ttxpage
);
500 tuxtxt_EndRendering(&renderinfo
);
501 tuxtxt_cache
.page
= rememberttxpage
;
502 tuxtxt_cache
.subpage
= rememberttxsubpage
;
505 fbClass::getInstance()->unlock();
506 eSkin::getActive()->setPalette(gFBDC::getInstance());
512 void eSubtitleWidget::globalFocusHasChanged(const eWidget
* newFocus
)
514 if ( !sn
&& !ttxpage
) // not running