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)
128 Surface * OsdVector::createNewSurface()
130 return new SurfaceVector(this);
133 void OsdVector::BeginPainting()
135 surfaces_mutex.Lock();
137 void OsdVector::EndPainting()
139 surfaces_mutex.Unlock();
142 void OsdVector::Blank()
144 // do nothing? remove this one?
147 int OsdVector::restore()
149 // First clear the contents of all registered surfaces
150 surfaces_mutex.Lock();
152 //Now go through all surfaces and draw them
153 list<SurfaceCommands>::iterator curdraw=scommands.begin();
154 while (curdraw!=scommands.end()) {
155 (*curdraw).commands.clear();
158 //also clear all handles, they are now invalid, no need to release them
167 loadindex_ref.clear();
168 tvmedias_load.clear();
169 tvmedias_load_inv.clear();
170 tvmedias_loaded.clear();
172 surfaces_mutex.Unlock();
176 void OsdVector::drawSurfaces()
178 surfaces_mutex.Lock();
179 list<SurfaceCommands*> todraw; //First figure out if a surfaces is below another surface
180 list<SurfaceCommands>::iterator itty1=scommands.begin();
181 while (itty1!=scommands.end()) {
182 list<SurfaceCommands>::iterator itty2=itty1;
185 while (itty2!=scommands.end()) {
186 SurfaceCommands & ref1=*itty1;
187 SurfaceCommands & ref2=*itty2;
188 if (ref1.x>=ref2.x && ref1.y>=ref2.y
189 && (ref1.x+ref1.w) <= (ref2.x+ref2.w)
190 && (ref1.y+ref1.h) <= (ref2.y+ref2.h) ) {
196 if (!hidden) { // we are not hidden, perfect
197 todraw.push_back(&(*itty1));
202 getScreenSize(swidth,sheight);
203 //Now go through all surfaces and draw them
204 list<SurfaceCommands*>::iterator curdraw=todraw.begin();
205 while (curdraw!=todraw.end()) {
206 drawSetTrans(*(*curdraw));
207 list<SVGCommand>::iterator commands=(*(*curdraw)).commands.begin();
208 list<SVGCommand>::iterator end=(*(*curdraw)).commands.end();
209 while (commands!=end) {
210 // update any images loaded in the mean time
211 if ((*commands).instr==DrawImageLoading) {
212 LoadIndex loadindex=(*commands).target.loadindex;
213 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
214 (*commands).instr=DrawImage;
215 (*commands).target.image=tvmedias_loaded[loadindex];;
216 incImageRef((*commands).target.image);
217 removeLoadIndexRef(loadindex);
221 // Now check if the command is on screen!
222 if (!(*commands).Outside(0,0,swidth,sheight)) {
223 executeDrawCommand(*commands);
230 surfaces_mutex.Unlock();
233 void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
234 list<SVGCommand>& commands)
236 surfaces_mutex.Lock();
237 //First determine it is already in our system
238 list<SurfaceCommands>::iterator itty=scommands.begin();
239 while (itty!=scommands.end()) {
240 if ((*itty).surf==surf) {
241 //decrease the references
242 dereferenceSVGCommand((*itty).commands);
248 if (itty==scommands.end()) {
249 SurfaceCommands new_sc;
255 itty=scommands.insert(itty,new_sc);
257 // update any images loaded in the mean time
258 list<SVGCommand>::iterator ilitty=commands.begin();
260 while (ilitty!=commands.end())
262 if ((*ilitty).instr==DrawImageLoading) {
263 LoadIndex loadindex=(*ilitty).target.loadindex;
264 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
266 (*ilitty).instr=DrawImage;
267 (*ilitty).target.image=tvmedias_loaded[loadindex];
268 incImageRef((*ilitty).target.image);
269 removeLoadIndexRef(loadindex);
276 // then clear and copy
277 (*itty).commands.clear();
278 (*itty).commands=commands;
279 //increase the references
280 referenceSVGCommand((*itty).commands);
281 cleanupOrphanedRefs();
283 surfaces_mutex.Unlock();
286 void OsdVector::removeSurface(const SurfaceVector *surf)
288 surfaces_mutex.Lock();
289 //First determine it is already in our system
290 list<SurfaceCommands>::iterator itty=scommands.begin();
291 while (itty!=scommands.end()) {
292 if ((*itty).surf==surf) {
293 dereferenceSVGCommand((*itty).commands);
294 (*itty).commands.clear();
295 scommands.erase(itty);
300 surfaces_mutex.Unlock();
304 void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )
307 list<SVGCommand>::iterator sitty = commands.begin();
308 while (sitty != commands.end()) {
309 removeStyleRef((*sitty).getRef());
310 ImageIndex ii = (*sitty).getImageIndex();
311 if (ii) removeImageRef(ii);
312 LoadIndex li=(*sitty).getLoadIndex();
313 if (li) removeLoadIndexRef(li);
318 void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )
320 list<SVGCommand>::iterator sitty=commands.begin();
321 while (sitty!=commands.end())
323 incStyleRef((*sitty).getRef());
324 ImageIndex ii=(*sitty).getImageIndex();
325 if (ii) incImageRef(ii);
326 LoadIndex li=(*sitty).getLoadIndex();
327 if (li) incLoadIndexRef(li);
333 void OsdVector::incImageRef(ImageIndex index)
335 if (images_ref.find(index)==images_ref.end()) {
342 void OsdVector::removeImageRef(const ImageIndex ref)
347 int OsdVector::getLoadIndexRef(LoadIndex index)
349 if (loadindex_ref.find(index)==loadindex_ref.end()) {
352 return loadindex_ref[index];
356 void OsdVector::incLoadIndexRef(LoadIndex index)
358 if (loadindex_ref.find(index)==loadindex_ref.end()) {
359 loadindex_ref[index]=1;
361 loadindex_ref[index]++;
365 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
367 loadindex_ref[ref]--;
368 if (loadindex_ref[ref]==0) {
369 //now check, if it is already loaded
370 map<LoadIndex,ImageIndex>::iterator itty=tvmedias_loaded.find(ref);
371 if ( itty != tvmedias_loaded.end()) {
372 removeImageRef((*itty).second); // remove lock
374 tvmedias_loaded.erase(ref);
375 tvmedias_load.erase(tvmedias_load_inv[ref]);
376 tvmedias_load_inv.erase(ref);
378 reader.invalidateLoadIndex(ref);
386 void OsdVector::cleanupOrphanedRefs()
387 { // Do some garbage collection
389 map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
390 while (mitty!=monobitmaps.end()) {
391 map<ImageIndex,int>::iterator curitty=images_ref.find((*mitty).second);
392 int count=(*curitty).second;
394 ImageIndex ref=(*curitty).first;
395 monobitmaps.erase(mitty++);
396 images_ref.erase(curitty++);
397 destroyImageRef(ref);
401 /*map<string,ImageIndex>::iterator jitty=jpegs.begin();
402 while (jitty!=jpegs.end()) {
403 map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
404 int count=(*curitty).second;
406 ImageIndex ref=(*curitty).first;
407 jpegs.erase(jitty++);
408 images_ref.erase(curitty++);
409 destroyImageRef(ref);
413 map<TVMediaInfo,ImageIndex>::iterator titty=tvmedias.begin();
414 while (titty!=tvmedias.end()) {
415 map<ImageIndex,int>::iterator curitty=images_ref.find((*titty).second);
416 int count=(*curitty).second;
418 ImageIndex ref=(*curitty).first;
419 tvmedias.erase(titty++);
420 images_ref.erase(curitty);
421 destroyImageRef(ref);
426 map<TVMediaInfo,LoadIndex>::iterator litty=tvmedias_load.begin();
427 while (litty!=tvmedias_load.end()) {
428 map<LoadIndex,int>::iterator curitty=loadindex_ref.find((*litty).second);
429 int count=(*curitty).second;
431 tvmedias_load_inv.erase((*litty).second);
432 tvmedias_loaded.erase((*litty).second);
433 tvmedias_load.erase(litty++);
437 list<ImageIndex>::iterator pitty=palettepics.begin();
438 while (pitty!=palettepics.end()) {
439 map<ImageIndex,int>::iterator curitty=images_ref.find((*pitty));
440 int count=(*curitty).second;
442 ImageIndex ref=(*curitty).first;
443 palettepics.erase(pitty++);
444 images_ref.erase(curitty++);
445 destroyImageRef(ref);
450 map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
451 while (sitty!=styles.end()) {
452 map<unsigned int,int>::iterator curitty=styles_ref.find((*sitty).second);
453 int count=(*curitty).second;
455 unsigned int ref=(*curitty).first;
456 styles.erase(sitty++);
457 styles_ref.erase(curitty++);
458 destroyStyleRef(ref);
466 int OsdVector::getImageRef(ImageIndex index)
468 if (images_ref.find(index)==images_ref.end()) {
471 return images_ref[index];
475 void OsdVector::incStyleRef(unsigned int index)
477 if (styles_ref.find(index)==styles_ref.end()) {
484 void OsdVector::removeStyleRef(unsigned int index)
489 unsigned int OsdVector::getStyleRef(const DrawStyle &c)
491 unsigned int style_handle=0;
492 if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
494 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
496 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
497 //Now check if the handle is valid
498 if (styles_ref.find(style_handle)==styles_ref.end()) {
499 //invalid handle recreate
500 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
503 incStyleRef(style_handle);
507 unsigned int OsdVector::getColorRef(const Colour &c)
509 unsigned int style_handle=0;
510 if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
512 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
514 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
515 if (styles_ref.find(style_handle)==styles_ref.end()) {
516 //invalid handle recreate
517 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
520 incStyleRef(style_handle);
524 int OsdVector::getStyleRef(unsigned int index)
526 if (styles_ref.find(index)==styles_ref.end()) {
529 return styles_ref[index];
533 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
535 ImageIndex image_handle=0;
536 LoadIndex loadindex=0;
537 if (tvmedias.find(tvmedia)==tvmedias.end())
539 loadindex=loadTVMedia(tvmedia);
541 image_handle=tvmedias[tvmedia];
542 if (images_ref.find(image_handle)==images_ref.end()) {
543 //invalid handle recreate
544 loadindex=loadTVMedia(tvmedia);
547 incImageRef(image_handle);
550 /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
551 incImageRef(image_handle);*/
556 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
559 if (tvmedias_load.find(tvmedia)==tvmedias_load.end())
561 switch (tvmedia.getType()) {
563 index=VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
566 index = ((long long) tvmedia.getPrimaryID()) << 32LL;
567 reader.addStaticImage(tvmedia.getPrimaryID());
570 index=VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
573 index=VDR::getInstance()->loadChannelLogo(tvmedia);
576 index=VDR::getInstance()->loadTVMedia(tvmedia);
580 tvmedias_load[tvmedia]=index;
581 tvmedias_load_inv[index]=tvmedia;
584 index=tvmedias_load[tvmedia];
587 incLoadIndexRef(index);
594 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
596 //Beware for thread safety
597 ImageIndex image_index=0;
599 TVMediaInfo tvmedia=tvmedias_load_inv[index];
600 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %llx arrived %d",index, imageIndex);
602 image_index=tvmedias[tvmedia]=imageIndex;
603 tvmedias_loaded[index]=image_index;
604 if (getLoadIndexRef(index) < 1) {
605 // we do not want the picture anymore . Really...
606 // fill images_ref in to not irritate the garbage collector
607 if (getImageRef(image_index) < 0) {
608 images_ref[image_index]=0;
612 incImageRef(image_index); // hold one index until all loadings refs are gone;
623 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
625 ImageIndex image_handle=0;
626 if (jpegs.find(fileName)==jpegs.end())
628 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
630 image_handle=jpegs[fileName];
633 if (images_ref.find(image_handle)==images_ref.end()) {
634 //invalid handle recreate
635 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
638 incImageRef(image_handle);
643 ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
645 ImageIndex image_handle;
646 if (monobitmaps.find(base)==monobitmaps.end())
648 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
650 image_handle=monobitmaps[base];
651 if (images_ref.find(image_handle)==images_ref.end()) {
652 //invalid handle recreate
653 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
656 incImageRef(image_handle);
660 ImageIndex OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
662 ImageIndex image_handle;
663 image_handle=createImagePalette(width,height,image_data,palette_data);
664 palettepics.push_back(image_handle);
665 incImageRef(image_handle);
669 OsdVector::PictureReader::~PictureReader()
671 decoders_lock.Lock();
672 while ( decoders.size()) {
673 PictureDecoder* dec=decoders.front();
674 decoders.pop_front();
678 decoders_lock.Unlock();
681 void OsdVector::PictureReader::init()
686 void OsdVector::PictureReader::shutdown()
693 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
695 decoders_lock.Lock();
697 decoders.push_front(decoder);
698 decoders_lock.Unlock();
701 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
703 decoders_lock.Lock();
704 std::list<PictureDecoder*>::iterator itty=decoders.begin();
705 while (itty!=decoders.end()) {
706 if ((*itty) == decoder)
708 decoders.erase(itty);
713 Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
716 decoders_lock.Unlock();
719 void OsdVector::PictureReader::threadMethod()
721 OsdVector *osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
722 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
724 if (!threadIsActive()) {
725 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
734 decoders_lock.Lock();
735 std::list<PictureDecoder*>::iterator itty=decoders.begin();
737 while (itty!=decoders.end()) {
738 if ((*itty)->getDecodedPicture(pictinf)) {
740 osdvector->createPicture(pictinf);
745 if (processReceivedPictures())
750 decoders_lock.Unlock();
752 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
754 struct timespec target_time;
755 clock_gettime(CLOCK_REALTIME,&target_time);
756 target_time.tv_nsec+=1000000LL*10;
757 if (target_time.tv_nsec>999999999) {
758 target_time.tv_nsec-=1000000000L;
759 target_time.tv_sec+=1;
762 threadWaitForSignalTimed(&target_time);
764 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
768 void OsdVector::PictureReader::threadPostStopCleanup()
773 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
775 pict_lock_incoming.Lock();
776 invalid_loadindex.insert(index);
777 pict_lock_incoming.Unlock();
780 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket *vresp)
782 pict_lock_incoming.Lock();
783 pict_incoming.push(vresp);
784 pict_lock_incoming.Unlock();
789 void OsdVector::PictureReader::addStaticImage(unsigned int id)
791 pict_lock_incoming.Lock();
792 pict_incoming_static.push(id);
793 invalid_loadindex.erase(((long long) id) << 32LL);
794 pict_lock_incoming.Unlock();
798 bool OsdVector::PictureReader::processReceivedPictures()
800 bool decoded = false;
802 pict_lock_incoming.Lock();
803 if (pict_incoming.size()) {
804 VDR_ResponsePacket *vresp=pict_incoming.front();
806 set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
807 if (setpos != invalid_loadindex.end()) {
809 invalid_loadindex.erase(setpos);
811 pict_lock_incoming.Unlock();
812 if (!valid) { // we do not want it anymore skip it;
816 // Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived VDR %x %d %d",
817 // vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
818 if (vresp->getFlag() != 2) {
819 UCHAR *userdata=vresp->getUserData();
820 ULONG length=vresp->getUserDataLength();
821 std::list<PictureDecoder*>::iterator itty=decoders.begin();
822 while (itty!=decoders.end()) {
823 userdata=(*itty)->decodePicture(vresp->getStreamID(), userdata, length);
830 if (!decoded && userdata ){
834 //else osd->informPicture(vresp->getStreamID(), 0);
836 } else if (pict_incoming_static.size()){
837 unsigned int static_id = pict_incoming_static.front();
838 pict_incoming_static.pop();
839 set<LoadIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
840 if (setpos != invalid_loadindex.end()) {
842 invalid_loadindex.erase(setpos);
844 pict_lock_incoming.Unlock();
845 if (!valid) { // we do not want it anymore skip it;
851 if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
853 std::list<PictureDecoder*>::iterator itty=decoders.begin();
854 while (itty!=decoders.end()) {
855 if (!(*itty)->decodePicture(((long long) static_id) << 32LL,userdata, length, false)){
863 pict_lock_incoming.Unlock();
867 if (pict_incoming.size() || pict_incoming_static.size()) return true;