dont use iPlayableService.evUser for iServiceInfomation.getInfo*
[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 sUser+8:
415                 {
416                         struct ddvd_time info;
417                         ddvd_get_last_time(m_ddvdconfig, &info);
418                         return info.pos_chapter;
419                 }
420                 case sUser+80:
421                 {
422                         struct ddvd_time info;
423                         ddvd_get_last_time(m_ddvdconfig, &info);
424                         return info.end_chapter;
425                 }
426                 case sUser+9:
427                 {
428                         struct ddvd_time info;
429                         ddvd_get_last_time(m_ddvdconfig, &info);
430                         return info.pos_title;
431                 }
432                 case sUser+90:
433                 {
434                         struct ddvd_time info;
435                         ddvd_get_last_time(m_ddvdconfig, &info);
436                         return info.end_title;
437                 }
438                 case sTXTPID:   // we abuse HAS_TELEXT icon in InfoBar to signalize subtitles status
439                 {
440                         int spu_id;
441                         uint16_t spu_lang;
442                         ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
443                         return spu_id;
444                 }
445                 default:
446                         return resNA;
447         }
448 }
449
450 std::string eServiceDVD::getInfoString(int w)
451 {
452         switch(w)
453         {
454                 case sUser+7: {
455                         int spu_id;
456                         uint16_t spu_lang;
457                         ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
458                         unsigned char spu_string[3]={spu_lang >> 8, spu_lang, 0};
459                         char osd[100];
460                         if (spu_id == -1)
461                                 sprintf(osd,"");
462                         else
463                                 sprintf(osd,"%d - %s",spu_id+1,spu_string);
464 //                      lbo_changed=1;
465                         return osd;
466                         }
467                 case sUser+6:
468                         {
469                         int audio_id,audio_type;
470                         uint16_t audio_lang;
471                         ddvd_get_last_audio(m_ddvdconfig, &audio_id, &audio_lang, &audio_type);
472                         char audio_string[3]={audio_lang >> 8, audio_lang, 0};
473                         char audio_form[5];
474                         switch(audio_type)
475                         {
476                                 case DDVD_MPEG:
477                                         sprintf(audio_form,"MPEG");
478                                         break;
479                                 case DDVD_AC3:
480                                         sprintf(audio_form,"AC3");
481                                         break;
482                                 case DDVD_DTS:
483                                         sprintf(audio_form,"DTS");
484                                         break;
485                                 case DDVD_LPCM:
486                                         sprintf(audio_form,"LPCM");
487                                         break;
488                                 default:
489                                         sprintf(audio_form,"-");
490                         }
491                         char osd[100];
492                         sprintf(osd,"%d - %s (%s)",audio_id+1,audio_string,audio_form);
493                         return osd;
494                         }
495                 default:
496                         eDebug("unhandled getInfoString(%d)", w);
497         }
498         return "";
499 }
500
501 PyObject *eServiceDVD::getInfoObject(int w)
502 {
503         switch(w)
504         {
505                 default:
506                         eDebug("unhandled getInfoObject(%d)", w);
507         }
508         Py_RETURN_NONE;
509 }
510
511 RESULT eServiceDVD::enableSubtitles(eWidget *parent, SWIG_PYOBJECT(ePyObject) entry)
512 {
513         if (m_subtitle_widget)
514                 delete m_subtitle_widget;
515         m_subtitle_widget = new eSubtitleWidget(parent);
516         m_subtitle_widget->resize(parent->size());
517         m_subtitle_widget->setPixmap(m_pixmap, eRect(0, 0, 720, 576));
518         m_subtitle_widget->setZPosition(-1);
519         m_subtitle_widget->show();
520         return 0;
521 }
522
523 RESULT eServiceDVD::disableSubtitles(eWidget *parent)
524 {
525         delete m_subtitle_widget;
526         m_subtitle_widget = 0;
527         return 0;
528 }
529
530 PyObject *eServiceDVD::getSubtitleList()
531 {
532         eDebug("eServiceDVD::getSubtitleList nyi");
533         Py_RETURN_NONE;
534 }
535
536 PyObject *eServiceDVD::getCachedSubtitle()
537 {
538         eDebug("eServiceDVD::getCachedSubtitle nyi");
539         Py_RETURN_NONE;
540 }
541
542 RESULT eServiceDVD::getLength(pts_t &len)
543 {
544 //      eDebug("eServiceDVD::getLength");
545         struct ddvd_time info;
546         ddvd_get_last_time(m_ddvdconfig, &info);
547         len = info.end_hours * 3600;
548         len += info.end_minutes * 60;
549         len += info.end_seconds;
550         len *= 90000;
551         return 0;
552 }
553
554 RESULT eServiceDVD::seekTo(pts_t to)
555 {
556         struct ddvd_time info;
557         to /= 90000;
558         int cur;
559         ddvd_get_last_time(m_ddvdconfig, &info);
560         cur = info.pos_hours * 3600;
561         cur += info.pos_minutes * 60;
562         cur += info.pos_seconds;
563         eDebug("seekTo %lld, cur %d, diff %lld", to, cur, to - cur);
564         ddvd_skip_seconds(m_ddvdconfig, to - cur);
565         return 0;
566 }
567
568 RESULT eServiceDVD::seekRelative(int direction, pts_t to)
569 {
570         int seconds = to / 90000;
571         seconds *= direction;
572         eDebug("seekRelative %d %d", direction, seconds);
573         ddvd_skip_seconds(m_ddvdconfig, seconds);
574         return 0;
575 }
576
577 RESULT eServiceDVD::getPlayPosition(pts_t &pos)
578 {
579         struct ddvd_time info;
580         ddvd_get_last_time(m_ddvdconfig, &info);
581         pos = info.pos_hours * 3600;
582         pos += info.pos_minutes * 60;
583         pos += info.pos_seconds;
584 //      eDebug("getPlayPosition %lld", pos);
585         pos *= 90000;
586         return 0;
587 }
588
589 RESULT eServiceDVD::seekTitle(int title)
590 {
591         eDebug("setTitle %d", title);
592         ddvd_set_title(m_ddvdconfig, title);
593         return 0;
594 }
595
596 RESULT eServiceDVD::seekChapter(int chapter)
597 {
598         eDebug("setChapter %d", chapter);
599         if ( chapter > 0 )
600                 ddvd_set_chapter(m_ddvdconfig, chapter);
601         return 0;
602 }
603
604 RESULT eServiceDVD::setTrickmode(int trick)
605 {
606         return -1;
607 }
608
609 RESULT eServiceDVD::isCurrentlySeekable()
610 {
611         return m_state == stRunning;
612 }
613
614 RESULT eServiceDVD::keyPressed(int key)
615 {
616         switch(key)
617         {
618         case iServiceKeys::keyLeft:
619                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_LEFT);
620                 break;
621         case iServiceKeys::keyRight:
622                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_RIGHT);
623                 break;
624         case iServiceKeys::keyUp:
625                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_UP);
626                 break;
627         case iServiceKeys::keyDown:
628                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_DOWN);
629                 break;
630         case iServiceKeys::keyOk:
631                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_OK);
632                 break;
633         case iServiceKeys::keyUser:
634                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIO);
635                 break;
636         case iServiceKeys::keyUser+1:
637                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_SUBTITLE);
638                 break;
639         case iServiceKeys::keyUser+2:
640                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIOMENU);
641                 break;
642         case iServiceKeys::keyUser+3:
643                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_CHAPTER);
644                 break;
645         case iServiceKeys::keyUser+4:
646                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_CHAPTER);
647                 break;
648         case iServiceKeys::keyUser+5:
649                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_TITLE);
650                 break;
651         case iServiceKeys::keyUser+6:
652                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_TITLE);
653                 break;
654         case iServiceKeys::keyUser+7:
655                 ddvd_send_key(m_ddvdconfig, DDVD_KEY_MENU);
656                 break;
657         default:
658                 return -1;
659         }
660         return 0;
661 }
662
663 RESULT eServiceDVD::cueSheet(ePtr<iCueSheet> &ptr)
664 {
665         if (m_cue_pts)
666         {
667                 ptr = this;
668                 return 0;
669         }
670         ptr = 0;
671         return -1;
672 }
673
674 PyObject *eServiceDVD::getCutList()
675 {
676         ePyObject list = PyList_New(1);
677         ePyObject tuple = PyTuple_New(2);
678         PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(m_cue_pts));
679         PyTuple_SetItem(tuple, 1, PyInt_FromLong(3));
680         PyList_SetItem(list, 0, tuple);
681         return list;
682 }
683
684 void eServiceDVD::setCutList(ePyObject list)
685 {
686 }
687
688 void eServiceDVD::setCutListEnable(int enable)
689 {
690 }
691
692 void eServiceDVD::loadCuesheet()
693 {
694         eDebug("eServiceDVD::loadCuesheet()");
695         char filename[128];
696         if ( m_ddvd_titlestring[0] != '\0' )
697                 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
698
699         eDebug("eServiceDVD::loadCuesheet() filename=%s",filename);
700
701         FILE *f = fopen(filename, "rb");
702
703         if (f)
704         {
705                 eDebug("loading cuts..");
706                 unsigned long long where;
707                 unsigned int what;
708
709                 if (!fread(&where, sizeof(where), 1, f))
710                         return;
711
712                 if (!fread(&what, sizeof(what), 1, f))
713                         return;
714                         
715 #if BYTE_ORDER == LITTLE_ENDIAN
716                 where = bswap_64(where);
717 #endif
718                 what = ntohl(what);
719
720                 m_cue_pts = where;
721                 fclose(f);
722         } else
723                 eDebug("cutfile not found!");
724
725         eDebug("eServiceDVD::loadCuesheet() pts=%lld",m_cue_pts);
726
727         if (m_cue_pts)
728                 m_event((iPlayableService*)this, evCuesheetChanged);
729 }
730
731 void eServiceDVD::saveCuesheet()
732 {
733         eDebug("eServiceDVD::saveCuesheet() pts=%lld",m_cue_pts);
734         char filename[128];
735         if ( m_ddvd_titlestring[0] != '\0' )
736                 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
737         
738         FILE *f = fopen(filename, "wb");
739
740         if (f)
741         {
742                 unsigned long long where;
743                 int what;
744
745                 {
746 #if BYTE_ORDER == BIG_ENDIAN
747                         where = m_cue_pts;
748 #else
749                         where = bswap_64(m_cue_pts);
750 #endif
751                         what = 3;
752                         fwrite(&where, sizeof(where), 1, f);
753                         fwrite(&what, sizeof(what), 1, f);
754                 }
755                 fclose(f);
756         }
757 }
758
759 eAutoInitPtr<eServiceFactoryDVD> init_eServiceFactoryDVD(eAutoInitNumbers::service+1, "eServiceFactoryDVD");
760
761 PyMODINIT_FUNC
762 initservicedvd(void)
763 {
764         Py_InitModule("servicedvd", NULL);
765 }