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