2 #include <lib/base/eerror.h>
3 #include <lib/base/object.h>
4 #include <lib/base/ebase.h>
5 #include <lib/base/nconfig.h>
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>
14 #include <netinet/in.h>
16 #error no byte order defined!
20 #include <dreamdvd/ddvdlib.h>
22 #include "servicedvd.h"
26 eServiceFactoryDVD::eServiceFactoryDVD()
28 ePtr<eServiceCenter> sc;
30 eServiceCenter::getPrivInstance(sc);
33 std::list<std::string> extensions;
34 extensions.push_back("iso");
35 sc->addServiceFactory(eServiceFactoryDVD::id, this, extensions);
39 eServiceFactoryDVD::~eServiceFactoryDVD()
41 ePtr<eServiceCenter> sc;
43 eServiceCenter::getPrivInstance(sc);
45 sc->removeServiceFactory(eServiceFactoryDVD::id);
48 DEFINE_REF(eServiceFactoryDVD)
51 RESULT eServiceFactoryDVD::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
54 ptr = new eServiceDVD(ref);
58 RESULT eServiceFactoryDVD::record(const eServiceReference &/*ref*/, ePtr<iRecordableService> &ptr)
64 RESULT eServiceFactoryDVD::list(const eServiceReference &, ePtr<iListableService> &ptr)
71 RESULT eServiceFactoryDVD::info(const eServiceReference &/*ref*/, ePtr<iStaticServiceInformation> &ptr)
77 RESULT eServiceFactoryDVD::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
85 DEFINE_REF(eServiceDVD);
87 eServiceDVD::eServiceDVD(eServiceReference ref):
88 m_ref(ref), m_ddvdconfig(ddvd_create()), m_subtitle_widget(0), m_state(stIdle),
89 m_current_trick(0), m_pump(eApp, 1), m_width(-1), m_height(-1),
90 m_aspect(-1), m_framerate(-1), m_progressive(-1)
92 int aspect = DDVD_16_9;
93 int policy = DDVD_PAN_SCAN;
94 int policy2 = DDVD_PAN_SCAN;
99 m_sn = eSocketNotifier::create(eApp, ddvd_get_messagepipe_fd(m_ddvdconfig), eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Error|eSocketNotifier::Hungup);
100 eDebug("SERVICEDVD construct!");
102 ddvd_set_dvd_path(m_ddvdconfig, ref.path.c_str());
103 ddvd_set_ac3thru(m_ddvdconfig, 0);
105 std::string ddvd_language;
106 if (!ePythonConfigQuery::getConfigValue("config.osd.language", ddvd_language))
107 ddvd_set_language(m_ddvdconfig, (ddvd_language.substr(0,2)).c_str());
109 int fd = open("/proc/stb/video/aspect", O_RDONLY);
112 rd = read(fd, tmp, 255);
113 if (rd > 2 && !strncmp(tmp, "4:3", 3))
115 else if (rd > 4 && !strncmp(tmp, "16:10", 5))
120 fd = open("/proc/stb/video/policy", O_RDONLY);
123 rd = read(fd, tmp, 255);
124 if (rd > 6 && !strncmp(tmp, "bestfit", 7))
125 policy = DDVD_JUSTSCALE;
126 else if (rd > 8 && !strncmp(tmp, "letterbox", 9))
127 policy = DDVD_LETTERBOX;
131 #ifdef DDVD_SUPPORTS_16_10_SCALING
132 fd = open("/proc/stb/video/policy2", O_RDONLY);
135 rd = read(fd, tmp, 255);
136 if (rd > 6 && !strncmp(tmp, "bestfit", 7))
137 policy2 = DDVD_JUSTSCALE;
138 else if (rd > 8 && !strncmp(tmp, "letterbox", 9))
139 policy2 = DDVD_LETTERBOX;
142 ddvd_set_video_ex(m_ddvdconfig, aspect, policy, policy2, DDVD_PAL /*unused*/);
144 ddvd_set_video(m_ddvdconfig, aspect, policy, DDVD_PAL /*unused*/);
145 #warning please update libdreamdvd for 16:10 scaling support!
148 CONNECT(m_sn->activated, eServiceDVD::gotMessage);
149 CONNECT(m_pump.recv_msg, eServiceDVD::gotThreadMessage);
150 strcpy(m_ddvd_titlestring,"");
155 void eServiceDVD::gotThreadMessage(const int &msg)
159 case 1: // thread stopped
161 m_event(this, evStopped);
166 void eServiceDVD::gotMessage(int /*what*/)
168 switch(ddvd_get_next_message(m_ddvdconfig,1))
170 case DDVD_COLORTABLE_UPDATE:
173 struct ddvd_color ctmp[4];
174 ddvd_get_last_colortable(ddvdconfig, ctmp);
178 rd1[252+i]=ctmp[i].red;
179 bl1[252+i]=ctmp[i].blue;
180 gn1[252+i]=ctmp[i].green;
181 tr1[252+i]=ctmp[i].trans;
184 if(ioctl(fb, FBIOPUTCMAP, &colormap) == -1)
186 printf("Framebuffer: <FBIOPUTCMAP failed>\n");
190 eDebug("no support for 8bpp framebuffer in dvdplayer yet!");
193 case DDVD_SCREEN_UPDATE:
194 eDebug("DVD_SCREEN_UPDATE!");
195 if (m_subtitle_widget) {
197 ddvd_get_last_blit_area(m_ddvdconfig, &x1, &x2, &y1, &y2);
199 int x_offset = 0, y_offset = 0, width = 720, height = 576;
201 #ifdef DDVD_SUPPORTS_GET_BLIT_DESTINATION
202 ddvd_get_blit_destination(m_ddvdconfig, &x_offset, &y_offset, &width, &height);
203 eDebug("values got from ddvd: %d %d %d %d", x_offset, y_offset, width, height);
204 y_offset = -y_offset;
205 width -= x_offset * 2;
206 height -= y_offset * 2;
208 eRect dest(x_offset, y_offset, width, height);
210 if (dest.width() && dest.height())
211 m_subtitle_widget->setPixmap(m_pixmap, eRect(x1, y1, (x2-x1)+1, (y2-y1)+1), dest);
214 case DDVD_SHOWOSD_STATE_PLAY:
216 eDebug("DVD_SHOWOSD_STATE_PLAY!");
218 m_event(this, evUser+1);
221 case DDVD_SHOWOSD_STATE_PAUSE:
223 eDebug("DVD_SHOWOSD_STATE_PAUSE!");
224 m_event(this, evUser+2);
227 case DDVD_SHOWOSD_STATE_FFWD:
229 eDebug("DVD_SHOWOSD_STATE_FFWD!");
230 m_event(this, evUser+3);
233 case DDVD_SHOWOSD_STATE_FBWD:
235 eDebug("DVD_SHOWOSD_STATE_FBWD!");
236 m_event(this, evUser+4);
239 case DDVD_SHOWOSD_STRING:
241 eDebug("DVD_SHOWOSD_STRING!");
242 m_event(this, evUser+5);
245 case DDVD_SHOWOSD_AUDIO:
247 eDebug("DVD_SHOWOSD_STRING!");
248 m_event(this, evUser+6);
251 case DDVD_SHOWOSD_SUBTITLE:
253 eDebug("DVD_SHOWOSD_SUBTITLE!");
254 m_event((iPlayableService*)this, evUpdatedInfo);
255 m_event(this, evUser+7);
258 case DDVD_EOF_REACHED:
259 eDebug("DVD_EOF_REACHED!");
260 m_event(this, evEOF);
262 case DDVD_SOF_REACHED:
263 eDebug("DVD_SOF_REACHED!");
264 m_event(this, evSOF);
266 case DDVD_SHOWOSD_ANGLE:
269 ddvd_get_angle_info(m_ddvdconfig, ¤t, &num);
270 eDebug("DVD_ANGLE_INFO: %d / %d", current, num);
271 m_event(this, evUser+13);
274 case DDVD_SHOWOSD_TIME:
276 static struct ddvd_time last_info;
277 struct ddvd_time info;
278 // eDebug("DVD_SHOWOSD_TIME!");
279 ddvd_get_last_time(m_ddvdconfig, &info);
280 if ( info.pos_chapter != last_info.pos_chapter )
281 m_event(this, evUser+8); // chapterUpdated
282 if ( info.pos_title != last_info.pos_title )
283 m_event(this, evUser+9); // titleUpdated
284 memcpy(&last_info, &info, sizeof(struct ddvd_time));
287 case DDVD_SHOWOSD_TITLESTRING:
289 ddvd_get_title_string(m_ddvdconfig, m_ddvd_titlestring);
290 eDebug("DDVD_SHOWOSD_TITLESTRING: %s",m_ddvd_titlestring);
294 m_event(this, evStart);
297 case DDVD_MENU_OPENED:
298 eDebug("DVD_MENU_OPENED!");
300 m_event(this, evSeekableStatusChanged);
301 m_event(this, evUser+11);
303 case DDVD_MENU_CLOSED:
304 eDebug("DVD_MENU_CLOSED!");
306 m_event(this, evSeekableStatusChanged);
307 m_event(this, evUser+12);
309 #ifdef DDVD_SUPPORTS_PICTURE_INFO
310 case DDVD_SIZE_CHANGED:
312 int changed = m_width != -1 && m_height != -1 && m_aspect != -1;
313 ddvd_get_last_size(m_ddvdconfig, &m_width, &m_height, &m_aspect);
315 m_event((iPlayableService*)this, evVideoSizeChanged);
318 case DDVD_PROGRESSIVE_CHANGED:
320 int changed = m_progressive != -1;
321 ddvd_get_last_progressive(m_ddvdconfig, &m_progressive);
323 m_event((iPlayableService*)this, evVideoProgressiveChanged);
326 case DDVD_FRAMERATE_CHANGED:
328 int changed = m_framerate != -1;
329 ddvd_get_last_framerate(m_ddvdconfig, &m_framerate);
331 m_event((iPlayableService*)this, evVideoFramerateChanged);
340 eServiceDVD::~eServiceDVD()
342 eDebug("SERVICEDVD destruct!");
345 ddvd_close(m_ddvdconfig);
349 RESULT eServiceDVD::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
351 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
355 RESULT eServiceDVD::start()
357 ASSERT(m_state == stIdle);
359 eDebug("eServiceDVD starting");
360 // m_event(this, evStart);
364 RESULT eServiceDVD::stop()
366 ASSERT(m_state != stIdle);
367 if (m_state == stStopped)
369 eDebug("DVD: stop %s", m_ref.path.c_str());
371 ddvd_send_key(m_ddvdconfig, DDVD_KEY_EXIT);
376 RESULT eServiceDVD::setTarget(int /*target*/)
381 RESULT eServiceDVD::pause(ePtr<iPauseableService> &ptr)
387 RESULT eServiceDVD::seek(ePtr<iSeekableService> &ptr)
393 RESULT eServiceDVD::subtitle(ePtr<iSubtitleOutput> &ptr)
399 RESULT eServiceDVD::keys(ePtr<iServiceKeys> &ptr)
406 RESULT eServiceDVD::setSlowMotion(int /*ratio*/)
411 RESULT eServiceDVD::setFastForward(int trick)
413 eDebug("setTrickmode(%d)", trick);
414 while (m_current_trick > trick && m_current_trick != -64)
416 ddvd_send_key(m_ddvdconfig, DDVD_KEY_FBWD);
417 if (m_current_trick == 0)
418 m_current_trick = -2;
419 else if (m_current_trick > 0)
421 m_current_trick /= 2;
422 if (abs(m_current_trick) == 1)
426 m_current_trick *= 2;
428 while (m_current_trick < trick && m_current_trick != 64)
430 ddvd_send_key(m_ddvdconfig, DDVD_KEY_FFWD);
431 if (m_current_trick == 0)
433 else if (m_current_trick < 0)
435 m_current_trick /= 2;
436 if (abs(m_current_trick) == 1)
440 m_current_trick *= 2;
445 RESULT eServiceDVD::pause()
447 eDebug("set pause!\n");
448 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PAUSE);
452 RESULT eServiceDVD::unpause()
454 eDebug("set unpause!\n");
455 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PLAY);
459 void eServiceDVD::thread()
461 eDebug("eServiceDVD dvd thread started");
463 ddvd_run(m_ddvdconfig);
466 void eServiceDVD::thread_finished()
468 eDebug("eServiceDVD dvd thread finished");
469 m_pump.send(1); // inform main thread
472 RESULT eServiceDVD::info(ePtr<iServiceInformation>&i)
478 RESULT eServiceDVD::getName(std::string &name)
480 if ( m_ddvd_titlestring[0] != '\0' )
481 name = m_ddvd_titlestring;
487 int eServiceDVD::getInfo(int w)
491 case sCurrentChapter:
493 struct ddvd_time info;
494 ddvd_get_last_time(m_ddvdconfig, &info);
495 return info.pos_chapter;
499 struct ddvd_time info;
500 ddvd_get_last_time(m_ddvdconfig, &info);
501 return info.end_chapter;
505 struct ddvd_time info;
506 ddvd_get_last_time(m_ddvdconfig, &info);
507 return info.pos_title;
511 struct ddvd_time info;
512 ddvd_get_last_time(m_ddvdconfig, &info);
513 return info.end_title;
515 case sTXTPID: // we abuse HAS_TELEXT icon in InfoBar to signalize subtitles status
519 ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
525 return resIsPyObject;
526 #ifdef DDVD_SUPPORTS_PICTURE_INFO
534 return m_progressive;
543 std::string eServiceDVD::getInfoString(int w)
548 return m_ref.toString();
550 eDebug("unhandled getInfoString(%d)", w);
555 PyObject *eServiceDVD::getInfoObject(int w)
561 ePyObject tuple = PyTuple_New(3);
562 int audio_id,audio_type;
564 ddvd_get_last_audio(m_ddvdconfig, &audio_id, &audio_lang, &audio_type);
565 char audio_string[3]={audio_lang >> 8, audio_lang, 0};
566 PyTuple_SetItem(tuple, 0, PyInt_FromLong(audio_id+1));
567 PyTuple_SetItem(tuple, 1, PyString_FromString(audio_string));
571 PyTuple_SetItem(tuple, 2, PyString_FromString("MPEG"));
574 PyTuple_SetItem(tuple, 2, PyString_FromString("AC3"));
577 PyTuple_SetItem(tuple, 2, PyString_FromString("DTS"));
580 PyTuple_SetItem(tuple, 2, PyString_FromString("LPCM"));
583 PyTuple_SetItem(tuple, 2, PyString_FromString(""));
589 ePyObject tuple = PyTuple_New(2);
592 ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
593 char spu_string[3]={spu_lang >> 8, spu_lang, 0};
596 PyTuple_SetItem(tuple, 0, PyInt_FromLong(0));
597 PyTuple_SetItem(tuple, 1, PyString_FromString(""));
601 PyTuple_SetItem(tuple, 0, PyInt_FromLong(spu_id+1));
602 PyTuple_SetItem(tuple, 1, PyString_FromString(spu_string));
608 ePyObject tuple = PyTuple_New(2);
610 ddvd_get_angle_info(m_ddvdconfig, ¤t, &num);
611 PyTuple_SetItem(tuple, 0, PyInt_FromLong(current));
612 PyTuple_SetItem(tuple, 1, PyInt_FromLong(num));
617 eDebug("unhandled getInfoObject(%d)", w);
622 RESULT eServiceDVD::enableSubtitles(eWidget *parent, SWIG_PYOBJECT(ePyObject) /*entry*/)
624 delete m_subtitle_widget;
626 m_subtitle_widget = new eSubtitleWidget(parent);
627 m_subtitle_widget->resize(parent->size());
629 eSize size = eSize(720, 576);
633 m_pixmap = new gPixmap(size, 32, 1); /* allocate accel surface (if possible) */
634 #ifdef DDVD_SUPPORTS_GET_BLIT_DESTINATION
635 ddvd_set_lfb_ex(m_ddvdconfig, (unsigned char *)m_pixmap->surface->data, size.width(), size.height(), 4, size.width()*4, 1);
637 ddvd_set_lfb(m_ddvdconfig, (unsigned char *)m_pixmap->surface->data, size.width(), size.height(), 4, size.width()*4);
638 #warning please update libdreamdvd for fast scaling
640 run(); // start the thread
643 m_subtitle_widget->setZPosition(-1);
644 m_subtitle_widget->show();
649 RESULT eServiceDVD::disableSubtitles(eWidget */*parent*/)
651 delete m_subtitle_widget;
652 m_subtitle_widget = 0;
656 PyObject *eServiceDVD::getSubtitleList()
658 eDebug("eServiceDVD::getSubtitleList nyi");
662 PyObject *eServiceDVD::getCachedSubtitle()
664 eDebug("eServiceDVD::getCachedSubtitle nyi");
668 RESULT eServiceDVD::getLength(pts_t &len)
670 // eDebug("eServiceDVD::getLength");
671 struct ddvd_time info;
672 ddvd_get_last_time(m_ddvdconfig, &info);
673 len = info.end_hours * 3600;
674 len += info.end_minutes * 60;
675 len += info.end_seconds;
680 RESULT eServiceDVD::seekTo(pts_t to)
682 eDebug("eServiceDVD::seekTo(%lld)",to);
685 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);
686 ddvd_set_resume_pos(m_ddvdconfig, m_resume_info);
691 RESULT eServiceDVD::seekRelative(int direction, pts_t to)
693 int seconds = to / 90000;
694 seconds *= direction;
695 eDebug("seekRelative %d %d", direction, seconds);
696 ddvd_skip_seconds(m_ddvdconfig, seconds);
700 RESULT eServiceDVD::getPlayPosition(pts_t &pos)
702 struct ddvd_time info;
703 ddvd_get_last_time(m_ddvdconfig, &info);
704 pos = info.pos_hours * 3600;
705 pos += info.pos_minutes * 60;
706 pos += info.pos_seconds;
707 // eDebug("getPlayPosition %lld", pos);
712 RESULT eServiceDVD::seekTitle(int title)
714 eDebug("setTitle %d", title);
715 ddvd_set_title(m_ddvdconfig, title);
719 RESULT eServiceDVD::seekChapter(int chapter)
721 eDebug("setChapter %d", chapter);
723 ddvd_set_chapter(m_ddvdconfig, chapter);
727 RESULT eServiceDVD::setTrickmode(int /*trick*/)
732 RESULT eServiceDVD::isCurrentlySeekable()
734 return m_state == stRunning ? 3 : 0;
737 RESULT eServiceDVD::keyPressed(int key)
741 case iServiceKeys::keyLeft:
742 ddvd_send_key(m_ddvdconfig, DDVD_KEY_LEFT);
744 case iServiceKeys::keyRight:
745 ddvd_send_key(m_ddvdconfig, DDVD_KEY_RIGHT);
747 case iServiceKeys::keyUp:
748 ddvd_send_key(m_ddvdconfig, DDVD_KEY_UP);
750 case iServiceKeys::keyDown:
751 ddvd_send_key(m_ddvdconfig, DDVD_KEY_DOWN);
753 case iServiceKeys::keyOk:
754 ddvd_send_key(m_ddvdconfig, DDVD_KEY_OK);
756 case iServiceKeys::keyUser:
757 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIO);
759 case iServiceKeys::keyUser+1:
760 ddvd_send_key(m_ddvdconfig, DDVD_KEY_SUBTITLE);
762 case iServiceKeys::keyUser+2:
763 ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIOMENU);
765 case iServiceKeys::keyUser+3:
766 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_CHAPTER);
768 case iServiceKeys::keyUser+4:
769 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_CHAPTER);
771 case iServiceKeys::keyUser+5:
772 ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_TITLE);
774 case iServiceKeys::keyUser+6:
775 ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_TITLE);
777 case iServiceKeys::keyUser+7:
778 ddvd_send_key(m_ddvdconfig, DDVD_KEY_MENU);
780 case iServiceKeys::keyUser+8:
781 ddvd_send_key(m_ddvdconfig, DDVD_KEY_ANGLE);
789 RESULT eServiceDVD::cueSheet(ePtr<iCueSheet> &ptr)
800 PyObject *eServiceDVD::getCutList()
802 ePyObject list = PyList_New(1);
803 ePyObject tuple = PyTuple_New(2);
804 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(m_cue_pts));
805 PyTuple_SetItem(tuple, 1, PyInt_FromLong(3));
806 PyList_SetItem(list, 0, tuple);
810 void eServiceDVD::setCutList(ePyObject /*list*/)
814 void eServiceDVD::setCutListEnable(int /*enable*/)
818 void eServiceDVD::loadCuesheet()
821 if ( m_ddvd_titlestring[0] != '\0' )
822 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
824 snprintf(filename, 128, "%s/dvd.cuts", m_ref.path.c_str());
826 eDebug("eServiceDVD::loadCuesheet() filename=%s",filename);
828 FILE *f = fopen(filename, "rb");
832 unsigned long long where;
835 if (!fread(&where, sizeof(where), 1, f))
837 if (!fread(&what, sizeof(what), 1, f))
839 #if BYTE_ORDER == LITTLE_ENDIAN
840 where = bswap_64(where);
844 if (!fread(&m_resume_info, sizeof(struct ddvd_resume), 1, f))
846 if (!fread(&what, sizeof(what), 1, f))
857 eDebug("cutfile not found!");
861 m_event((iPlayableService*)this, evCuesheetChanged);
862 eDebug("eServiceDVD::loadCuesheet() pts=%lld",m_cue_pts);
866 void eServiceDVD::saveCuesheet()
868 eDebug("eServiceDVD::saveCuesheet()");
870 struct ddvd_resume resume_info;
871 ddvd_get_resume_pos(m_ddvdconfig, &resume_info);
873 if (resume_info.title)
875 struct ddvd_time info;
876 ddvd_get_last_time(m_ddvdconfig, &info);
878 pos = info.pos_hours * 3600;
879 pos += info.pos_minutes * 60;
880 pos += info.pos_seconds;
883 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);
887 eDebug("we're in a menu or somewhere else funny. so save cuesheet with pts=0");
892 if ( m_ddvd_titlestring[0] != '\0' )
893 snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
895 snprintf(filename, 128, "%s/dvd.cuts", m_ref.path.c_str());
897 FILE *f = fopen(filename, "wb");
901 unsigned long long where;
904 #if BYTE_ORDER == BIG_ENDIAN
907 where = bswap_64(m_cue_pts);
910 fwrite(&where, sizeof(where), 1, f);
911 fwrite(&what, sizeof(what), 1, f);
914 fwrite(&resume_info, sizeof(struct ddvd_resume), 1, f);
915 fwrite(&what, sizeof(what), 1, f);
921 eAutoInitPtr<eServiceFactoryDVD> init_eServiceFactoryDVD(eAutoInitNumbers::service+1, "eServiceFactoryDVD");
926 Py_InitModule("servicedvd", NULL);