Merge commit 'origin/bug_448_fix_wlanscan'
[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                 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                 name = m_ref.path;
484         return 0;
485 }
486
487 int eServiceDVD::getInfo(int w)
488 {
489         switch (w)
490         {
491                 case sCurrentChapter:
492                 {
493                         struct ddvd_time info;
494                         ddvd_get_last_time(m_ddvdconfig, &info);
495                         return info.pos_chapter;
496                 }
497                 case sTotalChapters:
498                 {
499                         struct ddvd_time info;
500                         ddvd_get_last_time(m_ddvdconfig, &info);
501                         return info.end_chapter;
502                 }
503                 case sCurrentTitle:
504                 {
505                         struct ddvd_time info;
506                         ddvd_get_last_time(m_ddvdconfig, &info);
507                         return info.pos_title;
508                 }
509                 case sTotalTitles:
510                 {
511                         struct ddvd_time info;
512                         ddvd_get_last_time(m_ddvdconfig, &info);
513                         return info.end_title;
514                 }
515                 case sTXTPID:   // we abuse HAS_TELEXT icon in InfoBar to signalize subtitles status
516                 {
517                         int spu_id;
518                         uint16_t spu_lang;
519                         ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
520                         return spu_id;
521                 }
522                 case sUser+6:
523                 case sUser+7:
524                 case sUser+8:
525                         return resIsPyObject;
526 #ifdef DDVD_SUPPORTS_PICTURE_INFO
527                 case sVideoWidth:
528                         return m_width;
529                 case sVideoHeight:
530                         return m_height;
531                 case sAspect:
532                         return m_aspect;
533                 case sProgressive:
534                         return m_progressive;
535                 case sFrameRate:
536                         return m_framerate;
537 #endif
538                 default:
539                         return resNA;
540         }
541 }
542
543 std::string eServiceDVD::getInfoString(int w)
544 {
545         switch(w)
546         {
547                 case sServiceref:
548                         return m_ref.toString();
549                 default:
550                         eDebug("unhandled getInfoString(%d)", w);
551         }
552         return "";
553 }
554
555 PyObject *eServiceDVD::getInfoObject(int w)
556 {
557         switch(w)
558         {
559                 case sUser+6:
560                 {
561                         ePyObject tuple = PyTuple_New(3);
562                         int audio_id,audio_type;
563                         uint16_t audio_lang;
564                         ddvd_get_last_audio(m_ddvdconfig, &audio_id, &audio_lang, &audio_type);
565                         char audio_string[3]={audio_lang >> 8, audio_lang, 0};
566                         PyTuple_SetItem(tuple, 0, PyInt_FromLong(audio_id+1));
567                         PyTuple_SetItem(tuple, 1, PyString_FromString(audio_string));
568                         switch(audio_type)
569                         {
570                                 case DDVD_MPEG:
571                                         PyTuple_SetItem(tuple, 2, PyString_FromString("MPEG"));
572                                         break;
573                                 case DDVD_AC3:
574                                         PyTuple_SetItem(tuple, 2, PyString_FromString("AC3"));
575                                         break;
576                                 case DDVD_DTS:
577                                         PyTuple_SetItem(tuple, 2, PyString_FromString("DTS"));
578                                         break;
579                                 case DDVD_LPCM:
580                                         PyTuple_SetItem(tuple, 2, PyString_FromString("LPCM"));
581                                         break;
582                                 default:
583                                         PyTuple_SetItem(tuple, 2, PyString_FromString(""));
584                         }
585                         return tuple;
586                 }
587                 case sUser+7:
588                 {
589                         ePyObject tuple = PyTuple_New(2);
590                         int spu_id;
591                         uint16_t spu_lang;
592                         ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
593                         char spu_string[3]={spu_lang >> 8, spu_lang, 0};
594                         if (spu_id == -1)
595                         {
596                                 PyTuple_SetItem(tuple, 0, PyInt_FromLong(0));
597                                 PyTuple_SetItem(tuple, 1, PyString_FromString(""));
598                         }
599                         else
600                         {
601                                 PyTuple_SetItem(tuple, 0, PyInt_FromLong(spu_id+1));
602                                 PyTuple_SetItem(tuple, 1, PyString_FromString(spu_string));
603                         }                               
604                         return tuple;
605                 }
606                 case sUser+8:
607                 {
608                         ePyObject tuple = PyTuple_New(2);
609                         int current, num;
610                         ddvd_get_angle_info(m_ddvdconfig, &current, &num);
611                         PyTuple_SetItem(tuple, 0, PyInt_FromLong(current));
612                         PyTuple_SetItem(tuple, 1, PyInt_FromLong(num));
613
614                         return tuple;
615                 }
616                 default:
617                         eDebug("unhandled getInfoObject(%d)", w);
618         }
619         Py_RETURN_NONE;
620 }
621
622 RESULT eServiceDVD::enableSubtitles(eWidget *parent, SWIG_PYOBJECT(ePyObject) /*entry*/)
623 {
624         delete m_subtitle_widget;
625
626         m_subtitle_widget = new eSubtitleWidget(parent);
627         m_subtitle_widget->resize(parent->size());
628
629         eSize size = eSize(720, 576);
630
631         if (!m_pixmap)
632         {
633                 m_pixmap = new gPixmap(size, 32, 1); /* allocate accel surface (if possible) */
634 #ifdef DDVD_SUPPORTS_GET_BLIT_DESTINATION
635                 ddvd_set_lfb_ex(m_ddvdconfig, (unsigned char *)m_pixmap->surface->data, size.width(), size.height(), 4, size.width()*4, 1);
636 #else
637                 ddvd_set_lfb(m_ddvdconfig, (unsigned char *)m_pixmap->surface->data, size.width(), size.height(), 4, size.width()*4);
638 #warning please update libdreamdvd for fast scaling
639 #endif
640                 run(); // start the thread
641         }
642
643         m_subtitle_widget->setZPosition(-1);
644         m_subtitle_widget->show();
645
646         return 0;
647 }
648
649 RESULT eServiceDVD::disableSubtitles(eWidget */*parent*/)
650 {
651         delete m_subtitle_widget;
652         m_subtitle_widget = 0;
653         return 0;
654 }
655
656 PyObject *eServiceDVD::getSubtitleList()
657 {
658         eDebug("eServiceDVD::getSubtitleList nyi");
659         Py_RETURN_NONE;
660 }
661
662 PyObject *eServiceDVD::getCachedSubtitle()
663 {
664         eDebug("eServiceDVD::getCachedSubtitle nyi");
665         Py_RETURN_NONE;
666 }
667
668 RESULT eServiceDVD::getLength(pts_t &len)
669 {
670 //      eDebug("eServiceDVD::getLength");
671         struct ddvd_time info;
672         ddvd_get_last_time(m_ddvdconfig, &info);
673         len = info.end_hours * 3600;
674         len += info.end_minutes * 60;
675         len += info.end_seconds;
676         len *= 90000;
677         return 0;
678 }
679
680 RESULT eServiceDVD::seekTo(pts_t to)
681 {
682         eDebug("eServiceDVD::seekTo(%lld)",to);
683         if ( to > 0 )
684         {
685                 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);
686                 ddvd_set_resume_pos(m_ddvdconfig, m_resume_info);
687         }
688         return 0;
689 }
690
691 RESULT eServiceDVD::seekRelative(int direction, pts_t to)
692 {
693         int seconds = to / 90000;
694         seconds *= direction;
695         eDebug("seekRelative %d %d", direction, seconds);
696         ddvd_skip_seconds(m_ddvdconfig, seconds);
697         return 0;
698 }
699
700 RESULT eServiceDVD::getPlayPosition(pts_t &pos)
701 {
702         struct ddvd_time info;
703         ddvd_get_last_time(m_ddvdconfig, &info);
704         pos = info.pos_hours * 3600;
705         pos += info.pos_minutes * 60;
706         pos += info.pos_seconds;
707 //      eDebug("getPlayPosition %lld", pos);
708         pos *= 90000;
709         return 0;
710 }
711
712 RESULT eServiceDVD::seekTitle(int title)
713 {
714         eDebug("setTitle %d", title);
715         ddvd_set_title(m_ddvdconfig, title);
716         return 0;
717 }
718
719 RESULT eServiceDVD::seekChapter(int chapter)
720 {
721         eDebug("setChapter %d", chapter);
722         if ( chapter > 0 )
723                 ddvd_set_chapter(m_ddvdconfig, chapter);
724         return 0;
725 }
726
727 RESULT eServiceDVD::setTrickmode(int /*trick*/)
728 {
729         return -1;
730 }
731
732 RESULT eServiceDVD::isCurrentlySeekable()
733 {
734         return m_state == stRunning ? 3 : 0;
735 }
736
737 RESULT eServiceDVD::keyPressed(int key)
738 {
739         switch(key)
740         {
741         case iServiceKeys::keyLeft:
742                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_LEFT);
743                 break;
744         case iServiceKeys::keyRight:
745                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_RIGHT);
746                 break;
747         case iServiceKeys::keyUp:
748                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_UP);
749                 break;
750         case iServiceKeys::keyDown:
751                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_DOWN);
752                 break;
753         case iServiceKeys::keyOk:
754                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_OK);
755                 break;
756         case iServiceKeys::keyUser:
757                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIO);
758                 break;
759         case iServiceKeys::keyUser+1:
760                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_SUBTITLE);
761                 break;
762         case iServiceKeys::keyUser+2:
763                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIOMENU);
764                 break;
765         case iServiceKeys::keyUser+3:
766                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_CHAPTER);
767                 break;
768         case iServiceKeys::keyUser+4:
769                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_CHAPTER);
770                 break;
771         case iServiceKeys::keyUser+5:
772                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_TITLE);
773                 break;
774         case iServiceKeys::keyUser+6:
775                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_TITLE);
776                 break;
777         case iServiceKeys::keyUser+7:
778                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_MENU);
779                 break;
780         case iServiceKeys::keyUser+8:
781                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_ANGLE);
782                 break;
783         default:
784                 return -1;
785         }
786         return 0;
787 }
788
789 RESULT eServiceDVD::cueSheet(ePtr<iCueSheet> &ptr)
790 {
791         if (m_cue_pts)
792         {
793                 ptr = this;
794                 return 0;
795         }
796         ptr = 0;
797         return -1;
798 }
799
800 PyObject *eServiceDVD::getCutList()
801 {
802         ePyObject list = PyList_New(1);
803         ePyObject tuple = PyTuple_New(2);
804         PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(m_cue_pts));
805         PyTuple_SetItem(tuple, 1, PyInt_FromLong(3));
806         PyList_SetItem(list, 0, tuple);
807         return list;
808 }
809
810 void eServiceDVD::setCutList(ePyObject /*list*/)
811 {
812 }
813
814 void eServiceDVD::setCutListEnable(int /*enable*/)
815 {
816 }
817
818 void eServiceDVD::loadCuesheet()
819 {
820         char filename[128];
821         if ( m_ddvd_titlestring[0] != '\0' )
822                 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
823         else
824                 snprintf(filename, 128, "%s/dvd.cuts", m_ref.path.c_str());
825
826         eDebug("eServiceDVD::loadCuesheet() filename=%s",filename);
827
828         FILE *f = fopen(filename, "rb");
829
830         if (f)
831         {
832                 unsigned long long where;
833                 unsigned int what;
834
835                 if (!fread(&where, sizeof(where), 1, f))
836                         return;
837                 if (!fread(&what, sizeof(what), 1, f))
838                         return;
839 #if BYTE_ORDER == LITTLE_ENDIAN
840                 where = bswap_64(where);
841 #endif
842                 what = ntohl(what);
843
844                 if (!fread(&m_resume_info, sizeof(struct ddvd_resume), 1, f))
845                         return;
846                 if (!fread(&what, sizeof(what), 1, f))
847                         return;
848
849                 what = ntohl(what);
850                 if (what != 4 )
851                         return;
852
853                 m_cue_pts = where;
854
855                 fclose(f);
856         } else
857                 eDebug("cutfile not found!");
858
859         if (m_cue_pts)
860         {
861                 m_event((iPlayableService*)this, evCuesheetChanged);
862                 eDebug("eServiceDVD::loadCuesheet() pts=%lld",m_cue_pts);
863         }
864 }
865
866 void eServiceDVD::saveCuesheet()
867 {
868         eDebug("eServiceDVD::saveCuesheet()");
869
870         struct ddvd_resume resume_info;
871         ddvd_get_resume_pos(m_ddvdconfig, &resume_info);
872
873         if (resume_info.title)
874         {
875                 struct ddvd_time info;
876                 ddvd_get_last_time(m_ddvdconfig, &info);
877                 pts_t pos;
878                 pos = info.pos_hours * 3600;
879                 pos += info.pos_minutes * 60;
880                 pos += info.pos_seconds;
881                 pos *= 90000;
882                 m_cue_pts = pos;
883                 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);
884         }
885         else
886         {
887                 eDebug("we're in a menu or somewhere else funny. so save cuesheet with pts=0");
888                 m_cue_pts = 0;
889         }
890
891         char filename[128];
892         if ( m_ddvd_titlestring[0] != '\0' )
893                 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
894         else
895                 snprintf(filename, 128, "%s/dvd.cuts", m_ref.path.c_str());
896         
897         FILE *f = fopen(filename, "wb");
898
899         if (f)
900         {
901                 unsigned long long where;
902                 int what;
903
904 #if BYTE_ORDER == BIG_ENDIAN
905                 where = m_cue_pts;
906 #else
907                 where = bswap_64(m_cue_pts);
908 #endif
909                 what = htonl(3);
910                 fwrite(&where, sizeof(where), 1, f);
911                 fwrite(&what, sizeof(what), 1, f);
912                 
913                 what = htonl(4);
914                 fwrite(&resume_info, sizeof(struct ddvd_resume), 1, f);
915                 fwrite(&what, sizeof(what), 1, f);
916
917                 fclose(f);
918         }
919 }
920
921 eAutoInitPtr<eServiceFactoryDVD> init_eServiceFactoryDVD(eAutoInitNumbers::service+1, "eServiceFactoryDVD");
922
923 PyMODINIT_FUNC
924 initservicedvd(void)
925 {
926         Py_InitModule("servicedvd", NULL);
927 }