-include ../crosstool/cross-var
-
-CC=$(CROSS)gcc
-STRIP=$(CROSS)strip
-CXX=$(CROSS)g++
-LD=$(CROSS)g++
-
-INCLUDES = -I../jpeg/jpeg-6b
-CXXFLAGS_DEV = -g -O0 -Wall -Wshadow -DDEV -D_GNU_SOURCE $(INCLUDES)
-CXXFLAGS_REL = -O3 -Wall -Wshadow -D_GNU_SOURCE $(INCLUDES)
-LDFLAGS = -Wall -static
-
-LIBPATHS =
-LIBS = -lpthread -lrt
-CROSSLIBS = ../jpeg/jpeg-6b/libjpeg.a
-
-# This is the only thing windows and linux share
-include objects.mk
-
-OBJECTSMVP = main.o threadp.o remotemvp.o ledmvp.o mtdmvp.o videomvp.o audiomvp.o osdmvp.o surfacemvp.o
-OBJECTSWIN = threadwin.o remotewin.o ledwin.o mtdwin.o videowin.o audiowin.o osdwin.o surfacewin.o
-
-OBJECTS = $(OBJECTS1) $(OBJECTSMVP)
-
-.PHONY: clean fresh all install strip
-
-default: dev
-fresh: clean default
-
-vompclient: $(OBJECTS) ticonfig.o $(CROSSLIBS)
- $(LD) $(LDFLAGS) $(LIBPATHS) $(RELEASE) -o vompclient ticonfig.o $(OBJECTS) $(CROSSLIBS) $(LIBS)
-
-# A slight hash up
-ticonfig.o:
- $(CC) $(CXXFLAGS_REL) -c -o ticonfig.o ticonfig.c
-
-strip:
- $(STRIP) vompclient
-
-install:
- rm -f /mnt/auto/defiant/diskless/nfs/mvp/vompclient
- cp vompclient /mnt/auto/defiant/diskless/nfs/mvp
-
-install-wmp:
- rm -f /diskless/nfs/wmvp/vompclient
- cp vompclient /diskless/nfs/wmvp
-
-install-dev:
- rm -f /mnt/auto/defiant/diskless/nfs/mvp-dev/vompclient
- cp vompclient /mnt/auto/defiant/diskless/nfs/mvp-dev
-
-debug:
- ../../gdb/gdb-6.7/gdb/gdb /mnt/auto/defiant/diskless/nfs/mvp/vompclient /mnt/auto/defiant/diskless/nfs/mvp/core.*
-
-debug2:
- ../../gdb/gdb-6.7/gdb/gdb /mnt/auto/defiant/diskless/nfs/mvp-dev/vompclient /mnt/auto/defiant/diskless/nfs/mvp-dev/core.*
-
-dev: CXXFLAGS := $(CXXFLAGS_DEV)
-dev: vompclient
-
-release: CXXFLAGS := $(CXXFLAGS_REL)
-release: clean vompclient strip
-
-deps: GNUmakefile
- $(CC) -MM $(INCLUDES) $(OBJECTS:%.o=%.cc) > deps
-
--include deps
-
-clean:
- rm -f *.o deps vompclient *~ fonts/*.o fonts/*~
-
+vomp_platform =raspberry\r
+# valid platforms are raspberry and mvp\r
+\r
+ifeq ($(vomp_platform),mvp)\r
+\r
+$(info MVP crosscompiler)\r
+include ../crosstool/cross-var\r
+CC=$(CROSS)gcc\r
+STRIP=$(CROSS)strip\r
+CXX=$(CROSS)g++\r
+LD=$(CROSS)g++\r
+\r
+endif\r
+\r
+ifeq ($(vomp_platform),raspberry)\r
+\r
+$(info raspberry normal compiler)\r
+CC=gcc\r
+STRIP=strip\r
+CXX=g++\r
+LD=g++\r
+\r
+endif\r
+\r
+\r
+\r
+CXXFLAGS_DEV = -g -O0 -Wall -Wshadow -DDEV -D_GNU_SOURCE $(INCLUDES)\r
+CXXFLAGS_REL = -O3 -Wall -Wshadow -D_GNU_SOURCE $(INCLUDES)\r
+\r
+\r
+LIBPATHS =\r
+\r
+\r
+$(info Setting up objects)\r
+# This is the only thing windows and linux share\r
+include objects.mk\r
+\r
+OBJECTSWIN = threadwin.o remotewin.o ledwin.o mtdwin.o videowin.o audiowin.o osdwin.o surfacewin.o\r
+\r
+OBJECTS = $(OBJECTS1) \r
+\r
+\r
+ifeq ($(vomp_platform),mvp)\r
+$(info MVP flags)\r
+LDFLAGS = -Wall -static\r
+LIBS = -lpthread -lrt\r
+\r
+OBJECTS += main.o threadp.o remotemvp.o ledmvp.o mtdmvp.o videomvp.o audiomvp.o osdmvp.o surfacemvp.o vmedialist.o vcolourtuner.o vmediaview.o vvideomedia.o \r
+TIOBJECT = ticonfig.o\r
+CROSSLIBS = ../jpeg/jpeg-6b/libjpeg.a\r
+INCLUDES = -I../jpeg/jpeg-6b -DVOMP_PLATTFORM_MVP\r
+\r
+endif\r
+\r
+ifeq ($(vomp_platform),raspberry)\r
+$(info Raspberry pi flags)\r
+LDFLAGS = -Wall\r
+LIBS = -L/opt/vc/lib -lpthread -lrt -lEGL -lGLESv2 -lbcm_host\r
+\r
+OBJECTS += main.o threadp.o osdopengl.o surfaceopengl.o ledraspberry.o mtdraspberry.o videovpeogl.o audiovpe.o wjpegsimple.o remotelinux.o\r
+LIBS+= -ljpeg\r
+CROSSLIBS =\r
+INCLUDES = -DVOMP_PLATTFORM_RASPBERRY -I/opt/vc/include \r
+\r
+endif\r
+\r
+.PHONY: clean fresh all install strip\r
+\r
+default: dev\r
+fresh: clean default\r
+\r
+vompclient: $(OBJECTS) $(TIOBJECT) $(CROSSLIBS)\r
+ $(LD) $(LDFLAGS) $(LIBPATHS) $(RELEASE) -o vompclient $(TIOBJECT) $(OBJECTS) $(CROSSLIBS) $(LIBS)\r
+\r
+# A slight hash up\r
+ticonfig.o:\r
+ $(CC) $(CXXFLAGS_REL) -c -o ticonfig.o ticonfig.c\r
+\r
+strip:\r
+ $(STRIP) vompclient\r
+\r
+install:\r
+ rm -f /mnt/auto/defiant/diskless/nfs/mvp/vompclient\r
+ cp vompclient /mnt/auto/defiant/diskless/nfs/mvp\r
+\r
+install-wmp:\r
+ rm -f /diskless/nfs/wmvp/vompclient\r
+ cp vompclient /diskless/nfs/wmvp\r
+\r
+install-dev:\r
+ rm -f /mnt/auto/defiant/diskless/nfs/mvp-dev/vompclient\r
+ cp vompclient /mnt/auto/defiant/diskless/nfs/mvp-dev\r
+\r
+debug:\r
+ ../../gdb/gdb-6.7/gdb/gdb /mnt/auto/defiant/diskless/nfs/mvp/vompclient /mnt/auto/defiant/diskless/nfs/mvp/core.*\r
+\r
+debug2:\r
+ ../../gdb/gdb-6.7/gdb/gdb /mnt/auto/defiant/diskless/nfs/mvp-dev/vompclient /mnt/auto/defiant/diskless/nfs/mvp-dev/core.*\r
+\r
+dev: CXXFLAGS := $(CXXFLAGS_DEV)\r
+dev: vompclient\r
+\r
+release: CXXFLAGS := $(CXXFLAGS_REL)\r
+release: clean vompclient strip\r
+\r
+deps: GNUmakefile\r
+ $(CC) -MM $(INCLUDES) $(OBJECTS:%.o=%.cc) > deps\r
+\r
+-include deps\r
+\r
+clean:\r
+ rm -f *.o deps vompclient *~ fonts/*.o fonts/*~\r
+\r
!include "objects.mk"
-OBJECTSWIN = winmain.o threadwin.o remotewin.o ledwin.o mtdwin.o videowin.o audiowin.o osdwin.o surfacewin.o dsallocator.o dssourcefilter.o dssourcepin.o wwinvideofilter.o wwinaudiofilter.o wwinmp3audiofilter.o
+OBJECTSWIN = winmain.o threadwin.o remotewin.o ledwin.o mtdwin.o videowin.o audiowin.o osdwin.o surfacewin.o dsallocator.o dssourcefilter.o dssourcepin.o wwinvideofilter.o wwinaudiofilter.o wwinmp3audiofilter.o wjpegsimple.o
OBJECTS = $(OBJECTS1) $(OBJECTSWIN)
#include "vdr.h"
#include "option.h"
+/*
bool AbstractOption::loadOptionsfromServer(VDR* vdr)
{
return true;
bool AbstractOption::handleOptionChanges(Option* option)
{
return false;
-}
+}*/
class AbstractOption
{
public:
- virtual bool loadOptionsfromServer(VDR* vdr);
- virtual bool saveOptionstoServer();
- virtual bool addOptionPagesToWTB(WTabBar *wtb);
- virtual bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane);
- virtual bool handleOptionChanges(Option* option);
+ // inline definition allows plugins architecture for audio video
+ virtual bool loadOptionsfromServer(VDR* vdr) {return true;};
+ virtual bool saveOptionstoServer() {return true;};
+ virtual bool addOptionPagesToWTB(WTabBar *wtb) {return true;};
+ virtual bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane) {return true;};
+ virtual bool handleOptionChanges(Option* option){return false;};
};
#endif
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "afeed.h"
-
-#include "log.h"
-#include "demuxer.h"
-#include "callback.h"
-
-AFeed::AFeed(Callback* tcb)
-: cb(*tcb)
-{
- audioEnabled = 1;
-}
-
-int AFeed::init()
-{
- return 1;
-}
-
-int AFeed::shutdown()
-{
- // FIXME
- return 1;
-}
-
-void AFeed::disable()
-{
- audioEnabled = 0;
-}
-
-void AFeed::enable()
-{
- audioEnabled = 1;
-}
-
-int AFeed::start()
-{
- audioEnabled = 1;
- return threadStart();
-}
-
-void AFeed::stop()
-{
- threadCancel();
-}
-
-void AFeed::threadMethod()
-{
- bool alen;
-
- while(1)
- {
- threadCheckExit();
-
- if (audioEnabled)
- {
- alen = Demuxer::getInstance()->writeAudio();
-
- if (alen)
- {
- cb.call(this);
-// Log::getInstance()->log("Afeed", Log::DEBUG, "written");
- }
- else
- {
- //MILLISLEEP(100);
- MILLISLEEP(5); //Performance Issue Marten
- }
- }
- else
- {
- Demuxer::getInstance()->flushAudio();
- //Log::getInstance()->log("AFeed", Log::DEBUG, "No data delay");
- //MILLISLEEP(100);
- MILLISLEEP(5); //Performance Issue
- }
- }
-}
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "afeed.h"\r
+\r
+#include "log.h"\r
+#include "demuxer.h"\r
+#include "callback.h"\r
+\r
+\r
+AFeed::AFeed(Callback* tcb)\r
+: cb(*tcb)\r
+{\r
+ audioEnabled = 1;\r
+}\r
+\r
+int AFeed::init()\r
+{\r
+ return 1;\r
+}\r
+\r
+int AFeed::shutdown()\r
+{\r
+ // FIXME\r
+ return 1;\r
+}\r
+\r
+void AFeed::disable()\r
+{\r
+ audioEnabled = 0;\r
+}\r
+\r
+void AFeed::enable()\r
+{\r
+ audioEnabled = 1;\r
+}\r
+\r
+int AFeed::start()\r
+{\r
+ audioEnabled = 1;\r
+ return threadStart();\r
+}\r
+\r
+void AFeed::stop()\r
+{\r
+ threadCancel();\r
+}\r
+\r
+void AFeed::threadMethod()\r
+{\r
+ bool alen;\r
+\r
+ while(1)\r
+ {\r
+ threadCheckExit();\r
+\r
+ if (audioEnabled)\r
+ {\r
+ alen = Demuxer::getInstance()->writeAudio();\r
+\r
+ if (alen)\r
+ {\r
+ cb.call(this);\r
+// Log::getInstance()->log("Afeed", Log::DEBUG, "written");\r
+ }\r
+ else\r
+ {\r
+ //MILLISLEEP(100);\r
+ MILLISLEEP(5); //Performance Issue Marten\r
+ }\r
+ }\r
+ else\r
+ {\r
+ Demuxer::getInstance()->flushAudio();\r
+ //Log::getInstance()->log("AFeed", Log::DEBUG, "No data delay");\r
+ //MILLISLEEP(100);\r
+ MILLISLEEP(5); //Performance Issue\r
+ }\r
+ }\r
+}\r
+\r
#include <stdio.h>
#include <time.h>
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
+
+#include "threadsystem.h"
class Callback;
void threadMethod();
void threadPostStopCleanup() {};
int audioEnabled;
+ bool callbacksend;
Callback& cb;
};
{
return instance;
}
+/*
+void Audio::setInstance(Audio* inst)
+{
+ instance=inst;
+}*/
int Audio::volumeUp()
{
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef AUDIO_H
-#define AUDIO_H
-
-#include <stdio.h>
-#include "defines.h"
-#include "draintarget.h"
-#include "abstractoption.h"
-
-typedef struct
-{
- unsigned char frontleft;
- unsigned char frontright;
- unsigned char rearleft;
- unsigned char rearright;
- unsigned char center;
- unsigned char lfe;
-} audio_volume;
-
-class Audio : public DrainTarget, public AbstractOption
-{
- public:
- Audio();
- virtual ~Audio();
- static Audio* getInstance();
-
- virtual int init(UCHAR streamType)=0;
- virtual int shutdown()=0;
- virtual int setStreamType(UCHAR streamType)=0;
- virtual int setChannel()=0;
- virtual int setSource()=0;
- virtual int sync()=0;
- virtual int play()=0;
- virtual int stop()=0;
- virtual int pause()=0;
- virtual int unPause()=0;
- virtual int reset()=0;
- virtual int setVolume(int volume)=0;
- virtual int mute()=0;
- virtual int unMute()=0;
- virtual bool supportsAc3()=0;
- virtual bool maysupportAc3(){return false;}
-
- int volumeUp();
- int volumeDown();
- int getVolume();
- int toggleUserMute();
- int systemMuteOn();
- int systemMuteOff();
- int doMuting();
-
- // Audio stream type // FIXME these are MVP specific (probably!)
- const static UCHAR MPEG2_PES = 2;
- const static UCHAR MPEG1_PES = 3; // unused
- const static UCHAR MP3 = 0; //media player
-
-#ifdef DEV
- virtual int test()=0;
-#endif
-
- protected:
- static Audio* instance;
- int initted;
- UCHAR userMute;
- UCHAR systemMute;
- UCHAR muted;
- int volume;
-
- audio_volume Aoffset;
-};
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef AUDIO_H\r
+#define AUDIO_H\r
+\r
+#include <stdio.h>\r
+#include "defines.h"\r
+#include "draintarget.h"\r
+#include "abstractoption.h"\r
+\r
+typedef struct\r
+{\r
+ unsigned char frontleft;\r
+ unsigned char frontright;\r
+ unsigned char rearleft;\r
+ unsigned char rearright;\r
+ unsigned char center;\r
+ unsigned char lfe;\r
+} audio_volume;\r
+\r
+class Audio : public DrainTarget, public AbstractOption\r
+{\r
+ public:\r
+ Audio();\r
+ virtual ~Audio();\r
+ static Audio* getInstance();\r
+ // static void setInstance(Audio* );\r
+\r
+ virtual int init(UCHAR streamType)=0;\r
+ virtual int shutdown()=0;\r
+ virtual int setStreamType(UCHAR streamType)=0;\r
+ virtual int setChannel()=0;\r
+ virtual int setSource()=0;\r
+ virtual int sync()=0;\r
+ virtual int play()=0;\r
+ virtual int stop()=0;\r
+ virtual int pause()=0;\r
+ virtual int unPause()=0;\r
+ virtual int reset()=0;\r
+ virtual int setVolume(int volume)=0;\r
+ virtual int mute()=0;\r
+ virtual int unMute()=0;\r
+ virtual bool supportsAc3()=0;\r
+ virtual bool maysupportAc3(){return false;}\r
+\r
+ int volumeUp();\r
+ int volumeDown();\r
+ int getVolume();\r
+ int toggleUserMute();\r
+ int systemMuteOn();\r
+ int systemMuteOff();\r
+ int doMuting();\r
+\r
+ // Audio stream type // FIXME these are MVP specific (probably!)\r
+ const static UCHAR MPEG2_PES = 2;\r
+ const static UCHAR MPEG1_PES = 3; // unused\r
+ const static UCHAR MP3 = 0; //media player\r
+\r
+#ifdef DEV\r
+ virtual int test()=0;\r
+#endif\r
+\r
+ protected:\r
+ static Audio* instance;\r
+ int initted;\r
+ UCHAR userMute;\r
+ UCHAR systemMute;\r
+ UCHAR muted;\r
+ int volume;\r
+\r
+ audio_volume Aoffset;\r
+};\r
+\r
+#endif\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "audiowin.h"
-#include "videowin.h"
-#include "vdr.h"
-#include "wtabbar.h"
-#include "wwinaudiofilter.h"
-#include "wwinmp3audiofilter.h"
-#include "i18n.h"
-
-
-
-
-AudioWin::AudioWin()
-{
- initted = 0;
- firstsynched=false;
- winvolume=0;
- volume=20;
-audiofilterselected=-1;
- mp3audiofilterselected=-1;
- aud_type=Audio::MPEG2_PES;
-
-}
-
-AudioWin::~AudioWin()
-{
-
- int i;
- for (i=0;i<audiofilterlist.size();i++)
- {
- if (audiofilterlist[i].displayname) delete [] audiofilterlist[i].displayname;
- if (audiofilterlist[i].friendlyname) delete [] audiofilterlist[i].friendlyname;
- }
- audiofilterlist.clear();
-
- for (i=0;i<mp3audiofilterlist.size();i++)
- {
- if (mp3audiofilterlist[i].displayname) delete [] mp3audiofilterlist[i].displayname;
- if (mp3audiofilterlist[i].friendlyname) delete [] mp3audiofilterlist[i].friendlyname;
- }
- mp3audiofilterlist.clear();
-
-}
-
-int AudioWin::init(UCHAR tstreamType)
-{
- if (initted) return 0;
- initFilterDatabase();
- initMp3FilterDatabase();
- initted = 1;
- return 1;
-}
-
-int AudioWin::shutdown()
-{
- if (!initted) return 0;
- initted = 0;
- return 1;
-}
-
-int AudioWin::write(char *buf, int len)
-{
- return 0; //write(fdAudio, buf, len);
-}
-
-int AudioWin::setStreamType(UCHAR type)
-{
- ((VideoWin*)VideoWin::getInstance())->setAudioStreamType(type);
- aud_type=type;
- if (!initted) return 0;
- return 1;
-}
-
-int AudioWin::setChannel()
-{
- if (!initted) return 0;
- return 1;
-}
-
-int AudioWin::setSource()
-{
- if (!initted) return 0;
- return 1;
-}
-
-int AudioWin::sync()
-{
- if (!initted) return 0;
- return 1;
-}
-
-int AudioWin::play()
-{
- if (!initted) return 0;
- firstsynched=false;
- return ((VideoWin*)Video::getInstance())->dsplay();
-
-}
-
-int AudioWin::stop()
-{
- if (!initted) return 0;
- return ((VideoWin*)Video::getInstance())->dsstop();
-}
-
-int AudioWin::pause()
-{
- if (!initted) return 0;
- return ((VideoWin*)Video::getInstance())->dspause();
-}
-
-int AudioWin::unPause()
-{
- if (!initted) return 0;
- return ((VideoWin*)Video::getInstance())->dsunPause();
-}
-
-int AudioWin::reset()
-{
-
- if (!initted){return 0;}
- return ((VideoWin*)Video::getInstance())->dsreset();
-}
-
-int AudioWin::setVolume(int tvolume)
-{
- // parameter: 0 for silence, 20 for full
- if ((tvolume < 0) || (tvolume > 20)) return 0;
- winvolume=((tvolume-20)*100*30)/20;
- if (tvolume==0) winvolume=-10000;
- ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);
-
-
- return 1;
-}
-
-int AudioWin::mute()
-{
- if (!initted) return 0;
- ((VideoWin*)Video::getInstance())->SetAudioState(false);
- ((VideoWin*)Video::getInstance())->SetAudioVolume(-10000);
- return 1;
-}
-
-int AudioWin::unMute()
-{
- if (!initted) return 0;
- ((VideoWin*)Video::getInstance())->SetAudioState(true);
- ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);
- return 1;
-}
-
-void AudioWin::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)
-{
- mediapacket = mplist.front();
-}
-
-void AudioWin::initFilterDatabase()
-{
- /* This method should determine all availiable DirectShow Filters */
- IFilterMapper2* filtmap=NULL;
- HRESULT result;
- result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
- IID_IFilterMapper2,(void**)&filtmap);
- if (result != S_OK)
- {
- Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");
- return;
- }
- /* Wishlist, what Mediatypes do we want */
- GUID mtypesin[]={MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO,
- /*MEDIATYPE_Audio,MEDIASUBTYPE_MPEG1Payload,*/
- MEDIATYPE_Audio,MEDIASUBTYPE_DOLBY_AC3,
- MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3_SPDIF};
- IEnumMoniker *myenum;
- result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
- TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
- if (result != S_OK)
- {
- filtmap->Release();
- Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");
- return;
- }
- ULONG gethowmany;
- IMoniker * moni;
- while(myenum->Next(1,&moni,&gethowmany)==S_OK)
- {
- AudioFilterDesc desc;
- ZeroMemory(&desc,sizeof(desc));
-
- LPOLESTR string;
- moni->GetDisplayName(0,0,&string);
- desc.displayname=new char[wcslen(string)+1];
- wcstombs(desc.displayname,string,wcslen(string)+1);
- CoTaskMemFree(string);
- IPropertyBag *bag;
- if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
- {
- VARIANT vari;
- VariantInit(&vari);
- result = bag->Read(L"FriendlyName",&vari,NULL);
- if (result == S_OK)
- {
- desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
- wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
- }
- VariantClear(&vari);
- bag->Release();
-
- }
-
-
- audiofilterlist.push_back(desc);
-
-
-
- moni->Release();
- // bctx->Release();
- }
- int i;
- audiofilterselected=-1;
- myenum->Release();
- filtmap->Release();
-}
-
-void AudioWin::initMp3FilterDatabase()
-{
- /* This method should determine all availiable DirectShow Filters */
- IFilterMapper2* filtmap=NULL;
- HRESULT result;
- result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
- IID_IFilterMapper2,(void**)&filtmap);
- if (result != S_OK)
- {
- Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");
- return;
- }
- /* Wishlist, what Mediatypes do we want */
- GUID mtypesin[]={MEDIATYPE_Audio,MEDIATYPE_WaveFmt_Mpeg1Layer3,
- MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO};
- IEnumMoniker *myenum;
- result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
- TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
- if (result != S_OK)
- {
- filtmap->Release();
- Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");
- return;
- }
- ULONG gethowmany;
- IMoniker * moni;
- while(myenum->Next(1,&moni,&gethowmany)==S_OK)
- {
- AudioFilterDesc desc;
- ZeroMemory(&desc,sizeof(desc));
-
- LPOLESTR string;
- moni->GetDisplayName(0,0,&string);
- desc.displayname=new char[wcslen(string)+1];
- wcstombs(desc.displayname,string,wcslen(string)+1);
- CoTaskMemFree(string);
- IPropertyBag *bag;
- if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
- {
- VARIANT vari;
- VariantInit(&vari);
- result = bag->Read(L"FriendlyName",&vari,NULL);
- if (result == S_OK)
- {
- desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
- wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
- }
- VariantClear(&vari);
- bag->Release();
-
- }
-
-
- mp3audiofilterlist.push_back(desc);
-
-
-
- moni->Release();
- // bctx->Release();
- }
- int i;
- mp3audiofilterselected=-1;
- myenum->Release();
- filtmap->Release();
-}
-
-bool AudioWin::loadOptionsfromServer(VDR* vdr)
-{
- char *name=vdr->configLoad("DirectShow","AudioFilter");
-
- if (name != NULL)
- {
- for (int i = 0;i <audiofilterlist.size();i++)
- {
- if (strcmp(name,audiofilterlist[i].displayname)==0)
- {
- audiofilterselected = i;
- break;
- }
- }
- }
- name=vdr->configLoad("DirectShow","Mp3AudioFilter");
-
- if (name != NULL)
- {
- for (int i = 0;i <mp3audiofilterlist.size();i++)
- {
- if (strcmp(name,mp3audiofilterlist[i].displayname)==0)
- {
- mp3audiofilterselected = i;
- break;
- }
- }
- }
- return true;
-
-}
-
-bool AudioWin::saveOptionstoServer()
-{
- if (audiofilterselected!=-1) {
- VDR::getInstance()->configSave("DirectShow",
- "AudioFilter",audiofilterlist[audiofilterselected].displayname);
- }
- if (mp3audiofilterselected!=-1) {
- VDR::getInstance()->configSave("DirectShow",
- "Mp3AudioFilter",mp3audiofilterlist[mp3audiofilterselected].displayname);
- }
- return true;
-}
-
-UINT AudioWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)
-{
- DeliverMediaPacket(mediapacket, buffer, samplepos);
- if (*samplepos == mediapacket.length) {
- *samplepos = 0;
- return 1;
- }
- else return 0;
-}
-
-UINT AudioWin::DeliverMediaPacket(const MediaPacket packet,
- UCHAR* buffer,
- UINT *samplepos)
-{
-
- /*First Check, if we have an audio sample*/
- VideoWin *vw=(VideoWin*)Video::getInstance();
- if (!vw->isdsinited()) return 0;
- if (vw->InIframemode()) {
- samplepos=0;
- MILLISLEEP(10);
- return 0; //Not in iframe mode!
- }
- IMediaSample* ms=NULL;
- REFERENCE_TIME reftime1=0;
- REFERENCE_TIME reftime2=0;
-
- UINT headerstrip=0;
- if (packet.disconti) {
- firstsynched=false;
- vw->DeliverAudioMediaSample();
- }
-
- if (packet.type!=vw->lastAType()){//Format Change //Push data out !
- firstsynched=false;
- vw->DeliverAudioMediaSample();
- }
-
-
-
- /*Inspect PES-Header */
-/* UINT header_length=buffer[(packet.pos_buffer+8)%bufferlength]+8/*is this right*;
-*/
- if (*samplepos==0 && packet.type!=MPTYPE_MPEG_AUDIO_LAYER3) {//stripheader
- headerstrip=buffer[packet.pos_buffer+8]+9;
- if (packet.type == MPTYPE_AC3) headerstrip+=4; //skip ac3 bytes
- *samplepos+=headerstrip;
- if ( packet.synched ) {
- vw->DeliverAudioMediaSample();//write out old data
- reftime1=packet.presentation_time;
- reftime2=reftime1+1;
- firstsynched=true;
- } else {
- if (!firstsynched) {//
- *samplepos=packet.length;//if we have not processed at least one
- return packet.length;//synched packet ignore it!
- }
- }
- }
- BYTE *ms_buf;
- UINT ms_length;
- UINT ms_pos;
- UINT haveToCopy;
- if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample
- //samplepos=0;
- //MILLISLEEP(10);
- return *samplepos;
- }
- ms_pos=ms->GetActualDataLength();
- ms_length=ms->GetSize();
- haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
- if ((ms_length-ms_pos)<1) {
- vw->DeliverAudioMediaSample(); //we are full!
- if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample
- //samplepos=0;
- //MILLISLEEP(10);
- return *samplepos;
- }
- ms_pos=ms->GetActualDataLength();
- ms_length=ms->GetSize();
- haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
- }
- ms->GetPointer(&ms_buf);
-
-
- if (ms_pos==0) {//will only be changed on first packet
- if (packet.disconti) {
- ms->SetDiscontinuity(TRUE);
- } else {
- ms->SetDiscontinuity(FALSE);
- }
- if (packet.synched) {
- ms->SetSyncPoint(TRUE);
- ms->SetTime(&reftime1,&reftime2);
-
- //ms->SetTime(NULL,NULL);
- ms->SetMediaTime(NULL, NULL);
- if (reftime1<0) ms->SetPreroll(TRUE);
- else ms->SetPreroll(FALSE);
- }else {
- ms->SetSyncPoint(FALSE);
- ms->SetTime(NULL,NULL);
- ms->SetMediaTime(NULL, NULL);
- ms->SetPreroll(FALSE);
- // ms->SetSyncPoint(TRUE);
- }
- }
- if (packet.type!=vw->lastAType()) {
- vw->changeAType(packet.type,ms);
- ms->SetDiscontinuity(TRUE);
- }
-
-
- memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
-
- ms->SetActualDataLength(haveToCopy+ms_pos);
-
- *samplepos+=haveToCopy;
-
- return haveToCopy+headerstrip;
-
-}
-
-int AudioWin::dsInitAudioFilter(IGraphBuilder* dsgraphbuilder)
-{
- HRESULT hres;
- IFilterGraph2*fg2=NULL;
- VideoWin *vw=(VideoWin*)Video::getInstance();
- if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK)
- {
- Log::getInstance()->log("AudiooWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
- return 0;
- }
- IBaseFilter*audiofilter;
- if (aud_type!=Audio::MP3) {
- audiofilter = getAudioFilter();
- } else {
- audiofilter = getMp3AudioFilter();
- }
- if (hres=dsgraphbuilder->AddFilter(audiofilter,NULL) != S_OK)
- {
- Log::getInstance()->log("AudioWin", Log::WARN , "Failed adding Video Filter!");
- return 0;
- }
- IEnumPins *pinenum=NULL;
- bool error=false;
- if (audiofilter->EnumPins(&pinenum) == S_OK)
- {
- IPin *current=NULL;
- ULONG fetch=0;
- bool firststep=false;
- while (pinenum->Next(1,¤t,&fetch)==S_OK)
- {
- PIN_DIRECTION dir;
- if (current->QueryDirection(&dir)==S_OK)
- {
- if (dir == PINDIR_INPUT)
- {
- if (vw->getSourceFilter()->GetAudioPin()->Connect(current,NULL)==S_OK)
- {
- current->Release();
- firststep=true;
- break;
- }
- }
- }
- current->Release();
- }
- if (firststep==false)
- {
- Log::getInstance()->log("AudioWin", Log::WARN , "Audio Filter has no suitable input!");
- audiofilter->Release();
- return 0;
- }
- bool secondstep=false;
- pinenum->Reset();
- while (pinenum->Next(1,¤t,&fetch)==S_OK)
- {
- PIN_DIRECTION dir;
- if (current->QueryDirection(&dir)==S_OK)
- {
- if (dir == PINDIR_OUTPUT)
- {
-
- if (fg2->RenderEx((IPin*)current/*video*/,
- 0,NULL) ==S_OK)
- {
- current->Release();
- secondstep=true;
- break;
- }
- }
- }
- current->Release();
- }
- if (secondstep==false)
- {
- Log::getInstance()->log("AudioWin", Log::WARN , "Audio Filter has no suitable output!");
- audiofilter->Release();
-
- return 0;
- }
-
- audiofilter->Release();
- pinenum->Release();
-
- }
-
-
-
- fg2->Release();
- return 1;
-}
-
-
-IBaseFilter *AudioWin::getAudioFilter()
-{
- IBaseFilter *curfilter= NULL;
- bool notset=false;
- if (audiofilterselected == -1)
- {
- int i;
- for (i = 0;i <audiofilterlist.size();i++)
- {
- audiofilterselected = i;
- notset=true;
- break;
- }
- }
- IBindCtx *bindctx=NULL;
- if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
- IMoniker * moni=NULL;
- LPCOLESTR name=new WCHAR[strlen(audiofilterlist[audiofilterselected].displayname)+1];
- mbstowcs((wchar_t*)name,audiofilterlist[audiofilterselected].displayname,
- strlen(audiofilterlist[audiofilterselected].displayname)+1);
- ULONG eater;
- if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
- {
- if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
- {
- if (curfilter != NULL && notset)
- {
- VDR *vdr=VDR::getInstance();
- if (vdr != NULL)
- {
- vdr->configSave("DirectShow","AudioFilter",
- audiofilterlist[audiofilterselected].displayname);
- }
- }
-
- moni->Release();
- delete [] name;
- bindctx->Release();
- return curfilter;
- }
- bindctx->Release();
- delete [] name;
- return NULL;
- }
- return NULL;
-}
-
-IBaseFilter *AudioWin::getMp3AudioFilter()
-{
- IBaseFilter *curfilter= NULL;
- bool notset=false;
- if (mp3audiofilterselected == -1)
- {
- int i;
- for (i = 0;i <mp3audiofilterlist.size();i++)
- {
- mp3audiofilterselected = i;
- notset=true;
- break;
- }
- }
- IBindCtx *bindctx=NULL;
- if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
- IMoniker * moni=NULL;
- LPCOLESTR name=new WCHAR[strlen(mp3audiofilterlist[mp3audiofilterselected].displayname)+1];
- mbstowcs((wchar_t*)name,mp3audiofilterlist[mp3audiofilterselected].displayname,
- strlen(mp3audiofilterlist[mp3audiofilterselected].displayname)+1);
- ULONG eater;
- if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
- {
- if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
- {
- if (curfilter != NULL && notset)
- {
- VDR *vdr=VDR::getInstance();
- if (vdr != NULL)
- {
- vdr->configSave("DirectShow","Mp3AudioFilter",
- mp3audiofilterlist[mp3audiofilterselected].displayname);
- }
- }
-
- moni->Release();
- delete [] name;
- bindctx->Release();
- return curfilter;
- }
- bindctx->Release();
- delete [] name;
- return NULL;
- }
- return NULL;
-}
-
-
-bool AudioWin::addOptionPagesToWTB(WTabBar *wtb)
-{
- Boxx *box=new WWinAudioFilter();
- wtb->addTab(tr("Audio Filter"), box);
-
-
- box=new WWinMp3AudioFilter();
- wtb->addTab(tr("Mp3 Audio Filter"), box);
-
-
- return true;
-}
-
-const AudioFilterDescList *AudioWin::getAudioFilterList(int &selected)
-{
- selected=audiofilterselected;
- return &audiofilterlist;
-}
-
-const AudioFilterDescList *AudioWin::getMp3AudioFilterList(int &selected)
-{
- selected=mp3audiofilterselected;
- return &mp3audiofilterlist;
-}
-bool AudioWin::selectMp3AudioFilter(int filter)
-{
- mp3audiofilterselected=filter;
- return true;
-
-}
-
-bool AudioWin::selectAudioFilter(int filter)
-{
- audiofilterselected=filter;
- return true;
-
-}
-
-long long AudioWin::SetStartOffset(long long curreftime, bool *rsync){
- VideoWin *vw=(VideoWin*)Video::getInstance();
- return vw->SetStartAudioOffset(curreftime,rsync);
-}
-
-void AudioWin::ResetTimeOffsets() {
- VideoWin *vw=(VideoWin*)Video::getInstance();
- return vw->ResetTimeOffsets();
-}
-
-bool AudioWin::supportsAc3(){
- VideoWin *vw=(VideoWin*)Video::getInstance();
- return vw->supportsAc3();
-}
-
-#ifdef DEV
-int AudioWin::test()
-{
- return 0;
-}
-#endif
-
-
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "audiowin.h"\r
+#include "videowin.h"\r
+#include "vdr.h"\r
+#include "wtabbar.h"\r
+#include "wwinaudiofilter.h"\r
+#include "wwinmp3audiofilter.h"\r
+#include "i18n.h"\r
+\r
+\r
+\r
+\r
+AudioWin::AudioWin()\r
+{\r
+ initted = 0;\r
+ firstsynched=false;\r
+ winvolume=0;\r
+ volume=20;\r
+audiofilterselected=-1;\r
+ mp3audiofilterselected=-1;\r
+ aud_type=Audio::MPEG2_PES;\r
+\r
+}\r
+\r
+AudioWin::~AudioWin()\r
+{\r
+\r
+ int i;\r
+ for (i=0;i<audiofilterlist.size();i++)\r
+ {\r
+ if (audiofilterlist[i].displayname) delete [] audiofilterlist[i].displayname;\r
+ if (audiofilterlist[i].friendlyname) delete [] audiofilterlist[i].friendlyname;\r
+ }\r
+ audiofilterlist.clear();\r
+\r
+ for (i=0;i<mp3audiofilterlist.size();i++)\r
+ {\r
+ if (mp3audiofilterlist[i].displayname) delete [] mp3audiofilterlist[i].displayname;\r
+ if (mp3audiofilterlist[i].friendlyname) delete [] mp3audiofilterlist[i].friendlyname;\r
+ }\r
+ mp3audiofilterlist.clear();\r
+\r
+}\r
+\r
+int AudioWin::init(UCHAR tstreamType)\r
+{\r
+ if (initted) return 0;\r
+ initFilterDatabase();\r
+ initMp3FilterDatabase();\r
+ initted = 1;\r
+ return 1;\r
+}\r
+\r
+int AudioWin::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ initted = 0;\r
+ return 1;\r
+}\r
+\r
+int AudioWin::write(char *buf, int len)\r
+{\r
+ return 0; //write(fdAudio, buf, len);\r
+}\r
+\r
+int AudioWin::setStreamType(UCHAR type)\r
+{\r
+ ((VideoWin*)VideoWin::getInstance())->setAudioStreamType(type);\r
+ aud_type=type;\r
+ if (!initted) return 0;\r
+ return 1;\r
+}\r
+\r
+int AudioWin::setChannel()\r
+{\r
+ if (!initted) return 0;\r
+ return 1;\r
+}\r
+\r
+int AudioWin::setSource()\r
+{\r
+ if (!initted) return 0;\r
+ return 1;\r
+}\r
+\r
+int AudioWin::sync()\r
+{\r
+ if (!initted) return 0;\r
+ return 1;\r
+}\r
+\r
+int AudioWin::play()\r
+{\r
+ if (!initted) return 0;\r
+ firstsynched=false;\r
+ return ((VideoWin*)Video::getInstance())->dsplay();\r
+\r
+}\r
+\r
+int AudioWin::stop()\r
+{\r
+ if (!initted) return 0;\r
+ return ((VideoWin*)Video::getInstance())->dsstop();\r
+}\r
+\r
+int AudioWin::pause()\r
+{\r
+ if (!initted) return 0;\r
+ return ((VideoWin*)Video::getInstance())->dspause();\r
+}\r
+\r
+int AudioWin::unPause()\r
+{\r
+ if (!initted) return 0;\r
+ return ((VideoWin*)Video::getInstance())->dsunPause();\r
+}\r
+\r
+int AudioWin::reset()\r
+{\r
+ \r
+ if (!initted){return 0;}\r
+ return ((VideoWin*)Video::getInstance())->dsreset();\r
+}\r
+\r
+int AudioWin::setVolume(int tvolume)\r
+{\r
+ // parameter: 0 for silence, 20 for full\r
+ if ((tvolume < 0) || (tvolume > 20)) return 0;\r
+ winvolume=((tvolume-20)*100*30)/20;\r
+ if (tvolume==0) winvolume=-10000;\r
+ ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);\r
+\r
+\r
+ return 1;\r
+}\r
+\r
+int AudioWin::mute()\r
+{\r
+ if (!initted) return 0;\r
+ ((VideoWin*)Video::getInstance())->SetAudioState(false);\r
+ ((VideoWin*)Video::getInstance())->SetAudioVolume(-10000);\r
+ return 1;\r
+}\r
+\r
+int AudioWin::unMute()\r
+{\r
+ if (!initted) return 0;\r
+ ((VideoWin*)Video::getInstance())->SetAudioState(true);\r
+ ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);\r
+ return 1;\r
+}\r
+\r
+void AudioWin::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)\r
+{\r
+ mediapacket = mplist.front();\r
+}\r
+\r
+void AudioWin::initFilterDatabase()\r
+{\r
+ /* This method should determine all availiable DirectShow Filters */\r
+ IFilterMapper2* filtmap=NULL;\r
+ HRESULT result;\r
+ result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,\r
+ IID_IFilterMapper2,(void**)&filtmap);\r
+ if (result != S_OK)\r
+ {\r
+ Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");\r
+ return;\r
+ }\r
+ /* Wishlist, what Mediatypes do we want */\r
+ GUID mtypesin[]={MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO,\r
+ /*MEDIATYPE_Audio,MEDIASUBTYPE_MPEG1Payload,*/\r
+ MEDIATYPE_Audio,MEDIASUBTYPE_DOLBY_AC3,\r
+ MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3_SPDIF};\r
+ IEnumMoniker *myenum;\r
+ result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,\r
+ TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);\r
+ if (result != S_OK)\r
+ {\r
+ filtmap->Release();\r
+ Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");\r
+ return;\r
+ }\r
+ ULONG gethowmany;\r
+ IMoniker * moni;\r
+ while(myenum->Next(1,&moni,&gethowmany)==S_OK)\r
+ {\r
+ AudioFilterDesc desc;\r
+ ZeroMemory(&desc,sizeof(desc));\r
+ \r
+ LPOLESTR string;\r
+ moni->GetDisplayName(0,0,&string);\r
+ desc.displayname=new char[wcslen(string)+1];\r
+ wcstombs(desc.displayname,string,wcslen(string)+1);\r
+ CoTaskMemFree(string);\r
+ IPropertyBag *bag;\r
+ if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)\r
+ {\r
+ VARIANT vari;\r
+ VariantInit(&vari);\r
+ result = bag->Read(L"FriendlyName",&vari,NULL);\r
+ if (result == S_OK)\r
+ {\r
+ desc.friendlyname=new char[wcslen(vari.bstrVal)+1];\r
+ wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);\r
+ }\r
+ VariantClear(&vari);\r
+ bag->Release();\r
+\r
+ }\r
+ \r
+ \r
+ audiofilterlist.push_back(desc);\r
+ \r
+\r
+ \r
+ moni->Release();\r
+ // bctx->Release();\r
+ }\r
+ int i;\r
+ audiofilterselected=-1;\r
+ myenum->Release();\r
+ filtmap->Release();\r
+}\r
+\r
+void AudioWin::initMp3FilterDatabase()\r
+{\r
+ /* This method should determine all availiable DirectShow Filters */\r
+ IFilterMapper2* filtmap=NULL;\r
+ HRESULT result;\r
+ result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,\r
+ IID_IFilterMapper2,(void**)&filtmap);\r
+ if (result != S_OK)\r
+ {\r
+ Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");\r
+ return;\r
+ }\r
+ /* Wishlist, what Mediatypes do we want */\r
+ GUID mtypesin[]={MEDIATYPE_Audio,MEDIATYPE_WaveFmt_Mpeg1Layer3,\r
+ MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO};\r
+ IEnumMoniker *myenum;\r
+ result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,\r
+ TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);\r
+ if (result != S_OK)\r
+ {\r
+ filtmap->Release();\r
+ Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");\r
+ return;\r
+ }\r
+ ULONG gethowmany;\r
+ IMoniker * moni;\r
+ while(myenum->Next(1,&moni,&gethowmany)==S_OK)\r
+ {\r
+ AudioFilterDesc desc;\r
+ ZeroMemory(&desc,sizeof(desc));\r
+ \r
+ LPOLESTR string;\r
+ moni->GetDisplayName(0,0,&string);\r
+ desc.displayname=new char[wcslen(string)+1];\r
+ wcstombs(desc.displayname,string,wcslen(string)+1);\r
+ CoTaskMemFree(string);\r
+ IPropertyBag *bag;\r
+ if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)\r
+ {\r
+ VARIANT vari;\r
+ VariantInit(&vari);\r
+ result = bag->Read(L"FriendlyName",&vari,NULL);\r
+ if (result == S_OK)\r
+ {\r
+ desc.friendlyname=new char[wcslen(vari.bstrVal)+1];\r
+ wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);\r
+ }\r
+ VariantClear(&vari);\r
+ bag->Release();\r
+\r
+ }\r
+ \r
+ \r
+ mp3audiofilterlist.push_back(desc);\r
+ \r
+\r
+ \r
+ moni->Release();\r
+ // bctx->Release();\r
+ }\r
+ int i;\r
+ mp3audiofilterselected=-1;\r
+ myenum->Release();\r
+ filtmap->Release();\r
+}\r
+\r
+bool AudioWin::loadOptionsfromServer(VDR* vdr)\r
+{\r
+ char *name=vdr->configLoad("DirectShow","AudioFilter");\r
+ \r
+ if (name != NULL) \r
+ {\r
+ for (int i = 0;i <audiofilterlist.size();i++)\r
+ {\r
+ if (strcmp(name,audiofilterlist[i].displayname)==0)\r
+ {\r
+ audiofilterselected = i;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ name=vdr->configLoad("DirectShow","Mp3AudioFilter");\r
+ \r
+ if (name != NULL) \r
+ {\r
+ for (int i = 0;i <mp3audiofilterlist.size();i++)\r
+ {\r
+ if (strcmp(name,mp3audiofilterlist[i].displayname)==0)\r
+ {\r
+ mp3audiofilterselected = i;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+\r
+}\r
+\r
+bool AudioWin::saveOptionstoServer()\r
+{\r
+ if (audiofilterselected!=-1) {\r
+ VDR::getInstance()->configSave("DirectShow",\r
+ "AudioFilter",audiofilterlist[audiofilterselected].displayname);\r
+ }\r
+ if (mp3audiofilterselected!=-1) {\r
+ VDR::getInstance()->configSave("DirectShow",\r
+ "Mp3AudioFilter",mp3audiofilterlist[mp3audiofilterselected].displayname);\r
+ }\r
+ return true;\r
+}\r
+\r
+UINT AudioWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)\r
+{\r
+ DeliverMediaPacket(mediapacket, buffer, samplepos);\r
+ if (*samplepos == mediapacket.length) {\r
+ *samplepos = 0;\r
+ return 1;\r
+ }\r
+ else return 0;\r
+}\r
+\r
+UINT AudioWin::DeliverMediaPacket(const MediaPacket packet,\r
+ UCHAR* buffer,\r
+ UINT *samplepos)\r
+{\r
+\r
+ /*First Check, if we have an audio sample*/\r
+ VideoWin *vw=(VideoWin*)Video::getInstance();\r
+ if (!vw->isdsinited()) return 0;\r
+ if (vw->InIframemode()) {\r
+ samplepos=0;\r
+ MILLISLEEP(10);\r
+ return 0; //Not in iframe mode!\r
+ }\r
+ IMediaSample* ms=NULL;\r
+ REFERENCE_TIME reftime1=0;\r
+ REFERENCE_TIME reftime2=0;\r
+\r
+ UINT headerstrip=0;\r
+ if (packet.disconti) {\r
+ firstsynched=false;\r
+ vw->DeliverAudioMediaSample();\r
+ }\r
+\r
+ if (packet.type!=vw->lastAType()){//Format Change //Push data out !\r
+ firstsynched=false;\r
+ vw->DeliverAudioMediaSample();\r
+ }\r
+\r
+\r
+\r
+ /*Inspect PES-Header */\r
+/* UINT header_length=buffer[(packet.pos_buffer+8)%bufferlength]+8/*is this right*;\r
+*/\r
+ if (*samplepos==0 && packet.type!=MPTYPE_MPEG_AUDIO_LAYER3) {//stripheader\r
+ headerstrip=buffer[packet.pos_buffer+8]+9;\r
+ if (packet.type == MPTYPE_AC3) headerstrip+=4; //skip ac3 bytes\r
+ *samplepos+=headerstrip;\r
+ if ( packet.synched ) {\r
+ vw->DeliverAudioMediaSample();//write out old data\r
+ reftime1=packet.presentation_time;\r
+ reftime2=reftime1+1;\r
+ firstsynched=true;\r
+ } else {\r
+ if (!firstsynched) {//\r
+ *samplepos=packet.length;//if we have not processed at least one\r
+ return packet.length;//synched packet ignore it!\r
+ }\r
+ }\r
+ }\r
+ BYTE *ms_buf;\r
+ UINT ms_length;\r
+ UINT ms_pos;\r
+ UINT haveToCopy;\r
+ if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample\r
+ //samplepos=0;\r
+ //MILLISLEEP(10);\r
+ return *samplepos;\r
+ }\r
+ ms_pos=ms->GetActualDataLength();\r
+ ms_length=ms->GetSize();\r
+ haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);\r
+ if ((ms_length-ms_pos)<1) {\r
+ vw->DeliverAudioMediaSample(); //we are full!\r
+ if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample\r
+ //samplepos=0;\r
+ //MILLISLEEP(10);\r
+ return *samplepos;\r
+ }\r
+ ms_pos=ms->GetActualDataLength();\r
+ ms_length=ms->GetSize();\r
+ haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);\r
+ }\r
+ ms->GetPointer(&ms_buf);\r
+\r
+\r
+ if (ms_pos==0) {//will only be changed on first packet\r
+ if (packet.disconti) {\r
+ ms->SetDiscontinuity(TRUE);\r
+ } else {\r
+ ms->SetDiscontinuity(FALSE);\r
+ }\r
+ if (packet.synched) {\r
+ ms->SetSyncPoint(TRUE);\r
+ ms->SetTime(&reftime1,&reftime2);\r
+\r
+ //ms->SetTime(NULL,NULL);\r
+ ms->SetMediaTime(NULL, NULL);\r
+ if (reftime1<0) ms->SetPreroll(TRUE);\r
+ else ms->SetPreroll(FALSE);\r
+ }else {\r
+ ms->SetSyncPoint(FALSE);\r
+ ms->SetTime(NULL,NULL);\r
+ ms->SetMediaTime(NULL, NULL);\r
+ ms->SetPreroll(FALSE);\r
+ // ms->SetSyncPoint(TRUE);\r
+ }\r
+ }\r
+ if (packet.type!=vw->lastAType()) {\r
+ vw->changeAType(packet.type,ms);\r
+ ms->SetDiscontinuity(TRUE);\r
+ }\r
+\r
+\r
+ memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);\r
+\r
+ ms->SetActualDataLength(haveToCopy+ms_pos);\r
+\r
+ *samplepos+=haveToCopy;\r
+\r
+ return haveToCopy+headerstrip;\r
+\r
+}\r
+\r
+int AudioWin::dsInitAudioFilter(IGraphBuilder* dsgraphbuilder)\r
+{\r
+ HRESULT hres;\r
+ IFilterGraph2*fg2=NULL;\r
+ VideoWin *vw=(VideoWin*)Video::getInstance();\r
+ if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK)\r
+ {\r
+ Log::getInstance()->log("AudiooWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");\r
+ return 0;\r
+ }\r
+ IBaseFilter*audiofilter;\r
+ if (aud_type!=Audio::MP3) {\r
+ audiofilter = getAudioFilter();\r
+ } else {\r
+ audiofilter = getMp3AudioFilter();\r
+ }\r
+ if (dsgraphbuilder->AddFilter(audiofilter,NULL) != S_OK)\r
+ {\r
+ Log::getInstance()->log("AudioWin", Log::WARN , "Failed adding Video Filter!");\r
+ return 0;\r
+ }\r
+ IEnumPins *pinenum=NULL;\r
+ bool error=false;\r
+ if (audiofilter->EnumPins(&pinenum) == S_OK)\r
+ {\r
+ IPin *current=NULL;\r
+ ULONG fetch=0;\r
+ bool firststep=false;\r
+ while (pinenum->Next(1,¤t,&fetch)==S_OK)\r
+ {\r
+ PIN_DIRECTION dir;\r
+ if (current->QueryDirection(&dir)==S_OK)\r
+ {\r
+ if (dir == PINDIR_INPUT)\r
+ {\r
+ if (vw->getSourceFilter()->GetAudioPin()->Connect(current,NULL)==S_OK)\r
+ {\r
+ current->Release();\r
+ firststep=true;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ current->Release();\r
+ }\r
+ if (firststep==false)\r
+ {\r
+ Log::getInstance()->log("AudioWin", Log::WARN , "Audio Filter has no suitable input!");\r
+ audiofilter->Release();\r
+ return 0;\r
+ }\r
+ bool secondstep=false;\r
+ pinenum->Reset();\r
+ while (pinenum->Next(1,¤t,&fetch)==S_OK)\r
+ {\r
+ PIN_DIRECTION dir;\r
+ if (current->QueryDirection(&dir)==S_OK)\r
+ {\r
+ if (dir == PINDIR_OUTPUT)\r
+ {\r
+ \r
+ if (fg2->RenderEx((IPin*)current/*video*/,\r
+ 0,NULL) ==S_OK)\r
+ {\r
+ current->Release();\r
+ secondstep=true;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ current->Release();\r
+ }\r
+ if (secondstep==false)\r
+ {\r
+ Log::getInstance()->log("AudioWin", Log::WARN , "Audio Filter has no suitable output!");\r
+ audiofilter->Release();\r
+ \r
+ return 0;\r
+ }\r
+ \r
+ audiofilter->Release();\r
+ pinenum->Release();\r
+\r
+ }\r
+\r
+\r
+\r
+ fg2->Release();\r
+ return 1;\r
+}\r
+\r
+\r
+IBaseFilter *AudioWin::getAudioFilter()\r
+{\r
+ IBaseFilter *curfilter= NULL;\r
+ bool notset=false;\r
+ if (audiofilterselected == -1)\r
+ {\r
+ int i;\r
+ for (i = 0;i <audiofilterlist.size();i++)\r
+ {\r
+ audiofilterselected = i;\r
+ notset=true;\r
+ break;\r
+ }\r
+ }\r
+ IBindCtx *bindctx=NULL;\r
+ if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+ IMoniker * moni=NULL;\r
+ LPCOLESTR name=new WCHAR[strlen(audiofilterlist[audiofilterselected].displayname)+1];\r
+ mbstowcs((wchar_t*)name,audiofilterlist[audiofilterselected].displayname,\r
+ strlen(audiofilterlist[audiofilterselected].displayname)+1);\r
+ ULONG eater;\r
+ if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+ {\r
+ if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+ {\r
+ if (curfilter != NULL && notset)\r
+ {\r
+ VDR *vdr=VDR::getInstance();\r
+ if (vdr != NULL)\r
+ {\r
+ vdr->configSave("DirectShow","AudioFilter",\r
+ audiofilterlist[audiofilterselected].displayname);\r
+ }\r
+ }\r
+ \r
+ moni->Release();\r
+ delete [] name;\r
+ bindctx->Release();\r
+ return curfilter; \r
+ }\r
+ bindctx->Release();\r
+ delete [] name;\r
+ return NULL; \r
+ }\r
+ return NULL; \r
+}\r
+\r
+IBaseFilter *AudioWin::getMp3AudioFilter()\r
+{\r
+ IBaseFilter *curfilter= NULL;\r
+ bool notset=false;\r
+ if (mp3audiofilterselected == -1)\r
+ {\r
+ int i;\r
+ for (i = 0;i <mp3audiofilterlist.size();i++)\r
+ {\r
+ mp3audiofilterselected = i;\r
+ notset=true;\r
+ break;\r
+ }\r
+ }\r
+ IBindCtx *bindctx=NULL;\r
+ if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+ IMoniker * moni=NULL;\r
+ LPCOLESTR name=new WCHAR[strlen(mp3audiofilterlist[mp3audiofilterselected].displayname)+1];\r
+ mbstowcs((wchar_t*)name,mp3audiofilterlist[mp3audiofilterselected].displayname,\r
+ strlen(mp3audiofilterlist[mp3audiofilterselected].displayname)+1);\r
+ ULONG eater;\r
+ if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+ {\r
+ if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+ {\r
+ if (curfilter != NULL && notset)\r
+ {\r
+ VDR *vdr=VDR::getInstance();\r
+ if (vdr != NULL)\r
+ {\r
+ vdr->configSave("DirectShow","Mp3AudioFilter",\r
+ mp3audiofilterlist[mp3audiofilterselected].displayname);\r
+ }\r
+ }\r
+ \r
+ moni->Release();\r
+ delete [] name;\r
+ bindctx->Release();\r
+ return curfilter; \r
+ }\r
+ bindctx->Release();\r
+ delete [] name;\r
+ return NULL; \r
+ }\r
+ return NULL; \r
+}\r
+\r
+\r
+bool AudioWin::addOptionPagesToWTB(WTabBar *wtb)\r
+{\r
+ Boxx *box=new WWinAudioFilter();\r
+ wtb->addTab(tr("Audio Filter"), box);\r
+\r
+ \r
+ box=new WWinMp3AudioFilter();\r
+ wtb->addTab(tr("Mp3 Audio Filter"), box);\r
+ \r
+\r
+ return true;\r
+}\r
+\r
+const AudioFilterDescList *AudioWin::getAudioFilterList(int &selected)\r
+{\r
+ selected=audiofilterselected;\r
+ return &audiofilterlist;\r
+}\r
+\r
+const AudioFilterDescList *AudioWin::getMp3AudioFilterList(int &selected)\r
+{\r
+ selected=mp3audiofilterselected;\r
+ return &mp3audiofilterlist;\r
+}\r
+bool AudioWin::selectMp3AudioFilter(int filter)\r
+{\r
+ mp3audiofilterselected=filter;\r
+ return true;\r
+ \r
+}\r
+\r
+bool AudioWin::selectAudioFilter(int filter)\r
+{\r
+ audiofilterselected=filter;\r
+ return true;\r
+ \r
+}\r
+\r
+long long AudioWin::SetStartOffset(long long curreftime, bool *rsync){\r
+ VideoWin *vw=(VideoWin*)Video::getInstance();\r
+ return vw->SetStartAudioOffset(curreftime,rsync);\r
+}\r
+\r
+void AudioWin::ResetTimeOffsets() {\r
+ VideoWin *vw=(VideoWin*)Video::getInstance();\r
+ vw->ResetTimeOffsets();\r
+}\r
+\r
+bool AudioWin::supportsAc3(){\r
+ VideoWin *vw=(VideoWin*)Video::getInstance();\r
+ return vw->supportsAc3();\r
+}\r
+\r
+#ifdef DEV\r
+int AudioWin::test()\r
+{\r
+ return 0;\r
+}\r
+#endif\r
+\r
+\r
+\r
const std::vector<UCHAR>& getCrVector() const { return Cr; }
const std::vector<UCHAR>& getCbVector() const { return Cb; }
const std::vector<UCHAR>& getAVector() const { return A; }
+ const UINT getNumColours()const{return numColours;};
private:
const static UINT MAX_DEPTH = 8;
std::vector<ULONG> colour;
void setAllIndices(UCHAR index);
};
+
#endif
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "boxstack.h"
-
-#include "command.h"
-#include "remote.h"
-#include "log.h"
-
-BoxStack* BoxStack::instance = NULL;
-
-BoxStack::BoxStack()
-{
- if (instance) return;
- instance = this;
- initted = 0;
- numBoxes = 0;
-}
-
-BoxStack::~BoxStack()
-{
- instance = NULL;
-}
-
-BoxStack* BoxStack::getInstance()
-{
- return instance;
-}
-
-int BoxStack::init()
-{
- if (initted) return 0;
- initted = 1;
-
-#ifndef WIN32
- pthread_mutex_init(&boxLock, NULL);
-#else
- boxLock = CreateMutex(NULL,FALSE,NULL);
-#endif
-
- return 1;
-}
-
-int BoxStack::shutdown()
-{
- if (!initted) return 0;
-
- // FIXME don't think this can work properly, removeAll leaves the wallpaper there!
- removeAll();
-
- initted = 0;
- return 1;
-}
-
-int BoxStack::add(Boxx* v)
-{
- if (!initted) return 0;
- Log::getInstance()->log("BoxStack", Log::DEBUG, "add called");
-#ifndef WIN32
- pthread_mutex_lock(&boxLock);
-#else
- WaitForSingleObject(boxLock, INFINITE);
-#endif
- Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for add");
-
- if (numBoxes == 16)
- { //Error
- Log::getInstance()->log("BoxStack", Log::ERR, "More than 16 boxes! Unlocked for add");
-#ifndef WIN32
- pthread_mutex_unlock(&boxLock);
-#else
- ReleaseMutex(boxLock);
-#endif
- return 0;
- }
- boxes[numBoxes++] = v;
-
-#ifndef WIN32
- pthread_mutex_unlock(&boxLock);
-#else
- ReleaseMutex(boxLock);
-#endif
-
- Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for add");
-
- return 1;
-}
-
-// ---------------------------------------------------- REMOVE CODE
-
-int BoxStack::remove(Boxx* toDelete)
-{
- if (!initted) return 0;
-
- #ifndef WIN32
- pthread_mutex_lock(&boxLock);
- #else
- WaitForSingleObject(boxLock, INFINITE);
- #endif
- Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for remove");
-
- if (numBoxes == 0)
- {
- #ifndef WIN32
- pthread_mutex_unlock(&boxLock);
- #else
- ReleaseMutex(boxLock);
- #endif
- Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove numBoxes == 0");
- return 0;
- }
-
-// Log::getInstance()->log("BoxStack", Log::DEBUG, "entering remove, numBoxes=%i", numBoxes);
-
- int i;
-
- if (toDelete == NULL)
- {
- toDelete = boxes[numBoxes-1];
- i = numBoxes - 1;
- }
- else
- {
- // to be deleted box is more likely to be at the top
- for (i = numBoxes-1; i >= 0; i--)
- {
-// Log::getInstance()->log("BoxStack", Log::DEBUG, "todel: %p, i=%i, boxes[i]=%p", toDelete, i, boxes[i]);
- if (boxes[i] == toDelete) break;
- }
-
- if (i == -1)
- {
- // not a Box we have!
- // FIXME
- #ifndef WIN32
- pthread_mutex_unlock(&boxLock);
- #else
- ReleaseMutex(boxLock);
- #endif
- Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove - no boxx deleted");
- return 0;
- }
- }
-
-#ifndef WIN32
- pthread_mutex_unlock(&boxLock);
-#else
- ReleaseMutex(boxLock);
-#endif
-
-toDelete->preDelete();
-
-#ifndef WIN32
- pthread_mutex_lock(&boxLock);
-#else
- WaitForSingleObject(boxLock, INFINITE);
-#endif
-
-// Log::getInstance()->log("BoxStack", Log::DEBUG, "Starting deleteBox");
- deleteBox(i);
-// Log::getInstance()->log("BoxStack", Log::DEBUG, "Done deleteBox");
-
- // Shift the boxes on top down one
- --numBoxes;
- for(int j = i; j < numBoxes; j++) boxes[j] = boxes[j+1];
-
- // If there is only the wallpaper left signal command
- if (numBoxes == 1)
- {
- Message* m = new Message();
- m->to = Command::getInstance();
- m->message = Message::LAST_VIEW_CLOSE;
- Command::getInstance()->postMessageNoLock(m);
- }
-
-#ifndef WIN32
- pthread_mutex_unlock(&boxLock);
-#else
- ReleaseMutex(boxLock);
-#endif
- Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for remove");
-
- // Delete the box
- //AVO: do this delete outside the lock to allow for recursive calls within the destructor
- // as this box is not in the stack any more, there is no chance for a second delete
- Log::getInstance()->log("BoxStack", Log::DEBUG, "remove: going to delete boxx %p, num %d", toDelete, numBoxes);
- delete toDelete;
-
- return 1;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// NEW STUFF
-/////////////////////////////////////////////////////////////////////////////
-
-void BoxStack::deleteBox(int z)
-{
-// Log::getInstance()->log("BoxStack", Log::DEBUG, "Delete box %i of %i", z, numBoxes);
- RegionList rl;
- boxSplit(boxes[z]->area, z + 1, numBoxes, 1, rl);
- while(!rl.empty())
- {
- repaintRevealed(z, rl.front());
- rl.pop_front();
- }
-}
-
-void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)
-{
- Log::getInstance()->log("BoxStack", Log::DEBUG, "Update called");
-
-#ifndef WIN32
- pthread_mutex_lock(&boxLock);
-#else
- WaitForSingleObject(boxLock, INFINITE);
-#endif
- Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for update");
-
- // Get the z index of the box
- int z = 0;
- if (toUpdate)
- {
- for (z = 0; z < numBoxes; z++)
- {
- if (boxes[z] == toUpdate) break;
- }
-
- if (z == numBoxes)
- {
- // not a Box we have!
- #ifndef WIN32
- pthread_mutex_unlock(&boxLock);
- #else
- ReleaseMutex(boxLock);
- #endif
- Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for update! box not inside boxstack");
- return;
- }
- }
- else
- {
- toUpdate = boxes[0];
- }
-
- // get the region for the whole box, could be less than that
- // for smaller updates
-
- Region r = toUpdate->area;
-
- if (regionToUpdate)
- {
- // Can be null if the whole box should be updated
- // If this is given the numbers are relative to the size of the box, not the screen
-
- r.x += regionToUpdate->x;
- r.y += regionToUpdate->y;
- r.w = regionToUpdate->w;
- r.h = regionToUpdate->h;
- }
-
- RegionList rl;
-
- Region r2;
- boxSplit(r, z+1, numBoxes, 1, rl);
- while(!rl.empty())
- {
- r2 = rl.front();
- r2.z = z;
- boxes[z]->blt(r2);
- rl.pop_front();
- }
-
-#ifndef WIN32
- pthread_mutex_unlock(&boxLock);
-#else
- ReleaseMutex(boxLock);
-#endif
- Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for update");
-}
-
-void BoxStack::repaintRevealed(int x, Region r)
-{
- RegionList rl;
- boxSplit(r, x - 1, -1, -1, rl);
-
- Region r2;
- while(!rl.empty())
- {
- r2 = rl.front();
- boxes[r2.z]->blt(r2);
- rl.pop_front();
- }
-}
-
-void BoxStack::boxSplit(Region r, int start, int end, int direction, RegionList& rl)
-{
-// printf("Y= S=%i E=%i D=%i: Boxsplit: %i %i %i %i\n", start, end, direction, r.x, r.y, r.w, r.h);
-
- for(int z = start; z != end; z += direction)
- {
- if (r.overlappedBy(boxes[z]->area))
- {
-// printf("Z=%i S=%i E=%i D=%i: %i overlaps\n", z, start, end, direction, z);
-
- int top = r.y;
- int btm = r.y2();
-
- if (boxes[z]->area.y > r.y)
- {
-// printf("Z=%i S=%i E=%i D=%i: Case 1 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
- top = boxes[z]->area.y;
- Region newR;
- newR.x = r.x;
- newR.y = r.y;
- newR.w = r.w;
- newR.h = boxes[z]->area.y - r.y;
- boxSplit(newR, z + direction, end, direction, rl);
-
- if (direction == -1)
- {
- Region newR2;
- newR2.x = r.x;
- newR2.y = boxes[z]->area.y;
- newR2.w = r.w;
- newR2.h = r.h - newR.h;
- boxSplit(newR2, z, end, -1, rl);
- return;
- }
- }
-
- if (boxes[z]->area.y2() < r.y2())
- {
-// printf("Z=%i S=%i E=%i D=%i: Case 2 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
- btm = boxes[z]->area.y2();
- Region newR;
- newR.x = r.x;
- newR.y = boxes[z]->area.y2() + 1;
- newR.w = r.w;
- newR.h = r.y2() - newR.y + 1;
- boxSplit(newR, z + direction, end, direction, rl);
-
- if (direction == -1)
- {
- Region newR2;
- newR2.x = r.x;
- newR2.y = r.y;
- newR2.w = r.w;
- newR2.h = r.h - newR.h;
- boxSplit(newR2, z, end, -1, rl);
- return;
- }
- }
-
- if (boxes[z]->area.x > r.x)
- {
-// printf("Z=%i S=%i E=%i D=%i: Case 3 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
- Region newR;
- newR.x = r.x;
- newR.y = top;
- newR.w = boxes[z]->area.x - r.x;
- newR.h = btm - top + 1;
- boxSplit(newR, z + direction, end, direction, rl);
-
- if (direction == -1)
- {
- Region newR2;
- newR2.x = r.x + newR.w;
- newR2.y = r.y;
- newR2.w = r.w - newR.w;
- newR2.h = r.h;
- boxSplit(newR2, z, end, -1, rl);
- return;
- }
- }
-
- if (boxes[z]->area.x2() < r.x2())
- {
-// printf("Z=%i S=%i E=%i D=%i: Case 4 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
- Region newR;
- newR.x = boxes[z]->area.x2() + 1;
- newR.y = top;
- newR.w = r.x2() - newR.x + 1;
- newR.h = btm - top + 1;
- boxSplit(newR, z + direction, end, direction, rl);
-
- if (direction == -1)
- {
- Region newR2;
- newR2.x = r.x;
- newR2.y = r.y;
- newR2.w = r.w - newR.w;
- newR2.h = r.h;
- boxSplit(newR2, z, end, -1, rl);
- return;
- }
- }
-
- if (direction == -1)
- {
- // we are going down the stack
- // r is underlapped by boxes[z]
- // but we have not split
- // Therefore this region under test is
- // completely covering boxes[z]
-
- // don't go any further down, generate a region and quit
-
-// printf("Repaint region: %i %i %i %i\n", r.x, r.y, r.w, r.h);
- r.z = z;
- rl.push_front(r);
- }
-
-// printf("Returning from Z=%i\n", z);
- return;
- }
- else
- {
-// printf("Z=%i S=%i E=%i D=%i: %i does not overlap\n", z, start, end, direction, z);
- }
- }
-
- // if direction = 1 then we have come to a region that is
- // entirely clear of higher boxes and needs to be redrawn
-
- // if direction = -1 then we have come to a region that is on
- // the very bottom with nothing below it to repaint.
- // do nothing. stale window data will be left on screen?
-
- if (direction == 1)
- {
- rl.push_front(r);
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// END NEW STUFF
-/////////////////////////////////////////////////////////////////////////////
-
-// ---------------------------------------------------- END OF REMOVE CODE
-
-
-void BoxStack::removeAll()
-{
- // 1.. Don't delete wallpaper. No point.
-
- // Need locking on this one??
-
- // This is pretty silly now that preDelete needs mutex unlocked
-
- Boxx* toDel = NULL;
-
- while(numBoxes > 1)
- {
- #ifndef WIN32
- pthread_mutex_lock(&boxLock);
- #else
- WaitForSingleObject(boxLock, INFINITE);
- #endif
-
- if (numBoxes == 1)
- {
- #ifndef WIN32
- pthread_mutex_unlock(&boxLock);
- #else
- ReleaseMutex(boxLock);
- #endif
- break;
- }
-
- toDel = boxes[numBoxes - 1];
-
- #ifndef WIN32
- pthread_mutex_unlock(&boxLock);
- #else
- ReleaseMutex(boxLock);
- #endif
-
- toDel->preDelete();
-
- #ifndef WIN32
- pthread_mutex_lock(&boxLock);
- #else
- WaitForSingleObject(boxLock, INFINITE);
- #endif
-
- // If boxes[numBoxes - 1] isn't toDel then there's a problem
- if (boxes[numBoxes - 1] == toDel)
- {
- --numBoxes;
- }
- else
- {
- Log::getInstance()->log("BoxStack", Log::ERR, "Can this actually happen? Why?");
- toDel = NULL;
- }
-
- #ifndef WIN32
- pthread_mutex_unlock(&boxLock);
- #else
- ReleaseMutex(boxLock);
- #endif
-
- //AVO: do the delete outside the lock to allow for recursive deletes
- Log::getInstance()->log("BoxStack", Log::DEBUG, "going to delete boxx %p, num=%d", toDel, numBoxes);
- if (toDel) delete toDel;
- }
-}
-
-int BoxStack::handleCommand(int command)
-{
- int retVal;
- int retVal2 = 0;
- int i;
-
- if (command != Remote::NA_NONE)
- {
- // handle command return values
- // 0 - drop through to next box
- // 1 - dont drop to next box, but not handled
- // 2 - handled - stop command here
- // 4 - handled - delete this box
-
- for (i=numBoxes-1; i>=0; i--)
- {
-// Log::getInstance()->log("BoxStack", Log::DEBUG, "Giving command to i=%i", i);
- retVal = boxes[i]->handleCommand(command);
- if (retVal == 1)
- {
- // not handled but don't give to any more boxes
- return 0;
- }
-
- if (retVal == 2)
- {
- // command handled
- retVal2 = 1;
- break;
- }
- else if (retVal == 4)
- {
-// Log::getInstance()->log("BoxStack", Log::DEBUG, "Return 4: i=%i, boxes[i]=%p", i, boxes[i]);
- remove(boxes[i]);
- retVal2 = 1;
- break;
- }
- }
- }
- else
- {
- // fake the return code
- retVal2 = 2;
- }
-
- return retVal2;
-}
-
-void BoxStack::processMessage(Message* m)
-{
- if (m->to != this)
- {
- for (int i = numBoxes-1; i >= 0; i--)
- {
- if (boxes[i] == m->to)
- {
- Log::getInstance()->log("BoxStack", Log::DEBUG, "sending message from box %p to box %p %lu", m->from, m->to, m->message);
- boxes[i]->processMessage(m);
- return;
- }
- }
- return;
- }
-
- /* Handle mouse events*/
- // They come in with m->to = NULL? and just need to be delivered to top box?
- if ((numBoxes > 1) && ((m->message == Message::MOUSE_MOVE) || (m->message == Message::MOUSE_LBDOWN)))
- {
- boxes[numBoxes-1]->processMessage(m);
- return;
- }
-
- Log::getInstance()->log("BoxStack", Log::DEBUG, "it's for meeee!");
-
- switch(m->message)
- {
- case Message::CLOSE_ME:
- {
- remove((Boxx*)m->from);
- break;
- }
- case Message::ADD_VIEW: // currently not used by anything but it might come in useful again
- {
- Boxx* toAdd = (Boxx*)m->parameter;
- add(toAdd);
- toAdd->draw();
- update(toAdd);
- break;
- }
- }
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "boxstack.h"\r
+\r
+#include "command.h"\r
+#include "remote.h"\r
+#include "log.h"\r
+\r
+BoxStack* BoxStack::instance = NULL;\r
+\r
+BoxStack::BoxStack()\r
+{\r
+ if (instance) return;\r
+ instance = this;\r
+ initted = 0;\r
+ numBoxes = 0;\r
+}\r
+\r
+BoxStack::~BoxStack()\r
+{\r
+ instance = NULL;\r
+}\r
+\r
+BoxStack* BoxStack::getInstance()\r
+{\r
+ return instance;\r
+}\r
+\r
+int BoxStack::init()\r
+{\r
+ if (initted) return 0;\r
+ initted = 1;\r
+ \r
+#ifndef WIN32\r
+ pthread_mutex_init(&boxLock, NULL);\r
+#else\r
+ boxLock = CreateMutex(NULL,FALSE,NULL);\r
+#endif\r
+\r
+ return 1;\r
+}\r
+\r
+int BoxStack::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ // FIXME don't think this can work properly, removeAll leaves the wallpaper there!\r
+ removeAll();\r
+\r
+ initted = 0;\r
+ return 1;\r
+}\r
+\r
+int BoxStack::add(Boxx* v)\r
+{\r
+ if (!initted) return 0;\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "add called"); \r
+#ifndef WIN32\r
+ pthread_mutex_lock(&boxLock);\r
+#else\r
+ WaitForSingleObject(boxLock, INFINITE);\r
+#endif\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for add"); \r
+ \r
+ if (numBoxes == 16)\r
+ { //Error\r
+ Log::getInstance()->log("BoxStack", Log::ERR, "More than 16 boxes! Unlocked for add"); \r
+#ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+#else\r
+ ReleaseMutex(boxLock);\r
+#endif\r
+ return 0;\r
+ }\r
+ boxes[numBoxes++] = v;\r
+\r
+#ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+#else\r
+ ReleaseMutex(boxLock);\r
+#endif\r
+\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for add");\r
+ \r
+ return 1;\r
+}\r
+\r
+// ---------------------------------------------------- REMOVE CODE\r
+\r
+int BoxStack::remove(Boxx* toDelete)\r
+{\r
+ if (!initted) return 0;\r
+\r
+ #ifndef WIN32\r
+ pthread_mutex_lock(&boxLock);\r
+ #else\r
+ WaitForSingleObject(boxLock, INFINITE);\r
+ #endif\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for remove"); \r
+ \r
+ if (numBoxes == 0)\r
+ {\r
+ #ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+ #else\r
+ ReleaseMutex(boxLock);\r
+ #endif\r
+ Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove numBoxes == 0"); \r
+ return 0;\r
+ }\r
+\r
+// Log::getInstance()->log("BoxStack", Log::DEBUG, "entering remove, numBoxes=%i", numBoxes);\r
+\r
+ int i;\r
+\r
+ if (toDelete == NULL)\r
+ {\r
+ toDelete = boxes[numBoxes-1];\r
+ i = numBoxes - 1;\r
+ }\r
+ else\r
+ {\r
+ // to be deleted box is more likely to be at the top\r
+ for (i = numBoxes-1; i >= 0; i--)\r
+ {\r
+// Log::getInstance()->log("BoxStack", Log::DEBUG, "todel: %p, i=%i, boxes[i]=%p", toDelete, i, boxes[i]);\r
+ if (boxes[i] == toDelete) break;\r
+ }\r
+\r
+ if (i == -1)\r
+ {\r
+ // not a Box we have!\r
+ // FIXME\r
+ #ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+ #else\r
+ ReleaseMutex(boxLock);\r
+ #endif\r
+ Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove - no boxx deleted"); \r
+ return 0;\r
+ }\r
+ }\r
+\r
+#ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+#else\r
+ ReleaseMutex(boxLock);\r
+#endif\r
+\r
+toDelete->preDelete();\r
+\r
+#ifndef WIN32\r
+ pthread_mutex_lock(&boxLock);\r
+#else\r
+ WaitForSingleObject(boxLock, INFINITE);\r
+#endif\r
+\r
+// Log::getInstance()->log("BoxStack", Log::DEBUG, "Starting deleteBox");\r
+ deleteBox(i);\r
+// Log::getInstance()->log("BoxStack", Log::DEBUG, "Done deleteBox");\r
+\r
+ // Shift the boxes on top down one\r
+ --numBoxes;\r
+ for(int j = i; j < numBoxes; j++) boxes[j] = boxes[j+1];\r
+\r
+ // If there is only the wallpaper left signal command\r
+ if (numBoxes == 1)\r
+ {\r
+ Message* m = new Message();\r
+ m->to = Command::getInstance();\r
+ m->message = Message::LAST_VIEW_CLOSE;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ }\r
+\r
+#ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+#else\r
+ ReleaseMutex(boxLock);\r
+#endif\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for remove"); \r
+ \r
+ // Delete the box\r
+ //AVO: do this delete outside the lock to allow for recursive calls within the destructor\r
+ // as this box is not in the stack any more, there is no chance for a second delete\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "remove: going to delete boxx %p, num %d", toDelete, numBoxes); \r
+ delete toDelete;\r
+\r
+ return 1;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// NEW STUFF\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+void BoxStack::deleteBox(int z)\r
+{\r
+// Log::getInstance()->log("BoxStack", Log::DEBUG, "Delete box %i of %i", z, numBoxes);\r
+ RegionList rl;\r
+ boxSplit(boxes[z]->area, z + 1, numBoxes, 1, rl);\r
+ while(!rl.empty())\r
+ {\r
+ repaintRevealed(z, rl.front());\r
+ rl.pop_front();\r
+ }\r
+}\r
+\r
+void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)\r
+{\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "Update called");\r
+\r
+#ifndef WIN32\r
+ pthread_mutex_lock(&boxLock);\r
+#else\r
+ WaitForSingleObject(boxLock, INFINITE);\r
+#endif\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for update");\r
+\r
+ // Get the z index of the box\r
+ int z = 0;\r
+ if (toUpdate)\r
+ {\r
+ for (z = 0; z < numBoxes; z++)\r
+ {\r
+ if (boxes[z] == toUpdate) break;\r
+ }\r
+\r
+ if (z == numBoxes)\r
+ {\r
+ // not a Box we have!\r
+ #ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+ #else\r
+ ReleaseMutex(boxLock);\r
+ #endif \r
+ Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for update! box not inside boxstack");\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ toUpdate = boxes[0];\r
+ }\r
+\r
+ // get the region for the whole box, could be less than that\r
+ // for smaller updates\r
+\r
+ Region r = toUpdate->area;\r
+\r
+ if (regionToUpdate)\r
+ {\r
+ // Can be null if the whole box should be updated\r
+ // If this is given the numbers are relative to the size of the box, not the screen\r
+\r
+ r.x += regionToUpdate->x;\r
+ r.y += regionToUpdate->y;\r
+ r.w = regionToUpdate->w;\r
+ r.h = regionToUpdate->h;\r
+ }\r
+\r
+ RegionList rl;\r
+\r
+ Region r2;\r
+ boxSplit(r, z+1, numBoxes, 1, rl);\r
+ while(!rl.empty())\r
+ {\r
+ r2 = rl.front();\r
+ r2.z = z;\r
+ boxes[z]->blt(r2);\r
+ rl.pop_front();\r
+ }\r
+ \r
+#ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+#else\r
+ ReleaseMutex(boxLock);\r
+#endif \r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for update");\r
+}\r
+\r
+void BoxStack::repaintRevealed(int x, Region r)\r
+{\r
+ RegionList rl;\r
+ boxSplit(r, x - 1, -1, -1, rl);\r
+\r
+ Region r2;\r
+ while(!rl.empty())\r
+ {\r
+ r2 = rl.front();\r
+ boxes[r2.z]->blt(r2);\r
+ rl.pop_front();\r
+ }\r
+}\r
+\r
+void BoxStack::boxSplit(Region r, int start, int end, int direction, RegionList& rl)\r
+{\r
+// printf("Y= S=%i E=%i D=%i: Boxsplit: %i %i %i %i\n", start, end, direction, r.x, r.y, r.w, r.h);\r
+\r
+ for(int z = start; z != end; z += direction)\r
+ {\r
+ if (r.overlappedBy(boxes[z]->area))\r
+ {\r
+// printf("Z=%i S=%i E=%i D=%i: %i overlaps\n", z, start, end, direction, z);\r
+\r
+ int top = r.y;\r
+ int btm = r.y2();\r
+\r
+ if (boxes[z]->area.y > r.y)\r
+ {\r
+// printf("Z=%i S=%i E=%i D=%i: Case 1 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);\r
+ top = boxes[z]->area.y;\r
+ Region newR;\r
+ newR.x = r.x;\r
+ newR.y = r.y;\r
+ newR.w = r.w;\r
+ newR.h = boxes[z]->area.y - r.y;\r
+ boxSplit(newR, z + direction, end, direction, rl);\r
+\r
+ if (direction == -1)\r
+ {\r
+ Region newR2;\r
+ newR2.x = r.x;\r
+ newR2.y = boxes[z]->area.y;\r
+ newR2.w = r.w;\r
+ newR2.h = r.h - newR.h;\r
+ boxSplit(newR2, z, end, -1, rl);\r
+ return;\r
+ }\r
+ }\r
+\r
+ if (boxes[z]->area.y2() < r.y2())\r
+ {\r
+// printf("Z=%i S=%i E=%i D=%i: Case 2 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);\r
+ btm = boxes[z]->area.y2();\r
+ Region newR;\r
+ newR.x = r.x;\r
+ newR.y = boxes[z]->area.y2() + 1;\r
+ newR.w = r.w;\r
+ newR.h = r.y2() - newR.y + 1;\r
+ boxSplit(newR, z + direction, end, direction, rl);\r
+\r
+ if (direction == -1)\r
+ {\r
+ Region newR2;\r
+ newR2.x = r.x;\r
+ newR2.y = r.y;\r
+ newR2.w = r.w;\r
+ newR2.h = r.h - newR.h;\r
+ boxSplit(newR2, z, end, -1, rl);\r
+ return;\r
+ }\r
+ }\r
+\r
+ if (boxes[z]->area.x > r.x)\r
+ {\r
+// printf("Z=%i S=%i E=%i D=%i: Case 3 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);\r
+ Region newR;\r
+ newR.x = r.x;\r
+ newR.y = top;\r
+ newR.w = boxes[z]->area.x - r.x;\r
+ newR.h = btm - top + 1;\r
+ boxSplit(newR, z + direction, end, direction, rl);\r
+\r
+ if (direction == -1)\r
+ {\r
+ Region newR2;\r
+ newR2.x = r.x + newR.w;\r
+ newR2.y = r.y;\r
+ newR2.w = r.w - newR.w;\r
+ newR2.h = r.h;\r
+ boxSplit(newR2, z, end, -1, rl);\r
+ return;\r
+ }\r
+ }\r
+\r
+ if (boxes[z]->area.x2() < r.x2())\r
+ {\r
+// printf("Z=%i S=%i E=%i D=%i: Case 4 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);\r
+ Region newR;\r
+ newR.x = boxes[z]->area.x2() + 1;\r
+ newR.y = top;\r
+ newR.w = r.x2() - newR.x + 1;\r
+ newR.h = btm - top + 1;\r
+ boxSplit(newR, z + direction, end, direction, rl);\r
+\r
+ if (direction == -1)\r
+ {\r
+ Region newR2;\r
+ newR2.x = r.x;\r
+ newR2.y = r.y;\r
+ newR2.w = r.w - newR.w;\r
+ newR2.h = r.h;\r
+ boxSplit(newR2, z, end, -1, rl);\r
+ return;\r
+ }\r
+ }\r
+\r
+ if (direction == -1)\r
+ {\r
+ // we are going down the stack\r
+ // r is underlapped by boxes[z]\r
+ // but we have not split\r
+ // Therefore this region under test is\r
+ // completely covering boxes[z]\r
+\r
+ // don't go any further down, generate a region and quit\r
+\r
+// printf("Repaint region: %i %i %i %i\n", r.x, r.y, r.w, r.h);\r
+ r.z = z;\r
+ rl.push_front(r);\r
+ }\r
+\r
+// printf("Returning from Z=%i\n", z);\r
+ return;\r
+ }\r
+ else\r
+ {\r
+// printf("Z=%i S=%i E=%i D=%i: %i does not overlap\n", z, start, end, direction, z);\r
+ }\r
+ }\r
+\r
+ // if direction = 1 then we have come to a region that is\r
+ // entirely clear of higher boxes and needs to be redrawn\r
+\r
+ // if direction = -1 then we have come to a region that is on\r
+ // the very bottom with nothing below it to repaint.\r
+ // do nothing. stale window data will be left on screen?\r
+\r
+ if (direction == 1)\r
+ {\r
+ rl.push_front(r);\r
+ }\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// END NEW STUFF\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+// ---------------------------------------------------- END OF REMOVE CODE\r
+\r
+\r
+void BoxStack::removeAll()\r
+{\r
+ // 1.. Don't delete wallpaper. No point.\r
+\r
+ // Need locking on this one??\r
+ \r
+ // This is pretty silly now that preDelete needs mutex unlocked\r
+ \r
+ Boxx* toDel = NULL;\r
+ \r
+ while(numBoxes > 1)\r
+ {\r
+ #ifndef WIN32\r
+ pthread_mutex_lock(&boxLock);\r
+ #else\r
+ WaitForSingleObject(boxLock, INFINITE);\r
+ #endif \r
+\r
+ if (numBoxes == 1)\r
+ {\r
+ #ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+ #else\r
+ ReleaseMutex(boxLock);\r
+ #endif\r
+ break;\r
+ } \r
+ \r
+ toDel = boxes[numBoxes - 1];\r
+\r
+ #ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+ #else\r
+ ReleaseMutex(boxLock);\r
+ #endif\r
+\r
+ toDel->preDelete();\r
+ \r
+ #ifndef WIN32\r
+ pthread_mutex_lock(&boxLock);\r
+ #else\r
+ WaitForSingleObject(boxLock, INFINITE);\r
+ #endif \r
+\r
+ // If boxes[numBoxes - 1] isn't toDel then there's a problem\r
+ if (boxes[numBoxes - 1] == toDel)\r
+ {\r
+ --numBoxes;\r
+ }\r
+ else\r
+ {\r
+ Log::getInstance()->log("BoxStack", Log::ERR, "Can this actually happen? Why?");\r
+ toDel = NULL;\r
+ }\r
+\r
+ #ifndef WIN32\r
+ pthread_mutex_unlock(&boxLock);\r
+ #else\r
+ ReleaseMutex(boxLock);\r
+ #endif\r
+\r
+ //AVO: do the delete outside the lock to allow for recursive deletes\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "going to delete boxx %p, num=%d", toDel, numBoxes);\r
+ if (toDel) delete toDel;\r
+ }\r
+}\r
+\r
+int BoxStack::handleCommand(int command)\r
+{\r
+ int retVal;\r
+ int retVal2 = 0;\r
+ int i;\r
+\r
+ if (command != Remote::NA_NONE)\r
+ {\r
+ // handle command return values\r
+ // 0 - drop through to next box\r
+ // 1 - dont drop to next box, but not handled\r
+ // 2 - handled - stop command here\r
+ // 4 - handled - delete this box\r
+\r
+ for (i=numBoxes-1; i>=0; i--)\r
+ {\r
+// Log::getInstance()->log("BoxStack", Log::DEBUG, "Giving command to i=%i", i);\r
+ retVal = boxes[i]->handleCommand(command);\r
+ if (retVal == 1)\r
+ {\r
+ // not handled but don't give to any more boxes\r
+ return 0;\r
+ }\r
+\r
+ if (retVal == 2)\r
+ {\r
+ // command handled\r
+ retVal2 = 1;\r
+ break;\r
+ }\r
+ else if (retVal == 4)\r
+ {\r
+// Log::getInstance()->log("BoxStack", Log::DEBUG, "Return 4: i=%i, boxes[i]=%p", i, boxes[i]);\r
+ remove(boxes[i]);\r
+ retVal2 = 1;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // fake the return code\r
+ retVal2 = 2;\r
+ }\r
+\r
+ return retVal2;\r
+}\r
+\r
+void BoxStack::processMessage(Message* m)\r
+{\r
+ if (m->to != this)\r
+ {\r
+ for (int i = numBoxes-1; i >= 0; i--)\r
+ {\r
+ if (boxes[i] == m->to)\r
+ {\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "sending message from box %p to box %p %lu", m->from, m->to, m->message);\r
+ boxes[i]->processMessage(m);\r
+ return;\r
+ }\r
+ }\r
+ return;\r
+ }\r
+\r
+ /* Handle mouse events*/\r
+ // They come in with m->to = NULL? and just need to be delivered to top box?\r
+ if ((numBoxes > 1) && ((m->message == Message::MOUSE_MOVE) || (m->message == Message::MOUSE_LBDOWN)\r
+ || (m->message == Message::MOUSE_ANDROID_SCROLL)))\r
+ {\r
+ boxes[numBoxes-1]->processMessage(m);\r
+ return;\r
+ }\r
+\r
+ Log::getInstance()->log("BoxStack", Log::DEBUG, "it's for meeee!");\r
+\r
+ switch(m->message)\r
+ {\r
+ case Message::CLOSE_ME:\r
+ {\r
+ remove((Boxx*)m->from);\r
+ break;\r
+ }\r
+ case Message::ADD_VIEW: // currently not used by anything but it might come in useful again\r
+ {\r
+ Boxx* toAdd = (Boxx*)m->parameter;\r
+ add(toAdd);\r
+ toAdd->draw();\r
+ update(toAdd);\r
+ break;\r
+ }\r
+ }\r
+}\r
-/*
- Copyright 2007 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "boxx.h"
-#include "bitmap.h"
-#include "log.h"
-#include <stdlib.h>
-
-char Boxx::numBoxxes = 0;
-
-Boxx::Boxx()
-{
- // I want a parent box or a surface.
- parent = NULL;
- surface = NULL;
-
- area.x = 0;
- area.y = 0;
- area.w = 0;
- area.h = 0;
-
- paraVSpace = 6; // default gap for drawPara
-
- backgroundColourSet = false;
- visible = true;
-
- numBoxxes++;
- Log::getInstance()->log("Boxx", Log::DEBUG, "Construct, now %u", numBoxxes);
-}
-
-Boxx::~Boxx()
-{
- if (surface) delete surface;
- numBoxxes--;
- Log::getInstance()->log("Boxx", Log::DEBUG, "Destruct, now %u", numBoxxes);
-}
-
-void Boxx::draw()
-{
- //Log::getInstance()->log("Boxx", Log::DEBUG, "Draw this %p surface %p", this, surface);
- if (backgroundColourSet) fillColour(backgroundColour);
-
- Boxx* currentBoxx;
- vector<Boxx*>::iterator j;
- for (j = children.begin(); j != children.end(); j++)
- {
- currentBoxx = *j;
- if (currentBoxx->getVisible()) currentBoxx->draw();
- }
-}
-
-void Boxx::setSize(UINT w, UINT h)
-{
- area.w = w;
- area.h = h;
-}
-
-void Boxx::setPosition(UINT x, UINT y)
-{
- area.x = x;
- area.y = y;
-}
-
-void Boxx::createBuffer()
-{
- surface = new Surface_TYPE();
- surface->create(area.w, area.h);
-}
-
-void Boxx::add(Boxx* newChild)
-{
- newChild->setParent(this);
- children.push_back(newChild);
-}
-
-void Boxx::remove(Boxx* oldChild)
-{
- for(vector<Boxx*>::iterator i = children.begin(); i != children.end(); i++)
- {
- if (*i == oldChild)
- {
- children.erase(i);
- return;
- }
- }
- Log::getInstance()->log("Boxx", Log::ERR, "Remove child box called, child %p not found", oldChild);
-}
-
-void Boxx::setParent(Boxx* newParent)
-{
- parent = newParent;
-}
-
-void Boxx::setBackgroundColour(const Colour& Tcolour)
-{
- backgroundColour = Tcolour;
- backgroundColourSet = true;
-}
-
-void Boxx::setVisible(bool isVisible)
-{
- visible = isVisible;
-}
-
-bool Boxx::getVisible()
-{
- return visible;
-}
-
-void Boxx::setGap(UINT gap)
-{
- paraVSpace = gap;
-}
-
-void Boxx::blt(Region& r)
-{
- /* surface update to screen needs:
- source x distance into this surface
- source y distance into this surface
- width of update
- height of update
- destination x on screen
- destination y on screen
- */
-
- if (parent) abort(); // if (parent) then this is a child boxx. It can not blt.
-
- // this shouldn't be here
- r.x -= area.x;
- r.y -= area.y;
-
- surface->updateToScreen(r.x, r.y, r.w, r.h, area.x + r.x, area.y + r.y);
-
-}
-
-int Boxx::getScreenX()
-{
- if (parent) return area.x + parent->getScreenX();
- return area.x;
-}
-
-int Boxx::getScreenY()
-{
- if (parent) return area.y + parent->getScreenY();
- return area.y;
-}
-
-int Boxx::getRootBoxOffsetX() // convert this to be getX and silently do the parent/not thing? same for Y below?
-{
- if (parent) return area.x + parent->getRootBoxOffsetX();
- return 0;
-}
-
-int Boxx::getRootBoxOffsetY()
-{
- if (parent) return area.y + parent->getRootBoxOffsetY();
- return 0;
-}
-
-int Boxx::getX()
-{
- return area.x;
-}
-
-int Boxx::getY()
-{
- return area.y;
-}
-
-int Boxx::getX2()
-{
- return area.x + area.w;
-}
-
-int Boxx::getY2()
-{
- return area.y + area.h;
-}
-
-UINT Boxx::getWidth()
-{
- return area.w;
-}
-
-UINT Boxx::getHeight()
-{
- return area.h;
-}
-
-// FIXME Clean up the code to use just one of the following
-
-Region* Boxx::getRegion()
-{
- return &area;
-}
-
-Region Boxx::getRegionR()
-{
- return area;
-}
-
-void Boxx::getRootBoxRegion(Region* r)
-{
- // Returns a region that describes the position of this box on the box with the surface
- // To be used for boxstack->update calls
-
- r->x = getRootBoxOffsetX();
- r->y = getRootBoxOffsetY();
- r->w = area.w;
- r->h = area.h;
-}
-
-// Level 1 drawing functions
-
-void Boxx::fillColour(const Colour& colour)
-{
- rectangle(0, 0, area.w, area.h, colour);
-}
-
-void Boxx::drawPara(const char* text, int x, int y, const Colour& colour)
-{
- char line[256];
- int lineHeight = surface->getFontHeight() + paraVSpace;
-
- int lineWidth;
- int thisCharWidth;
- int textPos;
- int linePos;
- int ypos;
- int printLine;
-
- textPos = 0;
- ypos = y;
-
- while(1)
- {
- linePos = 0;
- lineWidth = 0;
- while(1)
- {
- printLine = 0;
-
- if (text[textPos] == '\0') break;
-
- if (text[textPos] == '\n')
- {
- textPos++; // ignore the \n
- printLine = 1;
- break;
- }
-
- thisCharWidth = surface->getCharWidth(text[textPos]);
- if ((lineWidth + thisCharWidth) > (int)(area.w - (2 * paraMargin)))
- {
- // this character would break the right margin
- if (text[textPos] == ' ')
- {
- // this char is a space, ignore and break
- textPos++;
- break;
- }
- else
- {
- // Need to go back to the last space in the line
- while ((text[textPos] != ' ') && (linePos >= 0))
- {
- textPos--;
- linePos--;
- }
- // Now take the space we just found
- textPos++;
- break;
- }
- }
- line[linePos++] = text[textPos];
- lineWidth += thisCharWidth;
- textPos++;
- }
-
-// line[linePos++] = '\0';
- if (linePos>=0) line[linePos++] = '\0'; //Here is the change
-
- if (printLine || (linePos > 1)) // if some text was put in line
- {
- drawText(line, x, ypos, colour);
- ypos += lineHeight;
- if (ypos > (int)(area.h - lineHeight)) break;
- }
- else
- {
- break;
- }
- }
-}
-
-void Boxx::rectangle(Region& region, const Colour& colour)
-{
- rectangle(region.x, region.y, region.w, region.h, colour);
-}
-
-// Level 0 drawing functions
-
-void Boxx::rectangle(UINT x, UINT y, UINT w, UINT h, const Colour& colour)
-{
- if (parent) parent->rectangle(area.x + x, area.y + y, w, h, colour);
- else surface->fillblt(x, y, w, h, colour.rgba());
-}
-
-void Boxx::drawText(const char* text, int x, int y, const Colour& colour)
-{
- if (parent) parent->drawText(text, area.x + x, area.y + y, colour);
- else surface->drawText(text, x, y, colour.rgba());
-}
-
-void Boxx::drawText(const char* text, int x, int y, int width, const Colour& colour)
-{
- if (parent) parent->drawText(text, area.x + x, area.y + y, width, colour);
- else surface->drawText(text, x, y, width, colour.rgba());
-}
-
-void Boxx::drawTextRJ(const char* text, int x, int y, const Colour& colour)
-{
- if (parent) parent->drawTextRJ(text, area.x + x, area.y + y, colour);
- else surface->drawTextRJ(text, x, y, colour.rgba());
-}
-
-void Boxx::drawTextCentre(const char* text, int x, int y, const Colour& colour)
-{
- if (parent) parent->drawTextCentre(text, area.x + x, area.y + y, colour);
- else surface->drawTextCentre(text, x, y, colour.rgba());
-}
-
-void Boxx::drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw)
-{
- if (parent) parent->drawPixelAlpha(area.x + x, area.y + y, colour,fastdraw);
- else
- {
- int c = ( (colour.alpha << 24 )
- | (colour.red << 16)
- | (colour.green << 8)
- | (colour.blue ) );
-
- surface->drawPixel(x, y, c,fastdraw);
- }
-}
-
-void Boxx::drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw)
-{
- if (parent) parent->drawPixel(area.x + x, area.y + y, colour,fastdraw);
- else
- {
- int c = ( (0xFF000000 )
- | (colour.red << 16)
- | (colour.green << 8)
- | (colour.blue ) );
-
- surface->drawPixel(x, y, c,fastdraw);
- }
-}
-void Boxx::drawBitmap(UINT x, UINT y, const Bitmap& bm)
-{
- if (parent) parent->drawBitmap(area.x + x, area.y + y, bm);
- else surface->drawBitmap(x, y, bm);
-}
-
-void Boxx::startFastDraw()
-{
- if (parent) parent->startFastDraw();
- else
- {
- surface->startFastDraw();
- }
-}
-
-void Boxx::endFastDraw()
-{
- if (parent) parent->endFastDraw();
- else
- {
- surface->endFastDraw();
- }
-}
-
-
-int Boxx::charWidth(char c)
-{
- if (parent) return parent->charWidth(c);
- else return surface->getCharWidth(c);
-}
-
-Surface * Boxx::getSurface() {
- if (parent) return parent->getSurface();
- return surface;
-}
-
+/*\r
+ Copyright 2007 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "boxx.h"\r
+#include "bitmap.h"\r
+#include "log.h"\r
+#include "osd.h"\r
+#include <stdlib.h>\r
+\r
+char Boxx::numBoxxes = 0;\r
+\r
+Boxx::Boxx()\r
+{\r
+ // I want a parent box or a surface.\r
+ parent = NULL;\r
+ surface = NULL;\r
+\r
+ area.x = 0;\r
+ area.y = 0;\r
+ area.w = 0;\r
+ area.h = 0;\r
+\r
+ paraVSpace = 6; // default gap for drawPara\r
+\r
+ backgroundColourSet = false;\r
+ visible = true;\r
+\r
+ numBoxxes++;\r
+ Log::getInstance()->log("Boxx", Log::DEBUG, "Construct, now %u", numBoxxes);\r
+}\r
+\r
+Boxx::~Boxx()\r
+{\r
+ if (surface) delete surface;\r
+ numBoxxes--;\r
+ Log::getInstance()->log("Boxx", Log::DEBUG, "Destruct, now %u", numBoxxes);\r
+}\r
+\r
+void Boxx::draw()\r
+{\r
+ //Log::getInstance()->log("Boxx", Log::DEBUG, "Draw this %p surface %p", this, surface);\r
+ if (backgroundColourSet) fillColour(backgroundColour);\r
+\r
+ Boxx* currentBoxx;\r
+ vector<Boxx*>::iterator j;\r
+ //int count=0;\r
+ for (j = children.begin(); j != children.end(); j++)\r
+ {\r
+ currentBoxx = *j;\r
+ // Log::getInstance()->log("Boxx", Log::DEBUG, "Draw child %d %d", count,currentBoxx);\r
+ if (currentBoxx->getVisible()) currentBoxx->draw();\r
+ // count++;\r
+ } \r
+ // Log::getInstance()->log("Boxx", Log::DEBUG, "Draw this %p surface %p End", this, surface);\r
+}\r
+\r
+void Boxx::setSize(UINT w, UINT h)\r
+{\r
+ area.w = w;\r
+ area.h = h;\r
+}\r
+\r
+void Boxx::setPosition(UINT x, UINT y)\r
+{\r
+ area.x = x;\r
+ area.y = y;\r
+}\r
+\r
+void Boxx::createBuffer()\r
+{\r
+ surface = Osd::getInstance()->createNewSurface();\r
+ surface->create(area.w, area.h);\r
+}\r
+\r
+void Boxx::add(Boxx* newChild)\r
+{\r
+ newChild->setParent(this);\r
+ children.push_back(newChild);\r
+}\r
+\r
+void Boxx::remove(Boxx* oldChild)\r
+{\r
+ for(vector<Boxx*>::iterator i = children.begin(); i != children.end(); i++)\r
+ {\r
+ if (*i == oldChild)\r
+ {\r
+ children.erase(i);\r
+ return;\r
+ }\r
+ }\r
+ Log::getInstance()->log("Boxx", Log::ERR, "Remove child box called, child %p not found", oldChild);\r
+}\r
+\r
+void Boxx::setParent(Boxx* newParent)\r
+{\r
+ parent = newParent;\r
+}\r
+\r
+void Boxx::setBackgroundColour(const Colour& Tcolour)\r
+{\r
+ backgroundColour = Tcolour;\r
+ backgroundColourSet = true;\r
+}\r
+\r
+void Boxx::setVisible(bool isVisible)\r
+{\r
+ visible = isVisible;\r
+}\r
+\r
+bool Boxx::getVisible()\r
+{\r
+ return visible;\r
+}\r
+\r
+void Boxx::setGap(UINT gap)\r
+{\r
+ paraVSpace = gap;\r
+}\r
+\r
+void Boxx::blt(Region& r)\r
+{\r
+ /* surface update to screen needs:\r
+ source x distance into this surface\r
+ source y distance into this surface\r
+ width of update\r
+ height of update\r
+ destination x on screen\r
+ destination y on screen\r
+ */\r
+\r
+ if (parent) abort(); // if (parent) then this is a child boxx. It can not blt.\r
+\r
+ // this shouldn't be here\r
+ r.x -= area.x;\r
+ r.y -= area.y;\r
+\r
+ surface->updateToScreen(r.x, r.y, r.w, r.h, area.x + r.x, area.y + r.y);\r
+ \r
+}\r
+\r
+int Boxx::getScreenX()\r
+{\r
+ if (parent) return area.x + parent->getScreenX();\r
+ return area.x;\r
+}\r
+\r
+int Boxx::getScreenY()\r
+{\r
+ if (parent) return area.y + parent->getScreenY();\r
+ return area.y;\r
+}\r
+\r
+int Boxx::getRootBoxOffsetX() // convert this to be getX and silently do the parent/not thing? same for Y below?\r
+{\r
+ if (parent) return area.x + parent->getRootBoxOffsetX();\r
+ return 0;\r
+}\r
+\r
+int Boxx::getRootBoxOffsetY()\r
+{\r
+ if (parent) return area.y + parent->getRootBoxOffsetY();\r
+ return 0;\r
+}\r
+\r
+int Boxx::getX()\r
+{\r
+ return area.x;\r
+}\r
+\r
+int Boxx::getY()\r
+{\r
+ return area.y;\r
+}\r
+\r
+int Boxx::getX2()\r
+{\r
+ return area.x + area.w;\r
+}\r
+\r
+int Boxx::getY2()\r
+{\r
+ return area.y + area.h;\r
+}\r
+\r
+UINT Boxx::getWidth()\r
+{\r
+ return area.w;\r
+}\r
+\r
+UINT Boxx::getHeight()\r
+{\r
+ return area.h;\r
+}\r
+\r
+// FIXME Clean up the code to use just one of the following\r
+\r
+Region* Boxx::getRegion()\r
+{\r
+ return &area;\r
+}\r
+\r
+Region Boxx::getRegionR()\r
+{\r
+ return area;\r
+}\r
+\r
+void Boxx::getRootBoxRegion(Region* r)\r
+{\r
+ // Returns a region that describes the position of this box on the box with the surface\r
+ // To be used for boxstack->update calls\r
+\r
+ r->x = getRootBoxOffsetX();\r
+ r->y = getRootBoxOffsetY();\r
+ r->w = area.w;\r
+ r->h = area.h; \r
+}\r
+\r
+// Level 1 drawing functions\r
+\r
+void Boxx::fillColour(const Colour& colour)\r
+{\r
+ rectangle(0, 0, area.w, area.h, colour);\r
+}\r
+\r
+void Boxx::drawPara(const char* text, int x, int y, const Colour& colour)\r
+{\r
+ char line[256];\r
+ int lineHeight = getFontHeight() + paraVSpace;\r
+\r
+ int lineWidth;\r
+ int thisCharWidth;\r
+ int textPos;\r
+ int linePos;\r
+ int ypos;\r
+ int printLine;\r
+\r
+ textPos = 0;\r
+ ypos = y;\r
+\r
+ while(1)\r
+ {\r
+ linePos = 0;\r
+ lineWidth = 0;\r
+ while(1)\r
+ {\r
+ printLine = 0;\r
+\r
+ if (text[textPos] == '\0') break;\r
+\r
+ if (text[textPos] == '\n')\r
+ {\r
+ textPos++; // ignore the \n\r
+ printLine = 1;\r
+ break;\r
+ }\r
+\r
+ thisCharWidth = charWidth(text[textPos]);\r
+ if ((lineWidth + thisCharWidth) > (int)(area.w - (2 * paraMargin)))\r
+ {\r
+ // this character would break the right margin\r
+ if (text[textPos] == ' ')\r
+ {\r
+ // this char is a space, ignore and break\r
+ textPos++;\r
+ break;\r
+ }\r
+ else\r
+ {\r
+ // Need to go back to the last space in the line\r
+ while ((text[textPos] != ' ') && (linePos >= 0))\r
+ {\r
+ textPos--;\r
+ linePos--;\r
+ }\r
+ // Now take the space we just found\r
+ textPos++;\r
+ break;\r
+ }\r
+ }\r
+ line[linePos++] = text[textPos];\r
+ lineWidth += thisCharWidth;\r
+ textPos++;\r
+ }\r
+\r
+// line[linePos++] = '\0';\r
+ if (linePos>=0) line[linePos++] = '\0'; //Here is the change\r
+\r
+ if (printLine || (linePos > 1)) // if some text was put in line\r
+ {\r
+ drawText(line, x, ypos, colour);\r
+ ypos += lineHeight;\r
+ if (ypos > (int)(area.h - lineHeight)) break;\r
+ }\r
+ else\r
+ {\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+void Boxx::rectangle(Region& region, const Colour& colour)\r
+{\r
+ rectangle(region.x, region.y, region.w, region.h, colour);\r
+}\r
+\r
+// Level 0 drawing functions\r
+\r
+void Boxx::rectangle(UINT x, UINT y, UINT w, UINT h, const Colour& colour)\r
+{\r
+ if (parent) parent->rectangle(area.x + x, area.y + y, w, h, colour);\r
+ else surface->fillblt(x, y, w, h, colour.rgba());\r
+}\r
+\r
+void Boxx::drawText(const char* text, int x, int y, const Colour& colour)\r
+{\r
+ if (parent) parent->drawText(text, area.x + x, area.y + y, colour);\r
+ else surface->drawText(text, x, y, colour.rgba());\r
+}\r
+\r
+void Boxx::drawText(const char* text, int x, int y, int width, const Colour& colour)\r
+{\r
+ if (parent) parent->drawText(text, area.x + x, area.y + y, width, colour);\r
+ else surface->drawText(text, x, y, width, colour.rgba());\r
+}\r
+\r
+void Boxx::drawTextRJ(const char* text, int x, int y, const Colour& colour)\r
+{\r
+ if (parent) parent->drawTextRJ(text, area.x + x, area.y + y, colour);\r
+ else surface->drawTextRJ(text, x, y, colour.rgba());\r
+}\r
+\r
+void Boxx::drawTextCentre(const char* text, int x, int y, const Colour& colour)\r
+{\r
+ if (parent) parent->drawTextCentre(text, area.x + x, area.y + y, colour);\r
+ else surface->drawTextCentre(text, x, y, colour.rgba());\r
+}\r
+\r
+void Boxx::drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw)\r
+{\r
+ if (parent) parent->drawPixelAlpha(area.x + x, area.y + y, colour,fastdraw);\r
+ else\r
+ {\r
+ int c = ( (colour.alpha << 24 )\r
+ | (colour.red << 16)\r
+ | (colour.green << 8)\r
+ | (colour.blue ) );\r
+\r
+ surface->drawPixel(x, y, c,fastdraw);\r
+ }\r
+}\r
+\r
+void Boxx::drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw)\r
+{\r
+ if (parent) parent->drawPixel(area.x + x, area.y + y, colour,fastdraw);\r
+ else\r
+ {\r
+ int c = ( (0xFF000000 )\r
+ | (colour.red << 16)\r
+ | (colour.green << 8)\r
+ | (colour.blue ) );\r
+\r
+ surface->drawPixel(x, y, c,fastdraw);\r
+ }\r
+}\r
+\r
+void Boxx::drawTTChar(int ox, int oy,int x, int y, cTeletextChar c)\r
+{\r
+ if (parent) parent->drawTTChar(area.x + ox, area.y + oy, x,y,c);\r
+ else if (surface) surface->drawTTChar(ox, oy,x,y,c);\r
+\r
+}\r
+\r
+void Boxx::drawBitmap(UINT x, UINT y, const Bitmap& bm)\r
+{\r
+ if (parent) parent->drawBitmap(area.x + x, area.y + y, bm);\r
+ else if (surface) surface->drawBitmap(x, y, bm);\r
+}\r
+\r
+void Boxx::drawJpeg(const char *fileName,int x, int y,int *width, int *height)\r
+{\r
+ if (parent) parent->drawJpeg(fileName,area.x +x,area.y +y,width,height);\r
+ else if (surface) surface->drawJpeg(fileName,x,y,width,height);\r
+}\r
+\r
+int Boxx::getFontHeight()\r
+{\r
+ if (parent) return parent->getFontHeight();\r
+ else if (surface) return surface->getFontHeight();\r
+ else return 18;\r
+}\r
+\r
+void Boxx::startFastDraw()\r
+{\r
+ if (parent) parent->startFastDraw();\r
+ else\r
+ {\r
+ if (surface) surface->startFastDraw();\r
+ }\r
+}\r
+\r
+void Boxx::endFastDraw()\r
+{\r
+ if (parent) parent->endFastDraw();\r
+ else\r
+ {\r
+ if (surface) surface->endFastDraw();\r
+ }\r
+}\r
+ \r
+\r
+int Boxx::charWidth(char c)\r
+{\r
+ if (parent) return parent->charWidth(c);\r
+ else if (surface) return surface->getCharWidth(c);\r
+ else return 10; //?\r
+}\r
+\r
+Surface * Boxx::getSurface() {\r
+ if (parent) return parent->getSurface();\r
+ return surface;\r
+}\r
+\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef BOXX_H
-#define BOXX_H
-
-#include <stdio.h>
-#include <vector>
-
-using namespace std;
-
-#include "colour.h"
-#include "region.h"
-#include "message.h"
-
-#ifdef WIN32
-#include "surfacewin.h"
-#else
-
-#ifdef _MIPS_ARCH
-#include "surfacedirectfb.h"
-#else
-#include "surfacemvp.h"
-#endif
-
-#endif
-
-class Bitmap;
-
-class Boxx
-{
- public:
- Boxx();
- virtual ~Boxx();
-
- virtual void setSize(UINT w, UINT h); // virtual? really?
- void setPosition(UINT x, UINT y); // Set position on parent. Even numbers only!!!
- void createBuffer(); // Make this a root view that goes in the BoxStack
- virtual void draw();
-
-
- void setGap(UINT gap);
- void setBackgroundColour(const Colour& colour);
- void setVisible(bool isVisible);
-
-
- // The following are supposed to be abstract functions
- // However, it is useful to be able to make instances of Boxx
- // Therefore the following stubs are provided.
- virtual void preDelete() {}
- virtual int handleCommand(int x) { return 0; }
- virtual void processMessage(Message* m) {}
- virtual bool mouseMove(int x, int y) { return false; }
- virtual bool mouseLBDOWN(int x, int y) { return false; }
- virtual void deactivateAllControls() {}
-
- /* preDelete
-
- I think it's functionally equivalent to e.g. delete timers in Boxx::preDelete
- because the only place where a Boxx is deleted is in
- BoxStack::remove. There is now a call in BoxStack::remove to Boxx::preDelete
- The reason for this is to stop timercalls calling BoxStack::update at the
- same time BoxStack::remove is locked trying to delete the Boxx
- */
-
- // Get functions
- int getScreenX(); // where is it on screen
- int getScreenY();
- int getRootBoxOffsetX(); // where is it relative to the top-parent in the boxstack
- int getRootBoxOffsetY();
- int getX(); // where is it relative to its parent
- int getX2(); // .. and the right edge
- int getY();
- int getY2();
- UINT getWidth();
- UINT getHeight();
- bool getVisible();
- Region* getRegion(); // Not to be used for changing the region
- Region getRegionR(); // Same but as an object
- void getRootBoxRegion(Region*);
-
- // Drawing functions level 1
- void fillColour(const Colour& colour);
- void drawPara(const char* text, int x, int y, const Colour& colour);
-
- // Drawing functions level 0
- void rectangle(UINT x, UINT y, UINT w, UINT h, const Colour& colour);
- void rectangle(Region& region, const Colour& colour);
-
- void drawText(const char* text, int x, int y, const Colour& colour);
- void drawText(const char* text, int x, int y, int width, const Colour& colour);
- void drawTextRJ(const char* text, int x, int y, const Colour& colour);
- void drawTextCentre(const char* text, int x, int y, const Colour& colour);
- void drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw=false);
- void drawBitmap(UINT x, UINT y, const Bitmap& bm);
- void drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw=false);
-
- /* This is for system which need a locking of the drawing surface to speed up drawing */
- void startFastDraw();
- void endFastDraw();
-
- int charWidth(char c);
-
- void add(Boxx*); // a boxx has a set of child boxxs
- void remove(Boxx*);
-
- /*
- The following function sets the child's parent pointer without adding the child to the children vector.
- It's a hack (that should be deprecated?) to allow things like WSymbol to be created, do some drawing on
- the surface and then be deleted again, leaving the drawing present.
- A better design would be to create many WSymbols - one per symbol and leave them created - then the
- automatic draw code will be able to redraw the symbols without all that code needing
- to be in the derived boxx's draw method.
- */
- void TEMPADD(Boxx* child) { child->setParent(this); }
-
- friend class BoxStack;
- protected:
- //get the surface this box is drawing to
- Surface *getSurface();
- Boxx* parent;
- Region area;
- vector<Boxx*> children;
-
- void setParent(Boxx*);
- void blt(Region& r);
-
- static const int paraMargin = 10;
- UINT paraVSpace;
-
- Colour backgroundColour;
- bool backgroundColourSet;
- bool visible;
-
- static char numBoxxes;
- Surface* surface;
-};
-
-#endif
-
-
-/*
-
-New Boxx design
-
-It's "Boxx" because "Box" was already taken.
-
-BoxStack replaces Viewman and handles displaying a stack of root boxxs (boxxs with surfaces) on the screen.
-
-Boxx relaces Box, Widget and parts of View and represents a box with or without a surface.
-Let's call a Boxx with a surface a root box, and a boxx without a surface a child box.
-
-A boxx with a surface (root) is like an old View and is handled by BoxStack.
-A boxx without a surface (child) is like and old Widget and needs to be a child box of another boxx (root or not).
-
-Don't add a boxx with a surface to another boxx. That isn't the design.
-
-So, when you create a boxx, either that boxx calls createBuffer() on itself,
-or some other box add()s the new box to itself.
-
-Root boxxs can overlap each other - this is managed by boxstack.
-Child boxxs within a parent boxx do not overlap each other.
-However, a grandchild box can overlap a child box (but must be entirely contained within the child box).
-
-TBBoxx replaces View but is now only a convenience class for the window dressing stuff. It isn't required anymore since
-all the real work that view used to do is done in Boxx now.
-
-Obseleted classes: Box, View, Viewman, Widget, others?
-No code outside boxx should talk about surfaces anymore. Hopefully.
-
-*/
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef BOXX_H\r
+#define BOXX_H\r
+\r
+#include <stdio.h>\r
+#include <vector>\r
+\r
+using namespace std;\r
+\r
+#include "colour.h"\r
+#include "region.h"\r
+#include "message.h"\r
+\r
+\r
+#include "surface.h"\r
+\r
+class Bitmap;\r
+\r
+class Boxx\r
+{\r
+ public:\r
+ Boxx();\r
+ virtual ~Boxx();\r
+\r
+ virtual void setSize(UINT w, UINT h); // virtual? really?\r
+ void setPosition(UINT x, UINT y); // Set position on parent. Even numbers only!!!\r
+ void createBuffer(); // Make this a root view that goes in the BoxStack\r
+ virtual void draw();\r
+ \r
+ \r
+ void setGap(UINT gap);\r
+ void setBackgroundColour(const Colour& colour);\r
+ void setVisible(bool isVisible);\r
+\r
+\r
+ // The following are supposed to be abstract functions\r
+ // However, it is useful to be able to make instances of Boxx\r
+ // Therefore the following stubs are provided.\r
+ virtual void preDelete() {}\r
+ virtual int handleCommand(int x) { return 0; }\r
+ virtual void processMessage(Message* m) {}\r
+ virtual bool mouseMove(int x, int y) { return false; }\r
+ virtual bool mouseLBDOWN(int x, int y) { return false; }\r
+ virtual bool mouseAndroidScroll(int x, int y,int sx, int sy) { return false; }\r
+ virtual void deactivateAllControls() {}\r
+\r
+ /* preDelete \r
+ \r
+ I think it's functionally equivalent to e.g. delete timers in Boxx::preDelete\r
+ because the only place where a Boxx is deleted is in \r
+ BoxStack::remove. There is now a call in BoxStack::remove to Boxx::preDelete\r
+ The reason for this is to stop timercalls calling BoxStack::update at the\r
+ same time BoxStack::remove is locked trying to delete the Boxx\r
+ */\r
+\r
+ // Get functions\r
+ int getScreenX(); // where is it on screen\r
+ int getScreenY();\r
+ int getRootBoxOffsetX(); // where is it relative to the top-parent in the boxstack\r
+ int getRootBoxOffsetY();\r
+ int getX(); // where is it relative to its parent\r
+ int getX2(); // .. and the right edge\r
+ int getY();\r
+ int getY2();\r
+ UINT getWidth();\r
+ UINT getHeight();\r
+ bool getVisible();\r
+ Region* getRegion(); // Not to be used for changing the region\r
+ Region getRegionR(); // Same but as an object\r
+ void getRootBoxRegion(Region*);\r
+ \r
+ // Drawing functions level 1\r
+ void fillColour(const Colour& colour);\r
+ void drawPara(const char* text, int x, int y, const Colour& colour);\r
+\r
+ // Drawing functions level 0\r
+ void rectangle(UINT x, UINT y, UINT w, UINT h, const Colour& colour);\r
+ void rectangle(Region& region, const Colour& colour);\r
+\r
+ void drawText(const char* text, int x, int y, const Colour& colour);\r
+ void drawText(const char* text, int x, int y, int width, const Colour& colour);\r
+ void drawTextRJ(const char* text, int x, int y, const Colour& colour);\r
+ void drawTextCentre(const char* text, int x, int y, const Colour& colour);\r
+ void drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw=false);\r
+ void drawBitmap(UINT x, UINT y, const Bitmap& bm);\r
+ void drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw=false);\r
+ int getFontHeight();\r
+\r
+ void drawJpeg(const char *fileName,int x, int y,int *width, int *height);\r
+\r
+ void drawTTChar(int ox, int oy,int x, int y, cTeletextChar c);\r
+\r
+ /* This is for system which need a locking of the drawing surface to speed up drawing */\r
+ void startFastDraw();\r
+ void endFastDraw();\r
+\r
+ int charWidth(char c);\r
+\r
+ void add(Boxx*); // a boxx has a set of child boxxs\r
+ void remove(Boxx*);\r
+\r
+ /*\r
+ The following function sets the child's parent pointer without adding the child to the children vector.\r
+ It's a hack (that should be deprecated?) to allow things like WSymbol to be created, do some drawing on\r
+ the surface and then be deleted again, leaving the drawing present.\r
+ A better design would be to create many WSymbols - one per symbol and leave them created - then the\r
+ automatic draw code will be able to redraw the symbols without all that code needing\r
+ to be in the derived boxx's draw method.\r
+ */ \r
+ void TEMPADD(Boxx* child) { child->setParent(this); }\r
+\r
+ friend class BoxStack;\r
+ protected:\r
+ //get the surface this box is drawing to\r
+ Surface *getSurface();\r
+ Boxx* parent;\r
+ Region area;\r
+ vector<Boxx*> children;\r
+\r
+ void setParent(Boxx*); \r
+ void blt(Region& r);\r
+\r
+ static const int paraMargin = 10;\r
+ UINT paraVSpace;\r
+\r
+ Colour backgroundColour;\r
+ bool backgroundColourSet;\r
+ bool visible;\r
+\r
+ static char numBoxxes;\r
+ Surface* surface;\r
+};\r
+\r
+#endif\r
+\r
+\r
+/*\r
+\r
+New Boxx design\r
+\r
+It's "Boxx" because "Box" was already taken.\r
+\r
+BoxStack replaces Viewman and handles displaying a stack of root boxxs (boxxs with surfaces) on the screen.\r
+\r
+Boxx relaces Box, Widget and parts of View and represents a box with or without a surface.\r
+Let's call a Boxx with a surface a root box, and a boxx without a surface a child box.\r
+\r
+A boxx with a surface (root) is like an old View and is handled by BoxStack.\r
+A boxx without a surface (child) is like and old Widget and needs to be a child box of another boxx (root or not).\r
+\r
+Don't add a boxx with a surface to another boxx. That isn't the design.\r
+\r
+So, when you create a boxx, either that boxx calls createBuffer() on itself,\r
+or some other box add()s the new box to itself.\r
+\r
+Root boxxs can overlap each other - this is managed by boxstack.\r
+Child boxxs within a parent boxx do not overlap each other.\r
+However, a grandchild box can overlap a child box (but must be entirely contained within the child box).\r
+\r
+TBBoxx replaces View but is now only a convenience class for the window dressing stuff. It isn't required anymore since\r
+all the real work that view used to do is done in Boxx now.\r
+\r
+Obseleted classes: Box, View, Viewman, Widget, others?\r
+No code outside boxx should talk about surfaces anymore. Hopefully.\r
+\r
+*/\r
+\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef WIN32
-#include <linux/errno.h>
-#endif
-
-#include "command.h"
-
-#ifdef WIN32
-#include "remotewin.h"
-#endif
-
-#include "led.h"
-#include "video.h"
-#include "audio.h"
-#include "vdr.h"
-#include "vvolume.h"
-#include "vserverselect.h"
-#include "vwelcome.h"
-#include "vmute.h"
-#include "colour.h"
-#include "osd.h"
-#include "i18n.h"
-#include "timerreceiver.h"
-#include "timers.h"
-#include "wol.h"
-#include "vconnect.h"
-#include "message.h"
-#include "remote.h"
-#include "vinfo.h"
-#include "boxx.h"
-#include "boxstack.h"
-#include "log.h"
-#include "vsleeptimer.h"
-
-
-Command* Command::instance = NULL;
-
-Command::Command()
-{
- if (instance) return;
- instance = this;
- initted = 0;
- isStandby = 0;
- firstBoot = 1;
- connLost = NULL;
- crashed = false;
- server = NULL;
-}
-
-Command::~Command()
-{
- instance = NULL;
-}
-
-Command* Command::getInstance()
-{
- return instance;
-}
-
-int Command::init(bool tcrashed, char* tServer)
-{
- if (initted) return 0;
- initted = 1;
- crashed = tcrashed;
- server = tServer;
-
- logger = Log::getInstance();
- boxstack = BoxStack::getInstance();
- remote = Remote::getInstance();
-
- remote->InitHWCListwithDefaults();
-
- if (!logger || !boxstack || !remote)
- {
- initted = 0;
- return 0;
- }
-#ifndef WIN32
- pthread_mutex_init(&masterLock, NULL);
-#else
- masterLock=CreateMutex(NULL,FALSE,NULL);
-#endif
-
- return 1;
-}
-
-int Command::shutdown()
-{
- if (!initted) return 0;
- initted = 0;
- return 1;
-}
-
-void Command::stop()
-{
-// VDR::getInstance()->cancelFindingServer();
- logger->log("Command", Log::NOTICE, "Command stop1...");
-
- udp.shutdown();
- logger->log("Command", Log::NOTICE, "Command stop2...");
- irun = 0;
-}
-
-void Command::doWallpaper()
-{
- Video* video = Video::getInstance();
-
- // Blue background
- Boxx* bbg = new Boxx();
- bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
- bbg->createBuffer();
- bbg->fillColour(Colour::VIDEOBLUE);
- boxstack->add(bbg);
- boxstack->update(bbg);
- boxstack->remove(bbg);
-
- // Wallpaper
- WJpeg* wallpaperj = new WJpeg();
- wallpaperj->setSize(video->getScreenWidth(), video->getScreenHeight());
- wallpaperj->createBuffer();
-
- if (video->getFormat() == Video::PAL)
- {
- logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
-#ifndef _MIPS_ARCH
- wallpaperj->init("/wallpaperPAL.jpg");
-#else
- wallpaperj->init("wallpaperPAL.jpg");
-#endif
- }
- else
- {
- logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
- wallpaperj->init("/wallpaperNTSC.jpg");
- }
- wallpaperj->draw();
-
- boxstack->add(wallpaperj);
- boxstack->update(wallpaperj);
-
- wallpaper = wallpaperj;
-}
-
-void Command::run()
-{
- if (!initted) return;
- irun = 1;
-#ifndef WIN32
- mainPid = getpid();
-#endif
-
- // just in case
- Video::getInstance()->signalOn();
- Led::getInstance()->on();
-
- doWallpaper();
-
- // End of startup. Lock the mutex and put the first view up
-// logger->log("Command", Log::DEBUG, "WANT LOCK");
-#ifndef WIN32
- pthread_mutex_lock(&masterLock);
-#else
- WaitForSingleObject(masterLock, INFINITE );
-#endif
- //logger->log("Command", Log::DEBUG, "LOCKED");
-
- if (crashed)
- {
- buildCrashedBox();
- }
- else
- {
- VConnect* vconnect = new VConnect(server);
- boxstack->add(vconnect);
- vconnect->run();
- }
-
- // Start method 2 of getting commands in...
- udp.run(this);
-
- UCHAR button = 0;
- while(irun)
- {
- // unlock and wait
- //logger->log("Command", Log::DEBUG, "UNLOCK");
-#ifndef WIN32
- pthread_mutex_unlock(&masterLock);
-#else
- ReleaseMutex(masterLock);
-#endif
-
- button = remote->getButtonPress(2); // FIXME why is this set to 2 and not 0? so it can quit
- // something happened, lock and process
-
- // logger->log("Command", Log::DEBUG, "WANT LOCK");
-#ifndef WIN32
- pthread_mutex_lock(&masterLock);
-#else
- WaitForSingleObject(masterLock, INFINITE );
-#endif
- // logger->log("Command", Log::DEBUG, "LOCK");
-
- if ((button == Remote::NA_NONE) /*|| (button == Remote::NA_UNKNOWN)*/) continue;
-
- if (button != Remote::NA_SIGNAL) handleCommand(button);
- processMessageQueue();
- }
-
- //logger->log("Command", Log::DEBUG, "UNLOCK");
-#ifndef WIN32
- pthread_mutex_unlock(&masterLock);
-#else
- ReleaseMutex(masterLock);
-#endif
-
-}
-
-void Command::postMessage(Message* m)
-{
- // This is locked here in case the main loop is not waiting for an event, but is processing one
- // it could be killed but then not react to it because the signal wouldn't cause
- // remote->getButtonPress to break
- // locking the mutex ensures that the master thread is waiting on getButtonPress
-
-
- //logger->log("Command", Log::DEBUG, "WANT LOCK");
-#ifndef WIN32
- pthread_mutex_lock(&masterLock);
-#else
- WaitForSingleObject(masterLock, INFINITE );
-#endif
- //logger->log("Command", Log::DEBUG, "LOCK");
- MessageQueue::postMessage(m);
-
-#ifndef WIN32
- kill(mainPid, SIGURG);
- pthread_mutex_unlock(&masterLock);
-#else
- ((RemoteWin*)Remote::getInstance())->Signal();
- ReleaseMutex(masterLock);
-#endif
- //logger->log("Command", Log::DEBUG, "UNLOCK");
-}
-
-void Command::postMessageNoLock(Message* m)
-{
- // As above but use this one if this message is being posted because of a button press
- // the mutex is already locked, locking around postMessage is not needed as the
- // queue is guaranteed to be run when the button has been processed
- MessageQueue::postMessage(m);
-}
-
-bool Command::postMessageIfNotBusy(Message* m)
-{
- // Used for Windows mouse events
-
- //logger->log("Command", Log::DEBUG, "TRY LOCK");
-#ifndef WIN32
- if (pthread_mutex_trylock(&masterLock) != EBUSY)
- {
- //logger->log("Command", Log::DEBUG, "LOCK");
- MessageQueue::postMessage(m);
- kill(mainPid, SIGURG);
- pthread_mutex_unlock(&masterLock);
- //logger->log("Command", Log::DEBUG, "UNLOCK");
- return true;
- }
- else
- {
- return false;
- }
-#else
- switch (WaitForSingleObject(masterLock, 0 ))
- { //FIXME this is not "if not busy" check
- case WAIT_OBJECT_0: //but with proper argument 0 this did not work
- // case WAIT_ABANDONED:
- MessageQueue::postMessage(m);
- ((RemoteWin*)Remote::getInstance())->Signal();
- ReleaseMutex(masterLock);
- return true;
-
- case WAIT_ABANDONED: return false;
- case WAIT_TIMEOUT: return false;
- }
- return false;
-#endif
-}
-
-void Command::postMessageFromOuterSpace(Message* m)
-{
- /*
- Yet another way of getting messages into Command. This one is for events that
- are not standard button presses (or UDP generated buttons). It is also not for
- events that are generated as a result of other events (events that can safely
- call postMessageNoLock and be guaranteed that the message will be processed
- because it is known that the queue is currently being processed).
- This is for events that come from outer space and can occur when the master
- mutex is locked or not, they need to be queued and executed but it doesn't
- matter when.
- Actually so far it is for events caused by the video stream - aspect ratio
- changes. These can occur when the master mutex is locked and so postMessage
- doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*
- locked at the time then the message could be sat around a while before
- being noticed.
- The whole message system was at first supposed to prevent the problem of
- calling a function on an object that had just been deleted, by ordering
- messages such that all calls are done before object deletion. However,
- because of the new centralised messaging system and the fact that BoxStack
- locates the destination object before calling it, the messaging system now
- allows the kind of sloppy calls it was supposed to stop. Weird huh. This
- is mentioned here because the video stream might generate an event just as
- the user hits stop. The mutex is locked, and by the time the message
- is examined the vvideorec/live has been deleted. This doesn't matter because
- boxstack will drop the message if it can't find the matching object to
- deliver it to.
- Finally, all this is fine and dandy, except that I'm not 100% sure that
- this sloppy postMessage and hope a queued signal will force it to be processed
- thingy will actually work. Hmmm.
- Lastly <g>, I will consider making the naming system a little more sane
- if this works.
- */
-
- logger->log("Command", Log::DEBUG, "PMFOS called");
- MessageQueue::postMessage(m);
-
-#ifndef WIN32
- kill(mainPid, SIGURG);
-#else
- ((RemoteWin*)Remote::getInstance())->Signal();
-#endif
-}
-
-void Command::processMessage(Message* m)
-{
- // FIXME - a slight modification - how if messagereceivers were to register
- // themselves as receivers to avoid the calling-a-deleted-object problem
- // then only deliver/register/unregister would have to be protected
-
- logger->log("Command", Log::DEBUG, "processing message %i", m->message);
-
-
- if (m->to == this)
- {
- switch(m->message)
- {
- // << FIXME OBSELETE
- case Message::STOP_PLAYBACK:
- {
- handleCommand(Remote::STOP); // an odd way of doing it, but so simple
- break;
- }
- // Also connection_lost comes from player - anywhere else?
- // FIXME OBSELETE >>
-
-
- case Message::VDR_CONNECTED:
- {
- doJustConnected((VConnect*)m->from);
- break;
- }
- case Message::SCREENSHOT:
- {
- Osd::getInstance()->screenShot("/out.jpg");
- break;
- }
- case Message::CONNECTION_LOST:
- {
- doFromTheTop(true);
- break;
- }
- case Message::UDP_BUTTON:
- {
- handleCommand(m->parameter);
- break;
- }
- case Message::CHANGE_LANGUAGE:
- {
- boxstack->removeAll();
- boxstack->update(wallpaper);
- I18n::initialize();
- if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
- VWelcome* vw = new VWelcome();
- vw->draw();
- boxstack->add(vw);
- boxstack->update(vw);
- break;
- }
- case Message::LAST_VIEW_CLOSE:
- {
- // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
- if (crashed)
- {
- crashed = false;
- doFromTheTop(false);
- }
-
-// VWelcome* vw = new VWelcome();
-// vw->draw();
-// boxstack->add(vw);
-// boxstack->update(vw);
-
- break;
- }
- }
- }
- else
- {
- /* FIXME
-
- Instead of sending through the boxstack, implement a more generic MessageReceiver interface
- and have potential receivers register with something
- When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
- This could all be done using the existing big command mutex to keep it simple
- */
-
- logger->log("Command", Log::DEBUG, "Sending message to boxstack");
- boxstack->processMessage(m);
- }
-}
-
-void Command::handleCommand(int button)
-{
- if (isStandby && (button != Remote::POWER)) return;
- if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
-
- // command was not handled
-
- switch(button)
- {
- case Remote::DF_LEFT:
- case Remote::DF_RIGHT:
- case Remote::VOLUMEUP:
- case Remote::VOLUMEDOWN:
- {
- VVolume* v = new VVolume();
- boxstack->add(v);
- v->handleCommand(button); // this will draw+show
- return;
- }
- case Remote::MUTE:
- {
- VMute* v = new VMute();
- v->draw();
- boxstack->add(v);
- boxstack->update(v);
- return;
- }
- case Remote::POWER:
- {
- doStandby();
- return;
- }
- case Remote::OK:
- {
- // FIXME
- if (!connLost) return; // if connLost, handle Remote::OK
- doFromTheTop(false);
- return;
- }
- case Remote::GO:
- {
- VSleeptimer* sleep = new VSleeptimer();
- boxstack->add(sleep);
- sleep->handleCommand(button); // this will draw+show
- return;
- }
- }
-}
-
-void Command::sig1()
-{
-#ifdef DEV
- Message* m = new Message(); // break into master mutex
- m->message = Message::SCREENSHOT;
- m->to = this;
- postMessage(m);
-#endif
-}
-
-void Command::doStandby()
-{
- if (isStandby)
- {
- Video::getInstance()->signalOn();
- Led::getInstance()->on();
- isStandby = 0;
-
-
- VConnect* vconnect = new VConnect(server);
- boxstack->add(vconnect);
- vconnect->run();
- }
- else
- {
- boxstack->removeAll();
- Video::getInstance()->signalOff();
- boxstack->update(wallpaper);
-
- VDR::getInstance()->configSave("General", "Last Power State", "Off");
- logger->netLogOff();
- VDR::getInstance()->disconnect();
- Led::getInstance()->off();
- isStandby = 1;
- Sleeptimer::getInstance()->shutdown();
-#ifdef WIN32
- stop(); //different behavoiur on windows, we exit
-#endif
- }
-}
-
-void Command::doFromTheTop(bool which)
-{
- if (which)
- {
- if (connLost)
- {
- logger->log("Command", Log::NOTICE, "Connection lost dialog already present");
- return;
- }
-
- logger->log("Command", Log::NOTICE, "Doing connection lost dialog");
- connLost = new VInfo();
- connLost->setSize(360, 200);
- connLost->createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- connLost->setPosition(190, 170);
- else
- connLost->setPosition(180, 120);
- connLost->setOneLiner(tr("Connection lost"));
- connLost->setDropThrough();
- connLost->setBorderOn(1);
- connLost->setTitleBarColour(Colour::DANGER);
- connLost->okButton();
- connLost->draw();
- boxstack->add(connLost);
- boxstack->update(connLost);
- remote->clearBuffer();
- }
- else
- {
- logger->netLogOff();
- VDR::getInstance()->disconnect();
- boxstack->removeAll();
- boxstack->update(wallpaper);
- connLost = NULL;
-
- flushMessageQueue();
- remote->clearBuffer();
-
- // at this point, everything should be reset to first-go
-
- VConnect* vconnect = new VConnect(server);
- boxstack->add(vconnect);
- vconnect->run();
- }
-}
-
-void Command::doReboot()
-{
- logger->netLogOff();
- VDR::getInstance()->disconnect();
- // just kill it...
- logger->log("Command", Log::NOTICE, "Reboot");
-#ifndef WIN32
-#ifndef _MIPS_ARCH
- reboot(LINUX_REBOOT_CMD_RESTART);
-#else
- stop();
-#endif
-#endif //Would we support this on windows?
-}
-
-void Command::connectionLost()
-{
- logger->netLogOff();
- Message* m = new Message(); // break into master mutex
- m->message = Message::CONNECTION_LOST;
- m->to = this;
- postMessageFromOuterSpace(m);
-}
-
-void Command::buildCrashedBox()
-{
- VInfo* crash = new VInfo();
- crash->setSize(360, 250);
- crash->createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- crash->setPosition(190, 146);
- else
- crash->setPosition(180, 96);
- crash->setMainText("Oops, vomp crashed.. :(\nPlease report this crash to the author, with as much detail as possible about what you were doing at the time that might have caused the crash.");
- crash->setBorderOn(1);
- crash->setTitleBarColour(Colour::DANGER);
- crash->okButton();
- crash->setExitable();
- crash->draw();
- boxstack->add(crash);
- boxstack->update(crash);
-}
-
-void Command::doJustConnected(VConnect* vconnect)
-{
- I18n::initialize();
- if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
-
- Video* video = Video::getInstance();
- Audio* audio = Audio::getInstance();
- boxstack->remove(vconnect);
-
- VInfo* vi = new VInfo();
- vi->setSize(400, 200);
- vi->createBuffer();
- if (video->getFormat() == Video::PAL)
- vi->setPosition(170, 200);
- else
- vi->setPosition(160, 150);
- vi->setOneLiner(tr("Connected, loading config"));
- vi->draw();
- boxstack->add(vi);
- boxstack->update(vi);
-
- VDR* vdr = VDR::getInstance();
- char* config;
-
- // See if we're supposed to do network logging
- config = vdr->configLoad("Advanced", "Network logging");
- if (config && !STRCASECMP(config, "On"))
- {
- logger->log("Command", Log::INFO, "Turning on network logging");
- logger->netLogOn();
- }
- else
- {
- logger->netLogOn();
- logger->log("Command", Log::INFO, "Turned off network logging");
- }
- if (config) delete[] config;
-
- // See if config says to override video format (PAL/NTSC)
- config = vdr->configLoad("General", "Override Video Format");
- if (config)
- {
- logger->log("Command", Log::DEBUG, "Override Video Format is present");
-
- if ( (!strcmp(config, "PAL") && (video->getFormat() == Video::NTSC))
- || (!strcmp(config, "NTSC") && (video->getFormat() == Video::PAL)) )
- {
- // Oh sheesh, need to switch format. Bye bye TV...
-
- // Take everything down
- boxstack->removeAll();
- boxstack->remove(wallpaper);
- Osd* osd = Osd::getInstance();
- osd->shutdown();
- video->shutdown();
-
- // Get video and osd back up with the new mode
- if (!strcmp(config, "PAL"))
- {
- logger->log("Command", Log::DEBUG, "Switching to PAL");
- video->init(Video::PAL);
- }
- else if (!strcmp(config, "NTSC"))
- {
- logger->log("Command", Log::DEBUG, "Switching to NTSC");
- video->init(Video::NTSC);
- }
- osd->init((char*)("/dev/stbgfx"));
-
- // Put the wallpaper back
- doWallpaper();
-
- // Re add the vinfo
- vi = new VInfo();
- vi->setSize(400, 200);
- vi->createBuffer();
- if (video->getFormat() == Video::PAL)
- vi->setPosition(170, 200);
- else
- vi->setPosition(160, 150);
-
- vi->setOneLiner(tr("Connected, loading config"));
- vi->draw();
- boxstack->add(vi);
- boxstack->update(vi);
- }
- else
- {
- logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
- }
- }
- else
- {
- logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
- }
-
- // Power off if first boot and config says so
- if (firstBoot)
- {
- firstBoot = 0;
-
- logger->log("Command", Log::DEBUG, "Load power after boot");
-
- config = vdr->configLoad("General", "Power After Boot");
-
- if (config)
- {
- if (!STRCASECMP(config, "On"))
- {
- logger->log("Command", Log::INFO, "Config says Power After Boot = On");
- }
- else if (!STRCASECMP(config, "Off"))
- {
- logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
- doStandby();
- delete[] config;
- return; // quit here
- }
- else if (!STRCASECMP(config, "Last state"))
- {
- char* lastPowerState = vdr->configLoad("General", "Last Power State");
- if (lastPowerState)
- {
- if (!STRCASECMP(lastPowerState, "On"))
- {
- logger->log("Command", Log::INFO, "Config says Last Power State = On");
- }
- else if (!STRCASECMP(lastPowerState, "Off"))
- {
- logger->log("Command", Log::INFO, "Config says Last Power State = Off");
- doStandby();
- delete[] config;
- return; // quit here
- }
- else
- {
- logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
- }
- }
- else
- {
- logger->log("Command", Log::INFO, "Config General/Last Power State not found");
- }
- }
- else
- {
- logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
- }
- delete[] config;
- }
- else
- {
- logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
- }
- }
-
-
- // Go S-Video if config says so
-
- config = vdr->configLoad("TV", "Connection");
-
- if (config)
- {
- if (!STRCASECMP(config, "S-Video"))
- {
- logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
- video->setConnection(Video::SVIDEO);
- }
- else
- {
- logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
- video->setConnection(Video::COMPOSITERGB);
- }
- delete[] config;
- }
- else
- {
- logger->log("Command", Log::INFO, "Config TV/S-Video not found");
- }
-
- // Set remote type
-
- config = vdr->configLoad("General", "Remote type");
-
- if (config)
- {
- if (!STRCASECMP(config, "New"))
- {
- logger->log("Command", Log::INFO, "Switching to New remote type");
- remote->setRemoteType(Remote::NEWREMOTE);
- }
- else
- {
- logger->log("Command", Log::INFO, "Switching to Old remote type");
- remote->setRemoteType(Remote::OLDREMOTE);
- }
- delete[] config;
- }
- else
- {
- logger->log("Command", Log::INFO, "Config General/Remote type not found");
- remote->setRemoteType(Remote::OLDREMOTE);
- }
-
-
-
-
- // Get TV aspect ratio
-
- config = vdr->configLoad("TV", "Aspect");
- if (config)
- {
- if (!STRCASECMP(config, "16:9"))
- {
- logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
- video->setTVsize(Video::ASPECT16X9);
- }
- else
- {
- logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
- video->setTVsize(Video::ASPECT4X3);
- }
- delete[] config;
- }
- else
- {
- logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
- video->setTVsize(Video::ASPECT4X3);
- }
-
- config = vdr->configLoad("TV", "Widemode");
- if (config)
- {
- if (!STRCASECMP(config, "Letterbox"))
- {
- logger->log("Command", Log::INFO, "Setting letterbox mode");
- video->setMode(Video::LETTERBOX);
- }
- else
- {
- logger->log("Command", Log::INFO, "Setting chop-sides mode");
- video->setMode(Video::NORMAL);
- }
- delete[] config;
- }
- else
- {
- logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
- video->setMode(Video::NORMAL);
- }
-
- config = vdr->configLoad("Advanced", "TCP receive window");
- if (config)
- {
- size_t newTCPsize = atoi(config);
- delete[] config;
-
- logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
- vdr->setReceiveWindow(newTCPsize);
- }
- else
- {
- logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
- vdr->setReceiveWindow(2048); // Default
- }
-
- config = vdr->configLoad("Advanced", "Disable WOL");
- if (config)
- {
- if (!STRCASECMP(config, "Yes"))
- {
- logger->log("Command", Log::INFO, "Config says disable WOL");
- Wol::getInstance()->setEnabled(false);
- }
- else
- {
- logger->log("Command", Log::INFO, "Config says enable WOL");
- Wol::getInstance()->setEnabled(true);
- }
-
- delete[] config;
- }
- else
- {
- logger->log("Command", Log::INFO, "By default, enable WOL");
- Wol::getInstance()->setEnabled(true);
- }
- /* device dependend config */
- audio->loadOptionsfromServer(vdr);
- video->loadOptionsfromServer(vdr);
- remote->loadOptionsfromServer(vdr);
- // config done
-
- // Save power state = on
-
- vdr->configSave("General", "Last Power State", "On");
-
- // Make sure connection didn't die
- if (!vdr->isConnected())
- {
- Command::getInstance()->connectionLost();
- }
- else
- {
- boxstack->remove(vi);
-
- VWelcome* vw = new VWelcome();
- vw->draw();
- boxstack->add(vw);
- boxstack->update(vw);
-
- // Enter pre-keys here
-// handleCommand(Remote::OK);
-// handleCommand(Remote::THREE);
-// handleCommand(Remote::SIX);
-// handleCommand(Remote::OK);
-// handleCommand(Remote::UP);
-// handleCommand(Remote::PLAY);
-// handleCommand(Remote::DOWN);
-// handleCommand(Remote::DOWN);
-// handleCommand(Remote::DOWN);
- // handleCommand(Remote::OK);
-// handleCommand(Remote::RED);
- }
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef WIN32\r
+#include <linux/errno.h>\r
+#endif\r
+\r
+#include "command.h"\r
+\r
+#ifdef WIN32\r
+#include "remotewin.h"\r
+#endif\r
+\r
+#ifdef __ANDROID__\r
+#include "remoteandroid.h"\r
+#endif\r
+\r
+#include "led.h"\r
+#include "video.h"\r
+#include "audio.h"\r
+#include "vdr.h"\r
+#include "vvolume.h"\r
+#include "vserverselect.h"\r
+#include "vwelcome.h"\r
+#include "vmute.h"\r
+#include "colour.h"\r
+#include "osd.h"\r
+#include "i18n.h"\r
+#include "timerreceiver.h"\r
+#include "timers.h"\r
+#include "wol.h"\r
+#include "vconnect.h"\r
+#include "message.h"\r
+#include "remote.h"\r
+#include "vinfo.h"\r
+#include "boxx.h"\r
+#include "boxstack.h"\r
+#include "log.h"\r
+#include "vsleeptimer.h"\r
+\r
+\r
+Command* Command::instance = NULL;\r
+\r
+Command::Command()\r
+{\r
+ if (instance) return;\r
+ instance = this;\r
+ initted = 0;\r
+ isStandby = 0;\r
+ firstBoot = 1;\r
+ connLost = NULL;\r
+ crashed = false;\r
+ server = NULL;\r
+}\r
+\r
+Command::~Command()\r
+{\r
+ instance = NULL;\r
+}\r
+\r
+Command* Command::getInstance()\r
+{\r
+ return instance;\r
+}\r
+\r
+int Command::init(bool tcrashed, char* tServer)\r
+{\r
+ if (initted) return 0;\r
+ initted = 1;\r
+ crashed = tcrashed;\r
+ server = tServer;\r
+\r
+ logger = Log::getInstance();\r
+ boxstack = BoxStack::getInstance();\r
+ remote = Remote::getInstance();\r
+ \r
+ remote->InitHWCListwithDefaults();\r
+ \r
+ if (!logger || !boxstack || !remote)\r
+ {\r
+ initted = 0;\r
+ return 0;\r
+ }\r
+#ifndef WIN32\r
+ pthread_mutex_init(&masterLock, NULL);\r
+#else\r
+ masterLock=CreateMutex(NULL,FALSE,NULL);\r
+#endif\r
+\r
+ return 1;\r
+}\r
+\r
+int Command::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ initted = 0;\r
+ return 1;\r
+}\r
+\r
+void Command::stop()\r
+{\r
+// VDR::getInstance()->cancelFindingServer();\r
+ logger->log("Command", Log::NOTICE, "Command stop1...");\r
+ \r
+ udp.shutdown();\r
+ logger->log("Command", Log::NOTICE, "Command stop2...");\r
+ irun = 0;\r
+}\r
+\r
+void Command::doWallpaper()\r
+{\r
+ Video* video = Video::getInstance();\r
+\r
+ // Blue background\r
+ Boxx* bbg = new Boxx();\r
+ bbg->setSize(video->getScreenWidth(), video->getScreenHeight());\r
+ bbg->createBuffer();\r
+ bbg->fillColour(Colour::VIDEOBLUE);\r
+ boxstack->add(bbg);\r
+ boxstack->update(bbg);\r
+ boxstack->remove(bbg);\r
+\r
+ // Wallpaper\r
+ WJpeg* wallpaperj = new WJpegTYPE();\r
+ wallpaperj->setSize(video->getScreenWidth(), video->getScreenHeight());\r
+ wallpaperj->createBuffer();\r
+\r
+ if (video->getFormat() == Video::PAL)\r
+ {\r
+ logger->log("Command", Log::DEBUG, "PAL wallpaper selected");\r
+#ifndef _MIPS_ARCH \r
+ wallpaperj->init("/wallpaperPAL.jpg");\r
+#else\r
+ wallpaperj->init("wallpaperPAL.jpg");\r
+#endif\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");\r
+ wallpaperj->init("/wallpaperNTSC.jpg");\r
+ }\r
+ wallpaperj->draw();\r
+\r
+ boxstack->add(wallpaperj);\r
+ boxstack->update(wallpaperj);\r
+\r
+ wallpaper = wallpaperj;\r
+}\r
+\r
+void Command::run()\r
+{\r
+ if (!initted) return;\r
+ irun = 1;\r
+#ifndef WIN32\r
+ mainPid = getpid();\r
+#endif\r
+\r
+ // just in case\r
+ Video::getInstance()->signalOn();\r
+ Led::getInstance()->on();\r
+\r
+ doWallpaper();\r
+\r
+ // End of startup. Lock the mutex and put the first view up\r
+// logger->log("Command", Log::DEBUG, "WANT LOCK");\r
+#ifndef WIN32\r
+ pthread_mutex_lock(&masterLock);\r
+#else\r
+ WaitForSingleObject(masterLock, INFINITE );\r
+#endif\r
+ //logger->log("Command", Log::DEBUG, "LOCKED");\r
+\r
+ if (crashed)\r
+ {\r
+ buildCrashedBox();\r
+ }\r
+ else\r
+ {\r
+ VConnect* vconnect = new VConnect(server);\r
+ boxstack->add(vconnect);\r
+ vconnect->run();\r
+ }\r
+\r
+ // Start method 2 of getting commands in...\r
+ udp.run(this);\r
+\r
+ UCHAR button = 0;\r
+ while(irun)\r
+ {\r
+ // unlock and wait\r
+ //logger->log("Command", Log::DEBUG, "UNLOCK");\r
+#ifndef WIN32\r
+ pthread_mutex_unlock(&masterLock);\r
+#else\r
+ ReleaseMutex(masterLock);\r
+#endif\r
+ \r
+ button = remote->getButtonPress(2); // FIXME why is this set to 2 and not 0? so it can quit \r
+ // something happened, lock and process\r
+ \r
+ // logger->log("Command", Log::DEBUG, "WANT LOCK");\r
+#ifndef WIN32\r
+ pthread_mutex_lock(&masterLock);\r
+#else\r
+ WaitForSingleObject(masterLock, INFINITE );\r
+#endif\r
+ // logger->log("Command", Log::DEBUG, "LOCK");\r
+\r
+ if ((button == Remote::NA_NONE) /*|| (button == Remote::NA_UNKNOWN)*/) continue;\r
+\r
+ if (button != Remote::NA_SIGNAL) handleCommand(button);\r
+ processMessageQueue();\r
+\r
+ }\r
+\r
+ //logger->log("Command", Log::DEBUG, "UNLOCK");\r
+#ifndef WIN32\r
+ pthread_mutex_unlock(&masterLock);\r
+#else\r
+ ReleaseMutex(masterLock);\r
+#endif\r
+\r
+\r
+}\r
+\r
+void Command::postMessage(Message* m)\r
+{\r
+ // This is locked here in case the main loop is not waiting for an event, but is processing one\r
+ // it could be killed but then not react to it because the signal wouldn't cause\r
+ // remote->getButtonPress to break\r
+ // locking the mutex ensures that the master thread is waiting on getButtonPress\r
+\r
+\r
+ //logger->log("Command", Log::DEBUG, "WANT LOCK");\r
+#ifndef WIN32\r
+ pthread_mutex_lock(&masterLock);\r
+#else\r
+ WaitForSingleObject(masterLock, INFINITE );\r
+#endif\r
+ //logger->log("Command", Log::DEBUG, "LOCK");\r
+ MessageQueue::postMessage(m);\r
+\r
+#ifndef WIN32\r
+#ifndef __ANDROID__\r
+ kill(mainPid, SIGURG);\r
+#else\r
+ ((RemoteAndroid*)Remote::getInstance())->Signal();\r
+#endif\r
+ pthread_mutex_unlock(&masterLock);\r
+#else\r
+ ((RemoteWin*)Remote::getInstance())->Signal();\r
+ ReleaseMutex(masterLock);\r
+#endif\r
+ //logger->log("Command", Log::DEBUG, "UNLOCK");\r
+}\r
+\r
+void Command::postMessageNoLock(Message* m)\r
+{\r
+ // As above but use this one if this message is being posted because of a button press\r
+ // the mutex is already locked, locking around postMessage is not needed as the\r
+ // queue is guaranteed to be run when the button has been processed\r
+ MessageQueue::postMessage(m);\r
+}\r
+\r
+bool Command::postMessageIfNotBusy(Message* m)\r
+{\r
+ // Used for Windows mouse events\r
+\r
+ //logger->log("Command", Log::DEBUG, "TRY LOCK");\r
+#ifndef WIN32\r
+ if (pthread_mutex_trylock(&masterLock) != EBUSY)\r
+ {\r
+ //logger->log("Command", Log::DEBUG, "LOCK");\r
+ MessageQueue::postMessage(m);\r
+#ifndef __ANDROID__\r
+ kill(mainPid, SIGURG);\r
+#else\r
+ ((RemoteAndroid*)Remote::getInstance())->Signal();\r
+#endif\r
+ pthread_mutex_unlock(&masterLock);\r
+ //logger->log("Command", Log::DEBUG, "UNLOCK");\r
+ return true;\r
+ }\r
+ else\r
+ {\r
+ return false;\r
+ }\r
+#else\r
+ switch (WaitForSingleObject(masterLock, 0 ))\r
+ { //FIXME this is not "if not busy" check\r
+ case WAIT_OBJECT_0: //but with proper argument 0 this did not work\r
+ // case WAIT_ABANDONED:\r
+ MessageQueue::postMessage(m);\r
+ ((RemoteWin*)Remote::getInstance())->Signal();\r
+ ReleaseMutex(masterLock);\r
+ return true;\r
+\r
+ case WAIT_ABANDONED: return false;\r
+ case WAIT_TIMEOUT: return false;\r
+ }\r
+ return false;\r
+#endif\r
+}\r
+\r
+void Command::postMessageFromOuterSpace(Message* m)\r
+{\r
+ /*\r
+ Yet another way of getting messages into Command. This one is for events that\r
+ are not standard button presses (or UDP generated buttons). It is also not for\r
+ events that are generated as a result of other events (events that can safely\r
+ call postMessageNoLock and be guaranteed that the message will be processed\r
+ because it is known that the queue is currently being processed).\r
+ This is for events that come from outer space and can occur when the master\r
+ mutex is locked or not, they need to be queued and executed but it doesn't\r
+ matter when.\r
+ Actually so far it is for events caused by the video stream - aspect ratio\r
+ changes. These can occur when the master mutex is locked and so postMessage\r
+ doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*\r
+ locked at the time then the message could be sat around a while before\r
+ being noticed.\r
+ The whole message system was at first supposed to prevent the problem of\r
+ calling a function on an object that had just been deleted, by ordering\r
+ messages such that all calls are done before object deletion. However,\r
+ because of the new centralised messaging system and the fact that BoxStack\r
+ locates the destination object before calling it, the messaging system now\r
+ allows the kind of sloppy calls it was supposed to stop. Weird huh. This\r
+ is mentioned here because the video stream might generate an event just as\r
+ the user hits stop. The mutex is locked, and by the time the message\r
+ is examined the vvideorec/live has been deleted. This doesn't matter because\r
+ boxstack will drop the message if it can't find the matching object to\r
+ deliver it to.\r
+ Finally, all this is fine and dandy, except that I'm not 100% sure that\r
+ this sloppy postMessage and hope a queued signal will force it to be processed\r
+ thingy will actually work. Hmmm.\r
+ Lastly <g>, I will consider making the naming system a little more sane\r
+ if this works.\r
+ */\r
+\r
+ logger->log("Command", Log::DEBUG, "PMFOS called");\r
+ MessageQueue::postMessage(m);\r
+\r
+#ifndef WIN32\r
+#ifndef __ANDROID__\r
+ kill(mainPid, SIGURG);\r
+#else\r
+ ((RemoteAndroid*)Remote::getInstance())->Signal();\r
+#endif\r
+#else\r
+ ((RemoteWin*)Remote::getInstance())->Signal();\r
+#endif\r
+}\r
+\r
+void Command::processMessage(Message* m)\r
+{\r
+ // FIXME - a slight modification - how if messagereceivers were to register\r
+ // themselves as receivers to avoid the calling-a-deleted-object problem\r
+ // then only deliver/register/unregister would have to be protected\r
+\r
+ logger->log("Command", Log::DEBUG, "processing message %i", m->message);\r
+\r
+\r
+ if (m->to == this)\r
+ {\r
+ switch(m->message)\r
+ {\r
+ // << FIXME OBSELETE\r
+ case Message::STOP_PLAYBACK:\r
+ {\r
+ handleCommand(Remote::STOP); // an odd way of doing it, but so simple\r
+ break;\r
+ }\r
+ // Also connection_lost comes from player - anywhere else?\r
+ // FIXME OBSELETE >>\r
+\r
+\r
+ case Message::VDR_CONNECTED:\r
+ {\r
+ doJustConnected((VConnect*)m->from);\r
+ break;\r
+ }\r
+ case Message::SCREENSHOT:\r
+ {\r
+ Osd::getInstance()->screenShot("/out.jpg");\r
+ break;\r
+ }\r
+ case Message::CONNECTION_LOST:\r
+ {\r
+ doFromTheTop(true);\r
+ break;\r
+ }\r
+ case Message::UDP_BUTTON:\r
+ {\r
+ handleCommand(m->parameter);\r
+ break;\r
+ }\r
+ case Message::CHANGE_LANGUAGE:\r
+ {\r
+ boxstack->removeAll();\r
+ boxstack->update(wallpaper);\r
+ I18n::initialize();\r
+ if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }\r
+ VWelcome* vw = new VWelcome();\r
+ vw->draw();\r
+ boxstack->add(vw);\r
+ boxstack->update(vw);\r
+ break;\r
+ }\r
+ case Message::LAST_VIEW_CLOSE:\r
+ {\r
+ // Shouldn't be done like this. Some generic message pass back from vinfo perhaps\r
+ if (crashed)\r
+ {\r
+ crashed = false;\r
+ doFromTheTop(false); \r
+ }\r
+ \r
+// VWelcome* vw = new VWelcome();\r
+// vw->draw();\r
+// boxstack->add(vw);\r
+// boxstack->update(vw);\r
+\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* FIXME\r
+ \r
+ Instead of sending through the boxstack, implement a more generic MessageReceiver interface\r
+ and have potential receivers register with something\r
+ When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message\r
+ This could all be done using the existing big command mutex to keep it simple\r
+ */\r
+ \r
+ logger->log("Command", Log::DEBUG, "Sending message to boxstack");\r
+ boxstack->processMessage(m);\r
+ }\r
+}\r
+\r
+void Command::handleCommand(int button)\r
+{\r
+ if (isStandby && (button != Remote::POWER)) return;\r
+ if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost\r
+\r
+ // command was not handled\r
+\r
+ switch(button)\r
+ {\r
+ case Remote::DF_LEFT:\r
+ case Remote::DF_RIGHT:\r
+ case Remote::VOLUMEUP:\r
+ case Remote::VOLUMEDOWN:\r
+ {\r
+ VVolume* v = new VVolume();\r
+ boxstack->add(v);\r
+ v->handleCommand(button); // this will draw+show\r
+ return;\r
+ }\r
+ case Remote::MUTE:\r
+ {\r
+ VMute* v = new VMute();\r
+ v->draw();\r
+ boxstack->add(v);\r
+ boxstack->update(v);\r
+ return;\r
+ }\r
+ case Remote::POWER:\r
+ {\r
+ doStandby();\r
+ return;\r
+ }\r
+ case Remote::OK:\r
+ {\r
+ // FIXME\r
+ if (!connLost) return; // if connLost, handle Remote::OK\r
+ doFromTheTop(false);\r
+ return;\r
+ }\r
+ case Remote::GO:\r
+ {\r
+ VSleeptimer* sleep = new VSleeptimer();\r
+ boxstack->add(sleep);\r
+ sleep->handleCommand(button); // this will draw+show\r
+ return;\r
+ }\r
+ }\r
+}\r
+\r
+void Command::sig1()\r
+{\r
+#ifdef DEV\r
+ Message* m = new Message(); // break into master mutex\r
+ m->message = Message::SCREENSHOT;\r
+ m->to = this;\r
+ postMessage(m);\r
+#endif\r
+}\r
+\r
+void Command::doStandby()\r
+{\r
+ if (isStandby)\r
+ {\r
+ Video::getInstance()->signalOn();\r
+ Led::getInstance()->on();\r
+ isStandby = 0;\r
+\r
+\r
+ VConnect* vconnect = new VConnect(server);\r
+ boxstack->add(vconnect);\r
+ vconnect->run();\r
+ }\r
+ else\r
+ {\r
+ boxstack->removeAll();\r
+ Video::getInstance()->signalOff();\r
+ boxstack->update(wallpaper);\r
+\r
+ VDR::getInstance()->configSave("General", "Last Power State", "Off");\r
+ logger->unsetExternLogger();\r
+ VDR::getInstance()->disconnect();\r
+ Led::getInstance()->off();\r
+ isStandby = 1;\r
+ Sleeptimer::getInstance()->shutdown();\r
+#ifdef WIN32\r
+ stop(); //different behavoiur on windows, we exit\r
+#endif\r
+ }\r
+}\r
+\r
+void Command::doFromTheTop(bool which)\r
+{\r
+ if (which)\r
+ {\r
+ if (connLost)\r
+ {\r
+ logger->log("Command", Log::NOTICE, "Connection lost dialog already present");\r
+ return;\r
+ }\r
+ \r
+ logger->log("Command", Log::NOTICE, "Doing connection lost dialog");\r
+ connLost = new VInfo();\r
+ connLost->setSize(360, 200);\r
+ connLost->createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ connLost->setPosition(190, 170);\r
+ else\r
+ connLost->setPosition(180, 120);\r
+ connLost->setOneLiner(tr("Connection lost"));\r
+ connLost->setDropThrough();\r
+ connLost->setBorderOn(1);\r
+ connLost->setTitleBarColour(Colour::DANGER);\r
+ connLost->okButton();\r
+ connLost->draw();\r
+ boxstack->add(connLost);\r
+ boxstack->update(connLost);\r
+ remote->clearBuffer();\r
+ }\r
+ else\r
+ {\r
+ logger->unsetExternLogger();\r
+ VDR::getInstance()->disconnect();\r
+ boxstack->removeAll();\r
+ boxstack->update(wallpaper);\r
+ connLost = NULL;\r
+ \r
+ flushMessageQueue();\r
+ remote->clearBuffer();\r
+ \r
+ // at this point, everything should be reset to first-go\r
+ \r
+ VConnect* vconnect = new VConnect(server);\r
+ boxstack->add(vconnect);\r
+ vconnect->run();\r
+ }\r
+}\r
+\r
+void Command::doReboot()\r
+{\r
+\r
+ logger->unsetExternLogger();\r
+ VDR::getInstance()->disconnect();\r
+ // just kill it...\r
+ logger->log("Command", Log::NOTICE, "Reboot");\r
+#ifndef WIN32\r
+#ifdef VOMP_PLATTFORM_MVP\r
+ reboot(LINUX_REBOOT_CMD_RESTART);\r
+#else\r
+ stop();\r
+\r
+#ifdef __ANDROID__\r
+ exit(0);\r
+#endif\r
+\r
+#endif\r
+#endif //Would we support this on windows?\r
+}\r
+\r
+void Command::connectionLost()\r
+{\r
+ logger->unsetExternLogger();\r
+ Message* m = new Message(); // break into master mutex\r
+ m->message = Message::CONNECTION_LOST;\r
+ m->to = this;\r
+ postMessageFromOuterSpace(m);\r
+}\r
+\r
+void Command::buildCrashedBox()\r
+{\r
+ VInfo* crash = new VInfo();\r
+ crash->setSize(360, 250);\r
+ crash->createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ crash->setPosition(190, 146);\r
+ else\r
+ crash->setPosition(180, 96);\r
+ crash->setMainText("Oops, vomp crashed.. :(\nPlease report this crash to the author, with as much detail as possible about what you were doing at the time that might have caused the crash.");\r
+ crash->setBorderOn(1);\r
+ crash->setTitleBarColour(Colour::DANGER);\r
+ crash->okButton();\r
+ crash->setExitable();\r
+ crash->draw();\r
+ boxstack->add(crash);\r
+ boxstack->update(crash);\r
+}\r
+\r
+void Command::doJustConnected(VConnect* vconnect)\r
+{\r
+ I18n::initialize();\r
+ if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }\r
+ \r
+ Video* video = Video::getInstance();\r
+ Audio* audio = Audio::getInstance(); \r
+ boxstack->remove(vconnect);\r
+\r
+ VInfo* vi = new VInfo();\r
+ vi->setSize(400, 200);\r
+ vi->createBuffer();\r
+ if (video->getFormat() == Video::PAL)\r
+ vi->setPosition(170, 200);\r
+ else\r
+ vi->setPosition(160, 150);\r
+ vi->setOneLiner(tr("Connected, loading config"));\r
+ vi->draw();\r
+ boxstack->add(vi);\r
+ boxstack->update(vi);\r
+\r
+ VDR* vdr = VDR::getInstance();\r
+ char* config;\r
+\r
+ // See if we're supposed to do network logging\r
+ config = vdr->configLoad("Advanced", "Network logging");\r
+ if (config && !STRCASECMP(config, "On"))\r
+ {\r
+ logger->log("Command", Log::INFO, "Turning on network logging");\r
+ logger->setExternLogger(vdr);\r
+ } \r
+ else\r
+ {\r
+ logger->unsetExternLogger();\r
+ logger->log("Command", Log::INFO, "Turned off network logging");\r
+ }\r
+ if (config) delete[] config;\r
+\r
+ // See if config says to override video format (PAL/NTSC)\r
+ config = vdr->configLoad("General", "Override Video Format");\r
+ if (config)\r
+ {\r
+ logger->log("Command", Log::DEBUG, "Override Video Format is present");\r
+\r
+ if ( (!strcmp(config, "PAL") && (video->getFormat() == Video::NTSC))\r
+ || (!strcmp(config, "NTSC") && (video->getFormat() == Video::PAL)) )\r
+ {\r
+ // Oh sheesh, need to switch format. Bye bye TV...\r
+\r
+ // Take everything down\r
+ boxstack->removeAll();\r
+ boxstack->remove(wallpaper);\r
+ Osd* osd = Osd::getInstance();\r
+#ifndef __ANDROID__\r
+ osd->shutdown();\r
+#endif\r
+ video->shutdown();\r
+\r
+ // Get video and osd back up with the new mode\r
+ if (!strcmp(config, "PAL"))\r
+ {\r
+ logger->log("Command", Log::DEBUG, "Switching to PAL");\r
+ video->init(Video::PAL);\r
+ }\r
+ else if (!strcmp(config, "NTSC"))\r
+ {\r
+ logger->log("Command", Log::DEBUG, "Switching to NTSC");\r
+ video->init(Video::NTSC);\r
+ }\r
+#ifndef __ANDROID__\r
+ //we do not init twice\r
+ osd->init((char*)("/dev/stbgfx"));\r
+#endif\r
+\r
+ // Put the wallpaper back\r
+ doWallpaper();\r
+\r
+ // Re add the vinfo\r
+ vi = new VInfo();\r
+ vi->setSize(400, 200);\r
+ vi->createBuffer();\r
+ if (video->getFormat() == Video::PAL)\r
+ vi->setPosition(170, 200);\r
+ else\r
+ vi->setPosition(160, 150);\r
+\r
+ vi->setOneLiner(tr("Connected, loading config"));\r
+ vi->draw();\r
+ boxstack->add(vi);\r
+ boxstack->update(vi);\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");\r
+ }\r
+\r
+ // Power off if first boot and config says so\r
+ if (firstBoot)\r
+ {\r
+ firstBoot = 0;\r
+\r
+ logger->log("Command", Log::DEBUG, "Load power after boot");\r
+\r
+ config = vdr->configLoad("General", "Power After Boot");\r
+\r
+ if (config)\r
+ {\r
+ if (!STRCASECMP(config, "On"))\r
+ {\r
+ logger->log("Command", Log::INFO, "Config says Power After Boot = On");\r
+ }\r
+ else if (!STRCASECMP(config, "Off"))\r
+ {\r
+ logger->log("Command", Log::INFO, "Config says Power After Boot = Off");\r
+ doStandby();\r
+ delete[] config;\r
+ return; // quit here\r
+ }\r
+ else if (!STRCASECMP(config, "Last state"))\r
+ {\r
+ char* lastPowerState = vdr->configLoad("General", "Last Power State");\r
+ if (lastPowerState)\r
+ {\r
+ if (!STRCASECMP(lastPowerState, "On"))\r
+ {\r
+ logger->log("Command", Log::INFO, "Config says Last Power State = On");\r
+ }\r
+ else if (!STRCASECMP(lastPowerState, "Off"))\r
+ {\r
+ logger->log("Command", Log::INFO, "Config says Last Power State = Off");\r
+ doStandby();\r
+ delete[] config;\r
+ return; // quit here\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Config General/Last Power State not understood");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Config General/Last Power State not found");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Config/Power After Boot not understood");\r
+ }\r
+ delete[] config;\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Config General/Power After Boot not found");\r
+ }\r
+ }\r
+\r
+\r
+ // Go S-Video if config says so\r
+\r
+ config = vdr->configLoad("TV", "Connection");\r
+\r
+ if (config)\r
+ {\r
+ if (!STRCASECMP(config, "S-Video"))\r
+ {\r
+ logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);\r
+ video->setConnection(Video::SVIDEO);\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);\r
+ video->setConnection(Video::COMPOSITERGB);\r
+ }\r
+ delete[] config;\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Config TV/S-Video not found");\r
+ }\r
+\r
+ // Set remote type\r
+\r
+ config = vdr->configLoad("General", "Remote type");\r
+\r
+ if (config)\r
+ {\r
+ if (!STRCASECMP(config, "New"))\r
+ {\r
+ logger->log("Command", Log::INFO, "Switching to New remote type");\r
+ remote->setRemoteType(Remote::NEWREMOTE);\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Switching to Old remote type");\r
+ remote->setRemoteType(Remote::OLDREMOTE);\r
+ }\r
+ delete[] config;\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Config General/Remote type not found");\r
+ remote->setRemoteType(Remote::OLDREMOTE);\r
+ }\r
+\r
+\r
+\r
+\r
+ // Get TV aspect ratio\r
+\r
+ config = vdr->configLoad("TV", "Aspect");\r
+ if (config)\r
+ {\r
+ if (!STRCASECMP(config, "16:9"))\r
+ {\r
+ logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");\r
+ video->setTVsize(Video::ASPECT16X9);\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");\r
+ video->setTVsize(Video::ASPECT4X3);\r
+ }\r
+ delete[] config;\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");\r
+ video->setTVsize(Video::ASPECT4X3);\r
+ }\r
+\r
+ config = vdr->configLoad("TV", "Widemode");\r
+ if (config)\r
+ {\r
+ if (!STRCASECMP(config, "Letterbox"))\r
+ {\r
+ logger->log("Command", Log::INFO, "Setting letterbox mode");\r
+ video->setMode(Video::LETTERBOX);\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Setting chop-sides mode");\r
+ video->setMode(Video::NORMAL);\r
+ }\r
+ delete[] config;\r
+ }\r
+ else\r
+ {\r
+#ifdef __ANDROID__\r
+ logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting letterbox mode");\r
+ video->setMode(Video::LETTERBOX);\r
+#else\r
+ logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");\r
+ video->setMode(Video::NORMAL);\r
+#endif\r
+ }\r
+\r
+ config = vdr->configLoad("Advanced", "TCP receive window");\r
+ if (config)\r
+ {\r
+ size_t newTCPsize = atoi(config);\r
+ delete[] config;\r
+\r
+ logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);\r
+ vdr->setReceiveWindow(newTCPsize);\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");\r
+ vdr->setReceiveWindow(2048); // Default\r
+ }\r
+\r
+ config = vdr->configLoad("Advanced", "Disable WOL");\r
+ if (config)\r
+ {\r
+ if (!STRCASECMP(config, "Yes"))\r
+ {\r
+ logger->log("Command", Log::INFO, "Config says disable WOL");\r
+ Wol::getInstance()->setEnabled(false);\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "Config says enable WOL");\r
+ Wol::getInstance()->setEnabled(true);\r
+ }\r
+\r
+ delete[] config;\r
+ }\r
+ else\r
+ {\r
+ logger->log("Command", Log::INFO, "By default, enable WOL");\r
+ Wol::getInstance()->setEnabled(true);\r
+ }\r
+ /* device dependend config */\r
+ audio->loadOptionsfromServer(vdr);\r
+ video->loadOptionsfromServer(vdr);\r
+ remote->loadOptionsfromServer(vdr);\r
+ // config done\r
+\r
+ // Save power state = on\r
+\r
+ vdr->configSave("General", "Last Power State", "On");\r
+\r
+ // Make sure connection didn't die\r
+ if (!vdr->isConnected())\r
+ {\r
+ Command::getInstance()->connectionLost();\r
+ }\r
+ else\r
+ {\r
+ boxstack->remove(vi);\r
+\r
+ VWelcome* vw = new VWelcome();\r
+ vw->draw();\r
+ boxstack->add(vw);\r
+ boxstack->update(vw);\r
+\r
+ // Enter pre-keys here\r
+// handleCommand(Remote::OK);\r
+// handleCommand(Remote::THREE);\r
+// handleCommand(Remote::SIX);\r
+// handleCommand(Remote::OK);\r
+// handleCommand(Remote::UP);\r
+// handleCommand(Remote::PLAY);\r
+// handleCommand(Remote::DOWN);\r
+// handleCommand(Remote::DOWN);\r
+// handleCommand(Remote::DOWN);\r
+ // handleCommand(Remote::OK);\r
+// handleCommand(Remote::RED);\r
+ }\r
+}\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef DEFINES_H
-#define DEFINES_H
-
-typedef unsigned char UCHAR;
-typedef unsigned short USHORT;
-typedef unsigned int UINT;
-typedef unsigned long ULONG;
-typedef unsigned long long ULLONG;
-
-#define OPTIONTYPE_TEXT 1
-#define OPTIONTYPE_INT 2
-
-ULLONG htonll(ULLONG a);
-ULLONG ntohll(ULLONG a);
-void MILLISLEEP(ULONG a);
-
-#ifdef WIN32
-
- #define Surface_TYPE SurfaceWin
- #define Thread_TYPE ThreadWin
- #define ThreadID_TYPE unsigned int
-
- #define SNPRINTF _snprintf
- #define VSNPRINTF _vsnprintf
- #define STRCASECMP _stricmp
- #define STRCASESTR StrStrI
-/* #define STRTOULL _strtoui64 */
- #define STRTOUL strtoul
- #define CLOSESOCKET closesocket
-
-#else
-
- int max(int, int);
- int min(UINT, int);
-#ifdef _MIPS_ARCH
- #define Surface_TYPE SurfaceDirectFB
-#else
- #define Surface_TYPE SurfaceMVP
-#endif
-
- #define Thread_TYPE ThreadP
- #include <pthread.h>
- #define ThreadID_TYPE pthread_t
-
- #define SNPRINTF snprintf
- #define VSNPRINTF vsnprintf
- #define STRCASECMP strcasecmp
- #define STRCASESTR strcasestr
- #define STRTOUL strtoul
- #define CLOSESOCKET close
-
-#endif
-
-/*
-typedef struct
-{
- UINT id; // Used for working out what has changed at the end
- char *title; // Name of the option
- char *configSection; // Which section of the config file
- char *configParam; // Parameter name in the config file
- UINT optionType; // 1 for text, 2 for int
- UINT optionCount; // How many choices?
- UINT defaultOption; // Serial of the default choice (base 0), or actual option in int mode
- int startInt; // Starting int for int mode
- const char * const * options; // Text for the options (null for int mode)
-} OPTIONDATA;
-*/
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef DEFINES_H\r
+#define DEFINES_H\r
+\r
+typedef unsigned char UCHAR;\r
+typedef unsigned short USHORT;\r
+typedef unsigned int UINT;\r
+typedef unsigned long ULONG;\r
+typedef unsigned long long ULLONG;\r
+\r
+#define OPTIONTYPE_TEXT 1\r
+#define OPTIONTYPE_INT 2\r
+\r
+//ULLONG htonll(ULLONG a);\r
+//ULLONG ntohll(ULLONG a);\r
+void MILLISLEEP(ULONG a);\r
+\r
+#ifdef WIN32\r
+\r
+ #define Surface_TYPE SurfaceWin\r
+ #define Thread_TYPE ThreadWin\r
+ #define ThreadID_TYPE unsigned int\r
+\r
+ #define SNPRINTF _snprintf\r
+ #define VSNPRINTF _vsnprintf\r
+ #define STRCASECMP _stricmp\r
+ #define STRCASESTR StrStrI\r
+/* #define STRTOULL _strtoui64 */\r
+ #define STRTOUL strtoul\r
+ #define CLOSESOCKET closesocket\r
+\r
+\r
+#else\r
+\r
+ int max(int, int);\r
+ int min(UINT, int);\r
+/*#ifdef _MIPS_ARCH\r
+ #define Surface_TYPE SurfaceDirectFB\r
+#else\r
+ #define Surface_TYPE SurfaceMVP\r
+#endif*/\r
+#ifdef __ANDROID__\r
+ #define Thread_TYPE ThreadPAndroid\r
+\r
+#else\r
+ #define Thread_TYPE ThreadP\r
+\r
+#endif\r
+ #include <pthread.h>\r
+ #define ThreadID_TYPE pthread_t\r
+\r
+ #define SNPRINTF snprintf\r
+ #define VSNPRINTF vsnprintf\r
+ #define STRCASECMP strcasecmp\r
+ #define STRCASESTR strcasestr\r
+ #define STRTOUL strtoul\r
+ #define CLOSESOCKET close\r
+\r
+// add here defines for plattform specific objects\r
+#ifdef VOMP_PLATTFORM_RASPBERRY\r
+ #define Remote_TYPE RemoteLinux // Generic Remote under Linux (Konsole!, not X) will support in the end:\r
+ #define RemoteStartDev ""//No devices passed\r
+\r
+ // Keyboard\r
+ // remotes under /dev/event\r
+ // HDMI CEC\r
+ //lirc?\r
+ #define Mtd_TYPE MtdRaspberry //this is device dependent\r
+ #define Led_TYPE LedRaspberry //this is device dependent\r
+ #define Osd_TYPE OsdOpenGL // This OpenGL ES 2.0, in the moment only for raspberry, but might be splitted for other devices\r
+ #define OsdStartDev ""\r
+ #define Audio_TYPE AudioVPE // This is Audio based on VPE (Vomp Presentation Engine) should support OpenMax and Alsa with ffmpeg in the end\r
+ #define Video_TYPE VideoVPEOGL // This is Video based on VPE (Vomp Presentation Engine) should support OpenMax and ffmpeg and opengl in the end\r
+\r
+#endif\r
+#ifdef VOMP_PLATTFORM_MVP\r
+ #define Remote_TYPE RemoteMVP\r
+ #define RemoteStartDev "/dev/rawir"\r
+ #define Mtd_TYPE MtdMVP\r
+ #define Led_TYPE LedMVP\r
+ #define Osd_TYPE OsdMVP\r
+ #define OsdStartDev "/dev/stbgfx"\r
+ #define Audio_TYPE AudioMVP\r
+ #define Video_TYPE VideoMVP\r
+#endif\r
+\r
+#ifdef VOMP_PLATTFORM_NMT // This was the attempt to port vomp to nmt, it failed but maybe the code is useful at some time\r
+ #define Remote_TYPE RemoteLirc\r
+ #define RemoteStartDev "/dev/lircd"\r
+ #define Mtd_TYPE MtdNMT\r
+ #define Led_TYPE LedMVP\r
+ #define Osd_TYPE OsdDirectFB\r
+ #define OsdStartDev ""\r
+ #define Audio_TYPE AudioNMT\r
+ #define Video_TYPE VideoNMT\r
+\r
+#endif\r
+\r
+#endif\r
+\r
+/*\r
+typedef struct\r
+{\r
+ UINT id; // Used for working out what has changed at the end\r
+ char *title; // Name of the option\r
+ char *configSection; // Which section of the config file\r
+ char *configParam; // Parameter name in the config file\r
+ UINT optionType; // 1 for text, 2 for int\r
+ UINT optionCount; // How many choices?\r
+ UINT defaultOption; // Serial of the default choice (base 0), or actual option in int mode\r
+ int startInt; // Starting int for int mode\r
+ const char * const * options; // Text for the options (null for int mode)\r
+} OPTIONDATA;\r
+*/\r
+\r
+#endif\r
-/*
- Copyright 2005-2008 Mark Calderbank
- Copyright 2007 Marten Richter (AC3 support)
-
- 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 "demuxer.h"
-
-#include "callback.h"
-#include "dvbsubtitles.h"
-#include "log.h"
-
-#include <cstdlib>
-
-#include <math.h>
-
-#define DEMUXER_SEQ_HEAD 0x000001B3
-#define DEMUXER_PIC_HEAD 0x00000101
-
-#define DEMUXER_H264_ACCESS_UNIT 0x00000109
-#define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107
-
-
-#define SEEK_THRESHOLD 150000 // About 1.5 seconds
-
-// Statics
-const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };
-Demuxer* Demuxer::instance = NULL;
-
-class NALUUnit {
-public:
- NALUUnit(const UCHAR* buf,UINT length_buf);
- ~NALUUnit();
-
-inline UINT getBits(UINT num_bits);
- UINT getUe();
- int getSe();
- bool isEonalu() {return eonalu;};
-
-protected:
- UCHAR* nalu_buf;
- UINT nalu_length;
- UINT pos;
- UCHAR bit_pos;
- UCHAR working_byte;
- UINT last_bytes;
- bool eonalu;
-};
-
-NALUUnit::NALUUnit(const UCHAR *buf, UINT length_buf)
-{
- nalu_length=0;
- nalu_buf=NULL;
- pos=0;
- bit_pos=0;
- working_byte=0;
- last_bytes=0;
- eonalu=false;
-
- UINT nalu_start=0;
- UINT nalu_end=0;
- UINT pattern =(((UINT)buf[ 0] << 16) |
- ((UINT)buf[1] << 8) |
- (UINT)buf[2] );
- nalu_start=3;
- while (pattern != 0x000001)
- {
- if (++nalu_start >= length_buf) return;
- pattern = ((pattern << 8) | buf[nalu_start])&0x00FFFFFF;
- }
- nalu_end=nalu_start+1;
- pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;
-
- while (pattern != 0x000001 && pattern != 0x000000)
- {
- if (++nalu_end >= length_buf) { nalu_end+=3;break;};
- pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;
- }
- nalu_end-=3;
- nalu_end=min(length_buf-1,nalu_end);
- nalu_length=nalu_end-nalu_start;
- nalu_buf=(UCHAR*)malloc(nalu_length);
- memcpy(nalu_buf,buf+nalu_start,nalu_length);
- pos=1;
-}
-
-NALUUnit::~NALUUnit()
-{
- if (nalu_buf) free(nalu_buf);
-}
-
-inline UINT NALUUnit::getBits(UINT num_bits)
-{
- if (num_bits==0) return 0; //???
- UINT remain_bits=num_bits;
- UINT work=0;
- //May be slow, but should work!
- while (remain_bits>0) {
- if (bit_pos==0) {
- if (pos<nalu_length)
- {
- last_bytes=(last_bytes<<8) & nalu_buf[pos];
- if ((last_bytes & 0x00FFFFFF) == 0x000003) pos++; //emulation prevention byte
- if (pos<nalu_length)
- {
- working_byte=nalu_buf[pos];
- pos++;
- }
- else
- {
- working_byte=0;
- eonalu=true;
- }
- }
- else
- {
- working_byte=0;
- eonalu=true;
- }
-
- }
- UINT fetch_bits=min(remain_bits,8-bit_pos);
- work=work <<fetch_bits;
- //work|=((working_byte>>bit_pos) & (0xFF>>(8-fetch_bits)));
- work|=(working_byte &(0xFF>>(bit_pos)))>>(8-fetch_bits-bit_pos);
- remain_bits-=fetch_bits;
- bit_pos=(bit_pos+fetch_bits)%8;
- }
- return work;
-}
-
-UINT NALUUnit::getUe()
-{
- int leadbits=-1;
- bool bit;
- for( bit = 0; !bit && !eonalu; leadbits++ )
- bit = getBits(1);
- if (eonalu) return true;
- return ((1 << leadbits)-1)+getBits(leadbits);
-}
-
-int NALUUnit::getSe()
-{
- UINT input=getUe();
- if (input==0) return 0;
- int output=((input+1)>>1);
- if (input & 0x1) output*=-1;
- return output;
-}
-
-
-
-static const int PESPacket_initial_size = 2000;
-
-// PESPacket methods
-PESPacket::PESPacket()
-{
- data_size = PESPacket_initial_size;
- data = (UCHAR*)malloc(data_size);
- data[0] = 0x00;
- data[1] = 0x00;
- data[2] = 0x01;
- init(0);
-}
-
-PESPacket::PESPacket(const PESPacket& packet)
-{
- copyFrom(packet);
-}
-
-PESPacket& PESPacket::operator=(const PESPacket& packet)
-{
- if (this != &packet)
- {
- if (data) free(data);
- copyFrom(packet);
- }
- return *this;
-}
-
-PESPacket::~PESPacket()
-{
- if (data) free(data);
-}
-
-void PESPacket::copyFrom(const PESPacket& packet)
-{
- length = packet.length;
- size = packet.size;
- packetType = packet.packetType;
- substream = packet.substream;
- seq_header = packet.seq_header;
- data_size = size;
- data = (UCHAR*)malloc(data_size);
- memcpy(data, packet.data, data_size);
-}
-
-void PESPacket::init(UCHAR type, UCHAR sub)
-{
- length = 0;
- size = 6;
- data[4] = data[5] = 0;
- data[3] = type;
- packetType = type;
- substream = sub;
- seq_header = 1; // Unknown seq_header status
-}
-
-void PESPacket::truncate()
-{
- init(packetType,substream);
-}
-
-int PESPacket::write(const UCHAR *buf, int len)
-{
- if (size + len > 0x10000) return 0;
- if (size + len > data_size)
- { // Reallocate
- UINT new_data_size = max(data_size + data_size / 2, data_size + len);
- if (new_data_size > 0x10000) new_data_size = 0x10000;
- data_size = new_data_size;
- data = (UCHAR*)realloc(data, data_size);
- }
- memcpy(data + size, buf, len);
- length += len;
- size += len;
- data[4] = (length >> 8);
- data[5] = (length & 0xFF);
- // We have added data - reset seq_header indicator if necessary
- if (seq_header == 0) seq_header = 1; // Reset to 'unknown'
- return 1;
-}
-
-ULLONG PESPacket::getPTS() const
-{
- if ( ( (packetType >= Demuxer::PESTYPE_AUD0 &&
- packetType <= Demuxer::PESTYPE_AUDMAX)
- ||
- (packetType >= Demuxer::PESTYPE_VID0 &&
- packetType <= Demuxer::PESTYPE_VIDMAX)
- ||
- packetType == Demuxer::PESTYPE_PRIVATE_1
- )
- && size >= 14 && data[7] & 0x80)
- {
- return ( (ULLONG)(data[ 9] & 0x0E) << 29) |
- ( (ULLONG)(data[10]) << 22 ) |
- ( (ULLONG)(data[11] & 0xFE) << 14 ) |
- ( (ULLONG)(data[12]) << 7 ) |
- ( (ULLONG)(data[13] & 0xFE) >> 1 );
- }
- else return PTS_INVALID;
-}
-
-UCHAR PESPacket::operator[] (UINT index) const
-{
- if (index >= size)
- return 0;
- else
- return data[index];
-}
-
-UINT PESPacket::findPictureHeader(bool h264) const
-{
- if (size < 12) return 0;
- UINT pattern = ( ((UINT)data[ 8] << 24) |
- ((UINT)data[ 9] << 16) |
- ((UINT)data[10] << 8) |
- (UINT)data[11] );
- UINT pos = 11;
- if (h264) {
-
- while (pattern != DEMUXER_H264_ACCESS_UNIT)
- {
- if (++pos >= size) return 0;
- pattern = (pattern << 8) | data[pos];
- }
- return pos-3;
- } else {
- while (pattern != DEMUXER_PIC_HEAD)
- {
- if (++pos >= size) return 0;
- pattern = (pattern << 8) | data[pos];
- }
- return pos-3;
- }
-}
-
-UINT PESPacket::countPictureHeaders(bool h264) const
-{
- if (size < 12) return 0;
- UINT pattern = ( ((UINT)data[ 8] << 24) |
- ((UINT)data[ 9] << 16) |
- ((UINT)data[10] << 8) |
- (UINT)data[11] );
- UINT pos = 11;
- UINT count=0;
- if (h264) {
-
- while (pos<size)
- {
- pos++;
- pattern = (pattern << 8) | data[pos];
- if (pattern==DEMUXER_H264_ACCESS_UNIT) count++;
- }
- return count;
- } else {
- while (pos<size)
- {
- pos++;
- pattern = (pattern << 8) | data[pos];
- if (pattern==DEMUXER_PIC_HEAD) count++;
- }
- return count;
- }
-}
-
-UINT PESPacket::findSeqHeader(bool h264) const
-{
- if (seq_header != 1) return seq_header;
- if (size < 12) return 0;
- UINT pattern = ( ((UINT)data[ 8] << 24) |
- ((UINT)data[ 9] << 16) |
- ((UINT)data[10] << 8) |
- (UINT)data[11] );
- UINT pos = 11;
- if (h264) {
- while ((pattern & 0xFFFFFF1F) != DEMUXER_H264_SEQ_PARAMETER_SET)
- {
- if (++pos >= size)
- {
- seq_header = 0;
- return 0;
- }
- pattern = (pattern << 8) | data[pos];
- }
- seq_header = pos - 3;
- }
- else
- {
- while (pattern != DEMUXER_SEQ_HEAD)
- {
- if (++pos >= size)
- {
- seq_header = 0;
- return 0;
- }
- pattern = (pattern << 8) | data[pos];
- }
- seq_header = pos - 3;
- }
- return seq_header;
-}
-
-// Demuxer methods
-Demuxer::Demuxer()
-{
- if (instance) return;
- instance = this;
- initted = false;
- callback = NULL;
- arcnt = 0;
- vid_seeking = aud_seeking = false;
- video_pts = audio_pts = 0;
- ispre_1_3_19 = false;
- packetnum=0;
- h264 = false;
- fps = 25.0;
-}
-
-Demuxer::~Demuxer()
-{
- shutdown();
- instance = NULL;
-}
-
-Demuxer* Demuxer::getInstance()
-{
- return instance;
-}
-
-int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, DrainTarget* teletext,
- ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT,double infps, DVBSubtitles* tsubtitles)
-{
- if (!initted)
- {
- if ( !videostream.init(video, demuxMemoryV) ||
- !audiostream.init(audio, demuxMemoryA) ||
- !teletextstream.init(teletext, demuxMemoryT))
- {
- Log::getInstance()->log("Demuxer", Log::CRIT,
- "Failed to initialize demuxer");
- shutdown();
- return 0;
- }
- }
- if (teletext) {
- isteletextdecoded = true;
- } else {
- isteletextdecoded = false;
- }
- fps=infps;
- reset();
- initted = true;
- subtitles = tsubtitles;
- callback = tcallback;
- return 1;
-}
-
-void Demuxer::reset()
-{
- Log::getInstance()->log("Demuxer", Log::DEBUG, "Reset called");
- flush();
- video_current = audio_current = teletext_current = subtitle_current = -1;
- horizontal_size = vertical_size = 0;
- aspect_ratio = (enum AspectRatio) 0;
- frame_rate = bit_rate = 0;
- ispre_1_3_19 = false;
- h264 = false;
- packetnum=0;
-
- for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++)
- {
- avail_mpaudchan[i] = false;
- }
- for (int i = 0; i <= (PESTYPE_SUBSTREAM_AC3MAX - PESTYPE_SUBSTREAM_AC30); i++)
- {
- avail_ac3audchan[i] = false;
- }
- for (int i = 0; i <= (PESTYPE_SUBSTREAM_DVBSUBTITLEMAX - PESTYPE_SUBSTREAM_DVBSUBTITLE0); i++)
- {
- avail_dvbsubtitlechan[i] = false;
- }
-}
-
-int Demuxer::shutdown()
-{
- videostream.shutdown();
- audiostream.shutdown();
- teletextstream.shutdown();
- initted = false;
- return 1;
-}
-
-void Demuxer::flush()
-{
- Log::getInstance()->log("Demuxer", Log::DEBUG, "Flush called");
-
- videostream.flush();
- audiostream.flush();
- teletextstream.flush();
-}
-
-void Demuxer::flushAudio()
-{
- audiostream.flush();
-}
-
-void Demuxer::seek()
-{
- vid_seeking = aud_seeking = true;
- video_pts = audio_pts = teletext_pts = 0;
-}
-
-void Demuxer::setAudioStream(int id)
-{
- audio_current = id;
-}
-
-void Demuxer::setVideoStream(int id)
-{
- video_current = id;
-}
-
-void Demuxer::setTeletextStream(int id)
-{
- teletext_current = id;
-}
-
-void Demuxer::setDVBSubtitleStream(int id)
-{
- subtitle_current = id;
-}
-
-void Demuxer::setAspectRatio(enum AspectRatio ar)
-{
- if (aspect_ratio != ar)
- {
- Log::getInstance()->log("Demux", Log::DEBUG,
- "Aspect ratio difference signalled");
- if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal
- {
- arcnt = 0;
- aspect_ratio = ar;
- if (callback) callback->call(this);
- }
- }
- else
- arcnt = 0;
-}
-
-bool Demuxer::writeAudio()
-{
- return audiostream.drain();
-}
-
-bool Demuxer::writeVideo()
-{
- return videostream.drain();
-}
-
-bool Demuxer::writeTeletext()
-{
- return teletextstream.drain();
-}
-
-bool Demuxer::submitPacket(PESPacket& packet)
-{
- UINT sent = 0;
- UCHAR packet_type = packet.getPacketType();
- const UCHAR* packetdata = packet.getData();
- if (packet_type >= PESTYPE_VID0 && packet_type <= PESTYPE_VIDMAX)
- {
- if (video_current == -1) video_current = packet_type;
- if (video_current == packet_type && !vid_seeking)
- {
- sent = videostream.put(&packetdata[0], packet.getSize(), h264?MPTYPE_VIDEO_H264:MPTYPE_VIDEO_MPEG2,packetnum);
- if (sent) packetnum++;
- }
- else
- sent = packet.getSize();
- }
- else if (packet_type >= PESTYPE_AUD0 && packet_type <= PESTYPE_AUDMAX)
- {
- if (audio_current == -1) audio_current = packet_type;
- avail_mpaudchan[packet_type - PESTYPE_AUD0] = true;
- if (audio_current == packet_type && !aud_seeking)
- {
- sent = audiostream.put(&packetdata[0], packet.getSize(), MPTYPE_MPEG_AUDIO,packetnum);
- if (sent) packetnum++;
- }
- else
- sent = packet.getSize();
- }
- else if (packet_type == PESTYPE_PRIVATE_1 &&
- packet.getSubstream() >= PESTYPE_SUBSTREAM_AC30 &&
- packet.getSubstream() <= PESTYPE_SUBSTREAM_AC3MAX)
- {
- avail_ac3audchan[packet.getSubstream() - PESTYPE_SUBSTREAM_AC30] = true;
- if (packet.getSubstream() == audio_current)
- {
- sent = audiostream.put(&packetdata[0], packet.getSize(), (ispre_1_3_19)? MPTYPE_AC3_PRE13 : MPTYPE_AC3,packetnum);
- if (sent) packetnum++;
- }
- else
- {
- sent = packet.getSize();
- }
- }
- else if (packet_type == PESTYPE_PRIVATE_1 &&
- packet.getSubstream() >= PESTYPE_SUBSTREAM_DVBSUBTITLE0 &&
- packet.getSubstream() <= PESTYPE_SUBSTREAM_DVBSUBTITLEMAX)
- {
- avail_dvbsubtitlechan[packet.getSubstream()-PESTYPE_SUBSTREAM_DVBSUBTITLE0]=true;
- if (subtitle_current == -1) subtitle_current = packet.getSubstream();
- if (subtitles && packet.getSubstream()==subtitle_current)
- {
- subtitles->put(packet);
- }
- sent = packet.getSize();
- }
- else if (isteletextdecoded && packet_type == PESTYPE_PRIVATE_1 &&
- packet.getSubstream() >= PESTYPE_SUBSTREAM_TELETEXT0 &&
- packet.getSubstream() <= PESTYPE_SUBSTREAM_TELETEXTMAX)
- {
-
- if (teletext_current == -1) teletext_current = packet.getSubstream();
- if (teletext_current == packet.getSubstream() )
- {
- sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT,packetnum);
- }
- else
- {
- sent = packet.getSize();
- }
- }
- else
- {
- sent = packet.getSize();
- }
-
- if (sent < packet.getSize()) // Stream is full.
- return false;
- else
- return true;
-}
-
-void Demuxer::parsePacketDetails(PESPacket& packet)
-{
- if (packet.getPacketType() >= PESTYPE_AUD0 &&
- packet.getPacketType() <= PESTYPE_AUDMAX)
- {
- // Extract audio PTS if it exists
- if (packet.hasPTS())
- {
- audio_pts = packet.getPTS();
- // We continue to seek on the audio if the video PTS that we
- // are trying to match is ahead of the audio PTS by at most
- // SEEK_THRESHOLD. We consider the possibility of PTS wrap.
- if (aud_seeking && !vid_seeking &&
- !( (video_pts_seek > audio_pts &&
- video_pts_seek - audio_pts < SEEK_THRESHOLD)
- ||
- (video_pts_seek < audio_pts &&
- video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))
- {
- aud_seeking = 0;
- Log::getInstance()->log("Demuxer", Log::DEBUG,
- "Leaving audio sync: Audio PTS = %llu", audio_pts);
- }
- }
- }
- else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream
- {
- //Inspired by vdr's device.c
- int payload_begin = packet[8]+9;
- unsigned char substream_id = packet[payload_begin];
- unsigned char substream_type = substream_id & 0xF0;
- unsigned char substream_index = substream_id & 0x1F;
-pre_1_3_19_Recording: //This is for old recordings stuff and live TV
- if (ispre_1_3_19)
- {
- substream_id = PESTYPE_PRIVATE_1;
- substream_type = 0x80;
- substream_index = 0;
- }
- switch (substream_type)
- {
- case 0x20://SPU
- case 0x30://SPU
- packet.setSubstream(substream_id);
- break;
- case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there?
- break;
- case 0x80: //ac3, currently only one ac3 track per recording supported
- packet.setSubstream(substream_type+substream_index);
-
- // Extract audio PTS if it exists
- if (packet.hasPTS())
- {
- audio_pts = packet.getPTS();
- // We continue to seek on the audio if the video PTS that we
- // are trying to match is ahead of the audio PTS by at most
- // SEEK_THRESHOLD. We consider the possibility of PTS wrap.
- if (aud_seeking && !vid_seeking &&
- !( (video_pts_seek > audio_pts &&
- video_pts_seek - audio_pts < SEEK_THRESHOLD)
- ||
- (video_pts_seek < audio_pts &&
- video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))
- {
- aud_seeking = 0;
- Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving audio sync: Audio PTS = %llu", audio_pts);
- }
- }
- break;
- case 0x10: //Teletext Is this correct?
- packet.setSubstream(substream_id);
- // Extract teletxt PTS if it exists
- if (packet.hasPTS())
- {
- teletext_pts = packet.getPTS();
- }
- break;
- default:
- if (!ispre_1_3_19)
- {
- ispre_1_3_19=true; //switching to compat mode and live tv mode
- goto pre_1_3_19_Recording;
- }
- else
- {
- packet.setSubstream(0);
- }
- break;
- }
- }
- else if (packet.getPacketType() >= PESTYPE_VID0 &&
- packet.getPacketType() <= PESTYPE_VIDMAX)
- {
- // Extract video PTS if it exists
- if (packet.hasPTS()) video_pts = packet.getPTS();
-
- // If there is a sequence header, extract information
- UINT pos = packet.findSeqHeader(h264);
- if (pos > 1)
- {
- if (!h264) {
- pos += 4;
- if (pos+6 >= packet.getSize()) return;
- horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4);
-
- vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2];
-
- setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4));
- frame_rate = packet[pos+3] & 0x0f;
- if (frame_rate >= 1 && frame_rate <= 8)
- frame_rate = FrameRates[frame_rate];
- else
- frame_rate = 0;
- bit_rate = ((int)packet[pos+4] << 10) |
- ((int)packet[pos+5] << 2) |
- ((int)packet[pos+6] >> 6);
- }
- else
- {
- /* Chris and Mark I know this is ugly, should we move this to a method of PESPacket or to NALUUnit what would be better?
- This looks so ugly since the header includes variable length parts and I have to parse through the whole header to get the wanted information*/
- NALUUnit nalu(packet.getData()+pos,packet.getSize()-pos);
- profile=nalu.getBits(8);
- nalu.getBits(8); //constraints
- nalu.getBits(8); //level_idc
- nalu.getUe(); //seq_parameter_set_id
- int chroma=1;
- if (profile==100 || profile==110 || profile==122 || profile==144)
- {
- chroma=nalu.getUe();
- if (chroma==3)
- {
- nalu.getBits(1);
- }
- nalu.getUe(); //bit depth lume
- nalu.getUe(); //bit depth chrome
- nalu.getBits(1);
- if (nalu.getBits(1))
- {
- for (int i=0;i<8;i++){
- if (nalu.getBits(1))
- {
- if (i<6)
- {
- UINT lastscale=8;
- UINT nextscale=8;
- for (int j=0;j<16;j++) {
- if (nextscale!=0) {
- UINT delta=nalu.getSe();
- nextscale=(lastscale+delta+256)%256;
- }
- lastscale=(nextscale==0)?lastscale:nextscale;
- }
- }
- else
- {
- UINT lastscale=8;
- UINT nextscale=8;
- for (int j=0;j<64;j++) {
- if (nextscale!=0) {
- UINT delta=nalu.getSe();
- nextscale=(lastscale+delta+256)%256;
- }
- lastscale=(nextscale==0)?lastscale:nextscale;
- }
- }
- }
- }
- }
- }
- int chromunitx=1;
- int chromunity=1;
- switch (chroma) {
- case 0:
- chromunitx=chromunity=1; break;
- case 1:
- chromunitx=chromunity=2; break;
- case 2:
- chromunitx=2;chromunity=1; break;
- case 3:
- chromunitx=chromunity=1; break;
- };
-
- nalu.getUe(); //log2framenum
- UINT temp=nalu.getUe();
- if (temp==0) //pict order
- nalu.getUe();
- else if (temp==1) {
- nalu.getBits(1);
- nalu.getSe();
- nalu.getSe();
- UINT temp2=nalu.getUe();
- for (int i=0;i<temp2;i++)
- nalu.getSe();
- }
- nalu.getUe(); //Num refframes
- nalu.getBits(1);
- horizontal_size=(nalu.getUe()+1)*16;
-
- vertical_size=(nalu.getUe()+1)*16;
- int interlaced=nalu.getBits(1);
- vertical_size*=(2-interlaced);
-
- if (!interlaced) nalu.getBits(1);
- nalu.getBits(1);
- if (nalu.getBits(1))
- {
- horizontal_size-=nalu.getUe()*chromunitx;
- horizontal_size-=nalu.getUe()*chromunitx;
- vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;
- vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;
- }
- if (nalu.getBits(1))
- {
- if (nalu.getBits(1))
- {
- UINT aspectratioidc=nalu.getBits(8);
- bool hasaspect=false;
- const float aspects[]={1., 1./1.,12./11.,10./11.,16./11.,40./33.,
- 24./11.,20./11.,32./11.,80./33.,18./11.,15./11.,64./33.,160./99.,4./3.,3./2.,2./1.};
-
- float aspectratio=((float) horizontal_size)/((float) vertical_size);
- if (aspectratioidc<=16)
- {
- hasaspect=true;
- aspectratio*=aspects[aspectratioidc];
-
- }
- else if (aspectratioidc==255)
- {
- int t_sar_width=nalu.getBits(16);
- int t_sar_height=nalu.getBits(16);
- if (t_sar_width!=0 && t_sar_height!=0)
- {
- hasaspect=true;
- aspectratio*=((float)t_sar_width)/((float)t_sar_height);
- }
- }
- if (hasaspect)
- {
- if (fabs(aspectratio-16./9.)<0.1) setAspectRatio(ASPECT_16_9);
- else if (fabs(aspectratio-4./3.)<0.1) setAspectRatio(ASPECT_4_3);
- }
- }
-
- }
-
- }
-
- if (vid_seeking)
- {
- vid_seeking = 0;
- video_pts_seek = video_pts;
- Log::getInstance()->log("Demuxer", Log::DEBUG,
- "Entering audio sync: Video PTS = %llu", video_pts);
- Log::getInstance()->log("Demuxer", Log::DEBUG,
- "Entering audio sync: Audio PTS = %llu", audio_pts);
- }
- return;
- }
- }
-}
-
-UINT Demuxer::stripAudio(UCHAR* buf, UINT len)
-{
- UINT read_pos = 0, write_pos = 0;
- UINT pattern, packet_length;
- if (len < 4) return 0;
- pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
- while (read_pos + 7 <= len)
- {
- pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];
- if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))
- read_pos++;
- else
- {
- packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;
- if (read_pos + packet_length > len)
- read_pos = len;
- else
- {
- if (read_pos != write_pos)
- memmove(buf+write_pos, buf+read_pos, packet_length);
- read_pos += packet_length;
- write_pos += packet_length;
- pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)
- | (buf[read_pos+2]);
- }
- }
- }
- return write_pos;
-}
-
-bool Demuxer::scanForVideo(UCHAR* buf, UINT len, bool &ish264)
-{
- UINT pos = 3;
- UINT pattern;
- ish264=false;
- if (len < 4) return false;
- pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
- while (pos < len)
- {
- pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++];
- if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX))
- return true;
- }
- return false;
-}
-
-bool* Demuxer::getmpAudioChannels()
-{
- return avail_mpaudchan;
-}
-
-bool* Demuxer::getac3AudioChannels()
-{
- return avail_ac3audchan;
-}
-
-bool* Demuxer::getSubtitleChannels()
-{
- return avail_dvbsubtitlechan;
-}
-
-int Demuxer::getselSubtitleChannel()
-{
- return subtitle_current;
-}
-
-int Demuxer::getselAudioChannel()
-{
- return audio_current;
-}
-
-
+/*\r
+ Copyright 2005-2008 Mark Calderbank\r
+ Copyright 2007 Marten Richter (AC3 support)\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software Foundation, Inc.,\r
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "demuxer.h"\r
+\r
+#include "callback.h"\r
+#include "dvbsubtitles.h"\r
+#include "log.h"\r
+\r
+#include <cstdlib>\r
+\r
+#include <math.h>\r
+\r
+#define DEMUXER_SEQ_HEAD 0x000001B3\r
+#define DEMUXER_PIC_HEAD 0x00000101\r
+\r
+#define DEMUXER_H264_ACCESS_UNIT 0x00000109\r
+#define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107\r
+\r
+\r
+#define SEEK_THRESHOLD 150000 // About 1.5 seconds\r
+\r
+// Statics\r
+const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };\r
+Demuxer* Demuxer::instance = NULL;\r
+\r
+class NALUUnit {\r
+public:\r
+ NALUUnit(const UCHAR* buf,UINT length_buf);\r
+ ~NALUUnit();\r
+\r
+inline UINT getBits(UINT num_bits);\r
+ UINT getUe();\r
+ int getSe();\r
+ bool isEonalu() {return eonalu;};\r
+\r
+protected:\r
+ UCHAR* nalu_buf;\r
+ UINT nalu_length;\r
+ UINT pos;\r
+ UCHAR bit_pos;\r
+ UCHAR working_byte;\r
+ UINT last_bytes;\r
+ bool eonalu;\r
+};\r
+\r
+NALUUnit::NALUUnit(const UCHAR *buf, UINT length_buf)\r
+{\r
+ nalu_length=0;\r
+ nalu_buf=NULL;\r
+ pos=0;\r
+ bit_pos=0;\r
+ working_byte=0;\r
+ last_bytes=0;\r
+ eonalu=false;\r
+\r
+ UINT nalu_start=0;\r
+ UINT nalu_end=0;\r
+ UINT pattern =(((UINT)buf[ 0] << 16) |\r
+ ((UINT)buf[1] << 8) |\r
+ (UINT)buf[2] );\r
+ nalu_start=3;\r
+ while (pattern != 0x000001)\r
+ {\r
+ if (++nalu_start >= length_buf) return;\r
+ pattern = ((pattern << 8) | buf[nalu_start])&0x00FFFFFF;\r
+ }\r
+ nalu_end=nalu_start+1;\r
+ pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;\r
+\r
+ while (pattern != 0x000001 && pattern != 0x000000)\r
+ {\r
+ if (++nalu_end >= length_buf) { nalu_end+=3;break;};\r
+ pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;\r
+ }\r
+ nalu_end-=3;\r
+ nalu_end=min(length_buf-1,nalu_end);\r
+ nalu_length=nalu_end-nalu_start;\r
+ nalu_buf=(UCHAR*)malloc(nalu_length);\r
+ memcpy(nalu_buf,buf+nalu_start,nalu_length);\r
+ pos=1;\r
+}\r
+\r
+NALUUnit::~NALUUnit()\r
+{\r
+ if (nalu_buf) free(nalu_buf);\r
+}\r
+\r
+inline UINT NALUUnit::getBits(UINT num_bits)\r
+{\r
+ if (num_bits==0) return 0; //???\r
+ UINT remain_bits=num_bits;\r
+ UINT work=0;\r
+ //May be slow, but should work!\r
+ while (remain_bits>0) {\r
+ if (bit_pos==0) {\r
+ if (pos<nalu_length)\r
+ {\r
+ last_bytes=(last_bytes<<8) & nalu_buf[pos];\r
+ if ((last_bytes & 0x00FFFFFF) == 0x000003) pos++; //emulation prevention byte\r
+ if (pos<nalu_length)\r
+ {\r
+ working_byte=nalu_buf[pos];\r
+ pos++;\r
+ } \r
+ else\r
+ {\r
+ working_byte=0;\r
+ eonalu=true;\r
+ }\r
+ } \r
+ else\r
+ {\r
+ working_byte=0;\r
+ eonalu=true;\r
+ }\r
+\r
+ }\r
+ UINT fetch_bits=min(remain_bits,8-bit_pos);\r
+ work=work <<fetch_bits;\r
+ //work|=((working_byte>>bit_pos) & (0xFF>>(8-fetch_bits)));\r
+ work|=(working_byte &(0xFF>>(bit_pos)))>>(8-fetch_bits-bit_pos);\r
+ remain_bits-=fetch_bits;\r
+ bit_pos=(bit_pos+fetch_bits)%8;\r
+ }\r
+ return work;\r
+}\r
+\r
+UINT NALUUnit::getUe()\r
+{\r
+ int leadbits=-1;\r
+ bool bit;\r
+ for( bit = 0; !bit && !eonalu; leadbits++ )\r
+ bit = getBits(1);\r
+ if (eonalu) return true;\r
+ return ((1 << leadbits)-1)+getBits(leadbits);\r
+}\r
+\r
+int NALUUnit::getSe()\r
+{\r
+ UINT input=getUe();\r
+ if (input==0) return 0;\r
+ int output=((input+1)>>1);\r
+ if (input & 0x1) output*=-1;\r
+ return output;\r
+}\r
+\r
+\r
+\r
+static const int PESPacket_initial_size = 2000;\r
+\r
+// PESPacket methods\r
+PESPacket::PESPacket()\r
+{\r
+ data_size = PESPacket_initial_size;\r
+ data = (UCHAR*)malloc(data_size);\r
+ data[0] = 0x00;\r
+ data[1] = 0x00;\r
+ data[2] = 0x01;\r
+ init(0);\r
+}\r
+\r
+PESPacket::PESPacket(const PESPacket& packet)\r
+{\r
+ copyFrom(packet);\r
+}\r
+\r
+PESPacket& PESPacket::operator=(const PESPacket& packet)\r
+{\r
+ if (this != &packet)\r
+ {\r
+ if (data) free(data);\r
+ copyFrom(packet);\r
+ }\r
+ return *this;\r
+}\r
+\r
+PESPacket::~PESPacket()\r
+{\r
+ if (data) free(data);\r
+}\r
+\r
+void PESPacket::copyFrom(const PESPacket& packet)\r
+{\r
+ length = packet.length;\r
+ size = packet.size;\r
+ packetType = packet.packetType;\r
+ substream = packet.substream;\r
+ seq_header = packet.seq_header;\r
+ data_size = size;\r
+ data = (UCHAR*)malloc(data_size);\r
+ memcpy(data, packet.data, data_size);\r
+}\r
+\r
+void PESPacket::init(UCHAR type, UCHAR sub)\r
+{\r
+ length = 0; \r
+ size = 6;\r
+ data[4] = data[5] = 0;\r
+ data[3] = type;\r
+ packetType = type;\r
+ substream = sub;\r
+ seq_header = 1; // Unknown seq_header status\r
+\r
+}\r
+\r
+void PESPacket::truncate()\r
+{\r
+ init(packetType,substream);\r
+}\r
+\r
+\r
+\r
+int PESPacket::write(const UCHAR *buf, int len)\r
+{\r
+\r
+\r
+ if (size + len > 0x10000) return 0;\r
+ if (size + len > data_size)\r
+ { // Reallocate\r
+ UINT new_data_size = max(data_size + data_size / 2, data_size + len);\r
+ if (new_data_size > 0x10000) new_data_size = 0x10000;\r
+ data_size = new_data_size;\r
+ data = (UCHAR*)realloc(data, data_size);\r
+ }\r
+ memcpy(data + size, buf, len);\r
+ length += len;\r
+ size += len;\r
+ data[4] = (length >> 8);\r
+ data[5] = (length & 0xFF);\r
+ // We have added data - reset seq_header indicator if necessary\r
+ if (seq_header == 0) seq_header = 1; // Reset to 'unknown'\r
+ return 1;\r
+}\r
+\r
+ULLONG PESPacket::getPTS() const\r
+{\r
+ if ( ( (packetType >= Demuxer::PESTYPE_AUD0 &&\r
+ packetType <= Demuxer::PESTYPE_AUDMAX)\r
+ ||\r
+ (packetType >= Demuxer::PESTYPE_VID0 &&\r
+ packetType <= Demuxer::PESTYPE_VIDMAX)\r
+ ||\r
+ packetType == Demuxer::PESTYPE_PRIVATE_1\r
+ )\r
+ && size >= 14 && data[7] & 0x80)\r
+ {\r
+ return ( (ULLONG)(data[ 9] & 0x0E) << 29) |\r
+ ( (ULLONG)(data[10]) << 22 ) |\r
+ ( (ULLONG)(data[11] & 0xFE) << 14 ) |\r
+ ( (ULLONG)(data[12]) << 7 ) |\r
+ ( (ULLONG)(data[13] & 0xFE) >> 1 );\r
+ }\r
+ else return PTS_INVALID;\r
+}\r
+\r
+UCHAR PESPacket::operator[] (UINT index) const\r
+{\r
+ if (index >= size)\r
+ return 0;\r
+ else\r
+ return data[index];\r
+}\r
+\r
+UINT PESPacket::findPictureHeader(bool h264) const\r
+{\r
+ if (size < 12) return 0;\r
+ UINT pattern = ( ((UINT)data[ 8] << 24) |\r
+ ((UINT)data[ 9] << 16) |\r
+ ((UINT)data[10] << 8) |\r
+ (UINT)data[11] );\r
+ UINT pos = 11;\r
+ if (h264) {\r
+ \r
+ while (pattern != DEMUXER_H264_ACCESS_UNIT)\r
+ {\r
+ if (++pos >= size) return 0;\r
+ pattern = (pattern << 8) | data[pos];\r
+ }\r
+ return pos-3;\r
+ } else {\r
+ while (pattern != DEMUXER_PIC_HEAD)\r
+ {\r
+ if (++pos >= size) return 0;\r
+ pattern = (pattern << 8) | data[pos];\r
+ }\r
+ return pos-3;\r
+ }\r
+}\r
+\r
+UINT PESPacket::countPictureHeaders(bool h264) const\r
+{\r
+ if (size < 12) return 0;\r
+ UINT pattern = ( ((UINT)data[ 8] << 24) |\r
+ ((UINT)data[ 9] << 16) |\r
+ ((UINT)data[10] << 8) |\r
+ (UINT)data[11] );\r
+ UINT pos = 11;\r
+ UINT count=0;\r
+ if (h264) {\r
+ \r
+ while (pos<size)\r
+ {\r
+ pos++;\r
+ pattern = (pattern << 8) | data[pos];\r
+ if (pattern==DEMUXER_H264_ACCESS_UNIT) count++;\r
+ }\r
+ return count;\r
+ } else {\r
+ while (pos<size)\r
+ {\r
+ pos++;\r
+ pattern = (pattern << 8) | data[pos];\r
+ if (pattern==DEMUXER_PIC_HEAD) count++;\r
+ }\r
+ return count;\r
+ }\r
+}\r
+\r
+UINT PESPacket::findSeqHeader(bool h264) const\r
+{\r
+ if (seq_header != 1) return seq_header;\r
+ if (size < 12) return 0;\r
+ UINT pattern = ( ((UINT)data[ 8] << 24) |\r
+ ((UINT)data[ 9] << 16) |\r
+ ((UINT)data[10] << 8) |\r
+ (UINT)data[11] );\r
+ UINT pos = 11;\r
+ if (h264) {\r
+ while ((pattern & 0xFFFFFF1F) != DEMUXER_H264_SEQ_PARAMETER_SET)\r
+ {\r
+ if (++pos >= size)\r
+ {\r
+ seq_header = 0;\r
+ return 0;\r
+ }\r
+ pattern = (pattern << 8) | data[pos];\r
+ }\r
+ seq_header = pos - 3;\r
+ } \r
+ else \r
+ {\r
+ while (pattern != DEMUXER_SEQ_HEAD)\r
+ {\r
+ if (++pos >= size)\r
+ {\r
+ seq_header = 0;\r
+ return 0;\r
+ }\r
+ pattern = (pattern << 8) | data[pos];\r
+ }\r
+ seq_header = pos - 3;\r
+ }\r
+ return seq_header;\r
+}\r
+\r
+// Demuxer methods\r
+Demuxer::Demuxer()\r
+{\r
+ if (instance) return;\r
+ instance = this;\r
+ initted = false;\r
+ callback = NULL;\r
+ arcnt = 0;\r
+ vid_seeking = aud_seeking = false;\r
+ video_pts = audio_pts = 0;\r
+ ispre_1_3_19 = false;\r
+ packetnum=0;\r
+ h264 = false;\r
+ fps = 25.0;\r
+}\r
+\r
+Demuxer::~Demuxer()\r
+{\r
+ shutdown();\r
+ instance = NULL;\r
+}\r
+\r
+Demuxer* Demuxer::getInstance()\r
+{\r
+ return instance;\r
+}\r
+\r
+int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, DrainTarget* teletext,\r
+ ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT,double infps, DVBSubtitles* tsubtitles)\r
+{\r
+ if (!initted)\r
+ {\r
+ if ( !videostream.init(video, demuxMemoryV) ||\r
+ !audiostream.init(audio, demuxMemoryA) ||\r
+ !teletextstream.init(teletext, demuxMemoryT))\r
+ {\r
+ Log::getInstance()->log("Demuxer", Log::CRIT,\r
+ "Failed to initialize demuxer");\r
+ shutdown();\r
+ return 0;\r
+ }\r
+ }\r
+ if (teletext) {\r
+ isteletextdecoded = true;\r
+ } else {\r
+ isteletextdecoded = false;\r
+ }\r
+ fps=infps;\r
+ reset();\r
+ initted = true;\r
+ subtitles = tsubtitles;\r
+ callback = tcallback;\r
+ return 1;\r
+}\r
+\r
+void Demuxer::reset()\r
+{\r
+ Log::getInstance()->log("Demuxer", Log::DEBUG, "Reset called");\r
+ flush();\r
+ video_current = audio_current = teletext_current = subtitle_current = -1;\r
+ horizontal_size = vertical_size = 0;\r
+ aspect_ratio = (enum AspectRatio) 0;\r
+ frame_rate = bit_rate = 0;\r
+ ispre_1_3_19 = false;\r
+ h264 = false;\r
+ packetnum=0;\r
+\r
+ for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++)\r
+ {\r
+ avail_mpaudchan[i] = false;\r
+ }\r
+ for (int i = 0; i <= (PESTYPE_SUBSTREAM_AC3MAX - PESTYPE_SUBSTREAM_AC30); i++)\r
+ {\r
+ avail_ac3audchan[i] = false;\r
+ }\r
+ for (int i = 0; i <= (PESTYPE_SUBSTREAM_DVBSUBTITLEMAX - PESTYPE_SUBSTREAM_DVBSUBTITLE0); i++)\r
+ {\r
+ avail_dvbsubtitlechan[i] = false;\r
+ }\r
+}\r
+\r
+int Demuxer::shutdown()\r
+{\r
+ videostream.shutdown();\r
+ audiostream.shutdown();\r
+ teletextstream.shutdown();\r
+ initted = false;\r
+ return 1;\r
+}\r
+\r
+void Demuxer::flush()\r
+{\r
+ Log::getInstance()->log("Demuxer", Log::DEBUG, "Flush called");\r
+\r
+ videostream.flush();\r
+ audiostream.flush();\r
+ teletextstream.flush();\r
+}\r
+\r
+void Demuxer::flushAudio()\r
+{\r
+ audiostream.flush();\r
+}\r
+\r
+void Demuxer::seek()\r
+{\r
+ vid_seeking = aud_seeking = true;\r
+ video_pts = audio_pts = teletext_pts = 0;\r
+}\r
+\r
+void Demuxer::setAudioStream(int id)\r
+{\r
+ audio_current = id;\r
+}\r
+\r
+void Demuxer::setVideoStream(int id)\r
+{\r
+ video_current = id;\r
+}\r
+\r
+void Demuxer::setTeletextStream(int id)\r
+{\r
+ teletext_current = id;\r
+}\r
+\r
+void Demuxer::setDVBSubtitleStream(int id)\r
+{\r
+ subtitle_current = id;\r
+}\r
+\r
+void Demuxer::setAspectRatio(enum AspectRatio ar)\r
+{\r
+ if (aspect_ratio != ar)\r
+ {\r
+ Log::getInstance()->log("Demux", Log::DEBUG,\r
+ "Aspect ratio difference signalled");\r
+ if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal\r
+ {\r
+ arcnt = 0;\r
+ aspect_ratio = ar;\r
+ if (callback) callback->call(this);\r
+ }\r
+ }\r
+ else\r
+ arcnt = 0;\r
+}\r
+\r
+bool Demuxer::writeAudio()\r
+{\r
+ return audiostream.drain();\r
+}\r
+\r
+bool Demuxer::writeVideo()\r
+{\r
+ return videostream.drain();\r
+}\r
+\r
+bool Demuxer::writeTeletext()\r
+{\r
+ return teletextstream.drain();\r
+}\r
+\r
+bool Demuxer::submitPacket(PESPacket& packet)\r
+{\r
+ UINT sent = 0;\r
+ UCHAR packet_type = packet.getPacketType();\r
+ const UCHAR* packetdata = packet.getData();\r
+ if (packet_type >= PESTYPE_VID0 && packet_type <= PESTYPE_VIDMAX)\r
+ {\r
+ if (video_current == -1) video_current = packet_type;\r
+ if (video_current == packet_type && !vid_seeking)\r
+ {\r
+ sent = videostream.put(&packetdata[0], packet.getSize(), h264?MPTYPE_VIDEO_H264:MPTYPE_VIDEO_MPEG2,packetnum);\r
+ if (sent) packetnum++;\r
+ }\r
+ else\r
+ sent = packet.getSize();\r
+ }\r
+ else if (packet_type >= PESTYPE_AUD0 && packet_type <= PESTYPE_AUDMAX)\r
+ {\r
+\r
+ if (audio_current == -1) audio_current = packet_type;\r
+ avail_mpaudchan[packet_type - PESTYPE_AUD0] = true;\r
+ if (audio_current == packet_type && !aud_seeking)\r
+ {\r
+ sent = audiostream.put(&packetdata[0], packet.getSize(), MPTYPE_MPEG_AUDIO,packetnum);\r
+ if (sent) packetnum++;\r
+ }\r
+ else\r
+ sent = packet.getSize();\r
+ }\r
+ else if (packet_type == PESTYPE_PRIVATE_1 &&\r
+ packet.getSubstream() >= PESTYPE_SUBSTREAM_AC30 &&\r
+ packet.getSubstream() <= PESTYPE_SUBSTREAM_AC3MAX)\r
+ {\r
+ avail_ac3audchan[packet.getSubstream() - PESTYPE_SUBSTREAM_AC30] = true;\r
+ if (packet.getSubstream() == audio_current)\r
+ {\r
+ sent = audiostream.put(&packetdata[0], packet.getSize(), (ispre_1_3_19)? MPTYPE_AC3_PRE13 : MPTYPE_AC3,packetnum);\r
+ if (sent) packetnum++;\r
+ }\r
+ else\r
+ {\r
+ sent = packet.getSize();\r
+ }\r
+ }\r
+ else if (packet_type == PESTYPE_PRIVATE_1 &&\r
+ packet.getSubstream() >= PESTYPE_SUBSTREAM_DVBSUBTITLE0 &&\r
+ packet.getSubstream() <= PESTYPE_SUBSTREAM_DVBSUBTITLEMAX)\r
+ {\r
+ avail_dvbsubtitlechan[packet.getSubstream()-PESTYPE_SUBSTREAM_DVBSUBTITLE0]=true;\r
+ if (subtitle_current == -1) subtitle_current = packet.getSubstream();\r
+ if (subtitles && packet.getSubstream()==subtitle_current)\r
+ {\r
+ subtitles->put(packet);\r
+ }\r
+ sent = packet.getSize();\r
+ }\r
+ else if (isteletextdecoded && packet_type == PESTYPE_PRIVATE_1 &&\r
+ packet.getSubstream() >= PESTYPE_SUBSTREAM_TELETEXT0 &&\r
+ packet.getSubstream() <= PESTYPE_SUBSTREAM_TELETEXTMAX)\r
+ {\r
+\r
+ if (teletext_current == -1) teletext_current = packet.getSubstream();\r
+ if (teletext_current == packet.getSubstream())\r
+ {\r
+ sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT,packetnum);\r
+ }\r
+ else \r
+ {\r
+ sent = packet.getSize();\r
+ }\r
+ }\r
+ else\r
+ {\r
+ sent = packet.getSize();\r
+ }\r
+\r
+ if (sent < packet.getSize()) // Stream is full.\r
+ return false;\r
+ else\r
+ return true;\r
+}\r
+\r
+void Demuxer::parsePacketDetails(PESPacket& packet)\r
+{\r
+ if (packet.getPacketType() >= PESTYPE_AUD0 &&\r
+ packet.getPacketType() <= PESTYPE_AUDMAX)\r
+ {\r
+ // Extract audio PTS if it exists\r
+ if (packet.hasPTS())\r
+ {\r
+ audio_pts = packet.getPTS();\r
+ // We continue to seek on the audio if the video PTS that we\r
+ // are trying to match is ahead of the audio PTS by at most\r
+ // SEEK_THRESHOLD. We consider the possibility of PTS wrap.\r
+ if (aud_seeking && !vid_seeking &&\r
+ !( (video_pts_seek > audio_pts &&\r
+ video_pts_seek - audio_pts < SEEK_THRESHOLD)\r
+ ||\r
+ (video_pts_seek < audio_pts &&\r
+ video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))\r
+ {\r
+ aud_seeking = 0;\r
+ Log::getInstance()->log("Demuxer", Log::DEBUG,\r
+ "Leaving audio sync: Audio PTS = %llu", audio_pts);\r
+ }\r
+ }\r
+ }\r
+ else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream\r
+ {\r
+ //Inspired by vdr's device.c\r
+ int payload_begin = packet[8]+9;\r
+ unsigned char substream_id = packet[payload_begin];\r
+ unsigned char substream_type = substream_id & 0xF0;\r
+ unsigned char substream_index = substream_id & 0x1F;\r
+pre_1_3_19_Recording: //This is for old recordings stuff and live TV\r
+ if (ispre_1_3_19)\r
+ {\r
+ substream_id = PESTYPE_PRIVATE_1;\r
+ substream_type = 0x80;\r
+ substream_index = 0;\r
+ }\r
+ switch (substream_type)\r
+ {\r
+ case 0x20://SPU\r
+ case 0x30://SPU\r
+ packet.setSubstream(substream_id);\r
+ break;\r
+ case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there?\r
+ break;\r
+ case 0x80: //ac3, currently only one ac3 track per recording supported\r
+ packet.setSubstream(substream_type+substream_index);\r
+\r
+ // Extract audio PTS if it exists\r
+ if (packet.hasPTS())\r
+ {\r
+ audio_pts = packet.getPTS();\r
+ // We continue to seek on the audio if the video PTS that we\r
+ // are trying to match is ahead of the audio PTS by at most\r
+ // SEEK_THRESHOLD. We consider the possibility of PTS wrap.\r
+ if (aud_seeking && !vid_seeking &&\r
+ !( (video_pts_seek > audio_pts &&\r
+ video_pts_seek - audio_pts < SEEK_THRESHOLD)\r
+ ||\r
+ (video_pts_seek < audio_pts &&\r
+ video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))\r
+ {\r
+ aud_seeking = 0;\r
+ Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving audio sync: Audio PTS = %llu", audio_pts);\r
+ }\r
+ }\r
+ break;\r
+ case 0x10: //Teletext Is this correct?\r
+ packet.setSubstream(substream_id);\r
+ // Extract teletxt PTS if it exists\r
+ if (packet.hasPTS())\r
+ {\r
+ teletext_pts = packet.getPTS();\r
+ }\r
+ break;\r
+ default:\r
+ if (!ispre_1_3_19)\r
+ {\r
+ ispre_1_3_19=true; //switching to compat mode and live tv mode\r
+ goto pre_1_3_19_Recording;\r
+ }\r
+ else\r
+ {\r
+ packet.setSubstream(0);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ else if (packet.getPacketType() >= PESTYPE_VID0 &&\r
+ packet.getPacketType() <= PESTYPE_VIDMAX)\r
+ {\r
+ // Extract video PTS if it exists\r
+ if (packet.hasPTS()) video_pts = packet.getPTS();\r
+\r
+ // If there is a sequence header, extract information\r
+ UINT pos = packet.findSeqHeader(h264);\r
+ if (pos > 1)\r
+ {\r
+ if (!h264) {\r
+ pos += 4;\r
+ if (pos+6 >= packet.getSize()) return;\r
+ horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4);\r
+ \r
+ vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2];\r
+\r
+ setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4));\r
+ frame_rate = packet[pos+3] & 0x0f;\r
+ if (frame_rate >= 1 && frame_rate <= 8)\r
+ frame_rate = FrameRates[frame_rate];\r
+ else\r
+ frame_rate = 0;\r
+ bit_rate = ((int)packet[pos+4] << 10) |\r
+ ((int)packet[pos+5] << 2) |\r
+ ((int)packet[pos+6] >> 6);\r
+ } \r
+ else\r
+ {\r
+ /* Chris and Mark I know this is ugly, should we move this to a method of PESPacket or to NALUUnit what would be better?\r
+ This looks so ugly since the header includes variable length parts and I have to parse through the whole header to get the wanted information*/\r
+ NALUUnit nalu(packet.getData()+pos,packet.getSize()-pos);\r
+ profile=nalu.getBits(8);\r
+ nalu.getBits(8); //constraints\r
+ nalu.getBits(8); //level_idc\r
+ nalu.getUe(); //seq_parameter_set_id\r
+ int chroma=1;\r
+ if (profile==100 || profile==110 || profile==122 || profile==144)\r
+ {\r
+ chroma=nalu.getUe();\r
+ if (chroma==3)\r
+ {\r
+ nalu.getBits(1);\r
+ }\r
+ nalu.getUe(); //bit depth lume\r
+ nalu.getUe(); //bit depth chrome\r
+ nalu.getBits(1);\r
+ if (nalu.getBits(1))\r
+ {\r
+ for (int i=0;i<8;i++){\r
+ if (nalu.getBits(1))\r
+ {\r
+ if (i<6)\r
+ {\r
+ UINT lastscale=8;\r
+ UINT nextscale=8;\r
+ for (int j=0;j<16;j++) {\r
+ if (nextscale!=0) {\r
+ UINT delta=nalu.getSe();\r
+ nextscale=(lastscale+delta+256)%256;\r
+ }\r
+ lastscale=(nextscale==0)?lastscale:nextscale;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ UINT lastscale=8;\r
+ UINT nextscale=8;\r
+ for (int j=0;j<64;j++) {\r
+ if (nextscale!=0) {\r
+ UINT delta=nalu.getSe();\r
+ nextscale=(lastscale+delta+256)%256;\r
+ }\r
+ lastscale=(nextscale==0)?lastscale:nextscale;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ int chromunitx=1;\r
+ int chromunity=1;\r
+ switch (chroma) {\r
+ case 0:\r
+ chromunitx=chromunity=1; break;\r
+ case 1:\r
+ chromunitx=chromunity=2; break;\r
+ case 2:\r
+ chromunitx=2;chromunity=1; break;\r
+ case 3:\r
+ chromunitx=chromunity=1; break;\r
+ };\r
+\r
+ nalu.getUe(); //log2framenum\r
+ UINT temp=nalu.getUe();\r
+ if (temp==0) //pict order\r
+ nalu.getUe();\r
+ else if (temp==1) {\r
+ nalu.getBits(1);\r
+ nalu.getSe();\r
+ nalu.getSe();\r
+ UINT temp2=nalu.getUe();\r
+ for (int i=0;i<temp2;i++)\r
+ nalu.getSe();\r
+ }\r
+ nalu.getUe(); //Num refframes\r
+ nalu.getBits(1);\r
+ horizontal_size=(nalu.getUe()+1)*16;\r
+ \r
+ vertical_size=(nalu.getUe()+1)*16;\r
+ int interlaced=nalu.getBits(1);\r
+ vertical_size*=(2-interlaced);\r
+ \r
+ if (!interlaced) nalu.getBits(1);\r
+ nalu.getBits(1);\r
+ if (nalu.getBits(1))\r
+ {\r
+ horizontal_size-=nalu.getUe()*chromunitx;\r
+ horizontal_size-=nalu.getUe()*chromunitx;\r
+ vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;\r
+ vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;\r
+ }\r
+ if (nalu.getBits(1))\r
+ {\r
+ if (nalu.getBits(1))\r
+ {\r
+ UINT aspectratioidc=nalu.getBits(8);\r
+ bool hasaspect=false;\r
+ const float aspects[]={1., 1./1.,12./11.,10./11.,16./11.,40./33.,\r
+ 24./11.,20./11.,32./11.,80./33.,18./11.,15./11.,64./33.,160./99.,4./3.,3./2.,2./1.};\r
+ \r
+ float aspectratio=((float) horizontal_size)/((float) vertical_size);\r
+ if (aspectratioidc<=16) \r
+ {\r
+ hasaspect=true;\r
+ aspectratio*=aspects[aspectratioidc];\r
+ \r
+ }\r
+ else if (aspectratioidc==255)\r
+ {\r
+ int t_sar_width=nalu.getBits(16);\r
+ int t_sar_height=nalu.getBits(16);\r
+ if (t_sar_width!=0 && t_sar_height!=0)\r
+ {\r
+ hasaspect=true;\r
+ aspectratio*=((float)t_sar_width)/((float)t_sar_height);\r
+ }\r
+ }\r
+ if (hasaspect)\r
+ {\r
+ if (fabs(aspectratio-16./9.)<0.1) setAspectRatio(ASPECT_16_9);\r
+ else if (fabs(aspectratio-4./3.)<0.1) setAspectRatio(ASPECT_4_3);\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ }\r
+ \r
+ if (vid_seeking)\r
+ {\r
+ vid_seeking = 0;\r
+ video_pts_seek = video_pts;\r
+ Log::getInstance()->log("Demuxer", Log::DEBUG,\r
+ "Entering audio sync: Video PTS = %llu", video_pts);\r
+ Log::getInstance()->log("Demuxer", Log::DEBUG,\r
+ "Entering audio sync: Audio PTS = %llu", audio_pts);\r
+ }\r
+ return;\r
+ } \r
+ }\r
+}\r
+\r
+UINT Demuxer::stripAudio(UCHAR* buf, UINT len)\r
+{\r
+ UINT read_pos = 0, write_pos = 0;\r
+ UINT pattern, packet_length;\r
+ if (len < 4) return 0;\r
+ pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
+ while (read_pos + 7 <= len)\r
+ {\r
+ pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];\r
+ if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))\r
+ read_pos++;\r
+ else\r
+ {\r
+ packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;\r
+ if (read_pos + packet_length > len)\r
+ read_pos = len;\r
+ else\r
+ {\r
+ if (read_pos != write_pos)\r
+ memmove(buf+write_pos, buf+read_pos, packet_length);\r
+ read_pos += packet_length;\r
+ write_pos += packet_length;\r
+ pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)\r
+ | (buf[read_pos+2]);\r
+ }\r
+ }\r
+ }\r
+ return write_pos;\r
+}\r
+\r
+void Demuxer::changeTimes(UCHAR* buf, UINT len,UINT playtime)\r
+{\r
+ UINT pattern, packet_length;\r
+ UINT read_pos = 0;\r
+ if (len < 4) return;\r
+ pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
+ while (read_pos + 7 <= len)\r
+ {\r
+ pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];\r
+ if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))\r
+ read_pos++;\r
+ else\r
+ {\r
+ packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;\r
+ // ok we have a packet figure out if pts and dts are present and replace them\r
+ if (read_pos + 19 > len) return;\r
+ ULLONG new_ts=playtime*90; //play time is on ms so multiply it by 90\r
+ if (buf[read_pos+7] & 0x80) { // pts is here, replace it\r
+ buf[read_pos+9]=0x21 | (( new_ts>>29)& 0xde );\r
+ buf[read_pos+10]=0x00 |(( new_ts>>22)& 0xff );\r
+ buf[read_pos+11]=0x01 | (( new_ts>>14)& 0xfe );\r
+ buf[read_pos+12]=0x00 | (( new_ts>>7)& 0xff );\r
+ buf[read_pos+13]=0x01 | (( new_ts<<1)& 0xfe );\r
+ }\r
+\r
+ if (buf[read_pos+7] & 0x40) { // pts is here, replace it\r
+ buf[read_pos+14]=0x21 | (( new_ts>>29)& 0xde );\r
+ buf[read_pos+15]=0x00 | (( new_ts>>22)& 0xff );\r
+ buf[read_pos+16]=0x01 | (( new_ts>>14)& 0xfe );\r
+ buf[read_pos+17]=0x00 | (( new_ts>>7)& 0xff );\r
+ buf[read_pos+18]=0x01 | (( new_ts<<1)& 0xfe );\r
+ }\r
+ read_pos += packet_length;\r
+ pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)\r
+ | (buf[read_pos+2]);\r
+ }\r
+ }\r
+\r
+}\r
+\r
+bool Demuxer::scanForVideo(UCHAR* buf, UINT len, bool &ish264)\r
+{\r
+ UINT pos = 3;\r
+ UINT pattern;\r
+ ish264=false;\r
+ if (len < 4) return false;\r
+ pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
+ while (pos < len)\r
+ {\r
+ pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++];\r
+ if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX))\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+bool* Demuxer::getmpAudioChannels()\r
+{\r
+ return avail_mpaudchan;\r
+}\r
+\r
+bool* Demuxer::getac3AudioChannels()\r
+{\r
+ return avail_ac3audchan;\r
+}\r
+\r
+bool* Demuxer::getSubtitleChannels()\r
+{\r
+ return avail_dvbsubtitlechan;\r
+}\r
+\r
+int Demuxer::getselSubtitleChannel()\r
+{\r
+ return subtitle_current;\r
+}\r
+\r
+int Demuxer::getselAudioChannel()\r
+{\r
+ return audio_current;\r
+}\r
+\r
+\r
-/*
- Copyright 2005-2008 Mark Calderbank
- Copyright 2007 Marten Richter (AC3 support)
-
- 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.
-*/
-
-/*
-
-Thanks go to Jon Gettler of the MVPMC project and Stephen Rice for
-the demuxer in mvpmc. It was used in the creation of this demuxer;
-however, no code was copied verbatim.
-
-*/
-
-#ifndef DEMUXER_H
-#define DEMUXER_H
-
-#include "stream.h"
-#include "defines.h"
-
-class DVBSubtitles;
-class Callback;
-class DrainTarget;
-
-class PESPacket
-{
- public:
- PESPacket();
- PESPacket(const PESPacket& packet);
- PESPacket& operator=(const PESPacket& packet);
- ~PESPacket();
- void init(UCHAR type, UCHAR sub=0);
- void truncate();
- int write(const UCHAR* buf, int len);
-
- UCHAR operator[] (UINT index) const;
- // return data[index] if in bounds, else 0
- // so no proper error condition but never mind for now
- const UCHAR* getData() const { return data; }
- UINT getLength() const { return length; }
- UINT getSize() const { return size; }
- UCHAR getPacketType() const { return packetType; }
- void setSubstream(UCHAR s) { substream = s; }
- UCHAR getSubstream() const { return substream; }
- ULLONG getPTS() const;
- bool hasPTS() const { return (getPTS() != PTS_INVALID); }
-
- UINT findPictureHeader(bool h264) const;
- UINT findSeqHeader(bool h264) const;
- UINT countPictureHeaders(bool h264) const;
- static const ULLONG PTS_INVALID = (1LL << 33);
- protected:
- void copyFrom(const PESPacket& packet);
- UCHAR * data;
- UINT length, size;
- UINT data_size;
- UCHAR packetType;
- UCHAR substream;
- UINT mutable seq_header; // 0 = no, 1 = unknown, else = header offset
-};
-
-class Demuxer
-{
- public:
- Demuxer();
- virtual ~Demuxer();
- static Demuxer* getInstance();
- int init(Callback* tcallback, DrainTarget* audio, DrainTarget* video,
- DrainTarget* teletext,
- ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT, double fps=25.,
- DVBSubtitles* tsubtitles=NULL);
- virtual void reset();
- virtual void flush();
- void flushAudio();
- void seek();
- void setVideoStream(int id);
- //TODO HANS next virtual necessary?
- //virtual void setAudioStream(int id);
- void setAudioStream(int id);
- void setTeletextStream(int id);
- void setDVBSubtitleStream(int id);
- bool writeAudio();
- bool writeVideo();
- bool writeTeletext();
-
- virtual int scan(UCHAR* buf, int len) = 0;
- virtual int findPTS(UCHAR* buf, int len, ULLONG* dest) = 0;
- virtual int put(UCHAR* buf, int len) = 0;
- virtual void setFrameNum(ULONG frame) {}
- virtual void setPacketNum(ULONG packet) {}
- virtual ULONG getFrameNumFromPTS(ULLONG pts) {return 0;}
- virtual ULONG getPacketNum() {return 0;}
-
- bool* getmpAudioChannels(); //Maybe virtual ?
- bool* getac3AudioChannels(); //Maybe virtual ?
- bool* getSubtitleChannels();
- int getselAudioChannel();
- int getselSubtitleChannel();
- bool ish264() {return h264;}
- void seth264(bool newh264){h264=newh264;}
-
- int getHorizontalSize() { return horizontal_size; }
- int getVerticalSize() { return vertical_size; }
- int getAspectRatio() { return aspect_ratio; }
- int getFrameRate() { return frame_rate; }
- int getBitRate() { return bit_rate; }
- ULLONG getVideoPTS() { return video_pts; }
- ULLONG getAudioPTS() { return audio_pts; }
-
- enum AspectRatio
- {
- ASPECT_4_3 = 2,
- ASPECT_16_9 = 3
- };
-
- // Remove all data from a buffer apart from video PES packets.
- // Returns the length of the reduced data.
- // removed *static function*, due to DemuxerTS
- virtual UINT stripAudio(UCHAR* buf, UINT len);
-
- // Scan a buffer to see if video packets are present.
- // Returns true if video exists; false if not.
- // removed *static function* for h264 detection
- static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264);
-
- enum PESTYPE
- {
- PESTYPE_PRIVATE_1 = 0xBD,
-
- PESTYPE_AUD0 = 0xC0,
- PESTYPE_AUD1, PESTYPE_AUD2, PESTYPE_AUD3, PESTYPE_AUD4,
- PESTYPE_AUD5, PESTYPE_AUD6, PESTYPE_AUD7, PESTYPE_AUD8,
- PESTYPE_AUD9, PESTYPE_AUD10, PESTYPE_AUD11, PESTYPE_AUD12,
- PESTYPE_AUD13, PESTYPE_AUD14, PESTYPE_AUD15, PESTYPE_AUD16,
- PESTYPE_AUD17, PESTYPE_AUD18, PESTYPE_AUD19, PESTYPE_AUD20,
- PESTYPE_AUD21, PESTYPE_AUD22, PESTYPE_AUD23, PESTYPE_AUD24,
- PESTYPE_AUD25, PESTYPE_AUD26, PESTYPE_AUD27, PESTYPE_AUD28,
- PESTYPE_AUD29, PESTYPE_AUD30, PESTYPE_AUD31,
- PESTYPE_AUDMAX = PESTYPE_AUD31,
-
- PESTYPE_VID0 = 0xE0,
- PESTYPE_VID1, PESTYPE_VID2, PESTYPE_VID3, PESTYPE_VID4,
- PESTYPE_VID5, PESTYPE_VID6, PESTYPE_VID7, PESTYPE_VID8,
- PESTYPE_VID9, PESTYPE_VID10, PESTYPE_VID11, PESTYPE_VID12,
- PESTYPE_VID13, PESTYPE_VID14, PESTYPE_VID15,
- PESTYPE_VIDMAX = PESTYPE_VID15
- };
- enum PESTYPE_SUBSTREAM
- {
- PESTYPE_SUBSTREAM_TELETEXT0 = 0x10,
- PESTYPE_SUBSTREAM_TELETEXT1,PESTYPE_SUBSTREAM_TELETEXT2, PESTYPE_SUBSTREAM_TELETEXT3,
- PESTYPE_SUBSTREAM_TELETEXT4,PESTYPE_SUBSTREAM_TELETEXT5,PESTYPE_SUBSTREAM_TELETEXT6,
- PESTYPE_SUBSTREAM_TELETEXT7, PESTYPE_SUBSTREAM_TELETEXT8, PESTYPE_SUBSTREAM_TELETEXT9,
- PESTYPE_SUBSTREAM_TELETEXT10,PESTYPE_SUBSTREAM_TELETEXT11,PESTYPE_SUBSTREAM_TELETEXT12,
- PESTYPE_SUBSTREAM_TELETEXT13,PESTYPE_SUBSTREAM_TELETEXT14,PESTYPE_SUBSTREAM_TELETEXT15,
- PESTYPE_SUBSTREAM_TELETEXTMAX=PESTYPE_SUBSTREAM_TELETEXT15,
- PESTYPE_SUBSTREAM_DVBSUBTITLE0=0x20,
- PESTYPE_SUBSTREAM_DVBSUBTITLE1,PESTYPE_SUBSTREAM_DVBSUBTITLE2,PESTYPE_SUBSTREAM_DVBSUBTITLE3,
- PESTYPE_SUBSTREAM_DVBSUBTITLE4,PESTYPE_SUBSTREAM_DVBSUBTITLE5,PESTYPE_SUBSTREAM_DVBSUBTITLE6,
- PESTYPE_SUBSTREAM_DVBSUBTITLE7,
- PESTYPE_SUBSTREAM_DVBSUBTITLEMAX=PESTYPE_SUBSTREAM_DVBSUBTITLE7,
- PESTYPE_SUBSTREAM_AC30 = 0x80,
- PESTYPE_SUBSTREAM_AC31,PESTYPE_SUBSTREAM_AC32, PESTYPE_SUBSTREAM_AC33,
- PESTYPE_SUBSTREAM_AC34,PESTYPE_SUBSTREAM_AC35,PESTYPE_SUBSTREAM_AC36,
- PESTYPE_SUBSTREAM_AC37,
- PESTYPE_SUBSTREAM_AC3MAX = PESTYPE_SUBSTREAM_AC37
- };
-
- protected:
- // Operations on PES packets
- bool submitPacket(PESPacket&);
- void parsePacketDetails(PESPacket&);
-
- // General demuxer objects and status indicators
- static Demuxer* instance;
- Stream videostream;
- Stream audiostream;
- DVBSubtitles* subtitles;
- Stream teletextstream;
- int shutdown();
- bool initted;
- bool vid_seeking;
- bool aud_seeking;
- bool h264;
- int video_current, audio_current, teletext_current, subtitle_current;
-
- // Video stream information
- void setAspectRatio(enum AspectRatio);
- Callback* callback;
-
- int horizontal_size;
- int vertical_size;
- int profile;
- enum AspectRatio aspect_ratio;
- int arcnt;
- int frame_rate;
- int bit_rate;
- ULLONG video_pts;
- ULLONG video_pts_seek;
- ULLONG audio_pts;
- ULLONG teletext_pts;
- bool isteletextdecoded;
-
-
- unsigned int packetnum;
-
- // Constants
- static const int FrameRates[9];
-
- double fps;
-
- bool ispre_1_3_19;
- bool avail_mpaudchan[PESTYPE_AUDMAX-PESTYPE_AUD0+1];
- bool avail_ac3audchan[PESTYPE_SUBSTREAM_AC3MAX-PESTYPE_SUBSTREAM_AC30+1];
- bool avail_dvbsubtitlechan[PESTYPE_SUBSTREAM_DVBSUBTITLEMAX-PESTYPE_SUBSTREAM_DVBSUBTITLE0+1];
-};
-
-#endif
+/*\r
+ Copyright 2005-2008 Mark Calderbank\r
+ Copyright 2007 Marten Richter (AC3 support)\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software Foundation, Inc.,\r
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+Thanks go to Jon Gettler of the MVPMC project and Stephen Rice for\r
+the demuxer in mvpmc. It was used in the creation of this demuxer;\r
+however, no code was copied verbatim.\r
+\r
+*/\r
+\r
+#ifndef DEMUXER_H\r
+#define DEMUXER_H\r
+\r
+#include "stream.h"\r
+#include "defines.h"\r
+\r
+class DVBSubtitles;\r
+class Callback;\r
+class DrainTarget;\r
+\r
+class PESPacket\r
+{\r
+ public:\r
+ PESPacket();\r
+ PESPacket(const PESPacket& packet);\r
+ PESPacket& operator=(const PESPacket& packet);\r
+ ~PESPacket();\r
+ void init(UCHAR type, UCHAR sub=0);\r
+ void truncate();\r
+ int write(const UCHAR* buf, int len);\r
+\r
+ UCHAR operator[] (UINT index) const;\r
+ // return data[index] if in bounds, else 0\r
+ // so no proper error condition but never mind for now\r
+ const UCHAR* getData() const { return data; }\r
+ UINT getLength() const { return length; }\r
+ UINT getSize() const { return size; }\r
+ UCHAR getPacketType() const { return packetType; }\r
+ void setSubstream(UCHAR s) { substream = s; }\r
+ UCHAR getSubstream() const { return substream; }\r
+ ULLONG getPTS() const;\r
+ bool hasPTS() const { return (getPTS() != PTS_INVALID); }\r
+\r
+ UINT findPictureHeader(bool h264) const;\r
+ UINT findSeqHeader(bool h264) const;\r
+ UINT countPictureHeaders(bool h264) const;\r
+ static const ULLONG PTS_INVALID = (1LL << 33);\r
+\r
+\r
+\r
+ protected:\r
+ void copyFrom(const PESPacket& packet);\r
+ UCHAR * data;\r
+ UINT length, size;\r
+ UINT data_size;\r
+ UCHAR packetType;\r
+ UCHAR substream;\r
+ UINT mutable seq_header; // 0 = no, 1 = unknown, else = header offset\r
+};\r
+\r
+class Demuxer\r
+{\r
+ public:\r
+ Demuxer();\r
+ virtual ~Demuxer();\r
+ static Demuxer* getInstance();\r
+ int init(Callback* tcallback, DrainTarget* audio, DrainTarget* video,\r
+ DrainTarget* teletext,\r
+ ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT, double fps=25.,\r
+ DVBSubtitles* tsubtitles=NULL);\r
+ virtual void reset();\r
+ virtual void flush();\r
+ void flushAudio();\r
+ void seek();\r
+ void setVideoStream(int id);\r
+ //TODO HANS next virtual necessary?\r
+ //virtual void setAudioStream(int id);\r
+ void setAudioStream(int id);\r
+ void setTeletextStream(int id);\r
+ void setDVBSubtitleStream(int id);\r
+ bool writeAudio();\r
+ bool writeVideo();\r
+ bool writeTeletext();\r
+\r
+ virtual int scan(UCHAR* buf, int len) = 0;\r
+ virtual int findPTS(UCHAR* buf, int len, ULLONG* dest) = 0;\r
+ virtual int put(UCHAR* buf, int len) = 0;\r
+ virtual void setFrameNum(ULONG frame) {}\r
+ virtual void setPacketNum(ULONG packet) {}\r
+ virtual ULONG getFrameNumFromPTS(ULLONG pts) {return 0;}\r
+ virtual ULONG getPacketNum() {return 0;}\r
+\r
+ bool* getmpAudioChannels(); //Maybe virtual ?\r
+ bool* getac3AudioChannels(); //Maybe virtual ?\r
+ bool* getSubtitleChannels();\r
+ int getselAudioChannel();\r
+ int getselSubtitleChannel();\r
+ bool ish264() {return h264;}\r
+ void seth264(bool newh264){h264=newh264;}\r
+\r
+ int getHorizontalSize() { return horizontal_size; }\r
+ int getVerticalSize() { return vertical_size; }\r
+ int getAspectRatio() { return aspect_ratio; }\r
+ int getFrameRate() { return frame_rate; }\r
+ int getBitRate() { return bit_rate; }\r
+ ULLONG getVideoPTS() { return video_pts; }\r
+ ULLONG getAudioPTS() { return audio_pts; }\r
+\r
+ enum AspectRatio\r
+ {\r
+ ASPECT_4_3 = 2,\r
+ ASPECT_16_9 = 3\r
+ };\r
+\r
+ // Remove all data from a buffer apart from video PES packets.\r
+ // Returns the length of the reduced data.\r
+ // removed *static function*, due to DemuxerTS\r
+ virtual UINT stripAudio(UCHAR* buf, UINT len);\r
+ void changeTimes(UCHAR* buf, UINT len,UINT playtime);\r
+\r
+ // Scan a buffer to see if video packets are present.\r
+ // Returns true if video exists; false if not.\r
+ // removed *static function* for h264 detection\r
+ static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264);\r
+\r
+ enum PESTYPE\r
+ {\r
+ PESTYPE_PRIVATE_1 = 0xBD,\r
+\r
+ PESTYPE_AUD0 = 0xC0,\r
+ PESTYPE_AUD1, PESTYPE_AUD2, PESTYPE_AUD3, PESTYPE_AUD4,\r
+ PESTYPE_AUD5, PESTYPE_AUD6, PESTYPE_AUD7, PESTYPE_AUD8,\r
+ PESTYPE_AUD9, PESTYPE_AUD10, PESTYPE_AUD11, PESTYPE_AUD12,\r
+ PESTYPE_AUD13, PESTYPE_AUD14, PESTYPE_AUD15, PESTYPE_AUD16,\r
+ PESTYPE_AUD17, PESTYPE_AUD18, PESTYPE_AUD19, PESTYPE_AUD20,\r
+ PESTYPE_AUD21, PESTYPE_AUD22, PESTYPE_AUD23, PESTYPE_AUD24,\r
+ PESTYPE_AUD25, PESTYPE_AUD26, PESTYPE_AUD27, PESTYPE_AUD28,\r
+ PESTYPE_AUD29, PESTYPE_AUD30, PESTYPE_AUD31,\r
+ PESTYPE_AUDMAX = PESTYPE_AUD31,\r
+\r
+ PESTYPE_VID0 = 0xE0,\r
+ PESTYPE_VID1, PESTYPE_VID2, PESTYPE_VID3, PESTYPE_VID4,\r
+ PESTYPE_VID5, PESTYPE_VID6, PESTYPE_VID7, PESTYPE_VID8,\r
+ PESTYPE_VID9, PESTYPE_VID10, PESTYPE_VID11, PESTYPE_VID12,\r
+ PESTYPE_VID13, PESTYPE_VID14, PESTYPE_VID15,\r
+ PESTYPE_VIDMAX = PESTYPE_VID15\r
+ };\r
+ enum PESTYPE_SUBSTREAM\r
+ {\r
+ PESTYPE_SUBSTREAM_TELETEXT0 = 0x10,\r
+ PESTYPE_SUBSTREAM_TELETEXT1,PESTYPE_SUBSTREAM_TELETEXT2, PESTYPE_SUBSTREAM_TELETEXT3,\r
+ PESTYPE_SUBSTREAM_TELETEXT4,PESTYPE_SUBSTREAM_TELETEXT5,PESTYPE_SUBSTREAM_TELETEXT6,\r
+ PESTYPE_SUBSTREAM_TELETEXT7, PESTYPE_SUBSTREAM_TELETEXT8, PESTYPE_SUBSTREAM_TELETEXT9,\r
+ PESTYPE_SUBSTREAM_TELETEXT10,PESTYPE_SUBSTREAM_TELETEXT11,PESTYPE_SUBSTREAM_TELETEXT12,\r
+ PESTYPE_SUBSTREAM_TELETEXT13,PESTYPE_SUBSTREAM_TELETEXT14,PESTYPE_SUBSTREAM_TELETEXT15,\r
+ PESTYPE_SUBSTREAM_TELETEXTMAX=PESTYPE_SUBSTREAM_TELETEXT15,\r
+ PESTYPE_SUBSTREAM_DVBSUBTITLE0=0x20,\r
+ PESTYPE_SUBSTREAM_DVBSUBTITLE1,PESTYPE_SUBSTREAM_DVBSUBTITLE2,PESTYPE_SUBSTREAM_DVBSUBTITLE3,\r
+ PESTYPE_SUBSTREAM_DVBSUBTITLE4,PESTYPE_SUBSTREAM_DVBSUBTITLE5,PESTYPE_SUBSTREAM_DVBSUBTITLE6,\r
+ PESTYPE_SUBSTREAM_DVBSUBTITLE7,\r
+ PESTYPE_SUBSTREAM_DVBSUBTITLEMAX=PESTYPE_SUBSTREAM_DVBSUBTITLE7,\r
+ PESTYPE_SUBSTREAM_AC30 = 0x80,\r
+ PESTYPE_SUBSTREAM_AC31,PESTYPE_SUBSTREAM_AC32, PESTYPE_SUBSTREAM_AC33,\r
+ PESTYPE_SUBSTREAM_AC34,PESTYPE_SUBSTREAM_AC35,PESTYPE_SUBSTREAM_AC36,\r
+ PESTYPE_SUBSTREAM_AC37,\r
+ PESTYPE_SUBSTREAM_AC3MAX = PESTYPE_SUBSTREAM_AC37\r
+ };\r
+\r
+ protected:\r
+ // Operations on PES packets\r
+ bool submitPacket(PESPacket&);\r
+ void parsePacketDetails(PESPacket&);\r
+\r
+ // General demuxer objects and status indicators\r
+ static Demuxer* instance;\r
+ Stream videostream;\r
+ Stream audiostream;\r
+ DVBSubtitles* subtitles;\r
+ Stream teletextstream;\r
+ int shutdown();\r
+ bool initted;\r
+ bool vid_seeking;\r
+ bool aud_seeking;\r
+ bool h264;\r
+ int video_current, audio_current, teletext_current, subtitle_current;\r
+\r
+ // Video stream information\r
+ void setAspectRatio(enum AspectRatio);\r
+ Callback* callback;\r
+\r
+ int horizontal_size;\r
+ int vertical_size;\r
+ int profile;\r
+ enum AspectRatio aspect_ratio;\r
+ int arcnt;\r
+ int frame_rate;\r
+ int bit_rate;\r
+ ULLONG video_pts;\r
+ ULLONG video_pts_seek;\r
+ ULLONG audio_pts;\r
+ ULLONG teletext_pts;\r
+ bool isteletextdecoded;\r
+\r
+\r
+ unsigned int packetnum;\r
+\r
+ // Constants\r
+ static const int FrameRates[9];\r
+\r
+ double fps;\r
+\r
+ bool ispre_1_3_19;\r
+ bool avail_mpaudchan[PESTYPE_AUDMAX-PESTYPE_AUD0+1];\r
+ bool avail_ac3audchan[PESTYPE_SUBSTREAM_AC3MAX-PESTYPE_SUBSTREAM_AC30+1];\r
+ bool avail_dvbsubtitlechan[PESTYPE_SUBSTREAM_DVBSUBTITLEMAX-PESTYPE_SUBSTREAM_DVBSUBTITLE0+1];\r
+};\r
+\r
+#endif\r
-/*
- Copyright 2006 Mark Calderbank, Andreas Vogel
-
- 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 "demuxeraudio.h"
-#include "audio.h"
-#include "i18n.h"
-#include "log.h"
-
-#define HDRBYTE1 0xff
-#define HDRBYTE2 0xe0
-#define HDRBYTE2MASK 0xe0
-
-
-
-class PacketBuffer {
-
- public:
- PacketBuffer(Stream *as,UCHAR strtype) {
- log=Log::getInstance();
- audio=as;
- streamtype=strtype;
- newStream();
- }
- //just handle the data (do not deal with headers)
- int putInternal(UCHAR* buf,int len,unsigned int &packetnum);
- void reset(){
- partPacket=0;
- bytesWritten=0;
- framelen=DemuxerAudio::PACKET_SIZE;
- }
- void newStream() {
- reset();
- numpackets=0;
- numbytes=0;
- skipfactor=0;
- numskip=0;
- }
- bool bufferFull() {
- return (partPacket>=framelen);
- }
- //can we write a new packet?
- bool bufferEmpty() {
- return partPacket==0;
- }
- //only set this, if buffer empty
- //otherwise ignored!
- bool setFramelen(int len) {
- if (! bufferEmpty() ) return false;
- if (len > (int)DemuxerAudio::PACKET_SIZE) return false;
- framelen=len;
- return true;
- }
- //how much bytes do we need to fill the packet?
- int bytesMissing() {
- return framelen-partPacket;
- }
- int getFramelen() {
- return framelen;
- }
- void setSkipFactor(int factor) {
- skipfactor=factor;
- numskip=0;
- }
- private:
- void packetWritten() {
- numbytes+=framelen;
- //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written packet %ld l=%d, bytes %ld",numpackets,framelen,numbytes);
- numpackets++;
- reset();
- }
- bool doSkip();
- UCHAR store[DemuxerAudio::PACKET_SIZE]; // Storage for partial packets
- int partPacket; // Length of partial packet stored from previous put()
- int bytesWritten; //if they are !=0 and != framelength the stream is full...
- int framelen;
- Log * log;
- Stream * audio;
- UCHAR streamtype;
- //global counters
- ULONG numpackets;
- ULONG numbytes;
- int skipfactor;
- int numskip;
-};
-
-
-DemuxerAudio::DemuxerAudio(int p_vID, int p_aID)
-{
- inSync=false;
- isStarting=true;
- log=Log::getInstance();
- readHeaders=0;
- streamtype=Audio::MP3;
- buffer=new PacketBuffer(&audiostream,streamtype);
-// buffer=new PacketBuffer(&teststream,streamtype);
- globalBytesWritten=0;
- packetnum=0;
- id3=NULL;
- info=NULL;
- vbr=NULL;
- reset();
-}
-
-DemuxerAudio::~DemuxerAudio() {
- delete buffer;
- if(info) delete info;
- if(id3) delete id3;
- if (vbr) delete vbr;
-}
-
-void DemuxerAudio::flush()
-{
- Demuxer::flushAudio();
- buffer->newStream();
- tmpFill=0;
-}
-
-void DemuxerAudio::reset() {
- buffer->newStream();
- tmpFill=0;
- readHeaders=0;
- packetnum=0;
- outOfSync=0;
- globalBytesWritten=0;
- if (id3) delete id3;
- id3=NULL;
- if (info) delete info;
- info=NULL;
- if (vbr) delete vbr;
- vbr=NULL;
- inSync=false;
- hasHdrInfo=false;
- hasVBRInfo=false;
- isStarting=true;
- hdrBitrate=128000;
- hdrSamplingRate=44100;
- avrBitrate=0;
- hdrFramelen=0;
- isStarting=true;
-}
-
-int DemuxerAudio::scan(UCHAR *buf, int len)
-{
- //no differend pids here
- return 0;
-}
-
-void DemuxerAudio::setVID(int p_vID)
-{
-}
-
-void DemuxerAudio::setAID(int p_aID,int type)
-{
-}
-
-static char * id3_1_genre[] = {
- "Blueshhh",
- "Classic Rock",
- "Country",
- "Dance",
- "Disco",
- "Funk",
- "Grunge",
- "Hip-Hop",
- "Jazz",
- "Metal",
- "New Age",
- "Oldies",
- "Other",
- "Pop",
- "R&B",
- "Rap",
- "Reggae",
- "Rock",
- "Techno",
- "Industrial",
- "Alternative",
- "Ska",
- "Death Metal",
- "Pranks",
- "Soundtrack",
- "Euro-Techno",
- "Ambient",
- "Trip-Hop",
- "Vocal",
- "Jazz+Funk",
- "Fusion",
- "Trance",
- "Classical",
- "Instrumental",
- "Acid",
- "House",
- "Game",
- "Sound Clip",
- "Gospel",
- "Noise",
- "AlternRock",
- "Bass",
- "Soul",
- "Punk",
- "Space",
- "Meditative",
- "Instrumental Pop",
- "Instrumental Rock",
- "Ethnic",
- "Gothic",
- "Darkwave",
- "Techno-Industrial",
- "Electronic",
- "Pop-Folk",
- "Eurodance",
- "Dream",
- "Southern Rock",
- "Comedy",
- "Cult",
- "Gangsta",
- "Top 40",
- "Christian Rap",
- "Pop/Funk",
- "Jungle",
- "Native American",
- "Cabaret",
- "New Wave",
- "Psychadelic",
- "Rave",
- "Showtunes",
- "Trailer",
- "Lo-Fi",
- "Tribal",
- "Acid Punk",
- "Acid Jazz",
- "Polka",
- "Retro",
- "Musical",
- "Rock & Roll",
- "Hard Rock"
-};
-
-
-
-static int bitrateTable[16][5]={
-/* L1,L2,L3,2L1,2L2 */
-/*0000*/ {-1,-1,-1,-1,-1},
-/*0001*/ {32,32,32,32,8},
-/*0010*/ {64,48,40,48,16},
-/*0011*/ {96,56,48,56,24},
-/*0100*/ {128,64,56,64,32},
-/*0101*/ {160,80,64,80,40},
-/*0110*/ {192,96,80,96,48},
-/*0111*/ {224,112,96,112,56},
-/*1000*/ {256,128,112,128,64},
-/*1001*/ {288,160,128,144,80},
-/*1010*/ {320,192,160,160,96},
-/*1011*/ {352,224,192,176,112},
-/*1100*/ {384,256,224,192,128},
-/*1101*/ {416,320,256,224,144},
-/*1110*/ {448,384,320,256,160},
-/*1111*/ {-1,-1,-1,-1,-1} };
-
-static int samplingRateTable[4][3]={
-/*00*/ {44100,22050,11025},
-/*01*/ {48000,24000,12000},
-/*10*/ {32000,16000,8000},
-/*11*/ {-1,-1,-1}};
-
-//max 7 char!
-static const char * mpegString(UCHAR code) {
- switch(code) {
- case 0:
- return "MPEG2.5";
- case 1:
- return "RESERV";
- case 2:
- return "MPEG 2";
- case 3:
- return "MPEG 1";
- }
- return "UNKNOWN";
-}
-
-static const char * layerString(UCHAR code) {
- switch(code) {
- case 0:
- return "Layer reserved";
- case 1:
- return "Layer III";
- case 2:
- return "Layer II";
- case 3:
- return "Layer I";
- }
- return "Layer UNKNOWN";
-}
-/**
- * parse an id3 Header
- * provided by Brian Walton
- * @returns -1 of nothing found
- */
-
-int DemuxerAudio::id3_2_3_FrameParse(unsigned char buf[], id3_frame *frame)
-{
- if (buf[0] < 0x20 || buf[1] < 0x20 || buf [2] < 0x20 ) return -1;
- frame->size = (buf[4] & 0x7F) << 21 | (buf[5] & 0x7F) << 14 | (buf[6] & 0x7F) << 7 | (buf[7] & 0x7F);
- if (frame->size == 0) return -1;
- //TODO. clearify flags against:
- //http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b
- frame->flags.tagAlterPreserv = (buf[8] & 0x80) >> 7;
- frame->flags.filelterPreserv = (buf[8] & 0x40) >> 6;
- frame->flags.readOnly = (buf[8] & 0x20) >> 5;
- frame->flags.groupId = (buf[9] & 0x20) >> 5;
- frame->flags.compression = (buf[9] & 0x80) >> 7;
- frame->flags.encryption = (buf[9] & 0x40) >> 6;
- frame->flags.unsync = 0;
- frame->flags.dataLen = 0;
- return 0;
-}
-
- /**
- * parse an id3 Header
- * provided by Brian Walton
- * @returns -1 of nothing found
- */
-
-int DemuxerAudio::id3_2_2_FrameParse(unsigned char buf[], id3_frame *frame)
-{
- if (buf[0] < 0x20 || buf[1] < 0x20 || buf[2] < 0x20) return -1;
- frame->size = (buf[3] & 0x7F) << 14 | (buf[4] & 0x7F) << 7 | (buf[5] & 0x7F);
- if (frame->size == 0) return -1;
- return 0;
-}
-
-
-//fill an id3tag from a frame payload
-//http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b
-//http://id3.org/id3v2-00
-static struct tagid {
- const char * bytes;
- int index;
-} knownFrames[]= {
- //ID3V2.3
- {"TIT2",1}, //title
- {"TPE1",2}, //artist
- {"TCON",3}, //genre
- {"TRCK",6}, //track
- {"TYER",4}, //year
- {"TALB",5}, //album
- {"TCOM",7}, //composer
- {"COMM",8}, //comment
- //Text encoding $xx
- //Language $xx xx xx
- //Short content descrip. <text string according to encoding> $00 (00)
- //The actual text <full text string according to encoding>
- //ID3V2.0
- {"TT2",1 },
- {"TP1",2 },
- {"TCM",7 },
- {"TCO",3 }, //(genreNumber)
- {"TAL",5 },
- {"TRK",6 },
- {"TYE",4 },
- {"COM",8 }
-};
-#define NUMKNOWN (sizeof(knownFrames)/sizeof(knownFrames[0]))
-
-/*fill in infos
- from an ID3 V2.x, V2.3 frame into the tags structure
- frameData must point to the header
- framelen is the len without header (10 Bytes for V23, 6 Bytes for v2x)
- */
-
-#define MAXLEN(tagtype) ((UINT)frameLen<sizeof(tag->tagtype)-1?(UINT)frameLen:sizeof(tag->tagtype)-1)
-bool DemuxerAudio::fillId3Tag(id3_tag * tag,UCHAR * frameData, int frameLen, int dataOffset, bool v23) {
- int tl=v23?4:3;
- int tagIndex=-1;
- if (tag == NULL) return false;
- if (frameLen < 2) return false;
- for (UINT i=0;i< NUMKNOWN;i++) {
- if(strncmp((char *)frameData,knownFrames[i].bytes,tl) == 0) {
- tagIndex=knownFrames[i].index;
- break;
- }
- }
- if (tagIndex < 0) return false;
- UCHAR encoding=*(frameData+dataOffset);
- dataOffset++;
- frameLen--;
- if (encoding != 0) {
- log->log("DemuxerAudio",Log::DEBUG,"unknown encoding for tag %d, tagid %s",encoding,
- knownFrames[tagIndex].bytes);
- return false;
- }
- switch(tagIndex) {
- case 1: //title
- strncpy(tag->title,(char*)(frameData+dataOffset),MAXLEN(title));
- tag->title[MAXLEN(title)]=0;
- break;
- case 2: //artist
- strncpy(tag->artist,(char*)(frameData+dataOffset),MAXLEN(artist));
- tag->artist[MAXLEN(artist)]=0;
- break;
- case 3: //genre
- {
- UCHAR * st=frameData+dataOffset;
- int genre=0;
- if (*st=='(') {
- genre=atoi((const char *)(st+1)) && 31;
- st=(UCHAR *)id3_1_genre[genre];
- }
- strncpy(tag->genre,(char*)st,MAXLEN(genre));
- tag->genre[MAXLEN(genre)]=0;
- break;
- }
- case 4: //year
- strncpy(tag->year,(char *)(frameData+dataOffset),MAXLEN(year));
- tag->year[MAXLEN(year)]=0;
- break;
- case 5: //album
- strncpy(tag->album,(char *)(frameData+dataOffset),MAXLEN(album));
- tag->album[MAXLEN(album)]=0;
- break;
- case 6: //track
- strncpy(tag->track,(char *)(frameData+dataOffset),MAXLEN(track));
- tag->track[MAXLEN(track)]=0;
- break;
- case 7: //composer
- strncpy(tag->composer,(char *)(frameData+dataOffset),MAXLEN(composer));
- tag->composer[MAXLEN(composer)]=0;
- break;
- case 8: //comment
- strncpy(tag->comment,(char *)(frameData+dataOffset),MAXLEN(comment));
- tag->comment[MAXLEN(comment)]=0;
- break;
- default:
- return false;
- }
-
- return true;
-}
-
-/**
- * parse an id3 Header
- * based on code provided by Brian Walton
- * @returns -1 of nothing found
- * otherwise the id3 info is filled
- */
-
-int DemuxerAudio::parseID3V2(UCHAR *data, int len) {
- int debug=0;
- UCHAR * start=data;
- id3_header id3header;
- id3_frame id3frame;
- id3_tag * id3tag=NULL;
- //len = read(fd, data, 10);
- if (len < 10) {
- delete id3tag;
- return -1;
- }
- len-=10;
- if(data[0]=='I' && data[1]=='D' && data[2]=='3')
- {
- id3tag=new id3_tag();
- id3header.major = data[3];
- id3header.minor = data[4];
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 V2.%d.%d found\n", id3header.major, id3header.minor);
- id3header.flags.unsynchronisation = (data[5] & 0x80)>>7;
- id3header.flags.extended_header = (data[5] & 0x40)>>6;
- id3header.flags.experimental = (data[5] & 0x20)>>5;
- id3header.flags.footer = (data[5] & 0x10)>>4;
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Unsynchronisation flag: %d\n", id3header.flags.unsynchronisation);
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header flag: %d\n", id3header.flags.extended_header);
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Experimental indicator flag: %d\n", id3header.flags.experimental);
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Footer present flag: %d\n", id3header.flags.footer);
- id3header.size = (data[6] & 0x7F) << 21 | (data[7] & 0x7F) << 14 | (data[8] & 0x7F) << 7 | (data[9] & 0x7F);
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 Size: %d\n", id3header.size);
- data=start+10;
- if (len <= id3header.size) {
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"header size to big %d, only %d bytes available\n",id3header.size,len);
- delete id3tag;
- return -1;
- }
- if (id3header.flags.extended_header)
- {
- int extended_hdr_hdr=4; //still to be discussed (id3.org...)
- //read extended header size
- if (len < extended_hdr_hdr) {
- if (debug) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended header found but cannot read\n");
- delete id3tag;
- return -1;
- }
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"remaining %d chars after extended hdr hdr\n", len);
- id3header.extended_header.size = (data[0] & 0x7F) << 21 | (data[1] & 0x7F) << 14 | (data[2] & 0x7F) << 7 | (data[3] & 0x7F);
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header size: %d\n", id3header.extended_header.size);
- if (len <= id3header.extended_header.size+extended_hdr_hdr) {
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended Header to big, only %d bytes available\n",len);
- delete id3tag;
- return -1;
- }
- //lseek(fd, id3header.extended_header.size - 6, SEEK_CUR);
- data+=id3header.extended_header.size+extended_hdr_hdr;
- len-=id3header.extended_header.size+extended_hdr_hdr;
- }
- //set the end of the header
- UCHAR * eob=start+id3header.size+10;
- bool readNext=true;
- while (data < eob && readNext)
- {
- //skip over some padding - found this in lame MCDI tag...
- if (*data == 0) {
- data++;
- continue;
- }
- readNext=false;
- switch(id3header.major)
- {
- case 2: //ID3 V2.2.x
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.2 frame, %d : %c %c %c\n", data-start,*data,*(data+1),*(data+2));
- if (data + 6 >= eob)
- {
- break;
- }
- if (id3_2_2_FrameParse(data, &id3frame) < 0)
- {
- break;
- }
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame size: %d\n", id3frame.size);
- fillId3Tag(id3tag,data,id3frame.size,6,false);
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + 6 +1);
- data+=6+id3frame.size;
- readNext=true;
- break;
- case 3: //ID3 V2.3.x
- {
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.3 frame, %d : %c %c %c %c\n", data-start,
- *data,*(data+1),*(data+2),*(data+3));
- if (data + 10 >= eob)
- {
- break;
- }
- if (id3_2_3_FrameParse(data, &id3frame) <0)
- {
- break;
- }
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame size: %d\n", id3frame.size);
- int dataOffset=10;
- if (id3frame.flags.groupId)
- {
- dataOffset++;
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame group: %d\n", data[dataOffset]);
- }
- if (id3frame.flags.compression)
- {
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame compressed: %d\n", id3frame.flags.compression);
- }
- if (id3frame.flags.encryption)
- {
- dataOffset+=1;
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame encryption method: %d\n", data[dataOffset]);
- }
- fillId3Tag(id3tag,data,id3frame.size-dataOffset+10,dataOffset,true);
- if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + dataOffset +1);
- data+=10+id3frame.size;
- readNext=true;
- break;
- }
- default:
- //don't support this version
- delete id3tag;
- return -1;
- }
- }
-
- data=eob;
- //store the found tag
- if (id3) delete id3;
- id3=id3tag;
- return data-start;
- }
- return -1;
-}
-
-/**
- * parse an id3v1 Header
- * based on code provided by Brian Walton
- * @returns -1 of nothing found
- * otherwise the id3 info is filled
- */
-#define MEMCPY(type,len,offset) {int type##max=sizeof(tag->type)-1<len?sizeof(tag->type)-1:len;strncpy(tag->type,(char*)&data[offset],type##max);tag->type[type##max]=0;}
-
-int DemuxerAudio::parseID3V1(UCHAR *data, int len) {
- int debug=1;
- if (len < 128) return -1;
- if(data[0]=='T' && data[1]=='A' && data[2]=='G')
- {
- id3_tag * tag=new id3_tag();
- if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1 tag found\n");
- MEMCPY(title,30,3);
- MEMCPY(artist,30,33);
- MEMCPY(album,30,63);
- MEMCPY(year,4,93);
- if (data[125]==0 && data[126]!=0)
- { //ID3 V1.1
- if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.1 tag\n");
- MEMCPY(comment,29,97);
- sprintf(tag->track, "%d", data[126]);
- } else {
- if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.0 tag\n");
- MEMCPY(comment,30,97);
- }
- if (data[127] < sizeof(id3_1_genre)/sizeof(id3_1_genre[0]))
- {
- sprintf(tag->genre, id3_1_genre[data[127]]);
- }
- if (id3) delete id3;
- id3=tag;
- return 0;
- }
- return -1;
-}
-
-//infos from http://www.multiweb.cz/twoinches/MP3inside.htm
-int DemuxerAudio::parseVBR(UCHAR *data, int len) {
- UCHAR *hdr=findHeader(data,len);
- //we expect the header exactly here
- if (hdr != data) return -1;
- const static char * VBRHDR="Xing";
- int vbridpos=36;
- UCHAR mpgtype=(data[1] & 0x18)>>3;
- UCHAR chmode=(data[2] & 0xc0) >> 6;
- UCHAR layer=(data[2] & 0x06) >>1;
- if ( mpgtype == 3 && chmode == 11) vbridpos=21;
- if ( mpgtype != 3 && chmode != 11) vbridpos=21;
- if ( mpgtype != 3 && chmode == 11) vbridpos=13;
- //check for the header ID
- if (vbridpos+(int)strlen(VBRHDR)+4 >= len) {
- Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header %d",len);
- return -1;
- }
- for (int i=4;i<vbridpos;i++) {
- if (data[i] != 0) {
- Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"garbage when searching VBR header at pos %d",i);
- return -1;
- }
- }
- if ( strncmp((char *)&data[vbridpos],VBRHDR,strlen(VBRHDR)) != 0) {
- Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"no VBR header at pos %d",vbridpos);
- return -1;
- }
- int framedata=vbridpos+strlen(VBRHDR);
- int expectedLen=0;
- //OK we should now have a valid vbr header
- bool hasFramenum=data[framedata+3] & 1;
- bool hasBytes=data[framedata+3] & 0x2;
- bool hasTOC=data[framedata+3] & 0x4;
- expectedLen+=8;
- if (hasTOC) expectedLen+=100;
- if (framedata+expectedLen > len) {
- Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header data %d, expected %d",
- len,framedata+expectedLen);
- return -1;
- }
- if (!hasFramenum || ! hasBytes || ! hasTOC) {
- //not usefull for us..
- Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"not all parts in VBR header - ignore");
- return -1;
- }
- framedata+=4;
- if (vbr) delete vbr;
- vbr=new vbrInfo();
- vbr->numFrames=data[framedata] << 24 | data[framedata+1]<<16|
- data[framedata+2]<<8 |data[framedata+3];
- framedata+=4;
- vbr->numBytes=data[framedata] << 24 | data[framedata+1]<<16|
- data[framedata+2]<<8 |data[framedata+3];
- framedata+=4;
- for (int ti=0;ti<100;ti++) {
- vbr->table[ti]=data[framedata+ti];
- }
- //compute file size in seconds
- //should be (#of frames -1) *samplesPerFrame / sampleRate
- //TODO: difference for Mono?
- ULONG samplesPerFrame=384; //layer1
- if (layer != 3) samplesPerFrame=1152;
- vbr->fileSeconds=(vbr->numFrames-1)*samplesPerFrame/hdrSamplingRate;
- Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"successfully read VBR %ldbytes, %ld frames, %ldsec",
- vbr->numBytes,vbr->numFrames,vbr->fileSeconds);
- return hdrFramelen;
-}
-
-
-
-
-
-
-
-UCHAR * DemuxerAudio::findHeader(UCHAR *buf, int len, bool writeInfo) {
- while (len >= 3) //assume hdr+crc
- {
- UCHAR pattern=*buf;
- buf++; len--;
- if (pattern != HDRBYTE1 ) continue;
- if ((*buf & HDRBYTE2MASK) != HDRBYTE2) continue;
- if (readHeader((buf-1),4,writeInfo) != 0) continue;
- return buf-1;
- }
- return NULL;
-}
-
-
-
-int DemuxerAudio::readHeader(UCHAR * hbuf,int len,bool writeInfo) {
- int curFramelen=0;
- int curBitrate=0;
- int curSamplingRate=0;
- if (*hbuf != HDRBYTE1) return -1;
- hbuf++;
- if ((*hbuf & HDRBYTE2MASK) != HDRBYTE2) return -1;
- UCHAR mpgtype=(*hbuf & 0x18)>>3;
- if (mpgtype == 1) {
- log->log("DemuxerAudio",Log::DEBUG,"header invalid mpgtype %s %i %i %i",
- mpegString(mpgtype),*hbuf,*(hbuf+1),*(hbuf+2));
- return 1;
- }
- UCHAR layer=(*hbuf & 0x06) >>1;
- //bool hasCRC=!(*hbuf & 1);
- hbuf++;
- UCHAR bitrateCode=(*hbuf & 0xf0) >>4;
- UCHAR samplingCode=(*hbuf & 0x0c) >> 2;
- bool padding=*hbuf & 0x02;
- hbuf++;
- //0 Stereo, 1 JointStereo, 2 Dual, 3 Mono
- UCHAR chmode=(*hbuf & 0xc0) >> 6;
- //UCHAR extension=(*hbuf & 0x30) >> 4;
-
- //layercode: 1-L3, 2-L2, 3-L1
- //columns 0,1,2 for MPEG1
- UCHAR bitrateColumn=3-layer;
- if (bitrateColumn > 2) {
- log->log("DemuxerAudio",Log::DEBUG,"header invalid layer %s %i %i %i",
- layerString(layer),*(hbuf-2),*(hbuf-1),*hbuf);
- return 1;
- }
- if (mpgtype != 3) bitrateColumn+=3;
- if (bitrateColumn>4) bitrateColumn=4;
- curBitrate=1000*bitrateTable[bitrateCode][bitrateColumn];
- UCHAR sampleRateColumn=0;
- if (mpgtype == 10) sampleRateColumn=1;
- if (mpgtype == 0) sampleRateColumn=2;
- curSamplingRate=samplingRateTable[samplingCode][sampleRateColumn];
- if (curSamplingRate < 0 || curBitrate < 0) {
- log->log("DemuxerAudio",Log::DEBUG,"header invalid rates br=%d sr=%d %i %i %i",
- curBitrate,curSamplingRate,*(hbuf-2),*(hbuf-1),*hbuf);
- return 1;
- }
- int padbytes=0;
- if (padding) {
- if (layer == 3) padbytes=4;
- else padbytes=1;
- }
- if (layer == 3) {
- //Layer 1
- //FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4
- curFramelen=(12*curBitrate/curSamplingRate+padbytes) * 4;
- }
- else {
- //Layer 2/3
- //FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
- curFramelen=144*curBitrate/curSamplingRate+padbytes;
- }
- //the header itself
- if (curFramelen < 32) {
- log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d-invalid %i %i %i",
- readHeaders,mpegString(mpgtype),layerString(layer),
- curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf);
- return 1;
- }
- if (writeInfo || isStarting){
- log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d %i %i %i",
- readHeaders,mpegString(mpgtype),layerString(layer),
- curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf);
- if (info) delete info;
- info=new mpegInfo();
- strcpy(info->mpegVersion,mpegString(mpgtype));
- info->mpegLayer=4-layer;
- info->bitRate=curBitrate;
- info->avrBitrate=curBitrate;
- info->sampleRate=curSamplingRate;
- const char *chmodStr=tr("Stereo");
- switch (chmode) {
- case 1: chmodStr=tr("JointStereo");break;
- case 2: chmodStr=tr("Dual");break;
- case 3: chmodStr=tr("Mono");break;
- }
- SNPRINTF(info->info,sizeof(info->info)-1,"%s",chmodStr);
- }
- if (isStarting) avrBitrate=curBitrate;
- isStarting=false;
- readHeaders++;
- //moving average F=0.005
- avrBitrate=avrBitrate+((5*(curBitrate-avrBitrate))/1024);
- hdrBitrate=curBitrate;
- hdrFramelen=curFramelen;
- hdrSamplingRate=curSamplingRate;
- hasHdrInfo=true;
- return 0;
-}
-
-int DemuxerAudio::findPTS(UCHAR* buf, int len, ULLONG* dest)
-{
- //we have no PTS number ...
- *dest=0;
- return (findHeader(buf,len) != NULL)?1:0;
-}
-
-bool PacketBuffer::doSkip() {
- if (!bufferFull()) return false;
- if (skipfactor == 0) return false;
- numskip++;
- if (numskip >= skipfactor) {
- //sent at least always 2 packets
- if (numskip > skipfactor) numskip=0;
- return false;
- }
- packetWritten();
- return true;
-}
-
-// just handle the real stream without dealing with the header
-int PacketBuffer::putInternal(UCHAR * wbuf, int len,unsigned int &packetnum)
-{
- /* Important, the type passed to stream must be a mediapacket type as defined in
- Draintarget.h and not the device setting of the mvp, so we have to translate it here,
- in order to get it working on windows
- --MR */
- UCHAR mptype=0;
- switch (streamtype) {
- case Audio::MPEG1_PES: //?
- case Audio::MPEG2_PES: //Important, this must be a PES !
- mptype=MPTYPE_MPEG_AUDIO; break;
- default:
- case Audio::MP3: //this can be any Mpeg1 Audio not only layer 3 not packed into PES
- mptype=MPTYPE_MPEG_AUDIO_LAYER3;break;
- };
- if (bufferFull()) {
-#ifndef WIN32
- if (doSkip()) return 0;//NoSkip on Windows
-#endif
- //we are still full - so try to write
- int sent=audio->put(store+bytesWritten,framelen-bytesWritten,/*streamtype*/mptype,packetnum);packetnum++;
- //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream (still full) pp=%d, framelen=%d, written=%d",sent,partPacket,framelen, bytesWritten );
- if (sent < (framelen - bytesWritten)) {
- //packet still not written
- bytesWritten+=sent;
- return 0;
- }
- packetWritten();
- //let the demuxer come back with the rest - need to check header first
- return 0;
- }
- if (partPacket+len >= framelen) {
- //now we have at least a complete packet
- int bytesConsumed=framelen-partPacket;
- memcpy(store+partPacket,wbuf,bytesConsumed);
- partPacket=framelen;
- //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"stored packet %ld, length %d (last %d) for stream %p",numpackets,framelen,bytesConsumed,audio );
-#ifndef WIN32 //No Skip on Windows
- if (doSkip()) return bytesConsumed;
-#endif
- int sent=audio->put(store,framelen,mptype,packetnum);packetnum++;
- bytesWritten+=sent;
- //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream",sent );
- if (bytesWritten < framelen) {
- //still not completely written
- return bytesConsumed;
- }
- packetWritten();
- //let the player come back...
- return bytesConsumed;
- }
- //OK packet still not complete
- if (len == 0) return 0;
- int bytesConsumed=len;
- memcpy(store+partPacket,wbuf,bytesConsumed);
- partPacket+=bytesConsumed;
- return bytesConsumed;
-}
-
-/**
- major entry for data from a player
- the demuxer is either in the state headerSearch (packet written or
- just at the beginning), writing garbage (inSync=false) or
- handling data (none set)
- A header is expected at the first byte after the previous packet -
- otherwise we switch to garbage where we always search for a header
- (but anyway provide the data to the underlying device - it's probably
- more intelligent then we are...
- We only loose a correct position display.
- */
-int DemuxerAudio::put(UCHAR* wbuf, int len)
-{
- //return audiostream.put(wbuf,len,streamtype);
- int framelen=PACKET_SIZE;
- UCHAR *hdr;
- int bytesConsumed=0;
- int oldBytes=0;
- if (tmpFill != 0 || (buffer->bufferEmpty() && len < HDRLEN)) {
- //OK we have to copy everything to the tmp buffer
- int cp=(UINT)len<(PACKET_SIZE-tmpFill)?(UINT)len:(PACKET_SIZE-tmpFill);
- memcpy(&tmpBuffer[tmpFill],wbuf,cp);
- oldBytes=tmpFill;
- tmpFill+=cp;
- wbuf=tmpBuffer;
- len=tmpFill;
- //if there is no header here and our buffer
- //is empty - just wait for the next header
- if (len < HDRLEN && buffer->bufferEmpty()) {
- log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten);
- return cp;
- }
- }
- while (bytesConsumed < len ) {
- if (buffer->bufferFull()) {
- //if this is the first part of the loop, try to write to the stream
- if (bytesConsumed == 0) buffer->putInternal(wbuf,0,packetnum);
- //if the buffer is full, no need to continue
- if (buffer->bufferFull()) break;
- }
- //either we are in a packet (buffer != full && buffer != empty)
- //or we are searching a header
- if (buffer->bufferEmpty()) {
- if (len-bytesConsumed < HDRLEN) {
- // we cannot still search
- if (tmpFill != 0) {
- //we are already working at the buffer
- break;
- }
- memcpy(tmpBuffer,wbuf,len-bytesConsumed);
- tmpFill=len-bytesConsumed;
- log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten);
- return len;
- }
-
- int lastFramelen=hdrFramelen;
- //if the header has been valid before and we are searching
- //it should be here
- int maxsearch=((len-bytesConsumed) < (int)PACKET_SIZE)?len-bytesConsumed:(int)PACKET_SIZE;
- hdr=findHeader(wbuf,maxsearch);
- if (hdr != NULL) {
- //log->log("DemuxerAudio",Log::DEBUG,"header found at offset %d",hdr-wbuf);
- }
- //hdr now points to the new header
- if (hdr != wbuf) {
- //still at least bytes before the header
- inSync=false;
- outOfSync++;
- int garbageBytes=(hdr!=NULL)?(hdr-wbuf):maxsearch;
- //we consider the garbage now as an own packet
- //we can consume at most our buffer
- //basically the buffer should be empty here (we are
- //in header search - and we fill up each garbage
-
- int nframesize=garbageBytes;
- if (nframesize > (int)PACKET_SIZE) {
- nframesize=(int)PACKET_SIZE;
- }
- if (! buffer->bufferEmpty()) {
- log->log("DemuxerAudio",Log::WARN,"buffer not empty when having garbage to store");
- //at the end no big problem, we only write the remaining bytes that we have...
- }
- else {
- buffer->setFramelen(nframesize);
- }
- log->log("DemuxerAudio",Log::DEBUG,"garbage found at packet %ld (bytes %ld) of length %d, "
- "framelen set to %d (last fl=%d)",
- readHeaders,globalBytesWritten,garbageBytes,buffer->getFramelen(),lastFramelen);
-#ifndef WIN32
- //hmm - we assume that he low level driver is more intelligent
- //and give him the data "as is"
- int written=buffer->putInternal(wbuf,garbageBytes,packetnum);
- globalBytesWritten+=written;
- bytesConsumed+=written;
- if (written != garbageBytes || hdr == NULL ) {
- break;
- }
-#else //DS is not intelligent
- globalBytesWritten+=garbageBytes;
- bytesConsumed+=garbageBytes;
-#endif
- //OK either all the "garbage" is written or
- //we found the next header as expected
- //continue with the next package
- wbuf=hdr;
- }
- //we have to wait now until the buffer is
- //free for the next package
- if ( ! buffer->bufferEmpty()) return bytesConsumed;
- //this is the place where we start a new packet
- framelen=hdrFramelen;
- if ( !buffer->setFramelen(framelen) ) {
- log->log("DemuxerAudio",Log::DEBUG,"unable to set framelen should=%d, current=%d",
- framelen,buffer->getFramelen());
- }
- inSync=true;
- }
- //now we are surely within a packet
- int written=buffer->putInternal(wbuf,len-bytesConsumed,packetnum);
- //update the status
- globalBytesWritten+=written;
- wbuf+=written;
- bytesConsumed+=written;
- if (written == 0) {
- //stream is full
- break;
- }
- //OK - handle the rest
- }
- if (bytesConsumed >= oldBytes) {
- //if we consumed more than the old bytes - OK the buffer
- //can be thrown away
- tmpFill=0;
- return bytesConsumed-oldBytes;
- }
- else {
- //only consumed bytes from the buffer
- if (bytesConsumed == 0) {
- //restore the buffer
- tmpFill=oldBytes;
- return 0;
- }
- //shift bytes in buffer
- for (int i=0;i<oldBytes-bytesConsumed;i++) {
- tmpBuffer[i]=tmpBuffer[i+bytesConsumed];
- }
- tmpFill=oldBytes-bytesConsumed;
- return 0;
- }
-}
-
-//info functions
-const id3_tag * DemuxerAudio::getId3Tag() {
- return id3;
-
-}
-const DemuxerAudio::mpegInfo * DemuxerAudio::getMpegInfo() {
- if (! hasHdrInfo) return NULL;
- info->avrBitrate=avrBitrate;
- info->bitRate=hdrBitrate;
- return info;
-}
-
-const DemuxerAudio::vbrInfo * DemuxerAudio::getVBRINfo() {
- return vbr;
-}
-
-int DemuxerAudio::checkStart(UCHAR *b, int len) {
- UCHAR *start=b;
- int id3len=parseID3V2(b,len);
- if (id3len > 0) {
- char * str=id3->toString();
- log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 %d bytes of %d",id3len,len);
- log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 found:%s",str);
- delete str;
- b+=id3len;
- len-=id3len;
- }
- int vbrlen=parseVBR(b,len);
- if (vbrlen > 0 ) {
- hasVBRInfo=true;
- b+=vbrlen;
- len-=vbrlen;
- }
- UCHAR * hdr=findHeader(b,len,true);
- if (hdr == NULL) return -1;
- return hdr-start;
-}
-
-int DemuxerAudio::checkID3(UCHAR *b, int len) {
- if (len != 128) return -1;
- int rt=parseID3V1(b,len);
- if (rt >= 0) {
- char * str=id3->toString();
- log->log("DemuxerAudio",Log::DEBUG,"parseID3V1 found:%s",str);
- delete str;
- }
- return rt;
-}
-
-bool DemuxerAudio::isSync() {
- return inSync;
-}
-
-UINT DemuxerAudio::getSyncErrors() {
- return outOfSync;
-}
-
-ULONG DemuxerAudio::getBytesPerSecond()
-{
- ULONG bps=hdrBitrate;
- if (! hasHdrInfo) return 0;
- if (hdrBitrate != avrBitrate) {
- //we seem to have vbr
- if (hasVBRInfo) {
- //vbr stuff TODO
- bps=avrBitrate;
- }
- else {
- //some guessing
- bps=avrBitrate;
- }
- }
- bps=bps/8;
- return bps;
-}
-
-ULONG DemuxerAudio::getSecondsFromLen(ULONG len) {
- if (! hasHdrInfo) return 0;
- if (vbr) {
- //first find the index where we are between
- //rough starting point:
- ULONG idx=100*len/vbr->numBytes;
- if (idx >= 100) idx=99;
- ULONG idxPos=(vbr->table[idx]) * vbr->numBytes/256;
- ULONG pbefore=idxPos;
- ULONG pafter=idxPos;
- //OK now we know whether we have to go up or down
- if (idxPos > len) {
- //down
- while (idxPos > len && idx > 0) {
- pafter=idxPos;
- idx--;
- idxPos=(vbr->table[idx]) * vbr->numBytes/256;
- pbefore=idxPos;
- }
- //OK we are now before our postion
- }
- else {
- //up
- while (idxPos < len && idx < 100 ) {
- pbefore=idxPos;
- idx++;
- idxPos=(vbr->table[idx]) * vbr->numBytes/256;
- pafter=idxPos;
- }
- //after our position
- if (idx > 0) idx --;
- }
- //idx is now the index before our position
- //approximate between the 2 points
- ULONG idxTime=idx * vbr->fileSeconds/100;
- if (pafter == pbefore) return idxTime;
- ULONG rt=idxTime+ (len-pbefore)* vbr->fileSeconds/(100 * (pafter-pbefore)) ;
- if (rt > vbr -> fileSeconds) return vbr->fileSeconds;
- if (rt < idxTime) return idxTime;
- return rt;
- }
- else {
- ULONG bps=getBytesPerSecond();
- if (bps == 0) return 0;
- return len/bps;
- }
-}
-
-ULONG DemuxerAudio::positionFromSeconds(ULONG seconds) {
- if (! hasHdrInfo) return 0;
- if (vbr) {
- ULONG idx=seconds*100/vbr->fileSeconds;
- if (idx > 99) idx=99;
- ULONG idxPos=vbr->table[idx] * vbr->numBytes/256;
- ULONG idx2=idx;
- if (idx < 99) idx2++;
- ULONG nextPos=vbr->table[idx] * vbr->numBytes/256;
- ULONG rt=idxPos+(nextPos-idxPos) * (seconds - idx * vbr->fileSeconds /256);
- if (rt < idxPos) return idxPos;
- if ( rt > vbr->numBytes) return vbr->numBytes;
- return rt;
- }
- else {
- ULONG bps=getBytesPerSecond();
- return bps*seconds;
- }
-}
-
-int id3_tag::stringlen(bool withTitle) const {
- if (!withTitle)
- return strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+
- strlen(track)+strlen(composer)+strlen(comment)+8+3+
- 90; //30 chars for each name...
- else
- return strlen(title)+strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+
- strlen(track)+strlen(composer)+strlen(comment)+8+3+
- 120; //30 chars for each name...
-}
-//create a string out of the id3 tag info
-//delete this string afterwards if you did not provide the buffer
-char * id3_tag::toString(char *b, int len, bool withTitle) const {
- const char *ta=tr("Artist");
-//char *tg=tr("Genre");
-//char *ty=tr("Year");
- const char *tx=tr("Album");
-//char *to=tr("Composer");
-//char *tc=tr("Comment");
- const char *tn=tr("Track");
- /* in the moment:
- Title:
- Artist:
- Album: year - name
- Track:
- */
- if (b == NULL) {
- len=stringlen(withTitle);
- b=new char[len];
- }
- const char * del=" - ";
- if (strlen(year) == 0) del="";
- if (withTitle){
- const char *tt=tr("Title");
- SNPRINTF(b,len-1,"%s: %s\n%s: %s\n%s: %s%s%s\n%s: %s",
- tt,title,ta,artist,tx,year,del,album,tn,track);
- }
- else {
-SNPRINTF(b,len-1,"%s: %s\n%s: %s%s%s\n%s: %s",
- ta,artist,tx,year,del,album,tn,track);
- }
- b[len-1]=0;
- return b;
-}
-
-void DemuxerAudio::setSkipFactor(int factor) {
- Log::getInstance()->log("DemuxerAudio",Log::DEBUG,"set skipfactor %d\n",factor);
- buffer->setSkipFactor(factor);
-}
-
+/*\r
+ Copyright 2006 Mark Calderbank, Andreas Vogel\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "demuxeraudio.h"\r
+#include "audio.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+\r
+#define HDRBYTE1 0xff\r
+#define HDRBYTE2 0xe0\r
+#define HDRBYTE2MASK 0xe0\r
+\r
+\r
+\r
+class PacketBuffer {\r
+ \r
+ public:\r
+ PacketBuffer(Stream *as,UCHAR strtype) {\r
+ log=Log::getInstance();\r
+ audio=as;\r
+ streamtype=strtype;\r
+ newStream();\r
+ }\r
+ //just handle the data (do not deal with headers)\r
+ int putInternal(UCHAR* buf,int len,unsigned int &packetnum);\r
+ void reset(){\r
+ partPacket=0;\r
+ bytesWritten=0;\r
+ framelen=DemuxerAudio::PACKET_SIZE;\r
+ }\r
+ void newStream() {\r
+ reset();\r
+ numpackets=0;\r
+ numbytes=0;\r
+ skipfactor=0;\r
+ numskip=0;\r
+ }\r
+ bool bufferFull() {\r
+ return (partPacket>=framelen);\r
+ }\r
+ //can we write a new packet?\r
+ bool bufferEmpty() {\r
+ return partPacket==0;\r
+ }\r
+ //only set this, if buffer empty\r
+ //otherwise ignored!\r
+ bool setFramelen(int len) {\r
+ if (! bufferEmpty() ) return false;\r
+ if (len > (int)DemuxerAudio::PACKET_SIZE) return false;\r
+ framelen=len;\r
+ return true;\r
+ }\r
+ //how much bytes do we need to fill the packet?\r
+ int bytesMissing() {\r
+ return framelen-partPacket;\r
+ }\r
+ int getFramelen() {\r
+ return framelen;\r
+ }\r
+ void setSkipFactor(int factor) {\r
+ skipfactor=factor;\r
+ numskip=0;\r
+ }\r
+ private:\r
+ void packetWritten() {\r
+ numbytes+=framelen;\r
+ //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written packet %ld l=%d, bytes %ld",numpackets,framelen,numbytes);\r
+ numpackets++;\r
+ reset();\r
+ }\r
+ bool doSkip();\r
+ UCHAR store[DemuxerAudio::PACKET_SIZE]; // Storage for partial packets\r
+ int partPacket; // Length of partial packet stored from previous put()\r
+ int bytesWritten; //if they are !=0 and != framelength the stream is full...\r
+ int framelen;\r
+ Log * log;\r
+ Stream * audio;\r
+ UCHAR streamtype;\r
+ //global counters\r
+ ULONG numpackets;\r
+ ULONG numbytes;\r
+ int skipfactor;\r
+ int numskip;\r
+};\r
+\r
+\r
+DemuxerAudio::DemuxerAudio(int p_vID, int p_aID)\r
+{\r
+ inSync=false;\r
+ isStarting=true;\r
+ log=Log::getInstance();\r
+ readHeaders=0;\r
+ streamtype=Audio::MP3;\r
+ buffer=new PacketBuffer(&audiostream,streamtype);\r
+// buffer=new PacketBuffer(&teststream,streamtype);\r
+ globalBytesWritten=0;\r
+ packetnum=0;\r
+ id3=NULL;\r
+ info=NULL;\r
+ vbr=NULL;\r
+ reset();\r
+}\r
+\r
+DemuxerAudio::~DemuxerAudio() {\r
+ delete buffer;\r
+ if(info) delete info;\r
+ if(id3) delete id3;\r
+ if (vbr) delete vbr;\r
+}\r
+\r
+void DemuxerAudio::flush()\r
+{\r
+ Demuxer::flushAudio();\r
+ buffer->newStream();\r
+ tmpFill=0;\r
+}\r
+\r
+void DemuxerAudio::reset() {\r
+ buffer->newStream();\r
+ tmpFill=0;\r
+ readHeaders=0;\r
+ packetnum=0;\r
+ outOfSync=0;\r
+ globalBytesWritten=0;\r
+ if (id3) delete id3;\r
+ id3=NULL;\r
+ if (info) delete info;\r
+ info=NULL;\r
+ if (vbr) delete vbr;\r
+ vbr=NULL;\r
+ inSync=false;\r
+ hasHdrInfo=false;\r
+ hasVBRInfo=false;\r
+ isStarting=true;\r
+ hdrBitrate=128000;\r
+ hdrSamplingRate=44100;\r
+ avrBitrate=0;\r
+ hdrFramelen=0;\r
+ isStarting=true;\r
+}\r
+\r
+int DemuxerAudio::scan(UCHAR *buf, int len)\r
+{\r
+ //no differend pids here\r
+ return 0;\r
+}\r
+\r
+void DemuxerAudio::setVID(int p_vID)\r
+{\r
+}\r
+\r
+void DemuxerAudio::setAID(int p_aID,int type)\r
+{\r
+}\r
+\r
+static const char * id3_1_genre[] = {\r
+ "Blueshhh",\r
+ "Classic Rock",\r
+ "Country",\r
+ "Dance",\r
+ "Disco",\r
+ "Funk",\r
+ "Grunge",\r
+ "Hip-Hop",\r
+ "Jazz",\r
+ "Metal",\r
+ "New Age",\r
+ "Oldies",\r
+ "Other",\r
+ "Pop",\r
+ "R&B",\r
+ "Rap",\r
+ "Reggae",\r
+ "Rock",\r
+ "Techno",\r
+ "Industrial",\r
+ "Alternative",\r
+ "Ska",\r
+ "Death Metal",\r
+ "Pranks",\r
+ "Soundtrack",\r
+ "Euro-Techno",\r
+ "Ambient",\r
+ "Trip-Hop",\r
+ "Vocal",\r
+ "Jazz+Funk",\r
+ "Fusion",\r
+ "Trance",\r
+ "Classical",\r
+ "Instrumental",\r
+ "Acid",\r
+ "House",\r
+ "Game",\r
+ "Sound Clip",\r
+ "Gospel",\r
+ "Noise",\r
+ "AlternRock",\r
+ "Bass",\r
+ "Soul",\r
+ "Punk",\r
+ "Space",\r
+ "Meditative",\r
+ "Instrumental Pop",\r
+ "Instrumental Rock",\r
+ "Ethnic",\r
+ "Gothic",\r
+ "Darkwave",\r
+ "Techno-Industrial",\r
+ "Electronic",\r
+ "Pop-Folk",\r
+ "Eurodance",\r
+ "Dream",\r
+ "Southern Rock",\r
+ "Comedy",\r
+ "Cult",\r
+ "Gangsta",\r
+ "Top 40",\r
+ "Christian Rap",\r
+ "Pop/Funk",\r
+ "Jungle",\r
+ "Native American",\r
+ "Cabaret",\r
+ "New Wave",\r
+ "Psychadelic",\r
+ "Rave",\r
+ "Showtunes",\r
+ "Trailer",\r
+ "Lo-Fi",\r
+ "Tribal",\r
+ "Acid Punk",\r
+ "Acid Jazz",\r
+ "Polka",\r
+ "Retro",\r
+ "Musical",\r
+ "Rock & Roll",\r
+ "Hard Rock"\r
+};\r
+\r
+\r
+\r
+static int bitrateTable[16][5]={\r
+/* L1,L2,L3,2L1,2L2 */\r
+/*0000*/ {-1,-1,-1,-1,-1},\r
+/*0001*/ {32,32,32,32,8},\r
+/*0010*/ {64,48,40,48,16},\r
+/*0011*/ {96,56,48,56,24},\r
+/*0100*/ {128,64,56,64,32},\r
+/*0101*/ {160,80,64,80,40},\r
+/*0110*/ {192,96,80,96,48},\r
+/*0111*/ {224,112,96,112,56},\r
+/*1000*/ {256,128,112,128,64},\r
+/*1001*/ {288,160,128,144,80},\r
+/*1010*/ {320,192,160,160,96},\r
+/*1011*/ {352,224,192,176,112},\r
+/*1100*/ {384,256,224,192,128},\r
+/*1101*/ {416,320,256,224,144},\r
+/*1110*/ {448,384,320,256,160},\r
+/*1111*/ {-1,-1,-1,-1,-1} };\r
+\r
+static int samplingRateTable[4][3]={\r
+/*00*/ {44100,22050,11025},\r
+/*01*/ {48000,24000,12000},\r
+/*10*/ {32000,16000,8000},\r
+/*11*/ {-1,-1,-1}};\r
+\r
+//max 7 char!\r
+static const char * mpegString(UCHAR code) {\r
+ switch(code) {\r
+ case 0:\r
+ return "MPEG2.5";\r
+ case 1:\r
+ return "RESERV";\r
+ case 2:\r
+ return "MPEG 2";\r
+ case 3:\r
+ return "MPEG 1";\r
+ }\r
+ return "UNKNOWN";\r
+}\r
+\r
+static const char * layerString(UCHAR code) {\r
+ switch(code) {\r
+ case 0:\r
+ return "Layer reserved";\r
+ case 1:\r
+ return "Layer III";\r
+ case 2:\r
+ return "Layer II";\r
+ case 3:\r
+ return "Layer I";\r
+ }\r
+ return "Layer UNKNOWN";\r
+}\r
+/**\r
+ * parse an id3 Header\r
+ * provided by Brian Walton\r
+ * @returns -1 of nothing found\r
+ */\r
+ \r
+int DemuxerAudio::id3_2_3_FrameParse(unsigned char buf[], id3_frame *frame)\r
+{\r
+ if (buf[0] < 0x20 || buf[1] < 0x20 || buf [2] < 0x20 ) return -1;\r
+ frame->size = (buf[4] & 0x7F) << 21 | (buf[5] & 0x7F) << 14 | (buf[6] & 0x7F) << 7 | (buf[7] & 0x7F);\r
+ if (frame->size == 0) return -1;\r
+ //TODO. clearify flags against:\r
+ //http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b\r
+ frame->flags.tagAlterPreserv = (buf[8] & 0x80) >> 7;\r
+ frame->flags.filelterPreserv = (buf[8] & 0x40) >> 6;\r
+ frame->flags.readOnly = (buf[8] & 0x20) >> 5;\r
+ frame->flags.groupId = (buf[9] & 0x20) >> 5;\r
+ frame->flags.compression = (buf[9] & 0x80) >> 7;\r
+ frame->flags.encryption = (buf[9] & 0x40) >> 6;\r
+ frame->flags.unsync = 0;\r
+ frame->flags.dataLen = 0;\r
+ return 0;\r
+}\r
+\r
+ /**\r
+ * parse an id3 Header\r
+ * provided by Brian Walton\r
+ * @returns -1 of nothing found\r
+ */\r
+ \r
+int DemuxerAudio::id3_2_2_FrameParse(unsigned char buf[], id3_frame *frame)\r
+{\r
+ if (buf[0] < 0x20 || buf[1] < 0x20 || buf[2] < 0x20) return -1;\r
+ frame->size = (buf[3] & 0x7F) << 14 | (buf[4] & 0x7F) << 7 | (buf[5] & 0x7F);\r
+ if (frame->size == 0) return -1;\r
+ return 0;\r
+}\r
+\r
+\r
+//fill an id3tag from a frame payload\r
+//http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b\r
+//http://id3.org/id3v2-00\r
+static struct tagid {\r
+ const char * bytes;\r
+ int index;\r
+} knownFrames[]= {\r
+ //ID3V2.3\r
+ {"TIT2",1}, //title\r
+ {"TPE1",2}, //artist\r
+ {"TCON",3}, //genre\r
+ {"TRCK",6}, //track\r
+ {"TYER",4}, //year\r
+ {"TALB",5}, //album\r
+ {"TCOM",7}, //composer\r
+ {"COMM",8}, //comment\r
+ //Text encoding $xx\r
+ //Language $xx xx xx\r
+ //Short content descrip. <text string according to encoding> $00 (00)\r
+ //The actual text <full text string according to encoding>\r
+ //ID3V2.0\r
+ {"TT2",1 },\r
+ {"TP1",2 },\r
+ {"TCM",7 },\r
+ {"TCO",3 }, //(genreNumber)\r
+ {"TAL",5 },\r
+ {"TRK",6 },\r
+ {"TYE",4 },\r
+ {"COM",8 }\r
+};\r
+#define NUMKNOWN (sizeof(knownFrames)/sizeof(knownFrames[0]))\r
+\r
+/*fill in infos\r
+ from an ID3 V2.x, V2.3 frame into the tags structure\r
+ frameData must point to the header\r
+ framelen is the len without header (10 Bytes for V23, 6 Bytes for v2x)\r
+ */\r
+\r
+#define MAXLEN(tagtype) ((UINT)frameLen<sizeof(tag->tagtype)-1?(UINT)frameLen:sizeof(tag->tagtype)-1)\r
+bool DemuxerAudio::fillId3Tag(id3_tag * tag,UCHAR * frameData, int frameLen, int dataOffset, bool v23) {\r
+ int tl=v23?4:3;\r
+ int tagIndex=-1;\r
+ if (tag == NULL) return false;\r
+ if (frameLen < 2) return false;\r
+ for (UINT i=0;i< NUMKNOWN;i++) {\r
+ if(strncmp((char *)frameData,knownFrames[i].bytes,tl) == 0) {\r
+ tagIndex=knownFrames[i].index;\r
+ break;\r
+ }\r
+ }\r
+ if (tagIndex < 0) return false;\r
+ UCHAR encoding=*(frameData+dataOffset);\r
+ dataOffset++;\r
+ frameLen--;\r
+ if (encoding != 0) {\r
+ log->log("DemuxerAudio",Log::DEBUG,"unknown encoding for tag %d, tagid %s",encoding,\r
+ knownFrames[tagIndex].bytes);\r
+ return false;\r
+ }\r
+ switch(tagIndex) {\r
+ case 1: //title\r
+ strncpy(tag->title,(char*)(frameData+dataOffset),MAXLEN(title));\r
+ tag->title[MAXLEN(title)]=0;\r
+ break;\r
+ case 2: //artist\r
+ strncpy(tag->artist,(char*)(frameData+dataOffset),MAXLEN(artist));\r
+ tag->artist[MAXLEN(artist)]=0;\r
+ break;\r
+ case 3: //genre\r
+ {\r
+ UCHAR * st=frameData+dataOffset;\r
+ int genre=0;\r
+ if (*st=='(') {\r
+ genre=atoi((const char *)(st+1)) && 31;\r
+ st=(UCHAR *)id3_1_genre[genre];\r
+ }\r
+ strncpy(tag->genre,(char*)st,MAXLEN(genre));\r
+ tag->genre[MAXLEN(genre)]=0;\r
+ break;\r
+ }\r
+ case 4: //year\r
+ strncpy(tag->year,(char *)(frameData+dataOffset),MAXLEN(year));\r
+ tag->year[MAXLEN(year)]=0;\r
+ break;\r
+ case 5: //album\r
+ strncpy(tag->album,(char *)(frameData+dataOffset),MAXLEN(album));\r
+ tag->album[MAXLEN(album)]=0;\r
+ break;\r
+ case 6: //track\r
+ strncpy(tag->track,(char *)(frameData+dataOffset),MAXLEN(track));\r
+ tag->track[MAXLEN(track)]=0;\r
+ break;\r
+ case 7: //composer\r
+ strncpy(tag->composer,(char *)(frameData+dataOffset),MAXLEN(composer));\r
+ tag->composer[MAXLEN(composer)]=0;\r
+ break;\r
+ case 8: //comment\r
+ strncpy(tag->comment,(char *)(frameData+dataOffset),MAXLEN(comment));\r
+ tag->comment[MAXLEN(comment)]=0;\r
+ break;\r
+ default:\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+/**\r
+ * parse an id3 Header\r
+ * based on code provided by Brian Walton\r
+ * @returns -1 of nothing found\r
+ * otherwise the id3 info is filled\r
+ */\r
+\r
+int DemuxerAudio::parseID3V2(UCHAR *data, int len) {\r
+ int debug=0;\r
+ UCHAR * start=data;\r
+ id3_header id3header;\r
+ id3_frame id3frame;\r
+ id3_tag * id3tag=NULL;\r
+ //len = read(fd, data, 10);\r
+ if (len < 10) {\r
+ delete id3tag;\r
+ return -1;\r
+ }\r
+ len-=10;\r
+ if(data[0]=='I' && data[1]=='D' && data[2]=='3')\r
+ {\r
+ id3tag=new id3_tag();\r
+ id3header.major = data[3];\r
+ id3header.minor = data[4];\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 V2.%d.%d found\n", id3header.major, id3header.minor);\r
+ id3header.flags.unsynchronisation = (data[5] & 0x80)>>7;\r
+ id3header.flags.extended_header = (data[5] & 0x40)>>6;\r
+ id3header.flags.experimental = (data[5] & 0x20)>>5;\r
+ id3header.flags.footer = (data[5] & 0x10)>>4;\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Unsynchronisation flag: %d\n", id3header.flags.unsynchronisation);\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header flag: %d\n", id3header.flags.extended_header);\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Experimental indicator flag: %d\n", id3header.flags.experimental);\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Footer present flag: %d\n", id3header.flags.footer);\r
+ id3header.size = (data[6] & 0x7F) << 21 | (data[7] & 0x7F) << 14 | (data[8] & 0x7F) << 7 | (data[9] & 0x7F);\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 Size: %d\n", id3header.size);\r
+ data=start+10;\r
+ if (len <= id3header.size) {\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"header size to big %d, only %d bytes available\n",id3header.size,len);\r
+ delete id3tag;\r
+ return -1;\r
+ }\r
+ if (id3header.flags.extended_header)\r
+ {\r
+ int extended_hdr_hdr=4; //still to be discussed (id3.org...)\r
+ //read extended header size\r
+ if (len < extended_hdr_hdr) {\r
+ if (debug) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended header found but cannot read\n");\r
+ delete id3tag;\r
+ return -1;\r
+ }\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"remaining %d chars after extended hdr hdr\n", len);\r
+ id3header.extended_header.size = (data[0] & 0x7F) << 21 | (data[1] & 0x7F) << 14 | (data[2] & 0x7F) << 7 | (data[3] & 0x7F);\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header size: %d\n", id3header.extended_header.size);\r
+ if (len <= id3header.extended_header.size+extended_hdr_hdr) {\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended Header to big, only %d bytes available\n",len);\r
+ delete id3tag;\r
+ return -1;\r
+ }\r
+ //lseek(fd, id3header.extended_header.size - 6, SEEK_CUR);\r
+ data+=id3header.extended_header.size+extended_hdr_hdr;\r
+ len-=id3header.extended_header.size+extended_hdr_hdr;\r
+ }\r
+ //set the end of the header\r
+ UCHAR * eob=start+id3header.size+10;\r
+ bool readNext=true;\r
+ while (data < eob && readNext)\r
+ {\r
+ //skip over some padding - found this in lame MCDI tag...\r
+ if (*data == 0) {\r
+ data++;\r
+ continue;\r
+ }\r
+ readNext=false;\r
+ switch(id3header.major)\r
+ {\r
+ case 2: //ID3 V2.2.x\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.2 frame, %d : %c %c %c\n", data-start,*data,*(data+1),*(data+2));\r
+ if (data + 6 >= eob)\r
+ {\r
+ break;\r
+ }\r
+ if (id3_2_2_FrameParse(data, &id3frame) < 0)\r
+ {\r
+ break;\r
+ }\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame size: %d\n", id3frame.size);\r
+ fillId3Tag(id3tag,data,id3frame.size,6,false);\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + 6 +1);\r
+ data+=6+id3frame.size;\r
+ readNext=true;\r
+ break;\r
+ case 3: //ID3 V2.3.x\r
+ {\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.3 frame, %d : %c %c %c %c\n", data-start,\r
+ *data,*(data+1),*(data+2),*(data+3));\r
+ if (data + 10 >= eob)\r
+ {\r
+ break;\r
+ }\r
+ if (id3_2_3_FrameParse(data, &id3frame) <0)\r
+ {\r
+ break;\r
+ }\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame size: %d\n", id3frame.size);\r
+ int dataOffset=10;\r
+ if (id3frame.flags.groupId)\r
+ {\r
+ dataOffset++;\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame group: %d\n", data[dataOffset]);\r
+ }\r
+ if (id3frame.flags.compression)\r
+ {\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame compressed: %d\n", id3frame.flags.compression);\r
+ }\r
+ if (id3frame.flags.encryption)\r
+ {\r
+ dataOffset+=1;\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame encryption method: %d\n", data[dataOffset]);\r
+ }\r
+ fillId3Tag(id3tag,data,id3frame.size-dataOffset+10,dataOffset,true);\r
+ if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + dataOffset +1);\r
+ data+=10+id3frame.size;\r
+ readNext=true;\r
+ break;\r
+ }\r
+ default:\r
+ //don't support this version\r
+ delete id3tag;\r
+ return -1;\r
+ }\r
+ }\r
+\r
+ data=eob;\r
+ //store the found tag\r
+ if (id3) delete id3;\r
+ id3=id3tag;\r
+ return data-start;\r
+ }\r
+ return -1;\r
+}\r
+\r
+/**\r
+ * parse an id3v1 Header\r
+ * based on code provided by Brian Walton\r
+ * @returns -1 of nothing found\r
+ * otherwise the id3 info is filled\r
+ */\r
+#define MEMCPY(type,len,offset) {int type##max=sizeof(tag->type)-1<len?sizeof(tag->type)-1:len;strncpy(tag->type,(char*)&data[offset],type##max);tag->type[type##max]=0;}\r
+\r
+int DemuxerAudio::parseID3V1(UCHAR *data, int len) {\r
+ int debug=1;\r
+ if (len < 128) return -1;\r
+ if(data[0]=='T' && data[1]=='A' && data[2]=='G')\r
+ {\r
+ id3_tag * tag=new id3_tag();\r
+ if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1 tag found\n");\r
+ MEMCPY(title,30,3);\r
+ MEMCPY(artist,30,33);\r
+ MEMCPY(album,30,63);\r
+ MEMCPY(year,4,93);\r
+ if (data[125]==0 && data[126]!=0)\r
+ { //ID3 V1.1\r
+ if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.1 tag\n");\r
+ MEMCPY(comment,29,97);\r
+ sprintf(tag->track, "%d", data[126]);\r
+ } else {\r
+ if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.0 tag\n");\r
+ MEMCPY(comment,30,97);\r
+ }\r
+ if (data[127] < sizeof(id3_1_genre)/sizeof(id3_1_genre[0]))\r
+ {\r
+ sprintf(tag->genre, id3_1_genre[data[127]]);\r
+ }\r
+ if (id3) delete id3;\r
+ id3=tag;\r
+ return 0;\r
+ }\r
+ return -1;\r
+}\r
+\r
+//infos from http://www.multiweb.cz/twoinches/MP3inside.htm\r
+int DemuxerAudio::parseVBR(UCHAR *data, int len) {\r
+ UCHAR *hdr=findHeader(data,len);\r
+ //we expect the header exactly here\r
+ if (hdr != data) return -1;\r
+ const static char * VBRHDR="Xing";\r
+ int vbridpos=36;\r
+ UCHAR mpgtype=(data[1] & 0x18)>>3;\r
+ UCHAR chmode=(data[2] & 0xc0) >> 6;\r
+ UCHAR layer=(data[2] & 0x06) >>1;\r
+ if ( mpgtype == 3 && chmode == 11) vbridpos=21;\r
+ if ( mpgtype != 3 && chmode != 11) vbridpos=21;\r
+ if ( mpgtype != 3 && chmode == 11) vbridpos=13;\r
+ //check for the header ID\r
+ if (vbridpos+(int)strlen(VBRHDR)+4 >= len) {\r
+ Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header %d",len);\r
+ return -1;\r
+ }\r
+ for (int i=4;i<vbridpos;i++) {\r
+ if (data[i] != 0) {\r
+ Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"garbage when searching VBR header at pos %d",i);\r
+ return -1;\r
+ }\r
+ }\r
+ if ( strncmp((char *)&data[vbridpos],VBRHDR,strlen(VBRHDR)) != 0) {\r
+ Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"no VBR header at pos %d",vbridpos);\r
+ return -1;\r
+ }\r
+ int framedata=vbridpos+strlen(VBRHDR);\r
+ int expectedLen=0;\r
+ //OK we should now have a valid vbr header\r
+ bool hasFramenum=data[framedata+3] & 1;\r
+ bool hasBytes=data[framedata+3] & 0x2;\r
+ bool hasTOC=data[framedata+3] & 0x4;\r
+ expectedLen+=8;\r
+ if (hasTOC) expectedLen+=100;\r
+ if (framedata+expectedLen > len) {\r
+ Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header data %d, expected %d",\r
+ len,framedata+expectedLen);\r
+ return -1;\r
+ }\r
+ if (!hasFramenum || ! hasBytes || ! hasTOC) {\r
+ //not usefull for us..\r
+ Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"not all parts in VBR header - ignore");\r
+ return -1;\r
+ }\r
+ framedata+=4;\r
+ if (vbr) delete vbr;\r
+ vbr=new vbrInfo();\r
+ vbr->numFrames=data[framedata] << 24 | data[framedata+1]<<16|\r
+ data[framedata+2]<<8 |data[framedata+3];\r
+ framedata+=4;\r
+ vbr->numBytes=data[framedata] << 24 | data[framedata+1]<<16|\r
+ data[framedata+2]<<8 |data[framedata+3];\r
+ framedata+=4;\r
+ for (int ti=0;ti<100;ti++) {\r
+ vbr->table[ti]=data[framedata+ti];\r
+ }\r
+ //compute file size in seconds\r
+ //should be (#of frames -1) *samplesPerFrame / sampleRate\r
+ //TODO: difference for Mono?\r
+ ULONG samplesPerFrame=384; //layer1\r
+ if (layer != 3) samplesPerFrame=1152;\r
+ vbr->fileSeconds=(vbr->numFrames-1)*samplesPerFrame/hdrSamplingRate;\r
+ Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"successfully read VBR %ldbytes, %ld frames, %ldsec",\r
+ vbr->numBytes,vbr->numFrames,vbr->fileSeconds);\r
+ return hdrFramelen;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+UCHAR * DemuxerAudio::findHeader(UCHAR *buf, int len, bool writeInfo) {\r
+ while (len >= 3) //assume hdr+crc\r
+ {\r
+ UCHAR pattern=*buf;\r
+ buf++; len--;\r
+ if (pattern != HDRBYTE1 ) continue;\r
+ if ((*buf & HDRBYTE2MASK) != HDRBYTE2) continue;\r
+ if (readHeader((buf-1),4,writeInfo) != 0) continue;\r
+ return buf-1;\r
+ }\r
+ return NULL;\r
+}\r
+\r
+\r
+\r
+int DemuxerAudio::readHeader(UCHAR * hbuf,int len,bool writeInfo) {\r
+ int curFramelen=0;\r
+ int curBitrate=0;\r
+ int curSamplingRate=0;\r
+ if (*hbuf != HDRBYTE1) return -1;\r
+ hbuf++;\r
+ if ((*hbuf & HDRBYTE2MASK) != HDRBYTE2) return -1;\r
+ UCHAR mpgtype=(*hbuf & 0x18)>>3;\r
+ if (mpgtype == 1) {\r
+ log->log("DemuxerAudio",Log::DEBUG,"header invalid mpgtype %s %i %i %i",\r
+ mpegString(mpgtype),*hbuf,*(hbuf+1),*(hbuf+2));\r
+ return 1;\r
+ }\r
+ UCHAR layer=(*hbuf & 0x06) >>1;\r
+ //bool hasCRC=!(*hbuf & 1);\r
+ hbuf++;\r
+ UCHAR bitrateCode=(*hbuf & 0xf0) >>4;\r
+ UCHAR samplingCode=(*hbuf & 0x0c) >> 2;\r
+ bool padding=*hbuf & 0x02;\r
+ hbuf++;\r
+ //0 Stereo, 1 JointStereo, 2 Dual, 3 Mono\r
+ UCHAR chmode=(*hbuf & 0xc0) >> 6;\r
+ //UCHAR extension=(*hbuf & 0x30) >> 4;\r
+\r
+ //layercode: 1-L3, 2-L2, 3-L1\r
+ //columns 0,1,2 for MPEG1\r
+ UCHAR bitrateColumn=3-layer;\r
+ if (bitrateColumn > 2) {\r
+ log->log("DemuxerAudio",Log::DEBUG,"header invalid layer %s %i %i %i",\r
+ layerString(layer),*(hbuf-2),*(hbuf-1),*hbuf);\r
+ return 1;\r
+ }\r
+ if (mpgtype != 3) bitrateColumn+=3;\r
+ if (bitrateColumn>4) bitrateColumn=4;\r
+ curBitrate=1000*bitrateTable[bitrateCode][bitrateColumn];\r
+ UCHAR sampleRateColumn=0;\r
+ if (mpgtype == 10) sampleRateColumn=1;\r
+ if (mpgtype == 0) sampleRateColumn=2;\r
+ curSamplingRate=samplingRateTable[samplingCode][sampleRateColumn];\r
+ if (curSamplingRate < 0 || curBitrate < 0) {\r
+ log->log("DemuxerAudio",Log::DEBUG,"header invalid rates br=%d sr=%d %i %i %i",\r
+ curBitrate,curSamplingRate,*(hbuf-2),*(hbuf-1),*hbuf);\r
+ return 1;\r
+ }\r
+ int padbytes=0;\r
+ if (padding) {\r
+ if (layer == 3) padbytes=4;\r
+ else padbytes=1;\r
+ }\r
+ if (layer == 3) {\r
+ //Layer 1\r
+ //FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4\r
+ curFramelen=(12*curBitrate/curSamplingRate+padbytes) * 4;\r
+ }\r
+ else {\r
+ //Layer 2/3\r
+ //FrameLengthInBytes = 144 * BitRate / SampleRate + Padding\r
+ curFramelen=144*curBitrate/curSamplingRate+padbytes;\r
+ }\r
+ //the header itself\r
+ if (curFramelen < 32) {\r
+ log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d-invalid %i %i %i",\r
+ readHeaders,mpegString(mpgtype),layerString(layer),\r
+ curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf);\r
+ return 1;\r
+ }\r
+ if (writeInfo || isStarting){\r
+ log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d %i %i %i",\r
+ readHeaders,mpegString(mpgtype),layerString(layer),\r
+ curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf);\r
+ if (info) delete info;\r
+ info=new mpegInfo();\r
+ strcpy(info->mpegVersion,mpegString(mpgtype));\r
+ info->mpegLayer=4-layer;\r
+ info->bitRate=curBitrate;\r
+ info->avrBitrate=curBitrate;\r
+ info->sampleRate=curSamplingRate;\r
+ const char *chmodStr=tr("Stereo");\r
+ switch (chmode) {\r
+ case 1: chmodStr=tr("JointStereo");break;\r
+ case 2: chmodStr=tr("Dual");break;\r
+ case 3: chmodStr=tr("Mono");break;\r
+ }\r
+ SNPRINTF(info->info,sizeof(info->info)-1,"%s",chmodStr);\r
+ }\r
+ if (isStarting) avrBitrate=curBitrate;\r
+ isStarting=false;\r
+ readHeaders++;\r
+ //moving average F=0.005\r
+ avrBitrate=avrBitrate+((5*(curBitrate-avrBitrate))/1024);\r
+ hdrBitrate=curBitrate;\r
+ hdrFramelen=curFramelen;\r
+ hdrSamplingRate=curSamplingRate;\r
+ hasHdrInfo=true;\r
+ return 0;\r
+}\r
+\r
+int DemuxerAudio::findPTS(UCHAR* buf, int len, ULLONG* dest)\r
+{\r
+ //we have no PTS number ...\r
+ *dest=0;\r
+ return (findHeader(buf,len) != NULL)?1:0;\r
+}\r
+\r
+bool PacketBuffer::doSkip() {\r
+ if (!bufferFull()) return false;\r
+ if (skipfactor == 0) return false;\r
+ numskip++;\r
+ if (numskip >= skipfactor) {\r
+ //sent at least always 2 packets\r
+ if (numskip > skipfactor) numskip=0;\r
+ return false;\r
+ }\r
+ packetWritten();\r
+ return true;\r
+}\r
+ \r
+// just handle the real stream without dealing with the header\r
+int PacketBuffer::putInternal(UCHAR * wbuf, int len,unsigned int &packetnum)\r
+{\r
+ /* Important, the type passed to stream must be a mediapacket type as defined in \r
+ Draintarget.h and not the device setting of the mvp, so we have to translate it here,\r
+ in order to get it working on windows\r
+ --MR */\r
+ UCHAR mptype=0;\r
+ switch (streamtype) {\r
+ case Audio::MPEG1_PES: //?\r
+ case Audio::MPEG2_PES: //Important, this must be a PES !\r
+ mptype=MPTYPE_MPEG_AUDIO; break;\r
+ default:\r
+ case Audio::MP3: //this can be any Mpeg1 Audio not only layer 3 not packed into PES\r
+ mptype=MPTYPE_MPEG_AUDIO_LAYER3;break;\r
+ };\r
+ if (bufferFull()) {\r
+#ifndef WIN32\r
+ if (doSkip()) return 0;//NoSkip on Windows\r
+#endif\r
+ //we are still full - so try to write\r
+ int sent=audio->put(store+bytesWritten,framelen-bytesWritten,/*streamtype*/mptype,packetnum);packetnum++;\r
+ //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream (still full) pp=%d, framelen=%d, written=%d",sent,partPacket,framelen, bytesWritten );\r
+ if (sent < (framelen - bytesWritten)) {\r
+ //packet still not written\r
+ bytesWritten+=sent;\r
+ return 0;\r
+ }\r
+ packetWritten();\r
+ //let the demuxer come back with the rest - need to check header first\r
+ return 0;\r
+ }\r
+ if (partPacket+len >= framelen) {\r
+ //now we have at least a complete packet\r
+ int bytesConsumed=framelen-partPacket;\r
+ memcpy(store+partPacket,wbuf,bytesConsumed);\r
+ partPacket=framelen;\r
+ //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"stored packet %ld, length %d (last %d) for stream %p",numpackets,framelen,bytesConsumed,audio );\r
+#ifndef WIN32 //No Skip on Windows\r
+ if (doSkip()) return bytesConsumed;\r
+#endif\r
+ int sent=audio->put(store,framelen,mptype,packetnum);packetnum++;\r
+ bytesWritten+=sent;\r
+ //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream",sent );\r
+ if (bytesWritten < framelen) {\r
+ //still not completely written\r
+ return bytesConsumed;\r
+ }\r
+ packetWritten();\r
+ //let the player come back...\r
+ return bytesConsumed;\r
+ }\r
+ //OK packet still not complete\r
+ if (len == 0) return 0;\r
+ int bytesConsumed=len;\r
+ memcpy(store+partPacket,wbuf,bytesConsumed);\r
+ partPacket+=bytesConsumed;\r
+ return bytesConsumed;\r
+}\r
+\r
+/**\r
+ major entry for data from a player\r
+ the demuxer is either in the state headerSearch (packet written or\r
+ just at the beginning), writing garbage (inSync=false) or\r
+ handling data (none set)\r
+ A header is expected at the first byte after the previous packet -\r
+ otherwise we switch to garbage where we always search for a header\r
+ (but anyway provide the data to the underlying device - it's probably\r
+ more intelligent then we are...\r
+ We only loose a correct position display.\r
+ */\r
+int DemuxerAudio::put(UCHAR* wbuf, int len)\r
+{\r
+ //return audiostream.put(wbuf,len,streamtype);\r
+ int framelen=PACKET_SIZE;\r
+ UCHAR *hdr;\r
+ int bytesConsumed=0;\r
+ int oldBytes=0;\r
+ if (tmpFill != 0 || (buffer->bufferEmpty() && len < HDRLEN)) {\r
+ //OK we have to copy everything to the tmp buffer\r
+ int cp=(UINT)len<(PACKET_SIZE-tmpFill)?(UINT)len:(PACKET_SIZE-tmpFill);\r
+ memcpy(&tmpBuffer[tmpFill],wbuf,cp);\r
+ oldBytes=tmpFill;\r
+ tmpFill+=cp;\r
+ wbuf=tmpBuffer;\r
+ len=tmpFill;\r
+ //if there is no header here and our buffer\r
+ //is empty - just wait for the next header\r
+ if (len < HDRLEN && buffer->bufferEmpty()) {\r
+ log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten);\r
+ return cp;\r
+ }\r
+ }\r
+ while (bytesConsumed < len ) {\r
+ if (buffer->bufferFull()) {\r
+ //if this is the first part of the loop, try to write to the stream\r
+ if (bytesConsumed == 0) buffer->putInternal(wbuf,0,packetnum);\r
+ //if the buffer is full, no need to continue\r
+ if (buffer->bufferFull()) break;\r
+ }\r
+ //either we are in a packet (buffer != full && buffer != empty)\r
+ //or we are searching a header\r
+ if (buffer->bufferEmpty()) {\r
+ if (len-bytesConsumed < HDRLEN) {\r
+ // we cannot still search\r
+ if (tmpFill != 0) {\r
+ //we are already working at the buffer\r
+ break;\r
+ }\r
+ memcpy(tmpBuffer,wbuf,len-bytesConsumed);\r
+ tmpFill=len-bytesConsumed;\r
+ log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten);\r
+ return len;\r
+ }\r
+\r
+ int lastFramelen=hdrFramelen;\r
+ //if the header has been valid before and we are searching\r
+ //it should be here\r
+ int maxsearch=((len-bytesConsumed) < (int)PACKET_SIZE)?len-bytesConsumed:(int)PACKET_SIZE;\r
+ hdr=findHeader(wbuf,maxsearch);\r
+ if (hdr != NULL) {\r
+ //log->log("DemuxerAudio",Log::DEBUG,"header found at offset %d",hdr-wbuf);\r
+ }\r
+ //hdr now points to the new header\r
+ if (hdr != wbuf) {\r
+ //still at least bytes before the header\r
+ inSync=false;\r
+ outOfSync++;\r
+ int garbageBytes=(hdr!=NULL)?(hdr-wbuf):maxsearch;\r
+ //we consider the garbage now as an own packet\r
+ //we can consume at most our buffer\r
+ //basically the buffer should be empty here (we are\r
+ //in header search - and we fill up each garbage\r
+\r
+ int nframesize=garbageBytes;\r
+ if (nframesize > (int)PACKET_SIZE) {\r
+ nframesize=(int)PACKET_SIZE;\r
+ }\r
+ if (! buffer->bufferEmpty()) {\r
+ log->log("DemuxerAudio",Log::WARN,"buffer not empty when having garbage to store");\r
+ //at the end no big problem, we only write the remaining bytes that we have...\r
+ }\r
+ else {\r
+ buffer->setFramelen(nframesize);\r
+ }\r
+ log->log("DemuxerAudio",Log::DEBUG,"garbage found at packet %ld (bytes %ld) of length %d, "\r
+ "framelen set to %d (last fl=%d)",\r
+ readHeaders,globalBytesWritten,garbageBytes,buffer->getFramelen(),lastFramelen);\r
+#ifndef WIN32 \r
+ //hmm - we assume that he low level driver is more intelligent\r
+ //and give him the data "as is"\r
+ int written=buffer->putInternal(wbuf,garbageBytes,packetnum);\r
+ globalBytesWritten+=written;\r
+ bytesConsumed+=written;\r
+ if (written != garbageBytes || hdr == NULL ) {\r
+ break;\r
+ }\r
+#else //DS is not intelligent\r
+ globalBytesWritten+=garbageBytes;\r
+ bytesConsumed+=garbageBytes;\r
+#endif\r
+ //OK either all the "garbage" is written or\r
+ //we found the next header as expected\r
+ //continue with the next package\r
+ wbuf=hdr;\r
+ }\r
+ //we have to wait now until the buffer is \r
+ //free for the next package\r
+ if ( ! buffer->bufferEmpty()) return bytesConsumed;\r
+ //this is the place where we start a new packet\r
+ framelen=hdrFramelen;\r
+ if ( !buffer->setFramelen(framelen) ) {\r
+ log->log("DemuxerAudio",Log::DEBUG,"unable to set framelen should=%d, current=%d",\r
+ framelen,buffer->getFramelen());\r
+ }\r
+ inSync=true;\r
+ }\r
+ //now we are surely within a packet\r
+ int written=buffer->putInternal(wbuf,len-bytesConsumed,packetnum);\r
+ //update the status\r
+ globalBytesWritten+=written;\r
+ wbuf+=written;\r
+ bytesConsumed+=written;\r
+ if (written == 0) {\r
+ //stream is full\r
+ break;\r
+ }\r
+ //OK - handle the rest\r
+ }\r
+ if (bytesConsumed >= oldBytes) {\r
+ //if we consumed more than the old bytes - OK the buffer\r
+ //can be thrown away\r
+ tmpFill=0;\r
+ return bytesConsumed-oldBytes;\r
+ }\r
+ else {\r
+ //only consumed bytes from the buffer\r
+ if (bytesConsumed == 0) {\r
+ //restore the buffer\r
+ tmpFill=oldBytes;\r
+ return 0;\r
+ }\r
+ //shift bytes in buffer\r
+ for (int i=0;i<oldBytes-bytesConsumed;i++) {\r
+ tmpBuffer[i]=tmpBuffer[i+bytesConsumed];\r
+ }\r
+ tmpFill=oldBytes-bytesConsumed;\r
+ return 0;\r
+ }\r
+}\r
+\r
+//info functions\r
+const id3_tag * DemuxerAudio::getId3Tag() {\r
+ return id3;\r
+\r
+}\r
+const DemuxerAudio::mpegInfo * DemuxerAudio::getMpegInfo() {\r
+ if (! hasHdrInfo) return NULL;\r
+ info->avrBitrate=avrBitrate;\r
+ info->bitRate=hdrBitrate;\r
+ return info;\r
+}\r
+\r
+const DemuxerAudio::vbrInfo * DemuxerAudio::getVBRINfo() {\r
+ return vbr;\r
+}\r
+\r
+int DemuxerAudio::checkStart(UCHAR *b, int len) {\r
+ UCHAR *start=b;\r
+ int id3len=parseID3V2(b,len);\r
+ if (id3len > 0) {\r
+ char * str=id3->toString();\r
+ log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 %d bytes of %d",id3len,len);\r
+ log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 found:%s",str);\r
+ delete str;\r
+ b+=id3len;\r
+ len-=id3len;\r
+ }\r
+ int vbrlen=parseVBR(b,len);\r
+ if (vbrlen > 0 ) {\r
+ hasVBRInfo=true;\r
+ b+=vbrlen;\r
+ len-=vbrlen;\r
+ }\r
+ UCHAR * hdr=findHeader(b,len,true);\r
+ if (hdr == NULL) return -1;\r
+ return hdr-start;\r
+}\r
+\r
+int DemuxerAudio::checkID3(UCHAR *b, int len) {\r
+ if (len != 128) return -1;\r
+ int rt=parseID3V1(b,len);\r
+ if (rt >= 0) {\r
+ char * str=id3->toString();\r
+ log->log("DemuxerAudio",Log::DEBUG,"parseID3V1 found:%s",str);\r
+ delete str;\r
+ }\r
+ return rt;\r
+}\r
+\r
+bool DemuxerAudio::isSync() {\r
+ return inSync;\r
+}\r
+\r
+UINT DemuxerAudio::getSyncErrors() {\r
+ return outOfSync;\r
+}\r
+\r
+ULONG DemuxerAudio::getBytesPerSecond()\r
+{\r
+ ULONG bps=hdrBitrate;\r
+ if (! hasHdrInfo) return 0;\r
+ if (hdrBitrate != avrBitrate) {\r
+ //we seem to have vbr\r
+ if (hasVBRInfo) {\r
+ //vbr stuff TODO\r
+ bps=avrBitrate;\r
+ }\r
+ else {\r
+ //some guessing\r
+ bps=avrBitrate;\r
+ }\r
+ }\r
+ bps=bps/8;\r
+ return bps;\r
+}\r
+\r
+ULONG DemuxerAudio::getSecondsFromLen(ULONG len) {\r
+ if (! hasHdrInfo) return 0;\r
+ if (vbr) {\r
+ //first find the index where we are between\r
+ //rough starting point:\r
+ ULONG idx=100*len/vbr->numBytes;\r
+ if (idx >= 100) idx=99;\r
+ ULONG idxPos=(vbr->table[idx]) * vbr->numBytes/256;\r
+ ULONG pbefore=idxPos;\r
+ ULONG pafter=idxPos;\r
+ //OK now we know whether we have to go up or down\r
+ if (idxPos > len) {\r
+ //down\r
+ while (idxPos > len && idx > 0) {\r
+ pafter=idxPos;\r
+ idx--;\r
+ idxPos=(vbr->table[idx]) * vbr->numBytes/256;\r
+ pbefore=idxPos;\r
+ }\r
+ //OK we are now before our postion\r
+ }\r
+ else {\r
+ //up\r
+ while (idxPos < len && idx < 100 ) {\r
+ pbefore=idxPos;\r
+ idx++;\r
+ idxPos=(vbr->table[idx]) * vbr->numBytes/256;\r
+ pafter=idxPos;\r
+ }\r
+ //after our position\r
+ if (idx > 0) idx --;\r
+ }\r
+ //idx is now the index before our position\r
+ //approximate between the 2 points\r
+ ULONG idxTime=idx * vbr->fileSeconds/100;\r
+ if (pafter == pbefore) return idxTime;\r
+ ULONG rt=idxTime+ (len-pbefore)* vbr->fileSeconds/(100 * (pafter-pbefore)) ;\r
+ if (rt > vbr -> fileSeconds) return vbr->fileSeconds;\r
+ if (rt < idxTime) return idxTime;\r
+ return rt;\r
+ }\r
+ else {\r
+ ULONG bps=getBytesPerSecond();\r
+ if (bps == 0) return 0;\r
+ return len/bps;\r
+ }\r
+}\r
+ \r
+ULONG DemuxerAudio::positionFromSeconds(ULONG seconds) {\r
+ if (! hasHdrInfo) return 0;\r
+ if (vbr) {\r
+ ULONG idx=seconds*100/vbr->fileSeconds;\r
+ if (idx > 99) idx=99;\r
+ ULONG idxPos=vbr->table[idx] * vbr->numBytes/256;\r
+ ULONG idx2=idx;\r
+ if (idx < 99) idx2++;\r
+ ULONG nextPos=vbr->table[idx] * vbr->numBytes/256;\r
+ ULONG rt=idxPos+(nextPos-idxPos) * (seconds - idx * vbr->fileSeconds /256);\r
+ if (rt < idxPos) return idxPos;\r
+ if ( rt > vbr->numBytes) return vbr->numBytes;\r
+ return rt;\r
+ }\r
+ else {\r
+ ULONG bps=getBytesPerSecond();\r
+ return bps*seconds;\r
+ }\r
+}\r
+\r
+int id3_tag::stringlen(bool withTitle) const {\r
+ if (!withTitle)\r
+ return strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+\r
+ strlen(track)+strlen(composer)+strlen(comment)+8+3+\r
+ 90; //30 chars for each name...\r
+ else\r
+ return strlen(title)+strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+\r
+ strlen(track)+strlen(composer)+strlen(comment)+8+3+\r
+ 120; //30 chars for each name...\r
+}\r
+//create a string out of the id3 tag info\r
+//delete this string afterwards if you did not provide the buffer\r
+char * id3_tag::toString(char *b, int len, bool withTitle) const {\r
+ const char *ta=tr("Artist");\r
+//char *tg=tr("Genre");\r
+//char *ty=tr("Year");\r
+ const char *tx=tr("Album");\r
+//char *to=tr("Composer");\r
+//char *tc=tr("Comment");\r
+ const char *tn=tr("Track");\r
+ /* in the moment:\r
+ Title: \r
+ Artist:\r
+ Album: year - name\r
+ Track:\r
+ */\r
+ if (b == NULL) {\r
+ len=stringlen(withTitle);\r
+ b=new char[len];\r
+ }\r
+ const char * del=" - ";\r
+ if (strlen(year) == 0) del="";\r
+ if (withTitle){\r
+ const char *tt=tr("Title");\r
+ SNPRINTF(b,len-1,"%s: %s\n%s: %s\n%s: %s%s%s\n%s: %s",\r
+ tt,title,ta,artist,tx,year,del,album,tn,track);\r
+ }\r
+ else {\r
+SNPRINTF(b,len-1,"%s: %s\n%s: %s%s%s\n%s: %s",\r
+ ta,artist,tx,year,del,album,tn,track);\r
+ }\r
+ b[len-1]=0;\r
+ return b;\r
+}\r
+\r
+void DemuxerAudio::setSkipFactor(int factor) {\r
+ Log::getInstance()->log("DemuxerAudio",Log::DEBUG,"set skipfactor %d\n",factor);\r
+ buffer->setSkipFactor(factor);\r
+}\r
+\r
-/*
- Copyright 2006-2008 Mark Calderbank
-
- 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 "demuxerts.h"
-#include "log.h"
-#include "video.h"
-#include "vdr.h"
-
-#define PTS_JUMP_MARGIN 10000
-#define PTS_ALLOWANCE 90000
-
-// TODO: PTS class to handle wrapping arithmetic & comparisons?
-static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)
-{
- // Assume pts1, pts2 < 2^33; calculate shortest distance between
- ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;
- if (ret > (1LL<<32)) ret = (1LL<<33) - ret;
- return ret;
-}
-
-static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
-{
- // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
- if (pts1 > pts2)
- return pts1 - pts2;
- else
- return (1LL<<33) + pts1 - pts2;
-}
-
-DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID)
-{
- vID = p_vID; vActive = false;
- aID = p_aID; aActive = false;
- subID = p_subID; subActive = false;
- atype = 0;
- subLength = 0;
- tID = p_tID;
- havechannelinfo=false;
- doubledframerate=false;
- framereserve=0;
-}
-
-void DemuxerTS::flush()
-{
- partPacket = 0;
- parsed = false;
- havechannelinfo=false;
- Demuxer::flush();
- vPacket.init(PESTYPE_VID0);
- switch (atype)
- {
- case 1:
- aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
- break;
- default:
- case 0:
- aPacket.init(PESTYPE_AUD0);
- break;
- }
- subPacket.init(PESTYPE_PRIVATE_1);
-tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
-
- vActive = false;
- aActive = false;
- subActive = false;
- subLength = 0;
- tActive = false;
- doubledframerate=false;
- framereserve=0;
-}
-
-int DemuxerTS::scan(UCHAR *buf, int len)
-{
- switch (atype)
- {
- case 1:
- return PESTYPE_PRIVATE_1;
- default:
- case 0:
- return PESTYPE_AUD0;
- }
-}
-
-void DemuxerTS::setVID(int p_vID)
-{
- vID = p_vID;
- vPacket.init(PESTYPE_VID0);
- vActive = false;
-}
-
-void DemuxerTS::setAID(int p_aID, int type)
-{
- aID = p_aID;
- atype = type;
- switch (atype)
- {
- case 1:
- aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
- setAudioStream(PESTYPE_SUBSTREAM_AC30);
- break;
- default:
- case 0:
- aPacket.init(PESTYPE_AUD0);
- setAudioStream(PESTYPE_AUD0);
- break;
- }
- aActive = false;
-}
-
-void DemuxerTS::setSubID(int p_subID)
-{
- subID = p_subID;
- subPacket.init(PESTYPE_PRIVATE_1);
- subActive = false;
- subLength = 0;
-}
-
-void DemuxerTS::setTID(int p_tID)
-{
- tID = p_tID;
- tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
- tActive = false;
-
-}
-
-
-
-
-int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)
-{
- int scanaid=0;
-
- while (len >= TS_SIZE)
- {
- if (*buf != TS_SIG) {buf++;len--; continue;}
-
- //Pattern scanning won't work for ts
-
-
- int datalen = TS_SIZE - 4;
- int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
- UCHAR payload = buf[1] & 0x40;
-
- if (buf[3] & 0x20) // Adaptation field is present
- datalen -= (buf[4] + 1);
-
- UCHAR* curbuf =buf+ (TS_SIZE - datalen);
-
-
- if (payload) {
- if (pid == 0x00) {//PAT, only take first program number, ignore the rest
- int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);
- if ((pmtpid >> 13) != 0x07)
- {
- Log::getInstance()->log("findPTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));
- }
- else
- {
- pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
- PMTPID = pmtpid;
- }
-
- } else if (pid == PMTPID) { //PMT
- int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);
- //sectionlength += 4; //include header but subtract crc in the end...
- int p = 13; //skip fixed part of pmt
- while ( p < sectionlength) {
- int streamtype = *(curbuf+p);
- p++;
- int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);
- p += 2; //skip ES Pid
- int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);
- p += 2; //skip ES length
- if ((foundpid >> 13) != 0x07)
- {
- Log::getInstance()->log("findPTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));
- }
- else
- {
- foundpid = foundpid & 0x1FFF; //clear upper 3 bits
- //int pos=0; UNUSED?
- if (streamtype==3 || streamtype ==4) {
- scanaid=foundpid;
- }
- }
- p += eslength; //skip es descriptor
- }
- } else if (pid == scanaid) {
- // UINT framelength = ((UINT)curbuf[4] << 8) | curbuf[5]; UNUSED?
-
- if ( curbuf[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
- {
- *dest = ( (ULLONG)(curbuf[9] & 0x0E) << 29 ) |
- ( (ULLONG)(curbuf[10]) << 22 ) |
- ( (ULLONG)(curbuf[11] & 0xFE) << 14 ) |
- ( (ULLONG)(curbuf[12]) << 7 ) |
- ( (ULLONG)(curbuf[13] & 0xFE) >> 1 );
- return 1;
- }
- }
- }
- len-=TS_SIZE;
- buf+=TS_SIZE;
- }
- // No PTS found.
- return 0;
-}
-
-void DemuxerTS::setFrameNum(ULONG frame)
-{
- frameCounting = true;
- frameNumber = frame;
- framereserve=0;
- Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setFrameNum %d", frame);
-}
-
-void DemuxerTS::setPacketNum(ULONG npacket)
-{
- packetCounting = true;
- packetNumber = npacket;
- Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setPacketNum %d", npacket);
-}
-
-
-int DemuxerTS::put(UCHAR* buf, int len)
-{
- int ret = 0; // return number of bytes consumed
-
- while (partPacket)
- {
- if (len >= TS_SIZE + 1 - partPacket)
- { // Remainder of partial packet is available, plus one
- memcpy(store+partPacket, buf, TS_SIZE - partPacket);
- ret += TS_SIZE - partPacket;
- buf += TS_SIZE - partPacket;
- len -= TS_SIZE - partPacket;
- partPacket = TS_SIZE;
- if (*buf == TS_SIG)
- { // Packet is properly terminated
- int rc = processTS(store);
- if (rc)
- partPacket = 0; // Successfully processed
- else
- return ret; // Try again later.
- }
- else
- { // Packet not terminated. Find another candidate, and shift store
- Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!");
- int search = 1;
- while (search < partPacket && store[search] != TS_SIG)
- search++;
- partPacket -= search;
- if (partPacket) memcpy(store, store+search, partPacket);
- }
- }
- else
- { // Still don't have complete packet. Consume what we do have.
- memcpy(store+partPacket, buf, len);
- partPacket += len;
- ret += len;
- return ret;
- }
- }
-
- // Position ourselves at a candidate TS packet
- while (len > 0 && *buf != TS_SIG)
- {
- Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!");
- buf++; ret++; len--;
- }
-
- while (len)
- {
- if (len < TS_SIZE + 1)
- { // Not enough data. Store what we have.
- memcpy(store, buf, len);
- partPacket = len;
- ret += len;
- return ret;
- }
-
- if (buf[TS_SIZE] != TS_SIG)
- { // Not terminated correctly.
- buf++; ret++; len--;
- while (len > 0 && *buf != TS_SIG)
- {
- buf++; ret++; len--;
- }
- }
- else
- {
- int rc = processTS(buf);
- if (rc)
- { // Successfully processed
- buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE;
- }
- else
- { // Processing failed.
- return ret;
- }
- }
- }
- return ret;
-}
-
-int DemuxerTS::processTS(UCHAR* buf)
-{
- int datalen = TS_SIZE - 4;
-
- int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
- UCHAR payload = buf[1] & 0x40;
-
- if (buf[3] & 0x20) // Adaptation field is present
- datalen -= (buf[4] + 1);
- if (datalen < 0) // Error in stream TODO log this
- return 1;
- if (datalen == 0) // Null packet
- return 1;
- buf += (TS_SIZE - datalen);
-
- if (payload)
- {
- int rc = 1;
- if (pid == 0x00) {//PAT, only take first program number, ignore the rest
- int pmtpid = (*(buf+11)<< 8) | *(buf+12);
- if ((pmtpid >> 13) != 0x07)
- {
- Log::getInstance()->log("ProcessTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(buf+11),*(buf+12), (pmtpid >> 13));
- }
- else
- {
- pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
- PMTPID = pmtpid;
- }
- return 1;
- }
- if (pid == PMTPID)
- { //PMT
- int sectionlength = ((*(buf+2) << 8) & 0x0F ) | *(buf+3);
- //sectionlength += 4; //include header but subtract crc in the end...
- int p = 13; //skip fixed part of pmt
- Channel new_channelinfo;
- new_channelinfo.numAPids=0;
- new_channelinfo.numDPids=0;
- new_channelinfo.numSPids=0;
- new_channelinfo.number=0;
- new_channelinfo.type=VDR::RADIO;
- new_channelinfo.name=NULL;
- new_channelinfo.tpid=0xFFFFF; //unused, check this
- new_channelinfo.vpid=0xFFFFF; //unused, check this
- new_channelinfo.index=0;
-
- new_channelinfo.apids.clear();
- new_channelinfo.dpids.clear();
- new_channelinfo.spids.clear();
-
- while ( p < sectionlength) {
- int streamtype = *(buf+p);
- p++;
- int foundpid = (*(buf+p)<< 8) | *(buf+p+1);
- p += 2; //skip ES Pid
- int eslength = ((*(buf+p) << 8) & 0x0F ) | *(buf+p+1);
- p += 2; //skip ES length
- if ((foundpid >> 13) != 0x07)
- {
- Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));
- }
- else
- {
- foundpid = foundpid & 0x1FFF; //clear upper 3 bits
- bool notfound=false;
- int pos=0;
- // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID is %x", foundpid);
- switch (streamtype)
- {
- case 0x1B: //MPEG 4 for future use
- case 1:
- case 2: { //video
- if (foundpid != getVID())
- setVID(foundpid);
- new_channelinfo.type=VDR::VIDEO;
- new_channelinfo.vstreamtype=streamtype;
- new_channelinfo.vpid=foundpid;
- if (streamtype==0x1b) h264=true;
- else h264=false;
-
- // Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid);
- }break;
- case 3:
- case 4: { //audio
- apid newapid;
- newapid.pid = foundpid;
- newapid.name = NULL; //set it in player
- new_channelinfo.apids.push_back(newapid);
- new_channelinfo.numAPids++;
- if (getAID() == 0) { //set unset AID to first audio pid that reports itself
- setAID(foundpid,0);
- Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set audio PID to %x", foundpid);
- }
- } break;
- case 5:
- case 6: { //Private Data
- apid newapid;
- newapid.pid = foundpid;
- newapid.name = NULL; //set it in player
- pos=0;
- notfound=true;
-
- while (pos< eslength && notfound) {
- switch (buf[p+pos]) {
- case 0x6A: {//Ac3 descriptor
- new_channelinfo.dpids.push_back(newapid);
- new_channelinfo.numDPids++;
- notfound=false;
- } break;
- case 0x59: {//SubtitlingDescriptor
- new_channelinfo.spids.push_back(newapid);
- new_channelinfo.numSPids++;
- notfound=false;
- } break;
- case 0x56: {
- new_channelinfo.tpid=foundpid;
- notfound=false;
- } break;
- };
- pos+=2+buf[p+pos+1];
- }
-
- } break;
- default://TODO how about subtitles and second audio pids
- break;
- }
- }
-
- p += eslength; //skip es descriptor
-
-
- }
- bool audioPIDpresent=false; //Check if pids chnages
- ULONG i;
- for (i=0;i<channelinfo.numAPids;i++) {
- if (aID == (int)channelinfo.apids[i].pid) {
- audioPIDpresent=true;
- }
- }
- for (i=0;i<channelinfo.numDPids && (! audioPIDpresent);i++) {
- if (aID == (int)channelinfo.dpids[i].pid) {
- audioPIDpresent=true;
- }
- }
- if (! audioPIDpresent) {
- if (channelinfo.numAPids>0) {
- setAID(channelinfo.apids[0].pid,0);
- } else if (channelinfo.numDPids>0) {
- setAID(channelinfo.dpids[0].pid,1);
- }
- }
-
- channelinfo=new_channelinfo;
- havechannelinfo=true;
-
- return 1;
- }
-
-
-
-
- if (pid == vID)
- {
- if (vActive)
- {
- if (!parsed)
- {
- parseTSPacketDetails(vPacket);
- parsed = true;
- }
- rc = submitPacket(vPacket);
- }
- vActive = true;
- }
- if (pid == aID)
- {
- if (aActive)
- {
- if (!parsed)
- {
- parseTSPacketDetails(aPacket);
- parsed = true;
- }
- rc = submitPacket(aPacket);
- }
- aActive = true;
- }
- if (pid == subID)
- {
- if (subActive)
- {
- if (!parsed)
- {
- parseTSPacketDetails(subPacket);
- parsed = true;
- }
- rc = submitPacket(subPacket);
- }
- subActive = true;
- }
- if (isteletextdecoded && pid == tID)
- {
- if (tActive)
- {
- if (!parsed)
- {
- parseTSPacketDetails(tPacket);
- parsed = true;
- }
- rc = submitPacket(tPacket);
- }
- tActive = true;
- }
- if (rc == 0) return 0;
-
- parsed = false;
- if (pid == vID)
- {
- vPacket.init(PESTYPE_VID0);
- buf += 6; datalen -= 6;
- }
- if (pid == aID)
- {
- switch (atype)
- {
- case 1:
- aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
- break;
- default:
- case 0:
- aPacket.init(PESTYPE_AUD0);
- break;
- }
- buf += 6; datalen -= 6;
- }
- if (pid == subID)
- {
- subPacket.init(PESTYPE_PRIVATE_1);
- subLength = (buf[4] << 8) + buf[5];
- buf += 6; datalen -= 6;
- }
- if (isteletextdecoded && pid == tID)
- {
- tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
- buf += 6; datalen -= 6;
- }
- }
-
- if ( (pid == vID && vActive) ||
- (pid == aID && aActive) ||
- (pid == tID && tActive) ||
- (pid == subID && subActive) )
- {
- PESPacket* packet = NULL;
- if (pid == vID) packet = &vPacket;
- if (pid == aID) packet = &aPacket;
- if (pid == subID) {
- packet = &subPacket;
- }
- if (pid == tID) packet = &tPacket;
- if (packet != NULL)
- {
- if (packet->write(buf, datalen) == 0)
- { // Writing to packet failed. It has overflowed.
- if (!parsed)
- {
- parseTSPacketDetails(*packet);
- parsed = true;
- }
- if (submitPacket(*packet) == 0) return 0;
- parsed = false;
- packet->truncate();
- packet->write((UCHAR*)"\200\000\000", 3);
- packet->write(buf, datalen);
- }
- }
- }
-
- if (pid == subID && subActive && subPacket.getLength() == subLength)
- {
- parsePacketDetails(subPacket);
-Log::getInstance()->log("DEMUXERTS", Log::DEBUG, "SUBMITTING A SUBTITLE PACKET %d %x", subLength, subPacket.getSubstream());
- submitPacket(subPacket);
- subActive = false;
- }
-
- return 1;
-}
-
-ULONG DemuxerTS::getPacketNum()
-{
- return packetNumber;
-}
-
-ULONG DemuxerTS::getFrameNumFromPTS(ULLONG pts)
-{
- ULLONG difference = (1LL<<33);
- ULONG ref_frame = 0;
- int total = 0, actual = 0;
- if (pts==0) return 0; //we are in startup
- pts_map_mutex.Lock();
- PTSMap::iterator iter = pts_map.begin();
- while (iter != pts_map.end())
- {
- ++total;
- //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts1 %lld pts2 %lld", pts, iter->pts);
- if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
- {
- difference = 0;
- ref_frame = iter->frame;
- actual = total;
- break;
- }
- ULLONG newdiff = PTSDifference(pts, iter->pts);
- if (newdiff < difference)
- {
- difference = newdiff;
- ref_frame = iter->frame;
- actual = total;
- }
- ++iter;
- }
- if (total > 1 && actual == 1) // We are using the most recent PTS ref.
- { // Delete the rest.
- iter = pts_map.begin(); iter++;
- pts_map.erase(iter, pts_map.end());
- }
- pts_map_mutex.Unlock();
-
- //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts %lld deleted %d difference %lld", pts, total,difference);
-
- if (difference == (1LL<<33))
- return 0; // We cannot make sense of the pts
- else
- return ref_frame + difference * fps / 90000;
-}
-
-
-void DemuxerTS::parseTSPacketDetails(PESPacket &packet) // Only important stuff for paket counting reminas
-{
- parsePacketDetails(packet);
- if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
- packet.getPacketType() <= PESTYPE_AUDMAX)
- {
- packetNumber++;
- }
- UINT pictsinpacket=packet.countPictureHeaders(h264);
-
- UINT numpicts=0;
- if (!doubledframerate)
- {
- numpicts=pictsinpacket;
- }
- else
- {
- numpicts=(pictsinpacket+framereserve)>>1;
- framereserve=(pictsinpacket+framereserve)%2;
- }
-
-
- if (frameCounting && numpicts &&
- packet.getPacketType() >= PESTYPE_VID0 &&
- packet.getPacketType() <= PESTYPE_VIDMAX)
- {
- frameNumber+=numpicts;
- ULONG frame_num = frameNumber;
- if ((h264 || packet.findSeqHeader(h264) > 1) && packet.hasPTS())
- {
- PTSMapEntry me;
- pts_map_mutex.Lock();
- if (pts_map.empty())
- {
- me.pts = packet.getPTS();
- me.frame = frame_num;
- pts_map_mutex.Unlock();
- pts_map_mutex.Lock();
- pts_map.push_front(me);
- }
- me = pts_map.front();
- pts_map_mutex.Unlock();
-
- //UINT fps = Video::getInstance()->getFPS();
- double tfps=fps;
- if (doubledframerate) tfps*=2.;
- ULLONG pts_expected = me.pts + 90000*((int)(((double)(frame_num - me.frame)) / tfps));
- while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
-
- if (!doubledframerate
- &&(abs((long long)PTSDistance(pts_expected, packet.getPTS())-1800) <= 1
- || abs((long long)PTSDistance(pts_expected, packet.getPTS())-1501) <= 1)) {
- doubledframerate=true; //Detected p50 or p60
- }
-
- if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
- {
- me.pts = packet.getPTS();
- me.frame = frame_num;
- pts_map_mutex.Lock();
- pts_map.push_front(me);
- pts_map_mutex.Unlock();
- }
- }
- }
-}
-
-
-bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len, bool &ish264)
-{
- int pmtpidy=0;
-
- while (len >= TS_SIZE)
- {
- if (*buf != TS_SIG) {buf++;len--; continue;}
-
- //Pattern scanning won't work for ts
-
-
- int datalen = TS_SIZE - 4;
- int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
- UCHAR payload = buf[1] & 0x40;
-
- if (buf[3] & 0x20) // Adaptation field is present
- datalen -= (buf[4] + 1);
-
- UCHAR* curbuf =buf+ (TS_SIZE - datalen);
-
- if (payload) {
- if (pid == 0x00) {//PAT, only take first program number, ignore the rest
- int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);
- if ((pmtpid >> 13) != 0x07)
- {
- Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));
- }
- else
- {
- pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
- pmtpidy = pmtpid;
- Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMT pid%02x",pmtpid );
- }
-
- } else if (pid == pmtpidy) { //PMT
- int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);
- //sectionlength += 4; //include header but subtract crc in the end...
- int p = 13; //skip fixed part of pmt
- while ( p < sectionlength) {
- int streamtype = *(curbuf+p);
- p++;
- int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);
- p += 2; //skip ES Pid
- int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);
- p += 2; //skip ES length
- if ((foundpid >> 13) != 0x07)
- {
- Log::getInstance()->log("DemuxerTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));
- }
- else
- {
- foundpid = foundpid & 0x1FFF; //clear upper 3 bits
- // int pos=0; UNUSED?
- Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Pid found %02x type %02x",foundpid ,streamtype);
- if (streamtype==1 || streamtype ==2) {
- ish264=false;
- Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found Mpeg2 Video");
- return true;
- }
- if (streamtype==0x1b) {
- ish264=true;
- Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found h264 Video");
- return true;
- }
- }
- p += eslength; //skip es descriptor
- }
- ish264=false;
- return false;
- }
- }
- len-=TS_SIZE;
- buf+=TS_SIZE;
- }
- ish264=false;
- return false;
-}
-
-UINT DemuxerTS::stripAudio(UCHAR* buf, UINT len) //it has to be adapted
-{
- //This function strips all TS Headers and non video payload
- UINT readpos=0;
- UINT writepos=0;
- PESPacket destpaket;
- bool started=true;
- while (readpos < len ) {
- if (buf[readpos] != TS_SIG) {readpos++; continue;}
- UINT oldreadpos=readpos;
-
- int datalen = TS_SIZE - 4;
- int pid = ( (buf[readpos+1] & 0x1F) << 8 ) | buf[readpos+2];
- UCHAR payload = buf[readpos+1] & 0x40;
- if (buf[readpos+3] & 0x20) { // Adaptation field is present
- datalen -= (buf[readpos+4] + 1);
- }
- if (datalen < 0) {// Error in stream TODO log this
- return 0;
- }
- if (datalen == 0) {// Null packet
- readpos=oldreadpos+TS_SIZE;
- continue;
- }
- readpos += (TS_SIZE - datalen);
- UINT towrite=min(datalen,len-readpos);
- if (pid == vID) {
- if (payload) {
- if (started) {
- parsePacketDetails(destpaket);
- memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
- writepos+=destpaket.getSize();
- }
- destpaket.init(PESTYPE_VID0);
- readpos += 6; towrite -= 6;
- started=true;
- }
-
- if (started) {
- if (!destpaket.write(buf+readpos,towrite)) {
- parsePacketDetails(destpaket);
- memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
- writepos+=destpaket.getSize();
- destpaket.truncate();
- destpaket.write((UCHAR*)"\200\000\000", 3);
- destpaket.write(buf+readpos,towrite);
-
- }
- }
-
-
-
- }
- readpos=oldreadpos+TS_SIZE;
- }
- parsePacketDetails(destpaket);
- memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
- writepos+=destpaket.getSize();
-
- return writepos;
-}
-
-
-
+/*\r
+ Copyright 2006-2008 Mark Calderbank\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software Foundation, Inc.,\r
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "demuxerts.h"\r
+#include "log.h"\r
+#include "video.h"\r
+#include "vdr.h"\r
+\r
+#define PTS_JUMP_MARGIN 10000\r
+#define PTS_ALLOWANCE 90000\r
+\r
+// TODO: PTS class to handle wrapping arithmetic & comparisons?\r
+static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)\r
+{\r
+ // Assume pts1, pts2 < 2^33; calculate shortest distance between\r
+ ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;\r
+ if (ret > (1LL<<32)) ret = (1LL<<33) - ret;\r
+ return ret;\r
+}\r
+\r
+static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)\r
+{\r
+ // Assume pts1, pts2 < 2^33; calculate pts1 - pts2\r
+ if (pts1 > pts2)\r
+ return pts1 - pts2;\r
+ else\r
+ return (1LL<<33) + pts1 - pts2;\r
+}\r
+\r
+DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID)\r
+{\r
+ vID = p_vID; vActive = false;\r
+ aID = p_aID; aActive = false;\r
+ subID = p_subID; subActive = false;\r
+ atype = 0;\r
+ subLength = 0;\r
+ tID = p_tID;\r
+ havechannelinfo=false;\r
+ //doubledframerate=false;\r
+ framereserve=0;\r
+}\r
+\r
+void DemuxerTS::flush()\r
+{\r
+ partPacket = 0;\r
+ parsed = false;\r
+ havechannelinfo=false;\r
+ Demuxer::flush();\r
+ vPacket.init(PESTYPE_VID0);\r
+ switch (atype)\r
+ {\r
+ case 1:\r
+ aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);\r
+ break;\r
+ default:\r
+ case 0:\r
+ aPacket.init(PESTYPE_AUD0);\r
+ break;\r
+ }\r
+ subPacket.init(PESTYPE_PRIVATE_1);\r
+tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);\r
+\r
+ vActive = false;\r
+ aActive = false;\r
+ subActive = false;\r
+ subLength = 0;\r
+ tActive = false;\r
+ // doubledframerate=false;\r
+ framereserve=0;\r
+}\r
+\r
+int DemuxerTS::scan(UCHAR *buf, int len)\r
+{\r
+ switch (atype)\r
+ {\r
+ case 1:\r
+ return PESTYPE_PRIVATE_1;\r
+ default:\r
+ case 0:\r
+ return PESTYPE_AUD0;\r
+ }\r
+}\r
+\r
+void DemuxerTS::setVID(int p_vID)\r
+{\r
+ vID = p_vID;\r
+ vPacket.init(PESTYPE_VID0);\r
+ vActive = false;\r
+}\r
+\r
+void DemuxerTS::setAID(int p_aID, int type)\r
+{\r
+ aID = p_aID;\r
+ atype = type;\r
+ switch (atype)\r
+ {\r
+ case 1:\r
+ aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);\r
+ setAudioStream(PESTYPE_SUBSTREAM_AC30);\r
+ break;\r
+ default:\r
+ case 0:\r
+ aPacket.init(PESTYPE_AUD0);\r
+ setAudioStream(PESTYPE_AUD0);\r
+ break;\r
+ }\r
+ aActive = false;\r
+}\r
+\r
+void DemuxerTS::setSubID(int p_subID)\r
+{\r
+ subID = p_subID;\r
+ subPacket.init(PESTYPE_PRIVATE_1);\r
+ subActive = false;\r
+ subLength = 0;\r
+}\r
+\r
+void DemuxerTS::setTID(int p_tID)\r
+{\r
+ tID = p_tID;\r
+ tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);\r
+ tActive = false;\r
+\r
+}\r
+\r
+\r
+\r
+\r
+int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)\r
+{\r
+ int scanaid=0;\r
+\r
+ while (len >= TS_SIZE)\r
+ {\r
+ if (*buf != TS_SIG) {buf++;len--; continue;} \r
+\r
+ //Pattern scanning won't work for ts\r
+\r
+ \r
+ int datalen = TS_SIZE - 4;\r
+ int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];\r
+ UCHAR payload = buf[1] & 0x40;\r
+ \r
+ if (buf[3] & 0x20) // Adaptation field is present\r
+ datalen -= (buf[4] + 1);\r
+\r
+ UCHAR* curbuf =buf+ (TS_SIZE - datalen);\r
+ \r
+\r
+ if (payload) {\r
+ if (pid == 0x00) {//PAT, only take first program number, ignore the rest\r
+ int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);\r
+ if ((pmtpid >> 13) != 0x07) \r
+ {\r
+ Log::getInstance()->log("findPTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));\r
+ } \r
+ else \r
+ {\r
+ pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits\r
+ PMTPID = pmtpid;\r
+ }\r
+ \r
+ } else if (pid == PMTPID) { //PMT\r
+ int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);\r
+ //sectionlength += 4; //include header but subtract crc in the end...\r
+ int p = 13; //skip fixed part of pmt\r
+ while ( p < sectionlength) {\r
+ int streamtype = *(curbuf+p);\r
+ p++;\r
+ int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);\r
+ p += 2; //skip ES Pid\r
+ int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);\r
+ p += 2; //skip ES length\r
+ if ((foundpid >> 13) != 0x07)\r
+ {\r
+ Log::getInstance()->log("findPTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));\r
+ }\r
+ else \r
+ {\r
+ foundpid = foundpid & 0x1FFF; //clear upper 3 bits\r
+ //int pos=0; UNUSED?\r
+ if (streamtype==3 || streamtype ==4) {\r
+ scanaid=foundpid;\r
+ }\r
+ }\r
+ p += eslength; //skip es descriptor\r
+ }\r
+ } else if (pid == scanaid) { \r
+ // UINT framelength = ((UINT)curbuf[4] << 8) | curbuf[5]; UNUSED?\r
+ \r
+ if ( curbuf[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present\r
+ {\r
+ *dest = ( (ULLONG)(curbuf[9] & 0x0E) << 29 ) |\r
+ ( (ULLONG)(curbuf[10]) << 22 ) |\r
+ ( (ULLONG)(curbuf[11] & 0xFE) << 14 ) |\r
+ ( (ULLONG)(curbuf[12]) << 7 ) |\r
+ ( (ULLONG)(curbuf[13] & 0xFE) >> 1 );\r
+ return 1;\r
+ }\r
+ }\r
+ }\r
+ len-=TS_SIZE;\r
+ buf+=TS_SIZE;\r
+ }\r
+ // No PTS found.\r
+ return 0;\r
+}\r
+\r
+void DemuxerTS::setFrameNum(ULONG frame)\r
+{\r
+ frameCounting = true;\r
+ frameNumber = frame;\r
+ framereserve=0;\r
+ Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setFrameNum %d", frame);\r
+}\r
+\r
+void DemuxerTS::setPacketNum(ULONG npacket)\r
+{\r
+ packetCounting = true;\r
+ packetNumber = npacket;\r
+ Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setPacketNum %d", npacket);\r
+}\r
+\r
+int DemuxerTS::put(UCHAR* buf, int len)\r
+{\r
+ int ret = 0; // return number of bytes consumed\r
+\r
+ bool misaligned_mess=false;\r
+ while (partPacket)\r
+ {\r
+ if (len >= TS_SIZE + 1 - partPacket)\r
+ { // Remainder of partial packet is available, plus one\r
+ memcpy(store+partPacket, buf, TS_SIZE - partPacket);\r
+ ret += TS_SIZE - partPacket;\r
+ buf += TS_SIZE - partPacket;\r
+ len -= TS_SIZE - partPacket;\r
+ partPacket = TS_SIZE;\r
+ if (*buf == TS_SIG)\r
+ { // Packet is properly terminated\r
+ int rc = processTS(store);\r
+ if (rc)\r
+ partPacket = 0; // Successfully processed\r
+ else\r
+ return ret; // Try again later.\r
+ }\r
+ else\r
+ { // Packet not terminated. Find another candidate, and shift store\r
+ if (!misaligned_mess) {\r
+ Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!A");\r
+ misaligned_mess=true; // do not alarm more than once\r
+ }\r
+ int search = 1;\r
+ while (search < partPacket && store[search] != TS_SIG)\r
+ search++;\r
+ partPacket -= search;\r
+ if (partPacket) memcpy(store, store+search, partPacket);\r
+ }\r
+ }\r
+ else\r
+ { // Still don't have complete packet. Consume what we do have.\r
+ memcpy(store+partPacket, buf, len);\r
+ partPacket += len;\r
+ ret += len;\r
+ return ret;\r
+ }\r
+ }\r
+\r
+ // Position ourselves at a candidate TS packet\r
+ while (len > 0 && *buf != TS_SIG)\r
+ {\r
+ if (!misaligned_mess) {\r
+ Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!B");\r
+ misaligned_mess=true; // do not alarm more than once\r
+ }\r
+ buf++; ret++; len--;\r
+ }\r
+\r
+ while (len)\r
+ {\r
+ if (len < TS_SIZE + 1)\r
+ { // Not enough data. Store what we have.\r
+ memcpy(store, buf, len);\r
+ partPacket = len;\r
+ ret += len;\r
+ return ret;\r
+ }\r
+\r
+ if (buf[TS_SIZE] != TS_SIG)\r
+ { // Not terminated correctly.\r
+ buf++; ret++; len--;\r
+ while (len > 0 && *buf != TS_SIG)\r
+ {\r
+ buf++; ret++; len--;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ int rc = processTS(buf);\r
+ if (rc)\r
+ { // Successfully processed\r
+ buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE;\r
+ }\r
+ else\r
+ { // Processing failed.\r
+ return ret;\r
+ }\r
+ }\r
+ }\r
+ return ret;\r
+}\r
+\r
+\r
+int DemuxerTS::processTS(UCHAR* buf)\r
+{\r
+ int datalen = TS_SIZE - 4;\r
+\r
+ int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];\r
+ UCHAR payload = buf[1] & 0x40;\r
+\r
+\r
+ if (buf[3] & 0x20) // Adaptation field is present\r
+ datalen -= (buf[4] + 1);\r
+ if (datalen < 0) // Error in stream TODO log this\r
+ return 1;\r
+ if (datalen == 0) // Null packet\r
+ return 1;\r
+ // if (!(buf[3] &0x10)) return 1; // no payload\r
+ buf += (TS_SIZE - datalen);\r
+\r
+ if (payload)\r
+ {\r
+ int rc = 1;\r
+ if (pid == 0x00) {//PAT, only take first program number, ignore the rest\r
+ int pmtpid = (*(buf+11)<< 8) | *(buf+12);\r
+ if ((pmtpid >> 13) != 0x07) \r
+ {\r
+ Log::getInstance()->log("ProcessTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(buf+11),*(buf+12), (pmtpid >> 13));\r
+ } \r
+ else \r
+ {\r
+ pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits\r
+ PMTPID = pmtpid;\r
+ }\r
+ return 1;\r
+ }\r
+ if (pid == PMTPID) \r
+ { //PMT\r
+ int sectionlength = ((*(buf+2) << 8) & 0x0F ) | *(buf+3);\r
+ //sectionlength += 4; //include header but subtract crc in the end...\r
+ int p = 13; //skip fixed part of pmt\r
+ Channel new_channelinfo;\r
+ new_channelinfo.numAPids=0;\r
+ new_channelinfo.numDPids=0;\r
+ new_channelinfo.numSPids=0;\r
+ new_channelinfo.number=0;\r
+ new_channelinfo.type=VDR::RADIO;\r
+ new_channelinfo.name=NULL;\r
+ new_channelinfo.tpid=0xFFFFF; //unused, check this\r
+ new_channelinfo.vpid=0xFFFFF; //unused, check this\r
+ new_channelinfo.index=0;\r
+\r
+ new_channelinfo.apids.clear();\r
+ new_channelinfo.dpids.clear();\r
+ new_channelinfo.spids.clear();\r
+ \r
+ while ( p < sectionlength) {\r
+ int streamtype = *(buf+p);\r
+ p++;\r
+ int foundpid = (*(buf+p)<< 8) | *(buf+p+1);\r
+ p += 2; //skip ES Pid\r
+ int eslength = ((*(buf+p) << 8) & 0x0F ) | *(buf+p+1);\r
+ p += 2; //skip ES length\r
+ if ((foundpid >> 13) != 0x07)\r
+ {\r
+ Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));\r
+ }\r
+ else \r
+ {\r
+ foundpid = foundpid & 0x1FFF; //clear upper 3 bits\r
+ bool notfound=false;\r
+ int pos=0;\r
+ // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID is %x", foundpid);\r
+ switch (streamtype)\r
+ {\r
+ case 0x1B: //MPEG 4 for future use\r
+ case 1:\r
+ case 2: { //video\r
+ if (foundpid != getVID()) \r
+ setVID(foundpid);\r
+ new_channelinfo.type=VDR::VIDEO;\r
+ new_channelinfo.vstreamtype=streamtype;\r
+ new_channelinfo.vpid=foundpid;\r
+ if (streamtype==0x1b) h264=true;\r
+ else h264=false;\r
+\r
+ // Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid);\r
+ }break;\r
+ case 3:\r
+ case 4: { //audio\r
+ apid newapid;\r
+ newapid.pid = foundpid;\r
+ newapid.name = NULL; //set it in player\r
+ new_channelinfo.apids.push_back(newapid);\r
+ new_channelinfo.numAPids++;\r
+ if (getAID() == 0) { //set unset AID to first audio pid that reports itself\r
+ setAID(foundpid,0);\r
+ Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set audio PID to %x", foundpid);\r
+ }\r
+ } break;\r
+ case 5:\r
+ case 6: { //Private Data \r
+ apid newapid;\r
+ newapid.pid = foundpid;\r
+ newapid.name = NULL; //set it in player\r
+ pos=0;\r
+ notfound=true;\r
+ \r
+ while (pos< eslength && notfound) {\r
+ switch (buf[p+pos]) {\r
+ case 0x6A: {//Ac3 descriptor \r
+ new_channelinfo.dpids.push_back(newapid);\r
+ new_channelinfo.numDPids++;\r
+ notfound=false;\r
+ } break; \r
+ case 0x59: {//SubtitlingDescriptor\r
+ new_channelinfo.spids.push_back(newapid);\r
+ new_channelinfo.numSPids++;\r
+ notfound=false;\r
+ } break;\r
+ case 0x56: {\r
+ new_channelinfo.tpid=foundpid;\r
+ notfound=false;\r
+ } break;\r
+ };\r
+ pos+=2+buf[p+pos+1];\r
+ }\r
+\r
+ } break;\r
+ default://TODO how about subtitles and second audio pids\r
+ break;\r
+ }\r
+ }\r
+ \r
+ p += eslength; //skip es descriptor\r
+ \r
+ \r
+ }\r
+ bool audioPIDpresent=false; //Check if pids chnages\r
+ ULONG i;\r
+ for (i=0;i<channelinfo.numAPids;i++) {\r
+ if (aID == (int)channelinfo.apids[i].pid) {\r
+ audioPIDpresent=true;\r
+ }\r
+ }\r
+ for (i=0;i<channelinfo.numDPids && (! audioPIDpresent);i++) {\r
+ if (aID == (int)channelinfo.dpids[i].pid) {\r
+ audioPIDpresent=true;\r
+ }\r
+ }\r
+ if (! audioPIDpresent) {\r
+ if (channelinfo.numAPids>0) {\r
+ setAID(channelinfo.apids[0].pid,0);\r
+ } else if (channelinfo.numDPids>0) {\r
+ setAID(channelinfo.dpids[0].pid,1);\r
+ }\r
+ }\r
+\r
+ channelinfo=new_channelinfo;\r
+ havechannelinfo=true;\r
+\r
+ return 1;\r
+ }\r
+ \r
+\r
+ \r
+\r
+ if (pid == vID)\r
+ {\r
+ if (vActive)\r
+ {\r
+ if (!parsed)\r
+ {\r
+ parseTSPacketDetails(vPacket);\r
+ parsed = true;\r
+ }\r
+ rc = submitPacket(vPacket);\r
+ }\r
+ vActive = true;\r
+ }\r
+ if (pid == aID)\r
+ {\r
+ if (aActive)\r
+ {\r
+ if (!parsed)\r
+ {\r
+ parseTSPacketDetails(aPacket);\r
+ parsed = true;\r
+ }\r
+ rc = submitPacket(aPacket);\r
+ }\r
+ aActive = true;\r
+ }\r
+ if (pid == subID)\r
+ {\r
+ if (subActive)\r
+ {\r
+ if (!parsed)\r
+ {\r
+ parseTSPacketDetails(subPacket);\r
+ parsed = true;\r
+ }\r
+ rc = submitPacket(subPacket);\r
+ }\r
+ subActive = true;\r
+ }\r
+ if (isteletextdecoded && pid == tID)\r
+ {\r
+ if (tActive)\r
+ {\r
+ if (!parsed)\r
+ {\r
+ parseTSPacketDetails(tPacket);\r
+ parsed = true;\r
+ }\r
+ rc = submitPacket(tPacket);\r
+ }\r
+ tActive = true;\r
+ }\r
+ if (rc == 0) return 0;\r
+\r
+ parsed = false;\r
+ if (pid == vID)\r
+ {\r
+ vPacket.init(PESTYPE_VID0);\r
+ buf += 6; datalen -= 6;\r
+ }\r
+ if (pid == aID)\r
+ {\r
+ switch (atype)\r
+ {\r
+ case 1:\r
+ aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);\r
+ break;\r
+ default:\r
+ case 0:\r
+ aPacket.init(PESTYPE_AUD0);\r
+ break;\r
+ }\r
+ buf += 6; datalen -= 6;\r
+ }\r
+ if (pid == subID)\r
+ {\r
+ subPacket.init(PESTYPE_PRIVATE_1);\r
+ subLength = (buf[4] << 8) + buf[5];\r
+ buf += 6; datalen -= 6;\r
+ }\r
+ if (isteletextdecoded && pid == tID)\r
+ {\r
+ tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);\r
+ buf += 6; datalen -= 6;\r
+ }\r
+ }\r
+\r
+ if ( (pid == vID && vActive) ||\r
+ (pid == aID && aActive) ||\r
+ (pid == tID && tActive) ||\r
+ (pid == subID && subActive) )\r
+ {\r
+ PESPacket* packet = NULL;\r
+ if (pid == vID) packet = &vPacket;\r
+ if (pid == aID) packet = &aPacket;\r
+ if (pid == subID) {\r
+ packet = &subPacket;\r
+ }\r
+ if (pid == tID) packet = &tPacket;\r
+ if (packet != NULL)\r
+ {\r
+ if (packet->write(buf, datalen) == 0)\r
+ { // Writing to packet failed. It has overflowed.\r
+ if (!parsed)\r
+ {\r
+ parseTSPacketDetails(*packet);\r
+ parsed = true;\r
+ }\r
+ if (submitPacket(*packet) == 0) return 0;\r
+ parsed = false;\r
+ packet->truncate();\r
+ packet->write((UCHAR*)"\200\000\000", 3);\r
+ packet->write(buf, datalen);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (pid == subID && subActive && subPacket.getLength() == subLength)\r
+ {\r
+ parsePacketDetails(subPacket);\r
+Log::getInstance()->log("DEMUXERTS", Log::DEBUG, "SUBMITTING A SUBTITLE PACKET %d %x", subLength, subPacket.getSubstream());\r
+ submitPacket(subPacket);\r
+ subActive = false;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+ULONG DemuxerTS::getPacketNum()\r
+{\r
+ return packetNumber;\r
+}\r
+\r
+ULONG DemuxerTS::getFrameNumFromPTS(ULLONG pts)\r
+{\r
+ ULLONG difference = (1LL<<33);\r
+ ULONG ref_frame = 0;\r
+ int total = 0, actual = 0;\r
+ if (pts==0) return 0; //we are in startup\r
+ pts_map_mutex.Lock();\r
+ PTSMap::iterator iter = pts_map.begin();\r
+ while (iter != pts_map.end())\r
+ {\r
+ ++total;\r
+ //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts1 %lld pts2 %lld", pts, iter->pts);\r
+ if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)\r
+ {\r
+ difference = 0;\r
+ ref_frame = iter->frame;\r
+ actual = total;\r
+ break;\r
+ }\r
+ ULLONG newdiff = PTSDifference(pts, iter->pts);\r
+ if (newdiff < difference)\r
+ {\r
+ difference = newdiff;\r
+ ref_frame = iter->frame;\r
+ actual = total;\r
+ }\r
+ ++iter;\r
+ }\r
+ if (total > 1 && actual == 1) // We are using the most recent PTS ref.\r
+ { // Delete the rest.\r
+ iter = pts_map.begin(); iter++;\r
+ pts_map.erase(iter, pts_map.end());\r
+ }\r
+ pts_map_mutex.Unlock();\r
+ \r
+ Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts %lld deleted %d difference %lld", pts, total,difference);\r
+\r
+ if (difference == (1LL<<33))\r
+ return 0; // We cannot make sense of the pts\r
+ else\r
+ return ref_frame + difference * fps / 90000;\r
+}\r
+\r
+\r
+void DemuxerTS::parseTSPacketDetails(PESPacket &packet) // Only important stuff for paket counting reminas\r
+{\r
+ parsePacketDetails(packet);\r
+ if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&\r
+ packet.getPacketType() <= PESTYPE_AUDMAX)\r
+ {\r
+ packetNumber++;\r
+ }\r
+ UINT pictsinpacket=packet.countPictureHeaders(h264);\r
+ \r
+ UINT numpicts=0;\r
+ /* if (!doubledframerate)\r
+ {*/\r
+ numpicts=pictsinpacket;\r
+ /* }\r
+ else\r
+ {\r
+ numpicts=(pictsinpacket+framereserve)>>1;\r
+ framereserve=(pictsinpacket+framereserve)%2;\r
+ }*/\r
+\r
+\r
+ if (frameCounting && numpicts &&\r
+ packet.getPacketType() >= PESTYPE_VID0 &&\r
+ packet.getPacketType() <= PESTYPE_VIDMAX)\r
+ {\r
+ frameNumber+=numpicts;\r
+ ULONG frame_num = frameNumber;\r
+ if ((h264 || packet.findSeqHeader(h264) > 1) && packet.hasPTS())\r
+ {\r
+ PTSMapEntry me;\r
+ pts_map_mutex.Lock();\r
+ if (pts_map.empty())\r
+ {\r
+ me.pts = packet.getPTS();\r
+ me.frame = frame_num;\r
+ pts_map_mutex.Unlock();\r
+ pts_map_mutex.Lock();\r
+ pts_map.push_front(me);\r
+ }\r
+ me = pts_map.front();\r
+ pts_map_mutex.Unlock();\r
+\r
+ //UINT fps = Video::getInstance()->getFPS();\r
+ double tfps=fps;\r
+ // if (doubledframerate) tfps*=2.;\r
+ ULLONG pts_expected = me.pts + 90000*((int)(((double)(frame_num - me.frame)) / tfps));\r
+ while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);\r
+\r
+ // this was a workaround for a vdr bug, now fixed, for older recordings deleter the index file\r
+\r
+ /*\r
+ if (!doubledframerate \r
+ &&(abs((long long)PTSDistance(pts_expected, packet.getPTS())-1800) <= 1 \r
+ || abs((long long)PTSDistance(pts_expected, packet.getPTS())-1501) <= 1)) {\r
+ doubledframerate=true; //Detected p50 or p60\r
+ }*/\r
+\r
+ if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!\r
+ {\r
+ me.pts = packet.getPTS();\r
+ me.frame = frame_num;\r
+ pts_map_mutex.Lock();\r
+ pts_map.push_front(me);\r
+ pts_map_mutex.Unlock();\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len, bool &ish264)\r
+{\r
+ int pmtpidy=0;\r
+\r
+ while (len >= TS_SIZE)\r
+ {\r
+ if (*buf != TS_SIG) {buf++;len--; continue;} \r
+\r
+ //Pattern scanning won't work for ts\r
+\r
+ \r
+ int datalen = TS_SIZE - 4;\r
+ int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];\r
+ UCHAR payload = buf[1] & 0x40;\r
+ \r
+ if (buf[3] & 0x20) // Adaptation field is present\r
+ datalen -= (buf[4] + 1);\r
+\r
+ UCHAR* curbuf =buf+ (TS_SIZE - datalen);\r
+ \r
+ if (payload) {\r
+ if (pid == 0x00) {//PAT, only take first program number, ignore the rest\r
+ int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);\r
+ if ((pmtpid >> 13) != 0x07) \r
+ {\r
+ Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));\r
+ } \r
+ else \r
+ {\r
+ pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits\r
+ pmtpidy = pmtpid;\r
+ Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMT pid%02x",pmtpid );\r
+ }\r
+ \r
+ } else if (pid == pmtpidy) { //PMT\r
+ int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);\r
+ //sectionlength += 4; //include header but subtract crc in the end...\r
+ int p = 13; //skip fixed part of pmt\r
+ while ( p < sectionlength) {\r
+ int streamtype = *(curbuf+p);\r
+ p++;\r
+ int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);\r
+ p += 2; //skip ES Pid\r
+ int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);\r
+ p += 2; //skip ES length\r
+ if ((foundpid >> 13) != 0x07)\r
+ {\r
+ Log::getInstance()->log("DemuxerTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));\r
+ }\r
+ else \r
+ {\r
+ foundpid = foundpid & 0x1FFF; //clear upper 3 bits\r
+ // int pos=0; UNUSED?\r
+ Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Pid found %02x type %02x",foundpid ,streamtype);\r
+ if (streamtype==1 || streamtype ==2) {\r
+ ish264=false;\r
+ Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found Mpeg2 Video");\r
+ return true;\r
+ }\r
+ if (streamtype==0x1b) {\r
+ ish264=true;\r
+ Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found h264 Video");\r
+ return true;\r
+ }\r
+ }\r
+ p += eslength; //skip es descriptor\r
+ }\r
+ ish264=false;\r
+ return false;\r
+ } \r
+ }\r
+ len-=TS_SIZE;\r
+ buf+=TS_SIZE;\r
+ }\r
+ ish264=false;\r
+ return false;\r
+}\r
+\r
+UINT DemuxerTS::stripAudio(UCHAR* buf, UINT len) //it has to be adapted\r
+{ \r
+ //This function strips all TS Headers and non video payload\r
+ UINT readpos=0;\r
+ UINT writepos=0;\r
+ PESPacket destpaket;\r
+ bool started=true;\r
+ while (readpos < len ) {\r
+ if (buf[readpos] != TS_SIG) {readpos++; continue;} \r
+ UINT oldreadpos=readpos;\r
+\r
+ int datalen = TS_SIZE - 4;\r
+ int pid = ( (buf[readpos+1] & 0x1F) << 8 ) | buf[readpos+2];\r
+ UCHAR payload = buf[readpos+1] & 0x40;\r
+ if (buf[readpos+3] & 0x20) { // Adaptation field is present\r
+ datalen -= (buf[readpos+4] + 1);\r
+ }\r
+ if (datalen < 0) {// Error in stream TODO log this\r
+ return 0;\r
+ }\r
+ if (datalen == 0) {// Null packet\r
+ readpos=oldreadpos+TS_SIZE;\r
+ continue;\r
+ }\r
+ readpos += (TS_SIZE - datalen);\r
+ UINT towrite=min(datalen,len-readpos);\r
+ if (pid == vID) {\r
+ if (payload) {\r
+ if (started) {\r
+ parsePacketDetails(destpaket);\r
+ memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());\r
+ writepos+=destpaket.getSize();\r
+ }\r
+ destpaket.init(PESTYPE_VID0);\r
+ readpos += 6; towrite -= 6;\r
+ started=true;\r
+ }\r
+\r
+ if (started) {\r
+ if (!destpaket.write(buf+readpos,towrite)) {\r
+ parsePacketDetails(destpaket);\r
+ memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());\r
+ writepos+=destpaket.getSize();\r
+ destpaket.truncate();\r
+ destpaket.write((UCHAR*)"\200\000\000", 3);\r
+ destpaket.write(buf+readpos,towrite);\r
+\r
+ }\r
+ }\r
+ \r
+ \r
+\r
+ }\r
+ readpos=oldreadpos+TS_SIZE;\r
+ }\r
+ parsePacketDetails(destpaket);\r
+ memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());\r
+ writepos+=destpaket.getSize();\r
+ \r
+ return writepos;\r
+} \r
+\r
+\r
+\r
-/*
- Copyright 2006-2007 Mark Calderbank
-
- 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 DEMUXERTS_H
-#define DEMUXERTS_H
-
-#include "mutex.h"
-#include <deque>
-
-#include "demuxer.h"
-#include "defines.h"
-#include "channel.h"
-
-#define TS_SIZE 188
-#define TS_SIG 0x47
-
-class DemuxerTS : public Demuxer
-{
- public:
- DemuxerTS(int p_vID = 0, int p_aID = 0, int p_subID = 0, int p_tID = 0);
- void flush();
- int scan(UCHAR* buf, int len);
- int findPTS(UCHAR* buf, int len, ULLONG* dest);
- void setVID(int p_vID);
- void setTID(int p_tID);
- void setAID(int p_aID, int type);
- void setSubID(int p_subID);
- int getVID() { return vID; }
- int getTID() { return tID; }
- int getAID() { return aID; }
- int getSubID() { return subID; }
- int put(UCHAR* buf, int len);
-
- void setFrameNum(ULONG frame);
- void setPacketNum(ULONG npacket);
- ULONG getFrameNumFromPTS(ULLONG pts);
- ULONG getPacketNum();
- UINT stripAudio(UCHAR* buf, UINT len);
- static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264);
- Channel getChannelInfo() {return channelinfo;};
-
-
- private:
- int processTS(UCHAR* buf);
-
- UCHAR store[TS_SIZE]; // Storage for partial packets
- int partPacket; // Length of partial packet stored from previous put()
- bool parsed; // Whether PES packet to be submitted has been parsed yet
- PESPacket vPacket; // Video PES packet under construction
- PESPacket aPacket; // Audio PES packet under construction
- PESPacket subPacket; // Subtitles PES packet under construction
- PESPacket tPacket; // Teletext PES packet under construction
- int vID, aID, subID,tID; // TS IDs for video/audio/subtitles
- int PMTPID; //TODO HANS which of these do I Need:
-
- int atype;
- bool subActive; // Same for subtitles
- UINT subLength; // Expected length of subtitle packet
- bool vActive, aActive, tActive; // Whether video/audio is actively being captured
-
- bool havechannelinfo;
- Channel channelinfo;
-
-
- //TODO HANS which of next do I need
- ULONG frameNumber, packetNumber;
- bool frameCounting, packetCounting;
- bool doubledframerate;
- int framereserve;
- typedef struct { ULLONG pts; ULONG frame; } PTSMapEntry;
- typedef std::deque<PTSMapEntry> PTSMap;
- PTSMap pts_map;
- Mutex pts_map_mutex;
- void parseTSPacketDetails(PESPacket &packet);
-
-
-};
-
-#endif
+/*\r
+ Copyright 2006-2007 Mark Calderbank\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef DEMUXERTS_H\r
+#define DEMUXERTS_H\r
+\r
+#include "mutex.h"\r
+#include <deque>\r
+\r
+#include "demuxer.h"\r
+#include "defines.h"\r
+#include "channel.h"\r
+\r
+#define TS_SIZE 188\r
+#define TS_SIG 0x47\r
+\r
+class DemuxerTS : public Demuxer\r
+{\r
+ public:\r
+ DemuxerTS(int p_vID = 0, int p_aID = 0, int p_subID = 0, int p_tID = 0); \r
+ void flush();\r
+ int scan(UCHAR* buf, int len);\r
+ int findPTS(UCHAR* buf, int len, ULLONG* dest);\r
+ void setVID(int p_vID);\r
+ void setTID(int p_tID);\r
+ void setAID(int p_aID, int type);\r
+ void setSubID(int p_subID);\r
+ int getVID() { return vID; }\r
+ int getTID() { return tID; }\r
+ int getAID() { return aID; }\r
+ int getSubID() { return subID; }\r
+ int put(UCHAR* buf, int len);\r
+\r
+ void setFrameNum(ULONG frame);\r
+ void setPacketNum(ULONG npacket);\r
+ ULONG getFrameNumFromPTS(ULLONG pts);\r
+ ULONG getPacketNum();\r
+ UINT stripAudio(UCHAR* buf, UINT len);\r
+ static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264);\r
+ Channel getChannelInfo() {return channelinfo;};\r
+\r
+\r
+ private:\r
+ int processTS(UCHAR* buf);\r
+\r
+ UCHAR store[TS_SIZE]; // Storage for partial packets\r
+ int partPacket; // Length of partial packet stored from previous put()\r
+ bool parsed; // Whether PES packet to be submitted has been parsed yet\r
+ PESPacket vPacket; // Video PES packet under construction\r
+ PESPacket aPacket; // Audio PES packet under construction\r
+ PESPacket subPacket; // Subtitles PES packet under construction\r
+ PESPacket tPacket; // Teletext PES packet under construction\r
+ int vID, aID, subID,tID; // TS IDs for video/audio/subtitles \r
+ int PMTPID; //TODO HANS which of these do I Need:\r
+\r
+ int atype;\r
+ bool subActive; // Same for subtitles\r
+ UINT subLength; // Expected length of subtitle packet \r
+ bool vActive, aActive, tActive; // Whether video/audio is actively being captured\r
+\r
+ bool havechannelinfo;\r
+ Channel channelinfo;\r
+ \r
+\r
+ //TODO HANS which of next do I need\r
+ ULONG frameNumber, packetNumber;\r
+ bool frameCounting, packetCounting;\r
+ // bool doubledframerate;\r
+ int framereserve;\r
+ typedef struct { ULLONG pts; ULONG frame; } PTSMapEntry;\r
+ typedef std::deque<PTSMapEntry> PTSMap;\r
+ PTSMap pts_map;\r
+ Mutex pts_map_mutex;\r
+ void parseTSPacketDetails(PESPacket &packet);\r
+ \r
+\r
+};\r
+\r
+#endif\r
-/*
- Copyright 2005-2008 Mark Calderbank
-
- 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 "demuxervdr.h"
-#include "video.h"
-#include "dvbsubtitles.h"
-#include "log.h"
-
-#ifndef WIN32
-#include <endian.h>
-#else
-#define __LITTLE_ENDIAN 1234
-#define __BIG_ENDIAN 4321
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
-
-#define PTS_JUMP_MARGIN 10000
-#define PTS_ALLOWANCE 90000
-
-// TODO: PTS class to handle wrapping arithmetic & comparisons?
-static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)
-{
- // Assume pts1, pts2 < 2^33; calculate shortest distance between
- ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;
- if (ret > (1LL<<32)) ret = (1LL<<33) - ret;
- return ret;
-}
-
-static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
-{
- // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
- if (pts1 > pts2)
- return pts1 - pts2;
- else
- return (1LL<<33) + pts1 - pts2;
-}
-
-DemuxerVDR::DemuxerVDR()
-{
- frameCounting = false;
- packetCounting = false;
- subtitlePacketPosition = 0;
-}
-
-void DemuxerVDR::reset()
-{
- frameCounting = false;
- packetCounting = false;
- pts_map.clear();
- Demuxer::reset();
-}
-
-void DemuxerVDR::flush()
-{
- state = 0;
- submitting = false;
- subtitlePacketPosition = 0;
- Demuxer::flush();
-}
-
-int DemuxerVDR::scan(UCHAR *buf, int len)
-{
- // Temporarily, just look for the lowest audio stream and return it
- UCHAR HiByte = PESTYPE_AUDMAX;
- int ret = 0;
-
- while (len >= 4)
- {
- UINT pattern = *(UINT*)buf;
- buf++; len--;
-
-#if __BYTE_ORDER == __BIG_ENDIAN
- if (pattern < (UINT)(0x100 | PESTYPE_AUD0) ||
- pattern > (UINT)(0x100 | HiByte)) continue;
- HiByte = pattern & 0xFF;
-#else
- if ((pattern & 0xFFFFFF) != 0x010000 ||
- pattern < ((UINT)PESTYPE_AUD0 << 24) ||
- pattern > ((UINT)HiByte << 24)) continue;
- HiByte = pattern >> 24;
-#endif
- ret = HiByte;
- if (HiByte == PESTYPE_AUD0) break;
- }
- return ret;
-}
-
-int DemuxerVDR::findPTS(UCHAR* buf, int len, ULLONG* dest)
-{
- while (len >= 14)
- {
- UINT pattern = *(UINT*)buf;
- buf++; len--;
-#if __BYTE_ORDER == __BIG_ENDIAN
- if (pattern < (0x100 | PESTYPE_AUD0) ||
- pattern > (0x100 | PESTYPE_VIDMAX)) continue;
-#else
- if ((pattern & 0xFFFFFF) != 0x010000 ||
- pattern < ((UINT)PESTYPE_AUD0 << 24) ||
- pattern > ((UINT)PESTYPE_VIDMAX << 24)) continue;
-#endif
- if ((buf[5] & 0xC0) != 0x80) continue;
-
- UINT packetlength = ((UINT)buf[3] << 8) | buf[4];
-
- if ( buf[6] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
- {
- if ( (buf[8] & 0x01) != 0x01 ||
- (buf[10] & 0x01) != 0x01 ||
- (buf[12] & 0x01) != 0x01) continue;
-
- *dest = ( (ULLONG)(buf[8] & 0x0E) << 29 ) |
- ( (ULLONG)(buf[9]) << 22 ) |
- ( (ULLONG)(buf[10] & 0xFE) << 14 ) |
- ( (ULLONG)(buf[11]) << 7 ) |
- ( (ULLONG)(buf[12] & 0xFE) >> 1 );
- return 1;
- }
-
- buf += 5; len -= 5;
- buf += packetlength; len -= packetlength;
- }
- // No PTS found.
- return 0;
-}
-
-void DemuxerVDR::setFrameNum(ULONG frame)
-{
- frameCounting = true;
- frameNumber = frame;
- Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame);
-}
-
-void DemuxerVDR::setPacketNum(ULONG npacket)
-{
- packetCounting = true;
- packetNumber = npacket;
- Log::getInstance()->log("Demuxer", Log::DEBUG, "setPacketNum %d", npacket);
-}
-
-int DemuxerVDR::put(UCHAR* buf, int len)
-{
- int ret = 0; // return number of bytes consumed
- if (submitting)
- {
- if (submitPacket(packet) == 0) // Still full!
- return ret;
- else
- submitting = false;
- }
-
- if (state > 0) // We are half way through a PES packet.
- {
- if (len >= state) // The remainder of the packet is available.
- {
- packet.write(buf, state);
- buf += state; len -= state; ret += state;
- state = 0;
- parseVDRPacketDetails();
- if (submitPacket(packet) == 0) // Stream is full
- {
- submitting = true;
- return ret;
- }
- }
- else // Write what we have, then exit.
- {
- packet.write(buf, len);
- state -= len;
- return len;
- }
- }
-
- while (len > 0)
- {
- switch (state)
- {
- case 0:
- case -1:
- if (*buf == 0x00) state--; else state = 0;
- buf++; len--; ret++;
- break;
- case -2:
- if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
- buf++; len--; ret++;
- break;
- case -3:
- if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
- (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
- (*buf == PESTYPE_PRIVATE_1))
- {
- packet.init(*buf);
- state--;
- }
- else if (*buf == 0x00)
- state = -1;
- else
- state = 0;
- buf++; len--; ret++;
- break;
- case -4:
- packetLength = ((UINT)*buf) << 8;
- state--;
- buf++; len--; ret++;
- break;
- case -5:
- packetLength += *buf;
- state--;
- buf++; len--; ret++;
- break;
- }
-
- if (state == -6) // Packet header complete
- {
- if (len >= packetLength) // The entire packet is available.
- {
- packet.write(buf, packetLength);
- buf += packetLength; len -= packetLength; ret += packetLength;
- state = 0;
- parseVDRPacketDetails();
- if (submitPacket(packet) == 0) // Stream is full
- {
- submitting = true;
- return ret;
- }
- }
- else // Write what we have.
- {
- packet.write(buf, len);
- state = packetLength - len;
- ret += len;
- len = 0;
- }
- }
- }
- return ret;
-}
-
-ULONG DemuxerVDR::getPacketNum()
-{
- return packetNumber;
-}
-
-ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)
-{
- ULLONG difference = (1LL<<33);
- ULONG ref_frame = 0;
- int total = 0, actual = 0;
- pts_map_mutex.Lock();
- PTSMap::iterator iter = pts_map.begin();
- while (iter != pts_map.end())
- {
- ++total;
- if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
- {
- difference = 0;
- ref_frame = iter->frame;
- actual = total;
- break;
- }
- ULLONG newdiff = PTSDifference(pts, iter->pts);
- if (newdiff < difference)
- {
- difference = newdiff;
- ref_frame = iter->frame;
- actual = total;
- }
- ++iter;
- }
- if (total > 1 && actual == 1) // We are using the most recent PTS ref.
- { // Delete the rest.
- iter = pts_map.begin(); iter++;
- pts_map.erase(iter, pts_map.end());
- }
- pts_map_mutex.Unlock();
-
- if (difference == (1LL<<33))
- return 0; // We cannot make sense of the pts
- else
- return ref_frame + (ULONG)((double) (difference / 90000) *fps);
-}
-
-void DemuxerVDR::dealWithSubtitlePacket()
-{
- const UCHAR* data = packet.getData();
- UINT packetSize = packet.getSize();
- if (packetSize < 9) return;
- UINT payloadOffset = data[8] + 9;
- if (packetSize < payloadOffset + 5) return;
- if (data[payloadOffset + 3] == 0x00)
- { // Not a continuation packet
- if (packetSize < payloadOffset + 7) return;
- subtitlePacket.init(data[3]);
- subtitlePacket.write(&data[6], payloadOffset - 6);
- subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
- subtitlePacketPosition = payloadOffset + 2;
- }
- else
- { // Continuation packet
- if (subtitlePacketPosition == 0) return;
- subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
- }
-
- const UCHAR* sub_data = subtitlePacket.getData();
- UINT subSize = subtitlePacket.getSize();
- while (subtitlePacketPosition < subSize)
- {
- if (sub_data[subtitlePacketPosition] == 0xFF)
- { // Packet is complete. Switch it into the "real" packet to be submitted.
- packet = subtitlePacket;
- parsePacketDetails(packet);
- subtitlePacketPosition = 0; // Wait for next non-continuation packet
- break;
- }
- if (sub_data[subtitlePacketPosition] != 0x0F)
- {
- subtitlePacketPosition = 0; // Wait for next non-continuation packet
- break;
- }
- if (subSize < subtitlePacketPosition + 6) break;
- UINT segmentLength = (sub_data[subtitlePacketPosition + 4] << 8)
- + sub_data[subtitlePacketPosition + 5];
- subtitlePacketPosition += segmentLength + 6;
- }
-}
-
-void DemuxerVDR::parseVDRPacketDetails()
-{
- if (packet.getPacketType() == PESTYPE_PRIVATE_1 && packet.getSize() > 8)
- {
- UINT payload_begin = packet[8] + 9;
- if (packet.getSize() > payload_begin)
- {
- UCHAR substream_type = packet[payload_begin] & 0xF0;
- if (substream_type == 0x20) // Subtitles
- {
- dealWithSubtitlePacket();
- }
- else // Not subtitles
- parsePacketDetails(packet);
- }
- }
- else // Not a private packet*/
- parsePacketDetails(packet);
-
- if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
- packet.getPacketType() <= PESTYPE_AUDMAX)
- {
- packetNumber++;
- }
-
- if (frameCounting && packet.findPictureHeader(h264) &&
- packet.getPacketType() >= PESTYPE_VID0 &&
- packet.getPacketType() <= PESTYPE_VIDMAX)
- {
- ULONG frame_num = (frameNumber)++;
- if (packet.findSeqHeader(h264) > 1 && packet.hasPTS())
- {
- PTSMapEntry me;
- pts_map_mutex.Lock();
- if (pts_map.empty())
- {
- me.pts = packet.getPTS();
- me.frame = frame_num;
- pts_map_mutex.Unlock();
-Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me.frame);
- pts_map_mutex.Lock();
- pts_map.push_front(me);
- }
- me = pts_map.front();
- pts_map_mutex.Unlock();
-
-// UINT fps = Video::getInstance()->getFPS();
- ULLONG pts_expected = me.pts + 90000*((ULONG)((double)(frame_num - me.frame)) / fps);
- while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
-
- if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
- {
-Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS JUMP *+ %llu %u", packet.getPTS(), frame_num);
- me.pts = packet.getPTS();
- me.frame = frame_num;
- pts_map_mutex.Lock();
- pts_map.push_front(me);
- pts_map_mutex.Unlock();
- }
- }
- }
-}
+/*\r
+ Copyright 2005-2008 Mark Calderbank\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software Foundation, Inc.,\r
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "demuxervdr.h"\r
+#include "video.h"\r
+#include "dvbsubtitles.h"\r
+#include "log.h"\r
+\r
+#ifndef WIN32\r
+#include <endian.h>\r
+#else\r
+#define __LITTLE_ENDIAN 1234\r
+#define __BIG_ENDIAN 4321\r
+#define __BYTE_ORDER __LITTLE_ENDIAN\r
+#endif\r
+\r
+#define PTS_JUMP_MARGIN 10000\r
+#define PTS_ALLOWANCE 90000\r
+\r
+// TODO: PTS class to handle wrapping arithmetic & comparisons?\r
+static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)\r
+{\r
+ // Assume pts1, pts2 < 2^33; calculate shortest distance between\r
+ ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;\r
+ if (ret > (1LL<<32)) ret = (1LL<<33) - ret;\r
+ return ret;\r
+}\r
+\r
+static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)\r
+{\r
+ // Assume pts1, pts2 < 2^33; calculate pts1 - pts2\r
+ if (pts1 > pts2)\r
+ return pts1 - pts2;\r
+ else\r
+ return (1LL<<33) + pts1 - pts2;\r
+}\r
+\r
+DemuxerVDR::DemuxerVDR()\r
+{\r
+ frameCounting = false;\r
+ packetCounting = false;\r
+ subtitlePacketPosition = 0;\r
+}\r
+\r
+void DemuxerVDR::reset()\r
+{\r
+ frameCounting = false;\r
+ packetCounting = false;\r
+ pts_map.clear();\r
+ Demuxer::reset();\r
+}\r
+\r
+void DemuxerVDR::flush()\r
+{\r
+ state = 0;\r
+ submitting = false;\r
+ subtitlePacketPosition = 0;\r
+ Demuxer::flush();\r
+}\r
+\r
+int DemuxerVDR::scan(UCHAR *buf, int len) {\r
+ // Temporarily, just look for the lowest audio stream and return it\r
+ UCHAR HiByte = PESTYPE_AUDMAX;\r
+ int ret = 0;\r
+\r
+ while (len >= 4) {\r
+ UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];\r
+ buf++;\r
+ len--;\r
+\r
+ if (pattern < (UINT)(0x100 | PESTYPE_AUD0) || pattern > (UINT)(\r
+ 0x100 | HiByte))\r
+ continue;\r
+ HiByte = pattern & 0xFF;\r
+\r
+ ret = HiByte;\r
+ if (HiByte == PESTYPE_AUD0)\r
+ break;\r
+ }\r
+ return ret;\r
+}\r
+\r
+int DemuxerVDR::findPTS(UCHAR* buf, int len, ULLONG* dest) {\r
+ while (len >= 14) {\r
+ UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];\r
+ buf++;\r
+ len--;\r
+ if (pattern < (0x100 | PESTYPE_AUD0) || pattern > (0x100\r
+ | PESTYPE_VIDMAX))\r
+ continue;\r
+\r
+ if ((buf[5] & 0xC0) != 0x80)\r
+ continue;\r
+\r
+ UINT packetlength = ((UINT) buf[3] << 8) | buf[4];\r
+\r
+ if (buf[6] & 0x80) // PTS_DTS_flags indicate that PTS is present\r
+ {\r
+ if ((buf[8] & 0x01) != 0x01 || (buf[10] & 0x01) != 0x01 || (buf[12]\r
+ & 0x01) != 0x01)\r
+ continue;\r
+\r
+ *dest = ((ULLONG)(buf[8] & 0x0E) << 29) | ((ULLONG)(buf[9]) << 22)\r
+ | ((ULLONG)(buf[10] & 0xFE) << 14) | ((ULLONG)(buf[11])\r
+ << 7) | ((ULLONG)(buf[12] & 0xFE) >> 1);\r
+ return 1;\r
+ }\r
+\r
+ buf += 5;\r
+ len -= 5;\r
+ buf += packetlength;\r
+ len -= packetlength;\r
+ }\r
+ // No PTS found.\r
+ return 0;\r
+}\r
+\r
+void DemuxerVDR::setFrameNum(ULONG frame)\r
+{\r
+ frameCounting = true;\r
+ frameNumber = frame;\r
+ Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame);\r
+}\r
+\r
+void DemuxerVDR::setPacketNum(ULONG npacket)\r
+{\r
+ packetCounting = true;\r
+ packetNumber = npacket;\r
+ Log::getInstance()->log("Demuxer", Log::DEBUG, "setPacketNum %d", npacket);\r
+}\r
+\r
+int DemuxerVDR::put(UCHAR* buf, int len)\r
+{\r
+ int ret = 0; // return number of bytes consumed\r
+ if (submitting)\r
+ {\r
+ if (submitPacket(packet) == 0) // Still full!\r
+ return ret;\r
+ else\r
+ submitting = false;\r
+ }\r
+\r
+ if (state > 0) // We are half way through a PES packet.\r
+ {\r
+ if (len >= state) // The remainder of the packet is available.\r
+ {\r
+ packet.write(buf, state);\r
+ buf += state; len -= state; ret += state;\r
+ state = 0;\r
+ parseVDRPacketDetails();\r
+ if (submitPacket(packet) == 0) // Stream is full\r
+ {\r
+ submitting = true;\r
+ return ret;\r
+ }\r
+ }\r
+ else // Write what we have, then exit.\r
+ {\r
+ packet.write(buf, len);\r
+ state -= len;\r
+ return len;\r
+ }\r
+ }\r
+\r
+ while (len > 0)\r
+ {\r
+ switch (state)\r
+ {\r
+ case 0:\r
+ case -1:\r
+ if (*buf == 0x00) state--; else state = 0;\r
+ buf++; len--; ret++;\r
+ break;\r
+ case -2:\r
+ if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;\r
+ buf++; len--; ret++;\r
+ break;\r
+ case -3:\r
+ if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||\r
+ (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||\r
+ (*buf == PESTYPE_PRIVATE_1))\r
+ {\r
+ packet.init(*buf);\r
+ state--;\r
+ }\r
+ else if (*buf == 0x00)\r
+ state = -1;\r
+ else\r
+ state = 0;\r
+ buf++; len--; ret++;\r
+ break;\r
+ case -4:\r
+ packetLength = ((UINT)*buf) << 8;\r
+ state--;\r
+ buf++; len--; ret++;\r
+ break;\r
+ case -5:\r
+ packetLength += *buf;\r
+ state--;\r
+ buf++; len--; ret++;\r
+ break;\r
+ }\r
+\r
+ if (state == -6) // Packet header complete\r
+ {\r
+ if (len >= packetLength) // The entire packet is available.\r
+ {\r
+ packet.write(buf, packetLength);\r
+ buf += packetLength; len -= packetLength; ret += packetLength;\r
+ state = 0;\r
+ parseVDRPacketDetails();\r
+ if (submitPacket(packet) == 0) // Stream is full\r
+ {\r
+ submitting = true;\r
+ return ret;\r
+ }\r
+ }\r
+ else // Write what we have.\r
+ {\r
+ packet.write(buf, len);\r
+ state = packetLength - len;\r
+ ret += len;\r
+ len = 0;\r
+ }\r
+ }\r
+ }\r
+ return ret;\r
+}\r
+\r
+ULONG DemuxerVDR::getPacketNum()\r
+{\r
+ return packetNumber;\r
+}\r
+\r
+ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)\r
+{\r
+ ULLONG difference = (1LL<<33);\r
+ ULONG ref_frame = 0;\r
+ int total = 0, actual = 0;\r
+ pts_map_mutex.Lock();\r
+ PTSMap::iterator iter = pts_map.begin();\r
+ while (iter != pts_map.end())\r
+ {\r
+ ++total;\r
+ if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)\r
+ {\r
+ difference = 0;\r
+ ref_frame = iter->frame;\r
+ actual = total;\r
+ break;\r
+ }\r
+ ULLONG newdiff = PTSDifference(pts, iter->pts);\r
+ if (newdiff < difference)\r
+ {\r
+ difference = newdiff;\r
+ ref_frame = iter->frame;\r
+ actual = total;\r
+ }\r
+ ++iter;\r
+ }\r
+ if (total > 1 && actual == 1) // We are using the most recent PTS ref.\r
+ { // Delete the rest.\r
+ iter = pts_map.begin(); iter++;\r
+ pts_map.erase(iter, pts_map.end());\r
+ }\r
+ pts_map_mutex.Unlock();\r
+\r
+ if (difference == (1LL<<33))\r
+ return 0; // We cannot make sense of the pts\r
+ else\r
+ return ref_frame + (ULONG)((double) (difference / 90000) *fps);\r
+}\r
+\r
+void DemuxerVDR::dealWithSubtitlePacket()\r
+{\r
+ const UCHAR* data = packet.getData();\r
+ UINT packetSize = packet.getSize();\r
+ if (packetSize < 9) return;\r
+ UINT payloadOffset = data[8] + 9;\r
+ if (packetSize < payloadOffset + 5) return;\r
+ if (data[payloadOffset + 3] == 0x00)\r
+ { // Not a continuation packet\r
+ if (packetSize < payloadOffset + 7) return;\r
+ subtitlePacket.init(data[3]);\r
+ subtitlePacket.write(&data[6], payloadOffset - 6);\r
+ subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);\r
+ subtitlePacketPosition = payloadOffset + 2;\r
+ }\r
+ else\r
+ { // Continuation packet\r
+ if (subtitlePacketPosition == 0) return;\r
+ subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);\r
+ }\r
+ \r
+ const UCHAR* sub_data = subtitlePacket.getData();\r
+ UINT subSize = subtitlePacket.getSize();\r
+ while (subtitlePacketPosition < subSize)\r
+ {\r
+ if (sub_data[subtitlePacketPosition] == 0xFF)\r
+ { // Packet is complete. Switch it into the "real" packet to be submitted.\r
+ packet = subtitlePacket;\r
+ parsePacketDetails(packet);\r
+ subtitlePacketPosition = 0; // Wait for next non-continuation packet\r
+ break;\r
+ }\r
+ if (sub_data[subtitlePacketPosition] != 0x0F)\r
+ {\r
+ subtitlePacketPosition = 0; // Wait for next non-continuation packet\r
+ break;\r
+ }\r
+ if (subSize < subtitlePacketPosition + 6) break;\r
+ UINT segmentLength = (sub_data[subtitlePacketPosition + 4] << 8)\r
+ + sub_data[subtitlePacketPosition + 5];\r
+ subtitlePacketPosition += segmentLength + 6;\r
+ }\r
+}\r
+\r
+void DemuxerVDR::parseVDRPacketDetails()\r
+{\r
+ if (packet.getPacketType() == PESTYPE_PRIVATE_1 && packet.getSize() > 8)\r
+ {\r
+ UINT payload_begin = packet[8] + 9;\r
+ if (packet.getSize() > payload_begin)\r
+ {\r
+ UCHAR substream_type = packet[payload_begin] & 0xF0;\r
+ if (substream_type == 0x20) // Subtitles\r
+ {\r
+ dealWithSubtitlePacket();\r
+ }\r
+ else // Not subtitles\r
+ parsePacketDetails(packet);\r
+ }\r
+ }\r
+ else // Not a private packet*/\r
+ parsePacketDetails(packet);\r
+\r
+ if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&\r
+ packet.getPacketType() <= PESTYPE_AUDMAX)\r
+ {\r
+ packetNumber++;\r
+ }\r
+\r
+ if (frameCounting && packet.findPictureHeader(h264) &&\r
+ packet.getPacketType() >= PESTYPE_VID0 &&\r
+ packet.getPacketType() <= PESTYPE_VIDMAX)\r
+ {\r
+ ULONG frame_num = (frameNumber)++;\r
+ if (packet.findSeqHeader(h264) > 1 && packet.hasPTS())\r
+ {\r
+ PTSMapEntry me;\r
+ pts_map_mutex.Lock();\r
+ if (pts_map.empty())\r
+ {\r
+ me.pts = packet.getPTS();\r
+ me.frame = frame_num;\r
+ pts_map_mutex.Unlock();\r
+Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me.frame);\r
+ pts_map_mutex.Lock();\r
+ pts_map.push_front(me);\r
+ }\r
+ me = pts_map.front();\r
+ pts_map_mutex.Unlock();\r
+\r
+// UINT fps = Video::getInstance()->getFPS();\r
+ ULLONG pts_expected = me.pts + 90000*((ULONG)((double)(frame_num - me.frame)) / fps);\r
+ while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);\r
+\r
+ if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!\r
+ {\r
+Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS JUMP *+ %llu %u", packet.getPTS(), frame_num);\r
+ me.pts = packet.getPTS();\r
+ me.frame = frame_num;\r
+ pts_map_mutex.Lock();\r
+ pts_map.push_front(me);\r
+ pts_map_mutex.Unlock();\r
+ }\r
+ }\r
+ }\r
+}\r
#include "directory.h"
-Directory::Directory(char* newName)
+Directory::Directory(const char* newName)
{
index = -1;
class Directory
{
public:
- Directory(char* newName);
+ Directory(const char* newName);
~Directory();
Directory* getDirByName(char* dirName);
+++ /dev/null
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "draintarget.h"
-
-DrainTarget::DrainTarget()
-{
-}
-DrainTarget::~DrainTarget()
-{
-}
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef DRAINTARGET_H
-#define DRAINTARGET_H
-
-#include "defines.h"
-#include <list>
-
-#define MPTYPE_VIDEO_MPEG2 0x00
-#define MPTYPE_MPEG_AUDIO 0x01
-#define MPTYPE_AC3 0x02
-#define MPTYPE_AC3_PRE13 0x03 //old vdr recording compatmode
-#define MPTYPE_MPEG_AUDIO_LAYER3 0x04 //for media mp3 playback
-#define MPTYPE_TELETEXT 0x05 //for EBU VBI teletext
-#define MPTYPE_VIDEO_H264 0x06
-
-
-
-struct MediaPacket
-{
- ULONG pos_buffer; //position in stream buffer
- ULONG length; //length of the packet
- // The fields below are not needed by the MVP
- UCHAR type;
- ULLONG pts;
- ULLONG dts;
- bool synched;
- int index;
-#ifdef WIN32
- long long presentation_time;/* in 100 ns units*/
- bool disconti;
-#endif
-};
-
-using namespace std;
-typedef list<MediaPacket> MediaPacketList;
-
-class DrainTarget
-{
- public:
- DrainTarget();
- virtual ~DrainTarget();
-
- virtual long long SetStartOffset(long long curreftime, bool *rsync)=0;
- virtual void ResetTimeOffsets()=0;
-
- virtual bool dtsTimefix(){return false;} //determines if the draintargets needs a mixure of pts and dts or not
-
-// The following two functions are used by the Stream
-// to deliver media packets to the front end (DrainTarget).
-//
-// First, the Stream calls PrepareMediaSample, which gives the front end
-// read-only access to the Stream's MediaPacketList. PrepareMediaSample should
-// examine the list to determine how much it wishes to consume, and
-// should copy any data it requires from the MediaPacket objects into
-// local storage.
-// This function call takes place under a mutex lock to ensure integrity
-// of the list structure. It should be fast and must not contain any
-// cancellation points, such as I/O calls for logging.
-//
-// Second, the Stream releases the mutex and calls DeliverMediaSample.
-// This function delivers data from the Stream buffer to the presentation
-// device and returns information to the Stream regarding how many MediaPackets
-// were consumed. Any data copied from the MediaPackets objects during
-// PrepareMediaSample is guaranteed by the Stream still to be valid
-// during the following DeliverMediaSample call.
-
- // samplepos is equal to the number of bytes from the first MediaPacket
- // in the list that have already been consumed in a previous call.
- virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos)=0;
-
- // The Stream guarantees that the value of *samplepos passed to
- // DeliverMediaSample will be equal to the value of samplepos passed to
- // PrepareMediaSample in the previous call.
- // This function should consume data from the buffer according to the
- // decisions made in PrepareMediaSample. Its return value and *samplepos
- // tell the Stream how much data it consumed.
- // If DeliverMediaSample returns X, the Stream will remove packets 0 to X-1
- // (inclusive) from the list before the next call.
- // DeliverMediaSample must also set *samplepos equal to the number of bytes
- // processed from packet X (usually zero).
- // It is allowed, that the draintarget modifies the part of the buffer, which belongs
- // to the mediapackets it is processing.
- virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos)=0;
-};
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef DRAINTARGET_H\r
+#define DRAINTARGET_H\r
+\r
+#include "defines.h"\r
+#include <list>\r
+\r
+#define MPTYPE_VIDEO_MPEG2 0x00\r
+#define MPTYPE_MPEG_AUDIO 0x01\r
+#define MPTYPE_AC3 0x02\r
+#define MPTYPE_AC3_PRE13 0x03 //old vdr recording compatmode\r
+#define MPTYPE_MPEG_AUDIO_LAYER3 0x04 //for media mp3 playback\r
+#define MPTYPE_TELETEXT 0x05 //for EBU VBI teletext\r
+#define MPTYPE_VIDEO_H264 0x06\r
+\r
+\r
+\r
+struct MediaPacket\r
+{\r
+ ULONG pos_buffer; //position in stream buffer\r
+ ULONG length; //length of the packet\r
+ // The fields below are not needed by the MVP\r
+ UCHAR type;\r
+ ULLONG pts;\r
+ ULLONG dts;\r
+ bool synched;\r
+ int index;\r
+#if defined(WIN32) || defined(__ANDROID__)\r
+ long long presentation_time;/* in 100 ns units*/\r
+ bool disconti;\r
+#endif\r
+};\r
+\r
+using namespace std;\r
+typedef list<MediaPacket> MediaPacketList;\r
+\r
+\r
+\r
+class DrainTarget\r
+{\r
+ public:\r
+ DrainTarget() {\r
+\r
+ }\r
+ virtual ~DrainTarget(){\r
+\r
+ }\r
+\r
+ virtual long long SetStartOffset(long long curreftime, bool *rsync)=0;\r
+ virtual void ResetTimeOffsets()=0;\r
+\r
+ virtual bool dtsTimefix(){return false;} //determines if the draintargets needs a mixure of pts and dts or not\r
+\r
+// The following two functions are used by the Stream\r
+// to deliver media packets to the front end (DrainTarget).\r
+//\r
+// First, the Stream calls PrepareMediaSample, which gives the front end\r
+// read-only access to the Stream's MediaPacketList. PrepareMediaSample should\r
+// examine the list to determine how much it wishes to consume, and\r
+// should copy any data it requires from the MediaPacket objects into\r
+// local storage.\r
+// This function call takes place under a mutex lock to ensure integrity\r
+// of the list structure. It should be fast and must not contain any\r
+// cancellation points, such as I/O calls for logging.\r
+//\r
+// Second, the Stream releases the mutex and calls DeliverMediaSample.\r
+// This function delivers data from the Stream buffer to the presentation\r
+// device and returns information to the Stream regarding how many MediaPackets\r
+// were consumed. Any data copied from the MediaPackets objects during\r
+// PrepareMediaSample is guaranteed by the Stream still to be valid\r
+// during the following DeliverMediaSample call.\r
+\r
+ // samplepos is equal to the number of bytes from the first MediaPacket\r
+ // in the list that have already been consumed in a previous call.\r
+ virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos)=0;\r
+\r
+ // The Stream guarantees that the value of *samplepos passed to\r
+ // DeliverMediaSample will be equal to the value of samplepos passed to\r
+ // PrepareMediaSample in the previous call.\r
+ // This function should consume data from the buffer according to the\r
+ // decisions made in PrepareMediaSample. Its return value and *samplepos\r
+ // tell the Stream how much data it consumed.\r
+ // If DeliverMediaSample returns X, the Stream will remove packets 0 to X-1\r
+ // (inclusive) from the list before the next call.\r
+ // DeliverMediaSample must also set *samplepos equal to the number of bytes\r
+ // processed from packet X (usually zero).\r
+ // It is allowed, that the draintarget modifies the part of the buffer, which belongs \r
+ // to the mediapackets it is processing.\r
+ virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos)=0;\r
+ // The drain target might advice the feeder about free buffers with threadSignal\r
+\r
+\r
+};\r
+\r
+#endif\r
#ifndef DVBSUBTITLES_H
#define DVBSUBTITLES_H
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
+#include "threadsystem.h"
+
#include "bitmap.h"
#include "demuxer.h"
#include <ctime>
#include <stdio.h>
#include <string.h>
-#ifndef WIN32
+
+//Nothing is using this ?
+/*#ifndef WIN32
#include <glob.h>
-#endif
+#endif*/
#include "vdr.h"
#include "log.h"
-/*
- Copyright 2004-2006 Chris Tallon, Andreas Vogel
-
- 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 IMAGEREADER_H
-#define IMAGEREADER_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef WIN32
-#include <sys/time.h>
-#endif
-#include <time.h>
-
-#include "callback.h"
-#include "thread.h"
-
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
-
-
-
-class MediaProvider;
-class Log;
-
-
-class ImageReader : public Thread_TYPE, public Callback
-{
- public:
-
- //create an image reader for a media channel
- //the channel must already been opened
- ImageReader(int channel,MediaProvider *p);
- //call shutdown before destroying the reader!
- virtual ~ImageReader();
- //request the next image block
- //will return the current block (if already read) and request the next from the server
- //rsize will return the received len: 0 on EOF, -1 on error
- //the returned buffer has to be freed outside (really use free!)
- //if the buffer is not filled it will wait until the chunk is received!
- int getImageChunk(ULLONG offset,UINT len, UINT * rsize,UCHAR **buffer);
-
- //is the reader still running?
- bool isReaderRunning();
-
- void shutdown();
-
- //stop the reader (waits until the reader thread does not access anything)
- void stop();
-
-
- virtual void call(void * caller);
-
-
- protected:
- void threadMethod();
- void threadPostStopCleanup();
-
- private:
- MediaProvider * provider;
- int channel;
- static const int MAXCHUNKS=2;
- //start the player thread
- void run();
- Log* logger;
-
- bool running;
- bool readerRunning;
- void waitTimed(int ms);
-
- typedef enum {
- S_REQUEST=1,
- S_FETCHING=2,
- S_READY=3,
- S_BREAK=4,
- S_FREE=0
- } rstate;
-
- class Chunk{
- public:
- UCHAR * buffer; //receive buffer (to be deallocated with free)
- ULLONG offset; //offset within stream/file
- UINT reqlen; //requested len
- ULONG len; //received len
- rstate state; //current state
- Chunk() {
- buffer=NULL;
- offset=0;
- reqlen=0;
- len=0;
- state=S_FREE;
- }
- };
- //received data
- //setting state in this array requires the thread lock
- Chunk data[MAXCHUNKS];
-
-};
-
-#endif
-
+/*\r
+ Copyright 2004-2006 Chris Tallon, Andreas Vogel\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef IMAGEREADER_H\r
+#define IMAGEREADER_H\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#ifndef WIN32\r
+#include <sys/time.h>\r
+#endif\r
+#include <time.h>\r
+\r
+#include "callback.h"\r
+#include "thread.h"\r
+\r
+#include "threadsystem.h"\r
+\r
+\r
+\r
+class MediaProvider;\r
+class Log;\r
+\r
+\r
+class ImageReader : public Thread_TYPE, public Callback\r
+{\r
+ public:\r
+\r
+ //create an image reader for a media channel\r
+ //the channel must already been opened\r
+ ImageReader(int channel,MediaProvider *p);\r
+ //call shutdown before destroying the reader!\r
+ virtual ~ImageReader();\r
+ //request the next image block\r
+ //will return the current block (if already read) and request the next from the server\r
+ //rsize will return the received len: 0 on EOF, -1 on error\r
+ //the returned buffer has to be freed outside (really use free!)\r
+ //if the buffer is not filled it will wait until the chunk is received!\r
+ int getImageChunk(ULLONG offset,UINT len, UINT * rsize,UCHAR **buffer);\r
+\r
+ //is the reader still running?\r
+ bool isReaderRunning();\r
+\r
+ void shutdown();\r
+\r
+ //stop the reader (waits until the reader thread does not access anything)\r
+ void stop();\r
+\r
+ \r
+ virtual void call(void * caller);\r
+\r
+\r
+ protected:\r
+ void threadMethod();\r
+ void threadPostStopCleanup();\r
+\r
+ private:\r
+ MediaProvider * provider;\r
+ int channel;\r
+ static const int MAXCHUNKS=2;\r
+ //start the player thread\r
+ void run();\r
+ Log* logger;\r
+\r
+ bool running;\r
+ bool readerRunning;\r
+ void waitTimed(int ms);\r
+\r
+ typedef enum {\r
+ S_REQUEST=1,\r
+ S_FETCHING=2,\r
+ S_READY=3,\r
+ S_BREAK=4,\r
+ S_FREE=0\r
+ } rstate;\r
+\r
+ class Chunk{\r
+ public:\r
+ UCHAR * buffer; //receive buffer (to be deallocated with free)\r
+ ULLONG offset; //offset within stream/file\r
+ UINT reqlen; //requested len\r
+ ULONG len; //received len\r
+ rstate state; //current state\r
+ Chunk() {\r
+ buffer=NULL;\r
+ offset=0;\r
+ reqlen=0;\r
+ len=0;\r
+ state=S_FREE;\r
+ } \r
+ };\r
+ //received data\r
+ //setting state in this array requires the thread lock\r
+ Chunk data[MAXCHUNKS];\r
+\r
+};\r
+\r
+#endif\r
+\r
{
public:
LedMVP();
- ~LedMVP();
+ virtual ~LedMVP();
int init(int device);
int shutdown();
-/*
- Copyright 2004-2005 Chris Tallon
- Copyright 2003-2004 University Of Bradford
-
- 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 "log.h"
-
-#include "vdr.h"
-
-Log* Log::instance = NULL;
-
-Log::Log()
-{
- if (instance) return;
- instance = this;
- logfile = NULL;
- initted = 0;
- logLevel = 0;
- netLog = false;
-}
-
-Log::~Log()
-{
- instance = NULL;
-}
-
-Log* Log::getInstance()
-{
- return instance;
-}
-
-void Log::upLogLevel()
-{
- if (logLevel == Log::DEBUG)
- {
- log("Log", logLevel, "Log level is at its highest already");
- return;
- }
-
- logLevel++;
- log("Log", logLevel, "Log level is now %i", logLevel);
-}
-
-void Log::downLogLevel()
-{
- if (logLevel == Log::CRAZY)
- {
- log("Log", logLevel, "Log level is at its lowest already");
- return;
- }
-
- logLevel--;
- log("Log", logLevel, "Log level is now %i", logLevel);
-}
-
-int Log::init(int startLogLevel, char* fileName, int tenabled)
-{
- initted = 1;
- logLevel = startLogLevel;
- enabled = tenabled;
-// logfile = fopen(fileName, "a");
-// logfile = fopen(stdout, "a");
- logfile = stdout;
-// logfile = fopen("/log", "a");
-
- if (logfile) return 1;
- else return 0;
-}
-
-int Log::shutdown()
-{
- if (!initted) return 1;
- if (enabled) fclose(logfile);
- return 1;
-}
-
-int Log::log(char *fromModule, int level, char* message, ...)
-{
- if (!instance || !logfile) return 0;
-
- if (!enabled && !netLog) return 1;
- if (level > logLevel) return 1;
-
- char buffer[151];
- int spaceLeft = 150;
-
-#ifndef _MSC_VER
- struct timeval tv;
- gettimeofday(&tv, NULL);
- struct tm* tms = localtime(&tv.tv_sec);
-#else
- struct _timeb tb;
- _ftime(&tb);
- struct tm* tms = localtime(&tb.time);
-#endif
- spaceLeft -= strftime(buffer, spaceLeft, "%H:%M:%S.", tms);
-#ifndef _MSC_VER
- spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tv.tv_usec);
-#else
- spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tb.millitm);
-#endif
-
- char levelString[10];
- if (level == CRAZY) strcpy(levelString, "[CRAZY] ");
- if (level == EMERG) strcpy(levelString, "[EMERG] ");
- if (level == ALERT) strcpy(levelString, "[ALERT] ");
- if (level == CRIT) strcpy(levelString, "[CRIT] ");
- if (level == ERR) strcpy(levelString, "[ERR] ");
- if (level == WARN) strcpy(levelString, "[WARN] ");
- if (level == NOTICE) strcpy(levelString, "[notice]");
- if (level == INFO) strcpy(levelString, "[info] ");
- if (level == DEBUG) strcpy(levelString, "[debug] ");
-
-#ifndef WIN32
- spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%s %d %s - ", levelString, getpid(), fromModule);
-#else
- spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%s %s - ", levelString, fromModule);
-#endif
-
- va_list ap;
- va_start(ap, message);
- spaceLeft = VSNPRINTF(&buffer[150-spaceLeft], spaceLeft, message, ap);
- va_end(ap);
-
- int messageLength = strlen(buffer);
- if (messageLength < 150)
- {
- buffer[messageLength] = '\n';
- buffer[messageLength+1] = '\0';
- }
- else
- {
- buffer[149] = '\n';
- buffer[150] = '\0';
- }
-
- int success = 1;
- if (enabled)
- {
- success = fputs(buffer, logfile);
- fflush(NULL);
- }
-
- if (netLog) vdr->networkLog(buffer);
-
- if (success != EOF)
- return 1;
- else
- return 0;
-
-}
-
-int Log::status()
-{
- if (instance && logfile) return 1;
- else return 0;
-}
-
-void Log::netLogOn()
-{
- vdr = VDR::getInstance();
- netLog = true;
- log("Log", Log::DEBUG, "Network logging started");
-}
-
-void Log::netLogOff()
-{
- netLog = false;
- vdr = NULL;
-}
-
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+ Copyright 2003-2004 University Of Bradford\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "log.h"\r
+\r
+#include "vdr.h"\r
+\r
+#ifdef __ANDROID__\r
+#include <android/log.h>\r
+#endif\r
+\r
+Log* Log::instance = NULL;\r
+\r
+Log::Log()\r
+{\r
+ if (instance) return;\r
+ instance = this;\r
+ logfile = NULL;\r
+ initted = 0;\r
+ logLevel = 0;\r
+ extlog = NULL;\r
+}\r
+\r
+Log::~Log()\r
+{\r
+ instance = NULL;\r
+}\r
+\r
+Log* Log::getInstance()\r
+{\r
+ return instance;\r
+}\r
+\r
+void Log::upLogLevel()\r
+{\r
+ if (logLevel == Log::DEBUG)\r
+ {\r
+ log("Log", logLevel, "Log level is at its highest already");\r
+ return;\r
+ }\r
+\r
+ logLevel++;\r
+ log("Log", logLevel, "Log level is now %i", logLevel);\r
+}\r
+\r
+void Log::downLogLevel()\r
+{\r
+ if (logLevel == Log::CRAZY)\r
+ {\r
+ log("Log", logLevel, "Log level is at its lowest already");\r
+ return;\r
+ }\r
+\r
+ logLevel--;\r
+ log("Log", logLevel, "Log level is now %i", logLevel);\r
+}\r
+\r
+int Log::init(int startLogLevel,const char* fileName, int tenabled)\r
+{\r
+ initted = 1;\r
+ logLevel = startLogLevel;\r
+ enabled = tenabled;\r
+// logfile = fopen(fileName, "a");\r
+// logfile = fopen(stdout, "a");\r
+ logfile = stdout;\r
+// logfile = fopen("/log", "a");\r
+\r
+ if (logfile) return 1;\r
+ else return 0;\r
+}\r
+\r
+int Log::shutdown()\r
+{\r
+ if (!initted) return 1;\r
+ if (enabled) fclose(logfile);\r
+ return 1;\r
+}\r
+\r
+int Log::log(const char *fromModule, int level,const char* message, ...)\r
+{\r
+ if (!instance || !logfile) return 0;\r
+\r
+ if (!enabled && !extlog) return 1;\r
+ if (level > logLevel) return 1;\r
+\r
+ char buffer[151];\r
+ int spaceLeft = 150;\r
+\r
+#ifndef _MSC_VER\r
+ struct timeval tv;\r
+ gettimeofday(&tv, NULL);\r
+ struct tm* tms = localtime(&tv.tv_sec);\r
+#else\r
+ struct _timeb tb;\r
+ _ftime(&tb);\r
+ struct tm* tms = localtime(&tb.time);\r
+#endif\r
+ spaceLeft -= strftime(buffer, spaceLeft, "%H:%M:%S.", tms);\r
+#ifndef _MSC_VER\r
+ spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tv.tv_usec);\r
+#else\r
+ spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tb.millitm);\r
+#endif\r
+\r
+ char levelString[10];\r
+ if (level == CRAZY) strcpy(levelString, "[CRAZY] ");\r
+ if (level == EMERG) strcpy(levelString, "[EMERG] ");\r
+ if (level == ALERT) strcpy(levelString, "[ALERT] ");\r
+ if (level == CRIT) strcpy(levelString, "[CRIT] ");\r
+ if (level == ERR) strcpy(levelString, "[ERR] ");\r
+ if (level == WARN) strcpy(levelString, "[WARN] ");\r
+ if (level == NOTICE) strcpy(levelString, "[notice]");\r
+ if (level == INFO) strcpy(levelString, "[info] ");\r
+ if (level == DEBUG) strcpy(levelString, "[debug] ");\r
+\r
+#ifndef WIN32\r
+ spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%s %d %s - ", levelString, getpid(), fromModule);\r
+#else\r
+ spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%s %s - ", levelString, fromModule);\r
+#endif\r
+\r
+ va_list ap;\r
+ va_start(ap, message);\r
+ spaceLeft = VSNPRINTF(&buffer[150-spaceLeft], spaceLeft, message, ap);\r
+ va_end(ap);\r
+\r
+ int messageLength = strlen(buffer);\r
+ if (messageLength < 150)\r
+ {\r
+ buffer[messageLength] = '\n';\r
+ buffer[messageLength+1] = '\0';\r
+ }\r
+ else\r
+ {\r
+ buffer[149] = '\n';\r
+ buffer[150] = '\0';\r
+ }\r
+ \r
+ int success = 1;\r
+ if (enabled)\r
+ {\r
+#ifndef __ANDROID__\r
+ success = fputs(buffer, logfile);\r
+ fflush(NULL);\r
+#else\r
+ int and_level=0;\r
+ switch (level) {\r
+ case CRAZY:\r
+ case ALERT:\r
+ case EMERG :\r
+ case CRIT:{\r
+ and_level=ANDROID_LOG_FATAL;\r
+ } break;\r
+ case ERR: {\r
+ and_level=ANDROID_LOG_ERROR;\r
+ } break;\r
+ case WARN: {\r
+ and_level=ANDROID_LOG_WARN;\r
+ } break;\r
+ case NOTICE:\r
+ case INFO: {\r
+ and_level=ANDROID_LOG_INFO;\r
+ } break;\r
+ case DEBUG :{\r
+ and_level=ANDROID_LOG_DEBUG;\r
+ } break;\r
+ };\r
+ __android_log_vprint(and_level, fromModule,\r
+ message, ap);\r
+#endif\r
+ }\r
+\r
+ if (extlog) extlog->LogExtern(buffer); //Replacement for network logging\r
+\r
+\r
+ if (success != EOF)\r
+ return 1;\r
+ else\r
+ return 0;\r
+\r
+}\r
+\r
+\r
+\r
+int Log::status()\r
+{\r
+ if (instance && logfile) return 1;\r
+ else return 0;\r
+}\r
+\r
+void Log::setExternLogger(ExternLogger* login) {\r
+ extlog=login;\r
+ log("Log", Log::DEBUG, "Extern logging started");\r
+}\r
+\r
+\r
+\r
+\r
-/*
- Copyright 2004-2005 Chris Tallon
- Copyright 2003-2004 University Of Bradford
-
- 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 LOG_H
-#define LOG_H
-
-#include <stdio.h>
-#ifndef WIN32
- #include <unistd.h>
- #include <sys/time.h>
-#else
- #include <sys/timeb.h>
-#endif
-
-#include <time.h>
-#include <string.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include "defines.h"
-
-class VDR;
-
-class Log
-{
- public:
- Log();
- ~Log();
- static Log* getInstance();
-
- int init(int defaultLevel, char* fileName, int enabled);
- int shutdown();
- int log(char *fromModule, int level, char *message, ...);
- int status();
- void upLogLevel();
- void downLogLevel();
- void netLogOn();
- void netLogOff();
-
- const static int CRAZY = 0; // mad crazy things that should never happen
- const static int EMERG = 1; // human assist required NOW
- const static int ALERT = 2; // system unusable, but happy to sit there
- const static int CRIT = 3; // still working, but maybe about to die
- const static int ERR = 4; // that response is not even listed...
- const static int WARN = 5; // this could be a bad thing. still running tho
- const static int NOTICE = 6; // significant good thing
- const static int INFO = 7; // verbose good thing
- const static int DEBUG = 8; // debug-level messages
-
- private:
- static Log* instance;
- int initted;
- int logLevel;
- int enabled;
-
- FILE *logfile;
-
- bool netLog;
- VDR* vdr;
-};
-
-#endif
-
-/*
-
-Documentation
--------------
-
-This class is intended to be instatiated once by the core.
-For a one off use:
-
-Log::getInstance()->log("<module-name>", Log::<levelname>, "<message>");
-
-Or, a pointer can be stored and used:
-
-Log *myptr = Log::getInstance();
-
-myptr->log("<module-name>", Log::<levelname>, "<message>");
-myptr->log("<module-name>", Log::<levelname>, "<message>");
-
-Level usages are above.
-
-The message parameter in the log function can be used in the same way as printf, eg.
-
-myptr->log("<module-name>", Log::<levelname>, "Success: %s %i", stringpointer, integer);
-
-*/
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+ Copyright 2003-2004 University Of Bradford\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef LOG_H\r
+#define LOG_H\r
+\r
+#include <stdio.h>\r
+#ifndef WIN32\r
+ #include <unistd.h>\r
+ #include <sys/time.h>\r
+#else\r
+ #include <sys/timeb.h>\r
+#endif\r
+\r
+#include <time.h>\r
+#include <string.h>\r
+#include <stdarg.h>\r
+#include <sys/types.h>\r
+#include "defines.h"\r
+\r
+\r
+class ExternLogger {\r
+public:\r
+ virtual bool LogExtern(const char* message)=0;\r
+};\r
+\r
+\r
+class Log\r
+{\r
+ public:\r
+ Log();\r
+ ~Log();\r
+ static Log* getInstance();\r
+\r
+ int init(int defaultLevel,const char* fileName, int enabled);\r
+ int shutdown();\r
+ int log(const char *fromModule, int level,const char *message, ...);\r
+ int status();\r
+ void upLogLevel();\r
+ void downLogLevel();\r
+ void setExternLogger(ExternLogger* log);\r
+ void unsetExternLogger() {\r
+ extlog=NULL;\r
+ }\r
+\r
+\r
+\r
+ const static int CRAZY = 0; // mad crazy things that should never happen\r
+ const static int EMERG = 1; // human assist required NOW\r
+ const static int ALERT = 2; // system unusable, but happy to sit there\r
+ const static int CRIT = 3; // still working, but maybe about to die\r
+ const static int ERR = 4; // that response is not even listed...\r
+ const static int WARN = 5; // this could be a bad thing. still running tho\r
+ const static int NOTICE = 6; // significant good thing\r
+ const static int INFO = 7; // verbose good thing\r
+ const static int DEBUG = 8; // debug-level messages\r
+\r
+ private:\r
+ static Log* instance;\r
+ int initted;\r
+ int logLevel;\r
+ int enabled;\r
+\r
+ FILE *logfile;\r
+ \r
+ ExternLogger* extlog;\r
+\r
+\r
+};\r
+\r
+#endif\r
+\r
+/*\r
+\r
+Documentation\r
+-------------\r
+\r
+This class is intended to be instatiated once by the core.\r
+For a one off use:\r
+\r
+Log::getInstance()->log("<module-name>", Log::<levelname>, "<message>");\r
+\r
+Or, a pointer can be stored and used:\r
+\r
+Log *myptr = Log::getInstance();\r
+\r
+myptr->log("<module-name>", Log::<levelname>, "<message>");\r
+myptr->log("<module-name>", Log::<levelname>, "<message>");\r
+\r
+Level usages are above.\r
+\r
+The message parameter in the log function can be used in the same way as printf, eg.\r
+\r
+myptr->log("<module-name>", Log::<levelname>, "Success: %s %i", stringpointer, integer);\r
+\r
+*/\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#ifndef WIN32
-#include <unistd.h>
-#include <endian.h>
-#endif
-
-#include "defines.h"
-#include "log.h"
-#include "timers.h"
-#include "vdr.h"
-#include "boxstack.h"
-#include "command.h"
-
-#ifndef _MIPS_ARCH
-
-#include "mtdmvp.h"
-#include "remotemvp.h"
-#include "ledmvp.h"
-#include "osdmvp.h"
-#include "audiomvp.h"
-#include "videomvp.h"
-
-#else
-
-#include "mtdnmt.h"
-#include "remotelirc.h"
-#include "lednmt.h"
-#include "osddirectfb.h"
-#include "audionmt.h"
-#include "videonmt.h"
-
-#endif
-
-
-#include "wol.h"
-#include "vsleeptimer.h"
-
-
-#ifndef WIN32
-void sighandler(int signalReceived);
-#endif
-
-void shutdown(int code);
-
-#ifndef _MIPS_ARCH
-
-extern "C"
-{
- int ticonfig_main(int, char**);
-}
-
-#endif
-
-// Global variables --------------------------------------------------------------------------------------------------
-Log* logger;
-Remote* remote;
-Mtd* mtd;
-Led* led;
-Osd* osd;
-Timers* timers;
-BoxStack* boxstack;
-Command* command;
-VDR* vdr;
-Video* video;
-Audio* audio;
-Wol* wol;
-Sleeptimer* sleeptimer;
-
-// Linux MVP main function and sighandler
-#ifndef WIN32
-int main(int argc, char** argv)
-{
-#ifndef _MIPS_ARCH
- if (strstr(argv[0], "ticonfig")) return ticonfig_main(argc, argv);
-#endif
-
- bool daemonize = true;
- bool debugEnabled = false;
- bool crashed = false;
- char* setServer = NULL;
- int c;
-
- while ((c = getopt(argc, argv, "cdns:")) != -1)
- {
- switch (c)
- {
- case 'c':
- crashed = true;
- break;
- case 'd':
- debugEnabled = true; // and...
- case 'n':
- daemonize = false;
- break;
- case 's':
- setServer = optarg;
- break;
- case '?':
- printf("Unknown option\n");
- return 1;
- default:
- printf("Option error\n");
- return 1;
- }
- }
-
- // Init global vars ------------------------------------------------------------------------------------------------
- logger = new Log();
- timers = new Timers();
- vdr = new VDR();
-#ifndef _MIPS_ARCH
- mtd = new MtdMVP();
- remote = new RemoteMVP();
- led = new LedMVP();
- osd = new OsdMVP();
- audio = new AudioMVP();
- video = new VideoMVP();
-#else
- mtd = new MtdNMT();
- remote = new RemoteLirc();
- led = new LedNMT();
- osd = new OsdDirectFB();
- audio = new AudioNMT();
- video = new VideoNMT();
-#endif
-
-
- boxstack = new BoxStack();
- command = new Command();
- wol = new Wol();
- sleeptimer = new Sleeptimer();
-
- if (!logger || !remote || !mtd || !led || !osd || !video || !audio || !boxstack || !command || !wol || !sleeptimer)
- {
- printf("Could not create objects. Memory problems?\n");
- shutdown(1);
- }
-
- // Get logging module started --------------------------------------------------------------------------------------
-
- if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0))
- {
- printf("Could not initialise log object. Aborting.\n");
- shutdown(1);
- }
-
- logger->log("Core", Log::INFO, "Starting up...");
-
- // Daemonize if not -d
-
- if (daemonize)
- {
- // Fork away
- pid_t forkTest = fork();
- if (forkTest == -1)
- { printf("Cannot fork (1).\n"); exit(1); }
- if (forkTest != 0) _exit(0); // PID returned, I am the parent
- // otherwise, I am the child
- setsid();
- forkTest = fork();
- if (forkTest == -1)
- { printf("Cannot fork (2).\n"); exit(1); }
- if (forkTest != 0) _exit(0); // PID returned, I am the parent
- // otherwise, I am the child
- close(0);
- close(1);
- close(2);
- }
-
- // Set up signal handling ------------------------------------------------------------------------------------------
-
- sighandler_t sigtest;
-
- sigtest = signal(SIGPIPE, SIG_IGN);
- if (sigtest == SIG_ERR)
- {
- logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGPIPE. Aborting.");
- shutdown(1);
- }
- sigtest = signal(SIGINT, sighandler);
- if (sigtest == SIG_ERR)
- {
- logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGINT. Aborting.");
- shutdown(1);
- }
- sigtest = signal(SIGTERM, sighandler);
- if (sigtest == SIG_ERR)
- {
- logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGTERM. Aborting.");
- shutdown(1);
- }
- sigtest = signal(SIGUSR1, sighandler);
- if (sigtest == SIG_ERR)
- {
- logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR1. Aborting.");
- shutdown(1);
- }
-/*
- sigtest = signal(SIGUSR2, sighandler);
- if (sigtest == SIG_ERR)
- {
- logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR2. Aborting.");
- shutdown(1);
- }
-*/
- sigtest = signal(SIGURG, sighandler);
- if (sigtest == SIG_ERR)
- {
- logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGURG. Aborting.");
- shutdown(1);
- }
-
- logger->log("Core", Log::INFO, "Signal handlers set up successfully");
-
-
- // Init modules ----------------------------------------------------------------------------------------------------
- int success;
-#ifndef _MIPS_ARCH
- success = remote->init("/dev/rawir");
-#else
- success = remote->init("/dev/lircd");
-#endif
- if (success)
- {
- logger->log("Core", Log::INFO, "Remote module initialised");
- }
- else
- {
- logger->log("Core", Log::EMERG, "Remote module failed to initialise");
- shutdown(1);
- }
-#ifndef _MIPS_ARCH
- success = led->init(((RemoteMVP*)remote)->getDevice());
-#else
- success = led->init(-1);
-#endif
- if (success)
- {
- logger->log("Core", Log::INFO, "LED module initialised");
- }
- else
- {
- logger->log("Core", Log::EMERG, "LED module failed to initialise");
- shutdown(1);
- }
-
- success = mtd->init();
- if (success)
- {
- logger->log("Core", Log::INFO, "Mtd module initialised");
- }
- else
- {
- logger->log("Core", Log::EMERG, "Mtd module failed to initialise");
- shutdown(1);
- }
-
- success = timers->init();
- if (success)
- {
- logger->log("Core", Log::INFO, "Timers module initialised");
- }
- else
- {
- logger->log("Core", Log::EMERG, "Timers module failed to initialise");
- shutdown(1);
- }
-
- UCHAR videoFormat = (UCHAR)mtd->getPALorNTSC();
- if (videoFormat == Video::PAL) logger->log("Core", Log::INFO, "Read from MTD: PAL 720x576");
- else if (videoFormat == Video::NTSC) logger->log("Core", Log::INFO, "Read from MTD: NTSC 720x480");
- else logger->log("Core", Log::INFO, "No help from MTD. Assuming NTSC 720x480");
-
- success = video->init(videoFormat);
- if (success)
- {
- logger->log("Core", Log::INFO, "Video module initialised");
- }
- else
- {
- logger->log("Core", Log::EMERG, "Video module failed to initialise");
- shutdown(1);
- }
-
- success = osd->init((void*)("/dev/stbgfx"));
- if (success)
- {
- logger->log("Core", Log::INFO, "OSD module initialised");
- }
- else
- {
- logger->log("Core", Log::EMERG, "OSD module failed to initialise");
- shutdown(1);
- }
-
- success = audio->init(Audio::MPEG2_PES);
- if (success)
- {
- logger->log("Core", Log::INFO, "Audio module initialised");
- }
- else
- {
- logger->log("Core", Log::EMERG, "Audio module failed to initialise");
- shutdown(1);
- }
-
- success = vdr->init(3024);
- if (success)
- {
- logger->log("Core", Log::INFO, "VDR module initialised");
- }
- else
- {
- logger->log("Core", Log::EMERG, "VDR module failed to initialise");
- shutdown(1);
- }
-
- success = boxstack->init();
- if (success)
- {
- logger->log("Core", Log::INFO, "BoxStack module initialised");
- }
- else
- {
- logger->log("Core", Log::EMERG, "BoxStack module failed to initialise");
- shutdown(1);
- }
-
- success = command->init(crashed, setServer);
- if (success)
- {
- logger->log("Core", Log::INFO, "Command module initialised");
- }
- else
- {
- logger->log("Core", Log::EMERG, "Command module failed to initialise");
- shutdown(1);
- }
-
- // Other init ------------------------------------------------------------------------------------------------------
-
- logger->log("Core", Log::NOTICE, "Startup successful");
-
- // Run main loop ---------------------------------------------------------------------------------------------------
-
- // Ok, all major device components and other bits are loaded and ready
- command->run();
-
- // When that returns quit ------------------------------------------------------------------------------------------
-
- shutdown(0);
- return 0;
-}
-
-// -------------------------------------------------------------------------------------------------------------------
-
-void sighandler(int signalReceived)
-{
- logger->log("Core", Log::NOTICE, "Signal %i received", signalReceived);
-
- switch (signalReceived)
- {
- case SIGINT:
- {
- logger->log("Core", Log::NOTICE, "Interrupt signal, shutting down...");
- command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe?
- break;
- }
- case SIGTERM:
- {
- logger->log("Core", Log::NOTICE, "Term signal, shutting down...");
- command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe?
- break;
- }
- case SIGUSR1:
- {
- command->sig1();
- break;
- }
-/*
- case SIGUSR1:
- {
- logger->log("Core", Log::DEBUG, "SIGUSR1 caught");
- logger->upLogLevel();
- break;
- }
- case SIGUSR2:
- {
- logger->log("Core", Log::DEBUG, "SIGUSR2 caught");
- logger->downLogLevel();
- break;
- }
-*/
- case SIGURG:
- {
- logger->log("Core", Log::DEBUG, "SIGURG caught");
- break;
- }
- }
-}
-#endif
-
-// -------------------------------------------------------------------------------------------------------------------
-
-void shutdown(int code)
-{
- if (boxstack)
- {
- boxstack->shutdown();
- delete boxstack;
- logger->log("Core", Log::NOTICE, "BoxStack module shut down");
- }
-
- // FIXME, send a del all to boxstack first, then get rid of it after command?
- if (command) // shut down command here in case views have posted messages
- {
- command->shutdown();
- delete command;
- logger->log("Core", Log::NOTICE, "Command module shut down");
- }
-
- if (vdr)
- {
- vdr->shutdown();
- delete vdr;
- logger->log("Core", Log::NOTICE, "VDR module shut down");
- }
-
- if (osd)
- {
- osd->shutdown();
- delete osd;
- logger->log("Core", Log::NOTICE, "OSD module shut down");
- }
-
- if (audio)
- {
- audio->shutdown();
- delete audio;
- logger->log("Core", Log::NOTICE, "Audio module shut down");
- }
-
- if (video)
- {
- video->shutdown();
- delete video;
- logger->log("Core", Log::NOTICE, "Video module shut down");
- }
-
- if (timers)
- {
- timers->shutdown();
- delete timers;
- logger->log("Core", Log::NOTICE, "Timers module shut down");
- }
-
- if (mtd)
- {
- mtd->shutdown();
- delete mtd;
- logger->log("Core", Log::NOTICE, "MTD module shut down");
- }
-
- if (led)
- {
- led->shutdown();
- delete led;
- logger->log("Core", Log::NOTICE, "LED module shut down");
- }
-
- if (remote)
- {
- remote->shutdown();
- delete remote;
- logger->log("Core", Log::NOTICE, "Remote module shut down");
- }
-
- if (wol)
- {
- delete wol;
- logger->log("Core", Log::NOTICE, "WOL module shut down");
- }
-
- if (sleeptimer)
- {
- delete sleeptimer;
- logger->log("Core", Log::NOTICE, "Sleeptimer module shut down");
- }
-
- if (logger)
- {
- logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");
- logger->shutdown();
- delete logger;
- }
-
- exit(code);
-}
-
-// -------------------------------------------------------------------------------------------------------------------
-
-ULLONG ntohll(ULLONG a)
-{
- return htonll(a);
-}
-
-ULLONG htonll(ULLONG a)
-{
- #if BYTE_ORDER == BIG_ENDIAN
- return a;
- #else
- ULLONG b = 0;
-
- b = ((a << 56) & 0xFF00000000000000ULL)
- | ((a << 40) & 0x00FF000000000000ULL)
- | ((a << 24) & 0x0000FF0000000000ULL)
- | ((a << 8) & 0x000000FF00000000ULL)
- | ((a >> 8) & 0x00000000FF000000ULL)
- | ((a >> 24) & 0x0000000000FF0000ULL)
- | ((a >> 40) & 0x000000000000FF00ULL)
- | ((a >> 56) & 0x00000000000000FFULL) ;
-
- return b;
- #endif
-}
-
-void MILLISLEEP(ULONG a)
-{
-#ifndef WIN32
- struct timespec delayTime;
- delayTime.tv_sec = a / 1000;
- delayTime.tv_nsec = (a % 1000) * 1000000;
- nanosleep(&delayTime, NULL);
-#else
- Sleep(a);
-#endif
-}
-
-int min(UINT a, int b)
-{
- if (a > b) return b;
- else return a;
-}
-
-int max(int a, int b)
-{
- if (a > b) return a;
- else return b;
-}
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <signal.h>\r
+#ifndef WIN32\r
+#include <unistd.h>\r
+#include <endian.h>\r
+#endif\r
+\r
+#include "defines.h"\r
+#include "log.h"\r
+#include "timers.h"\r
+#include "vdr.h"\r
+#include "boxstack.h"\r
+#include "command.h"\r
+\r
+\r
+#ifdef VOMP_PLATTFORM_MVP\r
+\r
+\r
+#include "mtdmvp.h"\r
+#include "remotemvp.h"\r
+#include "ledmvp.h"\r
+#include "osdmvp.h"\r
+#include "audiomvp.h"\r
+#include "videomvp.h"\r
+\r
+extern "C"\r
+{\r
+ int ticonfig_main(int, char**);\r
+}\r
+\r
+#endif\r
+\r
+#ifdef VOMP_PLATTFORM_NMT\r
+\r
+#include "mtdnmt.h"\r
+#include "remotelirc.h"\r
+#include "lednmt.h"\r
+#include "osddirectfb.h"\r
+#include "audionmt.h"\r
+#include "videonmt.h"\r
+\r
+#endif\r
+\r
+#ifdef VOMP_PLATTFORM_RASPBERRY\r
+\r
+#include "mtdraspberry.h"\r
+#include "remotelinux.h"\r
+#include "ledraspberry.h"\r
+#include "osdopengl.h"\r
+#include "audiovpe.h"\r
+#include "videovpeogl.h"\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+#include "wol.h"\r
+#include "vsleeptimer.h"\r
+\r
+\r
+#ifndef WIN32\r
+void sighandler(int signalReceived);\r
+#endif\r
+\r
+void shutdown(int code);\r
+\r
+\r
+\r
+// Global variables --------------------------------------------------------------------------------------------------\r
+Log* logger;\r
+Remote* remote;\r
+Mtd* mtd;\r
+Led* led;\r
+Osd* osd;\r
+Timers* timers;\r
+BoxStack* boxstack;\r
+Command* command;\r
+VDR* vdr;\r
+Video* video;\r
+Audio* audio;\r
+Wol* wol;\r
+Sleeptimer* sleeptimer;\r
+\r
+// Linux MVP main function and sighandler\r
+#ifndef WIN32\r
+int main(int argc, char** argv)\r
+{\r
+#ifdef VOMP_PLATTFORM_MVP\r
+ if (strstr(argv[0], "ticonfig")) return ticonfig_main(argc, argv);\r
+#endif\r
+\r
+ bool daemonize = true;\r
+ bool debugEnabled = false;\r
+ bool crashed = false;\r
+ char* setServer = NULL;\r
+ int c;\r
+\r
+ while ((c = getopt(argc, argv, "cdns:")) != -1)\r
+ {\r
+ switch (c)\r
+ {\r
+ case 'c':\r
+ crashed = true;\r
+ break;\r
+ case 'd':\r
+ debugEnabled = true; // and...\r
+ case 'n':\r
+ daemonize = false;\r
+ break; \r
+ case 's':\r
+ setServer = optarg;\r
+ break;\r
+ case '?':\r
+ printf("Unknown option\n");\r
+ return 1;\r
+ default:\r
+ printf("Option error\n");\r
+ return 1;\r
+ }\r
+ }\r
+ \r
+ // Init global vars ------------------------------------------------------------------------------------------------\r
+ logger = new Log();\r
+ timers = new Timers();\r
+ vdr = new VDR();\r
+\r
+ mtd = new Mtd_TYPE();\r
+ remote = new Remote_TYPE();\r
+ led = new Led_TYPE();\r
+ osd = new Osd_TYPE();\r
+ audio = new Audio_TYPE();\r
+ video = new Video_TYPE();\r
+\r
+\r
+\r
+ boxstack = new BoxStack();\r
+ command = new Command();\r
+ wol = new Wol();\r
+ sleeptimer = new Sleeptimer();\r
+ \r
+ if (!logger || !remote || !mtd || !led || !osd || !video || !audio || !boxstack || !command || !wol || !sleeptimer)\r
+ {\r
+ printf("Could not create objects. Memory problems?\n");\r
+ shutdown(1);\r
+ }\r
+\r
+ // Get logging module started --------------------------------------------------------------------------------------\r
+\r
+ if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0))\r
+ {\r
+ printf("Could not initialise log object. Aborting.\n");\r
+ shutdown(1);\r
+ }\r
+\r
+ logger->log("Core", Log::INFO, "Starting up...");\r
+\r
+ // Daemonize if not -d\r
+\r
+ if (daemonize)\r
+ {\r
+ // Fork away\r
+ pid_t forkTest = fork();\r
+ if (forkTest == -1)\r
+ { printf("Cannot fork (1).\n"); exit(1); }\r
+ if (forkTest != 0) _exit(0); // PID returned, I am the parent\r
+ // otherwise, I am the child\r
+ setsid();\r
+ forkTest = fork();\r
+ if (forkTest == -1)\r
+ { printf("Cannot fork (2).\n"); exit(1); }\r
+ if (forkTest != 0) _exit(0); // PID returned, I am the parent\r
+ // otherwise, I am the child\r
+ close(0);\r
+ close(1);\r
+ close(2);\r
+ }\r
+\r
+ // Set up signal handling ------------------------------------------------------------------------------------------\r
+\r
+ sighandler_t sigtest;\r
+\r
+ sigtest = signal(SIGPIPE, SIG_IGN);\r
+ if (sigtest == SIG_ERR)\r
+ {\r
+ logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGPIPE. Aborting.");\r
+ shutdown(1);\r
+ }\r
+ sigtest = signal(SIGINT, sighandler);\r
+ if (sigtest == SIG_ERR)\r
+ {\r
+ logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGINT. Aborting.");\r
+ shutdown(1);\r
+ }\r
+ sigtest = signal(SIGTERM, sighandler);\r
+ if (sigtest == SIG_ERR)\r
+ {\r
+ logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGTERM. Aborting.");\r
+ shutdown(1);\r
+ }\r
+ sigtest = signal(SIGUSR1, sighandler);\r
+ if (sigtest == SIG_ERR)\r
+ {\r
+ logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR1. Aborting.");\r
+ shutdown(1);\r
+ }\r
+/*\r
+ sigtest = signal(SIGUSR2, sighandler);\r
+ if (sigtest == SIG_ERR)\r
+ {\r
+ logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR2. Aborting.");\r
+ shutdown(1);\r
+ }\r
+*/\r
+ sigtest = signal(SIGURG, sighandler);\r
+ if (sigtest == SIG_ERR)\r
+ {\r
+ logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGURG. Aborting.");\r
+ shutdown(1);\r
+ }\r
+\r
+ logger->log("Core", Log::INFO, "Signal handlers set up successfully");\r
+\r
+\r
+ // Init modules ----------------------------------------------------------------------------------------------------\r
+ int success;\r
+\r
+ success = remote->init(RemoteStartDev);\r
+\r
+ if (success)\r
+ {\r
+ logger->log("Core", Log::INFO, "Remote module initialised");\r
+ }\r
+ else\r
+ {\r
+ logger->log("Core", Log::EMERG, "Remote module failed to initialise");\r
+ shutdown(1);\r
+ }\r
+#ifdef VOMP_PLATTFORM_MVP\r
+ success = led->init(((RemoteMVP*)remote)->getDevice());\r
+#else\r
+ success = led->init(-1);\r
+#endif \r
+ if (success)\r
+ {\r
+ logger->log("Core", Log::INFO, "LED module initialised");\r
+ }\r
+ else\r
+ {\r
+ logger->log("Core", Log::EMERG, "LED module failed to initialise");\r
+ shutdown(1);\r
+ }\r
+\r
+ success = mtd->init();\r
+ if (success)\r
+ {\r
+ logger->log("Core", Log::INFO, "Mtd module initialised");\r
+ }\r
+ else\r
+ {\r
+ logger->log("Core", Log::EMERG, "Mtd module failed to initialise");\r
+ shutdown(1);\r
+ }\r
+\r
+ success = timers->init();\r
+ if (success)\r
+ {\r
+ logger->log("Core", Log::INFO, "Timers module initialised");\r
+ }\r
+ else\r
+ {\r
+ logger->log("Core", Log::EMERG, "Timers module failed to initialise");\r
+ shutdown(1);\r
+ }\r
+\r
+ UCHAR videoFormat = (UCHAR)mtd->getPALorNTSC();\r
+ if (videoFormat == Video::PAL) logger->log("Core", Log::INFO, "Read from MTD: PAL 720x576");\r
+ else if (videoFormat == Video::NTSC) logger->log("Core", Log::INFO, "Read from MTD: NTSC 720x480");\r
+ else logger->log("Core", Log::INFO, "No help from MTD. Assuming NTSC 720x480");\r
+\r
+ success = video->init(videoFormat);\r
+ if (success)\r
+ {\r
+ logger->log("Core", Log::INFO, "Video module initialised");\r
+ }\r
+ else\r
+ {\r
+ logger->log("Core", Log::EMERG, "Video module failed to initialise");\r
+ shutdown(1);\r
+ }\r
+\r
+ success = osd->init((void*)OsdStartDev);\r
+ if (success)\r
+ {\r
+ logger->log("Core", Log::INFO, "OSD module initialised");\r
+ }\r
+ else\r
+ {\r
+ logger->log("Core", Log::EMERG, "OSD module failed to initialise");\r
+ shutdown(1);\r
+ }\r
+\r
+ success = audio->init(Audio::MPEG2_PES);\r
+ if (success)\r
+ {\r
+ logger->log("Core", Log::INFO, "Audio module initialised");\r
+ }\r
+ else\r
+ {\r
+ logger->log("Core", Log::EMERG, "Audio module failed to initialise");\r
+ shutdown(1);\r
+ }\r
+\r
+ success = vdr->init(3024);\r
+ if (success)\r
+ {\r
+ logger->log("Core", Log::INFO, "VDR module initialised");\r
+ }\r
+ else\r
+ {\r
+ logger->log("Core", Log::EMERG, "VDR module failed to initialise");\r
+ shutdown(1);\r
+ }\r
+\r
+ success = boxstack->init();\r
+ if (success)\r
+ {\r
+ logger->log("Core", Log::INFO, "BoxStack module initialised");\r
+ }\r
+ else\r
+ {\r
+ logger->log("Core", Log::EMERG, "BoxStack module failed to initialise");\r
+ shutdown(1);\r
+ }\r
+\r
+ success = command->init(crashed, setServer);\r
+ if (success)\r
+ {\r
+ logger->log("Core", Log::INFO, "Command module initialised");\r
+ }\r
+ else\r
+ {\r
+ logger->log("Core", Log::EMERG, "Command module failed to initialise");\r
+ shutdown(1);\r
+ }\r
+\r
+ // Other init ------------------------------------------------------------------------------------------------------\r
+\r
+ logger->log("Core", Log::NOTICE, "Startup successful");\r
+\r
+ // Run main loop ---------------------------------------------------------------------------------------------------\r
+\r
+ // Ok, all major device components and other bits are loaded and ready\r
+ command->run();\r
+\r
+ // When that returns quit ------------------------------------------------------------------------------------------\r
+\r
+ shutdown(0);\r
+ return 0;\r
+}\r
+\r
+// -------------------------------------------------------------------------------------------------------------------\r
+\r
+void sighandler(int signalReceived)\r
+{\r
+ logger->log("Core", Log::NOTICE, "Signal %i received", signalReceived);\r
+\r
+ switch (signalReceived)\r
+ {\r
+ case SIGINT:\r
+ {\r
+ logger->log("Core", Log::NOTICE, "Interrupt signal, shutting down...");\r
+ command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe?\r
+ break;\r
+ }\r
+ case SIGTERM:\r
+ {\r
+ logger->log("Core", Log::NOTICE, "Term signal, shutting down...");\r
+ command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe?\r
+ break;\r
+ }\r
+ case SIGUSR1:\r
+ {\r
+ command->sig1();\r
+ break;\r
+ }\r
+/*\r
+ case SIGUSR1:\r
+ {\r
+ logger->log("Core", Log::DEBUG, "SIGUSR1 caught");\r
+ logger->upLogLevel();\r
+ break;\r
+ }\r
+ case SIGUSR2:\r
+ {\r
+ logger->log("Core", Log::DEBUG, "SIGUSR2 caught");\r
+ logger->downLogLevel();\r
+ break;\r
+ }\r
+*/\r
+ case SIGURG:\r
+ {\r
+ logger->log("Core", Log::DEBUG, "SIGURG caught");\r
+ break;\r
+ }\r
+ }\r
+}\r
+#endif\r
+\r
+// -------------------------------------------------------------------------------------------------------------------\r
+\r
+void shutdown(int code)\r
+{\r
+ if (boxstack)\r
+ {\r
+ boxstack->shutdown();\r
+ delete boxstack;\r
+ logger->log("Core", Log::NOTICE, "BoxStack module shut down");\r
+ }\r
+\r
+ // FIXME, send a del all to boxstack first, then get rid of it after command?\r
+ if (command) // shut down command here in case views have posted messages\r
+ {\r
+ command->shutdown();\r
+ delete command;\r
+ logger->log("Core", Log::NOTICE, "Command module shut down");\r
+ }\r
+\r
+ if (vdr)\r
+ {\r
+ vdr->shutdown();\r
+ delete vdr;\r
+ logger->log("Core", Log::NOTICE, "VDR module shut down");\r
+ }\r
+\r
+ if (osd)\r
+ {\r
+ osd->shutdown();\r
+ delete osd;\r
+ logger->log("Core", Log::NOTICE, "OSD module shut down");\r
+ }\r
+\r
+ if (audio)\r
+ {\r
+ audio->shutdown();\r
+ delete audio;\r
+ logger->log("Core", Log::NOTICE, "Audio module shut down");\r
+ }\r
+\r
+ if (video)\r
+ {\r
+ video->shutdown();\r
+ delete video;\r
+ logger->log("Core", Log::NOTICE, "Video module shut down");\r
+ }\r
+\r
+ if (timers)\r
+ {\r
+ timers->shutdown();\r
+ delete timers;\r
+ logger->log("Core", Log::NOTICE, "Timers module shut down");\r
+ }\r
+\r
+ if (mtd)\r
+ {\r
+ mtd->shutdown();\r
+ delete mtd;\r
+ logger->log("Core", Log::NOTICE, "MTD module shut down");\r
+ }\r
+\r
+ if (led)\r
+ {\r
+ led->shutdown();\r
+ delete led;\r
+ logger->log("Core", Log::NOTICE, "LED module shut down");\r
+ }\r
+\r
+ if (remote)\r
+ {\r
+ remote->shutdown();\r
+ delete remote;\r
+ logger->log("Core", Log::NOTICE, "Remote module shut down");\r
+ }\r
+\r
+ if (wol)\r
+ {\r
+ delete wol;\r
+ logger->log("Core", Log::NOTICE, "WOL module shut down");\r
+ }\r
+\r
+ if (sleeptimer)\r
+ {\r
+ delete sleeptimer;\r
+ logger->log("Core", Log::NOTICE, "Sleeptimer module shut down");\r
+ }\r
+\r
+ if (logger)\r
+ {\r
+ logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");\r
+ logger->shutdown();\r
+ delete logger;\r
+ }\r
+\r
+ exit(code);\r
+}\r
+\r
+// -------------------------------------------------------------------------------------------------------------------\r
+\r
+ULLONG htonll(ULLONG a)\r
+{\r
+ #if BYTE_ORDER == BIG_ENDIAN\r
+ return a;\r
+ #else\r
+ ULLONG b = 0;\r
+\r
+ b = ((a << 56) & 0xFF00000000000000ULL)\r
+ | ((a << 40) & 0x00FF000000000000ULL)\r
+ | ((a << 24) & 0x0000FF0000000000ULL)\r
+ | ((a << 8) & 0x000000FF00000000ULL)\r
+ | ((a >> 8) & 0x00000000FF000000ULL)\r
+ | ((a >> 24) & 0x0000000000FF0000ULL)\r
+ | ((a >> 40) & 0x000000000000FF00ULL)\r
+ | ((a >> 56) & 0x00000000000000FFULL) ;\r
+\r
+ return b;\r
+ #endif\r
+}\r
+\r
+ULLONG ntohll(ULLONG a)\r
+{\r
+ return htonll(a);\r
+}\r
+\r
+void MILLISLEEP(ULONG a)\r
+{\r
+#ifndef WIN32\r
+ struct timespec delayTime;\r
+ delayTime.tv_sec = a / 1000;\r
+ delayTime.tv_nsec = (a % 1000) * 1000000;\r
+ nanosleep(&delayTime, NULL);\r
+#else\r
+ Sleep(a);\r
+#endif\r
+}\r
+\r
+int min(UINT a, int b)\r
+{\r
+ if (a > b) return b;\r
+ else return a;\r
+}\r
+\r
+int max(int a, int b)\r
+{\r
+ if (a > b) return a;\r
+ else return b;\r
+}\r
+\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef MESSAGE_H
-#define MESSAGE_H
-
-#include <stdio.h>
-#include "defines.h"
-
-// Usage of messages is more dubious now that the single master mutex lock
-// protects all gui actions. Reason(s) for usage:
-// 1. View A wants something to be done by View B *after* View A has been deleted
-// 2. A thread wants its object/view deleting *after* the thread has exited
-
-// Put a justification line after call to Message* m = new Message() line
-// So that the sources can be grepped for proper message useage
-
-class Message
-{
- public:
- Message();
-
- void* from;
- void* to;
- ULONG message;
- ULONG parameter;
- ULONG tag; // use this for identifying which object / question is being replied to
-
- const static ULONG QUESTION_YES = 1;
- const static ULONG CLOSE_ME = 2;
- const static ULONG PLAY_SELECTED_RECORDING = 3;
- const static ULONG DELETE_SELECTED_RECORDING = 4;
- const static ULONG SCREENSHOT = 5;
- const static ULONG CHANNEL_CHANGE = 6;
- const static ULONG RESUME_SELECTED_RECORDING = 7;
- const static ULONG STOP_PLAYBACK = 9;
- const static ULONG SERVER_SELECTED = 10;
- const static ULONG VDR_CONNECTED = 11;
- const static ULONG ADD_VIEW = 12;
- const static ULONG REDRAW_LANG = 14;
- const static ULONG EPG = 16;
- const static ULONG EPG_CLOSE = 17;
- const static ULONG CHANGED_OPTIONS = 18;
- const static ULONG CONNECTION_LOST = 19;
- const static ULONG MOVE_RECORDING = 20;
- const static ULONG UDP_BUTTON = 21;
- const static ULONG PLAYER_EVENT = 22;
- const static ULONG AUDIO_CHANGE_CHANNEL = 23;
- const static ULONG CHILD_CLOSE = 24;
- const static ULONG MOUSE_MOVE = 25;
- const static ULONG MOUSE_LBDOWN = 26;
- const static ULONG CHANGE_LANGUAGE = 27;
- const static ULONG LAST_VIEW_CLOSE = 28;
- const static ULONG CHANGED_REMOTECONTROL = 29;
- const static ULONG DELETE_SELECTED_TIMER = 30;
- const static ULONG CHANGED_DEVICEOPTIONS = 31;
- const static ULONG TELETEXTUPDATE = 32;
- const static ULONG TELETEXTUPDATEFIRSTLINE = 33;
- const static ULONG SUBTITLE_CHANGE_CHANNEL = 34;
-};
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef MESSAGE_H\r
+#define MESSAGE_H\r
+\r
+#include <stdio.h>\r
+\r
+class Message;\r
+#include "defines.h"\r
+\r
+// Usage of messages is more dubious now that the single master mutex lock\r
+// protects all gui actions. Reason(s) for usage:\r
+// 1. View A wants something to be done by View B *after* View A has been deleted\r
+// 2. A thread wants its object/view deleting *after* the thread has exited\r
+\r
+// Put a justification line after call to Message* m = new Message() line\r
+// So that the sources can be grepped for proper message useage\r
+\r
+class Message\r
+{\r
+ public:\r
+ Message();\r
+\r
+ void* from;\r
+ void* to;\r
+ ULONG message;\r
+ ULONG parameter;\r
+ ULONG tag; // use this for identifying which object / question is being replied to\r
+\r
+ const static ULONG QUESTION_YES = 1;\r
+ const static ULONG CLOSE_ME = 2;\r
+ const static ULONG PLAY_SELECTED_RECORDING = 3;\r
+ const static ULONG DELETE_SELECTED_RECORDING = 4;\r
+ const static ULONG SCREENSHOT = 5;\r
+ const static ULONG CHANNEL_CHANGE = 6;\r
+ const static ULONG RESUME_SELECTED_RECORDING = 7;\r
+ const static ULONG STOP_PLAYBACK = 9;\r
+ const static ULONG SERVER_SELECTED = 10;\r
+ const static ULONG VDR_CONNECTED = 11;\r
+ const static ULONG ADD_VIEW = 12;\r
+ const static ULONG REDRAW_LANG = 14;\r
+ const static ULONG EPG = 16;\r
+ const static ULONG EPG_CLOSE = 17;\r
+ const static ULONG CHANGED_OPTIONS = 18;\r
+ const static ULONG CONNECTION_LOST = 19;\r
+ const static ULONG MOVE_RECORDING = 20;\r
+ const static ULONG UDP_BUTTON = 21;\r
+ const static ULONG PLAYER_EVENT = 22;\r
+ const static ULONG AUDIO_CHANGE_CHANNEL = 23;\r
+ const static ULONG CHILD_CLOSE = 24;\r
+ const static ULONG MOUSE_MOVE = 25;\r
+ const static ULONG MOUSE_LBDOWN = 26;\r
+ const static ULONG CHANGE_LANGUAGE = 27;\r
+ const static ULONG LAST_VIEW_CLOSE = 28;\r
+ const static ULONG CHANGED_REMOTECONTROL = 29;\r
+ const static ULONG DELETE_SELECTED_TIMER = 30;\r
+ const static ULONG CHANGED_DEVICEOPTIONS = 31;\r
+ const static ULONG TELETEXTUPDATE = 32;\r
+ const static ULONG TELETEXTUPDATEFIRSTLINE = 33;\r
+ const static ULONG SUBTITLE_CHANGE_CHANNEL = 34;\r
+ const static ULONG MOUSE_ANDROID_SCROLL = 35;\r
+};\r
+\r
+#endif\r
-OBJECTS1 = command.o log.o tcp.o dsock.o thread.o timers.o i18n.o mutex.o \
- message.o messagequeue.o udp.o wol.o \
- vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o \
- directory.o mark.o option.o \
- player.o playerradio.o vfeed.o afeed.o \
- demuxer.o demuxervdr.o demuxerts.o stream.o draintarget.o \
- region.o colour.o boxstack.o boxx.o tbboxx.o \
- vinfo.o vquestion.o vrecordinglist.o vrecording.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 \
- vradiorec.o vaudioselector.o vscreensaver.o vopts.o \
- wselectlist.o wjpeg.o wsymbol.o wbutton.o wtextbox.o wwss.o \
- woptionpane.o woptionbox.o wremoteconfig.o wtabbar.o \
- fonts/helvB24.o fonts/helvB18.o \
- remote.o led.o mtd.o video.o audio.o osd.o surface.o \
- vmedialist.o media.o vpicturebanner.o \
- audioplayer.o demuxeraudio.o abstractoption.o \
- eventdispatcher.o vdrrequestpacket.o vdrresponsepacket.o \
- vvideolivetv.o vsleeptimer.o \
- playerlivetv.o playerliveradio.o \
- wprogressbar.o \
- bitmap.o dvbsubtitles.o \
- imagereader.o vcolourtuner.o mediaoptions.o mediaplayer.o mediafile.o \
- serialize.o localmediafile.o vmediaview.o vvideomedia.o playermedia.o \
- demuxermedia.o tfeed.o vteletextview.o teletextdecodervbiebu.o \
- teletxt/txtfont.o
-
+OBJECTS1 = command.o tcp.o dsock.o thread.o timers.o i18n.o \\r
+ message.o messagequeue.o udp.o wol.o audio.o video.o log.o mutex.o \\r
+ vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o \\r
+ directory.o mark.o option.o \\r
+ player.o playerradio.o vfeed.o afeed.o \\r
+ demuxer.o demuxervdr.o demuxerts.o stream.o \\r
+ region.o colour.o boxstack.o boxx.o tbboxx.o \\r
+ vinfo.o vquestion.o vrecordinglist.o vrecording.o \\r
+ vmute.o vvolume.o vtimerlist.o vtimeredit.o vrecordingmenu.o \\r
+ vchannellist.o vwelcome.o vvideorec.o vepgsettimer.o \\r
+ vchannelselect.o vserverselect.o vconnect.o vepg.o vrecmove.o \\r
+ vradiorec.o vaudioselector.o vscreensaver.o vopts.o \\r
+ wselectlist.o wjpeg.o wsymbol.o wbutton.o wtextbox.o wwss.o \\r
+ woptionpane.o woptionbox.o wremoteconfig.o wtabbar.o \\r
+ fonts/helvB24.o fonts/helvB18.o \\r
+ remote.o led.o mtd.o osd.o surface.o \\r
+ media.o vpicturebanner.o \\r
+ audioplayer.o demuxeraudio.o abstractoption.o \\r
+ eventdispatcher.o vdrrequestpacket.o vdrresponsepacket.o \\r
+ vvideolivetv.o vsleeptimer.o \\r
+ playerlivetv.o playerliveradio.o \\r
+ wprogressbar.o \\r
+ bitmap.o dvbsubtitles.o \\r
+ imagereader.o mediaoptions.o mediaplayer.o mediafile.o \\r
+ serialize.o localmediafile.o playermedia.o \\r
+ demuxermedia.o tfeed.o vteletextview.o teletextdecodervbiebu.o \\r
+ teletxt/txtfont.o\r
+\r
return fdOsd;
}
+Surface * OsdMvp::createNewSurface();{
+ return (Surface*)new SurfaceMvp();
+}
+
+
int OsdMVP::init(void* device)
{
if (initted) return 0;
return 1;
}
-void OsdMVP::screenShot(char* fileName)
+void OsdMVP::screenShot(const char* fileName)
{
screen->screenShot(fileName);
}
int init(void* device);
int shutdown();
+ Surface * createNewSurface();
+
int getFD();
- void screenShot(char* fileName);
+ void screenShot(const char* fileName);
private:
};
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-
-#include "osdwin.h"
-#include "mtd.h"
-#include "videowin.h"
-#include "surfacewin.h"
-
-#include "dsallocator.h"
-#include "message.h"
-#include "command.h"
-
-#define BACKBUFFER_WIDTH 1280
-#define BACKBUFFER_HEIGHT 720
-
-
-
-typedef HRESULT (__stdcall *FCT_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager);
-typedef HRESULT (__stdcall *FCT_MFCreateVideoSampleFromSurface)(IUnknown* pUnkSurface, IMFSample** ppSample);
-
-FCT_DXVA2CreateDirect3DDeviceManager9 ptrDXVA2CreateDirect3DDeviceManager9=NULL;
-FCT_MFCreateVideoSampleFromSurface ptrMFCreateVideoSampleFromSurface=NULL;
-
-//This is stuff for rendering the OSD
-
-
-OsdWin::OsdWin()
-{
- d3d=NULL;
- d3ddevice=NULL;
- d3drtsurf=NULL;
- swappy=NULL;
- swapsurf=NULL;
- evrstate=EVR_pres_off;
- window=NULL;
-
- external_driving=false;
- dsallocator=NULL;
- filter_type=D3DTEXF_FORCE_DWORD;
- lastrendertime=timeGetTime();
- event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);
- d3dmutex = CreateMutex(NULL,FALSE,NULL);
- /*EVR stuff*/
- dxvadevicehandle=NULL;
- evrsupported=true;
- HMODULE hlib=NULL;
- hlib=LoadLibrary("dxva2.dll");
- if (!hlib) {
- evrsupported=false;
- return;
- }
- ptrDXVA2CreateDirect3DDeviceManager9=(FCT_DXVA2CreateDirect3DDeviceManager9)GetProcAddress(hlib, "DXVA2CreateDirect3DDeviceManager9");
- if (!ptrDXVA2CreateDirect3DDeviceManager9){
- evrsupported=false;
- return;
- }
-
- hlib=LoadLibrary("evr.dll");
- if (!hlib) {
- evrsupported=false;
- return;
- }
-
- ptrMFCreateVideoSampleFromSurface = (FCT_MFCreateVideoSampleFromSurface)GetProcAddress(hlib,"MFCreateVideoSampleFromSurface");
- if (!ptrMFCreateVideoSampleFromSurface){
- evrsupported=false;
- return;
- }
-
-}
-
-OsdWin::~OsdWin()
-{
-
- if (initted)
- {
- threadStop();
- shutdown();
- }
- CloseHandle(event);
- CloseHandle(d3dmutex);
-}
-
-int OsdWin::getFD()
-{
- if (!initted) return 0;
- return fdOsd;
-}
-
-int OsdWin::init(void* device)
-{
- if (initted) return 0;
- Video* video = Video::getInstance();
- window=*((HWND*)device);
- //First Create Direct 3D Object
- d3d=Direct3DCreate9(D3D_SDK_VERSION);
- if (!d3d)
- {
- Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 object!");
- return 0;
- }
- // then create the Device
- D3DPRESENT_PARAMETERS d3dparas;
- ZeroMemory(&d3dparas,sizeof(d3dparas));
- d3dparas.BackBufferWidth=BACKBUFFER_WIDTH;
- d3dparas.BackBufferHeight=BACKBUFFER_HEIGHT;
- d3dparas.Windowed=TRUE;
- d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;
- if (d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,*((HWND*) device),
- D3DCREATE_SOFTWARE_VERTEXPROCESSING |D3DCREATE_MULTITHREADED,&d3dparas,&d3ddevice)!=D3D_OK) {
- Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 device!");
- return 0;
- }
- d3ddevice->GetRenderTarget(0,&d3drtsurf);
-
- /*
- if (!InitVertexBuffer()) {
- Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 vertex buf!");
- return 0;
- }*/
- /* We have to determine which kind of filtering is supported*/
- D3DCAPS9 caps;
- d3ddevice->GetDeviceCaps(&caps);
- if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR)!=0)
- && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)!=0)) {
- if (filter_type==D3DTEXF_FORCE_DWORD) {
- filter_type=D3DTEXF_LINEAR;
- }
- } else {
- if (filter_type==D3DTEXF_LINEAR)
- {
- filter_type=D3DTEXF_POINT;
- }
- }
-
- if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT)!=0)
- && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT)!=0)) {
- if (filter_type==D3DTEXF_FORCE_DWORD)
- {
- filter_type=D3DTEXF_POINT;
- }
- } else {
- if (filter_type==D3DTEXF_POINT) {
- filter_type=D3DTEXF_NONE;
- }
- }
- if (filter_type==D3DTEXF_FORCE_DWORD) {
- filter_type=D3DTEXF_NONE;
- }
-
- if (evrsupported)
- {
- if (ptrDXVA2CreateDirect3DDeviceManager9(&dxvatoken,&d3ddevman)!=S_OK) evrsupported=false;
- else {
- d3ddevman->ResetDevice(d3ddevice,dxvatoken);
- }
- }
-
-
-
-
- //Now we will create the Screen
- screen = new SurfaceWin(Surface::SCREEN);
- SetEvent(event);//Now all devices are ready
- screen->create(video->getScreenWidth(), video->getScreenHeight());
- screen->display();
- initted = 1; // must set this here or create surface won't work
- threadStart();
-
- return 1;
-}
-
-void OsdWin::LockDevice()
-{
- if (!evrsupported) return;
- if (!dxvadevicehandle)
- {
- d3ddevman->OpenDeviceHandle(&dxvadevicehandle);
- }
- IDirect3DDevice9 *temp;
- d3ddevman->LockDevice(dxvadevicehandle,&temp,TRUE);
-
-}
-
-void OsdWin::UnlockDevice()
-{
- if (!evrsupported) return;
- if (!initted) return;
- d3ddevman->UnlockDevice(dxvadevicehandle,TRUE);
- if (dxvadevicehandle)
- {
- d3ddevman->CloseDeviceHandle(dxvadevicehandle);
- dxvadevicehandle=NULL;
- }
-
-}
-
-DWORD OsdWin::getFilterCaps()
-{
- if (!initted) return NULL;
- D3DCAPS9 caps;
- d3ddevice->GetDeviceCaps(&caps);
- return caps.StretchRectFilterCaps;
-}
-
-LPDIRECT3DVERTEXBUFFER9 OsdWin::InitVertexBuffer(DWORD width, DWORD height)
-{
- LPDIRECT3DVERTEXBUFFER9 ret =NULL;
- Video* video=Video::getInstance();
- FLOAT texx=((float)video->getScreenWidth())/1024.f;
- FLOAT texy=((float)video->getScreenHeight())/1024.f;
- D3DCOLOR osdcolor=D3DCOLOR_RGBA(255,255,255,255);
- osdvertices[0].c=osdcolor;
- osdvertices[0].x=0.f-0.5f;
- osdvertices[0].y=0.f-0.5f;
- osdvertices[0].z=0.5f;
- osdvertices[0].rhw=1.f;
- osdvertices[0].u=0.f;
- osdvertices[0].v=0.f;
- osdvertices[1].c=osdcolor;
- osdvertices[1].x=((float)width)-0.5f;-0.5f;
- osdvertices[1].y=0.f-0.5f;
- osdvertices[1].z=0.5f;
- osdvertices[1].u=texx;
- osdvertices[1].v=0.f;
- osdvertices[1].rhw=1.f;
- osdvertices[2].c=osdcolor;
- osdvertices[2].x=((float)width)-0.5f;
- osdvertices[2].y=((float)height)-0.5f;
- osdvertices[2].z=0.5f;
- osdvertices[2].rhw=1.f;
- osdvertices[2].u=texx;
- osdvertices[2].v=texy;
- osdvertices[3].c=osdcolor;
- osdvertices[3].x=0.f-0.5f;
- osdvertices[3].y=((float)height)-0.5f;
- osdvertices[3].z=0.5f;
- osdvertices[3].rhw=1.f;
- osdvertices[3].u=0.f;
- osdvertices[3].v=texy;
-
- if (d3ddevice->CreateVertexBuffer(4*sizeof(OSDVERTEX),0,D3DFVF_OSDVERTEX,D3DPOOL_MANAGED,
- &ret,NULL)!=D3D_OK) {
- return NULL;
- }
- void *pvertex=NULL;
- if (ret->Lock(0,sizeof(osdvertices),&pvertex,0)!=D3D_OK) {
- return NULL;
- }
- memcpy(pvertex,osdvertices,sizeof(osdvertices));
- ret->Unlock();
- return ret;
-}
-
-int OsdWin::shutdown()
-{
- if (!initted) return 0;
- initted = 0;
- evrsupported=0;
- if (d3ddevman) d3ddevman->Release();
- d3drtsurf->Release();
- d3ddevice->Release();
- d3d->Release();
- if (swapsurf) swapsurf->Release();
- if (swappy) swappy->Release();
-
- return 1;
-}
-
-void OsdWin::screenShot(char* fileName)
-{
- screen->screenShot(fileName);
-}
-
-void OsdWin::threadMethod()
-{
- while (true)
- {
- DWORD waittime=10;
- if (initted){
- if (evrstate==EVR_pres_off || evrstate==EVR_pres_pause)
- {
- Render();
- } else if (evrstate==EVR_pres_started)
- {
- LPDIRECT3DSURFACE9 surf;
- if (dsallocator) dsallocator->GetNextSurface(&surf,&waittime);
- if (surf==NULL)
- {
- Render();
- }
- else
- {
- RenderDS(surf);
- surf->Release();
- if (dsallocator) dsallocator->DiscardSurfaceandgetWait(&waittime);
- }
- }
- }
- threadCheckExit();
- if (waittime!=0) Sleep(min(10,waittime));
- //Sleep(1);
- }
-}
-
-
-void OsdWin::threadPostStopCleanup()
-{
- //Doing nothing
- //goo;
-}
-
-
-// This function is called from the WinMain function in order to get Screen updates
-void OsdWin::Render()
-{
- if (!initted) return ;
- if (external_driving) {
- DWORD time1=timeGetTime(); //Updates the Menue
- if ((time1-lastrendertime)>200) {//5 fps for OSD updates are enough, avoids tearing
- InternalRendering(NULL);
- lastrendertime=timeGetTime();
- } else {
- //Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads
- }
- } else {
- DWORD time1=timeGetTime();
- if ((time1-lastrendertime)>50) {//10 fps for OSD updates are enough, avoids tearing
- InternalRendering(NULL);
- lastrendertime=timeGetTime();
- } else {
- //Sleep(5);
-
- }
-
- }
-}
-
-void OsdWin::RenderDS(LPDIRECT3DSURFACE9 present){
- if (!initted) return;
- if (external_driving) {
- InternalRendering(present);
- lastrendertime=timeGetTime();
- }
-}
-
-
-void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){
- BeginPainting();
- HRESULT losty=d3ddevice->TestCooperativeLevel();
- if (losty==D3DERR_DEVICELOST) {
- //Sleep(10);
- EndPainting();
- return; //Device Lost
- }
- if (losty==D3DERR_DEVICENOTRESET){
- EndPainting();
- DoLost();
- return;
- }
- WaitForSingleObject(event,INFINITE);
-
-
-
-
- LPDIRECT3DSURFACE9 targetsurf;
- if (swappy)
- {
- targetsurf=swapsurf;
- d3ddevice->SetRenderTarget(0,swapsurf);//Stupid VMR manipulates the render target
- }
- else
- {
- targetsurf=d3drtsurf;
- d3ddevice->SetRenderTarget(0,d3drtsurf);//Stupid VMR manipulates the render target
- }
- D3DSURFACE_DESC targetdesc;
- targetsurf->GetDesc(&targetdesc);
-
- if (external_driving) {
- //Copy video to Backbuffer
- if (present!=NULL ) {
- VideoWin* video =(VideoWin*) Video::getInstance();
- /*calculating destination rect */
- RECT destrect={0,0,/*video->getScreenWidth()*/ targetdesc.Width,
- /*video->getScreenHeight()*/targetdesc.Height};
- UCHAR mode=video->getMode();
- switch (mode) {
- case Video::EIGHTH:
- destrect.right=destrect.right/2;
- destrect.bottom=destrect.bottom/2;
- case Video::QUARTER:
- destrect.right=destrect.right/2+video->getPosx()*2;
- destrect.bottom=destrect.bottom/2+video->getPosy()*2;
- destrect.left=video->getPosx()*2;
- destrect.top=video->getPosy()*2;
- d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
- break;
- };
- D3DSURFACE_DESC surf_desc;
- present->GetDesc(&surf_desc);//for chop sides
- RECT sourcerect= {0,0,surf_desc.Width,surf_desc.Height};
- if (video->getPseudoTVsize()==Video::ASPECT4X3
- && video->getMode()==Video::NORMAL
- && video->getAspectRatio()==Video::ASPECT16X9) {
- unsigned int correction=((double) (surf_desc.Width))*4.*9./3./16.;
- sourcerect.left=(surf_desc.Width-correction)/2;
- sourcerect.right=sourcerect.left+correction;
- }
- d3ddevice->StretchRect(present,&sourcerect,targetsurf ,&destrect,filter_type);
-
- }
- } else {
- VideoWin* video =(VideoWin*) Video::getInstance();
- //Clear Background
- if (!video->isVideoOn()) d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
- }
- LPDIRECT3DVERTEXBUFFER9 vb=NULL;
- vb=InitVertexBuffer(targetdesc.Width,targetdesc.Height);
-
- //Drawing the OSD
- if (d3ddevice->BeginScene()==D3D_OK) {
- d3ddevice->SetStreamSource(0,vb,0,sizeof(OSDVERTEX));
- d3ddevice->SetFVF(D3DFVF_OSDVERTEX);
- d3ddevice->SetTexture(0,((SurfaceWin*)screen)->getD3dtexture());
- //d3ddevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
- d3ddevice->SetTextureStageState(0, D3DTSS_ALPHAOP,D3DTOP_MODULATE);
-
- d3ddevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
- d3ddevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
-
-
- d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
- d3ddevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
- d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
- d3ddevice->SetRenderState(D3DRS_LIGHTING,FALSE);
-
-
- d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);
- d3ddevice->EndScene();
- //Show it to the user!
- HRESULT hres;
- if (swappy)
- {
- if (hres=swappy->Present(NULL,NULL,NULL,NULL,0)==D3DERR_DEVICELOST){
- //EndPainting();
- if (!external_driving) DoLost();
- }
- }
- else
- {
- if (hres=d3ddevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST){
- //EndPainting();
- if (!external_driving) DoLost();
- }
- }
-
- }
-
- vb->Release();
- EndPainting();
-
-
-// if (!external_driving) {
-// Sleep(4);//The User can wait for 4 milliseconds to see his changes
-// }
-}
-
-bool OsdWin::DoLost(){
- Log::getInstance()->log("OSD", Log::WARN, "Direct3D Device Lost! Reobtaining...");
- ResetEvent(event);
- if (external_driving && dsallocator!=NULL) {
- dsallocator->LostDevice(d3ddevice,d3d); //Propagate the information through DS
- }
- //First we free up all resources
- Video* video = Video::getInstance();
- ((SurfaceWin*)screen)->ReleaseSurface();
- if (d3drtsurf) d3drtsurf->Release();
- d3drtsurf=NULL;
- D3DPRESENT_PARAMETERS d3dparas;
- ZeroMemory(&d3dparas,sizeof(d3dparas));
- d3dparas.BackBufferWidth=BACKBUFFER_WIDTH;
- d3dparas.BackBufferHeight=BACKBUFFER_HEIGHT;
- d3dparas.Windowed=TRUE;
- d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;
-
- if (swapsurf) {swapsurf->Release();swapsurf=NULL;};
- if (swappy) {swappy->Release();swappy=NULL;};
-
- if (d3ddevice->Reset(&d3dparas)!=D3D_OK){
- return false;
- }
- d3ddevice->GetRenderTarget(0,&d3drtsurf);
- if (d3ddevman) d3ddevman->ResetDevice(d3ddevice,dxvatoken);
- //InitVertexBuffer();
- //Redraw Views, Chris could you add a member function to BoxStack, so that
- // I can cause it to completely redraw the Views?
- // Otherwise the OSD would be distorted after Device Lost
- // FIXME
-
- SetEvent(event);
-
-
- screen->create(video->getScreenWidth(), video->getScreenHeight());
- screen->display();
-
- return true;
-
-}
-LPDIRECT3DDEVICE9 OsdWin::getD3dDev() {
- WaitForSingleObject(event,INFINITE);//We will only return if we are initted
- return d3ddevice;
-}
-
-LPDIRECT3D9 OsdWin::getD3d() {
- WaitForSingleObject(event,INFINITE);//We will only return if we are initted
- return d3d;
-}
-
-void OsdWin::BeginPainting() {//We synchronize calls to d3d between different threads
- WaitForSingleObject(d3dmutex,INFINITE);
- LockDevice();
-}
-
-void OsdWin::EndPainting() {
- UnlockDevice();
- ReleaseMutex(d3dmutex);
-}
-
-void OsdWin::setExternalDriving(DsAllocator* dsall,DWORD width, DWORD height) {
-
- if (swappy)
- {
- BeginPainting();
- d3ddevice->StretchRect(swapsurf,NULL,d3drtsurf,NULL,filter_type);
- LPDIRECT3DSWAPCHAIN9 temp=swappy;
- LPDIRECT3DSURFACE9 tempsurf=swapsurf;
- swappy=NULL;
- swapsurf=NULL;
- EndPainting();
- tempsurf->Release();
- temp->Release();
- }
-
- if (dsall==NULL) {
- external_driving=false;
- dsallocator=NULL;
- return;
- }
- WaitForSingleObject(event,INFINITE);//We will only return if we are initted
- BeginPainting();
-
- if (width>BACKBUFFER_WIDTH || height>BACKBUFFER_HEIGHT)
- {
- D3DPRESENT_PARAMETERS d3dparas;
- ZeroMemory(&d3dparas,sizeof(d3dparas));
- d3dparas.BackBufferWidth=width;
- d3dparas.BackBufferHeight=height;
- d3dparas.Windowed=TRUE;
- d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;
- if (d3ddevice->CreateAdditionalSwapChain(&d3dparas,&swappy)!=D3D_OK){
- Log::getInstance()->log("OSD", Log::WARN, "Could not create Swap Chain!");
- //return 0;
- } else {
- swappy->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&swapsurf);
- }
- Log::getInstance()->log("OSD", Log::INFO, "Create Additional Swap Chain %d %d!",width,height);
- }
-
- dsallocator=dsall;
- external_driving=true;
-
- EndPainting();
-}
-
-void OsdWin::Blank() {
- WaitForSingleObject(event,INFINITE);
- BeginPainting();
- d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
- EndPainting();
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+\r
+#include "osdwin.h"\r
+#include "mtd.h"\r
+#include "videowin.h"\r
+#include "surfacewin.h"\r
+\r
+#include "dsallocator.h"\r
+#include "message.h"\r
+#include "command.h"\r
+\r
+#define BACKBUFFER_WIDTH 1280\r
+#define BACKBUFFER_HEIGHT 720\r
+\r
+\r
+\r
+typedef HRESULT (__stdcall *FCT_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager);\r
+typedef HRESULT (__stdcall *FCT_MFCreateVideoSampleFromSurface)(IUnknown* pUnkSurface, IMFSample** ppSample);\r
+\r
+FCT_DXVA2CreateDirect3DDeviceManager9 ptrDXVA2CreateDirect3DDeviceManager9=NULL;\r
+FCT_MFCreateVideoSampleFromSurface ptrMFCreateVideoSampleFromSurface=NULL;\r
+\r
+//This is stuff for rendering the OSD\r
+\r
+\r
+OsdWin::OsdWin()\r
+{\r
+ d3d=NULL;\r
+ d3ddevice=NULL;\r
+ d3drtsurf=NULL;\r
+ swappy=NULL;\r
+ swapsurf=NULL;\r
+ evrstate=EVR_pres_off;\r
+ window=NULL;\r
+\r
+ external_driving=false;\r
+ dsallocator=NULL;\r
+ filter_type=D3DTEXF_FORCE_DWORD;\r
+ lastrendertime=timeGetTime();\r
+ event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);\r
+ d3dmutex = CreateMutex(NULL,FALSE,NULL);\r
+ /*EVR stuff*/\r
+ dxvadevicehandle=NULL;\r
+ evrsupported=true;\r
+ HMODULE hlib=NULL;\r
+ hlib=LoadLibrary("dxva2.dll");\r
+ if (!hlib) {\r
+ evrsupported=false;\r
+ return;\r
+ }\r
+ ptrDXVA2CreateDirect3DDeviceManager9=(FCT_DXVA2CreateDirect3DDeviceManager9)GetProcAddress(hlib, "DXVA2CreateDirect3DDeviceManager9");\r
+ if (!ptrDXVA2CreateDirect3DDeviceManager9){\r
+ evrsupported=false;\r
+ return;\r
+ }\r
+\r
+ hlib=LoadLibrary("evr.dll");\r
+ if (!hlib) {\r
+ evrsupported=false;\r
+ return;\r
+ }\r
+ \r
+ ptrMFCreateVideoSampleFromSurface = (FCT_MFCreateVideoSampleFromSurface)GetProcAddress(hlib,"MFCreateVideoSampleFromSurface");\r
+ if (!ptrMFCreateVideoSampleFromSurface){\r
+ evrsupported=false;\r
+ return;\r
+ }\r
+ \r
+}\r
+\r
+OsdWin::~OsdWin()\r
+{\r
+\r
+ if (initted) \r
+ {\r
+ threadStop();\r
+ shutdown();\r
+ }\r
+ CloseHandle(event);\r
+ CloseHandle(d3dmutex);\r
+}\r
+\r
+int OsdWin::getFD()\r
+{\r
+ if (!initted) return 0;\r
+ return fdOsd;\r
+}\r
+\r
+Surface * OsdWin::createNewSurface();{\r
+ return (Surface*)new SurfaceWin();\r
+}\r
+\r
+int OsdWin::init(void* device)\r
+{\r
+ if (initted) return 0;\r
+ Video* video = Video::getInstance();\r
+ window=*((HWND*)device);\r
+ //First Create Direct 3D Object\r
+ d3d=Direct3DCreate9(D3D_SDK_VERSION);\r
+ if (!d3d) \r
+ {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 object!");\r
+ return 0;\r
+ }\r
+ // then create the Device\r
+ D3DPRESENT_PARAMETERS d3dparas;\r
+ ZeroMemory(&d3dparas,sizeof(d3dparas));\r
+ d3dparas.BackBufferWidth=BACKBUFFER_WIDTH;\r
+ d3dparas.BackBufferHeight=BACKBUFFER_HEIGHT;\r
+ d3dparas.Windowed=TRUE;\r
+ d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;\r
+ if (d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,*((HWND*) device),\r
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING |D3DCREATE_MULTITHREADED,&d3dparas,&d3ddevice)!=D3D_OK) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 device!");\r
+ return 0;\r
+ }\r
+ d3ddevice->GetRenderTarget(0,&d3drtsurf);\r
+\r
+ /*\r
+ if (!InitVertexBuffer()) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 vertex buf!");\r
+ return 0;\r
+ }*/\r
+ /* We have to determine which kind of filtering is supported*/\r
+ D3DCAPS9 caps;\r
+ d3ddevice->GetDeviceCaps(&caps);\r
+ if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR)!=0)\r
+ && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)!=0)) {\r
+ if (filter_type==D3DTEXF_FORCE_DWORD) {\r
+ filter_type=D3DTEXF_LINEAR;\r
+ }\r
+ } else {\r
+ if (filter_type==D3DTEXF_LINEAR)\r
+ {\r
+ filter_type=D3DTEXF_POINT;\r
+ }\r
+ }\r
+ \r
+ if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT)!=0)\r
+ && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT)!=0)) {\r
+ if (filter_type==D3DTEXF_FORCE_DWORD) \r
+ {\r
+ filter_type=D3DTEXF_POINT;\r
+ }\r
+ } else {\r
+ if (filter_type==D3DTEXF_POINT) {\r
+ filter_type=D3DTEXF_NONE;\r
+ }\r
+ }\r
+ if (filter_type==D3DTEXF_FORCE_DWORD) {\r
+ filter_type=D3DTEXF_NONE;\r
+ }\r
+\r
+ if (evrsupported)\r
+ {\r
+ if (ptrDXVA2CreateDirect3DDeviceManager9(&dxvatoken,&d3ddevman)!=S_OK) evrsupported=false;\r
+ else {\r
+ d3ddevman->ResetDevice(d3ddevice,dxvatoken);\r
+ }\r
+ }\r
+\r
+\r
+\r
+\r
+ //Now we will create the Screen\r
+ screen = new SurfaceWin(Surface::SCREEN);\r
+ SetEvent(event);//Now all devices are ready\r
+ screen->create(video->getScreenWidth(), video->getScreenHeight());\r
+ screen->display();\r
+ initted = 1; // must set this here or create surface won't work\r
+ threadStart(); \r
+\r
+ return 1;\r
+}\r
+\r
+void OsdWin::LockDevice()\r
+{\r
+ if (!evrsupported) return;\r
+ if (!dxvadevicehandle) \r
+ {\r
+ d3ddevman->OpenDeviceHandle(&dxvadevicehandle);\r
+ }\r
+ IDirect3DDevice9 *temp;\r
+ d3ddevman->LockDevice(dxvadevicehandle,&temp,TRUE);\r
+\r
+}\r
+\r
+void OsdWin::UnlockDevice()\r
+{\r
+ if (!evrsupported) return;\r
+ if (!initted) return;\r
+ d3ddevman->UnlockDevice(dxvadevicehandle,TRUE);\r
+ if (dxvadevicehandle) \r
+ {\r
+ d3ddevman->CloseDeviceHandle(dxvadevicehandle);\r
+ dxvadevicehandle=NULL;\r
+ }\r
+\r
+}\r
+\r
+DWORD OsdWin::getFilterCaps()\r
+{\r
+ if (!initted) return NULL;\r
+ D3DCAPS9 caps;\r
+ d3ddevice->GetDeviceCaps(&caps);\r
+ return caps.StretchRectFilterCaps;\r
+}\r
+ \r
+LPDIRECT3DVERTEXBUFFER9 OsdWin::InitVertexBuffer(DWORD width, DWORD height)\r
+{\r
+ LPDIRECT3DVERTEXBUFFER9 ret =NULL;\r
+ Video* video=Video::getInstance();\r
+ FLOAT texx=((float)video->getScreenWidth())/1024.f;\r
+ FLOAT texy=((float)video->getScreenHeight())/1024.f;\r
+ D3DCOLOR osdcolor=D3DCOLOR_RGBA(255,255,255,255);\r
+ osdvertices[0].c=osdcolor;\r
+ osdvertices[0].x=0.f-0.5f;\r
+ osdvertices[0].y=0.f-0.5f;\r
+ osdvertices[0].z=0.5f;\r
+ osdvertices[0].rhw=1.f;\r
+ osdvertices[0].u=0.f;\r
+ osdvertices[0].v=0.f;\r
+ osdvertices[1].c=osdcolor;\r
+ osdvertices[1].x=((float)width)-0.5f;\r
+ osdvertices[1].y=0.f-0.5f;\r
+ osdvertices[1].z=0.5f;\r
+ osdvertices[1].u=texx;\r
+ osdvertices[1].v=0.f;\r
+ osdvertices[1].rhw=1.f;\r
+ osdvertices[2].c=osdcolor;\r
+ osdvertices[2].x=((float)width)-0.5f;\r
+ osdvertices[2].y=((float)height)-0.5f;\r
+ osdvertices[2].z=0.5f;\r
+ osdvertices[2].rhw=1.f;\r
+ osdvertices[2].u=texx;\r
+ osdvertices[2].v=texy;\r
+ osdvertices[3].c=osdcolor;\r
+ osdvertices[3].x=0.f-0.5f;\r
+ osdvertices[3].y=((float)height)-0.5f;\r
+ osdvertices[3].z=0.5f;\r
+ osdvertices[3].rhw=1.f;\r
+ osdvertices[3].u=0.f;\r
+ osdvertices[3].v=texy;\r
+ \r
+ if (d3ddevice->CreateVertexBuffer(4*sizeof(OSDVERTEX),0,D3DFVF_OSDVERTEX,D3DPOOL_MANAGED,\r
+ &ret,NULL)!=D3D_OK) {\r
+ return NULL;\r
+ }\r
+ void *pvertex=NULL;\r
+ if (ret->Lock(0,sizeof(osdvertices),&pvertex,0)!=D3D_OK) {\r
+ return NULL;\r
+ }\r
+ memcpy(pvertex,osdvertices,sizeof(osdvertices));\r
+ ret->Unlock();\r
+ return ret;\r
+}\r
+\r
+int OsdWin::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ initted = 0;\r
+ evrsupported=0;\r
+ if (d3ddevman) d3ddevman->Release();\r
+ d3drtsurf->Release();\r
+ d3ddevice->Release();\r
+ d3d->Release();\r
+ if (swapsurf) swapsurf->Release();\r
+ if (swappy) swappy->Release();\r
+\r
+ return 1;\r
+}\r
+\r
+void OsdWin::screenShot(const char* fileName)\r
+{\r
+ screen->screenShot(fileName);\r
+}\r
+\r
+void OsdWin::threadMethod()\r
+{\r
+ while (true)\r
+ {\r
+ DWORD waittime=10;\r
+ if (initted){\r
+ if (evrstate==EVR_pres_off || evrstate==EVR_pres_pause) \r
+ {\r
+ Render();\r
+ } else if (evrstate==EVR_pres_started)\r
+ {\r
+ LPDIRECT3DSURFACE9 surf;\r
+ if (dsallocator) dsallocator->GetNextSurface(&surf,&waittime);\r
+ if (surf==NULL)\r
+ {\r
+ Render();\r
+ }\r
+ else\r
+ {\r
+ RenderDS(surf);\r
+ surf->Release();\r
+ if (dsallocator) dsallocator->DiscardSurfaceandgetWait(&waittime);\r
+ }\r
+ }\r
+ }\r
+ threadCheckExit();\r
+ if (waittime!=0) Sleep(min(10,waittime));\r
+ //Sleep(1);\r
+ }\r
+}\r
+\r
+\r
+void OsdWin::threadPostStopCleanup()\r
+{\r
+ //Doing nothing\r
+ //goo;\r
+}\r
+\r
+\r
+// This function is called from the WinMain function in order to get Screen updates\r
+void OsdWin::Render()\r
+{\r
+ if (!initted) return ;\r
+ if (external_driving) {\r
+ DWORD time1=timeGetTime(); //Updates the Menue\r
+ if ((time1-lastrendertime)>200) {//5 fps for OSD updates are enough, avoids tearing\r
+ InternalRendering(NULL);\r
+ lastrendertime=timeGetTime();\r
+ } else {\r
+ //Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads\r
+ }\r
+ } else {\r
+ DWORD time1=timeGetTime();\r
+ if ((time1-lastrendertime)>50) {//10 fps for OSD updates are enough, avoids tearing\r
+ InternalRendering(NULL);\r
+ lastrendertime=timeGetTime();\r
+ } else {\r
+ //Sleep(5);\r
+ \r
+ }\r
+ \r
+ }\r
+}\r
+\r
+void OsdWin::RenderDS(LPDIRECT3DSURFACE9 present){\r
+ if (!initted) return; \r
+ if (external_driving) {\r
+ InternalRendering(present);\r
+ lastrendertime=timeGetTime();\r
+ }\r
+}\r
+\r
+\r
+void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){\r
+ BeginPainting();\r
+ HRESULT losty=d3ddevice->TestCooperativeLevel();\r
+ if (losty==D3DERR_DEVICELOST) {\r
+ //Sleep(10);\r
+ EndPainting();\r
+ return; //Device Lost\r
+ }\r
+ if (losty==D3DERR_DEVICENOTRESET){\r
+ EndPainting();\r
+ DoLost();\r
+ return;\r
+ }\r
+ WaitForSingleObject(event,INFINITE);\r
+ \r
+ \r
+ \r
+ \r
+ LPDIRECT3DSURFACE9 targetsurf;\r
+ if (swappy)\r
+ {\r
+ targetsurf=swapsurf;\r
+ d3ddevice->SetRenderTarget(0,swapsurf);//Stupid VMR manipulates the render target\r
+ } \r
+ else\r
+ {\r
+ targetsurf=d3drtsurf;\r
+ d3ddevice->SetRenderTarget(0,d3drtsurf);//Stupid VMR manipulates the render target\r
+ }\r
+ D3DSURFACE_DESC targetdesc;\r
+ targetsurf->GetDesc(&targetdesc);\r
+\r
+ if (external_driving) {\r
+ //Copy video to Backbuffer\r
+ if (present!=NULL ) {\r
+ VideoWin* video =(VideoWin*) Video::getInstance();\r
+ /*calculating destination rect */\r
+ RECT destrect={0,0,/*video->getScreenWidth()*/ targetdesc.Width,\r
+ /*video->getScreenHeight()*/targetdesc.Height};\r
+ UCHAR mode=video->getMode();\r
+ switch (mode) {\r
+ case Video::EIGHTH:\r
+ destrect.right=destrect.right/2;\r
+ destrect.bottom=destrect.bottom/2;\r
+ case Video::QUARTER:\r
+ destrect.right=destrect.right/2+video->getPosx()*2;\r
+ destrect.bottom=destrect.bottom/2+video->getPosy()*2;\r
+ destrect.left=video->getPosx()*2;\r
+ destrect.top=video->getPosy()*2;\r
+ d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);\r
+ break;\r
+ };\r
+ D3DSURFACE_DESC surf_desc;\r
+ present->GetDesc(&surf_desc);//for chop sides\r
+ RECT sourcerect= {0,0,surf_desc.Width,surf_desc.Height};\r
+ if (video->getPseudoTVsize()==Video::ASPECT4X3 \r
+ && video->getMode()==Video::NORMAL \r
+ && video->getAspectRatio()==Video::ASPECT16X9) {\r
+ unsigned int correction=((double) (surf_desc.Width))*4.*9./3./16.;\r
+ sourcerect.left=(surf_desc.Width-correction)/2;\r
+ sourcerect.right=sourcerect.left+correction;\r
+ }\r
+ d3ddevice->StretchRect(present,&sourcerect,targetsurf ,&destrect,filter_type);\r
+\r
+ }\r
+ } else {\r
+ VideoWin* video =(VideoWin*) Video::getInstance();\r
+ //Clear Background\r
+ if (!video->isVideoOn()) d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);\r
+ }\r
+ LPDIRECT3DVERTEXBUFFER9 vb=NULL;\r
+ vb=InitVertexBuffer(targetdesc.Width,targetdesc.Height);\r
+\r
+ //Drawing the OSD\r
+ if (d3ddevice->BeginScene()==D3D_OK) {\r
+ d3ddevice->SetStreamSource(0,vb,0,sizeof(OSDVERTEX));\r
+ d3ddevice->SetFVF(D3DFVF_OSDVERTEX);\r
+ d3ddevice->SetTexture(0,((SurfaceWin*)screen)->getD3dtexture());\r
+ //d3ddevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);\r
+ d3ddevice->SetTextureStageState(0, D3DTSS_ALPHAOP,D3DTOP_MODULATE);\r
+\r
+ d3ddevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);\r
+ d3ddevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);\r
+\r
+\r
+ d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);\r
+ d3ddevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);\r
+ d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);\r
+ d3ddevice->SetRenderState(D3DRS_LIGHTING,FALSE);\r
+\r
+\r
+ d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);\r
+ d3ddevice->EndScene();\r
+ //Show it to the user!\r
+ HRESULT hres;\r
+ if (swappy)\r
+ {\r
+ if (hres=swappy->Present(NULL,NULL,NULL,NULL,0)==D3DERR_DEVICELOST){\r
+ //EndPainting();\r
+ if (!external_driving) DoLost();\r
+ }\r
+ } \r
+ else\r
+ {\r
+ if (hres=d3ddevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST){\r
+ //EndPainting();\r
+ if (!external_driving) DoLost();\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+ vb->Release();\r
+ EndPainting();\r
+\r
+ \r
+// if (!external_driving) {\r
+// Sleep(4);//The User can wait for 4 milliseconds to see his changes\r
+// }\r
+}\r
+\r
+bool OsdWin::DoLost(){\r
+ Log::getInstance()->log("OSD", Log::WARN, "Direct3D Device Lost! Reobtaining...");\r
+ ResetEvent(event);\r
+ if (external_driving && dsallocator!=NULL) {\r
+ dsallocator->LostDevice(d3ddevice,d3d); //Propagate the information through DS\r
+ }\r
+ //First we free up all resources\r
+ Video* video = Video::getInstance();\r
+ ((SurfaceWin*)screen)->ReleaseSurface();\r
+ if (d3drtsurf) d3drtsurf->Release();\r
+ d3drtsurf=NULL;\r
+ D3DPRESENT_PARAMETERS d3dparas;\r
+ ZeroMemory(&d3dparas,sizeof(d3dparas));\r
+ d3dparas.BackBufferWidth=BACKBUFFER_WIDTH;\r
+ d3dparas.BackBufferHeight=BACKBUFFER_HEIGHT;\r
+ d3dparas.Windowed=TRUE;\r
+ d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;\r
+\r
+ if (swapsurf) {swapsurf->Release();swapsurf=NULL;};\r
+ if (swappy) {swappy->Release();swappy=NULL;};\r
+\r
+ if (d3ddevice->Reset(&d3dparas)!=D3D_OK){\r
+ return false;\r
+ }\r
+ d3ddevice->GetRenderTarget(0,&d3drtsurf);\r
+ if (d3ddevman) d3ddevman->ResetDevice(d3ddevice,dxvatoken);\r
+ //InitVertexBuffer();\r
+ //Redraw Views, Chris could you add a member function to BoxStack, so that\r
+ // I can cause it to completely redraw the Views?\r
+ // Otherwise the OSD would be distorted after Device Lost\r
+ // FIXME\r
+ \r
+ SetEvent(event);\r
+\r
+\r
+ screen->create(video->getScreenWidth(), video->getScreenHeight());\r
+ screen->display();\r
+ \r
+ return true;\r
+\r
+}\r
+LPDIRECT3DDEVICE9 OsdWin::getD3dDev() {\r
+ WaitForSingleObject(event,INFINITE);//We will only return if we are initted\r
+ return d3ddevice;\r
+}\r
+\r
+LPDIRECT3D9 OsdWin::getD3d() {\r
+ WaitForSingleObject(event,INFINITE);//We will only return if we are initted\r
+ return d3d;\r
+}\r
+\r
+void OsdWin::BeginPainting() {//We synchronize calls to d3d between different threads\r
+ WaitForSingleObject(d3dmutex,INFINITE);\r
+ LockDevice();\r
+}\r
+\r
+void OsdWin::EndPainting() {\r
+ UnlockDevice();\r
+ ReleaseMutex(d3dmutex);\r
+}\r
+\r
+void OsdWin::setExternalDriving(DsAllocator* dsall,DWORD width, DWORD height) {\r
+ \r
+ if (swappy)\r
+ {\r
+ BeginPainting();\r
+ d3ddevice->StretchRect(swapsurf,NULL,d3drtsurf,NULL,filter_type);\r
+ LPDIRECT3DSWAPCHAIN9 temp=swappy;\r
+ LPDIRECT3DSURFACE9 tempsurf=swapsurf;\r
+ swappy=NULL;\r
+ swapsurf=NULL;\r
+ EndPainting();\r
+ tempsurf->Release();\r
+ temp->Release();\r
+ }\r
+\r
+ if (dsall==NULL) {\r
+ external_driving=false;\r
+ dsallocator=NULL; \r
+ return;\r
+ }\r
+ WaitForSingleObject(event,INFINITE);//We will only return if we are initted\r
+ BeginPainting();\r
+\r
+ if (width>BACKBUFFER_WIDTH || height>BACKBUFFER_HEIGHT) \r
+ {\r
+ D3DPRESENT_PARAMETERS d3dparas;\r
+ ZeroMemory(&d3dparas,sizeof(d3dparas));\r
+ d3dparas.BackBufferWidth=width;\r
+ d3dparas.BackBufferHeight=height;\r
+ d3dparas.Windowed=TRUE;\r
+ d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;\r
+ if (d3ddevice->CreateAdditionalSwapChain(&d3dparas,&swappy)!=D3D_OK){\r
+ Log::getInstance()->log("OSD", Log::WARN, "Could not create Swap Chain!");\r
+ //return 0;\r
+ } else {\r
+ swappy->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&swapsurf);\r
+ }\r
+ Log::getInstance()->log("OSD", Log::INFO, "Create Additional Swap Chain %d %d!",width,height);\r
+ }\r
+\r
+ dsallocator=dsall;\r
+ external_driving=true;\r
+ \r
+ EndPainting();\r
+}\r
+\r
+void OsdWin::Blank() {\r
+ WaitForSingleObject(event,INFINITE);\r
+ BeginPainting();\r
+ d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);\r
+ EndPainting();\r
+}\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef OSDWIN_H
-#define OSDWIN_H
-
-#include <stdio.h>
-
-#include "osd.h"
-#include "defines.h"
-#include "log.h"
-#include "threadwin.h"
-#include <winsock2.h>
-#include <d3d9.h>
-#include <Dxva2api.h>
-
-struct OSDVERTEX
-{
- FLOAT x,y,z,rhw;
- DWORD c;
- FLOAT u,v;
-};
-
-#define D3DFVF_OSDVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE| D3DFVF_TEX1)
-
-class DsAllocator;
-
-
-
-class OsdWin : public Osd, public ThreadWin
-{
- public:
- OsdWin();
- ~OsdWin();
-
- int init(void* device);
- int shutdown();
-
- int getFD();
-
- void screenShot(char* fileName);
-
- void threadMethod();
- void threadPostStopCleanup();
-
- LPDIRECT3DDEVICE9 getD3dDev() ;
- LPDIRECT3D9 getD3d() ;
- // This function is called from the WinMain function in order to get Screen updates
- void Render();
- void RenderDS(LPDIRECT3DSURFACE9 present);
- void BeginPainting();
- void EndPainting();
- void setExternalDriving(DsAllocator* dsall,DWORD width, DWORD height);
- void Blank();
- DWORD getFilterCaps();
- DWORD getFilterType(){return filter_type;};
- void setFilterType(D3DTEXTUREFILTERTYPE type) {filter_type=type;};
-
-
-
-
-
- enum EVR_state {
- EVR_pres_off=0,
- EVR_pres_started,
- EVR_pres_pause
- };
-
- void SetEVRStatus(EVR_state new_state){evrstate=new_state;};
-
- IDirect3DDeviceManager9 * getD3dMan() {return d3ddevman;};
- bool IsEvrSupported() {return evrsupported;};
- HWND getWindow() {return window;};
-
-private:
- void LockDevice();
- void UnlockDevice();
-
- LPDIRECT3D9 d3d;
- LPDIRECT3DDEVICE9 d3ddevice;
-// LPDIRECT3DVERTEXBUFFER9 d3dvb;
- LPDIRECT3DSURFACE9 d3drtsurf;
- LPDIRECT3DSWAPCHAIN9 swappy;
- LPDIRECT3DSURFACE9 swapsurf;
- DsAllocator* dsallocator;
- // This indicates, that currently a video is played, thus the osd updates are driven by the Directshow Filtersystem
- bool external_driving;
- HANDLE d3dmutex;
- DWORD lastrendertime;
- void InternalRendering(LPDIRECT3DSURFACE9 present);
- bool DoLost();
- LPDIRECT3DVERTEXBUFFER9 InitVertexBuffer(DWORD width, DWORD height);
- OSDVERTEX osdvertices[4];
- HANDLE event;
- D3DTEXTUREFILTERTYPE filter_type;
- EVR_state evrstate;
- bool evrsupported;
- HWND window;
-
- UINT dxvatoken;
- IDirect3DDeviceManager9 *d3ddevman;
- HANDLE dxvadevicehandle;
-};
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef OSDWIN_H\r
+#define OSDWIN_H\r
+\r
+#include <stdio.h>\r
+\r
+#include "osd.h"\r
+#include "defines.h"\r
+#include "log.h"\r
+#include "threadwin.h"\r
+#include <winsock2.h>\r
+#include <d3d9.h>\r
+#include <Dxva2api.h>\r
+\r
+struct OSDVERTEX\r
+{\r
+ FLOAT x,y,z,rhw;\r
+ DWORD c;\r
+ FLOAT u,v;\r
+};\r
+\r
+#define D3DFVF_OSDVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE| D3DFVF_TEX1)\r
+\r
+class DsAllocator;\r
+\r
+\r
+\r
+class OsdWin : public Osd, public ThreadWin\r
+{\r
+ public:\r
+ OsdWin();\r
+ ~OsdWin();\r
+\r
+ int init(void* device);\r
+ int shutdown();\r
+\r
+ int getFD();\r
+\r
+ void screenShot(const char* fileName);\r
+\r
+ Surface * createNewSurface();\r
+\r
+ void threadMethod();\r
+ void threadPostStopCleanup();\r
+\r
+ LPDIRECT3DDEVICE9 getD3dDev() ;\r
+ LPDIRECT3D9 getD3d() ;\r
+ // This function is called from the WinMain function in order to get Screen updates\r
+ void Render();\r
+ void RenderDS(LPDIRECT3DSURFACE9 present);\r
+ void BeginPainting();\r
+ void EndPainting();\r
+ void setExternalDriving(DsAllocator* dsall,DWORD width, DWORD height);\r
+ void Blank();\r
+ DWORD getFilterCaps();\r
+ DWORD getFilterType(){return filter_type;};\r
+ void setFilterType(D3DTEXTUREFILTERTYPE type) {filter_type=type;};\r
+\r
+\r
+\r
+ \r
+\r
+ enum EVR_state {\r
+ EVR_pres_off=0,\r
+ EVR_pres_started,\r
+ EVR_pres_pause\r
+ };\r
+\r
+ void SetEVRStatus(EVR_state new_state){evrstate=new_state;};\r
+ \r
+ IDirect3DDeviceManager9 * getD3dMan() {return d3ddevman;};\r
+ bool IsEvrSupported() {return evrsupported;};\r
+ HWND getWindow() {return window;};\r
+\r
+private:\r
+ void LockDevice();\r
+ void UnlockDevice();\r
+\r
+ LPDIRECT3D9 d3d;\r
+ LPDIRECT3DDEVICE9 d3ddevice;\r
+// LPDIRECT3DVERTEXBUFFER9 d3dvb;\r
+ LPDIRECT3DSURFACE9 d3drtsurf;\r
+ LPDIRECT3DSWAPCHAIN9 swappy;\r
+ LPDIRECT3DSURFACE9 swapsurf;\r
+ DsAllocator* dsallocator;\r
+ // This indicates, that currently a video is played, thus the osd updates are driven by the Directshow Filtersystem\r
+ bool external_driving;\r
+ HANDLE d3dmutex;\r
+ DWORD lastrendertime;\r
+ void InternalRendering(LPDIRECT3DSURFACE9 present);\r
+ bool DoLost();\r
+ LPDIRECT3DVERTEXBUFFER9 InitVertexBuffer(DWORD width, DWORD height);\r
+ OSDVERTEX osdvertices[4];\r
+ HANDLE event;\r
+ D3DTEXTUREFILTERTYPE filter_type;\r
+ EVR_state evrstate;\r
+ bool evrsupported;\r
+ HWND window;\r
+\r
+ UINT dxvatoken;\r
+ IDirect3DDeviceManager9 *d3ddevman;\r
+ HANDLE dxvadevicehandle;\r
+};\r
+\r
+#endif\r
-/*
- Copyright 2004-2008 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "player.h"
-
-#include "log.h"
-#include "audio.h"
-#include "video.h"
-#include "demuxervdr.h"
-#include "demuxerts.h"
-#include "vdr.h"
-#include "messagequeue.h"
-#include "remote.h"
-#include "message.h"
-#include "dvbsubtitles.h"
-#include "osdreceiver.h"
-
-#define USER_RESPONSE_TIME 500 // Milliseconds
-
-// ----------------------------------- Called from outside, one offs or info funcs
-
-Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver)
-: vfeed(this), afeed(this), tfeed(this)
-{
- messageQueue = tmessageQueue;
- messageReceiver = tmessageReceiver;
- osdReceiver = tosdReceiver;
- audio = Audio::getInstance();
- video = Video::getInstance();
- logger = Log::getInstance();
- vdr = VDR::getInstance();
- initted = false;
- lengthBytes = 0;
- lengthFrames = 0;
- currentFrameNumber = 0;
- state = S_STOP;
- ifactor = 4;
- is_pesrecording=true;
-
- subtitlesShowing = false;
-
- videoStartup = false;
- threadBuffer = NULL;
-
- blockSize = 100000;
- startupBlockSize = 250000;
- video->turnVideoOn();
-}
-
-Player::~Player()
-{
- if (initted) shutdown();
-}
-
-int Player::init(bool p_isPesRecording,double framespersecond)
-{
- if (initted) return 0;
-#ifndef WIN32
- pthread_mutex_init(&mutex, NULL);
-#else
- mutex=CreateMutex(NULL,FALSE,NULL);
-#endif
- is_pesrecording = p_isPesRecording;
- fps=framespersecond;
- if (is_pesrecording)
- demuxer = new DemuxerVDR();
- else
- demuxer = new DemuxerTS();
- if (!demuxer) return 0;
- subtitles = new DVBSubtitles(osdReceiver);
- if (!subtitles) return 0;
-
- teletext = new TeletextDecoderVBIEBU();
- if (!teletext) return 0;
- teletext->setRecordigMode(true);
- unsigned int demux_video_size=2097152;
- if (video->supportsh264()) demux_video_size*=5;
-
- if (!demuxer->init(this, audio, video,teletext, demux_video_size,524288,65536, framespersecond, subtitles))
- {
- logger->log("Player", Log::ERR, "Demuxer failed to init");
- shutdown();
- return 0;
- }
-
- vfeed.init();
- afeed.init();
- tfeed.init();
-
- video->stop();
- video->blank();
- audio->stop();
-
- initted = true;
- return 1;
-}
-
-int Player::shutdown()
-{
- if (!initted) return 0;
- switchState(S_STOP);
- initted = false;
-
- delete demuxer;
- demuxer = NULL;
- delete subtitles;
- subtitles = NULL;
- delete teletext;
- teletext = NULL;
-
-#ifdef WIN32
- CloseHandle(mutex);
-#endif
-
- return 1;
-}
-
-void Player::setStartFrame(ULONG startFrame)
-{
- currentFrameNumber = startFrame;
-}
-
-void Player::setLengthBytes(ULLONG length)
-{
- lengthBytes = length;
- logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
-}
-
-void Player::setLengthFrames(ULONG length)
-{
- lengthFrames = length;
- logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
-}
-
-ULONG Player::getLengthFrames()
-{
- return lengthFrames;
-}
-
-ULONG Player::getCurrentFrameNum()
-{
- if (startup) return 0;
- switch(state)
- {
- case S_PLAY:
- case S_PAUSE_P:
- return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
- case S_PAUSE_I:
- case S_FFWD:
- case S_FBWD:
- return currentFrameNumber;
- default:
- return 0; // shouldn't happen
- }
-}
-
-bool* Player::getDemuxerMpegAudioChannels()
-{
- return demuxer->getmpAudioChannels();
-}
-
-bool* Player::getDemuxerAc3AudioChannels()
-{
- return demuxer->getac3AudioChannels();
-}
-
-bool* Player::getDemuxerSubtitleChannels()
-{
- return demuxer->getSubtitleChannels();
-}
-
-int Player::getCurrentAudioChannel()
-{
- if (is_pesrecording) {
- return demuxer->getselAudioChannel();
- } else {
- return ((DemuxerTS*)demuxer)->getAID();
- }
-}
-
-int Player::getCurrentSubtitleChannel()
-{
- if (is_pesrecording) {
- return demuxer->getselSubtitleChannel();
- } else {
- return ((DemuxerTS*)demuxer)->getSubID();
- }
-}
-
-void Player::setSubtitleChannel(int newChannel)
-{
- if (is_pesrecording) {
- return demuxer->setDVBSubtitleStream(newChannel);
- } else {
- return ((DemuxerTS*)demuxer)->setSubID(newChannel);
- }
-}
-
-int *Player::getTeletxtSubtitlePages()
-{
- return teletext->getSubtitlePages();
-}
-
-void Player::setAudioChannel(int newChannel, int type)
-{
- if (is_pesrecording) {
- demuxer->setAudioStream(newChannel);
- return;
- } else {
- ((DemuxerTS*)demuxer)->setAID(newChannel,type);
- return;
- }
-}
-
-bool Player::toggleSubtitles()
-{
- if (!subtitlesShowing)
- {
- subtitlesShowing = true;
- subtitles->show();
- }
- else
- {
- subtitlesShowing = false;
- subtitles->hide();
- }
- return subtitlesShowing;
-}
-
-void Player::turnSubtitlesOn(bool ison) {
- if (ison)
- {
- subtitlesShowing = true;
- subtitles->show();
- }
- else
- {
- subtitlesShowing = false;
- subtitles->hide();
- }
-
-}
-
-Channel Player::getDemuxerChannel() {
- if (!is_pesrecording) {
- return ((DemuxerTS*) demuxer)->getChannelInfo();
- }
- return Channel(); //Should not happen!
-}
-
-
-// ----------------------------------- Externally called events
-
-void Player::play()
-{
- if (!initted) return;
- if (state == S_PLAY) return;
- lock();
-
- bool doUnlock = false;
- if (state == S_PAUSE_P) doUnlock = true;
- switchState(S_PLAY);
- if (doUnlock) unLock();
-}
-
-void Player::stop()
-{
- if (!initted) return;
- if (state == S_STOP) return;
- lock();
- logger->log("Player", Log::DEBUG, "Stop called lock");
- switchState(S_STOP);
- unLock();
-}
-
-void Player::pause()
-{
- if (!initted) return;
- lock();
-
- if ((state == S_FFWD) || (state == S_FBWD))
- {
- switchState(S_PAUSE_I);
- }
- else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
- {
- switchState(S_PLAY);
- }
- else
- {
- switchState(S_PAUSE_P);
- }
-
- unLock();
-}
-
-void Player::fastForward()
-{
- if (!initted) return;
- lock();
-
- if (state == S_FFWD)
- {
- // change the rate
- switch(ifactor)
- {
- case 4: ifactor = 8; break;
- case 8: ifactor = 16; break;
- case 16: ifactor = 32; break;
- case 32: ifactor = 4; break;
- }
- }
- else
- {
- ifactor = 4;
- switchState(S_FFWD);
- }
- unLock();
-}
-
-void Player::fastBackward()
-{
- if (!initted) return;
- lock();
-
- if (state == S_FBWD)
- {
- // change the rate
- switch(ifactor)
- {
- case 4: ifactor = 8; break;
- case 8: ifactor = 16; break;
- case 16: ifactor = 32; break;
- case 32: ifactor = 4; break;
- }
- }
- else
- {
- ifactor = 4;
- switchState(S_FBWD);
- }
- unLock();
-}
-
-void Player::jumpToPercent(double percent)
-{
- lock();
- logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent);
- ULONG newFrame = (ULONG)(percent * lengthFrames / 100);
- switchState(S_JUMP, newFrame);
-// unLock(); - let thread unlock this
-}
-
-void Player::jumpToMark(int mark)
-{
- lock();
- logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);
- switchState(S_JUMP, mark);
-// unLock(); - let thread unlock this
-}
-
-void Player::jumpToFrameP(int newFrame)
-{
- lock();
- logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);
- switchState(S_JUMP_PI, newFrame);
- unLock();
-}
-
-void Player::skipForward(int seconds)
-{
- lock();
- logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
- ULONG newFrame = getCurrentFrameNum();
- if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
- newFrame +=(ULONG) (((double)seconds) * fps);
- if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
- else switchState(S_JUMP, newFrame);
-// unLock(); - let thread unlock this
-}
-
-void Player::skipBackward(int seconds)
-{
- lock();
- logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
- long newFrame = getCurrentFrameNum();
- if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
- newFrame -= (ULONG) (((double)seconds) * fps);
- if (newFrame < 0) newFrame = 0;
- switchState(S_JUMP, newFrame);
-// unLock(); - let thread unlock this
-}
-
-// ----------------------------------- Implementations called events
-
-void Player::switchState(UCHAR toState, ULONG jumpFrame)
-{
- if (!initted) return;
-
- logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
-
- switch(state) // current state selector
- {
- case S_PLAY: // from S_PLAY -----------------------------------
- {
- switch(toState)
- {
- case S_PLAY: // to S_PLAY
- {
- return;
- }
- case S_PAUSE_P: // to S_PAUSE_P
- {
- video->pause();
- audio->pause();
- state = S_PAUSE_P;
- return;
- }
- case S_PAUSE_I: // to S_PAUSE_I
- {
- // can't occur
- return;
- }
- case S_FFWD: // to S_FFWD
- {
- currentFrameNumber = getCurrentFrameNum();
- audio->systemMuteOn();
- threadStop();
- vfeed.stop();
- afeed.stop();
- tfeed.stop();
- subtitles->stop();
- demuxer->flush();
- state = S_FFWD;
- threadStart();
- return;
- }
- case S_FBWD: // to S_FBWD
- {
- currentFrameNumber = getCurrentFrameNum();
- audio->systemMuteOn();
- threadStop();
- vfeed.stop();
- afeed.stop();
- tfeed.stop();
- subtitles->stop();
- demuxer->flush();
- state = S_FBWD;
- threadStart();
- return;
- }
- case S_STOP: // to S_STOP
- {
- vfeed.stop();
- afeed.stop();
- tfeed.stop();
- subtitles->stop();
- threadStop();
- video->stop();
- video->blank();
- audio->stop();
- audio->unPause();
- video->reset();
- demuxer->reset();
- state = S_STOP;
- return;
- }
- case S_JUMP: // to S_JUMP
- {
- restartAtFrame(jumpFrame);
- return;
- }
- case S_JUMP_PI: // to S_JUMP_PI
- {
- audio->systemMuteOn();
- threadStop();
- vfeed.stop();
- afeed.stop();
- tfeed.stop();
- subtitles->stop();
- demuxer->flush();
- state = S_PAUSE_I;
- video->reset();
- video->play();
- restartAtFramePI(jumpFrame);
- return;
- }
- }
- }
- case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
- {
- switch(toState)
- {
- case S_PLAY: // to S_PLAY
- {
- video->unPause();
- audio->unPause();
- state = S_PLAY;
- return;
- }
- case S_PAUSE_P: // to S_PAUSE_P
- {
- return;
- }
- case S_PAUSE_I: // to S_PAUSE_I
- {
- return;
- }
- case S_FFWD: // to S_FFWD
- {
- currentFrameNumber = getCurrentFrameNum();
- audio->systemMuteOn();
- vfeed.stop();
- afeed.stop();
- tfeed.stop();
- subtitles->stop();
- threadStop();
- video->unPause();
- audio->unPause();
- state = S_FFWD;
- threadStart();
- return;
- }
- case S_FBWD: // to S_FBWD
- {
- currentFrameNumber = getCurrentFrameNum();
- audio->systemMuteOn();
- vfeed.stop();
- afeed.stop();
- tfeed.stop();
- subtitles->stop();
- threadStop();
- video->unPause();
- audio->unPause();
- state = S_FBWD;
- threadStart();
- return;
- }
- case S_STOP: // to S_STOP
- {
- vfeed.stop();
- afeed.stop();
- tfeed.stop();
- subtitles->stop();
- threadStop();
- video->stop();
- video->blank();
- audio->stop();
- video->reset();
- audio->unPause();
- demuxer->reset();
- audio->systemMuteOff();
- state = S_STOP;
- return;
- }
- case S_JUMP: // to S_JUMP
- {
- state = S_PLAY;
- audio->systemMuteOn();
- audio->unPause();
- restartAtFrame(jumpFrame);
- return;
- }
- case S_JUMP_PI: // to S_JUMP_PI
- {
- audio->systemMuteOn();
- audio->unPause();
- threadStop();
- vfeed.stop();
- afeed.stop();
- tfeed.stop();
- subtitles->stop();
- demuxer->flush();
- state = S_PAUSE_I;
- video->reset();
- video->play();
- restartAtFramePI(jumpFrame);
- return;
- }
- }
- }
- case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
- {
- switch(toState)
- {
- case S_PLAY: // to S_PLAY
- {
- state = S_PLAY;
- restartAtFrame(currentFrameNumber);
- return;
- }
- case S_PAUSE_P: // to S_PAUSE_P
- {
- return;
- }
- case S_PAUSE_I: // to S_PAUSE_I
- {
- return;
- }
- case S_FFWD: // to S_FFWD
- {
- state = S_FFWD;
- threadStart();
- return;
- }
- case S_FBWD: // to S_FBWD
- {
- state = S_FBWD;
- threadStart();
- return;
- }
- case S_STOP: // to S_STOP
- {
- video->stop();
- video->blank();
- audio->stop();
- video->reset();
- demuxer->reset();
- audio->systemMuteOff();
- state = S_STOP;
- return;
- }
- case S_JUMP: // to S_JUMP
- {
- state = S_PLAY;
- restartAtFrame(jumpFrame);
- return;
- }
- case S_JUMP_PI: // to S_JUMP_PI
- {
- restartAtFramePI(jumpFrame);
- return;
- }
- }
- }
- case S_FFWD: // from S_FFWD -----------------------------------
- {
- switch(toState)
- {
- case S_PLAY: // to S_PLAY
- {
- state = S_PLAY;
- ULONG stepback = (ULONG)(((double)USER_RESPONSE_TIME * ifactor) * fps / 1000.);
- if (stepback < currentFrameNumber)
- currentFrameNumber -= stepback;
- else
- currentFrameNumber = 0;
- restartAtFrame(currentFrameNumber);
- return;
- }
- case S_PAUSE_P: // to S_PAUSE_P
- {
- // can't occur
- return;
- }
- case S_PAUSE_I: // to S_PAUSE_I
- {
- threadStop();
- state = S_PAUSE_I;
- return;
- }
- case S_FFWD: // to S_FFWD
- {
- return;
- }
- case S_FBWD: // to S_FBWD
- {
- threadStop();
- state = S_FBWD;
- threadStart();
- return;
- }
- case S_STOP: // to S_STOP
- {
- threadStop();
- video->stop();
- video->blank();
- audio->stop();
- video->reset();
- demuxer->reset();
- state = S_STOP;
- return;
- }
- case S_JUMP: // to S_JUMP
- {
- state = S_PLAY;
- restartAtFrame(jumpFrame);
- return;
- }
- case S_JUMP_PI: // to S_JUMP_PI
- {
- threadStop();
- state = S_PAUSE_I;
- restartAtFramePI(jumpFrame);
- return;
- }
- }
- }
- case S_FBWD: // from S_FBWD -----------------------------------
- {
- switch(toState)
- {
- case S_PLAY: // to S_PLAY
- {
- state = S_PLAY;
- restartAtFrame(currentFrameNumber);
- return;
- }
- case S_PAUSE_P: // to S_PAUSE_P
- {
- // can't occur
- return;
- }
- case S_PAUSE_I: // to S_PAUSE_I
- {
- threadStop();
- state = S_PAUSE_I;
- return;
- }
- case S_FFWD: // to S_FFWD
- {
- threadStop();
- state = S_FFWD;
- threadStart();
- return;
- }
- case S_FBWD: // to S_FBWD
- {
- return;
- }
- case S_STOP: // to S_STOP
- {
- threadStop();
- video->stop();
- video->blank();
- audio->stop();
- video->reset();
- demuxer->reset();
- state = S_STOP;
- return;
- }
- case S_JUMP: // to S_JUMP
- {
- state = S_PLAY;
- restartAtFrame(jumpFrame);
- return;
- }
- case S_JUMP_PI: // to S_JUMP_PI
- {
- threadStop();
- state = S_PAUSE_I;
- restartAtFramePI(jumpFrame);
- return;
- }
- }
- }
- case S_STOP: // from S_STOP -----------------------------------
- {
- switch(toState)
- {
- case S_PLAY: // to S_PLAY
- {
- startup = true;
-
- audio->reset();
- audio->setStreamType(Audio::MPEG2_PES);
- audio->systemMuteOff();
- video->reset();
- demuxer->reset();
- // FIXME use restartAtFrame here?
- if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
- demuxer->setFrameNum(currentFrameNumber);
- demuxer->seek();
- videoStartup = true;
- state = S_PLAY;
- threadStart();
- logger->log("Player", Log::DEBUG, "Immediate play");
- afeed.start();
- vfeed.start();
- tfeed.start();
- subtitles->start();
- video->sync();
- audio->sync();
- audio->play();
- video->pause();
- return;
- }
- case S_PAUSE_P: // to S_PAUSE_P
- {
- return;
- }
- case S_PAUSE_I: // to S_PAUSE_I
- {
- return;
- }
- case S_FFWD: // to S_FFWD
- {
- return;
- }
- case S_FBWD: // to S_FBWD
- {
- return;
- }
- case S_STOP: // to S_STOP
- {
- return;
- }
- case S_JUMP: // to S_JUMP
- {
- return;
- }
- case S_JUMP_PI: // to S_JUMP_PI
- {
- return;
- }
- }
- }
- // case S_JUMP cannot be a start state because it auto flips to play
- // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I
- }
-}
-
-// ----------------------------------- Internal functions
-
-void Player::lock()
-{
-#ifndef WIN32
- pthread_mutex_lock(&mutex);
- logger->log("Player", Log::DEBUG, "LOCKED");
-
-#else
- WaitForSingleObject(mutex, INFINITE);
-#endif
-}
-
-void Player::unLock()
-{
-#ifndef WIN32
- logger->log("Player", Log::DEBUG, "UNLOCKING");
- pthread_mutex_unlock(&mutex);
-#else
- ReleaseMutex(mutex);
-#endif
-}
-
-void Player::restartAtFrame(ULONG newFrame)
-{
- vfeed.stop();
- afeed.stop();
- tfeed.stop();
- subtitles->stop();
- threadStop();
- video->stop();
- video->reset();
- audio->reset();
- audio->setStreamType(Audio::MPEG2_PES);
- demuxer->flush();
- demuxer->seek();
- currentFrameNumber = newFrame;
- demuxer->setFrameNum(newFrame);
- videoStartup = true;
- afeed.start();
- tfeed.start();
- vfeed.start();
- subtitles->start();
- threadStart();
- audio->play();
- video->sync();
- audio->sync();
- audio->systemMuteOff();
- audio->doMuting();
-}
-
-
-void Player::restartAtFramePI(ULONG newFrame)
-{
- ULLONG filePos;
- ULONG nextiframeNumber;
- ULONG iframeLength;
- ULONG iframeNumber;
-
- UCHAR* buffer;
- UINT amountReceived;
- UINT videoLength;
-
- // newFrame could be anywhere, go forwards to next I-Frame
- if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
-
- // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
- vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
-
- buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
- if (!vdr->isConnected())
- {
- if (buffer) free(buffer);
- doConnectionLost();
- }
- else
- {
- videoLength = demuxer->stripAudio(buffer, amountReceived);
- video->displayIFrame(buffer, videoLength);
- video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
- free(buffer);
- currentFrameNumber = iframeNumber;
- }
-}
-
-void Player::doConnectionLost()
-{
- logger->log("Player", Log::DEBUG, "Connection lost, sending message");
- Message* m = new Message();
- m->to = messageReceiver;
- m->from = this;
- m->message = Message::PLAYER_EVENT;
- m->parameter = Player::CONNECTION_LOST;
- messageQueue->postMessage(m);
-}
-
-// ----------------------------------- Callback
-
-void Player::call(void* caller)
-{
- if (caller == demuxer)
- {
- logger->log("Player", Log::DEBUG, "Callback from demuxer");
-
- if (video->getTVsize() == Video::ASPECT4X3)
- {
- logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
- return;
- }
-
- int dxCurrentAspect = demuxer->getAspectRatio();
- if (dxCurrentAspect == Demuxer::ASPECT_4_3)
- {
- logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
- video->setAspectRatio(Video::ASPECT4X3);
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = Player::ASPECT43;
- messageQueue->postMessageFromOuterSpace(m);
- }
- else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
- {
- logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
- video->setAspectRatio(Video::ASPECT16X9);
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = Player::ASPECT169;
- messageQueue->postMessageFromOuterSpace(m);
- }
- else
- {
- logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
- }
-
- }
- else
- {
- if (videoStartup)
- {
- videoStartup = false;
- video->reset();
- video->play();
- video->sync();
- vfeed.release();
- unLock();
- }
-
- threadSignalNoLock();
- }
-}
-
-// ----------------------------------- Feed thread
-
-void Player::threadMethod()
-{
- // this method used to be simple, the only thing it does
- // is farm out to threadFeed Live/Play/Scan
- // All the guff is to support scan hitting one end
-
- if ((state == S_FFWD) || (state == S_FBWD))
- {
- threadFeedScan();
- // if this returns then scan hit one end
- if (state == S_FFWD) // scan hit the end. stop
- {
- threadCheckExit();
- Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
- m->to = messageReceiver;
- m->from = this;
- m->message = Message::PLAYER_EVENT;
- m->parameter = STOP_PLAYBACK;
- logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
- messageQueue->postMessage(m);
- logger->log("Player", Log::DEBUG, "Message posted...");
- return;
- }
- // if execution gets to here, threadFeedScan hit the start, go to play mode
- state = S_PLAY;
- audio->reset();
- audio->setStreamType(Audio::MPEG2_PES);
- demuxer->flush();
- demuxer->seek();
- demuxer->setFrameNum(currentFrameNumber);
- videoStartup = true;
- afeed.start();
- tfeed.start();
- vfeed.start();
- subtitles->start();
- audio->play();
- audio->sync();
- audio->systemMuteOff();
- audio->doMuting();
- }
-
- if (state == S_PLAY) threadFeedPlay();
-}
-
-void Player::threadFeedPlay()
-{
- ULLONG feedPosition;
- UINT thisRead, writeLength, thisWrite, askFor;
- time_t lastRescan = time(NULL);
-
- feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
- if (!vdr->isConnected()) { doConnectionLost(); return; }
- logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
-
-
- while(1)
- {
- thisRead = 0;
- writeLength = 0;
- thisWrite = 0;
-
- threadCheckExit();
-
- // If we havn't rescanned for a while..
- if ((lastRescan + 60) < time(NULL))
- {
- lengthBytes = vdr->rescanRecording(&lengthFrames);
- if (!vdr->isConnected()) { doConnectionLost(); return; }
- logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
- lastRescan = time(NULL);
- }
-
- if (feedPosition >= lengthBytes) break; // finished playback
-
- if (startup)
- {
- if (startupBlockSize > lengthBytes)
- askFor = lengthBytes; // is a very small recording!
- else
- askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
- }
- else
- {
- if ((feedPosition + blockSize) > lengthBytes) // last block of recording
- askFor = lengthBytes - feedPosition;
- else // normal
- askFor = blockSize;
- }
- //logger->log("Player", Log::DEBUG, "Get Block in");
-
- threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
- //logger->log("Player", Log::DEBUG, "Get Block out");
-
- feedPosition += thisRead;
-
- if (!vdr->isConnected())
- {
- doConnectionLost();
- return;
- }
-
- if (!threadBuffer) break;
-
- if (startup)
- {
- int a_stream = demuxer->scan(threadBuffer, thisRead);
- demuxer->setAudioStream(a_stream);
- logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
- startup = false;
- }
-
- threadCheckExit();
-
- while(writeLength < thisRead)
- {
- //logger->log("Player", Log::DEBUG, "Put in");
- thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
- //logger->log("Player", Log::DEBUG, "Put out");
- writeLength += thisWrite;
-
- if (!thisWrite)
- {
- // demuxer is full and can't take anymore
- threadLock();
- threadWaitForSignal();
- threadUnlock();
- }
-
- threadCheckExit();
- }
-
- free(threadBuffer);
- threadBuffer = NULL;
-
- }
-
- // end of recording
- logger->log("Player", Log::DEBUG, "Recording playback ends");
-
- if (videoStartup) // oh woe. there never was a stream, I was conned!
- {
- videoStartup = false;
- unLock();
- MILLISLEEP(500); // I think this will solve a race
- }
-
- threadCheckExit();
-
-
- Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
- m->to = messageReceiver;
- m->from = this;
- m->message = Message::PLAYER_EVENT;
- m->parameter = Player::STOP_PLAYBACK;
- logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
- messageQueue->postMessage(m);
-}
-
-void Player::threadFeedScan()
-{
- // This method is actually really simple - get frame from vdr,
- // spit it at the video chip, wait for a time. Most of the code here
- // is to get the wait right so that the scan occurs at the correct rate.
-
- ULONG direction = 0;
- ULONG baseFrameNumber = 0;
- ULONG iframeNumber = 0;
- ULONG iframeLength = 0;
- ULLONG filePos;
- UINT amountReceived;
- UINT videoLength;
-
-#ifndef WIN32
- struct timeval clock0 = {0,0}; // Time stamp after fetching I-frame info
- struct timeval clock1 = {0,0}; // Time stamp after fetching I-frame data
- struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
-#else
- DWORD clock0 = 0, clock1 = 0, clock2 = 0;
-#endif
-
- int frameTimeOffset = 0; // Time in msec between frames
- int disp_msec = 0; // Time taken to display data
- int total_msec = 0; // Time taken to fetch data and display it
- int sleepTime = 0;
-
- if (state == S_FFWD) direction = 1; // and 0 for backward
-
- while(1)
- {
- // Fetch I-frames until we get one that can be displayed in good time
- // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
-
- baseFrameNumber = currentFrameNumber;
- do
- {
- threadCheckExit();
- if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
- return;
-
- if (iframeNumber >= lengthFrames) return;
- // scan has got to the end of what we knew to be there before we started scanning
-
- baseFrameNumber = iframeNumber;
- frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor));
-#ifndef WIN32
- gettimeofday(&clock0, NULL);
-#else
- clock0 = timeGetTime();
-#endif
- }
-#ifndef WIN32
- while (clock2.tv_sec != 0 &&
- (clock0.tv_sec - clock2.tv_sec) * 1000 +
- (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
-#else
- while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
-#endif
- logger->log("Player", Log::DEBUG, "XXX Got frame");
-
- threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
-
- if (!vdr->isConnected())
- {
- if (threadBuffer) free(threadBuffer);
- doConnectionLost();
- break;
- }
-
-#ifndef WIN32
- gettimeofday(&clock1, NULL);
- if (clock2.tv_sec != 0)
- sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
- + (clock2.tv_usec - clock1.tv_usec) / 1000
- + frameTimeOffset - disp_msec;
-#else
- clock1 = timeGetTime();
- if (clock2 != 0)
- sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
-#endif
- if (sleepTime < 0) sleepTime = 0;
- threadCheckExit();
- MILLISLEEP(sleepTime);
- logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
-
- videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
- video->displayIFrame(threadBuffer, videoLength);
- currentFrameNumber = iframeNumber;
- free(threadBuffer);
- threadBuffer = NULL;
-
-#ifndef WIN32
- gettimeofday(&clock2, NULL);
- total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
- + (clock2.tv_usec - clock0.tv_usec) / 1000
- - sleepTime;
- disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
- + (clock2.tv_usec - clock1.tv_usec) / 1000
- - sleepTime;
-#else
- clock2 = timeGetTime();
- total_msec = clock2 - clock0 - sleepTime;
- disp_msec = clock2 - clock1 - sleepTime;
-#endif
- logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
- }
-}
-
-void Player::threadPostStopCleanup()
-{
- if (threadBuffer)
- {
- free(threadBuffer);
- threadBuffer = NULL;
- }
-}
-
-// ----------------------------------- Dev
-
-#ifdef DEV
-void Player::test1()
-{
- logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
-}
-
-void Player::test2()
-{
- logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
-}
-#endif
+/*\r
+ Copyright 2004-2008 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "player.h"\r
+\r
+#include "log.h"\r
+#include "audio.h"\r
+#include "video.h"\r
+#include "demuxervdr.h"\r
+#include "demuxerts.h"\r
+#include "vdr.h"\r
+#include "messagequeue.h"\r
+#include "remote.h"\r
+#include "message.h"\r
+#include "dvbsubtitles.h"\r
+#include "osdreceiver.h"\r
+\r
+#define USER_RESPONSE_TIME 500 // Milliseconds\r
+\r
+// ----------------------------------- Called from outside, one offs or info funcs\r
+\r
+Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver)\r
+: vfeed(this), afeed(this), tfeed(this)\r
+{\r
+ messageQueue = tmessageQueue;\r
+ messageReceiver = tmessageReceiver;\r
+ osdReceiver = tosdReceiver;\r
+ audio = Audio::getInstance();\r
+ video = Video::getInstance();\r
+ logger = Log::getInstance();\r
+ vdr = VDR::getInstance();\r
+ initted = false;\r
+ lengthBytes = 0;\r
+ lengthFrames = 0;\r
+ currentFrameNumber = 0;\r
+ state = S_STOP;\r
+ ifactor = 4;\r
+ is_pesrecording=true;\r
+\r
+ subtitlesShowing = false;\r
+\r
+ videoStartup = false;\r
+ threadBuffer = NULL;\r
+ \r
+ blockSize = 100000;\r
+ startupBlockSize = 250000;\r
+ video->turnVideoOn();\r
+}\r
+\r
+Player::~Player()\r
+{\r
+ if (initted) shutdown();\r
+}\r
+\r
+int Player::init(bool p_isPesRecording,double framespersecond)\r
+{\r
+ if (initted) return 0;\r
+#ifndef WIN32\r
+ pthread_mutex_init(&mutex, NULL);\r
+#else\r
+ mutex=CreateMutex(NULL,FALSE,NULL);\r
+#endif\r
+ is_pesrecording = p_isPesRecording;\r
+ fps=framespersecond;\r
+ if (is_pesrecording)\r
+ demuxer = new DemuxerVDR();\r
+ else\r
+ demuxer = new DemuxerTS();\r
+ if (!demuxer) return 0;\r
+ subtitles = new DVBSubtitles(osdReceiver);\r
+ if (!subtitles) return 0;\r
+\r
+ teletext = new TeletextDecoderVBIEBU();\r
+ if (!teletext) return 0;\r
+ teletext->setRecordigMode(true);\r
+ unsigned int demux_video_size=2097152;\r
+ if (video->supportsh264()) demux_video_size*=5;\r
+ \r
+ if (!demuxer->init(this, audio, video,teletext, demux_video_size,524288,65536, framespersecond, subtitles))\r
+ {\r
+ logger->log("Player", Log::ERR, "Demuxer failed to init");\r
+ shutdown();\r
+ return 0;\r
+ }\r
+\r
+ vfeed.init();\r
+ afeed.init();\r
+ tfeed.init();\r
+\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+\r
+ initted = true;\r
+ return 1;\r
+}\r
+\r
+int Player::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ switchState(S_STOP);\r
+ initted = false;\r
+\r
+ delete demuxer;\r
+ demuxer = NULL;\r
+ delete subtitles;\r
+ subtitles = NULL;\r
+ delete teletext;\r
+ teletext = NULL;\r
+\r
+#ifdef WIN32\r
+ CloseHandle(mutex);\r
+#endif\r
+\r
+ return 1;\r
+}\r
+\r
+void Player::setStartFrame(ULONG startFrame)\r
+{\r
+ currentFrameNumber = startFrame;\r
+}\r
+\r
+void Player::setLengthBytes(ULLONG length)\r
+{\r
+ lengthBytes = length;\r
+ logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);\r
+}\r
+\r
+void Player::setLengthFrames(ULONG length)\r
+{\r
+ lengthFrames = length;\r
+ logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);\r
+}\r
+\r
+ULONG Player::getLengthFrames()\r
+{\r
+ return lengthFrames;\r
+}\r
+\r
+ULONG Player::getCurrentFrameNum()\r
+{\r
+ if (startup) return 0;\r
+ switch(state)\r
+ {\r
+ case S_PLAY:\r
+ case S_PAUSE_P:\r
+ return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());\r
+ case S_PAUSE_I:\r
+ case S_FFWD:\r
+ case S_FBWD:\r
+ return currentFrameNumber;\r
+ default:\r
+ return 0; // shouldn't happen\r
+ }\r
+}\r
+\r
+bool* Player::getDemuxerMpegAudioChannels()\r
+{\r
+ return demuxer->getmpAudioChannels();\r
+}\r
+\r
+bool* Player::getDemuxerAc3AudioChannels()\r
+{\r
+ return demuxer->getac3AudioChannels();\r
+}\r
+\r
+bool* Player::getDemuxerSubtitleChannels()\r
+{\r
+ return demuxer->getSubtitleChannels();\r
+}\r
+\r
+int Player::getCurrentAudioChannel()\r
+{\r
+ if (is_pesrecording) {\r
+ return demuxer->getselAudioChannel();\r
+ } else {\r
+ return ((DemuxerTS*)demuxer)->getAID();\r
+ }\r
+}\r
+\r
+int Player::getCurrentSubtitleChannel()\r
+{\r
+ if (is_pesrecording) {\r
+ return demuxer->getselSubtitleChannel();\r
+ } else {\r
+ return ((DemuxerTS*)demuxer)->getSubID();\r
+ }\r
+}\r
+\r
+void Player::setSubtitleChannel(int newChannel)\r
+{\r
+ if (is_pesrecording) {\r
+ demuxer->setDVBSubtitleStream(newChannel);\r
+ } else {\r
+ ((DemuxerTS*)demuxer)->setSubID(newChannel);\r
+ }\r
+}\r
+\r
+int *Player::getTeletxtSubtitlePages()\r
+{\r
+ return teletext->getSubtitlePages();\r
+}\r
+\r
+void Player::setAudioChannel(int newChannel, int type)\r
+{\r
+ if (is_pesrecording) {\r
+ demuxer->setAudioStream(newChannel);\r
+ return;\r
+ } else {\r
+ ((DemuxerTS*)demuxer)->setAID(newChannel,type);\r
+ return;\r
+ }\r
+}\r
+\r
+bool Player::toggleSubtitles()\r
+{\r
+ if (!subtitlesShowing)\r
+ {\r
+ subtitlesShowing = true;\r
+ subtitles->show();\r
+ }\r
+ else\r
+ {\r
+ subtitlesShowing = false;\r
+ subtitles->hide();\r
+ }\r
+ return subtitlesShowing;\r
+}\r
+\r
+void Player::turnSubtitlesOn(bool ison) {\r
+ if (ison)\r
+ {\r
+ subtitlesShowing = true;\r
+ subtitles->show();\r
+ }\r
+ else\r
+ {\r
+ subtitlesShowing = false;\r
+ subtitles->hide();\r
+ }\r
+\r
+}\r
+\r
+Channel Player::getDemuxerChannel() {\r
+ if (!is_pesrecording) {\r
+ return ((DemuxerTS*) demuxer)->getChannelInfo();\r
+ } \r
+ return Channel(); //Should not happen!\r
+}\r
+\r
+\r
+// ----------------------------------- Externally called events\r
+\r
+void Player::play()\r
+{\r
+ if (!initted) return;\r
+ if (state == S_PLAY) return;\r
+ lock();\r
+\r
+ bool doUnlock = false;\r
+ if (state == S_PAUSE_P) doUnlock = true;\r
+ switchState(S_PLAY);\r
+ if (doUnlock) unLock();\r
+}\r
+\r
+void Player::playpause()\r
+{\r
+ if (!initted) return;\r
+ lock();\r
+\r
+ bool doUnlock = false;\r
+ if (state==S_PLAY) {\r
+ doUnlock=true;\r
+ switchState(S_PAUSE_P);\r
+ } else {\r
+ if (state == S_PAUSE_P) doUnlock = true;\r
+ switchState(S_PLAY);\r
+ }\r
+ if (doUnlock) unLock();\r
+\r
+}\r
+\r
+\r
+\r
+\r
+void Player::stop()\r
+{\r
+ if (!initted) return;\r
+ if (state == S_STOP) return;\r
+ lock();\r
+ logger->log("Player", Log::DEBUG, "Stop called lock");\r
+ switchState(S_STOP);\r
+ unLock();\r
+}\r
+\r
+void Player::pause()\r
+{\r
+ if (!initted) return;\r
+ lock();\r
+\r
+ if ((state == S_FFWD) || (state == S_FBWD))\r
+ {\r
+ switchState(S_PAUSE_I);\r
+ }\r
+ else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))\r
+ {\r
+ switchState(S_PLAY);\r
+ }\r
+ else\r
+ {\r
+ switchState(S_PAUSE_P);\r
+ }\r
+\r
+ unLock();\r
+}\r
+\r
+void Player::fastForward()\r
+{\r
+ if (!initted) return;\r
+ lock();\r
+\r
+ if (state == S_FFWD)\r
+ {\r
+ // change the rate\r
+ switch(ifactor)\r
+ {\r
+ case 4: ifactor = 8; break;\r
+ case 8: ifactor = 16; break;\r
+ case 16: ifactor = 32; break;\r
+ case 32: ifactor = 4; break;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ifactor = 4;\r
+ switchState(S_FFWD);\r
+ }\r
+ unLock();\r
+}\r
+\r
+void Player::fastBackward()\r
+{\r
+ if (!initted) return;\r
+ lock();\r
+\r
+ if (state == S_FBWD)\r
+ {\r
+ // change the rate\r
+ switch(ifactor)\r
+ {\r
+ case 4: ifactor = 8; break;\r
+ case 8: ifactor = 16; break;\r
+ case 16: ifactor = 32; break;\r
+ case 32: ifactor = 4; break;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ifactor = 4;\r
+ switchState(S_FBWD);\r
+ }\r
+ unLock();\r
+}\r
+\r
+void Player::jumpToPercent(double percent)\r
+{\r
+ lock();\r
+ logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent);\r
+ ULONG newFrame = (ULONG)(percent * lengthFrames / 100);\r
+ switchState(S_JUMP, newFrame);\r
+// unLock(); - let thread unlock this\r
+}\r
+\r
+void Player::jumpToMark(int mark)\r
+{\r
+ lock();\r
+ logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);\r
+ switchState(S_JUMP, mark);\r
+// unLock(); - let thread unlock this\r
+}\r
+\r
+void Player::jumpToFrameP(int newFrame)\r
+{\r
+ lock();\r
+ logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);\r
+ switchState(S_JUMP_PI, newFrame);\r
+ unLock();\r
+}\r
+\r
+void Player::skipForward(int seconds)\r
+{\r
+ lock();\r
+ logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);\r
+ ULONG newFrame = getCurrentFrameNum();\r
+ if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid\r
+ newFrame +=(ULONG) (((double)seconds) * fps);\r
+ if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }\r
+ else switchState(S_JUMP, newFrame);\r
+// unLock(); - let thread unlock this\r
+}\r
+\r
+void Player::skipBackward(int seconds)\r
+{\r
+ lock();\r
+ logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);\r
+ long newFrame = getCurrentFrameNum();\r
+ if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid\r
+ newFrame -= (ULONG) (((double)seconds) * fps);\r
+ if (newFrame < 0) newFrame = 0;\r
+ switchState(S_JUMP, newFrame);\r
+// unLock(); - let thread unlock this\r
+}\r
+\r
+// ----------------------------------- Implementations called events\r
+\r
+void Player::switchState(UCHAR toState, ULONG jumpFrame)\r
+{\r
+ if (!initted) return;\r
+\r
+ logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);\r
+\r
+ switch(state) // current state selector\r
+ {\r
+ case S_PLAY: // from S_PLAY -----------------------------------\r
+ {\r
+ switch(toState)\r
+ {\r
+ case S_PLAY: // to S_PLAY\r
+ {\r
+ return;\r
+ }\r
+ case S_PAUSE_P: // to S_PAUSE_P\r
+ {\r
+ video->pause();\r
+ audio->pause();\r
+ state = S_PAUSE_P;\r
+ return;\r
+ }\r
+ case S_PAUSE_I: // to S_PAUSE_I\r
+ {\r
+ // can't occur\r
+ return;\r
+ }\r
+ case S_FFWD: // to S_FFWD\r
+ {\r
+ currentFrameNumber = getCurrentFrameNum();\r
+ audio->systemMuteOn();\r
+ threadStop();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ tfeed.stop();\r
+ subtitles->stop();\r
+ demuxer->flush();\r
+ state = S_FFWD;\r
+ threadStart();\r
+ return;\r
+ }\r
+ case S_FBWD: // to S_FBWD\r
+ {\r
+ currentFrameNumber = getCurrentFrameNum();\r
+ audio->systemMuteOn();\r
+ threadStop();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ tfeed.stop();\r
+ subtitles->stop();\r
+ demuxer->flush();\r
+ state = S_FBWD;\r
+ threadStart();\r
+ return;\r
+ }\r
+ case S_STOP: // to S_STOP\r
+ {\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ tfeed.stop();\r
+ subtitles->stop();\r
+ threadStop();\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+ audio->unPause();\r
+ video->reset();\r
+ demuxer->reset();\r
+ state = S_STOP;\r
+ return;\r
+ }\r
+ case S_JUMP: // to S_JUMP\r
+ {\r
+ restartAtFrame(jumpFrame);\r
+ return;\r
+ }\r
+ case S_JUMP_PI: // to S_JUMP_PI\r
+ {\r
+ audio->systemMuteOn();\r
+ threadStop();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ tfeed.stop();\r
+ subtitles->stop();\r
+ demuxer->flush();\r
+ state = S_PAUSE_I;\r
+ video->reset();\r
+ video->play();\r
+ restartAtFramePI(jumpFrame);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ case S_PAUSE_P: // from S_PAUSE_P -----------------------------------\r
+ {\r
+ switch(toState)\r
+ {\r
+ case S_PLAY: // to S_PLAY\r
+ {\r
+ video->unPause();\r
+ audio->unPause();\r
+ state = S_PLAY;\r
+ return;\r
+ }\r
+ case S_PAUSE_P: // to S_PAUSE_P\r
+ {\r
+ return;\r
+ }\r
+ case S_PAUSE_I: // to S_PAUSE_I\r
+ {\r
+ return;\r
+ }\r
+ case S_FFWD: // to S_FFWD\r
+ {\r
+ currentFrameNumber = getCurrentFrameNum();\r
+ audio->systemMuteOn();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ tfeed.stop();\r
+ subtitles->stop();\r
+ threadStop();\r
+ video->unPause();\r
+ audio->unPause();\r
+ state = S_FFWD;\r
+ threadStart();\r
+ return;\r
+ }\r
+ case S_FBWD: // to S_FBWD\r
+ {\r
+ currentFrameNumber = getCurrentFrameNum();\r
+ audio->systemMuteOn();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ tfeed.stop();\r
+ subtitles->stop();\r
+ threadStop();\r
+ video->unPause();\r
+ audio->unPause();\r
+ state = S_FBWD;\r
+ threadStart();\r
+ return;\r
+ }\r
+ case S_STOP: // to S_STOP\r
+ {\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ tfeed.stop();\r
+ subtitles->stop();\r
+ threadStop();\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+ video->reset();\r
+ audio->unPause();\r
+ demuxer->reset();\r
+ audio->systemMuteOff();\r
+ state = S_STOP;\r
+ return;\r
+ }\r
+ case S_JUMP: // to S_JUMP\r
+ {\r
+ state = S_PLAY;\r
+ audio->systemMuteOn();\r
+ audio->unPause();\r
+ restartAtFrame(jumpFrame);\r
+ return;\r
+ }\r
+ case S_JUMP_PI: // to S_JUMP_PI\r
+ {\r
+ audio->systemMuteOn();\r
+ audio->unPause();\r
+ threadStop();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ tfeed.stop();\r
+ subtitles->stop();\r
+ demuxer->flush();\r
+ state = S_PAUSE_I;\r
+ video->reset();\r
+ video->play();\r
+ restartAtFramePI(jumpFrame);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ case S_PAUSE_I: // from S_PAUSE_I -----------------------------------\r
+ {\r
+ switch(toState)\r
+ {\r
+ case S_PLAY: // to S_PLAY\r
+ {\r
+ state = S_PLAY;\r
+ restartAtFrame(currentFrameNumber);\r
+ return;\r
+ }\r
+ case S_PAUSE_P: // to S_PAUSE_P\r
+ {\r
+ return;\r
+ }\r
+ case S_PAUSE_I: // to S_PAUSE_I\r
+ {\r
+ return;\r
+ }\r
+ case S_FFWD: // to S_FFWD\r
+ {\r
+ state = S_FFWD;\r
+ threadStart();\r
+ return;\r
+ }\r
+ case S_FBWD: // to S_FBWD\r
+ {\r
+ state = S_FBWD;\r
+ threadStart();\r
+ return;\r
+ }\r
+ case S_STOP: // to S_STOP\r
+ {\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+ video->reset();\r
+ demuxer->reset();\r
+ audio->systemMuteOff();\r
+ state = S_STOP;\r
+ return;\r
+ }\r
+ case S_JUMP: // to S_JUMP\r
+ {\r
+ state = S_PLAY;\r
+ restartAtFrame(jumpFrame);\r
+ return;\r
+ }\r
+ case S_JUMP_PI: // to S_JUMP_PI\r
+ {\r
+ restartAtFramePI(jumpFrame);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ case S_FFWD: // from S_FFWD -----------------------------------\r
+ {\r
+ switch(toState)\r
+ {\r
+ case S_PLAY: // to S_PLAY\r
+ {\r
+ state = S_PLAY;\r
+ ULONG stepback = (ULONG)(((double)USER_RESPONSE_TIME * ifactor) * fps / 1000.);\r
+ if (stepback < currentFrameNumber)\r
+ currentFrameNumber -= stepback;\r
+ else\r
+ currentFrameNumber = 0;\r
+ restartAtFrame(currentFrameNumber);\r
+ return;\r
+ }\r
+ case S_PAUSE_P: // to S_PAUSE_P\r
+ {\r
+ // can't occur\r
+ return;\r
+ }\r
+ case S_PAUSE_I: // to S_PAUSE_I\r
+ {\r
+ threadStop();\r
+ state = S_PAUSE_I;\r
+ return;\r
+ }\r
+ case S_FFWD: // to S_FFWD\r
+ {\r
+ return;\r
+ }\r
+ case S_FBWD: // to S_FBWD\r
+ {\r
+ threadStop();\r
+ state = S_FBWD;\r
+ threadStart();\r
+ return;\r
+ }\r
+ case S_STOP: // to S_STOP\r
+ {\r
+ threadStop();\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+ video->reset();\r
+ demuxer->reset();\r
+ state = S_STOP;\r
+ return;\r
+ }\r
+ case S_JUMP: // to S_JUMP\r
+ {\r
+ state = S_PLAY;\r
+ restartAtFrame(jumpFrame);\r
+ return;\r
+ }\r
+ case S_JUMP_PI: // to S_JUMP_PI\r
+ {\r
+ threadStop();\r
+ state = S_PAUSE_I;\r
+ restartAtFramePI(jumpFrame);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ case S_FBWD: // from S_FBWD -----------------------------------\r
+ {\r
+ switch(toState)\r
+ {\r
+ case S_PLAY: // to S_PLAY\r
+ {\r
+ state = S_PLAY;\r
+ restartAtFrame(currentFrameNumber);\r
+ return;\r
+ }\r
+ case S_PAUSE_P: // to S_PAUSE_P\r
+ {\r
+ // can't occur\r
+ return;\r
+ }\r
+ case S_PAUSE_I: // to S_PAUSE_I\r
+ {\r
+ threadStop();\r
+ state = S_PAUSE_I;\r
+ return;\r
+ }\r
+ case S_FFWD: // to S_FFWD\r
+ {\r
+ threadStop();\r
+ state = S_FFWD;\r
+ threadStart();\r
+ return;\r
+ }\r
+ case S_FBWD: // to S_FBWD\r
+ {\r
+ return;\r
+ }\r
+ case S_STOP: // to S_STOP\r
+ {\r
+ threadStop();\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+ video->reset();\r
+ demuxer->reset();\r
+ state = S_STOP;\r
+ return;\r
+ }\r
+ case S_JUMP: // to S_JUMP\r
+ {\r
+ state = S_PLAY;\r
+ restartAtFrame(jumpFrame);\r
+ return;\r
+ }\r
+ case S_JUMP_PI: // to S_JUMP_PI\r
+ {\r
+ threadStop();\r
+ state = S_PAUSE_I;\r
+ restartAtFramePI(jumpFrame);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ case S_STOP: // from S_STOP -----------------------------------\r
+ {\r
+ switch(toState)\r
+ {\r
+ case S_PLAY: // to S_PLAY\r
+ {\r
+ startup = true;\r
+\r
+ audio->reset();\r
+ audio->setStreamType(Audio::MPEG2_PES);\r
+ audio->systemMuteOff();\r
+ video->reset();\r
+ demuxer->reset();\r
+ // FIXME use restartAtFrame here?\r
+ if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;\r
+ demuxer->setFrameNum(currentFrameNumber);\r
+ demuxer->seek();\r
+ videoStartup = true;\r
+ state = S_PLAY;\r
+ threadStart();\r
+ logger->log("Player", Log::DEBUG, "Immediate play");\r
+ afeed.start();\r
+ vfeed.start();\r
+ tfeed.start();\r
+ subtitles->start();\r
+ video->sync();\r
+ audio->sync();\r
+ audio->play();\r
+ video->pause();\r
+ return;\r
+ }\r
+ case S_PAUSE_P: // to S_PAUSE_P\r
+ {\r
+ return;\r
+ }\r
+ case S_PAUSE_I: // to S_PAUSE_I\r
+ {\r
+ return;\r
+ }\r
+ case S_FFWD: // to S_FFWD\r
+ {\r
+ return;\r
+ }\r
+ case S_FBWD: // to S_FBWD\r
+ {\r
+ return;\r
+ }\r
+ case S_STOP: // to S_STOP\r
+ {\r
+ return;\r
+ }\r
+ case S_JUMP: // to S_JUMP\r
+ {\r
+ return;\r
+ }\r
+ case S_JUMP_PI: // to S_JUMP_PI\r
+ {\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ // case S_JUMP cannot be a start state because it auto flips to play\r
+ // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I\r
+ }\r
+}\r
+\r
+// ----------------------------------- Internal functions\r
+\r
+void Player::lock()\r
+{\r
+#ifndef WIN32\r
+ pthread_mutex_lock(&mutex);\r
+ logger->log("Player", Log::DEBUG, "LOCKED");\r
+\r
+#else\r
+ WaitForSingleObject(mutex, INFINITE);\r
+#endif\r
+}\r
+\r
+void Player::unLock()\r
+{\r
+#ifndef WIN32\r
+ logger->log("Player", Log::DEBUG, "UNLOCKING");\r
+ pthread_mutex_unlock(&mutex);\r
+#else\r
+ ReleaseMutex(mutex);\r
+#endif\r
+}\r
+\r
+void Player::restartAtFrame(ULONG newFrame)\r
+{\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ tfeed.stop();\r
+ subtitles->stop();\r
+ threadStop();\r
+ video->stop();\r
+ video->reset();\r
+ audio->reset();\r
+ audio->setStreamType(Audio::MPEG2_PES);\r
+ demuxer->flush();\r
+ demuxer->seek();\r
+ currentFrameNumber = newFrame;\r
+ demuxer->setFrameNum(newFrame);\r
+ videoStartup = true;\r
+ afeed.start();\r
+ tfeed.start();\r
+ vfeed.start();\r
+ subtitles->start();\r
+ threadStart();\r
+ audio->play();\r
+ video->sync();\r
+ audio->sync();\r
+ audio->systemMuteOff();\r
+ audio->doMuting();\r
+}\r
+\r
+\r
+void Player::restartAtFramePI(ULONG newFrame)\r
+{\r
+ ULLONG filePos;\r
+ ULONG nextiframeNumber;\r
+ ULONG iframeLength;\r
+ ULONG iframeNumber;\r
+\r
+ UCHAR* buffer;\r
+ UINT amountReceived;\r
+ UINT videoLength;\r
+\r
+ // newFrame could be anywhere, go forwards to next I-Frame\r
+ if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;\r
+\r
+ // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame\r
+ vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);\r
+\r
+ buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);\r
+ if (!vdr->isConnected())\r
+ {\r
+ if (buffer) free(buffer);\r
+ doConnectionLost();\r
+ }\r
+ else\r
+ {\r
+ videoLength = demuxer->stripAudio(buffer, amountReceived);\r
+ video->displayIFrame(buffer, videoLength);\r
+ video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)\r
+ free(buffer);\r
+ currentFrameNumber = iframeNumber;\r
+ }\r
+}\r
+\r
+void Player::doConnectionLost()\r
+{\r
+ logger->log("Player", Log::DEBUG, "Connection lost, sending message");\r
+ Message* m = new Message();\r
+ m->to = messageReceiver;\r
+ m->from = this;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = Player::CONNECTION_LOST;\r
+ messageQueue->postMessage(m);\r
+}\r
+\r
+// ----------------------------------- Callback\r
+\r
+void Player::call(void* caller)\r
+{\r
+ if (caller == demuxer)\r
+ {\r
+ logger->log("Player", Log::DEBUG, "Callback from demuxer");\r
+\r
+ if (video->getTVsize() == Video::ASPECT4X3)\r
+ {\r
+ logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");\r
+ return;\r
+ }\r
+\r
+ int dxCurrentAspect = demuxer->getAspectRatio();\r
+ if (dxCurrentAspect == Demuxer::ASPECT_4_3)\r
+ {\r
+ logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");\r
+ video->setAspectRatio(Video::ASPECT4X3);\r
+\r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = Player::ASPECT43;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+ }\r
+ else if (dxCurrentAspect == Demuxer::ASPECT_16_9)\r
+ {\r
+ logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");\r
+ video->setAspectRatio(Video::ASPECT16X9);\r
+\r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = Player::ASPECT169;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+ }\r
+ else\r
+ {\r
+ logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");\r
+ }\r
+\r
+ }\r
+ else\r
+ {\r
+ if (videoStartup)\r
+ {\r
+ videoStartup = false;\r
+ video->reset();\r
+ video->play();\r
+ video->sync();\r
+ vfeed.release();\r
+ unLock();\r
+ }\r
+\r
+ threadSignalNoLock();\r
+ }\r
+}\r
+\r
+// ----------------------------------- Feed thread\r
+\r
+void Player::threadMethod()\r
+{\r
+ // this method used to be simple, the only thing it does\r
+ // is farm out to threadFeed Live/Play/Scan\r
+ // All the guff is to support scan hitting one end\r
+\r
+ if ((state == S_FFWD) || (state == S_FBWD))\r
+ {\r
+ if (video->PTSIFramePlayback()) threadPTSFeedScan();\r
+ else threadFeedScan();\r
+ // if this returns then scan hit one end\r
+ if (state == S_FFWD) // scan hit the end. stop\r
+ {\r
+ threadCheckExit();\r
+ Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+ m->to = messageReceiver;\r
+ m->from = this;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = STOP_PLAYBACK;\r
+ logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);\r
+ messageQueue->postMessage(m);\r
+ logger->log("Player", Log::DEBUG, "Message posted...");\r
+ return;\r
+ }\r
+ // if execution gets to here, threadFeedScan hit the start, go to play mode\r
+ state = S_PLAY;\r
+ audio->reset();\r
+ audio->setStreamType(Audio::MPEG2_PES);\r
+ demuxer->flush();\r
+ demuxer->seek();\r
+ demuxer->setFrameNum(currentFrameNumber);\r
+ videoStartup = true;\r
+ afeed.start();\r
+ tfeed.start();\r
+ vfeed.start();\r
+ subtitles->start();\r
+ audio->play();\r
+ audio->sync();\r
+ audio->systemMuteOff();\r
+ audio->doMuting();\r
+ }\r
+\r
+ if (state == S_PLAY) threadFeedPlay();\r
+}\r
+\r
+void Player::threadFeedPlay()\r
+{\r
+ ULLONG feedPosition;\r
+ UINT thisRead, writeLength, thisWrite, askFor;\r
+ time_t lastRescan = time(NULL);\r
+\r
+ feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);\r
+ if (!vdr->isConnected()) { doConnectionLost(); return; }\r
+ logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);\r
+\r
+\r
+ while(1)\r
+ {\r
+ thisRead = 0;\r
+ writeLength = 0;\r
+ thisWrite = 0;\r
+\r
+ threadCheckExit();\r
+\r
+ // If we havn't rescanned for a while..\r
+ if ((lastRescan + 60) < time(NULL))\r
+ {\r
+ lengthBytes = vdr->rescanRecording(&lengthFrames);\r
+ if (!vdr->isConnected()) { doConnectionLost(); return; }\r
+ logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);\r
+ lastRescan = time(NULL);\r
+ }\r
+\r
+ if (feedPosition >= lengthBytes) break; // finished playback\r
+\r
+ if (startup)\r
+ {\r
+ if (startupBlockSize > lengthBytes)\r
+ askFor = lengthBytes; // is a very small recording!\r
+ else\r
+ askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams\r
+ }\r
+ else\r
+ {\r
+ if ((feedPosition + blockSize) > lengthBytes) // last block of recording\r
+ askFor = lengthBytes - feedPosition;\r
+ else // normal\r
+ askFor = blockSize;\r
+ }\r
+ //logger->log("Player", Log::DEBUG, "Get Block in");\r
+\r
+ threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);\r
+ //logger->log("Player", Log::DEBUG, "Get Block out");\r
+\r
+ feedPosition += thisRead;\r
+\r
+ if (!vdr->isConnected())\r
+ {\r
+ doConnectionLost();\r
+ return;\r
+ }\r
+\r
+ if (!threadBuffer) break;\r
+\r
+ if (startup)\r
+ {\r
+ int a_stream = demuxer->scan(threadBuffer, thisRead);\r
+ demuxer->setAudioStream(a_stream);\r
+ logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);\r
+ startup = false;\r
+ }\r
+\r
+ threadCheckExit();\r
+\r
+ while(writeLength < thisRead)\r
+ {\r
+ //logger->log("Player", Log::DEBUG, "Put in");\r
+ thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);\r
+ //logger->log("Player", Log::DEBUG, "Put out");\r
+ writeLength += thisWrite;\r
+\r
+ if (!thisWrite)\r
+ {\r
+ // demuxer is full and can't take anymore\r
+ threadLock();\r
+ threadWaitForSignal();\r
+ threadUnlock();\r
+ }\r
+\r
+ threadCheckExit();\r
+ }\r
+\r
+ free(threadBuffer);\r
+ threadBuffer = NULL;\r
+\r
+ }\r
+\r
+ // end of recording\r
+ logger->log("Player", Log::DEBUG, "Recording playback ends");\r
+\r
+ if (videoStartup) // oh woe. there never was a stream, I was conned!\r
+ {\r
+ videoStartup = false;\r
+ unLock();\r
+ MILLISLEEP(500); // I think this will solve a race\r
+ }\r
+\r
+ threadCheckExit();\r
+\r
+\r
+ Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+ m->to = messageReceiver;\r
+ m->from = this;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = Player::STOP_PLAYBACK;\r
+ logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);\r
+ messageQueue->postMessage(m);\r
+}\r
+\r
+\r
+void Player::threadPTSFeedScan()\r
+{\r
+ // This method manipulates the PTS instead of waiting, this is for the android devices, maybe later for windows?\r
+\r
+ ULONG direction = 0;\r
+ int dir_fac=-1;\r
+ ULONG baseFrameNumber = 0;\r
+ ULONG iframeNumber = 0;\r
+ ULONG iframeLength = 0;\r
+ ULONG currentfeedFrameNumber=currentFrameNumber;\r
+ ULONG firstFrameNumber=currentFrameNumber;\r
+ ULLONG filePos;\r
+ UINT amountReceived;\r
+ UINT videoLength;\r
+\r
+ UINT playtime=0;\r
+\r
+#ifndef WIN32\r
+ struct timeval clock0 = {0,0}; // Time stamp after fetching I-frame info\r
+ struct timeval clock1 = {0,0}; // Time stamp after fetching I-frame data\r
+ struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame\r
+#else\r
+ DWORD clock0 = 0, clock1 = 0, clock2 = 0;\r
+#endif\r
+\r
+ int frameTimeOffset = 0; // Time in msec between frames\r
+ int disp_msec = 0; // Time taken to display data\r
+ int total_msec = 0; // Time taken to fetch data and display it\r
+ int sleepTime = 0;\r
+\r
+ if (state == S_FFWD) {\r
+ direction = 1; // and 0 for backward\r
+ dir_fac=1;\r
+ }\r
+ video->EnterIframePlayback();\r
+\r
+ while(1)\r
+ {\r
+ // Fetch I-frames until we get one that can be displayed in good time\r
+ // Repeat while clock0 + total_msec > clock2 + frameTimeOffset\r
+\r
+ baseFrameNumber = currentfeedFrameNumber;\r
+\r
+ threadCheckExit();\r
+ if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))\r
+ return;\r
+\r
+ if (iframeNumber >= lengthFrames) return;\r
+ // scan has got to the end of what we knew to be there before we started scanning\r
+\r
+ baseFrameNumber = iframeNumber;\r
+\r
+ frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentfeedFrameNumber) * 1000) / (fps * (double)ifactor));\r
+\r
+ logger->log("Player", Log::DEBUG, "XXX Got frame");\r
+\r
+ threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);\r
+\r
+ if (!vdr->isConnected())\r
+ {\r
+ if (threadBuffer) free(threadBuffer);\r
+ doConnectionLost();\r
+ break;\r
+ }\r
+\r
+\r
+ threadCheckExit();\r
+\r
+\r
+ videoLength = demuxer->stripAudio(threadBuffer, amountReceived);\r
+ demuxer->changeTimes(threadBuffer,videoLength,playtime);\r
+ int count=0;\r
+ while (!video->displayIFrame(threadBuffer, videoLength)) // the device might block\r
+ {\r
+ MILLISLEEP(20);\r
+ threadCheckExit();\r
+ count++;\r
+ if (count%300==0) {\r
+ ULLONG cur_time=video->getCurrentTimestamp();\r
+ // logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",\r
+ // firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);\r
+ if (cur_time!=0) {\r
+ currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));\r
+ }\r
+ }\r
+\r
+ }\r
+ playtime +=frameTimeOffset;\r
+ currentfeedFrameNumber = iframeNumber;\r
+ {\r
+ ULLONG cur_time=video->getCurrentTimestamp();\r
+ // logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",\r
+ // firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);\r
+ if (cur_time!=0) {\r
+ currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));\r
+ }\r
+ }\r
+\r
+ free(threadBuffer);\r
+ threadBuffer = NULL;\r
+ }\r
+}\r
+\r
+\r
+\r
+void Player::threadFeedScan()\r
+{\r
+ // This method is actually really simple - get frame from vdr,\r
+ // spit it at the video chip, wait for a time. Most of the code here\r
+ // is to get the wait right so that the scan occurs at the correct rate.\r
+\r
+ ULONG direction = 0;\r
+ ULONG baseFrameNumber = 0;\r
+ ULONG iframeNumber = 0;\r
+ ULONG iframeLength = 0;\r
+ ULLONG filePos;\r
+ UINT amountReceived;\r
+ UINT videoLength;\r
+\r
+#ifndef WIN32\r
+ struct timeval clock0 = {0,0}; // Time stamp after fetching I-frame info\r
+ struct timeval clock1 = {0,0}; // Time stamp after fetching I-frame data\r
+ struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame\r
+#else\r
+ DWORD clock0 = 0, clock1 = 0, clock2 = 0;\r
+#endif\r
+\r
+ int frameTimeOffset = 0; // Time in msec between frames\r
+ int disp_msec = 0; // Time taken to display data\r
+ int total_msec = 0; // Time taken to fetch data and display it\r
+ int sleepTime = 0;\r
+\r
+ if (state == S_FFWD) direction = 1; // and 0 for backward\r
+\r
+ while(1)\r
+ {\r
+ // Fetch I-frames until we get one that can be displayed in good time\r
+ // Repeat while clock0 + total_msec > clock2 + frameTimeOffset\r
+\r
+ baseFrameNumber = currentFrameNumber;\r
+ do\r
+ {\r
+ threadCheckExit();\r
+ if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))\r
+ return;\r
+\r
+ if (iframeNumber >= lengthFrames) return;\r
+ // scan has got to the end of what we knew to be there before we started scanning\r
+\r
+ baseFrameNumber = iframeNumber;\r
+ frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor));\r
+#ifndef WIN32\r
+ gettimeofday(&clock0, NULL);\r
+#else\r
+ clock0 = timeGetTime();\r
+#endif\r
+ }\r
+#ifndef WIN32\r
+ while (clock2.tv_sec != 0 &&\r
+ (clock0.tv_sec - clock2.tv_sec) * 1000 +\r
+ (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);\r
+#else\r
+ while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);\r
+#endif\r
+ logger->log("Player", Log::DEBUG, "XXX Got frame");\r
+\r
+ threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);\r
+ \r
+ if (!vdr->isConnected())\r
+ {\r
+ if (threadBuffer) free(threadBuffer);\r
+ doConnectionLost();\r
+ break;\r
+ }\r
+ \r
+#ifndef WIN32\r
+ gettimeofday(&clock1, NULL);\r
+ if (clock2.tv_sec != 0)\r
+ sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000\r
+ + (clock2.tv_usec - clock1.tv_usec) / 1000\r
+ + frameTimeOffset - disp_msec;\r
+#else\r
+ clock1 = timeGetTime();\r
+ if (clock2 != 0)\r
+ sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;\r
+#endif\r
+ if (sleepTime < 0) sleepTime = 0;\r
+ threadCheckExit();\r
+ MILLISLEEP(sleepTime);\r
+ logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);\r
+\r
+ videoLength = demuxer->stripAudio(threadBuffer, amountReceived);\r
+ video->displayIFrame(threadBuffer, videoLength);\r
+ currentFrameNumber = iframeNumber;\r
+ free(threadBuffer);\r
+ threadBuffer = NULL;\r
+\r
+#ifndef WIN32\r
+ gettimeofday(&clock2, NULL);\r
+ total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000\r
+ + (clock2.tv_usec - clock0.tv_usec) / 1000\r
+ - sleepTime;\r
+ disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000\r
+ + (clock2.tv_usec - clock1.tv_usec) / 1000\r
+ - sleepTime;\r
+#else\r
+ clock2 = timeGetTime();\r
+ total_msec = clock2 - clock0 - sleepTime;\r
+ disp_msec = clock2 - clock1 - sleepTime;\r
+#endif\r
+ logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);\r
+ }\r
+}\r
+\r
+void Player::threadPostStopCleanup()\r
+{\r
+ if (threadBuffer)\r
+ {\r
+ free(threadBuffer);\r
+ threadBuffer = NULL;\r
+ }\r
+}\r
+\r
+// ----------------------------------- Dev\r
+\r
+#ifdef DEV\r
+void Player::test1()\r
+{\r
+ logger->log("Player", Log::DEBUG, "PLAYER TEST 1");\r
+}\r
+\r
+void Player::test2()\r
+{\r
+ logger->log("Player", Log::DEBUG, "PLAYER TEST 2");\r
+}\r
+#endif\r
-/*
- Copyright 2004-2008 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef PLAYER_H
-#define PLAYER_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef WIN32
-#include <sys/time.h>
-#endif
-#include <time.h>
-
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
-
-#include "callback.h"
-#include "defines.h"
-#include "vfeed.h"
-#include "afeed.h"
-#include "tfeed.h"
-
-#include "teletextdecodervbiebu.h"
-
-class MessageQueue;
-class Audio;
-class Video;
-class VDR;
-class Log;
-class Demuxer;
-class OSDReceiver;
-class DVBSubtitles;
-class Channel;
-
-class Player : public Thread_TYPE, public Callback
-{
- public:
- Player(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* osdReceiver);
- virtual ~Player();
-
- int init(bool p_isPesRecording,double framespersec);
- int shutdown();
- void setStartFrame(ULONG frameNum);
- void setLengthBytes(ULLONG length);
- void setLengthFrames(ULONG length);
- void setAudioChannel(int newChannel, int type);
- void setSubtitleChannel(int newChannel);
- bool toggleSubtitles();
- void turnSubtitlesOn(bool ison);
- bool isSubtitlesOn() { return subtitlesShowing; }
-
- void play();
- void stop();
- void pause();
- void fastForward();
- void fastBackward();
- void jumpToPercent(double percent);
- void skipForward(int seconds);
- void skipBackward(int seconds);
- void jumpToMark(int mark);
- void jumpToFrameP(int newFrame);
-
- UCHAR getState() { return state; }
- ULONG getCurrentFrameNum();
- ULONG getLengthFrames();
- UCHAR getIScanRate() { return ifactor; }
- bool* getDemuxerMpegAudioChannels();
- bool* getDemuxerAc3AudioChannels();
- bool* getDemuxerSubtitleChannels();
- int *getTeletxtSubtitlePages();
- int getCurrentAudioChannel();
- int getCurrentSubtitleChannel();
- bool isPesRecording() { return is_pesrecording; }
- Channel getDemuxerChannel();
-
- TeletextDecoderVBIEBU * getTeletextDecoder() { return teletext; }
-
- void call(void*); // for callback interface
-
- const static UCHAR S_PLAY = 1;
- const static UCHAR S_PAUSE_P = 2;
- const static UCHAR S_PAUSE_I = 3;
- const static UCHAR S_FFWD = 4;
- const static UCHAR S_FBWD = 5;
- const static UCHAR S_STOP = 6;
- const static UCHAR S_JUMP = 7;
- const static UCHAR S_JUMP_PI = 8; // Jump to Pause_I mode
-
- // Player events
-
- // FIXME so far this just duplicates the old system + the wss
-
- const static UCHAR CONNECTION_LOST = 1;
- const static UCHAR STOP_PLAYBACK = 2;
- const static UCHAR STREAM_END = 3;
- const static UCHAR ASPECT43 = 4;
- const static UCHAR ASPECT169 = 5;
-
-#ifdef DEV
- void test1();
- void test2();
-#endif
-
- protected:
- void threadMethod();
- void threadPostStopCleanup();
-
- private:
- void switchState(UCHAR newState, ULONG jumpFrame=0);
-
- void threadFeedPlay();
- void threadFeedScan();
-
- void doConnectionLost();
- void restartAtFrame(ULONG newFrame);
- void restartAtFramePI(ULONG newFrame);
-
- bool subtitlesShowing;
- MessageQueue* messageQueue;
- void* messageReceiver;
- OSDReceiver* osdReceiver;
- Log* logger;
- Audio* audio;
- Video* video;
- Demuxer* demuxer;
- DVBSubtitles* subtitles;
- VDR* vdr;
- VFeed vfeed;
- AFeed afeed;
- TFeed tfeed;
- TeletextDecoderVBIEBU *teletext;
-
-
-
- bool initted;
- bool startup;
- bool videoStartup;
-
- bool is_pesrecording;
- double fps;
-
-#ifndef WIN32
- pthread_mutex_t mutex;
-#else
- HANDLE mutex;
-#endif
- void lock();
- void unLock();
-
- ULLONG lengthBytes;
- ULONG lengthFrames;
- ULONG currentFrameNumber;
- UINT blockSize;
- UINT startupBlockSize;
- UCHAR* threadBuffer;
- UCHAR state;
- UCHAR ifactor;
-};
-
-#endif
-
-
-/*
-
-Possible states:
-
-Play, Pause, FFwd, FBwd, (Stop), [Jump]
-
- Possible Working
-
-Play -> PauseP * *
- -> PauseI
- -> FFwd * *
- -> FBwd * *
- -> Stop * *
- -> Jump * *
- -> Jump_PI * *
-
-PauseP -> Play * *
- -> PauseI
- -> FFwd * *
- -> FBwd * *
- -> Stop * *
- -> Jump * *
- -> Jump_PI * *
-
-PauseI -> Play * *
- -> PauseP
- -> FFwd * *
- -> FBwd * *
- -> Stop * *
- -> Jump * *
- -> Jump_PI * *
-
-FFwd -> Play * *
- -> PauseP
- -> PauseI * *
- -> FBwd * *
- -> Stop * *
- -> Jump * *
- -> Jump_PI * *
-
-FBwd -> Play * *
- -> PauseP
- -> PauseI * *
- -> FFwd * *
- -> Stop * *
- -> Jump * *
- -> Jump_PI * *
-
-Stop -> Play * *
- -> PauseP
- -> PauseI
- -> FFwd
- -> FBwd
- -> Jump
- -> Jump_PI
-
-*/
+/*\r
+ Copyright 2004-2008 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef PLAYER_H\r
+#define PLAYER_H\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#ifndef WIN32\r
+#include <sys/time.h>\r
+#endif\r
+#include <time.h>\r
+\r
+#include "threadsystem.h"\r
+\r
+#include "callback.h"\r
+#include "defines.h"\r
+#include "vfeed.h"\r
+#include "afeed.h"\r
+#include "tfeed.h"\r
+\r
+#include "teletextdecodervbiebu.h"\r
+\r
+class MessageQueue;\r
+class Audio;\r
+class Video;\r
+class VDR;\r
+class Log;\r
+class Demuxer;\r
+class OSDReceiver;\r
+class DVBSubtitles;\r
+class Channel;\r
+\r
+class Player : public Thread_TYPE, public Callback\r
+{\r
+ public:\r
+ Player(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* osdReceiver);\r
+ virtual ~Player();\r
+\r
+ int init(bool p_isPesRecording,double framespersec);\r
+ int shutdown();\r
+ void setStartFrame(ULONG frameNum);\r
+ void setLengthBytes(ULLONG length);\r
+ void setLengthFrames(ULONG length);\r
+ void setAudioChannel(int newChannel, int type);\r
+ void setSubtitleChannel(int newChannel);\r
+ bool toggleSubtitles();\r
+ void turnSubtitlesOn(bool ison); \r
+ bool isSubtitlesOn() { return subtitlesShowing; }\r
+\r
+ void play();\r
+ void stop();\r
+ void pause();\r
+ void playpause();\r
+ void fastForward();\r
+ void fastBackward();\r
+ void jumpToPercent(double percent);\r
+ void skipForward(int seconds);\r
+ void skipBackward(int seconds);\r
+ void jumpToMark(int mark);\r
+ void jumpToFrameP(int newFrame);\r
+\r
+ UCHAR getState() { return state; }\r
+ ULONG getCurrentFrameNum();\r
+ ULONG getLengthFrames();\r
+ UCHAR getIScanRate() { return ifactor; }\r
+ bool* getDemuxerMpegAudioChannels();\r
+ bool* getDemuxerAc3AudioChannels();\r
+ bool* getDemuxerSubtitleChannels();\r
+ int *getTeletxtSubtitlePages();\r
+ int getCurrentAudioChannel();\r
+ int getCurrentSubtitleChannel();\r
+ bool isPesRecording() { return is_pesrecording; }\r
+ Channel getDemuxerChannel();\r
+\r
+ TeletextDecoderVBIEBU * getTeletextDecoder() { return teletext; }\r
+\r
+ void call(void*); // for callback interface\r
+\r
+ const static UCHAR S_PLAY = 1;\r
+ const static UCHAR S_PAUSE_P = 2;\r
+ const static UCHAR S_PAUSE_I = 3;\r
+ const static UCHAR S_FFWD = 4;\r
+ const static UCHAR S_FBWD = 5;\r
+ const static UCHAR S_STOP = 6;\r
+ const static UCHAR S_JUMP = 7;\r
+ const static UCHAR S_JUMP_PI = 8; // Jump to Pause_I mode\r
+\r
+ // Player events\r
+\r
+ // FIXME so far this just duplicates the old system + the wss\r
+\r
+ const static UCHAR CONNECTION_LOST = 1;\r
+ const static UCHAR STOP_PLAYBACK = 2;\r
+ const static UCHAR STREAM_END = 3;\r
+ const static UCHAR ASPECT43 = 4;\r
+ const static UCHAR ASPECT169 = 5;\r
+\r
+#ifdef DEV\r
+ void test1();\r
+ void test2();\r
+#endif\r
+\r
+ protected:\r
+ void threadMethod();\r
+ void threadPostStopCleanup();\r
+\r
+ private:\r
+ void switchState(UCHAR newState, ULONG jumpFrame=0);\r
+\r
+ void threadFeedPlay();\r
+ void threadFeedScan();\r
+ void threadPTSFeedScan();\r
+\r
+ void doConnectionLost();\r
+ void restartAtFrame(ULONG newFrame);\r
+ void restartAtFramePI(ULONG newFrame);\r
+\r
+ bool subtitlesShowing;\r
+ MessageQueue* messageQueue;\r
+ void* messageReceiver;\r
+ OSDReceiver* osdReceiver;\r
+ Log* logger;\r
+ Audio* audio;\r
+ Video* video;\r
+ Demuxer* demuxer;\r
+ DVBSubtitles* subtitles;\r
+ VDR* vdr;\r
+ VFeed vfeed;\r
+ AFeed afeed;\r
+ TFeed tfeed;\r
+ TeletextDecoderVBIEBU *teletext;\r
+ \r
+ \r
+\r
+ bool initted;\r
+ bool startup;\r
+ bool videoStartup;\r
+\r
+ bool is_pesrecording;\r
+ double fps;\r
+\r
+#ifndef WIN32\r
+ pthread_mutex_t mutex;\r
+#else\r
+ HANDLE mutex;\r
+#endif\r
+ void lock();\r
+ void unLock();\r
+\r
+ ULLONG lengthBytes;\r
+ ULONG lengthFrames;\r
+ ULONG currentFrameNumber;\r
+ UINT blockSize;\r
+ UINT startupBlockSize;\r
+ UCHAR* threadBuffer;\r
+ UCHAR state;\r
+ UCHAR ifactor;\r
+};\r
+\r
+#endif\r
+\r
+\r
+/*\r
+\r
+Possible states:\r
+\r
+Play, Pause, FFwd, FBwd, (Stop), [Jump]\r
+\r
+ Possible Working\r
+\r
+Play -> PauseP * *\r
+ -> PauseI\r
+ -> FFwd * *\r
+ -> FBwd * *\r
+ -> Stop * *\r
+ -> Jump * *\r
+ -> Jump_PI * *\r
+\r
+PauseP -> Play * *\r
+ -> PauseI\r
+ -> FFwd * *\r
+ -> FBwd * *\r
+ -> Stop * *\r
+ -> Jump * *\r
+ -> Jump_PI * *\r
+\r
+PauseI -> Play * *\r
+ -> PauseP\r
+ -> FFwd * *\r
+ -> FBwd * *\r
+ -> Stop * *\r
+ -> Jump * *\r
+ -> Jump_PI * *\r
+\r
+FFwd -> Play * *\r
+ -> PauseP\r
+ -> PauseI * *\r
+ -> FBwd * *\r
+ -> Stop * *\r
+ -> Jump * *\r
+ -> Jump_PI * *\r
+\r
+FBwd -> Play * *\r
+ -> PauseP\r
+ -> PauseI * *\r
+ -> FFwd * *\r
+ -> Stop * *\r
+ -> Jump * *\r
+ -> Jump_PI * *\r
+\r
+Stop -> Play * *\r
+ -> PauseP\r
+ -> PauseI\r
+ -> FFwd\r
+ -> FBwd\r
+ -> Jump\r
+ -> Jump_PI\r
+\r
+*/\r
-/*
- Copyright 2008 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "playerliveradio.h"
-
-#include "log.h"
-#include "audio.h"
-#include "demuxerts.h"
-#include "vdr.h"
-#include "messagequeue.h"
-#include "remote.h"
-#include "message.h"
-#include "channel.h"
-#include "video.h"
-
-// ----------------------------------- Called from outside, one offs or info funcs
-
-PlayerLiveRadio::PlayerLiveRadio(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
-: afeed(this)
-{
- messageQueue = tmessageQueue;
- messageReceiver = tmessageReceiver;
- chanList = tchanList;
-
- audio = Audio::getInstance();
- logger = Log::getInstance();
- vdr = VDR::getInstance();
- initted = false;
-
- stopNow = false;
- state = S_STOP;
- Video::getInstance()->turnVideoOff();
-}
-
-PlayerLiveRadio::~PlayerLiveRadio()
-{
- if (initted) shutdown();
-}
-
-int PlayerLiveRadio::init()
-{
- if (initted) return 0;
-
- demuxer = new DemuxerTS();
- if (!demuxer) return 0;
-
- if (!demuxer->init(this, audio, NULL, NULL, 0, 200000,0))
- {
- logger->log("PlayerLiveRadio", Log::ERR, "Demuxer failed to init");
- shutdown();
- return 0;
- }
-
- afeed.init();
- audio->stop();
-
- initted = true;
- return 1;
-}
-
-int PlayerLiveRadio::shutdown()
-{
- if (!initted) return 0;
- stop();
- initted = false;
-
- delete demuxer;
-
-
-
- return 1;
-}
-
-bool* PlayerLiveRadio::getDemuxerMpegAudioChannels()
-{
- return demuxer->getmpAudioChannels();
-}
-
-bool* PlayerLiveRadio::getDemuxerAc3AudioChannels()
-{
- return demuxer->getac3AudioChannels();
-}
-
-int PlayerLiveRadio::getCurrentAudioChannel()
-{
- return demuxer->getAID();
-}
-
-int *PlayerLiveRadio::getTeletxtSubtitlePages(){
- return NULL;
-}
-
-int PlayerLiveRadio::getCurrentSubtitleChannel(){
- return demuxer->getSubID();
-}
-
-void PlayerLiveRadio::setAudioChannel(int newChannel, int type)
-{
- return demuxer->setAID(newChannel, type);
-}
-
-void PlayerLiveRadio::setSubtitleChannel(int newChannel)
-{
- return demuxer->setSubID(newChannel);
-}
-
-// ----------------------------------- Externally called events
-
-void PlayerLiveRadio::go(ULONG index)
-{
- struct PLInstruction i;
- i.instruction = I_SETCHANNEL;
- i.channelIndex = index;
- instructions.push(i);
- threadStart();
-}
-
-void PlayerLiveRadio::setChannel(ULONG index)
-{
- logger->log("PlayerLiveRadio", Log::DEBUG, "setChannel");
- struct PLInstruction i;
- i.instruction = I_SETCHANNEL;
- i.channelIndex = index;
- instructions.push(i);
- logger->log("PlayerLiveRadio", Log::DEBUG, "posted setChannel instruction, now %i in queue", instructions.size());
- threadSignalNoLock();
-}
-
-void PlayerLiveRadio::stop()
-{
- logger->log("PlayerLiveRadio", Log::DEBUG, "stop");
- struct PLInstruction i;
- i.instruction = I_STOP;
- instructions.push(i);
- threadSignal();
- threadStop();
-}
-
-// ----------------------------------- Callback
-
-void PlayerLiveRadio::call(void* caller)
-{
-}
-
-// -----------------------------------
-
-void PlayerLiveRadio::streamReceive(ULONG flag, void* data, ULONG len)
-{
- // Flag:
- // 0 = normal stream packet
- // 1 = stream end
- // 2 = connection lost
-
- if (flag == 1)
- {
- if (data) abort();
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveRadio::STREAM_END;
- messageQueue->postMessageFromOuterSpace(m);
- }
-
- if (streamChunks.size() < 11)
- {
- StreamChunk s;
- s.data = data;
- s.len = len;
- streamChunks.push(s);
- threadSignalNoLock();
- }
- else
- {
- // Too many chunks in streamChunks, drop this chunk
- free(data);
- logger->log("PlayerLiveRadio", Log::WARN, "Dropped chunk");
- }
-}
-
-void PlayerLiveRadio::clearStreamChunks()
-{
- while(streamChunks.size())
- {
- logger->log("PlayerLiveRadio", Log::DEBUG, "Dropping chunk from old stream");
- struct StreamChunk s = streamChunks.front();
- streamChunks.pop();
- free(s.data);
- }
-}
-
-void PlayerLiveRadio::chunkToDemuxer()
-{
- StreamChunk s = streamChunks.front();
- streamChunks.pop();
- //logger->log("PlayerLiveRadio", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
- /*int a =*/ demuxer->put((UCHAR*)s.data, s.len);
- //logger->log("PlayerLiveRadio", Log::DEBUG, "put %i to demuxer", a);
- free(s.data);
-}
-
-void PlayerLiveRadio::switchState(UCHAR newState)
-{
- logger->log("PlayerLiveRadio", Log::DEBUG, "Switch from state %u to state %u", state, newState);
-
- switch(state)
- {
- case S_STOP: // FROM S_STOP
- {
- switch(newState)
- {
- case S_PREBUFFERING:
- {
- audio->stop();
- audio->unPause();
- audio->reset();
- audio->setStreamType(Audio::MPEG2_PES);
- audio->systemMuteOff();
- audio->doMuting();
- audio->play();
- audio->pause();
- demuxer->reset();
- afeed.start();
-
- state = newState;
- preBufferCount = 0;
- return;
- }
- default:
- {
- logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
- abort();
- break;
- }
- }
- }
-
- case S_PREBUFFERING: // FROM S_PREBUFFERING
- {
- switch(newState)
- {
- case S_PLAY:
- {
- audio->unPause();
- state = newState;
- return;
- }
- case S_STOP:
- {
- vdr->stopStreaming();
- clearStreamChunks();
- afeed.stop();
- audio->stop();
- audio->reset();
- state = newState;
- return;
- }
- case S_PREBUFFERING:
- {
- vdr->stopStreaming();
- clearStreamChunks();
- afeed.stop();
- audio->stop();
- audio->reset();
- audio->play();
- audio->pause();
- demuxer->reset();
- afeed.start();
-
- state = newState;
- preBufferCount = 0;
- return;
- }
- default:
- {
- logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
- abort();
- break;
- }
- }
- }
-
- case S_PLAY: // FROM S_PLAY
- {
- switch(newState)
- {
- case S_STOP:
- {
- vdr->stopStreaming();
- clearStreamChunks();
- afeed.stop();
- audio->stop();
- audio->reset();
- state = newState;
- return;
- }
- case S_PREBUFFERING: // IS THIS HOW IT WORKS?
- {
- vdr->stopStreaming();
- clearStreamChunks();
- afeed.stop();
- audio->stop();
- audio->reset();
- audio->play();
- audio->pause();
- demuxer->reset();
- afeed.start();
-
- state = newState;
- preBufferCount = 0;
- return;
- }
- default:
- {
- logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
- abort();
- break;
- }
- }
- }
- }
-}
-
-bool PlayerLiveRadio::checkError()
-{
- if (!vdr->isConnected())
- {
- switchState(S_STOP);
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveRadio::CONNECTION_LOST;
- messageQueue->postMessageFromOuterSpace(m);
-
- return true;
- }
- return false;
-}
-
-void PlayerLiveRadio::optimizeInstructionQueue()
-{
- // Walk the list
-
- // Currently there are only 2 instruction types, so this is a bit overkill...
-
- struct PLInstruction i;
- while(instructions.size() > 1)
- {
- i = instructions.front();
- if (i.instruction == I_SETCHANNEL)
- {
- instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
- }
- else if (i.instruction == I_STOP)
- {
- return; // return here and ensure the next instruction will be stop
- }
- }
-}
-
-void PlayerLiveRadio::threadMethod()
-{
- while(1)
- {
- while(!instructions.empty())
- {
- if (instructions.size() > 1)
- {
- logger->log("PlayerLiveRadio", Log::DEBUG, "Should optimise");
- optimizeInstructionQueue();
- }
-
- struct PLInstruction i = instructions.front();
- instructions.pop();
-
- if (i.instruction == I_SETCHANNEL)
- {
- logger->log("PlayerLiveRadio", Log::DEBUG, "start new stream");
-
- switchState(S_PREBUFFERING);
-
- if (!checkError())
- {
- Channel* chan = (*chanList)[i.channelIndex];
- chan->loadPids();
-
- if (chan->numAPids > 0)
- {
- demuxer->setAID(chan->apids[0].pid,0);
- logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);
- }
- else
- {
- logger->log("PlayerLiveRadio", Log::WARN, "Demuxer no pids!");
- }
-
- int streamSuccess = vdr->streamChannel(chan->number, this);
- if (!checkError() && !streamSuccess)
- {
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveRadio::STREAM_END;
- messageQueue->postMessageFromOuterSpace(m);
- }
- }
- }
- else if (i.instruction == I_STOP)
- {
- logger->log("PlayerLiveRadio", Log::DEBUG, "Stopping");
- switchState(S_STOP);
- checkError();
-
- stopNow = true;
- break;
- }
- }
-
- if (stopNow) break;
-
- while(streamChunks.size())
- {
- chunkToDemuxer();
-
- if (state == S_PREBUFFERING)
- {
- ++preBufferCount;
- ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
- logger->log("PlayerLiveRadio", Log::DEBUG, "Prebuffering %lu%%", percentDone);
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveRadio::PREBUFFERING;
- m->tag = percentDone;
- messageQueue->postMessageFromOuterSpace(m);
-
- if (preBufferCount == preBufferAmount)
- {
- switchState(S_PLAY);
- checkError();
- }
- }
- }
-
- threadLock();
- threadWaitForSignal(); // unlocks and waits for signal
- threadUnlock();
- }
-
- logger->log("PlayerLiveRadio", Log::DEBUG, "End of thread");
-}
-
+/*\r
+ Copyright 2008 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "playerliveradio.h"\r
+\r
+#include "log.h"\r
+#include "audio.h"\r
+#include "demuxerts.h"\r
+#include "vdr.h"\r
+#include "messagequeue.h"\r
+#include "remote.h"\r
+#include "message.h"\r
+#include "channel.h"\r
+#include "video.h"\r
+\r
+// ----------------------------------- Called from outside, one offs or info funcs\r
+\r
+PlayerLiveRadio::PlayerLiveRadio(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)\r
+: afeed(this)\r
+{\r
+ messageQueue = tmessageQueue;\r
+ messageReceiver = tmessageReceiver;\r
+ chanList = tchanList;\r
+ \r
+ audio = Audio::getInstance();\r
+ logger = Log::getInstance();\r
+ vdr = VDR::getInstance();\r
+ initted = false;\r
+\r
+ stopNow = false;\r
+ state = S_STOP;\r
+ Video::getInstance()->turnVideoOff();\r
+}\r
+\r
+PlayerLiveRadio::~PlayerLiveRadio()\r
+{\r
+ if (initted) shutdown();\r
+}\r
+\r
+int PlayerLiveRadio::init()\r
+{\r
+ if (initted) return 0;\r
+\r
+ demuxer = new DemuxerTS();\r
+ if (!demuxer) return 0;\r
+ \r
+ if (!demuxer->init(this, audio, NULL, NULL, 0, 200000,0))\r
+ {\r
+ logger->log("PlayerLiveRadio", Log::ERR, "Demuxer failed to init");\r
+ shutdown();\r
+ return 0;\r
+ }\r
+\r
+ afeed.init();\r
+ audio->stop();\r
+\r
+ initted = true;\r
+ return 1;\r
+}\r
+\r
+int PlayerLiveRadio::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ stop();\r
+ initted = false;\r
+\r
+ delete demuxer;\r
+\r
+\r
+\r
+ return 1;\r
+}\r
+\r
+bool* PlayerLiveRadio::getDemuxerMpegAudioChannels()\r
+{\r
+ return demuxer->getmpAudioChannels();\r
+}\r
+\r
+bool* PlayerLiveRadio::getDemuxerAc3AudioChannels()\r
+{\r
+ return demuxer->getac3AudioChannels();\r
+}\r
+\r
+int PlayerLiveRadio::getCurrentAudioChannel()\r
+{\r
+ return demuxer->getAID();\r
+}\r
+\r
+int *PlayerLiveRadio::getTeletxtSubtitlePages(){\r
+ return NULL;\r
+}\r
+\r
+int PlayerLiveRadio::getCurrentSubtitleChannel(){\r
+ return demuxer->getSubID();\r
+}\r
+\r
+void PlayerLiveRadio::setAudioChannel(int newChannel, int type)\r
+{\r
+ demuxer->setAID(newChannel, type);\r
+}\r
+\r
+void PlayerLiveRadio::setSubtitleChannel(int newChannel)\r
+{\r
+ demuxer->setSubID(newChannel);\r
+}\r
+\r
+// ----------------------------------- Externally called events\r
+\r
+void PlayerLiveRadio::go(ULONG index)\r
+{\r
+ struct PLInstruction i;\r
+ i.instruction = I_SETCHANNEL;\r
+ i.channelIndex = index;\r
+ instructions.push(i);\r
+ threadStart();\r
+}\r
+\r
+void PlayerLiveRadio::setChannel(ULONG index)\r
+{\r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "setChannel");\r
+ struct PLInstruction i;\r
+ i.instruction = I_SETCHANNEL;\r
+ i.channelIndex = index;\r
+ instructions.push(i); \r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "posted setChannel instruction, now %i in queue", instructions.size());\r
+ threadSignalNoLock();\r
+}\r
+\r
+void PlayerLiveRadio::stop()\r
+{\r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "stop");\r
+ struct PLInstruction i;\r
+ i.instruction = I_STOP;\r
+ instructions.push(i);\r
+ threadSignal();\r
+ threadStop();\r
+}\r
+\r
+// ----------------------------------- Callback\r
+\r
+void PlayerLiveRadio::call(void* caller)\r
+{\r
+}\r
+\r
+// -----------------------------------\r
+\r
+void PlayerLiveRadio::streamReceive(ULONG flag, void* data, ULONG len)\r
+{\r
+ // Flag:\r
+ // 0 = normal stream packet\r
+ // 1 = stream end\r
+ // 2 = connection lost\r
+\r
+ if (flag == 1)\r
+ {\r
+ if (data) abort();\r
+ \r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerLiveRadio::STREAM_END;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+ }\r
+ \r
+ if (streamChunks.size() < 11)\r
+ {\r
+ StreamChunk s;\r
+ s.data = data;\r
+ s.len = len;\r
+ streamChunks.push(s);\r
+ threadSignalNoLock();\r
+ }\r
+ else\r
+ {\r
+ // Too many chunks in streamChunks, drop this chunk\r
+ free(data);\r
+ logger->log("PlayerLiveRadio", Log::WARN, "Dropped chunk");\r
+ }\r
+}\r
+\r
+void PlayerLiveRadio::clearStreamChunks()\r
+{\r
+ while(streamChunks.size())\r
+ {\r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "Dropping chunk from old stream");\r
+ struct StreamChunk s = streamChunks.front();\r
+ streamChunks.pop();\r
+ free(s.data);\r
+ }\r
+}\r
+\r
+void PlayerLiveRadio::chunkToDemuxer()\r
+{\r
+ StreamChunk s = streamChunks.front();\r
+ streamChunks.pop();\r
+ //logger->log("PlayerLiveRadio", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);\r
+ /*int a =*/ demuxer->put((UCHAR*)s.data, s.len);\r
+ //logger->log("PlayerLiveRadio", Log::DEBUG, "put %i to demuxer", a);\r
+ free(s.data); \r
+}\r
+\r
+void PlayerLiveRadio::switchState(UCHAR newState)\r
+{\r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "Switch from state %u to state %u", state, newState);\r
+\r
+ switch(state)\r
+ {\r
+ case S_STOP: // FROM S_STOP\r
+ {\r
+ switch(newState)\r
+ {\r
+ case S_PREBUFFERING:\r
+ {\r
+ audio->stop();\r
+ audio->unPause();\r
+ audio->reset();\r
+ audio->setStreamType(Audio::MPEG2_PES);\r
+ audio->systemMuteOff(); \r
+ audio->doMuting(); \r
+ audio->play();\r
+ audio->pause();\r
+ demuxer->reset();\r
+ afeed.start();\r
+ \r
+ state = newState;\r
+ preBufferCount = 0;\r
+ return;\r
+ }\r
+ default:\r
+ {\r
+ logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+ abort();\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ case S_PREBUFFERING: // FROM S_PREBUFFERING\r
+ {\r
+ switch(newState)\r
+ {\r
+ case S_PLAY:\r
+ {\r
+ audio->unPause();\r
+ state = newState;\r
+ return;\r
+ }\r
+ case S_STOP:\r
+ {\r
+ vdr->stopStreaming();\r
+ clearStreamChunks();\r
+ afeed.stop();\r
+ audio->stop();\r
+ audio->reset();\r
+ state = newState;\r
+ return; \r
+ }\r
+ case S_PREBUFFERING:\r
+ {\r
+ vdr->stopStreaming();\r
+ clearStreamChunks();\r
+ afeed.stop();\r
+ audio->stop();\r
+ audio->reset();\r
+ audio->play();\r
+ audio->pause();\r
+ demuxer->reset();\r
+ afeed.start();\r
+\r
+ state = newState;\r
+ preBufferCount = 0;\r
+ return; \r
+ }\r
+ default:\r
+ {\r
+ logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+ abort();\r
+ break;\r
+ } \r
+ }\r
+ }\r
+ \r
+ case S_PLAY: // FROM S_PLAY\r
+ {\r
+ switch(newState)\r
+ {\r
+ case S_STOP:\r
+ { \r
+ vdr->stopStreaming();\r
+ clearStreamChunks();\r
+ afeed.stop();\r
+ audio->stop();\r
+ audio->reset();\r
+ state = newState;\r
+ return;\r
+ }\r
+ case S_PREBUFFERING: // IS THIS HOW IT WORKS?\r
+ {\r
+ vdr->stopStreaming();\r
+ clearStreamChunks();\r
+ afeed.stop();\r
+ audio->stop();\r
+ audio->reset();\r
+ audio->play();\r
+ audio->pause();\r
+ demuxer->reset();\r
+ afeed.start();\r
+\r
+ state = newState;\r
+ preBufferCount = 0;\r
+ return;\r
+ }\r
+ default:\r
+ {\r
+ logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+ abort();\r
+ break;\r
+ } \r
+ }\r
+ } \r
+ } \r
+}\r
+\r
+bool PlayerLiveRadio::checkError()\r
+{\r
+ if (!vdr->isConnected())\r
+ {\r
+ switchState(S_STOP);\r
+ \r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerLiveRadio::CONNECTION_LOST;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+ \r
+ return true;\r
+ } \r
+ return false;\r
+}\r
+\r
+void PlayerLiveRadio::optimizeInstructionQueue()\r
+{\r
+ // Walk the list\r
+ \r
+ // Currently there are only 2 instruction types, so this is a bit overkill...\r
+\r
+ struct PLInstruction i;\r
+ while(instructions.size() > 1)\r
+ {\r
+ i = instructions.front();\r
+ if (i.instruction == I_SETCHANNEL)\r
+ {\r
+ instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant\r
+ }\r
+ else if (i.instruction == I_STOP)\r
+ {\r
+ return; // return here and ensure the next instruction will be stop\r
+ }\r
+ }\r
+}\r
+\r
+void PlayerLiveRadio::threadMethod()\r
+{\r
+ while(1)\r
+ {\r
+ while(!instructions.empty())\r
+ {\r
+ if (instructions.size() > 1)\r
+ {\r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "Should optimise");\r
+ optimizeInstructionQueue();\r
+ }\r
+\r
+ struct PLInstruction i = instructions.front();\r
+ instructions.pop();\r
+ \r
+ if (i.instruction == I_SETCHANNEL)\r
+ {\r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "start new stream");\r
+\r
+ switchState(S_PREBUFFERING);\r
+\r
+ if (!checkError())\r
+ {\r
+ Channel* chan = (*chanList)[i.channelIndex];\r
+ chan->loadPids();\r
+\r
+ if (chan->numAPids > 0) \r
+ {\r
+ demuxer->setAID(chan->apids[0].pid,0);\r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);\r
+ }\r
+ else \r
+ {\r
+ logger->log("PlayerLiveRadio", Log::WARN, "Demuxer no pids!");\r
+ }\r
+\r
+ int streamSuccess = vdr->streamChannel(chan->number, this);\r
+ if (!checkError() && !streamSuccess)\r
+ { \r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerLiveRadio::STREAM_END;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+ }\r
+ }\r
+ }\r
+ else if (i.instruction == I_STOP)\r
+ {\r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "Stopping");\r
+ switchState(S_STOP);\r
+ checkError();\r
+\r
+ stopNow = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (stopNow) break;\r
+\r
+ while(streamChunks.size())\r
+ {\r
+ chunkToDemuxer();\r
+\r
+ if (state == S_PREBUFFERING)\r
+ {\r
+ ++preBufferCount;\r
+ ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);\r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "Prebuffering %lu%%", percentDone);\r
+ \r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerLiveRadio::PREBUFFERING;\r
+ m->tag = percentDone;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+\r
+ if (preBufferCount == preBufferAmount)\r
+ {\r
+ switchState(S_PLAY);\r
+ checkError();\r
+ }\r
+ }\r
+ }\r
+ \r
+ threadLock();\r
+ threadWaitForSignal(); // unlocks and waits for signal\r
+ threadUnlock();\r
+ }\r
+\r
+ logger->log("PlayerLiveRadio", Log::DEBUG, "End of thread");\r
+}\r
+\r
-/*
- Copyright 2007 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "playerlivetv.h"
-
-#include "log.h"
-#include "audio.h"
-#include "video.h"
-#include "demuxerts.h"
-#include "vdr.h"
-#include "messagequeue.h"
-#include "remote.h"
-#include "message.h"
-#include "channel.h"
-#include "dvbsubtitles.h"
-#include "osdreceiver.h"
-
-// ----------------------------------- Called from outside, one offs or info funcs
-
-PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
-: vfeed(this), afeed(this), tfeed(this)
-{
- messageQueue = tmessageQueue;
- messageReceiver = tmessageReceiver;
- osdReceiver = tosdReceiver;
- chanList = tchanList;
-
- audio = Audio::getInstance();
- video = Video::getInstance();
- logger = Log::getInstance();
- vdr = VDR::getInstance();
- initted = false;
-
- subtitlesShowing = false;
- videoStartup = false;
- pendingAudioPlay = false;
-
- stopNow = false;
- state = S_STOP;
-
- video->turnVideoOn();
-}
-
-PlayerLiveTV::~PlayerLiveTV()
-{
- if (initted) shutdown();
-}
-
-int PlayerLiveTV::init()
-{
- if (initted) return 0;
-
- demuxer = new DemuxerTS();
- if (!demuxer) return 0;
- subtitles = new DVBSubtitles(osdReceiver);
- if (!subtitles) return 0;
-
- teletext = new TeletextDecoderVBIEBU();
-
- unsigned int demux_video_size=2097152;
- if (video->supportsh264()) demux_video_size*=5;
-
- if (!demuxer->init(this, audio, video, teletext, demux_video_size, 524288, 65536,25./*unimportant*/,subtitles))
- {
- logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
- shutdown();
- return 0;
- }
-
- vfeed.init();
- afeed.init();
- tfeed.init();
-
- video->stop();
- video->blank();
- audio->stop();
-
- initted = true;
- return 1;
-}
-
-int PlayerLiveTV::shutdown()
-{
- if (!initted) return 0;
- stop();
- initted = false;
-
- delete demuxer;
- delete subtitles;
- delete teletext;
- teletext = NULL;
- return 1;
-}
-
-bool* PlayerLiveTV::getDemuxerMpegAudioChannels()
-{
- return demuxer->getmpAudioChannels();
-}
-
-bool* PlayerLiveTV::getDemuxerAc3AudioChannels()
-{
- return demuxer->getac3AudioChannels();
-}
-
-int PlayerLiveTV::getCurrentAudioChannel()
-{
- return demuxer->getAID();
-}
-
-void PlayerLiveTV::setAudioChannel(int newChannel, int type)
-{
- return demuxer->setAID(newChannel,type);
-}
-
-void PlayerLiveTV::setSubtitleChannel(int newChannel)
-{
- return demuxer->setSubID(newChannel);
-}
-
-int *PlayerLiveTV::getTeletxtSubtitlePages()
-{
- return teletext->getSubtitlePages();
-}
-
-int PlayerLiveTV::getCurrentSubtitleChannel(){
- return demuxer->getSubID();
-}
-
-bool PlayerLiveTV::toggleSubtitles()
-{
- if (!subtitlesShowing)
- {
- subtitlesShowing = true;
- subtitles->show();
- }
- else
- {
- subtitlesShowing = false;
- subtitles->hide();
- }
- return subtitlesShowing;
-}
-
-
-void PlayerLiveTV::turnSubtitlesOn(bool ison) {
- if (ison)
- {
- subtitlesShowing = true;
- subtitles->show();
- }
- else
- {
- subtitlesShowing = false;
- subtitles->hide();
- }
-
-}
-// ----------------------------------- Externally called events
-
-void PlayerLiveTV::go(ULONG index)
-{
- struct PLInstruction i;
- i.instruction = I_SETCHANNEL;
- i.channelIndex = index;
- instructions.push(i);
- threadStart();
-}
-
-void PlayerLiveTV::setChannel(ULONG index)
-{
- logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
- struct PLInstruction i;
- i.instruction = I_SETCHANNEL;
- i.channelIndex = index;
- instructions.push(i);
- threadSignalNoLock();
-}
-
-void PlayerLiveTV::stop()
-{
- logger->log("PlayerLiveTV", Log::DEBUG, "stop");
- struct PLInstruction i;
- i.instruction = I_STOP;
- instructions.push(i);
- threadSignal();
- threadStop();
-}
-
-// ----------------------------------- Callback
-
-void PlayerLiveTV::call(void* caller)
-{
- if (caller == demuxer)
- {
- logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");
-
- int dxCurrentAspect = demuxer->getAspectRatio();
- if (dxCurrentAspect == Demuxer::ASPECT_4_3)
- {
- if (video->getTVsize() == Video::ASPECT16X9)
- {
- logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
- video->setAspectRatio(Video::ASPECT4X3);
- }
- else
- {
- logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
- }
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveTV::ASPECT43;
- messageQueue->postMessageFromOuterSpace(m);
- }
- else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
- {
- if (video->getTVsize() == Video::ASPECT16X9)
- {
- logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
- video->setAspectRatio(Video::ASPECT16X9);
- }
- else
- {
- logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
- }
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveTV::ASPECT169;
- messageQueue->postMessageFromOuterSpace(m);
- }
- else
- {
- logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... ignoring");
- }
- }
- else if (caller == &afeed)
- {
- if (state == S_VIDEOSTARTUP)
- {
- logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");
- videoStartup = true;
- threadSignalNoLock();
- }
- }
-}
-
-// -----------------------------------
-
-void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)
-{
- // Flag:
- // 0 = normal stream packet
- // 1 = stream end
- // 2 = connection lost
-
-// logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
-
- if (flag == 1)
- {
- if (data) abort();
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveTV::STREAM_END;
- messageQueue->postMessageFromOuterSpace(m);
- }
-
- if (streamChunks.size() < 11)
- {
- StreamChunk s;
- s.data = data;
- s.len = len;
- streamChunks.push(s);
- threadSignalNoLock();
- }
- else
- {
- // Too many chunks in streamChunks, drop this chunk
- free(data);
- logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");
- }
-}
-
-void PlayerLiveTV::clearStreamChunks()
-{
- while(streamChunks.size())
- {
- logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");
- struct StreamChunk s = streamChunks.front();
- streamChunks.pop();
- free(s.data);
- }
-}
-
-void PlayerLiveTV::chunkToDemuxer()
-{
- StreamChunk s = streamChunks.front();
- streamChunks.pop();
- //logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
- /*int a = */demuxer->put((UCHAR*)s.data, s.len);
- //logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);
- free(s.data);
- if (pendingAudioPlay && demuxer->getHorizontalSize()) //Horizontal Size is zero, if not parsed
- {
- video->sync();
- video->play();
- video->pause();
- //audio->setStreamType(Audio::MPEG2_PES);
- audio->sync();
- audio->play();
- audio->pause();
- pendingAudioPlay = false;
- }
-}
-
-void PlayerLiveTV::switchState(UCHAR newState)
-{
- logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);
-
- switch(state)
- {
- case S_STOP: // FROM S_STOP
- {
- switch(newState)
- {
- case S_VIDEOSTARTUP:
- {
- video->blank();
- video->reset();
- //video->sync();
- //video->play();
- //video->pause();
-
- audio->stop();
- audio->unPause();
- audio->reset();
- //audio->setStreamType(Audio::MPEG2_PES);
- //audio->sync();
- // I make this modification, since the video/audio devices needs to know at least
- // which kind of video is embedded inside the stream
- // therefore the demuxer needs to feeded at least with enough data
- // to have one video header
- // This is crucial, if we have mixed h264/mpeg2 channels
- // the information from channels is not enough since some directshow decoders need
- // width and height information before startup
- pendingAudioPlay = true;
-
- //audio->play();
- //audio->pause();
-
- demuxer->reset();
- demuxer->seek();
-
- afeed.start();
- vfeed.start();
- subtitles->start();
- tfeed.start();
-
- state = newState;
- return;
- }
- default:
- {
- logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
- abort();
- break;
- }
- }
- }
-
- case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP
- {
- switch(newState)
- {
- case S_PREBUFFERING:
- {
- pendingAudioPlay=false;
- vfeed.release();
- state = newState;
- return;
- }
-
- case S_VIDEOSTARTUP:
- {
- vdr->stopStreaming();
- clearStreamChunks();
- vfeed.stop();
- afeed.stop();
- subtitles->stop();
- tfeed.stop();
-
- video->blank();
- video->reset();
- //video->sync();
- //video->play();
- //video->pause();
-
- audio->stop();
- audio->unPause();
- audio->reset();
- //audio->setStreamType(Audio::MPEG2_PES);
- //audio->sync();
- pendingAudioPlay = true;
- //audio->play();
- //audio->pause();
-
- demuxer->reset();
- demuxer->seek();
-
- afeed.start();
- vfeed.start();
- subtitles->start();
- tfeed.start();
- state = newState;
- return;
- }
- case S_STOP:
- {
- vdr->stopStreaming();
- pendingAudioPlay=false;
- clearStreamChunks();
- vfeed.stop();
- afeed.stop();
- subtitles->stop();
- tfeed.stop();
- video->stop();
- video->blank();
- audio->stop();
- audio->reset();
- video->reset();
- state = newState;
- return;
- }
- default:
- {
- logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
- abort();
- break;
- }
- }
- }
-
- case S_PREBUFFERING: // FROM S_PREBUFFERING
- {
- switch(newState)
- {
- case S_PLAY:
- {
- pendingAudioPlay=false;
- audio->unPause();
- video->unPause();
- state = newState;
- return;
- }
- case S_VIDEOSTARTUP:
- {
- vdr->stopStreaming();
- clearStreamChunks();
- vfeed.stop();
- afeed.stop();
- subtitles->stop();
- tfeed.stop();
- video->stop();
- video->blank();
- audio->stop();
- audio->unPause();
- audio->reset();
-
- video->reset();
- //video->sync();
- //video->play();
- //video->pause();
-
- //audio->setStreamType(Audio::MPEG2_PES);
- //audio->sync();
- pendingAudioPlay = true;
- //audio->play();
- //audio->pause();
-
- demuxer->reset();
- demuxer->seek();
-
- afeed.start();
- vfeed.start();
- subtitles->start();
- tfeed.start();
-
- state = newState;
- return;
- }
- case S_STOP:
- {
- pendingAudioPlay=false;
- vdr->stopStreaming();
- clearStreamChunks();
- vfeed.stop();
- afeed.stop();
- subtitles->stop();
- tfeed.stop();
- video->stop();
- video->blank();
- audio->stop();
- audio->reset();
- video->reset();
- state = newState;
- return;
- }
- default:
- {
- logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
- abort();
- break;
- }
- }
- }
-
- case S_PLAY: // FROM S_PLAY
- {
- switch(newState)
- {
- case S_STOP:
- {
- pendingAudioPlay=false;
- vdr->stopStreaming();
- clearStreamChunks();
- vfeed.stop();
- afeed.stop();
- subtitles->stop();
- tfeed.stop();
- video->stop();
- video->blank();
- audio->stop();
- audio->reset();
- video->reset();
- state = newState;
- return;
- }
- case S_VIDEOSTARTUP:
- {
- vdr->stopStreaming();
- clearStreamChunks();
- vfeed.stop();
- afeed.stop();
- subtitles->stop();
- tfeed.stop();
- video->stop();
- video->blank();
- audio->stop();
- audio->unPause();
- audio->reset();
-
- video->reset();
-
- //video->sync();
- // video->play();
- //video->pause();
-
- //audio->setStreamType(Audio::MPEG2_PES);
- //audio->sync();
- //audio->play();
- //audio->pause();
- pendingAudioPlay = true;
-
- demuxer->reset();
- demuxer->seek();
-
- afeed.start();
- vfeed.start();
- subtitles->start();
- tfeed.start();
-
- state = newState;
- return;
- }
- default:
- {
- logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
- abort();
- break;
- }
- }
- }
- }
-}
-
-bool PlayerLiveTV::checkError()
-{
- if (!vdr->isConnected())
- {
- if (state != S_STOP) switchState(S_STOP);
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveTV::CONNECTION_LOST;
- messageQueue->postMessageFromOuterSpace(m);
-
- return true;
- }
- return false;
-}
-
-void PlayerLiveTV::optimizeInstructionQueue()
-{
- // Walk the list
-
- // Currently there are only 2 instruction types, so this is a bit overkill...
-
- struct PLInstruction i;
- while(instructions.size() > 1)
- {
- i = instructions.front();
- if (i.instruction == I_SETCHANNEL)
- {
- instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
- }
- else if (i.instruction == I_STOP)
- {
- return; // return here and ensure the next instruction will be stop
- }
- }
-}
-
-void PlayerLiveTV::threadMethod()
-{
- while(1)
- {
- if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
- {
- switchState(S_PREBUFFERING);
- videoStartup = false;
- preBufferCount = 0;
-
- checkError();
- }
-
- while(!instructions.empty())
- {
- if (instructions.size() > 1) optimizeInstructionQueue();
-
- struct PLInstruction i = instructions.front();
- instructions.pop();
-
- if (i.instruction == I_SETCHANNEL)
- {
- logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");
-
-
- switchState(S_VIDEOSTARTUP);
-
- if (!checkError())
- {
- Channel* chan = (*chanList)[i.channelIndex];
- chan->loadPids();
- h264=chan->vstreamtype==0x1b;
- demuxer->seth264(h264);
- video->seth264mode(chan->vstreamtype==0x1b);
- demuxer->setVID(chan->vpid);
- video->seth264mode(chan->vstreamtype==0x1b);
-
- if (chan->numAPids > 0)
- {
- demuxer->setAID(chan->apids[0].pid,0);
- audio->setStreamType(Audio::MPEG2_PES);
- logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);
- }
- else
- {
- if (chan->numDPids > 0 && audio->maysupportAc3())
- {
- demuxer->setAID(chan->dpids[0].pid,1);
- logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3)", chan->vpid, chan->dpids[0].pid);
- }
- else
- {
- logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
- }
- }
- if (chan->numSPids > 0)
- demuxer->setSubID(chan->spids[0].pid);
- demuxer->setTID(chan->tpid);
- teletext->ResetDecoder();
- int streamSuccess = vdr->streamChannel(chan->number, this);
- if (!checkError() && !streamSuccess)
- {
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveTV::STREAM_END;
- messageQueue->postMessageFromOuterSpace(m);
- }
- }
- }
- else if (i.instruction == I_STOP)
- {
- logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");
- switchState(S_STOP);
- checkError();
-
- stopNow = true;
- break;
- }
- }
-
- if (stopNow) break;
-
- while(streamChunks.size())
- {
- chunkToDemuxer();
-
- if (state == S_PREBUFFERING)
- {
- ++preBufferCount;
- ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
- logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone);
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveTV::PREBUFFERING;
- m->tag = percentDone;
- messageQueue->postMessageFromOuterSpace(m);
-
- if (preBufferCount == preBufferAmount)
- {
- switchState(S_PLAY);
- checkError();
- }
- }
- }
-
- threadLock();
- threadWaitForSignal(); // unlocks and waits for signal
- threadUnlock();
- }
-
- logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");
-}
-
+/*\r
+ Copyright 2007 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "playerlivetv.h"\r
+\r
+#include "log.h"\r
+#include "audio.h"\r
+#include "video.h"\r
+#include "demuxerts.h"\r
+#include "vdr.h"\r
+#include "messagequeue.h"\r
+#include "remote.h"\r
+#include "message.h"\r
+#include "channel.h"\r
+#include "dvbsubtitles.h"\r
+#include "osdreceiver.h"\r
+\r
+// ----------------------------------- Called from outside, one offs or info funcs\r
+\r
+PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)\r
+: vfeed(this), afeed(this), tfeed(this)\r
+{\r
+ messageQueue = tmessageQueue;\r
+ messageReceiver = tmessageReceiver;\r
+ osdReceiver = tosdReceiver;\r
+ chanList = tchanList;\r
+ \r
+ audio = Audio::getInstance();\r
+ video = Video::getInstance();\r
+ logger = Log::getInstance();\r
+ vdr = VDR::getInstance();\r
+ initted = false;\r
+\r
+ subtitlesShowing = false;\r
+ videoStartup = false;\r
+ pendingAudioPlay = false;\r
+\r
+ stopNow = false;\r
+ state = S_STOP;\r
+\r
+ video->turnVideoOn();\r
+}\r
+\r
+PlayerLiveTV::~PlayerLiveTV()\r
+{\r
+ if (initted) shutdown();\r
+}\r
+\r
+int PlayerLiveTV::init()\r
+{\r
+ if (initted) return 0;\r
+\r
+ demuxer = new DemuxerTS();\r
+ if (!demuxer) return 0;\r
+ subtitles = new DVBSubtitles(osdReceiver);\r
+ if (!subtitles) return 0;\r
+\r
+ teletext = new TeletextDecoderVBIEBU();\r
+ \r
+ unsigned int demux_video_size=2097152;\r
+ if (video->supportsh264()) demux_video_size*=5;\r
+\r
+ int text_fak=video->getTeletextBufferFaktor();\r
+\r
+ \r
+ if (!demuxer->init(this, audio, video, teletext, demux_video_size,524288, 65536*text_fak,25./*unimportant*/,subtitles))\r
+ {\r
+ logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");\r
+ shutdown();\r
+ return 0;\r
+ }\r
+\r
+ vfeed.init();\r
+ afeed.init();\r
+ tfeed.init();\r
+\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+\r
+ initted = true;\r
+ return 1;\r
+}\r
+\r
+int PlayerLiveTV::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Shutdown");\r
+ stop();\r
+ initted = false;\r
+\r
+ delete demuxer;\r
+ delete subtitles;\r
+ delete teletext;\r
+ teletext = NULL;\r
+ return 1;\r
+}\r
+\r
+bool* PlayerLiveTV::getDemuxerMpegAudioChannels()\r
+{\r
+ return demuxer->getmpAudioChannels();\r
+}\r
+\r
+bool* PlayerLiveTV::getDemuxerAc3AudioChannels()\r
+{\r
+ return demuxer->getac3AudioChannels();\r
+}\r
+\r
+int PlayerLiveTV::getCurrentAudioChannel()\r
+{\r
+ return demuxer->getAID();\r
+}\r
+\r
+void PlayerLiveTV::setAudioChannel(int newChannel, int type)\r
+{\r
+ demuxer->setAID(newChannel,type);\r
+}\r
+\r
+void PlayerLiveTV::setSubtitleChannel(int newChannel)\r
+{\r
+ demuxer->setSubID(newChannel);\r
+}\r
+\r
+int *PlayerLiveTV::getTeletxtSubtitlePages()\r
+{\r
+ return teletext->getSubtitlePages();\r
+}\r
+\r
+int PlayerLiveTV::getCurrentSubtitleChannel(){\r
+ return demuxer->getSubID();\r
+}\r
+\r
+bool PlayerLiveTV::toggleSubtitles()\r
+{\r
+ if (!subtitlesShowing)\r
+ {\r
+ subtitlesShowing = true;\r
+ subtitles->show();\r
+ }\r
+ else\r
+ {\r
+ subtitlesShowing = false;\r
+ subtitles->hide();\r
+ }\r
+ return subtitlesShowing;\r
+}\r
+\r
+\r
+void PlayerLiveTV::turnSubtitlesOn(bool ison) {\r
+ if (ison)\r
+ {\r
+ subtitlesShowing = true;\r
+ subtitles->show();\r
+ }\r
+ else\r
+ {\r
+ subtitlesShowing = false;\r
+ subtitles->hide();\r
+ }\r
+\r
+}\r
+// ----------------------------------- Externally called events\r
+\r
+void PlayerLiveTV::go(ULONG index)\r
+{\r
+ struct PLInstruction i;\r
+ i.instruction = I_SETCHANNEL;\r
+ i.channelIndex = index;\r
+ instructions.push(i);\r
+ threadStart();\r
+}\r
+\r
+void PlayerLiveTV::setChannel(ULONG index)\r
+{\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");\r
+ struct PLInstruction i;\r
+ i.instruction = I_SETCHANNEL;\r
+ i.channelIndex = index;\r
+ instructions.push(i); \r
+ threadSignalNoLock();\r
+}\r
+\r
+void PlayerLiveTV::stop()\r
+{\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "stop");\r
+ struct PLInstruction i;\r
+ i.instruction = I_STOP;\r
+ instructions.push(i);\r
+ threadSignal();\r
+ threadStop();\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "stop succesfull");\r
+}\r
+\r
+// ----------------------------------- Callback\r
+\r
+void PlayerLiveTV::call(void* caller)\r
+{\r
+ if (caller == demuxer)\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");\r
+\r
+ int dxCurrentAspect = demuxer->getAspectRatio();\r
+ if (dxCurrentAspect == Demuxer::ASPECT_4_3)\r
+ {\r
+ if (video->getTVsize() == Video::ASPECT16X9)\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");\r
+ video->setAspectRatio(Video::ASPECT4X3);\r
+ }\r
+ else\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");\r
+ }\r
+\r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerLiveTV::ASPECT43;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+ }\r
+ else if (dxCurrentAspect == Demuxer::ASPECT_16_9)\r
+ {\r
+ if (video->getTVsize() == Video::ASPECT16X9)\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");\r
+ video->setAspectRatio(Video::ASPECT16X9);\r
+ }\r
+ else\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");\r
+ } \r
+\r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerLiveTV::ASPECT169;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+ }\r
+ else\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... ignoring");\r
+ }\r
+ }\r
+ else if (caller == &afeed)\r
+ {\r
+ if (state == S_VIDEOSTARTUP)\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");\r
+ videoStartup = true;\r
+ threadSignalNoLock();\r
+ }\r
+ }\r
+}\r
+\r
+// -----------------------------------\r
+\r
+void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)\r
+{\r
+ // Flag:\r
+ // 0 = normal stream packet\r
+ // 1 = stream end\r
+ // 2 = connection lost\r
+\r
+ //logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);\r
+\r
+ if (flag == 1)\r
+ {\r
+ if (data) abort();\r
+ \r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerLiveTV::STREAM_END;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+ }\r
+ \r
+ if (streamChunks.size() < 11)\r
+ {\r
+ StreamChunk s;\r
+ s.data = data;\r
+ s.len = len;\r
+ streamChunks.push(s);\r
+ threadSignalNoLock();\r
+ }\r
+ else\r
+ {\r
+ // Too many chunks in streamChunks, drop this chunk\r
+ free(data);\r
+ logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");\r
+ }\r
+}\r
+\r
+void PlayerLiveTV::clearStreamChunks()\r
+{\r
+ while(streamChunks.size())\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");\r
+ struct StreamChunk s = streamChunks.front();\r
+ streamChunks.pop();\r
+ free(s.data);\r
+ }\r
+}\r
+\r
+void PlayerLiveTV::chunkToDemuxer()\r
+{\r
+ StreamChunk s = streamChunks.front();\r
+ streamChunks.pop();\r
+// logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);\r
+ /* int a =*/ demuxer->put((UCHAR*)s.data, s.len);\r
+// logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);\r
+ free(s.data); \r
+ if (pendingAudioPlay && (demuxer->getHorizontalSize()|| !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed\r
+ {\r
+ video->sync();\r
+ video->play();\r
+ video->pause();\r
+ //audio->setStreamType(Audio::MPEG2_PES);\r
+ audio->sync();\r
+ audio->play();\r
+ audio->pause();\r
+ pendingAudioPlay = false;\r
+ }\r
+}\r
+\r
+void PlayerLiveTV::switchState(UCHAR newState)\r
+{\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);\r
+\r
+ switch(state)\r
+ {\r
+ case S_STOP: // FROM S_STOP\r
+ {\r
+ switch(newState)\r
+ {\r
+ case S_VIDEOSTARTUP:\r
+ {\r
+ video->blank();\r
+ video->reset();\r
+ //video->sync();\r
+ //video->play();\r
+ //video->pause();\r
+\r
+ audio->stop();\r
+ audio->unPause();\r
+ audio->reset();\r
+ //audio->setStreamType(Audio::MPEG2_PES);\r
+ //audio->sync();\r
+ // I make this modification, since the video/audio devices needs to know at least\r
+ // which kind of video is embedded inside the stream\r
+ // therefore the demuxer needs to feeded at least with enough data\r
+ // to have one video header\r
+ // This is crucial, if we have mixed h264/mpeg2 channels\r
+ // the information from channels is not enough since some directshow decoders need\r
+ // width and height information before startup\r
+ pendingAudioPlay = true;\r
+\r
+ //audio->play();\r
+ //audio->pause();\r
+\r
+ demuxer->reset();\r
+ demuxer->seek();\r
+\r
+ afeed.start();\r
+ vfeed.start();\r
+ subtitles->start();\r
+ tfeed.start();\r
+ \r
+ state = newState;\r
+ if (!video->independentAVStartUp()){\r
+ videoStartup = true;\r
+ threadSignalNoLock();\r
+ }\r
+ return;\r
+ }\r
+ default:\r
+ {\r
+ logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+ abort();\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP\r
+ {\r
+ switch(newState)\r
+ {\r
+ case S_PREBUFFERING:\r
+ {\r
+ pendingAudioPlay=false;\r
+ vfeed.release();\r
+ state = newState;\r
+ return;\r
+ }\r
+ \r
+ case S_VIDEOSTARTUP:\r
+ {\r
+\r
+ vdr->stopStreaming();\r
+ clearStreamChunks(); \r
+ vfeed.stop();\r
+ afeed.stop();\r
+ subtitles->stop();\r
+ tfeed.stop();\r
+ \r
+ video->blank();\r
+ video->reset();\r
+ //video->sync();\r
+ //video->play();\r
+ //video->pause();\r
+ audio->stop();\r
+ audio->unPause();\r
+ audio->reset();\r
+ //audio->setStreamType(Audio::MPEG2_PES);\r
+ //audio->sync();\r
+ pendingAudioPlay = true;\r
+ //audio->play();\r
+ //audio->pause();\r
+\r
+ demuxer->reset();\r
+ demuxer->seek();\r
+\r
+ afeed.start();\r
+ vfeed.start();\r
+ subtitles->start(); \r
+ tfeed.start();\r
+ state = newState;\r
+ if (!video->independentAVStartUp()){\r
+ videoStartup = true;\r
+ threadSignalNoLock();\r
+ }\r
+ return;\r
+ } \r
+ case S_STOP:\r
+ { \r
+ vdr->stopStreaming();\r
+ pendingAudioPlay=false;\r
+ clearStreamChunks();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ subtitles->stop();\r
+ tfeed.stop();\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+ audio->reset();\r
+ video->reset();\r
+ state = newState;\r
+ return;\r
+ }\r
+ default:\r
+ {\r
+ logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+ abort();\r
+ break;\r
+ } \r
+ }\r
+ }\r
+ \r
+ case S_PREBUFFERING: // FROM S_PREBUFFERING\r
+ {\r
+ switch(newState)\r
+ {\r
+ case S_PLAY:\r
+ {\r
+ pendingAudioPlay=false;\r
+ audio->unPause();\r
+ video->unPause();\r
+ state = newState;\r
+ return;\r
+ }\r
+ case S_VIDEOSTARTUP:\r
+ {\r
+ vdr->stopStreaming();\r
+ clearStreamChunks();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ subtitles->stop();\r
+ tfeed.stop();\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+ audio->unPause();\r
+ audio->reset();\r
+\r
+ video->reset();\r
+ //video->sync();\r
+ //video->play();\r
+ //video->pause();\r
+\r
+ //audio->setStreamType(Audio::MPEG2_PES);\r
+ //audio->sync();\r
+ pendingAudioPlay = true;\r
+ //audio->play();\r
+ //audio->pause();\r
+\r
+ demuxer->reset();\r
+ demuxer->seek();\r
+\r
+ afeed.start();\r
+ vfeed.start();\r
+ subtitles->start();\r
+ tfeed.start();\r
+\r
+ state = newState;\r
+ return;\r
+ }\r
+ case S_STOP:\r
+ {\r
+ pendingAudioPlay=false;\r
+ vdr->stopStreaming();\r
+ clearStreamChunks();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ subtitles->stop();\r
+ tfeed.stop();\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+ audio->reset();\r
+ video->reset();\r
+ state = newState;\r
+ return; \r
+ }\r
+ default:\r
+ {\r
+ logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+ abort();\r
+ break;\r
+ } \r
+ }\r
+ }\r
+ \r
+ case S_PLAY: // FROM S_PLAY\r
+ {\r
+ switch(newState)\r
+ {\r
+ case S_STOP:\r
+ { \r
+ pendingAudioPlay=false;\r
+ vdr->stopStreaming();\r
+ clearStreamChunks();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ subtitles->stop();\r
+ tfeed.stop();\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+ audio->reset();\r
+ video->reset();\r
+ state = newState;\r
+ return;\r
+ }\r
+ case S_VIDEOSTARTUP:\r
+ {\r
+ vdr->stopStreaming();\r
+ clearStreamChunks();\r
+ vfeed.stop();\r
+ afeed.stop();\r
+ subtitles->stop();\r
+ tfeed.stop();\r
+ video->stop();\r
+ video->blank();\r
+ audio->stop();\r
+ audio->unPause();\r
+ audio->reset();\r
+\r
+ video->reset();\r
+ \r
+ //video->sync();\r
+ // video->play();\r
+ //video->pause();\r
+\r
+ //audio->setStreamType(Audio::MPEG2_PES);\r
+ //audio->sync();\r
+ //audio->play();\r
+ //audio->pause();\r
+ pendingAudioPlay = true;\r
+ demuxer->reset();\r
+ demuxer->seek();\r
+\r
+ afeed.start();\r
+ vfeed.start();\r
+ subtitles->start();\r
+ tfeed.start();\r
+ state = newState;\r
+ if (!video->independentAVStartUp()){\r
+ videoStartup = true;\r
+ threadSignalNoLock();\r
+ }\r
+ return;\r
+ }\r
+ default:\r
+ {\r
+ logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+ abort();\r
+ break;\r
+ } \r
+ }\r
+ } \r
+ } \r
+}\r
+\r
+bool PlayerLiveTV::checkError()\r
+{\r
+ if (!vdr->isConnected())\r
+ {\r
+ if (state != S_STOP) switchState(S_STOP);\r
+ \r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerLiveTV::CONNECTION_LOST;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+ \r
+ return true;\r
+ } \r
+ return false;\r
+}\r
+\r
+void PlayerLiveTV::optimizeInstructionQueue()\r
+{\r
+ // Walk the list\r
+ \r
+ // Currently there are only 2 instruction types, so this is a bit overkill...\r
+\r
+ struct PLInstruction i;\r
+ while(instructions.size() > 1)\r
+ {\r
+ i = instructions.front();\r
+ if (i.instruction == I_SETCHANNEL)\r
+ {\r
+ instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant\r
+ }\r
+ else if (i.instruction == I_STOP)\r
+ {\r
+ return; // return here and ensure the next instruction will be stop\r
+ }\r
+ }\r
+}\r
+\r
+void PlayerLiveTV::threadMethod()\r
+{\r
+ while(1)\r
+ {\r
+\r
+// logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);\r
+ if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Enter prebuffering");\r
+ switchState(S_PREBUFFERING);\r
+ videoStartup = false;\r
+ preBufferCount = 0;\r
+ \r
+ checkError();\r
+ } \r
+ \r
+ while(!instructions.empty())\r
+ {\r
+ if (instructions.size() > 1) optimizeInstructionQueue();\r
+\r
+ struct PLInstruction i = instructions.front();\r
+ instructions.pop();\r
+ \r
+ if (i.instruction == I_SETCHANNEL)\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");\r
+ \r
+ \r
+ switchState(S_VIDEOSTARTUP);\r
+ \r
+ if (!checkError())\r
+ {\r
+ Channel* chan = (*chanList)[i.channelIndex];\r
+ chan->loadPids();\r
+ h264=chan->vstreamtype==0x1b;\r
+ demuxer->seth264(h264);\r
+ video->seth264mode(chan->vstreamtype==0x1b);\r
+ demuxer->setVID(chan->vpid);\r
+ video->seth264mode(chan->vstreamtype==0x1b);\r
+\r
+ if (chan->numAPids > 0) \r
+ {\r
+ demuxer->setAID(chan->apids[0].pid,0);\r
+ audio->setStreamType(Audio::MPEG2_PES);\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);\r
+ }\r
+ else \r
+ {\r
+ if (chan->numDPids > 0 && audio->maysupportAc3()) \r
+ {\r
+ demuxer->setAID(chan->dpids[0].pid,1);\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3)", chan->vpid, chan->dpids[0].pid);\r
+ } \r
+ else\r
+ {\r
+ logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);\r
+ }\r
+ }\r
+ if (chan->numSPids > 0)\r
+ demuxer->setSubID(chan->spids[0].pid);\r
+ demuxer->setTID(chan->tpid);\r
+ teletext->ResetDecoder();\r
+ int streamSuccess = vdr->streamChannel(chan->number, this);\r
+ if (!checkError() && !streamSuccess)\r
+ { \r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerLiveTV::STREAM_END;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+ }\r
+ }\r
+ }\r
+ else if (i.instruction == I_STOP)\r
+ {\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");\r
+ switchState(S_STOP);\r
+ checkError();\r
+\r
+ stopNow = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ threadCheckExit();\r
+\r
+ if (stopNow) break;\r
+\r
+ while(streamChunks.size())\r
+ {\r
+ chunkToDemuxer();\r
+\r
+ if (state == S_PREBUFFERING)\r
+ {\r
+ ++preBufferCount;\r
+ ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone);\r
+ \r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = messageReceiver;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerLiveTV::PREBUFFERING;\r
+ m->tag = percentDone;\r
+ messageQueue->postMessageFromOuterSpace(m);\r
+\r
+ if (preBufferCount == preBufferAmount)\r
+ {\r
+ switchState(S_PLAY);\r
+ checkError();\r
+ }\r
+ }\r
+ }\r
+ threadLock();\r
+ threadWaitForSignal(); // unlocks and waits for signal\r
+ threadUnlock();\r
+ }\r
+\r
+ logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");\r
+}\r
+\r
-/*
- Copyright 2004-2006 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "playerradio.h"
-
-#include "log.h"
-#include "audio.h"
-#include "video.h"
-#include "demuxervdr.h"
-#include "demuxerts.h"
-#include "remote.h"
-#include "vdr.h"
-#include "message.h"
-#include "messagequeue.h"
-
-// ----------------------------------- Called from outside, one offs or info funcs
-
-PlayerRadio::PlayerRadio(MessageQueue* tmessageQueue, void* tmessageReceiver)
-: afeed(this)
-{
- messageQueue = tmessageQueue;
- messageReceiver = tmessageReceiver;
- audio = Audio::getInstance();
- logger = Log::getInstance();
- vdr = VDR::getInstance();
- initted = false;
- lengthBytes = 0;
- lengthPackets = 0;
- streamPos = 0;
- state = S_STOP;
-
- startPTS = 0;
- lengthSeconds = 0;
-
- threadBuffer = NULL;
-
- blockSize = 10000;
- startupBlockSize = 20000;
-
- Video::getInstance()->turnVideoOff();
-}
-
-PlayerRadio::~PlayerRadio()
-{
- if (initted) shutdown();
-}
-
-int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets, bool isPesRecording)
-{
- if (initted) return 0;
-#ifndef WIN32
- pthread_mutex_init(&mutex, NULL);
-#else
- mutex=CreateMutex(NULL,FALSE,NULL);
-#endif
-
- if (isPesRecording)
- demuxer = new DemuxerVDR();
- else
- demuxer = new DemuxerTS();
- if (!demuxer) return 0;
-
- if (!demuxer->init(this, audio, NULL, NULL, 0, 40000, 0))
- {
- logger->log("PlayerRadio", Log::ERR, "Demuxer failed to init");
- shutdown();
- return 0;
- }
-
- afeed.init();
- audio->stop();
-
- lengthBytes = tlengthBytes;
- lengthPackets = tlengthPackets;
-
- logger->log("PlayerRadio", Log::DEBUG, "PlayerRadio has received length bytes of %llu", lengthBytes);
-
- UINT thisRead = 0;
- int success;
-
- UCHAR* buffer = vdr->getBlock(0, 10000, &thisRead);
- if (!buffer)
- {
- logger->log("PlayerRadio", Log::ERR, "Failed to get start block");
- shutdown();
- if (!vdr->isConnected()) doConnectionLost();
- return 0;
- }
-
- success = demuxer->findPTS(buffer, thisRead, &startPTS);
- if (!success)
- {
- logger->log("PlayerRadio", Log::ERR, "Failed to get start PTS");
- free(buffer);
- shutdown();
- return 0;
- }
-
- free(buffer);
-
- if (!setLengthSeconds())
- {
- logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds");
- shutdown();
- return 0;
- }
-
- initted = true;
- return 1;
-}
-
-bool PlayerRadio::setLengthSeconds()
-{
- int success;
- ULLONG endPTS = 0;
- UINT thisRead = 0;
- UCHAR* buffer = vdr->getBlock(lengthBytes - 10000, 10000, &thisRead);
- if (!buffer)
- {
- logger->log("PlayerRadio", Log::ERR, "Failed to get end block");
- if (!vdr->isConnected()) doConnectionLost();
- return false;
- }
-
- success = demuxer->findPTS(buffer, thisRead, &endPTS);
- free(buffer);
- if (!success)
- {
- logger->log("PlayerRadio", Log::ERR, "Failed to get end PTS");
- return false;
- }
-
- if (startPTS < endPTS)
- {
- lengthSeconds = (endPTS - startPTS) / 90000;
- }
- else
- {
- lengthSeconds = (startPTS - endPTS) / 90000;
- }
-
- return true;
-}
-
-int PlayerRadio::shutdown()
-{
- if (!initted) return 0;
- switchState(S_STOP);
- initted = false;
-
- delete demuxer;
- demuxer = NULL;
-
-#ifdef WIN32
- CloseHandle(mutex);
-#endif
-
- return 1;
-}
-
-
-void PlayerRadio::setStartBytes(ULLONG startBytes)
-{
- streamPos = startBytes;
-}
-
-ULONG PlayerRadio::getLengthSeconds()
-{
- return lengthSeconds;
-}
-
-ULONG PlayerRadio::getCurrentSeconds()
-{
- if (startup) return 0;
-
- long long currentPTS = demuxer->getAudioPTS();
- currentPTS -= startPTS;
- if (currentPTS < 0) currentPTS += 8589934592ULL;
- ULONG ret = currentPTS / 90000;
- return ret;
-}
-
-// ----------------------------------- Externally called events
-
-void PlayerRadio::play()
-{
- if (!initted) return;
- if (state == S_PLAY) return;
- lock();
- switchState(S_PLAY);
- unLock();
-}
-
-void PlayerRadio::stop()
-{
- if (!initted) return;
- if (state == S_STOP) return;
- lock();
- logger->log("PlayerRadio", Log::DEBUG, "Stop called lock");
- switchState(S_STOP);
- unLock();
-}
-
-void PlayerRadio::pause()
-{
- if (!initted) return;
- lock();
-
- if (state == S_PAUSE_P)
- {
- switchState(S_PLAY);
- }
- else
- {
- switchState(S_PAUSE_P);
- }
-
- unLock();
-}
-
-void PlayerRadio::jumpToPercent(double percent)
-{
- lock();
- logger->log("PlayerRadio", Log::DEBUG, "JUMP TO %i%%", percent);
- ULONG newPacket = (ULONG)(percent * lengthPackets / 100);
- switchState(S_JUMP, newPacket);
- unLock();
-}
-
-void PlayerRadio::skipForward(UINT seconds)
-{
- lock();
- logger->log("PlayerRadio", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
- ULONG currentSeconds = getCurrentSeconds();
- ULONG currentPacket = demuxer->getPacketNum();
-
- if (currentSeconds == 0) { unLock(); return; } // div by zero
- if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid
-
- ULONG newPacket = currentPacket + (currentPacket * seconds / currentSeconds);
- if (newPacket > lengthPackets) { switchState(S_PLAY); unLock(); }
- else switchState(S_JUMP, newPacket);
- unLock();
-}
-
-void PlayerRadio::skipBackward(UINT seconds)
-{
- lock();
- logger->log("PlayerRadio", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
-
- ULONG currentSeconds = getCurrentSeconds();
- ULONG currentPacket = demuxer->getPacketNum();
-
- if (currentSeconds == 0) { unLock(); return; } // div by zero
- if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid
-
- ULONG newPacket;
- if ((UINT)seconds > currentSeconds)
- newPacket = 0;
- else
- newPacket = currentPacket - (currentPacket * seconds / currentSeconds);
-
- switchState(S_JUMP, newPacket);
- unLock();
-}
-
-// ----------------------------------- Implementations called events
-
-void PlayerRadio::switchState(UCHAR toState, ULONG jumpPacket)
-{
- if (!initted) return;
-
- logger->log("PlayerRadio", Log::DEBUG, "Switch state from %u to %u", state, toState);
-
- switch(state) // current state selector
- {
- case S_PLAY: // from S_PLAY -----------------------------------
- {
- switch(toState)
- {
- case S_PLAY: // to S_PLAY
- {
- return;
- }
- case S_PAUSE_P: // to S_PAUSE_P
- {
- audio->pause();
- state = S_PAUSE_P;
- return;
- }
- case S_STOP: // to S_STOP
- {
- afeed.stop();
- threadStop();
- audio->stop();
- audio->unPause();
- demuxer->reset();
- state = S_STOP;
- return;
- }
- case S_JUMP: // to S_JUMP
- {
- restartAtPacket(jumpPacket);
- return;
- }
- }
- }
- case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
- {
- switch(toState)
- {
- case S_PLAY: // to S_PLAY
- {
- audio->unPause();
- state = S_PLAY;
- return;
- }
- case S_PAUSE_P: // to S_PAUSE_P
- {
- return;
- }
- case S_STOP: // to S_STOP
- {
- afeed.stop();
- threadStop();
- audio->stop();
- audio->unPause();
- demuxer->reset();
- audio->systemMuteOff();
- state = S_STOP;
- return;
- }
- case S_JUMP: // to S_JUMP
- {
- state = S_PLAY;
- audio->unPause();
- restartAtPacket(jumpPacket);
- return;
- }
- }
- }
- case S_STOP: // from S_STOP -----------------------------------
- {
- switch(toState)
- {
- case S_PLAY: // to S_PLAY
- {
- startup = true;
-
- audio->reset();
- audio->setStreamType(Audio::MPEG2_PES);
- audio->systemMuteOff();
- demuxer->reset();
-
- // FIXME use restartAtPacket here?
- if (currentPacketNumber > lengthPackets) currentPacketNumber = 0;
- demuxer->setPacketNum(currentPacketNumber);
- state = S_PLAY;
- threadStart();
- logger->log("PlayerRadio", Log::DEBUG, "Immediate play");
- afeed.start();
- audio->play();
-
- return;
- }
- case S_PAUSE_P: // to S_PAUSE_P
- {
- return;
- }
- case S_STOP: // to S_STOP
- {
- return;
- }
- case S_JUMP: // to S_JUMP
- {
- return;
- }
- }
- }
- // case S_JUMP cannot be selected as a start state because it auto flips to play
- }
-}
-
-// ----------------------------------- Internal functions
-
-void PlayerRadio::lock()
-{
-#ifndef WIN32
- pthread_mutex_lock(&mutex);
- logger->log("PlayerRadio", Log::DEBUG, "LOCKED");
-
-#else
- WaitForSingleObject(mutex, INFINITE);
-#endif
-}
-
-void PlayerRadio::unLock()
-{
-#ifndef WIN32
- logger->log("PlayerRadio", Log::DEBUG, "UNLOCKING");
- pthread_mutex_unlock(&mutex);
-#else
- ReleaseMutex(mutex);
-#endif
-}
-
-void PlayerRadio::restartAtPacket(ULONG newPacket)
-{
- afeed.stop();
- threadStop();
- audio->reset();
- audio->setStreamType(Audio::MPEG2_PES);
- demuxer->flush();
- currentPacketNumber = newPacket;
- demuxer->setPacketNum(newPacket);
- afeed.start();
- threadStart();
- audio->play();
- audio->systemMuteOff();
- audio->doMuting();
-}
-
-void PlayerRadio::doConnectionLost()
-{
- logger->log("PlayerRadio", Log::DEBUG, "Connection lost, sending message");
- Message* m = new Message();
- m->to = messageReceiver;
- m->from = this;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerRadio::CONNECTION_LOST;
- messageQueue->postMessage(m);
-}
-
-// ----------------------------------- Callback
-
-void PlayerRadio::call(void* caller)
-{
- threadSignalNoLock();
-}
-
-// ----------------------------------- Feed thread
-
-void PlayerRadio::threadMethod()
-{
- if (state == S_PLAY) threadFeedPlay();
-}
-
-void PlayerRadio::threadFeedPlay()
-{
- ULLONG feedPosition;
- UINT thisRead, writeLength, thisWrite, askFor;
- time_t lastRescan = time(NULL);
-
- feedPosition = vdr->positionFromFrameNumber(currentPacketNumber);
- if (!vdr->isConnected()) { doConnectionLost(); return; }
- logger->log("PlayerRadio", Log::DEBUG, "startFeedPlay: wantedPacket %i goto %llu", currentPacketNumber, feedPosition);
-
-
- while(1)
- {
- thisRead = 0;
- writeLength = 0;
- thisWrite = 0;
-
- threadCheckExit();
-
- // If we havn't rescanned for a while..
- if ((lastRescan + 60) < time(NULL))
- {
- lengthBytes = vdr->rescanRecording(&lengthPackets);
- if (!vdr->isConnected()) { doConnectionLost(); return; }
- logger->log("PlayerRadio", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
- lastRescan = time(NULL);
-
- if (!setLengthSeconds())
- {
- logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds in thread");
- return;
- }
- }
-
- if (feedPosition >= lengthBytes) break; // finished playback
-
- if (startup)
- {
- if (startupBlockSize > lengthBytes)
- askFor = lengthBytes; // is a very small recording!
- else
- askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
- }
- else
- {
- if ((feedPosition + blockSize) > lengthBytes) // last block of recording
- askFor = lengthBytes - feedPosition;
- else // normal
- askFor = blockSize;
- }
-
- threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
- feedPosition += thisRead;
-
- if (!vdr->isConnected())
- {
- doConnectionLost();
- return;
- }
-
- if (!threadBuffer) break;
-
- if (startup)
- {
- int a_stream = demuxer->scan(threadBuffer, thisRead);
- demuxer->setAudioStream(a_stream);
- logger->log("PlayerRadio", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
- startup = false;
- }
-
- threadCheckExit();
-
- while(writeLength < thisRead)
- {
- thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
- writeLength += thisWrite;
-
- if (!thisWrite)
- {
- // demuxer is full and can't take anymore
- threadLock();
- threadWaitForSignal();
- threadUnlock();
- }
-
- threadCheckExit();
- }
-
- free(threadBuffer);
- threadBuffer = NULL;
-
- }
-
- // end of recording
- logger->log("PlayerRadio", Log::DEBUG, "Recording playback ends");
-
- threadCheckExit();
-
-
- Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
- m->to = messageReceiver;
- m->from = this;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerRadio::STOP_PLAYBACK;
- logger->log("PlayerRadio", Log::DEBUG, "Posting message to %p...", messageQueue);
- messageQueue->postMessage(m);
-}
-
-void PlayerRadio::threadPostStopCleanup()
-{
- if (threadBuffer)
- {
- free(threadBuffer);
- threadBuffer = NULL;
- }
-}
-
+/*\r
+ Copyright 2004-2006 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "playerradio.h"\r
+\r
+#include "log.h"\r
+#include "audio.h"\r
+#include "video.h"\r
+#include "demuxervdr.h"\r
+#include "demuxerts.h"\r
+#include "remote.h"\r
+#include "vdr.h"\r
+#include "message.h"\r
+#include "messagequeue.h"\r
+\r
+// ----------------------------------- Called from outside, one offs or info funcs\r
+\r
+PlayerRadio::PlayerRadio(MessageQueue* tmessageQueue, void* tmessageReceiver)\r
+: afeed(this)\r
+{\r
+ messageQueue = tmessageQueue;\r
+ messageReceiver = tmessageReceiver;\r
+ audio = Audio::getInstance();\r
+ logger = Log::getInstance();\r
+ vdr = VDR::getInstance();\r
+ initted = false;\r
+ lengthBytes = 0;\r
+ lengthPackets = 0;\r
+ streamPos = 0;\r
+ state = S_STOP;\r
+\r
+ startPTS = 0;\r
+ lengthSeconds = 0;\r
+\r
+ threadBuffer = NULL;\r
+\r
+ blockSize = 10000;\r
+ startupBlockSize = 20000;\r
+\r
+ Video::getInstance()->turnVideoOff();\r
+}\r
+\r
+PlayerRadio::~PlayerRadio()\r
+{\r
+ if (initted) shutdown();\r
+}\r
+\r
+int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets, bool isPesRecording)\r
+{\r
+ if (initted) return 0;\r
+#ifndef WIN32\r
+ pthread_mutex_init(&mutex, NULL);\r
+#else\r
+ mutex=CreateMutex(NULL,FALSE,NULL);\r
+#endif\r
+\r
+ if (isPesRecording)\r
+ demuxer = new DemuxerVDR();\r
+ else\r
+ demuxer = new DemuxerTS();\r
+ if (!demuxer) return 0;\r
+\r
+ if (!demuxer->init(this, audio, NULL, NULL, 0, 40000, 0))\r
+ {\r
+ logger->log("PlayerRadio", Log::ERR, "Demuxer failed to init");\r
+ shutdown();\r
+ return 0;\r
+ }\r
+\r
+ afeed.init();\r
+ audio->stop();\r
+\r
+ lengthBytes = tlengthBytes;\r
+ lengthPackets = tlengthPackets;\r
+\r
+ logger->log("PlayerRadio", Log::DEBUG, "PlayerRadio has received length bytes of %llu", lengthBytes);\r
+\r
+ UINT thisRead = 0;\r
+ int success;\r
+\r
+ UCHAR* buffer = vdr->getBlock(0, 10000, &thisRead);\r
+ if (!buffer)\r
+ {\r
+ logger->log("PlayerRadio", Log::ERR, "Failed to get start block");\r
+ shutdown();\r
+ if (!vdr->isConnected()) doConnectionLost();\r
+ return 0;\r
+ }\r
+\r
+ success = demuxer->findPTS(buffer, thisRead, &startPTS);\r
+ if (!success)\r
+ {\r
+ logger->log("PlayerRadio", Log::ERR, "Failed to get start PTS");\r
+ free(buffer);\r
+ shutdown();\r
+ return 0;\r
+ }\r
+\r
+ free(buffer);\r
+\r
+ if (!setLengthSeconds())\r
+ {\r
+ logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds");\r
+ shutdown();\r
+ return 0;\r
+ }\r
+\r
+ initted = true;\r
+ return 1;\r
+}\r
+\r
+bool PlayerRadio::setLengthSeconds()\r
+{\r
+ int success;\r
+ ULLONG endPTS = 0;\r
+ UINT thisRead = 0;\r
+ UCHAR* buffer = vdr->getBlock(lengthBytes - 10000, 10000, &thisRead);\r
+ if (!buffer)\r
+ {\r
+ logger->log("PlayerRadio", Log::ERR, "Failed to get end block");\r
+ if (!vdr->isConnected()) doConnectionLost(); \r
+ return false;\r
+ }\r
+\r
+ success = demuxer->findPTS(buffer, thisRead, &endPTS);\r
+ free(buffer);\r
+ if (!success)\r
+ {\r
+ logger->log("PlayerRadio", Log::ERR, "Failed to get end PTS");\r
+ return false;\r
+ }\r
+\r
+ if (startPTS < endPTS)\r
+ {\r
+ lengthSeconds = (endPTS - startPTS) / 90000;\r
+ }\r
+ else\r
+ {\r
+ lengthSeconds = (startPTS - endPTS) / 90000;\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+int PlayerRadio::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ switchState(S_STOP);\r
+ initted = false;\r
+\r
+ delete demuxer;\r
+ demuxer = NULL;\r
+\r
+#ifdef WIN32\r
+ CloseHandle(mutex);\r
+#endif\r
+\r
+ return 1;\r
+}\r
+\r
+\r
+void PlayerRadio::setStartBytes(ULLONG startBytes)\r
+{\r
+ streamPos = startBytes;\r
+}\r
+\r
+ULONG PlayerRadio::getLengthSeconds()\r
+{\r
+ return lengthSeconds;\r
+}\r
+\r
+ULONG PlayerRadio::getCurrentSeconds()\r
+{\r
+ if (startup) return 0;\r
+\r
+ long long currentPTS = demuxer->getAudioPTS();\r
+ currentPTS -= startPTS;\r
+ if (currentPTS < 0) currentPTS += 8589934592ULL;\r
+ ULONG ret = currentPTS / 90000;\r
+ return ret;\r
+}\r
+\r
+// ----------------------------------- Externally called events\r
+\r
+void PlayerRadio::play()\r
+{\r
+ if (!initted) return;\r
+ if (state == S_PLAY) return;\r
+ lock();\r
+ switchState(S_PLAY);\r
+ unLock();\r
+}\r
+\r
+\r
+void PlayerRadio::playpause()\r
+{\r
+ if (!initted) return;\r
+ lock();\r
+ if (state==S_PLAY) {\r
+ switchState(S_PAUSE_P);\r
+ } else {\r
+ switchState(S_PLAY);\r
+ }\r
+ unLock();\r
+}\r
+\r
+void PlayerRadio::stop()\r
+{\r
+ if (!initted) return;\r
+ if (state == S_STOP) return;\r
+ lock();\r
+ logger->log("PlayerRadio", Log::DEBUG, "Stop called lock");\r
+ switchState(S_STOP);\r
+ unLock();\r
+}\r
+\r
+void PlayerRadio::pause()\r
+{\r
+ if (!initted) return;\r
+ lock();\r
+\r
+ if (state == S_PAUSE_P)\r
+ {\r
+ switchState(S_PLAY);\r
+ }\r
+ else\r
+ {\r
+ switchState(S_PAUSE_P);\r
+ }\r
+\r
+ unLock();\r
+}\r
+\r
+void PlayerRadio::jumpToPercent(double percent)\r
+{\r
+ lock();\r
+ logger->log("PlayerRadio", Log::DEBUG, "JUMP TO %i%%", percent);\r
+ ULONG newPacket = (ULONG)(percent * lengthPackets / 100);\r
+ switchState(S_JUMP, newPacket);\r
+ unLock();\r
+}\r
+\r
+void PlayerRadio::skipForward(UINT seconds)\r
+{\r
+ lock();\r
+ logger->log("PlayerRadio", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);\r
+ ULONG currentSeconds = getCurrentSeconds();\r
+ ULONG currentPacket = demuxer->getPacketNum();\r
+\r
+ if (currentSeconds == 0) { unLock(); return; } // div by zero\r
+ if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid\r
+\r
+ ULONG newPacket = currentPacket + (currentPacket * seconds / currentSeconds);\r
+ if (newPacket > lengthPackets) { switchState(S_PLAY); unLock(); }\r
+ else switchState(S_JUMP, newPacket);\r
+ unLock();\r
+}\r
+\r
+void PlayerRadio::skipBackward(UINT seconds)\r
+{\r
+ lock();\r
+ logger->log("PlayerRadio", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);\r
+\r
+ ULONG currentSeconds = getCurrentSeconds();\r
+ ULONG currentPacket = demuxer->getPacketNum();\r
+\r
+ if (currentSeconds == 0) { unLock(); return; } // div by zero\r
+ if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid\r
+\r
+ ULONG newPacket;\r
+ if ((UINT)seconds > currentSeconds)\r
+ newPacket = 0;\r
+ else\r
+ newPacket = currentPacket - (currentPacket * seconds / currentSeconds);\r
+\r
+ switchState(S_JUMP, newPacket);\r
+ unLock();\r
+}\r
+\r
+// ----------------------------------- Implementations called events\r
+\r
+void PlayerRadio::switchState(UCHAR toState, ULONG jumpPacket)\r
+{\r
+ if (!initted) return;\r
+\r
+ logger->log("PlayerRadio", Log::DEBUG, "Switch state from %u to %u", state, toState);\r
+\r
+ switch(state) // current state selector\r
+ {\r
+ case S_PLAY: // from S_PLAY -----------------------------------\r
+ {\r
+ switch(toState)\r
+ {\r
+ case S_PLAY: // to S_PLAY\r
+ {\r
+ return;\r
+ }\r
+ case S_PAUSE_P: // to S_PAUSE_P\r
+ {\r
+ audio->pause();\r
+ state = S_PAUSE_P;\r
+ return;\r
+ }\r
+ case S_STOP: // to S_STOP\r
+ {\r
+ afeed.stop();\r
+ threadStop();\r
+ audio->stop();\r
+ audio->unPause();\r
+ demuxer->reset();\r
+ state = S_STOP;\r
+ return;\r
+ }\r
+ case S_JUMP: // to S_JUMP\r
+ {\r
+ restartAtPacket(jumpPacket);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ case S_PAUSE_P: // from S_PAUSE_P -----------------------------------\r
+ {\r
+ switch(toState)\r
+ {\r
+ case S_PLAY: // to S_PLAY\r
+ {\r
+ audio->unPause();\r
+ state = S_PLAY;\r
+ return;\r
+ }\r
+ case S_PAUSE_P: // to S_PAUSE_P\r
+ {\r
+ return;\r
+ }\r
+ case S_STOP: // to S_STOP\r
+ {\r
+ afeed.stop();\r
+ threadStop();\r
+ audio->stop();\r
+ audio->unPause();\r
+ demuxer->reset();\r
+ audio->systemMuteOff();\r
+ state = S_STOP;\r
+ return;\r
+ }\r
+ case S_JUMP: // to S_JUMP\r
+ {\r
+ state = S_PLAY;\r
+ audio->unPause();\r
+ restartAtPacket(jumpPacket);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ case S_STOP: // from S_STOP -----------------------------------\r
+ {\r
+ switch(toState)\r
+ {\r
+ case S_PLAY: // to S_PLAY\r
+ {\r
+ startup = true;\r
+\r
+ audio->reset();\r
+ audio->setStreamType(Audio::MPEG2_PES);\r
+ audio->systemMuteOff();\r
+ demuxer->reset();\r
+\r
+ // FIXME use restartAtPacket here?\r
+ if (currentPacketNumber > lengthPackets) currentPacketNumber = 0;\r
+ demuxer->setPacketNum(currentPacketNumber);\r
+ state = S_PLAY;\r
+ threadStart();\r
+ logger->log("PlayerRadio", Log::DEBUG, "Immediate play");\r
+ afeed.start();\r
+ audio->play();\r
+\r
+ return;\r
+ }\r
+ case S_PAUSE_P: // to S_PAUSE_P\r
+ {\r
+ return;\r
+ }\r
+ case S_STOP: // to S_STOP\r
+ {\r
+ return;\r
+ }\r
+ case S_JUMP: // to S_JUMP\r
+ {\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ // case S_JUMP cannot be selected as a start state because it auto flips to play\r
+ }\r
+}\r
+\r
+// ----------------------------------- Internal functions\r
+\r
+void PlayerRadio::lock()\r
+{\r
+#ifndef WIN32\r
+ pthread_mutex_lock(&mutex);\r
+ logger->log("PlayerRadio", Log::DEBUG, "LOCKED");\r
+\r
+#else\r
+ WaitForSingleObject(mutex, INFINITE);\r
+#endif\r
+}\r
+\r
+void PlayerRadio::unLock()\r
+{\r
+#ifndef WIN32\r
+ logger->log("PlayerRadio", Log::DEBUG, "UNLOCKING");\r
+ pthread_mutex_unlock(&mutex);\r
+#else\r
+ ReleaseMutex(mutex);\r
+#endif\r
+}\r
+\r
+void PlayerRadio::restartAtPacket(ULONG newPacket)\r
+{\r
+ afeed.stop();\r
+ threadStop();\r
+ audio->reset();\r
+ audio->setStreamType(Audio::MPEG2_PES);\r
+ demuxer->flush();\r
+ currentPacketNumber = newPacket;\r
+ demuxer->setPacketNum(newPacket);\r
+ afeed.start();\r
+ threadStart();\r
+ audio->play();\r
+ audio->systemMuteOff();\r
+ audio->doMuting();\r
+}\r
+\r
+void PlayerRadio::doConnectionLost()\r
+{\r
+ logger->log("PlayerRadio", Log::DEBUG, "Connection lost, sending message");\r
+ Message* m = new Message();\r
+ m->to = messageReceiver;\r
+ m->from = this;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerRadio::CONNECTION_LOST;\r
+ messageQueue->postMessage(m);\r
+}\r
+\r
+// ----------------------------------- Callback\r
+\r
+void PlayerRadio::call(void* caller)\r
+{\r
+ threadSignalNoLock();\r
+}\r
+\r
+// ----------------------------------- Feed thread\r
+\r
+void PlayerRadio::threadMethod()\r
+{\r
+ if (state == S_PLAY) threadFeedPlay();\r
+}\r
+\r
+void PlayerRadio::threadFeedPlay()\r
+{\r
+ ULLONG feedPosition;\r
+ UINT thisRead, writeLength, thisWrite, askFor;\r
+ time_t lastRescan = time(NULL);\r
+\r
+ feedPosition = vdr->positionFromFrameNumber(currentPacketNumber);\r
+ if (!vdr->isConnected()) { doConnectionLost(); return; }\r
+ logger->log("PlayerRadio", Log::DEBUG, "startFeedPlay: wantedPacket %i goto %llu", currentPacketNumber, feedPosition);\r
+\r
+\r
+ while(1)\r
+ {\r
+ thisRead = 0;\r
+ writeLength = 0;\r
+ thisWrite = 0;\r
+\r
+ threadCheckExit();\r
+\r
+ // If we havn't rescanned for a while..\r
+ if ((lastRescan + 60) < time(NULL))\r
+ {\r
+ lengthBytes = vdr->rescanRecording(&lengthPackets);\r
+ if (!vdr->isConnected()) { doConnectionLost(); return; }\r
+ logger->log("PlayerRadio", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);\r
+ lastRescan = time(NULL);\r
+\r
+ if (!setLengthSeconds())\r
+ {\r
+ logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds in thread");\r
+ return;\r
+ }\r
+ }\r
+\r
+ if (feedPosition >= lengthBytes) break; // finished playback\r
+\r
+ if (startup)\r
+ {\r
+ if (startupBlockSize > lengthBytes)\r
+ askFor = lengthBytes; // is a very small recording!\r
+ else\r
+ askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams\r
+ }\r
+ else\r
+ {\r
+ if ((feedPosition + blockSize) > lengthBytes) // last block of recording\r
+ askFor = lengthBytes - feedPosition;\r
+ else // normal\r
+ askFor = blockSize;\r
+ }\r
+\r
+ threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);\r
+ feedPosition += thisRead;\r
+\r
+ if (!vdr->isConnected())\r
+ {\r
+ doConnectionLost();\r
+ return;\r
+ }\r
+\r
+ if (!threadBuffer) break;\r
+\r
+ if (startup)\r
+ {\r
+ int a_stream = demuxer->scan(threadBuffer, thisRead);\r
+ demuxer->setAudioStream(a_stream);\r
+ logger->log("PlayerRadio", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);\r
+ startup = false;\r
+ }\r
+\r
+ threadCheckExit();\r
+\r
+ while(writeLength < thisRead)\r
+ {\r
+ thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);\r
+ writeLength += thisWrite;\r
+\r
+ if (!thisWrite)\r
+ {\r
+ // demuxer is full and can't take anymore\r
+ threadLock();\r
+ threadWaitForSignal();\r
+ threadUnlock();\r
+ }\r
+\r
+ threadCheckExit();\r
+ }\r
+\r
+ free(threadBuffer);\r
+ threadBuffer = NULL;\r
+\r
+ }\r
+\r
+ // end of recording\r
+ logger->log("PlayerRadio", Log::DEBUG, "Recording playback ends");\r
+\r
+ threadCheckExit();\r
+\r
+\r
+ Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+ m->to = messageReceiver;\r
+ m->from = this;\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->parameter = PlayerRadio::STOP_PLAYBACK;\r
+ logger->log("PlayerRadio", Log::DEBUG, "Posting message to %p...", messageQueue);\r
+ messageQueue->postMessage(m);\r
+}\r
+\r
+void PlayerRadio::threadPostStopCleanup()\r
+{\r
+ if (threadBuffer)\r
+ {\r
+ free(threadBuffer);\r
+ threadBuffer = NULL;\r
+ }\r
+}\r
+\r
-/*
- Copyright 2004-2006 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef PLAYERRADIO_H
-#define PLAYERRADIO_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef WIN32
-#include <sys/time.h>
-#endif
-#include <time.h>
-
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
-#include "callback.h"
-#include "defines.h"
-#include "afeed.h"
-
-class Log;
-class Audio;
-class Video;
-class Demuxer;
-class VDR;
-class MessageQueue;
-
-class PlayerRadio : public Thread_TYPE, public Callback
-{
- public:
- PlayerRadio(MessageQueue* messageQueue, void* messageReceiver);
- virtual ~PlayerRadio();
-
- int init(ULLONG lengthBytes, ULONG lengthPackets, bool IsPesRecording);
- int shutdown();
- void setStartBytes(ULLONG startBytes);
-
- void play();
- void stop();
- void pause();
- void jumpToPercent(double percent);
- void skipForward(UINT seconds);
- void skipBackward(UINT seconds);
-
- UCHAR getState() { return state; }
- ULONG getCurrentSeconds();
- ULONG getLengthSeconds();
-
- void call(void*); // for callback interface
-
- const static UCHAR S_PLAY = 1;
- const static UCHAR S_PAUSE_P = 2;
- const static UCHAR S_STOP = 6;
- const static UCHAR S_JUMP = 7;
-
- // Player events
-
- const static UCHAR CONNECTION_LOST = 1;
- const static UCHAR STOP_PLAYBACK = 2;
- const static UCHAR STREAM_END = 3;
-
- protected:
- void threadMethod();
- void threadPostStopCleanup();
-
- private:
- void switchState(UCHAR newState, ULONG jumpPacket=0);
-
- void threadFeedPlay();
- void threadFeedScan();
-
- void doConnectionLost();
- void restartAtPacket(ULONG newPacket);
- bool setLengthSeconds();
-
- MessageQueue* messageQueue;
- void* messageReceiver;
- Log* logger;
- Audio* audio;
- Demuxer* demuxer;
- VDR* vdr;
- AFeed afeed;
-
- bool initted;
- bool startup;
-
- ULLONG startPTS;
- ULONG lengthSeconds;
-
-#ifndef WIN32
- pthread_mutex_t mutex;
-#else
- HANDLE mutex;
-#endif
- void lock();
- void unLock();
-
- ULLONG lengthBytes;
- ULLONG streamPos;
- ULONG lengthPackets;
- ULONG currentPacketNumber;
- UINT blockSize;
- UINT startupBlockSize;
- UCHAR* threadBuffer;
- UCHAR state;
-};
-
-#endif
-
-
-/*
-
-Possible states:
-
-Play, Pause, FFwd, FBwd, (Stop), [Jump]
-
- Possible Working
-
-Play -> PauseP * *
- -> Stop * *
- -> Jump * *
-
-PauseP -> Play * *
- -> Stop * *
- -> Jump * *
-
-PauseI -> Play * *
- -> PauseP
- -> Stop * *
- -> Jump * *
-
-Stop -> Play * *
- -> PauseP
- -> Jump
-
-Jump -> Play
- -> PauseP
- -> Stop
-
-*/
+/*\r
+ Copyright 2004-2006 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef PLAYERRADIO_H\r
+#define PLAYERRADIO_H\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#ifndef WIN32\r
+#include <sys/time.h>\r
+#endif\r
+#include <time.h>\r
+\r
+#include "threadsystem.h"\r
+\r
+#include "callback.h"\r
+#include "defines.h"\r
+#include "afeed.h"\r
+\r
+class Log;\r
+class Audio;\r
+class Video;\r
+class Demuxer;\r
+class VDR;\r
+class MessageQueue;\r
+\r
+class PlayerRadio : public Thread_TYPE, public Callback\r
+{\r
+ public:\r
+ PlayerRadio(MessageQueue* messageQueue, void* messageReceiver);\r
+ virtual ~PlayerRadio();\r
+\r
+ int init(ULLONG lengthBytes, ULONG lengthPackets, bool IsPesRecording);\r
+ int shutdown();\r
+ void setStartBytes(ULLONG startBytes);\r
+\r
+ void play();\r
+ void stop();\r
+ void pause();\r
+ void playpause();\r
+ void jumpToPercent(double percent);\r
+ void skipForward(UINT seconds);\r
+ void skipBackward(UINT seconds);\r
+\r
+ UCHAR getState() { return state; }\r
+ ULONG getCurrentSeconds();\r
+ ULONG getLengthSeconds();\r
+\r
+ void call(void*); // for callback interface\r
+\r
+ const static UCHAR S_PLAY = 1;\r
+ const static UCHAR S_PAUSE_P = 2;\r
+ const static UCHAR S_STOP = 6;\r
+ const static UCHAR S_JUMP = 7;\r
+\r
+ // Player events\r
+\r
+ const static UCHAR CONNECTION_LOST = 1;\r
+ const static UCHAR STOP_PLAYBACK = 2;\r
+ const static UCHAR STREAM_END = 3;\r
+\r
+ protected:\r
+ void threadMethod();\r
+ void threadPostStopCleanup();\r
+\r
+ private:\r
+ void switchState(UCHAR newState, ULONG jumpPacket=0);\r
+\r
+ void threadFeedPlay();\r
+ void threadFeedScan();\r
+\r
+ void doConnectionLost();\r
+ void restartAtPacket(ULONG newPacket);\r
+ bool setLengthSeconds();\r
+\r
+ MessageQueue* messageQueue;\r
+ void* messageReceiver;\r
+ Log* logger;\r
+ Audio* audio;\r
+ Demuxer* demuxer;\r
+ VDR* vdr;\r
+ AFeed afeed;\r
+\r
+ bool initted;\r
+ bool startup;\r
+\r
+ ULLONG startPTS;\r
+ ULONG lengthSeconds;\r
+\r
+#ifndef WIN32\r
+ pthread_mutex_t mutex;\r
+#else\r
+ HANDLE mutex;\r
+#endif\r
+ void lock();\r
+ void unLock();\r
+\r
+ ULLONG lengthBytes;\r
+ ULLONG streamPos;\r
+ ULONG lengthPackets;\r
+ ULONG currentPacketNumber;\r
+ UINT blockSize;\r
+ UINT startupBlockSize;\r
+ UCHAR* threadBuffer;\r
+ UCHAR state;\r
+};\r
+\r
+#endif\r
+\r
+\r
+/*\r
+\r
+Possible states:\r
+\r
+Play, Pause, FFwd, FBwd, (Stop), [Jump]\r
+\r
+ Possible Working\r
+\r
+Play -> PauseP * *\r
+ -> Stop * *\r
+ -> Jump * *\r
+\r
+PauseP -> Play * *\r
+ -> Stop * *\r
+ -> Jump * *\r
+\r
+PauseI -> Play * *\r
+ -> PauseP\r
+ -> Stop * *\r
+ -> Jump * *\r
+\r
+Stop -> Play * *\r
+ -> PauseP\r
+ -> Jump\r
+\r
+Jump -> Play\r
+ -> PauseP\r
+ -> Stop\r
+\r
+*/\r
#include <winsock2.h>
#include <windows.h>
#define PATH_MAX FILENAME_MAX
+#else
+// added for raspberry pi, should also work on mvp
+#include <linux/limits.h>
+
#endif
#include "directory.h"
Remote* Remote::instance = NULL;
+
+const ULONG Remote::NOLEARNMODE;
+// Not buttons
+const UCHAR Remote::NA_LEARN;
+const UCHAR Remote::NA_NONE;
+const UCHAR Remote::NA_UNKNOWN;
+const UCHAR Remote::NA_SIGNAL;
+const UCHAR Remote::DF_UP;
+const UCHAR Remote::DF_DOWN;
+const UCHAR Remote::DF_LEFT;
+const UCHAR Remote::DF_RIGHT;
+
+// Problem common buttons
+const UCHAR Remote::VOLUMEUP;
+const UCHAR Remote::VOLUMEDOWN;
+const UCHAR Remote::CHANNELUP;
+const UCHAR Remote::CHANNELDOWN;
+
+// Common buttons
+const UCHAR Remote::ZERO;
+const UCHAR Remote::ONE;
+const UCHAR Remote::TWO;
+const UCHAR Remote::THREE;
+const UCHAR Remote::FOUR;
+const UCHAR Remote::FIVE;
+const UCHAR Remote::SIX;
+const UCHAR Remote::SEVEN;
+const UCHAR Remote::EIGHT;
+const UCHAR Remote::NINE;
+const UCHAR Remote::POWER;
+const UCHAR Remote::GO;
+const UCHAR Remote::BACK;
+const UCHAR Remote::MENU;
+const UCHAR Remote::RED;
+const UCHAR Remote::GREEN;
+const UCHAR Remote::YELLOW;
+const UCHAR Remote::BLUE;
+const UCHAR Remote::MUTE;
+const UCHAR Remote::RADIO;
+const UCHAR Remote::REVERSE;
+const UCHAR Remote::PLAY;
+const UCHAR Remote::FORWARD;
+const UCHAR Remote::RECORD;
+const UCHAR Remote::STOP;
+const UCHAR Remote::PAUSE;
+const UCHAR Remote::SKIPBACK;
+const UCHAR Remote::SKIPFORWARD;
+const UCHAR Remote::OK;
+
+// Old remote only
+const UCHAR Remote::FULL;
+
+// New remote only
+const UCHAR Remote::TV;
+const UCHAR Remote::VIDEOS;
+const UCHAR Remote::MUSIC;
+const UCHAR Remote::PICTURES;
+const UCHAR Remote::GUIDE;
+const UCHAR Remote::UP;
+const UCHAR Remote::DOWN;
+const UCHAR Remote::LEFT;
+const UCHAR Remote::RIGHT;
+const UCHAR Remote::PREVCHANNEL;
+const UCHAR Remote::STAR;
+const UCHAR Remote::HASH;
+
+// Android only
+const UCHAR Remote::PLAYPAUSE;
+
+
+// Remote types
+const UCHAR Remote::OLDREMOTE;
+const UCHAR Remote::NEWREMOTE;
+
Remote::Remote()
{
if (instance) return;
RemoteTranslationList::const_iterator it;
for (it = translist.begin(); it != translist.end(); it++)
{
- current+=sprintf(current,"H%08lXI%08lXK%02X",
- (ULONG)it->first ,(ULONG) (it->first >> 32), it->second);
+ current+=snprintf(current,21,"H%08lXI%08lXK%02X",
+ (ULONG)it->first ,(ULONG) (it->first >> 32), it->second);
}
return output;
}
return tr("Star");
case HASH:
return tr("Hash");
+ case PLAYPAUSE:
+ return tr("Play/Pause");
default:
return NULL;
const static UCHAR STAR = 10;
const static UCHAR HASH = 14;
+ // Android only
+ const static UCHAR PLAYPAUSE = 201;
+
+
// Remote types
const static UCHAR OLDREMOTE = 1;
const static UCHAR NEWREMOTE = 2;
-/*
- Copyright 2005-2006 Mark Calderbank
-
- 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 "stream.h"
-#include "log.h"
-
-Stream::Stream()
-{
- initted = 0;
- draintarget = NULL;
- cur_packet_pos = 0;
-}
-
-Stream::~Stream()
-{
- shutdown();
-}
-
-void Stream::shutdown()
-{
- if (initted)
- {
- free(outbuf);
-#ifdef WIN32
- CloseHandle(mutex);
-#endif
-
- }
- initted = 0;
-}
-
-int Stream::init(DrainTarget* tdt, int bufsize)
-{
- outbuf = (UCHAR*) malloc(bufsize);
- if (!outbuf) return 0;
- draintarget = tdt;
- bufferSize = bufsize;
- initted = 1;
-#ifndef WIN32
- pthread_mutex_init(&mutex, NULL);
-#else
- mutex=CreateMutex(NULL,FALSE,NULL);
-#endif
- return 1;
-}
-
-void Stream::flush()
-{
- lock();
-
- mediapackets.clear();
- unLock();
- if (draintarget) draintarget->ResetTimeOffsets();
-}
-
-int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index)
-{
- int ret = 0;
- if (!draintarget) return 0;
- MediaPacket newPacket;
- newPacket.length = len;
- newPacket.pos_buffer = 0;
- newPacket.type = type;
- newPacket.pts=0;
- newPacket.dts=0;
- newPacket.synched=false;
- newPacket.index=index;
-#ifdef WIN32
- newPacket.disconti=false;
- newPacket.presentation_time=0;
-#endif
- if (type!=MPTYPE_MPEG_AUDIO_LAYER3) {//no PES
- //Extract the pts...
- bool hasdts=false;
- if ((inbuf[7] & 0x80) && len>14 ) {
- newPacket.synched=true;
- newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |
- ( (ULLONG)(inbuf[10]) << 22 ) |
- ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |
- ( (ULLONG)(inbuf[12]) << 7 ) |
- ( (ULLONG)(inbuf[13] & 0xFE) >> 1 );
- if ((inbuf[7] & 0x40) && len>19) {
- newPacket.dts=((ULLONG)(inbuf[14] & 0x0E) << 29 ) |
- ( (ULLONG)(inbuf[15]) << 22 ) |
- ( (ULLONG)(inbuf[16] & 0xFE) << 14 ) |
- ( (ULLONG)(inbuf[17]) << 7 ) |
- ( (ULLONG)(inbuf[18] & 0xFE) >> 1 );
- hasdts=true;
- }
-#ifdef WIN32
- //ok we have the pts now convert it to a continously time code in 100ns units
- if (hasdts && draintarget->dtsTimefix()) newPacket.presentation_time=(ULLONG)(newPacket.dts*10000LL/90LL);
- else newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);
-
- //newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);
- newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);
-#endif
- }
- }
-
- lock();
- int front, back;
- if (mediapackets.empty())
- {
- back = 0; front = bufferSize;
- }
- else
- {
- front = mediapackets.front().pos_buffer;
- back = mediapackets.back().pos_buffer + mediapackets.back().length;
- if (back == bufferSize) back = 0;
- }
- unLock();
-
- if (back <= front)
- {
- // The free space (if any) is in one continuous chunk.
- if (len <= front - back) ret = len; // Is there enough of it?
- }
- else if (len <= bufferSize - back)
- {
- // There is enough space at the end of the buffer
- ret = len;
- }
- else if (len <= front)
- {
- // There is enough space at the start of the buffer
- back = 0;
- ret = len;
- }
-
- if (ret) // Nonzero if we managed to find room for the packet
- {
- memcpy(outbuf + back, inbuf, len);
- newPacket.pos_buffer = back;
- lock();
- mediapackets.push_back(newPacket);
- unLock();
- }// else {
- // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize);
- //}
-
- return ret;
-}
-
-bool Stream::drain()
-{
- bool ret = false;
- lock();
- UINT listlength = mediapackets.size();
- if (listlength != 0)
- {
- draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);
- unLock();
- UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);
- lock();
- if (consumed != 0) ret = true;
- if (consumed > listlength) consumed = listlength;
- while (consumed--)
- {
- mediapackets.pop_front();
- }
- }
- unLock();
- return ret;
-}
-
-void Stream::lock()
-{
-#ifndef WIN32
- pthread_mutex_lock(&mutex);
- //logger->log("Player", Log::DEBUG, "LOCKED");
-
-#else
- WaitForSingleObject(mutex, INFINITE );
-#endif
-}
-
-void Stream::unLock()
-{
-#ifndef WIN32
- //logger->log("Player", Log::DEBUG, "UNLOCKING");
- pthread_mutex_unlock(&mutex);
-#else
- ReleaseMutex(mutex);
-#endif
-}
+/*\r
+ Copyright 2005-2006 Mark Calderbank\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "stream.h"\r
+#include "log.h"\r
+\r
+Stream::Stream()\r
+{\r
+ initted = 0;\r
+ draintarget = NULL;\r
+ cur_packet_pos = 0;\r
+}\r
+\r
+Stream::~Stream()\r
+{\r
+ shutdown();\r
+}\r
+\r
+void Stream::shutdown()\r
+{\r
+ if (initted)\r
+ {\r
+ free(outbuf);\r
+#ifdef WIN32\r
+ CloseHandle(mutex);\r
+#endif\r
+ \r
+ }\r
+ initted = 0;\r
+}\r
+\r
+int Stream::init(DrainTarget* tdt, int bufsize)\r
+{\r
+ outbuf = (UCHAR*) malloc(bufsize);\r
+ if (!outbuf) return 0;\r
+ draintarget = tdt;\r
+ bufferSize = bufsize;\r
+ initted = 1;\r
+#ifndef WIN32\r
+ pthread_mutex_init(&mutex, NULL);\r
+#else\r
+ mutex=CreateMutex(NULL,FALSE,NULL);\r
+#endif\r
+ return 1;\r
+}\r
+\r
+void Stream::flush()\r
+{\r
+ lock();\r
+\r
+ mediapackets.clear();\r
+ unLock();\r
+ if (draintarget) draintarget->ResetTimeOffsets();\r
+}\r
+\r
+int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index)\r
+{\r
+ int ret = 0;\r
+ if (!draintarget) return 0;\r
+ MediaPacket newPacket;\r
+ newPacket.length = len;\r
+ newPacket.pos_buffer = 0;\r
+ newPacket.type = type;\r
+ newPacket.pts=0;\r
+ newPacket.dts=0;\r
+ newPacket.synched=false;\r
+ newPacket.index=index;\r
+#if defined(WIN32) || defined(__ANDROID__)\r
+ newPacket.disconti=false;\r
+ newPacket.presentation_time=0;\r
+#endif\r
+ if (type!=MPTYPE_MPEG_AUDIO_LAYER3) {//no PES\r
+ //Extract the pts...\r
+ bool hasdts=false;\r
+ if ((inbuf[7] & 0x80) && len>14 ) {\r
+ newPacket.synched=true;\r
+ newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |\r
+ ( (ULLONG)(inbuf[10]) << 22 ) |\r
+ ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |\r
+ ( (ULLONG)(inbuf[12]) << 7 ) |\r
+ ( (ULLONG)(inbuf[13] & 0xFE) >> 1 );\r
+ if ((inbuf[7] & 0x40) && len>19) {\r
+ newPacket.dts=((ULLONG)(inbuf[14] & 0x0E) << 29 ) |\r
+ ( (ULLONG)(inbuf[15]) << 22 ) |\r
+ ( (ULLONG)(inbuf[16] & 0xFE) << 14 ) |\r
+ ( (ULLONG)(inbuf[17]) << 7 ) |\r
+ ( (ULLONG)(inbuf[18] & 0xFE) >> 1 );\r
+ hasdts=true;\r
+ }\r
+#if defined(WIN32) || defined(__ANDROID__)\r
+ //ok we have the pts now convert it to a continously time code in 100ns units\r
+ if (hasdts && draintarget->dtsTimefix()) newPacket.presentation_time=(ULLONG)(newPacket.dts*10000LL/90LL);\r
+ else newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);\r
+\r
+ //newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);\r
+ newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);\r
+#endif\r
+ }\r
+ }\r
+\r
+ lock();\r
+ int front, back;\r
+ if (mediapackets.empty())\r
+ {\r
+ back = 0; front = bufferSize;\r
+ }\r
+ else\r
+ {\r
+ front = mediapackets.front().pos_buffer;\r
+ back = mediapackets.back().pos_buffer + mediapackets.back().length;\r
+ if (back == bufferSize) back = 0;\r
+ }\r
+ unLock();\r
+\r
+ if (back <= front)\r
+ {\r
+ // The free space (if any) is in one continuous chunk.\r
+ if (len <= front - back) ret = len; // Is there enough of it?\r
+ }\r
+ else if (len <= bufferSize - back)\r
+ {\r
+ // There is enough space at the end of the buffer\r
+ ret = len;\r
+ }\r
+ else if (len <= front)\r
+ {\r
+ // There is enough space at the start of the buffer\r
+ back = 0;\r
+ ret = len;\r
+ }\r
+\r
+ if (ret) // Nonzero if we managed to find room for the packet\r
+ {\r
+ memcpy(outbuf + back, inbuf, len);\r
+ newPacket.pos_buffer = back;\r
+ lock();\r
+ mediapackets.push_back(newPacket);\r
+ unLock();\r
+ } else {\r
+ // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize);\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+bool Stream::drain()\r
+{\r
+ bool ret = false;\r
+ lock();\r
+ UINT listlength = mediapackets.size();\r
+ if (listlength != 0)\r
+ {\r
+ draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);\r
+ unLock();\r
+ UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);\r
+ lock();\r
+ if (consumed != 0) ret = true;\r
+ if (consumed > listlength) consumed = listlength;\r
+ while (consumed--) \r
+ {\r
+ mediapackets.pop_front();\r
+ }\r
+ }\r
+ unLock();\r
+ return ret;\r
+}\r
+\r
+void Stream::lock()\r
+{\r
+#ifndef WIN32\r
+ pthread_mutex_lock(&mutex);\r
+ //logger->log("Player", Log::DEBUG, "LOCKED");\r
+\r
+#else\r
+ WaitForSingleObject(mutex, INFINITE );\r
+#endif\r
+}\r
+\r
+void Stream::unLock()\r
+{\r
+#ifndef WIN32\r
+ //logger->log("Player", Log::DEBUG, "UNLOCKING");\r
+ pthread_mutex_unlock(&mutex);\r
+#else\r
+ ReleaseMutex(mutex);\r
+#endif\r
+}\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "surface.h"
-
-#include "osd.h"
-#include "log.h"
-
-Surface* Surface::screen = NULL;
-osd_font_t* Surface::font = &font_helvB18;
-
-Surface::Surface(int id)
-{
- if (id == SCREEN) screen = this;
-}
-
-Surface::~Surface()
-{
-}
-
-Surface* Surface::getScreen()
-{
- return screen;
-}
-
-int Surface::drawText(const char* text, int x, int y, ULONG rgba)
-{
- return drawText(text, x, y, 2000, rgba);
-}
-
-int Surface::drawText(const char* text, int x, int y, int width, ULONG rgba)
-{
- int h, n, i;
- int Y, X, cx;
-
- n = strlen(text);
- h = font->height;
-
- X = 0;
- cx = 0;
- startFastDraw();
- for (i=0; i<n; i++)
- {
- unsigned char c = text[i];
- unsigned long *character = &font->content[font->offset[c]];
- int w = font->width[c];
- int pixels = 0;
-
- for (X=0; (X<w) && (X + cx < width); X++)
- {
- for (Y=0; Y<h; Y++)
- {
- if ((character[Y] >> (32 - X)) & 0x1)
- {
- drawPixel(x+X+cx, y+Y, rgba,true);
- pixels++;
- }
- }
- }
- cx += w;
- }
- endFastDraw();
- return 1;
-}
-
-int Surface::drawTextRJ(const char* text, int x, int y, ULONG rgba)
-{
- int i, n, w;
- w = 0;
-
- n = strlen(text);
-
- for (i = 0; i < n; i++)
- {
- w += font->width[(unsigned char)text[i]];
- }
-
- x -= w;
-
- if (x < 0) return 0;
- else return drawText(text, x, y, rgba);
-}
-
-int Surface::drawTextCentre(const char* text, int x, int y, ULONG rgba)
-{
- int i, n, w;
- w = 0;
-
- n = strlen(text);
-
- for (i = 0; i < n; i++)
- {
- w += font->width[(unsigned char)text[i]]; //Characters bigger then 128 can appear
- }
-
- x -= w / 2;
-
- if (x < 0) return 0;
- else return drawText(text, x, y, rgba);
-}
-
-int Surface::getCharWidth(char c)
-{
- return font->width[(unsigned char) c];
-}
-
-int Surface::getFontHeight()
-{
- return font->spacing;
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "surface.h"\r
+\r
+#include <math.h>\r
+#include "osd.h"\r
+#include "log.h"\r
+#include "video.h"\r
+\r
+#include "teletxt/txtfont.h"\r
+\r
+unsigned int interpol_table_fac1[16][22];\r
+unsigned int interpol_table_fac2[16][22];\r
+unsigned int interpol_table_fac3[16][22];\r
+unsigned int interpol_table_fac4[16][22];\r
+int interpol_lowbit[16];\r
+int interpol_upbit[16];\r
+int interpol_lowline[22];\r
+int interpol_upline[22];\r
+bool pol_table_inited=false;\r
+\r
+void initpol_tables(){\r
+ int charsizex;\r
+ int charsizey;\r
+ charsizex=16;\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ charsizey=22;\r
+ } else {\r
+ charsizey=18;\r
+ }\r
+ int ttcharsizex=12;\r
+ int ttcharsizey=10;\r
+ for (int py=0;py<charsizey;py++) {\r
+ float fposy=((float)(ttcharsizey))/((float)(charsizey))*((float)py);\r
+ float yweight=fposy-floor(fposy);\r
+ float yinvweight=1.-yweight;\r
+ interpol_upline[py]=min((unsigned int)ceil(fposy),9);\r
+ interpol_lowline[py]=max((unsigned int)floor(fposy),0);\r
+ for (int px=0;px<charsizex;px++) {\r
+ float fposx=((float)(ttcharsizex))/((float)(charsizex))*((float)px);\r
+ float xweight=fposx-floor(fposx);\r
+ float xinvweight=1.-xweight;\r
+ interpol_upbit[px]= (min((unsigned int)ceil(fposx),11));\r
+ interpol_lowbit[px]= (max((unsigned int)floor(fposx),0));\r
+\r
+ interpol_table_fac1[px][py]=xweight*yweight*256.;\r
+ interpol_table_fac2[px][py]=xinvweight*yweight*256.;\r
+ interpol_table_fac3[px][py]=xweight*yinvweight*256.;\r
+ interpol_table_fac4[px][py]=xinvweight*yinvweight*256.;\r
+\r
+ }\r
+ }\r
+}\r
+\r
+\r
+Surface* Surface::screen = NULL;\r
+osd_font_t* Surface::font = &font_helvB18;\r
+\r
+Surface::Surface(int id)\r
+{\r
+ if (id == SCREEN) screen = this;\r
+}\r
+\r
+Surface::~Surface()\r
+{\r
+}\r
+\r
+Surface* Surface::getScreen()\r
+{\r
+ return screen;\r
+}\r
+\r
+int Surface::drawText(const char* text, int x, int y, ULONG rgba)\r
+{\r
+ return drawText(text, x, y, 2000, rgba);\r
+}\r
+\r
+int Surface::drawText(const char* text, int x, int y, int width, ULONG rgba)\r
+{\r
+ int h, n, i;\r
+ int Y, X, cx;\r
+\r
+ n = strlen(text);\r
+ h = font->height;\r
+\r
+ X = 0;\r
+ cx = 0;\r
+ startFastDraw();\r
+ for (i=0; i<n; i++)\r
+ {\r
+ unsigned char c = text[i];\r
+ unsigned long *character = &font->content[font->offset[c]];\r
+ int w = font->width[c];\r
+ int pixels = 0;\r
+\r
+ for (X=0; (X<w) && (X + cx < width); X++)\r
+ {\r
+ for (Y=0; Y<h; Y++)\r
+ {\r
+ if ((character[Y] >> (32 - X)) & 0x1)\r
+ {\r
+ drawPixel(x+X+cx, y+Y, rgba,true);\r
+ pixels++;\r
+ }\r
+ }\r
+ }\r
+ cx += w;\r
+ }\r
+ endFastDraw();\r
+ return 1;\r
+}\r
+\r
+int Surface::drawTextRJ(const char* text, int x, int y, ULONG rgba)\r
+{\r
+ int i, n, w;\r
+ w = 0;\r
+\r
+ n = strlen(text);\r
+\r
+ for (i = 0; i < n; i++)\r
+ {\r
+ w += font->width[(unsigned char)text[i]];\r
+ }\r
+\r
+ x -= w;\r
+\r
+ if (x < 0) return 0;\r
+ else return drawText(text, x, y, rgba);\r
+}\r
+\r
+int Surface::drawTextCentre(const char* text, int x, int y, ULONG rgba)\r
+{\r
+ int i, n, w;\r
+ w = 0;\r
+\r
+ n = strlen(text);\r
+\r
+ for (i = 0; i < n; i++)\r
+ {\r
+ w += font->width[(unsigned char)text[i]]; //Characters bigger then 128 can appear\r
+ }\r
+\r
+ x -= w / 2;\r
+\r
+ if (x < 0) return 0;\r
+ else return drawText(text, x, y, rgba);\r
+}\r
+\r
+int Surface::getCharWidth(char c)\r
+{\r
+ return font->width[(unsigned char) c];\r
+}\r
+\r
+int Surface::getFontHeight()\r
+{\r
+ return font->spacing;\r
+}\r
+\r
+//Moved from Teletext view in order to allow device depend optimizations\r
+\r
+Colour Surface::enumTeletextColorToCoulour(enumTeletextColor ttcol)\r
+{\r
+ switch (ttcol) {\r
+ case ttcBlack:\r
+ return Colour(0,0,0);\r
+ case ttcRed:\r
+ return Colour(255,0,0);\r
+ case ttcGreen:\r
+ return Colour(0,255,0);\r
+ case ttcYellow:\r
+ return Colour(255,255,0);\r
+ case ttcBlue:\r
+ return Colour(0,0,255);\r
+ case ttcMagenta:\r
+ return Colour(255,0,255);\r
+ case ttcCyan:\r
+ return Colour(0,255,255);\r
+ case ttcWhite:\r
+ return Colour(255,255,255);\r
+ case ttcTransparent:\r
+ return Colour(0,0,0,0);\r
+ case ttcHalfRed:\r
+ return Colour(127,0,0);\r
+ case ttcHalfGreen:\r
+ return Colour(0,127,0);\r
+ case ttcHalfYellow:\r
+ return Colour(127,127,0);\r
+ case ttcHalfBlue:\r
+ return Colour(0,0,127);\r
+ case ttcHalfMagenta:\r
+ return Colour(127,0,127);\r
+ case ttcHalfCyan:\r
+ return Colour(0,127,127);\r
+ case ttcGrey:\r
+ return Colour(127,127,127);\r
+ default:\r
+ return Colour(0,0,0);\r
+ };\r
+}\r
+\r
+\r
+\r
+//Next function inspired by osdteletext plugin\r
+void Surface::drawTTChar(int ox, int oy, int x, int y, cTeletextChar c)\r
+{\r
+ if (!pol_table_inited){\r
+ initpol_tables();\r
+ pol_table_inited=true;\r
+ }\r
+ unsigned int buffer [10];\r
+ unsigned int * charmap=GetFontChar(c,buffer);\r
+ if (!charmap) { //invalid char\r
+ memset(&buffer,0,10);\r
+ charmap=buffer;\r
+ }\r
+ enumTeletextColor ttforegcolour=c.GetFGColor();\r
+ enumTeletextColor ttbackgcolour=c.GetBGColor();\r
+ if (c.GetBoxedOut()) {\r
+ ttforegcolour=ttcTransparent;\r
+ ttbackgcolour=ttcTransparent;\r
+ }\r
+ int charsizex;\r
+ int charsizey;\r
+ charsizex=16;\r
+\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ charsizey=22;\r
+ } else {\r
+ charsizey=18;\r
+ }\r
+ int ttcharsizex=12;\r
+ int ttcharsizey=10;\r
+ int screenposx=charsizex*x+ox; //12*40= 480 250\r
+ int screenposy=y*charsizey+oy;\r
+\r
+\r
+ // Log::getInstance()->log("Surface", Log::ERR, "TTpos %d %d %d %d %d %d",x,y,ox,oy,screenposx,screenposy);\r
+ Colour fgcharcl=enumTeletextColorToCoulour(ttforegcolour);\r
+ Colour bgcharcl=enumTeletextColorToCoulour(ttbackgcolour);\r
+\r
+ startFastDraw();\r
+ for (int py=0;py<charsizey;py++) {\r
+ int upperbitline=charmap[interpol_upline[py]];\r
+ int lowerbitline=charmap[interpol_lowline[py]];\r
+ for (int px=0;px<charsizex;px++) {\r
+ int upperbit= interpol_upbit[px];\r
+ int lowerbit= interpol_lowbit[px];\r
+ Colour uuc=( upperbitline &(0x8000>>upperbit)) ? fgcharcl: bgcharcl;\r
+ Colour ulc=( upperbitline &(0x8000>>lowerbit)) ? fgcharcl: bgcharcl;\r
+ Colour luc=( lowerbitline &(0x8000>>upperbit)) ? fgcharcl: bgcharcl;\r
+ Colour llc=( lowerbitline &(0x8000>>lowerbit)) ? fgcharcl: bgcharcl;\r
+ unsigned int fac1,fac2,fac3,fac4;\r
+ fac1=interpol_table_fac1[px][py];\r
+ fac2=interpol_table_fac2[px][py];\r
+ fac3=interpol_table_fac3[px][py];\r
+ fac4=interpol_table_fac4[px][py];\r
+\r
+ Colour res((uuc.red*fac1+ulc.red*fac2+luc.red*fac3+llc.red*fac4)/256,\r
+ (uuc.green*fac1+ulc.green*fac2+luc.green*fac3+llc.green*fac4)/256,\r
+ (uuc.blue*fac1+ulc.blue*fac2+luc.blue*fac3+llc.blue*fac4)/256,\r
+ (uuc.alpha*fac1+ulc.alpha*fac2+luc.alpha*fac3+llc.alpha*fac4)/256); //if this is too slow make a table\r
+ int c = ( (res.alpha << 24 )\r
+ | (res.red << 16)\r
+ | (res.green << 8)\r
+ | (res.blue ) );\r
+ drawPixel(screenposx+px,screenposy+py,c, true);\r
+ }\r
+ }\r
+\r
+\r
+ endFastDraw();\r
+\r
+\r
+}\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef SURFACE_H
-#define SURFACE_H
-
-#include <stdio.h>
-#include "defines.h"
-#include "colour.h"
-
-// Font stuff
-
-typedef struct bogl_font {
- char *name; /* Font name. */
- int height; /* Height in pixels. */
- int spacing; /* Vertical spacing in pixels. */
- unsigned long *content; /* 32-bit right-padded bitmap array. */
- short *offset; /* 256 offsets into content. */
- unsigned char *width; /* 256 character widths. */
-} osd_font_t;
-
-extern osd_font_t font_CaslonRoman_1_25;
-extern osd_font_t font_helvB24;
-extern osd_font_t font_helvB18;
-
-class Bitmap;
-
-class Surface
-{
- public:
- Surface(int id = 0);
- virtual ~Surface();
-
- static Surface* getScreen();
- static int getFontHeight();
- int getCharWidth(char c);
-
- int drawText(const char* text, int x, int y, ULONG rgba);
- int drawText(const char* text, int x, int y, int width, ULONG rgba);
- int drawTextRJ(const char* text, int x, int y, ULONG rgba);
- int drawTextCentre(const char* text, int x, int y, ULONG rgba);
-
- virtual int create(UINT width, UINT height)=0;
- virtual void display()=0;
-
- virtual int fillblt(int x, int y, int width, int height, unsigned int c)=0;
- virtual void drawPixel(int x, int y, unsigned int c, bool fastdraw=false)=0;
- virtual void drawPixel(int x, int y, Colour& c, bool fastdraw=false)=0; virtual void drawHorzLine(int x1, int x2, int y, unsigned int c)=0;
- virtual void drawVertLine(int x, int y1, int y2, unsigned int c)=0;
- virtual void drawBitmap(int x, int y, const Bitmap& bm)=0;
- virtual int updateToScreen(int sx, int sy, int w, int h, int dx, int dy)=0;
- virtual void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)=0;
- virtual void screenShot(char* fileName)=0;
-
- /* This is for system which need a locking of the drawing surface to speed up drawing */
- virtual void startFastDraw() {};
- virtual void endFastDraw() {};
-
-
- virtual int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)=0;
-
- const static int SCREEN = 1;
- const static int BUFFER = 2;
-
- protected:
- static Surface* screen;
- static osd_font_t* font;
-};
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef SURFACE_H\r
+#define SURFACE_H\r
+\r
+#include <stdio.h>\r
+#include "defines.h"\r
+#include "colour.h"\r
+\r
+#include "teletextdecodervbiebu.h"\r
+\r
+// Font stuff\r
+\r
+typedef struct bogl_font {\r
+ char *name; /* Font name. */\r
+ int height; /* Height in pixels. */\r
+ int spacing; /* Vertical spacing in pixels. */\r
+ unsigned long *content; /* 32-bit right-padded bitmap array. */\r
+ short *offset; /* 256 offsets into content. */\r
+ unsigned char *width; /* 256 character widths. */\r
+} osd_font_t;\r
+\r
+//extern osd_font_t font_CaslonRoman_1_25;\r
+//extern osd_font_t font_helvB24;\r
+extern osd_font_t font_helvB18;\r
+\r
+class Bitmap;\r
+\r
+\r
+\r
+class Surface\r
+{\r
+ public:\r
+ Surface(int id = 0);\r
+ virtual ~Surface();\r
+\r
+ static Surface* getScreen();\r
+ virtual int getFontHeight();\r
+ virtual int getCharWidth(char c);\r
+\r
+ virtual int drawText(const char* text, int x, int y, ULONG rgba);\r
+ virtual int drawText(const char* text, int x, int y, int width, ULONG rgba);\r
+ virtual int drawTextRJ(const char* text, int x, int y, ULONG rgba);\r
+ virtual int drawTextCentre(const char* text, int x, int y, ULONG rgba);\r
+\r
+ virtual void drawJpeg(const char *fileName,int x, int y,int *width, int *height) {}\r
+\r
+ virtual int create(UINT width, UINT height)=0;\r
+ virtual void display()=0;\r
+\r
+ virtual int fillblt(int x, int y, int width, int height, unsigned int c)=0;\r
+ virtual void drawPixel(int x, int y, unsigned int c, bool fastdraw=false)=0;\r
+ virtual void drawPixel(int x, int y, Colour& c, bool fastdraw=false)=0;\r
+ virtual void drawHorzLine(int x1, int x2, int y, unsigned int c)=0;\r
+ virtual void drawVertLine(int x, int y1, int y2, unsigned int c)=0;\r
+ virtual void drawBitmap(int x, int y, const Bitmap& bm)=0;\r
+ virtual int updateToScreen(int sx, int sy, int w, int h, int dx, int dy)=0;\r
+ virtual void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)=0;\r
+ virtual void screenShot(const char* fileName)=0;\r
+\r
+ /* This is for system which need a locking of the drawing surface to speed up drawing */\r
+ virtual void startFastDraw() {};\r
+ virtual void endFastDraw() {};\r
+\r
+\r
+ virtual void drawTTChar(int ox, int oy,int x, int y, cTeletextChar c);\r
+\r
+\r
+ \r
+\r
+ // virtual int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)=0;\r
+\r
+ const static int SCREEN = 1;\r
+ const static int BUFFER = 2;\r
+\r
+ protected:\r
+ static Surface* screen;\r
+ static osd_font_t* font;\r
+ Colour enumTeletextColorToCoulour(enumTeletextColor ttcol);\r
+\r
+};\r
+\r
+#endif\r
-/*
- Copyright 2004-2005 Chris Tallon, 2009 Marten Richter
- Portions copyright 2008 Jon Gettler
-
- 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 "surfacedirectfb.h"
-
-#include "osd.h"
-#include "bitmap.h"
-#include "log.h"
-
-#include "osddirectfb.h"
-
-
-
-SurfaceDirectFB::SurfaceDirectFB(int id)
-: Surface(id)
-{
- surface=NULL;
-}
-
-SurfaceDirectFB::~SurfaceDirectFB()
-{
- if (surface) surface->Release(surface);
-
-}
-
-int SurfaceDirectFB::create(UINT width, UINT height)
-{
- int counter=0;
- while (!Osd::getInstance()->isInitted() && counter<2000) {
- MILLISLEEP(50); //Wait for Grafiksystem initialization
- counter++;
- }
- if (!Osd::getInstance()->isInitted()) return -1;
-
- IDirectFB*dfb=((OsdDirectFB*)Osd::getInstance())->getDfb();
-printf("ich bin doof");fflush(stdout);
- if (screen == this)
- {
- IDirectFBDisplayLayer *osd_layer=((OsdDirectFB*)Osd::getInstance())->getOsdLayer();
- if (osd_layer->GetSurface(osd_layer,&surface)!=DFB_OK)
- {
-
- return 0;
- }
- surface->Clear(surface,0x0,0x0,0x0,0xFF);
- } else {
- DFBSurfaceDescription dsc;
- memset(&dsc,0,sizeof(dsc));
- *((int*)&dsc.flags)=DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT;
-
- dsc.width=width;
- dsc.height=height;
- dsc.caps= DSCAPS_NONE;
- if (dfb->CreateSurface(dfb,&dsc,&surface)!=DFB_OK)
- {
- return 0;
- }
- }
- return 1;
-}
-
-void SurfaceDirectFB::display()
-{
-// unsigned long fb_descriptor[2];
-/*
- fb_descriptor[0] = surface.sfc.handle;
- fb_descriptor[1] = 1;
-*/
-// ioctl(fdOsd, GFX_FB_ATTACH, fb_descriptor);
-}
-
-
-// ----------------------------------------------------------------------------
-
-// Now for the drawing functions
-
-
-int SurfaceDirectFB::fillblt(int x, int y, int width, int height, unsigned int c)
-{
- int sw,sh;
- unsigned char r,g,b,a;
- int nx,ny,nw,nh;
- nx=x;
- ny=y;
- nw=width;
- nh=height;
- surface->GetSize(surface,&sw,&sh);
-
- if (nx >sw) nx=sw-1;
- if (ny >sh) ny=sh-1;
-
- if ((nx+nw) >= sw) nw=sw-nx;
- if ((ny+nh) >= sh) nh=sh-ny;
-
- if ((nx<0) || (ny < 0) || (nh <=0) || (nw <=0)) {
- return 0;
- }
-
- a= (c &0xff000000)>>24;
- r= (c &0x00ff0000)>>16;
- g= (c &0x0000ff00)>>8;
- b= (c &0x000000ff);
-
-
- surface->SetColor(surface,r,g,b,a);
- surface->FillRectangle(surface,nx,ny,nw,nh);
- return 0;
-}
-
-void SurfaceDirectFB::drawPixel(int x, int y, unsigned int c, bool fastdraw)
-{
- int sw,sh;
- unsigned char r,g,b,a;
- char *dst=NULL;
- int offset=0;
- int pitch;
- surface->GetSize(surface,&sw,&sh);
- if (x>=sw) return;
- if (y>=sh) return;
-
-
-
- a= (c &0xff000000)>>24;
- r= (c &0x00ff0000)>>16;
- g= (c &0x0000ff00)>>8;
- b= (c &0x000000ff);
-
- //TODO Fastdraw
- if (surface->Lock(surface,DSLF_WRITE,(void**)(void*)&dst,&pitch) == DFB_OK) {
- offset= y* pitch+x*4;
- dst[offset++]=b;
- dst[offset++]=g;
- dst[offset++]=r;
- dst[offset]=a;
- surface->Unlock(surface);
- }
-
-}
-
-void SurfaceDirectFB::drawPixel(int x, int y, Colour& c, bool fastdraw)
-{
- int sw,sh;
- char *dst=NULL;
- int offset=0;
- int pitch;
- surface->GetSize(surface,&sw,&sh);
- if (x>=sw) return;
- if (y>=sh) return;
-
- //TODO Fastdraw
- if (surface->Lock(surface,DSLF_WRITE,(void**)(void*)&dst,&pitch) == DFB_OK) {
- offset= y* pitch+x*4;
- dst[offset++]=c.blue;
- dst[offset++]=c.green;
- dst[offset++]=c.red;
- dst[offset]=c.alpha;
- surface->Unlock(surface);
- }
-
-}
-
-void SurfaceDirectFB::drawHorzLine(int x1, int x2, int y, unsigned int c)
-{
- fillblt(x1, y, x2-x1, 1, c);
-}
-
-void SurfaceDirectFB::drawVertLine(int x, int y1, int y2, unsigned int c)
-{
- fillblt(x, y1, 1, y2-y1, c);
-}
-
-void SurfaceDirectFB::drawBitmap(int x, int y, const Bitmap& bm)
-{/*
- UINT bmw = bm.getWidth(); UINT bmh = bm.getHeight();
- if (bmw == 0 || bmh == 0) return;
- if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height)) return;
- int remainder = (surface.sfc.width % 4);
- UINT line;
- if (remainder == 0)
- line = surface.sfc.width;
- else
- line = surface.sfc.width + (4 - remainder);
- const std::vector<UCHAR>& bmdata = bm.rawData();
- const std::vector<UCHAR>& Y = bm.palette.getYVector();
- const std::vector<UCHAR>& Cr = bm.palette.getCrVector();
- const std::vector<UCHAR>& Cb = bm.palette.getCbVector();
- const std::vector<UCHAR>& A = bm.palette.getAVector();
- UINT b_offset = 0;
- UINT s_offset = x + y*line;
- UINT plotWidth = bmw;
- UINT plotHeight = bmh;
- if (x + plotWidth - 1 > surface.sfc.width)
- plotWidth = surface.sfc.width - x + 1;
- if (y + plotHeight - 1 > surface.sfc.height)
- plotHeight = surface.sfc.height - y + 1;
- for (UINT j = 0; j < plotHeight; ++j)
- {
- UINT i = 0;
- if (x & 1) // odd x - need to plot first column separately
- {
- UCHAR index = bmdata[b_offset];
- *(surface.base[0] + s_offset) = Y[index];
- *(surface.base[1] + s_offset - 1) = Cb[index];
- *(surface.base[1] + s_offset) = Cr[index];
- *(surface.base[2] + s_offset) = A[index];
- i = 1;
- }
- // Now, plot pairs of pixels with averaged chroma values
- while (i < plotWidth - 1)
- {
- UCHAR index1 = bmdata[b_offset + i];
- UCHAR index2 = bmdata[b_offset + i + 1];
- *(surface.base[0] + s_offset + i) = Y[index1];
- *(surface.base[0] + s_offset + i + 1) = Y[index2];
- *(surface.base[1] + s_offset + i) = (Cb[index1] + Cb[index2]) / 2;
- *(surface.base[1] + s_offset + i + 1) = (Cr[index1] + Cr[index2]) / 2;
- *(surface.base[2] + s_offset + i) = A[index1];
- *(surface.base[2] + s_offset + i + 1) = A[index2];
- i += 2;
- }
- if (i == plotWidth - 1) // One column left to do
- {
- UCHAR index = bmdata[b_offset + i];
- *(surface.base[0] + s_offset + i) = Y[index];
- *(surface.base[1] + s_offset + i) = Cb[index];
- *(surface.base[1] + s_offset + i + 1) = Cr[index];
- *(surface.base[2] + s_offset + i) = A[index];
- }
- s_offset += line;
- b_offset += bmw;
- }*/
-}
-
- /* surface update to screen needs:
- source x distance into this surface
- source y distance into this surface
- width of update
- height of update
- destination x on screen
- destination y on screen
- */
-int SurfaceDirectFB::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME
-{
- IDirectFBSurface* screensurf=((SurfaceDirectFB*)screen)->getSurfaceDFB();
- if (!screensurf) return 0;
- if (this==screen) return 0;
-
- DFBRectangle rect;
- int sw,sh;
-
- screensurf->GetSize(screensurf,&sw,&sh);
-// screensurf->Clear(screensurf,0x0,0x0,0x0,0xFF);
- rect.x = sx;
- rect.y=sy;
- rect.w=w;
- rect.h=h;
-
- DFBRectangle drect; //TODO make osd HD
- drect.x=dx*sw/720;
- drect.y=dy*sh/576;
- drect.w=w*sw/720;
- drect.h=h*sh/576;
-
-// screensurf->Blit(screensurf,surface,&rect,dx,dy);
- screensurf->StretchBlit(screensurf,surface,&rect,&drect);
-
- return 0;//blt(fdOsd, surface.sfc.handle, sx, sy, w, h, ((SurfaceDirectFB*)screen)->getSurfaceHandle(), dx, dy);
-}
-
-int SurfaceDirectFB::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)
-{//Skip it, noone uses this!
-
- return 0;
-}
-
-void SurfaceDirectFB::screenShot(char* fileName)
-{
- return;
-
-}
-
-void SurfaceDirectFB::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)
-{
-
-}
-
+/*\r
+ Copyright 2004-2005 Chris Tallon, 2009 Marten Richter\r
+ Portions copyright 2008 Jon Gettler\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "surfacedirectfb.h"\r
+\r
+#include "osd.h"\r
+#include "bitmap.h"\r
+#include "log.h"\r
+\r
+#include "osddirectfb.h"\r
+\r
+\r
+\r
+SurfaceDirectFB::SurfaceDirectFB(int id)\r
+: Surface(id)\r
+{\r
+ surface=NULL;\r
+}\r
+\r
+SurfaceDirectFB::~SurfaceDirectFB()\r
+{\r
+ if (surface) surface->Release(surface);\r
+\r
+}\r
+\r
+int SurfaceDirectFB::create(UINT width, UINT height)\r
+{\r
+ int counter=0;\r
+ while (!Osd::getInstance()->isInitted() && counter<2000) {\r
+ MILLISLEEP(50); //Wait for Grafiksystem initialization\r
+ counter++;\r
+ }\r
+ if (!Osd::getInstance()->isInitted()) return -1;\r
+ \r
+ IDirectFB*dfb=((OsdDirectFB*)Osd::getInstance())->getDfb();\r
+printf("ich bin doof");fflush(stdout); \r
+ if (screen == this) \r
+ {\r
+ IDirectFBDisplayLayer *osd_layer=((OsdDirectFB*)Osd::getInstance())->getOsdLayer();\r
+ if (osd_layer->GetSurface(osd_layer,&surface)!=DFB_OK) \r
+ {\r
+\r
+ return 0;\r
+ }\r
+ surface->Clear(surface,0x0,0x0,0x0,0xFF);\r
+ } else {\r
+ DFBSurfaceDescription dsc;\r
+ memset(&dsc,0,sizeof(dsc));\r
+ *((int*)&dsc.flags)=DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT;\r
+ \r
+ dsc.width=width;\r
+ dsc.height=height;\r
+ dsc.caps= DSCAPS_NONE;\r
+ if (dfb->CreateSurface(dfb,&dsc,&surface)!=DFB_OK) \r
+ {\r
+ return 0;\r
+ }\r
+ }\r
+ return 1;\r
+}\r
+\r
+void SurfaceDirectFB::display()\r
+{\r
+// unsigned long fb_descriptor[2];\r
+/*\r
+ fb_descriptor[0] = surface.sfc.handle;\r
+ fb_descriptor[1] = 1;\r
+*/\r
+// ioctl(fdOsd, GFX_FB_ATTACH, fb_descriptor);\r
+}\r
+\r
+\r
+// ----------------------------------------------------------------------------\r
+\r
+// Now for the drawing functions\r
+\r
+\r
+int SurfaceDirectFB::fillblt(int x, int y, int width, int height, unsigned int c)\r
+{\r
+ int sw,sh;\r
+ unsigned char r,g,b,a;\r
+ int nx,ny,nw,nh;\r
+ nx=x;\r
+ ny=y;\r
+ nw=width;\r
+ nh=height;\r
+ surface->GetSize(surface,&sw,&sh);\r
+ \r
+ if (nx >sw) nx=sw-1;\r
+ if (ny >sh) ny=sh-1;\r
+ \r
+ if ((nx+nw) >= sw) nw=sw-nx; \r
+ if ((ny+nh) >= sh) nh=sh-ny; \r
+\r
+ if ((nx<0) || (ny < 0) || (nh <=0) || (nw <=0)) {\r
+ return 0;\r
+ }\r
+ \r
+ a= (c &0xff000000)>>24;\r
+ r= (c &0x00ff0000)>>16;\r
+ g= (c &0x0000ff00)>>8;\r
+ b= (c &0x000000ff);\r
+ \r
+ \r
+ surface->SetColor(surface,r,g,b,a);\r
+ surface->FillRectangle(surface,nx,ny,nw,nh);\r
+ return 0;\r
+}\r
+\r
+void SurfaceDirectFB::drawPixel(int x, int y, unsigned int c, bool fastdraw)\r
+{\r
+ int sw,sh;\r
+ unsigned char r,g,b,a;\r
+ char *dst=NULL;\r
+ int offset=0;\r
+ int pitch;\r
+ surface->GetSize(surface,&sw,&sh);\r
+ if (x>=sw) return;\r
+ if (y>=sh) return;\r
+ \r
+\r
+ \r
+ a= (c &0xff000000)>>24;\r
+ r= (c &0x00ff0000)>>16;\r
+ g= (c &0x0000ff00)>>8;\r
+ b= (c &0x000000ff);\r
+\r
+ //TODO Fastdraw\r
+ if (surface->Lock(surface,DSLF_WRITE,(void**)(void*)&dst,&pitch) == DFB_OK) {\r
+ offset= y* pitch+x*4;\r
+ dst[offset++]=b;\r
+ dst[offset++]=g;\r
+ dst[offset++]=r;\r
+ dst[offset]=a;\r
+ surface->Unlock(surface);\r
+ }\r
+\r
+}\r
+\r
+void SurfaceDirectFB::drawPixel(int x, int y, Colour& c, bool fastdraw)\r
+{\r
+ int sw,sh;\r
+ char *dst=NULL;\r
+ int offset=0;\r
+ int pitch;\r
+ surface->GetSize(surface,&sw,&sh);\r
+ if (x>=sw) return;\r
+ if (y>=sh) return;\r
+ \r
+ //TODO Fastdraw\r
+ if (surface->Lock(surface,DSLF_WRITE,(void**)(void*)&dst,&pitch) == DFB_OK) {\r
+ offset= y* pitch+x*4;\r
+ dst[offset++]=c.blue;\r
+ dst[offset++]=c.green;\r
+ dst[offset++]=c.red;\r
+ dst[offset]=c.alpha;\r
+ surface->Unlock(surface);\r
+ }\r
+\r
+}\r
+ \r
+void SurfaceDirectFB::drawHorzLine(int x1, int x2, int y, unsigned int c)\r
+{\r
+ fillblt(x1, y, x2-x1, 1, c);\r
+}\r
+\r
+void SurfaceDirectFB::drawVertLine(int x, int y1, int y2, unsigned int c)\r
+{\r
+ fillblt(x, y1, 1, y2-y1, c);\r
+}\r
+\r
+void SurfaceDirectFB::drawBitmap(int x, int y, const Bitmap& bm)\r
+{/*\r
+ UINT bmw = bm.getWidth(); UINT bmh = bm.getHeight();\r
+ if (bmw == 0 || bmh == 0) return;\r
+ if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height)) return;\r
+ int remainder = (surface.sfc.width % 4);\r
+ UINT line;\r
+ if (remainder == 0)\r
+ line = surface.sfc.width;\r
+ else\r
+ line = surface.sfc.width + (4 - remainder);\r
+ const std::vector<UCHAR>& bmdata = bm.rawData();\r
+ const std::vector<UCHAR>& Y = bm.palette.getYVector();\r
+ const std::vector<UCHAR>& Cr = bm.palette.getCrVector();\r
+ const std::vector<UCHAR>& Cb = bm.palette.getCbVector();\r
+ const std::vector<UCHAR>& A = bm.palette.getAVector();\r
+ UINT b_offset = 0;\r
+ UINT s_offset = x + y*line;\r
+ UINT plotWidth = bmw;\r
+ UINT plotHeight = bmh;\r
+ if (x + plotWidth - 1 > surface.sfc.width)\r
+ plotWidth = surface.sfc.width - x + 1;\r
+ if (y + plotHeight - 1 > surface.sfc.height)\r
+ plotHeight = surface.sfc.height - y + 1;\r
+ for (UINT j = 0; j < plotHeight; ++j)\r
+ {\r
+ UINT i = 0;\r
+ if (x & 1) // odd x - need to plot first column separately\r
+ {\r
+ UCHAR index = bmdata[b_offset];\r
+ *(surface.base[0] + s_offset) = Y[index];\r
+ *(surface.base[1] + s_offset - 1) = Cb[index];\r
+ *(surface.base[1] + s_offset) = Cr[index];\r
+ *(surface.base[2] + s_offset) = A[index];\r
+ i = 1;\r
+ }\r
+ // Now, plot pairs of pixels with averaged chroma values\r
+ while (i < plotWidth - 1)\r
+ {\r
+ UCHAR index1 = bmdata[b_offset + i];\r
+ UCHAR index2 = bmdata[b_offset + i + 1];\r
+ *(surface.base[0] + s_offset + i) = Y[index1];\r
+ *(surface.base[0] + s_offset + i + 1) = Y[index2];\r
+ *(surface.base[1] + s_offset + i) = (Cb[index1] + Cb[index2]) / 2;\r
+ *(surface.base[1] + s_offset + i + 1) = (Cr[index1] + Cr[index2]) / 2;\r
+ *(surface.base[2] + s_offset + i) = A[index1];\r
+ *(surface.base[2] + s_offset + i + 1) = A[index2];\r
+ i += 2;\r
+ }\r
+ if (i == plotWidth - 1) // One column left to do\r
+ {\r
+ UCHAR index = bmdata[b_offset + i];\r
+ *(surface.base[0] + s_offset + i) = Y[index];\r
+ *(surface.base[1] + s_offset + i) = Cb[index];\r
+ *(surface.base[1] + s_offset + i + 1) = Cr[index];\r
+ *(surface.base[2] + s_offset + i) = A[index];\r
+ }\r
+ s_offset += line;\r
+ b_offset += bmw;\r
+ }*/\r
+}\r
+\r
+ /* surface update to screen needs:\r
+ source x distance into this surface\r
+ source y distance into this surface\r
+ width of update\r
+ height of update\r
+ destination x on screen\r
+ destination y on screen\r
+ */\r
+int SurfaceDirectFB::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME\r
+{\r
+ IDirectFBSurface* screensurf=((SurfaceDirectFB*)screen)->getSurfaceDFB();\r
+ if (!screensurf) return 0;\r
+ if (this==screen) return 0;\r
+ \r
+ DFBRectangle rect;\r
+ int sw,sh;\r
+ \r
+ screensurf->GetSize(screensurf,&sw,&sh);\r
+// screensurf->Clear(screensurf,0x0,0x0,0x0,0xFF);\r
+ rect.x = sx;\r
+ rect.y=sy;\r
+ rect.w=w;\r
+ rect.h=h;\r
+ \r
+ DFBRectangle drect; //TODO make osd HD\r
+ drect.x=dx*sw/720;\r
+ drect.y=dy*sh/576;\r
+ drect.w=w*sw/720;\r
+ drect.h=h*sh/576;\r
+ \r
+// screensurf->Blit(screensurf,surface,&rect,dx,dy);\r
+ screensurf->StretchBlit(screensurf,surface,&rect,&drect);\r
+ \r
+ return 0;//blt(fdOsd, surface.sfc.handle, sx, sy, w, h, ((SurfaceDirectFB*)screen)->getSurfaceHandle(), dx, dy);\r
+}\r
+\r
+int SurfaceDirectFB::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)\r
+{//Skip it, noone uses this!\r
+\r
+ return 0;\r
+}\r
+\r
+void SurfaceDirectFB::screenShot(const char* fileName)\r
+{\r
+ return;\r
+ \r
+}\r
+\r
+void SurfaceDirectFB::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)\r
+{\r
+ \r
+}\r
+\r
-/*
- Copyright 2004-2005 Chris Tallon, 2009 Marten Richter
- Portions copyright 2004 Jon Gettler
-
- 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 SURFACEDirectFB_H
-#define SURFACEDirectFB_H
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-
-extern "C"
-{
- #include <jpeglib.h>
-}
-
-#include "defines.h"
-#include "surface.h"
-
-#include <directfb.h>
-
-
-
-class SurfaceDirectFB : public Surface
-{
- public:
- SurfaceDirectFB(int id = 0);
- ~SurfaceDirectFB();
-
- int create(UINT width, UINT height);
- void display();
-
- int fillblt(int x, int y, int width, int height, unsigned int rgba);
- void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);
- void drawPixel(int x, int y, Colour& c, bool fastdraw=false);
- void drawHorzLine(int x1, int x2, int y, unsigned int c);
- void drawVertLine(int x, int y1, int y2, unsigned int c);
- void drawBitmap(int x, int y, const Bitmap& bm);
- int updateToScreen(int sx, int sy, int w, int h, int dx, int dy);
- void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b);
- void screenShot(char* fileName);
- IDirectFBSurface* getSurfaceDFB(){return surface;};
-
-
- int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy);
-
- private:
- IDirectFBSurface *surface;
-
-
-
-};
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon, 2009 Marten Richter\r
+ Portions copyright 2004 Jon Gettler\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef SURFACEDirectFB_H\r
+#define SURFACEDirectFB_H\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+#include <sys/mman.h>\r
+#include <sys/ioctl.h>\r
+\r
+extern "C"\r
+{\r
+ #include <jpeglib.h>\r
+}\r
+\r
+#include "defines.h"\r
+#include "surface.h"\r
+\r
+#include <directfb.h>\r
+\r
+\r
+\r
+class SurfaceDirectFB : public Surface\r
+{\r
+ public:\r
+ SurfaceDirectFB(int id = 0);\r
+ ~SurfaceDirectFB();\r
+\r
+ int create(UINT width, UINT height);\r
+ void display();\r
+\r
+ int fillblt(int x, int y, int width, int height, unsigned int rgba);\r
+ void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);\r
+ void drawPixel(int x, int y, Colour& c, bool fastdraw=false);\r
+ void drawHorzLine(int x1, int x2, int y, unsigned int c);\r
+ void drawVertLine(int x, int y1, int y2, unsigned int c);\r
+ void drawBitmap(int x, int y, const Bitmap& bm);\r
+ int updateToScreen(int sx, int sy, int w, int h, int dx, int dy);\r
+ void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b);\r
+ void screenShot(const char* fileName);\r
+ IDirectFBSurface* getSurfaceDFB(){return surface;};\r
+\r
+\r
+ int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy);\r
+\r
+ private:\r
+ IDirectFBSurface *surface;\r
+\r
+\r
+\r
+};\r
+\r
+#endif\r
-/*
- Copyright 2006 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 "surfacewin.h"
-#include "osdwin.h"
-#include "bitmap.h"
-#include "log.h"
-
-SurfaceWin::SurfaceWin(int id)
-: Surface(id)
-{
- d3dtexture=NULL;
- d3dsurface=NULL;
- sheight=swidth=0;
-// fastdraw=false;
- event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);
-}
-
-SurfaceWin::~SurfaceWin()
-{
- if (d3dsurface) d3dsurface->Release();
- if (d3dtexture) d3dtexture->Release();
- CloseHandle(event);
-}
-
-int SurfaceWin::create(UINT width, UINT height)
-{
- OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-
-
- LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();
-
- while (true) {
- if (screen==this) {
- osd->BeginPainting();
- if (d3ddev->CreateTexture(1024,1024,0,0,D3DFMT_A8R8G8B8,
- // Does every adapter with alpha blending support this?
- D3DPOOL_DEFAULT,&d3dtexture ,NULL)!=D3D_OK) {
- osd->EndPainting();
- MILLISLEEP(50);//wait maybe next time it will work
- continue;
- }
- if (d3dtexture->GetSurfaceLevel(0,&d3dsurface)!=D3D_OK) {
- d3dtexture->Release();
- d3dtexture=NULL;
- MILLISLEEP(50);
- osd->EndPainting();
- continue;
- }
- } else {
- HRESULT hres;
- if (hres=d3ddev->CreateOffscreenPlainSurface(width,height,D3DFMT_A8R8G8B8,
- D3DPOOL_SYSTEMMEM,&d3dsurface,NULL)!=D3D_OK) {
- osd->EndPainting();
- MILLISLEEP(50);//wait maybe next time it will work
-
- continue;
- }
-
- }
- osd->EndPainting();
-
- sheight=height;
- swidth=width;
- /* If someone does high performance Animations on the OSD, we have to change the types
- of surface in order to address these performance issues, if we have only very few updates
- per second this would be fast enough !*/
- break;
- }
- SetEvent(event);
- return 1;
-}
-
-void SurfaceWin::display()
-{
-}
-
-int SurfaceWin::fillblt(int x, int y, int width, int height, unsigned int c)
-{
- WaitForSingleObject(event,INFINITE); //since this might be called before surface
- //allocation we will wait in this case, hopefully without deadlocks
- OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-
- if (!d3dsurface) {
- return 0; //why does this happen
- }
-
- LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();
-
- if (screen==this) {
- //This should not happen!
- return 0;
-
- } else {
- osd->BeginPainting();
- D3DLOCKED_RECT lockrect;
- int cx,cy,cwidth,cheight;
- cx=min(max(x,0),swidth-1);
- cy=min(max(y,0),sheight-1);
- cwidth=min(width,swidth-x);
- cheight=min(height,sheight-y);
- RECT rect={cx,cy,cwidth,cheight};
-
- if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {
- return 0;
- }
- unsigned int line;
- unsigned int column;
- for (line=0;line<cheight;line++) {
- unsigned int*row=((unsigned int*)(((char*)lockrect.pBits)+lockrect.Pitch*line));
- for (column=0;column<cwidth;column++) {
- row[column]=c;
- }
- }
-
- if (d3dsurface->UnlockRect()!=D3D_OK) {
- osd->EndPainting();
- return 0;
- }
- osd->EndPainting();
- }
-
- return 0;
-}
-
-
-void SurfaceWin::startFastDraw(){
- WaitForSingleObject(event,INFINITE); //since this might be called before surface
- //allocation we will wait in this case, hopefully without deadlocks
- if (!d3dsurface) {
- return; //why does this happen
- }
- OsdWin* osd=((OsdWin*)(Osd::getInstance()));
- LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();
- if (screen==this) {
- //This should not happen!
- return ;
-
- } else {
- osd->BeginPainting();
-// D3DLOCKED_RECT lockrect;
- RECT rect={0,0,swidth,sheight};
- if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {
- osd->EndPainting();
- return ;
- }
- }
-// fastdraw=true;
-}
-void SurfaceWin::endFastDraw(){
- OsdWin* osd=((OsdWin*)(Osd::getInstance()));
- if (d3dsurface->UnlockRect()!=D3D_OK) {
- osd->EndPainting();
- return ;
- }
- osd->EndPainting();
-// fastdraw=false;
- }
-
-void SurfaceWin::drawPixel(int x, int y, Colour & colour, bool fastdraw) {
- int c = ( (0xFF000000 )
- | (colour.red << 16)
- | (colour.green << 8)
- | (colour.blue ) );
-
- drawPixel(x, y, c, fastdraw);
- }
-
-void SurfaceWin::drawPixel(int x, int y, unsigned int c, bool fastdraw)
-{
- //FixMe: locking for every single Pixel will be painfully slow
- OsdWin* osd;
- if (!fastdraw) {
- WaitForSingleObject(event,INFINITE); //since this might be called before surface
- //allocation we will wait in this case, hopefully without deadlocks
- if (!d3dsurface) {
- return; //why does this happen
- }
- osd=((OsdWin*)(Osd::getInstance()));
- }
- if (x>=swidth || y>=sheight) return; //do not draw outside the surface
- if (screen==this) {
- //This should not happen!
- return ;
-
- } else {
- if (!fastdraw) {
- osd->BeginPainting();
-// D3DLOCKED_RECT lockrect;
- RECT rect={x,y,x+1,y+1};
- if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {
- osd->EndPainting();
- return ;
- }
- unsigned int*row=(unsigned int*)(((char*)lockrect.pBits));
- row[0]=c;
- if (d3dsurface->UnlockRect()!=D3D_OK) {
- osd->EndPainting();
- return ;
- }
- osd->EndPainting();
- } else {
- unsigned int*row=(unsigned int*)(((char*)lockrect.pBits+lockrect.Pitch*y+4*x));
- row[0]=c;
- }
-
- }
-
-}
-
-void SurfaceWin::drawHorzLine(int x1, int x2, int y, unsigned int c)
-{
- fillblt(x1, y, x2-x1, 1, c);
-}
-
-void SurfaceWin::drawVertLine(int x, int y1, int y2, unsigned int c)
-{
- fillblt(x, y1, 1, y2-y1, c);
-}
-
-void SurfaceWin::drawBitmap(int x, int y, const Bitmap& bm)
-{
- // Temporary code? Draw one pixel at a time using drawPixel()
- startFastDraw();
- for (UINT j = 0; j < bm.getHeight(); ++j)
- for (UINT i = 0; i < bm.getWidth(); ++i)
- drawPixel(x+i, y+j, bm.getColour(i,j),true);
- endFastDraw();
-}
-
-int SurfaceWin::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME
-{
- WaitForSingleObject(event,INFINITE); //since this might be called before surface
- //allocation we will wait in this case, hopefully without deadlocks
- if (!d3dsurface) {
- return 0; //why does this happen
- }
- OsdWin* osd=((OsdWin*)(Osd::getInstance()));
- LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();
- LPDIRECT3DSURFACE9 screensurface=((SurfaceWin*)screen)->getD3dsurface();
- if (!screensurface) return 0;
- RECT sourcerect={sx,sy,sx+w,sy+h};
- POINT destpoint={dx,dy};
- osd->BeginPainting();
- if (d3ddev->UpdateSurface(d3dsurface,&sourcerect,screensurface,&destpoint)!=D3D_OK) {
- Log::getInstance()->log("Surface", Log::DEBUG, "Could not update to Screen!");
- osd->EndPainting();
- return 0;
- }
- osd->EndPainting();
- return 0;
-}
-
-int SurfaceWin::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)
-{
- //I don't see code using this function, so I skip it, since it is a MVP specific interface
- return 0;
-}
-
-void SurfaceWin::screenShot(char* fileName)
-{
- //Isn't this for debugging only, so I won't implement it yet
-}
-
-void SurfaceWin::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)
-{
- //Isn't this for debugging only, so I won't implement it yet
-}
-void SurfaceWin::ReleaseSurface()
-{
- ResetEvent(event);
- LPDIRECT3DSURFACE9 temp_surf=d3dsurface;
- LPDIRECT3DTEXTURE9 temp_text=d3dtexture;
- d3dsurface=NULL;
- d3dtexture=NULL;
- sheight=swidth=0;
- if (temp_surf) temp_surf->Release();
- if (temp_text) temp_text->Release();
-}
-/*
-void SurfaceWin::drawJpeg(char *fileName,DWORD x, DWORD y,DWORD *width, DWORD *height){
- WaitForSingleObject(event,INFINITE); //since this might be called before surface
- //allocation we will wait in this case, hopefully without deadlocks
- if (!d3dsurface) {
- return ; //why does this happen
- }
- OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-
-
- D3DXIMAGE_INFO image_inf;
- osd->BeginPainting();
-// D3DXGetImageInfoFromFile(fileName,&image_inf);
- D3DXGetImageInfoFromResource(NULL,fileName,&image_inf);
- RECT dest_rec={x,y,x+image_inf.Width,
- y+image_inf.Height};
-/* if (D3DXLoadSurfaceFromFile(
- d3dsurface,
- NULL,
- &dest_rec,
- fileName,
- NULL,
- D3DX_FILTER_NONE,
- 0,
- &image_inf)!=D3D_OK) {
- Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");
-
- }*
- if (D3DXLoadSurfaceFromResource(
- d3dsurface,
- NULL,
- &dest_rec,
- NULL,
- fileName,
- NULL,
- D3DX_FILTER_NONE,
- 0,
- &image_inf)!=D3D_OK) {
- Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");
-
- }
- osd->EndPainting();
- *width=image_inf.Width;
- *height=image_inf.Height;
-
-}
-
-void SurfaceWin::drawJpeg(char *buffer,ULONG buflength,DWORD x, DWORD y,DWORD *width, DWORD *height){
- WaitForSingleObject(event,INFINITE); //since this might be called before surface
- //allocation we will wait in this case, hopefully without deadlocks
- if (!d3dsurface) {
- return ; //why does this happen
- }
- OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-
-
- D3DXIMAGE_INFO image_inf;
- osd->BeginPainting();
-// D3DXGetImageInfoFromFile(fileName,&image_inf);
- D3DXGetImageInfoFromFileInMemory((void*)buffer,buflength,&image_inf);
- RECT dest_rec={x,y,x+image_inf.Width,
- y+image_inf.Height};
-/* if (D3DXLoadSurfaceFromFile(
- d3dsurface,
- NULL,
- &dest_rec,
- fileName,
- NULL,
- D3DX_FILTER_NONE,
- 0,
- &image_inf)!=D3D_OK) {
- Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");
-
- }*/
-/* if (D3DXLoadSurfaceFromResource(
- d3dsurface,
- NULL,
- &dest_rec,
- NULL,
- fileName,
- NULL,
- D3DX_FILTER_NONE,
- 0,
- &image_inf)!=D3D_OK) {
- Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");
-
- }*
- if (D3DXLoadSurfaceFromFileInMemory(
- d3dsurface,
- NULL,
- &dest_rec,
- (void*)buffer,
- buflength,
- NULL,
- D3DX_FILTER_NONE,
- 0,
- &image_inf)!=D3D_OK) {
- Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");
-
- }
- osd->EndPainting();
- *width=image_inf.Width;
- *height=image_inf.Height;
-
-}*/
-
+/*\r
+ Copyright 2006 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "surfacewin.h"\r
+#include "osdwin.h"\r
+#include "bitmap.h"\r
+#include "log.h"\r
+\r
+SurfaceWin::SurfaceWin(int id)\r
+: Surface(id)\r
+{\r
+ d3dtexture=NULL;\r
+ d3dsurface=NULL;\r
+ sheight=swidth=0;\r
+// fastdraw=false;\r
+ event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);\r
+}\r
+\r
+SurfaceWin::~SurfaceWin()\r
+{\r
+ if (d3dsurface) d3dsurface->Release();\r
+ if (d3dtexture) d3dtexture->Release();\r
+ CloseHandle(event);\r
+}\r
+\r
+int SurfaceWin::create(UINT width, UINT height)\r
+{\r
+ OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+\r
+ LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();\r
+\r
+ while (true) {\r
+ if (screen==this) {\r
+ osd->BeginPainting();\r
+ if (d3ddev->CreateTexture(1024,1024,0,0,D3DFMT_A8R8G8B8,\r
+ // Does every adapter with alpha blending support this?\r
+ D3DPOOL_DEFAULT,&d3dtexture ,NULL)!=D3D_OK) {\r
+ osd->EndPainting();\r
+ MILLISLEEP(50);//wait maybe next time it will work\r
+ continue;\r
+ }\r
+ if (d3dtexture->GetSurfaceLevel(0,&d3dsurface)!=D3D_OK) {\r
+ d3dtexture->Release();\r
+ d3dtexture=NULL;\r
+ MILLISLEEP(50);\r
+ osd->EndPainting();\r
+ continue;\r
+ }\r
+ } else {\r
+ HRESULT hres;\r
+ if (hres=d3ddev->CreateOffscreenPlainSurface(width,height,D3DFMT_A8R8G8B8,\r
+ D3DPOOL_SYSTEMMEM,&d3dsurface,NULL)!=D3D_OK) {\r
+ osd->EndPainting();\r
+ MILLISLEEP(50);//wait maybe next time it will work\r
+\r
+ continue;\r
+ }\r
+\r
+ }\r
+ osd->EndPainting();\r
+\r
+ sheight=height;\r
+ swidth=width;\r
+ /* If someone does high performance Animations on the OSD, we have to change the types\r
+ of surface in order to address these performance issues, if we have only very few updates\r
+ per second this would be fast enough !*/\r
+ break;\r
+ }\r
+ SetEvent(event);\r
+ return 1;\r
+}\r
+\r
+void SurfaceWin::display()\r
+{\r
+}\r
+\r
+int SurfaceWin::fillblt(int x, int y, int width, int height, unsigned int c)\r
+{\r
+ WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+ //allocation we will wait in this case, hopefully without deadlocks\r
+ OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+ if (!d3dsurface) {\r
+ return 0; //why does this happen\r
+ }\r
+\r
+ LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();\r
+\r
+ if (screen==this) {\r
+ //This should not happen!\r
+ return 0;\r
+\r
+ } else {\r
+ osd->BeginPainting();\r
+ D3DLOCKED_RECT lockrect;\r
+ int cx,cy,cwidth,cheight;\r
+ cx=min(max(x,0),swidth-1);\r
+ cy=min(max(y,0),sheight-1);\r
+ cwidth=min(width,swidth-x);\r
+ cheight=min(height,sheight-y);\r
+ RECT rect={cx,cy,cwidth,cheight};\r
+\r
+ if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {\r
+ return 0;\r
+ }\r
+ unsigned int line;\r
+ unsigned int column;\r
+ for (line=0;line<cheight;line++) {\r
+ unsigned int*row=((unsigned int*)(((char*)lockrect.pBits)+lockrect.Pitch*line));\r
+ for (column=0;column<cwidth;column++) {\r
+ row[column]=c;\r
+ }\r
+ }\r
+\r
+ if (d3dsurface->UnlockRect()!=D3D_OK) {\r
+ osd->EndPainting();\r
+ return 0;\r
+ }\r
+ osd->EndPainting();\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+void SurfaceWin::startFastDraw(){\r
+ WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+ //allocation we will wait in this case, hopefully without deadlocks\r
+ if (!d3dsurface) {\r
+ return; //why does this happen\r
+ }\r
+ OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+ LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();\r
+ if (screen==this) {\r
+ //This should not happen!\r
+ return ;\r
+\r
+ } else {\r
+ osd->BeginPainting();\r
+// D3DLOCKED_RECT lockrect;\r
+ RECT rect={0,0,swidth,sheight};\r
+ if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {\r
+ osd->EndPainting();\r
+ return ;\r
+ }\r
+ }\r
+// fastdraw=true;\r
+}\r
+void SurfaceWin::endFastDraw(){\r
+ OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+ if (d3dsurface->UnlockRect()!=D3D_OK) {\r
+ osd->EndPainting();\r
+ return ;\r
+ }\r
+ osd->EndPainting();\r
+// fastdraw=false;\r
+ }\r
+\r
+void SurfaceWin::drawPixel(int x, int y, Colour & colour, bool fastdraw) {\r
+ int c = ( (0xFF000000 )\r
+ | (colour.red << 16)\r
+ | (colour.green << 8)\r
+ | (colour.blue ) );\r
+\r
+ drawPixel(x, y, c, fastdraw);\r
+ }\r
+\r
+void SurfaceWin::drawPixel(int x, int y, unsigned int c, bool fastdraw)\r
+{\r
+ //FixMe: locking for every single Pixel will be painfully slow\r
+ OsdWin* osd;\r
+ if (!fastdraw) {\r
+ WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+ //allocation we will wait in this case, hopefully without deadlocks\r
+ if (!d3dsurface) {\r
+ return; //why does this happen\r
+ }\r
+ osd=((OsdWin*)(Osd::getInstance()));\r
+ }\r
+ if (x>=swidth || y>=sheight) return; //do not draw outside the surface\r
+ if (screen==this) {\r
+ //This should not happen!\r
+ return ;\r
+\r
+ } else {\r
+ if (!fastdraw) {\r
+ osd->BeginPainting();\r
+// D3DLOCKED_RECT lockrect;\r
+ RECT rect={x,y,x+1,y+1};\r
+ if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {\r
+ osd->EndPainting();\r
+ return ;\r
+ }\r
+ unsigned int*row=(unsigned int*)(((char*)lockrect.pBits));\r
+ row[0]=c;\r
+ if (d3dsurface->UnlockRect()!=D3D_OK) {\r
+ osd->EndPainting();\r
+ return ;\r
+ }\r
+ osd->EndPainting();\r
+ } else {\r
+ unsigned int*row=(unsigned int*)(((char*)lockrect.pBits+lockrect.Pitch*y+4*x));\r
+ row[0]=c;\r
+ }\r
+\r
+ }\r
+\r
+}\r
+\r
+void SurfaceWin::drawHorzLine(int x1, int x2, int y, unsigned int c)\r
+{\r
+ fillblt(x1, y, x2-x1, 1, c);\r
+}\r
+\r
+void SurfaceWin::drawVertLine(int x, int y1, int y2, unsigned int c)\r
+{\r
+ fillblt(x, y1, 1, y2-y1, c);\r
+}\r
+\r
+void SurfaceWin::drawBitmap(int x, int y, const Bitmap& bm)\r
+{\r
+ // Temporary code? Draw one pixel at a time using drawPixel()\r
+ startFastDraw();\r
+ for (UINT j = 0; j < bm.getHeight(); ++j)\r
+ for (UINT i = 0; i < bm.getWidth(); ++i)\r
+ drawPixel(x+i, y+j, bm.getColour(i,j),true);\r
+ endFastDraw();\r
+}\r
+\r
+int SurfaceWin::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME\r
+{\r
+ WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+ //allocation we will wait in this case, hopefully without deadlocks\r
+ if (!d3dsurface) {\r
+ return 0; //why does this happen\r
+ }\r
+ OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+ LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();\r
+ LPDIRECT3DSURFACE9 screensurface=((SurfaceWin*)screen)->getD3dsurface();\r
+ if (!screensurface) return 0;\r
+ RECT sourcerect={sx,sy,sx+w,sy+h};\r
+ POINT destpoint={dx,dy};\r
+ osd->BeginPainting();\r
+ if (d3ddev->UpdateSurface(d3dsurface,&sourcerect,screensurface,&destpoint)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not update to Screen!");\r
+ osd->EndPainting();\r
+ return 0;\r
+ }\r
+ osd->EndPainting();\r
+ return 0;\r
+}\r
+\r
+int SurfaceWin::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)\r
+{\r
+ //I don't see code using this function, so I skip it, since it is a MVP specific interface\r
+ return 0;\r
+}\r
+\r
+void SurfaceWin::screenShot(const char* fileName)\r
+{\r
+ //Isn't this for debugging only, so I won't implement it yet\r
+}\r
+\r
+void SurfaceWin::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)\r
+{\r
+ //Isn't this for debugging only, so I won't implement it yet\r
+}\r
+void SurfaceWin::ReleaseSurface()\r
+{\r
+ ResetEvent(event);\r
+ LPDIRECT3DSURFACE9 temp_surf=d3dsurface;\r
+ LPDIRECT3DTEXTURE9 temp_text=d3dtexture;\r
+ d3dsurface=NULL;\r
+ d3dtexture=NULL;\r
+ sheight=swidth=0;\r
+ if (temp_surf) temp_surf->Release();\r
+ if (temp_text) temp_text->Release();\r
+}\r
+\r
+void SurfaceWin::drawJpeg(const char *fileName,int x, int y,int *width, int *height){\r
+ WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+ //allocation we will wait in this case, hopefully without deadlocks\r
+ if (!d3dsurface) {\r
+ return ; //why does this happen\r
+ }\r
+ OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+\r
+ D3DXIMAGE_INFO image_inf;\r
+ osd->BeginPainting();\r
+// D3DXGetImageInfoFromFile(fileName,&image_inf);\r
+ D3DXGetImageInfoFromResource(NULL,fileName,&image_inf);\r
+ RECT dest_rec={x,y,x+image_inf.Width,\r
+ y+image_inf.Height};\r
+/* if (D3DXLoadSurfaceFromFile(\r
+ d3dsurface,\r
+ NULL,\r
+ &dest_rec,\r
+ fileName,\r
+ NULL,\r
+ D3DX_FILTER_NONE,\r
+ 0,\r
+ &image_inf)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+ }*/\r
+ if (D3DXLoadSurfaceFromResource(\r
+ d3dsurface,\r
+ NULL,\r
+ &dest_rec,\r
+ NULL,\r
+ fileName,\r
+ NULL,\r
+ D3DX_FILTER_NONE,\r
+ 0,\r
+ &image_inf)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+ }\r
+ osd->EndPainting();\r
+ *width=image_inf.Width;\r
+ *height=image_inf.Height;\r
+\r
+}\r
+\r
+/*\r
+void SurfaceWin::drawJpeg(char *buffer,ULONG buflength,DWORD x, DWORD y,DWORD *width, DWORD *height){\r
+ WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+ //allocation we will wait in this case, hopefully without deadlocks\r
+ if (!d3dsurface) {\r
+ return ; //why does this happen\r
+ }\r
+ OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+\r
+ D3DXIMAGE_INFO image_inf;\r
+ osd->BeginPainting();\r
+// D3DXGetImageInfoFromFile(fileName,&image_inf);\r
+ D3DXGetImageInfoFromFileInMemory((void*)buffer,buflength,&image_inf);\r
+ RECT dest_rec={x,y,x+image_inf.Width,\r
+ y+image_inf.Height};\r
+/* if (D3DXLoadSurfaceFromFile(\r
+ d3dsurface,\r
+ NULL,\r
+ &dest_rec,\r
+ fileName,\r
+ NULL,\r
+ D3DX_FILTER_NONE,\r
+ 0,\r
+ &image_inf)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+ }*/\r
+/* if (D3DXLoadSurfaceFromResource(\r
+ d3dsurface,\r
+ NULL,\r
+ &dest_rec,\r
+ NULL,\r
+ fileName,\r
+ NULL,\r
+ D3DX_FILTER_NONE,\r
+ 0,\r
+ &image_inf)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+ }*\r
+ if (D3DXLoadSurfaceFromFileInMemory(\r
+ d3dsurface,\r
+ NULL,\r
+ &dest_rec,\r
+ (void*)buffer,\r
+ buflength,\r
+ NULL,\r
+ D3DX_FILTER_NONE,\r
+ 0,\r
+ &image_inf)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+ }\r
+ osd->EndPainting();\r
+ *width=image_inf.Width;\r
+ *height=image_inf.Height;\r
+\r
+}*/\r
+\r
-/*
- Copyright 2006 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 SURFACEWIN_H
-#define SURFACEWIN_H
-
-#include "defines.h"
-#include "surface.h"
-#include <winsock2.h>
-#include <d3d9.h>
-
-class SurfaceWin : public Surface
-{
- public:
- SurfaceWin(int id = 0);
- ~SurfaceWin();
-
- int create(UINT width, UINT height);
- void display();
-
- void startFastDraw();
- void endFastDraw();
-
- int fillblt(int x, int y, int width, int height, unsigned int c);
- void drawPixel(int x, int y, Colour& c, bool fastdraw=false);
- void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);
- void drawHorzLine(int x1, int x2, int y, unsigned int c);
- void drawVertLine(int x, int y1, int y2, unsigned int c);
- void drawBitmap(int x, int y, const Bitmap& bm);
- int updateToScreen(int sx, int sy, int w, int h, int dx, int dy);
- void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b);
- void screenShot(char* fileName);
- void ReleaseSurface();
- int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy);
-/* void drawJpeg(char *fileName,DWORD x, DWORD y,DWORD *width, DWORD *height);
- void drawJpeg(char *buffer,ULONG buflength,DWORD x, DWORD y,DWORD *width, DWORD *height);*/
- LPDIRECT3DSURFACE9 getD3dsurface() {WaitForSingleObject(event,INFINITE);
- return d3dsurface;};
- LPDIRECT3DTEXTURE9 getD3dtexture() {return d3dtexture;};
- private:
- LPDIRECT3DSURFACE9 d3dsurface;
- LPDIRECT3DTEXTURE9 d3dtexture;
- D3DLOCKED_RECT lockrect;
- UINT sheight,swidth;
- HANDLE event;
-};
-
-#endif
+/*\r
+ Copyright 2006 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef SURFACEWIN_H\r
+#define SURFACEWIN_H\r
+\r
+#include "defines.h"\r
+#include "surface.h"\r
+#include <winsock2.h>\r
+#include <d3d9.h>\r
+\r
+class SurfaceWin : public Surface\r
+{\r
+ public:\r
+ SurfaceWin(int id = 0);\r
+ ~SurfaceWin();\r
+\r
+ int create(UINT width, UINT height);\r
+ void display();\r
+\r
+ void startFastDraw();\r
+ void endFastDraw();\r
+\r
+ int fillblt(int x, int y, int width, int height, unsigned int c);\r
+ void drawPixel(int x, int y, Colour& c, bool fastdraw=false);\r
+ void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);\r
+ void drawHorzLine(int x1, int x2, int y, unsigned int c);\r
+ void drawVertLine(int x, int y1, int y2, unsigned int c);\r
+ void drawBitmap(int x, int y, const Bitmap& bm);\r
+ int updateToScreen(int sx, int sy, int w, int h, int dx, int dy);\r
+ void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b);\r
+ void screenShot(const char* fileName);\r
+ void ReleaseSurface();\r
+ int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy);\r
+ void drawJpeg(const char *fileName,int x, int y,int *width, int *height);\r
+/* void drawJpeg(char *buffer,ULONG buflength,DWORD x, DWORD y,DWORD *width, DWORD *height);*/\r
+ LPDIRECT3DSURFACE9 getD3dsurface() {WaitForSingleObject(event,INFINITE);\r
+ return d3dsurface;};\r
+ LPDIRECT3DTEXTURE9 getD3dtexture() {return d3dtexture;};\r
+ private:\r
+ LPDIRECT3DSURFACE9 d3dsurface;\r
+ LPDIRECT3DTEXTURE9 d3dtexture;\r
+ D3DLOCKED_RECT lockrect;\r
+ UINT sheight,swidth;\r
+ HANDLE event;\r
+};\r
+\r
+#endif\r
void TBBoxx::draw()
{
- Log::getInstance()->log("TBBoxx", Log::DEBUG, "Draw");
+ //Log::getInstance()->log("TBBoxx", Log::DEBUG, "Draw: %d",this);
fillColour(Colour::VIEWBACKGROUND);
-/*
- Copyright 2008 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.
-*/
-
-
-/* Portions from vdr osdteletext plugin "txtrender.c": */
-/***************************************************************************
- * *
- * txtrender.c - Teletext display abstraction and teletext code *
- * renderer *
- * *
- * This program 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. *
- * *
- * Changelog: *
- * 2005-03 initial version (c) Udo Richter *
- * *
- ***************************************************************************/
-
-#include "teletextdecodervbiebu.h"
-#include "teletxt/tables.h"
-#include "message.h"
-#include "command.h"
-#include "video.h"
-
-#ifdef WIN32
-#include <windows.h>
-#endif
-
-TeletextDecoderVBIEBU::TeletextDecoderVBIEBU()
-{
- selectedpage=0x100;
- ourpage=false;
- flags=lang=0;
-
- CleanPage();
- FirstG0CodePage=0;
- SecondG0CodePage=0;
- dirty=false;
- txtview=NULL;
- firstlineupdate=0;
- gotcha=false;
- char digits[]={'1','0','0'};
- setKeyinDigits(digits,false);
- isrecording=false;
- for (int i=0;i<10;i++) record_pages[i]=-1;
-
-
-}
-
-TeletextDecoderVBIEBU::~TeletextDecoderVBIEBU()
-{
-
-
-}
-
-long long TeletextDecoderVBIEBU::SetStartOffset(long long curreftime, bool *rsync)
-{
- return 0;
-}
-
-void TeletextDecoderVBIEBU::ResetTimeOffsets()
-{
-
-}
-
-
-
-void TeletextDecoderVBIEBU::ResetDecoder()
-{
- gotcha=false;
- ourpage=false;
- firstlineupdate=0;
- selectedpage=0x100;
- CleanPage();
- char digits[]={'1','0','0'};
- setKeyinDigits(digits,false);
- for (int i=0;i<10;i++) record_pages[i]=-1;
-
-}
-
-void TeletextDecoderVBIEBU::setPage(unsigned int newpage)
-{
- selectedpage=newpage;
- gotcha=false;
- ourpage=false;
- firstlineupdate=0;
- for (int i=0;i<25;i++) {
- memset(curpage[i],0,40);
- }
-}
-
-void TeletextDecoderVBIEBU::CleanPage()
-{
- int x,y;
- for (int i=0;i<25;i++) {
- memset(curpage[i],0,40);
- }
- for (y=0;y<25;y++) {
- for (x=0;x<40;x++) {
- cTeletextChar c;
- c.SetFGColor(ttcWhite);
- c.SetBGColor(ttcBlack);
- c.SetCharset(CHARSET_LATIN_G0);
- c.SetChar(' ');
- if (flags&0x60) {
- c.SetBoxedOut(true);
- }
- setChar(x,y,c);
- }
- }
-
-}
-void TeletextDecoderVBIEBU::setKeyinDigits(char digits[3],bool inKeying)
-{
- int x;
- inkeying=inKeying;
- for (x=0;x<3;x++) {
- cTeletextChar c;
- c.SetFGColor(ttcWhite);
- c.SetBGColor(ttcBlack);
- c.SetCharset(CHARSET_LATIN_G0);
- c.SetChar(digits[x]);
- if (flags&0x60) {
- c.SetBoxedOut(true);
- }
- setChar(x+3,0,c);
- keyindigits[x]=digits[x];
- }
-}
-
-void TeletextDecoderVBIEBU::PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos)
-{
- mediapacket = mplist.front();
-}
-
-static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
-{
- // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
- if (pts1 > pts2)
- return pts1 - pts2;
- else
- return (1LL<<33) + pts1 - pts2;
-}
-
-UINT TeletextDecoderVBIEBU::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)
-{
- if (mediapacket.type != MPTYPE_TELETEXT)
- {
- *samplepos= 0;
- return 1; //Skip it!
- }
- unsigned int headerstrip;
- unsigned char txtdata[43];
- headerstrip=buffer[mediapacket.pos_buffer+8]+9;
- //headerstrip+=4; //substream id
- unsigned int datapos=0;
- unsigned int datatype=buffer[mediapacket.pos_buffer+headerstrip+0];
- //Chris should we use here the pts data from mediapacket ?
- // in this case the data fields should also be added in mediamvp
- if (mediapacket.synched)
- { // An entry exists in the work list
- ULLONG nowPTS = Video::getInstance()->getCurrentTimestamp();
- if (PTSDifference(mediapacket.pts, nowPTS) >= 1200*90000) {
- *samplepos=0;
- return 1;//bad data skip it
- }
- if (nowPTS < (mediapacket.pts-4000) ) {
- *samplepos=0;
- return 0;
- }
- }
-
- if (( datatype>=0x10 && datatype <=0x1F) ||
- ( datatype>=0x99 && datatype <=0x9B)) {
- //EBU VBI DATA
- datapos++;
- while (datapos< (mediapacket.length-headerstrip)) {
- unsigned int unit_id=buffer[mediapacket.pos_buffer+headerstrip+datapos];
- datapos++;
- unsigned int unit_length=buffer[mediapacket.pos_buffer+headerstrip+datapos];
- datapos++;
- switch (unit_id) {
- case 0x02:
- case 0x03: {//Teletext with and without subtitles
- //call teletext decoder
- unsigned int field=buffer[mediapacket.pos_buffer+headerstrip+datapos];
-
- if ((datapos+44)< (mediapacket.length-headerstrip)) {
- for (int i=0;i<42;i++) {
- txtdata[i]=invtab[buffer[mediapacket.pos_buffer+headerstrip+datapos+2+i]];
- }
- DecodeTeletext(txtdata,field);
- }
- }break;
- case 0xC0: //inverted Teletext
- //call teletext decoder
- break;
-
- case 0xC3: //VPS
- //what to do with this, in the moment we do not need it
- break;
- case 0xC4: //WSS
- //what to do with this, in the moment we do not need it
- break;
- case 0xC5: //CC
- //what to do with this, in the moment we do not need it
- break;
- case 0xC6: //monochrome 4:2:2 samples, what is that?
- //what to do with this, in the moment we do not need it
- break;
- default:
- // case 0x00,0x01,0x04..0x7f,0x80..0xbf,0xc1,0xc2,0xc7..0xfe,0xff: //discard
- //discard
- break;
- };
- datapos+=unit_length;
- // while (buffer[mediapacket.pos_buffer+headerstrip+datapos]==0xFF &&(datapos< (mediapacket.length-headerstrip))) {
- // datapos++; //stuffing bytes
- // }
-
-
- }
- *samplepos=0;
- return 1;
-
-
- } else {
- *samplepos= 0;
- return 1; //Skip it! and discard data
- }
-
- return 0;
-
-}
-// This part is inspired by the vdr-plugin-osdteletext of Udo Richter and Marcel Wiesweg
-void TeletextDecoderVBIEBU::DecodeTeletext(const UCHAR* buffer, unsigned int field) //needs to be exactly 42 byte long!!
-{
- UCHAR hdrbuf[5];
- for (int i=0;i<5;i++) hdrbuf[i]=(unhamtab[buffer[2*i]]&0xF) | ((unhamtab[buffer[2*i+1]]&0xF)<< 4);
- int header=hdrbuf[0];
- int magazin=header & 0x7;
- int line = (header>>3) & 0x1f;
- if (magazin==0) magazin=8;
- if (line==0)
- {
- if (ourpage) {
- gotcha=true;
- inkeying=false;
- RenderTeletextCode(false);
- } else {
- RenderTeletextCode(true);
- }
- int pagenumber=hdrbuf[1];
- int pagemagazin=magazin<<8 | pagenumber;
- int pagesubnumber=(hdrbuf[2]) || ((hdrbuf[3]<<8) & 0x3f7f);
-
- if (pagemagazin == selectedpage) ourpage=true;
- else ourpage=false;
- if (isrecording) {
- for (int i=0;i<10;i++) {
- if (pagemagazin==record_pages[i]) break;
- if (record_pages[i]==-1) {
- record_pages[i]=pagemagazin;
- break;
- }
- }
- }
- if (hdrbuf[3] &0x80) { //This is a subtitle
- for (int i=0;i<10;i++) {
- if (pagemagazin==record_pages[i]) break;
- if (record_pages[i]==-1) {
- record_pages[i]=pagemagazin;
- break;
- }
- }
- }
-
-
- if (ourpage) {
- lang=((hdrbuf[4]>>5) & 0x07);
- flags=hdrbuf[2] & 0x80;
- flags|=(hdrbuf[3]&0x40)|((hdrbuf[3]>>2)&0x20); //??????
- flags|=((hdrbuf[4]<<4)&0x10)|((hdrbuf[4]<<2)&0x08)|(hdrbuf[4]&0x04)|((hdrbuf[4]>>1)&0x02)|((hdrbuf[4]>>4)&0x01);
- for (int i=0;i<25;i++) {
- memset(curpage[i],0,40);
- }
- }
-
- memcpy(curpage[line],buffer+2,40);
- } else if (ourpage && (line<=25)) {
- memcpy(curpage[line],buffer+2,40);
-
- }
-}
-
-
-/* from osdteletext plugin: (slightly adapted for vomp)*/
-// Font tables
-
-// teletext uses 7-bit numbers to identify a font set.
-// There are three font sets involved:
-// Primary G0, Secondary G0, and G2 font set.
-
-// Font tables are organized in blocks of 8 fonts:
-
-enumCharsets FontBlockG0_0000[8] = {
- CHARSET_LATIN_G0_EN,
- CHARSET_LATIN_G0_DE,
- CHARSET_LATIN_G0_SV_FI,
- CHARSET_LATIN_G0_IT,
- CHARSET_LATIN_G0_FR,
- CHARSET_LATIN_G0_PT_ES,
- CHARSET_LATIN_G0_CZ_SK,
- CHARSET_LATIN_G0
-};
-
-enumCharsets FontBlockG2Latin[8]={
- CHARSET_LATIN_G2,
- CHARSET_LATIN_G2,
- CHARSET_LATIN_G2,
- CHARSET_LATIN_G2,
- CHARSET_LATIN_G2,
- CHARSET_LATIN_G2,
- CHARSET_LATIN_G2,
- CHARSET_LATIN_G2
-};
-
-enumCharsets FontBlockG0_0001[8] = {
- CHARSET_LATIN_G0_PL,
- CHARSET_LATIN_G0_DE,
- CHARSET_LATIN_G0_SV_FI,
- CHARSET_LATIN_G0_IT,
- CHARSET_LATIN_G0_FR,
- CHARSET_LATIN_G0,
- CHARSET_LATIN_G0_CZ_SK,
- CHARSET_LATIN_G0
-};
-
-enumCharsets FontBlockG0_0010[8] = {
- CHARSET_LATIN_G0_EN,
- CHARSET_LATIN_G0_DE,
- CHARSET_LATIN_G0_SV_FI,
- CHARSET_LATIN_G0_IT,
- CHARSET_LATIN_G0_FR,
- CHARSET_LATIN_G0_PT_ES,
- CHARSET_LATIN_G0_TR,
- CHARSET_LATIN_G0
-};
-
-
-enumCharsets FontBlockG0_0011[8] = {
- CHARSET_LATIN_G0,
- CHARSET_LATIN_G0,
- CHARSET_LATIN_G0,
- CHARSET_LATIN_G0,
- CHARSET_LATIN_G0,
- CHARSET_LATIN_G0_SR_HR_SL,
- CHARSET_LATIN_G0,
- CHARSET_LATIN_G0_RO
-};
-
-enumCharsets FontBlockG0_0100[8] = {
- CHARSET_CYRILLIC_G0_SR_HR,
- CHARSET_LATIN_G0_DE,
- CHARSET_LATIN_G0_EE,
- CHARSET_LATIN_G0_LV_LT,
- CHARSET_CYRILLIC_G0_RU_BG,
- CHARSET_CYRILLIC_G0_UK,
- CHARSET_LATIN_G0_CZ_SK,
- CHARSET_INVALID
-};
-
-enumCharsets FontBlockG2_0100[8] = {
- CHARSET_CYRILLIC_G2,
- CHARSET_LATIN_G2,
- CHARSET_LATIN_G2,
- CHARSET_LATIN_G2,
- CHARSET_CYRILLIC_G2,
- CHARSET_CYRILLIC_G2,
- CHARSET_LATIN_G2,
- CHARSET_INVALID
-};
-
-enumCharsets FontBlockG0_0110[8] = {
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_LATIN_G0_TR,
- CHARSET_GREEK_G0
-};
-
-enumCharsets FontBlockG2_0110[8] = {
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_LATIN_G2,
- CHARSET_GREEK_G2
-};
-
-enumCharsets FontBlockG0_1000[8] = {
- CHARSET_LATIN_G0_EN,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_LATIN_G0_FR,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_ARABIC_G0
-};
-
-enumCharsets FontBlockG2_1000[8] = {
- CHARSET_ARABIC_G2,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_ARABIC_G2,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_ARABIC_G2
-};
-
-enumCharsets FontBlockG0_1010[8] = {
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_HEBREW_G0,
- CHARSET_INVALID,
- CHARSET_ARABIC_G0,
-};
-
-enumCharsets FontBlockG2_1010[8] = {
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_ARABIC_G2,
- CHARSET_INVALID,
- CHARSET_ARABIC_G2,
-};
-
-enumCharsets FontBlockInvalid[8] = {
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID,
- CHARSET_INVALID
-};
-
-
-
-// The actual font table definition:
-// Split the 7-bit number into upper 4 and lower 3 bits,
-// use upper 4 bits for outer array,
-// use lower 3 bits for inner array
-
-struct structFontBlock {
- enumCharsets *G0Block;
- enumCharsets *G2Block;
-};
-
-structFontBlock FontTable[16] = {
- { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block
- { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block
- { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block
- { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block
- { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block
- { FontBlockInvalid, FontBlockInvalid }, // 0101 block
- { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block
- { FontBlockInvalid, FontBlockInvalid }, // 0111 block
- { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block
- { FontBlockInvalid, FontBlockInvalid }, // 1001 block
- { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block
- { FontBlockInvalid, FontBlockInvalid }, // 1011 block
- { FontBlockInvalid, FontBlockInvalid }, // 1100 block
- { FontBlockInvalid, FontBlockInvalid }, // 1101 block
- { FontBlockInvalid, FontBlockInvalid }, // 1110 block
- { FontBlockInvalid, FontBlockInvalid } // 1111 block
-};
-
-inline enumCharsets GetG0Charset(int codepage) {
- return FontTable[codepage>>3].G0Block[codepage&7];
-}
-inline enumCharsets GetG2Charset(int codepage) {
- return FontTable[codepage>>3].G2Block[codepage&7];
-}
-
-enum enumSizeMode {
- // Possible size modifications of characters
- sizeNormal,
- sizeDoubleWidth,
- sizeDoubleHeight,
- sizeDoubleSize
-};
-
-void TeletextDecoderVBIEBU::RenderTeletextCode(bool renderfirstlineonly) {
- int x,y;
- bool EmptyNextLine=false;
- // Skip one line, in case double height chars were/will be used
-
- // Get code pages:
- int LocalG0CodePage=(FirstG0CodePage & 0x78)
- | ((lang & 0x04)>>2) | (lang & 0x02) | ((lang & 0x01)<<2);
- enumCharsets FirstG0=GetG0Charset(LocalG0CodePage);
- enumCharsets SecondG0=GetG0Charset(SecondG0CodePage);
- // Reserved for later use:
- // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage);
-
- for (y=0;y<24;(EmptyNextLine?y+=2:y++)) {
- // Start of line: Set start of line defaults
-
- // Hold Mosaics mode: Remember last mosaic char/charset
- // for next spacing code
- bool HoldMosaics=false;
- unsigned char HoldMosaicChar=' ';
- enumCharsets HoldMosaicCharset=FirstG0;
-
- enumSizeMode Size=sizeNormal;
- // Font size modification
- bool SecondCharset=false;
- // Use primary or secondary G0 charset
- bool GraphicCharset=false;
- // Graphics charset used?
- bool SeparateGraphics=false;
- // Use separated vs. contiguous graphics charset
- bool NoNextChar=false;
- // Skip display of next char, for double-width
- EmptyNextLine=false;
- // Skip next line, for double-height
-
- cTeletextChar c;
- // auto.initialized to everything off
- c.SetFGColor(ttcWhite);
- c.SetBGColor(ttcBlack);
- c.SetCharset(FirstG0);
-
- if (y==0 && (flags&0x10)) {
- if (!inkeying ) c.SetBoxedOut(true);
-
- }
- if (flags&0x60) {
- if (!(inkeying && y==0) ) c.SetBoxedOut(true);
-
- }
- if (y==0) {
-
- for (x=0;x<8;x++) {
- cTeletextChar c2=c;
-
- if (x>=3 && x<6){
- c2.SetChar(keyindigits[x-3]);
-
- }
- else
- c2.SetChar(' ');
- setChar(x,0,c2);
- }
- }
-
- // Pre-scan for double-height and double-size codes
- for (x=0;x<40;x++) {
- if (y==0 && x<8) x=8;
- if ((curpage[y][x] & 0x7f)==0x0D || (curpage[y][x] & 0x7f)==0x0F)
- EmptyNextLine=true;
- }
-
- // Move through line
- for (x=0;x<40;x++) {
- unsigned char ttc=curpage[y][x] & 0x7f;
- // skip parity check
-
- if (y==0 && x<8) continue;
- if (y==0 && x<31 && renderfirstlineonly && gotcha && !inkeying) continue;
- // no displayable data here...
-
-/* // Debug only: Output line data and spacing codes
- if (y==6) {
- if (ttc<0x20)
- printf("%s ",names[ttc]);
- else
- printf("%02x ",ttc);
- if (x==39) printf("\n");
- }
-*/
-
- // Handle all 'Set-At' spacing codes
- switch (ttc) {
- case 0x09: // Steady
- c.SetBlink(false);
- break;
- case 0x0C: // Normal Size
- if (Size!=sizeNormal) {
- Size=sizeNormal;
- HoldMosaicChar=' ';
- HoldMosaicCharset=FirstG0;
- }
- break;
- case 0x18: // Conceal
- c.SetConceal(true);
- break;
- case 0x19: // Contiguous Mosaic Graphics
- SeparateGraphics=false;
- if (GraphicCharset)
- c.SetCharset(CHARSET_GRAPHICS_G1);
- break;
- case 0x1A: // Separated Mosaic Graphics
- SeparateGraphics=true;
- if (GraphicCharset)
- c.SetCharset(CHARSET_GRAPHICS_G1_SEP);
- break;
- case 0x1C: // Black Background
- c.SetBGColor(ttcBlack);
- break;
- case 0x1D: // New Background
- c.SetBGColor(c.GetFGColor());
- break;
- case 0x1E: // Hold Mosaic
- HoldMosaics=true;
- break;
- }
-
- // temporary copy of character data:
- cTeletextChar c2=c;
- // c2 will be text character or space character or hold mosaic
- // c2 may also have temporary flags or charsets
-
- if (ttc<0x20) {
- // Spacing code, display space or hold mosaic
- if (HoldMosaics) {
- c2.SetChar(HoldMosaicChar);
- c2.SetCharset(HoldMosaicCharset);
- } else {
- c2.SetChar(' ');
- }
- } else {
- // Character code
- c2.SetChar(ttc);
- if (GraphicCharset) {
- if (ttc&0x20) {
- // real graphics code, remember for HoldMosaics
- HoldMosaicChar=ttc;
- HoldMosaicCharset=c.GetCharset();
- } else {
- // invalid code, pass-through to G0
- c2.SetCharset(SecondCharset?SecondG0:FirstG0);
- }
- }
- }
-
- // Handle double-height and double-width extremes
- if (y>=23) {
- if (Size==sizeDoubleHeight) Size=sizeNormal;
- if (Size==sizeDoubleSize) Size=sizeDoubleWidth;
- }
- if (x>=38) {
- if (Size==sizeDoubleWidth) Size=sizeNormal;
- if (Size==sizeDoubleSize) Size=sizeDoubleHeight;
- }
-
- // Now set character code
-
- if (NoNextChar) {
- // Suppress this char due to double width last char
- NoNextChar=false;
- } else {
- switch (Size) {
- case sizeNormal:
- // Normal sized
- setChar(x,y,c2);
- if (EmptyNextLine && y<23) {
- // Clean up next line
- setChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0));
- }
- break;
- case sizeDoubleWidth:
- // Double width
- setChar(x,y,c2.ToDblWidth(dblw_Left));
- setChar(x+1,y,c2.ToDblWidth(dblw_Right));
- if (EmptyNextLine && y<23) {
- // Clean up next line
- setChar(x ,y+1,c2.ToChar(' ').ToCharset(FirstG0));
- setChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0));
- }
- NoNextChar=true;
- break;
- case sizeDoubleHeight:
- // Double height
- setChar(x,y,c2.ToDblHeight(dblh_Top));
- setChar(x,y+1,c2.ToDblHeight(dblh_Bottom));
- break;
- case sizeDoubleSize:
- // Double Size
- setChar(x , y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Left ));
- setChar(x+1, y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Right));
- setChar(x ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left ));
- setChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right));
- NoNextChar=true;
- break;
- }
- }
-
- // Handle all 'Set-After' spacing codes
- if (ttc>=0x00 && ttc<=0x07) { // Set FG color
- if (GraphicCharset) {
- // Actual switch from graphics charset
- HoldMosaicChar=' ';
- HoldMosaicCharset=FirstG0;
- }
- c.SetFGColor((enumTeletextColor)ttc);
- c.SetCharset(SecondCharset?SecondG0:FirstG0);
- GraphicCharset=false;
- c.SetConceal(false);
- } else if (ttc==0x08) {
- c.SetBlink(true);
- } else if (ttc==0x0A) {
- c.SetBoxedOut(true);
- } else if (ttc==0x0B) {
- // Start Box
- c.SetBoxedOut(false);
- } else if (ttc==0x0D) {
- if (Size!=sizeDoubleHeight) {
- Size=sizeDoubleHeight;
- HoldMosaicChar=' ';
- HoldMosaicCharset=FirstG0;
- }
- } else if (ttc==0x0E) {
- if (Size!=sizeDoubleWidth) {
- Size=sizeDoubleWidth;
- HoldMosaicChar=' ';
- HoldMosaicCharset=FirstG0;
- }
- } else if (ttc==0x0E) {
- if (Size!=sizeDoubleSize) {
- Size=sizeDoubleSize;
- HoldMosaicChar=' ';
- HoldMosaicCharset=FirstG0;
- }
- } else if (ttc>=0x10 && ttc<=0x17) {
- if (!GraphicCharset) {
- // Actual switch to graphics charset
- HoldMosaicChar=' ';
- HoldMosaicCharset=FirstG0;
- }
- c.SetFGColor((enumTeletextColor)(ttc-0x10));
- c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1);
- GraphicCharset=true;
- c.SetConceal(false);
- } else if (ttc==0x1B) {
- SecondCharset=!SecondCharset;
- if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0);
- } else if (ttc==0x1F) {
- HoldMosaics=false;
- }
-
- } // end for x
- if (renderfirstlineonly) break;
- } // end for y
-
- for (x=0;x<40;x++) {
- // Clean out last line
- cTeletextChar c;
- c.SetFGColor(ttcWhite);
- c.SetBGColor(ttcBlack);
- c.SetCharset(FirstG0);
- c.SetChar(' ');
- if (flags&0x60) {
- c.SetBoxedOut(true);
- }
- setChar(x,24,c);
- }
- for (y=0;y<25;y++) {
- for (x=0;x<40;x++) {
- if (isDirty(x,y)) {
- dirty=true;
- break;
- }
- if (dirty) break;
- }
- if (dirty) break;
- }
-
- if (dirty && txtview!=NULL ) {
-
- if ( !renderfirstlineonly) {
- Message* m= new Message();
- m->message = Message::TELETEXTUPDATE;
- m->to = txtview;
- m->from = this;
- m->parameter = 0;
- Command::getInstance()->postMessageFromOuterSpace(m);
- } else if (firstlineupdate==10) {
- Message* m= new Message();
- m->message = Message::TELETEXTUPDATEFIRSTLINE;
- m->to = txtview;
- m->from = this;
- m->parameter = 0;
- Command::getInstance()->postMessageFromOuterSpace(m);
- firstlineupdate=0;
- } else firstlineupdate++;
-
-
- }
-
-}
+/*\r
+ Copyright 2008 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+\r
+/* Portions from vdr osdteletext plugin "txtrender.c": */\r
+/***************************************************************************\r
+ * *\r
+ * txtrender.c - Teletext display abstraction and teletext code *\r
+ * renderer *\r
+ * *\r
+ * This program is free software; you can redistribute it and/or modify *\r
+ * it under the terms of the GNU General Public License as published by *\r
+ * the Free Software Foundation; either version 2 of the License, or *\r
+ * (at your option) any later version. *\r
+ * *\r
+ * Changelog: *\r
+ * 2005-03 initial version (c) Udo Richter *\r
+ * *\r
+ ***************************************************************************/\r
+\r
+#include "teletextdecodervbiebu.h"\r
+#include "teletxt/tables.h"\r
+#include "message.h"\r
+#include "command.h"\r
+#include "video.h"\r
+\r
+#ifdef WIN32\r
+#include <windows.h>\r
+#endif\r
+\r
+TeletextDecoderVBIEBU::TeletextDecoderVBIEBU()\r
+{\r
+ selectedpage=0x100;\r
+ ourpage=false;\r
+ flags=lang=0; \r
+ \r
+ CleanPage();\r
+ FirstG0CodePage=0;\r
+ SecondG0CodePage=0;\r
+ dirty=false;\r
+ txtview=NULL;\r
+ firstlineupdate=0;\r
+ gotcha=false;\r
+ char digits[]={'1','0','0'};\r
+ setKeyinDigits(digits,false);\r
+ isrecording=false;\r
+ for (int i=0;i<10;i++) record_pages[i]=-1;\r
+ \r
+\r
+}\r
+\r
+TeletextDecoderVBIEBU::~TeletextDecoderVBIEBU()\r
+{\r
+\r
+\r
+}\r
+\r
+long long TeletextDecoderVBIEBU::SetStartOffset(long long curreftime, bool *rsync)\r
+{\r
+ return 0; \r
+}\r
+\r
+void TeletextDecoderVBIEBU::ResetTimeOffsets()\r
+{\r
+\r
+}\r
+\r
+\r
+\r
+void TeletextDecoderVBIEBU::ResetDecoder()\r
+{\r
+ gotcha=false;\r
+ ourpage=false;\r
+ firstlineupdate=0;\r
+ selectedpage=0x100;\r
+ CleanPage();\r
+ char digits[]={'1','0','0'};\r
+ setKeyinDigits(digits,false);\r
+ for (int i=0;i<10;i++) record_pages[i]=-1;\r
+ \r
+}\r
+\r
+void TeletextDecoderVBIEBU::setPage(unsigned int newpage)\r
+{\r
+ selectedpage=newpage;\r
+ gotcha=false;\r
+ ourpage=false;\r
+ firstlineupdate=0;\r
+ for (int i=0;i<25;i++) {\r
+ memset(curpage[i],0,40);\r
+ }\r
+}\r
+\r
+void TeletextDecoderVBIEBU::CleanPage()\r
+{\r
+ int x,y;\r
+ for (int i=0;i<25;i++) {\r
+ memset(curpage[i],0,40);\r
+ }\r
+ for (y=0;y<25;y++) {\r
+ for (x=0;x<40;x++) {\r
+ cTeletextChar c;\r
+ c.SetFGColor(ttcWhite);\r
+ c.SetBGColor(ttcBlack);\r
+ c.SetCharset(CHARSET_LATIN_G0);\r
+ c.SetChar(' ');\r
+ if (flags&0x60) {\r
+ c.SetBoxedOut(true); \r
+ }\r
+ setChar(x,y,c);\r
+ }\r
+ } \r
+\r
+}\r
+void TeletextDecoderVBIEBU::setKeyinDigits(char digits[3],bool inKeying)\r
+{\r
+ int x;\r
+ inkeying=inKeying;\r
+ for (x=0;x<3;x++) {\r
+ cTeletextChar c;\r
+ c.SetFGColor(ttcWhite);\r
+ c.SetBGColor(ttcBlack);\r
+ c.SetCharset(CHARSET_LATIN_G0);\r
+ c.SetChar(digits[x]);\r
+ if (flags&0x60) {\r
+ c.SetBoxedOut(true); \r
+ }\r
+ setChar(x+3,0,c);\r
+ keyindigits[x]=digits[x];\r
+ }\r
+}\r
+\r
+void TeletextDecoderVBIEBU::PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos)\r
+{\r
+ mediapacket = mplist.front();\r
+}\r
+\r
+static ULLONG TxtPTSDifference(ULLONG pts1, ULLONG pts2)\r
+{\r
+ // Assume pts1, pts2 < 2^33; calculate pts1 - pts2\r
+ if (pts1 > pts2)\r
+ return pts1 - pts2;\r
+ else\r
+ return -pts1 + pts2;\r
+}\r
+\r
+UINT TeletextDecoderVBIEBU::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)\r
+{\r
+ if (mediapacket.type != MPTYPE_TELETEXT)\r
+ {\r
+ *samplepos= 0;\r
+ return 1; //Skip it! \r
+ }\r
+ unsigned int headerstrip;\r
+ unsigned char txtdata[43];\r
+ headerstrip=buffer[mediapacket.pos_buffer+8]+9;\r
+ //headerstrip+=4; //substream id\r
+ unsigned int datapos=0;\r
+ unsigned int datatype=buffer[mediapacket.pos_buffer+headerstrip+0];\r
+ //Chris should we use here the pts data from mediapacket ?\r
+ // in this case the data fields should also be added in mediamvp\r
+ if (mediapacket.synched)\r
+ { // An entry exists in the work list\r
+ ULLONG nowPTS = Video::getInstance()->getCurrentTimestamp();\r
+\r
+ ULLONG ptsdifference=TxtPTSDifference(mediapacket.pts, nowPTS);\r
+\r
+ if (ptsdifference >= (120LL*90000LL)) {\r
+ *samplepos=0;\r
+ return 1;//bad data skip it\r
+ }\r
+ if (nowPTS < (mediapacket.pts-4000) ) {\r
+ *samplepos=0;\r
+ return 0;\r
+ } \r
+ }\r
+ \r
+ if (( datatype>=0x10 && datatype <=0x1F) ||\r
+ ( datatype>=0x99 && datatype <=0x9B)) {\r
+ //EBU VBI DATA\r
+ datapos++;\r
+ while (datapos< (mediapacket.length-headerstrip)) {\r
+ unsigned int unit_id=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
+ datapos++;\r
+ unsigned int unit_length=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
+ datapos++;\r
+ switch (unit_id) {\r
+ case 0x02:\r
+ case 0x03: {//Teletext with and without subtitles\r
+ //call teletext decoder\r
+ unsigned int field=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
+\r
+ if ((datapos+44)< (mediapacket.length-headerstrip)) {\r
+ for (int i=0;i<42;i++) {\r
+ txtdata[i]=invtab[buffer[mediapacket.pos_buffer+headerstrip+datapos+2+i]];\r
+ }\r
+ DecodeTeletext(txtdata,field);\r
+ }\r
+ }break;\r
+ case 0xC0: //inverted Teletext\r
+ //call teletext decoder\r
+ break;\r
+ \r
+ case 0xC3: //VPS\r
+ //what to do with this, in the moment we do not need it\r
+ break;\r
+ case 0xC4: //WSS\r
+ //what to do with this, in the moment we do not need it\r
+ break;\r
+ case 0xC5: //CC\r
+ //what to do with this, in the moment we do not need it\r
+ break;\r
+ case 0xC6: //monochrome 4:2:2 samples, what is that? \r
+ //what to do with this, in the moment we do not need it\r
+ break;\r
+ default:\r
+ // case 0x00,0x01,0x04..0x7f,0x80..0xbf,0xc1,0xc2,0xc7..0xfe,0xff: //discard\r
+ //discard\r
+ break;\r
+ };\r
+ datapos+=unit_length;\r
+ // while (buffer[mediapacket.pos_buffer+headerstrip+datapos]==0xFF &&(datapos< (mediapacket.length-headerstrip))) {\r
+ // datapos++; //stuffing bytes\r
+ // }\r
+\r
+ \r
+ }\r
+ *samplepos=0;\r
+ return 1;\r
+\r
+\r
+ } else {\r
+ *samplepos= 0;\r
+ return 1; //Skip it! and discard data \r
+ }\r
+\r
+ return 0;\r
+\r
+}\r
+// This part is inspired by the vdr-plugin-osdteletext of Udo Richter and Marcel Wiesweg\r
+void TeletextDecoderVBIEBU::DecodeTeletext(const UCHAR* buffer, unsigned int field) //needs to be exactly 42 byte long!!\r
+{\r
+ UCHAR hdrbuf[5];\r
+ for (int i=0;i<5;i++) hdrbuf[i]=(unhamtab[buffer[2*i]]&0xF) | ((unhamtab[buffer[2*i+1]]&0xF)<< 4);\r
+ int header=hdrbuf[0];\r
+ int magazin=header & 0x7;\r
+ int line = (header>>3) & 0x1f;\r
+ if (magazin==0) magazin=8;\r
+ if (line==0)\r
+ {\r
+ if (ourpage) {\r
+ gotcha=true;\r
+ inkeying=false;\r
+ RenderTeletextCode(false);\r
+ } else {\r
+ RenderTeletextCode(true);\r
+ }\r
+ int pagenumber=hdrbuf[1];\r
+ int pagemagazin=magazin<<8 | pagenumber;\r
+ int pagesubnumber=(hdrbuf[2]) || ((hdrbuf[3]<<8) & 0x3f7f);\r
+\r
+ if (pagemagazin == selectedpage) ourpage=true;\r
+ else ourpage=false;\r
+ if (isrecording) {\r
+ for (int i=0;i<10;i++) {\r
+ if (pagemagazin==record_pages[i]) break;\r
+ if (record_pages[i]==-1) {\r
+ record_pages[i]=pagemagazin;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ if (hdrbuf[3] &0x80) { //This is a subtitle\r
+ for (int i=0;i<10;i++) {\r
+ if (pagemagazin==record_pages[i]) break;\r
+ if (record_pages[i]==-1) {\r
+ record_pages[i]=pagemagazin;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ if (ourpage) {\r
+ lang=((hdrbuf[4]>>5) & 0x07);\r
+ flags=hdrbuf[2] & 0x80;\r
+ flags|=(hdrbuf[3]&0x40)|((hdrbuf[3]>>2)&0x20); //??????\r
+ flags|=((hdrbuf[4]<<4)&0x10)|((hdrbuf[4]<<2)&0x08)|(hdrbuf[4]&0x04)|((hdrbuf[4]>>1)&0x02)|((hdrbuf[4]>>4)&0x01);\r
+ for (int i=0;i<25;i++) {\r
+ memset(curpage[i],0,40);\r
+ }\r
+ }\r
+ \r
+ memcpy(curpage[line],buffer+2,40);\r
+ } else if (ourpage && (line<=25)) {\r
+ memcpy(curpage[line],buffer+2,40);\r
+ \r
+ }\r
+}\r
+\r
+\r
+/* from osdteletext plugin: (slightly adapted for vomp)*/\r
+// Font tables\r
+\r
+// teletext uses 7-bit numbers to identify a font set.\r
+// There are three font sets involved:\r
+// Primary G0, Secondary G0, and G2 font set.\r
+\r
+// Font tables are organized in blocks of 8 fonts:\r
+\r
+enumCharsets FontBlockG0_0000[8] = {\r
+ CHARSET_LATIN_G0_EN,\r
+ CHARSET_LATIN_G0_DE,\r
+ CHARSET_LATIN_G0_SV_FI,\r
+ CHARSET_LATIN_G0_IT,\r
+ CHARSET_LATIN_G0_FR,\r
+ CHARSET_LATIN_G0_PT_ES,\r
+ CHARSET_LATIN_G0_CZ_SK,\r
+ CHARSET_LATIN_G0\r
+};\r
+\r
+enumCharsets FontBlockG2Latin[8]={\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_LATIN_G2\r
+};\r
+\r
+enumCharsets FontBlockG0_0001[8] = {\r
+ CHARSET_LATIN_G0_PL,\r
+ CHARSET_LATIN_G0_DE,\r
+ CHARSET_LATIN_G0_SV_FI,\r
+ CHARSET_LATIN_G0_IT,\r
+ CHARSET_LATIN_G0_FR,\r
+ CHARSET_LATIN_G0,\r
+ CHARSET_LATIN_G0_CZ_SK,\r
+ CHARSET_LATIN_G0\r
+};\r
+\r
+enumCharsets FontBlockG0_0010[8] = {\r
+ CHARSET_LATIN_G0_EN,\r
+ CHARSET_LATIN_G0_DE,\r
+ CHARSET_LATIN_G0_SV_FI,\r
+ CHARSET_LATIN_G0_IT,\r
+ CHARSET_LATIN_G0_FR,\r
+ CHARSET_LATIN_G0_PT_ES,\r
+ CHARSET_LATIN_G0_TR,\r
+ CHARSET_LATIN_G0\r
+};\r
+\r
+\r
+enumCharsets FontBlockG0_0011[8] = {\r
+ CHARSET_LATIN_G0,\r
+ CHARSET_LATIN_G0,\r
+ CHARSET_LATIN_G0,\r
+ CHARSET_LATIN_G0,\r
+ CHARSET_LATIN_G0,\r
+ CHARSET_LATIN_G0_SR_HR_SL,\r
+ CHARSET_LATIN_G0,\r
+ CHARSET_LATIN_G0_RO\r
+};\r
+\r
+enumCharsets FontBlockG0_0100[8] = {\r
+ CHARSET_CYRILLIC_G0_SR_HR,\r
+ CHARSET_LATIN_G0_DE,\r
+ CHARSET_LATIN_G0_EE,\r
+ CHARSET_LATIN_G0_LV_LT,\r
+ CHARSET_CYRILLIC_G0_RU_BG,\r
+ CHARSET_CYRILLIC_G0_UK,\r
+ CHARSET_LATIN_G0_CZ_SK,\r
+ CHARSET_INVALID\r
+};\r
+\r
+enumCharsets FontBlockG2_0100[8] = {\r
+ CHARSET_CYRILLIC_G2,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_CYRILLIC_G2,\r
+ CHARSET_CYRILLIC_G2,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_INVALID\r
+};\r
+\r
+enumCharsets FontBlockG0_0110[8] = {\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_LATIN_G0_TR,\r
+ CHARSET_GREEK_G0\r
+};\r
+\r
+enumCharsets FontBlockG2_0110[8] = {\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_LATIN_G2,\r
+ CHARSET_GREEK_G2\r
+};\r
+\r
+enumCharsets FontBlockG0_1000[8] = {\r
+ CHARSET_LATIN_G0_EN,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_LATIN_G0_FR,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_ARABIC_G0\r
+};\r
+\r
+enumCharsets FontBlockG2_1000[8] = {\r
+ CHARSET_ARABIC_G2,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_ARABIC_G2,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_ARABIC_G2\r
+};\r
+\r
+enumCharsets FontBlockG0_1010[8] = {\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_HEBREW_G0,\r
+ CHARSET_INVALID,\r
+ CHARSET_ARABIC_G0,\r
+};\r
+\r
+enumCharsets FontBlockG2_1010[8] = {\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_ARABIC_G2,\r
+ CHARSET_INVALID,\r
+ CHARSET_ARABIC_G2,\r
+};\r
+\r
+enumCharsets FontBlockInvalid[8] = {\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID,\r
+ CHARSET_INVALID\r
+};\r
+\r
+\r
+\r
+// The actual font table definition:\r
+// Split the 7-bit number into upper 4 and lower 3 bits,\r
+// use upper 4 bits for outer array,\r
+// use lower 3 bits for inner array\r
+\r
+struct structFontBlock {\r
+ enumCharsets *G0Block;\r
+ enumCharsets *G2Block;\r
+};\r
+ \r
+structFontBlock FontTable[16] = {\r
+ { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block\r
+ { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block\r
+ { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block\r
+ { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block\r
+ { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block\r
+ { FontBlockInvalid, FontBlockInvalid }, // 0101 block\r
+ { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block\r
+ { FontBlockInvalid, FontBlockInvalid }, // 0111 block\r
+ { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block\r
+ { FontBlockInvalid, FontBlockInvalid }, // 1001 block\r
+ { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block\r
+ { FontBlockInvalid, FontBlockInvalid }, // 1011 block\r
+ { FontBlockInvalid, FontBlockInvalid }, // 1100 block\r
+ { FontBlockInvalid, FontBlockInvalid }, // 1101 block\r
+ { FontBlockInvalid, FontBlockInvalid }, // 1110 block\r
+ { FontBlockInvalid, FontBlockInvalid } // 1111 block\r
+};\r
+\r
+inline enumCharsets GetG0Charset(int codepage) {\r
+ return FontTable[codepage>>3].G0Block[codepage&7];\r
+}\r
+inline enumCharsets GetG2Charset(int codepage) {\r
+ return FontTable[codepage>>3].G2Block[codepage&7];\r
+}\r
+\r
+enum enumSizeMode {\r
+ // Possible size modifications of characters\r
+ sizeNormal,\r
+ sizeDoubleWidth,\r
+ sizeDoubleHeight,\r
+ sizeDoubleSize\r
+};\r
+\r
+void TeletextDecoderVBIEBU::RenderTeletextCode(bool renderfirstlineonly) {\r
+ int x,y;\r
+ bool EmptyNextLine=false;\r
+ // Skip one line, in case double height chars were/will be used\r
+\r
+ // Get code pages:\r
+ int LocalG0CodePage=(FirstG0CodePage & 0x78) \r
+ | ((lang & 0x04)>>2) | (lang & 0x02) | ((lang & 0x01)<<2);\r
+ enumCharsets FirstG0=GetG0Charset(LocalG0CodePage);\r
+ enumCharsets SecondG0=GetG0Charset(SecondG0CodePage);\r
+ // Reserved for later use:\r
+ // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage);\r
+ \r
+ for (y=0;y<24;(EmptyNextLine?y+=2:y++)) {\r
+ // Start of line: Set start of line defaults\r
+ \r
+ // Hold Mosaics mode: Remember last mosaic char/charset \r
+ // for next spacing code\r
+ bool HoldMosaics=false;\r
+ unsigned char HoldMosaicChar=' ';\r
+ enumCharsets HoldMosaicCharset=FirstG0;\r
+\r
+ enumSizeMode Size=sizeNormal;\r
+ // Font size modification\r
+ bool SecondCharset=false;\r
+ // Use primary or secondary G0 charset\r
+ bool GraphicCharset=false;\r
+ // Graphics charset used?\r
+ bool SeparateGraphics=false;\r
+ // Use separated vs. contiguous graphics charset\r
+ bool NoNextChar=false;\r
+ // Skip display of next char, for double-width\r
+ EmptyNextLine=false;\r
+ // Skip next line, for double-height\r
+\r
+ cTeletextChar c;\r
+ // auto.initialized to everything off\r
+ c.SetFGColor(ttcWhite);\r
+ c.SetBGColor(ttcBlack);\r
+ c.SetCharset(FirstG0);\r
+ \r
+ if (y==0 && (flags&0x10)) {\r
+ if (!inkeying ) c.SetBoxedOut(true);\r
+ \r
+ }\r
+ if (flags&0x60) {\r
+ if (!(inkeying && y==0) ) c.SetBoxedOut(true);\r
+ \r
+ }\r
+ if (y==0) {\r
+ \r
+ for (x=0;x<8;x++) {\r
+ cTeletextChar c2=c;\r
+ \r
+ if (x>=3 && x<6){\r
+ c2.SetChar(keyindigits[x-3]);\r
+\r
+ }\r
+ else\r
+ c2.SetChar(' ');\r
+ setChar(x,0,c2);\r
+ }\r
+ }\r
+\r
+ // Pre-scan for double-height and double-size codes\r
+ for (x=0;x<40;x++) {\r
+ if (y==0 && x<8) x=8;\r
+ if ((curpage[y][x] & 0x7f)==0x0D || (curpage[y][x] & 0x7f)==0x0F)\r
+ EmptyNextLine=true;\r
+ }\r
+\r
+ // Move through line\r
+ for (x=0;x<40;x++) {\r
+ unsigned char ttc=curpage[y][x] & 0x7f;\r
+ // skip parity check\r
+\r
+ if (y==0 && x<8) continue;\r
+ if (y==0 && x<31 && renderfirstlineonly && gotcha && !inkeying) continue;\r
+ // no displayable data here...\r
+ \r
+/* // Debug only: Output line data and spacing codes\r
+ if (y==6) {\r
+ if (ttc<0x20)\r
+ printf("%s ",names[ttc]);\r
+ else\r
+ printf("%02x ",ttc);\r
+ if (x==39) printf("\n");\r
+ }\r
+*/ \r
+ \r
+ // Handle all 'Set-At' spacing codes\r
+ switch (ttc) {\r
+ case 0x09: // Steady\r
+ c.SetBlink(false);\r
+ break;\r
+ case 0x0C: // Normal Size\r
+ if (Size!=sizeNormal) {\r
+ Size=sizeNormal;\r
+ HoldMosaicChar=' ';\r
+ HoldMosaicCharset=FirstG0;\r
+ } \r
+ break;\r
+ case 0x18: // Conceal\r
+ c.SetConceal(true);\r
+ break;\r
+ case 0x19: // Contiguous Mosaic Graphics\r
+ SeparateGraphics=false;\r
+ if (GraphicCharset)\r
+ c.SetCharset(CHARSET_GRAPHICS_G1);\r
+ break;\r
+ case 0x1A: // Separated Mosaic Graphics\r
+ SeparateGraphics=true;\r
+ if (GraphicCharset)\r
+ c.SetCharset(CHARSET_GRAPHICS_G1_SEP);\r
+ break;\r
+ case 0x1C: // Black Background\r
+ c.SetBGColor(ttcBlack);\r
+ break;\r
+ case 0x1D: // New Background\r
+ c.SetBGColor(c.GetFGColor());\r
+ break;\r
+ case 0x1E: // Hold Mosaic\r
+ HoldMosaics=true; \r
+ break;\r
+ }\r
+\r
+ // temporary copy of character data:\r
+ cTeletextChar c2=c;\r
+ // c2 will be text character or space character or hold mosaic\r
+ // c2 may also have temporary flags or charsets\r
+ \r
+ if (ttc<0x20) {\r
+ // Spacing code, display space or hold mosaic\r
+ if (HoldMosaics) {\r
+ c2.SetChar(HoldMosaicChar);\r
+ c2.SetCharset(HoldMosaicCharset);\r
+ } else {\r
+ c2.SetChar(' ');\r
+ }\r
+ } else {\r
+ // Character code \r
+ c2.SetChar(ttc);\r
+ if (GraphicCharset) {\r
+ if (ttc&0x20) {\r
+ // real graphics code, remember for HoldMosaics\r
+ HoldMosaicChar=ttc;\r
+ HoldMosaicCharset=c.GetCharset();\r
+ } else {\r
+ // invalid code, pass-through to G0\r
+ c2.SetCharset(SecondCharset?SecondG0:FirstG0);\r
+ } \r
+ }\r
+ }\r
+ \r
+ // Handle double-height and double-width extremes\r
+ if (y>=23) {\r
+ if (Size==sizeDoubleHeight) Size=sizeNormal;\r
+ if (Size==sizeDoubleSize) Size=sizeDoubleWidth;\r
+ }\r
+ if (x>=38) {\r
+ if (Size==sizeDoubleWidth) Size=sizeNormal;\r
+ if (Size==sizeDoubleSize) Size=sizeDoubleHeight;\r
+ }\r
+ \r
+ // Now set character code\r
+ \r
+ if (NoNextChar) {\r
+ // Suppress this char due to double width last char\r
+ NoNextChar=false;\r
+ } else {\r
+ switch (Size) {\r
+ case sizeNormal:\r
+ // Normal sized\r
+ setChar(x,y,c2);\r
+ if (EmptyNextLine && y<23) {\r
+ // Clean up next line\r
+ setChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
+ }\r
+ break;\r
+ case sizeDoubleWidth:\r
+ // Double width\r
+ setChar(x,y,c2.ToDblWidth(dblw_Left));\r
+ setChar(x+1,y,c2.ToDblWidth(dblw_Right));\r
+ if (EmptyNextLine && y<23) {\r
+ // Clean up next line\r
+ setChar(x ,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
+ setChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
+ }\r
+ NoNextChar=true;\r
+ break;\r
+ case sizeDoubleHeight:\r
+ // Double height\r
+ setChar(x,y,c2.ToDblHeight(dblh_Top));\r
+ setChar(x,y+1,c2.ToDblHeight(dblh_Bottom));\r
+ break;\r
+ case sizeDoubleSize:\r
+ // Double Size\r
+ setChar(x , y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Left ));\r
+ setChar(x+1, y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Right));\r
+ setChar(x ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left ));\r
+ setChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right));\r
+ NoNextChar=true;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ // Handle all 'Set-After' spacing codes\r
+ if (ttc>=0x00 && ttc<=0x07) { // Set FG color\r
+ if (GraphicCharset) {\r
+ // Actual switch from graphics charset\r
+ HoldMosaicChar=' ';\r
+ HoldMosaicCharset=FirstG0;\r
+ }\r
+ c.SetFGColor((enumTeletextColor)ttc);\r
+ c.SetCharset(SecondCharset?SecondG0:FirstG0);\r
+ GraphicCharset=false;\r
+ c.SetConceal(false);\r
+ } else if (ttc==0x08) {\r
+ c.SetBlink(true);\r
+ } else if (ttc==0x0A) {\r
+ c.SetBoxedOut(true);\r
+ } else if (ttc==0x0B) {\r
+ // Start Box\r
+ c.SetBoxedOut(false);\r
+ } else if (ttc==0x0D) {\r
+ if (Size!=sizeDoubleHeight) {\r
+ Size=sizeDoubleHeight;\r
+ HoldMosaicChar=' ';\r
+ HoldMosaicCharset=FirstG0;\r
+ } \r
+ } else if (ttc==0x0E) {\r
+ if (Size!=sizeDoubleWidth) {\r
+ Size=sizeDoubleWidth;\r
+ HoldMosaicChar=' ';\r
+ HoldMosaicCharset=FirstG0;\r
+ } \r
+ } else if (ttc==0x0E) {\r
+ if (Size!=sizeDoubleSize) {\r
+ Size=sizeDoubleSize;\r
+ HoldMosaicChar=' ';\r
+ HoldMosaicCharset=FirstG0;\r
+ } \r
+ } else if (ttc>=0x10 && ttc<=0x17) { \r
+ if (!GraphicCharset) {\r
+ // Actual switch to graphics charset\r
+ HoldMosaicChar=' ';\r
+ HoldMosaicCharset=FirstG0;\r
+ }\r
+ c.SetFGColor((enumTeletextColor)(ttc-0x10));\r
+ c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1);\r
+ GraphicCharset=true;\r
+ c.SetConceal(false);\r
+ } else if (ttc==0x1B) {\r
+ SecondCharset=!SecondCharset;\r
+ if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0);\r
+ } else if (ttc==0x1F) {\r
+ HoldMosaics=false;\r
+ }\r
+ \r
+ } // end for x\r
+ if (renderfirstlineonly) break;\r
+ } // end for y\r
+ \r
+ for (x=0;x<40;x++) {\r
+ // Clean out last line\r
+ cTeletextChar c;\r
+ c.SetFGColor(ttcWhite);\r
+ c.SetBGColor(ttcBlack);\r
+ c.SetCharset(FirstG0);\r
+ c.SetChar(' ');\r
+ if (flags&0x60) {\r
+ c.SetBoxedOut(true); \r
+ }\r
+ setChar(x,24,c);\r
+ } \r
+ for (y=0;y<25;y++) {\r
+ for (x=0;x<40;x++) {\r
+ if (isDirty(x,y)) {\r
+ dirty=true;\r
+ break;\r
+ }\r
+ if (dirty) break;\r
+ }\r
+ if (dirty) break;\r
+ }\r
+ \r
+ if (dirty && txtview!=NULL ) {\r
+ \r
+ if ( !renderfirstlineonly) {\r
+ Message* m= new Message();\r
+ m->message = Message::TELETEXTUPDATE;\r
+ m->to = txtview;\r
+ m->from = this;\r
+ m->parameter = 0;\r
+ Command::getInstance()->postMessageFromOuterSpace(m);\r
+ } else if (firstlineupdate==10) {\r
+ Message* m= new Message();\r
+ m->message = Message::TELETEXTUPDATEFIRSTLINE;\r
+ m->to = txtview;\r
+ m->from = this;\r
+ m->parameter = 0;\r
+ Command::getInstance()->postMessageFromOuterSpace(m);\r
+ firstlineupdate=0;\r
+ } else firstlineupdate++;\r
+ \r
+ \r
+ }\r
+ \r
+}\r
-/*\r
- Copyright 2008 Marten Richter\r
-\r
- This file is part of VOMP.\r
-\r
+/*\r\r
+ Copyright 2008 Marten Richter\r\r
+ This file is part of VOMP.\r\r
VOMP is free software; you can redistribute it and/or modify\r
it under the terms of the GNU General Public License as published by\r
the Free Software Foundation; either version 2 of the License, or\r
- (at your option) any later version.\r
-\r
+ (at your option) any later version.\r\r
VOMP is distributed in the hope that it will be useful,\r
but WITHOUT ANY WARRANTY; without even the implied warranty of\r
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
+ GNU General Public License for more details.\r\r
You should have received a copy of the GNU General Public License\r
along with VOMP; if not, write to the Free Software\r
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
-*/\r
-\r
-#include "tfeed.h"\r
-\r
-#include "log.h"\r
-#include "demuxer.h"\r
-#include "callback.h"\r
-\r
-TFeed::TFeed(Callback* tcb)\r
-: cb(*tcb)\r
-{\r
- teletextEnabled = 1;\r
-}\r
-\r
-int TFeed::init()\r
-{\r
- return 1;\r
-}\r
-\r
-int TFeed::shutdown()\r
-{\r
- // FIXME\r
- return 1;\r
-}\r
-\r
-void TFeed::disable()\r
-{\r
- teletextEnabled = 0;\r
-}\r
-\r
+*/\r\r
+\r\r
+#include "tfeed.h"\r\r
+#include "log.h"\r#include "demuxer.h"\r#include "callback.h"\r\r
+\r\r
+TFeed::TFeed(Callback* tcb)\r: cb(*tcb)\r{\r teletextEnabled = 1;\r}\r\r
+\r\r
+int TFeed::init()\r{\r return 1;\r}\r\r
+\r\r
+int TFeed::shutdown()\r{\r\r
+ // FIXME\r return 1;\r}\r\r
+\r\r
+void TFeed::disable()\r\r
+{\r teletextEnabled = 0;\r
+}\r\r
+\r\r
void TFeed::enable()\r
-{\r
- teletextEnabled = 1;\r
-}\r
-\r
+{\r teletextEnabled = 1;\r\r
+}\r\r
+\r\r
int TFeed::start()\r
{\r
teletextEnabled = 1;\r
return threadStart();\r
-}\r
-\r
+}\r\r
+\r\r
void TFeed::stop()\r
{\r
threadCancel();\r
-}\r
-\r
+}\r\r
+\r\r
void TFeed::threadMethod()\r
{\r
- bool tlen;\r
-\r
- while(1)\r
- {\r
+ bool tlen;\r\r
+ while(1)\r {\r
threadCheckExit();\r
-\r
- \r
- tlen = Demuxer::getInstance()->writeTeletext();\r
-\r
+ tlen = Demuxer::getInstance()->writeTeletext();\r\r
if (tlen)\r
{\r
cb.call(this);\r
//MILLISLEEP(100);\r
MILLISLEEP(20); //Performance Issue Marten\r
}\r
- \r
}\r
-}\r
+}\r
\ No newline at end of file
-/*\r
- Copyright 2008 Marten Richter\r
-\r
- This file is part of VOMP.\r
-\r
+/*\r Copyright 2008 Marten Richter\r\r
+ This file is part of VOMP.\r\r
VOMP is free software; you can redistribute it and/or modify\r
it under the terms of the GNU General Public License as published by\r
the Free Software Foundation; either version 2 of the License, or\r
- (at your option) any later version.\r
-\r
+ (at your option) any later version.\r\r
VOMP is distributed in the hope that it will be useful,\r
but WITHOUT ANY WARRANTY; without even the implied warranty of\r
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
+ GNU General Public License for more details.\r\r
You should have received a copy of the GNU General Public License\r
along with VOMP; if not, write to the Free Software\r
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
-*/\r
-\r
-#ifndef TFEED_H\r
-#define TFEED_H\r
-\r
-#include <stdio.h>\r
-#include <time.h>\r
-\r
-#ifdef WIN32\r
-#include "threadwin.h"\r
-#else\r
-#include "threadp.h"\r
-#endif\r
-\r
-class Callback;\r
-\r
-class TFeed : public Thread_TYPE\r
-{\r
- public:\r
- TFeed(Callback* tcb);\r
-\r
- int init();\r
- int shutdown();\r
-\r
- int start();\r
- void stop();\r
- void enable();\r
- void disable();\r
-\r
- private:\r
- void threadMethod();\r
- void threadPostStopCleanup() {};\r
- int teletextEnabled;\r
- Callback& cb;\r
-};\r
-\r
-#endif\r
+*/\r\r\r
+#ifndef TFEED_H\r#define TFEED_H\r\r
+#include <stdio.h>\r#include <time.h>\r\r
+#include "threadsystem.h"\r\r
+class Callback;\r\r
+class TFeed: public Thread_TYPE {\rpublic:\r TFeed(Callback* tcb);\r int init();\r int shutdown();\r int start();\r void stop();\r void enable();\r void disable();\r\rprivate:\r\r void threadMethod();\r void threadPostStopCleanup() {\r };\r\r int teletextEnabled;\r Callback& cb;\r};\r\r
+\r\r
+#endif\r\r
this->threadPostStopCleanup();
}
+
void ThreadP::threadCancel()
{
threadActive = 0;
this->threadPostStopCleanup();
}
+
void ThreadP::threadCheckExit()
{
if (!threadActive) pthread_exit(NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
}
+
pthread_t ThreadP::getThreadID() // returns the ID of this thread
{
return pthread;
void threadSignalNoLock(); // same as above but without locking guarantees. probably not a good idea.
// Methods to use from inside the thread
+
void threadSetKillable(); // allows threadCancel() to work
void threadCheckExit(); // terminates thread if threadStop() has been called
void threadWaitForSignal(); // pauses thread until threadSignal() is called
#include <stdio.h>
#include <list>
-#ifndef WIN32
-#include "threadp.h"
-#else
-#include "threadwin.h"
-#endif
+#include "threadsystem.h"
#include "defines.h"
int retval;
while(1)
{
- retval = ds->waitforMessage(0);
+ retval = ds->waitforMessage(1);
if (retval == 0)
{
}
else if (retval == 1)
{
+ threadCheckExit();
continue;
}
else
{
processRequest((UCHAR*)ds->getData(), ds->getDataLength());
}
+ threadCheckExit();
}
}
#include "defines.h"
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
+#include "threadsystem.h"
class DatagramSocket;
class MessageQueue;
VChannelList::~VChannelList()
{
+
if (chanList)
{
for (UINT i = 0; i < chanList->size(); i++)
void VChannelList::processMessage(Message* m)
{
- if (m->message == Message::MOUSE_MOVE)
+ /* if (m->message == Message::MOUSE_MOVE) {
+ if (sl.mouseAndroidScroll((m->tag >> 16),(m->tag & 0xFFFF),
+ (m->parameter >> 16),(m->parameter & 0xFFFF))) {
+ sl.draw();
+ doShowingBar();
+ boxstack->update(this);
+ }
+ }
+ else */if (m->message == Message::MOUSE_MOVE)
{
if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
{
-/*
- Copyright 2004-2005 Chris Tallon, Andreas Vogel
-
- 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 "vcolourtuner.h"
-
-#include "wsymbol.h"
-#include "remote.h"
-#include "colour.h"
-#include "video.h"
-#include "vinfo.h"
-#include "boxstack.h"
-#include "i18n.h"
-#include "log.h"
-#include "mediaoptions.h"
-
-#define PICTUREFILE "/colourtest.jpg"
-
-int VColourTuner::rfactor=100;
-int VColourTuner::gfactor=100;
-int VColourTuner::bfactor=100;
-
-VColourTuner::VColourTuner()
-{
- int sw= Video::getInstance()->getScreenWidth();
- int sh= Video::getInstance()->getScreenHeight();
- setSize(sw-80,sh-40);
- setPosition((sw-area.w)/2, (sh-area.h)/2);
- createBuffer();
- setTitleBarOn(0);
- picture.setPosition(160,60);
- add(&picture);
- drawPicture=true;
- vrfactor=rfactor;
- vbfactor=bfactor;
- vgfactor=gfactor;
- hasChanged=false;
- Log::getInstance()->log("VColourTuner",Log::DEBUG,"created %p",this);
-}
-
-VColourTuner::~VColourTuner()
-{
- Log::getInstance()->log("VColourTuner",Log::DEBUG,"deleted %p",this);
-}
-
-void VColourTuner::drawBox(int x, int y, int w, int h, Colour &c) {
- for (int row=y;row<y+h;row++)
- for (int col=x;col<x+w;col++) {
- surface->drawPixel(col,row,c);
- }
-}
-
-
-void VColourTuner::draw()
-{
- //do not call base classes draw to avoid drawing the picture...
- Log::getInstance()->log("VColourTuner::draw",Log::DEBUG,"dp %s, rf=%d, gf=%d, bf=%d",
- (drawPicture?"true":"false"),vrfactor,vgfactor,vbfactor);
- char valbuf[20];
- int x=20;
- int y=20;
- int bw=50;
- int bh=50;
- int picx=picture.getX();
- Colour bc=Colour(140,140,140);
- fillColour(bc);
- bc=Colour(255,255,255);
- drawText(tr("Colour Tuning"), x+20, y+5, Colour::LIGHTTEXT);
- drawBox(x, y+50, bw, bh, Colour::RED);
- drawBox(x, y+130, bw, bh, Colour::GREEN);
- drawBox(x, y+190, bw, bh, Colour::BLUE);
- drawBox(x, y+270, bw, bh, bc);
- sprintf(valbuf,"%03d%%",vrfactor);
- drawText(valbuf,x+bw+x,y+50, Colour::LIGHTTEXT);
- drawText("<1 2>",x+bw+x,y+74, Colour::LIGHTTEXT);
- sprintf(valbuf,"%03d%%",vgfactor);
- drawText(valbuf,x+bw+x,y+120, Colour::LIGHTTEXT);
- drawText("<4 5>",x+bw+x,y+144, Colour::LIGHTTEXT);
- sprintf(valbuf,"%03d%%",vbfactor);
- drawText(valbuf,x+bw+x,y+190, Colour::LIGHTTEXT);
- drawText("<7 8>",x+bw+x,y+214, Colour::LIGHTTEXT);
- sprintf(valbuf,"%03d%%",(vbfactor+vgfactor+vrfactor)/3);
- drawText(valbuf,x+bw+x,y+270, Colour::LIGHTTEXT);
- drawText("<3 6>",x+bw+x,y+294, Colour::LIGHTTEXT);
- drawText("9 norm",x+bw+x,y+318, Colour::LIGHTTEXT);
- drawText(tr("OK to save, BACK to cancel"), x+20, area.h - 50, Colour::LIGHTTEXT);
- if (drawPicture) {
- hasChanged=false;
- picture.init(PICTUREFILE);
- picture.draw();
- drawPicture=false;
- }
- int picy=picture.getY();
- int pich=picture.getHeight();
- if (hasChanged) drawText(tr("0 to draw picture"), picx+30, picy+pich+10, Colour::LIGHTTEXT);
-}
-
-int VColourTuner::handleCommand(int command)
-{
- int rt=0;
- switch(command) {
- case Remote::ONE:
- updateFactor(1,-1);
- rt=2;
- hasChanged=true;
- break;
- case Remote::TWO:
- updateFactor(1,1);
- rt=2;
- hasChanged=true;
- break;
- case Remote::FOUR:
- updateFactor(2,-1);
- rt=2;
- hasChanged=true;
- break;
- case Remote::FIVE:
- updateFactor(2,1);
- rt=2;
- hasChanged=true;
- break;
- case Remote::SEVEN:
- updateFactor(3,-1);
- rt=2;
- hasChanged=true;
- break;
- case Remote::EIGHT:
- updateFactor(3,1);
- hasChanged=true;
- rt=2;
- break;
- case Remote::THREE:
- updateFactor(4,-1);
- hasChanged=true;
- rt=2;
- break;
- case Remote::SIX:
- updateFactor(4,1);
- hasChanged=true;
- rt=2;
- break;
- case Remote::NINE:
- updateFactor(5,0);
- hasChanged=true;
- rt=2;
- break;
- case Remote::ZERO:
- drawPicture=true;
- rt=2;
- break;
- case Remote::BACK:
- vrfactor=rfactor;
- vgfactor=gfactor;
- vbfactor=bfactor;
-#ifndef WIN32
-#ifndef _MIPS_ARCH
- ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);
-#endif
-#endif
- rt=4;
- break;
- case Remote::OK:
- rfactor=vrfactor;
- gfactor=vgfactor;
- bfactor=vbfactor;
- MediaOptions::getInstance()->setIntOption("FactorRed",rfactor);
- MediaOptions::getInstance()->setIntOption("FactorGreen",gfactor);
- MediaOptions::getInstance()->setIntOption("FactorBlue",bfactor);
- rt=4;
- break;
- }
- if (rt == 2) {
-#ifndef WIN32
-#ifndef _MIPS_ARCH
- ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);
-#endif
-#endif
- bool updateAll=drawPicture;
- draw();
- if (updateAll) {
- BoxStack::getInstance()->update(this);
- }
- else {
- Region r;
- r.x=0;
- r.w=picture.getX()-1;
- r.y=0;
- r.h=area.h;
- BoxStack::getInstance()->update(this,&r);
- r.x=picture.getX();
- r.y=picture.getY();
- r.h=area.h-r.y;
- r.w=area.w-picture.getX();
- BoxStack::getInstance()->update(this,&r);
- }
- }
- return rt;
-}
-
-
-
-void VColourTuner::processMessage(Message* m)
-{
- if (m->message == Message::MOUSE_MOVE)
- {
-
- }
- else if (m->message == Message::MOUSE_LBDOWN)
- {
- //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::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
- }
- else if (y>=(int)area.h-24 && y<=(int)area.h-6)
- {
- ;
- }
- }
-}
-
-void VColourTuner::updateFactor(int color, int amount) {
- switch (color) {
- case 1:
- vrfactor+=amount;
- if (vrfactor < 20 ) vrfactor=20;
- if (vrfactor > 200) vrfactor=200;
- break;
- case 2:
- vgfactor+=amount;
- if (vgfactor < 20 ) vgfactor=20;
- if (vgfactor > 200) vgfactor=200;
- break;
- case 3:
- vbfactor+=amount;
- if (vbfactor < 20 ) vbfactor=20;
- if (vbfactor > 200) vbfactor=200;
- break;
- case 4:
- updateFactor(1,amount);
- updateFactor(2,amount);
- updateFactor(3,amount);
- break;
- case 5:
- while ((vrfactor+vbfactor+vgfactor) > 300) updateFactor(4,-1);
- while ((vrfactor+vbfactor+vgfactor) < 300) updateFactor(4,1);
- }
-}
-
-void VColourTuner::initFactors(){
- MediaOptions * options=MediaOptions::getInstance();
- int rf=options->getIntOption("FactorRed");
- int gf=options->getIntOption("FactorGreen");
- int bf=options->getIntOption("FactorBlue");
- if (rf >= 20 && bf >= 20 && gf >= 20)
- rfactor=rf;
- gfactor=gf;
- bfactor=bf;
- Log::getInstance()->log("VColourTuner",Log::DEBUG,"setting initial factors r=%d,g=%d,b=%d",rf,gf,bf);
-#ifndef WIN32
-#ifndef _MIPS_ARCH
- Surface_TYPE::initConversionTables(rfactor,gfactor,bfactor);
-#endif
-#endif
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon, Andreas Vogel\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vcolourtuner.h"\r
+\r
+#include "wsymbol.h"\r
+#include "remote.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "vinfo.h"\r
+#include "boxstack.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+#include "mediaoptions.h"\r
+\r
+#define PICTUREFILE "/colourtest.jpg"\r
+\r
+int VColourTuner::rfactor=100;\r
+int VColourTuner::gfactor=100;\r
+int VColourTuner::bfactor=100;\r
+\r
+VColourTuner::VColourTuner()\r
+{\r
+ int sw= Video::getInstance()->getScreenWidth();\r
+ int sh= Video::getInstance()->getScreenHeight();\r
+ setSize(sw-80,sh-40);\r
+ setPosition((sw-area.w)/2, (sh-area.h)/2);\r
+ createBuffer();\r
+ setTitleBarOn(0);\r
+ picture.setPosition(160,60);\r
+ add(&picture);\r
+ drawPicture=true;\r
+ vrfactor=rfactor;\r
+ vbfactor=bfactor;\r
+ vgfactor=gfactor;\r
+ hasChanged=false;\r
+ Log::getInstance()->log("VColourTuner",Log::DEBUG,"created %p",this);\r
+}\r
+\r
+VColourTuner::~VColourTuner()\r
+{\r
+ Log::getInstance()->log("VColourTuner",Log::DEBUG,"deleted %p",this);\r
+}\r
+\r
+void VColourTuner::drawBox(int x, int y, int w, int h, Colour &c) {\r
+ for (int row=y;row<y+h;row++)\r
+ for (int col=x;col<x+w;col++) {\r
+ surface->drawPixel(col,row,c);\r
+ }\r
+}\r
+\r
+\r
+void VColourTuner::draw()\r
+{\r
+ //do not call base classes draw to avoid drawing the picture...\r
+ Log::getInstance()->log("VColourTuner::draw",Log::DEBUG,"dp %s, rf=%d, gf=%d, bf=%d",\r
+ (drawPicture?"true":"false"),vrfactor,vgfactor,vbfactor);\r
+ char valbuf[20];\r
+ int x=20;\r
+ int y=20;\r
+ int bw=50;\r
+ int bh=50;\r
+ int picx=picture.getX();\r
+ Colour bc=Colour(140,140,140);\r
+ fillColour(bc);\r
+ bc=Colour(255,255,255);\r
+ drawText(tr("Colour Tuning"), x+20, y+5, Colour::LIGHTTEXT);\r
+ drawBox(x, y+50, bw, bh, Colour::RED);\r
+ drawBox(x, y+130, bw, bh, Colour::GREEN);\r
+ drawBox(x, y+190, bw, bh, Colour::BLUE);\r
+ drawBox(x, y+270, bw, bh, bc);\r
+ sprintf(valbuf,"%03d%%",vrfactor);\r
+ drawText(valbuf,x+bw+x,y+50, Colour::LIGHTTEXT);\r
+ drawText("<1 2>",x+bw+x,y+74, Colour::LIGHTTEXT);\r
+ sprintf(valbuf,"%03d%%",vgfactor);\r
+ drawText(valbuf,x+bw+x,y+120, Colour::LIGHTTEXT);\r
+ drawText("<4 5>",x+bw+x,y+144, Colour::LIGHTTEXT);\r
+ sprintf(valbuf,"%03d%%",vbfactor);\r
+ drawText(valbuf,x+bw+x,y+190, Colour::LIGHTTEXT);\r
+ drawText("<7 8>",x+bw+x,y+214, Colour::LIGHTTEXT);\r
+ sprintf(valbuf,"%03d%%",(vbfactor+vgfactor+vrfactor)/3);\r
+ drawText(valbuf,x+bw+x,y+270, Colour::LIGHTTEXT);\r
+ drawText("<3 6>",x+bw+x,y+294, Colour::LIGHTTEXT);\r
+ drawText("9 norm",x+bw+x,y+318, Colour::LIGHTTEXT);\r
+ drawText(tr("OK to save, BACK to cancel"), x+20, area.h - 50, Colour::LIGHTTEXT);\r
+ if (drawPicture) {\r
+ hasChanged=false;\r
+ picture.init(PICTUREFILE);\r
+ picture.draw();\r
+ drawPicture=false;\r
+ }\r
+ int picy=picture.getY();\r
+ int pich=picture.getHeight();\r
+ if (hasChanged) drawText(tr("0 to draw picture"), picx+30, picy+pich+10, Colour::LIGHTTEXT);\r
+}\r
+\r
+int VColourTuner::handleCommand(int command)\r
+{\r
+ int rt=0;\r
+ switch(command) {\r
+ case Remote::ONE:\r
+ updateFactor(1,-1);\r
+ rt=2;\r
+ hasChanged=true;\r
+ break;\r
+ case Remote::TWO:\r
+ updateFactor(1,1);\r
+ rt=2;\r
+ hasChanged=true;\r
+ break;\r
+ case Remote::FOUR:\r
+ updateFactor(2,-1);\r
+ rt=2;\r
+ hasChanged=true;\r
+ break;\r
+ case Remote::FIVE:\r
+ updateFactor(2,1);\r
+ rt=2;\r
+ hasChanged=true;\r
+ break;\r
+ case Remote::SEVEN:\r
+ updateFactor(3,-1);\r
+ rt=2;\r
+ hasChanged=true;\r
+ break;\r
+ case Remote::EIGHT:\r
+ updateFactor(3,1);\r
+ hasChanged=true;\r
+ rt=2;\r
+ break;\r
+ case Remote::THREE:\r
+ updateFactor(4,-1);\r
+ hasChanged=true;\r
+ rt=2;\r
+ break;\r
+ case Remote::SIX:\r
+ updateFactor(4,1);\r
+ hasChanged=true;\r
+ rt=2;\r
+ break;\r
+ case Remote::NINE:\r
+ updateFactor(5,0);\r
+ hasChanged=true;\r
+ rt=2;\r
+ break;\r
+ case Remote::ZERO:\r
+ drawPicture=true;\r
+ rt=2;\r
+ break;\r
+ case Remote::BACK:\r
+ vrfactor=rfactor;\r
+ vgfactor=gfactor;\r
+ vbfactor=bfactor;\r
+#ifndef WIN32\r
+#ifndef _MIPS_ARCH\r
+#ifndef __ANDROID__\r
+ ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);\r
+#endif\r
+#endif\r
+#endif\r
+ rt=4;\r
+ break;\r
+ case Remote::OK:\r
+ rfactor=vrfactor;\r
+ gfactor=vgfactor;\r
+ bfactor=vbfactor;\r
+ MediaOptions::getInstance()->setIntOption("FactorRed",rfactor);\r
+ MediaOptions::getInstance()->setIntOption("FactorGreen",gfactor);\r
+ MediaOptions::getInstance()->setIntOption("FactorBlue",bfactor);\r
+ rt=4;\r
+ break;\r
+ }\r
+ if (rt == 2) {\r
+#ifndef WIN32\r
+#ifndef _MIPS_ARCH\r
+#ifndef __ANDROID__\r
+ ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);\r
+#endif\r
+#endif\r
+#endif\r
+ bool updateAll=drawPicture;\r
+ draw();\r
+ if (updateAll) {\r
+ BoxStack::getInstance()->update(this);\r
+ }\r
+ else {\r
+ Region r;\r
+ r.x=0;\r
+ r.w=picture.getX()-1;\r
+ r.y=0;\r
+ r.h=area.h;\r
+ BoxStack::getInstance()->update(this,&r);\r
+ r.x=picture.getX();\r
+ r.y=picture.getY();\r
+ r.h=area.h-r.y;\r
+ r.w=area.w-picture.getX();\r
+ BoxStack::getInstance()->update(this,&r);\r
+ }\r
+ }\r
+ return rt;\r
+}\r
+\r
+\r
+\r
+void VColourTuner::processMessage(Message* m)\r
+{\r
+ if (m->message == Message::MOUSE_MOVE)\r
+ {\r
+ \r
+ }\r
+ else if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ //check if press is outside this view! then simulate cancel\r
+ int x=(m->parameter>>16)-getScreenX();\r
+ int y=(m->parameter&0xFFFF)-getScreenY();\r
+ if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
+ }\r
+ else if (y>=(int)area.h-24 && y<=(int)area.h-6)\r
+ {\r
+ ;\r
+ }\r
+ }\r
+}\r
+\r
+void VColourTuner::updateFactor(int color, int amount) {\r
+ switch (color) {\r
+ case 1:\r
+ vrfactor+=amount;\r
+ if (vrfactor < 20 ) vrfactor=20;\r
+ if (vrfactor > 200) vrfactor=200;\r
+ break;\r
+ case 2:\r
+ vgfactor+=amount;\r
+ if (vgfactor < 20 ) vgfactor=20;\r
+ if (vgfactor > 200) vgfactor=200;\r
+ break;\r
+ case 3:\r
+ vbfactor+=amount;\r
+ if (vbfactor < 20 ) vbfactor=20;\r
+ if (vbfactor > 200) vbfactor=200;\r
+ break;\r
+ case 4:\r
+ updateFactor(1,amount);\r
+ updateFactor(2,amount);\r
+ updateFactor(3,amount);\r
+ break;\r
+ case 5:\r
+ while ((vrfactor+vbfactor+vgfactor) > 300) updateFactor(4,-1);\r
+ while ((vrfactor+vbfactor+vgfactor) < 300) updateFactor(4,1);\r
+ }\r
+}\r
+\r
+void VColourTuner::initFactors(){\r
+ MediaOptions * options=MediaOptions::getInstance();\r
+ int rf=options->getIntOption("FactorRed");\r
+ int gf=options->getIntOption("FactorGreen");\r
+ int bf=options->getIntOption("FactorBlue");\r
+ if (rf >= 20 && bf >= 20 && gf >= 20)\r
+ rfactor=rf;\r
+ gfactor=gf;\r
+ bfactor=bf;\r
+ Log::getInstance()->log("VColourTuner",Log::DEBUG,"setting initial factors r=%d,g=%d,b=%d",rf,gf,bf);\r
+#ifndef __ANDROID__\r
+#ifndef WIN32\r
+#ifndef _MIPS_ARCH\r
+ Surface_TYPE::initConversionTables(rfactor,gfactor,bfactor);\r
+#endif\r
+#endif\r
+#endif\r
+}\r
Wol::getInstance()->setWakeUpIP(servers[selectedServer].ip);
vdr->setServerIP(servers[selectedServer].ip);
+
// Clear the serverIPs vector
for(UINT k = 0; k < servers.size(); k++)
{
}
servers.clear();
+
setOneLiner(tr("Connecting to VDR"));
draw();
boxstack->update(this);
success = vdr->connect();
if (success)
{
- logger->log("Command", Log::DEBUG, "Connected ok, doing login");
+ logger->log("VConnect", Log::DEBUG, "Connected ok, doing login");
success = vdr->doLogin();
if (!success)
} while(!success);
+
Message* m = new Message(); // Must be done after this thread ends
m->from = this;
m->to = Command::getInstance();
-/*
- Copyright 2004-2008 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vdr.h"
-
-#include "recman.h"
-#include "tcp.h"
-#include "log.h"
-#include "recinfo.h"
-#include "dsock.h"
-#include "channel.h"
-#include "event.h"
-#include "wol.h"
-#include "vdrrequestpacket.h"
-#include "vdrresponsepacket.h"
-#include "command.h"
-#include "media.h"
-#include "mediaprovider.h"
-#include "mediaproviderids.h"
-#include "vdrcommand.h"
-#include "video.h"
-
-VDR* VDR::instance = NULL;
-//prepare a request
-//will create a request package from a command variable and fill this
-//caller has to destroy buffer
-static SerializeBuffer * prepareRequest(VDR_Command *cmd) {
- SerializeBuffer *buf=new SerializeBuffer(512,false,true);
- if (cmd->serialize(buf) != 0) {
- delete buf;
- return NULL;
- }
- return buf;
-}
-
-//handle request/response
-//TODO avoid copy of buffer (needs extension of requestpacket)
-//TODO avoid command 2x (needs some more restructuring)
-SerializeBuffer * VDR::doRequestResponse(SerializeBuffer *rq,int cmd) {
- VDR_RequestPacket *rt=new VDR_RequestPacket;
- if (! rt) {
- delete rq;
- return NULL;
- }
- if (! rt->init(cmd,true,rq->getCurrent()-rq->getStart())) {
- delete rq;
- delete rt;
- return NULL;
- }
- if (! rt->copyin(rq->getStart(),(ULONG)(rq->getCurrent()-rq->getStart()))) {
- delete rq;
- delete rt;
- return NULL;
- }
- delete rq;
- VDR_ResponsePacket *rp=RequestResponse(rt);
- logger->log("doRequestResponse",Log::DEBUG,"got response %p",rp);
- if ( !rp) {
- delete rt;
- return NULL;
- }
- SerializeBuffer *buf=new SerializeBuffer(rp->getUserData(),rp->getUserDataLength(),true,true,false);
- delete rp;
- return buf;
-}
-
-
-
-//deserialize a received response
-//delete the package
-//return !=0 on error
-static int decodeResponse(SerializeBuffer *rp,VDR_Command *c) {
- ULONG expected=c->command;
- if (c->deserialize(rp) != 0) {
- delete rp;
- Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unable to deserialize for command %lu",expected);
- return -1;
- }
- delete rp;
- if (c->command != expected) {
- Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unexpected response received 0x%lx, expected 0x%lx",c->command,expected);
- return -1;
- }
- Log::getInstance()->log("VDR", Log::DEBUG, "decodeResponse successfully decoded command 0x%lx",expected);
- return 0;
-}
-
-
-
-VDR::VDR()
-{
- if (instance) return;
- instance = this;
- initted = 0;
- findingServer = 0;
- tcp = NULL;
- connected = false;
- maxChannelNumber = 0;
- channelNumberWidth = 1;
- TEMP_SINGLE_VDR_PR = NULL;
- providerId=MPROVIDERID_VDR;
- subRange=MPROVIDERRANGE_VDR;
- MediaPlayerRegister::getInstance()->registerMediaProvider(this,MPROVIDERID_VDR,MPROVIDERRANGE_VDR);
-}
-
-VDR::~VDR()
-{
- instance = NULL;
- if (initted) shutdown();
-}
-
-VDR* VDR::getInstance()
-{
- return instance;
-}
-
-int VDR::init(int tport)
-{
- if (initted) return 0;
- initted = 1;
- port = tport;
- logger = Log::getInstance();
- return 1;
-}
-
-int VDR::shutdown()
-{
- if (!initted) return 0;
- initted = 0;
- disconnect();
- return 1;
-}
-
-void VDR::findServers(vector<VDRServer>& servers)
-{
- Wol* wol = Wol::getInstance();
- findingServer = 1;
- char* message = "VOMP";
-
- DatagramSocket ds(port);
- int haveAtLeastOne = 0;
- int retval;
- int waitType = 1;
- bool firstloop = true;
- while(findingServer)
- {
- if (waitType == 1)
- {
- ds.shutdown();
- ds.init();
- logger->log("VDR", Log::NOTICE, "Broadcasting for server");
- ds.send("255.255.255.255", 3024, message, strlen(message));
- if(!firstloop) wol->doWakeUp();
- }
- retval = ds.waitforMessage(waitType);
-
- if (retval == 2) // we got a reply
- {
- if (!strcmp(ds.getData(), "VOMP")) // echo.....
- {
- waitType = 2;
- }
- else
- {
- VDRServer newServer;
- newServer.ip = new char[16];
- strcpy(newServer.ip, ds.getFromIPA());
-
- if (ds.getDataLength() == 0)
- {
- newServer.name = new char[1];
- newServer.name[0] = '\0';
- }
- else
- {
- newServer.name = new char[strlen(ds.getData())+1];
- strcpy(newServer.name, ds.getData());
- }
-
- servers.push_back(newServer);
- waitType = 2;
- haveAtLeastOne = 1;
- }
- }
- else
- {
- if (haveAtLeastOne) break;
- waitType = 1;
- firstloop = false;
- }
- }
- sort(servers.begin(), servers.end(), ServerSorter());
-}
-
-void VDR::cancelFindingServer()
-{
- findingServer = 0;
-}
-
-void VDR::setServerIP(char* newIP)
-{
- strcpy(serverIP, newIP);
-}
-
-int VDR::connect()
-{
- maxChannelNumber = 0;
- channelNumberWidth = 1;
-
- if (tcp) delete tcp;
- tcp = new TCP();
- if (tcp->connectTo(serverIP, 3024))
- {
- connected = true;
- threadStart();
- return 1;
- }
- else
- {
- return 0;
- }
-}
-
-void VDR::disconnect()
-{
- threadCancel();
- if (tcp) delete tcp;
- tcp = NULL;
- connected = false;
- logger->log("VDR", Log::DEBUG, "Disconnect");
-}
-
-void VDR::setReceiveWindow(size_t size)
-{
- if (connected) tcp->setReceiveWindow(size);
-}
-
-///////////////////////////////////////////////////////
-
-void VDR::threadMethod()
-{
- logger->log("VDR", Log::DEBUG, "VDR RUN");
-
- threadSetKillable(); // FIXME - change this to deal with the EDRs
-
- ULONG channelID;
-
- ULONG requestID;
- ULONG userDataLength;
- UCHAR* userData;
-
- ULONG streamID;
- ULONG flag;
-
- VDR_ResponsePacket* vresp;
-
- ULONG timeNow = 0;
- ULONG lastKAsent = 0;
- ULONG lastKArecv = time(NULL);
- int readSuccess;
-
- while(1)
- {
- timeNow = time(NULL);
-
- readSuccess = tcp->readData((UCHAR*)&channelID, sizeof(ULONG)); // 2s timeout atm
-
- if (!readSuccess)
- {
- //logger->log("VDR", Log::DEBUG, "Net read timeout");
- if (!tcp->isConnected()) { connectionDied(); return; } // return to stop this thread
- }
-
- // Error or timeout.
-
- if (!lastKAsent) // have not sent a KA
- {
- if (lastKArecv < (timeNow - 5))
- {
- logger->log("VDR", Log::DEBUG, "Sending KA packet");
- if (!sendKA(timeNow))
- {
- logger->log("VDR", Log::DEBUG, "Could not send KA, calling connectionDied");
- connectionDied();
- return;
- }
- lastKAsent = timeNow;
- }
- }
- else
- {
- if (lastKAsent <= (timeNow - 10))
- {
- logger->log("VDR", Log::DEBUG, "lastKA over 10s ago, calling connectionDied");
- connectionDied();
- return;
- }
- }
-
- if (!readSuccess) continue; // no data was read but the connection is ok.
-
- // Data was read
-
- channelID = ntohl(channelID);
-
- if (channelID == CHANNEL_REQUEST_RESPONSE)
- {
- if (!tcp->readData((UCHAR*)&requestID, sizeof(ULONG))) break;
- requestID = ntohl(requestID);
- if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;
- userDataLength = ntohl(userDataLength);
- if (userDataLength > 5000000) break; // how big can these packets get?
- userData = NULL;
- if (userDataLength > 0)
- {
- userData = (UCHAR*)malloc(userDataLength);
- if (!userData) break;
- if (!tcp->readData(userData, userDataLength)) break;
- }
-
- vresp = new VDR_ResponsePacket();
- vresp->setResponse(requestID, userData, userDataLength);
- logger->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength);
-
- if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
- {
- // If edFindAndCall returns true, edr was called and vresp was handed off.
- // else, delete vresp here.
- delete vresp;
- }
- }
- else if (channelID == CHANNEL_STREAM)
- {
- if (!tcp->readData((UCHAR*)&streamID, sizeof(ULONG))) break;
- streamID = ntohl(streamID);
-
- if (!tcp->readData((UCHAR*)&flag, sizeof(ULONG))) break;
- flag = ntohl(flag);
-
- if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;
- userDataLength = ntohl(userDataLength);
- userData = NULL;
- if (userDataLength > 0)
- {
- userData = (UCHAR*)malloc(userDataLength);
- if (!userData) break;
- if (!tcp->readData(userData, userDataLength)) break;
- }
-
- vresp = new VDR_ResponsePacket();
- vresp->setStream(streamID, flag, userData, userDataLength);
-// logger->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, flag=%lu, len=%lu", streamID, flag, userDataLength);
-
- if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
- {
- // If edFindAndCall returns true, edr was called and vresp was handed off.
- // else, delete vresp here.
- delete vresp;
- }
- }
- else if (channelID == CHANNEL_KEEPALIVE)
- {
- ULONG KAreply = 0;
- if (!tcp->readData((UCHAR*)&KAreply, sizeof(ULONG))) break;
- KAreply = (ULONG)ntohl(KAreply);
- if (KAreply == lastKAsent) // successful KA response
- {
- lastKAsent = 0;
- lastKArecv = KAreply;
- logger->log("VDR", Log::DEBUG, "Rxd correct KA reply");
- }
- }
- else
- {
- logger->log("VDR", Log::ERR, "Rxd a response packet on channel %lu !!", channelID);
- break;
- }
-
- // Who deletes vresp?
- // If RR, the individual protocol functions must delete vresp.
- // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there.
- }
-
- connectionDied();
-}
-
-void VDR::connectionDied()
-{
- // Called from within threadMethod to do cleanup if it decides the connection has died
-
- connected = false; // though actually it could still be connected until someone calls vdr->disconnect
-
- // Need to wake up any waiting channel 1 request-response threads
- // Normally this is done by a packet coming in with channelid and requestid
- // Instead, go through the list and for each channel 1 edr, make an empty vresp
- // An empty vresp will have userData == NULL, which means vresp->noResponse() == true
-
- // If it's a stream receiver, generate a stream packet with flag == connection_lost
-
- edLock();
- VDR_PacketReceiver* vdrpr;
- VDR_ResponsePacket* vresp;
- while(receivers.size())
- {
- vdrpr = (VDR_PacketReceiver*) *(receivers.begin());
- if (vdrpr->receiverChannel == CHANNEL_REQUEST_RESPONSE)
- {
- vresp = new VDR_ResponsePacket();
- vresp->setResponse(vdrpr->requestSerialNumber, NULL, 0);
- logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for request serial %lu", vdrpr->requestSerialNumber);
- edUnlock();
- if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
- {
- // If edFindAndCall returns true, edr was called and vresp was handed off.
- // else, delete vresp here.
- logger->log("VDR", Log::ERR, "Timeouts: no waiting thread found for request serial %lu !!!", vdrpr->requestSerialNumber);
- delete vresp;
- }
- edLock();
- }
- else if (vdrpr->receiverChannel == CHANNEL_STREAM)
- {
- vresp = new VDR_ResponsePacket();
- vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0);
- logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for streamid %lu", vdrpr->streamID);
- edUnlock();
- if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
- {
- // If edFindAndCall returns true, edr was called and vresp was handed off.
- // else, delete vresp here.
- logger->log("VDR", Log::ERR, "Timeouts: no waiting stream receiver found for streamid %lu !!!", vdrpr->streamID);
- delete vresp;
- }
- edLock();
-
- for(EDRL::iterator i = receivers.begin(); i != receivers.end(); i++)
- if ((VDR_PacketReceiver*)*i == vdrpr) { receivers.erase(i); break; }
- }
- }
- edUnlock();
- // Ok, all event receviers should be dealt with. just in case there weren't any, inform command
- logger->log("VDR", Log::DEBUG, "edUnlock at end of connectionDied");
-
- Command::getInstance()->connectionLost();
-}
-
-bool VDR::ed_cb_find(EDReceiver* edr, void* userTag)
-{
- // edr is a VDR_PacketReceiver object made in VDR::RequestResponse
- // userTag is a VDR_ResponsePacket made in threadMethod
-
- VDR_PacketReceiver* vdrpr = (VDR_PacketReceiver*)edr;
- VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
-
- // Is vresp for vdrpr ?
-
- ULONG packetChannel = vresp->getChannelID();
- if (vdrpr->receiverChannel != packetChannel) return false;
-
- if (packetChannel == CHANNEL_REQUEST_RESPONSE)
- {
- if (vdrpr->requestSerialNumber == vresp->getRequestID()) return true;
- }
- else if (packetChannel == CHANNEL_STREAM)
- {
- if (vdrpr->streamID == vresp->getStreamID()) return true;
- }
-
- return false;
-}
-
-VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)
-{
- //logger->log("VDR", Log::DEBUG, "RR %lu", vrp->getOpcode());
-
- if (!connected)
- {
- logger->log("VDR", Log::DEBUG, "RR when !connected");
- VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
- return vresp; // "no-response" return
- }
-
- // ED make new VDR and register
- // make a VDR_PacketReceiver
- // - init with serial number of request packet
-
- VDR_PacketReceiver vdrpr;
-// vdrpr.requestTime = time(NULL);
- vdrpr.receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE;
- vdrpr.requestSerialNumber = vrp->getSerial();
-
- edRegister(&vdrpr);
-
- edLock();
-
- if ((ULONG)tcp->sendData(vrp->getPtr(), vrp->getLen()) != vrp->getLen())
- {
- edUnlock();
- edUnregister(&vdrpr);
- VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
- return vresp; // "no-response" return
- }
-
- // Sleep and block this thread. The sleep unlocks the mutex
- logger->log("VDR", Log::DEBUG, "RR sleep - opcode %lu", vrp->getOpcode());
- edSleepThisReceiver(&vdrpr);
- logger->log("VDR", Log::DEBUG, "RR unsleep");
-
- // Woken because a response packet has arrived, mutex will be locked
-
- edUnlock();
- return vdrpr.save_vresp;
-}
-
-bool VDR::sendKA(ULONG timeStamp)
-{
- char buffer[8];
- *(ULONG*)&buffer[0] = htonl(CHANNEL_KEEPALIVE);
- *(ULONG*)&buffer[4] = htonl(timeStamp);
- if ((ULONG)tcp->sendData(buffer, 8) != 8) return false;
- return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-// Here VDR takes a break for the VDR_PacketReceiver helper class
-
-bool VDR_PacketReceiver::call(void* userTag)
-{
- if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE)
- {
- // It's a RR. Save vresp and, signal the waiting thread and return.
- // VDR::RequestResponse will be blocking waiting for this to happen.
- // That function has a pointer to this object and can read save_vresp.
- save_vresp = (VDR_ResponsePacket*)userTag;
- return true; // Signals ED to remove edr from receivers and wake up edr thread
- }
-
- if (receiverChannel == VDR::CHANNEL_STREAM)
- {
- // It's a stream packet.
- VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
- streamReceiver->streamReceive(vresp->getFlag(), vresp->getUserData(), vresp->getUserDataLength());
- delete vresp;
- return false;
- }
-
- abort(); // unknown receiverChannel, should not happen
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-int VDR::doLogin()
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_LOGIN, true, 6)) return 0;
-
- char* mactemp[6];
- tcp->getMAC((char*)mactemp);
- if (!vrp.copyin((UCHAR*)mactemp, 6)) return 0;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
-
- ULONG vdrTime = vresp->extractULONG();
- logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
- long vdrTimeOffset = vresp->extractLONG();
- logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
-
- delete vresp;
-
- // Set the time and zone on the MVP
-
-#ifndef WIN32
- struct timespec currentTime;
- currentTime.tv_sec = vdrTime;
- currentTime.tv_nsec = 0;
- int b = clock_settime(CLOCK_REALTIME, ¤tTime);
-
- logger->log("VDR", Log::DEBUG, "set clock = %u", b);
-
- // now make a TZ variable and set it
- char sign;
- int hours;
- int minutes;
- if (vdrTimeOffset > 0) sign = '-';
- else sign = '+';
-
- vdrTimeOffset = abs(vdrTimeOffset);
-
- hours = (int)vdrTimeOffset / 3600;
- minutes = vdrTimeOffset % 3600;
-
- logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
-
- minutes = (int)minutes / 60;
-
- logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
-
- char newTZ[30];
- sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
- setenv("TZ", newTZ, 1);
-
- logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
-#endif
-
- return 1;
-}
-
-bool VDR::networkLog(const char* logString)
-{
- if (!connected) return false;
- int stringLength = strlen(logString);
- int packetLength = stringLength + 8;
- char *buffer=new char[packetLength + 1];
- *(ULONG*)&buffer[0] = htonl(CHANNEL_NETLOG);
- *(ULONG*)&buffer[4] = htonl(stringLength);
- strcpy(&buffer[8], logString);
-
- if ((ULONG)tcp->sendData(buffer, packetLength) != packetLength) {
- delete [] buffer;
- return false;
- }
- delete [] buffer;
- return true;
-}
-
-bool VDR::getRecordingsList(RecMan* recman)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETRECORDINGLIST, true, 0)) return false;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return false; }
-
- ULONG totalSpace = vresp->extractULONG();
- ULONG freeSpace = vresp->extractULONG();
- ULONG percent = vresp->extractULONG();
- recman->setStats(totalSpace, freeSpace, percent);
-
- ULONG start;
- char* name;
- char* fileName;
-
- while (!vresp->end())
- {
- start = vresp->extractULONG();
- name = vresp->extractString();
- fileName = vresp->extractString();
-
- recman->addEntry(start, name, fileName);
-
- delete[] name;
- delete[] fileName;
- }
-
- delete vresp;
-
- return true;
-}
-
-int VDR::deleteRecording(char* fileName)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_DELETERECORDING, true, strlen(fileName) + 1)) return 0;
- if (!vrp.addString(fileName)) return 0;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
-
- int toReturn = (int)vresp->extractULONG();
- delete vresp;
-
- return toReturn;
-}
-
-char* VDR::moveRecording(char* fileName, char* newPath)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_MOVERECORDING, true, strlen(fileName) + 1 + strlen(newPath) + 1)) return NULL;
- if (!vrp.addString(fileName)) return NULL;
- if (!vrp.addString(newPath)) return NULL;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return NULL; }
-
- char* toReturn = NULL;
- int success = (int)vresp->extractULONG();
- if (success == 1)
- {
- toReturn = vresp->extractString();
- }
-
- delete vresp;
-
- return toReturn;
-}
-
-ChannelList* VDR::getChannelsList(ULONG type)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETCHANNELLIST, true, 0)) return NULL;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return NULL; }
-
- ChannelList* chanList = new ChannelList();
-
- bool h264support=Video::getInstance()->supportsh264();
-
- while (!vresp->end())
- {
- Channel* chan = new Channel();
- chan->number = vresp->extractULONG();
- chan->type = vresp->extractULONG();
- chan->name = vresp->extractString();
- chan->vstreamtype = vresp->extractULONG();
-
- if (chan->type == type && (chan->vstreamtype!=0x1b || h264support))
- {
- chanList->push_back(chan);
- logger->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
- if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;
- }
- else
- {
- delete chan;
- }
- }
-
- delete vresp;
-
- if (maxChannelNumber > 99999)
- channelNumberWidth = 6;
- else if (maxChannelNumber > 9999)
- channelNumberWidth = 5;
- else if (maxChannelNumber > 999)
- channelNumberWidth = 4;
- else if (maxChannelNumber > 99)
- channelNumberWidth = 3;
- else if (maxChannelNumber > 9)
- channelNumberWidth = 2;
- else
- channelNumberWidth = 1;
-
- return chanList;
-}
-
-int VDR::streamChannel(ULONG number, StreamReceiver* tstreamReceiver)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_STREAMCHANNEL, true, sizeof(ULONG))) return 0;
- if (!vrp.addULONG(number)) return 0;
-
-
- VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
- vdrpr->receiverChannel = VDR::CHANNEL_STREAM;
- vdrpr->streamID = vrp.getSerial();
- vdrpr->streamReceiver = tstreamReceiver;
- edRegister(vdrpr);
- TEMP_SINGLE_VDR_PR = vdrpr;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse())
- {
- delete vresp;
- edUnregister(vdrpr);
- delete vdrpr;
- return 0;
- }
-
- int toReturn = (int)vresp->extractULONG();
- logger->log("VDR", Log::DEBUG, "VDR said %lu to start streaming request", toReturn);
- delete vresp;
-
- return toReturn;
-}
-
-int VDR::stopStreaming()
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_STOPSTREAMING, true, 0)) return 0;
-
- if (TEMP_SINGLE_VDR_PR) // this block only needs to be done if it was a live stream
- // TEMP_SINGLE_VDR_PR will not be set unless we are streaming a channel
- {
- edUnregister(TEMP_SINGLE_VDR_PR);
- delete TEMP_SINGLE_VDR_PR;
- TEMP_SINGLE_VDR_PR = NULL;
- }
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
-
- int toReturn = (int)vresp->extractULONG();
- delete vresp;
-
- return toReturn;
-}
-
-UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETBLOCK, true, sizeof(ULLONG) + sizeof(ULONG))) return NULL;
- if (!vrp.addULLONG(position)) return NULL;
- if (!vrp.addULONG(maxAmount)) return NULL;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return NULL; }
-
- if (vresp->serverError())
- {
- logger->log("VDR", Log::DEBUG, "Detected getblock 0");
- delete vresp;
- return NULL;
- }
-
- // Special handling for getblock
- UCHAR* toReturn = vresp->getUserData();
- *amountReceived = vresp->getUserDataLength();
-
- delete vresp;
-
- return toReturn;
-}
-
-ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames, bool* IsPesRecording)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_STREAMRECORDING, true, strlen(fileName) + 1)) return 0;
- if (!vrp.addString(fileName)) return 0;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
-
- ULLONG lengthBytes = vresp->extractULLONG();
- ULONG lengthFrames = vresp->extractULONG();
- UCHAR isPesRecording = vresp->extractUCHAR();
- delete vresp;
-
- *totalFrames = lengthFrames;
- *IsPesRecording = (isPesRecording);//convert Uchar to bool
-
- logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu, IsPesRecording %x", lengthBytes, lengthFrames, *IsPesRecording);
-
- return lengthBytes;
-}
-
-ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_POSFROMFRAME, true, sizeof(ULONG))) return 0;
- if (!vrp.addULONG(frameNumber)) return 0;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
-
- ULLONG position = vresp->extractULLONG();
- delete vresp;
-
- logger->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
-
- return position;
-}
-
-ULONG VDR::frameNumberFromPosition(ULLONG position)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_FRAMEFROMPOS, true, sizeof(ULLONG))) return 0;
- if (!vrp.addULLONG(position)) return 0;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
-
- ULONG framenumber = vresp->extractULONG();
- delete vresp;
-
- logger->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
-
- return framenumber;
-}
-
-bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETNEXTIFRAME, true, sizeof(ULONG)*2)) return false;
- if (!vrp.addULONG(frameNumber)) return false;
- if (!vrp.addULONG(direction)) return false;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return false; }
-
- if (vresp->serverError())
- {
- logger->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
- delete vresp;
- return false;
- }
-
- *rfilePosition = vresp->extractULLONG();
- *rframeNumber = vresp->extractULONG();
- *rframeLength = vresp->extractULONG();
-
- delete vresp;
-
- logger->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
-
- return true;
-}
-
-EventList* VDR::getChannelSchedule(ULONG number)
-{
- time_t now;
- time(&now);
- return getChannelSchedule(number, now, 24 * 60 * 60);
-}
-
-EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
-{
-// retrieve event list (vector of events) from vdr within filter window. duration is in seconds
-
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETCHANNELSCHEDULE, true, sizeof(ULONG)*3)) return NULL;
- if (!vrp.addULONG(number)) return NULL;
- if (!vrp.addULONG(start)) return NULL;
- if (!vrp.addULONG(duration)) return NULL;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return NULL; }
-
- // received a ulong(0) - schedules error in the plugin
- if (vresp->serverError())
- {
- delete vresp;
- return NULL;
- }
-
- EventList* eventList = new EventList();
-
- while (!vresp->end())
- {
- Event* event = new Event();
- event->id = vresp->extractULONG();
- event->time = vresp->extractULONG();
- event->duration = vresp->extractULONG();
- event->title = vresp->extractString();
- event->subtitle = vresp->extractString();
- event->description = vresp->extractString();
- eventList->push_back(event);
- }
-
- delete vresp;
-
- logger->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
- return eventList;
-}
-
-int VDR::configSave(const char* section, const char* key, const char* value)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_CONFIGSAVE, false, 0)) return 0;
- if (!vrp.addString(section)) return 0;
- if (!vrp.addString(key)) return 0;
- if (!vrp.addString(value)) return 0;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
-
- int toReturn = (int)vresp->extractULONG();
- delete vresp;
-
- return toReturn;
-}
-
-char* VDR::configLoad(const char* section, const char* key)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_CONFIGLOAD, false, 0)) return NULL;
- if (!vrp.addString(section)) return NULL;
- if (!vrp.addString(key)) return NULL;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return NULL; }
-
- char* toReturn = vresp->extractString();
- delete vresp;
-
- return toReturn;
-}
-
-RecTimerList* VDR::getRecTimersList()
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETTIMERS, true, 0)) return NULL;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return NULL; }
-
- RecTimerList* recTimerList = new RecTimerList();
-
- ULONG numTimers = vresp->extractULONG();
- if (numTimers > 0)
- {
- RecTimer* newRecTimer;
- char* tempString;
-
- while (!vresp->end())
- {
- newRecTimer = new RecTimer();
- newRecTimer->active = vresp->extractULONG();
- newRecTimer->recording = vresp->extractULONG();
- newRecTimer->pending = vresp->extractULONG();
- newRecTimer->priority = vresp->extractULONG();
- newRecTimer->lifeTime = vresp->extractULONG();
- newRecTimer->channelNumber = vresp->extractULONG();
- newRecTimer->startTime = vresp->extractULONG();
- newRecTimer->stopTime = vresp->extractULONG();
- newRecTimer->day = vresp->extractULONG();
- newRecTimer->weekDays = vresp->extractULONG();
-
- tempString = vresp->extractString();
- newRecTimer->setFile(tempString);
- delete[] tempString;
-
- recTimerList->push_back(newRecTimer);
- logger->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
- newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
- newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
- }
- }
-
- delete vresp;
-
- sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
-
- return recTimerList;
-}
-
-ULONG VDR::setEventTimer(char* timerString)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_SETTIMER, true, strlen(timerString) + 1)) return 0;
- if (!vrp.addString(timerString)) return 0;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
-
- ULONG toReturn = vresp->extractULONG();
- delete vresp;
-
- return toReturn;
-}
-
-RecInfo* VDR::getRecInfo(char* fileName)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETRECINFO, true, strlen(fileName) + 1)) return NULL;
- if (!vrp.addString(fileName)) return NULL;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return NULL; }
-
- if (vresp->serverError())
- {
- logger->log("VDR", Log::DEBUG, "Could not get rec info");
- delete vresp;
- return NULL;
- }
-
- RecInfo* recInfo = new RecInfo();
-
- recInfo->timerStart = vresp->extractULONG();
- recInfo->timerEnd = vresp->extractULONG();
- recInfo->resumePoint = vresp->extractULONG();
- recInfo->summary = vresp->extractString();
-
- ULONG numComponents = vresp->extractULONG();
- if (numComponents)
- {
- recInfo->setNumComponents(numComponents);
- for (ULONG i = 0; i < numComponents; i++)
- {
- recInfo->streams[i] = vresp->extractUCHAR();
- recInfo->types[i] = vresp->extractUCHAR();
- recInfo->languages[i] = vresp->extractString();
- recInfo->descriptions[i] = vresp->extractString();
- }
- }
- recInfo->fps=vresp->extractdouble();
-
-
- recInfo->print();
-
- delete vresp;
- return recInfo;
-}
-
-// FIXME obselete
-ULLONG VDR::rescanRecording(ULONG* totalFrames)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_RESCANRECORDING, true, 0)) return 0;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
-
- ULLONG lengthBytes = vresp->extractULLONG();
- ULONG lengthFrames = vresp->extractULONG();
- delete vresp;
-
- logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
-
- *totalFrames = lengthFrames;
- return lengthBytes;
-}
-
-MarkList* VDR::getMarks(char* fileName)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETMARKS, true, strlen(fileName) + 1)) return NULL;
- if (!vrp.addString(fileName)) return NULL;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return NULL; }
-
- if (vresp->serverError())
- {
- delete vresp;
- return NULL;
- }
-
- MarkList* markList = new MarkList();
-
- while (!vresp->end())
- {
- Mark* mark = new Mark();
- mark->pos = vresp->extractULONG();
-
- markList->push_back(mark);
- logger->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);
- }
-
- delete vresp;
-
- return markList;
-}
-
-void VDR::getChannelPids(Channel* channel)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETCHANNELPIDS, true, sizeof(ULONG))) return ;
- if (!vrp.addULONG(channel->number)) return ;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return ; }
-
- // Format of response
- // vpid
- // number of apids
- // {
- // apid
- // lang string
- // }
-
- channel->vpid = vresp->extractULONG();
- channel->vstreamtype = vresp->extractULONG();
- channel->numAPids = vresp->extractULONG();
-
- for (ULONG i = 0; i < channel->numAPids; i++)
- {
- apid newapid;
- newapid.pid = vresp->extractULONG();
- newapid.name = vresp->extractString();
- channel->apids.push_back(newapid);
- }
-
- channel->numDPids = vresp->extractULONG();
-
- for (ULONG i = 0; i < channel->numDPids; i++)
- {
- apid newdpid;
- newdpid.pid = vresp->extractULONG();
- newdpid.name = vresp->extractString();
- channel->dpids.push_back(newdpid);
- }
-
- channel->numSPids = vresp->extractULONG();
-
- for (ULONG i = 0; i < channel->numSPids; i++)
- {
- apid newspid;
- newspid.pid = vresp->extractULONG();
- newspid.name = vresp->extractString();
- channel->spids.push_back(newspid);
- }
- channel->tpid = vresp->extractULONG();
-
- delete vresp;
-
- return ;
-}
-
-
-MediaList * VDR::getRootList() {
- return getMediaList(NULL);
-}
-/**
- * media List Request:
- * mediaURI
- * Media List response:
- * mediaList
-*/
-MediaList* VDR::getMediaList(const MediaURI * root)
-{
- logger->log("VDR", Log::DEBUG, "getMediaList %s,d=%s, prov=%d", (root?root->getName():"NULL"),
- ((root && root->hasDisplayName())?root->getDisplayName():"NULL"),
- (root?root->getProvider():providerId));
- MediaURI remoteURI(root);
- VDR_GetMediaListRequest request(&remoteURI);
- SerializeBuffer *vrp=prepareRequest(&request);
- if (!vrp) {
- logger->log("VDR", Log::ERR, "getMediaList unable to create command");
- return NULL;
- }
-
- SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
- if (!vresp) {
- Command::getInstance()->connectionLost();
- return NULL;
- }
-
- MediaList *rt=new MediaList(NULL);
- ULONG rtflags=0;
- VDR_GetMediaListResponse resp(&rtflags,rt);
- if (decodeResponse(vresp,&resp) != 0) {
- return NULL;
- }
- return rt;
-}
-
-/**
- * get image Request:
- * uri,x,y, channel
- * get media response:
- * 4 flags
- * 8 len of image
-*/
-int VDR::openMedium(ULONG channel,const MediaURI *uri, ULLONG * size, ULONG x, ULONG y)
-{
- MediaURI remoteURI(uri);
- VDR_OpenMediumRequest request(&channel,&remoteURI,&x,&y);
- *size=0;
- SerializeBuffer *vrp=prepareRequest(&request);
- if (!vrp) {
- logger->log("VDR", Log::ERR, "openMedium unable to create command");
- return -1;
- }
- SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
- if (!vresp) {
- Command::getInstance()->connectionLost();
- return -1;
- }
- ULONG flags=0;
- VDR_OpenMediumResponse response(&flags,size);
- if (decodeResponse(vresp,&response) != 0) {
- return -1;
- }
- logger->log("VDR", Log::DEBUG, "openMedia len=%llu", *size);
- return 0;
-}
-
-/**
- * getMediaBlock - no separate response class - simple data block
- * resp
- * packet
- */
-int VDR::getMediaBlock(ULONG channel, ULLONG position, ULONG maxAmount, ULONG* amountReceived, unsigned char **buffer)
-{
- *amountReceived=0;
- VDR_GetMediaBlockRequest request(&channel,&position,&maxAmount);
- SerializeBuffer *vrp=prepareRequest(&request);
- if (!vrp) {
- logger->log("VDR", Log::ERR, "getMediaBlock unable to create command");
- return -1;
- }
- SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
- if (!vresp) {
- Command::getInstance()->connectionLost();
- return -1;
- }
-
- // Special handling for getblock
- *amountReceived = (ULONG)(vresp->getEnd()-vresp->getStart());
- *buffer = vresp->steelBuffer();
- delete vresp;
- return 0;
-}
-
-/**
- * VDR_GETMEDIAINFO
- * channel
- * rt
- * flags
- * info
- */
-
-int VDR::getMediaInfo(ULONG channel, MediaInfo * result) {
- if (! result) return -1;
- VDR_GetMediaInfoRequest request(&channel);
- SerializeBuffer *vrp=prepareRequest(&request);
- if (!vrp) {
- logger->log("VDR", Log::ERR, "getMediaInfo unable to create command");
- return -1;
- }
- SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
- if (!vresp) {
- Command::getInstance()->connectionLost();
- return -1;
- }
-
- ULONG flags=0;
- VDR_GetMediaInfoResponse response(&flags,result);
- if (decodeResponse(vresp,&response) != 0) {
- return -1;
- }
- return 0;
-}
-
-/**
- * VDR_CLOSECHANNEL
- * channel
- * rt
- * flags
- */
-
-int VDR::closeMediaChannel(ULONG channel) {
- VDR_CloseMediaChannelRequest request(&channel);
- SerializeBuffer *vrp=prepareRequest(&request);
- if (!vrp) {
- logger->log("VDR", Log::ERR, "closeMediaChannel unable to create command");
- return -1;
- }
- SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
- if (!vresp) {
- Command::getInstance()->connectionLost();
- return -1;
- }
- ULONG flags;
- VDR_CloseMediaChannelResponse response(&flags);
- if (decodeResponse(vresp,&response) != 0) return -1;
- return (flags != 0)?-1:0;
-}
-
-
-
-
-int VDR::deleteTimer(RecTimer* delTimer)
-{
- logger->log("VDR", Log::DEBUG, "Delete timer called");
-
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_DELETETIMER, false, 0)) return 0;
- if (!vrp.addULONG(delTimer->channelNumber)) return 0;
- if (!vrp.addULONG(delTimer->weekDays)) return 0;
- if (!vrp.addULONG(delTimer->day)) return 0;
- if (!vrp.addULONG(delTimer->startTime)) return 0;
- if (!vrp.addULONG(delTimer->stopTime)) return 0;
-
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
-
- int toReturn = (int)vresp->extractULONG();
- delete vresp;
-
- return toReturn;
-}
-
-I18n::lang_code_list VDR::getLanguageList()
-{
- I18n::lang_code_list CodeList;
- CodeList["en"] = "English"; // Default entry
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETLANGUAGELIST, false, 0)) return CodeList;
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse() || vresp->end())
- {
- delete vresp;
- return CodeList;
- }
- CodeList.clear();
- while (!vresp->end())
- {
- char* c_code = vresp->extractString();
- char* c_name = vresp->extractString();
- string code = c_code;
- string name = c_name;
- CodeList[code] = name;
- delete[] c_code;
- delete[] c_name;
- }
- delete vresp;
- return CodeList;
-}
-
-int VDR::getLanguageContent(const std::string code, I18n::trans_table& texts)
-{
- VDR_RequestPacket vrp;
- if (!vrp.init(VDR_GETLANGUAGECONTENT, false, 0)) return 0;
- if (!vrp.addString(code.c_str())) return 0;
- VDR_ResponsePacket* vresp = RequestResponse(&vrp);
- if (vresp->noResponse()) { delete vresp; return 0; }
- texts.clear();
- while (!vresp->end())
- {
- char* c_key = vresp->extractString();
- char* c_text = vresp->extractString();
- string key = c_key;
- string text = c_text;
- texts[key] = text;
- delete[] c_key;
- delete[] c_text;
- }
- delete vresp;
- return 1;
-}
+/*\r
+ Copyright 2004-2008 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vdr.h"\r
+\r
+#include "recman.h"\r
+#include "tcp.h"\r
+#include "log.h"\r
+#include "recinfo.h"\r
+#include "dsock.h"\r
+#include "channel.h"\r
+#include "event.h"\r
+#include "wol.h"\r
+#include "vdrrequestpacket.h"\r
+#include "vdrresponsepacket.h"\r
+#include "command.h"\r
+#include "media.h"\r
+#include "mediaprovider.h"\r
+#include "mediaproviderids.h"\r
+#include "vdrcommand.h"\r
+#include "video.h"\r
+#include "osd.h"\r
+\r
+VDR* VDR::instance = NULL;\r
+//prepare a request\r
+//will create a request package from a command variable and fill this\r
+//caller has to destroy buffer\r
+static SerializeBuffer * prepareRequest(VDR_Command *cmd) {\r
+ SerializeBuffer *buf=new SerializeBuffer(512,false,true);\r
+ if (cmd->serialize(buf) != 0) {\r
+ delete buf;\r
+ return NULL;\r
+ }\r
+ return buf;\r
+}\r
+\r
+//handle request/response\r
+//TODO avoid copy of buffer (needs extension of requestpacket)\r
+//TODO avoid command 2x (needs some more restructuring)\r
+SerializeBuffer * VDR::doRequestResponse(SerializeBuffer *rq,int cmd) {\r
+ VDR_RequestPacket *rt=new VDR_RequestPacket;\r
+ if (! rt) {\r
+ delete rq;\r
+ return NULL;\r
+ }\r
+ if (! rt->init(cmd,true,rq->getCurrent()-rq->getStart())) {\r
+ delete rq;\r
+ delete rt;\r
+ return NULL;\r
+ }\r
+ if (! rt->copyin(rq->getStart(),(ULONG)(rq->getCurrent()-rq->getStart()))) {\r
+ delete rq;\r
+ delete rt;\r
+ return NULL;\r
+ }\r
+ delete rq;\r
+ VDR_ResponsePacket *rp=RequestResponse(rt);\r
+ logger->log("doRequestResponse",Log::DEBUG,"got response %p",rp);\r
+ if ( !rp) {\r
+ delete rt;\r
+ return NULL;\r
+ }\r
+ SerializeBuffer *buf=new SerializeBuffer(rp->getUserData(),rp->getUserDataLength(),true,true,false);\r
+ delete rp;\r
+ return buf;\r
+}\r
+\r
+\r
+\r
+//deserialize a received response\r
+//delete the package\r
+//return !=0 on error\r
+static int decodeResponse(SerializeBuffer *rp,VDR_Command *c) {\r
+ ULONG expected=c->command;\r
+ if (c->deserialize(rp) != 0) {\r
+ delete rp;\r
+ Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unable to deserialize for command %lu",expected);\r
+ return -1;\r
+ }\r
+ delete rp;\r
+ if (c->command != expected) {\r
+ Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unexpected response received 0x%lx, expected 0x%lx",c->command,expected);\r
+ return -1;\r
+ }\r
+ Log::getInstance()->log("VDR", Log::DEBUG, "decodeResponse successfully decoded command 0x%lx",expected);\r
+ return 0;\r
+}\r
+\r
+\r
+\r
+VDR::VDR()\r
+{\r
+ if (instance) return;\r
+ instance = this;\r
+ initted = 0;\r
+ findingServer = 0;\r
+ tcp = NULL;\r
+ connected = false;\r
+ maxChannelNumber = 0;\r
+ channelNumberWidth = 1;\r
+ TEMP_SINGLE_VDR_PR = NULL;\r
+ providerId=MPROVIDERID_VDR;\r
+ subRange=MPROVIDERRANGE_VDR;\r
+ MediaPlayerRegister::getInstance()->registerMediaProvider(this,MPROVIDERID_VDR,MPROVIDERRANGE_VDR);\r
+}\r
+\r
+VDR::~VDR()\r
+{\r
+ instance = NULL;\r
+ if (initted) shutdown();\r
+}\r
+\r
+VDR* VDR::getInstance()\r
+{\r
+ return instance;\r
+}\r
+\r
+int VDR::init(int tport)\r
+{\r
+ if (initted) return 0;\r
+ initted = 1;\r
+ port = tport;\r
+ logger = Log::getInstance();\r
+ return 1;\r
+}\r
+\r
+int VDR::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ initted = 0;\r
+ disconnect();\r
+ return 1;\r
+}\r
+\r
+void VDR::findServers(vector<VDRServer>& servers)\r
+{\r
+ Wol* wol = Wol::getInstance();\r
+ findingServer = 1;\r
+ char* message = "VOMP";\r
+\r
+ DatagramSocket ds(port);\r
+ int haveAtLeastOne = 0;\r
+ int retval;\r
+ int waitType = 1;\r
+ bool firstloop = true;\r
+ while(findingServer)\r
+ {\r
+ if (waitType == 1)\r
+ {\r
+ ds.shutdown();\r
+ ds.init();\r
+ logger->log("VDR", Log::NOTICE, "Broadcasting for server");\r
+ ds.send("255.255.255.255", 3024, message, strlen(message));\r
+ if(!firstloop) wol->doWakeUp();\r
+ }\r
+ retval = ds.waitforMessage(waitType);\r
+\r
+ if (retval == 2) // we got a reply\r
+ {\r
+ if (!strcmp(ds.getData(), "VOMP")) // echo.....\r
+ {\r
+ waitType = 2;\r
+ }\r
+ else\r
+ {\r
+ VDRServer newServer;\r
+ newServer.ip = new char[16];\r
+ strcpy(newServer.ip, ds.getFromIPA());\r
+\r
+ if (ds.getDataLength() == 0)\r
+ {\r
+ newServer.name = new char[1];\r
+ newServer.name[0] = '\0';\r
+ }\r
+ else\r
+ {\r
+ newServer.name = new char[strlen(ds.getData())+1];\r
+ strcpy(newServer.name, ds.getData());\r
+ }\r
+\r
+ servers.push_back(newServer);\r
+ waitType = 2;\r
+ haveAtLeastOne = 1;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (haveAtLeastOne) break;\r
+ waitType = 1;\r
+ firstloop = false;\r
+/* For DEBUGGING *\r
+ { VDRServer newServer;\r
+ newServer.ip = new char[16];\r
+ strcpy(newServer.ip, "192.168.1.7");\r
+ newServer.name = new char[6];\r
+ strcpy(newServer.name,"debug");\r
+ servers.push_back(newServer);\r
+ waitType = 2;\r
+ haveAtLeastOne = 1;}/**/\r
+\r
+\r
+\r
+ }\r
+ }\r
+ logger->log("VDR", Log::NOTICE, "END loop");\r
+ sort(servers.begin(), servers.end(), ServerSorter());\r
+}\r
+\r
+void VDR::cancelFindingServer()\r
+{\r
+ findingServer = 0;\r
+}\r
+\r
+void VDR::setServerIP(char* newIP)\r
+{\r
+ strcpy(serverIP, newIP);\r
+}\r
+\r
+int VDR::connect()\r
+{\r
+ maxChannelNumber = 0;\r
+ channelNumberWidth = 1;\r
+\r
+ if (tcp) delete tcp;\r
+ tcp = new TCP();\r
+ if (tcp->connectTo(serverIP, 3024))\r
+ {\r
+ connected = true;\r
+ threadStart();\r
+ return 1;\r
+ }\r
+ else\r
+ {\r
+ return 0;\r
+ }\r
+}\r
+\r
+void VDR::disconnect()\r
+{\r
+ threadCancel();\r
+ if (tcp) delete tcp;\r
+ tcp = NULL;\r
+ connected = false;\r
+ logger->log("VDR", Log::DEBUG, "Disconnect");\r
+}\r
+\r
+void VDR::setReceiveWindow(size_t size)\r
+{\r
+ if (connected) tcp->setReceiveWindow(size);\r
+}\r
+\r
+///////////////////////////////////////////////////////\r
+\r
+void VDR::threadMethod()\r
+{\r
+ logger->log("VDR", Log::DEBUG, "VDR RUN"); \r
+\r
+ threadSetKillable(); // FIXME - change this to deal with the EDRs\r
+ \r
+ ULONG channelID;\r
+ \r
+ ULONG requestID;\r
+ ULONG userDataLength;\r
+ UCHAR* userData;\r
+\r
+ ULONG streamID;\r
+ ULONG flag;\r
+\r
+ VDR_ResponsePacket* vresp;\r
+ \r
+ ULONG timeNow = 0;\r
+ ULONG lastKAsent = 0;\r
+ ULONG lastKArecv = time(NULL);\r
+ int readSuccess;\r
+\r
+ while(1)\r
+ {\r
+ timeNow = time(NULL);\r
+ \r
+ readSuccess = tcp->readData((UCHAR*)&channelID, sizeof(ULONG)); // 2s timeout atm\r
+\r
+ if (!readSuccess)\r
+ {\r
+ //logger->log("VDR", Log::DEBUG, "Net read timeout");\r
+ if (!tcp->isConnected()) { connectionDied(); return; } // return to stop this thread\r
+ }\r
+ \r
+ // Error or timeout.\r
+\r
+ if (!lastKAsent) // have not sent a KA\r
+ {\r
+ if (lastKArecv < (timeNow - 5))\r
+ {\r
+ logger->log("VDR", Log::DEBUG, "Sending KA packet");\r
+ if (!sendKA(timeNow))\r
+ {\r
+ logger->log("VDR", Log::DEBUG, "Could not send KA, calling connectionDied");\r
+ connectionDied();\r
+ return;\r
+ }\r
+ lastKAsent = timeNow;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (lastKAsent <= (timeNow - 10))\r
+ {\r
+ logger->log("VDR", Log::DEBUG, "lastKA over 10s ago, calling connectionDied");\r
+ connectionDied();\r
+ return;\r
+ } \r
+ }\r
+\r
+ if (!readSuccess) continue; // no data was read but the connection is ok.\r
+ \r
+ // Data was read\r
+ \r
+ channelID = ntohl(channelID);\r
+ \r
+ if (channelID == CHANNEL_REQUEST_RESPONSE)\r
+ {\r
+ if (!tcp->readData((UCHAR*)&requestID, sizeof(ULONG))) break;\r
+ requestID = ntohl(requestID);\r
+ if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;\r
+ userDataLength = ntohl(userDataLength);\r
+ if (userDataLength > 5000000) break; // how big can these packets get?\r
+ userData = NULL;\r
+ if (userDataLength > 0)\r
+ {\r
+ userData = (UCHAR*)malloc(userDataLength);\r
+ if (!userData) break;\r
+ if (!tcp->readData(userData, userDataLength)) break;\r
+ }\r
+\r
+ vresp = new VDR_ResponsePacket(); \r
+ vresp->setResponse(requestID, userData, userDataLength);\r
+ logger->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength);\r
+\r
+ if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
+ {\r
+ // If edFindAndCall returns true, edr was called and vresp was handed off.\r
+ // else, delete vresp here.\r
+ delete vresp;\r
+ }\r
+ }\r
+ else if (channelID == CHANNEL_STREAM)\r
+ {\r
+ if (!tcp->readData((UCHAR*)&streamID, sizeof(ULONG))) break;\r
+ streamID = ntohl(streamID);\r
+\r
+ if (!tcp->readData((UCHAR*)&flag, sizeof(ULONG))) break;\r
+ flag = ntohl(flag);\r
+\r
+ if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break; \r
+ userDataLength = ntohl(userDataLength);\r
+ userData = NULL;\r
+ if (userDataLength > 0)\r
+ {\r
+ userData = (UCHAR*)malloc(userDataLength);\r
+ if (!userData) break;\r
+ if (!tcp->readData(userData, userDataLength)) break;\r
+ }\r
+\r
+ vresp = new VDR_ResponsePacket(); \r
+ vresp->setStream(streamID, flag, userData, userDataLength);\r
+// logger->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, flag=%lu, len=%lu", streamID, flag, userDataLength);\r
+\r
+ if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
+ {\r
+ // If edFindAndCall returns true, edr was called and vresp was handed off.\r
+ // else, delete vresp here.\r
+ delete vresp;\r
+ }\r
+ }\r
+ else if (channelID == CHANNEL_KEEPALIVE)\r
+ {\r
+ ULONG KAreply = 0;\r
+ if (!tcp->readData((UCHAR*)&KAreply, sizeof(ULONG))) break;\r
+ KAreply = (ULONG)ntohl(KAreply);\r
+ if (KAreply == lastKAsent) // successful KA response\r
+ {\r
+ lastKAsent = 0;\r
+ lastKArecv = KAreply;\r
+ logger->log("VDR", Log::DEBUG, "Rxd correct KA reply");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ logger->log("VDR", Log::ERR, "Rxd a response packet on channel %lu !!", channelID);\r
+ break;\r
+ }\r
+ threadCheckExit();\r
+\r
+\r
+ // Who deletes vresp?\r
+ // If RR, the individual protocol functions must delete vresp.\r
+ // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there.\r
+ }\r
+ \r
+ connectionDied();\r
+}\r
+\r
+void VDR::connectionDied()\r
+{\r
+ // Called from within threadMethod to do cleanup if it decides the connection has died\r
+\r
+ connected = false; // though actually it could still be connected until someone calls vdr->disconnect\r
+\r
+ // Need to wake up any waiting channel 1 request-response threads\r
+ // Normally this is done by a packet coming in with channelid and requestid \r
+ // Instead, go through the list and for each channel 1 edr, make an empty vresp\r
+ // An empty vresp will have userData == NULL, which means vresp->noResponse() == true\r
+\r
+ // If it's a stream receiver, generate a stream packet with flag == connection_lost\r
+\r
+ edLock();\r
+ VDR_PacketReceiver* vdrpr;\r
+ VDR_ResponsePacket* vresp;\r
+ while(receivers.size())\r
+ {\r
+ vdrpr = (VDR_PacketReceiver*) *(receivers.begin());\r
+ if (vdrpr->receiverChannel == CHANNEL_REQUEST_RESPONSE)\r
+ {\r
+ vresp = new VDR_ResponsePacket();\r
+ vresp->setResponse(vdrpr->requestSerialNumber, NULL, 0);\r
+ logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for request serial %lu", vdrpr->requestSerialNumber);\r
+ edUnlock();\r
+ if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
+ {\r
+ // If edFindAndCall returns true, edr was called and vresp was handed off.\r
+ // else, delete vresp here.\r
+ logger->log("VDR", Log::ERR, "Timeouts: no waiting thread found for request serial %lu !!!", vdrpr->requestSerialNumber);\r
+ delete vresp;\r
+ }\r
+ edLock();\r
+ }\r
+ else if (vdrpr->receiverChannel == CHANNEL_STREAM)\r
+ {\r
+ vresp = new VDR_ResponsePacket();\r
+ vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0);\r
+ logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for streamid %lu", vdrpr->streamID);\r
+ edUnlock();\r
+ if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
+ {\r
+ // If edFindAndCall returns true, edr was called and vresp was handed off.\r
+ // else, delete vresp here.\r
+ logger->log("VDR", Log::ERR, "Timeouts: no waiting stream receiver found for streamid %lu !!!", vdrpr->streamID);\r
+ delete vresp;\r
+ }\r
+ edLock();\r
+ \r
+ for(EDRL::iterator i = receivers.begin(); i != receivers.end(); i++)\r
+ if ((VDR_PacketReceiver*)*i == vdrpr) { receivers.erase(i); break; }\r
+ }\r
+ }\r
+ edUnlock();\r
+ // Ok, all event receviers should be dealt with. just in case there weren't any, inform command\r
+ logger->log("VDR", Log::DEBUG, "edUnlock at end of connectionDied");\r
+\r
+ Command::getInstance()->connectionLost();\r
+}\r
+\r
+bool VDR::ed_cb_find(EDReceiver* edr, void* userTag)\r
+{\r
+ // edr is a VDR_PacketReceiver object made in VDR::RequestResponse\r
+ // userTag is a VDR_ResponsePacket made in threadMethod\r
+\r
+ VDR_PacketReceiver* vdrpr = (VDR_PacketReceiver*)edr;\r
+ VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;\r
+ \r
+ // Is vresp for vdrpr ?\r
+ \r
+ ULONG packetChannel = vresp->getChannelID();\r
+ if (vdrpr->receiverChannel != packetChannel) return false;\r
+\r
+ if (packetChannel == CHANNEL_REQUEST_RESPONSE)\r
+ {\r
+ if (vdrpr->requestSerialNumber == vresp->getRequestID()) return true;\r
+ }\r
+ else if (packetChannel == CHANNEL_STREAM)\r
+ {\r
+ if (vdrpr->streamID == vresp->getStreamID()) return true;\r
+ }\r
+ \r
+ return false;\r
+}\r
+\r
+VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)\r
+{\r
+ //logger->log("VDR", Log::DEBUG, "RR %lu", vrp->getOpcode());\r
+\r
+ if (!connected)\r
+ {\r
+ logger->log("VDR", Log::DEBUG, "RR when !connected");\r
+ VDR_ResponsePacket* vresp = new VDR_ResponsePacket();\r
+ return vresp; // "no-response" return\r
+ }\r
+\r
+ // ED make new VDR and register\r
+ // make a VDR_PacketReceiver\r
+ // - init with serial number of request packet\r
+\r
+ VDR_PacketReceiver vdrpr;\r
+// vdrpr.requestTime = time(NULL);\r
+ vdrpr.receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE;\r
+ vdrpr.requestSerialNumber = vrp->getSerial();\r
+\r
+ edRegister(&vdrpr);\r
+ \r
+ edLock(); \r
+\r
+ if ((ULONG)tcp->sendData(vrp->getPtr(), vrp->getLen()) != vrp->getLen())\r
+ {\r
+ edUnlock();\r
+ edUnregister(&vdrpr);\r
+ VDR_ResponsePacket* vresp = new VDR_ResponsePacket();\r
+ return vresp; // "no-response" return\r
+ }\r
+\r
+ // Sleep and block this thread. The sleep unlocks the mutex\r
+ logger->log("VDR", Log::DEBUG, "RR sleep - opcode %lu", vrp->getOpcode());\r
+ edSleepThisReceiver(&vdrpr);\r
+ logger->log("VDR", Log::DEBUG, "RR unsleep");\r
+ \r
+ // Woken because a response packet has arrived, mutex will be locked\r
+ \r
+ edUnlock();\r
+ return vdrpr.save_vresp;\r
+}\r
+\r
+bool VDR::sendKA(ULONG timeStamp)\r
+{\r
+ char buffer[8];\r
+\r
+ int pos=0;\r
+ ULONG ul=CHANNEL_KEEPALIVE;\r
+ buffer[pos++]=(ul>>24)&0xff;\r
+ buffer[pos++]=(ul>>16)&0xff;\r
+ buffer[pos++]=(ul>>8)&0xff;\r
+ buffer[pos++]=ul &0xff;\r
+ ul=timeStamp;\r
+ buffer[pos++]=(ul>>24)&0xff;\r
+ buffer[pos++]=(ul>>16)&0xff;\r
+ buffer[pos++]=(ul>>8)&0xff;\r
+ buffer[pos++]=ul &0xff;\r
+ if ((ULONG)tcp->sendData(buffer, 8) != 8) return false;\r
+ return true;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+// Here VDR takes a break for the VDR_PacketReceiver helper class\r
+\r
+bool VDR_PacketReceiver::call(void* userTag)\r
+{\r
+ if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE)\r
+ {\r
+ // It's a RR. Save vresp and, signal the waiting thread and return.\r
+ // VDR::RequestResponse will be blocking waiting for this to happen.\r
+ // That function has a pointer to this object and can read save_vresp.\r
+ save_vresp = (VDR_ResponsePacket*)userTag;\r
+ return true; // Signals ED to remove edr from receivers and wake up edr thread\r
+ }\r
+ \r
+ if (receiverChannel == VDR::CHANNEL_STREAM)\r
+ {\r
+ // It's a stream packet.\r
+ VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;\r
+ streamReceiver->streamReceive(vresp->getFlag(), vresp->getUserData(), vresp->getUserDataLength());\r
+ delete vresp;\r
+ return false;\r
+ }\r
+\r
+ abort(); // unknown receiverChannel, should not happen\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+int VDR::doLogin()\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_LOGIN, true, 6)) return 0;\r
+\r
+ char* mactemp[6];\r
+ tcp->getMAC((char*)mactemp);\r
+ if (!vrp.copyin((UCHAR*)mactemp, 6)) return 0;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+\r
+ ULONG vdrTime = vresp->extractULONG();\r
+ logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);\r
+ long vdrTimeOffset = vresp->extractLONG();\r
+ logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);\r
+\r
+ delete vresp;\r
+\r
+ // Set the time and zone on the MVP only\r
+\r
+#if !defined(WIN32) && !defined(__ANDROID__)\r
+ struct timespec currentTime;\r
+ currentTime.tv_sec = vdrTime;\r
+ currentTime.tv_nsec = 0;\r
+\r
+ int b = clock_settime(CLOCK_REALTIME, ¤tTime);\r
+\r
+ logger->log("VDR", Log::DEBUG, "set clock = %u", b);\r
+\r
+ // now make a TZ variable and set it\r
+ char sign;\r
+ int hours;\r
+ int minutes;\r
+ if (vdrTimeOffset > 0) sign = '-';\r
+ else sign = '+';\r
+\r
+ vdrTimeOffset = abs(vdrTimeOffset);\r
+\r
+ hours = (int)vdrTimeOffset / 3600;\r
+ minutes = vdrTimeOffset % 3600;\r
+\r
+ logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);\r
+\r
+ minutes = (int)minutes / 60;\r
+\r
+ logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);\r
+\r
+ char newTZ[30];\r
+ sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);\r
+ setenv("TZ", newTZ, 1);\r
+\r
+ logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);\r
+#endif\r
+\r
+ setCharset(Osd::getInstance()->charSet());\r
+\r
+ return 1;\r
+}\r
+\r
+bool VDR::LogExtern(const char* logString)\r
+{\r
+ if (!connected) return false;\r
+ int stringLength = strlen(logString);\r
+ int packetLength = stringLength + 8;\r
+ char *buffer=new char[packetLength + 1];\r
+ int pos=0;\r
+ ULONG ul=CHANNEL_NETLOG;\r
+ buffer[pos++]=(ul>>24)&0xff;\r
+ buffer[pos++]=(ul>>16)&0xff;\r
+ buffer[pos++]=(ul>>8)&0xff;\r
+ buffer[pos++]=ul &0xff;\r
+ ul=stringLength;\r
+ buffer[pos++]=(ul>>24)&0xff;\r
+ buffer[pos++]=(ul>>16)&0xff;\r
+ buffer[pos++]=(ul>>8)&0xff;\r
+ buffer[pos++]=ul &0xff;\r
+\r
+ strcpy(&buffer[8], logString);\r
+ \r
+ if ((ULONG)tcp->sendData(buffer, packetLength) != packetLength) {\r
+ delete [] buffer;\r
+ return false;\r
+ }\r
+ delete [] buffer;\r
+ return true;\r
+}\r
+\r
+bool VDR::setCharset(int charset)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_SETCHARSET, true, sizeof(ULONG))) return false;\r
+ if (!vrp.addULONG(charset)) return false;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return false; }\r
+\r
+ ULONG success = vresp->extractULONG();\r
+ delete vresp;\r
+\r
+ if (!success) return false;\r
+\r
+ return true;\r
+}\r
+\r
+bool VDR::getRecordingsList(RecMan* recman)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETRECORDINGLIST, true, 0)) return false;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return false; }\r
+\r
+ ULONG totalSpace = vresp->extractULONG();\r
+ ULONG freeSpace = vresp->extractULONG();\r
+ ULONG percent = vresp->extractULONG();\r
+\r
+ recman->setStats(totalSpace, freeSpace, percent);\r
+\r
+ ULONG start;\r
+ char* name;\r
+ char* fileName;\r
+\r
+ while (!vresp->end())\r
+ {\r
+\r
+ start = vresp->extractULONG();\r
+ name = vresp->extractString();\r
+ fileName = vresp->extractString();\r
+ recman->addEntry(start, name, fileName);\r
+ delete[] name;\r
+ delete[] fileName;\r
+ }\r
+ delete vresp;\r
+\r
+ return true;\r
+}\r
+\r
+int VDR::deleteRecording(char* fileName)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_DELETERECORDING, true, strlen(fileName) + 1)) return 0;\r
+ if (!vrp.addString(fileName)) return 0;\r
+ \r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+ \r
+ int toReturn = (int)vresp->extractULONG();\r
+ delete vresp;\r
+\r
+ return toReturn;\r
+}\r
+\r
+char* VDR::moveRecording(char* fileName, char* newPath)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_MOVERECORDING, true, strlen(fileName) + 1 + strlen(newPath) + 1)) return NULL;\r
+ if (!vrp.addString(fileName)) return NULL;\r
+ if (!vrp.addString(newPath)) return NULL;\r
+ \r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return NULL; }\r
+ \r
+ char* toReturn = NULL;\r
+ int success = (int)vresp->extractULONG();\r
+ if (success == 1)\r
+ {\r
+ toReturn = vresp->extractString();\r
+ }\r
+\r
+ delete vresp;\r
+\r
+ return toReturn;\r
+}\r
+\r
+ChannelList* VDR::getChannelsList(ULONG type)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETCHANNELLIST, true, 0)) return NULL;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return NULL; }\r
+ \r
+ ChannelList* chanList = new ChannelList();\r
+\r
+ bool h264support=Video::getInstance()->supportsh264();\r
+\r
+ while (!vresp->end())\r
+ {\r
+ Channel* chan = new Channel();\r
+ chan->number = vresp->extractULONG();\r
+ chan->type = vresp->extractULONG();\r
+ chan->name = vresp->extractString();\r
+ chan->vstreamtype = vresp->extractULONG();\r
+\r
+ if (chan->type == type && (chan->vstreamtype!=0x1b || h264support))\r
+ {\r
+ chanList->push_back(chan);\r
+ logger->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);\r
+ if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;\r
+ }\r
+ else\r
+ {\r
+ delete chan;\r
+ }\r
+ }\r
+\r
+ delete vresp;\r
+\r
+ if (maxChannelNumber > 99999)\r
+ channelNumberWidth = 6;\r
+ else if (maxChannelNumber > 9999)\r
+ channelNumberWidth = 5;\r
+ else if (maxChannelNumber > 999)\r
+ channelNumberWidth = 4;\r
+ else if (maxChannelNumber > 99)\r
+ channelNumberWidth = 3;\r
+ else if (maxChannelNumber > 9)\r
+ channelNumberWidth = 2;\r
+ else\r
+ channelNumberWidth = 1;\r
+\r
+ return chanList;\r
+}\r
+\r
+int VDR::streamChannel(ULONG number, StreamReceiver* tstreamReceiver)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_STREAMCHANNEL, true, sizeof(ULONG))) return 0;\r
+ if (!vrp.addULONG(number)) return 0;\r
+ \r
+ \r
+ VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();\r
+ vdrpr->receiverChannel = VDR::CHANNEL_STREAM;\r
+ vdrpr->streamID = vrp.getSerial();\r
+ vdrpr->streamReceiver = tstreamReceiver;\r
+ edRegister(vdrpr);\r
+ TEMP_SINGLE_VDR_PR = vdrpr;\r
+ \r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse())\r
+ {\r
+ delete vresp;\r
+ edUnregister(vdrpr);\r
+ delete vdrpr;\r
+ return 0;\r
+ }\r
+ \r
+ int toReturn = (int)vresp->extractULONG();\r
+ logger->log("VDR", Log::DEBUG, "VDR said %lu to start streaming request", toReturn);\r
+ delete vresp;\r
+\r
+ return toReturn;\r
+}\r
+\r
+int VDR::stopStreaming()\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_STOPSTREAMING, true, 0)) return 0;\r
+\r
+ if (TEMP_SINGLE_VDR_PR) // this block only needs to be done if it was a live stream\r
+ // TEMP_SINGLE_VDR_PR will not be set unless we are streaming a channel\r
+ {\r
+ edUnregister(TEMP_SINGLE_VDR_PR);\r
+ delete TEMP_SINGLE_VDR_PR;\r
+ TEMP_SINGLE_VDR_PR = NULL;\r
+ }\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+ \r
+ int toReturn = (int)vresp->extractULONG();\r
+ delete vresp;\r
+\r
+ return toReturn;\r
+}\r
+\r
+UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETBLOCK, true, sizeof(ULLONG) + sizeof(ULONG))) return NULL;\r
+ if (!vrp.addULLONG(position)) return NULL;\r
+ if (!vrp.addULONG(maxAmount)) return NULL;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return NULL; }\r
+\r
+ if (vresp->serverError())\r
+ {\r
+ logger->log("VDR", Log::DEBUG, "Detected getblock 0");\r
+ delete vresp;\r
+ return NULL;\r
+ }\r
+\r
+ // Special handling for getblock\r
+ UCHAR* toReturn = vresp->getUserData();\r
+ *amountReceived = vresp->getUserDataLength();\r
+ \r
+ delete vresp;\r
+ \r
+ return toReturn;\r
+}\r
+\r
+ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames, bool* IsPesRecording)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_STREAMRECORDING, true, strlen(fileName) + 1)) return 0;\r
+ if (!vrp.addString(fileName)) return 0;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+ \r
+ ULLONG lengthBytes = vresp->extractULLONG();\r
+ ULONG lengthFrames = vresp->extractULONG();\r
+ UCHAR isPesRecording = vresp->extractUCHAR();\r
+ delete vresp;\r
+\r
+ *totalFrames = lengthFrames;\r
+ *IsPesRecording = (isPesRecording);//convert Uchar to bool\r
+\r
+ logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu, IsPesRecording %x", lengthBytes, lengthFrames, *IsPesRecording);\r
+\r
+ return lengthBytes;\r
+}\r
+\r
+ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_POSFROMFRAME, true, sizeof(ULONG))) return 0;\r
+ if (!vrp.addULONG(frameNumber)) return 0;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+ \r
+ ULLONG position = vresp->extractULLONG();\r
+ delete vresp;\r
+ \r
+ logger->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);\r
+\r
+ return position;\r
+}\r
+\r
+ULONG VDR::frameNumberFromPosition(ULLONG position)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_FRAMEFROMPOS, true, sizeof(ULLONG))) return 0;\r
+ if (!vrp.addULLONG(position)) return 0;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+ \r
+ ULONG framenumber = vresp->extractULONG();\r
+ delete vresp;\r
+ \r
+ logger->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);\r
+\r
+ return framenumber;\r
+}\r
+\r
+bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETNEXTIFRAME, true, sizeof(ULONG)*2)) return false;\r
+ if (!vrp.addULONG(frameNumber)) return false;\r
+ if (!vrp.addULONG(direction)) return false;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return false; }\r
+ \r
+ if (vresp->serverError())\r
+ {\r
+ logger->log("VDR", Log::DEBUG, "Detected getNextIFrame error");\r
+ delete vresp;\r
+ return false;\r
+ }\r
+\r
+ *rfilePosition = vresp->extractULLONG();\r
+ *rframeNumber = vresp->extractULONG();\r
+ *rframeLength = vresp->extractULONG();\r
+\r
+ delete vresp;\r
+\r
+ logger->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);\r
+\r
+ return true;\r
+}\r
+\r
+EventList* VDR::getChannelSchedule(ULONG number)\r
+{\r
+ time_t now;\r
+ time(&now);\r
+ return getChannelSchedule(number, now, 24 * 60 * 60);\r
+}\r
+\r
+EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)\r
+{\r
+// retrieve event list (vector of events) from vdr within filter window. duration is in seconds\r
+\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETCHANNELSCHEDULE, true, sizeof(ULONG)*3)) return NULL;\r
+ if (!vrp.addULONG(number)) return NULL;\r
+ if (!vrp.addULONG(start)) return NULL;\r
+ if (!vrp.addULONG(duration)) return NULL;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return NULL; }\r
+ \r
+ // received a ulong(0) - schedules error in the plugin\r
+ if (vresp->serverError())\r
+ {\r
+ delete vresp;\r
+ return NULL;\r
+ }\r
+\r
+ EventList* eventList = new EventList();\r
+\r
+ while (!vresp->end())\r
+ {\r
+ Event* event = new Event();\r
+ event->id = vresp->extractULONG();\r
+ event->time = vresp->extractULONG();\r
+ event->duration = vresp->extractULONG();\r
+ event->title = vresp->extractString();\r
+ event->subtitle = vresp->extractString();\r
+ event->description = vresp->extractString();\r
+ eventList->push_back(event);\r
+ }\r
+\r
+ delete vresp;\r
+\r
+ logger->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");\r
+ return eventList;\r
+}\r
+\r
+int VDR::configSave(const char* section, const char* key, const char* value)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_CONFIGSAVE, false, 0)) return 0;\r
+ if (!vrp.addString(section)) return 0;\r
+ if (!vrp.addString(key)) return 0;\r
+ if (!vrp.addString(value)) return 0;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+ \r
+ int toReturn = (int)vresp->extractULONG();\r
+ delete vresp;\r
+\r
+ return toReturn;\r
+}\r
+\r
+char* VDR::configLoad(const char* section, const char* key)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_CONFIGLOAD, false, 0)) return NULL;\r
+ if (!vrp.addString(section)) return NULL;\r
+ if (!vrp.addString(key)) return NULL;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return NULL; }\r
+ \r
+ char* toReturn = vresp->extractString();\r
+ delete vresp;\r
+\r
+ return toReturn;\r
+}\r
+\r
+RecTimerList* VDR::getRecTimersList()\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETTIMERS, true, 0)) return NULL;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return NULL; }\r
+\r
+ RecTimerList* recTimerList = new RecTimerList();\r
+\r
+ ULONG numTimers = vresp->extractULONG();\r
+ if (numTimers > 0)\r
+ {\r
+ RecTimer* newRecTimer;\r
+ char* tempString;\r
+\r
+ while (!vresp->end())\r
+ {\r
+ newRecTimer = new RecTimer();\r
+ newRecTimer->active = vresp->extractULONG();\r
+ newRecTimer->recording = vresp->extractULONG();\r
+ newRecTimer->pending = vresp->extractULONG();\r
+ newRecTimer->priority = vresp->extractULONG();\r
+ newRecTimer->lifeTime = vresp->extractULONG();\r
+ newRecTimer->channelNumber = vresp->extractULONG();\r
+ newRecTimer->startTime = vresp->extractULONG();\r
+ newRecTimer->stopTime = vresp->extractULONG();\r
+ newRecTimer->day = vresp->extractULONG();\r
+ newRecTimer->weekDays = vresp->extractULONG();\r
+\r
+ tempString = vresp->extractString();\r
+ newRecTimer->setFile(tempString);\r
+ delete[] tempString;\r
+\r
+ recTimerList->push_back(newRecTimer);\r
+ logger->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",\r
+ newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,\r
+ newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());\r
+ }\r
+ }\r
+\r
+ delete vresp;\r
+\r
+ sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());\r
+\r
+ return recTimerList;\r
+}\r
+\r
+ULONG VDR::setEventTimer(char* timerString)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_SETTIMER, true, strlen(timerString) + 1)) return 0;\r
+ if (!vrp.addString(timerString)) return 0;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+ \r
+ ULONG toReturn = vresp->extractULONG();\r
+ delete vresp;\r
+\r
+ return toReturn;\r
+}\r
+\r
+RecInfo* VDR::getRecInfo(char* fileName)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETRECINFO, true, strlen(fileName) + 1)) return NULL;\r
+ if (!vrp.addString(fileName)) return NULL;\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+\r
+ if (vresp->noResponse()) { delete vresp; return NULL; }\r
+\r
+ if (vresp->serverError())\r
+ {\r
+ logger->log("VDR", Log::DEBUG, "Could not get rec info");\r
+ delete vresp;\r
+ return NULL;\r
+ }\r
+\r
+ RecInfo* recInfo = new RecInfo();\r
+\r
+ recInfo->timerStart = vresp->extractULONG();\r
+ recInfo->timerEnd = vresp->extractULONG();\r
+ recInfo->resumePoint = vresp->extractULONG();\r
+ recInfo->summary = vresp->extractString();\r
+\r
+ ULONG numComponents = vresp->extractULONG();\r
+ if (numComponents)\r
+ {\r
+ recInfo->setNumComponents(numComponents);\r
+ for (ULONG i = 0; i < numComponents; i++)\r
+ {\r
+ recInfo->streams[i] = vresp->extractUCHAR();\r
+ recInfo->types[i] = vresp->extractUCHAR();\r
+ recInfo->languages[i] = vresp->extractString();\r
+ recInfo->descriptions[i] = vresp->extractString();\r
+ }\r
+ }\r
+ recInfo->fps=vresp->extractdouble();\r
+ \r
+\r
+ recInfo->print();\r
+\r
+ delete vresp;\r
+ return recInfo;\r
+}\r
+\r
+// FIXME obselete\r
+ULLONG VDR::rescanRecording(ULONG* totalFrames)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_RESCANRECORDING, true, 0)) return 0;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+ \r
+ ULLONG lengthBytes = vresp->extractULLONG();\r
+ ULONG lengthFrames = vresp->extractULONG();\r
+ delete vresp;\r
+ \r
+ logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);\r
+\r
+ *totalFrames = lengthFrames;\r
+ return lengthBytes;\r
+}\r
+\r
+MarkList* VDR::getMarks(char* fileName)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETMARKS, true, strlen(fileName) + 1)) return NULL;\r
+ if (!vrp.addString(fileName)) return NULL;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return NULL; }\r
+ \r
+ if (vresp->serverError())\r
+ {\r
+ delete vresp;\r
+ return NULL;\r
+ }\r
+\r
+ MarkList* markList = new MarkList();\r
+\r
+ while (!vresp->end())\r
+ {\r
+ Mark* mark = new Mark();\r
+ mark->pos = vresp->extractULONG();\r
+\r
+ markList->push_back(mark);\r
+ logger->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);\r
+ }\r
+\r
+ delete vresp;\r
+ \r
+ return markList;\r
+}\r
+\r
+void VDR::getChannelPids(Channel* channel)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETCHANNELPIDS, true, sizeof(ULONG))) return ;\r
+ if (!vrp.addULONG(channel->number)) return ;\r
+\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return ; }\r
+ \r
+ // Format of response\r
+ // vpid\r
+ // number of apids\r
+ // {\r
+ // apid\r
+ // lang string\r
+ // }\r
+\r
+ channel->vpid = vresp->extractULONG();\r
+ channel->vstreamtype = vresp->extractULONG();\r
+ channel->numAPids = vresp->extractULONG();\r
+\r
+ for (ULONG i = 0; i < channel->numAPids; i++)\r
+ {\r
+ apid newapid;\r
+ newapid.pid = vresp->extractULONG();\r
+ newapid.name = vresp->extractString();\r
+ channel->apids.push_back(newapid);\r
+ }\r
+\r
+ channel->numDPids = vresp->extractULONG();\r
+\r
+ for (ULONG i = 0; i < channel->numDPids; i++)\r
+ {\r
+ apid newdpid;\r
+ newdpid.pid = vresp->extractULONG();\r
+ newdpid.name = vresp->extractString();\r
+ channel->dpids.push_back(newdpid);\r
+ }\r
+\r
+ channel->numSPids = vresp->extractULONG();\r
+\r
+ for (ULONG i = 0; i < channel->numSPids; i++)\r
+ {\r
+ apid newspid;\r
+ newspid.pid = vresp->extractULONG();\r
+ newspid.name = vresp->extractString();\r
+ channel->spids.push_back(newspid);\r
+ }\r
+ channel->tpid = vresp->extractULONG();\r
+\r
+ delete vresp;\r
+ \r
+ return ;\r
+}\r
+\r
+\r
+MediaList * VDR::getRootList() {\r
+ return getMediaList(NULL);\r
+}\r
+/**\r
+ * media List Request:\r
+ * mediaURI\r
+ * Media List response:\r
+ * mediaList\r
+*/\r
+MediaList* VDR::getMediaList(const MediaURI * root)\r
+{\r
+ logger->log("VDR", Log::DEBUG, "getMediaList %s,d=%s, prov=%d", (root?root->getName():"NULL"), \r
+ ((root && root->hasDisplayName())?root->getDisplayName():"NULL"),\r
+ (root?root->getProvider():providerId));\r
+ MediaURI remoteURI(root);\r
+ VDR_GetMediaListRequest request(&remoteURI);\r
+ SerializeBuffer *vrp=prepareRequest(&request);\r
+ if (!vrp) {\r
+ logger->log("VDR", Log::ERR, "getMediaList unable to create command");\r
+ return NULL;\r
+ }\r
+ \r
+ SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
+ if (!vresp) {\r
+ Command::getInstance()->connectionLost();\r
+ return NULL;\r
+ }\r
+ \r
+ MediaList *rt=new MediaList(NULL);\r
+ ULONG rtflags=0;\r
+ VDR_GetMediaListResponse resp(&rtflags,rt);\r
+ if (decodeResponse(vresp,&resp) != 0) {\r
+ return NULL;\r
+ }\r
+ return rt;\r
+}\r
+\r
+/**\r
+ * get image Request:\r
+ * uri,x,y, channel\r
+ * get media response:\r
+ * 4 flags\r
+ * 8 len of image\r
+*/\r
+int VDR::openMedium(ULONG channel,const MediaURI *uri, ULLONG * size, ULONG x, ULONG y)\r
+{\r
+ MediaURI remoteURI(uri);\r
+ VDR_OpenMediumRequest request(&channel,&remoteURI,&x,&y);\r
+ *size=0;\r
+ SerializeBuffer *vrp=prepareRequest(&request);\r
+ if (!vrp) {\r
+ logger->log("VDR", Log::ERR, "openMedium unable to create command");\r
+ return -1;\r
+ }\r
+ SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
+ if (!vresp) {\r
+ Command::getInstance()->connectionLost();\r
+ return -1;\r
+ }\r
+ ULONG flags=0;\r
+ VDR_OpenMediumResponse response(&flags,size);\r
+ if (decodeResponse(vresp,&response) != 0) {\r
+ return -1;\r
+ }\r
+ logger->log("VDR", Log::DEBUG, "openMedia len=%llu", *size);\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * getMediaBlock - no separate response class - simple data block\r
+ * resp\r
+ * packet\r
+ */\r
+int VDR::getMediaBlock(ULONG channel, ULLONG position, ULONG maxAmount, ULONG* amountReceived, unsigned char **buffer)\r
+{\r
+ *amountReceived=0;\r
+ VDR_GetMediaBlockRequest request(&channel,&position,&maxAmount);\r
+ SerializeBuffer *vrp=prepareRequest(&request);\r
+ if (!vrp) {\r
+ logger->log("VDR", Log::ERR, "getMediaBlock unable to create command");\r
+ return -1;\r
+ }\r
+ SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
+ if (!vresp) {\r
+ Command::getInstance()->connectionLost();\r
+ return -1;\r
+ }\r
+ \r
+ // Special handling for getblock\r
+ *amountReceived = (ULONG)(vresp->getEnd()-vresp->getStart());\r
+ *buffer = vresp->steelBuffer();\r
+ delete vresp;\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * VDR_GETMEDIAINFO\r
+ * channel\r
+ * rt\r
+ * flags\r
+ * info\r
+ */\r
+\r
+int VDR::getMediaInfo(ULONG channel, MediaInfo * result) {\r
+ if (! result) return -1;\r
+ VDR_GetMediaInfoRequest request(&channel);\r
+ SerializeBuffer *vrp=prepareRequest(&request);\r
+ if (!vrp) {\r
+ logger->log("VDR", Log::ERR, "getMediaInfo unable to create command");\r
+ return -1;\r
+ }\r
+ SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
+ if (!vresp) {\r
+ Command::getInstance()->connectionLost();\r
+ return -1;\r
+ }\r
+\r
+ ULONG flags=0;\r
+ VDR_GetMediaInfoResponse response(&flags,result);\r
+ if (decodeResponse(vresp,&response) != 0) {\r
+ return -1;\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * VDR_CLOSECHANNEL\r
+ * channel\r
+ * rt\r
+ * flags\r
+ */\r
+\r
+int VDR::closeMediaChannel(ULONG channel) {\r
+ VDR_CloseMediaChannelRequest request(&channel);\r
+ SerializeBuffer *vrp=prepareRequest(&request);\r
+ if (!vrp) {\r
+ logger->log("VDR", Log::ERR, "closeMediaChannel unable to create command");\r
+ return -1;\r
+ }\r
+ SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
+ if (!vresp) {\r
+ Command::getInstance()->connectionLost();\r
+ return -1;\r
+ }\r
+ ULONG flags;\r
+ VDR_CloseMediaChannelResponse response(&flags);\r
+ if (decodeResponse(vresp,&response) != 0) return -1;\r
+ return (flags != 0)?-1:0;\r
+}\r
+\r
+\r
+\r
+\r
+int VDR::deleteTimer(RecTimer* delTimer)\r
+{\r
+ logger->log("VDR", Log::DEBUG, "Delete timer called");\r
+ \r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_DELETETIMER, false, 0)) return 0;\r
+ if (!vrp.addULONG(delTimer->channelNumber)) return 0;\r
+ if (!vrp.addULONG(delTimer->weekDays)) return 0; \r
+ if (!vrp.addULONG(delTimer->day)) return 0;\r
+ if (!vrp.addULONG(delTimer->startTime)) return 0; \r
+ if (!vrp.addULONG(delTimer->stopTime)) return 0; \r
+ \r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+ \r
+ int toReturn = (int)vresp->extractULONG();\r
+ delete vresp;\r
+\r
+ return toReturn;\r
+}\r
+\r
+I18n::lang_code_list VDR::getLanguageList()\r
+{\r
+ I18n::lang_code_list CodeList;\r
+ CodeList["en"] = "English"; // Default entry\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETLANGUAGELIST, false, 0)) return CodeList;\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse() || vresp->end())\r
+ {\r
+ delete vresp;\r
+ return CodeList;\r
+ }\r
+ CodeList.clear();\r
+ while (!vresp->end())\r
+ {\r
+ char* c_code = vresp->extractString();\r
+ char* c_name = vresp->extractString();\r
+ string code = c_code;\r
+ string name = c_name;\r
+ CodeList[code] = name;\r
+ delete[] c_code;\r
+ delete[] c_name;\r
+ }\r
+ delete vresp;\r
+ return CodeList;\r
+}\r
+\r
+int VDR::getLanguageContent(const std::string code, I18n::trans_table& texts)\r
+{\r
+ VDR_RequestPacket vrp;\r
+ if (!vrp.init(VDR_GETLANGUAGECONTENT, false, 0)) return 0;\r
+ if (!vrp.addString(code.c_str())) return 0;\r
+ VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+ if (vresp->noResponse()) { delete vresp; return 0; }\r
+ texts.clear();\r
+ while (!vresp->end())\r
+ {\r
+ char* c_key = vresp->extractString();\r
+ char* c_text = vresp->extractString();\r
+ string key = c_key;\r
+ string text = c_text;\r
+ texts[key] = text;\r
+ delete[] c_key;\r
+ delete[] c_text;\r
+ }\r
+ delete vresp;\r
+ return 1;\r
+}\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-
-// FIXME - This and the protocol are overly complicated now. Sorry.
-// I'll clean it up in a couple of releases time...
-
-
-#ifndef VDR_H
-#define VDR_H
-
-#include <stdio.h>
-#include <time.h>
-#include <vector>
-#include <algorithm>
-
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
-#include "defines.h"
-#include "rectimer.h"
-#include "mark.h"
-#include "mediaprovider.h"
-#include "eventdispatcher.h"
-#include "i18n.h"
-
-class TCP;
-class Log;
-class RecInfo;
-class Event;
-class Channel;
-class VDR_RequestPacket;
-class VDR_ResponsePacket;
-class SerializeBuffer;
-
-using namespace std;
-
-typedef vector<Event*> EventList;
-typedef vector<Channel*> ChannelList;
-typedef vector<RecTimer*> RecTimerList;
-
-struct VDRServer
-{
- char* ip;
- char* name;
-};
-
-struct RecTimerSorter // : public binary_function<double, double, bool>
-{
- bool operator() (const RecTimer* a, const RecTimer* b)
- {
- return a->startTime < b->startTime;
- }
-};
-
-struct ServerSorter
-{
- bool operator() (const VDRServer& a, const VDRServer& b)
- {
- if (strcmp(b.name, a.name) > 0) return true;
- return false;
- }
-};
-
-class RecMan;
-
-class StreamReceiver
-{
- public:
- virtual void streamReceive(ULONG, void*, ULONG)=0;
-};
-
-class VDR_PacketReceiver : public EDReceiver // implementation in vdr.cc
-{
- public:
- virtual bool call(void* userTag);
-
- friend class VDR;
- protected:
-// ULONG requestTime;
- ULONG receiverChannel;
-
- // If receiverChannel == 1:
- ULONG requestSerialNumber; // set by RequestResponse, used in ed_cb_find
- VDR_ResponsePacket* save_vresp; // set by ed_cb_call, used in RequestResponse
-
- // If receiverChannel == 2:
- ULONG streamID;
- StreamReceiver* streamReceiver;
-};
-
-class VDR : public Thread_TYPE, public EventDispatcher, public MediaProvider
-{
-
- public:
- const static ULONG VIDEO = 1;
- const static ULONG RADIO = 2;
-
- const static ULONG CHANNEL_REQUEST_RESPONSE = 1;
- const static ULONG CHANNEL_STREAM = 2;
- const static ULONG CHANNEL_KEEPALIVE = 3;
- const static ULONG CHANNEL_NETLOG = 4;
-
- VDR();
- ~VDR();
- static VDR* getInstance();
-
- int init(int port);
- int shutdown();
-
- void findServers(vector<VDRServer>& servers);
- void cancelFindingServer();
- void setServerIP(char*);
- void setReceiveWindow(size_t size);
- int connect();
- void disconnect();
- bool isConnected() { return connected; }
- ULONG getChannelNumberWidth() { return channelNumberWidth; }
-
- // protocol functions
- // for the following, if result == false then the connection has died
- // doLogin
- // getRecordingList
- // getChannelsList
- // getChannelSchedule
- // getRecTimersList
- // isConnected can be called after the following to determine if still ok
- // deleteRecording
- // streamRecording
- // positionFromFrameNumber
- // streamChannel
- // getBlock
- // stopStreaming
- // configLoad
- // configSave
- // setEventTimer
-
- int doLogin();
- bool getRecordingsList(RecMan* recman);
- RecInfo* getRecInfo(char* fileName);
- int deleteRecording(char* fileName);
- char* moveRecording(char* fileName, char* newPath);
- ULLONG streamRecording(char* fileName, ULONG* lengthFrames, bool* IsPesRecording);
- ULLONG positionFromFrameNumber(ULONG frameNumber);
- ULONG frameNumberFromPosition(ULLONG position);
- bool getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength);
- // Direction: 0=backwards, 1=forwards
- MarkList* getMarks(char* fileName);
- int deleteTimer(RecTimer* delTimer);
- ChannelList* getChannelsList(ULONG type);
- int streamChannel(ULONG number, StreamReceiver*);
- int streamChannel(ULONG number);
- void getChannelPids(Channel* channel);
- UCHAR* getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived);
- //get image blocks separate - we can do this in parallel
- int stopStreaming();
- EventList* getChannelSchedule(ULONG number);
- EventList* getChannelSchedule(ULONG number, time_t start, ULONG duration);
- int configSave(const char* section, const char* key, const char* value);
- char* configLoad(const char* section, const char* key);
- ULONG setEventTimer(char* timerString);
- RecTimerList* getRecTimersList();
- bool networkLog(const char* buffer);
-
- /**
- * the MediaProvider functions
- *
- */
- virtual MediaList* getRootList();
- virtual MediaList* getMediaList(const MediaURI * parent);
- virtual int openMedium(ULONG channel,const MediaURI *uri,ULLONG * size, ULONG xsize,ULONG ysize);
- virtual int getMediaBlock(ULONG channel, unsigned long long offset, unsigned long len, unsigned long * outlen,
- unsigned char ** buffer);
- virtual int getMediaInfo(ULONG channel, struct MediaInfo * result);
- virtual int closeMediaChannel(ULONG channel);
-
-
- I18n::lang_code_list getLanguageList();
- int getLanguageContent(const string code, I18n::trans_table&);
-
- // end protocol functions
-
-
- // obselete
- ULLONG rescanRecording(ULONG* lengthFrames); // FIXME obselete
-
-
-
- private:
- static VDR* instance;
-
- VDR_ResponsePacket* RequestResponse(VDR_RequestPacket* request);
- UCHAR* getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived, ULONG cmd);
-
- void connectionDied();
- bool sendKA(ULONG timeStamp);
-
- Log* logger;
- int initted;
- int findingServer;
- TCP* tcp;
- int port;
- char serverIP[16];
- bool connected;
- ULONG maxChannelNumber;
- ULONG channelNumberWidth;
- VDR_PacketReceiver* TEMP_SINGLE_VDR_PR;
-
-
- ULONG providerId;
- ULONG subRange;
- SerializeBuffer * doRequestResponse(SerializeBuffer *in,int cmd);
- protected:
-
- // Thread
- void threadMethod();
- void threadPostStopCleanup() {};
-
- // EventDispatcher
- virtual bool ed_cb_find(EDReceiver* edr, void* userTag);
-};
-
-#endif
-
-/*
-
-index.vdr file format for video:
-
-For every video frame:
-{
- File offset 4 bytes
- Picture type 1 byte
- File number 1 byte
- Zero 2 bytes
-}
-
-Picture types:
-
-#define NO_PICTURE 0
-#define I_FRAME 1
-#define P_FRAME 2
-#define B_FRAME 3
-
-
-
-Packet formats
-
-Packet format for an RR channel request:
-
-4 bytes = channel ID = 1 (request/response channel)
-4 bytes = request ID (from serialNumber)
-4 bytes = opcode
-4 bytes = length of the rest of the packet
-? bytes = rest of packet. depends on packet
-
-
-Packet format for an RR channel response:
-
-4 bytes = channel ID = 1 (request/response channel)
-4 bytes = request ID (from serialNumber)
-4 bytes = length of the rest of the packet
-? bytes = rest of packet. depends on packet
-
-
-Packet format for a stream packet:
-
-4 bytes = channel ID = 2 (stream channel)
-4 bytes = stream ID (from requestID)
-4 bytes = length of the stream data (rest of packet)
-? bytes = stream data
-
-*/
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+\r
+// FIXME - This and the protocol are overly complicated now. Sorry.\r
+// I'll clean it up in a couple of releases time...\r
+\r
+\r
+#ifndef VDR_H\r
+#define VDR_H\r
+\r
+#include <stdio.h>\r
+#include <time.h>\r
+#include <vector>\r
+#include <algorithm>\r
+\r
+#include "threadsystem.h"\r
+\r
+#include "defines.h"\r
+#include "rectimer.h"\r
+#include "mark.h"\r
+#include "mediaprovider.h"\r
+#include "eventdispatcher.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+\r
+class TCP;\r
+class Log;\r
+class RecInfo;\r
+class Event;\r
+class Channel;\r
+class VDR_RequestPacket;\r
+class VDR_ResponsePacket;\r
+class SerializeBuffer;\r
+\r
+using namespace std;\r
+\r
+typedef vector<Event*> EventList;\r
+typedef vector<Channel*> ChannelList;\r
+typedef vector<RecTimer*> RecTimerList;\r
+\r
+struct VDRServer\r
+{\r
+ char* ip;\r
+ char* name;\r
+};\r
+\r
+struct RecTimerSorter // : public binary_function<double, double, bool>\r
+{\r
+ bool operator() (const RecTimer* a, const RecTimer* b)\r
+ {\r
+ return a->startTime < b->startTime;\r
+ }\r
+};\r
+\r
+struct ServerSorter\r
+{\r
+ bool operator() (const VDRServer& a, const VDRServer& b)\r
+ {\r
+ if (strcmp(b.name, a.name) > 0) return true;\r
+ return false;\r
+ }\r
+};\r
+\r
+class RecMan;\r
+\r
+class StreamReceiver\r
+{\r
+ public:\r
+ virtual void streamReceive(ULONG, void*, ULONG)=0;\r
+};\r
+\r
+class VDR_PacketReceiver : public EDReceiver // implementation in vdr.cc\r
+{\r
+ public:\r
+ virtual bool call(void* userTag);\r
+\r
+ friend class VDR;\r
+ protected:\r
+// ULONG requestTime;\r
+ ULONG receiverChannel;\r
+ \r
+ // If receiverChannel == 1:\r
+ ULONG requestSerialNumber; // set by RequestResponse, used in ed_cb_find\r
+ VDR_ResponsePacket* save_vresp; // set by ed_cb_call, used in RequestResponse\r
+ \r
+ // If receiverChannel == 2:\r
+ ULONG streamID;\r
+ StreamReceiver* streamReceiver;\r
+};\r
+\r
+class VDR : public Thread_TYPE, public EventDispatcher, public MediaProvider, public ExternLogger\r
+{\r
+\r
+ public:\r
+ const static ULONG VIDEO = 1;\r
+ const static ULONG RADIO = 2;\r
+ \r
+ const static ULONG CHANNEL_REQUEST_RESPONSE = 1;\r
+ const static ULONG CHANNEL_STREAM = 2;\r
+ const static ULONG CHANNEL_KEEPALIVE = 3;\r
+ const static ULONG CHANNEL_NETLOG = 4;\r
+ \r
+ VDR();\r
+ ~VDR();\r
+ static VDR* getInstance();\r
+\r
+ int init(int port);\r
+ int shutdown();\r
+\r
+ void findServers(vector<VDRServer>& servers);\r
+ void cancelFindingServer();\r
+ void setServerIP(char*);\r
+ void setReceiveWindow(size_t size);\r
+ int connect();\r
+ void disconnect();\r
+ bool isConnected() { return connected; }\r
+ ULONG getChannelNumberWidth() { return channelNumberWidth; }\r
+\r
+ // protocol functions\r
+ // for the following, if result == false then the connection has died\r
+ // doLogin\r
+ // getRecordingList\r
+ // getChannelsList\r
+ // getChannelSchedule\r
+ // getRecTimersList\r
+ // isConnected can be called after the following to determine if still ok\r
+ // deleteRecording\r
+ // streamRecording\r
+ // positionFromFrameNumber\r
+ // streamChannel\r
+ // getBlock\r
+ // stopStreaming\r
+ // configLoad\r
+ // configSave\r
+ // setEventTimer\r
+\r
+ int doLogin();\r
+ bool getRecordingsList(RecMan* recman);\r
+ RecInfo* getRecInfo(char* fileName);\r
+ int deleteRecording(char* fileName);\r
+ char* moveRecording(char* fileName, char* newPath);\r
+ ULLONG streamRecording(char* fileName, ULONG* lengthFrames, bool* IsPesRecording);\r
+ ULLONG positionFromFrameNumber(ULONG frameNumber);\r
+ ULONG frameNumberFromPosition(ULLONG position);\r
+ bool getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength);\r
+ // Direction: 0=backwards, 1=forwards\r
+ MarkList* getMarks(char* fileName);\r
+ int deleteTimer(RecTimer* delTimer);\r
+ ChannelList* getChannelsList(ULONG type);\r
+ int streamChannel(ULONG number, StreamReceiver*);\r
+ int streamChannel(ULONG number);\r
+ void getChannelPids(Channel* channel);\r
+ UCHAR* getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived);\r
+ //get image blocks separate - we can do this in parallel\r
+ int stopStreaming();\r
+ EventList* getChannelSchedule(ULONG number);\r
+ EventList* getChannelSchedule(ULONG number, time_t start, ULONG duration);\r
+ int configSave(const char* section, const char* key, const char* value);\r
+ char* configLoad(const char* section, const char* key);\r
+ ULONG setEventTimer(char* timerString);\r
+ RecTimerList* getRecTimersList();\r
+ bool LogExtern(const char* buffer);\r
+ \r
+ bool setCharset(int charset); // 1 latin 2 UTF-8\r
+\r
+ /**\r
+ * the MediaProvider functions\r
+ *\r
+ */\r
+ virtual MediaList* getRootList();\r
+ virtual MediaList* getMediaList(const MediaURI * parent);\r
+ virtual int openMedium(ULONG channel,const MediaURI *uri,ULLONG * size, ULONG xsize,ULONG ysize);\r
+ virtual int getMediaBlock(ULONG channel, unsigned long long offset, unsigned long len, unsigned long * outlen,\r
+ unsigned char ** buffer);\r
+ virtual int getMediaInfo(ULONG channel, struct MediaInfo * result);\r
+ virtual int closeMediaChannel(ULONG channel);\r
+\r
+\r
+ I18n::lang_code_list getLanguageList();\r
+ int getLanguageContent(const string code, I18n::trans_table&);\r
+\r
+ // end protocol functions\r
+\r
+\r
+ // obselete\r
+ ULLONG rescanRecording(ULONG* lengthFrames); // FIXME obselete\r
+\r
+\r
+\r
+ private:\r
+ static VDR* instance;\r
+\r
+ VDR_ResponsePacket* RequestResponse(VDR_RequestPacket* request);\r
+ UCHAR* getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived, ULONG cmd);\r
+ \r
+ void connectionDied();\r
+ bool sendKA(ULONG timeStamp);\r
+ \r
+ Log* logger;\r
+ int initted;\r
+ int findingServer;\r
+ TCP* tcp;\r
+ int port;\r
+ char serverIP[16];\r
+ bool connected;\r
+ ULONG maxChannelNumber;\r
+ ULONG channelNumberWidth;\r
+ VDR_PacketReceiver* TEMP_SINGLE_VDR_PR;\r
+\r
+\r
+ ULONG providerId;\r
+ ULONG subRange;\r
+ SerializeBuffer * doRequestResponse(SerializeBuffer *in,int cmd);\r
+ protected:\r
+ \r
+ // Thread\r
+ void threadMethod();\r
+ void threadPostStopCleanup() {};\r
+\r
+ // EventDispatcher\r
+ virtual bool ed_cb_find(EDReceiver* edr, void* userTag);\r
+};\r
+\r
+#endif\r
+\r
+/*\r
+\r
+index.vdr file format for video:\r
+\r
+For every video frame:\r
+{\r
+ File offset 4 bytes\r
+ Picture type 1 byte\r
+ File number 1 byte\r
+ Zero 2 bytes\r
+}\r
+\r
+Picture types:\r
+\r
+#define NO_PICTURE 0\r
+#define I_FRAME 1\r
+#define P_FRAME 2\r
+#define B_FRAME 3\r
+\r
+\r
+\r
+Packet formats\r
+\r
+Packet format for an RR channel request:\r
+\r
+4 bytes = channel ID = 1 (request/response channel)\r
+4 bytes = request ID (from serialNumber)\r
+4 bytes = opcode\r
+4 bytes = length of the rest of the packet\r
+? bytes = rest of packet. depends on packet\r
+\r
+\r
+Packet format for an RR channel response:\r
+\r
+4 bytes = channel ID = 1 (request/response channel)\r
+4 bytes = request ID (from serialNumber)\r
+4 bytes = length of the rest of the packet\r
+? bytes = rest of packet. depends on packet\r
+\r
+\r
+Packet format for a stream packet:\r
+\r
+4 bytes = channel ID = 2 (stream channel)\r
+4 bytes = stream ID (from requestID)\r
+4 bytes = length of the stream data (rest of packet)\r
+? bytes = stream data\r
+\r
+*/\r
+\r
-/*
- Copyright 2004-2005 Chris Tallon, Andreas Vogel
-
- 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 VDRCOMMAND_H
-#define VDRCOMMAND_H
-
-#include "defines.h"
-#include "serialize.h"
-#include "media.h"
-
-/**
- * data holder for VDR commands
- * it's only important to add serializable objects
- * in the same order on both sides
- */
-
-//until we really have response - commands we simply take
-//the request+this flag for responses
-//not really necessary but for checks it's better to have a command ID at least in some responses
-const static ULONG VDR_RESPONSE_FLAG =0x1000000;
-
-//as this header is only included by vdr.cc the constants are this way private
-//but can easily be used on the server side as well
-
-const static ULONG VDR_LOGIN = 1;
-const static ULONG VDR_GETRECORDINGLIST = 2;
-const static ULONG VDR_DELETERECORDING = 3;
-const static ULONG VDR_GETCHANNELLIST = 5;
-const static ULONG VDR_STREAMCHANNEL = 6;
-const static ULONG VDR_GETBLOCK = 7;
-const static ULONG VDR_STOPSTREAMING = 8;
-const static ULONG VDR_STREAMRECORDING = 9;
-const static ULONG VDR_GETCHANNELSCHEDULE = 10;
-const static ULONG VDR_CONFIGSAVE = 11;
-const static ULONG VDR_CONFIGLOAD = 12;
-const static ULONG VDR_RESCANRECORDING = 13; // FIXME obselete
-const static ULONG VDR_GETTIMERS = 14;
-const static ULONG VDR_SETTIMER = 15;
-const static ULONG VDR_POSFROMFRAME = 16;
-const static ULONG VDR_FRAMEFROMPOS = 17;
-const static ULONG VDR_MOVERECORDING = 18;
-const static ULONG VDR_GETNEXTIFRAME = 19;
-const static ULONG VDR_GETRECINFO = 20;
-const static ULONG VDR_GETMARKS = 21;
-const static ULONG VDR_GETCHANNELPIDS = 22;
-const static ULONG VDR_DELETETIMER = 23;
-const static ULONG VDR_GETLANGUAGELIST = 33;
-const static ULONG VDR_GETLANGUAGECONTENT = 34;
-const static ULONG VDR_GETMEDIALIST = 30;
-const static ULONG VDR_OPENMEDIA = 31;
-const static ULONG VDR_GETMEDIABLOCK = 32;
-const static ULONG VDR_GETMEDIAINFO = 35;
-const static ULONG VDR_CLOSECHANNEL = 36;
-
-class VDR_Command : public SerializableList {
- public:
- VDR_Command(const ULONG cmd) {
- command=cmd;
- addParam(&command);
- }
- virtual ~VDR_Command(){}
- ULONG command;
-};
-
-class VDR_GetMediaListRequest : public VDR_Command {
- public:
- VDR_GetMediaListRequest(MediaURI *root) :VDR_Command(VDR_GETMEDIALIST) {
- addParam(root);
- }
-};
-
-class VDR_GetMediaListResponse : public VDR_Command {
- public:
- VDR_GetMediaListResponse(ULONG *flags,MediaList *m) : VDR_Command(VDR_GETMEDIALIST|VDR_RESPONSE_FLAG){
- addParam(flags);
- addParam(m);
- }
-};
-
-class VDR_OpenMediumRequest : public VDR_Command {
- public:
- VDR_OpenMediumRequest(ULONG *channel,MediaURI *u,ULONG *xsize, ULONG *ysize) :
- VDR_Command(VDR_OPENMEDIA) {
- addParam(channel);
- addParam(u);
- addParam(xsize);
- addParam(ysize);
- }
-};
-class VDR_OpenMediumResponse : public VDR_Command {
- public:
- VDR_OpenMediumResponse(ULONG *flags,ULLONG *size) :
- VDR_Command(VDR_OPENMEDIA|VDR_RESPONSE_FLAG) {
- addParam(flags);
- addParam(size);
- }
-};
-class VDR_GetMediaBlockRequest : public VDR_Command {
- public:
- VDR_GetMediaBlockRequest(ULONG * channel, ULLONG *pos, ULONG *max):
- VDR_Command(VDR_GETMEDIABLOCK) {
- addParam(channel);
- addParam(pos);
- addParam(max);
- }
-};
-
-//no response class for GetMediaBlock
-
-
-class VDR_CloseMediaChannelRequest : public VDR_Command {
- public:
- VDR_CloseMediaChannelRequest(ULONG * channel):
- VDR_Command(VDR_CLOSECHANNEL) {
- addParam(channel);
- }
-};
-
-class VDR_CloseMediaChannelResponse : public VDR_Command {
- public:
- VDR_CloseMediaChannelResponse(ULONG * flags):
- VDR_Command(VDR_CLOSECHANNEL|VDR_RESPONSE_FLAG) {
- addParam(flags);
- }
-};
-
-class VDR_GetMediaInfoRequest : public VDR_Command {
- public:
- VDR_GetMediaInfoRequest(ULONG * channel):
- VDR_Command(VDR_GETMEDIAINFO) {
- addParam(channel);
- }
-};
-class VDR_GetMediaInfoResponse : public VDR_Command {
- public:
- VDR_GetMediaInfoResponse(ULONG * flags,MediaInfo *info):
- VDR_Command(VDR_GETMEDIAINFO|VDR_RESPONSE_FLAG) {
- addParam(flags);
- addParam(info);
- }
-};
-
-
-
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon, Andreas Vogel\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef VDRCOMMAND_H\r
+#define VDRCOMMAND_H\r
+\r
+#include "defines.h"\r
+#include "serialize.h"\r
+#include "media.h"\r
+\r
+/**\r
+ * data holder for VDR commands\r
+ * it's only important to add serializable objects\r
+ * in the same order on both sides\r
+ */\r
+\r
+//until we really have response - commands we simply take\r
+//the request+this flag for responses\r
+//not really necessary but for checks it's better to have a command ID at least in some responses\r
+const static ULONG VDR_RESPONSE_FLAG =0x1000000;\r
+\r
+//as this header is only included by vdr.cc the constants are this way private\r
+//but can easily be used on the server side as well\r
+\r
+const static ULONG VDR_LOGIN = 1;\r
+const static ULONG VDR_GETRECORDINGLIST = 2;\r
+const static ULONG VDR_DELETERECORDING = 3;\r
+const static ULONG VDR_GETCHANNELLIST = 5;\r
+const static ULONG VDR_STREAMCHANNEL = 6;\r
+const static ULONG VDR_GETBLOCK = 7;\r
+const static ULONG VDR_STOPSTREAMING = 8;\r
+const static ULONG VDR_STREAMRECORDING = 9;\r
+const static ULONG VDR_GETCHANNELSCHEDULE = 10;\r
+const static ULONG VDR_CONFIGSAVE = 11;\r
+const static ULONG VDR_CONFIGLOAD = 12;\r
+const static ULONG VDR_RESCANRECORDING = 13; // FIXME obselete\r
+const static ULONG VDR_GETTIMERS = 14;\r
+const static ULONG VDR_SETTIMER = 15;\r
+const static ULONG VDR_POSFROMFRAME = 16;\r
+const static ULONG VDR_FRAMEFROMPOS = 17;\r
+const static ULONG VDR_MOVERECORDING = 18;\r
+const static ULONG VDR_GETNEXTIFRAME = 19;\r
+const static ULONG VDR_GETRECINFO = 20;\r
+const static ULONG VDR_GETMARKS = 21;\r
+const static ULONG VDR_GETCHANNELPIDS = 22;\r
+const static ULONG VDR_DELETETIMER = 23;\r
+const static ULONG VDR_GETLANGUAGELIST = 33;\r
+const static ULONG VDR_GETLANGUAGECONTENT = 34;\r
+const static ULONG VDR_SETCHARSET = 37;\r
+const static ULONG VDR_GETMEDIALIST = 30;\r
+const static ULONG VDR_OPENMEDIA = 31;\r
+const static ULONG VDR_GETMEDIABLOCK = 32;\r
+const static ULONG VDR_GETMEDIAINFO = 35;\r
+const static ULONG VDR_CLOSECHANNEL = 36;\r
+\r
+class VDR_Command : public SerializableList {\r
+ public:\r
+ VDR_Command(const ULONG cmd) {\r
+ command=cmd;\r
+ addParam(&command);\r
+ }\r
+ virtual ~VDR_Command(){}\r
+ ULONG command;\r
+};\r
+\r
+class VDR_GetMediaListRequest : public VDR_Command {\r
+ public:\r
+ VDR_GetMediaListRequest(MediaURI *root) :VDR_Command(VDR_GETMEDIALIST) {\r
+ addParam(root);\r
+ }\r
+};\r
+\r
+class VDR_GetMediaListResponse : public VDR_Command {\r
+ public:\r
+ VDR_GetMediaListResponse(ULONG *flags,MediaList *m) : VDR_Command(VDR_GETMEDIALIST|VDR_RESPONSE_FLAG){\r
+ addParam(flags);\r
+ addParam(m);\r
+ }\r
+};\r
+\r
+class VDR_OpenMediumRequest : public VDR_Command {\r
+ public:\r
+ VDR_OpenMediumRequest(ULONG *channel,MediaURI *u,ULONG *xsize, ULONG *ysize) :\r
+ VDR_Command(VDR_OPENMEDIA) {\r
+ addParam(channel);\r
+ addParam(u);\r
+ addParam(xsize);\r
+ addParam(ysize);\r
+ }\r
+};\r
+class VDR_OpenMediumResponse : public VDR_Command {\r
+ public:\r
+ VDR_OpenMediumResponse(ULONG *flags,ULLONG *size) :\r
+ VDR_Command(VDR_OPENMEDIA|VDR_RESPONSE_FLAG) {\r
+ addParam(flags);\r
+ addParam(size);\r
+ }\r
+};\r
+class VDR_GetMediaBlockRequest : public VDR_Command {\r
+ public:\r
+ VDR_GetMediaBlockRequest(ULONG * channel, ULLONG *pos, ULONG *max):\r
+ VDR_Command(VDR_GETMEDIABLOCK) {\r
+ addParam(channel);\r
+ addParam(pos);\r
+ addParam(max);\r
+ }\r
+};\r
+\r
+//no response class for GetMediaBlock\r
+\r
+\r
+class VDR_CloseMediaChannelRequest : public VDR_Command {\r
+ public:\r
+ VDR_CloseMediaChannelRequest(ULONG * channel):\r
+ VDR_Command(VDR_CLOSECHANNEL) {\r
+ addParam(channel);\r
+ }\r
+};\r
+\r
+class VDR_CloseMediaChannelResponse : public VDR_Command {\r
+ public:\r
+ VDR_CloseMediaChannelResponse(ULONG * flags):\r
+ VDR_Command(VDR_CLOSECHANNEL|VDR_RESPONSE_FLAG) {\r
+ addParam(flags);\r
+ }\r
+};\r
+\r
+class VDR_GetMediaInfoRequest : public VDR_Command {\r
+ public:\r
+ VDR_GetMediaInfoRequest(ULONG * channel):\r
+ VDR_Command(VDR_GETMEDIAINFO) {\r
+ addParam(channel);\r
+ }\r
+};\r
+class VDR_GetMediaInfoResponse : public VDR_Command {\r
+ public:\r
+ VDR_GetMediaInfoResponse(ULONG * flags,MediaInfo *info):\r
+ VDR_Command(VDR_GETMEDIAINFO|VDR_RESPONSE_FLAG) {\r
+ addParam(flags);\r
+ addParam(info);\r
+ }\r
+};\r
+\r
+\r
+\r
+\r
+#endif\r
serialNumber = serialNumberCounter++;
opcode = topcode;
- *(ULONG*)&buffer[0] = htonl(channel);
- *(ULONG*)&buffer[4] = htonl(serialNumber);
+ int pos=0;
+ buffer[pos++]=(channel>>24)&0xff;
+ buffer[pos++]=(channel>>16)&0xff;
+ buffer[pos++]=(channel>>8)&0xff;
+ buffer[pos++]=channel &0xff;
+ buffer[pos++]=(serialNumber>>24)&0xff;
+ buffer[pos++]=(serialNumber>>16)&0xff;
+ buffer[pos++]=(serialNumber>>8)&0xff;
+ buffer[pos++]=serialNumber &0xff;
+ buffer[pos++]=(opcode>>24)&0xff;
+ buffer[pos++]=(opcode>>16)&0xff;
+ buffer[pos++]=(opcode>>8)&0xff;
+ buffer[pos++]=opcode &0xff;
+ buffer[pos++]=(userDataLength>>24)&0xff;
+ buffer[pos++]=(userDataLength>>16)&0xff;
+ buffer[pos++]=(userDataLength>>8)&0xff;
+ buffer[pos++]=userDataLength &0xff;
+
+ /**(ULONG*)&buffer[4] = htonl(serialNumber);
*(ULONG*)&buffer[8] = htonl(opcode);
- *(ULONG*)&buffer[userDataLenPos] = htonl(userDataLength);
+ *(ULONG*)&buffer[userDataLenPos] = htonl(userDataLength);*/
bufUsed = headerLength;
return true;
if (!checkExtend(len)) return false;
memcpy(buffer + bufUsed, src, len);
bufUsed += len;
- if (!lengthSet) *(ULONG*)&buffer[userDataLenPos] = htonl(bufUsed - headerLength);
+ if (!lengthSet) {
+ int pos=userDataLenPos;
+ ULONG tocopy=bufUsed - headerLength;
+ buffer[pos++]=(tocopy>>24)&0xff;
+ buffer[pos++]=(tocopy>>16)&0xff;
+ buffer[pos++]=(tocopy>>8)&0xff;
+ buffer[pos++]=tocopy &0xff;
+ }
return true;
}
+
+
bool VDR_RequestPacket::addString(const char* string)
{
ULONG len = strlen(string) + 1;
if (!checkExtend(len)) return false;
memcpy(buffer + bufUsed, string, len);
bufUsed += len;
- if (!lengthSet) *(ULONG*)&buffer[userDataLenPos] = htonl(bufUsed - headerLength);
+ if (!lengthSet) {
+ int pos=userDataLenPos;
+ ULONG tocopy=bufUsed - headerLength;
+ buffer[pos++]=(tocopy>>24)&0xff;
+ buffer[pos++]=(tocopy>>16)&0xff;
+ buffer[pos++]=(tocopy>>8)&0xff;
+ buffer[pos++]=tocopy &0xff;
+ }
return true;
}
bool VDR_RequestPacket::addULONG(ULONG ul)
{
if (!checkExtend(sizeof(ULONG))) return false;
- *(ULONG*)&buffer[bufUsed] = htonl(ul);
- bufUsed += sizeof(ULONG);
- if (!lengthSet) *(ULONG*)&buffer[userDataLenPos] = htonl(bufUsed - headerLength);
+// *(ULONG*)&buffer[bufUsed] = htonl(ul);
+
+ buffer[bufUsed++]=(ul>>24)&0xff;
+ buffer[bufUsed++]=(ul>>16)&0xff;
+ buffer[bufUsed++]=(ul>>8)&0xff;
+ buffer[bufUsed++]=ul &0xff;
+
+ if (!lengthSet) {
+ int pos=userDataLenPos;
+ ULONG tocopy=bufUsed - headerLength;
+ buffer[pos++]=(tocopy>>24)&0xff;
+ buffer[pos++]=(tocopy>>16)&0xff;
+ buffer[pos++]=(tocopy>>8)&0xff;
+ buffer[pos++]=tocopy &0xff;
+ }
return true;
}
bool VDR_RequestPacket::addULLONG(ULLONG ull)
{
if (!checkExtend(sizeof(ULLONG))) return false;
- *(ULLONG*)&buffer[bufUsed] = htonll(ull);
- bufUsed += sizeof(ULLONG);
- if (!lengthSet) *(ULONG*)&buffer[userDataLenPos] = htonl(bufUsed - headerLength);
+ buffer[bufUsed++]=(ull>>56)&0xff;
+ buffer[bufUsed++]=(ull>>48)&0xff;
+ buffer[bufUsed++]=(ull>>40)&0xff;
+ buffer[bufUsed++]=(ull>>32)&0xff;
+ buffer[bufUsed++]=(ull>>24)&0xff;
+ buffer[bufUsed++]=(ull>>16)&0xff;
+ buffer[bufUsed++]=(ull>>8)&0xff;
+ buffer[bufUsed++]=ull &0xff;
+
+ if (!lengthSet) {
+ int pos=userDataLenPos;
+ ULONG tocopy=bufUsed - headerLength;
+ buffer[pos++]=(tocopy>>24)&0xff;
+ buffer[pos++]=(tocopy>>16)&0xff;
+ buffer[pos++]=(tocopy>>8)&0xff;
+ buffer[pos++]=tocopy &0xff;
+ }
return true;
}
-/*
- Copyright 2007 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vdrresponsepacket.h"
-
-#include "vdr.h"
-#include "tcp.h"
-
-VDR_ResponsePacket::VDR_ResponsePacket()
-{
- userDataLength = 0;
- packetPos = 0;
- userData = NULL;
- ownBlock = true;
-
- channelID = 0;
-
- requestID = 0;
- streamID = 0;
-
- flag = 0;
-}
-
-VDR_ResponsePacket::~VDR_ResponsePacket()
-{
- if (!ownBlock) return; // don't free if it's a getblock
-
- if (userData) free(userData);
-}
-
-void VDR_ResponsePacket::setResponse(ULONG trequestID, UCHAR* tuserData, ULONG tuserDataLength)
-{
- channelID = VDR::CHANNEL_REQUEST_RESPONSE;
- requestID = trequestID;
- userData = tuserData;
- userDataLength = tuserDataLength;
-}
-
-void VDR_ResponsePacket::setStream(ULONG tstreamID, ULONG tflag, UCHAR* tuserData, ULONG tuserDataLength)
-{
- channelID = VDR::CHANNEL_STREAM;
- streamID = tstreamID;
- flag = tflag;
- userData = tuserData;
- userDataLength = tuserDataLength;
-}
-
-bool VDR_ResponsePacket::end()
-{
- return (packetPos >= userDataLength);
-}
-
-void VDR_ResponsePacket::dumpUD()
-{
- TCP::dump(userData, userDataLength);
-}
-
-int VDR_ResponsePacket::serverError()
-{
- if ((packetPos == 0) && (userDataLength == 4) && !ntohl(*(ULONG*)userData)) return 1;
- else return 0;
-}
-
-char* VDR_ResponsePacket::extractString()
-{
- if (serverError()) return NULL;
-
- int length = strlen((char*)&userData[packetPos]);
- if ((packetPos + length) > userDataLength) return NULL;
- char* str = new char[length + 1];
- strcpy(str, (char*)&userData[packetPos]);
- packetPos += length + 1;
- return str;
-}
-
-UCHAR VDR_ResponsePacket::extractUCHAR()
-{
- if ((packetPos + sizeof(UCHAR)) > userDataLength) return 0;
- UCHAR uc = userData[packetPos];
- packetPos += sizeof(UCHAR);
- return uc;
-}
-
-ULONG VDR_ResponsePacket::extractULONG()
-{
- if ((packetPos + sizeof(ULONG)) > userDataLength) return 0;
- ULONG ul = ntohl(*(ULONG*)&userData[packetPos]);
- packetPos += sizeof(ULONG);
- return ul;
-}
-
-ULLONG VDR_ResponsePacket::extractULLONG()
-{
- if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0;
- ULLONG ull = ntohll(*(ULLONG*)&userData[packetPos]);
- packetPos += sizeof(ULLONG);
- return ull;
-}
-
-double VDR_ResponsePacket::extractdouble()
-{
- if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0;
- ULLONG ull = ntohll(*(ULLONG*)&userData[packetPos]);
- double d;
- memcpy(&d,&ull,sizeof(double));
- packetPos += sizeof(ULLONG);
- return d;
-}
-
-long VDR_ResponsePacket::extractLONG()
-{
- if ((packetPos + sizeof(long)) > userDataLength) return 0;
- long l = ntohl(*(long*)&userData[packetPos]);
- packetPos += sizeof(long);
- return l;
-}
-
-UCHAR* VDR_ResponsePacket::getUserData()
-{
- ownBlock = false;
- return userData;
-}
-
+/*\r
+ Copyright 2007 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vdrresponsepacket.h"\r
+\r
+#include "vdr.h"\r
+#include "tcp.h"\r
+\r
+VDR_ResponsePacket::VDR_ResponsePacket()\r
+{\r
+ userDataLength = 0;\r
+ packetPos = 0;\r
+ userData = NULL;\r
+ ownBlock = true;\r
+ \r
+ channelID = 0;\r
+ \r
+ requestID = 0;\r
+ streamID = 0;\r
+ \r
+ flag = 0;\r
+}\r
+\r
+VDR_ResponsePacket::~VDR_ResponsePacket()\r
+{\r
+ if (!ownBlock) return; // don't free if it's a getblock\r
+ \r
+ if (userData) free(userData);\r
+}\r
+\r
+void VDR_ResponsePacket::setResponse(ULONG trequestID, UCHAR* tuserData, ULONG tuserDataLength)\r
+{\r
+ channelID = VDR::CHANNEL_REQUEST_RESPONSE;\r
+ requestID = trequestID;\r
+ userData = tuserData;\r
+ userDataLength = tuserDataLength;\r
+}\r
+\r
+void VDR_ResponsePacket::setStream(ULONG tstreamID, ULONG tflag, UCHAR* tuserData, ULONG tuserDataLength)\r
+{\r
+ channelID = VDR::CHANNEL_STREAM;\r
+ streamID = tstreamID;\r
+ flag = tflag;\r
+ userData = tuserData;\r
+ userDataLength = tuserDataLength;\r
+}\r
+\r
+bool VDR_ResponsePacket::end()\r
+{\r
+ return (packetPos >= userDataLength);\r
+}\r
+\r
+void VDR_ResponsePacket::dumpUD()\r
+{\r
+ TCP::dump(userData, userDataLength);\r
+}\r
+\r
+int VDR_ResponsePacket::serverError()\r
+{\r
+ if ((packetPos == 0) && (userDataLength == 4) && !ntohl(*(ULONG*)userData)) return 1;\r
+ else return 0;\r
+}\r
+\r
+char* VDR_ResponsePacket::extractString()\r
+{\r
+ if (serverError()) return NULL;\r
+\r
+ int length = strlen((char*)&userData[packetPos]);\r
+ if ((packetPos + length) > userDataLength) return NULL;\r
+ char* str = new char[length + 1];\r
+ strcpy(str, (char*)&userData[packetPos]);\r
+ packetPos += length + 1;\r
+ return str;\r
+}\r
+\r
+UCHAR VDR_ResponsePacket::extractUCHAR()\r
+{\r
+ if ((packetPos + sizeof(UCHAR)) > userDataLength) return 0;\r
+ UCHAR uc = userData[packetPos];\r
+ packetPos += sizeof(UCHAR);\r
+ return uc;\r
+}\r
+\r
+ULONG VDR_ResponsePacket::extractULONG()\r
+{\r
+ if ((packetPos + sizeof(ULONG)) > userDataLength) return 0;\r
+ ULONG ul = userData[packetPos++]<<24;\r
+ ul|= userData[packetPos++]<<16;\r
+ ul|= userData[packetPos++]<<8;\r
+ ul|= userData[packetPos++];\r
+ //packetPos += sizeof(ULONG);\r
+ return ul;\r
+}\r
+\r
+ULLONG VDR_ResponsePacket::extractULLONG()\r
+{\r
+ if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0;\r
+ ULLONG ull= ((ULLONG)userData[packetPos++])<<56;\r
+ ull|= ((ULLONG)userData[packetPos++])<<48;\r
+ ull|= ((ULLONG)userData[packetPos++])<<40;\r
+ ull|= ((ULLONG)userData[packetPos++])<<32;\r
+ ull|= ((ULLONG)userData[packetPos++])<<24;\r
+ ull|= ((ULLONG)userData[packetPos++])<<16;\r
+ ull|= ((ULLONG)userData[packetPos++])<<8;\r
+ ull|= ((ULLONG)userData[packetPos++]);\r
+ return ull;\r
+}\r
+\r
+double VDR_ResponsePacket::extractdouble()\r
+{\r
+ if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0;\r
+ ULLONG ull = extractULLONG();\r
+ double d;\r
+ memcpy(&d,&ull,sizeof(double));\r
+ return d;\r
+}\r
+\r
+long VDR_ResponsePacket::extractLONG()\r
+{\r
+ if ((packetPos + sizeof(long)) > userDataLength) return 0;\r
+ long l = userData[packetPos++]<<24;\r
+ l|= userData[packetPos++]<<16;\r
+ l|= userData[packetPos++]<<8;\r
+ l|= userData[packetPos++];\r
+ return l;\r
+}\r
+\r
+UCHAR* VDR_ResponsePacket::getUserData()\r
+{\r
+ ownBlock = false;\r
+ return userData;\r
+}\r
+\r
-/*
- Copyright 2005 Brian Walton
-
- 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.
-*/
-/*
- vepg presents a 2 dimensional electronic programme guide with channels down
- the y axis and time along the x axis.
- Programmes are layed on the x axis as alterate coloured blocks with as much
- of the programme title as will fit inside the block shown as text.
- Up and down commands step through the channels whilst left and right commands
- move through the programmes of the currently selected channel.
- When a programme is selected, it highlights in the grid and full programe details
- (start time, title and description) are displayed in an area at te top left of the screen.
- Any currently programmed timers will display in the grid and in the orogramme detail window as red
- It is possible to select a programme to be recorded by pressing the record button.
- The video stream currently being viewed is shown as quarter screen in the top right.
-*/
-
-#include "vepg.h"
-
-#include "remote.h"
-#include "vchannellist.h"
-#include "command.h"
-#include "video.h"
-#include "vepgsettimer.h"
-#include "timers.h"
-#include "wsymbol.h"
-#include "message.h"
-#include "colour.h"
-#include "boxstack.h"
-#include "channel.h"
-#include "i18n.h"
-#include "log.h"
-
-VEpg* VEpg::instance = NULL;
-
-VEpg::VEpg(void* tparent, UINT tcurrentChannelIndex, ULONG streamType)
-{
- instance = this;
- currentChannelIndex = tcurrentChannelIndex;
-
- // PAL / NTSC sizes -----------------------
-
- int xsize, ysize;
- int xpos, ypos;
- int summaryLines, summaryLowerPadding;
- int chanNameYpos;
- //UINT gridRows; // is a class member
-
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- xsize = 632;
- ysize = 541;
- xpos = 60;
- ypos = 16;
- summaryLines = 8;
- summaryLowerPadding = 18;
- chanNameYpos = 244;
- gridRows = 7;
- }
- else
- {
- xsize = 632;
- ysize = 452;
- xpos = 50;
- ypos = 10;
- summaryLines = 6;
- summaryLowerPadding = 28;
- chanNameYpos = 206;
- gridRows = 5;
- }
-
- // initialise variables and pointers
- boxstack = BoxStack::getInstance();
- parent = tparent;
- eventList = NULL;
- chanList = VDR::getInstance()->getChannelsList(streamType); //TODO want to be able to display video and radio together
- e = 0;
-
- for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
- {
- // initialise array of pointers to eventlist structures
- eventLista[listIndex] = NULL;
- }
-
- // Create pallet on which to paint our epg view and position it in centre of screen.
- // Need to reduce size to deal with overscanning TVs.
-
- setSize(xsize, ysize);
- createBuffer();
- setPosition(xpos, ypos);
-
- // beautify
-// Colour transparent = Colour(0, 0, 0, 0);
-// setBackgroundColour(transparent);
-
-// progTitle.setSurface(surface);
- progTitle.setPosition(0,0);
- progTitle.setSize(300,(Surface::getFontHeight() + 4) * 2 + 16); //paragraph line seperation is 4 pixels
- progTitle.setBackgroundColour(Colour::TITLEBARBACKGROUND);
- progTitle.setTextPos(5, 16);
- progTitle.setGap(4);
- add(&progTitle);
-
-// progInfo.setSurface(surface);
- progInfo.setBackgroundColour(Colour::VIEWBACKGROUND);
- progInfo.setPosition(0, progTitle.getY2());
- progInfo.setSize(300,((Surface::getFontHeight() + 4) * summaryLines) + summaryLowerPadding);
- progInfo.setGap(4);
- add(&progInfo);
-
-// chanName.setSurface(surface);
- chanName.setSize(510, (Surface::getFontHeight() + 4));
- chanName.setPosition(305, chanNameYpos);
- Colour t1(0, 0, 0, 90);
- chanName.setBackgroundColour(t1);
- add(&chanName);
-
- // create area to display list of channels
-// chanListbox.setSurface(surface); // add channel list
- chanListbox.setPosition(0, progInfo.getY2() + Surface::getFontHeight() + 8); // position channel list
- chanListbox.setSize(150, ((Surface::getFontHeight() + 2) * gridRows) + 5); //listbox line seperation is 2 pixels
- chanListbox.setGap(2);
- add(&chanListbox);
-
- // populate channel list
- if (chanList)
- {
- Channel* chan;
- int first = 1;
- for (UINT i = 0; i < chanList->size(); i++)
- {
- chan = (*chanList)[i];
- if (i == currentChannelIndex)
- first = 1;
- chan->index = chanListbox.addOption(chan->name, 0, first);
- first = 0;
- }
- chanName.setText((*chanList)[chanListbox.getCurrentOption()]->name);
- }
-
- listTop = chanListbox.getTopOption();
- chanListbox.draw(); // doing this to allow chanListbox.getBottomOption() in updateEventList() to work
- time(<ime); // set ltime to now
- ltime = prevHour(<ime); // set ltime to previous hour TODO make this half hour?
- time(&selTime); // set selTime to now
- updateEventList(); // get list of programmes
-}
-
-void VEpg::preDelete()
-{
- Timers::getInstance()->cancelTimer(this, 1);
-}
-
-VEpg::~VEpg()
-{
-
- instance = NULL;
-
- for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
- {
- if (eventLista[listIndex])
- {
- (eventLista)[listIndex]->clear();
- delete eventLista[listIndex];
- }
- }
- // delete [] eventLista; // FIXME
-
- // destroy dynamically allocated memory
-}
-
-VEpg* VEpg::getInstance()
-{
- return instance;
-}
-
-void VEpg::setInfo(Event* event)
-{
- time_t t;
- struct tm* btime; // to hold programme start and end time
- char timeString[9]; // to hold programme start and end time
- int length = strlen(event->title); // calculate length of programme title string
- char* title = new char[length + 15]; // create string to hold start time, end time and programme title
- btime = localtime((time_t*)&event->time); //get programme start time
-#ifndef _MSC_VER
- strftime(timeString, 9, "%0H:%0M - ", btime); // and format it as hh:mm -
-#else
- strftime(timeString, 9, "%H:%M - ", btime); // and format it as hh:mm -
-#endif
- strcpy(title, timeString); // put it in our buffer
- t = event->time + event->duration; //get programme end time
- btime = localtime(&t);
-#ifndef _MSC_VER
- strftime(timeString, 7, "%0H:%0M ", btime); // and format it as hh:mm -
-#else
- strftime(timeString, 7, "%H:%M ", btime); // and format it as hh:mm -
-#endif
- strcat(title, timeString); // put it in our buffer
- strcat(title, event->title); // then add the programme title
- progTitle.setText(title); // sput this sring in our text box
- length = strlen(event->description);
- char* info = new char[length + 1]; // create programme detail string
- strcpy(info, event->description);
- progInfo.setText(info); // show programme detail string
-// destroy dynamically allocated memory
- delete[] info;
- delete[] title;
-}
-
-void VEpg::draw()
-{
-// View::draw(); // draw pallet
- // beautify
- Colour transparent = Colour(0, 0, 0, 0);
- fillColour(transparent);
-
-
- // Moved all the dynamic data drawing to a seperate function
-
- // Display the status and key stuff at the bottom
-
- UINT keyx = chanListbox.getRootBoxOffsetX();
- UINT keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;
- Colour ref1 = Colour(100, 100, 100, 255);
- rectangle(keyx, keyy, 605, Surface::getFontHeight() * 2 + 14, ref1);
-
- WSymbol w;
- TEMPADD(&w);
-
- w.nextSymbol = WSymbol::LEFTARROW;
- w.setPosition(keyx + 1, keyy + 20);
- w.draw();
-
- w.nextSymbol = WSymbol::UP;
- w.setPosition(keyx + 26, keyy + 3);
- w.draw();
-
- w.nextSymbol = WSymbol::DOWN;
- w.setPosition(keyx + 26, keyy + 36);
- w.draw();
-
- w.nextSymbol = WSymbol::RIGHTARROW;
- w.setPosition(keyx + 50, keyy + 20);
- w.draw();
-
- drawText(tr("OK"), keyx + 18, keyy + 20, Colour::LIGHTTEXT);
-
- Colour ref2 = Colour(200, 0, 0, 255);
- rectangle(keyx + 72, keyy + 4, 104, Surface::getFontHeight() + 2, ref2);
- drawText(tr("Page up"), keyx + 74, keyy + 5, Colour::LIGHTTEXT);
-
- Colour ref3 = Colour(0, 200, 0, 255);
- rectangle(keyx + 72, keyy + Surface::getFontHeight() + 8, 104, Surface::getFontHeight() + 2, ref3);
- drawText(tr("Page down"), keyx + 74, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);
-
- Colour ref4 = Colour(200, 200, 0, 255);
- rectangle(keyx + 180, keyy + 4, 104, Surface::getFontHeight() + 2, ref4);
- drawText(tr("-24 hours"), keyx + 182, keyy + 5, Colour::LIGHTTEXT);
-
- Colour ref5 = Colour(0, 0, 200, 255);
- rectangle(keyx + 180, keyy + Surface::getFontHeight() + 8, 104, Surface::getFontHeight() + 2, ref5);
- drawText(tr("+24 hours"), keyx + 182, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);
-
- Colour ref6 = Colour(180, 180, 180, 255);
- rectangle(keyx + 290, keyy + 4, 180, Surface::getFontHeight() + 2, ref6);
- drawText(tr("Guide / Back: Close"), keyx + 292 , keyy + 5, Colour::LIGHTTEXT);
-
- Colour ref7 = Colour(180, 180, 180, 255);
- rectangle(keyx + 290, keyy + Surface::getFontHeight() + 8, 180, Surface::getFontHeight() + 2, ref7);
- Colour red = Colour(130, 0, 0);
- drawText(tr("Rec: Set timer"), keyx + 292, keyy + Surface::getFontHeight() + 9, red);
-
- Colour ref8 = Colour(180, 180, 180, 255);
- rectangle(keyx + 474, keyy + 4, 128, Surface::getFontHeight() + 2, ref8);
- w.nextSymbol = WSymbol::PLAY;
- w.setPosition(keyx + 476, keyy + 5);
- w.draw();
- drawText(tr("Sel channel"), keyx + 496, keyy + 5, Colour::LIGHTTEXT);
-
- Colour ref9 = Colour(180, 180, 180, 255);
- rectangle(keyx + 474, keyy + Surface::getFontHeight() + 8, 128, Surface::getFontHeight() + 2, ref9);
- drawText(tr("Go: Preview"), keyx + 476, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);
-
-
- // Draw all the dynamic data
- drawData();
-}
-
-void VEpg::drawData()
-{
- // Not doing View::draw() every time causes
- // things not to be cleared off the surface properly
- // So, blank out the data area first
-
- rectangle(
- chanListbox.getRootBoxOffsetX(),
- chanListbox.getRootBoxOffsetY() - Surface::getFontHeight() - 3,
- 155 + WINDOW_WIDTH * MINUTE_SCALE,
- chanListbox.getHeight() + Surface::getFontHeight() + 4,
- Colour::BLACK);
-
- chanListbox.draw();
- drawgrid();
- chanName.draw(); // TODO this should be dealt with by vvideolive
-
- progTitle.draw();
- progInfo.draw();
-
- // Set timer to redraw to move the current time bar
- time_t t, dt;
- time(&t);
- dt = 60 - (t % 60);
- if (dt == 0) dt = 60;
- dt += t;
- Timers::getInstance()->setTimerT(this, 1, dt);
-}
-
-void VEpg::timercall(int clientReference)
-{
- drawData();
- boxstack->update(this);
-}
-
-int VEpg::handleCommand(int command)
-{
- switch(command)
- {
- case Remote::DF_UP:
- case Remote::UP:
- { // cursor up the channel list
- chanListbox.up();
- drawData();
- boxstack->update(this);
- return 2;
- }
- case Remote::DF_DOWN:
- case Remote::DOWN:
- { // cursor down the channel list
- Log::getInstance()->log("VEPG", Log::DEBUG, "Down start");
-
- chanListbox.down();
- drawData();
- boxstack->update(this);
- Log::getInstance()->log("VEPG", Log::DEBUG, "Down end");
-
- return 2;
- }
- case Remote::DF_LEFT:
- case Remote::LEFT:
- { // cursor left through time
- selTime = thisEvent.time - 1;
- drawData();
- boxstack->update(this);
- return 2;
- }
- case Remote::DF_RIGHT:
- case Remote::RIGHT:
- {
- // cursor right through time
- selTime = thisEvent.time + thisEvent.duration;
- drawData();
- boxstack->update(this);
- return 2;
- }
- case Remote::RED:
- {
- // cursor up one page
- chanListbox.pageUp();
- drawData();
- boxstack->update(this);
- return 2;
- }
- case Remote::GREEN:
- {
- // cursor down one page
- chanListbox.pageDown();
- drawData();
- boxstack->update(this);
- return 2;
- }
- case Remote::BLUE:
- {
- // step forward 24 hours
- selTime += 24 * 60 * 60;
- drawData();
- boxstack->update(this);
- return 2;
- }
- case Remote::YELLOW:
- {
- // step forward 24 hours
- selTime -= 24 * 60 * 60;
- drawData();
- boxstack->update(this);
- return 2;
- }
- case Remote::RECORD:
- {
- if (!chanList) return 2;
- Log::getInstance()->log("VEPG", Log::DEBUG, "ID %lu TIME %lu DURATION %lu TITLE %s", thisEvent.id, thisEvent.time, thisEvent.duration, thisEvent.title);
- VEpgSetTimer* vs = new VEpgSetTimer(&thisEvent, (*chanList)[chanListbox.getCurrentOption()]);
- vs->draw();
- boxstack->add(vs);
- boxstack->update(vs);
- return 2;
- }
- case Remote::PLAY:
- case Remote::GO:
- case Remote::OK:
- {
- if (!chanList) return 2;
-
- // select programme and display menu TODO currently just changes to selected channel
-
- currentChannelIndex = chanListbox.getCurrentOption();
-
- if (parent)
- {
- Message* m = new Message(); // Must be done after this view deleted
- m->from = this;
- m->to = parent;
- m->message = Message::CHANNEL_CHANGE;
- m->parameter = (*chanList)[currentChannelIndex]->number;
- Command::getInstance()->postMessageNoLock(m);
- }
-
- setCurrentChannel();
-
- if(command == Remote::GO)
- return 2;
- // GO just changes channel in preview, PLAY changes channel and returns to normal TV
- }
- case Remote::BACK:
- case Remote::GUIDE:
- {
- // return to normal TV mode
- if (parent) // ptr check done in case being tested from videorec
- {
- Message* m = new Message(); // Must be done after this view deleted
- m->from = this;
- m->to = parent;
- m->message = Message::EPG_CLOSE;
- Command::getInstance()->postMessageNoLock(m);
- }
- return 4;
- }
- case Remote::CHANNELUP:
- {
- if (currentChannelIndex == (chanList->size() - 1)) // at the end
- currentChannelIndex = 0;
- else
- ++currentChannelIndex;
-
- if (parent)
- {
- Message* m = new Message(); // Must be done after this view deleted
- m->from = this;
- m->to = parent;
- m->message = Message::CHANNEL_CHANGE;
- m->parameter = (*chanList)[currentChannelIndex]->number;
- Command::getInstance()->postMessageNoLock(m);
- }
-
- setCurrentChannel();
-
- return 2;
- }
- case Remote::CHANNELDOWN:
- {
- if (currentChannelIndex == 0) // at the start
- currentChannelIndex = chanList->size() - 1; // so go to end
- else
- --currentChannelIndex;
-
- if (parent)
- {
- Message* m = new Message(); // Must be done after this view deleted
- m->from = this;
- m->to = parent;
- m->message = Message::CHANNEL_CHANGE;
- m->parameter = (*chanList)[currentChannelIndex]->number;
- Command::getInstance()->postMessageNoLock(m);
- }
-
- setCurrentChannel();
-
- return 2;
- }
- }
- // stop command getting to any more views
- return 1;
-}
-
-void VEpg::drawgrid() // redraws grid and select programme
-{
- // draw the grid of programmes
- char timeString[20];
- time_t t;
- time(&t); // set t = now
- if(selTime < t)
- selTime = t; // don't allow cursor in the past
- if(listTop != chanListbox.getTopOption())
- {
- // chanListbox has scrolled TODO speed up by changing only rows that have changed
- listTop = chanListbox.getTopOption();
- updateEventList();
- }
- if ((selTime >= ltime + WINDOW_WIDTH * 60) || (selTime <= ltime))
- {
- // we have cursored back before left time of window
- //TODO check that this and above don't happen together
- ltime = prevHour(&selTime);
- updateEventList();
- }
- // draw time scale
- Colour white = Colour(255, 255, 255, 255);
-
- t = ltime;
- struct tm* tms;
- tms = localtime(&t);
- strftime(timeString, 19, "%a %d %b", tms);
- int timey = chanListbox.getRootBoxOffsetY() - Surface::getFontHeight() - 3;
- int timex = 135;
- drawTextRJ(timeString, timex - 10, timey, Colour::LIGHTTEXT); // print date
- strftime(timeString, 19, "%H:%M", tms);
- drawText(timeString, timex, timey, Colour::LIGHTTEXT); // print left time
- rectangle(155, timey + Surface::getFontHeight(), 2, 7, white);
- t = t + 3600;
- tms = localtime(&t);
- strftime(timeString, 19, "%H:%M", tms);
- drawText(timeString, timex + 180, timey, Colour::LIGHTTEXT); // print middle time
- rectangle(335, timey + Surface::getFontHeight(), 2, 7, white);
- t = t + 3600;
- tms = localtime(&t);
- strftime(timeString, 19, "%H:%M", tms);
- drawText(timeString, timex + 360, timey, Colour::LIGHTTEXT); // print right time
- rectangle(515, timey + Surface::getFontHeight(), 2, 7, white);
- // pointer to selTime
- //rectangle(155 + (selTime - ltime) / 20, timey + Surface::getFontHeight(), 2, 7, Colour(255, 50, 50, 255));
-
- // current time line
- time(&t);
- if ((t >= ltime) && (t < (ltime + 9000)))
- {
- rectangle(155 + (t - ltime) / 20, timey + Surface::getFontHeight(), 2, ((Surface::getFontHeight() + 2) * 7) + 7 + 2, Colour::RED);
- }
-
- // TODO should the above two comditional statements be combined to avoid calling updateEventList() twice?
- Event* event;
- Event noevent; // an event to use if there are gaps in the epg
- thisEvent.setdescription(tr("There are no programme details available for this period"));
- thisEvent.duration = WINDOW_WIDTH * 60;
- thisEvent.time = ltime;
- thisEvent.settitle(tr("No programme details"));
- thisEvent.id = 0;
- bool swapColour = FALSE; // alternate cell colour
- bool currentRow = FALSE;
- int y = chanListbox.getRootBoxOffsetY() + 5; // vertical position of cell
- Colour bg, fg; // background colour of cells in grid
- // for each displayed channel, find programmes that fall in 2.5 hour time window
- for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
- {
- if (listTop + (int)listIndex >= chanListbox.getBottomOption())
- continue; // ensure nothing populates grid below last channel
- currentRow = (listTop + (int)listIndex == chanListbox.getCurrentOption());
- noevent.time = ltime;
- noevent.duration = WINDOW_WIDTH * 60;
- noevent.settitle("");
- paintCell(&noevent, y, Colour::NOPROGRAMME, Colour::LIGHTTEXT); // fill row with no programme colour to be painted ove with valid programmes
- if (currentRow)
- {
- thisEvent.setdescription(tr("There are no programme details available for this period"));
- thisEvent.duration = WINDOW_WIDTH * 60;
- thisEvent.time = ltime;
- thisEvent.settitle(tr("No programme details"));
- thisEvent.id = 0;
- }
- if (eventLista[listIndex])
- {
- sort(eventLista[listIndex]->begin(), eventLista[listIndex]->end(), EventSorter());
- for(e = 0; e < (eventLista[listIndex])->size(); e++) // step through events for this channel
- {
- fg = Colour::LIGHTTEXT;
- event = (*eventLista[listIndex])[e];
- if (event)
- {
- UINT end = event->time + event->duration; // programme end time
- if(event->time >= UINT(ltime) + (WINDOW_WIDTH * 60)) // programme starts after RHS of window
- continue; // that's enough of this channel's events
- if(end <= UINT(ltime)) // programme ends before LHS of window
- continue; // this event is before the window - let's try the next event
- // this event is one we are interested in
- bg = (swapColour)?Colour::PROGRAMMEA:Colour::PROGRAMMEB; // alternate cell colour
- swapColour = !swapColour; // it wil be the other colour next time
- if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow)
- {
- // this is the selected programme
- thisEvent.setdescription(event->description);
- thisEvent.duration = event->duration;
- thisEvent.time = event->time;
- thisEvent.settitle(event->title);
- thisEvent.id = event->id;
- if(thisEvent.id == 0)
- thisEvent.id = 1;
- bg = Colour::SELECTHIGHLIGHT; // highlight cell
- fg = Colour::DARKTEXT;
- }
- else
- {
- if (currentRow && thisEvent.id == 0)
- {
- if (end <= UINT(selTime) && end > UINT(thisEvent.time))
- thisEvent.time = end;
- if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration)
- thisEvent.duration = event->time - thisEvent.time;
- }
- }
- paintCell(event, y, bg, fg);
- }
- }
- }
- else
- {
- // no event list for this channel. Already painted noevent colour so just highlight if selected
- if (currentRow)
- {
- bg = Colour::SELECTHIGHLIGHT; // highlight cell
- fg = Colour::DARKTEXT;
- paintCell(&thisEvent, y, bg, fg);
- }
- else
- {
- bg = Colour::NOPROGRAMME;
- fg = Colour::LIGHTTEXT;
- noevent.settitle(tr("No programme details"));
- paintCell(&noevent, y, bg, fg);
- }
- }
- y += Surface::getFontHeight() + 2;
- }
- setInfo(&thisEvent);
-}
-
-void VEpg::updateEventList()
-{
- 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 VEpg::setCurrentChannel()
-{
- chanName.setText((*chanList)[currentChannelIndex]->name);
- chanName.draw();
- Region r;
- chanName.getRootBoxRegion(&r);
- boxstack->update(this, &r);
-}
-
-void VEpg::paintCell(Event* event, int yOffset, const Colour& bg, const Colour& fg)
-{
- int w, x, y, h;
- w = x = 0; // keep compiler happy
-
- y =yOffset;
- h = Surface::getFontHeight(); // TODO if want border around text, need to increae this and wselectlist line height
- UINT end = event->time + event->duration; // programme end time
- if(event->time <= UINT(ltime) && end > UINT(ltime)) // spans start of displayed window
- {
- x = 155; // LHS of window
- if (end > (UINT(ltime) + (WINDOW_WIDTH * 60)))
- w = WINDOW_WIDTH * MINUTE_SCALE; // spans full 2 hour window
- else
- w = MINUTE_SCALE * (event->time + event->duration - ltime ) / 60; // get width of remaining programme
- }
- if((event->time >= UINT(ltime)) && (event->time <= UINT(ltime) + (WINDOW_WIDTH * 60))) // starts within window
- {
- x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);
- w = MINUTE_SCALE * event->duration / 60;
- //if (w > 155 + MINUTE_SCALE * WINDOW_WIDTH -x)
- // w = w + x - 155 - MINUTE_SCALE * WINDOW_WIDTH; // ends outside window
- }
- if (w > 155 + WINDOW_WIDTH * MINUTE_SCALE - x)
- w = 155 + WINDOW_WIDTH * MINUTE_SCALE -x; // limit cells to RHS of window
- rectangle(x, y, w, h, bg);
- char* tt = new char[strlen(event->title) + 1];
- strcpy (tt, event->title);
- int textWidth = 0;
- for (UINT textPos = 0; textPos < strlen(tt); textPos++)
- {
- int thisCharWidth = surface->getCharWidth(tt[textPos]);
- if (textWidth + thisCharWidth > w) // text will not fit in cell
- {
- textWidth = textPos;
- break;
- }
- textWidth += thisCharWidth;
- }
- char* tT = new char[textWidth];
- if(textWidth > 1)
- {
- strncpy(tT, tt, textWidth - 1);
- tT[textWidth - 1] = '\0';
- surface->drawText(tT, x+2, y, fg.rgba());
- }
- delete tT;
-
-}
-
-time_t VEpg::prevHour(time_t* t)
-{
- struct tm* tms;
- tms = localtime(t);
- tms->tm_sec = 0;
- tms->tm_min = 0;
- return mktime(tms);
-}
-
-void VEpg::processMessage(Message* m)
-{
- if (m->message == Message::MOUSE_MOVE)
- {
- if (chanListbox.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- drawData();
- boxstack->update(this);
- }
- }
- else if (m->message == Message::MOUSE_LBDOWN)
- {
- if (chanListbox.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();
- int keyx = chanListbox.getRootBoxOffsetX();
- int keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;
-
- if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
- {
- boxstack->handleCommand(Remote::BACK); //simulate cancel press
- }
- else if (x>=(keyx+72) && y>=(keyy+4) &&x<=(keyx+72+104) &&y<=(keyy+4+Surface::getFontHeight() + 2))
- {
- boxstack->handleCommand(Remote::RED);
- }
- else if (x>=(keyx+72) && y>=(keyy+ Surface::getFontHeight() + 8) &&x<=(keyx+72+104) &&y<=(keyy+8+2*Surface::getFontHeight() + 2))
- {
- boxstack->handleCommand(Remote::GREEN);
- }
- else if (x>=(keyx+180) && y>=(keyy+4) &&x<=(keyx+180+104) &&y<=(keyy+4+Surface::getFontHeight() + 2))
- {
- boxstack->handleCommand(Remote::YELLOW);
- }
- else if (x>=(keyx+180) && y>=(keyy+ Surface::getFontHeight() + 8) &&x<=(keyx+180+104) &&y<=(keyy+8+2*Surface::getFontHeight() + 2))
- {
- boxstack->handleCommand(Remote::BLUE);
- }
- else if (x>=(keyx+290) && y>=(keyy+4) &&x<=(keyx+180+290) &&y<=(keyy+4+Surface::getFontHeight() + 2))
- {
- boxstack->handleCommand(Remote::BACK);
- }
- else if (x>=(keyx+290) && y>=(keyy+ Surface::getFontHeight() + 8) &&x<=(keyx+290+180) &&y<=(keyy+8+2*Surface::getFontHeight() + 2))
- {
- boxstack->handleCommand(Remote::RECORD);
- }
- else if (x>=(keyx+474) && y>=(keyy+4) &&x<=(keyx+128+474) &&y<=(keyy+4+Surface::getFontHeight() + 2))
- {
- boxstack->handleCommand(Remote::PLAY);
- }
- else if (x>=(keyx+474) && y>=(keyy+ Surface::getFontHeight() + 8) &&x<=(keyx+238+474) &&y<=(keyy+8+2*Surface::getFontHeight() + 2))
- {
- boxstack->handleCommand(Remote::GO);
- }
- else if ( x>=(chanListbox.getRootBoxOffsetX())
- && y>=(chanListbox.getRootBoxOffsetY() + 5)
- // &&x<=(chanListbox.getOffsetX()+155 + WINDOW_WIDTH * MINUTE_SCALE)
- &&y<=(chanListbox.getRootBoxOffsetY() - Surface::getFontHeight()
- - 3+(int)chanListbox.getHeight() + Surface::getFontHeight() + 3)
- )
- {
- int cy=y-(chanListbox.getRootBoxOffsetY() + 5);
- int row=cy/(Surface::getFontHeight()+2);
- int clistTop = chanListbox.getTopOption();
- chanListbox.hintSetCurrent(clistTop+row);
- int cx=x-155;
- time_t ttime = cx*60/MINUTE_SCALE+ltime;
- //x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);
-
- selTime = ttime;
- drawData();
- boxstack->update(this);
- }
- }
- }
-}
-
+/*\r
+ Copyright 2005 Brian Walton\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+/*\r
+ vepg presents a 2 dimensional electronic programme guide with channels down\r
+ the y axis and time along the x axis.\r
+ Programmes are layed on the x axis as alterate coloured blocks with as much\r
+ of the programme title as will fit inside the block shown as text.\r
+ Up and down commands step through the channels whilst left and right commands\r
+ move through the programmes of the currently selected channel.\r
+ When a programme is selected, it highlights in the grid and full programe details\r
+ (start time, title and description) are displayed in an area at te top left of the screen.\r
+ Any currently programmed timers will display in the grid and in the orogramme detail window as red\r
+ It is possible to select a programme to be recorded by pressing the record button.\r
+ The video stream currently being viewed is shown as quarter screen in the top right.\r
+*/\r
+\r
+#include "vepg.h"\r
+\r
+#include "remote.h"\r
+#include "vchannellist.h"\r
+#include "command.h"\r
+#include "video.h"\r
+#include "vepgsettimer.h"\r
+#include "timers.h"\r
+#include "wsymbol.h"\r
+#include "message.h"\r
+#include "colour.h"\r
+#include "boxstack.h"\r
+#include "channel.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+\r
+VEpg* VEpg::instance = NULL;\r
+\r
+VEpg::VEpg(void* tparent, UINT tcurrentChannelIndex, ULONG streamType)\r
+{\r
+ instance = this;\r
+ currentChannelIndex = tcurrentChannelIndex;\r
+\r
+ // PAL / NTSC sizes -----------------------\r
+\r
+ int xsize, ysize;\r
+ int xpos, ypos;\r
+ int summaryLines, summaryLowerPadding;\r
+ int chanNameYpos;\r
+ //UINT gridRows; // is a class member\r
+\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ xsize = 632;\r
+ ysize = 541;\r
+ xpos = 60;\r
+ ypos = 16;\r
+ summaryLines = 8;\r
+ summaryLowerPadding = 18;\r
+ chanNameYpos = 244;\r
+ gridRows = 7;\r
+ }\r
+ else\r
+ {\r
+ xsize = 632;\r
+ ysize = 452;\r
+ xpos = 50;\r
+ ypos = 10;\r
+ summaryLines = 6;\r
+ summaryLowerPadding = 28;\r
+ chanNameYpos = 206;\r
+ gridRows = 5;\r
+ }\r
+\r
+ // initialise variables and pointers\r
+ boxstack = BoxStack::getInstance();\r
+ parent = tparent;\r
+ eventList = NULL;\r
+ chanList = VDR::getInstance()->getChannelsList(streamType); //TODO want to be able to display video and radio together\r
+ e = 0;\r
+\r
+ for(UINT listIndex = 0; listIndex < gridRows; listIndex++)\r
+ {\r
+ // initialise array of pointers to eventlist structures\r
+ eventLista[listIndex] = NULL;\r
+ }\r
+\r
+ // Create pallet on which to paint our epg view and position it in centre of screen.\r
+ // Need to reduce size to deal with overscanning TVs.\r
+\r
+ setSize(xsize, ysize);\r
+ createBuffer();\r
+ setPosition(xpos, ypos);\r
+\r
+ // beautify\r
+// Colour transparent = Colour(0, 0, 0, 0);\r
+// setBackgroundColour(transparent);\r
+\r
+// progTitle.setSurface(surface);\r
+ progTitle.setPosition(0,0);\r
+ progTitle.setSize(300,(getFontHeight() + 4) * 2 + 16); //paragraph line seperation is 4 pixels\r
+ progTitle.setBackgroundColour(Colour::TITLEBARBACKGROUND);\r
+ progTitle.setTextPos(5, 16);\r
+ progTitle.setGap(4);\r
+ add(&progTitle);\r
+\r
+// progInfo.setSurface(surface);\r
+ progInfo.setBackgroundColour(Colour::VIEWBACKGROUND);\r
+ progInfo.setPosition(0, progTitle.getY2());\r
+ progInfo.setSize(300,((getFontHeight() + 4) * summaryLines) + summaryLowerPadding);\r
+ progInfo.setGap(4);\r
+ add(&progInfo);\r
+\r
+// chanName.setSurface(surface);\r
+ chanName.setSize(510, (getFontHeight() + 4));\r
+ chanName.setPosition(305, chanNameYpos);\r
+ Colour t1(0, 0, 0, 90);\r
+ chanName.setBackgroundColour(t1);\r
+ add(&chanName);\r
+\r
+ // create area to display list of channels\r
+// chanListbox.setSurface(surface); // add channel list\r
+ chanListbox.setPosition(0, progInfo.getY2() + getFontHeight() + 8); // position channel list\r
+ chanListbox.setSize(150, ((getFontHeight() + 2) * gridRows) + 5); //listbox line seperation is 2 pixels\r
+ chanListbox.setGap(2);\r
+ add(&chanListbox);\r
+\r
+ // populate channel list\r
+ if (chanList)\r
+ {\r
+ Channel* chan;\r
+ int first = 1;\r
+ for (UINT i = 0; i < chanList->size(); i++)\r
+ {\r
+ chan = (*chanList)[i];\r
+ if (i == currentChannelIndex)\r
+ first = 1;\r
+ chan->index = chanListbox.addOption(chan->name, 0, first);\r
+ first = 0;\r
+ }\r
+ chanName.setText((*chanList)[chanListbox.getCurrentOption()]->name);\r
+ }\r
+\r
+ listTop = chanListbox.getTopOption();\r
+ chanListbox.draw(); // doing this to allow chanListbox.getBottomOption() in updateEventList() to work\r
+ time(<ime); // set ltime to now\r
+ ltime = prevHour(<ime); // set ltime to previous hour TODO make this half hour?\r
+ time(&selTime); // set selTime to now\r
+ updateEventList(); // get list of programmes\r
+}\r
+\r
+void VEpg::preDelete()\r
+{\r
+ Timers::getInstance()->cancelTimer(this, 1);\r
+}\r
+\r
+VEpg::~VEpg()\r
+{\r
+\r
+ instance = NULL;\r
+\r
+ for(UINT listIndex = 0; listIndex < gridRows; listIndex++)\r
+ {\r
+ if (eventLista[listIndex])\r
+ {\r
+ (eventLista)[listIndex]->clear();\r
+ delete eventLista[listIndex];\r
+ }\r
+ }\r
+ // delete [] eventLista; // FIXME\r
+\r
+ // destroy dynamically allocated memory\r
+}\r
+\r
+VEpg* VEpg::getInstance()\r
+{\r
+ return instance;\r
+}\r
+\r
+void VEpg::setInfo(Event* event)\r
+{\r
+ time_t t;\r
+ struct tm* btime; // to hold programme start and end time\r
+ char timeString[9]; // to hold programme start and end time\r
+ int length = strlen(event->title); // calculate length of programme title string\r
+ char* title = new char[length + 15]; // create string to hold start time, end time and programme title\r
+ btime = localtime((time_t*)&event->time); //get programme start time\r
+#ifndef _MSC_VER\r
+ strftime(timeString, 9, "%0H:%0M - ", btime); // and format it as hh:mm -\r
+#else\r
+ strftime(timeString, 9, "%H:%M - ", btime); // and format it as hh:mm -\r
+#endif\r
+ strcpy(title, timeString); // put it in our buffer\r
+ t = event->time + event->duration; //get programme end time\r
+ btime = localtime(&t);\r
+#ifndef _MSC_VER\r
+ strftime(timeString, 7, "%0H:%0M ", btime); // and format it as hh:mm -\r
+#else\r
+ strftime(timeString, 7, "%H:%M ", btime); // and format it as hh:mm -\r
+#endif\r
+ strcat(title, timeString); // put it in our buffer\r
+ strcat(title, event->title); // then add the programme title\r
+ progTitle.setText(title); // sput this sring in our text box\r
+ length = strlen(event->description);\r
+ char* info = new char[length + 1]; // create programme detail string\r
+ strcpy(info, event->description);\r
+ progInfo.setText(info); // show programme detail string\r
+// destroy dynamically allocated memory\r
+ delete[] info;\r
+ delete[] title;\r
+}\r
+\r
+void VEpg::draw()\r
+{\r
+// View::draw(); // draw pallet\r
+ // beautify\r
+ Colour transparent = Colour(0, 0, 0, 0);\r
+ fillColour(transparent);\r
+ \r
+ \r
+ // Moved all the dynamic data drawing to a seperate function\r
+\r
+ // Display the status and key stuff at the bottom\r
+\r
+ UINT keyx = chanListbox.getRootBoxOffsetX();\r
+ UINT keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;\r
+ Colour ref1 = Colour(100, 100, 100, 255);\r
+ rectangle(keyx, keyy, 605, getFontHeight() * 2 + 14, ref1);\r
+\r
+ WSymbol w;\r
+ TEMPADD(&w);\r
+ \r
+ w.nextSymbol = WSymbol::LEFTARROW;\r
+ w.setPosition(keyx + 1, keyy + 20);\r
+ w.draw();\r
+\r
+ w.nextSymbol = WSymbol::UP;\r
+ w.setPosition(keyx + 26, keyy + 3);\r
+ w.draw();\r
+\r
+ w.nextSymbol = WSymbol::DOWN;\r
+ w.setPosition(keyx + 26, keyy + 36);\r
+ w.draw();\r
+\r
+ w.nextSymbol = WSymbol::RIGHTARROW;\r
+ w.setPosition(keyx + 50, keyy + 20);\r
+ w.draw();\r
+\r
+ drawText(tr("OK"), keyx + 18, keyy + 20, Colour::LIGHTTEXT);\r
+\r
+ Colour ref2 = Colour(200, 0, 0, 255);\r
+ rectangle(keyx + 72, keyy + 4, 104, getFontHeight() + 2, ref2);\r
+ drawText(tr("Page up"), keyx + 74, keyy + 5, Colour::LIGHTTEXT);\r
+\r
+ Colour ref3 = Colour(0, 200, 0, 255);\r
+ rectangle(keyx + 72, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, ref3);\r
+ drawText(tr("Page down"), keyx + 74, keyy + getFontHeight() + 9, Colour::LIGHTTEXT);\r
+\r
+ Colour ref4 = Colour(200, 200, 0, 255);\r
+ rectangle(keyx + 180, keyy + 4, 104, getFontHeight() + 2, ref4);\r
+ drawText(tr("-24 hours"), keyx + 182, keyy + 5, Colour::LIGHTTEXT);\r
+\r
+ Colour ref5 = Colour(0, 0, 200, 255);\r
+ rectangle(keyx + 180, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, ref5);\r
+ drawText(tr("+24 hours"), keyx + 182, keyy + getFontHeight() + 9, Colour::LIGHTTEXT);\r
+\r
+ Colour ref6 = Colour(180, 180, 180, 255);\r
+ rectangle(keyx + 290, keyy + 4, 180, getFontHeight() + 2, ref6);\r
+ drawText(tr("Guide / Back: Close"), keyx + 292 , keyy + 5, Colour::LIGHTTEXT);\r
+\r
+ Colour ref7 = Colour(180, 180, 180, 255);\r
+ rectangle(keyx + 290, keyy + getFontHeight() + 8, 180, getFontHeight() + 2, ref7);\r
+ Colour red = Colour(130, 0, 0);\r
+ drawText(tr("Rec: Set timer"), keyx + 292, keyy + getFontHeight() + 9, red);\r
+\r
+ Colour ref8 = Colour(180, 180, 180, 255);\r
+ rectangle(keyx + 474, keyy + 4, 128, getFontHeight() + 2, ref8);\r
+ w.nextSymbol = WSymbol::PLAY;\r
+ w.setPosition(keyx + 476, keyy + 5);\r
+ w.draw();\r
+ drawText(tr("Sel channel"), keyx + 496, keyy + 5, Colour::LIGHTTEXT);\r
+\r
+ Colour ref9 = Colour(180, 180, 180, 255);\r
+ rectangle(keyx + 474, keyy + getFontHeight() + 8, 128, getFontHeight() + 2, ref9);\r
+ drawText(tr("Go: Preview"), keyx + 476, keyy + getFontHeight() + 9, Colour::LIGHTTEXT);\r
+\r
+\r
+ // Draw all the dynamic data\r
+ drawData();\r
+}\r
+\r
+void VEpg::drawData()\r
+{\r
+ // Not doing View::draw() every time causes\r
+ // things not to be cleared off the surface properly\r
+ // So, blank out the data area first\r
+\r
+ rectangle(\r
+ chanListbox.getRootBoxOffsetX(),\r
+ chanListbox.getRootBoxOffsetY() - getFontHeight() - 3,\r
+ 155 + WINDOW_WIDTH * MINUTE_SCALE,\r
+ chanListbox.getHeight() + getFontHeight() + 4,\r
+ Colour::BLACK);\r
+\r
+ chanListbox.draw();\r
+ drawgrid();\r
+ chanName.draw(); // TODO this should be dealt with by vvideolive\r
+\r
+ progTitle.draw();\r
+ progInfo.draw();\r
+\r
+ // Set timer to redraw to move the current time bar\r
+ time_t t, dt;\r
+ time(&t);\r
+ dt = 60 - (t % 60);\r
+ if (dt == 0) dt = 60;\r
+ dt += t;\r
+ Timers::getInstance()->setTimerT(this, 1, dt);\r
+}\r
+\r
+void VEpg::timercall(int clientReference)\r
+{\r
+ drawData();\r
+ boxstack->update(this);\r
+}\r
+\r
+int VEpg::handleCommand(int command)\r
+{\r
+ switch(command)\r
+ {\r
+ case Remote::DF_UP:\r
+ case Remote::UP:\r
+ { // cursor up the channel list\r
+ chanListbox.up();\r
+ drawData();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::DF_DOWN:\r
+ case Remote::DOWN:\r
+ { // cursor down the channel list\r
+ Log::getInstance()->log("VEPG", Log::DEBUG, "Down start");\r
+ \r
+ chanListbox.down();\r
+ drawData();\r
+ boxstack->update(this);\r
+ Log::getInstance()->log("VEPG", Log::DEBUG, "Down end");\r
+\r
+ return 2;\r
+ }\r
+ case Remote::DF_LEFT:\r
+ case Remote::LEFT:\r
+ { // cursor left through time\r
+ selTime = thisEvent.time - 1;\r
+ drawData();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::DF_RIGHT:\r
+ case Remote::RIGHT:\r
+ {\r
+ // cursor right through time\r
+ selTime = thisEvent.time + thisEvent.duration;\r
+ drawData();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::RED:\r
+ {\r
+ // cursor up one page\r
+ chanListbox.pageUp();\r
+ drawData();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::GREEN:\r
+ {\r
+ // cursor down one page\r
+ chanListbox.pageDown();\r
+ drawData();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::BLUE:\r
+ {\r
+ // step forward 24 hours\r
+ selTime += 24 * 60 * 60;\r
+ drawData();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::YELLOW:\r
+ {\r
+ // step forward 24 hours\r
+ selTime -= 24 * 60 * 60;\r
+ drawData();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::RECORD:\r
+ {\r
+ if (!chanList) return 2;\r
+ Log::getInstance()->log("VEPG", Log::DEBUG, "ID %lu TIME %lu DURATION %lu TITLE %s", thisEvent.id, thisEvent.time, thisEvent.duration, thisEvent.title);\r
+ VEpgSetTimer* vs = new VEpgSetTimer(&thisEvent, (*chanList)[chanListbox.getCurrentOption()]);\r
+ vs->draw();\r
+ boxstack->add(vs);\r
+ boxstack->update(vs);\r
+ return 2;\r
+ }\r
+ case Remote::PLAY:\r
+ case Remote::GO:\r
+ case Remote::OK:\r
+ {\r
+ if (!chanList) return 2;\r
+\r
+ // select programme and display menu TODO currently just changes to selected channel\r
+\r
+ currentChannelIndex = chanListbox.getCurrentOption();\r
+\r
+ if (parent)\r
+ {\r
+ Message* m = new Message(); // Must be done after this view deleted\r
+ m->from = this;\r
+ m->to = parent;\r
+ m->message = Message::CHANNEL_CHANGE;\r
+ m->parameter = (*chanList)[currentChannelIndex]->number;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ }\r
+ \r
+ setCurrentChannel();\r
+\r
+ if(command == Remote::GO)\r
+ return 2;\r
+ // GO just changes channel in preview, PLAY changes channel and returns to normal TV\r
+ }\r
+ case Remote::BACK:\r
+ case Remote::GUIDE:\r
+ {\r
+ // return to normal TV mode\r
+ if (parent) // ptr check done in case being tested from videorec\r
+ {\r
+ Message* m = new Message(); // Must be done after this view deleted\r
+ m->from = this;\r
+ m->to = parent;\r
+ m->message = Message::EPG_CLOSE;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ }\r
+ return 4;\r
+ }\r
+ case Remote::CHANNELUP:\r
+ {\r
+ if (currentChannelIndex == (chanList->size() - 1)) // at the end\r
+ currentChannelIndex = 0;\r
+ else\r
+ ++currentChannelIndex;\r
+ \r
+ if (parent)\r
+ {\r
+ Message* m = new Message(); // Must be done after this view deleted\r
+ m->from = this;\r
+ m->to = parent;\r
+ m->message = Message::CHANNEL_CHANGE;\r
+ m->parameter = (*chanList)[currentChannelIndex]->number;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ }\r
+ \r
+ setCurrentChannel();\r
+\r
+ return 2;\r
+ }\r
+ case Remote::CHANNELDOWN:\r
+ {\r
+ if (currentChannelIndex == 0) // at the start\r
+ currentChannelIndex = chanList->size() - 1; // so go to end\r
+ else\r
+ --currentChannelIndex;\r
+\r
+ if (parent)\r
+ {\r
+ Message* m = new Message(); // Must be done after this view deleted\r
+ m->from = this;\r
+ m->to = parent;\r
+ m->message = Message::CHANNEL_CHANGE;\r
+ m->parameter = (*chanList)[currentChannelIndex]->number;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ }\r
+ \r
+ setCurrentChannel();\r
+\r
+ return 2;\r
+ }\r
+ }\r
+ // stop command getting to any more views\r
+ return 1;\r
+}\r
+\r
+void VEpg::drawgrid() // redraws grid and select programme\r
+{\r
+ // draw the grid of programmes\r
+ char timeString[20];\r
+ time_t t;\r
+ time(&t); // set t = now\r
+ if(selTime < t)\r
+ selTime = t; // don't allow cursor in the past\r
+ if(listTop != chanListbox.getTopOption())\r
+ {\r
+ // chanListbox has scrolled TODO speed up by changing only rows that have changed\r
+ listTop = chanListbox.getTopOption();\r
+ updateEventList();\r
+ }\r
+ if ((selTime >= ltime + WINDOW_WIDTH * 60) || (selTime <= ltime))\r
+ {\r
+ // we have cursored back before left time of window\r
+ //TODO check that this and above don't happen together\r
+ ltime = prevHour(&selTime);\r
+ updateEventList();\r
+ }\r
+ // draw time scale\r
+ Colour white = Colour(255, 255, 255, 255);\r
+ \r
+ t = ltime;\r
+ struct tm* tms;\r
+ tms = localtime(&t);\r
+ strftime(timeString, 19, "%a %d %b", tms);\r
+ int timey = chanListbox.getRootBoxOffsetY() - getFontHeight() - 3;\r
+ int timex = 135;\r
+ drawTextRJ(timeString, timex - 10, timey, Colour::LIGHTTEXT); // print date\r
+ strftime(timeString, 19, "%H:%M", tms);\r
+ drawText(timeString, timex, timey, Colour::LIGHTTEXT); // print left time\r
+\r
+ rectangle(155, timey + getFontHeight(), 2, 7, white);\r
+ t = t + 3600;\r
+ tms = localtime(&t);\r
+ strftime(timeString, 19, "%H:%M", tms);\r
+ drawText(timeString, timex + 180, timey, Colour::LIGHTTEXT); // print middle time\r
+ rectangle(335, timey + getFontHeight(), 2, 7, white);\r
+ t = t + 3600;\r
+ tms = localtime(&t);\r
+ strftime(timeString, 19, "%H:%M", tms);\r
+ drawText(timeString, timex + 360, timey, Colour::LIGHTTEXT); // print right time\r
+ rectangle(515, timey + getFontHeight(), 2, 7, white);\r
+ // pointer to selTime\r
+ //rectangle(155 + (selTime - ltime) / 20, timey + getFontHeight(), 2, 7, Colour(255, 50, 50, 255));\r
+\r
+ // current time line\r
+ time(&t);\r
+ if ((t >= ltime) && (t < (ltime + 9000)))\r
+ {\r
+ rectangle(155 + (t - ltime) / 20, timey + getFontHeight(), 2, ((getFontHeight() + 2) * 7) + 7 + 2, Colour::RED);\r
+ }\r
+\r
+ // TODO should the above two comditional statements be combined to avoid calling updateEventList() twice?\r
+ Event* event;\r
+ Event noevent; // an event to use if there are gaps in the epg\r
+ thisEvent.setdescription(tr("There are no programme details available for this period"));\r
+ thisEvent.duration = WINDOW_WIDTH * 60;\r
+ thisEvent.time = ltime;\r
+ thisEvent.settitle(tr("No programme details"));\r
+ thisEvent.id = 0;\r
+ bool swapColour = false; // alternate cell colour\r
+ bool currentRow = false;\r
+ int y = chanListbox.getRootBoxOffsetY() + 5; // vertical position of cell\r
+ Colour bg, fg; // background colour of cells in grid\r
+ // for each displayed channel, find programmes that fall in 2.5 hour time window\r
+ for(UINT listIndex = 0; listIndex < gridRows; listIndex++)\r
+ {\r
+ if (listTop + (int)listIndex >= chanListbox.getBottomOption())\r
+ continue; // ensure nothing populates grid below last channel\r
+ currentRow = (listTop + (int)listIndex == chanListbox.getCurrentOption());\r
+ noevent.time = ltime;\r
+ noevent.duration = WINDOW_WIDTH * 60;\r
+ noevent.settitle("");\r
+ paintCell(&noevent, y, Colour::NOPROGRAMME, Colour::LIGHTTEXT); // fill row with no programme colour to be painted ove with valid programmes\r
+ if (currentRow)\r
+ {\r
+ thisEvent.setdescription(tr("There are no programme details available for this period"));\r
+ thisEvent.duration = WINDOW_WIDTH * 60;\r
+ thisEvent.time = ltime;\r
+ thisEvent.settitle(tr("No programme details"));\r
+ thisEvent.id = 0;\r
+ }\r
+ if (eventLista[listIndex])\r
+ {\r
+ sort(eventLista[listIndex]->begin(), eventLista[listIndex]->end(), EventSorter());\r
+ for(e = 0; e < (eventLista[listIndex])->size(); e++) // step through events for this channel\r
+ {\r
+ fg = Colour::LIGHTTEXT;\r
+ event = (*eventLista[listIndex])[e];\r
+ if (event)\r
+ {\r
+ UINT end = event->time + event->duration; // programme end time\r
+ if(event->time >= UINT(ltime) + (WINDOW_WIDTH * 60)) // programme starts after RHS of window\r
+ continue; // that's enough of this channel's events\r
+ if(end <= UINT(ltime)) // programme ends before LHS of window\r
+ continue; // this event is before the window - let's try the next event\r
+ // this event is one we are interested in\r
+ bg = (swapColour)?Colour::PROGRAMMEA:Colour::PROGRAMMEB; // alternate cell colour\r
+ swapColour = !swapColour; // it wil be the other colour next time\r
+ if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow)\r
+ {\r
+ // this is the selected programme\r
+ thisEvent.setdescription(event->description);\r
+ thisEvent.duration = event->duration;\r
+ thisEvent.time = event->time;\r
+ thisEvent.settitle(event->title);\r
+ thisEvent.id = event->id;\r
+ if(thisEvent.id == 0)\r
+ thisEvent.id = 1;\r
+ bg = Colour::SELECTHIGHLIGHT; // highlight cell\r
+ fg = Colour::DARKTEXT;\r
+ }\r
+ else\r
+ {\r
+ if (currentRow && thisEvent.id == 0)\r
+ {\r
+ if (end <= UINT(selTime) && end > UINT(thisEvent.time))\r
+ thisEvent.time = end;\r
+ if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration)\r
+ thisEvent.duration = event->time - thisEvent.time;\r
+ }\r
+ }\r
+ paintCell(event, y, bg, fg);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // no event list for this channel. Already painted noevent colour so just highlight if selected\r
+ if (currentRow)\r
+ {\r
+ bg = Colour::SELECTHIGHLIGHT; // highlight cell\r
+ fg = Colour::DARKTEXT;\r
+ paintCell(&thisEvent, y, bg, fg);\r
+ }\r
+ else\r
+ {\r
+ bg = Colour::NOPROGRAMME;\r
+ fg = Colour::LIGHTTEXT;\r
+ noevent.settitle(tr("No programme details"));\r
+ paintCell(&noevent, y, bg, fg);\r
+ }\r
+ }\r
+ y += getFontHeight() + 2;\r
+ }\r
+ setInfo(&thisEvent);\r
+}\r
+\r
+void VEpg::updateEventList()\r
+{\r
+ if (!chanList) return;\r
+ Channel* chan;\r
+ for(UINT listIndex = 0; listIndex < gridRows; listIndex++)\r
+ {\r
+ if(listTop + listIndex >= UINT(chanListbox.getBottomOption()))\r
+ continue;\r
+ chan = (*chanList)[listTop + listIndex];\r
+\r
+ 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\r
+ }\r
+}\r
+\r
+void VEpg::setCurrentChannel()\r
+{\r
+ chanName.setText((*chanList)[currentChannelIndex]->name);\r
+ chanName.draw();\r
+ Region r;\r
+ chanName.getRootBoxRegion(&r);\r
+ boxstack->update(this, &r);\r
+}\r
+\r
+void VEpg::paintCell(Event* event, int yOffset, const Colour& bg, const Colour& fg)\r
+{\r
+ int w, x, y, h;\r
+ w = x = 0; // keep compiler happy\r
+\r
+ y =yOffset;\r
+ h = getFontHeight(); // TODO if want border around text, need to increae this and wselectlist line height\r
+ UINT end = event->time + event->duration; // programme end time\r
+ if(event->time <= UINT(ltime) && end > UINT(ltime)) // spans start of displayed window\r
+ {\r
+ x = 155; // LHS of window\r
+ if (end > (UINT(ltime) + (WINDOW_WIDTH * 60)))\r
+ w = WINDOW_WIDTH * MINUTE_SCALE; // spans full 2 hour window\r
+ else\r
+ w = MINUTE_SCALE * (event->time + event->duration - ltime ) / 60; // get width of remaining programme\r
+ }\r
+ if((event->time >= UINT(ltime)) && (event->time <= UINT(ltime) + (WINDOW_WIDTH * 60))) // starts within window\r
+ {\r
+ x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);\r
+ w = MINUTE_SCALE * event->duration / 60;\r
+ //if (w > 155 + MINUTE_SCALE * WINDOW_WIDTH -x)\r
+ // w = w + x - 155 - MINUTE_SCALE * WINDOW_WIDTH; // ends outside window\r
+ }\r
+ if (w > 155 + WINDOW_WIDTH * MINUTE_SCALE - x)\r
+ w = 155 + WINDOW_WIDTH * MINUTE_SCALE -x; // limit cells to RHS of window\r
+ rectangle(x, y, w, h, bg);\r
+ char* tt = new char[strlen(event->title) + 1];\r
+ strcpy (tt, event->title);\r
+ int textWidth = 0;\r
+ for (UINT textPos = 0; textPos < strlen(tt); textPos++)\r
+ {\r
+ int thisCharWidth = charWidth(tt[textPos]);\r
+ if (textWidth + thisCharWidth > w) // text will not fit in cell\r
+ {\r
+ textWidth = textPos;\r
+ break;\r
+ }\r
+ textWidth += thisCharWidth;\r
+ }\r
+ char* tT = new char[textWidth];\r
+ if(textWidth > 1)\r
+ {\r
+ strncpy(tT, tt, textWidth - 1);\r
+ tT[textWidth - 1] = '\0';\r
+ surface->drawText(tT, x+2, y, fg.rgba());\r
+ }\r
+ delete tT;\r
+\r
+}\r
+\r
+time_t VEpg::prevHour(time_t* t)\r
+{\r
+ struct tm* tms;\r
+ tms = localtime(t);\r
+ tms->tm_sec = 0;\r
+ tms->tm_min = 0;\r
+ return mktime(tms);\r
+}\r
+\r
+void VEpg::processMessage(Message* m)\r
+{\r
+ if (m->message == Message::MOUSE_MOVE)\r
+ {\r
+ if (chanListbox.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ drawData();\r
+ boxstack->update(this);\r
+ }\r
+ }\r
+ else if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ if (chanListbox.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ boxstack->handleCommand(Remote::OK); //simulate OK press\r
+ }\r
+ else\r
+ {\r
+ //check if press is outside this view! then simulate cancel\r
+ int x=(m->parameter>>16)-getScreenX();\r
+ int y=(m->parameter&0xFFFF)-getScreenY();\r
+ int keyx = chanListbox.getRootBoxOffsetX();\r
+ int keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;\r
+\r
+ if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+ {\r
+ boxstack->handleCommand(Remote::BACK); //simulate cancel press\r
+ }\r
+ else if (x>=(keyx+72) && y>=(keyy+4) &&x<=(keyx+72+104) &&y<=(keyy+4+getFontHeight() + 2))\r
+ {\r
+ boxstack->handleCommand(Remote::RED);\r
+ }\r
+ else if (x>=(keyx+72) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+72+104) &&y<=(keyy+8+2*getFontHeight() + 2))\r
+ {\r
+ boxstack->handleCommand(Remote::GREEN);\r
+ }\r
+ else if (x>=(keyx+180) && y>=(keyy+4) &&x<=(keyx+180+104) &&y<=(keyy+4+getFontHeight() + 2))\r
+ {\r
+ boxstack->handleCommand(Remote::YELLOW);\r
+ }\r
+ else if (x>=(keyx+180) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+180+104) &&y<=(keyy+8+2*getFontHeight() + 2))\r
+ {\r
+ boxstack->handleCommand(Remote::BLUE);\r
+ }\r
+ else if (x>=(keyx+290) && y>=(keyy+4) &&x<=(keyx+180+290) &&y<=(keyy+4+getFontHeight() + 2))\r
+ {\r
+ boxstack->handleCommand(Remote::BACK);\r
+ }\r
+ else if (x>=(keyx+290) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+290+180) &&y<=(keyy+8+2*getFontHeight() + 2))\r
+ {\r
+ boxstack->handleCommand(Remote::RECORD);\r
+ }\r
+ else if (x>=(keyx+474) && y>=(keyy+4) &&x<=(keyx+128+474) &&y<=(keyy+4+getFontHeight() + 2))\r
+ {\r
+ boxstack->handleCommand(Remote::PLAY);\r
+ }\r
+ else if (x>=(keyx+474) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+238+474) &&y<=(keyy+8+2*getFontHeight() + 2))\r
+ {\r
+ boxstack->handleCommand(Remote::GO);\r
+ }\r
+ else if ( x>=(chanListbox.getRootBoxOffsetX())\r
+ && y>=(chanListbox.getRootBoxOffsetY() + 5)\r
+ // &&x<=(chanListbox.getOffsetX()+155 + WINDOW_WIDTH * MINUTE_SCALE)\r
+ &&y<=(chanListbox.getRootBoxOffsetY() - getFontHeight()\r
+ - 3+(int)chanListbox.getHeight() + getFontHeight() + 3)\r
+ )\r
+ {\r
+ int cy=y-(chanListbox.getRootBoxOffsetY() + 5);\r
+ int row=cy/(getFontHeight()+2);\r
+ int clistTop = chanListbox.getTopOption();\r
+ chanListbox.hintSetCurrent(clistTop+row);\r
+ int cx=x-155;\r
+ time_t ttime = cx*60/MINUTE_SCALE+ltime;\r
+ //x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);\r
+\r
+ selTime = ttime;\r
+ drawData();\r
+ boxstack->update(this);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
add(&buttonYes);
add(&buttonNo);
- buttonYes.setPosition(80, 40 + (7 * surface->getFontHeight()));
- buttonNo.setPosition(220, 40 + (7 * surface->getFontHeight()));
+ buttonYes.setPosition(80, 40 + (7 * getFontHeight()));
+ buttonNo.setPosition(220, 40 + (7 * getFontHeight()));
buttonYes.setText(tr("Yes"));
buttonNo.setText(tr("No"));
{
TBBoxx::draw();
drawPara(event->title, 10, 40, Colour::LIGHTTEXT);
- drawText(channel->name, 10, 40 + (2 * surface->getFontHeight()), Colour::LIGHTTEXT);
+ drawText(channel->name, 10, 40 + (2 * getFontHeight()), Colour::LIGHTTEXT);
char fullString[20];
time_t t;
strcat(fullString, timeString); // put it in our buffer
- drawText(fullString, 10, 40 + (3 * surface->getFontHeight()), Colour::LIGHTTEXT);
- drawText(tr("Create this timer?"), 10, 40 + (5 * surface->getFontHeight()), Colour::LIGHTTEXT);
+ drawText(fullString, 10, 40 + (3 * getFontHeight()), Colour::LIGHTTEXT);
+ drawText(tr("Create this timer?"), 10, 40 + (5 * getFontHeight()), Colour::LIGHTTEXT);
buttonYes.draw();
buttonNo.draw();
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vfeed.h"
-
-#include "log.h"
-#include "demuxer.h"
-#include "callback.h"
-
-VFeed::VFeed(Callback* tcb)
-: cb(*tcb)
-{
-}
-
-int VFeed::init()
-{
- return 1;
-}
-
-int VFeed::shutdown()
-{
- // FIXME
- return 1;
-}
-
-int VFeed::start()
-{
- return threadStart();
-}
-
-void VFeed::stop()
-{
- threadCancel();
-}
-
-void VFeed::release()
-{
- threadSignal();
-}
-
-void VFeed::threadMethod()
-{
- bool vlen;
-
- Log::getInstance()->log("VFeed", Log::DEBUG, "Started");
- threadWaitForSignal(); // Don't feed video until audio has started
- Log::getInstance()->log("VFeed", Log::DEBUG, "Released");
-
- while(1)
- {
- threadCheckExit();
- vlen = Demuxer::getInstance()->writeVideo();
-
- if (vlen)
- {
- cb.call(this);
- }
- else
- {
- //Log::getInstance()->log("VFeed", Log::DEBUG, "No data delay");
- MILLISLEEP(5);
- }
- }
-}
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vfeed.h"\r
+\r
+#include "log.h"\r
+#include "demuxer.h"\r
+#include "callback.h"\r
+\r
+VFeed::VFeed(Callback* tcb)\r
+: cb(*tcb)\r
+{\r
+}\r
+\r
+int VFeed::init()\r
+{\r
+ return 1;\r
+}\r
+\r
+int VFeed::shutdown()\r
+{\r
+ // FIXME\r
+ return 1;\r
+}\r
+\r
+int VFeed::start()\r
+{\r
+ return threadStart();\r
+}\r
+\r
+void VFeed::stop()\r
+{\r
+ Log::getInstance()->log("VFeed", Log::DEBUG, "Stop1");\r
+ threadCancel();\r
+ Log::getInstance()->log("VFeed", Log::DEBUG, "Stop2");\r
+}\r
+\r
+void VFeed::release()\r
+{\r
+ threadSignal();\r
+}\r
+\r
+void VFeed::threadMethod()\r
+{\r
+ bool vlen;\r
+\r
+ Log::getInstance()->log("VFeed", Log::DEBUG, "Started");\r
+ threadWaitForSignal(); // Don't feed video until audio has started\r
+ Log::getInstance()->log("VFeed", Log::DEBUG, "Released");\r
+\r
+ while(1)\r
+ {\r
+ threadCheckExit();\r
+ vlen = Demuxer::getInstance()->writeVideo();\r
+\r
+ if (vlen)\r
+ {\r
+ cb.call(this);\r
+ }\r
+ else\r
+ {\r
+ //Log::getInstance()->log("VFeed", Log::DEBUG, "No data delay");\r
+ MILLISLEEP(5);\r
+ }\r
+ }\r
+}\r
+\r
#include <stdio.h>
#include <time.h>
-#ifdef WIN32
-#include "threadwin.h"
+#ifndef WIN32
+#ifdef __ANDROID__
+#include "threadpandroid.h"
#else
#include "threadp.h"
#endif
+#else
+#include "threadwin.h"
+#endif
class Callback;
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-//portions from vdr by Klaus Schmiding HSMF code
-
-#include "video.h"
-
-Video* Video::instance = NULL;
-
-Video::Video()
-{
- if (instance) return;
- instance = this;
- initted = 0;
-
- fdVideo = 0;
-
- format = 0;
- connection = 0;
- aspectRatio = 0;
- mode = 0;
- tvsize = 0;
-
- screenWidth = 0;
- screenHeight = 0;
-}
-
-Video::~Video()
-{
- instance = NULL;
-}
-
-Video* Video::getInstance()
-{
- return instance;
-}
-
-/*
-hmsf Video::framesToHMSF(ULONG frames, double fps)
-{
- hmsf ret;
- / * from vdr *
- double Seconds;
- ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);
- int s = int(Seconds);
- ret.seconds=s;
- ret.minutes = s / 60 % 60;
- ret.hours = s / 3600;
-
-/ * if (format == NTSC)
- {
- ret.hours = frames / 108000;
- frames %= 108000;
- ret.minutes = frames / 1800;
- frames %= 1800;
- ret.seconds = frames / 30;
- ret.frames = frames % 30;
- }
- else
- {
- ret.hours = frames / 90000;
- frames %= 90000;
- ret.minutes = frames / 1500;
- frames %= 1500;
- ret.seconds = frames / 25;
- ret.frames = frames % 25;
- }* /
- return ret;
-}*/
-
-/*
-UINT Video::getFPS()
-{
- if (format == NTSC) return 30;
- else return 25;
-}
-*/
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+//portions from vdr by Klaus Schmiding HSMF code\r
+\r
+#include "video.h"\r
+\r
+Video* Video::instance = NULL;\r
+\r
+Video::Video()\r
+{\r
+ if (instance) return;\r
+ instance = this;\r
+ initted = 0;\r
+\r
+ fdVideo = 0;\r
+\r
+ format = 0;\r
+ connection = 0;\r
+ aspectRatio = 0;\r
+ mode = 0;\r
+ tvsize = 0;\r
+\r
+ screenWidth = 0;\r
+ screenHeight = 0;\r
+}\r
+\r
+Video::~Video()\r
+{\r
+ instance = NULL;\r
+}\r
+\r
+Video* Video::getInstance()\r
+{\r
+ return instance;\r
+}\r
+/*\r
+void Video::setInstance(Video* inst)\r
+{\r
+ instance=inst;\r
+}*/\r
+\r
+/*\r
+hmsf Video::framesToHMSF(ULONG frames, double fps)\r
+{\r
+ hmsf ret;\r
+ / * from vdr *\r
+ double Seconds;\r
+ ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);\r
+ int s = int(Seconds);\r
+ ret.seconds=s;\r
+ ret.minutes = s / 60 % 60;\r
+ ret.hours = s / 3600;\r
+\r
+/ * if (format == NTSC)\r
+ {\r
+ ret.hours = frames / 108000;\r
+ frames %= 108000;\r
+ ret.minutes = frames / 1800;\r
+ frames %= 1800;\r
+ ret.seconds = frames / 30;\r
+ ret.frames = frames % 30;\r
+ }\r
+ else\r
+ {\r
+ ret.hours = frames / 90000;\r
+ frames %= 90000;\r
+ ret.minutes = frames / 1500;\r
+ frames %= 1500;\r
+ ret.seconds = frames / 25;\r
+ ret.frames = frames % 25;\r
+ }* /\r
+ return ret;\r
+}*/\r
+\r
+/*\r
+UINT Video::getFPS()\r
+{\r
+ if (format == NTSC) return 30;\r
+ else return 25;\r
+}\r
+*/\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef VIDEO_H
-#define VIDEO_H
-
-#include <stdio.h>
-#include "defines.h"
-#include "draintarget.h"
-#include "abstractoption.h"
-
-typedef struct _hmsf
-{
- UINT hours;
- UINT minutes;
- UINT seconds;
- UINT frames;
-} hmsf;
-
-class Video: public DrainTarget, public AbstractOption
-{
- public:
- Video();
- virtual ~Video();
- static Video* getInstance();
-
- virtual int init(UCHAR format)=0;
- virtual int shutdown()=0;
- virtual int setFormat(UCHAR format)=0;
- virtual int setConnection(UCHAR connection)=0;
- virtual int setAspectRatio(UCHAR aspectRatio)=0; // This one does the pin 8 scart widescreen switching
- virtual int setMode(UCHAR mode)=0;
- virtual int setTVsize(UCHAR size)=0; // Is the TV a widescreen?
- virtual int setDefaultAspect()=0;
- virtual int setSource()=0;
- virtual int setPosition(int x, int y)=0;
- virtual int sync()=0;
- virtual int play()=0;
- virtual int stop()=0;
- virtual int pause()=0;
- virtual int unPause()=0;
- virtual int fastForward()=0;
- virtual int unFastForward()=0;
- virtual int reset()=0;
- virtual int blank()=0;
- virtual int signalOn()=0;
- virtual int signalOff()=0;
- virtual int attachFrameBuffer()=0; // What does this do?
-// virtual ULONG timecodeToFrameNumber(ULLONG timecode)=0; //Obsolete and not HD compatible
- virtual ULLONG getCurrentTimestamp()=0;
- virtual void displayIFrame(const UCHAR* buffer, UINT length)=0;
-
- virtual bool supportsh264(){return false;};
- virtual void seth264mode(bool ish264) {h264=ish264;};
-
- virtual void turnVideoOn(){};
- virtual void turnVideoOff(){};
-// virtual ULLONG frameNumberToTimecode(ULONG timecode) { return 0; };//Obsolete and not HD compatible
-
-#ifdef DEV
- virtual int test() { return 0; }
- virtual int test2() { return 0; }
-#endif
-
- int getMode() { return mode; }
- UCHAR getFormat() { return format; }
- UINT getScreenWidth() { return screenWidth; }
- UINT getScreenHeight() { return screenHeight; }
- UCHAR getTVsize() { return tvsize; }
-
- //hmsf framesToHMSF(ULONG frames,double fps);
- // UINT getFPS(); //removed
-
- // Video formats - AV_SET_VID_DISP_FMT
- const static UCHAR NTSC = 0;
- const static UCHAR PAL = 1;
-
- // Video connections - AV_SET_VID_OUTPUT
- const static UCHAR COMPOSITERGB = 1;
- const static UCHAR SVIDEO = 2;
-
- // Video aspect ratios - AV_SET_VID_RATIO
- const static UCHAR ASPECT4X3 = 0;
- const static UCHAR ASPECT16X9 = 1;
-
- // Video modes - AV_SET_VID_MODE
- const static UCHAR NORMAL = 0;
- const static UCHAR LETTERBOX = 1;
-/*
- Actual Source Aspect Aspect IOCTL Mode IOCTL MODE A MODE B
-
- 4:3 4:3 NORMAL fullframe43 fullframe43
- 4:3 16:9 NORMAL fullframe43 fullframe43 -- invalid?
- 4:3 4:3 LETTERBOX fullframe43 fullframe43
- 4:3 16:9 LETTERBOX fullframe43 fullframe43 -- invalid?
- 16:9 4:3 NORMAL chop sides fullframe169
- 16:9 16:9 NORMAL chop sides fullframe169
- 16:9 4:3 LETTERBOX letterbox letterbox
- 16:9 16:9 LETTERBOX chop sides fullframe169
-
- Conclusions
-
- 1. There are two chip modes - accessible by reopening the fd
- 2. The video chip knows the aspect ratio purely from the incoming MPEG
- 3. MODE A is for 4:3 TVs, MODE B is for 16:9 TVs
-
- To switch to MODE A, set the aspect ioctl to 4:3 and reopen the FD.
- To switch to MODE B, set the aspect ioctl to 16:9 and reopen the FD.
-*/
-
- const static UCHAR UNKNOWN2 = 2;
- const static UCHAR QUARTER = 3;
- const static UCHAR EIGHTH = 4;
- const static UCHAR ZOOM = 5;
- const static UCHAR UNKNOWN6 = 6;
-
- protected:
- static Video* instance;
- int initted;
- int fdVideo;
-
- UCHAR tvsize;
- UCHAR format;
- UCHAR connection;
- UCHAR aspectRatio;
- UCHAR mode;
- bool h264;
-
- UINT screenWidth;
- UINT screenHeight;
-};
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef VIDEO_H\r
+#define VIDEO_H\r
+\r
+#include <stdio.h>\r
+#include "defines.h"\r
+#include "draintarget.h"\r
+#include "abstractoption.h"\r
+\r
+typedef struct _hmsf\r
+{\r
+ UINT hours;\r
+ UINT minutes;\r
+ UINT seconds;\r
+ UINT frames;\r
+} hmsf;\r
+\r
+class Video: public DrainTarget, public AbstractOption\r
+{\r
+ public:\r
+ Video();\r
+ virtual ~Video();\r
+ static Video* getInstance();\r
+ //static void setInstance(Video*);\r
+\r
+ virtual int init(UCHAR format)=0;\r
+ virtual int shutdown()=0;\r
+ virtual int setFormat(UCHAR format)=0;\r
+ virtual int setConnection(UCHAR connection)=0;\r
+ virtual int setAspectRatio(UCHAR aspectRatio)=0; // This one does the pin 8 scart widescreen switching\r
+ virtual int setMode(UCHAR mode)=0;\r
+ virtual int setTVsize(UCHAR size)=0; // Is the TV a widescreen?\r
+ virtual int setDefaultAspect()=0;\r
+ virtual int setSource()=0;\r
+ virtual int setPosition(int x, int y)=0;\r
+ virtual int sync()=0;\r
+ virtual int play()=0;\r
+ virtual int stop()=0;\r
+ virtual int pause()=0;\r
+ virtual int unPause()=0;\r
+ virtual int fastForward()=0;\r
+ virtual int unFastForward()=0;\r
+ virtual int reset()=0;\r
+ virtual int blank()=0;\r
+ virtual int signalOn()=0;\r
+ virtual int signalOff()=0;\r
+ virtual int attachFrameBuffer()=0; // What does this do?\r
+// virtual ULONG timecodeToFrameNumber(ULLONG timecode)=0; //Obsolete and not HD compatible\r
+ virtual ULLONG getCurrentTimestamp()=0;\r
+ virtual bool displayIFrame(const UCHAR* buffer, UINT length)=0;\r
+ virtual int EnterIframePlayback() {return 1;}; // Must not be implemented\r
+\r
+ virtual bool supportsh264(){return false;};\r
+ virtual void seth264mode(bool ish264) {h264=ish264;};\r
+ virtual int getTeletextBufferFaktor(){return 1;};\r
+\r
+ virtual bool independentAVStartUp() {return true;};\r
+\r
+\r
+ //Tells, if the device allows an independent startup of audio and video\r
+ // this needs internal buffers in device and is possible for windows and mvp\r
+\r
+ virtual bool PTSIFramePlayback() {return false;};\r
+ // Tells, if the iframe playback is realized using a manipulation of the pts of the packets\r
+ //android does it like this...\r
+\r
+ virtual bool blockingDrainTarget() { return false;};\r
+ // if the draintargets blocks, the feed has to be stop when pausing\r
+\r
+\r
+ virtual void turnVideoOn(){};\r
+ virtual void turnVideoOff(){};\r
+// virtual ULLONG frameNumberToTimecode(ULONG timecode) { return 0; };//Obsolete and not HD compatible\r
+\r
+#ifdef DEV\r
+ virtual int test() { return 0; }\r
+ virtual int test2() { return 0; }\r
+#endif\r
+\r
+ int getMode() { return mode; }\r
+ UCHAR getFormat() { return format; }\r
+ UINT getScreenWidth() { return screenWidth; }\r
+ UINT getScreenHeight() { return screenHeight; }\r
+ UCHAR getTVsize() { return tvsize; }\r
+\r
+ //hmsf framesToHMSF(ULONG frames,double fps);\r
+ // UINT getFPS(); //removed\r
+\r
+ // Video formats - AV_SET_VID_DISP_FMT\r
+ const static UCHAR NTSC = 0;\r
+ const static UCHAR PAL = 1;\r
+\r
+ // Video connections - AV_SET_VID_OUTPUT\r
+ const static UCHAR COMPOSITERGB = 1;\r
+ const static UCHAR SVIDEO = 2;\r
+\r
+ // Video aspect ratios - AV_SET_VID_RATIO\r
+ const static UCHAR ASPECT4X3 = 0;\r
+ const static UCHAR ASPECT16X9 = 1;\r
+\r
+ // Video modes - AV_SET_VID_MODE\r
+ const static UCHAR NORMAL = 0;\r
+ const static UCHAR LETTERBOX = 1;\r
+/*\r
+ Actual Source Aspect Aspect IOCTL Mode IOCTL MODE A MODE B\r
+\r
+ 4:3 4:3 NORMAL fullframe43 fullframe43\r
+ 4:3 16:9 NORMAL fullframe43 fullframe43 -- invalid?\r
+ 4:3 4:3 LETTERBOX fullframe43 fullframe43\r
+ 4:3 16:9 LETTERBOX fullframe43 fullframe43 -- invalid?\r
+ 16:9 4:3 NORMAL chop sides fullframe169\r
+ 16:9 16:9 NORMAL chop sides fullframe169\r
+ 16:9 4:3 LETTERBOX letterbox letterbox\r
+ 16:9 16:9 LETTERBOX chop sides fullframe169\r
+\r
+ Conclusions\r
+\r
+ 1. There are two chip modes - accessible by reopening the fd\r
+ 2. The video chip knows the aspect ratio purely from the incoming MPEG\r
+ 3. MODE A is for 4:3 TVs, MODE B is for 16:9 TVs\r
+\r
+ To switch to MODE A, set the aspect ioctl to 4:3 and reopen the FD.\r
+ To switch to MODE B, set the aspect ioctl to 16:9 and reopen the FD.\r
+*/\r
+\r
+ const static UCHAR UNKNOWN2 = 2;\r
+ const static UCHAR QUARTER = 3;\r
+ const static UCHAR EIGHTH = 4;\r
+ const static UCHAR ZOOM = 5;\r
+ const static UCHAR UNKNOWN6 = 6;\r
+\r
+ protected:\r
+ static Video* instance;\r
+ int initted;\r
+ int fdVideo;\r
+\r
+ UCHAR tvsize;\r
+ UCHAR format;\r
+ UCHAR connection;\r
+ UCHAR aspectRatio;\r
+ UCHAR mode;\r
+ bool h264;\r
+\r
+ UINT screenWidth;\r
+ UINT screenHeight;\r
+};\r
+\r
+#endif\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "videomvp.h"
-
-// temp
-#include "log.h"
-
-VideoMVP::VideoMVP()
-{
- if (instance) return;
-}
-
-VideoMVP::~VideoMVP()
-{
- instance = NULL;
-}
-
-int VideoMVP::init(UCHAR tformat)
-{
- if (initted) return 0;
- initted = 1;
-
- if ((fdVideo = open("/dev/vdec_dev", O_WRONLY)) < 0) return 0;
-
- if (!setFormat(tformat)) { shutdown(); return 0; }
- if (!setConnection(COMPOSITERGB)) { shutdown(); return 0; }
- if (!setAspectRatio(ASPECT4X3)) { shutdown(); return 0; }
- if (!setMode(NORMAL)) { shutdown(); return 0; }
- if (!setSource()) { shutdown(); return 0; }
- if (!attachFrameBuffer()) { shutdown(); return 0; }
-
- setTVsize(ASPECT4X3);
-
- if (format == PAL) setLetterboxBorder("38");
- else setLetterboxBorder("31");
-
- stop();
-
-
- return 1;
-}
-
-void VideoMVP::setLetterboxBorder(char* border)
-{
- FILE* fdlbox = fopen("/proc/lbox_border", "w");
- if (!fdlbox) return;
- fputs(border, fdlbox);
- fclose(fdlbox);
-}
-
-int VideoMVP::setTVsize(UCHAR ttvsize)
-{
- tvsize = ttvsize;
-
- // Override the aspect ratio usage, temporarily use to set the video chip mode
- if (!setAspectRatio(tvsize)) { shutdown(); return 0; }
- close(fdVideo);
- if ((fdVideo = open("/dev/vdec_dev", O_WRONLY)) < 0) return 0;
- if (!setSource()) { shutdown(); return 0; }
- if (!attachFrameBuffer()) { shutdown(); return 0; }
-
- // Reopening the fd causes the scart aspect line to go back to 4:3
- // Set this again to the same as the tv screen size
- if (!setAspectRatio(tvsize)) { shutdown(); return 0; }
-
- // mode == LETTERBOX is invalid if the TV is widescreen
- if (tvsize == ASPECT16X9) setMode(NORMAL);
-
- return 1;
-}
-
-int VideoMVP::setDefaultAspect()
-{
- return setAspectRatio(tvsize);
-}
-
-int VideoMVP::shutdown()
-{
- if (!initted) return 0;
- initted = 0;
- close(fdVideo);
- return 1;
-}
-
-int VideoMVP::checkSCART()
-{
- // Returns 3 for SCART Composite out
- // Returns 3 for SCART S-Video out
- // Returns 2 for SCART RGB out
- // Returns 3 for SCART not plugged in
-
- // So, as you can have RGB and composite out simultaneously,
- // and it can't detect S-Video, what is the point of this?
-
- int scart;
- if (ioctl(fdVideo, AV_CHK_SCART, &scart) != 0) return -10;
-
- return scart;
-}
-
-int VideoMVP::setFormat(UCHAR tformat)
-{
- if (!initted) return 0;
- if ((tformat != PAL) && (tformat != NTSC)) return 0;
- format = tformat;
-
- if (ioctl(fdVideo, AV_SET_VID_DISP_FMT, format) != 0) return 0;
-
- if (format == NTSC)
- {
- screenWidth = 720;
- screenHeight = 480;
- }
- if (format == PAL)
- {
- screenWidth = 720;
- screenHeight = 576;
- }
-
- return 1;
-}
-
-int VideoMVP::setConnection(UCHAR tconnection)
-{
- if (!initted) return 0;
- if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;
- connection = tconnection;
-
- if (ioctl(fdVideo, AV_SET_VID_OUTPUT, connection) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::setAspectRatio(UCHAR taspectRatio)
-{
- if (!initted) return 0;
- if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;
- aspectRatio = taspectRatio;
-
- Log::getInstance()->log("Video", Log::DEBUG, "Setting aspect to %i", aspectRatio);
-
- if (ioctl(fdVideo, AV_SET_VID_RATIO, aspectRatio) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::setMode(UCHAR tmode)
-{
- if (!initted) return 0;
-
- if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode
-
- if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)
- && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;
- mode = tmode;
-
- if (ioctl(fdVideo, AV_SET_VID_MODE, mode) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::signalOff()
-{
- if (ioctl(fdVideo, AV_SET_VID_DENC, 0) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::signalOn()
-{
- if (ioctl(fdVideo, AV_SET_VID_DENC, 1) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::setSource()
-{
- if (!initted) return 0;
-
- // What does this do...
- if (ioctl(fdVideo, AV_SET_VID_SRC, 1) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::setPosition(int x, int y)
-{
- if (!initted) return 0;
-
-// vid_pos_regs_t pos_d;
-// pos_d.x = x;
-// pos_d.y = y;
-
- vid_pos_regs_t pos_d;
-
- memset(&pos_d, 0, sizeof(pos_d));
-
- pos_d.dest.y = y;
- pos_d.dest.x = x;
-/*
-typedef struct {
- int w;
- int h;
- int scale;
- int x1;
- int y;
- int x;
- int y2;
- int x3;
- int y3;
- int x4;
- int y4;
-} vid_pos_regs_t;
-*/
-
-/*
- pos_d.w = 100;
- pos_d.h = 30;
- pos_d.scale = 2;
- pos_d.x1 = 0;
- pos_d.y = 100; // Top left X
- pos_d.x = 50; // Top left Y
- pos_d.y2 = 30;
- pos_d.x3 = 60;
- pos_d.y3 = 90;
- pos_d.x4 = 120;
- pos_d.y4 = 150;
-*/
-
- if (ioctl(fdVideo, AV_SET_VID_POSITION, &pos_d) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::sync()
-{
- if (!initted) return 0;
-
- if (ioctl(fdVideo, AV_SET_VID_SYNC, 2) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::play()
-{
- if (!initted) return 0;
-
- if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::stop()
-{
- if (!initted) return 0;
-
- if (ioctl(fdVideo, AV_SET_VID_STOP, 0) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::reset()
-{
- if (!initted) return 0;
-
- if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::pause()
-{
- if (!initted) return 0;
-
- if (ioctl(fdVideo, AV_SET_VID_PAUSE, 0) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::unPause() // FIXME get rid - same as play!!
-{
- if (!initted) return 0;
- if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::fastForward()
-{
- if (!initted) return 0;
-
- if (ioctl(fdVideo, AV_SET_VID_FFWD, 1) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::unFastForward()
-{
- if (!initted) return 0;
-
-// if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0; // don't need this.
-
- if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::attachFrameBuffer()
-{
- if (!initted) return 0;
-
- if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0;
- return 1;
-}
-
-int VideoMVP::blank(void)
-{
- if (ioctl(fdVideo, AV_SET_VID_FB, 1) != 0) return 0;
- if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0;
- return 1;
-}
-
-ULLONG VideoMVP::getCurrentTimestamp()
-{
- sync_data_t timestamps;
- if (ioctl(fdVideo, AV_GET_VID_TIMESTAMPS, ×tamps) == 0)
- {
- // FIXME are these the right way around?
-
- timestamps.stc = (timestamps.stc >> 31 ) | (timestamps.stc & 1);
- timestamps.pts = (timestamps.pts >> 31 ) | (timestamps.pts & 1);
-
- return timestamps.stc;
- }
- else
- {
- return 0;
- }
-}
-
-ULONG VideoMVP::timecodeToFrameNumber(ULLONG timecode)
-{
- if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);
- else return (ULONG)(((double)timecode / (double)90000) * (double)30);
-}
-
-#ifdef DEV
-int VideoMVP::test()
-{
- return 0;
-
-// ULLONG stc = 0;
-// return ioctl(fdVideo, AV_SET_VID_STC, &stc);
-/*
- // reset();
- return 1;
-*/
-}
-
-int VideoMVP::test2()
-{
- return 0;
-}
-#endif
-
-void VideoMVP::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)
-{
- MediaPacketList::const_iterator iter = mplist.begin();
- deliver_start = iter->pos_buffer + samplepos;
- mediapacket_len[0] = deliver_length = iter->length;
- deliver_count = 1;
- while (++iter != mplist.end() &&
- iter->pos_buffer == deliver_start + deliver_length)
- {
- deliver_length += iter->length;
- mediapacket_len[deliver_count] = iter->length;
- ++deliver_count;
- if (deliver_length >= WRITE_LENGTH ||
- deliver_count == WRITE_PACKETS) break;
- }
-}
-
-UINT VideoMVP::DeliverMediaSample(UCHAR* buffer, UINT* samplepos)
-{
- int written = ::write(fdVideo, buffer + deliver_start, deliver_length);
- if (written == (int)deliver_length) { *samplepos = 0; return deliver_count;}
- if (written <= 0) return 0;
- // Handle a partial write. Is this possible? Should we bother?
- UINT i = 0;
- while ((written -= mediapacket_len[i]) >= 0) i++;
- *samplepos = mediapacket_len[i] + written;
- return i;
-}
-
-void VideoMVP::ResetTimeOffsets()
-{
-}
-
-void VideoMVP::displayIFrame(const UCHAR* buffer, UINT length)
-{
- write(fdVideo, buffer, length);
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "videomvp.h"\r
+\r
+// temp\r
+#include "log.h"\r
+\r
+VideoMVP::VideoMVP()\r
+{\r
+ if (instance) return;\r
+}\r
+\r
+VideoMVP::~VideoMVP()\r
+{\r
+ instance = NULL;\r
+}\r
+\r
+int VideoMVP::init(UCHAR tformat)\r
+{\r
+ if (initted) return 0;\r
+ initted = 1;\r
+\r
+ if ((fdVideo = open("/dev/vdec_dev", O_WRONLY)) < 0) return 0;\r
+\r
+ if (!setFormat(tformat)) { shutdown(); return 0; }\r
+ if (!setConnection(COMPOSITERGB)) { shutdown(); return 0; }\r
+ if (!setAspectRatio(ASPECT4X3)) { shutdown(); return 0; }\r
+ if (!setMode(NORMAL)) { shutdown(); return 0; }\r
+ if (!setSource()) { shutdown(); return 0; }\r
+ if (!attachFrameBuffer()) { shutdown(); return 0; }\r
+\r
+ setTVsize(ASPECT4X3);\r
+\r
+ if (format == PAL) setLetterboxBorder("38");\r
+ else setLetterboxBorder("31");\r
+\r
+ stop();\r
+\r
+\r
+ return 1;\r
+}\r
+\r
+void VideoMVP::setLetterboxBorder(char* border)\r
+{\r
+ FILE* fdlbox = fopen("/proc/lbox_border", "w");\r
+ if (!fdlbox) return;\r
+ fputs(border, fdlbox);\r
+ fclose(fdlbox);\r
+}\r
+\r
+int VideoMVP::setTVsize(UCHAR ttvsize)\r
+{\r
+ tvsize = ttvsize;\r
+\r
+ // Override the aspect ratio usage, temporarily use to set the video chip mode\r
+ if (!setAspectRatio(tvsize)) { shutdown(); return 0; }\r
+ close(fdVideo);\r
+ if ((fdVideo = open("/dev/vdec_dev", O_WRONLY)) < 0) return 0;\r
+ if (!setSource()) { shutdown(); return 0; }\r
+ if (!attachFrameBuffer()) { shutdown(); return 0; }\r
+\r
+ // Reopening the fd causes the scart aspect line to go back to 4:3\r
+ // Set this again to the same as the tv screen size\r
+ if (!setAspectRatio(tvsize)) { shutdown(); return 0; }\r
+\r
+ // mode == LETTERBOX is invalid if the TV is widescreen\r
+ if (tvsize == ASPECT16X9) setMode(NORMAL);\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::setDefaultAspect()\r
+{\r
+ return setAspectRatio(tvsize);\r
+}\r
+\r
+int VideoMVP::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ initted = 0;\r
+ close(fdVideo);\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::checkSCART()\r
+{\r
+ // Returns 3 for SCART Composite out\r
+ // Returns 3 for SCART S-Video out\r
+ // Returns 2 for SCART RGB out\r
+ // Returns 3 for SCART not plugged in\r
+\r
+ // So, as you can have RGB and composite out simultaneously,\r
+ // and it can't detect S-Video, what is the point of this?\r
+\r
+ int scart;\r
+ if (ioctl(fdVideo, AV_CHK_SCART, &scart) != 0) return -10;\r
+\r
+ return scart;\r
+}\r
+\r
+int VideoMVP::setFormat(UCHAR tformat)\r
+{\r
+ if (!initted) return 0;\r
+ if ((tformat != PAL) && (tformat != NTSC)) return 0;\r
+ format = tformat;\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_DISP_FMT, format) != 0) return 0;\r
+\r
+ if (format == NTSC)\r
+ {\r
+ screenWidth = 720;\r
+ screenHeight = 480;\r
+ }\r
+ if (format == PAL)\r
+ {\r
+ screenWidth = 720;\r
+ screenHeight = 576;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::setConnection(UCHAR tconnection)\r
+{\r
+ if (!initted) return 0;\r
+ if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;\r
+ connection = tconnection;\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_OUTPUT, connection) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::setAspectRatio(UCHAR taspectRatio)\r
+{\r
+ if (!initted) return 0;\r
+ if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;\r
+ aspectRatio = taspectRatio;\r
+\r
+ Log::getInstance()->log("Video", Log::DEBUG, "Setting aspect to %i", aspectRatio);\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_RATIO, aspectRatio) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::setMode(UCHAR tmode)\r
+{\r
+ if (!initted) return 0;\r
+\r
+ if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode\r
+\r
+ if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)\r
+ && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;\r
+ mode = tmode;\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_MODE, mode) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::signalOff()\r
+{\r
+ if (ioctl(fdVideo, AV_SET_VID_DENC, 0) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::signalOn()\r
+{\r
+ if (ioctl(fdVideo, AV_SET_VID_DENC, 1) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::setSource()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ // What does this do...\r
+ if (ioctl(fdVideo, AV_SET_VID_SRC, 1) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::setPosition(int x, int y)\r
+{\r
+ if (!initted) return 0;\r
+\r
+// vid_pos_regs_t pos_d;\r
+// pos_d.x = x;\r
+// pos_d.y = y;\r
+\r
+ vid_pos_regs_t pos_d;\r
+\r
+ memset(&pos_d, 0, sizeof(pos_d));\r
+\r
+ pos_d.dest.y = y;\r
+ pos_d.dest.x = x;\r
+/*\r
+typedef struct {\r
+ int w;\r
+ int h;\r
+ int scale;\r
+ int x1;\r
+ int y;\r
+ int x;\r
+ int y2;\r
+ int x3;\r
+ int y3;\r
+ int x4;\r
+ int y4;\r
+} vid_pos_regs_t;\r
+*/\r
+\r
+/*\r
+ pos_d.w = 100;\r
+ pos_d.h = 30;\r
+ pos_d.scale = 2;\r
+ pos_d.x1 = 0;\r
+ pos_d.y = 100; // Top left X\r
+ pos_d.x = 50; // Top left Y\r
+ pos_d.y2 = 30;\r
+ pos_d.x3 = 60;\r
+ pos_d.y3 = 90;\r
+ pos_d.x4 = 120;\r
+ pos_d.y4 = 150;\r
+*/\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_POSITION, &pos_d) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::sync()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_SYNC, 2) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::play()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::stop()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_STOP, 0) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::reset()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::pause()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_PAUSE, 0) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::unPause() // FIXME get rid - same as play!!\r
+{\r
+ if (!initted) return 0;\r
+ if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::fastForward()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_FFWD, 1) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::unFastForward()\r
+{\r
+ if (!initted) return 0;\r
+\r
+// if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0; // don't need this.\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::attachFrameBuffer()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoMVP::blank(void)\r
+{\r
+ if (ioctl(fdVideo, AV_SET_VID_FB, 1) != 0) return 0;\r
+ if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0;\r
+ return 1;\r
+}\r
+\r
+ULLONG VideoMVP::getCurrentTimestamp()\r
+{\r
+ sync_data_t timestamps;\r
+ if (ioctl(fdVideo, AV_GET_VID_TIMESTAMPS, ×tamps) == 0)\r
+ {\r
+ // FIXME are these the right way around?\r
+\r
+ timestamps.stc = (timestamps.stc >> 31 ) | (timestamps.stc & 1);\r
+ timestamps.pts = (timestamps.pts >> 31 ) | (timestamps.pts & 1);\r
+\r
+ return timestamps.stc;\r
+ }\r
+ else\r
+ {\r
+ return 0;\r
+ }\r
+}\r
+\r
+ULONG VideoMVP::timecodeToFrameNumber(ULLONG timecode)\r
+{\r
+ if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);\r
+ else return (ULONG)(((double)timecode / (double)90000) * (double)30);\r
+}\r
+\r
+#ifdef DEV\r
+int VideoMVP::test()\r
+{\r
+ return 0;\r
+\r
+// ULLONG stc = 0;\r
+// return ioctl(fdVideo, AV_SET_VID_STC, &stc);\r
+/*\r
+ // reset();\r
+ return 1;\r
+*/\r
+}\r
+\r
+int VideoMVP::test2()\r
+{\r
+ return 0;\r
+}\r
+#endif\r
+\r
+void VideoMVP::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)\r
+{\r
+ MediaPacketList::const_iterator iter = mplist.begin();\r
+ deliver_start = iter->pos_buffer + samplepos;\r
+ mediapacket_len[0] = deliver_length = iter->length;\r
+ deliver_count = 1;\r
+ while (++iter != mplist.end() &&\r
+ iter->pos_buffer == deliver_start + deliver_length)\r
+ {\r
+ deliver_length += iter->length;\r
+ mediapacket_len[deliver_count] = iter->length;\r
+ ++deliver_count;\r
+ if (deliver_length >= WRITE_LENGTH ||\r
+ deliver_count == WRITE_PACKETS) break;\r
+ }\r
+}\r
+\r
+UINT VideoMVP::DeliverMediaSample(UCHAR* buffer, UINT* samplepos)\r
+{\r
+ int written = ::write(fdVideo, buffer + deliver_start, deliver_length);\r
+ if (written == (int)deliver_length) { *samplepos = 0; return deliver_count;}\r
+ if (written <= 0) return 0;\r
+ // Handle a partial write. Is this possible? Should we bother?\r
+ UINT i = 0;\r
+ while ((written -= mediapacket_len[i]) >= 0) i++;\r
+ *samplepos = mediapacket_len[i] + written;\r
+ return i;\r
+}\r
+\r
+void VideoMVP::ResetTimeOffsets()\r
+{\r
+}\r
+\r
+bool VideoMVP::displayIFrame(const UCHAR* buffer, UINT length)\r
+{\r
+ write(fdVideo, buffer, length);\r
+ return true;\r
+}\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-// Thanks to Jon Gettler and BtB of the MVPMC project for all the hardware information
-
-
-#ifndef VIDEOMVP_H
-#define VIDEOMVP_H
-
-// FIXME - check why so many things include unistd
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <string.h>
-
-#include <stdint.h>
-
-#include "defines.h"
-#include "video.h"
-
-typedef struct
-{
- int nleft;
- int state;
-} vid_state_regs_t;
-
-typedef struct
-{
- uint64_t stc;
- uint64_t pts;
-} sync_data_t;
-
-typedef struct
-{
- int y;
- int x;
- int w;
- int h;
-} vid_rect_t;
-
-typedef struct
-{
- vid_rect_t src;
- vid_rect_t dest;
-} vid_pos_regs_t;
-
-struct vid_regs
-{
- UCHAR dummy[44];
-};
-
-#define AV_SET_VID_STOP _IOW('v', 21, int)
-#define AV_SET_VID_PLAY _IOW('v', 22, int)
-#define AV_SET_VID_FREEZE _IOW('v', 23, int)
-#define AV_SET_VID_RESUME _IOW('v', 24, int)
-#define AV_SET_VID_SRC _IOW('v', 25, int)
-#define AV_SET_VID_FB _IOW('v', 26, int)
-#define AV_GET_VID_STATE _IOR('v', 27, vid_state_regs_t*)
-#define AV_SET_VID_PAUSE _IOW('v', 28, int)
-#define AV_SET_VID_FFWD _IOW('v', 29, int)
-#define AV_SET_VID_SLOMO _IOW('v', 30, int)
-#define AV_SET_VID_BLANK _IOW('v', 32, int)
-#define AV_SET_VID_POSITION _IOW('v', 36, vid_pos_regs_t*)
-#define AV_SET_VID_SCALE_ON _IOW('v', 37, int)
-#define AV_SET_VID_SCALE_OFF _IOW('v', 38, int)
-#define AV_GET_VID_TIMESTAMPS _IOR('v', 39, sync_data_t*)
-#define AV_SET_VID_STC _IOW('v', 40, uint64_t*)
-#define AV_SET_VID_RATIO _IOW('v', 41, int)
-#define AV_SET_VID_SYNC _IOW('v', 42, int)
-#define AV_SET_VID_DISABLE_SYNC _IOW('v', 43, int)
-#define AV_SET_VID_DISP_FMT _IOW('v', 45, int)
-#define AV_SET_VID_RESET _IOW('v', 51, int)
-#define AV_SET_VID_OUTPUT _IOW('v', 57, int)
-#define AV_SET_VID_MODE _IOW('v', 58, int)
-#define AV_GET_VID_REGS _IOR('v', 61, struct vid_regs*)
-#define AV_SET_VID_COLORBAR _IOW('v', 62, int)
-#define AV_SET_VID_DENC _IOW('v', 63, int)
-#define AV_CHK_SCART _IOW('v', 64, int)
-
-#define WRITE_LENGTH (32*1024) // Consume up to 32K at a time from Stream
-#define WRITE_PACKETS 16 // But no more than 16 packets
-
-class VideoMVP : public Video
-{
- public:
- VideoMVP();
- ~VideoMVP();
-
- int init(UCHAR format);
- int shutdown();
-
- int setFormat(UCHAR format);
- int setConnection(UCHAR connection);
- int setAspectRatio(UCHAR aspectRatio); // This one does the pin 8 scart widescreen switching
- int setMode(UCHAR mode);
- int setTVsize(UCHAR size); // Is the TV a widescreen?
- int setDefaultAspect();
- int setSource();
- int setPosition(int x, int y);
- int sync();
- int play();
- int stop();
- int pause();
- int unPause();
- int fastForward();
- int unFastForward();
- int reset();
- int blank();
- int signalOn();
- int signalOff();
- int attachFrameBuffer(); // What does this do?
- ULONG timecodeToFrameNumber(ULLONG timecode);
- ULLONG getCurrentTimestamp();
- void displayIFrame(const UCHAR* buffer, UINT length);
-
- // Writing Data to Videodevice
- virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);
- virtual UINT DeliverMediaSample( UCHAR* buffer, UINT* samplepos);
- virtual long long SetStartOffset(long long curreftime, bool *rsync)
- { return 0; };
- virtual void ResetTimeOffsets();
-
-#ifdef DEV
- int test();
- int test2();
-#endif
-
- private:
- int checkSCART();
- void setLetterboxBorder(char* border);
-
- UINT deliver_start, deliver_length, deliver_count;
- UINT mediapacket_len[WRITE_PACKETS];
-};
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+// Thanks to Jon Gettler and BtB of the MVPMC project for all the hardware information\r
+\r
+\r
+#ifndef VIDEOMVP_H\r
+#define VIDEOMVP_H\r
+\r
+// FIXME - check why so many things include unistd\r
+\r
+#include <stdio.h>\r
+#include <unistd.h>\r
+#include <fcntl.h>\r
+#include <sys/ioctl.h>\r
+#include <string.h>\r
+\r
+#include <stdint.h>\r
+\r
+#include "defines.h"\r
+#include "video.h"\r
+\r
+typedef struct\r
+{\r
+ int nleft;\r
+ int state;\r
+} vid_state_regs_t;\r
+\r
+typedef struct\r
+{\r
+ uint64_t stc;\r
+ uint64_t pts;\r
+} sync_data_t;\r
+\r
+typedef struct\r
+{\r
+ int y;\r
+ int x;\r
+ int w;\r
+ int h;\r
+} vid_rect_t;\r
+\r
+typedef struct\r
+{\r
+ vid_rect_t src;\r
+ vid_rect_t dest;\r
+} vid_pos_regs_t;\r
+\r
+struct vid_regs\r
+{\r
+ UCHAR dummy[44];\r
+};\r
+\r
+#define AV_SET_VID_STOP _IOW('v', 21, int)\r
+#define AV_SET_VID_PLAY _IOW('v', 22, int)\r
+#define AV_SET_VID_FREEZE _IOW('v', 23, int)\r
+#define AV_SET_VID_RESUME _IOW('v', 24, int)\r
+#define AV_SET_VID_SRC _IOW('v', 25, int)\r
+#define AV_SET_VID_FB _IOW('v', 26, int)\r
+#define AV_GET_VID_STATE _IOR('v', 27, vid_state_regs_t*)\r
+#define AV_SET_VID_PAUSE _IOW('v', 28, int)\r
+#define AV_SET_VID_FFWD _IOW('v', 29, int)\r
+#define AV_SET_VID_SLOMO _IOW('v', 30, int)\r
+#define AV_SET_VID_BLANK _IOW('v', 32, int)\r
+#define AV_SET_VID_POSITION _IOW('v', 36, vid_pos_regs_t*)\r
+#define AV_SET_VID_SCALE_ON _IOW('v', 37, int)\r
+#define AV_SET_VID_SCALE_OFF _IOW('v', 38, int)\r
+#define AV_GET_VID_TIMESTAMPS _IOR('v', 39, sync_data_t*)\r
+#define AV_SET_VID_STC _IOW('v', 40, uint64_t*)\r
+#define AV_SET_VID_RATIO _IOW('v', 41, int)\r
+#define AV_SET_VID_SYNC _IOW('v', 42, int)\r
+#define AV_SET_VID_DISABLE_SYNC _IOW('v', 43, int)\r
+#define AV_SET_VID_DISP_FMT _IOW('v', 45, int)\r
+#define AV_SET_VID_RESET _IOW('v', 51, int)\r
+#define AV_SET_VID_OUTPUT _IOW('v', 57, int)\r
+#define AV_SET_VID_MODE _IOW('v', 58, int)\r
+#define AV_GET_VID_REGS _IOR('v', 61, struct vid_regs*)\r
+#define AV_SET_VID_COLORBAR _IOW('v', 62, int)\r
+#define AV_SET_VID_DENC _IOW('v', 63, int)\r
+#define AV_CHK_SCART _IOW('v', 64, int)\r
+\r
+#define WRITE_LENGTH (32*1024) // Consume up to 32K at a time from Stream\r
+#define WRITE_PACKETS 16 // But no more than 16 packets\r
+\r
+class VideoMVP : public Video\r
+{\r
+ public:\r
+ VideoMVP();\r
+ ~VideoMVP();\r
+\r
+ int init(UCHAR format);\r
+ int shutdown();\r
+\r
+ int setFormat(UCHAR format);\r
+ int setConnection(UCHAR connection);\r
+ int setAspectRatio(UCHAR aspectRatio); // This one does the pin 8 scart widescreen switching\r
+ int setMode(UCHAR mode);\r
+ int setTVsize(UCHAR size); // Is the TV a widescreen?\r
+ int setDefaultAspect();\r
+ int setSource();\r
+ int setPosition(int x, int y);\r
+ int sync();\r
+ int play();\r
+ int stop();\r
+ int pause();\r
+ int unPause();\r
+ int fastForward();\r
+ int unFastForward();\r
+ int reset();\r
+ int blank();\r
+ int signalOn();\r
+ int signalOff();\r
+ int attachFrameBuffer(); // What does this do?\r
+ ULONG timecodeToFrameNumber(ULLONG timecode);\r
+ ULLONG getCurrentTimestamp();\r
+ bool displayIFrame(const UCHAR* buffer, UINT length);\r
+\r
+ // Writing Data to Videodevice\r
+ virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);\r
+ virtual UINT DeliverMediaSample( UCHAR* buffer, UINT* samplepos);\r
+ virtual long long SetStartOffset(long long curreftime, bool *rsync)\r
+ { return 0; };\r
+ virtual void ResetTimeOffsets();\r
+\r
+#ifdef DEV\r
+ int test();\r
+ int test2();\r
+#endif\r
+\r
+ private:\r
+ int checkSCART();\r
+ void setLetterboxBorder(char* border);\r
+\r
+ UINT deliver_start, deliver_length, deliver_count;\r
+ UINT mediapacket_len[WRITE_PACKETS];\r
+};\r
+\r
+#endif\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-
-
-#include "videowin.h"
-#include "log.h"
-#include "dssourcefilter.h"
-#include "dsallocator.h"
-#include "vdr.h"
-#include "osdwin.h"
-#include "audiowin.h"
-#include "wwinvideofilter.h"
-#include "wwinvideoh264filter.h"
-#include "wtabbar.h"
-#include "woptionpane.h"
-#include "i18n.h"
-#include "demuxer.h"
-
-#include <Mfapi.h>
-#include <mferror.h>
-
-void AdjustWindow();
-
-
-
-VideoWin::VideoWin()
-{
- dsinited=false;
- dsgraphbuilder=NULL;
- dsmediacontrol=NULL;
- dsrenderer=NULL;
- dsrefclock=NULL;
- dsmediafilter=NULL;
- dsbasicaudio=NULL;
- sourcefilter=NULL;
- allocatorvmr=NULL;
- cr_time=0;
- lastaudiomode=MPTYPE_MPEG_AUDIO;
- //lastaudiomode=MPTYPE_AC3;
- dsvmrsurfnotify=NULL;
- filtermutex=CreateMutex(NULL,FALSE,NULL);
- offsetnotset=true;
- offsetvideonotset=true;
- offsetaudionotset=true;
- startoffset=0;
- lastrefaudiotime=0;
- lastrefvideotime=0;
- lastreftimeRT=0;
- lastreftimePTS=0;
- firstsynched=false;
- cur_audio_media_sample=NULL;
- cur_video_media_sample=NULL;
- videoon=true;
- audioon=true;
- audiovolume=0;
- pseudotvsize=0;
- videoposx=0;
- videoposy=0;
- aud_type=Audio::MPEG2_PES;
- iframemode=false;//We are not in Iframe mode at begining
- vmrdeinterlacing=2;//Best
- videofilterselected=-1;
- videoH264filterselected=-1;
- OSVERSIONINFO verinfo;
- verinfo.dwOSVersionInfoSize=sizeof(verinfo);
- GetVersionEx(&verinfo);
-
- if (verinfo.dwMajorVersion>=6) {
- currentpresenter=EVR;
- } else {
- currentpresenter=VMR9;
- }
- videoH264dtsfix=false;
- videompeg2dtsfix=false;
-
-
-
-
-}
-
-VideoWin::~VideoWin()
-{
- CleanupDS();
- CloseHandle(filtermutex);
- unsigned int i;
- for (i=0;i<videofilterlist.size();i++)
- {
- if (videofilterlist[i].displayname) delete [] videofilterlist[i].displayname;
- if (videofilterlist[i].friendlyname) delete [] videofilterlist[i].friendlyname;
- }
- videofilterlist.clear();
-
- for (i=0;i<videoH264filterlist.size();i++)
- {
- if (videoH264filterlist[i].displayname) delete [] videoH264filterlist[i].displayname;
- if (videoH264filterlist[i].friendlyname) delete [] videoH264filterlist[i].friendlyname;
- }
- videoH264filterlist.clear();
-
-
-
-
- instance = NULL;
-}
-
-int VideoWin::init(UCHAR tformat)
-{
- if (initted) return 0;
-
- initted = 1;
- tvsize=Video::ASPECT16X9; //Internally Vomp should think we are a 16:9 TV
- videoposx=0;
- videoposy=0;
- initFilterDatabase();
- initH264FilterDatabase();
-
- if (!setFormat(tformat)){ shutdown(); return 0; }
- return 1;
-}
-
-
-
-int VideoWin::setTVsize(UCHAR ttvsize)
-{
- pseudotvsize=ttvsize;
- return 1;
-}
-
-int VideoWin::setDefaultAspect()
-{
- return setAspectRatio(Video::ASPECT4X3);
-}
-
-int VideoWin::shutdown()
-{
- if (!initted) return 0;
- initted = 0;
- return 1;
-}
-
-int VideoWin::setFormat(UCHAR tformat)
-{
- if (!initted) return 0;
- if ((tformat != PAL) && (tformat != NTSC)) return 0;
- format = tformat;
- if (format == NTSC)
- {
- screenWidth = 720;
- screenHeight = 480;
- }
- if (format == PAL)
- {
- screenWidth = 720;
- screenHeight = 576;
- }
-
- return 1;
-}
-
-int VideoWin::setConnection(UCHAR tconnection)
-{
- if (!initted) return 0;
- if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;
- connection = tconnection;
-
- return 1;
-}
-
-int VideoWin::setAspectRatio(UCHAR taspectRatio)
-{
- if (!initted) return 0;
- if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;
- aspectRatio = taspectRatio;
- AdjustWindow();
- return 1;
-}
-
-int VideoWin::setMode(UCHAR tmode)
-{
- if (!initted) return 0;
-
- //if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode
-
- if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)
- && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;
- mode = tmode;
- videoposx=0;
- videoposy=0;
- AdjustWindow();
-
- return 1;
-}
-
-int VideoWin::signalOff()
-{
- return 1;
-}
-
-int VideoWin::signalOn()
-{
- return 1;
-}
-
-int VideoWin::setSource()
-{
- if (!initted) return 0;
-
- return 1;
-}
-
-int VideoWin::setPosition(int x, int y)
-{
- if (!initted) return 0;
- if (mode==QUARTER || mode==EIGHTH) {
- videoposx=x;
- videoposy=y;
- }
- return 1;
-}
-
-int VideoWin::sync()
-{
- if (!initted) return 0;
-
- return 1;
-}
-void VideoWin::initFilterDatabase()
-{
- /* This method should determine all availiable DirectShow Filters */
- IFilterMapper2* filtmap=NULL;
- HRESULT result;
- result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
- IID_IFilterMapper2,(void**)&filtmap);
- if (result != S_OK)
- {
- Log::getInstance()->log("VideoWin", Log::ERR , "Unable to create FilterMapper!");
- return;
- }
- /* Wishlist, what Mediatypes do we want */
- GUID mtypesin[]={MEDIATYPE_Video,MEDIASUBTYPE_MPEG2_VIDEO};
- IEnumMoniker *myenum;
- result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
- TRUE,1,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
- if (result != S_OK)
- {
- filtmap->Release();
- Log::getInstance()->log("VideoWin", Log::ERR , "Unable to enum Filters!");
- return;
- }
- ULONG gethowmany;
- IMoniker * moni;
- while(myenum->Next(1,&moni,&gethowmany)==S_OK)
- {
- VideoFilterDesc desc;
- ZeroMemory(&desc,sizeof(desc));
-
- LPOLESTR string;
- moni->GetDisplayName(0,0,&string);
- desc.displayname=new char[wcslen(string)+1];
- wcstombs(desc.displayname,string,wcslen(string)+1);
- CoTaskMemFree(string);
- IPropertyBag *bag;
- if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
- {
- VARIANT vari;
- VariantInit(&vari);
- result = bag->Read(L"FriendlyName",&vari,NULL);
- if (result == S_OK)
- {
- desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
- wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
- }
- VariantClear(&vari);
- bag->Release();
-
- }
-
-
- videofilterlist.push_back(desc);
-
-
-
- moni->Release();
- // bctx->Release();
- }
- int i;
- videofilterselected=-1;
-
-
-
- myenum->Release();
-
-
-
- filtmap->Release();
-}
-
-void VideoWin::initH264FilterDatabase()
-{
- /* This method should determine all availiable DirectShow Filters */
- IFilterMapper2* filtmap=NULL;
- HRESULT result;
- result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
- IID_IFilterMapper2,(void**)&filtmap);
- if (result != S_OK)
- {
- Log::getInstance()->log("VideoWin", Log::ERR , "Unable to create FilterMapper!");
- return;
- }
- /* Wishlist, what Mediatypes do we want */
- GUID mtypesin[]={MEDIATYPE_Video,MEDIASUBTYPE_H264};
- IEnumMoniker *myenum;
- result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
- TRUE,1,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
- if (result != S_OK)
- {
- filtmap->Release();
- Log::getInstance()->log("VideoWin", Log::ERR , "Unable to enum Filters!");
- return;
- }
- ULONG gethowmany;
- IMoniker * moni;
- while(myenum->Next(1,&moni,&gethowmany)==S_OK)
- {
- VideoFilterDesc desc;
- ZeroMemory(&desc,sizeof(desc));
-
- LPOLESTR string;
- moni->GetDisplayName(0,0,&string);
- desc.displayname=new char[wcslen(string)+1];
- wcstombs(desc.displayname,string,wcslen(string)+1);
- CoTaskMemFree(string);
- IPropertyBag *bag;
- if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
- {
- VARIANT vari;
- VariantInit(&vari);
- result = bag->Read(L"FriendlyName",&vari,NULL);
- if (result == S_OK)
- {
- desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
- wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
- }
- VariantClear(&vari);
- bag->Release();
-
- }
-
-
- videoH264filterlist.push_back(desc);
-
-
-
- moni->Release();
- // bctx->Release();
- }
- int i;
- videoH264filterselected=-1;
-
-
-
- myenum->Release();
-
-
-
- filtmap->Release();
-}
-
-bool VideoWin::loadOptionsfromServer(VDR* vdr)
-{
- char *name=vdr->configLoad("DirectShow","VideoFilter");
-
- if (name != NULL)
- {
- for (int i = 0;i <videofilterlist.size();i++)
- {
- if (strcmp(name,videofilterlist[i].displayname)==0)
- {
- videofilterselected = i;
- break;
- }
- }
- }
- name=vdr->configLoad("DirectShow","VideoH264Filter");
-
- if (name != NULL)
- {
- for (int i = 0;i <videoH264filterlist.size();i++)
- {
- if (strcmp(name,videoH264filterlist[i].displayname)==0)
- {
- videoH264filterselected = i;
- break;
- }
- }
- }
- name=vdr->configLoad("DirectShow","VMR9DeinterlacingMode");
- if (name != NULL)
- {
- if (STRCASECMP(name,"NoMix")==0) {
- vmrdeinterlacing=0;
- } else if (STRCASECMP(name,"None")==0) {
- vmrdeinterlacing=1;
- } else if (STRCASECMP(name,"Best")==0) {
- vmrdeinterlacing=2;
- } else if (STRCASECMP(name,"Bob")==0) {
- vmrdeinterlacing=3;
- } else if (STRCASECMP(name,"Weave")==0) {
- vmrdeinterlacing=4;
- }
- }
-
- name=vdr->configLoad("DirectShow", "VideoPresenter");
- if (name!=NULL) {
- if (STRCASECMP(name,"VMR9")==0) {
- currentpresenter=VMR9;
- } else if (STRCASECMP(name,"EVR")==0) {
- currentpresenter=EVR;
- }
- }
- if (!((OsdWin*)Osd::getInstance())->IsEvrSupported()) {
- currentpresenter=VMR9;
- }
-
- name=vdr->configLoad("DirectShow","videoH264dtsfix");
- if (name!=NULL) {
- if (STRCASECMP(name,"YES")==0) {
- videoH264dtsfix=true;
- } else {
- videoH264dtsfix=false;
- }
- }
- name=vdr->configLoad("DirectShow","videompeg2dtsfix");
- if (name!=NULL) {
- if (STRCASECMP(name,"YES")==0) {
- videompeg2dtsfix=true;
- } else {
- videompeg2dtsfix=false;
- }
- }
-
- name=vdr->configLoad("DirectGraphics", "StretchFiltering");
- if (name!=NULL) {
- if (STRCASECMP(name,"None")==0) {
- ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_NONE);
- } else if (STRCASECMP(name,"Point")==0) {
- ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_POINT);
- } else if (STRCASECMP(name,"Linear")==0) {
- ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_LINEAR);
- }
- }
-
-
-
-
- return true;
-
-}
-
-bool VideoWin::handleOptionChanges(Option* option)
-{
- if( Video::handleOptionChanges(option)) return true;
- switch(option->id) {
- case 1: {
- if (STRCASECMP(option->options[option->userSetChoice],"None")==0) {
- ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_NONE);
- } else if (STRCASECMP(option->options[option->userSetChoice],"Point")==0) {
- ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_POINT);
- } else if (STRCASECMP(option->options[option->userSetChoice],"Linear")==0) {
- ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_LINEAR);
- }
- return true;
- } break;
- case 2: {
- if (STRCASECMP(option->options[option->userSetChoice],"NoMix")==0) {
- vmrdeinterlacing=0;
- } else if (STRCASECMP(option->options[option->userSetChoice],"None")==0) {
- vmrdeinterlacing=1;
- } else if (STRCASECMP(option->options[option->userSetChoice],"Best")==0) {
- vmrdeinterlacing=2;
- } else if (STRCASECMP(option->options[option->userSetChoice],"Bob")==0) {
- vmrdeinterlacing=3;
- } else if (STRCASECMP(option->options[option->userSetChoice],"Weave")==0) {
- vmrdeinterlacing=4;
- }
- }break;
- case 3: {
- if (STRCASECMP(option->options[option->userSetChoice],"VMR9")==0) {
- currentpresenter=VMR9;
- } else if (STRCASECMP(option->options[option->userSetChoice],"EVR")==0) {
- currentpresenter=EVR;
- }
- }break;
- case 4: {
- if (STRCASECMP(option->options[option->userSetChoice],"Yes")==0) {
- videoH264dtsfix=true;
- } else {
- videoH264dtsfix=false;
- }
- }break;
- case 5: {
- if (STRCASECMP(option->options[option->userSetChoice],"Yes")==0) {
- videompeg2dtsfix=true;
- } else {
- videompeg2dtsfix=false;
- }
- }break;
- };
- return false;
-
-}
-
-bool VideoWin::saveOptionstoServer()
-{
- if (videofilterselected!=-1) {
- VDR::getInstance()->configSave("DirectShow",
- "VideoFilter",videofilterlist[videofilterselected].displayname);
- VDR::getInstance()->configSave("DirectShow",
- "VideoH264Filter",videoH264filterlist[videoH264filterselected].displayname);
- }
- return true;
-}
-
-/*Option(UINT id, const char* displayText, const char* configSection, const char* configKey, UINT optionType,
- UINT numChoices, UINT defaultChoice, UINT startInt,
- const char * const * options, const char * const * optionkeys = NULL, AbstractOption* handler=NULL);*/
-
-bool VideoWin::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane)
-{
- if (!Video::addOptionsToPanes(panenumber,options,pane)) return false;
-
-
- Option* option;
- if (panenumber == 2)
- {
- DWORD scalingcaps=((OsdWin*)Osd::getInstance())->getFilterCaps();
- char **scalingopts=new char *[3];
- int i=0;
- scalingopts[i]=new char[strlen("None")+1];
- strcpy(scalingopts[i],"None");
- i++;
- if ((scalingcaps & D3DPTFILTERCAPS_MINFPOINT)!=0
- && (scalingcaps & D3DPTFILTERCAPS_MAGFPOINT)!=0) {
- scalingopts[i]=new char[strlen("Point")+1];
- strcpy(scalingopts[i],"Point");
- i++;
- }
- if ((scalingcaps & D3DPTFILTERCAPS_MINFLINEAR)!=0
- && (scalingcaps & D3DPTFILTERCAPS_MAGFLINEAR)!=0) {
- scalingopts[i]=new char[strlen("Linear")+1];
- strcpy(scalingopts[i],"Linear");
- i++;
- }
- option = new Option(1 ,tr("Video Stretching Filter"), "DirectGraphics", "StretchFiltering", Option::TYPE_TEXT, i, (i-1), 0, scalingopts,NULL,true, this);
- options->push_back(option);
- pane->addOptionLine(option);
- static const char* deintopts[]={"NoMix","None","Best","Bob","Weave"};
- option = new Option(2,tr("VMR9 Deinterlacing Mode"), "DirectShow","VMR9DeinterlacingMode",Option::TYPE_TEXT,5,2,0,deintopts,NULL,false,this);
- options->push_back(option);
- pane->addOptionLine(option);
-
- if (((OsdWin*)Osd::getInstance())->IsEvrSupported())
- {
- static const char* presenteropts[]={"EVR","VMR9"};
- option = new Option(3,tr("Video Presenter Filter"),"DirectShow", "VideoPresenter",Option::TYPE_TEXT,2,
- (currentpresenter==EVR)?0:1,0,presenteropts,NULL,false,this);
- } else {
- static const char* presenteropts[]={"VMR9"};
- option = new Option(3,tr("Video Presenter Filter"),"DirectShow", "VideoPresenter",Option::TYPE_TEXT,1,0,0,presenteropts,NULL,false,this);
- }
- options->push_back(option);
- pane->addOptionLine(option);
-
- static const char* yesnoopts[]={"Yes","No"};
- option = new Option(4,tr("Video H264 fix dts time"), "DirectShow","videoH264dtsfix",Option::TYPE_TEXT,2,1,0,yesnoopts,NULL,false,this);
- options->push_back(option);
- pane->addOptionLine(option);
-
- option = new Option(5,tr("Video Mpeg2 fix dts time"), "DirectShow","videompeg2dtsfix",Option::TYPE_TEXT,2,1,0,yesnoopts,NULL,false,this);
- options->push_back(option);
- pane->addOptionLine(option);
-
-
-
- }
-
- return true;
-}
-
-IBaseFilter *VideoWin::getVideoFilter()
-{
- IBaseFilter *curfilter= NULL;
- if (videofilterselected == -1)
- {
- int i;
- for (i = 0;i <videofilterlist.size();i++)
- {
-
- if (videofilterlist[i].vmr9tested == true)
- {
- if (videofilterlist[i].vmr9 == true)
- {
- videofilterselected = i;
- break;
- }
- else
- {
- continue;
- }
- }
- else
- {
- IMoniker * moni=NULL;
- IBindCtx *bindctx=NULL;
- if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
- LPCOLESTR name=(LPCOLESTR)new WCHAR[strlen(videofilterlist[i].displayname)+1];
- mbstowcs((wchar_t*)name,videofilterlist[i].displayname,strlen(videofilterlist[i].displayname)+1);
- ULONG eater=0;
-
-
- if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
- {
- if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
- {
- IAMDecoderCaps* desccaps=NULL;
- if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
- {
- DWORD caps;
- desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
- if (caps == DECODER_CAP_SUPPORTED)
- {
- videofilterlist[i].vmr9tested = true;
- videofilterlist[i].vmr9 = true;
- videofilterselected = i;
- }
- else
- {
- videofilterlist[i].vmr9tested = true;
- videofilterlist[i].vmr9 = false;
-
- curfilter->Release();
- curfilter=NULL;
- }
- }
- desccaps->Release();
- }
- moni->Release();
- }
- delete [] name;
- bindctx->Release();
- }
- if (videofilterlist[i].vmr9) break;
-
- }
- if (curfilter != NULL)
- {
- VDR *vdr=VDR::getInstance();
- if (vdr != NULL)
- {
- vdr->configSave("DirectShow","VideoFilter",
- videofilterlist[videofilterselected].displayname);
- }
- return curfilter;
- }
- }
- else
- {
- IBindCtx *bindctx=NULL;
- if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
- IMoniker * moni=NULL;
- LPCOLESTR name=new WCHAR[strlen(videofilterlist[videofilterselected].displayname)+1];
- mbstowcs((wchar_t*)name,videofilterlist[videofilterselected].displayname,
- strlen(videofilterlist[videofilterselected].displayname)+1);
- ULONG eater;
- if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
- {
- if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
- {
- IAMDecoderCaps* desccaps=NULL;
- if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
- {
- DWORD caps;
- desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
- if (caps == DECODER_CAP_SUPPORTED)
- {
- videofilterlist[videofilterselected].vmr9tested = true;
- videofilterlist[videofilterselected].vmr9 = true;
- }
- else
- {
- videofilterlist[videofilterselected].vmr9tested = true;
- videofilterlist[videofilterselected].vmr9 = false;
- Log::getInstance()->log("VideoWin", Log::WARN ,"Filter does not support VMR9, but is selected, manual selection!");
- }
- }
- moni->Release();
- delete [] name;
- bindctx->Release();
- return curfilter;
- }
- moni->Release();
- }
- bindctx->Release();
- delete [] name;
- return NULL;
- }
- return NULL;
-
-}
-
-IBaseFilter *VideoWin::getVideoH264Filter()
-{
- IBaseFilter *curfilter= NULL;
- if (videoH264filterselected == -1)
- {
- int i;
- for (i = 0;i <videoH264filterlist.size();i++)
- {
-
- if (videoH264filterlist[i].vmr9tested == true)
- {
- if (videoH264filterlist[i].vmr9 == true)
- {
- videoH264filterselected = i;
- break;
- }
- else
- {
- continue;
- }
- }
- else
- {
- IMoniker * moni=NULL;
- IBindCtx *bindctx=NULL;
- if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
- LPCOLESTR name=(LPCOLESTR)new WCHAR[strlen(videoH264filterlist[i].displayname)+1];
- mbstowcs((wchar_t*)name,videoH264filterlist[i].displayname,strlen(videoH264filterlist[i].displayname)+1);
- ULONG eater=0;
- Log::getInstance()->log("VideoWin", Log::DEBUG ,"Creating filter: %s",videoH264filterlist[i].friendlyname);
-
-
-
- if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
- {
- if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
- {
- IAMDecoderCaps* desccaps=NULL;
- if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
- {
- DWORD caps;
- desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
- if (caps == DECODER_CAP_SUPPORTED)
- {
- videoH264filterlist[i].vmr9tested = true;
- videoH264filterlist[i].vmr9 = true;
- videoH264filterselected = i;
- }
- else
- {
- videoH264filterlist[i].vmr9tested = true;
- videoH264filterlist[i].vmr9 = false;
-
- curfilter->Release();
- curfilter=NULL;
- }
- }
- desccaps->Release();
- }
- moni->Release();
- }
- delete [] name;
- bindctx->Release();
- }
- if (videoH264filterlist[i].vmr9) break;
-
- }
- if (curfilter != NULL)
- {
- VDR *vdr=VDR::getInstance();
- if (vdr != NULL)
- {
- vdr->configSave("DirectShow","VideoH264Filter",
- videoH264filterlist[videoH264filterselected].displayname);
- }
- return curfilter;
- }
- }
- else
- {
- IBindCtx *bindctx=NULL;
- if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
- IMoniker * moni=NULL;
- LPCOLESTR name=new WCHAR[strlen(videoH264filterlist[videoH264filterselected].displayname)+1];
- mbstowcs((wchar_t*)name,videoH264filterlist[videoH264filterselected].displayname,
- strlen(videoH264filterlist[videoH264filterselected].displayname)+1);
- ULONG eater;
- Log::getInstance()->log("VideoWin", Log::DEBUG ,"Creating filter: %s",videoH264filterlist[videoH264filterselected].friendlyname);
- if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
- {
- if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
- {
- IAMDecoderCaps* desccaps=NULL;
- if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
- {
- DWORD caps;
- desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
- if (caps == DECODER_CAP_SUPPORTED)
- {
- videoH264filterlist[videoH264filterselected].vmr9tested = true;
- videoH264filterlist[videoH264filterselected].vmr9 = true;
- }
- else
- {
- videoH264filterlist[videoH264filterselected].vmr9tested = true;
- videoH264filterlist[videoH264filterselected].vmr9 = false;
- Log::getInstance()->log("VideoWin", Log::WARN ,"Filter does not support VMR9, but is selected, manual selection!");
- }
- }
- moni->Release();
- delete [] name;
- bindctx->Release();
- return curfilter;
- }
- moni->Release();
- }
- bindctx->Release();
- delete [] name;
- return NULL;
- }
- return NULL;
-
-}
-
-
-#ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions
-#include "dshelper.h"
-#endif
-
-#define DO_VIDEO
-
-int VideoWin::play()
-{
- if (!initted) return 0;
- return 1;
-}
-
-bool VideoWin::addOptionPagesToWTB(WTabBar *wtb)
-{
- Boxx *box=new WWinVideoFilter();
- wtb->addTab(tr("Video Filter"), box);
- box=new WWinVideoH264Filter();
- wtb->addTab(tr("H264 Filter"), box);
- return true;
-}
-
-const VideoFilterDescList *VideoWin::getVideoFilterList(int &selected)
-{
- selected=videofilterselected;
- return &videofilterlist;
-}
-
-const VideoFilterDescList *VideoWin::getVideoH264FilterList(int &selected)
-{
- selected=videoH264filterselected;
- return &videoH264filterlist;
-}
-
-bool VideoWin::selectVideoFilter(int filter)
-{
- IBindCtx *bindctx=NULL;
- if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
- IMoniker * moni=NULL;
- LPCOLESTR name=new WCHAR[strlen(videofilterlist[filter].displayname)+1];
- mbstowcs((wchar_t*)name,videofilterlist[filter].displayname,
- strlen(videofilterlist[filter].displayname)+1);
- ULONG eater;
- bool success=false;
- if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
- {
- IBaseFilter* curfilter=NULL;
- if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
- {
- IAMDecoderCaps* desccaps=NULL;
- if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
- {
- DWORD caps;
- HRESULT hres=desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
- if (caps == DECODER_CAP_SUPPORTED)
- {
- videofilterlist[filter].vmr9tested = true;
- videofilterlist[filter].vmr9 = true;
- success=true;
- }
- else
- {
- videofilterlist[filter].vmr9tested = true;
- videofilterlist[filter].vmr9 = false;
- success=false;
- }
- desccaps->Release();
- } else {
- videofilterlist[filter].vmr9tested = true;
- videofilterlist[filter].vmr9 = false;
- success=false;
- }
-
- curfilter->Release();
-
- }
- moni->Release();
- }
- bindctx->Release();
- delete [] name;
- if (success || true)
- {
- videofilterselected=filter;
- return true;
- }
- else
- {
- return false;
- }
-}
-
-bool VideoWin::selectVideoH264Filter(int filter)
-{
- IBindCtx *bindctx=NULL;
- if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
- IMoniker * moni=NULL;
- LPCOLESTR name=new WCHAR[strlen(videoH264filterlist[filter].displayname)+1];
- mbstowcs((wchar_t*)name,videoH264filterlist[filter].displayname,
- strlen(videoH264filterlist[filter].displayname)+1);
- ULONG eater;
- bool success=false;
- if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
- {
- IBaseFilter* curfilter=NULL;
- if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
- {
- IAMDecoderCaps* desccaps=NULL;
- if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
- {
- DWORD caps;
- HRESULT hres=desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
- if (caps == DECODER_CAP_SUPPORTED)
- {
- videoH264filterlist[filter].vmr9tested = true;
- videoH264filterlist[filter].vmr9 = true;
- success=true;
- }
- else
- {
- videoH264filterlist[filter].vmr9tested = true;
- videoH264filterlist[filter].vmr9 = false;
- success=false;
- }
- desccaps->Release();
- } else {
- videoH264filterlist[filter].vmr9tested = true;
- videoH264filterlist[filter].vmr9 = false;
- success=false;
- }
-
- curfilter->Release();
-
- }
- moni->Release();
- }
- bindctx->Release();
- delete [] name;
- if (success || true)
- {
- videoH264filterselected=filter;
- return true;
- }
- else
- {
- return false;
- }
-}
-
-int VideoWin::dsInitVideoFilter()
-{
- #ifdef DO_VIDEO
- HRESULT hres;
- if (videoon) {
- //We alloc the vmr9 as next step
- if (currentpresenter==VMR9)
- {
- Log::getInstance()->log("VideoWin", Log::INFO ,"VMR9 Videopresenter selected!");
- if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0,
- CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsrenderer)!=S_OK)
- {
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!");
- ReleaseMutex(filtermutex);
- CleanupDS();
- }
- /*VMR 9 stuff**/
- if (hres=dsgraphbuilder->AddFilter(dsrenderer,L"VMR9")!=S_OK)
- {
- ReleaseMutex(filtermutex);
- CleanupDS();
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!");
- return 0;
- }
- IVMRFilterConfig9* vmrfilconfig;
- if (dsrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK)
- {
- ReleaseMutex(filtermutex);
- CleanupDS();
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!");
- return 0;
- }
- if (vmrdeinterlacing!=0) vmrfilconfig->SetNumberOfStreams(1);//Enter Mixing Mode
- vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless);
- vmrfilconfig->Release();
- if (dsrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,
- (void**)& dsvmrsurfnotify) != S_OK)
- {
- ReleaseMutex(filtermutex);
- CleanupDS();
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!");
- return 0;
- }
- allocatorvmr=new DsAllocator();
- dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr);
- allocatorvmr->AdviseNotify(dsvmrsurfnotify);
-
- IVMRDeinterlaceControl9* deintctrl;
- if (dsrenderer->QueryInterface(IID_IVMRDeinterlaceControl9,(void**)&deintctrl)!=S_OK)
- {
- ReleaseMutex(filtermutex);
- CleanupDS();
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Deinterlace control!");
- return 0;
- }
- /*turnoff*/
- switch (vmrdeinterlacing)
- {
- case 1: //No Deinterlasing
- deintctrl->SetDeinterlaceMode(0xFFFFFFFF,(LPGUID)&GUID_NULL);//Turn Off
- break;
- case 2: //Best
- deintctrl->SetDeinterlacePrefs(DeinterlacePref_NextBest);//Choose Next Best
- break;
- case 3: //Bob
- deintctrl->SetDeinterlacePrefs(DeinterlacePref_BOB);//Choose NBob
- break;
- case 4: //Weave
- deintctrl->SetDeinterlacePrefs(DeinterlacePref_Weave);//Choose Weave
- break;
- };
- deintctrl->Release();
- /*VMR 9 stuff end */
- }
- else if (currentpresenter==EVR)
- {
- Log::getInstance()->log("VideoWin", Log::INFO ,"EVR Videopresenter selected!");
- if (hres=CoCreateInstance(CLSID_EnhancedVideoRenderer,0,
- CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsrenderer)!=S_OK)
- {
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating EVR renderer!");
- ReleaseMutex(filtermutex);
- CleanupDS();
- }
- /*EVR stuff**/
- if (hres=dsgraphbuilder->AddFilter(dsrenderer,L"EVR")!=S_OK)
- {
- ReleaseMutex(filtermutex);
- CleanupDS();
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding EVR renderer!");
- return 0;
- }
-
-
- IMFGetService *evr_services;
- if (dsrenderer->QueryInterface(IID_IMFGetService,(void**)&evr_services)!=S_OK)
- {
- ReleaseMutex(filtermutex);
- CleanupDS();
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFGetServices interface!");
- return 0;
- }
-
- IMFVideoDisplayControl* mfvideodisplaycontrol;
- if (evr_services->GetService(MR_VIDEO_RENDER_SERVICE,IID_IMFVideoDisplayControl,(void**)&mfvideodisplaycontrol)!=S_OK)
- {
- ReleaseMutex(filtermutex);
- CleanupDS();
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFVideoDisplayControl interface!");
- return 0;
- }
-
- evr_services->Release();
- mfvideodisplaycontrol->SetVideoWindow(((OsdWin*) Osd::getInstance())->getWindow());
- //RECT client;
- //GetClientRect(((OsdWin*) Osd::getInstance())->getWindow(), &client);
- //mfvideodisplaycontrol->SetVideoPosition(NULL,&client);
-
- mfvideodisplaycontrol->Release();
-
-
- /// if (vmrdeinterlacing!=0) vmrfilconfig->SetNumberOfStreams(1);//Enter Mixing Mode //always the case for evr!
-
- IMFVideoRenderer *mfvideorenderer;
- if (dsrenderer->QueryInterface(IID_IMFVideoRenderer,(void**)&mfvideorenderer)!=S_OK)
- {
- ReleaseMutex(filtermutex);
- CleanupDS();
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFVideoRenderer interface!");
- return 0;
- }
-
- allocatorvmr=new DsAllocator();
- HRESULT hres=mfvideorenderer->InitializeRenderer(NULL,allocatorvmr);
-
- mfvideorenderer->Release();
- //How should I do this in EVR?
- /* IVMRDeinterlaceControl9* deintctrl;
- if (dsrenderer->QueryInterface(IID_IVMRDeinterlaceControl9,(void**)&deintctrl)!=S_OK)
- {
- ReleaseMutex(filtermutex);
- CleanupDS();
- Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Deinterlace control!");
- return 0;
- }
- /*turnoff*
- switch (vmrdeinterlacing)
- {
- case 1: //No Deinterlasing
- deintctrl->SetDeinterlaceMode(0xFFFFFFFF,(LPGUID)&GUID_NULL);//Turn Off
- break;
- case 2: //Best
- deintctrl->SetDeinterlacePrefs(DeinterlacePref_NextBest);//Choose Next Best
- break;
- case 3: //Bob
- deintctrl->SetDeinterlacePrefs(DeinterlacePref_BOB);//Choose NBob
- break;
- case 4: //Weave
- deintctrl->SetDeinterlacePrefs(DeinterlacePref_Weave);//Choose Weave
- break;
- };
- deintctrl->Release();*/
- /*EVR stuff end */
- } else {
- Log::getInstance()->log("VideoWin", Log::ERR ,"No videopresenter selected! Please post on the forum!");
- return -1;
- }
- IFilterGraph2*fg2=NULL;
- if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK)
- {
- Log::getInstance()->log("VideoWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
- ReleaseMutex(filtermutex);
- CleanupDS();
- return 0;
- }
-/*#ifndef NEW_DS_MECHANISMENS
-
- if (hres=fg2->RenderEx((IPin*)sourcefilter->GetVideoPin()/*video*,
- AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL) != S_OK)
- {
- Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering Video!");
- fg2->Release();
- ReleaseMutex(filtermutex);
- CleanupDS();
- return 0;
- }
-
-#else*/
- IBaseFilter*videofilter;
- if (h264)
- {
- Log::getInstance()->log("VideoWin", Log::DEBUG ,"Entering h264 playback...");
- videofilter=getVideoH264Filter();
- }
- else
- {
- Log::getInstance()->log("VideoWin", Log::DEBUG ,"Entering MPEG2 playback...");
- videofilter=getVideoFilter();
- }
- if (hres=dsgraphbuilder->AddFilter(videofilter,NULL) != S_OK)
- {
- Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Video Filter!");
- ReleaseMutex(filtermutex);
- CleanupDS();
- return 0;
- }
- IEnumPins *pinenum=NULL;
- bool error=false;
-
- mptype_video_detail vid_details;
- Demuxer* demux=Demuxer::getInstance();
- vid_details.width=demux->getHorizontalSize();
- vid_details.height=demux->getVerticalSize();
-
- if (h264)
- {
- if (vid_details.width!=0 && vid_details.height!=0)
- {
- sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_H264,&vid_details);
- }
- else
- {
- sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_H264,NULL);
- }
-
- }
- else
- {
- if (vid_details.width!=0 && vid_details.height!=0)
- {
- sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_MPEG2,&vid_details);
- }
- else
- {
- sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_MPEG2,NULL);
- }
- }
- if (videofilter->EnumPins(&pinenum) == S_OK)
- {
- IPin *current=NULL;
- ULONG fetch=0;
- bool firststep=false;
-
- while (pinenum->Next(1,¤t,&fetch)==S_OK)
- {
- PIN_DIRECTION dir;
- if (current->QueryDirection(&dir)==S_OK)
- {
- if (dir == PINDIR_INPUT)
- {
- if (sourcefilter->GetVideoPin()->Connect(current,NULL)==S_OK)
- {
- current->Release();
- firststep=true;
- break;
- }
- }
- }
- current->Release();
- }
- if (firststep==false)
- {
- Log::getInstance()->log("VideoWin", Log::WARN , "Video Filter has no suitable input!");
- videofilter->Release();
- ReleaseMutex(filtermutex);
- CleanupDS();
- return 0;
- }
- bool secondstep=false;
- pinenum->Reset();
- while (pinenum->Next(1,¤t,&fetch)==S_OK)
- {
- PIN_DIRECTION dir;
- if (current->QueryDirection(&dir)==S_OK)
- {
- if (dir == PINDIR_OUTPUT)
- {
-
- if (fg2->RenderEx((IPin*)current/*video*/,
- AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL) ==S_OK)
- {
- current->Release();
- secondstep=true;
- break;
- }
- }
- }
- current->Release();
- }
- if (secondstep==false)
- {
- Log::getInstance()->log("VideoWin", Log::WARN , "Video Filter has no suitable output!");
- videofilter->Release();
- ReleaseMutex(filtermutex);
- CleanupDS();
- return 0;
- }
-
- videofilter->Release();
- pinenum->Release();
-
- }
-
-
-
- fg2->Release();
- return 1;
- }
-#endif
- return 1;
-}
-
-int VideoWin::setAudioStreamType(UCHAR type)
-{
- aud_type=type;
- if (!initted) return 0;
- return 1;
-}
-
-int VideoWin::dsplay()
-{
- if (!initted) return 0;
- CleanupDS();
-
- //Build filter graph
- HRESULT hres;
- //So this is the real code, this prevents the feeder from calling noexisting objects!
- WaitForSingleObject(filtermutex,INFINITE);
- if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
- IID_IGraphBuilder,(void**)&dsgraphbuilder) != S_OK)
- {
- ReleaseMutex(filtermutex);
- return 0;
- }
- #ifdef DS_DEBUG
- AddToRot(dsgraphbuilder,&graphidentifier);
- #endif
-
- firstsynched=false;
- if (aud_type==Audio::MP3) {
- lastaudiomode=MPTYPE_MPEG_AUDIO_LAYER3;
- } else {
- lastaudiomode=MPTYPE_MPEG_AUDIO;
- }
- //lastaudiomode=MPTYPE_AC3;
- sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data
- // to DirectShow
- if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter") != S_OK)
- {
- Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");
- ReleaseMutex(filtermutex);
- CleanupDS();
- return 0;
- }
- sourcefilter->GetAudioPin()->SetPinMode(lastaudiomode);
- /*if (hres=dsgraphbuilder->Render((IPin*)sourcefilter->GetAudioPin()/*audio*)!=S_OK)
- {
- Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");
- ReleaseMutex(filtermutex);
- CleanupDS();
- return 0;
- }*/
- if (((AudioWin*)Audio::getInstance())->dsInitAudioFilter(dsgraphbuilder)==0)
- {
- Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");
- ReleaseMutex(filtermutex);
- CleanupDS();
- return 0;
- }
-
-
- if (dsInitVideoFilter()==0)
- {
- return 0;
- }
-
- if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,
- IID_IReferenceClock,(void**)&dsrefclock)!=S_OK)
- {
- return 0;
- }
- dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);
- HRESULT hresdeb = dsmediafilter->SetSyncSource(dsrefclock);
-
- dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);
- dsgraphbuilder->QueryInterface(IID_IBasicAudio,(void **) &dsbasicaudio);
- if (dsbasicaudio)
- dsbasicaudio->put_Volume(audiovolume);
- dsinited=true;
- //MILLISLEEP(100);
-
- hresdeb=dsmediacontrol->Run();
- iframemode=false;//exit iframe mode
- ReleaseMutex(filtermutex);
- return 1;
-}
-
-int VideoWin::EnterIframePlayback()
-{
- if (!initted) return 0;
- CleanupDS();
- //So this is the real code, this prevents the feeder from calling noexisting objects!
- WaitForSingleObject(filtermutex,INFINITE);
- iframemode=true;//enter iframe mode
- //Build filter graph
- HRESULT hres;
- if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
- IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) {
- ReleaseMutex(filtermutex);
- return 0;
- }
-#ifdef DS_DEBUG
- AddToRot(dsgraphbuilder,&graphidentifier);
-#endif
-
- //firstsynched=false;
- sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data
- // to DirectShow
- if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) {
- Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");
- ReleaseMutex(filtermutex);
- CleanupDS();
- return 0;
- }
-#ifdef DO_VIDEO
- if (videoon) {
- dsInitVideoFilter();
- }
-#endif
-/* if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,
- IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) {
- return 0;
- }*/
-
- dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);
- dsmediafilter->SetSyncSource(/*dsrefclock*/NULL); //Run as fast as you can!
-
- dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);
- dsgraphbuilder->QueryInterface(IID_IBasicAudio,(void **) &dsbasicaudio);
- dsinited=true;
-
-
- dsmediacontrol->Run();
- ReleaseMutex(filtermutex);
- return 1;
-
-}
-
-int VideoWin::dsstop()
-{
- if (!initted) return 0;
-
- CleanupDS();
-
-
- return 1;
-}
-
-int VideoWin::stop()
-{
- if (!initted) return 0;
-
-
- return 1;
-}
-
-int VideoWin::reset()
-{
- if (!initted) return 0;
-
-
- return 1;
-}
-
-int VideoWin::dsreset()
-{
- if (!initted) return 0;
- videoposx=0;
- videoposy=0;
- iframemode=false;//exit iframe mode
- CleanupDS();
-
- return 1;
-}
-
-int VideoWin::dspause()
-{
- if (!initted) return 0;
- WaitForSingleObject(filtermutex,INFINITE);
- if (dsmediacontrol) dsmediacontrol->Pause();
- ReleaseMutex(filtermutex);
- return 1;
-}
-
-int VideoWin::pause()
-{
- if (!initted) return 0;
-
- return 1;
-}
-
-int VideoWin::unPause() // FIXME get rid - same as play!!
-{//No on windows this is not the same, I don't get rid of!
- if (!initted) return 0;
- return 1;
-}
-
-int VideoWin::dsunPause() // FIXME get rid - same as play!!
-{//No on windows this is not the same, I don't get rid of!
- if (!initted) return 0;
- WaitForSingleObject(filtermutex,INFINITE);
- if (dsmediacontrol) dsmediacontrol->Run();
- ReleaseMutex(filtermutex);
-
- return 1;
-}
-
-int VideoWin::fastForward()
-{
- if (!initted) return 0;
-
- return 1;
-}
-
-int VideoWin::unFastForward()
-{
- if (!initted) return 0;
-
- return 1;
-}
-
-int VideoWin::attachFrameBuffer()
-{
- if (!initted) return 0;
- return 1;
-}
-
-int VideoWin::blank(void)
-{
- ((OsdWin*)Osd::getInstance())->Blank();
- return 1;
-}
-
-ULLONG VideoWin::getCurrentTimestamp()
-{
- REFERENCE_TIME startoffset;
- REFERENCE_TIME ncr_time;
- if (iframemode) return 0; //Not in iframe mode!
- if (!dsrefclock || !sourcefilter) return 0;
- FILTER_STATE state;
- sourcefilter->GetState(10,&state);
-
- if (state==State_Running) dsrefclock->GetTime(&cr_time);
- ncr_time=cr_time;
- startoffset=sourcefilter->getStartOffset();
- if (startoffset==0) return 0;
- ncr_time-=startoffset;
- ncr_time-=lastreftimeRT;
- /* ULLONG result=frameNumberToTimecode(
- VDR::getInstance()->frameNumberFromPosition(lastreftimeBYTE));*/
- long long result=lastreftimePTS;
- result+=(ULLONG)(ncr_time/10000LL*90LL);
- if (result<0) result=(1LL << 33)-result;
- return result;
-
-}
-/* //to beremoved
-ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode)
-{
- if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);
- else return (ULONG)(((double)timecode / (double)90000) * (double)30);
-}
-
-ULLONG VideoWin::frameNumberToTimecode(ULONG framenumber)
-{
- if (format == PAL) return (ULLONG)(((double)framenumber * (double)90000) / (double)25);
- else return (ULLONG)(((double)framenumber * (double)90000) / (double)30);
-}
-*/
-void VideoWin::CleanupDS()
-{
- WaitForSingleObject(filtermutex,INFINITE);
- dsinited=false;
- if (dsmediacontrol)dsmediacontrol->Stop();
- if (cur_audio_media_sample) {
- cur_audio_media_sample->Release();
- cur_audio_media_sample=NULL;
- }
- if (cur_video_media_sample) {
- cur_video_media_sample->Release();
- cur_video_media_sample=NULL;
- }
- if (dsbasicaudio) {
- dsbasicaudio->Release();
- dsbasicaudio=NULL;
- }
- if (dsvmrsurfnotify) {
- dsvmrsurfnotify->Release();
- dsvmrsurfnotify=NULL;
- }
- if (dsrenderer) {
- dsrenderer->Release();
- dsrenderer=NULL;
- }
-
- if (allocatorvmr) {
- allocatorvmr->Release();
- allocatorvmr=NULL;
- }
-
- if (dsrefclock) {
- dsrefclock->Release();
- dsrefclock=NULL;
- }
- if (dsmediafilter) {
- dsmediafilter->Release();
- dsmediafilter=NULL;
- }
-
-
-
- if (dsmediacontrol) {
- dsmediacontrol->Stop();
- dsmediacontrol->Release();
- dsmediacontrol=NULL;
- }
- if (dsgraphbuilder){
-#ifdef DS_DEBUG
- RemoveFromRot(graphidentifier);
-#endif
- dsgraphbuilder->Release();
- dsgraphbuilder=NULL;
-
- sourcefilter=NULL; //The Graph Builder destroys our SourceFilter
- }
- ReleaseMutex(filtermutex);
-
-}
-
-void VideoWin::PrepareMediaSample(const MediaPacketList& mplist,
- UINT samplepos)
-{
- mediapacket = mplist.front();
-}
-
-UINT VideoWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)
-{
- DeliverMediaPacket(mediapacket, buffer, samplepos);
- if (*samplepos == mediapacket.length) {
- *samplepos = 0;
- return 1;
- }
- else return 0;
-}
-
-UINT VideoWin::DeliverMediaPacket(MediaPacket packet,
- const UCHAR* buffer,
- UINT *samplepos)
-{
-
- /*First Check, if we have an audio sample*/
- if (!isdsinited()) return 0;
- if (packet.type == MPTYPE_VIDEO_H264)
- {
- h264=true;
- }
- else
- {
- h264=false;
- }
-
-#ifdef DO_VIDEO
- if (!videoon) {
- *samplepos+=packet.length;
- MILLISLEEP(0); //yet not implemented//bad idea
- return packet.length;
- }
- /*First Check, if we have an audio sample*/
- if (iframemode) {
- //samplepos=0;
- MILLISLEEP(10);
- return 0; //Not in iframe mode!
- }
- IMediaSample* ms=NULL;
- REFERENCE_TIME reftime1=0;
- REFERENCE_TIME reftime2=0;
-
- UINT headerstrip=0;
- if (packet.disconti) {
- firstsynched=false;
- DeliverVideoMediaSample();
- }
-
-
-
- /*Inspect PES-Header */
-
- if (*samplepos==0) {//stripheader
- headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/;
- *samplepos+=headerstrip;
- if ( packet.synched ) {
- DeliverVideoMediaSample();//write out old data
- /* if (packet.presentation_time<0) { //Preroll?
- *samplepos=packet.length;//if we have not processed at least one
- return packet.length;//synched packet ignore it!
- }*/
-
- reftime1=packet.presentation_time;
- reftime2=reftime1+1;
- firstsynched=true;
- } else {
- if (!firstsynched) {//
- *samplepos=packet.length;//if we have not processed at least one
- return packet.length;//synched packet ignore it!
- }
- }
- }
- BYTE *ms_buf;
- UINT ms_length;
- UINT ms_pos;
- UINT haveToCopy;
-
- if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
- //samplepos=0;
- //MessageBox(0,"da isser","hei",0);
- //MILLISLEEP(1);
- return 0;
- }
- ms_pos=ms->GetActualDataLength();
- ms_length=ms->GetSize();
- haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
- if ((ms_length-ms_pos)<1 ) {
- DeliverVideoMediaSample(); //we are full!
- if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
- //samplepos=0;
- //MessageBox(0,"da isser","hei",0);
- //MILLISLEEP(10);
- return 0;
- }
- ms_pos=ms->GetActualDataLength();
- ms_length=ms->GetSize();
- haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
- }
- ms->GetPointer(&ms_buf);
-
-
- if (ms_pos==0) {//will only be changed on first packet
- if (packet.disconti) {
- ms->SetDiscontinuity(TRUE);
- } else {
- ms->SetDiscontinuity(FALSE);
- }
- if (packet.synched) {
- ms->SetSyncPoint(TRUE);
- ms->SetTime(&reftime1,&reftime2);
- //Log::getInstance()->log("VideoWin", Log::DEBUG , "Setted videotime to %lld %lld",reftime1,reftime2);
- //Log::getInstance()->log("VideoWin", Log::DEBUG , "Packet pts %lld dts %lld",packet.pts,packet.dts);
- //ms->SetTime(NULL,NULL);
- ms->SetMediaTime(NULL, NULL);
- if (reftime1<0) ms->SetPreroll(TRUE);
- else ms->SetPreroll(FALSE);
- /*Timecode handling*/
- lastreftimeRT=reftime1;
- lastreftimePTS=packet.pts;
-
- }
- else
- {
- ms->SetSyncPoint(FALSE);
- ms->SetTime(NULL,NULL);
- ms->SetMediaTime(NULL, NULL);
- ms->SetPreroll(FALSE);
-
- // ms->SetSyncPoint(TRUE);
- }
- }
-
-
-
- memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
- ms->SetActualDataLength(haveToCopy+ms_pos);
-
- *samplepos+=haveToCopy;
-
- return haveToCopy+headerstrip;
-
-#else
-
- *samplepos+=packet.length;
- MILLISLEEP(0); //yet not implemented//bad idea
- return packet.length;
-#endif
-}
-
-int VideoWin::getCurrentAudioMediaSample(IMediaSample** ms)
-{
- //WaitForSingleObject(filtermutex,INFINITE);
- if (!sourcefilter){
- // ReleaseMutex(filtermutex);
- return 0;
- }
- if (cur_audio_media_sample) {
- *ms=cur_audio_media_sample;//already open
- return 1;
- }
- if (!sourcefilter->getCurrentAudioMediaSample(ms)) {
- // ReleaseMutex(filtermutex);
- }
- if (*ms) (*ms)->SetActualDataLength(0);
- cur_audio_media_sample=*ms;
- //Don't release the mutex before deliver
- return 1;
-}
-
-int VideoWin::getCurrentVideoMediaSample(IMediaSample** ms)
-{
- //WaitForSingleObject(filtermutex,INFINITE);
- if (!sourcefilter){
- // ReleaseMutex(filtermutex);
- return 0;
- }
- if (cur_video_media_sample) {
- *ms=cur_video_media_sample;//already open
- return 1;
- }
- if (!sourcefilter->getCurrentVideoMediaSample(ms)) {
- // ReleaseMutex(filtermutex);
- }
- if (*ms) (*ms)->SetActualDataLength(0);
-
- cur_video_media_sample=*ms;
- //Don't release the mutex before deliver
- return 1;
-}
-
-int VideoWin::DeliverAudioMediaSample(){
- if (cur_audio_media_sample) {
- sourcefilter->DeliverAudioMediaSample(cur_audio_media_sample);
- cur_audio_media_sample=NULL;
- }
- //ReleaseMutex(filtermutex);
- return 1;
-}
-
-int VideoWin::DeliverVideoMediaSample(){
- if (cur_video_media_sample) {
- sourcefilter->DeliverVideoMediaSample(cur_video_media_sample);
- cur_video_media_sample=NULL;
- }
- //ReleaseMutex(filtermutex);
- return 1;
-}
-
-long long VideoWin::SetStartOffset(long long curreftime, bool *rsync)
-{
- *rsync=false;
- if (offsetnotset) {
- startoffset=curreftime;//offset is set for audio
- offsetnotset=false;
- offsetvideonotset=false;
-
-
- } else {
- if (offsetvideonotset) {
- offsetvideonotset=false;
- *rsync=true;
- } else {
- if ( (curreftime-lastrefvideotime)>10000000LL
- || (curreftime-lastrefvideotime)<-10000000LL) {//if pts jumps to big resync
- startoffset+=curreftime-lastrefvideotime;
- lastrefaudiotime+=curreftime-lastrefvideotime;
- //*rsync=true;
- offsetaudionotset=true;
-
- }
- }
-
- }
-
- lastrefvideotime=curreftime;
-
- return startoffset;
-
-}
-
-long long VideoWin::SetStartAudioOffset(long long curreftime, bool *rsync)
-{
- *rsync=false;
- if (offsetnotset) {
- startoffset=curreftime;
- offsetnotset=false;
- offsetaudionotset=false;
- }else {
- if (offsetaudionotset) {
- offsetaudionotset=false;
- *rsync=true;
- } else {
- if ( (curreftime-lastrefaudiotime)>10000000LL
- || (curreftime-lastrefaudiotime)<-10000000LL) {//if pts jumps to big resync
- startoffset+=curreftime-lastrefaudiotime;
- lastrefvideotime+=curreftime-lastrefaudiotime;
- //*rsync=true;
- offsetvideonotset=true;
-
- }
- }
-
- }
- lastrefaudiotime=curreftime;
- return startoffset;
-
-}
-void VideoWin::ResetTimeOffsets() {
- offsetnotset=true; //called from demuxer
- offsetvideonotset=true;
- offsetaudionotset=true;
- startoffset=0;
- lastrefaudiotime=0;
- lastrefvideotime=0;
- lastreftimeRT=0;
- lastreftimePTS=0;
-
-
-}
-
-void VideoWin::SetAudioVolume(long volume)
-{
- audiovolume=volume;
- if (dsbasicaudio) dsbasicaudio->put_Volume(volume);
-}
-
-void VideoWin::displayIFrame(const UCHAR* buffer, UINT length)
-{
- if (!iframemode) EnterIframePlayback();
- if (!isdsinited()) return ;
-
-#ifdef DO_VIDEO
- IMediaSample* ms=NULL;
- REFERENCE_TIME reftime1=0;
- REFERENCE_TIME reftime2=0;
- if (!videoon) return;
- if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
- MILLISLEEP(10);
- return ;
- }
- BYTE *ms_buf;
- DWORD ms_length;
- ms->GetPointer(&ms_buf);
- ms_length=ms->GetSize();
-
- /*First Check, if we have an video sample*/
- DWORD read_pos = 0, write_pos = 0;
- DWORD pattern, packet_length;
- DWORD headerstrip=0;
- bool first=true;
- if (length < 4) return ;
- //Now we strip the pes header
- pattern = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]);
- while (read_pos + 7 <= length)
- {
- pattern = ((pattern << 8) & 0xFFFFFFFF) | buffer[read_pos+3];
- if (pattern < 0x000001E0 || pattern > 0x000001EF) {
- read_pos++;
- continue;
- }
- else
- {
- headerstrip=buffer[read_pos+8]+9/*is this right*/;
- packet_length = ((buffer[read_pos+4] << 8) | (buffer[read_pos+5])) + 6;
- if (read_pos + packet_length > length)
- read_pos = length;
- else
- {
- if ( (headerstrip < packet_length) &&
- (write_pos+packet_length-headerstrip)>ms_length) {
- if (first) {
- ms->SetSyncPoint(TRUE);
- ms->SetDiscontinuity(TRUE);
- first=false;
- } else ms->SetSyncPoint(FALSE);
- ms->SetTime(NULL,NULL);
- ms->SetMediaTime(NULL, NULL);
- ms->SetActualDataLength(write_pos);
- DeliverVideoMediaSample();
-
- if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
- MILLISLEEP(10);
- return ;
- }
- write_pos=0;
- ms_length=ms->GetSize();
- ms->GetPointer(&ms_buf);
- }
- if (packet_length>headerstrip) {
- memcpy(ms_buf+write_pos, buffer+read_pos+headerstrip, packet_length-headerstrip);
- write_pos += packet_length-headerstrip;
- }
- read_pos += packet_length;
-
- pattern = (buffer[read_pos] << 16) | (buffer[read_pos+1] << 8)
- | (buffer[read_pos+2]);
- }
- }
- }
-
- if (first) {ms->SetSyncPoint(TRUE);
- ms->SetDiscontinuity(TRUE);
- first=false;}
- else ms->SetSyncPoint(FALSE);
- ms->SetTime(NULL,NULL);
- ms->SetMediaTime(NULL, NULL);
- ms->SetActualDataLength(write_pos);
- DeliverVideoMediaSample();
-
-#else
-
- // *samplepos+=packet.length;
- MILLISLEEP(0); //yet not implemented//bad idea
- return ;
-#endif
-}
-
-bool VideoWin::supportsAc3(){
- if (sourcefilter != NULL) {
- return sourcefilter->supportsAc3();
- } else {
- return false;
- }
-}
-
-bool VideoWin::supportsh264()
-{
- if (videoH264filterlist.size()>0) return true;
- else return false;
-}
-
-
-bool VideoWin::changeAType(int type,IMediaSample* ms){
- if (sourcefilter!= NULL) {
- lastaudiomode=type;
- return sourcefilter->changeAType(type,ms);
- }
- else
- {
- return false;
- }
-}
-
-#ifdef DEV
-int VideoWin::test()
-{
- return 0;
-}
-
-int VideoWin::test2()
-{
- return 0;
-}
-#endif
-
-
-
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+#include "videowin.h"\r
+#include "log.h"\r
+#include "dssourcefilter.h"\r
+#include "dsallocator.h"\r
+#include "vdr.h"\r
+#include "osdwin.h"\r
+#include "audiowin.h"\r
+#include "wwinvideofilter.h"\r
+#include "wwinvideoh264filter.h"\r
+#include "wtabbar.h"\r
+#include "woptionpane.h"\r
+#include "i18n.h"\r
+#include "demuxer.h"\r
+\r
+#include <Mfapi.h>\r
+#include <mferror.h>\r
+\r
+void AdjustWindow();\r
+\r
+\r
+\r
+VideoWin::VideoWin()\r
+{\r
+ dsinited=false;\r
+ dsgraphbuilder=NULL;\r
+ dsmediacontrol=NULL;\r
+ dsrenderer=NULL;\r
+ dsrefclock=NULL;\r
+ dsmediafilter=NULL;\r
+ dsbasicaudio=NULL;\r
+ sourcefilter=NULL;\r
+ allocatorvmr=NULL;\r
+ cr_time=0;\r
+ lastaudiomode=MPTYPE_MPEG_AUDIO;\r
+ //lastaudiomode=MPTYPE_AC3;\r
+ dsvmrsurfnotify=NULL;\r
+ filtermutex=CreateMutex(NULL,FALSE,NULL);\r
+ offsetnotset=true;\r
+ offsetvideonotset=true;\r
+ offsetaudionotset=true;\r
+ startoffset=0;\r
+ lastrefaudiotime=0;\r
+ lastrefvideotime=0;\r
+ lastreftimeRT=0;\r
+ lastreftimePTS=0;\r
+ firstsynched=false;\r
+ cur_audio_media_sample=NULL;\r
+ cur_video_media_sample=NULL;\r
+ videoon=true;\r
+ audioon=true;\r
+ audiovolume=0;\r
+ pseudotvsize=0;\r
+ videoposx=0;\r
+ videoposy=0;\r
+ aud_type=Audio::MPEG2_PES;\r
+ iframemode=false;//We are not in Iframe mode at begining\r
+ vmrdeinterlacing=2;//Best\r
+ videofilterselected=-1;\r
+ videoH264filterselected=-1;\r
+ OSVERSIONINFO verinfo;\r
+ verinfo.dwOSVersionInfoSize=sizeof(verinfo);\r
+ GetVersionEx(&verinfo);\r
+\r
+ if (verinfo.dwMajorVersion>=6) {\r
+ currentpresenter=EVR;\r
+ } else {\r
+ currentpresenter=VMR9;\r
+ }\r
+ videoH264dtsfix=false;\r
+ videompeg2dtsfix=false;\r
+\r
+\r
+\r
+\r
+}\r
+\r
+VideoWin::~VideoWin()\r
+{\r
+ CleanupDS();\r
+ CloseHandle(filtermutex);\r
+ unsigned int i;\r
+ for (i=0;i<videofilterlist.size();i++)\r
+ {\r
+ if (videofilterlist[i].displayname) delete [] videofilterlist[i].displayname;\r
+ if (videofilterlist[i].friendlyname) delete [] videofilterlist[i].friendlyname;\r
+ }\r
+ videofilterlist.clear();\r
+\r
+ for (i=0;i<videoH264filterlist.size();i++)\r
+ {\r
+ if (videoH264filterlist[i].displayname) delete [] videoH264filterlist[i].displayname;\r
+ if (videoH264filterlist[i].friendlyname) delete [] videoH264filterlist[i].friendlyname;\r
+ }\r
+ videoH264filterlist.clear();\r
+\r
+\r
+\r
+\r
+ instance = NULL;\r
+}\r
+\r
+int VideoWin::init(UCHAR tformat)\r
+{\r
+ if (initted) return 0;\r
+\r
+ initted = 1;\r
+ tvsize=Video::ASPECT16X9; //Internally Vomp should think we are a 16:9 TV\r
+ videoposx=0;\r
+ videoposy=0;\r
+ initFilterDatabase();\r
+ initH264FilterDatabase();\r
+\r
+ if (!setFormat(tformat)){ shutdown(); return 0; }\r
+ return 1;\r
+}\r
+\r
+\r
+\r
+int VideoWin::setTVsize(UCHAR ttvsize)\r
+{\r
+ pseudotvsize=ttvsize;\r
+ return 1;\r
+}\r
+\r
+int VideoWin::setDefaultAspect()\r
+{\r
+ return setAspectRatio(Video::ASPECT4X3);\r
+}\r
+\r
+int VideoWin::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ initted = 0;\r
+ return 1;\r
+}\r
+\r
+int VideoWin::setFormat(UCHAR tformat)\r
+{\r
+ if (!initted) return 0;\r
+ if ((tformat != PAL) && (tformat != NTSC)) return 0;\r
+ format = tformat;\r
+ if (format == NTSC)\r
+ {\r
+ screenWidth = 720;\r
+ screenHeight = 480;\r
+ }\r
+ if (format == PAL)\r
+ {\r
+ screenWidth = 720;\r
+ screenHeight = 576;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoWin::setConnection(UCHAR tconnection)\r
+{\r
+ if (!initted) return 0;\r
+ if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;\r
+ connection = tconnection;\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoWin::setAspectRatio(UCHAR taspectRatio)\r
+{\r
+ if (!initted) return 0;\r
+ if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;\r
+ aspectRatio = taspectRatio;\r
+ AdjustWindow();\r
+ return 1;\r
+}\r
+\r
+int VideoWin::setMode(UCHAR tmode)\r
+{\r
+ if (!initted) return 0;\r
+\r
+ //if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode\r
+\r
+ if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)\r
+ && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;\r
+ mode = tmode;\r
+ videoposx=0;\r
+ videoposy=0;\r
+ AdjustWindow();\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoWin::signalOff()\r
+{\r
+ return 1;\r
+}\r
+\r
+int VideoWin::signalOn()\r
+{\r
+ return 1;\r
+}\r
+\r
+int VideoWin::setSource()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoWin::setPosition(int x, int y)\r
+{\r
+ if (!initted) return 0;\r
+ if (mode==QUARTER || mode==EIGHTH) {\r
+ videoposx=x;\r
+ videoposy=y;\r
+ }\r
+ return 1;\r
+}\r
+\r
+int VideoWin::sync()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ return 1;\r
+}\r
+void VideoWin::initFilterDatabase()\r
+{\r
+ /* This method should determine all availiable DirectShow Filters */\r
+ IFilterMapper2* filtmap=NULL;\r
+ HRESULT result;\r
+ result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,\r
+ IID_IFilterMapper2,(void**)&filtmap);\r
+ if (result != S_OK)\r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::ERR , "Unable to create FilterMapper!");\r
+ return;\r
+ }\r
+ /* Wishlist, what Mediatypes do we want */\r
+ GUID mtypesin[]={MEDIATYPE_Video,MEDIASUBTYPE_MPEG2_VIDEO};\r
+ IEnumMoniker *myenum;\r
+ result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,\r
+ TRUE,1,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);\r
+ if (result != S_OK)\r
+ {\r
+ filtmap->Release();\r
+ Log::getInstance()->log("VideoWin", Log::ERR , "Unable to enum Filters!");\r
+ return;\r
+ }\r
+ ULONG gethowmany;\r
+ IMoniker * moni;\r
+ while(myenum->Next(1,&moni,&gethowmany)==S_OK)\r
+ {\r
+ VideoFilterDesc desc;\r
+ ZeroMemory(&desc,sizeof(desc));\r
+ \r
+ LPOLESTR string;\r
+ moni->GetDisplayName(0,0,&string);\r
+ desc.displayname=new char[wcslen(string)+1];\r
+ wcstombs(desc.displayname,string,wcslen(string)+1);\r
+ CoTaskMemFree(string);\r
+ IPropertyBag *bag;\r
+ if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)\r
+ {\r
+ VARIANT vari;\r
+ VariantInit(&vari);\r
+ result = bag->Read(L"FriendlyName",&vari,NULL);\r
+ if (result == S_OK)\r
+ {\r
+ desc.friendlyname=new char[wcslen(vari.bstrVal)+1];\r
+ wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);\r
+ }\r
+ VariantClear(&vari);\r
+ bag->Release();\r
+\r
+ }\r
+ \r
+ \r
+ videofilterlist.push_back(desc);\r
+ \r
+\r
+ \r
+ moni->Release();\r
+ // bctx->Release();\r
+ }\r
+ int i;\r
+ videofilterselected=-1;\r
+ \r
+ \r
+ \r
+ myenum->Release();\r
+\r
+\r
+\r
+ filtmap->Release();\r
+}\r
+\r
+void VideoWin::initH264FilterDatabase()\r
+{\r
+ /* This method should determine all availiable DirectShow Filters */\r
+ IFilterMapper2* filtmap=NULL;\r
+ HRESULT result;\r
+ result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,\r
+ IID_IFilterMapper2,(void**)&filtmap);\r
+ if (result != S_OK)\r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::ERR , "Unable to create FilterMapper!");\r
+ return;\r
+ }\r
+ /* Wishlist, what Mediatypes do we want */\r
+ GUID mtypesin[]={MEDIATYPE_Video,MEDIASUBTYPE_H264};\r
+ IEnumMoniker *myenum;\r
+ result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,\r
+ TRUE,1,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);\r
+ if (result != S_OK)\r
+ {\r
+ filtmap->Release();\r
+ Log::getInstance()->log("VideoWin", Log::ERR , "Unable to enum Filters!");\r
+ return;\r
+ }\r
+ ULONG gethowmany;\r
+ IMoniker * moni;\r
+ while(myenum->Next(1,&moni,&gethowmany)==S_OK)\r
+ {\r
+ VideoFilterDesc desc;\r
+ ZeroMemory(&desc,sizeof(desc));\r
+ \r
+ LPOLESTR string;\r
+ moni->GetDisplayName(0,0,&string);\r
+ desc.displayname=new char[wcslen(string)+1];\r
+ wcstombs(desc.displayname,string,wcslen(string)+1);\r
+ CoTaskMemFree(string);\r
+ IPropertyBag *bag;\r
+ if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)\r
+ {\r
+ VARIANT vari;\r
+ VariantInit(&vari);\r
+ result = bag->Read(L"FriendlyName",&vari,NULL);\r
+ if (result == S_OK)\r
+ {\r
+ desc.friendlyname=new char[wcslen(vari.bstrVal)+1];\r
+ wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);\r
+ }\r
+ VariantClear(&vari);\r
+ bag->Release();\r
+\r
+ }\r
+ \r
+ \r
+ videoH264filterlist.push_back(desc);\r
+ \r
+\r
+ \r
+ moni->Release();\r
+ // bctx->Release();\r
+ }\r
+ int i;\r
+ videoH264filterselected=-1;\r
+ \r
+ \r
+ \r
+ myenum->Release();\r
+\r
+\r
+\r
+ filtmap->Release();\r
+}\r
+\r
+bool VideoWin::loadOptionsfromServer(VDR* vdr)\r
+{\r
+ char *name=vdr->configLoad("DirectShow","VideoFilter");\r
+ \r
+ if (name != NULL) \r
+ {\r
+ for (int i = 0;i <videofilterlist.size();i++)\r
+ {\r
+ if (strcmp(name,videofilterlist[i].displayname)==0)\r
+ {\r
+ videofilterselected = i;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ name=vdr->configLoad("DirectShow","VideoH264Filter");\r
+ \r
+ if (name != NULL) \r
+ {\r
+ for (int i = 0;i <videoH264filterlist.size();i++)\r
+ {\r
+ if (strcmp(name,videoH264filterlist[i].displayname)==0)\r
+ {\r
+ videoH264filterselected = i;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ name=vdr->configLoad("DirectShow","VMR9DeinterlacingMode");\r
+ if (name != NULL) \r
+ {\r
+ if (STRCASECMP(name,"NoMix")==0) {\r
+ vmrdeinterlacing=0;\r
+ } else if (STRCASECMP(name,"None")==0) {\r
+ vmrdeinterlacing=1;\r
+ } else if (STRCASECMP(name,"Best")==0) {\r
+ vmrdeinterlacing=2;\r
+ } else if (STRCASECMP(name,"Bob")==0) {\r
+ vmrdeinterlacing=3;\r
+ } else if (STRCASECMP(name,"Weave")==0) {\r
+ vmrdeinterlacing=4;\r
+ }\r
+ }\r
+\r
+ name=vdr->configLoad("DirectShow", "VideoPresenter");\r
+ if (name!=NULL) {\r
+ if (STRCASECMP(name,"VMR9")==0) {\r
+ currentpresenter=VMR9;\r
+ } else if (STRCASECMP(name,"EVR")==0) {\r
+ currentpresenter=EVR;\r
+ } \r
+ }\r
+ if (!((OsdWin*)Osd::getInstance())->IsEvrSupported()) {\r
+ currentpresenter=VMR9;\r
+ }\r
+\r
+ name=vdr->configLoad("DirectShow","videoH264dtsfix");\r
+ if (name!=NULL) {\r
+ if (STRCASECMP(name,"YES")==0) {\r
+ videoH264dtsfix=true;\r
+ } else {\r
+ videoH264dtsfix=false;\r
+ }\r
+ }\r
+ name=vdr->configLoad("DirectShow","videompeg2dtsfix");\r
+ if (name!=NULL) {\r
+ if (STRCASECMP(name,"YES")==0) {\r
+ videompeg2dtsfix=true;\r
+ } else {\r
+ videompeg2dtsfix=false;\r
+ }\r
+ }\r
+\r
+ name=vdr->configLoad("DirectGraphics", "StretchFiltering");\r
+ if (name!=NULL) {\r
+ if (STRCASECMP(name,"None")==0) {\r
+ ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_NONE);\r
+ } else if (STRCASECMP(name,"Point")==0) {\r
+ ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_POINT);\r
+ } else if (STRCASECMP(name,"Linear")==0) {\r
+ ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_LINEAR);\r
+ }\r
+ }\r
+\r
+ \r
+\r
+\r
+ return true;\r
+\r
+}\r
+\r
+bool VideoWin::handleOptionChanges(Option* option)\r
+{\r
+ if( Video::handleOptionChanges(option)) return true;\r
+ switch(option->id) {\r
+ case 1: {\r
+ if (STRCASECMP(option->options[option->userSetChoice],"None")==0) {\r
+ ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_NONE);\r
+ } else if (STRCASECMP(option->options[option->userSetChoice],"Point")==0) {\r
+ ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_POINT);\r
+ } else if (STRCASECMP(option->options[option->userSetChoice],"Linear")==0) {\r
+ ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_LINEAR);\r
+ }\r
+ return true;\r
+ } break;\r
+ case 2: {\r
+ if (STRCASECMP(option->options[option->userSetChoice],"NoMix")==0) {\r
+ vmrdeinterlacing=0;\r
+ } else if (STRCASECMP(option->options[option->userSetChoice],"None")==0) {\r
+ vmrdeinterlacing=1;\r
+ } else if (STRCASECMP(option->options[option->userSetChoice],"Best")==0) {\r
+ vmrdeinterlacing=2;\r
+ } else if (STRCASECMP(option->options[option->userSetChoice],"Bob")==0) {\r
+ vmrdeinterlacing=3;\r
+ } else if (STRCASECMP(option->options[option->userSetChoice],"Weave")==0) {\r
+ vmrdeinterlacing=4;\r
+ } \r
+ }break;\r
+ case 3: {\r
+ if (STRCASECMP(option->options[option->userSetChoice],"VMR9")==0) {\r
+ currentpresenter=VMR9;\r
+ } else if (STRCASECMP(option->options[option->userSetChoice],"EVR")==0) {\r
+ currentpresenter=EVR;\r
+ } \r
+ }break;\r
+ case 4: {\r
+ if (STRCASECMP(option->options[option->userSetChoice],"Yes")==0) {\r
+ videoH264dtsfix=true;\r
+ } else {\r
+ videoH264dtsfix=false;\r
+ }\r
+ }break;\r
+ case 5: {\r
+ if (STRCASECMP(option->options[option->userSetChoice],"Yes")==0) {\r
+ videompeg2dtsfix=true;\r
+ } else {\r
+ videompeg2dtsfix=false;\r
+ }\r
+ }break;\r
+ };\r
+ return false;\r
+\r
+}\r
+\r
+bool VideoWin::saveOptionstoServer()\r
+{\r
+ if (videofilterselected!=-1) {\r
+ VDR::getInstance()->configSave("DirectShow",\r
+ "VideoFilter",videofilterlist[videofilterselected].displayname);\r
+ VDR::getInstance()->configSave("DirectShow",\r
+ "VideoH264Filter",videoH264filterlist[videoH264filterselected].displayname);\r
+ }\r
+ return true;\r
+}\r
+\r
+/*Option(UINT id, const char* displayText, const char* configSection, const char* configKey, UINT optionType, \r
+ UINT numChoices, UINT defaultChoice, UINT startInt,\r
+ const char * const * options, const char * const * optionkeys = NULL, AbstractOption* handler=NULL);*/\r
+\r
+bool VideoWin::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane)\r
+{\r
+ if (!Video::addOptionsToPanes(panenumber,options,pane)) return false;\r
+\r
+\r
+ Option* option;\r
+ if (panenumber == 2) \r
+ {\r
+ DWORD scalingcaps=((OsdWin*)Osd::getInstance())->getFilterCaps();\r
+ char **scalingopts=new char *[3];\r
+ int i=0;\r
+ scalingopts[i]=new char[strlen("None")+1];\r
+ strcpy(scalingopts[i],"None");\r
+ i++;\r
+ if ((scalingcaps & D3DPTFILTERCAPS_MINFPOINT)!=0 \r
+ && (scalingcaps & D3DPTFILTERCAPS_MAGFPOINT)!=0) {\r
+ scalingopts[i]=new char[strlen("Point")+1];\r
+ strcpy(scalingopts[i],"Point");\r
+ i++;\r
+ }\r
+ if ((scalingcaps & D3DPTFILTERCAPS_MINFLINEAR)!=0 \r
+ && (scalingcaps & D3DPTFILTERCAPS_MAGFLINEAR)!=0) {\r
+ scalingopts[i]=new char[strlen("Linear")+1];\r
+ strcpy(scalingopts[i],"Linear");\r
+ i++;\r
+ }\r
+ option = new Option(1 ,tr("Video Stretching Filter"), "DirectGraphics", "StretchFiltering", Option::TYPE_TEXT, i, (i-1), 0, scalingopts,NULL,true, this);\r
+ options->push_back(option);\r
+ pane->addOptionLine(option);\r
+ static const char* deintopts[]={"NoMix","None","Best","Bob","Weave"};\r
+ option = new Option(2,tr("VMR9 Deinterlacing Mode"), "DirectShow","VMR9DeinterlacingMode",Option::TYPE_TEXT,5,2,0,deintopts,NULL,false,this);\r
+ options->push_back(option);\r
+ pane->addOptionLine(option);\r
+\r
+ if (((OsdWin*)Osd::getInstance())->IsEvrSupported()) \r
+ {\r
+ static const char* presenteropts[]={"EVR","VMR9"};\r
+ option = new Option(3,tr("Video Presenter Filter"),"DirectShow", "VideoPresenter",Option::TYPE_TEXT,2,\r
+ (currentpresenter==EVR)?0:1,0,presenteropts,NULL,false,this);\r
+ } else {\r
+ static const char* presenteropts[]={"VMR9"};\r
+ option = new Option(3,tr("Video Presenter Filter"),"DirectShow", "VideoPresenter",Option::TYPE_TEXT,1,0,0,presenteropts,NULL,false,this);\r
+ }\r
+ options->push_back(option);\r
+ pane->addOptionLine(option);\r
+\r
+ static const char* yesnoopts[]={"Yes","No"};\r
+ option = new Option(4,tr("Video H264 fix dts time"), "DirectShow","videoH264dtsfix",Option::TYPE_TEXT,2,1,0,yesnoopts,NULL,false,this);\r
+ options->push_back(option);\r
+ pane->addOptionLine(option);\r
+\r
+ option = new Option(5,tr("Video Mpeg2 fix dts time"), "DirectShow","videompeg2dtsfix",Option::TYPE_TEXT,2,1,0,yesnoopts,NULL,false,this);\r
+ options->push_back(option);\r
+ pane->addOptionLine(option);\r
+\r
+\r
+ \r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+IBaseFilter *VideoWin::getVideoFilter()\r
+{\r
+ IBaseFilter *curfilter= NULL;\r
+ if (videofilterselected == -1)\r
+ {\r
+ int i;\r
+ for (i = 0;i <videofilterlist.size();i++)\r
+ {\r
+ \r
+ if (videofilterlist[i].vmr9tested == true)\r
+ {\r
+ if (videofilterlist[i].vmr9 == true)\r
+ {\r
+ videofilterselected = i;\r
+ break;\r
+ } \r
+ else\r
+ {\r
+ continue;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ IMoniker * moni=NULL;\r
+ IBindCtx *bindctx=NULL;\r
+ if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+ LPCOLESTR name=(LPCOLESTR)new WCHAR[strlen(videofilterlist[i].displayname)+1];\r
+ mbstowcs((wchar_t*)name,videofilterlist[i].displayname,strlen(videofilterlist[i].displayname)+1);\r
+ ULONG eater=0;\r
+ \r
+\r
+ if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+ {\r
+ if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+ {\r
+ IAMDecoderCaps* desccaps=NULL;\r
+ if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+ {\r
+ DWORD caps;\r
+ desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+ if (caps == DECODER_CAP_SUPPORTED)\r
+ {\r
+ videofilterlist[i].vmr9tested = true;\r
+ videofilterlist[i].vmr9 = true;\r
+ videofilterselected = i;\r
+ } \r
+ else\r
+ {\r
+ videofilterlist[i].vmr9tested = true;\r
+ videofilterlist[i].vmr9 = false;\r
+ \r
+ curfilter->Release();\r
+ curfilter=NULL;\r
+ }\r
+ }\r
+ desccaps->Release();\r
+ }\r
+ moni->Release();\r
+ } \r
+ delete [] name;\r
+ bindctx->Release();\r
+ }\r
+ if (videofilterlist[i].vmr9) break;\r
+ \r
+ }\r
+ if (curfilter != NULL)\r
+ {\r
+ VDR *vdr=VDR::getInstance();\r
+ if (vdr != NULL)\r
+ {\r
+ vdr->configSave("DirectShow","VideoFilter",\r
+ videofilterlist[videofilterselected].displayname);\r
+ }\r
+ return curfilter;\r
+ }\r
+ } \r
+ else\r
+ {\r
+ IBindCtx *bindctx=NULL;\r
+ if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+ IMoniker * moni=NULL;\r
+ LPCOLESTR name=new WCHAR[strlen(videofilterlist[videofilterselected].displayname)+1];\r
+ mbstowcs((wchar_t*)name,videofilterlist[videofilterselected].displayname,\r
+ strlen(videofilterlist[videofilterselected].displayname)+1);\r
+ ULONG eater;\r
+ if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+ {\r
+ if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+ {\r
+ IAMDecoderCaps* desccaps=NULL;\r
+ if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+ {\r
+ DWORD caps;\r
+ desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+ if (caps == DECODER_CAP_SUPPORTED)\r
+ {\r
+ videofilterlist[videofilterselected].vmr9tested = true;\r
+ videofilterlist[videofilterselected].vmr9 = true;\r
+ } \r
+ else\r
+ {\r
+ videofilterlist[videofilterselected].vmr9tested = true;\r
+ videofilterlist[videofilterselected].vmr9 = false;\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Filter does not support VMR9, but is selected, manual selection!");\r
+ }\r
+ }\r
+ moni->Release();\r
+ delete [] name;\r
+ bindctx->Release();\r
+ return curfilter;\r
+ } \r
+ moni->Release();\r
+ }\r
+ bindctx->Release();\r
+ delete [] name;\r
+ return NULL; \r
+ }\r
+ return NULL;\r
+ \r
+}\r
+\r
+IBaseFilter *VideoWin::getVideoH264Filter()\r
+{\r
+ IBaseFilter *curfilter= NULL;\r
+ if (videoH264filterselected == -1)\r
+ {\r
+ int i;\r
+ for (i = 0;i <videoH264filterlist.size();i++)\r
+ {\r
+ \r
+ if (videoH264filterlist[i].vmr9tested == true)\r
+ {\r
+ if (videoH264filterlist[i].vmr9 == true)\r
+ {\r
+ videoH264filterselected = i;\r
+ break;\r
+ } \r
+ else\r
+ {\r
+ continue;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ IMoniker * moni=NULL;\r
+ IBindCtx *bindctx=NULL;\r
+ if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+ LPCOLESTR name=(LPCOLESTR)new WCHAR[strlen(videoH264filterlist[i].displayname)+1];\r
+ mbstowcs((wchar_t*)name,videoH264filterlist[i].displayname,strlen(videoH264filterlist[i].displayname)+1);\r
+ ULONG eater=0;\r
+ Log::getInstance()->log("VideoWin", Log::DEBUG ,"Creating filter: %s",videoH264filterlist[i].friendlyname);\r
+\r
+ \r
+\r
+ if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+ {\r
+ if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+ {\r
+ IAMDecoderCaps* desccaps=NULL;\r
+ if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+ {\r
+ DWORD caps;\r
+ desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+ if (caps == DECODER_CAP_SUPPORTED)\r
+ {\r
+ videoH264filterlist[i].vmr9tested = true;\r
+ videoH264filterlist[i].vmr9 = true;\r
+ videoH264filterselected = i;\r
+ } \r
+ else\r
+ {\r
+ videoH264filterlist[i].vmr9tested = true;\r
+ videoH264filterlist[i].vmr9 = false;\r
+ \r
+ curfilter->Release();\r
+ curfilter=NULL;\r
+ }\r
+ }\r
+ desccaps->Release();\r
+ }\r
+ moni->Release();\r
+ } \r
+ delete [] name;\r
+ bindctx->Release();\r
+ }\r
+ if (videoH264filterlist[i].vmr9) break;\r
+ \r
+ }\r
+ if (curfilter != NULL)\r
+ {\r
+ VDR *vdr=VDR::getInstance();\r
+ if (vdr != NULL)\r
+ {\r
+ vdr->configSave("DirectShow","VideoH264Filter",\r
+ videoH264filterlist[videoH264filterselected].displayname);\r
+ }\r
+ return curfilter;\r
+ }\r
+ } \r
+ else\r
+ {\r
+ IBindCtx *bindctx=NULL;\r
+ if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+ IMoniker * moni=NULL;\r
+ LPCOLESTR name=new WCHAR[strlen(videoH264filterlist[videoH264filterselected].displayname)+1];\r
+ mbstowcs((wchar_t*)name,videoH264filterlist[videoH264filterselected].displayname,\r
+ strlen(videoH264filterlist[videoH264filterselected].displayname)+1);\r
+ ULONG eater;\r
+ Log::getInstance()->log("VideoWin", Log::DEBUG ,"Creating filter: %s",videoH264filterlist[videoH264filterselected].friendlyname);\r
+ if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+ {\r
+ if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+ {\r
+ IAMDecoderCaps* desccaps=NULL;\r
+ if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+ {\r
+ DWORD caps;\r
+ desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+ if (caps == DECODER_CAP_SUPPORTED)\r
+ {\r
+ videoH264filterlist[videoH264filterselected].vmr9tested = true;\r
+ videoH264filterlist[videoH264filterselected].vmr9 = true;\r
+ } \r
+ else\r
+ {\r
+ videoH264filterlist[videoH264filterselected].vmr9tested = true;\r
+ videoH264filterlist[videoH264filterselected].vmr9 = false;\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Filter does not support VMR9, but is selected, manual selection!");\r
+ }\r
+ }\r
+ moni->Release();\r
+ delete [] name;\r
+ bindctx->Release();\r
+ return curfilter;\r
+ } \r
+ moni->Release();\r
+ }\r
+ bindctx->Release();\r
+ delete [] name;\r
+ return NULL; \r
+ }\r
+ return NULL;\r
+ \r
+}\r
+\r
+\r
+#ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions\r
+#include "dshelper.h"\r
+#endif\r
+\r
+#define DO_VIDEO\r
+\r
+int VideoWin::play()\r
+{\r
+ if (!initted) return 0;\r
+ return 1;\r
+}\r
+\r
+bool VideoWin::addOptionPagesToWTB(WTabBar *wtb)\r
+{\r
+ Boxx *box=new WWinVideoFilter();\r
+ wtb->addTab(tr("Video Filter"), box);\r
+ box=new WWinVideoH264Filter();\r
+ wtb->addTab(tr("H264 Filter"), box);\r
+ return true;\r
+}\r
+\r
+const VideoFilterDescList *VideoWin::getVideoFilterList(int &selected)\r
+{\r
+ selected=videofilterselected;\r
+ return &videofilterlist;\r
+}\r
+\r
+const VideoFilterDescList *VideoWin::getVideoH264FilterList(int &selected)\r
+{\r
+ selected=videoH264filterselected;\r
+ return &videoH264filterlist;\r
+}\r
+\r
+bool VideoWin::selectVideoFilter(int filter)\r
+{\r
+ IBindCtx *bindctx=NULL;\r
+ if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+ IMoniker * moni=NULL;\r
+ LPCOLESTR name=new WCHAR[strlen(videofilterlist[filter].displayname)+1];\r
+ mbstowcs((wchar_t*)name,videofilterlist[filter].displayname,\r
+ strlen(videofilterlist[filter].displayname)+1);\r
+ ULONG eater;\r
+ bool success=false;\r
+ if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+ {\r
+ IBaseFilter* curfilter=NULL;\r
+ if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+ {\r
+ IAMDecoderCaps* desccaps=NULL;\r
+ if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+ {\r
+ DWORD caps;\r
+ HRESULT hres=desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+ if (caps == DECODER_CAP_SUPPORTED)\r
+ {\r
+ videofilterlist[filter].vmr9tested = true;\r
+ videofilterlist[filter].vmr9 = true;\r
+ success=true;\r
+ } \r
+ else\r
+ {\r
+ videofilterlist[filter].vmr9tested = true;\r
+ videofilterlist[filter].vmr9 = false;\r
+ success=false;\r
+ }\r
+ desccaps->Release();\r
+ } else {\r
+ videofilterlist[filter].vmr9tested = true;\r
+ videofilterlist[filter].vmr9 = false;\r
+ success=false;\r
+ }\r
+\r
+ curfilter->Release();\r
+ \r
+ } \r
+ moni->Release();\r
+ }\r
+ bindctx->Release();\r
+ delete [] name;\r
+ if (success || true) \r
+ {\r
+ videofilterselected=filter;\r
+ return true;\r
+ } \r
+ else\r
+ {\r
+ return false;\r
+ }\r
+}\r
+\r
+bool VideoWin::selectVideoH264Filter(int filter)\r
+{\r
+ IBindCtx *bindctx=NULL;\r
+ if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+ IMoniker * moni=NULL;\r
+ LPCOLESTR name=new WCHAR[strlen(videoH264filterlist[filter].displayname)+1];\r
+ mbstowcs((wchar_t*)name,videoH264filterlist[filter].displayname,\r
+ strlen(videoH264filterlist[filter].displayname)+1);\r
+ ULONG eater;\r
+ bool success=false;\r
+ if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+ {\r
+ IBaseFilter* curfilter=NULL;\r
+ if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+ {\r
+ IAMDecoderCaps* desccaps=NULL;\r
+ if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+ {\r
+ DWORD caps;\r
+ HRESULT hres=desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+ if (caps == DECODER_CAP_SUPPORTED)\r
+ {\r
+ videoH264filterlist[filter].vmr9tested = true;\r
+ videoH264filterlist[filter].vmr9 = true;\r
+ success=true;\r
+ } \r
+ else\r
+ {\r
+ videoH264filterlist[filter].vmr9tested = true;\r
+ videoH264filterlist[filter].vmr9 = false;\r
+ success=false;\r
+ }\r
+ desccaps->Release();\r
+ } else {\r
+ videoH264filterlist[filter].vmr9tested = true;\r
+ videoH264filterlist[filter].vmr9 = false;\r
+ success=false;\r
+ }\r
+\r
+ curfilter->Release();\r
+ \r
+ } \r
+ moni->Release();\r
+ }\r
+ bindctx->Release();\r
+ delete [] name;\r
+ if (success || true) \r
+ {\r
+ videoH264filterselected=filter;\r
+ return true;\r
+ } \r
+ else\r
+ {\r
+ return false;\r
+ }\r
+}\r
+\r
+int VideoWin::dsInitVideoFilter()\r
+{\r
+ #ifdef DO_VIDEO\r
+ HRESULT hres;\r
+ if (videoon) {\r
+ //We alloc the vmr9 as next step\r
+ if (currentpresenter==VMR9) \r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::INFO ,"VMR9 Videopresenter selected!");\r
+ if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0,\r
+ CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsrenderer)!=S_OK) \r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!");\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ }\r
+ /*VMR 9 stuff**/\r
+ if (hres=dsgraphbuilder->AddFilter(dsrenderer,L"VMR9")!=S_OK)\r
+ {\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!");\r
+ return 0;\r
+ }\r
+ IVMRFilterConfig9* vmrfilconfig;\r
+ if (dsrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK)\r
+ {\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!");\r
+ return 0;\r
+ }\r
+ if (vmrdeinterlacing!=0) vmrfilconfig->SetNumberOfStreams(1);//Enter Mixing Mode\r
+ vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless);\r
+ vmrfilconfig->Release();\r
+ if (dsrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,\r
+ (void**)& dsvmrsurfnotify) != S_OK)\r
+ {\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!");\r
+ return 0;\r
+ }\r
+ allocatorvmr=new DsAllocator();\r
+ dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr);\r
+ allocatorvmr->AdviseNotify(dsvmrsurfnotify);\r
+ \r
+ IVMRDeinterlaceControl9* deintctrl;\r
+ if (dsrenderer->QueryInterface(IID_IVMRDeinterlaceControl9,(void**)&deintctrl)!=S_OK)\r
+ {\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Deinterlace control!");\r
+ return 0;\r
+ }\r
+ /*turnoff*/\r
+ switch (vmrdeinterlacing)\r
+ {\r
+ case 1: //No Deinterlasing\r
+ deintctrl->SetDeinterlaceMode(0xFFFFFFFF,(LPGUID)&GUID_NULL);//Turn Off\r
+ break;\r
+ case 2: //Best\r
+ deintctrl->SetDeinterlacePrefs(DeinterlacePref_NextBest);//Choose Next Best\r
+ break;\r
+ case 3: //Bob\r
+ deintctrl->SetDeinterlacePrefs(DeinterlacePref_BOB);//Choose NBob\r
+ break;\r
+ case 4: //Weave\r
+ deintctrl->SetDeinterlacePrefs(DeinterlacePref_Weave);//Choose Weave\r
+ break;\r
+ };\r
+ deintctrl->Release();\r
+ /*VMR 9 stuff end */\r
+ }\r
+ else if (currentpresenter==EVR)\r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::INFO ,"EVR Videopresenter selected!");\r
+ if (hres=CoCreateInstance(CLSID_EnhancedVideoRenderer,0,\r
+ CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsrenderer)!=S_OK) \r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating EVR renderer!");\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ }\r
+ /*EVR stuff**/\r
+ if (hres=dsgraphbuilder->AddFilter(dsrenderer,L"EVR")!=S_OK)\r
+ {\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding EVR renderer!");\r
+ return 0;\r
+ }\r
+ \r
+ \r
+ IMFGetService *evr_services;\r
+ if (dsrenderer->QueryInterface(IID_IMFGetService,(void**)&evr_services)!=S_OK)\r
+ {\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFGetServices interface!");\r
+ return 0;\r
+ }\r
+\r
+ IMFVideoDisplayControl* mfvideodisplaycontrol;\r
+ if (evr_services->GetService(MR_VIDEO_RENDER_SERVICE,IID_IMFVideoDisplayControl,(void**)&mfvideodisplaycontrol)!=S_OK)\r
+ {\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFVideoDisplayControl interface!");\r
+ return 0;\r
+ }\r
+\r
+ evr_services->Release();\r
+ mfvideodisplaycontrol->SetVideoWindow(((OsdWin*) Osd::getInstance())->getWindow());\r
+ //RECT client;\r
+ //GetClientRect(((OsdWin*) Osd::getInstance())->getWindow(), &client);\r
+ //mfvideodisplaycontrol->SetVideoPosition(NULL,&client);\r
+\r
+ mfvideodisplaycontrol->Release();\r
+\r
+\r
+ /// if (vmrdeinterlacing!=0) vmrfilconfig->SetNumberOfStreams(1);//Enter Mixing Mode //always the case for evr!\r
+\r
+ IMFVideoRenderer *mfvideorenderer;\r
+ if (dsrenderer->QueryInterface(IID_IMFVideoRenderer,(void**)&mfvideorenderer)!=S_OK)\r
+ {\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFVideoRenderer interface!");\r
+ return 0;\r
+ }\r
+ \r
+ allocatorvmr=new DsAllocator();\r
+ HRESULT hres=mfvideorenderer->InitializeRenderer(NULL,allocatorvmr);\r
+\r
+ mfvideorenderer->Release();\r
+ //How should I do this in EVR?\r
+ /* IVMRDeinterlaceControl9* deintctrl;\r
+ if (dsrenderer->QueryInterface(IID_IVMRDeinterlaceControl9,(void**)&deintctrl)!=S_OK)\r
+ {\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Deinterlace control!");\r
+ return 0;\r
+ }\r
+ /*turnoff*\r
+ switch (vmrdeinterlacing)\r
+ {\r
+ case 1: //No Deinterlasing\r
+ deintctrl->SetDeinterlaceMode(0xFFFFFFFF,(LPGUID)&GUID_NULL);//Turn Off\r
+ break;\r
+ case 2: //Best\r
+ deintctrl->SetDeinterlacePrefs(DeinterlacePref_NextBest);//Choose Next Best\r
+ break;\r
+ case 3: //Bob\r
+ deintctrl->SetDeinterlacePrefs(DeinterlacePref_BOB);//Choose NBob\r
+ break;\r
+ case 4: //Weave\r
+ deintctrl->SetDeinterlacePrefs(DeinterlacePref_Weave);//Choose Weave\r
+ break;\r
+ };\r
+ deintctrl->Release();*/\r
+ /*EVR stuff end */\r
+ } else {\r
+ Log::getInstance()->log("VideoWin", Log::ERR ,"No videopresenter selected! Please post on the forum!");\r
+ return -1;\r
+ }\r
+ IFilterGraph2*fg2=NULL;\r
+ if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK)\r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ return 0;\r
+ }\r
+/*#ifndef NEW_DS_MECHANISMENS\r
+ \r
+ if (hres=fg2->RenderEx((IPin*)sourcefilter->GetVideoPin()/*video*,\r
+ AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL) != S_OK) \r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering Video!");\r
+ fg2->Release();\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ return 0;\r
+ }\r
+ \r
+#else*/\r
+ IBaseFilter*videofilter;\r
+ if (h264) \r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::DEBUG ,"Entering h264 playback...");\r
+ videofilter=getVideoH264Filter();\r
+ } \r
+ else\r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::DEBUG ,"Entering MPEG2 playback...");\r
+ videofilter=getVideoFilter();\r
+ }\r
+ if (hres=dsgraphbuilder->AddFilter(videofilter,NULL) != S_OK) \r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Video Filter!");\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ return 0;\r
+ }\r
+ IEnumPins *pinenum=NULL;\r
+ bool error=false;\r
+\r
+ mptype_video_detail vid_details;\r
+ Demuxer* demux=Demuxer::getInstance();\r
+ vid_details.width=demux->getHorizontalSize();\r
+ vid_details.height=demux->getVerticalSize();\r
+\r
+ if (h264)\r
+ {\r
+ if (vid_details.width!=0 && vid_details.height!=0)\r
+ {\r
+ sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_H264,&vid_details);\r
+ }\r
+ else\r
+ {\r
+ sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_H264,NULL);\r
+ }\r
+\r
+ }\r
+ else\r
+ {\r
+ if (vid_details.width!=0 && vid_details.height!=0)\r
+ {\r
+ sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_MPEG2,&vid_details);\r
+ }\r
+ else\r
+ {\r
+ sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_MPEG2,NULL);\r
+ } \r
+ }\r
+ if (videofilter->EnumPins(&pinenum) == S_OK)\r
+ {\r
+ IPin *current=NULL;\r
+ ULONG fetch=0;\r
+ bool firststep=false;\r
+\r
+ while (pinenum->Next(1,¤t,&fetch)==S_OK)\r
+ {\r
+ PIN_DIRECTION dir;\r
+ if (current->QueryDirection(&dir)==S_OK)\r
+ {\r
+ if (dir == PINDIR_INPUT)\r
+ {\r
+ if (sourcefilter->GetVideoPin()->Connect(current,NULL)==S_OK)\r
+ {\r
+ current->Release();\r
+ firststep=true;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ current->Release();\r
+ }\r
+ if (firststep==false)\r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::WARN , "Video Filter has no suitable input!");\r
+ videofilter->Release();\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ return 0;\r
+ }\r
+ bool secondstep=false;\r
+ pinenum->Reset();\r
+ while (pinenum->Next(1,¤t,&fetch)==S_OK)\r
+ {\r
+ PIN_DIRECTION dir;\r
+ if (current->QueryDirection(&dir)==S_OK)\r
+ {\r
+ if (dir == PINDIR_OUTPUT)\r
+ {\r
+ \r
+ if (fg2->RenderEx((IPin*)current/*video*/,\r
+ AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL) ==S_OK)\r
+ {\r
+ current->Release();\r
+ secondstep=true;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ current->Release();\r
+ }\r
+ if (secondstep==false)\r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::WARN , "Video Filter has no suitable output!");\r
+ videofilter->Release();\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ return 0;\r
+ }\r
+ \r
+ videofilter->Release();\r
+ pinenum->Release();\r
+\r
+ }\r
+\r
+\r
+\r
+ fg2->Release();\r
+ return 1;\r
+ }\r
+#endif \r
+ return 1;\r
+}\r
+\r
+int VideoWin::setAudioStreamType(UCHAR type)\r
+{\r
+ aud_type=type;\r
+ if (!initted) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoWin::dsplay()\r
+{\r
+ if (!initted) return 0;\r
+ CleanupDS();\r
+ \r
+ //Build filter graph\r
+ HRESULT hres;\r
+ //So this is the real code, this prevents the feeder from calling noexisting objects!\r
+ WaitForSingleObject(filtermutex,INFINITE);\r
+ if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,\r
+ IID_IGraphBuilder,(void**)&dsgraphbuilder) != S_OK) \r
+ {\r
+ ReleaseMutex(filtermutex);\r
+ return 0;\r
+ }\r
+ #ifdef DS_DEBUG\r
+ AddToRot(dsgraphbuilder,&graphidentifier);\r
+ #endif\r
+ \r
+ firstsynched=false;\r
+ if (aud_type==Audio::MP3) {\r
+ lastaudiomode=MPTYPE_MPEG_AUDIO_LAYER3;\r
+ } else {\r
+ lastaudiomode=MPTYPE_MPEG_AUDIO;\r
+ }\r
+ //lastaudiomode=MPTYPE_AC3;\r
+ sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data\r
+ // to DirectShow\r
+ if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter") != S_OK) \r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ return 0;\r
+ }\r
+ sourcefilter->GetAudioPin()->SetPinMode(lastaudiomode);\r
+ /*if (hres=dsgraphbuilder->Render((IPin*)sourcefilter->GetAudioPin()/*audio*)!=S_OK) \r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ return 0;\r
+ }*/\r
+ if (((AudioWin*)Audio::getInstance())->dsInitAudioFilter(dsgraphbuilder)==0)\r
+ {\r
+ Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");\r
+ ReleaseMutex(filtermutex);\r
+ CleanupDS();\r
+ return 0;\r
+ }\r
+\r
+\r
+ if (dsInitVideoFilter()==0)\r
+ { \r
+ return 0;\r
+ }\r
+\r
+ if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,\r
+ IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) \r
+ {\r
+ return 0;\r
+ }\r
+ dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);\r
+ HRESULT hresdeb = dsmediafilter->SetSyncSource(dsrefclock);\r
+\r
+ dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);\r
+ dsgraphbuilder->QueryInterface(IID_IBasicAudio,(void **) &dsbasicaudio); \r
+ if (dsbasicaudio) \r
+ dsbasicaudio->put_Volume(audiovolume);\r
+ dsinited=true;\r
+ //MILLISLEEP(100);\r
+\r
+ hresdeb=dsmediacontrol->Run();\r
+ iframemode=false;//exit iframe mode\r
+ ReleaseMutex(filtermutex);\r
+ return 1;\r
+}\r
+\r
+int VideoWin::EnterIframePlayback()\r
+{\r
+ if (!initted) return 0;\r
+ CleanupDS();\r
+ //So this is the real code, this prevents the feeder from calling noexisting objects!\r
+ WaitForSingleObject(filtermutex,INFINITE);\r
+ iframemode=true;//enter iframe mode\r
+ //Build filter graph\r
+ HRESULT hres;\r
+ if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,\r
+ IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) {\r
+ ReleaseMutex(filtermutex);\r
+ return 0;\r
+ }\r
+#ifdef DS_DEBUG\r
+ AddToRot(dsgraphbuilder,&graphidentifier);\r
+#endif\r
+ \r
+ //firstsynched=false;\r
+ sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data\r
+ // to DirectShow\r
+ if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) {\r
+ Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");\r
+ ReleaseMutex(filtermutex); \r
+ CleanupDS();\r
+ return 0;\r
+ }\r
+#ifdef DO_VIDEO\r
+ if (videoon) {\r
+ dsInitVideoFilter();\r
+ }\r
+#endif\r
+/* if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,\r
+ IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) {\r
+ return 0;\r
+ }*/\r
+\r
+ dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);\r
+ dsmediafilter->SetSyncSource(/*dsrefclock*/NULL); //Run as fast as you can!\r
+\r
+ dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);\r
+ dsgraphbuilder->QueryInterface(IID_IBasicAudio,(void **) &dsbasicaudio); \r
+ dsinited=true;\r
+ \r
+\r
+ dsmediacontrol->Run();\r
+ ReleaseMutex(filtermutex);\r
+ return 1;\r
+\r
+}\r
+\r
+int VideoWin::dsstop()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ CleanupDS();\r
+\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoWin::stop()\r
+{\r
+ if (!initted) return 0;\r
+\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoWin::reset()\r
+{\r
+ if (!initted) return 0;\r
+ \r
+\r
+ return 1;\r
+}\r
+\r
+int VideoWin::dsreset()\r
+{\r
+ if (!initted) return 0;\r
+ videoposx=0;\r
+ videoposy=0;\r
+ iframemode=false;//exit iframe mode\r
+ CleanupDS();\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoWin::dspause()\r
+{\r
+ if (!initted) return 0;\r
+ WaitForSingleObject(filtermutex,INFINITE);\r
+ if (dsmediacontrol) dsmediacontrol->Pause();\r
+ ReleaseMutex(filtermutex);\r
+ return 1;\r
+}\r
+\r
+int VideoWin::pause()\r
+{\r
+ if (!initted) return 0;\r
+ \r
+ return 1;\r
+}\r
+\r
+int VideoWin::unPause() // FIXME get rid - same as play!!\r
+{//No on windows this is not the same, I don't get rid of!\r
+ if (!initted) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoWin::dsunPause() // FIXME get rid - same as play!!\r
+{//No on windows this is not the same, I don't get rid of!\r
+ if (!initted) return 0;\r
+ WaitForSingleObject(filtermutex,INFINITE);\r
+ if (dsmediacontrol) dsmediacontrol->Run();\r
+ ReleaseMutex(filtermutex);\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoWin::fastForward()\r
+{\r
+ if (!initted) return 0;\r
+\r
+ return 1;\r
+}\r
+\r
+int VideoWin::unFastForward()\r
+{\r
+ if (!initted) return 0;\r
+ \r
+ return 1;\r
+}\r
+\r
+int VideoWin::attachFrameBuffer()\r
+{\r
+ if (!initted) return 0;\r
+ return 1;\r
+}\r
+\r
+int VideoWin::blank(void)\r
+{\r
+ ((OsdWin*)Osd::getInstance())->Blank();\r
+ return 1;\r
+}\r
+\r
+ULLONG VideoWin::getCurrentTimestamp()\r
+{\r
+ REFERENCE_TIME startoffset;\r
+ REFERENCE_TIME ncr_time;\r
+ if (iframemode) return 0; //Not in iframe mode!\r
+ if (!dsrefclock || !sourcefilter) return 0;\r
+ FILTER_STATE state;\r
+ sourcefilter->GetState(10,&state);\r
+\r
+ if (state==State_Running) dsrefclock->GetTime(&cr_time);\r
+ ncr_time=cr_time;\r
+ startoffset=sourcefilter->getStartOffset();\r
+ if (startoffset==0) return 0;\r
+ ncr_time-=startoffset;\r
+ ncr_time-=lastreftimeRT;\r
+ /* ULLONG result=frameNumberToTimecode(\r
+ VDR::getInstance()->frameNumberFromPosition(lastreftimeBYTE));*/\r
+ long long result=lastreftimePTS;\r
+ result+=(ULLONG)(ncr_time/10000LL*90LL);\r
+ if (result<0) result=(1LL << 33)-result;\r
+ return result;\r
+\r
+}\r
+\r
+\r
+/* //to beremoved\r
+ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode)\r
+{\r
+ if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);\r
+ else return (ULONG)(((double)timecode / (double)90000) * (double)30);\r
+}\r
+\r
+ULLONG VideoWin::frameNumberToTimecode(ULONG framenumber)\r
+{\r
+ if (format == PAL) return (ULLONG)(((double)framenumber * (double)90000) / (double)25);\r
+ else return (ULLONG)(((double)framenumber * (double)90000) / (double)30);\r
+}\r
+*/\r
+void VideoWin::CleanupDS()\r
+{\r
+ WaitForSingleObject(filtermutex,INFINITE);\r
+ dsinited=false;\r
+ if (dsmediacontrol)dsmediacontrol->Stop();\r
+ if (cur_audio_media_sample) {\r
+ cur_audio_media_sample->Release();\r
+ cur_audio_media_sample=NULL;\r
+ }\r
+ if (cur_video_media_sample) {\r
+ cur_video_media_sample->Release();\r
+ cur_video_media_sample=NULL;\r
+ }\r
+ if (dsbasicaudio) {\r
+ dsbasicaudio->Release();\r
+ dsbasicaudio=NULL;\r
+ }\r
+ if (dsvmrsurfnotify) {\r
+ dsvmrsurfnotify->Release();\r
+ dsvmrsurfnotify=NULL;\r
+ }\r
+ if (dsrenderer) {\r
+ dsrenderer->Release();\r
+ dsrenderer=NULL;\r
+ }\r
+\r
+ if (allocatorvmr) {\r
+ allocatorvmr->Release();\r
+ allocatorvmr=NULL;\r
+ }\r
+\r
+ if (dsrefclock) {\r
+ dsrefclock->Release();\r
+ dsrefclock=NULL;\r
+ }\r
+ if (dsmediafilter) {\r
+ dsmediafilter->Release();\r
+ dsmediafilter=NULL;\r
+ }\r
+\r
+\r
+\r
+ if (dsmediacontrol) {\r
+ dsmediacontrol->Stop();\r
+ dsmediacontrol->Release();\r
+ dsmediacontrol=NULL;\r
+ }\r
+ if (dsgraphbuilder){\r
+#ifdef DS_DEBUG\r
+ RemoveFromRot(graphidentifier);\r
+#endif\r
+ dsgraphbuilder->Release();\r
+ dsgraphbuilder=NULL;\r
+ \r
+ sourcefilter=NULL; //The Graph Builder destroys our SourceFilter\r
+ }\r
+ ReleaseMutex(filtermutex);\r
+\r
+}\r
+\r
+void VideoWin::PrepareMediaSample(const MediaPacketList& mplist,\r
+ UINT samplepos)\r
+{\r
+ mediapacket = mplist.front();\r
+}\r
+\r
+UINT VideoWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)\r
+{\r
+ DeliverMediaPacket(mediapacket, buffer, samplepos);\r
+ if (*samplepos == mediapacket.length) {\r
+ *samplepos = 0;\r
+ return 1;\r
+ }\r
+ else return 0;\r
+}\r
+\r
+UINT VideoWin::DeliverMediaPacket(MediaPacket packet,\r
+ const UCHAR* buffer,\r
+ UINT *samplepos)\r
+{\r
+\r
+ /*First Check, if we have an audio sample*/\r
+ if (!isdsinited()) return 0;\r
+ if (packet.type == MPTYPE_VIDEO_H264)\r
+ {\r
+ h264=true;\r
+ }\r
+ else\r
+ {\r
+ h264=false;\r
+ }\r
+\r
+#ifdef DO_VIDEO\r
+ if (!videoon) {\r
+ *samplepos+=packet.length;\r
+ MILLISLEEP(0); //yet not implemented//bad idea\r
+ return packet.length;\r
+ }\r
+ /*First Check, if we have an audio sample*/\r
+ if (iframemode) {\r
+ //samplepos=0;\r
+ MILLISLEEP(10);\r
+ return 0; //Not in iframe mode!\r
+ }\r
+ IMediaSample* ms=NULL;\r
+ REFERENCE_TIME reftime1=0;\r
+ REFERENCE_TIME reftime2=0;\r
+\r
+ UINT headerstrip=0;\r
+ if (packet.disconti) {\r
+ firstsynched=false;\r
+ DeliverVideoMediaSample();\r
+ }\r
+\r
+ \r
+\r
+ /*Inspect PES-Header */\r
+\r
+ if (*samplepos==0) {//stripheader\r
+ headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/;\r
+ *samplepos+=headerstrip;\r
+ if ( packet.synched ) {\r
+ DeliverVideoMediaSample();//write out old data\r
+ /* if (packet.presentation_time<0) { //Preroll?\r
+ *samplepos=packet.length;//if we have not processed at least one\r
+ return packet.length;//synched packet ignore it!\r
+ }*/\r
+\r
+ reftime1=packet.presentation_time;\r
+ reftime2=reftime1+1;\r
+ firstsynched=true;\r
+ } else {\r
+ if (!firstsynched) {//\r
+ *samplepos=packet.length;//if we have not processed at least one\r
+ return packet.length;//synched packet ignore it!\r
+ }\r
+ }\r
+ }\r
+ BYTE *ms_buf;\r
+ UINT ms_length;\r
+ UINT ms_pos;\r
+ UINT haveToCopy;\r
+\r
+ if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample\r
+ //samplepos=0;\r
+ //MessageBox(0,"da isser","hei",0);\r
+ //MILLISLEEP(1);\r
+ return 0;\r
+ }\r
+ ms_pos=ms->GetActualDataLength();\r
+ ms_length=ms->GetSize();\r
+ haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);\r
+ if ((ms_length-ms_pos)<1 ) {\r
+ DeliverVideoMediaSample(); //we are full!\r
+ if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample\r
+ //samplepos=0;\r
+ //MessageBox(0,"da isser","hei",0);\r
+ //MILLISLEEP(10);\r
+ return 0;\r
+ }\r
+ ms_pos=ms->GetActualDataLength();\r
+ ms_length=ms->GetSize();\r
+ haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);\r
+ }\r
+ ms->GetPointer(&ms_buf);\r
+\r
+\r
+ if (ms_pos==0) {//will only be changed on first packet\r
+ if (packet.disconti) {\r
+ ms->SetDiscontinuity(TRUE);\r
+ } else {\r
+ ms->SetDiscontinuity(FALSE);\r
+ }\r
+ if (packet.synched) {\r
+ ms->SetSyncPoint(TRUE);\r
+ ms->SetTime(&reftime1,&reftime2);\r
+ //Log::getInstance()->log("VideoWin", Log::DEBUG , "Setted videotime to %lld %lld",reftime1,reftime2);\r
+ //Log::getInstance()->log("VideoWin", Log::DEBUG , "Packet pts %lld dts %lld",packet.pts,packet.dts);\r
+ //ms->SetTime(NULL,NULL);\r
+ ms->SetMediaTime(NULL, NULL);\r
+ if (reftime1<0) ms->SetPreroll(TRUE);\r
+ else ms->SetPreroll(FALSE);\r
+ /*Timecode handling*/\r
+ lastreftimeRT=reftime1;\r
+ lastreftimePTS=packet.pts;\r
+\r
+ }\r
+ else\r
+ {\r
+ ms->SetSyncPoint(FALSE);\r
+ ms->SetTime(NULL,NULL);\r
+ ms->SetMediaTime(NULL, NULL);\r
+ ms->SetPreroll(FALSE);\r
+\r
+ // ms->SetSyncPoint(TRUE);\r
+ }\r
+ }\r
+ \r
+\r
+\r
+ memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);\r
+ ms->SetActualDataLength(haveToCopy+ms_pos);\r
+\r
+ *samplepos+=haveToCopy;\r
+\r
+ return haveToCopy+headerstrip;\r
+\r
+#else\r
+\r
+ *samplepos+=packet.length;\r
+ MILLISLEEP(0); //yet not implemented//bad idea\r
+ return packet.length;\r
+#endif\r
+}\r
+\r
+int VideoWin::getCurrentAudioMediaSample(IMediaSample** ms)\r
+{\r
+ //WaitForSingleObject(filtermutex,INFINITE);\r
+ if (!sourcefilter){\r
+ // ReleaseMutex(filtermutex);\r
+ return 0;\r
+ }\r
+ if (cur_audio_media_sample) {\r
+ *ms=cur_audio_media_sample;//already open\r
+ return 1;\r
+ }\r
+ if (!sourcefilter->getCurrentAudioMediaSample(ms)) {\r
+ // ReleaseMutex(filtermutex);\r
+ }\r
+ if (*ms) (*ms)->SetActualDataLength(0);\r
+ cur_audio_media_sample=*ms;\r
+ //Don't release the mutex before deliver\r
+ return 1;\r
+}\r
+\r
+int VideoWin::getCurrentVideoMediaSample(IMediaSample** ms)\r
+{\r
+ //WaitForSingleObject(filtermutex,INFINITE);\r
+ if (!sourcefilter){\r
+ // ReleaseMutex(filtermutex);\r
+ return 0;\r
+ }\r
+ if (cur_video_media_sample) {\r
+ *ms=cur_video_media_sample;//already open\r
+ return 1;\r
+ }\r
+ if (!sourcefilter->getCurrentVideoMediaSample(ms)) {\r
+ // ReleaseMutex(filtermutex);\r
+ }\r
+ if (*ms) (*ms)->SetActualDataLength(0);\r
+\r
+ cur_video_media_sample=*ms;\r
+ //Don't release the mutex before deliver\r
+ return 1;\r
+}\r
+\r
+int VideoWin::DeliverAudioMediaSample(){\r
+ if (cur_audio_media_sample) {\r
+ sourcefilter->DeliverAudioMediaSample(cur_audio_media_sample);\r
+ cur_audio_media_sample=NULL;\r
+ }\r
+ //ReleaseMutex(filtermutex);\r
+ return 1;\r
+}\r
+\r
+int VideoWin::DeliverVideoMediaSample(){\r
+ if (cur_video_media_sample) {\r
+ sourcefilter->DeliverVideoMediaSample(cur_video_media_sample);\r
+ cur_video_media_sample=NULL;\r
+ }\r
+ //ReleaseMutex(filtermutex);\r
+ return 1;\r
+}\r
+\r
+long long VideoWin::SetStartOffset(long long curreftime, bool *rsync)\r
+{\r
+ *rsync=false;\r
+ if (offsetnotset) {\r
+ startoffset=curreftime;//offset is set for audio\r
+ offsetnotset=false;\r
+ offsetvideonotset=false;\r
+\r
+\r
+ } else {\r
+ if (offsetvideonotset) {\r
+ offsetvideonotset=false;\r
+ *rsync=true;\r
+ } else {\r
+ if ( (curreftime-lastrefvideotime)>10000000LL\r
+ || (curreftime-lastrefvideotime)<-10000000LL) {//if pts jumps to big resync\r
+ startoffset+=curreftime-lastrefvideotime;\r
+ lastrefaudiotime+=curreftime-lastrefvideotime;\r
+ //*rsync=true;\r
+ offsetaudionotset=true;\r
+\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ lastrefvideotime=curreftime;\r
+ \r
+ return startoffset;\r
+\r
+}\r
+\r
+long long VideoWin::SetStartAudioOffset(long long curreftime, bool *rsync)\r
+{\r
+ *rsync=false;\r
+ if (offsetnotset) {\r
+ startoffset=curreftime;\r
+ offsetnotset=false;\r
+ offsetaudionotset=false;\r
+ }else {\r
+ if (offsetaudionotset) {\r
+ offsetaudionotset=false;\r
+ *rsync=true;\r
+ } else {\r
+ if ( (curreftime-lastrefaudiotime)>10000000LL\r
+ || (curreftime-lastrefaudiotime)<-10000000LL) {//if pts jumps to big resync\r
+ startoffset+=curreftime-lastrefaudiotime;\r
+ lastrefvideotime+=curreftime-lastrefaudiotime;\r
+ //*rsync=true;\r
+ offsetvideonotset=true;\r
+\r
+ }\r
+ }\r
+\r
+ }\r
+ lastrefaudiotime=curreftime;\r
+ return startoffset;\r
+\r
+}\r
+void VideoWin::ResetTimeOffsets() {\r
+ offsetnotset=true; //called from demuxer\r
+ offsetvideonotset=true;\r
+ offsetaudionotset=true;\r
+ startoffset=0;\r
+ lastrefaudiotime=0;\r
+ lastrefvideotime=0;\r
+ lastreftimeRT=0;\r
+ lastreftimePTS=0;\r
+\r
+\r
+}\r
+\r
+void VideoWin::SetAudioVolume(long volume)\r
+{\r
+ audiovolume=volume;\r
+ if (dsbasicaudio) dsbasicaudio->put_Volume(volume);\r
+}\r
+\r
+bool VideoWin::displayIFrame(const UCHAR* buffer, UINT length)\r
+{\r
+ if (!iframemode) EnterIframePlayback();\r
+ if (!isdsinited()) return false;\r
+ \r
+#ifdef DO_VIDEO\r
+ IMediaSample* ms=NULL;\r
+ REFERENCE_TIME reftime1=0;\r
+ REFERENCE_TIME reftime2=0;\r
+ if (!videoon) return;\r
+ if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample\r
+ MILLISLEEP(10);\r
+ return ;\r
+ }\r
+ BYTE *ms_buf;\r
+ DWORD ms_length;\r
+ ms->GetPointer(&ms_buf);\r
+ ms_length=ms->GetSize();\r
+ \r
+ /*First Check, if we have an video sample*/\r
+ DWORD read_pos = 0, write_pos = 0;\r
+ DWORD pattern, packet_length;\r
+ DWORD headerstrip=0;\r
+ bool first=true;\r
+ if (length < 4) return ;\r
+ //Now we strip the pes header\r
+ pattern = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]);\r
+ while (read_pos + 7 <= length)\r
+ {\r
+ pattern = ((pattern << 8) & 0xFFFFFFFF) | buffer[read_pos+3];\r
+ if (pattern < 0x000001E0 || pattern > 0x000001EF) {\r
+ read_pos++;\r
+ continue;\r
+ }\r
+ else\r
+ {\r
+ headerstrip=buffer[read_pos+8]+9/*is this right*/;\r
+ packet_length = ((buffer[read_pos+4] << 8) | (buffer[read_pos+5])) + 6;\r
+ if (read_pos + packet_length > length)\r
+ read_pos = length;\r
+ else\r
+ {\r
+ if ( (headerstrip < packet_length) &&\r
+ (write_pos+packet_length-headerstrip)>ms_length) {\r
+ if (first) {\r
+ ms->SetSyncPoint(TRUE);\r
+ ms->SetDiscontinuity(TRUE);\r
+ first=false;\r
+ } else ms->SetSyncPoint(FALSE);\r
+ ms->SetTime(NULL,NULL);\r
+ ms->SetMediaTime(NULL, NULL);\r
+ ms->SetActualDataLength(write_pos);\r
+ DeliverVideoMediaSample();\r
+\r
+ if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample\r
+ MILLISLEEP(10);\r
+ return ;\r
+ }\r
+ write_pos=0;\r
+ ms_length=ms->GetSize();\r
+ ms->GetPointer(&ms_buf);\r
+ }\r
+ if (packet_length>headerstrip) {\r
+ memcpy(ms_buf+write_pos, buffer+read_pos+headerstrip, packet_length-headerstrip);\r
+ write_pos += packet_length-headerstrip;\r
+ }\r
+ read_pos += packet_length;\r
+ \r
+ pattern = (buffer[read_pos] << 16) | (buffer[read_pos+1] << 8)\r
+ | (buffer[read_pos+2]);\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (first) {ms->SetSyncPoint(TRUE);\r
+ ms->SetDiscontinuity(TRUE);\r
+ first=false;} \r
+ else ms->SetSyncPoint(FALSE);\r
+ ms->SetTime(NULL,NULL);\r
+ ms->SetMediaTime(NULL, NULL);\r
+ ms->SetActualDataLength(write_pos);\r
+ DeliverVideoMediaSample();\r
+\r
+ return true;\r
+#else\r
+\r
+ // *samplepos+=packet.length;\r
+ MILLISLEEP(0); //yet not implemented//bad idea\r
+ return true;\r
+#endif\r
+}\r
+\r
+bool VideoWin::supportsAc3(){\r
+ if (sourcefilter != NULL) {\r
+ return sourcefilter->supportsAc3();\r
+ } else {\r
+ return false;\r
+ }\r
+}\r
+\r
+bool VideoWin::supportsh264()\r
+{\r
+ if (videoH264filterlist.size()>0) return true;\r
+ else return false;\r
+}\r
+\r
+\r
+bool VideoWin::changeAType(int type,IMediaSample* ms){\r
+ if (sourcefilter!= NULL) {\r
+ lastaudiomode=type;\r
+ return sourcefilter->changeAType(type,ms);\r
+ }\r
+ else \r
+ {\r
+ return false;\r
+ }\r
+}\r
+\r
+#ifdef DEV\r
+int VideoWin::test()\r
+{\r
+ return 0;\r
+}\r
+\r
+int VideoWin::test2()\r
+{\r
+ return 0;\r
+}\r
+#endif\r
+\r
+\r
+\r
+\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef VIDEOWIN_H
-#define VIDEOWIN_H
-
-#include <stdio.h>
-#include <string.h>
-#include <winsock2.h>
-#include <dshow.h>
-#include <d3d9.h>
-#include <vmr9.h>
-#include <vector>
-
-#include "defines.h"
-#include "video.h"
-
-//#define DS_DEBUG
-#define NEW_DS_MECHANISMENS
-
-#ifdef NEW_DS_MECHANISMENS
-struct VideoFilterDesc {
- char * displayname;
- char * friendlyname;
- bool vmr9;
- bool vmr9tested;
-};
-using namespace std;
-typedef vector<VideoFilterDesc> VideoFilterDescList;
-#endif
-
-class DsSourceFilter;
-class DsAllocator;
-
-class VideoWin : public Video
-{
-public:
- VideoWin();
- ~VideoWin();
-
- int init(UCHAR format);
- int shutdown();
-
- int setFormat(UCHAR format);
- int setConnection(UCHAR connection);
- int setAspectRatio(UCHAR aspectRatio); // This one does the pin 8 scart widescreen switching
- UCHAR getAspectRatio(){return aspectRatio;};
- UCHAR getMode(){return mode;};
- UCHAR getPseudoTVsize() {return pseudotvsize;};
- int setMode(UCHAR mode);
- int setTVsize(UCHAR size); // Is the TV a widescreen?
- int setDefaultAspect();
- int setSource();
- int setPosition(int x, int y);
- int sync();
- int play();
- int dsplay();
- bool InIframemode() {return iframemode;};
- int stop();
- int dsstop();
- int pause();
- int dspause();
- int unPause();
- int dsunPause();
- int fastForward();
- int unFastForward();
- int reset();
- int dsreset();
- int blank();
- int signalOn();
- int signalOff();
- int attachFrameBuffer(); // What does this do?
-// ULONG timecodeToFrameNumber(ULLONG timecode);
-// ULLONG frameNumberToTimecode(ULONG framenumber);
- ULLONG getCurrentTimestamp();
-
- bool loadOptionsfromServer(VDR* vdr);
- bool saveOptionstoServer();
- bool addOptionPagesToWTB(WTabBar *wtb);
- bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane);
- bool handleOptionChanges(Option* option);
-
- //Writing Data to Videodevice
- virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);
- virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos);
- UINT DeliverMediaPacket(const MediaPacket packet, const UCHAR* buffer, UINT *samplepos);
- virtual bool dtsTimefix() {if (h264)return videoH264dtsfix; else return videompeg2dtsfix;}
-
- virtual bool supportsh264();
-
-
- virtual bool supportsAc3();
-
- enum VideoPresenter {
- VMR9,
- EVR
- } ;
-
-
-
-private:
- MediaPacket mediapacket;
-public:
-
- int getCurrentAudioMediaSample(IMediaSample** ms);
- int DeliverAudioMediaSample();
-
- int getCurrentVideoMediaSample(IMediaSample** ms);
- int DeliverVideoMediaSample();
- int setAudioStreamType(UCHAR type);
-
- virtual long long SetStartOffset(long long curreftime, bool *rsync);
- long long SetStartAudioOffset(long long curreftime, bool *rsync);
- virtual void ResetTimeOffsets();
-
- void SetAudioState(bool state){audioon=state;};
- void SetAudioVolume(long volume);
-
- void turnVideoOn(){videoon=true;};
- void turnVideoOff(){videoon=false;};
-
- virtual void displayIFrame(const UCHAR* buffer, UINT length);
-
- unsigned int getPosx() {return videoposx;};
- unsigned int getPosy() {return videoposy;};
- bool isVideoOn() {return videoon;};
- bool isdsinited() {return dsinited;};
- int lastAType() {return lastaudiomode;};
- bool changeAType(int type,IMediaSample* ms);
-
-
- const VideoFilterDescList *getVideoFilterList(int &selected);
- bool selectVideoFilter(int filter);
- DsSourceFilter* getSourceFilter() {return sourcefilter;};
-
- const VideoFilterDescList *getVideoH264FilterList(int &selected);
- bool selectVideoH264Filter(int filter);
-
-
-#ifdef DEV
- int test();
- int test2();
-#endif
-private:
- int EnterIframePlayback();
-#ifdef NEW_DS_MECHANISMENS
- void dstest();
- void initFilterDatabase();
- IBaseFilter *getVideoFilter();
- VideoFilterDescList videofilterlist;
- int videofilterselected;
-
- void initH264FilterDatabase();
- IBaseFilter *getVideoH264Filter();
- VideoFilterDescList videoH264filterlist;
- int videoH264filterselected;
- bool videoH264dtsfix;
- bool videompeg2dtsfix;
-#endif
- int dsInitVideoFilter();
- IMediaControl* dsmediacontrol;
-
- IGraphBuilder* dsgraphbuilder;
- IMediaSample* cur_audio_media_sample;
- IMediaSample* cur_video_media_sample;
- IBaseFilter* dsrenderer;
- IVMRSurfaceAllocatorNotify9 *dsvmrsurfnotify;
- IReferenceClock *dsrefclock;
- IMediaFilter* dsmediafilter;
- IBasicAudio* dsbasicaudio;
- REFERENCE_TIME cr_time;
-
- DsSourceFilter* sourcefilter;
- DsAllocator* allocatorvmr;
- HANDLE filtermutex;
- void CleanupDS();
- bool offsetnotset;
- bool offsetvideonotset;
- bool offsetaudionotset;
- long long startoffset;
- long long lastrefvideotime;
- long long lastrefaudiotime;
- bool dsinited;
- bool firstsynched;
- bool audioon;
- bool videoon;
- bool iframemode;
- UCHAR pseudotvsize;
- REFERENCE_TIME lastreftimeRT;
- ULLONG lastreftimePTS;
- unsigned int videoposx;
- unsigned int videoposy;
- int lastaudiomode;
- int audiovolume;
- UCHAR aud_type;
- unsigned int vmrdeinterlacing;
- VideoPresenter currentpresenter;
-#ifdef DS_DEBUG
- DWORD graphidentifier;
-#endif
-};
-
-#endif
-
-
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef VIDEOWIN_H\r
+#define VIDEOWIN_H\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <winsock2.h>\r
+#include <dshow.h>\r
+#include <d3d9.h>\r
+#include <vmr9.h>\r
+#include <vector>\r
+\r
+#include "defines.h"\r
+#include "video.h"\r
+\r
+//#define DS_DEBUG\r
+#define NEW_DS_MECHANISMENS\r
+\r
+#ifdef NEW_DS_MECHANISMENS\r
+struct VideoFilterDesc {\r
+ char * displayname;\r
+ char * friendlyname;\r
+ bool vmr9;\r
+ bool vmr9tested;\r
+};\r
+using namespace std;\r
+typedef vector<VideoFilterDesc> VideoFilterDescList;\r
+#endif\r
+\r
+class DsSourceFilter;\r
+class DsAllocator;\r
+\r
+class VideoWin : public Video\r
+{\r
+public:\r
+ VideoWin();\r
+ virtual ~VideoWin();\r
+\r
+ int init(UCHAR format);\r
+ int shutdown();\r
+\r
+ int setFormat(UCHAR format);\r
+ int setConnection(UCHAR connection);\r
+ int setAspectRatio(UCHAR aspectRatio); // This one does the pin 8 scart widescreen switching\r
+ UCHAR getAspectRatio(){return aspectRatio;};\r
+ UCHAR getMode(){return mode;};\r
+ UCHAR getPseudoTVsize() {return pseudotvsize;};\r
+ int setMode(UCHAR mode);\r
+ int setTVsize(UCHAR size); // Is the TV a widescreen?\r
+ int setDefaultAspect();\r
+ int setSource();\r
+ int setPosition(int x, int y);\r
+ int sync();\r
+ int play();\r
+ int dsplay();\r
+ bool InIframemode() {return iframemode;};\r
+ int stop();\r
+ int dsstop();\r
+ int pause();\r
+ int dspause();\r
+ int unPause();\r
+ int dsunPause();\r
+ int fastForward();\r
+ int unFastForward();\r
+ int reset();\r
+ int dsreset();\r
+ int blank();\r
+ int signalOn();\r
+ int signalOff();\r
+ int attachFrameBuffer(); // What does this do?\r
+// ULONG timecodeToFrameNumber(ULLONG timecode);\r
+// ULLONG frameNumberToTimecode(ULONG framenumber);\r
+ ULLONG getCurrentTimestamp();\r
+\r
+ bool loadOptionsfromServer(VDR* vdr);\r
+ bool saveOptionstoServer();\r
+ bool addOptionPagesToWTB(WTabBar *wtb);\r
+ bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane);\r
+ bool handleOptionChanges(Option* option);\r
+\r
+ //Writing Data to Videodevice\r
+ virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);\r
+ virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos);\r
+ UINT DeliverMediaPacket(const MediaPacket packet, const UCHAR* buffer, UINT *samplepos);\r
+ virtual bool dtsTimefix() {if (h264)return videoH264dtsfix; else return videompeg2dtsfix;}\r
+\r
+ virtual bool supportsh264();\r
+\r
+\r
+ virtual bool supportsAc3();\r
+\r
+ enum VideoPresenter {\r
+ VMR9,\r
+ EVR\r
+ } ;\r
+\r
+\r
+\r
+private:\r
+ MediaPacket mediapacket;\r
+public:\r
+\r
+ int getCurrentAudioMediaSample(IMediaSample** ms);\r
+ int DeliverAudioMediaSample();\r
+\r
+ int getCurrentVideoMediaSample(IMediaSample** ms);\r
+ int DeliverVideoMediaSample();\r
+ int setAudioStreamType(UCHAR type);\r
+\r
+ virtual long long SetStartOffset(long long curreftime, bool *rsync);\r
+ long long SetStartAudioOffset(long long curreftime, bool *rsync);\r
+ virtual void ResetTimeOffsets();\r
+\r
+ void SetAudioState(bool state){audioon=state;};\r
+ void SetAudioVolume(long volume);\r
+\r
+ void turnVideoOn(){videoon=true;};\r
+ void turnVideoOff(){videoon=false;};\r
+\r
+ virtual bool displayIFrame(const UCHAR* buffer, UINT length);\r
+\r
+ unsigned int getPosx() {return videoposx;};\r
+ unsigned int getPosy() {return videoposy;};\r
+ bool isVideoOn() {return videoon;};\r
+ bool isdsinited() {return dsinited;};\r
+ int lastAType() {return lastaudiomode;};\r
+ bool changeAType(int type,IMediaSample* ms);\r
+\r
+\r
+ const VideoFilterDescList *getVideoFilterList(int &selected);\r
+ bool selectVideoFilter(int filter);\r
+ DsSourceFilter* getSourceFilter() {return sourcefilter;};\r
+\r
+ const VideoFilterDescList *getVideoH264FilterList(int &selected);\r
+ bool selectVideoH264Filter(int filter);\r
+\r
+\r
+#ifdef DEV\r
+ int test();\r
+ int test2();\r
+#endif\r
+private:\r
+ int EnterIframePlayback();\r
+#ifdef NEW_DS_MECHANISMENS\r
+ void dstest(); \r
+ void initFilterDatabase();\r
+ IBaseFilter *getVideoFilter(); \r
+ VideoFilterDescList videofilterlist;\r
+ int videofilterselected;\r
+\r
+ void initH264FilterDatabase();\r
+ IBaseFilter *getVideoH264Filter(); \r
+ VideoFilterDescList videoH264filterlist;\r
+ int videoH264filterselected;\r
+ bool videoH264dtsfix;\r
+ bool videompeg2dtsfix;\r
+#endif\r
+ int dsInitVideoFilter();\r
+ IMediaControl* dsmediacontrol;\r
+\r
+ IGraphBuilder* dsgraphbuilder;\r
+ IMediaSample* cur_audio_media_sample;\r
+ IMediaSample* cur_video_media_sample;\r
+ IBaseFilter* dsrenderer;\r
+ IVMRSurfaceAllocatorNotify9 *dsvmrsurfnotify;\r
+ IReferenceClock *dsrefclock;\r
+ IMediaFilter* dsmediafilter;\r
+ IBasicAudio* dsbasicaudio;\r
+ REFERENCE_TIME cr_time;\r
+\r
+ DsSourceFilter* sourcefilter;\r
+ DsAllocator* allocatorvmr;\r
+ HANDLE filtermutex;\r
+ void CleanupDS();\r
+ bool offsetnotset;\r
+ bool offsetvideonotset;\r
+ bool offsetaudionotset;\r
+ long long startoffset;\r
+ long long lastrefvideotime;\r
+ long long lastrefaudiotime;\r
+ bool dsinited;\r
+ bool firstsynched;\r
+ bool audioon;\r
+ bool videoon;\r
+ bool iframemode;\r
+ UCHAR pseudotvsize;\r
+ REFERENCE_TIME lastreftimeRT;\r
+ ULLONG lastreftimePTS;\r
+ unsigned int videoposx;\r
+ unsigned int videoposy;\r
+ int lastaudiomode;\r
+ int audiovolume;\r
+ UCHAR aud_type;\r
+ unsigned int vmrdeinterlacing; \r
+ VideoPresenter currentpresenter;\r
+#ifdef DS_DEBUG\r
+ DWORD graphidentifier;\r
+#endif\r
+};\r
+\r
+#endif\r
+\r
+\r
+\r
-/*
- Copyright 2004-2005 Chris Tallon, Andreas Vogel
-
- 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 <time.h>
-
-#include "vmediaview.h"
-
-#include "vpicturebanner.h"
-#include "vcolourtuner.h"
-#include "audioplayer.h"
-#include "timers.h"
-#include "boxx.h"
-#include "wselectlist.h"
-#include "remote.h"
-#include "wsymbol.h"
-#include "boxstack.h"
-#include "vdr.h"
-#include "media.h"
-#include "video.h"
-#include "vinfo.h"
-#include "i18n.h"
-#include "message.h"
-#include "command.h"
-#include "mediaoptions.h"
-#include "mediaplayer.h"
-#include "log.h"
-
-const int VMediaView::EVENT_SLIDESHOW=100;
-const int VMediaView::EVENT_DRAWINGDONE=101;
-const int VMediaView::EVENT_DRAWINGERROR=102;
-const int VMediaView::EVENT_DIRECTORYDONE=103;
-
-
-/**
- * the combined user interface for pictures and audio
- * has 2 surfaces to enable drawing in a separate thread
- * the info display can either show a picture info or and audio info
- * if the audio player comes on top it disables the picture info display
- * basically we have 3 modes:
- * - HIDDEN viewer is hidden (pictureEnabled=false, audioEnabled=false)
- * if justPlaying=true the audioplayer is still running
- * - PICTURE picture viewer on top ("slide show") - pictureEnabled=true, audioEnabled=false
- * no AudioBanner visible
- * if justPlaying=true the audio player runs in bg
- * - AUDIO audioPlayer on top ("playlist mode") - pictureEnabled=true, audioEnabled=true
- * the picture viewer is currently halted (should be able to continue if no AudioInfo)
- * no picture banner (we should have an audio banner to indicate the audio player on top!)
- * state transitions (via setPictureMode, setAudioMode)
- * - show Picture -> pictureEnabled=true,
- * only called from command handler if audioEnabled=false
- * call from mediaList only possible if audioEnabled=false
- * *** TODO: would be better to have separate function for external call/internal call
- * - play [Audio] -> if activate is set -> audioEnabled=true (-> Mode AUDIO)
- * used for calls from medialist
- * internal calls do not set activate!
- * - YELLOW key - toggle
- * if audioActive==true -> audioActive=false (new mode depends on pictureEnabled - either HIDDEN or PICTURE)
- * if audioActive==false -> audioActive=true (new mode AUDIO)
- * *** open handling if no audio file there (ignore key???) - currently empty player
- * - BACK if mode AUDIO -> audioEnabled=false, justPlaying=false
- * - BACK if mode PICTURE -> pictureEnabled=false;
- * - player StreamEnd -> audioEnabled=false (new mode depends on pciture - either HIDDEN or PICTURE)
- * info/banner handling:
- * - AudioInfo - alternativ to pictureInfo
- * off when disabling audio or after timer or with OK in AUDIO mode
- * on currently any command or player event (end/new song) when audioEnabled==true and retriggerAudioInfo=true
- * on on OK in AUDIO mode
- * - Picture Info
- * off when disabling Picture or after timer, OK, green
- * on only on green when pictureEnabled==true
- * - PictureBanner
- * 2 modes: loading/normal
- * normal:
- * off when disabling picture, OK, after timer
- * on when enabling picture, with OK
- * loading:
- * off when disabling picture and when loading done
- * on on start loading
- * *** open: do not show when audio enabled and slide show running (currently slideshow is paused)
- * - AudioBanner
- * always shown when audioEnabled=true
- * on when enabling Audio
- * off when disabling audio
- * update in play
- * timers: 1 - slide show
- * 2 - pictureBanner
- * 3 - info showtime
- * 4 - audio short update
- */
-
-#define DRAWING_THREAD
-
-Colour VMediaView::pictureBack=Colour(140,140,140);
-Colour VMediaView::infoBack=Colour(110,110,110);
-Colour VMediaView::audioBannerBack=Colour(110,110,110,20);
-//the jpeg reader
-
-//how long do we wait for a single picture chunk
-//the unit is 100ms (the timeout on the server side)
-#define MAXTRY 100
-class VPreader : public JpegReader {
- private:
- ImageReader *reader;
- VMediaView * parent;
- ULLONG size;
- bool dobreak;;
- public:
- VPreader(VMediaView *p,ImageReader *r){
- parent=p;
- size=0;
- reader=r;
- dobreak=false;
- };
- virtual ULONG readChunk(ULONG offset,ULONG len,char ** buf) {
- Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "read chunk o=%d,len=%d,buf=%p",
- offset,len,*buf);
- UINT numrec=0;
- int rt=0;
- for (int trycount=0;trycount < MAXTRY && ! dobreak && numrec == 0 && rt == 0;trycount++) {
- if (dobreak) {
- *buf=NULL;
- rt=-1;
- }
- else {
- rt=reader->getImageChunk((ULLONG)offset,(UINT)len,&numrec,(UCHAR **)buf);
- }
- }
- Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "got n=%d,buf=%p,rt=%d",
- numrec,*buf,rt);
- return numrec;
- }
- virtual int initRead(const MediaURI *uri,ULLONG *sz,ULONG factor=100) {
- Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s",uri->getDisplayName());
- Video* video = Video::getInstance();
- dobreak=false;
- int rt=MediaPlayer::getInstance()->openMedium(1,uri,sz,video->getScreenWidth()*factor/100, video->getScreenHeight()*factor/100);
- if (rt < 0) *sz=0;
- size=*sz;
- Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s returned %llu",uri->getDisplayName(),size);
- return rt;
- }
- virtual ULONG getSize() {return size;}
- //seems to be thread safe (more or less...)
- void setBreak() {
- dobreak=true;
- }
-};
-
-/**
- * a separate thread for drawing pictures
- * will be started with the sfc and the draw control
- * will send a player event when done
- */
-class DrawingThread : public Thread_TYPE {
- private:
- VMediaView *_parent;
- VPreader * _reader;
- WJpeg::JpegControl *_ctl;
- Surface *_sfc;
- Colour _colour;
- bool _interrupted;
- public:
- DrawingThread(VMediaView *parent) {
- _parent=parent;
- _reader=NULL;
- _ctl=NULL;
- _sfc=NULL;
- _interrupted=false;
- }
- virtual ~DrawingThread(){}
- bool isRunning() {
- return (threadIsActive()!=0);
- }
- bool start(WJpeg::JpegControl *ctl,Surface *sfc,VPreader *reader,Colour &c) {
- if (isRunning()) {
- return false;
- }
- _interrupted=false;
- _ctl=ctl;
- _sfc=sfc;
- _reader=reader;
- _colour=c;
- return (threadStart() == 1);
- }
- bool stop() {
- Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop initiated");
- if (threadIsActive()) {
- _interrupted=true;
- if (_reader) _reader->setBreak();
- threadStop();
- }
- Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop done");
- _reader=NULL;
- return true;
- }
- protected:
- virtual void threadMethod() {
- Log::getInstance()->log("DrawingThread",Log::DEBUG,"started");
- bool rt=WJpeg::drawJpeg(_ctl,_sfc,_reader,_colour);
- _reader=NULL;
- if (! _interrupted) {
- Message* m = new Message();
- //we misuse PLAYER_EVENT here
- m->message = Message::PLAYER_EVENT;
- m->to = _parent;
- m->from = _parent;
- m->parameter= rt?VMediaView::EVENT_DRAWINGDONE:VMediaView::EVENT_DRAWINGERROR;
- Command::getInstance()->postMessageFromOuterSpace(m);
- }
- Log::getInstance()->log("DrawingThread",Log::DEBUG,"finishing interrupt=%d",(int)_interrupted);
- }
- virtual void threadPostStopCleanup() {}
-
-};
-
-
-VMediaView::VMediaView(VMediaList *p)
-{
- Log::getInstance()->log("VMediaView::VMediaView", Log::DEBUG, "p=%p", this);
- audioEnabled=false;
- pictureEnabled=false;
- parent=p;
- ireader=new ImageReader(1,MediaPlayer::getInstance());
- reader=new VPreader(this,ireader);
- //the surface handling
- Video* video = Video::getInstance();
- setSize(video->getScreenWidth(), video->getScreenHeight());
- createBuffer();
- sfc2=getSurface();
- surface=NULL;
- //create the second surface
- createBuffer();
- sfc1=getSurface();
- originalh=area.h;
- originalw=area.w;
- //disable the surface
- area.h=1;
- area.w=1;
- //banners and infos
- pictureBanner=NULL;
- slideshow=false;
- pictureError=NULL;
- currentPicture=NULL;
- info=NULL;
- pictureLoading=false;
-
- //picture settings
- showtime=INITIAL_SHOWTIME;
- rotate=WJpeg::ROT_0;
- currentScale=1;
- options=MediaOptions::getInstance();
- VColourTuner::initFactors();
- int st=options->getIntOption("SlideShowInterval");
- if (st > 0) showtime=st;
- ctl.area.w=originalw;
- ctl.area.h=originalh;
- ctl.enlarge=false;
- ctl.scaleafter=options->getIntOption("ScaleFactor");
- const char * mode=options->getStringOption("PictureMode");
- if (strcmp(mode,"clip") == 0) ctl.mode=WJpeg::CROP;
- else if (strcmp(mode,"letter") == 0) ctl.mode=WJpeg::LETTER;
- else if (strcmp(mode,"clipfactor") == 0) ctl.mode=WJpeg::CROPPERCENT;
- ctl.scaleAmount=options->getIntOption("PictureSize");
- if (ctl.scaleAmount < 10) ctl.scaleAmount=10;
- if (ctl.scaleAmount > 200) ctl.scaleAmount=200;
- ctl2=ctl;
- cropmode=ctl.mode;
- //current control is the one used for DISPLAY (not the one for drawing - this is the other one)
- //this is closely coupled to the surface - i.e. ctl is for sfc1, ctl2 for sfc2
- currentControl=&ctl;
- bannerEnabled=true;
- pictureShowing=false;
-
- //audio player
-
- barBlue.set(0, 0, 150, 150);
- audioError=NULL;
- currentAudio=NULL;
- justPlaying=false;
- playall=false;
- retriggerAudioInfo=false;
- audioBanner=NULL;
- drawingThread=new DrawingThread(this);
-}
-
-VMediaView::~VMediaView()
-{
- Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "p=%p,secondSfc=%s", this,(secondSurface()?"true":"false"));
- destroyPictureBanner();
- if (currentPicture) delete currentPicture;
- Timers::getInstance()->cancelTimer(this,1);
- Timers::getInstance()->cancelTimer(this,2);
- Timers::getInstance()->cancelTimer(this,3);
- Timers::getInstance()->cancelTimer(this,4);
- Timers::getInstance()->cancelTimer(this,5);
- destroyInfo();
- destroyAudioBanner();
- if (getPlayer(false)) {
- AudioPlayer::getInstance(NULL,false)->shutdown();
- }
- if (currentAudio) delete currentAudio;
- drawingThread->stop();
- ireader->shutdown();
- delete ireader;
- delete reader;
- if (secondSurface()) {
- delete sfc1;
- sfc1=NULL;
- }
- else {
- delete sfc2;
- sfc2=NULL;
- }
- MediaPlayer::getInstance()->closeMediaChannel(1);
- MediaPlayer::getInstance()->closeMediaChannel(2);
- Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "done p=%p", this);
-}
-
-void VMediaView::setPictureMode(bool act) {
- Log::getInstance()->log("VMediaView", Log::DEBUG, "set pictureMode %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);
- if ( act) {
- if ( ! pictureEnabled && ! audioEnabled) {
- area.h=originalh;
- area.w=originalw;
- showPictureBanner();
- parent->updateAll();
- }
- if (! pictureEnabled) {
- //we newly enable the picture - so clear the screen
- draw();
- BoxStack::getInstance()->update(this);
- if (slideshow) startSlideshow();
- }
- }
- else
- {
- if ( pictureEnabled) {
- destroyPictureBanner();
- stopSlideshow(false);
-#ifdef DRAWING_THREAD
- drawingThread->stop();
-#endif
- if (! audioEnabled) {
- destroyInfo();
- area.w=1;
- area.h=1;
- draw();
- parent->updateAll();
- }
- }
- pictureShowing=false;
- }
- pictureEnabled=act;
-}
-
-//we can disable audio without automatically hiding us
-//this will become strange - we are visible but do not handle
-//keys - so if you call setAudioMode(false,false) be sure
-//to call setAudioMode(false,true) afterwards
-//it is only here to give the list a chance to start a new play
-//when we call directoryDone
-void VMediaView::setAudioMode(bool act,bool doHiding) {
- Log::getInstance()->log("VMediaView", Log::DEBUG, "setAudioMode %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);
- if ( act) {
- if (! audioEnabled) {
- if (! pictureEnabled) {
- area.w=originalw;
- area.h=originalh;
- draw(); //empty screen if no picture
- parent->updateAll();
- }
- destroyPictureBanner();
-
- }
- audioEnabled=true;
- showAudioBanner();
- showAudioInfo();
- }
- else
- {
- if ( audioEnabled) {
- audioEnabled=false;
- destroyInfo();
- destroyAudioBanner();
- }
- if (! pictureEnabled && doHiding) {
- area.w=1;
- area.h=1;
- draw();
- parent->updateAll();
- }
- else {
- //picture now on top
- if (havePictureBanner && ! pictureBanner) showPictureBanner();
- }
- }
-}
-
-
-
-void VMediaView::draw()
-{
- Log::getInstance()->log("VMediaView::draw", Log::DEBUG, "pictureError=%s,p=%p", pictureError,this);
-
- if (pictureShowing ) fillColour(pictureBack);
- else fillColour(Colour::BLACK);
- if (pictureError) {
- drawText(pictureError,100,area.h/2,Colour::LIGHTTEXT);
- return;
- }
-}
-
-
-int VMediaView::handleCommand(int command)
-{
- Log::getInstance()->log("VMediaView::handleCommand", Log::DEBUG, "cmd=%d,p=%p", command,this);
- if ( !audioEnabled && ! pictureEnabled ) {
- //only handle YELLOW
- if (command == Remote::YELLOW) {
- setAudioMode(true);
- return 1;
- }
- return 0;
- }
- if ( ! audioEnabled) {
- //------------------------- command in mode PICTURE (i.e. picture is on top) ----------------
- //picture on top
- int rt=1;
- switch(command)
- {
- case Remote::DF_UP:
- case Remote::UP:
- case Remote::SKIPBACK:
- rotate=WJpeg::ROT_0;
- showPicture(VMediaList::MV_PREV,slideshow,true);
- rt= 2;
- break;
- case Remote::FORWARD:
- if (showtime > 1) showtime--;
- updatePictureBanner(true);
- break;
- case Remote::DF_DOWN:
- case Remote::DOWN:
- case Remote::SKIPFORWARD:
- rotate=WJpeg::ROT_0;
- showPicture(VMediaList::MV_NEXT,slideshow,true);
- rt= 2;
- break;
- case Remote::REVERSE:
- if (showtime < 50 ) showtime++;
- updatePictureBanner(true);
- break;
- case Remote::OK:
- {
- if (pictureBanner) {
- destroyPictureBanner();
- destroyInfo();
- havePictureBanner=false;
- }
- else {
- havePictureBanner=true;
- showPictureBanner(pictureLoading);
- }
- rt= 2;
- }
- break;
- case Remote::PLAY:
- {
- slideshow=true;
- rotate=WJpeg::ROT_0;
- showPicture(VMediaList::MV_NEXT,slideshow,true);
- rt= 2;
- }
- break;
- case Remote::PAUSE:
- if (slideshow) {
- stopSlideshow(true);
- updatePictureBanner();
- }
- else {
- slideshow=true;
- rotate=WJpeg::ROT_0;
- showPicture(VMediaList::MV_NEXT,slideshow,true);
- }
- rt= 2;
- break;
- case Remote::STOP:
- stopSlideshow(true);
- showtime=INITIAL_SHOWTIME;
- updatePictureBanner();
- rt= 2;
- break;
- case Remote::RED:
- switch(rotate) {
- case WJpeg::ROT_0:
- rotate=WJpeg::ROT_90;
- break;
- case WJpeg::ROT_90:
- rotate=WJpeg::ROT_180;
- break;
- case WJpeg::ROT_180:
- rotate=WJpeg::ROT_270;
- break;
- case WJpeg::ROT_270:
- rotate=WJpeg::ROT_0;
- break;
- }
- showPicture(VMediaList::MV_NONE,slideshow,true);
- rt=2;
- break;
- case Remote::GREEN:
- if (info) destroyInfo();
- else showPictureInfo();
- rt=2;
- break;
- case Remote::BLUE:
- switch (cropmode) {
- case WJpeg::CROP:
- cropmode=WJpeg::LETTER;
- break;
- case WJpeg::LETTER:
- cropmode=WJpeg::CROPPERCENT;
- break;
- default:
- cropmode=WJpeg::CROP;
- break;
- }
- showPicture(VMediaList::MV_NONE,slideshow,true);
- rt=2;
- break;
- case Remote::MENU: {
- stopSlideshow(true);
- destroyPictureBanner();
- destroyInfo();
- VColourTuner *ct=new VColourTuner();
- BoxStack::getInstance()->add(ct);
- ct->draw();
- BoxStack::getInstance()->update(ct);
- rt=2;
-
- } break;
- case Remote::BACK:
- {
- setPictureMode(false);
- rt= 2;
- }
- break;
- case Remote::YELLOW:
- {
- setAudioMode(true);
- }
- }
- return rt;
- }
- else
- {
- int rt=1;
- bool updateInfo=false;
- //------------------------- command in mode AUDIO (i.e. audio is on top) ----------------
- switch(command)
- {
- case Remote::YELLOW:
- setAudioMode(false);
- rt=2;
- break;
- case Remote::DF_UP:
- case Remote::UP:
- play(playall,false,VMediaList::MV_PREV);
- rt= 2;
- break;
- case Remote::FORWARD:
- if (! audioError) getPlayer()->fastForward();
- updateInfo=true;
- rt=2;
- break;
- case Remote::DF_DOWN:
- case Remote::DOWN:
- play(playall,false,VMediaList::MV_NEXT);
- rt= 2;
- break;
- case Remote::SKIPFORWARD:
- if (! audioError) getPlayer()->skipForward(10);
- rt=2;
- break;
- case Remote::SKIPBACK:
- if (! audioError) getPlayer()->skipBackward(10);
- rt=2;
- break;
- case Remote::REVERSE:
- rt=2;
- break;
- case Remote::ZERO:
- if (! audioError) getPlayer()->jumpToPercent(0);
- rt=2;
- break;
- case Remote::ONE:
- if (! audioError) getPlayer()->jumpToPercent(10);
- rt=2;
- break;
- case Remote::TWO:
- if (! audioError) getPlayer()->jumpToPercent(20);
- rt=2;
- break;
- case Remote::THREE:
- if (! audioError) getPlayer()->jumpToPercent(30);
- rt=2;
- break;
- case Remote::FOUR:
- if (! audioError) getPlayer()->jumpToPercent(40);
- rt=2;
- break;
- case Remote::FIVE:
- if (! audioError) getPlayer()->jumpToPercent(50);
- rt=2;
- break;
- case Remote::SIX:
- if (! audioError) getPlayer()->jumpToPercent(60);
- rt=2;
- break;
- case Remote::SEVEN:
- if (! audioError) getPlayer()->jumpToPercent(70);
- rt=2;
- break;
- case Remote::EIGHT:
- if (! audioError) getPlayer()->jumpToPercent(80);
- rt=2;
- break;
- case Remote::NINE:
- if (! audioError) getPlayer()->jumpToPercent(90);
- rt=2;
- break;
- case Remote::OK:
- case Remote::GREEN:
- {
- if (info) {
- destroyInfo();
- retriggerAudioInfo=false;
- }
- else {
- retriggerAudioInfo=true;
- showAudioInfo();
- }
- if (getPlayer()->getState() == AudioPlayer::S_ERROR) {
- if (playall) play(playall,false,VMediaList::MV_NEXT);
- }
- rt= 2;
- }
- break;
- case Remote::PLAY:
- {
- if (! audioError) getPlayer()->unpause();
- updateInfo=true;
- if (getPlayer()->getState() != AudioPlayer::S_ERROR) ;
- else if (playall) play(playall,false,VMediaList::MV_NEXT);
- rt= 2;
- }
- break;
- case Remote::PAUSE:
- if (! audioError) getPlayer()->pause();
- updateInfo=true;
- rt= 2;
- break;
- case Remote::STOP:
- getPlayer()->stop();
- justPlaying=false;
- updateInfo=true;
- rt= 2;
- break;
- case Remote::BACK:
- {
- getPlayer()->stop();
- playall=false;
- retriggerAudioInfo=false;
- justPlaying=false;
- setAudioMode(false);
- if (! pictureShowing) setPictureMode(false); //could have been delayed
- rt= 2;
- }
- break;
- }
- if (audioEnabled && updateInfo) updateAudioInfo();
- return rt;
- }
-}
-
-void VMediaView::processMessage(Message* m)
-{
- Log::getInstance()->log("VMediaView::processMessage", Log::DEBUG, "cmd=%lu,p=%lu", m->message,m->parameter);
- if (m->message == Message::MOUSE_MOVE)
- {
- ;
- }
- else if (m->message == Message::MOUSE_LBDOWN)
- {
-
- //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::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
- }
- }
- else if (m->message = Message::PLAYER_EVENT) {
- switch (m->parameter) {
- case EVENT_SLIDESHOW:
- if (! pictureEnabled) break; //old timer msg...
- //if (! audioEnabled) {
- if (true) {
- if (slideshow) {
- rotate=WJpeg::ROT_0;
- showPicture(VMediaList::MV_NEXT,true,false);
- startSlideshow();
- }
- }
- break;
- case EVENT_DRAWINGERROR:
- drawingDone(true);
- break;
- case EVENT_DRAWINGDONE:
- drawingDone(false);
- break;
- case EVENT_DIRECTORYDONE:
- //just disable audio without (poetntially) hiding us
- //this gives the list a chance to decide whether audio
- //should be on top afterwards without showing the list
- //immediately
- setAudioMode(false,false);
- parent->directoryDone();
- if (! pictureShowing) setPictureMode(false);
- if (! justPlaying) setAudioMode(false);
- break;
- case AudioPlayer::STREAM_ERR:
- case AudioPlayer::STREAM_END:
- if (playall) play(playall,false,VMediaList::MV_NEXT);
- else {
- setAudioMode(false);
- justPlaying=false;
- }
- break;
- case AudioPlayer::SHORT_UPDATE:
- if (info && audioEnabled ) {
- drawAudioClocks();
- BoxStack::getInstance()->update(info,&clocksRegion);
- BoxStack::getInstance()->update(info,&barRegion);
- Timers::getInstance()->setTimerD(this, 4, 1);
- }
- break;
- case AudioPlayer::NEW_SONG:
- if (audioEnabled) updateAudioInfo();
- break;
- case AudioPlayer::CONNECTION_LOST:
- if (audioEnabled) destroyInfo();
- if (AudioPlayer *player=getPlayer(false)) {
- player->shutdown();
- player=NULL;
- }
- Command::getInstance()->connectionLost();
- break;
- }
- }
-}
-
-
-VMediaView * VMediaView::createViewer(VMediaList * mparent) {
- Log::getInstance()->log("VMediaView::createViewer", Log::DEBUG, "p=%p",
- mparent);
- VMediaView *vmn=new VMediaView(mparent);
- BoxStack::getInstance()->add(vmn);
- vmn->draw();
- BoxStack::getInstance()->update(vmn);
- return vmn;
-}
-
-void VMediaView::startSlideshow() {
- slideshow=true;
- if (! pictureLoading) Timers::getInstance()->setTimerD(this,1,showtime);
-}
-
-void VMediaView::stopSlideshow(bool hard) {
- if (hard) slideshow=false;
- Timers::getInstance()->cancelTimer(this,1);
-}
-
-
-void VMediaView::showPicture(ULONG move,bool bslideshow,bool activateBanner) {
- pictureShowing=true;
- setPictureMode(true);
- stopSlideshow(true);
-#ifdef DRAWING_THREAD
- drawingThread->stop();
-#endif
- slideshow=bslideshow;
- Media *newPicture=parent->getMedia(MEDIA_TYPE_PICTURE,move);
- if ( ! newPicture) {
- pictureShowing=false;
- if (!audioEnabled) {
- //within the event handler first directoryDone is called
- //and afterwards everything is stopped if nothing new
- sendCommandMsg(EVENT_DIRECTORYDONE);
- }
- slideshow=false;
- }
- else
- {
- pictureShowing=true;
- if (currentPicture) {
- delete currentPicture;
- currentPicture=NULL;
- }
- currentPicture=newPicture;
- loadPicture(currentPicture,activateBanner);
- }
-}
-
-//the real picture drawing method
-//will start drawing on a new surface and will switch it wehn done
-
-int VMediaView::loadPicture(Media *md,bool activateBanner) {
- pictureError=NULL;
- if (! md) return 1;
- if (! md->getURI()) {
- pictureError=tr("No media found");
- Log::getInstance()->log("VMediaView::load",Log::ERR,"no URI in media");
- return 1;
- }
- Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",
- md->getURI()->getName(),this);
- //do we have a pictureBanner?
- havePictureBanner=pictureBanner!=NULL || activateBanner;
- pictureLoading=true;
-#ifdef DRAWING_THREAD
- if (!audioEnabled && havePictureBanner ) showPictureBanner(true);
- drawingThread->stop();
-#else
- showPictureBanner(true);
-#endif
- ireader->stop();
- ULLONG size=0;
- int rtok=reader->initRead(md->getURI(),&size,ctl.scaleAmount); //scaleAmount is the same for both...
- if (rtok == 0) {
- //now we can really draw
- //get the surface for drawing
- Surface * drawSurface=NULL;
- WJpeg::JpegControl *drawCtl=NULL;
- getDrawingParam(drawSurface,drawCtl);
- drawCtl->error[0]=0;
- drawCtl->rotation=rotate;
- drawCtl->mode=cropmode;
- drawCtl->compressedSize=size;
-#ifdef DRAWING_THREAD
- bool ok=drawingThread->start(drawCtl,drawSurface,reader,pictureBack);
- if (! ok) {
- Log::getInstance()->log("VMediaView::load", Log::ERR, "unable to start drawing thread");
- pictureError=tr("JpegError");
- pictureLoading=false;
- destroyPictureBanner();
- return 1;
- }
- return 0;
-#else
- //here we could hand this over to the drawing thread
- bool ok=WJpeg::drawJpeg(drawCtl,drawSurface,reader,pictureBack);
- drawingDone(!ok);
- return ok?0:1;
-#endif
- }
- pictureLoading=false;
- return 1;
-}
-
-void VMediaView::drawingDone(bool hasError) {
- pictureLoading=false;
- destroyPictureBanner(); //disable loading indication (or real banner)
- if (! hasError) {
- switchSurface();
- Log::getInstance()->log("VMediaView::drawingDone", Log::DEBUG, "success: sfc now=%p",surface);
- pictureError=NULL;
- //only show the pictureBanner if it was there before
- if (havePictureBanner && ! audioEnabled) showPictureBanner();
- Log::getInstance()->log("VMediaView::load", Log::DEBUG, "success" );
- updatePictureInfo(); //will only do somethng if pictureEnabled
- }
- else
- {
- pictureError=tr("JpegError");
- if (pictureEnabled) {
- draw();
- destroyInfo();
- }
- }
- MediaPlayer::getInstance()->closeMediaChannel(1);
-#ifndef DRAWING_THREAD
- if (audioEnabled) showAudioBanner();
-#endif
- if (slideshow) startSlideshow();
- BoxStack::getInstance()->update(this);
-}
-
-void VMediaView::showPictureBanner(bool loading) {
- //we are in the main thread - so we can (and must) safely hard destroy/create the banner
- Timers::getInstance()->cancelTimer(this,2);
- if (! currentPicture) {
- //hmm...
- destroyPictureBanner(false);
- return;
- }
- if (pictureBanner) destroyPictureBanner(false);
- if (! pictureEnabled || ! bannerEnabled) return;
- pictureBanner= new VPictureBanner(loading, slideshow);
- pictureBanner->fillColour(infoBack);
- if (! loading) {
- int len=strlen(currentPicture->getFileName())+Media::TIMEBUFLEN+20;
- char *buf=new char[len];
- char tbuf[Media::TIMEBUFLEN];
- SNPRINTF(buf,len,"%c%02ds%c %s %s " ,
- slideshow?' ':'[',
- showtime,
- slideshow?' ':']',
- currentPicture->getTimeString(tbuf),
- currentPicture->getFileName()
- );
- pictureBanner->setText(buf);
- delete [] buf;
- }
- else {
- char *buf=new char[strlen(currentPicture->getDisplayName())+50];
- SNPRINTF(buf,50,"%s %s",tr("Loading"), currentPicture->getDisplayName());
- pictureBanner->setText(buf);
- delete buf;
- }
- pictureBanner->draw();
- if (! loading ) Timers::getInstance()->setTimerD(this,2,8);
- BoxStack::getInstance()->add(pictureBanner);
- BoxStack::getInstance()->update(pictureBanner);
- }
-
-void VMediaView::destroyPictureBanner(bool fromTimer) {
- if (pictureBanner) {
- if (fromTimer) sendViewMsg(pictureBanner);
- else BoxStack::getInstance()->remove(pictureBanner);
- pictureBanner=NULL;
- if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);
- }
-}
-void VMediaView::updatePictureBanner(bool loading) {
- if (pictureBanner ) {
- showPictureBanner(loading);
- }
-}
-void VMediaView::timercall(int clientref) {
- Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "id=%d",clientref);
- switch(clientref)
- {
- case 4:
- {
- sendCommandMsg(AudioPlayer::SHORT_UPDATE);
- break;
- }
- case 3:
- {
- Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "infoEnd");
- destroyInfo(true);
- if (audioEnabled) {
- //we only did show the audio error info if audio is enabled
- bool stillError=false;
- if (AudioPlayer * player=getPlayer(false)) {
- stillError=player->getState()==AudioPlayer::S_ERROR;
- }
- if (stillError) {
- sendCommandMsg(AudioPlayer::STREAM_END);
- }
- }
- break;
- }
- case 1:
- if (! slideshow) return;
- Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "slideshow");
- sendCommandMsg(EVENT_SLIDESHOW);
- break;
- case 2:
- Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "pictureBannerEnd");
- destroyPictureBanner(true);
- break;
- }
-
- }
-
-#define INFOBUF 2000
-void VMediaView::showPictureInfo(){
- if (! pictureEnabled || audioEnabled) return;
- if (info) destroyInfo();
- if (! currentPicture) return;
-
- info=new VInfo();
- info->setTitleText(currentPicture->getFileName());
- info->setDropThrough();
- info->setSize(500, 300);
- info->createBuffer();
- info->setBorderOn(1);
- info->setTitleBarOn(1);
-
- if (Video::getInstance()->getFormat() == Video::PAL)
- info->setPosition(100, 180);
- else
- info->setPosition(100, 150);
- char buf[INFOBUF];
- char tbuf[Media::TIMEBUFLEN];
- //modes should come from mediaoptions...
- const char *mode=NULL;
- switch (currentControl->mode) {
- case WJpeg::CROPPERCENT:
- mode="clipfactor";
- break;
- case WJpeg::LETTER:
- mode="letter";
- break;
- default:
- mode="clip";
- break;
- }
- const char *dirname=parent->getDirname(MEDIA_TYPE_PICTURE);
- int ldir=0;
- const char *prfx="";
- if (dirname) ldir=strlen(dirname);
- if (ldir > 35){
- dirname=dirname+ldir-35;
- prfx="...";
- }
- SNPRINTF(buf,INFOBUF,"%s= %s%s\n%s= %u x %u\n%s= %lu kBytes\n%s= %s\n%s= %u\n%s= %u%%\n%s= %s",
- tr("Directory"), prfx,dirname,
- tr("Format(px)"),currentControl->picw,currentControl->pich,
- tr("Filesize"),currentControl->compressedSize/1000,
- tr("Time"),currentPicture->getTimeString(tbuf),
- tr("Rotation"),90*currentControl->finalRotation,
- tr("Scale"),currentControl->scale,
- tr("Picture Mode"),mode );
- info->setMainText(buf);
- info->draw();
- BoxStack::getInstance()->add(info);
- BoxStack::getInstance()->update(info);
- Timers::getInstance()->setTimerD(this,3,8);
-}
-void VMediaView::updatePictureInfo(){
- if (info) {
- showPictureInfo();
- }
-}
-void VMediaView::destroyInfo(bool fromTimer){
- if (info) {
- if (! fromTimer) {
- Log::getInstance()->log("VMediaView",Log::DEBUG,"remove info %p",info);
- BoxStack::getInstance()->remove(info);
- }
- else {
- Log::getInstance()->log("VMediaView",Log::DEBUG,"trigger remove info %p",info);
- sendViewMsg(info);
- }
- info=NULL;
- }
- if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);
- if (! fromTimer) Timers::getInstance()->cancelTimer(this,4);
-}
-
-void VMediaView::sendViewMsg(Boxx *v) {
- Message* m = new Message();
- m->message = Message::CLOSE_ME;
- m->to = BoxStack::getInstance();
- m->from = v;
- m->parameter=(ULONG)v;
- Command::getInstance()->postMessageFromOuterSpace(m);
-}
-void VMediaView::sendCommandMsg(int command) {
- Message* m = new Message();
- //we misuse PLAYER_EVENT here
- m->message = Message::PLAYER_EVENT;
- m->to = this;
- m->from = this;
- m->parameter= command;
- Command::getInstance()->postMessageFromOuterSpace(m);
-}
-
-void VMediaView::enableBanner(bool enable) {
- bannerEnabled=false;
- updatePictureBanner();
-}
-
-void VMediaView::getDrawingParam(Surface *&sfc,WJpeg::JpegControl *&c){
- if (secondSurface()) {
- //we currently display on sfc2
- sfc=sfc1;
- c=&ctl;
- }
- else {
- sfc=sfc2;
- c=&ctl2;
- }
-}
-void VMediaView::switchSurface(){
- if (secondSurface()) {
- //now we switch to sfc1
- surface=sfc1;
- currentControl=&ctl;
- }
- else {
- surface=sfc2;
- currentControl=&ctl2;
- }
-}
-
-AudioPlayer * VMediaView::getPlayer(bool createIfNeeded)
-{
- AudioPlayer* rt=AudioPlayer::getInstance(this,false);
- if (! createIfNeeded && rt == NULL) return NULL;
- if (rt == NULL) {
- rt=AudioPlayer::getInstance(this);
- rt->run();
- }
- return rt;
-}
-
-bool VMediaView::isAudioPlaying() {
- Log::getInstance()->log("VMediaView::isPlaying", Log::DEBUG, "rt=%s", justPlaying?"true":"false");
- return justPlaying;
-}
-
-
-
-
-
-
-int VMediaView::play(bool all,bool activate,ULONG move,bool showInfo) {
- int rt=0;
- if (getPlayer(false)) getPlayer(false)->stop();
- justPlaying=false;
- if (currentAudio) delete currentAudio;
- currentAudio=NULL;
- playall=all;
- currentAudio=parent->getMedia(MEDIA_TYPE_AUDIO,move);
- audioError=NULL;
- if ( ! currentAudio || ! currentAudio->getURI()) {
- Log::getInstance()->log("VMediaView::load", Log::ERR, "no URI in media");
- audioError=tr("no audio file");
- if (audioEnabled) sendCommandMsg(EVENT_DIRECTORYDONE);
- rt= -1;
- }
- else {
- Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",
- currentAudio->getURI()->getName(),this);
- int wseq=getPlayer()->play(currentAudio->getURI());
- if (getPlayer()->waitForSequence(5,wseq)<0) {
- audioError=tr("unable to open audio file");
- rt= -1;
- }
- else {
- justPlaying=true;
- rt=0;
- }
- Log::getInstance()->log("VMediaView", Log::DEBUG, "player started for %s",currentAudio->getURI()->getName());
- }
- if (activate && ! audioEnabled){
- if (showInfo) retriggerAudioInfo=true;
- setAudioMode(true);
- }
- else {
- //avoid duplicate creation of banner and info
- showAudioBanner();
- showAudioInfo();
- }
- if (activate && (! currentPicture || ! pictureShowing)) draw();
- BoxStack::getInstance()->update(this);
- return rt;
-}
-
-void VMediaView::showAudioInfo() {
- if (! audioEnabled) return;
- Timers::getInstance()->cancelTimer(this,4);
- Timers::getInstance()->cancelTimer(this,3);
- if (info) destroyInfo();
- if (! retriggerAudioInfo) return;
- drawAudioInfo();
- bool playerError=getPlayer()->getState()==AudioPlayer::S_ERROR || audioError;
- if (! playerError) Timers::getInstance()->setTimerD(this,3,AUDIOBANNER_TIME);
- else Timers::getInstance()->setTimerD(this,3,AUDIOERROR_TIME);
- if (! playerError) Timers::getInstance()->setTimerD(this,4, 1);
- BoxStack::getInstance()->update(info);
- }
-
-void VMediaView::updateAudioInfo() {
- if (info) {
- showAudioInfo();
- }
-}
-
-void VMediaView::drawAudioInfo(){
- Log::getInstance()->log("VMediaView",Log::DEBUG, "draw banner for %p",info);
- const char *title=NULL;
- char *playerTitle=NULL;
- bool playerError=false;
- int numlines=0;
- int len=0;
- int num=0;
- const char *pl=tr("Playlist");
- const char *first=NULL;
- char *playerInfo=NULL;
- if (audioError) {
- if (getPlayer()->getState() == AudioPlayer::S_PLAY) audioError=NULL;
- }
- if (! currentAudio && ! audioError) audioError=tr("no audio file");
- if (audioError ) {
- title=tr("MediaError");
- }
- else {
- playerTitle=getPlayer()->getTitle();
- if (playerTitle) title=playerTitle;
- else title=currentAudio->getDisplayName();
- num=parent->getNumEntries(MEDIA_TYPE_AUDIO,currentAudio->index);
- playerError=getPlayer()->getState() == AudioPlayer::S_ERROR;
- //1more line for long dirs
- numlines=playall?5:4;
- }
- if (playerError) {
- numlines=3;
- first=tr("Unable to play audio file");
- len=strlen(first)+3;
- }
- else if (audioError) {
- numlines=3;
- first=audioError;
- len=strlen(first)+3;
- }
- else {
- playerInfo=getPlayer()->getID3Info();drawText(tr("Loading"),5,3,Colour::LIGHTTEXT);
- len=strlen(currentAudio->getDisplayName())+strlen(pl)+30+strlen(parent->getDirname(MEDIA_TYPE_AUDIO))+Media::TIMEBUFLEN+110;
- if (playerInfo) {
- for (UINT i=0;i<strlen(playerInfo);i++)
- if (playerInfo[i] == '\n') numlines++;
- len+=strlen(playerInfo);
- first=playerInfo;
- }
- else {
- first="";
- }
- }
- destroyInfo();
- info=new VInfo();
- UINT height=numlines*30+60;
- UINT vheight=Video::getInstance()->getScreenHeight();
- UINT vwidth=Video::getInstance()->getScreenWidth();
- if (height > vheight-2*AUDIOBANNER_BOTTOM_MARGIN)
- height=vheight-2*AUDIOBANNER_BOTTOM_MARGIN;
- info->setSize(vwidth -2*AUDIOBANNER_X_MARGIN, height);
- info->createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);
- }
- else
- {
- info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);
- }
-
- info->setTitleBarOn(0);
- info->setDropThrough();
- //from vvideorec
- //set the regions for the closcks and bars on banner
- barRegion.x = info->getWidth()-AUDIOBARLEN-20;
- barRegion.y = info->getHeight() - 30; // FIXME, need to be - 1? and below?
- barRegion.w = info->getWidth()-AUDIOBARLEN+10;
- barRegion.h = 30;
-
- clocksRegion.x = 130;
- clocksRegion.y = barRegion.y + 3;
- clocksRegion.w = 190;
- clocksRegion.h = surface->getFontHeight();
- Log::getInstance()->log("VMediaView",Log::DEBUG,"created AudioInfo %p",info);
- BoxStack::getInstance()->add(info);
- char *buf=new char [len];
- if (playerError || audioError) {
- SNPRINTF(buf,len,"%s",first);
- }
- else {
- char tbuf[Media::TIMEBUFLEN];
- if (playall) {
- SNPRINTF(buf,len,"%s\n"
- "%s:%s\n"
- "%s: %d/%d\n"
- "%s:%s\n"
- "%s:%s\n",
- first,
- tr("FileName"),currentAudio->getDisplayName(),
- pl,num,parent->getNumEntries(MEDIA_TYPE_AUDIO),
- tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),
- tr("Time"),currentAudio->getTimeString(tbuf));
- }
- else {
- SNPRINTF(buf,len,"%s\n"
- "%s:%s\n"
- "%s:%s\n"
- "%s:%s\n",
- first,
- tr("FileName"),currentAudio->getDisplayName(),
- tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),
- tr("Time"),currentAudio->getTimeString(tbuf));
- }
- }
- Log::getInstance()->log("VMediaView",Log::DEBUG,"info: (%d)%s",strlen(buf),buf);
- //now the real drawing functions
- info->draw();
- //title
- info->rectangle(0, 0, info->getWidth(), 30, Colour::TITLEBARBACKGROUND);
- info->drawText(title, 5, 5, Colour::LIGHTTEXT);
- info->drawPara(buf,5,32,Colour::LIGHTTEXT);
- delete [] buf;
- if (! audioError) {
- WSymbol w;
- info->TEMPADD(&w);
- int x=10;
- int ybottom=info->getHeight();
- info->rectangle(0, ybottom - barRegion.h, info->getWidth(), barRegion.h, Colour::TITLEBARBACKGROUND);
- bool drawSymbol=true;
- switch(getPlayer()->getState()) {
- case AudioPlayer::S_PAUSE:
- w.nextSymbol = WSymbol::PAUSE;
- break;
- case AudioPlayer::S_PLAY:
- w.nextSymbol = WSymbol::PLAY;
- break;
- case AudioPlayer::S_DONE:
- if (playall)
- w.nextSymbol = WSymbol::PLAY;
- else
- drawSymbol=false;
- break;
- case AudioPlayer::S_BACK:
- w.nextSymbol = WSymbol::FBWD ;
- break;
- case AudioPlayer::S_FF:
- w.nextSymbol = WSymbol::FFWD ;
- break;
- default:
- drawSymbol=false;
- break;
- }
- if (drawSymbol) {
- w.setPosition(x, ybottom-24);
- w.draw();
- }
- else {
- //stop symbol
- info->rectangle(x, ybottom - 23, 18, 16, Colour::LIGHTTEXT);
- }
- x+=30;
- drawAudioClocks();
- }
- if (playerInfo) delete playerInfo;
- if (playerTitle) delete playerTitle;
-}
-
-void VMediaView::drawAudioClocks() {
- if (! info || ! audioEnabled) return;
- Log::getInstance()->log("VMediaView::drawAudioClocks", Log::DEBUG, "");
- //draw clocks and bar
- info->rectangle(clocksRegion, Colour::TITLEBARBACKGROUND);
-
- time_t currentSec = (time_t)(getPlayer()->getCurrentTimes());
- time_t lengthSec=(time_t)(getPlayer()->getSonglen());
- struct tm cpos;
- struct tm slen;
-/* gmtime_r(¤tSec,&cpos);
- gmtime_r(&lengthSec,&slen);*/
- cpos.tm_hour=currentSec/3600;
- cpos.tm_min=(currentSec-cpos.tm_hour*3600)/60;
- cpos.tm_sec=(currentSec-cpos.tm_hour*3600-cpos.tm_min*60);
- slen.tm_hour=lengthSec/3600;;
- slen.tm_min=(lengthSec-slen.tm_hour*3600)/60;
- slen.tm_sec=(lengthSec-slen.tm_hour*3600-slen.tm_min*60);
-
- char buffer[100];
- if (currentSec >= lengthSec)
- {
- SNPRINTF(buffer,99, "-:--:-- / -:--:-- %03dk",getPlayer()->getCurrentBitrate()/1000);
- }
- else
- {
- SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i %03dk", cpos.tm_hour, cpos.tm_min, cpos.tm_sec, slen.tm_hour, slen.tm_min, slen.tm_sec,
- getPlayer()->getCurrentBitrate()/1000);
- //Log::getInstance()->log("VMediaView", Log::DEBUG, buffer);
- }
-
- info->drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
-
- // Draw progress bar
- int progBarXbase = 0;
- int barlen=250;
-
- info->rectangle(barRegion.x + progBarXbase, barRegion.y + 3, barlen+10, 24, Colour::LIGHTTEXT);
- info->rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 5, barlen+6, 20, barBlue);
-
- if (currentSec > lengthSec) currentSec=lengthSec;
- if (lengthSec == 0) return;
-
- // Draw yellow portion
- int progressWidth = (barlen+2) * currentSec / lengthSec;
- info->rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 7, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-
-}
-
-void VMediaView::showAudioBanner() {
- destroyAudioBanner();
- if (! audioEnabled) return;
- audioBanner=new VInfo();
- Log::getInstance()->log("VMediaView",Log::DEBUG,"creating AudioBanner %p", audioBanner);
- Video *v=Video::getInstance();
- audioBanner->setSize(v->getScreenWidth()-100, 36);
- audioBanner->createBuffer();
- audioBanner->setPosition(50, v->getScreenHeight()-50);
- audioBanner->fillColour(audioBannerBack);
- audioBanner->setTitleBarOn(0);
- audioBanner->setDropThrough();
- if ( ! currentAudio || ! currentAudio->getDisplayName() || audioError) {
- audioBanner->drawText(tr("AudioPlayer - not playing"),5,3,Colour::LIGHTTEXT);
- }
- else {
- char * buf=new char[strlen(currentAudio->getDisplayName())+50];
- SNPRINTF(buf,50,"%s %s",tr("AudioPlayer"),currentAudio->getDisplayName());
- audioBanner->drawText(buf,5,3,Colour::LIGHTTEXT);
- delete buf;
- }
- BoxStack::getInstance()->add(audioBanner);
- BoxStack::getInstance()->update(audioBanner);
-}
-
-void VMediaView::destroyAudioBanner() {
- if (audioBanner) {
- Log::getInstance()->log("VMediaView",Log::DEBUG,"deleting AudioBanner %p",audioBanner);
- BoxStack::getInstance()->remove(audioBanner);
- audioBanner=NULL;
- }
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon, Andreas Vogel\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include <time.h>\r
+\r
+#include "vmediaview.h"\r
+\r
+#include "vpicturebanner.h"\r
+#include "vcolourtuner.h"\r
+#include "audioplayer.h"\r
+#include "timers.h"\r
+#include "boxx.h"\r
+#include "wselectlist.h"\r
+#include "remote.h"\r
+#include "wsymbol.h"\r
+#include "boxstack.h"\r
+#include "vdr.h"\r
+#include "media.h"\r
+#include "video.h"\r
+#include "vinfo.h"\r
+#include "i18n.h"\r
+#include "message.h"\r
+#include "command.h"\r
+#include "mediaoptions.h"\r
+#include "mediaplayer.h"\r
+#include "log.h"\r
+\r
+const int VMediaView::EVENT_SLIDESHOW=100;\r
+const int VMediaView::EVENT_DRAWINGDONE=101;\r
+const int VMediaView::EVENT_DRAWINGERROR=102;\r
+const int VMediaView::EVENT_DIRECTORYDONE=103;\r
+\r
+\r
+/**\r
+ * the combined user interface for pictures and audio\r
+ * has 2 surfaces to enable drawing in a separate thread\r
+ * the info display can either show a picture info or and audio info\r
+ * if the audio player comes on top it disables the picture info display\r
+ * basically we have 3 modes:\r
+ * - HIDDEN viewer is hidden (pictureEnabled=false, audioEnabled=false)\r
+ * if justPlaying=true the audioplayer is still running\r
+ * - PICTURE picture viewer on top ("slide show") - pictureEnabled=true, audioEnabled=false\r
+ * no AudioBanner visible\r
+ * if justPlaying=true the audio player runs in bg\r
+ * - AUDIO audioPlayer on top ("playlist mode") - pictureEnabled=true, audioEnabled=true\r
+ * the picture viewer is currently halted (should be able to continue if no AudioInfo)\r
+ * no picture banner (we should have an audio banner to indicate the audio player on top!)\r
+ * state transitions (via setPictureMode, setAudioMode)\r
+ * - show Picture -> pictureEnabled=true, \r
+ * only called from command handler if audioEnabled=false\r
+ * call from mediaList only possible if audioEnabled=false\r
+ * *** TODO: would be better to have separate function for external call/internal call\r
+ * - play [Audio] -> if activate is set -> audioEnabled=true (-> Mode AUDIO)\r
+ * used for calls from medialist\r
+ * internal calls do not set activate!\r
+ * - YELLOW key - toggle\r
+ * if audioActive==true -> audioActive=false (new mode depends on pictureEnabled - either HIDDEN or PICTURE)\r
+ * if audioActive==false -> audioActive=true (new mode AUDIO)\r
+ * *** open handling if no audio file there (ignore key???) - currently empty player\r
+ * - BACK if mode AUDIO -> audioEnabled=false, justPlaying=false\r
+ * - BACK if mode PICTURE -> pictureEnabled=false;\r
+ * - player StreamEnd -> audioEnabled=false (new mode depends on pciture - either HIDDEN or PICTURE)\r
+ * info/banner handling:\r
+ * - AudioInfo - alternativ to pictureInfo\r
+ * off when disabling audio or after timer or with OK in AUDIO mode\r
+ * on currently any command or player event (end/new song) when audioEnabled==true and retriggerAudioInfo=true\r
+ * on on OK in AUDIO mode\r
+ * - Picture Info\r
+ * off when disabling Picture or after timer, OK, green\r
+ * on only on green when pictureEnabled==true\r
+ * - PictureBanner\r
+ * 2 modes: loading/normal\r
+ * normal:\r
+ * off when disabling picture, OK, after timer\r
+ * on when enabling picture, with OK\r
+ * loading:\r
+ * off when disabling picture and when loading done\r
+ * on on start loading\r
+ * *** open: do not show when audio enabled and slide show running (currently slideshow is paused)\r
+ * - AudioBanner\r
+ * always shown when audioEnabled=true\r
+ * on when enabling Audio\r
+ * off when disabling audio\r
+ * update in play\r
+ * timers: 1 - slide show\r
+ * 2 - pictureBanner\r
+ * 3 - info showtime\r
+ * 4 - audio short update\r
+ */\r
+\r
+#define DRAWING_THREAD\r
+\r
+Colour VMediaView::pictureBack=Colour(140,140,140);\r
+Colour VMediaView::infoBack=Colour(110,110,110);\r
+Colour VMediaView::audioBannerBack=Colour(110,110,110,20);\r
+//the jpeg reader\r
+\r
+//how long do we wait for a single picture chunk\r
+//the unit is 100ms (the timeout on the server side)\r
+#define MAXTRY 100 \r
+class VPreader : public JpegReader {\r
+ private:\r
+ ImageReader *reader;\r
+ VMediaView * parent;\r
+ ULLONG size;\r
+ bool dobreak;;\r
+ public:\r
+ VPreader(VMediaView *p,ImageReader *r){ \r
+ parent=p;\r
+ size=0;\r
+ reader=r;\r
+ dobreak=false;\r
+ };\r
+ virtual ULONG readChunk(ULONG offset,ULONG len,char ** buf) {\r
+ Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "read chunk o=%d,len=%d,buf=%p",\r
+ offset,len,*buf);\r
+ UINT numrec=0;\r
+ int rt=0;\r
+ for (int trycount=0;trycount < MAXTRY && ! dobreak && numrec == 0 && rt == 0;trycount++) {\r
+ if (dobreak) {\r
+ *buf=NULL;\r
+ rt=-1;\r
+ }\r
+ else {\r
+ rt=reader->getImageChunk((ULLONG)offset,(UINT)len,&numrec,(UCHAR **)buf);\r
+ }\r
+ }\r
+ Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "got n=%d,buf=%p,rt=%d",\r
+ numrec,*buf,rt);\r
+ return numrec;\r
+ }\r
+ virtual int initRead(const MediaURI *uri,ULLONG *sz,ULONG factor=100) {\r
+ Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s",uri->getDisplayName());\r
+ Video* video = Video::getInstance();\r
+ dobreak=false;\r
+ int rt=MediaPlayer::getInstance()->openMedium(1,uri,sz,video->getScreenWidth()*factor/100, video->getScreenHeight()*factor/100);\r
+ if (rt < 0) *sz=0;\r
+ size=*sz;\r
+ Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s returned %llu",uri->getDisplayName(),size);\r
+ return rt;\r
+ }\r
+ virtual ULONG getSize() {return size;}\r
+ //seems to be thread safe (more or less...)\r
+ void setBreak() {\r
+ dobreak=true;\r
+ }\r
+};\r
+\r
+/**\r
+ * a separate thread for drawing pictures\r
+ * will be started with the sfc and the draw control\r
+ * will send a player event when done\r
+ */\r
+class DrawingThread : public Thread_TYPE {\r
+ private:\r
+ VMediaView *_parent;\r
+ VPreader * _reader;\r
+ WJpeg::JpegControl *_ctl;\r
+ Surface *_sfc;\r
+ Colour _colour;\r
+ bool _interrupted;\r
+ public:\r
+ DrawingThread(VMediaView *parent) {\r
+ _parent=parent;\r
+ _reader=NULL;\r
+ _ctl=NULL;\r
+ _sfc=NULL;\r
+ _interrupted=false;\r
+ }\r
+ virtual ~DrawingThread(){}\r
+ bool isRunning() {\r
+ return (threadIsActive()!=0);\r
+ }\r
+ bool start(WJpeg::JpegControl *ctl,Surface *sfc,VPreader *reader,Colour &c) {\r
+ if (isRunning()) {\r
+ return false;\r
+ }\r
+ _interrupted=false;\r
+ _ctl=ctl;\r
+ _sfc=sfc;\r
+ _reader=reader;\r
+ _colour=c;\r
+ return (threadStart() == 1);\r
+ }\r
+ bool stop() {\r
+ Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop initiated");\r
+ if (threadIsActive()) {\r
+ _interrupted=true;\r
+ if (_reader) _reader->setBreak();\r
+ threadStop();\r
+ }\r
+ Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop done");\r
+ _reader=NULL;\r
+ return true;\r
+ }\r
+ protected:\r
+ virtual void threadMethod() {\r
+ Log::getInstance()->log("DrawingThread",Log::DEBUG,"started");\r
+ bool rt=WJpeg::drawJpeg(_ctl,_sfc,_reader,_colour);\r
+ _reader=NULL;\r
+ if (! _interrupted) {\r
+ Message* m = new Message(); \r
+ //we misuse PLAYER_EVENT here\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->to = _parent;\r
+ m->from = _parent;\r
+ m->parameter= rt?VMediaView::EVENT_DRAWINGDONE:VMediaView::EVENT_DRAWINGERROR;\r
+ Command::getInstance()->postMessageFromOuterSpace(m);\r
+ }\r
+ Log::getInstance()->log("DrawingThread",Log::DEBUG,"finishing interrupt=%d",(int)_interrupted);\r
+ }\r
+ virtual void threadPostStopCleanup() {}\r
+\r
+};\r
+\r
+\r
+VMediaView::VMediaView(VMediaList *p)\r
+{\r
+ Log::getInstance()->log("VMediaView::VMediaView", Log::DEBUG, "p=%p", this);\r
+ audioEnabled=false;\r
+ pictureEnabled=false;\r
+ parent=p;\r
+ ireader=new ImageReader(1,MediaPlayer::getInstance());\r
+ reader=new VPreader(this,ireader);\r
+ //the surface handling\r
+ Video* video = Video::getInstance();\r
+ setSize(video->getScreenWidth(), video->getScreenHeight());\r
+ createBuffer();\r
+ sfc2=getSurface();\r
+ surface=NULL;\r
+ //create the second surface\r
+ createBuffer();\r
+ sfc1=getSurface();\r
+ originalh=area.h;\r
+ originalw=area.w;\r
+ //disable the surface\r
+ area.h=1;\r
+ area.w=1;\r
+ //banners and infos\r
+ pictureBanner=NULL;\r
+ slideshow=false;\r
+ pictureError=NULL;\r
+ currentPicture=NULL;\r
+ info=NULL;\r
+ pictureLoading=false;\r
+\r
+ //picture settings\r
+ showtime=INITIAL_SHOWTIME;\r
+ rotate=WJpeg::ROT_0;\r
+ currentScale=1;\r
+ options=MediaOptions::getInstance();\r
+ VColourTuner::initFactors();\r
+ int st=options->getIntOption("SlideShowInterval");\r
+ if (st > 0) showtime=st;\r
+ ctl.area.w=originalw;\r
+ ctl.area.h=originalh;\r
+ ctl.enlarge=false;\r
+ ctl.scaleafter=options->getIntOption("ScaleFactor");\r
+ const char * mode=options->getStringOption("PictureMode");\r
+ if (strcmp(mode,"clip") == 0) ctl.mode=WJpeg::CROP;\r
+ else if (strcmp(mode,"letter") == 0) ctl.mode=WJpeg::LETTER;\r
+ else if (strcmp(mode,"clipfactor") == 0) ctl.mode=WJpeg::CROPPERCENT;\r
+ ctl.scaleAmount=options->getIntOption("PictureSize");\r
+ if (ctl.scaleAmount < 10) ctl.scaleAmount=10;\r
+ if (ctl.scaleAmount > 200) ctl.scaleAmount=200;\r
+ ctl2=ctl;\r
+ cropmode=ctl.mode;\r
+ //current control is the one used for DISPLAY (not the one for drawing - this is the other one)\r
+ //this is closely coupled to the surface - i.e. ctl is for sfc1, ctl2 for sfc2\r
+ currentControl=&ctl;\r
+ bannerEnabled=true;\r
+ pictureShowing=false;\r
+\r
+ //audio player\r
+\r
+ barBlue.set(0, 0, 150, 150);\r
+ audioError=NULL;\r
+ currentAudio=NULL;\r
+ justPlaying=false;\r
+ playall=false;\r
+ retriggerAudioInfo=false;\r
+ audioBanner=NULL;\r
+ drawingThread=new DrawingThread(this);\r
+}\r
+\r
+VMediaView::~VMediaView()\r
+{\r
+ Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "p=%p,secondSfc=%s", this,(secondSurface()?"true":"false"));\r
+ destroyPictureBanner();\r
+ if (currentPicture) delete currentPicture;\r
+ Timers::getInstance()->cancelTimer(this,1);\r
+ Timers::getInstance()->cancelTimer(this,2);\r
+ Timers::getInstance()->cancelTimer(this,3);\r
+ Timers::getInstance()->cancelTimer(this,4);\r
+ Timers::getInstance()->cancelTimer(this,5);\r
+ destroyInfo();\r
+ destroyAudioBanner();\r
+ if (getPlayer(false)) {\r
+ AudioPlayer::getInstance(NULL,false)->shutdown();\r
+ }\r
+ if (currentAudio) delete currentAudio;\r
+ drawingThread->stop();\r
+ ireader->shutdown();\r
+ delete ireader;\r
+ delete reader;\r
+ if (secondSurface()) {\r
+ delete sfc1;\r
+ sfc1=NULL;\r
+ }\r
+ else {\r
+ delete sfc2;\r
+ sfc2=NULL;\r
+ }\r
+ MediaPlayer::getInstance()->closeMediaChannel(1);\r
+ MediaPlayer::getInstance()->closeMediaChannel(2);\r
+ Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "done p=%p", this);\r
+}\r
+\r
+void VMediaView::setPictureMode(bool act) {\r
+ Log::getInstance()->log("VMediaView", Log::DEBUG, "set pictureMode %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);\r
+ if ( act) {\r
+ if ( ! pictureEnabled && ! audioEnabled) {\r
+ area.h=originalh;\r
+ area.w=originalw;\r
+ showPictureBanner();\r
+ parent->updateAll();\r
+ }\r
+ if (! pictureEnabled) {\r
+ //we newly enable the picture - so clear the screen\r
+ draw();\r
+ BoxStack::getInstance()->update(this);\r
+ if (slideshow) startSlideshow();\r
+ }\r
+ }\r
+ else \r
+ {\r
+ if ( pictureEnabled) {\r
+ destroyPictureBanner();\r
+ stopSlideshow(false);\r
+#ifdef DRAWING_THREAD\r
+ drawingThread->stop();\r
+#endif\r
+ if (! audioEnabled) {\r
+ destroyInfo();\r
+ area.w=1;\r
+ area.h=1;\r
+ draw();\r
+ parent->updateAll();\r
+ }\r
+ }\r
+ pictureShowing=false;\r
+ }\r
+ pictureEnabled=act;\r
+}\r
+\r
+//we can disable audio without automatically hiding us\r
+//this will become strange - we are visible but do not handle\r
+//keys - so if you call setAudioMode(false,false) be sure\r
+//to call setAudioMode(false,true) afterwards\r
+//it is only here to give the list a chance to start a new play\r
+//when we call directoryDone\r
+void VMediaView::setAudioMode(bool act,bool doHiding) {\r
+ Log::getInstance()->log("VMediaView", Log::DEBUG, "setAudioMode %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);\r
+ if ( act) {\r
+ if (! audioEnabled) {\r
+ if (! pictureEnabled) {\r
+ area.w=originalw;\r
+ area.h=originalh;\r
+ draw(); //empty screen if no picture\r
+ parent->updateAll();\r
+ }\r
+ destroyPictureBanner();\r
+\r
+ }\r
+ audioEnabled=true;\r
+ showAudioBanner();\r
+ showAudioInfo();\r
+ }\r
+ else \r
+ {\r
+ if ( audioEnabled) {\r
+ audioEnabled=false;\r
+ destroyInfo();\r
+ destroyAudioBanner();\r
+ }\r
+ if (! pictureEnabled && doHiding) {\r
+ area.w=1;\r
+ area.h=1;\r
+ draw();\r
+ parent->updateAll();\r
+ }\r
+ else {\r
+ //picture now on top\r
+ if (havePictureBanner && ! pictureBanner) showPictureBanner();\r
+ }\r
+ }\r
+}\r
+\r
+\r
+\r
+void VMediaView::draw()\r
+{\r
+ Log::getInstance()->log("VMediaView::draw", Log::DEBUG, "pictureError=%s,p=%p", pictureError,this);\r
+ \r
+ if (pictureShowing ) fillColour(pictureBack);\r
+ else fillColour(Colour::BLACK);\r
+ if (pictureError) {\r
+ drawText(pictureError,100,area.h/2,Colour::LIGHTTEXT);\r
+ return;\r
+ }\r
+}\r
+\r
+\r
+int VMediaView::handleCommand(int command)\r
+{\r
+ Log::getInstance()->log("VMediaView::handleCommand", Log::DEBUG, "cmd=%d,p=%p", command,this);\r
+ if ( !audioEnabled && ! pictureEnabled ) {\r
+ //only handle YELLOW\r
+ if (command == Remote::YELLOW) {\r
+ setAudioMode(true);\r
+ return 1;\r
+ }\r
+ return 0;\r
+ }\r
+ if ( ! audioEnabled) {\r
+ //------------------------- command in mode PICTURE (i.e. picture is on top) ----------------\r
+ //picture on top\r
+ int rt=1;\r
+ switch(command)\r
+ {\r
+ case Remote::DF_UP:\r
+ case Remote::UP:\r
+ case Remote::SKIPBACK:\r
+ rotate=WJpeg::ROT_0;\r
+ showPicture(VMediaList::MV_PREV,slideshow,true);\r
+ rt= 2;\r
+ break;\r
+ case Remote::FORWARD:\r
+ if (showtime > 1) showtime--;\r
+ updatePictureBanner(true);\r
+ break;\r
+ case Remote::DF_DOWN:\r
+ case Remote::DOWN:\r
+ case Remote::SKIPFORWARD:\r
+ rotate=WJpeg::ROT_0;\r
+ showPicture(VMediaList::MV_NEXT,slideshow,true);\r
+ rt= 2;\r
+ break;\r
+ case Remote::REVERSE:\r
+ if (showtime < 50 ) showtime++;\r
+ updatePictureBanner(true);\r
+ break;\r
+ case Remote::OK:\r
+ {\r
+ if (pictureBanner) {\r
+ destroyPictureBanner();\r
+ destroyInfo();\r
+ havePictureBanner=false;\r
+ }\r
+ else {\r
+ havePictureBanner=true;\r
+ showPictureBanner(pictureLoading);\r
+ }\r
+ rt= 2;\r
+ }\r
+ break;\r
+ case Remote::PLAY:\r
+ {\r
+ slideshow=true;\r
+ rotate=WJpeg::ROT_0;\r
+ showPicture(VMediaList::MV_NEXT,slideshow,true);\r
+ rt= 2;\r
+ }\r
+ break;\r
+ case Remote::PAUSE:\r
+ if (slideshow) {\r
+ stopSlideshow(true);\r
+ updatePictureBanner();\r
+ }\r
+ else {\r
+ slideshow=true;\r
+ rotate=WJpeg::ROT_0;\r
+ showPicture(VMediaList::MV_NEXT,slideshow,true);\r
+ }\r
+ rt= 2;\r
+ break;\r
+ case Remote::STOP:\r
+ stopSlideshow(true);\r
+ showtime=INITIAL_SHOWTIME;\r
+ updatePictureBanner();\r
+ rt= 2;\r
+ break;\r
+ case Remote::RED:\r
+ switch(rotate) {\r
+ case WJpeg::ROT_0:\r
+ rotate=WJpeg::ROT_90;\r
+ break;\r
+ case WJpeg::ROT_90:\r
+ rotate=WJpeg::ROT_180;\r
+ break;\r
+ case WJpeg::ROT_180:\r
+ rotate=WJpeg::ROT_270;\r
+ break;\r
+ case WJpeg::ROT_270:\r
+ rotate=WJpeg::ROT_0;\r
+ break;\r
+ }\r
+ showPicture(VMediaList::MV_NONE,slideshow,true);\r
+ rt=2;\r
+ break;\r
+ case Remote::GREEN:\r
+ if (info) destroyInfo();\r
+ else showPictureInfo();\r
+ rt=2;\r
+ break;\r
+ case Remote::BLUE:\r
+ switch (cropmode) {\r
+ case WJpeg::CROP:\r
+ cropmode=WJpeg::LETTER;\r
+ break;\r
+ case WJpeg::LETTER:\r
+ cropmode=WJpeg::CROPPERCENT;\r
+ break;\r
+ default:\r
+ cropmode=WJpeg::CROP;\r
+ break;\r
+ }\r
+ showPicture(VMediaList::MV_NONE,slideshow,true);\r
+ rt=2;\r
+ break;\r
+ case Remote::MENU: {\r
+ stopSlideshow(true);\r
+ destroyPictureBanner();\r
+ destroyInfo();\r
+ VColourTuner *ct=new VColourTuner();\r
+ BoxStack::getInstance()->add(ct);\r
+ ct->draw();\r
+ BoxStack::getInstance()->update(ct);\r
+ rt=2;\r
+ \r
+ } break;\r
+ case Remote::BACK:\r
+ {\r
+ setPictureMode(false);\r
+ rt= 2;\r
+ }\r
+ break;\r
+ case Remote::YELLOW:\r
+ {\r
+ setAudioMode(true);\r
+ }\r
+ }\r
+ return rt;\r
+ } \r
+ else \r
+ {\r
+ int rt=1;\r
+ bool updateInfo=false;\r
+ //------------------------- command in mode AUDIO (i.e. audio is on top) ----------------\r
+ switch(command)\r
+ {\r
+ case Remote::YELLOW:\r
+ setAudioMode(false);\r
+ rt=2;\r
+ break;\r
+ case Remote::DF_UP:\r
+ case Remote::UP:\r
+ play(playall,false,VMediaList::MV_PREV);\r
+ rt= 2;\r
+ break;\r
+ case Remote::FORWARD:\r
+ if (! audioError) getPlayer()->fastForward();\r
+ updateInfo=true;\r
+ rt=2;\r
+ break;\r
+ case Remote::DF_DOWN:\r
+ case Remote::DOWN:\r
+ play(playall,false,VMediaList::MV_NEXT);\r
+ rt= 2;\r
+ break;\r
+ case Remote::SKIPFORWARD:\r
+ if (! audioError) getPlayer()->skipForward(10);\r
+ rt=2;\r
+ break;\r
+ case Remote::SKIPBACK:\r
+ if (! audioError) getPlayer()->skipBackward(10);\r
+ rt=2;\r
+ break;\r
+ case Remote::REVERSE:\r
+ rt=2;\r
+ break;\r
+ case Remote::ZERO:\r
+ if (! audioError) getPlayer()->jumpToPercent(0);\r
+ rt=2;\r
+ break;\r
+ case Remote::ONE:\r
+ if (! audioError) getPlayer()->jumpToPercent(10);\r
+ rt=2;\r
+ break;\r
+ case Remote::TWO:\r
+ if (! audioError) getPlayer()->jumpToPercent(20);\r
+ rt=2;\r
+ break;\r
+ case Remote::THREE:\r
+ if (! audioError) getPlayer()->jumpToPercent(30);\r
+ rt=2;\r
+ break;\r
+ case Remote::FOUR:\r
+ if (! audioError) getPlayer()->jumpToPercent(40);\r
+ rt=2;\r
+ break;\r
+ case Remote::FIVE:\r
+ if (! audioError) getPlayer()->jumpToPercent(50);\r
+ rt=2;\r
+ break;\r
+ case Remote::SIX:\r
+ if (! audioError) getPlayer()->jumpToPercent(60);\r
+ rt=2;\r
+ break;\r
+ case Remote::SEVEN:\r
+ if (! audioError) getPlayer()->jumpToPercent(70);\r
+ rt=2;\r
+ break;\r
+ case Remote::EIGHT:\r
+ if (! audioError) getPlayer()->jumpToPercent(80);\r
+ rt=2;\r
+ break;\r
+ case Remote::NINE:\r
+ if (! audioError) getPlayer()->jumpToPercent(90);\r
+ rt=2;\r
+ break;\r
+ case Remote::OK:\r
+ case Remote::GREEN:\r
+ {\r
+ if (info) {\r
+ destroyInfo();\r
+ retriggerAudioInfo=false;\r
+ }\r
+ else {\r
+ retriggerAudioInfo=true;\r
+ showAudioInfo();\r
+ }\r
+ if (getPlayer()->getState() == AudioPlayer::S_ERROR) {\r
+ if (playall) play(playall,false,VMediaList::MV_NEXT);\r
+ }\r
+ rt= 2;\r
+ }\r
+ break;\r
+ case Remote::PLAY:\r
+ {\r
+ if (! audioError) getPlayer()->unpause();\r
+ updateInfo=true;\r
+ if (getPlayer()->getState() != AudioPlayer::S_ERROR) ;\r
+ else if (playall) play(playall,false,VMediaList::MV_NEXT);\r
+ rt= 2;\r
+ }\r
+ break;\r
+ case Remote::PAUSE:\r
+ if (! audioError) getPlayer()->pause();\r
+ updateInfo=true;\r
+ rt= 2;\r
+ break;\r
+ case Remote::STOP:\r
+ getPlayer()->stop();\r
+ justPlaying=false;\r
+ updateInfo=true;\r
+ rt= 2;\r
+ break;\r
+ case Remote::BACK:\r
+ {\r
+ getPlayer()->stop();\r
+ playall=false;\r
+ retriggerAudioInfo=false;\r
+ justPlaying=false;\r
+ setAudioMode(false);\r
+ if (! pictureShowing) setPictureMode(false); //could have been delayed\r
+ rt= 2;\r
+ }\r
+ break;\r
+ }\r
+ if (audioEnabled && updateInfo) updateAudioInfo();\r
+ return rt;\r
+ }\r
+}\r
+\r
+void VMediaView::processMessage(Message* m)\r
+{\r
+ Log::getInstance()->log("VMediaView::processMessage", Log::DEBUG, "cmd=%lu,p=%lu", m->message,m->parameter);\r
+ if (m->message == Message::MOUSE_MOVE)\r
+ {\r
+ ;\r
+ }\r
+ else if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ \r
+ //check if press is outside this view! then simulate cancel\r
+ int x=(m->parameter>>16)-getScreenX();\r
+ int y=(m->parameter&0xFFFF)-getScreenY();\r
+ if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
+ }\r
+ }\r
+ else if (m->message = Message::PLAYER_EVENT) {\r
+ switch (m->parameter) {\r
+ case EVENT_SLIDESHOW:\r
+ if (! pictureEnabled) break; //old timer msg...\r
+ //if (! audioEnabled) {\r
+ if (true) {\r
+ if (slideshow) {\r
+ rotate=WJpeg::ROT_0;\r
+ showPicture(VMediaList::MV_NEXT,true,false);\r
+ startSlideshow();\r
+ }\r
+ }\r
+ break;\r
+ case EVENT_DRAWINGERROR:\r
+ drawingDone(true);\r
+ break;\r
+ case EVENT_DRAWINGDONE:\r
+ drawingDone(false);\r
+ break;\r
+ case EVENT_DIRECTORYDONE:\r
+ //just disable audio without (poetntially) hiding us\r
+ //this gives the list a chance to decide whether audio\r
+ //should be on top afterwards without showing the list\r
+ //immediately\r
+ setAudioMode(false,false);\r
+ parent->directoryDone();\r
+ if (! pictureShowing) setPictureMode(false);\r
+ if (! justPlaying) setAudioMode(false);\r
+ break;\r
+ case AudioPlayer::STREAM_ERR:\r
+ case AudioPlayer::STREAM_END:\r
+ if (playall) play(playall,false,VMediaList::MV_NEXT);\r
+ else {\r
+ setAudioMode(false);\r
+ justPlaying=false;\r
+ }\r
+ break;\r
+ case AudioPlayer::SHORT_UPDATE:\r
+ if (info && audioEnabled ) {\r
+ drawAudioClocks();\r
+ BoxStack::getInstance()->update(info,&clocksRegion);\r
+ BoxStack::getInstance()->update(info,&barRegion);\r
+ Timers::getInstance()->setTimerD(this, 4, 1);\r
+ }\r
+ break;\r
+ case AudioPlayer::NEW_SONG:\r
+ if (audioEnabled) updateAudioInfo();\r
+ break;\r
+ case AudioPlayer::CONNECTION_LOST:\r
+ if (audioEnabled) destroyInfo();\r
+ if (AudioPlayer *player=getPlayer(false)) {\r
+ player->shutdown();\r
+ player=NULL;\r
+ }\r
+ Command::getInstance()->connectionLost();\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+VMediaView * VMediaView::createViewer(VMediaList * mparent) {\r
+ Log::getInstance()->log("VMediaView::createViewer", Log::DEBUG, "p=%p",\r
+ mparent);\r
+ VMediaView *vmn=new VMediaView(mparent);\r
+ BoxStack::getInstance()->add(vmn);\r
+ vmn->draw();\r
+ BoxStack::getInstance()->update(vmn);\r
+ return vmn;\r
+}\r
+\r
+void VMediaView::startSlideshow() {\r
+ slideshow=true;\r
+ if (! pictureLoading) Timers::getInstance()->setTimerD(this,1,showtime);\r
+}\r
+\r
+void VMediaView::stopSlideshow(bool hard) {\r
+ if (hard) slideshow=false;\r
+ Timers::getInstance()->cancelTimer(this,1);\r
+}\r
+\r
+\r
+void VMediaView::showPicture(ULONG move,bool bslideshow,bool activateBanner) {\r
+ pictureShowing=true;\r
+ setPictureMode(true);\r
+ stopSlideshow(true);\r
+#ifdef DRAWING_THREAD\r
+ drawingThread->stop();\r
+#endif\r
+ slideshow=bslideshow;\r
+ Media *newPicture=parent->getMedia(MEDIA_TYPE_PICTURE,move);\r
+ if ( ! newPicture) {\r
+ pictureShowing=false;\r
+ if (!audioEnabled) {\r
+ //within the event handler first directoryDone is called\r
+ //and afterwards everything is stopped if nothing new\r
+ sendCommandMsg(EVENT_DIRECTORYDONE);\r
+ }\r
+ slideshow=false;\r
+ }\r
+ else \r
+ {\r
+ pictureShowing=true;\r
+ if (currentPicture) {\r
+ delete currentPicture;\r
+ currentPicture=NULL;\r
+ }\r
+ currentPicture=newPicture;\r
+ loadPicture(currentPicture,activateBanner);\r
+ }\r
+}\r
+\r
+//the real picture drawing method\r
+//will start drawing on a new surface and will switch it wehn done\r
+\r
+int VMediaView::loadPicture(Media *md,bool activateBanner) {\r
+ pictureError=NULL;\r
+ if (! md) return 1;\r
+ if (! md->getURI()) {\r
+ pictureError=tr("No media found");\r
+ Log::getInstance()->log("VMediaView::load",Log::ERR,"no URI in media");\r
+ return 1;\r
+ }\r
+ Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",\r
+ md->getURI()->getName(),this);\r
+ //do we have a pictureBanner?\r
+ havePictureBanner=pictureBanner!=NULL || activateBanner;\r
+ pictureLoading=true;\r
+#ifdef DRAWING_THREAD\r
+ if (!audioEnabled && havePictureBanner ) showPictureBanner(true);\r
+ drawingThread->stop();\r
+#else\r
+ showPictureBanner(true);\r
+#endif\r
+ ireader->stop();\r
+ ULLONG size=0;\r
+ int rtok=reader->initRead(md->getURI(),&size,ctl.scaleAmount); //scaleAmount is the same for both...\r
+ if (rtok == 0) {\r
+ //now we can really draw\r
+ //get the surface for drawing\r
+ Surface * drawSurface=NULL;\r
+ WJpeg::JpegControl *drawCtl=NULL;\r
+ getDrawingParam(drawSurface,drawCtl);\r
+ drawCtl->error[0]=0;\r
+ drawCtl->rotation=rotate;\r
+ drawCtl->mode=cropmode;\r
+ drawCtl->compressedSize=size;\r
+#ifdef DRAWING_THREAD\r
+ bool ok=drawingThread->start(drawCtl,drawSurface,reader,pictureBack);\r
+ if (! ok) {\r
+ Log::getInstance()->log("VMediaView::load", Log::ERR, "unable to start drawing thread");\r
+ pictureError=tr("JpegError");\r
+ pictureLoading=false;\r
+ destroyPictureBanner();\r
+ return 1;\r
+ }\r
+ return 0;\r
+#else\r
+ //here we could hand this over to the drawing thread\r
+ bool ok=WJpeg::drawJpeg(drawCtl,drawSurface,reader,pictureBack);\r
+ drawingDone(!ok);\r
+ return ok?0:1;\r
+#endif\r
+ }\r
+ pictureLoading=false;\r
+ return 1;\r
+}\r
+\r
+void VMediaView::drawingDone(bool hasError) {\r
+ pictureLoading=false;\r
+ destroyPictureBanner(); //disable loading indication (or real banner)\r
+ if (! hasError) {\r
+ switchSurface();\r
+ Log::getInstance()->log("VMediaView::drawingDone", Log::DEBUG, "success: sfc now=%p",surface);\r
+ pictureError=NULL;\r
+ //only show the pictureBanner if it was there before\r
+ if (havePictureBanner && ! audioEnabled) showPictureBanner();\r
+ Log::getInstance()->log("VMediaView::load", Log::DEBUG, "success" );\r
+ updatePictureInfo(); //will only do somethng if pictureEnabled\r
+ }\r
+ else \r
+ {\r
+ pictureError=tr("JpegError");\r
+ if (pictureEnabled) {\r
+ draw();\r
+ destroyInfo();\r
+ }\r
+ }\r
+ MediaPlayer::getInstance()->closeMediaChannel(1);\r
+#ifndef DRAWING_THREAD\r
+ if (audioEnabled) showAudioBanner();\r
+#endif\r
+ if (slideshow) startSlideshow();\r
+ BoxStack::getInstance()->update(this);\r
+}\r
+\r
+void VMediaView::showPictureBanner(bool loading) {\r
+ //we are in the main thread - so we can (and must) safely hard destroy/create the banner\r
+ Timers::getInstance()->cancelTimer(this,2);\r
+ if (! currentPicture) {\r
+ //hmm...\r
+ destroyPictureBanner(false);\r
+ return;\r
+ }\r
+ if (pictureBanner) destroyPictureBanner(false);\r
+ if (! pictureEnabled || ! bannerEnabled) return;\r
+ pictureBanner= new VPictureBanner(loading, slideshow);\r
+ pictureBanner->fillColour(infoBack);\r
+ if (! loading) {\r
+ int len=strlen(currentPicture->getFileName())+Media::TIMEBUFLEN+20;\r
+ char *buf=new char[len];\r
+ char tbuf[Media::TIMEBUFLEN];\r
+ SNPRINTF(buf,len,"%c%02ds%c %s %s " ,\r
+ slideshow?' ':'[',\r
+ showtime,\r
+ slideshow?' ':']',\r
+ currentPicture->getTimeString(tbuf),\r
+ currentPicture->getFileName()\r
+ );\r
+ pictureBanner->setText(buf);\r
+ delete [] buf;\r
+ }\r
+ else {\r
+ char *buf=new char[strlen(currentPicture->getDisplayName())+50];\r
+ SNPRINTF(buf,50,"%s %s",tr("Loading"), currentPicture->getDisplayName());\r
+ pictureBanner->setText(buf);\r
+ delete buf;\r
+ }\r
+ pictureBanner->draw();\r
+ if (! loading ) Timers::getInstance()->setTimerD(this,2,8);\r
+ BoxStack::getInstance()->add(pictureBanner);\r
+ BoxStack::getInstance()->update(pictureBanner);\r
+ }\r
+\r
+void VMediaView::destroyPictureBanner(bool fromTimer) {\r
+ if (pictureBanner) {\r
+ if (fromTimer) sendViewMsg(pictureBanner); \r
+ else BoxStack::getInstance()->remove(pictureBanner);\r
+ pictureBanner=NULL;\r
+ if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);\r
+ }\r
+}\r
+void VMediaView::updatePictureBanner(bool loading) {\r
+ if (pictureBanner ) {\r
+ showPictureBanner(loading);\r
+ }\r
+}\r
+void VMediaView::timercall(int clientref) {\r
+ Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "id=%d",clientref);\r
+ switch(clientref)\r
+ {\r
+ case 4:\r
+ {\r
+ sendCommandMsg(AudioPlayer::SHORT_UPDATE);\r
+ break;\r
+ }\r
+ case 3:\r
+ {\r
+ Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "infoEnd");\r
+ destroyInfo(true);\r
+ if (audioEnabled) {\r
+ //we only did show the audio error info if audio is enabled\r
+ bool stillError=false;\r
+ if (AudioPlayer * player=getPlayer(false)) {\r
+ stillError=player->getState()==AudioPlayer::S_ERROR;\r
+ }\r
+ if (stillError) {\r
+ sendCommandMsg(AudioPlayer::STREAM_END);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 1:\r
+ if (! slideshow) return;\r
+ Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "slideshow");\r
+ sendCommandMsg(EVENT_SLIDESHOW);\r
+ break;\r
+ case 2:\r
+ Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "pictureBannerEnd");\r
+ destroyPictureBanner(true);\r
+ break;\r
+ }\r
+ \r
+ }\r
+\r
+#define INFOBUF 2000\r
+void VMediaView::showPictureInfo(){\r
+ if (! pictureEnabled || audioEnabled) return;\r
+ if (info) destroyInfo();\r
+ if (! currentPicture) return;\r
+\r
+ info=new VInfo();\r
+ info->setTitleText(currentPicture->getFileName());\r
+ info->setDropThrough();\r
+ info->setSize(500, 300);\r
+ info->createBuffer();\r
+ info->setBorderOn(1);\r
+ info->setTitleBarOn(1);\r
+\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ info->setPosition(100, 180);\r
+ else\r
+ info->setPosition(100, 150);\r
+ char buf[INFOBUF];\r
+ char tbuf[Media::TIMEBUFLEN];\r
+ //modes should come from mediaoptions...\r
+ const char *mode=NULL;\r
+ switch (currentControl->mode) {\r
+ case WJpeg::CROPPERCENT:\r
+ mode="clipfactor";\r
+ break;\r
+ case WJpeg::LETTER:\r
+ mode="letter";\r
+ break;\r
+ default:\r
+ mode="clip";\r
+ break;\r
+ }\r
+ const char *dirname=parent->getDirname(MEDIA_TYPE_PICTURE);\r
+ int ldir=0;\r
+ const char *prfx="";\r
+ if (dirname) ldir=strlen(dirname);\r
+ if (ldir > 35){\r
+ dirname=dirname+ldir-35;\r
+ prfx="...";\r
+ }\r
+ SNPRINTF(buf,INFOBUF,"%s= %s%s\n%s= %u x %u\n%s= %lu kBytes\n%s= %s\n%s= %u\n%s= %u%%\n%s= %s",\r
+ tr("Directory"), prfx,dirname,\r
+ tr("Format(px)"),currentControl->picw,currentControl->pich,\r
+ tr("Filesize"),currentControl->compressedSize/1000,\r
+ tr("Time"),currentPicture->getTimeString(tbuf),\r
+ tr("Rotation"),90*currentControl->finalRotation,\r
+ tr("Scale"),currentControl->scale,\r
+ tr("Picture Mode"),mode );\r
+ info->setMainText(buf);\r
+ info->draw();\r
+ BoxStack::getInstance()->add(info);\r
+ BoxStack::getInstance()->update(info);\r
+ Timers::getInstance()->setTimerD(this,3,8);\r
+}\r
+void VMediaView::updatePictureInfo(){\r
+ if (info) {\r
+ showPictureInfo();\r
+ }\r
+}\r
+void VMediaView::destroyInfo(bool fromTimer){\r
+ if (info) {\r
+ if (! fromTimer) {\r
+ Log::getInstance()->log("VMediaView",Log::DEBUG,"remove info %p",info);\r
+ BoxStack::getInstance()->remove(info);\r
+ }\r
+ else {\r
+ Log::getInstance()->log("VMediaView",Log::DEBUG,"trigger remove info %p",info);\r
+ sendViewMsg(info);\r
+ }\r
+ info=NULL;\r
+ }\r
+ if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);\r
+ if (! fromTimer) Timers::getInstance()->cancelTimer(this,4);\r
+}\r
+\r
+void VMediaView::sendViewMsg(Boxx *v) {\r
+ Message* m = new Message(); \r
+ m->message = Message::CLOSE_ME;\r
+ m->to = BoxStack::getInstance();\r
+ m->from = v;\r
+ m->parameter=(ULONG)v;\r
+ Command::getInstance()->postMessageFromOuterSpace(m);\r
+}\r
+void VMediaView::sendCommandMsg(int command) {\r
+ Message* m = new Message(); \r
+ //we misuse PLAYER_EVENT here\r
+ m->message = Message::PLAYER_EVENT;\r
+ m->to = this;\r
+ m->from = this;\r
+ m->parameter= command;\r
+ Command::getInstance()->postMessageFromOuterSpace(m);\r
+}\r
+\r
+void VMediaView::enableBanner(bool enable) {\r
+ bannerEnabled=false;\r
+ updatePictureBanner();\r
+}\r
+\r
+void VMediaView::getDrawingParam(Surface *&sfc,WJpeg::JpegControl *&c){\r
+ if (secondSurface()) {\r
+ //we currently display on sfc2\r
+ sfc=sfc1;\r
+ c=&ctl;\r
+ }\r
+ else {\r
+ sfc=sfc2;\r
+ c=&ctl2;\r
+ }\r
+}\r
+void VMediaView::switchSurface(){\r
+ if (secondSurface()) {\r
+ //now we switch to sfc1\r
+ surface=sfc1;\r
+ currentControl=&ctl;\r
+ }\r
+ else {\r
+ surface=sfc2;\r
+ currentControl=&ctl2;\r
+ }\r
+}\r
+\r
+AudioPlayer * VMediaView::getPlayer(bool createIfNeeded)\r
+{\r
+ AudioPlayer* rt=AudioPlayer::getInstance(this,false);\r
+ if (! createIfNeeded && rt == NULL) return NULL;\r
+ if (rt == NULL) {\r
+ rt=AudioPlayer::getInstance(this);\r
+ rt->run();\r
+ }\r
+ return rt;\r
+}\r
+\r
+bool VMediaView::isAudioPlaying() {\r
+ Log::getInstance()->log("VMediaView::isPlaying", Log::DEBUG, "rt=%s", justPlaying?"true":"false");\r
+ return justPlaying;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+int VMediaView::play(bool all,bool activate,ULONG move,bool showInfo) {\r
+ int rt=0;\r
+ if (getPlayer(false)) getPlayer(false)->stop();\r
+ justPlaying=false;\r
+ if (currentAudio) delete currentAudio;\r
+ currentAudio=NULL;\r
+ playall=all;\r
+ currentAudio=parent->getMedia(MEDIA_TYPE_AUDIO,move);\r
+ audioError=NULL;\r
+ if ( ! currentAudio || ! currentAudio->getURI()) {\r
+ Log::getInstance()->log("VMediaView::load", Log::ERR, "no URI in media");\r
+ audioError=tr("no audio file");\r
+ if (audioEnabled) sendCommandMsg(EVENT_DIRECTORYDONE);\r
+ rt= -1;\r
+ }\r
+ else {\r
+ Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",\r
+ currentAudio->getURI()->getName(),this);\r
+ int wseq=getPlayer()->play(currentAudio->getURI());\r
+ if (getPlayer()->waitForSequence(5,wseq)<0) {\r
+ audioError=tr("unable to open audio file");\r
+ rt= -1;\r
+ }\r
+ else {\r
+ justPlaying=true;\r
+ rt=0;\r
+ }\r
+ Log::getInstance()->log("VMediaView", Log::DEBUG, "player started for %s",currentAudio->getURI()->getName());\r
+ }\r
+ if (activate && ! audioEnabled){\r
+ if (showInfo) retriggerAudioInfo=true;\r
+ setAudioMode(true);\r
+ }\r
+ else {\r
+ //avoid duplicate creation of banner and info\r
+ showAudioBanner();\r
+ showAudioInfo();\r
+ }\r
+ if (activate && (! currentPicture || ! pictureShowing)) draw();\r
+ BoxStack::getInstance()->update(this);\r
+ return rt;\r
+}\r
+\r
+void VMediaView::showAudioInfo() {\r
+ if (! audioEnabled) return;\r
+ Timers::getInstance()->cancelTimer(this,4);\r
+ Timers::getInstance()->cancelTimer(this,3);\r
+ if (info) destroyInfo();\r
+ if (! retriggerAudioInfo) return;\r
+ drawAudioInfo();\r
+ bool playerError=getPlayer()->getState()==AudioPlayer::S_ERROR || audioError;\r
+ if (! playerError) Timers::getInstance()->setTimerD(this,3,AUDIOBANNER_TIME);\r
+ else Timers::getInstance()->setTimerD(this,3,AUDIOERROR_TIME);\r
+ if (! playerError) Timers::getInstance()->setTimerD(this,4, 1);\r
+ BoxStack::getInstance()->update(info);\r
+ }\r
+\r
+void VMediaView::updateAudioInfo() {\r
+ if (info) {\r
+ showAudioInfo();\r
+ }\r
+}\r
+\r
+void VMediaView::drawAudioInfo(){\r
+ Log::getInstance()->log("VMediaView",Log::DEBUG, "draw banner for %p",info);\r
+ const char *title=NULL;\r
+ char *playerTitle=NULL;\r
+ bool playerError=false;\r
+ int numlines=0;\r
+ int len=0;\r
+ int num=0;\r
+ const char *pl=tr("Playlist");\r
+ const char *first=NULL;\r
+ char *playerInfo=NULL;\r
+ if (audioError) {\r
+ if (getPlayer()->getState() == AudioPlayer::S_PLAY) audioError=NULL;\r
+ }\r
+ if (! currentAudio && ! audioError) audioError=tr("no audio file");\r
+ if (audioError ) {\r
+ title=tr("MediaError");\r
+ }\r
+ else {\r
+ playerTitle=getPlayer()->getTitle();\r
+ if (playerTitle) title=playerTitle;\r
+ else title=currentAudio->getDisplayName();\r
+ num=parent->getNumEntries(MEDIA_TYPE_AUDIO,currentAudio->index);\r
+ playerError=getPlayer()->getState() == AudioPlayer::S_ERROR;\r
+ //1more line for long dirs\r
+ numlines=playall?5:4;\r
+ }\r
+ if (playerError) {\r
+ numlines=3;\r
+ first=tr("Unable to play audio file");\r
+ len=strlen(first)+3;\r
+ }\r
+ else if (audioError) {\r
+ numlines=3;\r
+ first=audioError;\r
+ len=strlen(first)+3;\r
+ }\r
+ else {\r
+ playerInfo=getPlayer()->getID3Info();drawText(tr("Loading"),5,3,Colour::LIGHTTEXT);\r
+ len=strlen(currentAudio->getDisplayName())+strlen(pl)+30+strlen(parent->getDirname(MEDIA_TYPE_AUDIO))+Media::TIMEBUFLEN+110;\r
+ if (playerInfo) {\r
+ for (UINT i=0;i<strlen(playerInfo);i++) \r
+ if (playerInfo[i] == '\n') numlines++;\r
+ len+=strlen(playerInfo);\r
+ first=playerInfo;\r
+ }\r
+ else {\r
+ first="";\r
+ }\r
+ }\r
+ destroyInfo();\r
+ info=new VInfo();\r
+ UINT height=numlines*30+60;\r
+ UINT vheight=Video::getInstance()->getScreenHeight();\r
+ UINT vwidth=Video::getInstance()->getScreenWidth();\r
+ if (height > vheight-2*AUDIOBANNER_BOTTOM_MARGIN)\r
+ height=vheight-2*AUDIOBANNER_BOTTOM_MARGIN;\r
+ info->setSize(vwidth -2*AUDIOBANNER_X_MARGIN, height);\r
+ info->createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);\r
+ }\r
+ else\r
+ {\r
+ info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);\r
+ }\r
+\r
+ info->setTitleBarOn(0);\r
+ info->setDropThrough();\r
+ //from vvideorec \r
+ //set the regions for the closcks and bars on banner\r
+ barRegion.x = info->getWidth()-AUDIOBARLEN-20;\r
+ barRegion.y = info->getHeight() - 30; // FIXME, need to be - 1? and below?\r
+ barRegion.w = info->getWidth()-AUDIOBARLEN+10;\r
+ barRegion.h = 30;\r
+\r
+ clocksRegion.x = 130;\r
+ clocksRegion.y = barRegion.y + 3;\r
+ clocksRegion.w = 190;\r
+ clocksRegion.h = getFontHeight();\r
+ Log::getInstance()->log("VMediaView",Log::DEBUG,"created AudioInfo %p",info);\r
+ BoxStack::getInstance()->add(info);\r
+ char *buf=new char [len];\r
+ if (playerError || audioError) {\r
+ SNPRINTF(buf,len,"%s",first);\r
+ }\r
+ else {\r
+ char tbuf[Media::TIMEBUFLEN];\r
+ if (playall) {\r
+ SNPRINTF(buf,len,"%s\n"\r
+ "%s:%s\n"\r
+ "%s: %d/%d\n"\r
+ "%s:%s\n"\r
+ "%s:%s\n",\r
+ first,\r
+ tr("FileName"),currentAudio->getDisplayName(),\r
+ pl,num,parent->getNumEntries(MEDIA_TYPE_AUDIO),\r
+ tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),\r
+ tr("Time"),currentAudio->getTimeString(tbuf));\r
+ }\r
+ else {\r
+ SNPRINTF(buf,len,"%s\n"\r
+ "%s:%s\n"\r
+ "%s:%s\n"\r
+ "%s:%s\n",\r
+ first,\r
+ tr("FileName"),currentAudio->getDisplayName(),\r
+ tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),\r
+ tr("Time"),currentAudio->getTimeString(tbuf));\r
+ }\r
+ }\r
+ Log::getInstance()->log("VMediaView",Log::DEBUG,"info: (%d)%s",strlen(buf),buf);\r
+ //now the real drawing functions\r
+ info->draw();\r
+ //title\r
+ info->rectangle(0, 0, info->getWidth(), 30, Colour::TITLEBARBACKGROUND);\r
+ info->drawText(title, 5, 5, Colour::LIGHTTEXT);\r
+ info->drawPara(buf,5,32,Colour::LIGHTTEXT);\r
+ delete [] buf;\r
+ if (! audioError) {\r
+ WSymbol w;\r
+ info->TEMPADD(&w);\r
+ int x=10;\r
+ int ybottom=info->getHeight();\r
+ info->rectangle(0, ybottom - barRegion.h, info->getWidth(), barRegion.h, Colour::TITLEBARBACKGROUND);\r
+ bool drawSymbol=true;\r
+ switch(getPlayer()->getState()) {\r
+ case AudioPlayer::S_PAUSE:\r
+ w.nextSymbol = WSymbol::PAUSE;\r
+ break;\r
+ case AudioPlayer::S_PLAY:\r
+ w.nextSymbol = WSymbol::PLAY;\r
+ break;\r
+ case AudioPlayer::S_DONE:\r
+ if (playall) \r
+ w.nextSymbol = WSymbol::PLAY;\r
+ else\r
+ drawSymbol=false;\r
+ break;\r
+ case AudioPlayer::S_BACK:\r
+ w.nextSymbol = WSymbol::FBWD ;\r
+ break;\r
+ case AudioPlayer::S_FF:\r
+ w.nextSymbol = WSymbol::FFWD ;\r
+ break;\r
+ default:\r
+ drawSymbol=false;\r
+ break;\r
+ }\r
+ if (drawSymbol) {\r
+ w.setPosition(x, ybottom-24);\r
+ w.draw();\r
+ }\r
+ else {\r
+ //stop symbol\r
+ info->rectangle(x, ybottom - 23, 18, 16, Colour::LIGHTTEXT);\r
+ }\r
+ x+=30;\r
+ drawAudioClocks();\r
+ }\r
+ if (playerInfo) delete playerInfo;\r
+ if (playerTitle) delete playerTitle;\r
+}\r
+\r
+void VMediaView::drawAudioClocks() {\r
+ if (! info || ! audioEnabled) return;\r
+ Log::getInstance()->log("VMediaView::drawAudioClocks", Log::DEBUG, "");\r
+ //draw clocks and bar\r
+ info->rectangle(clocksRegion, Colour::TITLEBARBACKGROUND);\r
+\r
+ time_t currentSec = (time_t)(getPlayer()->getCurrentTimes());\r
+ time_t lengthSec=(time_t)(getPlayer()->getSonglen());\r
+ struct tm cpos;\r
+ struct tm slen;\r
+/* gmtime_r(¤tSec,&cpos);\r
+ gmtime_r(&lengthSec,&slen);*/\r
+ cpos.tm_hour=currentSec/3600;\r
+ cpos.tm_min=(currentSec-cpos.tm_hour*3600)/60;\r
+ cpos.tm_sec=(currentSec-cpos.tm_hour*3600-cpos.tm_min*60);\r
+ slen.tm_hour=lengthSec/3600;;\r
+ slen.tm_min=(lengthSec-slen.tm_hour*3600)/60;\r
+ slen.tm_sec=(lengthSec-slen.tm_hour*3600-slen.tm_min*60);\r
+\r
+ char buffer[100];\r
+ if (currentSec >= lengthSec)\r
+ {\r
+ SNPRINTF(buffer,99, "-:--:-- / -:--:-- %03dk",getPlayer()->getCurrentBitrate()/1000);\r
+ }\r
+ else\r
+ {\r
+ SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i %03dk", cpos.tm_hour, cpos.tm_min, cpos.tm_sec, slen.tm_hour, slen.tm_min, slen.tm_sec,\r
+ getPlayer()->getCurrentBitrate()/1000);\r
+ //Log::getInstance()->log("VMediaView", Log::DEBUG, buffer);\r
+ }\r
+\r
+ info->drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);\r
+ \r
+ // Draw progress bar\r
+ int progBarXbase = 0;\r
+ int barlen=250;\r
+\r
+ info->rectangle(barRegion.x + progBarXbase, barRegion.y + 3, barlen+10, 24, Colour::LIGHTTEXT);\r
+ info->rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 5, barlen+6, 20, barBlue);\r
+\r
+ if (currentSec > lengthSec) currentSec=lengthSec;\r
+ if (lengthSec == 0) return;\r
+\r
+ // Draw yellow portion\r
+ int progressWidth = (barlen+2) * currentSec / lengthSec;\r
+ info->rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 7, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+\r
+}\r
+\r
+void VMediaView::showAudioBanner() {\r
+ destroyAudioBanner();\r
+ if (! audioEnabled) return;\r
+ audioBanner=new VInfo();\r
+ Log::getInstance()->log("VMediaView",Log::DEBUG,"creating AudioBanner %p", audioBanner);\r
+ Video *v=Video::getInstance();\r
+ audioBanner->setSize(v->getScreenWidth()-100, 36);\r
+ audioBanner->createBuffer();\r
+ audioBanner->setPosition(50, v->getScreenHeight()-50);\r
+ audioBanner->fillColour(audioBannerBack);\r
+ audioBanner->setTitleBarOn(0);\r
+ audioBanner->setDropThrough();\r
+ if ( ! currentAudio || ! currentAudio->getDisplayName() || audioError) {\r
+ audioBanner->drawText(tr("AudioPlayer - not playing"),5,3,Colour::LIGHTTEXT);\r
+ }\r
+ else {\r
+ char * buf=new char[strlen(currentAudio->getDisplayName())+50];\r
+ SNPRINTF(buf,50,"%s %s",tr("AudioPlayer"),currentAudio->getDisplayName());\r
+ audioBanner->drawText(buf,5,3,Colour::LIGHTTEXT);\r
+ delete buf;\r
+ }\r
+ BoxStack::getInstance()->add(audioBanner);\r
+ BoxStack::getInstance()->update(audioBanner);\r
+}\r
+\r
+void VMediaView::destroyAudioBanner() {\r
+ if (audioBanner) {\r
+ Log::getInstance()->log("VMediaView",Log::DEBUG,"deleting AudioBanner %p",audioBanner);\r
+ BoxStack::getInstance()->remove(audioBanner);\r
+ audioBanner=NULL;\r
+ }\r
+}\r
-/*
- Copyright 2007 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vopts.h"
-
-#include "colour.h"
-#include "video.h"
-#include "audio.h"
-#include "remote.h"
-#include "boxstack.h"
-#include "woptionpane.h"
-#include "wremoteconfig.h"
-#include "log.h"
-#include "option.h"
-#include "vdr.h"
-#include "command.h"
-#include "mediaoptions.h"
-
-//#include "vdr.h"
-//#include "command.h"
-
-VOpts::VOpts()
-{
- setTitleBarOn(1);
- setTitleBarColour(Colour::TITLEBARBACKGROUND);
- setTitleText(tr("Options"));
-
- setSize(520, 360);
- createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- setPosition(100, 110);
- else
- setPosition(90, 90);
-
- tabbar.setPosition(6, 32);
- tabbar.setSize(getWidth() - 12, getHeight() - 34);
- add(&tabbar);
-
- Option* option;
- WOptionPane* wop;
-
- // --- edit options start here
-
- static const char* options1[] = {"Old", "New"};
- static const char* options3[] = {"RGB+composite", "S-Video"};
- static const char* options4[] = {"4:3", "16:9"};
- static const char* options5[] = {"Chop sides", "Letterbox"};
- static const char* options6[] = {"On", "Off", "Last state"};
- static const char* options7[] = {"All", "FTA only"};
- static const char* options15[] = {"Alphabetical", "Chronological"};
-
- static const char* options13[] = {"1024", "2048", "4096", "8192", "16384", "32768", "65536"};
- static const char* options14[] = {"No", "Yes"};
-
- // Get list of languages from VDR and construct options table
- LangCode = VDR::getInstance()->getLanguageList();
- options2 = new const char*[LangCode.size()];
- options2keys = new const char*[LangCode.size()];
- I18n::lang_code_list::const_iterator iter;
- UINT LangNumber = 0;
- for (iter = LangCode.begin(); iter != LangCode.end(); ++iter,++LangNumber)
- {
- options2[LangNumber] = iter->second.c_str();
- options2keys[LangNumber] = iter->first.c_str();
- }
-
- numPanes = 4;
- panes = new Boxx*[numPanes];
-
- wop = new WOptionPane();
- tabbar.addTab(tr("General"), wop);
- panes[0] = wop;
-
- option = new Option(1, "Remote control type", "General", "Remote type", Option::TYPE_TEXT, 2, 0, 0, options1);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(2, "Language", "General", "LangCode", Option::TYPE_KEYED_TEXT, LangCode.size(), 0, 0, options2, options2keys);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(3, "TV connection type", "TV", "Connection", Option::TYPE_TEXT, 2, 0, 0, options3);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(4, "TV aspect ratio", "TV", "Aspect", Option::TYPE_TEXT, 2, 0, 0, options4);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(5, "16:9 on 4:3 display mode", "TV", "Widemode", Option::TYPE_TEXT, 2, 0, 0, options5);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(6, "Power state after bootup", "General", "Power After Boot", Option::TYPE_TEXT, 3, 0, 0, options6);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(7, "Display channels", "General", "Channels", Option::TYPE_TEXT, 2, 0, 0, options7);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(15, "Recordings sort order", "General", "Recordings Sort Order", Option::TYPE_TEXT, 2, 0, 0, options15);
- options.push_back(option);
- wop->addOptionLine(option);
-
- Remote::getInstance()->addOptionsToPanes(0,&options,wop);
- Video::getInstance()->addOptionsToPanes(0,&options,wop);
- Audio::getInstance()->addOptionsToPanes(0,&options,wop);
-
-
-/* WRemoteConfig* wrc = new WRemoteConfig();
- tabbar.addTab(tr("Remote Control"), wrc);*/
- Remote::getInstance()->addOptionPagesToWTB(&tabbar);
- // panes[1] = wrc;
-
- Video::getInstance()->addOptionPagesToWTB(&tabbar);
- Audio::getInstance()->addOptionPagesToWTB(&tabbar);
- MediaOptions::getInstance()->addOptionPagesToWTB(&tabbar);
-
-
- wop = new WOptionPane();
- tabbar.addTab(tr("Timers"), wop);
- panes[1] = wop;
-
- option = new Option(9, "Default start margin (minutes)", "Timers", "Start margin", Option::TYPE_INT, 20, 5, 0, NULL);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(10, "Default end margin (minutes)", "Timers", "End margin", Option::TYPE_INT, 20, 5, 0, NULL);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(11, "Default priority", "Timers", "Priority", Option::TYPE_INT, 100, 99, 0, NULL);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(12, "Default lifetime", "Timers", "Lifetime", Option::TYPE_INT, 100, 99, 0, NULL);
- options.push_back(option);
- wop->addOptionLine(option);
-
- Remote::getInstance()->addOptionsToPanes(1,&options,wop);
- Video::getInstance()->addOptionsToPanes(1,&options,wop);
- Audio::getInstance()->addOptionsToPanes(1,&options,wop);
-
-
- wop = new WOptionPane();
- tabbar.addTab(tr("Advanced"), wop);
- panes[2] = wop;
-
- option = new Option(8, "VDR-Pri 0=OK !See forums!", "General", "Live priority", Option::TYPE_INT, 100, 0, 0, NULL);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(13, "TCP receive window size", "Advanced", "TCP receive window", Option::TYPE_TEXT, 7, 1, 0, options13);
- options.push_back(option);
- wop->addOptionLine(option);
- option = new Option(14, "Use WSS (PAL only)", "General", "WSS", Option::TYPE_TEXT, 2, 0, 0, options14);
- options.push_back(option);
- wop->addOptionLine(option);
-
- Remote::getInstance()->addOptionsToPanes(2,&options,wop);
- Video::getInstance()->addOptionsToPanes(2,&options,wop);
- Audio::getInstance()->addOptionsToPanes(2,&options,wop);
-}
-
-VOpts::~VOpts()
-{
- // for (int i = 0; i < numPanes; i++) delete panes[i]; //Move to TabBar, Marten
- delete[] panes;
-
- for(vector<Option*>::iterator j = options.begin(); j != options.end(); j++) delete *j;
- delete[] options2;
- delete[] options2keys;
-}
-
-int VOpts::handleCommand(int command)
-{
- // either is active, handle back
- if (command == Remote::BACK)
- {
- doSave();
- return 4;
- }
- else
- {
- int retval = tabbar.handleCommand(command);
- if (retval == 1)
- {
- BoxStack::getInstance()->update(this);
- return 2;
- }
- else if (retval == 2)
- {
- // command was taken and actively ignored
- return 2;
- }
- else
- {
- return 1; // ???
- }
- }
-}
-
-void VOpts::doSave()
-{
- VDR* vdr = VDR::getInstance();
-
- Remote::getInstance()->saveOptionstoServer(); //Remote
- Video::getInstance()->saveOptionstoServer(); //Video
- Audio::getInstance()->saveOptionstoServer(); //Remote
- MediaOptions::getInstance()->saveOptionstoServer(); //Media
-
- // Damn, and the dynamic idea was going *so* well...
- //Whats about a check with typeid operator?
- WOptionPane* wop;
- wop = (WOptionPane*)panes[0];
- wop->saveOpts();
- wop = (WOptionPane*)panes[1];
- wop->saveOpts();
- wop = (WOptionPane*)panes[2];
- wop->saveOpts();
-
-
- for (UINT i = 0; i < options.size(); i++)
- {
- if (options[i]->configChoice == options[i]->userSetChoice) continue; // no change
-
- Log::getInstance()->log("Options", Log::DEBUG, "Option %i has changed", i);
-
- // Save to vdr
-
- if (options[i]->optionType == Option::TYPE_TEXT)
- {
- vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->options[options[i]->userSetChoice]);
- }
- else if (options[i]->optionType == Option::TYPE_KEYED_TEXT)
- {
- vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->optionkeys[options[i]->userSetChoice]);
- }
- else
- {
- char buffer[20];
- sprintf(buffer, "%i", options[i]->userSetChoice);
- vdr->configSave(options[i]->configSection, options[i]->configKey, buffer);
- }
-
- // Set new setting
- if (options[i]->opthandler == NULL) //Ok, noone else is handling this, we are doing it
- {
- switch(options[i]->id)
- {
- case 1:
- {
- if (options[i]->userSetChoice == 1)
- {
- Log::getInstance()->log("Options", Log::DEBUG, "Setting New Remote");
- Remote::getInstance()->setRemoteType(Remote::NEWREMOTE);
- }
- else
- {
- Log::getInstance()->log("Options", Log::DEBUG, "Setting Old Remote");
- Remote::getInstance()->setRemoteType(Remote::OLDREMOTE);
- }
- break;
- }
- case 2:
- {
- Message* m = new Message();
- m->message = Message::CHANGE_LANGUAGE;
- m->to = Command::getInstance();
- Command::getInstance()->postMessageNoLock(m);
- break;
- }
- case 3:
- {
- if (options[i]->userSetChoice == 1)
- {
- Log::getInstance()->log("Options", Log::DEBUG, "Setting S-Video");
- Video::getInstance()->setConnection(Video::SVIDEO);
- }
- else
- {
- Log::getInstance()->log("Options", Log::DEBUG, "Setting RGB/Composite");
- Video::getInstance()->setConnection(Video::COMPOSITERGB);
- }
- break;
- }
- case 4:
- {
- if (options[i]->userSetChoice == 1)
- {
- Log::getInstance()->log("Options", Log::DEBUG, "Setting 16:9 TV");
- Video::getInstance()->setTVsize(Video::ASPECT16X9);
- }
- else
- {
- Log::getInstance()->log("Options", Log::DEBUG, "Setting 4:3 TV");
- Video::getInstance()->setTVsize(Video::ASPECT4X3);
- }
- break;
- }
- case 5:
- {
- if (options[i]->userSetChoice == 1)
- {
- Log::getInstance()->log("Options", Log::DEBUG, "Setting letterbox");
- Video::getInstance()->setMode(Video::LETTERBOX);
- }
- else
- {
- Log::getInstance()->log("Options", Log::DEBUG, "Setting chop-sides");
- Video::getInstance()->setMode(Video::NORMAL);
- }
- break;
- }
- case 13:
- {
- size_t newTCPsize = 2048;
- if (options[i]->userSetChoice == 0) newTCPsize = 1024;
- else if (options[i]->userSetChoice == 1) newTCPsize = 2048;
- else if (options[i]->userSetChoice == 2) newTCPsize = 4096;
- else if (options[i]->userSetChoice == 3) newTCPsize = 8192;
- else if (options[i]->userSetChoice == 4) newTCPsize = 16384;
- else if (options[i]->userSetChoice == 5) newTCPsize = 32768;
- else if (options[i]->userSetChoice == 6) newTCPsize = 65536;
- Log::getInstance()->log("Options", Log::DEBUG, "Setting TCP window size %i", newTCPsize);
- VDR::getInstance()->setReceiveWindow(newTCPsize);
- break;
- }
- }
- }
- else
- {
- options[i]->opthandler->handleOptionChanges(options[i]);
- }
- }
-}
-
-void VOpts::processMessage(Message* m)
-{
- if (m->message == Message::MOUSE_MOVE)
- {
- int x=(m->parameter>>16)-getScreenX();
- int y=(m->parameter&0xFFFF)-getScreenY();
- if (tabbar.mouseMove(x,y))
- {
- BoxStack::getInstance()->update(this);
- }
-
- }
- else if (m->message == Message::MOUSE_LBDOWN)
- {
- int x=(m->parameter>>16)-getScreenX();
- int y=(m->parameter&0xFFFF)-getScreenY();
- if (tabbar.mouseLBDOWN(x,y))
- {
- BoxStack::getInstance()->update(this);
- }
- else if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
- {
- BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
- }
- }
-}
+/*\r
+ Copyright 2007 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vopts.h"\r
+\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "audio.h"\r
+#include "remote.h"\r
+#include "boxstack.h"\r
+#include "woptionpane.h"\r
+#include "wremoteconfig.h"\r
+#include "log.h"\r
+#include "option.h"\r
+#include "vdr.h"\r
+#include "command.h"\r
+\r
+#ifdef VOMP_PLATTFORM_MVP\r
+#include "mediaoptions.h"\r
+#endif\r
+//#include "vdr.h"\r
+//#include "command.h"\r
+\r
+VOpts::VOpts()\r
+{\r
+ setTitleBarOn(1);\r
+ setTitleBarColour(Colour::TITLEBARBACKGROUND);\r
+ setTitleText(tr("Options"));\r
+\r
+\r
+ setSize(520, 360);\r
+ createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ setPosition(100, 110);\r
+ else\r
+ setPosition(90, 90);\r
+ \r
+ tabbar.setPosition(6, 32);\r
+ tabbar.setSize(getWidth() - 12, getHeight() - 34);\r
+ add(&tabbar);\r
+ \r
+ Option* option;\r
+ WOptionPane* wop;\r
+ \r
+ // --- edit options start here\r
+ \r
+ static const char* options1[] = {"Old", "New"};\r
+ static const char* options3[] = {"RGB+composite", "S-Video"};\r
+ static const char* options4[] = {"4:3", "16:9"};\r
+ static const char* options5[] = {"Chop sides", "Letterbox"};\r
+ static const char* options6[] = {"On", "Off", "Last state"};\r
+ static const char* options7[] = {"All", "FTA only"};\r
+ static const char* options15[] = {"Alphabetical", "Chronological"};\r
+\r
+ static const char* options13[] = {"1024", "2048", "4096", "8192", "16384", "32768", "65536"};\r
+ static const char* options14[] = {"No", "Yes"};\r
+ // Get list of languages from VDR and construct options table\r
+ LangCode = VDR::getInstance()->getLanguageList();\r
+ options2 = new const char*[LangCode.size()];\r
+ options2keys = new const char*[LangCode.size()];\r
+ I18n::lang_code_list::const_iterator iter;\r
+ UINT LangNumber = 0;\r
+ for (iter = LangCode.begin(); iter != LangCode.end(); ++iter,++LangNumber)\r
+ {\r
+ options2[LangNumber] = iter->second.c_str();\r
+ options2keys[LangNumber] = iter->first.c_str();\r
+ }\r
+\r
+ numPanes = 4;\r
+ panes = new Boxx*[numPanes];\r
+ wop = new WOptionPane();\r
+ tabbar.addTab(tr("General"), wop);\r
+ panes[0] = wop;\r
+ option = new Option(1, "Remote control type", "General", "Remote type", Option::TYPE_TEXT, 2, 0, 0, options1);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(2, "Language", "General", "LangCode", Option::TYPE_KEYED_TEXT, LangCode.size(), 0, 0, options2, options2keys);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(3, "TV connection type", "TV", "Connection", Option::TYPE_TEXT, 2, 0, 0, options3);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(4, "TV aspect ratio", "TV", "Aspect", Option::TYPE_TEXT, 2, 0, 0, options4);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(5, "16:9 on 4:3 display mode", "TV", "Widemode", Option::TYPE_TEXT, 2, 0, 0, options5);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(6, "Power state after bootup", "General", "Power After Boot", Option::TYPE_TEXT, 3, 0, 0, options6);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(7, "Display channels", "General", "Channels", Option::TYPE_TEXT, 2, 0, 0, options7);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(15, "Recordings sort order", "General", "Recordings Sort Order", Option::TYPE_TEXT, 2, 0, 0, options15);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+\r
+ Remote::getInstance()->addOptionsToPanes(0,&options,wop);\r
+ Video::getInstance()->addOptionsToPanes(0,&options,wop);\r
+ Audio::getInstance()->addOptionsToPanes(0,&options,wop);\r
+\r
+ \r
+/* WRemoteConfig* wrc = new WRemoteConfig();\r
+ tabbar.addTab(tr("Remote Control"), wrc);*/\r
+ Remote::getInstance()->addOptionPagesToWTB(&tabbar);\r
+ // panes[1] = wrc;\r
+\r
+ Video::getInstance()->addOptionPagesToWTB(&tabbar);\r
+ Audio::getInstance()->addOptionPagesToWTB(&tabbar);\r
+#ifdef VOMP_PLATTFORM_MVP\r
+ MediaOptions::getInstance()->addOptionPagesToWTB(&tabbar);\r
+#endif\r
+\r
+\r
+ wop = new WOptionPane(); \r
+ tabbar.addTab(tr("Timers"), wop);\r
+ panes[1] = wop;\r
+ \r
+ option = new Option(9, "Default start margin (minutes)", "Timers", "Start margin", Option::TYPE_INT, 20, 5, 0, NULL);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(10, "Default end margin (minutes)", "Timers", "End margin", Option::TYPE_INT, 20, 5, 0, NULL);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(11, "Default priority", "Timers", "Priority", Option::TYPE_INT, 100, 99, 0, NULL);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(12, "Default lifetime", "Timers", "Lifetime", Option::TYPE_INT, 100, 99, 0, NULL);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+\r
+ Remote::getInstance()->addOptionsToPanes(1,&options,wop);\r
+ Video::getInstance()->addOptionsToPanes(1,&options,wop);\r
+ Audio::getInstance()->addOptionsToPanes(1,&options,wop);\r
+\r
+ \r
+ wop = new WOptionPane(); \r
+ tabbar.addTab(tr("Advanced"), wop);\r
+ panes[2] = wop;\r
+ \r
+ option = new Option(8, "VDR-Pri 0=OK !See forums!", "General", "Live priority", Option::TYPE_INT, 100, 0, 0, NULL);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(13, "TCP receive window size", "Advanced", "TCP receive window", Option::TYPE_TEXT, 7, 1, 0, options13);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option);\r
+ option = new Option(14, "Use WSS (PAL only)", "General", "WSS", Option::TYPE_TEXT, 2, 0, 0, options14);\r
+ options.push_back(option);\r
+ wop->addOptionLine(option); \r
+\r
+ Remote::getInstance()->addOptionsToPanes(2,&options,wop);\r
+ Video::getInstance()->addOptionsToPanes(2,&options,wop);\r
+ Audio::getInstance()->addOptionsToPanes(2,&options,wop);\r
+}\r
+\r
+VOpts::~VOpts()\r
+{\r
+ // for (int i = 0; i < numPanes; i++) delete panes[i]; //Move to TabBar, Marten\r
+ delete[] panes;\r
+\r
+ for(vector<Option*>::iterator j = options.begin(); j != options.end(); j++) delete *j;\r
+ delete[] options2;\r
+ delete[] options2keys;\r
+}\r
+\r
+int VOpts::handleCommand(int command)\r
+{\r
+ // either is active, handle back\r
+ if (command == Remote::BACK)\r
+ {\r
+ doSave();\r
+ return 4;\r
+ }\r
+ else\r
+ {\r
+ int retval = tabbar.handleCommand(command);\r
+ if (retval == 1)\r
+ {\r
+ BoxStack::getInstance()->update(this);\r
+ return 2;\r
+ }\r
+ else if (retval == 2)\r
+ {\r
+ // command was taken and actively ignored\r
+ return 2;\r
+ }\r
+ else\r
+ {\r
+ return 1; // ???\r
+ }\r
+ }\r
+}\r
+\r
+void VOpts::doSave()\r
+{\r
+ VDR* vdr = VDR::getInstance();\r
+\r
+ Remote::getInstance()->saveOptionstoServer(); //Remote\r
+ Video::getInstance()->saveOptionstoServer(); //Video\r
+ Audio::getInstance()->saveOptionstoServer(); //Remote\r
+#ifdef VOMP_PLATTFORM_MVP\r
+ MediaOptions::getInstance()->saveOptionstoServer(); //Media\r
+#endif\r
+\r
+ // Damn, and the dynamic idea was going *so* well...\r
+ //Whats about a check with typeid operator?\r
+ WOptionPane* wop;\r
+ wop = (WOptionPane*)panes[0];\r
+ wop->saveOpts(); \r
+ wop = (WOptionPane*)panes[1];\r
+ wop->saveOpts(); \r
+ wop = (WOptionPane*)panes[2];\r
+ wop->saveOpts(); \r
+\r
+\r
+ for (UINT i = 0; i < options.size(); i++)\r
+ {\r
+ if (options[i]->configChoice == options[i]->userSetChoice) continue; // no change\r
+\r
+ Log::getInstance()->log("Options", Log::DEBUG, "Option %i has changed", i);\r
+\r
+ // Save to vdr\r
+\r
+ if (options[i]->optionType == Option::TYPE_TEXT)\r
+ {\r
+ vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->options[options[i]->userSetChoice]);\r
+ }\r
+ else if (options[i]->optionType == Option::TYPE_KEYED_TEXT)\r
+ {\r
+ vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->optionkeys[options[i]->userSetChoice]);\r
+ }\r
+ else\r
+ {\r
+ char buffer[20];\r
+ sprintf(buffer, "%i", options[i]->userSetChoice);\r
+ vdr->configSave(options[i]->configSection, options[i]->configKey, buffer);\r
+ }\r
+ \r
+ // Set new setting\r
+ if (options[i]->opthandler == NULL) //Ok, noone else is handling this, we are doing it\r
+ {\r
+ switch(options[i]->id)\r
+ {\r
+ case 1:\r
+ {\r
+ if (options[i]->userSetChoice == 1)\r
+ {\r
+ Log::getInstance()->log("Options", Log::DEBUG, "Setting New Remote");\r
+ Remote::getInstance()->setRemoteType(Remote::NEWREMOTE);\r
+ }\r
+ else\r
+ {\r
+ Log::getInstance()->log("Options", Log::DEBUG, "Setting Old Remote");\r
+ Remote::getInstance()->setRemoteType(Remote::OLDREMOTE);\r
+ }\r
+ break;\r
+ }\r
+ case 2:\r
+ {\r
+ Message* m = new Message();\r
+ m->message = Message::CHANGE_LANGUAGE;\r
+ m->to = Command::getInstance();\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ break;\r
+ }\r
+ case 3:\r
+ {\r
+ if (options[i]->userSetChoice == 1)\r
+ {\r
+ Log::getInstance()->log("Options", Log::DEBUG, "Setting S-Video");\r
+ Video::getInstance()->setConnection(Video::SVIDEO);\r
+ }\r
+ else\r
+ {\r
+ Log::getInstance()->log("Options", Log::DEBUG, "Setting RGB/Composite");\r
+ Video::getInstance()->setConnection(Video::COMPOSITERGB);\r
+ }\r
+ break;\r
+ }\r
+ case 4:\r
+ {\r
+ if (options[i]->userSetChoice == 1)\r
+ {\r
+ Log::getInstance()->log("Options", Log::DEBUG, "Setting 16:9 TV");\r
+ Video::getInstance()->setTVsize(Video::ASPECT16X9);\r
+ }\r
+ else\r
+ {\r
+ Log::getInstance()->log("Options", Log::DEBUG, "Setting 4:3 TV");\r
+ Video::getInstance()->setTVsize(Video::ASPECT4X3);\r
+ }\r
+ break;\r
+ }\r
+ case 5:\r
+ {\r
+ if (options[i]->userSetChoice == 1)\r
+ {\r
+ Log::getInstance()->log("Options", Log::DEBUG, "Setting letterbox");\r
+ Video::getInstance()->setMode(Video::LETTERBOX);\r
+ }\r
+ else\r
+ {\r
+ Log::getInstance()->log("Options", Log::DEBUG, "Setting chop-sides");\r
+ Video::getInstance()->setMode(Video::NORMAL);\r
+ }\r
+ break;\r
+ }\r
+ case 13:\r
+ {\r
+ size_t newTCPsize = 2048;\r
+ if (options[i]->userSetChoice == 0) newTCPsize = 1024;\r
+ else if (options[i]->userSetChoice == 1) newTCPsize = 2048;\r
+ else if (options[i]->userSetChoice == 2) newTCPsize = 4096;\r
+ else if (options[i]->userSetChoice == 3) newTCPsize = 8192;\r
+ else if (options[i]->userSetChoice == 4) newTCPsize = 16384;\r
+ else if (options[i]->userSetChoice == 5) newTCPsize = 32768;\r
+ else if (options[i]->userSetChoice == 6) newTCPsize = 65536;\r
+ Log::getInstance()->log("Options", Log::DEBUG, "Setting TCP window size %i", newTCPsize);\r
+ VDR::getInstance()->setReceiveWindow(newTCPsize);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ options[i]->opthandler->handleOptionChanges(options[i]);\r
+ }\r
+ }\r
+}\r
+\r
+void VOpts::processMessage(Message* m)\r
+{\r
+ if (m->message == Message::MOUSE_MOVE)\r
+ {\r
+ int x=(m->parameter>>16)-getScreenX();\r
+ int y=(m->parameter&0xFFFF)-getScreenY();\r
+ if (tabbar.mouseMove(x,y))\r
+ {\r
+ BoxStack::getInstance()->update(this);\r
+ }\r
+ \r
+ }\r
+ else if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ int x=(m->parameter>>16)-getScreenX();\r
+ int y=(m->parameter&0xFFFF)-getScreenY();\r
+ if (tabbar.mouseLBDOWN(x,y)) \r
+ {\r
+ BoxStack::getInstance()->update(this);\r
+ } \r
+ else if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
+ }\r
+ }\r
+}\r
+\r
-/*
- Copyright 2004-2006 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vradiorec.h"
-
-#include "command.h"
-#include "osd.h"
-#include "player.h"
-#include "wsymbol.h"
-#include "recording.h"
-#include "message.h"
-#include "vdr.h"
-#include "video.h"
-#include "timers.h"
-#include "playerradio.h"
-#include "boxstack.h"
-#include "remote.h"
-#include "vinfo.h"
-#include "i18n.h"
-#include "log.h"
-
-VRadioRec::VRadioRec(Recording* rec)
-{
- boxstack = BoxStack::getInstance();
- vdr = VDR::getInstance();
- video = Video::getInstance();
- timers = Timers::getInstance();
- myRec = rec;
- playing = false;
- startMargin = 0;
- endMargin = 0;
-
- player = new PlayerRadio(Command::getInstance(), this);
-
- char* cstartMargin = vdr->configLoad("Timers", "Start margin");
- char* cendMargin = vdr->configLoad("Timers", "End margin");
- if (!cstartMargin)
- {
- startMargin = 300; // 5 mins default
- }
- else
- {
- startMargin = atoi(cstartMargin) * 60;
- delete[] cstartMargin;
- }
-
- if (!cendMargin)
- {
- endMargin = 300; // 5 mins default
- }
- else
- {
- endMargin = atoi(cendMargin) * 60;
- delete[] cendMargin;
- }
-
- Log::getInstance()->log("VRadioRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);
-
- setSize(video->getScreenWidth(), video->getScreenHeight());
- createBuffer();
- setPosition(0, 0);
-
- barRegion.x = 0;
- barRegion.y = video->getScreenHeight() - 58; // FIXME, need to be - 1? and below?
- barRegion.w = video->getScreenWidth();
- barRegion.h = 58;
-
- clocksRegion.x = barRegion.x + 140;
- clocksRegion.y = barRegion.y + 12;
- clocksRegion.w = 170;
- clocksRegion.h = surface->getFontHeight();
-
-
- barBlue.set(0, 0, 150, 150);
-
- barShowing = false;
-}
-
-void VRadioRec::preDelete()
-{
- timers->cancelTimer(this, 1);
- timers->cancelTimer(this, 2);
-}
-
-VRadioRec::~VRadioRec()
-{
- if (playing) stopPlay();
-
-
- // kill recInfo in case resumePoint has changed (likely)
- myRec->dropRecInfo();
- // FIXME - do this properly - save the resume point back to the server manually and update
- // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well
-}
-
-void VRadioRec::draw()
-{
- fillColour(Colour::BLACK);
-}
-
-void VRadioRec::go()
-{
- Log::getInstance()->log("VRadioRec", Log::DEBUG, "Starting stream: %s", myRec->getFileName());
- ULONG lengthFrames = 0;
- bool isPesRecording;
- ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);
- myRec->IsPesRecording = isPesRecording;
-
- bool cantStart = false;
-
- if (!lengthBytes) cantStart = true;
- else if (!player->init(lengthBytes, lengthFrames, myRec->IsPesRecording)) cantStart = true;
- else
- {
- doBar(0);
- // player->setStartBytes(startBytes);
- player->play();
- playing = true;
- }
-
- if (cantStart)
- {
- stopPlay(); // clean up
-
- if (!vdr->isConnected())
- {
- Command::getInstance()->connectionLost();
- return;
- }
-
- Message* m = new Message();
- m->message = Message::CLOSE_ME;
- m->from = this;
- m->to = boxstack;
- Command::getInstance()->postMessageNoLock(m);
-
- VInfo* vi = new VInfo();
- vi->setSize(400, 150);
- vi->createBuffer();
- if (video->getFormat() == Video::PAL)
- vi->setPosition(170, 200);
- else
- vi->setPosition(160, 150);
- vi->setExitable();
- vi->setBorderOn(1);
- vi->setTitleBarOn(0);
- vi->setOneLiner(tr("Error playing recording"));
- vi->draw();
-
- m = new Message();
- m->message = Message::ADD_VIEW;
- m->to = boxstack;
- m->parameter = (ULONG)vi;
- Command::getInstance()->postMessageNoLock(m);
- }
-}
-
-int VRadioRec::handleCommand(int command)
-{
- switch(command)
- {
- case Remote::PLAY:
- {
- player->play();
- doBar(0);
- return 2;
- }
-
- case Remote::STOP:
- case Remote::BACK:
- case Remote::MENU:
- {
- if (playing) stopPlay();
- return 4;
- }
- case Remote::PAUSE:
- {
- player->pause();
- doBar(0);
- return 2;
- }
- case Remote::SKIPFORWARD:
- {
- doBar(3);
- player->skipForward(60);
- return 2;
- }
- case Remote::SKIPBACK:
- {
- doBar(4);
- player->skipBackward(60);
- return 2;
- }
- case Remote::YELLOW:
- {
- doBar(2);
- player->skipBackward(10);
- return 2;
- }
- case Remote::BLUE:
- {
- doBar(1);
- player->skipForward(10);
- return 2;
- }
- case Remote::OK:
- {
- if (barShowing) removeBar();
- else doBar(0);
- return 2;
- }
-
- case Remote::ZERO: player->jumpToPercent(0); doBar(0); return 2;
- case Remote::ONE: player->jumpToPercent(10); doBar(0); return 2;
- case Remote::TWO: player->jumpToPercent(20); doBar(0); return 2;
- case Remote::THREE: player->jumpToPercent(30); doBar(0); return 2;
- case Remote::FOUR: player->jumpToPercent(40); doBar(0); return 2;
- case Remote::FIVE: player->jumpToPercent(50); doBar(0); return 2;
- case Remote::SIX: player->jumpToPercent(60); doBar(0); return 2;
- case Remote::SEVEN: player->jumpToPercent(70); doBar(0); return 2;
- case Remote::EIGHT: player->jumpToPercent(80); doBar(0); return 2;
- case Remote::NINE: player->jumpToPercent(90); doBar(0); return 2;
-
-#ifdef DEV
- case Remote::RED:
- {
- //player->test1();
-
- return 2;
- }
- case Remote::GREEN:
- {
- //player->test2();
- return 2;
- }
-#endif
-
- }
-
- return 1;
-}
-
-void VRadioRec::processMessage(Message* m)
-{
- if (m->message == Message::MOUSE_LBDOWN)
- {
- int x=(m->parameter>>16)-(int)getScreenX();
- int y=(m->parameter&0xFFFF)-(int)getScreenY();
- if (!barShowing)
- {
- boxstack->handleCommand(Remote::OK); //simulate rok press
- }
- else if ((int)barRegion.x<=x && (int)barRegion.y<=y && ((int)barRegion.x+(int)barRegion.w)>=x
- && ((int)barRegion.y+(int)barRegion.h)>=y)
- {
- int progBarXbase = barRegion.x + 300;
- if (x>=(int)barRegion.x + progBarXbase + 24
- && x<=(int)barRegion.x + progBarXbase + 4 + 302
- && y>=(int)barRegion.y + 12 - 2
- && y<=(int)barRegion.y + 12 - 2+28)
- {
- int cx=x-(barRegion.x + progBarXbase + 4);
- double percent=((double)cx)/302.*100.;
- player->jumpToPercent(percent);
- doBar(3);
- return;
- // int progressWidth = 302 * currentFrameNum / lengthFrames;
- // rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
- }
- }
- else
- {
- boxstack->handleCommand(Remote::OK); //simulate rok press
- }
- }
- else if (m->message == Message::PLAYER_EVENT)
- {
- if (m->from != player) return;
-
- Log::getInstance()->log("VRadioRec", Log::DEBUG, "Message received");
-
- switch(m->parameter)
- {
- case Player::CONNECTION_LOST: // connection lost detected
- {
- // I can't handle this, send it to command
- Message* m2 = new Message();
- m2->to = Command::getInstance();
- m2->message = Message::CONNECTION_LOST;
- Command::getInstance()->postMessageNoLock(m2);
- break;
- }
- case Player::STOP_PLAYBACK:
- {
- // FIXME Obselete ish - improve this
- Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
- m2->to = Command::getInstance();
- m2->message = Message::STOP_PLAYBACK;
- Command::getInstance()->postMessageNoLock(m2);
- break;
- }
- }
- }
-}
-
-void VRadioRec::stopPlay()
-{
- Log::getInstance()->log("VRadioRec", Log::DEBUG, "Pre stopPlay");
-
- removeBar();
- player->stop();
- vdr->stopStreaming();
- delete player;
-
- playing = false;
-
- if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
- Log::getInstance()->log("VRadioRec", Log::DEBUG, "Post stopPlay");
-}
-
-void VRadioRec::doBar(int action)
-{
- barShowing = true;
-
- rectangle(barRegion, barBlue);
-
- /* Work out what to display - choices:
-
- Playing >
- Paused ||
-
- Specials, informed by parameter
-
- Skip forward 10s >|
- Skip backward 10s |<
- Skip forward 1m >>|
- Skip backward 1m |<<
-
- */
-
- WSymbol w;
- TEMPADD(&w);
- w.nextSymbol = 0;
- w.setPosition(barRegion.x + 66, barRegion.y + 16);
-
- UCHAR playerState = 0;
-
- if (action)
- {
- if (action == 1) w.nextSymbol = WSymbol::SKIPFORWARD;
- else if (action == 2) w.nextSymbol = WSymbol::SKIPBACK;
- else if (action == 3) w.nextSymbol = WSymbol::SKIPFORWARD2;
- else if (action == 4) w.nextSymbol = WSymbol::SKIPBACK2;
- }
- else
- {
- playerState = player->getState();
- if (playerState == Player::S_PAUSE_P) w.nextSymbol = WSymbol::PAUSE;
- else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
- else w.nextSymbol = WSymbol::PLAY;
- }
-
- w.draw();
-
- drawBarClocks();
-
- BoxStack::getInstance()->update(this, &barRegion);
-
- timers->setTimerD(this, 1, 4); // only set the getridofbar timer if not ffwd/fbwd
- timers->setTimerD(this, 2, 0, 200000000);
-}
-
-void VRadioRec::timercall(int clientReference)
-{
- switch(clientReference)
- {
- case 1:
- {
- // Remove bar
- removeBar();
- break;
- }
- case 2:
- {
- // Update clock
- if (!barShowing) break;
- drawBarClocks();
- boxstack->update(this, &barRegion);
-
- timers->setTimerD(this, 2, 0, 200000000);
- break;
- }
- }
-}
-
-void VRadioRec::drawBarClocks()
-{
- Log* logger = Log::getInstance();
- logger->log("VRadioRec", Log::DEBUG, "Draw bar clocks");
-
- // Draw RTC
- // Blank the area first
- rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
- char timeString[20];
- time_t t;
- time(&t);
- struct tm* tms = localtime(&t);
- strftime(timeString, 19, "%H:%M", tms);
- drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
-
- // Draw clocks
-
- rectangle(clocksRegion, barBlue);
-
-/*
- ULONG currentFrameNum = player->getCurrentFrameNum();
- ULONG lengthFrames;
- if (myRec->recInfo->timerEnd > time(NULL))
- {
- // chasing playback
- // Work out an approximate length in frames (good to 1s...)
- lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
- }
- else
- {
-// lengthFrames = player->getLengthFrames();
- lengthFrames = 0;
- }
-
- hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);
- hmsf lengthHMSF = video->framesToHMSF(lengthFrames);
-
- char buffer[100];
- if (currentFrameNum >= lengthFrames)
- {
- strcpy(buffer, "-:--:-- / -:--:--");
- }
- else
- {
- SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
- logger->log("VRadioRec", Log::DEBUG, buffer);
- }
-*/
-
- ULONG currentSeconds = player->getCurrentSeconds();
- ULONG lengthSeconds = player->getLengthSeconds();
- char buffer[100];
-
- if (lengthSeconds && (currentSeconds < lengthSeconds))
- {
- ULONG dcurrentSeconds = currentSeconds;
- ULONG dlengthSeconds = lengthSeconds;
-
- ULONG currentHours = dcurrentSeconds / 3600;
- dcurrentSeconds %= 3600;
- ULONG currentMinutes = dcurrentSeconds / 60;
- dcurrentSeconds %= 60;
-
- ULONG lengthHours = dlengthSeconds / 3600;
- dlengthSeconds %= 3600;
- ULONG lengthMinutes = dlengthSeconds / 60;
- dlengthSeconds %= 60;
-
- SNPRINTF(buffer, 99, "%01lu:%02lu:%02lu / %01lu:%02lu:%02lu", currentHours, currentMinutes, dcurrentSeconds, lengthHours, lengthMinutes, dlengthSeconds);
- logger->log("VRadioRec", Log::DEBUG, buffer);
- }
- else
- {
- strcpy(buffer, "-:--:-- / -:--:--");
- }
-
- drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
-
- // Draw progress bar
- int progBarXbase = barRegion.x + 300;
-
- rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
- rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
-
- if (currentSeconds > lengthSeconds) return;
- if (lengthSeconds == 0) return;
-
- // Draw yellow portion
- int progressWidth = 302 * currentSeconds / lengthSeconds;
- rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-/*
-
- if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
- {
- int nrWidth = (int)(302 * ((double)(lengthFrames - 0) / lengthFrames)); // 0 inserted instead of getlengthframes
-
- Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
-// Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
- Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
- rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);
- }
-*/
-
- logger->log("VRadioRec", Log::DEBUG, "blips");
-
- // Now calc position for start margin blips
- int posPix;
-
- posPix = 302 * startMargin / lengthSeconds;
- logger->log("VRadioRec", Log::DEBUG, "posPix %i", posPix);
-
- rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
- rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
-
- posPix = 302 * (lengthSeconds - endMargin) / lengthSeconds;
-
- rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
- rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
-}
-
-void VRadioRec::removeBar()
-{
- if (!barShowing) return;
- timers->cancelTimer(this, 2);
- barShowing = false;
- rectangle(barRegion, Colour::BLACK);
- boxstack->update(this, &barRegion);
-}
-
+/*\r
+ Copyright 2004-2006 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vradiorec.h"\r
+\r
+#include "command.h"\r
+#include "osd.h"\r
+#include "player.h"\r
+#include "wsymbol.h"\r
+#include "recording.h"\r
+#include "message.h"\r
+#include "vdr.h"\r
+#include "video.h"\r
+#include "timers.h"\r
+#include "playerradio.h"\r
+#include "boxstack.h"\r
+#include "remote.h"\r
+#include "vinfo.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+\r
+VRadioRec::VRadioRec(Recording* rec)\r
+{\r
+ boxstack = BoxStack::getInstance();\r
+ vdr = VDR::getInstance();\r
+ video = Video::getInstance();\r
+ timers = Timers::getInstance();\r
+ myRec = rec;\r
+ playing = false;\r
+ startMargin = 0;\r
+ endMargin = 0;\r
+\r
+ player = new PlayerRadio(Command::getInstance(), this);\r
+\r
+ char* cstartMargin = vdr->configLoad("Timers", "Start margin");\r
+ char* cendMargin = vdr->configLoad("Timers", "End margin");\r
+ if (!cstartMargin)\r
+ {\r
+ startMargin = 300; // 5 mins default\r
+ }\r
+ else\r
+ {\r
+ startMargin = atoi(cstartMargin) * 60;\r
+ delete[] cstartMargin;\r
+ }\r
+\r
+ if (!cendMargin)\r
+ {\r
+ endMargin = 300; // 5 mins default\r
+ }\r
+ else\r
+ {\r
+ endMargin = atoi(cendMargin) * 60;\r
+ delete[] cendMargin;\r
+ }\r
+\r
+ Log::getInstance()->log("VRadioRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);\r
+\r
+ setSize(video->getScreenWidth(), video->getScreenHeight());\r
+ createBuffer();\r
+ setPosition(0, 0);\r
+\r
+ barRegion.x = 0;\r
+ barRegion.y = video->getScreenHeight() - 58; // FIXME, need to be - 1? and below?\r
+ barRegion.w = video->getScreenWidth();\r
+ barRegion.h = 58;\r
+\r
+ clocksRegion.x = barRegion.x + 140;\r
+ clocksRegion.y = barRegion.y + 12;\r
+ clocksRegion.w = 170;\r
+ clocksRegion.h = getFontHeight();\r
+\r
+\r
+ barBlue.set(0, 0, 150, 150);\r
+\r
+ barShowing = false;\r
+}\r
+\r
+void VRadioRec::preDelete()\r
+{\r
+ timers->cancelTimer(this, 1);\r
+ timers->cancelTimer(this, 2);\r
+}\r
+\r
+VRadioRec::~VRadioRec()\r
+{\r
+ if (playing) stopPlay();\r
+\r
+\r
+ // kill recInfo in case resumePoint has changed (likely)\r
+ myRec->dropRecInfo();\r
+ // FIXME - do this properly - save the resume point back to the server manually and update\r
+ // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well\r
+}\r
+\r
+void VRadioRec::draw()\r
+{\r
+ fillColour(Colour::BLACK);\r
+}\r
+\r
+void VRadioRec::go()\r
+{\r
+ Log::getInstance()->log("VRadioRec", Log::DEBUG, "Starting stream: %s", myRec->getFileName());\r
+ ULONG lengthFrames = 0;\r
+ bool isPesRecording;\r
+ ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);\r
+ myRec->IsPesRecording = isPesRecording;\r
+\r
+ bool cantStart = false;\r
+\r
+ if (!lengthBytes) cantStart = true;\r
+ else if (!player->init(lengthBytes, lengthFrames, myRec->IsPesRecording)) cantStart = true;\r
+ else\r
+ {\r
+ doBar(0);\r
+ // player->setStartBytes(startBytes);\r
+ player->play();\r
+ playing = true;\r
+ }\r
+\r
+ if (cantStart)\r
+ {\r
+ stopPlay(); // clean up\r
+\r
+ if (!vdr->isConnected())\r
+ {\r
+ Command::getInstance()->connectionLost();\r
+ return;\r
+ }\r
+\r
+ Message* m = new Message();\r
+ m->message = Message::CLOSE_ME;\r
+ m->from = this;\r
+ m->to = boxstack;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+\r
+ VInfo* vi = new VInfo();\r
+ vi->setSize(400, 150);\r
+ vi->createBuffer();\r
+ if (video->getFormat() == Video::PAL)\r
+ vi->setPosition(170, 200);\r
+ else\r
+ vi->setPosition(160, 150);\r
+ vi->setExitable();\r
+ vi->setBorderOn(1);\r
+ vi->setTitleBarOn(0);\r
+ vi->setOneLiner(tr("Error playing recording"));\r
+ vi->draw();\r
+\r
+ m = new Message();\r
+ m->message = Message::ADD_VIEW;\r
+ m->to = boxstack;\r
+ m->parameter = (ULONG)vi;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ }\r
+}\r
+\r
+int VRadioRec::handleCommand(int command)\r
+{\r
+ switch(command)\r
+ {\r
+ case Remote::PLAY:\r
+ {\r
+ player->play();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+ case Remote::PLAYPAUSE:\r
+ {\r
+ player->playpause();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+\r
+ case Remote::STOP:\r
+ case Remote::BACK:\r
+ case Remote::MENU:\r
+ {\r
+ if (playing) stopPlay();\r
+ return 4;\r
+ }\r
+ case Remote::PAUSE:\r
+ {\r
+ player->pause();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+ case Remote::SKIPFORWARD:\r
+ {\r
+ doBar(3);\r
+ player->skipForward(60);\r
+ return 2;\r
+ }\r
+ case Remote::SKIPBACK:\r
+ {\r
+ doBar(4);\r
+ player->skipBackward(60);\r
+ return 2;\r
+ }\r
+ case Remote::YELLOW:\r
+ {\r
+ doBar(2);\r
+ player->skipBackward(10);\r
+ return 2;\r
+ }\r
+ case Remote::BLUE:\r
+ {\r
+ doBar(1);\r
+ player->skipForward(10);\r
+ return 2;\r
+ }\r
+ case Remote::OK:\r
+ {\r
+ if (barShowing) removeBar();\r
+ else doBar(0);\r
+ return 2;\r
+ }\r
+\r
+ case Remote::ZERO: player->jumpToPercent(0); doBar(0); return 2;\r
+ case Remote::ONE: player->jumpToPercent(10); doBar(0); return 2;\r
+ case Remote::TWO: player->jumpToPercent(20); doBar(0); return 2;\r
+ case Remote::THREE: player->jumpToPercent(30); doBar(0); return 2;\r
+ case Remote::FOUR: player->jumpToPercent(40); doBar(0); return 2;\r
+ case Remote::FIVE: player->jumpToPercent(50); doBar(0); return 2;\r
+ case Remote::SIX: player->jumpToPercent(60); doBar(0); return 2;\r
+ case Remote::SEVEN: player->jumpToPercent(70); doBar(0); return 2;\r
+ case Remote::EIGHT: player->jumpToPercent(80); doBar(0); return 2;\r
+ case Remote::NINE: player->jumpToPercent(90); doBar(0); return 2;\r
+\r
+#ifdef DEV\r
+ case Remote::RED:\r
+ {\r
+ //player->test1();\r
+\r
+ return 2;\r
+ }\r
+ case Remote::GREEN:\r
+ {\r
+ //player->test2();\r
+ return 2;\r
+ }\r
+#endif\r
+\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+void VRadioRec::processMessage(Message* m)\r
+{\r
+ if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ int x=(m->parameter>>16)-(int)getScreenX();\r
+ int y=(m->parameter&0xFFFF)-(int)getScreenY();\r
+ if (!barShowing)\r
+ {\r
+ boxstack->handleCommand(Remote::OK); //simulate rok press\r
+ }\r
+ else if ((int)barRegion.x<=x && (int)barRegion.y<=y && ((int)barRegion.x+(int)barRegion.w)>=x\r
+ && ((int)barRegion.y+(int)barRegion.h)>=y)\r
+ {\r
+ int progBarXbase = barRegion.x + 300;\r
+ if (x>=(int)barRegion.x + progBarXbase + 24\r
+ && x<=(int)barRegion.x + progBarXbase + 4 + 302\r
+ && y>=(int)barRegion.y + 12 - 2\r
+ && y<=(int)barRegion.y + 12 - 2+28)\r
+ {\r
+ int cx=x-(barRegion.x + progBarXbase + 4);\r
+ double percent=((double)cx)/302.*100.;\r
+ player->jumpToPercent(percent);\r
+ doBar(3);\r
+ return;\r
+ // int progressWidth = 302 * currentFrameNum / lengthFrames;\r
+ // rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ boxstack->handleCommand(Remote::OK); //simulate rok press\r
+ }\r
+ }\r
+ else if (m->message == Message::PLAYER_EVENT)\r
+ {\r
+ if (m->from != player) return;\r
+\r
+ Log::getInstance()->log("VRadioRec", Log::DEBUG, "Message received");\r
+\r
+ switch(m->parameter)\r
+ {\r
+ case Player::CONNECTION_LOST: // connection lost detected\r
+ {\r
+ // I can't handle this, send it to command\r
+ Message* m2 = new Message();\r
+ m2->to = Command::getInstance();\r
+ m2->message = Message::CONNECTION_LOST;\r
+ Command::getInstance()->postMessageNoLock(m2);\r
+ break;\r
+ }\r
+ case Player::STOP_PLAYBACK:\r
+ {\r
+ // FIXME Obselete ish - improve this\r
+ Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+ m2->to = Command::getInstance();\r
+ m2->message = Message::STOP_PLAYBACK;\r
+ Command::getInstance()->postMessageNoLock(m2);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void VRadioRec::stopPlay()\r
+{\r
+ Log::getInstance()->log("VRadioRec", Log::DEBUG, "Pre stopPlay");\r
+\r
+ removeBar();\r
+ player->stop();\r
+ vdr->stopStreaming();\r
+ delete player;\r
+\r
+ playing = false;\r
+\r
+ if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }\r
+ Log::getInstance()->log("VRadioRec", Log::DEBUG, "Post stopPlay");\r
+}\r
+\r
+void VRadioRec::doBar(int action)\r
+{\r
+ barShowing = true;\r
+\r
+ rectangle(barRegion, barBlue);\r
+\r
+ /* Work out what to display - choices:\r
+\r
+ Playing >\r
+ Paused ||\r
+\r
+ Specials, informed by parameter\r
+\r
+ Skip forward 10s >|\r
+ Skip backward 10s |<\r
+ Skip forward 1m >>|\r
+ Skip backward 1m |<<\r
+\r
+ */\r
+\r
+ WSymbol w;\r
+ TEMPADD(&w);\r
+ w.nextSymbol = 0;\r
+ w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
+\r
+ UCHAR playerState = 0;\r
+\r
+ if (action)\r
+ {\r
+ if (action == 1) w.nextSymbol = WSymbol::SKIPFORWARD;\r
+ else if (action == 2) w.nextSymbol = WSymbol::SKIPBACK;\r
+ else if (action == 3) w.nextSymbol = WSymbol::SKIPFORWARD2;\r
+ else if (action == 4) w.nextSymbol = WSymbol::SKIPBACK2;\r
+ }\r
+ else\r
+ {\r
+ playerState = player->getState();\r
+ if (playerState == Player::S_PAUSE_P) w.nextSymbol = WSymbol::PAUSE;\r
+ else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;\r
+ else w.nextSymbol = WSymbol::PLAY;\r
+ }\r
+\r
+ w.draw();\r
+\r
+ drawBarClocks();\r
+\r
+ BoxStack::getInstance()->update(this, &barRegion);\r
+\r
+ timers->setTimerD(this, 1, 4); // only set the getridofbar timer if not ffwd/fbwd\r
+ timers->setTimerD(this, 2, 0, 200000000);\r
+}\r
+\r
+void VRadioRec::timercall(int clientReference)\r
+{\r
+ switch(clientReference)\r
+ {\r
+ case 1:\r
+ {\r
+ // Remove bar\r
+ removeBar();\r
+ break;\r
+ }\r
+ case 2:\r
+ {\r
+ // Update clock\r
+ if (!barShowing) break;\r
+ drawBarClocks();\r
+ boxstack->update(this, &barRegion);\r
+ \r
+ timers->setTimerD(this, 2, 0, 200000000);\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+void VRadioRec::drawBarClocks()\r
+{\r
+ Log* logger = Log::getInstance();\r
+ logger->log("VRadioRec", Log::DEBUG, "Draw bar clocks");\r
+\r
+ // Draw RTC\r
+ // Blank the area first\r
+ rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
+ char timeString[20];\r
+ time_t t;\r
+ time(&t);\r
+ struct tm* tms = localtime(&t);\r
+ strftime(timeString, 19, "%H:%M", tms);\r
+ drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);\r
+\r
+ // Draw clocks\r
+\r
+ rectangle(clocksRegion, barBlue);\r
+\r
+/*\r
+ ULONG currentFrameNum = player->getCurrentFrameNum();\r
+ ULONG lengthFrames;\r
+ if (myRec->recInfo->timerEnd > time(NULL))\r
+ {\r
+ // chasing playback\r
+ // Work out an approximate length in frames (good to 1s...)\r
+ lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();\r
+ }\r
+ else\r
+ {\r
+// lengthFrames = player->getLengthFrames();\r
+ lengthFrames = 0;\r
+ }\r
+\r
+ hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);\r
+ hmsf lengthHMSF = video->framesToHMSF(lengthFrames);\r
+\r
+ char buffer[100];\r
+ if (currentFrameNum >= lengthFrames)\r
+ {\r
+ strcpy(buffer, "-:--:-- / -:--:--");\r
+ }\r
+ else\r
+ {\r
+ SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
+ logger->log("VRadioRec", Log::DEBUG, buffer);\r
+ }\r
+*/\r
+\r
+ ULONG currentSeconds = player->getCurrentSeconds();\r
+ ULONG lengthSeconds = player->getLengthSeconds();\r
+ char buffer[100];\r
+\r
+ if (lengthSeconds && (currentSeconds < lengthSeconds))\r
+ {\r
+ ULONG dcurrentSeconds = currentSeconds;\r
+ ULONG dlengthSeconds = lengthSeconds;\r
+\r
+ ULONG currentHours = dcurrentSeconds / 3600;\r
+ dcurrentSeconds %= 3600;\r
+ ULONG currentMinutes = dcurrentSeconds / 60;\r
+ dcurrentSeconds %= 60;\r
+\r
+ ULONG lengthHours = dlengthSeconds / 3600;\r
+ dlengthSeconds %= 3600;\r
+ ULONG lengthMinutes = dlengthSeconds / 60;\r
+ dlengthSeconds %= 60;\r
+\r
+ SNPRINTF(buffer, 99, "%01lu:%02lu:%02lu / %01lu:%02lu:%02lu", currentHours, currentMinutes, dcurrentSeconds, lengthHours, lengthMinutes, dlengthSeconds);\r
+ logger->log("VRadioRec", Log::DEBUG, buffer);\r
+ }\r
+ else\r
+ {\r
+ strcpy(buffer, "-:--:-- / -:--:--");\r
+ }\r
+\r
+ drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);\r
+\r
+ // Draw progress bar\r
+ int progBarXbase = barRegion.x + 300;\r
+\r
+ rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);\r
+ rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
+\r
+ if (currentSeconds > lengthSeconds) return;\r
+ if (lengthSeconds == 0) return;\r
+\r
+ // Draw yellow portion\r
+ int progressWidth = 302 * currentSeconds / lengthSeconds;\r
+ rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+/*\r
+\r
+ if (myRec->recInfo->timerEnd > time(NULL)) // if chasing\r
+ {\r
+ int nrWidth = (int)(302 * ((double)(lengthFrames - 0) / lengthFrames)); // 0 inserted instead of getlengthframes\r
+\r
+ Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);\r
+// Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());\r
+ Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);\r
+ rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);\r
+ }\r
+*/\r
+\r
+ logger->log("VRadioRec", Log::DEBUG, "blips");\r
+\r
+ // Now calc position for start margin blips\r
+ int posPix;\r
+\r
+ posPix = 302 * startMargin / lengthSeconds;\r
+ logger->log("VRadioRec", Log::DEBUG, "posPix %i", posPix);\r
+\r
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);\r
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);\r
+\r
+ posPix = 302 * (lengthSeconds - endMargin) / lengthSeconds;\r
+\r
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);\r
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);\r
+}\r
+\r
+void VRadioRec::removeBar()\r
+{\r
+ if (!barShowing) return;\r
+ timers->cancelTimer(this, 2);\r
+ barShowing = false;\r
+ rectangle(barRegion, Colour::BLACK);\r
+ boxstack->update(this, &barRegion);\r
+}\r
+\r
parent = tparent;
}
-void VRecMove::addDirs(Directory* dir, char* prefix)
+void VRecMove::addDirs(Directory* dir,const char* prefix)
{
Directory* currentDir;
for(DirectoryList::iterator i = dir->dirList.begin(); i != dir->dirList.end(); i++)
void* parent;
RecMan* recman;
WSelectList sl;
- void addDirs(Directory* dir, char* prefix);
+ void addDirs(Directory* dir,const char* prefix);
};
#endif
-/*
- Copyright 2004-2008 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vrecording.h"
-
-#include "remote.h"
-#include "recinfo.h"
-#include "vquestion.h"
-#include "vinfo.h"
-#include "vdr.h"
-#include "colour.h"
-#include "video.h"
-#include "i18n.h"
-#include "command.h"
-#include "vrecmove.h"
-#include "boxstack.h"
-#include "recman.h"
-#include "vrecordinglist.h"
-#include "recording.h"
-#include "message.h"
-#include "log.h"
-
-VRecording::VRecording(RecMan* trecman, Recording* trec)
-{
- rec = trec;
- recman = trecman;
-
- Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());
- rec->loadRecInfo();
- Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());
-
- setSize(570, 420);
- createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- setPosition(80, 70);
- }
- else
- {
- setPosition(70, 35);
- }
-
- setTitleBarOn(1);
- setBorderOn(1);
- setTitleText(rec->getProgName());
- setTitleBarColour(Colour::TITLEBARBACKGROUND);
-
- summary.setPosition(10, 30 + 5);
- summary.setSize(area.w - 20, area.h - 30 - 15 - 50);
- summary.setParaMode(true);
-
- if (rec->recInfo &&strlen(rec->recInfo->summary))
- summary.setText(rec->recInfo->summary);
- else
- summary.setText(tr("Summary unavailable"));
-
- add(&summary);
-
-
- buttonPlay.setPosition(10, area.h - 40);
- buttonResume.setPosition(150, area.h - 40);
- buttonMove.setPosition(290, area.h - 40);
- buttonDelete.setPosition(430, area.h - 40);
-
- int sfh = Surface::getFontHeight();
-
- buttonPlay.setSize(130, sfh);
- buttonResume.setSize(130, sfh);
- buttonMove.setSize(130, sfh);
- buttonDelete.setSize(130, sfh);
-
- buttonRegion.x = 10;
- buttonRegion.y = area.h - 40;
- buttonRegion.w = 550;
- buttonRegion.h = sfh;
-
- buttonPlay.setText(tr("Play"));
- buttonResume.setText(tr("Resume"));
- buttonMove.setText(tr("Move"));
- buttonDelete.setText(tr("Delete"));
-
- add(&buttonPlay);
- add(&buttonResume);
- add(&buttonMove);
- add(&buttonDelete);
-
- buttonPlay.setActive(1);
- selected = 1;
-}
-
-VRecording::~VRecording()
-{
-}
-
-void VRecording::setParent(VRecordingList* tvRecList)
-{
- vRecList = tvRecList;
-}
-
-void VRecording::draw()
-{
- TBBoxx::draw();
-}
-
-int VRecording::handleCommand(int command)
-{
- switch(command)
- {
- case Remote::LEFT:
- case Remote::DF_LEFT:
- case Remote::DF_UP:
- case Remote::UP:
- {
- doLeft();
- return 2;
- }
- case Remote::RIGHT:
- case Remote::DF_RIGHT:
- case Remote::DF_DOWN:
- case Remote::DOWN:
- {
- doRight();
- return 2;
- }
- case Remote::OK:
- {
-
- if (selected == 1)
- {
- Message* m = new Message(); // Must be done after this view deleted
- m->from = this;
- m->to = vRecList;
- m->message = Message::PLAY_SELECTED_RECORDING;
- Command::getInstance()->postMessageNoLock(m);
- return 4;
- }
-
- if (selected == 2)
- {
- Message* m = new Message(); // Must be done after this view deleted
- m->from = this;
- m->to = vRecList;
- m->message = Message::RESUME_SELECTED_RECORDING;
- Command::getInstance()->postMessageNoLock(m);
- return 4;
- }
-
- if (selected == 3)
- {
- VRecMove* vrm = new VRecMove(recman);
- vrm->setParent(this);
- vrm->draw();
- BoxStack::getInstance()->add(vrm);
- BoxStack::getInstance()->update(vrm);
- return 2;
- }
-
- if (selected == 4)
- {
- VQuestion* v = new VQuestion(this);
- v->setSize(260, 180);
- v->createBuffer();
- v->setTitleBarColour(Colour::DANGER);
- v->setTitleBarOn(1);
- v->setBorderOn(1);
- v->setTitleText(tr("Delete recording"));
- v->setMainText(tr("Are you sure you want to delete this recording?"));
- v->setDefault(VQuestion::NO);
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- v->setPosition(230, 160);
- }
- else
- {
- v->setPosition(220, 140);
- }
-
- v->draw();
- BoxStack::getInstance()->add(v);
- BoxStack::getInstance()->update(v);
- return 2;
- }
- }
-
- case Remote::BACK:
- {
- return 4;
- }
- }
- // stop command getting to any more views
- return 1;
-}
-
-void VRecording::doRight()
-{
- switch(selected)
- {
- case 1:
- buttonPlay.setActive(0);
- buttonResume.setActive(1);
- buttonPlay.draw();
- buttonResume.draw();
- break;
- case 2:
- buttonResume.setActive(0);
- buttonMove.setActive(1);
- buttonResume.draw();
- buttonMove.draw();
- break;
- case 3:
- buttonMove.setActive(0);
- buttonDelete.setActive(1);
- buttonMove.draw();
- buttonDelete.draw();
- break;
- case 4:
- buttonDelete.setActive(0);
- buttonPlay.setActive(1);
- buttonDelete.draw();
- buttonPlay.draw();
- break;
- }
-
- if (++selected == 5) selected = 1;
-
- BoxStack::getInstance()->update(this, &buttonRegion);
-}
-
-void VRecording::doLeft()
-{
- switch(selected)
- {
- case 1:
- buttonPlay.setActive(0);
- buttonDelete.setActive(1);
- buttonPlay.draw();
- buttonDelete.draw();
- break;
- case 2:
- buttonResume.setActive(0);
- buttonPlay.setActive(1);
- buttonResume.draw();
- buttonPlay.draw();
- break;
- case 3:
- buttonMove.setActive(0);
- buttonResume.setActive(1);
- buttonMove.draw();
- buttonResume.draw();
- break;
- case 4:
- buttonDelete.setActive(0);
- buttonMove.setActive(1);
- buttonDelete.draw();
- buttonMove.draw();
- break;
- }
-
- if (--selected == 0) selected = 4;
-
- BoxStack::getInstance()->update(this, &buttonRegion);
-}
-
-void VRecording::processMessage(Message* m)
-{
- if (m->message == Message::MOUSE_MOVE)
- {
- if (buttonPlay.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- buttonPlay.setActive(1);
- buttonResume.setActive(0);
- buttonMove.setActive(0);
- buttonDelete.setActive(0);
- selected=1;
- draw();
- BoxStack::getInstance()->update(this);
- }
- else if (buttonResume.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- buttonPlay.setActive(0);
- buttonResume.setActive(1);
- buttonMove.setActive(0);
- buttonDelete.setActive(0);
- selected=2;
- draw();
- BoxStack::getInstance()->update(this);
- }
- else if (buttonMove.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- buttonPlay.setActive(0);
- buttonResume.setActive(0);
- buttonMove.setActive(1);
- buttonDelete.setActive(0);
- selected=3;
- draw();
- BoxStack::getInstance()->update(this);
- }
- else if (buttonDelete.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- buttonPlay.setActive(0);
- buttonResume.setActive(0);
- buttonMove.setActive(0);
- buttonDelete.setActive(1);
- selected=4;
- draw();
- BoxStack::getInstance()->update(this);
- }
- }
- else if (m->message == Message::MOUSE_LBDOWN)
- {
- if (buttonPlay.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
- }
- else if (buttonResume.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
- }
- else if (buttonMove.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
- }
- else if (buttonDelete.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- BoxStack::getInstance()->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::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
- }
- }
- }
- else if (m->message == Message::QUESTION_YES)
- {
- if (selected == 4)
- {
- Message* m2 = new Message(); // Delete self
- m2->from = this;
- m2->to = BoxStack::getInstance();
- m2->message = Message::CLOSE_ME;
- Command::getInstance()->postMessageNoLock(m2);
-
- m2 = new Message(); // OK. Want this to delete before this message does its job
- m2->from = this;
- m2->to = vRecList;
- m2->message = Message::DELETE_SELECTED_RECORDING;
- Command::getInstance()->postMessageNoLock(m2);
- }
- }
- else if (m->message == Message::MOVE_RECORDING)
- {
- Message* m2 = new Message(); // Delete self
- m2->from = this;
- m2->to = BoxStack::getInstance();
- m2->message = Message::CLOSE_ME;
- Command::getInstance()->postMessageNoLock(m2);
-
- m2 = new Message();
- m2->from = this;
- m2->to = vRecList;
- m2->message = Message::MOVE_RECORDING;
- m2->parameter = m->parameter;
- Command::getInstance()->postMessageNoLock(m2);
- }
-}
-
+/*\r
+ Copyright 2004-2008 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vrecording.h"\r
+\r
+#include "remote.h"\r
+#include "recinfo.h"\r
+#include "vquestion.h"\r
+#include "vinfo.h"\r
+#include "vdr.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "i18n.h"\r
+#include "command.h"\r
+#include "vrecmove.h"\r
+#include "boxstack.h"\r
+#include "recman.h"\r
+#include "vrecordinglist.h"\r
+#include "recording.h"\r
+#include "message.h"\r
+#include "log.h"\r
+\r
+VRecording::VRecording(RecMan* trecman, Recording* trec)\r
+{\r
+ rec = trec;\r
+ recman = trecman;\r
+ \r
+ Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());\r
+ rec->loadRecInfo();\r
+ Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());\r
+\r
+ setSize(570, 420);\r
+ createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ setPosition(80, 70);\r
+ }\r
+ else\r
+ {\r
+ setPosition(70, 35);\r
+ }\r
+\r
+ setTitleBarOn(1);\r
+ setBorderOn(1);\r
+ setTitleText(rec->getProgName());\r
+ setTitleBarColour(Colour::TITLEBARBACKGROUND);\r
+\r
+ summary.setPosition(10, 30 + 5);\r
+ summary.setSize(area.w - 20, area.h - 30 - 15 - 50);\r
+ summary.setParaMode(true);\r
+\r
+ if (rec->recInfo &&strlen(rec->recInfo->summary))\r
+ summary.setText(rec->recInfo->summary);\r
+ else\r
+ summary.setText(tr("Summary unavailable"));\r
+\r
+ add(&summary);\r
+ \r
+ \r
+ buttonPlay.setPosition(10, area.h - 40);\r
+ buttonResume.setPosition(150, area.h - 40);\r
+ buttonMove.setPosition(290, area.h - 40);\r
+ buttonDelete.setPosition(430, area.h - 40);\r
+ \r
+ int sfh = getFontHeight();\r
+ \r
+ buttonPlay.setSize(130, sfh);\r
+ buttonResume.setSize(130, sfh);\r
+ buttonMove.setSize(130, sfh);\r
+ buttonDelete.setSize(130, sfh);\r
+ \r
+ buttonRegion.x = 10;\r
+ buttonRegion.y = area.h - 40;\r
+ buttonRegion.w = 550;\r
+ buttonRegion.h = sfh;\r
+\r
+ buttonPlay.setText(tr("Play"));\r
+ buttonResume.setText(tr("Resume"));\r
+ buttonMove.setText(tr("Move"));\r
+ buttonDelete.setText(tr("Delete"));\r
+ \r
+ add(&buttonPlay);\r
+ add(&buttonResume); \r
+ add(&buttonMove);\r
+ add(&buttonDelete);\r
+ \r
+ buttonPlay.setActive(1);\r
+ selected = 1;\r
+}\r
+\r
+VRecording::~VRecording()\r
+{\r
+}\r
+\r
+void VRecording::setParent(VRecordingList* tvRecList)\r
+{\r
+ vRecList = tvRecList;\r
+}\r
+\r
+void VRecording::draw()\r
+{\r
+ TBBoxx::draw();\r
+}\r
+\r
+int VRecording::handleCommand(int command)\r
+{\r
+ switch(command)\r
+ {\r
+ case Remote::LEFT:\r
+ case Remote::DF_LEFT:\r
+ case Remote::DF_UP:\r
+ case Remote::UP:\r
+ {\r
+ doLeft();\r
+ return 2;\r
+ }\r
+ case Remote::RIGHT:\r
+ case Remote::DF_RIGHT:\r
+ case Remote::DF_DOWN:\r
+ case Remote::DOWN:\r
+ {\r
+ doRight();\r
+ return 2;\r
+ }\r
+ case Remote::OK:\r
+ {\r
+\r
+ if (selected == 1)\r
+ {\r
+ Message* m = new Message(); // Must be done after this view deleted\r
+ m->from = this;\r
+ m->to = vRecList;\r
+ m->message = Message::PLAY_SELECTED_RECORDING;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ return 4;\r
+ }\r
+\r
+ if (selected == 2)\r
+ {\r
+ Message* m = new Message(); // Must be done after this view deleted\r
+ m->from = this;\r
+ m->to = vRecList;\r
+ m->message = Message::RESUME_SELECTED_RECORDING;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ return 4;\r
+ }\r
+\r
+ if (selected == 3)\r
+ {\r
+ VRecMove* vrm = new VRecMove(recman);\r
+ vrm->setParent(this);\r
+ vrm->draw();\r
+ BoxStack::getInstance()->add(vrm);\r
+ BoxStack::getInstance()->update(vrm);\r
+ return 2;\r
+ }\r
+\r
+ if (selected == 4)\r
+ {\r
+ VQuestion* v = new VQuestion(this);\r
+ v->setSize(260, 180);\r
+ v->createBuffer();\r
+ v->setTitleBarColour(Colour::DANGER);\r
+ v->setTitleBarOn(1);\r
+ v->setBorderOn(1);\r
+ v->setTitleText(tr("Delete recording"));\r
+ v->setMainText(tr("Are you sure you want to delete this recording?"));\r
+ v->setDefault(VQuestion::NO);\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ v->setPosition(230, 160);\r
+ }\r
+ else\r
+ {\r
+ v->setPosition(220, 140);\r
+ }\r
+\r
+ v->draw();\r
+ BoxStack::getInstance()->add(v);\r
+ BoxStack::getInstance()->update(v);\r
+ return 2;\r
+ }\r
+ }\r
+\r
+ case Remote::BACK:\r
+ {\r
+ return 4;\r
+ }\r
+ }\r
+ // stop command getting to any more views\r
+ return 1;\r
+}\r
+\r
+void VRecording::doRight()\r
+{\r
+ switch(selected)\r
+ {\r
+ case 1:\r
+ buttonPlay.setActive(0);\r
+ buttonResume.setActive(1);\r
+ buttonPlay.draw();\r
+ buttonResume.draw();\r
+ break;\r
+ case 2:\r
+ buttonResume.setActive(0);\r
+ buttonMove.setActive(1);\r
+ buttonResume.draw();\r
+ buttonMove.draw();\r
+ break;\r
+ case 3:\r
+ buttonMove.setActive(0);\r
+ buttonDelete.setActive(1);\r
+ buttonMove.draw();\r
+ buttonDelete.draw();\r
+ break;\r
+ case 4:\r
+ buttonDelete.setActive(0);\r
+ buttonPlay.setActive(1);\r
+ buttonDelete.draw();\r
+ buttonPlay.draw();\r
+ break;\r
+ }\r
+ \r
+ if (++selected == 5) selected = 1;\r
+ \r
+ BoxStack::getInstance()->update(this, &buttonRegion);\r
+}\r
+\r
+void VRecording::doLeft()\r
+{\r
+ switch(selected)\r
+ {\r
+ case 1:\r
+ buttonPlay.setActive(0);\r
+ buttonDelete.setActive(1);\r
+ buttonPlay.draw();\r
+ buttonDelete.draw();\r
+ break;\r
+ case 2:\r
+ buttonResume.setActive(0);\r
+ buttonPlay.setActive(1);\r
+ buttonResume.draw();\r
+ buttonPlay.draw();\r
+ break;\r
+ case 3:\r
+ buttonMove.setActive(0);\r
+ buttonResume.setActive(1);\r
+ buttonMove.draw();\r
+ buttonResume.draw();\r
+ break;\r
+ case 4:\r
+ buttonDelete.setActive(0);\r
+ buttonMove.setActive(1);\r
+ buttonDelete.draw();\r
+ buttonMove.draw();\r
+ break;\r
+ }\r
+ \r
+ if (--selected == 0) selected = 4;\r
+ \r
+ BoxStack::getInstance()->update(this, &buttonRegion);\r
+}\r
+\r
+void VRecording::processMessage(Message* m)\r
+{\r
+ if (m->message == Message::MOUSE_MOVE)\r
+ {\r
+ if (buttonPlay.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ buttonPlay.setActive(1);\r
+ buttonResume.setActive(0);\r
+ buttonMove.setActive(0);\r
+ buttonDelete.setActive(0);\r
+ selected=1;\r
+ draw();\r
+ BoxStack::getInstance()->update(this);\r
+ }\r
+ else if (buttonResume.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ buttonPlay.setActive(0);\r
+ buttonResume.setActive(1);\r
+ buttonMove.setActive(0);\r
+ buttonDelete.setActive(0);\r
+ selected=2;\r
+ draw();\r
+ BoxStack::getInstance()->update(this);\r
+ }\r
+ else if (buttonMove.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ buttonPlay.setActive(0);\r
+ buttonResume.setActive(0);\r
+ buttonMove.setActive(1);\r
+ buttonDelete.setActive(0);\r
+ selected=3;\r
+ draw();\r
+ BoxStack::getInstance()->update(this);\r
+ }\r
+ else if (buttonDelete.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ buttonPlay.setActive(0);\r
+ buttonResume.setActive(0);\r
+ buttonMove.setActive(0);\r
+ buttonDelete.setActive(1);\r
+ selected=4;\r
+ draw();\r
+ BoxStack::getInstance()->update(this);\r
+ }\r
+ }\r
+ else if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ if (buttonPlay.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
+ }\r
+ else if (buttonResume.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
+ }\r
+ else if (buttonMove.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
+ }\r
+ else if (buttonDelete.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
+ }\r
+ else\r
+ {\r
+ //check if press is outside this view! then simulate cancel\r
+ int x=(m->parameter>>16)-getScreenX();\r
+ int y=(m->parameter&0xFFFF)-getScreenY();\r
+ if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
+ }\r
+ }\r
+ }\r
+ else if (m->message == Message::QUESTION_YES)\r
+ {\r
+ if (selected == 4)\r
+ {\r
+ Message* m2 = new Message(); // Delete self\r
+ m2->from = this;\r
+ m2->to = BoxStack::getInstance();\r
+ m2->message = Message::CLOSE_ME;\r
+ Command::getInstance()->postMessageNoLock(m2);\r
+\r
+ m2 = new Message(); // OK. Want this to delete before this message does its job\r
+ m2->from = this;\r
+ m2->to = vRecList;\r
+ m2->message = Message::DELETE_SELECTED_RECORDING;\r
+ Command::getInstance()->postMessageNoLock(m2);\r
+ }\r
+ }\r
+ else if (m->message == Message::MOVE_RECORDING)\r
+ {\r
+ Message* m2 = new Message(); // Delete self\r
+ m2->from = this;\r
+ m2->to = BoxStack::getInstance();\r
+ m2->message = Message::CLOSE_ME;\r
+ Command::getInstance()->postMessageNoLock(m2);\r
+\r
+ m2 = new Message();\r
+ m2->from = this;\r
+ m2->to = vRecList;\r
+ m2->message = Message::MOVE_RECORDING;\r
+ m2->parameter = m->parameter;\r
+ Command::getInstance()->postMessageNoLock(m2);\r
+ }\r
+}\r
+\r
-/*
- Copyright 2004-2007 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vrecordinglist.h"
-
-#include "recman.h"
-#include "directory.h"
-#include "recording.h"
-#include "remote.h"
-#include "wsymbol.h"
-#include "boxstack.h"
-#include "vrecordingmenu.h"
-#include "vrecording.h"
-#include "vdr.h"
-#include "vvideorec.h"
-#include "vradiorec.h"
-#include "colour.h"
-#include "video.h"
-#include "i18n.h"
-#include "command.h"
-#include "vinfo.h"
-#include "log.h"
-
-VRecordingList::VRecordingList()
-{
- boxstack = BoxStack::getInstance();
- recman = NULL;
- loading = true;
-
- setSize(570, 420);
- createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- setPosition(80, 70);
- }
- else
- {
- setPosition(70, 35);
- }
-
- setTitleBarOn(1);
- setTitleBarColour(Colour::TITLEBARBACKGROUND);
-
- sl.setPosition(10, 30 + 5);
- sl.setSize(area.w - 20, area.h - 30 - 15 - 30);
- add(&sl);
-}
-
-VRecordingList::~VRecordingList()
-{
- delete recman;
-}
-
-void VRecordingList::drawData(bool doIndexPop)
-{
- int saveIndex = sl.getCurrentOption();
- int saveTop = sl.getTopOption();
-
- sl.clear();
- sl.addColumn(0);
- sl.addColumn(110);
-
- int first = 1;
-
- char tempA[300]; // FIXME this is guesswork!
- char tempB[300]; // FIXME
- struct tm* btime;
-
- Directory* currentSubDir;
- DirectoryList::iterator i;
- DirectoryList* dirList = recman->getDirectories();
- for (i = dirList->begin(); i != dirList->end(); i++)
- {
- currentSubDir = *i;
- SNPRINTF(tempA, 299, tr("<dir> %lu\t%s"), currentSubDir->getNumRecordings(), currentSubDir->name);
- currentSubDir->index = sl.addOption(tempA, 0, first);
- first = 0;
- }
-
- // FIXME convert the whole program to time_t's
-
- Recording* currentRec;
- RecordingList::iterator j;
- RecordingList* recList = recman->getRecordings();
- for (j = recList->begin(); j != recList->end(); j++)
- {
- currentRec = *j;
- time_t recStartTime = (time_t)currentRec->getStartTime();
- btime = localtime(&recStartTime);
-//NMT does not like this too!
- //#ifndef _MSC_VER
-// strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime);
-//#else
- strftime(tempA, 299, "%d/%m %H:%M ", btime);
-//#endif
- sprintf(tempB, "%s\t%s", tempA, currentRec->getProgName());
- currentRec->index = sl.addOption(tempB, 0, first);
- first = 0;
- }
-
- if (doIndexPop)
- {
- sl.hintSetCurrent(slIndexStack.top());
- slIndexStack.pop();
- }
- else
- {
- sl.hintSetCurrent(saveIndex);
- sl.hintSetTop(saveTop);
- }
- sl.draw();
- doShowingBar();
-}
-
-void VRecordingList::draw(bool doIndexPop)
-{
- if (!loading)
- {
- if (recman->isSubDir())
- {
- char title[300];
- SNPRINTF(title, 299, tr("Recordings - %s"), recman->getCurDirName());
- setTitleText(title, 364);
- }
- else
- {
- setTitleText(tr("Recordings"));
- }
- }
-
- TBBoxx::draw();
-
- if (loading)
- {
- drawText(tr("Loading..."), 240, 180, Colour::LIGHTTEXT);
- }
- else
- {
- char freeSpace[50];
- int gigFree = recman->getFreeSpace() / 1024;
- SNPRINTF(freeSpace, 49, tr("%lu%% used, %iGB free"), recman->getUsedPercent(), gigFree);
- drawTextRJ(freeSpace, 560, 5, Colour::LIGHTTEXT);
-
- // Symbols
-
- WSymbol w;
- TEMPADD(&w);
-
- w.nextSymbol = WSymbol::UP;
- w.setPosition(20, 385);
- w.draw();
-
- w.nextSymbol = WSymbol::DOWN;
- w.setPosition(50, 385);
- w.draw();
-
- w.nextSymbol = WSymbol::SKIPBACK;
- w.setPosition(85, 385);
- w.draw();
-
- w.nextSymbol = WSymbol::SKIPFORWARD;
- w.setPosition(115, 385);
- w.draw();
-
- w.nextSymbol = WSymbol::PLAY;
- w.setPosition(150, 385);
- w.draw();
-
- drawTextRJ(tr("[ok] = menu"), 560, 385, Colour::LIGHTTEXT);
-
- // All static stuff done
-
- drawData(doIndexPop);
- }
-}
-
-void VRecordingList::doShowingBar()
-{
- int topOption = sl.getTopOption() + 1;
- if (sl.getNumOptions() == 0) topOption = 0;
-
- rectangle(220, 385, 180, 25, Colour::VIEWBACKGROUND);
- char showing[200];
- sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());
- drawText(showing, 220, 385, Colour::LIGHTTEXT);
-}
-
-void VRecordingList::processMessage(Message* m)
-{
- Log::getInstance()->log("VRecordingList", 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()))
- {
- sl.draw();
- doShowingBar();
- 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
- }
- }
- }
- else if (m->message == Message::DELETE_SELECTED_RECORDING)
- {
- Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing delete selected");
- doDeleteSelected();
- }
- else if (m->message == Message::MOVE_RECORDING)
- {
- Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing move recording");
- doMoveRecording((Directory*)m->parameter);
- }
- else if (m->message == Message::PLAY_SELECTED_RECORDING)
- {
- doPlay(false);
- }
- else if (m->message == Message::RESUME_SELECTED_RECORDING)
- {
- doPlay(true);
- }
-}
-
-void VRecordingList::doDeleteSelected()
-{
- Recording* toDelete = getCurrentOptionRecording();
-
- if (!toDelete) return;
-
- Log::getInstance()->log("VRecordingList", Log::DEBUG, "FOUND: %i %s %s", toDelete->index, toDelete->getProgName(), toDelete->getFileName());
-
- int success = recman->deleteRecording(toDelete);
- if (!VDR::getInstance()->isConnected())
- {
- Command::getInstance()->connectionLost();
- return;
- }
-
- if (success != 1)
- {
- VInfo* vi = new VInfo();
- vi->setSize(360, 200);
- vi->createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- vi->setPosition(190, 170);
- else
- vi->setPosition(180, 120);
- vi->setOneLiner(tr("Failed to delete recording"));
- vi->setExitable();
- vi->setBorderOn(1);
- vi->setTitleBarColour(Colour::DANGER);
- vi->okButton();
- vi->draw();
- boxstack->add(vi);
- boxstack->update(vi);
- }
- else
- {
- draw();
- boxstack->update(this);
- }
-
-}
-
-void VRecordingList::doMoveRecording(Directory* toDir)
-{
- Recording* toMove = getCurrentOptionRecording();
- if (!toMove || !toDir) return;
-
- Log::getInstance()->log("VRecordingList", Log::DEBUG, "MOVE: %s %s", toMove->getProgName(), toDir->name);
-
- int success = recman->moveRecording(toMove, toDir);
- if (!VDR::getInstance()->isConnected())
- {
- Command::getInstance()->connectionLost();
- return;
- }
-
- if (success != 1)
- {
- VInfo* vi = new VInfo();
- vi->setSize(360, 200);
- vi->createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- vi->setPosition(190, 170);
- else
- vi->setPosition(180, 120);
- vi->setOneLiner(tr("Failed to move recording"));
- vi->setExitable();
- vi->setBorderOn(1);
- vi->setTitleBarColour(Colour::DANGER);
- vi->okButton();
- vi->draw();
- boxstack->add(vi);
- boxstack->update(vi);
- }
- else
- {
- draw();
- boxstack->update(this);
- }
-}
-
-int VRecordingList::doPlay(bool resume)
-{
- Recording* toPlay = getCurrentOptionRecording();
- if (toPlay)
- {
- toPlay->loadRecInfo(); // check if still need this
- toPlay->loadMarks();
- bool ish264;
-
- bool isRadio = toPlay->isRadio(ish264);
-
- if (isRadio)
- {
- VRadioRec* radrec = new VRadioRec(toPlay);
- radrec->draw();
- boxstack->add(radrec);
- boxstack->update(radrec);
- radrec->go();
- }
- else
- {
- if (ish264 && !Video::getInstance()->supportsh264()) {
- VInfo* vi = new VInfo();
- vi->setSize(360, 200);
- vi->createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- vi->setPosition(190, 170);
- else
- vi->setPosition(180, 120);
- vi->setOneLiner(tr("H264 video not supported"));
- vi->setExitable();
- vi->setBorderOn(1);
- vi->setTitleBarColour(Colour::DANGER);
- vi->okButton();
- vi->draw();
- boxstack->add(vi);
- boxstack->update(vi);
-
- } else {
- VVideoRec* vidrec = new VVideoRec(toPlay, ish264);
- vidrec->draw();
- boxstack->add(vidrec);
- boxstack->update(vidrec);
- vidrec->go(resume);
- }
- }
- return 1;
- }
- // should not get to here
- return 0;
-}
-
-Recording* VRecordingList::getCurrentOptionRecording()
-{
- Recording* currentRec;
- RecordingList::iterator j;
- RecordingList* recList = recman->getRecordings();
- for (j = recList->begin(); j != recList->end(); j++)
- {
- currentRec = *j;
- if (currentRec->index == sl.getCurrentOption()) return currentRec;
- }
-
- return NULL;
-}
-
-int VRecordingList::handleCommand(int command)
-{
- switch(command)
- {
- case Remote::DF_UP:
- case Remote::UP:
- {
- sl.up();
- sl.draw();
-
- doShowingBar();
- boxstack->update(this);
- return 2;
- }
- case Remote::DF_DOWN:
- case Remote::DOWN:
- {
- sl.down();
- sl.draw();
-
- doShowingBar();
- boxstack->update(this);
- return 2;
- }
- case Remote::SKIPBACK:
- {
- sl.pageUp();
- sl.draw();
-
- doShowingBar();
- boxstack->update(this);
- return 2;
- }
- case Remote::SKIPFORWARD:
- {
- sl.pageDown();
- sl.draw();
-
- doShowingBar();
- boxstack->update(this);
- return 2;
- }
- case Remote::OK:
- {
- if (sl.getNumOptions() == 0) return 2;
-
- // Check to see if it is a sub directory
- Directory* currentSubDir;
- DirectoryList::iterator i;
- DirectoryList* dirList = recman->getDirectories();
- for (i = dirList->begin(); i != dirList->end(); i++)
- {
- currentSubDir = *i;
- if (currentSubDir->index == sl.getCurrentOption())
- {
- if (recman->down(currentSubDir))
- {
- slIndexStack.push(sl.getCurrentOption());
- sl.clear();
- draw();
- boxstack->update(this);
- }
- return 2;
- }
- }
-
- // check to see if it's a recording
- Recording* current = getCurrentOptionRecording();
- if (current)
- {
- Log::getInstance()->log("VRecordingList", Log::DEBUG, "Found the option you pointed at. %s %s", current->getProgName(), current->getFileName());
-
-/*
- VRecordingMenu* v = new VRecordingMenu(recman);
- v->setParent(this);
- v->setRecording(current);
- v->draw();
- boxstack->add(v);
- boxstack->update(v);
-*/
- VRecording* vr = new VRecording(recman, current);
- vr->setParent(this);
- vr->draw();
- boxstack->add(vr);
- boxstack->update(vr);
-
- return 2;
- }
- // should not get to here
- return 1;
- }
- case Remote::BACK:
- {
- if (recman->isSubDir())
- {
- recman->up();
- sl.clear();
- draw(true);
- boxstack->update(this);
- return 2;
- }
- else
- {
- return 4;
- }
- }
- case Remote::PLAY:
- {
- if (doPlay(true)) return 2;
- return 1;
- }
- case Remote::LEFT:
- case Remote::RIGHT:
- case Remote::ZERO:
- {
- reSort();
- return 2;
- }
- }
- // stop command getting to any more views
- return 1;
-}
-
-bool VRecordingList::load()
-{
- VDR* vdr = VDR::getInstance();
-
- recman = new RecMan();
- bool success = vdr->getRecordingsList(recman);
- if (success)
- {
- loading = false;
-
- char* defaultSortOrder = vdr->configLoad("General", "Recordings Sort Order");
- if (defaultSortOrder)
- {
- if (!STRCASECMP(defaultSortOrder, "Chronological")) recman->setSortOrderChron();
- delete[] defaultSortOrder;
- }
-
- recman->sort();
-
- draw();
- boxstack->update(this);
- }
-
- return success;
-}
-
-void VRecordingList::reSort()
-{
- recman->toggleSortOrder();
- recman->sort();
- sl.clear();
- draw();
- boxstack->update(this);
-}
-
+/*\r
+ Copyright 2004-2007 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vrecordinglist.h"\r
+\r
+#include "recman.h"\r
+#include "directory.h"\r
+#include "recording.h"\r
+#include "remote.h"\r
+#include "wsymbol.h"\r
+#include "boxstack.h"\r
+#include "vrecordingmenu.h"\r
+#include "vrecording.h"\r
+#include "vdr.h"\r
+#include "vvideorec.h"\r
+#include "vradiorec.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "i18n.h"\r
+#include "command.h"\r
+#include "vinfo.h"\r
+#include "log.h"\r
+\r
+VRecordingList::VRecordingList()\r
+{\r
+ boxstack = BoxStack::getInstance();\r
+ recman = NULL;\r
+ loading = true;\r
+\r
+ setSize(570, 420);\r
+ createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ setPosition(80, 70);\r
+ }\r
+ else\r
+ {\r
+ setPosition(70, 35);\r
+ }\r
+\r
+ setTitleBarOn(1);\r
+ setTitleBarColour(Colour::TITLEBARBACKGROUND);\r
+\r
+ sl.setPosition(10, 30 + 5);\r
+ sl.setSize(area.w - 20, area.h - 30 - 15 - 30);\r
+ add(&sl);\r
+}\r
+\r
+VRecordingList::~VRecordingList()\r
+{\r
+ delete recman;\r
+}\r
+\r
+void VRecordingList::drawData(bool doIndexPop)\r
+{\r
+ int saveIndex = sl.getCurrentOption();\r
+ int saveTop = sl.getTopOption();\r
+ sl.clear();\r
+ sl.addColumn(0);\r
+ sl.addColumn(110);\r
+\r
+ int first = 1;\r
+\r
+ char tempA[300]; // FIXME this is guesswork!\r
+ char tempB[300]; // FIXME\r
+ struct tm* btime;\r
+\r
+ Directory* currentSubDir;\r
+ DirectoryList::iterator i;\r
+ DirectoryList* dirList = recman->getDirectories();\r
+ for (i = dirList->begin(); i != dirList->end(); i++)\r
+ {\r
+ currentSubDir = *i;\r
+ SNPRINTF(tempA, 299, tr("<dir> %lu\t%s"), currentSubDir->getNumRecordings(), currentSubDir->name);\r
+ currentSubDir->index = sl.addOption(tempA, 0, first);\r
+ first = 0;\r
+ }\r
+ // FIXME convert the whole program to time_t's\r
+\r
+ Recording* currentRec;\r
+ RecordingList::iterator j;\r
+ RecordingList* recList = recman->getRecordings();\r
+ for (j = recList->begin(); j != recList->end(); j++)\r
+ {\r
+ currentRec = *j;\r
+ time_t recStartTime = (time_t)currentRec->getStartTime();\r
+ btime = localtime(&recStartTime);\r
+//NMT does not like this too!\r
+ //#ifndef _MSC_VER\r
+// strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime);\r
+//#else\r
+ strftime(tempA, 299, "%d/%m %H:%M ", btime);\r
+//#endif\r
+ sprintf(tempB, "%s\t%s", tempA, currentRec->getProgName());\r
+ currentRec->index = sl.addOption(tempB, 0, first);\r
+ first = 0;\r
+ }\r
+\r
+ if (doIndexPop)\r
+ {\r
+ sl.hintSetCurrent(slIndexStack.top());\r
+ slIndexStack.pop();\r
+ }\r
+ else\r
+ {\r
+ sl.hintSetCurrent(saveIndex);\r
+ sl.hintSetTop(saveTop);\r
+ }\r
+ sl.draw();\r
+ doShowingBar();\r
+}\r
+\r
+void VRecordingList::draw(bool doIndexPop)\r
+{\r
+ if (!loading)\r
+ {\r
+ if (recman->isSubDir())\r
+ {\r
+ char title[300];\r
+ SNPRINTF(title, 299, tr("Recordings - %s"), recman->getCurDirName());\r
+ setTitleText(title, 364);\r
+ }\r
+ else\r
+ {\r
+ setTitleText(tr("Recordings"));\r
+ }\r
+ }\r
+\r
+ TBBoxx::draw();\r
+\r
+ if (loading)\r
+ {\r
+ drawText(tr("Loading..."), 240, 180, Colour::LIGHTTEXT);\r
+ }\r
+ else\r
+ {\r
+ char freeSpace[50];\r
+ int gigFree = recman->getFreeSpace() / 1024;\r
+ SNPRINTF(freeSpace, 49, tr("%lu%% used, %iGB free"), recman->getUsedPercent(), gigFree);\r
+ drawTextRJ(freeSpace, 560, 5, Colour::LIGHTTEXT);\r
+ // Symbols\r
+\r
+ WSymbol w;\r
+ TEMPADD(&w);\r
+ w.nextSymbol = WSymbol::UP;\r
+ w.setPosition(20, 385);\r
+ w.draw();\r
+ w.nextSymbol = WSymbol::DOWN;\r
+ w.setPosition(50, 385);\r
+ w.draw();\r
+ w.nextSymbol = WSymbol::SKIPBACK;\r
+ w.setPosition(85, 385);\r
+ w.draw();\r
+ w.nextSymbol = WSymbol::SKIPFORWARD;\r
+ w.setPosition(115, 385);\r
+ w.draw();\r
+ w.nextSymbol = WSymbol::PLAY;\r
+ w.setPosition(150, 385);\r
+ w.draw();\r
+ drawTextRJ(tr("[ok] = menu"), 560, 385, Colour::LIGHTTEXT);\r
+\r
+ // All static stuff done\r
+ drawData(doIndexPop);\r
+ }\r
+}\r
+\r
+void VRecordingList::doShowingBar()\r
+{\r
+ int topOption = sl.getTopOption() + 1;\r
+ if (sl.getNumOptions() == 0) topOption = 0;\r
+\r
+ rectangle(220, 385, 180, 25, Colour::VIEWBACKGROUND);\r
+ char showing[200];\r
+ sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());\r
+ drawText(showing, 220, 385, Colour::LIGHTTEXT);\r
+}\r
+\r
+void VRecordingList::processMessage(Message* m)\r
+{\r
+ Log::getInstance()->log("VRecordingList", Log::DEBUG, "Got message value %lu", m->message);\r
+\r
+ if (m->message == Message::MOUSE_MOVE)\r
+ {\r
+ if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ sl.draw();\r
+ doShowingBar();\r
+ boxstack->update(this);\r
+ }\r
+ }\r
+ else if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ boxstack->handleCommand(Remote::OK); //simulate OK press\r
+ }\r
+ else\r
+ {\r
+ //check if press is outside this view! then simulate cancel\r
+ int x=(m->parameter>>16)-getScreenX();\r
+ int y=(m->parameter&0xFFFF)-getScreenY();\r
+ if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+ {\r
+ boxstack->handleCommand(Remote::BACK); //simulate cancel press\r
+ }\r
+ }\r
+ }\r
+ else if (m->message == Message::DELETE_SELECTED_RECORDING)\r
+ {\r
+ Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing delete selected");\r
+ doDeleteSelected();\r
+ }\r
+ else if (m->message == Message::MOVE_RECORDING)\r
+ {\r
+ Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing move recording");\r
+ doMoveRecording((Directory*)m->parameter);\r
+ }\r
+ else if (m->message == Message::PLAY_SELECTED_RECORDING)\r
+ {\r
+ doPlay(false);\r
+ }\r
+ else if (m->message == Message::RESUME_SELECTED_RECORDING)\r
+ {\r
+ doPlay(true);\r
+ }\r
+}\r
+\r
+void VRecordingList::doDeleteSelected()\r
+{\r
+ Recording* toDelete = getCurrentOptionRecording();\r
+\r
+ if (!toDelete) return;\r
+\r
+ Log::getInstance()->log("VRecordingList", Log::DEBUG, "FOUND: %i %s %s", toDelete->index, toDelete->getProgName(), toDelete->getFileName());\r
+\r
+ int success = recman->deleteRecording(toDelete);\r
+ if (!VDR::getInstance()->isConnected())\r
+ {\r
+ Command::getInstance()->connectionLost();\r
+ return;\r
+ }\r
+\r
+ if (success != 1)\r
+ {\r
+ VInfo* vi = new VInfo();\r
+ vi->setSize(360, 200);\r
+ vi->createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ vi->setPosition(190, 170);\r
+ else\r
+ vi->setPosition(180, 120);\r
+ vi->setOneLiner(tr("Failed to delete recording"));\r
+ vi->setExitable();\r
+ vi->setBorderOn(1);\r
+ vi->setTitleBarColour(Colour::DANGER);\r
+ vi->okButton();\r
+ vi->draw();\r
+ boxstack->add(vi);\r
+ boxstack->update(vi);\r
+ }\r
+ else\r
+ {\r
+ draw();\r
+ boxstack->update(this);\r
+ }\r
+\r
+}\r
+\r
+void VRecordingList::doMoveRecording(Directory* toDir)\r
+{\r
+ Recording* toMove = getCurrentOptionRecording();\r
+ if (!toMove || !toDir) return;\r
+\r
+ Log::getInstance()->log("VRecordingList", Log::DEBUG, "MOVE: %s %s", toMove->getProgName(), toDir->name);\r
+\r
+ int success = recman->moveRecording(toMove, toDir);\r
+ if (!VDR::getInstance()->isConnected())\r
+ {\r
+ Command::getInstance()->connectionLost();\r
+ return;\r
+ }\r
+\r
+ if (success != 1)\r
+ {\r
+ VInfo* vi = new VInfo();\r
+ vi->setSize(360, 200);\r
+ vi->createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ vi->setPosition(190, 170);\r
+ else\r
+ vi->setPosition(180, 120);\r
+ vi->setOneLiner(tr("Failed to move recording"));\r
+ vi->setExitable();\r
+ vi->setBorderOn(1);\r
+ vi->setTitleBarColour(Colour::DANGER);\r
+ vi->okButton();\r
+ vi->draw();\r
+ boxstack->add(vi);\r
+ boxstack->update(vi);\r
+ }\r
+ else\r
+ {\r
+ draw();\r
+ boxstack->update(this);\r
+ }\r
+}\r
+\r
+int VRecordingList::doPlay(bool resume)\r
+{\r
+ Recording* toPlay = getCurrentOptionRecording();\r
+ if (toPlay)\r
+ {\r
+ toPlay->loadRecInfo(); // check if still need this\r
+ toPlay->loadMarks();\r
+ bool ish264;\r
+\r
+ bool isRadio = toPlay->isRadio(ish264);\r
+\r
+ if (isRadio)\r
+ {\r
+ VRadioRec* radrec = new VRadioRec(toPlay);\r
+ radrec->draw();\r
+ boxstack->add(radrec);\r
+ boxstack->update(radrec);\r
+ radrec->go();\r
+ }\r
+ else\r
+ {\r
+ if (ish264 && !Video::getInstance()->supportsh264()) {\r
+ VInfo* vi = new VInfo();\r
+ vi->setSize(360, 200);\r
+ vi->createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ vi->setPosition(190, 170);\r
+ else\r
+ vi->setPosition(180, 120);\r
+ vi->setOneLiner(tr("H264 video not supported"));\r
+ vi->setExitable();\r
+ vi->setBorderOn(1);\r
+ vi->setTitleBarColour(Colour::DANGER);\r
+ vi->okButton();\r
+ vi->draw();\r
+ boxstack->add(vi);\r
+ boxstack->update(vi);\r
+ \r
+ } else {\r
+ VVideoRec* vidrec = new VVideoRec(toPlay, ish264);\r
+ vidrec->draw();\r
+ boxstack->add(vidrec);\r
+ boxstack->update(vidrec);\r
+ vidrec->go(resume);\r
+ }\r
+ }\r
+ return 1;\r
+ }\r
+ // should not get to here\r
+ return 0;\r
+}\r
+\r
+Recording* VRecordingList::getCurrentOptionRecording()\r
+{\r
+ Recording* currentRec;\r
+ RecordingList::iterator j;\r
+ RecordingList* recList = recman->getRecordings();\r
+ for (j = recList->begin(); j != recList->end(); j++)\r
+ {\r
+ currentRec = *j;\r
+ if (currentRec->index == sl.getCurrentOption()) return currentRec;\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+int VRecordingList::handleCommand(int command)\r
+{\r
+ switch(command)\r
+ {\r
+ case Remote::DF_UP:\r
+ case Remote::UP:\r
+ {\r
+ sl.up();\r
+ sl.draw();\r
+\r
+ doShowingBar();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::DF_DOWN:\r
+ case Remote::DOWN:\r
+ {\r
+ sl.down();\r
+ sl.draw();\r
+\r
+ doShowingBar();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::SKIPBACK:\r
+ {\r
+ sl.pageUp();\r
+ sl.draw();\r
+\r
+ doShowingBar();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::SKIPFORWARD:\r
+ {\r
+ sl.pageDown();\r
+ sl.draw();\r
+\r
+ doShowingBar();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::OK:\r
+ {\r
+ if (sl.getNumOptions() == 0) return 2;\r
+\r
+ // Check to see if it is a sub directory\r
+ Directory* currentSubDir;\r
+ DirectoryList::iterator i;\r
+ DirectoryList* dirList = recman->getDirectories();\r
+ for (i = dirList->begin(); i != dirList->end(); i++)\r
+ {\r
+ currentSubDir = *i;\r
+ if (currentSubDir->index == sl.getCurrentOption())\r
+ {\r
+ if (recman->down(currentSubDir))\r
+ {\r
+ slIndexStack.push(sl.getCurrentOption());\r
+ sl.clear();\r
+ draw();\r
+ boxstack->update(this);\r
+ }\r
+ return 2;\r
+ }\r
+ }\r
+\r
+ // check to see if it's a recording\r
+ Recording* current = getCurrentOptionRecording();\r
+ if (current)\r
+ {\r
+ Log::getInstance()->log("VRecordingList", Log::DEBUG, "Found the option you pointed at. %s %s", current->getProgName(), current->getFileName());\r
+\r
+/*\r
+ VRecordingMenu* v = new VRecordingMenu(recman);\r
+ v->setParent(this);\r
+ v->setRecording(current);\r
+ v->draw();\r
+ boxstack->add(v);\r
+ boxstack->update(v);\r
+*/ \r
+ VRecording* vr = new VRecording(recman, current);\r
+ vr->setParent(this);\r
+ vr->draw();\r
+ boxstack->add(vr);\r
+ boxstack->update(vr);\r
+ \r
+ return 2;\r
+ }\r
+ // should not get to here\r
+ return 1;\r
+ }\r
+ case Remote::BACK:\r
+ {\r
+ if (recman->isSubDir())\r
+ {\r
+ recman->up();\r
+ sl.clear();\r
+ draw(true);\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ else\r
+ {\r
+ return 4;\r
+ }\r
+ }\r
+ case Remote::PLAYPAUSE:\r
+ case Remote::PLAY:\r
+ {\r
+ if (doPlay(true)) return 2;\r
+ return 1;\r
+ }\r
+ case Remote::LEFT:\r
+ case Remote::RIGHT:\r
+ case Remote::ZERO:\r
+ {\r
+ reSort();\r
+ return 2;\r
+ }\r
+ }\r
+ // stop command getting to any more views\r
+ return 1;\r
+}\r
+\r
+bool VRecordingList::load()\r
+{\r
+ VDR* vdr = VDR::getInstance();\r
+\r
+ recman = new RecMan();\r
+\r
+ bool success = vdr->getRecordingsList(recman);\r
+\r
+ if (success)\r
+ {\r
+ loading = false;\r
+ char* defaultSortOrder = vdr->configLoad("General", "Recordings Sort Order");\r
+ if (defaultSortOrder)\r
+ {\r
+ if (!STRCASECMP(defaultSortOrder, "Chronological")) recman->setSortOrderChron();\r
+ delete[] defaultSortOrder;\r
+ }\r
+ recman->sort();\r
+ draw();\r
+ boxstack->update(this);\r
+ }\r
+\r
+ return success;\r
+}\r
+\r
+void VRecordingList::reSort()\r
+{\r
+ recman->toggleSortOrder();\r
+ recman->sort();\r
+ sl.clear();\r
+ draw();\r
+ boxstack->update(this);\r
+}\r
+\r
#include "boxx.h"
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
+#include "threadsystem.h"
class VScreensaver : public Boxx, public Thread_TYPE
{
public:
VScreensaver();
- ~VScreensaver();
+ virtual ~VScreensaver();
int handleCommand(int command);
void draw();
#include "boxx.h"
#include "timerreceiver.h"
-#ifndef WIN32
-#include "threadp.h"
-#else
-#include "threadwin.h"
-#endif
+#include "threadsystem.h"
class Sleeptimer : public Thread_TYPE
{
-/*
- Copyright 2005-2008 Chris Tallon, 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 <math.h>
-#include "vteletextview.h"
-#include "video.h"
-#include "timers.h"
-#include "boxstack.h"
-#include "remote.h"
-#include "teletxt/txtfont.h"
-
-unsigned int interpol_table_fac1[16][22];
-unsigned int interpol_table_fac2[16][22];
-unsigned int interpol_table_fac3[16][22];
-unsigned int interpol_table_fac4[16][22];
-int interpol_lowbit[16];
-int interpol_upbit[16];
-int interpol_lowline[22];
-int interpol_upline[22];
-
-void initpol_tables(){
- int charsizex;
- int charsizey;
- charsizex=16;
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- charsizey=22;
- } else {
- charsizey=18;
- }
- int ttcharsizex=12;
- int ttcharsizey=10;
- for (int py=0;py<charsizey;py++) {
- float fposy=((float)(ttcharsizey))/((float)(charsizey))*((float)py);
- float yweight=fposy-floor(fposy);
- float yinvweight=1.-yweight;
- interpol_upline[py]=min((unsigned int)ceil(fposy),9);
- interpol_lowline[py]=max((unsigned int)floor(fposy),0);
- for (int px=0;px<charsizex;px++) {
- float fposx=((float)(ttcharsizex))/((float)(charsizex))*((float)px);
- float xweight=fposx-floor(fposx);
- float xinvweight=1.-xweight;
- interpol_upbit[px]= (min((unsigned int)ceil(fposx),11));
- interpol_lowbit[px]= (max((unsigned int)floor(fposx),0));
-
- interpol_table_fac1[px][py]=xweight*yweight*256.;
- interpol_table_fac2[px][py]=xinvweight*yweight*256.;
- interpol_table_fac3[px][py]=xweight*yinvweight*256.;
- interpol_table_fac4[px][py]=xinvweight*yinvweight*256.;
-
- }
- }
-}
-
-VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder,Boxx* playerview)
-{
- ttdecoder=TTdecoder;
- pv=playerview;
- subtitlemode=false;
- initpol_tables();
-
-
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- //setSize(680, 550);
- setSize(680,22); //Only first line
- setPosition(40, 26);
- }
- else
- {
- setPosition(40, 30);
- //setSize(680, 450);
- setSize(680,18);//only first line
- }
- createBuffer();
- keyindigit=1;
- page=0x100;
-
-}
-
-VTeletextView::~VTeletextView ()
-{
- // Make sure the timer is deleted
- pv->draw();
- BoxStack::getInstance()->update(pv);
- Timers::getInstance()->cancelTimer(this, 1);
- ttdecoder->unRegisterTeletextView(this);
-
-}
-
-void VTeletextView::draw(bool completedraw, bool onlyfirstline)
-{
- Boxx::draw();
- int x,y;
-
- for (y=0;y<25;y++) {
- for (x=0;x<40;x++) {
- if (ttdecoder->isDirty(x,y) || completedraw) {
- cTeletextChar c=ttdecoder->getChar(x,y);
- c.SetDirty(false);
- //Skip Blinking and conceal
- drawChar(x,y,c);
- ttdecoder->setChar(x,y,c);
- }
- }
- if (onlyfirstline) break;
- }
-
-
-}
-
-Colour VTeletextView::enumTeletextColorToCoulour(enumTeletextColor ttcol)
-{
- switch (ttcol) {
- case ttcBlack:
- return Colour(0,0,0);
- case ttcRed:
- return Colour(255,0,0);
- case ttcGreen:
- return Colour(0,255,0);
- case ttcYellow:
- return Colour(255,255,0);
- case ttcBlue:
- return Colour(0,0,255);
- case ttcMagenta:
- return Colour(255,0,255);
- case ttcCyan:
- return Colour(0,255,255);
- case ttcWhite:
- return Colour(255,255,255);
- case ttcTransparent:
- return Colour(0,0,0,0);
- case ttcHalfRed:
- return Colour(127,0,0);
- case ttcHalfGreen:
- return Colour(0,127,0);
- case ttcHalfYellow:
- return Colour(127,127,0);
- case ttcHalfBlue:
- return Colour(0,0,127);
- case ttcHalfMagenta:
- return Colour(127,0,127);
- case ttcHalfCyan:
- return Colour(0,127,127);
- case ttcGrey:
- return Colour(127,127,127);
- default:
- return Colour(0,0,0);
- };
-}
-
-//Next function inspired by osdteletext plugin
-void VTeletextView::drawChar(int x, int y, cTeletextChar c)
-{
- unsigned int buffer [10];
- unsigned int * charmap=GetFontChar(c,buffer);
- if (!charmap) { //invalid char
- memset(&buffer,0,10);
- charmap=buffer;
- }
- enumTeletextColor ttforegcolour=c.GetFGColor();
- enumTeletextColor ttbackgcolour=c.GetBGColor();
- if (c.GetBoxedOut()) {
- ttforegcolour=ttcTransparent;
- ttbackgcolour=ttcTransparent;
- }
- int charsizex;
- int charsizey;
- charsizex=16;
- bool firstline=false;
- if (y==0) firstline=true;
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- charsizey=22;
- } else {
- charsizey=18;
- }
- int ttcharsizex=12;
- int ttcharsizey=10;
- int screenposx=charsizex*x; //12*40= 480 250
- int screenposy=y*charsizey;
- Boxx* drawtarget=this;
- if (!firstline) {
-
- drawtarget=pv;
- screenposy+=this->getScreenY();
- screenposx+=this->getScreenX();
-
- }
-
- Colour fgcharcl=enumTeletextColorToCoulour(ttforegcolour);
- Colour bgcharcl=enumTeletextColorToCoulour(ttbackgcolour);
-
- drawtarget->startFastDraw();
- for (int py=0;py<charsizey;py++) {
- int upperbitline=charmap[interpol_upline[py]];
- int lowerbitline=charmap[interpol_lowline[py]];
- for (int px=0;px<charsizex;px++) {
- int upperbit= interpol_upbit[px];
- int lowerbit= interpol_lowbit[px];
- Colour uuc=( upperbitline &(0x8000>>upperbit)) ? fgcharcl: bgcharcl;
- Colour ulc=( upperbitline &(0x8000>>lowerbit)) ? fgcharcl: bgcharcl;
- Colour luc=( lowerbitline &(0x8000>>upperbit)) ? fgcharcl: bgcharcl;
- Colour llc=( lowerbitline &(0x8000>>lowerbit)) ? fgcharcl: bgcharcl;
- unsigned int fac1,fac2,fac3,fac4;
- fac1=interpol_table_fac1[px][py];
- fac2=interpol_table_fac2[px][py];
- fac3=interpol_table_fac3[px][py];
- fac4=interpol_table_fac4[px][py];
-
- Colour res((uuc.red*fac1+ulc.red*fac2+luc.red*fac3+llc.red*fac4)/256,
- (uuc.green*fac1+ulc.green*fac2+luc.green*fac3+llc.green*fac4)/256,
- (uuc.blue*fac1+ulc.blue*fac2+luc.blue*fac3+llc.blue*fac4)/256,
- (uuc.alpha*fac1+ulc.alpha*fac2+luc.alpha*fac3+llc.alpha*fac4)/256); //if this is too slow make a table
- drawtarget->drawPixelAlpha(screenposx+px,screenposy+py,res, true);
- }
- }
-
-
- drawtarget->endFastDraw();
-
-
-}
-
-int VTeletextView::handleCommand(int command) {
- if (subtitlemode) return 0; //Ok we are in subtitle mode, we are a slave of the player
- switch (command) {
- case Remote::OK:
- return 2;
- case Remote::BACK:
- return 4;
- case Remote::ZERO:
- case Remote::ONE:
- case Remote::TWO:
- case Remote::THREE:
- case Remote::FOUR:
- case Remote::FIVE:
- case Remote::SIX:
- case Remote::SEVEN:
- case Remote::EIGHT:
- case Remote::NINE:
- {
- // key in teletext page
- doKey(command);
- return 2;
- }
- };
-
- return 0;
-
-}
-
-void VTeletextView::doKey(int command)
-{
- char pagenums[3];
- if (keyindigit==1){
- if (command==9) return; //not allowed
- page=command<<8;
- pagenums[0]=command+ 48;
- pagenums[1]='-';
- pagenums[2]='-';
- keyindigit++;
- } else if (keyindigit==2) {
- page|=command<<4;
- pagenums[0]=48+((page &0xF00)>>8);
- pagenums[1]=command+ 48;
- pagenums[2]='-';
- keyindigit++;
- } else if (keyindigit==3) {
- page|=command;
- pagenums[0]=48+((page &0xF00)>>8);
- pagenums[1]=48+((page &0x0F0)>>4);
- pagenums[2]=48+command;
- keyindigit=1;
- ttdecoder->setPage(page);
- }
- ttdecoder->setKeyinDigits(pagenums,true);
- Region toupdate;
- toupdate.w=16*40;
- if (Video::getInstance()->getFormat() == Video::PAL) {
- toupdate.h=22;
-
- } else {
- toupdate.h=18;
-
- }
- toupdate.x=0;
- toupdate.y=0;
-
- draw(false,true);
- BoxStack::getInstance()->update(this,&toupdate);
-
-}
-
-void VTeletextView::timercall(int clientReference)
-{
-
-}
-
-void VTeletextView::processMessage(Message* m)
-{
- if (m->message == Message::TELETEXTUPDATE)
- {
- draw(false,false);
- BoxStack::getInstance()->update(this);
- BoxStack::getInstance()->update(pv);
-
- } else if (m->message == Message::TELETEXTUPDATEFIRSTLINE)
- {
- Region toupdate;
- toupdate.w=16*40;
- if (Video::getInstance()->getFormat() == Video::PAL) {
- toupdate.h=22;
-
- } else {
- toupdate.h=18;
-
- }
- toupdate.x=0;
- toupdate.y=0;
-
-
-
- draw(false,true);
- BoxStack::getInstance()->update(this,&toupdate);
-
- }
-}
-
-
+/*\r
+ Copyright 2005-2008 Chris Tallon, Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+#include <math.h>\r
+#include "vteletextview.h"\r
+#include "video.h"\r
+#include "timers.h"\r
+#include "boxstack.h"\r
+#include "remote.h"\r
+\r
+\r
+VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder,Boxx* playerview)\r
+{ \r
+ ttdecoder=TTdecoder;\r
+ pv=playerview;\r
+ subtitlemode=false;\r
+ \r
+ \r
+\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ { \r
+ //setSize(680, 550);\r
+ setSize(680,22); //Only first line\r
+ setPosition(40, 26);\r
+ }\r
+ else\r
+ {\r
+ setPosition(40, 30);\r
+ //setSize(680, 450);\r
+ setSize(680,18);//only first line\r
+ }\r
+ createBuffer();\r
+ keyindigit=1;\r
+ page=0x100;\r
+ \r
+}\r
+\r
+VTeletextView::~VTeletextView ()\r
+{\r
+ // Make sure the timer is deleted\r
+ Log::getInstance()->log("VTeletextView", Log::DEBUG, "VTeletextView destruct");\r
+ pv->draw();\r
+ BoxStack::getInstance()->update(pv);\r
+ Timers::getInstance()->cancelTimer(this, 1);\r
+ ttdecoder->unRegisterTeletextView(this);\r
+ \r
+}\r
+\r
+void VTeletextView::draw(bool completedraw, bool onlyfirstline)\r
+{\r
+ //Log::getInstance()->log("VTeletextView", Log::ERR, "Start draw");\r
+ Boxx::draw();\r
+ int x,y;\r
+ \r
+ Boxx *drawtarget=NULL;\r
+ int ox,oy;\r
+ for (y=0;y<25;y++) {\r
+ if (y==0) {\r
+ drawtarget=this;\r
+ ox=0;\r
+ oy=0;\r
+ } else {\r
+ drawtarget=pv;\r
+ ox=this->getScreenX();\r
+ oy=this->getScreenY();\r
+ }\r
+\r
+ for (x=0;x<40;x++) {\r
+ if (ttdecoder->isDirty(x,y) || completedraw) {\r
+ cTeletextChar c=ttdecoder->getChar(x,y);\r
+ c.SetDirty(false);\r
+ //Skip Blinking and conceal\r
+ drawtarget->drawTTChar(ox,oy,x,y,c);\r
+ ttdecoder->setChar(x,y,c);\r
+ }\r
+ }\r
+ // Log::getInstance()->log("VTeletextView", Log::ERR, "Line %d",y);\r
+ if (onlyfirstline) break;\r
+ }\r
+ // Log::getInstance()->log("VTeletextView", Log::ERR, "Start end");\r
+ \r
+ \r
+}\r
+\r
+\r
+\r
+\r
+\r
+int VTeletextView::handleCommand(int command) {\r
+ if (subtitlemode) return 0; //Ok we are in subtitle mode, we are a slave of the player\r
+ switch (command) {\r
+ case Remote::OK:\r
+ return 2;\r
+ case Remote::BACK:\r
+ return 4;\r
+ case Remote::ZERO:\r
+ case Remote::ONE:\r
+ case Remote::TWO:\r
+ case Remote::THREE:\r
+ case Remote::FOUR:\r
+ case Remote::FIVE:\r
+ case Remote::SIX:\r
+ case Remote::SEVEN:\r
+ case Remote::EIGHT:\r
+ case Remote::NINE:\r
+ {\r
+ // key in teletext page\r
+ doKey(command);\r
+ return 2;\r
+ }\r
+ };\r
+\r
+ return 0;\r
+ \r
+}\r
+\r
+void VTeletextView::doKey(int command)\r
+{\r
+ char pagenums[3];\r
+ if (keyindigit==1){\r
+ if (command==9) return; //not allowed\r
+ page=command<<8;\r
+ pagenums[0]=command+ 48;\r
+ pagenums[1]='-';\r
+ pagenums[2]='-';\r
+ keyindigit++;\r
+ } else if (keyindigit==2) {\r
+ page|=command<<4;\r
+ pagenums[0]=48+((page &0xF00)>>8);\r
+ pagenums[1]=command+ 48;\r
+ pagenums[2]='-';\r
+ keyindigit++;\r
+ } else if (keyindigit==3) {\r
+ page|=command;\r
+ pagenums[0]=48+((page &0xF00)>>8);\r
+ pagenums[1]=48+((page &0x0F0)>>4);\r
+ pagenums[2]=48+command;\r
+ keyindigit=1;\r
+ ttdecoder->setPage(page);\r
+ }\r
+ ttdecoder->setKeyinDigits(pagenums,true);\r
+ Region toupdate;\r
+ toupdate.w=16*40;\r
+ if (Video::getInstance()->getFormat() == Video::PAL) {\r
+ toupdate.h=22;\r
+ \r
+ } else {\r
+ toupdate.h=18;\r
+ \r
+ }\r
+ toupdate.x=0;\r
+ toupdate.y=0;\r
+ \r
+ draw(false,true);\r
+ BoxStack::getInstance()->update(this,&toupdate);\r
+\r
+}\r
+\r
+void VTeletextView::timercall(int clientReference)\r
+{\r
+ \r
+}\r
+\r
+void VTeletextView::processMessage(Message* m)\r
+{\r
+ if (m->message == Message::TELETEXTUPDATE)\r
+ {\r
+ draw(false,false);\r
+ BoxStack::getInstance()->update(this);\r
+ BoxStack::getInstance()->update(pv);\r
+\r
+ } else if (m->message == Message::TELETEXTUPDATEFIRSTLINE) \r
+ {\r
+ Region toupdate;\r
+ toupdate.w=16*40;\r
+ if (Video::getInstance()->getFormat() == Video::PAL) {\r
+ toupdate.h=22;\r
+ \r
+ } else {\r
+ toupdate.h=18;\r
+ \r
+ }\r
+ toupdate.x=0;\r
+ toupdate.y=0;\r
+\r
+\r
+ \r
+ draw(false,true);\r
+ BoxStack::getInstance()->update(this,&toupdate);\r
+\r
+ }\r
+}\r
+\r
+\r
-/*
- Copyright 2005-2008 Chris Tallon, 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 VTELETEXTVIEW_H
-#define VTELETEXTVIEW_H
-
-#include <stdio.h>
-
-#include "boxx.h"
-#include "timerreceiver.h"
-#include "teletextdecodervbiebu.h"
-
-class VTeletextView : public Boxx, public TimerReceiver
-{
- public:
- VTeletextView (TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview);
- ~VTeletextView ();
- void draw(bool completedraw, bool onlyfirstline);
- void draw() {draw(true,false);};
- void drawChar(int x, int y, cTeletextChar c);
-
- Colour enumTeletextColorToCoulour(enumTeletextColor ttcol);
-
- void processMessage(Message* m);
-
- void setSubtitleMode(bool mode) {subtitlemode=mode;};
- bool isInSubtitleMode() {return subtitlemode;};
-
- int handleCommand(int command);
- void timercall(int clientReference);
-
-
- private:
- void doKey(int command);
-
-
- protected:
- TeletextDecoderVBIEBU* ttdecoder;
- int keyindigit;
- int page;
- bool subtitlemode;
- Boxx* pv;
-
-
-};
-
-#endif
+/*\r
+ Copyright 2005-2008 Chris Tallon, Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef VTELETEXTVIEW_H\r
+#define VTELETEXTVIEW_H\r
+\r
+#include <stdio.h>\r
+\r
+#include "boxx.h"\r
+#include "timerreceiver.h"\r
+#include "teletextdecodervbiebu.h"\r
+\r
+class VTeletextView : public Boxx, public TimerReceiver\r
+{\r
+ public:\r
+ VTeletextView (TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview);\r
+ ~VTeletextView ();\r
+ void draw(bool completedraw, bool onlyfirstline);\r
+ void draw() {draw(true,false);};\r
+\r
+\r
+\r
+\r
+ void processMessage(Message* m);\r
+\r
+ void setSubtitleMode(bool mode) {subtitlemode=mode;};\r
+ bool isInSubtitleMode() {return subtitlemode;};\r
+\r
+ int handleCommand(int command);\r
+ void timercall(int clientReference);\r
+ \r
+\r
+ private:\r
+ void doKey(int command);\r
+ \r
+\r
+ protected:\r
+ TeletextDecoderVBIEBU* ttdecoder;\r
+ int keyindigit;\r
+ int page;\r
+ bool subtitlemode;\r
+ Boxx* pv;\r
+ \r
+\r
+};\r
+\r
+#endif\r
int xpos = 20;
int ypos = 50;
- drawText(tr("Active"), xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- drawText(tr("Channel"), xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- drawText(tr("Name"), xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- drawText(tr("Directory"), xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- ypos += surface->getFontHeight();
- drawText(tr("Start"), xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- drawText(tr("Stop"), xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- drawText(tr("Priority"), xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- drawText(tr("Lifetime"), xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- ypos += surface->getFontHeight();
- drawText(tr("Current"), xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- drawText(tr("Recording"), xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
+ int fontheight=getFontHeight();
+ drawText(tr("Active"), xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ drawText(tr("Channel"), xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ drawText(tr("Name"), xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ drawText(tr("Directory"), xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ ypos += fontheight;
+ drawText(tr("Start"), xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ drawText(tr("Stop"), xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ drawText(tr("Priority"), xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ drawText(tr("Lifetime"), xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ ypos += fontheight;
+ drawText(tr("Current"), xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ drawText(tr("Recording"), xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
// Temp
// Active
if (recTimer->active) strcpy(buffer, "Yes");
else strcpy(buffer, "No");
- drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
+ drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
// Channel
SNPRINTF(buffer, 999, "%lu", recTimer->channelNumber);
- drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
+ drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
// Name
SNPRINTF(buffer, 999, "%s", recTimer->getName());
- drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
+ drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
// Directory
if (recTimer->getDirectory()) SNPRINTF(buffer, 999, "%s", recTimer->getDirectory());
else strcpy(buffer, "");
- drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- ypos += surface->getFontHeight();
+ drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ ypos += fontheight;
// Start
tms = localtime((time_t*)&recTimer->startTime);
strftime(buffer, 999, "%d/%m %H:%M", tms);
- drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
+ drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
// Stop
tms = localtime((time_t*)&recTimer->stopTime);
strftime(buffer, 999, "%d/%m %H:%M", tms);
- drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
+ drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
// Priority
SNPRINTF(buffer, 999, "%lu", recTimer->priority);
- drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
+ drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
// Lifetime
SNPRINTF(buffer, 999, "%lu", recTimer->lifeTime);
- drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
- ypos += surface->getFontHeight();
+ drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
+ ypos += fontheight;
// Current
if (recTimer->pending) strcpy(buffer, "Yes");
else strcpy(buffer, "No");
- drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
+ drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
// Recording now
if (recTimer->recording) strcpy(buffer, "Yes");
else strcpy(buffer, "No");
- drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += surface->getFontHeight();
+ drawText(buffer, xpos, ypos, Colour::LIGHTTEXT); ypos += fontheight;
}
void VTimerEdit::swap()
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vtimerlist.h"
-
-#include "message.h"
-#include "remote.h"
-#include "wsymbol.h"
-#include "colour.h"
-#include "video.h"
-#include "i18n.h"
-#include "timers.h"
-#include "vtimeredit.h"
-#include "command.h"
-#include "boxstack.h"
-#include "vdr.h"
-#include "vinfo.h"
-#include "log.h"
-
-VTimerList::VTimerList()
-{
- recTimerList = NULL;
-
- clockRegion.x = 420;
- clockRegion.y = 0;
- clockRegion.w = 150;
- clockRegion.h = 30;
-
- indicatorsRegion.x = 6;
- indicatorsRegion.y = 44;
- indicatorsRegion.w = 18;
- indicatorsRegion.h = 15 * (surface->getFontHeight() + 1);
-
- flipflop = true;
-
- setSize(570, 420);
- createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- setPosition(80, 70);
- }
- else
- {
- setPosition(70, 35);
- }
-
- setTitleBarOn(1);
- setTitleText(tr("Timers"));
- setTitleBarColour(Colour::TITLEBARBACKGROUND);
-
- sl.setPosition(30, 30 + 5);
- sl.setSize(area.w - 40, area.h - 30 - 15 - 30);
- add(&sl);
-}
-
-void VTimerList::preDelete()
-{
- Timers::getInstance()->cancelTimer(this, 1);
-}
-
-VTimerList::~VTimerList()
-{
- if (recTimerList)
- {
- for (UINT i = 0; i < recTimerList->size(); i++)
- {
- delete (*recTimerList)[i];
- }
-
- recTimerList->clear();
- delete recTimerList;
- }
-}
-
-void VTimerList::draw()
-{
- // Draw statics
-
- TBBoxx::draw();
-
- WSymbol w;
- TEMPADD(&w);
-
- w.nextSymbol = WSymbol::UP;
- w.setPosition(20, 385);
- w.draw();
-
- w.nextSymbol = WSymbol::DOWN;
- w.setPosition(50, 385);
- w.draw();
-
- w.nextSymbol = WSymbol::SKIPBACK;
- w.setPosition(85, 385);
- w.draw();
-
- w.nextSymbol = WSymbol::SKIPFORWARD;
- w.setPosition(115, 385);
- w.draw();
-
- drawTextRJ("[ok] = edit", 560, 385, Colour::LIGHTTEXT);
-
- drawClock();
- drawShowing();
- drawIndicators();
-}
-
-bool VTimerList::load()
-{
- recTimerList = VDR::getInstance()->getRecTimersList();
-
- if (!recTimerList) return false;
-
- char strA[300];
- char strB[300];
-
- struct tm* btime;
-
- // FIXME all drawing stuff in this class and sl.clear somewhere?!
-
- sl.addColumn(0);
- sl.addColumn(110);
-
- RecTimer* recTimer;
- int first = 1;
-
- for (UINT i = 0; i < recTimerList->size(); i++)
- {
- recTimer = (*recTimerList)[i];
-
- btime = localtime((time_t*)&recTimer->startTime);
- strftime(strA, 299, "%d/%m %H:%M ", btime);
- SNPRINTF(strB, 299, "%s\t%s", strA, recTimer->getName());
- sl.addOption(strB, (ULONG)recTimer, first);
- first = 0;
- }
-
- return true;
-}
-
-void VTimerList::drawClock()
-{
- // Blank the area first
- rectangle(area.w - 150, 0, 150, 30, titleBarColour);
-
- char timeString[20];
- time_t t;
- time(&t);
- struct tm* tms = localtime(&t);
- strftime(timeString, 19, "%d/%m %H:%M:%S", tms);
- drawTextRJ(timeString, 560, 5, Colour::LIGHTTEXT);
-
- Timers::getInstance()->setTimerT(this, 1, t + 1);
-}
-
-void VTimerList::drawShowing()
-{
- int topOption = sl.getTopOption() + 1;
- if (sl.getNumOptions() == 0) topOption = 0;
-
- rectangle(220, 385, 180, 25, Colour::VIEWBACKGROUND);
- char showing[200];
- sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());
- drawText(showing, 220, 385, Colour::LIGHTTEXT);
-}
-
-void VTimerList::drawIndicators()
-{
- int top = sl.getTopOption();
- int bottom = sl.getBottomOption();
- int yinc = surface->getFontHeight() + 1;
- RecTimer* recTimer;
-
- rectangle(6, 44, 18, 15*yinc, Colour::VIEWBACKGROUND);
-
- // The indexes recorded from the wselectlist into the index member of the RecTimer
- // Is the same as the position in the vector of RecTimers
- // Because they are in order, they don't change order and wselectlist starts from 0 up consecutively
-
- int ypos = 44;
- for (int current = top; current < bottom; current++)
- {
- recTimer = (*recTimerList)[current];
-
- if (recTimer->recording) // Flashing red square
- {
- if (flipflop)
- {
- rectangle(6, ypos, 18, 16, Colour::RED);
- drawText("R", 8, ypos-3, Colour::LIGHTTEXT);
- }
- }
- else if (recTimer->pending)
- {
- rectangle(6, ypos, 18, 16, Colour::RED);
- drawText("X", 8, ypos-3, Colour::BLACK);
- }
- else if (recTimer->active == 0)
- {
- rectangle(6, ypos, 18, 16, Colour::SELECTHIGHLIGHT);
- drawText("X", 8, ypos-3, Colour::BLACK);
- }
- else
- {
-// if (flipflop) rectangle(6, ypos, 18, 16, Colour::GREEN);
- }
-
- ypos += yinc;
- }
-}
-
-void VTimerList::timercall(int clientReference)
-{
- drawClock();
- BoxStack::getInstance()->update(this, &clockRegion);
-
- flipflop = !flipflop;
- drawIndicators();
- BoxStack::getInstance()->update(this, &indicatorsRegion);
-}
-
-int VTimerList::handleCommand(int command)
-{
- switch(command)
- {
- case Remote::DF_UP:
- case Remote::UP:
- {
- sl.up();
- sl.draw();
- drawShowing();
- drawIndicators();
- BoxStack::getInstance()->update(this);
- return 2;
- }
- case Remote::DF_DOWN:
- case Remote::DOWN:
- {
- sl.down();
- sl.draw();
- drawShowing();
- drawIndicators();
- BoxStack::getInstance()->update(this);
- return 2;
- }
- case Remote::SKIPBACK:
- {
- sl.pageUp();
- sl.draw();
- drawShowing();
- drawIndicators();
- BoxStack::getInstance()->update(this);
- return 2;
- }
- case Remote::SKIPFORWARD:
- {
- sl.pageDown();
- sl.draw();
- drawShowing();
- drawIndicators();
- BoxStack::getInstance()->update(this);
- return 2;
- }
- case Remote::OK:
- {
- RecTimer* recTimer = NULL;
- if (recTimerList) recTimer = (RecTimer*)sl.getCurrentOptionData();
- if (recTimer == NULL) return 2;
-
- VTimerEdit* v = new VTimerEdit(recTimer);
- v->setParent(this);
- v->draw();
- BoxStack::getInstance()->add(v);
- BoxStack::getInstance()->update(v);
-
- return 2;
- }
- case Remote::BACK:
- {
- return 4;
- }
- }
- // stop command getting to any more views
- return 1;
-}
-
-void VTimerList::processMessage(Message* m)
-{
- if (m->message == Message::MOUSE_MOVE)
- {
- if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- sl.draw();
- BoxStack::getInstance()->update(this);
- }
- }
- else if (m->message == Message::MOUSE_LBDOWN)
- {
- if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- BoxStack::getInstance()->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::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
- }
- }
- }
- else if (m->message == Message::DELETE_SELECTED_TIMER)
- {
- RecTimer* recTimer = (RecTimer*)sl.getCurrentOptionData();
- if (recTimer == NULL) return;
- Log::getInstance()->log("VTimerList", Log::DEBUG, "Got timer to delete");
-
-
- ULONG retval = VDR::getInstance()->deleteTimer(recTimer);
- if (!VDR::getInstance()->isConnected()) { Command::getInstance()->connectionLost(); return; }
- Log::getInstance()->log("VTimerList", Log::DEBUG, "Got return fron delete timer: %lu", retval);
-
- if (retval != 10)
- {
- VInfo* errorBox = new VInfo();
- errorBox->setSize(360, 200);
- errorBox->createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- errorBox->setPosition(190, 170);
- else
- errorBox->setPosition(180, 120);
-
-
- if (retval == 1) errorBox->setOneLiner(tr("Timers being edited at VDR, please try later"));
- else if (retval == 3) errorBox->setOneLiner(tr("Unable to delete timer - timer is running"));
- else if (retval == 4) errorBox->setOneLiner(tr("Error - timer not found at VDR"));
- else errorBox->setOneLiner(tr("Unknown error"));
-
- errorBox->setExitable();
- errorBox->setBorderOn(1);
- errorBox->setTitleBarColour(Colour::DANGER);
- errorBox->okButton();
- errorBox->draw();
- BoxStack::getInstance()->add(errorBox);
- BoxStack::getInstance()->update(errorBox);
- }
-
- int saveIndex = sl.getCurrentOption();
- int saveTop = sl.getTopOption();
-
- if (recTimerList)
- {
- for (UINT i = 0; i < recTimerList->size(); i++)
- {
- delete (*recTimerList)[i];
- }
-
- recTimerList->clear();
- delete recTimerList;
- }
-
- sl.clear();
- load();
-
- sl.hintSetCurrent(saveIndex);
- sl.hintSetTop(saveTop);
- draw();
- BoxStack::getInstance()->update(this);
- }
-}
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vtimerlist.h"\r
+\r
+#include "message.h"\r
+#include "remote.h"\r
+#include "wsymbol.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "i18n.h"\r
+#include "timers.h"\r
+#include "vtimeredit.h"\r
+#include "command.h"\r
+#include "boxstack.h"\r
+#include "vdr.h"\r
+#include "vinfo.h"\r
+#include "log.h"\r
+\r
+VTimerList::VTimerList()\r
+{\r
+ recTimerList = NULL;\r
+\r
+ clockRegion.x = 420;\r
+ clockRegion.y = 0;\r
+ clockRegion.w = 150;\r
+ clockRegion.h = 30;\r
+\r
+\r
+\r
+ flipflop = true;\r
+\r
+ setSize(570, 420);\r
+ createBuffer();\r
+\r
+ indicatorsRegion.x = 6;\r
+ indicatorsRegion.y = 44;\r
+ indicatorsRegion.w = 18;\r
+ indicatorsRegion.h = 15 * (getFontHeight() + 1);\r
+\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ setPosition(80, 70);\r
+ }\r
+ else\r
+ {\r
+ setPosition(70, 35);\r
+ }\r
+\r
+ setTitleBarOn(1);\r
+ setTitleText(tr("Timers"));\r
+ setTitleBarColour(Colour::TITLEBARBACKGROUND);\r
+\r
+ sl.setPosition(30, 30 + 5);\r
+ sl.setSize(area.w - 40, area.h - 30 - 15 - 30);\r
+ add(&sl);\r
+}\r
+\r
+void VTimerList::preDelete()\r
+{\r
+ Timers::getInstance()->cancelTimer(this, 1);\r
+}\r
+\r
+VTimerList::~VTimerList()\r
+{\r
+ if (recTimerList)\r
+ {\r
+ for (UINT i = 0; i < recTimerList->size(); i++)\r
+ {\r
+ delete (*recTimerList)[i];\r
+ }\r
+\r
+ recTimerList->clear();\r
+ delete recTimerList;\r
+ }\r
+}\r
+\r
+void VTimerList::draw()\r
+{\r
+ // Draw statics\r
+\r
+ TBBoxx::draw();\r
+\r
+ WSymbol w;\r
+ TEMPADD(&w);\r
+\r
+ w.nextSymbol = WSymbol::UP;\r
+ w.setPosition(20, 385);\r
+ w.draw();\r
+\r
+ w.nextSymbol = WSymbol::DOWN;\r
+ w.setPosition(50, 385);\r
+ w.draw();\r
+\r
+ w.nextSymbol = WSymbol::SKIPBACK;\r
+ w.setPosition(85, 385);\r
+ w.draw();\r
+\r
+ w.nextSymbol = WSymbol::SKIPFORWARD;\r
+ w.setPosition(115, 385);\r
+ w.draw();\r
+\r
+ drawTextRJ("[ok] = edit", 560, 385, Colour::LIGHTTEXT);\r
+\r
+ drawClock();\r
+ drawShowing();\r
+ drawIndicators();\r
+}\r
+\r
+bool VTimerList::load()\r
+{\r
+ recTimerList = VDR::getInstance()->getRecTimersList();\r
+\r
+ if (!recTimerList) return false;\r
+\r
+ char strA[300];\r
+ char strB[300];\r
+\r
+ struct tm* btime;\r
+\r
+ // FIXME all drawing stuff in this class and sl.clear somewhere?!\r
+\r
+ sl.addColumn(0);\r
+ sl.addColumn(110);\r
+\r
+ RecTimer* recTimer;\r
+ int first = 1;\r
+\r
+ for (UINT i = 0; i < recTimerList->size(); i++)\r
+ {\r
+ recTimer = (*recTimerList)[i];\r
+\r
+ btime = localtime((time_t*)&recTimer->startTime);\r
+ strftime(strA, 299, "%d/%m %H:%M ", btime);\r
+ SNPRINTF(strB, 299, "%s\t%s", strA, recTimer->getName());\r
+ sl.addOption(strB, (ULONG)recTimer, first);\r
+ first = 0;\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+void VTimerList::drawClock()\r
+{\r
+ // Blank the area first\r
+ rectangle(area.w - 150, 0, 150, 30, titleBarColour);\r
+\r
+ char timeString[20];\r
+ time_t t;\r
+ time(&t);\r
+ struct tm* tms = localtime(&t);\r
+ strftime(timeString, 19, "%d/%m %H:%M:%S", tms);\r
+ drawTextRJ(timeString, 560, 5, Colour::LIGHTTEXT);\r
+\r
+ Timers::getInstance()->setTimerT(this, 1, t + 1);\r
+}\r
+\r
+void VTimerList::drawShowing()\r
+{\r
+ int topOption = sl.getTopOption() + 1;\r
+ if (sl.getNumOptions() == 0) topOption = 0;\r
+\r
+ rectangle(220, 385, 180, 25, Colour::VIEWBACKGROUND);\r
+ char showing[200];\r
+ sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());\r
+ drawText(showing, 220, 385, Colour::LIGHTTEXT);\r
+}\r
+\r
+void VTimerList::drawIndicators()\r
+{\r
+ int top = sl.getTopOption();\r
+ int bottom = sl.getBottomOption();\r
+ int yinc = getFontHeight() + 1;\r
+ RecTimer* recTimer;\r
+\r
+ rectangle(6, 44, 18, 15*yinc, Colour::VIEWBACKGROUND);\r
+\r
+ // The indexes recorded from the wselectlist into the index member of the RecTimer\r
+ // Is the same as the position in the vector of RecTimers\r
+ // Because they are in order, they don't change order and wselectlist starts from 0 up consecutively\r
+\r
+ int ypos = 44;\r
+ for (int current = top; current < bottom; current++)\r
+ {\r
+ recTimer = (*recTimerList)[current];\r
+\r
+ if (recTimer->recording) // Flashing red square\r
+ {\r
+ if (flipflop)\r
+ {\r
+ rectangle(6, ypos, 18, 16, Colour::RED);\r
+ drawText("R", 8, ypos-3, Colour::LIGHTTEXT);\r
+ }\r
+ }\r
+ else if (recTimer->pending)\r
+ {\r
+ rectangle(6, ypos, 18, 16, Colour::RED);\r
+ drawText("X", 8, ypos-3, Colour::BLACK);\r
+ }\r
+ else if (recTimer->active == 0)\r
+ {\r
+ rectangle(6, ypos, 18, 16, Colour::SELECTHIGHLIGHT);\r
+ drawText("X", 8, ypos-3, Colour::BLACK);\r
+ }\r
+ else\r
+ {\r
+// if (flipflop) rectangle(6, ypos, 18, 16, Colour::GREEN);\r
+ }\r
+\r
+ ypos += yinc;\r
+ }\r
+}\r
+\r
+void VTimerList::timercall(int clientReference)\r
+{\r
+ drawClock();\r
+ BoxStack::getInstance()->update(this, &clockRegion);\r
+\r
+ flipflop = !flipflop;\r
+ drawIndicators();\r
+ BoxStack::getInstance()->update(this, &indicatorsRegion);\r
+}\r
+\r
+int VTimerList::handleCommand(int command)\r
+{\r
+ switch(command)\r
+ {\r
+ case Remote::DF_UP:\r
+ case Remote::UP:\r
+ {\r
+ sl.up();\r
+ sl.draw();\r
+ drawShowing();\r
+ drawIndicators();\r
+ BoxStack::getInstance()->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::DF_DOWN:\r
+ case Remote::DOWN:\r
+ {\r
+ sl.down();\r
+ sl.draw();\r
+ drawShowing();\r
+ drawIndicators();\r
+ BoxStack::getInstance()->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::SKIPBACK:\r
+ {\r
+ sl.pageUp();\r
+ sl.draw();\r
+ drawShowing();\r
+ drawIndicators();\r
+ BoxStack::getInstance()->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::SKIPFORWARD:\r
+ {\r
+ sl.pageDown();\r
+ sl.draw();\r
+ drawShowing();\r
+ drawIndicators();\r
+ BoxStack::getInstance()->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::OK:\r
+ {\r
+ RecTimer* recTimer = NULL;\r
+ if (recTimerList) recTimer = (RecTimer*)sl.getCurrentOptionData();\r
+ if (recTimer == NULL) return 2;\r
+\r
+ VTimerEdit* v = new VTimerEdit(recTimer);\r
+ v->setParent(this);\r
+ v->draw();\r
+ BoxStack::getInstance()->add(v);\r
+ BoxStack::getInstance()->update(v);\r
+\r
+ return 2;\r
+ }\r
+ case Remote::BACK:\r
+ {\r
+ return 4;\r
+ }\r
+ }\r
+ // stop command getting to any more views\r
+ return 1;\r
+}\r
+\r
+void VTimerList::processMessage(Message* m)\r
+{\r
+ if (m->message == Message::MOUSE_MOVE)\r
+ {\r
+ if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ sl.draw();\r
+ BoxStack::getInstance()->update(this);\r
+ }\r
+ }\r
+ else if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
+ }\r
+ else\r
+ {\r
+ //check if press is outside this view! then simulate cancel\r
+ int x=(m->parameter>>16)-getScreenX();\r
+ int y=(m->parameter&0xFFFF)-getScreenY();\r
+ if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
+ }\r
+ }\r
+ }\r
+ else if (m->message == Message::DELETE_SELECTED_TIMER)\r
+ {\r
+ RecTimer* recTimer = (RecTimer*)sl.getCurrentOptionData();\r
+ if (recTimer == NULL) return;\r
+ Log::getInstance()->log("VTimerList", Log::DEBUG, "Got timer to delete");\r
+\r
+ \r
+ ULONG retval = VDR::getInstance()->deleteTimer(recTimer);\r
+ if (!VDR::getInstance()->isConnected()) { Command::getInstance()->connectionLost(); return; }\r
+ Log::getInstance()->log("VTimerList", Log::DEBUG, "Got return fron delete timer: %lu", retval);\r
+ \r
+ if (retval != 10)\r
+ {\r
+ VInfo* errorBox = new VInfo();\r
+ errorBox->setSize(360, 200);\r
+ errorBox->createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ errorBox->setPosition(190, 170);\r
+ else\r
+ errorBox->setPosition(180, 120);\r
+\r
+ \r
+ if (retval == 1) errorBox->setOneLiner(tr("Timers being edited at VDR, please try later"));\r
+ else if (retval == 3) errorBox->setOneLiner(tr("Unable to delete timer - timer is running"));\r
+ else if (retval == 4) errorBox->setOneLiner(tr("Error - timer not found at VDR"));\r
+ else errorBox->setOneLiner(tr("Unknown error"));\r
+\r
+ errorBox->setExitable();\r
+ errorBox->setBorderOn(1);\r
+ errorBox->setTitleBarColour(Colour::DANGER);\r
+ errorBox->okButton();\r
+ errorBox->draw();\r
+ BoxStack::getInstance()->add(errorBox);\r
+ BoxStack::getInstance()->update(errorBox);\r
+ }\r
+ \r
+ int saveIndex = sl.getCurrentOption();\r
+ int saveTop = sl.getTopOption();\r
+ \r
+ if (recTimerList)\r
+ {\r
+ for (UINT i = 0; i < recTimerList->size(); i++)\r
+ {\r
+ delete (*recTimerList)[i];\r
+ }\r
+\r
+ recTimerList->clear();\r
+ delete recTimerList;\r
+ }\r
+\r
+ sl.clear();\r
+ load();\r
+\r
+ sl.hintSetCurrent(saveIndex);\r
+ sl.hintSetTop(saveTop);\r
+ draw();\r
+ BoxStack::getInstance()->update(this);\r
+ }\r
+}\r
+\r
-/*
- Copyright 2007-2008 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vvideolivetv.h"
-
-#include "vchannellist.h"
-#include "video.h"
-#include "playerlive.h"
-#include "playerlivetv.h"
-#include "playerliveradio.h"
-#include "channel.h"
-#include "boxstack.h"
-#include "colour.h"
-#include "osd.h"
-#include "command.h"
-#include "i18n.h"
-#include "wtextbox.h"
-#include "remote.h"
-#include "vaudioselector.h"
-#include "colour.h"
-#include "event.h"
-#include "timers.h"
-#include "vepg.h"
-#include "bitmap.h"
-#include "log.h"
-#include "vteletextview.h"
-
-VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
-{
- vdr = VDR::getInstance();
- boxstack = BoxStack::getInstance();
- video = Video::getInstance();
-
- vas = NULL;
-
- chanList = tchanList;
- vchannelList = tvchannelList;
- numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
-
- currentChannelIndex = 0;
- previousChannelIndex = 0;
- osdChannelIndex = 0;
- keying = 0;
- preBuffering = 0;
-
- playing = false;
-
- // Convert channel number to index
- UINT i;
- for(i = 0; i < chanList->size(); i++)
- {
- if ((*chanList)[i]->number == (UINT)initialChannelNumber)
- {
- currentChannelIndex = i;
- osdChannelIndex = i;
- break;
- }
- }
-
- eventList = NULL;
-
- videoMode = video->getMode();
-
- if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
- {
- streamType = VDR::VIDEO;
- player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);
- }
- else
- {
- streamType = VDR::RADIO;
- player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
- }
- player->init();
-
- setSize(video->getScreenWidth(), video->getScreenHeight());
- createBuffer();
- Colour transparent(0, 0, 0, 0);
- setBackgroundColour(transparent);
-
- dowss = false;
- char* optionWSS = vdr->configLoad("General", "WSS");
- if (optionWSS)
- {
- if (strstr(optionWSS, "Yes")) dowss = true;
- delete[] optionWSS;
- }
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
-
- if (dowss)
- {
- wss.setFormat(video->getFormat());
- wss.setWide(true);
- add(&wss);
-
- wssRegion.x = 0;
- wssRegion.y = 6;
- wssRegion.w = video->getScreenWidth();
- wssRegion.h = 2;
- }
-
- // This variable is set to true if the user pressed OK to bring the OSD on screen
- // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling
- okTriggeredOSD = false;
-
- Colour osdBack = Colour(0, 0, 0, 128);
-
- osd.setBackgroundColour(osdBack);
- osd.setPosition(0, video->getScreenHeight() - 150);
- osd.setSize(video->getScreenWidth(), 150);
- osd.setVisible(false);
- add(&osd);
-
- clock.setBackgroundColour(osdBack);
- clock.setPosition(osd.getWidth() - 100, 4);
- clock.setSize(90, 30);
- osd.add(&clock);
-
- osdChanNum.setBackgroundColour(osdBack);
- osdChanNum.setPosition(50, 4);
- osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font
- osd.add(&osdChanNum);
-
- osdChanName.setBackgroundColour(osdBack);
- osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
- osdChanName.setSize(300, 30);
- osd.add(&osdChanName);
-
- boxRed.setBackgroundColour(Colour::RED);
- boxRed.setPosition(54, 104);
- boxRed.setSize(18, 16);
- osd.add(&boxRed);
-
- boxGreen.setBackgroundColour(Colour::GREEN);
- boxGreen.setPosition(220, 104);
- boxGreen.setSize(18, 16);
- osd.add(&boxGreen);
-
- boxYellow.setBackgroundColour(Colour::YELLOW);
- boxYellow.setPosition(390, 104);
- boxYellow.setSize(18, 16);
- osd.add(&boxYellow);
-
- boxBlue.setBackgroundColour(Colour::BLUE);
- boxBlue.setPosition(560, 104);
- boxBlue.setSize(18, 16);
- osd.add(&boxBlue);
-
- textRed.setBackgroundColour(osdBack);
- textRed.setPosition(boxRed.getX2(), 98);
- textRed.setSize(boxGreen.getX() - boxRed.getX2(), 30);
- textRed.setText(tr("Summary"));
- osd.add(&textRed);
-
- if (streamType == VDR::VIDEO)
- {
- textGreen.setBackgroundColour(osdBack);
- textGreen.setPosition(boxGreen.getX2(), 98);
- textGreen.setSize(boxYellow.getX() - boxGreen.getX2(), 30);
- textGreen.setText(tr("Audio"));
- osd.add(&textGreen);
- }
-
- textYellow.setBackgroundColour(osdBack);
- textYellow.setPosition(boxYellow.getX2(), 98);
- textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);
- textYellow.setText("Teletext");
- osd.add(&textYellow);
-
- textBlue.setBackgroundColour(osdBack);
- textBlue.setPosition(boxBlue.getX2(), 98);
- textBlue.setSize(osd.getX2() - boxBlue.getX2(), 30);
- textBlue.setText(tr("EPG"));
- osd.add(&textBlue);
-
- sl.setBackgroundColour(osdBack);
- sl.setPosition(70, 36);
- sl.setSize(500, 58);
- sl.setNoLoop();
- osd.add(&sl);
-
- // Summary Box
- summary.setBackgroundColour(osdBack);
- summary.setPosition(0, video->getScreenHeight() - 300);
- summary.setSize(video->getScreenWidth(), 150);
- summary.setVisible(false);
- add(&summary);
-
- textSummary.setBackgroundColour(osdBack);
- textSummary.setPosition(40, 10);
- textSummary.setSize(video->getScreenWidth() - 80, 130);
- textSummary.setParaMode(true);
- summary.add(&textSummary);
-
- summaryBlackLine.setBackgroundColour(Colour::BLACK);
- summaryBlackLine.setPosition(0, summary.getHeight() - 4);
- summaryBlackLine.setSize(summary.getWidth(), 4);
- summary.add(&summaryBlackLine);
-
- sAspectRatio.setPosition(osd.getWidth() - 90, 40);
- sAspectRatio.nextColour = Colour::SELECTHIGHLIGHT;
- sAspectRatio.setVisible(false);
- osd.add(&sAspectRatio);
-
- bufferBar.setPosition(osd.getWidth() - 90, 70);
- bufferBar.setSize(40, 20);
- bufferBar.setVisible(true);
- osd.add(&bufferBar);
-
- sAudioChannels.setPosition(osd.getWidth() - 130, 40);
- sAudioChannels.nextColour = Colour::SELECTHIGHLIGHT;
- sAudioChannels.setVisible(false);
- osd.add(&sAudioChannels);
-
- textUnavailable.setBackgroundColour(osdBack);
- textUnavailable.setPosition(60, 30);
- textUnavailable.setSize(osd.getWidth() - 120, 30);
- textUnavailable.setText(tr("Channel Unavailable"));
- textUnavailable.setVisible(false);
- add(&textUnavailable);
-
- // FIXME painful
- Region r1 = summary.getRegionR();
- Region r2 = osd.getRegionR();
- osdSummaryRegion = r1 + r2;
-}
-
-void VVideoLiveTV::preDelete()
-{
- if (playing) stop();
-}
-
-VVideoLiveTV::~VVideoLiveTV()
-{
- delete player;
- video->setDefaultAspect();
- delData();
-}
-
-void VVideoLiveTV::delData()
-{
- if (eventList)
- {
- int eventListSize = eventList->size();
- for(int i = 0; i < eventListSize; i++)
- {
- delete (*eventList)[i];
- }
- eventList->clear();
- delete eventList;
-
- }
- sl.clear();
-}
-
-int VVideoLiveTV::handleCommand(int command)
-{
- switch(command)
- {
- case Remote::BACK:
- {
- if (osd.getVisible() && !textUnavailable.getVisible())
- {
- clearScreen();
- return 2;
- }
- // else drop through to stop
- }
- case Remote::STOP:
- {
- stop();
- vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
- return 4;
- }
-
- // NEW REMOTE ONLY - navigate EPG, bring it onscreen if it's not there
- case Remote::UP:
- {
- doUpDown(false);
- return 2;
- }
- case Remote::DOWN:
- {
- doUpDown(true);
- return 2;
- }
- case Remote::LEFT:
- {
- doLeftRight(false);
- return 2;
- }
- case Remote::RIGHT:
- {
- doLeftRight(true);
- return 2;
- }
- // Continue new remote only...
- case Remote::CHANNELUP:
- {
- doChanUpDown(UP);
- return 2;
- }
- case Remote::CHANNELDOWN:
- {
- doChanUpDown(DOWN);
- return 2;
- }
-
- // END NEW REMOTE ONLY, START OLD REMOTE ONLY
-
- // DF_LEFT and DF_RIGHT never get here because they are stolen
- // by command as vol- and vol+
-
- // Old remote. Decide what to do based on whether
- // OK was pressed - osd shown manually, use up/down for epg nav
- // UP/DOWN was pressed to change channel, osd was shown auto, use up/down for ch+/ch-
-
- case Remote::DF_UP:
- {
- // Old remote, decide what to do based on okTriggeredOSD
- if (okTriggeredOSD) doUpDown(false);
- else doChanUpDown(UP);
- return 2;
- }
- case Remote::DF_DOWN:
- {
- // Old remote, decide what to do based on okTriggeredOSD
- if (okTriggeredOSD) doUpDown(true);
- else doChanUpDown(DOWN);
- return 2;
- }
-
- // END NEW/OLD REMOTE STUFF
-
- case Remote::PREVCHANNEL:
- {
- channelChange(PREVIOUS, 0);
- osdChannelIndex = currentChannelIndex;
- displayOSD(true);
- return 2;
- }
- case Remote::OK:
- {
- doOK();
- return 2;
- }
- case Remote::RED:
- case Remote::MENU:
- {
- doSummary();
- return 2;
- }
- case Remote::FULL:
- case Remote::TV:
- {
- toggleChopSides();
- return 2;
- }
-
- case Remote::ZERO:
- case Remote::ONE:
- case Remote::TWO:
- case Remote::THREE:
- case Remote::FOUR:
- case Remote::FIVE:
- case Remote::SIX:
- case Remote::SEVEN:
- case Remote::EIGHT:
- case Remote::NINE:
- {
- // key in channel number
- doKey(command);
- return 2;
- }
-
- case Remote::GREEN:
- {
- if (streamType == VDR::VIDEO) doAudioSelector();
- return 2;
- }
- case Remote::YELLOW:
- {
- if (streamType ==VDR::VIDEO) doTeletext(); //TODO: Add a selector for subtitles or teletext
- return 2;
- }
- case Remote::GUIDE:
- case Remote::BLUE:
- {
- doEPG();
- return 2;
- }
- case Remote::RECORD:
- if (streamType = VDR::VIDEO)
- (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();
- return 2;
- }
-
- return 1;
-}
-
-void VVideoLiveTV::go()
-{
- playing = true;
- draw();
- boxstack->update(this);
-
- setClock();
- displayOSD(true);
-
- player->go(currentChannelIndex);
-}
-
-void VVideoLiveTV::stop()
-{
- Timers::getInstance()->cancelTimer(this, 1);
- Timers::getInstance()->cancelTimer(this, 2);
- player->stop();
- playing = false;
-}
-
-void VVideoLiveTV::doLeftRight(bool right)
-{
- if (osd.getVisible())
- {
- if (right) osdChannelIndex = upChannel(osdChannelIndex);
- else osdChannelIndex = downChannel(osdChannelIndex);
- }
- else
- {
- osdChannelIndex = currentChannelIndex;
- }
- displayOSD(true);
-}
-
-void VVideoLiveTV::doUpDown(bool down)
-{
- if (osd.getVisible())
- {
- if (down) sl.down();
- else sl.up();
- sl.draw();
-
- displayOSD(false);
- }
- else
- {
- displayOSD(true);
- }
-}
-
-void VVideoLiveTV::doChanUpDown(int which)
-{
- channelChange(OFFSET, which);
- osdChannelIndex = currentChannelIndex;
- displayOSD(true);
-}
-
-void VVideoLiveTV::doOK()
-{
- if (osd.getVisible())
- {
- if (keying)
- {
- UINT newChannel = 0;
- for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
-
- channelChange(NUMBER, newChannel);
- osdChannelIndex = currentChannelIndex;
- displayOSD(true);
- }
- else if (osdChannelIndex == currentChannelIndex)
- {
- clearScreen();
- }
- else
- {
- channelChange(INDEX, osdChannelIndex);
- displayOSD(true);
- }
- }
- else
- {
- osdChannelIndex = currentChannelIndex;
- displayOSD(true);
- okTriggeredOSD = true;
- }
-}
-
-void VVideoLiveTV::doSummary()
-{
- if (summary.getVisible())
- {
- summary.setVisible(false);
- draw();
- boxstack->update(this, summary.getRegion());
- Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd
- return;
- }
-
- summary.setVisible(true);
-
- if (osd.getVisible())
- {
- Timers::getInstance()->cancelTimer(this, 1);
- displayOSD(false);
- }
- else
- {
- displayOSD(true);
- }
-}
-
-void VVideoLiveTV::doKey(int command)
-{
- if (!osd.getVisible()) // First key. prep the data
- {
- setNowNextData();
- keying = 0;
- }
-
- int i;
- for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
- keyingInput[0] = command;
- keying++;
-
- char* keyingString = new char[numberWidth + 1];
- for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
- keyingString[numberWidth] = '\0';
-
- for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
-
- if (keying == numberWidth)
- {
- UINT newChannel = 0;
- for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
-
- channelChange(NUMBER, newChannel);
- osdChannelIndex = currentChannelIndex;
- Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,
- displayOSD(true); // this will put one back if required
- }
- else
- {
- osdChanNum.setText(keyingString);
-
- if (!osd.getVisible())
- {
- osd.setVisible(true);
- draw();
- }
- else
- {
- osdChanNum.draw();
- }
- boxstack->update(this, osd.getRegion());
- Timers::getInstance()->setTimerD(this, 1, 3); // 3s for keying input
- }
- delete[] keyingString;
-}
-
-void VVideoLiveTV::doTeletext(bool subtitlemode)
-{
- if (streamType !=VDR::VIDEO) return;
- bool exists=true;
-
- // Cancel keying
- if (keying)
- {
- keying = 0;
- // and reset the display - this is a copy from setNowNextData
- char formatChanNum[20];
- SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
- osdChanNum.setText(formatChanNum);
- osdChanName.setText((*chanList)[osdChannelIndex]->name);
- }
- if (osd.getVisible()) clearScreen();
- // Draw the teletxt
- VTeletextView *vtxv=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
- if (vtxv==NULL) {
- vtxv= new VTeletextView(((PlayerLiveTV*)player)->getTeletextDecoder(),this);
- ((PlayerLiveTV*)player)->getTeletextDecoder()->registerTeletextView(vtxv);
- exists=false;
- }
- vtxv->setSubtitleMode(subtitlemode);
- vtxv->draw();
- draw();
-
- if (!exists) {
- BoxStack::getInstance()->add(vtxv);
- }
- BoxStack::getInstance()->update(this);
- BoxStack::getInstance()->update(vtxv);
-}
-
-void VVideoLiveTV::doAudioSelector()
-{
- // If the osd is already visisble there might be a timer for it
- Timers::getInstance()->cancelTimer(this, 1);
- //This causes a deadlock with the timertrhread itself is locked
-
-
- // Cancel keying
- if (keying)
- {
- keying = 0;
- // and reset the display - this is a copy from setNowNextData
- char formatChanNum[20];
- SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
- osdChanNum.setText(formatChanNum);
- osdChanName.setText((*chanList)[osdChannelIndex]->name);
- }
- int subtitleChannel=((PlayerLiveTV*)player)->getCurrentSubtitleChannel();
- int subtitleType=0x10;
- if (!(static_cast<PlayerLiveTV*>(player))->isSubtitlesOn()) {
- if (((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView() &&
- ((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode()
- ) {
- subtitleChannel=((PlayerLiveTV*)player)->getTeletextDecoder()->getPage();
- subtitleType=0x11;
-
- } else {
- subtitleType=0xFF; //turnedOff
- subtitleChannel=0;
- }
- }
-
- // Draw the selector
- vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel(),
- subtitleType,subtitleChannel,NULL);
- Colour osdBack = Colour(0, 0, 0, 128);
- vas->setBackgroundColour(osdBack);
- vas->setPosition(0, osd.getScreenY() - vas->getHeight());
- vas->draw();
-
- // make vas != null and displayOSD will not set a timer or do any boxstack update
- summary.setVisible(false);
- if (osd.getVisible()) displayOSD(false);
- else displayOSD(true);
- draw();
-
- BoxStack::getInstance()->add(vas);
- BoxStack::getInstance()->update(this);
- BoxStack::getInstance()->update(vas);
-}
-
-void VVideoLiveTV::doEPG()
-{
- if (osd.getVisible()) clearScreen();
-
- 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);
-}
-
-void VVideoLiveTV::setNowNextData()
-{
- delData();
-
- Channel* currentChannel = (*chanList)[osdChannelIndex];
-
- char formatChanNum[20];
- SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
- osdChanNum.setText(formatChanNum);
- osdChanName.setText(currentChannel->name);
-
- eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
-
- if (!eventList)
- {
- sl.addOption(tr("No channel data available"), 0, 1);
- }
- else
- {
- sort(eventList->begin(), eventList->end(), EventSorter());
-
- char tempString[300];
- char tempString2[300];
- struct tm* btime;
- Event* event;
- int eventListSize = eventList->size();
- for(int i = 0; i < eventListSize; i++)
- {
- event = (*eventList)[i];
-
- //btime = localtime((time_t*)&event->time);
- time_t etime = event->time;
- btime = localtime(&etime);
-#ifndef _MSC_VER
- strftime(tempString2, 299, "%0H:%0M ", btime);
-#else
- strftime(tempString2, 299, "%H:%M ", btime);
-#endif
- SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
-
- sl.addOption(tempString, (ULONG)event, (i==0));
- }
- }
-}
-
-void VVideoLiveTV::setSummaryData()
-{
- // If osd is not being displayed, sl will be filled with now, current channel
- // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now
- Event* selectedEvent = (Event*)sl.getCurrentOptionData();
-
- if (!selectedEvent)
- {
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary");
- textSummary.setText(tr("No summary available"));
- }
- else
- {
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description);
- textSummary.setText(selectedEvent->description);
- }
-}
-
-void VVideoLiveTV::displayOSD(bool newNowNextData)
-{
- osd.setVisible(true);
- if (newNowNextData)
- {
- setNowNextData();
- keying = 0;
- }
- osd.draw();
-
- if (summary.getVisible())
- {
- setSummaryData();
- summary.draw();
- boxstack->update(this, &osdSummaryRegion);
- }
- else
- {
- boxstack->update(this, osd.getRegion());
- }
-
- bool setTimer = true;
- if (vas) setTimer = false;
- if (summary.getVisible()) setTimer = false;
- if (textUnavailable.getVisible()) setTimer = false;
-
- if (setTimer) Timers::getInstance()->setTimerD(this, 1, 4);
-}
-
-void VVideoLiveTV::clearScreen()
-{
- if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);
-
- textUnavailable.setVisible(false);
- osd.setVisible(false);
- summary.setVisible(false);
-
- okTriggeredOSD = false;
-
- draw();
- boxstack->update(this);
-}
-
-void VVideoLiveTV::showUnavailable()
-{
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Show unavailable called");
- textUnavailable.setVisible(true);
- textUnavailable.draw();
-
- if (!osd.getVisible()) displayOSD(true);
-
- boxstack->update(this, textUnavailable.getRegion());
-}
-
-void VVideoLiveTV::setClock()
-{
- char timeString[20];
- time_t t;
- time(&t);
- struct tm* tms = localtime(&t);
- strftime(timeString, 19, "%H:%M", tms);
- clock.setText(timeString);
-
- time_t dt = 60 - (t % 60); // seconds to the next minute
- if (dt == 0) dt = 60; // advance a whole minute if necessary
- dt += t; // get a time_t value for it rather than using duration
- // (so it will occur at the actual second and not second and a half)
-
- Timers::getInstance()->setTimerT(this, 2, dt);
-}
-
-void VVideoLiveTV::timercall(int ref)
-{
- if (ref == 1)
- {
- if (keying)
- {
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key start.");
- UINT newChannel = 0;
- for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
-
- Message* m = new Message();
- m->message = Message::CHANNEL_CHANGE;
- m->to = this;
- m->parameter = newChannel;
- m->tag = 1; // signal to call displayOSD();
- Command::getInstance()->postMessageFromOuterSpace(m);
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key end.");
- }
- else
- {
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 not key start.");
- // We have received a timer, we are not keying. If still prebuffering, don't remove the bar
- if (preBuffering < 100)
- {
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Still prebuffering, not removing osd...");
- Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s
- return;
- }
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 1.");
- osd.setVisible(false);
- okTriggeredOSD = false;
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 2.");
- draw();
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 4.");
- boxstack->update(this, osd.getRegion());
-
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 3.");
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey end.");
- }
- }
- else if (ref == 2)
- {
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 start.");
- setClock();
- if (osd.getVisible())
- {
- clock.draw();
- boxstack->update(this, osd.getRegion());
- }
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 end.");
- }
-}
-
-bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
-{
- UINT newChannel = 0;
- if (streamType ==VDR::VIDEO) {
- VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
- if (vtxt ) {
- BoxStack::getInstance()->remove(vtxt);
-
- }
- }
- if (changeType == INDEX)
- {
- newChannel = newData;
- }
- else if (changeType == NUMBER)
- {
- UINT i;
- for(i = 0; i < chanList->size(); i++)
- {
- if ((*chanList)[i]->number == (UINT)newData)
- {
- newChannel = i;
- break;
- }
- }
-
- if (i == chanList->size())
- {
- // no such channel
- return false;
- }
- }
- else if (changeType == OFFSET)
- {
- if (newData == UP) newChannel = upChannel(currentChannelIndex);
- else newChannel = downChannel(currentChannelIndex);
- }
- else if (changeType == PREVIOUS)
- {
- newChannel = previousChannelIndex;
- }
- else
- {
- return false; // bad input
- }
-
- if (newChannel == currentChannelIndex) return true;
-
- previousChannelIndex = currentChannelIndex;
- currentChannelIndex = newChannel;
-
- preBuffering = 0;
-
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
- player->setChannel(currentChannelIndex);
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);
-
- // Blank out the symbols
- sAspectRatio.setVisible(false);
- bufferBar.setPercent(0);
- sAudioChannels.setVisible(false);
-
- // Remove other stuff
- if (textUnavailable.getVisible())
- {
- textUnavailable.setVisible(false);
-
- }
-
- draw();
- BoxStack::getInstance()->update(this);
-
- return true;
-}
-
-void VVideoLiveTV::processMessage(Message* m)
-{
- if (m->message == Message::MOUSE_LBDOWN)
- {
- //check if press is outside this view! then simulate cancel
- int x=(m->parameter>>16)-osd.getScreenX();
- int y=(m->parameter&0xFFFF)-osd.getScreenY();
- if (osd.getVisible()) {
-
- if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&
- (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {
- BoxStack::getInstance()->handleCommand(Remote::RED);
- } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&
- (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){
- BoxStack::getInstance()->handleCommand(Remote::GREEN);
- } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&
- (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){
- BoxStack::getInstance()->handleCommand(Remote::YELLOW);
- } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&
- (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){
- BoxStack::getInstance()->handleCommand(Remote::BLUE);
- } else {
- BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
- }
-
- } else {
- BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
- }
- }
- else if (m->message == Message::CHANNEL_CHANGE)
- {
- channelChange(NUMBER, m->parameter);
- osdChannelIndex = currentChannelIndex;
- if (m->tag == 1) displayOSD(true);
- }
- else if (m->message == Message::EPG_CLOSE)
- {
- video->setMode(videoMode);
- }
- else if (m->message == Message::CHILD_CLOSE)
- {
- if (m->from == vas)
- {
- vas = NULL;
- displayOSD(false);
- }
- }
- else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
- {
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
- player->setAudioChannel((m->parameter & 0xFFFF),(m->parameter & 0xFF0000)>>16);
- }
- else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
- {
- if (streamType !=VDR::VIDEO) return;
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);
- int type=((m->parameter & 0xFF0000)>>16);
- switch (type) {
- case 0x10: { //dvbsubtitle
- if (streamType = VDR::VIDEO){
- player->setSubtitleChannel((m->parameter & 0xFFFF));
- (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(true);
- VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
- if (vtxt && vtxt->isInSubtitleMode()) {
- BoxStack::getInstance()->remove(vtxt);
- }
- }
- } break;
- case 0xFF: { //nosubtitles
- if (streamType = VDR::VIDEO){
- (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
- VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
- if (vtxt && vtxt->isInSubtitleMode()) {
- BoxStack::getInstance()->remove(vtxt);
- }
- }
- } break;
- case 0x11: { //videotext
- (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
- doTeletext(true);
- ((PlayerLiveTV*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
- } break;
- };
- if (vas) {
- BoxStack::getInstance()->update(vas);
- //BoxStack::getInstance()->update(&osd); //eveil error
- }
- BoxStack::getInstance()->update(this, osd.getRegion());
-
-
- }
- else if (m->message == Message::PLAYER_EVENT)
- {
- switch(m->parameter)
- {
- case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
- {
- Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
- Command::getInstance()->connectionLost();
- break;
- }
-
- case PlayerLiveTV::STREAM_END:
- {
- // Message comes from playerlivetv through master mutex, so can do anything here
- showUnavailable();
- break;
- }
-
- case PlayerLiveTV::ASPECT43:
- {
- if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
- {
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
- wss.setWide(false);
- wss.draw();
- BoxStack::getInstance()->update(this, &wssRegion);
- }
-
- sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;
- sAspectRatio.setVisible(true);
-
- if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
- {
- osd.draw();
- BoxStack::getInstance()->update(this, osd.getRegion());
- }
-
- break;
- }
- case PlayerLiveTV::ASPECT169:
- {
- if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
- {
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
- wss.setWide(true);
- wss.draw();
- BoxStack::getInstance()->update(this, &wssRegion);
- }
-
- sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;
- sAspectRatio.setVisible(true);
-
- if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
- {
- osd.draw();
- BoxStack::getInstance()->update(this, osd.getRegion());
- }
-
- break;
- }
- case PlayerLiveTV::PREBUFFERING:
- {
- preBuffering = m->tag;
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", preBuffering);
- bufferBar.setPercent(preBuffering);
-
- if (osd.getVisible())
- {
- bufferBar.setVisible(true);
- bufferBar.draw();
- Region r;
- bufferBar.getRootBoxRegion(&r); ///////// FIXME !!!
- BoxStack::getInstance()->update(this, &r);
-
- if (preBuffering == 100)
- {
- doAudioChannelSymbol();
- }
- }
- }
- }
- }
-}
-
-void VVideoLiveTV::doAudioChannelSymbol()
-{
- // get the doobery
- Channel* currentChannel = (*chanList)[osdChannelIndex];
-
- bool multiAudio = false;
- #if WIN32
- if (currentChannel->numDPids > 1) multiAudio = true;
- #endif
- if (currentChannel->numAPids > 1) multiAudio = true;
-
- // draw the doobery
-
- if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO;
- else sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO;
- sAudioChannels.setVisible(true);
-
- if (osd.getVisible())
- {
- sAudioChannels.draw();
- Region r;
- sAudioChannels.getRootBoxRegion(&r); ///////// FIXME !!!
- // Fix this n'all.
- r.w = 32;
- r.h = 16;
- BoxStack::getInstance()->update(this, &r);
- }
-}
-
-UINT VVideoLiveTV::upChannel(UINT index)
-{
- if (index == (chanList->size() - 1)) // at the end
- return 0; // so go to start
- else
- return index + 1;
-}
-
-UINT VVideoLiveTV::downChannel(UINT index)
-{
- if (index == 0) // at the start
- return chanList->size() - 1; // so go to end
- else
- return index - 1;
-}
-
-void VVideoLiveTV::toggleChopSides()
-{
- if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
-
- if (videoMode == Video::NORMAL)
- {
- videoMode = Video::LETTERBOX;
- video->setMode(Video::LETTERBOX);
- }
- else
- {
- videoMode = Video::NORMAL;
- video->setMode(Video::NORMAL);
- }
-}
-
-void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)
-{
- drawBitmap(posX, posY, bm);
- Region r;
- r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
- boxstack->update(this, &r);
-}
-
-void VVideoLiveTV::clearOSD()
-{
- rectangle(area, Colour(0,0,0,0));
- boxstack->update(this, &area);
-}
-
-void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)
-{
- Region r;
- r.x = posX; r.y = posY; r.w = width; r.h = height;
- rectangle(r, Colour(0,0,0,0));
- boxstack->update(this, &r);
-}
+/*\r
+ Copyright 2007-2008 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vvideolivetv.h"\r
+\r
+#include "vchannellist.h"\r
+#include "video.h"\r
+#include "audio.h"\r
+#include "playerlive.h"\r
+#include "playerlivetv.h"\r
+#include "playerliveradio.h"\r
+#include "channel.h"\r
+#include "boxstack.h"\r
+#include "colour.h"\r
+#include "osd.h"\r
+#include "command.h"\r
+#include "i18n.h"\r
+#include "wtextbox.h"\r
+#include "remote.h"\r
+#include "vaudioselector.h"\r
+#include "colour.h"\r
+#include "event.h"\r
+#include "timers.h"\r
+#include "vepg.h"\r
+#include "bitmap.h"\r
+#include "log.h"\r
+#include "vteletextview.h"\r
+\r
+VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)\r
+{\r
+ vdr = VDR::getInstance();\r
+ boxstack = BoxStack::getInstance();\r
+ video = Video::getInstance();\r
+ \r
+ vas = NULL;\r
+\r
+ chanList = tchanList;\r
+ vchannelList = tvchannelList;\r
+ numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();\r
+\r
+ currentChannelIndex = 0;\r
+ previousChannelIndex = 0;\r
+ osdChannelIndex = 0;\r
+ keying = 0;\r
+ preBuffering = 0;\r
+\r
+ playing = false;\r
+\r
+ // Convert channel number to index\r
+ UINT i;\r
+ for(i = 0; i < chanList->size(); i++)\r
+ {\r
+ if ((*chanList)[i]->number == (UINT)initialChannelNumber)\r
+ {\r
+ currentChannelIndex = i;\r
+ osdChannelIndex = i;\r
+ break;\r
+ }\r
+ }\r
+\r
+ eventList = NULL;\r
+\r
+ videoMode = video->getMode();\r
+ \r
+ if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)\r
+ {\r
+ streamType = VDR::VIDEO;\r
+ player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);\r
+ }\r
+ else\r
+ {\r
+ streamType = VDR::RADIO;\r
+ player = new PlayerLiveRadio(Command::getInstance(), this, chanList);\r
+ }\r
+ player->init();\r
+\r
+ setSize(video->getScreenWidth(), video->getScreenHeight());\r
+ createBuffer();\r
+ Colour transparent(0, 0, 0, 0);\r
+ setBackgroundColour(transparent);\r
+\r
+ dowss = false;\r
+ char* optionWSS = vdr->configLoad("General", "WSS");\r
+ if (optionWSS)\r
+ {\r
+ if (strstr(optionWSS, "Yes")) dowss = true;\r
+ delete[] optionWSS;\r
+ }\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);\r
+\r
+ if (dowss)\r
+ {\r
+ wss.setFormat(video->getFormat());\r
+ wss.setWide(true);\r
+ add(&wss);\r
+ \r
+ wssRegion.x = 0;\r
+ wssRegion.y = 6;\r
+ wssRegion.w = video->getScreenWidth();\r
+ wssRegion.h = 2;\r
+ }\r
+ \r
+ // This variable is set to true if the user pressed OK to bring the OSD on screen\r
+ // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling\r
+ okTriggeredOSD = false;\r
+ \r
+ Colour osdBack = Colour(0, 0, 0, 128);\r
+ \r
+ osd.setBackgroundColour(osdBack);\r
+ osd.setPosition(0, video->getScreenHeight() - 150);\r
+ osd.setSize(video->getScreenWidth(), 150);\r
+ osd.setVisible(false);\r
+ add(&osd);\r
+ \r
+ clock.setBackgroundColour(osdBack);\r
+ clock.setPosition(osd.getWidth() - 100, 4);\r
+ clock.setSize(90, 30);\r
+ osd.add(&clock);\r
+\r
+ osdChanNum.setBackgroundColour(osdBack);\r
+ osdChanNum.setPosition(50, 4);\r
+ osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font\r
+ osd.add(&osdChanNum); \r
+\r
+ osdChanName.setBackgroundColour(osdBack);\r
+ osdChanName.setPosition(osdChanNum.getX2() + 10, 4);\r
+ osdChanName.setSize(300, 30);\r
+ osd.add(&osdChanName);\r
+ \r
+ boxRed.setBackgroundColour(Colour::RED);\r
+ boxRed.setPosition(54, 104);\r
+ boxRed.setSize(18, 16);\r
+ osd.add(&boxRed);\r
+\r
+ boxGreen.setBackgroundColour(Colour::GREEN);\r
+ boxGreen.setPosition(220, 104);\r
+ boxGreen.setSize(18, 16);\r
+ osd.add(&boxGreen);\r
+\r
+ boxYellow.setBackgroundColour(Colour::YELLOW);\r
+ boxYellow.setPosition(390, 104);\r
+ boxYellow.setSize(18, 16);\r
+ osd.add(&boxYellow);\r
+\r
+ boxBlue.setBackgroundColour(Colour::BLUE);\r
+ boxBlue.setPosition(560, 104);\r
+ boxBlue.setSize(18, 16);\r
+ osd.add(&boxBlue); \r
+ \r
+ textRed.setBackgroundColour(osdBack);\r
+ textRed.setPosition(boxRed.getX2(), 98);\r
+ textRed.setSize(boxGreen.getX() - boxRed.getX2(), 30);\r
+ textRed.setText(tr("Summary"));\r
+ osd.add(&textRed); \r
+ \r
+ if (streamType == VDR::VIDEO)\r
+ {\r
+ textGreen.setBackgroundColour(osdBack);\r
+ textGreen.setPosition(boxGreen.getX2(), 98);\r
+ textGreen.setSize(boxYellow.getX() - boxGreen.getX2(), 30);\r
+ textGreen.setText(tr("Audio"));\r
+ osd.add(&textGreen); \r
+ }\r
+ \r
+ textYellow.setBackgroundColour(osdBack);\r
+ textYellow.setPosition(boxYellow.getX2(), 98);\r
+ textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);\r
+ textYellow.setText(tr("Teletext"));\r
+ osd.add(&textYellow); \r
+ \r
+ textBlue.setBackgroundColour(osdBack);\r
+ textBlue.setPosition(boxBlue.getX2(), 98);\r
+ textBlue.setSize(osd.getX2() - boxBlue.getX2(), 30);\r
+ textBlue.setText(tr("EPG"));\r
+ osd.add(&textBlue); \r
+ \r
+ sl.setBackgroundColour(osdBack);\r
+ sl.setPosition(70, 36);\r
+ sl.setSize(500, 58);\r
+ sl.setNoLoop();\r
+ osd.add(&sl);\r
+ \r
+ // Summary Box\r
+ summary.setBackgroundColour(osdBack);\r
+ summary.setPosition(0, video->getScreenHeight() - 300);\r
+ summary.setSize(video->getScreenWidth(), 150);\r
+ summary.setVisible(false);\r
+ add(&summary); \r
+ \r
+ textSummary.setBackgroundColour(osdBack);\r
+ textSummary.setPosition(40, 10);\r
+ textSummary.setSize(video->getScreenWidth() - 80, 130);\r
+ textSummary.setParaMode(true);\r
+ summary.add(&textSummary);\r
+ \r
+ summaryBlackLine.setBackgroundColour(Colour::BLACK);\r
+ summaryBlackLine.setPosition(0, summary.getHeight() - 4);\r
+ summaryBlackLine.setSize(summary.getWidth(), 4);\r
+ summary.add(&summaryBlackLine);\r
+ \r
+ sAspectRatio.setPosition(osd.getWidth() - 90, 40);\r
+ sAspectRatio.nextColour = Colour::SELECTHIGHLIGHT;\r
+ sAspectRatio.setVisible(false);\r
+ osd.add(&sAspectRatio);\r
+ \r
+ bufferBar.setPosition(osd.getWidth() - 90, 70);\r
+ bufferBar.setSize(40, 20);\r
+ bufferBar.setVisible(true);\r
+ osd.add(&bufferBar);\r
+ \r
+ sAudioChannels.setPosition(osd.getWidth() - 130, 40);\r
+ sAudioChannels.nextColour = Colour::SELECTHIGHLIGHT;\r
+ sAudioChannels.setVisible(false);\r
+ osd.add(&sAudioChannels);\r
+ \r
+ textUnavailable.setBackgroundColour(osdBack);\r
+ textUnavailable.setPosition(60, 30);\r
+ textUnavailable.setSize(osd.getWidth() - 120, 30);\r
+ textUnavailable.setText(tr("Channel Unavailable"));\r
+ textUnavailable.setVisible(false);\r
+ add(&textUnavailable);\r
+ \r
+ // FIXME painful\r
+ Region r1 = summary.getRegionR();\r
+ Region r2 = osd.getRegionR();\r
+ osdSummaryRegion = r1 + r2;\r
+}\r
+\r
+void VVideoLiveTV::preDelete()\r
+{\r
+ if (playing) stop();\r
+}\r
+\r
+VVideoLiveTV::~VVideoLiveTV()\r
+{\r
+ delete player;\r
+ video->setDefaultAspect();\r
+ delData();\r
+}\r
+\r
+void VVideoLiveTV::delData()\r
+{\r
+ if (eventList)\r
+ {\r
+ int eventListSize = eventList->size();\r
+ for(int i = 0; i < eventListSize; i++)\r
+ {\r
+ delete (*eventList)[i];\r
+ }\r
+ eventList->clear();\r
+ delete eventList;\r
+\r
+ }\r
+ sl.clear();\r
+}\r
+\r
+int VVideoLiveTV::handleCommand(int command)\r
+{\r
+ switch(command)\r
+ {\r
+ case Remote::BACK:\r
+ {\r
+ if (osd.getVisible() && !textUnavailable.getVisible())\r
+ {\r
+ clearScreen();\r
+ return 2;\r
+ }\r
+ // else drop through to stop\r
+ }\r
+ case Remote::STOP:\r
+ {\r
+ stop();\r
+ vchannelList->highlightChannel((*chanList)[currentChannelIndex]);\r
+ return 4;\r
+ }\r
+ \r
+ // NEW REMOTE ONLY - navigate EPG, bring it onscreen if it's not there\r
+ case Remote::UP:\r
+ {\r
+ doUpDown(false);\r
+ return 2;\r
+ }\r
+ case Remote::DOWN:\r
+ {\r
+ doUpDown(true);\r
+ return 2;\r
+ }\r
+ case Remote::LEFT:\r
+ {\r
+ doLeftRight(false);\r
+ return 2;\r
+ }\r
+ case Remote::RIGHT:\r
+ {\r
+ doLeftRight(true);\r
+ return 2;\r
+ }\r
+ // Continue new remote only...\r
+ case Remote::CHANNELUP:\r
+ {\r
+ doChanUpDown(UP);\r
+ return 2;\r
+ }\r
+ case Remote::CHANNELDOWN:\r
+ {\r
+ doChanUpDown(DOWN);\r
+ return 2;\r
+ }\r
+\r
+ // END NEW REMOTE ONLY, START OLD REMOTE ONLY\r
+ \r
+ // DF_LEFT and DF_RIGHT never get here because they are stolen\r
+ // by command as vol- and vol+\r
+ \r
+ // Old remote. Decide what to do based on whether\r
+ // OK was pressed - osd shown manually, use up/down for epg nav\r
+ // UP/DOWN was pressed to change channel, osd was shown auto, use up/down for ch+/ch-\r
+ \r
+ case Remote::DF_UP:\r
+ {\r
+ // Old remote, decide what to do based on okTriggeredOSD\r
+ if (okTriggeredOSD) doUpDown(false);\r
+ else doChanUpDown(UP);\r
+ return 2;\r
+ }\r
+ case Remote::DF_DOWN:\r
+ {\r
+ // Old remote, decide what to do based on okTriggeredOSD\r
+ if (okTriggeredOSD) doUpDown(true);\r
+ else doChanUpDown(DOWN);\r
+ return 2;\r
+ }\r
+\r
+ // END NEW/OLD REMOTE STUFF\r
+\r
+ case Remote::PREVCHANNEL:\r
+ {\r
+ channelChange(PREVIOUS, 0);\r
+ osdChannelIndex = currentChannelIndex;\r
+ displayOSD(true);\r
+ return 2;\r
+ }\r
+ case Remote::OK:\r
+ {\r
+ doOK();\r
+ return 2;\r
+ }\r
+ case Remote::RED:\r
+ case Remote::MENU:\r
+ {\r
+ doSummary();\r
+ return 2;\r
+ }\r
+ case Remote::FULL:\r
+ case Remote::TV:\r
+ {\r
+ toggleChopSides();\r
+ return 2;\r
+ }\r
+\r
+ case Remote::ZERO:\r
+ case Remote::ONE:\r
+ case Remote::TWO:\r
+ case Remote::THREE:\r
+ case Remote::FOUR:\r
+ case Remote::FIVE:\r
+ case Remote::SIX:\r
+ case Remote::SEVEN:\r
+ case Remote::EIGHT:\r
+ case Remote::NINE:\r
+ {\r
+ // key in channel number\r
+ doKey(command);\r
+ return 2;\r
+ }\r
+\r
+ case Remote::GREEN:\r
+ {\r
+ if (streamType == VDR::VIDEO) doAudioSelector();\r
+ return 2; \r
+ }\r
+ case Remote::YELLOW:\r
+ {\r
+ if (streamType ==VDR::VIDEO) doTeletext(); //TODO: Add a selector for subtitles or teletext\r
+ return 2;\r
+ }\r
+ case Remote::GUIDE:\r
+ case Remote::BLUE:\r
+ {\r
+ doEPG();\r
+ return 2;\r
+ }\r
+ case Remote::RECORD:\r
+ if (streamType == VDR::VIDEO)\r
+ (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();\r
+ return 2;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+void VVideoLiveTV::go()\r
+{\r
+ playing = true;\r
+ draw();\r
+ boxstack->update(this);\r
+\r
+ setClock();\r
+ displayOSD(true);\r
+ \r
+ player->go(currentChannelIndex);\r
+}\r
+\r
+void VVideoLiveTV::stop()\r
+{\r
+ Timers::getInstance()->cancelTimer(this, 1);\r
+ Timers::getInstance()->cancelTimer(this, 2);\r
+ player->stop();\r
+ playing = false;\r
+}\r
+\r
+void VVideoLiveTV::doLeftRight(bool right)\r
+{\r
+ if (osd.getVisible())\r
+ {\r
+ if (right) osdChannelIndex = upChannel(osdChannelIndex);\r
+ else osdChannelIndex = downChannel(osdChannelIndex);\r
+ }\r
+ else\r
+ {\r
+ osdChannelIndex = currentChannelIndex;\r
+ }\r
+ displayOSD(true);\r
+}\r
+\r
+void VVideoLiveTV::doUpDown(bool down)\r
+{\r
+ if (osd.getVisible())\r
+ {\r
+ if (down) sl.down();\r
+ else sl.up();\r
+ sl.draw();\r
+ \r
+ displayOSD(false);\r
+ }\r
+ else\r
+ {\r
+ displayOSD(true);\r
+ }\r
+}\r
+\r
+void VVideoLiveTV::doChanUpDown(int which)\r
+{\r
+ channelChange(OFFSET, which);\r
+ osdChannelIndex = currentChannelIndex;\r
+ displayOSD(true);\r
+}\r
+\r
+void VVideoLiveTV::doOK()\r
+{\r
+ if (osd.getVisible())\r
+ {\r
+ if (keying)\r
+ {\r
+ UINT newChannel = 0;\r
+ for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);\r
+ \r
+ channelChange(NUMBER, newChannel);\r
+ osdChannelIndex = currentChannelIndex;\r
+ displayOSD(true);\r
+ }\r
+ else if (osdChannelIndex == currentChannelIndex)\r
+ {\r
+ clearScreen();\r
+ }\r
+ else\r
+ {\r
+ channelChange(INDEX, osdChannelIndex);\r
+ displayOSD(true);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ osdChannelIndex = currentChannelIndex;\r
+ displayOSD(true);\r
+ okTriggeredOSD = true;\r
+ }\r
+}\r
+\r
+void VVideoLiveTV::doSummary()\r
+{\r
+ if (summary.getVisible())\r
+ {\r
+ summary.setVisible(false);\r
+ draw();\r
+ boxstack->update(this, summary.getRegion());\r
+ Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd\r
+ return;\r
+ }\r
+\r
+ summary.setVisible(true);\r
+\r
+ if (osd.getVisible())\r
+ {\r
+ Timers::getInstance()->cancelTimer(this, 1);\r
+ displayOSD(false);\r
+ }\r
+ else\r
+ {\r
+ displayOSD(true);\r
+ }\r
+}\r
+\r
+void VVideoLiveTV::doKey(int command)\r
+{\r
+ if (!osd.getVisible()) // First key. prep the data\r
+ {\r
+ setNowNextData();\r
+ keying = 0; \r
+ }\r
+\r
+ int i;\r
+ for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];\r
+ keyingInput[0] = command;\r
+ keying++;\r
+\r
+ char* keyingString = new char[numberWidth + 1];\r
+ for (i = 0; i < numberWidth; i++) keyingString[i] = '_';\r
+ keyingString[numberWidth] = '\0';\r
+\r
+ for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;\r
+ \r
+ if (keying == numberWidth)\r
+ {\r
+ UINT newChannel = 0;\r
+ for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);\r
+ \r
+ channelChange(NUMBER, newChannel);\r
+ osdChannelIndex = currentChannelIndex;\r
+ Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,\r
+ displayOSD(true); // this will put one back if required\r
+ }\r
+ else\r
+ {\r
+ osdChanNum.setText(keyingString);\r
+\r
+ if (!osd.getVisible())\r
+ {\r
+ osd.setVisible(true);\r
+ draw();\r
+ }\r
+ else\r
+ {\r
+ osdChanNum.draw();\r
+ }\r
+ boxstack->update(this, osd.getRegion());\r
+ Timers::getInstance()->setTimerD(this, 1, 3); // 3s for keying input\r
+ }\r
+ delete[] keyingString;\r
+}\r
+\r
+void VVideoLiveTV::doTeletext(bool subtitlemode)\r
+{\r
+ if (streamType !=VDR::VIDEO) return;\r
+ bool exists=true;\r
+\r
+ // Cancel keying\r
+ if (keying)\r
+ {\r
+ keying = 0;\r
+ // and reset the display - this is a copy from setNowNextData\r
+ char formatChanNum[20];\r
+ SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);\r
+ osdChanNum.setText(formatChanNum);\r
+ osdChanName.setText((*chanList)[osdChannelIndex]->name);\r
+ }\r
+ if (osd.getVisible()) clearScreen();\r
+ // Draw the teletxt\r
+ VTeletextView *vtxv=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
+ if (vtxv==NULL) {\r
+ vtxv= new VTeletextView(((PlayerLiveTV*)player)->getTeletextDecoder(),this);\r
+ ((PlayerLiveTV*)player)->getTeletextDecoder()->registerTeletextView(vtxv);\r
+ exists=false;\r
+ }\r
+ vtxv->setSubtitleMode(subtitlemode);\r
+ vtxv->draw();\r
+ draw();\r
+ \r
+ if (!exists) {\r
+ BoxStack::getInstance()->add(vtxv);\r
+ }\r
+ BoxStack::getInstance()->update(this);\r
+ BoxStack::getInstance()->update(vtxv); \r
+}\r
+\r
+void VVideoLiveTV::doAudioSelector()\r
+{\r
+ // If the osd is already visisble there might be a timer for it\r
+ Timers::getInstance()->cancelTimer(this, 1);\r
+ //This causes a deadlock with the timertrhread itself is locked\r
+\r
+\r
+ // Cancel keying\r
+ if (keying)\r
+ {\r
+ keying = 0;\r
+ // and reset the display - this is a copy from setNowNextData\r
+ char formatChanNum[20];\r
+ SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);\r
+ osdChanNum.setText(formatChanNum);\r
+ osdChanName.setText((*chanList)[osdChannelIndex]->name);\r
+ }\r
+ int subtitleChannel=((PlayerLiveTV*)player)->getCurrentSubtitleChannel();\r
+ int subtitleType=0x10;\r
+ if (!(static_cast<PlayerLiveTV*>(player))->isSubtitlesOn()) {\r
+ if (((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView() &&\r
+ ((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() \r
+ ) {\r
+ subtitleChannel=((PlayerLiveTV*)player)->getTeletextDecoder()->getPage();\r
+ subtitleType=0x11;\r
+ \r
+ } else {\r
+ subtitleType=0xFF; //turnedOff\r
+ subtitleChannel=0;\r
+ }\r
+ }\r
+\r
+ // Draw the selector\r
+ vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel(),\r
+ subtitleType,subtitleChannel,NULL);\r
+ Colour osdBack = Colour(0, 0, 0, 128);\r
+ vas->setBackgroundColour(osdBack);\r
+ vas->setPosition(0, osd.getScreenY() - vas->getHeight());\r
+ vas->draw();\r
+\r
+ // make vas != null and displayOSD will not set a timer or do any boxstack update\r
+ summary.setVisible(false);\r
+ if (osd.getVisible()) displayOSD(false);\r
+ else displayOSD(true);\r
+ draw();\r
+\r
+ BoxStack::getInstance()->add(vas);\r
+ BoxStack::getInstance()->update(this); \r
+ BoxStack::getInstance()->update(vas); \r
+} \r
+ \r
+void VVideoLiveTV::doEPG()\r
+{\r
+ if (osd.getVisible()) clearScreen();\r
+\r
+ video->setMode(Video::QUARTER);\r
+ video->setPosition(170, 5); //TODO need to deal with 4:3 switching\r
+\r
+ VEpg* vepg = new VEpg(this, currentChannelIndex, streamType);\r
+ vepg->draw();\r
+ boxstack->add(vepg);\r
+ boxstack->update(vepg);\r
+}\r
+\r
+void VVideoLiveTV::setNowNextData()\r
+{\r
+ delData();\r
+ \r
+ Channel* currentChannel = (*chanList)[osdChannelIndex];\r
+\r
+ char formatChanNum[20];\r
+ SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);\r
+ osdChanNum.setText(formatChanNum);\r
+ osdChanName.setText(currentChannel->name);\r
+\r
+ eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);\r
+\r
+ if (!eventList)\r
+ {\r
+ sl.addOption(tr("No channel data available"), 0, 1);\r
+ }\r
+ else\r
+ {\r
+ sort(eventList->begin(), eventList->end(), EventSorter());\r
+\r
+ char tempString[300];\r
+ char tempString2[300];\r
+ struct tm* btime;\r
+ Event* event;\r
+ int eventListSize = eventList->size();\r
+ for(int i = 0; i < eventListSize; i++)\r
+ {\r
+ event = (*eventList)[i];\r
+\r
+ //btime = localtime((time_t*)&event->time);\r
+ time_t etime = event->time;\r
+ btime = localtime(&etime);\r
+#ifndef _MSC_VER\r
+ strftime(tempString2, 299, "%0H:%0M ", btime);\r
+#else\r
+ strftime(tempString2, 299, "%H:%M ", btime);\r
+#endif\r
+ SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);\r
+ \r
+ sl.addOption(tempString, (ULONG)event, (i==0));\r
+ }\r
+ }\r
+}\r
+\r
+void VVideoLiveTV::setSummaryData()\r
+{\r
+ // If osd is not being displayed, sl will be filled with now, current channel\r
+ // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now\r
+ Event* selectedEvent = (Event*)sl.getCurrentOptionData();\r
+ \r
+ if (!selectedEvent)\r
+ {\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary"); \r
+ textSummary.setText(tr("No summary available"));\r
+ }\r
+ else\r
+ {\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description); \r
+ textSummary.setText(selectedEvent->description);\r
+ }\r
+}\r
+\r
+void VVideoLiveTV::displayOSD(bool newNowNextData)\r
+{\r
+ osd.setVisible(true);\r
+ if (newNowNextData)\r
+ {\r
+ setNowNextData();\r
+ keying = 0;\r
+ }\r
+ osd.draw();\r
+ \r
+ if (summary.getVisible())\r
+ {\r
+ setSummaryData();\r
+ summary.draw();\r
+ boxstack->update(this, &osdSummaryRegion);\r
+ }\r
+ else\r
+ {\r
+ boxstack->update(this, osd.getRegion());\r
+ }\r
+ \r
+ bool setTimer = true;\r
+ if (vas) setTimer = false;\r
+ if (summary.getVisible()) setTimer = false;\r
+ if (textUnavailable.getVisible()) setTimer = false;\r
+\r
+ if (setTimer) Timers::getInstance()->setTimerD(this, 1, 4);\r
+}\r
+\r
+void VVideoLiveTV::clearScreen()\r
+{ \r
+ if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);\r
+\r
+ textUnavailable.setVisible(false);\r
+ osd.setVisible(false);\r
+ summary.setVisible(false);\r
+\r
+ okTriggeredOSD = false;\r
+\r
+ draw();\r
+ boxstack->update(this);\r
+}\r
+\r
+void VVideoLiveTV::showUnavailable()\r
+{\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Show unavailable called"); \r
+ textUnavailable.setVisible(true);\r
+ textUnavailable.draw();\r
+ \r
+ if (!osd.getVisible()) displayOSD(true);\r
+\r
+ boxstack->update(this, textUnavailable.getRegion()); \r
+}\r
+\r
+void VVideoLiveTV::setClock()\r
+{\r
+ char timeString[20];\r
+ time_t t;\r
+ time(&t);\r
+ struct tm* tms = localtime(&t);\r
+ strftime(timeString, 19, "%H:%M", tms);\r
+ clock.setText(timeString);\r
+\r
+ time_t dt = 60 - (t % 60); // seconds to the next minute\r
+ if (dt == 0) dt = 60; // advance a whole minute if necessary\r
+ dt += t; // get a time_t value for it rather than using duration\r
+ // (so it will occur at the actual second and not second and a half)\r
+\r
+ Timers::getInstance()->setTimerT(this, 2, dt);\r
+}\r
+\r
+void VVideoLiveTV::timercall(int ref)\r
+{\r
+ if (ref == 1)\r
+ {\r
+ if (keying)\r
+ {\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key start."); \r
+ UINT newChannel = 0;\r
+ for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);\r
+ \r
+ Message* m = new Message();\r
+ m->message = Message::CHANNEL_CHANGE;\r
+ m->to = this;\r
+ m->parameter = newChannel;\r
+ m->tag = 1; // signal to call displayOSD();\r
+ Command::getInstance()->postMessageFromOuterSpace(m);\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key end."); \r
+ }\r
+ else\r
+ {\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 not key start."); \r
+ // We have received a timer, we are not keying. If still prebuffering, don't remove the bar\r
+ if (preBuffering < 100)\r
+ {\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Still prebuffering, not removing osd..."); \r
+ Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s\r
+ return;\r
+ }\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 1."); \r
+ osd.setVisible(false);\r
+ okTriggeredOSD = false;\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 2."); \r
+ draw();\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 4."); \r
+ boxstack->update(this, osd.getRegion());\r
+\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 3."); \r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey end."); \r
+ }\r
+ }\r
+ else if (ref == 2)\r
+ {\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 start."); \r
+ setClock();\r
+ if (osd.getVisible())\r
+ {\r
+ clock.draw();\r
+ boxstack->update(this, osd.getRegion());\r
+ }\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 end."); \r
+ }\r
+}\r
+\r
+bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)\r
+{\r
+ UINT newChannel = 0;\r
+ if (streamType ==VDR::VIDEO) {\r
+ VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
+ if (vtxt ) {\r
+ BoxStack::getInstance()->remove(vtxt);\r
+\r
+ }\r
+ }\r
+ if (changeType == INDEX)\r
+ {\r
+ newChannel = newData;\r
+ }\r
+ else if (changeType == NUMBER)\r
+ {\r
+ UINT i;\r
+ for(i = 0; i < chanList->size(); i++)\r
+ {\r
+ if ((*chanList)[i]->number == (UINT)newData)\r
+ {\r
+ newChannel = i;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (i == chanList->size())\r
+ {\r
+ // no such channel\r
+ return false;\r
+ }\r
+ }\r
+ else if (changeType == OFFSET)\r
+ {\r
+ if (newData == UP) newChannel = upChannel(currentChannelIndex);\r
+ else newChannel = downChannel(currentChannelIndex);\r
+ }\r
+ else if (changeType == PREVIOUS)\r
+ {\r
+ newChannel = previousChannelIndex;\r
+ }\r
+ else\r
+ {\r
+ return false; // bad input\r
+ }\r
+\r
+ if (newChannel == currentChannelIndex) return true;\r
+\r
+ previousChannelIndex = currentChannelIndex;\r
+ currentChannelIndex = newChannel;\r
+ \r
+ preBuffering = 0;\r
+ \r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);\r
+ player->setChannel(currentChannelIndex);\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);\r
+\r
+ // Blank out the symbols\r
+ sAspectRatio.setVisible(false);\r
+ bufferBar.setPercent(0);\r
+ sAudioChannels.setVisible(false);\r
+ \r
+ // Remove other stuff\r
+ if (textUnavailable.getVisible())\r
+ {\r
+ textUnavailable.setVisible(false);\r
+ \r
+ }\r
+\r
+ draw();\r
+ BoxStack::getInstance()->update(this);\r
+ \r
+ return true;\r
+}\r
+\r
+void VVideoLiveTV::processMessage(Message* m)\r
+{\r
+ if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ //check if press is outside this view! then simulate cancel\r
+ int x=(m->parameter>>16)-osd.getScreenX();\r
+ int y=(m->parameter&0xFFFF)-osd.getScreenY();\r
+ if (osd.getVisible()) {\r
+ \r
+ if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&\r
+ (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {\r
+ BoxStack::getInstance()->handleCommand(Remote::RED);\r
+ } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&\r
+ (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){\r
+ BoxStack::getInstance()->handleCommand(Remote::GREEN);\r
+ } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&\r
+ (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){\r
+ BoxStack::getInstance()->handleCommand(Remote::YELLOW);\r
+ } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&\r
+ (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){\r
+ BoxStack::getInstance()->handleCommand(Remote::BLUE);\r
+ } else {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+ }\r
+\r
+ } else {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+ }\r
+ }\r
+ else if (m->message == Message::CHANNEL_CHANGE)\r
+ {\r
+ channelChange(NUMBER, m->parameter);\r
+ osdChannelIndex = currentChannelIndex;\r
+ if (m->tag == 1) displayOSD(true);\r
+ }\r
+ else if (m->message == Message::EPG_CLOSE)\r
+ {\r
+ video->setMode(videoMode);\r
+ }\r
+ else if (m->message == Message::CHILD_CLOSE)\r
+ {\r
+ if (m->from == vas)\r
+ {\r
+ vas = NULL;\r
+ displayOSD(false);\r
+ }\r
+ }\r
+ else if (m->message == Message::AUDIO_CHANGE_CHANNEL)\r
+ {\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);\r
+ player->setAudioChannel((m->parameter & 0xFFFF),(m->parameter & 0xFF0000)>>16);\r
+ } \r
+ else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)\r
+ {\r
+ if (streamType !=VDR::VIDEO) return;\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);\r
+ int type=((m->parameter & 0xFF0000)>>16);\r
+ switch (type) {\r
+ case 0x10: { //dvbsubtitle\r
+ if (streamType == VDR::VIDEO){\r
+ player->setSubtitleChannel((m->parameter & 0xFFFF));\r
+ (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(true);\r
+ VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
+ if (vtxt && vtxt->isInSubtitleMode()) {\r
+ BoxStack::getInstance()->remove(vtxt);\r
+ }\r
+ }\r
+ } break;\r
+ case 0xFF: { //nosubtitles\r
+ if (streamType == VDR::VIDEO){\r
+ (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);\r
+ VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
+ if (vtxt && vtxt->isInSubtitleMode()) {\r
+ BoxStack::getInstance()->remove(vtxt);\r
+ } \r
+ }\r
+ } break;\r
+ case 0x11: { //videotext\r
+ (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);\r
+ doTeletext(true);\r
+ ((PlayerLiveTV*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));\r
+ } break;\r
+ };\r
+ if (vas) {\r
+ BoxStack::getInstance()->update(vas);\r
+ //BoxStack::getInstance()->update(&osd); //eveil error\r
+ }\r
+ BoxStack::getInstance()->update(this, osd.getRegion());\r
+\r
+ \r
+ }\r
+ else if (m->message == Message::PLAYER_EVENT)\r
+ {\r
+ switch(m->parameter)\r
+ {\r
+ case PlayerLiveTV::CONNECTION_LOST: // connection lost detected\r
+ {\r
+ Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");\r
+ Command::getInstance()->connectionLost();\r
+ break;\r
+ }\r
+ \r
+ case PlayerLiveTV::STREAM_END:\r
+ {\r
+ // Message comes from playerlivetv through master mutex, so can do anything here\r
+ showUnavailable(); \r
+ break;\r
+ }\r
+ \r
+ case PlayerLiveTV::ASPECT43:\r
+ {\r
+ if ((video->getTVsize() == Video::ASPECT16X9) && dowss)\r
+ {\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");\r
+ wss.setWide(false);\r
+ wss.draw();\r
+ BoxStack::getInstance()->update(this, &wssRegion);\r
+ }\r
+ \r
+ sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;\r
+ sAspectRatio.setVisible(true);\r
+ \r
+ if (osd.getVisible()) // don't wake up the whole osd just for a aspect change\r
+ {\r
+ osd.draw();\r
+ BoxStack::getInstance()->update(this, osd.getRegion());\r
+ }\r
+ \r
+ break;\r
+ }\r
+ case PlayerLiveTV::ASPECT169:\r
+ {\r
+ if ((video->getTVsize() == Video::ASPECT16X9) && dowss)\r
+ {\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");\r
+ wss.setWide(true);\r
+ wss.draw();\r
+ BoxStack::getInstance()->update(this, &wssRegion);\r
+ }\r
+ \r
+ sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;\r
+ sAspectRatio.setVisible(true);\r
+\r
+ if (osd.getVisible()) // don't wake up the whole osd just for a aspect change\r
+ {\r
+ osd.draw();\r
+ BoxStack::getInstance()->update(this, osd.getRegion());\r
+ }\r
+ \r
+ break;\r
+ }\r
+ case PlayerLiveTV::PREBUFFERING:\r
+ {\r
+ preBuffering = m->tag;\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", preBuffering);\r
+ bufferBar.setPercent(preBuffering);\r
+\r
+ if (osd.getVisible())\r
+ {\r
+ bufferBar.setVisible(true);\r
+ bufferBar.draw();\r
+ Region r;\r
+ bufferBar.getRootBoxRegion(&r); ///////// FIXME !!!\r
+ BoxStack::getInstance()->update(this, &r);\r
+\r
+ if (preBuffering == 100)\r
+ {\r
+ doAudioChannelSymbol();\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void VVideoLiveTV::doAudioChannelSymbol()\r
+{\r
+ // get the doobery\r
+ Channel* currentChannel = (*chanList)[osdChannelIndex];\r
+ \r
+ bool multiAudio = false;\r
+ if (Audio::getInstance()->supportsAc3()) {\r
+ if ((currentChannel->numDPids+currentChannel->numAPids) > 1) multiAudio = true;\r
+ }\r
+ if (currentChannel->numAPids > 1) multiAudio = true;\r
+ \r
+ // draw the doobery\r
+ \r
+ if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO;\r
+ else sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO;\r
+ sAudioChannels.setVisible(true);\r
+ \r
+ if (osd.getVisible())\r
+ {\r
+ sAudioChannels.draw();\r
+ Region r;\r
+ sAudioChannels.getRootBoxRegion(&r); ///////// FIXME !!!\r
+ // Fix this n'all.\r
+ r.w = 32;\r
+ r.h = 16;\r
+ BoxStack::getInstance()->update(this, &r);\r
+ }\r
+}\r
+\r
+UINT VVideoLiveTV::upChannel(UINT index)\r
+{\r
+ if (index == (chanList->size() - 1)) // at the end\r
+ return 0; // so go to start\r
+ else\r
+ return index + 1;\r
+}\r
+\r
+UINT VVideoLiveTV::downChannel(UINT index)\r
+{\r
+ if (index == 0) // at the start\r
+ return chanList->size() - 1; // so go to end\r
+ else\r
+ return index - 1;\r
+}\r
+\r
+void VVideoLiveTV::toggleChopSides()\r
+{\r
+ if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs\r
+\r
+ if (videoMode == Video::NORMAL)\r
+ {\r
+ videoMode = Video::LETTERBOX;\r
+ video->setMode(Video::LETTERBOX);\r
+ }\r
+ else\r
+ {\r
+ videoMode = Video::NORMAL;\r
+ video->setMode(Video::NORMAL);\r
+ }\r
+}\r
+\r
+void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)\r
+{\r
+ drawBitmap(posX, posY, bm);\r
+ Region r;\r
+ r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();\r
+ boxstack->update(this, &r);\r
+}\r
+\r
+void VVideoLiveTV::clearOSD()\r
+{\r
+ rectangle(area, Colour(0,0,0,0));\r
+ boxstack->update(this, &area);\r
+}\r
+\r
+void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)\r
+{\r
+ Region r;\r
+ r.x = posX; r.y = posY; r.w = width; r.h = height;\r
+ rectangle(r, Colour(0,0,0,0));\r
+ boxstack->update(this, &r);\r
+}\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vvideomedia.h"
-#include "vmedialist.h"
-#include "media.h"
-#include "mediaplayer.h"
-
-#include "command.h"
-#include "osd.h"
-#include "wsymbol.h"
-#include "audio.h"
-#include "video.h"
-#include "timers.h"
-#include "playermedia.h"
-#include "recording.h"
-#include "vaudioselector.h"
-#include "message.h"
-#include "remote.h"
-#include "boxstack.h"
-#include "vinfo.h"
-#include "i18n.h"
-#include "log.h"
-#include "recinfo.h"
-
-//use the picture channel
-#define MEDIACHANNEL 1
-
-//we misuse PLAYER_EVENTS for timer messages
-//this should be larger then any player message
-#define PLAYER_TIMER_BASE 100
-
-VVideoMedia::VVideoMedia(Media* media, VMediaList *p)
-{
- lparent=p;
- boxstack = BoxStack::getInstance();
- video = Video::getInstance();
- timers = Timers::getInstance();
- vas = NULL;
- vsummary = NULL;
- lengthBytes=0;
- myMedia = new Media(media);
-
- player = new PlayerMedia(this);
- player->run();
-
- videoMode = video->getMode();
-
- playing = false;
-
-
- setSize(video->getScreenWidth(), video->getScreenHeight());
- createBuffer();
- transparent.set(0, 0, 0, 0);
- setBackgroundColour(transparent);
-
- barRegion.x = 0;
- barRegion.y = video->getScreenHeight() - 58; // FIXME, need to be - 1? and below?
- barRegion.w = video->getScreenWidth();
- barRegion.h = 58;
-
- clocksRegion.x = barRegion.x + 140;
- clocksRegion.y = barRegion.y + 12;
- clocksRegion.w = 170;
- clocksRegion.h = surface->getFontHeight();
-
-
- barBlue.set(0, 0, 150, 150);
-
- barShowing = false;
- barGenHold = false;
- barScanHold = false;
- barVasHold = false;
-
- dowss = false;
- char* optionWSS = VDR::getInstance()->configLoad("General", "WSS");
- if (optionWSS)
- {
- if (strstr(optionWSS, "Yes")) dowss = true;
- delete[] optionWSS;
- }
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Do WSS: %u", dowss);
-
- if (dowss)
- {
- wss.setFormat(video->getFormat());
- wss.setWide(true);
- add(&wss);
-
- wssRegion.x = 0;
- wssRegion.y = 0;
- wssRegion.w = video->getScreenWidth();
- wssRegion.h = 300;
- }
-}
-
-VVideoMedia::~VVideoMedia()
-{
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Entering destructor");
-
- if (vas)
- {
- boxstack->remove(vas);
- vas = NULL;
- }
-
- if (vsummary) {
- remove(vsummary);
- delete vsummary;
- }
-
- if (playing) stopPlay();
- video->setDefaultAspect();
-
- timers->cancelTimer(this, 1);
- timers->cancelTimer(this, 2);
-
- delete myMedia;
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "shutting down player");
- player->shutdown();
- delete player;
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "deleted");
-}
-
-void VVideoMedia::go(bool resume)
-{
- ULONG startFrameNum=0;
-
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Starting stream: %s at frame: %lu", myMedia->getFileName(), startFrameNum);
-
- lengthBytes = 0;
-
- int rt=0;
- const MediaURI *u=myMedia->getURI();
- if (!u) {
- Log::getInstance()->log("VVideoMedia", Log::ERR, "stream: %s has no URI", myMedia->getFileName());
- rt=-1;
- }
- else {
- rt=MediaPlayer::getInstance()->openMedium(MEDIACHANNEL,u,&lengthBytes,area.w,area.h);
- }
- if (rt==0)
- {
- //TODO: figure out len in frames
- int seq=player->playNew(MEDIACHANNEL,lengthBytes,0);
- int ok=player->waitForSequence(2,seq);
- if (ok < 0) rt=-1;
- else {
- playing = true;
- doBar(0);
- }
- }
- if (rt != 0)
- {
- stopPlay(); // clean up
-
- Message* m = new Message();
- m->message = Message::CLOSE_ME;
- m->from = this;
- m->to = boxstack;
- Command::getInstance()->postMessageNoLock(m);
-
- VInfo* vi = new VInfo();
- vi->setSize(400, 150);
- vi->createBuffer();
- if (video->getFormat() == Video::PAL)
- vi->setPosition(170, 200);
- else
- vi->setPosition(160, 150);
- vi->setExitable();
- vi->setBorderOn(1);
- vi->setTitleBarOn(0);
- vi->setOneLiner(tr("Error playing media"));
- vi->draw();
-
- m = new Message();
- m->message = Message::ADD_VIEW;
- m->to = boxstack;
- m->parameter = (ULONG)vi;
- Command::getInstance()->postMessageNoLock(m);
- }
-}
-
-int VVideoMedia::handleCommand(int command)
-{
- switch(command)
- {
- case Remote::PLAY:
- {
- player->play();
- doBar(0);
- return 2;
- }
-
- case Remote::BACK:
- {
- if (vsummary)
- {
- removeSummary();
- return 2;
- }
- } // DROP THROUGH
- case Remote::STOP:
- case Remote::MENU:
- {
- if (playing) stopPlay();
-
- return 4;
- }
- case Remote::PAUSE:
- {
- player->pause();
- doBar(0);
- return 2;
- }
- case Remote::SKIPFORWARD:
- {
- doBar(3);
- player->skipForward(60);
- return 2;
- }
- case Remote::SKIPBACK:
- {
- doBar(4);
- player->skipBackward(60);
- return 2;
- }
- case Remote::FORWARD:
- {
- player->fastForward();
- doBar(0);
- return 2;
- }
- case Remote::REVERSE:
- {
- player->fastBackward();
- doBar(0);
- return 2;
- }
- case Remote::RED:
- {
- if (vsummary) removeSummary();
- else doSummary();
- return 2;
- }
- case Remote::GREEN:
- {
- doAudioSelector();
- return 2;
- }
- case Remote::YELLOW:
- {
- doBar(2);
- player->skipBackward(10);
- return 2;
- }
- case Remote::BLUE:
- {
- doBar(1);
- player->skipForward(10);
- return 2;
- }
- case Remote::STAR:
- {
- doBar(2);
- player->skipBackward(10);
- return 2;
- }
- case Remote::HASH:
- {
- doBar(1);
- player->skipForward(10);
- return 2;
- }
- case Remote::FULL:
- case Remote::TV:
- {
- toggleChopSides();
- return 2;
- }
-
- case Remote::OK:
- {
- if (vsummary)
- {
- removeSummary();
- return 2;
- }
-
- if (barShowing) removeBar();
- else {
- doBar(0);
- barGenHold=true;
- }
- return 2;
- }
-
- case Remote::ZERO: player->jumpToPercent(0); doBar(0); return 2;
- case Remote::ONE: player->jumpToPercent(10); doBar(0); return 2;
- case Remote::TWO: player->jumpToPercent(20); doBar(0); return 2;
- case Remote::THREE: player->jumpToPercent(30); doBar(0); return 2;
- case Remote::FOUR: player->jumpToPercent(40); doBar(0); return 2;
- case Remote::FIVE: player->jumpToPercent(50); doBar(0); return 2;
- case Remote::SIX: player->jumpToPercent(60); doBar(0); return 2;
- case Remote::SEVEN: player->jumpToPercent(70); doBar(0); return 2;
- case Remote::EIGHT: player->jumpToPercent(80); doBar(0); return 2;
- case Remote::NINE: player->jumpToPercent(90); doBar(0); return 2;
-
-
- }
-
- return 1;
-}
-
-void VVideoMedia::processMessage(Message* m)
-{
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Message received");
-
- if (m->message == Message::MOUSE_LBDOWN)
- {
- UINT x = (m->parameter>>16) - getScreenX();
- UINT y = (m->parameter&0xFFFF) - getScreenY();
-
- if (!barShowing)
- {
- BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
- }
- else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
- {
- int progBarXbase = barRegion.x + 300;
- if (x>=barRegion.x + progBarXbase + 24
- && x<=barRegion.x + progBarXbase + 4 + 302
- && y>=barRegion.y + 12 - 2
- && y<=barRegion.y + 12 - 2+28)
- {
- int cx=x-(barRegion.x + progBarXbase + 4);
- double percent=((double)cx)/302.*100.;
- player->jumpToPercent(percent);
- doBar(3);
- return;
- // int progressWidth = 302 * currentFrameNum / lengthFrames;
- // rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
- }
- }
- else
- {
- BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
- }
- }
- else if (m->message == Message::PLAYER_EVENT)
- {
- switch(m->parameter)
- {
- case PlayerMedia::CONNECTION_LOST: // connection lost detected
- {
- // I can't handle this, send it to command
- Message* m2 = new Message();
- m2->to = Command::getInstance();
- m2->message = Message::CONNECTION_LOST;
- Command::getInstance()->postMessageNoLock(m2);
- break;
- }
- case PlayerMedia::STREAM_END:
- {
- Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
- m2->to = BoxStack::getInstance();
- m2->message = Message::CLOSE_ME;
- Command::getInstance()->postMessageNoLock(m2);
- break;
- }
- case PlayerMedia::STATUS_CHANGE:
- doBar(0);
- break;
- case PlayerMedia::ASPECT43:
- {
- if (dowss)
- {
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 43");
- wss.setWide(false);
- wss.draw();
- boxstack->update(this, &wssRegion);
- }
- break;
- }
- case PlayerMedia::ASPECT169:
- {
- if (dowss)
- {
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 169");
- wss.setWide(true);
- wss.draw();
- boxstack->update(this, &wssRegion);
- }
- break;
- }
- case (PLAYER_TIMER_BASE+1) :
- //timer1:
- // Remove bar
- removeBar();
- break;
- case (PLAYER_TIMER_BASE+2) :
- //timer2:
- // Update clock
- if (!barShowing) break;
- drawBarClocks();
- BoxStack::getInstance()->update(this,&barRegion);
- if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);
- else timers->setTimerD(this, 2, 1);
- break;
- }
- }
- else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
- {
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received change audio channel to %i", m->parameter);
- player->setAudioChannel(m->parameter);
- }
- else if (m->message == Message::CHILD_CLOSE)
- {
- if (m->from == vas)
- {
- vas = NULL;
- barVasHold = false;
- if (!barGenHold && !barScanHold && !barVasHold) removeBar();
- }
- }
-}
-
-void VVideoMedia::stopPlay()
-{
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Pre stopPlay");
-
- removeBar();
-
- player->stop();
-
- playing = false;
- MediaPlayer::getInstance()->closeMediaChannel(MEDIACHANNEL);
-
- Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Post stopPlay");
-}
-
-void VVideoMedia::toggleChopSides()
-{
- if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
-
- if (videoMode == Video::NORMAL)
- {
- videoMode = Video::LETTERBOX;
- video->setMode(Video::LETTERBOX);
- }
- else
- {
- videoMode = Video::NORMAL;
- video->setMode(Video::NORMAL);
- }
-}
-
-void VVideoMedia::doAudioSelector()
-{
- bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
- bool* availableAc3AudioChannels = 0;
- int currentAudioChannel = player->getCurrentAudioChannel();
- if (Audio::getInstance()->supportsAc3())
- {
- availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
- }
-
-
- RecInfo ri;
- ri.summary=new char[strlen(myMedia->getDisplayName())+1];
- strcpy(ri.summary,myMedia->getDisplayName());
- vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, NULL,NULL,0,0, &ri);
-
- vas->setBackgroundColour(barBlue);
- vas->setPosition(0, barRegion.y - 120);
-
-// pal 62, ntsc 57
-
- barVasHold = true;
- doBar(0);
-
- vas->draw();
- boxstack->add(vas);
- boxstack->update(vas);
-}
-
-void VVideoMedia::doBar(int action)
-{
- Log::getInstance()->log("VVideoMedia",Log::DEBUG,"doBar %d",action);
- barShowing = true;
-
- rectangle(barRegion, barBlue);
-
- /* Work out what to display - choices:
-
- Playing >
- Paused ||
- FFwd >>
- FBwd <<
-
- Specials, informed by parameter
-
- Skip forward 10s >|
- Skip backward 10s |<
- Skip forward 1m >>|
- Skip backward 1m |<<
-
- */
-
- WSymbol w;
- TEMPADD(&w);
- w.nextSymbol = 0;
- w.setPosition(barRegion.x + 66, barRegion.y + 16);
-
- UCHAR playerState = 0;
-
- if (action)
- {
- if (action == 1) w.nextSymbol = WSymbol::SKIPFORWARD;
- else if (action == 2) w.nextSymbol = WSymbol::SKIPBACK;
- else if (action == 3) w.nextSymbol = WSymbol::SKIPFORWARD2;
- else if (action == 4) w.nextSymbol = WSymbol::SKIPBACK2;
- }
- else
- {
- playerState = player->getState();
- if (playerState == PlayerMedia::S_PLAY) w.nextSymbol = WSymbol::PLAY;
- else if (playerState == PlayerMedia::S_FF) w.nextSymbol = WSymbol::FFWD;
- else if (playerState == PlayerMedia::S_BACK) w.nextSymbol = WSymbol::FBWD;
- else if (playerState == PlayerMedia::S_SEEK) w.nextSymbol = WSymbol::RIGHTARROW;
- else if (playerState == PlayerMedia::S_STOP) w.nextSymbol = WSymbol::PAUSE;
- else w.nextSymbol = WSymbol::PAUSE;
- }
-
- w.draw();
-
- if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK))
- {
- // draw blips to show how fast the scan is
- UCHAR scanrate = 2;//player->getIScanRate();
- if (scanrate >= 2)
- {
- char text[5];
- SNPRINTF(text, 5, "%ux", scanrate);
- drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);
- }
- }
-
- drawBarClocks();
- boxstack->update(this, &barRegion);
-
- timers->cancelTimer(this, 1);
-
-
- if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK)) barScanHold = true;
- else barScanHold = false;
-
- if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
-
- if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);
- else timers->setTimerD(this, 2, 1);
-}
-
-void VVideoMedia::timercall(int clientReference)
-{
- Message *m=new Message();
- m->message=Message::PLAYER_EVENT;
- m->to=this;
- m->from=this;
- m->parameter=PLAYER_TIMER_BASE+clientReference;
- Command::getInstance()->postMessageFromOuterSpace(m);
-}
-
-void VVideoMedia::drawBarClocks()
-{
- if (barScanHold)
- {
- UCHAR playerState = player->getState();
- // sticky bar is set if we are in ffwd/fbwd mode
- // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
- // will repaint all the bar (it will call this function again, but
- // this section won't run because stickyBarF will then == false)
-
- if ((playerState != PlayerMedia::S_FF) && (playerState != PlayerMedia::S_BACK))
- {
- barScanHold = false;
- doBar(0);
- return;
- }
- }
-
- Log* logger = Log::getInstance();
- logger->log("VVideoMedia", Log::DEBUG, "Draw bar clocks");
-
- // Draw RTC
- // Blank the area first
- rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
- char timeString[20];
- time_t t;
- time(&t);
- struct tm* tms = localtime(&t);
- strftime(timeString, 19, "%H:%M", tms);
- drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
-
- ULLONG lenPTS=player->getLenPTS();
- // Draw clocks
-
- rectangle(clocksRegion, barBlue);
-
- ULLONG currentPTS = player->getCurrentPTS();
-
- hmsf currentFrameHMSF = ptsToHMS(currentPTS);
- hmsf lengthHMSF = ptsToHMS(lenPTS);
-
- char buffer[100];
- if (currentPTS > lenPTS && lenPTS != 0)
- {
- strcpy(buffer, "-:--:-- / -:--:--");
- }
- else
- {
- SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
- }
- logger->log("VVideoMedia", Log::DEBUG, "cur %llu,len %llu, txt %s",currentPTS,lenPTS,buffer);
-
- drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
-
-
-
-
-
-
-
- // Draw progress bar
- int progBarXbase = barRegion.x + 300;
-
- if (lenPTS == 0) return;
- rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
- rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
-
- if (currentPTS > lenPTS) return;
-
- // Draw yellow portion
- int progressWidth = 302 * currentPTS / lenPTS;
- rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-
-}
-
-void VVideoMedia::removeBar()
-{
- if (!barShowing) return;
- timers->cancelTimer(this, 2);
- barShowing = false;
- barGenHold = false;
- barScanHold = false;
- barVasHold = false;
- rectangle(barRegion, transparent);
- BoxStack::getInstance()->update(this, &barRegion);
-}
-
-void VVideoMedia::doSummary()
-{
- vsummary = new VInfo();
- vsummary->setTitleText(myMedia->getDisplayName());
- vsummary->setBorderOn(1);
- vsummary->setExitable();
- const MediaURI *u=myMedia->getURI();
- int stlen=0;
- if (u) {
- stlen+=strlen(myMedia->getFileName());
- stlen+=strlen(tr("FileName"))+10;
- }
- stlen+=strlen(tr("Size"))+50;
- stlen+=strlen(tr("Directory"))+500;
- stlen+=strlen(tr("Time"))+50;
- char *pinfo=player->getInfo();
- stlen+=strlen(pinfo)+10;
- char *buf=new char [stlen];
- char *tsbuf=new char [stlen];
- char *tsbuf2=new char [stlen];
- char *tbuf=new char[Media::TIMEBUFLEN];
- SNPRINTF(buf,stlen,"%s\n"
- "%s: %llu Bytes\n"
- "%s\n"
- "%s: %s\n"
- "%s",
- shortendedText(tr("FileName"),": ",myMedia->getFileName(),tsbuf,vsummary->getWidth()),
- tr("Size"),
- lengthBytes,
- shortendedText(tr("Directory"),": ",lparent->getDirname(MEDIA_TYPE_VIDEO),tsbuf2,vsummary->getWidth()),
- tr("Time"),
- myMedia->getTimeString(tbuf),
- pinfo
- );
- //TODO more info
- if (u) {
- Log::getInstance()->log("VVideoMedia",Log::DEBUG,"info %s",buf);
- vsummary->setMainText(buf);
- }
- else vsummary->setMainText(tr("Info unavailable"));
- delete pinfo;
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- vsummary->setPosition(70, 100);
- }
- else
- {
- vsummary->setPosition(40, 70);
- }
- vsummary->setSize(580, 350);
- add(vsummary);
- vsummary->draw();
-
- BoxStack::getInstance()->update(this);
- delete [] buf;
- delete [] tsbuf;
- delete [] tsbuf2;
- delete [] tbuf;
-}
-
-void VVideoMedia::removeSummary()
-{
- if (vsummary)
- {
- remove(vsummary);
- delete vsummary;
- vsummary = NULL;
- draw();
- BoxStack::getInstance()->update(this);
- }
-}
-
-
-hmsf VVideoMedia::ptsToHMS(ULLONG pts) {
- ULLONG secs=pts/90000;
- hmsf rt;
- rt.frames=0;
- rt.seconds=secs%60;
- secs=secs/60;
- rt.minutes=secs%60;
- secs=secs/60;
- rt.hours=secs;
- return rt;
-}
-
-char * VVideoMedia::shortendedText(const char * title, const char * title2,const char * intext,char *buffer,UINT width) {
- if (! intext) {
- intext="";
- }
- UINT twidth=0;
- for (const char *p=title;*p!=0;p++) twidth+=charWidth(*p);
- for (const char *p=title2;*p!=0;p++) twidth+=charWidth(*p);
- const char *prfx="...";
- UINT prfwidth=3*charWidth('.');
- const char *istart=intext+strlen(intext);
- UINT iwidth=0;
- while (twidth+iwidth+prfwidth < width-2*paraMargin && istart> intext) {
- istart--;
- iwidth+=charWidth(*istart);
- }
- if (twidth+iwidth+prfwidth >= width-2*paraMargin && istart < intext+strlen(intext)) istart++;
- if (istart == intext) prfx="";
- sprintf(buffer,"%s%s%s%s",title,title2,prfx,intext);
- return buffer;
-}
-
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vvideomedia.h"\r
+#include "vmedialist.h"\r
+#include "media.h"\r
+#include "mediaplayer.h"\r
+\r
+#include "command.h"\r
+#include "osd.h"\r
+#include "wsymbol.h"\r
+#include "audio.h"\r
+#include "video.h"\r
+#include "timers.h"\r
+#include "playermedia.h"\r
+#include "recording.h"\r
+#include "vaudioselector.h"\r
+#include "message.h"\r
+#include "remote.h"\r
+#include "boxstack.h"\r
+#include "vinfo.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+#include "recinfo.h"\r
+\r
+//use the picture channel\r
+#define MEDIACHANNEL 1\r
+\r
+//we misuse PLAYER_EVENTS for timer messages\r
+//this should be larger then any player message\r
+#define PLAYER_TIMER_BASE 100\r
+\r
+VVideoMedia::VVideoMedia(Media* media, VMediaList *p)\r
+{\r
+ lparent=p;\r
+ boxstack = BoxStack::getInstance();\r
+ video = Video::getInstance();\r
+ timers = Timers::getInstance();\r
+ vas = NULL;\r
+ vsummary = NULL;\r
+ lengthBytes=0;\r
+ myMedia = new Media(media);\r
+\r
+ player = new PlayerMedia(this);\r
+ player->run();\r
+\r
+ videoMode = video->getMode();\r
+\r
+ playing = false;\r
+\r
+\r
+ setSize(video->getScreenWidth(), video->getScreenHeight());\r
+ createBuffer();\r
+ transparent.set(0, 0, 0, 0);\r
+ setBackgroundColour(transparent);\r
+\r
+ barRegion.x = 0;\r
+ barRegion.y = video->getScreenHeight() - 58; // FIXME, need to be - 1? and below?\r
+ barRegion.w = video->getScreenWidth();\r
+ barRegion.h = 58;\r
+\r
+ clocksRegion.x = barRegion.x + 140;\r
+ clocksRegion.y = barRegion.y + 12;\r
+ clocksRegion.w = 170;\r
+ clocksRegion.h = getFontHeight();\r
+\r
+\r
+ barBlue.set(0, 0, 150, 150);\r
+\r
+ barShowing = false;\r
+ barGenHold = false;\r
+ barScanHold = false;\r
+ barVasHold = false;\r
+\r
+ dowss = false;\r
+ char* optionWSS = VDR::getInstance()->configLoad("General", "WSS");\r
+ if (optionWSS)\r
+ {\r
+ if (strstr(optionWSS, "Yes")) dowss = true;\r
+ delete[] optionWSS;\r
+ }\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Do WSS: %u", dowss);\r
+\r
+ if (dowss)\r
+ {\r
+ wss.setFormat(video->getFormat());\r
+ wss.setWide(true);\r
+ add(&wss);\r
+\r
+ wssRegion.x = 0;\r
+ wssRegion.y = 0;\r
+ wssRegion.w = video->getScreenWidth();\r
+ wssRegion.h = 300;\r
+ }\r
+}\r
+\r
+VVideoMedia::~VVideoMedia()\r
+{\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Entering destructor");\r
+\r
+ if (vas)\r
+ {\r
+ boxstack->remove(vas);\r
+ vas = NULL;\r
+ }\r
+\r
+ if (vsummary) {\r
+ remove(vsummary);\r
+ delete vsummary;\r
+ }\r
+\r
+ if (playing) stopPlay();\r
+ video->setDefaultAspect();\r
+\r
+ timers->cancelTimer(this, 1);\r
+ timers->cancelTimer(this, 2);\r
+\r
+ delete myMedia;\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "shutting down player");\r
+ player->shutdown();\r
+ delete player;\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "deleted");\r
+}\r
+\r
+void VVideoMedia::go(bool resume)\r
+{\r
+ ULONG startFrameNum=0;\r
+\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Starting stream: %s at frame: %lu", myMedia->getFileName(), startFrameNum);\r
+\r
+ lengthBytes = 0;\r
+\r
+ int rt=0;\r
+ const MediaURI *u=myMedia->getURI();\r
+ if (!u) {\r
+ Log::getInstance()->log("VVideoMedia", Log::ERR, "stream: %s has no URI", myMedia->getFileName());\r
+ rt=-1;\r
+ }\r
+ else {\r
+ rt=MediaPlayer::getInstance()->openMedium(MEDIACHANNEL,u,&lengthBytes,area.w,area.h);\r
+ }\r
+ if (rt==0)\r
+ {\r
+ //TODO: figure out len in frames\r
+ int seq=player->playNew(MEDIACHANNEL,lengthBytes,0);\r
+ int ok=player->waitForSequence(2,seq);\r
+ if (ok < 0) rt=-1; \r
+ else {\r
+ playing = true;\r
+ doBar(0);\r
+ }\r
+ }\r
+ if (rt != 0)\r
+ {\r
+ stopPlay(); // clean up\r
+\r
+ Message* m = new Message();\r
+ m->message = Message::CLOSE_ME;\r
+ m->from = this;\r
+ m->to = boxstack;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+\r
+ VInfo* vi = new VInfo();\r
+ vi->setSize(400, 150);\r
+ vi->createBuffer();\r
+ if (video->getFormat() == Video::PAL)\r
+ vi->setPosition(170, 200);\r
+ else\r
+ vi->setPosition(160, 150);\r
+ vi->setExitable();\r
+ vi->setBorderOn(1);\r
+ vi->setTitleBarOn(0);\r
+ vi->setOneLiner(tr("Error playing media"));\r
+ vi->draw();\r
+\r
+ m = new Message();\r
+ m->message = Message::ADD_VIEW;\r
+ m->to = boxstack;\r
+ m->parameter = (ULONG)vi;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ }\r
+}\r
+\r
+int VVideoMedia::handleCommand(int command)\r
+{\r
+ switch(command)\r
+ {\r
+ case Remote::PLAY:\r
+ {\r
+ player->play();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+\r
+ case Remote::BACK:\r
+ {\r
+ if (vsummary)\r
+ {\r
+ removeSummary();\r
+ return 2;\r
+ }\r
+ } // DROP THROUGH\r
+ case Remote::STOP:\r
+ case Remote::MENU:\r
+ {\r
+ if (playing) stopPlay();\r
+\r
+ return 4;\r
+ }\r
+ case Remote::PAUSE:\r
+ {\r
+ player->pause();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+ case Remote::SKIPFORWARD:\r
+ {\r
+ doBar(3);\r
+ player->skipForward(60);\r
+ return 2;\r
+ }\r
+ case Remote::SKIPBACK:\r
+ {\r
+ doBar(4);\r
+ player->skipBackward(60);\r
+ return 2;\r
+ }\r
+ case Remote::FORWARD:\r
+ {\r
+ player->fastForward();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+ case Remote::REVERSE:\r
+ {\r
+ player->fastBackward();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+ case Remote::RED:\r
+ {\r
+ if (vsummary) removeSummary();\r
+ else doSummary();\r
+ return 2;\r
+ }\r
+ case Remote::GREEN:\r
+ {\r
+ doAudioSelector();\r
+ return 2;\r
+ }\r
+ case Remote::YELLOW:\r
+ {\r
+ doBar(2);\r
+ player->skipBackward(10);\r
+ return 2;\r
+ }\r
+ case Remote::BLUE:\r
+ {\r
+ doBar(1);\r
+ player->skipForward(10);\r
+ return 2;\r
+ }\r
+ case Remote::STAR:\r
+ {\r
+ doBar(2);\r
+ player->skipBackward(10);\r
+ return 2;\r
+ }\r
+ case Remote::HASH:\r
+ {\r
+ doBar(1);\r
+ player->skipForward(10);\r
+ return 2;\r
+ }\r
+ case Remote::FULL:\r
+ case Remote::TV:\r
+ {\r
+ toggleChopSides();\r
+ return 2;\r
+ }\r
+\r
+ case Remote::OK:\r
+ {\r
+ if (vsummary)\r
+ {\r
+ removeSummary();\r
+ return 2;\r
+ }\r
+ \r
+ if (barShowing) removeBar();\r
+ else {\r
+ doBar(0);\r
+ barGenHold=true;\r
+ }\r
+ return 2;\r
+ }\r
+\r
+ case Remote::ZERO: player->jumpToPercent(0); doBar(0); return 2;\r
+ case Remote::ONE: player->jumpToPercent(10); doBar(0); return 2;\r
+ case Remote::TWO: player->jumpToPercent(20); doBar(0); return 2;\r
+ case Remote::THREE: player->jumpToPercent(30); doBar(0); return 2;\r
+ case Remote::FOUR: player->jumpToPercent(40); doBar(0); return 2;\r
+ case Remote::FIVE: player->jumpToPercent(50); doBar(0); return 2;\r
+ case Remote::SIX: player->jumpToPercent(60); doBar(0); return 2;\r
+ case Remote::SEVEN: player->jumpToPercent(70); doBar(0); return 2;\r
+ case Remote::EIGHT: player->jumpToPercent(80); doBar(0); return 2;\r
+ case Remote::NINE: player->jumpToPercent(90); doBar(0); return 2;\r
+\r
+\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+void VVideoMedia::processMessage(Message* m)\r
+{\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Message received");\r
+\r
+ if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ UINT x = (m->parameter>>16) - getScreenX();\r
+ UINT y = (m->parameter&0xFFFF) - getScreenY();\r
+\r
+ if (!barShowing)\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+ }\r
+ else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)\r
+ {\r
+ int progBarXbase = barRegion.x + 300;\r
+ if (x>=barRegion.x + progBarXbase + 24\r
+ && x<=barRegion.x + progBarXbase + 4 + 302\r
+ && y>=barRegion.y + 12 - 2\r
+ && y<=barRegion.y + 12 - 2+28)\r
+ {\r
+ int cx=x-(barRegion.x + progBarXbase + 4);\r
+ double percent=((double)cx)/302.*100.;\r
+ player->jumpToPercent(percent);\r
+ doBar(3);\r
+ return;\r
+ // int progressWidth = 302 * currentFrameNum / lengthFrames;\r
+ // rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+ }\r
+ }\r
+ else if (m->message == Message::PLAYER_EVENT)\r
+ {\r
+ switch(m->parameter)\r
+ {\r
+ case PlayerMedia::CONNECTION_LOST: // connection lost detected\r
+ {\r
+ // I can't handle this, send it to command\r
+ Message* m2 = new Message();\r
+ m2->to = Command::getInstance();\r
+ m2->message = Message::CONNECTION_LOST;\r
+ Command::getInstance()->postMessageNoLock(m2);\r
+ break;\r
+ }\r
+ case PlayerMedia::STREAM_END:\r
+ {\r
+ Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+ m2->to = BoxStack::getInstance();\r
+ m2->message = Message::CLOSE_ME;\r
+ Command::getInstance()->postMessageNoLock(m2);\r
+ break;\r
+ }\r
+ case PlayerMedia::STATUS_CHANGE:\r
+ doBar(0);\r
+ break;\r
+ case PlayerMedia::ASPECT43:\r
+ {\r
+ if (dowss)\r
+ {\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 43");\r
+ wss.setWide(false);\r
+ wss.draw();\r
+ boxstack->update(this, &wssRegion);\r
+ }\r
+ break;\r
+ }\r
+ case PlayerMedia::ASPECT169:\r
+ {\r
+ if (dowss)\r
+ {\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 169");\r
+ wss.setWide(true);\r
+ wss.draw();\r
+ boxstack->update(this, &wssRegion);\r
+ }\r
+ break;\r
+ }\r
+ case (PLAYER_TIMER_BASE+1) :\r
+ //timer1:\r
+ // Remove bar\r
+ removeBar();\r
+ break;\r
+ case (PLAYER_TIMER_BASE+2) :\r
+ //timer2:\r
+ // Update clock\r
+ if (!barShowing) break;\r
+ drawBarClocks();\r
+ BoxStack::getInstance()->update(this,&barRegion);\r
+ if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);\r
+ else timers->setTimerD(this, 2, 1);\r
+ break;\r
+ }\r
+ }\r
+ else if (m->message == Message::AUDIO_CHANGE_CHANNEL)\r
+ {\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received change audio channel to %i", m->parameter);\r
+ player->setAudioChannel(m->parameter);\r
+ }\r
+ else if (m->message == Message::CHILD_CLOSE)\r
+ {\r
+ if (m->from == vas)\r
+ {\r
+ vas = NULL;\r
+ barVasHold = false;\r
+ if (!barGenHold && !barScanHold && !barVasHold) removeBar();\r
+ }\r
+ }\r
+}\r
+\r
+void VVideoMedia::stopPlay()\r
+{\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Pre stopPlay");\r
+\r
+ removeBar();\r
+\r
+ player->stop();\r
+\r
+ playing = false;\r
+ MediaPlayer::getInstance()->closeMediaChannel(MEDIACHANNEL);\r
+\r
+ Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Post stopPlay");\r
+}\r
+\r
+void VVideoMedia::toggleChopSides()\r
+{\r
+ if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs\r
+\r
+ if (videoMode == Video::NORMAL)\r
+ {\r
+ videoMode = Video::LETTERBOX;\r
+ video->setMode(Video::LETTERBOX);\r
+ }\r
+ else\r
+ {\r
+ videoMode = Video::NORMAL;\r
+ video->setMode(Video::NORMAL);\r
+ }\r
+}\r
+\r
+void VVideoMedia::doAudioSelector()\r
+{\r
+ bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();\r
+ bool* availableAc3AudioChannels = 0;\r
+ int currentAudioChannel = player->getCurrentAudioChannel();\r
+ if (Audio::getInstance()->supportsAc3())\r
+ {\r
+ availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();\r
+ }\r
+\r
+\r
+ RecInfo ri;\r
+ ri.summary=new char[strlen(myMedia->getDisplayName())+1];\r
+ strcpy(ri.summary,myMedia->getDisplayName());\r
+ vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, NULL,NULL,0,0, &ri);\r
+ \r
+ vas->setBackgroundColour(barBlue);\r
+ vas->setPosition(0, barRegion.y - 120);\r
+\r
+// pal 62, ntsc 57\r
+\r
+ barVasHold = true;\r
+ doBar(0);\r
+\r
+ vas->draw();\r
+ boxstack->add(vas);\r
+ boxstack->update(vas);\r
+}\r
+\r
+void VVideoMedia::doBar(int action)\r
+{\r
+ Log::getInstance()->log("VVideoMedia",Log::DEBUG,"doBar %d",action);\r
+ barShowing = true;\r
+\r
+ rectangle(barRegion, barBlue);\r
+\r
+ /* Work out what to display - choices:\r
+\r
+ Playing >\r
+ Paused ||\r
+ FFwd >>\r
+ FBwd <<\r
+\r
+ Specials, informed by parameter\r
+\r
+ Skip forward 10s >|\r
+ Skip backward 10s |<\r
+ Skip forward 1m >>|\r
+ Skip backward 1m |<<\r
+\r
+ */\r
+\r
+ WSymbol w;\r
+ TEMPADD(&w);\r
+ w.nextSymbol = 0;\r
+ w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
+\r
+ UCHAR playerState = 0;\r
+\r
+ if (action)\r
+ {\r
+ if (action == 1) w.nextSymbol = WSymbol::SKIPFORWARD;\r
+ else if (action == 2) w.nextSymbol = WSymbol::SKIPBACK;\r
+ else if (action == 3) w.nextSymbol = WSymbol::SKIPFORWARD2;\r
+ else if (action == 4) w.nextSymbol = WSymbol::SKIPBACK2;\r
+ }\r
+ else\r
+ {\r
+ playerState = player->getState();\r
+ if (playerState == PlayerMedia::S_PLAY) w.nextSymbol = WSymbol::PLAY;\r
+ else if (playerState == PlayerMedia::S_FF) w.nextSymbol = WSymbol::FFWD;\r
+ else if (playerState == PlayerMedia::S_BACK) w.nextSymbol = WSymbol::FBWD;\r
+ else if (playerState == PlayerMedia::S_SEEK) w.nextSymbol = WSymbol::RIGHTARROW;\r
+ else if (playerState == PlayerMedia::S_STOP) w.nextSymbol = WSymbol::PAUSE;\r
+ else w.nextSymbol = WSymbol::PAUSE;\r
+ }\r
+\r
+ w.draw();\r
+\r
+ if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK))\r
+ {\r
+ // draw blips to show how fast the scan is\r
+ UCHAR scanrate = 2;//player->getIScanRate();\r
+ if (scanrate >= 2)\r
+ {\r
+ char text[5];\r
+ SNPRINTF(text, 5, "%ux", scanrate);\r
+ drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);\r
+ }\r
+ }\r
+\r
+ drawBarClocks();\r
+ boxstack->update(this, &barRegion);\r
+\r
+ timers->cancelTimer(this, 1);\r
+\r
+\r
+ if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK)) barScanHold = true;\r
+ else barScanHold = false;\r
+\r
+ if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);\r
+\r
+ if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);\r
+ else timers->setTimerD(this, 2, 1);\r
+}\r
+\r
+void VVideoMedia::timercall(int clientReference)\r
+{\r
+ Message *m=new Message();\r
+ m->message=Message::PLAYER_EVENT;\r
+ m->to=this;\r
+ m->from=this;\r
+ m->parameter=PLAYER_TIMER_BASE+clientReference;\r
+ Command::getInstance()->postMessageFromOuterSpace(m);\r
+}\r
+\r
+void VVideoMedia::drawBarClocks()\r
+{\r
+ if (barScanHold)\r
+ {\r
+ UCHAR playerState = player->getState();\r
+ // sticky bar is set if we are in ffwd/fbwd mode\r
+ // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which\r
+ // will repaint all the bar (it will call this function again, but\r
+ // this section won't run because stickyBarF will then == false)\r
+\r
+ if ((playerState != PlayerMedia::S_FF) && (playerState != PlayerMedia::S_BACK))\r
+ {\r
+ barScanHold = false;\r
+ doBar(0);\r
+ return; \r
+ }\r
+ }\r
+\r
+ Log* logger = Log::getInstance();\r
+ logger->log("VVideoMedia", Log::DEBUG, "Draw bar clocks");\r
+\r
+ // Draw RTC\r
+ // Blank the area first\r
+ rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
+ char timeString[20];\r
+ time_t t;\r
+ time(&t);\r
+ struct tm* tms = localtime(&t);\r
+ strftime(timeString, 19, "%H:%M", tms);\r
+ drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);\r
+\r
+ ULLONG lenPTS=player->getLenPTS();\r
+ // Draw clocks\r
+\r
+ rectangle(clocksRegion, barBlue);\r
+\r
+ ULLONG currentPTS = player->getCurrentPTS();\r
+\r
+ hmsf currentFrameHMSF = ptsToHMS(currentPTS);\r
+ hmsf lengthHMSF = ptsToHMS(lenPTS);\r
+\r
+ char buffer[100];\r
+ if (currentPTS > lenPTS && lenPTS != 0)\r
+ {\r
+ strcpy(buffer, "-:--:-- / -:--:--");\r
+ }\r
+ else\r
+ {\r
+ SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
+ }\r
+ logger->log("VVideoMedia", Log::DEBUG, "cur %llu,len %llu, txt %s",currentPTS,lenPTS,buffer);\r
+\r
+ drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ // Draw progress bar\r
+ int progBarXbase = barRegion.x + 300;\r
+\r
+ if (lenPTS == 0) return;\r
+ rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);\r
+ rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
+\r
+ if (currentPTS > lenPTS) return;\r
+\r
+ // Draw yellow portion\r
+ int progressWidth = 302 * currentPTS / lenPTS;\r
+ rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+\r
+}\r
+\r
+void VVideoMedia::removeBar()\r
+{\r
+ if (!barShowing) return;\r
+ timers->cancelTimer(this, 2);\r
+ barShowing = false;\r
+ barGenHold = false;\r
+ barScanHold = false;\r
+ barVasHold = false;\r
+ rectangle(barRegion, transparent);\r
+ BoxStack::getInstance()->update(this, &barRegion);\r
+}\r
+\r
+void VVideoMedia::doSummary()\r
+{\r
+ vsummary = new VInfo();\r
+ vsummary->setTitleText(myMedia->getDisplayName());\r
+ vsummary->setBorderOn(1);\r
+ vsummary->setExitable();\r
+ const MediaURI *u=myMedia->getURI();\r
+ int stlen=0;\r
+ if (u) {\r
+ stlen+=strlen(myMedia->getFileName());\r
+ stlen+=strlen(tr("FileName"))+10;\r
+ }\r
+ stlen+=strlen(tr("Size"))+50;\r
+ stlen+=strlen(tr("Directory"))+500;\r
+ stlen+=strlen(tr("Time"))+50;\r
+ char *pinfo=player->getInfo();\r
+ stlen+=strlen(pinfo)+10;\r
+ char *buf=new char [stlen];\r
+ char *tsbuf=new char [stlen];\r
+ char *tsbuf2=new char [stlen];\r
+ char *tbuf=new char[Media::TIMEBUFLEN];\r
+ SNPRINTF(buf,stlen,"%s\n" \r
+ "%s: %llu Bytes\n"\r
+ "%s\n"\r
+ "%s: %s\n"\r
+ "%s",\r
+ shortendedText(tr("FileName"),": ",myMedia->getFileName(),tsbuf,vsummary->getWidth()),\r
+ tr("Size"),\r
+ lengthBytes,\r
+ shortendedText(tr("Directory"),": ",lparent->getDirname(MEDIA_TYPE_VIDEO),tsbuf2,vsummary->getWidth()),\r
+ tr("Time"),\r
+ myMedia->getTimeString(tbuf),\r
+ pinfo\r
+ );\r
+ //TODO more info\r
+ if (u) {\r
+ Log::getInstance()->log("VVideoMedia",Log::DEBUG,"info %s",buf);\r
+ vsummary->setMainText(buf);\r
+ }\r
+ else vsummary->setMainText(tr("Info unavailable"));\r
+ delete pinfo;\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ vsummary->setPosition(70, 100);\r
+ }\r
+ else\r
+ {\r
+ vsummary->setPosition(40, 70);\r
+ }\r
+ vsummary->setSize(580, 350);\r
+ add(vsummary);\r
+ vsummary->draw();\r
+\r
+ BoxStack::getInstance()->update(this);\r
+ delete [] buf;\r
+ delete [] tsbuf;\r
+ delete [] tsbuf2;\r
+ delete [] tbuf;\r
+}\r
+\r
+void VVideoMedia::removeSummary()\r
+{\r
+ if (vsummary)\r
+ {\r
+ remove(vsummary);\r
+ delete vsummary;\r
+ vsummary = NULL;\r
+ draw();\r
+ BoxStack::getInstance()->update(this);\r
+ }\r
+}\r
+\r
+\r
+hmsf VVideoMedia::ptsToHMS(ULLONG pts) {\r
+ ULLONG secs=pts/90000;\r
+ hmsf rt;\r
+ rt.frames=0;\r
+ rt.seconds=secs%60;\r
+ secs=secs/60;\r
+ rt.minutes=secs%60;\r
+ secs=secs/60;\r
+ rt.hours=secs;\r
+ return rt;\r
+}\r
+ \r
+char * VVideoMedia::shortendedText(const char * title, const char * title2,const char * intext,char *buffer,UINT width) {\r
+ if (! intext) {\r
+ intext="";\r
+ }\r
+ UINT twidth=0;\r
+ for (const char *p=title;*p!=0;p++) twidth+=charWidth(*p);\r
+ for (const char *p=title2;*p!=0;p++) twidth+=charWidth(*p);\r
+ const char *prfx="...";\r
+ UINT prfwidth=3*charWidth('.');\r
+ const char *istart=intext+strlen(intext);\r
+ UINT iwidth=0;\r
+ while (twidth+iwidth+prfwidth < width-2*paraMargin && istart> intext) {\r
+ istart--;\r
+ iwidth+=charWidth(*istart);\r
+ }\r
+ if (twidth+iwidth+prfwidth >= width-2*paraMargin && istart < intext+strlen(intext)) istart++;\r
+ if (istart == intext) prfx="";\r
+ sprintf(buffer,"%s%s%s%s",title,title2,prfx,intext);\r
+ return buffer;\r
+}\r
+\r
+\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include <math.h>
-
-#include "vvideorec.h"
-#include "vteletextview.h"
-
-#include "command.h"
-#include "osd.h"
-#include "wsymbol.h"
-#include "audio.h"
-#include "vdr.h"
-#include "video.h"
-#include "timers.h"
-#include "player.h"
-#include "recording.h"
-#include "vaudioselector.h"
-#include "message.h"
-#include "remote.h"
-#include "boxstack.h"
-#include "vinfo.h"
-#include "i18n.h"
-#include "bitmap.h"
-#include "recinfo.h"
-#include "log.h"
-#include "channel.h"
-
-VVideoRec::VVideoRec(Recording* rec, bool ish264)
-{
- boxstack = BoxStack::getInstance();
- vdr = VDR::getInstance();
- video = Video::getInstance();
- timers = Timers::getInstance();
- vas = NULL;
- vsummary = NULL;
-
- videoMode = video->getMode();
- myRec = rec;
-
- video->seth264mode(ish264);
-
- player = new Player(Command::getInstance(), this, this);
- player->init(myRec->IsPesRecording,myRec->recInfo->fps);
-
- playing = false;
-
- startMargin = 0;
- endMargin = 0;
- char* cstartMargin = vdr->configLoad("Timers", "Start margin");
- char* cendMargin = vdr->configLoad("Timers", "End margin");
- if (!cstartMargin)
- {
- startMargin = 300; // 5 mins default
- }
- else
- {
- startMargin = atoi(cstartMargin) * 60;
- delete[] cstartMargin;
- }
-
- if (!cendMargin)
- {
- endMargin = 300; // 5 mins default
- }
- else
- {
- endMargin = atoi(cendMargin) * 60;
- delete[] cendMargin;
- }
-
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);
-
- setSize(video->getScreenWidth(), video->getScreenHeight());
- createBuffer();
- transparent.set(0, 0, 0, 0);
- setBackgroundColour(transparent);
-
- barRegion.x = 0;
- barRegion.y = video->getScreenHeight() - 58; // FIXME, need to be - 1? and below?
- barRegion.w = video->getScreenWidth();
- barRegion.h = 58;
-
- clocksRegion.x = barRegion.x + 140;
- clocksRegion.y = barRegion.y + 12;
- clocksRegion.w = 170;
- clocksRegion.h = surface->getFontHeight();
-// barBlue.set(0, 0, 150, 150);
- barBlue.set(0, 0, 0, 128);
-
- barShowing = false;
- barGenHold = false;
- barScanHold = false;
- barVasHold = false;
-
- dowss = false;
- char* optionWSS = vdr->configLoad("General", "WSS");
- if (optionWSS)
- {
- if (strstr(optionWSS, "Yes")) dowss = true;
- delete[] optionWSS;
- }
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Do WSS: %u", dowss);
-
- if (dowss)
- {
- wss.setFormat(video->getFormat());
- wss.setWide(true);
- add(&wss);
-
- wssRegion.x = 0;
- wssRegion.y = 0;
- wssRegion.w = video->getScreenWidth();
- wssRegion.h = 300;
- }
-}
-
-void VVideoRec::preDelete()
-{
- timers->cancelTimer(this, 1);
- timers->cancelTimer(this, 2);
-
- if (vas)
- {
- boxstack->remove(vas);
- vas = NULL;
- }
-
- if (vsummary) delete vsummary;
-
- if (playing) stopPlay();
-}
-
-VVideoRec::~VVideoRec()
-{
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Entering vvideorec destructor");
-
- video->setDefaultAspect();
-
- // kill recInfo in case resumePoint has changed (likely)
- myRec->dropRecInfo();
- // FIXME - do this properly - save the resume point back to the server manually and update
- // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well
-}
-
-void VVideoRec::go(bool resume)
-{
- ULONG startFrameNum;
- if (resume)
- startFrameNum = myRec->recInfo->resumePoint;
- else
- startFrameNum = 0;
-
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Starting stream: %s at frame: %lu", myRec->getFileName(), startFrameNum);
- ULONG lengthFrames = 0;
- bool isPesRecording;
- ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);
- myRec->IsPesRecording = isPesRecording;
- if (lengthBytes)
- {
- player->setLengthBytes(lengthBytes);
- player->setLengthFrames(lengthFrames);
- player->setStartFrame(startFrameNum);
- player->play();
- playing = true;
- doBar(0);
- }
- else
- {
- stopPlay(); // clean up
-
- if (!vdr->isConnected())
- {
- Command::getInstance()->connectionLost();
- return;
- }
-
- Message* m = new Message();
- m->message = Message::CLOSE_ME;
- m->from = this;
- m->to = boxstack;
- Command::getInstance()->postMessageNoLock(m);
-
- VInfo* vi = new VInfo();
- vi->setSize(400, 150);
- vi->createBuffer();
- if (video->getFormat() == Video::PAL)
- vi->setPosition(170, 200);
- else
- vi->setPosition(160, 150);
- vi->setExitable();
- vi->setBorderOn(1);
- vi->setTitleBarOn(0);
- vi->setOneLiner(tr("Error playing recording"));
- vi->draw();
-
- m = new Message();
- m->message = Message::ADD_VIEW;
- m->to = boxstack;
- m->parameter = (ULONG)vi;
- Command::getInstance()->postMessageNoLock(m);
- }
-}
-
-int VVideoRec::handleCommand(int command)
-{
- switch(command)
- {
- case Remote::PLAY:
- {
- player->play();
- doBar(0);
- return 2;
- }
-
- case Remote::BACK:
- {
- if (vsummary)
- {
- removeSummary();
- return 2;
- }
- } // DROP THROUGH
- case Remote::STOP:
- case Remote::MENU:
- {
- if (playing) stopPlay();
-
- return 4;
- }
- case Remote::PAUSE:
- {
- player->pause();
- doBar(0);
- return 2;
- }
- case Remote::SKIPFORWARD:
- {
- doBar(3);
- player->skipForward(60);
- return 2;
- }
- case Remote::SKIPBACK:
- {
- doBar(4);
- player->skipBackward(60);
- return 2;
- }
- case Remote::FORWARD:
- {
- player->fastForward();
- doBar(0);
- return 2;
- }
- case Remote::REVERSE:
- {
- player->fastBackward();
- doBar(0);
- return 2;
- }
- case Remote::RED:
- {
- if (vsummary) removeSummary();
- else doSummary();
- return 2;
- }
- case Remote::GREEN:
- {
- doAudioSelector();
- return 2;
- }
- case Remote::YELLOW:
- {
- if (myRec->hasMarks())
- {
- // skip to previous mark
- Log* logger = Log::getInstance();
- int currentFrame = (player->getCurrentFrameNum()); // get current Frame
- currentFrame -= 5. * myRec->recInfo->fps; // subtrack 5 seconds, else you cannot skip more than once back ..
-
- int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame
- if (prevMark)
- {
- logger->log("VVideoRec", Log::NOTICE, "jump back from pos %i to mark at %i",currentFrame,prevMark);
- player->jumpToMark(prevMark);
- }
- doBar(4);
- }
- else
- {
- doBar(2);
- player->skipBackward(10);
- }
- return 2;
- }
- case Remote::BLUE:
- {
- if (myRec->hasMarks())
- {
- // skip to next mark
- Log* logger = Log::getInstance();
- int currentFrame = (player->getCurrentFrameNum());
-
- int nextMark = myRec->getNextMark(currentFrame);
-
- if (nextMark)
- {
- logger->log("VVideoRec", Log::NOTICE, "jump forward from pos %i to mark at %i",currentFrame,nextMark);
- player->jumpToMark(nextMark);
- }
- doBar(3);
- }
- else
- {
- doBar(1);
- player->skipForward(10);
- }
- return 2;
- }
- case Remote::STAR:
- {
- doBar(2);
- player->skipBackward(10);
- return 2;
- }
- case Remote::HASH:
- {
- doBar(1);
- player->skipForward(10);
- return 2;
- }
- case Remote::FULL:
- case Remote::TV:
- {
- toggleChopSides();
- return 2;
- }
-
- case Remote::OK:
- {
- if (vsummary)
- {
- removeSummary();
- return 2;
- }
-
- if (barShowing) removeBar();
- else doBar(0);
- return 2;
- }
-
- case Remote::ZERO: player->jumpToPercent(0); doBar(0); return 2;
- case Remote::ONE: player->jumpToPercent(10); doBar(0); return 2;
- case Remote::TWO: player->jumpToPercent(20); doBar(0); return 2;
- case Remote::THREE: player->jumpToPercent(30); doBar(0); return 2;
- case Remote::FOUR: player->jumpToPercent(40); doBar(0); return 2;
- case Remote::FIVE: player->jumpToPercent(50); doBar(0); return 2;
- case Remote::SIX: player->jumpToPercent(60); doBar(0); return 2;
- case Remote::SEVEN: player->jumpToPercent(70); doBar(0); return 2;
- case Remote::EIGHT: player->jumpToPercent(80); doBar(0); return 2;
- case Remote::NINE: player->jumpToPercent(90); doBar(0); return 2;
-
- case Remote::RECORD: player->toggleSubtitles(); return 2;
-#ifdef DEV
-// case Remote::RED:
-// {
- //Don't use RED for anything. It will eventually be recording summary
-
- //player->test1();
-
-
- /*
- // for testing EPG in NTSC with a NTSC test video
- Video::getInstance()->setMode(Video::QUARTER);
- Video::getInstance()->setPosition(170, 5);
- VEpg* vepg = new VEpg(NULL, 0);
- vepg->draw();
- BoxStack::getInstance()->add(vepg);
- BoxStack::getInstance()->update(vepg);
- */
-
-// return 2;
-// }
-
-#endif
-
- }
-
- return 1;
-}
-
-void VVideoRec::doTeletext()
-{
-
- bool exists=true;
-
-
- // Draw the teletxt
- VTeletextView *vtxv=player->getTeletextDecoder()->getTeletxtView();
- if (vtxv==NULL) {
- vtxv= new VTeletextView((player)->getTeletextDecoder(),this);
- (player)->getTeletextDecoder()->registerTeletextView(vtxv);
- exists=false;
- }
- vtxv->setSubtitleMode(true);
- vtxv->draw();
- draw();
-
- if (!exists) {
- BoxStack::getInstance()->add(vtxv);
- }
- BoxStack::getInstance()->update(this);
- BoxStack::getInstance()->update(vtxv);
-}
-
-void VVideoRec::processMessage(Message* m)
-{
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");
-
- if (m->message == Message::MOUSE_LBDOWN)
- {
- UINT x = (m->parameter>>16) - getScreenX();
- UINT y = (m->parameter&0xFFFF) - getScreenY();
-
- if (!barShowing)
- {
- BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
- }
- else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
- {
- int progBarXbase = barRegion.x + 300;
- if (myRec->hasMarks())
- {
- MarkList* markList = myRec->getMarkList();
- MarkList::iterator i;
- Mark* loopMark = NULL;
- int posPix;
- ULONG lengthFrames;
- if (myRec->recInfo->timerEnd > time(NULL))
- {
- // chasing playback
- // Work out an approximate length in frames (good to 1s...)
- lengthFrames = (ULONG)((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);
- }
- else
- {
- lengthFrames = player->getLengthFrames();
- }
- for(i = markList->begin(); i != markList->end(); i++)
- {
- loopMark = *i;
- if (loopMark->pos)
- {
- posPix = 302 * loopMark->pos / lengthFrames;
- rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
- if (x>=barRegion.x + progBarXbase + 2 + posPix
- && x<=barRegion.x + progBarXbase + 2 + posPix+3
- && y>=barRegion.y + 12 - 2
- && y<=barRegion.y + 12 - 2+28)
- {
- player->jumpToMark(loopMark->pos);
- doBar(3);
- return;
- }
- }
- }
- }
-
- if (x>=barRegion.x + progBarXbase + 24
- && x<=barRegion.x + progBarXbase + 4 + 302
- && y>=barRegion.y + 12 - 2
- && y<=barRegion.y + 12 - 2+28)
- {
- int cx=x-(barRegion.x + progBarXbase + 4);
- double percent=((double)cx)/302.*100.;
- player->jumpToPercent(percent);
- doBar(3);
- return;
- // int progressWidth = 302 * currentFrameNum / lengthFrames;
- // rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
- }
- }
- else
- {
- BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
- }
- }
- else if (m->from == player)
- {
- if (m->message != Message::PLAYER_EVENT) return;
- switch(m->parameter)
- {
- case Player::CONNECTION_LOST: // connection lost detected
- {
- // I can't handle this, send it to command
- Message* m2 = new Message();
- m2->to = Command::getInstance();
- m2->message = Message::CONNECTION_LOST;
- Command::getInstance()->postMessageNoLock(m2);
- break;
- }
- case Player::STOP_PLAYBACK:
- {
- // FIXME Obselete ish - improve this
- Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
- m2->to = Command::getInstance();
- m2->message = Message::STOP_PLAYBACK;
- Command::getInstance()->postMessageNoLock(m2);
- break;
- }
- case Player::ASPECT43:
- {
- if (dowss)
- {
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
- wss.setWide(false);
- wss.draw();
- boxstack->update(this, &wssRegion);
- }
- break;
- }
- case Player::ASPECT169:
- {
- if (dowss)
- {
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
- wss.setWide(true);
- wss.draw();
- boxstack->update(this, &wssRegion);
- }
- break;
- }
- }
- }
- else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
- {
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change audio channel to %i", m->parameter);
- player->setAudioChannel(m->parameter&0xFFFF,(m->parameter&0xFF0000)>> 16 );
- }
- else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
- {
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);
- int type=((m->parameter & 0xFF0000)>>16);
- switch (type) {
- case 0x10: { //dvbsubtitle
- player->setSubtitleChannel((m->parameter & 0xFFFF));
- player->turnSubtitlesOn(true);
- VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();
- if (vtxt && vtxt->isInSubtitleMode()) {
- BoxStack::getInstance()->remove(vtxt);
- }
- } break;
- case 0xFF: { //nosubtitles
-
- player->turnSubtitlesOn(false);
- VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();
- if (vtxt && vtxt->isInSubtitleMode()) {
- BoxStack::getInstance()->remove(vtxt);
- }
-
- } break;
- case 0x11: { //videotext
- player->turnSubtitlesOn(false);
- doTeletext();
- ((Player*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
- } break;
- };
- if (vas) {
- BoxStack::getInstance()->update(vas);
- }
- BoxStack::getInstance()->update(this);
-
-
- }
- else if (m->message == Message::CHILD_CLOSE)
- {
- if (m->from == vas)
- {
- vas = NULL;
- barVasHold = false;
- if (!barGenHold && !barScanHold && !barVasHold) removeBar();
- }
- }
-}
-
-void VVideoRec::stopPlay()
-{
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Pre stopPlay");
-
- removeBar();
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "1");
- player->stop();
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "2");
- vdr->stopStreaming();
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "3");
- delete player;
-
- playing = false;
-
- if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
- Log::getInstance()->log("VVideoRec", Log::DEBUG, "Post stopPlay");
-}
-
-void VVideoRec::toggleChopSides()
-{
- if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
-
- if (videoMode == Video::NORMAL)
- {
- videoMode = Video::LETTERBOX;
- video->setMode(Video::LETTERBOX);
- }
- else
- {
- videoMode = Video::NORMAL;
- video->setMode(Video::NORMAL);
- }
-}
-
-void VVideoRec::doAudioSelector()
-{
- int subtitleChannel=player->getCurrentSubtitleChannel();
- int subtitleType=0x10;
- if (!(player)->isSubtitlesOn()) {
- if ((player)->getTeletextDecoder()->getTeletxtView() &&
- (player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode()
- ) {
- subtitleChannel=(player)->getTeletextDecoder()->getPage();
- subtitleType=0x11;
-
- } else {
- subtitleType=0xFF; //turnedOff
- subtitleChannel=0;
- }
- }
- if (player->isPesRecording()) {
- bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
- bool* availableAc3AudioChannels = NULL;
- bool* availableSubtitleChannels = player->getDemuxerSubtitleChannels();
- int *availableTTxtpages = player->getTeletxtSubtitlePages();
- int currentAudioChannel = player->getCurrentAudioChannel();
- if (Audio::getInstance()->supportsAc3())
- {
- availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
- }
-
- vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel,availableSubtitleChannels, availableTTxtpages,
- subtitleChannel, subtitleType, myRec->recInfo);
- } else {
- // Draw the selector
- Channel temp_channel=player->getDemuxerChannel();
- RecInfo *cur_info= myRec->recInfo;
- unsigned char numchan_recinfo = cur_info->numComponents;
- unsigned char numchan_subtitles_siz = temp_channel.numSPids;
- ULONG mp_audcounter = 0;
- ULONG ac3_counter = 0;
- int dvb_subcounter = 1;
-
- unsigned char type;
- char* lang;
- char* description;
- int i;
- for (i = 0; i < numchan_recinfo; i++)
- {
- apid* ac = NULL;
- type = cur_info->types[i];
- lang = cur_info->languages[i];
- description = cur_info->descriptions[i];
-
-
- if (cur_info->streams[i] == 2) {
- switch (type)
- {
- case 1: //mpaudio mono
- case 3: //mpaudio stereo
- if (mp_audcounter < temp_channel.numAPids) ac = &temp_channel.apids[mp_audcounter];
-
- mp_audcounter++;
- break;
- case 5: //ac3
- if (ac3_counter < temp_channel.numDPids) ac = &temp_channel.dpids[ac3_counter];
- ac3_counter++;
- break;
- }
- } else if (cur_info->streams[i] == 3){
- if (dvb_subcounter < numchan_subtitles_siz) ac = &temp_channel.spids[dvb_subcounter];
- } else continue; //neither audio nor subtitle
- if (ac)
- {
- if (description && (strlen(description) > 0))
- {
- ac->name = new char[strlen(description) + 1];
- strcpy(ac->name, description);
-
- } else if (lang && strlen(lang) > 0)
- {
- ac->name = new char[strlen(lang) + 1];
- strcpy(ac->name, lang);
-
- }
- }
- }
- for (i=0;i<temp_channel.numAPids;i++) {
- apid *ac=&temp_channel.apids[i];
- if (ac->name==NULL) {
- ac->name = new char[strlen(tr("unknown")) + 1];
- strcpy(ac->name, tr("unknown"));
- }
- }
- for (i=0;i<temp_channel.numDPids;i++) {
- apid *ac=&temp_channel.dpids[i];
- if (ac->name==NULL) {
- ac->name = new char[strlen(tr("unknown")) + 1];
- strcpy(ac->name, tr("unknown"));
- }
- }
- for (i=0;i<temp_channel.numSPids;i++) {
- apid *ac=&temp_channel.spids[i];
- if (ac->name==NULL) {
- ac->name = new char[strlen(tr("unknown")) + 1];
- strcpy(ac->name, tr("unknown"));
- }
- }
-
- vas = new VAudioSelector(this,&temp_channel , (player)->getCurrentAudioChannel(),
- subtitleType,subtitleChannel,player->getTeletxtSubtitlePages());
- for (i=0;i<temp_channel.numAPids;i++) {
- apid *ac=&temp_channel.apids[i];
- delete[] ac->name;
- ac->name=NULL;
- }
- for (i=0;i<temp_channel.numDPids;i++) {
- apid *ac=&temp_channel.dpids[i];
- delete[] ac->name;
- ac->name=NULL;
- }
- for (i=0;i<temp_channel.numSPids;i++) {
- apid *ac=&temp_channel.spids[i];
- delete[] ac->name;
- ac->name=NULL;
- }
- }
-
-
- vas->setBackgroundColour(barBlue);
- vas->setPosition(0, barRegion.y - 120);
-
-// pal 62, ntsc 57
-
- barVasHold = true;
- doBar(0);
-
- vas->draw();
- boxstack->add(vas);
- boxstack->update(vas);
-}
-
-void VVideoRec::doBar(int action)
-{
- barShowing = true;
-
- rectangle(barRegion, barBlue);
-
- /* Work out what to display - choices:
-
- Playing >
- Paused ||
- FFwd >>
- FBwd <<
-
- Specials, informed by parameter
-
- Skip forward 10s >|
- Skip backward 10s |<
- Skip forward 1m >>|
- Skip backward 1m |<<
-
- */
-
- WSymbol w;
- TEMPADD(&w);
- w.nextSymbol = 0;
- w.setPosition(barRegion.x + 66, barRegion.y + 16);
-
- UCHAR playerState = 0;
-
- if (action)
- {
- if (action == 1) w.nextSymbol = WSymbol::SKIPFORWARD;
- else if (action == 2) w.nextSymbol = WSymbol::SKIPBACK;
- else if (action == 3) w.nextSymbol = WSymbol::SKIPFORWARD2;
- else if (action == 4) w.nextSymbol = WSymbol::SKIPBACK2;
- }
- else
- {
- playerState = player->getState();
- if (playerState == Player::S_PAUSE_P) w.nextSymbol = WSymbol::PAUSE;
- else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
- else if (playerState == Player::S_FFWD) w.nextSymbol = WSymbol::FFWD;
- else if (playerState == Player::S_FBWD) w.nextSymbol = WSymbol::FBWD;
- else w.nextSymbol = WSymbol::PLAY;
- }
-
- w.draw();
-
- if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))
- {
- // draw blips to show how fast the scan is
- UCHAR scanrate = player->getIScanRate();
- if (scanrate >= 2)
- {
- char text[5];
- SNPRINTF(text, 5, "%ux", scanrate);
- drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);
- }
- }
-
- drawBarClocks();
-
- boxstack->update(this, &barRegion);
-
- timers->cancelTimer(this, 1);
-
-
- if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;
- else barScanHold = false;
-
- if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
-
- timers->setTimerD(this, 2, 0, 200000000);
-}
-
-void VVideoRec::timercall(int clientReference)
-{
- switch(clientReference)
- {
- case 1:
- {
- // Remove bar
- removeBar();
- break;
- }
- case 2:
- {
- // Update clock
- if (!barShowing) break;
- drawBarClocks();
- boxstack->update(this, &barRegion);
-
- timers->setTimerD(this, 2, 0, 200000000);
- break;
- }
- }
-}
-
-hmsf VVideoRec::framesToHMSF(ULONG frames)
-{
- hmsf ret;
- /* from vdr */
- double Seconds;
- double fps=myRec->recInfo->fps;
- ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);
- int s = int(Seconds);
- ret.seconds=s % 60;
- ret.minutes = s / 60 % 60;
- ret.hours = s / 3600;
-
-
- return ret;
-}
-
-void VVideoRec::drawBarClocks()
-{
- if (barScanHold)
- {
- UCHAR playerState = player->getState();
- // sticky bar is set if we are in ffwd/fbwd mode
- // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
- // will repaint all the bar (it will call this function again, but
- // this section won't run because stickyBarF will then == false)
-
- if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))
- {
- barScanHold = false;
- doBar(0);
- return; // doBar will call this function and do the rest
- }
- }
-
- Log* logger = Log::getInstance();
- logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");
-
- // Draw RTC
- // Blank the area first
- rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
- char timeString[20];
- time_t t;
- time(&t);
- struct tm* tms = localtime(&t);
- strftime(timeString, 19, "%H:%M", tms);
- drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
-
- // Draw clocks
-
- rectangle(clocksRegion, barBlue);
-
- ULONG currentFrameNum = player->getCurrentFrameNum();
- ULONG lengthFrames;
- if (myRec->recInfo->timerEnd > time(NULL))
- {
- // chasing playback
- // Work out an approximate length in frames (good to 1s...)
- lengthFrames =(ULONG) ((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);
- }
- else
- {
- lengthFrames = player->getLengthFrames();
- }
-
- hmsf currentFrameHMSF = framesToHMSF(currentFrameNum);
- hmsf lengthHMSF = framesToHMSF(lengthFrames);
-
- char buffer[100];
- if (currentFrameNum >= lengthFrames)
- {
- strcpy(buffer, "-:--:-- / -:--:--");
- }
- else
- {
- SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
- logger->log("VVideoRec", Log::DEBUG, buffer);
- }
-
- drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
-
-
-
-
-
-
-
- // Draw progress bar
- int progBarXbase = barRegion.x + 300;
-
- rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
- rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
-
- if (currentFrameNum > lengthFrames) return;
- if (lengthFrames == 0) return;
-
- // Draw yellow portion
- int progressWidth = 302 * currentFrameNum / lengthFrames;
- rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-
- if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
- {
- int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));
-
- Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
- Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
- Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
- rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);
- }
-
- int posPix;
- // Now calc position for blips
-
- if (myRec->hasMarks())
- {
- // Draw blips where there are cut marks
- MarkList* markList = myRec->getMarkList();
- MarkList::iterator i;
- Mark* loopMark = NULL;
-
- for(i = markList->begin(); i != markList->end(); i++)
- {
- loopMark = *i;
- if (loopMark->pos)
- {
- logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);
- posPix = 302 * loopMark->pos / lengthFrames;
- rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
- }
- }
- }
- else
- {
- // Draw blips where start and end margins probably are
-
- posPix =(int) (302. * myRec->recInfo->fps * ((double)startMargin) /((double) lengthFrames));
-
- rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
- rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
-
- posPix = (int)(302. * ((double)lengthFrames - ((double)endMargin) * myRec->recInfo->fps) / ((double)lengthFrames));
-
- rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
- rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
- }
-}
-
-void VVideoRec::removeBar()
-{
- if (!barShowing) return;
- timers->cancelTimer(this, 2);
- barShowing = false;
- barGenHold = false;
- barScanHold = false;
- barVasHold = false;
- rectangle(barRegion, transparent);
- boxstack->update(this, &barRegion);
-}
-
-void VVideoRec::doSummary()
-{
- vsummary = new VInfo();
- vsummary->setTitleText(myRec->getProgName());
- vsummary->setBorderOn(1);
- vsummary->setExitable();
- if (myRec->recInfo->summary) vsummary->setMainText(myRec->recInfo->summary);
- else vsummary->setMainText(tr("Summary unavailable"));
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- vsummary->setPosition(120, 130);
- }
- else
- {
- vsummary->setPosition(110, 90);
- }
- vsummary->setSize(510, 270);
- add(vsummary);
- vsummary->draw();
-
- BoxStack::getInstance()->update(this);
-}
-
-void VVideoRec::removeSummary()
-{
- if (vsummary)
- {
- remove(vsummary);
- delete vsummary;
- vsummary = NULL;
- draw();
- BoxStack::getInstance()->update(this);
- }
-}
-
-void VVideoRec::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)
-{
- drawBitmap(posX, posY, bm);
- Region r;
- r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
- boxstack->update(this, &r);
-}
-
-void VVideoRec::clearOSD()
-{
- rectangle(area, transparent);
- boxstack->update(this, &area);
-}
-
-void VVideoRec::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)
-{
- Region r;
- r.x = posX; r.y = posY; r.w = width; r.h = height;
- rectangle(r, transparent);
- boxstack->update(this, &r);
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include <math.h>\r
+\r
+#include "vvideorec.h"\r
+#include "vteletextview.h"\r
+\r
+#include "command.h"\r
+#include "osd.h"\r
+#include "wsymbol.h"\r
+#include "audio.h"\r
+#include "vdr.h"\r
+#include "video.h"\r
+#include "timers.h"\r
+#include "player.h"\r
+#include "recording.h"\r
+#include "vaudioselector.h"\r
+#include "message.h"\r
+#include "remote.h"\r
+#include "boxstack.h"\r
+#include "vinfo.h"\r
+#include "i18n.h"\r
+#include "bitmap.h"\r
+#include "recinfo.h"\r
+#include "log.h"\r
+#include "channel.h"\r
+ \r
+VVideoRec::VVideoRec(Recording* rec, bool ish264)\r
+{\r
+ boxstack = BoxStack::getInstance();\r
+ vdr = VDR::getInstance();\r
+ video = Video::getInstance();\r
+ timers = Timers::getInstance();\r
+ vas = NULL;\r
+ vsummary = NULL;\r
+\r
+ videoMode = video->getMode();\r
+ myRec = rec;\r
+\r
+ video->seth264mode(ish264);\r
+\r
+ player = new Player(Command::getInstance(), this, this);\r
+ player->init(myRec->IsPesRecording,myRec->recInfo->fps);\r
+\r
+ playing = false;\r
+\r
+ startMargin = 0;\r
+ endMargin = 0;\r
+ char* cstartMargin = vdr->configLoad("Timers", "Start margin");\r
+ char* cendMargin = vdr->configLoad("Timers", "End margin");\r
+ if (!cstartMargin)\r
+ {\r
+ startMargin = 300; // 5 mins default\r
+ }\r
+ else\r
+ {\r
+ startMargin = atoi(cstartMargin) * 60;\r
+ delete[] cstartMargin;\r
+ }\r
+\r
+ if (!cendMargin)\r
+ {\r
+ endMargin = 300; // 5 mins default\r
+ }\r
+ else\r
+ {\r
+ endMargin = atoi(cendMargin) * 60;\r
+ delete[] cendMargin;\r
+ }\r
+\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);\r
+\r
+ setSize(video->getScreenWidth(), video->getScreenHeight());\r
+ createBuffer();\r
+ transparent.set(0, 0, 0, 0);\r
+ setBackgroundColour(transparent);\r
+\r
+ barRegion.x = 0;\r
+ barRegion.y = video->getScreenHeight() - 58; // FIXME, need to be - 1? and below?\r
+ barRegion.w = video->getScreenWidth();\r
+ barRegion.h = 58;\r
+\r
+ clocksRegion.x = barRegion.x + 140;\r
+ clocksRegion.y = barRegion.y + 12;\r
+ clocksRegion.w = 170;\r
+ clocksRegion.h = getFontHeight();\r
+// barBlue.set(0, 0, 150, 150);\r
+ barBlue.set(0, 0, 0, 128);\r
+\r
+ barShowing = false;\r
+ barGenHold = false;\r
+ barScanHold = false;\r
+ barVasHold = false;\r
+\r
+ dowss = false;\r
+ char* optionWSS = vdr->configLoad("General", "WSS");\r
+ if (optionWSS)\r
+ {\r
+ if (strstr(optionWSS, "Yes")) dowss = true;\r
+ delete[] optionWSS;\r
+ }\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Do WSS: %u", dowss);\r
+\r
+ if (dowss)\r
+ {\r
+ wss.setFormat(video->getFormat());\r
+ wss.setWide(true);\r
+ add(&wss);\r
+\r
+ wssRegion.x = 0;\r
+ wssRegion.y = 0;\r
+ wssRegion.w = video->getScreenWidth();\r
+ wssRegion.h = 300;\r
+ }\r
+}\r
+\r
+void VVideoRec::preDelete()\r
+{\r
+ timers->cancelTimer(this, 1);\r
+ timers->cancelTimer(this, 2);\r
+\r
+ if (vas)\r
+ {\r
+ boxstack->remove(vas);\r
+ vas = NULL;\r
+ }\r
+\r
+ if (vsummary) delete vsummary;\r
+\r
+ if (playing) stopPlay();\r
+}\r
+\r
+VVideoRec::~VVideoRec()\r
+{\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Entering vvideorec destructor");\r
+\r
+ video->setDefaultAspect();\r
+\r
+ // kill recInfo in case resumePoint has changed (likely)\r
+ myRec->dropRecInfo();\r
+ // FIXME - do this properly - save the resume point back to the server manually and update\r
+ // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well\r
+}\r
+\r
+void VVideoRec::go(bool resume)\r
+{\r
+ ULONG startFrameNum;\r
+ if (resume)\r
+ startFrameNum = myRec->recInfo->resumePoint;\r
+ else\r
+ startFrameNum = 0;\r
+\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Starting stream: %s at frame: %lu", myRec->getFileName(), startFrameNum);\r
+ ULONG lengthFrames = 0;\r
+ bool isPesRecording;\r
+ ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);\r
+ myRec->IsPesRecording = isPesRecording;\r
+ if (lengthBytes)\r
+ {\r
+ player->setLengthBytes(lengthBytes);\r
+ player->setLengthFrames(lengthFrames);\r
+ player->setStartFrame(startFrameNum);\r
+ player->play();\r
+ playing = true;\r
+ doBar(0);\r
+ }\r
+ else\r
+ {\r
+ stopPlay(); // clean up\r
+\r
+ if (!vdr->isConnected())\r
+ {\r
+ Command::getInstance()->connectionLost();\r
+ return;\r
+ }\r
+\r
+ Message* m = new Message();\r
+ m->message = Message::CLOSE_ME;\r
+ m->from = this;\r
+ m->to = boxstack;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+\r
+ VInfo* vi = new VInfo();\r
+ vi->setSize(400, 150);\r
+ vi->createBuffer();\r
+ if (video->getFormat() == Video::PAL)\r
+ vi->setPosition(170, 200);\r
+ else\r
+ vi->setPosition(160, 150);\r
+ vi->setExitable();\r
+ vi->setBorderOn(1);\r
+ vi->setTitleBarOn(0);\r
+ vi->setOneLiner(tr("Error playing recording"));\r
+ vi->draw();\r
+\r
+ m = new Message();\r
+ m->message = Message::ADD_VIEW;\r
+ m->to = boxstack;\r
+ m->parameter = (ULONG)vi;\r
+ Command::getInstance()->postMessageNoLock(m);\r
+ }\r
+}\r
+\r
+int VVideoRec::handleCommand(int command)\r
+{\r
+ switch(command)\r
+ {\r
+ case Remote::PLAY:\r
+ {\r
+ player->play();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+\r
+ case Remote::PLAYPAUSE:\r
+ {\r
+ player->playpause();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+\r
+ case Remote::BACK:\r
+ {\r
+ if (vsummary)\r
+ {\r
+ removeSummary();\r
+ return 2;\r
+ }\r
+ } // DROP THROUGH\r
+ case Remote::STOP:\r
+ case Remote::MENU:\r
+ {\r
+ if (playing) stopPlay();\r
+\r
+ return 4;\r
+ }\r
+ case Remote::PAUSE:\r
+ {\r
+ player->pause();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+ case Remote::SKIPFORWARD:\r
+ {\r
+ doBar(3);\r
+ player->skipForward(60);\r
+ return 2;\r
+ }\r
+ case Remote::SKIPBACK:\r
+ {\r
+ doBar(4);\r
+ player->skipBackward(60);\r
+ return 2;\r
+ }\r
+ case Remote::FORWARD:\r
+ {\r
+ player->fastForward();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+ case Remote::REVERSE:\r
+ {\r
+ player->fastBackward();\r
+ doBar(0);\r
+ return 2;\r
+ }\r
+ case Remote::RED:\r
+ {\r
+ if (vsummary) removeSummary();\r
+ else doSummary();\r
+ return 2;\r
+ }\r
+ case Remote::GREEN:\r
+ {\r
+ doAudioSelector();\r
+ return 2;\r
+ }\r
+ case Remote::YELLOW:\r
+ {\r
+ if (myRec->hasMarks())\r
+ {\r
+ // skip to previous mark\r
+ Log* logger = Log::getInstance();\r
+ int currentFrame = (player->getCurrentFrameNum()); // get current Frame\r
+ currentFrame -= 5. * myRec->recInfo->fps; // subtrack 5 seconds, else you cannot skip more than once back ..\r
+\r
+ int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame\r
+ if (prevMark)\r
+ {\r
+ logger->log("VVideoRec", Log::NOTICE, "jump back from pos %i to mark at %i",currentFrame,prevMark);\r
+ player->jumpToMark(prevMark);\r
+ }\r
+ doBar(4);\r
+ }\r
+ else\r
+ {\r
+ doBar(2);\r
+ player->skipBackward(10);\r
+ }\r
+ return 2;\r
+ }\r
+ case Remote::BLUE:\r
+ {\r
+ if (myRec->hasMarks())\r
+ {\r
+ // skip to next mark\r
+ Log* logger = Log::getInstance();\r
+ int currentFrame = (player->getCurrentFrameNum());\r
+\r
+ int nextMark = myRec->getNextMark(currentFrame);\r
+\r
+ if (nextMark)\r
+ {\r
+ logger->log("VVideoRec", Log::NOTICE, "jump forward from pos %i to mark at %i",currentFrame,nextMark);\r
+ player->jumpToMark(nextMark);\r
+ }\r
+ doBar(3);\r
+ }\r
+ else\r
+ {\r
+ doBar(1);\r
+ player->skipForward(10);\r
+ }\r
+ return 2;\r
+ }\r
+ case Remote::STAR:\r
+ {\r
+ doBar(2);\r
+ player->skipBackward(10);\r
+ return 2;\r
+ }\r
+ case Remote::HASH:\r
+ {\r
+ doBar(1);\r
+ player->skipForward(10);\r
+ return 2;\r
+ }\r
+ case Remote::FULL:\r
+ case Remote::TV:\r
+ {\r
+ toggleChopSides();\r
+ return 2;\r
+ }\r
+\r
+ case Remote::OK:\r
+ {\r
+ if (vsummary)\r
+ {\r
+ removeSummary();\r
+ return 2;\r
+ }\r
+ \r
+ if (barShowing) removeBar();\r
+ else doBar(0);\r
+ return 2;\r
+ }\r
+\r
+ case Remote::ZERO: player->jumpToPercent(0); doBar(0); return 2;\r
+ case Remote::ONE: player->jumpToPercent(10); doBar(0); return 2;\r
+ case Remote::TWO: player->jumpToPercent(20); doBar(0); return 2;\r
+ case Remote::THREE: player->jumpToPercent(30); doBar(0); return 2;\r
+ case Remote::FOUR: player->jumpToPercent(40); doBar(0); return 2;\r
+ case Remote::FIVE: player->jumpToPercent(50); doBar(0); return 2;\r
+ case Remote::SIX: player->jumpToPercent(60); doBar(0); return 2;\r
+ case Remote::SEVEN: player->jumpToPercent(70); doBar(0); return 2;\r
+ case Remote::EIGHT: player->jumpToPercent(80); doBar(0); return 2;\r
+ case Remote::NINE: player->jumpToPercent(90); doBar(0); return 2;\r
+\r
+ case Remote::RECORD: player->toggleSubtitles(); return 2;\r
+#ifdef DEV\r
+// case Remote::RED:\r
+// {\r
+ //Don't use RED for anything. It will eventually be recording summary\r
+\r
+ //player->test1();\r
+\r
+\r
+ /*\r
+ // for testing EPG in NTSC with a NTSC test video\r
+ Video::getInstance()->setMode(Video::QUARTER);\r
+ Video::getInstance()->setPosition(170, 5);\r
+ VEpg* vepg = new VEpg(NULL, 0);\r
+ vepg->draw();\r
+ BoxStack::getInstance()->add(vepg);\r
+ BoxStack::getInstance()->update(vepg);\r
+ */\r
+\r
+// return 2;\r
+// }\r
+\r
+#endif\r
+\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+void VVideoRec::doTeletext()\r
+{\r
+ \r
+ bool exists=true;\r
+\r
+ \r
+ // Draw the teletxt\r
+ VTeletextView *vtxv=player->getTeletextDecoder()->getTeletxtView();\r
+ if (vtxv==NULL) {\r
+ vtxv= new VTeletextView((player)->getTeletextDecoder(),this);\r
+ (player)->getTeletextDecoder()->registerTeletextView(vtxv);\r
+ exists=false;\r
+ }\r
+ vtxv->setSubtitleMode(true);\r
+ vtxv->draw();\r
+ draw();\r
+ \r
+ if (!exists) {\r
+ BoxStack::getInstance()->add(vtxv);\r
+ }\r
+ BoxStack::getInstance()->update(this);\r
+ BoxStack::getInstance()->update(vtxv); \r
+}\r
+\r
+void VVideoRec::processMessage(Message* m)\r
+{\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");\r
+\r
+ if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ UINT x = (m->parameter>>16) - getScreenX();\r
+ UINT y = (m->parameter&0xFFFF) - getScreenY();\r
+\r
+ if (!barShowing)\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+ }\r
+ else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)\r
+ {\r
+ int progBarXbase = barRegion.x + 300;\r
+ if (myRec->hasMarks())\r
+ {\r
+ MarkList* markList = myRec->getMarkList();\r
+ MarkList::iterator i;\r
+ Mark* loopMark = NULL;\r
+ int posPix;\r
+ ULONG lengthFrames;\r
+ if (myRec->recInfo->timerEnd > time(NULL))\r
+ {\r
+ // chasing playback\r
+ // Work out an approximate length in frames (good to 1s...)\r
+ lengthFrames = (ULONG)((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);\r
+ }\r
+ else\r
+ {\r
+ lengthFrames = player->getLengthFrames();\r
+ }\r
+ for(i = markList->begin(); i != markList->end(); i++)\r
+ {\r
+ loopMark = *i;\r
+ if (loopMark->pos)\r
+ {\r
+ posPix = 302 * loopMark->pos / lengthFrames;\r
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);\r
+ if (x>=barRegion.x + progBarXbase + 2 + posPix\r
+ && x<=barRegion.x + progBarXbase + 2 + posPix+3\r
+ && y>=barRegion.y + 12 - 2\r
+ && y<=barRegion.y + 12 - 2+28)\r
+ {\r
+ player->jumpToMark(loopMark->pos);\r
+ doBar(3);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (x>=barRegion.x + progBarXbase + 24\r
+ && x<=barRegion.x + progBarXbase + 4 + 302\r
+ && y>=barRegion.y + 12 - 2\r
+ && y<=barRegion.y + 12 - 2+28)\r
+ {\r
+ int cx=x-(barRegion.x + progBarXbase + 4);\r
+ double percent=((double)cx)/302.*100.;\r
+ player->jumpToPercent(percent);\r
+ doBar(3);\r
+ return;\r
+ // int progressWidth = 302 * currentFrameNum / lengthFrames;\r
+ // rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+ }\r
+ }\r
+ else if (m->from == player)\r
+ {\r
+ if (m->message != Message::PLAYER_EVENT) return;\r
+ switch(m->parameter)\r
+ {\r
+ case Player::CONNECTION_LOST: // connection lost detected\r
+ {\r
+ // I can't handle this, send it to command\r
+ Message* m2 = new Message();\r
+ m2->to = Command::getInstance();\r
+ m2->message = Message::CONNECTION_LOST;\r
+ Command::getInstance()->postMessageNoLock(m2);\r
+ break;\r
+ }\r
+ case Player::STOP_PLAYBACK:\r
+ {\r
+ // FIXME Obselete ish - improve this\r
+ Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+ m2->to = Command::getInstance();\r
+ m2->message = Message::STOP_PLAYBACK;\r
+ Command::getInstance()->postMessageNoLock(m2);\r
+ break;\r
+ }\r
+ case Player::ASPECT43:\r
+ {\r
+ if (dowss)\r
+ {\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");\r
+ wss.setWide(false);\r
+ wss.draw();\r
+ boxstack->update(this, &wssRegion);\r
+ }\r
+ break;\r
+ }\r
+ case Player::ASPECT169:\r
+ {\r
+ if (dowss)\r
+ {\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");\r
+ wss.setWide(true);\r
+ wss.draw();\r
+ boxstack->update(this, &wssRegion);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ else if (m->message == Message::AUDIO_CHANGE_CHANNEL)\r
+ {\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change audio channel to %i", m->parameter);\r
+ player->setAudioChannel(m->parameter&0xFFFF,(m->parameter&0xFF0000)>> 16 );\r
+ }\r
+ else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)\r
+ {\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);\r
+ int type=((m->parameter & 0xFF0000)>>16);\r
+ switch (type) {\r
+ case 0x10: { //dvbsubtitle\r
+ player->setSubtitleChannel((m->parameter & 0xFFFF));\r
+ player->turnSubtitlesOn(true);\r
+ VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();\r
+ if (vtxt && vtxt->isInSubtitleMode()) {\r
+ BoxStack::getInstance()->remove(vtxt);\r
+ }\r
+ } break;\r
+ case 0xFF: { //nosubtitles\r
+ \r
+ player->turnSubtitlesOn(false);\r
+ VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();\r
+ if (vtxt && vtxt->isInSubtitleMode()) {\r
+ BoxStack::getInstance()->remove(vtxt);\r
+ } \r
+ \r
+ } break;\r
+ case 0x11: { //videotext\r
+ player->turnSubtitlesOn(false);\r
+ doTeletext();\r
+ ((Player*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));\r
+ } break;\r
+ };\r
+ if (vas) {\r
+ BoxStack::getInstance()->update(vas);\r
+ }\r
+ BoxStack::getInstance()->update(this);\r
+\r
+ \r
+ } \r
+ else if (m->message == Message::CHILD_CLOSE)\r
+ {\r
+ if (m->from == vas)\r
+ {\r
+ vas = NULL;\r
+ barVasHold = false;\r
+ if (!barGenHold && !barScanHold && !barVasHold) removeBar();\r
+ }\r
+ }\r
+}\r
+\r
+void VVideoRec::stopPlay()\r
+{\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Pre stopPlay");\r
+\r
+ removeBar();\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "1");\r
+ player->stop();\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "2");\r
+ vdr->stopStreaming();\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "3");\r
+ delete player;\r
+\r
+ playing = false;\r
+\r
+ if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }\r
+ Log::getInstance()->log("VVideoRec", Log::DEBUG, "Post stopPlay");\r
+}\r
+\r
+void VVideoRec::toggleChopSides()\r
+{\r
+ if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs\r
+\r
+ if (videoMode == Video::NORMAL)\r
+ {\r
+ videoMode = Video::LETTERBOX;\r
+ video->setMode(Video::LETTERBOX);\r
+ }\r
+ else\r
+ {\r
+ videoMode = Video::NORMAL;\r
+ video->setMode(Video::NORMAL);\r
+ }\r
+}\r
+\r
+void VVideoRec::doAudioSelector()\r
+{\r
+ int subtitleChannel=player->getCurrentSubtitleChannel();\r
+ int subtitleType=0x10;\r
+ if (!(player)->isSubtitlesOn()) {\r
+ if ((player)->getTeletextDecoder()->getTeletxtView() &&\r
+ (player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() \r
+ ) {\r
+ subtitleChannel=(player)->getTeletextDecoder()->getPage();\r
+ subtitleType=0x11;\r
+ \r
+ } else {\r
+ subtitleType=0xFF; //turnedOff\r
+ subtitleChannel=0;\r
+ }\r
+ }\r
+ if (player->isPesRecording()) {\r
+ bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();\r
+ bool* availableAc3AudioChannels = NULL;\r
+ bool* availableSubtitleChannels = player->getDemuxerSubtitleChannels();\r
+ int *availableTTxtpages = player->getTeletxtSubtitlePages();\r
+ int currentAudioChannel = player->getCurrentAudioChannel();\r
+ if (Audio::getInstance()->supportsAc3())\r
+ {\r
+ availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();\r
+ }\r
+ \r
+ vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel,availableSubtitleChannels, availableTTxtpages,\r
+ subtitleChannel, subtitleType, myRec->recInfo);\r
+ } else {\r
+ // Draw the selector\r
+ Channel temp_channel=player->getDemuxerChannel();\r
+ RecInfo *cur_info= myRec->recInfo;\r
+ unsigned char numchan_recinfo = cur_info->numComponents;\r
+ unsigned char numchan_subtitles_siz = temp_channel.numSPids;\r
+ ULONG mp_audcounter = 0;\r
+ ULONG ac3_counter = 0;\r
+ int dvb_subcounter = 1;\r
+ \r
+ unsigned char type;\r
+ char* lang;\r
+ char* description;\r
+ int i;\r
+ for (i = 0; i < numchan_recinfo; i++)\r
+ { \r
+ apid* ac = NULL;\r
+ type = cur_info->types[i];\r
+ lang = cur_info->languages[i];\r
+ description = cur_info->descriptions[i];\r
+ \r
+\r
+ if (cur_info->streams[i] == 2) {\r
+ switch (type)\r
+ {\r
+ case 1: //mpaudio mono\r
+ case 3: //mpaudio stereo\r
+ if (mp_audcounter < temp_channel.numAPids) ac = &temp_channel.apids[mp_audcounter];\r
+ \r
+ mp_audcounter++;\r
+ break;\r
+ case 5: //ac3\r
+ if (ac3_counter < temp_channel.numDPids) ac = &temp_channel.dpids[ac3_counter];\r
+ ac3_counter++;\r
+ break;\r
+ }\r
+ } else if (cur_info->streams[i] == 3){\r
+ if (dvb_subcounter < numchan_subtitles_siz) ac = &temp_channel.spids[dvb_subcounter];\r
+ } else continue; //neither audio nor subtitle\r
+ if (ac)\r
+ {\r
+ if (description && (strlen(description) > 0))\r
+ {\r
+ ac->name = new char[strlen(description) + 1];\r
+ strcpy(ac->name, description);\r
+ \r
+ } else if (lang && strlen(lang) > 0)\r
+ {\r
+ ac->name = new char[strlen(lang) + 1];\r
+ strcpy(ac->name, lang);\r
+ \r
+ }\r
+ }\r
+ }\r
+ for (i=0;i<temp_channel.numAPids;i++) {\r
+ apid *ac=&temp_channel.apids[i];\r
+ if (ac->name==NULL) {\r
+ ac->name = new char[strlen(tr("unknown")) + 1];\r
+ strcpy(ac->name, tr("unknown"));\r
+ }\r
+ }\r
+ for (i=0;i<temp_channel.numDPids;i++) {\r
+ apid *ac=&temp_channel.dpids[i];\r
+ if (ac->name==NULL) {\r
+ ac->name = new char[strlen(tr("unknown")) + 1];\r
+ strcpy(ac->name, tr("unknown"));\r
+ }\r
+ }\r
+ for (i=0;i<temp_channel.numSPids;i++) {\r
+ apid *ac=&temp_channel.spids[i];\r
+ if (ac->name==NULL) {\r
+ ac->name = new char[strlen(tr("unknown")) + 1];\r
+ strcpy(ac->name, tr("unknown"));\r
+ }\r
+ }\r
+\r
+ vas = new VAudioSelector(this,&temp_channel , (player)->getCurrentAudioChannel(),\r
+ subtitleType,subtitleChannel,player->getTeletxtSubtitlePages()); \r
+ for (i=0;i<temp_channel.numAPids;i++) {\r
+ apid *ac=&temp_channel.apids[i];\r
+ delete[] ac->name;\r
+ ac->name=NULL;\r
+ }\r
+ for (i=0;i<temp_channel.numDPids;i++) {\r
+ apid *ac=&temp_channel.dpids[i];\r
+ delete[] ac->name;\r
+ ac->name=NULL;\r
+ }\r
+ for (i=0;i<temp_channel.numSPids;i++) {\r
+ apid *ac=&temp_channel.spids[i];\r
+ delete[] ac->name;\r
+ ac->name=NULL;\r
+ }\r
+ }\r
+\r
+\r
+ vas->setBackgroundColour(barBlue);\r
+ vas->setPosition(0, barRegion.y - 120);\r
+\r
+// pal 62, ntsc 57\r
+\r
+ barVasHold = true;\r
+ doBar(0);\r
+\r
+ vas->draw();\r
+ boxstack->add(vas);\r
+ boxstack->update(vas);\r
+}\r
+\r
+void VVideoRec::doBar(int action)\r
+{\r
+ barShowing = true;\r
+\r
+ rectangle(barRegion, barBlue);\r
+\r
+ /* Work out what to display - choices:\r
+\r
+ Playing >\r
+ Paused ||\r
+ FFwd >>\r
+ FBwd <<\r
+\r
+ Specials, informed by parameter\r
+\r
+ Skip forward 10s >|\r
+ Skip backward 10s |<\r
+ Skip forward 1m >>|\r
+ Skip backward 1m |<<\r
+\r
+ */\r
+\r
+ WSymbol w;\r
+ TEMPADD(&w);\r
+ w.nextSymbol = 0;\r
+ w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
+\r
+ UCHAR playerState = 0;\r
+\r
+ if (action)\r
+ {\r
+ if (action == 1) w.nextSymbol = WSymbol::SKIPFORWARD;\r
+ else if (action == 2) w.nextSymbol = WSymbol::SKIPBACK;\r
+ else if (action == 3) w.nextSymbol = WSymbol::SKIPFORWARD2;\r
+ else if (action == 4) w.nextSymbol = WSymbol::SKIPBACK2;\r
+ }\r
+ else\r
+ {\r
+ playerState = player->getState();\r
+ if (playerState == Player::S_PAUSE_P) w.nextSymbol = WSymbol::PAUSE;\r
+ else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;\r
+ else if (playerState == Player::S_FFWD) w.nextSymbol = WSymbol::FFWD;\r
+ else if (playerState == Player::S_FBWD) w.nextSymbol = WSymbol::FBWD;\r
+ else w.nextSymbol = WSymbol::PLAY;\r
+ }\r
+\r
+ w.draw();\r
+\r
+ if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))\r
+ {\r
+ // draw blips to show how fast the scan is\r
+ UCHAR scanrate = player->getIScanRate();\r
+ if (scanrate >= 2)\r
+ {\r
+ char text[5];\r
+ SNPRINTF(text, 5, "%ux", scanrate);\r
+ drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);\r
+ }\r
+ }\r
+\r
+ drawBarClocks();\r
+\r
+ boxstack->update(this, &barRegion);\r
+\r
+ timers->cancelTimer(this, 1);\r
+\r
+\r
+ if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;\r
+ else barScanHold = false;\r
+\r
+ if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);\r
+\r
+ timers->setTimerD(this, 2, 0, 200000000);\r
+}\r
+\r
+void VVideoRec::timercall(int clientReference)\r
+{\r
+ switch(clientReference)\r
+ {\r
+ case 1:\r
+ {\r
+ // Remove bar\r
+ removeBar();\r
+ break;\r
+ }\r
+ case 2:\r
+ {\r
+ // Update clock\r
+ if (!barShowing) break;\r
+ drawBarClocks();\r
+ boxstack->update(this, &barRegion);\r
+ \r
+ timers->setTimerD(this, 2, 0, 200000000);\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+hmsf VVideoRec::framesToHMSF(ULONG frames)\r
+{\r
+ hmsf ret;\r
+ /* from vdr */\r
+ double Seconds;\r
+ double fps=myRec->recInfo->fps;\r
+ ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);\r
+ int s = int(Seconds);\r
+ ret.seconds=s % 60;\r
+ ret.minutes = s / 60 % 60;\r
+ ret.hours = s / 3600;\r
+\r
+\r
+ return ret;\r
+}\r
+\r
+void VVideoRec::drawBarClocks()\r
+{\r
+ if (barScanHold)\r
+ {\r
+ UCHAR playerState = player->getState();\r
+ // sticky bar is set if we are in ffwd/fbwd mode\r
+ // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which\r
+ // will repaint all the bar (it will call this function again, but\r
+ // this section won't run because stickyBarF will then == false)\r
+\r
+ if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))\r
+ {\r
+ barScanHold = false;\r
+ doBar(0);\r
+ return; // doBar will call this function and do the rest\r
+ }\r
+ }\r
+\r
+ Log* logger = Log::getInstance();\r
+ logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");\r
+\r
+ // Draw RTC\r
+ // Blank the area first\r
+ rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
+ char timeString[20];\r
+ time_t t;\r
+ time(&t);\r
+ struct tm* tms = localtime(&t);\r
+ strftime(timeString, 19, "%H:%M", tms);\r
+ drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);\r
+\r
+ // Draw clocks\r
+\r
+ rectangle(clocksRegion, barBlue);\r
+\r
+ ULONG currentFrameNum = player->getCurrentFrameNum();\r
+ ULONG lengthFrames;\r
+ if (myRec->recInfo->timerEnd > time(NULL))\r
+ {\r
+ // chasing playback\r
+ // Work out an approximate length in frames (good to 1s...)\r
+ lengthFrames =(ULONG) ((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);\r
+ }\r
+ else\r
+ {\r
+ lengthFrames = player->getLengthFrames();\r
+ }\r
+\r
+ hmsf currentFrameHMSF = framesToHMSF(currentFrameNum);\r
+ hmsf lengthHMSF = framesToHMSF(lengthFrames);\r
+\r
+ char buffer[100];\r
+ if (currentFrameNum >= lengthFrames)\r
+ {\r
+ strcpy(buffer, "-:--:-- / -:--:--");\r
+ }\r
+ else\r
+ {\r
+ SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
+ logger->log("VVideoRec", Log::DEBUG, buffer);\r
+ }\r
+\r
+ drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ // Draw progress bar\r
+ int progBarXbase = barRegion.x + 300;\r
+\r
+ rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);\r
+ rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
+\r
+ if (currentFrameNum > lengthFrames) return;\r
+ if (lengthFrames == 0) return;\r
+\r
+ // Draw yellow portion\r
+ int progressWidth = 302 * currentFrameNum / lengthFrames;\r
+ rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+\r
+ if (myRec->recInfo->timerEnd > time(NULL)) // if chasing\r
+ {\r
+ int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));\r
+\r
+ Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);\r
+ Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());\r
+ Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);\r
+ rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);\r
+ }\r
+\r
+ int posPix;\r
+ // Now calc position for blips\r
+\r
+ if (myRec->hasMarks())\r
+ {\r
+ // Draw blips where there are cut marks\r
+ MarkList* markList = myRec->getMarkList();\r
+ MarkList::iterator i;\r
+ Mark* loopMark = NULL;\r
+\r
+ for(i = markList->begin(); i != markList->end(); i++)\r
+ {\r
+ loopMark = *i;\r
+ if (loopMark->pos)\r
+ {\r
+ logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);\r
+ posPix = 302 * loopMark->pos / lengthFrames;\r
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // Draw blips where start and end margins probably are\r
+\r
+ posPix =(int) (302. * myRec->recInfo->fps * ((double)startMargin) /((double) lengthFrames));\r
+\r
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);\r
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);\r
+\r
+ posPix = (int)(302. * ((double)lengthFrames - ((double)endMargin) * myRec->recInfo->fps) / ((double)lengthFrames));\r
+\r
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);\r
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);\r
+ }\r
+}\r
+\r
+void VVideoRec::removeBar()\r
+{\r
+ if (!barShowing) return;\r
+ timers->cancelTimer(this, 2);\r
+ barShowing = false;\r
+ barGenHold = false;\r
+ barScanHold = false;\r
+ barVasHold = false;\r
+ rectangle(barRegion, transparent);\r
+ boxstack->update(this, &barRegion);\r
+}\r
+\r
+void VVideoRec::doSummary()\r
+{\r
+ vsummary = new VInfo();\r
+ vsummary->setTitleText(myRec->getProgName());\r
+ vsummary->setBorderOn(1);\r
+ vsummary->setExitable();\r
+ if (myRec->recInfo->summary) vsummary->setMainText(myRec->recInfo->summary);\r
+ else vsummary->setMainText(tr("Summary unavailable"));\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ vsummary->setPosition(120, 130);\r
+ }\r
+ else\r
+ {\r
+ vsummary->setPosition(110, 90);\r
+ }\r
+ vsummary->setSize(510, 270);\r
+ add(vsummary);\r
+ vsummary->draw();\r
+\r
+ BoxStack::getInstance()->update(this);\r
+}\r
+\r
+void VVideoRec::removeSummary()\r
+{\r
+ if (vsummary)\r
+ {\r
+ remove(vsummary);\r
+ delete vsummary;\r
+ vsummary = NULL;\r
+ draw();\r
+ BoxStack::getInstance()->update(this);\r
+ }\r
+}\r
+\r
+void VVideoRec::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)\r
+{\r
+ drawBitmap(posX, posY, bm);\r
+ Region r;\r
+ r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();\r
+ boxstack->update(this, &r);\r
+}\r
+\r
+void VVideoRec::clearOSD()\r
+{\r
+ rectangle(area, transparent);\r
+ boxstack->update(this, &area);\r
+}\r
+\r
+void VVideoRec::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)\r
+{\r
+ Region r;\r
+ r.x = posX; r.y = posY; r.w = width; r.h = height;\r
+ rectangle(r, transparent);\r
+ boxstack->update(this, &r);\r
+}\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "vwelcome.h"
-
-#include "remote.h"
-#include "vdr.h"
-#include "vchannellist.h"
-#include "vrecordinglist.h"
-#include "vtimerlist.h"
-#include "command.h"
-#include "message.h"
-#include "colour.h"
-#include "video.h"
-#include "i18n.h"
-#include "timers.h"
-#include "vscreensaver.h"
-#include "vmedialist.h"
-#include "boxstack.h"
-#include "vopts.h"
-
-VWelcome::VWelcome()
-{
- boxstack = BoxStack::getInstance();
-
- clockRegion.x = 400;
- clockRegion.y = 0;
- clockRegion.w = 60;
- clockRegion.h = 30;
-
- setSize(460, 220);
- createBuffer();
- if (Video::getInstance()->getFormat() == Video::PAL)
- {
- setPosition(140, 170);
- }
- else
- {
- setPosition(130, 140);
- }
-
- setTitleBarOn(1);
- setTitleBarColour(Colour::TITLEBARBACKGROUND);
-
- sl.setPosition(20, 40);
- sl.setSize(200, 160);
- add(&sl);
-
- setTitleText(tr("Welcome"));
- sl.addOption(tr("1. Live TV"), 1, 1);
- sl.addOption(tr("2. Radio"), 2, 0);
- sl.addOption(tr("3. Recordings"), 3, 0);
- sl.addOption(tr("4. Timers"), 4, 0);
-#ifndef _MIPS_ARCH
-#ifndef WIN32
- sl.addOption(tr("5. MediaPlayer"), 5, 0);
-#endif
-#endif
- sl.addOption(tr("6. Options"), 6, 0);
-#ifndef _MIPS_ARCH
- sl.addOption(tr("7. Reboot"), 7, 0);
-#else
- sl.addOption(tr("7. Exit to Gaya"), 7, 0);
-#endif
-
- jpeg.setPosition(240, 60);
-#ifndef _MIPS_ARCH
- jpeg.init("/vdr.jpg");
-#else
- jpeg.init("vdr.jpg");
-#endif
- add(&jpeg);
-}
-
-void VWelcome::preDelete()
-{
- Timers::getInstance()->cancelTimer(this, 1);
-}
-
-VWelcome::~VWelcome()
-{
-}
-
-void VWelcome::draw()
-{
- TBBoxx::draw();
- drawClock();
-}
-
-void VWelcome::drawClock()
-{
- // Blank the area first
- rectangle(area.w - 60, 0, 60, 30, titleBarColour);
-
- char timeString[20];
- time_t t;
- time(&t);
- struct tm* tms = localtime(&t);
- strftime(timeString, 19, "%H:%M", tms);
- drawTextRJ(timeString, 450, 5, Colour::LIGHTTEXT);
-
- time_t dt = 60 - (t % 60); // seconds to the next minute
- if (dt == 0) dt = 60; // advance a whole minute if necessary
- dt += t; // get a time_t value for it rather than using duration
- // (so it will occur at the actual second and not second and a half)
-
- Timers::getInstance()->setTimerT(this, 1, dt);
-}
-
-void VWelcome::timercall(int clientReference)
-{
- drawClock();
- boxstack->update(this, &clockRegion);
-}
-
-int VWelcome::handleCommand(int command)
-{
- switch(command)
- {
- case Remote::DF_UP:
- case Remote::UP:
- {
- sl.up();
- sl.draw();
- boxstack->update(this);
- return 2;
- }
- case Remote::DF_DOWN:
- case Remote::DOWN:
- {
- sl.down();
- sl.draw();
- boxstack->update(this);
- return 2;
- }
- case Remote::ONE:
- {
- doChannelsList();
- return 2;
- }
- case Remote::TWO:
- {
- doRadioList();
- return 2;
- }
- case Remote::THREE:
- {
- doRecordingsList();
- return 2;
- }
- case Remote::FOUR:
- {
- doTimersList();
- return 2;
- }
- case Remote::FIVE:
- {
- doMediaList();
- return 2;
- }
- case Remote::SIX:
- {
- doOptions();
- return 2;
- }
- case Remote::SEVEN:
- {
- Command::getInstance()->doReboot();
- }
- case Remote::OK:
- {
- ULONG option = sl.getCurrentOptionData();
- if (option == 1)
- {
- doChannelsList();
- return 2;
- }
- else if (option == 2)
- {
- doRadioList();
- return 2;
- }
- else if (option == 3)
- {
- doRecordingsList();
- return 2;
- }
- else if (option == 4)
- {
- doTimersList();
- return 2;
- }
- else if (option == 5)
- {
- doMediaList();
- return 2;
- }
- else if (option == 6)
- {
- doOptions();
- return 2;
- }
- else if (option == 7)
- {
- Command::getInstance()->doReboot();
- return 2;
- }
- return 2; // never gets here
- }
-//#ifdef DEV
- case Remote::NINE:
- {
- VScreensaver* vscreensaver = new VScreensaver();
- boxstack->add(vscreensaver);
- vscreensaver->draw();
-// boxstack->update(vscreensaver);
-
- return 2;
- }
-//#endif
-
- // Test
-// case Remote::BACK:
-// {
-// return 4;
-// }
-
- }
- return 1;
-}
-
-void VWelcome::doChannelsList()
-{
- ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO);
-
- if (chanList)
- {
- VChannelList* vchan = new VChannelList(VDR::VIDEO);
- vchan->setList(chanList);
-
- vchan->draw();
- boxstack->add(vchan);
- boxstack->update(vchan);
- }
- else
- {
- Command::getInstance()->connectionLost();
- }
-}
-
-void VWelcome::doRadioList()
-{
- ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::RADIO);
-
- if (chanList)
- {
- VChannelList* vchan = new VChannelList(VDR::RADIO);
- vchan->setList(chanList);
-
- vchan->draw();
- boxstack->add(vchan);
- boxstack->update(vchan);
- }
- else
- {
- Command::getInstance()->connectionLost();
- }
-}
-
-void VWelcome::doRecordingsList()
-{
- VRecordingList* vrec = new VRecordingList();
- vrec->draw();
- boxstack->add(vrec);
- boxstack->update(vrec);
-
- if (!vrec->load())
- {
- Command::getInstance()->connectionLost();
- }
-}
-
-void VWelcome::doMediaList()
-{
- VMediaList::createList();
-}
-
-void VWelcome::doTimersList()
-{
- VTimerList* vtl = new VTimerList();
- if (!vtl->load())
- {
- delete vtl;
- Command::getInstance()->connectionLost();
- return;
- }
-
- vtl->draw();
- boxstack->add(vtl);
- boxstack->update(vtl);
-}
-
-void VWelcome::doOptions()
-{
-// VOptionsMenu* voptionsmenu = new VOptionsMenu();
-// voptionsmenu->draw();
-// boxstack->add(voptionsmenu);
-// boxstack->updateView(voptionsmenu);
-
- VOpts* vopts = new VOpts();
- vopts->draw();
- boxstack->add(vopts);
- boxstack->update(vopts);
-}
-
-void VWelcome::processMessage(Message* m)
-{
- if (m->message == Message::MOUSE_MOVE)
- {
- if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
- {
- sl.draw();
- 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
- }
- }
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "vwelcome.h"\r
+\r
+#include "remote.h"\r
+#include "vdr.h"\r
+#include "vchannellist.h"\r
+#include "vrecordinglist.h"\r
+#include "vtimerlist.h"\r
+#include "command.h"\r
+#include "message.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "i18n.h"\r
+#include "timers.h"\r
+#include "vscreensaver.h"\r
+#include "vmedialist.h"\r
+#include "boxstack.h"\r
+#include "vopts.h"\r
+\r
+#include "log.h"\r
+\r
+VWelcome::VWelcome()\r
+{\r
+ boxstack = BoxStack::getInstance();\r
+\r
+ clockRegion.x = 400;\r
+ clockRegion.y = 0;\r
+ clockRegion.w = 60;\r
+ clockRegion.h = 30;\r
+\r
+ setSize(460, 220);\r
+ createBuffer();\r
+ if (Video::getInstance()->getFormat() == Video::PAL)\r
+ {\r
+ setPosition(140, 170);\r
+ }\r
+ else\r
+ {\r
+ setPosition(130, 140);\r
+ }\r
+\r
+ setTitleBarOn(1);\r
+ setTitleBarColour(Colour::TITLEBARBACKGROUND);\r
+\r
+ sl.setPosition(20, 40);\r
+ sl.setSize(200, 160);\r
+ add(&sl);\r
+\r
+ setTitleText(tr("Welcome"));\r
+ sl.addOption(tr("1. Live TV"), 1, 1);\r
+ sl.addOption(tr("2. Radio"), 2, 0);\r
+ sl.addOption(tr("3. Recordings"), 3, 0);\r
+ sl.addOption(tr("4. Timers"), 4, 0);\r
+#ifdef VOMP_PLATTFORM_MVP\r
+ sl.addOption(tr("5. MediaPlayer"), 5, 0);\r
+#endif\r
+\r
+ sl.addOption(tr("6. Options"), 6, 0);\r
+#ifdef VOMP_PLATTFORM_MVP\r
+ sl.addOption(tr("7. Reboot"), 7, 0);\r
+#else\r
+ sl.addOption(tr("7. Exit"), 7, 0);\r
+#endif\r
+\r
+ jpeg.setPosition(240, 60);\r
+#ifndef _MIPS_ARCH \r
+ jpeg.init("/vdr.jpg");\r
+#else\r
+ jpeg.init("vdr.jpg");\r
+#endif\r
+ add(&jpeg);\r
+}\r
+\r
+void VWelcome::preDelete()\r
+{\r
+ Timers::getInstance()->cancelTimer(this, 1);\r
+}\r
+\r
+VWelcome::~VWelcome()\r
+{\r
+}\r
+\r
+void VWelcome::draw()\r
+{\r
+ Log::getInstance()->log("VWelcome", Log::DEBUG, "Mark1");\r
+ TBBoxx::draw();\r
+ Log::getInstance()->log("VWelcome", Log::DEBUG, "Mark2");\r
+ drawClock();\r
+ Log::getInstance()->log("VWelcome", Log::DEBUG, "Mark3");\r
+}\r
+\r
+void VWelcome::drawClock()\r
+{\r
+ // Blank the area first\r
+ rectangle(area.w - 60, 0, 60, 30, titleBarColour);\r
+\r
+ char timeString[20];\r
+ time_t t;\r
+ time(&t);\r
+ struct tm* tms = localtime(&t);\r
+ strftime(timeString, 19, "%H:%M", tms);\r
+ drawTextRJ(timeString, 450, 5, Colour::LIGHTTEXT);\r
+\r
+ time_t dt = 60 - (t % 60); // seconds to the next minute\r
+ if (dt == 0) dt = 60; // advance a whole minute if necessary\r
+ dt += t; // get a time_t value for it rather than using duration\r
+ // (so it will occur at the actual second and not second and a half)\r
+\r
+ Timers::getInstance()->setTimerT(this, 1, dt);\r
+}\r
+\r
+void VWelcome::timercall(int clientReference)\r
+{\r
+ drawClock();\r
+ boxstack->update(this, &clockRegion);\r
+}\r
+\r
+int VWelcome::handleCommand(int command)\r
+{\r
+ switch(command)\r
+ {\r
+ case Remote::DF_UP:\r
+ case Remote::UP:\r
+ {\r
+ sl.up();\r
+ sl.draw();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::DF_DOWN:\r
+ case Remote::DOWN:\r
+ {\r
+ sl.down();\r
+ sl.draw();\r
+ boxstack->update(this);\r
+ return 2;\r
+ }\r
+ case Remote::ONE:\r
+ {\r
+ doChannelsList();\r
+ return 2;\r
+ }\r
+ case Remote::TWO:\r
+ {\r
+ doRadioList();\r
+ return 2;\r
+ }\r
+ case Remote::THREE:\r
+ {\r
+ doRecordingsList();\r
+ return 2;\r
+ }\r
+ case Remote::FOUR:\r
+ {\r
+ doTimersList();\r
+ return 2;\r
+ }\r
+ case Remote::FIVE:\r
+ {\r
+#ifdef VOMP_PLATTFORM_MVP\r
+ doMediaList();\r
+#endif\r
+ return 2;\r
+ }\r
+ case Remote::SIX:\r
+ {\r
+ doOptions();\r
+ return 2;\r
+ }\r
+ case Remote::SEVEN:\r
+ {\r
+ Command::getInstance()->doReboot();\r
+ }\r
+ case Remote::OK:\r
+ {\r
+ ULONG option = sl.getCurrentOptionData();\r
+ if (option == 1)\r
+ {\r
+ doChannelsList();\r
+ return 2;\r
+ }\r
+ else if (option == 2)\r
+ {\r
+ doRadioList();\r
+ return 2;\r
+ }\r
+ else if (option == 3)\r
+ {\r
+ doRecordingsList();\r
+ return 2;\r
+ }\r
+ else if (option == 4)\r
+ {\r
+ doTimersList();\r
+ return 2;\r
+ }\r
+ else if (option == 5)\r
+ {\r
+ doMediaList();\r
+ return 2;\r
+ }\r
+ else if (option == 6)\r
+ {\r
+ doOptions();\r
+ return 2;\r
+ }\r
+ else if (option == 7)\r
+ {\r
+ Command::getInstance()->doReboot();\r
+ return 2;\r
+ }\r
+ return 2; // never gets here\r
+ }\r
+//#ifdef DEV\r
+ case Remote::NINE:\r
+ {\r
+ VScreensaver* vscreensaver = new VScreensaver();\r
+ boxstack->add(vscreensaver);\r
+ vscreensaver->draw();\r
+// boxstack->update(vscreensaver);\r
+\r
+ return 2;\r
+ }\r
+//#endif\r
+\r
+ // Test\r
+// case Remote::BACK:\r
+// {\r
+// return 4;\r
+// }\r
+\r
+ }\r
+ return 1;\r
+}\r
+\r
+void VWelcome::doChannelsList()\r
+{\r
+ ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO);\r
+\r
+ if (chanList)\r
+ {\r
+ VChannelList* vchan = new VChannelList(VDR::VIDEO);\r
+ vchan->setList(chanList);\r
+\r
+ vchan->draw();\r
+ boxstack->add(vchan);\r
+ boxstack->update(vchan);\r
+ }\r
+ else\r
+ {\r
+ Command::getInstance()->connectionLost();\r
+ }\r
+}\r
+\r
+void VWelcome::doRadioList()\r
+{\r
+ ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::RADIO);\r
+\r
+ if (chanList)\r
+ {\r
+ VChannelList* vchan = new VChannelList(VDR::RADIO);\r
+ vchan->setList(chanList);\r
+\r
+ vchan->draw();\r
+ boxstack->add(vchan);\r
+ boxstack->update(vchan);\r
+ }\r
+ else\r
+ {\r
+ Command::getInstance()->connectionLost();\r
+ }\r
+}\r
+\r
+void VWelcome::doRecordingsList()\r
+{\r
+ VRecordingList* vrec = new VRecordingList();\r
+ vrec->draw();\r
+ boxstack->add(vrec);\r
+ boxstack->update(vrec);\r
+\r
+ if (!vrec->load())\r
+ {\r
+ Command::getInstance()->connectionLost();\r
+ }\r
+}\r
+\r
+void VWelcome::doMediaList()\r
+{\r
+#ifdef VOMP_MEDIAPLAYER\r
+ VMediaList::createList();\r
+#endif\r
+}\r
+\r
+void VWelcome::doTimersList()\r
+{\r
+ VTimerList* vtl = new VTimerList();\r
+ if (!vtl->load())\r
+ {\r
+ delete vtl;\r
+ Command::getInstance()->connectionLost();\r
+ return;\r
+ }\r
+ \r
+ vtl->draw();\r
+ boxstack->add(vtl);\r
+ boxstack->update(vtl);\r
+}\r
+\r
+void VWelcome::doOptions()\r
+{\r
+// VOptionsMenu* voptionsmenu = new VOptionsMenu();\r
+// voptionsmenu->draw();\r
+// boxstack->add(voptionsmenu);\r
+// boxstack->updateView(voptionsmenu);\r
+\r
+ VOpts* vopts = new VOpts();\r
+ vopts->draw();\r
+ boxstack->add(vopts);\r
+ boxstack->update(vopts);\r
+}\r
+\r
+void VWelcome::processMessage(Message* m)\r
+{\r
+ if (m->message == Message::MOUSE_MOVE)\r
+ {\r
+ if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ sl.draw();\r
+ boxstack->update(this);\r
+ }\r
+ }\r
+ else if (m->message == Message::MOUSE_LBDOWN)\r
+ {\r
+ if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+ {\r
+ boxstack->handleCommand(Remote::OK); //simulate OK press\r
+ }\r
+ }\r
+}\r
#include "wselectlist.h"
#include "wjpeg.h"
#include "region.h"
+#include "defines.h"
class Message;
class BoxStack;
private:
WSelectList sl;
- WJpeg jpeg;
+ WJpegTYPE jpeg;
BoxStack* boxstack;
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "wbutton.h"
-
-#include "colour.h"
-
-WButton::WButton()
-{
- int fontHeight = Surface::getFontHeight();
- setSize(70, fontHeight);
-
- mytext = NULL;
- active = 0;
- tag = 0;
- dimmed = false;
-}
-
-WButton::~WButton()
-{
- if (mytext) delete[] mytext;
-}
-
-void WButton::setText(const char* takeText)
-{
- int length = strlen(takeText);
- mytext = new char[length + 1];
- strcpy(mytext, takeText);
-}
-
-void WButton::setActive(UCHAR tactive)
-{
- dimmed = false;
- active = tactive;
-}
-
-void WButton::dim()
-{
- // a bolt on for now - an active but dimmed state
- dimmed = true;
- active = false;
-}
-
-void WButton::draw()
-{
- if (dimmed)
- {
- fillColour(Colour::BLACK);
- drawTextCentre(mytext, area.w / 2, 0, Colour::SELECTHIGHLIGHT);
- }
- else if (active)
- {
- fillColour(Colour::SELECTHIGHLIGHT);
- drawTextCentre(mytext, area.w / 2, 0, Colour::DARKTEXT);
- }
- else
- {
- fillColour(Colour::BUTTONBACKGROUND);
- drawTextCentre(mytext, area.w / 2, 0, Colour::LIGHTTEXT);
- }
-}
-
-void WButton::setTag(int newTag)
-{
- tag = newTag;
-}
-
-int WButton::getTag()
-{
- return tag;
-}
-
-// Sorry, I've broken these in the boxx upgrade - chris
-
-bool WButton::mouseMove(int x, int y)
-{
- if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0
- && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && !active)
- {
- setActive(1);
- return true;
- }
- return false;
-}
-
-bool WButton::mouseLBDOWN(int x, int y)
-{
- if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0
- && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && active)
- {
- return true;
- }
- return false;
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "wbutton.h"\r
+\r
+#include "colour.h"\r
+\r
+WButton::WButton()\r
+{\r
+\r
+ setSize(70, 21/*fontHeight*/);\r
+\r
+ mytext = NULL;\r
+ active = 0;\r
+ tag = 0;\r
+ dimmed = false;\r
+}\r
+\r
+WButton::~WButton()\r
+{\r
+ if (mytext) delete[] mytext;\r
+}\r
+\r
+void WButton::setText(const char* takeText)\r
+{\r
+ int length = strlen(takeText);\r
+ mytext = new char[length + 1];\r
+ strcpy(mytext, takeText);\r
+}\r
+\r
+void WButton::setActive(UCHAR tactive)\r
+{\r
+ dimmed = false;\r
+ active = tactive;\r
+}\r
+\r
+void WButton::dim()\r
+{\r
+ // a bolt on for now - an active but dimmed state\r
+ dimmed = true;\r
+ active = false;\r
+}\r
+\r
+void WButton::draw()\r
+{\r
+ if (dimmed)\r
+ {\r
+ fillColour(Colour::BLACK);\r
+ drawTextCentre(mytext, area.w / 2, 0, Colour::SELECTHIGHLIGHT);\r
+ }\r
+ else if (active)\r
+ {\r
+ fillColour(Colour::SELECTHIGHLIGHT);\r
+ drawTextCentre(mytext, area.w / 2, 0, Colour::DARKTEXT);\r
+ }\r
+ else\r
+ {\r
+ fillColour(Colour::BUTTONBACKGROUND);\r
+ drawTextCentre(mytext, area.w / 2, 0, Colour::LIGHTTEXT);\r
+ }\r
+}\r
+\r
+void WButton::setTag(int newTag)\r
+{\r
+ tag = newTag;\r
+}\r
+\r
+int WButton::getTag()\r
+{\r
+ return tag;\r
+}\r
+\r
+// Sorry, I've broken these in the boxx upgrade - chris\r
+\r
+bool WButton::mouseMove(int x, int y)\r
+{\r
+ if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0\r
+ && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && !active)\r
+ {\r
+ setActive(1);\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+bool WButton::mouseLBDOWN(int x, int y)\r
+{\r
+ if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0\r
+ && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && active)\r
+ {\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
{
public:
WButton();
- ~WButton();
+ virtual ~WButton();
void setText(const char* text);
void setActive(UCHAR tactive);
void dim();
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-#include "boxx.h"
-#include "wjpeg.h"
-#include <setjmp.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifndef WIN32
-#include <unistd.h>
-#else
-
-#endif
-
-#include "i18n.h"
-#include "log.h"
-#include "surface.h"
-extern "C"
-{
- #include <jpeglib.h>
-}
-
-
-//#define USE_BUFFER
-//#define EXTENDED_JPEGLIB
-
-//a struct to store user data for the jpeg decompressor
-class jpegUserData{
- public:
- WJpeg::JpegControl * ctl;
- JpegReader *reader;
- jpegUserData() {
- ctl=NULL;
- reader=NULL;
- }
- };
-
-//the scale factors supported by the jpeg lib
-
-struct scale{
- UINT num;
- UINT denom;
-};
-
-
-struct scale jpegFactors[]={
-#ifndef EXTENDED_JPEGLIB
- {1,1},{1,2},{1,4},{1,8}
-#else
- {1,1},{7,8},{3,4},{5,8},{1,2},{3,8},{1,4},{1,8}
-#endif
-};
-
-
-#ifdef WIN32
-#define LocalReader WindowsResourceJpegReader
-class WindowsResourceJpegReader: public JpegReader {
- public:
- virtual ULONG initRead(const char *filename);
- virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
- virtual ULONG getSize();
- virtual ~WindowsResourceJpegReader();
-protected:
- HGLOBAL hres;
- LPVOID buffer;
- DWORD size;
-};
-
-ULONG WindowsResourceJpegReader::initRead(const char *filename)
-{
- HRSRC res=FindResource(NULL,filename,RT_RCDATA);
- hres=LoadResource(NULL,res);
- buffer=LockResource(hres);
- size=SizeofResource(NULL,res);
- //CloseHandle(hres);
- return size;
-}
-
- ULONG WindowsResourceJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
-{
- if (offset>size) return 0;
- ULONG toread=min(size-offset,len);
- char* buffy=(char*)malloc(toread);
- memcpy(buffy,((char*)buffer)+offset,toread);
- *buf=buffy;
- return toread;
-}
-
- WindowsResourceJpegReader::~WindowsResourceJpegReader(){
- buffer=NULL;
- size=0;
- FreeResource(hres);
- }
-
- ULONG WindowsResourceJpegReader::getSize(){
- return (ULONG)size;
-}
-#else
-
-#define LocalReader LocalJpegReader
-class LocalJpegReader: public JpegReader {
- public:
- virtual ULONG initRead(const char *filename);
- virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
- virtual ~LocalJpegReader();
- virtual ULONG getSize();
- LocalJpegReader();
-protected:
- FILE *file;
- ULONG size;
-};
-
-LocalJpegReader::LocalJpegReader(){
- file=NULL;
- size=0;
-}
-
-ULONG LocalJpegReader::initRead(const char *filename)
-{
- if (file) fclose(file);
- size=0;
- file=fopen(filename,"r");
- if (file) {
- struct stat st;
- if (fstat(fileno(file), &st) != 0) return 0;
- size= st.st_size;
- return size;
- }
- Log::getInstance()->log("WJepg", Log::ERR, "localReader unable to open File %s", filename);
- return 0;
-}
-
-ULONG LocalJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
-{
- *buf=NULL;
- ULONG bread=0;
- if (file) {
- ULLONG cpos=ftell(file);
- if (offset != cpos) {
- fseek(file,offset-cpos,SEEK_CUR);
- }
- if (offset != (ULONG)ftell(file)) {
- Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
- }
- else {
- *buf=(char *)malloc(len);
- if ( ! (*buf)) {
- Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
- }
- else {
- bread=fread(*buf,1,len,file);
- }
- }
- }
- return bread;
-}
-
-LocalJpegReader::~LocalJpegReader(){
- if (file) fclose(file);
- file=NULL;
-}
-ULONG LocalJpegReader::getSize(){
- return size;
-}
-#endif
-
-/*----------------------------------------------------------------
- the jpeg lib routines
- ----------------------------------------------------------------
- */
-
-extern "C" {
-
-
-struct my_error_mgr {
- struct jpeg_error_mgr pub; /* "public" fields */
-
- jmp_buf setjmp_buffer; /* for return to caller */
-};
-
-typedef struct my_error_mgr * my_error_ptr;
-
-/*
- * Here's the routine that will replace the standard error_exit method:
- */
-
-METHODDEF(void)
-my_error_exit (j_common_ptr cinfo)
-{
- /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
- my_error_ptr myerr = (my_error_ptr) cinfo->err;
-
- /* Always display the message. */
- /* We could postpone this until after returning, if we chose. */
- (*cinfo->err->output_message) (cinfo);
- /* Return control to the setjmp point */
- longjmp(myerr->setjmp_buffer, 1);
-}
-
-ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {
- jpegUserData *user=(jpegUserData *)cb;
- return user->reader->readChunk(offset,size,buf);
-}
-//the memory buffer reader for the jpeg lib
-//taken from jdatasrc.c
-
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jerror.h"
-
-
-typedef struct {
- struct jpeg_source_mgr pub; /* public fields */
-
- JOCTET * buffer; /* start of buffer */
- boolean start_of_file; /* have we gotten any data yet? */
- void * userdata; /* used for callback */
- ULONG offset;
-} my_source_mgr;
-
-typedef my_source_mgr * my_src_ptr;
-
-#define INPUT_BUF_SIZE (64*4096) /* choose an efficiently fread'able size */
-
-
-/*
- * Initialize source --- called by jpeg_read_header
- * before any data is actually read.
- */
-
-METHODDEF(void)
-linit_source (j_decompress_ptr cinfo)
-{
- my_src_ptr src = (my_src_ptr) cinfo->src;
-
- /* We reset the empty-input-file flag for each image,
- * but we don't clear the input buffer.
- * This is correct behavior for reading a series of images from one source.
- */
- src->start_of_file = TRUE;
- src->offset=0;
-}
-
-
-/*
- * Fill the input buffer --- called whenever buffer is emptied.
- *
- * In typical applications, this should read fresh data into the buffer
- * (ignoring the current state of next_input_byte & bytes_in_buffer),
- * reset the pointer & count to the start of the buffer, and return TRUE
- * indicating that the buffer has been reloaded. It is not necessary to
- * fill the buffer entirely, only to obtain at least one more byte.
- *
- * There is no such thing as an EOF return. If the end of the file has been
- * reached, the routine has a choice of ERREXIT() or inserting fake data into
- * the buffer. In most cases, generating a warning message and inserting a
- * fake EOI marker is the best course of action --- this will allow the
- * decompressor to output however much of the image is there. However,
- * the resulting error message is misleading if the real problem is an empty
- * input file, so we handle that case specially.
- *
- * In applications that need to be able to suspend compression due to input
- * not being available yet, a FALSE return indicates that no more data can be
- * obtained right now, but more may be forthcoming later. In this situation,
- * the decompressor will return to its caller (with an indication of the
- * number of scanlines it has read, if any). The application should resume
- * decompression after it has loaded more data into the input buffer. Note
- * that there are substantial restrictions on the use of suspension --- see
- * the documentation.
- *
- * When suspending, the decompressor will back up to a convenient restart point
- * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
- * indicate where the restart point will be if the current call returns FALSE.
- * Data beyond this point must be rescanned after resumption, so move it to
- * the front of the buffer rather than discarding it.
- */
-
-METHODDEF(boolean)
-lfill_input_buffer (j_decompress_ptr cinfo)
-{
- my_src_ptr src = (my_src_ptr) cinfo->src;
- size_t nbytes;
- if (src->buffer) free(src->buffer);
- src->buffer=NULL;
- nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);
-
- if (nbytes <= 0) {
- WARNMS(cinfo, JWRN_JPEG_EOF);
- src->buffer = (JOCTET *)malloc(2);
- src->buffer[0] = (JOCTET) 0xFF;
- src->buffer[1] = (JOCTET) JPEG_EOI;
- nbytes = 2;
-
- }
- src->offset+=nbytes;
-
- src->pub.next_input_byte = src->buffer;
- src->pub.bytes_in_buffer = nbytes;
- src->start_of_file = FALSE;
-
- return TRUE;
-}
-
-
-/*
- * Skip data --- used to skip over a potentially large amount of
- * uninteresting data (such as an APPn marker).
- *
- * Writers of suspendable-input applications must note that skip_input_data
- * is not granted the right to give a suspension return. If the skip extends
- * beyond the data currently in the buffer, the buffer can be marked empty so
- * that the next read will cause a fill_input_buffer call that can suspend.
- * Arranging for additional bytes to be discarded before reloading the input
- * buffer is the application writer's problem.
- */
-
-METHODDEF(void)
-lskip_input_data (j_decompress_ptr cinfo, long num_bytes)
-{
- my_src_ptr src = (my_src_ptr) cinfo->src;
-
- /* Just a dumb implementation for now. Could use fseek() except
- * it doesn't work on pipes. Not clear that being smart is worth
- * any trouble anyway --- large skips are infrequent.
- */
- if (num_bytes > 0) {
- while (num_bytes > (long) src->pub.bytes_in_buffer) {
- num_bytes -= (long) src->pub.bytes_in_buffer;
- (void) lfill_input_buffer(cinfo);
- /* note we assume that fill_input_buffer will never return FALSE,
- * so suspension need not be handled.
- */
- }
- src->pub.next_input_byte += (size_t) num_bytes;
- src->pub.bytes_in_buffer -= (size_t) num_bytes;
- }
-}
-
-
-/*
- * An additional method that can be provided by data source modules is the
- * resync_to_restart method for error recovery in the presence of RST markers.
- * For the moment, this source module just uses the default resync method
- * provided by the JPEG library. That method assumes that no backtracking
- * is possible.
- */
-
-
-/*
- * Terminate source --- called by jpeg_finish_decompress
- * after all data has been read. Often a no-op.
- *
- * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
- * application must deal with any cleanup that should happen even
- * for error exit.
- */
-
-METHODDEF(void)
-lterm_source (j_decompress_ptr cinfo)
-{
- /* no work necessary here */
-}
-
-
-/*
- * Prepare for input from a stdio stream.
- * The caller must have already opened the stream, and is responsible
- * for closing it after finishing decompression.
- */
-
-extern "C" void
-jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)
-{
- my_src_ptr src;
-
- /* The source object and input buffer are made permanent so that a series
- * of JPEG images can be read from the same file by calling jpeg_stdio_src
- * only before the first one. (If we discarded the buffer at the end of
- * one image, we'd likely lose the start of the next one.)
- * This makes it unsafe to use this manager and a different source
- * manager serially with the same JPEG object. Caveat programmer.
- */
- if (cinfo->src == NULL) { /* first time for this JPEG object? */
- cinfo->src = (struct jpeg_source_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- SIZEOF(my_source_mgr));
- src = (my_src_ptr) cinfo->src;
- src->buffer = NULL;
- }
-
- src = (my_src_ptr) cinfo->src;
- src->pub.init_source = linit_source;
- src->pub.fill_input_buffer = lfill_input_buffer;
- src->pub.skip_input_data = lskip_input_data;
- src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
- src->pub.term_source = lterm_source;
- src->userdata=userdata;
- src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
- src->pub.next_input_byte = NULL; /* until buffer loaded */
- src->offset=0;
- src->userdata=userdata;
- if (src->buffer) {
- free(src->buffer);
- src->buffer=NULL;
- }
-}
-/* cleanup to be called before cleanup of cinfo*/
-extern "C" void
-jpeg_memio_cleanup (j_decompress_ptr cinfo) {
- my_src_ptr src=(my_src_ptr)cinfo->src;
- Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));
- if (src && src->buffer) {
- free(src->buffer);
- src->buffer=NULL;
- }
-}
-
-//taken from mvpmc
-//http://git.mvpmc.org/cgi-bin/gitweb.cgi?p=mvpmc.git;a=blob_plain;h=02d4354c0cbbed802a9aa1478918a49fcbf61d00;f=libs/libwidget/image_jpeg.c
-
-#define GET2BYTES(cinfo, V, swap, offset) do { \
- if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
- cinfo->src->bytes_in_buffer--; \
- V = (*cinfo->src->next_input_byte++) << (swap?0:8); \
- if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
- cinfo->src->bytes_in_buffer--; \
- V += (*cinfo->src->next_input_byte++) << (swap?8:0); \
- offset += 2; } while(0)
-
-#define GET4BYTES(cinfo, V, swap, offset) do { \
- if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
- cinfo->src->bytes_in_buffer--; \
- V = (*cinfo->src->next_input_byte++) << (swap?0:24); \
- if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
- cinfo->src->bytes_in_buffer--; \
- V += (*cinfo->src->next_input_byte++) << (swap?8:16); \
- if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
- cinfo->src->bytes_in_buffer--; \
- V += (*cinfo->src->next_input_byte++) << (swap?16:8); \
- if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
- cinfo->src->bytes_in_buffer--; \
- V += (*cinfo->src->next_input_byte++) << (swap?24:0); \
- offset += 4; } while(0)
-
-static boolean
-get_exif_orient (j_decompress_ptr cinfo)
-/* Get the Exif orientation info */
-{
- unsigned int tmp, offset, length, numtags;
- int orient=-1;
- jpegUserData * ud=0;
- boolean swap;
- orient = 1;
- offset = 0;
- my_src_ptr mysrc = (my_src_ptr) cinfo->src;
-
- /* marker length */
- GET2BYTES(cinfo, length, 0, offset);
- if (length<8) goto err;
- /* Exif header */
- GET4BYTES(cinfo, tmp, 0, offset);
- if (tmp != 0x45786966) goto err;
- GET2BYTES(cinfo, tmp, 0, offset);
- if (tmp != 0x0000) goto err;
- /* Byte-order */
- GET2BYTES(cinfo, tmp, 0, offset);
- if (tmp == 0x4949) swap = 1;
- else if (tmp == 0x4d4d) swap = 0;
- else goto err;
- GET2BYTES(cinfo, tmp, swap, offset);
- if (tmp != 0x002A) goto err;
- /* offset to first IFD */
- GET4BYTES(cinfo, tmp, swap, offset);
- offset += tmp-8;
- (*mysrc->pub.skip_input_data)(cinfo, tmp-8);
- /* number of tags in IFD */
- GET2BYTES(cinfo, numtags, swap, offset);
- if (numtags == 0) goto err;
-
- /* Search for Orientation Tag in IFD0 */
- for (;;) {
- if (offset > length-12) goto err;
- GET2BYTES(cinfo, tmp, swap, offset);
- if (tmp == 0x0112) break; /* found Orientation Tag */
- if (--numtags == 0) goto err;
- offset += 10;
- (*mysrc->pub.skip_input_data)(cinfo, 10);
- }
- offset += 6;
- (*mysrc->pub.skip_input_data)(cinfo, 6);
- GET2BYTES(cinfo, orient, swap, offset);
- if( orient==0 || orient>8 ) orient = 1;
-
- Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);
- ud=(jpegUserData *)(mysrc->userdata);
- switch(orient) {
- case 3:
- ud->ctl->exifRotation=WJpeg::ROT_180;
- break;
- case 6:
- ud->ctl->exifRotation=WJpeg::ROT_90;
- break;
- case 8:
- ud->ctl->exifRotation=WJpeg::ROT_270;
- break;
- }
-
-err:
- (*mysrc->pub.skip_input_data)(cinfo, length-offset);
- return TRUE;
-}
-}
-
-/*----------------------------------------------------------------
- the implementation
- ----------------------------------------------------------------
- */
-
-
-WJpeg::WJpeg(){
- reader=NULL;
- owningReader=false;
- errbuf[0]=0;
-}
-
-WJpeg::~WJpeg() {
- if (owningReader && reader) delete reader;
-}
-
-int WJpeg::init(char* tfileName)
-{
- if (owningReader && reader) delete reader;
- errbuf[0]=0; //clean error state
- LocalReader *myreader=new LocalReader();
- reader=myreader;
- owningReader=true;
- ULONG psize=myreader->initRead(tfileName);
- if (psize == 0) {
- delete reader;
- reader=NULL;
- owningReader=false;
- SNPRINTF(errbuf,200,"unable to open %s",tfileName);
- return 0;
- }
- return 1;
-}
-
-
-
-
-bool WJpeg::hasError() {
- return (errbuf[0] != 0);
-}
-void WJpeg::draw()
-{
- bool ok=false;
- JpegControl ctl;
- if (reader) {
- Region myRegion;
- Surface *sfc=getSurface(myRegion);
- myRegion.w=area.w;
- myRegion.h=area.h;
- ctl.area=myRegion;
- ctl.enlarge=true;
- if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;
- }
- else {
- SNPRINTF(errbuf,200,"jpeg reader not initialized");
- }
- if (! ok) {
- drawTextCentre(tr("Jpeg ERROR"), 240, 170, Colour::LIGHTTEXT);
- if (errbuf[0] != 0) drawTextCentre(errbuf,240,200, Colour::LIGHTTEXT);
- if (ctl.error[0] != 0) drawTextCentre(ctl.error,240,230, Colour::LIGHTTEXT);
- }
-}
-
-/**
- the main drawing function
- this will read the pciture via the reader
- and draw directly into the surface
- it will compute an appropriate scale and set the infos in the
- JpegControl structure
-**/
-
-bool WJpeg::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, Colour & backgroundColour) {
- Log* logger = Log::getInstance();
- if (! rdr || ! sfc) {
- logger->log("BJpeg", Log::ERR, "JPEG error rdr=NULL or sfc=NULL");
- return false;
- }
- logger->log("BJpeg", Log::DEBUG, "draw Jpeg Started sfc=%p, rdr=%p",sfc,rdr);
- unsigned char* buffer =NULL;
- struct jpeg_decompress_struct cinfo;
- struct my_error_mgr jerr;
- cinfo.err = jpeg_std_error(&jerr.pub);
- jerr.pub.error_exit = my_error_exit;
- /* Establish the setjmp return context for my_error_exit to use. */
- if (setjmp(jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error.
- * We need to clean up the JPEG object, close the input file, and return.
- */
- if (rdr) jpeg_memio_cleanup(&cinfo);
- jpeg_destroy_decompress(&cinfo);
- logger->log("BJpeg", Log::ERR, "JPEG error");
- if (buffer) free(buffer);
- return false;
- }
- jpegUserData userdata;
- int xpos=0;
- int ypos=0;
- jpeg_create_decompress(&cinfo);
- userdata.reader=rdr;
- userdata.ctl=ctl;
- ctl->exifRotation=ROT_0;
- ctl->error[0]=0;
- ctl->exifDate[0]=0;
- //create the input for the jpeg lib
- jpeg_memio_src(&cinfo,(void *)(&userdata));
- //processor for EXIF data
- jpeg_set_marker_processor(&cinfo, JPEG_APP0+1, get_exif_orient);
- //read in header info
- jpeg_read_header(&cinfo, TRUE);
- ctl->picw=cinfo.image_width;
- ctl->pich=cinfo.image_height;
- ctl->compressedSize=rdr->getSize();
- //now we have important info available in ctl (pictuerw,h, exif orientation,size)
- //compute rotation due to the defined enum values we can simply add them
- ctl->finalRotation=(enum Rotation)((ctl->rotation+ctl->exifRotation)%4);
- logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", ctl->picw,ctl->pich,ctl->finalRotation);
- //now we have to compute the scale
- //input: ctl->picw,ctl->pich,ctl->finalRotation,ctl->mode,ctl->scaleAmount, ctl->scaleafter
- // list of available jpeg scale factors
- //out: scalenum,scaledenom,scaleafter
-
- UINT picturew=ctl->picw;
- UINT pictureh=ctl->pich;
- switch (ctl->finalRotation){
- case ROT_90:
- case ROT_270:
- pictureh=ctl->picw;
- picturew=ctl->pich;
- break;
- default:
- break;
- }
- UINT scalenum=1;
- UINT scaledenom=1;
- UINT scaleafter=1;
- if (! ctl->enlarge) {
- //scale - compute the factors to fit 100%
- int scalew=1000*picturew/ctl->area.w;
- int scaleh=1000*pictureh/ctl->area.h;
- int scale=scaleh;
- if (scalew > scaleh) scale=scalew;
-
- //OK now find out which is the optimal setting
- //rule: find settings being nearest to:
- // mode=LETTER - smaller or equal screen size (i.e. scale*scalefactor <= 1000)
- // mode=CROP - bigger or equal screen size (i.e. scale *scalefactor>= 1000)
- // mode=CROPPERCENT - smaller or equal screensize*scaleamount (i.e. scale*scalefactor<= 1000*scaleamount)
- // scaleamount is in % - so in reality we use scaleamount*10 instead scaleamount*1000
- //the scalefactor computes as scalenum/(scaledenom*scaleafter)
- scaledenom=8;
- int minDiff=1000;
- logger->log("BJpeg", Log::DEBUG, "start scaling screenw=%u, screenh=%u, pw=%u,ph=%u, scale=%d, mode=%d, %%=%u, after=%u",
- ctl->area.w,ctl->area.h,picturew,pictureh,scale,(int)ctl->mode,ctl->scaleAmount, ctl->scaleafter);
- for (UINT j=0;j<sizeof(jpegFactors)/sizeof(jpegFactors[0]);j++) {
- for (UINT sa=1;sa<=ctl->scaleafter;sa++) {
- int curf=(scale*jpegFactors[j].num)/(jpegFactors[j].denom*sa);
- bool setThis=false;
- logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,num=%u,denom=%u,after=%u,minDiff=%d",
- curf,jpegFactors[j].num,jpegFactors[j].denom,sa,minDiff);
- switch(ctl->mode) {
- case CROP:
- if (curf >= 1000 && curf < (minDiff +1000)) {
- setThis=true;
- minDiff=curf-1000;
- }
- break;
- case LETTER:
- if (curf <= 1000 && curf > (1000-minDiff)) {
- setThis=true;
- minDiff=1000-curf;
- }
- break;
- case CROPPERCENT:
- if (curf <= 10*(int)ctl->scaleAmount ) {
- int abs=curf-1000;
- if (abs < 0) abs=-abs;
- if (abs < minDiff) {
- setThis=true;
- minDiff=abs;
- }
- }
- break;
- }
- if (setThis) {
- logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);
- scalenum=jpegFactors[j].num;
- scaledenom=jpegFactors[j].denom;
- scaleafter=sa;
- }
- }
- }
- ctl->scale=100*scalenum/(scaledenom*scaleafter);
-
- logger->log("BJpeg", Log::DEBUG, "JPEG scaling found scale=%i num=%i denom=%i after=%i result=%i scale=%i%% ",
- scale,scalenum,scaledenom,scaleafter,scale*ctl->scale/100,ctl->scale);
-
- cinfo.scale_denom=scaledenom;
- cinfo.scale_num=scalenum;
- }
- else
- {
- //set drawing area according to picture
- ctl->area.w=ctl->picw;
- ctl->area.h=ctl->pich;
- }
-
- //now we know the scaling
- //compute the scaled size and position
-
- jpeg_start_decompress(&cinfo);
- //picturew/h is now the output width from the decompressor and afterscaler
- //this is unrotated
- picturew=cinfo.output_width;
- pictureh=cinfo.output_height;
- if (scaleafter > 1) {
- picturew=picturew/scaleafter;
- pictureh=pictureh/scaleafter;
- }
- //if our image is smaller - center it
- if (! ctl->enlarge) {
- if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {
- int dim=pictureh;
- xpos=(((int)ctl->area.w)-dim)/2;
- dim=picturew;
- ypos=(((int)ctl->area.h)-dim)/2;
- } else {
- int dim=picturew;
- xpos=(((int)ctl->area.w)-dim)/2;
- dim=pictureh;
- ypos=(((int)ctl->area.h)-dim)/2;
- }
- if (xpos <0) xpos=0;
- if (ypos <0) ypos=0;
- }
- xpos+=ctl->area.x;
- ypos+=ctl->area.y;
- //remember the jpeg dimensions for computing the buffer
- UINT jpegwidth=cinfo.output_width;
- UINT jpegheight=cinfo.output_height;
- logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, jw=%i, jh=%i, rot=%d",
- picturew, pictureh,xpos,ypos,jpegwidth,jpegheight,(int)ctl->finalRotation*90);
-
- //fill the background
- sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour.rgba());
-
- //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
- int linelen=jpegwidth*3;
-#ifdef USE_BUFFER
- // MAKE THE 2D ARRAY
- buffer = (unsigned char*)malloc(jpegheight * linelen);
- logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, lines = %i linelen = %i", buffer, jpegheight, linelen);
- if (buffer == NULL) {
- if (rdr) jpeg_memio_cleanup(&cinfo);
- jpeg_destroy_decompress(&cinfo);
- logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");
- SNPRINTF(ctl->error,100,"no room for buffer");
- return false;
- }
-#endif
-
-#ifndef USE_BUFFER
- //unsigned char lbuf[linelen];
- unsigned char *lbuf=new unsigned char[linelen*scaleafter];
- unsigned char * ptr=lbuf;
- UINT outy=0;
-#else
- unsigned char * ptr=buffer;
-#endif
-
- int rowsread = 0;
-
- Colour c;
- sfc->startFastDraw();//Tell the surface, that we will draw a lot of pixel,
- //so that performance, can be optimized
- logger->log("BJpeg", Log::DEBUG, "start drawing ");
- UINT colincr=0;
- //factors to base 1024
- UINT fac=1024;
- if (scaleafter > 1) {
- colincr=3*scaleafter-3;
- fac=1024/(scaleafter*scaleafter);
- }
- logger->log("BJpeg", Log::DEBUG, "jpeg draw scale %d image: %u %u, picture: %u %u", scaleafter,picturew,pictureh,jpegwidth,jpegheight);
- while (cinfo.output_scanline < jpegheight)
- {
-// logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
- rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
-#ifdef USE_BUFFER
- ptr+=linelen;
-#else
- if (scaleafter > 1) {
- if (rowsread % scaleafter != scaleafter-1) {
- //this simple approach wold maybe forget scaleafter -1 lines at the end...
- ptr+=linelen;
- continue;
- }
- ptr=lbuf;
- }
- drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);
- outy++;
-
-#endif
- }
- sfc->endFastDraw();
-
- logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
-
- jpeg_finish_decompress(&cinfo);
- jpeg_memio_cleanup(&cinfo);
- jpeg_destroy_decompress(&cinfo);
-
- logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");
- rdr->drawingDone();
-
-#ifdef USE_BUFFER
- UINT y;
- //Tell the surface, that we will draw a lot of pixel,
- //so that performance, can be optimized
- sfc->startFastDraw();
- logger->log("BJpeg", Log::DEBUG, "jpeg start buffer draw" );
- unsigned char* p=buffer; //start of first row
- UINT rowincr=linelen*scaleafter;
- //for simplicity omit last line to avoid running out of buffer
- for (y = 0; y < pictureh-1 ;y++)
- {
- drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);
- p+=rowincr;
- }
- sfc->endFastDraw();
- logger->log("BJpeg", Log::DEBUG, "end draw");
- free(buffer);
-#else
- delete[] lbuf;
-#endif
- logger->log("BJpeg", Log::DEBUG, "deleted buffer");
- return true;
-}
-
-//get my own surface
-Surface * WJpeg::getSurface(Region & r) {
- r.x=getRootBoxOffsetX();
- r.y=getRootBoxOffsetY();
- r.w=area.w;
- r.h=area.h;
- return Boxx::getSurface();
-}
-
-
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+#include "boxx.h"\r
+#include "wjpeg.h"\r
+#include <setjmp.h>\r
+#include <sys/types.h>\r
+#include <sys/stat.h>\r
+\r
+#ifndef WIN32\r
+#include <unistd.h>\r
+#else\r
+\r
+#endif\r
+\r
+#include "i18n.h"\r
+#include "log.h"\r
+#include "surface.h"\r
+\r
+\r
+/*----------------------------------------------------------------\r
+ the implementation\r
+ ----------------------------------------------------------------\r
+ */\r
+\r
+\r
+WJpeg::WJpeg(){\r
+\r
+}\r
+\r
+WJpeg::~WJpeg() {\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+void WJpeg::draw()\r
+{\r
+\r
+}\r
+\r
+\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef WJPEG_H
-#define WJPEG_H
-
-#include <stdio.h>
-#include <malloc.h>
-
-#ifdef WIN32
-
-#include <winsock2.h>
-#include <windows.h>
-
-
-//#define NEED_FAR_POINTERS
-#define XMD_H //workaround some compiling issues
-#endif
-
-class Surface;
-class Boxx;
-
-//a reader to be implemented by the caller
-class JpegReader {
- public:
- //read the next chunk of jpeg data
- //offset - from start of file
- //len I buf len (max bytes to read)
- //return read len, 0 on EOF, -1 on error, *buf set to buffer
- //will be released with free(!!!) after decoding
- virtual ULONG readChunk(ULONG offset,ULONG len,char **buf)=0;
- //a callback when the drawing is complete
- //the implementation is optional
- virtual void drawingDone(){};
- //get the size of the current picture
- virtual ULONG getSize(){ return 0;}
- virtual ~JpegReader(){};
-};
-class WJpeg : public Boxx
-{
- public:
-
- // temp for boxx
- void setDimensions(int width, int height) {area.w=width;area.h=height;};
-
-
- WJpeg();
- virtual ~WJpeg();
- //old style usage - load local file
- //the sequence is init(filename), draw
- //the new usage is drawJpeg (with having the right offsets computed)
- int init(char* fileName);
- void draw();
-
- bool hasError();
-
- //mode for scaling pictures
- enum ScaleMode {
- LETTER=0,
- CROP=1,
- CROPPERCENT=2};
- //rotations
- enum Rotation{
- ROT_0=0,
- ROT_90=1,
- ROT_180=2,
- ROT_270=3
- };
- //jpeg info
- struct JpegControl {
- public:
- //the available drawing area
- Region area;
- bool enlarge;
- //the maximum allowed scale factor after decompress
- UINT scaleafter;
- //the scale mode
- enum ScaleMode mode;
- //the size value if scaleMode==cropPercent
- //%of the drawing area size
- UINT scaleAmount;
- //the rotation (user defined as input)
- //if exif rotation is found this will be added
- enum Rotation rotation;
-
- //paremeters filled during Jpeg parsing
- enum Rotation exifRotation;
- char exifDate[30];
- char error[100];
- UINT picw;
- UINT pich;
- ULONG compressedSize;
-
- //parameters computed to display picture
- enum Rotation finalRotation;
- //scale in %
- UINT scale;
- JpegControl() {
- area.x=0;
- area.y=0;
- area.w=0;
- area.h=0;
- enlarge=false;
- scaleafter=3;
- scaleAmount=110;
- mode=CROPPERCENT;
- rotation=ROT_0;
- exifRotation=ROT_0;
- finalRotation=ROT_0;
- exifDate[0]='\0';
- error[0]='\0';
- picw=0;
- pich=0;
- compressedSize=0;
- scale=100;
- }
- };
-
- //the standalone drawing function
- //this will draw into the provided surface
- //the reader has to be initialized before
- //calling this function does not need a WJpeg being instantiated
- //it simply draws into the surface
- bool static drawJpeg(JpegControl * control, Surface* sfc, JpegReader *rdr, Colour & backgroundColour);
-
- private:
- //our drawPixel with considers rotation
- /* handle picture rotation
- 90: xr=h-y
- yr=x
- 180:xr=w-x
- yr=h-y
- 270:xr=y
- yr=w-x
- */
- inline static void drawPixel(Surface * sfc,enum Rotation rotate,int x, int y,int w,int h,int xpos, int ypos,Colour c){
- int xb=0;
- int yb=0;
- switch(rotate) {
- case ROT_0:
- xb=x;
- yb=y;
- break;
- case ROT_90:
- xb=h-y;
- yb=x;
- break;
- case ROT_180:
- xb=w-x;
- yb=h-y;
- break;
- case ROT_270:
- xb=y;
- yb=w-x;
- break;
- }
- xb+=xpos;
- yb+=ypos;
- if (xb < 0 || yb < 0 ) {
- return;
- }
- sfc->drawPixel((UINT)xb,(UINT)yb,c,true);
- }
-
- /**
- draw a line of pixels coming from the decompressor
- if scaleafter > 1 we draw that many lines (numlines is the# lines in the buffer)
- picturew is the resulting width of the picture
- **/
- inline static void drawLine(Surface *sfc,enum Rotation rotate, unsigned char *cp,UINT scaleafter,UINT picturew,UINT pictureh,
- UINT xpos, UINT ypos, UINT outy, UINT linelen,UINT pixeloffset, UINT numlines, UINT fac) {
- Colour c;
- for (UINT x = 0; x < picturew; x++)
- {
- if (scaleafter > 1 ) {
- //boxfilter scalefactor*scalefactor
- //take 0...scalefactor pixels in x and y direction
- for (int colornum=0;colornum<3;colornum++) {
- UINT comp=0;
- unsigned char * accp=cp;
- for (UINT rows=0;rows<scaleafter;rows++) {
- unsigned char * pp=accp;
- for (UINT cols=0;cols<scaleafter;cols++) {
- comp+=(UINT)*pp;
- if (pp-accp < (int)linelen-3) pp+=3;
- }
- if (rows < numlines) accp+=linelen;
- }
- comp=(comp*fac) >> 10;
- if (colornum == 0) c.red=comp;
- if (colornum == 1) c.green=comp;
- if (colornum == 2) c.blue=comp;
- cp++;
- }
-
- }
- else {
- c.red = *cp;cp++;
- c.green = *cp;cp++;
- c.blue = *cp;cp++;
- }
- cp+=pixeloffset;
- drawPixel(sfc,rotate,x, outy, picturew,pictureh,xpos,ypos,c);
- }
- }
- //find my own surface and fill the area with my x and y offset within
- Surface * getSurface(Region &a);
-
- JpegReader *reader;
- bool owningReader;
- char errbuf[200];
-};
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef WJPEG_H\r
+#define WJPEG_H\r
+\r
+#include <stdio.h>\r
+#include <malloc.h>\r
+#include "boxx.h"\r
+\r
+\r
+\r
+\r
+class WJpeg : public Boxx\r
+{\r
+ public:\r
+ \r
+ // temp for boxx\r
+ void setDimensions(int width, int height) {area.w=width;area.h=height;};\r
+ \r
+ \r
+ WJpeg();\r
+ virtual ~WJpeg();\r
+ //old style usage - load local file\r
+ //the sequence is init(filename), draw\r
+ //the new usage is drawJpeg (with having the right offsets computed)\r
+ virtual int init(const char* fileName)=0;\r
+ virtual void draw();\r
+\r
+\r
+};\r
+\r
+\r
+#if !defined(WIN32) || !defined(__ANDROID)\r
+#define WJpegTYPE WJpegSimple\r
+#include "wjpegsimple.h"\r
+#else\r
+#define WJpegTYPE WJpegComplex\r
+#include "wjpegcomplex.h"\r
+#endif\r
+\r
+#endif\r
#include <ctype.h>
#include <errno.h>
+
+
+#if !defined(__ANDROID__) && !defined(WIN32)
+#include <net/ethernet.h>
+#else
+#define ETH_ALEN 6
+#endif
+
+
#ifndef WIN32
#include <unistd.h>
-#include <net/ethernet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#else
-#define ETH_ALEN 6
-
#include <winsock2.h>
#include <errno.h>
#include <Ws2tcpip.h>
#include "woptionbox.h"
#include "colour.h"
+#include "log.h"
#ifndef WIN32
#include "unistd.h"
#endif
options = NULL;
active = 0;
currentOption = 0;
-
mode = MODE_TEXT;
textbox.setPosition(20, 0);
- textbox.setSize(10, surface->getFontHeight());
+ textbox.setSize(10, getFontHeight());
textbox.setParaMode(false);
textbox.setTextPos(0, 0);
add(&textbox);
void WOptionBox::setSize(UINT w, UINT h)
{
Boxx::setSize(w, h);
- textbox.setSize(w - 40, surface->getFontHeight());
+ textbox.setSize(w - 40, getFontHeight());
rightArrow.setPosition(w - 18, 2);
}
void WOptionPane::addOptionLine(Option* option)
{
- int fontHeight = surface->getFontHeight();
+ int fontHeight = getFontHeight();
+
options.resize(numOptions+1);
options[numOptions] = option;
-
+
WTextbox* tb = new WTextbox();
tb->setPosition(4, 4 + (numOptions * 30));
tb->setSize(300, fontHeight);
tb->setText(tr(option->displayText));
tb->setTextPos(0, 0);
add(tb);
-
+
textBoxes.resize(numOptions+1);
textBoxes[numOptions] = tb;
ob->setPosition(310, 4 + (numOptions * 30));
ob->setSize(190, fontHeight);
add(ob);
-
+
optionBoxes.resize(numOptions+1);
optionBoxes[numOptions] = ob;
-
+
if (option->optionType == Option::TYPE_TEXT ||
option->optionType == Option::TYPE_KEYED_TEXT)
{
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#include "wselectlist.h"
-
-#include "colour.h"
-
-WSelectList::WSelectList()
-{
- selectedOption = 0;
- topOption = 0;
- numOptionsDisplayable = 0;
- numColumns = 0;
- noLoop = 0;
- gap = 1;
- showseloption = true;
- darkseloption = false;
- backgroundColour = Colour::VIEWBACKGROUND;
-}
-
-WSelectList::~WSelectList()
-{
- clear();
-}
-
-void WSelectList::clear()
-{
- int vsize = options.size();
- for (int i = 0; i < vsize; i++)
- {
- delete[] options[i].text;
- }
- options.clear();
-
- selectedOption = 0;
- topOption = 0;
- numOptionsDisplayable = 0;
- numColumns = 0;
-}
-
-void WSelectList::setNoLoop()
-{
- noLoop = 1;
-}
-
-void WSelectList::setBackgroundColour(const Colour& colour)
-{
- backgroundColour = colour;
-}
-
-void WSelectList::hintSetCurrent(int idx)
-{
- selectedOption = idx;
- if (selectedOption >= options.size()) selectedOption = options.size() - 1;
-}
-
-void WSelectList::hintSetTop(int idx)
-{
- topOption = idx;
-}
-
-int WSelectList::addOption(const char* text, ULONG data, int selected)
-{
- int thisNewOption = options.size();
-
- wsloption wslo;
- wslo.text = new char[strlen(text) + 1];
- strcpy(wslo.text, text);
- wslo.data = data;
- options.push_back(wslo);
- if (selected) selectedOption = thisNewOption;
- return thisNewOption;
-}
-
-void WSelectList::draw()
-{
- int fontHeight = surface->getFontHeight();
- int ySeperation = fontHeight + gap;
-
- numOptionsDisplayable = (area.h - 5) / ySeperation;
-
- if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;
- if (selectedOption == ((UINT)topOption - 1)) topOption--;
- // if still not visible...
- if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))
- {
- topOption = selectedOption - (numOptionsDisplayable / 2);
- }
-
- if (topOption < 0) topOption = 0;
-
-
- fillColour(backgroundColour);
-
- UINT ypos = 5;
- for (UINT i = topOption; i < (topOption + numOptionsDisplayable); i++)
- {
- if (i == options.size()) return;
- if ((ypos + ySeperation) > area.h) break;
-
- if (i == selectedOption && showseloption)
- {
- rectangle(0, ypos, area.w, fontHeight, darkseloption ? Colour::SELECTDARKHIGHLIGHT: Colour::SELECTHIGHLIGHT);
- drawOptionLine(options[i].text, 5, ypos, area.w - 5, Colour::DARKTEXT);
- }
- else
- {
- drawOptionLine(options[i].text, 5, ypos, area.w - 5, Colour::LIGHTTEXT);
- }
- ypos += ySeperation;
- }
-}
-
-void WSelectList::addColumn(int x)
-{
- if (numColumns == 10) return;
- columns[numColumns++] = x;
-}
-
-void WSelectList::drawOptionLine(char* text, int xpos, int ypos, int width, const Colour& colour)
-{
- if (!numColumns)
- {
- drawText(text, xpos, ypos, width, colour);
- }
- else
- {
- char buffer[200];
- strncpy(buffer, text, 199);
- int currentColumn = 0;
- char* pointer;
-
- pointer = strtok(buffer, "\t");
- while(pointer)
- {
- drawText(pointer, xpos + columns[currentColumn], ypos, width - columns[currentColumn], colour);
- currentColumn++;
- if (currentColumn == 10) return;
- pointer = strtok(NULL, "\t");
- }
- }
-}
-
-void WSelectList::up()
-{
- if (selectedOption > 0)
- {
- selectedOption--;
- }
- else
- {
- if (!noLoop) selectedOption = options.size() - 1;
- }
-}
-
-void WSelectList::down()
-{
- if (selectedOption < options.size() - 1)
- {
- selectedOption++;
- }
- else
- {
- if (!noLoop) selectedOption = 0;
- }
-}
-
-void WSelectList::pageUp()
-{
- topOption -= numOptionsDisplayable;
- if (topOption < 0) topOption = 0;
-
- selectedOption = topOption;
-}
-
-void WSelectList::pageDown()
-{
- if ((topOption + numOptionsDisplayable) >= options.size())
- {
- selectedOption = options.size() - 1;
- }
- else
- {
- topOption += numOptionsDisplayable;
- selectedOption = topOption;
- }
-}
-
-int WSelectList::getTopOption()
-{
- return topOption;
-}
-
-int WSelectList::getNumOptions()
-{
- return options.size();
-}
-
-int WSelectList::getBottomOption()
-{
- UINT retval = topOption + numOptionsDisplayable;
- if (retval > options.size()) return options.size();
- else return retval;
-}
-
-int WSelectList::getCurrentOption()
-{
- return selectedOption;
-}
-
-ULONG WSelectList::getCurrentOptionData()
-{
- if (!options.size()) return 0;
- return options[selectedOption].data;
-}
-
-bool WSelectList::mouseMove(int x, int y)
-{
- int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());
- if (ml>=0 && ml!=(int)selectedOption)
- {
- selectedOption = ml;
- return true;
- }
- return false;
-}
-
-bool WSelectList::mouseLBDOWN(int x, int y)
-{
- int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());
- if (ml == (int)selectedOption)
- {
- /* caller should generate a OK message*/
- return true;
- }
- return false;
-}
-
-int WSelectList::getMouseLine(int x,int y)
-{
- int fontHeight = surface->getFontHeight();
- int ySeperation = fontHeight + gap;
-
- if (y<0) return -1;
- if (x<0 || x>(int)area.w) return -1;
- if (y>(int)(10+numOptionsDisplayable*ySeperation)) return -1;
-
- int cy = y - 5;
-
- int selected=cy/ySeperation;
- if (y<5) selected=-1;
- if (selected> ((int)numOptionsDisplayable)) return -1;
- /* Important: should be the same algorithm used in draw! */
- if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;
- if (selectedOption == ((UINT)topOption - 1)) topOption--;
- // if still not visible...
- if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))
- {
- topOption = selectedOption - (numOptionsDisplayable / 2);
- }
-
- if (topOption < 0) topOption = 0;
-
- if ((selected+topOption >= (int) options.size()) ||
- (selected + topOption < 0)) return -1;
-
- return selected + topOption;
-}
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include "wselectlist.h"\r
+\r
+#include "colour.h"\r
+#include "log.h"\r
+\r
+WSelectList::WSelectList()\r
+{\r
+ selectedOption = 0;\r
+ topOption = 0;\r
+ numOptionsDisplayable = 0;\r
+ numColumns = 0;\r
+ noLoop = 0;\r
+ gap = 1;\r
+ showseloption = true;\r
+ darkseloption = false;\r
+ backgroundColour = Colour::VIEWBACKGROUND;\r
+}\r
+\r
+WSelectList::~WSelectList()\r
+{\r
+ clear();\r
+}\r
+\r
+void WSelectList::clear()\r
+{\r
+ int vsize = options.size();\r
+ for (int i = 0; i < vsize; i++)\r
+ {\r
+ delete[] options[i].text;\r
+ }\r
+ options.clear();\r
+\r
+ selectedOption = 0;\r
+ topOption = 0;\r
+ numOptionsDisplayable = 0;\r
+ numColumns = 0;\r
+}\r
+\r
+void WSelectList::setNoLoop()\r
+{\r
+ noLoop = 1;\r
+}\r
+\r
+void WSelectList::setBackgroundColour(const Colour& colour)\r
+{\r
+ backgroundColour = colour;\r
+}\r
+\r
+void WSelectList::hintSetCurrent(int idx)\r
+{\r
+ selectedOption = idx;\r
+ if (selectedOption >= options.size()) selectedOption = options.size() - 1;\r
+}\r
+\r
+void WSelectList::hintSetTop(int idx)\r
+{\r
+ topOption = idx;\r
+}\r
+\r
+int WSelectList::addOption(const char* text, ULONG data, int selected)\r
+{\r
+ int thisNewOption = options.size();\r
+\r
+ wsloption wslo;\r
+ wslo.text = new char[strlen(text) + 1];\r
+ strcpy(wslo.text, text);\r
+ wslo.data = data;\r
+ options.push_back(wslo);\r
+ if (selected) selectedOption = thisNewOption;\r
+ return thisNewOption;\r
+}\r
+\r
+void WSelectList::draw()\r
+{\r
+ int fontHeight = getFontHeight();\r
+ int ySeperation = fontHeight + gap;\r
+\r
+ numOptionsDisplayable = (area.h - 5) / ySeperation;\r
+\r
+ if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;\r
+ if (selectedOption == ((UINT)topOption - 1)) topOption--;\r
+ // if still not visible...\r
+ if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))\r
+ {\r
+ topOption = selectedOption - (numOptionsDisplayable / 2);\r
+ }\r
+\r
+ if (topOption < 0) topOption = 0;\r
+\r
+\r
+ fillColour(backgroundColour);\r
+\r
+ UINT ypos = 5;\r
+ for (UINT i = topOption; i < (topOption + numOptionsDisplayable); i++)\r
+ {\r
+ if (i == options.size()) return;\r
+ if ((ypos + ySeperation) > area.h) break;\r
+\r
+ if (i == selectedOption && showseloption)\r
+ {\r
+\r
+ rectangle(0, ypos, area.w, fontHeight, darkseloption ? Colour::SELECTDARKHIGHLIGHT: Colour::SELECTHIGHLIGHT);\r
+\r
+ drawOptionLine(options[i].text, 5, ypos, area.w - 5, Colour::DARKTEXT);\r
+ }\r
+ else\r
+ {\r
+\r
+ drawOptionLine(options[i].text, 5, ypos, area.w - 5, Colour::LIGHTTEXT);\r
+ }\r
+ ypos += ySeperation;\r
+ }\r
+\r
+}\r
+\r
+void WSelectList::addColumn(int x)\r
+{\r
+ if (numColumns == 10) return;\r
+ columns[numColumns++] = x;\r
+}\r
+\r
+void WSelectList::drawOptionLine(char* text, int xpos, int ypos, int width, const Colour& colour)\r
+{\r
+ if (!numColumns)\r
+ {\r
+\r
+ drawText(text, xpos, ypos, width, colour);\r
+ }\r
+ else\r
+ {\r
+ char buffer[200];\r
+ strncpy(buffer, text, 199);\r
+ int currentColumn = 0;\r
+ char* pointer;\r
+\r
+ pointer = strtok(buffer, "\t");\r
+ while(pointer)\r
+ {\r
+\r
+ drawText(pointer, xpos + columns[currentColumn], ypos, width - columns[currentColumn], colour);\r
+\r
+ currentColumn++;\r
+ if (currentColumn == 10) return;\r
+ pointer = strtok(NULL, "\t");\r
+ }\r
+ }\r
+}\r
+\r
+void WSelectList::up()\r
+{\r
+ if (selectedOption > 0)\r
+ {\r
+ selectedOption--;\r
+ }\r
+ else\r
+ {\r
+ if (!noLoop) selectedOption = options.size() - 1;\r
+ }\r
+}\r
+\r
+void WSelectList::down()\r
+{\r
+ if (selectedOption < options.size() - 1)\r
+ {\r
+ selectedOption++;\r
+ }\r
+ else\r
+ {\r
+ if (!noLoop) selectedOption = 0;\r
+ }\r
+}\r
+\r
+void WSelectList::pageUp()\r
+{\r
+ topOption -= numOptionsDisplayable;\r
+ if (topOption < 0) topOption = 0;\r
+\r
+ selectedOption = topOption;\r
+}\r
+\r
+void WSelectList::pageDown()\r
+{\r
+ if ((topOption + numOptionsDisplayable) >= options.size())\r
+ {\r
+ selectedOption = options.size() - 1;\r
+ }\r
+ else\r
+ {\r
+ topOption += numOptionsDisplayable;\r
+ selectedOption = topOption;\r
+ }\r
+}\r
+\r
+int WSelectList::getTopOption()\r
+{\r
+ return topOption;\r
+}\r
+\r
+int WSelectList::getNumOptions()\r
+{\r
+ return options.size();\r
+}\r
+\r
+int WSelectList::getBottomOption()\r
+{\r
+ UINT retval = topOption + numOptionsDisplayable;\r
+ if (retval > options.size()) return options.size();\r
+ else return retval;\r
+}\r
+\r
+int WSelectList::getCurrentOption()\r
+{\r
+ return selectedOption;\r
+}\r
+\r
+ULONG WSelectList::getCurrentOptionData()\r
+{\r
+ if (!options.size()) return 0;\r
+ return options[selectedOption].data;\r
+}\r
+\r
+bool WSelectList::mouseAndroidScroll(int x, int y,int sx, int sy)\r
+{\r
+/* int fontHeight = getFontHeight();\r
+ int movelines= sy/fontHeight;\r
+\r
+ int seloption=selectedOption+movelines;\r
+ if (seloption<0) seloption=0;\r
+ else if (seloption>options.size()-1) seloption=options.size()-1;\r
+ selectedOption=seloption;*/\r
+\r
+}\r
+\r
+bool WSelectList::mouseMove(int x, int y)\r
+{\r
+ int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());\r
+ if (ml>=0 && ml!=(int)selectedOption)\r
+ {\r
+ selectedOption = ml;\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+bool WSelectList::mouseLBDOWN(int x, int y)\r
+{\r
+ int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());\r
+ if (ml == (int)selectedOption)\r
+ {\r
+ /* caller should generate a OK message*/\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+int WSelectList::getMouseLine(int x,int y)\r
+{\r
+ int fontHeight = getFontHeight();\r
+ int ySeperation = fontHeight + gap;\r
+\r
+ if (y<0) return -1;\r
+ if (x<0 || x>(int)area.w) return -1;\r
+ if (y>(int)(10+numOptionsDisplayable*ySeperation)) return -1;\r
+\r
+ int cy = y - 5;\r
+\r
+ int selected=cy/ySeperation;\r
+ if (y<5) selected=-1;\r
+ if (selected> ((int)numOptionsDisplayable)) return -1;\r
+ /* Important: should be the same algorithm used in draw! */\r
+ if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;\r
+ if (selectedOption == ((UINT)topOption - 1)) topOption--;\r
+ // if still not visible...\r
+ if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))\r
+ {\r
+ topOption = selectedOption - (numOptionsDisplayable / 2);\r
+ }\r
+\r
+ if (topOption < 0) topOption = 0;\r
+\r
+ if ((selected+topOption >= (int) options.size()) ||\r
+ (selected + topOption < 0)) return -1;\r
+\r
+ return selected + topOption;\r
+}\r
-/*
- Copyright 2004-2005 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#ifndef WSELECTLIST_H
-#define WSELECTLIST_H
-
-#include <stdio.h>
-#include <string.h>
-
-#include <vector>
-
-#include "defines.h"
-#include "boxx.h"
-
-using namespace std;
-
-typedef struct
-{
- char* text;
- ULONG data;
-} wsloption;
-
-class WSelectList : public Boxx
-{
- public:
- WSelectList();
- ~WSelectList();
- void clear();
- void addColumn(int x);
-
- void setNoLoop();
- void setShowSelOption(bool set) { showseloption = set; };
- void setDarkSelOption(bool set) { darkseloption = set; };
- int addOption(const char* text, ULONG data, int selected);
- void draw();
- void setBackgroundColour(const Colour& colour);
-
- void down();
- void up();
- void pageUp();
- void pageDown();
-
- int getTopOption();
- int getNumOptions();
- int getBottomOption(); // actually returns bottom + 1 i.e. the one just past display ?!
- int getCurrentOption();
- ULONG getCurrentOptionData();
-
- void hintSetCurrent(int index);
- void hintSetTop(int index);
-
- virtual bool mouseMove(int x, int y);
- virtual bool mouseLBDOWN(int x, int y);
-
- private:
- void drawOptionLine(char* text, int xpos, int ypos, int width, const Colour& colour);
- int getMouseLine(int x, int y);
-
- vector<wsloption> options;
- UINT selectedOption;
- int topOption;
- UINT numOptionsDisplayable;
- int columns[10];
- int numColumns;
- int noLoop;
- bool showseloption, darkseloption;
-
- UINT gap;
- Colour backgroundColour;
-};
-
-#endif
+/*\r
+ Copyright 2004-2005 Chris Tallon\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef WSELECTLIST_H\r
+#define WSELECTLIST_H\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#include <vector>\r
+\r
+#include "defines.h"\r
+#include "boxx.h"\r
+\r
+using namespace std;\r
+\r
+typedef struct\r
+{\r
+ char* text;\r
+ ULONG data;\r
+} wsloption;\r
+\r
+class WSelectList : public Boxx\r
+{\r
+ public:\r
+ WSelectList();\r
+ ~WSelectList();\r
+ void clear();\r
+ void addColumn(int x);\r
+\r
+ void setNoLoop();\r
+ void setShowSelOption(bool set) { showseloption = set; };\r
+ void setDarkSelOption(bool set) { darkseloption = set; };\r
+ int addOption(const char* text, ULONG data, int selected);\r
+ void draw();\r
+ void setBackgroundColour(const Colour& colour);\r
+\r
+ void down();\r
+ void up();\r
+ void pageUp();\r
+ void pageDown();\r
+\r
+ int getTopOption();\r
+ int getNumOptions();\r
+ int getBottomOption(); // actually returns bottom + 1 i.e. the one just past display ?!\r
+ int getCurrentOption();\r
+ ULONG getCurrentOptionData();\r
+\r
+ void hintSetCurrent(int index);\r
+ void hintSetTop(int index);\r
+\r
+ virtual bool mouseMove(int x, int y);\r
+ virtual bool mouseLBDOWN(int x, int y);\r
+ virtual bool mouseAndroidScroll(int x, int y,int sx, int sy);\r
+\r
+ private:\r
+ void drawOptionLine(char* text, int xpos, int ypos, int width, const Colour& colour);\r
+ int getMouseLine(int x, int y);\r
+\r
+ vector<wsloption> options;\r
+ UINT selectedOption;\r
+ int topOption;\r
+ UINT numOptionsDisplayable;\r
+ int columns[10];\r
+ int numColumns;\r
+ int noLoop;\r
+ bool showseloption, darkseloption;\r
+ \r
+ UINT gap;\r
+ Colour backgroundColour;\r
+};\r
+\r
+#endif\r
int x, y, bytesIn, bitsIn;
+ startFastDraw();
for (y = 0; y < sHeight; y++)
{
for (x = 0; x < widthBits; x++)
if ((base[bytesIn] >> (7 - bitsIn)) & 0x01)
{
- drawPixel(x, y, nextColour);
+ drawPixel(x, y, nextColour,true);
}
}
}
+ endFastDraw();
}
bool WSymbol::mouseLBDOWN(int x, int y)
WButton* newButton = new WButton();
newButton->setText(name);
newButton->setPosition(newButtonX, 2);
- newButton->setSize(td.nameWidth + 6, Surface::getFontHeight());
+ newButton->setSize(td.nameWidth + 6, getFontHeight());
if ((newButtonX + newButton->getWidth()) > (getWidth() - 22)) newButton->setVisible(false);
add(newButton);