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