From 6efd43866406782c45e5e75c2a5f9b70f2eb4d02 Mon Sep 17 00:00:00 2001 From: Marten Richter Date: Sun, 21 Sep 2014 11:00:08 +0200 Subject: [PATCH] For new raspberry version: fixes, move to new version of libav, use avresample, Bugfix: Destroy subtitle images Features: New advanced epg closer to vdr with noopacity --- GNUmakefile | 9 +- audioomx.cc | 148 ++------ audioomx.h | 8 +- debian/control | 4 +- event.cc | 23 +- event.h | 6 +- imageomx.cc | 7 +- imageomx.h | 2 +- objects.mk | 2 +- osdopenvg.cc | 1 + osdvector.cc | 45 ++- osdvector.h | 3 +- surfacevector.cc | 7 + tvmedia.cc | 13 + tvmedia.h | 3 + vdr.cc | 2 +- vepg.cc | 9 +- vepg.h | 2 +- vepglistadvanced.cc | 844 ++++++++++++++++++++++++++++++++++++++++++++ vepglistadvanced.h | 113 ++++++ vepgsummary.cc | 2 +- vvideolivetv.cc | 21 +- wselectlist.cc | 5 + wselectlist.h | 1 + 24 files changed, 1107 insertions(+), 173 deletions(-) create mode 100644 vepglistadvanced.cc create mode 100644 vepglistadvanced.h diff --git a/GNUmakefile b/GNUmakefile index d0c518e..b27c5a5 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -8,6 +8,7 @@ vomp_options= #vomp_options+= -DVOMP_HAS_EXIT + ifeq ($(vomp_platform),mvp) $(info MVP crosscompiler) include ../crosstool/cross-var @@ -61,10 +62,10 @@ endif ifeq ($(vomp_platform),raspberry) $(info Raspberry pi flags) LDFLAGS = -Wall -Wl,--format=binary -Wl,other/vdrhires.jpg -Wl,other/wallpaper720p.jpg -Wl,--format=default -LIBS = -L/opt/vc/lib -lpthread -lrt -lEGL -lOpenVG -lopenmaxil -lbcm_host -lavformat -lavcodec -lavutil +LIBS = -L/opt/vc/lib -lpthread -lrt -lEGL -lOpenVG -lopenmaxil -lbcm_host -lavformat -lavcodec -lavutil -lavresample OBJECTS += main.o threadp.o osdvector.o surfacevector.o osdopenvg.o ledraspberry.o mtdraspberry.o videoomx.o audioomx.o imageomx.o wjpegsimple.o remotelinux.o -LIBS+= -lfreetype -lMagick++ +LIBS+= -ldl -lfontconfig -lfreetype -lMagick++ CROSSLIBS = INCLUDES = -DVOMP_PLATTFORM_RASPBERRY -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/usr/include/freetype2 -I/usr/include/ImageMagick CXXFLAGS_DEV += -D__STDC_CONSTANT_MACROS @@ -75,10 +76,10 @@ endif ifeq ($(vomp_platform),crossraspberry) $(info Raspberry pi flags cross compiler) LDFLAGS = -Wall -Wl,--format=binary -Wl,other/vdrhires.jpg -Wl,other/wallpaper720p.jpg -Wl,--format=default -Wl,--verbose -Xlinker --rpath-link=rpi-root/usr/lib/arm-linux-gnueabihf -Xlinker --rpath-link=rpi-root/lib/arm-linux-gnueabihf -Xlinker --rpath-link=rpi-root/opt/vc/lib -LIBS = -Lrpi-root/opt/vc/lib -Lrpi-root/lib -Lrpi-root/usr/lib -Lrpi-root/lib/arm-linux-gnueabihf -Lrpi-root/usr/lib/arm-linux-gnueabihf -Lrpi-root/usr/local/lib -lpthread -lrt -lEGL -lOpenVG -lopenmaxil -lbcm_host -lavformat -lavcodec -lavutil -ldl -lfontconfig +LIBS = -Lrpi-root/opt/vc/lib -Lrpi-root/lib -Lrpi-root/usr/lib -Lrpi-root/lib/arm-linux-gnueabihf -Lrpi-root/usr/lib/arm-linux-gnueabihf -Lrpi-root/usr/local/lib -lpthread -lrt -lEGL -lOpenVG -lopenmaxil -lbcm_host -lavformat -lavcodec -lavutil -lavresample -ldl -lfontconfig OBJECTS += main.o threadp.o osdvector.o surfacevector.o osdopenvg.o ledraspberry.o mtdraspberry.o videoomx.o audioomx.o imageomx.o wjpegsimple.o remotelinux.o -LIBS+= -lfreetype -lMagick++ +LIBS+= -lfreetype -lMagick++ CROSSLIBS = INCLUDES = -DVOMP_PLATTFORM_RASPBERRY -Irpi-root/opt/vc/include -Irpi-root/opt/vc/include/interface/vcos/pthreads -Irpi-root/usr/include -Irpi-root/usr/include/freetype2 -Irpi-root/usr/include/ImageMagick CXXFLAGS_DEV += -D__STDC_CONSTANT_MACROS -mfloat-abi=hard diff --git a/audioomx.cc b/audioomx.cc index ef54b81..f6ae46f 100644 --- a/audioomx.cc +++ b/audioomx.cc @@ -27,6 +27,11 @@ #include "osdopenvg.h" #include +extern "C" { +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +} + AudioOMX::AudioOMX() { initted = 0; @@ -57,9 +62,10 @@ AudioOMX::AudioOMX() mp23codec_libav=NULL; mp23codec_context_libav=NULL; -#ifdef USE_LIBRESAMPLE + resam_con_libav=NULL; -#endif + + decompress_buffer=NULL; decompress_buffer_size=0; @@ -850,7 +856,7 @@ int AudioOMX::InitDecoderLibAV() libav_mutex.Unlock(); return 0; } -#ifdef USE_LIBRESAMPLE + resam_con_libav = avresample_alloc_context(); if (resam_con_libav == NULL) { Log::getInstance()->log("Audio", Log::DEBUG, @@ -861,11 +867,12 @@ int AudioOMX::InitDecoderLibAV() av_opt_set_int(resam_con_libav, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); // our standard format av_opt_set_int(resam_con_libav, "out_sample_rate",48000,0); av_opt_set_int(resam_con_libav, "out_sample_fmt",AV_SAMPLE_FMT_S16,0); + av_opt_set_int(resam_con_libav, "matrix_encoding",AV_MATRIX_ENCODING_DPLII,0); av_opt_set_int(resam_con_libav, "in_sample_rate",48000,0); av_opt_set_int(resam_con_libav, "in_sample_fmt",AV_SAMPLE_FMT_S16,0); av_opt_set_int(resam_con_libav, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0); //just an example -#endif + av_init_packet(&incoming_paket_libav); decode_frame_libav=avcodec_alloc_frame(); @@ -895,10 +902,10 @@ void AudioOMX::DeinitDecoderLibAV() { avcodec_close(mp23codec_context_libav); av_free(mp23codec_context_libav); mp23codec_context_libav = NULL; -#ifdef USE_LIBRESAMPLE - avresample_free(resam_con_libav); + + avresample_free(&resam_con_libav); resam_con_libav=NULL; -#endif + } libav_mutex.Unlock(); @@ -1693,54 +1700,7 @@ unsigned int AudioOMX::AdvanceAacLatmAudioSync(const UCHAR *data,unsigned int si } return size; } -#ifndef USE_LIBRESAMPLE -#define SQRT3_2 1.22474487139158904909 -void AudioOMX::getDownMixMatrix(unsigned long long channels, - int *left_mat,int *right_mat) -{ - int i,j; - double downmix_matrix[2][64]; - for (i=0;i<64;i++) { - for (j=0;j<2;j++) { - downmix_matrix[j][i]=0.; - } - } - downmix_matrix[0/*links*/][/*FRONT_LEFT*/0]=1.; - downmix_matrix[1/*rechts*/][/*FRONT_RIGHT*/1]=1.; - downmix_matrix[0/*links*/] [/*FRONT_CENTER*/2] = M_SQRT1_2; - downmix_matrix[1/*rechts*/] [/*FRONT_CENTER*/2] = M_SQRT1_2; - - if (channels & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT) ) { - downmix_matrix[0/*links*/][/*BACK_CENTER*/8]=-M_SQRT1_2*M_SQRT1_2; - downmix_matrix[1/*rechts*/][/*BACK_CENTER*/8]=M_SQRT1_2*M_SQRT1_2; - } else { - downmix_matrix[0/*links*/][/*BACK_CENTER*/8]=-M_SQRT1_2; - downmix_matrix[1/*rechts*/][/*BACK_CENTER*/8]=M_SQRT1_2; - } - downmix_matrix[0/*links*/][/*BACK_LEFT*/4 ]=-M_SQRT1_2*SQRT3_2; - downmix_matrix[1/*rechts*/][/*BACK_LEFT*/4]=M_SQRT1_2*M_SQRT1_2; - downmix_matrix[0/*links*/][/*BACK_RIGHT*/5 ]=-M_SQRT1_2*M_SQRT1_2; - downmix_matrix[1/*rechts*/][/*BACK_RIGHT*/5]=M_SQRT1_2*SQRT3_2; - downmix_matrix[0/*links*/][/*SIDE_LEFT*/9 ]=-M_SQRT1_2*SQRT3_2; - downmix_matrix[1/*rechts*/][/*SIDE_LEFT*/9]=M_SQRT1_2*M_SQRT1_2; - downmix_matrix[0/*links*/][/*SIDE_RIGHT*/10 ]=-M_SQRT1_2*M_SQRT1_2; - downmix_matrix[1/*rechts*/][/*SIDE_RIGHT*/10]=M_SQRT1_2*SQRT3_2; - downmix_matrix[0/*links*/][/*FRONT_LEFT_OF_CENTER*/6]=1.; - downmix_matrix[1/*rechts*/][/*FRONT_RIGHT_OF_CENTER*/7]=1.; - downmix_matrix[0/*links*/][/*LOW_FREQUENCY*/3]=M_SQRT1_2; - downmix_matrix[1/*rechts*/][/*LOW_FREQUENCY*/3]=M_SQRT1_2; - - for (i=0,j=0;i<64;i++) { - if ((1ULL << i)& channels) { - left_mat[j]=(int)(downmix_matrix[0][i]*(1<<16)); - right_mat[j]=(int)(downmix_matrix[1][i]*(1<<16)); - j++; - } - } -} - -#endif void AudioOMX::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos) { @@ -2209,7 +2169,7 @@ UINT AudioOMX::DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, int dsize = av_samples_get_buffer_size(NULL, /*current_context->channels*/2, decode_frame_libav->nb_samples, - current_context->sample_fmt, 1); + AV_SAMPLE_FMT_S16, 1); int dsize_in = av_samples_get_buffer_size(NULL, current_context->channels, decode_frame_libav->nb_samples, current_context->sample_fmt, 1); @@ -2257,73 +2217,25 @@ UINT AudioOMX::DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, } //Log::getInstance()->log("Audio", Log::DEBUG,"memcpy in %d %d %d" ,dsize,current_context->sample_rate,cur_input_buf_omx->nFilledLen); - if (current_context->channels==2) { - memcpy(cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen, - decode_frame_libav->data[0], dsize); - } -#ifndef USE_LIBRESAMPLE - else if (current_context->channels==1) { //convert to stereo - short* startbuffer=(short* )decode_frame_libav->data[0]; - short* endbuffer=(short* )(decode_frame_libav->data[0]+dsize/2); - short* destbuffer=(short* )(cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen); - while (startbuffer!=endbuffer) { - unsigned short temp=*startbuffer; - *destbuffer=temp; - destbuffer++; - *destbuffer=temp; - destbuffer++; - startbuffer++; - } - } else { - unsigned int channels=current_context->channels; - int left_mat[channels]; - int right_mat[channels]; - getDownMixMatrix(current_context->channel_layout,left_mat,right_mat); - - short* startbuffer=(short* )decode_frame_libav->data[0]; - short* endbuffer=(short* )(decode_frame_libav->data[0]+dsize_in); - short* destbuffer=(short* )(cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen); - while (startbuffer!=endbuffer) { - short* cur_buf=startbuffer; - short* cur_buf_end=startbuffer+channels; - int work1=0.; - int work2=0.; - int *mat1=left_mat; - int *mat2=right_mat; - while (cur_buf!=cur_buf_end) { - work1+= ((*mat1)*(*cur_buf)); - work2+= ((*mat2)*(*cur_buf)); - cur_buf++; - mat1++; - mat2++; - } - *destbuffer=work1>>16; - destbuffer++; - *destbuffer=work2>>16; - destbuffer++; - startbuffer+=channels; - } - } -#else - else { - //untested for future use - av_opt_set_int(resam_con_libav, "in_sample_rate",current_context->sample_rate,0); - av_opt_set_int(resam_con_libav, "in_sample_fmt",current_context->sample_fmt,0); - av_opt_set_int(resam_con_libav, "in_channel_layout",current_context->channel_layout, 0); - int ret=avresample_open(resam_con_libav); - if (ret<0) { - Log::getInstance()->log("Audio", Log::ERR,"Opening AV resample failed %d",ret); - } else { - avresample_convert(resam_con_libav, cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen, - dsize, decode_frame_libav->nb_samples, - decode_frame_libav->data[0], dsize_in, decode_frame_libav->nb_samples); - avresample_close(resam_con_libav); - } + av_opt_set_int(resam_con_libav, "in_sample_rate",decode_frame_libav->sample_rate,0); + av_opt_set_int(resam_con_libav, "in_sample_fmt",decode_frame_libav->format,0); + av_opt_set_int(resam_con_libav, "in_channel_layout",decode_frame_libav->channel_layout, 0); + //Log::getInstance()->log("Audio", Log::ERR,"AV resampledata %d %d %d %d",current_context->channels,current_context->sample_rate,current_context->sample_fmt,current_context->channel_layout); + //Log::getInstance()->log("Audio", Log::ERR,"AV resampledata2 %d %d %d",decode_frame_libav->sample_rate,decode_frame_libav->format,decode_frame_libav->channel_layout); + int ret=avresample_open(resam_con_libav); + if (ret<0) { + Log::getInstance()->log("Audio", Log::ERR,"Opening AV resample failed %d",ret); + } else { + uint8_t *output=cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen; + + avresample_convert(resam_con_libav, &output, + dsize, decode_frame_libav->nb_samples, + decode_frame_libav->extended_data, decode_frame_libav->linesize[0], decode_frame_libav->nb_samples); + avresample_close(resam_con_libav); } -#endif //Log::getInstance()->log("Audio", Log::DEBUG,"memcpy out"); cur_input_buf_omx->nFilledLen += dsize; diff --git a/audioomx.h b/audioomx.h index b6b01e0..6c16d64 100644 --- a/audioomx.h +++ b/audioomx.h @@ -30,14 +30,11 @@ #include "audio.h" #include "videoomx.h" -//#define USE_LIBRESAMPLE // untested code for future use extern "C" { #include #include -#ifdef USE_LIBRESAMPLE #include -#endif } @@ -187,11 +184,8 @@ class AudioOMX : public Audio AVCodecContext *mp23codec_context_libav; AVPacket incoming_paket_libav; AVFrame *decode_frame_libav; -#ifdef USE_LIBRESAMPLE AVAudioResampleContext *resam_con_libav; -#else - void getDownMixMatrix(unsigned long long channels,int *left_mat,int *right_mat); -#endif + UCHAR * decompress_buffer; unsigned int decompress_buffer_size; diff --git a/debian/control b/debian/control index a915791..fbbb69c 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: vompclient Section: unknown Priority: extra Maintainer: Marten Richter -Build-Depends: debhelper (>= 8.0.0), libcec-dev (>= 1.8.1), libraspberrypi-dev, libfreetype6-dev, libmagick++-dev, libavformat-dev, libavutil-dev, libavcodec-dev +Build-Depends: debhelper (>= 8.0.0), libcec-dev (>= 1.8.1), libraspberrypi-dev, libfreetype6-dev, libmagick++-dev, libavformat-dev, libavutil-dev, libavcodec-dev, libavresample-dev Standards-Version: 3.9.3 Homepage: www.loggytronic.com/vomp.php Vcs-Git: http://git.vomp.tv/vompclient-raspi.git @@ -10,7 +10,7 @@ Vcs-Browser: http://git.vomp.tv/gitweb/ Package: vompclient-raspi Architecture: armhf -Depends: ${shlibs:Depends}, ${misc:Depends}, libcec1 (>= 1.8.1), libraspberrypi-bin, libfreetype6, libmagick++5, libavformat53, libavutil51, libavcodec53 +Depends: ${shlibs:Depends}, ${misc:Depends}, libcec1 (>= 1.8.1), libraspberrypi-bin, libfreetype6, libmagick++5, libavformat54, libavutil51, libavcodec54, libavresample1 Description: vompclient for raspberry pi This is the vompclient binary for the raspberry pi platform. It connects to the server with the vdr software including diff --git a/event.cc b/event.cc index cd9ac39..ac272b8 100644 --- a/event.cc +++ b/event.cc @@ -25,6 +25,9 @@ #include "seriesinfo.h" #include "vdr.h" +MovieInfo* Event::movieInfo = NULL; +SeriesInfo* Event::seriesInfo = NULL; + Event::Event() { id = 0; @@ -34,8 +37,9 @@ Event::Event() title = NULL; subtitle = NULL; description = NULL; - movieInfo = NULL; - seriesInfo = NULL; + index = -1; + movieID = 0; + seriesID =0; } Event::~Event() @@ -43,8 +47,6 @@ Event::~Event() if (title) delete[] title; if (subtitle) delete[] subtitle; if (description) delete[] description; - if (movieInfo) delete movieInfo; - if (seriesInfo) delete seriesInfo; } void Event::settitle(const char* s) @@ -77,13 +79,14 @@ void Event::loadinfos(UINT channelid) movieInfo = NULL; seriesInfo = NULL; - movieID = 0; - seriesID =0; - vdr->getScraperEventType(channelid, id, movieID, seriesID, episodeID); - Log::getInstance()->log("Event", Log::DEBUG, "Got Scraper EventType %d %d, %d %d %d", - id, channelid, - movieID, seriesID, episodeID); + + if (movieID == 0 && seriesID == 0) { + vdr->getScraperEventType(channelid, id, movieID, seriesID, episodeID); + Log::getInstance()->log("Event", Log::DEBUG, "Got Scraper EventType %d %d, %d %d %d", + id, channelid, + movieID, seriesID, episodeID); + } if (!vdr->isConnected()) Command::getInstance()->connectionLost(); diff --git a/event.h b/event.h index 7d8b4e7..e2ad934 100644 --- a/event.h +++ b/event.h @@ -55,8 +55,10 @@ class Event char* subtitle; char* description; - MovieInfo *movieInfo; - SeriesInfo *seriesInfo; + int index; + + static MovieInfo *movieInfo; + static SeriesInfo *seriesInfo; int movieID; int seriesID; int episodeID; diff --git a/imageomx.cc b/imageomx.cc index bd75d6e..5668cf3 100644 --- a/imageomx.cc +++ b/imageomx.cc @@ -238,9 +238,9 @@ int ImageOMX::AllocateCodecsOMX(unsigned char * buffer, unsigned int length) -bool ImageOMX::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem) +unsigned char* ImageOMX::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem) { - if (pictInfValid) return false; // does support only one image at a Time; + if (pictInfValid) return buffer; // does support only one image at a Time; // Log::getInstance()->log("Image", Log::DEBUG, // "decodePicture 1"); EGLPictureCreator * pictcreat =dynamic_cast(Osd::getInstance()); @@ -268,7 +268,8 @@ bool ImageOMX::decodePicture(LoadIndex index, unsigned char * buffer, unsigned i pthread_setcanceltype(oldcanceltype, NULL); if (ret && freemem) free(buffer); - return ret; + if (ret) return NULL; + else return buffer; } diff --git a/imageomx.h b/imageomx.h index 1921c40..25021fa 100644 --- a/imageomx.h +++ b/imageomx.h @@ -51,7 +51,7 @@ class ImageOMX : public OsdVector::PictureDecoder void init(); void shutdown(); - bool decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem); + unsigned char* decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem); bool getDecodedPicture(struct OsdVector::PictureInfo& pict_inf); void freeReference(void * ref); diff --git a/objects.mk b/objects.mk index 7b6fec5..e74efec 100644 --- a/objects.mk +++ b/objects.mk @@ -6,7 +6,7 @@ OBJECTS1 = command.o tcp.o dsock.o thread.o timers.o i18n.o \ demuxer.o demuxervdr.o demuxerts.o stream.o \ region.o colour.o boxstack.o boxx.o tbboxx.o \ vinfo.o vquestion.o vrecordinglist.o vrecordinglistclassic.o vrecordinglistadvanced.o vrecording.o \ - vepgsummary.o \ + vepgsummary.o vepglistadvanced.o \ vmute.o vvolume.o vtimerlist.o vtimeredit.o vrecordingmenu.o \ vchannellist.o vwelcome.o vvideorec.o vepgsettimer.o \ vchannelselect.o vserverselect.o vconnect.o vepg.o vrecmove.o \ diff --git a/osdopenvg.cc b/osdopenvg.cc index 5caf581..6c85934 100644 --- a/osdopenvg.cc +++ b/osdopenvg.cc @@ -1039,6 +1039,7 @@ unsigned int OsdOpenVG::handleTask(OpenVGCommand& command) VGImage input=vgCreateImage(VG_A_8,command.param1, command.param2, VG_IMAGE_QUALITY_NONANTIALIASED| VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER); + //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create palette %d %d %x %d",command.param1,command.param2,vgGetError(),input); vgImageSubData(input,command.data,command.param1, VG_A_8,0,0,command.param1, command.param2); // upload palettized image data VGImage handle=vgCreateImage(VG_sRGBA_8888,command.param1, command.param2, diff --git a/osdvector.cc b/osdvector.cc index 0702289..28e1d21 100644 --- a/osdvector.cc +++ b/osdvector.cc @@ -35,7 +35,7 @@ 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 freemem); + unsigned char *decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem); bool getDecodedPicture( struct OsdVector::PictureInfo& pict_inf); @@ -46,15 +46,15 @@ protected: bool pictInfValid; }; -bool MagickDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem) +unsigned char * MagickDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem) { - if (pictInfValid) return false; // does support only one image at a Time; + if (pictInfValid) return buffer; // does support only one image at a Time; Image magicimage; Blob *imageblob = new Blob(); - + Blob myblob; try{ Log::getInstance()->log("MagickDecoder", Log::DEBUG, "decodePicture"); - Blob myblob; + if (freemem) myblob.updateNoCopy(buffer,length,Blob::MallocAllocator); else myblob.update(buffer,length); magicimage.read(myblob); @@ -65,8 +65,10 @@ bool MagickDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsig { Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: %s",error_.what()); delete imageblob; - - return false; + Log::getInstance()->log("MagickDecoder", Log::DEBUG, "Libmagick: error mark2"); + unsigned char* newbuffer=(unsigned char*) malloc(length); + memcpy(newbuffer,myblob.data(),length); + return newbuffer; } pictInf.reference = (void*) imageblob; pictInf.width = magicimage.columns(); @@ -80,7 +82,7 @@ bool MagickDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsig // I can handle everything, so the return value is always true - return true; + return NULL; } void MagickDecoder::freeReference(void * ref) { @@ -159,6 +161,7 @@ int OsdVector::restore() //jpegs.clear(); styles.clear(); styles_ref.clear(); + palettepics.clear(); tvmedias.clear(); loadindex_ref.clear(); @@ -431,6 +434,18 @@ void OsdVector::cleanupOrphanedRefs() } else ++litty; } + list::iterator pitty=palettepics.begin(); + while (pitty!=palettepics.end()) { + map::iterator curitty=images_ref.find((*pitty)); + int count=(*curitty).second; + if (count==0) { + ImageIndex ref=(*curitty).first; + palettepics.erase(pitty++); + images_ref.erase(curitty++); + destroyImageRef(ref); + } else ++pitty; + } + map,unsigned int>::iterator sitty=styles.begin(); while (sitty!=styles.end()) { @@ -551,6 +566,9 @@ LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia) index = ((long long) tvmedia.getPrimaryID()) << 32LL; reader.addStaticImage(tvmedia.getPrimaryID()); } break; + case 5: + index=VDR::getInstance()->loadTVMediaEventThumb(tvmedia); + break; default: index=VDR::getInstance()->loadTVMedia(tvmedia); break; @@ -640,6 +658,7 @@ ImageIndex OsdVector::getImagePalette(int width,int height,const unsigned char { ImageIndex image_handle; image_handle=createImagePalette(width,height,image_data,palette_data); + palettepics.push_back(image_handle); incImageRef(image_handle); return image_handle; } @@ -789,15 +808,15 @@ bool OsdVector::PictureReader::processReceivedPictures() ULONG length=vresp->getUserDataLength(); std::list::iterator itty=decoders.begin(); while (itty!=decoders.end()) { - if ((*itty)->decodePicture(vresp->getStreamID(), - userdata, length)){ + userdata=(*itty)->decodePicture(vresp->getStreamID(), userdata, length); + if (!userdata){ decoded=true; break; } itty++; } - if (!decoded ){ - free(vresp->getUserData()); + if (!decoded && userdata ){ + free(userdata); } } //else osd->informPicture(vresp->getStreamID(), 0); @@ -821,7 +840,7 @@ bool OsdVector::PictureReader::processReceivedPictures() { std::list::iterator itty=decoders.begin(); while (itty!=decoders.end()) { - if ((*itty)->decodePicture(((long long) static_id) << 32LL,userdata, length, false)){ + if (!(*itty)->decodePicture(((long long) static_id) << 32LL,userdata, length, false)){ decoded=true; break; } diff --git a/osdvector.h b/osdvector.h index ad2a0b9..b8d3f21 100644 --- a/osdvector.h +++ b/osdvector.h @@ -280,7 +280,7 @@ class OsdVector : public Osd virtual ~PictureDecoder() {}; // 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, bool freemem=true)=0; + virtual unsigned char * decodePicture(LoadIndex 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; @@ -360,6 +360,7 @@ protected: map monobitmaps; //map jpegs; map tvmedias; + list palettepics; diff --git a/surfacevector.cc b/surfacevector.cc index 72fc698..29bee4d 100644 --- a/surfacevector.cc +++ b/surfacevector.cc @@ -193,6 +193,9 @@ void SurfaceVector::drawTVMedia(TVMediaInfo & tvmedia,float x, float y, float w command_mutex.Lock(); ImageIndex image=0; LoadIndex load_index=osd->getTVMediaRef(tvmedia,image); + if (width!=0 && height!=0) { + removeCommands(x,y,width,height); + } if (image) { //Log::getInstance()->log("SurfaceVector", Log::DEBUG, "TVMedia Add instru image %d %d", load_index,image); commands.push_back(SVGCommand::PaintImage(x,y,width,height,image,0,corner)); @@ -274,6 +277,7 @@ void SurfaceVector::drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegio tw*=scalex; th*=scaley; SVGCommand temp=SVGCommand::PaintImage(tx,ty,tw,th,image,0); + removeCommands(tx,ty,tw,th); commands.push_back(temp); command_mutex.Unlock(); } @@ -289,6 +293,7 @@ void SurfaceVector::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int hei command_mutex.Lock(); ImageIndex image=osd->getMonoBitmapRef(base,width,height); unsigned int ref=osd->getStyleRef(nextColour); + removeCommands(dx,dy,width,height); commands.push_back(SVGCommand::PaintImage(dx,dy,height,width,image,ref)); command_mutex.Unlock(); } @@ -301,6 +306,8 @@ int SurfaceVector::removeCommands(float x,float y,float width,float height) while (itty!=commands.end()) { if ((*itty).Test(x,y,width,height) && (*itty).instr != DrawClipping) { + //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).reference,(*itty).target.image); osd->removeStyleRef((*itty).getRef()); // We remove the Style reference, so that osd can free stuff ImageIndex ii=(*itty).getImageIndex(); if (ii) osd->removeImageRef(ii); diff --git a/tvmedia.cc b/tvmedia.cc index 7bf8896..fb0ab22 100644 --- a/tvmedia.cc +++ b/tvmedia.cc @@ -73,6 +73,19 @@ void TVMediaInfo::setDefaultJpeg(int jpeg_index) primary_id=jpeg_index; } +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; +} + bool operator<(const TVMediaInfo& rhs, const TVMediaInfo& lhs) { if (rhs.type==lhs.type) { diff --git a/tvmedia.h b/tvmedia.h index 99c65e1..42af1ea 100644 --- a/tvmedia.h +++ b/tvmedia.h @@ -44,9 +44,12 @@ public: 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 setDefaultJpeg(int jpeg_index); int getType() {return type;}; int getPrimaryID() {return primary_id;}; + int getSecondaryID() {return secondary_id;}; private: int type; // 1 movie or 2 series or 3 unknown recording or 4 static artwork diff --git a/vdr.cc b/vdr.cc index e20dda0..46fecfb 100644 --- a/vdr.cc +++ b/vdr.cc @@ -1054,7 +1054,7 @@ EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration) VDR_ResponsePacket* vresp = RequestResponse(&vrp); if (vresp->noResponse()) { delete vresp; return NULL; } - + // received a ulong(0) - schedules error in the plugin if (vresp->serverError()) { diff --git a/vepg.cc b/vepg.cc index 5af3e0d..94605e9 100644 --- a/vepg.cc +++ b/vepg.cc @@ -50,7 +50,7 @@ VEpg* VEpg::instance = NULL; -VEpg::VEpg(void* tparent, UINT tcurrentChannelIndex, ULONG streamType) +VEpg::VEpg(void* tparent, UINT tcurrentChannelIndex, ChannelList* tchanList) { instance = this; currentChannelIndex = tcurrentChannelIndex; @@ -96,7 +96,7 @@ VEpg::VEpg(void* tparent, UINT tcurrentChannelIndex, ULONG streamType) boxstack = BoxStack::getInstance(); parent = tparent; eventList = NULL; - chanList = VDR::getInstance()->getChannelsList(streamType); //TODO want to be able to display video and radio together + chanList = tchanList; e = 0; eventLista.resize(gridRows); @@ -674,6 +674,11 @@ void VEpg::updateEventList() if(listTop + listIndex >= UINT(chanListbox.getBottomOption())) continue; chan = (*chanList)[listTop + listIndex]; + if (eventLista[listIndex]) + { + (eventLista)[listIndex]->clear(); + delete eventLista[listIndex]; + } eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, ltime - 1, window_width * 60 + 2); // ltime - 1 to get prog before window (allows cursor left past ltime). + 2 to get prog after window } } diff --git a/vepg.h b/vepg.h index b3bbf09..adc6f7e 100644 --- a/vepg.h +++ b/vepg.h @@ -45,7 +45,7 @@ class VVideoLive; class VEpg : public Boxx, public TimerReceiver { public: - VEpg(void* parent, UINT currentChannel, ULONG streamType); + VEpg(void* parent, UINT currentChannel, ChannelList* tchanList); ~VEpg(); static VEpg* getInstance(); diff --git a/vepglistadvanced.cc b/vepglistadvanced.cc new file mode 100644 index 0000000..a15f283 --- /dev/null +++ b/vepglistadvanced.cc @@ -0,0 +1,844 @@ +/* + Copyright 2004-2007 Chris Tallon, 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 "vepglistadvanced.h" + +#include "boxstack.h" +#include "remote.h" +#include "wsymbol.h" +#include "boxstack.h" +#include "vdr.h" +#include "colour.h" +#include "video.h" +#include "i18n.h" +#include "command.h" +#include "log.h" +#include "movieinfo.h" +#include "seriesinfo.h" +#include "event.h" +#include "channel.h" +#include "vepgsummary.h" +#include "vepgsettimer.h" +#include "vepg.h" + +#include + + +VEpgListAdvanced::VEpgListAdvanced(VVideoLiveTV *tvideolive, ChannelList* tchanList,ULONG initialChannelNumber) +{ + channelNumber = initialChannelNumber; + chanList = tchanList; + videolive = tvideolive; + boxstack = BoxStack::getInstance(); + + mode = OneChannel; + + setSize(640, 500); //old setSize(570, 420); + createBuffer(); + + setPosition(40, 40); + + setTitleBarOn(1); + setTitleBarColour(DrawStyle::TITLEBARBACKGROUND); + + sl.setPosition(10, 30 + 5); + sl.setSize(area.w*42/100 - 20, area.h - 30 - 15 - 30); + sl.setLinesPerOption(2.4f); + add(&sl); + + Region slarea=sl.getRegionR(); + + epg.setParaMode(true); + epg.setPosition(slarea.x +slarea.w+10 ,30+5); + epg.setSize(area.w -slarea.x -slarea.w -10, area.h - 30 - 15 - 30); + add(&epg); + epg.setText(""); + epg.setBackgroundColour(DrawStyle::VIEWBACKGROUND); + + epgTVmedia.setPosition(epg.getRegionR().w-100-10,10); + epgTVmedia.setSize(100,150/Osd::getInstance()->getPixelAspect()); + epg.add(&epgTVmedia); + + boxRed.setBackgroundColour(DrawStyle::RED); + boxRed.setPosition(165 /*54*/, sl.getY2()+8); + boxRed.setSize(18, 16); + add(&boxRed); + + textRed.setPosition(boxRed.getX2(), sl.getY2()+4); + textRed.setSize(116, 30); + + add(&textRed); + + boxGreen.setBackgroundColour(DrawStyle::GREEN); + boxGreen.setPosition(165 +1*110, sl.getY2()+8); + boxGreen.setSize(18, 16); + add(&boxGreen); + + textGreen.setPosition(boxGreen.getX2(), sl.getY2()+4); + textGreen.setSize(116, 30); + add(&textGreen); + + boxYellow.setBackgroundColour(DrawStyle::YELLOW); + boxYellow.setPosition(165 +2*110, sl.getY2()+8); + boxYellow.setSize(18, 16); + add(&boxYellow); + + textYellow.setPosition(boxYellow.getX2(), sl.getY2()+4); + textYellow.setSize(116, 30); + add(&textYellow); + + boxBlue.setBackgroundColour(DrawStyle::BLUE); + boxBlue.setPosition(165 +3*110, sl.getY2()+8); + boxBlue.setSize(18, 16); + add(&boxBlue); + + textBlue.setPosition(boxBlue.getX2(), sl.getY2()+4); + textBlue.setSize(116, 30); + add(&textBlue); + + setButtonText(); + + + updateEpgDataChannel(); +} + +VEpgListAdvanced::~VEpgListAdvanced() +{ + clearEventList(); +} + + +void VEpgListAdvanced::setButtonText() +{ + switch (mode) + { + case OneChannel: { + textRed.setText(tr("Record")); + textGreen.setText(tr("Now")); + textYellow.setText(tr("Next")); + textBlue.setText(tr("Guide")); + + } break; + case Now: { + textRed.setText(tr("Record")); + textGreen.setText(tr("Next")); + textYellow.setText(tr("Schedule")); + textBlue.setText(tr("Switch")); + } break; + case Next: { + textRed.setText(tr("Record")); + textGreen.setText(tr("Now")); + textYellow.setText(tr("Schedule")); + textBlue.setText(tr("Switch")); + } break; + + }; +} + +void VEpgListAdvanced::doRed() +{ + doRecord(); +} + +void VEpgListAdvanced::doGreen() +{ + switch (mode) + { + case Now: { + doNext(); + } break; + case OneChannel: + case Next: { + doNow(); + } break; + }; +} + +void VEpgListAdvanced::doYellow() +{ + switch (mode) + { + case OneChannel: { + doNext(); + } break; + case Next: + case Now: { + doProgramm(); + } break; + }; +} + +void VEpgListAdvanced::doBlue() +{ + switch (mode) + { + case OneChannel: { + doGrid(); + } break; + case Next: + case Now: { + doSwitch(); + } break; + }; +} + +void VEpgListAdvanced::doNext() +{ + Log::getInstance()->log("VEventListAdvanced", Log::DEBUG, "doNext"); + if (mode!=OneChannel) { + Channel * chan=(*chanList)[ sl.getCurrentOptionData()]; + channelNumber = chan->number; + } + mode=Next; + updateEpgDataNowNext(true); + setButtonText(); + draw(true); + boxstack->update(this); +} +void VEpgListAdvanced::doNow() +{ + Log::getInstance()->log("VEventListAdvanced", Log::DEBUG, "doNow"); + if (mode!=OneChannel) { + Channel * chan=(*chanList)[ sl.getCurrentOptionData()]; + channelNumber = chan->number; + } + mode=Now; + updateEpgDataNowNext(true); + setButtonText(); + draw(true); + boxstack->update(this); +} + +void VEpgListAdvanced::doProgramm() +{ + Log::getInstance()->log("VEventListAdvanced", Log::DEBUG, "doProgram"); + mode=OneChannel; + + Channel * chan=(*chanList)[ sl.getCurrentOptionData()]; + channelNumber = chan->number; + updateEpgDataChannel(); + setButtonText(); + draw(true); + boxstack->update(this); +} + +void VEpgListAdvanced::doSwitch() +{ + + if (videolive) + { + if (mode!=OneChannel) { + Channel * chan=(*chanList)[ sl.getCurrentOptionData()]; + channelNumber = chan->number; + } + Log::getInstance()->log("VEventListAdvanced", Log::DEBUG, "doSwitch %d", channelNumber); + Message* m = new Message(); // Must be done after this view deleted + m->from = this; + m->to = videolive; + m->message = Message::CHANNEL_CHANGE; + m->parameter = channelNumber; + m->tag = 0; + Command::getInstance()->postMessageNoLock(m); + } +} + +void VEpgListAdvanced::doRecord() +{ + int channel; + Event* current = getCurrentOptionEvent(channel); + if (current) + { + Log::getInstance()->log("VEventListAdvanced", Log::DEBUG, "Found the option you pointed at. %s %d", current->title, current->id); + unsigned int chanlistsize=chanList->size(); + Channel * chan; + UINT listIndex; + for(listIndex = 0; listIndex < chanlistsize; listIndex++) + { + chan = (*chanList)[listIndex]; + if (chan->number == channel) break; + } + + Log::getInstance()->log("VEpgSummary", Log::DEBUG, "ID %lu TIME %lu DURATION %lu TITLE %s", current->id, current->time, + current->duration, current->title); + VEpgSetTimer* vs = new VEpgSetTimer(current, chan); + vs->draw(); + BoxStack *boxstack=BoxStack::getInstance(); + boxstack->add(vs); + boxstack->update(vs); + } + +} + +void VEpgListAdvanced::doGrid() +{ + Video* video=Video::getInstance(); + video->setMode(Video::QUARTER); + video->setPosition(170, 5); //TODO add stack for these changes + if (mode!=OneChannel) { + Channel * chan=(*chanList)[ sl.getCurrentOptionData()]; + channelNumber = chan->number; + } + + VEpg* vepg = new VEpg(videolive, channelNumber, chanList); + vepg->draw(); + boxstack->add(vepg); + boxstack->update(vepg); + +} + +void VEpgListAdvanced::clearEventList() +{ + std::vector::iterator itty = eventLista.begin(); + while (itty!= eventLista.end()) { + if (*itty) { + (*itty)->clear(); + delete (*itty); + } + itty++; + } + eventLista.clear(); + +} + + +/* Prototype + * + * if (!chanList) return; + Channel* chan; + for(UINT listIndex = 0; listIndex < gridRows; listIndex++) + { + if(listTop + listIndex >= UINT(chanListbox.getBottomOption())) + continue; + chan = (*chanList)[listTop + listIndex]; + eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, ltime - 1, window_width * 60 + 2); // ltime - 1 to get prog before window (allows cursor left past ltime). + 2 to get prog after window + } + + */ + +void VEpgListAdvanced::updateEpgData() +{ + switch (mode) + { + case OneChannel: { + //updateEpgDataChannel(); + } break; + case Next: + case Now: { + updateEpgDataNowNext(false); + } break; + }; + +} + +void VEpgListAdvanced::updateEpgDataNowNext(bool changeState) +{ + int startupdate=0; + int endupdate=0; + + unsigned int chanlistsize=chanList->size(); + if (changeState) { + clearEventList(); + eventLista.resize(chanList->size()); + Channel* chan; + for(UINT listIndex = 0; listIndex < chanlistsize; listIndex++) + { + if (listIndex < 0) continue; + if (listIndex >= chanlistsize) continue; + chan = (*chanList)[listIndex]; + if (chan->number == channelNumber) { + startupdate = listIndex-sl.getNumOptionsDisplayable()-2; + endupdate = listIndex+sl.getNumOptionsDisplayable()+2; + break; + } + } + } else { + startupdate=sl.getTopOption()-2; + endupdate=sl.getBottomOption()+1; + } + + time_t now; + time(&now); + + Channel* chan; + for(int listIndex = startupdate; listIndex < endupdate; listIndex++) + { + if (listIndex < 0) continue; + if (listIndex >= chanlistsize) continue; + + chan = (*chanList)[listIndex]; + if (!eventLista[listIndex]) eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, now, 4 * 60 *60); + + } + +} + +void VEpgListAdvanced::updateEpgDataChannel() +{ + clearEventList(); + eventLista.resize(1); + time_t now; + time(&now); + eventLista[0] = VDR::getInstance()->getChannelSchedule(channelNumber, now, 24 * 60 *60 *30); // one month + Log::getInstance()->log("VEventListAdvanced", Log::DEBUG, "Eventlist %x %d", eventLista[0],channelNumber); + +} + +void VEpgListAdvanced::drawData(bool doIndexPop) +{ + switch (mode) + { + case OneChannel: { + drawDataChannel(doIndexPop); + } break; + case Next: { + drawDataNowNext(true, doIndexPop); + } break; + case Now: { + drawDataNowNext(false, doIndexPop); + } break; + }; + +} + +void VEpgListAdvanced::drawDataChannel(bool doIndexPop) +{ + int saveIndex = sl.getCurrentOption(); + int saveTop = sl.getTopOption(); + sl.clear(); + sl.addColumn(0); + sl.addColumn(25 ); + sl.addColumn(25 + 7); + //sl.addColumn(118); + + int first = 1; + + char tempA[300]; // FIXME this is guesswork! + char tempB[300]; // FIXME + char tempC[300]; // FIXME + struct tm* btime; + + + + Event* currentEvent; + EventList::iterator j; + EventList* eventList = eventLista[0]; + if (eventList) { + for (j = eventList->begin(); j != eventList->end(); j++) + { + currentEvent = *j; + time_t eventStartTime = (time_t)currentEvent->time; + time_t eventEndTime = (time_t)(currentEvent->time + currentEvent->duration); + + btime = localtime(&eventStartTime); + strftime(tempA, 299, "%d/%m/%y %H:%M ", btime); + btime = localtime(&eventEndTime); + strftime(tempB, 299, "- %H:%M ", btime); + //#endif + sprintf(tempC, "%s\n \t%s%s", currentEvent->title,tempA,tempB); + // New TVMedia stuff + TVMediaInfo *info= new TVMediaInfo(); + info->setPosterThumb(channelNumber, currentEvent->id); + currentEvent->index = sl.addOption(tempC, currentEvent->id, first, info); + first = 0; + } + } + + if (doIndexPop) + { + sl.hintSetCurrent(0); + } + else + { + sl.hintSetCurrent(saveIndex); + sl.hintSetTop(saveTop); + } + updateSelection(); + sl.draw(); + epg.draw(); +} + +void VEpgListAdvanced::drawDataNowNext(bool next, bool doIndexPop) +{ + int saveIndex = sl.getCurrentOption(); + int saveTop = sl.getTopOption(); + sl.clear(); + sl.addColumn(0); + sl.addColumn(25 ); + sl.addColumn(160); + + int first = 1; + + char tempA[300]; // FIXME this is guesswork! + char tempB[300]; // FIXME + char tempC[300]; // FIXME + struct tm* btime; + + + + Event* currentEvent; + EventList::iterator j; + int minevents=1; + if (next) minevents++; + int setcurrenthelper =0; + + unsigned int chanlistsize=chanList->size(); + for(UINT listIndex = 0; listIndex < chanlistsize; listIndex++) + { + Channel* chan; + chan = (*chanList)[listIndex]; + + EventList* eventList = eventLista[listIndex]; + if (eventList && eventList->size()>=minevents) { + j = eventList->begin(); + + currentEvent = j[minevents-1]; + time_t eventStartTime = (time_t)currentEvent->time; + time_t eventEndTime = (time_t)(currentEvent->time + currentEvent->duration); + + btime = localtime(&eventStartTime); + strftime(tempA, 299, "%H:%M ", btime); + btime = localtime(&eventEndTime); + strftime(tempB, 299, "- %H:%M ", btime); + //#endif + sprintf(tempC, "%s\n%s\t %s%s", currentEvent->title, chan->name,tempA,tempB); + + } else { + sprintf(tempC, "\n%s", chan->name); + + } + TVMediaInfo *info= new TVMediaInfo(); + if ((*chanList)[listIndex]->number == channelNumber) { + first = 1; + setcurrenthelper = listIndex; + } + info->setChannelLogo((*chanList)[listIndex]->number); + currentEvent->index = sl.addOption(tempC, listIndex, first, info); + first = 0; + } + + if (doIndexPop) + { + sl.hintSetCurrent(setcurrenthelper); + } + else + { + sl.hintSetCurrent(saveIndex); + sl.hintSetTop(saveTop); + } + updateSelection(); + sl.draw(); + epg.draw(); +} + +void VEpgListAdvanced::draw(bool doIndexPop) +{ + + // Single channel mode + switch (mode) { + case OneChannel: { + char tempA[300]; + unsigned int chanlistsize=chanList->size(); + Channel * chan; + UINT listIndex; + for(listIndex = 0; listIndex < chanlistsize; listIndex++) + { + chan = (*chanList)[listIndex]; + if (chan->number == channelNumber) break; + } + sprintf(tempA, tr("Schedule - %s"), (*chanList)[listIndex]->name); + setTitleText(tempA); + } break; + case Now: { + setTitleText(tr("Now")); + } break; + case Next: { + setTitleText(tr("Next")); + } break; + }; + + + + + TBBoxx::draw(); + + + char freeSpace[50]; + struct tm* btime; + time_t now; + time(&now); + btime = localtime(&now); + strftime(freeSpace, 299, "%d/%m/%y", btime); + drawTextRJ(freeSpace, 560+70, 5, DrawStyle::LIGHTTEXT); + // Symbols + + WSymbol w; + TEMPADD(&w); + w.nextSymbol = WSymbol::UP; + w.setPosition(20, area.h-35); + w.draw(); + w.nextSymbol = WSymbol::DOWN; + w.setPosition(50, area.h-35); + w.draw(); + w.nextSymbol = WSymbol::SKIPBACK; + w.setPosition(85, area.h-35); + w.draw(); + w.nextSymbol = WSymbol::SKIPFORWARD; + w.setPosition(115, area.h-35); + w.draw(); + + drawTextRJ(tr("[ok] = info"), 560+70, 385+80, DrawStyle::LIGHTTEXT); + + // All static stuff done + drawData(doIndexPop); + +} + +Event* VEpgListAdvanced::getCurrentOptionEvent(int& channel) +{ + // version for channel + Event* currentEvent = NULL; + EventList::iterator j; + EventList* eventList = NULL; + switch (mode) + { + case OneChannel: { + eventList = eventLista[0]; + if (eventList) { + channel = channelNumber; + for (j = eventList->begin(); j != eventList->end(); j++) + { + currentEvent = *j; + if (currentEvent->index == sl.getCurrentOption()) return currentEvent; + } + + + } break; + case Next: { + eventList = eventLista[sl.getCurrentOptionData()]; + channel = (*chanList)[sl.getCurrentOptionData()]->number; + + + if (eventList && eventList->size()>1) { + j = eventList->begin(); + currentEvent = j[1]; + } else { + currentEvent = NULL; + } + } break; + case Now: { + eventList = eventLista[sl.getCurrentOptionData()]; + channel = (*chanList)[sl.getCurrentOptionData()]->number; + + if (eventList && eventList->size()>0) { + j = eventList->begin(); + currentEvent = j[0]; + } else { + currentEvent = NULL; + } + } break; + }; + + + } + return currentEvent; +} + + + +void VEpgListAdvanced::updateSelection() +{ + updateEpgData(); + int channel=0; + Event* toShow = getCurrentOptionEvent(channel); + if (toShow) + { + toShow->loadinfos(channel); + std::stringstream description; + + description << "\n"<< toShow->title << "\n\n"; + description << toShow->subtitle <<"\n"; + description << toShow->description; + + TVMedia poster; + poster.height=0; + if (toShow->movieInfo) { + poster=toShow->movieInfo->poster; + } + if (toShow->seriesInfo) { + if (toShow->seriesInfo->seasonposter.height) { + poster=toShow->seriesInfo->seasonposter; + } + else if (toShow->seriesInfo->posters.size()) { + poster=toShow->seriesInfo->posters[0]; + } + } + if (poster.height) { + epgTVmedia.setTVMedia(poster.info, WTVMedia::ZoomHorizontal); + epgTVmedia.setVisible(true); + } else { + epgTVmedia.setVisible(false); + } + + epg.setText(description.str().c_str()); + } else { + epg.setText(""); + epgTVmedia.setVisible(false); + } + +} + +int VEpgListAdvanced::handleCommand(int command) +{ + switch(command) + { + case Remote::DF_UP: + case Remote::UP: + { + sl.up(); + quickUpdate(); + + boxstack->update(this); + return 2; + } + case Remote::DF_DOWN: + case Remote::DOWN: + { + sl.down(); + quickUpdate(); + + boxstack->update(this); + return 2; + } + case Remote::SKIPBACK: + { + sl.pageUp(); + quickUpdate(); + + boxstack->update(this); + return 2; + } + case Remote::SKIPFORWARD: + { + sl.pageDown(); + quickUpdate(); + + boxstack->update(this); + return 2; + } + case Remote::RED: + { + doRed(); + return 2; + } + case Remote::GREEN: + { + doGreen(); + return 2; + } + case Remote::YELLOW: + { + doYellow(); + return 2; + } + case Remote::BLUE: + { + doBlue(); + return 2; + } + case Remote::OK: + { + if (sl.getNumOptions() == 0) return 2; + + + int channel; + Event* current = getCurrentOptionEvent(channel); + if (current) + { + Log::getInstance()->log("VEventListAdvanced", Log::DEBUG, "Found the option you pointed at. %s %d", current->title, current->id); + unsigned int chanlistsize=chanList->size(); + Channel * chan; + UINT listIndex; + for(listIndex = 0; listIndex < chanlistsize; listIndex++) + { + chan = (*chanList)[listIndex]; + if (chan->number == channel) break; + } + + VEpgSummary* vr = new VEpgSummary(current, (*chanList)[listIndex]); + vr->draw(); + boxstack->add(vr); + boxstack->update(vr); + + return 2; + } + // should not get to here + return 1; + } + case Remote::BACK: + { + return 4; + } + } + // stop command getting to any more views + return 1; +} + +void VEpgListAdvanced::processMessage(Message* m) +{ + Log::getInstance()->log("VEpgListAdvanced", Log::DEBUG, "Got message value %lu", m->message); + + if (m->message == Message::MOUSE_MOVE) + { + if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY())) + { + quickUpdate(); + boxstack->update(this); + } + } + else if (m->message == Message::MOUSE_LBDOWN) + { + if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY())) + { + boxstack->handleCommand(Remote::OK); //simulate OK press + } + else + { + //check if press is outside this view! then simulate cancel + int x=(m->parameter>>16)-getScreenX(); + int y=(m->parameter&0xFFFF)-getScreenY(); + if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight()) + { + boxstack->handleCommand(Remote::BACK); //simulate cancel press + } + } + } +} + + + +void VEpgListAdvanced::quickUpdate() { //only quick for plattform that need it! + updateSelection(); +#ifdef GRADIENT_DRAWING + draw(); +#else + sl.draw(); + epg.draw(); +#endif +} diff --git a/vepglistadvanced.h b/vepglistadvanced.h new file mode 100644 index 0000000..5b48149 --- /dev/null +++ b/vepglistadvanced.h @@ -0,0 +1,113 @@ +/* + Copyright 2004-2005 Chris Tallon, 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 VEPGLIST_ADVANCED_H +#define VEPGLIST_ADVANCED_H + + +#include + +#include "tbboxx.h" +#include "wtextbox.h" +#include "wselectlist.h" +#include "wtvmedia.h" + +class BoxStack; +class VVideoLiveTV; + +class VEpgListAdvanced : public TBBoxx +{ + public: + VEpgListAdvanced(VVideoLiveTV *tvideolive, ChannelList* tchanList, ULONG initialChannelNumber); + virtual ~VEpgListAdvanced(); + + void draw(bool doIndexPop = false); + bool load(); + void drawData(bool doIndexPop = false); + + protected: + + enum EpgMode { + OneChannel, + Now, + Next + }; + + enum EpgMode mode; + + void quickUpdate(); + void updateSelection(); + + void setButtonText(); + + void clearEventList(); + + void updateEpgData(); + void updateEpgDataChannel(); + void updateEpgDataNowNext(bool changestate); + void drawDataChannel(bool doIndexPop); + void drawDataNowNext(bool next, bool doIndexPop); + + int handleCommand(int command); + void processMessage(Message* m); + + void doRed(); + void doGreen(); + void doYellow(); + void doBlue(); + + void doNext(); + void doNow(); + void doProgramm(); + void doSwitch(); + void doRecord(); + void doGrid(); + + WTextbox epg; + WTVMedia epgTVmedia; + + BoxStack* boxstack; + bool loading; + + WSelectList sl; + + Event* getCurrentOptionEvent(int& channel); + + ChannelList* chanList; + ULONG channelNumber; + VVideoLiveTV *videolive; + + Boxx boxRed; + Boxx boxGreen; + Boxx boxYellow; + Boxx boxBlue; + + WTextbox textRed; + WTextbox textGreen; + WTextbox textYellow; + WTextbox textBlue; + + std::vector eventLista; + + + +}; + +#endif diff --git a/vepgsummary.cc b/vepgsummary.cc index 84c0669..796a700 100644 --- a/vepgsummary.cc +++ b/vepgsummary.cc @@ -123,7 +123,7 @@ VEpgSummary::VEpgSummary(Event *tevent, Channel* tchannel) epgTVmedia.setSize(130,195/Osd::getInstance()->getPixelAspect()); summary->add(&epgTVmedia); if (movieview) movieview->add(&epgTVmedia); - if (seriesview) movieview->add(&epgTVmedia); + if (seriesview) seriesview->add(&epgTVmedia); TVMedia poster; poster.height=0; if (event->movieInfo) { diff --git a/vvideolivetv.cc b/vvideolivetv.cc index bf550c2..4718449 100644 --- a/vvideolivetv.cc +++ b/vvideolivetv.cc @@ -43,6 +43,7 @@ #include "log.h" #include "vteletextview.h" #include "vepgsummary.h" +#include "vepglistadvanced.h" VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList) : osdBack(0, 0, 0, 128) @@ -707,13 +708,21 @@ void VVideoLiveTV::doEPG() { if (osd.getVisible()) clearScreen(); - video->setMode(Video::QUARTER); - video->setPosition(170, 5); //TODO need to deal with 4:3 switching + if (!Command::getInstance()->advMenues()) { + video->setMode(Video::QUARTER); + video->setPosition(170, 5); //TODO need to deal with 4:3 switching - VEpg* vepg = new VEpg(this, currentChannelIndex, streamType); - vepg->draw(); - boxstack->add(vepg); - boxstack->update(vepg); + VEpg* vepg = new VEpg(this, currentChannelIndex, chanList); + vepg->draw(); + boxstack->add(vepg); + boxstack->update(vepg); + } else { + Channel* currentChannel = (*chanList)[osdChannelIndex]; + VEpgListAdvanced *vepg= new VEpgListAdvanced(this, chanList, currentChannel->number); + vepg->draw(); + boxstack->add(vepg); + boxstack->update(vepg); + } } void VVideoLiveTV::setNowNextData() diff --git a/wselectlist.cc b/wselectlist.cc index f8ecc13..3037dfc 100644 --- a/wselectlist.cc +++ b/wselectlist.cc @@ -270,6 +270,11 @@ ULONG WSelectList::getCurrentOptionData() return options[selectedOption].data; } +int WSelectList::getNumOptionsDisplayable() +{ + return numOptionsDisplayable; +} + bool WSelectList::mouseAndroidScroll(int x, int y,int sx, int sy) { /* int fontHeight = getFontHeight(); diff --git a/wselectlist.h b/wselectlist.h index 455622b..9106484 100644 --- a/wselectlist.h +++ b/wselectlist.h @@ -63,6 +63,7 @@ class WSelectList : public Boxx int getTopOption(); int getNumOptions(); int getBottomOption(); // actually returns bottom + 1 i.e. the one just past display ?! + int getNumOptionsDisplayable(); int getCurrentOption(); ULONG getCurrentOptionData(); -- 2.39.2