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