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