]> git.vomp.tv Git - vompclient.git/blob - osdvector.cc
Screenshot support for vector based osd on raspberry pi
[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 }
112
113 OsdVector::~OsdVector()
114 {
115 }
116
117
118 int OsdVector::getFD()
119 {
120         return 0;
121 }
122
123 void OsdVector::screenShot(const char* fileName)
124 {
125         //Do nothing, if no libmagick is there
126 #ifdef PICTURE_DECODER_MAGICK
127         int width,height;
128         getRealScreenSize(width,height);
129         size_t length=width*height*4;
130         void *mem=malloc(length);
131
132         try {
133                 Blob myblob;
134                 if (!screenShot(mem,width,height,true)) {
135                         Log::getInstance()->log("OsdVector", Log::DEBUG, "Screenshot failed!");
136                         free(mem);
137                         return;
138                 }
139                 myblob.updateNoCopy(mem,length,Blob::MallocAllocator);
140                 Image image(myblob,Geometry(width,height),8,"RGBA");
141                 image.write(fileName);
142         }catch( Exception &error_ )
143         {
144                 Log::getInstance()->log("MagickEncoder", Log::DEBUG, "Libmagick: %s",error_.what());
145
146         }
147
148 #endif
149 }
150
151 Surface * OsdVector::createNewSurface()
152 {
153         return new SurfaceVector(this);
154 }
155
156 void OsdVector::BeginPainting()
157 {
158         surfaces_mutex.Lock();
159 }
160 void OsdVector::EndPainting()
161 {
162         surfaces_mutex.Unlock();
163 }
164
165 void OsdVector::Blank()
166 {
167         // do nothing? remove this one?
168 }
169
170 int OsdVector::restore()
171 {
172         // First clear the contents of all registered surfaces
173         surfaces_mutex.Lock();
174
175         //Now go through all surfaces and draw them
176         list<SurfaceCommands>::iterator curdraw=scommands.begin();
177         while (curdraw!=scommands.end()) {
178                 (*curdraw).commands.clear();
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         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         list<SurfaceCommands*> todraw; //First figure out if a surfaces is below another surface
203         list<SurfaceCommands>::iterator itty1=scommands.begin();
204         while (itty1!=scommands.end()) {
205                 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         list<SurfaceCommands*>::iterator curdraw=todraw.begin();
228         while (curdraw!=todraw.end()) {
229                 drawSetTrans(*(*curdraw));
230                 list<SVGCommand>::iterator commands=(*(*curdraw)).commands.begin();
231                 list<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                         list<SVGCommand>& commands)
258 {
259         surfaces_mutex.Lock();
260         //First determine it is already in our system
261         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         list<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         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(list<SVGCommand>& commands )
328 {
329
330         list<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(list<SVGCommand>& commands )
342 {
343         list<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         if (loadindex_ref.find(index)==loadindex_ref.end()) {
373                 return -1;
374         } else {
375                 return loadindex_ref[index];
376         }
377 }
378
379 void OsdVector::incLoadIndexRef(LoadIndex index)
380 {
381         if (loadindex_ref.find(index)==loadindex_ref.end()) {
382                 loadindex_ref[index]=1;
383         } else {
384                 loadindex_ref[index]++;
385         }
386 }
387
388 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
389 {
390         loadindex_ref[ref]--;
391         if (loadindex_ref[ref]==0) {
392                 //now check, if it is already loaded
393                 map<LoadIndex,ImageIndex>::iterator itty=tvmedias_loaded.find(ref);
394                 if ( itty != tvmedias_loaded.end()) {
395                         removeImageRef((*itty).second); // remove lock
396                 }
397                 tvmedias_loaded.erase(ref);
398                 tvmedias_load.erase(tvmedias_load_inv[ref]);
399                 tvmedias_load_inv.erase(ref);
400
401                 reader.invalidateLoadIndex(ref);
402
403
404         }
405 }
406
407
408
409 void OsdVector::cleanupOrphanedRefs()
410 { // Do some garbage collection
411
412         map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
413         while (mitty!=monobitmaps.end()) {
414                 map<ImageIndex,int>::iterator curitty=images_ref.find((*mitty).second);
415                 int count=(*curitty).second;
416                 if (count==0) {
417                         ImageIndex ref=(*curitty).first;
418                         monobitmaps.erase(mitty++);
419                         images_ref.erase(curitty++);
420                         destroyImageRef(ref);
421                 } else ++mitty;
422         }
423
424         /*map<string,ImageIndex>::iterator jitty=jpegs.begin();
425         while (jitty!=jpegs.end()) {
426                 map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
427                 int count=(*curitty).second;
428                 if (count==0) {
429                         ImageIndex ref=(*curitty).first;
430                         jpegs.erase(jitty++);
431                         images_ref.erase(curitty++);
432                         destroyImageRef(ref);
433                 } else ++jitty;
434         }*/
435
436         map<TVMediaInfo,ImageIndex>::iterator titty=tvmedias.begin();
437         while (titty!=tvmedias.end()) {
438                 map<ImageIndex,int>::iterator curitty=images_ref.find((*titty).second);
439                 int count=(*curitty).second;
440                 if (count==0) {
441                         ImageIndex ref=(*curitty).first;
442                         tvmedias.erase(titty++);
443                         images_ref.erase(curitty);
444                         destroyImageRef(ref);
445                 } else ++titty;
446         }
447
448
449         map<TVMediaInfo,LoadIndex>::iterator litty=tvmedias_load.begin();
450         while (litty!=tvmedias_load.end()) {
451                 map<LoadIndex,int>::iterator curitty=loadindex_ref.find((*litty).second);
452                 int count=(*curitty).second;
453                 if (count==0) {
454                         tvmedias_load_inv.erase((*litty).second);
455                         tvmedias_loaded.erase((*litty).second);
456                         tvmedias_load.erase(litty++);
457                 } else ++litty;
458         }
459
460         list<ImageIndex>::iterator pitty=palettepics.begin();
461         while (pitty!=palettepics.end()) {
462                 map<ImageIndex,int>::iterator curitty=images_ref.find((*pitty));
463                 int count=(*curitty).second;
464                 if (count==0) {
465                         ImageIndex ref=(*curitty).first;
466                         palettepics.erase(pitty++);
467                         images_ref.erase(curitty++);
468                         destroyImageRef(ref);
469                 } else ++pitty;
470         }
471
472
473         map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
474         while (sitty!=styles.end()) {
475                 map<unsigned int,int>::iterator curitty=styles_ref.find((*sitty).second);
476                 int count=(*curitty).second;
477                 if (count==0) {
478                         unsigned int ref=(*curitty).first;
479                         styles.erase(sitty++);
480                         styles_ref.erase(curitty++);
481                         destroyStyleRef(ref);
482
483                 } else ++sitty;
484
485         }
486 }
487
488
489 int OsdVector::getImageRef(ImageIndex index)
490 {
491         if (images_ref.find(index)==images_ref.end()) {
492                 return -1;
493         } else {
494                 return images_ref[index];
495         }
496 }
497
498 void OsdVector::incStyleRef(unsigned int index)
499 {
500         if (styles_ref.find(index)==styles_ref.end()) {
501                 styles_ref[index]=1;
502         } else {
503                 styles_ref[index]++;
504         }
505 }
506
507 void OsdVector::removeStyleRef(unsigned int index)
508 {
509         styles_ref[index]--;
510 }
511
512 unsigned int OsdVector::getStyleRef(const DrawStyle &c)
513 {
514         unsigned int style_handle=0;
515         if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
516         {
517                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
518         } else {
519                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
520                 //Now check if the handle is valid
521                 if (styles_ref.find(style_handle)==styles_ref.end()) {
522                         //invalid handle recreate
523                         style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
524                 }
525         }
526         incStyleRef(style_handle);
527         return style_handle;
528 }
529
530 unsigned int OsdVector::getColorRef(const Colour &c)
531 {
532         unsigned int style_handle=0;
533         if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
534         {
535                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
536         } else {
537                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
538                 if (styles_ref.find(style_handle)==styles_ref.end()) {
539                         //invalid handle recreate
540                         style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
541                 }
542         }
543         incStyleRef(style_handle);
544         return style_handle;
545 }
546
547 int OsdVector::getStyleRef(unsigned int index)
548 {
549         if (styles_ref.find(index)==styles_ref.end()) {
550                 return -1;
551         } else {
552                 return styles_ref[index];
553         }
554 }
555
556 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
557 {
558         ImageIndex image_handle=0;
559         LoadIndex loadindex=0;
560         if (tvmedias.find(tvmedia)==tvmedias.end())
561         {
562                 loadindex=loadTVMedia(tvmedia);
563         } else {
564                 image_handle=tvmedias[tvmedia];
565                 if (images_ref.find(image_handle)==images_ref.end()) {
566                         //invalid handle recreate
567                         loadindex=loadTVMedia(tvmedia);
568                         image_handle=0;
569                 } else {
570                         incImageRef(image_handle);
571                 }
572         }
573         /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
574         incImageRef(image_handle);*/
575         image=image_handle;
576         return loadindex;
577 }
578
579 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
580 {
581         LoadIndex index=0;
582         if (tvmedias_load.find(tvmedia)==tvmedias_load.end())
583         {
584                 switch (tvmedia.getType()) {
585                 case 3:
586                         index=VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
587                         break;
588                 case 4: {
589                         index = ((long long) tvmedia.getPrimaryID()) << 32LL;
590                         reader.addStaticImage(tvmedia.getPrimaryID());
591                 } break;
592                 case 5:
593                         index=VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
594                 break;
595                 case 6:
596                         index=VDR::getInstance()->loadChannelLogo(tvmedia);
597                 break;
598                 default:
599                         index=VDR::getInstance()->loadTVMedia(tvmedia);
600                         break;
601                 }
602
603                 tvmedias_load[tvmedia]=index;
604                 tvmedias_load_inv[index]=tvmedia;
605         } else {
606
607                 index=tvmedias_load[tvmedia];
608         }
609
610         incLoadIndexRef(index);
611
612         return index;
613 }
614
615
616
617 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
618 {
619         //Beware for thread safety
620         ImageIndex image_index=0;
621
622         TVMediaInfo tvmedia=tvmedias_load_inv[index];
623           Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %llx arrived %d",index, imageIndex);
624         if (imageIndex) {
625                 image_index=tvmedias[tvmedia]=imageIndex;
626                 tvmedias_loaded[index]=image_index;
627                 if (getLoadIndexRef(index) < 1) {
628                         // we do not want the picture anymore . Really...
629                         // fill images_ref in to not irritate the garbage collector
630                         if (getImageRef(image_index) < 0) {
631                                 images_ref[image_index]=0;
632                         }
633                 } else {
634
635                         incImageRef(image_index); // hold one index until all loadings refs are gone;
636                 }
637         }
638
639
640 }
641
642
643
644
645 /*
646 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
647 {
648         ImageIndex image_handle=0;
649         if (jpegs.find(fileName)==jpegs.end())
650         {
651                 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
652         } else {
653                 image_handle=jpegs[fileName];
654                 *width=0;
655                 *height=0;
656                 if (images_ref.find(image_handle)==images_ref.end()) {
657                         //invalid handle recreate
658                         image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
659                 }
660         }
661         incImageRef(image_handle);
662         return image_handle;
663 }
664 */
665
666 ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
667 {
668         ImageIndex image_handle;
669         if (monobitmaps.find(base)==monobitmaps.end())
670         {
671                 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
672         } else {
673                 image_handle=monobitmaps[base];
674                 if (images_ref.find(image_handle)==images_ref.end()) {
675                         //invalid handle recreate
676                         image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
677                 }
678         }
679         incImageRef(image_handle);
680         return image_handle;
681 }
682
683 ImageIndex  OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
684 {
685         ImageIndex image_handle;
686         image_handle=createImagePalette(width,height,image_data,palette_data);
687         palettepics.push_back(image_handle);
688         incImageRef(image_handle);
689         return image_handle;
690 }
691
692 OsdVector::PictureReader::~PictureReader()
693 {
694         decoders_lock.Lock();
695         while ( decoders.size()) {
696                 PictureDecoder* dec=decoders.front();
697                 decoders.pop_front();
698                 delete dec;
699         }
700
701         decoders_lock.Unlock();
702 }
703
704 void OsdVector::PictureReader::init()
705 {
706         threadStart();
707 }
708
709 void OsdVector::PictureReader::shutdown()
710 {
711         threadStop();
712
713
714 }
715
716 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
717 {
718         decoders_lock.Lock();
719         decoder->init();
720         decoders.push_front(decoder);
721         decoders_lock.Unlock();
722 }
723
724 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
725 {
726         decoders_lock.Lock();
727         std::list<PictureDecoder*>::iterator itty=decoders.begin();
728         while (itty!=decoders.end()) {
729                 if ((*itty) == decoder)
730                 {
731                         decoders.erase(itty);
732                         break;
733                 }
734                 itty++;
735         }
736         Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
737         decoder->shutdown();
738         delete decoder;
739         decoders_lock.Unlock();
740 }
741
742 void OsdVector::PictureReader::threadMethod()
743 {
744         OsdVector *osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
745         Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
746         while (true) {
747                 if (!threadIsActive()) {
748                         Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
749                         threadCheckExit();
750                 }
751
752                 bool todos=true;
753                 while (todos)
754                 {
755                         todos=false;
756                         PictureInfo pictinf;
757                         decoders_lock.Lock();
758                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
759
760                         while (itty!=decoders.end()) {
761                                 if ((*itty)->getDecodedPicture(pictinf)) {
762                                         todos = true;
763                                         osdvector->createPicture(pictinf);
764                                 }
765
766                                 itty++;
767                         }
768                         if (processReceivedPictures())
769                         {
770                                 todos = true;
771                         }
772
773                         decoders_lock.Unlock();
774                 }
775                 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
776
777                 struct timespec target_time;
778                 clock_gettime(CLOCK_REALTIME,&target_time);
779                 target_time.tv_nsec+=1000000LL*10;
780                 if (target_time.tv_nsec>999999999) {
781                         target_time.tv_nsec-=1000000000L;
782                         target_time.tv_sec+=1;
783                 }
784                 threadLock();
785                 threadWaitForSignalTimed(&target_time);
786                 threadUnlock();
787                 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
788         }
789 }
790
791 void OsdVector::PictureReader::threadPostStopCleanup()
792 {
793
794 }
795
796 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
797 {
798         pict_lock_incoming.Lock();
799         invalid_loadindex.insert(index);
800         pict_lock_incoming.Unlock();
801 }
802
803 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket *vresp)
804 {
805         pict_lock_incoming.Lock();
806         pict_incoming.push(vresp);
807         pict_lock_incoming.Unlock();
808         threadSignal();
809 }
810
811
812 void OsdVector::PictureReader::addStaticImage(unsigned int id)
813 {
814         pict_lock_incoming.Lock();
815         pict_incoming_static.push(id);
816         invalid_loadindex.erase(((long long) id) << 32LL);
817         pict_lock_incoming.Unlock();
818         threadSignal();
819 }
820
821 bool OsdVector::PictureReader::processReceivedPictures()
822 {
823         bool decoded = false;
824         bool valid = true;
825         pict_lock_incoming.Lock();
826     if (pict_incoming.size()) {
827                 VDR_ResponsePacket *vresp=pict_incoming.front();
828                 pict_incoming.pop();
829                 set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
830                 if (setpos != invalid_loadindex.end()) {
831                         valid = false;
832                         invalid_loadindex.erase(setpos);
833                 }
834                 pict_lock_incoming.Unlock();
835                 if (!valid) { // we do not want it anymore skip it;
836                         delete vresp;
837                         return true;
838                 }
839         //       Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived VDR %x %d %d",
840         //                       vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
841                 if (vresp->getFlag() != 2) {
842                         UCHAR *userdata=vresp->getUserData();
843                         ULONG length=vresp->getUserDataLength();
844                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
845                         while (itty!=decoders.end()) {
846                                 userdata=(*itty)->decodePicture(vresp->getStreamID(), userdata, length);
847                                 if (!userdata){
848                                         decoded=true;
849                                         break;
850                                 }
851                                 itty++;
852                         }
853                         if (!decoded && userdata ){
854                                 free(userdata);
855                         }
856                 }
857                 //else  osd->informPicture(vresp->getStreamID(), 0);
858                 delete vresp;
859         } else if (pict_incoming_static.size()){
860                 unsigned int static_id = pict_incoming_static.front();
861                 pict_incoming_static.pop();
862                 set<LoadIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
863                 if (setpos != invalid_loadindex.end()) {
864                         valid = false;
865                         invalid_loadindex.erase(setpos);
866                 }
867                 pict_lock_incoming.Unlock();
868                 if (!valid) { // we do not want it anymore skip it;
869                         return true;
870                 }
871
872                 UCHAR *userdata;
873                 ULONG length;
874                 if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
875                 {
876                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
877                         while (itty!=decoders.end()) {
878                                 if (!(*itty)->decodePicture(((long long) static_id) << 32LL,userdata, length, false)){
879                                         decoded=true;
880                                         break;
881                                 }
882                                 itty++;
883                         }
884                 }
885         } else {
886                 pict_lock_incoming.Unlock();
887         }
888
889
890     if (pict_incoming.size() || pict_incoming_static.size()) return true;
891         return decoded;
892 }