]> git.vomp.tv Git - vompclient.git/blob - osdvector.cc
Fix leak in picture handling of osdvector, add static fallback pictures, some default...
[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, if no libmagick is there
126 #ifdef PICTURE_DECODER_MAGICK
127         int width,height;
128         getRealScreenSize(width,height);
129         size_t length=width*height*4;
130         void *mem=malloc(length);
131
132         try {
133                 Blob myblob;
134                 if (!screenShot(mem,width,height,true)) {
135                         Log::getInstance()->log("OsdVector", Log::DEBUG, "Screenshot failed!");
136                         free(mem);
137                         return;
138                 }
139                 myblob.updateNoCopy(mem,length,Blob::MallocAllocator);
140                 Image image(myblob,Geometry(width,height),8,"RGBA");
141                 image.write(fileName);
142         }catch( Exception &error_ )
143         {
144                 Log::getInstance()->log("MagickEncoder", Log::DEBUG, "Libmagick: %s",error_.what());
145
146         }
147
148 #endif
149 }
150
151 Surface * OsdVector::createNewSurface()
152 {
153         return new SurfaceVector(this);
154 }
155
156
157 void OsdVector::Blank()
158 {
159         // do nothing? remove this one?
160 }
161
162 int OsdVector::restore()
163 {
164         // First clear the contents of all registered surfaces
165         surfaces_mutex.Lock();
166
167         //Now go through all surfaces and draw them
168         list<SurfaceCommands>::iterator curdraw=scommands.begin();
169         while (curdraw!=scommands.end()) {
170                 (*curdraw).commands.clear();
171                 curdraw++;
172         }
173         //also clear all handles, they are now invalid, no need to release them
174         images_ref.clear();
175         monobitmaps.clear();
176         //jpegs.clear();
177         styles.clear();
178         styles_ref.clear();
179         palettepics.clear();
180
181         tvmedias.clear();
182         loadindex_ref.clear();
183         tvmedias_load.clear();
184         tvmedias_load_inv.clear();
185         tvmedias_loaded.clear();
186
187         surfaces_mutex.Unlock();
188         return 1;
189 }
190
191 void OsdVector::drawSurfaces()
192 {
193         surfaces_mutex.Lock();
194         list<SurfaceCommands*> todraw; //First figure out if a surfaces is below another surface
195         list<SurfaceCommands>::iterator itty1=scommands.begin();
196         while (itty1!=scommands.end()) {
197                 list<SurfaceCommands>::iterator itty2=itty1;
198                 itty2++;
199                 bool hidden=false;
200                 while (itty2!=scommands.end()) {
201                         SurfaceCommands & ref1=*itty1;
202                         SurfaceCommands & ref2=*itty2;
203                         if (ref1.x>=ref2.x && ref1.y>=ref2.y
204                                         && (ref1.x+ref1.w) <= (ref2.x+ref2.w)
205                                         && (ref1.y+ref1.h) <= (ref2.y+ref2.h) ) {
206                                 hidden=true;
207                                 break;
208                         }
209                         itty2++;
210                 }
211                 if (!hidden) { // we are not hidden, perfect
212                         todraw.push_back(&(*itty1));
213                 }
214                 itty1++;
215         }
216         int swidth,sheight;
217         getScreenSize(swidth,sheight);
218         //Now go through all surfaces and draw them
219         list<SurfaceCommands*>::iterator curdraw=todraw.begin();
220         while (curdraw!=todraw.end()) {
221                 drawSetTrans(*(*curdraw));
222                 list<SVGCommand>::iterator commands=(*(*curdraw)).commands.begin();
223                 list<SVGCommand>::iterator end=(*(*curdraw)).commands.end();
224                 while (commands!=end) {
225                         // update any images loaded in the mean time
226                         if ((*commands).instr==DrawImageLoading) {
227                                 LoadIndex loadindex=(*commands).target.loadindex;
228                                 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
229                                         (*commands).instr=DrawImage;
230                                         (*commands).target.image=tvmedias_loaded[loadindex];;
231                                         incImageRef((*commands).target.image);
232                                         removeLoadIndexRef(loadindex);
233                                 }
234
235                         }
236                         // Now check if the command is on screen!
237                         if  (!(*commands).Outside(0,0,swidth,sheight)) {
238                                 executeDrawCommand(*commands);
239                         }
240                         commands++;
241                 }
242                 curdraw++;
243         }
244
245         surfaces_mutex.Unlock();
246 }
247
248 void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
249                         list<SVGCommand>& commands)
250 {
251         surfaces_mutex.Lock();
252         //First determine it is already in our system
253         list<SurfaceCommands>::iterator itty=scommands.begin();
254         while (itty!=scommands.end()) {
255                 if ((*itty).surf==surf) {
256                         //decrease the references
257                         dereferenceSVGCommand((*itty).commands);
258                         break;
259                 }
260                 itty++;
261         }
262         // if not insert it
263         if (itty==scommands.end()) {
264                 SurfaceCommands new_sc;
265                 new_sc.surf=surf;
266                 new_sc.x=x;
267                 new_sc.y=y;
268                 new_sc.w=width;
269                 new_sc.h=height;
270                 itty=scommands.insert(itty,new_sc);
271         }
272         // update any images loaded in the mean time
273         list<SVGCommand>::iterator ilitty=commands.begin();
274
275         while (ilitty!=commands.end())
276         {
277                 if ((*ilitty).instr==DrawImageLoading) {
278                         LoadIndex loadindex=(*ilitty).target.loadindex;
279                         if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
280
281                                 (*ilitty).instr=DrawImage;
282                                 (*ilitty).target.image=tvmedias_loaded[loadindex];
283                                 incImageRef((*ilitty).target.image);
284                                 removeLoadIndexRef(loadindex);
285                         }
286                 }
287                 ilitty++;
288         }
289
290
291         // then clear and copy
292         (*itty).commands.clear();
293         (*itty).commands=commands;
294         //increase the references
295         referenceSVGCommand((*itty).commands);
296         cleanupOrphanedRefs();
297
298         surfaces_mutex.Unlock();
299 }
300
301 void OsdVector::removeSurface(const SurfaceVector *surf)
302 {
303         surfaces_mutex.Lock();
304         //First determine it is already in our system
305         list<SurfaceCommands>::iterator itty=scommands.begin();
306         while (itty!=scommands.end()) {
307                 if ((*itty).surf==surf) {
308                         dereferenceSVGCommand((*itty).commands);
309                         (*itty).commands.clear();
310                         scommands.erase(itty);
311                         break;
312                 }
313                 itty++;
314         }
315         surfaces_mutex.Unlock();
316
317 }
318
319 void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )
320 {
321
322         list<SVGCommand>::iterator sitty = commands.begin();
323         while (sitty != commands.end()) {
324                 removeStyleRef((*sitty).getRef());
325                 ImageIndex ii = (*sitty).getImageIndex();
326                 if (ii) removeImageRef(ii);
327                 LoadIndex li=(*sitty).getLoadIndex();
328                 if (li) removeLoadIndexRef(li);
329                 sitty++;
330         }
331 }
332
333 void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )
334 {
335         list<SVGCommand>::iterator sitty=commands.begin();
336         while (sitty!=commands.end())
337         {
338                 incStyleRef((*sitty).getRef());
339                 ImageIndex ii=(*sitty).getImageIndex();
340                 if (ii) incImageRef(ii);
341                 LoadIndex li=(*sitty).getLoadIndex();
342                 if (li) incLoadIndexRef(li);
343                 sitty++;
344         }
345 }
346
347
348 void OsdVector::incImageRef(ImageIndex index)
349 {
350         if (images_ref.find(index)==images_ref.end()) {
351                 images_ref[index]=1;
352         } else {
353                 images_ref[index]++;
354         }
355 }
356
357 void OsdVector::removeImageRef(const ImageIndex ref)
358 {
359         images_ref[ref]--;
360 }
361
362 int OsdVector::getLoadIndexRef(LoadIndex index)
363 {
364         surfaces_mutex.Lock();
365         if (loadindex_ref.find(index)==loadindex_ref.end()) {
366                 return -1;
367         } else {
368                 return loadindex_ref[index];
369         }
370         surfaces_mutex.Unlock();
371 }
372
373 void OsdVector::incLoadIndexRef(LoadIndex index)
374 {
375         if (loadindex_ref.find(index)==loadindex_ref.end()) {
376                 loadindex_ref[index]=1;
377         } else {
378                 loadindex_ref[index]++;
379         }
380 }
381
382 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
383 {
384         loadindex_ref[ref]--;
385         if (loadindex_ref[ref]==0) {
386                 //now check, if it is already loaded
387                 map<LoadIndex,ImageIndex>::iterator itty=tvmedias_loaded.find(ref);
388                 if ( itty != tvmedias_loaded.end()) {
389                         removeImageRef((*itty).second); // remove lock
390                 }
391                 tvmedias_loaded.erase(ref);
392 //              Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia removeLoadIndexRef %d %llx",tvmedias_load.size(),ref);
393                 tvmedias_load.erase(tvmedias_load_inv[ref]);
394                 tvmedias_load_inv.erase(ref);
395
396                 reader.invalidateLoadIndex(ref);
397
398
399         }
400 }
401
402
403
404 void OsdVector::cleanupOrphanedRefs()
405 { // Do some garbage collection
406
407         map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
408         while (mitty!=monobitmaps.end()) {
409                 map<ImageIndex,int>::iterator curitty=images_ref.find((*mitty).second);
410                 int count=(*curitty).second;
411                 if (count==0) {
412                         ImageIndex ref=(*curitty).first;
413                         monobitmaps.erase(mitty++);
414                         images_ref.erase(curitty++);
415                         destroyImageRef(ref);
416                 } else ++mitty;
417         }
418
419         /*map<string,ImageIndex>::iterator jitty=jpegs.begin();
420         while (jitty!=jpegs.end()) {
421                 map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
422                 int count=(*curitty).second;
423                 if (count==0) {
424                         ImageIndex ref=(*curitty).first;
425                         jpegs.erase(jitty++);
426                         images_ref.erase(curitty++);
427                         destroyImageRef(ref);
428                 } else ++jitty;
429         }*/
430
431         map<TVMediaInfo,ImageIndex>::iterator titty=tvmedias.begin();
432         while (titty!=tvmedias.end()) {
433                 map<ImageIndex,int>::iterator curitty=images_ref.find((*titty).second);
434                 int count=(*curitty).second;
435                 if (count==0) {
436                         ImageIndex ref=(*curitty).first;
437                         tvmedias.erase(titty++);
438                         images_ref.erase(curitty);
439                         destroyImageRef(ref);
440                 } else ++titty;
441         }
442
443
444         map<TVMediaInfo,LoadIndex>::iterator litty=tvmedias_load.begin();
445         while (litty!=tvmedias_load.end()) {
446                 map<LoadIndex,int>::iterator curitty=loadindex_ref.find((*litty).second);
447                 int count=(*curitty).second;
448                 if (count==0) {
449                         tvmedias_load_inv.erase((*litty).second);
450                         tvmedias_loaded.erase((*litty).second);
451                         tvmedias_load.erase(litty++);
452                 } else ++litty;
453         }
454
455         list<ImageIndex>::iterator pitty=palettepics.begin();
456         while (pitty!=palettepics.end()) {
457                 map<ImageIndex,int>::iterator curitty=images_ref.find((*pitty));
458                 int count=(*curitty).second;
459                 if (count==0) {
460                         ImageIndex ref=(*curitty).first;
461                         palettepics.erase(pitty++);
462                         images_ref.erase(curitty++);
463                         destroyImageRef(ref);
464                 } else ++pitty;
465         }
466
467         map<ImageIndex,int>::iterator citty=images_ref.begin();
468         while (citty!=images_ref.end()) {
469                 int count=(*citty).second;
470                 if (count==0) {
471                         ImageIndex ref=(*citty).first;
472                         images_ref.erase(citty++);
473                         destroyImageRef(ref);
474                 } else ++citty;
475         }
476
477
478         map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
479         while (sitty!=styles.end()) {
480                 map<unsigned int,int>::iterator curitty=styles_ref.find((*sitty).second);
481                 int count=(*curitty).second;
482                 if (count==0) {
483                         unsigned int ref=(*curitty).first;
484                         styles.erase(sitty++);
485                         styles_ref.erase(curitty++);
486                         destroyStyleRef(ref);
487
488                 } else ++sitty;
489
490         }
491 }
492
493
494 int OsdVector::getImageRef(ImageIndex index)
495 {
496         surfaces_mutex.Lock();
497         if (images_ref.find(index)==images_ref.end()) {
498                 return -1;
499         } else {
500                 return images_ref[index];
501         }
502         surfaces_mutex.Unlock();
503 }
504
505 void OsdVector::incStyleRef(unsigned int index)
506 {
507         if (styles_ref.find(index)==styles_ref.end()) {
508                 styles_ref[index]=1;
509         } else {
510                 styles_ref[index]++;
511         }
512 }
513
514 void OsdVector::removeStyleRef(unsigned int index)
515 {
516         styles_ref[index]--;
517 }
518
519 unsigned int OsdVector::getStyleRef(const DrawStyle &c)
520 {
521         surfaces_mutex.Lock();
522         unsigned int style_handle=0;
523         if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
524         {
525                 surfaces_mutex.Unlock();
526                 style_handle=createStyleRef(c);
527                 surfaces_mutex.Lock();
528                 styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=style_handle;
529         } else {
530                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
531                 //Now check if the handle is valid
532                 if (styles_ref.find(style_handle)==styles_ref.end()) {
533                         //invalid handle recreate
534                         surfaces_mutex.Unlock();
535                         style_handle=createStyleRef(c);
536                         surfaces_mutex.Lock();
537                         styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=style_handle;
538                 }
539         }
540         incStyleRef(style_handle);
541         surfaces_mutex.Unlock();
542         return style_handle;
543 }
544
545 unsigned int OsdVector::getColorRef(const Colour &c)
546 {
547         surfaces_mutex.Lock();
548         unsigned int style_handle=0;
549         if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
550         {
551                 surfaces_mutex.Unlock();
552                 style_handle=createColorRef(c);
553                 surfaces_mutex.Lock();
554                 styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=style_handle;
555         } else {
556                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
557                 if (styles_ref.find(style_handle)==styles_ref.end()) {
558                         //invalid handle recreate
559                         surfaces_mutex.Unlock();
560                         style_handle=createColorRef(c);
561                         surfaces_mutex.Lock();
562                         styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=style_handle;
563                 }
564         }
565         incStyleRef(style_handle);
566         surfaces_mutex.Unlock();
567         return style_handle;
568 }
569
570 int OsdVector::getStyleRef(unsigned int index)
571 {
572         if (styles_ref.find(index)==styles_ref.end()) {
573                 return -1;
574         } else {
575                 return styles_ref[index];
576         }
577 }
578
579 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
580 {
581         ImageIndex image_handle=0;
582         LoadIndex loadindex=0;
583         surfaces_mutex.Lock();
584         if (tvmedias.find(tvmedia)==tvmedias.end())
585         {
586                 loadindex=loadTVMedia(tvmedia);
587         } else {
588                 image_handle=tvmedias[tvmedia];
589                 if (images_ref.find(image_handle)==images_ref.end()) {
590                         //invalid handle recreate
591                         loadindex=loadTVMedia(tvmedia);
592                         image_handle=0;
593                 } else {
594                         incImageRef(image_handle);
595                 }
596         }
597         /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
598         incImageRef(image_handle);*/
599         image=image_handle;
600         surfaces_mutex.Unlock();
601         return loadindex;
602 }
603
604 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
605 {
606         LoadIndex index=0;
607
608         if (tvmedias_load.find(tvmedia)==tvmedias_load.end())
609         {
610                 switch (tvmedia.getType()) {
611                 case 3:
612                         index=VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
613                         break;
614                 case 4: {
615                         index = ((long long) tvmedia.getPrimaryID()) << 32LL;
616                         reader.addStaticImage(tvmedia.getPrimaryID());
617                 } break;
618                 case 5:
619                         index=VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
620                 break;
621                 case 6:
622                         index=VDR::getInstance()->loadChannelLogo(tvmedia);
623                 break;
624                 default:
625                         index=VDR::getInstance()->loadTVMedia(tvmedia);
626                         break;
627                 }
628                 if (tvmedia.getType()!=4 && tvmedia.getStaticFallback()>-1) {
629                         reader.informFallback(index,tvmedia.getStaticFallback());
630                 }
631
632                 tvmedias_load[tvmedia]=index;
633                 tvmedias_load_inv[index]=tvmedia;
634         } else {
635                 index=tvmedias_load[tvmedia];
636         }
637
638         incLoadIndexRef(index);
639
640         return index;
641 }
642
643
644
645 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
646 {
647         //Beware for thread safety
648         ImageIndex image_index=0;
649
650         Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %llx arrived %x",index, imageIndex);
651         surfaces_mutex.Lock();
652         TVMediaInfo tvmedia=tvmedias_load_inv[index];
653         if (imageIndex) {
654                 map<LoadIndex,int>::iterator itty=loadindex_ref.find(index);
655                 image_index=tvmedias[tvmedia]=imageIndex;
656                 tvmedias_loaded[index]=image_index;
657
658                 if (itty==loadindex_ref.end() || (*itty).second == 0) {
659                         // we do not want the picture anymore . Really...
660                         // fill images_ref in to not irritate the garbage collector
661                         if (images_ref.find(index)==images_ref.end()) {
662                                 images_ref[image_index]=0;
663                         }
664                 } else {
665                         incImageRef(image_index); // hold one index until all loadings refs are gone;
666                 }
667         }
668         surfaces_mutex.Unlock();
669
670
671 }
672
673
674
675
676 /*
677 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
678 {
679         ImageIndex image_handle=0;
680         if (jpegs.find(fileName)==jpegs.end())
681         {
682                 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
683         } else {
684                 image_handle=jpegs[fileName];
685                 *width=0;
686                 *height=0;
687                 if (images_ref.find(image_handle)==images_ref.end()) {
688                         //invalid handle recreate
689                         image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
690                 }
691         }
692         incImageRef(image_handle);
693         return image_handle;
694 }
695 */
696
697 ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
698 {
699         ImageIndex image_handle;
700         surfaces_mutex.Lock();
701         if (monobitmaps.find(base)==monobitmaps.end())
702         {
703                 surfaces_mutex.Unlock();
704                 image_handle=createMonoBitmap(base,width,height);
705                 surfaces_mutex.Lock();
706                 monobitmaps[base]=image_handle;
707         } else {
708                 image_handle=monobitmaps[base];
709                 if (images_ref.find(image_handle)==images_ref.end()) {
710                         //invalid handle recreate
711                         surfaces_mutex.Unlock();
712                         image_handle=createMonoBitmap(base,width,height);
713                         surfaces_mutex.Lock();
714                         monobitmaps[base]=image_handle;
715                 }
716         }
717         incImageRef(image_handle);
718         surfaces_mutex.Unlock();
719         return image_handle;
720 }
721
722 ImageIndex  OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
723 {
724         ImageIndex image_handle;
725         image_handle=createImagePalette(width,height,image_data,palette_data);
726         surfaces_mutex.Lock();
727         palettepics.push_back(image_handle);
728         incImageRef(image_handle);
729         surfaces_mutex.Unlock();
730         return image_handle;
731 }
732
733 OsdVector::PictureReader::~PictureReader()
734 {
735         decoders_lock.Lock();
736         while ( decoders.size()) {
737                 PictureDecoder* dec=decoders.front();
738                 decoders.pop_front();
739                 delete dec;
740         }
741
742         decoders_lock.Unlock();
743 }
744
745 void OsdVector::PictureReader::init()
746 {
747         threadStart();
748 }
749
750 void OsdVector::PictureReader::shutdown()
751 {
752         threadStop();
753
754
755 }
756
757 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
758 {
759         decoders_lock.Lock();
760         decoder->init();
761         decoders.push_front(decoder);
762         decoders_lock.Unlock();
763 }
764
765 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
766 {
767         decoders_lock.Lock();
768         std::list<PictureDecoder*>::iterator itty=decoders.begin();
769         while (itty!=decoders.end()) {
770                 if ((*itty) == decoder)
771                 {
772                         decoders.erase(itty);
773                         break;
774                 }
775                 itty++;
776         }
777         Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
778         decoder->shutdown();
779         delete decoder;
780         decoders_lock.Unlock();
781 }
782
783 void OsdVector::PictureReader::threadMethod()
784 {
785         OsdVector *osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
786         Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
787         while (true) {
788                 if (!threadIsActive()) {
789                         Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
790                         threadCheckExit();
791                 }
792
793                 bool todos=true;
794                 while (todos)
795                 {
796                         todos=false;
797                         PictureInfo pictinf;
798                         decoders_lock.Lock();
799                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
800
801                         while (itty!=decoders.end()) {
802                                 if ((*itty)->getDecodedPicture(pictinf)) {
803                                         todos = true;
804                                         osdvector->createPicture(pictinf);
805                                 }
806
807                                 itty++;
808                         }
809                         if (processReceivedPictures())
810                         {
811                                 todos = true;
812                         }
813
814                         decoders_lock.Unlock();
815                 }
816                 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
817
818                 struct timespec target_time;
819                 clock_gettime(CLOCK_REALTIME,&target_time);
820                 target_time.tv_nsec+=1000000LL*10;
821                 if (target_time.tv_nsec>999999999) {
822                         target_time.tv_nsec-=1000000000L;
823                         target_time.tv_sec+=1;
824                 }
825                 threadLock();
826                 threadWaitForSignalTimed(&target_time);
827                 threadUnlock();
828                 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
829         }
830 }
831
832 void OsdVector::PictureReader::threadPostStopCleanup()
833 {
834
835 }
836
837 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
838 {
839         pict_lock_incoming.Lock();
840         invalid_loadindex.insert(index);
841         pict_lock_incoming.Unlock();
842 }
843
844 void OsdVector::PictureReader::informFallback(LoadIndex index, int fallback)
845 {
846         pict_lock_incoming.Lock();
847         inform_fallback[index]=fallback;
848         pict_lock_incoming.Unlock();
849 }
850
851 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket *vresp)
852 {
853         pict_lock_incoming.Lock();
854         pict_incoming.push(vresp);
855         pict_lock_incoming.Unlock();
856         threadSignal();
857 }
858
859
860 void OsdVector::PictureReader::addStaticImage(unsigned int id)
861 {
862         pict_lock_incoming.Lock();
863         pict_incoming_static.push(id);
864         invalid_loadindex.erase(((long long) id) << 32LL);
865         pict_lock_incoming.Unlock();
866         threadSignal();
867 }
868
869 bool OsdVector::PictureReader::processReceivedPictures()
870 {
871         bool decoded = false;
872         bool valid = true;
873         pict_lock_incoming.Lock();
874     if (pict_incoming.size()) {
875                 VDR_ResponsePacket *vresp=pict_incoming.front();
876                 pict_incoming.pop();
877                 set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
878                 if (setpos != invalid_loadindex.end()) {
879                         valid = false;
880                         invalid_loadindex.erase(setpos);
881                 }
882                 pict_lock_incoming.Unlock();
883                 if (!valid) { // we do not want it anymore skip it;
884                         delete vresp;
885                         return true;
886                 }
887 //               Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived VDR %x %d %d",
888 //                       vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
889                 bool decode = false;
890                 bool freed = false;
891                 UCHAR *userdata;
892                 ULONG length;
893
894                 if (vresp->getFlag() != 2) {
895                         userdata=vresp->getUserData();
896                         length=vresp->getUserDataLength();
897                         decode = true;
898                         freed = true;
899                 } else {
900                         int fallback=-1;
901                         pict_lock_incoming.Lock();
902                         if (inform_fallback.find(vresp->getStreamID())!=inform_fallback.end()) {
903                                 fallback=inform_fallback[vresp->getStreamID()];
904                         }
905                         pict_lock_incoming.Unlock();
906                         if (fallback >= 0 && ((OsdVector*)Osd::getInstance())->getStaticImageData(fallback, &userdata, &length))
907                         {
908                                 decode = true;
909                                 freed = false;
910                         }
911
912                 }
913                 if (decode) {
914                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
915                         while (itty!=decoders.end()) {
916                                 userdata=(*itty)->decodePicture(vresp->getStreamID(), userdata, length, freed);
917                                 if (!userdata){
918                                         decoded=true;
919                                         break;
920                                 }
921                                 itty++;
922                         }
923                         if (!decoded && userdata && freed){
924                                 free(userdata);
925                         }
926                 }
927                 pict_lock_incoming.Lock();
928                 inform_fallback.erase(vresp->getStreamID());
929                 pict_lock_incoming.Unlock();
930                 //else  osd->informPicture(vresp->getStreamID(), 0);
931                 delete vresp;
932         } else if (pict_incoming_static.size()){
933                 unsigned int static_id = pict_incoming_static.front();
934                 pict_incoming_static.pop();
935                 set<LoadIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
936                 if (setpos != invalid_loadindex.end()) {
937                         valid = false;
938                         invalid_loadindex.erase(setpos);
939                 }
940                 pict_lock_incoming.Unlock();
941                 if (!valid) { // we do not want it anymore skip it;
942                         return true;
943                 }
944
945                 UCHAR *userdata;
946                 ULONG length;
947                 if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
948                 {
949                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
950                         while (itty!=decoders.end()) {
951                                 if (!(*itty)->decodePicture(((long long) static_id) << 32LL,userdata, length, false)){
952                                         decoded=true;
953                                         break;
954                                 }
955                                 itty++;
956                         }
957                 }
958         } else {
959                 pict_lock_incoming.Unlock();
960         }
961
962
963     if (pict_incoming.size() || pict_incoming_static.size()) return true;
964         return decoded;
965 }