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