]> git.vomp.tv Git - vompclient.git/blob - osdvector.cc
Merge branch 'master' of ssh://git.vomp.tv:20022/vompclient into scraper_support
[vompclient.git] / osdvector.cc
1 /*
2     Copyright 2012 Marten Richter
3
4     This file is part of VOMP.
5
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.
10
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.
15
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.
19 */
20
21 #include "osdvector.h"
22 #include "surfacevector.h"
23 #include "vdr.h"
24 #include "vdrresponsepacket.h"
25 #include "command.h"
26 #include "message.h"
27
28 OsdVector::OsdVector()
29 {
30         setlocale(LC_CTYPE,"C.UTF-8");
31         picture_update=true;
32 }
33
34 OsdVector::~OsdVector()
35 {
36
37 }
38
39
40 int OsdVector::getFD()
41 {
42         return 0;
43 }
44
45 void OsdVector::screenShot(const char* fileName)
46 {
47         //Do nothing,
48 }
49
50 Surface * OsdVector::createNewSurface()
51 {
52         return new SurfaceVector(this);
53 }
54
55 void OsdVector::BeginPainting()
56 {
57         surfaces_mutex.Lock();
58 }
59 void OsdVector::EndPainting()
60 {
61         surfaces_mutex.Unlock();
62 }
63
64 void OsdVector::Blank()
65 {
66         // do nothing? remove this one?
67 }
68
69 int OsdVector::restore()
70 {
71         // First clear the contents of all registered surfaces
72         surfaces_mutex.Lock();
73
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();
78                 curdraw++;
79         }
80         //also clear all handles, they are now invalid, no need to release them
81         images_ref.clear();
82         monobitmaps.clear();
83         jpegs.clear();
84         styles.clear();
85         styles_ref.clear();
86
87         surfaces_mutex.Unlock();
88         return 1;
89 }
90
91 void OsdVector::drawSurfaces()
92 {
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;
98                 itty2++;
99                 bool hidden=false;
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) ) {
106                                 hidden=true;
107                                 break;
108                         }
109                         itty2++;
110                 }
111                 if (!hidden) { // we are not hidden, perfect
112                         todraw.push_back(&(*itty1));
113                 }
114                 itty1++;
115         }
116         int swidth,sheight;
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);
133                                 }
134
135                         }
136                         // Now check if the command is on screen!
137                         if  (!(*commands).Outside(0,0,swidth,sheight)) {
138                                 executeDrawCommand(*commands);
139                         }
140                         commands++;
141                 }
142                 curdraw++;
143         }
144
145         surfaces_mutex.Unlock();
146 }
147
148 void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
149                         list<SVGCommand>& commands)
150 {
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);
158                         break;
159                 }
160                 itty++;
161         }
162         // if not insert it
163         if (itty==scommands.end()) {
164                 SurfaceCommands new_sc;
165                 new_sc.surf=surf;
166                 new_sc.x=x;
167                 new_sc.y=y;
168                 new_sc.w=width;
169                 new_sc.h=height;
170                 itty=scommands.insert(itty,new_sc);
171         }
172         // update any images loaded in the mean time
173         list<SVGCommand>::iterator ilitty=commands.begin();
174
175         while (ilitty!=commands.end())
176         {
177                 if ((*ilitty).instr==DrawImageLoading) {
178                         LoadIndex loadindex=(*ilitty).target.loadindex;
179                         if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) {
180
181                                 (*ilitty).instr=DrawImage;
182                                 (*ilitty).target.image=tvmedias_loaded[loadindex];
183                                 incImageRef((*ilitty).target.image);
184                                 removeLoadIndexRef(loadindex);
185                         }
186                 }
187                 ilitty++;
188         }
189
190
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())
197         {
198                 incStyleRef((*sitty).getRef());
199                 ImageIndex ii=(*sitty).getImageIndex();
200                 if (ii) incImageRef(ii);
201                 LoadIndex li=(*sitty).getLoadIndex();
202                 if (li) incLoadIndexRef(li);
203                 sitty++;
204         }
205         cleanupOrphanedRefs();
206
207         surfaces_mutex.Unlock();
208 }
209
210 void OsdVector::removeSurface(const SurfaceVector *surf)
211 {
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);
220                         break;
221                 }
222                 itty++;
223         }
224         surfaces_mutex.Unlock();
225
226 }
227
228 void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )
229 {
230
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);
238                 sitty++;
239         }
240 }
241
242 void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )
243 {
244         list<SVGCommand>::iterator sitty=commands.begin();
245         while (sitty!=commands.end())
246         {
247                 incStyleRef((*sitty).getRef());
248                 ImageIndex ii=(*sitty).getImageIndex();
249                 if (ii) incImageRef(ii);
250                 LoadIndex li=(*sitty).getLoadIndex();
251                 if (li) incLoadIndexRef(li);
252                 sitty++;
253         }
254 }
255
256
257 void OsdVector::incImageRef(ImageIndex index)
258 {
259         if (images_ref.find(index)==images_ref.end()) {
260                 images_ref[index]=1;
261         } else {
262                 images_ref[index]++;
263         }
264 }
265
266 void OsdVector::removeImageRef(const ImageIndex ref)
267 {
268         images_ref[ref]--;
269 }
270
271 unsigned int OsdVector::getLoadIndexRef(LoadIndex index)
272 {
273         if (loadindex_ref.find(index)==loadindex_ref.end()) {
274                 return -1;
275         } else {
276                 return loadindex_ref[index];
277         }
278 }
279
280 void OsdVector::incLoadIndexRef(LoadIndex index)
281 {
282         if (loadindex_ref.find(index)==loadindex_ref.end()) {
283                 loadindex_ref[index]=1;
284         } else {
285                 loadindex_ref[index]++;
286         }
287 }
288
289 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
290 {
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
297                 }
298                 tvmedias_loaded.erase(ref);
299                 tvmedias_load.erase(tvmedias_load_inv[ref]);
300                 tvmedias_load_inv.erase(ref);
301         }
302 }
303
304 void OsdVector::cleanupOrphanedRefs()
305 { // Do some garbage collection
306
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;
311                 if (count==0) {
312                         ImageIndex ref=(*curitty).first;
313                         monobitmaps.erase(mitty++);
314                         images_ref.erase(curitty++);
315                         destroyImageRef(ref);
316                 } else ++mitty;
317         }
318
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;
323                 if (count==0) {
324                         ImageIndex ref=(*curitty).first;
325                         jpegs.erase(jitty++);
326                         images_ref.erase(curitty++);
327                         destroyImageRef(ref);
328                 } else ++jitty;
329         }
330
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;
335                 if (count==0) {
336
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);
342                 } else ++titty;
343         }
344
345
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;
350                 if (count==0) {
351                         unsigned int ref=(*curitty).first;
352                         styles.erase(sitty++);
353                         styles_ref.erase(curitty++);
354                         destroyStyleRef(ref);
355
356                 } else ++sitty;
357
358         }
359 }
360
361
362 unsigned int OsdVector::getImageRef(ImageIndex index)
363 {
364         if (images_ref.find(index)==images_ref.end()) {
365                 return -1;
366         } else {
367                 return images_ref[index];
368         }
369 }
370
371 void OsdVector::incStyleRef(unsigned int index)
372 {
373         if (styles_ref.find(index)==styles_ref.end()) {
374                 styles_ref[index]=1;
375         } else {
376                 styles_ref[index]++;
377         }
378 }
379
380 void OsdVector::removeStyleRef(unsigned int index)
381 {
382         styles_ref[index]--;
383 }
384
385 unsigned int OsdVector::getStyleRef(const DrawStyle &c)
386 {
387         unsigned int style_handle=0;
388         if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
389         {
390                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
391         } else {
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);
397                 }
398         }
399         incStyleRef(style_handle);
400         return style_handle;
401 }
402
403 unsigned int OsdVector::getColorRef(const Colour &c)
404 {
405         unsigned int style_handle=0;
406         if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
407         {
408                 style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
409         } else {
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);
414                 }
415         }
416         incStyleRef(style_handle);
417         return style_handle;
418 }
419
420 unsigned int OsdVector::getStyleRef(unsigned int index)
421 {
422         if (styles_ref.find(index)==styles_ref.end()) {
423                 return -1;
424         } else {
425                 return styles_ref[index];
426         }
427 }
428
429 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
430 {
431         ImageIndex image_handle=0;
432         LoadIndex loadindex=0;
433         if (tvmedias.find(tvmedia)==tvmedias.end())
434         {
435                 loadindex=loadTVMedia(tvmedia);
436         } else {
437                 image_handle=tvmedias[tvmedia];
438                 if (images_ref.find(image_handle)==images_ref.end()) {
439                         //invalid handle recreate
440                         loadindex=loadTVMedia(tvmedia);
441                         image_handle=0;
442                 } else {
443                         incImageRef(image_handle);
444                 }
445         }
446         /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
447         incImageRef(image_handle);*/
448         image=image_handle;
449         return loadindex;
450 }
451
452 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
453 {
454         LoadIndex index=0;
455         if (tvmedias_load.find(tvmedia)==tvmedias_load.end())
456         {
457                 index=VDR::getInstance()->loadTVMedia(tvmedia);
458                 tvmedias_load[tvmedia]=index;
459                 tvmedias_load_inv[index]=tvmedia;
460         } else {
461                 index=tvmedias_load[tvmedia];
462         }
463
464         incLoadIndexRef(index);
465
466         return index;
467 }
468
469 void OsdVector::setTVMedia(LoadIndex index, unsigned char * buffer, unsigned int length)
470 {
471         //Beware for thread safety
472         ImageIndex image_index=0;
473
474         TVMediaInfo tvmedia=tvmedias_load_inv[index];
475           Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %d arrived",index);
476         if (buffer) {
477                 if (getLoadIndexRef(index)<1) {
478                         // we do not want the picture anymore . Really...
479                 } else {
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;
483                 }
484         }
485
486
487 }
488
489
490
491 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
492 {
493         ImageIndex image_handle=0;
494         if (jpegs.find(fileName)==jpegs.end())
495         {
496                 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
497         } else {
498                 image_handle=jpegs[fileName];
499                 *width=0;
500                 *height=0;
501                 if (images_ref.find(image_handle)==images_ref.end()) {
502                         //invalid handle recreate
503                         image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
504                 }
505         }
506         incImageRef(image_handle);
507         return image_handle;
508 }
509
510 ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
511 {
512         ImageIndex image_handle;
513         if (monobitmaps.find(base)==monobitmaps.end())
514         {
515                 image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
516         } else {
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);
521                 }
522         }
523         incImageRef(image_handle);
524         return image_handle;
525 }
526
527 ImageIndex  OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
528 {
529         ImageIndex image_handle;
530         image_handle=createImagePalette(width,height,image_data,palette_data);
531         incImageRef(image_handle);
532         return image_handle;
533 }
534
535 void OsdVector::receivePicture(VDR_ResponsePacket *vresp)
536 {
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;
545                 m->from=this;
546                 m->to=Command::getInstance();
547                 picture_update=false;
548                 Command::getInstance()->postMessageFromOuterSpace(m); // inform command about new picture
549         }
550 }
551
552 bool OsdVector::processReceivedPictures()
553 {
554         bool ret=false;
555         pict_lock_incoming.Lock();
556         int i=0;
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();
561                 pict_incoming.pop();
562                 pict_lock_incoming.Unlock();
563                 if (vresp->getFlag() != 2) {
564                         setTVMedia(vresp->getStreamID(), vresp->getUserData(),  vresp->getUserDataLength());
565                         ret=true;
566                 }
567                 else  setTVMedia(vresp->getStreamID(), NULL,  0);
568                 delete vresp;
569                 cur_time = getTimeMS();
570                 pict_lock_incoming.Lock();
571         }
572         if (pict_incoming.size()==0) picture_update=true;
573         pict_lock_incoming.Unlock();
574
575
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;
580                 m->from=this;
581                 m->to=Command::getInstance();
582                 picture_update=false;
583                 Command::getInstance()->postMessageNoLock(m); // inform command about new picture
584         }
585         return ret;
586 }