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