vdr
1.7.27
|
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 }