diff options
author | Andreas Brachold <vdr07@deltab.de> | 2005-07-19 15:09:05 +0000 |
---|---|---|
committer | Andreas Brachold <vdr07@deltab.de> | 2005-07-19 15:09:05 +0000 |
commit | f897f2aa7055c493db6391c50c8d19da970078e8 (patch) | |
tree | d13a515b24c149d7da4e9828cc9e9c73d4916f00 /player-image.c | |
download | vdr-plugin-image-f897f2aa7055c493db6391c50c8d19da970078e8.tar.gz vdr-plugin-image-f897f2aa7055c493db6391c50c8d19da970078e8.tar.bz2 |
Initial import with release 0.2.3
Diffstat (limited to 'player-image.c')
-rw-r--r-- | player-image.c | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/player-image.c b/player-image.c new file mode 100644 index 0000000..f8818f8 --- /dev/null +++ b/player-image.c @@ -0,0 +1,478 @@ +/* + * Image plugin to VDR (C++) + * + * (C) 2004 Andreas Brachold <vdr04-at-deltab.de> + * 2003 Kai Tobias Burwieck <kai@burwieck.net> + * + * 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 <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <unistd.h> +#include <signal.h> +#include <wait.h> + +#include "player-image.h" +#include "control-image.h" +#include "setup-image.h" +#include "data-image.h" +#include "image.h" +#include "list.h" +#include "i18n.h" + +#include "libimage/pnm.h" +#include "libimage/xpm.h" + + +const char *g_szConvertScript = "imageplugin.sh"; + + +//----------cImagePlayer------------- + + + + +cImagePlayer::cImagePlayer(cSlideShow *pCurSlideShow) +: cStillImagePlayer( +#if VDRVERSNUM >= 10308 + (ImageSetup.m_bLiveAudio != 0)?pmVideoOnly: +#endif + pmAudioVideo + ) +, m_bConvertRunning(false) +, m_szError(NULL) +{ + theSlideShow.Assign(pCurSlideShow); +} + +bool cImagePlayer::GetIndex(int &nCurrent, int &nTotal, bool /*bSnapToIFrame*/) +{ + // Notify other status-plugins with one picture as one second + nCurrent = theSlideShow.ImageCurrent(); + // Notify other status-plugins count of picture as totalcount of seconds + nTotal = theSlideShow.ImageTotal(); + + return true; +} + +cImagePlayer::~cImagePlayer() +{ + // Remove Slideshow + theSlideShow.Shutdown(); +} + + +void cImagePlayer::Activate(bool bOn) +{ + if(bOn) { + if(theSlideShow.GetImage()) + { + cStillImagePlayer::Activate(bOn); + Convert(""); + } + } + else + cStillImagePlayer::Activate(false); +} + + +bool cImagePlayer::NextImage(int nOffset) +{ + return theSlideShow.NextImage(nOffset); +} + + + +bool cImagePlayer::PrevImage(int nOffset) +{ + return theSlideShow.PrevImage(nOffset); +} + + +bool cImagePlayer::GotoImage(unsigned int nNewPictureIndex) +{ + return theSlideShow.GotoImage(nNewPictureIndex); +} + + +bool cImagePlayer::Convert(const char *szChange) +{ + cImage* pImage = theSlideShow.GetImage(); + if(pImage) + { + cShellWrapper* pCmd = new cShellWrapper; + pCmd->bClearBackground = true; + pCmd->nOffLeft = m_StillImage.GetBorderWidth(); + pCmd->nOffTop = m_StillImage.GetBorderHeight(); + pCmd->nWidth = UseWidth(); + pCmd->nHeight = UseHeight(); + + // Build image_convert.sh "source.jpg" "/tmp/image/dest.pnm" 720 576 0 0 0 0 original + pCmd->szPNM = strdup(pImage->NamePNM()); + + asprintf(&pCmd->szCmd, "%s \"%s\" \"%s\" %d %d %d %d %d %s", + g_szConvertScript, + pImage->Name(), + pCmd->szPNM, + pCmd->nWidth, + pCmd->nHeight, + 0, + 0, + 0, + szChange ? szChange : ""); + + Exec(pCmd); + return true; + } + return false; +} + + + +bool cImagePlayer::ConvertJump(int nOffset) +{ + register unsigned int w,h; + const unsigned int MAX_BILDER = 9; + cImage* pImage[MAX_BILDER]; + for (w = 0; w < MAX_BILDER; ++w) + pImage[w] = NULL; + int nBilder = theSlideShow.GetJumpNames(nOffset,pImage,MAX_BILDER); + if(nBilder > 0 + && pImage[0]) { + + unsigned int nMatrix = (nBilder < 5) ? 2 : 3; + + for (h = 0; h < nMatrix; ++h) + for (w = 0; w < nMatrix && pImage[(h*nMatrix)+w]; ++w) + { + cShellWrapper* pCmd = new cShellWrapper; + + pCmd->bClearBackground = (w == 0 && h == 0); + pCmd->nWidth = UseWidth(); + pCmd->nHeight = UseHeight(); + pCmd->nWidth /= nMatrix; + pCmd->nHeight /= nMatrix; + pCmd->nOffLeft = (pCmd->nWidth * w) + m_StillImage.GetBorderWidth(); + pCmd->nOffTop = (pCmd->nHeight * h) + m_StillImage.GetBorderHeight(); + + // Build image_convert.sh "source.jpg" "/tmp/image/source.jpg-i.pnm" 256 192 0 0 0 0 original + pCmd->szPNM = strdup(pImage[(h*nMatrix)+w]->NameIndex()); + + + + asprintf(&pCmd->szCmd, "%s \"%s\" \"%s\" %d %d %d %d %d %s", + g_szConvertScript, + pImage[(h*nMatrix)+w]->Name(), + pCmd->szPNM, + pCmd->nWidth, + pCmd->nHeight, + 0, + 0, + 0, + /*szChange ? szChange : */""); + pCmd->szNumber = '0'+((h*nMatrix)+w)+1; + + Exec(pCmd); + } + return true; + } + return false; +} + + +bool cImagePlayer::ConvertZoom(const char *szChange, int nZoomFaktor, + int nLeftPos, int nTopPos) +{ + cImage* pImage = theSlideShow.GetImage(); + if(pImage) + { + cShellWrapper* pCmd = new cShellWrapper; + pCmd->bClearBackground = true; + pCmd->nOffLeft = m_StillImage.GetBorderWidth() + (nLeftPos>0?0:(nLeftPos*-1)); + pCmd->nOffTop = m_StillImage.GetBorderHeight() + (nTopPos>0?0:(nTopPos*-1)); + pCmd->nWidth = UseWidth(); + pCmd->nHeight = UseHeight(); + + // Build image_convert.sh "source.jpg" "/tmp/image/dest.pnm" 720 576 0 0 0 0 original + pCmd->szPNM = strdup(pImage->NameZoom()); + + asprintf(&pCmd->szCmd, "%s \"%s\" \"%s\" %d %d %d %d %d %s", + g_szConvertScript, + pImage->Name(), + pCmd->szPNM, + pCmd->nWidth, + pCmd->nHeight, + nZoomFaktor, + nLeftPos>0?nLeftPos:0, + nTopPos>0?nTopPos:0, + szChange ? szChange : ""); + + Exec(pCmd); + return true; + } + return false; +} + + +void cImagePlayer::LoadImage(cShellWrapper* pShell) +{ + cPNM pnmImage; + bool bSuccess = false; + register unsigned int nHeight = m_StillImage.GetHeight(); + register unsigned int nWidth = m_StillImage.GetWidth(); + register unsigned int nOffLeft = 0; + register unsigned int nOffTop = 0; + errno = 0; + if(!pShell || pShell->bClearBackground) + m_StillImage.ClearRGBMem(); + + if(pShell && pShell->szPNM) + { + nHeight = std::min(nHeight,pShell->nHeight); + nWidth = std::min(nWidth,pShell->nWidth); + nOffLeft = pShell->nOffLeft; + nOffTop = pShell->nOffTop; + + FILE *f=fopen(pShell->szPNM, "r"); + if(f) + { + xel* pRow = NULL; + register unsigned int w; + register unsigned int h; + + if(pnmImage.readHeader(f)) + { + register unsigned int nColorDepth = pnmImage.GetColorDepth(); + + if(pnmImage.GetWidth() < nWidth) + nOffLeft += (nWidth - pnmImage.GetWidth()) / 2; + + if(pnmImage.GetHeight() < nHeight) + nOffTop += (nHeight - pnmImage.GetHeight()) / 2; + + + for(h = 0; + h < pnmImage.GetHeight() + && h < nHeight + && h+nOffTop < m_StillImage.GetHeight(); + ++h) + { + if(!pnmImage.allocrow(&pRow) + ||!pnmImage.readrow(f, pRow) ) + break; + + xel* pP = pRow; + for(w = 0;w < pnmImage.GetWidth() + && w < nWidth + && w+nOffLeft < m_StillImage.GetWidth(); + ++w,++pP) + { + uint8_t* pImageRGB = m_StillImage.GetRGBMem() + + ((((h+nOffTop)*m_StillImage.GetWidth())+w+nOffLeft)*3); + + if(nColorDepth == 0xFF) // normal 8-bit at any canal (24 Bit) colordepth + { + *(pImageRGB + 0) = (uint8_t) PPM_GETR(*pP); + *(pImageRGB + 1) = (uint8_t) PPM_GETG(*pP); + *(pImageRGB + 2) = (uint8_t) PPM_GETB(*pP); + } + else if(nColorDepth == 1) // black/white image + { + *(pImageRGB + 0) = (uint8_t) PPM_GETR(*pP)==0?0x00:0xFF; + *(pImageRGB + 1) = (uint8_t) PPM_GETG(*pP)==0?0x00:0xFF; + *(pImageRGB + 2) = (uint8_t) PPM_GETB(*pP)==0?0x00:0xFF; + } + else // Adjust other colordepth to 8bit + { + *(pImageRGB + 0) = (uint8_t) (PPM_GETR(*pP)*255 / pnmImage.GetColorDepth()) & 0xFF; + *(pImageRGB + 1) = (uint8_t) (PPM_GETG(*pP)*255 / pnmImage.GetColorDepth()) & 0xFF; + *(pImageRGB + 2) = (uint8_t) (PPM_GETB(*pP)*255 / pnmImage.GetColorDepth()) & 0xFF; + } + } + pnmImage.freerow(pRow); + pRow = NULL; + } + if(pRow) + pnmImage.freerow((char*)pRow); + else + { + if(pShell->szNumber && ImageSetup.ShowNumbers) + cXPM::Overlay(pShell->szNumber,m_StillImage.GetRGBMem(), + m_StillImage.GetWidth(),m_StillImage.GetHeight(), + cXPM::TopRight,nOffLeft,nOffTop,pnmImage.GetWidth(),pnmImage.GetHeight()); + + bSuccess = true; + } + } + fclose(f); + } + } + if(!bSuccess) { + + // Merge Errorimage with Encoder-Memory + if(pShell && pShell->szNumber) + cXPM::Overlay('s',m_StillImage.GetRGBMem(), + m_StillImage.GetWidth(),m_StillImage.GetHeight(), + cXPM::Center,pShell->nOffLeft,pShell->nOffTop,pShell->nWidth,pShell->nHeight); + else + cXPM::Error(m_StillImage.GetRGBMem(), + m_StillImage.GetWidth(),m_StillImage.GetHeight()); + + // Build Error, depends PNM Errormsg or system messages + char szErr[128]; + + if(pnmImage.GetError()) + strncpy(szErr,pnmImage.GetError(),sizeof(szErr)); + else if(errno) { + int nErr = errno; + szErr[sizeof(szErr)-1] = '\0'; + if(0 != strerror_r(nErr,szErr,sizeof(szErr)-1)) { + szErr[0] = '\0'; + } + } + + // Make Syslog entry + if(pShell && pShell->szPNM && szErr) + esyslog("imageplugin: Error until read %s : '%s'", pShell->szPNM, szErr); + else if(pShell && pShell->szPNM) + esyslog("imageplugin: Error until read %s", pShell->szPNM); + else + esyslog("imageplugin: Error until read image %s",szErr?szErr:""); + + { // Copy Errormessage forward to OSD Thread + cMutexLock lock(&m_MutexErr); + if(m_szError) + free(m_szError); + if(szErr) + asprintf(&m_szError, "%s : %s", tr("Image couldn't load"),szErr); + else + m_szError = strdup(tr("Image couldn't load")); + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +/** void cImagePlayer::ExecFailed() +Show a precompiled Image if Exec can't find a converted Image +@param - char* szErr +@return - nothing */ +void cImagePlayer::ExecFailed(cShellWrapper* pShell,const char* szErr) +{ + if(!pShell || pShell->bClearBackground) + m_StillImage.ClearRGBMem(); + + // Merge Errorimage with Encoder-Memory + if(pShell && pShell->szNumber) + cXPM::Overlay('s',m_StillImage.GetRGBMem(), + m_StillImage.GetWidth(),m_StillImage.GetHeight(), + cXPM::Center,pShell->nOffLeft,pShell->nOffTop,pShell->nWidth,pShell->nHeight); + else + cXPM::Error(m_StillImage.GetRGBMem(), + m_StillImage.GetWidth(),m_StillImage.GetHeight()); + + + // Store Message for OSD-Thread + { + cMutexLock lock(&m_MutexErr); + if(m_szError) + free(m_szError); + m_szError = strdup(szErr); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/** void cImagePlayer::ErrorMsg() +ThreadSafe Method to show messages from Worker thread, +this functions is called only from cImageControl::ProcessKey(kNone) +@return - nothing */ +void cImagePlayer::ErrorMsg() +{ + char* szErr = NULL; + { + cMutexLock lock(&m_MutexErr); + szErr = m_szError; + m_szError = NULL; + } + if(szErr) + { + OSD_ErrorMsg(szErr); + free(szErr); + } +} + +const char* cImagePlayer::FileName(void) const +{ + cImage* pImage = theSlideShow.GetImage(); + return pImage?pImage->Name():NULL; +} + +void cImagePlayer::Exec(cShellWrapper* pCmd) +{ + if(pCmd->szPNM) + m_bConvertRunning = true; + if(pCmd) { + cMutexLock lock(&m_Mutex); + if(!m_queue.add(pCmd)) + delete pCmd; //Queue full or Thread is dead + } +} + +bool cImagePlayer::Worker(bool bDoIt) +{ + bool bQueueEmpty; + cShellWrapper *pShell = NULL; + + { // Protect the queue ++ + cMutexLock lock(&m_Mutex); + if(bDoIt && !m_queue.empty()) { + pShell = *m_queue.begin(); + m_queue.erase(m_queue.begin()); + } + bQueueEmpty = m_queue.empty(); + } // ++ + + if(!pShell) + { + m_bConvertRunning = m_StillImage.EncodeRequired(); + return bQueueEmpty; + } + + if(pShell->szCmd) { + //dsyslog("imageplugin: executing script '%s'", pShell->szCmd); + + ImageSetup.SetEnv(); + if(0 == SystemExec(pShell->szCmd)) + { + if(pShell->szPNM) { + LoadImage(pShell); + m_StillImage.EncodeRequired(true); + } + } + else + { + esyslog("imageplugin: script execution failed '%s'", pShell->szCmd); + if(pShell->szPNM) { + ExecFailed(pShell,tr("Script execution failed")); + m_StillImage.EncodeRequired(true); + } + } + } + delete pShell; + return bQueueEmpty; +} |