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);
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)
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 myblob.updateNoCopy(buffer,length,Blob::MallocAllocator);
59 magicimage.read(myblob);
61 magicimage.write(imageblob,"RGBA");
63 }catch( Exception &error_ )
65 Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: %s",error_.what());
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;
81 // I can handle everything, so the return value is always true
84 void MagickDecoder::freeReference(void * ref)
86 Blob *todelete = (Blob*) ref;
90 bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
92 if (!pictInfValid) return false;
101 OsdVector::OsdVector()
103 setlocale(LC_CTYPE,"C.UTF-8");
104 #ifdef PICTURE_DECODER_MAGICK
105 reader.addDecoder(new MagickDecoder(&reader));
110 OsdVector::~OsdVector()
115 int OsdVector::getFD()
120 void OsdVector::screenShot(const char* fileName)
125 Surface * OsdVector::createNewSurface()
127 return new SurfaceVector(this);
130 void OsdVector::BeginPainting()
132 surfaces_mutex.Lock();
134 void OsdVector::EndPainting()
136 surfaces_mutex.Unlock();
139 void OsdVector::Blank()
141 // do nothing? remove this one?
144 int OsdVector::restore()
146 // First clear the contents of all registered surfaces
147 surfaces_mutex.Lock();
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();
155 //also clear all handles, they are now invalid, no need to release them
162 surfaces_mutex.Unlock();
166 void OsdVector::drawSurfaces()
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;
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) ) {
186 if (!hidden) { // we are not hidden, perfect
187 todraw.push_back(&(*itty1));
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);
211 // Now check if the command is on screen!
212 if (!(*commands).Outside(0,0,swidth,sheight)) {
213 executeDrawCommand(*commands);
220 surfaces_mutex.Unlock();
223 void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
224 list<SVGCommand>& commands)
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);
238 if (itty==scommands.end()) {
239 SurfaceCommands new_sc;
245 itty=scommands.insert(itty,new_sc);
247 // update any images loaded in the mean time
248 list<SVGCommand>::iterator ilitty=commands.begin();
250 while (ilitty!=commands.end())
252 if ((*ilitty).instr==DrawImageLoading) {
253 LoadIndex loadindex=(*ilitty).target.loadindex;
254 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
256 (*ilitty).instr=DrawImage;
257 (*ilitty).target.image=tvmedias_loaded[loadindex];
258 incImageRef((*ilitty).target.image);
259 removeLoadIndexRef(loadindex);
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())
273 incStyleRef((*sitty).getRef());
274 ImageIndex ii=(*sitty).getImageIndex();
275 if (ii) incImageRef(ii);
276 LoadIndex li=(*sitty).getLoadIndex();
277 if (li) incLoadIndexRef(li);
280 cleanupOrphanedRefs();
282 surfaces_mutex.Unlock();
285 void OsdVector::removeSurface(const SurfaceVector *surf)
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);
299 surfaces_mutex.Unlock();
303 void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )
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);
317 void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )
319 list<SVGCommand>::iterator sitty=commands.begin();
320 while (sitty!=commands.end())
322 incStyleRef((*sitty).getRef());
323 ImageIndex ii=(*sitty).getImageIndex();
324 if (ii) incImageRef(ii);
325 LoadIndex li=(*sitty).getLoadIndex();
326 if (li) incLoadIndexRef(li);
332 void OsdVector::incImageRef(ImageIndex index)
334 if (images_ref.find(index)==images_ref.end()) {
341 void OsdVector::removeImageRef(const ImageIndex ref)
346 int OsdVector::getLoadIndexRef(LoadIndex index)
348 if (loadindex_ref.find(index)==loadindex_ref.end()) {
351 return loadindex_ref[index];
355 void OsdVector::incLoadIndexRef(LoadIndex index)
357 if (loadindex_ref.find(index)==loadindex_ref.end()) {
358 loadindex_ref[index]=1;
360 loadindex_ref[index]++;
364 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
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
373 tvmedias_loaded.erase(ref);
374 tvmedias_load.erase(tvmedias_load_inv[ref]);
375 tvmedias_load_inv.erase(ref);
377 reader.invalidateLoadIndex(ref);
385 void OsdVector::cleanupOrphanedRefs()
386 { // Do some garbage collection
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;
393 ImageIndex ref=(*curitty).first;
394 monobitmaps.erase(mitty++);
395 images_ref.erase(curitty++);
396 destroyImageRef(ref);
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;
405 ImageIndex ref=(*curitty).first;
406 jpegs.erase(jitty++);
407 images_ref.erase(curitty++);
408 destroyImageRef(ref);
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;
417 ImageIndex ref=(*curitty).first;
418 tvmedias.erase(titty++);
419 images_ref.erase(curitty++);
420 destroyImageRef(ref);
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;
430 unsigned int ref=(*curitty).first;
431 styles.erase(sitty++);
432 styles_ref.erase(curitty++);
433 destroyStyleRef(ref);
441 int OsdVector::getImageRef(ImageIndex index)
443 if (images_ref.find(index)==images_ref.end()) {
446 return images_ref[index];
450 void OsdVector::incStyleRef(unsigned int index)
452 if (styles_ref.find(index)==styles_ref.end()) {
459 void OsdVector::removeStyleRef(unsigned int index)
464 unsigned int OsdVector::getStyleRef(const DrawStyle &c)
466 unsigned int style_handle=0;
467 if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
469 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
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);
478 incStyleRef(style_handle);
482 unsigned int OsdVector::getColorRef(const Colour &c)
484 unsigned int style_handle=0;
485 if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
487 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
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);
495 incStyleRef(style_handle);
499 int OsdVector::getStyleRef(unsigned int index)
501 if (styles_ref.find(index)==styles_ref.end()) {
504 return styles_ref[index];
508 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
510 ImageIndex image_handle=0;
511 LoadIndex loadindex=0;
512 if (tvmedias.find(tvmedia)==tvmedias.end())
514 loadindex=loadTVMedia(tvmedia);
516 image_handle=tvmedias[tvmedia];
517 if (images_ref.find(image_handle)==images_ref.end()) {
518 //invalid handle recreate
519 loadindex=loadTVMedia(tvmedia);
522 incImageRef(image_handle);
525 /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
526 incImageRef(image_handle);*/
531 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
534 if (tvmedias_load.find(tvmedia)==tvmedias_load.end())
536 switch (tvmedia.getType()) {
538 index=VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
541 index=VDR::getInstance()->loadTVMedia(tvmedia);
545 tvmedias_load[tvmedia]=index;
546 tvmedias_load_inv[index]=tvmedia;
548 index=tvmedias_load[tvmedia];
551 incLoadIndexRef(index);
558 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
560 //Beware for thread safety
561 ImageIndex image_index=0;
563 TVMediaInfo tvmedia=tvmedias_load_inv[index];
564 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %d arrived",index);
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;
576 incImageRef(image_index); // hold one index until all loadings refs are gone;
587 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
589 ImageIndex image_handle=0;
590 if (jpegs.find(fileName)==jpegs.end())
592 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
594 image_handle=jpegs[fileName];
597 if (images_ref.find(image_handle)==images_ref.end()) {
598 //invalid handle recreate
599 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
602 incImageRef(image_handle);
606 ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
608 ImageIndex image_handle;
609 if (monobitmaps.find(base)==monobitmaps.end())
611 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
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);
619 incImageRef(image_handle);
623 ImageIndex OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
625 ImageIndex image_handle;
626 image_handle=createImagePalette(width,height,image_data,palette_data);
627 incImageRef(image_handle);
631 OsdVector::PictureReader::~PictureReader()
633 decoders_lock.Lock();
634 while ( decoders.size()) {
635 PictureDecoder* dec=decoders.front();
636 decoders.pop_front();
640 decoders_lock.Unlock();
643 void OsdVector::PictureReader::init()
648 void OsdVector::PictureReader::shutdown()
655 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
657 decoders_lock.Lock();
659 decoders.push_front(decoder);
660 decoders_lock.Unlock();
663 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
665 decoders_lock.Lock();
666 std::list<PictureDecoder*>::iterator itty=decoders.begin();
667 while (itty!=decoders.end()) {
668 if ((*itty) == decoder)
670 decoders.erase(itty);
675 Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
678 decoders_lock.Unlock();
681 void OsdVector::PictureReader::threadMethod()
683 OsdVector *osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
684 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
686 if (!threadIsActive()) {
687 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
696 decoders_lock.Lock();
697 std::list<PictureDecoder*>::iterator itty=decoders.begin();
699 while (itty!=decoders.end()) {
700 if ((*itty)->getDecodedPicture(pictinf)) {
702 osdvector->createPicture(pictinf);
707 if (processReceivedPictures())
712 decoders_lock.Unlock();
714 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
717 threadWaitForSignal();
719 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
723 void OsdVector::PictureReader::threadPostStopCleanup()
728 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
730 pict_lock_incoming.Lock();
731 invalid_loadindex.insert(index);
732 pict_lock_incoming.Unlock();
735 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket *vresp)
737 pict_lock_incoming.Lock();
738 pict_incoming.push(vresp);
739 pict_lock_incoming.Unlock();
743 bool OsdVector::PictureReader::processReceivedPictures()
745 bool decoded = false;
747 pict_lock_incoming.Lock();
748 if (pict_incoming.size()) {
749 VDR_ResponsePacket *vresp=pict_incoming.front();
751 set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
752 if (setpos != invalid_loadindex.end()) {
754 invalid_loadindex.erase(setpos);
756 pict_lock_incoming.Unlock();
757 if (!valid) { // we do not want it anymore skip it;
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(),
774 free(vresp->getUserData());
777 //else osd->informPicture(vresp->getStreamID(), 0);
780 pict_lock_incoming.Unlock();