]> git.vomp.tv Git - vompclient.git/blob - vpicture.cc
Updates to new streaming protocol and live tv
[vompclient.git] / vpicture.cc
1 /*
2     Copyright 2004-2005 Chris Tallon, Andreas Vogel
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include <time.h>
22
23 #include "vpicture.h"
24
25 #include "vpicturebanner.h"
26 #include "timers.h"
27 #include "boxx.h"
28 #include "wselectlist.h"
29 #include "remote.h"
30 #include "wsymbol.h"
31 #include "boxstack.h"
32 #include "vdr.h"
33 #include "media.h"
34 #include "vvideolive.h"
35 #include "video.h"
36 #include "vinfo.h"
37 #include "i18n.h"
38 #include "message.h"
39 #include "command.h"
40
41 Colour VPicture::pictureBack=Colour(140,140,140);
42 Colour VPicture::infoBack=Colour(110,110,110);
43 //the jpeg reader
44
45 class VPreader : public JpegReader {
46   private:
47     VPicture * parent;
48   public:
49   VPreader(VPicture *p){
50      parent=p;};
51   virtual ULONG readChunk(ULONG offset,ULONG len,char ** buf) {
52      Log::getInstance()->log("VPicture::jpegReader", Log::DEBUG, "read chunk o=%d,len=%d,buf=%p",
53         offset,len,*buf);
54      UINT numrec=0;
55      *buf=(char *)VDR::getInstance()->getImageBlock(offset,(UINT)len,&numrec);
56      Log::getInstance()->log("VPicture::jpegReader", Log::DEBUG, "got n=%d,buf=%p",
57         numrec,*buf);
58      return numrec;
59      }
60   virtual ULONG initRead(const char *filename) {
61      Log::getInstance()->log("VPicture::jpegReader", Log::DEBUG, "load image %s",filename);
62      Video* video = Video::getInstance();
63      ULONG size=VDR::getInstance()->loadImage(filename,video->getScreenWidth(), video->getScreenHeight());
64      Log::getInstance()->log("VPicture::jpegReader", Log::DEBUG, "load image %s returned %d",filename,size);
65      return size;
66      }
67 };
68
69 VPicture::VPicture(VMediaList *p)
70 {
71   parent=p;
72   reader=new VPreader(this);
73   needDraw=false;
74   Video* video = Video::getInstance();
75   setSize(video->getScreenWidth(), video->getScreenHeight());
76   createBuffer();
77 //  jpeg.setSurface(surface);
78   jpeg.setDimensions(area.w,area.h);
79   banner=NULL;
80   fullname=NULL;
81   filename=NULL;
82   ftime=0;
83   slideshow=false;
84   showtime=INITIAL_SHOWTIME;
85   mediaError=NULL;
86   currentMedia=NULL;
87   shortBanner=false;
88   rotate=0;
89   info=NULL;
90   jpeg.setBackgroundColour(pictureBack);
91   add(&jpeg);
92 }
93
94 VPicture::~VPicture()
95 {
96   delete reader;
97   if (banner) BoxStack::getInstance()->remove(banner);
98   if (fullname) delete fullname;
99   if (filename) delete filename;
100   Timers::getInstance()->cancelTimer(this,1);
101   Timers::getInstance()->cancelTimer(this,2);
102   Timers::getInstance()->cancelTimer(this,3);
103   destroyInfo();
104   
105 }
106
107 void VPicture::draw()
108 {
109   Log::getInstance()->log("VPicture::draw", Log::DEBUG, "needDraw=%d,p=%p", needDraw,this);
110   Boxx::draw();
111   
112   if (mediaError) {
113     drawText(mediaError,20,area.h-10,Colour::LIGHTTEXT);
114     return;
115     }
116 }
117
118
119 int VPicture::handleCommand(int command)
120 {
121   Timers::getInstance()->cancelTimer(this,1);
122   int rt=1;
123   switch(command)
124   {
125     case Remote::DF_UP:
126     case Remote::UP:
127     case Remote::SKIPBACK:
128       showPicture(VMediaList::MV_PREV);
129       BoxStack::getInstance()->update(this);
130       rt= 2;
131       break;
132     case Remote::FORWARD:
133       if (showtime > 1) showtime--;
134       updateBanner(true);
135       break;
136     case Remote::DF_DOWN:
137     case Remote::DOWN:
138     case Remote::SKIPFORWARD:
139       showPicture(VMediaList::MV_NEXT);
140       BoxStack::getInstance()->update(this);
141       rt= 2;
142       break;
143     case Remote::REVERSE:
144       if (showtime < 50 ) showtime++;
145       updateBanner(true);
146       break;
147     case Remote::OK:
148     {
149       if (banner) {
150         destroyBanner();
151         destroyInfo();
152         }
153       else showBanner();
154       rt= 2;
155     }
156     break;
157     case Remote::PLAY:
158     {
159       slideshow=true;
160       showPicture(VMediaList::MV_NEXT);
161       BoxStack::getInstance()->update(this);
162       rt= 2;
163     }
164     break;
165     case Remote::PAUSE:
166       slideshow=false;
167       updateBanner();
168       rt= 2;
169       break;
170     case Remote::STOP:
171       slideshow=false;
172       showtime=INITIAL_SHOWTIME;
173       updateBanner();
174       rt= 2;
175       break;
176     case Remote::RED:
177       switch(rotate) {
178         case WJpeg::ROT_0:
179           rotate=WJpeg::ROT_90;
180           break;
181         case WJpeg::ROT_90:
182           rotate=WJpeg::ROT_180;
183           break;
184         case WJpeg::ROT_180:
185           rotate=WJpeg::ROT_270;
186           break;
187         case WJpeg::ROT_270:
188           rotate=WJpeg::ROT_0;
189           break;
190         }
191       showPicture(VMediaList::MV_NONE,rotate);
192       BoxStack::getInstance()->update(this);
193       rt=2;
194       break;
195     case Remote::GREEN:
196       if (info) destroyInfo();
197       else showInfo();
198       rt=2;
199       break;
200     case Remote::BACK:
201     {
202       rt= 4;
203     }
204     break;
205   }
206   if (slideshow) startSlideshow();
207   // stop command getting to any more views
208   return rt;
209 }
210
211 void VPicture::processMessage(Message* m)
212 {
213   if (m->message == Message::MOUSE_MOVE)
214   {
215     ;
216   }
217   else if (m->message == Message::MOUSE_LBDOWN)
218   {
219     
220     //check if press is outside this view! then simulate cancel
221     int x=(m->parameter>>16)-getScreenX();
222     int y=(m->parameter&0xFFFF)-getScreenY();
223     if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
224     {
225       BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
226     }
227   }
228 }
229
230 VPicture * VPicture::createViewer(VMediaList * mparent, bool bslideshow) {
231    Log::getInstance()->log("VPicture::createViewer", Log::DEBUG, "p=%p",
232         mparent);
233    VPicture *vmn=new VPicture(mparent);
234    BoxStack::getInstance()->add(vmn);
235    BoxStack::getInstance()->update(vmn);
236    vmn->showPicture();
237    if (bslideshow) vmn->startSlideshow();
238    vmn->showBanner();
239    BoxStack::getInstance()->update(vmn);
240    return vmn;
241 }
242
243 void VPicture::startSlideshow() {
244    slideshow=true;
245    Timers::getInstance()->setTimerD(this,1,showtime);
246 }
247
248 void VPicture::showPicture(ULONG move, int rt) {
249   rotate=rt;
250   currentMedia=parent->getMedia(MEDIA_TYPE_PICTURE,move);
251   load(currentMedia);
252   if (mediaError || jpeg.hasError()) destroyInfo();
253   else updateInfo();
254   BoxStack::getInstance()->update(this);
255 }
256
257
258 int VPicture::load(Media *md) {
259   jpeg.init(NULL,false,NULL);
260   mediaError=tr("No media found");
261   needDraw=false;
262   if (! md) return 1;
263   const char *fname=md->getFileName();
264   ftime=md->getTime();
265   int len=strlen(fname)+2+strlen(parent->getDirname());
266   if (fullname) {
267      delete fullname;
268      fullname=NULL;
269      }
270   fullname=new char[len];
271   sprintf(fullname,"%s/%s",parent->getDirname(),fname);
272   if (filename) delete filename;
273   len=strlen(fname)+1;
274   filename=new char[len];
275   strcpy(filename,fname);
276   Log::getInstance()->log("VPicture::load", Log::DEBUG, "filename=%s,p=%p",
277         fullname,this);
278   VDR* vdr=VDR::getInstance();
279   //do we have a banner?
280   bool haveBanner=banner!=NULL && ! shortBanner;
281   if (vdr->isConnected()) {
282      showBanner(true);
283      jpeg.init(fullname,false,reader);
284      jpeg.setRotate(rotate);
285      needDraw=true;
286      mediaError=NULL;
287      draw();
288      //only show the banner if it was there before
289      if (haveBanner) showBanner();
290      else {
291         if(banner) destroyBanner();
292         }
293      Log::getInstance()->log("VPicture::load", Log::DEBUG, "success: filename=%s,p=%p",
294         fullname,this);
295      return 0;
296   }
297   else {
298     mediaError=tr("no VDR connection");
299     }
300   return 1;
301 }
302
303 void VPicture::showBanner(bool loading,int shortDisplay) {
304         //we are in the main thread - so we can (and must) safely hard destroy/create the banner
305   Timers::getInstance()->cancelTimer(this,2);
306   if (! filename || ! currentMedia) {
307     //hmm...
308     destroyBanner(!loading);
309     return;
310     }
311   if (banner) destroyBanner(!loading);
312   banner= new VPictureBanner(this, loading, slideshow);
313   banner->fillColour(infoBack);
314   if (! loading) {
315     int len=strlen(filename)+Media::TIMEBUFLEN+20;
316     char *buf=new char[len];
317     char tbuf[Media::TIMEBUFLEN];
318     SNPRINTF(buf,len,"%c%02ds%c %s %s ",
319       slideshow?' ':'[',
320       showtime,
321       slideshow?' ':']',
322       currentMedia->getTimeString(tbuf),
323       filename);
324     banner->setText(buf);
325     delete [] buf;
326   }
327   else {
328     banner->setText(filename);
329   }
330   banner->draw();
331   if (shortDisplay != 0) shortBanner=true;
332   if (! slideshow && shortDisplay == 0) shortDisplay=8;
333   //OK we start timer if we don't load and either shortDisplay or no slideshow
334   if (! loading && shortDisplay != 0)   Timers::getInstance()->setTimerD(this,2,shortDisplay);
335         BoxStack::getInstance()->add(banner);
336         BoxStack::getInstance()->update(banner);
337
338   }
339
340 void VPicture::destroyBanner(bool fromTimer) {
341   shortBanner=false;
342   if (banner) {
343     if (fromTimer) sendViewMsg(banner,true); 
344                 else BoxStack::getInstance()->remove(banner);
345     banner=NULL;
346     if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);
347     }
348 }
349 void VPicture::updateBanner(bool shortDisplay) {
350   if (banner && ! shortBanner) {
351     showBanner(false);
352     }
353   else if (shortDisplay) {
354     showBanner(false,2);
355     }
356 }
357 void VPicture::timercall(int clientref) {
358    switch(clientref)
359    {
360       case 1:
361         if (! slideshow) return;
362         Log::getInstance()->log("VPicture::timercall", Log::DEBUG, "slideshow");
363                                 sendCommandMsg(Remote::PLAY);
364         break;
365       case 2:
366         destroyBanner(true);
367         break;
368       case 3:
369         destroyInfo(true);
370         break;
371     }
372    
373   }
374
375 #define INFOBUF 1000
376 void VPicture::showInfo(){
377   if (info) destroyInfo();
378   if (! currentMedia) return;
379
380   info=new VInfo();
381   info->setTitleText(currentMedia->getFileName());
382   info->setDropThrough();
383   info->setSize(500, 300);
384   info->createBuffer();
385   info->setBorderOn(1);
386   info->setTitleBarOn(1);
387
388   if (Video::getInstance()->getFormat() == Video::PAL)
389         info->setPosition(100, 180);
390   else
391         info->setPosition(100, 150);
392   char buf[INFOBUF];
393   char tbuf[Media::TIMEBUFLEN];
394   SNPRINTF(buf,INFOBUF,"%s= %s\n%s= %ld x %ld\n%s= %ld kBytes\n%s= %s\n%s= %ld\n%s= 1/%ld",
395      tr("Directory"), parent->getDirname(),
396      tr("Format(px)"),jpeg.getJpegInfo(WJpeg::JPEG_WIDTH),jpeg.getJpegInfo(WJpeg::JPEG_HEIGHT),
397      tr("Filesize"),jpeg.getJpegInfo(WJpeg::JPEG_SIZE)/1000,
398      tr("Time"),currentMedia->getTimeString(tbuf),
399      tr("Rotation"),90*jpeg.getJpegInfo(WJpeg::JPEG_ROTATE),
400      tr("Scale"),jpeg.getJpegInfo(WJpeg::JPEG_SCALE));
401   info->setMainText(buf);
402   info->draw();
403   sendViewMsg(info,false);
404   Timers::getInstance()->setTimerD(this,3,8);
405 }
406 void VPicture::updateInfo(){
407   if (info) {
408     showInfo();
409     }
410 }
411 void VPicture::destroyInfo(bool fromTimer){
412   if (info) {
413     sendViewMsg(info,true);
414     info=NULL;
415     }
416   if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);
417 }
418
419 void VPicture::sendViewMsg(Boxx *v,bool vdestroy) {
420         Message* m = new Message(); 
421   m->message = vdestroy?Message::CLOSE_ME:Message::ADD_VIEW;
422   m->to = BoxStack::getInstance();
423   m->from = v;
424         m->parameter=(ULONG)v;
425   Command::getInstance()->postMessageFromOuterSpace(m);
426 }
427 void VPicture::sendCommandMsg(int command) {
428         Message* m = new Message(); 
429   m->message = Message::UDP_BUTTON;
430   m->to = Command::getInstance();
431   m->from = this;
432         m->parameter=command;
433   Command::getInstance()->postMessageFromOuterSpace(m);
434 }