]> git.vomp.tv Git - vompclient-marten.git/blob - vmediaview.cc
Detect mpeg audio frame header changes, and wait at least 4 packets after a change...
[vompclient-marten.git] / vmediaview.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include <time.h>
22
23 #include "vmediaview.h"
24
25 #include "vpicturebanner.h"
26 #include "vcolourtuner.h"
27 #include "audioplayer.h"
28 #include "timers.h"
29 #include "boxx.h"
30 #include "wselectlist.h"
31 #include "remote.h"
32 #include "wsymbol.h"
33 #include "boxstack.h"
34 #include "vdr.h"
35 #include "media.h"
36 #include "video.h"
37 #include "vinfo.h"
38 #include "i18n.h"
39 #include "message.h"
40 #include "command.h"
41 #include "mediaoptions.h"
42 #include "mediaplayer.h"
43 #include "log.h"
44
45 const int VMediaView::EVENT_SLIDESHOW=100;
46 const int VMediaView::EVENT_DRAWINGDONE=101;
47 const int VMediaView::EVENT_DRAWINGERROR=102;
48 const int VMediaView::EVENT_DIRECTORYDONE=103;
49
50
51 /**
52   * the combined user interface for pictures and audio
53   * has 2 surfaces to enable drawing in a separate thread
54   * the info display can either show a picture info or and audio info
55   * if the audio player comes on top it disables the picture info display
56   * basically we have 3 modes:
57   *   - HIDDEN viewer is hidden (pictureEnabled=false, audioEnabled=false)
58   *     if justPlaying=true the audioplayer is still running
59   *   - PICTURE picture viewer on top ("slide show") - pictureEnabled=true, audioEnabled=false
60   *     no AudioBanner visible
61   *     if justPlaying=true the audio player runs in bg
62   *   - AUDIO audioPlayer on top ("playlist mode") - pictureEnabled=true, audioEnabled=true
63   *     the picture viewer is currently halted (should be able to continue if no AudioInfo)
64   *     no picture banner (we should have an audio banner to indicate the audio player on top!)
65   * state transitions (via setPictureMode, setAudioMode)
66   *   - show Picture -> pictureEnabled=true, 
67   *     only called from command handler if audioEnabled=false
68   *     call from mediaList only possible if audioEnabled=false
69   *         *** TODO: would be better to have separate function for external call/internal call
70   *   - play [Audio] -> if activate is set -> audioEnabled=true (-> Mode AUDIO)
71   *                     used for calls from medialist
72   *                     internal calls do not set activate!
73   *   - YELLOW key - toggle
74   *     if audioActive==true -> audioActive=false (new mode depends on pictureEnabled - either HIDDEN or PICTURE)
75   *     if audioActive==false -> audioActive=true (new mode AUDIO)
76   *          *** open handling if no audio file there (ignore key???) - currently empty player
77   *   - BACK if mode AUDIO -> audioEnabled=false, justPlaying=false
78   *   - BACK if mode PICTURE -> pictureEnabled=false;
79   *   - player StreamEnd -> audioEnabled=false (new mode depends on pciture - either HIDDEN or PICTURE)
80   * info/banner handling:
81   *   - AudioInfo - alternativ to pictureInfo
82   *     off when disabling audio or after timer or with OK in AUDIO mode
83   *     on currently any command or player event (end/new song) when audioEnabled==true and retriggerAudioInfo=true
84   *     on on OK in AUDIO mode
85   *   - Picture Info
86   *     off when disabling Picture or after timer, OK, green
87   *     on only on green when pictureEnabled==true
88   *   - PictureBanner
89   *     2 modes: loading/normal
90   *       normal:
91   *       off when disabling picture, OK, after timer
92   *       on when enabling picture, with OK
93   *       loading:
94   *       off when disabling picture and when loading done
95   *       on on start loading
96   *          *** open: do not show when audio enabled and slide show running (currently slideshow is paused)
97   *   - AudioBanner
98   *       always shown when audioEnabled=true
99   *       on when enabling Audio
100   *       off when disabling audio
101   *       update in play
102   * timers: 1 - slide show
103   *         2 - pictureBanner
104   *         3 - info showtime
105   *         4 - audio short update
106   */
107
108 #define DRAWING_THREAD
109
110 DrawStyle VMediaView::pictureBack=DrawStyle(140,140,140);
111 DrawStyle VMediaView::infoBack=DrawStyle(110,110,110);
112 DrawStyle VMediaView::audioBannerBack=DrawStyle(110,110,110,20);
113 //the jpeg reader
114
115 //how long do we wait for a single picture chunk
116 //the unit is 100ms (the timeout on the server side)
117 #define MAXTRY 100 
118 class VPreader : public JpegReader {
119   private:
120     ImageReader *reader;
121     VMediaView * parent;
122     ULLONG size;
123     bool dobreak;;
124   public:
125   VPreader(VMediaView *p,ImageReader *r){ 
126     parent=p;
127     size=0;
128     reader=r;
129     dobreak=false;
130   };
131   virtual ULONG readChunk(ULONG offset,ULONG len,char ** buf) {
132      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "read chunk o=%d,len=%d,buf=%p",
133         offset,len,*buf);
134      UINT numrec=0;
135      int rt=0;
136      for (int trycount=0;trycount < MAXTRY && ! dobreak && numrec == 0 && rt == 0;trycount++) {
137        if (dobreak) {
138          *buf=NULL;
139          rt=-1;
140        }
141        else {
142          rt=reader->getImageChunk((ULLONG)offset,(UINT)len,&numrec,(UCHAR **)buf);
143        }
144      }
145      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "got n=%d,buf=%p,rt=%d",
146         numrec,*buf,rt);
147      return numrec;
148      }
149   virtual int initRead(const MediaURI *uri,ULLONG *sz,ULONG factor=100) {
150      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s",uri->getDisplayName());
151      Video* video = Video::getInstance();
152      dobreak=false;
153      int rt=MediaPlayer::getInstance()->openMedium(1,uri,sz,video->getScreenWidth()*factor/100, video->getScreenHeight()*factor/100);
154      if (rt < 0) *sz=0;
155      size=*sz;
156      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s returned %llu",uri->getDisplayName(),size);
157      return rt;
158      }
159   virtual ULONG getSize() {return size;}
160   //seems to be thread safe (more or less...)
161   void setBreak() {
162     dobreak=true;
163   }
164 };
165
166 /**
167   * a separate thread for drawing pictures
168   * will be started with the sfc and the draw control
169   * will send a player event when done
170   */
171 class DrawingThread : public Thread_TYPE {
172   private:
173     VMediaView *_parent;
174     VPreader * _reader;
175     WJpegComplex::JpegControl *_ctl;
176     Surface *_sfc;
177     DrawStyle _colour;
178     bool _interrupted;
179   public:
180     DrawingThread(VMediaView *parent) {
181       _parent=parent;
182       _reader=NULL;
183       _ctl=NULL;
184       _sfc=NULL;
185       _interrupted=false;
186     }
187     virtual ~DrawingThread(){}
188     bool isRunning() {
189       return (threadIsActive()!=0);
190     }
191     bool start(WJpegComplex::JpegControl *ctl,Surface *sfc,VPreader *reader,DrawStyle &c) {
192       if (isRunning()) {
193         return false;
194       }
195       _interrupted=false;
196       _ctl=ctl;
197       _sfc=sfc;
198       _reader=reader;
199       _colour=c;
200       return (threadStart() == 1);
201     }
202     bool stop() {
203       Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop initiated");
204       if (threadIsActive()) {
205         _interrupted=true;
206         if (_reader) _reader->setBreak();
207         threadStop();
208       }
209       Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop done");
210       _reader=NULL;
211       return true;
212     }
213   protected:
214     virtual void threadMethod() {
215       Log::getInstance()->log("DrawingThread",Log::DEBUG,"started");
216       bool rt=WJpegComplex::drawJpeg(_ctl,_sfc,_reader,_colour);
217       _reader=NULL;
218       if (! _interrupted) {
219         Message* m = new Message(); 
220         //we misuse PLAYER_EVENT here
221         m->message = Message::PLAYER_EVENT;
222         m->to = _parent;
223         m->from = _parent;
224         m->parameter= rt?VMediaView::EVENT_DRAWINGDONE:VMediaView::EVENT_DRAWINGERROR;
225         Command::getInstance()->postMessageFromOuterSpace(m);
226       }
227       Log::getInstance()->log("DrawingThread",Log::DEBUG,"finishing interrupt=%d",(int)_interrupted);
228     }
229     virtual void threadPostStopCleanup() {}
230
231 };
232
233
234 VMediaView::VMediaView(VMediaList *p)
235 {
236   Log::getInstance()->log("VMediaView::VMediaView", Log::DEBUG, "p=%p", this);
237   audioEnabled=false;
238   pictureEnabled=false;
239   parent=p;
240   ireader=new ImageReader(1,MediaPlayer::getInstance());
241   reader=new VPreader(this,ireader);
242   //the surface handling
243   Video* video = Video::getInstance();
244   setSize(video->getScreenWidth(), video->getScreenHeight());
245   createBuffer();
246   sfc2=getSurface();
247   surface=NULL;
248   //create the second surface
249   createBuffer();
250   sfc1=getSurface();
251   originalh=area.h;
252   originalw=area.w;
253   //disable the surface
254   area.h=1;
255   area.w=1;
256   //banners and infos
257   pictureBanner=NULL;
258   slideshow=false;
259   pictureError=NULL;
260   currentPicture=NULL;
261   info=NULL;
262   pictureLoading=false;
263
264   //picture settings
265   showtime=INITIAL_SHOWTIME;
266   rotate=WJpegComplex::ROT_0;
267   currentScale=1;
268   options=MediaOptions::getInstance();
269   VColourTuner::initFactors();
270   int st=options->getIntOption("SlideShowInterval");
271   if (st > 0) showtime=st;
272   ctl.area.w=originalw;
273   ctl.area.h=originalh;
274   ctl.enlarge=false;
275   ctl.scaleafter=options->getIntOption("ScaleFactor");
276   const char * mode=options->getStringOption("PictureMode");
277   if (strcmp(mode,"clip") == 0) ctl.mode=WJpegComplex::CROP;
278   else if (strcmp(mode,"letter") == 0) ctl.mode=WJpegComplex::LETTER;
279   else if (strcmp(mode,"clipfactor") == 0) ctl.mode=WJpegComplex::CROPPERCENT;
280   ctl.scaleAmount=options->getIntOption("PictureSize");
281   if (ctl.scaleAmount < 10) ctl.scaleAmount=10;
282   if (ctl.scaleAmount > 200) ctl.scaleAmount=200;
283   ctl2=ctl;
284   cropmode=ctl.mode;
285   //current control is the one used for DISPLAY (not the one for drawing - this is the other one)
286   //this is closely coupled to the surface - i.e. ctl is for sfc1, ctl2 for sfc2
287   currentControl=&ctl;
288   bannerEnabled=true;
289   pictureShowing=false;
290
291   //audio player
292
293   barBlue.set(0, 0, 150, 150);
294   audioError=NULL;
295   currentAudio=NULL;
296   justPlaying=false;
297   playall=false;
298   retriggerAudioInfo=false;
299   audioBanner=NULL;
300   drawingThread=new DrawingThread(this);
301 }
302
303 VMediaView::~VMediaView()
304 {
305   Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "p=%p,secondSfc=%s", this,(secondSurface()?"true":"false"));
306   destroyPictureBanner();
307   if (currentPicture) delete currentPicture;
308   Timers::getInstance()->cancelTimer(this,1);
309   Timers::getInstance()->cancelTimer(this,2);
310   Timers::getInstance()->cancelTimer(this,3);
311   Timers::getInstance()->cancelTimer(this,4);
312   Timers::getInstance()->cancelTimer(this,5);
313   destroyInfo();
314   destroyAudioBanner();
315   if (getPlayer(false)) {
316     AudioPlayer::getInstance(NULL,false)->shutdown();
317   }
318   if (currentAudio) delete currentAudio;
319   drawingThread->stop();
320   ireader->shutdown();
321   delete ireader;
322   delete reader;
323   if (secondSurface()) {
324     delete sfc1;
325     sfc1=NULL;
326   }
327   else {
328     delete sfc2;
329     sfc2=NULL;
330   }
331   MediaPlayer::getInstance()->closeMediaChannel(1);
332   MediaPlayer::getInstance()->closeMediaChannel(2);
333   Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "done p=%p", this);
334 }
335
336 void VMediaView::setPictureMode(bool act) {
337   Log::getInstance()->log("VMediaView", Log::DEBUG, "set pictureMode %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);
338   if ( act) {
339     if ( ! pictureEnabled && ! audioEnabled) {
340       area.h=originalh;
341       area.w=originalw;
342       showPictureBanner();
343       parent->updateAll();
344     }
345     if (! pictureEnabled) {
346       //we newly enable the picture - so clear the screen
347       draw();
348       BoxStack::getInstance()->update(this);
349       if (slideshow) startSlideshow();
350     }
351   }
352   else 
353   {
354     if ( pictureEnabled) {
355       destroyPictureBanner();
356       stopSlideshow(false);
357 #ifdef DRAWING_THREAD
358       drawingThread->stop();
359 #endif
360       if (! audioEnabled) {
361         destroyInfo();
362         area.w=1;
363         area.h=1;
364         draw();
365         parent->updateAll();
366       }
367     }
368     pictureShowing=false;
369   }
370   pictureEnabled=act;
371 }
372
373 //we can disable audio without automatically hiding us
374 //this will become strange - we are visible but do not handle
375 //keys - so if you call setAudioMode(false,false) be sure
376 //to call setAudioMode(false,true) afterwards
377 //it is only here to give the list a chance to start a new play
378 //when we call directoryDone
379 void VMediaView::setAudioMode(bool act,bool doHiding) {
380   Log::getInstance()->log("VMediaView", Log::DEBUG, "setAudioMode  %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);
381   if ( act) {
382     if (! audioEnabled) {
383       if (! pictureEnabled) {
384         area.w=originalw;
385         area.h=originalh;
386         draw(); //empty screen if no picture
387         parent->updateAll();
388       }
389       destroyPictureBanner();
390
391     }
392     audioEnabled=true;
393     showAudioBanner();
394     showAudioInfo();
395   }
396   else 
397   {
398     if ( audioEnabled) {
399       audioEnabled=false;
400       destroyInfo();
401       destroyAudioBanner();
402     }
403     if (! pictureEnabled  && doHiding) {
404       area.w=1;
405       area.h=1;
406       draw();
407       parent->updateAll();
408     }
409     else {
410       //picture now on top
411       if (havePictureBanner && ! pictureBanner) showPictureBanner();
412     }
413   }
414 }
415
416
417
418 void VMediaView::draw()
419 {
420   Log::getInstance()->log("VMediaView::draw", Log::DEBUG, "pictureError=%s,p=%p", pictureError,this);
421   
422   if (pictureShowing ) fillColour(pictureBack);
423   else fillColour(DrawStyle::BLACK);
424   if (pictureError) {
425     drawText(pictureError,100,area.h/2,DrawStyle::LIGHTTEXT);
426     return;
427     }
428 }
429
430
431 int VMediaView::handleCommand(int command)
432 {
433   Log::getInstance()->log("VMediaView::handleCommand", Log::DEBUG, "cmd=%d,p=%p", command,this);
434   if ( !audioEnabled && ! pictureEnabled ) {
435     //only handle YELLOW
436     if (command == Remote::YELLOW) {
437       setAudioMode(true);
438       return 1;
439     }
440     return 0;
441   }
442   if ( ! audioEnabled) {
443     //------------------------- command in mode PICTURE (i.e. picture is on top) ----------------
444     //picture on top
445     int rt=1;
446     switch(command)
447     {
448       case Remote::DF_UP:
449       case Remote::UP:
450       case Remote::SKIPBACK:
451         rotate=WJpegComplex::ROT_0;
452         showPicture(VMediaList::MV_PREV,slideshow,true);
453         rt= 2;
454         break;
455       case Remote::FORWARD:
456         if (showtime > 1) showtime--;
457         updatePictureBanner(true);
458         break;
459       case Remote::DF_DOWN:
460       case Remote::DOWN:
461       case Remote::SKIPFORWARD:
462         rotate=WJpegComplex::ROT_0;
463         showPicture(VMediaList::MV_NEXT,slideshow,true);
464         rt= 2;
465         break;
466       case Remote::REVERSE:
467         if (showtime < 50 ) showtime++;
468         updatePictureBanner(true);
469         break;
470       case Remote::OK:
471       {
472         if (pictureBanner) {
473           destroyPictureBanner();
474           destroyInfo();
475           havePictureBanner=false;
476           }
477         else {
478           havePictureBanner=true;
479           showPictureBanner(pictureLoading);
480         }
481         rt= 2;
482       }
483       break;
484       case Remote::PLAY:
485       {
486         slideshow=true;
487         rotate=WJpegComplex::ROT_0;
488         showPicture(VMediaList::MV_NEXT,slideshow,true);
489         rt= 2;
490       }
491       break;
492       case Remote::PAUSE:
493         if (slideshow) {
494           stopSlideshow(true);
495           updatePictureBanner();
496         }
497         else {
498           slideshow=true;
499           rotate=WJpegComplex::ROT_0;
500           showPicture(VMediaList::MV_NEXT,slideshow,true);
501         }
502         rt= 2;
503         break;
504       case Remote::STOP:
505         stopSlideshow(true);
506         showtime=INITIAL_SHOWTIME;
507         updatePictureBanner();
508         rt= 2;
509         break;
510       case Remote::RED:
511         switch(rotate) {
512           case WJpegComplex::ROT_0:
513             rotate=WJpegComplex::ROT_90;
514             break;
515           case WJpegComplex::ROT_90:
516             rotate=WJpegComplex::ROT_180;
517             break;
518           case WJpegComplex::ROT_180:
519             rotate=WJpegComplex::ROT_270;
520             break;
521           case WJpegComplex::ROT_270:
522             rotate=WJpegComplex::ROT_0;
523             break;
524           }
525         showPicture(VMediaList::MV_NONE,slideshow,true);
526         rt=2;
527         break;
528       case Remote::GREEN:
529         if (info) destroyInfo();
530         else showPictureInfo();
531         rt=2;
532         break;
533       case Remote::BLUE:
534         switch (cropmode) {
535           case WJpegComplex::CROP:
536             cropmode=WJpegComplex::LETTER;
537             break;
538           case WJpegComplex::LETTER:
539             cropmode=WJpegComplex::CROPPERCENT;
540             break;
541           default:
542             cropmode=WJpegComplex::CROP;
543             break;
544         }
545         showPicture(VMediaList::MV_NONE,slideshow,true);
546         rt=2;
547         break;
548       case Remote::MENU: {
549         stopSlideshow(true);
550         destroyPictureBanner();
551         destroyInfo();
552         VColourTuner *ct=new VColourTuner();
553         BoxStack::getInstance()->add(ct);
554         ct->draw();
555         BoxStack::getInstance()->update(ct);
556         rt=2;
557        
558                          } break;
559       case Remote::BACK:
560       {
561         setPictureMode(false);
562         rt= 2;
563       }
564       break;
565       case Remote::YELLOW:
566       {
567         setAudioMode(true);
568       }
569     }
570     return rt;
571   } 
572   else 
573   {
574     int rt=1;
575     bool updateInfo=false;
576     //------------------------- command in mode AUDIO (i.e. audio is on top) ----------------
577     switch(command)
578     {
579       case Remote::YELLOW:
580         setAudioMode(false);
581         rt=2;
582         break;
583       case Remote::DF_UP:
584       case Remote::UP:
585         play(playall,false,VMediaList::MV_PREV);
586         rt= 2;
587         break;
588       case Remote::FORWARD:
589         if (! audioError) getPlayer()->fastForward();
590         updateInfo=true;
591         rt=2;
592         break;
593       case Remote::DF_DOWN:
594       case Remote::DOWN:
595         play(playall,false,VMediaList::MV_NEXT);
596         rt= 2;
597         break;
598       case Remote::SKIPFORWARD:
599         if (! audioError) getPlayer()->skipForward(10);
600         rt=2;
601         break;
602       case Remote::SKIPBACK:
603         if (! audioError) getPlayer()->skipBackward(10);
604         rt=2;
605         break;
606       case Remote::REVERSE:
607         rt=2;
608         break;
609       case Remote::ZERO:
610         if (! audioError) getPlayer()->jumpToPercent(0);
611         rt=2;
612         break;
613       case Remote::ONE:
614         if (! audioError) getPlayer()->jumpToPercent(10);
615         rt=2;
616         break;
617       case Remote::TWO:
618         if (! audioError) getPlayer()->jumpToPercent(20);
619         rt=2;
620         break;
621       case Remote::THREE:
622         if (! audioError) getPlayer()->jumpToPercent(30);
623         rt=2;
624         break;
625       case Remote::FOUR:
626         if (! audioError) getPlayer()->jumpToPercent(40);
627         rt=2;
628         break;
629       case Remote::FIVE:
630         if (! audioError) getPlayer()->jumpToPercent(50);
631         rt=2;
632         break;
633       case Remote::SIX:
634         if (! audioError) getPlayer()->jumpToPercent(60);
635         rt=2;
636         break;
637       case Remote::SEVEN:
638         if (! audioError) getPlayer()->jumpToPercent(70);
639         rt=2;
640         break;
641       case Remote::EIGHT:
642         if (! audioError) getPlayer()->jumpToPercent(80);
643         rt=2;
644         break;
645       case Remote::NINE:
646         if (! audioError) getPlayer()->jumpToPercent(90);
647         rt=2;
648         break;
649       case Remote::OK:
650       case Remote::GREEN:
651       {
652         if (info) {
653           destroyInfo();
654           retriggerAudioInfo=false;
655           }
656         else {
657           retriggerAudioInfo=true;
658           showAudioInfo();
659         }
660         if (getPlayer()->getState() == AudioPlayer::S_ERROR) {
661           if (playall) play(playall,false,VMediaList::MV_NEXT);
662         }
663         rt= 2;
664       }
665       break;
666       case Remote::PLAY:
667       {
668         if (! audioError) getPlayer()->unpause();
669         updateInfo=true;
670         if (getPlayer()->getState() != AudioPlayer::S_ERROR) ;
671         else if (playall) play(playall,false,VMediaList::MV_NEXT);
672         rt= 2;
673       }
674       break;
675       case Remote::PAUSE:
676         if (! audioError) getPlayer()->pause();
677         updateInfo=true;
678         rt= 2;
679         break;
680       case Remote::STOP:
681         getPlayer()->stop();
682         justPlaying=false;
683         updateInfo=true;
684         rt= 2;
685         break;
686       case Remote::BACK:
687       {
688         getPlayer()->stop();
689         playall=false;
690         retriggerAudioInfo=false;
691         justPlaying=false;
692         setAudioMode(false);
693         if (! pictureShowing) setPictureMode(false); //could have been delayed
694         rt= 2;
695       }
696       break;
697     }
698     if (audioEnabled && updateInfo) updateAudioInfo();
699     return rt;
700   }
701 }
702
703 void VMediaView::processMessage(Message* m)
704 {
705   Log::getInstance()->log("VMediaView::processMessage", Log::DEBUG, "cmd=%lu,p=%lu", m->message,m->parameter);
706   if (m->message == Message::MOUSE_MOVE)
707   {
708     ;
709   }
710   else if (m->message == Message::MOUSE_LBDOWN)
711   {
712     
713     //check if press is outside this view! then simulate cancel
714     int x=(m->parameter>>16)-getScreenX();
715     int y=(m->parameter&0xFFFF)-getScreenY();
716     if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
717     {
718       BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
719     }
720   }
721   else if (m->message = Message::PLAYER_EVENT) {
722     switch (m->parameter) {
723       case EVENT_SLIDESHOW:
724         if (! pictureEnabled) break; //old timer msg...
725         //if (! audioEnabled) {
726         if (true) {
727           if (slideshow) {
728             rotate=WJpegComplex::ROT_0;
729             showPicture(VMediaList::MV_NEXT,true,false);
730             startSlideshow();
731           }
732         }
733         break;
734       case EVENT_DRAWINGERROR:
735         drawingDone(true);
736         break;
737       case EVENT_DRAWINGDONE:
738         drawingDone(false);
739         break;
740       case EVENT_DIRECTORYDONE:
741         //just disable audio without (poetntially) hiding us
742         //this gives the list a chance to decide whether audio
743         //should be on top afterwards without showing the list
744         //immediately
745         setAudioMode(false,false);
746         parent->directoryDone();
747         if (! pictureShowing) setPictureMode(false);
748         if (! justPlaying) setAudioMode(false);
749         break;
750       case AudioPlayer::STREAM_ERR:
751       case AudioPlayer::STREAM_END:
752         if (playall) play(playall,false,VMediaList::MV_NEXT);
753         else {
754           setAudioMode(false);
755           justPlaying=false;
756         }
757         break;
758       case AudioPlayer::SHORT_UPDATE:
759                                 if (info && audioEnabled ) {
760                                         drawAudioClocks();
761                                         BoxStack::getInstance()->update(info,&clocksRegion);
762                                   BoxStack::getInstance()->update(info,&barRegion);
763                                         Timers::getInstance()->setTimerD(this, 4, 1);
764                                 }
765         break;
766       case AudioPlayer::NEW_SONG:
767         if (audioEnabled) updateAudioInfo();
768         break;
769       case AudioPlayer::CONNECTION_LOST:
770         if (audioEnabled) destroyInfo();
771         if (AudioPlayer *player=getPlayer(false)) {
772           player->shutdown();
773           player=NULL;
774         }
775         Command::getInstance()->connectionLost();
776         break;
777     }
778   }
779 }
780
781
782 VMediaView * VMediaView::createViewer(VMediaList * mparent) {
783    Log::getInstance()->log("VMediaView::createViewer", Log::DEBUG, "p=%p",
784         mparent);
785    VMediaView *vmn=new VMediaView(mparent);
786    BoxStack::getInstance()->add(vmn);
787    vmn->draw();
788    BoxStack::getInstance()->update(vmn);
789    return vmn;
790 }
791
792 void VMediaView::startSlideshow() {
793    slideshow=true;
794    if (! pictureLoading) Timers::getInstance()->setTimerD(this,1,showtime);
795 }
796
797 void VMediaView::stopSlideshow(bool hard) {
798    if (hard) slideshow=false;
799    Timers::getInstance()->cancelTimer(this,1);
800 }
801
802
803 void VMediaView::showPicture(ULONG move,bool bslideshow,bool activateBanner) {
804   pictureShowing=true;
805   setPictureMode(true);
806   stopSlideshow(true);
807 #ifdef DRAWING_THREAD
808   drawingThread->stop();
809 #endif
810   slideshow=bslideshow;
811   Media *newPicture=parent->getMedia(MEDIA_TYPE_PICTURE,move);
812   if ( ! newPicture) {
813     pictureShowing=false;
814     if (!audioEnabled) {
815       //within the event handler first directoryDone is called
816       //and afterwards everything is stopped if nothing new
817       sendCommandMsg(EVENT_DIRECTORYDONE);
818     }
819     slideshow=false;
820   }
821   else 
822   {
823     pictureShowing=true;
824     if (currentPicture) {
825       delete currentPicture;
826       currentPicture=NULL;
827     }
828     currentPicture=newPicture;
829     loadPicture(currentPicture,activateBanner);
830   }
831 }
832
833 //the real picture drawing method
834 //will start drawing on a new surface and will switch it wehn done
835
836 int VMediaView::loadPicture(Media *md,bool activateBanner) {
837   pictureError=NULL;
838   if (! md) return 1;
839   if (! md->getURI()) {
840     pictureError=tr("No media found");
841     Log::getInstance()->log("VMediaView::load",Log::ERR,"no URI in media");
842     return 1;
843   }
844   Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",
845         md->getURI()->getName(),this);
846   //do we have a pictureBanner?
847   havePictureBanner=pictureBanner!=NULL || activateBanner;
848   pictureLoading=true;
849 #ifdef DRAWING_THREAD
850   if (!audioEnabled && havePictureBanner ) showPictureBanner(true);
851   drawingThread->stop();
852 #else
853   showPictureBanner(true);
854 #endif
855   ireader->stop();
856   ULLONG size=0;
857   int rtok=reader->initRead(md->getURI(),&size,ctl.scaleAmount); //scaleAmount is the same for both...
858   if (rtok == 0) {
859      //now we can really draw
860      //get the surface for drawing
861      Surface * drawSurface=NULL;
862      WJpegComplex::JpegControl *drawCtl=NULL;
863      getDrawingParam(drawSurface,drawCtl);
864      drawCtl->error[0]=0;
865      drawCtl->rotation=rotate;
866      drawCtl->mode=cropmode;
867      drawCtl->compressedSize=size;
868 #ifdef DRAWING_THREAD
869      bool ok=drawingThread->start(drawCtl,drawSurface,reader,pictureBack);
870      if (! ok) {
871        Log::getInstance()->log("VMediaView::load", Log::ERR, "unable to start drawing thread");
872        pictureError=tr("JpegError");
873        pictureLoading=false;
874        destroyPictureBanner();
875        return 1;
876      }
877      return 0;
878 #else
879      //here we could hand this over to the drawing thread
880      bool ok=WJpegComplex::drawJpeg(drawCtl,drawSurface,reader,pictureBack);
881      drawingDone(!ok);
882      return ok?0:1;
883 #endif
884   }
885   pictureLoading=false;
886   return 1;
887 }
888
889 void VMediaView::drawingDone(bool hasError) {
890   pictureLoading=false;
891   destroyPictureBanner(); //disable loading indication (or real banner)
892   if (! hasError) {
893     switchSurface();
894     Log::getInstance()->log("VMediaView::drawingDone", Log::DEBUG, "success: sfc now=%p",surface);
895     pictureError=NULL;
896     //only show the pictureBanner if it was there before
897     if (havePictureBanner && ! audioEnabled) showPictureBanner();
898     Log::getInstance()->log("VMediaView::load", Log::DEBUG, "success" );
899     updatePictureInfo(); //will only do somethng if pictureEnabled
900   }
901   else 
902   {
903     pictureError=tr("JpegError");
904     if (pictureEnabled) {
905       draw();
906       destroyInfo();
907     }
908   }
909   MediaPlayer::getInstance()->closeMediaChannel(1);
910 #ifndef DRAWING_THREAD
911   if (audioEnabled) showAudioBanner();
912 #endif
913   if (slideshow) startSlideshow();
914   BoxStack::getInstance()->update(this);
915 }
916
917 void VMediaView::showPictureBanner(bool loading) {
918   //we are in the main thread - so we can (and must) safely hard destroy/create the banner
919   Timers::getInstance()->cancelTimer(this,2);
920   if (! currentPicture) {
921     //hmm...
922     destroyPictureBanner(false);
923     return;
924     }
925   if (pictureBanner) destroyPictureBanner(false);
926   if (! pictureEnabled || ! bannerEnabled) return;
927   pictureBanner= new VPictureBanner(loading, slideshow);
928   pictureBanner->fillColour(infoBack);
929   if (! loading) {
930     int len=strlen(currentPicture->getFileName())+Media::TIMEBUFLEN+20;
931     char *buf=new char[len];
932     char tbuf[Media::TIMEBUFLEN];
933     SNPRINTF(buf,len,"%c%02ds%c %s %s " ,
934       slideshow?' ':'[',
935       showtime,
936       slideshow?' ':']',
937       currentPicture->getTimeString(tbuf),
938       currentPicture->getFileName()
939       );
940     pictureBanner->setText(buf);
941     delete [] buf;
942   }
943   else {
944     char *buf=new char[strlen(currentPicture->getDisplayName())+50];
945     SNPRINTF(buf,50,"%s %s",tr("Loading"), currentPicture->getDisplayName());
946     pictureBanner->setText(buf);
947     delete buf;
948   }
949   pictureBanner->draw();
950   if (! loading )   Timers::getInstance()->setTimerD(this,2,8);
951   BoxStack::getInstance()->add(pictureBanner);
952   BoxStack::getInstance()->update(pictureBanner);
953   }
954
955 void VMediaView::destroyPictureBanner(bool fromTimer) {
956   if (pictureBanner) {
957     if (fromTimer) sendViewMsg(pictureBanner); 
958     else BoxStack::getInstance()->remove(pictureBanner);
959     pictureBanner=NULL;
960     if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);
961     }
962 }
963 void VMediaView::updatePictureBanner(bool loading) {
964   if (pictureBanner ) {
965     showPictureBanner(loading);
966     }
967 }
968 void VMediaView::timercall(int clientref) {
969    Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "id=%d",clientref);
970    switch(clientref)
971    {
972       case 4:
973         {
974           sendCommandMsg(AudioPlayer::SHORT_UPDATE);
975           break;
976         }
977       case 3:
978         {
979           Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "infoEnd");
980           destroyInfo(true);
981           if (audioEnabled) {
982             //we only did show the audio error info if audio is enabled
983             bool stillError=false;
984             if (AudioPlayer * player=getPlayer(false)) {
985               stillError=player->getState()==AudioPlayer::S_ERROR;
986             }
987             if (stillError) {
988               sendCommandMsg(AudioPlayer::STREAM_END);
989             }
990           }
991           break;
992         }
993       case 1:
994         if (! slideshow) return;
995         Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "slideshow");
996         sendCommandMsg(EVENT_SLIDESHOW);
997         break;
998       case 2:
999         Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "pictureBannerEnd");
1000         destroyPictureBanner(true);
1001         break;
1002     }
1003    
1004   }
1005
1006 #define INFOBUF 2000
1007 void VMediaView::showPictureInfo(){
1008   if (! pictureEnabled || audioEnabled) return;
1009   if (info) destroyInfo();
1010   if (! currentPicture) return;
1011
1012   info=new VInfo();
1013   info->setTitleText(currentPicture->getFileName());
1014   info->setDropThrough();
1015   info->setSize(500, 300);
1016   info->createBuffer();
1017   info->setBorderOn(1);
1018   info->setTitleBarOn(1);
1019
1020   if (Video::getInstance()->getFormat() == Video::PAL)
1021         info->setPosition(100, 180);
1022   else
1023         info->setPosition(100, 150);
1024   char buf[INFOBUF];
1025   char tbuf[Media::TIMEBUFLEN];
1026   //modes should come from mediaoptions...
1027   const char *mode=NULL;
1028   switch (currentControl->mode) {
1029     case WJpegComplex::CROPPERCENT:
1030       mode="clipfactor";
1031       break;
1032     case WJpegComplex::LETTER:
1033       mode="letter";
1034       break;
1035     default:
1036       mode="clip";
1037       break;
1038   }
1039   const char *dirname=parent->getDirname(MEDIA_TYPE_PICTURE);
1040   int ldir=0;
1041   const char *prfx="";
1042   if (dirname) ldir=strlen(dirname);
1043   if (ldir > 35){
1044     dirname=dirname+ldir-35;
1045     prfx="...";
1046   }
1047   SNPRINTF(buf,INFOBUF,"%s= %s%s\n%s= %u x %u\n%s= %lu kBytes\n%s= %s\n%s= %u\n%s= %u%%\n%s= %s",
1048      tr("Directory"), prfx,dirname,
1049      tr("Format(px)"),currentControl->picw,currentControl->pich,
1050      tr("Filesize"),currentControl->compressedSize/1000,
1051      tr("Time"),currentPicture->getTimeString(tbuf),
1052      tr("Rotation"),90*currentControl->finalRotation,
1053      tr("Scale"),currentControl->scale,
1054      tr("Picture Mode"),mode );
1055   info->setMainText(buf);
1056   info->draw();
1057   BoxStack::getInstance()->add(info);
1058   BoxStack::getInstance()->update(info);
1059   Timers::getInstance()->setTimerD(this,3,8);
1060 }
1061 void VMediaView::updatePictureInfo(){
1062   if (info) {
1063     showPictureInfo();
1064     }
1065 }
1066 void VMediaView::destroyInfo(bool fromTimer){
1067   if (info) {
1068     if (! fromTimer) {
1069       Log::getInstance()->log("VMediaView",Log::DEBUG,"remove info %p",info);
1070       BoxStack::getInstance()->remove(info);
1071     }
1072     else {
1073       Log::getInstance()->log("VMediaView",Log::DEBUG,"trigger remove info %p",info);
1074       sendViewMsg(info);
1075     }
1076     info=NULL;
1077     }
1078   if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);
1079   if (! fromTimer) Timers::getInstance()->cancelTimer(this,4);
1080 }
1081
1082 void VMediaView::sendViewMsg(Boxx *v) {
1083   Message* m = new Message(); 
1084   m->message = Message::CLOSE_ME;
1085   m->to = BoxStack::getInstance();
1086   m->from = v;
1087   m->parameter=(ULONG)v;
1088   Command::getInstance()->postMessageFromOuterSpace(m);
1089 }
1090 void VMediaView::sendCommandMsg(int command) {
1091   Message* m = new Message(); 
1092   //we misuse PLAYER_EVENT here
1093   m->message = Message::PLAYER_EVENT;
1094   m->to = this;
1095   m->from = this;
1096   m->parameter= command;
1097   Command::getInstance()->postMessageFromOuterSpace(m);
1098 }
1099
1100 void VMediaView::enableBanner(bool enable) {
1101   bannerEnabled=false;
1102   updatePictureBanner();
1103 }
1104
1105 void VMediaView::getDrawingParam(Surface *&sfc,WJpegComplex::JpegControl *&c){
1106   if (secondSurface()) {
1107     //we currently display on sfc2
1108     sfc=sfc1;
1109     c=&ctl;
1110   }
1111   else {
1112     sfc=sfc2;
1113     c=&ctl2;
1114   }
1115 }
1116 void VMediaView::switchSurface(){
1117   if (secondSurface()) {
1118     //now we switch to sfc1
1119     surface=sfc1;
1120     currentControl=&ctl;
1121   }
1122   else {
1123     surface=sfc2;
1124     currentControl=&ctl2;
1125   }
1126 }
1127
1128 AudioPlayer * VMediaView::getPlayer(bool createIfNeeded)
1129 {
1130   AudioPlayer* rt=AudioPlayer::getInstance(this,false);
1131   if (! createIfNeeded && rt == NULL) return NULL;
1132   if (rt == NULL) {
1133     rt=AudioPlayer::getInstance(this);
1134     rt->run();
1135   }
1136   return rt;
1137 }
1138
1139 bool VMediaView::isAudioPlaying() {
1140   Log::getInstance()->log("VMediaView::isPlaying", Log::DEBUG, "rt=%s", justPlaying?"true":"false");
1141   return justPlaying;
1142 }
1143
1144
1145
1146
1147
1148
1149 int VMediaView::play(bool all,bool activate,ULONG move,bool showInfo) {
1150   int rt=0;
1151   if (getPlayer(false)) getPlayer(false)->stop();
1152   justPlaying=false;
1153   if (currentAudio) delete currentAudio;
1154   currentAudio=NULL;
1155   playall=all;
1156   currentAudio=parent->getMedia(MEDIA_TYPE_AUDIO,move);
1157   audioError=NULL;
1158   if ( ! currentAudio || ! currentAudio->getURI()) {
1159     Log::getInstance()->log("VMediaView::load", Log::ERR, "no URI in media");
1160     audioError=tr("no audio file");
1161     if (audioEnabled) sendCommandMsg(EVENT_DIRECTORYDONE);
1162     rt= -1;
1163   }
1164   else {
1165     Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",
1166       currentAudio->getURI()->getName(),this);
1167     int wseq=getPlayer()->play(currentAudio->getURI());
1168     if (getPlayer()->waitForSequence(5,wseq)<0) {
1169        audioError=tr("unable to open audio file");
1170        rt= -1;
1171     }
1172     else {
1173       justPlaying=true;
1174       rt=0;
1175     }
1176     Log::getInstance()->log("VMediaView", Log::DEBUG, "player started for %s",currentAudio->getURI()->getName());
1177   }
1178   if (activate && ! audioEnabled){
1179     if (showInfo) retriggerAudioInfo=true;
1180     setAudioMode(true);
1181   }
1182   else {
1183     //avoid duplicate creation of banner and info
1184     showAudioBanner();
1185     showAudioInfo();
1186   }
1187   if (activate && (! currentPicture || ! pictureShowing)) draw();
1188   BoxStack::getInstance()->update(this);
1189   return rt;
1190 }
1191
1192 void VMediaView::showAudioInfo() {
1193   if (! audioEnabled) return;
1194   Timers::getInstance()->cancelTimer(this,4);
1195   Timers::getInstance()->cancelTimer(this,3);
1196   if (info) destroyInfo();
1197   if (! retriggerAudioInfo) return;
1198   drawAudioInfo();
1199   bool playerError=getPlayer()->getState()==AudioPlayer::S_ERROR || audioError;
1200   if (! playerError) Timers::getInstance()->setTimerD(this,3,AUDIOBANNER_TIME);
1201   else Timers::getInstance()->setTimerD(this,3,AUDIOERROR_TIME);
1202         if (! playerError) Timers::getInstance()->setTimerD(this,4, 1);
1203   BoxStack::getInstance()->update(info);
1204   }
1205
1206 void VMediaView::updateAudioInfo() {
1207   if (info) {
1208     showAudioInfo();
1209     }
1210 }
1211
1212 void VMediaView::drawAudioInfo(){
1213   Log::getInstance()->log("VMediaView",Log::DEBUG, "draw banner for %p",info);
1214   const char *title=NULL;
1215   char *playerTitle=NULL;
1216   bool playerError=false;
1217   int numlines=0;
1218   int len=0;
1219   int num=0;
1220   const char *pl=tr("Playlist");
1221   const char *first=NULL;
1222   char *playerInfo=NULL;
1223   if (audioError) {
1224     if (getPlayer()->getState() == AudioPlayer::S_PLAY) audioError=NULL;
1225   }
1226   if (! currentAudio && ! audioError) audioError=tr("no audio file");
1227   if (audioError ) {
1228     title=tr("MediaError");
1229   }
1230   else {
1231     playerTitle=getPlayer()->getTitle();
1232     if (playerTitle) title=playerTitle;
1233     else title=currentAudio->getDisplayName();
1234     num=parent->getNumEntries(MEDIA_TYPE_AUDIO,currentAudio->index);
1235     playerError=getPlayer()->getState() == AudioPlayer::S_ERROR;
1236     //1more line for long dirs
1237     numlines=playall?5:4;
1238   }
1239   if (playerError) {
1240     numlines=3;
1241     first=tr("Unable to play audio file");
1242     len=strlen(first)+3;
1243   }
1244   else if (audioError) {
1245     numlines=3;
1246     first=audioError;
1247     len=strlen(first)+3;
1248   }
1249   else {
1250     playerInfo=getPlayer()->getID3Info();drawText(tr("Loading"),5,3,DrawStyle::LIGHTTEXT);
1251     len=strlen(currentAudio->getDisplayName())+strlen(pl)+30+strlen(parent->getDirname(MEDIA_TYPE_AUDIO))+Media::TIMEBUFLEN+110;
1252     if (playerInfo) {
1253       for (UINT i=0;i<strlen(playerInfo);i++) 
1254         if (playerInfo[i] == '\n') numlines++;
1255       len+=strlen(playerInfo);
1256       first=playerInfo;
1257     }
1258     else {
1259       first="";
1260     }
1261   }
1262   destroyInfo();
1263   info=new VInfo();
1264   UINT height=numlines*30+60;
1265   UINT vheight=Video::getInstance()->getScreenHeight();
1266   UINT vwidth=Video::getInstance()->getScreenWidth();
1267   if (height > vheight-2*AUDIOBANNER_BOTTOM_MARGIN)
1268     height=vheight-2*AUDIOBANNER_BOTTOM_MARGIN;
1269   info->setSize(vwidth -2*AUDIOBANNER_X_MARGIN, height);
1270   info->createBuffer();
1271   if (Video::getInstance()->getFormat() == Video::PAL)
1272   {
1273     info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);
1274   }
1275   else
1276   {
1277     info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);
1278   }
1279
1280   info->setTitleBarOn(0);
1281   info->setDropThrough();
1282   //from vvideorec 
1283         //set the regions for the closcks and bars on banner
1284   barRegion.x = info->getWidth()-AUDIOBARLEN-20;
1285   barRegion.y = info->getHeight() - 30;   // FIXME, need to be - 1? and below?
1286   barRegion.w = info->getWidth()-AUDIOBARLEN+10;
1287   barRegion.h = 30;
1288
1289   clocksRegion.x = 130;
1290   clocksRegion.y = barRegion.y + 3;
1291   clocksRegion.w = 190;
1292   clocksRegion.h = getFontHeight();
1293   Log::getInstance()->log("VMediaView",Log::DEBUG,"created AudioInfo %p",info);
1294   BoxStack::getInstance()->add(info);
1295   char *buf=new char [len];
1296   if (playerError || audioError) {
1297     SNPRINTF(buf,len,"%s",first);
1298   }
1299   else {
1300     char tbuf[Media::TIMEBUFLEN];
1301     if (playall) {
1302     SNPRINTF(buf,len,"%s\n"
1303         "%s:%s\n"
1304         "%s: %d/%d\n"
1305         "%s:%s\n"
1306         "%s:%s\n",
1307         first,
1308         tr("FileName"),currentAudio->getDisplayName(),
1309         pl,num,parent->getNumEntries(MEDIA_TYPE_AUDIO),
1310         tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),
1311         tr("Time"),currentAudio->getTimeString(tbuf));
1312     }
1313     else {
1314     SNPRINTF(buf,len,"%s\n"
1315         "%s:%s\n"
1316         "%s:%s\n"
1317         "%s:%s\n",
1318         first,
1319         tr("FileName"),currentAudio->getDisplayName(),
1320         tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),
1321         tr("Time"),currentAudio->getTimeString(tbuf));
1322     }
1323   }
1324   Log::getInstance()->log("VMediaView",Log::DEBUG,"info: (%d)%s",strlen(buf),buf);
1325   //now the real drawing functions
1326   info->draw();
1327   //title
1328   info->rectangle(0, 0, info->getWidth(), 30, DrawStyle::TITLEBARBACKGROUND);
1329   info->drawText(title, 5, 5, DrawStyle::LIGHTTEXT);
1330   info->drawPara(buf,5,32,DrawStyle::LIGHTTEXT);
1331   delete [] buf;
1332   if (! audioError) {
1333     WSymbol w;
1334     info->TEMPADD(&w);
1335     int x=10;
1336     int ybottom=info->getHeight();
1337     info->rectangle(0, ybottom - barRegion.h, info->getWidth(), barRegion.h, DrawStyle::TITLEBARBACKGROUND);
1338     bool drawSymbol=true;
1339     switch(getPlayer()->getState()) {
1340       case AudioPlayer::S_PAUSE:
1341         w.nextSymbol = WSymbol::PAUSE;
1342         break;
1343       case AudioPlayer::S_PLAY:
1344         w.nextSymbol = WSymbol::PLAY;
1345         break;
1346       case AudioPlayer::S_DONE:
1347         if (playall) 
1348           w.nextSymbol = WSymbol::PLAY;
1349         else
1350           drawSymbol=false;
1351         break;
1352       case AudioPlayer::S_BACK:
1353         w.nextSymbol = WSymbol::FBWD ;
1354         break;
1355       case AudioPlayer::S_FF:
1356         w.nextSymbol = WSymbol::FFWD ;
1357         break;
1358       default:
1359         drawSymbol=false;
1360         break;
1361     }
1362     if (drawSymbol) {
1363       w.setPosition(x, ybottom-24);
1364       w.draw();
1365     }
1366     else {
1367       //stop symbol
1368       info->rectangle(x, ybottom - 23, 18, 16, DrawStyle::LIGHTTEXT);
1369     }
1370     x+=30;
1371     drawAudioClocks();
1372   }
1373   if (playerInfo) delete playerInfo;
1374   if (playerTitle) delete playerTitle;
1375 }
1376
1377 void VMediaView::drawAudioClocks() {
1378         if (! info || ! audioEnabled) return;
1379         Log::getInstance()->log("VMediaView::drawAudioClocks", Log::DEBUG, "");
1380   //draw clocks and bar
1381   info->rectangle(clocksRegion, DrawStyle::TITLEBARBACKGROUND);
1382
1383   time_t currentSec = (time_t)(getPlayer()->getCurrentTimes());
1384   time_t lengthSec=(time_t)(getPlayer()->getSonglen());
1385         struct tm cpos;
1386         struct tm slen;
1387 /*      gmtime_r(&currentSec,&cpos);
1388         gmtime_r(&lengthSec,&slen);*/
1389     cpos.tm_hour=currentSec/3600;
1390     cpos.tm_min=(currentSec-cpos.tm_hour*3600)/60;
1391     cpos.tm_sec=(currentSec-cpos.tm_hour*3600-cpos.tm_min*60);
1392     slen.tm_hour=lengthSec/3600;;
1393     slen.tm_min=(lengthSec-slen.tm_hour*3600)/60;
1394     slen.tm_sec=(lengthSec-slen.tm_hour*3600-slen.tm_min*60);
1395
1396   char buffer[100];
1397   if (currentSec >= lengthSec)
1398   {
1399     SNPRINTF(buffer,99, "-:--:-- / -:--:--  %03dk",getPlayer()->getCurrentBitrate()/1000);
1400   }
1401   else
1402   {
1403     SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i  %03dk", cpos.tm_hour, cpos.tm_min, cpos.tm_sec, slen.tm_hour, slen.tm_min, slen.tm_sec,
1404                                 getPlayer()->getCurrentBitrate()/1000);
1405                 //Log::getInstance()->log("VMediaView", Log::DEBUG, buffer);
1406   }
1407
1408   info->drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);
1409   
1410         // Draw progress bar
1411   int progBarXbase = 0;
1412         int barlen=250;
1413
1414   info->rectangle(barRegion.x + progBarXbase, barRegion.y + 3, barlen+10, 24, DrawStyle::LIGHTTEXT);
1415   info->rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 5, barlen+6, 20, barBlue);
1416
1417   if (currentSec > lengthSec) currentSec=lengthSec;
1418   if (lengthSec == 0) return;
1419
1420   // Draw yellow portion
1421   int progressWidth = (barlen+2) * currentSec / lengthSec;
1422   info->rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 7, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
1423
1424 }
1425
1426 void VMediaView::showAudioBanner() {
1427   destroyAudioBanner();
1428   if (! audioEnabled) return;
1429   audioBanner=new VInfo();
1430   Log::getInstance()->log("VMediaView",Log::DEBUG,"creating AudioBanner %p", audioBanner);
1431   Video *v=Video::getInstance();
1432   audioBanner->setSize(v->getScreenWidth()-100, 36);
1433   audioBanner->createBuffer();
1434   audioBanner->setPosition(50, v->getScreenHeight()-50);
1435   audioBanner->fillColour(audioBannerBack);
1436   audioBanner->setTitleBarOn(0);
1437   audioBanner->setDropThrough();
1438   if ( ! currentAudio || ! currentAudio->getDisplayName() || audioError) {
1439     audioBanner->drawText(tr("AudioPlayer - not playing"),5,3,DrawStyle::LIGHTTEXT);
1440   }
1441   else {
1442     char * buf=new char[strlen(currentAudio->getDisplayName())+50];
1443     SNPRINTF(buf,50,"%s %s",tr("AudioPlayer"),currentAudio->getDisplayName());
1444     audioBanner->drawText(buf,5,3,DrawStyle::LIGHTTEXT);
1445     delete buf;
1446   }
1447   BoxStack::getInstance()->add(audioBanner);
1448   BoxStack::getInstance()->update(audioBanner);
1449 }
1450
1451 void VMediaView::destroyAudioBanner() {
1452   if (audioBanner) {
1453     Log::getInstance()->log("VMediaView",Log::DEBUG,"deleting AudioBanner %p",audioBanner);
1454     BoxStack::getInstance()->remove(audioBanner);
1455     audioBanner=NULL;
1456   }
1457 }