disable cuesheet (resume) until in understand the libdvdnav :)
[vuplus_dvbapp] / 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                         if ( info.pos_chapter != last_info.pos_chapter )
211                                 m_event(this, evUser+8); // chapterUpdated
212                         if ( info.pos_title != last_info.pos_title )
213                                 m_event(this, evUser+9); // titleUpdated
214                         memcpy(&last_info, &info, sizeof(struct ddvd_time));
215                         break;
216                 }
217                 case DDVD_SHOWOSD_TITLESTRING:
218                 {
219                         ddvd_get_title_string(m_ddvdconfig, m_ddvd_titlestring);
220                         eDebug("DDVD_SHOWOSD_TITLESTRING: %s",m_ddvd_titlestring);
221                         loadCuesheet();
222                         m_event(this, evStart);
223                         break;
224                 }
225                 case DDVD_MENU_OPENED:
226                         eDebug("DVD_MENU_OPENED!");
227                         m_state = stMenu;
228                         m_event(this, evSeekableStatusChanged);
229                         m_event(this, evUser+11);
230                         break;
231                 case DDVD_MENU_CLOSED:
232                         eDebug("DVD_MENU_CLOSED!");
233                         m_state = stRunning;
234                         m_event(this, evSeekableStatusChanged);
235                         m_event(this, evUser+12);
236                         break;
237                 default:
238                         break;
239         }
240 }
241
242 eServiceDVD::~eServiceDVD()
243 {
244         eDebug("SERVICEDVD destruct!");
245         kill();
246         ddvd_close(m_ddvdconfig);
247 }
248
249 RESULT eServiceDVD::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
250 {
251         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
252         return 0;
253 }
254
255 RESULT eServiceDVD::start()
256 {
257         assert(m_state == stIdle);
258         m_state = stRunning;
259         eDebug("eServiceDVD starting");
260         run();
261 //      m_event(this, evStart);
262         return 0;
263 }
264
265 RESULT eServiceDVD::stop()
266 {
267         assert(m_state != stIdle);
268         if (m_state == stStopped)
269                 return -1;
270         eDebug("DVD: stop %s", m_filename.c_str());
271         m_state = stStopped;
272         ddvd_send_key(m_ddvdconfig, DDVD_KEY_EXIT);
273         struct ddvd_time info;
274         ddvd_get_last_time(m_ddvdconfig, &info);
275         if ( info.pos_chapter < info.end_chapter )
276         {
277                 pts_t pos;
278                 pos = info.pos_hours * 3600;
279                 pos += info.pos_minutes * 60;
280                 pos += info.pos_seconds;
281                 pos *= 90000;
282                 pos += info.pos_title * 256;
283                 pos += info.pos_chapter;
284                 m_cue_pts = pos;
285                 eDebug("POS %llu\n", m_cue_pts);
286         }
287         saveCuesheet();
288         return 0;
289 }
290
291 RESULT eServiceDVD::setTarget(int target)
292 {
293         return -1;
294 }
295
296 RESULT eServiceDVD::pause(ePtr<iPauseableService> &ptr)
297 {
298         ptr=this;
299         return 0;
300 }
301
302 RESULT eServiceDVD::seek(ePtr<iSeekableService> &ptr)
303 {
304         ptr=this;
305         return 0;
306 }
307
308 RESULT eServiceDVD::subtitle(ePtr<iSubtitleOutput> &ptr)
309 {
310         ptr=this;
311         return 0;
312 }
313
314 RESULT eServiceDVD::keys(ePtr<iServiceKeys> &ptr)
315 {
316         ptr=this;
317         return 0;
318 }
319
320         // iPausableService
321 RESULT eServiceDVD::setSlowMotion(int ratio)
322 {
323         return -1;
324 }
325
326 RESULT eServiceDVD::setFastForward(int trick)
327 {
328         eDebug("setTrickmode(%d)", trick);
329         while (m_current_trick > trick && m_current_trick != -64)
330         {
331                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_FBWD);
332                 if (m_current_trick == 0)
333                         m_current_trick = -2;
334                 else if (m_current_trick > 0)
335                 {
336                         m_current_trick /= 2;
337                         if (abs(m_current_trick) == 1)
338                                 m_current_trick=0;
339                 }
340                 else
341                         m_current_trick *= 2;
342         }
343         while (m_current_trick < trick && m_current_trick != 64)
344         {
345                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_FFWD);
346                 if (m_current_trick == 0)
347                         m_current_trick = 2;
348                 else if (m_current_trick < 0)
349                 {
350                         m_current_trick /= 2;
351                         if (abs(m_current_trick) == 1)
352                                 m_current_trick=0;
353                 }
354                 else
355                         m_current_trick *= 2;
356         }
357         return 0;
358 }
359
360 RESULT eServiceDVD::pause()
361 {
362         eDebug("set pause!\n");
363         ddvd_send_key(m_ddvdconfig, DDVD_KEY_PAUSE);
364         return 0;
365 }
366
367 RESULT eServiceDVD::unpause()
368 {
369         eDebug("set unpause!\n");
370         ddvd_send_key(m_ddvdconfig, DDVD_KEY_PLAY);
371         return 0;
372 }
373
374 void eServiceDVD::thread()
375 {
376         eDebug("eServiceDVD dvd thread started");
377         hasStarted();
378         ddvd_run(m_ddvdconfig);
379 }
380
381 void eServiceDVD::thread_finished()
382 {
383         eDebug("eServiceDVD dvd thread finished");
384         m_pump.send(1); // inform main thread
385 }
386
387 RESULT eServiceDVD::info(ePtr<iServiceInformation>&i)
388 {
389         i = this;
390         return 0;
391 }
392
393 RESULT eServiceDVD::getName(std::string &name)
394 {
395         if ( m_ddvd_titlestring[0] != '\0' )
396                 name = m_ddvd_titlestring;
397         else
398                 name = m_filename;
399         return 0;
400 }
401
402 int eServiceDVD::getInfo(int w)
403 {
404         switch (w)
405                 {
406                 case sUser:
407                 case sArtist:
408                 case sAlbum:
409                         return resIsPyObject;  // then getInfoObject should be called
410                 case sComment:
411                 case sTracknumber:
412                 case sGenre:
413                         return resIsString;  // then getInfoString should be called
414                 case evUser+8:
415                 {
416                         struct ddvd_time info;
417                         ddvd_get_last_time(m_ddvdconfig, &info);
418                         return info.pos_chapter;
419                 }
420                 case evUser+80:
421                 {
422                         struct ddvd_time info;
423                         ddvd_get_last_time(m_ddvdconfig, &info);
424                         return info.end_chapter;
425                 }
426
427                 case evUser+9:
428                 {
429                         struct ddvd_time info;
430                         ddvd_get_last_time(m_ddvdconfig, &info);
431                         return info.pos_title;
432                 }
433                 case evUser+90:
434                 {
435                         struct ddvd_time info;
436                         ddvd_get_last_time(m_ddvdconfig, &info);
437                         return info.end_title;
438                 }
439
440                 case sTXTPID:   // we abuse HAS_TELEXT icon in InfoBar to signalize subtitles status
441                 {
442                         int spu_id;
443                         uint16_t spu_lang;
444                         ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
445                         return spu_id;
446                 }
447                 default:
448                         return resNA;
449         }
450 }
451
452 std::string eServiceDVD::getInfoString(int w)
453 {
454         switch(w)
455         {
456                 case evUser+7: {
457                         int spu_id;
458                         uint16_t spu_lang;
459                         ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
460                         unsigned char spu_string[3]={spu_lang >> 8, spu_lang, 0};
461                         char osd[100];
462                         if (spu_id == -1)
463                                 sprintf(osd,"");
464                         else
465                                 sprintf(osd,"%d - %s",spu_id+1,spu_string);
466 //                      lbo_changed=1;
467                         return osd;
468                         }
469                 case evUser+6:
470                         {
471                         int audio_id,audio_type;
472                         uint16_t audio_lang;
473                         ddvd_get_last_audio(m_ddvdconfig, &audio_id, &audio_lang, &audio_type);
474                         char audio_string[3]={audio_lang >> 8, audio_lang, 0};
475                         char audio_form[5];
476                         switch(audio_type)
477                         {
478                                 case DDVD_MPEG:
479                                         sprintf(audio_form,"MPEG");
480                                         break;
481                                 case DDVD_AC3:
482                                         sprintf(audio_form,"AC3");
483                                         break;
484                                 case DDVD_DTS:
485                                         sprintf(audio_form,"DTS");
486                                         break;
487                                 case DDVD_LPCM:
488                                         sprintf(audio_form,"LPCM");
489                                         break;
490                                 default:
491                                         sprintf(audio_form,"-");
492                         }
493                         char osd[100];
494                         sprintf(osd,"%d - %s (%s)",audio_id+1,audio_string,audio_form);
495                         return osd;
496                         }
497                 default:
498                         eDebug("unhandled getInfoString(%d)", w);
499         }
500         return "";
501 }
502
503 PyObject *eServiceDVD::getInfoObject(int w)
504 {
505         switch(w)
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         struct ddvd_time info;
559         to /= 90000;
560         int cur;
561         ddvd_get_last_time(m_ddvdconfig, &info);
562         cur = info.pos_hours * 3600;
563         cur += info.pos_minutes * 60;
564         cur += info.pos_seconds;
565         eDebug("seekTo %lld, cur %d, diff %lld", to, cur, to - cur);
566         ddvd_skip_seconds(m_ddvdconfig, to - cur);
567         return 0;
568 }
569
570 RESULT eServiceDVD::seekRelative(int direction, pts_t to)
571 {
572         int seconds = to / 90000;
573         seconds *= direction;
574         eDebug("seekRelative %d %d", direction, seconds);
575         ddvd_skip_seconds(m_ddvdconfig, seconds);
576         return 0;
577 }
578
579 RESULT eServiceDVD::getPlayPosition(pts_t &pos)
580 {
581         struct ddvd_time info;
582         ddvd_get_last_time(m_ddvdconfig, &info);
583         pos = info.pos_hours * 3600;
584         pos += info.pos_minutes * 60;
585         pos += info.pos_seconds;
586 //      eDebug("getPlayPosition %lld", pos);
587         pos *= 90000;
588         return 0;
589 }
590
591 RESULT eServiceDVD::seekTitle(int title)
592 {
593         eDebug("setTitle %d", title);
594         ddvd_set_title(m_ddvdconfig, title);
595         return 0;
596 }
597
598 RESULT eServiceDVD::seekChapter(int chapter)
599 {
600         eDebug("setChapter %d", chapter);
601         if ( chapter > 0 )
602                 ddvd_set_chapter(m_ddvdconfig, chapter);
603         return 0;
604 }
605
606 RESULT eServiceDVD::setTrickmode(int trick)
607 {
608         return -1;
609 }
610
611 RESULT eServiceDVD::isCurrentlySeekable()
612 {
613         return m_state == stRunning;
614 }
615
616 RESULT eServiceDVD::keyPressed(int key)
617 {
618         switch(key)
619         {
620         case iServiceKeys::keyLeft:
621                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_LEFT);
622                 break;
623         case iServiceKeys::keyRight:
624                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_RIGHT);
625                 break;
626         case iServiceKeys::keyUp:
627                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_UP);
628                 break;
629         case iServiceKeys::keyDown:
630                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_DOWN);
631                 break;
632         case iServiceKeys::keyOk:
633                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_OK);
634                 break;
635         case iServiceKeys::keyUser:
636                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIO);
637                 break;
638         case iServiceKeys::keyUser+1:
639                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_SUBTITLE);
640                 break;
641         case iServiceKeys::keyUser+2:
642                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIOMENU);
643                 break;
644         case iServiceKeys::keyUser+3:
645                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_CHAPTER);
646                 break;
647         case iServiceKeys::keyUser+4:
648                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_CHAPTER);
649                 break;
650         case iServiceKeys::keyUser+5:
651                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_TITLE);
652                 break;
653         case iServiceKeys::keyUser+6:
654                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_TITLE);
655                 break;
656         case iServiceKeys::keyUser+7:
657                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_MENU);
658                 break;
659         default:
660                 return -1;
661         }
662         return 0;
663 }
664
665 RESULT eServiceDVD::cueSheet(ePtr<iCueSheet> &ptr)
666 {
667         if (m_cue_pts)
668         {
669                 ptr = this;
670                 return 0;
671         }
672         ptr = 0;
673         return -1;
674 }
675
676 PyObject *eServiceDVD::getCutList()
677 {
678         ePyObject list = PyList_New(1);
679         ePyObject tuple = PyTuple_New(2);
680         PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(m_cue_pts));
681         PyTuple_SetItem(tuple, 1, PyInt_FromLong(3));
682         PyList_SetItem(list, 0, tuple);
683         return list;
684 }
685
686 void eServiceDVD::setCutList(ePyObject list)
687 {
688 }
689
690 void eServiceDVD::setCutListEnable(int enable)
691 {
692 }
693
694 void eServiceDVD::loadCuesheet()
695 {
696         eDebug("eServiceDVD::loadCuesheet()");
697         char filename[128];
698         if ( m_ddvd_titlestring[0] != '\0' )
699                 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
700
701         eDebug("eServiceDVD::loadCuesheet() filename=%s",filename);
702
703         FILE *f = fopen(filename, "rb");
704
705         if (f)
706         {
707                 eDebug("loading cuts..");
708                 unsigned long long where;
709                 unsigned int what;
710
711                 if (!fread(&where, sizeof(where), 1, f))
712                         return;
713
714                 if (!fread(&what, sizeof(what), 1, f))
715                         return;
716                         
717 #if BYTE_ORDER == LITTLE_ENDIAN
718                 where = bswap_64(where);
719 #endif
720                 what = ntohl(what);
721
722                 m_cue_pts = where;
723                 fclose(f);
724         } else
725                 eDebug("cutfile not found!");
726
727         eDebug("eServiceDVD::loadCuesheet() pts=%lld",m_cue_pts);
728
729         if (m_cue_pts)
730                 m_event((iPlayableService*)this, evCuesheetChanged);
731 }
732
733 void eServiceDVD::saveCuesheet()
734 {
735         eDebug("eServiceDVD::saveCuesheet() pts=%lld",m_cue_pts);
736         char filename[128];
737         if ( m_ddvd_titlestring[0] != '\0' )
738                 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
739         
740         FILE *f = fopen(filename, "wb");
741
742         if (f)
743         {
744                 unsigned long long where;
745                 int what;
746
747                 {
748 #if BYTE_ORDER == BIG_ENDIAN
749                         where = m_cue_pts;
750 #else
751                         where = bswap_64(m_cue_pts);
752 #endif
753                         what = 3;
754                         fwrite(&where, sizeof(where), 1, f);
755                         fwrite(&what, sizeof(what), 1, f);
756                 }
757                 fclose(f);
758         }
759 }
760
761 eAutoInitPtr<eServiceFactoryDVD> init_eServiceFactoryDVD(eAutoInitNumbers::service+1, "eServiceFactoryDVD");
762
763 PyMODINIT_FUNC
764 initservicedvd(void)
765 {
766         Py_InitModule("servicedvd", NULL);
767 }