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