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