]> git.vomp.tv Git - vompclient-marten.git/blob - vpicture.cc
Demuxer changes/fixes/improvements
[vompclient-marten.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",
110         needDraw,this);
111 //  View::draw();
112   
113   if (mediaError) {
114     drawText(mediaError,20,area.h-10,Colour::LIGHTTEXT);
115     return;
116     }
117   if (needDraw) {
118     jpeg.draw();
119   }
120 }
121
122
123 int VPicture::handleCommand(int command)
124 {
125   Timers::getInstance()->cancelTimer(this,1);
126   int rt=1;
127   switch(command)
128   {
129     case Remote::DF_UP:
130     case Remote::UP:
131     case Remote::SKIPBACK:
132       showPicture(VMediaList::MV_PREV);
133       BoxStack::getInstance()->update(this);
134       rt= 2;
135       break;
136     case Remote::FORWARD:
137       if (showtime > 1) showtime--;
138       updateBanner(true);
139       break;
140     case Remote::DF_DOWN:
141     case Remote::DOWN:
142     case Remote::SKIPFORWARD:
143       showPicture(VMediaList::MV_NEXT);
144       BoxStack::getInstance()->update(this);
145       rt= 2;
146       break;
147     case Remote::REVERSE:
148       if (showtime < 50 ) showtime++;
149       updateBanner(true);
150       break;
151     case Remote::OK:
152     {
153       if (banner) {
154         destroyBanner();
155         destroyInfo();
156         }
157       else showBanner();
158       rt= 2;
159     }
160     break;
161     case Remote::PLAY:
162     {
163       slideshow=true;
164       showPicture(VMediaList::MV_NEXT);
165       BoxStack::getInstance()->update(this);
166       rt= 2;
167     }
168     break;
169     case Remote::PAUSE:
170       slideshow=false;
171       updateBanner();
172       rt= 2;
173       break;
174     case Remote::STOP:
175       slideshow=false;
176       showtime=INITIAL_SHOWTIME;
177       updateBanner();
178       rt= 2;
179       break;
180     case Remote::RED:
181       switch(rotate) {
182         case WJpeg::ROT_0:
183           rotate=WJpeg::ROT_90;
184           break;
185         case WJpeg::ROT_90:
186           rotate=WJpeg::ROT_180;
187           break;
188         case WJpeg::ROT_180:
189           rotate=WJpeg::ROT_270;
190           break;
191         case WJpeg::ROT_270:
192           rotate=WJpeg::ROT_0;
193           break;
194         }
195       showPicture(VMediaList::MV_NONE,rotate);
196       BoxStack::getInstance()->update(this);
197       rt=2;
198       break;
199     case Remote::GREEN:
200       if (info) destroyInfo();
201       else showInfo();
202       rt=2;
203       break;
204     case Remote::BACK:
205     {
206       rt= 4;
207     }
208     break;
209   }
210   if (slideshow) startSlideshow();
211   // stop command getting to any more views
212   return rt;
213 }
214
215 void VPicture::processMessage(Message* m)
216 {
217   if (m->message == Message::MOUSE_MOVE)
218   {
219     ;
220   }
221   else if (m->message == Message::MOUSE_LBDOWN)
222   {
223     
224     //check if press is outside this view! then simulate cancel
225     int x=(m->parameter>>16)-getScreenX();
226     int y=(m->parameter&0xFFFF)-getScreenY();
227     if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
228     {
229       BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
230     }
231   }
232 }
233
234 VPicture * VPicture::createViewer(VMediaList * mparent, bool bslideshow) {
235    Log::getInstance()->log("VPicture::createViewer", Log::DEBUG, "p=%p",
236         mparent);
237    VPicture *vmn=new VPicture(mparent);
238    BoxStack::getInstance()->add(vmn);
239    BoxStack::getInstance()->update(vmn);
240    vmn->showPicture();
241    if (bslideshow) vmn->startSlideshow();
242    vmn->showBanner();
243    BoxStack::getInstance()->update(vmn);
244    return vmn;
245 }
246
247 void VPicture::startSlideshow() {
248    slideshow=true;
249    Timers::getInstance()->setTimerD(this,1,showtime);
250 }
251
252 void VPicture::showPicture(ULONG move, int rt) {
253   rotate=rt;
254   currentMedia=parent->getMedia(MEDIA_TYPE_PICTURE,move);
255   load(currentMedia);
256   if (mediaError || jpeg.hasError()) destroyInfo();
257   else updateInfo();
258   BoxStack::getInstance()->update(this);
259 }
260
261
262 int VPicture::load(Media *md) {
263   jpeg.init(NULL,false,NULL);
264   mediaError=tr("No media found");
265   needDraw=false;
266   if (! md) return 1;
267   const char *fname=md->getFileName();
268   ftime=md->getTime();
269   int len=strlen(fname)+2+strlen(parent->getDirname());
270   if (fullname) {
271      delete fullname;
272      fullname=NULL;
273      }
274   fullname=new char[len];
275   sprintf(fullname,"%s/%s",parent->getDirname(),fname);
276   if (filename) delete filename;
277   len=strlen(fname)+1;
278   filename=new char[len];
279   strcpy(filename,fname);
280   Log::getInstance()->log("VPicture::load", Log::DEBUG, "filename=%s,p=%p",
281         fullname,this);
282   VDR* vdr=VDR::getInstance();
283   //do we have a banner?
284   bool haveBanner=banner!=NULL && ! shortBanner;
285   if (vdr->isConnected()) {
286      showBanner(true);
287      jpeg.init(fullname,false,reader);
288      jpeg.setRotate(rotate);
289      needDraw=true;
290      mediaError=NULL;
291      draw();
292      //only show the banner if it was there before
293      if (haveBanner) showBanner();
294      else {
295         if(banner) destroyBanner();
296         }
297      Log::getInstance()->log("VPicture::load", Log::DEBUG, "success: filename=%s,p=%p",
298         fullname,this);
299      return 0;
300   }
301   else {
302     mediaError=tr("no VDR connection");
303     }
304   return 1;
305 }
306
307 void VPicture::showBanner(bool loading,int shortDisplay) {
308   //if the loading flag is set,
309         //we are in the main thread - so we can (and must) safely hard destroy/create the banner
310   Timers::getInstance()->cancelTimer(this,2);
311   if (! filename || ! currentMedia) {
312     //hmm...
313     destroyBanner(!loading);
314     return;
315     }
316   if (banner) destroyBanner(!loading);
317   banner= new VPictureBanner(this, loading, slideshow);
318   banner->fillColour(infoBack);
319   if (! loading) {
320     int len=strlen(filename)+Media::TIMEBUFLEN+20;
321     char *buf=new char[len];
322     char tbuf[Media::TIMEBUFLEN];
323     SNPRINTF(buf,len,"%c%02ds%c %s %s ",
324       slideshow?' ':'[',
325       showtime,
326       slideshow?' ':']',
327       currentMedia->getTimeString(tbuf),
328       filename);
329     banner->setText(buf);
330     delete [] buf;
331   }
332   else {
333     banner->setText(filename);
334   }
335   banner->draw();
336   if (shortDisplay != 0) shortBanner=true;
337   if (! slideshow && shortDisplay == 0) shortDisplay=8;
338   //OK we start timer if we don't load and either shortDisplay or no slideshow
339   if (! loading && shortDisplay != 0)   Timers::getInstance()->setTimerD(this,2,shortDisplay);
340   if (! loading) ;  /*sendViewMsg(banner,false); upgrade to boxx */
341         else {
342                 BoxStack::getInstance()->add(banner);
343                 BoxStack::getInstance()->update(banner);
344         }
345
346   }
347
348 void VPicture::destroyBanner(bool fromTimer) {
349   shortBanner=false;
350   if (banner) {
351     if (fromTimer) ;/* sendViewMsg(banner,true); upgrade to boxx*/
352                 else BoxStack::getInstance()->remove(banner);
353     banner=NULL;
354     if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);
355     }
356 }
357 void VPicture::updateBanner(bool shortDisplay) {
358   if (banner && ! shortBanner) {
359     showBanner(false);
360     }
361   else if (shortDisplay) {
362     showBanner(false,2);
363     }
364 }
365 void VPicture::timercall(int clientref) {
366    switch(clientref)
367    {
368       case 1:
369         if (! slideshow) return;
370         Log::getInstance()->log("VPicture::timercall", Log::DEBUG, "slideshow");
371                                 sendCommandMsg(Remote::PLAY);
372         break;
373       case 2:
374         destroyBanner(true);
375         break;
376       case 3:
377         destroyInfo(true);
378         break;
379     }
380    
381   }
382
383 #define INFOBUF 1000
384 void VPicture::showInfo(){
385   if (info) destroyInfo();
386   if (! currentMedia) return;
387
388   info=new VInfo();
389   info->setTitleText(currentMedia->getFileName());
390   info->setDropThrough();
391   info->setSize(500, 300);
392   info->createBuffer();
393   info->setBorderOn(1);
394   info->setTitleBarOn(1);
395
396   if (Video::getInstance()->getFormat() == Video::PAL)
397         info->setPosition(100, 180);
398   else
399         info->setPosition(100, 150);
400   char buf[INFOBUF];
401   char tbuf[Media::TIMEBUFLEN];
402   SNPRINTF(buf,INFOBUF,"%s= %s\n%s= %ld x %ld\n%s= %ld kBytes\n%s= %s\n%s= %ld\n%s= 1/%ld",
403      tr("Directory"), parent->getDirname(),
404      tr("Format(px)"),jpeg.getJpegInfo(WJpeg::JPEG_WIDTH),jpeg.getJpegInfo(WJpeg::JPEG_HEIGHT),
405      tr("Filesize"),jpeg.getJpegInfo(WJpeg::JPEG_SIZE)/1000,
406      tr("Time"),currentMedia->getTimeString(tbuf),
407      tr("Rotation"),90*jpeg.getJpegInfo(WJpeg::JPEG_ROTATE),
408      tr("Scale"),jpeg.getJpegInfo(WJpeg::JPEG_SCALE));
409   info->setMainText(buf);
410   info->draw();
411   sendViewMsg(info,false);
412   Timers::getInstance()->setTimerD(this,3,8);
413 }
414 void VPicture::updateInfo(){
415   if (info) {
416     showInfo();
417     }
418 }
419 void VPicture::destroyInfo(bool fromTimer){
420   if (info) {
421     sendViewMsg(info,true);
422     info=NULL;
423     }
424   if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);
425 }
426
427 void VPicture::sendViewMsg(Boxx *v,bool vdestroy) {
428         Message* m = new Message(); 
429   m->message = vdestroy?Message::CLOSE_ME:Message::ADD_VIEW;
430   m->to = BoxStack::getInstance();
431   m->from = v;
432         m->parameter=(ULONG)v;
433   Command::getInstance()->postMessageFromOuterSpace(m);
434 }
435 void VPicture::sendCommandMsg(int command) {
436         Message* m = new Message(); 
437   m->message = Message::UDP_BUTTON;
438   m->to = Command::getInstance();
439   m->from = this;
440         m->parameter=command;
441   Command::getInstance()->postMessageFromOuterSpace(m);
442 }