]> git.vomp.tv Git - vompclient.git/blob - osdvector.cc
Roll OsdOpenVG::haveOpenVGResponse into putOpenVGCommand
[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   std::map<DrawStyle, VectorHandle>::iterator i;
674   for(i = drawstyleHandles.begin(); i != drawstyleHandles.end(); i++)
675   {
676     const DrawStyle* test = &(i->first);
677     Log::getInstance()->log("OsdVector", Log::DEBUG, "DumpStyles: %p %i", test , i->second);
678   }
679
680   std::map<VectorHandle, int>::iterator i2;
681   for (i2 = drawstyleHandlesRefCounts.begin(); i2 != drawstyleHandlesRefCounts.end(); i2++)
682   {
683     Log::getInstance()->log("OsdVector", Log::DEBUG, "DumpStylesRef: %i %i", i2->first, i2->second);
684   }
685 }
686 #endif
687
688 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
689 {
690   ImageIndex image_handle = 0;
691   LoadIndex loadindex = 0;
692   surfaces_mutex.lock();
693
694   if (tvmedias.find(tvmedia) == tvmedias.end())
695   {
696     loadindex = loadTVMedia(tvmedia);
697   }
698   else
699   {
700     image_handle = tvmedias[tvmedia];
701
702     if (images_ref.find(image_handle) == images_ref.end())
703     {
704       //invalid handle recreate
705       loadindex = loadTVMedia(tvmedia);
706       image_handle = 0;
707     }
708     else
709     {
710       incImageRef(image_handle);
711     }
712   }
713
714   /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
715   incImageRef(image_handle);*/
716   image = image_handle;
717   surfaces_mutex.unlock();
718   return loadindex;
719 }
720
721 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
722 {
723   LoadIndex index = 0;
724
725   if (tvmedias_load.find(tvmedia) == tvmedias_load.end())
726   {
727     switch (tvmedia.getType())
728     {
729       case 3:
730         index = VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
731         break;
732
733       case 4:
734       {
735         index = ((long long) tvmedia.getPrimaryID()) << 32LL;
736         reader.addStaticImage(tvmedia.getPrimaryID());
737       } break;
738
739       case 5:
740         index = VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
741         break;
742
743       case 6:
744         index = VDR::getInstance()->loadChannelLogo(tvmedia);
745         break;
746
747       default:
748         index = VDR::getInstance()->loadTVMedia(tvmedia);
749         break;
750     }
751
752     if (tvmedia.getType() != 4 && tvmedia.getStaticFallback() > -1)
753     {
754       reader.informFallback(index, tvmedia.getStaticFallback());
755     }
756
757     tvmedias_load[tvmedia] = index;
758     tvmedias_load_inv[index] = tvmedia;
759   }
760   else
761   {
762     index = tvmedias_load[tvmedia];
763   }
764
765   incLoadIndexRef(index);
766
767   return index;
768 }
769
770 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
771 {
772   //Beware for thread safety
773   ImageIndex image_index = 0;
774
775   Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %llx arrived %x", index, imageIndex);
776   surfaces_mutex.lock();
777   TVMediaInfo tvmedia = tvmedias_load_inv[index];
778
779   if (imageIndex)
780   {
781     std::map<LoadIndex, int>::iterator itty = loadindex_ref.find(index);
782     image_index = tvmedias[tvmedia] = imageIndex;
783     tvmedias_loaded[index] = image_index;
784
785     if (itty == loadindex_ref.end() || (*itty).second == 0)
786     {
787       // we do not want the picture anymore . Really...
788       // fill images_ref in to not irritate the garbage collector
789       if (images_ref.find(image_index) == images_ref.end())
790       {
791         images_ref[image_index] = 0;
792       }
793     }
794     else
795     {
796       incImageRef(image_index); // hold one index until all loadings refs are gone;
797     }
798   }
799
800   surfaces_mutex.unlock();
801 }
802
803 /*
804 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
805 {
806         ImageIndex image_handle=0;
807         if (jpegs.find(fileName)==jpegs.end())
808         {
809                 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
810         } else {
811                 image_handle=jpegs[fileName];
812                 *width=0;
813                 *height=0;
814                 if (images_ref.find(image_handle)==images_ref.end()) {
815                         //invalid handle recreate
816                         image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
817                 }
818         }
819         incImageRef(image_handle);
820         return image_handle;
821 }
822 */
823
824 ImageIndex OsdVector::getMonoBitmapRef(void* base, int width, int height)
825 {
826   ImageIndex image_handle;
827   surfaces_mutex.lock();
828
829   if (monobitmaps.find(base) == monobitmaps.end())
830   {
831     surfaces_mutex.unlock();
832     image_handle = createMonoBitmap(base, width, height);
833     surfaces_mutex.lock();
834     monobitmaps[base] = image_handle;
835   }
836   else
837   {
838     image_handle = monobitmaps[base];
839
840     if (images_ref.find(image_handle) == images_ref.end())
841     {
842       //invalid handle recreate
843       surfaces_mutex.unlock();
844       image_handle = createMonoBitmap(base, width, height);
845       surfaces_mutex.lock();
846       monobitmaps[base] = image_handle;
847     }
848   }
849
850   incImageRef(image_handle);
851   surfaces_mutex.unlock();
852   return image_handle;
853 }
854
855 ImageIndex OsdVector::getImagePalette(int width, int height, const unsigned char* image_data, const unsigned int* palette_data)
856 {
857   ImageIndex image_handle;
858   image_handle = createImagePalette(width, height, image_data, palette_data);
859   surfaces_mutex.lock();
860   palettepics.push_back(image_handle);
861   incImageRef(image_handle);
862   surfaces_mutex.unlock();
863   return image_handle;
864 }
865
866 OsdVector::PictureReader::~PictureReader()
867 {
868   decoders_lock.lock();
869
870   while (decoders.size())
871   {
872     PictureDecoder* dec = decoders.front();
873     decoders.pop_front();
874     delete dec;
875   }
876
877   decoders_lock.unlock();
878 }
879
880 void OsdVector::PictureReader::init()
881 {
882   threadStart();
883 }
884
885 void OsdVector::PictureReader::shutdown()
886 {
887   threadStop();
888 }
889
890 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
891 {
892   decoders_lock.lock();
893   decoder->init();
894   decoders.push_front(decoder);
895   decoders_lock.unlock();
896 }
897
898 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
899 {
900   decoders_lock.lock();
901   std::list<PictureDecoder*>::iterator itty = decoders.begin();
902
903   while (itty != decoders.end())
904   {
905     if ((*itty) == decoder)
906     {
907       decoders.erase(itty);
908       break;
909     }
910
911     itty++;
912   }
913
914   Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
915   decoder->shutdown();
916   delete decoder;
917   decoders_lock.unlock();
918 }
919
920 void OsdVector::PictureReader::threadMethod()
921 {
922   OsdVector* osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
923   Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
924
925   while (true)
926   {
927     if (!threadIsActive())
928     {
929       Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
930       threadCheckExit();
931     }
932
933     bool todos = true;
934
935     while (todos)
936     {
937       todos = false;
938       PictureInfo pictinf;
939       decoders_lock.lock();
940       std::list<PictureDecoder*>::iterator itty = decoders.begin();
941
942       while (itty != decoders.end())
943       {
944         if ((*itty)->getDecodedPicture(pictinf))
945         {
946           todos = true;
947           osdvector->createPicture(pictinf);
948         }
949
950         itty++;
951       }
952
953       if (processReceivedPictures())
954       {
955         todos = true;
956       }
957
958       decoders_lock.unlock();
959     }
960
961     //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
962
963     struct timespec target_time;
964     getClockRealTime(&target_time);
965
966     target_time.tv_nsec += 1000000LL * 10;
967
968     if (target_time.tv_nsec > 999999999)
969     {
970       target_time.tv_nsec -= 1000000000L;
971       target_time.tv_sec += 1;
972     }
973
974     threadLock();
975     threadWaitForSignalTimed(&target_time);
976     threadUnlock();
977     //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
978   }
979 }
980
981 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
982 {
983   pict_lock_incoming.lock();
984   invalid_loadindex.insert(index);
985   pict_lock_incoming.unlock();
986 }
987
988 void OsdVector::PictureReader::informFallback(LoadIndex index, int fallback)
989 {
990   pict_lock_incoming.lock();
991   inform_fallback[index] = fallback;
992   pict_lock_incoming.unlock();
993 }
994
995 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket* vresp)
996 {
997   pict_lock_incoming.lock();
998   pict_incoming.push(vresp);
999   pict_lock_incoming.unlock();
1000   threadSignal();
1001 }
1002
1003
1004 void OsdVector::PictureReader::addStaticImage(unsigned int id)
1005 {
1006   pict_lock_incoming.lock();
1007   pict_incoming_static.push(id);
1008   invalid_loadindex.erase(((long long) id) << 32LL);
1009   pict_lock_incoming.unlock();
1010   threadSignal();
1011 }
1012
1013 #if WIN32
1014   // FIXME win pragma
1015   #pragma warning(disable : 4703)
1016 #endif
1017
1018 bool OsdVector::PictureReader::processReceivedPictures()
1019 {
1020   bool decoded = false;
1021   bool valid = true;
1022   pict_lock_incoming.lock();
1023
1024   if (pict_incoming.size())
1025   {
1026     VDR_ResponsePacket* vresp = pict_incoming.front();
1027     pict_incoming.pop();
1028     std::set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
1029
1030     if (setpos != invalid_loadindex.end())
1031     {
1032       valid = false;
1033       invalid_loadindex.erase(setpos);
1034     }
1035
1036     pict_lock_incoming.unlock();
1037
1038     if (!valid)   // we do not want it anymore skip it;
1039     {
1040       delete vresp;
1041       return true;
1042     }
1043
1044     // Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived VDR %x %d %d",
1045     // vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
1046     bool decode = false;
1047     bool freed = false;
1048     UCHAR* userdata;
1049     ULONG length;
1050
1051     if (vresp->getFlag() != 2)
1052     {
1053       userdata = vresp->getUserData();
1054       length = vresp->getUserDataLength();
1055       decode = true;
1056       freed = true;
1057     }
1058     else
1059     {
1060       int fallback = -1;
1061       pict_lock_incoming.lock();
1062
1063       if (inform_fallback.find(vresp->getStreamID()) != inform_fallback.end())
1064       {
1065         fallback = inform_fallback[vresp->getStreamID()];
1066       }
1067
1068       pict_lock_incoming.unlock();
1069
1070       if (fallback >= 0 && ((OsdVector*)Osd::getInstance())->getStaticImageData(fallback, &userdata, &length))
1071       {
1072         decode = true;
1073         freed = false;
1074       }
1075     }
1076
1077     if (decode)
1078     {
1079       std::list<PictureDecoder*>::iterator itty = decoders.begin();
1080
1081       while (itty != decoders.end())
1082       {
1083         userdata = (*itty)->decodePicture(vresp->getStreamID(), userdata, length, freed);
1084
1085         if (!userdata)
1086         {
1087           decoded = true;
1088           break;
1089         }
1090
1091         itty++;
1092       }
1093
1094       if (!decoded && userdata && freed)
1095       {
1096         free(userdata);
1097       }
1098     }
1099
1100     pict_lock_incoming.lock();
1101     inform_fallback.erase(vresp->getStreamID());
1102     pict_lock_incoming.unlock();
1103     //else  osd->informPicture(vresp->getStreamID(), 0);
1104     delete vresp;
1105   }
1106   else if (pict_incoming_static.size())
1107   {
1108     unsigned int static_id = pict_incoming_static.front();
1109     pict_incoming_static.pop();
1110     std::set<LoadIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
1111
1112     if (setpos != invalid_loadindex.end())
1113     {
1114       valid = false;
1115       invalid_loadindex.erase(setpos);
1116     }
1117
1118     pict_lock_incoming.unlock();
1119
1120     if (!valid)   // we do not want it anymore skip it;
1121     {
1122       return true;
1123     }
1124
1125     UCHAR* userdata;
1126     ULONG length;
1127
1128     if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
1129     {
1130       std::list<PictureDecoder*>::iterator itty = decoders.begin();
1131
1132       while (itty != decoders.end())
1133       {
1134         if (!(*itty)->decodePicture(((long long) static_id) << 32LL, userdata, length, false))
1135         {
1136           decoded = true;
1137           break;
1138         }
1139
1140         itty++;
1141       }
1142     }
1143   }
1144   else
1145   {
1146     pict_lock_incoming.unlock();
1147   }
1148
1149   if (pict_incoming.size() || pict_incoming_static.size()) return true;
1150
1151   return decoded;
1152 }