]> git.vomp.tv Git - vompclient.git/blob - osdvector.cc
OSDOpenVG: Render on demand: Fix backing out of a view render race
[vompclient.git] / osdvector.cc
1 /*
2     Copyright 2012 Marten Richter, 2020 Chris Tallon
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, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "surfacevector.h"
21 #include "vdr.h"
22 #include "vdrresponsepacket.h"
23 #include "control.h"
24 #include "message.h"
25
26 #include "osdvector.h"
27
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
30 #define MAGICKCORE_QUANTUM_DEPTH 16
31 #define MAGICKCORE_HDRI_ENABLE 0
32 #include <Magick++.h>
33
34 using namespace Magick;
35
36 class MagickDecoder: public OsdVector::PictureDecoder
37 {
38   public:
39     MagickDecoder(OsdVector::PictureReader* treader): OsdVector::PictureDecoder(treader) {pictInfValid = false;};
40
41     unsigned char* decodePicture(LoadIndex index, unsigned char* buffer, unsigned int length, bool freemem);
42
43     bool getDecodedPicture( struct OsdVector::PictureInfo& pict_inf);
44
45     void freeReference(void* ref);
46
47   protected:
48     OsdVector::PictureInfo pictInf;
49     bool pictInfValid;
50 };
51
52 unsigned char* MagickDecoder::decodePicture(LoadIndex index, unsigned char* buffer, unsigned int length, bool freemem)
53 {
54   if (pictInfValid) return buffer; // does support only one image at a Time;
55
56   Image magicimage;
57   Blob* imageblob = new Blob();
58   Blob myblob;
59
60   try
61   {
62     Log::getInstance()->log("MagickDecoder", Log::DEBUG, "decodePicture");
63
64     if (freemem) myblob.updateNoCopy(buffer, length, Blob::MallocAllocator);
65     else myblob.update(buffer, length);
66
67     magicimage.read(myblob);
68
69     magicimage.write(imageblob, "RGBA");
70
71   }
72   catch ( Exception& error_ )
73   {
74     Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: %s", error_.what());
75     delete imageblob;
76     Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: error mark2");
77     unsigned char* newbuffer = (unsigned char*) malloc(length);
78     memcpy(newbuffer, myblob.data(), length);
79     return newbuffer;
80   }
81
82   pictInf.reference = (void*) imageblob;
83   pictInf.width = magicimage.columns();
84   pictInf.height = magicimage.rows();
85   pictInf.image = imageblob->data();
86   pictInf.decoder = this;
87   pictInf.type = OsdVector::PictureInfo::RGBAMemBlock;
88   pictInf.lindex = index;
89   pictInfValid = true;
90
91
92
93   // I can handle everything, so the return value is always true
94   return NULL;
95 }
96 void MagickDecoder::freeReference(void* ref)
97 {
98   Blob* todelete = (Blob*) ref;
99   delete todelete;
100 }
101
102 bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
103 {
104   if (!pictInfValid) return false;
105
106   pict_inf = pictInf;
107   pictInfValid = false;
108   return true;
109 }
110
111
112 #endif
113
114 OsdVector::OsdVector()
115 {
116   setlocale(LC_CTYPE, "C.UTF-8");
117 #ifdef PICTURE_DECODER_MAGICK
118   reader.addDecoder(new MagickDecoder(&reader));
119 #endif
120 }
121
122 bool OsdVector::screenShot(const char* fileName)
123 {
124   //Do nothing, if no libmagick is there
125 #ifdef PICTURE_DECODER_MAGICK
126   int width, height;
127   getRealScreenSize(width, height);
128   size_t length = width * height * 4;
129   void* mem = malloc(length);
130
131   try
132   {
133     Blob myblob;
134
135     if (!screenShotInternal(mem, width, height, true))
136     {
137       Log::getInstance()->log("OsdVector", Log::DEBUG, "Screenshot failed!");
138       free(mem);
139       return false;
140     }
141
142     myblob.updateNoCopy(mem, length, Blob::MallocAllocator);
143     Image image(myblob, Geometry(width, height), 8, "RGBA");
144     image.write(fileName);
145   }
146   catch ( Exception& error_ )
147   {
148     Log::getInstance()->log("MagickEncoder", Log::DEBUG, "Libmagick: %s", error_.what());
149     return false;
150   }
151
152   return true;
153 #endif
154   return false;
155 }
156
157 Surface* OsdVector::createNewSurface()
158 {
159   return new SurfaceVector(this);
160 }
161
162 void OsdVector::Blank()
163 {
164   // do nothing? remove this one?
165 }
166
167 int OsdVector::restore()
168 {
169   // First clear the contents of all registered surfaces
170   surfaces_mutex.lock();
171
172   //Now go through all surfaces and clear them
173   for (auto& surface : surfaces)
174   {
175     surface.commands.clear();
176     surface.commands.reserve(2048);
177   }
178
179   //also clear all handles, they are now invalid, no need to release them
180   images_ref.clear();
181   monobitmaps.clear();
182   //jpegs.clear();
183   drawstyleHandles.clear();
184   drawstyleHandlesRefCounts.clear();
185   drawstyleHandles_lastit_valid = drawstyleHandlesRefCounts_lastit_valid = false;
186   palettepics.clear();
187
188   tvmedias.clear();
189   loadindex_ref.clear();
190   tvmedias_load.clear();
191   tvmedias_load_inv.clear();
192   tvmedias_loaded.clear();
193
194   surfaces_mutex.unlock();
195   return 1;
196 }
197
198 void OsdVector::drawSurfaces()
199 {
200   surfaces_mutex.lock();
201   std::list<SurfaceInfo*> todraw; //First figure out if a surfaces is below another surface
202   std::list<SurfaceInfo>::iterator itty1 = surfaces.begin();
203
204   while (itty1 != surfaces.end())
205   {
206     std::list<SurfaceInfo>::iterator itty2 = itty1;
207     itty2++;
208     bool hidden = false;
209
210     while (itty2 != surfaces.end())
211     {
212       SurfaceInfo& ref1 = *itty1;
213       SurfaceInfo& ref2 = *itty2;
214
215       if (ref1.x >= ref2.x && ref1.y >= ref2.y
216           && (ref1.x + ref1.w) <= (ref2.x + ref2.w)
217           && (ref1.y + ref1.h) <= (ref2.y + ref2.h) )
218       {
219         hidden = true;
220         break;
221       }
222
223       itty2++;
224     }
225
226     if (!hidden)   // we are not hidden, perfect
227     {
228       todraw.push_back(&(*itty1));
229     }
230
231     itty1++;
232   }
233
234   int swidth, sheight;
235   getScreenSize(swidth, sheight);
236   //Now go through all surfaces and draw them
237   std::list<SurfaceInfo*>::iterator curdraw = todraw.begin();
238
239   while (curdraw != todraw.end())
240   {
241     drawSetTrans(*(*curdraw));
242     std::vector<SVGCommand>::iterator commands = (*(*curdraw)).commands.begin();
243     std::vector<SVGCommand>::iterator end = (*(*curdraw)).commands.end();
244
245     while (commands != end)
246     {
247       // update any images loaded in the mean time
248       if ((*commands).instr == DrawImageLoading)
249       {
250         LoadIndex loadindex = (*commands).target.loadindex;
251
252         if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end())
253         {
254           (*commands).instr = DrawImage;
255           (*commands).target.image = tvmedias_loaded[loadindex];;
256           incImageRef((*commands).target.image);
257           removeLoadIndexRef(loadindex);
258         }
259
260       }
261
262       // Now check if the command is on screen!
263       if  (!(*commands).Outside(0, 0, swidth, sheight))
264       {
265         executeDrawCommand(*commands);
266       }
267
268       commands++;
269     }
270
271     curdraw++;
272   }
273
274   surfaces_mutex.unlock();
275 }
276
277 void OsdVector::updateOrAddSurface(const SurfaceVector* surf, float x, float y, float height, float width, std::vector<SVGCommand>& commands)
278 {
279   std::lock_guard<std::mutex> lg(surfaces_mutex);
280   SurfacesIterator si;
281
282   #if DEV
283   Log::getInstance()->log("OsdVector", Log::CRAZY, "updateOrAddSurface, surfaces.length %i", surfaces.size());
284   dumpStyles();
285   #endif
286
287   // First determine it is already in our system
288   for(si = surfaces.begin(); si != surfaces.end(); si++)
289   {
290     if (si->surface == surf)
291     {
292       // If the surface given (surf) is already in our surfaces vector, reset our SurfaceInfo->commands vector
293       decrementAllRefCounts(si->commands);
294       si->commands.clear();
295       break;
296     }
297   }
298
299   // if not found, make a new SurfaceInfo
300   if (si == surfaces.end())
301   {
302     SurfaceInfo new_sc;
303     new_sc.surface = surf;
304     new_sc.x = x;
305     new_sc.y = y;
306     new_sc.w = width;
307     new_sc.h = height;
308     si = surfaces.insert(si, new_sc);
309   }
310
311   // update any images loaded in the mean time
312
313   for (SVGCommand& command : commands)
314   {
315     if (command.instr == DrawImageLoading)
316     {
317       LoadIndex loadindex = command.target.loadindex;
318
319       if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end())
320       {
321         command.instr = DrawImage;
322         command.target.image = tvmedias_loaded[loadindex];
323         incImageRef(command.target.image);
324         removeLoadIndexRef(loadindex);
325       }
326     }
327   }
328
329   si->commands = commands; // Copy surf->commands to our SurfaceInfo->commands
330   incrementAllRefCounts(si->commands);
331
332   cleanupOrphanedRefs();
333
334   #if DEV
335   Log::getInstance()->log("OsdVector", Log::CRAZY, "After UOAS:");
336   dumpStyles();
337   #endif
338
339   // OSDOVG-ROD-EXPERIMENT
340   Log::getInstance()->log("OsdVector", Log::CRAZY, "EXPERIMENT - call doRender");
341   doRender();
342 }
343
344 void OsdVector::removeSurface(const SurfaceVector* surf)
345 {
346   std::lock_guard<std::mutex> lg(surfaces_mutex);                      // FIXME - Can block here on shutdown if a timer is fired just as the wrong time
347         Log::getInstance()->log("OSDVector-347", Log::CRAZY, "EXPERIMENT - removeSurface");
348   for (auto i = surfaces.begin(); i != surfaces.end(); i++)
349   {
350     if (i->surface == surf)
351     {
352       decrementAllRefCounts(i->commands);
353       i->commands.clear();
354       surfaces.erase(i);
355       return;
356     }
357   }
358 }
359
360 void OsdVector::decrementAllRefCounts(std::vector<SVGCommand>& commands)
361 {
362   for (SVGCommand& command : commands)
363   {
364     VectorHandle handle = command.getHandle();
365     if (handle != 0) // command might not have a handle
366       decrementDrawStyleHandleRefCount(handle);
367
368     ImageIndex ii = command.getImageIndex();
369     if (ii) removeImageRef(ii);
370
371     LoadIndex li = command.getLoadIndex();
372     if (li) removeLoadIndexRef(li);
373   }
374 }
375
376 void OsdVector::incrementAllRefCounts(std::vector<SVGCommand>& commands)
377 {
378   for (SVGCommand& command : commands)
379   {
380     VectorHandle handle = command.getHandle();
381     if (handle != 0) // command might not have a handle
382       incrementDrawStyleHandleRefCount(handle);
383
384     ImageIndex ii = command.getImageIndex();
385     if (ii) incImageRef(ii);
386
387     LoadIndex li = command.getLoadIndex();
388     if (li) incLoadIndexRef(li);
389   }
390 }
391
392 void OsdVector::incImageRef(ImageIndex index)
393 {
394   if (images_ref.find(index) == images_ref.end())
395   {
396     images_ref[index] = 1;
397   }
398   else
399   {
400     images_ref[index]++;
401   }
402 }
403
404 void OsdVector::removeImageRef(const ImageIndex ref)
405 {
406   images_ref[ref]--;
407 }
408
409 int OsdVector::getLoadIndexRef(LoadIndex index)
410 {
411   surfaces_mutex.lock();
412
413   if (loadindex_ref.find(index) == loadindex_ref.end())
414   {
415     return -1;
416   }
417   else
418   {
419     return loadindex_ref[index];
420   }
421
422   surfaces_mutex.unlock();
423 }
424
425 void OsdVector::incLoadIndexRef(LoadIndex index)
426 {
427   if (loadindex_ref.find(index) == loadindex_ref.end())
428   {
429     loadindex_ref[index] = 1;
430   }
431   else
432   {
433     loadindex_ref[index]++;
434   }
435 }
436
437 void OsdVector::removeLoadIndexRef(const LoadIndex ref)
438 {
439   loadindex_ref[ref]--;
440
441   if (loadindex_ref[ref] == 0)
442   {
443     //now check, if it is already loaded
444     std::map<LoadIndex, ImageIndex>::iterator itty = tvmedias_loaded.find(ref);
445
446     if ( itty != tvmedias_loaded.end())
447     {
448       removeImageRef((*itty).second); // remove lock
449     }
450
451     tvmedias_loaded.erase(ref);
452     //          Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia removeLoadIndexRef %d %llx",tvmedias_load.size(),ref);
453     tvmedias_load.erase(tvmedias_load_inv[ref]);
454     tvmedias_load_inv.erase(ref);
455
456     reader.invalidateLoadIndex(ref);
457   }
458 }
459
460 void OsdVector::cleanupOrphanedRefs()
461 {
462   // Do some garbage collection
463
464   std::map<void*, ImageIndex>::iterator mitty = monobitmaps.begin();
465
466   while (mitty != monobitmaps.end())
467   {
468     std::map<ImageIndex, int>::iterator curitty = images_ref.find((*mitty).second);
469     int count = (*curitty).second;
470
471     if (count == 0)
472     {
473       ImageIndex ref = (*curitty).first;
474       monobitmaps.erase(mitty++);
475       images_ref.erase(curitty++);
476       destroyImageRef(ref);
477     }
478     else ++mitty;
479   }
480
481   /*map<string,ImageIndex>::iterator jitty=jpegs.begin();
482   while (jitty!=jpegs.end()) {
483         map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
484         int count=(*curitty).second;
485         if (count==0) {
486                 ImageIndex ref=(*curitty).first;
487                 jpegs.erase(jitty++);
488                 images_ref.erase(curitty++);
489                 destroyImageRef(ref);
490         } else ++jitty;
491   }*/
492
493   std::map<TVMediaInfo, ImageIndex>::iterator titty = tvmedias.begin();
494
495   while (titty != tvmedias.end())
496   {
497     std::map<ImageIndex, int>::iterator curitty = images_ref.find((*titty).second);
498     int count = (*curitty).second;
499
500     if (count == 0)
501     {
502       ImageIndex ref = (*curitty).first;
503       tvmedias.erase(titty++);
504       images_ref.erase(curitty);
505       destroyImageRef(ref);
506     }
507     else ++titty;
508   }
509
510
511   std::map<TVMediaInfo, LoadIndex>::iterator litty = tvmedias_load.begin();
512
513   while (litty != tvmedias_load.end())
514   {
515     std::map<LoadIndex, int>::iterator curitty = loadindex_ref.find((*litty).second);
516     int count = (*curitty).second;
517
518     if (count == 0)
519     {
520       tvmedias_load_inv.erase((*litty).second);
521       tvmedias_loaded.erase((*litty).second);
522       tvmedias_load.erase(litty++);
523     }
524     else ++litty;
525   }
526
527   std::list<ImageIndex>::iterator pitty = palettepics.begin();
528
529   while (pitty != palettepics.end())
530   {
531     std::map<ImageIndex, int>::iterator curitty = images_ref.find((*pitty));
532     int count = (*curitty).second;
533
534     if (count == 0)
535     {
536       ImageIndex ref = (*curitty).first;
537       palettepics.erase(pitty++);
538       images_ref.erase(curitty++);
539       destroyImageRef(ref);
540     }
541     else ++pitty;
542   }
543
544   std::map<ImageIndex, int>::iterator citty = images_ref.begin();
545
546   while (citty != images_ref.end())
547   {
548     int count = (*citty).second;
549
550     if (count == 0)
551     {
552       ImageIndex ref = (*citty).first;
553       images_ref.erase(citty++);
554       destroyImageRef(ref);
555     }
556     else ++citty;
557   }
558
559
560   std::map<DrawStyle, VectorHandle>::iterator sitty = drawstyleHandles.begin();
561
562   while (sitty != drawstyleHandles.end())
563   {
564     std::map<VectorHandle, int>::iterator curitty = drawstyleHandlesRefCounts.find((*sitty).second);
565     int count = (*curitty).second;
566
567     if (count == 0)
568     {
569       VectorHandle ref = (*curitty).first;
570       drawstyleHandles.erase(sitty++);
571       drawstyleHandlesRefCounts.erase(curitty++);
572       drawstyleHandles_lastit_valid = drawstyleHandlesRefCounts_lastit_valid = false;
573       destroyDrawStyleHandle(ref);
574
575     }
576     else ++sitty;
577
578   }
579 }
580
581 int OsdVector::getImageRef(ImageIndex index)
582 {
583   surfaces_mutex.lock();
584
585   if (images_ref.find(index) == images_ref.end())
586   {
587     return -1;
588   }
589   else
590   {
591     return images_ref[index];
592   }
593
594   surfaces_mutex.unlock();
595 }
596
597 void OsdVector::incrementDrawStyleHandleRefCount(VectorHandle index)
598 {
599   if (!drawstyleHandlesRefCounts_lastit_valid || (drawstyleHandlesRefCounts_lastit->first != index))
600   {
601     drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.find(index);
602     if (drawstyleHandlesRefCounts_lastit == drawstyleHandlesRefCounts.end())
603     {
604       drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.insert(std::pair<VectorHandle, int>(index, 0)).first;
605     }
606   }
607
608   drawstyleHandlesRefCounts_lastit->second++;
609   drawstyleHandlesRefCounts_lastit_valid = true;
610 }
611
612 void OsdVector::decrementDrawStyleHandleRefCount(VectorHandle index)
613 {
614   if (!drawstyleHandlesRefCounts_lastit_valid || (drawstyleHandlesRefCounts_lastit->first != index))
615   {
616     drawstyleHandlesRefCounts_lastit_valid = false;
617     drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.find(index);
618   }
619
620   if (drawstyleHandlesRefCounts_lastit != drawstyleHandlesRefCounts.end())
621   {
622     drawstyleHandlesRefCounts_lastit_valid = true;
623     drawstyleHandlesRefCounts_lastit->second--;
624   }
625 }
626
627 VectorHandle OsdVector::getDrawStyleHandle(const DrawStyle& c)
628 {
629   surfaces_mutex.lock();
630   VectorHandle style_handle = 0;
631
632   #if DEV
633   dumpStyles();
634   #endif
635
636   if (!drawstyleHandles_lastit_valid || (drawstyleHandles_lastit->first != c))
637   {
638     drawstyleHandles_lastit_valid = false;
639     drawstyleHandles_lastit = drawstyleHandles.find(c);
640   }
641
642   if (drawstyleHandles_lastit == drawstyleHandles.end())
643   {
644     surfaces_mutex.unlock();
645     style_handle = createDrawStyleHandle(c);
646     surfaces_mutex.lock();
647     drawstyleHandles_lastit = drawstyleHandles.insert(std::pair<DrawStyle, VectorHandle>(c, style_handle)).first;
648   }
649   else
650   {
651     style_handle = drawstyleHandles_lastit->second;
652
653     //Now check if the handle is valid
654     if (!drawstyleHandlesRefCounts_lastit_valid || (*drawstyleHandlesRefCounts_lastit).first != style_handle)
655     {
656       drawstyleHandlesRefCounts_lastit_valid = false;
657       drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.find(style_handle);
658     }
659
660     if (drawstyleHandlesRefCounts_lastit == drawstyleHandlesRefCounts.end())
661     {
662       //invalid handle recreate
663       surfaces_mutex.unlock();
664       style_handle = createDrawStyleHandle(c);
665       surfaces_mutex.lock();
666       drawstyleHandles_lastit->second = style_handle;
667     }
668     else drawstyleHandlesRefCounts_lastit_valid = true;
669   }
670
671   drawstyleHandles_lastit_valid = true;
672   incrementDrawStyleHandleRefCount(style_handle);
673   surfaces_mutex.unlock();
674   return style_handle;
675 }
676
677 #if DEV
678 void OsdVector::dumpStyles()
679 {
680   return;
681
682   std::map<DrawStyle, VectorHandle>::iterator i;
683   for(i = drawstyleHandles.begin(); i != drawstyleHandles.end(); i++)
684   {
685     const DrawStyle* test = &(i->first);
686     Log::getInstance()->log("OsdVector", Log::DEBUG, "DumpStyles: %p %i", test , i->second);
687   }
688
689   std::map<VectorHandle, int>::iterator i2;
690   for (i2 = drawstyleHandlesRefCounts.begin(); i2 != drawstyleHandlesRefCounts.end(); i2++)
691   {
692     Log::getInstance()->log("OsdVector", Log::DEBUG, "DumpStylesRef: %i %i", i2->first, i2->second);
693   }
694 }
695 #endif
696
697 LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image)
698 {
699   ImageIndex image_handle = 0;
700   LoadIndex loadindex = 0;
701   surfaces_mutex.lock();
702
703   if (tvmedias.find(tvmedia) == tvmedias.end())
704   {
705     loadindex = loadTVMedia(tvmedia);
706   }
707   else
708   {
709     image_handle = tvmedias[tvmedia];
710
711     if (images_ref.find(image_handle) == images_ref.end())
712     {
713       //invalid handle recreate
714       loadindex = loadTVMedia(tvmedia);
715       image_handle = 0;
716     }
717     else
718     {
719       incImageRef(image_handle);
720     }
721   }
722
723   /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
724   incImageRef(image_handle);*/
725   image = image_handle;
726   surfaces_mutex.unlock();
727   return loadindex;
728 }
729
730 LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia)
731 {
732   LoadIndex index = 0;
733
734   if (tvmedias_load.find(tvmedia) == tvmedias_load.end())
735   {
736     switch (tvmedia.getType())
737     {
738       case 3:
739         index = VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
740         break;
741
742       case 4:
743       {
744         index = ((long long) tvmedia.getPrimaryID()) << 32LL;
745         reader.addStaticImage(tvmedia.getPrimaryID());
746       } break;
747
748       case 5:
749         index = VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
750         break;
751
752       case 6:
753         index = VDR::getInstance()->loadChannelLogo(tvmedia);
754         break;
755
756       default:
757         index = VDR::getInstance()->loadTVMedia(tvmedia);
758         break;
759     }
760
761     if (tvmedia.getType() != 4 && tvmedia.getStaticFallback() > -1)
762     {
763       reader.informFallback(index, tvmedia.getStaticFallback());
764     }
765
766     tvmedias_load[tvmedia] = index;
767     tvmedias_load_inv[index] = tvmedia;
768   }
769   else
770   {
771     index = tvmedias_load[tvmedia];
772   }
773
774   incLoadIndexRef(index);
775
776   return index;
777 }
778
779 void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
780 {
781   //Beware for thread safety
782   ImageIndex image_index = 0;
783
784   Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %llx arrived %x", index, imageIndex);
785   surfaces_mutex.lock();
786   TVMediaInfo tvmedia = tvmedias_load_inv[index];
787
788   if (imageIndex)
789   {
790     std::map<LoadIndex, int>::iterator itty = loadindex_ref.find(index);
791     image_index = tvmedias[tvmedia] = imageIndex;
792     tvmedias_loaded[index] = image_index;
793
794     if (itty == loadindex_ref.end() || (*itty).second == 0)
795     {
796       // we do not want the picture anymore . Really...
797       // fill images_ref in to not irritate the garbage collector
798       if (images_ref.find(image_index) == images_ref.end())
799       {
800         images_ref[image_index] = 0;
801       }
802     }
803     else
804     {
805       incImageRef(image_index); // hold one index until all loadings refs are gone;
806     }
807   }
808
809   surfaces_mutex.unlock();
810 }
811
812 /*
813 ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
814 {
815         ImageIndex image_handle=0;
816         if (jpegs.find(fileName)==jpegs.end())
817         {
818                 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
819         } else {
820                 image_handle=jpegs[fileName];
821                 *width=0;
822                 *height=0;
823                 if (images_ref.find(image_handle)==images_ref.end()) {
824                         //invalid handle recreate
825                         image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
826                 }
827         }
828         incImageRef(image_handle);
829         return image_handle;
830 }
831 */
832
833 ImageIndex OsdVector::getMonoBitmapRef(void* base, int width, int height)
834 {
835   ImageIndex image_handle;
836   surfaces_mutex.lock();
837
838   if (monobitmaps.find(base) == monobitmaps.end())
839   {
840     surfaces_mutex.unlock();
841     image_handle = createMonoBitmap(base, width, height);
842     surfaces_mutex.lock();
843     monobitmaps[base] = image_handle;
844   }
845   else
846   {
847     image_handle = monobitmaps[base];
848
849     if (images_ref.find(image_handle) == images_ref.end())
850     {
851       //invalid handle recreate
852       surfaces_mutex.unlock();
853       image_handle = createMonoBitmap(base, width, height);
854       surfaces_mutex.lock();
855       monobitmaps[base] = image_handle;
856     }
857   }
858
859   incImageRef(image_handle);
860   surfaces_mutex.unlock();
861   return image_handle;
862 }
863
864 ImageIndex OsdVector::getImagePalette(int width, int height, const unsigned char* image_data, const unsigned int* palette_data)
865 {
866   ImageIndex image_handle;
867   image_handle = createImagePalette(width, height, image_data, palette_data);
868   surfaces_mutex.lock();
869   palettepics.push_back(image_handle);
870   incImageRef(image_handle);
871   surfaces_mutex.unlock();
872   return image_handle;
873 }
874
875 /// PictureReader Class
876
877 OsdVector::PictureReader::~PictureReader()
878 {
879   decoders_lock.lock();
880
881   while (decoders.size())
882   {
883     PictureDecoder* dec = decoders.front();
884     decoders.pop_front();
885     delete dec;
886   }
887
888   decoders_lock.unlock();
889 }
890
891 void OsdVector::PictureReader::init()
892 {
893   threadStart();
894 }
895
896 void OsdVector::PictureReader::shutdown()
897 {
898   threadStop();
899 }
900
901 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
902 {
903   decoders_lock.lock();
904   decoder->init();
905   decoders.push_front(decoder);
906   decoders_lock.unlock();
907 }
908
909 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
910 {
911   decoders_lock.lock();
912   std::list<PictureDecoder*>::iterator itty = decoders.begin();
913
914   while (itty != decoders.end())
915   {
916     if ((*itty) == decoder)
917     {
918       decoders.erase(itty);
919       break;
920     }
921
922     itty++;
923   }
924
925   Log::getInstance()->log("OsdVector", Log::DEBUG, "removeDecoder");
926   decoder->shutdown();
927   delete decoder;
928   decoders_lock.unlock();
929 }
930
931 void OsdVector::PictureReader::threadMethod()
932 {
933   OsdVector* osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
934   Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
935
936   while (true)
937   {
938     if (!threadIsActive())
939     {
940       Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
941       threadCheckExit();
942     }
943
944     bool todos = true;
945
946     while (todos)
947     {
948       todos = false;
949       PictureInfo pictinf;
950       decoders_lock.lock();
951       std::list<PictureDecoder*>::iterator itty = decoders.begin();
952
953       while (itty != decoders.end())
954       {
955         if ((*itty)->getDecodedPicture(pictinf))
956         {
957           todos = true;
958           osdvector->createPicture(pictinf);
959         }
960
961         itty++;
962       }
963
964       if (processReceivedPictures())
965       {
966         todos = true;
967       }
968
969       decoders_lock.unlock();
970     }
971
972     //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
973
974     struct timespec target_time;
975     getClockRealTime(&target_time);
976
977     target_time.tv_nsec += 1000000LL * 10;
978
979     if (target_time.tv_nsec > 999999999)
980     {
981       target_time.tv_nsec -= 1000000000L;
982       target_time.tv_sec += 1;
983     }
984
985     threadLock();
986     threadWaitForSignalTimed(&target_time);
987     threadUnlock();
988     //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
989   }
990 }
991
992 void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
993 {
994   pict_lock_incoming.lock();
995   invalid_loadindex.insert(index);
996   pict_lock_incoming.unlock();
997 }
998
999 void OsdVector::PictureReader::informFallback(LoadIndex index, int fallback)
1000 {
1001   pict_lock_incoming.lock();
1002   inform_fallback[index] = fallback;
1003   pict_lock_incoming.unlock();
1004 }
1005
1006 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket* vresp)
1007 {
1008   pict_lock_incoming.lock();
1009   pict_incoming.push(vresp);
1010   pict_lock_incoming.unlock();
1011   threadSignal();
1012 }
1013
1014
1015 void OsdVector::PictureReader::addStaticImage(unsigned int id)
1016 {
1017   pict_lock_incoming.lock();
1018   pict_incoming_static.push(id);
1019   invalid_loadindex.erase(((long long) id) << 32LL);
1020   pict_lock_incoming.unlock();
1021   threadSignal();
1022 }
1023
1024 #if WIN32
1025   // FIXME win pragma
1026   #pragma warning(disable : 4703)
1027 #endif
1028
1029 bool OsdVector::PictureReader::processReceivedPictures()
1030 {
1031   bool decoded = false;
1032   bool valid = true;
1033   pict_lock_incoming.lock();
1034
1035   if (pict_incoming.size())
1036   {
1037     VDR_ResponsePacket* vresp = pict_incoming.front();
1038     pict_incoming.pop();
1039     std::set<LoadIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
1040
1041     if (setpos != invalid_loadindex.end())
1042     {
1043       valid = false;
1044       invalid_loadindex.erase(setpos);
1045     }
1046
1047     pict_lock_incoming.unlock();
1048
1049     if (!valid)   // we do not want it anymore skip it;
1050     {
1051       delete vresp;
1052       return true;
1053     }
1054
1055     // Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived VDR %x %d %d",
1056     // vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
1057     bool decode = false;
1058     bool freed = false;
1059     UCHAR* userdata;
1060     ULONG length;
1061
1062     if (vresp->getFlag() != 2)
1063     {
1064       userdata = vresp->getUserData();
1065       length = vresp->getUserDataLength();
1066       decode = true;
1067       freed = true;
1068     }
1069     else
1070     {
1071       int fallback = -1;
1072       pict_lock_incoming.lock();
1073
1074       if (inform_fallback.find(vresp->getStreamID()) != inform_fallback.end())
1075       {
1076         fallback = inform_fallback[vresp->getStreamID()];
1077       }
1078
1079       pict_lock_incoming.unlock();
1080
1081       if (fallback >= 0 && ((OsdVector*)Osd::getInstance())->getStaticImageData(fallback, &userdata, &length))
1082       {
1083         decode = true;
1084         freed = false;
1085       }
1086     }
1087
1088     if (decode)
1089     {
1090       std::list<PictureDecoder*>::iterator itty = decoders.begin();
1091
1092       while (itty != decoders.end())
1093       {
1094         userdata = (*itty)->decodePicture(vresp->getStreamID(), userdata, length, freed);
1095
1096         if (!userdata)
1097         {
1098           decoded = true;
1099           break;
1100         }
1101
1102         itty++;
1103       }
1104
1105       if (!decoded && userdata && freed)
1106       {
1107         free(userdata);
1108       }
1109     }
1110
1111     pict_lock_incoming.lock();
1112     inform_fallback.erase(vresp->getStreamID());
1113     pict_lock_incoming.unlock();
1114     //else  osd->informPicture(vresp->getStreamID(), 0);
1115     delete vresp;
1116   }
1117   else if (pict_incoming_static.size())
1118   {
1119     unsigned int static_id = pict_incoming_static.front();
1120     pict_incoming_static.pop();
1121     std::set<LoadIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
1122
1123     if (setpos != invalid_loadindex.end())
1124     {
1125       valid = false;
1126       invalid_loadindex.erase(setpos);
1127     }
1128
1129     pict_lock_incoming.unlock();
1130
1131     if (!valid)   // we do not want it anymore skip it;
1132     {
1133       return true;
1134     }
1135
1136     UCHAR* userdata;
1137     ULONG length;
1138
1139     if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
1140     {
1141       std::list<PictureDecoder*>::iterator itty = decoders.begin();
1142
1143       while (itty != decoders.end())
1144       {
1145         if (!(*itty)->decodePicture(((long long) static_id) << 32LL, userdata, length, false))
1146         {
1147           decoded = true;
1148           break;
1149         }
1150
1151         itty++;
1152       }
1153     }
1154   }
1155   else
1156   {
1157     pict_lock_incoming.unlock();
1158   }
1159
1160   if (pict_incoming.size() || pict_incoming_static.size()) return true;
1161
1162   return decoded;
1163 }