Merge remote branch 'origin/pootle-import'
[enigma2.git] / lib / python / Plugins / Extensions / DVDPlayer / src / servicedvd.cpp
1 /* yes, it's dvd  */
2 #include <lib/base/eerror.h>
3 #include <lib/base/object.h>
4 #include <lib/base/ebase.h>
5 #include <lib/base/nconfig.h>
6 #include <string>
7 #include <lib/service/service.h>
8 #include <lib/base/init_num.h>
9 #include <lib/base/init.h>
10 #include <lib/gui/esubtitle.h>
11 #include <lib/gdi/gpixmap.h>
12
13 #include <byteswap.h>
14 #include <netinet/in.h>
15 #ifndef BYTE_ORDER
16 #error no byte order defined!
17 #endif
18
19 extern "C" {
20 #include <dreamdvd/ddvdlib.h>
21 }
22 #include "servicedvd.h"
23
24 // eServiceFactoryDVD
25
26 eServiceFactoryDVD::eServiceFactoryDVD()
27 {
28         ePtr<eServiceCenter> sc;
29         
30         eServiceCenter::getPrivInstance(sc);
31         if (sc)
32         {
33                 std::list<std::string> extensions;
34                 extensions.push_back("iso");
35                 extensions.push_back("img");
36                 sc->addServiceFactory(eServiceFactoryDVD::id, this, extensions);
37         }
38 }
39
40 eServiceFactoryDVD::~eServiceFactoryDVD()
41 {
42         ePtr<eServiceCenter> sc;
43         
44         eServiceCenter::getPrivInstance(sc);
45         if (sc)
46                 sc->removeServiceFactory(eServiceFactoryDVD::id);
47 }
48
49 DEFINE_REF(eServiceFactoryDVD)
50
51         // iServiceHandler
52 RESULT eServiceFactoryDVD::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
53 {
54                 // check resources...
55         ptr = new eServiceDVD(ref);
56         return 0;
57 }
58
59 RESULT eServiceFactoryDVD::record(const eServiceReference &/*ref*/, ePtr<iRecordableService> &ptr)
60 {
61         ptr=0;
62         return -1;
63 }
64
65 RESULT eServiceFactoryDVD::list(const eServiceReference &, ePtr<iListableService> &ptr)
66 {
67         ptr=0;
68         return -1;
69 }
70
71
72 RESULT eServiceFactoryDVD::info(const eServiceReference &/*ref*/, ePtr<iStaticServiceInformation> &ptr)
73 {
74         ptr=0;
75         return -1;
76 }
77
78 RESULT eServiceFactoryDVD::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
79 {
80         ptr = 0;
81         return -1;
82 }
83
84 // eServiceDVD
85
86 DEFINE_REF(eServiceDVD);
87
88 eServiceDVD::eServiceDVD(eServiceReference ref):
89         m_ref(ref), m_ddvdconfig(ddvd_create()), m_subtitle_widget(0), m_state(stIdle),
90         m_current_trick(0), m_pump(eApp, 1), m_width(-1), m_height(-1),
91         m_aspect(-1), m_framerate(-1), m_progressive(-1)
92 {
93         int aspect = DDVD_16_9;
94         int policy = DDVD_PAN_SCAN;
95         int policy2 = DDVD_PAN_SCAN;
96
97         char tmp[255];
98         ssize_t rd;
99
100         m_sn = eSocketNotifier::create(eApp, ddvd_get_messagepipe_fd(m_ddvdconfig), eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Error|eSocketNotifier::Hungup);
101         eDebug("SERVICEDVD construct!");
102         // create handle
103         ddvd_set_dvd_path(m_ddvdconfig, ref.path.c_str());
104         ddvd_set_ac3thru(m_ddvdconfig, 0);
105
106         std::string ddvd_language;
107         if (!ePythonConfigQuery::getConfigValue("config.osd.language", ddvd_language))
108                 ddvd_set_language(m_ddvdconfig, (ddvd_language.substr(0,2)).c_str());
109
110         int fd = open("/proc/stb/video/aspect", O_RDONLY);
111         if (fd > -1)
112         {
113                 rd = read(fd, tmp, 255);
114                 if (rd > 2 && !strncmp(tmp, "4:3", 3))
115                         aspect = DDVD_4_3;
116                 else if (rd > 4 && !strncmp(tmp, "16:10", 5))
117                         aspect = DDVD_16_10;
118                 close(fd);
119         }
120
121         fd = open("/proc/stb/video/policy", O_RDONLY);
122         if (fd > -1)
123         {
124                 rd = read(fd, tmp, 255);
125                 if (rd > 6 && !strncmp(tmp, "bestfit", 7))
126                         policy = DDVD_JUSTSCALE;
127                 else if (rd > 8 && !strncmp(tmp, "letterbox", 9))
128                         policy = DDVD_LETTERBOX;
129                 close(fd);
130         }
131
132 #ifdef DDVD_SUPPORTS_16_10_SCALING
133         fd = open("/proc/stb/video/policy2", O_RDONLY);
134         if (fd > -1)
135         {
136                 rd = read(fd, tmp, 255);
137                 if (rd > 6 && !strncmp(tmp, "bestfit", 7))
138                         policy2 = DDVD_JUSTSCALE;
139                 else if (rd > 8 && !strncmp(tmp, "letterbox", 9))
140                         policy2 = DDVD_LETTERBOX;
141                 close(fd);
142         }
143         ddvd_set_video_ex(m_ddvdconfig, aspect, policy, policy2, DDVD_PAL /*unused*/);
144 #else
145         ddvd_set_video(m_ddvdconfig, aspect, policy, DDVD_PAL /*unused*/);
146 #warning please update libdreamdvd for 16:10 scaling support!
147 #endif
148
149         CONNECT(m_sn->activated, eServiceDVD::gotMessage);
150         CONNECT(m_pump.recv_msg, eServiceDVD::gotThreadMessage);
151         strcpy(m_ddvd_titlestring,"");
152         m_cue_pts = 0;
153         pause();
154 }
155
156 void eServiceDVD::gotThreadMessage(const int &msg)
157 {
158         switch(msg)
159         {
160         case 1: // thread stopped
161                 m_state = stStopped;
162                 m_event(this, evStopped);
163                 break;
164         }
165 }
166
167 void eServiceDVD::gotMessage(int /*what*/)
168 {
169         switch(ddvd_get_next_message(m_ddvdconfig,1))
170         {
171                 case DDVD_COLORTABLE_UPDATE:
172                 {
173 /*
174                         struct ddvd_color ctmp[4];
175                         ddvd_get_last_colortable(ddvdconfig, ctmp);
176                         int i=0;
177                         while (i < 4)
178                         {
179                                 rd1[252+i]=ctmp[i].red;
180                                 bl1[252+i]=ctmp[i].blue;
181                                 gn1[252+i]=ctmp[i].green;
182                                 tr1[252+i]=ctmp[i].trans;
183                                 i++;
184                         }
185                         if(ioctl(fb, FBIOPUTCMAP, &colormap) == -1)
186                         {
187                                 printf("Framebuffer: <FBIOPUTCMAP failed>\n");
188                                 return 1;
189                         }
190 */
191                         eDebug("no support for 8bpp framebuffer in dvdplayer yet!");
192                         break;
193                 }
194                 case DDVD_SCREEN_UPDATE:
195                         eDebug("DVD_SCREEN_UPDATE!");
196                         if (m_subtitle_widget) {
197                                 int x1,x2,y1,y2;
198                                 ddvd_get_last_blit_area(m_ddvdconfig, &x1, &x2, &y1, &y2);
199                                 
200                                 int x_offset = 0, y_offset = 0, width = 720, height = 576;
201
202 #ifdef DDVD_SUPPORTS_GET_BLIT_DESTINATION
203                                 ddvd_get_blit_destination(m_ddvdconfig, &x_offset, &y_offset, &width, &height);
204                                 eDebug("values got from ddvd: %d %d %d %d", x_offset, y_offset, width, height);
205                                 y_offset = -y_offset;
206                                 width -= x_offset * 2;
207                                 height -= y_offset * 2;
208 #endif
209                                 eRect dest(x_offset, y_offset, width, height);
210
211                                 if (dest.width() && dest.height())
212                                         m_subtitle_widget->setPixmap(m_pixmap, eRect(x1, y1, (x2-x1)+1, (y2-y1)+1), dest);
213                         }
214                         break;
215                 case DDVD_SHOWOSD_STATE_PLAY:
216                 {
217                         eDebug("DVD_SHOWOSD_STATE_PLAY!");
218                         m_current_trick = 0;
219                         m_event(this, evUser+1);
220                         break;
221                 }
222                 case DDVD_SHOWOSD_STATE_PAUSE:
223                 {
224                         eDebug("DVD_SHOWOSD_STATE_PAUSE!");
225                         m_event(this, evUser+2);
226                         break;
227                 }
228                 case DDVD_SHOWOSD_STATE_FFWD:
229                 {
230                         eDebug("DVD_SHOWOSD_STATE_FFWD!");
231                         m_event(this, evUser+3);
232                         break;
233                 }
234                 case DDVD_SHOWOSD_STATE_FBWD:
235                 {
236                         eDebug("DVD_SHOWOSD_STATE_FBWD!");
237                         m_event(this, evUser+4);
238                         break;
239                 }
240                 case DDVD_SHOWOSD_STRING:
241                 {
242                         eDebug("DVD_SHOWOSD_STRING!");
243                         m_event(this, evUser+5);
244                         break;
245                 }
246                 case DDVD_SHOWOSD_AUDIO:
247                 {
248                         eDebug("DVD_SHOWOSD_STRING!");
249                         m_event(this, evUser+6);
250                         break;
251                 }
252                 case DDVD_SHOWOSD_SUBTITLE:
253                 {
254                         eDebug("DVD_SHOWOSD_SUBTITLE!");
255                         m_event((iPlayableService*)this, evUpdatedInfo);
256                         m_event(this, evUser+7);
257                         break;
258                 }
259                 case DDVD_EOF_REACHED:
260                         eDebug("DVD_EOF_REACHED!");
261                         m_event(this, evEOF);
262                         break;
263                 case DDVD_SOF_REACHED:
264                         eDebug("DVD_SOF_REACHED!");
265                         m_event(this, evSOF);
266                         break;
267                 case DDVD_SHOWOSD_ANGLE:
268                 {
269                         int current, num;
270                         ddvd_get_angle_info(m_ddvdconfig, &current, &num);
271                         eDebug("DVD_ANGLE_INFO: %d / %d", current, num);
272                         m_event(this, evUser+13);
273                         break;
274                 }
275                 case DDVD_SHOWOSD_TIME:
276                 {
277                         static struct ddvd_time last_info;
278                         struct ddvd_time info;
279 //                      eDebug("DVD_SHOWOSD_TIME!");
280                         ddvd_get_last_time(m_ddvdconfig, &info);
281                         if ( info.pos_chapter != last_info.pos_chapter )
282                                 m_event(this, evUser+8); // chapterUpdated
283                         if ( info.pos_title != last_info.pos_title )
284                                 m_event(this, evUser+9); // titleUpdated
285                         memcpy(&last_info, &info, sizeof(struct ddvd_time));
286                         break;
287                 }
288                 case DDVD_SHOWOSD_TITLESTRING:
289                 {
290                         ddvd_get_title_string(m_ddvdconfig, m_ddvd_titlestring);
291                         eDebug("DDVD_SHOWOSD_TITLESTRING: %s",m_ddvd_titlestring);
292                         loadCuesheet();
293                         if (!m_cue_pts)
294                                 unpause();
295                         m_event(this, evStart);
296                         break;
297                 }
298                 case DDVD_MENU_OPENED:
299                         eDebug("DVD_MENU_OPENED!");
300                         m_state = stMenu;
301                         m_event(this, evSeekableStatusChanged);
302                         m_event(this, evUser+11);
303                         break;
304                 case DDVD_MENU_CLOSED:
305                         eDebug("DVD_MENU_CLOSED!");
306                         m_state = stRunning;
307                         m_event(this, evSeekableStatusChanged);
308                         m_event(this, evUser+12);
309                         break;
310 #ifdef DDVD_SUPPORTS_PICTURE_INFO
311                 case DDVD_SIZE_CHANGED:
312                 {
313                         int changed = m_width != -1 && m_height != -1 && m_aspect != -1;
314                         ddvd_get_last_size(m_ddvdconfig, &m_width, &m_height, &m_aspect);
315                         if (changed)
316                                 m_event((iPlayableService*)this, evVideoSizeChanged);
317                         break;
318                 }
319                 case DDVD_PROGRESSIVE_CHANGED:
320                 {
321                         int changed = m_progressive != -1;
322                         ddvd_get_last_progressive(m_ddvdconfig, &m_progressive);
323                         if (changed)
324                                 m_event((iPlayableService*)this, evVideoProgressiveChanged);
325                         break;
326                 }
327                 case DDVD_FRAMERATE_CHANGED:
328                 {
329                         int changed = m_framerate != -1;
330                         ddvd_get_last_framerate(m_ddvdconfig, &m_framerate);
331                         if (changed)
332                                 m_event((iPlayableService*)this, evVideoFramerateChanged);
333                         break;
334                 }
335 #endif
336                 default:
337                         break;
338         }
339 }
340
341 eServiceDVD::~eServiceDVD()
342 {
343         eDebug("SERVICEDVD destruct!");
344         kill();
345         saveCuesheet();
346         ddvd_close(m_ddvdconfig);
347         disableSubtitles(0);
348 }
349
350 RESULT eServiceDVD::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
351 {
352         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
353         return 0;
354 }
355
356 RESULT eServiceDVD::start()
357 {
358         ASSERT(m_state == stIdle);
359         m_state = stRunning;
360         eDebug("eServiceDVD starting");
361 //      m_event(this, evStart);
362         return 0;
363 }
364
365 RESULT eServiceDVD::stop()
366 {
367         ASSERT(m_state != stIdle);
368         if (m_state == stStopped)
369                 return -1;
370         eDebug("DVD: stop %s", m_ref.path.c_str());
371         m_state = stStopped;
372         ddvd_send_key(m_ddvdconfig, DDVD_KEY_EXIT);
373
374         return 0;
375 }
376
377 RESULT eServiceDVD::setTarget(int /*target*/)
378 {
379         return -1;
380 }
381
382 RESULT eServiceDVD::pause(ePtr<iPauseableService> &ptr)
383 {
384         ptr=this;
385         return 0;
386 }
387
388 RESULT eServiceDVD::seek(ePtr<iSeekableService> &ptr)
389 {
390         ptr=this;
391         return 0;
392 }
393
394 RESULT eServiceDVD::subtitle(ePtr<iSubtitleOutput> &ptr)
395 {
396         ptr=this;
397         return 0;
398 }
399
400 RESULT eServiceDVD::audioTracks(ePtr<iAudioTrackSelection> &ptr)
401 {
402         ptr = this;
403         return 0;
404 }
405
406 int eServiceDVD::getNumberOfTracks()
407 {
408         int i = 0;
409         ddvd_get_audio_count(m_ddvdconfig, &i);
410         return i;
411 }
412
413 int eServiceDVD::getCurrentTrack()
414 {
415         int audio_id,audio_type;
416         uint16_t audio_lang;
417         ddvd_get_last_audio(m_ddvdconfig, &audio_id, &audio_lang, &audio_type);
418         return audio_id;
419 }
420
421 RESULT eServiceDVD::selectTrack(unsigned int i)
422 {
423         ddvd_set_audio(m_ddvdconfig, i);
424         return 0;
425 }
426
427 RESULT eServiceDVD::getTrackInfo(struct iAudioTrackInfo &info, unsigned int audio_id)
428 {
429         int audio_type;
430         uint16_t audio_lang;
431         ddvd_get_audio_byid(m_ddvdconfig, audio_id, &audio_lang, &audio_type);
432         char audio_string[3]={audio_lang >> 8, audio_lang, 0};
433         info.m_pid = audio_id+1;
434         info.m_language = audio_string;
435         switch(audio_type)
436         {
437                 case DDVD_MPEG:
438                         info.m_description = "MPEG";
439                         break;
440                 case DDVD_AC3:
441                         info.m_description = "AC3";
442                         break;
443                 case DDVD_DTS:
444                         info.m_description = "DTS";
445                         break;
446                 case DDVD_LPCM:
447                         info.m_description = "LPCM";
448                         break;
449                 default:
450                         info.m_description = "und";
451         }
452         return 0;
453 }
454
455 RESULT eServiceDVD::keys(ePtr<iServiceKeys> &ptr)
456 {
457         ptr=this;
458         return 0;
459 }
460
461         // iPausableService
462 RESULT eServiceDVD::setSlowMotion(int /*ratio*/)
463 {
464         return -1;
465 }
466
467 RESULT eServiceDVD::setFastForward(int trick)
468 {
469         eDebug("setTrickmode(%d)", trick);
470         while (m_current_trick > trick && m_current_trick != -64)
471         {
472                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_FBWD);
473                 if (m_current_trick == 0)
474                         m_current_trick = -2;
475                 else if (m_current_trick > 0)
476                 {
477                         m_current_trick /= 2;
478                         if (abs(m_current_trick) == 1)
479                                 m_current_trick=0;
480                 }
481                 else
482                         m_current_trick *= 2;
483         }
484         while (m_current_trick < trick && m_current_trick != 64)
485         {
486                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_FFWD);
487                 if (m_current_trick == 0)
488                         m_current_trick = 2;
489                 else if (m_current_trick < 0)
490                 {
491                         m_current_trick /= 2;
492                         if (abs(m_current_trick) == 1)
493                                 m_current_trick=0;
494                 }
495                 else
496                         m_current_trick *= 2;
497         }
498         return 0;
499 }
500
501 RESULT eServiceDVD::pause()
502 {
503         eDebug("set pause!\n");
504         ddvd_send_key(m_ddvdconfig, DDVD_KEY_PAUSE);
505         return 0;
506 }
507
508 RESULT eServiceDVD::unpause()
509 {
510         eDebug("set unpause!\n");
511         ddvd_send_key(m_ddvdconfig, DDVD_KEY_PLAY);
512         return 0;
513 }
514
515 void eServiceDVD::thread()
516 {
517         eDebug("eServiceDVD dvd thread started");
518         hasStarted();
519         ddvd_run(m_ddvdconfig);
520 }
521
522 void eServiceDVD::thread_finished()
523 {
524         eDebug("eServiceDVD dvd thread finished");
525         m_pump.send(1); // inform main thread
526 }
527
528 RESULT eServiceDVD::info(ePtr<iServiceInformation>&i)
529 {
530         i = this;
531         return 0;
532 }
533
534 RESULT eServiceDVD::getName(std::string &name)
535 {
536         if ( m_ddvd_titlestring[0] != '\0' )
537                 name = m_ddvd_titlestring;
538         else
539                 if ( !m_ref.name.empty() )
540                         name = m_ref.name;
541                 else
542                         name = m_ref.path;
543         return 0;
544 }
545
546 int eServiceDVD::getInfo(int w)
547 {
548         switch (w)
549         {
550                 case sCurrentChapter:
551                 {
552                         struct ddvd_time info;
553                         ddvd_get_last_time(m_ddvdconfig, &info);
554                         return info.pos_chapter;
555                 }
556                 case sTotalChapters:
557                 {
558                         struct ddvd_time info;
559                         ddvd_get_last_time(m_ddvdconfig, &info);
560                         return info.end_chapter;
561                 }
562                 case sCurrentTitle:
563                 {
564                         struct ddvd_time info;
565                         ddvd_get_last_time(m_ddvdconfig, &info);
566                         return info.pos_title;
567                 }
568                 case sTotalTitles:
569                 {
570                         struct ddvd_time info;
571                         ddvd_get_last_time(m_ddvdconfig, &info);
572                         return info.end_title;
573                 }
574                 case sTXTPID:   // we abuse HAS_TELEXT icon in InfoBar to signalize subtitles status
575                 {
576                         int spu_id;
577                         uint16_t spu_lang;
578                         ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
579                         return spu_id;
580                 }
581                 case sUser+6:
582                 case sUser+7:
583                 case sUser+8:
584                         return resIsPyObject;
585 #ifdef DDVD_SUPPORTS_PICTURE_INFO
586                 case sVideoWidth:
587                         return m_width;
588                 case sVideoHeight:
589                         return m_height;
590                 case sAspect:
591                         return m_aspect;
592                 case sProgressive:
593                         return m_progressive;
594                 case sFrameRate:
595                         return m_framerate;
596 #endif
597                 default:
598                         return resNA;
599         }
600 }
601
602 std::string eServiceDVD::getInfoString(int w)
603 {
604         switch(w)
605         {
606                 case sServiceref:
607                         return m_ref.toString();
608                 default:
609                         eDebug("unhandled getInfoString(%d)", w);
610         }
611         return "";
612 }
613
614 PyObject *eServiceDVD::getInfoObject(int w)
615 {
616         switch(w)
617         {
618                 case sUser+6:
619                 {
620                         ePyObject tuple = PyTuple_New(3);
621                         int audio_id,audio_type;
622                         uint16_t audio_lang;
623                         ddvd_get_last_audio(m_ddvdconfig, &audio_id, &audio_lang, &audio_type);
624                         char audio_string[3]={audio_lang >> 8, audio_lang, 0};
625                         PyTuple_SetItem(tuple, 0, PyInt_FromLong(audio_id+1));
626                         PyTuple_SetItem(tuple, 1, PyString_FromString(audio_string));
627                         switch(audio_type)
628                         {
629                                 case DDVD_MPEG:
630                                         PyTuple_SetItem(tuple, 2, PyString_FromString("MPEG"));
631                                         break;
632                                 case DDVD_AC3:
633                                         PyTuple_SetItem(tuple, 2, PyString_FromString("AC3"));
634                                         break;
635                                 case DDVD_DTS:
636                                         PyTuple_SetItem(tuple, 2, PyString_FromString("DTS"));
637                                         break;
638                                 case DDVD_LPCM:
639                                         PyTuple_SetItem(tuple, 2, PyString_FromString("LPCM"));
640                                         break;
641                                 default:
642                                         PyTuple_SetItem(tuple, 2, PyString_FromString(""));
643                         }
644                         return tuple;
645                 }
646                 case sUser+7:
647                 {
648                         ePyObject tuple = PyTuple_New(2);
649                         int spu_id;
650                         uint16_t spu_lang;
651                         ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
652                         char spu_string[3]={spu_lang >> 8, spu_lang, 0};
653                         if (spu_id == -1)
654                         {
655                                 PyTuple_SetItem(tuple, 0, PyInt_FromLong(0));
656                                 PyTuple_SetItem(tuple, 1, PyString_FromString(""));
657                         }
658                         else
659                         {
660                                 PyTuple_SetItem(tuple, 0, PyInt_FromLong(spu_id+1));
661                                 PyTuple_SetItem(tuple, 1, PyString_FromString(spu_string));
662                         }                               
663                         return tuple;
664                 }
665                 case sUser+8:
666                 {
667                         ePyObject tuple = PyTuple_New(2);
668                         int current, num;
669                         ddvd_get_angle_info(m_ddvdconfig, &current, &num);
670                         PyTuple_SetItem(tuple, 0, PyInt_FromLong(current));
671                         PyTuple_SetItem(tuple, 1, PyInt_FromLong(num));
672
673                         return tuple;
674                 }
675                 default:
676                         eDebug("unhandled getInfoObject(%d)", w);
677         }
678         Py_RETURN_NONE;
679 }
680
681 RESULT eServiceDVD::enableSubtitles(eWidget *parent, ePyObject tuple)
682 {
683         delete m_subtitle_widget;
684         eSize size = eSize(720, 576);
685
686         m_subtitle_widget = new eSubtitleWidget(parent);
687         m_subtitle_widget->resize(parent->size());
688
689         int pid = -1;
690
691         if ( tuple != Py_None )
692         {               
693                 ePyObject entry;
694                 int tuplesize = PyTuple_Size(tuple);
695                 if (!PyTuple_Check(tuple))
696                         goto error_out;
697                 if (tuplesize < 1)
698                         goto error_out;
699                 entry = PyTuple_GET_ITEM(tuple, 1);
700                 if (!PyInt_Check(entry))
701                         goto error_out;
702                 pid = PyInt_AsLong(entry)-1;
703
704                 ddvd_set_spu(m_ddvdconfig, pid);
705                 m_event(this, evUser+7);
706         }
707         eDebug("eServiceDVD::enableSubtitles %i", pid);
708
709         if (!m_pixmap)
710         {
711                 m_pixmap = new gPixmap(size, 32, 1); /* allocate accel surface (if possible) */
712 #ifdef DDVD_SUPPORTS_GET_BLIT_DESTINATION
713                 ddvd_set_lfb_ex(m_ddvdconfig, (unsigned char *)m_pixmap->surface->data, size.width(), size.height(), 4, size.width()*4, 1);
714 #else
715                 ddvd_set_lfb(m_ddvdconfig, (unsigned char *)m_pixmap->surface->data, size.width(), size.height(), 4, size.width()*4);
716 #warning please update libdreamdvd for fast scaling
717 #endif
718                 run(); // start the thread
719         }
720
721         m_subtitle_widget->setZPosition(-1);
722         m_subtitle_widget->show();
723
724         return 0;
725
726 error_out:
727         return -1;
728 }
729
730 RESULT eServiceDVD::disableSubtitles(eWidget */*parent*/)
731 {
732         delete m_subtitle_widget;
733         m_subtitle_widget = 0;
734         return 0;
735 }
736
737 PyObject *eServiceDVD::getSubtitleList()
738 {
739         ePyObject l = PyList_New(0);
740         unsigned int spu_count = 0;
741         ddvd_get_spu_count(m_ddvdconfig, &spu_count);
742
743         for ( unsigned int spu_id = 0; spu_id < spu_count; spu_id++ )
744         {
745                 uint16_t spu_lang;
746                 ddvd_get_spu_byid(m_ddvdconfig, spu_id, &spu_lang);
747                 char spu_string[3]={spu_lang >> 8, spu_lang, 0};
748
749                 ePyObject tuple = PyTuple_New(5);
750                 PyTuple_SetItem(tuple, 0, PyInt_FromLong(2));
751                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(spu_id+1));
752                 PyTuple_SetItem(tuple, 2, PyInt_FromLong(5));
753                 PyTuple_SetItem(tuple, 3, PyInt_FromLong(0));
754                 PyTuple_SetItem(tuple, 4, PyString_FromString(spu_string));
755                 PyList_Append(l, tuple);
756                 Py_DECREF(tuple);
757         }
758         return l;
759 }
760
761 PyObject *eServiceDVD::getCachedSubtitle()
762 {
763         eDebug("eServiceDVD::getCachedSubtitle nyi");
764         Py_RETURN_NONE;
765 }
766
767 RESULT eServiceDVD::getLength(pts_t &len)
768 {
769 //      eDebug("eServiceDVD::getLength");
770         struct ddvd_time info;
771         ddvd_get_last_time(m_ddvdconfig, &info);
772         len = info.end_hours * 3600;
773         len += info.end_minutes * 60;
774         len += info.end_seconds;
775         len *= 90000;
776         return 0;
777 }
778
779 RESULT eServiceDVD::seekTo(pts_t to)
780 {
781         eDebug("eServiceDVD::seekTo(%lld)",to);
782         if ( to > 0 )
783         {
784                 eDebug("set_resume_pos: resume_info.title=%d, chapter=%d, block=%lu, audio_id=%d, audio_lock=%d, spu_id=%d, spu_lock=%d",m_resume_info.title,m_resume_info.chapter,m_resume_info.block,m_resume_info.audio_id, m_resume_info.audio_lock, m_resume_info.spu_id, m_resume_info.spu_lock);
785                 ddvd_set_resume_pos(m_ddvdconfig, m_resume_info);
786         }
787         return 0;
788 }
789
790 RESULT eServiceDVD::seekRelative(int direction, pts_t to)
791 {
792         int seconds = to / 90000;
793         seconds *= direction;
794         eDebug("seekRelative %d %d", direction, seconds);
795         ddvd_skip_seconds(m_ddvdconfig, seconds);
796         return 0;
797 }
798
799 RESULT eServiceDVD::getPlayPosition(pts_t &pos)
800 {
801         struct ddvd_time info;
802         ddvd_get_last_time(m_ddvdconfig, &info);
803         pos = info.pos_hours * 3600;
804         pos += info.pos_minutes * 60;
805         pos += info.pos_seconds;
806 //      eDebug("getPlayPosition %lld", pos);
807         pos *= 90000;
808         return 0;
809 }
810
811 RESULT eServiceDVD::seekTitle(int title)
812 {
813         eDebug("setTitle %d", title);
814         ddvd_set_title(m_ddvdconfig, title);
815         return 0;
816 }
817
818 RESULT eServiceDVD::seekChapter(int chapter)
819 {
820         eDebug("setChapter %d", chapter);
821         if ( chapter > 0 )
822                 ddvd_set_chapter(m_ddvdconfig, chapter);
823         return 0;
824 }
825
826 RESULT eServiceDVD::setTrickmode(int /*trick*/)
827 {
828         return -1;
829 }
830
831 RESULT eServiceDVD::isCurrentlySeekable()
832 {
833         return m_state == stRunning ? 3 : 0;
834 }
835
836 RESULT eServiceDVD::keyPressed(int key)
837 {
838         switch(key)
839         {
840         case iServiceKeys::keyLeft:
841                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_LEFT);
842                 break;
843         case iServiceKeys::keyRight:
844                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_RIGHT);
845                 break;
846         case iServiceKeys::keyUp:
847                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_UP);
848                 break;
849         case iServiceKeys::keyDown:
850                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_DOWN);
851                 break;
852         case iServiceKeys::keyOk:
853                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_OK);
854                 break;
855         case iServiceKeys::keyUser:
856                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIO);
857                 break;
858         case iServiceKeys::keyUser+1:
859                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_SUBTITLE);
860                 break;
861         case iServiceKeys::keyUser+2:
862                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIOMENU);
863                 break;
864         case iServiceKeys::keyUser+3:
865                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_CHAPTER);
866                 break;
867         case iServiceKeys::keyUser+4:
868                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_CHAPTER);
869                 break;
870         case iServiceKeys::keyUser+5:
871                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_TITLE);
872                 break;
873         case iServiceKeys::keyUser+6:
874                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_TITLE);
875                 break;
876         case iServiceKeys::keyUser+7:
877                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_MENU);
878                 break;
879         case iServiceKeys::keyUser+8:
880                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_ANGLE);
881                 break;
882         default:
883                 return -1;
884         }
885         return 0;
886 }
887
888 RESULT eServiceDVD::cueSheet(ePtr<iCueSheet> &ptr)
889 {
890         if (m_cue_pts)
891         {
892                 ptr = this;
893                 return 0;
894         }
895         ptr = 0;
896         return -1;
897 }
898
899 PyObject *eServiceDVD::getCutList()
900 {
901         ePyObject list = PyList_New(1);
902         ePyObject tuple = PyTuple_New(2);
903         PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(m_cue_pts));
904         PyTuple_SetItem(tuple, 1, PyInt_FromLong(3));
905         PyList_SetItem(list, 0, tuple);
906         return list;
907 }
908
909 void eServiceDVD::setCutList(ePyObject /*list*/)
910 {
911 }
912
913 void eServiceDVD::setCutListEnable(int /*enable*/)
914 {
915 }
916
917 void eServiceDVD::loadCuesheet()
918 {
919         char filename[128];
920         if ( m_ddvd_titlestring[0] != '\0' )
921                 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
922         else
923                 snprintf(filename, 128, "%s/dvd.cuts", m_ref.path.c_str());
924
925         eDebug("eServiceDVD::loadCuesheet() filename=%s",filename);
926
927         FILE *f = fopen(filename, "rb");
928
929         if (f)
930         {
931                 unsigned long long where;
932                 unsigned int what;
933
934                 if (!fread(&where, sizeof(where), 1, f))
935                         return;
936                 if (!fread(&what, sizeof(what), 1, f))
937                         return;
938 #if BYTE_ORDER == LITTLE_ENDIAN
939                 where = bswap_64(where);
940 #endif
941                 what = ntohl(what);
942
943                 if (!fread(&m_resume_info, sizeof(struct ddvd_resume), 1, f))
944                         return;
945                 if (!fread(&what, sizeof(what), 1, f))
946                         return;
947
948                 what = ntohl(what);
949                 if (what != 4 )
950                         return;
951
952                 m_cue_pts = where;
953
954                 fclose(f);
955         } else
956                 eDebug("cutfile not found!");
957
958         if (m_cue_pts)
959         {
960                 m_event((iPlayableService*)this, evCuesheetChanged);
961                 eDebug("eServiceDVD::loadCuesheet() pts=%lld",m_cue_pts);
962         }
963 }
964
965 void eServiceDVD::saveCuesheet()
966 {
967         eDebug("eServiceDVD::saveCuesheet()");
968
969         struct ddvd_resume resume_info;
970         ddvd_get_resume_pos(m_ddvdconfig, &resume_info);
971
972         if (resume_info.title)
973         {
974                 struct ddvd_time info;
975                 ddvd_get_last_time(m_ddvdconfig, &info);
976                 pts_t pos;
977                 pos = info.pos_hours * 3600;
978                 pos += info.pos_minutes * 60;
979                 pos += info.pos_seconds;
980                 pos *= 90000;
981                 m_cue_pts = pos;
982                 eDebug("ddvd_get_resume_pos resume_info.title=%d, chapter=%d, block=%lu, audio_id=%d, audio_lock=%d, spu_id=%d, spu_lock=%d  (pts=%llu)",resume_info.title,resume_info.chapter,resume_info.block,resume_info.audio_id, resume_info.audio_lock, resume_info.spu_id, resume_info.spu_lock,m_cue_pts);
983         }
984         else
985         {
986                 eDebug("we're in a menu or somewhere else funny. so save cuesheet with pts=0");
987                 m_cue_pts = 0;
988         }
989
990         char filename[128];
991         if ( m_ddvd_titlestring[0] != '\0' )
992                 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
993         else
994                 snprintf(filename, 128, "%s/dvd.cuts", m_ref.path.c_str());
995         
996         FILE *f = fopen(filename, "wb");
997
998         if (f)
999         {
1000                 unsigned long long where;
1001                 int what;
1002
1003 #if BYTE_ORDER == BIG_ENDIAN
1004                 where = m_cue_pts;
1005 #else
1006                 where = bswap_64(m_cue_pts);
1007 #endif
1008                 what = htonl(3);
1009                 fwrite(&where, sizeof(where), 1, f);
1010                 fwrite(&what, sizeof(what), 1, f);
1011                 
1012                 what = htonl(4);
1013                 fwrite(&resume_info, sizeof(struct ddvd_resume), 1, f);
1014                 fwrite(&what, sizeof(what), 1, f);
1015
1016                 fclose(f);
1017         }
1018 }
1019
1020 eAutoInitPtr<eServiceFactoryDVD> init_eServiceFactoryDVD(eAutoInitNumbers::service+1, "eServiceFactoryDVD");
1021
1022 PyMODINIT_FUNC
1023 initservicedvd(void)
1024 {
1025         Py_InitModule("servicedvd", NULL);
1026 }