2 Copyright 2012 Marten Richter
4 This file is part of VOMP.
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.
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.
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.
21 #include "osdvector.h"
22 #include "surfacevector.h"
24 #include "vdrresponsepacket.h"
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
32 using namespace Magick;
34 class MagickDecoder: public OsdVector::PictureDecoder {
36 MagickDecoder(OsdVector::PictureReader* treader): OsdVector::PictureDecoder(treader) {pictInfValid=false;};
38 unsigned char *decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem);
40 bool getDecodedPicture( struct OsdVector::PictureInfo& pict_inf);
42 void freeReference(void * ref);
45 OsdVector::PictureInfo pictInf;
49 unsigned char * MagickDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem)
51 if (pictInfValid) return buffer; // does support only one image at a Time;
53 Blob *imageblob = new Blob();
56 Log::getInstance()->log("MagickDecoder", Log::DEBUG, "decodePicture");
58 if (freemem) myblob.updateNoCopy(buffer,length,Blob::MallocAllocator);
59 else myblob.update(buffer,length);
60 magicimage.read(myblob);
62 magicimage.write(imageblob,"RGBA");
64 }catch( Exception &error_ )
66 Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: %s",error_.what());
68 Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: error mark2");
69 unsigned char* newbuffer=(unsigned char*) malloc(length);
70 memcpy(newbuffer,myblob.data(),length);
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;
84 // I can handle everything, so the return value is always true
87 void MagickDecoder::freeReference(void * ref)
89 Blob *todelete = (Blob*) ref;
93 bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
95 if (!pictInfValid) return false;
104 OsdVector::OsdVector()
106 setlocale(LC_CTYPE,"C.UTF-8");
107 #ifdef PICTURE_DECODER_MAGICK
108 reader.addDecoder(new MagickDecoder(&reader));
113 OsdVector::~OsdVector()
118 int OsdVector::getFD()
123 void OsdVector::screenShot(const char* fileName)
125 //Do nothing, if no libmagick is there
126 #ifdef PICTURE_DECODER_MAGICK
128 getRealScreenSize(width,height);
129 size_t length=width*height*4;
130 void *mem=malloc(length);
134 if (!screenShot(mem,width,height,true)) {
135 Log::getInstance()->log("OsdVector", Log::DEBUG, "Screenshot failed!");
139 myblob.updateNoCopy(mem,length,Blob::MallocAllocator);
140 Image image(myblob,Geometry(width,height),8,"RGBA");
141 image.write(fileName);
142 }catch( Exception &error_ )
144 Log::getInstance()->log("MagickEncoder", Log::DEBUG, "Libmagick: %s",error_.what());
151 Surface * OsdVector::createNewSurface()
153 return new SurfaceVector(this);
157 void OsdVector::Blank()
159 // do nothing? remove this one?
162 int OsdVector::restore()
164 // First clear the contents of all registered surfaces
165 surfaces_mutex.Lock();
167 //Now go through all surfaces and draw them
168 list<SurfaceCommands>::iterator curdraw=scommands.begin();
169 while (curdraw!=scommands.end()) {
170 (*curdraw).commands.clear();
173 //also clear all handles, they are now invalid, no need to release them
182 loadindex_ref.clear();
183 tvmedias_load.clear();
184 tvmedias_load_inv.clear();
185 tvmedias_loaded.clear();
187 surfaces_mutex.Unlock();
191 void OsdVector::drawSurfaces()
193 surfaces_mutex.Lock();
194 list<SurfaceCommands*> todraw; //First figure out if a surfaces is below another surface
195 list<SurfaceCommands>::iterator itty1=scommands.begin();
196 while (itty1!=scommands.end()) {
197 list<SurfaceCommands>::iterator itty2=itty1;
200 while (itty2!=scommands.end()) {
201 SurfaceCommands & ref1=*itty1;
202 SurfaceCommands & ref2=*itty2;
203 if (ref1.x>=ref2.x && ref1.y>=ref2.y
204 && (ref1.x+ref1.w) <= (ref2.x+ref2.w)
205 && (ref1.y+ref1.h) <= (ref2.y+ref2.h) ) {
211 if (!hidden) { // we are not hidden, perfect
212 todraw.push_back(&(*itty1));
217 getScreenSize(swidth,sheight);
218 //Now go through all surfaces and draw them
219 list<SurfaceCommands*>::iterator curdraw=todraw.begin();
220 while (curdraw!=todraw.end()) {
221 drawSetTrans(*(*curdraw));
222 list<SVGCommand>::iterator commands=(*(*curdraw)).commands.begin();
223 list<SVGCommand>::iterator end=(*(*curdraw)).commands.end();
224 while (commands!=end) {
225 // update any images loaded in the mean time
226 if ((*commands).instr==DrawImageLoading) {
227 LoadIndex loadindex=(*commands).target.loadindex;
228 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
229 (*commands).instr=DrawImage;
230 (*commands).target.image=tvmedias_loaded[loadindex];;
231 incImageRef((*commands).target.image);
232 removeLoadIndexRef(loadindex);
236 // Now check if the command is on screen!
237 if (!(*commands).Outside(0,0,swidth,sheight)) {
238 executeDrawCommand(*commands);
245 surfaces_mutex.Unlock();
248 void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
249 list<SVGCommand>& commands)
251 surfaces_mutex.Lock();
252 //First determine it is already in our system
253 list<SurfaceCommands>::iterator itty=scommands.begin();
254 while (itty!=scommands.end()) {
255 if ((*itty).surf==surf) {
256 //decrease the references
257 dereferenceSVGCommand((*itty).commands);
263 if (itty==scommands.end()) {
264 SurfaceCommands new_sc;
270 itty=scommands.insert(itty,new_sc);
272 // update any images loaded in the mean time
273 list<SVGCommand>::iterator ilitty=commands.begin();
275 while (ilitty!=commands.end())
277 if ((*ilitty).instr==DrawImageLoading) {
278 LoadIndex loadindex=(*ilitty).target.loadindex;
279 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
281 (*ilitty).instr=DrawImage;
282 (*ilitty).target.image=tvmedias_loaded[loadindex];
283 incImageRef((*ilitty).target.image);
284 removeLoadIndexRef(loadindex);
291 // then clear and copy
292 (*itty).commands.clear();
293 (*itty).commands=commands;
294 //increase the references
295 referenceSVGCommand((*itty).commands);
296 cleanupOrphanedRefs();
298 surfaces_mutex.Unlock();
301 void OsdVector::removeSurface(const SurfaceVector *surf)
303 surfaces_mutex.Lock();
304 //First determine it is already in our system
305 list<SurfaceCommands>::iterator itty=scommands.begin();
306 while (itty!=scommands.end()) {
307 if ((*itty).surf==surf) {
308 dereferenceSVGCommand((*itty).commands);
309 (*itty).commands.clear();
310 scommands.erase(itty);
315 surfaces_mutex.Unlock();
319 void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )
322 list<SVGCommand>::iterator sitty = commands.begin();
323 while (sitty != commands.end()) {
324 removeStyleRef((*sitty).getRef());
325 ImageIndex ii = (*sitty).getImageIndex();
326 if (ii) removeImageRef(ii);
327 LoadIndex li=(*sitty).getLoadIndex();
328 if (li) removeLoadIndexRef(li);
333 void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )
335 list<SVGCommand>::iterator sitty=commands.begin();
336 while (sitty!=commands.end())
338 incStyleRef((*sitty).getRef());
339 ImageIndex ii=(*sitty).getImageIndex();
340 if (ii) incImageRef(ii);
341 LoadIndex li=(*sitty).getLoadIndex();
342 if (li) incLoadIndexRef(li);
348 void OsdVector::incImageRef(ImageIndex index)
350 if (images_ref.find(index)==images_ref.end()) {
357 void OsdVector::removeImageRef(const ImageIndex ref)
362 int OsdVector::getLoadIndexRef(LoadIndex index)
364 surfaces_mutex.Lock();
365 if (loadindex_ref.find(index)==loadindex_ref.end()) {
368 return loadindex_ref[index];
370 surfaces_mutex.Unlock();
373 void OsdVector::incLoadIndexRef(LoadIndex index)
375 if (loadindex_ref.find(index)==loadindex_ref.end()) {
376 loadindex_ref[index]=1;
378 loadindex_ref[index]++;
382 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
384 loadindex_ref[ref]--;
385 if (loadindex_ref[ref]==0) {
386 //now check, if it is already loaded
387 map<LoadIndex,ImageIndex>::iterator itty=tvmedias_loaded.find(ref);
388 if ( itty != tvmedias_loaded.end()) {
389 removeImageRef((*itty).second); // remove lock
391 tvmedias_loaded.erase(ref);
392 // Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia removeLoadIndexRef %d %llx",tvmedias_load.size(),ref);
393 tvmedias_load.erase(tvmedias_load_inv[ref]);
394 tvmedias_load_inv.erase(ref);
396 reader.invalidateLoadIndex(ref);
404 void OsdVector::cleanupOrphanedRefs()
405 { // Do some garbage collection
407 map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
408 while (mitty!=monobitmaps.end()) {
409 map<ImageIndex,int>::iterator curitty=images_ref.find((*mitty).second);
410 int count=(*curitty).second;
412 ImageIndex ref=(*curitty).first;
413 monobitmaps.erase(mitty++);
414 images_ref.erase(curitty++);
415 destroyImageRef(ref);
419 /*map<string,ImageIndex>::iterator jitty=jpegs.begin();
420 while (jitty!=jpegs.end()) {
421 map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
422 int count=(*curitty).second;
424 ImageIndex ref=(*curitty).first;
425 jpegs.erase(jitty++);
426 images_ref.erase(curitty++);
427 destroyImageRef(ref);
431 map<TVMediaInfo,ImageIndex>::iterator titty=tvmedias.begin();
432 while (titty!=tvmedias.end()) {
433 map<ImageIndex,int>::iterator curitty=images_ref.find((*titty).second);
434 int count=(*curitty).second;
436 ImageIndex ref=(*curitty).first;
437 tvmedias.erase(titty++);
438 images_ref.erase(curitty);
439 destroyImageRef(ref);
444 map<TVMediaInfo,LoadIndex>::iterator litty=tvmedias_load.begin();
445 while (litty!=tvmedias_load.end()) {
446 map<LoadIndex,int>::iterator curitty=loadindex_ref.find((*litty).second);
447 int count=(*curitty).second;
449 tvmedias_load_inv.erase((*litty).second);
450 tvmedias_loaded.erase((*litty).second);
451 tvmedias_load.erase(litty++);
455 list<ImageIndex>::iterator pitty=palettepics.begin();
456 while (pitty!=palettepics.end()) {
457 map<ImageIndex,int>::iterator curitty=images_ref.find((*pitty));
458 int count=(*curitty).second;
460 ImageIndex ref=(*curitty).first;
461 palettepics.erase(pitty++);
462 images_ref.erase(curitty++);
463 destroyImageRef(ref);
467 map<ImageIndex,int>::iterator citty=images_ref.begin();
468 while (citty!=images_ref.end()) {
469 int count=(*citty).second;
471 ImageIndex ref=(*citty).first;
472 images_ref.erase(citty++);
473 destroyImageRef(ref);
478 map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
479 while (sitty!=styles.end()) {
480 map<unsigned int,int>::iterator curitty=styles_ref.find((*sitty).second);
481 int count=(*curitty).second;
483 unsigned int ref=(*curitty).first;
484 styles.erase(sitty++);
485 styles_ref.erase(curitty++);
486 destroyStyleRef(ref);
494 int OsdVector::getImageRef(ImageIndex index)
496 surfaces_mutex.Lock();
497 if (images_ref.find(index)==images_ref.end()) {
500 return images_ref[index];
502 surfaces_mutex.Unlock();
505 void OsdVector::incStyleRef(unsigned int index)
507 if (styles_ref.find(index)==styles_ref.end()) {
514 void OsdVector::removeStyleRef(unsigned int index)
519 unsigned int OsdVector::getStyleRef(const DrawStyle &c)
521 surfaces_mutex.Lock();
522 unsigned int style_handle=0;
523 if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
525 surfaces_mutex.Unlock();
526 style_handle=createStyleRef(c);
527 surfaces_mutex.Lock();
528 styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=style_handle;
530 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
531 //Now check if the handle is valid
532 if (styles_ref.find(style_handle)==styles_ref.end()) {
533 //invalid handle recreate
534 surfaces_mutex.Unlock();
535 style_handle=createStyleRef(c);
536 surfaces_mutex.Lock();
537 styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=style_handle;
540 incStyleRef(style_handle);
541 surfaces_mutex.Unlock();
545 unsigned int OsdVector::getColorRef(const Colour &c)
547 surfaces_mutex.Lock();
548 unsigned int style_handle=0;
549 if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
551 surfaces_mutex.Unlock();
552 style_handle=createColorRef(c);
553 surfaces_mutex.Lock();
554 styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=style_handle;
556 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
557 if (styles_ref.find(style_handle)==styles_ref.end()) {
558 //invalid handle recreate
559 surfaces_mutex.Unlock();
560 style_handle=createColorRef(c);
561 surfaces_mutex.Lock();
562 styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=style_handle;
565 incStyleRef(style_handle);
566 surfaces_mutex.Unlock();
570 int OsdVector::getStyleRef(unsigned int index)
572 if (styles_ref.find(index)==styles_ref.end()) {
575 return styles_ref[index];
579 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
581 ImageIndex image_handle=0;
582 LoadIndex loadindex=0;
583 surfaces_mutex.Lock();
584 if (tvmedias.find(tvmedia)==tvmedias.end())
586 loadindex=loadTVMedia(tvmedia);
588 image_handle=tvmedias[tvmedia];
589 if (images_ref.find(image_handle)==images_ref.end()) {
590 //invalid handle recreate
591 loadindex=loadTVMedia(tvmedia);
594 incImageRef(image_handle);
597 /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
598 incImageRef(image_handle);*/
600 surfaces_mutex.Unlock();
604 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
608 if (tvmedias_load.find(tvmedia)==tvmedias_load.end())
610 switch (tvmedia.getType()) {
612 index=VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
615 index = ((long long) tvmedia.getPrimaryID()) << 32LL;
616 reader.addStaticImage(tvmedia.getPrimaryID());
619 index=VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
622 index=VDR::getInstance()->loadChannelLogo(tvmedia);
625 index=VDR::getInstance()->loadTVMedia(tvmedia);
628 if (tvmedia.getType()!=4 && tvmedia.getStaticFallback()>-1) {
629 reader.informFallback(index,tvmedia.getStaticFallback());
632 tvmedias_load[tvmedia]=index;
633 tvmedias_load_inv[index]=tvmedia;
635 index=tvmedias_load[tvmedia];
638 incLoadIndexRef(index);
645 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
647 //Beware for thread safety
648 ImageIndex image_index=0;
650 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %llx arrived %x",index, imageIndex);
651 surfaces_mutex.Lock();
652 TVMediaInfo tvmedia=tvmedias_load_inv[index];
654 map<LoadIndex,int>::iterator itty=loadindex_ref.find(index);
655 image_index=tvmedias[tvmedia]=imageIndex;
656 tvmedias_loaded[index]=image_index;
658 if (itty==loadindex_ref.end() || (*itty).second == 0) {
659 // we do not want the picture anymore . Really...
660 // fill images_ref in to not irritate the garbage collector
661 if (images_ref.find(index)==images_ref.end()) {
662 images_ref[image_index]=0;
665 incImageRef(image_index); // hold one index until all loadings refs are gone;
668 surfaces_mutex.Unlock();
677 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
679 ImageIndex image_handle=0;
680 if (jpegs.find(fileName)==jpegs.end())
682 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
684 image_handle=jpegs[fileName];
687 if (images_ref.find(image_handle)==images_ref.end()) {
688 //invalid handle recreate
689 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
692 incImageRef(image_handle);
697 ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
699 ImageIndex image_handle;
700 surfaces_mutex.Lock();
701 if (monobitmaps.find(base)==monobitmaps.end())
703 surfaces_mutex.Unlock();
704 image_handle=createMonoBitmap(base,width,height);
705 surfaces_mutex.Lock();
706 monobitmaps[base]=image_handle;
708 image_handle=monobitmaps[base];
709 if (images_ref.find(image_handle)==images_ref.end()) {
710 //invalid handle recreate
711 surfaces_mutex.Unlock();
712 image_handle=createMonoBitmap(base,width,height);
713 surfaces_mutex.Lock();
714 monobitmaps[base]=image_handle;
717 incImageRef(image_handle);
718 surfaces_mutex.Unlock();
722 ImageIndex OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
724 ImageIndex image_handle;
725 image_handle=createImagePalette(width,height,image_data,palette_data);
726 surfaces_mutex.Lock();
727 palettepics.push_back(image_handle);
728 incImageRef(image_handle);
729 surfaces_mutex.Unlock();
733 OsdVector::PictureReader::~PictureReader()
735 decoders_lock.Lock();
736 while ( decoders.size()) {
737 PictureDecoder* dec=decoders.front();
738 decoders.pop_front();
742 decoders_lock.Unlock();
745 void OsdVector::PictureReader::init()
750 void OsdVector::PictureReader::shutdown()
757 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
759 decoders_lock.Lock();
761 decoders.push_front(decoder);
762 decoders_lock.Unlock();
765 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
767 decoders_lock.Lock();
768 std::list<PictureDecoder*>::iterator itty=decoders.begin();
769 while (itty!=decoders.end()) {
770 if ((*itty) == decoder)
772 decoders.erase(itty);
777 Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
780 decoders_lock.Unlock();
783 void OsdVector::PictureReader::threadMethod()
785 OsdVector *osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
786 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
788 if (!threadIsActive()) {
789 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
798 decoders_lock.Lock();
799 std::list<PictureDecoder*>::iterator itty=decoders.begin();
801 while (itty!=decoders.end()) {
802 if ((*itty)->getDecodedPicture(pictinf)) {
804 osdvector->createPicture(pictinf);
809 if (processReceivedPictures())
814 decoders_lock.Unlock();
816 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
818 struct timespec target_time;
819 clock_gettime(CLOCK_REALTIME,&target_time);
820 target_time.tv_nsec+=1000000LL*10;
821 if (target_time.tv_nsec>999999999) {
822 target_time.tv_nsec-=1000000000L;
823 target_time.tv_sec+=1;
826 threadWaitForSignalTimed(&target_time);
828 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
832 void OsdVector::PictureReader::threadPostStopCleanup()
837 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
839 pict_lock_incoming.Lock();
840 invalid_loadindex.insert(index);
841 pict_lock_incoming.Unlock();
844 void OsdVector::PictureReader::informFallback(LoadIndex index, int fallback)
846 pict_lock_incoming.Lock();
847 inform_fallback[index]=fallback;
848 pict_lock_incoming.Unlock();
851 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket *vresp)
853 pict_lock_incoming.Lock();
854 pict_incoming.push(vresp);
855 pict_lock_incoming.Unlock();
860 void OsdVector::PictureReader::addStaticImage(unsigned int id)
862 pict_lock_incoming.Lock();
863 pict_incoming_static.push(id);
864 invalid_loadindex.erase(((long long) id) << 32LL);
865 pict_lock_incoming.Unlock();
869 bool OsdVector::PictureReader::processReceivedPictures()
871 bool decoded = false;
873 pict_lock_incoming.Lock();
874 if (pict_incoming.size()) {
875 VDR_ResponsePacket *vresp=pict_incoming.front();
877 set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
878 if (setpos != invalid_loadindex.end()) {
880 invalid_loadindex.erase(setpos);
882 pict_lock_incoming.Unlock();
883 if (!valid) { // we do not want it anymore skip it;
887 // Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived VDR %x %d %d",
888 // vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
894 if (vresp->getFlag() != 2) {
895 userdata=vresp->getUserData();
896 length=vresp->getUserDataLength();
901 pict_lock_incoming.Lock();
902 if (inform_fallback.find(vresp->getStreamID())!=inform_fallback.end()) {
903 fallback=inform_fallback[vresp->getStreamID()];
905 pict_lock_incoming.Unlock();
906 if (fallback >= 0 && ((OsdVector*)Osd::getInstance())->getStaticImageData(fallback, &userdata, &length))
914 std::list<PictureDecoder*>::iterator itty=decoders.begin();
915 while (itty!=decoders.end()) {
916 userdata=(*itty)->decodePicture(vresp->getStreamID(), userdata, length, freed);
923 if (!decoded && userdata && freed){
927 pict_lock_incoming.Lock();
928 inform_fallback.erase(vresp->getStreamID());
929 pict_lock_incoming.Unlock();
930 //else osd->informPicture(vresp->getStreamID(), 0);
932 } else if (pict_incoming_static.size()){
933 unsigned int static_id = pict_incoming_static.front();
934 pict_incoming_static.pop();
935 set<LoadIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
936 if (setpos != invalid_loadindex.end()) {
938 invalid_loadindex.erase(setpos);
940 pict_lock_incoming.Unlock();
941 if (!valid) { // we do not want it anymore skip it;
947 if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
949 std::list<PictureDecoder*>::iterator itty=decoders.begin();
950 while (itty!=decoders.end()) {
951 if (!(*itty)->decodePicture(((long long) static_id) << 32LL,userdata, length, false)){
959 pict_lock_incoming.Unlock();
963 if (pict_incoming.size() || pict_incoming_static.size()) return true;