]> git.vomp.tv Git - vompclient.git/blob - osdvector.cc
Extended recordings menu, including artwork from tvscraper
[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         bool decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length);
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 bool MagickDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length)
50 {
51         if (pictInfValid) return false; // does support only one image at a Time;
52         Image magicimage;
53         Blob *imageblob = new Blob();
54
55         try{
56                 Log::getInstance()->log("MagickDecoder", Log::DEBUG, "decodePicture");
57                 Blob myblob;
58                 myblob.updateNoCopy(buffer,length,Blob::MallocAllocator);
59                 magicimage.read(myblob);
60
61                 magicimage.write(imageblob,"RGBA");
62
63         }catch( Exception &error_ )
64         {
65                 Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: %s",error_.what());
66                 delete imageblob;
67
68                 return false;
69         }
70         pictInf.reference = (void*) imageblob;
71         pictInf.width = magicimage.columns();
72         pictInf.height = magicimage.rows();
73         pictInf.image = imageblob->data();
74         pictInf.decoder = this;
75         pictInf.type = OsdVector::PictureInfo::RGBAMemBlock;
76         pictInf.lindex = index;
77         pictInfValid = true;
78
79
80
81         // I can handle everything, so the return value is always true
82         return true;
83 }
84 void MagickDecoder::freeReference(void * ref)
85 {
86         Blob *todelete = (Blob*) ref;
87         delete todelete;
88 }
89
90 bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
91 {
92         if (!pictInfValid) return false;
93         pict_inf=pictInf;
94         pictInfValid = false;
95         return true;
96 }
97
98
99 #endif
100
101 OsdVector::OsdVector()
102 {
103         setlocale(LC_CTYPE,"C.UTF-8");
104 #ifdef PICTURE_DECODER_MAGICK
105         reader.addDecoder(new MagickDecoder(&reader));
106 #endif
107
108 }
109
110 OsdVector::~OsdVector()
111 {
112 }
113
114
115 int OsdVector::getFD()
116 {
117         return 0;
118 }
119
120 void OsdVector::screenShot(const char* fileName)
121 {
122         //Do nothing,
123 }
124
125 Surface * OsdVector::createNewSurface()
126 {
127         return new SurfaceVector(this);
128 }
129
130 void OsdVector::BeginPainting()
131 {
132         surfaces_mutex.Lock();
133 }
134 void OsdVector::EndPainting()
135 {
136         surfaces_mutex.Unlock();
137 }
138
139 void OsdVector::Blank()
140 {
141         // do nothing? remove this one?
142 }
143
144 int OsdVector::restore()
145 {
146         // First clear the contents of all registered surfaces
147         surfaces_mutex.Lock();
148
149         //Now go through all surfaces and draw them
150         list<SurfaceCommands>::iterator curdraw=scommands.begin();
151         while (curdraw!=scommands.end()) {
152                 (*curdraw).commands.clear();
153                 curdraw++;
154         }
155         //also clear all handles, they are now invalid, no need to release them
156         images_ref.clear();
157         monobitmaps.clear();
158         jpegs.clear();
159         styles.clear();
160         styles_ref.clear();
161
162         surfaces_mutex.Unlock();
163         return 1;
164 }
165
166 void OsdVector::drawSurfaces()
167 {
168         surfaces_mutex.Lock();
169         list<SurfaceCommands*> todraw; //First figure out if a surfaces is below another surface
170         list<SurfaceCommands>::iterator itty1=scommands.begin();
171         while (itty1!=scommands.end()) {
172                 list<SurfaceCommands>::iterator itty2=itty1;
173                 itty2++;
174                 bool hidden=false;
175                 while (itty2!=scommands.end()) {
176                         SurfaceCommands & ref1=*itty1;
177                         SurfaceCommands & ref2=*itty2;
178                         if (ref1.x>=ref2.x && ref1.y>=ref2.y
179                                         && (ref1.x+ref1.w) <= (ref2.x+ref2.w)
180                                         && (ref1.y+ref1.h) <= (ref2.y+ref2.h) ) {
181                                 hidden=true;
182                                 break;
183                         }
184                         itty2++;
185                 }
186                 if (!hidden) { // we are not hidden, perfect
187                         todraw.push_back(&(*itty1));
188                 }
189                 itty1++;
190         }
191         int swidth,sheight;
192         getScreenSize(swidth,sheight);
193         //Now go through all surfaces and draw them
194         list<SurfaceCommands*>::iterator curdraw=todraw.begin();
195         while (curdraw!=todraw.end()) {
196                 drawSetTrans(*(*curdraw));
197                 list<SVGCommand>::iterator commands=(*(*curdraw)).commands.begin();
198                 list<SVGCommand>::iterator end=(*(*curdraw)).commands.end();
199                 while (commands!=end) {
200                         // update any images loaded in the mean time
201                         if ((*commands).instr==DrawImageLoading) {
202                                 LoadIndex loadindex=(*commands).target.loadindex;
203                                 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
204                                         (*commands).instr=DrawImage;
205                                         (*commands).target.image=tvmedias_loaded[loadindex];;
206                                         incImageRef((*commands).target.image);
207                                         removeLoadIndexRef(loadindex);
208                                 }
209
210                         }
211                         // Now check if the command is on screen!
212                         if  (!(*commands).Outside(0,0,swidth,sheight)) {
213                                 executeDrawCommand(*commands);
214                         }
215                         commands++;
216                 }
217                 curdraw++;
218         }
219
220         surfaces_mutex.Unlock();
221 }
222
223 void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
224                         list<SVGCommand>& commands)
225 {
226         surfaces_mutex.Lock();
227         //First determine it is already in our system
228         list<SurfaceCommands>::iterator itty=scommands.begin();
229         while (itty!=scommands.end()) {
230                 if ((*itty).surf==surf) {
231                         //decrease the references
232                         dereferenceSVGCommand((*itty).commands);
233                         break;
234                 }
235                 itty++;
236         }
237         // if not insert it
238         if (itty==scommands.end()) {
239                 SurfaceCommands new_sc;
240                 new_sc.surf=surf;
241                 new_sc.x=x;
242                 new_sc.y=y;
243                 new_sc.w=width;
244                 new_sc.h=height;
245                 itty=scommands.insert(itty,new_sc);
246         }
247         // update any images loaded in the mean time
248         list<SVGCommand>::iterator ilitty=commands.begin();
249
250         while (ilitty!=commands.end())
251         {
252                 if ((*ilitty).instr==DrawImageLoading) {
253                         LoadIndex loadindex=(*ilitty).target.loadindex;
254                         if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
255
256                                 (*ilitty).instr=DrawImage;
257                                 (*ilitty).target.image=tvmedias_loaded[loadindex];
258                                 incImageRef((*ilitty).target.image);
259                                 removeLoadIndexRef(loadindex);
260                         }
261                 }
262                 ilitty++;
263         }
264
265
266         // then clear and copy
267         (*itty).commands.clear();
268         (*itty).commands=commands;
269         //increase the references
270         list<SVGCommand>::iterator sitty=(*itty).commands.begin();
271         while (sitty!=(*itty).commands.end())
272         {
273                 incStyleRef((*sitty).getRef());
274                 ImageIndex ii=(*sitty).getImageIndex();
275                 if (ii) incImageRef(ii);
276                 LoadIndex li=(*sitty).getLoadIndex();
277                 if (li) incLoadIndexRef(li);
278                 sitty++;
279         }
280         cleanupOrphanedRefs();
281
282         surfaces_mutex.Unlock();
283 }
284
285 void OsdVector::removeSurface(const SurfaceVector *surf)
286 {
287         surfaces_mutex.Lock();
288         //First determine it is already in our system
289         list<SurfaceCommands>::iterator itty=scommands.begin();
290         while (itty!=scommands.end()) {
291                 if ((*itty).surf==surf) {
292                         dereferenceSVGCommand((*itty).commands);
293                         (*itty).commands.clear();
294                         scommands.erase(itty);
295                         break;
296                 }
297                 itty++;
298         }
299         surfaces_mutex.Unlock();
300
301 }
302
303 void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )
304 {
305
306         list<SVGCommand>::iterator sitty = commands.begin();
307         while (sitty != commands.end()) {
308                 removeStyleRef((*sitty).getRef());
309                 ImageIndex ii = (*sitty).getImageIndex();
310                 if (ii) removeImageRef(ii);
311                 LoadIndex li=(*sitty).getLoadIndex();
312                 if (li) removeLoadIndexRef(li);
313                 sitty++;
314         }
315 }
316
317 void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )
318 {
319         list<SVGCommand>::iterator sitty=commands.begin();
320         while (sitty!=commands.end())
321         {
322                 incStyleRef((*sitty).getRef());
323                 ImageIndex ii=(*sitty).getImageIndex();
324                 if (ii) incImageRef(ii);
325                 LoadIndex li=(*sitty).getLoadIndex();
326                 if (li) incLoadIndexRef(li);
327                 sitty++;
328         }
329 }
330
331
332 void OsdVector::incImageRef(ImageIndex index)
333 {
334         if (images_ref.find(index)==images_ref.end()) {
335                 images_ref[index]=1;
336         } else {
337                 images_ref[index]++;
338         }
339 }
340
341 void OsdVector::removeImageRef(const ImageIndex ref)
342 {
343         images_ref[ref]--;
344 }
345
346 int OsdVector::getLoadIndexRef(LoadIndex index)
347 {
348         if (loadindex_ref.find(index)==loadindex_ref.end()) {
349                 return -1;
350         } else {
351                 return loadindex_ref[index];
352         }
353 }
354
355 void OsdVector::incLoadIndexRef(LoadIndex index)
356 {
357         if (loadindex_ref.find(index)==loadindex_ref.end()) {
358                 loadindex_ref[index]=1;
359         } else {
360                 loadindex_ref[index]++;
361         }
362 }
363
364 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
365 {
366         loadindex_ref[ref]--;
367         if (loadindex_ref[ref]==0) {
368                 //now check, if it is already loaded
369                 map<LoadIndex,ImageIndex>::iterator itty=tvmedias_loaded.find(ref);
370                 if ( itty != tvmedias_loaded.end()) {
371                         removeImageRef((*itty).second); // remove lock
372                 }
373                 tvmedias_loaded.erase(ref);
374                 tvmedias_load.erase(tvmedias_load_inv[ref]);
375                 tvmedias_load_inv.erase(ref);
376
377                 reader.invalidateLoadIndex(ref);
378
379
380         }
381 }
382
383
384
385 void OsdVector::cleanupOrphanedRefs()
386 { // Do some garbage collection
387
388         map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
389         while (mitty!=monobitmaps.end()) {
390                 map<ImageIndex,int>::iterator curitty=images_ref.find((*mitty).second);
391                 int count=(*curitty).second;
392                 if (count==0) {
393                         ImageIndex ref=(*curitty).first;
394                         monobitmaps.erase(mitty++);
395                         images_ref.erase(curitty++);
396                         destroyImageRef(ref);
397                 } else ++mitty;
398         }
399
400         map<string,ImageIndex>::iterator jitty=jpegs.begin();
401         while (jitty!=jpegs.end()) {
402                 map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
403                 int count=(*curitty).second;
404                 if (count==0) {
405                         ImageIndex ref=(*curitty).first;
406                         jpegs.erase(jitty++);
407                         images_ref.erase(curitty++);
408                         destroyImageRef(ref);
409                 } else ++jitty;
410         }
411
412         map<TVMediaInfo,ImageIndex>::iterator titty=tvmedias.begin();
413         while (titty!=tvmedias.end()) {
414                 map<ImageIndex,int>::iterator curitty=images_ref.find((*titty).second);
415                 int count=(*curitty).second;
416                 if (count==0) {
417                         ImageIndex ref=(*curitty).first;
418                         tvmedias.erase(titty++);
419                         images_ref.erase(curitty++);
420                         destroyImageRef(ref);
421                 } else ++titty;
422         }
423
424
425         map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
426         while (sitty!=styles.end()) {
427                 map<unsigned int,int>::iterator curitty=styles_ref.find((*sitty).second);
428                 int count=(*curitty).second;
429                 if (count==0) {
430                         unsigned int ref=(*curitty).first;
431                         styles.erase(sitty++);
432                         styles_ref.erase(curitty++);
433                         destroyStyleRef(ref);
434
435                 } else ++sitty;
436
437         }
438 }
439
440
441 int OsdVector::getImageRef(ImageIndex index)
442 {
443         if (images_ref.find(index)==images_ref.end()) {
444                 return -1;
445         } else {
446                 return images_ref[index];
447         }
448 }
449
450 void OsdVector::incStyleRef(unsigned int index)
451 {
452         if (styles_ref.find(index)==styles_ref.end()) {
453                 styles_ref[index]=1;
454         } else {
455                 styles_ref[index]++;
456         }
457 }
458
459 void OsdVector::removeStyleRef(unsigned int index)
460 {
461         styles_ref[index]--;
462 }
463
464 unsigned int OsdVector::getStyleRef(const DrawStyle &c)
465 {
466         unsigned int style_handle=0;
467         if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
468         {
469                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
470         } else {
471                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
472                 //Now check if the handle is valid
473                 if (styles_ref.find(style_handle)==styles_ref.end()) {
474                         //invalid handle recreate
475                         style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
476                 }
477         }
478         incStyleRef(style_handle);
479         return style_handle;
480 }
481
482 unsigned int OsdVector::getColorRef(const Colour &c)
483 {
484         unsigned int style_handle=0;
485         if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
486         {
487                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
488         } else {
489                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
490                 if (styles_ref.find(style_handle)==styles_ref.end()) {
491                         //invalid handle recreate
492                         style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
493                 }
494         }
495         incStyleRef(style_handle);
496         return style_handle;
497 }
498
499 int OsdVector::getStyleRef(unsigned int index)
500 {
501         if (styles_ref.find(index)==styles_ref.end()) {
502                 return -1;
503         } else {
504                 return styles_ref[index];
505         }
506 }
507
508 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
509 {
510         ImageIndex image_handle=0;
511         LoadIndex loadindex=0;
512         if (tvmedias.find(tvmedia)==tvmedias.end())
513         {
514                 loadindex=loadTVMedia(tvmedia);
515         } else {
516                 image_handle=tvmedias[tvmedia];
517                 if (images_ref.find(image_handle)==images_ref.end()) {
518                         //invalid handle recreate
519                         loadindex=loadTVMedia(tvmedia);
520                         image_handle=0;
521                 } else {
522                         incImageRef(image_handle);
523                 }
524         }
525         /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
526         incImageRef(image_handle);*/
527         image=image_handle;
528         return loadindex;
529 }
530
531 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
532 {
533         LoadIndex index=0;
534         if (tvmedias_load.find(tvmedia)==tvmedias_load.end())
535         {
536                 switch (tvmedia.getType()) {
537                 case 3:
538                         index=VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
539                         break;
540                 default:
541                         index=VDR::getInstance()->loadTVMedia(tvmedia);
542                         break;
543                 }
544
545                 tvmedias_load[tvmedia]=index;
546                 tvmedias_load_inv[index]=tvmedia;
547         } else {
548                 index=tvmedias_load[tvmedia];
549         }
550
551         incLoadIndexRef(index);
552
553         return index;
554 }
555
556
557
558 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
559 {
560         //Beware for thread safety
561         ImageIndex image_index=0;
562
563         TVMediaInfo tvmedia=tvmedias_load_inv[index];
564           Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %d arrived",index);
565         if (imageIndex) {
566                 image_index=tvmedias[tvmedia]=imageIndex;
567                 tvmedias_loaded[index]=image_index;
568                 if (getLoadIndexRef(index) < 1) {
569                         // we do not want the picture anymore . Really...
570                         // fill images_ref in to not irritate the garbage collector
571                         if (getImageRef(image_index) < 0) {
572                                 images_ref[image_index]=0;
573                         }
574                 } else {
575
576                         incImageRef(image_index); // hold one index until all loadings refs are gone;
577                 }
578         }
579
580
581 }
582
583
584
585
586
587 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
588 {
589         ImageIndex image_handle=0;
590         if (jpegs.find(fileName)==jpegs.end())
591         {
592                 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
593         } else {
594                 image_handle=jpegs[fileName];
595                 *width=0;
596                 *height=0;
597                 if (images_ref.find(image_handle)==images_ref.end()) {
598                         //invalid handle recreate
599                         image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
600                 }
601         }
602         incImageRef(image_handle);
603         return image_handle;
604 }
605
606 ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
607 {
608         ImageIndex image_handle;
609         if (monobitmaps.find(base)==monobitmaps.end())
610         {
611                 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
612         } else {
613                 image_handle=monobitmaps[base];
614                 if (images_ref.find(image_handle)==images_ref.end()) {
615                         //invalid handle recreate
616                         image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
617                 }
618         }
619         incImageRef(image_handle);
620         return image_handle;
621 }
622
623 ImageIndex  OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
624 {
625         ImageIndex image_handle;
626         image_handle=createImagePalette(width,height,image_data,palette_data);
627         incImageRef(image_handle);
628         return image_handle;
629 }
630
631 OsdVector::PictureReader::~PictureReader()
632 {
633         decoders_lock.Lock();
634         while ( decoders.size()) {
635                 PictureDecoder* dec=decoders.front();
636                 decoders.pop_front();
637                 delete dec;
638         }
639
640         decoders_lock.Unlock();
641 }
642
643 void OsdVector::PictureReader::init()
644 {
645         threadStart();
646 }
647
648 void OsdVector::PictureReader::shutdown()
649 {
650         threadStop();
651
652
653 }
654
655 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
656 {
657         decoders_lock.Lock();
658         decoder->init();
659         decoders.push_front(decoder);
660         decoders_lock.Unlock();
661 }
662
663 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
664 {
665         decoders_lock.Lock();
666         std::list<PictureDecoder*>::iterator itty=decoders.begin();
667         while (itty!=decoders.end()) {
668                 if ((*itty) == decoder)
669                 {
670                         decoders.erase(itty);
671                         break;
672                 }
673                 itty++;
674         }
675         Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
676         decoder->shutdown();
677         delete decoder;
678         decoders_lock.Unlock();
679 }
680
681 void OsdVector::PictureReader::threadMethod()
682 {
683         OsdVector *osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
684         Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
685         while (true) {
686                 if (!threadIsActive()) {
687                         Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
688                         threadCheckExit();
689                 }
690
691                 bool todos=true;
692                 while (todos)
693                 {
694                         todos=false;
695                         PictureInfo pictinf;
696                         decoders_lock.Lock();
697                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
698
699                         while (itty!=decoders.end()) {
700                                 if ((*itty)->getDecodedPicture(pictinf)) {
701                                         todos = true;
702                                         osdvector->createPicture(pictinf);
703                                 }
704
705                                 itty++;
706                         }
707                         if (processReceivedPictures())
708                         {
709                                 todos = true;
710                         }
711
712                         decoders_lock.Unlock();
713                 }
714                 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
715
716                 threadLock();
717                 threadWaitForSignal();
718                 threadUnlock();
719                 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
720         }
721 }
722
723 void OsdVector::PictureReader::threadPostStopCleanup()
724 {
725
726 }
727
728 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
729 {
730         pict_lock_incoming.Lock();
731         invalid_loadindex.insert(index);
732         pict_lock_incoming.Unlock();
733 }
734
735 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket *vresp)
736 {
737         pict_lock_incoming.Lock();
738         pict_incoming.push(vresp);
739         pict_lock_incoming.Unlock();
740         threadSignal();
741 }
742
743 bool OsdVector::PictureReader::processReceivedPictures()
744 {
745         bool decoded = false;
746         bool valid = true;
747         pict_lock_incoming.Lock();
748     if (pict_incoming.size()) {
749                 VDR_ResponsePacket *vresp=pict_incoming.front();
750                 pict_incoming.pop();
751                 set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
752                 if (setpos != invalid_loadindex.end()) {
753                         valid = false;
754                         invalid_loadindex.erase(setpos);
755                 }
756                 pict_lock_incoming.Unlock();
757                 if (!valid) { // we do not want it anymore skip it;
758                         delete vresp;
759                         return true;
760                 }
761                 if (vresp->getFlag() != 2) {
762                         UCHAR *userdata=vresp->getUserData();
763                         ULONG length=vresp->getUserDataLength();
764                         std::list<PictureDecoder*>::iterator itty=decoders.begin();
765                         while (itty!=decoders.end()) {
766                                 if ((*itty)->decodePicture(vresp->getStreamID(),
767                                         userdata, length)){
768                                         decoded=true;
769                                         break;
770                                 }
771                                 itty++;
772                         }
773                         if (!decoded ){
774                                 free(vresp->getUserData());
775                         }
776                 }
777                 //else  osd->informPicture(vresp->getStreamID(), 0);
778                 delete vresp;
779         } else {
780                 pict_lock_incoming.Unlock();
781         }
782
783
784         return decoded;
785 }