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