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 bool 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 bool MagickDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem)
51 if (pictInfValid) return false; // 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());
71 pictInf.reference = (void*) imageblob;
72 pictInf.width = magicimage.columns();
73 pictInf.height = magicimage.rows();
74 pictInf.image = imageblob->data();
75 pictInf.decoder = this;
76 pictInf.type = OsdVector::PictureInfo::RGBAMemBlock;
77 pictInf.lindex = index;
82 // I can handle everything, so the return value is always true
85 void MagickDecoder::freeReference(void * ref)
87 Blob *todelete = (Blob*) ref;
91 bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
93 if (!pictInfValid) return false;
102 OsdVector::OsdVector()
104 setlocale(LC_CTYPE,"C.UTF-8");
105 #ifdef PICTURE_DECODER_MAGICK
106 reader.addDecoder(new MagickDecoder(&reader));
111 OsdVector::~OsdVector()
116 int OsdVector::getFD()
121 void OsdVector::screenShot(const char* fileName)
126 Surface * OsdVector::createNewSurface()
128 return new SurfaceVector(this);
131 void OsdVector::BeginPainting()
133 surfaces_mutex.Lock();
135 void OsdVector::EndPainting()
137 surfaces_mutex.Unlock();
140 void OsdVector::Blank()
142 // do nothing? remove this one?
145 int OsdVector::restore()
147 // First clear the contents of all registered surfaces
148 surfaces_mutex.Lock();
150 //Now go through all surfaces and draw them
151 list<SurfaceCommands>::iterator curdraw=scommands.begin();
152 while (curdraw!=scommands.end()) {
153 (*curdraw).commands.clear();
156 //also clear all handles, they are now invalid, no need to release them
164 loadindex_ref.clear();
165 tvmedias_load.clear();
166 tvmedias_load_inv.clear();
167 tvmedias_loaded.clear();
169 surfaces_mutex.Unlock();
173 void OsdVector::drawSurfaces()
175 surfaces_mutex.Lock();
176 list<SurfaceCommands*> todraw; //First figure out if a surfaces is below another surface
177 list<SurfaceCommands>::iterator itty1=scommands.begin();
178 while (itty1!=scommands.end()) {
179 list<SurfaceCommands>::iterator itty2=itty1;
182 while (itty2!=scommands.end()) {
183 SurfaceCommands & ref1=*itty1;
184 SurfaceCommands & ref2=*itty2;
185 if (ref1.x>=ref2.x && ref1.y>=ref2.y
186 && (ref1.x+ref1.w) <= (ref2.x+ref2.w)
187 && (ref1.y+ref1.h) <= (ref2.y+ref2.h) ) {
193 if (!hidden) { // we are not hidden, perfect
194 todraw.push_back(&(*itty1));
199 getScreenSize(swidth,sheight);
200 //Now go through all surfaces and draw them
201 list<SurfaceCommands*>::iterator curdraw=todraw.begin();
202 while (curdraw!=todraw.end()) {
203 drawSetTrans(*(*curdraw));
204 list<SVGCommand>::iterator commands=(*(*curdraw)).commands.begin();
205 list<SVGCommand>::iterator end=(*(*curdraw)).commands.end();
206 while (commands!=end) {
207 // update any images loaded in the mean time
208 if ((*commands).instr==DrawImageLoading) {
209 LoadIndex loadindex=(*commands).target.loadindex;
210 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
211 (*commands).instr=DrawImage;
212 (*commands).target.image=tvmedias_loaded[loadindex];;
213 incImageRef((*commands).target.image);
214 removeLoadIndexRef(loadindex);
218 // Now check if the command is on screen!
219 if (!(*commands).Outside(0,0,swidth,sheight)) {
220 executeDrawCommand(*commands);
227 surfaces_mutex.Unlock();
230 void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
231 list<SVGCommand>& commands)
233 surfaces_mutex.Lock();
234 //First determine it is already in our system
235 list<SurfaceCommands>::iterator itty=scommands.begin();
236 while (itty!=scommands.end()) {
237 if ((*itty).surf==surf) {
238 //decrease the references
239 dereferenceSVGCommand((*itty).commands);
245 if (itty==scommands.end()) {
246 SurfaceCommands new_sc;
252 itty=scommands.insert(itty,new_sc);
254 // update any images loaded in the mean time
255 list<SVGCommand>::iterator ilitty=commands.begin();
257 while (ilitty!=commands.end())
259 if ((*ilitty).instr==DrawImageLoading) {
260 LoadIndex loadindex=(*ilitty).target.loadindex;
261 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
263 (*ilitty).instr=DrawImage;
264 (*ilitty).target.image=tvmedias_loaded[loadindex];
265 incImageRef((*ilitty).target.image);
266 removeLoadIndexRef(loadindex);
273 // then clear and copy
274 (*itty).commands.clear();
275 (*itty).commands=commands;
276 //increase the references
277 referenceSVGCommand((*itty).commands);
278 cleanupOrphanedRefs();
280 surfaces_mutex.Unlock();
283 void OsdVector::removeSurface(const SurfaceVector *surf)
285 surfaces_mutex.Lock();
286 //First determine it is already in our system
287 list<SurfaceCommands>::iterator itty=scommands.begin();
288 while (itty!=scommands.end()) {
289 if ((*itty).surf==surf) {
290 dereferenceSVGCommand((*itty).commands);
291 (*itty).commands.clear();
292 scommands.erase(itty);
297 surfaces_mutex.Unlock();
301 void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )
304 list<SVGCommand>::iterator sitty = commands.begin();
305 while (sitty != commands.end()) {
306 removeStyleRef((*sitty).getRef());
307 ImageIndex ii = (*sitty).getImageIndex();
308 if (ii) removeImageRef(ii);
309 LoadIndex li=(*sitty).getLoadIndex();
310 if (li) removeLoadIndexRef(li);
315 void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )
317 list<SVGCommand>::iterator sitty=commands.begin();
318 while (sitty!=commands.end())
320 incStyleRef((*sitty).getRef());
321 ImageIndex ii=(*sitty).getImageIndex();
322 if (ii) incImageRef(ii);
323 LoadIndex li=(*sitty).getLoadIndex();
324 if (li) incLoadIndexRef(li);
330 void OsdVector::incImageRef(ImageIndex index)
332 if (images_ref.find(index)==images_ref.end()) {
339 void OsdVector::removeImageRef(const ImageIndex ref)
344 int OsdVector::getLoadIndexRef(LoadIndex index)
346 if (loadindex_ref.find(index)==loadindex_ref.end()) {
349 return loadindex_ref[index];
353 void OsdVector::incLoadIndexRef(LoadIndex index)
355 if (loadindex_ref.find(index)==loadindex_ref.end()) {
356 loadindex_ref[index]=1;
358 loadindex_ref[index]++;
362 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
364 loadindex_ref[ref]--;
365 if (loadindex_ref[ref]==0) {
366 //now check, if it is already loaded
367 map<LoadIndex,ImageIndex>::iterator itty=tvmedias_loaded.find(ref);
368 if ( itty != tvmedias_loaded.end()) {
369 removeImageRef((*itty).second); // remove lock
371 tvmedias_loaded.erase(ref);
372 tvmedias_load.erase(tvmedias_load_inv[ref]);
373 tvmedias_load_inv.erase(ref);
375 reader.invalidateLoadIndex(ref);
383 void OsdVector::cleanupOrphanedRefs()
384 { // Do some garbage collection
386 map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
387 while (mitty!=monobitmaps.end()) {
388 map<ImageIndex,int>::iterator curitty=images_ref.find((*mitty).second);
389 int count=(*curitty).second;
391 ImageIndex ref=(*curitty).first;
392 monobitmaps.erase(mitty++);
393 images_ref.erase(curitty++);
394 destroyImageRef(ref);
398 /*map<string,ImageIndex>::iterator jitty=jpegs.begin();
399 while (jitty!=jpegs.end()) {
400 map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
401 int count=(*curitty).second;
403 ImageIndex ref=(*curitty).first;
404 jpegs.erase(jitty++);
405 images_ref.erase(curitty++);
406 destroyImageRef(ref);
410 map<TVMediaInfo,ImageIndex>::iterator titty=tvmedias.begin();
411 while (titty!=tvmedias.end()) {
412 map<ImageIndex,int>::iterator curitty=images_ref.find((*titty).second);
413 int count=(*curitty).second;
415 ImageIndex ref=(*curitty).first;
416 tvmedias.erase(titty++);
417 images_ref.erase(curitty);
418 destroyImageRef(ref);
423 map<TVMediaInfo,LoadIndex>::iterator litty=tvmedias_load.begin();
424 while (litty!=tvmedias_load.end()) {
425 map<LoadIndex,int>::iterator curitty=loadindex_ref.find((*litty).second);
426 int count=(*curitty).second;
428 tvmedias_load_inv.erase((*litty).second);
429 tvmedias_loaded.erase((*litty).second);
430 tvmedias_load.erase(litty++);
435 map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
436 while (sitty!=styles.end()) {
437 map<unsigned int,int>::iterator curitty=styles_ref.find((*sitty).second);
438 int count=(*curitty).second;
440 unsigned int ref=(*curitty).first;
441 styles.erase(sitty++);
442 styles_ref.erase(curitty++);
443 destroyStyleRef(ref);
451 int OsdVector::getImageRef(ImageIndex index)
453 if (images_ref.find(index)==images_ref.end()) {
456 return images_ref[index];
460 void OsdVector::incStyleRef(unsigned int index)
462 if (styles_ref.find(index)==styles_ref.end()) {
469 void OsdVector::removeStyleRef(unsigned int index)
474 unsigned int OsdVector::getStyleRef(const DrawStyle &c)
476 unsigned int style_handle=0;
477 if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
479 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
481 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
482 //Now check if the handle is valid
483 if (styles_ref.find(style_handle)==styles_ref.end()) {
484 //invalid handle recreate
485 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
488 incStyleRef(style_handle);
492 unsigned int OsdVector::getColorRef(const Colour &c)
494 unsigned int style_handle=0;
495 if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
497 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
499 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
500 if (styles_ref.find(style_handle)==styles_ref.end()) {
501 //invalid handle recreate
502 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
505 incStyleRef(style_handle);
509 int OsdVector::getStyleRef(unsigned int index)
511 if (styles_ref.find(index)==styles_ref.end()) {
514 return styles_ref[index];
518 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
520 ImageIndex image_handle=0;
521 LoadIndex loadindex=0;
522 if (tvmedias.find(tvmedia)==tvmedias.end())
524 loadindex=loadTVMedia(tvmedia);
526 image_handle=tvmedias[tvmedia];
527 if (images_ref.find(image_handle)==images_ref.end()) {
528 //invalid handle recreate
529 loadindex=loadTVMedia(tvmedia);
532 incImageRef(image_handle);
535 /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
536 incImageRef(image_handle);*/
541 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
544 if (tvmedias_load.find(tvmedia)==tvmedias_load.end())
546 switch (tvmedia.getType()) {
548 index=VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
551 index = ((long long) tvmedia.getPrimaryID()) << 32LL;
552 reader.addStaticImage(tvmedia.getPrimaryID());
555 index=VDR::getInstance()->loadTVMedia(tvmedia);
559 tvmedias_load[tvmedia]=index;
560 tvmedias_load_inv[index]=tvmedia;
563 index=tvmedias_load[tvmedia];
566 incLoadIndexRef(index);
573 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
575 //Beware for thread safety
576 ImageIndex image_index=0;
578 TVMediaInfo tvmedia=tvmedias_load_inv[index];
579 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %llx arrived %d",index, imageIndex);
581 image_index=tvmedias[tvmedia]=imageIndex;
582 tvmedias_loaded[index]=image_index;
583 if (getLoadIndexRef(index) < 1) {
584 // we do not want the picture anymore . Really...
585 // fill images_ref in to not irritate the garbage collector
586 if (getImageRef(image_index) < 0) {
587 images_ref[image_index]=0;
591 incImageRef(image_index); // hold one index until all loadings refs are gone;
602 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
604 ImageIndex image_handle=0;
605 if (jpegs.find(fileName)==jpegs.end())
607 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
609 image_handle=jpegs[fileName];
612 if (images_ref.find(image_handle)==images_ref.end()) {
613 //invalid handle recreate
614 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
617 incImageRef(image_handle);
622 ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
624 ImageIndex image_handle;
625 if (monobitmaps.find(base)==monobitmaps.end())
627 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
629 image_handle=monobitmaps[base];
630 if (images_ref.find(image_handle)==images_ref.end()) {
631 //invalid handle recreate
632 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
635 incImageRef(image_handle);
639 ImageIndex OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
641 ImageIndex image_handle;
642 image_handle=createImagePalette(width,height,image_data,palette_data);
643 incImageRef(image_handle);
647 OsdVector::PictureReader::~PictureReader()
649 decoders_lock.Lock();
650 while ( decoders.size()) {
651 PictureDecoder* dec=decoders.front();
652 decoders.pop_front();
656 decoders_lock.Unlock();
659 void OsdVector::PictureReader::init()
664 void OsdVector::PictureReader::shutdown()
671 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
673 decoders_lock.Lock();
675 decoders.push_front(decoder);
676 decoders_lock.Unlock();
679 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
681 decoders_lock.Lock();
682 std::list<PictureDecoder*>::iterator itty=decoders.begin();
683 while (itty!=decoders.end()) {
684 if ((*itty) == decoder)
686 decoders.erase(itty);
691 Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
694 decoders_lock.Unlock();
697 void OsdVector::PictureReader::threadMethod()
699 OsdVector *osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
700 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
702 if (!threadIsActive()) {
703 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
712 decoders_lock.Lock();
713 std::list<PictureDecoder*>::iterator itty=decoders.begin();
715 while (itty!=decoders.end()) {
716 if ((*itty)->getDecodedPicture(pictinf)) {
718 osdvector->createPicture(pictinf);
723 if (processReceivedPictures())
728 decoders_lock.Unlock();
730 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
733 threadWaitForSignal();
735 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
739 void OsdVector::PictureReader::threadPostStopCleanup()
744 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
746 pict_lock_incoming.Lock();
747 invalid_loadindex.insert(index);
748 pict_lock_incoming.Unlock();
751 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket *vresp)
753 pict_lock_incoming.Lock();
754 pict_incoming.push(vresp);
755 pict_lock_incoming.Unlock();
760 void OsdVector::PictureReader::addStaticImage(unsigned int id)
762 pict_lock_incoming.Lock();
763 pict_incoming_static.push(id);
764 invalid_loadindex.erase(((long long) id) << 32LL);
765 pict_lock_incoming.Unlock();
769 bool OsdVector::PictureReader::processReceivedPictures()
771 bool decoded = false;
773 pict_lock_incoming.Lock();
774 if (pict_incoming.size()) {
775 VDR_ResponsePacket *vresp=pict_incoming.front();
777 set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
778 if (setpos != invalid_loadindex.end()) {
780 invalid_loadindex.erase(setpos);
782 pict_lock_incoming.Unlock();
783 if (!valid) { // we do not want it anymore skip it;
787 if (vresp->getFlag() != 2) {
788 UCHAR *userdata=vresp->getUserData();
789 ULONG length=vresp->getUserDataLength();
790 std::list<PictureDecoder*>::iterator itty=decoders.begin();
791 while (itty!=decoders.end()) {
792 if ((*itty)->decodePicture(vresp->getStreamID(),
800 free(vresp->getUserData());
803 //else osd->informPicture(vresp->getStreamID(), 0);
805 } else if (pict_incoming_static.size()){
806 unsigned int static_id = pict_incoming_static.front();
807 pict_incoming_static.pop();
808 set<LoadIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
809 if (setpos != invalid_loadindex.end()) {
811 invalid_loadindex.erase(setpos);
813 pict_lock_incoming.Unlock();
814 if (!valid) { // we do not want it anymore skip it;
820 if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
822 std::list<PictureDecoder*>::iterator itty=decoders.begin();
823 while (itty!=decoders.end()) {
824 if ((*itty)->decodePicture(((long long) static_id) << 32LL,userdata, length, false)){
832 pict_lock_incoming.Unlock();