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