2 Copyright 2012 Marten Richter, 2020 Chris Tallon
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, see <https://www.gnu.org/licenses/>.
20 // FIXME It doesn't seem like the LoadingIndex entries in loadindex_ref ever get deleted
23 #include "surfacevector.h"
25 #include "vdrresponsepacket.h"
29 #include "osdvector.h"
31 // The next section is activated, if the magick++ PictureReader is provided, it should be available for many POSIX platforms
32 #ifdef PICTURE_DECODER_MAGICK
33 #define MAGICKCORE_QUANTUM_DEPTH 16
34 #define MAGICKCORE_HDRI_ENABLE 0
37 using namespace Magick;
39 static const char* TAG = "OsdVector";
41 class MagickDecoder: public OsdVector::PictureDecoder
44 MagickDecoder(OsdVector::PictureReader* treader): OsdVector::PictureDecoder(treader) {pictInfValid = false;};
46 unsigned char* decodePicture(LoadingIndex index, unsigned char* buffer, unsigned int length, bool freemem);
48 bool getDecodedPicture( struct OsdVector::PictureInfo& pict_inf);
50 void freeReference(void* ref);
53 OsdVector::PictureInfo pictInf;
57 unsigned char* MagickDecoder::decodePicture(LoadingIndex index, unsigned char* buffer, unsigned int length, bool freemem)
59 if (pictInfValid) return buffer; // does support only one image at a Time;
62 Blob* imageblob = new Blob();
67 LogNT::getInstance()->debug("MagickDecoder", "decodePicture");
69 if (freemem) myblob.updateNoCopy(buffer, length, Blob::MallocAllocator);
70 else myblob.update(buffer, length);
72 magicimage.read(myblob);
74 magicimage.write(imageblob, "RGBA");
77 catch ( Exception& error_ )
79 LogNT::getInstance()->debug("MagickDecoder", "Libmagick: {}", error_.what());
81 LogNT::getInstance()->debug("MagickDecoder", "Libmagick: error mark2");
82 unsigned char* newbuffer = (unsigned char*) malloc(length);
83 memcpy(newbuffer, myblob.data(), length);
87 pictInf.reference = (void*) imageblob;
88 pictInf.width = magicimage.columns();
89 pictInf.height = magicimage.rows();
90 pictInf.image = imageblob->data();
91 pictInf.decoder = this;
92 pictInf.type = OsdVector::PictureInfo::RGBAMemBlock;
93 pictInf.lindex = index;
98 // I can handle everything, so the return value is always true
101 void MagickDecoder::freeReference(void* ref)
103 Blob* todelete = (Blob*) ref;
107 bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
109 if (!pictInfValid) return false;
112 pictInfValid = false;
119 OsdVector::OsdVector()
121 logger = LogNT::getInstance();
123 setlocale(LC_CTYPE, "C.UTF-8");
124 #ifdef PICTURE_DECODER_MAGICK
125 reader.addDecoder(new MagickDecoder(&reader));
127 MessageQueue::getInstance()->addReceiver(this);
130 OsdVector::~OsdVector()
132 MessageQueue::getInstance()->removeReceiver(this);
135 bool OsdVector::screenShot(const char* fileName)
137 //Do nothing, if no libmagick is there
138 #ifdef PICTURE_DECODER_MAGICK
140 getRealScreenSize(width, height);
141 size_t length = width * height * 4;
142 void* mem = malloc(length);
148 if (!screenShotInternal(mem, width, height, true))
150 logger->debug(TAG, "Screenshot failed!");
155 myblob.updateNoCopy(mem, length, Blob::MallocAllocator);
156 Image image(myblob, Geometry(width, height), 8, "RGBA");
157 image.write(fileName);
159 catch ( Exception& error_ )
161 logger->debug("MagickEncoder", "Libmagick: {}", error_.what());
170 Surface* OsdVector::createNewSurface()
172 return new SurfaceVector(this);
175 void OsdVector::Blank()
177 // FIXME do nothing? remove this one?
180 int OsdVector::restore()
182 // First clear the contents of all registered surfaces
183 surfaces_mutex.lock();
185 //Now go through all surfaces and clear them
186 for (auto& surface : surfaces)
188 surface.commands.clear();
189 surface.commands.reserve(2048);
192 //also clear all handles, they are now invalid, no need to release them
193 vhi_refcounts.clear();
196 drawstyleHandles.clear();
197 drawstyleHandlesRefCounts.clear();
198 drawstyleHandles_lastit_valid = drawstyleHandlesRefCounts_lastit_valid = false;
202 loadindex_ref.clear();
203 tvmedias_load.clear();
204 tvmedias_load_inv.clear();
205 tvmedias_loaded.clear();
207 surfaces_mutex.unlock();
211 void OsdVector::drawSurfaces()
213 surfaces_mutex.lock();
214 std::list<SurfaceInfo*> todraw; //First figure out if a surfaces is below another surface
215 std::list<SurfaceInfo>::iterator itty1 = surfaces.begin();
217 while (itty1 != surfaces.end())
219 std::list<SurfaceInfo>::iterator itty2 = itty1;
223 while (itty2 != surfaces.end())
225 SurfaceInfo& ref1 = *itty1;
226 SurfaceInfo& ref2 = *itty2;
228 if (ref1.x >= ref2.x && ref1.y >= ref2.y
229 && (ref1.x + ref1.w) <= (ref2.x + ref2.w)
230 && (ref1.y + ref1.h) <= (ref2.y + ref2.h) )
239 if (!hidden) // we are not hidden, perfect
241 todraw.push_back(&(*itty1));
248 getScreenSize(swidth, sheight);
249 //Now go through all surfaces and draw them
250 std::list<SurfaceInfo*>::iterator curdraw = todraw.begin();
252 while (curdraw != todraw.end())
254 drawSetTrans(*(*curdraw));
255 std::vector<SVGCommand>::iterator commands = (*(*curdraw)).commands.begin();
256 std::vector<SVGCommand>::iterator end = (*(*curdraw)).commands.end();
258 while (commands != end)
260 // update any images loaded in the mean time
261 if ((*commands).instr == DrawImageLoading)
263 LoadingIndex loadindex = (*commands).target.loadindex;
265 if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end())
267 (*commands).instr = DrawImage;
268 (*commands).target.image = tvmedias_loaded[loadindex];;
269 incImageRef((*commands).target.image);
270 removeLoadingIndexRef(loadindex);
275 // Now check if the command is on screen!
276 if (!(*commands).Outside(0, 0, swidth, sheight))
278 executeDrawCommand(*commands);
287 surfaces_mutex.unlock();
290 void OsdVector::updateOrAddSurface(const SurfaceVector* surf, float x, float y, float height, float width, std::vector<SVGCommand>& commands)
292 std::lock_guard<std::mutex> lg(surfaces_mutex);
296 logger->trace(TAG, "updateOrAddSurface, surfaces.length {}", surfaces.size());
300 // First determine it is already in our system
301 for(si = surfaces.begin(); si != surfaces.end(); si++)
303 if (si->surface == surf)
305 // If the surface given (surf) is already in our surfaces vector, reset our SurfaceInfo->commands vector
306 decrementAllRefCounts(si->commands);
307 si->commands.clear();
312 // if not found, make a new SurfaceInfo
313 if (si == surfaces.end())
316 new_sc.surface = surf;
321 si = surfaces.insert(si, new_sc);
324 // update any images loaded in the mean time
326 for (SVGCommand& command : commands)
328 if (command.instr == DrawImageLoading)
330 LoadingIndex loadindex = command.target.loadindex;
332 if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end())
334 command.instr = DrawImage;
335 command.target.image = tvmedias_loaded[loadindex];
336 incImageRef(command.target.image);
337 removeLoadingIndexRef(loadindex);
342 si->commands = commands; // Copy surf->commands to our SurfaceInfo->commands
343 incrementAllRefCounts(si->commands);
345 cleanupOrphanedRefs();
348 logger->trace(TAG, "After UOAS:");
352 // OSDOVG-ROD-EXPERIMENT
353 logger->trace(TAG, "EXPERIMENT - call doRender");
357 void OsdVector::removeSurface(const SurfaceVector* surf)
359 std::lock_guard<std::mutex> lg(surfaces_mutex); // FIXME - Can block here on shutdown if a timer is fired just as the wrong time
360 logger->trace("OsdVector-348", "EXPERIMENT - removeSurface");
361 for (auto i = surfaces.begin(); i != surfaces.end(); i++)
363 if (i->surface == surf)
365 decrementAllRefCounts(i->commands);
373 void OsdVector::decrementAllRefCounts(std::vector<SVGCommand>& commands)
375 for (SVGCommand& command : commands)
377 VectorHandle handle = command.getHandle();
378 if (handle != 0) // command might not have a handle
379 decrementDrawStyleHandleRefCount(handle);
381 VectorHandleImage imageHandle = command.getImageHandle();
382 if (imageHandle) removeImageRef(imageHandle);
384 LoadingIndex li = command.getLoadingIndex();
385 if (li) removeLoadingIndexRef(li);
389 void OsdVector::incrementAllRefCounts(std::vector<SVGCommand>& commands)
391 for (SVGCommand& command : commands)
393 VectorHandle handle = command.getHandle();
394 if (handle != 0) // command might not have a handle
395 incrementDrawStyleHandleRefCount(handle);
397 VectorHandleImage imageHandle = command.getImageHandle();
398 if (imageHandle) incImageRef(imageHandle);
400 LoadingIndex li = command.getLoadingIndex();
401 if (li) incLoadingIndexRef(li);
405 void OsdVector::incImageRef(VectorHandleImage handle)
407 if (vhi_refcounts.find(handle) == vhi_refcounts.end())
409 vhi_refcounts[handle] = 1;
413 vhi_refcounts[handle]++;
417 void OsdVector::removeImageRef(const VectorHandleImage handle)
419 vhi_refcounts[handle]--;
422 int OsdVector::getLoadingIndexRef(LoadingIndex index)
424 surfaces_mutex.lock();
426 if (loadindex_ref.find(index) == loadindex_ref.end())
432 return loadindex_ref[index];
435 surfaces_mutex.unlock();
438 void OsdVector::incLoadingIndexRef(LoadingIndex index)
440 if (loadindex_ref.find(index) == loadindex_ref.end())
442 loadindex_ref[index] = 1;
446 loadindex_ref[index]++;
450 void OsdVector::removeLoadingIndexRef(const LoadingIndex ref)
452 loadindex_ref[ref]--;
454 if (loadindex_ref[ref] == 0)
456 //now check, if it is already loaded
457 std::map<LoadingIndex, VectorHandleImage>::iterator itty = tvmedias_loaded.find(ref);
459 if ( itty != tvmedias_loaded.end())
461 removeImageRef((*itty).second); // remove lock
463 /* Update - not this? Re-enabled. */
466 * I'm not sure exactly how all this works but removing this line of code prevents
467 * reference counts in vhi_refcounts from going negative. Therefore I suspect the above
468 * line is wrong. Will test for a while.
472 tvmedias_loaded.erase(ref);
473 // logger->debug(TAG, "TVMedia removeLoadIndexRef {} {:#x}",tvmedias_load.size(),ref);
474 tvmedias_load.erase(tvmedias_load_inv[ref]);
475 tvmedias_load_inv.erase(ref);
477 reader.invalidateLoadingIndex(ref);
481 void OsdVector::dumpImages()
483 // surfaces_mutex.lock();
485 printf("tvmedias.size = %i\n", tvmedias.size());
487 printf("vhi_refcounts\n");
488 // std::map<ImageIndex, int> vhi_refcounts;
489 // ImageIndex is a VectorHandle. VectorHandle is an unsigned int
490 for(auto& a : vhi_refcounts)
492 printf("ImageIndex: %u int: %i\n", a.first, a.second);
495 printf("loadingindex_ref\n");
496 // std::map<LoadingIndex, int> loadindex_ref;
497 // LoadingIndex is a unsigned long long
498 for(auto& a : loadindex_ref)
500 printf("LoadingIndex: %llu (%llu) int: %i\n", a.first, a.first >> 32, a.second);
503 // surfaces_mutex.unlock();
506 void OsdVector::cleanupOrphanedRefs()
508 // Do some garbage collection
510 std::map<void*, VectorHandleImage>::iterator mitty = monobitmaps.begin();
512 while (mitty != monobitmaps.end())
514 std::map<VectorHandleImage, int>::iterator curitty = vhi_refcounts.find((*mitty).second);
515 int count = (*curitty).second;
519 VectorHandleImage handle = (*curitty).first;
520 monobitmaps.erase(mitty++);
521 vhi_refcounts.erase(curitty++);
522 destroyImageRef(handle);
527 /*map<string,VectorHandleImage>::iterator jitty=jpegs.begin();
528 while (jitty!=jpegs.end()) {
529 map<VectorHandleImage,int>::iterator curitty=vhi_refcounts.find((*jitty).second);
530 int count=(*curitty).second;
532 VectorHandleImage handle=(*curitty).first;
533 jpegs.erase(jitty++);
534 vhi_refcounts.erase(curitty++);
535 destroyImageRef(handle);
539 std::map<TVMediaInfo, VectorHandleImage>::iterator titty = tvmedias.begin();
541 while (titty != tvmedias.end())
543 std::map<VectorHandleImage, int>::iterator curitty = vhi_refcounts.find((*titty).second);
544 int count = (*curitty).second;
548 VectorHandleImage handle = (*curitty).first;
549 tvmedias.erase(titty++);
550 vhi_refcounts.erase(curitty);
551 destroyImageRef(handle);
557 std::map<TVMediaInfo, LoadingIndex>::iterator litty = tvmedias_load.begin();
559 while (litty != tvmedias_load.end())
561 std::map<LoadingIndex, int>::iterator curitty = loadindex_ref.find((*litty).second);
562 int count = (*curitty).second;
566 tvmedias_load_inv.erase((*litty).second);
567 tvmedias_loaded.erase((*litty).second);
568 tvmedias_load.erase(litty++);
573 std::list<VectorHandleImage>::iterator pitty = palettepics.begin();
575 while (pitty != palettepics.end())
577 std::map<VectorHandleImage, int>::iterator curitty = vhi_refcounts.find((*pitty));
578 int count = (*curitty).second;
582 VectorHandleImage handle = (*curitty).first;
583 palettepics.erase(pitty++);
584 vhi_refcounts.erase(curitty++);
585 destroyImageRef(handle);
590 std::map<VectorHandleImage, int>::iterator citty = vhi_refcounts.begin();
592 while (citty != vhi_refcounts.end())
594 int count = (*citty).second;
598 VectorHandleImage handle = (*citty).first;
599 vhi_refcounts.erase(citty++);
600 destroyImageRef(handle);
606 std::map<DrawStyle, VectorHandle>::iterator sitty = drawstyleHandles.begin();
608 while (sitty != drawstyleHandles.end())
610 std::map<VectorHandle, int>::iterator curitty = drawstyleHandlesRefCounts.find((*sitty).second);
611 int count = (*curitty).second;
615 VectorHandle ref = (*curitty).first;
616 drawstyleHandles.erase(sitty++);
617 drawstyleHandlesRefCounts.erase(curitty++);
618 drawstyleHandles_lastit_valid = drawstyleHandlesRefCounts_lastit_valid = false;
619 destroyDrawStyleHandle(ref);
627 //int OsdVector::getImageRef(VectorHandleImage handle)
629 // surfaces_mutex.lock();
631 // if (vhi_refcounts.find(handle) == vhi_refcounts.end())
637 // return vhi_refcounts[handle];
640 // surfaces_mutex.unlock();
643 void OsdVector::incrementDrawStyleHandleRefCount(VectorHandle index)
645 if (!drawstyleHandlesRefCounts_lastit_valid || (drawstyleHandlesRefCounts_lastit->first != index))
647 drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.find(index);
648 if (drawstyleHandlesRefCounts_lastit == drawstyleHandlesRefCounts.end())
650 drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.insert(std::pair<VectorHandle, int>(index, 0)).first;
654 drawstyleHandlesRefCounts_lastit->second++;
655 drawstyleHandlesRefCounts_lastit_valid = true;
658 void OsdVector::decrementDrawStyleHandleRefCount(VectorHandle index)
660 if (!drawstyleHandlesRefCounts_lastit_valid || (drawstyleHandlesRefCounts_lastit->first != index))
662 drawstyleHandlesRefCounts_lastit_valid = false;
663 drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.find(index);
666 if (drawstyleHandlesRefCounts_lastit != drawstyleHandlesRefCounts.end())
668 drawstyleHandlesRefCounts_lastit_valid = true;
669 drawstyleHandlesRefCounts_lastit->second--;
673 VectorHandle OsdVector::getDrawStyleHandle(const DrawStyle& c)
675 surfaces_mutex.lock();
676 VectorHandle style_handle = 0;
682 if (!drawstyleHandles_lastit_valid || (drawstyleHandles_lastit->first != c))
684 drawstyleHandles_lastit_valid = false;
685 drawstyleHandles_lastit = drawstyleHandles.find(c);
688 if (drawstyleHandles_lastit == drawstyleHandles.end())
690 surfaces_mutex.unlock();
691 style_handle = createDrawStyleHandle(c);
692 surfaces_mutex.lock();
693 drawstyleHandles_lastit = drawstyleHandles.insert(std::pair<DrawStyle, VectorHandle>(c, style_handle)).first;
697 style_handle = drawstyleHandles_lastit->second;
699 //Now check if the handle is valid
700 if (!drawstyleHandlesRefCounts_lastit_valid || (*drawstyleHandlesRefCounts_lastit).first != style_handle)
702 drawstyleHandlesRefCounts_lastit_valid = false;
703 drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.find(style_handle);
706 if (drawstyleHandlesRefCounts_lastit == drawstyleHandlesRefCounts.end())
708 //invalid handle recreate
709 surfaces_mutex.unlock();
710 style_handle = createDrawStyleHandle(c);
711 surfaces_mutex.lock();
712 drawstyleHandles_lastit->second = style_handle;
714 else drawstyleHandlesRefCounts_lastit_valid = true;
717 drawstyleHandles_lastit_valid = true;
718 incrementDrawStyleHandleRefCount(style_handle);
719 surfaces_mutex.unlock();
724 void OsdVector::dumpStyles()
728 std::map<DrawStyle, VectorHandle>::iterator i;
729 for(i = drawstyleHandles.begin(); i != drawstyleHandles.end(); i++)
731 const DrawStyle* test = &(i->first);
732 logger->debug(TAG, "DumpStyles: {} {}", (void*)test , i->second);
735 std::map<VectorHandle, int>::iterator i2;
736 for (i2 = drawstyleHandlesRefCounts.begin(); i2 != drawstyleHandlesRefCounts.end(); i2++)
738 logger->debug(TAG, "DumpStylesRef: {} {}", i2->first, i2->second);
743 LoadingIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, VectorHandleImage& handle)
745 VectorHandleImage localHandle = 0;
746 LoadingIndex loadindex = 0;
747 surfaces_mutex.lock();
749 if (tvmedias.find(tvmedia) == tvmedias.end()) // if not found, return a loadIndex from loadTVMedia(tvmedia)
751 loadindex = loadTVMedia(tvmedia);
753 else // if found, return a real imageIndex. incImageRef(localHandle). EXCEPT: If it's not found in vhi_refcounts (???) in which case do same as above.
755 localHandle = tvmedias[tvmedia];
757 if (vhi_refcounts.find(localHandle) == vhi_refcounts.end())
759 //invalid handle recreate
760 loadindex = loadTVMedia(tvmedia);
765 incImageRef(localHandle);
769 /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
770 incImageRef(localHandle);*/
771 handle = localHandle;
772 surfaces_mutex.unlock();
776 LoadingIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia) // insert a tvmedia for loading
778 LoadingIndex index = 0;
780 if (tvmedias_load.find(tvmedia) == tvmedias_load.end()) // if not found in tvmedias_load
782 switch (tvmedia.getType())
785 index = VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
790 index = ((long long) tvmedia.getPrimaryID()) << 32LL;
791 reader.addStaticImage(tvmedia.getPrimaryID());
795 index = VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
799 index = VDR::getInstance()->loadChannelLogo(tvmedia);
803 index = VDR::getInstance()->loadTVMedia(tvmedia);
807 if (tvmedia.getType() != 4 && tvmedia.getStaticFallback() > -1)
809 reader.informFallback(index, tvmedia.getStaticFallback());
812 tvmedias_load[tvmedia] = index;
813 tvmedias_load_inv[index] = tvmedia;
817 index = tvmedias_load[tvmedia];
820 incLoadingIndexRef(index);
825 void OsdVector::informPicture(LoadingIndex index, VectorHandleImage handle)
827 //Beware for thread safety
828 VectorHandleImage localHandle = 0;
830 logger->debug(TAG, "TVMedia Picture for load-id {:#x} arrived index {:#x}", index, handle);
831 surfaces_mutex.lock();
832 TVMediaInfo tvmedia = tvmedias_load_inv[index];
836 std::map<LoadingIndex, int>::iterator itty = loadindex_ref.find(index);
837 localHandle = tvmedias[tvmedia] = handle;
838 tvmedias_loaded[index] = localHandle;
840 if (itty == loadindex_ref.end() || (*itty).second == 0)
842 // we do not want the picture anymore . Really...
843 // fill vhi_refcounts in to not irritate the garbage collector
844 if (vhi_refcounts.find(localHandle) == vhi_refcounts.end())
846 vhi_refcounts[localHandle] = 0;
851 incImageRef(localHandle); // hold one index until all loadings refs are gone;
855 surfaces_mutex.unlock();
857 // OSDOVG-ROD-EXPERIMENT
858 logger->trace(TAG, "EXPERIMENT - call doRender");
862 void OsdVector::processMessage(Message* m)
866 case Message::NEW_PICTURE:
868 //logger->debug(TAG, "TVMedia NEW_PICTURE");
869 informPicture(m->tag, reinterpret_cast<VectorHandleImage>(m->data));
872 case Message::NEW_PICTURE_STATIC:
874 //logger->debug(TAG, "TVMedia NEW_PICTURE {:#x} {:#x}", m->tag, m->parameter);
875 informPicture(static_cast<unsigned long long>(m->tag) << 32LL, reinterpret_cast<VectorHandleImage>(m->data));
882 VectorHandleImage OsdVector::getJpegRef(const char* fileName, int *width,int *height)
884 VectorHandleImage image_handle=0;
885 if (jpegs.find(fileName)==jpegs.end())
887 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
889 image_handle=jpegs[fileName];
892 if (vhi_refcounts.find(image_handle)==vhi_refcounts.end()) {
893 //invalid handle recreate
894 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
897 incImageRef(image_handle);
902 VectorHandleImage OsdVector::getMonoBitmapRef(void* base, int width, int height)
904 VectorHandleImage image_handle;
905 surfaces_mutex.lock();
907 if (monobitmaps.find(base) == monobitmaps.end())
909 surfaces_mutex.unlock();
910 image_handle = createMonoBitmap(base, width, height);
911 surfaces_mutex.lock();
912 monobitmaps[base] = image_handle;
916 image_handle = monobitmaps[base];
918 if (vhi_refcounts.find(image_handle) == vhi_refcounts.end())
920 //invalid handle recreate
921 surfaces_mutex.unlock();
922 image_handle = createMonoBitmap(base, width, height);
923 surfaces_mutex.lock();
924 monobitmaps[base] = image_handle;
928 incImageRef(image_handle);
929 surfaces_mutex.unlock();
933 VectorHandleImage OsdVector::getImagePalette(int width, int height, const unsigned char* image_data, const unsigned int* palette_data)
935 VectorHandleImage image_handle;
936 image_handle = createImagePalette(width, height, image_data, palette_data);
937 surfaces_mutex.lock();
938 palettepics.push_back(image_handle);
939 incImageRef(image_handle);
940 surfaces_mutex.unlock();
944 /// PictureReader Class
946 OsdVector::PictureReader::~PictureReader()
949 if (readerThread.joinable())
951 threadReqQuit = true;
952 threadCond.notify_one();
953 threadMutex.unlock();
957 threadMutex.unlock();
960 decoders_lock.lock();
961 while (decoders.size())
963 PictureDecoder* dec = decoders.front();
964 decoders.pop_front();
967 decoders_lock.unlock();
970 void OsdVector::PictureReader::init()
973 readerThread = std::thread( [this]
976 threadMutex.unlock();
979 threadMutex.unlock();
982 void OsdVector::PictureReader::shutdown()
984 std::unique_lock<std::mutex> lg(threadMutex);
986 if (readerThread.joinable())
988 threadReqQuit = true;
989 threadCond.notify_one();
995 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
997 decoders_lock.lock();
999 decoders.push_front(decoder);
1000 decoders_lock.unlock();
1003 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
1005 decoders_lock.lock();
1006 std::list<PictureDecoder*>::iterator itty = decoders.begin();
1008 while (itty != decoders.end())
1010 if ((*itty) == decoder)
1012 decoders.erase(itty);
1019 LogNT::getInstance()->debug("PictureReader", "removeDecoder");
1020 decoder->shutdown();
1022 decoders_lock.unlock();
1025 void OsdVector::PictureReader::threadMethod()
1027 OsdVector* osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
1028 // LogNT::getInstance()->debug("PictureReader", "TVMedia Start Picture Reader");
1030 std::unique_lock<std::mutex> ul(threadMutex); // locked
1034 threadCond.wait(ul, [this]{ return threadReqQuit || runLoop; });
1036 if (threadReqQuit) return; // unlock
1037 // LogNT::getInstance()->debug("PictureReader", "Running loop");
1041 // unlocked while we work
1046 miniRunAgain = false;
1048 PictureInfo pictinf;
1049 decoders_lock.lock();
1050 std::list<PictureDecoder*>::iterator itty = decoders.begin();
1052 while (itty != decoders.end())
1054 if ((*itty)->getDecodedPicture(pictinf)) // FIXME somewhere around here?, or in getDecodedPicture, try SA optimisation
1056 miniRunAgain = true;
1057 osdvector->createPicture(pictinf);
1062 if (processReceivedPictures()) miniRunAgain = true;
1063 decoders_lock.unlock();
1065 // LogNT::getInstance()->debug("PictureReader", "miniRunAgain = true...");
1067 } while(miniRunAgain);
1073 void OsdVector::PictureReader::invalidateLoadingIndex(LoadingIndex index)
1075 pict_lock_incoming.lock();
1076 invalid_loadindex.insert(index);
1077 pict_lock_incoming.unlock();
1079 // From conversion to std::thread
1080 // The thread used to spin every 10ms, now it only waits on the cond
1081 // This method does not signal the main thread, does it need to now?
1082 // Doesn't look like it, but if it does get the 4 lines below
1085 void OsdVector::PictureReader::informFallback(LoadingIndex index, int fallback)
1087 pict_lock_incoming.lock();
1088 inform_fallback[index] = fallback;
1089 pict_lock_incoming.unlock();
1090 // Also here, does this need to signal the thread?
1093 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket* vresp)
1095 pict_lock_incoming.lock();
1096 pict_incoming.push(vresp);
1097 pict_lock_incoming.unlock();
1099 // These 4 lines to signal the thread
1102 threadCond.notify_one();
1103 threadMutex.unlock();
1106 void OsdVector::PictureReader::addStaticImage(unsigned int id)
1108 pict_lock_incoming.lock();
1109 pict_incoming_static.push(id);
1110 invalid_loadindex.erase(((long long) id) << 32LL);
1111 pict_lock_incoming.unlock();
1115 threadCond.notify_one();
1116 threadMutex.unlock();
1121 #pragma warning(disable : 4703)
1124 bool OsdVector::PictureReader::processReceivedPictures()
1126 bool decoded = false;
1128 pict_lock_incoming.lock();
1130 if (pict_incoming.size())
1132 VDR_ResponsePacket* vresp = pict_incoming.front();
1133 pict_incoming.pop();
1134 std::set<LoadingIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
1136 if (setpos != invalid_loadindex.end())
1139 invalid_loadindex.erase(setpos);
1142 pict_lock_incoming.unlock();
1144 if (!valid) // we do not want it anymore skip it;
1150 // LogNT::getInstance()->debug("PictureReader", "TVMedia Pictures arrived VDR {:#x} {} {}",
1151 // vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
1152 bool decode = false;
1157 if (vresp->getFlag() != 2)
1159 userdata = vresp->getUserData();
1160 length = vresp->getUserDataLength();
1167 pict_lock_incoming.lock();
1169 if (inform_fallback.find(vresp->getStreamID()) != inform_fallback.end())
1171 fallback = inform_fallback[vresp->getStreamID()];
1174 pict_lock_incoming.unlock();
1176 if (fallback >= 0 && ((OsdVector*)Osd::getInstance())->getStaticImageData(fallback, &userdata, &length))
1185 std::list<PictureDecoder*>::iterator itty = decoders.begin();
1187 while (itty != decoders.end())
1189 userdata = (*itty)->decodePicture(vresp->getStreamID(), userdata, length, freed);
1200 if (!decoded && userdata && freed)
1206 pict_lock_incoming.lock();
1207 inform_fallback.erase(vresp->getStreamID());
1208 pict_lock_incoming.unlock();
1209 //else osd->informPicture(vresp->getStreamID(), 0);
1212 else if (pict_incoming_static.size())
1214 unsigned int static_id = pict_incoming_static.front();
1215 pict_incoming_static.pop();
1216 std::set<LoadingIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
1218 if (setpos != invalid_loadindex.end())
1221 invalid_loadindex.erase(setpos);
1224 pict_lock_incoming.unlock();
1226 if (!valid) // we do not want it anymore skip it;
1234 if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
1236 std::list<PictureDecoder*>::iterator itty = decoders.begin();
1238 while (itty != decoders.end())
1240 if (!(*itty)->decodePicture(((long long) static_id) << 32LL, userdata, length, false))
1252 pict_lock_incoming.unlock();
1255 if (pict_incoming.size() || pict_incoming_static.size()) return true;