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