From c82a7b789794c54700e9e241ce0bfa9e72e86649 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Wed, 29 Dec 2021 18:33:32 +0000 Subject: [PATCH] Replace TVMedia & OsdVector refcounting with new Image system See image.h for details Still need regression testing --- boxstack.cc | 8 +- boxstack.h | 2 + boxx.cc | 6 +- boxx.h | 8 +- control.cc | 86 +++-- control.h | 2 + eglpicturecreator.h | 4 +- image.cc | 37 +++ image.h | 281 ++++++++++++++++ imageloader.cc | 632 +++++++++++++++++++++++++++++++++++ imageloader.h | 119 +++++++ imageomx.cc | 6 +- imageomx.h | 8 +- imageomx2.cc | 12 +- imageomx2.h | 9 +- message.h | 1 - movieinfo.cc | 24 -- movieinfo.h | 64 ++-- objects.mk | 5 +- osd.cc | 16 +- osd.h | 29 +- osdopenvg.cc | 138 ++++---- osdopenvg.h | 24 +- osdvector.cc | 680 +++----------------------------------- osdvector.h | 190 +++-------- osdvectortypes.h | 61 ++++ seriesinfo.h | 7 +- surface.h | 1 - surfacevector.cc | 42 +-- surfacevector.h | 5 +- tbboxx.cc | 19 +- tbboxx.h | 8 +- tvmedia.cc | 98 ------ tvmedia.h | 137 -------- vchannellist.cc | 33 +- vchannellist.h | 2 + vdr.cc | 477 ++++++++++++++------------ vdr.h | 15 +- vdrresponsepacket.cc | 7 +- vepg.cc | 1 + vepglistadvanced.cc | 63 ++-- vepgsummary.cc | 5 +- vopts.cc | 6 +- vrecording.cc | 6 +- vrecordinglistadvanced.cc | 29 +- vtimeredit.cc | 6 +- vtimerlist.cc | 6 +- vvideolivetv.cc | 126 +++---- vvideorec.cc | 3 +- vwelcome.cc | 43 ++- wpictureview.cc | 16 +- wpictureview.h | 11 +- wremoteconfig.h | 2 +- wselectlist.cc | 49 ++- wselectlist.h | 12 +- wtvmedia.cc | 95 +++--- wtvmedia.h | 26 +- 57 files changed, 2065 insertions(+), 1743 deletions(-) create mode 100644 image.cc create mode 100644 image.h create mode 100644 imageloader.cc create mode 100644 imageloader.h create mode 100644 osdvectortypes.h delete mode 100644 tvmedia.cc delete mode 100644 tvmedia.h diff --git a/boxstack.cc b/boxstack.cc index 9577475..afd76ef 100644 --- a/boxstack.cc +++ b/boxstack.cc @@ -1,3 +1,4 @@ + /* Copyright 2004-2020 Chris Tallon @@ -17,11 +18,12 @@ along with VOMP. If not, see . */ -#include "boxstack.h" - +#include "log.h" #include "messagequeue.h" #include "input.h" -#include "log.h" +#include "osd.h" + +#include "boxstack.h" static const char* TAG = "BoxStack"; diff --git a/boxstack.h b/boxstack.h index e930c1d..fcc36f1 100644 --- a/boxstack.h +++ b/boxstack.h @@ -34,6 +34,8 @@ typedef std::list RegionList; typedef std::stack > VideoDisplayStack; +class Osd; + class BoxStack : public MessageReceiver { public: diff --git a/boxx.cc b/boxx.cc index 3736249..d5e6342 100644 --- a/boxx.cc +++ b/boxx.cc @@ -532,13 +532,13 @@ void Boxx::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,unsig else if (surface) surface->drawMonoBitmap(base, dx,dy, height, width, nextColour); } -void Boxx::drawTVMedia(TVMediaInfo& tvmedia, float x, float y, float width, float height, Corner corner) +void Boxx::drawImage(Image& image, float x, float y, float width, float height, Corner corner) { - if (parent) parent->drawTVMedia(tvmedia, static_cast(area.x) + x, static_cast(area.y) + y, width, height, corner); + if (parent) parent->drawImage(image, static_cast(area.x) + x, static_cast(area.y) + y, width, height, corner); else if (surface) { SurfaceVector* surfacevector = dynamic_cast(surface); - if (surfacevector) surfacevector->drawTVMedia(tvmedia, x, y, width, height, corner); + if (surfacevector) surfacevector->drawImage(image, x, y, width, height, corner); else surface->fillblt(static_cast(x), static_cast(y), static_cast(width), static_cast(height), DrawStyle::RED); // Signal that something went wrong } } diff --git a/boxx.h b/boxx.h index 0c1b216..6f8f521 100644 --- a/boxx.h +++ b/boxx.h @@ -22,12 +22,14 @@ #include -#include "osdvector.h" #include "bitmap.h" #include "colour.h" #include "region.h" #include "video.h" -#include "tvmedia.h" +#include "image.h" +#include "teletextdecodervbiebu.h" + +#include "osdvectortypes.h" // FIXME Only included for enum Corner. Fix this one day. class Bitmap; class Message; @@ -111,7 +113,7 @@ class Boxx void drawBitmap(UINT x, UINT y, const Bitmap& bm, const DisplayRegion& region); //Now deprecated // void drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw=false); - void drawTVMedia(TVMediaInfo& tvmedia, float x, float y, float width, float height, Corner corner=TopLeft); + void drawImage(Image& image, float x, float y, float width, float height, Corner corner=TopLeft); void drawClippingRectangle(float x, float y, float w, float h); int getFontHeight(); diff --git a/control.cc b/control.cc index 47f6e40..d413498 100644 --- a/control.cc +++ b/control.cc @@ -62,6 +62,7 @@ #include "config.h" #include "vvideolivetv.h" #include "channel.h" +#include "imageloader.h" #ifdef VOMP_PLATFORM_RASPBERRY @@ -115,6 +116,9 @@ bool Control::init(bool tcrashed) SkinFactory::InitSkin(0); + // FIXME All constructors first which do very little & don't rely on presence of other objects. + // Then all inits. Inits retrieve pointers to other objects. + try { led = new Led_TYPE(); if (!led) throw 10; @@ -129,21 +133,24 @@ bool Control::init(bool tcrashed) audio = new Audio_TYPE(); if (!audio) throw 40; if (!audio->init(Audio::MPEG2_PES)) throw 41; - osd = new Osd_TYPE(); if (!osd) throw 50; - if (!osd->init()) throw 51; + imageLoader = new ImageLoader(); if (!imageLoader) throw 50; + if (!imageLoader->init()) throw 51; + + osd = new Osd_TYPE(); if (!osd) throw 60; + if (!osd->init()) throw 61; - vdr = new VDR(); if (!vdr) throw 60; - if (!vdr->init()) throw 61; + vdr = new VDR(); if (!vdr) throw 70; + if (!vdr->init()) throw 71; - boxstack = new BoxStack(); if (!boxstack) throw 70; - if (!boxstack->init()) throw 71; + boxstack = new BoxStack(); if (!boxstack) throw 80; + if (!boxstack->init()) throw 81; - sleepTimer = new SleepTimer(); if (!sleepTimer) throw 80; + sleepTimer = new SleepTimer(); if (!sleepTimer) throw 90; - wol = new Wol(); if (!wol) throw 90; + wol = new Wol(); if (!wol) throw 100; - inputMan = new InputMan(); if (!inputMan) throw 100; - if (!inputMan->init()) throw 101; + inputMan = new InputMan(); if (!inputMan) throw 110; + if (!inputMan->init()) throw 111; } catch (int e) @@ -156,52 +163,61 @@ bool Control::init(bool tcrashed) else if (e == 31) logger->crit(TAG, "Video module failed to initialise"); else if (e == 40) logger->crit(TAG, "Audio module failed to create"); else if (e == 41) logger->crit(TAG, "Audio module failed to initialise"); - else if (e == 50) logger->crit(TAG, "OSD module failed to create"); - else if (e == 51) logger->crit(TAG, "OSD module failed to initialise"); - else if (e == 60) logger->crit(TAG, "VDR module failed to create"); - else if (e == 61) logger->crit(TAG, "VDR module failed to initialise"); - else if (e == 70) logger->crit(TAG, "BoxStack module failed to create"); - else if (e == 71) logger->crit(TAG, "BoxStack module failed to initialise"); - else if (e == 80) logger->crit(TAG, "SleepTimer module failed to create"); - else if (e == 90) logger->crit(TAG, "WOL module failed to create"); - else if (e == 100) logger->crit(TAG, "InputMan module failed to create"); - else if (e == 101) logger->crit(TAG, "InputMan module failed to initialise"); + else if (e == 50) logger->crit(TAG, "ImageLoader module failed to create"); + else if (e == 51) logger->crit(TAG, "ImageLoader module failed to initialise"); + else if (e == 60) logger->crit(TAG, "OSD module failed to create"); + else if (e == 61) logger->crit(TAG, "OSD module failed to initialise"); + else if (e == 70) logger->crit(TAG, "VDR module failed to create"); + else if (e == 71) logger->crit(TAG, "VDR module failed to initialise"); + else if (e == 80) logger->crit(TAG, "BoxStack module failed to create"); + else if (e == 81) logger->crit(TAG, "BoxStack module failed to initialise"); + else if (e == 90) logger->crit(TAG, "SleepTimer module failed to create"); + else if (e == 100) logger->crit(TAG, "WOL module failed to create"); + else if (e == 110) logger->crit(TAG, "InputMan module failed to create"); + else if (e == 111) logger->crit(TAG, "InputMan module failed to initialise"); switch(e) { - case 101: + case 111: delete inputMan; inputMan = NULL; FALLTHROUGH - case 100: + case 110: delete wol; wol = NULL; FALLTHROUGH - case 90: + case 100: delete sleepTimer; sleepTimer = NULL; FALLTHROUGH - case 80: + case 90: boxstack->shutdown(); FALLTHROUGH - case 71: + case 81: delete boxstack; boxstack = NULL; FALLTHROUGH - case 70: + case 80: vdr->shutdown(); FALLTHROUGH - case 61: + case 71: delete vdr; vdr = NULL; FALLTHROUGH - case 60: + case 70: osd->shutdown(); FALLTHROUGH - case 51: + case 61: delete osd; osd = NULL; FALLTHROUGH + case 60: + imageLoader->shutdown(); + FALLTHROUGH + case 51: + delete imageLoader; + imageLoader = NULL; + FALLTHROUGH case 50: audio->shutdown(); FALLTHROUGH @@ -292,6 +308,14 @@ void Control::shutdown() logger->info(TAG, "OSD module shut down"); } + if (imageLoader) + { + imageLoader->shutdown(); + delete imageLoader; + imageLoader = NULL; + logger->info(TAG, "ImageLoader shut down"); + } + if (audio) { audio->shutdown(); @@ -408,8 +432,8 @@ void Control::run() inputMan->start(); -// logger->debug(TAG, "Setting log trace only mode"); -// logger->setTraceOnlyMode(true); + //logger->debug(TAG, "Setting log trace only mode"); + //logger->setTraceOnlyMode(false); messageLoopRun = true; messageLoop(); diff --git a/control.h b/control.h index 68ca368..fc0ab74 100644 --- a/control.h +++ b/control.h @@ -30,6 +30,7 @@ class VDR; class VConnect; class Message; class InputMan; +class ImageLoader; class Boxx; class BoxStack; class LogNT; @@ -79,6 +80,7 @@ class Control : public MessageQueue Video* video{}; Audio* audio{}; VDR* vdr{}; + ImageLoader* imageLoader{}; BoxStack* boxstack{}; SleepTimer* sleepTimer{}; Wol* wol{}; diff --git a/eglpicturecreator.h b/eglpicturecreator.h index ffe0556..9e38f2b 100644 --- a/eglpicturecreator.h +++ b/eglpicturecreator.h @@ -20,10 +20,12 @@ #ifndef EGLPICTURECREATOR_H #define EGLPICTURECREATOR_H +#include "osdvectortypes.h" + class EGLPictureCreator { public: - virtual bool getEGLPicture(struct OsdVector::PictureInfo& pictureInfo, EGLDisplay* display)=0; + virtual bool getEGLPicture(struct PictureInfo& pictureInfo, EGLDisplay* display)=0; }; #endif diff --git a/image.cc b/image.cc new file mode 100644 index 0000000..5e04d2b --- /dev/null +++ b/image.cc @@ -0,0 +1,37 @@ +/* + Copyright 2014 Marten Richter, 2021 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP. If not, see . +*/ + +#include "seriesinfo.h" +#include "movieinfo.h" + +#include "image.h" + +void CImageGeneric::setSeriesInfo(const SeriesInfo* si) +{ + type = 0; // movie or series + primary_id = si->id; //movie or series_id + secondary_id = si->episode.episodeid; //0 or episode id +} + +void CImageGeneric::setMovieInfo(const MovieInfo* mi) +{ + type = 1; // movie or series + primary_id = mi->id; //movie or series_id + secondary_id = 0; //0 or episode id +} diff --git a/image.h b/image.h new file mode 100644 index 0000000..f3afe5a --- /dev/null +++ b/image.h @@ -0,0 +1,281 @@ +/* + Copyright 2021 Chris Tallon + Portions Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP. If not, see . +*/ + +#ifndef IMAGE_H +#define IMAGE_H + +/* + * The new Image system, 2021. + * + * There are several image types that the client deals with: + * * Static images - these are built into the binary and are mostly small PNG icons + * * Channel logos + * * Recording thumbnails (and ones for folders) + * * Event thumbnails + * * "Generic" images loaded for the larger event display(?) + * + * The Image base class represents all these and is to be used in and around Views + * to refer to images. __An Image object (via the derived classes) describes a + * particular image to display, but does not hold actual image data__. + * + * Each Image type above has a derived class to hold information specific about that + * type of image. E.g. a recording thumbnail image stores the recording filename. + * + * Future work: Investigate removing WSymbol and all related stuff, maybe including + * the DrawBitmap stuff in OsdVector. Surely this is all there to support the very + * basic bitmap symbols - this call all be replaced with PNGs. + * + * Image objects may only be instantiated by calling a ImageLoader::create___ + * method. ImageLoader caches all existing Image objects and if an exact duplicate + * would be created by a create method then the existing Image object will be + * returned instead. This is normally done by returning a copy of the existing + * Image. However, if the request is unique but the VDR load fails, and the Image + * has a static-artwork fallback, then either: + * * The existing static-artwork is still waiting to be decoded - your Image object + * will contain Image.otherImage pointing to the first image which requested that + * static-artwork. + * * The existing static-artwork is ready - your Image object will have a normal + * OsdImage object (which will be a copy of the first one) - see later. + * + * The "Image" type is actually a shared_ptr so as many Image object + * copies can be made as necessary, there will only ever be one real CImage object + * per unique image description. + * + * OsdImages + * + * An OsdImage represents a real image held in hardware / graphics memory / whatever + * layer is actually providing graphics. Derived classes from OsdImage contain + * the real hardware handles for each type of OSD - e.g. OsdOpenVG OsdImage objects + * contain a VGImage. + * + * Tye "OsdImage" is actually a shared_ptr so as many copies can + * be made as necessary, there will only ever be one copy of the image data held + * in the real graphics layer. + * + * The link between Image objects and OsdImage objects: + * + * An Image object without a contained OsdImage object is waiting for it to be + * loaded from VDR or to be decoded locally. + * + * An Image object with an OsdImage object may have a unique OsdImage or it may + * be shared between many Image objects. ImageLoader will assign the Image an + * appropriate OsdImage when it is downloaded and/or decoded. + * + * Deletion + * + * All Image objects have their first copy in mImages in ImageLoader. All OsdImages + * have their first copy in images in Osd. OsdVector::cleanupOrphanedRefs() calls + * ImageLoader::garbageCollect() to delete Images, and it calls + * Osd::garbageCollectOsdImages() to delete OsdImages - this should be overridden + * by the actual Osd implementation e.g. OsdOpenVG as it will know how to destroy + * the underlying hardware reference. Both garbage collectors delete any Image / + * OsdImage object that has a use-count of 1 (their first/master copy). + * + * Reasons for the upgrade: + * + * The new system allows failed VDR loads to fallback to static images and to use + * pre-existing static images. This vastly speeds up the recordingslist for example, + * where VDR holds no images for recordings. + * + * Code readability - The ref-counting system in OsdVector was very manual and + * difficult to follow. This is now all handled by shared_ptrs. + * + * TVMedia objects before were deep-copied and deep-compared. Now the actual + * objects are unique and have multiple shared_ptrs for them. + * + * Should be more extendable for new Image types in future if needed. + * + * Other Osd implementations: + * + * Will need significant updating to the new system, but the hope is it should + * be simpler and more logical. +*/ + +#include +#include +#include +#include + +#include "defines.h" +#include "osd.h" + +class CImage; +class CImageStatic; +class CImageGeneric; +class CImageRecFolder; +class CImageRecThumb; +class CImageEventThumb; +class CImageChannelLogo; +using Image = std::shared_ptr; +using ImageStatic = std::shared_ptr; +using ImageGeneric = std::shared_ptr; +using ImageRecFolder = std::shared_ptr; +using ImageRecThumb = std::shared_ptr; +using ImageEventThumb = std::shared_ptr; +using ImageChannelLogo = std::shared_ptr; + +// FIXME - Is there much point having the shared_ptr system for the derived objects? +// See OsdImage which doesn't do this. + +class CImage +{ + friend class ImageLoader; + + public: + enum ImageType { INVALID, STATIC, GENERIC, RECFOLDER, RECTHUMB, EVENTTHUMB, CHANNELLOGO }; + + ImageType getType() { return type; } + bool isReady() { return ready; } + OsdImage getOsdImage() { return osdImage; } + + protected: + ImageType type{INVALID}; + + std::mutex stateLock; + bool ready{}; + bool loading{}; + bool failed{}; + bool usingFallback{}; + int staticArtworkID{-1}; + ULONG serverLoadingRef{}; + OsdImage osdImage; + Image otherImage; // If set, this image will use otherImage's osdImage when it is ready +}; + +class CImageStatic : public CImage +{ + friend class ImageLoader; +}; + +class SeriesInfo; +class MovieInfo; +class CImageGeneric : public CImage +{ + friend class ImageLoader; + friend class VDR; + + public: + void setSeriesInfo(const SeriesInfo* si); + void setMovieInfo(const MovieInfo* mi); + void setElement(int cont, int memb) { type_pict = 0; container = cont; container_member = memb; } + + private: + int primary_id{}; + int secondary_id{}; + int type{2}; // 1 = movie, 2 = series + int type_pict{-1}; // 0 full info, 1 poster thumb, 2 season thumb - OR - + // 0 full info, 1 poster, 2 poster banner, 3 poster thumb -- BUT which is true?! + int container{-1}; // indices the dataelements with picture in movieinfo or seriesinfo + int container_member{-1}; // index into the container +}; + +class CImageRecFolder : public CImage +{ + friend class ImageLoader; + + private: + std::string fileName; +}; + +class CImageRecThumb : public CImage +{ + friend class ImageLoader; + + public: + const char* getFileName() { return fileName.c_str(); } + void setServerLoadingRef(ULONG slr) { serverLoadingRef = slr; } + + private: + std::string fileName; +}; + +class CImageEventThumb : public CImage +{ + friend class ImageLoader; + + public: + ULONG getChannel() { return channel; } + ULONG getEvent() { return event; } + void setServerLoadingRef(ULONG slr) { serverLoadingRef = slr; } + private: + ULONG channel{}; + ULONG event{}; + +}; + +class CImageChannelLogo : public CImage +{ + friend class ImageLoader; + + public: + ULONG getChannelID() { return channel; } + void setServerLoadingRef(ULONG slr) { serverLoadingRef = slr; } + private: + ULONG channel{}; +}; + + +//////////////////////////////////////////////////////////////////////////////////////// + +struct TVMediaStruct // FIXME Hopefully roll this in above +{ + unsigned int width{}; + unsigned int height{}; + Image image; +}; + +struct Actor +{ + std::string name; + std::string role; + TVMediaStruct thumb; +}; + +typedef std::vector Actors; + +typedef std::vector TVMedias; + + +#endif + +/* + +Old TVMedia types information: + +0 \ +1 | - "movie or series" +2 / +3 poster thumb (char* recname) +4 static +5 poster thumb (channel, eventid) +6 channel logo + +const static ULONG VDR_LOADTVMEDIA = 41; 0,1,2 +const static ULONG VDR_LOADTVMEDIARECTHUMB = 42; 3 +const static ULONG VDR_LOADTVMEDIAEVENTTHUMB = 44; 5 +const static ULONG VDR_LOADCHANNELLOGO = 45; 6 + +Types 3, 4, 5, 6 are handled by create*() methods in ImageLoader. +Types 0, 1, 2 (though probably only 2 of these) are created with ImageLoader::createGeneric(). + +After a createGeneric() only, caller must fill the Image with more information and then call +imageLoader->ensureLoaded(image) to kick off loading the image from VDR. + +*/ diff --git a/imageloader.cc b/imageloader.cc new file mode 100644 index 0000000..2f5e322 --- /dev/null +++ b/imageloader.cc @@ -0,0 +1,632 @@ +/* + Copyright 2021 Chris Tallon + Portions Copyright 2012 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP. If not, see . +*/ + +#include "log.h" +#include "vdr.h" +#include "vdrresponsepacket.h" +#include "staticartwork.h" + +#include "imageloader.h" + +const static char* TAG = "ImageLoader"; + +ImageLoader* ImageLoader::instance = NULL; + +ImageLoader::ImageLoader() +{ + instance = this; + logger = LogNT::getInstance(); +} + +ImageLoader::~ImageLoader() +{ + instance = NULL; + + decoders_lock.lock(); + while (decoders.size()) + { + PictureDecoder* dec = decoders.front(); + decoders.pop_front(); + delete dec; + } + decoders_lock.unlock(); +} + +ImageLoader* ImageLoader::getInstance() +{ + return instance; +} + +bool ImageLoader::init() +{ + // Start picture reader thread + pictureReaderCondSigtex.lock(); // misuse condsigtex here + pictureReaderThread = std::thread( [this] + { + pictureReaderCondSigtex.lock(); + pictureReaderCondSigtex.unlock(); + pictureReaderThreadMethod(); + }); + pictureReaderCondSigtex.unlock(); + + return true; +} + +void ImageLoader::shutdown() +{ + std::unique_lock lg(pictureReaderCondSigtex); + + if (pictureReaderThread.joinable()) + { + pictureReaderThreadQuit = true; + pictureReaderThreadCond.notify_one(); + lg.unlock(); + pictureReaderThread.join(); + } +} + +void ImageLoader::addDecoder(PictureDecoder* decoder) +{ + decoders_lock.lock(); + logger->debug(TAG, "addDecoder {}", static_cast(decoder)); + decoder->init(); + decoders.push_front(decoder); + decoders_lock.unlock(); +} + +void ImageLoader::removeDecoder(PictureDecoder* decoder) +{ + decoders_lock.lock(); + std::list::iterator itty = decoders.begin(); + + while (itty != decoders.end()) + { + if ((*itty) == decoder) + { + decoders.erase(itty); + break; + } + + itty++; + } + + logger->debug(TAG, "removeDecoder"); + decoder->shutdown(); + delete decoder; + decoders_lock.unlock(); +} + +void ImageLoader::garbageCollect() +{ + mImagesLock.lock(); + auto it = std::remove_if(mImages.begin(), mImages.end(), [](Image& i) { return i.use_count() == 1; }); + mImages.erase(it, mImages.end()); + mImagesLock.unlock(); +} + +void ImageLoader::dumpImages() +{ + logger->trace(TAG, "Num Images: {}", mImages.size()); +} + +ImageStatic ImageLoader::createStatic(int sa_id) +{ + ImageStatic staticImage = std::make_shared(); + staticImage->type = CImage::STATIC; + staticImage->staticArtworkID = sa_id; + Image image = staticImage; + + mImagesLock.lock(); + mImages.push_back(image); + mImagesLock.unlock(); + + ensureLoaded(image); + return staticImage; +} + +// For the old TVMedia types 0,1,2, though I suspect one of these doesn't exist +// I think there's only SeriesInfo and MovieInfo that uses this now +ImageGeneric ImageLoader::createGeneric() +{ + ImageGeneric genericImage = std::make_shared(); + genericImage->type = CImage::GENERIC; + Image image = genericImage; + + mImagesLock.lock(); + mImages.push_back(image); + mImagesLock.unlock(); + + // Generic Images do not have ensureLoaded called on them + // It is the callers responsibility to fill the generic with + // extra information and then call ImageLoader::ensureLoaded(image) + return genericImage; +} + +// FIXME use unique_lock, lock around add as well, unlock before ensureLoaded + +ImageRecFolder ImageLoader::createRecFolder(const char* recName) +{ + // Does this image already exist? + { + std::lock_guard lg(mImagesLock); + for(Image& mImage : mImages) + { + if (mImage->type == CImage::RECFOLDER) + { + ImageRecFolder i = std::static_pointer_cast(mImage); + if (i->fileName == recName) return i; + } + } + } + + ImageRecFolder recFolderImage = std::make_shared(); + recFolderImage->type = CImage::RECFOLDER; + recFolderImage->fileName = recName; + recFolderImage->staticArtworkID = sa_recfolder; // For fallback + Image image = recFolderImage; + + mImagesLock.lock(); + mImages.push_back(image); + mImagesLock.unlock(); + + ensureLoaded(image); + return recFolderImage; +} + +ImageRecThumb ImageLoader::createRecThumb(const char* recName) +{ + // Does this image already exist? + { + std::lock_guard lg(mImagesLock); + for(Image& mImage : mImages) + { + if (mImage->type == CImage::RECTHUMB) + { + ImageRecThumb i = std::static_pointer_cast(mImage); + if (i->fileName == recName) return i; + } + } + } + + ImageRecThumb recThumbImage = std::make_shared(); + recThumbImage->type = CImage::RECTHUMB; + recThumbImage->fileName = recName; + recThumbImage->staticArtworkID = sa_recording; // For fallback + Image image = recThumbImage; + + mImagesLock.lock(); + mImages.push_back(image); + mImagesLock.unlock(); + + ensureLoaded(image); + return recThumbImage; +} + +ImageEventThumb ImageLoader::createEventThumb(ULONG channel, ULONG event) +{ + // Does this image already exist? + { + std::lock_guard lg(mImagesLock); + for(Image& mImage : mImages) + { + if (mImage->type == CImage::EVENTTHUMB) + { + ImageEventThumb i = std::static_pointer_cast(mImage); + if ((i->channel == channel) && (i->event == event)) return i; + } + } + } + + ImageEventThumb eventThumbImage = std::make_shared(); + eventThumbImage->type = CImage::EVENTTHUMB; + eventThumbImage->channel = channel; + eventThumbImage->event = event; + eventThumbImage->staticArtworkID = sa_defposter; // For fallback + Image image = eventThumbImage; + + mImagesLock.lock(); + mImages.push_back(image); + mImagesLock.unlock(); + + ensureLoaded(image); + return eventThumbImage; +} + +ImageChannelLogo ImageLoader::createChannelLogo(ULONG channel, int sa_id) +{ + // Does this image already exist? + { + std::lock_guard lg(mImagesLock); + for(Image& mImage : mImages) + { + if (mImage->type == CImage::CHANNELLOGO) + { + ImageChannelLogo i = std::static_pointer_cast(mImage); + if ((i->channel == channel) && (i->staticArtworkID == sa_id)) return i; + } + } + } + + logger->trace(TAG, "createChannelLogo said = {}", sa_id); + + ImageChannelLogo channelLogoImage = std::make_shared(); + channelLogoImage->type = CImage::CHANNELLOGO; + channelLogoImage->channel = channel; + channelLogoImage->staticArtworkID = sa_id; + + Image image = channelLogoImage; + + mImagesLock.lock(); + mImages.push_back(image); + mImagesLock.unlock(); + + ensureLoaded(image); + return channelLogoImage; +} + +void ImageLoader::ensureLoaded(ImageGeneric& ig) +{ + Image image = ig; + ensureLoaded(image); +} + +void ImageLoader::ensureLoaded(Image& image) +{ + image->stateLock.lock(); ///////// LOCK + + if (!image->ready && !image->loading) // needs loading + { + switch (image->getType()) + { + case CImage::STATIC: + { + decodeStatic(image); + break; + } + case CImage::GENERIC: + { + ImageGeneric ign = std::static_pointer_cast(image); + VDR::getInstance()->loadImageGeneric(ign); + break; + } + case CImage::RECFOLDER: + case CImage::RECTHUMB: + { + ImageRecThumb irt = std::static_pointer_cast(image); + VDR::getInstance()->loadImageRecThumb(irt); + break; + } + case CImage::EVENTTHUMB: + { + ImageEventThumb iet = std::static_pointer_cast(image); + VDR::getInstance()->loadImageEventThumb(iet); + break; + } + case CImage::CHANNELLOGO: + { + ImageChannelLogo icl = std::static_pointer_cast(image); + VDR::getInstance()->loadImageChannelLogo(icl); + break; + } + } + + image->loading = true; + } + + image->stateLock.unlock(); ///////// UNLOCK +} + +void ImageLoader::downloadDone(VDR_ResponsePacket* vresp) +{ + // This is VDR's reception thread, don't delay + // Take the incoming vresp and add it to an incoming queue. Then signal the processor thread + + // TODO reimplement index-map + + PictureReaderWorkItem p; + p.vresp = vresp; + + pictureReaderWorkLock.lock(); + pictureReaderWork.push(p); + pictureReaderWorkLock.unlock(); + + + // Now do most minimal lock & signal. Uses separate lock to the work vector. + // This split mechanism guarantees work won't be missed at the expense of possibly + // waking the thread unnecessarily. + pictureReaderCondSigtex.lock(); + pictureReaderThreadRun = true; + pictureReaderThreadCond.notify_one(); + pictureReaderCondSigtex.unlock(); +} + +bool ImageLoader::pictureRendered(LoadingIndex index, OsdImage& oimage) +{ + // This is called form OsdVector after it is notified from the actual gfx layer + // that an image has been loaded into the graphics system and is ready for use + + logger->trace(TAG, "pictureRendered: li {}", static_cast(index)); + + Image image = loadingIndexToImage(index); + + if (!image) + { + // An image has been loaded but we don't know anything about it. + // Probably a slow load for something already dropped off screen. + return false; + } + + // prob want to lock the whole thing ot update other images waiting for the same oimage + std::lock_guard lg1(mImagesLock); + + std::lock_guard lg(image->stateLock); + image->loading = false; + image->ready = true; + image->osdImage = oimage; + + logger->trace(TAG, "pictureRendered: {}", static_cast(image.get())); + + // Are there any images waiting for this one? + for(auto mImage : mImages) + { + if ((mImage->ready == false) && (mImage->otherImage == image)) + { + mImage->osdImage = image->osdImage; + mImage->loading = false; + mImage->ready = true; + // FIXME ?? Clear mImage->otherImage? + } + } + + return true; +} + +Image ImageLoader::loadingIndexToImage(LoadingIndex index) +{ + std::lock_guard lg(mImagesLock); + + for(Image& i : mImages) + { + //logger->trace(TAG, "li2I {} {}", (void*)index, (void*)i.get()); + if (i.get() == static_cast(index)) return i; + } + + // It is only possible to get to here calling from pictureRendered, but the Image + // has already been discarded (went off screen before it ever loaded) + + Image dead; + return dead; +} + +void ImageLoader::decodeStatic(Image& image) +{ + PictureReaderWorkItem p; + p.image = image; + pictureReaderWorkLock.lock(); + pictureReaderWork.push(p); + pictureReaderWorkLock.unlock(); + + // Same split as above, separate locks for vector and signal + + pictureReaderCondSigtex.lock(); + pictureReaderThreadRun = true; + pictureReaderThreadCond.notify_one(); + pictureReaderCondSigtex.unlock(); +} + + +void ImageLoader::pictureReaderThreadMethod() +{ + std::unique_lock ul(pictureReaderCondSigtex); // Lock for most minimal time + while (true) + { + pictureReaderThreadCond.wait(ul, [this]{ return pictureReaderThreadQuit || pictureReaderThreadRun; }); + // locked + if (pictureReaderThreadQuit) return; // unlock + pictureReaderThreadRun = false; + ul.unlock(); + + // unlocked while we work + + bool miniRunAgain; + do + { + miniRunAgain = false; + + PictureInfo pictinf; + decoders_lock.lock(); + std::list::iterator itty = decoders.begin(); + + while (itty != decoders.end()) + { + if ((*itty)->getDecodedPicture(pictinf)) // pictinf now contains handle (vgImage) and reference (a EGLImageKHR) + { + miniRunAgain = true; + // logger->trace(TAG, "got decoded pic {}", (void*)pictinf.lindex ); + + OsdVector* osdvector = dynamic_cast(Osd::getInstance()); // put this here, osdvector is not created yet when tihs method starts + osdvector->createPicture(pictinf); // This goes into OsdOpenVG which generates Message::NEW_PICTURE + } + itty++; + } + + pictureReaderProcessOne(); + + decoders_lock.unlock(); + + if (pictureReaderWork.size()) miniRunAgain = true; + + } while(miniRunAgain); + + ul.lock(); + } +} + +void ImageLoader::pictureReaderProcessOne() +{ + OsdVector* osdvector = dynamic_cast(Osd::getInstance()); + + pictureReaderWorkLock.lock(); + if (pictureReaderWork.empty()) + { + pictureReaderWorkLock.unlock(); + return; + } + + PictureReaderWorkItem pwi; + pwi = pictureReaderWork.front(); + pictureReaderWork.pop(); + pictureReaderWorkLock.unlock(); + + + // Either pwi has a image or a vresp. If it's a image then it's a static artwork decode + // If it's a vresp then it's a server download done + + // Set up the common variables + Image image; + bool free_it = false; + UCHAR* imageData{}; + ULONG length{}; + + + if (pwi.vresp) + { + // Now find the Image with this vresp->getStreamID() == image.serverLoadingRef + mImagesLock.lock(); + + // logger->trace(TAG, "mImages size: {}", mImages.size()); + // for(Image& i : mImages) + // { + // logger->trace(TAG, "Image said: {} {}", (void*)i.get(), i->staticArtworkID); + // } + + for(Image& i : mImages) + { + if (i->serverLoadingRef == pwi.vresp->getStreamID()) + { + image = i; + break; + } + } + mImagesLock.unlock(); + + + if (!image) + { + logger->trace(TAG, "Could not find Image for VRESP in download-done!!"); + abort(); + } + + std::lock_guard lg(image->stateLock); + + if (pwi.vresp->getFlag() != 2) // Server image success + { + imageData = pwi.vresp->getUserData(); + length = pwi.vresp->getUserDataLength(); + free_it = true; + } + else + { + image->serverLoadingRef = 0; + image->usingFallback = true; + logger->trace(TAG, "Fallback for {}", static_cast(image.get())); + } + + delete pwi.vresp; + } + else + { + image = pwi.image; + } + + // vresp is gone. Now we have a Image which might have some downloaded data + + // Before we go on, does anyone still want this image? + if (image.use_count() == 2) return; // It's only in the mImages and here + + //logger->trace(TAG, "Still needed {} {}", (void*)image.get(), image->staticArtworkID); + + // Set up a static decode? + if ( (image->getType() == CImage::STATIC) + || ((image->usingFallback == true) && (image->staticArtworkID != -1)) + ) + { + //logger->trace(TAG, "Do static {}", (void*)image.get()); + + // Do we already have this static decoded? + mImagesLock.lock(); + for(Image& i : mImages) + { + if (i == image) continue; + + //logger->trace(TAG, "Image said: {} {}", (void*)i.get(), i->staticArtworkID); + + if ( ((i->getType() == CImage::STATIC) || (i->usingFallback == true)) + && (i->staticArtworkID == image->staticArtworkID) + && (!i->otherImage) // Don't link to another image which is already linked to another image + ) + { + if (i->ready) // Link osdImage, set ready, done. + { + image->osdImage = i->osdImage; + image->ready = true; + image->loading = false; + mImagesLock.unlock(); + return; + } + else // Link to the other image file and wait for it to be ready + { + image->otherImage = i; + mImagesLock.unlock(); + return; + } + } + } + mImagesLock.unlock(); + + // Continue with a new decode + + osdvector->getStaticImageData(image->staticArtworkID, &imageData, &length); + } + + // Now decode. + + if (imageData) + { + //logger->trace(TAG, "Doing decode {}", (void*)image.get()); + + std::list::iterator it = decoders.begin(); + + while (it != decoders.end()) + { + imageData = (*it)->decodePicture(image.get(), imageData, length, free_it); + //logger->trace(TAG, "Doing decode done {} {}", (void*)image.get(), (void*) imageData); + + if (!imageData) break; + it++; + } + + if (imageData) + { + image->failed = true; + if (free_it) free(imageData); + } + } +} diff --git a/imageloader.h b/imageloader.h new file mode 100644 index 0000000..7aa206b --- /dev/null +++ b/imageloader.h @@ -0,0 +1,119 @@ +/* + Copyright 2021 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP. If not, see . +*/ + +#ifndef IMAGELOADER_H +#define IMAGELOADER_H + +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "osdvectortypes.h" +#include "osdvector.h" + +#include "image.h" + + +class LogNT; +class VDR_ResponsePacket; + +class PictureReader; +class PictureDecoder +{ + public: + PictureDecoder() {} + virtual ~PictureDecoder() {} + + // its is always guaranted, that after getDecodedPicture a call to decodePicture follows, if the return value was true; + virtual unsigned char* decodePicture(LoadingIndex index, unsigned char* buffer, unsigned int length, bool freemem = true) = 0; + + virtual bool getDecodedPicture(struct PictureInfo& pict_inf) = 0; + virtual void freeReference(void* ref) = 0; + + virtual void init() {}; + virtual void shutdown() {}; +}; + +class ImageLoader +{ + public: + ImageStatic createStatic(int sa_id); + ImageGeneric createGeneric(); + ImageRecFolder createRecFolder(const char* recFileName); + ImageRecThumb createRecThumb(const char* recFileName); + ImageEventThumb createEventThumb(ULONG channel, ULONG event); + ImageChannelLogo createChannelLogo(ULONG channel, int sa_id = -1); + + ImageLoader(); + ~ImageLoader(); + static ImageLoader* getInstance(); + + bool init(); + void shutdown(); + void ensureLoaded(Image& image); + void ensureLoaded(ImageGeneric& imageGeneric); + void decodeStatic(Image& t); + void downloadDone(VDR_ResponsePacket* vresp); + bool pictureRendered(LoadingIndex index, OsdImage& oimage); + void garbageCollect(); + + void addDecoder(PictureDecoder* decoder); + void removeDecoder(PictureDecoder* decoder); + + void dumpImages(); + + private: + static ImageLoader* instance; + + LogNT* logger{}; + + std::vector mImages; // Master vector of Image objects + std::mutex mImagesLock; + + struct PictureReaderWorkItem + { + VDR_ResponsePacket* vresp{}; + // or + Image image; + }; + + std::queue pictureReaderWork; + std::mutex pictureReaderWorkLock; + + void pictureReaderThreadMethod(); + std::mutex pictureReaderThreadMutex; + std::thread pictureReaderThread; + bool pictureReaderThreadRun{}; + bool pictureReaderThreadQuit{}; + std::condition_variable pictureReaderThreadCond; + std::mutex pictureReaderCondSigtex; // Careful with this, lock for minimal time + + std::mutex decoders_lock; + std::list decoders; + + Image loadingIndexToImage(LoadingIndex index); + void pictureReaderProcessOne(); +}; + +#endif diff --git a/imageomx.cc b/imageomx.cc index 6be066e..27d13fc 100644 --- a/imageomx.cc +++ b/imageomx.cc @@ -31,7 +31,7 @@ static const char* TAG = "ImageOMX"; -ImageOMX::ImageOMX(OsdVector::PictureReader * treader):OsdVector::PictureDecoder(treader) +ImageOMX::ImageOMX() { initted = 0; @@ -481,7 +481,7 @@ bool ImageOMX::intDecodePicture(LoadingIndex index, unsigned char* /* buffer */, pictInf.width = port_def_type.format.image.nFrameWidth; pictInf.height = port_def_type.format.image.nFrameHeight; pictInf.decoder = this; - pictInf.type = OsdVector::PictureInfo::RGBAMemBlock; + pictInf.type = PictureInfo::RGBAMemBlock; pictInf.lindex = index; @@ -646,7 +646,7 @@ bool ImageOMX::intDecodePicture(LoadingIndex index, unsigned char* /* buffer */, } -bool ImageOMX::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf) +bool ImageOMX::getDecodedPicture(struct PictureInfo& pict_inf) { if (!pictInfValid) return false; pict_inf=pictInf; diff --git a/imageomx.h b/imageomx.h index ce722aa..0fe4021 100644 --- a/imageomx.h +++ b/imageomx.h @@ -37,18 +37,18 @@ -class ImageOMX : public OsdVector::PictureDecoder +class ImageOMX : public PictureDecoder { friend class VideoOMX; public: - ImageOMX(OsdVector::PictureReader * treader); + ImageOMX(); virtual ~ImageOMX(); void init(); void shutdown(); unsigned char* decodePicture(LoadingIndex index, unsigned char * buffer, unsigned int length, bool freemem); - bool getDecodedPicture(struct OsdVector::PictureInfo& pict_inf); + bool getDecodedPicture(struct PictureInfo& pict_inf); void freeReference(void * ref); private: @@ -107,7 +107,7 @@ class ImageOMX : public OsdVector::PictureDecoder char L_VPE_OMX_EGL_REND[128]; protected: - OsdVector::PictureInfo pictInf; + PictureInfo pictInf; bool pictInfValid; }; diff --git a/imageomx2.cc b/imageomx2.cc index 2601bdf..7f1057e 100644 --- a/imageomx2.cc +++ b/imageomx2.cc @@ -17,19 +17,19 @@ along with VOMP. If not, see . */ -#include "osdvector.h" +#include +#include "log.h" #include "omx/omximagedecode.h" #include "omx/omxeglrender.h" +#include "eglpicturecreator.h" +#include "imageloader.h" #include "imageomx2.h" -#include "eglpicturecreator.h" - const static char* TAG = "ImageOMX2"; ImageOMX2::ImageOMX2(/*EGLDisplay t_egl_display*/) -: OsdVector::PictureDecoder(NULL) { log = LogNT::getInstance(); //egl_display = t_egl_display; @@ -91,7 +91,7 @@ unsigned char* ImageOMX2::decodePicture(LoadingIndex index, unsigned char* buffe currentDecode.lindex = index; currentDecode.decoder = this; - currentDecode.type = OsdVector::PictureInfo::RGBAMemBlock; + currentDecode.type = PictureInfo::RGBAMemBlock; //currentDecode.image/handle = // filled during render //currentDecode.reference = // filled during render @@ -151,7 +151,7 @@ unsigned char* ImageOMX2::decodePicture(LoadingIndex index, unsigned char* buffe } } -bool ImageOMX2::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf) +bool ImageOMX2::getDecodedPicture(struct PictureInfo& pict_inf) { if (!currentDecodeValid) return false; pict_inf = currentDecode; diff --git a/imageomx2.h b/imageomx2.h index ef85a75..28e00ed 100644 --- a/imageomx2.h +++ b/imageomx2.h @@ -47,14 +47,13 @@ with VideoOMX?) #ifndef IMAGEOMX2_H #define IMAGEOMX2_H -#include "osdvector.h" -#include "osdopenvg.h" +#include "osdvectortypes.h" class LogNT; class OMX_Image_Decode; class OMX_EGL_Render; -class ImageOMX2 : public OsdVector::PictureDecoder +class ImageOMX2 : public PictureDecoder { // PictureDecoder Interface public: @@ -65,7 +64,7 @@ class ImageOMX2 : public OsdVector::PictureDecoder void shutdown(); unsigned char* decodePicture(LoadingIndex index, unsigned char* buffer, unsigned int length, bool freemem) noexcept; - bool getDecodedPicture(struct OsdVector::PictureInfo& pict_inf); + bool getDecodedPicture(struct PictureInfo& pict_inf); void freeReference(void*) {}; // Internal stuff @@ -77,7 +76,7 @@ class ImageOMX2 : public OsdVector::PictureDecoder OMX_EGL_Render* omx_eglrender{}; // State data for the decode - struct OsdVector::PictureInfo currentDecode{}; // There's only one user so no locking required + struct PictureInfo currentDecode{}; // There's only one user so no locking required bool currentDecodeValid{}; // Internal functions diff --git a/message.h b/message.h index 4abaeb7..be72b04 100644 --- a/message.h +++ b/message.h @@ -84,7 +84,6 @@ class Message const static int SUBTITLE_CHANGE_CHANNEL = 34; const static int MOUSE_SCROLL = 35; const static int NEW_PICTURE = 36; - const static int NEW_PICTURE_STATIC = 37; const static int REDRAW = 38; const static int SHUTDOWN = 39; diff --git a/movieinfo.cc b/movieinfo.cc index 2513c18..191d0c2 100644 --- a/movieinfo.cc +++ b/movieinfo.cc @@ -20,27 +20,3 @@ #include "movieinfo.h" -MovieInfo::MovieInfo() -{ - id=0; - title=""; - originalTitle=""; - tagline=""; - overview=""; - adult=0; - collectionName=""; - - budget=0; - revenue=0; - genres=""; - homepage=""; - releaseDate=""; - runtime=0; - popularity=0.f; - voteAverage=0.f; - - - -} - - diff --git a/movieinfo.h b/movieinfo.h index 31c3358..65f31d0 100644 --- a/movieinfo.h +++ b/movieinfo.h @@ -1,5 +1,5 @@ /* - Copyright 2014 Marten Richter + Copyright 2014 Marten Richter, 2021 Chris Tallon This file is part of VOMP. @@ -14,43 +14,41 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + along with VOMP. If not, see . */ #ifndef MOVIEINFO_H #define MOVIEINFO_H -#include "tvmedia.h" - -class MovieInfo { -public: - MovieInfo(); - - int id; - - std::string title; - std::string originalTitle; - std::string tagline; - std::string overview; - UCHAR adult; - std::string collectionName; - - int budget; - int revenue; - std::string genres; - std::string homepage; - std::string releaseDate; - int runtime; - float popularity; - float voteAverage; - - TVMedia poster; - TVMedia fanart; - TVMedia collectionPoster; - TVMedia collectionFanart; - Actors actors; +#include + +#include "image.h" + +struct MovieInfo +{ + int id{}; + + std::string title; + std::string originalTitle; + std::string tagline; + std::string overview; + UCHAR adult{}; + std::string collectionName; + + int budget{}; + int revenue{}; + std::string genres; + std::string homepage; + std::string releaseDate; + int runtime{}; + float popularity{}; + float voteAverage{}; + + TVMediaStruct poster; + TVMediaStruct fanart; + TVMediaStruct collectionPoster; + TVMediaStruct collectionFanart; + Actors actors; }; - #endif diff --git a/objects.mk b/objects.mk index b6370b9..2037b9d 100644 --- a/objects.mk +++ b/objects.mk @@ -17,9 +17,10 @@ OBJ_COMMON = util.o control.o thread.o timers.o i18n.o udp4.o udp6.o vdpc.o tcp. vdrresponsepacket.o vvideolivetv.o sleeptimer.o \ wprogressbar.o bitmap.o dvbsubtitles.o tfeed.o vteletextview.o \ teletextdecodervbiebu.o teletxt/txtfont.o movieinfo.o seriesinfo.o \ - wmovieview.o wseriesview.o tvmedia.o wtvmedia.o wpictureview.o \ + wmovieview.o wseriesview.o wtvmedia.o wpictureview.o \ osdvector.o surfacevector.o buffer.o config.o log.o \ - playervideorec.o playervideolive.o playerradiolive.o playerradiorec.o + playervideorec.o playervideolive.o playerradiolive.o playerradiorec.o \ + imageloader.o image.o OBJ_RASPBERRY = main.o threadp.o osdopenvg.o \ ledraspberry.o videoomx.o audioomx.o imageomx.o \ diff --git a/osd.cc b/osd.cc index e497911..2976d88 100644 --- a/osd.cc +++ b/osd.cc @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon + Copyright 2004-2021 Chris Tallon This file is part of VOMP. @@ -14,8 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + along with VOMP. If not, see . */ #include "osd.h" @@ -42,3 +41,14 @@ Osd* Osd::getInstance() { return instance; } + +void Osd::addOsdImage(OsdImage& o) +{ + images.push_back(o); + //LogNT::getInstance()->trace("OsdImage", "ADDED HW IMAGE: {}", images.size()); +} + +void Osd::dumpImages() +{ + //LogNT::getInstance()->trace("OsdImage", "Num OsdImages: {}", images.size()); +} diff --git a/osd.h b/osd.h index 804d571..2754a1c 100644 --- a/osd.h +++ b/osd.h @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon + Copyright 2004-2021 Chris Tallon This file is part of VOMP. @@ -20,6 +20,16 @@ #ifndef OSD_H #define OSD_H +#include +#include +#include + +// See image.h for docs + +class OsdImageBase; +using OsdImage = std::shared_ptr; +class OsdImageBase {}; + class Surface; class Osd @@ -34,7 +44,7 @@ class Osd virtual int restore() { return 1; }; virtual int stopUpdate() { return 1; }; - virtual Surface * createNewSurface()=0; // For Boxx + virtual Surface* createNewSurface()=0; // For Boxx virtual int charSet() { return 1; }; bool isInitted() { return initted; }; @@ -49,11 +59,22 @@ class Osd // OSDOVG-ROD-EXPERIMENT virtual void doRender() { }; + // Images + OsdImage createOsdImage(); + virtual void garbageCollectOsdImages()=0; + + void dumpImages(); + protected: static Osd* instance; bool initted{}; - Surface* screen; - int fdOsd; + Surface* screen{}; + int fdOsd{}; + + // Images + void addOsdImage(OsdImage& oImage); + std::vector images; + std::mutex imagesLock; }; #endif diff --git a/osdopenvg.cc b/osdopenvg.cc index 7b6b980..171984a 100644 --- a/osdopenvg.cc +++ b/osdopenvg.cc @@ -17,6 +17,7 @@ along with VOMP. If not, see . */ +#include #include #include #include @@ -63,10 +64,14 @@ OsdOpenVG::OsdOpenVG() EXTERNAL_PICTS #undef EXTERNALPICTURE + + MessageQueue::getInstance()->addReceiver(this); } OsdOpenVG::~OsdOpenVG() { + MessageQueue::getInstance()->removeReceiver(this); + if (initted) shutdown(); if (cur_fontname) free(cur_fontname); @@ -84,7 +89,7 @@ int OsdOpenVG::init() { if (initted) return 0; - reader.init(); + OsdVector::init(); //First get connection to egl egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); @@ -314,12 +319,10 @@ int OsdOpenVG::init() taskmutex.unlock(); vgmutex.unlock(); -#ifdef PICTURE_DECODER_OMX - // imageomx = new ImageOMX(&reader); - // reader.addDecoder(imageomx); +#ifdef PICTURE_DECODER_OMX imageomx2 = new ImageOMX2(/*egl_display*/); - reader.addDecoder(imageomx2); + ImageLoader::getInstance()->addDecoder(imageomx2); #endif return 1; @@ -345,12 +348,8 @@ int OsdOpenVG::stopUpdate() int OsdOpenVG::shutdown() { - reader.shutdown(); - #ifdef PICTURE_DECODER_OMX -// if (imageomx) reader.removeDecoder(imageomx); -// imageomx = NULL; - if (imageomx2) reader.removeDecoder(imageomx2); + if (imageomx2) ImageLoader::getInstance()->removeDecoder(imageomx2); imageomx2 = NULL; #endif @@ -419,6 +418,48 @@ int OsdOpenVG::shutdown() return 1; } +void OsdOpenVG::processMessage(Message* m) +{ + if (m->message == Message::NEW_PICTURE) + { + logger->debug(TAG, "NEW_PICTURE"); + + OsdImageBase* newImageOVG = new OsdImageOpenVG(reinterpret_cast(m->data)); + OsdImage oImage(newImageOVG); + + addOsdImage(oImage); + + ImageLoader::getInstance()->pictureRendered(reinterpret_cast(m->tag), oImage); + // The above returns false if it does not accept the OsdImage + // We just drop out here and leave the only reference to it in Osd::images + // It will be deleted properly on the next garbage collection run + + // OSDOVG-ROD-EXPERIMENT + logger->trace(TAG, "EXPERIMENT - call doRender"); + doRender(); + } +} + +void OsdOpenVG::garbageCollectOsdImages() +{ + // Only use references into images + // Therefore if use_count == 1 the only copy of the OsdImage is in images and therefore is dead + + imagesLock.lock(); + for(auto& oi : images) + { + if (oi.use_count() == 1) + destroyImageRef(std::static_pointer_cast(oi)->getVGImage()); + } + + auto it = std::remove_if(images.begin(), images.end(), [](OsdImage& oi) { return oi.use_count() == 1; }); + images.erase(it, images.end()); + + // C++20: std::erase_if(images, [](OsdImage oi) { return oi.use_count() == 1; }); + + imagesLock.unlock(); +} + // OSDOVG-ROD-EXPERIMENT - temp hack to allow OsdVector to signal the thread in OsdOpenVG void OsdOpenVG::doRender() { @@ -439,7 +480,7 @@ void OsdOpenVG::doRender() * Pros: * More responsive OSD * Cuts 5% constant CPU usage - * Seems to have tickled the GFX corruption bug, might make it easier to find that + * Seems to have tickled the GFX corruption bug, might make it easier to find that - update: found and fixed!! * * Cons: * There's a comment about video tearing if render is called too often. @@ -636,13 +677,6 @@ void OsdOpenVG::purgeAllReferences() } jpegs.clear();* / - map::iterator titty=tvmedias.begin(); - while (titty!=tvmedias.end()) { - vgDestroyImage((VGImage)(*titty).second); - titty++; - } - tvmedias.clear(); - map,unsigned int>::iterator sitty=drawstyleHandles.begin(); while (sitty!=drawstyleHandles.end()) { vgDestroyPaint((VGPaint)(*sitty).second); @@ -1138,15 +1172,30 @@ void OsdOpenVG::executeDrawCommand(SVGCommand& command) break; } case DrawImage: + case DrawBitmap: { + VGImage vgimage; + if (command.instr == DrawBitmap) vgimage = static_cast(command.target.bitmap); + else if (command.instr == DrawImage) + { + // FIXME use shared_ptr for OsdImageOpenVG objects? + // -or- + // Don't use shared_ptrs for all those CImage types, are they needed? + // Preferring the second option at the moment + + OsdImage oi = command.image->getOsdImage(); + OsdImageOpenVG* oiovg = std::static_pointer_cast(oi).get(); + vgimage = oiovg->getVGImage(); + } + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); vgGetMatrix(save_matrix); - VGfloat imagewidth = vgGetParameteri(static_cast(command.target.image), VG_IMAGE_WIDTH); - VGfloat imageheight = vgGetParameteri(static_cast(command.target.image), VG_IMAGE_HEIGHT); + VGfloat imagewidth = vgGetParameteri(vgimage, VG_IMAGE_WIDTH); + VGfloat imageheight = vgGetParameteri(vgimage, VG_IMAGE_HEIGHT); //vgScale(command.w,command.h); - if (command.handle) //special behaviout for bw images they act as a mask on the current paint + if (command.handle) //special behaviour for bw images they act as a mask on the current paint { vgTranslate(command.x, command.y); vgSetPaint(static_cast(command.handle), VG_FILL_PATH); @@ -1227,9 +1276,9 @@ void OsdOpenVG::executeDrawCommand(SVGCommand& command) //vgTranslate(200.f,500.f); //vgScale(100.f,100.f); - vgDrawImage(static_cast(command.target.image)); + vgDrawImage(vgimage); - //LogNT::getInstance()->debug(TAG, "Draw Image {} {:#x} {} {} {} {} {:#x}",command.handle,command.target.image,command.x,command.y,command.w,command.h, + //LogNT::getInstance()->debug(TAG, "Draw Image {} {:#x} {} {} {} {} {:#x}",command.handle,vgimage,command.x,command.y,command.w,command.h, // vgGetError()); if (command.handle) { @@ -1356,7 +1405,7 @@ unsigned int OsdOpenVG::handleOpenVGCommand(OpenVGCommand& command) } case OVGdestroyImageRef: //imcount--; { - //LogNT::getInstance()->debug(TAG, "TVMedia Draw Image Destroy {:#x} {}",command.param1,imcount); + //LogNT::getInstance()->debug(TAG, "OsdImage Destroy vgDestroyImage {:#x}",command.param1); vgDestroyImage(static_cast(command.param1)); return 0; } @@ -1449,26 +1498,13 @@ unsigned int OsdOpenVG::handleOpenVGCommand(OpenVGCommand& command) VG_sABGR_8888, 0, 0, info->width, info->height); info->decoder->freeReference(info->reference); - bool static_image = true; - - if (info->lindex & 0xffffffff) static_image = false; - - Message* m = new Message(); // We have a pictures! send a message to ourself, to switch to gui thread + Message* m = new Message(); m->from = this; m->to = this; m->data = reinterpret_cast(handle); - - if (!static_image) - { - m->message = Message::NEW_PICTURE; - m->tag = info->lindex; - } - else - { - m->message = Message::NEW_PICTURE_STATIC; - m->tag = info->lindex >> 32LL; - } + m->message = Message::NEW_PICTURE; + m->tag = reinterpret_cast(info->lindex); MessageQueue::getInstance()->postMessage(m); delete info; @@ -1494,25 +1530,13 @@ unsigned int OsdOpenVG::handleOpenVGCommand(OpenVGCommand& command) { PictureInfo* info = const_cast(static_cast(command.data)); eglDestroyImageKHR(egl_display, info->reference); - bool static_image = true; - - if (info->lindex & 0xffffffff) static_image = false; Message* m = new Message(); m->from = this; m->to = this; m->data = reinterpret_cast(info->handle); - - if (!static_image) - { - m->message = Message::NEW_PICTURE; - m->tag = info->lindex; - } - else - { - m->message = Message::NEW_PICTURE_STATIC; - m->tag = info->lindex >> 32LL; - } + m->message = Message::NEW_PICTURE; + m->tag = reinterpret_cast(info->lindex); MessageQueue::getInstance()->postMessage(m); // inform command about new picture delete info; @@ -1620,13 +1644,13 @@ void OsdOpenVG::createPicture(struct PictureInfo& pict_inf) if (pict_inf.type == PictureInfo::RGBAMemBlock) { comm.task = OVGcreateImageMemory; - comm.data = new PictureInfo(pict_inf); + comm.data = new PictureInfo(pict_inf); // deleted in the commands processor putOpenVGCommand(comm, false); } else if (pict_inf.type == PictureInfo::EGLImage) { comm.task = OVGreadyEGLImage; - comm.data = new PictureInfo(pict_inf); + comm.data = new PictureInfo(pict_inf); // deleted in the commands processor putOpenVGCommand(comm, false); } else @@ -1636,7 +1660,7 @@ void OsdOpenVG::createPicture(struct PictureInfo& pict_inf) } } -bool OsdOpenVG::getEGLPicture(struct OsdVector::PictureInfo& info, EGLDisplay* display) +bool OsdOpenVG::getEGLPicture(struct PictureInfo& info, EGLDisplay* display) { struct OpenVGCommand comm; info.type = PictureInfo::EGLImage; diff --git a/osdopenvg.h b/osdopenvg.h index 4ccb079..84f4402 100644 --- a/osdopenvg.h +++ b/osdopenvg.h @@ -34,6 +34,7 @@ #include "defines.h" #include "osdvector.h" #include "videoomx.h" +#include "messagequeue.h" #include "staticartwork.h" #ifdef PICTURE_DECODER_OMX //#include "imageomx.h" @@ -79,8 +80,19 @@ class ImageOMX2; #include "eglpicturecreator.h" +class OsdImageOpenVG : public OsdImageBase +{ + friend class OsdOpenVG; + private: + OsdImageOpenVG(VGImage vgi) + : vgimage(vgi) {} + + VGImage getVGImage() { return vgimage; } -class OsdOpenVG : public OsdVector + VGImage vgimage; +}; + +class OsdOpenVG : public OsdVector, public MessageReceiver #ifdef PICTURE_DECODER_OMX , public EGLPictureCreator #endif @@ -104,10 +116,16 @@ class OsdOpenVG : public OsdVector virtual float getPixelAspect() {return aspect_correction;}; - bool getEGLPicture(struct OsdVector::PictureInfo& info, EGLDisplay* display); + bool getEGLPicture(struct PictureInfo& info, EGLDisplay* display); void updateBackgroundColor(DrawStyle bg); + void createPicture(struct PictureInfo& pict_inf); + + void processMessage(Message* m); + + void garbageCollectOsdImages(); + protected: // OSDOVG-ROD-EXPERIMENT @@ -118,7 +136,6 @@ class OsdOpenVG : public OsdVector // VectorHandleImage createJpeg(const char* fileName, int *width,int *height); VectorHandleImage createMonoBitmap(void* base, int width, int height); VectorHandleImage createImagePalette(int width, int height, const unsigned char* image_data, const unsigned int* palette_data); - void createPicture(struct PictureInfo& pict_inf); void destroyDrawStyleHandle(VectorHandle index); VectorHandle createDrawStyleHandle(const DrawStyle& c); bool getStaticImageData(unsigned int static_id, UCHAR** userdata, ULONG* length); @@ -190,7 +207,6 @@ class OsdOpenVG : public OsdVector uint8_t* static_artwork_end[sa_MAX]; #ifdef PICTURE_DECODER_OMX - //ImageOMX* imageomx; ImageOMX2* imageomx2; #endif }; diff --git a/osdvector.cc b/osdvector.cc index 990072c..ab8a138 100644 --- a/osdvector.cc +++ b/osdvector.cc @@ -1,5 +1,5 @@ /* - Copyright 2012 Marten Richter, 2020 Chris Tallon + Copyright 2012 Marten Richter, 2021 Chris Tallon This file is part of VOMP. @@ -17,14 +17,11 @@ along with VOMP. If not, see . */ -// FIXME It doesn't seem like the LoadingIndex entries in loadindex_ref ever get deleted - #include "log.h" #include "surfacevector.h" -#include "vdr.h" #include "vdrresponsepacket.h" #include "control.h" -#include "message.h" +#include "imageloader.h" #include "osdvector.h" @@ -38,27 +35,27 @@ using namespace Magick; static const char* TAG = "OsdVector"; -class MagickDecoder: public OsdVector::PictureDecoder +class MagickDecoder: public PictureDecoder { public: - MagickDecoder(OsdVector::PictureReader* treader): OsdVector::PictureDecoder(treader) {pictInfValid = false;}; + MagickDecoder() {} unsigned char* decodePicture(LoadingIndex index, unsigned char* buffer, unsigned int length, bool freemem); - bool getDecodedPicture( struct OsdVector::PictureInfo& pict_inf); + bool getDecodedPicture(struct PictureInfo& pict_inf); void freeReference(void* ref); protected: - OsdVector::PictureInfo pictInf; - bool pictInfValid; + PictureInfo pictInf; + bool pictInfValid{}; }; unsigned char* MagickDecoder::decodePicture(LoadingIndex index, unsigned char* buffer, unsigned int length, bool freemem) { if (pictInfValid) return buffer; // does support only one image at a Time; - Image magicimage; + Magick::Image magicimage; Blob* imageblob = new Blob(); Blob myblob; @@ -89,12 +86,10 @@ unsigned char* MagickDecoder::decodePicture(LoadingIndex index, unsigned char* b pictInf.height = magicimage.rows(); pictInf.image = imageblob->data(); pictInf.decoder = this; - pictInf.type = OsdVector::PictureInfo::RGBAMemBlock; + pictInf.type = PictureInfo::RGBAMemBlock; pictInf.lindex = index; pictInfValid = true; - - // I can handle everything, so the return value is always true return NULL; } @@ -104,7 +99,7 @@ void MagickDecoder::freeReference(void* ref) delete todelete; } -bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf) +bool MagickDecoder::getDecodedPicture(struct PictureInfo& pict_inf) { if (!pictInfValid) return false; @@ -113,23 +108,27 @@ bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf) return true; } - #endif + + OsdVector::OsdVector() { logger = LogNT::getInstance(); setlocale(LC_CTYPE, "C.UTF-8"); +} + +int OsdVector::init() +{ #ifdef PICTURE_DECODER_MAGICK - reader.addDecoder(new MagickDecoder(&reader)); + ImageLoader::getInstance()->addDecoder(new MagickDecoder()); #endif - MessageQueue::getInstance()->addReceiver(this); + return 1; } OsdVector::~OsdVector() { - MessageQueue::getInstance()->removeReceiver(this); } bool OsdVector::screenShot(const char* fileName) @@ -153,7 +152,7 @@ bool OsdVector::screenShot(const char* fileName) } myblob.updateNoCopy(mem, length, Blob::MallocAllocator); - Image image(myblob, Geometry(width, height), 8, "RGBA"); + Magick::Image image(myblob, Geometry(width, height), 8, "RGBA"); image.write(fileName); } catch ( Exception& error_ ) @@ -198,12 +197,6 @@ int OsdVector::restore() drawstyleHandles_lastit_valid = drawstyleHandlesRefCounts_lastit_valid = false; palettepics.clear(); - tvmedias.clear(); - loadindex_ref.clear(); - tvmedias_load.clear(); - tvmedias_load_inv.clear(); - tvmedias_loaded.clear(); - surfaces_mutex.unlock(); return 1; } @@ -258,18 +251,12 @@ void OsdVector::drawSurfaces() while (commands != end) { // update any images loaded in the mean time - if ((*commands).instr == DrawImageLoading) + if (commands->instr == DrawImageLoading) { - LoadingIndex loadindex = (*commands).target.loadindex; - - if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end()) + if (commands->image->isReady()) { - (*commands).instr = DrawImage; - (*commands).target.image = tvmedias_loaded[loadindex];; - incImageRef((*commands).target.image); - removeLoadingIndexRef(loadindex); + commands->instr = DrawImage; } - } // Now check if the command is on screen! @@ -322,19 +309,13 @@ void OsdVector::updateOrAddSurface(const SurfaceVector* surf, float x, float y, } // update any images loaded in the mean time - for (SVGCommand& command : commands) { if (command.instr == DrawImageLoading) { - LoadingIndex loadindex = command.target.loadindex; - - if (tvmedias_loaded.find(loadindex) != tvmedias_loaded.end()) + if (command.image->isReady()) { command.instr = DrawImage; - command.target.image = tvmedias_loaded[loadindex]; - incImageRef(command.target.image); - removeLoadingIndexRef(loadindex); } } } @@ -378,11 +359,8 @@ void OsdVector::decrementAllRefCounts(std::vector& commands) if (handle != 0) // command might not have a handle decrementDrawStyleHandleRefCount(handle); - VectorHandleImage imageHandle = command.getImageHandle(); - if (imageHandle) removeImageRef(imageHandle); - - LoadingIndex li = command.getLoadingIndex(); - if (li) removeLoadingIndexRef(li); + VectorHandleImage imageHandle = command.getImageHandle(); + if (imageHandle) removeImageRef(imageHandle); } } @@ -394,11 +372,8 @@ void OsdVector::incrementAllRefCounts(std::vector& commands) if (handle != 0) // command might not have a handle incrementDrawStyleHandleRefCount(handle); - VectorHandleImage imageHandle = command.getImageHandle(); - if (imageHandle) incImageRef(imageHandle); - - LoadingIndex li = command.getLoadingIndex(); - if (li) incLoadingIndexRef(li); + VectorHandleImage imageHandle = command.getImageHandle(); + if (imageHandle) incImageRef(imageHandle); } } @@ -419,88 +394,31 @@ void OsdVector::removeImageRef(const VectorHandleImage handle) vhi_refcounts[handle]--; } -int OsdVector::getLoadingIndexRef(LoadingIndex index) -{ - surfaces_mutex.lock(); - - if (loadindex_ref.find(index) == loadindex_ref.end()) - { - return -1; - } - else - { - return loadindex_ref[index]; - } - - surfaces_mutex.unlock(); -} - -void OsdVector::incLoadingIndexRef(LoadingIndex index) -{ - if (loadindex_ref.find(index) == loadindex_ref.end()) - { - loadindex_ref[index] = 1; - } - else - { - loadindex_ref[index]++; - } -} - -void OsdVector::removeLoadingIndexRef(const LoadingIndex ref) -{ - loadindex_ref[ref]--; - - if (loadindex_ref[ref] == 0) - { - //now check, if it is already loaded - std::map::iterator itty = tvmedias_loaded.find(ref); - - if ( itty != tvmedias_loaded.end()) - { - removeImageRef((*itty).second); // remove lock - - /* Update - not this? Re-enabled. */ - - /* - * I'm not sure exactly how all this works but removing this line of code prevents - * reference counts in vhi_refcounts from going negative. Therefore I suspect the above - * line is wrong. Will test for a while. - */ - } - - tvmedias_loaded.erase(ref); - // logger->debug(TAG, "TVMedia removeLoadIndexRef {} {:#x}",tvmedias_load.size(),ref); - tvmedias_load.erase(tvmedias_load_inv[ref]); - tvmedias_load_inv.erase(ref); - - reader.invalidateLoadingIndex(ref); - } -} - void OsdVector::dumpImages() { // surfaces_mutex.lock(); - printf("tvmedias.size = %i\n", tvmedias.size()); +// printf("vhi_refcounts\n"); +// // std::map vhi_refcounts; +// // ImageIndex is a VectorHandle. VectorHandle is an unsigned int +// for(auto& a : vhi_refcounts) +// { +// printf("ImageIndex: %u int: %i\n", a.first, a.second); +// } + +// printf("loadingindex_ref\n"); +// // std::map loadindex_ref; +// // LoadingIndex is a unsigned long long +// for(auto& a : loadindex_ref) +// { +// printf("LoadingIndex: %llu (%llu) int: %i\n", a.first, a.first >> 32, a.second); +// } - printf("vhi_refcounts\n"); - // std::map vhi_refcounts; - // ImageIndex is a VectorHandle. VectorHandle is an unsigned int - for(auto& a : vhi_refcounts) - { - printf("ImageIndex: %u int: %i\n", a.first, a.second); - } + // surfaces_mutex.unlock(); - printf("loadingindex_ref\n"); - // std::map loadindex_ref; - // LoadingIndex is a unsigned long long - for(auto& a : loadindex_ref) - { - printf("LoadingIndex: %llu (%llu) int: %i\n", a.first, a.first >> 32, a.second); - } - // surfaces_mutex.unlock(); + ImageLoader::getInstance()->dumpImages(); + Osd::dumpImages(); } void OsdVector::cleanupOrphanedRefs() @@ -536,40 +454,6 @@ void OsdVector::cleanupOrphanedRefs() } else ++jitty; }*/ - std::map::iterator titty = tvmedias.begin(); - - while (titty != tvmedias.end()) - { - std::map::iterator curitty = vhi_refcounts.find((*titty).second); - int count = (*curitty).second; - - if (count == 0) - { - VectorHandleImage handle = (*curitty).first; - tvmedias.erase(titty++); - vhi_refcounts.erase(curitty); - destroyImageRef(handle); - } - else ++titty; - } - - - std::map::iterator litty = tvmedias_load.begin(); - - while (litty != tvmedias_load.end()) - { - std::map::iterator curitty = loadindex_ref.find((*litty).second); - int count = (*curitty).second; - - if (count == 0) - { - tvmedias_load_inv.erase((*litty).second); - tvmedias_loaded.erase((*litty).second); - tvmedias_load.erase(litty++); - } - else ++litty; - } - std::list::iterator pitty = palettepics.begin(); while (pitty != palettepics.end()) @@ -602,7 +486,6 @@ void OsdVector::cleanupOrphanedRefs() else ++citty; } - std::map::iterator sitty = drawstyleHandles.begin(); while (sitty != drawstyleHandles.end()) @@ -622,23 +505,10 @@ void OsdVector::cleanupOrphanedRefs() else ++sitty; } -} -//int OsdVector::getImageRef(VectorHandleImage handle) -//{ -// surfaces_mutex.lock(); -// -// if (vhi_refcounts.find(handle) == vhi_refcounts.end()) -// { -// return -1; -// } -// else -// { -// return vhi_refcounts[handle]; -// } -// -// surfaces_mutex.unlock(); -//} + ImageLoader::getInstance()->garbageCollect(); + garbageCollectOsdImages(); // Call this on self - derived object knows how to destroy them +} void OsdVector::incrementDrawStyleHandleRefCount(VectorHandle index) { @@ -740,144 +610,6 @@ void OsdVector::dumpStyles() } #endif -LoadingIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, VectorHandleImage& handle) -{ - VectorHandleImage localHandle = 0; - LoadingIndex loadindex = 0; - surfaces_mutex.lock(); - - if (tvmedias.find(tvmedia) == tvmedias.end()) // if not found, return a loadIndex from loadTVMedia(tvmedia) - { - loadindex = loadTVMedia(tvmedia); - } - 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. - { - localHandle = tvmedias[tvmedia]; - - if (vhi_refcounts.find(localHandle) == vhi_refcounts.end()) - { - //invalid handle recreate - loadindex = loadTVMedia(tvmedia); - localHandle = 0; - } - else - { - incImageRef(localHandle); - } - } - - /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height); - incImageRef(localHandle);*/ - handle = localHandle; - surfaces_mutex.unlock(); - return loadindex; -} - -LoadingIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia) // insert a tvmedia for loading -{ - LoadingIndex index = 0; - - if (tvmedias_load.find(tvmedia) == tvmedias_load.end()) // if not found in tvmedias_load - { - switch (tvmedia.getType()) - { - case 3: - index = VDR::getInstance()->loadTVMediaRecThumb(tvmedia); - break; - - case 4: - { - index = ((long long) tvmedia.getPrimaryID()) << 32LL; - reader.addStaticImage(tvmedia.getPrimaryID()); - } break; - - case 5: - index = VDR::getInstance()->loadTVMediaEventThumb(tvmedia); - break; - - case 6: - index = VDR::getInstance()->loadChannelLogo(tvmedia); - break; - - default: - index = VDR::getInstance()->loadTVMedia(tvmedia); - break; - } - - if (tvmedia.getType() != 4 && tvmedia.getStaticFallback() > -1) - { - reader.informFallback(index, tvmedia.getStaticFallback()); - } - - tvmedias_load[tvmedia] = index; - tvmedias_load_inv[index] = tvmedia; - } - else - { - index = tvmedias_load[tvmedia]; - } - - incLoadingIndexRef(index); - - return index; -} - -void OsdVector::informPicture(LoadingIndex index, VectorHandleImage handle) -{ - //Beware for thread safety - VectorHandleImage localHandle = 0; - - logger->debug(TAG, "TVMedia Picture for load-id {:#x} arrived index {:#x}", index, handle); - surfaces_mutex.lock(); - TVMediaInfo tvmedia = tvmedias_load_inv[index]; - - if (handle) - { - std::map::iterator itty = loadindex_ref.find(index); - localHandle = tvmedias[tvmedia] = handle; - tvmedias_loaded[index] = localHandle; - - if (itty == loadindex_ref.end() || (*itty).second == 0) - { - // we do not want the picture anymore . Really... - // fill vhi_refcounts in to not irritate the garbage collector - if (vhi_refcounts.find(localHandle) == vhi_refcounts.end()) - { - vhi_refcounts[localHandle] = 0; - } - } - else - { - incImageRef(localHandle); // hold one index until all loadings refs are gone; - } - } - - surfaces_mutex.unlock(); - - // OSDOVG-ROD-EXPERIMENT - logger->trace(TAG, "EXPERIMENT - call doRender"); - doRender(); -} - -void OsdVector::processMessage(Message* m) -{ - switch(m->message) - { - case Message::NEW_PICTURE: - { - //logger->debug(TAG, "TVMedia NEW_PICTURE"); - informPicture(m->tag, reinterpret_cast(m->data)); - break; - } - case Message::NEW_PICTURE_STATIC: - { - //logger->debug(TAG, "TVMedia NEW_PICTURE {:#x} {:#x}", m->tag, m->parameter); - informPicture(static_cast(m->tag) << 32LL, reinterpret_cast(m->data)); - break; - } - } -} - /* VectorHandleImage OsdVector::getJpegRef(const char* fileName, int *width,int *height) { @@ -940,319 +672,3 @@ VectorHandleImage OsdVector::getImagePalette(int width, int height, const unsign surfaces_mutex.unlock(); return image_handle; } - -/// PictureReader Class - -OsdVector::PictureReader::~PictureReader() -{ - threadMutex.lock(); - if (readerThread.joinable()) - { - threadReqQuit = true; - threadCond.notify_one(); - threadMutex.unlock(); - readerThread.join(); - } - else - threadMutex.unlock(); - - - decoders_lock.lock(); - while (decoders.size()) - { - PictureDecoder* dec = decoders.front(); - decoders.pop_front(); - delete dec; - } - decoders_lock.unlock(); -} - -void OsdVector::PictureReader::init() -{ - threadMutex.lock(); - readerThread = std::thread( [this] - { - threadMutex.lock(); - threadMutex.unlock(); - threadMethod(); - }); - threadMutex.unlock(); -} - -void OsdVector::PictureReader::shutdown() -{ - std::unique_lock lg(threadMutex); - - if (readerThread.joinable()) - { - threadReqQuit = true; - threadCond.notify_one(); - lg.unlock(); - readerThread.join(); - } -} - -void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder) -{ - decoders_lock.lock(); - decoder->init(); - decoders.push_front(decoder); - decoders_lock.unlock(); -} - -void OsdVector::PictureReader::removeDecoder(PictureDecoder* decoder) -{ - decoders_lock.lock(); - std::list::iterator itty = decoders.begin(); - - while (itty != decoders.end()) - { - if ((*itty) == decoder) - { - decoders.erase(itty); - break; - } - - itty++; - } - - LogNT::getInstance()->debug("PictureReader", "removeDecoder"); - decoder->shutdown(); - delete decoder; - decoders_lock.unlock(); -} - -void OsdVector::PictureReader::threadMethod() -{ - OsdVector* osdvector = dynamic_cast(Osd::getInstance()); -// LogNT::getInstance()->debug("PictureReader", "TVMedia Start Picture Reader"); - - std::unique_lock ul(threadMutex); // locked - - while (true) - { - threadCond.wait(ul, [this]{ return threadReqQuit || runLoop; }); - // locked - if (threadReqQuit) return; // unlock -// LogNT::getInstance()->debug("PictureReader", "Running loop"); - runLoop = false; - ul.unlock(); - - // unlocked while we work - - bool miniRunAgain; - do - { - miniRunAgain = false; - - PictureInfo pictinf; - decoders_lock.lock(); - std::list::iterator itty = decoders.begin(); - - while (itty != decoders.end()) - { - if ((*itty)->getDecodedPicture(pictinf)) // FIXME somewhere around here?, or in getDecodedPicture, try SA optimisation - { - miniRunAgain = true; - osdvector->createPicture(pictinf); - } - itty++; - } - - if (processReceivedPictures()) miniRunAgain = true; - decoders_lock.unlock(); - -// LogNT::getInstance()->debug("PictureReader", "miniRunAgain = true..."); - - } while(miniRunAgain); - - ul.lock(); - } -} - -void OsdVector::PictureReader::invalidateLoadingIndex(LoadingIndex index) -{ - pict_lock_incoming.lock(); - invalid_loadindex.insert(index); - pict_lock_incoming.unlock(); - - // From conversion to std::thread - // The thread used to spin every 10ms, now it only waits on the cond - // This method does not signal the main thread, does it need to now? - // Doesn't look like it, but if it does get the 4 lines below -} - -void OsdVector::PictureReader::informFallback(LoadingIndex index, int fallback) -{ - pict_lock_incoming.lock(); - inform_fallback[index] = fallback; - pict_lock_incoming.unlock(); - // Also here, does this need to signal the thread? -} - -void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket* vresp) -{ - pict_lock_incoming.lock(); - pict_incoming.push(vresp); - pict_lock_incoming.unlock(); - - // These 4 lines to signal the thread - threadMutex.lock(); - runLoop = true; - threadCond.notify_one(); - threadMutex.unlock(); -} - -void OsdVector::PictureReader::addStaticImage(unsigned int id) -{ - pict_lock_incoming.lock(); - pict_incoming_static.push(id); - invalid_loadindex.erase(((long long) id) << 32LL); - pict_lock_incoming.unlock(); - - threadMutex.lock(); - runLoop = true; - threadCond.notify_one(); - threadMutex.unlock(); -} - -#if WIN32 - // FIXME win pragma - #pragma warning(disable : 4703) -#endif - -bool OsdVector::PictureReader::processReceivedPictures() -{ - bool decoded = false; - bool valid = true; - pict_lock_incoming.lock(); - - if (pict_incoming.size()) - { - VDR_ResponsePacket* vresp = pict_incoming.front(); - pict_incoming.pop(); - std::set::iterator setpos = invalid_loadindex.find(vresp->getStreamID()); - - if (setpos != invalid_loadindex.end()) - { - valid = false; - invalid_loadindex.erase(setpos); - } - - pict_lock_incoming.unlock(); - - if (!valid) // we do not want it anymore skip it; - { - delete vresp; - return true; - } - - // LogNT::getInstance()->debug("PictureReader", "TVMedia Pictures arrived VDR {:#x} {} {}", - // vresp->getStreamID(),vresp->getUserDataLength(),vresp->getFlag()); - bool decode = false; - bool freed = false; - UCHAR* userdata; - ULONG length; - - if (vresp->getFlag() != 2) - { - userdata = vresp->getUserData(); - length = vresp->getUserDataLength(); - decode = true; - freed = true; - } - else - { - int fallback = -1; - pict_lock_incoming.lock(); - - if (inform_fallback.find(vresp->getStreamID()) != inform_fallback.end()) - { - fallback = inform_fallback[vresp->getStreamID()]; - } - - pict_lock_incoming.unlock(); - - if (fallback >= 0 && ((OsdVector*)Osd::getInstance())->getStaticImageData(fallback, &userdata, &length)) - { - decode = true; - freed = false; - } - } - - if (decode) - { - std::list::iterator itty = decoders.begin(); - - while (itty != decoders.end()) - { - userdata = (*itty)->decodePicture(vresp->getStreamID(), userdata, length, freed); - - if (!userdata) - { - decoded = true; - break; - } - - itty++; - } - - if (!decoded && userdata && freed) - { - free(userdata); - } - } - - pict_lock_incoming.lock(); - inform_fallback.erase(vresp->getStreamID()); - pict_lock_incoming.unlock(); - //else osd->informPicture(vresp->getStreamID(), 0); - delete vresp; - } - else if (pict_incoming_static.size()) - { - unsigned int static_id = pict_incoming_static.front(); - pict_incoming_static.pop(); - std::set::iterator setpos = invalid_loadindex.find(((long long) static_id) << 32LL); - - if (setpos != invalid_loadindex.end()) - { - valid = false; - invalid_loadindex.erase(setpos); - } - - pict_lock_incoming.unlock(); - - if (!valid) // we do not want it anymore skip it; - { - return true; - } - - UCHAR* userdata; - ULONG length; - - if (((OsdVector*)Osd::getInstance())->getStaticImageData(static_id, &userdata, &length)) - { - std::list::iterator itty = decoders.begin(); - - while (itty != decoders.end()) - { - if (!(*itty)->decodePicture(((long long) static_id) << 32LL, userdata, length, false)) - { - decoded = true; - break; - } - - itty++; - } - } - } - else - { - pict_lock_incoming.unlock(); - } - - if (pict_incoming.size() || pict_incoming_static.size()) return true; - - return decoded; -} diff --git a/osdvector.h b/osdvector.h index 8bf7398..80e99cb 100644 --- a/osdvector.h +++ b/osdvector.h @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter + Copyright 2004-2005,2021 Chris Tallon, 2006,2011-2012 Marten Richter This file is part of VOMP. @@ -31,11 +31,11 @@ #include #include "defines.h" -#include "messagequeue.h" +#include "osdvectortypes.h" #include "osd.h" #include "colour.h" -#include "tvmedia.h" -#include "vdr.h" +#include "image.h" +#include "imageloader.h" #include "teletextdecodervbiebu.h" class LogNT; @@ -48,7 +48,8 @@ enum SVGCommandInstr DrawImage, DrawTTchar, DrawClipping, - DrawImageLoading + DrawImageLoading, + DrawBitmap }; enum PathIndex @@ -59,20 +60,6 @@ enum PathIndex PIPoint }; -enum Corner -{ - TopLeft, - TopRight, - BottomLeft, - BottomRight, - TopMiddle, - BottomMiddle, - TopLeftLimited -}; - -typedef VectorHandle VectorHandleImage; -typedef unsigned long long LoadingIndex; - class SVGCommand { public: @@ -89,7 +76,7 @@ class SVGCommand return nc; }; - inline static SVGCommand PaintImageLoading(LoadingIndex load_in, float ix, float iy, float iw, float ih, Corner corner = TopLeft) + inline static SVGCommand PaintImageLoading(Image& image, float ix, float iy, float iw, float ih, Corner corner = TopLeft) { SVGCommand nc; nc.instr = DrawImageLoading; @@ -97,26 +84,43 @@ class SVGCommand nc.y = iy; nc.w = iw; nc.h = ih; - nc.target.loadindex = load_in; nc.handle = 0; // not valid for PaintImageLoading nc.corner = corner; + + nc.image = image; + return nc; }; - inline static SVGCommand PaintImage(float ix, float iy, float iw, float ih, VectorHandleImage handle, VectorHandle ref, Corner corner = TopLeft) + inline static SVGCommand PaintBitmap(float ix, float iy, float iw, float ih, + VectorHandleImage handle, VectorHandle ref, Corner corner = TopLeft) { SVGCommand nc; - nc.instr = DrawImage; + nc.instr = DrawBitmap; nc.x = ix; nc.y = iy; nc.w = iw; nc.h = ih; - nc.target.image = handle; + nc.target.bitmap = handle; nc.handle = ref; // can be 0 (no handle) or can be an Drawstyle nandle nc.corner = corner; return nc; }; + inline static SVGCommand PaintImage(float ix, float iy, float iw, float ih, + Image& image, Corner corner = TopLeft) + { + SVGCommand nc; + nc.instr = DrawImage; + nc.x = ix; + nc.y = iy; + nc.w = iw; + nc.h = ih; + nc.image = image; + nc.corner = corner; + return nc; + }; + inline static SVGCommand PaintTTchar(float ix, float iy, float iw, float ih, unsigned int ttchar_in) { SVGCommand nc; @@ -170,21 +174,15 @@ class SVGCommand return ((x + w) < tx) || ((y + h) < ty) || ((tx + tw) < x) || ((ty + th) < y); } - VectorHandle getHandle() + VectorHandle getHandle() // Is this DrawStyle references? { return handle; }; VectorHandleImage getImageHandle() { - if (instr != DrawImage) return 0; - else return target.image; - }; - - LoadingIndex getLoadingIndex() - { - if (instr != DrawImageLoading) return 0; - else return target.loadindex; + if (instr != DrawBitmap) return 0; + else return target.bitmap; }; SVGCommandInstr instr{DrawNoop}; @@ -195,10 +193,11 @@ class SVGCommand { PathIndex path_index; wchar_t textchar; - VectorHandleImage image; + VectorHandleImage bitmap; unsigned int ttchar; - LoadingIndex loadindex; } target; + + Image image; // This would be in the union but it's a non-trivial type }; class SurfaceVector; @@ -211,7 +210,7 @@ struct SurfaceInfo float x, y, w, h; }; -class OsdVector : public Osd, public MessageReceiver +class OsdVector : public Osd { public: void dumpImages(); @@ -219,6 +218,9 @@ class OsdVector : public Osd, public MessageReceiver OsdVector(); virtual ~OsdVector(); + // FIXME switch to bool + virtual int init(); // Derived classes overriding init() must call this base init() + int restore(); bool screenShot(const char* fileName); @@ -243,119 +245,25 @@ class OsdVector : public Osd, public MessageReceiver // Used only by OsdVector and SurfaceVector void removeImageRef(const VectorHandleImage ref); - void removeLoadingIndexRef(const LoadingIndex ref); VectorHandle getDrawStyleHandle(const DrawStyle& c); void decrementDrawStyleHandleRefCount(VectorHandle ref); - LoadingIndex getTVMediaRef(TVMediaInfo& tvmedia, VectorHandleImage& handle); //virtual VectorHandleImage getJpegRef(const char* fileName, int *width,int *height); virtual VectorHandleImage getMonoBitmapRef(void* base, int width, int height); virtual VectorHandleImage getImagePalette(int width, int height, const unsigned char* image_data, const unsigned int* palette_data); - - // should be only called from control thread - void informPicture(LoadingIndex index, VectorHandleImage handle); - void processMessage(Message* m); - - int charSet() {return 2;}; //UTF-8 - - class PictureDecoder; - struct PictureInfo - { - enum PictType - { - RGBAMemBlock, - EGLImage, - D2DBitmap - }; - PictType type; - ULONG width; - ULONG height; - LoadingIndex lindex; - union - { - const void* image; - unsigned int handle; - }; - void* reference; - PictureDecoder* decoder; - }; - - - class PictureReader; - - class PictureDecoder - { - public: - PictureDecoder(PictureReader* /*treader*/) {/* reader = treader; */}; - virtual ~PictureDecoder() {}; - - // its is always guaranted, that after getDecodedPicture a call to decodePicture follows, if the return value was true; - virtual unsigned char* decodePicture(LoadingIndex index, unsigned char* buffer, unsigned int length, bool freemem = true) = 0; - - virtual bool getDecodedPicture(struct PictureInfo& pict_inf) = 0; - virtual void freeReference(void* ref) = 0; - - virtual void init() {}; - virtual void shutdown() {}; - - protected: - //PictureReader* reader; - }; - - class PictureReader - { - public: - ~PictureReader(); - void init(); - void addDecoder(PictureDecoder*); - void removeDecoder(PictureDecoder*); - void shutdown(); - bool processReceivedPictures(); - - // should be called from control thread - void receivePicture(VDR_ResponsePacket* vresp); - - void addStaticImage(unsigned int id); - void invalidateLoadingIndex(LoadingIndex index); - void informFallback(LoadingIndex index, int fallback); - - protected: - - void threadMethod(); - std::mutex threadMutex; - std::thread readerThread; - bool threadReqQuit{}; - std::condition_variable threadCond; - bool runLoop{}; - - std::mutex pict_lock_incoming; //locks - std::mutex decoders_lock; - std::queue pict_incoming; - std::queue pict_incoming_static; - std::list decoders; - std::map inform_fallback; - std::set invalid_loadindex; - - bool picture_update; - }; - - PictureReader* getPictReader() { return &reader; }; + virtual void createPicture(struct PictureInfo& pict_inf) = 0; + virtual void destroyImageRef(VectorHandleImage handle) = 0; protected: LogNT* logger{}; - PictureReader reader; - float byte_char_width[256]{}; - - virtual void destroyImageRef(VectorHandleImage handle) = 0; //virtual VectorHandleImage createJpeg(const char* fileName, int *width,int *height)=0; virtual VectorHandleImage createMonoBitmap(void* base, int width, int height) = 0; virtual VectorHandleImage createImagePalette(int width, int height, const unsigned char* image_data, const unsigned int* palette_data) = 0; - virtual void createPicture(struct PictureInfo& pict_inf) = 0; virtual VectorHandle createDrawStyleHandle(const DrawStyle& c) = 0; virtual void destroyDrawStyleHandle(VectorHandle index) = 0; virtual void drawSetTrans(SurfaceInfo& sc) = 0; @@ -367,38 +275,21 @@ class OsdVector : public Osd, public MessageReceiver void dumpStyles(); #endif - // See what we can make private in OsdVector private: - // Methods that only seem to be called internally void incImageRef(VectorHandleImage handle); - void incLoadingIndexRef(LoadingIndex index); - int getLoadingIndexRef(LoadingIndex index); void decrementAllRefCounts(std::vector& commands); void incrementAllRefCounts(std::vector& commands); void cleanupOrphanedRefs(); void incrementDrawStyleHandleRefCount(VectorHandle index); - LoadingIndex loadTVMedia(TVMediaInfo& tvmedia); - - // int getImageRef(VectorHandleImage handle); // Not used anywhere - - // All the below are data structures only touched by this base class OsdVector - std::map tvmedias; std::map monobitmaps; //map jpegs; std::list palettepics; - std::map vhi_refcounts; // This appears to cover all 3 (4) of the above types - std::map loadindex_ref; - std::map tvmedias_load; - std::map tvmedias_load_inv; - std::map tvmedias_loaded; - - std::map drawstyleHandles; std::map::iterator drawstyleHandles_lastit; bool drawstyleHandles_lastit_valid{}; @@ -410,7 +301,6 @@ class OsdVector : public Osd, public MessageReceiver std::list surfaces; using SurfacesIterator = std::list::iterator; std::mutex surfaces_mutex; - }; #endif diff --git a/osdvectortypes.h b/osdvectortypes.h new file mode 100644 index 0000000..18d846c --- /dev/null +++ b/osdvectortypes.h @@ -0,0 +1,61 @@ +/* + Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP. If not, see . +*/ + +#ifndef OSDVECTORTYPES_H +#define OSDVECTORTYPES_H + +#include "defines.h" + +typedef void* LoadingIndex; +typedef VectorHandle VectorHandleImage; + +class PictureDecoder; +struct PictureInfo +{ + enum PictType + { + RGBAMemBlock, + EGLImage, + D2DBitmap + }; + PictType type; + ULONG width; + ULONG height; + LoadingIndex lindex; + union + { + const void* image; + unsigned int handle; + }; + void* reference; + PictureDecoder* decoder; +}; + +enum Corner +{ + TopLeft, + TopRight, + BottomLeft, + BottomRight, + TopMiddle, + BottomMiddle, + TopLeftLimited +}; + +#endif diff --git a/seriesinfo.h b/seriesinfo.h index ab68a1b..e3aadd9 100644 --- a/seriesinfo.h +++ b/seriesinfo.h @@ -21,9 +21,10 @@ #ifndef SERIESINFO_H #define SERIESINFO_H -#include "tvmedia.h" #include +#include "image.h" + class EpisodeInfo { public: EpisodeInfo(); @@ -37,7 +38,7 @@ public: std::string guestStars; std::string overview; double rating; - TVMedia image; + TVMediaStruct image; }; @@ -65,6 +66,6 @@ public: TVMedias posters; // Image 2 TVMedias banners; // Image 3 TVMedias fanart; // Image 4 - TVMedia seasonposter; // Image 5 + TVMediaStruct seasonposter; // Image 5 }; #endif diff --git a/surface.h b/surface.h index 561c28e..ab79e4f 100644 --- a/surface.h +++ b/surface.h @@ -20,7 +20,6 @@ #ifndef SURFACE_H #define SURFACE_H -#include #include "defines.h" #include "colour.h" diff --git a/surfacevector.cc b/surfacevector.cc index a01bbad..ca199e5 100644 --- a/surfacevector.cc +++ b/surfacevector.cc @@ -22,6 +22,8 @@ #include #include "bitmap.h" #include "staticartwork.h" +#include "imageloader.h" + #include "surfacevector.h" const static char* TAG = "SurfaceVector"; @@ -30,12 +32,12 @@ SurfaceVector::SurfaceVector(OsdVector* vosd) { logger = LogNT::getInstance(); osd = vosd; + imageLoader = ImageLoader::getInstance(); commands.reserve(2048); } SurfaceVector::~SurfaceVector() { - osd->removeSurface(this); for (SVGCommand& command : commands) @@ -44,9 +46,6 @@ SurfaceVector::~SurfaceVector() VectorHandleImage handle = command.getImageHandle(); if (handle) osd->removeImageRef(handle); - - LoadingIndex li = command.getLoadingIndex(); - if (li) osd->removeLoadingIndexRef(li); } } @@ -242,9 +241,9 @@ void SurfaceVector::drawJpeg(const char* fileName, int x, int y, int* width, int if (index != sa_MAX) { - TVMediaInfo info; - info.setStaticArtwork(index); - drawTVMedia(info, x, y, *width, *height, TopLeft); + ImageStatic image = imageLoader->createStatic(index); + Image toDraw = image; + drawImage(toDraw, x, y, *width, *height, TopLeft); } } @@ -253,32 +252,29 @@ void SurfaceVector::drawJpeg(const char *fileName,int x, int y,int *width, int * { command_mutex.lock(); VectorHandleImage handle=osd->getJpegRef(fileName,width,height); - commands.push_back(SVGCommand::PaintImage(x,y,*width,*height,handle,0)); + commands.push_back(SVGCommand::PaintImage(x,y,*width,*height,image)); command_mutex.unlock(); } */ -void SurfaceVector::drawTVMedia(TVMediaInfo& tvmedia, float x, float y, float width, float height, Corner corner) +void SurfaceVector::drawImage(Image& image, float x, float y, float width, float height, Corner corner) { command_mutex.lock(); - VectorHandleImage handle = 0; - LoadingIndex load_index = osd->getTVMediaRef(tvmedia, handle); // This is where you can get a cache hit - if (width != 0 && height != 0) { removeCommands(x, y, width, height); } - if (handle) + if (image->isReady()) { - logger->trace(TAG, "drawTVMedia: i=true, Add instr PaintImage load_index={} handle={}", load_index, handle); - commands.push_back(SVGCommand::PaintImage(x, y, width, height, handle, 0, corner)); + logger->trace(TAG, "drawImage: READY, Add instr PaintImage for {}", static_cast(image.get())); + commands.push_back(SVGCommand::PaintImage(x, y, width, height, image, corner)); } else { - logger->trace(TAG, "drawTVMedia: i=false, Add instr PaintImageLoading {} {}", load_index, handle); - commands.push_back(SVGCommand::PaintImageLoading(load_index, x, y, width, height, corner)); + logger->trace(TAG, "drawImage: NOT_READY, Add instr PaintImageLoading {} LI {}", static_cast(image.get()), reinterpret_cast(image.get())); + commands.push_back(SVGCommand::PaintImageLoading(image, x, y, width, height, corner)); } command_mutex.unlock(); @@ -299,7 +295,7 @@ int SurfaceVector::create(UINT width, UINT height) } void SurfaceVector::display() { - //nothing this is really mvp specific // FIXME remove? + //nothing this is really mvp specific // FIXME remove? -- yes, only surfacedirectfb has some commented out code in display() } int SurfaceVector::fillblt(int x, int y, int width, int height, const DrawStyle& c) @@ -354,7 +350,7 @@ void SurfaceVector::drawBitmap(int x, int y, const Bitmap& bm, const DisplayRegi ty *= scaley; tw *= scalex; th *= scaley; - SVGCommand temp = SVGCommand::PaintImage(tx, ty, tw, th, handle, 0); + SVGCommand temp = SVGCommand::PaintBitmap(tx, ty, tw, th, handle, 0); removeCommands(tx, ty, tw, th); commands.push_back(temp); command_mutex.unlock(); @@ -376,7 +372,7 @@ void SurfaceVector::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int hei VectorHandleImage handle = osd->getMonoBitmapRef(base, width, height); VectorHandle ref = osd->getDrawStyleHandle(nextColour); removeCommands(dx, dy, width, height); - commands.push_back(SVGCommand::PaintImage(dx, dy, height, width, handle, ref)); // FIXME BUG height and width wrong way around? + commands.push_back(SVGCommand::PaintBitmap(dx, dy, height, width, handle, ref)); // FIXME BUG height and width wrong way around? command_mutex.unlock(); } @@ -401,14 +397,10 @@ int SurfaceVector::removeCommands(float x, float y, float width, float height) //Log::getInstance()->log("OSD", Log::DEBUG, "Remove command %d %g %g %g %g %d %d",(*itty).instr, //(*itty).x,(*itty).y,(*itty).w,(*itty).h,(*itty).handle,(*itty).target.image); osd->decrementDrawStyleHandleRefCount((*itty).getHandle()); // We remove the Style reference, so that osd can free stuff // FIXME BUG BUG BUG - VectorHandleImage handle = (*itty).getImageHandle(); + VectorHandleImage handle = (*itty).getImageHandle(); if (handle) osd->removeImageRef(handle); - LoadingIndex li = (*itty).getLoadingIndex(); - - if (li) osd->removeLoadingIndexRef(li); - if (!remove) { remstart = itty; diff --git a/surfacevector.h b/surfacevector.h index 57f9cfa..17b4ade 100644 --- a/surfacevector.h +++ b/surfacevector.h @@ -25,6 +25,8 @@ #include "surface.h" #include "osdvector.h" +#include "image.h" +#include "imageloader.h" class SurfaceVector : public Surface { @@ -43,7 +45,7 @@ class SurfaceVector : public Surface void drawJpeg(const char* fileName, int x, int y, int* width, int* height); // set width and height to zero, if the original size is wanted, if one index is non zero, // the images is scaled with correct aspect ratio, if both are non zero both are scaled - void drawTVMedia(TVMediaInfo& tvmedia, float x, float y, float width, float height, Corner corner = TopLeft); + void drawImage(Image& image, float x, float y, float width, float height, Corner corner = TopLeft); // set w and h to 0, for unsetting clipping, use correct x and y parameter so that cleanup of commands works void drawClippingRectangle(float x, float y, float w, float h); @@ -69,6 +71,7 @@ class SurfaceVector : public Surface protected: LogNT* logger{}; + ImageLoader* imageLoader{}; int removeCommands(float x, float y, float width, float height); diff --git a/tbboxx.cc b/tbboxx.cc index 857388d..603325d 100644 --- a/tbboxx.cc +++ b/tbboxx.cc @@ -1,5 +1,5 @@ /* - Copyright 2007 Chris Tallon + Copyright 2007-2021 Chris Tallon This file is part of VOMP. @@ -14,8 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + along with VOMP. If not, see . */ #include "tbboxx.h" @@ -26,13 +25,11 @@ TBBoxx::TBBoxx() borderOn = 0; titleText = NULL; titleBarTextWidth = 0; - icon = NULL; } TBBoxx::~TBBoxx() { if (titleText) delete[] titleText; - if (icon) delete icon; } void TBBoxx::setTitleText(const char* takeText, int width) @@ -60,9 +57,10 @@ void TBBoxx::draw() rectangle(0, 0, area.w, 30, titleBarColour); int xpos = 5; #ifdef GRADIENT_DRAWING - if (icon) { - drawTVMedia(*icon, static_cast(xpos), 0,30,30,TopLeftLimited); - xpos+=5+30; + if (tbIcon) + { + drawImage(tbIcon, static_cast(xpos), 0, 30, 30, TopLeftLimited); + xpos += 5 + 30; } #endif if (titleText) @@ -80,10 +78,9 @@ void TBBoxx::setTitleBarColour(const DrawStyle& Tcolour) titleBarColour = Tcolour; } -void TBBoxx::setTitleBarIcon(TVMediaInfo * ticon) +void TBBoxx::setTitleBarIcon(Image& ticon) { - if (icon) delete icon; - icon = ticon; + tbIcon = ticon; } void TBBoxx::setTitleBarOn(UCHAR on) diff --git a/tbboxx.h b/tbboxx.h index 73edb1d..8c82fe0 100644 --- a/tbboxx.h +++ b/tbboxx.h @@ -14,8 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + along with VOMP. If not, see . */ #ifndef TBBOXX_H @@ -26,6 +25,7 @@ #include "boxx.h" #include "defines.h" #include "colour.h" +#include "image.h" // Note! Do not use setBackgroundColour on a TBBoxx or anything derived from it - // it will screw up the display @@ -42,18 +42,18 @@ class TBBoxx : public Boxx void setTitleText(const char* title, int width=0); void setTitleBarColour(const DrawStyle& colour); - void setTitleBarIcon(TVMediaInfo * icon); + void setTitleBarIcon(Image& icon); char* getTitleText() { return titleText; }; private: char* titleText; UCHAR borderOn; int titleBarTextWidth; + Image tbIcon; protected: DrawStyle titleBarColour; UCHAR titleBarOn; - TVMediaInfo *icon; }; #endif diff --git a/tvmedia.cc b/tvmedia.cc deleted file mode 100644 index fd6968e..0000000 --- a/tvmedia.cc +++ /dev/null @@ -1,98 +0,0 @@ -/* - Copyright 2014 Marten Richter - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "tvmedia.h" -#include "movieinfo.h" -#include "seriesinfo.h" - - -TVMediaInfo::TVMediaInfo() -{ - type=2; // movie or series - primary_id=0; //movie or series_id - secondary_id=0; //0 or episode id - type_pict=-1; // 0 full info, 1 poster, 2 poster banner, 3 poster thumb - container=-1; // indices the dataelements with picture in movieinfo or seriesinfo - container_member=-1; // index into the container - primary_name=""; - static_fallback = -1; // fallback if not available -} - - -TVMediaInfo::TVMediaInfo(const TVMediaInfo& info) -{ - type=info.type; // movie or series - primary_id=info.primary_id; //movie or series_id - secondary_id=info.secondary_id; //0 or episode id - type_pict=info.type_pict; // 0 full info, 1 poster, 2 poster banner, 3 poster thumb - container=info.container; // indices the dataelements with picture in movieinfo or seriesinfo - container_member=info.container_member; // index into the container - primary_name=info.primary_name; - static_fallback = info.static_fallback; - -} - -void TVMediaInfo::setMovieInfo(const MovieInfo * mi) -{ - type=1; // movie or series - primary_id=mi->id; //movie or series_id - secondary_id=0; //0 or episode id -} - -void TVMediaInfo::setSeriesInfo(const SeriesInfo * si) -{ - type=0; // movie or series - primary_id=si->id; //movie or series_id - secondary_id=si->episode.episodeid; //0 or episode id -} - -void TVMediaInfo::setPosterThumb(const char* recname) -{ - type=3; - primary_name=recname; -} - -void TVMediaInfo::setStaticArtwork(int id) -{ - type=4; - primary_id=id; -} - -void TVMediaInfo::setStaticFallback(int id) -{ - static_fallback=id; -} - - - -void TVMediaInfo::setPosterThumb(int channel, int eventid) -{ - type=5; - primary_id=channel; - secondary_id=eventid; -} - -void TVMediaInfo::setChannelLogo(int channel) -{ - type=6; - primary_id=channel; -} - - diff --git a/tvmedia.h b/tvmedia.h deleted file mode 100644 index 5349e73..0000000 --- a/tvmedia.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - Copyright 2014 Marten Richter - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef TVMEDIA_H -#define TVMEDIA_H - -#include "defines.h" -#include -#include - -class MovieInfo; -class SeriesInfo; - - -class TVMediaInfo -{ -friend class VDR; -public: - TVMediaInfo(); - TVMediaInfo(const TVMediaInfo& info); - - friend bool operator<(const TVMediaInfo& rhs, const TVMediaInfo& lhs); - friend bool operator==(const TVMediaInfo& rhs, const TVMediaInfo& lhs); - - void setSeasonThumb() { type_pict=2; container=0; container_member=0;}; - void setPosterThumb() { type_pict=1; container=0; container_member=0;}; - void setElement(int cont,int memb) { type_pict=0; container=cont; container_member=memb;}; - void setMovieInfo(const MovieInfo * mi); - void setSeriesInfo(const SeriesInfo * si); - void setPosterThumb(const char* recname); - void setPosterThumb(int channel, int eventid); - void setChannelLogo(int channel); - void setStaticArtwork(int artwork); - void setStaticFallback(int fallback); - int getType() {return type;}; - int getPrimaryID() {return primary_id;}; - int getSecondaryID() {return secondary_id;}; - int getStaticFallback() {return static_fallback;}; - -private: - int type; // 1 movie or 2 series or 3 unknown recording or 4 static artwork - int primary_id; //movie or series_id - int secondary_id; //0 or episode id - int type_pict; // 0 full info, 1 poster thumb, 2 season thumb - int container; // indices the dataelements with picture in movieinfo or seriesinfo - int container_member; // index into the container - std::string primary_name; - int static_fallback; // id of static replacement in case resource is not available -}; - -struct TVMedia -{ - unsigned int width{}; - unsigned int height{}; - - // no filename, file handling is only on the server - TVMediaInfo info; - -}; - -typedef std::vector TVMedias; - -struct Actor -{ - std::string name; - std::string role; - TVMedia thumb; -}; - -typedef std::vector Actors; - - -inline bool operator<(const TVMediaInfo& rhs, const TVMediaInfo& lhs) -{ - if (rhs.type==lhs.type) { - if (rhs.primary_id==lhs.primary_id) { - if (rhs.static_fallback==lhs.static_fallback) { - if (rhs.secondary_id==lhs.secondary_id) { - if (rhs.type_pict==lhs.type_pict) { - if (rhs.container==lhs.container) { - if (rhs.primary_name== lhs.primary_name) { - return rhs.container_member < lhs.container_member; - } else { - return rhs.primary_name < lhs.primary_name; - } - } else { - return rhs.containersetStaticArtwork(sa_tv); - setTitleBarIcon(info); + Image icon = imageLoader->createStatic(sa_tv); + setTitleBarIcon(icon); } else if (type == VDR::RADIO) { setTitleText(tr("Radio Stations")); - TVMediaInfo *info= new TVMediaInfo(); - info->setStaticArtwork(sa_radio); - setTitleBarIcon(info); + Image icon = imageLoader->createStatic(sa_radio); + setTitleBarIcon(icon); } setTitleBarColour(DrawStyle::TITLEBARBACKGROUND); @@ -97,17 +99,20 @@ void VChannelList::setList(std::shared_ptr tlist) for (UINT i = 0; i < chanList->size(); i++) { chan = (*chanList)[i]; - //sprintf(str, "%lu\t%s", chan->number, chan->name); std::ostringstream os; os << chan->number << '\t' << chan->name; - TVMediaInfo *info=NULL; - if (osdv) { - info= new TVMediaInfo(); - info->setChannelLogo((*chanList)[i]->number); - if (type == VDR::VIDEO) info->setStaticFallback(sa_tv); - else info->setStaticFallback(sa_radio); + if (osdv) + { + int sa_id = -1; + if (type == VDR::VIDEO) sa_id = sa_tv; + else if (type == VDR::RADIO) sa_id = sa_radio; + Image icon = imageLoader->createChannelLogo((*chanList)[i]->number, sa_id); + + chan->index = sl.addOption(os.str(), chan, first, icon); } - chan->index = sl.addOption(os.str(), chan, first, info); + else + chan->index = sl.addOption(os.str(), chan, first); + first = 0; } } diff --git a/vchannellist.h b/vchannellist.h index 6074801..c577570 100644 --- a/vchannellist.h +++ b/vchannellist.h @@ -34,6 +34,7 @@ class Channel; class BoxStack; +class ImageLoader; class VChannelList : public TBBoxx, public MessageReceiver { @@ -48,6 +49,7 @@ class VChannelList : public TBBoxx, public MessageReceiver void draw(); private: + ImageLoader* imageLoader; BoxStack* boxstack; std::shared_ptr chanList; diff --git a/vdr.cc b/vdr.cc index 9705686..fd711e5 100644 --- a/vdr.cc +++ b/vdr.cc @@ -37,7 +37,8 @@ #include "movieinfo.h" #include "seriesinfo.h" #include "osdvector.h" -#include "tvmedia.h" +#include "image.h" +#include "imageloader.h" #include "vdr.h" @@ -496,7 +497,7 @@ bool VDR::ed_cb_find(EDReceiver* edr, void* userTag) // Is vresp for vdrpr ? ULONG packetChannel = vresp->getChannelID(); - //logger->debug(TAG, "TVMedia debug {} {} {:#x}", vdrpr->receiverChannel,packetChannel,vdrpr); + //logger->debug(TAG, "Image debug {} {} {:#x}", vdrpr->receiverChannel,packetChannel,vdrpr); if (vdrpr->receiverChannel != packetChannel) return false; if (packetChannel == CHANNEL_REQUEST_RESPONSE) @@ -609,16 +610,17 @@ void VDR_PacketReceiver::call(void* userTag, bool& r_deregisterEDR, bool& r_wake } else if (receiverChannel == VDR::CHANNEL_TVMEDIA) { - // It's TVMedia + // It's Image // Pass off the vresp object to OSDVector // This used to return true which would signal the cond (wake the thread) // but am going to try setting this to false because I don't know that there is a thread to signal // delete the EDR. It's made once per media requested and wasn't owned/deleted by anything before VDR_ResponsePacket* vresp = reinterpret_cast(userTag); - LogNT::getInstance()->debug(TAG, "TVMedia Pictures arrived VDR {:#x}", vresp->getStreamID()); - OsdVector *osd=dynamic_cast(Osd::getInstance()); - if (osd) osd->getPictReader()->receivePicture(vresp); + LogNT::getInstance()->debug(TAG, "Image Pictures arrived VDR {:#x}", vresp->getStreamID()); + ImageLoader::getInstance()->downloadDone(vresp); + //OsdVector *osd=dynamic_cast(Osd::getInstance()); + //if (osd) osd->getPictReader()->receivePicture(vresp); // else delete vresp; //nonsense // only rpi does CHANNEL_TVMEDIA, rpi has osdvector. therefore, can't get here. r_deregisterEDR = true; @@ -1689,249 +1691,288 @@ void VDR::getScraperEventType(UINT channelid, UINT eventid, int & movieID, MovieInfo *VDR::getScraperMovieInfo(int movieID) { - VDR_RequestPacket vrp; - if (!vrp.init(VDR_GETSCRAPERMOVIEINFO, false, 0)) return NULL; - if (!vrp.addULONG(movieID)) return NULL; - VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (vresp->noResponse()) { delete vresp; return NULL; } - MovieInfo * movieinf= new MovieInfo(); - - movieinf->id=movieID; - movieinf->title = vresp->extractStdString(); - movieinf->originalTitle = vresp->extractStdString(); - movieinf->tagline = vresp->extractStdString(); - movieinf->overview = vresp->extractStdString(); - movieinf->adult = vresp->extractUCHAR(); - movieinf->collectionName = vresp->extractStdString(); - - movieinf->budget = vresp->extractLONG(); - movieinf->revenue = vresp->extractLONG(); - movieinf->genres = vresp->extractStdString(); - movieinf->homepage = vresp->extractStdString(); - movieinf->releaseDate = vresp->extractStdString(); - movieinf->runtime = vresp->extractLONG(); - movieinf->popularity = vresp->extractdouble(); - movieinf->voteAverage = vresp->extractdouble(); - movieinf->poster.width = vresp->extractULONG(); - movieinf->poster.height = vresp->extractULONG(); - movieinf->poster.info.setMovieInfo(movieinf); - movieinf->poster.info.setElement(0,0); - movieinf->fanart.width = vresp->extractULONG(); - movieinf->fanart.height = vresp->extractULONG(); - movieinf->fanart.info.setMovieInfo(movieinf); - movieinf->fanart.info.setElement(1,0); - movieinf->collectionPoster.width = vresp->extractULONG(); - movieinf->collectionPoster.height = vresp->extractULONG(); - movieinf->collectionPoster.info.setMovieInfo(movieinf); - movieinf->collectionPoster.info.setElement(2,0); - movieinf->collectionFanart.width = vresp->extractULONG(); - movieinf->collectionFanart.height = vresp->extractULONG(); - movieinf->collectionFanart.info.setMovieInfo(movieinf); - movieinf->collectionFanart.info.setElement(3,0); - ULONG num_actors = vresp->extractULONG(); - movieinf->actors.clear(); - movieinf->actors.reserve(num_actors); - for (ULONG acty=0; acty < num_actors; acty++) { - Actor new_act; - new_act.name = vresp->extractStdString(); - new_act.role = vresp->extractStdString(); - new_act.thumb.width = vresp->extractULONG(); - new_act.thumb.height = vresp->extractULONG(); - new_act.thumb.info.setMovieInfo(movieinf); - new_act.thumb.info.setElement(4,acty); - movieinf->actors.push_back(new_act); - } + ImageLoader* imageLoader = ImageLoader::getInstance(); + VDR_RequestPacket vrp; + if (!vrp.init(VDR_GETSCRAPERMOVIEINFO, false, 0)) return NULL; + if (!vrp.addULONG(movieID)) return NULL; + VDR_ResponsePacket* vresp = RequestResponse(&vrp); + if (vresp->noResponse()) { delete vresp; return NULL; } + MovieInfo* movieinf = new MovieInfo; + + ImageGeneric imageGeneric1 = imageLoader->createGeneric(); + movieinf->poster.image = imageGeneric1; + + ImageGeneric imageGeneric2 = imageLoader->createGeneric(); + movieinf->fanart.image = imageGeneric2; + + ImageGeneric imageGeneric3 = imageLoader->createGeneric(); + movieinf->collectionPoster.image = imageGeneric3; + + ImageGeneric imageGeneric4 = imageLoader->createGeneric(); + movieinf->collectionFanart.image = imageGeneric4; + + movieinf->id=movieID; + movieinf->title = vresp->extractStdString(); + movieinf->originalTitle = vresp->extractStdString(); + movieinf->tagline = vresp->extractStdString(); + movieinf->overview = vresp->extractStdString(); + movieinf->adult = vresp->extractUCHAR(); + movieinf->collectionName = vresp->extractStdString(); + + movieinf->budget = vresp->extractLONG(); + movieinf->revenue = vresp->extractLONG(); + movieinf->genres = vresp->extractStdString(); + movieinf->homepage = vresp->extractStdString(); + movieinf->releaseDate = vresp->extractStdString(); + movieinf->runtime = vresp->extractLONG(); + movieinf->popularity = vresp->extractdouble(); + movieinf->voteAverage = vresp->extractdouble(); + movieinf->poster.width = vresp->extractULONG(); + movieinf->poster.height = vresp->extractULONG(); + imageGeneric1->setMovieInfo(movieinf); + imageGeneric1->setElement(0,0); + movieinf->fanart.width = vresp->extractULONG(); + movieinf->fanart.height = vresp->extractULONG(); + imageGeneric2->setMovieInfo(movieinf); + imageGeneric2->setElement(1,0); + movieinf->collectionPoster.width = vresp->extractULONG(); + movieinf->collectionPoster.height = vresp->extractULONG(); + imageGeneric3->setMovieInfo(movieinf); + imageGeneric3->setElement(2,0); + movieinf->collectionFanart.width = vresp->extractULONG(); + movieinf->collectionFanart.height = vresp->extractULONG(); + imageGeneric4->setMovieInfo(movieinf); + imageGeneric4->setElement(3,0); + ULONG num_actors = vresp->extractULONG(); + movieinf->actors.clear(); + movieinf->actors.reserve(num_actors); + for (ULONG acty=0; acty < num_actors; acty++) + { + Actor new_act; + ImageGeneric newActImageGeneric = imageLoader->createGeneric(); + new_act.thumb.image = newActImageGeneric; + + new_act.name = vresp->extractStdString(); + new_act.role = vresp->extractStdString(); + new_act.thumb.width = vresp->extractULONG(); + new_act.thumb.height = vresp->extractULONG(); + newActImageGeneric->setMovieInfo(movieinf); + newActImageGeneric->setElement(4,acty); + movieinf->actors.push_back(new_act); + imageLoader->ensureLoaded(newActImageGeneric); + } - delete vresp; - return movieinf; + imageLoader->ensureLoaded(imageGeneric1); + imageLoader->ensureLoaded(imageGeneric2); + imageLoader->ensureLoaded(imageGeneric3); + imageLoader->ensureLoaded(imageGeneric4); + delete vresp; + return movieinf; } -SeriesInfo *VDR::getScraperSeriesInfo(int seriesID, int episodeID) +SeriesInfo* VDR::getScraperSeriesInfo(int seriesID, int episodeID) { - VDR_RequestPacket vrp; - if (!vrp.init(VDR_GETSCRAPERSERIESINFO, false, 0)) return NULL; - if (!vrp.addULONG(seriesID)) return NULL; - if (!vrp.addULONG(episodeID)) return NULL; + ImageLoader* imageLoader = ImageLoader::getInstance(); - VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (vresp->noResponse()) { delete vresp; return 0; } - SeriesInfo * seriesinf= new SeriesInfo(); - - seriesinf->id=seriesID; - - - seriesinf->name = vresp->extractStdString(); - seriesinf->overview = vresp->extractStdString(); - seriesinf->firstAired = vresp->extractStdString(); - seriesinf->network = vresp->extractStdString(); - seriesinf->genre = vresp->extractStdString(); - seriesinf->rating = vresp->extractdouble(); - seriesinf->status = vresp->extractStdString(); - - - seriesinf->episode.episodeid=episodeID; - seriesinf->episode.number = vresp->extractLONG(); - seriesinf->episode.season = vresp->extractLONG(); - seriesinf->episode.name = vresp->extractStdString(); - seriesinf->episode.firstAired = vresp->extractStdString(); - seriesinf->episode.guestStars = vresp->extractStdString(); - seriesinf->episode.overview = vresp->extractStdString(); - seriesinf->episode.rating = vresp->extractdouble(); - seriesinf->episode.image.width = vresp->extractULONG(); - seriesinf->episode.image.height = vresp->extractULONG(); - seriesinf->episode.image.info.setSeriesInfo(seriesinf); - seriesinf->episode.image.info.setElement(0,0); - - - ULONG num_actors = vresp->extractULONG(); - seriesinf->actors.clear(); - seriesinf->actors.reserve(num_actors); - for (ULONG acty=0; acty < num_actors; acty++) { - Actor new_act; - new_act.name = vresp->extractStdString(); - new_act.role = vresp->extractStdString(); - new_act.thumb.width = vresp->extractULONG(); - new_act.thumb.height = vresp->extractULONG(); - new_act.thumb.info.setSeriesInfo(seriesinf); - new_act.thumb.info.setElement(1,acty); - seriesinf->actors.push_back(new_act); - } - ULONG num_posters = vresp->extractULONG(); - for (ULONG medias = 0; medias < num_posters; medias++ ) { - TVMedia media; - media.info.setSeriesInfo(seriesinf); - media.info.setElement(2,medias); - media.width = vresp->extractULONG(); - media.height = vresp->extractULONG(); - seriesinf->posters.push_back(media); - } + VDR_RequestPacket vrp; + if (!vrp.init(VDR_GETSCRAPERSERIESINFO, false, 0)) return NULL; + if (!vrp.addULONG(seriesID)) return NULL; + if (!vrp.addULONG(episodeID)) return NULL; - ULONG num_banners = vresp->extractULONG(); - for (ULONG medias = 0; medias < num_banners; medias++ ) { - TVMedia media; - media.info.setSeriesInfo(seriesinf); - media.info.setElement(3,medias); - media.width = vresp->extractULONG(); - media.height = vresp->extractULONG(); - seriesinf->banners.push_back(media); - } - ULONG num_fanarts = vresp->extractULONG(); - for (ULONG medias = 0; medias < num_fanarts; medias++ ) { - TVMedia media; - media.info.setSeriesInfo(seriesinf); - media.info.setElement(4,medias); - media.width = vresp->extractULONG(); - media.height = vresp->extractULONG(); - seriesinf->fanart.push_back(media); - } - seriesinf->seasonposter.width = vresp->extractULONG(); - seriesinf->seasonposter.height = vresp->extractULONG(); - seriesinf->seasonposter.info.setSeriesInfo(seriesinf); - seriesinf->seasonposter.info.setElement(5,0); + VDR_ResponsePacket* vresp = RequestResponse(&vrp); + if (vresp->noResponse()) { delete vresp; return 0; } + SeriesInfo* seriesinf = new SeriesInfo(); + + ImageGeneric imageGeneric1 = imageLoader->createGeneric(); + Image imageBase1 = imageGeneric1; + seriesinf->episode.image.image = imageBase1; + + ImageGeneric imageGeneric2 = imageLoader->createGeneric(); + Image imageBase2 = imageGeneric2; + seriesinf->seasonposter.image = imageBase2; + + seriesinf->id = seriesID; + + seriesinf->name = vresp->extractStdString(); + seriesinf->overview = vresp->extractStdString(); + seriesinf->firstAired = vresp->extractStdString(); + seriesinf->network = vresp->extractStdString(); + seriesinf->genre = vresp->extractStdString(); + seriesinf->rating = vresp->extractdouble(); + seriesinf->status = vresp->extractStdString(); + + + seriesinf->episode.episodeid=episodeID; + seriesinf->episode.number = vresp->extractLONG(); + seriesinf->episode.season = vresp->extractLONG(); + seriesinf->episode.name = vresp->extractStdString(); + seriesinf->episode.firstAired = vresp->extractStdString(); + seriesinf->episode.guestStars = vresp->extractStdString(); + seriesinf->episode.overview = vresp->extractStdString(); + seriesinf->episode.rating = vresp->extractdouble(); + seriesinf->episode.image.width = vresp->extractULONG(); + seriesinf->episode.image.height = vresp->extractULONG(); + imageGeneric1->setSeriesInfo(seriesinf); + imageGeneric1->setElement(0,0); + + + ULONG num_actors = vresp->extractULONG(); + seriesinf->actors.clear(); + seriesinf->actors.reserve(num_actors); + for (ULONG acty=0; acty < num_actors; acty++) { + Actor new_act; + new_act.name = vresp->extractStdString(); + new_act.role = vresp->extractStdString(); + new_act.thumb.width = vresp->extractULONG(); + new_act.thumb.height = vresp->extractULONG(); + + ImageGeneric actorIG = imageLoader->createGeneric(); + new_act.thumb.image = actorIG; + actorIG->setSeriesInfo(seriesinf); + actorIG->setElement(1,acty); + seriesinf->actors.push_back(new_act); + + imageLoader->ensureLoaded(actorIG); + } + ULONG num_posters = vresp->extractULONG(); + for (ULONG medias = 0; medias < num_posters; medias++ ) { + TVMediaStruct media; + ImageGeneric mediaIG = imageLoader->createGeneric(); + media.image = mediaIG; + mediaIG->setSeriesInfo(seriesinf); + mediaIG->setElement(2, medias); + media.width = vresp->extractULONG(); + media.height = vresp->extractULONG(); + seriesinf->posters.push_back(media); + + imageLoader->ensureLoaded(mediaIG); + } - delete vresp; - return seriesinf; + ULONG num_banners = vresp->extractULONG(); + for (ULONG medias = 0; medias < num_banners; medias++ ) { + TVMediaStruct media; + ImageGeneric mediaIG = imageLoader->createGeneric(); + media.image = mediaIG; + mediaIG->setSeriesInfo(seriesinf); + mediaIG->setElement(3,medias); + media.width = vresp->extractULONG(); + media.height = vresp->extractULONG(); + seriesinf->banners.push_back(media); + + imageLoader->ensureLoaded(mediaIG); + } + ULONG num_fanarts = vresp->extractULONG(); + for (ULONG medias = 0; medias < num_fanarts; medias++ ) { + TVMediaStruct media; + ImageGeneric mediaIG = imageLoader->createGeneric(); + media.image = mediaIG; + mediaIG->setSeriesInfo(seriesinf); + mediaIG->setElement(4,medias); + media.width = vresp->extractULONG(); + media.height = vresp->extractULONG(); + seriesinf->fanart.push_back(media); + + imageLoader->ensureLoaded(mediaIG); + } + seriesinf->seasonposter.width = vresp->extractULONG(); + seriesinf->seasonposter.height = vresp->extractULONG(); + imageGeneric2->setSeriesInfo(seriesinf); + imageGeneric2->setElement(5,0); + imageLoader->ensureLoaded(imageGeneric1); + imageLoader->ensureLoaded(imageGeneric2); + + delete vresp; + return seriesinf; } -ULONG VDR::loadTVMedia(TVMediaInfo& tvmedia) +bool VDR::loadImageGeneric(ImageGeneric& image) { - VDR_RequestPacket vrp; - - if (!vrp.init(VDR_LOADTVMEDIA, false, 0)) return ULONG_MAX; - if (!vrp.addULONG(tvmedia.type)) return ULONG_MAX; - if (!vrp.addULONG(tvmedia.primary_id)) return ULONG_MAX; - if (!vrp.addULONG(tvmedia.secondary_id)) return ULONG_MAX; - if (!vrp.addULONG(tvmedia.type_pict)) return ULONG_MAX; - if (!vrp.addULONG(tvmedia.container)) return ULONG_MAX; - if (!vrp.addULONG(tvmedia.container_member)) return ULONG_MAX; -/* logger->debug(TAG, "TVMedia with ID {} {}; {} {} {} {};{}", - tvmedia.primary_id,tvmedia.secondary_id,tvmedia.type,tvmedia.type_pict, - tvmedia.container,tvmedia.container_member,vrp.getSerial());*/ - - - VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); - vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA; - vdrpr->streamID = vrp.getSerial(); - vdrpr->streamReceiver = NULL; - edRegister(vdrpr); - + VDR_RequestPacket vrp; - VDR_ResponsePacket* vresp = RequestResponse(&vrp); - //if (vresp->noResponse()) { delete vresp; return ULONG_MAX; } - delete vresp; + if (!vrp.init(VDR_LOADTVMEDIA, false, 0)) return false; + if (!vrp.addULONG(image->getType())) return false; + if (!vrp.addULONG(image->primary_id)) return false; + if (!vrp.addULONG(image->secondary_id)) return false; + if (!vrp.addULONG(image->type_pict)) return false; + if (!vrp.addULONG(image->container)) return false; + if (!vrp.addULONG(image->container_member)) return false; + logger->debug(TAG, "Image with ID {} {}; {} {} {} {};{}", + image->primary_id,image->secondary_id,image->type,image->type_pict, + image->container,image->container_member,vrp.getSerial()); + +// FIXME - ImageLoader should register itself as a permenant stream receiver instead of making temporary ones like this + VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); + vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA; + vdrpr->streamID = vrp.getSerial(); + vdrpr->streamReceiver = NULL; + edRegister(vdrpr); - return vrp.getSerial(); + VDR_ResponsePacket* vresp = RequestResponse(&vrp); + bool ret = !vresp->noResponse(); + delete vresp; + return ret; } -ULONG VDR::loadTVMediaRecThumb(TVMediaInfo & media) +bool VDR::loadImageRecThumb(ImageRecThumb& image) // FIXME convert return to bool { + VDR_RequestPacket vrp; - VDR_RequestPacket vrp; - - if (!vrp.init(VDR_LOADTVMEDIARECTHUMB, false, 0)) return ULONG_MAX; - if (!vrp.addString(media.primary_name.c_str())) return ULONG_MAX; - - VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); - vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA; - vdrpr->streamID = vrp.getSerial(); - vdrpr->streamReceiver = NULL; - edRegister(vdrpr); - + if (!vrp.init(VDR_LOADTVMEDIARECTHUMB, false, 0)) return false; + if (!vrp.addString(image->getFileName())) return false; + image->setServerLoadingRef(vrp.getSerial()); - VDR_ResponsePacket* vresp = RequestResponse(&vrp); - //if (vresp->noResponse()) { delete vresp; return ULONG_MAX; } - delete vresp; + VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); + vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA; + vdrpr->streamID = vrp.getSerial(); + vdrpr->streamReceiver = NULL; + edRegister(vdrpr); - return vrp.getSerial(); + VDR_ResponsePacket* vresp = RequestResponse(&vrp); + bool ret = !vresp->noResponse(); + delete vresp; + return ret; } -ULONG VDR::loadTVMediaEventThumb(TVMediaInfo & media) +bool VDR::loadImageEventThumb(ImageEventThumb& image) { + VDR_RequestPacket vrp; - VDR_RequestPacket vrp; - - if (!vrp.init(VDR_LOADTVMEDIAEVENTTHUMB, false, 0)) return ULONG_MAX; - if (!vrp.addULONG(media.primary_id)) return ULONG_MAX; - if (!vrp.addULONG(media.secondary_id)) return ULONG_MAX; - - VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); - vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA; - vdrpr->streamID = vrp.getSerial(); - vdrpr->streamReceiver = NULL; - edRegister(vdrpr); - + if (!vrp.init(VDR_LOADTVMEDIAEVENTTHUMB, false, 0)) return false; + if (!vrp.addULONG(image->getChannel())) return false; + if (!vrp.addULONG(image->getEvent())) return false; + image->setServerLoadingRef(vrp.getSerial()); - VDR_ResponsePacket* vresp = RequestResponse(&vrp); - //if (vresp->noResponse()) { delete vresp; return ULONG_MAX; } - delete vresp; + VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); + vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA; + vdrpr->streamID = vrp.getSerial(); + vdrpr->streamReceiver = NULL; + edRegister(vdrpr); - return vrp.getSerial(); + VDR_ResponsePacket* vresp = RequestResponse(&vrp); + bool ret = !vresp->noResponse(); + delete vresp; + return ret; } -ULONG VDR::loadChannelLogo(TVMediaInfo & media) +bool VDR::loadImageChannelLogo(ImageChannelLogo& image) { + VDR_RequestPacket vrp; - VDR_RequestPacket vrp; - - if (!vrp.init(VDR_LOADCHANNELLOGO, false, 0)) return ULONG_MAX; - if (!vrp.addULONG(media.primary_id)) return ULONG_MAX; - - VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); - vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA; - vdrpr->streamID = vrp.getSerial(); - vdrpr->streamReceiver = NULL; - edRegister(vdrpr); - + if (!vrp.init(VDR_LOADCHANNELLOGO, false, 0)) return false; + if (!vrp.addULONG(image->getChannelID())) return false; + image->setServerLoadingRef(vrp.getSerial()); - VDR_ResponsePacket* vresp = RequestResponse(&vrp); - //if (vresp->noResponse()) { delete vresp; return ULONG_MAX; } - delete vresp; - -// logger->debug(TAG, "TVMedia Channel Logo {} {:#x}", -// media.primary_id,vrp.getSerial()); + VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); + vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA; + vdrpr->streamID = vrp.getSerial(); + vdrpr->streamReceiver = NULL; + edRegister(vdrpr); - return vrp.getSerial(); + VDR_ResponsePacket* vresp = RequestResponse(&vrp); + bool ret = !vresp->noResponse(); + delete vresp; + return ret; } diff --git a/vdr.h b/vdr.h index adb6178..ef29c67 100644 --- a/vdr.h +++ b/vdr.h @@ -44,6 +44,7 @@ #include "i18n.h" #include "control.h" #include "tcp.h" +#include "image.h" class RecInfo; class Event; @@ -55,7 +56,6 @@ class SerializeBuffer; #endif class MovieInfo; class SeriesInfo; -class TVMediaInfo; typedef std::vector EventList; typedef std::vector ChannelList; @@ -201,14 +201,13 @@ public ExternLogger //TV Scraper support void getScraperEventType(char * fileName, int & movieID, int & seriesID, int & episodeID); void getScraperEventType(UINT eventid, UINT channelid, int & movieID, int & seriesID, int & episodeID, int & epgImage); - MovieInfo *getScraperMovieInfo(int movieID); - SeriesInfo *getScraperSeriesInfo(int seriesID, int episodeID); - ULONG loadTVMedia(TVMediaInfo& tvmedia); - ULONG loadTVMediaRecThumb(TVMediaInfo& tvmedia); - ULONG loadTVMediaEventThumb(TVMediaInfo& tvmedia); - ULONG loadChannelLogo(TVMediaInfo& tvmedia); - void invalidateTVMedia(ULONG loadindex); + MovieInfo* getScraperMovieInfo(int movieID); + SeriesInfo* getScraperSeriesInfo(int seriesID, int episodeID); + bool loadImageGeneric(ImageGeneric& image); + bool loadImageRecThumb(ImageRecThumb& image); + bool loadImageEventThumb(ImageEventThumb& image); + bool loadImageChannelLogo(ImageChannelLogo& image); I18n::lang_code_list getLanguageList(); int getLanguageContent(const std::string code, I18n::trans_table&); diff --git a/vdrresponsepacket.cc b/vdrresponsepacket.cc index 83713c1..aaf8aaa 100644 --- a/vdrresponsepacket.cc +++ b/vdrresponsepacket.cc @@ -18,13 +18,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -// FIXME - -#include "vdrresponsepacket.h" - +#include "util.h" #include "vdr.h" -#include "util.h" +#include "vdrresponsepacket.h" VDR_ResponsePacket::VDR_ResponsePacket() { diff --git a/vepg.cc b/vepg.cc index f0a11a8..150faa2 100644 --- a/vepg.cc +++ b/vepg.cc @@ -43,6 +43,7 @@ #include "channel.h" #include "i18n.h" #include "log.h" +#include "osd.h" #include "vepg.h" diff --git a/vepglistadvanced.cc b/vepglistadvanced.cc index dea8b6b..3b81ebf 100644 --- a/vepglistadvanced.cc +++ b/vepglistadvanced.cc @@ -37,6 +37,8 @@ #include "vepgsettimer.h" #include "vepg.h" #include "staticartwork.h" +#include "image.h" +#include "imageloader.h" #include "vepglistadvanced.h" @@ -58,10 +60,8 @@ VEpgListAdvanced::VEpgListAdvanced(MessageReceiver* tvideolive, std::shared_ptr< setTitleBarOn(1); setTitleBarColour(DrawStyle::TITLEBARBACKGROUND); - TVMediaInfo* info = new TVMediaInfo(); - info->setChannelLogo(channelNumber); - info->setStaticFallback(sa_tv); - setTitleBarIcon(info); + Image icon = ImageLoader::getInstance()->createChannelLogo(channelNumber, sa_tv); + setTitleBarIcon(icon); sl.setPosition(10, 30 + 5); sl.setSize(area.w * 42 / 100 - 20, area.h - 30 - 15 - 30); @@ -236,9 +236,8 @@ void VEpgListAdvanced::doNext() mode = Next; updateEpgDataNowNext(true); setButtonText(); - TVMediaInfo* info = new TVMediaInfo(); - info->setStaticArtwork(sa_tv); - setTitleBarIcon(info); + Image icon = ImageLoader::getInstance()->createStatic(sa_tv); + setTitleBarIcon(icon); draw(true); boxstack->update(this); } @@ -257,9 +256,8 @@ void VEpgListAdvanced::doNow() mode = Now; updateEpgDataNowNext(true); setButtonText(); - TVMediaInfo* info = new TVMediaInfo(); - info->setStaticArtwork(sa_tv); - setTitleBarIcon(info); + Image icon = ImageLoader::getInstance()->createStatic(sa_tv); + setTitleBarIcon(icon); draw(true); boxstack->update(this); } @@ -273,10 +271,8 @@ void VEpgListAdvanced::doProgramm() channelNumber = chan->number; updateEpgDataChannel(); setButtonText(); - TVMediaInfo* info = new TVMediaInfo(); - info->setChannelLogo(channelNumber); - info->setStaticFallback(sa_tv); - setTitleBarIcon(info); + Image icon = ImageLoader::getInstance()->createChannelLogo(channelNumber, sa_tv); + setTitleBarIcon(icon); draw(true); boxstack->update(this); } @@ -513,12 +509,8 @@ void VEpgListAdvanced::drawDataChannel(bool doIndexPop) strftime(endTimeStr, 16, "%H:%M", &btime); std::string eventText = fmt::format("\t {}\n \t \t{} - {}", currentEvent->title, startTimeStr, endTimeStr); - // New TVMedia stuff - TVMediaInfo* info = new TVMediaInfo(); - info->setPosterThumb(channelNumber, currentEvent->id); - info->setStaticFallback(sa_defposter); - - currentEvent->index = sl.addOption(eventText, reinterpret_cast(currentEvent->id), first, info); + Image icon = ImageLoader::getInstance()->createEventThumb(channelNumber, currentEvent->id); + currentEvent->index = sl.addOption(eventText, reinterpret_cast(currentEvent->id), first, icon); first = 0; } } @@ -590,7 +582,6 @@ void VEpgListAdvanced::drawDataNowNext(bool next, bool doIndexPop) eventText = fmt::format("\n{}", chan->name); } - TVMediaInfo* info = new TVMediaInfo(); if ((*chanList)[listIndex]->number == channelNumber) { @@ -598,9 +589,8 @@ void VEpgListAdvanced::drawDataNowNext(bool next, bool doIndexPop) setcurrenthelper = listIndex; } - info->setChannelLogo((*chanList)[listIndex]->number); - info->setStaticFallback(sa_tv); - int index = sl.addOption(eventText, reinterpret_cast(listIndex), first, info); + Image icon = ImageLoader::getInstance()->createChannelLogo((*chanList)[listIndex]->number, sa_tv); + int index = sl.addOption(eventText, reinterpret_cast(listIndex), first, icon); if (currentEvent) currentEvent->index = index; @@ -729,10 +719,8 @@ void VEpgListAdvanced::updateSelection() if (mode == OneChannel) { - TVMediaInfo* info = new TVMediaInfo(); - info->setChannelLogo(channelNumber); - info->setStaticFallback(sa_tv); - setTitleBarIcon(info); + Image icon = ImageLoader::getInstance()->createChannelLogo(channelNumber, sa_tv); + setTitleBarIcon(icon); } Event* toShow = getCurrentOptionEvent(channel); @@ -746,7 +734,7 @@ void VEpgListAdvanced::updateSelection() description << toShow->subtitle << "\n"; description << toShow->description; - TVMedia poster; + TVMediaStruct poster; poster.height = 0; if (toShow->movieInfo) @@ -768,23 +756,21 @@ void VEpgListAdvanced::updateSelection() if (poster.height) { - epgTVmedia.setTVMedia(poster.info, WTVMedia::ZoomHorizontal); + epgTVmedia.setImage(poster.image, WTVMedia::ZoomHorizontal); epgTVmedia.setVisible(true); } else { if (toShow->epgImage) { - TVMediaInfo info; - info.setPosterThumb(channel, toShow->id); - epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal); + Image icon = ImageLoader::getInstance()->createEventThumb(channel, toShow->id); + epgTVmedia.setImage(icon, WTVMedia::ZoomHorizontal); epgTVmedia.setVisible(true); } else if (mode != OneChannel) { - TVMediaInfo info; - info.setChannelLogo(channel); - epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal); + Image icon = ImageLoader::getInstance()->createChannelLogo(channel); + epgTVmedia.setImage(icon, WTVMedia::ZoomHorizontal); epgTVmedia.setVisible(true); } else @@ -801,9 +787,8 @@ void VEpgListAdvanced::updateSelection() if (mode != OneChannel) { - TVMediaInfo info; - info.setChannelLogo(channel); - epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal); + Image icon = ImageLoader::getInstance()->createChannelLogo(channel); + epgTVmedia.setImage(icon, WTVMedia::ZoomHorizontal); epgTVmedia.setVisible(true); } else diff --git a/vepgsummary.cc b/vepgsummary.cc index 6d61eec..8dd5436 100644 --- a/vepgsummary.cc +++ b/vepgsummary.cc @@ -36,6 +36,7 @@ #include "wmovieview.h" #include "wseriesview.h" #include "wpictureview.h" +#include "imageloader.h" #include "vepgsummary.h" @@ -131,7 +132,7 @@ VEpgSummary::VEpgSummary(Event *tevent, Channel* tchannel) summary->add(&epgTVmedia); if (movieview) movieview->add(&epgTVmedia); if (seriesview) seriesview->add(&epgTVmedia); - TVMedia poster; + TVMediaStruct poster; poster.height=0; if (event->movieInfo) { poster=event->movieInfo->poster; @@ -146,7 +147,7 @@ VEpgSummary::VEpgSummary(Event *tevent, Channel* tchannel) } } if (poster.height) { - epgTVmedia.setTVMedia(poster.info, WTVMedia::ZoomHorizontal); + epgTVmedia.setImage(poster.image, WTVMedia::ZoomHorizontal); epgTVmedia.setVisible(true); } else { epgTVmedia.setVisible(false); diff --git a/vopts.cc b/vopts.cc index f396694..8efed3a 100644 --- a/vopts.cc +++ b/vopts.cc @@ -34,6 +34,7 @@ #include "message.h" #include "control.h" #include "staticartwork.h" +#include "imageloader.h" #ifdef VOMP_PLATTFORM_MVP #include "mediaoptions.h" @@ -48,9 +49,8 @@ VOpts::VOpts() setTitleBarOn(1); setTitleBarColour(DrawStyle::TITLEBARBACKGROUND); setTitleText(tr("Options")); - TVMediaInfo *info= new TVMediaInfo(); - info->setStaticArtwork(sa_properties); - setTitleBarIcon(info); + Image icon = ImageLoader::getInstance()->createStatic(sa_properties); + setTitleBarIcon(icon); setSize(520, 360); createBuffer(); diff --git a/vrecording.cc b/vrecording.cc index 366fff8..fd30f3c 100644 --- a/vrecording.cc +++ b/vrecording.cc @@ -163,9 +163,9 @@ void VRecording::draw() TBBoxx::draw(); OsdVector *osdv=dynamic_cast(Osd::getInstance()); if (osdv) { - TVMedia poster; + TVMediaStruct poster; // does not need any image creation, it's copying from an already made Movie/SeriesInfo object if (rec->movieInfo) { - poster=rec->movieInfo->poster; + poster = rec->movieInfo->poster; } if (rec->seriesInfo) { if (rec->seriesInfo->seasonposter.height) { @@ -178,7 +178,7 @@ void VRecording::draw() } if (poster.height) { // float aspect=((float)poster.height)/((float)poster.width)/Osd::getInstance()->getPixelAspect(); - drawTVMedia(poster.info, static_cast(buttonRegion.x), static_cast(tabbar.getY2() - 3), + drawImage(poster.image, static_cast(buttonRegion.x), static_cast(tabbar.getY2() - 3), static_cast(buttonRegion.w), /*buttonRegion.w*aspect*/ 0.f, BottomLeft); } } diff --git a/vrecordinglistadvanced.cc b/vrecordinglistadvanced.cc index 25be5e0..bdee168 100644 --- a/vrecordinglistadvanced.cc +++ b/vrecordinglistadvanced.cc @@ -42,6 +42,9 @@ #include "movieinfo.h" #include "seriesinfo.h" #include "staticartwork.h" +#include "image.h" +#include "imageloader.h" +#include "osd.h" #include "vrecordinglistadvanced.h" @@ -55,9 +58,9 @@ VRecordingListAdvanced::VRecordingListAdvanced() setTitleBarOn(1); setTitleBarColour(DrawStyle::TITLEBARBACKGROUND); - TVMediaInfo* info = new TVMediaInfo(); - info->setStaticArtwork(sa_recordings); - setTitleBarIcon(info); + + Image icon = ImageLoader::getInstance()->createStatic(sa_recordings); + setTitleBarIcon(icon); sl.setPosition(10, 30 + 5); sl.setSize(area.w*42/100 - 20, area.h - 30 - 15 - 30); @@ -105,15 +108,12 @@ void VRecordingListAdvanced::drawData(bool doIndexPop) currentSubDir = *i; std::string dirString = fmt::format("\t{} \n \t {}/{}", currentSubDir->name, currentSubDir->getNumNewRecordings(), currentSubDir->getNumRecordings()); - TVMediaInfo *info=new TVMediaInfo(); + Image icon; if (currentSubDir->recList.begin() != currentSubDir->recList.end()) { - info->setPosterThumb((*currentSubDir->recList.begin())->getFileName()); - info->setStaticFallback(sa_recfolder); - } else { - info->setStaticArtwork(sa_recfolder); + icon = ImageLoader::getInstance()->createRecFolder((*currentSubDir->recList.begin())->getFileName()); } - currentSubDir->index = sl.addOption(dirString, 0, first, info); + currentSubDir->index = sl.addOption(dirString, 0, first, icon); first = 0; } @@ -130,11 +130,8 @@ void VRecordingListAdvanced::drawData(bool doIndexPop) strftime(timeString, 16, "%d/%m/%y %H:%M", &btime); std::string fileString = fmt::format("{}\t{}\n \t{}", (currentRec->getNew() ? '*': ' '), currentRec->getProgName(), timeString); - // New TVMedia stuff - TVMediaInfo *info= new TVMediaInfo(); - info->setPosterThumb(currentRec->getFileName()); - info->setStaticFallback(sa_recording); - currentRec->index = sl.addOption(fileString, 0, first, info); + Image icon = ImageLoader::getInstance()->createRecThumb(currentRec->getFileName()); + currentRec->index = sl.addOption(fileString, 0, first, icon); first = 0; } @@ -233,7 +230,7 @@ void VRecordingListAdvanced::updateSelection() description << tr("Summary unavailable"); } - TVMedia poster; + TVMediaStruct poster; poster.height=0; if (toShow->movieInfo) { poster=toShow->movieInfo->poster; @@ -248,7 +245,7 @@ void VRecordingListAdvanced::updateSelection() } } if (poster.height) { - epgTVmedia.setTVMedia(poster.info, WTVMedia::ZoomHorizontal); + epgTVmedia.setImage(poster.image, WTVMedia::ZoomHorizontal); epgTVmedia.setVisible(true); } else { epgTVmedia.setVisible(false); diff --git a/vtimeredit.cc b/vtimeredit.cc index c11c282..c075133 100644 --- a/vtimeredit.cc +++ b/vtimeredit.cc @@ -29,6 +29,7 @@ #include "vquestion.h" #include "messagequeue.h" #include "staticartwork.h" +#include "imageloader.h" VTimerEdit::VTimerEdit(RecTimer* trt) { @@ -56,9 +57,8 @@ VTimerEdit::VTimerEdit(RecTimer* trt) setTitleBarOn(1); setTitleText(tr("Edit Timer")); setTitleBarColour(DrawStyle::TITLEBARBACKGROUND); - TVMediaInfo *info= new TVMediaInfo(); - info->setStaticArtwork(sa_timers); - setTitleBarIcon(info); + Image icon = ImageLoader::getInstance()->createStatic(sa_timers); + setTitleBarIcon(icon); MessageQueue::getInstance()->addReceiver(this); } diff --git a/vtimerlist.cc b/vtimerlist.cc index f588620..87c59e6 100644 --- a/vtimerlist.cc +++ b/vtimerlist.cc @@ -34,6 +34,7 @@ #include "vinfo.h" #include "log.h" #include "staticartwork.h" +#include "imageloader.h" #include "vtimerlist.h" @@ -66,9 +67,8 @@ VTimerList::VTimerList() setTitleBarOn(1); setTitleText(tr("Timers")); setTitleBarColour(DrawStyle::TITLEBARBACKGROUND); - TVMediaInfo *info= new TVMediaInfo(); - info->setStaticArtwork(sa_timers); - setTitleBarIcon(info); + Image icon = ImageLoader::getInstance()->createStatic(sa_timers); + setTitleBarIcon(icon); sl.setPosition(30, 30 + 5); sl.setSize(area.w - 40, area.h - 30 - 15 - 30); diff --git a/vvideolivetv.cc b/vvideolivetv.cc index cde08e4..837334a 100644 --- a/vvideolivetv.cc +++ b/vvideolivetv.cc @@ -46,6 +46,7 @@ #include "staticartwork.h" #include "demuxer.h" #include "messagequeue.h" +#include "imageloader.h" #include "vvideolivetv.h" @@ -112,14 +113,13 @@ VVideoLiveTV::VVideoLiveTV(std::shared_ptr tchanList, ULONG initial // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling okTriggeredOSD = false; - TVMediaInfo info; - info.setChannelLogo(initialChannelNumber); + Image icon = ImageLoader::getInstance()->createChannelLogo(initialChannelNumber); if (osdv && streamType == VDR::RADIO) { radioChannelLogo.setPosition(video->getScreenWidth()/4,video->getScreenHeight()/4); radioChannelLogo.setSize(video->getScreenWidth()/2,video->getScreenHeight()/2); radioChannelLogo.setVisible(true); - radioChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical); + radioChannelLogo.setImage(icon, WTVMedia::ZoomVertical); add(&radioChannelLogo); } @@ -142,7 +142,7 @@ VVideoLiveTV::VVideoLiveTV(std::shared_ptr tchanList, ULONG initial //osdChannelLogo.setBackgroundColour(DrawStyle::OSDBACKGROUND); osdChannelLogo.setPosition(30,5); osdChannelLogo.setSize(60,60); - osdChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical); + osdChannelLogo.setImage(icon, WTVMedia::ZoomVertical); osd.add(&osdChannelLogo); channellogomove = 30-5; boxdiff = 145; @@ -235,23 +235,24 @@ VVideoLiveTV::VVideoLiveTV(std::shared_ptr tchanList, ULONG initial if (osdv) { - TVMediaInfo ninfo; - ninfo.setStaticArtwork(sa_txtoff); + Image sIcon; + + sIcon = ImageLoader::getInstance()->createStatic(sa_txtoff); txtlogo.setPosition(54+4*boxdiff,104); txtlogo.setSize(22,20); - txtlogo.setTVMedia(ninfo, WTVMedia::ZoomVertical); + txtlogo.setImage(sIcon, WTVMedia::ZoomVertical); osd.add(&txtlogo); - ninfo.setStaticArtwork(sa_dolbyoff); + sIcon = ImageLoader::getInstance()->createStatic(sa_dolbyoff); dolbylogo.setPosition(54+4*boxdiff+15,104); dolbylogo.setSize(22,20); - dolbylogo.setTVMedia(ninfo, WTVMedia::ZoomVertical); + dolbylogo.setImage(sIcon, WTVMedia::ZoomVertical); osd.add(&dolbylogo); - ninfo.setStaticArtwork(sa_sd576i); + sIcon = ImageLoader::getInstance()->createStatic(sa_sd576i); reslogo.setPosition(54+4*boxdiff+30,104); reslogo.setSize(22,20); - reslogo.setTVMedia(ninfo, WTVMedia::ZoomVertical); + reslogo.setImage(sIcon, WTVMedia::ZoomVertical); osd.add(&reslogo); reslogo.setVisible(false); @@ -990,17 +991,16 @@ bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData) if (osdv) { - TVMediaInfo info; Channel* currentChannel = (*chanList)[currentChannelIndex]; if (currentChannel) { - info.setChannelLogo(currentChannel->number); + Image icon = ImageLoader::getInstance()->createChannelLogo(currentChannel->number); if (streamType == VDR::RADIO) { - radioChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical); + radioChannelLogo.setImage(icon, WTVMedia::ZoomVertical); radioChannelLogo.setVisible(true); } - osdChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical); + osdChannelLogo.setImage(icon, WTVMedia::ZoomVertical); } } @@ -1206,56 +1206,66 @@ void VVideoLiveTV::doAudioChannelSymbol() Channel* currentChannel = (*chanList)[osdChannelIndex]; bool multiAudio = false; - if (Audio::getInstance()->supportsAc3()) { - if ((currentChannel->numDPids+currentChannel->numAPids) > 1) multiAudio = true; + if (Audio::getInstance()->supportsAc3()) + { + if ((currentChannel->numDPids+currentChannel->numAPids) > 1) multiAudio = true; } if (currentChannel->numAPids > 1) multiAudio = true; // draw the doobery - if (!osdv) { - if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO; - else sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO; - sAudioChannels.setVisible(true); + if (!osdv) + { + if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO; + else sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO; + sAudioChannels.setVisible(true); } if (osdv) { - dolbylogo.setVisible(true); - txtlogo.setVisible(true); - TVMediaInfo info; - if (currentChannel->tpid!=0) info.setStaticArtwork(sa_txton); - else info.setStaticArtwork(sa_txtoff); - txtlogo.setTVMedia(info, WTVMedia::ZoomVertical); - - - if (Audio::getInstance()->supportsAc3() && currentChannel->numDPids>1) - info.setStaticArtwork(sa_dolbyon); - else info.setStaticArtwork(sa_dolbyoff); - dolbylogo.setTVMedia(info, WTVMedia::ZoomVertical); - - Demuxer* demux=Demuxer::getInstance(); - if (demux) { - int vertical_size=demux->getVerticalSize(); - LogNT::getInstance()->debug(TAG, "TVMedia vertical size {}", vertical_size); - reslogo.setVisible(true); - switch (vertical_size) { - case 576: - info.setStaticArtwork(sa_sd576i); - reslogo.setTVMedia(info, WTVMedia::ZoomVertical);break; - case 720: - info.setStaticArtwork(sa_hd720p); - reslogo.setTVMedia(info, WTVMedia::ZoomVertical);break; - case 1080: - info.setStaticArtwork(sa_hd1080i); - reslogo.setTVMedia(info, WTVMedia::ZoomVertical);break; - default: // we assume sd - reslogo.setVisible(false); - }; - - } else { - reslogo.setVisible(false); - } + dolbylogo.setVisible(true); + txtlogo.setVisible(true); + Image icon; + int sa_id; + + if (currentChannel->tpid!=0) sa_id = sa_txton; + else sa_id = sa_txtoff; + icon = ImageLoader::getInstance()->createStatic(sa_id); + txtlogo.setImage(icon, WTVMedia::ZoomVertical); + + if (Audio::getInstance()->supportsAc3() && currentChannel->numDPids>1) + sa_id = sa_dolbyon; + else + sa_id = sa_dolbyoff; + icon = ImageLoader::getInstance()->createStatic(sa_id); + dolbylogo.setImage(icon, WTVMedia::ZoomVertical); + Demuxer* demux=Demuxer::getInstance(); + if (demux) + { + int vertical_size = demux->getVerticalSize(); + LogNT::getInstance()->debug(TAG, "TVMedia vertical size {}", vertical_size); + reslogo.setVisible(true); + switch (vertical_size) + { + case 576: + icon = ImageLoader::getInstance()->createStatic(sa_sd576i); + reslogo.setImage(icon, WTVMedia::ZoomVertical); + break; + case 720: + icon = ImageLoader::getInstance()->createStatic(sa_hd720p); + reslogo.setImage(icon, WTVMedia::ZoomVertical); + break; + case 1080: + icon = ImageLoader::getInstance()->createStatic(sa_hd1080i); + reslogo.setImage(icon, WTVMedia::ZoomVertical); + break; + default: // we assume sd + reslogo.setVisible(false); + } + + } else { + reslogo.setVisible(false); + } } if (osd.getVisible()) @@ -1318,7 +1328,7 @@ void VVideoLiveTV::updatePosterBanner() if (toShow) { - TVMedia poster; + TVMediaStruct poster; poster.height=0; bool posterscale=true; if (toShow->movieInfo) { @@ -1335,7 +1345,7 @@ void VVideoLiveTV::updatePosterBanner() } } if (poster.height) { - osdposterbanner.setTVMedia(poster.info, posterscale ? WTVMedia::ZoomVertical : WTVMedia::ZoomHorizontal); + osdposterbanner.setImage(poster.image, posterscale ? WTVMedia::ZoomVertical : WTVMedia::ZoomHorizontal); osdposterbanner.setVisible(true); } else { osdposterbanner.setVisible(false); diff --git a/vvideorec.cc b/vvideorec.cc index a2b9a4c..5e7db3f 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -21,6 +21,7 @@ #include "control.h" #include "osd.h" +#include "osdvector.h" #include "wsymbol.h" #include "audio.h" #include "vdr.h" @@ -89,7 +90,7 @@ VVideoRec::VVideoRec(Recording* rec, bool ish264) createBuffer(); setBackgroundColour(DrawStyle::TRANSPARENT); - OsdVector* osdv=dynamic_cast(Osd::getInstance()); + OsdVector* osdv = dynamic_cast(Osd::getInstance()); if (osdv) { osdv->updateBackgroundColor(DrawStyle::BLACK); diff --git a/vwelcome.cc b/vwelcome.cc index 8a94fdf..e076273 100644 --- a/vwelcome.cc +++ b/vwelcome.cc @@ -35,6 +35,8 @@ #include "boxstack.h" #include "vopts.h" #include "staticartwork.h" +#include "image.h" +#include "imageloader.h" #include "vwelcome.h" @@ -79,9 +81,11 @@ VWelcome::VWelcome() #else vdr.setPosition(250, 65); vdr.setSize(180, 160); - TVMediaInfo sinfo; - sinfo.setStaticArtwork(sa_vdrlogo); - vdr.setTVMedia(sinfo, WTVMedia::ZoomHorizontal); + + ImageLoader* loader = ImageLoader::getInstance(); + + Image vdrImage = loader->createStatic(sa_vdrlogo); + vdr.setImage(vdrImage, WTVMedia::ZoomHorizontal); add(&vdr); #endif @@ -99,37 +103,32 @@ VWelcome::VWelcome() setTitleText(tr("Welcome")); + Image icon; - TVMediaInfo *info= new TVMediaInfo(); - info->setStaticArtwork(sa_tv); - sl.addOption(tr("1. Live TV"), reinterpret_cast(1), 1, info); + icon = loader->createStatic(sa_tv); + sl.addOption(tr("1. Live TV"), reinterpret_cast(1), 1, icon); - info= new TVMediaInfo(); - info->setStaticArtwork(sa_radio); - sl.addOption(tr("2. Radio"), reinterpret_cast(2), 0, info); + icon = loader->createStatic(sa_radio); + sl.addOption(tr("2. Radio"), reinterpret_cast(2), 0, icon); - info= new TVMediaInfo(); - info->setStaticArtwork(sa_recordings); - sl.addOption(tr("3. Recordings"), reinterpret_cast(3), 0, info); + icon = loader->createStatic(sa_recordings); + sl.addOption(tr("3. Recordings"), reinterpret_cast(3), 0, icon); - info= new TVMediaInfo(); - info->setStaticArtwork(sa_timers); - sl.addOption(tr("4. Timers"), reinterpret_cast(4), 0, info); + icon = loader->createStatic(sa_timers); + sl.addOption(tr("4. Timers"), reinterpret_cast(4), 0, icon); #ifdef VOMP_PLATTFORM_MVP sl.addOption(tr("5. MediaPlayer"), reinterpret_cast(5), 0); #endif - info= new TVMediaInfo(); - info->setStaticArtwork(sa_properties); - sl.addOption(tr("6. Options"), reinterpret_cast(6), 0,info); + icon = loader->createStatic(sa_properties); + sl.addOption(tr("6. Options"), reinterpret_cast(6), 0, icon); - info= new TVMediaInfo(); - info->setStaticArtwork(sa_restart); + icon = loader->createStatic(sa_restart); // NCONFIG #ifndef VOMP_HAS_EXIT - sl.addOption(tr("7. Reboot"), reinterpret_cast(7), 0,info); + sl.addOption(tr("7. Reboot"), reinterpret_cast(7), 0, icon); #else - sl.addOption(tr("7. Exit"), reinterpret_cast(7), 0,info); + sl.addOption(tr("7. Exit"), reinterpret_cast(7), 0, icon); #endif MessageQueue::getInstance()->addReceiver(this); diff --git a/wpictureview.cc b/wpictureview.cc index a0c876c..ddaa453 100644 --- a/wpictureview.cc +++ b/wpictureview.cc @@ -80,18 +80,18 @@ void WPictureView::draw() while (citty!=cur_pict.end()) { if (!const_height) { - drawTVMedia((*citty)->media, + drawImage((*citty)->media, xpos, ypos + max_height /*- (*citty)->h*/, (*citty)->w, /*(*citty)->h*/0.f,BottomLeft); } else { if (!(*citty)->banner) { - drawTVMedia((*citty)->media, + drawImage((*citty)->media, xpos+area.w*0.5f, ypos, 0.f, const_height,TopMiddle); } else { - drawTVMedia((*citty)->media, + drawImage((*citty)->media, xpos+area.w*0.5f, ypos, area.w-2.f, 0.f,TopMiddle); @@ -141,9 +141,9 @@ void WPictureView::draw() } -void WPictureView::addPicture(TVMediaInfo& pict, float pwidth, float pheight , bool banner, std::string caption, std::string caption2) +void WPictureView::addPicture(Image& pict, float pwidth, float pheight , bool banner, std::string caption, std::string caption2) { - pictures.push_back(Picture(pict,pwidth,pheight, banner, caption,caption2)); + pictures.push_back(Picture(pict, pwidth, pheight, banner, caption, caption2)); } int WPictureView::handleCommand(int command) @@ -219,7 +219,7 @@ WActorGallery::WActorGallery(Actors& actors) float height= aspect*width; //Log::getInstance()->log("WActorGallery", Log::DEBUG, "TVMedia %d %d %g", (*itty).thumb.width,(*itty).thumb.height,aspect); - addPicture((*itty).thumb.info, width, height, false,(*itty).name,"\""+(*itty).role+"\""); + addPicture((*itty).thumb.image, width, height, false,(*itty).name,"\""+(*itty).role+"\""); itty++; } } @@ -258,8 +258,8 @@ void WArtworkGallery::addTVMedias(TVMedias& medias, bool banner) } } -void WArtworkGallery::addTVMedia(TVMedia& media, bool banner) +void WArtworkGallery::addTVMedia(TVMediaStruct& media, bool banner) { if (media.width) - addPicture(media.info, media.width, media.height, banner); + addPicture(media.image, media.width, media.height, banner); } diff --git a/wpictureview.h b/wpictureview.h index 84e5032..01b98ea 100644 --- a/wpictureview.h +++ b/wpictureview.h @@ -28,6 +28,8 @@ #include "defines.h" #include "boxx.h" +#include "image.h" +#include "imageloader.h" class Colour; @@ -36,7 +38,7 @@ class WPictureView : public Boxx public: WPictureView(); virtual ~WPictureView(); - void addPicture(TVMediaInfo& pict, float width, float height,bool banner=false, std::string caption ="", std::string caption2 =""); + void addPicture(Image& pict, float width, float height,bool banner=false, std::string caption ="", std::string caption2 =""); void draw(); void setForegroundColour(const DrawStyle& fcolour); @@ -48,11 +50,12 @@ class WPictureView : public Boxx protected: class Picture { public: - Picture(TVMediaInfo tmedia,float width, float height, bool tbanner, std::string tcaption, std::string tcaption2){ + Picture(Image& tmedia, float width, float height, bool tbanner, std::string tcaption, std::string tcaption2) + { media=tmedia; caption=tcaption;caption2=tcaption2;w=width; h=height; banner=tbanner; } - TVMediaInfo media; + Image media; std::string caption; std::string caption2; float w; @@ -81,7 +84,7 @@ public: WArtworkGallery(SeriesInfo& series); protected: void addTVMedias(TVMedias& medias, bool banner=false); - void addTVMedia(TVMedia& media, bool banner=false); + void addTVMedia(TVMediaStruct& media, bool banner=false); }; diff --git a/wremoteconfig.h b/wremoteconfig.h index 764e476..23d9170 100644 --- a/wremoteconfig.h +++ b/wremoteconfig.h @@ -24,7 +24,7 @@ #include "boxx.h" #include "wselectlist.h" -class Input; +class InputMan; class Message; class WRemoteConfig : public Boxx diff --git a/wselectlist.cc b/wselectlist.cc index 21381fe..5ed2252 100644 --- a/wselectlist.cc +++ b/wselectlist.cc @@ -36,11 +36,6 @@ WSelectList::~WSelectList() void WSelectList::clear() { - int vsize = options.size(); - for (int i = 0; i < vsize; i++) - { - if (options[i].pict) delete options[i].pict; - } options.clear(); selectedOption = 0; @@ -70,27 +65,51 @@ void WSelectList::hintSetTop(int idx) topOption = idx; } -int WSelectList::addOption(const char* text, void* data, int selected, TVMediaInfo* pict) +int WSelectList::addOption(const char* text, void* data, int selected) +{ + int thisNewOption = options.size(); + + wsloption wslo; + wslo.text = text; + wslo.data = data; + options.push_back(wslo); + if (selected) selectedOption = thisNewOption; + return thisNewOption; +} + +int WSelectList::addOption(const std::string& text, void* data, int selected) +{ + int thisNewOption = options.size(); + + wsloption wslo; + wslo.text = text; + wslo.data = data; + options.push_back(wslo); + if (selected) selectedOption = thisNewOption; + return thisNewOption; +} + +int WSelectList::addOption(const char* text, void* data, int selected, Image& icon) { int thisNewOption = options.size(); wsloption wslo; wslo.text = text; wslo.data = data; - wslo.pict = pict; + wslo.image = icon; options.push_back(wslo); if (selected) selectedOption = thisNewOption; return thisNewOption; } -int WSelectList::addOption(const std::string& text, void* data, int selected, TVMediaInfo* pict) +int WSelectList::addOption(const std::string& text, void* data, int selected, Image& icon) { int thisNewOption = options.size(); wsloption wslo; wslo.text = text; wslo.data = data; - wslo.pict = pict; + wslo.image = icon; options.push_back(wslo); if (selected) selectedOption = thisNewOption; return thisNewOption; @@ -124,12 +143,12 @@ void WSelectList::draw() if (i == selectedOption && showseloption) { rectangle(0, ypos, area.w, static_cast(static_cast(fontHeight) * linesPerOption) - 1, darkseloption ? DrawStyle::SELECTDARKHIGHLIGHT : DrawStyle::SELECTHIGHLIGHT); - drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::DARKTEXT, options[i].pict); + drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::DARKTEXT, options[i].image); } else { rectangle(0, ypos, area.w, static_cast(static_cast(fontHeight) * linesPerOption) - 1, DrawStyle::SELECTBACKGROUND); - drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::LIGHTTEXT, options[i].pict); + drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::LIGHTTEXT, options[i].image); } ypos += ySeparation; } @@ -147,7 +166,7 @@ int WSelectList::getColumn(int x) return columns[x]; } -void WSelectList::drawOptionLine(const std::string& text, int xpos, int ypos, int width, const DrawStyle& colour, TVMediaInfo* pict) +void WSelectList::drawOptionLine(const std::string& text, int xpos, int ypos, int width, const DrawStyle& colour, Image& image) { UINT curline = 0; UINT taboffset = 0; @@ -157,10 +176,10 @@ void WSelectList::drawOptionLine(const std::string& text, int xpos, int ypos, in int imagewidth = 0; int xposmod = xpos; if (numColumns > 1) imagewidth = columns[1] - columns[0]; - if (pict) + if (image) { - drawTVMedia(*pict, static_cast(xpos), static_cast(ypos), static_cast(imagewidth), - static_cast(fontHeight) * linesPerOption, TopLeftLimited); + drawImage(image, static_cast(xpos), static_cast(ypos), static_cast(imagewidth), + static_cast(fontHeight) * linesPerOption, TopLeftLimited); taboffset++; xposmod += xpos; } diff --git a/wselectlist.h b/wselectlist.h index a76a9a1..14b122f 100644 --- a/wselectlist.h +++ b/wselectlist.h @@ -24,13 +24,14 @@ #include #include "defines.h" +#include "image.h" #include "boxx.h" typedef struct { std::string text; void* data; - TVMediaInfo* pict; + Image image; } wsloption; class WSelectList : public Boxx @@ -45,8 +46,11 @@ class WSelectList : public Boxx void setNoLoop(); void setShowSelOption(bool set) { showseloption = set; } void setDarkSelOption(bool set) { darkseloption = set; } - int addOption(const char* text, void* data, int selected, TVMediaInfo* pict = NULL); - int addOption(const std::string& text, void* data, int selected, TVMediaInfo* pict = NULL); + // FIXME 4 versions ! + int addOption(const char* text, void* data, int selected); + int addOption(const std::string& text, void* data, int selected); + int addOption(const char* text, void* data, int selected, Image& icon); + int addOption(const std::string& text, void* data, int selected, Image& icon); void draw(); void setBackgroundColour(const DrawStyle& colour); void setLinesPerOption(float lines) { linesPerOption = lines; } @@ -71,7 +75,7 @@ class WSelectList : public Boxx virtual bool mouseAndroidScroll(int x, int y, int sx, int sy); private: - void drawOptionLine(const std::string& text, int xpos, int ypos, int width, const DrawStyle& colour, TVMediaInfo* pict); + void drawOptionLine(const std::string& text, int xpos, int ypos, int width, const DrawStyle& colour, Image& icon); int getMouseLine(int x, int y); DrawStyle backgroundColour; diff --git a/wtvmedia.cc b/wtvmedia.cc index a6815c2..14ad82d 100644 --- a/wtvmedia.cc +++ b/wtvmedia.cc @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon, 2014 Marten Richter + Copyright 2004-2005,2021 Chris Tallon, 2014 Marten Richter This file is part of VOMP. @@ -14,57 +14,50 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + along with VOMP. If not, see . */ -#include "boxx.h" -#include "wtvmedia.h" - - - - - WTVMedia::WTVMedia() - { - media = false; - scale=NoZoom; - } - - WTVMedia::~WTVMedia() - { - } - - - - void WTVMedia::setTVMedia(TVMediaInfo & ninfo, Scaling nscale) - { - info = ninfo; - scale = nscale; - media =true; - } - - void WTVMedia::draw() - { - //Boxx::draw(); - if (!media) return; - float w=0; - float h=0; - switch (scale) - { - case ZoomHorizontal: - w = static_cast(area.w); - break; - case ZoomVertical: - h = static_cast(area.h); - break; - case ZoomBoth: - w = static_cast(area.w); - h = static_cast(area.h); - break; +#include "boxx.h" - case NoZoom: - ; // ? - } - drawTVMedia(info,0.f,0.f,w,h,TopLeft); +#include "wtvmedia.h" - } +WTVMedia::WTVMedia() +{ + media = false; + scale = NoZoom; +} + +WTVMedia::~WTVMedia() +{ +} + +void WTVMedia::setImage(Image& tImage, Scaling nscale) +{ + image = tImage; + scale = nscale; + media = true; +} + +void WTVMedia::draw() +{ + //Boxx::draw(); + if (!media) return; + float w=0; + float h=0; + switch (scale) + { + case ZoomHorizontal: + w = static_cast(area.w); + break; + case ZoomVertical: + h = static_cast(area.h); + break; + case ZoomBoth: + w = static_cast(area.w); + h = static_cast(area.h); + break; + case NoZoom: + ; // ? + } + drawImage(image,0.f,0.f,w,h,TopLeft); +} diff --git a/wtvmedia.h b/wtvmedia.h index 17708be..ebf10b6 100644 --- a/wtvmedia.h +++ b/wtvmedia.h @@ -14,19 +14,14 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + along with VOMP. If not, see . */ #ifndef WTVMEDIA_H #define WTVMEDIA_H -#include -#include #include "boxx.h" - - - +#include "image.h" class WTVMedia : public Boxx { @@ -34,22 +29,21 @@ class WTVMedia : public Boxx WTVMedia(); virtual ~WTVMedia(); - enum Scaling { - NoZoom, - ZoomHorizontal, - ZoomVertical, - ZoomBoth + enum Scaling + { + NoZoom, + ZoomHorizontal, + ZoomVertical, + ZoomBoth }; - void setTVMedia(TVMediaInfo & info, Scaling scale); + void setImage(Image& image, Scaling scale); void draw(); protected: - TVMediaInfo info; + Image image; Scaling scale; bool media; }; - - #endif -- 2.39.5