]> git.vomp.tv Git - vompclient.git/blob - osdvector.cc
Remove some dead code, rename some things
[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, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "osdvector.h"
21 #include "surfacevector.h"
22 #include "vdr.h"
23 #include "vdrresponsepacket.h"
24 #include "control.h"
25 #include "message.h"
26
27 // The next section is activated, if the magick++ PictureReader is provided, it should be available for many POSIX platforms
28 #ifdef PICTURE_DECODER_MAGICK
29 #define MAGICKCORE_QUANTUM_DEPTH 16
30 #define MAGICKCORE_HDRI_ENABLE 0
31 #include <Magick++.h>
32
33 using namespace Magick;
34
35 class MagickDecoder: public OsdVector::PictureDecoder
36 {
37   public:
38     MagickDecoder(OsdVector::PictureReader* treader): OsdVector::PictureDecoder(treader) {pictInfValid = false;};
39
40     unsigned char* decodePicture(LoadIndex index, unsigned char* buffer, unsigned int length, bool freemem);
41
42     bool getDecodedPicture( struct OsdVector::PictureInfo& pict_inf);
43
44     void freeReference(void* ref);
45
46   protected:
47     OsdVector::PictureInfo pictInf;
48     bool pictInfValid;
49 };
50
51 unsigned char* MagickDecoder::decodePicture(LoadIndex index, unsigned char* buffer, unsigned int length, bool freemem)
52 {
53   if (pictInfValid) return buffer; // does support only one image at a Time;
54
55   Image magicimage;
56   Blob* imageblob = new Blob();
57   Blob myblob;
58
59   try
60   {
61     Log::getInstance()->log("MagickDecoder", Log::DEBUG, "decodePicture");
62
63     if (freemem) myblob.updateNoCopy(buffer, length, Blob::MallocAllocator);
64     else myblob.update(buffer, length);
65
66     magicimage.read(myblob);
67
68     magicimage.write(imageblob, "RGBA");
69
70   }
71   catch ( Exception& error_ )
72   {
73     Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: %s", error_.what());
74     delete imageblob;
75     Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: error mark2");
76     unsigned char* newbuffer = (unsigned char*) malloc(length);
77     memcpy(newbuffer, myblob.data(), length);
78     return newbuffer;
79   }
80
81   pictInf.reference = (void*) imageblob;
82   pictInf.width = magicimage.columns();
83   pictInf.height = magicimage.rows();
84   pictInf.image = imageblob->data();
85   pictInf.decoder = this;
86   pictInf.type = OsdVector::PictureInfo::RGBAMemBlock;
87   pictInf.lindex = index;
88   pictInfValid = true;
89
90
91
92   // I can handle everything, so the return value is always true
93   return NULL;
94 }
95 void MagickDecoder::freeReference(void* ref)
96 {
97   Blob* todelete = (Blob*) ref;
98   delete todelete;
99 }
100
101 bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
102 {
103   if (!pictInfValid) return false;
104
105   pict_inf = pictInf;
106   pictInfValid = false;
107   return true;
108 }
109
110
111 #endif
112
113 OsdVector::OsdVector()
114 {
115   setlocale(LC_CTYPE, "C.UTF-8");
116 #ifdef PICTURE_DECODER_MAGICK
117   reader.addDecoder(new MagickDecoder(&reader));
118 #endif
119
120   for (int i = 0; i < 256; i++)
121   {
122     byte_char_width[i] = 0.f;
123   }
124
125   styles_lastit_valid = styles_ref_lastit_valid = false;
126 }
127
128 void OsdVector::screenShot(const char* fileName)
129 {
130   //Do nothing, if no libmagick is there
131 #ifdef PICTURE_DECODER_MAGICK
132   int width, height;
133   getRealScreenSize(width, height);
134   size_t length = width * height * 4;
135   void* mem = malloc(length);
136
137   try
138   {
139     Blob myblob;
140
141     if (!screenShot(mem, width, height, true))
142     {
143       Log::getInstance()->log("OsdVector", Log::DEBUG, "Screenshot failed!");
144       free(mem);
145       return;
146     }
147
148     myblob.updateNoCopy(mem, length, Blob::MallocAllocator);
149     Image image(myblob, Geometry(width, height), 8, "RGBA");
150     image.write(fileName);
151   }
152   catch ( Exception& error_ )
153   {
154     Log::getInstance()->log("MagickEncoder", Log::DEBUG, "Libmagick: %s", error_.what());
155
156   }
157
158 #endif
159 }
160
161 Surface* OsdVector::createNewSurface()
162 {
163   return new SurfaceVector(this);
164 }
165
166
167 void OsdVector::Blank()
168 {
169   // do nothing? remove this one?
170 }
171
172 int OsdVector::restore()
173 {
174   // First clear the contents of all registered surfaces
175   surfaces_mutex.lock();
176
177   //Now go through all surfaces and draw them
178   std::list<SurfaceInfo>::iterator curdraw = surfaces.begin();
179
180   while (curdraw != surfaces.end())
181   {
182     (*curdraw).commands.clear();
183     (*curdraw).commands.reserve(2048);
184     curdraw++;
185   }
186
187   //also clear all handles, they are now invalid, no need to release them
188   images_ref.clear();
189   monobitmaps.clear();
190   //jpegs.clear();
191   styles.clear();
192   styles_ref.clear();
193   styles_lastit_valid = styles_ref_lastit_valid = false;
194   palettepics.clear();
195
196   tvmedias.clear();
197   loadindex_ref.clear();
198   tvmedias_load.clear();
199   tvmedias_load_inv.clear();
200   tvmedias_loaded.clear();
201
202   surfaces_mutex.unlock();
203   return 1;
204 }
205
206 void OsdVector::drawSurfaces()
207 {
208   surfaces_mutex.lock();
209   std::list<SurfaceInfo*> todraw; //First figure out if a surfaces is below another surface
210   std::list<SurfaceInfo>::iterator itty1 = surfaces.begin();
211
212   while (itty1 != surfaces.end())
213   {
214     std::list<SurfaceInfo>::iterator itty2 = itty1;
215     itty2++;
216     bool hidden = false;
217
218     while (itty2 != surfaces.end())
219     {
220       SurfaceInfo& ref1 = *itty1;
221       SurfaceInfo& ref2 = *itty2;
222
223       if (ref1.x >= ref2.x && ref1.y >= ref2.y
224           && (ref1.x + ref1.w) <= (ref2.x + ref2.w)
225           && (ref1.y + ref1.h) <= (ref2.y + ref2.h) )
226       {
227         hidden = true;
228         break;
229       }
230
231       itty2++;
232     }
233
234     if (!hidden)   // we are not hidden, perfect
235     {
236       todraw.push_back(&(*itty1));
237     }
238
239     itty1++;
240   }
241
242   int swidth, sheight;
243   getScreenSize(swidth, sheight);
244   //Now go through all surfaces and draw them
245   std::list<SurfaceInfo*>::iterator curdraw = todraw.begin();
246
247   while (curdraw != todraw.end())
248   {
249     drawSetTrans(*(*curdraw));
250     std::vector<SVGCommand>::iterator commands = (*(*curdraw)).commands.begin();
251     std::vector<SVGCommand>::iterator end = (*(*curdraw)).commands.end();
252
253     while (commands != end)
254     {
255       // update any images loaded in the mean time
256       if ((*commands).instr == DrawImageLoading)
257       {
258         LoadIndex loadindex = (*commands).target.loadindex;
259
260         if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end())
261         {
262           (*commands).instr = DrawImage;
263           (*commands).target.image = tvmedias_loaded[loadindex];;
264           incImageRef((*commands).target.image);
265           removeLoadIndexRef(loadindex);
266         }
267
268       }
269
270       // Now check if the command is on screen!
271       if  (!(*commands).Outside(0, 0, swidth, sheight))
272       {
273         executeDrawCommand(*commands);
274       }
275
276       commands++;
277     }
278
279     curdraw++;
280   }
281
282   surfaces_mutex.unlock();
283 }
284
285 void OsdVector::updateOrAddSurface(const SurfaceVector* surf, float x, float y, float height, float width,
286                                    std::vector<SVGCommand>& commands)
287 {
288   surfaces_mutex.lock();
289   //First determine it is already in our system
290   std::list<SurfaceInfo>::iterator itty = surfaces.begin();
291
292   while (itty != surfaces.end())
293   {
294     if ((*itty).surf == surf)
295     {
296       //decrease the references
297       decrementAllRefCounts((*itty).commands);
298       break;
299     }
300
301     itty++;
302   }
303
304   // if not insert it
305   if (itty == surfaces.end())
306   {
307     SurfaceInfo new_sc;
308     new_sc.surf = surf;
309     new_sc.x = x;
310     new_sc.y = y;
311     new_sc.w = width;
312     new_sc.h = height;
313     itty = surfaces.insert(itty, new_sc);
314   }
315
316   // update any images loaded in the mean time
317   std::vector<SVGCommand>::iterator ilitty = commands.begin();
318
319   while (ilitty != commands.end())
320   {
321     if ((*ilitty).instr == DrawImageLoading)
322     {
323       LoadIndex loadindex = (*ilitty).target.loadindex;
324
325       if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end())
326       {
327
328         (*ilitty).instr = DrawImage;
329         (*ilitty).target.image = tvmedias_loaded[loadindex];
330         incImageRef((*ilitty).target.image);
331         removeLoadIndexRef(loadindex);
332       }
333     }
334
335     ilitty++;
336   }
337
338
339   // then clear and copy
340   (*itty).commands.clear();
341   (*itty).commands = commands;
342   //increase the references
343   incrementAllRefCounts((*itty).commands);
344   cleanupOrphanedRefs();
345
346   surfaces_mutex.unlock();
347 }
348
349 void OsdVector::removeSurface(const SurfaceVector* surf)
350 {
351   surfaces_mutex.lock();
352   //First determine it is already in our system
353   std::list<SurfaceInfo>::iterator itty = surfaces.begin();
354
355   while (itty != surfaces.end())
356   {
357     if ((*itty).surf == surf)
358     {
359       decrementAllRefCounts((*itty).commands);
360       (*itty).commands.clear();
361       surfaces.erase(itty);
362       break;
363     }
364
365     itty++;
366   }
367
368   surfaces_mutex.unlock();
369
370 }
371
372 void OsdVector::decrementAllRefCounts(std::vector<SVGCommand>& commands )
373 {
374
375   std::vector<SVGCommand>::iterator sitty = commands.begin();
376
377   while (sitty != commands.end())
378   {
379     removeStyleRef((*sitty).getRef());
380     ImageIndex ii = (*sitty).getImageIndex();
381
382     if (ii) removeImageRef(ii);
383
384     LoadIndex li = (*sitty).getLoadIndex();
385
386     if (li) removeLoadIndexRef(li);
387
388     sitty++;
389   }
390 }
391
392 void OsdVector::incrementAllRefCounts(std::vector<SVGCommand>& commands )
393 {
394   std::vector<SVGCommand>::iterator sitty = commands.begin();
395
396   while (sitty != commands.end())
397   {
398     incStyleRef((*sitty).getRef());
399     ImageIndex ii = (*sitty).getImageIndex();
400
401     if (ii) incImageRef(ii);
402
403     LoadIndex li = (*sitty).getLoadIndex();
404
405     if (li) incLoadIndexRef(li);
406
407     sitty++;
408   }
409 }
410
411
412 void OsdVector::incImageRef(ImageIndex index)
413 {
414   if (images_ref.find(index) == images_ref.end())
415   {
416     images_ref[index] = 1;
417   }
418   else
419   {
420     images_ref[index]++;
421   }
422 }
423
424 void OsdVector::removeImageRef(const ImageIndex ref)
425 {
426   images_ref[ref]--;
427 }
428
429 int OsdVector::getLoadIndexRef(LoadIndex index)
430 {
431   surfaces_mutex.lock();
432
433   if (loadindex_ref.find(index) == loadindex_ref.end())
434   {
435     return -1;
436   }
437   else
438   {
439     return loadindex_ref[index];
440   }
441
442   surfaces_mutex.unlock();
443 }
444
445 void OsdVector::incLoadIndexRef(LoadIndex index)
446 {
447   if (loadindex_ref.find(index) == loadindex_ref.end())
448   {
449     loadindex_ref[index] = 1;
450   }
451   else
452   {
453     loadindex_ref[index]++;
454   }
455 }
456
457 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
458 {
459   loadindex_ref[ref]--;
460
461   if (loadindex_ref[ref] == 0)
462   {
463     //now check, if it is already loaded
464     std::map<LoadIndex, ImageIndex>::iterator itty = tvmedias_loaded.find(ref);
465
466     if ( itty != tvmedias_loaded.end())
467     {
468       removeImageRef((*itty).second); // remove lock
469     }
470
471     tvmedias_loaded.erase(ref);
472     //          Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia removeLoadIndexRef %d %llx",tvmedias_load.size(),ref);
473     tvmedias_load.erase(tvmedias_load_inv[ref]);
474     tvmedias_load_inv.erase(ref);
475
476     reader.invalidateLoadIndex(ref);
477
478
479   }
480 }
481
482
483
484 void OsdVector::cleanupOrphanedRefs()
485 {
486   // Do some garbage collection
487
488   std::map<void*, ImageIndex>::iterator mitty = monobitmaps.begin();
489
490   while (mitty != monobitmaps.end())
491   {
492     std::map<ImageIndex, int>::iterator curitty = images_ref.find((*mitty).second);
493     int count = (*curitty).second;
494
495     if (count == 0)
496     {
497       ImageIndex ref = (*curitty).first;
498       monobitmaps.erase(mitty++);
499       images_ref.erase(curitty++);
500       destroyImageRef(ref);
501     }
502     else ++mitty;
503   }
504
505   /*map<string,ImageIndex>::iterator jitty=jpegs.begin();
506   while (jitty!=jpegs.end()) {
507         map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
508         int count=(*curitty).second;
509         if (count==0) {
510                 ImageIndex ref=(*curitty).first;
511                 jpegs.erase(jitty++);
512                 images_ref.erase(curitty++);
513                 destroyImageRef(ref);
514         } else ++jitty;
515   }*/
516
517   std::map<TVMediaInfo, ImageIndex>::iterator titty = tvmedias.begin();
518
519   while (titty != tvmedias.end())
520   {
521     std::map<ImageIndex, int>::iterator curitty = images_ref.find((*titty).second);
522     int count = (*curitty).second;
523
524     if (count == 0)
525     {
526       ImageIndex ref = (*curitty).first;
527       tvmedias.erase(titty++);
528       images_ref.erase(curitty);
529       destroyImageRef(ref);
530     }
531     else ++titty;
532   }
533
534
535   std::map<TVMediaInfo, LoadIndex>::iterator litty = tvmedias_load.begin();
536
537   while (litty != tvmedias_load.end())
538   {
539     std::map<LoadIndex, int>::iterator curitty = loadindex_ref.find((*litty).second);
540     int count = (*curitty).second;
541
542     if (count == 0)
543     {
544       tvmedias_load_inv.erase((*litty).second);
545       tvmedias_loaded.erase((*litty).second);
546       tvmedias_load.erase(litty++);
547     }
548     else ++litty;
549   }
550
551   std::list<ImageIndex>::iterator pitty = palettepics.begin();
552
553   while (pitty != palettepics.end())
554   {
555     std::map<ImageIndex, int>::iterator curitty = images_ref.find((*pitty));
556     int count = (*curitty).second;
557
558     if (count == 0)
559     {
560       ImageIndex ref = (*curitty).first;
561       palettepics.erase(pitty++);
562       images_ref.erase(curitty++);
563       destroyImageRef(ref);
564     }
565     else ++pitty;
566   }
567
568   std::map<ImageIndex, int>::iterator citty = images_ref.begin();
569
570   while (citty != images_ref.end())
571   {
572     int count = (*citty).second;
573
574     if (count == 0)
575     {
576       ImageIndex ref = (*citty).first;
577       images_ref.erase(citty++);
578       destroyImageRef(ref);
579     }
580     else ++citty;
581   }
582
583
584   std::map<DrawStyle, VectorHandle>::iterator sitty = styles.begin();
585
586   while (sitty != styles.end())
587   {
588     std::map<VectorHandle, int>::iterator curitty = styles_ref.find((*sitty).second);
589     int count = (*curitty).second;
590
591     if (count == 0)
592     {
593       VectorHandle ref = (*curitty).first;
594       styles.erase(sitty++);
595       styles_ref.erase(curitty++);
596       styles_lastit_valid = styles_ref_lastit_valid = false;
597       destroyStyleRef(ref);
598
599     }
600     else ++sitty;
601
602   }
603 }
604
605
606 int OsdVector::getImageRef(ImageIndex index)
607 {
608   surfaces_mutex.lock();
609
610   if (images_ref.find(index) == images_ref.end())
611   {
612     return -1;
613   }
614   else
615   {
616     return images_ref[index];
617   }
618
619   surfaces_mutex.unlock();
620 }
621
622 void OsdVector::incStyleRef(VectorHandle index)
623 {
624   if (!styles_ref_lastit_valid || (*styles_ref_lastit).first != index)
625   {
626     styles_ref_lastit_valid = false;
627     styles_ref_lastit = styles_ref.find(index);
628   }
629
630   if (styles_ref_lastit == styles_ref.end())
631   {
632     styles_ref_lastit = styles_ref.insert(std::pair<VectorHandle, int>(index, 1)).first;
633   }
634   else
635   {
636     (*styles_ref_lastit).second++;
637   }
638
639   styles_ref_lastit_valid = true;
640 }
641
642 void OsdVector::removeStyleRef(VectorHandle index)
643 {
644   if (!styles_ref_lastit_valid || (*styles_ref_lastit).first != index)
645   {
646     styles_ref_lastit_valid = false;
647     styles_ref_lastit = styles_ref.find(index);
648   }
649
650   if (styles_ref_lastit != styles_ref.end())
651   {
652     styles_ref_lastit_valid = true;
653     (*styles_ref_lastit).second--;
654   }
655 }
656
657 VectorHandle OsdVector::getStyleRef(const DrawStyle& c)
658 {
659   surfaces_mutex.lock();
660   VectorHandle style_handle = 0;
661
662   if (!styles_lastit_valid || (*styles_lastit).first != c)
663   {
664     styles_lastit_valid = false;
665     styles_lastit = styles.find(c);
666   }
667
668   if (styles_lastit == styles.end())
669   {
670     surfaces_mutex.unlock();
671     style_handle = createStyleRef(c);
672     surfaces_mutex.lock();
673     styles_lastit = styles.insert(std::pair<DrawStyle, VectorHandle>(c, style_handle)).first;
674   }
675   else
676   {
677
678     style_handle = (*styles_lastit).second;
679
680     //Now check if the handle is valid
681     if (!styles_ref_lastit_valid || (*styles_ref_lastit).first != style_handle)
682     {
683       styles_ref_lastit_valid = false;
684       styles_ref_lastit = styles_ref.find(style_handle);
685     }
686
687     if (styles_ref_lastit == styles_ref.end())
688     {
689       //invalid handle recreate
690       surfaces_mutex.unlock();
691       style_handle = createStyleRef(c);
692       surfaces_mutex.lock();
693       (*styles_lastit).second = style_handle;
694     }
695     else styles_ref_lastit_valid = true;
696   }
697
698   styles_lastit_valid = true;
699   incStyleRef(style_handle);
700   surfaces_mutex.unlock();
701   return style_handle;
702 }
703
704 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
705 {
706   ImageIndex image_handle = 0;
707   LoadIndex loadindex = 0;
708   surfaces_mutex.lock();
709
710   if (tvmedias.find(tvmedia) == tvmedias.end())
711   {
712     loadindex = loadTVMedia(tvmedia);
713   }
714   else
715   {
716     image_handle = tvmedias[tvmedia];
717
718     if (images_ref.find(image_handle) == images_ref.end())
719     {
720       //invalid handle recreate
721       loadindex = loadTVMedia(tvmedia);
722       image_handle = 0;
723     }
724     else
725     {
726       incImageRef(image_handle);
727     }
728   }
729
730   /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
731   incImageRef(image_handle);*/
732   image = image_handle;
733   surfaces_mutex.unlock();
734   return loadindex;
735 }
736
737 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
738 {
739   LoadIndex index = 0;
740
741   if (tvmedias_load.find(tvmedia) == tvmedias_load.end())
742   {
743     switch (tvmedia.getType())
744     {
745       case 3:
746         index = VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
747         break;
748
749       case 4:
750       {
751         index = ((long long) tvmedia.getPrimaryID()) << 32LL;
752         reader.addStaticImage(tvmedia.getPrimaryID());
753       } break;
754
755       case 5:
756         index = VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
757         break;
758
759       case 6:
760         index = VDR::getInstance()->loadChannelLogo(tvmedia);
761         break;
762
763       default:
764         index = VDR::getInstance()->loadTVMedia(tvmedia);
765         break;
766     }
767
768     if (tvmedia.getType() != 4 && tvmedia.getStaticFallback() > -1)
769     {
770       reader.informFallback(index, tvmedia.getStaticFallback());
771     }
772
773     tvmedias_load[tvmedia] = index;
774     tvmedias_load_inv[index] = tvmedia;
775   }
776   else
777   {
778     index = tvmedias_load[tvmedia];
779   }
780
781   incLoadIndexRef(index);
782
783   return index;
784 }
785
786
787
788 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
789 {
790   //Beware for thread safety
791   ImageIndex image_index = 0;
792
793   Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %llx arrived %x", index, imageIndex);
794   surfaces_mutex.lock();
795   TVMediaInfo tvmedia = tvmedias_load_inv[index];
796
797   if (imageIndex)
798   {
799     std::map<LoadIndex, int>::iterator itty = loadindex_ref.find(index);
800     image_index = tvmedias[tvmedia] = imageIndex;
801     tvmedias_loaded[index] = image_index;
802
803     if (itty == loadindex_ref.end() || (*itty).second == 0)
804     {
805       // we do not want the picture anymore . Really...
806       // fill images_ref in to not irritate the garbage collector
807       if (images_ref.find(image_index) == images_ref.end())
808       {
809         images_ref[image_index] = 0;
810       }
811     }
812     else
813     {
814       incImageRef(image_index); // hold one index until all loadings refs are gone;
815     }
816   }
817
818   surfaces_mutex.unlock();
819
820
821 }
822
823
824
825
826 /*
827 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
828 {
829         ImageIndex image_handle=0;
830         if (jpegs.find(fileName)==jpegs.end())
831         {
832                 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
833         } else {
834                 image_handle=jpegs[fileName];
835                 *width=0;
836                 *height=0;
837                 if (images_ref.find(image_handle)==images_ref.end()) {
838                         //invalid handle recreate
839                         image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
840                 }
841         }
842         incImageRef(image_handle);
843         return image_handle;
844 }
845 */
846
847 ImageIndex OsdVector::getMonoBitmapRef(void* base, int width, int height)
848 {
849   ImageIndex image_handle;
850   surfaces_mutex.lock();
851
852   if (monobitmaps.find(base) == monobitmaps.end())
853   {
854     surfaces_mutex.unlock();
855     image_handle = createMonoBitmap(base, width, height);
856     surfaces_mutex.lock();
857     monobitmaps[base] = image_handle;
858   }
859   else
860   {
861     image_handle = monobitmaps[base];
862
863     if (images_ref.find(image_handle) == images_ref.end())
864     {
865       //invalid handle recreate
866       surfaces_mutex.unlock();
867       image_handle = createMonoBitmap(base, width, height);
868       surfaces_mutex.lock();
869       monobitmaps[base] = image_handle;
870     }
871   }
872
873   incImageRef(image_handle);
874   surfaces_mutex.unlock();
875   return image_handle;
876 }
877
878 ImageIndex  OsdVector::getImagePalette(int width, int height, const unsigned char* image_data, const unsigned int* palette_data)
879 {
880   ImageIndex image_handle;
881   image_handle = createImagePalette(width, height, image_data, palette_data);
882   surfaces_mutex.lock();
883   palettepics.push_back(image_handle);
884   incImageRef(image_handle);
885   surfaces_mutex.unlock();
886   return image_handle;
887 }
888
889 OsdVector::PictureReader::~PictureReader()
890 {
891   decoders_lock.lock();
892
893   while ( decoders.size())
894   {
895     PictureDecoder* dec = decoders.front();
896     decoders.pop_front();
897     delete dec;
898   }
899
900   decoders_lock.unlock();
901 }
902
903 void OsdVector::PictureReader::init()
904 {
905   threadStart();
906 }
907
908 void OsdVector::PictureReader::shutdown()
909 {
910   threadStop();
911
912
913 }
914
915 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
916 {
917   decoders_lock.lock();
918   decoder->init();
919   decoders.push_front(decoder);
920   decoders_lock.unlock();
921 }
922
923 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
924 {
925   decoders_lock.lock();
926   std::list<PictureDecoder*>::iterator itty = decoders.begin();
927
928   while (itty != decoders.end())
929   {
930     if ((*itty) == decoder)
931     {
932       decoders.erase(itty);
933       break;
934     }
935
936     itty++;
937   }
938
939   Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
940   decoder->shutdown();
941   delete decoder;
942   decoders_lock.unlock();
943 }
944
945 void OsdVector::PictureReader::threadMethod()
946 {
947   OsdVector* osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
948   Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
949
950   while (true)
951   {
952     if (!threadIsActive())
953     {
954       Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
955       threadCheckExit();
956     }
957
958     bool todos = true;
959
960     while (todos)
961     {
962       todos = false;
963       PictureInfo pictinf;
964       decoders_lock.lock();
965       std::list<PictureDecoder*>::iterator itty = decoders.begin();
966
967       while (itty != decoders.end())
968       {
969         if ((*itty)->getDecodedPicture(pictinf))
970         {
971           todos = true;
972           osdvector->createPicture(pictinf);
973         }
974
975         itty++;
976       }
977
978       if (processReceivedPictures())
979       {
980         todos = true;
981       }
982
983       decoders_lock.unlock();
984     }
985
986     //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
987
988     struct timespec target_time;
989     getClockRealTime(&target_time);
990
991     target_time.tv_nsec += 1000000LL * 10;
992
993     if (target_time.tv_nsec > 999999999)
994     {
995       target_time.tv_nsec -= 1000000000L;
996       target_time.tv_sec += 1;
997     }
998
999     threadLock();
1000     threadWaitForSignalTimed(&target_time);
1001     threadUnlock();
1002     //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
1003   }
1004 }
1005
1006 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
1007 {
1008   pict_lock_incoming.lock();
1009   invalid_loadindex.insert(index);
1010   pict_lock_incoming.unlock();
1011 }
1012
1013 void OsdVector::PictureReader::informFallback(LoadIndex index, int fallback)
1014 {
1015   pict_lock_incoming.lock();
1016   inform_fallback[index] = fallback;
1017   pict_lock_incoming.unlock();
1018 }
1019
1020 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket* vresp)
1021 {
1022   pict_lock_incoming.lock();
1023   pict_incoming.push(vresp);
1024   pict_lock_incoming.unlock();
1025   threadSignal();
1026 }
1027
1028
1029 void OsdVector::PictureReader::addStaticImage(unsigned int id)
1030 {
1031   pict_lock_incoming.lock();
1032   pict_incoming_static.push(id);
1033   invalid_loadindex.erase(((long long) id) << 32LL);
1034   pict_lock_incoming.unlock();
1035   threadSignal();
1036 }
1037
1038 #if WIN32
1039   // FIXME win pragma
1040   #pragma warning(disable : 4703)
1041 #endif
1042
1043 bool OsdVector::PictureReader::processReceivedPictures()
1044 {
1045   bool decoded = false;
1046   bool valid = true;
1047   pict_lock_incoming.lock();
1048
1049   if (pict_incoming.size())
1050   {
1051     VDR_ResponsePacket* vresp = pict_incoming.front();
1052     pict_incoming.pop();
1053     std::set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
1054
1055     if (setpos != invalid_loadindex.end())
1056     {
1057       valid = false;
1058       invalid_loadindex.erase(setpos);
1059     }
1060
1061     pict_lock_incoming.unlock();
1062
1063     if (!valid)   // we do not want it anymore skip it;
1064     {
1065       delete vresp;
1066       return true;
1067     }
1068
1069     //           Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived VDR %x %d %d",
1070     //                   vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
1071     bool decode = false;
1072     bool freed = false;
1073     UCHAR* userdata;
1074     ULONG length;
1075
1076     if (vresp->getFlag() != 2)
1077     {
1078       userdata = vresp->getUserData();
1079       length = vresp->getUserDataLength();
1080       decode = true;
1081       freed = true;
1082     }
1083     else
1084     {
1085       int fallback = -1;
1086       pict_lock_incoming.lock();
1087
1088       if (inform_fallback.find(vresp->getStreamID()) != inform_fallback.end())
1089       {
1090         fallback = inform_fallback[vresp->getStreamID()];
1091       }
1092
1093       pict_lock_incoming.unlock();
1094
1095       if (fallback >= 0 && ((OsdVector*)Osd::getInstance())->getStaticImageData(fallback, &userdata, &length))
1096       {
1097         decode = true;
1098         freed = false;
1099       }
1100
1101     }
1102
1103     if (decode)
1104     {
1105       std::list<PictureDecoder*>::iterator itty = decoders.begin();
1106
1107       while (itty != decoders.end())
1108       {
1109         userdata = (*itty)->decodePicture(vresp->getStreamID(), userdata, length, freed);
1110
1111         if (!userdata)
1112         {
1113           decoded = true;
1114           break;
1115         }
1116
1117         itty++;
1118       }
1119
1120       if (!decoded && userdata && freed)
1121       {
1122         free(userdata);
1123       }
1124     }
1125
1126     pict_lock_incoming.lock();
1127     inform_fallback.erase(vresp->getStreamID());
1128     pict_lock_incoming.unlock();
1129     //else  osd->informPicture(vresp->getStreamID(), 0);
1130     delete vresp;
1131   }
1132   else if (pict_incoming_static.size())
1133   {
1134     unsigned int static_id = pict_incoming_static.front();
1135     pict_incoming_static.pop();
1136     std::set<LoadIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
1137
1138     if (setpos != invalid_loadindex.end())
1139     {
1140       valid = false;
1141       invalid_loadindex.erase(setpos);
1142     }
1143
1144     pict_lock_incoming.unlock();
1145
1146     if (!valid)   // we do not want it anymore skip it;
1147     {
1148       return true;
1149     }
1150
1151     UCHAR* userdata;
1152     ULONG length;
1153
1154     if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
1155     {
1156       std::list<PictureDecoder*>::iterator itty = decoders.begin();
1157
1158       while (itty != decoders.end())
1159       {
1160         if (!(*itty)->decodePicture(((long long) static_id) << 32LL, userdata, length, false))
1161         {
1162           decoded = true;
1163           break;
1164         }
1165
1166         itty++;
1167       }
1168     }
1169   }
1170   else
1171   {
1172     pict_lock_incoming.unlock();
1173   }
1174
1175
1176   if (pict_incoming.size() || pict_incoming_static.size()) return true;
1177
1178   return decoded;
1179 }