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