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