]> git.vomp.tv Git - vompclient.git/commitdiff
End of line normalization
authorMarten Richter <marten.richter@freenet.de>
Mon, 5 Nov 2012 07:40:58 +0000 (08:40 +0100)
committerMarten Richter <marten.richter@freenet.de>
Mon, 5 Nov 2012 07:40:58 +0000 (08:40 +0100)
74 files changed:
GNUmakefile
afeed.cc
audio.h
audioomx.h
audiowin.cc
boxstack.cc
boxx.cc
boxx.h
command.cc
defines.h
demuxer.cc
demuxer.h
demuxeraudio.cc
demuxerts.h
demuxervdr.cc
draintarget.h
feed.h
fonts/licensesourcesans.txt
glosdshader.cc
glosdshader.h
glshader.cc
glshader.h
imagereader.h
log.cc
log.h
main.cc
message.h
objects.mk
osd.h
osdopengl.cc
osdopengl.h
osdopenvg.cc
osdopenvg.h
osdvector.cc
osdvector.h
osdwin.cc
osdwin.h
player.cc
player.h
playerliveradio.cc
playerlivetv.cc
playerradio.cc
playerradio.h
stream.cc
surface.cc
surface.h
surfacedirectfb.cc
surfacedirectfb.h
surfacemvp.h
surfaceopengl.cc
surfaceopengl.h
surfacevector.cc
surfacevector.h
surfacewin.cc
surfacewin.h
teletextdecodervbiebu.cc
tfeed.cc
tfeed.h
threadsystem.h
vcolourtuner.cc
vdr.cc
vdr.h
vdrcommand.h
vdrresponsepacket.cc
vepg.cc
vfeed.cc
video.cc
video.h
videomvp.cc
videomvp.h
videoomx.h
videowin.cc
videowin.h
vmediaview.cc

index 6221114b7f5f168c316dc0df2ff9ba065c30e1c8..54ea355c5d2485ee158e054141882e03ea713084 100644 (file)
-vomp_platform =raspberry\r
-# valid platforms are raspberry and mvp\r
-vomp_options=\r
-#uncomment the line below, if you want to vomp application like, without a reboot option, automatically set for windows!\r
-#vomp_options+= -DVOMP_HAS_EXIT\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 += wwss.o main.o threadp.o remotemvp.o ledmvp.o mtdmvp.o videomvp.o audiomvp.o osdmvp.o surfacemvp.o wjpegcomplex.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
-\r
-endif\r
-\r
-ifeq ($(vomp_platform),raspberry)\r
-$(info Raspberry pi flags)\r
-LDFLAGS = -Wall -Wl,--format=binary -Wl,fonts/sourcesans.ttf -Wl,other/vdrhires.jpg -Wl,other/wallpaper720p.jpg -Wl,--format=default \r
-LIBS = -L/opt/vc/lib -lpthread -lrt -lEGL -lOpenVG -lopenmaxil -lbcm_host   -lavformat -lavcodec -lavutil\r
-\r
-OBJECTS += main.o threadp.o  osdvector.o surfacevector.o osdopenvg.o ledraspberry.o mtdraspberry.o videoomx.o audioomx.o wjpegsimple.o remotelinux.o  \r
-LIBS+=  -lfreetype -lMagick++ -lMagickCore\r
-CROSSLIBS = \r
-INCLUDES = -DVOMP_PLATTFORM_RASPBERRY   -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads  -I/usr/include/freetype2 -I/usr/include/ImageMagick\r
-CXXFLAGS_DEV += -D__STDC_CONSTANT_MACROS\r
-CXXFLAGS_REL += -D__STDC_CONSTANT_MACROS\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) $(vomp_options) $(OBJECTS:%.o=%.cc) > deps\r
-\r
--include deps\r
-\r
-clean:\r
-       rm -f *.o deps vompclient *~ fonts/*.o fonts/*~ teletxt/*.o\r
-\r
+vomp_platform =raspberry
+# valid platforms are raspberry and mvp
+vomp_options=
+#uncomment the line below, if you want to vomp application like, without a reboot option, automatically set for windows!
+#vomp_options+= -DVOMP_HAS_EXIT
+ifeq ($(vomp_platform),mvp)
+
+$(info MVP crosscompiler)
+include ../crosstool/cross-var
+CC=$(CROSS)gcc
+STRIP=$(CROSS)strip
+CXX=$(CROSS)g++
+LD=$(CROSS)g++
+
+endif
+
+ifeq ($(vomp_platform),raspberry)
+
+$(info raspberry normal compiler)
+CC=gcc
+STRIP=strip
+CXX=g++
+LD=g++
+
+endif
+
+
+
+CXXFLAGS_DEV = -g -O0 -Wall -Wshadow -DDEV -D_GNU_SOURCE $(INCLUDES)
+CXXFLAGS_REL = -O3 -Wall -Wshadow  -D_GNU_SOURCE $(INCLUDES)
+
+
+LIBPATHS =
+
+
+$(info Setting up objects)
+# This is the only thing windows and linux share
+include objects.mk
+
+OBJECTSWIN = threadwin.o remotewin.o ledwin.o mtdwin.o videowin.o audiowin.o osdwin.o surfacewin.o
+
+OBJECTS = $(OBJECTS1) 
+
+
+ifeq ($(vomp_platform),mvp)
+$(info MVP flags)
+LDFLAGS = -Wall -static
+LIBS = -lpthread -lrt
+
+OBJECTS += wwss.o main.o threadp.o remotemvp.o ledmvp.o mtdmvp.o videomvp.o audiomvp.o osdmvp.o surfacemvp.o wjpegcomplex.o vmedialist.o vcolourtuner.o vmediaview.o vvideomedia.o 
+TIOBJECT = ticonfig.o
+CROSSLIBS = ../jpeg/jpeg-6b/libjpeg.a
+INCLUDES = -I../jpeg/jpeg-6b  -DVOMP_PLATTFORM_MVP 
+
+
+endif
+
+ifeq ($(vomp_platform),raspberry)
+$(info Raspberry pi flags)
+LDFLAGS = -Wall -Wl,--format=binary -Wl,fonts/sourcesans.ttf -Wl,other/vdrhires.jpg -Wl,other/wallpaper720p.jpg -Wl,--format=default 
+LIBS = -L/opt/vc/lib -lpthread -lrt -lEGL -lOpenVG -lopenmaxil -lbcm_host   -lavformat -lavcodec -lavutil
+
+OBJECTS += main.o threadp.o  osdvector.o surfacevector.o osdopenvg.o ledraspberry.o mtdraspberry.o videoomx.o audioomx.o wjpegsimple.o remotelinux.o  
+LIBS+=  -lfreetype -lMagick++ -lMagickCore
+CROSSLIBS = 
+INCLUDES = -DVOMP_PLATTFORM_RASPBERRY   -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads  -I/usr/include/freetype2 -I/usr/include/ImageMagick
+CXXFLAGS_DEV += -D__STDC_CONSTANT_MACROS
+CXXFLAGS_REL += -D__STDC_CONSTANT_MACROS
+
+endif
+
+.PHONY: clean fresh all install strip
+
+default: dev
+fresh:   clean default
+
+vompclient: $(OBJECTS) $(TIOBJECT) $(CROSSLIBS)
+       $(LD) $(LDFLAGS) $(LIBPATHS) $(RELEASE) -o vompclient $(TIOBJECT) $(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) $(vomp_options) $(OBJECTS:%.o=%.cc) > deps
+
+-include deps
+
+clean:
+       rm -f *.o deps vompclient *~ fonts/*.o fonts/*~ teletxt/*.o
+
index ee0b55b43fbd57e4907432dc6d1980151af8476f..c841f4508a29219c2d6efddb39289f174c31380b 100644 (file)
--- a/afeed.cc
+++ b/afeed.cc
-/*\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
-       Log::getInstance()->log("AFeed", Log::DEBUG, "Stop1");\r
-  threadCancel();\r
-       Log::getInstance()->log("AFeed", Log::DEBUG, "Stop2");\r
-}\r
-\r
-void AFeed::threadMethod()\r
-{\r
-  bool alen;\r
-\r
-  while(1)\r
-  {\r
-    threadCheckExit();\r
-\r
-    if (audioEnabled)\r
-    {\r
-      bool newdata=false;\r
-      alen = Demuxer::getInstance()->writeAudio(&newdata);\r
-\r
-      if (newdata) cb.call(this);\r
-      if (alen)\r
-      {\r
-           //Log::getInstance()->log("Afeed", Log::DEBUG, "written");\r
-          cb.call(this);\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
+/*
+    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()
+{
+       Log::getInstance()->log("AFeed", Log::DEBUG, "Stop1");
+  threadCancel();
+       Log::getInstance()->log("AFeed", Log::DEBUG, "Stop2");
+}
+
+void AFeed::threadMethod()
+{
+  bool alen;
+
+  while(1)
+  {
+    threadCheckExit();
+
+    if (audioEnabled)
+    {
+      bool newdata=false;
+      alen = Demuxer::getInstance()->writeAudio(&newdata);
+
+      if (newdata) cb.call(this);
+      if (alen)
+      {
+           //Log::getInstance()->log("Afeed", Log::DEBUG, "written");
+          cb.call(this);
+      }
+      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
+    }
+  }
+}
+
diff --git a/audio.h b/audio.h
index 601c2e77e676aee927068005b5b42ba0e744ea1c..4a3342b4300eda0fd1d33a427d75a787d02a4700 100644 (file)
--- a/audio.h
+++ b/audio.h
-/*\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
-    virtual bool streamTypeSupported(int streamtype)\r
-    {\r
-       switch (streamtype) {\r
-       case 3:\r
-       case 4:\r
-               return true;\r
-       default:\r
-               return false;\r
-       };\r
-    }\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.
+*/
+
+#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();
+   // static void setInstance(Audio* );
+
+    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;}
+    virtual bool streamTypeSupported(int streamtype)
+    {
+       switch (streamtype) {
+       case 3:
+       case 4:
+               return true;
+       default:
+               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
index 30032e42198370ea9cf707e2d40b50e2f89986b5..b166e0d572338e5435345976278ea121725cd3e2 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon, 2009,2012 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 AUDIOOMX_H\r
-#define AUDIOOMX_H\r
-\r
-#include <stdio.h>\r
-#include <unistd.h>\r
-#include <fcntl.h>\r
-#include <sys/ioctl.h>\r
-\r
-#include "defines.h"\r
-#include "audio.h"\r
-#include "videoomx.h"\r
-\r
-extern "C" {\r
-#include <libavcodec/avcodec.h>\r
-#include <libavformat/avformat.h>\r
-}\r
-\r
-\r
-\r
-\r
-class AudioOMX : public Audio\r
-{\r
-  friend class VideoOMX;\r
-  public:\r
-    AudioOMX();\r
-    virtual ~AudioOMX();\r
-\r
-    int init(UCHAR streamType);\r
-    int shutdown();\r
-\r
-    int setStreamType(UCHAR streamType);\r
-    int setChannel();\r
-    int setSource();\r
-    int sync();\r
-    int play();\r
-    int stop();\r
-    int pause();\r
-    int unPause();\r
-    int reset();\r
-    int setVolume(int volume);\r
-    int mute();\r
-    int unMute();\r
-    bool supportsAc3() { return true; }\r
-    bool maysupportAc3(){return true;}\r
-    bool streamTypeSupported(int streamtype)\r
-    {\r
-       switch (streamtype) {\r
-       case 0x11: //AAC LATM packaging\r
-       case 0x6A://ac3\r
-       case 3: //mpeg 1 layer 1 and 2\r
-       case 4:\r
-               return true;\r
-       default:\r
-               return false;\r
-       };\r
-    }\r
-\r
-\r
-    //Writing Data to Audiodevice\r
-    virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);\r
-    virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos);\r
-    UINT DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer,UINT *samplepos);\r
-\r
-    virtual long long SetStartOffset(long long curreftime, bool *rsync);\r
-    virtual void ResetTimeOffsets();\r
-\r
-    virtual bool DrainTargetReady() {return omx_running;};\r
-\r
-\r
-       UCHAR getLastAType() {return lastAType;}\r
-\r
-       bool loadOptionsfromServer(VDR* vdr);\r
-       bool saveOptionstoServer();\r
-       bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane);\r
-       bool handleOptionChanges(Option* option);\r
-\r
-\r
-#ifdef DEV\r
-    int test();\r
-#endif\r
-\r
-  private:\r
-    int initAllParams();\r
-    UCHAR streamType;\r
-       UCHAR lastAType;\r
-       bool firstsynched;\r
-\r
-    MediaPacket packet;\r
-    UINT packetpos;\r
-\r
-       bool paused;\r
-\r
-    bool hdmi; // use hdmi as audio output\r
-    bool passthrough; // use audio passthrough for the current audio type\r
-\r
-    bool canpass_aac;\r
-    bool canpass_ac3;\r
-    bool canpass_mp2;\r
-    bool canpass_mp3;\r
-    bool canpass_pcm_mch;\r
-\r
-\r
-    int prefered_aac;\r
-    int prefered_ac3; //0 stereo PCM, 1 passthrough 2 Multichannel PCM\r
-    int prefered_mp2;\r
-    int prefered_mp3;\r
-\r
-\r
-\r
-    static OMX_ERRORTYPE EmptyBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp,OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver);\r
-       static OMX_ERRORTYPE FillBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp, OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver);\r
-\r
-\r
-\r
-       unsigned int AdvanceAc3AudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize);\r
-       unsigned int AdvanceAacLatmAudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize);\r
-       unsigned int AdvanceMpAudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize);\r
-\r
-\r
-    void ReturnEmptyOMXBuffer(OMX_BUFFERHEADERTYPE* bulibaver);\r
-\r
-   // OMX_HANDLETYPE omx_aud_dec;\r
-       OMX_HANDLETYPE omx_aud_rend;\r
-       OMX_HANDLETYPE omx_clock;\r
-\r
-       //OMX_U32 omx_codec_input_port;\r
-       //OMX_U32 omx_codec_output_port;\r
-       OMX_U32 omx_rend_input_port;\r
-       OMX_U32 omx_rend_clock_port;\r
-       OMX_U32 omx_clock_output_port;\r
-\r
-       long long lastreftimeOMX;\r
-    ULLONG lastreftimePTS;\r
-\r
-\r
-\r
-       int AllocateCodecsOMX();\r
-       int DeAllocateCodecsOMX();\r
-\r
-       int PrepareInputBufsOMX(bool setportdef);\r
-       int DestroyInputBufsOMX();\r
-       int DestroyInputBufsOMXwhilePlaying();\r
-\r
-       int ChangeAudioPortConfig(bool disport);\r
-       int ChangeAudioDestination();\r
-       long long correctAudioLatency(long long pts,int addsamples,int srate);\r
-\r
-       vector<OMX_BUFFERHEADERTYPE*> input_bufs_omx_all;\r
-       list<OMX_BUFFERHEADERTYPE*> input_bufs_omx_free;\r
-       Mutex input_bufs_omx_mutex;\r
-       OMX_BUFFERHEADERTYPE* cur_input_buf_omx;\r
-\r
-    bool omx_running;\r
-    bool omx_first_frame;\r
-    Mutex libav_mutex;\r
-\r
-    AVCodec *aaclatmcodec_libav;\r
-    AVCodecContext *aaclatmcodec_context_libav;\r
-       AVCodec *ac3codec_libav;\r
-       AVCodecContext *ac3codec_context_libav;\r
-       AVCodec *mp23codec_libav;\r
-    AVCodecContext *mp23codec_context_libav;\r
-    AVPacket incoming_paket_libav;\r
-    AVFrame *decode_frame_libav;\r
-\r
-    UCHAR * decompress_buffer;\r
-    unsigned int decompress_buffer_size;\r
-    unsigned int decompress_buffer_filled;\r
-    bool lsync;\r
-\r
-\r
-        int InitDecoderLibAV();\r
-        void DeinitDecoderLibAV();\r
-\r
-};\r
-\r
-#endif\r
+/*
+    Copyright 2004-2005 Chris Tallon, 2009,2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef AUDIOOMX_H
+#define AUDIOOMX_H
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include "defines.h"
+#include "audio.h"
+#include "videoomx.h"
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+}
+
+
+
+
+class AudioOMX : public Audio
+{
+  friend class VideoOMX;
+  public:
+    AudioOMX();
+    virtual ~AudioOMX();
+
+    int init(UCHAR streamType);
+    int shutdown();
+
+    int setStreamType(UCHAR streamType);
+    int setChannel();
+    int setSource();
+    int sync();
+    int play();
+    int stop();
+    int pause();
+    int unPause();
+    int reset();
+    int setVolume(int volume);
+    int mute();
+    int unMute();
+    bool supportsAc3() { return true; }
+    bool maysupportAc3(){return true;}
+    bool streamTypeSupported(int streamtype)
+    {
+       switch (streamtype) {
+       case 0x11: //AAC LATM packaging
+       case 0x6A://ac3
+       case 3: //mpeg 1 layer 1 and 2
+       case 4:
+               return true;
+       default:
+               return false;
+       };
+    }
+
+
+    //Writing Data to Audiodevice
+    virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);
+    virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos);
+    UINT DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer,UINT *samplepos);
+
+    virtual long long SetStartOffset(long long curreftime, bool *rsync);
+    virtual void ResetTimeOffsets();
+
+    virtual bool DrainTargetReady() {return omx_running;};
+
+
+       UCHAR getLastAType() {return lastAType;}
+
+       bool loadOptionsfromServer(VDR* vdr);
+       bool saveOptionstoServer();
+       bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane);
+       bool handleOptionChanges(Option* option);
+
+
+#ifdef DEV
+    int test();
+#endif
+
+  private:
+    int initAllParams();
+    UCHAR streamType;
+       UCHAR lastAType;
+       bool firstsynched;
+
+    MediaPacket packet;
+    UINT packetpos;
+
+       bool paused;
+
+    bool hdmi; // use hdmi as audio output
+    bool passthrough; // use audio passthrough for the current audio type
+
+    bool canpass_aac;
+    bool canpass_ac3;
+    bool canpass_mp2;
+    bool canpass_mp3;
+    bool canpass_pcm_mch;
+
+
+    int prefered_aac;
+    int prefered_ac3; //0 stereo PCM, 1 passthrough 2 Multichannel PCM
+    int prefered_mp2;
+    int prefered_mp3;
+
+
+
+    static OMX_ERRORTYPE EmptyBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp,OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver);
+       static OMX_ERRORTYPE FillBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp, OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver);
+
+
+
+       unsigned int AdvanceAc3AudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize);
+       unsigned int AdvanceAacLatmAudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize);
+       unsigned int AdvanceMpAudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize);
+
+
+    void ReturnEmptyOMXBuffer(OMX_BUFFERHEADERTYPE* bulibaver);
+
+   // OMX_HANDLETYPE omx_aud_dec;
+       OMX_HANDLETYPE omx_aud_rend;
+       OMX_HANDLETYPE omx_clock;
+
+       //OMX_U32 omx_codec_input_port;
+       //OMX_U32 omx_codec_output_port;
+       OMX_U32 omx_rend_input_port;
+       OMX_U32 omx_rend_clock_port;
+       OMX_U32 omx_clock_output_port;
+
+       long long lastreftimeOMX;
+    ULLONG lastreftimePTS;
+
+
+
+       int AllocateCodecsOMX();
+       int DeAllocateCodecsOMX();
+
+       int PrepareInputBufsOMX(bool setportdef);
+       int DestroyInputBufsOMX();
+       int DestroyInputBufsOMXwhilePlaying();
+
+       int ChangeAudioPortConfig(bool disport);
+       int ChangeAudioDestination();
+       long long correctAudioLatency(long long pts,int addsamples,int srate);
+
+       vector<OMX_BUFFERHEADERTYPE*> input_bufs_omx_all;
+       list<OMX_BUFFERHEADERTYPE*> input_bufs_omx_free;
+       Mutex input_bufs_omx_mutex;
+       OMX_BUFFERHEADERTYPE* cur_input_buf_omx;
+
+    bool omx_running;
+    bool omx_first_frame;
+    Mutex libav_mutex;
+
+    AVCodec *aaclatmcodec_libav;
+    AVCodecContext *aaclatmcodec_context_libav;
+       AVCodec *ac3codec_libav;
+       AVCodecContext *ac3codec_context_libav;
+       AVCodec *mp23codec_libav;
+    AVCodecContext *mp23codec_context_libav;
+    AVPacket incoming_paket_libav;
+    AVFrame *decode_frame_libav;
+
+    UCHAR * decompress_buffer;
+    unsigned int decompress_buffer_size;
+    unsigned int decompress_buffer_filled;
+    bool lsync;
+
+
+        int InitDecoderLibAV();
+        void DeinitDecoderLibAV();
+
+};
+
+#endif
index 2079b1d68c0b8e9beba454cc6d89c8b9106b05ae..9903890ba72fd1c053649ff23be5c2067714dd8f 100644 (file)
-/*\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,&current,&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,&current,&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
+/*
+    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 (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,&current,&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,&current,&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();
+  vw->ResetTimeOffsets();
+}
+
+bool AudioWin::supportsAc3(){
+    VideoWin *vw=(VideoWin*)Video::getInstance();
+    return vw->supportsAc3();
+}
+
+#ifdef DEV
+int AudioWin::test()
+{
+  return 0;
+}
+#endif
+
+
+
index 5330003b1e8f307651bd492d29e6b695e63d723e..4c821d2b7d6b94e56a25e32333dc8252c368308d 100644 (file)
-/*\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::redrawAllBoxes()\r
-{\r
-#ifndef WIN32\r
-  pthread_mutex_lock(&boxLock);\r
-#else\r
-  WaitForSingleObject(boxLock, INFINITE);\r
-#endif\r
-\r
-  for (int z = 0; z < numBoxes; z++)\r
-  {\r
-         boxes[z]->draw();\r
-  }\r
-\r
-\r
-#ifndef WIN32\r
-    pthread_mutex_unlock(&boxLock);\r
-#else\r
-    ReleaseMutex(boxLock);\r
-#endif\r
-    update(NULL,NULL); // should blt all\r
-}\r
-\r
-void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)\r
-{\r
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "Update called");\r
-  if (!initted) return; // it is allowed to call this before init\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
-  if (!toUpdate) {\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, no box present");\r
-         return ;\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 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::redrawAllBoxes()
+{
+#ifndef WIN32
+  pthread_mutex_lock(&boxLock);
+#else
+  WaitForSingleObject(boxLock, INFINITE);
+#endif
+
+  for (int z = 0; z < numBoxes; z++)
+  {
+         boxes[z]->draw();
+  }
+
+
+#ifndef WIN32
+    pthread_mutex_unlock(&boxLock);
+#else
+    ReleaseMutex(boxLock);
+#endif
+    update(NULL,NULL); // should blt all
+}
+
+void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)
+{
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "Update called");
+  if (!initted) return; // it is allowed to call this before init
+#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];
+  }
+
+  if (!toUpdate) {
+#ifndef WIN32
+         pthread_mutex_unlock(&boxLock);
+#else
+         ReleaseMutex(boxLock);
+#endif
+         Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for update, no box present");
+         return ;
+  }
+
+  // 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)
+                 || (m->message == Message::MOUSE_ANDROID_SCROLL)))
+  {
+    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;
+    }
+  }
+}
diff --git a/boxx.cc b/boxx.cc
index af2464dcc92597bb405f356c5092f8c1043d0553..a1b31b1741eab8370892e52f79117ec6f622772e 100644 (file)
--- a/boxx.cc
+++ b/boxx.cc
-/*\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 DrawStyle& 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 DrawStyle& 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 DrawStyle& colour)\r
-{\r
-  char line[256];\r
-  int lineHeight = getFontHeight() + paraVSpace;\r
-\r
-  float lineWidth;\r
-  float 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
-      unsigned int cur_length=1;\r
-      wchar_t cur_char=getWChar(text+textPos,&cur_length);\r
-\r
-      if (cur_char == '\0') break;\r
-\r
-      if (cur_char == '\n')\r
-      {\r
-        textPos+=cur_length; // ignore the \n\r
-        printLine = 1;\r
-        break;\r
-      }\r
-      thisCharWidth = charWidth(cur_char);\r
-      if ((lineWidth + thisCharWidth) > (int)(area.w - (2 * paraMargin)))\r
-      {\r
-        // this character would break the right margin\r
-        if (cur_char == ' ')\r
-        {\r
-          // this char is a space, ignore and break\r
-          textPos+=cur_length;\r
-          break;\r
-        }\r
-        else\r
-        {\r
-          // Need to go back to the last space in the line\r
-          while ((cur_char != ' ') && (linePos >= 0))\r
-          {\r
-            textPos-=cur_length;\r
-            cur_char=getWChar(text+textPos,&cur_length);\r
-            linePos--;\r
-          }\r
-          // Now take the space we just found\r
-          textPos+=cur_length;\r
-          break;\r
-        }\r
-      }\r
-      for (int n=0;n<cur_length;n++) line[linePos++] = text[textPos+n];\r
-      lineWidth += thisCharWidth;\r
-      textPos+=cur_length;\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 DrawStyle& 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 DrawStyle& 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);\r
-}\r
-\r
-void Boxx::drawText(const char* text, int x, int y, const DrawStyle& colour)\r
-{\r
-  if (parent) parent->drawText(text, area.x + x, area.y + y, colour);\r
-  else surface->drawText(text, x, y, colour);\r
-}\r
-\r
-void Boxx::drawText(const char* text, int x, int y, int width, const DrawStyle& 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);\r
-}\r
-\r
-void Boxx::drawTextRJ(const char* text, int x, int y, const DrawStyle& colour)\r
-{\r
-  if (parent) parent->drawTextRJ(text, area.x + x, area.y + y, colour);\r
-  else surface->drawTextRJ(text, x, y, colour);\r
-}\r
-\r
-void Boxx::drawTextCentre(const char* text, int x, int y, const DrawStyle& colour)\r
-{\r
-  if (parent) parent->drawTextCentre(text, area.x + x, area.y + y, colour);\r
-  else  surface->drawTextCentre(text, x, y, colour);\r
-}\r
-// Now deprecated\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
-\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, const DisplayRegion & region)\r
-{\r
-  if (parent) parent->drawBitmap(area.x + x, area.y + y, bm, region);\r
-  else  if (surface) surface->drawBitmap(x, y, bm, region);\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
-void Boxx::drawMonoBitmap(UCHAR*base, int dx, int dy, unsigned int height,unsigned int width, Colour& nextColour)\r
-{\r
-       if (parent) parent->drawMonoBitmap(base, area.x +dx,area.y +dy, height,width, nextColour);\r
-       else if (surface) surface->drawMonoBitmap(base, dx,dy, height,width, nextColour);\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
-float Boxx::charWidth(wchar_t c)\r
-{\r
-  if (parent) return parent->charWidth(c);\r
-  else  if (surface) return surface->getCharWidth(c);\r
-  else return 16.; //?\r
-}\r
-\r
-wchar_t Boxx::getWChar(const char* str, unsigned int *length)\r
-{\r
-       if (parent) return parent->getWChar(str,length);\r
-       else  if (surface) return surface->getWChar(str,length);\r
-       else return '?'; //?\r
-}\r
-\r
-Surface * Boxx::getSurface() {\r
-  if (parent) return parent->getSurface();\r
-  return surface;\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 "osd.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;
+  //int count=0;
+  for (j = children.begin(); j != children.end(); j++)
+  {
+    currentBoxx = *j;
+   // Log::getInstance()->log("Boxx", Log::DEBUG, "Draw child %d %d", count,currentBoxx);
+    if (currentBoxx->getVisible()) currentBoxx->draw();
+   // count++;
+  }  
+ // Log::getInstance()->log("Boxx", Log::DEBUG, "Draw this %p surface %p End", this, surface);
+}
+
+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 = Osd::getInstance()->createNewSurface();
+  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 DrawStyle& 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 DrawStyle& colour)
+{
+  rectangle(0, 0, area.w, area.h, colour);
+}
+
+void Boxx::drawPara(const char* text, int x, int y, const DrawStyle& colour)
+{
+  char line[256];
+  int lineHeight = getFontHeight() + paraVSpace;
+
+  float lineWidth;
+  float thisCharWidth;
+  int textPos;
+  int linePos;
+  int ypos;
+  int printLine;
+
+  textPos = 0;
+  ypos = y;
+
+  while(1)
+  {
+    linePos = 0;
+    lineWidth = 0;
+    while(1)
+    {
+      printLine = 0;
+      unsigned int cur_length=1;
+      wchar_t cur_char=getWChar(text+textPos,&cur_length);
+
+      if (cur_char == '\0') break;
+
+      if (cur_char == '\n')
+      {
+        textPos+=cur_length; // ignore the \n
+        printLine = 1;
+        break;
+      }
+      thisCharWidth = charWidth(cur_char);
+      if ((lineWidth + thisCharWidth) > (int)(area.w - (2 * paraMargin)))
+      {
+        // this character would break the right margin
+        if (cur_char == ' ')
+        {
+          // this char is a space, ignore and break
+          textPos+=cur_length;
+          break;
+        }
+        else
+        {
+          // Need to go back to the last space in the line
+          while ((cur_char != ' ') && (linePos >= 0))
+          {
+            textPos-=cur_length;
+            cur_char=getWChar(text+textPos,&cur_length);
+            linePos--;
+          }
+          // Now take the space we just found
+          textPos+=cur_length;
+          break;
+        }
+      }
+      for (int n=0;n<cur_length;n++) line[linePos++] = text[textPos+n];
+      lineWidth += thisCharWidth;
+      textPos+=cur_length;
+    }
+
+//    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 DrawStyle& 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 DrawStyle& colour)
+{
+  if (parent) parent->rectangle(area.x + x, area.y + y, w, h, colour);
+  else surface->fillblt(x, y, w, h, colour);
+}
+
+void Boxx::drawText(const char* text, int x, int y, const DrawStyle& colour)
+{
+  if (parent) parent->drawText(text, area.x + x, area.y + y, colour);
+  else surface->drawText(text, x, y, colour);
+}
+
+void Boxx::drawText(const char* text, int x, int y, int width, const DrawStyle& colour)
+{
+  if (parent) parent->drawText(text, area.x + x, area.y + y, width, colour);
+  else surface->drawText(text, x, y, width, colour);
+}
+
+void Boxx::drawTextRJ(const char* text, int x, int y, const DrawStyle& colour)
+{
+  if (parent) parent->drawTextRJ(text, area.x + x, area.y + y, colour);
+  else surface->drawTextRJ(text, x, y, colour);
+}
+
+void Boxx::drawTextCentre(const char* text, int x, int y, const DrawStyle& colour)
+{
+  if (parent) parent->drawTextCentre(text, area.x + x, area.y + y, colour);
+  else  surface->drawTextCentre(text, x, y, colour);
+}
+// Now deprecated
+/*
+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::drawTTChar(int ox, int oy,int x, int y, cTeletextChar c)
+{
+       if (parent) parent->drawTTChar(area.x + ox, area.y + oy, x,y,c);
+       else  if (surface) surface->drawTTChar(ox, oy,x,y,c);
+
+}
+
+void Boxx::drawBitmap(UINT x, UINT y, const Bitmap& bm, const DisplayRegion & region)
+{
+  if (parent) parent->drawBitmap(area.x + x, area.y + y, bm, region);
+  else  if (surface) surface->drawBitmap(x, y, bm, region);
+}
+
+void Boxx::drawJpeg(const char *fileName,int x, int y,int *width, int *height)
+{
+       if (parent) parent->drawJpeg(fileName,area.x +x,area.y +y,width,height);
+       else if (surface) surface->drawJpeg(fileName,x,y,width,height);
+}
+
+void Boxx::drawMonoBitmap(UCHAR*base, int dx, int dy, unsigned int height,unsigned int width, Colour& nextColour)
+{
+       if (parent) parent->drawMonoBitmap(base, area.x +dx,area.y +dy, height,width, nextColour);
+       else if (surface) surface->drawMonoBitmap(base, dx,dy, height,width, nextColour);
+}
+
+int Boxx::getFontHeight()
+{
+       if (parent) return parent->getFontHeight();
+       else if (surface) return surface->getFontHeight();
+       else return 18;
+}
+
+void Boxx::startFastDraw()
+{
+    if (parent) parent->startFastDraw();
+    else
+    {
+        if (surface) surface->startFastDraw();
+    }
+}
+
+void Boxx::endFastDraw()
+{
+    if (parent) parent->endFastDraw();
+    else
+    {
+        if (surface) surface->endFastDraw();
+    }
+}
+
+float Boxx::charWidth(wchar_t c)
+{
+  if (parent) return parent->charWidth(c);
+  else  if (surface) return surface->getCharWidth(c);
+  else return 16.; //?
+}
+
+wchar_t Boxx::getWChar(const char* str, unsigned int *length)
+{
+       if (parent) return parent->getWChar(str,length);
+       else  if (surface) return surface->getWChar(str,length);
+       else return '?'; //?
+}
+
+Surface * Boxx::getSurface() {
+  if (parent) return parent->getSurface();
+  return surface;
+}
+
diff --git a/boxx.h b/boxx.h
index 6755cb74cc277c46f04a8015d1db362122f8668b..06b3c9289814f35d9b85a8902ffcb66e4c031285 100644 (file)
--- a/boxx.h
+++ b/boxx.h
-/*\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
-  friend class Wwss;\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 DrawStyle& 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 DrawStyle & colour);\r
-    void drawPara(const char* text, int x, int y, const DrawStyle& colour);\r
-\r
-    // Drawing functions level 0\r
-    void rectangle(UINT x, UINT y, UINT w, UINT h, const DrawStyle& colour);\r
-    void rectangle(Region& region, const DrawStyle& colour);\r
-\r
-    void drawText(const char* text, int x, int y, const DrawStyle& colour);\r
-    void drawText(const char* text, int x, int y, int width, const DrawStyle& colour);\r
-    void drawTextRJ(const char* text, int x, int y, const DrawStyle& colour);\r
-    void drawTextCentre(const char* text, int x, int y, const DrawStyle& colour);\r
-    //Now deprecated\r
-    //void drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw=false);\r
-    void drawBitmap(UINT x, UINT y, const Bitmap& bm, const DisplayRegion & region);\r
-   //Now deprecated\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
-    void drawMonoBitmap(UCHAR*base, int dx, int dy, unsigned int height,unsigned int width, Colour& nextColour);\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
-    float charWidth(wchar_t c);\r
-    wchar_t getWChar(const char* str, unsigned int *length);\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
-    DrawStyle 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 BOXX_H
+#define BOXX_H
+
+#include <stdio.h>
+#include <vector>
+
+using namespace std;
+
+#include "colour.h"
+#include "region.h"
+#include "message.h"
+
+
+#include "surface.h"
+
+class Bitmap;
+
+class Boxx
+{
+  friend class Wwss;
+  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 DrawStyle& 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 bool mouseAndroidScroll(int x, int y,int sx, int sy) { 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 DrawStyle & colour);
+    void drawPara(const char* text, int x, int y, const DrawStyle& colour);
+
+    // Drawing functions level 0
+    void rectangle(UINT x, UINT y, UINT w, UINT h, const DrawStyle& colour);
+    void rectangle(Region& region, const DrawStyle& colour);
+
+    void drawText(const char* text, int x, int y, const DrawStyle& colour);
+    void drawText(const char* text, int x, int y, int width, const DrawStyle& colour);
+    void drawTextRJ(const char* text, int x, int y, const DrawStyle& colour);
+    void drawTextCentre(const char* text, int x, int y, const DrawStyle& colour);
+    //Now deprecated
+    //void drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw=false);
+    void drawBitmap(UINT x, UINT y, const Bitmap& bm, const DisplayRegion & region);
+   //Now deprecated
+    // void drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw=false);
+    int getFontHeight();
+
+    void drawJpeg(const char *fileName,int x, int y,int *width, int *height);
+
+    void drawTTChar(int ox, int oy,int x, int y, cTeletextChar c);
+    void drawMonoBitmap(UCHAR*base, int dx, int dy, unsigned int height,unsigned int width, Colour& nextColour);
+
+    /* This is for system which need a locking of the drawing surface to speed up drawing */
+    void startFastDraw();
+    void endFastDraw();
+
+    float charWidth(wchar_t c);
+    wchar_t getWChar(const char* str, unsigned int *length);
+
+    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;
+
+    DrawStyle 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.
+
+*/
+
index 814f0538d60282516b44d6fc71cecaf26e5ad816..463d2ecc0a945d2214c73eff2f3dbbf7b47d4937 100644 (file)
-/*\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 "mtd.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(DrawStyle::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
-       if (remote->handlesVolume()) {\r
-               if (button==Remote::DF_LEFT || button==Remote::VOLUMEDOWN)\r
-                       remote->volumeDown();\r
-               else remote->volumeUp();\r
-       } else {\r
-               VVolume* v = new VVolume();\r
-               boxstack->add(v);\r
-               v->handleCommand(button); // this will draw+show\r
-       }\r
-      return;\r
-    }\r
-    case Remote::MUTE:\r
-    {\r
-       if (remote->handlesVolume()) {\r
-               remote->volumeMute();\r
-       } else {\r
-               VMute* v = new VMute();\r
-               v->draw();\r
-               boxstack->add(v);\r
-               boxstack->update(v);\r
-       }\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(DrawStyle::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
-#ifndef VOMP_HAS_EXIT\r
-  // some plattforms, want a proper deinitialisation of their hardware before reboot\r
-  Osd::getInstance()->shutdown();\r
-  Audio::getInstance()->shutdown();\r
-  Video::getInstance()->shutdown();\r
-  Remote::getInstance()->shutdown();\r
-\r
-  reboot(LINUX_REBOOT_CMD_RESTART);\r
-  // if  reboot is not allowed -> stop\r
-  stop();\r
-\r
-\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(DrawStyle::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
-  logger->log("Command", Log::INFO, "Entering doJustConnected");\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::PAL))\r
-        || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))\r
-        || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))\r
-        || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))\r
-        )\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
-      remote->shutdown(); // need on raspberry shut not do any harm, hopefully\r
-      remote->init(RemoteStartDev);\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
-      } else if (!strcmp(config, "PAL_M"))\r
-      {\r
-        logger->log("Command", Log::DEBUG, "Switching to PAL_M");\r
-        video->init(Video::PAL_M);\r
-      } else if (!strcmp(config, "NTSC_J"))\r
-      {\r
-        logger->log("Command", Log::DEBUG, "Switching to NTSC_J");\r
-        video->init(Video::NTSC_J);\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
-    } else  if (!STRCASECMP(config, "HDMI"))\r
-    {\r
-      logger->log("Command", Log::INFO, "Switching to HDMI as Connection=%s", config);\r
-      video->setConnection(Video::HDMI);\r
-    } else  if (!STRCASECMP(config, "HDMI3D"))\r
-    {\r
-      logger->log("Command", Log::INFO, "Switching to HDMI3D as Connection=%s", config);\r
-      video->setConnection(Video::HDMI3D);\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
-\r
-  video->executePendingModeChanges();\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 WIN32
+#include <linux/errno.h>
+#endif
+
+#include "command.h"
+
+#ifdef WIN32
+#include "remotewin.h"
+#endif
+
+#ifdef __ANDROID__
+#include "remoteandroid.h"
+#endif
+
+#include "led.h"
+#include "video.h"
+#include "audio.h"
+#include "mtd.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(DrawStyle::VIDEOBLUE);
+  boxstack->add(bbg);
+  boxstack->update(bbg);
+  boxstack->remove(bbg);
+
+  // Wallpaper
+  WJpeg* wallpaperj = new WJpegTYPE();
+  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
+#ifndef __ANDROID__
+  kill(mainPid, SIGURG);
+#else
+  ((RemoteAndroid*)Remote::getInstance())->Signal();
+#endif
+  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);
+#ifndef __ANDROID__
+    kill(mainPid, SIGURG);
+#else
+    ((RemoteAndroid*)Remote::getInstance())->Signal();
+#endif
+    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
+#ifndef __ANDROID__
+  kill(mainPid, SIGURG);
+#else
+  ((RemoteAndroid*)Remote::getInstance())->Signal();
+#endif
+#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:
+    {
+       if (remote->handlesVolume()) {
+               if (button==Remote::DF_LEFT || button==Remote::VOLUMEDOWN)
+                       remote->volumeDown();
+               else remote->volumeUp();
+       } else {
+               VVolume* v = new VVolume();
+               boxstack->add(v);
+               v->handleCommand(button); // this will draw+show
+       }
+      return;
+    }
+    case Remote::MUTE:
+    {
+       if (remote->handlesVolume()) {
+               remote->volumeMute();
+       } else {
+               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->unsetExternLogger();
+    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(DrawStyle::DANGER);
+    connLost->okButton();
+    connLost->draw();
+    boxstack->add(connLost);
+    boxstack->update(connLost);
+    remote->clearBuffer();
+  }
+  else
+  {
+    logger->unsetExternLogger();
+    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->unsetExternLogger();
+  VDR::getInstance()->disconnect();
+  // just kill it...
+  logger->log("Command", Log::NOTICE, "Reboot");
+#ifndef WIN32
+#ifndef VOMP_HAS_EXIT
+  // some plattforms, want a proper deinitialisation of their hardware before reboot
+  Osd::getInstance()->shutdown();
+  Audio::getInstance()->shutdown();
+  Video::getInstance()->shutdown();
+  Remote::getInstance()->shutdown();
+
+  reboot(LINUX_REBOOT_CMD_RESTART);
+  // if  reboot is not allowed -> stop
+  stop();
+
+
+#else
+  stop();
+
+#ifdef __ANDROID__
+  exit(0);
+#endif
+
+#endif
+#endif //Would we support this on windows?
+}
+
+void Command::connectionLost()
+{
+  logger->unsetExternLogger();
+  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(DrawStyle::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; }
+  logger->log("Command", Log::INFO, "Entering doJustConnected");
+  
+  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->setExternLogger(vdr);
+  }  
+  else
+  {
+         logger->unsetExternLogger();
+    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::PAL))
+        || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))
+        || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))
+        || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))
+        )
+    {
+      // Oh sheesh, need to switch format. Bye bye TV...
+
+      // Take everything down
+      boxstack->removeAll();
+      boxstack->remove(wallpaper);
+      Osd* osd = Osd::getInstance();
+#ifndef __ANDROID__
+      osd->shutdown();
+#endif
+      video->shutdown();
+
+      remote->shutdown(); // need on raspberry shut not do any harm, hopefully
+      remote->init(RemoteStartDev);
+
+      // 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);
+      } else if (!strcmp(config, "PAL_M"))
+      {
+        logger->log("Command", Log::DEBUG, "Switching to PAL_M");
+        video->init(Video::PAL_M);
+      } else if (!strcmp(config, "NTSC_J"))
+      {
+        logger->log("Command", Log::DEBUG, "Switching to NTSC_J");
+        video->init(Video::NTSC_J);
+      }
+#ifndef __ANDROID__
+      //we do not init twice
+      osd->init((char*)("/dev/stbgfx"));
+#endif
+
+      // 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  if (!STRCASECMP(config, "HDMI"))
+    {
+      logger->log("Command", Log::INFO, "Switching to HDMI as Connection=%s", config);
+      video->setConnection(Video::HDMI);
+    } else  if (!STRCASECMP(config, "HDMI3D"))
+    {
+      logger->log("Command", Log::INFO, "Switching to HDMI3D as Connection=%s", config);
+      video->setConnection(Video::HDMI3D);
+    }
+    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
+  {
+#ifdef __ANDROID__
+        logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting letterbox mode");
+        video->setMode(Video::LETTERBOX);
+#else
+    logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
+    video->setMode(Video::NORMAL);
+#endif
+  }
+
+  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);
+
+  video->executePendingModeChanges();
+  // 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);
+  }
+}
index aec5c863050caf73fa0ce66c2f5da90e75a82195..ae606a61ef2db8b7dd233993777a210063dea041 100644 (file)
--- a/defines.h
+++ b/defines.h
-/*\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
-#define BENCHMARK_FPS\r
-\r
-//ULLONG htonll(ULLONG a);\r
-//ULLONG ntohll(ULLONG a);\r
-void MILLISLEEP(ULONG a);\r
-long long getTimeMS();\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
-  #define DEFAULT_TCP_WINDOWSIZENR 1  /*=2048*/\r
-  #define PLAYER_MAX_STREAMING_BUFFERS 120 // for video in uints of 50000 KB\r
-\r
-  #define VOMP_HAS_EXIT\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 OsdOpenVG   // 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 AudioOMX   // This is Audio based on OpenMax and libav for decoding\r
-   #define Video_TYPE VideoOMX   // This is Video based on OpenMax\r
-\r
-\r
-\r
-   #define VPE_OMX_SUPPORT // Activate support for hardware codec using openmax il\r
-   #define VPE_OMX_H264_DECODER "OMX.broadcom.video_decode"\r
-   #define VPE_OMX_MPEG2_DECODER "OMX.broadcom.video_decode"\r
-   #define VPE_OMX_VIDEO_SCHED "OMX.broadcom.video_scheduler"\r
-   #define VPE_OMX_VIDEO_REND "OMX.broadcom.video_render"\r
-   #define VPE_OMX_VIDEO_DEINTERLACE "OMX.broadcom.image_fx"\r
-   #define VPE_OMX_CLOCK "OMX.broadcom.clock"\r
-   #define VPE_OMX_AUDIO_DECODER "OMX.broadcom.audio_decode"\r
-   #define VPE_OMX_AUDIO_REND "OMX.broadcom.audio_render"\r
-\r
-   //#define  VPE_LIBAV_SUPPORT\r
-  // #define  VPE_LIBAV_MPEG2_TRANSCODING\r
-\r
-  #define DEFAULT_TCP_WINDOWSIZENR 6  /*=2048*/\r
-  #define PLAYER_MAX_STREAMING_BUFFERS 120 // for video in uints of 50000 KB\r
-  #define TV_NORM_SWITCHABLE\r
-  #define HANDLE_VT_SWITCHING\r
-\r
-  #define VOMP_LINUX_CLOCK  CLOCK_MONOTONIC\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
-  #define Surface_TYPE SurfaceMVP //deprecated\r
-  #define DEFAULT_TCP_WINDOWSIZENR 1  /*=2048*/\r
-  #define PLAYER_MAX_STREAMING_BUFFERS 11 // for video in uints of 50000 KB\r
-  #define PAL_WSS\r
-  #define MVP_REMOTE_TYPES\r
-\r
-  #define VOMP_MEDIAPLAYER\r
-  #define VOMP_LINUX_CLOCK  CLOCK_REALTIME\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
-  #define Surface_TYPE SurfaceDirectFB //deprecated\r
-  #define DEFAULT_TCP_WINDOWSIZENR 1  /*=2048*/\r
-  #define PLAYER_MAX_STREAMING_BUFFERS 11 // for video in uints of 50000 KB\r
-\r
-  #define VOMP_LINUX_CLOCK  CLOCK_REALTIME\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 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
+
+#define BENCHMARK_FPS
+
+//ULLONG htonll(ULLONG a);
+//ULLONG ntohll(ULLONG a);
+void MILLISLEEP(ULONG a);
+long long getTimeMS();
+
+#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
+  #define DEFAULT_TCP_WINDOWSIZENR 1  /*=2048*/
+  #define PLAYER_MAX_STREAMING_BUFFERS 120 // for video in uints of 50000 KB
+
+  #define VOMP_HAS_EXIT
+
+#else
+
+  int max(int, int);
+  int min(UINT, int);
+/*#ifdef _MIPS_ARCH
+  #define Surface_TYPE SurfaceDirectFB
+#else
+  #define Surface_TYPE SurfaceMVP
+#endif*/
+#ifdef __ANDROID__
+  #define Thread_TYPE ThreadPAndroid
+
+#else
+  #define Thread_TYPE ThreadP
+
+#endif
+  #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
+
+// add here defines for plattform specific objects
+#ifdef VOMP_PLATTFORM_RASPBERRY
+   #define Remote_TYPE RemoteLinux  // Generic Remote under Linux (Konsole!, not X) will support in the end:
+   #define RemoteStartDev ""//No devices passed
+
+  // Keyboard
+  // remotes under /dev/event
+  // HDMI CEC
+  //lirc?
+   #define Mtd_TYPE MtdRaspberry  //this is device dependent
+   #define Led_TYPE LedRaspberry  //this is device dependent
+   #define Osd_TYPE OsdOpenVG   // This OpenGL ES 2.0, in the moment only for raspberry, but might be splitted for other devices
+   #define OsdStartDev ""
+   #define Audio_TYPE AudioOMX   // This is Audio based on OpenMax and libav for decoding
+   #define Video_TYPE VideoOMX   // This is Video based on OpenMax
+
+
+
+   #define VPE_OMX_SUPPORT // Activate support for hardware codec using openmax il
+   #define VPE_OMX_H264_DECODER "OMX.broadcom.video_decode"
+   #define VPE_OMX_MPEG2_DECODER "OMX.broadcom.video_decode"
+   #define VPE_OMX_VIDEO_SCHED "OMX.broadcom.video_scheduler"
+   #define VPE_OMX_VIDEO_REND "OMX.broadcom.video_render"
+   #define VPE_OMX_VIDEO_DEINTERLACE "OMX.broadcom.image_fx"
+   #define VPE_OMX_CLOCK "OMX.broadcom.clock"
+   #define VPE_OMX_AUDIO_DECODER "OMX.broadcom.audio_decode"
+   #define VPE_OMX_AUDIO_REND "OMX.broadcom.audio_render"
+
+   //#define  VPE_LIBAV_SUPPORT
+  // #define  VPE_LIBAV_MPEG2_TRANSCODING
+
+  #define DEFAULT_TCP_WINDOWSIZENR 6  /*=2048*/
+  #define PLAYER_MAX_STREAMING_BUFFERS 120 // for video in uints of 50000 KB
+  #define TV_NORM_SWITCHABLE
+  #define HANDLE_VT_SWITCHING
+
+  #define VOMP_LINUX_CLOCK  CLOCK_MONOTONIC
+
+#endif
+#ifdef VOMP_PLATTFORM_MVP
+  #define Remote_TYPE RemoteMVP
+  #define RemoteStartDev "/dev/rawir"
+  #define Mtd_TYPE MtdMVP
+  #define Led_TYPE LedMVP
+  #define Osd_TYPE OsdMVP
+  #define OsdStartDev "/dev/stbgfx"
+  #define Audio_TYPE AudioMVP
+  #define Video_TYPE VideoMVP
+  #define Surface_TYPE SurfaceMVP //deprecated
+  #define DEFAULT_TCP_WINDOWSIZENR 1  /*=2048*/
+  #define PLAYER_MAX_STREAMING_BUFFERS 11 // for video in uints of 50000 KB
+  #define PAL_WSS
+  #define MVP_REMOTE_TYPES
+
+  #define VOMP_MEDIAPLAYER
+  #define VOMP_LINUX_CLOCK  CLOCK_REALTIME
+#endif
+
+#ifdef VOMP_PLATTFORM_NMT // This was the attempt to port vomp to nmt, it failed but maybe the code is useful at some time
+  #define Remote_TYPE RemoteLirc
+  #define RemoteStartDev "/dev/lircd"
+  #define Mtd_TYPE MtdNMT
+  #define Led_TYPE LedMVP
+  #define Osd_TYPE OsdDirectFB
+  #define OsdStartDev ""
+  #define Audio_TYPE AudioNMT
+  #define Video_TYPE VideoNMT
+  #define Surface_TYPE SurfaceDirectFB //deprecated
+  #define DEFAULT_TCP_WINDOWSIZENR 1  /*=2048*/
+  #define PLAYER_MAX_STREAMING_BUFFERS 11 // for video in uints of 50000 KB
+
+  #define VOMP_LINUX_CLOCK  CLOCK_REALTIME
+
+#endif
+
+#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
index a3700bc5c1ea9b5758bd663cfbf0bf8104198679..db37c9dc5eb7232209167892f32ecf735d0dc98e 100644 (file)
-/*\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
-#define DEMUXER_SEQ_EXT_HEAD 0x000001B5\r
-\r
-#define DEMUXER_H264_ACCESS_UNIT 0x00000109\r
-#define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107\r
-#define DEMUXER_H264_SUB_ENHANCEMENT_INF 0x00000106\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
-UINT PESPacket::findSeqExtHeader(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_SUB_ENHANCEMENT_INF)\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_EXT_HEAD && (data[pos+1]&0xf0)!=0x10)\r
-         {\r
-                 if (++pos >= (size-1))\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
-  astreamtype=4;\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
-  interlaced=true; // default is true\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
-  astreamtype=4;\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(bool * dataavail)\r
-{\r
-  return audiostream.drain(dataavail);\r
-}\r
-\r
-bool Demuxer::writeVideo(bool * dataavail)\r
-{\r
-  return videostream.drain(dataavail);\r
-}\r
-\r
-bool Demuxer::writeTeletext(bool * dataavail)\r
-{\r
-   return teletextstream.drain(dataavail);\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
-      UCHAR type=MPTYPE_MPEG_AUDIO;\r
-      switch (astreamtype)\r
-      {\r
-      case 3:\r
-      case 4:\r
-         type=MPTYPE_MPEG_AUDIO; break;\r
-      case 0x11:\r
-         type=MPTYPE_AAC_LATM; break;\r
-      };\r
-      sent = audiostream.put(&packetdata[0], packet.getSize(), type,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
-               int old_substream=packet.getSubstream();\r
-               if (old_substream){ //someone else already set it, this is live tv\r
-                       substream_id = old_substream;\r
-                       substream_type = substream_id & 0xF0;\r
-                       substream_index = substream_id & 0x1F;\r
-               } else {\r
-                substream_id = PESTYPE_PRIVATE_1;\r
-                substream_type = 0x80;\r
-                substream_index = 0;\r
-               }\r
-\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 tinterlaced=nalu.getBits(1);\r
-                vertical_size*=(2-tinterlaced);\r
-                interlaced=!tinterlaced;\r
-                \r
-                if (!tinterlaced) 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-tinterlaced)*chromunity;\r
-                    vertical_size-=nalu.getUe()*(2-tinterlaced)*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
-            UINT posext = packet.findSeqExtHeader(h264);\r
-            if (posext>1) {\r
-               if (!h264) {\r
-                       interlaced=!(packet[pos+1] & 0x08); //really simple\r
-                       // if more than full hd is coming we need to add additional parsers here\r
-               } else {\r
-               /*      NALUUnit nalu(packet.getData()+posext,packet.getSize()-posext);\r
-                       while (!nalu.isEonalu()) {\r
-                               unsigned int payloadtype=0;\r
-                               unsigned int payloadadd=0xFF;\r
-                               while (payloadadd==0xFF && !nalu.isEonalu()) {\r
-                                       payloadadd=nalu.getBits(8);\r
-                                       payloadtype+=payloadadd;\r
-                               }\r
-                               unsigned int payloadsize=0;\r
-                               payloadadd=0xff;\r
-                               while (payloadadd==0xFF && !nalu.isEonalu()) {\r
-                                      payloadadd=nalu.getBits(8);\r
-                                      payloadsize+=payloadadd;\r
-                           }\r
-                               switch (payloadtype) {\r
-                               case 1: { // picture timing SEI\r
-\r
-                               } break;\r
-                               default: {\r
-                                       while (payloadsize) { // not handled skip\r
-                                               nalu.getBits(8);\r
-                                               payloadsize--;\r
-                                       }\r
-                               } break;\r
-                               }\r
-\r
-\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.
+*/
+
+#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_SEQ_EXT_HEAD 0x000001B5
+
+#define DEMUXER_H264_ACCESS_UNIT 0x00000109
+#define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107
+#define DEMUXER_H264_SUB_ENHANCEMENT_INF 0x00000106
+
+
+#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;
+}
+
+UINT PESPacket::findSeqExtHeader(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_SUB_ENHANCEMENT_INF)
+         {
+                 if (++pos >= size)
+                 {
+                         seq_header = 0;
+                         return 0;
+                 }
+                 pattern = (pattern << 8) | data[pos];
+         }
+         seq_header = pos - 3;
+  }
+  else
+  {
+         while (pattern != DEMUXER_SEQ_EXT_HEAD && (data[pos+1]&0xf0)!=0x10)
+         {
+                 if (++pos >= (size-1))
+                 {
+                         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;
+  astreamtype=4;
+}
+
+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;
+  interlaced=true; // default is true
+  aspect_ratio = (enum AspectRatio) 0;
+  frame_rate = bit_rate = 0;
+  ispre_1_3_19 = false;
+  h264 = false;
+  packetnum=0;
+  astreamtype=4;
+
+  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(bool * dataavail)
+{
+  return audiostream.drain(dataavail);
+}
+
+bool Demuxer::writeVideo(bool * dataavail)
+{
+  return videostream.drain(dataavail);
+}
+
+bool Demuxer::writeTeletext(bool * dataavail)
+{
+   return teletextstream.drain(dataavail);
+}
+
+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)
+       {
+      UCHAR type=MPTYPE_MPEG_AUDIO;
+      switch (astreamtype)
+      {
+      case 3:
+      case 4:
+         type=MPTYPE_MPEG_AUDIO; break;
+      case 0x11:
+         type=MPTYPE_AAC_LATM; break;
+      };
+      sent = audiostream.put(&packetdata[0], packet.getSize(), type,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)
+        {
+               int old_substream=packet.getSubstream();
+               if (old_substream){ //someone else already set it, this is live tv
+                       substream_id = old_substream;
+                       substream_type = substream_id & 0xF0;
+                       substream_index = substream_id & 0x1F;
+               } else {
+                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 tinterlaced=nalu.getBits(1);
+                vertical_size*=(2-tinterlaced);
+                interlaced=!tinterlaced;
+                
+                if (!tinterlaced) 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-tinterlaced)*chromunity;
+                    vertical_size-=nalu.getUe()*(2-tinterlaced)*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);
+                        }
+                    }
+
+                }
+
+            }
+            UINT posext = packet.findSeqExtHeader(h264);
+            if (posext>1) {
+               if (!h264) {
+                       interlaced=!(packet[pos+1] & 0x08); //really simple
+                       // if more than full hd is coming we need to add additional parsers here
+               } else {
+               /*      NALUUnit nalu(packet.getData()+posext,packet.getSize()-posext);
+                       while (!nalu.isEonalu()) {
+                               unsigned int payloadtype=0;
+                               unsigned int payloadadd=0xFF;
+                               while (payloadadd==0xFF && !nalu.isEonalu()) {
+                                       payloadadd=nalu.getBits(8);
+                                       payloadtype+=payloadadd;
+                               }
+                               unsigned int payloadsize=0;
+                               payloadadd=0xff;
+                               while (payloadadd==0xFF && !nalu.isEonalu()) {
+                                      payloadadd=nalu.getBits(8);
+                                      payloadsize+=payloadadd;
+                           }
+                               switch (payloadtype) {
+                               case 1: { // picture timing SEI
+
+                               } break;
+                               default: {
+                                       while (payloadsize) { // not handled skip
+                                               nalu.getBits(8);
+                                               payloadsize--;
+                                       }
+                               } break;
+                               }
+
+
+
+                       }*/
+
+
+               }
+            }
+           
+            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;
+}
+
+void Demuxer::changeTimes(UCHAR* buf, UINT len,UINT playtime)
+{
+       UINT pattern, packet_length;
+       UINT read_pos = 0;
+       if (len < 4) return;
+       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;
+             // ok we have a packet figure out if pts and dts are present and replace them
+             if (read_pos + 19 > len) return;
+             ULLONG new_ts=playtime*90; //play time is on ms so multiply it by 90
+             if (buf[read_pos+7] & 0x80) { // pts is here, replace it
+                 buf[read_pos+9]=0x21 | (( new_ts>>29)& 0xde );
+                 buf[read_pos+10]=0x00 |(( new_ts>>22)& 0xff );
+                 buf[read_pos+11]=0x01 | (( new_ts>>14)& 0xfe );
+                 buf[read_pos+12]=0x00 | (( new_ts>>7)& 0xff );
+                 buf[read_pos+13]=0x01 | (( new_ts<<1)& 0xfe );
+             }
+
+             if (buf[read_pos+7] & 0x40) { // pts is here, replace it
+                  buf[read_pos+14]=0x21 | (( new_ts>>29)& 0xde );
+                  buf[read_pos+15]=0x00 | (( new_ts>>22)& 0xff );
+                  buf[read_pos+16]=0x01 | (( new_ts>>14)& 0xfe );
+                  buf[read_pos+17]=0x00 | (( new_ts>>7)& 0xff );
+                  buf[read_pos+18]=0x01 | (( new_ts<<1)& 0xfe );
+             }
+             read_pos += packet_length;
+             pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)
+                                               | (buf[read_pos+2]);
+             }
+         }
+
+}
+
+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;
+}
+
+
index 2d65ea23e4e05845c6cd491d1dc7b2444403e03e..54db93c2a24306904e0d86227d7916f335b1cbeb 100644 (file)
--- a/demuxer.h
+++ b/demuxer.h
-/*\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 findSeqExtHeader(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(bool * dataavail=NULL);\r
-    bool writeVideo(bool * dataavail=NULL);\r
-    bool writeTeletext(bool * dataavail=NULL);\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
-    bool getInterlaced() { return interlaced;}\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
-    int astreamtype;\r
-\r
-    // Video stream information\r
-    void setAspectRatio(enum AspectRatio);\r
-    Callback* callback;\r
-\r
-    int horizontal_size;\r
-    int vertical_size;\r
-    bool interlaced;\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 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 findSeqExtHeader(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 * dataavail=NULL);
+    bool writeVideo(bool * dataavail=NULL);
+    bool writeTeletext(bool * dataavail=NULL);
+
+    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; }
+    bool getInterlaced() { return interlaced;}
+    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);
+    void changeTimes(UCHAR* buf, UINT len,UINT playtime);
+
+    // 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;
+    int astreamtype;
+
+    // Video stream information
+    void setAspectRatio(enum AspectRatio);
+    Callback* callback;
+
+    int horizontal_size;
+    int vertical_size;
+    bool interlaced;
+    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
index 09c7ea07cad592dd099e64fe1b6030e6fc248c9f..23fdcc327d12e0362ecbdfeb40e14c1e4929d49f 100644 (file)
-/*\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 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 const 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);
+}
+
index fa5c01bd39a8932acb5cc8ce33fbbd6f6bfbaf4b..90a1d90bc82f285e9528f18bafc7014d6f73d672 100644 (file)
@@ -1,96 +1,96 @@
-/*\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, int streamtype);\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 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, int streamtype);
+    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
index c3ddfa5067999f58ded48ca897d627771d5f5c15..c5bd28d71e5208c375c11b3502f87fe43a93d58f 100644 (file)
-/*\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
+/*
+    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 = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+               buf++;
+               len--;
+
+               if (pattern < (UINT)(0x100 | PESTYPE_AUD0) || pattern > (UINT)(
+                               0x100 | HiByte))
+                       continue;
+               HiByte = pattern & 0xFF;
+
+               ret = HiByte;
+               if (HiByte == PESTYPE_AUD0)
+                       break;
+       }
+       return ret;
+}
+
+int DemuxerVDR::findPTS(UCHAR* buf, int len, ULLONG* dest) {
+       while (len >= 14) {
+               UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+               buf++;
+               len--;
+               if (pattern < (0x100 | PESTYPE_AUD0) || pattern > (0x100
+                               | PESTYPE_VIDMAX))
+                       continue;
+
+               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();
+      }
+    }
+  }
+}
index bb8f32e5cc4d0ee36f5dbb93921414295a0e04c1..95d5e0669ccd4f34585c214042b6467a6fc8f86e 100644 (file)
-/*\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
-#define MPTYPE_AAC_LATM 0x07\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
-#ifndef VOMP_PLATTFORM_MVP\r
-  long long presentation_time;/* native time of plattform, in 100 ns units(Windows)*/\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 DrainTargetReady() {return false;}; //if the draintarget is blocking in paused state, this tells that it is ready to rumble\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
+/*
+    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
+#define MPTYPE_AAC_LATM 0x07
+
+
+
+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;
+#ifndef VOMP_PLATTFORM_MVP
+  long long presentation_time;/* native time of plattform, in 100 ns units(Windows)*/
+  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 DrainTargetReady() {return false;}; //if the draintarget is blocking in paused state, this tells that it is ready to rumble
+
+    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;
+    // The drain target might advice the feeder about free buffers with threadSignal
+
+
+};
+
+#endif
diff --git a/feed.h b/feed.h
index 5f6c14b54ecd03b9e27a41fcb39304ed0d8d1865..972253de6b7c9160f1bc15cc8a9a24ef7bd39dd6 100644 (file)
--- a/feed.h
+++ b/feed.h
@@ -1,29 +1,29 @@
-/*\r
-    Copyright 2011 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 FEED_H\r
-#define FEED_H\r
-\r
-class Feed{\r
-public:\r
-       virtual void SignalFeeder()=0;\r
-};\r
-\r
-#endif\r
+/*
+    Copyright 2011 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 FEED_H
+#define FEED_H
+
+class Feed{
+public:
+       virtual void SignalFeeder()=0;
+};
+
+#endif
index d154618a7d0ca5a850c562e04f634ab2d218ee92..1177330426de9f788fedeae13dfe6a195a06d3b2 100644 (file)
@@ -1,93 +1,93 @@
-Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.\r
-\r
-This Font Software is licensed under the SIL Open Font License, Version 1.1.\r
-\r
-This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL\r
-\r
-\r
------------------------------------------------------------\r
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\r
------------------------------------------------------------\r
-\r
-PREAMBLE\r
-The goals of the Open Font License (OFL) are to stimulate worldwide\r
-development of collaborative font projects, to support the font creation\r
-efforts of academic and linguistic communities, and to provide a free and\r
-open framework in which fonts may be shared and improved in partnership\r
-with others.\r
-\r
-The OFL allows the licensed fonts to be used, studied, modified and\r
-redistributed freely as long as they are not sold by themselves. The\r
-fonts, including any derivative works, can be bundled, embedded, \r
-redistributed and/or sold with any software provided that any reserved\r
-names are not used by derivative works. The fonts and derivatives,\r
-however, cannot be released under any other type of license. The\r
-requirement for fonts to remain under this license does not apply\r
-to any document created using the fonts or their derivatives.\r
-\r
-DEFINITIONS\r
-"Font Software" refers to the set of files released by the Copyright\r
-Holder(s) under this license and clearly marked as such. This may\r
-include source files, build scripts and documentation.\r
-\r
-"Reserved Font Name" refers to any names specified as such after the\r
-copyright statement(s).\r
-\r
-"Original Version" refers to the collection of Font Software components as\r
-distributed by the Copyright Holder(s).\r
-\r
-"Modified Version" refers to any derivative made by adding to, deleting,\r
-or substituting -- in part or in whole -- any of the components of the\r
-Original Version, by changing formats or by porting the Font Software to a\r
-new environment.\r
-\r
-"Author" refers to any designer, engineer, programmer, technical\r
-writer or other person who contributed to the Font Software.\r
-\r
-PERMISSION & CONDITIONS\r
-Permission is hereby granted, free of charge, to any person obtaining\r
-a copy of the Font Software, to use, study, copy, merge, embed, modify,\r
-redistribute, and sell modified and unmodified copies of the Font\r
-Software, subject to the following conditions:\r
-\r
-1) Neither the Font Software nor any of its individual components,\r
-in Original or Modified Versions, may be sold by itself.\r
-\r
-2) Original or Modified Versions of the Font Software may be bundled,\r
-redistributed and/or sold with any software, provided that each copy\r
-contains the above copyright notice and this license. These can be\r
-included either as stand-alone text files, human-readable headers or\r
-in the appropriate machine-readable metadata fields within text or\r
-binary files as long as those fields can be easily viewed by the user.\r
-\r
-3) No Modified Version of the Font Software may use the Reserved Font\r
-Name(s) unless explicit written permission is granted by the corresponding\r
-Copyright Holder. This restriction only applies to the primary font name as\r
-presented to the users.\r
-\r
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\r
-Software shall not be used to promote, endorse or advertise any\r
-Modified Version, except to acknowledge the contribution(s) of the\r
-Copyright Holder(s) and the Author(s) or with their explicit written\r
-permission.\r
-\r
-5) The Font Software, modified or unmodified, in part or in whole,\r
-must be distributed entirely under this license, and must not be\r
-distributed under any other license. The requirement for fonts to\r
-remain under this license does not apply to any document created\r
-using the Font Software.\r
-\r
-TERMINATION\r
-This license becomes null and void if any of the above conditions are\r
-not met.\r
-\r
-DISCLAIMER\r
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\r
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\r
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\r
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\r
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\r
-OTHER DEALINGS IN THE FONT SOFTWARE.\r
+Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+
+This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded, 
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
index 8ef5eb00d807d393e73062f965a7d3f73453cbb9..f5e8c6f5486a664d3cc88bff6fb26f236d6aba2f 100644 (file)
@@ -1,85 +1,85 @@
-/*\r
-    Copyright 2012 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 "glosdshader.h"\r
-\r
-const GLchar generic_vertex_shader[] =\r
-               "attribute vec4 vec_pos;\n"\r
-               "attribute vec2 tex_coord;\n"\r
-               "varying vec2 out_texCoord;\n"\r
-               "void main()\n"\r
-               "{\n"\r
-               " gl_Position=vec_pos;\n"\r
-               " out_texCoord=tex_coord;\n"\r
-               "}\n";\r
-\r
-const GLchar osd_frag_shader[] =\r
-               "precision mediump float;\n"\r
-               "uniform sampler2D texture;\n"\r
-               "varying vec2 out_texCoord;\n"\r
-               "void main()\n"\r
-               "{\n"\r
-               " gl_FragColor=texture2D(texture,out_texCoord);\n"\r
-               "}\n";\r
-\r
-GLOsdShader::GLOsdShader(): GLShader("GLOsdShader")\r
-{\r
-\r
-}\r
-\r
-GLOsdShader::~GLOsdShader()\r
-{\r
-       //parent does everything\r
-}\r
-\r
-int GLOsdShader::init()\r
-{\r
-       if (!initShaders(generic_vertex_shader,osd_frag_shader)) {\r
-               return 0;\r
-       }\r
-       osd_sampler_loc=glGetUniformLocation(shad_program,"texture");\r
-       return 1;\r
-\r
-}\r
-\r
-int GLOsdShader::deinit()\r
-{\r
-       return deinitShaders();\r
-}\r
-\r
-int GLOsdShader::PrepareRendering(GLuint osd_tex){ // This Function setups the rendering pipeline according to the shaders standards\r
-       glUseProgram(shad_program);\r
-\r
-       glActiveTexture(GL_TEXTURE0);\r
-       glBindTexture(GL_TEXTURE_2D,osd_tex);\r
-\r
-       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);\r
-       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);\r
-\r
-       glUniform1i(osd_sampler_loc,0);\r
-       return 1;\r
-\r
-}\r
-\r
-int GLOsdShader::BindAttributes()\r
-{\r
-       glBindAttribLocation(shad_program,0,"vec_pos");\r
-       glBindAttribLocation(shad_program,1,"tex_coord");\r
-       return 1;\r
-}\r
+/*
+    Copyright 2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+#include "glosdshader.h"
+
+const GLchar generic_vertex_shader[] =
+               "attribute vec4 vec_pos;\n"
+               "attribute vec2 tex_coord;\n"
+               "varying vec2 out_texCoord;\n"
+               "void main()\n"
+               "{\n"
+               " gl_Position=vec_pos;\n"
+               " out_texCoord=tex_coord;\n"
+               "}\n";
+
+const GLchar osd_frag_shader[] =
+               "precision mediump float;\n"
+               "uniform sampler2D texture;\n"
+               "varying vec2 out_texCoord;\n"
+               "void main()\n"
+               "{\n"
+               " gl_FragColor=texture2D(texture,out_texCoord);\n"
+               "}\n";
+
+GLOsdShader::GLOsdShader(): GLShader("GLOsdShader")
+{
+
+}
+
+GLOsdShader::~GLOsdShader()
+{
+       //parent does everything
+}
+
+int GLOsdShader::init()
+{
+       if (!initShaders(generic_vertex_shader,osd_frag_shader)) {
+               return 0;
+       }
+       osd_sampler_loc=glGetUniformLocation(shad_program,"texture");
+       return 1;
+
+}
+
+int GLOsdShader::deinit()
+{
+       return deinitShaders();
+}
+
+int GLOsdShader::PrepareRendering(GLuint osd_tex){ // This Function setups the rendering pipeline according to the shaders standards
+       glUseProgram(shad_program);
+
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture(GL_TEXTURE_2D,osd_tex);
+
+       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+
+       glUniform1i(osd_sampler_loc,0);
+       return 1;
+
+}
+
+int GLOsdShader::BindAttributes()
+{
+       glBindAttribLocation(shad_program,0,"vec_pos");
+       glBindAttribLocation(shad_program,1,"tex_coord");
+       return 1;
+}
index 3a48ef3275bee4f41adaac2e670125e4435cde2b..22f01d73b34f39f82226e17395286a8d232654f7 100644 (file)
@@ -1,44 +1,44 @@
-/*\r
-    Copyright 2012 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 GL_OSDSHADER_H\r
-#define GL_OSDSHADER_H\r
-\r
-#include "glshader.h"\r
-\r
-class GLOsdShader: public GLShader {\r
-public:\r
-       GLOsdShader();\r
-       virtual ~GLOsdShader();\r
-\r
-       int init();\r
-       int deinit();\r
-\r
-       int PrepareRendering(GLuint osd_tex); // This Function setups the rendering pipeline according to the shaders standards\r
-\r
-protected:\r
-       virtual int BindAttributes();\r
-\r
-       GLint osd_sampler_loc;\r
-\r
-};\r
-\r
-\r
-#endif\r
+/*
+    Copyright 2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef GL_OSDSHADER_H
+#define GL_OSDSHADER_H
+
+#include "glshader.h"
+
+class GLOsdShader: public GLShader {
+public:
+       GLOsdShader();
+       virtual ~GLOsdShader();
+
+       int init();
+       int deinit();
+
+       int PrepareRendering(GLuint osd_tex); // This Function setups the rendering pipeline according to the shaders standards
+
+protected:
+       virtual int BindAttributes();
+
+       GLint osd_sampler_loc;
+
+};
+
+
+#endif
index fce9c7b2308b5071886f42d50970e882db412951..801aca4fb4a7971236fd82e98758eb141ea36bce 100644 (file)
-/*\r
-    Copyright 2012 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 "glshader.h"\r
-\r
-GLShader::GLShader(const char* name)\r
-{\r
-       initted=0;\r
-       objname=name;\r
-}\r
-\r
-GLShader::~GLShader()\r
-{\r
-       if (initted) {\r
-               deinitShaders();\r
-       }\r
-\r
-\r
-\r
-}\r
-\r
-int GLShader::initShaders(const char * vertex_shad,const char *fragment_shad)\r
-{\r
-         vertex_shader=CreateShader(vertex_shad, GL_VERTEX_SHADER);\r
-         frag_shader=CreateShader(fragment_shad, GL_FRAGMENT_SHADER);\r
-\r
-         // Create the program for osd rendering\r
-         shad_program=glCreateProgram();\r
-         if (shad_program==0) {\r
-                 Log::getInstance()->log("GLShader", Log::WARN, "%s: Creating glsl program failed!%d",objname,glGetError());\r
-             return 0;\r
-         }\r
-         glAttachShader(shad_program,vertex_shader);\r
-         glAttachShader(shad_program,frag_shader);\r
-         if (!BindAttributes()) {\r
-                 return 0;\r
-         }\r
-         glLinkProgram(shad_program);\r
-\r
-\r
-         GLint link_status;\r
-         glGetProgramiv(shad_program,GL_LINK_STATUS, &link_status);\r
-\r
-         if (!link_status) {\r
-                 char buffer[1024];\r
-                 glGetProgramInfoLog(shad_program,1024,NULL,buffer);\r
-                 Log::getInstance()->log("GLShader", Log::WARN, "%s: Compiling Programm failed!",objname);\r
-                 Log::getInstance()->log("GLShader", Log::WARN, "%s",buffer);\r
-                 glDeleteProgram(shad_program);\r
-                 return 0;\r
-         }\r
-\r
-}\r
-\r
-GLuint GLShader::CreateShader(const GLchar * source, GLenum type)\r
-{\r
-       GLuint ret_shad=0;\r
-\r
-       ret_shad=glCreateShader(type);\r
-       if (ret_shad==0 ) {\r
-               Log::getInstance()->log("GLShader", Log::WARN, "%s: Creating Shader failed! %d",objname, glGetError());\r
-               return 0;\r
-       }\r
-       glShaderSource(ret_shad,1,&source,NULL);\r
-       glCompileShader(ret_shad);\r
-       GLint comp_status;\r
-       glGetShaderiv(ret_shad,GL_COMPILE_STATUS, &comp_status);\r
-\r
-       if (!comp_status) {\r
-               char buffer[1024];\r
-               Log::getInstance()->log("GLShader", Log::WARN, "%s: Compiling Shader failed!",objname);\r
-               glGetShaderInfoLog(ret_shad,1024,NULL,buffer);\r
-               Log::getInstance()->log("GLShader", Log::WARN, "%s: %s",objname,buffer);\r
-               glDeleteShader(ret_shad);\r
-               return 0;\r
-       }\r
-       return ret_shad;\r
-}\r
-\r
-int GLShader::deinitShaders()\r
-{\r
-        if (frag_shader!=0) glDeleteShader(frag_shader);\r
-        frag_shader=0;\r
-        if (vertex_shader!=0) glDeleteShader(vertex_shader);\r
-        vertex_shader=0;\r
-        if (shad_program!=0) glDeleteProgram(shad_program);\r
-        shad_program=0;\r
-        initted=0;\r
-        return 0;\r
-}\r
-\r
+/*
+    Copyright 2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+#include "glshader.h"
+
+GLShader::GLShader(const char* name)
+{
+       initted=0;
+       objname=name;
+}
+
+GLShader::~GLShader()
+{
+       if (initted) {
+               deinitShaders();
+       }
+
+
+
+}
+
+int GLShader::initShaders(const char * vertex_shad,const char *fragment_shad)
+{
+         vertex_shader=CreateShader(vertex_shad, GL_VERTEX_SHADER);
+         frag_shader=CreateShader(fragment_shad, GL_FRAGMENT_SHADER);
+
+         // Create the program for osd rendering
+         shad_program=glCreateProgram();
+         if (shad_program==0) {
+                 Log::getInstance()->log("GLShader", Log::WARN, "%s: Creating glsl program failed!%d",objname,glGetError());
+             return 0;
+         }
+         glAttachShader(shad_program,vertex_shader);
+         glAttachShader(shad_program,frag_shader);
+         if (!BindAttributes()) {
+                 return 0;
+         }
+         glLinkProgram(shad_program);
+
+
+         GLint link_status;
+         glGetProgramiv(shad_program,GL_LINK_STATUS, &link_status);
+
+         if (!link_status) {
+                 char buffer[1024];
+                 glGetProgramInfoLog(shad_program,1024,NULL,buffer);
+                 Log::getInstance()->log("GLShader", Log::WARN, "%s: Compiling Programm failed!",objname);
+                 Log::getInstance()->log("GLShader", Log::WARN, "%s",buffer);
+                 glDeleteProgram(shad_program);
+                 return 0;
+         }
+
+}
+
+GLuint GLShader::CreateShader(const GLchar * source, GLenum type)
+{
+       GLuint ret_shad=0;
+
+       ret_shad=glCreateShader(type);
+       if (ret_shad==0 ) {
+               Log::getInstance()->log("GLShader", Log::WARN, "%s: Creating Shader failed! %d",objname, glGetError());
+               return 0;
+       }
+       glShaderSource(ret_shad,1,&source,NULL);
+       glCompileShader(ret_shad);
+       GLint comp_status;
+       glGetShaderiv(ret_shad,GL_COMPILE_STATUS, &comp_status);
+
+       if (!comp_status) {
+               char buffer[1024];
+               Log::getInstance()->log("GLShader", Log::WARN, "%s: Compiling Shader failed!",objname);
+               glGetShaderInfoLog(ret_shad,1024,NULL,buffer);
+               Log::getInstance()->log("GLShader", Log::WARN, "%s: %s",objname,buffer);
+               glDeleteShader(ret_shad);
+               return 0;
+       }
+       return ret_shad;
+}
+
+int GLShader::deinitShaders()
+{
+        if (frag_shader!=0) glDeleteShader(frag_shader);
+        frag_shader=0;
+        if (vertex_shader!=0) glDeleteShader(vertex_shader);
+        vertex_shader=0;
+        if (shad_program!=0) glDeleteProgram(shad_program);
+        shad_program=0;
+        initted=0;
+        return 0;
+}
+
index b349e4c326de83f621292b05c01c399def0037c7..5f772d0d8a8b274afe165cc09fdfb5156e4e046a 100644 (file)
@@ -1,55 +1,55 @@
-/*\r
-    Copyright 2012 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 GL_SHADER_H\r
-#define GL_SHADER_H\r
-\r
-#include <GLES2/gl2.h>\r
-#include "log.h"\r
-\r
-class GLShader {\r
-public:\r
-       GLShader(const char* name);\r
-       virtual ~GLShader();\r
-\r
-       int initShaders(const GLchar  * vertex_shad,const GLchar  *fragment_shad);\r
-\r
-       int deinitShaders();\r
-\r
-\r
-\r
-protected:\r
-\r
-       GLuint CreateShader(const GLchar * source, GLenum type);\r
-\r
-       virtual int BindAttributes() {return 1;};\r
-\r
-       GLuint vertex_shader;\r
-       GLuint frag_shader;\r
-\r
-       GLuint shad_program;\r
-       int initted;\r
-       const char* objname;\r
-\r
-};\r
-\r
-\r
-\r
-#endif\r
+/*
+    Copyright 2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef GL_SHADER_H
+#define GL_SHADER_H
+
+#include <GLES2/gl2.h>
+#include "log.h"
+
+class GLShader {
+public:
+       GLShader(const char* name);
+       virtual ~GLShader();
+
+       int initShaders(const GLchar  * vertex_shad,const GLchar  *fragment_shad);
+
+       int deinitShaders();
+
+
+
+protected:
+
+       GLuint CreateShader(const GLchar * source, GLenum type);
+
+       virtual int BindAttributes() {return 1;};
+
+       GLuint vertex_shader;
+       GLuint frag_shader;
+
+       GLuint shad_program;
+       int initted;
+       const char* objname;
+
+};
+
+
+
+#endif
index 533a0571a9dbd2d7c9cba90e98f633f4ff898e30..11c73343eac95279048398b221657cb2bfa73dc9 100644 (file)
-/*\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
+/*
+    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"
+
+#include "threadsystem.h"
+
+
+
+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
+
diff --git a/log.cc b/log.cc
index ac80171e65af8d8d8847f084bde36817a8419f93..1d8c57545ce614061d206ae2560611254f294479 100644 (file)
--- a/log.cc
+++ b/log.cc
-/*\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
-void Log::logLongString(const char *fromModule, int level,const char *message)\r
-{\r
-       int string_size=strlen(message);\r
-       char buffer[100];\r
-       const char * pointer=message;\r
-       for (int str_written=0; str_written<string_size;str_written+=99) {\r
-               strncpy(buffer,pointer,99);\r
-               buffer[99]=0;\r
-               pointer+=99;\r
-               log(fromModule,level,"%s",buffer);\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.
+*/
+
+#include "log.h"
+
+#include "vdr.h"
+
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+
+Log* Log::instance = NULL;
+
+Log::Log()
+{
+  if (instance) return;
+  instance = this;
+  logfile = NULL;
+  initted = 0;
+  logLevel = 0;
+  extlog = NULL;
+}
+
+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,const 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(const char *fromModule, int level,const char* message, ...)
+{
+  if (!instance || !logfile) return 0;
+
+  if (!enabled && !extlog) 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)
+  {
+#ifndef __ANDROID__
+    success = fputs(buffer, logfile);
+    fflush(NULL);
+#else
+    int and_level=0;
+    switch (level) {
+    case CRAZY:
+    case ALERT:
+    case EMERG :
+    case CRIT:{
+       and_level=ANDROID_LOG_FATAL;
+    } break;
+    case ERR: {
+       and_level=ANDROID_LOG_ERROR;
+    } break;
+    case WARN: {
+       and_level=ANDROID_LOG_WARN;
+    } break;
+    case NOTICE:
+    case INFO: {
+        and_level=ANDROID_LOG_INFO;
+    } break;
+    case DEBUG :{
+        and_level=ANDROID_LOG_DEBUG;
+    } break;
+    };
+    __android_log_vprint(and_level, fromModule,
+                             message,  ap);
+#endif
+  }
+
+  if (extlog) extlog->LogExtern(buffer); //Replacement for network logging
+
+
+  if (success != EOF)
+    return 1;
+  else
+    return 0;
+
+}
+
+void Log::logLongString(const char *fromModule, int level,const char *message)
+{
+       int string_size=strlen(message);
+       char buffer[100];
+       const char * pointer=message;
+       for (int str_written=0; str_written<string_size;str_written+=99) {
+               strncpy(buffer,pointer,99);
+               buffer[99]=0;
+               pointer+=99;
+               log(fromModule,level,"%s",buffer);
+       }
+
+}
+
+int Log::status()
+{
+  if (instance && logfile) return 1;
+  else return 0;
+}
+
+void Log::setExternLogger(ExternLogger* login) {
+       extlog=login;
+    log("Log", Log::DEBUG, "Extern logging started");
+}
+
+
+
+
diff --git a/log.h b/log.h
index 1c3528d062a277daabd17a493402080b8d044770..be9cf27269f18ff3e2b4cb66f117b263e860a7a3 100644 (file)
--- a/log.h
+++ b/log.h
-/*\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
-    void logLongString(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
+    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 ExternLogger {
+public:
+       virtual bool LogExtern(const char* message)=0;
+};
+
+
+class Log
+{
+  public:
+    Log();
+    ~Log();
+    static Log* getInstance();
+
+    int init(int defaultLevel,const char* fileName, int enabled);
+    int shutdown();
+    int log(const char *fromModule, int level,const char *message, ...);
+    void logLongString(const char *fromModule, int level,const char *message);
+    int status();
+    void upLogLevel();
+    void downLogLevel();
+    void setExternLogger(ExternLogger* log);
+    void unsetExternLogger() {
+       extlog=NULL;
+    }
+
+
+
+    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;
+    
+    ExternLogger* extlog;
+
+
+};
+
+#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);
+
+*/
diff --git a/main.cc b/main.cc
index ae156b02108108f195234ba7ab4264dc546d56a3..360eea6c5a1362ddb7cf6c990fcabbc1806be90f 100644 (file)
--- a/main.cc
+++ b/main.cc
-/*\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
-\r
-#ifdef HANDLE_VT_SWITCHING\r
-#include <signal.h>\r
-#include <sys/ioctl.h>\r
-#include <linux/vt.h>\r
-#endif\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 "osdopenvg.h"\r
-#include "audioomx.h"\r
-#include "videoomx.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
-#ifdef HANDLE_VT_SWITCHING\r
-int fdtty;\r
-struct vt_mode old_vtmode;\r
-#endif\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
-#ifdef HANDLE_VT_SWITCHING\r
-  if ((fdtty = open("/dev/tty", O_WRONLY),0) == -1) {\r
-         logger->log("Core", Log::EMERG, "Could not open /dev/tty. Please change permissions");\r
-  } else {\r
-         int free_vt;\r
-         if (ioctl(fdtty,VT_OPENQRY,&free_vt)==-1 || free_vt==-1){\r
-                 logger->log("Core", Log::EMERG, "Could not retrieve free virtual console, please change permissions");\r
-         } else {\r
-                 ioctl(fdtty,VT_ACTIVATE,free_vt);\r
-                 ioctl(fdtty,VT_WAITACTIVE,free_vt);\r
-                 ioctl(fdtty, VT_LOCKSWITCH, 1);\r
-         }\r
-  }\r
-\r
-#endif\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
-#ifdef HANDLE_VT_SWITCHING\r
-  ioctl(fdtty, VT_UNLOCKSWITCH, 1);\r
-  close(fdtty);\r
-#endif\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
-long long getTimeMS() {\r
-       struct timespec ts;\r
-       clock_gettime(VOMP_LINUX_CLOCK, &ts);\r
-       return ts.tv_sec*1000+ts.tv_nsec/1000000LL;\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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#ifndef WIN32
+#include <unistd.h>
+#include <endian.h>
+#endif
+
+#include "defines.h"
+
+#ifdef HANDLE_VT_SWITCHING
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+#endif
+#include "log.h"
+#include "timers.h"
+#include "vdr.h"
+#include "boxstack.h"
+#include "command.h"
+
+
+#ifdef VOMP_PLATTFORM_MVP
+
+
+#include "mtdmvp.h"
+#include "remotemvp.h"
+#include "ledmvp.h"
+#include "osdmvp.h"
+#include "audiomvp.h"
+#include "videomvp.h"
+
+extern "C"
+{
+  int ticonfig_main(int, char**);
+}
+
+#endif
+
+#ifdef VOMP_PLATTFORM_NMT
+
+#include "mtdnmt.h"
+#include "remotelirc.h"
+#include "lednmt.h"
+#include "osddirectfb.h"
+#include "audionmt.h"
+#include "videonmt.h"
+
+#endif
+
+#ifdef VOMP_PLATTFORM_RASPBERRY
+
+#include "mtdraspberry.h"
+#include "remotelinux.h"
+#include "ledraspberry.h"
+#include "osdopenvg.h"
+#include "audioomx.h"
+#include "videoomx.h"
+
+#endif
+
+
+
+
+#include "wol.h"
+#include "vsleeptimer.h"
+
+
+#ifndef WIN32
+void sighandler(int signalReceived);
+#endif
+
+void shutdown(int code);
+
+
+
+// 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;
+
+#ifdef HANDLE_VT_SWITCHING
+int fdtty;
+struct vt_mode old_vtmode;
+#endif
+
+// Linux MVP main function and sighandler
+#ifndef WIN32
+int main(int argc, char** argv)
+{
+#ifdef VOMP_PLATTFORM_MVP
+  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();
+
+  mtd        = new Mtd_TYPE();
+  remote     = new Remote_TYPE();
+  led        = new Led_TYPE();
+  osd        = new Osd_TYPE();
+  audio      = new Audio_TYPE();
+  video      = new Video_TYPE();
+
+
+
+  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");
+
+#ifdef HANDLE_VT_SWITCHING
+  if ((fdtty = open("/dev/tty", O_WRONLY),0) == -1) {
+         logger->log("Core", Log::EMERG, "Could not open /dev/tty. Please change permissions");
+  } else {
+         int free_vt;
+         if (ioctl(fdtty,VT_OPENQRY,&free_vt)==-1 || free_vt==-1){
+                 logger->log("Core", Log::EMERG, "Could not retrieve free virtual console, please change permissions");
+         } else {
+                 ioctl(fdtty,VT_ACTIVATE,free_vt);
+                 ioctl(fdtty,VT_WAITACTIVE,free_vt);
+                 ioctl(fdtty, VT_LOCKSWITCH, 1);
+         }
+  }
+
+#endif
+
+  // Init modules ----------------------------------------------------------------------------------------------------
+  int success;
+
+  success = remote->init(RemoteStartDev);
+
+  if (success)
+  {
+    logger->log("Core", Log::INFO, "Remote module initialised");
+  }
+  else
+  {
+    logger->log("Core", Log::EMERG, "Remote module failed to initialise");
+    shutdown(1);
+  }
+#ifdef VOMP_PLATTFORM_MVP
+  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*)OsdStartDev);
+  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");
+  }
+#ifdef HANDLE_VT_SWITCHING
+  ioctl(fdtty, VT_UNLOCKSWITCH, 1);
+  close(fdtty);
+#endif
+
+  if (logger)
+  {
+    logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");
+    logger->shutdown();
+    delete logger;
+  }
+
+  exit(code);
+}
+
+// -------------------------------------------------------------------------------------------------------------------
+
+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
+}
+
+ULLONG ntohll(ULLONG a)
+{
+  return htonll(a);
+}
+
+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
+}
+
+long long getTimeMS() {
+       struct timespec ts;
+       clock_gettime(VOMP_LINUX_CLOCK, &ts);
+       return ts.tv_sec*1000+ts.tv_nsec/1000000LL;
+}
+
+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;
+}
+
index a2c854fe4970d1fd0087f94608c6b34cc44d844d..b53018a40b36b1131198ffb80d3fdc540971c856 100644 (file)
--- a/message.h
+++ b/message.h
@@ -1,82 +1,82 @@
-/*\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
+/*
+    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>
+
+class Message;
+#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;
+    const static ULONG MOUSE_ANDROID_SCROLL = 35;
+};
+
+#endif
index b1436c4952921189d47706ba3f25df60366c3b9e..5ecff896523cdfcaa80cc3c40c1e8846f6dab90a 100644 (file)
@@ -1,28 +1,28 @@
-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           \\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  \\r
-           serialize.o localmediafile.o   playermedia.o \\r
-           demuxermedia.o tfeed.o vteletextview.o teletextdecodervbiebu.o        \\r
-           teletxt/txtfont.o mediafile.o\r
-\r
+OBJECTS1 = command.o  tcp.o dsock.o thread.o timers.o i18n.o       \
+           message.o messagequeue.o udp.o wol.o audio.o video.o log.o  mutex.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            \
+           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           \
+           woptionpane.o woptionbox.o wremoteconfig.o wtabbar.o                  \
+           fonts/helvB24.o fonts/helvB18.o                                       \
+           remote.o led.o mtd.o  osd.o surface.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  mediaoptions.o mediaplayer.o  \
+           serialize.o localmediafile.o   playermedia.o \
+           demuxermedia.o tfeed.o vteletextview.o teletextdecodervbiebu.o        \
+           teletxt/txtfont.o mediafile.o
+
diff --git a/osd.h b/osd.h
index cf3a8717dd675a8e60a729934b397b157388ba40..0fe00b9a8f12738d6f5912618e08d54da99837b7 100644 (file)
--- a/osd.h
+++ b/osd.h
@@ -1,56 +1,56 @@
-/*\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 OSD_H\r
-#define OSD_H\r
-\r
-#include <stdio.h>\r
-\r
-class Surface;\r
-\r
-class Osd\r
-{\r
-  public:\r
-    Osd();\r
-    virtual ~Osd();\r
-    static Osd* getInstance();\r
-\r
-    virtual int init(void* device)=0;\r
-    virtual int shutdown()=0;\r
-    virtual int restore(){return 1;};\r
-    virtual int stopUpdate() {return 1;};\r
-\r
-    virtual Surface * createNewSurface()=0; // For Boxx\r
-    virtual int charSet() {return 1;};\r
-\r
-    bool isInitted() {return initted;};\r
-\r
-    virtual int getFD()=0;\r
-\r
-    virtual void screenShot(const char* fileName)=0;\r
-\r
-  protected:\r
-    static Osd* instance;\r
-    int initted;\r
-    Surface* screen;\r
-    int fdOsd;\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.
+*/
+
+#ifndef OSD_H
+#define OSD_H
+
+#include <stdio.h>
+
+class Surface;
+
+class Osd
+{
+  public:
+    Osd();
+    virtual ~Osd();
+    static Osd* getInstance();
+
+    virtual int init(void* device)=0;
+    virtual int shutdown()=0;
+    virtual int restore(){return 1;};
+    virtual int stopUpdate() {return 1;};
+
+    virtual Surface * createNewSurface()=0; // For Boxx
+    virtual int charSet() {return 1;};
+
+    bool isInitted() {return initted;};
+
+    virtual int getFD()=0;
+
+    virtual void screenShot(const char* fileName)=0;
+
+  protected:
+    static Osd* instance;
+    int initted;
+    Surface* screen;
+    int fdOsd;
+};
+
+#endif
index a62a2bd63edbdfc582487420435d221f2224fa3a..9d68a41f07509d6cf3215e1e103638be030a7f31 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon, 2006,2011-2012 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
-#include "osdopengl.h"\r
-#include "mtd.h"\r
-#include "videoomx.h"\r
-#include "surfaceopengl.h"\r
-\r
-\r
-#include "message.h"\r
-#include "command.h"\r
-\r
-\r
-#define  BACKBUFFER_WIDTH 1280\r
-#define  BACKBUFFER_HEIGHT 720\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-OsdOpenGL::OsdOpenGL()\r
-{\r
-  glmutex.Lock();\r
-\r
-  external_driving=false;\r
-\r
-  lastrendertime=getTimeMS();\r
-  display_height=0;\r
-  display_width=0;\r
-  mode=0;\r
-\r
-#ifdef BENCHMARK_FPS\r
-       last_benchmark_time=getTimeMS();\r
-       num_benchmark_frames=0;\r
-#endif\r
-\r
-  \r
-}\r
-\r
-OsdOpenGL::~OsdOpenGL()\r
-{\r
-\r
-  if (initted) \r
-  {\r
-         threadStop();\r
-               shutdown();\r
-  }\r
-\r
-\r
-  glmutex.Unlock();\r
-}\r
-\r
-int OsdOpenGL::getFD()\r
-{\r
-  if (!initted) return 0;\r
-  return fdOsd;\r
-}\r
-\r
-Surface * OsdOpenGL::createNewSurface() {\r
-       return (Surface*)new SurfaceOpenGL();\r
-}\r
-\r
-int OsdOpenGL::init(void* device)\r
-{\r
-  if (initted) return 0;\r
-  Video* video = Video::getInstance();\r
-   //window=*((HWND*)device);\r
-  \r
-   // May be this device specific part should go to a device specific child class\r
-\r
-   //init broadcom chipset (Move to video?)\r
-\r
-\r
-   //First get connection to egl\r
-   egl_display=eglGetDisplay(EGL_DEFAULT_DISPLAY);\r
-\r
-   if (egl_display==EGL_NO_DISPLAY) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Could not get egl display! %x",eglGetError());\r
-          glmutex.Unlock();\r
-          return 0;\r
-   }\r
-\r
-\r
-\r
-   if (eglInitialize(egl_display, NULL, NULL)==EGL_FALSE) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Initialising display failed! %x",eglGetError());\r
-          glmutex.Unlock();\r
-          return 0;\r
-   }\r
-\r
-   const char *query_str=eglQueryString(egl_display,EGL_CLIENT_APIS);\r
-   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());\r
-   query_str=eglQueryString(egl_display,EGL_EXTENSIONS);\r
-   if (query_str)    Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());\r
-\r
-   const EGLint attributs[]={\r
-                EGL_RED_SIZE,8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,\r
-         EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,\r
-         EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,\r
-         EGL_NONE\r
-   }; // Here, we might have to select the resolution!\r
-\r
-\r
-   EGLint number;\r
-\r
-   if (eglChooseConfig(egl_display, attributs, &egl_ourconfig, 1, &number)==EGL_FALSE) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Choosing egl config failed! %x",eglGetError());\r
-          glmutex.Unlock();\r
-          return 0;\r
-   }\r
-\r
-   const EGLint attr_context[]={\r
-                  EGL_CONTEXT_CLIENT_VERSION,2,\r
-          EGL_NONE\r
-      };\r
-\r
-   egl_context=eglCreateContext(egl_display,egl_ourconfig,EGL_NO_CONTEXT,attr_context);\r
-   if (egl_context==EGL_NO_CONTEXT) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Creating egl context failed! %x",eglGetError());\r
-          glmutex.Unlock();\r
-          return 0;\r
-   }\r
-\r
-   // warning broadcom specific, get display size!\r
-   display_width=display_height=0;\r
-   if (graphics_get_display_size(0, &display_width, &display_height)<0) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Getting display size failed! (BCM API) ");\r
-          glmutex.Unlock();\r
-          return 0;\r
-   }\r
-   Log::getInstance()->log("OSD", Log::NOTICE, "Displaysize is %d x %d ",display_width, display_height);\r
-   VC_RECT_T dst_rect ={0,0,display_width,display_height};\r
-   VC_RECT_T src_rect={0,0,BACKBUFFER_WIDTH <<16,BACKBUFFER_HEIGHT<<16};\r
-\r
-  DISPMANX_UPDATE_HANDLE_T  bcm_update;\r
-\r
-   bcm_display=vc_dispmanx_display_open(0);\r
-   bcm_update=vc_dispmanx_update_start(0);\r
-   bcm_element=vc_dispmanx_element_add(bcm_update,bcm_display,\r
-         2,&dst_rect, 0,\r
-         &src_rect,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);\r
-\r
-   vc_dispmanx_update_submit_sync(bcm_update);\r
-   static EGL_DISPMANX_WINDOW_T nativewindow;\r
-   nativewindow.element=bcm_element;\r
-   nativewindow.height=BACKBUFFER_HEIGHT;\r
-   nativewindow.width=BACKBUFFER_WIDTH;\r
-\r
-   egl_surface = eglCreateWindowSurface(egl_display,egl_ourconfig, &nativewindow,NULL );\r
-   if (egl_surface==EGL_NO_SURFACE) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Creating egl window surface failed!");\r
-          glmutex.Unlock();\r
-          return 0;\r
-   }\r
-\r
-   if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed");\r
-          glmutex.Unlock();\r
-                  return 0;\r
-   }\r
-   // Test stuff\r
-\r
-   query_str=(const char*)glGetString(GL_VERSION) ;\r
-   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());\r
-\r
-   query_str=(const char*)glGetString(GL_VENDOR) ;\r
-   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());\r
-\r
-   query_str=(const char*)glGetString(GL_RENDERER) ;\r
-   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());\r
-\r
-   query_str=(const char*)glGetString(GL_EXTENSIONS) ;\r
-   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());\r
-\r
-\r
-\r
-\r
-  //Now we will create the Screen\r
-  screen = (Surface*) new SurfaceOpenGL(Surface::SCREEN);\r
-\r
-  screen->create(video->getScreenWidth(), video->getScreenHeight());\r
-  screen->display();\r
-  initted = 1; // must set this here or create surface won't work\r
-\r
-  //glGenBuffers(1, &vB);\r
-  //glGenBuffers(1, &iB);\r
-\r
-  //Preparing the Shaders\r
-\r
-  if (!osd_shader.init()) {\r
-         Log::getInstance()->log("OSD", Log::WARN, "Init Osd Shader failed");\r
-         glmutex.Unlock();\r
-         return 0;\r
-  }\r
-\r
-\r
-\r
-\r
-  glClearColor(0.0f,0.0f,0.0f,1.f);\r
-  eglSwapInterval(egl_display, 1 );\r
-\r
-  eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
-\r
-  if (((VideoOMX*)Video::getInstance())->initUsingOSDObjects()!=1) { //call Video for init opengl stuff\r
-         return 0;\r
-  }\r
-\r
-\r
-  glmutex.Unlock();\r
-  threadStart();\r
-\r
-  return 1;\r
-}\r
-       \r
-void OsdOpenGL::InitVertexBuffer(float  scalex,float scaley)\r
-{\r
-  Video* video=Video::getInstance();\r
-  float texx=1.f;\r
-  float texy=1.f;\r
-  OSDCOLOR osdcolor={1.f,1.f,1.f,1.f};\r
-\r
- // osdvertices[0].c=osdcolor;\r
-  osdvertices[0].x= (scalex);\r
-  osdvertices[0].y=-scaley;\r
-  osdvertices[0].z=0.5;\r
-  osdvertices[0].u=texx;\r
-  osdvertices[0].v=texy;\r
- // osdvertices[1].c=osdcolor;\r
-  osdvertices[1].x=(scalex);\r
-  osdvertices[1].y=(scaley);\r
-  osdvertices[1].z=0.5f;\r
-  osdvertices[1].u=texx;\r
-  osdvertices[1].v=0.f;\r
-  //  osdvertices[0].c=osdcolor;\r
-  osdvertices[2].x=(-scalex);\r
-  osdvertices[2].y=-scaley;\r
-  osdvertices[2].z=0.5f;\r
-  osdvertices[2].u=0.f;\r
-  osdvertices[2].v=texy;\r
- // osdvertices[3].c=osdcolor;\r
-  osdvertices[3].x=-scalex;\r
-  osdvertices[3].y=(scaley);\r
-  osdvertices[3].z=0.5f;\r
-  osdvertices[3].u=0.f;\r
-  osdvertices[3].v=0.f;\r
-  \r
-  osdindices[0]=0;\r
-  osdindices[1]=1;\r
-  osdindices[2]=2;\r
-  osdindices[3]=0;\r
-  osdindices[4]=2;\r
-  osdindices[5]=3;\r
-\r
-  return;\r
-}\r
-\r
-int OsdOpenGL::shutdown()\r
-{\r
-  if (!initted) return 0;\r
-  glmutex.Lock();\r
-  initted = 0;\r
-  threadStop();\r
-  delete screen;\r
-  screen=NULL;\r
-\r
-  (((VideoOMX*)Video::getInstance())->shutdownUsingOSDObjects());\r
-\r
-\r
-  osd_shader.deinit();\r
-\r
-  glClear(GL_COLOR_BUFFER_BIT);\r
-  eglSwapBuffers(egl_display, egl_surface);\r
-  eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
-  eglDestroySurface(egl_display,egl_surface);\r
-  eglDestroyContext(egl_display,egl_context);\r
-  eglTerminate(egl_display );\r
-\r
-  DISPMANX_UPDATE_HANDLE_T  bcm_update;\r
-  bcm_update=vc_dispmanx_update_start(0);\r
-\r
-  vc_dispmanx_element_remove(bcm_update,bcm_element);\r
-  vc_dispmanx_update_submit_sync(bcm_update);\r
-  vc_dispmanx_display_close(bcm_display);\r
-\r
-\r
-  return 1;\r
-}\r
-\r
-void OsdOpenGL::screenShot(const char* fileName)\r
-{\r
-  BeginPainting();\r
-  screen->screenShot(fileName);\r
-  EndPainting();\r
-}\r
-\r
-void OsdOpenGL::threadMethod()\r
-{\r
-       // We have to claim the gl context for this thread\r
-       //glmutex.Lock();\r
-\r
-       //glmutex.Unlock();\r
-       int ts=0;\r
-       while (true)\r
-       {\r
-               ts=10;\r
-               unsigned int waittime=10;\r
-\r
-               if (initted) {\r
-\r
-                       long long time1 = getTimeMS();\r
-                       if ((time1 - lastrendertime) > 200) {//5 fps for OSD updates are enough, avoids tearing\r
-                               InternalRendering();\r
-                               lastrendertime = getTimeMS();\r
-\r
-                       }\r
-               }\r
-\r
-               threadCheckExit();\r
-               if (ts!=0) {\r
-                       struct timespec target_time;\r
-                       clock_gettime(CLOCK_REALTIME,&target_time);\r
-                       target_time.tv_nsec+=1000000LL*ts;\r
-                       if (target_time.tv_nsec>999999999) {\r
-                               target_time.tv_nsec-=1000000000L;\r
-                               target_time.tv_sec+=1;\r
-                       }\r
-                       threadWaitForSignalTimed(&target_time);\r
-               }\r
-               //Sleep(1);\r
-       }\r
-       //eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
-}\r
-\r
-\r
-void OsdOpenGL::threadPostStopCleanup()\r
-{\r
-       //Doing nothing\r
-       //goo;\r
-}\r
-\r
-\r
-\r
-void OsdOpenGL::InternalRendering(){\r
-\r
-    BeginPainting();\r
-\r
-\r
-\r
-\r
-       //InitVertexBuffer(display_width,display_height);\r
-    InitVertexBuffer(1.f,1.f);\r
-\r
-\r
-       glViewport(0, 0, BACKBUFFER_WIDTH ,BACKBUFFER_HEIGHT);\r
-\r
-       glClearColor(0.0f,0.0f,0.0f,1.f);\r
-       glClear(GL_COLOR_BUFFER_BIT);\r
-\r
-       osd_shader.PrepareRendering(((SurfaceOpenGL*)screen)->getTexture());\r
-\r
-       glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), osdvertices);\r
-       glEnableVertexAttribArray(0);\r
-       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), &(osdvertices[0].u));\r
-       glEnableVertexAttribArray(1);\r
-\r
-\r
-\r
-       glDisable(GL_BLEND);\r
-\r
-\r
-\r
-       glDrawArrays(GL_TRIANGLE_STRIP, 0,  4);\r
-\r
-\r
-\r
-       //Show it to the user!\r
-       eglSwapBuffers(egl_display, egl_surface);\r
-\r
-       EndPainting();\r
-\r
-#ifdef BENCHMARK_FPS\r
-       num_benchmark_frames++;\r
-       if (getTimeMS()-last_benchmark_time>4000) {\r
-               float fps=1000./(float)(getTimeMS()-last_benchmark_time);\r
-               fps*=((float)num_benchmark_frames);\r
-               num_benchmark_frames=0;\r
-               Log::getInstance()->log("OSD", Log::NOTICE, "Current FPS %g", fps);\r
-               last_benchmark_time=getTimeMS();\r
-\r
-       }\r
-\r
-#endif\r
-\r
-       \r
-\r
-}\r
-\r
-\r
-\r
-\r
-void OsdOpenGL::BeginPainting() {//We synchronize calls to d3d between different threads\r
-       glmutex.Lock();\r
-       if (initted) {\r
-               if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {\r
-                       Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in thread %d",eglGetError());\r
-                       return;\r
-               }\r
-       }\r
-}\r
-\r
-void OsdOpenGL::EndPainting() {\r
-       eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
-       glmutex.Unlock();\r
-}\r
-\r
-\r
-\r
-void OsdOpenGL::Blank() {\r
-       BeginPainting();\r
-       glClearColor(0.15f, 1.f, 0.35f, 1.0f); // change this to black after testing\r
-       glClear( GL_COLOR_BUFFER_BIT );\r
-       glClear( GL_DEPTH_BUFFER_BIT );\r
-       EndPainting();\r
-}\r
+/*
+    Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+
+#include "osdopengl.h"
+#include "mtd.h"
+#include "videoomx.h"
+#include "surfaceopengl.h"
+
+
+#include "message.h"
+#include "command.h"
+
+
+#define  BACKBUFFER_WIDTH 1280
+#define  BACKBUFFER_HEIGHT 720
+
+
+
+
+
+
+
+OsdOpenGL::OsdOpenGL()
+{
+  glmutex.Lock();
+
+  external_driving=false;
+
+  lastrendertime=getTimeMS();
+  display_height=0;
+  display_width=0;
+  mode=0;
+
+#ifdef BENCHMARK_FPS
+       last_benchmark_time=getTimeMS();
+       num_benchmark_frames=0;
+#endif
+
+  
+}
+
+OsdOpenGL::~OsdOpenGL()
+{
+
+  if (initted) 
+  {
+         threadStop();
+               shutdown();
+  }
+
+
+  glmutex.Unlock();
+}
+
+int OsdOpenGL::getFD()
+{
+  if (!initted) return 0;
+  return fdOsd;
+}
+
+Surface * OsdOpenGL::createNewSurface() {
+       return (Surface*)new SurfaceOpenGL();
+}
+
+int OsdOpenGL::init(void* device)
+{
+  if (initted) return 0;
+  Video* video = Video::getInstance();
+   //window=*((HWND*)device);
+  
+   // May be this device specific part should go to a device specific child class
+
+   //init broadcom chipset (Move to video?)
+
+
+   //First get connection to egl
+   egl_display=eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+   if (egl_display==EGL_NO_DISPLAY) {
+          Log::getInstance()->log("OSD", Log::WARN, "Could not get egl display! %x",eglGetError());
+          glmutex.Unlock();
+          return 0;
+   }
+
+
+
+   if (eglInitialize(egl_display, NULL, NULL)==EGL_FALSE) {
+          Log::getInstance()->log("OSD", Log::WARN, "Initialising display failed! %x",eglGetError());
+          glmutex.Unlock();
+          return 0;
+   }
+
+   const char *query_str=eglQueryString(egl_display,EGL_CLIENT_APIS);
+   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());
+   query_str=eglQueryString(egl_display,EGL_EXTENSIONS);
+   if (query_str)    Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());
+
+   const EGLint attributs[]={
+                EGL_RED_SIZE,8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,
+         EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,
+         EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,
+         EGL_NONE
+   }; // Here, we might have to select the resolution!
+
+
+   EGLint number;
+
+   if (eglChooseConfig(egl_display, attributs, &egl_ourconfig, 1, &number)==EGL_FALSE) {
+          Log::getInstance()->log("OSD", Log::WARN, "Choosing egl config failed! %x",eglGetError());
+          glmutex.Unlock();
+          return 0;
+   }
+
+   const EGLint attr_context[]={
+                  EGL_CONTEXT_CLIENT_VERSION,2,
+          EGL_NONE
+      };
+
+   egl_context=eglCreateContext(egl_display,egl_ourconfig,EGL_NO_CONTEXT,attr_context);
+   if (egl_context==EGL_NO_CONTEXT) {
+          Log::getInstance()->log("OSD", Log::WARN, "Creating egl context failed! %x",eglGetError());
+          glmutex.Unlock();
+          return 0;
+   }
+
+   // warning broadcom specific, get display size!
+   display_width=display_height=0;
+   if (graphics_get_display_size(0, &display_width, &display_height)<0) {
+          Log::getInstance()->log("OSD", Log::WARN, "Getting display size failed! (BCM API) ");
+          glmutex.Unlock();
+          return 0;
+   }
+   Log::getInstance()->log("OSD", Log::NOTICE, "Displaysize is %d x %d ",display_width, display_height);
+   VC_RECT_T dst_rect ={0,0,display_width,display_height};
+   VC_RECT_T src_rect={0,0,BACKBUFFER_WIDTH <<16,BACKBUFFER_HEIGHT<<16};
+
+  DISPMANX_UPDATE_HANDLE_T  bcm_update;
+
+   bcm_display=vc_dispmanx_display_open(0);
+   bcm_update=vc_dispmanx_update_start(0);
+   bcm_element=vc_dispmanx_element_add(bcm_update,bcm_display,
+         2,&dst_rect, 0,
+         &src_rect,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);
+
+   vc_dispmanx_update_submit_sync(bcm_update);
+   static EGL_DISPMANX_WINDOW_T nativewindow;
+   nativewindow.element=bcm_element;
+   nativewindow.height=BACKBUFFER_HEIGHT;
+   nativewindow.width=BACKBUFFER_WIDTH;
+
+   egl_surface = eglCreateWindowSurface(egl_display,egl_ourconfig, &nativewindow,NULL );
+   if (egl_surface==EGL_NO_SURFACE) {
+          Log::getInstance()->log("OSD", Log::WARN, "Creating egl window surface failed!");
+          glmutex.Unlock();
+          return 0;
+   }
+
+   if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
+          Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed");
+          glmutex.Unlock();
+                  return 0;
+   }
+   // Test stuff
+
+   query_str=(const char*)glGetString(GL_VERSION) ;
+   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());
+
+   query_str=(const char*)glGetString(GL_VENDOR) ;
+   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());
+
+   query_str=(const char*)glGetString(GL_RENDERER) ;
+   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());
+
+   query_str=(const char*)glGetString(GL_EXTENSIONS) ;
+   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",glGetError());
+
+
+
+
+  //Now we will create the Screen
+  screen = (Surface*) new SurfaceOpenGL(Surface::SCREEN);
+
+  screen->create(video->getScreenWidth(), video->getScreenHeight());
+  screen->display();
+  initted = 1; // must set this here or create surface won't work
+
+  //glGenBuffers(1, &vB);
+  //glGenBuffers(1, &iB);
+
+  //Preparing the Shaders
+
+  if (!osd_shader.init()) {
+         Log::getInstance()->log("OSD", Log::WARN, "Init Osd Shader failed");
+         glmutex.Unlock();
+         return 0;
+  }
+
+
+
+
+  glClearColor(0.0f,0.0f,0.0f,1.f);
+  eglSwapInterval(egl_display, 1 );
+
+  eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+
+  if (((VideoOMX*)Video::getInstance())->initUsingOSDObjects()!=1) { //call Video for init opengl stuff
+         return 0;
+  }
+
+
+  glmutex.Unlock();
+  threadStart();
+
+  return 1;
+}
+       
+void OsdOpenGL::InitVertexBuffer(float  scalex,float scaley)
+{
+  Video* video=Video::getInstance();
+  float texx=1.f;
+  float texy=1.f;
+  OSDCOLOR osdcolor={1.f,1.f,1.f,1.f};
+
+ // osdvertices[0].c=osdcolor;
+  osdvertices[0].x= (scalex);
+  osdvertices[0].y=-scaley;
+  osdvertices[0].z=0.5;
+  osdvertices[0].u=texx;
+  osdvertices[0].v=texy;
+ // osdvertices[1].c=osdcolor;
+  osdvertices[1].x=(scalex);
+  osdvertices[1].y=(scaley);
+  osdvertices[1].z=0.5f;
+  osdvertices[1].u=texx;
+  osdvertices[1].v=0.f;
+  //  osdvertices[0].c=osdcolor;
+  osdvertices[2].x=(-scalex);
+  osdvertices[2].y=-scaley;
+  osdvertices[2].z=0.5f;
+  osdvertices[2].u=0.f;
+  osdvertices[2].v=texy;
+ // osdvertices[3].c=osdcolor;
+  osdvertices[3].x=-scalex;
+  osdvertices[3].y=(scaley);
+  osdvertices[3].z=0.5f;
+  osdvertices[3].u=0.f;
+  osdvertices[3].v=0.f;
+  
+  osdindices[0]=0;
+  osdindices[1]=1;
+  osdindices[2]=2;
+  osdindices[3]=0;
+  osdindices[4]=2;
+  osdindices[5]=3;
+
+  return;
+}
+
+int OsdOpenGL::shutdown()
+{
+  if (!initted) return 0;
+  glmutex.Lock();
+  initted = 0;
+  threadStop();
+  delete screen;
+  screen=NULL;
+
+  (((VideoOMX*)Video::getInstance())->shutdownUsingOSDObjects());
+
+
+  osd_shader.deinit();
+
+  glClear(GL_COLOR_BUFFER_BIT);
+  eglSwapBuffers(egl_display, egl_surface);
+  eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+  eglDestroySurface(egl_display,egl_surface);
+  eglDestroyContext(egl_display,egl_context);
+  eglTerminate(egl_display );
+
+  DISPMANX_UPDATE_HANDLE_T  bcm_update;
+  bcm_update=vc_dispmanx_update_start(0);
+
+  vc_dispmanx_element_remove(bcm_update,bcm_element);
+  vc_dispmanx_update_submit_sync(bcm_update);
+  vc_dispmanx_display_close(bcm_display);
+
+
+  return 1;
+}
+
+void OsdOpenGL::screenShot(const char* fileName)
+{
+  BeginPainting();
+  screen->screenShot(fileName);
+  EndPainting();
+}
+
+void OsdOpenGL::threadMethod()
+{
+       // We have to claim the gl context for this thread
+       //glmutex.Lock();
+
+       //glmutex.Unlock();
+       int ts=0;
+       while (true)
+       {
+               ts=10;
+               unsigned int waittime=10;
+
+               if (initted) {
+
+                       long long time1 = getTimeMS();
+                       if ((time1 - lastrendertime) > 200) {//5 fps for OSD updates are enough, avoids tearing
+                               InternalRendering();
+                               lastrendertime = getTimeMS();
+
+                       }
+               }
+
+               threadCheckExit();
+               if (ts!=0) {
+                       struct timespec target_time;
+                       clock_gettime(CLOCK_REALTIME,&target_time);
+                       target_time.tv_nsec+=1000000LL*ts;
+                       if (target_time.tv_nsec>999999999) {
+                               target_time.tv_nsec-=1000000000L;
+                               target_time.tv_sec+=1;
+                       }
+                       threadWaitForSignalTimed(&target_time);
+               }
+               //Sleep(1);
+       }
+       //eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+}
+
+
+void OsdOpenGL::threadPostStopCleanup()
+{
+       //Doing nothing
+       //goo;
+}
+
+
+
+void OsdOpenGL::InternalRendering(){
+
+    BeginPainting();
+
+
+
+
+       //InitVertexBuffer(display_width,display_height);
+    InitVertexBuffer(1.f,1.f);
+
+
+       glViewport(0, 0, BACKBUFFER_WIDTH ,BACKBUFFER_HEIGHT);
+
+       glClearColor(0.0f,0.0f,0.0f,1.f);
+       glClear(GL_COLOR_BUFFER_BIT);
+
+       osd_shader.PrepareRendering(((SurfaceOpenGL*)screen)->getTexture());
+
+       glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), osdvertices);
+       glEnableVertexAttribArray(0);
+       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), &(osdvertices[0].u));
+       glEnableVertexAttribArray(1);
+
+
+
+       glDisable(GL_BLEND);
+
+
+
+       glDrawArrays(GL_TRIANGLE_STRIP, 0,  4);
+
+
+
+       //Show it to the user!
+       eglSwapBuffers(egl_display, egl_surface);
+
+       EndPainting();
+
+#ifdef BENCHMARK_FPS
+       num_benchmark_frames++;
+       if (getTimeMS()-last_benchmark_time>4000) {
+               float fps=1000./(float)(getTimeMS()-last_benchmark_time);
+               fps*=((float)num_benchmark_frames);
+               num_benchmark_frames=0;
+               Log::getInstance()->log("OSD", Log::NOTICE, "Current FPS %g", fps);
+               last_benchmark_time=getTimeMS();
+
+       }
+
+#endif
+
+       
+
+}
+
+
+
+
+void OsdOpenGL::BeginPainting() {//We synchronize calls to d3d between different threads
+       glmutex.Lock();
+       if (initted) {
+               if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
+                       Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in thread %d",eglGetError());
+                       return;
+               }
+       }
+}
+
+void OsdOpenGL::EndPainting() {
+       eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+       glmutex.Unlock();
+}
+
+
+
+void OsdOpenGL::Blank() {
+       BeginPainting();
+       glClearColor(0.15f, 1.f, 0.35f, 1.0f); // change this to black after testing
+       glClear( GL_COLOR_BUFFER_BIT );
+       glClear( GL_DEPTH_BUFFER_BIT );
+       EndPainting();
+}
index d3825c4ff46c7c9eefed36c9c005d9d3b3365a79..853c334e2790f24842fcc411aca5a58cf848ccd6 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon, 2006,2011-2012 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 OSDOPENGL_H\r
-#define OSDOPENGL_H\r
-\r
-#include <stdio.h>\r
-\r
-\r
-\r
-#include <GLES2/gl2.h>\r
-#include <EGL/egl.h>\r
-#include <EGL/eglext.h>\r
-\r
-#include "osd.h"\r
-#include "defines.h"\r
-#include "log.h"\r
-#include "threadp.h"\r
-#include "mutex.h"\r
-#include "videoomx.h"\r
-\r
-#include "glosdshader.h"\r
-\r
-\r
-\r
-\r
-\r
-\r
-struct OSDCOLOR{\r
-       GLfloat r;\r
-       GLfloat g;\r
-       GLfloat b;\r
-       GLfloat a;\r
-};\r
-\r
-\r
-struct OSDVERTEX {\r
-       GLfloat x;\r
-       GLfloat y;\r
-       GLfloat z;\r
-/*     OSDCOLOR c;*/\r
-       GLfloat u;\r
-       GLfloat v;\r
-};\r
-\r
-\r
-\r
-\r
-\r
-\r
-class OsdOpenGL : public Osd, public Thread_TYPE\r
-{\r
-  public:\r
-    OsdOpenGL();\r
-    virtual ~OsdOpenGL();\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
-\r
-       void BeginPainting();\r
-       void EndPainting();\r
-\r
-       void Blank();\r
-\r
-       void getEGLObjs(EGLDisplay *i_egl_display,EGLSurface *i_egl_surface,EGLContext *i_egl_context, EGLConfig *i_egl_config){\r
-               *i_egl_display=egl_display;\r
-               *i_egl_surface=egl_surface;\r
-               *i_egl_context=egl_context;\r
-               *i_egl_config=egl_ourconfig;\r
-       };\r
-\r
-       EGLConfig getEGLConfig() {return egl_ourconfig;};\r
-\r
-       void AdviseAboutNewFrame() {threadSignal();};\r
-\r
-\r
-\r
-\r
-private:\r
-\r
-       //Maybe move the following stuff to a generic opengl object also for boosting DCT etc.\r
-\r
-\r
-\r
-       void threadMethod();\r
-    void threadPostStopCleanup();\r
-\r
-       // This indicates, that currently a video is played, thus the osd updates are driven by the Videosystem\r
-       bool external_driving;\r
-       Mutex glmutex;\r
-       long long  lastrendertime;\r
-       void InternalRendering();\r
-       void InitVertexBuffer(float  scalex,float scaley);\r
-       OSDVERTEX osdvertices[4];\r
-       GLubyte osdindices[6];\r
-\r
-       GLOsdShader osd_shader;\r
-\r
-\r
-\r
-\r
-        /* BCM specific */\r
-\r
-    uint32_t display_height;\r
-       uint32_t display_width;\r
-       DISPMANX_DISPLAY_HANDLE_T bcm_display;\r
-       DISPMANX_ELEMENT_HANDLE_T bcm_element;\r
-\r
-       uint32_t mode;\r
-\r
-\r
-       EGLDisplay egl_display;\r
-       EGLSurface egl_surface;\r
-       EGLContext egl_context;\r
-       EGLConfig egl_ourconfig;\r
-#ifdef BENCHMARK_FPS\r
-       long long last_benchmark_time;\r
-       unsigned int num_benchmark_frames;\r
-#endif\r
-\r
-};\r
-\r
-#endif\r
+/*
+    Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef OSDOPENGL_H
+#define OSDOPENGL_H
+
+#include <stdio.h>
+
+
+
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "osd.h"
+#include "defines.h"
+#include "log.h"
+#include "threadp.h"
+#include "mutex.h"
+#include "videoomx.h"
+
+#include "glosdshader.h"
+
+
+
+
+
+
+struct OSDCOLOR{
+       GLfloat r;
+       GLfloat g;
+       GLfloat b;
+       GLfloat a;
+};
+
+
+struct OSDVERTEX {
+       GLfloat x;
+       GLfloat y;
+       GLfloat z;
+/*     OSDCOLOR c;*/
+       GLfloat u;
+       GLfloat v;
+};
+
+
+
+
+
+
+class OsdOpenGL : public Osd, public Thread_TYPE
+{
+  public:
+    OsdOpenGL();
+    virtual ~OsdOpenGL();
+
+    int init(void* device);
+    int shutdown();
+
+    int getFD();
+
+    void screenShot(const char* fileName);
+
+    Surface * createNewSurface();
+
+
+       void BeginPainting();
+       void EndPainting();
+
+       void Blank();
+
+       void getEGLObjs(EGLDisplay *i_egl_display,EGLSurface *i_egl_surface,EGLContext *i_egl_context, EGLConfig *i_egl_config){
+               *i_egl_display=egl_display;
+               *i_egl_surface=egl_surface;
+               *i_egl_context=egl_context;
+               *i_egl_config=egl_ourconfig;
+       };
+
+       EGLConfig getEGLConfig() {return egl_ourconfig;};
+
+       void AdviseAboutNewFrame() {threadSignal();};
+
+
+
+
+private:
+
+       //Maybe move the following stuff to a generic opengl object also for boosting DCT etc.
+
+
+
+       void threadMethod();
+    void threadPostStopCleanup();
+
+       // This indicates, that currently a video is played, thus the osd updates are driven by the Videosystem
+       bool external_driving;
+       Mutex glmutex;
+       long long  lastrendertime;
+       void InternalRendering();
+       void InitVertexBuffer(float  scalex,float scaley);
+       OSDVERTEX osdvertices[4];
+       GLubyte osdindices[6];
+
+       GLOsdShader osd_shader;
+
+
+
+
+        /* BCM specific */
+
+    uint32_t display_height;
+       uint32_t display_width;
+       DISPMANX_DISPLAY_HANDLE_T bcm_display;
+       DISPMANX_ELEMENT_HANDLE_T bcm_element;
+
+       uint32_t mode;
+
+
+       EGLDisplay egl_display;
+       EGLSurface egl_surface;
+       EGLContext egl_context;
+       EGLConfig egl_ourconfig;
+#ifdef BENCHMARK_FPS
+       long long last_benchmark_time;
+       unsigned int num_benchmark_frames;
+#endif
+
+};
+
+#endif
index b78a1b4d28d34d8030e4e4cf9e47e38c13f0b03a..28bc22672bd6cbb5efcae97c860149d157d2bc68 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon, 2006,2011-2012 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
-#include "osdopenvg.h"\r
-#include "mtd.h"\r
-#include "videoomx.h"\r
-#include "surface.h"\r
-#include <Magick++.h>\r
-\r
-#include "message.h"\r
-#include "command.h"\r
-#include "teletxt/txtfont.h"\r
-\r
-#include <sys/syscall.h>\r
-#include <vector>\r
-#include <math.h>\r
-\r
-using namespace Magick;\r
-\r
-extern uint8_t font_data[]     asm("_binary_fonts_sourcesans_ttf_start");\r
-extern uint8_t font_data_end[] asm("_binary_fonts_sourcesans_ttf_end");\r
-extern uint8_t vdr_data[]     asm("_binary_other_vdrhires_jpg_start");\r
-extern uint8_t vdr_data_end[] asm("_binary_other_vdrhires_jpg_end");\r
-extern uint8_t wallpaper_data[]     asm("_binary_other_wallpaper720p_jpg_start");\r
-extern uint8_t wallpaper_data_end[] asm("_binary_other_wallpaper720p_jpg_end");\r
-\r
-\r
-#define  BACKBUFFER_WIDTH 1280\r
-#define  BACKBUFFER_HEIGHT 720\r
-\r
-\r
-OsdOpenVG::OsdOpenVG()\r
-{\r
-  vgmutex.Lock();\r
-  taskmutex.Lock();\r
-  lastrendertime=getTimeMS();\r
-  display_height=0;\r
-  display_width=0;\r
-  mode=0;\r
-  aspect_correction=1.;\r
-\r
-  freetype_inited=false;\r
-  wait_id=1;\r
-\r
-}\r
-\r
-OsdOpenVG::~OsdOpenVG()\r
-{\r
-\r
-  if (initted)\r
-  {\r
-               shutdown();\r
-  }\r
-\r
-  if (freetype_inited) FT_Done_Face(ft_face);\r
-\r
-  vgmutex.Unlock();\r
-  taskmutex.Unlock();\r
-}\r
-\r
-\r
-\r
-int OsdOpenVG::init(void* device)\r
-{\r
-  if (initted) return 0;\r
-  Video* video = Video::getInstance();\r
-   //window=*((HWND*)device);\r
-\r
-   // May be this device specific part should go to a device specific child class\r
-\r
-   //init broadcom chipset (Move to video?)\r
-\r
-\r
-   //First get connection to egl\r
-   egl_display=eglGetDisplay(EGL_DEFAULT_DISPLAY);\r
-\r
-   if (egl_display==EGL_NO_DISPLAY) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Could not get egl display! %x",eglGetError());\r
-          vgmutex.Unlock();\r
-          return 0;\r
-   }\r
-\r
-\r
-\r
-   if (eglInitialize(egl_display, NULL, NULL)==EGL_FALSE) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Initialising display failed! %x",eglGetError());\r
-          vgmutex.Unlock();\r
-          return 0;\r
-   }\r
-\r
-\r
-   const char *query_str=eglQueryString(egl_display,EGL_CLIENT_APIS);\r
-   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());\r
-   query_str=eglQueryString(egl_display,EGL_EXTENSIONS);\r
-   if (query_str)    Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());\r
-\r
-   if (eglBindAPI(EGL_OPENVG_API)==EGL_FALSE) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Binding openvg api failed! %x",eglGetError());\r
-          vgmutex.Unlock();\r
-          return 0;\r
-   }\r
-\r
-   const EGLint attributs[]={\r
-                EGL_RED_SIZE,8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,\r
-         EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,\r
-         EGL_CONFORMANT, EGL_OPENVG_BIT,\r
-         EGL_NONE\r
-   }; // Here, we might have to select the resolution!\r
-\r
-\r
-   EGLint number;\r
-\r
-   if (eglChooseConfig(egl_display, attributs, &egl_ourconfig, 1, &number)==EGL_FALSE) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Choosing egl config failed! %x",eglGetError());\r
-          vgmutex.Unlock();\r
-          return 0;\r
-   }\r
-\r
-\r
-\r
-   egl_context=eglCreateContext(egl_display,egl_ourconfig,NULL,NULL);\r
-   if (egl_context==EGL_NO_CONTEXT) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Creating egl context failed! %x",eglGetError());\r
-          vgmutex.Unlock();\r
-          return 0;\r
-   }\r
-\r
-   // warning broadcom specific, get display size!\r
-   display_width=display_height=0;\r
-   if (graphics_get_display_size(0, &display_width, &display_height)<0) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Getting display size failed! (BCM API) ");\r
-          vgmutex.Unlock();\r
-          return 0;\r
-   }\r
-   Log::getInstance()->log("OSD", Log::NOTICE, "Displaysize is %d x %d ",display_width, display_height);\r
-   VC_RECT_T dst_rect ={0,0,display_width,display_height};\r
-   VC_RECT_T src_rect={0,0,BACKBUFFER_WIDTH <<16,BACKBUFFER_HEIGHT<<16};\r
-  // VC_RECT_T src_rect_bg={0,0,1<<16,1<<16};\r
- //  VC_RECT_T src_rect_im={0,0,1,1};\r
-\r
-  /* uint32_t back_image_ptr;\r
-   bcm_backres=vc_dispmanx_resource_create(VC_IMAGE_RGB888,1,1,&back_image_ptr);\r
-   unsigned int color=0x00FF0000;\r
-   vc_dispmanx_resource_write_data(bcm_backres,VC_IMAGE_RGB888,4,&color,&src_rect_im);*/\r
-\r
-   DISPMANX_UPDATE_HANDLE_T  bcm_update;\r
-   bcm_display=vc_dispmanx_display_open(0);\r
-   bcm_update=vc_dispmanx_update_start(0);\r
-   bcm_element=vc_dispmanx_element_add(bcm_update,bcm_display,\r
-         2,&dst_rect, 0,\r
-         &src_rect,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);\r
-\r
-\r
- /*  bcm_background=vc_dispmanx_element_add(bcm_update,bcm_display,\r
-            0,&dst_rect,bcm_backres ,\r
-            &src_rect_bg,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);*/\r
-\r
-   vc_dispmanx_update_submit_sync(bcm_update);\r
-\r
-\r
-\r
-   static EGL_DISPMANX_WINDOW_T nativewindow;\r
-   nativewindow.element=bcm_element;\r
-   nativewindow.height=BACKBUFFER_HEIGHT;\r
-   nativewindow.width=BACKBUFFER_WIDTH;\r
-\r
-   egl_surface = eglCreateWindowSurface(egl_display,egl_ourconfig, &nativewindow,NULL );\r
-   if (egl_surface==EGL_NO_SURFACE) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Creating egl window surface failed!");\r
-          vgmutex.Unlock();\r
-          return 0;\r
-   }\r
-   Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current in1%d",syscall(SYS_gettid));\r
-   if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {\r
-          Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed");\r
-          vgmutex.Unlock();\r
-                  return 0;\r
-   }\r
-   // Test stuff\r
-\r
-   query_str=(const char*)vgGetString(VG_VERSION) ;\r
-   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());\r
-\r
-   query_str=(const char*)vgGetString(VG_VENDOR) ;\r
-   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());\r
-\r
-   query_str=(const char*)vgGetString(VG_RENDERER) ;\r
-   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());\r
-\r
-   query_str=(const char*)vgGetString(VG_EXTENSIONS) ;\r
-   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);\r
-   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());\r
-\r
-  aspect_correction= ((float)BACKBUFFER_HEIGHT)/576.f/(((float)BACKBUFFER_WIDTH)/720.f);\r
-  initPaths();\r
-  if (!loadFont()) {\r
-         return 0;\r
-  }\r
-  vgttfont=vgCreateFont(0);\r
-  vgttpaint=vgCreatePaint();\r
-  vgSetParameteri( vgttpaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);\r
-  vgSetColor(vgttpaint,0xffffffff);\r
-\r
-  eglSwapInterval(egl_display, 1 );\r
-\r
-  Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out 1%d",syscall(SYS_gettid));\r
-  eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
-  //Now we will create the Screen\r
-  initted = 1; // must set this here or create surface won't work\r
-\r
-\r
-  /*if (((VideoOMX*)Video::getInstance())->initUsingOSDObjects()!=1) { //call Video for init  stuff\r
-         return 0;\r
-  }*/\r
-  InitializeMagick("");\r
-\r
-  pthread_cond_init(&vgtaskCond, NULL);\r
-  pthread_mutex_init(&vgtaskCondMutex, NULL);\r
-\r
-  threadStart();\r
-  taskmutex.Unlock();\r
-  vgmutex.Unlock();\r
-\r
-\r
-  return 1;\r
-}\r
-\r
-\r
-void OsdOpenVG::initPaths()\r
-{\r
-\r
-\r
-       VGPath current;\r
-       current=vgCreatePath(VG_PATH_FORMAT_STANDARD,\r
-                       VG_PATH_DATATYPE_F,1.f,0.f,\r
-                       0,0,VG_PATH_CAPABILITY_ALL);\r
-\r
-       vguLine(current,0.f,0.f,1.f,0.f);\r
-       // HorzLine\r
-       std_paths[HorzLine]=current;\r
-\r
-       current=vgCreatePath(VG_PATH_FORMAT_STANDARD,\r
-                               VG_PATH_DATATYPE_F,1.f,0.f,\r
-                               0,0,VG_PATH_CAPABILITY_ALL);\r
-       vguLine(current,0.f,0.f,0.f,1.f);\r
-       // VertLine\r
-       std_paths[VertLine]=current;\r
-\r
-       current=vgCreatePath(VG_PATH_FORMAT_STANDARD,\r
-                               VG_PATH_DATATYPE_F,1.f,0.f,\r
-                               0,0,VG_PATH_CAPABILITY_ALL);\r
-       //vguRect(current,0.f,0.f,1.f,1.f);\r
-       vguRect(current,0.f,0.f,1.f,1.f);\r
-       // Rectabgle\r
-       std_paths[Rectangle]=current;\r
-\r
-       current=vgCreatePath(VG_PATH_FORMAT_STANDARD,\r
-                               VG_PATH_DATATYPE_F,1.f,0.f,\r
-                               0,0,0);\r
-       vguEllipse(current,0.f,0.f,1.f,1.f);\r
-       // Point\r
-       std_paths[Point]=current;\r
-\r
-}\r
-\r
-void OsdOpenVG::destroyPaths()\r
-{\r
-       vgDestroyPath(std_paths[HorzLine]);\r
-       vgDestroyPath(std_paths[VertLine]);\r
-       vgDestroyPath(std_paths[Rectangle]);\r
-       vgDestroyPath(std_paths[Point]);\r
-\r
-}\r
-\r
-int OsdOpenVG::stopUpdate()\r
-{\r
-       threadStop();\r
-       processTasks();\r
-       return 1;\r
-}\r
-\r
-\r
-int OsdOpenVG::shutdown()\r
-{\r
-  if (!initted) return 0;\r
-\r
-  initted = 0;\r
-  Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark1");\r
-  threadStop();\r
-  Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark2");\r
-  processTasks();\r
-  Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark3");\r
-\r
-  taskmutex.Lock();\r
-  vgmutex.Lock();\r
-  //(((VideoOMX*)Video::getInstance())->shutdownUsingOSDObjects());\r
-\r
-\r
-\r
-  vgDestroyFont(vgfont);\r
-  vgDestroyFont(vgttfont);\r
-  vgDestroyPaint(vgttpaint);\r
-  destroyPaths();\r
-  vgClear(0,0,BACKBUFFER_WIDTH,BACKBUFFER_HEIGHT);\r
-  eglSwapBuffers(egl_display, egl_surface);\r
-  Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out final");\r
-  eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
-  eglDestroySurface(egl_display,egl_surface);\r
-  eglDestroyContext(egl_display,egl_context);\r
-  eglTerminate(egl_display );\r
-\r
-  DISPMANX_UPDATE_HANDLE_T  bcm_update;\r
-  bcm_update=vc_dispmanx_update_start(0);\r
-\r
-  vc_dispmanx_element_remove(bcm_update,bcm_element);\r
-//  vc_dispmanx_element_remove(bcm_update,bcm_background);\r
-  vc_dispmanx_update_submit_sync(bcm_update);\r
-//  vc_dispmanx_resource_delete(bcm_backres);\r
-  vc_dispmanx_display_close(bcm_display);\r
-\r
-\r
-\r
-  return 1;\r
-}\r
-\r
-\r
-\r
-\r
-void OsdOpenVG::threadMethod()\r
-{\r
-       // We have to claim the egl context for this thread\r
-\r
-       if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {\r
-               Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in thread %x",eglGetError());\r
-               return;\r
-       }\r
-       int ts=0;\r
-       while (true)\r
-       {\r
-               ts=1;\r
-               unsigned int waittime=1;\r
-\r
-               if (initted) {\r
-\r
-                       long long time1 = getTimeMS();\r
-                       if ((time1 - lastrendertime) > 200) {//5 fps for OSD updates are enough, avoids tearing\r
-                               InternalRendering();\r
-                               lastrendertime = getTimeMS();\r
-\r
-                       }\r
-                       if (processTasks()) ts=0;\r
-               }\r
-               threadCheckExit();\r
-               if (ts!=0) {\r
-                       struct timespec target_time;\r
-                       clock_gettime(CLOCK_REALTIME,&target_time);\r
-                       target_time.tv_nsec+=1000000LL*ts;\r
-                       if (target_time.tv_nsec>999999999) {\r
-                               target_time.tv_nsec-=1000000000L;\r
-                               target_time.tv_sec+=1;\r
-                       }\r
-                       threadLock();\r
-                       threadWaitForSignalTimed(&target_time);\r
-                       threadUnlock();\r
-               }\r
-               //Sleep(1);\r
-       }\r
-       //eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
-}\r
-\r
-\r
-void OsdOpenVG::threadPostStopCleanup()\r
-{\r
-       //Doing nothing\r
-       //goo;\r
-}\r
-\r
-\r
-\r
-\r
-\r
-\r
-void OsdOpenVG::InternalRendering(){\r
-       vgmutex.Lock();\r
-    float colclear[]={1.f,1.0f,1.f,1.f};\r
-    vgSetfv(VG_CLEAR_COLOR,4,colclear);\r
-       vgClear(0,0,BACKBUFFER_WIDTH,BACKBUFFER_HEIGHT);\r
-       vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);\r
-\r
-\r
-       drawSurfaces(); //iterate through and draws all commands\r
-\r
-       //Show it to the user!\r
-       eglSwapBuffers(egl_display, egl_surface);\r
-       vgmutex.Unlock();\r
-\r
-}\r
-\r
-/*font stuff*/\r
-\r
-float OsdOpenVG::getFontHeight()\r
-{\r
-       return font_height; //dummy\r
-}\r
-float OsdOpenVG::getCharWidth(wchar_t c)\r
-{\r
-       unsigned int glyph_index=FT_Get_Char_Index(ft_face,c);\r
-       return font_exp_x[glyph_index];\r
-}\r
-\r
-unsigned int OsdOpenVG::loadTTchar(cTeletextChar c)\r
-{\r
-       unsigned int glyph_index=c.getGlyphIndex();\r
-       if (tt_font_chars.find(glyph_index)!=tt_font_chars.end())\r
-       {\r
-               return glyph_index;\r
-       }\r
-\r
-       unsigned int buffer[10];\r
-       const VGfloat glyphOrigin[] = { 0.f, 0.f };\r
-       const VGfloat escapement[] = { 12.f, 0.f };\r
-       unsigned int * charmap = GetFontChar(c, buffer);\r
-       if (!charmap) { //invalid char\r
-               return 0;\r
-       }\r
-       for (int i=0;i<10;i++) {\r
-               buffer[i]=charmap[i]>>4;\r
-       }\r
-\r
-       VGImage handle = vgCreateImage(\r
-                       VG_A_8,\r
-                       12,\r
-                       10,\r
-                       VG_IMAGE_QUALITY_NONANTIALIASED | VG_IMAGE_QUALITY_FASTER\r
-                                       | VG_IMAGE_QUALITY_BETTER);\r
-       vgImageSubData(handle, buffer, 4, VG_A_1, 0, 0, 12, 10);\r
-       vgSetGlyphToImage(\r
-                       vgttfont,\r
-                       glyph_index,\r
-                       handle, glyphOrigin, escapement);\r
-       vgDestroyImage(handle);\r
-       tt_font_chars[glyph_index]=1;\r
-\r
-       return glyph_index;\r
-}\r
-\r
-int  OsdOpenVG::loadFont()\r
-{\r
-       int error;\r
-       float font_size=16.f;\r
-       if (!freetype_inited) {\r
-               error=FT_Init_FreeType(&ft_library);\r
-               if (error)\r
-               {\r
-                       Log::getInstance()->log("OSD", Log::WARN, "Could not load freetype %x",error);\r
-                       return 0;\r
-               }\r
-\r
-               error=FT_New_Memory_Face(ft_library,font_data,font_data_end-font_data,0,&ft_face );\r
-               if (error) {\r
-                       Log::getInstance()->log("OSD", Log::WARN, "Could not load font face %x",error);\r
-                       return 0;\r
-               }\r
-               error=FT_Set_Char_Size(ft_face,0,font_size*64,0,0 /*dpi*/);\r
-               if (error) {\r
-                       FT_Done_Face(ft_face);\r
-                       Log::getInstance()->log("OSD", Log::WARN, "Could not set  face size %x",error);\r
-                       return 0;\r
-               }\r
-               freetype_inited=true;\r
-       }\r
-       vgfont=vgCreateFont(0);\r
-       FT_ULong cur_char;\r
-       FT_UInt glyph;\r
-       font_height=ft_face->size->metrics.height/64.f;\r
-       cur_char = FT_Get_First_Char(ft_face,&glyph);\r
-       vector<VGubyte> segments;\r
-       vector<VGfloat> coord;\r
-       segments.reserve(256);\r
-       coord.reserve(1024);\r
-       //Log::getInstance()->log("OSD", Log::DEBUG, "Create Glyph test %d %x %x %d",cur_char,font_data_end,font_data,glyph);\r
-       while (glyph !=0)\r
-       {\r
-               error=FT_Load_Glyph(ft_face,glyph,FT_LOAD_DEFAULT);\r
-               if (error){\r
-                       FT_Done_Face(ft_face);\r
-                       Log::getInstance()->log("OSD", Log::WARN, "Could not load glyph %x",error);\r
-                       return 0;\r
-               }\r
-               VGPath path;\r
-               FT_Outline ot=ft_face->glyph->outline;\r
-               segments.clear();\r
-               coord.clear();\r
-\r
-               if (ot.n_contours ==0) {\r
-                       path=VG_INVALID_HANDLE;\r
-               } else {\r
-                       path=vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,\r
-                                       1.0f,0.f,0,0,VG_PATH_CAPABILITY_ALL);\r
-\r
-                       /* convert glyph */\r
-                       FT_Vector *pt=ot.points;\r
-                       const char *tags=ot.tags;\r
-                       const short* cont=ot.contours;\r
-                       short n_cont=ot.n_contours;\r
-                       short n_point=ot.n_points;\r
-                       short last_cont=0;\r
-                       for (short point=0;n_cont!=0;cont++,n_cont--) {\r
-                               short next_cont=*cont+1;\r
-                               bool first=true;\r
-                               char last_tag=0;\r
-                               short first_point=point;\r
-                               //Log::getInstance()->log("OSD", Log::DEBUG, "runs %d",*cont);\r
-                               for (;point<next_cont;point++) {\r
-                                       char tag=tags[point];\r
-                                       FT_Vector fpoint=pt[point];\r
-                               //      Log::getInstance()->log("OSD", Log::DEBUG, "tag %d point %d %d: %d %d",tag,fpoint.x,fpoint.y,point,n_point);\r
-                                       if (first) {\r
-                                               segments.push_back(VG_MOVE_TO);\r
-                                               first=false;\r
-                                       } else if (tag &0x1) { //on curve\r
-                                               if (last_tag &0x1) {\r
-                                                       segments.push_back(VG_LINE_TO);\r
-                                               } else if (last_tag &0x2){\r
-                                                       segments.push_back(VG_CUBIC_TO);\r
-                                               } else {\r
-                                                       segments.push_back(VG_QUAD_TO);\r
-                                               }\r
-\r
-                                       } else {\r
-                                               if (!(tag &0x2)){\r
-                                                       if (!(last_tag &0x1)) {\r
-                                                               segments.push_back(VG_QUAD_TO);\r
-                                                               int coord_size=coord.size();\r
-                                                               VGfloat x=(coord[coord_size-2]+ ((float)fpoint.x)/64.f)*0.5f*aspect_correction;\r
-                                                               VGfloat y=(coord[coord_size-1]+(font_size- ((float)fpoint.y)/64.f))*0.5f;\r
-                                                               coord.push_back(x);\r
-                                                               coord.push_back(y);\r
-                                                       }\r
-                                               }\r
-\r
-\r
-                                       }\r
-                                       last_tag=tag;\r
-                                       coord.push_back(((float)fpoint.x)*aspect_correction/64.);\r
-                                       coord.push_back(font_size-((float)fpoint.y)/64.);\r
-                                       //Log::getInstance()->log("OSD", Log::DEBUG, "Create APD Glyph coord %d %d %g %g",fpoint.x,fpoint.y,coord[coord.size()-2],coord[coord.size()-1]);\r
-                               }\r
-                               if (!(last_tag &0x1)) {\r
-                                       if (last_tag &0x2) {\r
-                                               segments.push_back(VG_CUBIC_TO);\r
-                                       } else {\r
-                                               segments.push_back(VG_QUAD_TO);\r
-                                       }\r
-                                       coord.push_back(((float)pt[first_point].x)*aspect_correction/64.);\r
-                                       coord.push_back(font_size-((float)pt[first_point].y)/64.);\r
-                               }\r
-                               //segments.push_back(VG_CLOSE_PATH);\r
-\r
-\r
-                       }\r
-                       vgAppendPathData(path,segments.size(),&segments[0],&coord[0]);\r
-                       int n=0;\r
-               /*      for (int m=0;m<segments.size();m++) {\r
-                               switch (segments[m])\r
-                               {\r
-                               case VG_MOVE_TO:\r
-                                       Log::getInstance()->log("OSD", Log::DEBUG, "Move To %g %g",coord[n],coord[n+1]);n+=2; break;\r
-                               case VG_LINE_TO:\r
-                                       Log::getInstance()->log("OSD", Log::DEBUG, "Line To %g %g",coord[n],coord[n+1]);n+=2; break;\r
-                               case VG_CUBIC_TO:\r
-                                       Log::getInstance()->log("OSD", Log::DEBUG, "Cubic To %g %g %g %g %g %g",coord[n],coord[n+1],coord[n+2],coord[n+3],coord[n+4],coord[n+5]);n+=6; break;\r
-                               case VG_QUAD_TO:\r
-                                       Log::getInstance()->log("OSD", Log::DEBUG, "Quad To %g %g %g %g",coord[n],coord[n+1],coord[n+2],coord[n+3]);n+=4; break;\r
-                               case VG_CLOSE_PATH:\r
-                                       Log::getInstance()->log("OSD", Log::DEBUG, "Close Path"); break;\r
-                               }\r
-\r
-                       }*/\r
-                       //vguRect(path,0.f,0.f,1.f,1.f);\r
-                       //Log::getInstance()->log("OSD", Log::DEBUG, "Create APD Glyph %d %x",segments.size(),vgGetError());\r
-               }\r
-               VGfloat ori[]={0.f,0.f};\r
-               VGfloat esp[]={ft_face->glyph->advance.x/64.f*aspect_correction,ft_face->glyph->advance.y/64.f};\r
-               font_exp_x[glyph]=ft_face->glyph->advance.x/64.f*aspect_correction; //recalculate\r
-\r
-               vgSetGlyphToPath(vgfont,glyph,path,VG_FALSE,ori,esp);\r
-               //Log::getInstance()->log("OSD", Log::DEBUG, "Create Glyph %d %d %x",path,glyph,vgGetError());\r
-               if (path!=VG_INVALID_HANDLE) {\r
-                       vgDestroyPath(path);\r
-               }\r
-               cur_char = FT_Get_Next_Char(ft_face,cur_char,&glyph);\r
-       }\r
-       return 1;\r
-}\r
-\r
-\r
-void OsdOpenVG::drawSetTrans(SurfaceCommands & sc)\r
-{\r
-       vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);\r
-       vgLoadIdentity();\r
-       vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);\r
-       vgTranslate(0.f+sc.x,-576.f+sc.y);\r
-\r
-       vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);\r
-       vgLoadIdentity();\r
-    vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);\r
-       vgTranslate(0.f+sc.x,-576.f+sc.y);\r
-\r
-       vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);\r
-       vgLoadIdentity();\r
-       vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);\r
-       vgTranslate(0.f+sc.x,-576.f+sc.y);\r
-\r
-\r
-\r
-       //vgTranslate(0.f+sc.x,576.f-sc.y);\r
-       //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Translate %g %g",sc.x,sc.y);\r
-\r
-}\r
-void OsdOpenVG::executeDrawCommand(SVGCommand & command)\r
-{\r
-\r
-       VGfloat  save_matrix[9];\r
-       switch (command.instr) {\r
-       case DrawPath: {\r
-        vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);\r
-       //      VGuint rgba;\r
-       //      rgba = vgGetColor((VGPaint) command.reference);\r
-               //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Path %d %x %g %g %g %g",command.reference,command.target.path_index,command.x,command.y,command.w,command.h);\r
-               //vgSeti(VG_FILL_RULE,);\r
-\r
-               vgGetMatrix(save_matrix);\r
-               vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);\r
-               vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);\r
-               vgTranslate(command.x,command.y);\r
-               vgScale(command.w,command.h);\r
-               vgDrawPath(std_paths[command.target.path_index],VG_FILL_PATH);\r
-               vgLoadMatrix(save_matrix);\r
-       } break;\r
-       case DrawImage: {\r
-           vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);\r
-               vgGetMatrix(save_matrix);\r
-               vgTranslate(command.x,command.y);\r
-               //vgScale(command.w,command.h);\r
-               if (command.reference) { //special behaviout for bw images they act as a mask on the current paint\r
-                       vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);\r
-                       vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);\r
-                       vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_STENCIL);\r
-                       vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);\r
-                       vgScale(aspect_correction,1.f);\r
-               } else {\r
-                       VGfloat imagewidth=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_WIDTH);\r
-                       VGfloat imageheight=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_HEIGHT);\r
-                       //vgScale(720.f/((float)BACKBUFFER_WIDTH), 576.f/((float)BACKBUFFER_HEIGHT));\r
-                       float scalex=command.w/imagewidth;\r
-                       float scaley=command.h/imageheight;\r
-                       //vgScale(command.w/imagewidth,command.h/imageheight);\r
-                       vgScale(scalex,scaley);\r
-                       vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);\r
-                       //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Image Scale  %g %g %g %g %g %g",command.w,imagewidth,command.h,imageheight,scalex,scaley);\r
-               }\r
-\r
-\r
-               //vgLoadIdentity();\r
-               //vgTranslate(200.f,500.f);\r
-               //vgScale(100.f,100.f);\r
-\r
-               vgDrawImage((VGImage) command.target.image);\r
-               //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Image %d %x %g %g %g %g %x",command.reference,command.target.image,command.x,command.y,command.w,command.h,\r
-               //              vgGetError());\r
-               if (command.reference) {\r
-                       vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);\r
-                       vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);\r
-               }\r
-               vgLoadMatrix(save_matrix);\r
-       } break;\r
-       case DrawGlyph: {\r
-               vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);\r
-               vgGetMatrix(save_matrix);\r
-               vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);\r
-               vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);\r
-               vgTranslate(command.x,command.y);\r
-               VGfloat gori[]={0.,0.};\r
-               vgSetfv(VG_GLYPH_ORIGIN,2,gori);\r
-\r
-               unsigned int glyph_index=FT_Get_Char_Index(ft_face,command.target.textchar);\r
-               vgDrawGlyph(vgfont,glyph_index,VG_FILL_PATH,VG_FALSE);\r
-               //vgDrawPath(std_paths[Rectangle],VG_FILL_PATH);\r
-       /*      Log::getInstance()->log("OSD", Log::DEBUG, "Draw Glyph %d %c %d %g %g %x",command.reference,command.target.textchar,glyph_index,command.x,command.y,\r
-                                               vgGetError());*/\r
-               vgLoadMatrix(save_matrix);\r
-               vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);\r
-       } break;\r
-       case DrawTTchar:{\r
-               cTeletextChar tchar;\r
-               tchar.setInternal(command.target.ttchar);\r
-               vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);\r
-               vgGetMatrix(save_matrix);\r
-               enumTeletextColor ttforegcolour=tchar.GetFGColor();\r
-               enumTeletextColor ttbackgcolour=tchar.GetBGColor();\r
-           if (tchar.GetBoxedOut()) {\r
-               ttforegcolour=ttcTransparent;\r
-               ttbackgcolour=ttcTransparent;\r
-           }\r
-           vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_STENCIL);\r
-           vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);\r
-\r
-\r
-               vgTranslate(command.x+command.w*11.85f*1.4f,command.y+command.h*19.75f);\r
-               VGfloat gori[]={0.,0.};\r
-               vgSetfv(VG_GLYPH_ORIGIN,2,gori);\r
-\r
-               vgScale(-1.4f,2.f);\r
-               unsigned int color=Surface::enumTeletextColorToCoulour(ttbackgcolour).rgba();\r
-               color=color<<8 | (color &0xff000000)>>24;\r
-               vgSetColor(vgttpaint,color);\r
-               vgSetPaint((VGPaint) vgttpaint,VG_FILL_PATH);\r
-               vgSetPaint((VGPaint) vgttpaint,VG_STROKE_PATH);\r
-               cTeletextChar filled;\r
-               filled.setInternal(0x187f);\r
-               unsigned int glyph_index=loadTTchar(filled);\r
-               vgDrawGlyph(vgttfont,glyph_index,VG_FILL_PATH,VG_FALSE);\r
-\r
-               color=Surface::enumTeletextColorToCoulour(ttforegcolour).rgba();\r
-               color=color<<8 | (color &0xff000000)>>24;\r
-               vgSetColor(vgttpaint,color);\r
-               vgSetPaint((VGPaint) vgttpaint,VG_FILL_PATH);\r
-               vgSetPaint((VGPaint) vgttpaint,VG_STROKE_PATH);\r
-               glyph_index=loadTTchar(tchar);\r
-               vgDrawGlyph(vgttfont,glyph_index,VG_FILL_PATH,VG_FALSE);\r
-\r
-               /*      Log::getInstance()->log("OSD", Log::DEBUG, "Draw TTchar %x %x %x %x",glyph_index,ttforegcolour,Surface::enumTeletextColorToCoulour(ttforegcolour).rgba(),\r
-                                       vgGetColor(vgttpaint));*/\r
-\r
-\r
-               vgLoadMatrix(save_matrix);\r
-               vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);\r
-               vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);\r
-               vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);\r
-\r
-       }break;\r
-       }\r
-}\r
-\r
-unsigned int OsdOpenVG::handleTask(OpenVGCommand& command)\r
-{\r
-       switch (command.task){\r
-       case OVGdestroyImageRef: {\r
-               vgDestroyImage((VGImage)command.param1);\r
-               return 0;\r
-       } break;\r
-       case OVGdestroyPaint: {\r
-               Log::getInstance()->log("OSD", Log::DEBUG, "Draw Paint Destroy %d ",command.param1);\r
-               vgDestroyPaint((VGPaint)command.param1);\r
-               return 0;\r
-       } break;\r
-       case OVGcreateImagePalette: {\r
-               VGImage input=vgCreateImage(VG_A_8,command.param1, command.param2,\r
-                               VG_IMAGE_QUALITY_NONANTIALIASED|\r
-                               VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);\r
-               vgImageSubData(input,command.data,command.param1,\r
-                                                       VG_A_8,0,0,command.param1, command.param2); // upload palettized image data\r
-               VGImage handle=vgCreateImage(VG_sRGBA_8888,command.param1, command.param2,\r
-                                               VG_IMAGE_QUALITY_NONANTIALIASED|\r
-                                               VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);\r
-               VGuint *palette=(VGuint*)malloc(256*sizeof(VGuint));\r
-               VGuint *in_palette=(VGuint*)command.data2;\r
-               for (int i=0;i<256;i++) {\r
-                       VGuint color=in_palette[i];\r
-                       palette[i]=color<<8 | (color &0xff000000)>>24;\r
-               }\r
-\r
-               vgLookupSingle(handle,input,palette,VG_ALPHA,VG_FALSE,VG_FALSE);\r
-               free(palette);\r
-               vgDestroyImage(input);\r
-\r
-               return handle;\r
-       } break;\r
-       case OVGcreateMonoBitmap: {\r
-               VGImage handle=vgCreateImage(VG_A_1,command.param1, command.param2,\r
-                                       VG_IMAGE_QUALITY_NONANTIALIASED|\r
-                                       VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);\r
-               //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);\r
-               unsigned int buffer_len=(command.param1*command.param2)>>3;\r
-               unsigned char * buffer=(unsigned char*)malloc(buffer_len);\r
-               unsigned char * r_buffer1=buffer;\r
-               const unsigned char * r_buffer2=(const unsigned char *)command.data;\r
-               unsigned char *buffer_end=buffer+buffer_len;\r
-               while (r_buffer1!=buffer_end) {\r
-                       unsigned char byte=*r_buffer2;\r
-                       *r_buffer1=((byte * 0x0802LU & 0x22110LU) | (byte * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;\r
-                       r_buffer1++;r_buffer2++;\r
-               }\r
-\r
-\r
-               vgImageSubData(handle,buffer,command.param1>>3,\r
-                                       VG_A_1,0,0,command.param1, command.param2);\r
-               free(buffer);\r
-       //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono2  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);\r
-               return handle;\r
-       } break;\r
-       case OVGcreateImageFile: {\r
-               VGImage handle;\r
-               try{\r
-                       Image *imagefile=(Image*)command.data;\r
-                       Blob imageblob;\r
-                       imagefile->write(&imageblob,"RGBA");\r
-\r
-\r
-                       handle=vgCreateImage(VG_sXBGR_8888,imagefile->columns(),imagefile->rows(),\r
-                                       VG_IMAGE_QUALITY_NONANTIALIASED|\r
-                                       VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);\r
-               //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details  %d %d %x mark1",imagefile->columns(),imagefile->rows(),*(unsigned int*)imageblob.data());\r
-                       vgImageSubData(handle,imageblob.data(),imagefile->columns()*4,\r
-                                       VG_sXBGR_8888,0,0,imagefile->columns(),imagefile->rows());\r
-               //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details  %d %d %x mark2",imagefile->columns(),imagefile->rows(),*(unsigned int*)imageblob.data());\r
-                       delete imagefile;\r
-               }catch( Exception &error_ )\r
-               {\r
-                       Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick hT: %s",error_.what());\r
-\r
-                       return 0;\r
-               }\r
-\r
-               //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create file  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);\r
-               return handle;\r
-       } break;\r
-       case OVGcreateColorRef :{\r
-               VGPaint handle;\r
-               handle=vgCreatePaint();\r
-               vgSetParameteri(handle, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);\r
-               vgSetColor(handle,command.param1);\r
-               VGuint rgba;\r
-               rgba = vgGetColor((VGPaint)handle);\r
-               Log::getInstance()->log("OSD", Log::DEBUG, "Draw Paint %d %x %x",handle,command.param1,rgba);\r
-               return handle;\r
-       } break;\r
-       case OVGimageUploadLine: {\r
-               vgImageSubData((VGImage)command.param1,command.data,0,VG_sARGB_8888,0,command.param2,command.param3,1);\r
-               return 0;\r
-       } break;\r
-\r
-       }\r
-}\r
-\r
-bool OsdOpenVG::processTasks()\r
-{\r
-       bool worked=false;\r
-       taskmutex.Lock();\r
-       vgmutex.Lock();\r
-       while (vgcommands.size()>0)\r
-       {\r
-               OpenVGCommand &comm=vgcommands.front();\r
-               OpenVGResponse resp;\r
-               resp.result=handleTask(comm);\r
-               resp.id=comm.id;\r
-               if (comm.id) {\r
-                       vgresponses.push_back(resp);\r
-               }\r
-               vgcommands.pop_front();\r
-               taskmutex.Unlock();\r
-               vgmutex.Unlock();\r
-               //threadCheckExit();\r
-               pthread_mutex_lock(&vgtaskCondMutex);\r
-               pthread_cond_signal(&vgtaskCond);\r
-               pthread_mutex_unlock(&vgtaskCondMutex);\r
-               taskmutex.Lock();\r
-               vgmutex.Lock();\r
-               worked=true;\r
-       }\r
-       taskmutex.Unlock();\r
-       vgmutex.Unlock();\r
-\r
-       return worked;\r
-}\r
-\r
-bool OsdOpenVG::haveOpenVGResponse(unsigned int id,unsigned int * resp)\r
-{\r
-       taskmutex.Lock();\r
-       if (vgresponses.size()>0)\r
-       {\r
-               deque<OpenVGResponse>::iterator itty=vgresponses.begin();\r
-               while (itty!=vgresponses.end())\r
-               {\r
-                       if ((*itty).id==id) {\r
-                               *resp=(*itty).result;\r
-                               taskmutex.Unlock();\r
-                               return true;\r
-                       }\r
-                       itty++;\r
-               }\r
-       }\r
-       taskmutex.Unlock();\r
-       return false;\r
-}\r
-\r
-\r
-unsigned int  OsdOpenVG::putOpenVGCommand(OpenVGCommand& comm,bool wait)\r
-{\r
-       taskmutex.Lock();\r
-       if (wait){\r
-               comm.id=wait_id;\r
-               wait_id++;\r
-       } else {\r
-               comm.id=0; // we are not waiting\r
-       }\r
-       vgcommands.push_back(comm);\r
-       taskmutex.Unlock();\r
-       threadSignal();\r
-       while (wait) {\r
-               unsigned int resp;\r
-               if (!haveOpenVGResponse(comm.id,&resp)) {\r
-                       struct timespec target_time;\r
-                       clock_gettime(CLOCK_REALTIME,&target_time);\r
-                       target_time.tv_nsec+=1000000LL*100;\r
-                       if (target_time.tv_nsec>999999999) {\r
-                                       target_time.tv_nsec-=1000000000L;\r
-                                       target_time.tv_sec+=1;\r
-                       }\r
-                       pthread_mutex_lock(&vgtaskCondMutex);\r
-                       pthread_cond_timedwait(&vgtaskCond, &vgtaskCondMutex,&target_time);\r
-                       pthread_mutex_unlock(&vgtaskCondMutex);\r
-               } else {\r
-                       return resp;\r
-               }\r
-       }\r
-       return 0;\r
-}\r
-\r
-void OsdOpenVG::imageUploadLine(ImageIndex index,unsigned int j,unsigned int width,void *data)\r
-{\r
-       vgImageSubData((VGImage)index,data,0,VG_sARGB_8888,0,j,width,1);\r
-\r
-       struct OpenVGCommand comm;\r
-       comm.task=OVGimageUploadLine;\r
-       comm.param1=index;\r
-       comm.param2=j;\r
-       comm.param3=width;\r
-       comm.data=data;\r
-       putOpenVGCommand(comm,true);\r
-}\r
-\r
-void OsdOpenVG::destroyImageRef(ImageIndex index)\r
-{\r
-       struct OpenVGCommand comm;\r
-       comm.task=OVGdestroyImageRef;\r
-       comm.param1=index;\r
-       putOpenVGCommand(comm,false);\r
-}\r
-\r
-ImageIndex OsdOpenVG::createJpeg(const char* fileName, int *width,int *height)\r
-{\r
-       Image* magicimage=NULL;\r
-       bool mem=false;\r
-       struct OpenVGCommand comm;\r
-       comm.task=OVGcreateImageFile;\r
-\r
-       try{\r
-               // Now figure out, if it is a special case\r
-               if (strcmp(fileName,"/vdr.jpg")==0) {\r
-                       magicimage=new Image(Blob(vdr_data,vdr_data_end-vdr_data));\r
-                       *height=100; // this is faked so that the system does use the old coordinate system\r
-                       *width=ceil(190.f*aspect_correction);\r
-                       Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm vdr.jpg");\r
-               } else if (strcmp(fileName,"/wallpaperPAL.jpg")==0) {\r
-                       magicimage=new Image(Blob(wallpaper_data,wallpaper_data_end-wallpaper_data));\r
-                       *width=720; // this is faked so that the system does use the old coordinate system\r
-                       *height=576;\r
-                       Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm wallpaperPAL.jpg");\r
-               } else {\r
-                       magicimage=new Image();\r
-                       magicimage->read(fileName);\r
-                       Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm file: %s",fileName);\r
-                       *width=ceil(magicimage->baseColumns()*aspect_correction); // this is faked so that the system does use the old coordinate system\r
-                       *height=magicimage->baseRows();\r
-               }\r
-\r
-       }catch( Exception &error_ )\r
-       {\r
-               Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick: %s",error_.what());\r
-\r
-               return 0;\r
-       }\r
-       comm.data=magicimage;\r
-       return putOpenVGCommand(comm,true);\r
-}\r
-\r
-ImageIndex OsdOpenVG::createMonoBitmap(void *base,int width,int height)\r
-{\r
-       struct OpenVGCommand comm;\r
-       comm.task=OVGcreateMonoBitmap;\r
-       comm.param1=width;\r
-       comm.param2=height;\r
-       comm.data=base;\r
-       return putOpenVGCommand(comm,true);\r
-}\r
-\r
-ImageIndex OsdOpenVG::createImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)\r
-{\r
-    struct OpenVGCommand comm;\r
-    comm.task=OVGcreateImagePalette;\r
-    comm.param1=width;\r
-    comm.param2=height;\r
-    comm.data=image_data;\r
-    comm.data2=palette_data;\r
-    return putOpenVGCommand(comm,true);\r
-}\r
-\r
-void OsdOpenVG::destroyStyleRef(unsigned int index)\r
-{\r
-       struct OpenVGCommand comm;\r
-       comm.task=OVGdestroyPaint;\r
-       comm.param1=index;\r
-       putOpenVGCommand(comm,false);\r
-}\r
-\r
-unsigned int OsdOpenVG::createStyleRef(const DrawStyle &c)\r
-{\r
-       unsigned int col=c.rgba();\r
-       struct OpenVGCommand comm;\r
-       comm.task=OVGcreateColorRef;\r
-       comm.param1=col<<8 | (col &0xff000000)>>24;\r
-       comm.data=&c;\r
-       return putOpenVGCommand(comm,true);\r
-}\r
-\r
-unsigned int OsdOpenVG::createColorRef(const Colour &c)\r
-{\r
-       unsigned int col=c.rgba();\r
-       struct OpenVGCommand comm;\r
-       comm.task=OVGcreateColorRef;\r
-       comm.param1=col<<8 | (col &0xff000000)>>24;\r
-       comm.data=&c;\r
-       return putOpenVGCommand(comm,true);\r
-}\r
-\r
-\r
+/*
+    Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+
+#include "osdopenvg.h"
+#include "mtd.h"
+#include "videoomx.h"
+#include "surface.h"
+#include <Magick++.h>
+
+#include "message.h"
+#include "command.h"
+#include "teletxt/txtfont.h"
+
+#include <sys/syscall.h>
+#include <vector>
+#include <math.h>
+
+using namespace Magick;
+
+extern uint8_t font_data[]     asm("_binary_fonts_sourcesans_ttf_start");
+extern uint8_t font_data_end[] asm("_binary_fonts_sourcesans_ttf_end");
+extern uint8_t vdr_data[]     asm("_binary_other_vdrhires_jpg_start");
+extern uint8_t vdr_data_end[] asm("_binary_other_vdrhires_jpg_end");
+extern uint8_t wallpaper_data[]     asm("_binary_other_wallpaper720p_jpg_start");
+extern uint8_t wallpaper_data_end[] asm("_binary_other_wallpaper720p_jpg_end");
+
+
+#define  BACKBUFFER_WIDTH 1280
+#define  BACKBUFFER_HEIGHT 720
+
+
+OsdOpenVG::OsdOpenVG()
+{
+  vgmutex.Lock();
+  taskmutex.Lock();
+  lastrendertime=getTimeMS();
+  display_height=0;
+  display_width=0;
+  mode=0;
+  aspect_correction=1.;
+
+  freetype_inited=false;
+  wait_id=1;
+
+}
+
+OsdOpenVG::~OsdOpenVG()
+{
+
+  if (initted)
+  {
+               shutdown();
+  }
+
+  if (freetype_inited) FT_Done_Face(ft_face);
+
+  vgmutex.Unlock();
+  taskmutex.Unlock();
+}
+
+
+
+int OsdOpenVG::init(void* device)
+{
+  if (initted) return 0;
+  Video* video = Video::getInstance();
+   //window=*((HWND*)device);
+
+   // May be this device specific part should go to a device specific child class
+
+   //init broadcom chipset (Move to video?)
+
+
+   //First get connection to egl
+   egl_display=eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+   if (egl_display==EGL_NO_DISPLAY) {
+          Log::getInstance()->log("OSD", Log::WARN, "Could not get egl display! %x",eglGetError());
+          vgmutex.Unlock();
+          return 0;
+   }
+
+
+
+   if (eglInitialize(egl_display, NULL, NULL)==EGL_FALSE) {
+          Log::getInstance()->log("OSD", Log::WARN, "Initialising display failed! %x",eglGetError());
+          vgmutex.Unlock();
+          return 0;
+   }
+
+
+   const char *query_str=eglQueryString(egl_display,EGL_CLIENT_APIS);
+   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());
+   query_str=eglQueryString(egl_display,EGL_EXTENSIONS);
+   if (query_str)    Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());
+
+   if (eglBindAPI(EGL_OPENVG_API)==EGL_FALSE) {
+          Log::getInstance()->log("OSD", Log::WARN, "Binding openvg api failed! %x",eglGetError());
+          vgmutex.Unlock();
+          return 0;
+   }
+
+   const EGLint attributs[]={
+                EGL_RED_SIZE,8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,
+         EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,
+         EGL_CONFORMANT, EGL_OPENVG_BIT,
+         EGL_NONE
+   }; // Here, we might have to select the resolution!
+
+
+   EGLint number;
+
+   if (eglChooseConfig(egl_display, attributs, &egl_ourconfig, 1, &number)==EGL_FALSE) {
+          Log::getInstance()->log("OSD", Log::WARN, "Choosing egl config failed! %x",eglGetError());
+          vgmutex.Unlock();
+          return 0;
+   }
+
+
+
+   egl_context=eglCreateContext(egl_display,egl_ourconfig,NULL,NULL);
+   if (egl_context==EGL_NO_CONTEXT) {
+          Log::getInstance()->log("OSD", Log::WARN, "Creating egl context failed! %x",eglGetError());
+          vgmutex.Unlock();
+          return 0;
+   }
+
+   // warning broadcom specific, get display size!
+   display_width=display_height=0;
+   if (graphics_get_display_size(0, &display_width, &display_height)<0) {
+          Log::getInstance()->log("OSD", Log::WARN, "Getting display size failed! (BCM API) ");
+          vgmutex.Unlock();
+          return 0;
+   }
+   Log::getInstance()->log("OSD", Log::NOTICE, "Displaysize is %d x %d ",display_width, display_height);
+   VC_RECT_T dst_rect ={0,0,display_width,display_height};
+   VC_RECT_T src_rect={0,0,BACKBUFFER_WIDTH <<16,BACKBUFFER_HEIGHT<<16};
+  // VC_RECT_T src_rect_bg={0,0,1<<16,1<<16};
+ //  VC_RECT_T src_rect_im={0,0,1,1};
+
+  /* uint32_t back_image_ptr;
+   bcm_backres=vc_dispmanx_resource_create(VC_IMAGE_RGB888,1,1,&back_image_ptr);
+   unsigned int color=0x00FF0000;
+   vc_dispmanx_resource_write_data(bcm_backres,VC_IMAGE_RGB888,4,&color,&src_rect_im);*/
+
+   DISPMANX_UPDATE_HANDLE_T  bcm_update;
+   bcm_display=vc_dispmanx_display_open(0);
+   bcm_update=vc_dispmanx_update_start(0);
+   bcm_element=vc_dispmanx_element_add(bcm_update,bcm_display,
+         2,&dst_rect, 0,
+         &src_rect,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);
+
+
+ /*  bcm_background=vc_dispmanx_element_add(bcm_update,bcm_display,
+            0,&dst_rect,bcm_backres ,
+            &src_rect_bg,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);*/
+
+   vc_dispmanx_update_submit_sync(bcm_update);
+
+
+
+   static EGL_DISPMANX_WINDOW_T nativewindow;
+   nativewindow.element=bcm_element;
+   nativewindow.height=BACKBUFFER_HEIGHT;
+   nativewindow.width=BACKBUFFER_WIDTH;
+
+   egl_surface = eglCreateWindowSurface(egl_display,egl_ourconfig, &nativewindow,NULL );
+   if (egl_surface==EGL_NO_SURFACE) {
+          Log::getInstance()->log("OSD", Log::WARN, "Creating egl window surface failed!");
+          vgmutex.Unlock();
+          return 0;
+   }
+   Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current in1%d",syscall(SYS_gettid));
+   if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
+          Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed");
+          vgmutex.Unlock();
+                  return 0;
+   }
+   // Test stuff
+
+   query_str=(const char*)vgGetString(VG_VERSION) ;
+   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
+
+   query_str=(const char*)vgGetString(VG_VENDOR) ;
+   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
+
+   query_str=(const char*)vgGetString(VG_RENDERER) ;
+   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
+
+   query_str=(const char*)vgGetString(VG_EXTENSIONS) ;
+   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
+   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
+
+  aspect_correction= ((float)BACKBUFFER_HEIGHT)/576.f/(((float)BACKBUFFER_WIDTH)/720.f);
+  initPaths();
+  if (!loadFont()) {
+         return 0;
+  }
+  vgttfont=vgCreateFont(0);
+  vgttpaint=vgCreatePaint();
+  vgSetParameteri( vgttpaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+  vgSetColor(vgttpaint,0xffffffff);
+
+  eglSwapInterval(egl_display, 1 );
+
+  Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out 1%d",syscall(SYS_gettid));
+  eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+  //Now we will create the Screen
+  initted = 1; // must set this here or create surface won't work
+
+
+  /*if (((VideoOMX*)Video::getInstance())->initUsingOSDObjects()!=1) { //call Video for init  stuff
+         return 0;
+  }*/
+  InitializeMagick("");
+
+  pthread_cond_init(&vgtaskCond, NULL);
+  pthread_mutex_init(&vgtaskCondMutex, NULL);
+
+  threadStart();
+  taskmutex.Unlock();
+  vgmutex.Unlock();
+
+
+  return 1;
+}
+
+
+void OsdOpenVG::initPaths()
+{
+
+
+       VGPath current;
+       current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
+                       VG_PATH_DATATYPE_F,1.f,0.f,
+                       0,0,VG_PATH_CAPABILITY_ALL);
+
+       vguLine(current,0.f,0.f,1.f,0.f);
+       // HorzLine
+       std_paths[HorzLine]=current;
+
+       current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
+                               VG_PATH_DATATYPE_F,1.f,0.f,
+                               0,0,VG_PATH_CAPABILITY_ALL);
+       vguLine(current,0.f,0.f,0.f,1.f);
+       // VertLine
+       std_paths[VertLine]=current;
+
+       current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
+                               VG_PATH_DATATYPE_F,1.f,0.f,
+                               0,0,VG_PATH_CAPABILITY_ALL);
+       //vguRect(current,0.f,0.f,1.f,1.f);
+       vguRect(current,0.f,0.f,1.f,1.f);
+       // Rectabgle
+       std_paths[Rectangle]=current;
+
+       current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
+                               VG_PATH_DATATYPE_F,1.f,0.f,
+                               0,0,0);
+       vguEllipse(current,0.f,0.f,1.f,1.f);
+       // Point
+       std_paths[Point]=current;
+
+}
+
+void OsdOpenVG::destroyPaths()
+{
+       vgDestroyPath(std_paths[HorzLine]);
+       vgDestroyPath(std_paths[VertLine]);
+       vgDestroyPath(std_paths[Rectangle]);
+       vgDestroyPath(std_paths[Point]);
+
+}
+
+int OsdOpenVG::stopUpdate()
+{
+       threadStop();
+       processTasks();
+       return 1;
+}
+
+
+int OsdOpenVG::shutdown()
+{
+  if (!initted) return 0;
+
+  initted = 0;
+  Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark1");
+  threadStop();
+  Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark2");
+  processTasks();
+  Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark3");
+
+  taskmutex.Lock();
+  vgmutex.Lock();
+  //(((VideoOMX*)Video::getInstance())->shutdownUsingOSDObjects());
+
+
+
+  vgDestroyFont(vgfont);
+  vgDestroyFont(vgttfont);
+  vgDestroyPaint(vgttpaint);
+  destroyPaths();
+  vgClear(0,0,BACKBUFFER_WIDTH,BACKBUFFER_HEIGHT);
+  eglSwapBuffers(egl_display, egl_surface);
+  Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out final");
+  eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+  eglDestroySurface(egl_display,egl_surface);
+  eglDestroyContext(egl_display,egl_context);
+  eglTerminate(egl_display );
+
+  DISPMANX_UPDATE_HANDLE_T  bcm_update;
+  bcm_update=vc_dispmanx_update_start(0);
+
+  vc_dispmanx_element_remove(bcm_update,bcm_element);
+//  vc_dispmanx_element_remove(bcm_update,bcm_background);
+  vc_dispmanx_update_submit_sync(bcm_update);
+//  vc_dispmanx_resource_delete(bcm_backres);
+  vc_dispmanx_display_close(bcm_display);
+
+
+
+  return 1;
+}
+
+
+
+
+void OsdOpenVG::threadMethod()
+{
+       // We have to claim the egl context for this thread
+
+       if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
+               Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in thread %x",eglGetError());
+               return;
+       }
+       int ts=0;
+       while (true)
+       {
+               ts=1;
+               unsigned int waittime=1;
+
+               if (initted) {
+
+                       long long time1 = getTimeMS();
+                       if ((time1 - lastrendertime) > 200) {//5 fps for OSD updates are enough, avoids tearing
+                               InternalRendering();
+                               lastrendertime = getTimeMS();
+
+                       }
+                       if (processTasks()) ts=0;
+               }
+               threadCheckExit();
+               if (ts!=0) {
+                       struct timespec target_time;
+                       clock_gettime(CLOCK_REALTIME,&target_time);
+                       target_time.tv_nsec+=1000000LL*ts;
+                       if (target_time.tv_nsec>999999999) {
+                               target_time.tv_nsec-=1000000000L;
+                               target_time.tv_sec+=1;
+                       }
+                       threadLock();
+                       threadWaitForSignalTimed(&target_time);
+                       threadUnlock();
+               }
+               //Sleep(1);
+       }
+       //eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+}
+
+
+void OsdOpenVG::threadPostStopCleanup()
+{
+       //Doing nothing
+       //goo;
+}
+
+
+
+
+
+
+void OsdOpenVG::InternalRendering(){
+       vgmutex.Lock();
+    float colclear[]={1.f,1.0f,1.f,1.f};
+    vgSetfv(VG_CLEAR_COLOR,4,colclear);
+       vgClear(0,0,BACKBUFFER_WIDTH,BACKBUFFER_HEIGHT);
+       vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
+
+
+       drawSurfaces(); //iterate through and draws all commands
+
+       //Show it to the user!
+       eglSwapBuffers(egl_display, egl_surface);
+       vgmutex.Unlock();
+
+}
+
+/*font stuff*/
+
+float OsdOpenVG::getFontHeight()
+{
+       return font_height; //dummy
+}
+float OsdOpenVG::getCharWidth(wchar_t c)
+{
+       unsigned int glyph_index=FT_Get_Char_Index(ft_face,c);
+       return font_exp_x[glyph_index];
+}
+
+unsigned int OsdOpenVG::loadTTchar(cTeletextChar c)
+{
+       unsigned int glyph_index=c.getGlyphIndex();
+       if (tt_font_chars.find(glyph_index)!=tt_font_chars.end())
+       {
+               return glyph_index;
+       }
+
+       unsigned int buffer[10];
+       const VGfloat glyphOrigin[] = { 0.f, 0.f };
+       const VGfloat escapement[] = { 12.f, 0.f };
+       unsigned int * charmap = GetFontChar(c, buffer);
+       if (!charmap) { //invalid char
+               return 0;
+       }
+       for (int i=0;i<10;i++) {
+               buffer[i]=charmap[i]>>4;
+       }
+
+       VGImage handle = vgCreateImage(
+                       VG_A_8,
+                       12,
+                       10,
+                       VG_IMAGE_QUALITY_NONANTIALIASED | VG_IMAGE_QUALITY_FASTER
+                                       | VG_IMAGE_QUALITY_BETTER);
+       vgImageSubData(handle, buffer, 4, VG_A_1, 0, 0, 12, 10);
+       vgSetGlyphToImage(
+                       vgttfont,
+                       glyph_index,
+                       handle, glyphOrigin, escapement);
+       vgDestroyImage(handle);
+       tt_font_chars[glyph_index]=1;
+
+       return glyph_index;
+}
+
+int  OsdOpenVG::loadFont()
+{
+       int error;
+       float font_size=16.f;
+       if (!freetype_inited) {
+               error=FT_Init_FreeType(&ft_library);
+               if (error)
+               {
+                       Log::getInstance()->log("OSD", Log::WARN, "Could not load freetype %x",error);
+                       return 0;
+               }
+
+               error=FT_New_Memory_Face(ft_library,font_data,font_data_end-font_data,0,&ft_face );
+               if (error) {
+                       Log::getInstance()->log("OSD", Log::WARN, "Could not load font face %x",error);
+                       return 0;
+               }
+               error=FT_Set_Char_Size(ft_face,0,font_size*64,0,0 /*dpi*/);
+               if (error) {
+                       FT_Done_Face(ft_face);
+                       Log::getInstance()->log("OSD", Log::WARN, "Could not set  face size %x",error);
+                       return 0;
+               }
+               freetype_inited=true;
+       }
+       vgfont=vgCreateFont(0);
+       FT_ULong cur_char;
+       FT_UInt glyph;
+       font_height=ft_face->size->metrics.height/64.f;
+       cur_char = FT_Get_First_Char(ft_face,&glyph);
+       vector<VGubyte> segments;
+       vector<VGfloat> coord;
+       segments.reserve(256);
+       coord.reserve(1024);
+       //Log::getInstance()->log("OSD", Log::DEBUG, "Create Glyph test %d %x %x %d",cur_char,font_data_end,font_data,glyph);
+       while (glyph !=0)
+       {
+               error=FT_Load_Glyph(ft_face,glyph,FT_LOAD_DEFAULT);
+               if (error){
+                       FT_Done_Face(ft_face);
+                       Log::getInstance()->log("OSD", Log::WARN, "Could not load glyph %x",error);
+                       return 0;
+               }
+               VGPath path;
+               FT_Outline ot=ft_face->glyph->outline;
+               segments.clear();
+               coord.clear();
+
+               if (ot.n_contours ==0) {
+                       path=VG_INVALID_HANDLE;
+               } else {
+                       path=vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+                                       1.0f,0.f,0,0,VG_PATH_CAPABILITY_ALL);
+
+                       /* convert glyph */
+                       FT_Vector *pt=ot.points;
+                       const char *tags=ot.tags;
+                       const short* cont=ot.contours;
+                       short n_cont=ot.n_contours;
+                       short n_point=ot.n_points;
+                       short last_cont=0;
+                       for (short point=0;n_cont!=0;cont++,n_cont--) {
+                               short next_cont=*cont+1;
+                               bool first=true;
+                               char last_tag=0;
+                               short first_point=point;
+                               //Log::getInstance()->log("OSD", Log::DEBUG, "runs %d",*cont);
+                               for (;point<next_cont;point++) {
+                                       char tag=tags[point];
+                                       FT_Vector fpoint=pt[point];
+                               //      Log::getInstance()->log("OSD", Log::DEBUG, "tag %d point %d %d: %d %d",tag,fpoint.x,fpoint.y,point,n_point);
+                                       if (first) {
+                                               segments.push_back(VG_MOVE_TO);
+                                               first=false;
+                                       } else if (tag &0x1) { //on curve
+                                               if (last_tag &0x1) {
+                                                       segments.push_back(VG_LINE_TO);
+                                               } else if (last_tag &0x2){
+                                                       segments.push_back(VG_CUBIC_TO);
+                                               } else {
+                                                       segments.push_back(VG_QUAD_TO);
+                                               }
+
+                                       } else {
+                                               if (!(tag &0x2)){
+                                                       if (!(last_tag &0x1)) {
+                                                               segments.push_back(VG_QUAD_TO);
+                                                               int coord_size=coord.size();
+                                                               VGfloat x=(coord[coord_size-2]+ ((float)fpoint.x)/64.f)*0.5f*aspect_correction;
+                                                               VGfloat y=(coord[coord_size-1]+(font_size- ((float)fpoint.y)/64.f))*0.5f;
+                                                               coord.push_back(x);
+                                                               coord.push_back(y);
+                                                       }
+                                               }
+
+
+                                       }
+                                       last_tag=tag;
+                                       coord.push_back(((float)fpoint.x)*aspect_correction/64.);
+                                       coord.push_back(font_size-((float)fpoint.y)/64.);
+                                       //Log::getInstance()->log("OSD", Log::DEBUG, "Create APD Glyph coord %d %d %g %g",fpoint.x,fpoint.y,coord[coord.size()-2],coord[coord.size()-1]);
+                               }
+                               if (!(last_tag &0x1)) {
+                                       if (last_tag &0x2) {
+                                               segments.push_back(VG_CUBIC_TO);
+                                       } else {
+                                               segments.push_back(VG_QUAD_TO);
+                                       }
+                                       coord.push_back(((float)pt[first_point].x)*aspect_correction/64.);
+                                       coord.push_back(font_size-((float)pt[first_point].y)/64.);
+                               }
+                               //segments.push_back(VG_CLOSE_PATH);
+
+
+                       }
+                       vgAppendPathData(path,segments.size(),&segments[0],&coord[0]);
+                       int n=0;
+               /*      for (int m=0;m<segments.size();m++) {
+                               switch (segments[m])
+                               {
+                               case VG_MOVE_TO:
+                                       Log::getInstance()->log("OSD", Log::DEBUG, "Move To %g %g",coord[n],coord[n+1]);n+=2; break;
+                               case VG_LINE_TO:
+                                       Log::getInstance()->log("OSD", Log::DEBUG, "Line To %g %g",coord[n],coord[n+1]);n+=2; break;
+                               case VG_CUBIC_TO:
+                                       Log::getInstance()->log("OSD", Log::DEBUG, "Cubic To %g %g %g %g %g %g",coord[n],coord[n+1],coord[n+2],coord[n+3],coord[n+4],coord[n+5]);n+=6; break;
+                               case VG_QUAD_TO:
+                                       Log::getInstance()->log("OSD", Log::DEBUG, "Quad To %g %g %g %g",coord[n],coord[n+1],coord[n+2],coord[n+3]);n+=4; break;
+                               case VG_CLOSE_PATH:
+                                       Log::getInstance()->log("OSD", Log::DEBUG, "Close Path"); break;
+                               }
+
+                       }*/
+                       //vguRect(path,0.f,0.f,1.f,1.f);
+                       //Log::getInstance()->log("OSD", Log::DEBUG, "Create APD Glyph %d %x",segments.size(),vgGetError());
+               }
+               VGfloat ori[]={0.f,0.f};
+               VGfloat esp[]={ft_face->glyph->advance.x/64.f*aspect_correction,ft_face->glyph->advance.y/64.f};
+               font_exp_x[glyph]=ft_face->glyph->advance.x/64.f*aspect_correction; //recalculate
+
+               vgSetGlyphToPath(vgfont,glyph,path,VG_FALSE,ori,esp);
+               //Log::getInstance()->log("OSD", Log::DEBUG, "Create Glyph %d %d %x",path,glyph,vgGetError());
+               if (path!=VG_INVALID_HANDLE) {
+                       vgDestroyPath(path);
+               }
+               cur_char = FT_Get_Next_Char(ft_face,cur_char,&glyph);
+       }
+       return 1;
+}
+
+
+void OsdOpenVG::drawSetTrans(SurfaceCommands & sc)
+{
+       vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+       vgLoadIdentity();
+       vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);
+       vgTranslate(0.f+sc.x,-576.f+sc.y);
+
+       vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
+       vgLoadIdentity();
+    vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);
+       vgTranslate(0.f+sc.x,-576.f+sc.y);
+
+       vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+       vgLoadIdentity();
+       vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);
+       vgTranslate(0.f+sc.x,-576.f+sc.y);
+
+
+
+       //vgTranslate(0.f+sc.x,576.f-sc.y);
+       //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Translate %g %g",sc.x,sc.y);
+
+}
+void OsdOpenVG::executeDrawCommand(SVGCommand & command)
+{
+
+       VGfloat  save_matrix[9];
+       switch (command.instr) {
+       case DrawPath: {
+        vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+       //      VGuint rgba;
+       //      rgba = vgGetColor((VGPaint) command.reference);
+               //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Path %d %x %g %g %g %g",command.reference,command.target.path_index,command.x,command.y,command.w,command.h);
+               //vgSeti(VG_FILL_RULE,);
+
+               vgGetMatrix(save_matrix);
+               vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);
+               vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);
+               vgTranslate(command.x,command.y);
+               vgScale(command.w,command.h);
+               vgDrawPath(std_paths[command.target.path_index],VG_FILL_PATH);
+               vgLoadMatrix(save_matrix);
+       } break;
+       case DrawImage: {
+           vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+               vgGetMatrix(save_matrix);
+               vgTranslate(command.x,command.y);
+               //vgScale(command.w,command.h);
+               if (command.reference) { //special behaviout for bw images they act as a mask on the current paint
+                       vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);
+                       vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);
+                       vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_STENCIL);
+                       vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
+                       vgScale(aspect_correction,1.f);
+               } else {
+                       VGfloat imagewidth=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_WIDTH);
+                       VGfloat imageheight=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_HEIGHT);
+                       //vgScale(720.f/((float)BACKBUFFER_WIDTH), 576.f/((float)BACKBUFFER_HEIGHT));
+                       float scalex=command.w/imagewidth;
+                       float scaley=command.h/imageheight;
+                       //vgScale(command.w/imagewidth,command.h/imageheight);
+                       vgScale(scalex,scaley);
+                       vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);
+                       //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Image Scale  %g %g %g %g %g %g",command.w,imagewidth,command.h,imageheight,scalex,scaley);
+               }
+
+
+               //vgLoadIdentity();
+               //vgTranslate(200.f,500.f);
+               //vgScale(100.f,100.f);
+
+               vgDrawImage((VGImage) command.target.image);
+               //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Image %d %x %g %g %g %g %x",command.reference,command.target.image,command.x,command.y,command.w,command.h,
+               //              vgGetError());
+               if (command.reference) {
+                       vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);
+                       vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
+               }
+               vgLoadMatrix(save_matrix);
+       } break;
+       case DrawGlyph: {
+               vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
+               vgGetMatrix(save_matrix);
+               vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);
+               vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);
+               vgTranslate(command.x,command.y);
+               VGfloat gori[]={0.,0.};
+               vgSetfv(VG_GLYPH_ORIGIN,2,gori);
+
+               unsigned int glyph_index=FT_Get_Char_Index(ft_face,command.target.textchar);
+               vgDrawGlyph(vgfont,glyph_index,VG_FILL_PATH,VG_FALSE);
+               //vgDrawPath(std_paths[Rectangle],VG_FILL_PATH);
+       /*      Log::getInstance()->log("OSD", Log::DEBUG, "Draw Glyph %d %c %d %g %g %x",command.reference,command.target.textchar,glyph_index,command.x,command.y,
+                                               vgGetError());*/
+               vgLoadMatrix(save_matrix);
+               vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+       } break;
+       case DrawTTchar:{
+               cTeletextChar tchar;
+               tchar.setInternal(command.target.ttchar);
+               vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
+               vgGetMatrix(save_matrix);
+               enumTeletextColor ttforegcolour=tchar.GetFGColor();
+               enumTeletextColor ttbackgcolour=tchar.GetBGColor();
+           if (tchar.GetBoxedOut()) {
+               ttforegcolour=ttcTransparent;
+               ttbackgcolour=ttcTransparent;
+           }
+           vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_STENCIL);
+           vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
+
+
+               vgTranslate(command.x+command.w*11.85f*1.4f,command.y+command.h*19.75f);
+               VGfloat gori[]={0.,0.};
+               vgSetfv(VG_GLYPH_ORIGIN,2,gori);
+
+               vgScale(-1.4f,2.f);
+               unsigned int color=Surface::enumTeletextColorToCoulour(ttbackgcolour).rgba();
+               color=color<<8 | (color &0xff000000)>>24;
+               vgSetColor(vgttpaint,color);
+               vgSetPaint((VGPaint) vgttpaint,VG_FILL_PATH);
+               vgSetPaint((VGPaint) vgttpaint,VG_STROKE_PATH);
+               cTeletextChar filled;
+               filled.setInternal(0x187f);
+               unsigned int glyph_index=loadTTchar(filled);
+               vgDrawGlyph(vgttfont,glyph_index,VG_FILL_PATH,VG_FALSE);
+
+               color=Surface::enumTeletextColorToCoulour(ttforegcolour).rgba();
+               color=color<<8 | (color &0xff000000)>>24;
+               vgSetColor(vgttpaint,color);
+               vgSetPaint((VGPaint) vgttpaint,VG_FILL_PATH);
+               vgSetPaint((VGPaint) vgttpaint,VG_STROKE_PATH);
+               glyph_index=loadTTchar(tchar);
+               vgDrawGlyph(vgttfont,glyph_index,VG_FILL_PATH,VG_FALSE);
+
+               /*      Log::getInstance()->log("OSD", Log::DEBUG, "Draw TTchar %x %x %x %x",glyph_index,ttforegcolour,Surface::enumTeletextColorToCoulour(ttforegcolour).rgba(),
+                                       vgGetColor(vgttpaint));*/
+
+
+               vgLoadMatrix(save_matrix);
+               vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+               vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);
+               vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
+
+       }break;
+       }
+}
+
+unsigned int OsdOpenVG::handleTask(OpenVGCommand& command)
+{
+       switch (command.task){
+       case OVGdestroyImageRef: {
+               vgDestroyImage((VGImage)command.param1);
+               return 0;
+       } break;
+       case OVGdestroyPaint: {
+               Log::getInstance()->log("OSD", Log::DEBUG, "Draw Paint Destroy %d ",command.param1);
+               vgDestroyPaint((VGPaint)command.param1);
+               return 0;
+       } break;
+       case OVGcreateImagePalette: {
+               VGImage input=vgCreateImage(VG_A_8,command.param1, command.param2,
+                               VG_IMAGE_QUALITY_NONANTIALIASED|
+                               VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
+               vgImageSubData(input,command.data,command.param1,
+                                                       VG_A_8,0,0,command.param1, command.param2); // upload palettized image data
+               VGImage handle=vgCreateImage(VG_sRGBA_8888,command.param1, command.param2,
+                                               VG_IMAGE_QUALITY_NONANTIALIASED|
+                                               VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
+               VGuint *palette=(VGuint*)malloc(256*sizeof(VGuint));
+               VGuint *in_palette=(VGuint*)command.data2;
+               for (int i=0;i<256;i++) {
+                       VGuint color=in_palette[i];
+                       palette[i]=color<<8 | (color &0xff000000)>>24;
+               }
+
+               vgLookupSingle(handle,input,palette,VG_ALPHA,VG_FALSE,VG_FALSE);
+               free(palette);
+               vgDestroyImage(input);
+
+               return handle;
+       } break;
+       case OVGcreateMonoBitmap: {
+               VGImage handle=vgCreateImage(VG_A_1,command.param1, command.param2,
+                                       VG_IMAGE_QUALITY_NONANTIALIASED|
+                                       VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
+               //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
+               unsigned int buffer_len=(command.param1*command.param2)>>3;
+               unsigned char * buffer=(unsigned char*)malloc(buffer_len);
+               unsigned char * r_buffer1=buffer;
+               const unsigned char * r_buffer2=(const unsigned char *)command.data;
+               unsigned char *buffer_end=buffer+buffer_len;
+               while (r_buffer1!=buffer_end) {
+                       unsigned char byte=*r_buffer2;
+                       *r_buffer1=((byte * 0x0802LU & 0x22110LU) | (byte * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
+                       r_buffer1++;r_buffer2++;
+               }
+
+
+               vgImageSubData(handle,buffer,command.param1>>3,
+                                       VG_A_1,0,0,command.param1, command.param2);
+               free(buffer);
+       //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono2  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
+               return handle;
+       } break;
+       case OVGcreateImageFile: {
+               VGImage handle;
+               try{
+                       Image *imagefile=(Image*)command.data;
+                       Blob imageblob;
+                       imagefile->write(&imageblob,"RGBA");
+
+
+                       handle=vgCreateImage(VG_sXBGR_8888,imagefile->columns(),imagefile->rows(),
+                                       VG_IMAGE_QUALITY_NONANTIALIASED|
+                                       VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
+               //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details  %d %d %x mark1",imagefile->columns(),imagefile->rows(),*(unsigned int*)imageblob.data());
+                       vgImageSubData(handle,imageblob.data(),imagefile->columns()*4,
+                                       VG_sXBGR_8888,0,0,imagefile->columns(),imagefile->rows());
+               //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details  %d %d %x mark2",imagefile->columns(),imagefile->rows(),*(unsigned int*)imageblob.data());
+                       delete imagefile;
+               }catch( Exception &error_ )
+               {
+                       Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick hT: %s",error_.what());
+
+                       return 0;
+               }
+
+               //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create file  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
+               return handle;
+       } break;
+       case OVGcreateColorRef :{
+               VGPaint handle;
+               handle=vgCreatePaint();
+               vgSetParameteri(handle, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+               vgSetColor(handle,command.param1);
+               VGuint rgba;
+               rgba = vgGetColor((VGPaint)handle);
+               Log::getInstance()->log("OSD", Log::DEBUG, "Draw Paint %d %x %x",handle,command.param1,rgba);
+               return handle;
+       } break;
+       case OVGimageUploadLine: {
+               vgImageSubData((VGImage)command.param1,command.data,0,VG_sARGB_8888,0,command.param2,command.param3,1);
+               return 0;
+       } break;
+
+       }
+}
+
+bool OsdOpenVG::processTasks()
+{
+       bool worked=false;
+       taskmutex.Lock();
+       vgmutex.Lock();
+       while (vgcommands.size()>0)
+       {
+               OpenVGCommand &comm=vgcommands.front();
+               OpenVGResponse resp;
+               resp.result=handleTask(comm);
+               resp.id=comm.id;
+               if (comm.id) {
+                       vgresponses.push_back(resp);
+               }
+               vgcommands.pop_front();
+               taskmutex.Unlock();
+               vgmutex.Unlock();
+               //threadCheckExit();
+               pthread_mutex_lock(&vgtaskCondMutex);
+               pthread_cond_signal(&vgtaskCond);
+               pthread_mutex_unlock(&vgtaskCondMutex);
+               taskmutex.Lock();
+               vgmutex.Lock();
+               worked=true;
+       }
+       taskmutex.Unlock();
+       vgmutex.Unlock();
+
+       return worked;
+}
+
+bool OsdOpenVG::haveOpenVGResponse(unsigned int id,unsigned int * resp)
+{
+       taskmutex.Lock();
+       if (vgresponses.size()>0)
+       {
+               deque<OpenVGResponse>::iterator itty=vgresponses.begin();
+               while (itty!=vgresponses.end())
+               {
+                       if ((*itty).id==id) {
+                               *resp=(*itty).result;
+                               taskmutex.Unlock();
+                               return true;
+                       }
+                       itty++;
+               }
+       }
+       taskmutex.Unlock();
+       return false;
+}
+
+
+unsigned int  OsdOpenVG::putOpenVGCommand(OpenVGCommand& comm,bool wait)
+{
+       taskmutex.Lock();
+       if (wait){
+               comm.id=wait_id;
+               wait_id++;
+       } else {
+               comm.id=0; // we are not waiting
+       }
+       vgcommands.push_back(comm);
+       taskmutex.Unlock();
+       threadSignal();
+       while (wait) {
+               unsigned int resp;
+               if (!haveOpenVGResponse(comm.id,&resp)) {
+                       struct timespec target_time;
+                       clock_gettime(CLOCK_REALTIME,&target_time);
+                       target_time.tv_nsec+=1000000LL*100;
+                       if (target_time.tv_nsec>999999999) {
+                                       target_time.tv_nsec-=1000000000L;
+                                       target_time.tv_sec+=1;
+                       }
+                       pthread_mutex_lock(&vgtaskCondMutex);
+                       pthread_cond_timedwait(&vgtaskCond, &vgtaskCondMutex,&target_time);
+                       pthread_mutex_unlock(&vgtaskCondMutex);
+               } else {
+                       return resp;
+               }
+       }
+       return 0;
+}
+
+void OsdOpenVG::imageUploadLine(ImageIndex index,unsigned int j,unsigned int width,void *data)
+{
+       vgImageSubData((VGImage)index,data,0,VG_sARGB_8888,0,j,width,1);
+
+       struct OpenVGCommand comm;
+       comm.task=OVGimageUploadLine;
+       comm.param1=index;
+       comm.param2=j;
+       comm.param3=width;
+       comm.data=data;
+       putOpenVGCommand(comm,true);
+}
+
+void OsdOpenVG::destroyImageRef(ImageIndex index)
+{
+       struct OpenVGCommand comm;
+       comm.task=OVGdestroyImageRef;
+       comm.param1=index;
+       putOpenVGCommand(comm,false);
+}
+
+ImageIndex OsdOpenVG::createJpeg(const char* fileName, int *width,int *height)
+{
+       Image* magicimage=NULL;
+       bool mem=false;
+       struct OpenVGCommand comm;
+       comm.task=OVGcreateImageFile;
+
+       try{
+               // Now figure out, if it is a special case
+               if (strcmp(fileName,"/vdr.jpg")==0) {
+                       magicimage=new Image(Blob(vdr_data,vdr_data_end-vdr_data));
+                       *height=100; // this is faked so that the system does use the old coordinate system
+                       *width=ceil(190.f*aspect_correction);
+                       Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm vdr.jpg");
+               } else if (strcmp(fileName,"/wallpaperPAL.jpg")==0) {
+                       magicimage=new Image(Blob(wallpaper_data,wallpaper_data_end-wallpaper_data));
+                       *width=720; // this is faked so that the system does use the old coordinate system
+                       *height=576;
+                       Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm wallpaperPAL.jpg");
+               } else {
+                       magicimage=new Image();
+                       magicimage->read(fileName);
+                       Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm file: %s",fileName);
+                       *width=ceil(magicimage->baseColumns()*aspect_correction); // this is faked so that the system does use the old coordinate system
+                       *height=magicimage->baseRows();
+               }
+
+       }catch( Exception &error_ )
+       {
+               Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick: %s",error_.what());
+
+               return 0;
+       }
+       comm.data=magicimage;
+       return putOpenVGCommand(comm,true);
+}
+
+ImageIndex OsdOpenVG::createMonoBitmap(void *base,int width,int height)
+{
+       struct OpenVGCommand comm;
+       comm.task=OVGcreateMonoBitmap;
+       comm.param1=width;
+       comm.param2=height;
+       comm.data=base;
+       return putOpenVGCommand(comm,true);
+}
+
+ImageIndex OsdOpenVG::createImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
+{
+    struct OpenVGCommand comm;
+    comm.task=OVGcreateImagePalette;
+    comm.param1=width;
+    comm.param2=height;
+    comm.data=image_data;
+    comm.data2=palette_data;
+    return putOpenVGCommand(comm,true);
+}
+
+void OsdOpenVG::destroyStyleRef(unsigned int index)
+{
+       struct OpenVGCommand comm;
+       comm.task=OVGdestroyPaint;
+       comm.param1=index;
+       putOpenVGCommand(comm,false);
+}
+
+unsigned int OsdOpenVG::createStyleRef(const DrawStyle &c)
+{
+       unsigned int col=c.rgba();
+       struct OpenVGCommand comm;
+       comm.task=OVGcreateColorRef;
+       comm.param1=col<<8 | (col &0xff000000)>>24;
+       comm.data=&c;
+       return putOpenVGCommand(comm,true);
+}
+
+unsigned int OsdOpenVG::createColorRef(const Colour &c)
+{
+       unsigned int col=c.rgba();
+       struct OpenVGCommand comm;
+       comm.task=OVGcreateColorRef;
+       comm.param1=col<<8 | (col &0xff000000)>>24;
+       comm.data=&c;
+       return putOpenVGCommand(comm,true);
+}
+
+
index 6882c9ce6c7e1fb202943517a62cfb49da39964c..9a1e9ac3483d0491fd66842856e7341d9b6d2ec6 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon, 2006,2011-2012 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 OSDOPENVG_H\r
-#define OSDOPENVG_H\r
-\r
-#include <stdio.h>\r
-\r
-\r
-#include <EGL/egl.h>\r
-#include <EGL/eglext.h>\r
-#include <VG/openvg.h>\r
-#include <VG/vgu.h>\r
-\r
-\r
-\r
-#include "osdvector.h"\r
-#include "defines.h"\r
-#include "log.h"\r
-#include "threadp.h"\r
-#include "mutex.h"\r
-#include "videoomx.h"\r
-\r
-#include <deque>\r
-\r
-#include <ft2build.h>\r
-#include FT_FREETYPE_H\r
-\r
-enum OpenVGTask {\r
-       OVGdestroyImageRef,\r
-       OVGdestroyPaint,\r
-       OVGcreateImagePalette,\r
-       OVGcreateMonoBitmap,\r
-       OVGcreateColorRef,\r
-       OVGimageUploadLine,\r
-       OVGcreateImageFile\r
-};\r
-\r
-struct OpenVGCommand\r
-{\r
-       enum OpenVGTask task;\r
-       const void *data;\r
-       const void *data2;\r
-       unsigned int param1,param2,param3;\r
-       unsigned int id; //only set an id if you are waiting\r
-};\r
-\r
-struct OpenVGResponse{\r
-       unsigned int id;\r
-       unsigned int result;\r
-};\r
-\r
-\r
-class OsdOpenVG : public OsdVector, public Thread_TYPE\r
-{\r
-  public:\r
-    OsdOpenVG();\r
-    virtual ~OsdOpenVG();\r
-\r
-    int init(void* device);\r
-    int shutdown();\r
-    int stopUpdate();\r
-\r
-\r
-\r
-\r
-    float getFontHeight();\r
-    float getCharWidth(wchar_t c);\r
-    void imageUploadLine(ImageIndex index,unsigned int j,unsigned int width,void *data);\r
-\r
-\r
-protected:\r
-   /*osd vector implementation*/\r
-    void destroyImageRef(ImageIndex index);\r
-    ImageIndex createJpeg(const char* fileName, int *width,int *height);\r
-    ImageIndex createMonoBitmap(void *base,int width,int height);\r
-    ImageIndex createImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data);\r
-    void destroyStyleRef(unsigned int index);\r
-       unsigned int createStyleRef(const DrawStyle &c);\r
-       unsigned int createColorRef(const Colour &c);\r
-\r
-       void drawSetTrans(SurfaceCommands & sc);\r
-       void executeDrawCommand(SVGCommand & command);\r
-\r
-       void initPaths();\r
-       void destroyPaths();\r
-       VGPath std_paths[Point+1];\r
-       long long  lastrendertime;\r
-       void InternalRendering();\r
-\r
-\r
-\r
-       Mutex vgmutex;\r
-       Mutex taskmutex;\r
-    pthread_cond_t vgtaskCond;\r
-    pthread_mutex_t vgtaskCondMutex;\r
-    deque<OpenVGCommand> vgcommands;\r
-    deque<OpenVGResponse> vgresponses;\r
-    bool processTasks();\r
-    bool haveOpenVGResponse(unsigned int id,unsigned int * resp);\r
-    unsigned int  putOpenVGCommand(OpenVGCommand& comm,bool wait);\r
-    unsigned int handleTask(OpenVGCommand& command);\r
-    unsigned int wait_id;\r
-\r
-    FT_Library  ft_library;\r
-    FT_Face     ft_face;\r
-    VGFont vgfont;\r
-    VGFont vgttfont;\r
-    VGPaint vgttpaint;\r
-    int  loadFont();\r
-    map<unsigned int,float> font_exp_x;\r
-\r
-    unsigned int loadTTchar(cTeletextChar c);\r
-    map<unsigned int,int> tt_font_chars;\r
-\r
-\r
-\r
-       void threadMethod();\r
-    void threadPostStopCleanup();\r
-\r
-\r
-        /* BCM specific */\r
-\r
-    uint32_t display_height;\r
-       uint32_t display_width;\r
-       DISPMANX_DISPLAY_HANDLE_T bcm_display;\r
-       DISPMANX_ELEMENT_HANDLE_T bcm_element;\r
-//     DISPMANX_ELEMENT_HANDLE_T bcm_background;\r
-//     DISPMANX_RESOURCE_HANDLE_T bcm_backres;\r
-\r
-       uint32_t mode;\r
-\r
-\r
-       EGLDisplay egl_display;\r
-       EGLSurface egl_surface;\r
-       EGLContext egl_context;\r
-       EGLConfig egl_ourconfig;\r
-       float font_height;\r
-       float aspect_correction;\r
-       bool freetype_inited;\r
-\r
-\r
-};\r
-\r
-#endif\r
+/*
+    Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef OSDOPENVG_H
+#define OSDOPENVG_H
+
+#include <stdio.h>
+
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <VG/openvg.h>
+#include <VG/vgu.h>
+
+
+
+#include "osdvector.h"
+#include "defines.h"
+#include "log.h"
+#include "threadp.h"
+#include "mutex.h"
+#include "videoomx.h"
+
+#include <deque>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+enum OpenVGTask {
+       OVGdestroyImageRef,
+       OVGdestroyPaint,
+       OVGcreateImagePalette,
+       OVGcreateMonoBitmap,
+       OVGcreateColorRef,
+       OVGimageUploadLine,
+       OVGcreateImageFile
+};
+
+struct OpenVGCommand
+{
+       enum OpenVGTask task;
+       const void *data;
+       const void *data2;
+       unsigned int param1,param2,param3;
+       unsigned int id; //only set an id if you are waiting
+};
+
+struct OpenVGResponse{
+       unsigned int id;
+       unsigned int result;
+};
+
+
+class OsdOpenVG : public OsdVector, public Thread_TYPE
+{
+  public:
+    OsdOpenVG();
+    virtual ~OsdOpenVG();
+
+    int init(void* device);
+    int shutdown();
+    int stopUpdate();
+
+
+
+
+    float getFontHeight();
+    float getCharWidth(wchar_t c);
+    void imageUploadLine(ImageIndex index,unsigned int j,unsigned int width,void *data);
+
+
+protected:
+   /*osd vector implementation*/
+    void destroyImageRef(ImageIndex index);
+    ImageIndex createJpeg(const char* fileName, int *width,int *height);
+    ImageIndex createMonoBitmap(void *base,int width,int height);
+    ImageIndex createImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data);
+    void destroyStyleRef(unsigned int index);
+       unsigned int createStyleRef(const DrawStyle &c);
+       unsigned int createColorRef(const Colour &c);
+
+       void drawSetTrans(SurfaceCommands & sc);
+       void executeDrawCommand(SVGCommand & command);
+
+       void initPaths();
+       void destroyPaths();
+       VGPath std_paths[Point+1];
+       long long  lastrendertime;
+       void InternalRendering();
+
+
+
+       Mutex vgmutex;
+       Mutex taskmutex;
+    pthread_cond_t vgtaskCond;
+    pthread_mutex_t vgtaskCondMutex;
+    deque<OpenVGCommand> vgcommands;
+    deque<OpenVGResponse> vgresponses;
+    bool processTasks();
+    bool haveOpenVGResponse(unsigned int id,unsigned int * resp);
+    unsigned int  putOpenVGCommand(OpenVGCommand& comm,bool wait);
+    unsigned int handleTask(OpenVGCommand& command);
+    unsigned int wait_id;
+
+    FT_Library  ft_library;
+    FT_Face     ft_face;
+    VGFont vgfont;
+    VGFont vgttfont;
+    VGPaint vgttpaint;
+    int  loadFont();
+    map<unsigned int,float> font_exp_x;
+
+    unsigned int loadTTchar(cTeletextChar c);
+    map<unsigned int,int> tt_font_chars;
+
+
+
+       void threadMethod();
+    void threadPostStopCleanup();
+
+
+        /* BCM specific */
+
+    uint32_t display_height;
+       uint32_t display_width;
+       DISPMANX_DISPLAY_HANDLE_T bcm_display;
+       DISPMANX_ELEMENT_HANDLE_T bcm_element;
+//     DISPMANX_ELEMENT_HANDLE_T bcm_background;
+//     DISPMANX_RESOURCE_HANDLE_T bcm_backres;
+
+       uint32_t mode;
+
+
+       EGLDisplay egl_display;
+       EGLSurface egl_surface;
+       EGLContext egl_context;
+       EGLConfig egl_ourconfig;
+       float font_height;
+       float aspect_correction;
+       bool freetype_inited;
+
+
+};
+
+#endif
index fadd1615333fdafa960272d9a2a26c74b7668227..322ee4bc2f1eedd995b7b2fc16dea8030e5652e5 100644 (file)
-/*\r
-    Copyright 2012 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 "osdvector.h"\r
-#include "surfacevector.h"\r
-\r
-OsdVector::OsdVector()\r
-{\r
-       setlocale(LC_CTYPE,"C.UTF-8");\r
-}\r
-\r
-OsdVector::~OsdVector()\r
-{\r
-\r
-}\r
-\r
-\r
-int OsdVector::getFD()\r
-{\r
-       return 0;\r
-}\r
-\r
-void OsdVector::screenShot(const char* fileName)\r
-{\r
-       //Do nothing,\r
-}\r
-\r
-Surface * OsdVector::createNewSurface()\r
-{\r
-       return new SurfaceVector(this);\r
-}\r
-\r
-void OsdVector::BeginPainting()\r
-{\r
-       surfaces_mutex.Lock();\r
-}\r
-void OsdVector::EndPainting()\r
-{\r
-       surfaces_mutex.Unlock();\r
-}\r
-\r
-void OsdVector::Blank()\r
-{\r
-       // do nothing? remove this one?\r
-}\r
-\r
-int OsdVector::restore()\r
-{\r
-       // First clear the contents of all registered surfaces\r
-       surfaces_mutex.Lock();\r
-\r
-       //Now go through all surfaces and draw them\r
-       list<SurfaceCommands>::iterator curdraw=scommands.begin();\r
-       while (curdraw!=scommands.end()) {\r
-               (*curdraw).commands.clear();\r
-               curdraw++;\r
-       }\r
-       //also clear all handles, they are now invalid, no need to release them\r
-       images_ref.clear();;\r
-       monobitmaps.clear();\r
-       jpegs.clear();\r
-       styles.clear();\r
-       styles_ref.clear();\r
-\r
-       surfaces_mutex.Unlock();\r
-       return 1;\r
-}\r
-\r
-void OsdVector::drawSurfaces()\r
-{\r
-       surfaces_mutex.Lock();\r
-       list<SurfaceCommands*> todraw; //First figure out if a surfaces is below another surface\r
-       list<SurfaceCommands>::iterator itty1=scommands.begin();\r
-       while (itty1!=scommands.end()) {\r
-               list<SurfaceCommands>::iterator itty2=itty1;\r
-               itty2++;\r
-               bool hidden=false;\r
-               while (itty2!=scommands.end()) {\r
-                       SurfaceCommands & ref1=*itty1;\r
-                       SurfaceCommands & ref2=*itty2;\r
-                       if (ref1.x>=ref2.x && ref1.y>=ref2.y\r
-                                       && (ref1.x+ref1.w) <= (ref2.x+ref2.w)\r
-                                       && (ref1.y+ref1.h) <= (ref2.y+ref2.h) ) {\r
-                               hidden=true;\r
-                               break;\r
-                       }\r
-                       itty2++;\r
-               }\r
-               if (!hidden) { // we are not hidden, perfect\r
-                       todraw.push_back(&(*itty1));\r
-               }\r
-               itty1++;\r
-       }\r
-       //Now go through all surfaces and draw them\r
-       list<SurfaceCommands*>::iterator curdraw=todraw.begin();\r
-       while (curdraw!=todraw.end()) {\r
-               drawSetTrans(*(*curdraw));\r
-               list<SVGCommand>::iterator commands=(*(*curdraw)).commands.begin();\r
-               list<SVGCommand>::iterator end=(*(*curdraw)).commands.end();\r
-               while (commands!=end) {\r
-                       executeDrawCommand(*commands);\r
-                       commands++;\r
-               }\r
-               curdraw++;\r
-       }\r
-\r
-       surfaces_mutex.Unlock();\r
-}\r
-\r
-\r
-void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,\r
-                       list<SVGCommand>& commands)\r
-{\r
-       surfaces_mutex.Lock();\r
-       //First determine it is already in our system\r
-       list<SurfaceCommands>::iterator itty=scommands.begin();\r
-       while (itty!=scommands.end()) {\r
-               if ((*itty).surf==surf) {\r
-                       //decrease the references\r
-                       dereferenceSVGCommand((*itty).commands);\r
-                       break;\r
-               }\r
-               itty++;\r
-       }\r
-       // if not insert it\r
-       if (itty==scommands.end()) {\r
-               SurfaceCommands new_sc;\r
-               new_sc.surf=surf;\r
-               new_sc.x=x;\r
-               new_sc.y=y;\r
-               new_sc.w=width;\r
-               new_sc.h=height;\r
-               itty=scommands.insert(itty,new_sc);\r
-       }\r
-       // then clear and copy\r
-       (*itty).commands.clear();\r
-       (*itty).commands=commands;\r
-       //increase the references\r
-       list<SVGCommand>::iterator sitty=(*itty).commands.begin();\r
-       while (sitty!=(*itty).commands.end())\r
-       {\r
-               incStyleRef((*sitty).getRef());\r
-               ImageIndex ii=(*sitty).getImageIndex();\r
-               if (ii) incImageRef(ii);\r
-               sitty++;\r
-       }\r
-       cleanupOrphanedRefs();\r
-\r
-       surfaces_mutex.Unlock();\r
-}\r
-\r
-void OsdVector::removeSurface(const SurfaceVector *surf)\r
-{\r
-       surfaces_mutex.Lock();\r
-       //First determine it is already in our system\r
-       list<SurfaceCommands>::iterator itty=scommands.begin();\r
-       while (itty!=scommands.end()) {\r
-               if ((*itty).surf==surf) {\r
-                       dereferenceSVGCommand((*itty).commands);\r
-                       (*itty).commands.clear();\r
-                       scommands.erase(itty);\r
-                       break;\r
-               }\r
-               itty++;\r
-       }\r
-       surfaces_mutex.Unlock();\r
-\r
-}\r
-\r
-void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )\r
-{\r
-\r
-       list<SVGCommand>::iterator sitty = commands.begin();\r
-       while (sitty != commands.end()) {\r
-               removeStyleRef((*sitty).getRef());\r
-               ImageIndex ii = (*sitty).getImageIndex();\r
-               if (ii) removeImageRef(ii);\r
-               sitty++;\r
-       }\r
-}\r
-\r
-void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )\r
-{\r
-       list<SVGCommand>::iterator sitty=commands.begin();\r
-       while (sitty!=commands.end())\r
-       {\r
-               incStyleRef((*sitty).getRef());\r
-               ImageIndex ii=(*sitty).getImageIndex();\r
-               if (ii) incImageRef(ii);\r
-               sitty++;\r
-       }\r
-}\r
-\r
-void OsdVector::incImageRef(ImageIndex index)\r
-{\r
-       if (images_ref.find(index)==images_ref.end()) {\r
-               images_ref[index]=1;\r
-       } else {\r
-               images_ref[index]++;\r
-       }\r
-}\r
-\r
-void OsdVector::removeImageRef(const ImageIndex ref)\r
-{\r
-       images_ref[ref]--;\r
-}\r
-\r
-void OsdVector::cleanupOrphanedRefs()\r
-{ // Do some garbage collection\r
-\r
-       map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();\r
-       while (mitty!=monobitmaps.end()) {\r
-               map<ImageIndex,unsigned int>::iterator curitty=images_ref.find((*mitty).second);\r
-               int count=(*curitty).second;\r
-               if (count==0) {\r
-                       ImageIndex ref=(*curitty).first;\r
-                       monobitmaps.erase(mitty++);\r
-                       images_ref.erase(curitty++);\r
-                       destroyImageRef(ref);\r
-               } else ++mitty;\r
-       }\r
-\r
-       map<string,ImageIndex>::iterator jitty=jpegs.begin();\r
-       while (jitty!=jpegs.end()) {\r
-               map<ImageIndex,unsigned int>::iterator curitty=images_ref.find((*jitty).second);\r
-               int count=(*curitty).second;\r
-               if (count==0) {\r
-                       ImageIndex ref=(*curitty).first;\r
-                       jpegs.erase(jitty++);\r
-                       images_ref.erase(curitty++);\r
-                       destroyImageRef(ref);\r
-               } else ++jitty;\r
-       }\r
-\r
-\r
-       map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();\r
-       while (sitty!=styles.end()) {\r
-               map<unsigned int,unsigned int>::iterator curitty=styles_ref.find((*sitty).second);\r
-               int count=(*curitty).second;\r
-               if (count==0) {\r
-                       unsigned int ref=(*curitty).first;\r
-                       styles.erase(sitty++);\r
-                       styles_ref.erase(curitty++);\r
-                       destroyStyleRef(ref);\r
-\r
-               } else ++sitty;\r
-\r
-       }\r
-}\r
-\r
-\r
-unsigned int OsdVector::getImageRef(ImageIndex index)\r
-{\r
-       if (images_ref.find(index)==images_ref.end()) {\r
-               return -1;\r
-       } else {\r
-               return images_ref[index];\r
-       }\r
-}\r
-\r
-void OsdVector::incStyleRef(unsigned int index)\r
-{\r
-       if (styles_ref.find(index)==styles_ref.end()) {\r
-               styles_ref[index]=1;\r
-       } else {\r
-               styles_ref[index]++;\r
-       }\r
-}\r
-\r
-void OsdVector::removeStyleRef(unsigned int index)\r
-{\r
-       styles_ref[index]--;\r
-}\r
-\r
-unsigned int OsdVector::getStyleRef(const DrawStyle &c)\r
-{\r
-       unsigned int style_handle=0;\r
-       if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())\r
-       {\r
-               style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);\r
-       } else {\r
-               style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];\r
-               //Now check if the handle is valid\r
-               if (styles_ref.find(style_handle)==styles_ref.end()) {\r
-                       //invalid handle recreate\r
-                       style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);\r
-               }\r
-       }\r
-       incStyleRef(style_handle);\r
-       return style_handle;\r
-}\r
-\r
-unsigned int OsdVector::getColorRef(const Colour &c)\r
-{\r
-       unsigned int style_handle=0;\r
-       if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())\r
-       {\r
-               style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);\r
-       } else {\r
-               style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];\r
-               if (styles_ref.find(style_handle)==styles_ref.end()) {\r
-                       //invalid handle recreate\r
-                       style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);\r
-               }\r
-       }\r
-       incStyleRef(style_handle);\r
-       return style_handle;\r
-}\r
-\r
-unsigned int OsdVector::getStyleRef(unsigned int index)\r
-{\r
-       if (styles_ref.find(index)==styles_ref.end()) {\r
-               return -1;\r
-       } else {\r
-               return styles_ref[index];\r
-       }\r
-}\r
-\r
-ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)\r
-{\r
-       ImageIndex image_handle=0;\r
-       if (jpegs.find(fileName)==jpegs.end())\r
-       {\r
-               image_handle=jpegs[fileName]=createJpeg(fileName,width,height);\r
-       } else {\r
-               image_handle=jpegs[fileName];\r
-               *width=0;\r
-               *height=0;\r
-               if (images_ref.find(image_handle)==images_ref.end()) {\r
-                       //invalid handle recreate\r
-                       image_handle=jpegs[fileName]=createJpeg(fileName,width,height);\r
-               }\r
-       }\r
-       incImageRef(image_handle);\r
-       return image_handle;\r
-}\r
-\r
-ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)\r
-{\r
-       ImageIndex image_handle;\r
-       if (monobitmaps.find(base)==monobitmaps.end())\r
-       {\r
-               image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);\r
-       } else {\r
-               image_handle=monobitmaps[base];\r
-               if (images_ref.find(image_handle)==images_ref.end()) {\r
-                       //invalid handle recreate\r
-                       image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);\r
-               }\r
-       }\r
-       incImageRef(image_handle);\r
-       return image_handle;\r
-}\r
-\r
-ImageIndex  OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)\r
-{\r
-       ImageIndex image_handle;\r
-       image_handle=createImagePalette(width,height,image_data,palette_data);\r
-       incImageRef(image_handle);\r
-       return image_handle;\r
-}\r
+/*
+    Copyright 2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#include "osdvector.h"
+#include "surfacevector.h"
+
+OsdVector::OsdVector()
+{
+       setlocale(LC_CTYPE,"C.UTF-8");
+}
+
+OsdVector::~OsdVector()
+{
+
+}
+
+
+int OsdVector::getFD()
+{
+       return 0;
+}
+
+void OsdVector::screenShot(const char* fileName)
+{
+       //Do nothing,
+}
+
+Surface * OsdVector::createNewSurface()
+{
+       return new SurfaceVector(this);
+}
+
+void OsdVector::BeginPainting()
+{
+       surfaces_mutex.Lock();
+}
+void OsdVector::EndPainting()
+{
+       surfaces_mutex.Unlock();
+}
+
+void OsdVector::Blank()
+{
+       // do nothing? remove this one?
+}
+
+int OsdVector::restore()
+{
+       // First clear the contents of all registered surfaces
+       surfaces_mutex.Lock();
+
+       //Now go through all surfaces and draw them
+       list<SurfaceCommands>::iterator curdraw=scommands.begin();
+       while (curdraw!=scommands.end()) {
+               (*curdraw).commands.clear();
+               curdraw++;
+       }
+       //also clear all handles, they are now invalid, no need to release them
+       images_ref.clear();;
+       monobitmaps.clear();
+       jpegs.clear();
+       styles.clear();
+       styles_ref.clear();
+
+       surfaces_mutex.Unlock();
+       return 1;
+}
+
+void OsdVector::drawSurfaces()
+{
+       surfaces_mutex.Lock();
+       list<SurfaceCommands*> todraw; //First figure out if a surfaces is below another surface
+       list<SurfaceCommands>::iterator itty1=scommands.begin();
+       while (itty1!=scommands.end()) {
+               list<SurfaceCommands>::iterator itty2=itty1;
+               itty2++;
+               bool hidden=false;
+               while (itty2!=scommands.end()) {
+                       SurfaceCommands & ref1=*itty1;
+                       SurfaceCommands & ref2=*itty2;
+                       if (ref1.x>=ref2.x && ref1.y>=ref2.y
+                                       && (ref1.x+ref1.w) <= (ref2.x+ref2.w)
+                                       && (ref1.y+ref1.h) <= (ref2.y+ref2.h) ) {
+                               hidden=true;
+                               break;
+                       }
+                       itty2++;
+               }
+               if (!hidden) { // we are not hidden, perfect
+                       todraw.push_back(&(*itty1));
+               }
+               itty1++;
+       }
+       //Now go through all surfaces and draw them
+       list<SurfaceCommands*>::iterator curdraw=todraw.begin();
+       while (curdraw!=todraw.end()) {
+               drawSetTrans(*(*curdraw));
+               list<SVGCommand>::iterator commands=(*(*curdraw)).commands.begin();
+               list<SVGCommand>::iterator end=(*(*curdraw)).commands.end();
+               while (commands!=end) {
+                       executeDrawCommand(*commands);
+                       commands++;
+               }
+               curdraw++;
+       }
+
+       surfaces_mutex.Unlock();
+}
+
+
+void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
+                       list<SVGCommand>& commands)
+{
+       surfaces_mutex.Lock();
+       //First determine it is already in our system
+       list<SurfaceCommands>::iterator itty=scommands.begin();
+       while (itty!=scommands.end()) {
+               if ((*itty).surf==surf) {
+                       //decrease the references
+                       dereferenceSVGCommand((*itty).commands);
+                       break;
+               }
+               itty++;
+       }
+       // if not insert it
+       if (itty==scommands.end()) {
+               SurfaceCommands new_sc;
+               new_sc.surf=surf;
+               new_sc.x=x;
+               new_sc.y=y;
+               new_sc.w=width;
+               new_sc.h=height;
+               itty=scommands.insert(itty,new_sc);
+       }
+       // then clear and copy
+       (*itty).commands.clear();
+       (*itty).commands=commands;
+       //increase the references
+       list<SVGCommand>::iterator sitty=(*itty).commands.begin();
+       while (sitty!=(*itty).commands.end())
+       {
+               incStyleRef((*sitty).getRef());
+               ImageIndex ii=(*sitty).getImageIndex();
+               if (ii) incImageRef(ii);
+               sitty++;
+       }
+       cleanupOrphanedRefs();
+
+       surfaces_mutex.Unlock();
+}
+
+void OsdVector::removeSurface(const SurfaceVector *surf)
+{
+       surfaces_mutex.Lock();
+       //First determine it is already in our system
+       list<SurfaceCommands>::iterator itty=scommands.begin();
+       while (itty!=scommands.end()) {
+               if ((*itty).surf==surf) {
+                       dereferenceSVGCommand((*itty).commands);
+                       (*itty).commands.clear();
+                       scommands.erase(itty);
+                       break;
+               }
+               itty++;
+       }
+       surfaces_mutex.Unlock();
+
+}
+
+void OsdVector::dereferenceSVGCommand(list<SVGCommand>& commands )
+{
+
+       list<SVGCommand>::iterator sitty = commands.begin();
+       while (sitty != commands.end()) {
+               removeStyleRef((*sitty).getRef());
+               ImageIndex ii = (*sitty).getImageIndex();
+               if (ii) removeImageRef(ii);
+               sitty++;
+       }
+}
+
+void OsdVector::referenceSVGCommand(list<SVGCommand>& commands )
+{
+       list<SVGCommand>::iterator sitty=commands.begin();
+       while (sitty!=commands.end())
+       {
+               incStyleRef((*sitty).getRef());
+               ImageIndex ii=(*sitty).getImageIndex();
+               if (ii) incImageRef(ii);
+               sitty++;
+       }
+}
+
+void OsdVector::incImageRef(ImageIndex index)
+{
+       if (images_ref.find(index)==images_ref.end()) {
+               images_ref[index]=1;
+       } else {
+               images_ref[index]++;
+       }
+}
+
+void OsdVector::removeImageRef(const ImageIndex ref)
+{
+       images_ref[ref]--;
+}
+
+void OsdVector::cleanupOrphanedRefs()
+{ // Do some garbage collection
+
+       map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
+       while (mitty!=monobitmaps.end()) {
+               map<ImageIndex,unsigned int>::iterator curitty=images_ref.find((*mitty).second);
+               int count=(*curitty).second;
+               if (count==0) {
+                       ImageIndex ref=(*curitty).first;
+                       monobitmaps.erase(mitty++);
+                       images_ref.erase(curitty++);
+                       destroyImageRef(ref);
+               } else ++mitty;
+       }
+
+       map<string,ImageIndex>::iterator jitty=jpegs.begin();
+       while (jitty!=jpegs.end()) {
+               map<ImageIndex,unsigned int>::iterator curitty=images_ref.find((*jitty).second);
+               int count=(*curitty).second;
+               if (count==0) {
+                       ImageIndex ref=(*curitty).first;
+                       jpegs.erase(jitty++);
+                       images_ref.erase(curitty++);
+                       destroyImageRef(ref);
+               } else ++jitty;
+       }
+
+
+       map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
+       while (sitty!=styles.end()) {
+               map<unsigned int,unsigned int>::iterator curitty=styles_ref.find((*sitty).second);
+               int count=(*curitty).second;
+               if (count==0) {
+                       unsigned int ref=(*curitty).first;
+                       styles.erase(sitty++);
+                       styles_ref.erase(curitty++);
+                       destroyStyleRef(ref);
+
+               } else ++sitty;
+
+       }
+}
+
+
+unsigned int OsdVector::getImageRef(ImageIndex index)
+{
+       if (images_ref.find(index)==images_ref.end()) {
+               return -1;
+       } else {
+               return images_ref[index];
+       }
+}
+
+void OsdVector::incStyleRef(unsigned int index)
+{
+       if (styles_ref.find(index)==styles_ref.end()) {
+               styles_ref[index]=1;
+       } else {
+               styles_ref[index]++;
+       }
+}
+
+void OsdVector::removeStyleRef(unsigned int index)
+{
+       styles_ref[index]--;
+}
+
+unsigned int OsdVector::getStyleRef(const DrawStyle &c)
+{
+       unsigned int style_handle=0;
+       if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
+       {
+               style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
+       } else {
+               style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
+               //Now check if the handle is valid
+               if (styles_ref.find(style_handle)==styles_ref.end()) {
+                       //invalid handle recreate
+                       style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createStyleRef(c);
+               }
+       }
+       incStyleRef(style_handle);
+       return style_handle;
+}
+
+unsigned int OsdVector::getColorRef(const Colour &c)
+{
+       unsigned int style_handle=0;
+       if (styles.find(pair<Colour*,unsigned int>((Colour*)&c,c.rgba()))==styles.end())
+       {
+               style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
+       } else {
+               style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())];
+               if (styles_ref.find(style_handle)==styles_ref.end()) {
+                       //invalid handle recreate
+                       style_handle=styles[pair<Colour*,unsigned int>((Colour*)&c,c.rgba())]=createColorRef(c);
+               }
+       }
+       incStyleRef(style_handle);
+       return style_handle;
+}
+
+unsigned int OsdVector::getStyleRef(unsigned int index)
+{
+       if (styles_ref.find(index)==styles_ref.end()) {
+               return -1;
+       } else {
+               return styles_ref[index];
+       }
+}
+
+ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height)
+{
+       ImageIndex image_handle=0;
+       if (jpegs.find(fileName)==jpegs.end())
+       {
+               image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
+       } else {
+               image_handle=jpegs[fileName];
+               *width=0;
+               *height=0;
+               if (images_ref.find(image_handle)==images_ref.end()) {
+                       //invalid handle recreate
+                       image_handle=jpegs[fileName]=createJpeg(fileName,width,height);
+               }
+       }
+       incImageRef(image_handle);
+       return image_handle;
+}
+
+ImageIndex OsdVector::getMonoBitmapRef(void *base,int width,int height)
+{
+       ImageIndex image_handle;
+       if (monobitmaps.find(base)==monobitmaps.end())
+       {
+               image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
+       } else {
+               image_handle=monobitmaps[base];
+               if (images_ref.find(image_handle)==images_ref.end()) {
+                       //invalid handle recreate
+                       image_handle=monobitmaps[base]=createMonoBitmap(base,width,height);
+               }
+       }
+       incImageRef(image_handle);
+       return image_handle;
+}
+
+ImageIndex  OsdVector::getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
+{
+       ImageIndex image_handle;
+       image_handle=createImagePalette(width,height,image_data,palette_data);
+       incImageRef(image_handle);
+       return image_handle;
+}
index 255d49a8a49855bfd1bac1f6bb313e4188a0f6ae..b9474f17cdbc7fdde94569e6c320c66d224883bd 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon, 2006,2011-2012 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 OSDVECTOR_H\r
-#define OSDVECTOR_H\r
-#include "osd.h"\r
-#include "mutex.h"\r
-#include "colour.h"\r
-#include <list>\r
-#include <map>\r
-#include <string>\r
-\r
-#include "teletextdecodervbiebu.h"\r
-\r
-enum SVGCommandInstr {\r
-       DrawPath,\r
-       DrawGlyph,\r
-       DrawImage,\r
-       DrawTTchar\r
-};\r
-enum PathIndex {\r
-       HorzLine,\r
-       VertLine,\r
-       Rectangle,\r
-       Point\r
-};\r
-\r
-typedef  unsigned int ImageIndex;\r
-\r
-class SVGCommand\r
-{\r
-public:\r
-       SVGCommand(float ix, float iy,float iw,float ih,PathIndex path,unsigned int ref)\r
-       {\r
-               instr=DrawPath;\r
-               x=ix;\r
-               y=iy;\r
-               w=iw;\r
-               h=ih;\r
-               target.path_index=path;\r
-               reference=ref;\r
-       };\r
-       SVGCommand(float ix, float iy,float iw,float ih,ImageIndex image_in,unsigned int ref)\r
-       {\r
-               instr=DrawImage;\r
-               x=ix;\r
-               y=iy;\r
-               w=iw;\r
-               h=ih;\r
-               target.image=image_in;\r
-               reference=ref;\r
-       };\r
-       SVGCommand(float ix, float iy,float iw,float ih,unsigned int ttchar_in)\r
-       {\r
-               instr=DrawTTchar;\r
-               x=ix;\r
-               y=iy;\r
-               w=iw;\r
-               h=ih;\r
-               reference=0;\r
-               target.ttchar=ttchar_in;\r
-       };\r
-       SVGCommand(float ix, float iy,wchar_t char_in,unsigned int ref)\r
-       {\r
-               instr=DrawGlyph;\r
-               x=ix;\r
-               y=iy;\r
-               w=0;\r
-               h=0;\r
-               reference=ref;\r
-               target.textchar=char_in;\r
-       };\r
-\r
-       bool Test(float tx,float ty,float tw, float th)\r
-       {\r
-               return (x>=tx) && (y>=ty) && ((x+w)<=(tx+tw)) && ((y+h)<=(ty+th));\r
-       }\r
-       bool TTTest(float tox,float toy,float tx, float ty)\r
-       {\r
-               return (x==tox) && (toy==y) && (w==tx) && (h==ty);\r
-       }\r
-       unsigned int getRef(){return reference;};\r
-       ImageIndex getImageIndex() {\r
-               if (instr!=DrawImage) return 0;\r
-               else return target.image;\r
-       };\r
-       SVGCommandInstr instr;\r
-       float x,y,w,h;\r
-       unsigned int reference;\r
-       union {\r
-               PathIndex path_index; //path_index\r
-               wchar_t textchar;\r
-               ImageIndex image;\r
-               unsigned int ttchar;\r
-       } target;\r
-};\r
-\r
-class SurfaceVector;\r
-\r
-struct SurfaceCommands{\r
-       const SurfaceVector* surf;\r
-       list<SVGCommand> commands;\r
-       float x,y,w,h;\r
-};\r
-\r
-\r
-class OsdVector : public Osd\r
-{\r
-  public:\r
-    OsdVector();\r
-    virtual ~OsdVector();\r
-\r
-\r
-    int restore();\r
-\r
-    int getFD();\r
-\r
-    void screenShot(const char* fileName);\r
-\r
-    Surface * createNewSurface();\r
-       void BeginPainting();\r
-       void EndPainting();\r
-\r
-       void Blank();\r
-\r
-       void updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,\r
-                       list<SVGCommand>& commands);\r
-       void removeSurface(const SurfaceVector *surf);\r
-\r
-       virtual float getFontHeight()=0;\r
-       virtual float getCharWidth(wchar_t c)=0;\r
-\r
-       virtual ImageIndex getJpegRef(const char* fileName, int *width,int *height);\r
-       virtual ImageIndex getMonoBitmapRef(void *base,int width,int height);\r
-       virtual ImageIndex getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data);\r
-       virtual void imageUploadLine(ImageIndex index,unsigned int j,unsigned int width,void *data)=0;\r
-       void removeImageRef(const ImageIndex ref);\r
-       unsigned int getColorRef(const Colour &c); //internally this is the same as getStyleRef\r
-       unsigned int getStyleRef(const DrawStyle &c);\r
-       virtual void removeStyleRef(unsigned int ref);\r
-\r
-\r
-    int charSet() {return 2;}; //UTF-8\r
-\r
-\r
-\r
-protected:\r
-\r
-       void incImageRef(ImageIndex index);\r
-       unsigned int getImageRef(ImageIndex index);\r
-       virtual void destroyImageRef(ImageIndex index)=0;\r
-       virtual ImageIndex createJpeg(const char* fileName, int *width,int *height)=0;\r
-       virtual ImageIndex createMonoBitmap(void *base,int width,int height)=0;\r
-       virtual ImageIndex createImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)=0;\r
-\r
-       map<ImageIndex,unsigned int> images_ref;\r
-       map<void *,ImageIndex> monobitmaps;\r
-       map<string,ImageIndex> jpegs;\r
-\r
-       void incStyleRef(unsigned int index);\r
-       unsigned int getStyleRef(ImageIndex index);\r
-       virtual void destroyStyleRef(unsigned int index)=0;\r
-       map<pair<Colour*,unsigned int>,unsigned int> styles;\r
-       map<unsigned int,unsigned int> styles_ref;\r
-       virtual unsigned int createStyleRef(const DrawStyle &c)=0;\r
-       virtual unsigned int createColorRef(const Colour &c)=0;\r
-\r
-       void dereferenceSVGCommand(list<SVGCommand>& commands );\r
-       void referenceSVGCommand(list<SVGCommand>& commands );\r
-       void cleanupOrphanedRefs();\r
-\r
-\r
-\r
-       virtual void drawSetTrans(SurfaceCommands & sc)=0;\r
-       virtual void executeDrawCommand(SVGCommand & command)=0;\r
-\r
-\r
-\r
-\r
-       list<SurfaceCommands> scommands;\r
-\r
-       Mutex surfaces_mutex;\r
-\r
-       void drawSurfaces();\r
-};\r
-\r
-\r
-\r
-\r
-#endif\r
+/*
+    Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef OSDVECTOR_H
+#define OSDVECTOR_H
+#include "osd.h"
+#include "mutex.h"
+#include "colour.h"
+#include <list>
+#include <map>
+#include <string>
+
+#include "teletextdecodervbiebu.h"
+
+enum SVGCommandInstr {
+       DrawPath,
+       DrawGlyph,
+       DrawImage,
+       DrawTTchar
+};
+enum PathIndex {
+       HorzLine,
+       VertLine,
+       Rectangle,
+       Point
+};
+
+typedef  unsigned int ImageIndex;
+
+class SVGCommand
+{
+public:
+       SVGCommand(float ix, float iy,float iw,float ih,PathIndex path,unsigned int ref)
+       {
+               instr=DrawPath;
+               x=ix;
+               y=iy;
+               w=iw;
+               h=ih;
+               target.path_index=path;
+               reference=ref;
+       };
+       SVGCommand(float ix, float iy,float iw,float ih,ImageIndex image_in,unsigned int ref)
+       {
+               instr=DrawImage;
+               x=ix;
+               y=iy;
+               w=iw;
+               h=ih;
+               target.image=image_in;
+               reference=ref;
+       };
+       SVGCommand(float ix, float iy,float iw,float ih,unsigned int ttchar_in)
+       {
+               instr=DrawTTchar;
+               x=ix;
+               y=iy;
+               w=iw;
+               h=ih;
+               reference=0;
+               target.ttchar=ttchar_in;
+       };
+       SVGCommand(float ix, float iy,wchar_t char_in,unsigned int ref)
+       {
+               instr=DrawGlyph;
+               x=ix;
+               y=iy;
+               w=0;
+               h=0;
+               reference=ref;
+               target.textchar=char_in;
+       };
+
+       bool Test(float tx,float ty,float tw, float th)
+       {
+               return (x>=tx) && (y>=ty) && ((x+w)<=(tx+tw)) && ((y+h)<=(ty+th));
+       }
+       bool TTTest(float tox,float toy,float tx, float ty)
+       {
+               return (x==tox) && (toy==y) && (w==tx) && (h==ty);
+       }
+       unsigned int getRef(){return reference;};
+       ImageIndex getImageIndex() {
+               if (instr!=DrawImage) return 0;
+               else return target.image;
+       };
+       SVGCommandInstr instr;
+       float x,y,w,h;
+       unsigned int reference;
+       union {
+               PathIndex path_index; //path_index
+               wchar_t textchar;
+               ImageIndex image;
+               unsigned int ttchar;
+       } target;
+};
+
+class SurfaceVector;
+
+struct SurfaceCommands{
+       const SurfaceVector* surf;
+       list<SVGCommand> commands;
+       float x,y,w,h;
+};
+
+
+class OsdVector : public Osd
+{
+  public:
+    OsdVector();
+    virtual ~OsdVector();
+
+
+    int restore();
+
+    int getFD();
+
+    void screenShot(const char* fileName);
+
+    Surface * createNewSurface();
+       void BeginPainting();
+       void EndPainting();
+
+       void Blank();
+
+       void updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width,
+                       list<SVGCommand>& commands);
+       void removeSurface(const SurfaceVector *surf);
+
+       virtual float getFontHeight()=0;
+       virtual float getCharWidth(wchar_t c)=0;
+
+       virtual ImageIndex getJpegRef(const char* fileName, int *width,int *height);
+       virtual ImageIndex getMonoBitmapRef(void *base,int width,int height);
+       virtual ImageIndex getImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data);
+       virtual void imageUploadLine(ImageIndex index,unsigned int j,unsigned int width,void *data)=0;
+       void removeImageRef(const ImageIndex ref);
+       unsigned int getColorRef(const Colour &c); //internally this is the same as getStyleRef
+       unsigned int getStyleRef(const DrawStyle &c);
+       virtual void removeStyleRef(unsigned int ref);
+
+
+    int charSet() {return 2;}; //UTF-8
+
+
+
+protected:
+
+       void incImageRef(ImageIndex index);
+       unsigned int getImageRef(ImageIndex index);
+       virtual void destroyImageRef(ImageIndex index)=0;
+       virtual ImageIndex createJpeg(const char* fileName, int *width,int *height)=0;
+       virtual ImageIndex createMonoBitmap(void *base,int width,int height)=0;
+       virtual ImageIndex createImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)=0;
+
+       map<ImageIndex,unsigned int> images_ref;
+       map<void *,ImageIndex> monobitmaps;
+       map<string,ImageIndex> jpegs;
+
+       void incStyleRef(unsigned int index);
+       unsigned int getStyleRef(ImageIndex index);
+       virtual void destroyStyleRef(unsigned int index)=0;
+       map<pair<Colour*,unsigned int>,unsigned int> styles;
+       map<unsigned int,unsigned int> styles_ref;
+       virtual unsigned int createStyleRef(const DrawStyle &c)=0;
+       virtual unsigned int createColorRef(const Colour &c)=0;
+
+       void dereferenceSVGCommand(list<SVGCommand>& commands );
+       void referenceSVGCommand(list<SVGCommand>& commands );
+       void cleanupOrphanedRefs();
+
+
+
+       virtual void drawSetTrans(SurfaceCommands & sc)=0;
+       virtual void executeDrawCommand(SVGCommand & command)=0;
+
+
+
+
+       list<SurfaceCommands> scommands;
+
+       Mutex surfaces_mutex;
+
+       void drawSurfaces();
+};
+
+
+
+
+#endif
index 83560b905c5179f5106152324d138e43cee23049..c55bb112388df60b059e726619a337fbcf31690e 100644 (file)
--- a/osdwin.cc
+++ b/osdwin.cc
-/*\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.
+*/
+
+
+#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;
+}
+
+Surface * OsdWin::createNewSurface(){
+       return (Surface*)new SurfaceWin();
+}
+
+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;
+  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(const 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();
+}
index 81f64f5601e66c0d793431eb6e1586c5a18b0f83..d9048534e78ea3f61797a430d528b092cad2170a 100644 (file)
--- a/osdwin.h
+++ b/osdwin.h
-/*\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-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(const char* fileName);
+
+    Surface * createNewSurface();
+
+       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
index ddff93fa76e159e7a820ead55f5b552c44ebdab7..c8f9329be1aaf45f0458b2dd2a1a1f9de02545b1 100644 (file)
--- a/player.cc
+++ b/player.cc
-/*\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
-  unsigned int demux_audio_size=524288;\r
-  if (video->supportsh264()) {\r
-         demux_video_size*=5*2;//5;\r
-\r
-  }\r
-  if (audio->maysupportAc3()) {\r
-         //demux_audio_size*=2;\r
-  }\r
\r
-  if (!demuxer->init(this, audio, video,teletext, demux_video_size,demux_audio_size,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, int streamtype)\r
-{\r
-    if (is_pesrecording) {\r
-        demuxer->setAudioStream(newChannel);\r
-        return;\r
-    } else {\r
-        ((DemuxerTS*)demuxer)->setAID(newChannel,type,streamtype);\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 NULL; //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.
+*/
+
+#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;
+  unsigned int demux_audio_size=524288;
+  if (video->supportsh264()) {
+         demux_video_size*=5*2;//5;
+
+  }
+  if (audio->maysupportAc3()) {
+         //demux_audio_size*=2;
+  }
+  if (!demuxer->init(this, audio, video,teletext, demux_video_size,demux_audio_size,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) {
+         demuxer->setDVBSubtitleStream(newChannel);
+    } else {
+        ((DemuxerTS*)demuxer)->setSubID(newChannel);
+    }
+}
+
+int *Player::getTeletxtSubtitlePages()
+{
+    return teletext->getSubtitlePages();
+}
+
+void Player::setAudioChannel(int newChannel, int type, int streamtype)
+{
+    if (is_pesrecording) {
+        demuxer->setAudioStream(newChannel);
+        return;
+    } else {
+        ((DemuxerTS*)demuxer)->setAID(newChannel,type,streamtype);
+        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 NULL; //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::playpause()
+{
+  if (!initted) return;
+  lock();
+
+  bool doUnlock = false;
+  if (state==S_PLAY) {
+         doUnlock=true;
+         switchState(S_PAUSE_P);
+  } else {
+         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))
+  {
+    if (video->PTSIFramePlayback()) threadPTSFeedScan();
+    else 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::threadPTSFeedScan()
+{
+  // This method manipulates the PTS instead of waiting, this is for the android devices, maybe later for windows?
+
+  ULONG direction = 0;
+  int dir_fac=-1;
+  ULONG baseFrameNumber = 0;
+  ULONG iframeNumber = 0;
+  ULONG iframeLength = 0;
+  ULONG currentfeedFrameNumber=currentFrameNumber;
+  ULONG firstFrameNumber=currentFrameNumber;
+  ULLONG filePos;
+  UINT amountReceived;
+  UINT videoLength;
+
+  UINT playtime=0;
+
+#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
+         dir_fac=1;
+  }
+  video->EnterIframePlayback();
+
+  while(1)
+  {
+    // Fetch I-frames until we get one that can be displayed in good time
+    // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
+
+    baseFrameNumber = currentfeedFrameNumber;
+
+    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)currentfeedFrameNumber) * 1000) / (fps * (double)ifactor));
+
+    logger->log("Player", Log::DEBUG, "XXX Got frame");
+
+    threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
+
+    if (!vdr->isConnected())
+    {
+      if (threadBuffer) free(threadBuffer);
+      doConnectionLost();
+      break;
+    }
+
+
+    threadCheckExit();
+
+
+    videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
+    demuxer->changeTimes(threadBuffer,videoLength,playtime);
+    int count=0;
+    while (!video->displayIFrame(threadBuffer, videoLength)) // the device might block
+    {
+       MILLISLEEP(20);
+       threadCheckExit();
+       count++;
+       if (count%300==0) {
+               ULLONG cur_time=video->getCurrentTimestamp();
+       //       logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",
+               //              firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);
+               if (cur_time!=0) {
+                   currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));
+               }
+       }
+
+    }
+    playtime +=frameTimeOffset;
+    currentfeedFrameNumber = iframeNumber;
+    {
+               ULLONG cur_time=video->getCurrentTimestamp();
+       //       logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",
+               //              firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);
+               if (cur_time!=0) {
+                   currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));
+               }
+       }
+
+    free(threadBuffer);
+    threadBuffer = NULL;
+  }
+}
+
+
+
+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
index 5c9d7f7e9e1ab3f2c7d0e74dd8220478dc58ff9f..12de87a8001d25ef2c7a22dee58c821950d0dee7 100644 (file)
--- a/player.h
+++ b/player.h
-/*\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, int streamtype);\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 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>
+
+#include "threadsystem.h"
+
+#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, int streamtype);
+    void setSubtitleChannel(int newChannel);
+    bool toggleSubtitles();
+    void turnSubtitlesOn(bool ison); 
+    bool isSubtitlesOn() { return subtitlesShowing; }
+
+    void play();
+    void stop();
+    void pause();
+    void playpause();
+    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 threadPTSFeedScan();
+
+    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
+
+*/
index 0a2fe57365d454681ce5cf8f7f82fb081f187aa6..9a4a1bb30dcb2136a330fee06a50a477e3476323 100644 (file)
-/*\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,int streamtype)\r
-{\r
-  demuxer->setAID(newChannel, type,streamtype);\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
-          bool found=false;\r
-\r
-          if (chan->numAPids > 0) \r
-          {\r
-                 int j=0;\r
-                 while (j<chan->numAPids && !found) {\r
-                         if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type)) {\r
-                                 demuxer->setAID(chan->apids[j].pid,0,chan->apids[j].type);\r
-                                 audio->setStreamType(Audio::MPEG2_PES);\r
-                                 logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[j].pid,chan->apids[j].type);\r
-                                 found=true;\r
-                         }\r
-                         j++;\r
-                 }\r
-          }\r
-\r
-          if (!found)\r
-          {\r
-                 if (chan->numDPids > 0  && audio->maysupportAc3())\r
-                 {\r
-                         int j=0;\r
-                         while (j<chan->numDPids && !found) {\r
-                                 if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type)) {\r
-                                         demuxer->setAID(chan->dpids[j].pid,1,chan->dpids[j].type);\r
-                                         audio->setStreamType(Audio::MPEG2_PES);\r
-                                         logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", chan->vpid, chan->dpids[j].pid,chan->dpids[j].type);\r
-                                         found=true;\r
-                                 }\r
-                                 j++;\r
-                         }\r
-                 }\r
-                 else\r
-                 {\r
-                         logger->log("PlayerLiveRadio", Log::WARN, "Demuxer no pids!");\r
-                 }\r
-          }\r
-\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 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,int streamtype)
+{
+  demuxer->setAID(newChannel, type,streamtype);
+}
+
+void PlayerLiveRadio::setSubtitleChannel(int newChannel)
+{
+  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();
+
+          bool found=false;
+
+          if (chan->numAPids > 0) 
+          {
+                 int j=0;
+                 while (j<chan->numAPids && !found) {
+                         if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type)) {
+                                 demuxer->setAID(chan->apids[j].pid,0,chan->apids[j].type);
+                                 audio->setStreamType(Audio::MPEG2_PES);
+                                 logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[j].pid,chan->apids[j].type);
+                                 found=true;
+                         }
+                         j++;
+                 }
+          }
+
+          if (!found)
+          {
+                 if (chan->numDPids > 0  && audio->maysupportAc3())
+                 {
+                         int j=0;
+                         while (j<chan->numDPids && !found) {
+                                 if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type)) {
+                                         demuxer->setAID(chan->dpids[j].pid,1,chan->dpids[j].type);
+                                         audio->setStreamType(Audio::MPEG2_PES);
+                                         logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", chan->vpid, chan->dpids[j].pid,chan->dpids[j].type);
+                                         found=true;
+                                 }
+                                 j++;
+                         }
+                 }
+                 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");
+}
+
index bbd3928b3c5c7a99c301396dbe8d5c4a53b775be..f2fc4179da1248e67ab229756c54585a4e839dc0 100644 (file)
-/*\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
-   unsigned int demux_audio_size=524288;\r
-   if (video->supportsh264()) {\r
-         demux_video_size*=5*1;//5;\r
-\r
-   }\r
-   if (audio->maysupportAc3()) {\r
-         //demux_audio_size*=2;\r
-   }\r
-\r
-  int text_fak=video->getTeletextBufferFaktor();\r
-\r
\r
-  if (!demuxer->init(this, audio, video, teletext, demux_video_size,demux_audio_size, 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,int streamtype)\r
-{\r
-  demuxer->setAID(newChannel,type,streamtype);\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() < PLAYER_MAX_STREAMING_BUFFERS)\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
-           bool found=false;\r
-\r
-          if (chan->numAPids > 0) \r
-          {\r
-                 int j=0;\r
-                 while (j<chan->numAPids && !found) {\r
-                         if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type)) {\r
-                                 demuxer->setAID(chan->apids[j].pid,0,chan->apids[j].type);\r
-                                 audio->setStreamType(Audio::MPEG2_PES);\r
-                                 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[j].pid,chan->apids[j].type);\r
-                                 found=true;\r
-                         }\r
-                         j++;\r
-                 }\r
-          }\r
-\r
-          if (!found)\r
-          {\r
-              if (chan->numDPids > 0  && audio->maysupportAc3()) \r
-              {\r
-                 int j=0;\r
-                 while (j<chan->numDPids && !found) {\r
-                         if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type)) {\r
-                                 demuxer->setAID(chan->dpids[j].pid,1,chan->dpids[j].type);\r
-                                 audio->setStreamType(Audio::MPEG2_PES);\r
-                                 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", chan->vpid, chan->dpids[j].pid,chan->dpids[j].type);\r
-                                 found=true;\r
-                         }\r
-                         j++;\r
-                 }\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
-       //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1 %d", streamChunks.size());\r
-      chunkToDemuxer();\r
-      //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2 %d", streamChunks.size());\r
-\r
-      if (state == S_PREBUFFERING)\r
-      {\r
-        // logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark3");\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
-  //  logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal %d", streamChunks.size());\r
-    threadLock();\r
-    threadWaitForSignal(); // unlocks and waits for signal\r
-    threadUnlock();\r
-    //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal2 %d",streamChunks.size());\r
-  }\r
-\r
-  logger->log("PlayerLiveTV", 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;
+   unsigned int demux_audio_size=524288;
+   if (video->supportsh264()) {
+         demux_video_size*=5*1;//5;
+
+   }
+   if (audio->maysupportAc3()) {
+         //demux_audio_size*=2;
+   }
+
+  int text_fak=video->getTeletextBufferFaktor();
+
+  if (!demuxer->init(this, audio, video, teletext, demux_video_size,demux_audio_size, 65536*text_fak,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;
+  logger->log("PlayerLiveTV", Log::DEBUG, "Shutdown");
+  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,int streamtype)
+{
+  demuxer->setAID(newChannel,type,streamtype);
+}
+
+void PlayerLiveTV::setSubtitleChannel(int newChannel)
+{
+   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();
+  logger->log("PlayerLiveTV", Log::DEBUG, "stop succesfull");
+}
+
+// ----------------------------------- 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() < PLAYER_MAX_STREAMING_BUFFERS)
+  {
+    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()|| !video->independentAVStartUp())) //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;
+          if (!video->independentAVStartUp()){
+                 videoStartup = true;
+                 threadSignalNoLock();
+          }
+          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;
+          if (!video->independentAVStartUp()){
+              videoStartup = true;
+              threadSignalNoLock();
+          }
+          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;
+          if (!video->independentAVStartUp()){
+                 videoStartup = true;
+              threadSignalNoLock();
+          }
+          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)
+  {
+
+       //logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);
+    if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
+    {
+          logger->log("PlayerLiveTV", Log::DEBUG, "Enter prebuffering");
+      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);
+
+           bool found=false;
+
+          if (chan->numAPids > 0) 
+          {
+                 int j=0;
+                 while (j<chan->numAPids && !found) {
+                         if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type)) {
+                                 demuxer->setAID(chan->apids[j].pid,0,chan->apids[j].type);
+                                 audio->setStreamType(Audio::MPEG2_PES);
+                                 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[j].pid,chan->apids[j].type);
+                                 found=true;
+                         }
+                         j++;
+                 }
+          }
+
+          if (!found)
+          {
+              if (chan->numDPids > 0  && audio->maysupportAc3()) 
+              {
+                 int j=0;
+                 while (j<chan->numDPids && !found) {
+                         if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type)) {
+                                 demuxer->setAID(chan->dpids[j].pid,1,chan->dpids[j].type);
+                                 audio->setStreamType(Audio::MPEG2_PES);
+                                 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", chan->vpid, chan->dpids[j].pid,chan->dpids[j].type);
+                                 found=true;
+                         }
+                         j++;
+                 }
+              } 
+              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;
+      }
+    }
+
+       threadCheckExit();
+
+    if (stopNow) break;
+
+    while(streamChunks.size())
+    {
+       //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1 %d", streamChunks.size());
+      chunkToDemuxer();
+      //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2 %d", streamChunks.size());
+
+      if (state == S_PREBUFFERING)
+      {
+        // logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark3");
+        ++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();
+        }
+      }
+    }
+  //  logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal %d", streamChunks.size());
+    threadLock();
+    threadWaitForSignal(); // unlocks and waits for signal
+    threadUnlock();
+    //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal2 %d",streamChunks.size());
+  }
+
+  logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");
+}
+
index 1b8e8bac3953905a113990b2db3080d9d502b38e..6d5d6b3e57594a008375d4ede99a341ef9a9e124 100644 (file)
-/*\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.
+*/
+
+#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::playpause()
+{
+  if (!initted) return;
+  lock();
+  if (state==S_PLAY) {
+         switchState(S_PAUSE_P);
+  } else {
+         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;
+  }
+}
+
index a8fed68eba8edc6fbbfd69ebf47151f543a69c95..ac370ce85f9f4a846c59a2038221370d727b7e10 100644 (file)
-/*\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
+/*
+    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>
+
+#include "threadsystem.h"
+
+#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 playpause();
+    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
+
+*/
index abea315f4739fbbadf26717181e7fe7996df22b0..665739b9f6e9b36faf0a03ac4b410f9d7308d30b 100644 (file)
--- a/stream.cc
+++ b/stream.cc
-/*\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
-#ifndef VOMP_PLATTFORM_MVP\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
-#ifndef VOMP_PLATTFORM_MVP\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(bool * dataavail)\r
-{\r
-  bool ret = false;\r
-  if (dataavail) *dataavail=false;\r
-  lock();\r
-  UINT listlength = mediapackets.size();\r
-  if (listlength != 0)\r
-  {\r
-    draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);\r
-    unLock();\r
-    if (dataavail && draintarget->DrainTargetReady()) *dataavail=true;\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 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;
+#ifndef VOMP_PLATTFORM_MVP
+  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;
+        }
+#ifndef VOMP_PLATTFORM_MVP
+        //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 * dataavail)
+{
+  bool ret = false;
+  if (dataavail) *dataavail=false;
+  lock();
+  UINT listlength = mediapackets.size();
+  if (listlength != 0)
+  {
+    draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);
+    unLock();
+    if (dataavail && draintarget->DrainTargetReady()) *dataavail=true;
+    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
+}
index 40b61b72af431ad6ed8b9347eed65fb06262a6d1..1ae541161916112bd4180afdd6712e8bdff357a8 100644 (file)
-/*\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, const DrawStyle& c)\r
-{\r
-  return drawText(text, x, y, 2000, c);\r
-}\r
-\r
-int Surface::drawText(const char* text, int x, int y, int width, const DrawStyle& c)\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
-  ULONG rgba=c.rgba();\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, const DrawStyle& c)\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, c);\r
-}\r
-\r
-int Surface::drawTextCentre(const char* text, int x, int y, const DrawStyle& c)\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, c);\r
-}\r
-\r
-float Surface::getCharWidth(wchar_t c)\r
-{\r
-  return (float)font->width[(unsigned char) c];\r
-}\r
-\r
-int Surface::getFontHeight()\r
-{\r
-  return font->spacing;\r
-}\r
-\r
- wchar_t Surface::getWChar(const char* str, unsigned int *length)\r
- {\r
-        *length=1;\r
-        return *str;\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
-\r
-void Surface::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,\r
-               unsigned int width, Colour& nextColour) {\r
-       startFastDraw();\r
-       int x, y;\r
-       unsigned int bytesIn, bitsIn;\r
-       int widthBytes=width/8;\r
-       for (y = 0; y < height; y++) {\r
-               for (x = 0; x < width; x++) {\r
-                       bytesIn = (y * widthBytes) + (int) (x / 8);\r
-                       bitsIn = x % 8;\r
-\r
-                       if ((base[bytesIn] >> (7 - bitsIn)) & 0x01) {\r
-                               drawPixel(dx+x, dy+y, nextColour, true);\r
-                       }\r
-               }\r
-       }\r
-       endFastDraw();\r
-}\r
-\r
-void Surface::drawPoint(int x, int y, DrawStyle& c, bool fastdraw)\r
-{\r
-       drawPixel(x,y,c,fastdraw);\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 <math.h>
+#include "osd.h"
+#include "log.h"
+#include "video.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];
+bool pol_table_inited=false;
+
+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.;
+
+        }
+    }
+}
+
+
+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, const DrawStyle& c)
+{
+  return drawText(text, x, y, 2000, c);
+}
+
+int Surface::drawText(const char* text, int x, int y, int width, const DrawStyle& c)
+{
+  int h, n, i;
+  int Y, X, cx;
+
+  n = strlen(text);
+  h = font->height;
+
+  X = 0;
+  cx = 0;
+  ULONG rgba=c.rgba();
+  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, const DrawStyle& c)
+{
+  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, c);
+}
+
+int Surface::drawTextCentre(const char* text, int x, int y, const DrawStyle& c)
+{
+  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, c);
+}
+
+float Surface::getCharWidth(wchar_t c)
+{
+  return (float)font->width[(unsigned char) c];
+}
+
+int Surface::getFontHeight()
+{
+  return font->spacing;
+}
+
+ wchar_t Surface::getWChar(const char* str, unsigned int *length)
+ {
+        *length=1;
+        return *str;
+ }
+
+//Moved from Teletext view in order to allow device depend optimizations
+
+Colour Surface::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 Surface::drawTTChar(int ox, int oy, int x, int y, cTeletextChar c)
+{
+       if (!pol_table_inited){
+               initpol_tables();
+               pol_table_inited=true;
+       }
+    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;
+
+    if (Video::getInstance()->getFormat() == Video::PAL)
+    {
+        charsizey=22;
+    } else {
+        charsizey=18;
+    }
+    int ttcharsizex=12;
+    int ttcharsizey=10;
+    int screenposx=charsizex*x+ox; //12*40= 480 250
+    int screenposy=y*charsizey+oy;
+
+
+   // Log::getInstance()->log("Surface", Log::ERR, "TTpos %d %d %d %d %d %d",x,y,ox,oy,screenposx,screenposy);
+    Colour fgcharcl=enumTeletextColorToCoulour(ttforegcolour);
+    Colour bgcharcl=enumTeletextColorToCoulour(ttbackgcolour);
+
+    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
+            int c = (  (res.alpha << 24 )
+                        | (res.red    << 16)
+                        | (res.green  <<  8)
+                        | (res.blue        ) );
+            drawPixel(screenposx+px,screenposy+py,c, true);
+        }
+    }
+
+
+    endFastDraw();
+
+
+}
+
+void Surface::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,
+               unsigned int width, Colour& nextColour) {
+       startFastDraw();
+       int x, y;
+       unsigned int bytesIn, bitsIn;
+       int widthBytes=width/8;
+       for (y = 0; y < height; y++) {
+               for (x = 0; x < width; x++) {
+                       bytesIn = (y * widthBytes) + (int) (x / 8);
+                       bitsIn = x % 8;
+
+                       if ((base[bytesIn] >> (7 - bitsIn)) & 0x01) {
+                               drawPixel(dx+x, dy+y, nextColour, true);
+                       }
+               }
+       }
+       endFastDraw();
+}
+
+void Surface::drawPoint(int x, int y, DrawStyle& c, bool fastdraw)
+{
+       drawPixel(x,y,c,fastdraw);
+}
index 83afa52580700bcee741f091e25dcf98fe3e951d..4c5d4e68a5b9f99fabfb721f0c6bf05e2ba0139e 100644 (file)
--- a/surface.h
+++ b/surface.h
-/*\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
-class DisplayRegion;\r
-\r
-\r
-\r
-class Surface\r
-{\r
-  friend class Wwss; // classes that need surface access, their usage is forbidden for vector based\r
-  friend class WJpegComplex;// implementations of osd\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"
+
+#include "teletextdecodervbiebu.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 DisplayRegion;
+
+
+
+class Surface
+{
+  friend class Wwss; // classes that need surface access, their usage is forbidden for vector based
+  friend class WJpegComplex;// implementations of osd
   friend class VColourTuner;
-  public:\r
-    Surface(int id = 0);\r
-    virtual ~Surface();\r
-\r
-    static Surface* getScreen();\r
-    virtual int getFontHeight();\r
-    virtual float getCharWidth(wchar_t c);\r
-    virtual wchar_t getWChar(const char* str, unsigned int *length);\r
-\r
-    virtual int drawText(const char* text, int x, int y, const DrawStyle& c);\r
-    virtual int drawText(const char* text, int x, int y, int width, const DrawStyle& c);\r
-    virtual int drawTextRJ(const char* text, int x, int y, const DrawStyle& c);\r
-    virtual int drawTextCentre(const char* text, int x, int y, const DrawStyle& c);\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, const DrawStyle& c)=0;\r
-    virtual void drawHorzLine(int x1, int x2, int y, const DrawStyle& c)=0;\r
-    virtual void drawVertLine(int x, int y1, int y2, const DrawStyle& c)=0;\r
-    virtual void drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegion & region)=0;\r
-    virtual void drawPoint(int x, int y, DrawStyle& c, bool fastdraw=false); // This draws a point, must not be a pixel\r
-    virtual void drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,unsigned int width, Colour& nextColour);\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
-    static Colour enumTeletextColorToCoulour(enumTeletextColor ttcol);\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
-\r
-\r
-    virtual void drawPixel(int x, int y, unsigned int c, bool fastdraw=false)=0; // deprecated preparation for vector based drawing, only allowed to be called inside implementation\r
-    virtual void drawPixel(int x, int y, Colour& c, bool fastdraw=false)=0; // deprecated preparation for vector based drawing, only allowed to be called inside implementation\r
-\r
-};\r
-\r
-#endif\r
+  public:
+    Surface(int id = 0);
+    virtual ~Surface();
+
+    static Surface* getScreen();
+    virtual int getFontHeight();
+    virtual float getCharWidth(wchar_t c);
+    virtual wchar_t getWChar(const char* str, unsigned int *length);
+
+    virtual int drawText(const char* text, int x, int y, const DrawStyle& c);
+    virtual int drawText(const char* text, int x, int y, int width, const DrawStyle& c);
+    virtual int drawTextRJ(const char* text, int x, int y, const DrawStyle& c);
+    virtual int drawTextCentre(const char* text, int x, int y, const DrawStyle& c);
+
+    virtual void drawJpeg(const char *fileName,int x, int y,int *width, int *height) {}
+
+    virtual int create(UINT width, UINT height)=0;
+    virtual void display()=0;
+
+    virtual int fillblt(int x, int y, int width, int height, const DrawStyle& c)=0;
+    virtual void drawHorzLine(int x1, int x2, int y, const DrawStyle& c)=0;
+    virtual void drawVertLine(int x, int y1, int y2, const DrawStyle& c)=0;
+    virtual void drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegion & region)=0;
+    virtual void drawPoint(int x, int y, DrawStyle& c, bool fastdraw=false); // This draws a point, must not be a pixel
+    virtual void drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,unsigned int width, Colour& nextColour);
+    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(const 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 void drawTTChar(int ox, int oy,int x, int y, cTeletextChar c);
+    static Colour enumTeletextColorToCoulour(enumTeletextColor ttcol);
+
+
+  
+
+   // 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;
+
+
+    virtual void drawPixel(int x, int y, unsigned int c, bool fastdraw=false)=0; // deprecated preparation for vector based drawing, only allowed to be called inside implementation
+    virtual void drawPixel(int x, int y, Colour& c, bool fastdraw=false)=0; // deprecated preparation for vector based drawing, only allowed to be called inside implementation
+
+};
+
+#endif
index baeeb91791eccc9096a4d640f1bc8e9bb3869b54..7bcf3ebe7e6294de206308febfad2bd98154bee8 100644 (file)
-/*\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 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(const char* fileName)
+{
+  return;
+  
+}
+
+void SurfaceDirectFB::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)
+{
+  
+}
+
index e1870ead4ec8e37e41b0c5b300999604ea3ca8ba..e9a3fff7c7e51e7e2ad522b332030979a6f414c0 100644 (file)
@@ -1,75 +1,75 @@
-/*\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
-    virtual ~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
-\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
-    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
-\r
-\r
-\r
-};\r
-\r
-#endif\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);
+    virtual ~SurfaceDirectFB();
+
+    int create(UINT width, UINT height);
+    void display();
+
+    int fillblt(int x, int y, int width, int height, unsigned int rgba);
+
+    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(const 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;
+
+    void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);
+    void drawPixel(int x, int y, Colour& c, bool fastdraw=false);
+
+
+
+};
+
+#endif
index 12c7c88cb5603ec5e4f143cbbb254410defa6d94..a0c4807130a3c058d182384cd4748bf122ef140f 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon\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 SURFACEMVP_H\r
-#define SURFACEMVP_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
-// Structures for surface management\r
-\r
-typedef struct\r
-{\r
-  unsigned long num;\r
-  unsigned long unknown[4];\r
-  unsigned long width;\r
-  unsigned long height;\r
-  char unknown2;\r
-} stbgfx_display_t;\r
-\r
-typedef struct\r
-{\r
-  unsigned long unknown;\r
-  unsigned long win_unknown;\r
-  unsigned long addr;\r
-  unsigned long size;\r
-  unsigned long unknown2;\r
-  unsigned long width;\r
-  unsigned long height;\r
-  unsigned long unknown3;\r
-  unsigned long unknown4;\r
-  unsigned long width2;\r
-  unsigned long unknown5;\r
-  unsigned long unknown6;\r
-} stbgfx_map_item_t;\r
-\r
-typedef struct {\r
-  stbgfx_map_item_t map[3];\r
-  unsigned long other[2];\r
-} stbgfx_map_t;\r
-\r
-typedef struct\r
-{\r
-  unsigned long handle; /* surface handle */\r
-  unsigned long width;\r
-  unsigned long height;\r
-  unsigned long flags;\r
-  long unknown;   //unsigned long\r
-  unsigned long depth;  /* number of subplanes */\r
-} stbgfx_sfc_t;\r
-\r
-typedef struct\r
-{\r
-  stbgfx_display_t display;\r
-  stbgfx_map_t map;\r
-  stbgfx_sfc_t sfc;\r
-  unsigned char *base[3];\r
-} osd_surface_t;\r
-\r
-\r
-// Structures for surface drawing\r
-\r
-typedef struct\r
-{\r
-  unsigned long handle;\r
-  unsigned long x;\r
-  unsigned long y;\r
-  unsigned long width;\r
-  unsigned long height;\r
-  unsigned long colour;\r
-} osd_fillblt_t;\r
-\r
-typedef struct {\r
-  unsigned long dst_handle;\r
-  unsigned long dst_x;\r
-  unsigned long dst_y;\r
-  unsigned long width;\r
-  unsigned long height;\r
-  unsigned long src_handle;\r
-  unsigned long src_x;\r
-  unsigned long src_y;\r
-  unsigned long u1;\r
-  unsigned long u2;\r
-  unsigned char u3;\r
-} osd_bitblt_t;\r
-\r
-// Surface ioctls\r
-\r
-#define GFX_FB_SFC_ALLOC  _IOWR(0xfb,1,int*)\r
-#define GFX_FB_SFC_FREE   _IOW(0xfb,2,int)\r
-#define GFX_FB_MAP    _IOWR(0xfb,3,int*)\r
-#define GFX_FB_SFC_UNMAP  _IOW(0xfb,4,int)\r
-#define GFX_FB_SET_PAL_1  _IOWR(0xfb,5,int*)\r
-#define GFX_FB_SET_PAL_2  _IOW(0xfb,6,int*)\r
-#define GFX_FB_OSD_SURFACE  _IO(0xfb,7)\r
-#define GFX_FB_SFC_SET_SHARE  _IOW(0xfb,8,int)\r
-#define GFX_FB_OSD_CUR_SETATTR  _IOW(0xfb,9,int*)\r
-#define GFX_FB_ATTACH   _IOW(0xfb,11,int)\r
-#define GFX_FB_SFC_DETACH _IOW(0xfb,12,int*)\r
-#define GFX_FB_MOVE_DISPLAY _IOWR(0xfb,13,int)\r
-#define GFX_FB_SET_DISPLAY  _IOW(0xfb,14,int)\r
-#define GFX_FB_OSD_CUR_MOVE_1 _IOW(0xfb,15,int*)\r
-#define GFX_FB_OSD_CUR_MOVE_2 _IOW(0xfb,16,int)\r
-#define GFX_FB_SET_OSD    _IOW(0xfb,18,int)\r
-#define GFX_FB_SET_DISP_CTRL  _IOW(0xfb,21,int*)\r
-#define GFX_FB_GET_DISP_CTRL  _IOWR(0xfb,22,int*)\r
-#define GFX_FB_SET_VIS_DEV_CTL  _IOWR(0xfb,23,int*)\r
-#define GFX_FB_GET_VIS_DEV_CTL  _IOWR(0xfb,24,int*)\r
-#define GFX_FB_OSD_BITBLT _IOW(0xfb,51,osd_bitblt_t*)\r
-#define GFX_FB_OSD_FILLBLT  _IOW(0xfb,53,osd_fillblt_t*)\r
-#define GFX_FB_OSD_ADVFILLBLT _IOW(0xfb,54,osd_afillblt_t*)\r
-#define GFX_FB_OSD_BLEND  _IOW(0xfb,55,int*)\r
-#define GFX_FB_OSD_ADVBLEND _IOW(0xfb,56,int*)\r
-#define GFX_FB_OSD_RESIZE _IOW(0xfb,58,int*)\r
-#define GFX_FB_ENGINE_WAIT  _IOW(0xfb,60,int)\r
-#define GFX_FB_RESET_ENGINE _IO(0xfb,61)\r
-#define GFX_FB_SET_ENGINE_MODE  _IOW(0xfb,62,int)\r
-#define GFX_FB_GET_ENGINE_MODE  _IO(0xfb,63)\r
-#define GFX_FB_GET_SFC_INFO _IO(0xfb,64,int*)\r
-#define GFX_FB_OSD_SFC_CLIP _IOW(0xfb,65,osd_clip_rec_t*)\r
-#define GFX_FB_OSD_COLOURKEY  _IOW(0xfb,67,int*)\r
-#define GFX_FB_GET_SFC_PSEUDO _IOWR(0xfb,68,int*)\r
-\r
-class SurfaceMVP : public Surface\r
-{\r
-  public:\r
-    SurfaceMVP(int id = 0);\r
-    virtual ~SurfaceMVP();\r
-\r
-    int create(UINT width, UINT height);\r
-    void display();\r
-    unsigned long getSurfaceHandle();\r
-\r
-    int fillblt(int x, int y, int width, int height, const DrawStyle& c);\r
-\r
-    void drawHorzLine(int x1, int x2, int y, const DrawStyle& c);\r
-    void drawVertLine(int x, int y1, int y2, const DrawStyle& c);\r
-    void drawBitmap(int x, int y, const Bitmap& bm, const DisplayRegion& region);\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
-\r
-    static void initConversionTables()\r
-    {\r
-      initConversionTables(100,100,100);\r
-    }\r
-    //init tables with factors for R,G,B - each in percent\r
-    static void initConversionTables(int r, int g, int b);\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
-    int fdOsd;\r
-    osd_surface_t surface;\r
-\r
-    void yuv2rgb(int y, int u, int v, unsigned char* pr, unsigned char* pg, unsigned char* pb);\r
-    /*\r
-     * rgb2yuv() - convert an RGB pixel to YUV\r
-     */\r
-    inline void rgb2yuv(unsigned char r, unsigned char g, unsigned char b, unsigned char *y, unsigned char *u, unsigned char *v)\r
-    {\r
-      int Y, U, V;\r
-\r
-      Y = conv_YB[b] + conv_YG[g] + conv_YR[r];\r
-      U = conv_UB[b] + conv_UG[g] + conv_UR[r] + 128;\r
-      V = conv_VB[b] + conv_VG[g] + conv_VR[r] + 128;\r
-\r
-      if (Y > 255)\r
-        Y = 255;\r
-      else if (Y < 0)\r
-        Y = 0;\r
-      if (U > 255)\r
-        U = 255;\r
-      else if (U < 0)\r
-        U = 0;\r
-      if (V > 255)\r
-        V = 255;\r
-      else if (V < 0)\r
-        V = 0;\r
-\r
-      *y = Y;\r
-      *u = U;\r
-      *v = V;\r
-    }\r
-\r
-\r
-    // Implicit inlines\r
-    void c2rgba(unsigned long c, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a)\r
-    {\r
-      *a = (c & 0xff000000) >> 24;\r
-      *r = (c & 0x00ff0000) >> 16;\r
-      *g = (c & 0x0000ff00) >> 8;\r
-      *b = (c & 0x000000ff);\r
-    }\r
-\r
-    static int conv_YB[256];\r
-    static int conv_YG[256];\r
-    static int conv_YR[256];\r
-    static int conv_UB[256];\r
-    static int conv_UG[256];\r
-    static int conv_UR[256];\r
-    static int conv_VB[256];\r
-    static int conv_VG[256];\r
-    static int conv_VR[256];\r
-\r
-    static int conv_BY[256];\r
-    static int conv_GY[256];\r
-    static int conv_RY[256];\r
-    static int conv_BU[256];\r
-    static int conv_GU[256];\r
-    static int conv_RU[256];\r
-    static int conv_BV[256];\r
-    static int conv_GV[256];\r
-    static int conv_RV[256];\r
-  protected:\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
-\r
-};\r
-\r
-#endif\r
+/*
+    Copyright 2004-2005 Chris Tallon
+    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 SURFACEMVP_H
+#define SURFACEMVP_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"
+
+// Structures for surface management
+
+typedef struct
+{
+  unsigned long num;
+  unsigned long unknown[4];
+  unsigned long width;
+  unsigned long height;
+  char unknown2;
+} stbgfx_display_t;
+
+typedef struct
+{
+  unsigned long unknown;
+  unsigned long win_unknown;
+  unsigned long addr;
+  unsigned long size;
+  unsigned long unknown2;
+  unsigned long width;
+  unsigned long height;
+  unsigned long unknown3;
+  unsigned long unknown4;
+  unsigned long width2;
+  unsigned long unknown5;
+  unsigned long unknown6;
+} stbgfx_map_item_t;
+
+typedef struct {
+  stbgfx_map_item_t map[3];
+  unsigned long other[2];
+} stbgfx_map_t;
+
+typedef struct
+{
+  unsigned long handle; /* surface handle */
+  unsigned long width;
+  unsigned long height;
+  unsigned long flags;
+  long unknown;   //unsigned long
+  unsigned long depth;  /* number of subplanes */
+} stbgfx_sfc_t;
+
+typedef struct
+{
+  stbgfx_display_t display;
+  stbgfx_map_t map;
+  stbgfx_sfc_t sfc;
+  unsigned char *base[3];
+} osd_surface_t;
+
+
+// Structures for surface drawing
+
+typedef struct
+{
+  unsigned long handle;
+  unsigned long x;
+  unsigned long y;
+  unsigned long width;
+  unsigned long height;
+  unsigned long colour;
+} osd_fillblt_t;
+
+typedef struct {
+  unsigned long dst_handle;
+  unsigned long dst_x;
+  unsigned long dst_y;
+  unsigned long width;
+  unsigned long height;
+  unsigned long src_handle;
+  unsigned long src_x;
+  unsigned long src_y;
+  unsigned long u1;
+  unsigned long u2;
+  unsigned char u3;
+} osd_bitblt_t;
+
+// Surface ioctls
+
+#define GFX_FB_SFC_ALLOC  _IOWR(0xfb,1,int*)
+#define GFX_FB_SFC_FREE   _IOW(0xfb,2,int)
+#define GFX_FB_MAP    _IOWR(0xfb,3,int*)
+#define GFX_FB_SFC_UNMAP  _IOW(0xfb,4,int)
+#define GFX_FB_SET_PAL_1  _IOWR(0xfb,5,int*)
+#define GFX_FB_SET_PAL_2  _IOW(0xfb,6,int*)
+#define GFX_FB_OSD_SURFACE  _IO(0xfb,7)
+#define GFX_FB_SFC_SET_SHARE  _IOW(0xfb,8,int)
+#define GFX_FB_OSD_CUR_SETATTR  _IOW(0xfb,9,int*)
+#define GFX_FB_ATTACH   _IOW(0xfb,11,int)
+#define GFX_FB_SFC_DETACH _IOW(0xfb,12,int*)
+#define GFX_FB_MOVE_DISPLAY _IOWR(0xfb,13,int)
+#define GFX_FB_SET_DISPLAY  _IOW(0xfb,14,int)
+#define GFX_FB_OSD_CUR_MOVE_1 _IOW(0xfb,15,int*)
+#define GFX_FB_OSD_CUR_MOVE_2 _IOW(0xfb,16,int)
+#define GFX_FB_SET_OSD    _IOW(0xfb,18,int)
+#define GFX_FB_SET_DISP_CTRL  _IOW(0xfb,21,int*)
+#define GFX_FB_GET_DISP_CTRL  _IOWR(0xfb,22,int*)
+#define GFX_FB_SET_VIS_DEV_CTL  _IOWR(0xfb,23,int*)
+#define GFX_FB_GET_VIS_DEV_CTL  _IOWR(0xfb,24,int*)
+#define GFX_FB_OSD_BITBLT _IOW(0xfb,51,osd_bitblt_t*)
+#define GFX_FB_OSD_FILLBLT  _IOW(0xfb,53,osd_fillblt_t*)
+#define GFX_FB_OSD_ADVFILLBLT _IOW(0xfb,54,osd_afillblt_t*)
+#define GFX_FB_OSD_BLEND  _IOW(0xfb,55,int*)
+#define GFX_FB_OSD_ADVBLEND _IOW(0xfb,56,int*)
+#define GFX_FB_OSD_RESIZE _IOW(0xfb,58,int*)
+#define GFX_FB_ENGINE_WAIT  _IOW(0xfb,60,int)
+#define GFX_FB_RESET_ENGINE _IO(0xfb,61)
+#define GFX_FB_SET_ENGINE_MODE  _IOW(0xfb,62,int)
+#define GFX_FB_GET_ENGINE_MODE  _IO(0xfb,63)
+#define GFX_FB_GET_SFC_INFO _IO(0xfb,64,int*)
+#define GFX_FB_OSD_SFC_CLIP _IOW(0xfb,65,osd_clip_rec_t*)
+#define GFX_FB_OSD_COLOURKEY  _IOW(0xfb,67,int*)
+#define GFX_FB_GET_SFC_PSEUDO _IOWR(0xfb,68,int*)
+
+class SurfaceMVP : public Surface
+{
+  public:
+    SurfaceMVP(int id = 0);
+    virtual ~SurfaceMVP();
+
+    int create(UINT width, UINT height);
+    void display();
+    unsigned long getSurfaceHandle();
+
+    int fillblt(int x, int y, int width, int height, const DrawStyle& c);
+
+    void drawHorzLine(int x1, int x2, int y, const DrawStyle& c);
+    void drawVertLine(int x, int y1, int y2, const DrawStyle& c);
+    void drawBitmap(int x, int y, const Bitmap& bm, const DisplayRegion& region);
+    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(const char* fileName);
+
+    static void initConversionTables()
+    {
+      initConversionTables(100,100,100);
+    }
+    //init tables with factors for R,G,B - each in percent
+    static void initConversionTables(int r, int g, int b);
+
+    int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy);
+
+  private:
+    int fdOsd;
+    osd_surface_t surface;
+
+    void yuv2rgb(int y, int u, int v, unsigned char* pr, unsigned char* pg, unsigned char* pb);
+    /*
+     * rgb2yuv() - convert an RGB pixel to YUV
+     */
+    inline void rgb2yuv(unsigned char r, unsigned char g, unsigned char b, unsigned char *y, unsigned char *u, unsigned char *v)
+    {
+      int Y, U, V;
+
+      Y = conv_YB[b] + conv_YG[g] + conv_YR[r];
+      U = conv_UB[b] + conv_UG[g] + conv_UR[r] + 128;
+      V = conv_VB[b] + conv_VG[g] + conv_VR[r] + 128;
+
+      if (Y > 255)
+        Y = 255;
+      else if (Y < 0)
+        Y = 0;
+      if (U > 255)
+        U = 255;
+      else if (U < 0)
+        U = 0;
+      if (V > 255)
+        V = 255;
+      else if (V < 0)
+        V = 0;
+
+      *y = Y;
+      *u = U;
+      *v = V;
+    }
+
+
+    // Implicit inlines
+    void c2rgba(unsigned long c, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a)
+    {
+      *a = (c & 0xff000000) >> 24;
+      *r = (c & 0x00ff0000) >> 16;
+      *g = (c & 0x0000ff00) >> 8;
+      *b = (c & 0x000000ff);
+    }
+
+    static int conv_YB[256];
+    static int conv_YG[256];
+    static int conv_YR[256];
+    static int conv_UB[256];
+    static int conv_UG[256];
+    static int conv_UR[256];
+    static int conv_VB[256];
+    static int conv_VG[256];
+    static int conv_VR[256];
+
+    static int conv_BY[256];
+    static int conv_GY[256];
+    static int conv_RY[256];
+    static int conv_BU[256];
+    static int conv_GU[256];
+    static int conv_RU[256];
+    static int conv_BV[256];
+    static int conv_GV[256];
+    static int conv_RV[256];
+  protected:
+    void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);
+    void drawPixel(int x, int y, Colour& c, bool fastdraw=false);
+
+};
+
+#endif
index 578fb3dab3482a25b731254e09c5c40942cdee86..c1745c03fcbb942a8bb54efa84cd8d642f62dfff 100644 (file)
-/*\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 <stdlib.h>\r
-\r
-#include "surfaceopengl.h"\r
-#include "osdopengl.h"\r
-#include "bitmap.h"\r
-#include "log.h"\r
-#include "mutex.h"\r
-\r
-inline unsigned int InternalColour(unsigned int c){\r
-       return (c &0x000000FF)<<16 |\r
-                                         (c &0x0000FF00) |\r
-                                         (c &0x00FF0000)>>16 |\r
-                                         (c &0xFF000000);\r
-}\r
-\r
-SurfaceOpenGL::SurfaceOpenGL(int id)\r
-: Surface(id)\r
-{\r
-       gltexture=0;\r
-  data=NULL;\r
-  sheight=swidth=0;\r
-//  fastdraw=false;\r
-  srf_mutex.Lock();\r
-}\r
-\r
-SurfaceOpenGL::~SurfaceOpenGL()\r
-{\r
-       srf_mutex.Lock();\r
-       if (data) {\r
-               free(data);\r
-               data=NULL;\r
-       } else {\r
-               glDeleteTextures(1,&gltexture);\r
-       }\r
-       srf_mutex.Unlock();\r
-}\r
-\r
-int SurfaceOpenGL::create(UINT width, UINT height)\r
-{\r
-       OsdOpenGL* osd=((OsdOpenGL*)(Osd::getInstance()));\r
-       //osd->BeginPainting();\r
-\r
-\r
-       if (this == screen) { // We do not need locking here, since the osd calls this\r
-\r
-               swidth=width;\r
-               sheight=height;\r
-               glGenTextures(1, &gltexture);\r
-\r
-               glBindTexture(GL_TEXTURE_2D, gltexture);\r
-\r
-               void *image = malloc(sheight * swidth * 4);\r
-               memset(image, 0, sheight * swidth * 4);\r
-       /*      for (int i=0;i< sheight * swidth * 4; i++) { //fill it with garbage, useful for debugging\r
-                       ((char*)image)[i]=i%255;\r
-               }*/\r
-               glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, swidth, sheight, 0, GL_RGBA,\r
-                               GL_UNSIGNED_BYTE, image);\r
-\r
-       } else {\r
-               sheight = height;\r
-               swidth = width;\r
-               data=(char*)malloc(sizeof(uint32_t)*width*height);\r
-       }\r
-\r
-\r
-       //osd->EndPainting();\r
-       srf_mutex.Unlock();\r
-       return 1;\r
-}\r
-\r
-void SurfaceOpenGL::display()\r
-{\r
-}\r
-\r
-int SurfaceOpenGL::fillblt(int x, int y, int width, int height, const DrawStyle& c) {\r
-       srf_mutex.Lock();\r
-       //since this might be called before surface\r
-       //allocation we will wait in this case, hopefully without deadlocks\r
-       if (screen == this || !data ) {\r
-               //This should not happen!\r
-               srf_mutex.Unlock();\r
-               return 0;\r
-\r
-       }\r
-       /*   OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
-\r
-        osd->BeginPainting();\r
-\r
-        glViewport(0,0,swidth,sheight);*/\r
-\r
-       //osd->EndPainting();\r
-       srf_mutex.Unlock();\r
-\r
-       unsigned int my_c=InternalColour(c.rgba());\r
-\r
-       int iheight=height;\r
-       if (height+y>sheight) iheight=sheight-y;\r
-       int iwidth=width;\r
-    if (width+x>swidth) iwidth=swidth-y;\r
-\r
-       unsigned int line;\r
-       unsigned int column;\r
-       for (line = y; line < (iheight + y); line++) {\r
-               uint32_t *row = ((unsigned int*) (((char*) data) + (swidth * line + x)\r
-                               * sizeof(uint32_t)));\r
-               for (column = 0; column < iwidth; column++) {\r
-                       row[column] = my_c;\r
-               }\r
-       }\r
-\r
-/*     if (d3dsurface->UnlockRect() != D3D_OK) {\r
-               osd->EndPainting();\r
-               return 0;\r
-       }\r
-       osd->EndPainting();*/\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-void SurfaceOpenGL::startFastDraw(){\r
-       srf_mutex.Lock();\r
-\r
-}\r
-void SurfaceOpenGL::endFastDraw(){\r
-       srf_mutex.Unlock();\r
- }\r
-\r
-void SurfaceOpenGL::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 SurfaceOpenGL::drawPixel(int x, int y, unsigned int c, bool fastdraw) {\r
-       //FixMe: locking for every single Pixel will be painfully slow\r
-       if (screen == this) {\r
-               //This should not happen!\r
-               return ;\r
-       }\r
-       if (!data) {\r
-               return; //why does this happen\r
-       }\r
-       //OsdWin* osd;\r
-       if (!fastdraw) {\r
-               srf_mutex.Lock(); //since this might be called before surface\r
-       }\r
-       //allocation we will wait in this case, hopefully without deadlocks\r
-\r
-       //osd = ((OsdWin*) (Osd::getInstance()));\r
-\r
-       if (x >= swidth || y >= sheight)\r
-               return; //do not draw outside the surface\r
-\r
-       unsigned int my_c=InternalColour(c);\r
-\r
-       unsigned int*row = (unsigned int*) (((char*) data + (swidth * y + x)\r
-                       * sizeof(uint32_t)));\r
-       row[0] = my_c;\r
-\r
-       if (!fastdraw) {\r
-               srf_mutex.Unlock(); //since this might be called before surface\r
-       }\r
-\r
-}\r
-\r
-void SurfaceOpenGL::drawHorzLine(int x1, int x2, int y, const DrawStyle& c)\r
-{\r
-   fillblt(x1, y, x2-x1, 1, c);\r
-}\r
-\r
-void SurfaceOpenGL::drawVertLine(int x, int y1, int y2, const DrawStyle& c)\r
-{\r
-  fillblt(x, y1, 1, y2-y1, c);\r
-}\r
-\r
-void SurfaceOpenGL::drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegion & region) //region should not matter for SD\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 SurfaceOpenGL::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME\r
-{\r
-//     Log::getInstance()->log("Surface", Log::WARN, "UTS Mark1");\r
-       srf_mutex.Lock();//since this might be called before surface\r
-  //allocation we will wait in this case, hopefully without deadlocks\r
-\r
-  OsdOpenGL* osd=((OsdOpenGL*)(Osd::getInstance()));\r
- // Log::getInstance()->log("Surface", Log::WARN, "UTS Mark2");\r
-  GLuint screengltexture=((SurfaceOpenGL*)screen)->getTexture();\r
-\r
-  osd->BeginPainting();\r
- // Log::getInstance()->log("Surface", Log::WARN, "UTS Mark3");\r
-  glBindTexture(GL_TEXTURE_2D, screengltexture);\r
-//  Log::getInstance()->log("Surface", Log::WARN, "UTS Mark4 %d",glGetError());\r
-\r
-  for (int y=0;y<h;y++) { //hopefully this is not too slow\r
-        // Log::getInstance()->log("Surface", Log::WARN, "UTS Mark4a %d %d %d %d %d %d",sx,sy,w,h,dx,dy);\r
-         glTexSubImage2D(GL_TEXTURE_2D,0,dx,(dy+y),w,1,GL_RGBA,GL_UNSIGNED_BYTE,\r
-                         data+((y+sy)*swidth+sx)*sizeof(uint32_t));\r
-\r
-\r
-  }\r
-\r
-  osd->EndPainting();\r
-\r
-  srf_mutex.Unlock();\r
-\r
-  return 0;\r
-}\r
-\r
-int SurfaceOpenGL::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 SurfaceOpenGL::screenShot(const char* fileName)\r
-{\r
-  //Isn't this for debugging only, so I won't implement it yet\r
-}\r
-\r
-void SurfaceOpenGL::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
-\r
-\r
-void SurfaceOpenGL::drawJpeg(const char *fileName,int x, int y,int *width, int *height){\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 ; //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 SurfaceOpenGL::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.
+*/
+
+#include <stdlib.h>
+
+#include "surfaceopengl.h"
+#include "osdopengl.h"
+#include "bitmap.h"
+#include "log.h"
+#include "mutex.h"
+
+inline unsigned int InternalColour(unsigned int c){
+       return (c &0x000000FF)<<16 |
+                                         (c &0x0000FF00) |
+                                         (c &0x00FF0000)>>16 |
+                                         (c &0xFF000000);
+}
+
+SurfaceOpenGL::SurfaceOpenGL(int id)
+: Surface(id)
+{
+       gltexture=0;
+  data=NULL;
+  sheight=swidth=0;
+//  fastdraw=false;
+  srf_mutex.Lock();
+}
+
+SurfaceOpenGL::~SurfaceOpenGL()
+{
+       srf_mutex.Lock();
+       if (data) {
+               free(data);
+               data=NULL;
+       } else {
+               glDeleteTextures(1,&gltexture);
+       }
+       srf_mutex.Unlock();
+}
+
+int SurfaceOpenGL::create(UINT width, UINT height)
+{
+       OsdOpenGL* osd=((OsdOpenGL*)(Osd::getInstance()));
+       //osd->BeginPainting();
+
+
+       if (this == screen) { // We do not need locking here, since the osd calls this
+
+               swidth=width;
+               sheight=height;
+               glGenTextures(1, &gltexture);
+
+               glBindTexture(GL_TEXTURE_2D, gltexture);
+
+               void *image = malloc(sheight * swidth * 4);
+               memset(image, 0, sheight * swidth * 4);
+       /*      for (int i=0;i< sheight * swidth * 4; i++) { //fill it with garbage, useful for debugging
+                       ((char*)image)[i]=i%255;
+               }*/
+               glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, swidth, sheight, 0, GL_RGBA,
+                               GL_UNSIGNED_BYTE, image);
+
+       } else {
+               sheight = height;
+               swidth = width;
+               data=(char*)malloc(sizeof(uint32_t)*width*height);
+       }
+
+
+       //osd->EndPainting();
+       srf_mutex.Unlock();
+       return 1;
+}
+
+void SurfaceOpenGL::display()
+{
+}
+
+int SurfaceOpenGL::fillblt(int x, int y, int width, int height, const DrawStyle& c) {
+       srf_mutex.Lock();
+       //since this might be called before surface
+       //allocation we will wait in this case, hopefully without deadlocks
+       if (screen == this || !data ) {
+               //This should not happen!
+               srf_mutex.Unlock();
+               return 0;
+
+       }
+       /*   OsdWin* osd=((OsdWin*)(Osd::getInstance()));
+
+        osd->BeginPainting();
+
+        glViewport(0,0,swidth,sheight);*/
+
+       //osd->EndPainting();
+       srf_mutex.Unlock();
+
+       unsigned int my_c=InternalColour(c.rgba());
+
+       int iheight=height;
+       if (height+y>sheight) iheight=sheight-y;
+       int iwidth=width;
+    if (width+x>swidth) iwidth=swidth-y;
+
+       unsigned int line;
+       unsigned int column;
+       for (line = y; line < (iheight + y); line++) {
+               uint32_t *row = ((unsigned int*) (((char*) data) + (swidth * line + x)
+                               * sizeof(uint32_t)));
+               for (column = 0; column < iwidth; column++) {
+                       row[column] = my_c;
+               }
+       }
+
+/*     if (d3dsurface->UnlockRect() != D3D_OK) {
+               osd->EndPainting();
+               return 0;
+       }
+       osd->EndPainting();*/
+
+       return 0;
+}
+
+
+void SurfaceOpenGL::startFastDraw(){
+       srf_mutex.Lock();
+
+}
+void SurfaceOpenGL::endFastDraw(){
+       srf_mutex.Unlock();
+ }
+
+void SurfaceOpenGL::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 SurfaceOpenGL::drawPixel(int x, int y, unsigned int c, bool fastdraw) {
+       //FixMe: locking for every single Pixel will be painfully slow
+       if (screen == this) {
+               //This should not happen!
+               return ;
+       }
+       if (!data) {
+               return; //why does this happen
+       }
+       //OsdWin* osd;
+       if (!fastdraw) {
+               srf_mutex.Lock(); //since this might be called before surface
+       }
+       //allocation we will wait in this case, hopefully without deadlocks
+
+       //osd = ((OsdWin*) (Osd::getInstance()));
+
+       if (x >= swidth || y >= sheight)
+               return; //do not draw outside the surface
+
+       unsigned int my_c=InternalColour(c);
+
+       unsigned int*row = (unsigned int*) (((char*) data + (swidth * y + x)
+                       * sizeof(uint32_t)));
+       row[0] = my_c;
+
+       if (!fastdraw) {
+               srf_mutex.Unlock(); //since this might be called before surface
+       }
+
+}
+
+void SurfaceOpenGL::drawHorzLine(int x1, int x2, int y, const DrawStyle& c)
+{
+   fillblt(x1, y, x2-x1, 1, c);
+}
+
+void SurfaceOpenGL::drawVertLine(int x, int y1, int y2, const DrawStyle& c)
+{
+  fillblt(x, y1, 1, y2-y1, c);
+}
+
+void SurfaceOpenGL::drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegion & region) //region should not matter for SD
+{
+  // 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 SurfaceOpenGL::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME
+{
+//     Log::getInstance()->log("Surface", Log::WARN, "UTS Mark1");
+       srf_mutex.Lock();//since this might be called before surface
+  //allocation we will wait in this case, hopefully without deadlocks
+
+  OsdOpenGL* osd=((OsdOpenGL*)(Osd::getInstance()));
+ // Log::getInstance()->log("Surface", Log::WARN, "UTS Mark2");
+  GLuint screengltexture=((SurfaceOpenGL*)screen)->getTexture();
+
+  osd->BeginPainting();
+ // Log::getInstance()->log("Surface", Log::WARN, "UTS Mark3");
+  glBindTexture(GL_TEXTURE_2D, screengltexture);
+//  Log::getInstance()->log("Surface", Log::WARN, "UTS Mark4 %d",glGetError());
+
+  for (int y=0;y<h;y++) { //hopefully this is not too slow
+        // Log::getInstance()->log("Surface", Log::WARN, "UTS Mark4a %d %d %d %d %d %d",sx,sy,w,h,dx,dy);
+         glTexSubImage2D(GL_TEXTURE_2D,0,dx,(dy+y),w,1,GL_RGBA,GL_UNSIGNED_BYTE,
+                         data+((y+sy)*swidth+sx)*sizeof(uint32_t));
+
+
+  }
+
+  osd->EndPainting();
+
+  srf_mutex.Unlock();
+
+  return 0;
+}
+
+int SurfaceOpenGL::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 SurfaceOpenGL::screenShot(const char* fileName)
+{
+  //Isn't this for debugging only, so I won't implement it yet
+}
+
+void SurfaceOpenGL::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 SurfaceOpenGL::drawJpeg(const char *fileName,int x, int y,int *width, int *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 SurfaceOpenGL::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;
+
+}*/
+
index 81d0809ad05ca93bc0a69dfce16e549c661a4766..88ba56a4004dcf953ac6876ab0201d7e75115c39 100644 (file)
@@ -1,72 +1,72 @@
-/*\r
-    Copyright 2006, 2011-2012 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 SURFACEOPENGL_H\r
-#define SURFACEOPENGL_H\r
-\r
-#include "defines.h"\r
-#include "surface.h"\r
-#include "mutex.h"\r
-#include <GLES2/gl2.h>\r
-\r
-class SurfaceOpenGL : public Surface\r
-{\r
-  public:\r
-    SurfaceOpenGL(int id = 0);\r
-    virtual ~SurfaceOpenGL();\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, const DrawStyle& c);\r
-\r
-    void drawHorzLine(int x1, int x2, int y, const DrawStyle& c);\r
-    void drawVertLine(int x, int y1, int y2, const DrawStyle& c);\r
-    void drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegion & region);\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
-\r
-    GLuint getTexture() {return gltexture;};\r
-\r
-\r
-\r
-  private:\r
-    GLuint  gltexture;\r
-    UINT sheight,swidth;\r
-    char * data;\r
-\r
-\r
-\r
-    Mutex srf_mutex;\r
-  protected:\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
-\r
-};\r
-\r
-#endif\r
+/*
+    Copyright 2006, 2011-2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef SURFACEOPENGL_H
+#define SURFACEOPENGL_H
+
+#include "defines.h"
+#include "surface.h"
+#include "mutex.h"
+#include <GLES2/gl2.h>
+
+class SurfaceOpenGL : public Surface
+{
+  public:
+    SurfaceOpenGL(int id = 0);
+    virtual ~SurfaceOpenGL();
+
+    int create(UINT width, UINT height);
+    void display();
+
+    void startFastDraw();
+    void endFastDraw();
+
+    int fillblt(int x, int y, int width, int height, const DrawStyle& c);
+
+    void drawHorzLine(int x1, int x2, int y, const DrawStyle& c);
+    void drawVertLine(int x, int y1, int y2, const DrawStyle& c);
+    void drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegion & region);
+    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(const 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(const char *fileName,int x, int y,int *width, int *height);
+/*  void drawJpeg(char *buffer,ULONG buflength,DWORD x, DWORD y,DWORD *width, DWORD *height);*/
+
+    GLuint getTexture() {return gltexture;};
+
+
+
+  private:
+    GLuint  gltexture;
+    UINT sheight,swidth;
+    char * data;
+
+
+
+    Mutex srf_mutex;
+  protected:
+    void drawPixel(int x, int y, Colour& c, bool fastdraw=false);
+    void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);
+
+};
+
+#endif
index 6203c472a11fab6d550162d7797f9eda0893d329..aa2cc7b89fe835bd20d3492971fec099d25343e8 100644 (file)
-/*\r
-    Copyright 2012 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 "surfacevector.h"\r
-#include "bitmap.h"\r
-#include <wchar.h>\r
-#include <stdlib.h>\r
-\r
-SurfaceVector::SurfaceVector(OsdVector* vosd)\r
-{\r
-\r
-       osd=vosd;\r
-}\r
-\r
-SurfaceVector::~SurfaceVector()\r
-{\r
-       osd->removeSurface(this);\r
-       list<SVGCommand>::iterator itty=commands.begin();\r
-       while (itty!=commands.end())\r
-       {\r
-               osd->removeStyleRef((*itty).getRef()); // We remove the Style reference, so that osd can free stuff\r
-               ImageIndex ii=(*itty).getImageIndex();\r
-               if (ii) osd->removeImageRef(ii);\r
-               itty++;\r
-       }\r
-}\r
-\r
-\r
-int SurfaceVector::getFontHeight()\r
-{\r
-       return osd->getFontHeight();\r
-}\r
-\r
-float SurfaceVector::getCharWidth(wchar_t c)\r
-{\r
-       return osd->getCharWidth(c);\r
-}\r
-\r
-wchar_t SurfaceVector::getWChar(const char* str, unsigned int *length)\r
-{\r
-       int mlength=0;\r
-       int max_length=4;\r
-       wchar_t tempo[1];\r
-       size_t num_bytes=1;\r
-       if (str[0]=='\0') {\r
-               *length=1;\r
-               return '\0';\r
-       } else if (str[1]=='\0'){\r
-               max_length=2;\r
-       } else if (str[2]=='\0'){\r
-               max_length=3;\r
-       }\r
-       mbstate_t state;\r
-       memset((void*)&state,0,sizeof(state));\r
-       num_bytes=mbrtowc(tempo, str, max_length, &state);\r
-       if (num_bytes!=((size_t) -1) && num_bytes!=((size_t) -2))\r
-       {\r
-               *length=num_bytes;\r
-               return *tempo;\r
-       }\r
-       *length=1;\r
-       return '?';\r
-}\r
-\r
-\r
-int SurfaceVector::drawText(const char* text, int x, int y, const DrawStyle& c){\r
-       return drawText(text, x, y, 0, c);\r
-}\r
-\r
-int SurfaceVector::drawText(const char* text, int x, int y, int width, const DrawStyle& c)\r
-{\r
-       float shift=0.;\r
-       const char *run=text;\r
-       mbstate_t state;\r
-       wchar_t tempo[1];\r
-       size_t num_bytes=1;\r
-       size_t length=strlen(text);\r
-       memset((void*)&state,0,sizeof(state));\r
-       command_mutex.Lock();\r
-       num_bytes=mbrtowc(tempo, run, length, &state);\r
-       while (num_bytes!=((size_t) -1) && num_bytes!=((size_t) -2) && length>0)\r
-       {\r
-               unsigned int ref=osd->getStyleRef(c);\r
-               commands.push_back(SVGCommand(x+shift,y,*tempo,ref));\r
-               shift+=osd->getCharWidth(*tempo);\r
-               length -= num_bytes;\r
-               run += num_bytes;\r
-               if (shift>width && width >0) {\r
-                       command_mutex.Unlock();\r
-                       return 1;\r
-               }\r
-               num_bytes=mbrtowc(tempo, run, length, &state);\r
-       }\r
-       command_mutex.Unlock();\r
-       return 1;\r
-\r
-}\r
-int SurfaceVector::drawTextRJ(const char* text, int x, int y, const DrawStyle& c)\r
-{\r
-       float shift=0.;\r
-       const char *run=text;\r
-       mbstate_t state;\r
-       wchar_t tempo[1];\r
-       size_t num_bytes=1;\r
-       size_t length=strlen(text);\r
-       memset((void*)&state,0,sizeof(state));\r
-\r
-       num_bytes=mbrtowc(tempo, run, length, &state);\r
-       while (num_bytes!=((size_t) -1) && num_bytes!=((size_t) -2) && length>0)\r
-       {\r
-               shift+=osd->getCharWidth(*tempo);\r
-               length -= num_bytes;\r
-               run += num_bytes;\r
-               num_bytes=mbrtowc(tempo, run, length, &state);\r
-       }\r
-       return drawText(text, x-shift,  y, c);\r
-}\r
-\r
-int SurfaceVector::drawTextCentre(const char* text, int x, int y, const DrawStyle& c)\r
-{\r
-       float shift=0;\r
-       const char *run=text;\r
-       mbstate_t state;\r
-       wchar_t tempo[1];\r
-       size_t num_bytes=1;\r
-       size_t length=strlen(text);\r
-       memset((void*)&state,0,sizeof(state));\r
-\r
-       num_bytes=mbrtowc(tempo, run, length, &state);\r
-       while (num_bytes!=((size_t) -1) && num_bytes!=((size_t) -2) && length>0)\r
-       {\r
-               shift+=osd->getCharWidth(*tempo);\r
-               length -= num_bytes;\r
-               run += num_bytes;\r
-               num_bytes=mbrtowc(tempo, run, length, &state);\r
-       }\r
-       return drawText(text, x-shift/2.,  y, c);\r
-}\r
-\r
-void SurfaceVector::drawJpeg(const char *fileName,int x, int y,int *width, int *height)\r
-{\r
-       command_mutex.Lock();\r
-       ImageIndex image=osd->getJpegRef(fileName,width,height);\r
-       commands.push_back(SVGCommand(x,y,*width,*height,image,0));\r
-       command_mutex.Unlock();\r
-}\r
-\r
-int SurfaceVector::create(UINT width, UINT height)\r
-{\r
-       sheight=height;\r
-       swidth=width;\r
-       return 1;\r
-}\r
-void SurfaceVector::display()\r
-{\r
-       //nothing this is really mvp specific\r
-}\r
-\r
-int SurfaceVector::fillblt(int x, int y, int width, int height, const DrawStyle& c)\r
-{\r
-       command_mutex.Lock();\r
-       removeCommands(x,y,width,height); // remove commands below the box\r
-       unsigned int ref=osd->getStyleRef(c);\r
-       commands.push_back(SVGCommand(x,y,width,height,Rectangle,ref));\r
-       command_mutex.Unlock();\r
-       return 1;\r
-\r
-}\r
-void SurfaceVector::drawHorzLine(int x1, int x2, int y, const DrawStyle& c)\r
-{\r
-       command_mutex.Lock();\r
-       unsigned int ref=osd->getStyleRef(c);\r
-       commands.push_back(SVGCommand(x1,y,x2-x1,1,HorzLine,ref));\r
-       command_mutex.Unlock();\r
-}\r
-\r
-void SurfaceVector::drawVertLine(int x, int y1, int y2, const DrawStyle& c){\r
-       command_mutex.Lock();\r
-       unsigned int ref=osd->getStyleRef(c);\r
-       commands.push_back(SVGCommand(x,y1,1,y2-y1,VertLine,ref));\r
-       command_mutex.Unlock();\r
-}\r
-\r
-void SurfaceVector::drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegion & region)\r
-{\r
-       //this is complicated\r
-       command_mutex.Lock();\r
-/*\r
-       unsigned int * data=(unsigned int*)malloc(sizeof(unsigned int)*bm.getWidth()*bm.getHeight());\r
-       for (UINT j = 0; j < bm.getHeight(); ++j){\r
-          for (UINT i = 0; i < bm.getWidth(); ++i)\r
-          {\r
-                  data[i+j*bm.getHeight()]=bm.getColour(i,j);\r
-          }\r
-    }*/\r
-       ImageIndex image=osd->getImagePalette(bm.getWidth(),bm.getHeight(),&(bm.rawData()[0]),\r
-                       (const unsigned int*)&bm.palette.getColourVector()[0]); // data is freed by the OSD\r
-       //free(data);\r
-       float tx=x+region.windowx;\r
-       float ty=y+region.windowy;\r
-       float th=bm.getHeight();\r
-       float tw=bm.getWidth();\r
-\r
-       float scalex=720.f/((float) (region.framewidth+1));\r
-       float scaley=576.f/((float) (region.frameheight+1));\r
-       tx*=scalex;\r
-       ty*=scaley;\r
-       tw*=scalex;\r
-       th*=scaley;\r
-       SVGCommand temp=SVGCommand(tx,ty,tw,th,image,0);\r
-       commands.push_back(temp);\r
-       command_mutex.Unlock();\r
-}\r
-\r
-void SurfaceVector::drawPoint(int x, int y, DrawStyle& c, bool fastdraw){\r
-       if (!fastdraw) command_mutex.Lock();\r
-       unsigned int ref=osd->getStyleRef(c);\r
-       commands.push_back(SVGCommand(x,y,1,1,Point,ref));\r
-       if (!fastdraw)  command_mutex.Unlock();\r
-}\r
-void SurfaceVector::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,unsigned int width, Colour& nextColour)\r
-{\r
-       command_mutex.Lock();\r
-       ImageIndex image=osd->getMonoBitmapRef(base,width,height);\r
-       unsigned int ref=osd->getColorRef(nextColour);\r
-       commands.push_back(SVGCommand(dx,dy,height,width,image,ref));\r
-       command_mutex.Unlock();\r
-}\r
-\r
-\r
-int SurfaceVector::removeCommands(float x,float y,float width,float height)\r
-{\r
-       // we iterate through all old commands in order to remove commands hidden by this rectangle\r
-       list<SVGCommand>::iterator itty=commands.begin();\r
-       while (itty!=commands.end())\r
-       {\r
-               if ((*itty).Test(x,y,width,height) ) {\r
-                       osd->removeStyleRef((*itty).getRef()); // We remove the Style reference, so that osd can free stuff\r
-                       ImageIndex ii=(*itty).getImageIndex();\r
-                       if (ii) osd->removeImageRef(ii);\r
-                       itty=commands.erase(itty);\r
-               } else {\r
-                       itty++;\r
-               }\r
-       }\r
-       return 1;\r
-\r
-}\r
-\r
-int SurfaceVector::updateToScreen(int sx, int sy, int w, int h, int dx, int dy)\r
-{\r
-       // ok this method really works in a pixel oriented way\r
-       command_mutex.Lock();\r
-       osd->updateOrAddSurface(this,dx-sx,dy-sy,swidth,sheight,commands);\r
-       command_mutex.Unlock();\r
-       return 1;\r
-}\r
-\r
-\r
-/* This is for systems which need a locking of the drawing surface to speed up drawing */\r
-void SurfaceVector::startFastDraw() {\r
-       command_mutex.Lock();\r
-}\r
-void SurfaceVector::endFastDraw() {\r
-       command_mutex.Unlock();\r
-}\r
-\r
-\r
-void SurfaceVector::drawTTChar(int ox, int oy,int x, int y, cTeletextChar c)\r
-{\r
-       command_mutex.Lock();\r
-       list<SVGCommand>::iterator itty=commands.begin();\r
-       while (itty!=commands.end())\r
-       {\r
-               if ((*itty).TTTest(ox,oy,x,y) ) {\r
-                       itty=commands.erase(itty);\r
-                       break;\r
-               } else {\r
-                       itty++;\r
-               }\r
-       }\r
-       commands.push_back(SVGCommand(ox,oy,x,y,c.getInternal()));\r
-       command_mutex.Unlock();\r
-}\r
+/*
+    Copyright 2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#include "surfacevector.h"
+#include "bitmap.h"
+#include <wchar.h>
+#include <stdlib.h>
+
+SurfaceVector::SurfaceVector(OsdVector* vosd)
+{
+
+       osd=vosd;
+}
+
+SurfaceVector::~SurfaceVector()
+{
+       osd->removeSurface(this);
+       list<SVGCommand>::iterator itty=commands.begin();
+       while (itty!=commands.end())
+       {
+               osd->removeStyleRef((*itty).getRef()); // We remove the Style reference, so that osd can free stuff
+               ImageIndex ii=(*itty).getImageIndex();
+               if (ii) osd->removeImageRef(ii);
+               itty++;
+       }
+}
+
+
+int SurfaceVector::getFontHeight()
+{
+       return osd->getFontHeight();
+}
+
+float SurfaceVector::getCharWidth(wchar_t c)
+{
+       return osd->getCharWidth(c);
+}
+
+wchar_t SurfaceVector::getWChar(const char* str, unsigned int *length)
+{
+       int mlength=0;
+       int max_length=4;
+       wchar_t tempo[1];
+       size_t num_bytes=1;
+       if (str[0]=='\0') {
+               *length=1;
+               return '\0';
+       } else if (str[1]=='\0'){
+               max_length=2;
+       } else if (str[2]=='\0'){
+               max_length=3;
+       }
+       mbstate_t state;
+       memset((void*)&state,0,sizeof(state));
+       num_bytes=mbrtowc(tempo, str, max_length, &state);
+       if (num_bytes!=((size_t) -1) && num_bytes!=((size_t) -2))
+       {
+               *length=num_bytes;
+               return *tempo;
+       }
+       *length=1;
+       return '?';
+}
+
+
+int SurfaceVector::drawText(const char* text, int x, int y, const DrawStyle& c){
+       return drawText(text, x, y, 0, c);
+}
+
+int SurfaceVector::drawText(const char* text, int x, int y, int width, const DrawStyle& c)
+{
+       float shift=0.;
+       const char *run=text;
+       mbstate_t state;
+       wchar_t tempo[1];
+       size_t num_bytes=1;
+       size_t length=strlen(text);
+       memset((void*)&state,0,sizeof(state));
+       command_mutex.Lock();
+       num_bytes=mbrtowc(tempo, run, length, &state);
+       while (num_bytes!=((size_t) -1) && num_bytes!=((size_t) -2) && length>0)
+       {
+               unsigned int ref=osd->getStyleRef(c);
+               commands.push_back(SVGCommand(x+shift,y,*tempo,ref));
+               shift+=osd->getCharWidth(*tempo);
+               length -= num_bytes;
+               run += num_bytes;
+               if (shift>width && width >0) {
+                       command_mutex.Unlock();
+                       return 1;
+               }
+               num_bytes=mbrtowc(tempo, run, length, &state);
+       }
+       command_mutex.Unlock();
+       return 1;
+
+}
+int SurfaceVector::drawTextRJ(const char* text, int x, int y, const DrawStyle& c)
+{
+       float shift=0.;
+       const char *run=text;
+       mbstate_t state;
+       wchar_t tempo[1];
+       size_t num_bytes=1;
+       size_t length=strlen(text);
+       memset((void*)&state,0,sizeof(state));
+
+       num_bytes=mbrtowc(tempo, run, length, &state);
+       while (num_bytes!=((size_t) -1) && num_bytes!=((size_t) -2) && length>0)
+       {
+               shift+=osd->getCharWidth(*tempo);
+               length -= num_bytes;
+               run += num_bytes;
+               num_bytes=mbrtowc(tempo, run, length, &state);
+       }
+       return drawText(text, x-shift,  y, c);
+}
+
+int SurfaceVector::drawTextCentre(const char* text, int x, int y, const DrawStyle& c)
+{
+       float shift=0;
+       const char *run=text;
+       mbstate_t state;
+       wchar_t tempo[1];
+       size_t num_bytes=1;
+       size_t length=strlen(text);
+       memset((void*)&state,0,sizeof(state));
+
+       num_bytes=mbrtowc(tempo, run, length, &state);
+       while (num_bytes!=((size_t) -1) && num_bytes!=((size_t) -2) && length>0)
+       {
+               shift+=osd->getCharWidth(*tempo);
+               length -= num_bytes;
+               run += num_bytes;
+               num_bytes=mbrtowc(tempo, run, length, &state);
+       }
+       return drawText(text, x-shift/2.,  y, c);
+}
+
+void SurfaceVector::drawJpeg(const char *fileName,int x, int y,int *width, int *height)
+{
+       command_mutex.Lock();
+       ImageIndex image=osd->getJpegRef(fileName,width,height);
+       commands.push_back(SVGCommand(x,y,*width,*height,image,0));
+       command_mutex.Unlock();
+}
+
+int SurfaceVector::create(UINT width, UINT height)
+{
+       sheight=height;
+       swidth=width;
+       return 1;
+}
+void SurfaceVector::display()
+{
+       //nothing this is really mvp specific
+}
+
+int SurfaceVector::fillblt(int x, int y, int width, int height, const DrawStyle& c)
+{
+       command_mutex.Lock();
+       removeCommands(x,y,width,height); // remove commands below the box
+       unsigned int ref=osd->getStyleRef(c);
+       commands.push_back(SVGCommand(x,y,width,height,Rectangle,ref));
+       command_mutex.Unlock();
+       return 1;
+
+}
+void SurfaceVector::drawHorzLine(int x1, int x2, int y, const DrawStyle& c)
+{
+       command_mutex.Lock();
+       unsigned int ref=osd->getStyleRef(c);
+       commands.push_back(SVGCommand(x1,y,x2-x1,1,HorzLine,ref));
+       command_mutex.Unlock();
+}
+
+void SurfaceVector::drawVertLine(int x, int y1, int y2, const DrawStyle& c){
+       command_mutex.Lock();
+       unsigned int ref=osd->getStyleRef(c);
+       commands.push_back(SVGCommand(x,y1,1,y2-y1,VertLine,ref));
+       command_mutex.Unlock();
+}
+
+void SurfaceVector::drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegion & region)
+{
+       //this is complicated
+       command_mutex.Lock();
+/*
+       unsigned int * data=(unsigned int*)malloc(sizeof(unsigned int)*bm.getWidth()*bm.getHeight());
+       for (UINT j = 0; j < bm.getHeight(); ++j){
+          for (UINT i = 0; i < bm.getWidth(); ++i)
+          {
+                  data[i+j*bm.getHeight()]=bm.getColour(i,j);
+          }
+    }*/
+       ImageIndex image=osd->getImagePalette(bm.getWidth(),bm.getHeight(),&(bm.rawData()[0]),
+                       (const unsigned int*)&bm.palette.getColourVector()[0]); // data is freed by the OSD
+       //free(data);
+       float tx=x+region.windowx;
+       float ty=y+region.windowy;
+       float th=bm.getHeight();
+       float tw=bm.getWidth();
+
+       float scalex=720.f/((float) (region.framewidth+1));
+       float scaley=576.f/((float) (region.frameheight+1));
+       tx*=scalex;
+       ty*=scaley;
+       tw*=scalex;
+       th*=scaley;
+       SVGCommand temp=SVGCommand(tx,ty,tw,th,image,0);
+       commands.push_back(temp);
+       command_mutex.Unlock();
+}
+
+void SurfaceVector::drawPoint(int x, int y, DrawStyle& c, bool fastdraw){
+       if (!fastdraw) command_mutex.Lock();
+       unsigned int ref=osd->getStyleRef(c);
+       commands.push_back(SVGCommand(x,y,1,1,Point,ref));
+       if (!fastdraw)  command_mutex.Unlock();
+}
+void SurfaceVector::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,unsigned int width, Colour& nextColour)
+{
+       command_mutex.Lock();
+       ImageIndex image=osd->getMonoBitmapRef(base,width,height);
+       unsigned int ref=osd->getColorRef(nextColour);
+       commands.push_back(SVGCommand(dx,dy,height,width,image,ref));
+       command_mutex.Unlock();
+}
+
+
+int SurfaceVector::removeCommands(float x,float y,float width,float height)
+{
+       // we iterate through all old commands in order to remove commands hidden by this rectangle
+       list<SVGCommand>::iterator itty=commands.begin();
+       while (itty!=commands.end())
+       {
+               if ((*itty).Test(x,y,width,height) ) {
+                       osd->removeStyleRef((*itty).getRef()); // We remove the Style reference, so that osd can free stuff
+                       ImageIndex ii=(*itty).getImageIndex();
+                       if (ii) osd->removeImageRef(ii);
+                       itty=commands.erase(itty);
+               } else {
+                       itty++;
+               }
+       }
+       return 1;
+
+}
+
+int SurfaceVector::updateToScreen(int sx, int sy, int w, int h, int dx, int dy)
+{
+       // ok this method really works in a pixel oriented way
+       command_mutex.Lock();
+       osd->updateOrAddSurface(this,dx-sx,dy-sy,swidth,sheight,commands);
+       command_mutex.Unlock();
+       return 1;
+}
+
+
+/* This is for systems which need a locking of the drawing surface to speed up drawing */
+void SurfaceVector::startFastDraw() {
+       command_mutex.Lock();
+}
+void SurfaceVector::endFastDraw() {
+       command_mutex.Unlock();
+}
+
+
+void SurfaceVector::drawTTChar(int ox, int oy,int x, int y, cTeletextChar c)
+{
+       command_mutex.Lock();
+       list<SVGCommand>::iterator itty=commands.begin();
+       while (itty!=commands.end())
+       {
+               if ((*itty).TTTest(ox,oy,x,y) ) {
+                       itty=commands.erase(itty);
+                       break;
+               } else {
+                       itty++;
+               }
+       }
+       commands.push_back(SVGCommand(ox,oy,x,y,c.getInternal()));
+       command_mutex.Unlock();
+}
index 51a82a6c5ff10988606b59dbe2be4a83dd6b7bcc..76a882ff31fe629e6b2492a01416ecf506ef0edf 100644 (file)
@@ -1,93 +1,93 @@
-/*\r
-    Copyright 2012 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 SURFACEVECTOR_H\r
-#define SURFACEVECTOR_H\r
-\r
-#include "surface.h"\r
-#include "osdvector.h"\r
-\r
-#include <list>\r
-\r
-\r
-class SurfaceVector : public Surface\r
-{\r
-  public:\r
-    SurfaceVector(OsdVector* vosd);\r
-    virtual ~SurfaceVector();\r
-\r
-    int getFontHeight();\r
-    float getCharWidth(wchar_t c);\r
-    wchar_t getWChar(const char* str, unsigned int *length);\r
-\r
-    int drawText(const char* text, int x, int y, const DrawStyle& c);\r
-    int drawText(const char* text, int x, int y, int width, const DrawStyle& c);\r
-    int drawTextRJ(const char* text, int x, int y, const DrawStyle& c);\r
-    int drawTextCentre(const char* text, int x, int y, const DrawStyle& c);\r
-\r
-    void drawJpeg(const char *fileName,int x, int y,int *width, int *height);\r
-\r
-    int create(UINT width, UINT height);\r
-    void display();\r
-\r
-    int fillblt(int x, int y, int width, int height, const DrawStyle& c);\r
-    void drawHorzLine(int x1, int x2, int y, const DrawStyle& c);\r
-    void drawVertLine(int x, int y1, int y2, const DrawStyle& c);\r
-    void drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegion & region);\r
-    void drawPoint(int x, int y, DrawStyle& c, bool fastdraw=false); // This draws a point, must not be a pixel\r
-    void drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,unsigned int width, Colour& nextColour);\r
-    int updateToScreen(int sx, int sy, int w, int h, int dx, int dy);\r
-\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
-\r
-    void drawTTChar(int ox, int oy,int x, int y, cTeletextChar c);\r
-\r
-    void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b){};\r
-    void screenShot(const char* fileName){};\r
-\r
-  protected:\r
-\r
-\r
-    int removeCommands(float x,float y,float width,float height);\r
-\r
-    list<SVGCommand> commands;\r
-    int swidth, sheight;\r
-    Mutex command_mutex;\r
-    OsdVector* osd;\r
-\r
-    void drawPixel(int x, int y, unsigned int c, bool fastdraw){}; // these are not supported!\r
-    void drawPixel(int x, int y, Colour& c, bool fastdraw){};\r
-\r
-\r
-};\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-#endif\r
+/*
+    Copyright 2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef SURFACEVECTOR_H
+#define SURFACEVECTOR_H
+
+#include "surface.h"
+#include "osdvector.h"
+
+#include <list>
+
+
+class SurfaceVector : public Surface
+{
+  public:
+    SurfaceVector(OsdVector* vosd);
+    virtual ~SurfaceVector();
+
+    int getFontHeight();
+    float getCharWidth(wchar_t c);
+    wchar_t getWChar(const char* str, unsigned int *length);
+
+    int drawText(const char* text, int x, int y, const DrawStyle& c);
+    int drawText(const char* text, int x, int y, int width, const DrawStyle& c);
+    int drawTextRJ(const char* text, int x, int y, const DrawStyle& c);
+    int drawTextCentre(const char* text, int x, int y, const DrawStyle& c);
+
+    void drawJpeg(const char *fileName,int x, int y,int *width, int *height);
+
+    int create(UINT width, UINT height);
+    void display();
+
+    int fillblt(int x, int y, int width, int height, const DrawStyle& c);
+    void drawHorzLine(int x1, int x2, int y, const DrawStyle& c);
+    void drawVertLine(int x, int y1, int y2, const DrawStyle& c);
+    void drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegion & region);
+    void drawPoint(int x, int y, DrawStyle& c, bool fastdraw=false); // This draws a point, must not be a pixel
+    void drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,unsigned int width, Colour& nextColour);
+    int updateToScreen(int sx, int sy, int w, int h, int dx, int dy);
+
+
+    /* This is for system which need a locking of the drawing surface to speed up drawing */
+    void startFastDraw();
+    void endFastDraw() ;
+
+
+    void drawTTChar(int ox, int oy,int x, int y, cTeletextChar c);
+
+    void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b){};
+    void screenShot(const char* fileName){};
+
+  protected:
+
+
+    int removeCommands(float x,float y,float width,float height);
+
+    list<SVGCommand> commands;
+    int swidth, sheight;
+    Mutex command_mutex;
+    OsdVector* osd;
+
+    void drawPixel(int x, int y, unsigned int c, bool fastdraw){}; // these are not supported!
+    void drawPixel(int x, int y, Colour& c, bool fastdraw){};
+
+
+};
+
+
+
+
+
+
+
+
+
+#endif
index c3477debd8ba6662463475aecf5d3a6bed1fdb8c..e64f5639da56fff393ea9dc1996ded8f2c26d014 100644 (file)
-/*\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, const DrawStyle& 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
-  ULONG col=c.rgba();\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]=col;\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,const DrawStyle& c)\r
-{\r
-   fillblt(x1, y, x2-x1, 1, c);\r
-}\r
-\r
-void SurfaceWin::drawVertLine(int x, int y1, int y2, const DrawStyle& 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.
+*/
+
+#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, const DrawStyle& 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
+  }
+  ULONG col=c.rgba();
+
+  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]=col;
+      }
+    }
+
+    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,const DrawStyle& c)
+{
+   fillblt(x1, y, x2-x1, 1, c);
+}
+
+void SurfaceWin::drawVertLine(int x, int y1, int y2, const DrawStyle& 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(const 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(const char *fileName,int x, int y,int *width, int *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;
+
+}*/
+
index 0692c7a35bc0331bd11550a34dff31c5f474d475..093b28e3b4f93149f7d8964d65efe302e63c734f 100644 (file)
@@ -1,66 +1,66 @@
-/*\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, const DrawStyle& c);\r
-    void drawHorzLine(int x1, int x2, int y, const DrawStyle& c);\r
-    void drawVertLine(int x, int y1, int y2, const DrawStyle& 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
-  protected:\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
-};\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.
+*/
+
+#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, const DrawStyle& c);
+    void drawHorzLine(int x1, int x2, int y, const DrawStyle& c);
+    void drawVertLine(int x, int y1, int y2, const DrawStyle& 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(const 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(const char *fileName,int x, int y,int *width, int *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;
+  protected:
+    void drawPixel(int x, int y, Colour& c, bool fastdraw=false);
+    void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);
+};
+
+#endif
index 1e97f83a14de258bce2ed3976dfe9ca921d3b53b..4053aee4ac7d848435e1feee6c775140ff266ca5 100644 (file)
-/*\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
+/*
+    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 TxtPTSDifference(ULLONG pts1, ULLONG pts2)
+{
+  // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
+  if (pts1 > pts2)
+    return pts1 - pts2;
+  else
+    return -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();
+
+        ULLONG ptsdifference=TxtPTSDifference(mediapacket.pts, nowPTS);
+
+       if (ptsdifference >= (120LL*90000LL)) {
+            *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++;
+        
+       
+    }
+        
+}
index 040fe09fc26b2ae4dacbe7251708e59fdcec4743..0b88678c248e09f8dd14ecd62514ea56970820ee 100644 (file)
--- a/tfeed.cc
+++ b/tfeed.cc
@@ -1,63 +1,63 @@
-/*\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
-    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 "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
-\r\r
-int TFeed::start()\r
-{\r
-  teletextEnabled = 1;\r
-  return threadStart();\r
-}\r\r
-\r\r
-void TFeed::stop()\r
-{\r
-  threadCancel();\r
-}\r\r
-\r\r
-void TFeed::threadMethod()\r
-{\r
-  bool tlen;\r\r
-  while(1)\r  {\r
-    threadCheckExit();\r
-    tlen = Demuxer::getInstance()->writeTeletext();\r\r
-    if (tlen)\r
-    {\r
-      cb.call(this);\r
-//        Log::getInstance()->log("Tfeed", Log::DEBUG, "written");\r
-    }\r
-    else\r
-    {\r
-      //MILLISLEEP(100);\r
-        MILLISLEEP(20); //Performance Issue Marten\r
-    }\r
-  }\r
+/*\r
+    Copyright 2008 Marten Richter\r
+    This file is part of VOMP.\r
+    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.\r
+    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.\r
+    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.
+*/\r
+\r
+#include "tfeed.h"\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
+void TFeed::enable()
+{\r     teletextEnabled = 1;\r
+}\r
+\r
+int TFeed::start()
+{
+  teletextEnabled = 1;
+  return threadStart();
+}\r
+\r
+void TFeed::stop()
+{
+  threadCancel();
+}\r
+\r
+void TFeed::threadMethod()
+{
+  bool tlen;\r
+  while(1)\r  {
+    threadCheckExit();
+    tlen = Demuxer::getInstance()->writeTeletext();\r
+    if (tlen)
+    {
+      cb.call(this);
+//        Log::getInstance()->log("Tfeed", Log::DEBUG, "written");
+    }
+    else
+    {
+      //MILLISLEEP(100);
+        MILLISLEEP(20); //Performance Issue Marten
+    }
+  }
 }\r
\ No newline at end of file
diff --git a/tfeed.h b/tfeed.h
index 1c153f136e07ef244f709b2b84d01f559d3810a8..e713bb029ba69d184127235729eefa4be7aa0929 100644 (file)
--- a/tfeed.h
+++ b/tfeed.h
@@ -1,21 +1,21 @@
-/*\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
-#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
+/*\r    Copyright 2008 Marten Richter\r
+    This file is part of VOMP.\r
+    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.\r
+    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.\r
+    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.
+*/\r\r
+#ifndef TFEED_H\r#define TFEED_H\r
+#include <stdio.h>\r#include <time.h>\r
+#include "threadsystem.h"\r
+class Callback;\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
+#endif\r
index cddc15fb3e990d34d092a9b9c4fe89855bf1eaa0..4d512035d38643d15e677915c1f6510c166a4da8 100644 (file)
@@ -1,29 +1,29 @@
-/*\r
-    Copyright 2011 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 WIN32\r
-#ifdef __ANDROID__\r
-#include "threadpandroid.h"\r
-#else\r
-#include "threadp.h"\r
-#endif\r
-#else\r
-#include "threadwin.h"\r
-#endif\r
+/*
+    Copyright 2011 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 WIN32
+#ifdef __ANDROID__
+#include "threadpandroid.h"
+#else
+#include "threadp.h"
+#endif
+#else
+#include "threadwin.h"
+#endif
index 1e828a441da615717235a7b2a6317e4eb1513083..bab815ae24d1017cab0aa3a9986bb4a082126b0f 100644 (file)
-/*\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
+/*
+    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"
 
 #ifdef VOMP_PLATTFORM_MVP
 #include "surfacemvp.h"
 #endif
 
-\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, DrawStyle &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
-    DrawStyle bc=DrawStyle(140,140,140);\r
-    fillColour(bc);\r
-    bc=DrawStyle(255,255,255);\r
-    drawText(tr("Colour Tuning"), x+20, y+5, DrawStyle::LIGHTTEXT);\r
-    drawBox(x, y+50, bw, bh, DrawStyle::RED);\r
-    drawBox(x, y+130, bw, bh, DrawStyle::GREEN);\r
-    drawBox(x, y+190, bw, bh, DrawStyle::BLUE);\r
-    drawBox(x, y+270, bw, bh, bc);\r
-    sprintf(valbuf,"%03d%%",vrfactor);\r
-    drawText(valbuf,x+bw+x,y+50, DrawStyle::LIGHTTEXT);\r
-    drawText("<1 2>",x+bw+x,y+74, DrawStyle::LIGHTTEXT);\r
-    sprintf(valbuf,"%03d%%",vgfactor);\r
-    drawText(valbuf,x+bw+x,y+120, DrawStyle::LIGHTTEXT);\r
-    drawText("<4 5>",x+bw+x,y+144, DrawStyle::LIGHTTEXT);\r
-    sprintf(valbuf,"%03d%%",vbfactor);\r
-    drawText(valbuf,x+bw+x,y+190, DrawStyle::LIGHTTEXT);\r
-    drawText("<7 8>",x+bw+x,y+214, DrawStyle::LIGHTTEXT);\r
-    sprintf(valbuf,"%03d%%",(vbfactor+vgfactor+vrfactor)/3);\r
-    drawText(valbuf,x+bw+x,y+270, DrawStyle::LIGHTTEXT);\r
-    drawText("<3 6>",x+bw+x,y+294, DrawStyle::LIGHTTEXT);\r
-    drawText("9 norm",x+bw+x,y+318, DrawStyle::LIGHTTEXT);\r
-    drawText(tr("OK to save, BACK to cancel"), x+20, area.h - 50, DrawStyle::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, DrawStyle::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
+
+#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, DrawStyle &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();
+    DrawStyle bc=DrawStyle(140,140,140);
+    fillColour(bc);
+    bc=DrawStyle(255,255,255);
+    drawText(tr("Colour Tuning"), x+20, y+5, DrawStyle::LIGHTTEXT);
+    drawBox(x, y+50, bw, bh, DrawStyle::RED);
+    drawBox(x, y+130, bw, bh, DrawStyle::GREEN);
+    drawBox(x, y+190, bw, bh, DrawStyle::BLUE);
+    drawBox(x, y+270, bw, bh, bc);
+    sprintf(valbuf,"%03d%%",vrfactor);
+    drawText(valbuf,x+bw+x,y+50, DrawStyle::LIGHTTEXT);
+    drawText("<1 2>",x+bw+x,y+74, DrawStyle::LIGHTTEXT);
+    sprintf(valbuf,"%03d%%",vgfactor);
+    drawText(valbuf,x+bw+x,y+120, DrawStyle::LIGHTTEXT);
+    drawText("<4 5>",x+bw+x,y+144, DrawStyle::LIGHTTEXT);
+    sprintf(valbuf,"%03d%%",vbfactor);
+    drawText(valbuf,x+bw+x,y+190, DrawStyle::LIGHTTEXT);
+    drawText("<7 8>",x+bw+x,y+214, DrawStyle::LIGHTTEXT);
+    sprintf(valbuf,"%03d%%",(vbfactor+vgfactor+vrfactor)/3);
+    drawText(valbuf,x+bw+x,y+270, DrawStyle::LIGHTTEXT);
+    drawText("<3 6>",x+bw+x,y+294, DrawStyle::LIGHTTEXT);
+    drawText("9 norm",x+bw+x,y+318, DrawStyle::LIGHTTEXT);
+    drawText(tr("OK to save, BACK to cancel"), x+20, area.h - 50, DrawStyle::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, DrawStyle::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
+#ifndef __ANDROID__
+    ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);
+#endif
+#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
+#ifndef __ANDROID__
+    ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);
+#endif
+#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 __ANDROID__
+#ifndef WIN32
+#ifndef _MIPS_ARCH
+  Surface_TYPE::initConversionTables(rfactor,gfactor,bfactor);
+#endif
+#endif
+#endif
+}
diff --git a/vdr.cc b/vdr.cc
index 1798c3b1ed7ae23ff1f1e69ecc949a6f91e58599..33ed8ec2a2b3ae26704143c496375f4150bbcbfd 100644 (file)
--- a/vdr.cc
+++ b/vdr.cc
-/*\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
-#define VOMP_PROTOCOLL_VERSION 0x00000100\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(unsigned int* v_server,unsigned int* v_client)\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
-  unsigned int version=vresp->extractULONG();\r
-\r
-  *v_server=version;\r
-  *v_client=VOMP_PROTOCOLL_VERSION;\r
-\r
-  delete vresp;\r
-\r
-  if (version!=VOMP_PROTOCOLL_VERSION) {\r
-\r
-         return 0;\r
-\r
-  }\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, &currentTime);\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
-    char * name=vresp->extractString();\r
-    strncpy(newapid.desc,name,9);\r
-    delete [] name;\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
-    char * name=vresp->extractString();\r
-    strncpy(newdpid.desc,name,9);\r
-    delete [] name;\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
-    char * name=vresp->extractString();\r
-    strncpy(newspid.desc,name,9);\r
-    delete [] name;\r
-    channel->spids.push_back(newspid);\r
-  }\r
-  channel->tpid = vresp->extractULONG();\r
-  // extension\r
-  for (ULONG i = 0; i < channel->numAPids; i++)\r
-  {\r
-         channel->apids[i].type = vresp->extractULONG();\r
-  }\r
-  for (ULONG i = 0; i < channel->numDPids; i++)\r
-  {\r
-         channel->dpids[i].type = vresp->extractULONG();\r
-  }\r
-  for (ULONG i = 0; i < channel->numSPids; i++)\r
-  {\r
-         channel->spids[i].type = vresp->extractULONG();\r
-         channel->spids[i].data1 = vresp->extractULONG();\r
-         channel->spids[i].data2 = vresp->extractULONG();\r
-  }\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-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"
+#include "osd.h"
+
+#define VOMP_PROTOCOLL_VERSION 0x00000100
+
+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;
+/* For DEBUGGING *
+      { VDRServer newServer;
+      newServer.ip = new char[16];
+      strcpy(newServer.ip, "192.168.1.7");
+      newServer.name = new char[6];
+      strcpy(newServer.name,"debug");
+      servers.push_back(newServer);
+      waitType = 2;
+      haveAtLeastOne = 1;}/**/
+
+
+
+    }
+  }
+  logger->log("VDR", Log::NOTICE, "END loop");
+  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;
+    }
+    threadCheckExit();
+
+
+    // 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];
+
+  int pos=0;
+  ULONG ul=CHANNEL_KEEPALIVE;
+  buffer[pos++]=(ul>>24)&0xff;
+  buffer[pos++]=(ul>>16)&0xff;
+  buffer[pos++]=(ul>>8)&0xff;
+  buffer[pos++]=ul &0xff;
+  ul=timeStamp;
+  buffer[pos++]=(ul>>24)&0xff;
+  buffer[pos++]=(ul>>16)&0xff;
+  buffer[pos++]=(ul>>8)&0xff;
+  buffer[pos++]=ul &0xff;
+  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(unsigned int* v_server,unsigned int* v_client)
+{
+  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);
+
+  unsigned int version=vresp->extractULONG();
+
+  *v_server=version;
+  *v_client=VOMP_PROTOCOLL_VERSION;
+
+  delete vresp;
+
+  if (version!=VOMP_PROTOCOLL_VERSION) {
+
+         return 0;
+
+  }
+
+  // Set the time and zone on the MVP only
+
+#if !defined(WIN32) && !defined(__ANDROID__)
+  struct timespec currentTime;
+  currentTime.tv_sec = vdrTime;
+  currentTime.tv_nsec = 0;
+
+  int b = clock_settime(CLOCK_REALTIME, &currentTime);
+
+  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
+
+  setCharset(Osd::getInstance()->charSet());
+
+  return 1;
+}
+
+bool VDR::LogExtern(const char* logString)
+{
+  if (!connected) return false;
+  int stringLength = strlen(logString);
+  int packetLength = stringLength + 8;
+  char *buffer=new char[packetLength + 1];
+  int pos=0;
+  ULONG ul=CHANNEL_NETLOG;
+  buffer[pos++]=(ul>>24)&0xff;
+  buffer[pos++]=(ul>>16)&0xff;
+  buffer[pos++]=(ul>>8)&0xff;
+  buffer[pos++]=ul &0xff;
+  ul=stringLength;
+  buffer[pos++]=(ul>>24)&0xff;
+  buffer[pos++]=(ul>>16)&0xff;
+  buffer[pos++]=(ul>>8)&0xff;
+  buffer[pos++]=ul &0xff;
+
+  strcpy(&buffer[8], logString);
+  
+  if ((ULONG)tcp->sendData(buffer, packetLength) != packetLength) {
+         delete [] buffer;
+         return false;
+  }
+  delete [] buffer;
+  return true;
+}
+
+bool VDR::setCharset(int charset)
+{
+  VDR_RequestPacket vrp;
+  if (!vrp.init(VDR_SETCHARSET, true, sizeof(ULONG))) return false;
+  if (!vrp.addULONG(charset)) return false;
+
+  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
+  if (vresp->noResponse()) { delete vresp; return false; }
+
+  ULONG success = vresp->extractULONG();
+  delete vresp;
+
+  if (!success) return false;
+
+  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();
+    char * name=vresp->extractString();
+    strncpy(newapid.desc,name,9);
+    delete [] name;
+    channel->apids.push_back(newapid);
+  }
+
+  channel->numDPids = vresp->extractULONG();
+
+  for (ULONG i = 0; i < channel->numDPids; i++)
+  {
+    apid newdpid;
+    newdpid.pid = vresp->extractULONG();
+    char * name=vresp->extractString();
+    strncpy(newdpid.desc,name,9);
+    delete [] name;
+    channel->dpids.push_back(newdpid);
+  }
+
+  channel->numSPids = vresp->extractULONG();
+
+  for (ULONG i = 0; i < channel->numSPids; i++)
+  {
+    apid newspid;
+    newspid.pid = vresp->extractULONG();
+    char * name=vresp->extractString();
+    strncpy(newspid.desc,name,9);
+    delete [] name;
+    channel->spids.push_back(newspid);
+  }
+  channel->tpid = vresp->extractULONG();
+  // extension
+  for (ULONG i = 0; i < channel->numAPids; i++)
+  {
+         channel->apids[i].type = vresp->extractULONG();
+  }
+  for (ULONG i = 0; i < channel->numDPids; i++)
+  {
+         channel->dpids[i].type = vresp->extractULONG();
+  }
+  for (ULONG i = 0; i < channel->numSPids; i++)
+  {
+         channel->spids[i].type = vresp->extractULONG();
+         channel->spids[i].data1 = vresp->extractULONG();
+         channel->spids[i].data2 = 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;
+}
diff --git a/vdr.h b/vdr.h
index 5a5172d70e844a7eb154f41720b35f58452e6e2a..b0ba3f6fd8180a5b949ac469ce1d973e955c2399 100644 (file)
--- a/vdr.h
+++ b/vdr.h
-/*\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(unsigned int* v_server,unsigned int* v_client);\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
+
+    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>
+
+#include "threadsystem.h"
+
+#include "defines.h"
+#include "rectimer.h"
+#include "mark.h"
+#include "mediaprovider.h"
+#include "eventdispatcher.h"
+#include "i18n.h"
+#include "log.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 ExternLogger
+{
+
+  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(unsigned int* v_server,unsigned int* v_client);
+    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          LogExtern(const char* buffer);
+    
+    bool setCharset(int charset); // 1 latin 2 UTF-8
+
+    /**
+      * 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
+
+*/
+
index 486f00497e637fbf35d99d4cd55f137f34ad969b..7f8d450988e19eca5b26fd5d520c312e768366b6 100644 (file)
-/*\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
+/*
+    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_SETCHARSET          = 37;
+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
index 8a14fd2a491f069cef755a63e1da571952824394..37b2be5d90fc2a34dbc9fffece629104e5147319 100644 (file)
-/*\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 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 = userData[packetPos++]<<24;
+  ul|= userData[packetPos++]<<16;
+  ul|= userData[packetPos++]<<8;
+  ul|= userData[packetPos++];
+  //packetPos += sizeof(ULONG);
+  return ul;
+}
+
+ULLONG VDR_ResponsePacket::extractULLONG()
+{
+  if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0;
+  ULLONG ull= ((ULLONG)userData[packetPos++])<<56;
+  ull|= ((ULLONG)userData[packetPos++])<<48;
+  ull|= ((ULLONG)userData[packetPos++])<<40;
+  ull|= ((ULLONG)userData[packetPos++])<<32;
+  ull|= ((ULLONG)userData[packetPos++])<<24;
+  ull|= ((ULLONG)userData[packetPos++])<<16;
+  ull|= ((ULLONG)userData[packetPos++])<<8;
+  ull|= ((ULLONG)userData[packetPos++]);
+  return ull;
+}
+
+double VDR_ResponsePacket::extractdouble()
+{
+  if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0;
+  ULLONG ull = extractULLONG();
+  double d;
+  memcpy(&d,&ull,sizeof(double));
+  return d;
+}
+
+long VDR_ResponsePacket::extractLONG()
+{
+  if ((packetPos + sizeof(long)) > userDataLength) return 0;
+  long l = userData[packetPos++]<<24;
+  l|= userData[packetPos++]<<16;
+  l|= userData[packetPos++]<<8;
+  l|= userData[packetPos++];
+  return l;
+}
+
+UCHAR* VDR_ResponsePacket::getUserData()
+{
+  ownBlock = false;
+  return userData;
+}
+
diff --git a/vepg.cc b/vepg.cc
index c60f1cfd6c1f8a48616cf16c6078ca31f48e4847..72edcae60aa940b547efff78525efd1d7009fb88 100644 (file)
--- a/vepg.cc
+++ b/vepg.cc
-/*\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
-//  DrawStyle transparent = DrawStyle(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(DrawStyle::TITLEBARBACKGROUND);\r
-  progTitle.setTextPos(5, 16);\r
-  progTitle.setGap(4);\r
-  add(&progTitle);\r
-\r
-//  progInfo.setSurface(surface);\r
-  progInfo.setBackgroundColour(DrawStyle::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
-  DrawStyle 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(&ltime); // set ltime to now\r
-  ltime = prevHour(&ltime); // 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
-  DrawStyle transparent = DrawStyle(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
-  DrawStyle ref1 = DrawStyle(100, 100, 100, 255); //to do global definition for skin\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, DrawStyle::LIGHTTEXT);\r
-\r
-  DrawStyle ref2 = DrawStyle(200, 0, 0, 255);\r
-  rectangle(keyx + 72, keyy + 4, 104, getFontHeight() + 2, ref2);\r
-  drawText(tr("Page up"), keyx + 74, keyy + 5, DrawStyle::LIGHTTEXT);\r
-\r
-  DrawStyle ref3 = DrawStyle(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, DrawStyle::LIGHTTEXT);\r
-\r
-  DrawStyle ref4 = DrawStyle(200, 200, 0, 255);\r
-  rectangle(keyx + 180, keyy + 4, 104, getFontHeight() + 2, ref4);\r
-  drawText(tr("-24 hours"), keyx + 182, keyy + 5, DrawStyle::LIGHTTEXT);\r
-\r
-  DrawStyle ref5 = DrawStyle(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, DrawStyle::LIGHTTEXT);\r
-\r
-  DrawStyle ref6 = DrawStyle(180, 180, 180, 255);\r
-  rectangle(keyx + 290, keyy + 4, 180, getFontHeight() + 2, ref6);\r
-  drawText(tr("Guide / Back: Close"), keyx + 292 , keyy + 5, DrawStyle::LIGHTTEXT);\r
-\r
-  DrawStyle ref7 = DrawStyle(180, 180, 180, 255);\r
-  rectangle(keyx + 290, keyy + getFontHeight() + 8, 180, getFontHeight() + 2, ref7);\r
-  DrawStyle red = DrawStyle(130, 0, 0);\r
-  drawText(tr("Rec: Set timer"), keyx + 292, keyy + getFontHeight() + 9, red);\r
-\r
-  DrawStyle ref8 = DrawStyle(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, DrawStyle::LIGHTTEXT);\r
-\r
-  DrawStyle ref9 = DrawStyle(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, DrawStyle::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
-    DrawStyle::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
-  DrawStyle white = DrawStyle(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, DrawStyle::LIGHTTEXT); // print date\r
-  strftime(timeString, 19, "%H:%M", tms);\r
-  drawText(timeString, timex, timey, DrawStyle::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, DrawStyle::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, DrawStyle::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, DrawStyle(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, DrawStyle::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
-  DrawStyle 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, DrawStyle::NOPROGRAMME, DrawStyle::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 = DrawStyle::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)?DrawStyle::PROGRAMMEA:DrawStyle::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 = DrawStyle::SELECTHIGHLIGHT; // highlight cell\r
-            fg = DrawStyle::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 = DrawStyle::SELECTHIGHLIGHT; // highlight cell\r
-        fg = DrawStyle::DARKTEXT;\r
-        paintCell(&thisEvent, y, bg, fg);\r
-      }\r
-      else\r
-      {\r
-        bg = DrawStyle::NOPROGRAMME;\r
-        fg = DrawStyle::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 DrawStyle& bg, const DrawStyle& 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
-  float textWidth = 0;\r
-  unsigned int cur_length=1;\r
-  unsigned int text_max=strlen(tt);\r
-  UINT textPos;\r
-  for (textPos = 0; textPos <text_max; textPos+=cur_length)\r
-  {\r
-       wchar_t cur_char=getWChar(tt+textPos,&cur_length);\r
-    float thisCharWidth = charWidth(cur_char);\r
-    if (textWidth + thisCharWidth > w) // text will not fit in cell\r
-    {\r
-      break;\r
-    }\r
-    textWidth += thisCharWidth;\r
-  }\r
-  char* tT = new char[textPos+1];\r
-  if(textPos > 0)\r
-  {\r
-    strncpy(tT, tt, textPos );\r
-    tT[textPos ] =  '\0';\r
-    surface->drawText(tT, x+2, y, fg);\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
+/*
+    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
+//  DrawStyle transparent = DrawStyle(0, 0, 0, 0);
+//  setBackgroundColour(transparent);
+
+//  progTitle.setSurface(surface);
+  progTitle.setPosition(0,0);
+  progTitle.setSize(300,(getFontHeight() + 4) * 2 + 16); //paragraph line seperation is 4 pixels
+  progTitle.setBackgroundColour(DrawStyle::TITLEBARBACKGROUND);
+  progTitle.setTextPos(5, 16);
+  progTitle.setGap(4);
+  add(&progTitle);
+
+//  progInfo.setSurface(surface);
+  progInfo.setBackgroundColour(DrawStyle::VIEWBACKGROUND);
+  progInfo.setPosition(0, progTitle.getY2());
+  progInfo.setSize(300,((getFontHeight() + 4) * summaryLines) + summaryLowerPadding);
+  progInfo.setGap(4);
+  add(&progInfo);
+
+//  chanName.setSurface(surface);
+  chanName.setSize(510, (getFontHeight() + 4));
+  chanName.setPosition(305, chanNameYpos);
+  DrawStyle 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() + getFontHeight() + 8); // position channel list
+  chanListbox.setSize(150, ((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(&ltime); // set ltime to now
+  ltime = prevHour(&ltime); // 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
+  DrawStyle transparent = DrawStyle(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;
+  DrawStyle ref1 = DrawStyle(100, 100, 100, 255); //to do global definition for skin
+  rectangle(keyx, keyy, 605, 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, DrawStyle::LIGHTTEXT);
+
+  DrawStyle ref2 = DrawStyle(200, 0, 0, 255);
+  rectangle(keyx + 72, keyy + 4, 104, getFontHeight() + 2, ref2);
+  drawText(tr("Page up"), keyx + 74, keyy + 5, DrawStyle::LIGHTTEXT);
+
+  DrawStyle ref3 = DrawStyle(0, 200, 0, 255);
+  rectangle(keyx + 72, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, ref3);
+  drawText(tr("Page down"), keyx + 74, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
+
+  DrawStyle ref4 = DrawStyle(200, 200, 0, 255);
+  rectangle(keyx + 180, keyy + 4, 104, getFontHeight() + 2, ref4);
+  drawText(tr("-24 hours"), keyx + 182, keyy + 5, DrawStyle::LIGHTTEXT);
+
+  DrawStyle ref5 = DrawStyle(0, 0, 200, 255);
+  rectangle(keyx + 180, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, ref5);
+  drawText(tr("+24 hours"), keyx + 182, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
+
+  DrawStyle ref6 = DrawStyle(180, 180, 180, 255);
+  rectangle(keyx + 290, keyy + 4, 180, getFontHeight() + 2, ref6);
+  drawText(tr("Guide / Back: Close"), keyx + 292 , keyy + 5, DrawStyle::LIGHTTEXT);
+
+  DrawStyle ref7 = DrawStyle(180, 180, 180, 255);
+  rectangle(keyx + 290, keyy + getFontHeight() + 8, 180, getFontHeight() + 2, ref7);
+  DrawStyle red = DrawStyle(130, 0, 0);
+  drawText(tr("Rec: Set timer"), keyx + 292, keyy + getFontHeight() + 9, red);
+
+  DrawStyle ref8 = DrawStyle(180, 180, 180, 255);
+  rectangle(keyx + 474, keyy + 4, 128, getFontHeight() + 2, ref8);
+  w.nextSymbol = WSymbol::PLAY;
+  w.setPosition(keyx + 476, keyy + 5);
+  w.draw();
+  drawText(tr("Sel channel"), keyx + 496, keyy + 5, DrawStyle::LIGHTTEXT);
+
+  DrawStyle ref9 = DrawStyle(180, 180, 180, 255);
+  rectangle(keyx + 474, keyy + getFontHeight() + 8, 128, getFontHeight() + 2, ref9);
+  drawText(tr("Go: Preview"), keyx + 476, keyy + getFontHeight() + 9, DrawStyle::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() - getFontHeight() - 3,
+    155 + WINDOW_WIDTH * MINUTE_SCALE,
+    chanListbox.getHeight() + getFontHeight() + 4,
+    DrawStyle::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
+  DrawStyle white = DrawStyle(255, 255, 255, 255);
+  
+  t = ltime;
+  struct tm* tms;
+  tms = localtime(&t);
+  strftime(timeString, 19, "%a %d %b", tms);
+  int timey = chanListbox.getRootBoxOffsetY() - getFontHeight() - 3;
+  int timex = 135;
+  drawTextRJ(timeString, timex - 10, timey, DrawStyle::LIGHTTEXT); // print date
+  strftime(timeString, 19, "%H:%M", tms);
+  drawText(timeString, timex, timey, DrawStyle::LIGHTTEXT); // print left time
+
+  rectangle(155, timey + getFontHeight(), 2, 7, white);
+  t = t + 3600;
+  tms = localtime(&t);
+  strftime(timeString, 19, "%H:%M", tms);
+  drawText(timeString, timex + 180, timey, DrawStyle::LIGHTTEXT); // print middle time
+  rectangle(335, timey + getFontHeight(), 2, 7, white);
+  t = t + 3600;
+  tms = localtime(&t);
+  strftime(timeString, 19, "%H:%M", tms);
+  drawText(timeString, timex + 360, timey, DrawStyle::LIGHTTEXT); // print right time
+  rectangle(515, timey + getFontHeight(), 2, 7, white);
+  // pointer to selTime
+  //rectangle(155 + (selTime - ltime) / 20, timey + getFontHeight(), 2, 7, DrawStyle(255, 50, 50, 255));
+
+  // current time line
+  time(&t);
+  if ((t >= ltime) && (t < (ltime + 9000)))
+  {
+    rectangle(155 + (t - ltime) / 20, timey + getFontHeight(), 2, ((getFontHeight() + 2) * 7) + 7 + 2, DrawStyle::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
+  DrawStyle 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, DrawStyle::NOPROGRAMME, DrawStyle::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 = DrawStyle::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)?DrawStyle::PROGRAMMEA:DrawStyle::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 = DrawStyle::SELECTHIGHLIGHT; // highlight cell
+            fg = DrawStyle::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 = DrawStyle::SELECTHIGHLIGHT; // highlight cell
+        fg = DrawStyle::DARKTEXT;
+        paintCell(&thisEvent, y, bg, fg);
+      }
+      else
+      {
+        bg = DrawStyle::NOPROGRAMME;
+        fg = DrawStyle::LIGHTTEXT;
+        noevent.settitle(tr("No programme details"));
+        paintCell(&noevent, y, bg, fg);
+      }
+    }
+    y += 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 DrawStyle& bg, const DrawStyle& fg)
+{
+  int w, x, y, h;
+  w = x = 0; // keep compiler happy
+
+  y =yOffset;
+  h = 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);
+  float textWidth = 0;
+  unsigned int cur_length=1;
+  unsigned int text_max=strlen(tt);
+  UINT textPos;
+  for (textPos = 0; textPos <text_max; textPos+=cur_length)
+  {
+       wchar_t cur_char=getWChar(tt+textPos,&cur_length);
+    float thisCharWidth = charWidth(cur_char);
+    if (textWidth + thisCharWidth > w) // text will not fit in cell
+    {
+      break;
+    }
+    textWidth += thisCharWidth;
+  }
+  char* tT = new char[textPos+1];
+  if(textPos > 0)
+  {
+    strncpy(tT, tt, textPos );
+    tT[textPos ] =  '\0';
+    surface->drawText(tT, x+2, y, fg);
+  }
+  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+getFontHeight() + 2))
+      {
+        boxstack->handleCommand(Remote::RED);
+      }
+      else if (x>=(keyx+72) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+72+104) &&y<=(keyy+8+2*getFontHeight() + 2))
+      {
+        boxstack->handleCommand(Remote::GREEN);
+      }
+      else if (x>=(keyx+180) && y>=(keyy+4) &&x<=(keyx+180+104) &&y<=(keyy+4+getFontHeight() + 2))
+      {
+        boxstack->handleCommand(Remote::YELLOW);
+      }
+      else if (x>=(keyx+180) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+180+104) &&y<=(keyy+8+2*getFontHeight() + 2))
+      {
+        boxstack->handleCommand(Remote::BLUE);
+      }
+      else if (x>=(keyx+290) && y>=(keyy+4) &&x<=(keyx+180+290) &&y<=(keyy+4+getFontHeight() + 2))
+      {
+        boxstack->handleCommand(Remote::BACK);
+      }
+      else if (x>=(keyx+290) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+290+180) &&y<=(keyy+8+2*getFontHeight() + 2))
+      {
+        boxstack->handleCommand(Remote::RECORD);
+      }
+      else if (x>=(keyx+474) && y>=(keyy+4) &&x<=(keyx+128+474) &&y<=(keyy+4+getFontHeight() + 2))
+      {
+        boxstack->handleCommand(Remote::PLAY);
+      }
+      else if (x>=(keyx+474) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+238+474) &&y<=(keyy+8+2*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() - getFontHeight()
+                - 3+(int)chanListbox.getHeight() + getFontHeight() + 3)
+              )
+      {
+        int cy=y-(chanListbox.getRootBoxOffsetY() + 5);
+        int row=cy/(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);
+      }
+    }
+  }
+}
+
index b0fefab34b796d4975f0ccdb0905c8bb6eb64319..1f0af70638f557d614f54791f632cde4d4919908 100644 (file)
--- a/vfeed.cc
+++ b/vfeed.cc
@@ -1,84 +1,84 @@
-/*\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 FPS");\r
-      MILLISLEEP(5);\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.
+*/
+
+#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()
+{
+       Log::getInstance()->log("VFeed", Log::DEBUG, "Stop1");
+  threadCancel();
+       Log::getInstance()->log("VFeed", Log::DEBUG, "Stop2");
+}
+
+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 FPS");
+      MILLISLEEP(5);
+    }
+  }
+}
+
index 864c1a06b5628f7afad9034eac41a023071c1e65..135d756d61b1ea379a3cfa7da03b3d3b66b7a1bf 100644 (file)
--- a/video.cc
+++ b/video.cc
@@ -1,98 +1,98 @@
-/*\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.
+*/
+//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;
+}
+/*
+void Video::setInstance(Video* inst)
+{
+  instance=inst;
+}*/
+
+/*
+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;
+}
+*/
diff --git a/video.h b/video.h
index 9c9611f1442dc655ecb1fabd4f3de53590f349eb..bacd8ea8382a86df56408f3e5dd366ac4d6b47d1 100644 (file)
--- a/video.h
+++ b/video.h
-/*\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 UCHAR getSupportedFormats() { return COMPOSITERGB | SVIDEO;}; // if it returns zero there are no different formats\r
-    virtual UINT supportedTVsize() { return 0;}; // if no selection is allowed\r
-    virtual UCHAR supportedTVFormats() { return 0;}; // if no selection is allowed\r
-\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 void executePendingModeChanges() {}; // This is called if you change the output mode and the device take a while for reinitialization\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
-\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
-    const static UCHAR PAL_M = 2;\r
-    const static UCHAR NTSC_J = 4;\r
-\r
-    // Video connections - AV_SET_VID_OUTPUT\r
-    const static UCHAR COMPOSITERGB = 1;\r
-    const static UCHAR SVIDEO = 2;\r
-    const static UCHAR HDMI = 4;\r
-    const static UCHAR HDMI3D = 16; //For future use\r
-\r
-    // Video aspect ratios - AV_SET_VID_RATIO\r
-    const static UCHAR ASPECT4X3 = 0;\r
-    const static UCHAR ASPECT16X9 = 1;\r
-    const static UCHAR ASPECT14X9 = 2; //future use\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.
+*/
+
+#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();
+    //static void setInstance(Video*);
+
+    virtual int init(UCHAR format)=0;
+    virtual int shutdown()=0;
+    virtual int setFormat(UCHAR format)=0;
+    virtual UCHAR getSupportedFormats() { return COMPOSITERGB | SVIDEO;}; // if it returns zero there are no different formats
+    virtual UINT supportedTVsize() { return 0;}; // if no selection is allowed
+    virtual UCHAR supportedTVFormats() { return 0;}; // if no selection is allowed
+
+    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 void executePendingModeChanges() {}; // This is called if you change the output mode and the device take a while for reinitialization
+    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 bool displayIFrame(const UCHAR* buffer, UINT length)=0;
+    virtual int EnterIframePlayback() {return 1;}; // Must not be implemented
+
+       virtual bool supportsh264(){return false;};
+       virtual void seth264mode(bool ish264) {h264=ish264;};
+       virtual int getTeletextBufferFaktor(){return 1;};
+
+       virtual bool independentAVStartUp() {return true;};
+
+
+       //Tells, if the device allows an independent startup of audio and video
+       // this needs internal buffers in device and is possible for windows and mvp
+
+       virtual bool PTSIFramePlayback() {return false;};
+       // Tells, if the iframe playback is realized using a manipulation of the pts of the packets
+       //android does it like this...
+
+       virtual bool blockingDrainTarget() { return false;};
+       // if the draintargets blocks, the feed has to be stop when pausing
+
+
+    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;
+    const static UCHAR PAL_M = 2;
+    const static UCHAR NTSC_J = 4;
+
+    // Video connections - AV_SET_VID_OUTPUT
+    const static UCHAR COMPOSITERGB = 1;
+    const static UCHAR SVIDEO = 2;
+    const static UCHAR HDMI = 4;
+    const static UCHAR HDMI3D = 16; //For future use
+
+    // Video aspect ratios - AV_SET_VID_RATIO
+    const static UCHAR ASPECT4X3 = 0;
+    const static UCHAR ASPECT16X9 = 1;
+    const static UCHAR ASPECT14X9 = 2; //future use
+
+    // 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
index 1c6313b055c36980e8ff8e516a6afb5c8e86ea60..7f12942bd098c452f90c04aeccdb9dda18bae3c5 100644 (file)
-/*\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, &timestamps) == 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.
+*/
+
+#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, &timestamps) == 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()
+{
+}
+
+bool VideoMVP::displayIFrame(const UCHAR* buffer, UINT length)
+{
+  write(fdVideo, buffer, length);
+  return true;
+}
index aabad63c2fa88c458da6ce8709a6bafe70db7c6a..c1b07c8d678a289f860ecf4e4ab70d14a05d05dd 100644 (file)
-/*\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
-    virtual ~VideoMVP();\r
-\r
-    int init(UCHAR format);\r
-    int shutdown();\r
-\r
-    UCHAR getSupportedFormats() { return COMPOSITERGB | SVIDEO;};\r
-    UINT supportedTVsize() { return ASPECT4X3|ASPECT16X9;};\r
-    UCHAR supportedTVFormats() { return 0;}; /* We cannot change this here\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.
+*/
+
+// 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();
+    virtual ~VideoMVP();
+
+    int init(UCHAR format);
+    int shutdown();
+
+    UCHAR getSupportedFormats() { return COMPOSITERGB | SVIDEO;};
+    UINT supportedTVsize() { return ASPECT4X3|ASPECT16X9;};
+    UCHAR supportedTVFormats() { return 0;}; /* We cannot change this here
+
+    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();
+    bool 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
index 3371aad07e808a499a0862873998a9d0f4d9affe..ea3c247afa8221fdfdee0a77a5168eee1e94c548 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon 2009,2012 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
-#ifndef VIDEOOMX_H\r
-#define VIDEOOMX_H\r
-\r
-#include "mutex.h"\r
-\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 <list>\r
-#include <vector>\r
-\r
-#include "defines.h"\r
-#include "video.h"\r
-#include "threadsystem.h"\r
-\r
-#define OMX_SKIP64BIT\r
-\r
-#include <IL/OMX_Core.h>\r
-#include <IL/OMX_Types.h>\r
-#include <IL/OMX_Component.h>\r
-#include <IL/OMX_Broadcom.h>\r
-\r
-\r
-struct VPE_OMX_EVENT {\r
-       OMX_IN OMX_HANDLETYPE handle;\r
-       OMX_IN OMX_PTR appdata;\r
-    OMX_IN OMX_EVENTTYPE event_type;\r
-    OMX_IN OMX_U32 data1;\r
-       OMX_IN OMX_U32 data2;\r
-       OMX_IN OMX_PTR event_data;\r
-};\r
-\r
-\r
-\r
-\r
-class AudioVPE;\r
-\r
-class VideoOMX : public Video\r
-{\r
-  friend class AudioOMX;\r
-  public:\r
-    VideoOMX();\r
-    virtual ~VideoOMX();\r
-\r
-    int init(UCHAR format);\r
-    int shutdown();\r
-\r
-    UCHAR getSupportedFormats() { return COMPOSITERGB | HDMI;};\r
-    UINT supportedTVsize() { return ASPECT4X3|ASPECT16X9|ASPECT14X9 ;};\r
-    UCHAR supportedTVFormats() { return NTSC|PAL|PAL_M|NTSC_J;};\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
-\r
-    void executePendingModeChanges();\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* bulibaver, UINT length);\r
-\r
-    virtual bool dtsTimefix(){return false;} //please we need dts time values\r
-    virtual int getTeletextBufferFaktor(){return 5;};\r
-\r
-    // Writing Data to Videodevice\r
-    virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);\r
-    virtual UINT DeliverMediaSample(UCHAR* bulibaver, UINT* samplepos);\r
-\r
-\r
-       virtual bool supportsh264(){return true;};\r
-\r
-       int WriteOutTS(const unsigned char *bulibaver,int length, int type);\r
-       void WriteOutPATPMT();\r
-\r
-\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
-       bool loadOptionsfromServer(VDR* vdr);\r
-       bool saveOptionstoServer();\r
-       bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane);\r
-       bool handleOptionChanges(Option* option);\r
-\r
-\r
-#ifdef DEV\r
-    int test();\r
-    int test2();\r
-#endif\r
-\r
-\r
-\r
-    static inline OMX_TICKS intToOMXTicks(long long pts) {\r
-       OMX_TICKS temp;\r
-       temp.nLowPart=pts;\r
-       temp.nHighPart=pts>>32;\r
-       return temp;\r
-    }\r
-\r
-\r
-\r
-  private:\r
-          int EnterIframePlayback();\r
-          bool iframemode;\r
-          bool InIframemode() {return iframemode;};\r
-\r
-          UINT DeliverMediaPacket(MediaPacket packet,const UCHAR* bulibaver,UINT *samplepos);\r
-\r
-#define VPE_DECODER_OMX 1\r
-\r
-\r
-\r
-          bool offsetnotset;\r
-          bool offsetvideonotset;\r
-          bool offsetaudionotset;\r
-          long long startoffset;\r
-          long long lastrefvideotime;\r
-          long long lastrefaudiotime;\r
+/*
+    Copyright 2004-2005 Chris Tallon 2009,2012 Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+
+#ifndef VIDEOOMX_H
+#define VIDEOOMX_H
+
+#include "mutex.h"
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <string.h>
+
+#include <stdint.h>
+
+#include <list>
+#include <vector>
+
+#include "defines.h"
+#include "video.h"
+#include "threadsystem.h"
+
+#define OMX_SKIP64BIT
+
+#include <IL/OMX_Core.h>
+#include <IL/OMX_Types.h>
+#include <IL/OMX_Component.h>
+#include <IL/OMX_Broadcom.h>
+
+
+struct VPE_OMX_EVENT {
+       OMX_IN OMX_HANDLETYPE handle;
+       OMX_IN OMX_PTR appdata;
+    OMX_IN OMX_EVENTTYPE event_type;
+    OMX_IN OMX_U32 data1;
+       OMX_IN OMX_U32 data2;
+       OMX_IN OMX_PTR event_data;
+};
+
+
+
+
+class AudioVPE;
+
+class VideoOMX : public Video
+{
+  friend class AudioOMX;
+  public:
+    VideoOMX();
+    virtual ~VideoOMX();
+
+    int init(UCHAR format);
+    int shutdown();
+
+    UCHAR getSupportedFormats() { return COMPOSITERGB | HDMI;};
+    UINT supportedTVsize() { return ASPECT4X3|ASPECT16X9|ASPECT14X9 ;};
+    UCHAR supportedTVFormats() { return NTSC|PAL|PAL_M|NTSC_J;};
+
+    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?
+
+    void executePendingModeChanges();
+    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();
+    bool displayIFrame(const UCHAR* bulibaver, UINT length);
+
+    virtual bool dtsTimefix(){return false;} //please we need dts time values
+    virtual int getTeletextBufferFaktor(){return 5;};
+
+    // Writing Data to Videodevice
+    virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);
+    virtual UINT DeliverMediaSample(UCHAR* bulibaver, UINT* samplepos);
+
+
+       virtual bool supportsh264(){return true;};
+
+       int WriteOutTS(const unsigned char *bulibaver,int length, int type);
+       void WriteOutPATPMT();
+
+
+
+       virtual long long SetStartOffset(long long curreftime, bool *rsync);
+       long long SetStartAudioOffset(long long curreftime, bool *rsync);
+       virtual void ResetTimeOffsets();
+
+       bool loadOptionsfromServer(VDR* vdr);
+       bool saveOptionstoServer();
+       bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane);
+       bool handleOptionChanges(Option* option);
+
+
+#ifdef DEV
+    int test();
+    int test2();
+#endif
+
+
+
+    static inline OMX_TICKS intToOMXTicks(long long pts) {
+       OMX_TICKS temp;
+       temp.nLowPart=pts;
+       temp.nHighPart=pts>>32;
+       return temp;
+    }
+
+
+
+  private:
+          int EnterIframePlayback();
+          bool iframemode;
+          bool InIframemode() {return iframemode;};
+
+          UINT DeliverMediaPacket(MediaPacket packet,const UCHAR* bulibaver,UINT *samplepos);
+
+#define VPE_DECODER_OMX 1
+
+
+
+          bool offsetnotset;
+          bool offsetvideonotset;
+          bool offsetaudionotset;
+          long long startoffset;
+          long long lastrefvideotime;
+          long long lastrefaudiotime;
          // long long cur_pts;
-          long long lastreftimeOMX;\r
-          ULLONG lastreftimePTS;\r
-\r
-       //   long long playbacktimeoffset; //this is the offset between the media time and system clock\r
-       //   long long pausetimecode;\r
-          bool paused;\r
-\r
-        /*  static long long GetCurrentSystemTime();\r
-          static void WaitUntil(long long time);\r
-          void FrameWaitforDisplay(long long pts);\r
-          bool FrameSkip(long long pts);\r
-          bool skipping;\r
-          void AdjustAudioPTS(long long pts);*/\r
-\r
-\r
-\r
-\r
-          static OMX_ERRORTYPE EventHandler_OMX(OMX_IN OMX_HANDLETYPE handle,OMX_IN OMX_PTR appdata,\r
-          OMX_IN OMX_EVENTTYPE event_type,OMX_IN OMX_U32 data1,\r
-          OMX_IN OMX_U32 data2,OMX_IN OMX_PTR event_data);\r
-          static OMX_ERRORTYPE EmptyBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp,OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver);\r
-          static OMX_ERRORTYPE FillBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp, OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver);\r
-\r
-          UINT DeliverMediaPacketOMX(MediaPacket packet,\r
-                                                    const UCHAR* bulibaver,\r
-                                                    UINT *samplepos);\r
-\r
-          bool detectIFrame(const UCHAR *buffer,unsigned int length);\r
-\r
-          int PrepareInputBufsOMX();\r
-          int DestroyInputBufsOMX();\r
-\r
-          void AddOmxEvent(VPE_OMX_EVENT  new_event);\r
-          void ReturnEmptyOMXBuffer(OMX_BUFFERHEADERTYPE* bulibaver);\r
-\r
-          int ChangeComponentState(OMX_HANDLETYPE handle,OMX_STATETYPE type);\r
-          int CommandFinished(OMX_HANDLETYPE handle,OMX_U32 command,OMX_U32 data2);\r
-          int WaitForEvent(OMX_HANDLETYPE handle,OMX_U32 event);\r
-          int EnablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait);\r
-          int DisablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait=true);\r
-          int clearEvents();\r
-\r
-\r
-       int setClockExecutingandRunning();\r
-       int initClock();\r
-       void destroyClock();\r
-       int idleClock();\r
-       int getClockAudioandInit(OMX_HANDLETYPE *p_omx_clock,OMX_U32 *p_omx_clock_output_port);\r
-       int getClockVideoandInit();\r
-       void LockClock() {clock_mutex.Lock();};\r
-       void UnlockClock() {clock_mutex.Unlock();};\r
-       OMX_ERRORTYPE ProtOMXEmptyThisBuffer(OMX_HANDLETYPE handle, OMX_BUFFERHEADERTYPE* buffer);\r
-       void clockPause();\r
-       void clockUnpause();\r
-\r
-       void interlaceSwitch4Demux();\r
-\r
-       Mutex clock_mutex; //clock mutex is now responsible for all omx stuff\r
-       long long cur_clock_time;\r
-\r
-\r
-\r
-          OMX_HANDLETYPE omx_vid_dec;\r
-          OMX_HANDLETYPE omx_vid_sched;\r
-          OMX_HANDLETYPE omx_vid_deint;\r
-          OMX_HANDLETYPE omx_vid_rend;\r
-          OMX_HANDLETYPE omx_clock;\r
-          int clock_references;\r
-          bool dodeint; //deinterlacer was activated in omx filtergraph\r
-          bool deint_first_frame; //handle frame change\r
-          void DeinterlaceFix();\r
-\r
-\r
-          OMX_U32 omx_codec_input_port;\r
-          OMX_U32 omx_codec_output_port;\r
-          OMX_U32 omx_deint_input_port;\r
-          OMX_U32 omx_deint_output_port;\r
-          OMX_U32 omx_rend_input_port;\r
-          OMX_U32 omx_shed_input_port;\r
-          OMX_U32 omx_shed_output_port;\r
-          OMX_U32 omx_shed_clock_port;\r
-          OMX_U32 omx_clock_output_port;\r
-        //  OMX_NALUFORMATSTYPE omx_nalu_format;\r
-\r
-\r
-\r
-          int AllocateCodecsOMX();\r
-          int DeAllocateCodecsOMX();\r
-          int FlushRenderingPipe();\r
-\r
-          vector<OMX_BUFFERHEADERTYPE*> input_bufs_omx_all;\r
-          list<OMX_BUFFERHEADERTYPE*> input_bufs_omx_free;\r
-          Mutex input_bufs_omx_mutex;\r
-          OMX_BUFFERHEADERTYPE* cur_input_buf_omx;\r
-\r
-          void PutBufferToPres(OMX_BUFFERHEADERTYPE* buffer);\r
-\r
-\r
-\r
-          bool omx_running;\r
-          bool omx_first_frame;\r
-\r
-          Mutex omx_event_mutex;\r
-\r
-          list<VPE_OMX_EVENT> omx_events;\r
-\r
-          bool omx_mpeg2;\r
-          bool omx_h264;\r
-          float xpos,ypos;\r
-          int deinterlace;\r
-          void updateMode();//called internally to adjust for different parameters\r
-          void selectVideoMode(int interlaced);\r
-          UCHAR tvsystem;\r
-          bool signalon;\r
-          bool pendingmodechange;\r
-          bool hdmi;\r
-          int outputinterlaced;\r
-\r
-\r
-\r
-   bool firstsynched;\r
-\r
-    \r
-   vector<MediaPacket> mediapackets;\r
-};\r
-\r
-#endif\r
+          long long lastreftimeOMX;
+          ULLONG lastreftimePTS;
+
+       //   long long playbacktimeoffset; //this is the offset between the media time and system clock
+       //   long long pausetimecode;
+          bool paused;
+
+        /*  static long long GetCurrentSystemTime();
+          static void WaitUntil(long long time);
+          void FrameWaitforDisplay(long long pts);
+          bool FrameSkip(long long pts);
+          bool skipping;
+          void AdjustAudioPTS(long long pts);*/
+
+
+
+
+          static OMX_ERRORTYPE EventHandler_OMX(OMX_IN OMX_HANDLETYPE handle,OMX_IN OMX_PTR appdata,
+          OMX_IN OMX_EVENTTYPE event_type,OMX_IN OMX_U32 data1,
+          OMX_IN OMX_U32 data2,OMX_IN OMX_PTR event_data);
+          static OMX_ERRORTYPE EmptyBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp,OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver);
+          static OMX_ERRORTYPE FillBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp, OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver);
+
+          UINT DeliverMediaPacketOMX(MediaPacket packet,
+                                                    const UCHAR* bulibaver,
+                                                    UINT *samplepos);
+
+          bool detectIFrame(const UCHAR *buffer,unsigned int length);
+
+          int PrepareInputBufsOMX();
+          int DestroyInputBufsOMX();
+
+          void AddOmxEvent(VPE_OMX_EVENT  new_event);
+          void ReturnEmptyOMXBuffer(OMX_BUFFERHEADERTYPE* bulibaver);
+
+          int ChangeComponentState(OMX_HANDLETYPE handle,OMX_STATETYPE type);
+          int CommandFinished(OMX_HANDLETYPE handle,OMX_U32 command,OMX_U32 data2);
+          int WaitForEvent(OMX_HANDLETYPE handle,OMX_U32 event);
+          int EnablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait);
+          int DisablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait=true);
+          int clearEvents();
+
+
+       int setClockExecutingandRunning();
+       int initClock();
+       void destroyClock();
+       int idleClock();
+       int getClockAudioandInit(OMX_HANDLETYPE *p_omx_clock,OMX_U32 *p_omx_clock_output_port);
+       int getClockVideoandInit();
+       void LockClock() {clock_mutex.Lock();};
+       void UnlockClock() {clock_mutex.Unlock();};
+       OMX_ERRORTYPE ProtOMXEmptyThisBuffer(OMX_HANDLETYPE handle, OMX_BUFFERHEADERTYPE* buffer);
+       void clockPause();
+       void clockUnpause();
+
+       void interlaceSwitch4Demux();
+
+       Mutex clock_mutex; //clock mutex is now responsible for all omx stuff
+       long long cur_clock_time;
+
+
+
+          OMX_HANDLETYPE omx_vid_dec;
+          OMX_HANDLETYPE omx_vid_sched;
+          OMX_HANDLETYPE omx_vid_deint;
+          OMX_HANDLETYPE omx_vid_rend;
+          OMX_HANDLETYPE omx_clock;
+          int clock_references;
+          bool dodeint; //deinterlacer was activated in omx filtergraph
+          bool deint_first_frame; //handle frame change
+          void DeinterlaceFix();
+
+
+          OMX_U32 omx_codec_input_port;
+          OMX_U32 omx_codec_output_port;
+          OMX_U32 omx_deint_input_port;
+          OMX_U32 omx_deint_output_port;
+          OMX_U32 omx_rend_input_port;
+          OMX_U32 omx_shed_input_port;
+          OMX_U32 omx_shed_output_port;
+          OMX_U32 omx_shed_clock_port;
+          OMX_U32 omx_clock_output_port;
+        //  OMX_NALUFORMATSTYPE omx_nalu_format;
+
+
+
+          int AllocateCodecsOMX();
+          int DeAllocateCodecsOMX();
+          int FlushRenderingPipe();
+
+          vector<OMX_BUFFERHEADERTYPE*> input_bufs_omx_all;
+          list<OMX_BUFFERHEADERTYPE*> input_bufs_omx_free;
+          Mutex input_bufs_omx_mutex;
+          OMX_BUFFERHEADERTYPE* cur_input_buf_omx;
+
+          void PutBufferToPres(OMX_BUFFERHEADERTYPE* buffer);
+
+
+
+          bool omx_running;
+          bool omx_first_frame;
+
+          Mutex omx_event_mutex;
+
+          list<VPE_OMX_EVENT> omx_events;
+
+          bool omx_mpeg2;
+          bool omx_h264;
+          float xpos,ypos;
+          int deinterlace;
+          void updateMode();//called internally to adjust for different parameters
+          void selectVideoMode(int interlaced);
+          UCHAR tvsystem;
+          bool signalon;
+          bool pendingmodechange;
+          bool hdmi;
+          int outputinterlaced;
+
+
+
+   bool firstsynched;
+
+    
+   vector<MediaPacket> mediapackets;
+};
+
+#endif
index 8979151bbe6a1bdb0364b2ace98a78a8bebf8c80..425ff00f10434e1475b03f2c39cdd7e64f40a253 100644 (file)
-/*\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,&current,&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,&current,&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.
+*/
+
+
+
+#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,&current,&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,&current,&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);
+}
+
+bool VideoWin::displayIFrame(const UCHAR* buffer, UINT length)
+{
+       if (!iframemode) EnterIframePlayback();
+       if (!isdsinited()) return false;
+       
+#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();
+
+  return true;
+#else
+
+    //   *samplepos+=packet.length;
+      MILLISLEEP(0); //yet not implemented//bad idea
+       return  true;
+#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
+
+
+
+
index 4293d2166ae01a3a975603e18e110a48a61aaf5d..3300433ec4b592c5299873ef74d61c5f80cfd123 100644 (file)
-/*\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
-       UCHAR getSupportedFormats() { return 0;};\r
-       UINT supportedTVsize() { return ASPECT4X3|ASPECT16X9;};\r
-       UCHAR supportedTVFormats() { return 0;};\r
-\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
-       virtual int getTeletextBufferFaktor(){return 4;};\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
+
+    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();
+       virtual ~VideoWin();
+
+       int init(UCHAR format);
+       int shutdown();
+
+       int setFormat(UCHAR format);
+       UCHAR getSupportedFormats() { return 0;};
+       UINT supportedTVsize() { return ASPECT4X3|ASPECT16X9;};
+       UCHAR supportedTVFormats() { return 0;};
+
+       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 int getTeletextBufferFaktor(){return 4;};
+
+
+       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 bool 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
+
+
+
index 33e44327970bfb3d5e274561c3b410129218402f..3745f7fa9c526b2047b0e492683d8754389a3b3a 100644 (file)
-/*\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
-DrawStyle VMediaView::pictureBack=DrawStyle(140,140,140);\r
-DrawStyle VMediaView::infoBack=DrawStyle(110,110,110);\r
-DrawStyle VMediaView::audioBannerBack=DrawStyle(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
-    WJpegComplex::JpegControl *_ctl;\r
-    Surface *_sfc;\r
-    DrawStyle _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(WJpegComplex::JpegControl *ctl,Surface *sfc,VPreader *reader,DrawStyle &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=WJpegComplex::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=WJpegComplex::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=WJpegComplex::CROP;\r
-  else if (strcmp(mode,"letter") == 0) ctl.mode=WJpegComplex::LETTER;\r
-  else if (strcmp(mode,"clipfactor") == 0) ctl.mode=WJpegComplex::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(DrawStyle::BLACK);\r
-  if (pictureError) {\r
-    drawText(pictureError,100,area.h/2,DrawStyle::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=WJpegComplex::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=WJpegComplex::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=WJpegComplex::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=WJpegComplex::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 WJpegComplex::ROT_0:\r
-            rotate=WJpegComplex::ROT_90;\r
-            break;\r
-          case WJpegComplex::ROT_90:\r
-            rotate=WJpegComplex::ROT_180;\r
-            break;\r
-          case WJpegComplex::ROT_180:\r
-            rotate=WJpegComplex::ROT_270;\r
-            break;\r
-          case WJpegComplex::ROT_270:\r
-            rotate=WJpegComplex::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 WJpegComplex::CROP:\r
-            cropmode=WJpegComplex::LETTER;\r
-            break;\r
-          case WJpegComplex::LETTER:\r
-            cropmode=WJpegComplex::CROPPERCENT;\r
-            break;\r
-          default:\r
-            cropmode=WJpegComplex::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=WJpegComplex::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
-     WJpegComplex::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=WJpegComplex::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 WJpegComplex::CROPPERCENT:\r
-      mode="clipfactor";\r
-      break;\r
-    case WJpegComplex::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,WJpegComplex::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,DrawStyle::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, DrawStyle::TITLEBARBACKGROUND);\r
-  info->drawText(title, 5, 5, DrawStyle::LIGHTTEXT);\r
-  info->drawPara(buf,5,32,DrawStyle::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, DrawStyle::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, DrawStyle::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, DrawStyle::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(&currentSec,&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, DrawStyle::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, DrawStyle::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, DrawStyle::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,DrawStyle::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,DrawStyle::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 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
+
+DrawStyle VMediaView::pictureBack=DrawStyle(140,140,140);
+DrawStyle VMediaView::infoBack=DrawStyle(110,110,110);
+DrawStyle VMediaView::audioBannerBack=DrawStyle(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;
+    WJpegComplex::JpegControl *_ctl;
+    Surface *_sfc;
+    DrawStyle _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(WJpegComplex::JpegControl *ctl,Surface *sfc,VPreader *reader,DrawStyle &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=WJpegComplex::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=WJpegComplex::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=WJpegComplex::CROP;
+  else if (strcmp(mode,"letter") == 0) ctl.mode=WJpegComplex::LETTER;
+  else if (strcmp(mode,"clipfactor") == 0) ctl.mode=WJpegComplex::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(DrawStyle::BLACK);
+  if (pictureError) {
+    drawText(pictureError,100,area.h/2,DrawStyle::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=WJpegComplex::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=WJpegComplex::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=WJpegComplex::ROT_0;
+        showPicture(VMediaList::MV_NEXT,slideshow,true);
+        rt= 2;
+      }
+      break;
+      case Remote::PAUSE:
+        if (slideshow) {
+          stopSlideshow(true);
+          updatePictureBanner();
+        }
+        else {
+          slideshow=true;
+          rotate=WJpegComplex::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 WJpegComplex::ROT_0:
+            rotate=WJpegComplex::ROT_90;
+            break;
+          case WJpegComplex::ROT_90:
+            rotate=WJpegComplex::ROT_180;
+            break;
+          case WJpegComplex::ROT_180:
+            rotate=WJpegComplex::ROT_270;
+            break;
+          case WJpegComplex::ROT_270:
+            rotate=WJpegComplex::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 WJpegComplex::CROP:
+            cropmode=WJpegComplex::LETTER;
+            break;
+          case WJpegComplex::LETTER:
+            cropmode=WJpegComplex::CROPPERCENT;
+            break;
+          default:
+            cropmode=WJpegComplex::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=WJpegComplex::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;
+     WJpegComplex::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=WJpegComplex::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 WJpegComplex::CROPPERCENT:
+      mode="clipfactor";
+      break;
+    case WJpegComplex::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,WJpegComplex::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,DrawStyle::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 = 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, DrawStyle::TITLEBARBACKGROUND);
+  info->drawText(title, 5, 5, DrawStyle::LIGHTTEXT);
+  info->drawPara(buf,5,32,DrawStyle::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, DrawStyle::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, DrawStyle::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, DrawStyle::TITLEBARBACKGROUND);
+
+  time_t currentSec = (time_t)(getPlayer()->getCurrentTimes());
+  time_t lengthSec=(time_t)(getPlayer()->getSonglen());
+       struct tm cpos;
+       struct tm slen;
+/*     gmtime_r(&currentSec,&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, DrawStyle::LIGHTTEXT);
+  
+       // Draw progress bar
+  int progBarXbase = 0;
+       int barlen=250;
+
+  info->rectangle(barRegion.x + progBarXbase, barRegion.y + 3, barlen+10, 24, DrawStyle::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, DrawStyle::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,DrawStyle::LIGHTTEXT);
+  }
+  else {
+    char * buf=new char[strlen(currentAudio->getDisplayName())+50];
+    SNPRINTF(buf,50,"%s %s",tr("AudioPlayer"),currentAudio->getDisplayName());
+    audioBanner->drawText(buf,5,3,DrawStyle::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;
+  }
+}