/* yes, it's dvd */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BYTE_ORDER #error no byte order defined! #endif extern "C" { #include } #include "servicedvd.h" // eServiceFactoryDVD eServiceFactoryDVD::eServiceFactoryDVD() { ePtr sc; eServiceCenter::getPrivInstance(sc); if (sc) { std::list extensions; extensions.push_back("iso"); sc->addServiceFactory(eServiceFactoryDVD::id, this, extensions); } } eServiceFactoryDVD::~eServiceFactoryDVD() { ePtr sc; eServiceCenter::getPrivInstance(sc); if (sc) sc->removeServiceFactory(eServiceFactoryDVD::id); } DEFINE_REF(eServiceFactoryDVD) // iServiceHandler RESULT eServiceFactoryDVD::play(const eServiceReference &ref, ePtr &ptr) { // check resources... ptr = new eServiceDVD(ref.path.c_str()); return 0; } RESULT eServiceFactoryDVD::record(const eServiceReference &/*ref*/, ePtr &ptr) { ptr=0; return -1; } RESULT eServiceFactoryDVD::list(const eServiceReference &, ePtr &ptr) { ptr=0; return -1; } RESULT eServiceFactoryDVD::info(const eServiceReference &/*ref*/, ePtr &ptr) { ptr=0; return -1; } RESULT eServiceFactoryDVD::offlineOperations(const eServiceReference &, ePtr &ptr) { ptr = 0; return -1; } // eServiceDVD DEFINE_REF(eServiceDVD); eServiceDVD::eServiceDVD(const char *filename): m_filename(filename), m_ddvdconfig(ddvd_create()), m_subtitle_widget(0), m_state(stIdle), m_current_trick(0), m_pump(eApp, 1) { int aspect = DDVD_16_9; int policy = DDVD_PAN_SCAN; char tmp[255]; ssize_t rd; m_sn = eSocketNotifier::create(eApp, ddvd_get_messagepipe_fd(m_ddvdconfig), eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Error|eSocketNotifier::Hungup); eDebug("SERVICEDVD construct!"); // create handle ddvd_set_dvd_path(m_ddvdconfig, filename); ddvd_set_ac3thru(m_ddvdconfig, 0); ddvd_set_language(m_ddvdconfig, "de"); int fd = open("/proc/stb/video/aspect", O_RDONLY); if (fd > -1) { rd = read(fd, tmp, 255); if (rd > 2 && !strncmp(tmp, "4:3", 3)) aspect = DDVD_4_3; else if (rd > 4 && !strncmp(tmp, "16:10", 5)) aspect = DDVD_16_10; close(fd); } fd = open("/proc/stb/video/policy", O_RDONLY); if (fd > -1) { rd = read(fd, tmp, 255); if (rd > 6 && !strncmp(tmp, "bestfit", 7)) policy = DDVD_JUSTSCALE; else if (rd > 8 && !strncmp(tmp, "letterbox", 9)) policy = DDVD_LETTERBOX; close(fd); } ddvd_set_video(m_ddvdconfig, aspect, policy, DDVD_PAL /*unused*/); CONNECT(m_sn->activated, eServiceDVD::gotMessage); CONNECT(m_pump.recv_msg, eServiceDVD::gotThreadMessage); strcpy(m_ddvd_titlestring,""); m_cue_pts = 0; pause(); } void eServiceDVD::gotThreadMessage(const int &msg) { switch(msg) { case 1: // thread stopped m_state = stStopped; m_event(this, evStopped); break; } } void eServiceDVD::gotMessage(int /*what*/) { switch(ddvd_get_next_message(m_ddvdconfig,1)) { case DDVD_COLORTABLE_UPDATE: { /* struct ddvd_color ctmp[4]; ddvd_get_last_colortable(ddvdconfig, ctmp); int i=0; while (i < 4) { rd1[252+i]=ctmp[i].red; bl1[252+i]=ctmp[i].blue; gn1[252+i]=ctmp[i].green; tr1[252+i]=ctmp[i].trans; i++; } if(ioctl(fb, FBIOPUTCMAP, &colormap) == -1) { printf("Framebuffer: \n"); return 1; } */ eDebug("no support for 8bpp framebuffer in dvdplayer yet!"); break; } case DDVD_SCREEN_UPDATE: eDebug("DVD_SCREEN_UPDATE!"); if (m_subtitle_widget) { int x1,x2,y1,y2; ddvd_get_last_blit_area(m_ddvdconfig, &x1, &x2, &y1, &y2); m_subtitle_widget->setPixmap(m_pixmap, eRect(x1, y1, (x2-x1)+1, (y2-y1)+1)); } break; case DDVD_SHOWOSD_STATE_PLAY: { eDebug("DVD_SHOWOSD_STATE_PLAY!"); m_current_trick = 0; m_event(this, evUser+1); break; } case DDVD_SHOWOSD_STATE_PAUSE: { eDebug("DVD_SHOWOSD_STATE_PAUSE!"); m_event(this, evUser+2); break; } case DDVD_SHOWOSD_STATE_FFWD: { eDebug("DVD_SHOWOSD_STATE_FFWD!"); m_event(this, evUser+3); break; } case DDVD_SHOWOSD_STATE_FBWD: { eDebug("DVD_SHOWOSD_STATE_FBWD!"); m_event(this, evUser+4); break; } case DDVD_SHOWOSD_STRING: { eDebug("DVD_SHOWOSD_STRING!"); m_event(this, evUser+5); break; } case DDVD_SHOWOSD_AUDIO: { eDebug("DVD_SHOWOSD_STRING!"); m_event(this, evUser+6); break; } case DDVD_SHOWOSD_SUBTITLE: { eDebug("DVD_SHOWOSD_SUBTITLE!"); m_event((iPlayableService*)this, evUpdatedInfo); m_event(this, evUser+7); break; } case DDVD_EOF_REACHED: eDebug("DVD_EOF_REACHED!"); m_event(this, evEOF); break; case DDVD_SOF_REACHED: eDebug("DVD_SOF_REACHED!"); m_event(this, evSOF); break; case DDVD_SHOWOSD_ANGLE: { int current, num; ddvd_get_angle_info(m_ddvdconfig, ¤t, &num); eDebug("DVD_ANGLE_INFO: %d / %d", current, num); m_event(this, evUser+13); break; } case DDVD_SHOWOSD_TIME: { static struct ddvd_time last_info; struct ddvd_time info; // eDebug("DVD_SHOWOSD_TIME!"); ddvd_get_last_time(m_ddvdconfig, &info); if ( info.pos_chapter != last_info.pos_chapter ) m_event(this, evUser+8); // chapterUpdated if ( info.pos_title != last_info.pos_title ) m_event(this, evUser+9); // titleUpdated memcpy(&last_info, &info, sizeof(struct ddvd_time)); break; } case DDVD_SHOWOSD_TITLESTRING: { ddvd_get_title_string(m_ddvdconfig, m_ddvd_titlestring); eDebug("DDVD_SHOWOSD_TITLESTRING: %s",m_ddvd_titlestring); loadCuesheet(); if (!m_cue_pts) unpause(); m_event(this, evStart); break; } case DDVD_MENU_OPENED: eDebug("DVD_MENU_OPENED!"); m_state = stMenu; m_event(this, evSeekableStatusChanged); m_event(this, evUser+11); break; case DDVD_MENU_CLOSED: eDebug("DVD_MENU_CLOSED!"); m_state = stRunning; m_event(this, evSeekableStatusChanged); m_event(this, evUser+12); break; default: break; } } eServiceDVD::~eServiceDVD() { eDebug("SERVICEDVD destruct!"); kill(); saveCuesheet(); ddvd_close(m_ddvdconfig); disableSubtitles(0); } RESULT eServiceDVD::connectEvent(const Slot2 &event, ePtr &connection) { connection = new eConnection((iPlayableService*)this, m_event.connect(event)); return 0; } RESULT eServiceDVD::start() { assert(m_state == stIdle); m_state = stRunning; eDebug("eServiceDVD starting"); // m_event(this, evStart); return 0; } RESULT eServiceDVD::stop() { assert(m_state != stIdle); if (m_state == stStopped) return -1; eDebug("DVD: stop %s", m_filename.c_str()); m_state = stStopped; ddvd_send_key(m_ddvdconfig, DDVD_KEY_EXIT); return 0; } RESULT eServiceDVD::setTarget(int /*target*/) { return -1; } RESULT eServiceDVD::pause(ePtr &ptr) { ptr=this; return 0; } RESULT eServiceDVD::seek(ePtr &ptr) { ptr=this; return 0; } RESULT eServiceDVD::subtitle(ePtr &ptr) { ptr=this; return 0; } RESULT eServiceDVD::keys(ePtr &ptr) { ptr=this; return 0; } // iPausableService RESULT eServiceDVD::setSlowMotion(int /*ratio*/) { return -1; } RESULT eServiceDVD::setFastForward(int trick) { eDebug("setTrickmode(%d)", trick); while (m_current_trick > trick && m_current_trick != -64) { ddvd_send_key(m_ddvdconfig, DDVD_KEY_FBWD); if (m_current_trick == 0) m_current_trick = -2; else if (m_current_trick > 0) { m_current_trick /= 2; if (abs(m_current_trick) == 1) m_current_trick=0; } else m_current_trick *= 2; } while (m_current_trick < trick && m_current_trick != 64) { ddvd_send_key(m_ddvdconfig, DDVD_KEY_FFWD); if (m_current_trick == 0) m_current_trick = 2; else if (m_current_trick < 0) { m_current_trick /= 2; if (abs(m_current_trick) == 1) m_current_trick=0; } else m_current_trick *= 2; } return 0; } RESULT eServiceDVD::pause() { eDebug("set pause!\n"); ddvd_send_key(m_ddvdconfig, DDVD_KEY_PAUSE); return 0; } RESULT eServiceDVD::unpause() { eDebug("set unpause!\n"); ddvd_send_key(m_ddvdconfig, DDVD_KEY_PLAY); return 0; } void eServiceDVD::thread() { eDebug("eServiceDVD dvd thread started"); hasStarted(); ddvd_run(m_ddvdconfig); } void eServiceDVD::thread_finished() { eDebug("eServiceDVD dvd thread finished"); m_pump.send(1); // inform main thread } RESULT eServiceDVD::info(ePtr&i) { i = this; return 0; } RESULT eServiceDVD::getName(std::string &name) { if ( m_ddvd_titlestring[0] != '\0' ) name = m_ddvd_titlestring; else name = m_filename; return 0; } int eServiceDVD::getInfo(int w) { switch (w) { case sCurrentChapter: { struct ddvd_time info; ddvd_get_last_time(m_ddvdconfig, &info); return info.pos_chapter; } case sTotalChapters: { struct ddvd_time info; ddvd_get_last_time(m_ddvdconfig, &info); return info.end_chapter; } case sCurrentTitle: { struct ddvd_time info; ddvd_get_last_time(m_ddvdconfig, &info); return info.pos_title; } case sTotalTitles: { struct ddvd_time info; ddvd_get_last_time(m_ddvdconfig, &info); return info.end_title; } case sTXTPID: // we abuse HAS_TELEXT icon in InfoBar to signalize subtitles status { int spu_id; uint16_t spu_lang; ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang); return spu_id; } case sUser+6: case sUser+7: case sUser+8: return resIsPyObject; default: return resNA; } } std::string eServiceDVD::getInfoString(int w) { switch(w) { case sServiceref: break; default: eDebug("unhandled getInfoString(%d)", w); } return ""; } PyObject *eServiceDVD::getInfoObject(int w) { switch(w) { case sUser+6: { ePyObject tuple = PyTuple_New(3); int audio_id,audio_type; uint16_t audio_lang; ddvd_get_last_audio(m_ddvdconfig, &audio_id, &audio_lang, &audio_type); char audio_string[3]={audio_lang >> 8, audio_lang, 0}; PyTuple_SetItem(tuple, 0, PyInt_FromLong(audio_id+1)); PyTuple_SetItem(tuple, 1, PyString_FromString(audio_string)); switch(audio_type) { case DDVD_MPEG: PyTuple_SetItem(tuple, 2, PyString_FromString("MPEG")); break; case DDVD_AC3: PyTuple_SetItem(tuple, 2, PyString_FromString("AC3")); break; case DDVD_DTS: PyTuple_SetItem(tuple, 2, PyString_FromString("DTS")); break; case DDVD_LPCM: PyTuple_SetItem(tuple, 2, PyString_FromString("LPCM")); break; default: PyTuple_SetItem(tuple, 2, PyString_FromString("")); } return tuple; } case sUser+7: { ePyObject tuple = PyTuple_New(2); int spu_id; uint16_t spu_lang; ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang); char spu_string[3]={spu_lang >> 8, spu_lang, 0}; if (spu_id == -1) { PyTuple_SetItem(tuple, 0, PyInt_FromLong(0)); PyTuple_SetItem(tuple, 1, PyString_FromString("")); } else { PyTuple_SetItem(tuple, 0, PyInt_FromLong(spu_id+1)); PyTuple_SetItem(tuple, 1, PyString_FromString(spu_string)); } return tuple; } case sUser+8: { ePyObject tuple = PyTuple_New(2); int current, num; ddvd_get_angle_info(m_ddvdconfig, ¤t, &num); PyTuple_SetItem(tuple, 0, PyInt_FromLong(current)); PyTuple_SetItem(tuple, 1, PyInt_FromLong(num)); return tuple; } default: eDebug("unhandled getInfoObject(%d)", w); } Py_RETURN_NONE; } RESULT eServiceDVD::enableSubtitles(eWidget *parent, SWIG_PYOBJECT(ePyObject) /*entry*/) { delete m_subtitle_widget; m_subtitle_widget = new eSubtitleWidget(parent); m_subtitle_widget->resize(parent->size()); eSize size = parent->size(); if (!m_pixmap) { m_pixmap = new gPixmap(size, 32); ddvd_set_lfb(m_ddvdconfig, (unsigned char *)m_pixmap->surface->data, size.width(), size.height(), 4, size.width()*4); run(); // start the thread } m_subtitle_widget->setZPosition(-1); m_subtitle_widget->show(); return 0; } RESULT eServiceDVD::disableSubtitles(eWidget */*parent*/) { delete m_subtitle_widget; m_subtitle_widget = 0; return 0; } PyObject *eServiceDVD::getSubtitleList() { eDebug("eServiceDVD::getSubtitleList nyi"); Py_RETURN_NONE; } PyObject *eServiceDVD::getCachedSubtitle() { eDebug("eServiceDVD::getCachedSubtitle nyi"); Py_RETURN_NONE; } RESULT eServiceDVD::getLength(pts_t &len) { // eDebug("eServiceDVD::getLength"); struct ddvd_time info; ddvd_get_last_time(m_ddvdconfig, &info); len = info.end_hours * 3600; len += info.end_minutes * 60; len += info.end_seconds; len *= 90000; return 0; } RESULT eServiceDVD::seekTo(pts_t to) { eDebug("eServiceDVD::seekTo(%lld)",to); if ( to > 0 ) { 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); ddvd_set_resume_pos(m_ddvdconfig, m_resume_info); } return 0; } RESULT eServiceDVD::seekRelative(int direction, pts_t to) { int seconds = to / 90000; seconds *= direction; eDebug("seekRelative %d %d", direction, seconds); ddvd_skip_seconds(m_ddvdconfig, seconds); return 0; } RESULT eServiceDVD::getPlayPosition(pts_t &pos) { struct ddvd_time info; ddvd_get_last_time(m_ddvdconfig, &info); pos = info.pos_hours * 3600; pos += info.pos_minutes * 60; pos += info.pos_seconds; // eDebug("getPlayPosition %lld", pos); pos *= 90000; return 0; } RESULT eServiceDVD::seekTitle(int title) { eDebug("setTitle %d", title); ddvd_set_title(m_ddvdconfig, title); return 0; } RESULT eServiceDVD::seekChapter(int chapter) { eDebug("setChapter %d", chapter); if ( chapter > 0 ) ddvd_set_chapter(m_ddvdconfig, chapter); return 0; } RESULT eServiceDVD::setTrickmode(int /*trick*/) { return -1; } RESULT eServiceDVD::isCurrentlySeekable() { return m_state == stRunning; } RESULT eServiceDVD::keyPressed(int key) { switch(key) { case iServiceKeys::keyLeft: ddvd_send_key(m_ddvdconfig, DDVD_KEY_LEFT); break; case iServiceKeys::keyRight: ddvd_send_key(m_ddvdconfig, DDVD_KEY_RIGHT); break; case iServiceKeys::keyUp: ddvd_send_key(m_ddvdconfig, DDVD_KEY_UP); break; case iServiceKeys::keyDown: ddvd_send_key(m_ddvdconfig, DDVD_KEY_DOWN); break; case iServiceKeys::keyOk: ddvd_send_key(m_ddvdconfig, DDVD_KEY_OK); break; case iServiceKeys::keyUser: ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIO); break; case iServiceKeys::keyUser+1: ddvd_send_key(m_ddvdconfig, DDVD_KEY_SUBTITLE); break; case iServiceKeys::keyUser+2: ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIOMENU); break; case iServiceKeys::keyUser+3: ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_CHAPTER); break; case iServiceKeys::keyUser+4: ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_CHAPTER); break; case iServiceKeys::keyUser+5: ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_TITLE); break; case iServiceKeys::keyUser+6: ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_TITLE); break; case iServiceKeys::keyUser+7: ddvd_send_key(m_ddvdconfig, DDVD_KEY_MENU); break; case iServiceKeys::keyUser+8: ddvd_send_key(m_ddvdconfig, DDVD_KEY_ANGLE); break; default: return -1; } return 0; } RESULT eServiceDVD::cueSheet(ePtr &ptr) { if (m_cue_pts) { ptr = this; return 0; } ptr = 0; return -1; } PyObject *eServiceDVD::getCutList() { ePyObject list = PyList_New(1); ePyObject tuple = PyTuple_New(2); PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(m_cue_pts)); PyTuple_SetItem(tuple, 1, PyInt_FromLong(3)); PyList_SetItem(list, 0, tuple); return list; } void eServiceDVD::setCutList(ePyObject /*list*/) { } void eServiceDVD::setCutListEnable(int /*enable*/) { } void eServiceDVD::loadCuesheet() { char filename[128]; if ( m_ddvd_titlestring[0] != '\0' ) snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring); else snprintf(filename, 128, "%s/dvd.cuts", m_filename.c_str()); eDebug("eServiceDVD::loadCuesheet() filename=%s",filename); FILE *f = fopen(filename, "rb"); if (f) { unsigned long long where; unsigned int what; if (!fread(&where, sizeof(where), 1, f)) return; if (!fread(&what, sizeof(what), 1, f)) return; #if BYTE_ORDER == LITTLE_ENDIAN where = bswap_64(where); #endif what = ntohl(what); if (!fread(&m_resume_info, sizeof(struct ddvd_resume), 1, f)) return; if (!fread(&what, sizeof(what), 1, f)) return; what = ntohl(what); if (what != 4 ) return; m_cue_pts = where; fclose(f); } else eDebug("cutfile not found!"); if (m_cue_pts) { m_event((iPlayableService*)this, evCuesheetChanged); eDebug("eServiceDVD::loadCuesheet() pts=%lld",m_cue_pts); } } void eServiceDVD::saveCuesheet() { eDebug("eServiceDVD::saveCuesheet()"); struct ddvd_resume resume_info; ddvd_get_resume_pos(m_ddvdconfig, &resume_info); if (resume_info.title) { struct ddvd_time info; ddvd_get_last_time(m_ddvdconfig, &info); pts_t pos; pos = info.pos_hours * 3600; pos += info.pos_minutes * 60; pos += info.pos_seconds; pos *= 90000; m_cue_pts = pos; 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); } else { eDebug("we're in a menu or somewhere else funny. so save cuesheet with pts=0"); m_cue_pts = 0; } char filename[128]; if ( m_ddvd_titlestring[0] != '\0' ) snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring); else snprintf(filename, 128, "%s/dvd.cuts", m_filename.c_str()); FILE *f = fopen(filename, "wb"); if (f) { unsigned long long where; int what; #if BYTE_ORDER == BIG_ENDIAN where = m_cue_pts; #else where = bswap_64(m_cue_pts); #endif what = htonl(3); fwrite(&where, sizeof(where), 1, f); fwrite(&what, sizeof(what), 1, f); what = htonl(4); fwrite(&resume_info, sizeof(struct ddvd_resume), 1, f); fwrite(&what, sizeof(what), 1, f); fclose(f); } } eAutoInitPtr init_eServiceFactoryDVD(eAutoInitNumbers::service+1, "eServiceFactoryDVD"); PyMODINIT_FUNC initservicedvd(void) { Py_InitModule("servicedvd", NULL); }