filebrowser now ends up in previous directory again after playing a dvd stucture...
[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_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                         if (!m_cue_pts)
235                                 unpause();
236                         m_event(this, evStart);
237                         break;
238                 }
239                 case DDVD_MENU_OPENED:
240                         eDebug("DVD_MENU_OPENED!");
241                         m_state = stMenu;
242                         m_event(this, evSeekableStatusChanged);
243                         m_event(this, evUser+11);
244                         break;
245                 case DDVD_MENU_CLOSED:
246                         eDebug("DVD_MENU_CLOSED!");
247                         m_state = stRunning;
248                         m_event(this, evSeekableStatusChanged);
249                         m_event(this, evUser+12);
250                         break;
251                 default:
252                         break;
253         }
254 }
255
256 eServiceDVD::~eServiceDVD()
257 {
258         eDebug("SERVICEDVD destruct!");
259         kill();
260         saveCuesheet();
261         ddvd_close(m_ddvdconfig);
262 }
263
264 RESULT eServiceDVD::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
265 {
266         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
267         return 0;
268 }
269
270 RESULT eServiceDVD::start()
271 {
272         assert(m_state == stIdle);
273         m_state = stRunning;
274         eDebug("eServiceDVD starting");
275         run();
276 //      m_event(this, evStart);
277         return 0;
278 }
279
280 RESULT eServiceDVD::stop()
281 {
282         assert(m_state != stIdle);
283         if (m_state == stStopped)
284                 return -1;
285         eDebug("DVD: stop %s", m_filename.c_str());
286         m_state = stStopped;
287         ddvd_send_key(m_ddvdconfig, DDVD_KEY_EXIT);
288
289         return 0;
290 }
291
292 RESULT eServiceDVD::setTarget(int /*target*/)
293 {
294         return -1;
295 }
296
297 RESULT eServiceDVD::pause(ePtr<iPauseableService> &ptr)
298 {
299         ptr=this;
300         return 0;
301 }
302
303 RESULT eServiceDVD::seek(ePtr<iSeekableService> &ptr)
304 {
305         ptr=this;
306         return 0;
307 }
308
309 RESULT eServiceDVD::subtitle(ePtr<iSubtitleOutput> &ptr)
310 {
311         ptr=this;
312         return 0;
313 }
314
315 RESULT eServiceDVD::keys(ePtr<iServiceKeys> &ptr)
316 {
317         ptr=this;
318         return 0;
319 }
320
321         // iPausableService
322 RESULT eServiceDVD::setSlowMotion(int /*ratio*/)
323 {
324         return -1;
325 }
326
327 RESULT eServiceDVD::setFastForward(int trick)
328 {
329         eDebug("setTrickmode(%d)", trick);
330         while (m_current_trick > trick && m_current_trick != -64)
331         {
332                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_FBWD);
333                 if (m_current_trick == 0)
334                         m_current_trick = -2;
335                 else if (m_current_trick > 0)
336                 {
337                         m_current_trick /= 2;
338                         if (abs(m_current_trick) == 1)
339                                 m_current_trick=0;
340                 }
341                 else
342                         m_current_trick *= 2;
343         }
344         while (m_current_trick < trick && m_current_trick != 64)
345         {
346                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_FFWD);
347                 if (m_current_trick == 0)
348                         m_current_trick = 2;
349                 else if (m_current_trick < 0)
350                 {
351                         m_current_trick /= 2;
352                         if (abs(m_current_trick) == 1)
353                                 m_current_trick=0;
354                 }
355                 else
356                         m_current_trick *= 2;
357         }
358         return 0;
359 }
360
361 RESULT eServiceDVD::pause()
362 {
363         eDebug("set pause!\n");
364         ddvd_send_key(m_ddvdconfig, DDVD_KEY_PAUSE);
365         return 0;
366 }
367
368 RESULT eServiceDVD::unpause()
369 {
370         eDebug("set unpause!\n");
371         ddvd_send_key(m_ddvdconfig, DDVD_KEY_PLAY);
372         return 0;
373 }
374
375 void eServiceDVD::thread()
376 {
377         eDebug("eServiceDVD dvd thread started");
378         hasStarted();
379         ddvd_run(m_ddvdconfig);
380 }
381
382 void eServiceDVD::thread_finished()
383 {
384         eDebug("eServiceDVD dvd thread finished");
385         m_pump.send(1); // inform main thread
386 }
387
388 RESULT eServiceDVD::info(ePtr<iServiceInformation>&i)
389 {
390         i = this;
391         return 0;
392 }
393
394 RESULT eServiceDVD::getName(std::string &name)
395 {
396         if ( m_ddvd_titlestring[0] != '\0' )
397                 name = m_ddvd_titlestring;
398         else
399                 name = m_filename;
400         return 0;
401 }
402
403 int eServiceDVD::getInfo(int w)
404 {
405         switch (w)
406         {
407                 case sCurrentChapter:
408                 {
409                         struct ddvd_time info;
410                         ddvd_get_last_time(m_ddvdconfig, &info);
411                         return info.pos_chapter;
412                 }
413                 case sTotalChapters:
414                 {
415                         struct ddvd_time info;
416                         ddvd_get_last_time(m_ddvdconfig, &info);
417                         return info.end_chapter;
418                 }
419                 case sCurrentTitle:
420                 {
421                         struct ddvd_time info;
422                         ddvd_get_last_time(m_ddvdconfig, &info);
423                         return info.pos_title;
424                 }
425                 case sTotalTitles:
426                 {
427                         struct ddvd_time info;
428                         ddvd_get_last_time(m_ddvdconfig, &info);
429                         return info.end_title;
430                 }
431                 case sTXTPID:   // we abuse HAS_TELEXT icon in InfoBar to signalize subtitles status
432                 {
433                         int spu_id;
434                         uint16_t spu_lang;
435                         ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
436                         return spu_id;
437                 }
438                 case sUser+6:
439                 case sUser+7:
440                         return resIsPyObject;
441                 default:
442                         return resNA;
443         }
444 }
445
446 std::string eServiceDVD::getInfoString(int w)
447 {
448         switch(w)
449         {
450                 case sServiceref:
451                         break;
452                 default:
453                         eDebug("unhandled getInfoString(%d)", w);
454         }
455         return "";
456 }
457
458 PyObject *eServiceDVD::getInfoObject(int w)
459 {
460         switch(w)
461         {
462                 case sUser+6:
463                 {
464                         ePyObject tuple = PyTuple_New(3);
465                         int audio_id,audio_type;
466                         uint16_t audio_lang;
467                         ddvd_get_last_audio(m_ddvdconfig, &audio_id, &audio_lang, &audio_type);
468                         char audio_string[3]={audio_lang >> 8, audio_lang, 0};
469                         PyTuple_SetItem(tuple, 0, PyInt_FromLong(audio_id+1));
470                         PyTuple_SetItem(tuple, 1, PyString_FromString(audio_string));
471                         switch(audio_type)
472                         {
473                                 case DDVD_MPEG:
474                                         PyTuple_SetItem(tuple, 2, PyString_FromString("MPEG"));
475                                         break;
476                                 case DDVD_AC3:
477                                         PyTuple_SetItem(tuple, 2, PyString_FromString("AC3"));
478                                         break;
479                                 case DDVD_DTS:
480                                         PyTuple_SetItem(tuple, 2, PyString_FromString("DTS"));
481                                         break;
482                                 case DDVD_LPCM:
483                                         PyTuple_SetItem(tuple, 2, PyString_FromString("LPCM"));
484                                         break;
485                                 default:
486                                         PyTuple_SetItem(tuple, 2, PyString_FromString(""));
487                         }
488                         return tuple;
489                 }
490                 case sUser+7:
491                 {
492                         ePyObject tuple = PyTuple_New(2);
493                         int spu_id;
494                         uint16_t spu_lang;
495                         ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
496                         char spu_string[3]={spu_lang >> 8, spu_lang, 0};
497                         if (spu_id == -1)
498                         {
499                                 PyTuple_SetItem(tuple, 0, PyInt_FromLong(0));
500                                 PyTuple_SetItem(tuple, 1, PyString_FromString(""));
501                         }
502                         else
503                         {
504                                 PyTuple_SetItem(tuple, 0, PyInt_FromLong(spu_id+1));
505                                 PyTuple_SetItem(tuple, 1, PyString_FromString(spu_string));
506                         }                               
507                         return tuple;
508                 }
509                 default:
510                         eDebug("unhandled getInfoObject(%d)", w);
511         }
512         Py_RETURN_NONE;
513 }
514
515 RESULT eServiceDVD::enableSubtitles(eWidget *parent, SWIG_PYOBJECT(ePyObject) /*entry*/)
516 {
517         if (m_subtitle_widget)
518                 delete m_subtitle_widget;
519         m_subtitle_widget = new eSubtitleWidget(parent);
520         m_subtitle_widget->resize(parent->size());
521         m_subtitle_widget->setPixmap(m_pixmap, eRect(0, 0, 720, 576));
522         m_subtitle_widget->setZPosition(-1);
523         m_subtitle_widget->show();
524         return 0;
525 }
526
527 RESULT eServiceDVD::disableSubtitles(eWidget */*parent*/)
528 {
529         delete m_subtitle_widget;
530         m_subtitle_widget = 0;
531         return 0;
532 }
533
534 PyObject *eServiceDVD::getSubtitleList()
535 {
536         eDebug("eServiceDVD::getSubtitleList nyi");
537         Py_RETURN_NONE;
538 }
539
540 PyObject *eServiceDVD::getCachedSubtitle()
541 {
542         eDebug("eServiceDVD::getCachedSubtitle nyi");
543         Py_RETURN_NONE;
544 }
545
546 RESULT eServiceDVD::getLength(pts_t &len)
547 {
548 //      eDebug("eServiceDVD::getLength");
549         struct ddvd_time info;
550         ddvd_get_last_time(m_ddvdconfig, &info);
551         len = info.end_hours * 3600;
552         len += info.end_minutes * 60;
553         len += info.end_seconds;
554         len *= 90000;
555         return 0;
556 }
557
558 RESULT eServiceDVD::seekTo(pts_t to)
559 {
560         eDebug("eServiceDVD::seekTo(%lld)",to);
561         if ( to > 0 )
562         {
563                 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);
564                 ddvd_set_resume_pos(m_ddvdconfig, m_resume_info);
565         }
566         return 0;
567 }
568
569 RESULT eServiceDVD::seekRelative(int direction, pts_t to)
570 {
571         int seconds = to / 90000;
572         seconds *= direction;
573         eDebug("seekRelative %d %d", direction, seconds);
574         ddvd_skip_seconds(m_ddvdconfig, seconds);
575         return 0;
576 }
577
578 RESULT eServiceDVD::getPlayPosition(pts_t &pos)
579 {
580         struct ddvd_time info;
581         ddvd_get_last_time(m_ddvdconfig, &info);
582         pos = info.pos_hours * 3600;
583         pos += info.pos_minutes * 60;
584         pos += info.pos_seconds;
585 //      eDebug("getPlayPosition %lld", pos);
586         pos *= 90000;
587         return 0;
588 }
589
590 RESULT eServiceDVD::seekTitle(int title)
591 {
592         eDebug("setTitle %d", title);
593         ddvd_set_title(m_ddvdconfig, title);
594         return 0;
595 }
596
597 RESULT eServiceDVD::seekChapter(int chapter)
598 {
599         eDebug("setChapter %d", chapter);
600         if ( chapter > 0 )
601                 ddvd_set_chapter(m_ddvdconfig, chapter);
602         return 0;
603 }
604
605 RESULT eServiceDVD::setTrickmode(int /*trick*/)
606 {
607         return -1;
608 }
609
610 RESULT eServiceDVD::isCurrentlySeekable()
611 {
612         return m_state == stRunning;
613 }
614
615 RESULT eServiceDVD::keyPressed(int key)
616 {
617         switch(key)
618         {
619         case iServiceKeys::keyLeft:
620                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_LEFT);
621                 break;
622         case iServiceKeys::keyRight:
623                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_RIGHT);
624                 break;
625         case iServiceKeys::keyUp:
626                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_UP);
627                 break;
628         case iServiceKeys::keyDown:
629                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_DOWN);
630                 break;
631         case iServiceKeys::keyOk:
632                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_OK);
633                 break;
634         case iServiceKeys::keyUser:
635                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIO);
636                 break;
637         case iServiceKeys::keyUser+1:
638                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_SUBTITLE);
639                 break;
640         case iServiceKeys::keyUser+2:
641                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIOMENU);
642                 break;
643         case iServiceKeys::keyUser+3:
644                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_CHAPTER);
645                 break;
646         case iServiceKeys::keyUser+4:
647                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_CHAPTER);
648                 break;
649         case iServiceKeys::keyUser+5:
650                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_TITLE);
651                 break;
652         case iServiceKeys::keyUser+6:
653                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_TITLE);
654                 break;
655         case iServiceKeys::keyUser+7:
656                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_MENU);
657                 break;
658         default:
659                 return -1;
660         }
661         return 0;
662 }
663
664 RESULT eServiceDVD::cueSheet(ePtr<iCueSheet> &ptr)
665 {
666         if (m_cue_pts)
667         {
668                 ptr = this;
669                 return 0;
670         }
671         ptr = 0;
672         return -1;
673 }
674
675 PyObject *eServiceDVD::getCutList()
676 {
677         ePyObject list = PyList_New(1);
678         ePyObject tuple = PyTuple_New(2);
679         PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(m_cue_pts));
680         PyTuple_SetItem(tuple, 1, PyInt_FromLong(3));
681         PyList_SetItem(list, 0, tuple);
682         return list;
683 }
684
685 void eServiceDVD::setCutList(ePyObject /*list*/)
686 {
687 }
688
689 void eServiceDVD::setCutListEnable(int /*enable*/)
690 {
691 }
692
693 void eServiceDVD::loadCuesheet()
694 {
695         char filename[128];
696         if ( m_ddvd_titlestring[0] != '\0' )
697                 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
698         else
699                 snprintf(filename, 128, "%s/dvd.cuts", m_filename.c_str());
700
701         eDebug("eServiceDVD::loadCuesheet() filename=%s",filename);
702
703         FILE *f = fopen(filename, "rb");
704
705         if (f)
706         {
707                 unsigned long long where;
708                 unsigned int what;
709
710                 if (!fread(&where, sizeof(where), 1, f))
711                         return;
712                 if (!fread(&what, sizeof(what), 1, f))
713                         return;
714 #if BYTE_ORDER == LITTLE_ENDIAN
715                 where = bswap_64(where);
716 #endif
717                 what = ntohl(what);
718
719                 if (!fread(&m_resume_info, sizeof(struct ddvd_resume), 1, f))
720                         return;
721                 if (!fread(&what, sizeof(what), 1, f))
722                         return;
723
724                 what = ntohl(what);
725                 if (what != 4 )
726                         return;
727
728                 m_cue_pts = where;
729
730                 fclose(f);
731         } else
732                 eDebug("cutfile not found!");
733
734         if (m_cue_pts)
735         {
736                 m_event((iPlayableService*)this, evCuesheetChanged);
737                 eDebug("eServiceDVD::loadCuesheet() pts=%lld",m_cue_pts);
738         }
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 }