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/>.
21 #include "surfacevector.h"
23 #include "vdrresponsepacket.h"
27 #include "osdvector.h"
29 // The next section is activated, if the magick++ PictureReader is provided, it should be available for many POSIX platforms
30 #ifdef PICTURE_DECODER_MAGICK
31 #define MAGICKCORE_QUANTUM_DEPTH 16
32 #define MAGICKCORE_HDRI_ENABLE 0
35 using namespace Magick;
37 static const char* TAG = "OsdVector";
39 class MagickDecoder: public OsdVector::PictureDecoder
42 MagickDecoder(OsdVector::PictureReader* treader): OsdVector::PictureDecoder(treader) {pictInfValid = false;};
44 unsigned char* decodePicture(LoadingIndex index, unsigned char* buffer, unsigned int length, bool freemem);
46 bool getDecodedPicture( struct OsdVector::PictureInfo& pict_inf);
48 void freeReference(void* ref);
51 OsdVector::PictureInfo pictInf;
55 unsigned char* MagickDecoder::decodePicture(LoadingIndex index, unsigned char* buffer, unsigned int length, bool freemem)
57 if (pictInfValid) return buffer; // does support only one image at a Time;
60 Blob* imageblob = new Blob();
65 LogNT::getInstance()->debug("MagickDecoder", "decodePicture");
67 if (freemem) myblob.updateNoCopy(buffer, length, Blob::MallocAllocator);
68 else myblob.update(buffer, length);
70 magicimage.read(myblob);
72 magicimage.write(imageblob, "RGBA");
75 catch ( Exception& error_ )
77 LogNT::getInstance()->debug("MagickDecoder", "Libmagick: {}", error_.what());
79 LogNT::getInstance()->debug("MagickDecoder", "Libmagick: error mark2");
80 unsigned char* newbuffer = (unsigned char*) malloc(length);
81 memcpy(newbuffer, myblob.data(), length);
85 pictInf.reference = (void*) imageblob;
86 pictInf.width = magicimage.columns();
87 pictInf.height = magicimage.rows();
88 pictInf.image = imageblob->data();
89 pictInf.decoder = this;
90 pictInf.type = OsdVector::PictureInfo::RGBAMemBlock;
91 pictInf.lindex = index;
96 // I can handle everything, so the return value is always true
99 void MagickDecoder::freeReference(void* ref)
101 Blob* todelete = (Blob*) ref;
105 bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
107 if (!pictInfValid) return false;
110 pictInfValid = false;
117 OsdVector::OsdVector()
119 logger = LogNT::getInstance();
121 setlocale(LC_CTYPE, "C.UTF-8");
122 #ifdef PICTURE_DECODER_MAGICK
123 reader.addDecoder(new MagickDecoder(&reader));
125 MessageQueue::getInstance()->addReceiver(this);
128 OsdVector::~OsdVector()
130 MessageQueue::getInstance()->removeReceiver(this);
133 bool OsdVector::screenShot(const char* fileName)
135 //Do nothing, if no libmagick is there
136 #ifdef PICTURE_DECODER_MAGICK
138 getRealScreenSize(width, height);
139 size_t length = width * height * 4;
140 void* mem = malloc(length);
146 if (!screenShotInternal(mem, width, height, true))
148 logger->debug(TAG, "Screenshot failed!");
153 myblob.updateNoCopy(mem, length, Blob::MallocAllocator);
154 Image image(myblob, Geometry(width, height), 8, "RGBA");
155 image.write(fileName);
157 catch ( Exception& error_ )
159 logger->debug("MagickEncoder", "Libmagick: {}", error_.what());
168 Surface* OsdVector::createNewSurface()
170 return new SurfaceVector(this);
173 void OsdVector::Blank()
175 // FIXME do nothing? remove this one?
178 int OsdVector::restore()
180 // First clear the contents of all registered surfaces
181 surfaces_mutex.lock();
183 //Now go through all surfaces and clear them
184 for (auto& surface : surfaces)
186 surface.commands.clear();
187 surface.commands.reserve(2048);
190 //also clear all handles, they are now invalid, no need to release them
191 vhi_refcounts.clear();
194 drawstyleHandles.clear();
195 drawstyleHandlesRefCounts.clear();
196 drawstyleHandles_lastit_valid = drawstyleHandlesRefCounts_lastit_valid = false;
200 loadindex_ref.clear();
201 tvmedias_load.clear();
202 tvmedias_load_inv.clear();
203 tvmedias_loaded.clear();
205 surfaces_mutex.unlock();
209 void OsdVector::drawSurfaces()
211 surfaces_mutex.lock();
212 std::list<SurfaceInfo*> todraw; //First figure out if a surfaces is below another surface
213 std::list<SurfaceInfo>::iterator itty1 = surfaces.begin();
215 while (itty1 != surfaces.end())
217 std::list<SurfaceInfo>::iterator itty2 = itty1;
221 while (itty2 != surfaces.end())
223 SurfaceInfo& ref1 = *itty1;
224 SurfaceInfo& ref2 = *itty2;
226 if (ref1.x >= ref2.x && ref1.y >= ref2.y
227 && (ref1.x + ref1.w) <= (ref2.x + ref2.w)
228 && (ref1.y + ref1.h) <= (ref2.y + ref2.h) )
237 if (!hidden) // we are not hidden, perfect
239 todraw.push_back(&(*itty1));
246 getScreenSize(swidth, sheight);
247 //Now go through all surfaces and draw them
248 std::list<SurfaceInfo*>::iterator curdraw = todraw.begin();
250 while (curdraw != todraw.end())
252 drawSetTrans(*(*curdraw));
253 std::vector<SVGCommand>::iterator commands = (*(*curdraw)).commands.begin();
254 std::vector<SVGCommand>::iterator end = (*(*curdraw)).commands.end();
256 while (commands != end)
258 // update any images loaded in the mean time
259 if ((*commands).instr == DrawImageLoading)
261 LoadingIndex loadindex = (*commands).target.loadindex;
263 if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end())
265 (*commands).instr = DrawImage;
266 (*commands).target.image = tvmedias_loaded[loadindex];;
267 incImageRef((*commands).target.image);
268 removeLoadingIndexRef(loadindex);
273 // Now check if the command is on screen!
274 if (!(*commands).Outside(0, 0, swidth, sheight))
276 executeDrawCommand(*commands);
285 surfaces_mutex.unlock();
288 void OsdVector::updateOrAddSurface(const SurfaceVector* surf, float x, float y, float height, float width, std::vector<SVGCommand>& commands)
290 std::lock_guard<std::mutex> lg(surfaces_mutex);
294 logger->trace(TAG, "updateOrAddSurface, surfaces.length {}", surfaces.size());
298 // First determine it is already in our system
299 for(si = surfaces.begin(); si != surfaces.end(); si++)
301 if (si->surface == surf)
303 // If the surface given (surf) is already in our surfaces vector, reset our SurfaceInfo->commands vector
304 decrementAllRefCounts(si->commands);
305 si->commands.clear();
310 // if not found, make a new SurfaceInfo
311 if (si == surfaces.end())
314 new_sc.surface = surf;
319 si = surfaces.insert(si, new_sc);
322 // update any images loaded in the mean time
324 for (SVGCommand& command : commands)
326 if (command.instr == DrawImageLoading)
328 LoadingIndex loadindex = command.target.loadindex;
330 if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end())
332 command.instr = DrawImage;
333 command.target.image = tvmedias_loaded[loadindex];
334 incImageRef(command.target.image);
335 removeLoadingIndexRef(loadindex);
340 si->commands = commands; // Copy surf->commands to our SurfaceInfo->commands
341 incrementAllRefCounts(si->commands);
343 cleanupOrphanedRefs();
346 logger->trace(TAG, "After UOAS:");
350 // OSDOVG-ROD-EXPERIMENT
351 logger->trace(TAG, "EXPERIMENT - call doRender");
355 void OsdVector::removeSurface(const SurfaceVector* surf)
357 std::lock_guard<std::mutex> lg(surfaces_mutex); // FIXME - Can block here on shutdown if a timer is fired just as the wrong time
358 logger->trace("OsdVector-348", "EXPERIMENT - removeSurface");
359 for (auto i = surfaces.begin(); i != surfaces.end(); i++)
361 if (i->surface == surf)
363 decrementAllRefCounts(i->commands);
371 void OsdVector::decrementAllRefCounts(std::vector<SVGCommand>& commands)
373 for (SVGCommand& command : commands)
375 VectorHandle handle = command.getHandle();
376 if (handle != 0) // command might not have a handle
377 decrementDrawStyleHandleRefCount(handle);
379 VectorHandleImage imageHandle = command.getImageHandle();
380 if (imageHandle) removeImageRef(imageHandle);
382 LoadingIndex li = command.getLoadingIndex();
383 if (li) removeLoadingIndexRef(li);
387 void OsdVector::incrementAllRefCounts(std::vector<SVGCommand>& commands)
389 for (SVGCommand& command : commands)
391 VectorHandle handle = command.getHandle();
392 if (handle != 0) // command might not have a handle
393 incrementDrawStyleHandleRefCount(handle);
395 VectorHandleImage imageHandle = command.getImageHandle();
396 if (imageHandle) incImageRef(imageHandle);
398 LoadingIndex li = command.getLoadingIndex();
399 if (li) incLoadingIndexRef(li);
403 void OsdVector::incImageRef(VectorHandleImage handle)
405 if (vhi_refcounts.find(handle) == vhi_refcounts.end())
407 vhi_refcounts[handle] = 1;
411 vhi_refcounts[handle]++;
415 void OsdVector::removeImageRef(const VectorHandleImage handle)
417 vhi_refcounts[handle]--;
420 int OsdVector::getLoadingIndexRef(LoadingIndex index)
422 surfaces_mutex.lock();
424 if (loadindex_ref.find(index) == loadindex_ref.end())
430 return loadindex_ref[index];
433 surfaces_mutex.unlock();
436 void OsdVector::incLoadingIndexRef(LoadingIndex index)
438 if (loadindex_ref.find(index) == loadindex_ref.end())
440 loadindex_ref[index] = 1;
444 loadindex_ref[index]++;
448 void OsdVector::removeLoadingIndexRef(const LoadingIndex ref)
450 loadindex_ref[ref]--;
452 if (loadindex_ref[ref] == 0)
454 //now check, if it is already loaded
455 std::map<LoadingIndex, VectorHandleImage>::iterator itty = tvmedias_loaded.find(ref);
457 if ( itty != tvmedias_loaded.end())
459 // removeImageRef((*itty).second); // remove lock
461 * I'm not sure exactly how all this works but removing this line of code prevents
462 * reference counts in vhi_refcounts from going negative. Therefore I suspect the above
463 * line is wrong. Will test for a while.
467 tvmedias_loaded.erase(ref);
468 // logger->debug(TAG, "TVMedia removeLoadIndexRef {} {:#x}",tvmedias_load.size(),ref);
469 tvmedias_load.erase(tvmedias_load_inv[ref]);
470 tvmedias_load_inv.erase(ref);
472 reader.invalidateLoadingIndex(ref);
476 void OsdVector::cleanupOrphanedRefs()
478 // Do some garbage collection
480 std::map<void*, VectorHandleImage>::iterator mitty = monobitmaps.begin();
482 while (mitty != monobitmaps.end())
484 std::map<VectorHandleImage, int>::iterator curitty = vhi_refcounts.find((*mitty).second);
485 int count = (*curitty).second;
489 VectorHandleImage handle = (*curitty).first;
490 monobitmaps.erase(mitty++);
491 vhi_refcounts.erase(curitty++);
492 destroyImageRef(handle);
497 /*map<string,VectorHandleImage>::iterator jitty=jpegs.begin();
498 while (jitty!=jpegs.end()) {
499 map<VectorHandleImage,int>::iterator curitty=vhi_refcounts.find((*jitty).second);
500 int count=(*curitty).second;
502 VectorHandleImage handle=(*curitty).first;
503 jpegs.erase(jitty++);
504 vhi_refcounts.erase(curitty++);
505 destroyImageRef(handle);
509 std::map<TVMediaInfo, VectorHandleImage>::iterator titty = tvmedias.begin();
511 while (titty != tvmedias.end())
513 std::map<VectorHandleImage, int>::iterator curitty = vhi_refcounts.find((*titty).second);
514 int count = (*curitty).second;
518 VectorHandleImage handle = (*curitty).first;
519 tvmedias.erase(titty++);
520 vhi_refcounts.erase(curitty);
521 destroyImageRef(handle);
527 std::map<TVMediaInfo, LoadingIndex>::iterator litty = tvmedias_load.begin();
529 while (litty != tvmedias_load.end())
531 std::map<LoadingIndex, int>::iterator curitty = loadindex_ref.find((*litty).second);
532 int count = (*curitty).second;
536 tvmedias_load_inv.erase((*litty).second);
537 tvmedias_loaded.erase((*litty).second);
538 tvmedias_load.erase(litty++);
543 std::list<VectorHandleImage>::iterator pitty = palettepics.begin();
545 while (pitty != palettepics.end())
547 std::map<VectorHandleImage, int>::iterator curitty = vhi_refcounts.find((*pitty));
548 int count = (*curitty).second;
552 VectorHandleImage handle = (*curitty).first;
553 palettepics.erase(pitty++);
554 vhi_refcounts.erase(curitty++);
555 destroyImageRef(handle);
560 std::map<VectorHandleImage, int>::iterator citty = vhi_refcounts.begin();
562 while (citty != vhi_refcounts.end())
564 int count = (*citty).second;
568 VectorHandleImage handle = (*citty).first;
569 vhi_refcounts.erase(citty++);
570 destroyImageRef(handle);
576 std::map<DrawStyle, VectorHandle>::iterator sitty = drawstyleHandles.begin();
578 while (sitty != drawstyleHandles.end())
580 std::map<VectorHandle, int>::iterator curitty = drawstyleHandlesRefCounts.find((*sitty).second);
581 int count = (*curitty).second;
585 VectorHandle ref = (*curitty).first;
586 drawstyleHandles.erase(sitty++);
587 drawstyleHandlesRefCounts.erase(curitty++);
588 drawstyleHandles_lastit_valid = drawstyleHandlesRefCounts_lastit_valid = false;
589 destroyDrawStyleHandle(ref);
597 //int OsdVector::getImageRef(VectorHandleImage handle)
599 // surfaces_mutex.lock();
601 // if (vhi_refcounts.find(handle) == vhi_refcounts.end())
607 // return vhi_refcounts[handle];
610 // surfaces_mutex.unlock();
613 void OsdVector::incrementDrawStyleHandleRefCount(VectorHandle index)
615 if (!drawstyleHandlesRefCounts_lastit_valid || (drawstyleHandlesRefCounts_lastit->first != index))
617 drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.find(index);
618 if (drawstyleHandlesRefCounts_lastit == drawstyleHandlesRefCounts.end())
620 drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.insert(std::pair<VectorHandle, int>(index, 0)).first;
624 drawstyleHandlesRefCounts_lastit->second++;
625 drawstyleHandlesRefCounts_lastit_valid = true;
628 void OsdVector::decrementDrawStyleHandleRefCount(VectorHandle index)
630 if (!drawstyleHandlesRefCounts_lastit_valid || (drawstyleHandlesRefCounts_lastit->first != index))
632 drawstyleHandlesRefCounts_lastit_valid = false;
633 drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.find(index);
636 if (drawstyleHandlesRefCounts_lastit != drawstyleHandlesRefCounts.end())
638 drawstyleHandlesRefCounts_lastit_valid = true;
639 drawstyleHandlesRefCounts_lastit->second--;
643 VectorHandle OsdVector::getDrawStyleHandle(const DrawStyle& c)
645 surfaces_mutex.lock();
646 VectorHandle style_handle = 0;
652 if (!drawstyleHandles_lastit_valid || (drawstyleHandles_lastit->first != c))
654 drawstyleHandles_lastit_valid = false;
655 drawstyleHandles_lastit = drawstyleHandles.find(c);
658 if (drawstyleHandles_lastit == drawstyleHandles.end())
660 surfaces_mutex.unlock();
661 style_handle = createDrawStyleHandle(c);
662 surfaces_mutex.lock();
663 drawstyleHandles_lastit = drawstyleHandles.insert(std::pair<DrawStyle, VectorHandle>(c, style_handle)).first;
667 style_handle = drawstyleHandles_lastit->second;
669 //Now check if the handle is valid
670 if (!drawstyleHandlesRefCounts_lastit_valid || (*drawstyleHandlesRefCounts_lastit).first != style_handle)
672 drawstyleHandlesRefCounts_lastit_valid = false;
673 drawstyleHandlesRefCounts_lastit = drawstyleHandlesRefCounts.find(style_handle);
676 if (drawstyleHandlesRefCounts_lastit == drawstyleHandlesRefCounts.end())
678 //invalid handle recreate
679 surfaces_mutex.unlock();
680 style_handle = createDrawStyleHandle(c);
681 surfaces_mutex.lock();
682 drawstyleHandles_lastit->second = style_handle;
684 else drawstyleHandlesRefCounts_lastit_valid = true;
687 drawstyleHandles_lastit_valid = true;
688 incrementDrawStyleHandleRefCount(style_handle);
689 surfaces_mutex.unlock();
694 void OsdVector::dumpStyles()
698 std::map<DrawStyle, VectorHandle>::iterator i;
699 for(i = drawstyleHandles.begin(); i != drawstyleHandles.end(); i++)
701 const DrawStyle* test = &(i->first);
702 logger->debug(TAG, "DumpStyles: {} {}", (void*)test , i->second);
705 std::map<VectorHandle, int>::iterator i2;
706 for (i2 = drawstyleHandlesRefCounts.begin(); i2 != drawstyleHandlesRefCounts.end(); i2++)
708 logger->debug(TAG, "DumpStylesRef: {} {}", i2->first, i2->second);
713 LoadingIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, VectorHandleImage& handle)
715 VectorHandleImage localHandle = 0;
716 LoadingIndex loadindex = 0;
717 surfaces_mutex.lock();
719 if (tvmedias.find(tvmedia) == tvmedias.end()) // if not found, return a loadIndex from loadTVMedia(tvmedia)
721 loadindex = loadTVMedia(tvmedia);
723 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.
725 localHandle = tvmedias[tvmedia];
727 if (vhi_refcounts.find(localHandle) == vhi_refcounts.end())
729 //invalid handle recreate
730 loadindex = loadTVMedia(tvmedia);
735 incImageRef(localHandle);
739 /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height);
740 incImageRef(localHandle);*/
741 handle = localHandle;
742 surfaces_mutex.unlock();
746 LoadingIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia) // insert a tvmedia for loading
748 LoadingIndex index = 0;
750 if (tvmedias_load.find(tvmedia) == tvmedias_load.end()) // if not found in tvmedias_load
752 switch (tvmedia.getType())
755 index = VDR::getInstance()->loadTVMediaRecThumb(tvmedia);
760 index = ((long long) tvmedia.getPrimaryID()) << 32LL;
761 reader.addStaticImage(tvmedia.getPrimaryID());
765 index = VDR::getInstance()->loadTVMediaEventThumb(tvmedia);
769 index = VDR::getInstance()->loadChannelLogo(tvmedia);
773 index = VDR::getInstance()->loadTVMedia(tvmedia);
777 if (tvmedia.getType() != 4 && tvmedia.getStaticFallback() > -1)
779 reader.informFallback(index, tvmedia.getStaticFallback());
782 tvmedias_load[tvmedia] = index;
783 tvmedias_load_inv[index] = tvmedia;
787 index = tvmedias_load[tvmedia];
790 incLoadingIndexRef(index);
795 void OsdVector::informPicture(LoadingIndex index, VectorHandleImage handle)
797 //Beware for thread safety
798 VectorHandleImage localHandle = 0;
800 logger->debug(TAG, "TVMedia Picture for load-id {:#x} arrived index {:#x}", index, handle);
801 surfaces_mutex.lock();
802 TVMediaInfo tvmedia = tvmedias_load_inv[index];
806 std::map<LoadingIndex, int>::iterator itty = loadindex_ref.find(index);
807 localHandle = tvmedias[tvmedia] = handle;
808 tvmedias_loaded[index] = localHandle;
810 if (itty == loadindex_ref.end() || (*itty).second == 0)
812 // we do not want the picture anymore . Really...
813 // fill vhi_refcounts in to not irritate the garbage collector
814 if (vhi_refcounts.find(localHandle) == vhi_refcounts.end())
816 vhi_refcounts[localHandle] = 0;
821 incImageRef(localHandle); // hold one index until all loadings refs are gone;
825 surfaces_mutex.unlock();
827 // OSDOVG-ROD-EXPERIMENT
828 logger->trace(TAG, "EXPERIMENT - call doRender");
832 void OsdVector::processMessage(Message* m)
836 case Message::NEW_PICTURE:
838 //logger->debug(TAG, "TVMedia NEW_PICTURE");
839 informPicture(m->tag, reinterpret_cast<VectorHandleImage>(m->data));
842 case Message::NEW_PICTURE_STATIC:
844 //logger->debug(TAG, "TVMedia NEW_PICTURE {:#x} {:#x}", m->tag, m->parameter);
845 informPicture(static_cast<unsigned long long>(m->tag) << 32LL, reinterpret_cast<VectorHandleImage>(m->data));
852 VectorHandleImage OsdVector::getJpegRef(const char* fileName, int *width,int *height)
854 VectorHandleImage image_handle=0;
855 if (jpegs.find(fileName)==jpegs.end())
857 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
859 image_handle=jpegs[fileName];
862 if (vhi_refcounts.find(image_handle)==vhi_refcounts.end()) {
863 //invalid handle recreate
864 image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
867 incImageRef(image_handle);
872 VectorHandleImage OsdVector::getMonoBitmapRef(void* base, int width, int height)
874 VectorHandleImage image_handle;
875 surfaces_mutex.lock();
877 if (monobitmaps.find(base) == monobitmaps.end())
879 surfaces_mutex.unlock();
880 image_handle = createMonoBitmap(base, width, height);
881 surfaces_mutex.lock();
882 monobitmaps[base] = image_handle;
886 image_handle = monobitmaps[base];
888 if (vhi_refcounts.find(image_handle) == vhi_refcounts.end())
890 //invalid handle recreate
891 surfaces_mutex.unlock();
892 image_handle = createMonoBitmap(base, width, height);
893 surfaces_mutex.lock();
894 monobitmaps[base] = image_handle;
898 incImageRef(image_handle);
899 surfaces_mutex.unlock();
903 VectorHandleImage OsdVector::getImagePalette(int width, int height, const unsigned char* image_data, const unsigned int* palette_data)
905 VectorHandleImage image_handle;
906 image_handle = createImagePalette(width, height, image_data, palette_data);
907 surfaces_mutex.lock();
908 palettepics.push_back(image_handle);
909 incImageRef(image_handle);
910 surfaces_mutex.unlock();
914 /// PictureReader Class
916 OsdVector::PictureReader::~PictureReader()
919 if (readerThread.joinable())
921 threadReqQuit = true;
922 threadCond.notify_one();
923 threadMutex.unlock();
927 threadMutex.unlock();
930 decoders_lock.lock();
931 while (decoders.size())
933 PictureDecoder* dec = decoders.front();
934 decoders.pop_front();
937 decoders_lock.unlock();
940 void OsdVector::PictureReader::init()
943 readerThread = std::thread( [this]
946 threadMutex.unlock();
949 threadMutex.unlock();
952 void OsdVector::PictureReader::shutdown()
954 std::unique_lock<std::mutex> lg(threadMutex);
956 if (readerThread.joinable())
958 threadReqQuit = true;
959 threadCond.notify_one();
965 void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
967 decoders_lock.lock();
969 decoders.push_front(decoder);
970 decoders_lock.unlock();
973 void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder)
975 decoders_lock.lock();
976 std::list<PictureDecoder*>::iterator itty = decoders.begin();
978 while (itty != decoders.end())
980 if ((*itty) == decoder)
982 decoders.erase(itty);
989 LogNT::getInstance()->debug(TAG, "removeDecoder");
992 decoders_lock.unlock();
995 void OsdVector::PictureReader::threadMethod()
997 OsdVector* osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
998 // LogNT::getInstance()->debug("PictureReader", "TVMedia Start Picture Reader");
1000 std::unique_lock<std::mutex> ul(threadMutex); // locked
1004 threadCond.wait(ul, [this]{ return threadReqQuit || runLoop; });
1006 if (threadReqQuit) return; // unlock
1007 // LogNT::getInstance()->debug("PictureReader", "Running loop");
1011 // unlocked while we work
1016 miniRunAgain = false;
1018 PictureInfo pictinf;
1019 decoders_lock.lock();
1020 std::list<PictureDecoder*>::iterator itty = decoders.begin();
1022 while (itty != decoders.end())
1024 if ((*itty)->getDecodedPicture(pictinf)) // FIXME somewhere around here?, or in getDecodedPicture, try SA optimisation
1026 miniRunAgain = true;
1027 osdvector->createPicture(pictinf);
1032 if (processReceivedPictures()) miniRunAgain = true;
1033 decoders_lock.unlock();
1035 // LogNT::getInstance()->debug("PictureReader", "miniRunAgain = true...");
1037 } while(miniRunAgain);
1043 void OsdVector::PictureReader::invalidateLoadingIndex(LoadingIndex index)
1045 pict_lock_incoming.lock();
1046 invalid_loadindex.insert(index);
1047 pict_lock_incoming.unlock();
1049 // From conversion to std::thread
1050 // The thread used to spin every 10ms, now it only waits on the cond
1051 // This method does not signal the main thread, does it need to now?
1052 // Doesn't look like it, but if it does get the 4 lines below
1055 void OsdVector::PictureReader::informFallback(LoadingIndex index, int fallback)
1057 pict_lock_incoming.lock();
1058 inform_fallback[index] = fallback;
1059 pict_lock_incoming.unlock();
1060 // Also here, does this need to signal the thread?
1063 void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket* vresp)
1065 pict_lock_incoming.lock();
1066 pict_incoming.push(vresp);
1067 pict_lock_incoming.unlock();
1069 // These 4 lines to signal the thread
1072 threadCond.notify_one();
1073 threadMutex.unlock();
1076 void OsdVector::PictureReader::addStaticImage(unsigned int id)
1078 pict_lock_incoming.lock();
1079 pict_incoming_static.push(id);
1080 invalid_loadindex.erase(((long long) id) << 32LL);
1081 pict_lock_incoming.unlock();
1085 threadCond.notify_one();
1086 threadMutex.unlock();
1091 #pragma warning(disable : 4703)
1094 bool OsdVector::PictureReader::processReceivedPictures()
1096 bool decoded = false;
1098 pict_lock_incoming.lock();
1100 if (pict_incoming.size())
1102 VDR_ResponsePacket* vresp = pict_incoming.front();
1103 pict_incoming.pop();
1104 std::set<LoadingIndex>::iterator setpos = invalid_loadindex.find(vresp->getStreamID());
1106 if (setpos != invalid_loadindex.end())
1109 invalid_loadindex.erase(setpos);
1112 pict_lock_incoming.unlock();
1114 if (!valid) // we do not want it anymore skip it;
1120 // LogNT::getInstance()->debug(TAG, "TVMedia Pictures arrived VDR {:#x} {} {}",
1121 // vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag());
1122 bool decode = false;
1127 if (vresp->getFlag() != 2)
1129 userdata = vresp->getUserData();
1130 length = vresp->getUserDataLength();
1137 pict_lock_incoming.lock();
1139 if (inform_fallback.find(vresp->getStreamID()) != inform_fallback.end())
1141 fallback = inform_fallback[vresp->getStreamID()];
1144 pict_lock_incoming.unlock();
1146 if (fallback >= 0 && ((OsdVector*)Osd::getInstance())->getStaticImageData(fallback, &userdata, &length))
1155 std::list<PictureDecoder*>::iterator itty = decoders.begin();
1157 while (itty != decoders.end())
1159 userdata = (*itty)->decodePicture(vresp->getStreamID(), userdata, length, freed);
1170 if (!decoded && userdata && freed)
1176 pict_lock_incoming.lock();
1177 inform_fallback.erase(vresp->getStreamID());
1178 pict_lock_incoming.unlock();
1179 //else osd->informPicture(vresp->getStreamID(), 0);
1182 else if (pict_incoming_static.size())
1184 unsigned int static_id = pict_incoming_static.front();
1185 pict_incoming_static.pop();
1186 std::set<LoadingIndex>::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL);
1188 if (setpos != invalid_loadindex.end())
1191 invalid_loadindex.erase(setpos);
1194 pict_lock_incoming.unlock();
1196 if (!valid) // we do not want it anymore skip it;
1204 if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length))
1206 std::list<PictureDecoder*>::iterator itty = decoders.begin();
1208 while (itty != decoders.end())
1210 if (!(*itty)->decodePicture(((long long) static_id) << 32LL, userdata, length, false))
1222 pict_lock_incoming.unlock();
1225 if (pict_incoming.size() || pict_incoming_static.size()) return true;