vdr  1.7.27
player.c
Go to the documentation of this file.
00001 /*
00002  * player.c: A player for still pictures
00003  *
00004  * See the README file for copyright information and how to reach the author.
00005  *
00006  * $Id: player.c 2.1 2011/02/20 17:15:25 kls Exp $
00007  */
00008 
00009 #include "player.h"
00010 #include <vdr/remote.h>
00011 #include <vdr/tools.h>
00012 
00013 int SlideShowDelay = 3; // seconds
00014 
00015 cString HandleUnderscores(const char *s)
00016 {
00017   // Skip anything before and including the first '_' and replace
00018   // any remaining '_' with blanks:
00019   const char *p = strchr(s, '_');
00020   if (p) {
00021      p++;
00022      char buf[strlen(p) + 1];
00023      strcpy(buf, p);
00024      return strreplace(buf, '_', ' ');
00025      }
00026   return s;
00027 }
00028 
00029 // --- cPicturePlayer --------------------------------------------------------
00030 
00031 class cPicturePlayer : public cPlayer {
00032 private:
00033   int size;
00034   int length;
00035   uchar *buffer;
00036   virtual void Activate(bool On);
00037 public:
00038   cPicturePlayer(void);
00039   ~cPicturePlayer();
00040   void SetPicture(const char *FileName);
00041   };
00042 
00043 cPicturePlayer::cPicturePlayer(void)
00044 {
00045   size = KILOBYTE(100); // will be adjusted automatically if files are larger
00046   length = 0;
00047   buffer = MALLOC(uchar, size);
00048 }
00049 
00050 cPicturePlayer::~cPicturePlayer()
00051 {
00052   free(buffer);
00053 }
00054 
00055 void cPicturePlayer::Activate(bool On)
00056 {
00057   if (length > 0)
00058      DeviceStillPicture(buffer, length);
00059 }
00060 
00061 void cPicturePlayer::SetPicture(const char *FileName)
00062 {
00063   int f = open(FileName, O_RDONLY);
00064   if (f >= 0) {
00065      for (;;) {
00066          length = read(f, buffer, size);
00067          if (length > 0) {
00068             if (length >= size) {
00069                int NewSize = size * 3 / 2;
00070                if (uchar *NewBuffer = (uchar *)realloc(buffer, NewSize)) {
00071                   buffer = NewBuffer;
00072                   size = NewSize;
00073                   }
00074                else {
00075                   LOG_ERROR_STR("out of memory");
00076                   break;
00077                   }
00078                lseek(f, 0, SEEK_SET);
00079                continue;
00080                }
00081             DeviceStillPicture(buffer, length);
00082             }
00083          else
00084             LOG_ERROR_STR(FileName);
00085          break;
00086          }
00087      close(f);
00088      }
00089   else
00090      LOG_ERROR_STR(FileName);
00091 }
00092 
00093 // --- cPictureControl -------------------------------------------------------
00094 
00095 int cPictureControl::active = 0;
00096 cString cPictureControl::lastDisplayed;
00097 
00098 cPictureControl::cPictureControl(cPictureEntry *Pictures, const cPictureEntry *PictureEntry, bool SlideShow)
00099 :cControl(player = new cPicturePlayer)
00100 {
00101   pictures = Pictures;
00102   pictureEntry = PictureEntry;
00103   osd = NULL;
00104   lastPath = "/";
00105   slideShowDelay.Set(SlideShowDelay * 1000);
00106   slideShow = SlideShow;
00107   alwaysDisplayCaption = false;
00108   NextPicture(slideShow && pictureEntry->IsDirectory() ? 1 : 0);
00109   active++;
00110 }
00111 
00112 cPictureControl::~cPictureControl()
00113 {
00114   active--;
00115   delete osd;
00116   delete player;
00117   delete pictures;
00118 }
00119 
00120 void cPictureControl::NextPicture(int Direction)
00121 {
00122   if (Direction) {
00123      const cPictureEntry *pe = Direction > 0 ? pictureEntry->NextPicture() : pictureEntry->PrevPicture();
00124      if (pe)
00125         pictureEntry = pe;
00126      }
00127   if (pictureEntry) {
00128      player->SetPicture(pictureEntry->Path());
00129      DisplayCaption();
00130      }
00131 }
00132 
00133 void cPictureControl::NextDirectory(int Direction)
00134 {
00135   // This only works reliable if a directory contains only subdirectories or pictures, not both!
00136   if (Direction) {
00137      const cPictureEntry *pe = Direction > 0 ? pictureEntry->Parent()->Entries()->Last()->NextPicture() : pictureEntry->Parent()->Entries()->First()->PrevPicture();
00138      if (pe && Direction < 0)
00139         pe = pe->Parent()->Entries()->First();
00140      if (pe && pe != pictureEntry) {
00141         pictureEntry = pe;
00142         player->SetPicture(pictureEntry->Path());
00143         DisplayCaption();
00144         }
00145      }
00146 }
00147 
00148 static void DrawTextOutlined(cOsd *Osd, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font)
00149 {
00150   for (int dx = -1; dx <= 1; dx++) {
00151       for (int dy = -1; dy <= 1; dy++) {
00152           if (dx || dy)
00153              Osd->DrawText(x + dx, y + dy, s, ColorBg, clrTransparent, Font);
00154           }
00155       }
00156   Osd->DrawText(x, y, s, ColorFg, clrTransparent, Font);
00157 }
00158 
00159 void cPictureControl::DisplayCaption(void)
00160 {
00161   bool Force = false;
00162   cString Path = pictureEntry->Path();
00163   lastDisplayed = Path + strlen(pictures->Name()) + 1;
00164   const char *p = strrchr(Path, '/');
00165   const char *q = strrchr(lastPath, '/');
00166   if (p && q) {
00167      int lp = p - Path;
00168      int lq = q - lastPath;
00169      if (lp != lq || strncmp(lastPath, Path, lp)) {
00170         lastPath = Path;
00171         Force = true;
00172         }
00173      }
00174   if (!alwaysDisplayCaption && !Force) {
00175      DELETENULL(osd);
00176      return;
00177      }
00178   const cFont *Font = cFont::GetFont(fontOsd);
00179   int w = cOsd::OsdWidth();
00180   int h = 2 * Font->Height();
00181   if (!osd) {
00182      osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - h, OSD_LEVEL_SUBTITLES);
00183      tArea Areas[] = { { 0, 0, w - 1, h - 1, 8 } };
00184      if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
00185         osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
00186      else {
00187         tArea Areas[] = { { 0, 0, w - 1, h - 1, 4 } };
00188         osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
00189         }
00190      }
00191   const char *Year = pictureEntry->Parent()->Parent() ? pictureEntry->Parent()->Parent()->Name() : "";
00192   cString Description = HandleUnderscores(pictureEntry->Parent()->Name());
00193   osd->DrawRectangle(0, 0, w - 1, h - 1, clrTransparent);
00194   DrawTextOutlined(osd, 0, 0, Description, clrWhite, clrBlack, Font);
00195   DrawTextOutlined(osd, 0, h / 2, Year, clrWhite, clrBlack, Font);
00196   struct stat sb;
00197   if (stat(Path, &sb) == 0) {
00198      cString Time = DayDateTime(sb.st_mtime);
00199      DrawTextOutlined(osd, w - Font->Width(Time), h / 2, Time, clrWhite, clrBlack, Font);
00200      }
00201   p++;
00202   Path.Truncate(-4); // don't display the ".mpg" extension
00203   DrawTextOutlined(osd, w - Font->Width(p), 0, p, clrWhite, clrBlack, Font);
00204   osd->Flush();
00205 }
00206 
00207 eOSState cPictureControl::ProcessKey(eKeys Key)
00208 {
00209   switch (Key) {
00210     case kUp:
00211     case kPlay:   slideShowDelay.Set();
00212                   slideShow = true;
00213                   break;
00214     case kDown:
00215     case kPause:  slideShow = false;
00216                   break;
00217     case kLeft|k_Repeat:
00218     case kLeft:   NextPicture(-1);
00219                   slideShow = false;
00220                   break;
00221     case kRight|k_Repeat:
00222     case kRight:  NextPicture(+1);
00223                   slideShow = false;
00224                   break;
00225     case kOk:     if (osd && !alwaysDisplayCaption)
00226                      DELETENULL(osd);
00227                   else {
00228                      alwaysDisplayCaption = !alwaysDisplayCaption;
00229                      DisplayCaption();
00230                      }
00231                   break;
00232     case kGreen:
00233     case kPrev:   NextDirectory(-1);
00234                   slideShow = false;
00235                   break;
00236     case kYellow:
00237     case kNext:   NextDirectory(+1);
00238                   slideShow = false;
00239                   break;
00240     case kBlue:
00241     case kStop:   return osEnd;
00242     case kBack:   slideShow = false;
00243                   cRemote::CallPlugin(PLUGIN_NAME_I18N);
00244                   break;
00245     default: break;
00246     }
00247   if (slideShow && slideShowDelay.TimedOut()) {
00248      NextPicture(+1);
00249      slideShowDelay.Set(SlideShowDelay * 1000);
00250      }
00251   return osContinue;
00252 }
00253 
00254 const char *cPictureControl::LastDisplayed(void)
00255 {
00256   return lastDisplayed;
00257 }