int OsdOpenVG::init(void* device)
{
if (initted) return 0;
+ reader.init();
Video* video = Video::getInstance();
//window=*((HWND*)device);
int OsdOpenVG::shutdown()
{
+ reader.shutdown();
if (!initted) return 0;
initted = 0;
//Log::getInstance()->log("OSD", Log::DEBUG, "Draw create file %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
return handle;
} break;
+ case OVGcreateImageMemory: {
+ PictureInfo *info = (PictureInfo*) command.data;
+ VGImage handle;
+ //Log::getInstance()->log("OSD", Log::DEBUG, "TVMedia OVGcreateImageMemory");
+ handle=vgCreateImage(VG_sXBGR_8888,info->width,info->height,VG_IMAGE_QUALITY_BETTER);
+ vgImageSubData(handle,info->image,info->width*4,
+ VG_sXBGR_8888,0,0,info->width,info->height);
+ info->decoder->freeReference(info->reference);
+ Message* m = new Message();
+ // We have a pictures! send a message to ourself, to switch to gui thread
+ m->message=Message::NEW_PICTURE;
+ m->from=this;
+ m->to=Command::getInstance();
+ m->parameter = handle;
+ m->tag = info->lindex;
+ Command::getInstance()->postMessageFromOuterSpace(m); // inform command about new picture
+
+ delete info;
+
+ } break;
+
case OVGcreateColorRef :{
VGPaint handle;
handle=vgCreatePaint();
vgmutex.Lock();
while (vgcommands.size()>0)
{
- OpenVGCommand &comm=vgcommands.front();
+ OpenVGCommand comm=vgcommands.front();
+ vgcommands.pop_front();
+ taskmutex.Unlock();
+
OpenVGResponse resp;
resp.result=handleTask(comm);
resp.id=comm.id;
+ taskmutex.Lock();
if (comm.id) {
vgresponses.push_back(resp);
}
- vgcommands.pop_front();
taskmutex.Unlock();
vgmutex.Unlock();
//threadCheckExit();
ImageIndex OsdOpenVG::createJpeg(const char* fileName, int *width,int *height)
{
Image* magicimage=NULL;
- bool mem=false;
struct OpenVGCommand comm;
comm.task=OVGcreateImageFile;
return putOpenVGCommand(comm,true);
}
-ImageIndex OsdOpenVG::createPicture(unsigned char *data, unsigned int length)
+void OsdOpenVG::createPicture(struct PictureInfo& pict_inf)
{
- Image* magicimage=NULL;
- bool mem=false;
struct OpenVGCommand comm;
- comm.task=OVGcreateImageFile;
+ if (pict_inf.type == PictureInfo::RGBAMemBlock) {
+ comm.task = OVGcreateImageMemory;
+ comm.data = new PictureInfo(pict_inf);
+ putOpenVGCommand(comm,false);
+ } else {
+ // unsupported
+ pict_inf.decoder->freeReference(pict_inf.reference);
- try{
- // Now figure out, if it is a special case
- //Log::getInstance()->log("OSD", Log::DEBUG, "createPicture");
- magicimage=new Image(Blob(data,length)); // fix me this is an unnecessary memcpy
- free(data);
- }catch( Exception &error_ )
- {
- Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick: %s",error_.what());
- return 0;
}
- comm.data=magicimage;
- return putOpenVGCommand(comm,true);
}
#include "command.h"
#include "message.h"
+// The next section is activated, if the magick++ PictureReader is provided, it should be available for many POSIX platforms
+#ifdef PICTURE_DECODER_MAGICK
+#include <Magick++.h>
+
+using namespace Magick;
+
+class MagickDecoder: public OsdVector::PictureDecoder {
+public:
+ MagickDecoder(OsdVector::PictureReader* treader): OsdVector::PictureDecoder(treader) {pictInfValid=false;};
+
+ bool decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length);
+
+ bool getDecodedPicture( struct OsdVector::PictureInfo& pict_inf);
+
+ void freeReference(void * ref);
+
+protected:
+ OsdVector::PictureInfo pictInf;
+ bool pictInfValid;
+};
+
+bool MagickDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length)
+{
+ if (pictInfValid) return false; // does support only one image at a Time;
+ Image magicimage;
+ Blob *imageblob = new Blob();
+
+ try{
+ Log::getInstance()->log("MagickDecoder", Log::DEBUG, "decodePicture");
+ Blob myblob;
+ myblob.updateNoCopy(buffer,length,Blob::MallocAllocator);
+ magicimage.read(myblob);
+
+ magicimage.write(imageblob,"RGBA");
+
+ }catch( Exception &error_ )
+ {
+ Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: %s",error_.what());
+ delete imageblob;
+
+ return false;
+ }
+ pictInf.reference = (void*) imageblob;
+ pictInf.width = magicimage.columns();
+ pictInf.height = magicimage.rows();
+ pictInf.image = imageblob->data();
+ pictInf.decoder = this;
+ pictInf.type = OsdVector::PictureInfo::RGBAMemBlock;
+ pictInf.lindex = index;
+ pictInfValid = true;
+
+
+
+ // I can handle everything, so the return value is always true
+ return true;
+}
+void MagickDecoder::freeReference(void * ref)
+{
+ Blob *todelete = (Blob*) ref;
+ delete todelete;
+}
+
+bool MagickDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
+{
+ if (!pictInfValid) return false;
+ pict_inf=pictInf;
+ pictInfValid = false;
+ return true;
+}
+
+
+#endif
+
OsdVector::OsdVector()
{
setlocale(LC_CTYPE,"C.UTF-8");
- picture_update=true;
+#ifdef PICTURE_DECODER_MAGICK
+ reader.addDecoder(new MagickDecoder(&reader));
+#endif
+
}
OsdVector::~OsdVector()
{
-
}
images_ref[ref]--;
}
-unsigned int OsdVector::getLoadIndexRef(LoadIndex index)
+int OsdVector::getLoadIndexRef(LoadIndex index)
{
if (loadindex_ref.find(index)==loadindex_ref.end()) {
return -1;
tvmedias_loaded.erase(ref);
tvmedias_load.erase(tvmedias_load_inv[ref]);
tvmedias_load_inv.erase(ref);
+
+ reader.invalidateLoadIndex(ref);
+
+
}
}
+
+
void OsdVector::cleanupOrphanedRefs()
{ // Do some garbage collection
map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
while (mitty!=monobitmaps.end()) {
- map<ImageIndex,unsigned int>::iterator curitty=images_ref.find((*mitty).second);
+ map<ImageIndex,int>::iterator curitty=images_ref.find((*mitty).second);
int count=(*curitty).second;
if (count==0) {
ImageIndex ref=(*curitty).first;
map<string,ImageIndex>::iterator jitty=jpegs.begin();
while (jitty!=jpegs.end()) {
- map<ImageIndex,unsigned int>::iterator curitty=images_ref.find((*jitty).second);
+ map<ImageIndex,int>::iterator curitty=images_ref.find((*jitty).second);
int count=(*curitty).second;
if (count==0) {
ImageIndex ref=(*curitty).first;
map<TVMediaInfo,ImageIndex>::iterator titty=tvmedias.begin();
while (titty!=tvmedias.end()) {
- map<ImageIndex,unsigned int>::iterator curitty=images_ref.find((*titty).second);
+ map<ImageIndex,int>::iterator curitty=images_ref.find((*titty).second);
int count=(*curitty).second;
if (count==0) {
-
- Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia destroy Picture");
ImageIndex ref=(*curitty).first;
tvmedias.erase(titty++);
images_ref.erase(curitty++);
map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
while (sitty!=styles.end()) {
- map<unsigned int,unsigned int>::iterator curitty=styles_ref.find((*sitty).second);
+ map<unsigned int,int>::iterator curitty=styles_ref.find((*sitty).second);
int count=(*curitty).second;
if (count==0) {
unsigned int ref=(*curitty).first;
}
-unsigned int OsdVector::getImageRef(ImageIndex index)
+int OsdVector::getImageRef(ImageIndex index)
{
if (images_ref.find(index)==images_ref.end()) {
return -1;
return style_handle;
}
-unsigned int OsdVector::getStyleRef(unsigned int index)
+int OsdVector::getStyleRef(unsigned int index)
{
if (styles_ref.find(index)==styles_ref.end()) {
return -1;
return index;
}
-void OsdVector::setTVMedia(LoadIndex index, unsigned char * buffer, unsigned int length)
+
+
+void OsdVector::informPicture(LoadIndex index, ImageIndex imageIndex)
{
//Beware for thread safety
ImageIndex image_index=0;
TVMediaInfo tvmedia=tvmedias_load_inv[index];
Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %d arrived",index);
- if (buffer) {
- if (getLoadIndexRef(index)<1) {
+ if (imageIndex) {
+ image_index=tvmedias[tvmedia]=imageIndex;
+ tvmedias_loaded[index]=image_index;
+ if (getLoadIndexRef(index) < 1) {
// we do not want the picture anymore . Really...
+ // fill images_ref in to not irritate the garbage collector
+ if (getImageRef(image_index) < 0) {
+ images_ref[image_index]=0;
+ }
} else {
- image_index=tvmedias[tvmedia]=createPicture(buffer,length);
- tvmedias_loaded[index]=image_index;
+
incImageRef(image_index); // hold one index until all loadings refs are gone;
}
}
+
+
ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
{
ImageIndex image_handle=0;
return image_handle;
}
-void OsdVector::receivePicture(VDR_ResponsePacket *vresp)
+OsdVector::PictureReader::~PictureReader()
+{
+ decoders_lock.Lock();
+ while ( decoders.size()) {
+ PictureDecoder* dec=decoders.front();
+ decoders.pop_front();
+ delete dec;
+ }
+
+ decoders_lock.Unlock();
+}
+
+void OsdVector::PictureReader::init()
+{
+ threadStart();
+}
+
+void OsdVector::PictureReader::shutdown()
+{
+ threadStop();
+
+
+}
+
+void OsdVector::PictureReader::addDecoder(PictureDecoder* decoder)
+{
+ decoders_lock.Lock();
+ decoders.push_front(decoder);
+ decoders_lock.Unlock();
+}
+
+void OsdVector::PictureReader::threadMethod()
+{
+ OsdVector *osdvector = dynamic_cast<OsdVector*>(Osd::getInstance());
+ Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Start Picture Reader");
+ while (true) {
+ if (!threadIsActive()) {
+ Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia End Picture Reader");
+ threadCheckExit();
+ }
+
+ bool todos=true;
+ while (todos)
+ {
+ todos=false;
+ PictureInfo pictinf;
+ decoders_lock.Lock();
+ std::list<PictureDecoder*>::iterator itty=decoders.begin();
+
+ while (itty!=decoders.end()) {
+ if ((*itty)->getDecodedPicture(pictinf)) {
+ todos = true;
+ osdvector->createPicture(pictinf);
+ }
+
+ itty++;
+ }
+ if (processReceivedPictures())
+ {
+ todos = true;
+ }
+
+ decoders_lock.Unlock();
+ }
+ //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep Picture Reader");
+
+ threadLock();
+ threadWaitForSignal();
+ threadUnlock();
+ //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Sleep end Picture Reader");
+ }
+}
+
+void OsdVector::PictureReader::threadPostStopCleanup()
+{
+
+}
+
+void OsdVector::PictureReader::invalidateLoadIndex(LoadIndex index)
+{
+ pict_lock_incoming.Lock();
+ invalid_loadindex.insert(index);
+ pict_lock_incoming.Unlock();
+}
+
+void OsdVector::PictureReader::receivePicture(VDR_ResponsePacket *vresp)
{
pict_lock_incoming.Lock();
pict_incoming.push(vresp);
pict_lock_incoming.Unlock();
- //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived");
- if (picture_update) {
- Message* m = new Message();
- // This is incoming from VDR, we do not want to block gui so send a message to ourself to switch to gui thread
- m->message=Message::PICTURES_ARRIVED;
- m->from=this;
- m->to=Command::getInstance();
- picture_update=false;
- Command::getInstance()->postMessageFromOuterSpace(m); // inform command about new picture
- }
+ threadSignal();
}
-bool OsdVector::processReceivedPictures()
+bool OsdVector::PictureReader::processReceivedPictures()
{
- bool ret=false;
+ bool decoded = false;
+ bool valid = true;
pict_lock_incoming.Lock();
- int i=0;
- long long time1 = getTimeMS();
- long long cur_time =time1;
- while (pict_incoming.size() && (time1-cur_time)<100) {
+ if (pict_incoming.size()) {
VDR_ResponsePacket *vresp=pict_incoming.front();
pict_incoming.pop();
+ set<LoadIndex>::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;
+ }
if (vresp->getFlag() != 2) {
- setTVMedia(vresp->getStreamID(), vresp->getUserData(), vresp->getUserDataLength());
- ret=true;
+ UCHAR *userdata=vresp->getUserData();
+ ULONG length=vresp->getUserDataLength();
+ std::list<PictureDecoder*>::iterator itty=decoders.begin();
+ while (itty!=decoders.end()) {
+ if ((*itty)->decodePicture(vresp->getStreamID(),
+ userdata, length)){
+ decoded=true;
+ break;
+ }
+ itty++;
+ }
+ if (!decoded ){
+ free(vresp->getUserData());
+ }
}
- else setTVMedia(vresp->getStreamID(), NULL, 0);
+ //else osd->informPicture(vresp->getStreamID(), 0);
delete vresp;
- cur_time = getTimeMS();
- pict_lock_incoming.Lock();
+ } else {
+ pict_lock_incoming.Unlock();
}
- if (pict_incoming.size()==0) picture_update=true;
- pict_lock_incoming.Unlock();
- if (!picture_update) {
- Message* m = new Message();
- // We have remaing pictures! send a message to ourself to switch to gui thread
- m->message=Message::PICTURES_ARRIVED;
- m->from=this;
- m->to=Command::getInstance();
- picture_update=false;
- Command::getInstance()->postMessageNoLock(m); // inform command about new picture
- }
- return ret;
+ return decoded;
}
#include "osd.h"
#include "mutex.h"
#include "colour.h"
+#include <set>
#include <list>
#include <map>
#include <queue>
virtual void removeStyleRef(unsigned int ref);
virtual void getScreenSize(int &width, int &height)=0;
- // should be called from command thread
- bool processReceivedPictures();
+ // should be only called from command thread
+ void informPicture(LoadIndex index, ImageIndex i_index);
+
- void receivePicture(VDR_ResponsePacket *vresp);
int charSet() {return 2;}; //UTF-8
+ class PictureDecoder;
+ struct PictureInfo
+ {
+ enum PictType {
+ RGBAMemBlock,
+ EGLImage
+ };
+ PictType type;
+ ULONG width;
+ ULONG height;
+ LoadIndex lindex;
+ const void * image;
+ void *reference;
+ PictureDecoder* decoder;
+ };
+
+
+ class PictureReader;
+
+ class PictureDecoder
+ {
+ public:
+ PictureDecoder(PictureReader * treader) {reader=treader;};
+
+ // its is always guaranted, that after getDecodedPicture a call to decodePicture follows, if the return value was true;
+ virtual bool decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length)=0;
+
+ virtual bool getDecodedPicture(struct PictureInfo& pict_inf)=0;
+ virtual void freeReference(void * ref)=0;
+
+ protected:
+ PictureReader * reader;
+ };
+
+ class PictureReader: public Thread_TYPE {
+ public:
+
+ ~PictureReader();
+
+ void init();
+ void addDecoder(PictureDecoder*);
+
+ void shutdown();
+
+
+ bool processReceivedPictures();
+
+ // should be called from command thread
+ void receivePicture(VDR_ResponsePacket *vresp);
+
+ void invalidateLoadIndex(LoadIndex index);
+
+
+
+
+ protected:
+
+ void threadMethod();
+ void threadPostStopCleanup();
+
+ Mutex pict_lock_incoming; //locks
+ Mutex decoders_lock;
+ std::queue<VDR_ResponsePacket*> pict_incoming;
+ std::list<PictureDecoder*> decoders;
+ set<LoadIndex> invalid_loadindex;
+
+ bool picture_update;
+
+ };
+
+ PictureReader *getPictReader() { return &reader;};
+
+
protected:
+ PictureReader reader;
+
void incImageRef(ImageIndex index);
- unsigned int getImageRef(ImageIndex index);
+ int getImageRef(ImageIndex index);
virtual void destroyImageRef(ImageIndex index)=0;
void incLoadIndexRef(LoadIndex index);
- unsigned int getLoadIndexRef(LoadIndex index);
+ int getLoadIndexRef(LoadIndex index);
virtual ImageIndex createJpeg(const char* fileName, int *width,int *height)=0;
virtual ImageIndex createMonoBitmap(void *base,int width,int height)=0;
virtual ImageIndex createImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)=0;
- virtual ImageIndex createPicture(unsigned char *data, unsigned int length)=0;
+ virtual void createPicture(struct PictureInfo& pict_inf)=0;
virtual LoadIndex loadTVMedia(TVMediaInfo& tvmedia);
- map<ImageIndex,unsigned int> images_ref;
+ map<ImageIndex,int> images_ref;
map<void *,ImageIndex> monobitmaps;
map<string,ImageIndex> jpegs;
map<TVMediaInfo,ImageIndex> tvmedias;
- void setTVMedia(LoadIndex index, unsigned char * buffer, unsigned int length);
- Mutex pict_lock_incoming; //locks
- std::queue<VDR_ResponsePacket*> pict_incoming;
- bool picture_update;
- map<LoadIndex,unsigned int> loadindex_ref;
+
+
+ map<LoadIndex,int> loadindex_ref;
map<TVMediaInfo,LoadIndex> tvmedias_load;
map<LoadIndex,TVMediaInfo> tvmedias_load_inv;
map<LoadIndex,ImageIndex> tvmedias_loaded;
+
+
void incStyleRef(unsigned int index);
- unsigned int getStyleRef(ImageIndex index);
+ int getStyleRef(ImageIndex index);
virtual void destroyStyleRef(unsigned int index)=0;
map<pair<Colour*,unsigned int>,unsigned int> styles;
- map<unsigned int,unsigned int> styles_ref;
+ map<unsigned int,int> styles_ref;
virtual unsigned int createStyleRef(const DrawStyle &c)=0;
virtual unsigned int createColorRef(const Colour &c)=0;