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 OsdVector::OsdVector()
30 setlocale(LC_CTYPE,"C.UTF-8");
34 OsdVector::~OsdVector()
40 int OsdVector::getFD()
45 void OsdVector::screenShot(const char* fileName)
50 Surface * OsdVector::createNewSurface()
52 return new SurfaceVector(this);
55 void OsdVector::BeginPainting()
57 surfaces_mutex.Lock();
59 void OsdVector::EndPainting()
61 surfaces_mutex.Unlock();
64 void OsdVector::Blank()
66 // do nothing? remove this one?
69 int OsdVector::restore()
71 // First clear the contents of all registered surfaces
72 surfaces_mutex.Lock();
74 //Now go through all surfaces and draw them
75 list<SurfaceCommands>::iterator curdraw=scommands.begin();
76 while (curdraw!=scommands.end()) {
77 (*curdraw).commands.clear();
80 //also clear all handles, they are now invalid, no need to release them
87 surfaces_mutex.Unlock();
91 void OsdVector::drawSurfaces()
93 surfaces_mutex.Lock();
94 list<SurfaceCommands*> todraw; //First figure out if a surfaces is below another surface
95 list<SurfaceCommands>::iterator itty1=scommands.begin();
96 while (itty1!=scommands.end()) {
97 list<SurfaceCommands>::iterator itty2=itty1;
100 while (itty2!=scommands.end()) {
101 SurfaceCommands & ref1=*itty1;
102 SurfaceCommands & ref2=*itty2;
103 if (ref1.x>=ref2.x && ref1.y>=ref2.y
104 && (ref1.x+ref1.w) <= (ref2.x+ref2.w)
105 && (ref1.y+ref1.h) <= (ref2.y+ref2.h) ) {
111 if (!hidden) { // we are not hidden, perfect
112 todraw.push_back(&(*itty1));
117 getScreenSize(swidth,sheight);
118 //Now go through all surfaces and draw them
119 list<SurfaceCommands*>::iterator curdraw=todraw.begin();
120 while (curdraw!=todraw.end()) {
121 drawSetTrans(*(*curdraw));
122 list<SVGCommand>::iterator commands=(*(*curdraw)).commands.begin();
123 list<SVGCommand>::iterator end=(*(*curdraw)).commands.end();
124 while (commands!=end) {
125 // update any images loaded in the mean time
126 if ((*commands).instr==DrawImageLoading) {
127 LoadIndex loadindex=(*commands).target.loadindex;
128 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
129 (*commands).instr=DrawImage;
130 (*commands).target.image=tvmedias_loaded[loadindex];;
131 incImageRef((*commands).target.image);
132 removeLoadIndexRef(loadindex);
136 // Now check if the command is on screen!
137 if (!(*commands).Outside(0,0,swidth,sheight)) {
138 executeDrawCommand(*commands);
145 surfaces_mutex.Unlock();
148 void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
149 list<SVGCommand>& commands)
151 surfaces_mutex.Lock();
152 //First determine it is already in our system
153 list<SurfaceCommands>::iterator itty=scommands.begin();
154 while (itty!=scommands.end()) {
155 if ((*itty).surf==surf) {
156 //decrease the references
157 dereferenceSVGCommand((*itty).commands);
163 if (itty==scommands.end()) {
164 SurfaceCommands new_sc;
170 itty=scommands.insert(itty,new_sc);
172 // update any images loaded in the mean time
173 list<SVGCommand>::iterator ilitty=commands.begin();
175 while (ilitty!=commands.end())
177 if ((*ilitty).instr==DrawImageLoading) {
178 LoadIndex loadindex=(*ilitty).target.loadindex;
179 if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
181 (*ilitty).instr=DrawImage;
182 (*ilitty).target.image=tvmedias_loaded[loadindex];
183 incImageRef((*ilitty).target.image);
184 removeLoadIndexRef(loadindex);
191 // then clear and copy
192 (*itty).commands.clear();
193 (*itty).commands=commands;
194 //increase the references
195 list<SVGCommand>::iterator sitty=(*itty).commands.begin();
196 while (sitty!=(*itty).commands.end())
198 incStyleRef((*sitty).getRef());
199 ImageIndex ii=(*sitty).getImageIndex();
200 if (ii) incImageRef(ii);
201 LoadIndex li=(*sitty).getLoadIndex();
202 if (li) incLoadIndexRef(li);
205 cleanupOrphanedRefs();
207 surfaces_mutex.Unlock();
210 void OsdVector::removeSurface(const SurfaceVector *surf)
212 surfaces_mutex.Lock();
213 //First determine it is already in our system
214 list<SurfaceCommands>::iterator itty=scommands.begin();
215 while (itty!=scommands.end()) {
216 if ((*itty).surf==surf) {
217 dereferenceSVGCommand((*itty).commands);
218 (*itty).commands.clear();
219 scommands.erase(itty);
224 surfaces_mutex.Unlock();
228 void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )
231 list<SVGCommand>::iterator sitty = commands.begin();
232 while (sitty != commands.end()) {
233 removeStyleRef((*sitty).getRef());
234 ImageIndex ii = (*sitty).getImageIndex();
235 if (ii) removeImageRef(ii);
236 LoadIndex li=(*sitty).getLoadIndex();
237 if (li) removeLoadIndexRef(li);
242 void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )
244 list<SVGCommand>::iterator sitty=commands.begin();
245 while (sitty!=commands.end())
247 incStyleRef((*sitty).getRef());
248 ImageIndex ii=(*sitty).getImageIndex();
249 if (ii) incImageRef(ii);
250 LoadIndex li=(*sitty).getLoadIndex();
251 if (li) incLoadIndexRef(li);
257 void OsdVector::incImageRef(ImageIndex index)
259 if (images_ref.find(index)==images_ref.end()) {
266 void OsdVector::removeImageRef(const ImageIndex ref)
271 unsigned int OsdVector::getLoadIndexRef(LoadIndex index)
273 if (loadindex_ref.find(index)==loadindex_ref.end()) {
276 return loadindex_ref[index];
280 void OsdVector::incLoadIndexRef(LoadIndex index)
282 if (loadindex_ref.find(index)==loadindex_ref.end()) {
283 loadindex_ref[index]=1;
285 loadindex_ref[index]++;
289 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
291 loadindex_ref[ref]--;
292 if (loadindex_ref[ref]==0) {
293 //now check, if it is already loaded
294 map<LoadIndex,ImageIndex>::iterator itty=tvmedias_loaded.find(ref);
295 if ( itty != tvmedias_loaded.end()) {
296 removeImageRef((*itty).second); // remove lock
298 tvmedias_loaded.erase(ref);
299 tvmedias_load.erase(tvmedias_load_inv[ref]);
300 tvmedias_load_inv.erase(ref);
304 void OsdVector::cleanupOrphanedRefs()
305 { // Do some garbage collection
307 map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
308 while (mitty!=monobitmaps.end()) {
309 map<ImageIndex,unsigned int>::iterator curitty=images_ref.find((*mitty).second);
310 int count=(*curitty).second;
312 ImageIndex ref=(*curitty).first;
313 monobitmaps.erase(mitty++);
314 images_ref.erase(curitty++);
315 destroyImageRef(ref);
319 map<string,ImageIndex>::iterator jitty=jpegs.begin();
320 while (jitty!=jpegs.end()) {
321 map<ImageIndex,unsigned int>::iterator curitty=images_ref.find((*jitty).second);
322 int count=(*curitty).second;
324 ImageIndex ref=(*curitty).first;
325 jpegs.erase(jitty++);
326 images_ref.erase(curitty++);
327 destroyImageRef(ref);
331 map<TVMediaInfo,ImageIndex>::iterator titty=tvmedias.begin();
332 while (titty!=tvmedias.end()) {
333 map<ImageIndex,unsigned int>::iterator curitty=images_ref.find((*titty).second);
334 int count=(*curitty).second;
337 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia destroy Picture");
338 ImageIndex ref=(*curitty).first;
339 tvmedias.erase(titty++);
340 images_ref.erase(curitty++);
341 destroyImageRef(ref);
346 map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
347 while (sitty!=styles.end()) {
348 map<unsigned int,unsigned int>::iterator curitty=styles_ref.find((*sitty).second);
349 int count=(*curitty).second;
351 unsigned int ref=(*curitty).first;
352 styles.erase(sitty++);
353 styles_ref.erase(curitty++);
354 destroyStyleRef(ref);
362 unsigned int OsdVector::getImageRef(ImageIndex index)
364 if (images_ref.find(index)==images_ref.end()) {
367 return images_ref[index];
371 void OsdVector::incStyleRef(unsigned int index)
373 if (styles_ref.find(index)==styles_ref.end()) {
380 void OsdVector::removeStyleRef(unsigned int index)
385 unsigned int OsdVector::getStyleRef(const DrawStyle &c)
387 unsigned int style_handle=0;
388 if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
390 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
392 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
393 //Now check if the handle is valid
394 if (styles_ref.find(style_handle)==styles_ref.end()) {
395 //invalid handle recreate
396 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
399 incStyleRef(style_handle);
403 unsigned int OsdVector::getColorRef(const Colour &c)
405 unsigned int style_handle=0;
406 if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
408 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
410 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
411 if (styles_ref.find(style_handle)==styles_ref.end()) {
412 //invalid handle recreate
413 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
416 incStyleRef(style_handle);
420 unsigned int OsdVector::getStyleRef(unsigned int index)
422 if (styles_ref.find(index)==styles_ref.end()) {
425 return styles_ref[index];
429 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
431 ImageIndex image_handle=0;
432 LoadIndex loadindex=0;
433 if (tvmedias.find(tvmedia)==tvmedias.end())
435 loadindex=loadTVMedia(tvmedia);
437 image_handle=tvmedias[tvmedia];
438 if (images_ref.find(image_handle)==images_ref.end()) {
439 //invalid handle recreate
440 loadindex=loadTVMedia(tvmedia);
443 incImageRef(image_handle);
446 /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
447 incImageRef(image_handle);*/
452 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
455 if (tvmedias_load.find(tvmedia)==tvmedias_load.end())
457 index=VDR::getInstance()->loadTVMedia(tvmedia);
458 tvmedias_load[tvmedia]=index;
459 tvmedias_load_inv[index]=tvmedia;
461 index=tvmedias_load[tvmedia];
464 incLoadIndexRef(index);
469 void OsdVector::setTVMedia(LoadIndex index, unsigned char * buffer, unsigned int length)
471 //Beware for thread safety
472 ImageIndex image_index=0;
474 TVMediaInfo tvmedia=tvmedias_load_inv[index];
475 Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %d arrived",index);
477 if (getLoadIndexRef(index)<1) {
478 // we do not want the picture anymore . Really...
480 image_index=tvmedias[tvmedia]=createPicture(buffer,length);
481 tvmedias_loaded[index]=image_index;
482 incImageRef(image_index); // hold one index until all loadings refs are gone;
491 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
493 ImageIndex image_handle=0;
494 if (jpegs.find(fileName)==jpegs.end())
496 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
498 image_handle=jpegs[fileName];
501 if (images_ref.find(image_handle)==images_ref.end()) {
502 //invalid handle recreate
503 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
506 incImageRef(image_handle);
510 ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
512 ImageIndex image_handle;
513 if (monobitmaps.find(base)==monobitmaps.end())
515 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
517 image_handle=monobitmaps[base];
518 if (images_ref.find(image_handle)==images_ref.end()) {
519 //invalid handle recreate
520 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
523 incImageRef(image_handle);
527 ImageIndex OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
529 ImageIndex image_handle;
530 image_handle=createImagePalette(width,height,image_data,palette_data);
531 incImageRef(image_handle);
535 void OsdVector::receivePicture(VDR_ResponsePacket *vresp)
537 pict_lock_incoming.Lock();
538 pict_incoming.push(vresp);
539 pict_lock_incoming.Unlock();
540 //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived");
541 if (picture_update) {
542 Message* m = new Message();
543 // This is incoming from VDR, we do not want to block gui so send a message to ourself to switch to gui thread
544 m->message=Message::PICTURES_ARRIVED;
546 m->to=Command::getInstance();
547 picture_update=false;
548 Command::getInstance()->postMessageFromOuterSpace(m); // inform command about new picture
552 bool OsdVector::processReceivedPictures()
555 pict_lock_incoming.Lock();
557 long long time1 = getTimeMS();
558 long long cur_time =time1;
559 while (pict_incoming.size() && (time1-cur_time)<100) {
560 VDR_ResponsePacket *vresp=pict_incoming.front();
562 pict_lock_incoming.Unlock();
563 if (vresp->getFlag() != 2) {
564 setTVMedia(vresp->getStreamID(), vresp->getUserData(), vresp->getUserDataLength());
567 else setTVMedia(vresp->getStreamID(), NULL, 0);
569 cur_time = getTimeMS();
570 pict_lock_incoming.Lock();
572 if (pict_incoming.size()==0) picture_update=true;
573 pict_lock_incoming.Unlock();
576 if (!picture_update) {
577 Message* m = new Message();
578 // We have remaing pictures! send a message to ourself to switch to gui thread
579 m->message=Message::PICTURES_ARRIVED;
581 m->to=Command::getInstance();
582 picture_update=false;
583 Command::getInstance()->postMessageNoLock(m); // inform command about new picture