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