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