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