/* * Image plugin to VDR (C++) * * (C) 2004-2005 Andreas Brachold * based on (C) 2003 Kai Tobias Burwieck * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include "control-image.h" #include "data-image.h" #include "setup-image.h" #include "config.h" #include "list.h" #include "bitmap.h" //#include //#include #include #include //#include //#define X_DISPLAY_MISSING //#include //using namespace Magick; //#include ////////////////////////////////////////////////////////////////////////////// /** C-tor Create for control-object to control the image-player */ cImageControl::cImageControl() :cOsdObject() ,pBrowser(NULL) ,pCommands(NULL) { if(ImageSetup.MuteAudio) { volume = cDevice::PrimaryDevice()->CurrentVolume(); cDevice::PrimaryDevice()->SetVolume(0, true); } m_tStarted = time(NULL); m_bSlideShowActiv = ImageSetup.m_bSlideShow; picturesize = 0; newheight= 0; newwidth = 0; rotate = 0; ImageSetup.rotate = 0; ImageSetup.save = false; visible=musicplays=false; CanLoadCover=false; osd = NULL; Layer0Pixmap = NULL; Layer1Pixmap = NULL; Layer2Pixmap = NULL; } void cImageControl::SetSlideShow(cSlideShow * pNewSlideShow) { theSlideShow.Assign(pNewSlideShow); } ////////////////////////////////////////////////////////////////////////////// /** D-tor Destroy control-object to control the image-player */ cImageControl::~cImageControl() { // Free OSD Data theSlideShow.Shutdown(); if(pBrowser) { delete pBrowser; pBrowser=NULL; } if(pCommands) { delete pCommands; pCommands=NULL; } Layer0Pixmap = NULL; Layer1Pixmap = NULL; Layer2Pixmap = NULL; if(ImageSetup.MuteAudio) { cDevice::PrimaryDevice()->SetVolume(volume, true); } Hide(); } void cImageControl::Hide() { if(osd) { delete osd; osd=NULL; } visible = false; } ////////////////////////////////////////////////////////////////////////////// /** LOAD PICTURE */ void cImageControl::LoadPicture(void) { cImageloadBitmap *picture; if((picture = cImageloadBitmap::Load(FileName(), w, h, true, rotate)) != NULL) { newwidth = picture->newWidth(); newheight = picture->newHeight(); int posx = ( w - newwidth) / 2; int posy = ( h - newheight) / 2; #ifdef BUGHUNT printf("width : %i\n",newwidth); printf("height : %i\n",newheight); printf("posx : %i\n",posx); printf("posy : %i\n",posy); #endif if (effect == 2) { #ifdef BUGHUNT printf("Crossfade : Copy Layer 2 to Layer 1\n"); #endif Layer1Pixmap->Clear(); Layer1Pixmap->Copy(Layer2Pixmap, cRect(0,0,w,h) , cPoint(0,0) ); #ifdef BUGHUNT printf("Crossfade : DrawImage on Layer 2\n"); #endif Layer2Pixmap->Clear(); Layer2Pixmap->DrawImage(cPoint(posx, posy), picture->Get()); } else { #ifdef BUGHUNT printf("Normal/Fadein-out : DrawImage on Layer 1\n"); #endif Layer1Pixmap->Clear(); Layer1Pixmap->DrawImage(cPoint(posx, posy), picture->Get()); } } } ////////////////////////////////////////////////////////////////////////////// /** BUILD AREAS */ bool cImageControl::BuildAreas(void) { int res; res = false; if (FileName()== NULL ) { esyslog("picselshow : Oops can't load image : %s\n",FileName()); } else { tArea Area[] = {{ 0, 0, w -1, h -1, depth}, }; eOsdError result = osd->CanHandleAreas(Area, sizeof(Area) / sizeof(Area)); if (result == oeOk) { osd->SetAreas(Area, sizeof(Area) / sizeof(Area)); res = true; } else { const char *errormsg = NULL; switch (result) { case oeTooManyAreas: errormsg = "Too many OSD areas"; break; case oeTooManyColors: errormsg = "Too many colors"; break; case oeBppNotSupported: errormsg = "Depth not supported"; break; case oeAreasOverlap: errormsg = "Areas are overlapped"; break; case oeWrongAlignment: errormsg = "Areas not correctly aligned"; break; case oeOutOfMemory: errormsg = "OSD memory overflow"; break; case oeUnknown: errormsg = "Unknown OSD error"; break; default: break; } esyslog("picselshow: ERROR! OSD open failed! Can't handle areas (%d)-%s\n", result, errormsg); if(osd) { Hide(); } } } return res; } ////////////////////////////////////////////////////////////////////////////// /** BUILD PIXMAPS */ void cImageControl::BuildDefault(void) { #ifdef BUGHUNT printf("Build default\n"); #endif Layer0Pixmap = NULL; Layer1Pixmap = NULL; Layer2Pixmap = NULL; if (!Layer0Pixmap) { #ifdef BUGHUNT printf("Layer0Pixmap not exists: Creating now\n"); #endif Layer0Pixmap = osd->CreatePixmap(0, cRect(0, 0, w , h )); // Layer0Pixmap->Clear(); Layer0Pixmap->Fill(clrBlack); } if (!Layer1Pixmap) { #ifdef BUGHUNT printf("Layer1Pixmap not exists: Creating now\n"); #endif Layer1Pixmap = osd->CreatePixmap(1, cRect(0, 0, w , h )); Layer1Pixmap->Clear(); } if (!Layer2Pixmap) { #ifdef BUGHUNT printf("Layer2Pixmap not exists: Creating now\n"); #endif Layer2Pixmap = osd->CreatePixmap(2, cRect(0, 0, w , h )); Layer2Pixmap->Clear(); } #ifdef BUGHUNT printf("Default built\n"); #endif } ////////////////////////////////////////////////////////////////////////////// /** SHOW */ void cImageControl::Show() { effect = ImageSetup.Effect; picturesize=ImageSetup.PictureSize; CanLoadCover=true; if (!osd) { w=640; h=480; depth=8; switch(picturesize) { case 0: w = 640; h = 480; depth = 32; break; case 1: w = 768; h = 576; depth = 32; break; case 2: w = 1280; h = 720; depth = 32; break; case 3: w = 1920; h = 1080; depth = 32; break; case 4: w = ImageSetup.max_osdwidth; h = ImageSetup.max_osdheight; depth = 32; break; } // osd=cOsdProvider::NewOsd(Setup.OSDLeft + ((Setup.OSDWidth /2) - (w/2)), Setup.OSDTop + ((Setup.OSDHeight /2) - (h/2)), 19); osd=cOsdProvider::NewOsd(ImageSetup.OffsetLeft, ImageSetup.OffsetTop, 19); if (BuildAreas()) BuildDefault(); else { esyslog("picselshow: ERROR: Cannot build areas -> ABORT"); return; } } if(CanLoadCover) { #ifdef BUGHUNT Start = cTimeMs::Now(); #endif // Layer1Pixmap->Clear(); #ifdef BUGHUNT printf("LoadPicture\n"); #endif //Draw image LoadPicture(); CanLoadCover = false; m_tStarted = time(NULL); switch(effect) { case 0: #ifdef BUGHUNT printf("None effect\n"); #endif Flush(); break; case 1: #ifdef BUGHUNT printf("Fading\n"); #endif FadeIn(); break; case 2: #ifdef BUGHUNT printf("Crossfade\n"); #endif CrossFade(); break; default: Flush(); } } ImageSetup.rotate = 0; ImageSetup.save = false; } void cImageControl::Flush(void) { if(osd) osd->Flush(); } ////////////////////////////////////////////////////////////////////////////// /** VDR-Callback entry for Key was processed @return eOSState @param eKeys Key - the processed Keycode */ eOSState cImageControl::ProcessKey(eKeys Key) { if(pBrowser) { eOSState eOSRet = pBrowser->ProcessKey(Key); switch(eOSRet) { case osBack: delete pBrowser; pBrowser = NULL; visible =false; Show(); return osContinue; default: return eOSRet; } } else if(pCommands) { eOSState eOSRet = pCommands->ProcessKey(Key); switch(eOSRet) { case osBack: delete pCommands; pCommands = NULL; visible =false; Show(); return osContinue; default: return eOSRet; } } else { // check for next image SlideImage(); eOSState state = cOsdObject::ProcessKey(Key); if(state==osUnknown) { switch(Key) { //processed global keybindings // Toggle between Play/Pause case kPlay: case kPause: ToogleSlideShowActiv(); break; // Stop Plugin case kBack: case kStop: return osEnd; // Change time how long image is see case k1|k_Repeat: case k1: DecSlideTime(); break; case k3|k_Repeat: case k3: IncSlideTime(); break; // Navigate between images case kLeft: case kGreen: if( m_bSlideShowActiv && ImageTotal() >0) { PrevImage(1); CanLoadCover = true; Show(); } break; case kRight: case kYellow: if( m_bSlideShowActiv && ImageTotal() >0) { NextImage(1); CanLoadCover = true; Show(); } break; case kOk: Hide(); pBrowser = new cMenuImageBrowse(); break; case kRed: Hide(); pCommands = new cMenuMP3Playlist(); break; case kBlue: if(ImageSetup.AutoMusic && !musicplays) { PlayMusic(); musicplays = true; } break; case kDown: if( m_bSlideShowActiv && ImageTotal() >0) { PrevImage(3); // rotate =1; CanLoadCover = true; Show(); } break; case kUp: if( m_bSlideShowActiv && ImageTotal() >0) { NextImage(3); // rotate =0; CanLoadCover = true; Show(); } break; default: break; } state = osContinue; } return state; } } ////////////////////////////////////////////////////////////////////////////// /** Toogle between Play and Stop of the current SlideShow */ void cImageControl::ToogleSlideShowActiv(void) { m_bSlideShowActiv = !m_bSlideShowActiv; } ////////////////////////////////////////////////////////////////////////////// /** Check to get access for to viewed file @return bool - false access was denied */ bool cImageControl::CheckAccess() const { const char *szFileName = FileName(); if(szFileName && 0 == access(szFileName,F_OK)) { return true; } return false; } void cImageControl::OriginalImage(bool bCached) { if(!CheckAccess()) { esyslog("picselshow: Operation failed"); } } void cImageControl::NextImage(int Step) { theSlideShow.NextImage(Step); OriginalImage(true); } void cImageControl::PrevImage(int Step) { theSlideShow.PrevImage(Step); OriginalImage(true); } void cImageControl::GotoImage(unsigned int Pict) { theSlideShow.GotoImage(Pict); OriginalImage(true); } int cImageControl::ImageTotal(void) const { return theSlideShow.ImageTotal(); } int cImageControl::ImageCurrent(void) const { return theSlideShow.ImageCurrent(); } const char* cImageControl::FileName(void) const { std::string datei; datei = PluginConfig_Path().c_str(); datei = datei + "/moronsuite/picselshow/images/splash.png"; if(ImageTotal() > 0) { cPicture* pImage = theSlideShow.GetImage(); return pImage?pImage->Name():NULL; } else { return datei.c_str(); } } void cImageControl::SlideImage() { if( m_bSlideShowActiv && ImageTotal() >0 ) { if(ImageSetup.m_nSSsec <= (time(NULL) - m_tStarted)) { CanLoadCover = true; if(ImageSetup.Effect == 1) FadeOut(); NextImage(1); Show(); } } } void cImageControl::PlayMusic() { std::string plugindir; plugindir = ImageSetup.MusicDir; plugindir = plugindir + "/"; char *buffer; ServiceID="Music-Play-v1"; ServiceAvailable=cPluginManager::CallFirstService(*ServiceID, NULL); if(!ServiceAvailable) { esyslog("picselshow: ERROR: could not reach Music-Play-v1"); } else { MP3ServiceData ServiceData; asprintf(&buffer, "%s%s",plugindir.c_str(), "Slideshow.m3u" ); ServiceData.data.filename=buffer; if(cPluginManager::CallFirstService(ServiceID, &ServiceData)) { if(!ServiceData.result) { esyslog("picselshow: ERROR: couldn't load playlist !"); } } free(buffer); buffer=0; } } void cImageControl::IncSlideTime(void) { if(ImageSetup.m_nSSsec < cImageSetup::m_cSSMax) { ImageSetup.m_nSSsec++; } } void cImageControl::DecSlideTime(void) { if(ImageSetup.m_nSSsec > cImageSetup::m_cSSMin) { ImageSetup.m_nSSsec--; } } /* void cImageControl::FadeIn(void) { // SetNeedsFastResponse(true); int alpha = 0; int fd = 16; while (!(fd==0)) { if (Layer1Pixmap && osd) { alpha = alpha + 16; if (alpha > 255) alpha = 255; #ifdef BUGHUNT printf("fd = %i , alpha = %i\n",fd,alpha); #endif Layer1Pixmap->SetAlpha(alpha); Flush(); } fd--; } // Flush(); // SetNeedsFastResponse(false); } */ void cImageControl::FadeIn(void) { int alpha; for (int i=1; i < 9 ; i++) { alpha = (i*32); if(alpha >255) alpha = 255; #ifdef BUGHUNT printf("fadein i= %d\n", alpha); #endif Layer1Pixmap->SetAlpha(alpha); osd->Flush(); } } void cImageControl::FadeOut(void) { int alpha; for (int i=1; i < 9 ; i++) { alpha = (255 - (i*32)); if(alpha < 0) alpha = 0; #ifdef BUGHUNT printf("fadeou i= %d\n", alpha); #endif Layer1Pixmap->SetAlpha(alpha); osd->Flush(); } } void cImageControl::CrossFade(void) { int fadeOut,fadeIn; #ifdef BUGHUNT uint64_t Now; Now = cTimeMs::Now(); printf("Zeit fuers Laden des Bildes: %i\n", (Now - Start)); #endif /* Layer1Pixmap->Clear(); Layer1Pixmap = Layer2Pixmap; Layer2Pixmap->Clear(); */ for (int i=1; i < 17 ; i++) { #ifdef BUGHUNT Start = cTimeMs::Now(); #endif fadeIn = (i * 16); if(fadeIn >255) fadeIn = 255; #ifdef BUGHUNT printf("fadein i= %d\n", fadeIn); #endif fadeOut = (255 - (i*16)); if(fadeOut < 0) fadeOut = 0; #ifdef BUGHUNT printf("fadeou i= %d\n", fadeOut); #endif Layer1Pixmap->SetAlpha(fadeOut); Layer2Pixmap->SetAlpha(fadeIn); #ifdef BUGHUNT Now = cTimeMs::Now(); printf("Pixmap->SetAlpha: %i\n", (Now -Start)); Start = cTimeMs::Now(); #endif osd->Flush(); #ifdef BUGHUNT Now = cTimeMs::Now(); printf("Flush: %i\n", (Now -Start)); #endif } } /* void cImageControl::FadeOut(void) { SetNeedsFastResponse(true); int alpha = 255; int fd = 16; while (!(fd==0)) { if (Layer1Pixmap && osd) { alpha = alpha - 16; if (alpha < 0) alpha = 0; #ifdef BUGHUNT printf("fd = %i , alpha = %i\n",fd,alpha); #endif Layer1Pixmap->SetAlpha(alpha); Flush(); } fd--; } // Flush(); SetNeedsFastResponse(false); } */