]> git.vomp.tv Git - vompclient.git/blob - osdvector.cc
Switch from deprecated libavresample to libswresample. Some AudioOMX CWFs
[vompclient.git] / osdvector.cc
1 /*
2     Copyright 2012 Marten Richter, 2020 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "surfacevector.h"
21 #include "vdr.h"
22 #include "vdrresponsepacket.h"
23 #include "control.h"
24 #include "message.h"
25
26 #include "osdvector.h"
27
28 // The next section is activated, if the magick++ PictureReader is provided, it should be available for many POSIX platforms
29 #ifdef PICTURE_DECODER_MAGICK
30 #define MAGICKCORE_QUANTUM_DEPTH 16
31 #define MAGICKCORE_HDRI_ENABLE 0
32 #include <Magick++.h>
33
34 using namespace Magick;
35
36 class MagickDecoder: public OsdVector::PictureDecoder
37 {
38   public:
39     MagickDecoder(OsdVector::PictureReader* treader): OsdVector::PictureDecoder(treader) {pictInfValid = false;};
40
41     unsigned char* decodePicture(LoadIndex index, unsigned char* buffer, unsigned int length, bool freemem);
42
43     bool getDecodedPicture( struct OsdVector::PictureInfo& pict_inf);
44
45     void freeReference(void* ref);
46
47   protected:
48     OsdVector::PictureInfo pictInf;
49     bool pictInfValid;
50 };
51
52 unsigned char* MagickDecoder::decodePicture(LoadIndex index, unsigned char* buffer, unsigned int length, bool freemem)
53 {
54   if (pictInfValid) return buffer; // does support only one image at a Time;
55
56   Image magicimage;
57   Blob* imageblob = new Blob();
58   Blob myblob;
59
60   try
61   {
62     Log::getInstance()->log("MagickDecoder", Log::DEBUG, "decodePicture");
63
64     if (freemem) myblob.updateNoCopy(buffer, length, Blob::MallocAllocator);
65     else myblob.update(buffer, length);
66
67     magicimage.read(myblob);
68
69     magicimage.write(imageblob, "RGBA");
70
71   }
72   catch ( Exception& error_ )
73   {
74     Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: %s", error_.what());
75     delete imageblob;
76     Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: error mark2");
77     unsigned char* newbuffer = (unsigned char*) malloc(length);
78     memcpy(newbuffer, myblob.data(), length);
79     return newbuffer;
80   }
81
82   pictInf.reference = (void*) imageblob;
83   pictInf.width = magicimage.columns();
84   pictInf.height = magicimage.rows();
85   pictInf.image = imageblob->data();
86   pictInf.decoder = this;
87   pictInf.type = OsdVector::PictureInfo::RGBAMemBlock;
88   pictInf.lindex = index;
89   pictInfValid = true;
90
91
92
93   // I can handle everything, so the return value is always true
94   return NULL;
95 }
96 void MagickDecoder::freeReference(void* ref)
97 {
98   Blob* todelete = (Blob*) ref;
99   delete todelete;
100 }
101
102 bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
103 {
104   if (!pictInfValid) return false;
105
106   pict_inf = pictInf;
107   pictInfValid = false;
108   return true;
109 }
110
111
112 #endif
113
114 OsdVector::OsdVector()
115 {
116   setlocale(LC_CTYPE, "C.UTF-8");
117 #ifdef PICTURE_DECODER_MAGICK
118   reader.addDecoder(new MagickDecoder(&reader));
119 #endif
120 }
121
122 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   styles.clear();
182   styles_ref.clear();
183   styles_lastit_valid = styles_ref_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   // First determine it is already in our system
281   for(si = surfaces.begin(); si != surfaces.end(); si++)
282   {
283     if (si->surface == surf)
284     {
285       // If the surface given (surf) is already in our surfaces vector, reset our SurfaceInfo->commands vector
286       decrementAllRefCounts(si->commands);
287       si->commands.clear();
288       break;
289     }
290   }
291
292   // if not found, make a new SurfaceInfo
293   if (si == surfaces.end())
294   {
295     SurfaceInfo new_sc;
296     new_sc.surface = surf;
297     new_sc.x = x;
298     new_sc.y = y;
299     new_sc.w = width;
300     new_sc.h = height;
301     si = surfaces.insert(si, new_sc);
302   }
303
304   // update any images loaded in the mean time
305
306   for (SVGCommand& command : commands)
307   {
308     if (command.instr == DrawImageLoading)
309     {
310       LoadIndex loadindex = command.target.loadindex;
311
312       if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end())
313       {
314         command.instr = DrawImage;
315         command.target.image = tvmedias_loaded[loadindex];
316         incImageRef(command.target.image);
317         removeLoadIndexRef(loadindex);
318       }
319     }
320   }
321
322   si->commands = commands; // Copy surf->commands to our SurfaceInfo->commands
323   incrementAllRefCounts(si->commands);
324
325   cleanupOrphanedRefs();
326 }
327
328 void OsdVector::removeSurface(const SurfaceVector* surf)
329 {
330   std::lock_guard<std::mutex> lg(surfaces_mutex);
331   for (auto i = surfaces.begin(); i != surfaces.end(); i++)
332   {
333     if (i->surface == surf)
334     {
335       decrementAllRefCounts(i->commands);
336       i->commands.clear();
337       surfaces.erase(i);
338       return;
339     }
340   }
341 }
342
343 void OsdVector::decrementAllRefCounts(std::vector<SVGCommand>& commands)
344 {
345   for (SVGCommand& command : commands)
346   {
347     decrementStyleRefCount(command.getRef());
348
349     ImageIndex ii = command.getImageIndex();
350     if (ii) removeImageRef(ii);
351
352     LoadIndex li = command.getLoadIndex();
353     if (li) removeLoadIndexRef(li);
354   }
355 }
356
357 void OsdVector::incrementAllRefCounts(std::vector<SVGCommand>& commands)
358 {
359   for (SVGCommand& command : commands)
360   {
361     incrementStyleRefCount(command.getRef());
362
363     ImageIndex ii = command.getImageIndex();
364     if (ii) incImageRef(ii);
365
366     LoadIndex li = command.getLoadIndex();
367     if (li) incLoadIndexRef(li);
368   }
369 }
370
371 void OsdVector::incImageRef(ImageIndex index)
372 {
373   if (images_ref.find(index) == images_ref.end())
374   {
375     images_ref[index] = 1;
376   }
377   else
378   {
379     images_ref[index]++;
380   }
381 }
382
383 void OsdVector::removeImageRef(const ImageIndex ref)
384 {
385   images_ref[ref]--;
386 }
387
388 int OsdVector::getLoadIndexRef(LoadIndex index)
389 {
390   surfaces_mutex.lock();
391
392   if (loadindex_ref.find(index) == loadindex_ref.end())
393   {
394     return -1;
395   }
396   else
397   {
398     return loadindex_ref[index];
399   }
400
401   surfaces_mutex.unlock();
402 }
403
404 void OsdVector::incLoadIndexRef(LoadIndex index)
405 {
406   if (loadindex_ref.find(index) == loadindex_ref.end())
407   {
408     loadindex_ref[index] = 1;
409   }
410   else
411   {
412     loadindex_ref[index]++;
413   }
414 }
415
416 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
417 {
418   loadindex_ref[ref]--;
419
420   if (loadindex_ref[ref] == 0)
421   {
422     //now check, if it is already loaded
423     std::map<LoadIndex, ImageIndex>::iterator itty = tvmedias_loaded.find(ref);
424
425     if ( itty != tvmedias_loaded.end())
426     {
427       removeImageRef((*itty).second); // remove lock
428     }
429
430     tvmedias_loaded.erase(ref);
431     //          Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia removeLoadIndexRef %d %llx",tvmedias_load.size(),ref);
432     tvmedias_load.erase(tvmedias_load_inv[ref]);
433     tvmedias_load_inv.erase(ref);
434
435     reader.invalidateLoadIndex(ref);
436   }
437 }
438
439 void OsdVector::cleanupOrphanedRefs()
440 {
441   // Do some garbage collection
442
443   std::map<void*, ImageIndex>::iterator mitty = monobitmaps.begin();
444
445   while (mitty != monobitmaps.end())
446   {
447     std::map<ImageIndex, int>::iterator curitty = images_ref.find((*mitty).second);
448     int count = (*curitty).second;
449
450     if (count == 0)
451     {
452       ImageIndex ref = (*curitty).first;
453       monobitmaps.erase(mitty++);
454       images_ref.erase(curitty++);
455       destroyImageRef(ref);
456     }
457     else ++mitty;
458   }
459
460   /*map<string,ImageIndex>::iterator jitty=jpegs.begin();
461   while (jitty!=jpegs.end()) {
462         map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
463         int count=(*curitty).second;
464         if (count==0) {
465                 ImageIndex ref=(*curitty).first;
466                 jpegs.erase(jitty++);
467                 images_ref.erase(curitty++);
468                 destroyImageRef(ref);
469         } else ++jitty;
470   }*/
471
472   std::map<TVMediaInfo, ImageIndex>::iterator titty = tvmedias.begin();
473
474   while (titty != tvmedias.end())
475   {
476     std::map<ImageIndex, int>::iterator curitty = images_ref.find((*titty).second);
477     int count = (*curitty).second;
478
479     if (count == 0)
480     {
481       ImageIndex ref = (*curitty).first;
482       tvmedias.erase(titty++);
483       images_ref.erase(curitty);
484       destroyImageRef(ref);
485     }
486     else ++titty;
487   }
488
489
490   std::map<TVMediaInfo, LoadIndex>::iterator litty = tvmedias_load.begin();
491
492   while (litty != tvmedias_load.end())
493   {
494     std::map<LoadIndex, int>::iterator curitty = loadindex_ref.find((*litty).second);
495     int count = (*curitty).second;
496
497     if (count == 0)
498     {
499       tvmedias_load_inv.erase((*litty).second);
500       tvmedias_loaded.erase((*litty).second);
501       tvmedias_load.erase(litty++);
502     }
503     else ++litty;
504   }
505
506   std::list<ImageIndex>::iterator pitty = palettepics.begin();
507
508   while (pitty != palettepics.end())
509   {
510     std::map<ImageIndex, int>::iterator curitty = images_ref.find((*pitty));
511     int count = (*curitty).second;
512
513     if (count == 0)
514     {
515       ImageIndex ref = (*curitty).first;
516       palettepics.erase(pitty++);
517       images_ref.erase(curitty++);
518       destroyImageRef(ref);
519     }
520     else ++pitty;
521   }
522
523   std::map<ImageIndex, int>::iterator citty = images_ref.begin();
524
525   while (citty != images_ref.end())
526   {
527     int count = (*citty).second;
528
529     if (count == 0)
530     {
531       ImageIndex ref = (*citty).first;
532       images_ref.erase(citty++);
533       destroyImageRef(ref);
534     }
535     else ++citty;
536   }
537
538
539   std::map<DrawStyle, VectorHandle>::iterator sitty = styles.begin();
540
541   while (sitty != styles.end())
542   {
543     std::map<VectorHandle, int>::iterator curitty = styles_ref.find((*sitty).second);
544     int count = (*curitty).second;
545
546     if (count == 0)
547     {
548       VectorHandle ref = (*curitty).first;
549       styles.erase(sitty++);
550       styles_ref.erase(curitty++);
551       styles_lastit_valid = styles_ref_lastit_valid = false;
552       destroyStyleRef(ref);
553
554     }
555     else ++sitty;
556
557   }
558 }
559
560 int OsdVector::getImageRef(ImageIndex index)
561 {
562   surfaces_mutex.lock();
563
564   if (images_ref.find(index) == images_ref.end())
565   {
566     return -1;
567   }
568   else
569   {
570     return images_ref[index];
571   }
572
573   surfaces_mutex.unlock();
574 }
575
576 void OsdVector::incrementStyleRefCount(VectorHandle index)
577 {
578   if (!styles_ref_lastit_valid || (styles_ref_lastit->first != index))
579   {
580     styles_ref_lastit = styles_ref.find(index);
581     if (styles_ref_lastit == styles_ref.end())
582     {
583       styles_ref_lastit = styles_ref.insert(std::pair<VectorHandle, int>(index, 0)).first;
584     }
585   }
586
587   styles_ref_lastit->second++;
588   styles_ref_lastit_valid = true;
589 }
590
591 void OsdVector::decrementStyleRefCount(VectorHandle index)
592 {
593   if (!styles_ref_lastit_valid || (styles_ref_lastit->first != index))
594   {
595     styles_ref_lastit_valid = false;
596     styles_ref_lastit = styles_ref.find(index);
597   }
598
599   if (styles_ref_lastit != styles_ref.end())
600   {
601     styles_ref_lastit_valid = true;
602     styles_ref_lastit->second--;
603   }
604 }
605
606 VectorHandle OsdVector::getStyleRef(const DrawStyle& c)
607 {
608   surfaces_mutex.lock();
609   VectorHandle style_handle = 0;
610
611   if (!styles_lastit_valid || (styles_lastit->first != c))
612   {
613     styles_lastit_valid = false;
614     styles_lastit = styles.find(c);
615   }
616
617   if (styles_lastit == styles.end())
618   {
619     surfaces_mutex.unlock();
620     style_handle = createStyleRef(c);
621     surfaces_mutex.lock();
622     styles_lastit = styles.insert(std::pair<DrawStyle, VectorHandle>(c, style_handle)).first;
623   }
624   else
625   {
626     style_handle = styles_lastit->second;
627
628     //Now check if the handle is valid
629     if (!styles_ref_lastit_valid || (*styles_ref_lastit).first != style_handle)
630     {
631       styles_ref_lastit_valid = false;
632       styles_ref_lastit = styles_ref.find(style_handle);
633     }
634
635     if (styles_ref_lastit == styles_ref.end())
636     {
637       //invalid handle recreate
638       surfaces_mutex.unlock();
639       style_handle = createStyleRef(c);
640       surfaces_mutex.lock();
641       styles_lastit->second = style_handle;
642     }
643     else styles_ref_lastit_valid = true;
644   }
645
646   styles_lastit_valid = true;
647   incrementStyleRefCount(style_handle);
648   surfaces_mutex.unlock();
649   return style_handle;
650 }
651
652 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
653 {
654   ImageIndex image_handle = 0;
655   LoadIndex loadindex = 0;
656   surfaces_mutex.lock();
657
658   if (tvmedias.find(tvmedia) == tvmedias.end())
659   {
660     loadindex = loadTVMedia(tvmedia);
661   }
662   else
663   {
664     image_handle = tvmedias[tvmedia];
665
666     if (images_ref.find(image_handle) == images_ref.end())
667     {
668       //invalid handle recreate
669       loadindex = loadTVMedia(tvmedia);
670       image_handle = 0;
671     }
672     else
673     {
674       incImageRef(image_handle);
675     }
676   }
677
678   /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
679   incImageRef(image_handle);*/
680   image = image_handle;
681   surfaces_mutex.unlock();
682   return loadindex;
683 }
684
685 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
686 {
687   LoadIndex index = 0;
688
689   if (tvmedias_load.find(tvmedia) == tvmedias_load.end())
690   {
691     switch (tvmedia.getType())
692     {
693       case 3:
694         index = VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
695         break;
696
697       case 4:
698       {
699         index = ((long long) tvmedia.getPrimaryID()) << 32LL;
700         reader.addStaticImage(tvmedia.getPrimaryID());
701       } break;
702
703       case 5:
704         index = VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
705         break;
706
707       case 6:
708         index = VDR::getInstance()->loadChannelLogo(tvmedia);
709         break;
710
711       default:
712         index = VDR::getInstance()->loadTVMedia(tvmedia);
713         break;
714     }
715
716     if (tvmedia.getType() != 4 && tvmedia.getStaticFallback() > -1)
717     {
718       reader.informFallback(index, tvmedia.getStaticFallback());
719     }
720
721     tvmedias_load[tvmedia] = index;
722     tvmedias_load_inv[index] = tvmedia;
723   }
724   else
725   {
726     index = tvmedias_load[tvmedia];
727   }
728
729   incLoadIndexRef(index);
730
731   return index;
732 }
733
734 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
735 {
736   //Beware for thread safety
737   ImageIndex image_index = 0;
738
739   Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %llx arrived %x", index, imageIndex);
740   surfaces_mutex.lock();
741   TVMediaInfo tvmedia = tvmedias_load_inv[index];
742
743   if (imageIndex)
744   {
745     std::map<LoadIndex, int>::iterator itty = loadindex_ref.find(index);
746     image_index = tvmedias[tvmedia] = imageIndex;
747     tvmedias_loaded[index] = image_index;
748
749     if (itty == loadindex_ref.end() || (*itty).second == 0)
750     {
751       // we do not want the picture anymore . Really...
752       // fill images_ref in to not irritate the garbage collector
753       if (images_ref.find(image_index) == images_ref.end())
754       {
755         images_ref[image_index] = 0;
756       }
757     }
758     else
759     {
760       incImageRef(image_index); // hold one index until all loadings refs are gone;
761     }
762   }
763
764   surfaces_mutex.unlock();
765 }
766
767 /*
768 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
769 {
770         ImageIndex image_handle=0;
771         if (jpegs.find(fileName)==jpegs.end())
772         {
773                 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
774         } else {
775                 image_handle=jpegs[fileName];
776                 *width=0;
777                 *height=0;
778                 if (images_ref.find(image_handle)==images_ref.end()) {
779                         //invalid handle recreate
780                         image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
781                 }
782         }
783         incImageRef(image_handle);
784         return image_handle;
785 }
786 */
787
788 ImageIndex OsdVector::getMonoBitmapRef(void* base, int width, int height)
789 {
790   ImageIndex image_handle;
791   surfaces_mutex.lock();
792
793   if (monobitmaps.find(base) == monobitmaps.end())
794   {
795     surfaces_mutex.unlock();
796     image_handle = createMonoBitmap(base, width, height);
797     surfaces_mutex.lock();
798     monobitmaps[base] = image_handle;
799   }
800   else
801   {
802     image_handle = monobitmaps[base];
803
804     if (images_ref.find(image_handle) == images_ref.end())
805     {
806       //invalid handle recreate
807       surfaces_mutex.unlock();
808       image_handle = createMonoBitmap(base, width, height);
809       surfaces_mutex.lock();
810       monobitmaps[base] = image_handle;
811     }
812   }
813
814   incImageRef(image_handle);
815   surfaces_mutex.unlock();
816   return image_handle;
817 }
818
819 ImageIndex OsdVector::getImagePalette(int width, int height, const unsigned char* image_data, const unsigned int* palette_data)
820 {
821   ImageIndex image_handle;
822   image_handle = createImagePalette(width, height, image_data, palette_data);
823   surfaces_mutex.lock();
824   palettepics.push_back(image_handle);
825   incImageRef(image_handle);
826   surfaces_mutex.unlock();
827   return image_handle;
828 }
829
830 OsdVector::PictureReader::~PictureReader()
831 {
832   decoders_lock.lock();
833
834   while (decoders.size())
835   {
836     PictureDecoder* dec = decoders.front();
837     decoders.pop_front();
838     delete dec;
839   }
840
841   decoders_lock.unlock();
842 }
843
844 void OsdVector::PictureReader::init()
845 {
846   threadStart();
847 }
848
849 void OsdVector::PictureReader::shutdown()
850 {
851   threadStop();
852 }
853
854 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
855 {
856   decoders_lock.lock();
857   decoder->init();
858   decoders.push_front(decoder);
859   decoders_lock.unlock();
860 }
861
862 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
863 {
864   decoders_lock.lock();
865   std::list<PictureDecoder*>::iterator itty = decoders.begin();
866
867   while (itty != decoders.end())
868   {
869     if ((*itty) == decoder)
870     {
871       decoders.erase(itty);
872       break;
873     }
874
875     itty++;
876   }
877
878   Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
879   decoder->shutdown();
880   delete decoder;
881   decoders_lock.unlock();
882 }
883
884 void OsdVector::PictureReader::threadMethod()
885 {
886   OsdVector* osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
887   Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
888
889   while (true)
890   {
891     if (!threadIsActive())
892     {
893       Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
894       threadCheckExit();
895     }
896
897     bool todos = true;
898
899     while (todos)
900     {
901       todos = false;
902       PictureInfo pictinf;
903       decoders_lock.lock();
904       std::list<PictureDecoder*>::iterator itty = decoders.begin();
905
906       while (itty != decoders.end())
907       {
908         if ((*itty)->getDecodedPicture(pictinf))
909         {
910           todos = true;
911           osdvector->createPicture(pictinf);
912         }
913
914         itty++;
915       }
916
917       if (processReceivedPictures())
918       {
919         todos = true;
920       }
921
922       decoders_lock.unlock();
923     }
924
925     //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
926
927     struct timespec target_time;
928     getClockRealTime(&target_time);
929
930     target_time.tv_nsec += 1000000LL * 10;
931
932     if (target_time.tv_nsec > 999999999)
933     {
934       target_time.tv_nsec -= 1000000000L;
935       target_time.tv_sec += 1;
936     }
937
938     threadLock();
939     threadWaitForSignalTimed(&target_time);
940     threadUnlock();
941     //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
942   }
943 }
944
945 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
946 {
947   pict_lock_incoming.lock();
948   invalid_loadindex.insert(index);
949   pict_lock_incoming.unlock();
950 }
951
952 void OsdVector::PictureReader::informFallback(LoadIndex index, int fallback)
953 {
954   pict_lock_incoming.lock();
955   inform_fallback[index] = fallback;
956   pict_lock_incoming.unlock();
957 }
958
959 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket* vresp)
960 {
961   pict_lock_incoming.lock();
962   pict_incoming.push(vresp);
963   pict_lock_incoming.unlock();
964   threadSignal();
965 }
966
967
968 void OsdVector::PictureReader::addStaticImage(unsigned int id)
969 {
970   pict_lock_incoming.lock();
971   pict_incoming_static.push(id);
972   invalid_loadindex.erase(((long long) id) << 32LL);
973   pict_lock_incoming.unlock();
974   threadSignal();
975 }
976
977 #if WIN32
978   // FIXME win pragma
979   #pragma warning(disable : 4703)
980 #endif
981
982 bool OsdVector::PictureReader::processReceivedPictures()
983 {
984   bool decoded = false;
985   bool valid = true;
986   pict_lock_incoming.lock();
987
988   if (pict_incoming.size())
989   {
990     VDR_ResponsePacket* vresp = pict_incoming.front();
991     pict_incoming.pop();
992     std::set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
993
994     if (setpos != invalid_loadindex.end())
995     {
996       valid = false;
997       invalid_loadindex.erase(setpos);
998     }
999
1000     pict_lock_incoming.unlock();
1001
1002     if (!valid)   // we do not want it anymore skip it;
1003     {
1004       delete vresp;
1005       return true;
1006     }
1007
1008     // Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived VDR %x %d %d",
1009     // vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
1010     bool decode = false;
1011     bool freed = false;
1012     UCHAR* userdata;
1013     ULONG length;
1014
1015     if (vresp->getFlag() != 2)
1016     {
1017       userdata = vresp->getUserData();
1018       length = vresp->getUserDataLength();
1019       decode = true;
1020       freed = true;
1021     }
1022     else
1023     {
1024       int fallback = -1;
1025       pict_lock_incoming.lock();
1026
1027       if (inform_fallback.find(vresp->getStreamID()) != inform_fallback.end())
1028       {
1029         fallback = inform_fallback[vresp->getStreamID()];
1030       }
1031
1032       pict_lock_incoming.unlock();
1033
1034       if (fallback >= 0 && ((OsdVector*)Osd::getInstance())->getStaticImageData(fallback, &userdata, &length))
1035       {
1036         decode = true;
1037         freed = false;
1038       }
1039     }
1040
1041     if (decode)
1042     {
1043       std::list<PictureDecoder*>::iterator itty = decoders.begin();
1044
1045       while (itty != decoders.end())
1046       {
1047         userdata = (*itty)->decodePicture(vresp->getStreamID(), userdata, length, freed);
1048
1049         if (!userdata)
1050         {
1051           decoded = true;
1052           break;
1053         }
1054
1055         itty++;
1056       }
1057
1058       if (!decoded && userdata && freed)
1059       {
1060         free(userdata);
1061       }
1062     }
1063
1064     pict_lock_incoming.lock();
1065     inform_fallback.erase(vresp->getStreamID());
1066     pict_lock_incoming.unlock();
1067     //else  osd->informPicture(vresp->getStreamID(), 0);
1068     delete vresp;
1069   }
1070   else if (pict_incoming_static.size())
1071   {
1072     unsigned int static_id = pict_incoming_static.front();
1073     pict_incoming_static.pop();
1074     std::set<LoadIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
1075
1076     if (setpos != invalid_loadindex.end())
1077     {
1078       valid = false;
1079       invalid_loadindex.erase(setpos);
1080     }
1081
1082     pict_lock_incoming.unlock();
1083
1084     if (!valid)   // we do not want it anymore skip it;
1085     {
1086       return true;
1087     }
1088
1089     UCHAR* userdata;
1090     ULONG length;
1091
1092     if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
1093     {
1094       std::list<PictureDecoder*>::iterator itty = decoders.begin();
1095
1096       while (itty != decoders.end())
1097       {
1098         if (!(*itty)->decodePicture(((long long) static_id) << 32LL, userdata, length, false))
1099         {
1100           decoded = true;
1101           break;
1102         }
1103
1104         itty++;
1105       }
1106     }
1107   }
1108   else
1109   {
1110     pict_lock_incoming.unlock();
1111   }
1112
1113   if (pict_incoming.size() || pict_incoming_static.size()) return true;
1114
1115   return decoded;
1116 }