]> git.vomp.tv Git - vompclient.git/blob - osdvector.cc
Channel logo support, PNG hardware support, bugfixes and channel logos in all menus
[vompclient.git] / osdvector.cc
1 /*
2     Copyright 2012 Marten Richter
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 "osdvector.h"
22 #include "surfacevector.h"
23 #include "vdr.h"
24 #include "vdrresponsepacket.h"
25 #include "command.h"
26 #include "message.h"
27
28 // The next section is activated, if the magick++ PictureReader is provided, it should be available for many POSIX platforms
29 #ifdef PICTURE_DECODER_MAGICK
30 #include <Magick++.h>
31
32 using namespace Magick;
33
34 class MagickDecoder: public OsdVector::PictureDecoder {
35 public:
36         MagickDecoder(OsdVector::PictureReader* treader): OsdVector::PictureDecoder(treader) {pictInfValid=false;};
37
38         unsigned char *decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem);
39
40     bool getDecodedPicture( struct OsdVector::PictureInfo& pict_inf);
41
42     void freeReference(void * ref);
43
44 protected:
45     OsdVector::PictureInfo pictInf;
46         bool pictInfValid;
47 };
48
49 unsigned char * MagickDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem)
50 {
51         if (pictInfValid) return buffer; // does support only one image at a Time;
52         Image magicimage;
53         Blob *imageblob = new Blob();
54         Blob myblob;
55         try{
56                 Log::getInstance()->log("MagickDecoder", Log::DEBUG, "decodePicture");
57
58                 if (freemem) myblob.updateNoCopy(buffer,length,Blob::MallocAllocator);
59                 else myblob.update(buffer,length);
60                 magicimage.read(myblob);
61
62                 magicimage.write(imageblob,"RGBA");
63
64         }catch( Exception &error_ )
65         {
66                 Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: %s",error_.what());
67                 delete imageblob;
68                 Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: error mark2");
69                 unsigned char* newbuffer=(unsigned char*) malloc(length);
70                 memcpy(newbuffer,myblob.data(),length);
71                 return newbuffer;
72         }
73         pictInf.reference = (void*) imageblob;
74         pictInf.width = magicimage.columns();
75         pictInf.height = magicimage.rows();
76         pictInf.image = imageblob->data();
77         pictInf.decoder = this;
78         pictInf.type = OsdVector::PictureInfo::RGBAMemBlock;
79         pictInf.lindex = index;
80         pictInfValid = true;
81
82
83
84         // I can handle everything, so the return value is always true
85         return NULL;
86 }
87 void MagickDecoder::freeReference(void * ref)
88 {
89         Blob *todelete = (Blob*) ref;
90         delete todelete;
91 }
92
93 bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
94 {
95         if (!pictInfValid) return false;
96         pict_inf=pictInf;
97         pictInfValid = false;
98         return true;
99 }
100
101
102 #endif
103
104 OsdVector::OsdVector()
105 {
106         setlocale(LC_CTYPE,"C.UTF-8");
107 #ifdef PICTURE_DECODER_MAGICK
108         reader.addDecoder(new MagickDecoder(&reader));
109 #endif
110
111 }
112
113 OsdVector::~OsdVector()
114 {
115 }
116
117
118 int OsdVector::getFD()
119 {
120         return 0;
121 }
122
123 void OsdVector::screenShot(const char* fileName)
124 {
125         //Do nothing,
126 }
127
128 Surface * OsdVector::createNewSurface()
129 {
130         return new SurfaceVector(this);
131 }
132
133 void OsdVector::BeginPainting()
134 {
135         surfaces_mutex.Lock();
136 }
137 void OsdVector::EndPainting()
138 {
139         surfaces_mutex.Unlock();
140 }
141
142 void OsdVector::Blank()
143 {
144         // do nothing? remove this one?
145 }
146
147 int OsdVector::restore()
148 {
149         // First clear the contents of all registered surfaces
150         surfaces_mutex.Lock();
151
152         //Now go through all surfaces and draw them
153         list<SurfaceCommands>::iterator curdraw=scommands.begin();
154         while (curdraw!=scommands.end()) {
155                 (*curdraw).commands.clear();
156                 curdraw++;
157         }
158         //also clear all handles, they are now invalid, no need to release them
159         images_ref.clear();
160         monobitmaps.clear();
161         //jpegs.clear();
162         styles.clear();
163         styles_ref.clear();
164         palettepics.clear();
165
166         tvmedias.clear();
167         loadindex_ref.clear();
168         tvmedias_load.clear();
169         tvmedias_load_inv.clear();
170         tvmedias_loaded.clear();
171
172         surfaces_mutex.Unlock();
173         return 1;
174 }
175
176 void OsdVector::drawSurfaces()
177 {
178         surfaces_mutex.Lock();
179         list<SurfaceCommands*> todraw; //First figure out if a surfaces is below another surface
180         list<SurfaceCommands>::iterator itty1=scommands.begin();
181         while (itty1!=scommands.end()) {
182                 list<SurfaceCommands>::iterator itty2=itty1;
183                 itty2++;
184                 bool hidden=false;
185                 while (itty2!=scommands.end()) {
186                         SurfaceCommands & ref1=*itty1;
187                         SurfaceCommands & ref2=*itty2;
188                         if (ref1.x>=ref2.x && ref1.y>=ref2.y
189                                         && (ref1.x+ref1.w) <= (ref2.x+ref2.w)
190                                         && (ref1.y+ref1.h) <= (ref2.y+ref2.h) ) {
191                                 hidden=true;
192                                 break;
193                         }
194                         itty2++;
195                 }
196                 if (!hidden) { // we are not hidden, perfect
197                         todraw.push_back(&(*itty1));
198                 }
199                 itty1++;
200         }
201         int swidth,sheight;
202         getScreenSize(swidth,sheight);
203         //Now go through all surfaces and draw them
204         list<SurfaceCommands*>::iterator curdraw=todraw.begin();
205         while (curdraw!=todraw.end()) {
206                 drawSetTrans(*(*curdraw));
207                 list<SVGCommand>::iterator commands=(*(*curdraw)).commands.begin();
208                 list<SVGCommand>::iterator end=(*(*curdraw)).commands.end();
209                 while (commands!=end) {
210                         // update any images loaded in the mean time
211                         if ((*commands).instr==DrawImageLoading) {
212                                 LoadIndex loadindex=(*commands).target.loadindex;
213                                 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
214                                         (*commands).instr=DrawImage;
215                                         (*commands).target.image=tvmedias_loaded[loadindex];;
216                                         incImageRef((*commands).target.image);
217                                         removeLoadIndexRef(loadindex);
218                                 }
219
220                         }
221                         // Now check if the command is on screen!
222                         if  (!(*commands).Outside(0,0,swidth,sheight)) {
223                                 executeDrawCommand(*commands);
224                         }
225                         commands++;
226                 }
227                 curdraw++;
228         }
229
230         surfaces_mutex.Unlock();
231 }
232
233 void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
234                         list<SVGCommand>& commands)
235 {
236         surfaces_mutex.Lock();
237         //First determine it is already in our system
238         list<SurfaceCommands>::iterator itty=scommands.begin();
239         while (itty!=scommands.end()) {
240                 if ((*itty).surf==surf) {
241                         //decrease the references
242                         dereferenceSVGCommand((*itty).commands);
243                         break;
244                 }
245                 itty++;
246         }
247         // if not insert it
248         if (itty==scommands.end()) {
249                 SurfaceCommands new_sc;
250                 new_sc.surf=surf;
251                 new_sc.x=x;
252                 new_sc.y=y;
253                 new_sc.w=width;
254                 new_sc.h=height;
255                 itty=scommands.insert(itty,new_sc);
256         }
257         // update any images loaded in the mean time
258         list<SVGCommand>::iterator ilitty=commands.begin();
259
260         while (ilitty!=commands.end())
261         {
262                 if ((*ilitty).instr==DrawImageLoading) {
263                         LoadIndex loadindex=(*ilitty).target.loadindex;
264                         if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
265
266                                 (*ilitty).instr=DrawImage;
267                                 (*ilitty).target.image=tvmedias_loaded[loadindex];
268                                 incImageRef((*ilitty).target.image);
269                                 removeLoadIndexRef(loadindex);
270                         }
271                 }
272                 ilitty++;
273         }
274
275
276         // then clear and copy
277         (*itty).commands.clear();
278         (*itty).commands=commands;
279         //increase the references
280         referenceSVGCommand((*itty).commands);
281         cleanupOrphanedRefs();
282
283         surfaces_mutex.Unlock();
284 }
285
286 void OsdVector::removeSurface(const SurfaceVector *surf)
287 {
288         surfaces_mutex.Lock();
289         //First determine it is already in our system
290         list<SurfaceCommands>::iterator itty=scommands.begin();
291         while (itty!=scommands.end()) {
292                 if ((*itty).surf==surf) {
293                         dereferenceSVGCommand((*itty).commands);
294                         (*itty).commands.clear();
295                         scommands.erase(itty);
296                         break;
297                 }
298                 itty++;
299         }
300         surfaces_mutex.Unlock();
301
302 }
303
304 void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )
305 {
306
307         list<SVGCommand>::iterator sitty = commands.begin();
308         while (sitty != commands.end()) {
309                 removeStyleRef((*sitty).getRef());
310                 ImageIndex ii = (*sitty).getImageIndex();
311                 if (ii) removeImageRef(ii);
312                 LoadIndex li=(*sitty).getLoadIndex();
313                 if (li) removeLoadIndexRef(li);
314                 sitty++;
315         }
316 }
317
318 void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )
319 {
320         list<SVGCommand>::iterator sitty=commands.begin();
321         while (sitty!=commands.end())
322         {
323                 incStyleRef((*sitty).getRef());
324                 ImageIndex ii=(*sitty).getImageIndex();
325                 if (ii) incImageRef(ii);
326                 LoadIndex li=(*sitty).getLoadIndex();
327                 if (li) incLoadIndexRef(li);
328                 sitty++;
329         }
330 }
331
332
333 void OsdVector::incImageRef(ImageIndex index)
334 {
335         if (images_ref.find(index)==images_ref.end()) {
336                 images_ref[index]=1;
337         } else {
338                 images_ref[index]++;
339         }
340 }
341
342 void OsdVector::removeImageRef(const ImageIndex ref)
343 {
344         images_ref[ref]--;
345 }
346
347 int OsdVector::getLoadIndexRef(LoadIndex index)
348 {
349         if (loadindex_ref.find(index)==loadindex_ref.end()) {
350                 return -1;
351         } else {
352                 return loadindex_ref[index];
353         }
354 }
355
356 void OsdVector::incLoadIndexRef(LoadIndex index)
357 {
358         if (loadindex_ref.find(index)==loadindex_ref.end()) {
359                 loadindex_ref[index]=1;
360         } else {
361                 loadindex_ref[index]++;
362         }
363 }
364
365 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
366 {
367         loadindex_ref[ref]--;
368         if (loadindex_ref[ref]==0) {
369                 //now check, if it is already loaded
370                 map<LoadIndex,ImageIndex>::iterator itty=tvmedias_loaded.find(ref);
371                 if ( itty != tvmedias_loaded.end()) {
372                         removeImageRef((*itty).second); // remove lock
373                 }
374                 tvmedias_loaded.erase(ref);
375                 tvmedias_load.erase(tvmedias_load_inv[ref]);
376                 tvmedias_load_inv.erase(ref);
377
378                 reader.invalidateLoadIndex(ref);
379
380
381         }
382 }
383
384
385
386 void OsdVector::cleanupOrphanedRefs()
387 { // Do some garbage collection
388
389         map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
390         while (mitty!=monobitmaps.end()) {
391                 map<ImageIndex,int>::iterator curitty=images_ref.find((*mitty).second);
392                 int count=(*curitty).second;
393                 if (count==0) {
394                         ImageIndex ref=(*curitty).first;
395                         monobitmaps.erase(mitty++);
396                         images_ref.erase(curitty++);
397                         destroyImageRef(ref);
398                 } else ++mitty;
399         }
400
401         /*map<string,ImageIndex>::iterator jitty=jpegs.begin();
402         while (jitty!=jpegs.end()) {
403                 map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
404                 int count=(*curitty).second;
405                 if (count==0) {
406                         ImageIndex ref=(*curitty).first;
407                         jpegs.erase(jitty++);
408                         images_ref.erase(curitty++);
409                         destroyImageRef(ref);
410                 } else ++jitty;
411         }*/
412
413         map<TVMediaInfo,ImageIndex>::iterator titty=tvmedias.begin();
414         while (titty!=tvmedias.end()) {
415                 map<ImageIndex,int>::iterator curitty=images_ref.find((*titty).second);
416                 int count=(*curitty).second;
417                 if (count==0) {
418                         ImageIndex ref=(*curitty).first;
419                         tvmedias.erase(titty++);
420                         images_ref.erase(curitty);
421                         destroyImageRef(ref);
422                 } else ++titty;
423         }
424
425
426         map<TVMediaInfo,LoadIndex>::iterator litty=tvmedias_load.begin();
427         while (litty!=tvmedias_load.end()) {
428                 map<LoadIndex,int>::iterator curitty=loadindex_ref.find((*litty).second);
429                 int count=(*curitty).second;
430                 if (count==0) {
431                         tvmedias_load_inv.erase((*litty).second);
432                         tvmedias_loaded.erase((*litty).second);
433                         tvmedias_load.erase(litty++);
434                 } else ++litty;
435         }
436
437         list<ImageIndex>::iterator pitty=palettepics.begin();
438         while (pitty!=palettepics.end()) {
439                 map<ImageIndex,int>::iterator curitty=images_ref.find((*pitty));
440                 int count=(*curitty).second;
441                 if (count==0) {
442                         ImageIndex ref=(*curitty).first;
443                         palettepics.erase(pitty++);
444                         images_ref.erase(curitty++);
445                         destroyImageRef(ref);
446                 } else ++pitty;
447         }
448
449
450         map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
451         while (sitty!=styles.end()) {
452                 map<unsigned int,int>::iterator curitty=styles_ref.find((*sitty).second);
453                 int count=(*curitty).second;
454                 if (count==0) {
455                         unsigned int ref=(*curitty).first;
456                         styles.erase(sitty++);
457                         styles_ref.erase(curitty++);
458                         destroyStyleRef(ref);
459
460                 } else ++sitty;
461
462         }
463 }
464
465
466 int OsdVector::getImageRef(ImageIndex index)
467 {
468         if (images_ref.find(index)==images_ref.end()) {
469                 return -1;
470         } else {
471                 return images_ref[index];
472         }
473 }
474
475 void OsdVector::incStyleRef(unsigned int index)
476 {
477         if (styles_ref.find(index)==styles_ref.end()) {
478                 styles_ref[index]=1;
479         } else {
480                 styles_ref[index]++;
481         }
482 }
483
484 void OsdVector::removeStyleRef(unsigned int index)
485 {
486         styles_ref[index]--;
487 }
488
489 unsigned int OsdVector::getStyleRef(const DrawStyle &c)
490 {
491         unsigned int style_handle=0;
492         if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
493         {
494                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
495         } else {
496                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
497                 //Now check if the handle is valid
498                 if (styles_ref.find(style_handle)==styles_ref.end()) {
499                         //invalid handle recreate
500                         style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
501                 }
502         }
503         incStyleRef(style_handle);
504         return style_handle;
505 }
506
507 unsigned int OsdVector::getColorRef(const Colour &c)
508 {
509         unsigned int style_handle=0;
510         if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
511         {
512                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
513         } else {
514                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
515                 if (styles_ref.find(style_handle)==styles_ref.end()) {
516                         //invalid handle recreate
517                         style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
518                 }
519         }
520         incStyleRef(style_handle);
521         return style_handle;
522 }
523
524 int OsdVector::getStyleRef(unsigned int index)
525 {
526         if (styles_ref.find(index)==styles_ref.end()) {
527                 return -1;
528         } else {
529                 return styles_ref[index];
530         }
531 }
532
533 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
534 {
535         ImageIndex image_handle=0;
536         LoadIndex loadindex=0;
537         if (tvmedias.find(tvmedia)==tvmedias.end())
538         {
539                 loadindex=loadTVMedia(tvmedia);
540         } else {
541                 image_handle=tvmedias[tvmedia];
542                 if (images_ref.find(image_handle)==images_ref.end()) {
543                         //invalid handle recreate
544                         loadindex=loadTVMedia(tvmedia);
545                         image_handle=0;
546                 } else {
547                         incImageRef(image_handle);
548                 }
549         }
550         /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
551         incImageRef(image_handle);*/
552         image=image_handle;
553         return loadindex;
554 }
555
556 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
557 {
558         LoadIndex index=0;
559         if (tvmedias_load.find(tvmedia)==tvmedias_load.end())
560         {
561                 switch (tvmedia.getType()) {
562                 case 3:
563                         index=VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
564                         break;
565                 case 4: {
566                         index = ((long long) tvmedia.getPrimaryID()) << 32LL;
567                         reader.addStaticImage(tvmedia.getPrimaryID());
568                 } break;
569                 case 5:
570                         index=VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
571                 break;
572                 case 6:
573                         index=VDR::getInstance()->loadChannelLogo(tvmedia);
574                 break;
575                 default:
576                         index=VDR::getInstance()->loadTVMedia(tvmedia);
577                         break;
578                 }
579
580                 tvmedias_load[tvmedia]=index;
581                 tvmedias_load_inv[index]=tvmedia;
582         } else {
583
584                 index=tvmedias_load[tvmedia];
585         }
586
587         incLoadIndexRef(index);
588
589         return index;
590 }
591
592
593
594 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
595 {
596         //Beware for thread safety
597         ImageIndex image_index=0;
598
599         TVMediaInfo tvmedia=tvmedias_load_inv[index];
600           Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %llx arrived %d",index, imageIndex);
601         if (imageIndex) {
602                 image_index=tvmedias[tvmedia]=imageIndex;
603                 tvmedias_loaded[index]=image_index;
604                 if (getLoadIndexRef(index) < 1) {
605                         // we do not want the picture anymore . Really...
606                         // fill images_ref in to not irritate the garbage collector
607                         if (getImageRef(image_index) < 0) {
608                                 images_ref[image_index]=0;
609                         }
610                 } else {
611
612                         incImageRef(image_index); // hold one index until all loadings refs are gone;
613                 }
614         }
615
616
617 }
618
619
620
621
622 /*
623 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
624 {
625         ImageIndex image_handle=0;
626         if (jpegs.find(fileName)==jpegs.end())
627         {
628                 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
629         } else {
630                 image_handle=jpegs[fileName];
631                 *width=0;
632                 *height=0;
633                 if (images_ref.find(image_handle)==images_ref.end()) {
634                         //invalid handle recreate
635                         image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
636                 }
637         }
638         incImageRef(image_handle);
639         return image_handle;
640 }
641 */
642
643 ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
644 {
645         ImageIndex image_handle;
646         if (monobitmaps.find(base)==monobitmaps.end())
647         {
648                 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
649         } else {
650                 image_handle=monobitmaps[base];
651                 if (images_ref.find(image_handle)==images_ref.end()) {
652                         //invalid handle recreate
653                         image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
654                 }
655         }
656         incImageRef(image_handle);
657         return image_handle;
658 }
659
660 ImageIndex  OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
661 {
662         ImageIndex image_handle;
663         image_handle=createImagePalette(width,height,image_data,palette_data);
664         palettepics.push_back(image_handle);
665         incImageRef(image_handle);
666         return image_handle;
667 }
668
669 OsdVector::PictureReader::~PictureReader()
670 {
671         decoders_lock.Lock();
672         while ( decoders.size()) {
673                 PictureDecoder* dec=decoders.front();
674                 decoders.pop_front();
675                 delete dec;
676         }
677
678         decoders_lock.Unlock();
679 }
680
681 void OsdVector::PictureReader::init()
682 {
683         threadStart();
684 }
685
686 void OsdVector::PictureReader::shutdown()
687 {
688         threadStop();
689
690
691 }
692
693 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
694 {
695         decoders_lock.Lock();
696         decoder->init();
697         decoders.push_front(decoder);
698         decoders_lock.Unlock();
699 }
700
701 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
702 {
703         decoders_lock.Lock();
704         std::list<PictureDecoder*>::iterator itty=decoders.begin();
705         while (itty!=decoders.end()) {
706                 if ((*itty) == decoder)
707                 {
708                         decoders.erase(itty);
709                         break;
710                 }
711                 itty++;
712         }
713         Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
714         decoder->shutdown();
715         delete decoder;
716         decoders_lock.Unlock();
717 }
718
719 void OsdVector::PictureReader::threadMethod()
720 {
721         OsdVector *osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
722         Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
723         while (true) {
724                 if (!threadIsActive()) {
725                         Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
726                         threadCheckExit();
727                 }
728
729                 bool todos=true;
730                 while (todos)
731                 {
732                         todos=false;
733                         PictureInfo pictinf;
734                         decoders_lock.Lock();
735                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
736
737                         while (itty!=decoders.end()) {
738                                 if ((*itty)->getDecodedPicture(pictinf)) {
739                                         todos = true;
740                                         osdvector->createPicture(pictinf);
741                                 }
742
743                                 itty++;
744                         }
745                         if (processReceivedPictures())
746                         {
747                                 todos = true;
748                         }
749
750                         decoders_lock.Unlock();
751                 }
752                 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
753
754                 struct timespec target_time;
755                 clock_gettime(CLOCK_REALTIME,&target_time);
756                 target_time.tv_nsec+=1000000LL*10;
757                 if (target_time.tv_nsec>999999999) {
758                         target_time.tv_nsec-=1000000000L;
759                         target_time.tv_sec+=1;
760                 }
761                 threadLock();
762                 threadWaitForSignalTimed(&target_time);
763                 threadUnlock();
764                 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
765         }
766 }
767
768 void OsdVector::PictureReader::threadPostStopCleanup()
769 {
770
771 }
772
773 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
774 {
775         pict_lock_incoming.Lock();
776         invalid_loadindex.insert(index);
777         pict_lock_incoming.Unlock();
778 }
779
780 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket *vresp)
781 {
782         pict_lock_incoming.Lock();
783         pict_incoming.push(vresp);
784         pict_lock_incoming.Unlock();
785         threadSignal();
786 }
787
788
789 void OsdVector::PictureReader::addStaticImage(unsigned int id)
790 {
791         pict_lock_incoming.Lock();
792         pict_incoming_static.push(id);
793         invalid_loadindex.erase(((long long) id) << 32LL);
794         pict_lock_incoming.Unlock();
795         threadSignal();
796 }
797
798 bool OsdVector::PictureReader::processReceivedPictures()
799 {
800         bool decoded = false;
801         bool valid = true;
802         pict_lock_incoming.Lock();
803     if (pict_incoming.size()) {
804                 VDR_ResponsePacket *vresp=pict_incoming.front();
805                 pict_incoming.pop();
806                 set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
807                 if (setpos != invalid_loadindex.end()) {
808                         valid = false;
809                         invalid_loadindex.erase(setpos);
810                 }
811                 pict_lock_incoming.Unlock();
812                 if (!valid) { // we do not want it anymore skip it;
813                         delete vresp;
814                         return true;
815                 }
816         //       Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived VDR %x %d %d",
817         //                       vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
818                 if (vresp->getFlag() != 2) {
819                         UCHAR *userdata=vresp->getUserData();
820                         ULONG length=vresp->getUserDataLength();
821                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
822                         while (itty!=decoders.end()) {
823                                 userdata=(*itty)->decodePicture(vresp->getStreamID(), userdata, length);
824                                 if (!userdata){
825                                         decoded=true;
826                                         break;
827                                 }
828                                 itty++;
829                         }
830                         if (!decoded && userdata ){
831                                 free(userdata);
832                         }
833                 }
834                 //else  osd->informPicture(vresp->getStreamID(), 0);
835                 delete vresp;
836         } else if (pict_incoming_static.size()){
837                 unsigned int static_id = pict_incoming_static.front();
838                 pict_incoming_static.pop();
839                 set<LoadIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
840                 if (setpos != invalid_loadindex.end()) {
841                         valid = false;
842                         invalid_loadindex.erase(setpos);
843                 }
844                 pict_lock_incoming.Unlock();
845                 if (!valid) { // we do not want it anymore skip it;
846                         return true;
847                 }
848
849                 UCHAR *userdata;
850                 ULONG length;
851                 if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
852                 {
853                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
854                         while (itty!=decoders.end()) {
855                                 if (!(*itty)->decodePicture(((long long) static_id) << 32LL,userdata, length, false)){
856                                         decoded=true;
857                                         break;
858                                 }
859                                 itty++;
860                         }
861                 }
862         } else {
863                 pict_lock_incoming.Unlock();
864         }
865
866
867     if (pict_incoming.size() || pict_incoming_static.size()) return true;
868         return decoded;
869 }