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