]> git.vomp.tv Git - vompclient.git/commitdiff
Initial import of patches for ARM/Android/Raspeberry pi
authorMarten Richter <marten.richter@freenet.de>
Thu, 17 May 2012 07:08:41 +0000 (09:08 +0200)
committerMarten Richter <marten.richter@freenet.de>
Thu, 17 May 2012 07:08:41 +0000 (09:08 +0200)
112 files changed:
GNUmakefile
Makefile.nmake
abstractoption.cc
abstractoption.h
afeed.cc
afeed.h
audio.cc
audio.h
audiowin.cc
bitmap.h
boxstack.cc
boxx.cc
boxx.h
command.cc
defines.h
demuxer.cc
demuxer.h
demuxeraudio.cc
demuxerts.cc
demuxerts.h
demuxervdr.cc
directory.cc
directory.h
draintarget.cc [deleted file]
draintarget.h
dvbsubtitles.h
i18n.cc
imagereader.h
ledmvp.h
log.cc
log.h
main.cc
message.h
objects.mk
osdmvp.cc
osdmvp.h
osdwin.cc
osdwin.h
player.cc
player.h
playerliveradio.cc
playerlivetv.cc
playerradio.cc
playerradio.h
recman.h
remote.cc
remote.h
stream.cc
surface.cc
surface.h
surfacedirectfb.cc
surfacedirectfb.h
surfacewin.cc
surfacewin.h
tbboxx.cc
teletextdecodervbiebu.cc
tfeed.cc
tfeed.h
threadp.cc
threadp.h
timerreceiver.h [changed mode: 0755->0644]
timers.cc [changed mode: 0755->0644]
timers.h [changed mode: 0755->0644]
udp.cc [changed mode: 0755->0644]
udp.h [changed mode: 0755->0644]
vchannellist.cc
vcolourtuner.cc
vconnect.cc
vdr.cc
vdr.h
vdrcommand.h
vdrrequestpacket.cc
vdrresponsepacket.cc
vepg.cc
vepgsettimer.cc
vfeed.cc
vfeed.h
video.cc
video.h
videomvp.cc
videomvp.h
videowin.cc
videowin.h
vmediaview.cc
vopts.cc
vradiorec.cc
vrecmove.cc
vrecmove.h
vrecording.cc
vrecordinglist.cc
vscreensaver.h
vsleeptimer.h
vteletextview.cc
vteletextview.h
vtimeredit.cc
vtimerlist.cc
vvideolivetv.cc
vvideomedia.cc
vvideorec.cc
vwelcome.cc
vwelcome.h
wbutton.cc
wbutton.h
wjpeg.cc
wjpeg.h
wol.cc
woptionbox.cc
woptionpane.cc
wselectlist.cc
wselectlist.h
wsymbol.cc
wtabbar.cc

index 88ad464aff85b8551f3482b3c99031dd1bfb988c..112207a7506672444d8cc6310f3a8482886d3b76 100644 (file)
-include ../crosstool/cross-var
-
-CC=$(CROSS)gcc
-STRIP=$(CROSS)strip
-CXX=$(CROSS)g++
-LD=$(CROSS)g++
-
-INCLUDES = -I../jpeg/jpeg-6b
-CXXFLAGS_DEV = -g -O0 -Wall -Wshadow -DDEV -D_GNU_SOURCE $(INCLUDES)
-CXXFLAGS_REL = -O3 -Wall -Wshadow  -D_GNU_SOURCE $(INCLUDES)
-LDFLAGS = -Wall -static
-
-LIBPATHS =
-LIBS = -lpthread -lrt
-CROSSLIBS = ../jpeg/jpeg-6b/libjpeg.a
-
-# This is the only thing windows and linux share
-include objects.mk
-
-OBJECTSMVP = main.o threadp.o remotemvp.o ledmvp.o mtdmvp.o videomvp.o audiomvp.o osdmvp.o surfacemvp.o
-OBJECTSWIN = threadwin.o remotewin.o ledwin.o mtdwin.o videowin.o audiowin.o osdwin.o surfacewin.o
-
-OBJECTS = $(OBJECTS1) $(OBJECTSMVP)
-
-.PHONY: clean fresh all install strip
-
-default: dev
-fresh:   clean default
-
-vompclient: $(OBJECTS) ticonfig.o $(CROSSLIBS)
-       $(LD) $(LDFLAGS) $(LIBPATHS) $(RELEASE) -o vompclient ticonfig.o $(OBJECTS) $(CROSSLIBS) $(LIBS)
-
-# A slight hash up
-ticonfig.o:
-       $(CC) $(CXXFLAGS_REL) -c -o ticonfig.o ticonfig.c
-
-strip:
-       $(STRIP) vompclient
-
-install:
-       rm -f /mnt/auto/defiant/diskless/nfs/mvp/vompclient
-       cp vompclient /mnt/auto/defiant/diskless/nfs/mvp
-
-install-wmp:
-       rm -f /diskless/nfs/wmvp/vompclient
-       cp vompclient /diskless/nfs/wmvp
-
-install-dev:
-       rm -f /mnt/auto/defiant/diskless/nfs/mvp-dev/vompclient
-       cp vompclient /mnt/auto/defiant/diskless/nfs/mvp-dev
-
-debug:
-       ../../gdb/gdb-6.7/gdb/gdb /mnt/auto/defiant/diskless/nfs/mvp/vompclient /mnt/auto/defiant/diskless/nfs/mvp/core.*
-
-debug2:
-       ../../gdb/gdb-6.7/gdb/gdb /mnt/auto/defiant/diskless/nfs/mvp-dev/vompclient /mnt/auto/defiant/diskless/nfs/mvp-dev/core.*
-
-dev: CXXFLAGS := $(CXXFLAGS_DEV)
-dev: vompclient
-
-release: CXXFLAGS := $(CXXFLAGS_REL)
-release: clean vompclient strip
-
-deps: GNUmakefile
-       $(CC) -MM $(INCLUDES) $(OBJECTS:%.o=%.cc) > deps
-
--include deps
-
-clean:
-       rm -f *.o deps vompclient *~ fonts/*.o fonts/*~
-
+vomp_platform =raspberry\r
+# valid platforms are raspberry and mvp\r
+\r
+ifeq ($(vomp_platform),mvp)\r
+\r
+$(info MVP crosscompiler)\r
+include ../crosstool/cross-var\r
+CC=$(CROSS)gcc\r
+STRIP=$(CROSS)strip\r
+CXX=$(CROSS)g++\r
+LD=$(CROSS)g++\r
+\r
+endif\r
+\r
+ifeq ($(vomp_platform),raspberry)\r
+\r
+$(info raspberry normal compiler)\r
+CC=gcc\r
+STRIP=strip\r
+CXX=g++\r
+LD=g++\r
+\r
+endif\r
+\r
+\r
+\r
+CXXFLAGS_DEV = -g -O0 -Wall -Wshadow -DDEV -D_GNU_SOURCE $(INCLUDES)\r
+CXXFLAGS_REL = -O3 -Wall -Wshadow  -D_GNU_SOURCE $(INCLUDES)\r
+\r
+\r
+LIBPATHS =\r
+\r
+\r
+$(info Setting up objects)\r
+# This is the only thing windows and linux share\r
+include objects.mk\r
+\r
+OBJECTSWIN = threadwin.o remotewin.o ledwin.o mtdwin.o videowin.o audiowin.o osdwin.o surfacewin.o\r
+\r
+OBJECTS = $(OBJECTS1) \r
+\r
+\r
+ifeq ($(vomp_platform),mvp)\r
+$(info MVP flags)\r
+LDFLAGS = -Wall -static\r
+LIBS = -lpthread -lrt\r
+\r
+OBJECTS += main.o threadp.o remotemvp.o ledmvp.o mtdmvp.o videomvp.o audiomvp.o osdmvp.o surfacemvp.o vmedialist.o vcolourtuner.o vmediaview.o vvideomedia.o \r
+TIOBJECT = ticonfig.o\r
+CROSSLIBS = ../jpeg/jpeg-6b/libjpeg.a\r
+INCLUDES = -I../jpeg/jpeg-6b -DVOMP_PLATTFORM_MVP\r
+\r
+endif\r
+\r
+ifeq ($(vomp_platform),raspberry)\r
+$(info Raspberry pi flags)\r
+LDFLAGS = -Wall\r
+LIBS = -L/opt/vc/lib -lpthread -lrt -lEGL -lGLESv2 -lbcm_host\r
+\r
+OBJECTS += main.o threadp.o osdopengl.o surfaceopengl.o ledraspberry.o mtdraspberry.o videovpeogl.o audiovpe.o wjpegsimple.o remotelinux.o\r
+LIBS+= -ljpeg\r
+CROSSLIBS =\r
+INCLUDES = -DVOMP_PLATTFORM_RASPBERRY   -I/opt/vc/include \r
+\r
+endif\r
+\r
+.PHONY: clean fresh all install strip\r
+\r
+default: dev\r
+fresh:   clean default\r
+\r
+vompclient: $(OBJECTS) $(TIOBJECT) $(CROSSLIBS)\r
+       $(LD) $(LDFLAGS) $(LIBPATHS) $(RELEASE) -o vompclient $(TIOBJECT) $(OBJECTS) $(CROSSLIBS) $(LIBS)\r
+\r
+# A slight hash up\r
+ticonfig.o:\r
+       $(CC) $(CXXFLAGS_REL) -c -o ticonfig.o ticonfig.c\r
+\r
+strip:\r
+       $(STRIP) vompclient\r
+\r
+install:\r
+       rm -f /mnt/auto/defiant/diskless/nfs/mvp/vompclient\r
+       cp vompclient /mnt/auto/defiant/diskless/nfs/mvp\r
+\r
+install-wmp:\r
+       rm -f /diskless/nfs/wmvp/vompclient\r
+       cp vompclient /diskless/nfs/wmvp\r
+\r
+install-dev:\r
+       rm -f /mnt/auto/defiant/diskless/nfs/mvp-dev/vompclient\r
+       cp vompclient /mnt/auto/defiant/diskless/nfs/mvp-dev\r
+\r
+debug:\r
+       ../../gdb/gdb-6.7/gdb/gdb /mnt/auto/defiant/diskless/nfs/mvp/vompclient /mnt/auto/defiant/diskless/nfs/mvp/core.*\r
+\r
+debug2:\r
+       ../../gdb/gdb-6.7/gdb/gdb /mnt/auto/defiant/diskless/nfs/mvp-dev/vompclient /mnt/auto/defiant/diskless/nfs/mvp-dev/core.*\r
+\r
+dev: CXXFLAGS := $(CXXFLAGS_DEV)\r
+dev: vompclient\r
+\r
+release: CXXFLAGS := $(CXXFLAGS_REL)\r
+release: clean vompclient strip\r
+\r
+deps: GNUmakefile\r
+       $(CC) -MM $(INCLUDES) $(OBJECTS:%.o=%.cc) > deps\r
+\r
+-include deps\r
+\r
+clean:\r
+       rm -f *.o deps vompclient *~ fonts/*.o fonts/*~\r
+\r
index cf2d5ea154da1114733300f40e167baba77ecba9..dbb2fb8e9768191c76919c8b5476590f364fa79d 100644 (file)
@@ -17,7 +17,7 @@ CROSSLIBS =
 !include "objects.mk"
 
 
-OBJECTSWIN = winmain.o threadwin.o remotewin.o ledwin.o mtdwin.o videowin.o audiowin.o osdwin.o surfacewin.o dsallocator.o dssourcefilter.o dssourcepin.o wwinvideofilter.o wwinaudiofilter.o wwinmp3audiofilter.o
+OBJECTSWIN = winmain.o threadwin.o remotewin.o ledwin.o mtdwin.o videowin.o audiowin.o osdwin.o surfacewin.o dsallocator.o dssourcefilter.o dssourcepin.o wwinvideofilter.o wwinaudiofilter.o wwinmp3audiofilter.o wjpegsimple.o
 
 OBJECTS = $(OBJECTS1) $(OBJECTSWIN)
 
index 6c7408c661327a21a67eb2038dc79d428631cf16..586a8f729384b1b480dfbc17b328d68a44738eae 100644 (file)
@@ -21,6 +21,7 @@
 #include "vdr.h"
 #include "option.h"
 
+/*
 bool AbstractOption::loadOptionsfromServer(VDR* vdr)
 {
     return true;
@@ -44,5 +45,5 @@ bool AbstractOption::addOptionsToPanes(int panenumber,Options *options,WOptionPa
 bool AbstractOption::handleOptionChanges(Option* option)
 {
     return false;
-}
+}*/
 
index ac6c5ba6873e17b9f40cf7ef452fa64f32ac1765..a08497c25028fb4b3135cfcbae5fe63f6b90fc07 100644 (file)
@@ -31,11 +31,12 @@ class WOptionPane;
 class AbstractOption
 {
   public:
-    virtual bool loadOptionsfromServer(VDR* vdr);
-    virtual bool saveOptionstoServer();
-    virtual bool addOptionPagesToWTB(WTabBar *wtb);
-    virtual bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane);
-    virtual bool handleOptionChanges(Option* option);
+       // inline definition allows plugins architecture for audio video
+    virtual bool loadOptionsfromServer(VDR* vdr) {return true;};
+    virtual bool saveOptionstoServer() {return true;};
+    virtual bool addOptionPagesToWTB(WTabBar *wtb) {return true;};
+    virtual bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane) {return true;};
+    virtual bool handleOptionChanges(Option* option){return false;};
 };
 
 #endif
index 43e8c865660be0861d74fcb222f812ffb202c887..4da46c7ac1a9fd5a80cac87bed671964a28d10e2 100644 (file)
--- a/afeed.cc
+++ b/afeed.cc
@@ -1,97 +1,98 @@
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "afeed.h"
-
-#include "log.h"
-#include "demuxer.h"
-#include "callback.h"
-
-AFeed::AFeed(Callback* tcb)
-: cb(*tcb)
-{
-  audioEnabled = 1;
-}
-
-int AFeed::init()
-{
-  return 1;
-}
-
-int AFeed::shutdown()
-{
-  // FIXME
-  return 1;
-}
-
-void AFeed::disable()
-{
-  audioEnabled = 0;
-}
-
-void AFeed::enable()
-{
-  audioEnabled = 1;
-}
-
-int AFeed::start()
-{
-  audioEnabled = 1;
-  return threadStart();
-}
-
-void AFeed::stop()
-{
-  threadCancel();
-}
-
-void AFeed::threadMethod()
-{
-  bool alen;
-
-  while(1)
-  {
-    threadCheckExit();
-
-    if (audioEnabled)
-    {
-      alen = Demuxer::getInstance()->writeAudio();
-
-      if (alen)
-      {
-          cb.call(this);
-//        Log::getInstance()->log("Afeed", Log::DEBUG, "written");
-      }
-      else
-      {
-        //MILLISLEEP(100);
-        MILLISLEEP(5); //Performance Issue Marten
-      }
-    }
-    else
-    {
-      Demuxer::getInstance()->flushAudio();
-      //Log::getInstance()->log("AFeed", Log::DEBUG, "No data delay");
-      //MILLISLEEP(100);
-      MILLISLEEP(5); //Performance Issue
-    }
-  }
-}
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "afeed.h"\r
+\r
+#include "log.h"\r
+#include "demuxer.h"\r
+#include "callback.h"\r
+\r
+\r
+AFeed::AFeed(Callback* tcb)\r
+: cb(*tcb)\r
+{\r
+  audioEnabled = 1;\r
+}\r
+\r
+int AFeed::init()\r
+{\r
+  return 1;\r
+}\r
+\r
+int AFeed::shutdown()\r
+{\r
+  // FIXME\r
+  return 1;\r
+}\r
+\r
+void AFeed::disable()\r
+{\r
+  audioEnabled = 0;\r
+}\r
+\r
+void AFeed::enable()\r
+{\r
+  audioEnabled = 1;\r
+}\r
+\r
+int AFeed::start()\r
+{\r
+  audioEnabled = 1;\r
+  return threadStart();\r
+}\r
+\r
+void AFeed::stop()\r
+{\r
+  threadCancel();\r
+}\r
+\r
+void AFeed::threadMethod()\r
+{\r
+  bool alen;\r
+\r
+  while(1)\r
+  {\r
+    threadCheckExit();\r
+\r
+    if (audioEnabled)\r
+    {\r
+      alen = Demuxer::getInstance()->writeAudio();\r
+\r
+      if (alen)\r
+      {\r
+          cb.call(this);\r
+//        Log::getInstance()->log("Afeed", Log::DEBUG, "written");\r
+      }\r
+      else\r
+      {\r
+        //MILLISLEEP(100);\r
+        MILLISLEEP(5); //Performance Issue Marten\r
+      }\r
+    }\r
+    else\r
+    {\r
+      Demuxer::getInstance()->flushAudio();\r
+      //Log::getInstance()->log("AFeed", Log::DEBUG, "No data delay");\r
+      //MILLISLEEP(100);\r
+      MILLISLEEP(5); //Performance Issue\r
+    }\r
+  }\r
+}\r
+\r
diff --git a/afeed.h b/afeed.h
index 599d9cb15394c3694d6174ef42250c855b88637d..69ca1338cd129a878483ef68e1ea9bab49e6bc3c 100644 (file)
--- a/afeed.h
+++ b/afeed.h
 #include <stdio.h>
 #include <time.h>
 
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
+
+#include "threadsystem.h"
 
 class Callback;
 
@@ -49,6 +46,7 @@ class AFeed : public Thread_TYPE
     void threadMethod();
     void threadPostStopCleanup() {};
     int audioEnabled;
+    bool callbacksend;
     Callback& cb;
 };
 
index ab2d4dfc6710f01d94097af8647b1789a4c73e40..aa02ec4198886ce69ba69c00eb9834648477a166 100644 (file)
--- a/audio.cc
+++ b/audio.cc
@@ -42,6 +42,11 @@ Audio* Audio::getInstance()
 {
   return instance;
 }
+/*
+void Audio::setInstance(Audio* inst)
+{
+  instance=inst;
+}*/
 
 int Audio::volumeUp()
 {
diff --git a/audio.h b/audio.h
index 082bc27bff0592a43011ec49173fb1a125ce9488..ab0a213a6c40e6a2e8ed80ef71693a2d23e540fd 100644 (file)
--- a/audio.h
+++ b/audio.h
@@ -1,91 +1,92 @@
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef AUDIO_H
-#define AUDIO_H
-
-#include <stdio.h>
-#include "defines.h"
-#include "draintarget.h"
-#include "abstractoption.h"
-
-typedef struct
-{
-    unsigned char frontleft;
-    unsigned char frontright;
-    unsigned char rearleft;
-    unsigned char rearright;
-    unsigned char center;
-    unsigned char lfe;
-} audio_volume;
-
-class Audio : public DrainTarget, public AbstractOption
-{
-  public:
-    Audio();
-    virtual ~Audio();
-    static Audio* getInstance();
-
-    virtual int init(UCHAR streamType)=0;
-    virtual int shutdown()=0;
-    virtual int setStreamType(UCHAR streamType)=0;
-    virtual int setChannel()=0;
-    virtual int setSource()=0;
-    virtual int sync()=0;
-    virtual int play()=0;
-    virtual int stop()=0;
-    virtual int pause()=0;
-    virtual int unPause()=0;
-    virtual int reset()=0;
-    virtual int setVolume(int volume)=0;
-    virtual int mute()=0;
-    virtual int unMute()=0;
-    virtual bool supportsAc3()=0;
-    virtual bool maysupportAc3(){return false;}
-
-    int volumeUp();
-    int volumeDown();
-    int getVolume();
-    int toggleUserMute();
-    int systemMuteOn();
-    int systemMuteOff();
-    int doMuting();
-
-    // Audio stream type  // FIXME these are MVP specific (probably!)
-    const static UCHAR MPEG2_PES = 2;
-    const static UCHAR MPEG1_PES = 3; // unused
-    const static UCHAR MP3 = 0;  //media player
-
-#ifdef DEV
-    virtual int test()=0;
-#endif
-
-  protected:
-    static Audio* instance;
-    int initted;
-    UCHAR userMute;
-    UCHAR systemMute;
-    UCHAR muted;
-    int volume;
-
-    audio_volume Aoffset;
-};
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef AUDIO_H\r
+#define AUDIO_H\r
+\r
+#include <stdio.h>\r
+#include "defines.h"\r
+#include "draintarget.h"\r
+#include "abstractoption.h"\r
+\r
+typedef struct\r
+{\r
+    unsigned char frontleft;\r
+    unsigned char frontright;\r
+    unsigned char rearleft;\r
+    unsigned char rearright;\r
+    unsigned char center;\r
+    unsigned char lfe;\r
+} audio_volume;\r
+\r
+class Audio : public DrainTarget, public AbstractOption\r
+{\r
+  public:\r
+    Audio();\r
+    virtual ~Audio();\r
+    static Audio* getInstance();\r
+   // static void setInstance(Audio* );\r
+\r
+    virtual int init(UCHAR streamType)=0;\r
+    virtual int shutdown()=0;\r
+    virtual int setStreamType(UCHAR streamType)=0;\r
+    virtual int setChannel()=0;\r
+    virtual int setSource()=0;\r
+    virtual int sync()=0;\r
+    virtual int play()=0;\r
+    virtual int stop()=0;\r
+    virtual int pause()=0;\r
+    virtual int unPause()=0;\r
+    virtual int reset()=0;\r
+    virtual int setVolume(int volume)=0;\r
+    virtual int mute()=0;\r
+    virtual int unMute()=0;\r
+    virtual bool supportsAc3()=0;\r
+    virtual bool maysupportAc3(){return false;}\r
+\r
+    int volumeUp();\r
+    int volumeDown();\r
+    int getVolume();\r
+    int toggleUserMute();\r
+    int systemMuteOn();\r
+    int systemMuteOff();\r
+    int doMuting();\r
+\r
+    // Audio stream type  // FIXME these are MVP specific (probably!)\r
+    const static UCHAR MPEG2_PES = 2;\r
+    const static UCHAR MPEG1_PES = 3; // unused\r
+    const static UCHAR MP3 = 0;  //media player\r
+\r
+#ifdef DEV\r
+    virtual int test()=0;\r
+#endif\r
+\r
+  protected:\r
+    static Audio* instance;\r
+    int initted;\r
+    UCHAR userMute;\r
+    UCHAR systemMute;\r
+    UCHAR muted;\r
+    int volume;\r
+\r
+    audio_volume Aoffset;\r
+};\r
+\r
+#endif\r
index aeb8347c2dbb76964e2fc34559493bf505ed644a..2079b1d68c0b8e9beba454cc6d89c8b9106b05ae 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "audiowin.h"
-#include "videowin.h"
-#include "vdr.h"
-#include "wtabbar.h"
-#include "wwinaudiofilter.h"
-#include "wwinmp3audiofilter.h"
-#include "i18n.h"
-
-
-
-
-AudioWin::AudioWin()
-{
-  initted = 0;
-  firstsynched=false;
-  winvolume=0;
-  volume=20;
-audiofilterselected=-1;
-  mp3audiofilterselected=-1;
-  aud_type=Audio::MPEG2_PES;
-
-}
-
-AudioWin::~AudioWin()
-{
-
-  int i;
-  for (i=0;i<audiofilterlist.size();i++)
-  {
-   if (audiofilterlist[i].displayname) delete [] audiofilterlist[i].displayname;
-   if (audiofilterlist[i].friendlyname) delete [] audiofilterlist[i].friendlyname;
-  }
-  audiofilterlist.clear();
-
-  for (i=0;i<mp3audiofilterlist.size();i++)
-  {
-   if (mp3audiofilterlist[i].displayname) delete [] mp3audiofilterlist[i].displayname;
-   if (mp3audiofilterlist[i].friendlyname) delete [] mp3audiofilterlist[i].friendlyname;
-  }
-  mp3audiofilterlist.clear();
-
-}
-
-int AudioWin::init(UCHAR tstreamType)
-{
-  if (initted) return 0;
-  initFilterDatabase();
-  initMp3FilterDatabase();
-  initted = 1;
-  return 1;
-}
-
-int AudioWin::shutdown()
-{
-  if (!initted) return 0;
-  initted = 0;
-  return 1;
-}
-
-int AudioWin::write(char *buf, int len)
-{
-  return 0; //write(fdAudio, buf, len);
-}
-
-int AudioWin::setStreamType(UCHAR type)
-{
-  ((VideoWin*)VideoWin::getInstance())->setAudioStreamType(type);
-  aud_type=type;
-  if (!initted) return 0;
-  return 1;
-}
-
-int AudioWin::setChannel()
-{
-  if (!initted) return 0;
-  return 1;
-}
-
-int AudioWin::setSource()
-{
-  if (!initted) return 0;
-  return 1;
-}
-
-int AudioWin::sync()
-{
-  if (!initted) return 0;
-  return 1;
-}
-
-int AudioWin::play()
-{
-  if (!initted) return 0;
-  firstsynched=false;
-  return ((VideoWin*)Video::getInstance())->dsplay();
-
-}
-
-int AudioWin::stop()
-{
-  if (!initted) return 0;
-  return ((VideoWin*)Video::getInstance())->dsstop();
-}
-
-int AudioWin::pause()
-{
-  if (!initted) return 0;
-  return ((VideoWin*)Video::getInstance())->dspause();
-}
-
-int AudioWin::unPause()
-{
-  if (!initted) return 0;
-  return ((VideoWin*)Video::getInstance())->dsunPause();
-}
-
-int AudioWin::reset()
-{
-  
-  if (!initted){return 0;}
-  return ((VideoWin*)Video::getInstance())->dsreset();
-}
-
-int AudioWin::setVolume(int tvolume)
-{
-  // parameter: 0 for silence, 20 for full
-  if ((tvolume < 0) || (tvolume > 20)) return 0;
-  winvolume=((tvolume-20)*100*30)/20;
-  if (tvolume==0) winvolume=-10000;
-  ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);
-
-
-  return 1;
-}
-
-int AudioWin::mute()
-{
-  if (!initted) return 0;
-  ((VideoWin*)Video::getInstance())->SetAudioState(false);
-  ((VideoWin*)Video::getInstance())->SetAudioVolume(-10000);
-  return 1;
-}
-
-int AudioWin::unMute()
-{
-  if (!initted) return 0;
-  ((VideoWin*)Video::getInstance())->SetAudioState(true);
-  ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);
-  return 1;
-}
-
-void AudioWin::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)
-{
-  mediapacket = mplist.front();
-}
-
-void AudioWin::initFilterDatabase()
-{
-     /* This method should determine all availiable DirectShow Filters */
-    IFilterMapper2* filtmap=NULL;
-    HRESULT result;
-    result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
-                IID_IFilterMapper2,(void**)&filtmap);
-    if (result != S_OK)
-    {
-        Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");
-        return;
-    }
-    /* Wishlist, what Mediatypes do we want */
-    GUID mtypesin[]={MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO,
-    /*MEDIATYPE_Audio,MEDIASUBTYPE_MPEG1Payload,*/
-    MEDIATYPE_Audio,MEDIASUBTYPE_DOLBY_AC3,
-     MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3_SPDIF};
-    IEnumMoniker *myenum;
-    result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
-                    TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
-    if (result != S_OK)
-    {
-        filtmap->Release();
-        Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");
-        return;
-    }
-    ULONG gethowmany;
-    IMoniker * moni;
-    while(myenum->Next(1,&moni,&gethowmany)==S_OK)
-    {
-        AudioFilterDesc desc;
-        ZeroMemory(&desc,sizeof(desc));
-   
-        LPOLESTR string;
-        moni->GetDisplayName(0,0,&string);
-        desc.displayname=new char[wcslen(string)+1];
-        wcstombs(desc.displayname,string,wcslen(string)+1);
-        CoTaskMemFree(string);
-        IPropertyBag *bag;
-        if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
-        {
-            VARIANT vari;
-            VariantInit(&vari);
-            result = bag->Read(L"FriendlyName",&vari,NULL);
-            if (result == S_OK)
-            {
-                desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
-                wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
-            }
-            VariantClear(&vari);
-            bag->Release();
-
-        }
-        
-       
-        audiofilterlist.push_back(desc);
-       
-
-        
-        moni->Release();
-       // bctx->Release();
-    }
-    int i;
-    audiofilterselected=-1;
-    myenum->Release();
-    filtmap->Release();
-}
-
-void AudioWin::initMp3FilterDatabase()
-{
-     /* This method should determine all availiable DirectShow Filters */
-    IFilterMapper2* filtmap=NULL;
-    HRESULT result;
-    result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
-                IID_IFilterMapper2,(void**)&filtmap);
-    if (result != S_OK)
-    {
-        Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");
-        return;
-    }
-    /* Wishlist, what Mediatypes do we want */
-    GUID mtypesin[]={MEDIATYPE_Audio,MEDIATYPE_WaveFmt_Mpeg1Layer3,
-                    MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO};
-    IEnumMoniker *myenum;
-    result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
-                    TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
-    if (result != S_OK)
-    {
-        filtmap->Release();
-        Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");
-        return;
-    }
-    ULONG gethowmany;
-    IMoniker * moni;
-    while(myenum->Next(1,&moni,&gethowmany)==S_OK)
-    {
-        AudioFilterDesc desc;
-        ZeroMemory(&desc,sizeof(desc));
-   
-        LPOLESTR string;
-        moni->GetDisplayName(0,0,&string);
-        desc.displayname=new char[wcslen(string)+1];
-        wcstombs(desc.displayname,string,wcslen(string)+1);
-        CoTaskMemFree(string);
-        IPropertyBag *bag;
-        if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
-        {
-            VARIANT vari;
-            VariantInit(&vari);
-            result = bag->Read(L"FriendlyName",&vari,NULL);
-            if (result == S_OK)
-            {
-                desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
-                wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
-            }
-            VariantClear(&vari);
-            bag->Release();
-
-        }
-        
-       
-        mp3audiofilterlist.push_back(desc);
-       
-
-        
-        moni->Release();
-       // bctx->Release();
-    }
-    int i;
-    mp3audiofilterselected=-1;
-    myenum->Release();
-    filtmap->Release();
-}
-
-bool AudioWin::loadOptionsfromServer(VDR* vdr)
-{
-    char *name=vdr->configLoad("DirectShow","AudioFilter");
-    
-    if (name != NULL) 
-    {
-        for (int i = 0;i <audiofilterlist.size();i++)
-        {
-            if (strcmp(name,audiofilterlist[i].displayname)==0)
-            {
-                audiofilterselected = i;
-                break;
-            }
-        }
-   }
-    name=vdr->configLoad("DirectShow","Mp3AudioFilter");
-    
-    if (name != NULL) 
-    {
-        for (int i = 0;i <mp3audiofilterlist.size();i++)
-        {
-            if (strcmp(name,mp3audiofilterlist[i].displayname)==0)
-            {
-                mp3audiofilterselected = i;
-                break;
-            }
-        }
-   }
-   return true;
-
-}
-
-bool AudioWin::saveOptionstoServer()
-{
-    if (audiofilterselected!=-1) {
-        VDR::getInstance()->configSave("DirectShow",
-            "AudioFilter",audiofilterlist[audiofilterselected].displayname);
-    }
-    if (mp3audiofilterselected!=-1) {
-        VDR::getInstance()->configSave("DirectShow",
-            "Mp3AudioFilter",mp3audiofilterlist[mp3audiofilterselected].displayname);
-    }
-    return true;
-}
-
-UINT AudioWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)
-{
-  DeliverMediaPacket(mediapacket, buffer, samplepos);
-  if (*samplepos == mediapacket.length) {
-    *samplepos = 0;
-    return 1;
-  }
-  else return 0;
-}
-
-UINT AudioWin::DeliverMediaPacket(const MediaPacket packet,
-     UCHAR* buffer,
-     UINT *samplepos)
-{
-
-  /*First Check, if we have an audio sample*/
-  VideoWin *vw=(VideoWin*)Video::getInstance();
- if (!vw->isdsinited()) return 0;
-  if (vw->InIframemode()) {
-               samplepos=0;
-               MILLISLEEP(10);
-               return 0; //Not in iframe mode!
-  }
-  IMediaSample* ms=NULL;
-  REFERENCE_TIME reftime1=0;
-  REFERENCE_TIME reftime2=0;
-
-  UINT headerstrip=0;
-  if (packet.disconti) {
-    firstsynched=false;
-    vw->DeliverAudioMediaSample();
-  }
-
-  if (packet.type!=vw->lastAType()){//Format Change //Push data out !
-      firstsynched=false;
-      vw->DeliverAudioMediaSample();
-  }
-
-
-
-  /*Inspect PES-Header */
-/*  UINT header_length=buffer[(packet.pos_buffer+8)%bufferlength]+8/*is this right*;
-*/
-  if (*samplepos==0 && packet.type!=MPTYPE_MPEG_AUDIO_LAYER3) {//stripheader
-      headerstrip=buffer[packet.pos_buffer+8]+9;
-    if (packet.type == MPTYPE_AC3) headerstrip+=4; //skip ac3 bytes
-    *samplepos+=headerstrip;
-    if ( packet.synched ) {
-      vw->DeliverAudioMediaSample();//write out old data
-      reftime1=packet.presentation_time;
-      reftime2=reftime1+1;
-      firstsynched=true;
-    } else {
-      if (!firstsynched) {//
-        *samplepos=packet.length;//if we have not processed at least one
-        return packet.length;//synched packet ignore it!
-      }
-    }
-  }
-  BYTE *ms_buf;
-  UINT ms_length;
-  UINT ms_pos;
-  UINT haveToCopy;
-  if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample
-    //samplepos=0;
-    //MILLISLEEP(10);
-    return *samplepos;
-  }
-  ms_pos=ms->GetActualDataLength();
-  ms_length=ms->GetSize();
-  haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
-  if ((ms_length-ms_pos)<1) {
-    vw->DeliverAudioMediaSample(); //we are full!
-    if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample
-      //samplepos=0;
-      //MILLISLEEP(10);
-      return *samplepos;
-    }
-    ms_pos=ms->GetActualDataLength();
-    ms_length=ms->GetSize();
-    haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
-  }
-  ms->GetPointer(&ms_buf);
-
-
-  if (ms_pos==0) {//will only be changed on first packet
-    if (packet.disconti) {
-      ms->SetDiscontinuity(TRUE);
-    } else {
-      ms->SetDiscontinuity(FALSE);
-    }
-    if (packet.synched) {
-      ms->SetSyncPoint(TRUE);
-      ms->SetTime(&reftime1,&reftime2);
-
-      //ms->SetTime(NULL,NULL);
-      ms->SetMediaTime(NULL, NULL);
-    if (reftime1<0) ms->SetPreroll(TRUE);
-    else ms->SetPreroll(FALSE);
-    }else {
-      ms->SetSyncPoint(FALSE);
-      ms->SetTime(NULL,NULL);
-      ms->SetMediaTime(NULL, NULL);
-    ms->SetPreroll(FALSE);
-    //  ms->SetSyncPoint(TRUE);
-    }
-  }
-  if (packet.type!=vw->lastAType()) {
-      vw->changeAType(packet.type,ms);
-      ms->SetDiscontinuity(TRUE);
-  }
-
-
-  memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
-
-    ms->SetActualDataLength(haveToCopy+ms_pos);
-
-  *samplepos+=haveToCopy;
-
-  return haveToCopy+headerstrip;
-
-}
-
-int AudioWin::dsInitAudioFilter(IGraphBuilder* dsgraphbuilder)
-{
-    HRESULT hres;
-    IFilterGraph2*fg2=NULL;
-    VideoWin *vw=(VideoWin*)Video::getInstance();
-    if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK)
-    {
-        Log::getInstance()->log("AudiooWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
-        return 0;
-    }
-    IBaseFilter*audiofilter;
-    if (aud_type!=Audio::MP3) {
-        audiofilter = getAudioFilter();
-    } else {
-        audiofilter = getMp3AudioFilter();
-    }
-    if (hres=dsgraphbuilder->AddFilter(audiofilter,NULL) != S_OK) 
-    {
-        Log::getInstance()->log("AudioWin", Log::WARN , "Failed adding Video Filter!");
-        return 0;
-    }
-    IEnumPins *pinenum=NULL;
-    bool error=false;
-    if (audiofilter->EnumPins(&pinenum) == S_OK)
-    {
-        IPin *current=NULL;
-        ULONG fetch=0;
-        bool firststep=false;
-        while (pinenum->Next(1,&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();
-  return vw->ResetTimeOffsets();
-}
-
-bool AudioWin::supportsAc3(){
-    VideoWin *vw=(VideoWin*)Video::getInstance();
-    return vw->supportsAc3();
-}
-
-#ifdef DEV
-int AudioWin::test()
-{
-  return 0;
-}
-#endif
-
-
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "audiowin.h"\r
+#include "videowin.h"\r
+#include "vdr.h"\r
+#include "wtabbar.h"\r
+#include "wwinaudiofilter.h"\r
+#include "wwinmp3audiofilter.h"\r
+#include "i18n.h"\r
+\r
+\r
+\r
+\r
+AudioWin::AudioWin()\r
+{\r
+  initted = 0;\r
+  firstsynched=false;\r
+  winvolume=0;\r
+  volume=20;\r
+audiofilterselected=-1;\r
+  mp3audiofilterselected=-1;\r
+  aud_type=Audio::MPEG2_PES;\r
+\r
+}\r
+\r
+AudioWin::~AudioWin()\r
+{\r
+\r
+  int i;\r
+  for (i=0;i<audiofilterlist.size();i++)\r
+  {\r
+   if (audiofilterlist[i].displayname) delete [] audiofilterlist[i].displayname;\r
+   if (audiofilterlist[i].friendlyname) delete [] audiofilterlist[i].friendlyname;\r
+  }\r
+  audiofilterlist.clear();\r
+\r
+  for (i=0;i<mp3audiofilterlist.size();i++)\r
+  {\r
+   if (mp3audiofilterlist[i].displayname) delete [] mp3audiofilterlist[i].displayname;\r
+   if (mp3audiofilterlist[i].friendlyname) delete [] mp3audiofilterlist[i].friendlyname;\r
+  }\r
+  mp3audiofilterlist.clear();\r
+\r
+}\r
+\r
+int AudioWin::init(UCHAR tstreamType)\r
+{\r
+  if (initted) return 0;\r
+  initFilterDatabase();\r
+  initMp3FilterDatabase();\r
+  initted = 1;\r
+  return 1;\r
+}\r
+\r
+int AudioWin::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+  initted = 0;\r
+  return 1;\r
+}\r
+\r
+int AudioWin::write(char *buf, int len)\r
+{\r
+  return 0; //write(fdAudio, buf, len);\r
+}\r
+\r
+int AudioWin::setStreamType(UCHAR type)\r
+{\r
+  ((VideoWin*)VideoWin::getInstance())->setAudioStreamType(type);\r
+  aud_type=type;\r
+  if (!initted) return 0;\r
+  return 1;\r
+}\r
+\r
+int AudioWin::setChannel()\r
+{\r
+  if (!initted) return 0;\r
+  return 1;\r
+}\r
+\r
+int AudioWin::setSource()\r
+{\r
+  if (!initted) return 0;\r
+  return 1;\r
+}\r
+\r
+int AudioWin::sync()\r
+{\r
+  if (!initted) return 0;\r
+  return 1;\r
+}\r
+\r
+int AudioWin::play()\r
+{\r
+  if (!initted) return 0;\r
+  firstsynched=false;\r
+  return ((VideoWin*)Video::getInstance())->dsplay();\r
+\r
+}\r
+\r
+int AudioWin::stop()\r
+{\r
+  if (!initted) return 0;\r
+  return ((VideoWin*)Video::getInstance())->dsstop();\r
+}\r
+\r
+int AudioWin::pause()\r
+{\r
+  if (!initted) return 0;\r
+  return ((VideoWin*)Video::getInstance())->dspause();\r
+}\r
+\r
+int AudioWin::unPause()\r
+{\r
+  if (!initted) return 0;\r
+  return ((VideoWin*)Video::getInstance())->dsunPause();\r
+}\r
+\r
+int AudioWin::reset()\r
+{\r
+  \r
+  if (!initted){return 0;}\r
+  return ((VideoWin*)Video::getInstance())->dsreset();\r
+}\r
+\r
+int AudioWin::setVolume(int tvolume)\r
+{\r
+  // parameter: 0 for silence, 20 for full\r
+  if ((tvolume < 0) || (tvolume > 20)) return 0;\r
+  winvolume=((tvolume-20)*100*30)/20;\r
+  if (tvolume==0) winvolume=-10000;\r
+  ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);\r
+\r
+\r
+  return 1;\r
+}\r
+\r
+int AudioWin::mute()\r
+{\r
+  if (!initted) return 0;\r
+  ((VideoWin*)Video::getInstance())->SetAudioState(false);\r
+  ((VideoWin*)Video::getInstance())->SetAudioVolume(-10000);\r
+  return 1;\r
+}\r
+\r
+int AudioWin::unMute()\r
+{\r
+  if (!initted) return 0;\r
+  ((VideoWin*)Video::getInstance())->SetAudioState(true);\r
+  ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);\r
+  return 1;\r
+}\r
+\r
+void AudioWin::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)\r
+{\r
+  mediapacket = mplist.front();\r
+}\r
+\r
+void AudioWin::initFilterDatabase()\r
+{\r
+     /* This method should determine all availiable DirectShow Filters */\r
+    IFilterMapper2* filtmap=NULL;\r
+    HRESULT result;\r
+    result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,\r
+                IID_IFilterMapper2,(void**)&filtmap);\r
+    if (result != S_OK)\r
+    {\r
+        Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");\r
+        return;\r
+    }\r
+    /* Wishlist, what Mediatypes do we want */\r
+    GUID mtypesin[]={MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO,\r
+    /*MEDIATYPE_Audio,MEDIASUBTYPE_MPEG1Payload,*/\r
+    MEDIATYPE_Audio,MEDIASUBTYPE_DOLBY_AC3,\r
+     MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3_SPDIF};\r
+    IEnumMoniker *myenum;\r
+    result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,\r
+                    TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);\r
+    if (result != S_OK)\r
+    {\r
+        filtmap->Release();\r
+        Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");\r
+        return;\r
+    }\r
+    ULONG gethowmany;\r
+    IMoniker * moni;\r
+    while(myenum->Next(1,&moni,&gethowmany)==S_OK)\r
+    {\r
+        AudioFilterDesc desc;\r
+        ZeroMemory(&desc,sizeof(desc));\r
+   \r
+        LPOLESTR string;\r
+        moni->GetDisplayName(0,0,&string);\r
+        desc.displayname=new char[wcslen(string)+1];\r
+        wcstombs(desc.displayname,string,wcslen(string)+1);\r
+        CoTaskMemFree(string);\r
+        IPropertyBag *bag;\r
+        if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)\r
+        {\r
+            VARIANT vari;\r
+            VariantInit(&vari);\r
+            result = bag->Read(L"FriendlyName",&vari,NULL);\r
+            if (result == S_OK)\r
+            {\r
+                desc.friendlyname=new char[wcslen(vari.bstrVal)+1];\r
+                wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);\r
+            }\r
+            VariantClear(&vari);\r
+            bag->Release();\r
+\r
+        }\r
+        \r
+       \r
+        audiofilterlist.push_back(desc);\r
+       \r
+\r
+        \r
+        moni->Release();\r
+       // bctx->Release();\r
+    }\r
+    int i;\r
+    audiofilterselected=-1;\r
+    myenum->Release();\r
+    filtmap->Release();\r
+}\r
+\r
+void AudioWin::initMp3FilterDatabase()\r
+{\r
+     /* This method should determine all availiable DirectShow Filters */\r
+    IFilterMapper2* filtmap=NULL;\r
+    HRESULT result;\r
+    result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,\r
+                IID_IFilterMapper2,(void**)&filtmap);\r
+    if (result != S_OK)\r
+    {\r
+        Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");\r
+        return;\r
+    }\r
+    /* Wishlist, what Mediatypes do we want */\r
+    GUID mtypesin[]={MEDIATYPE_Audio,MEDIATYPE_WaveFmt_Mpeg1Layer3,\r
+                    MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO};\r
+    IEnumMoniker *myenum;\r
+    result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,\r
+                    TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);\r
+    if (result != S_OK)\r
+    {\r
+        filtmap->Release();\r
+        Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");\r
+        return;\r
+    }\r
+    ULONG gethowmany;\r
+    IMoniker * moni;\r
+    while(myenum->Next(1,&moni,&gethowmany)==S_OK)\r
+    {\r
+        AudioFilterDesc desc;\r
+        ZeroMemory(&desc,sizeof(desc));\r
+   \r
+        LPOLESTR string;\r
+        moni->GetDisplayName(0,0,&string);\r
+        desc.displayname=new char[wcslen(string)+1];\r
+        wcstombs(desc.displayname,string,wcslen(string)+1);\r
+        CoTaskMemFree(string);\r
+        IPropertyBag *bag;\r
+        if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)\r
+        {\r
+            VARIANT vari;\r
+            VariantInit(&vari);\r
+            result = bag->Read(L"FriendlyName",&vari,NULL);\r
+            if (result == S_OK)\r
+            {\r
+                desc.friendlyname=new char[wcslen(vari.bstrVal)+1];\r
+                wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);\r
+            }\r
+            VariantClear(&vari);\r
+            bag->Release();\r
+\r
+        }\r
+        \r
+       \r
+        mp3audiofilterlist.push_back(desc);\r
+       \r
+\r
+        \r
+        moni->Release();\r
+       // bctx->Release();\r
+    }\r
+    int i;\r
+    mp3audiofilterselected=-1;\r
+    myenum->Release();\r
+    filtmap->Release();\r
+}\r
+\r
+bool AudioWin::loadOptionsfromServer(VDR* vdr)\r
+{\r
+    char *name=vdr->configLoad("DirectShow","AudioFilter");\r
+    \r
+    if (name != NULL) \r
+    {\r
+        for (int i = 0;i <audiofilterlist.size();i++)\r
+        {\r
+            if (strcmp(name,audiofilterlist[i].displayname)==0)\r
+            {\r
+                audiofilterselected = i;\r
+                break;\r
+            }\r
+        }\r
+   }\r
+    name=vdr->configLoad("DirectShow","Mp3AudioFilter");\r
+    \r
+    if (name != NULL) \r
+    {\r
+        for (int i = 0;i <mp3audiofilterlist.size();i++)\r
+        {\r
+            if (strcmp(name,mp3audiofilterlist[i].displayname)==0)\r
+            {\r
+                mp3audiofilterselected = i;\r
+                break;\r
+            }\r
+        }\r
+   }\r
+   return true;\r
+\r
+}\r
+\r
+bool AudioWin::saveOptionstoServer()\r
+{\r
+    if (audiofilterselected!=-1) {\r
+        VDR::getInstance()->configSave("DirectShow",\r
+            "AudioFilter",audiofilterlist[audiofilterselected].displayname);\r
+    }\r
+    if (mp3audiofilterselected!=-1) {\r
+        VDR::getInstance()->configSave("DirectShow",\r
+            "Mp3AudioFilter",mp3audiofilterlist[mp3audiofilterselected].displayname);\r
+    }\r
+    return true;\r
+}\r
+\r
+UINT AudioWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)\r
+{\r
+  DeliverMediaPacket(mediapacket, buffer, samplepos);\r
+  if (*samplepos == mediapacket.length) {\r
+    *samplepos = 0;\r
+    return 1;\r
+  }\r
+  else return 0;\r
+}\r
+\r
+UINT AudioWin::DeliverMediaPacket(const MediaPacket packet,\r
+     UCHAR* buffer,\r
+     UINT *samplepos)\r
+{\r
+\r
+  /*First Check, if we have an audio sample*/\r
+  VideoWin *vw=(VideoWin*)Video::getInstance();\r
+ if (!vw->isdsinited()) return 0;\r
+  if (vw->InIframemode()) {\r
+               samplepos=0;\r
+               MILLISLEEP(10);\r
+               return 0; //Not in iframe mode!\r
+  }\r
+  IMediaSample* ms=NULL;\r
+  REFERENCE_TIME reftime1=0;\r
+  REFERENCE_TIME reftime2=0;\r
+\r
+  UINT headerstrip=0;\r
+  if (packet.disconti) {\r
+    firstsynched=false;\r
+    vw->DeliverAudioMediaSample();\r
+  }\r
+\r
+  if (packet.type!=vw->lastAType()){//Format Change //Push data out !\r
+      firstsynched=false;\r
+      vw->DeliverAudioMediaSample();\r
+  }\r
+\r
+\r
+\r
+  /*Inspect PES-Header */\r
+/*  UINT header_length=buffer[(packet.pos_buffer+8)%bufferlength]+8/*is this right*;\r
+*/\r
+  if (*samplepos==0 && packet.type!=MPTYPE_MPEG_AUDIO_LAYER3) {//stripheader\r
+      headerstrip=buffer[packet.pos_buffer+8]+9;\r
+    if (packet.type == MPTYPE_AC3) headerstrip+=4; //skip ac3 bytes\r
+    *samplepos+=headerstrip;\r
+    if ( packet.synched ) {\r
+      vw->DeliverAudioMediaSample();//write out old data\r
+      reftime1=packet.presentation_time;\r
+      reftime2=reftime1+1;\r
+      firstsynched=true;\r
+    } else {\r
+      if (!firstsynched) {//\r
+        *samplepos=packet.length;//if we have not processed at least one\r
+        return packet.length;//synched packet ignore it!\r
+      }\r
+    }\r
+  }\r
+  BYTE *ms_buf;\r
+  UINT ms_length;\r
+  UINT ms_pos;\r
+  UINT haveToCopy;\r
+  if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample\r
+    //samplepos=0;\r
+    //MILLISLEEP(10);\r
+    return *samplepos;\r
+  }\r
+  ms_pos=ms->GetActualDataLength();\r
+  ms_length=ms->GetSize();\r
+  haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);\r
+  if ((ms_length-ms_pos)<1) {\r
+    vw->DeliverAudioMediaSample(); //we are full!\r
+    if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample\r
+      //samplepos=0;\r
+      //MILLISLEEP(10);\r
+      return *samplepos;\r
+    }\r
+    ms_pos=ms->GetActualDataLength();\r
+    ms_length=ms->GetSize();\r
+    haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);\r
+  }\r
+  ms->GetPointer(&ms_buf);\r
+\r
+\r
+  if (ms_pos==0) {//will only be changed on first packet\r
+    if (packet.disconti) {\r
+      ms->SetDiscontinuity(TRUE);\r
+    } else {\r
+      ms->SetDiscontinuity(FALSE);\r
+    }\r
+    if (packet.synched) {\r
+      ms->SetSyncPoint(TRUE);\r
+      ms->SetTime(&reftime1,&reftime2);\r
+\r
+      //ms->SetTime(NULL,NULL);\r
+      ms->SetMediaTime(NULL, NULL);\r
+    if (reftime1<0) ms->SetPreroll(TRUE);\r
+    else ms->SetPreroll(FALSE);\r
+    }else {\r
+      ms->SetSyncPoint(FALSE);\r
+      ms->SetTime(NULL,NULL);\r
+      ms->SetMediaTime(NULL, NULL);\r
+    ms->SetPreroll(FALSE);\r
+    //  ms->SetSyncPoint(TRUE);\r
+    }\r
+  }\r
+  if (packet.type!=vw->lastAType()) {\r
+      vw->changeAType(packet.type,ms);\r
+      ms->SetDiscontinuity(TRUE);\r
+  }\r
+\r
+\r
+  memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);\r
+\r
+    ms->SetActualDataLength(haveToCopy+ms_pos);\r
+\r
+  *samplepos+=haveToCopy;\r
+\r
+  return haveToCopy+headerstrip;\r
+\r
+}\r
+\r
+int AudioWin::dsInitAudioFilter(IGraphBuilder* dsgraphbuilder)\r
+{\r
+    HRESULT hres;\r
+    IFilterGraph2*fg2=NULL;\r
+    VideoWin *vw=(VideoWin*)Video::getInstance();\r
+    if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK)\r
+    {\r
+        Log::getInstance()->log("AudiooWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");\r
+        return 0;\r
+    }\r
+    IBaseFilter*audiofilter;\r
+    if (aud_type!=Audio::MP3) {\r
+        audiofilter = getAudioFilter();\r
+    } else {\r
+        audiofilter = getMp3AudioFilter();\r
+    }\r
+    if (dsgraphbuilder->AddFilter(audiofilter,NULL) != S_OK)\r
+    {\r
+        Log::getInstance()->log("AudioWin", Log::WARN , "Failed adding Video Filter!");\r
+        return 0;\r
+    }\r
+    IEnumPins *pinenum=NULL;\r
+    bool error=false;\r
+    if (audiofilter->EnumPins(&pinenum) == S_OK)\r
+    {\r
+        IPin *current=NULL;\r
+        ULONG fetch=0;\r
+        bool firststep=false;\r
+        while (pinenum->Next(1,&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
index 654775f38f40daa35379c52a6f62a06db9f173b6..115cf311936d7a67e9a98e18f7b327c296d3a352 100644 (file)
--- a/bitmap.h
+++ b/bitmap.h
@@ -39,6 +39,7 @@ class Palette
     const std::vector<UCHAR>& getCrVector() const { return Cr; }
     const std::vector<UCHAR>& getCbVector() const { return Cb; }
     const std::vector<UCHAR>& getAVector() const { return A; }
+    const UINT getNumColours()const{return numColours;};
   private:
     const static UINT MAX_DEPTH = 8;
     std::vector<ULONG> colour;
@@ -70,4 +71,5 @@ class Bitmap
     void setAllIndices(UCHAR index);
 }; 
 
+
 #endif
index cbf2dac8b96f9badcfbd0df78173ae93121172f0..739dd5a8ac413c91e32e55f6897d7a3cb34e0bf7 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "boxstack.h"
-
-#include "command.h"
-#include "remote.h"
-#include "log.h"
-
-BoxStack* BoxStack::instance = NULL;
-
-BoxStack::BoxStack()
-{
-  if (instance) return;
-  instance = this;
-  initted = 0;
-  numBoxes = 0;
-}
-
-BoxStack::~BoxStack()
-{
-  instance = NULL;
-}
-
-BoxStack* BoxStack::getInstance()
-{
-  return instance;
-}
-
-int BoxStack::init()
-{
-  if (initted) return 0;
-  initted = 1;
-  
-#ifndef WIN32
-  pthread_mutex_init(&boxLock, NULL);
-#else
-  boxLock = CreateMutex(NULL,FALSE,NULL);
-#endif
-
-  return 1;
-}
-
-int BoxStack::shutdown()
-{
-  if (!initted) return 0;
-
-  // FIXME don't think this can work properly, removeAll leaves the wallpaper there!
-  removeAll();
-
-  initted = 0;
-  return 1;
-}
-
-int BoxStack::add(Boxx* v)
-{
-  if (!initted) return 0;
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "add called"); 
-#ifndef WIN32
-  pthread_mutex_lock(&boxLock);
-#else
-  WaitForSingleObject(boxLock, INFINITE);
-#endif
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for add");  
-  
-  if (numBoxes == 16)
-  { //Error
-    Log::getInstance()->log("BoxStack", Log::ERR, "More than 16 boxes! Unlocked for add"); 
-#ifndef WIN32
-    pthread_mutex_unlock(&boxLock);
-#else
-    ReleaseMutex(boxLock);
-#endif
-    return 0;
-  }
-  boxes[numBoxes++] = v;
-
-#ifndef WIN32
-  pthread_mutex_unlock(&boxLock);
-#else
-  ReleaseMutex(boxLock);
-#endif
-
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for add");
-  
-  return 1;
-}
-
-// ---------------------------------------------------- REMOVE CODE
-
-int BoxStack::remove(Boxx* toDelete)
-{
-  if (!initted) return 0;
-
-  #ifndef WIN32
-  pthread_mutex_lock(&boxLock);
-  #else
-  WaitForSingleObject(boxLock, INFINITE);
-  #endif
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for remove");  
-  
-  if (numBoxes == 0)
-  {
-    #ifndef WIN32
-    pthread_mutex_unlock(&boxLock);
-    #else
-    ReleaseMutex(boxLock);
-    #endif
-    Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove numBoxes == 0");  
-    return 0;
-  }
-
-//  Log::getInstance()->log("BoxStack", Log::DEBUG, "entering remove, numBoxes=%i", numBoxes);
-
-  int i;
-
-  if (toDelete == NULL)
-  {
-    toDelete = boxes[numBoxes-1];
-    i = numBoxes - 1;
-  }
-  else
-  {
-    // to be deleted box is more likely to be at the top
-    for (i = numBoxes-1; i >= 0; i--)
-    {
-//      Log::getInstance()->log("BoxStack", Log::DEBUG, "todel: %p, i=%i, boxes[i]=%p", toDelete, i, boxes[i]);
-      if (boxes[i] == toDelete) break;
-    }
-
-    if (i == -1)
-    {
-      // not a Box we have!
-      // FIXME
-      #ifndef WIN32
-      pthread_mutex_unlock(&boxLock);
-      #else
-      ReleaseMutex(boxLock);
-      #endif
-      Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove - no boxx deleted");  
-      return 0;
-    }
-  }
-
-#ifndef WIN32
-  pthread_mutex_unlock(&boxLock);
-#else
-  ReleaseMutex(boxLock);
-#endif
-
-toDelete->preDelete();
-
-#ifndef WIN32
-  pthread_mutex_lock(&boxLock);
-#else
-  WaitForSingleObject(boxLock, INFINITE);
-#endif
-
-//  Log::getInstance()->log("BoxStack", Log::DEBUG, "Starting deleteBox");
-  deleteBox(i);
-//  Log::getInstance()->log("BoxStack", Log::DEBUG, "Done deleteBox");
-
-  // Shift the boxes on top down one
-  --numBoxes;
-  for(int j = i; j < numBoxes; j++) boxes[j] = boxes[j+1];
-
-  // If there is only the wallpaper left signal command
-  if (numBoxes == 1)
-  {
-    Message* m = new Message();
-    m->to = Command::getInstance();
-    m->message = Message::LAST_VIEW_CLOSE;
-    Command::getInstance()->postMessageNoLock(m);
-  }
-
-#ifndef WIN32
-  pthread_mutex_unlock(&boxLock);
-#else
-  ReleaseMutex(boxLock);
-#endif
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for remove");  
-  // Delete the box
-  //AVO: do this delete outside the lock to allow for recursive calls within the destructor
-  //     as this box is not in the stack any more, there is no chance for a second delete
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "remove: going to delete boxx %p, num %d", toDelete, numBoxes);  
-  delete toDelete;
-
-  return 1;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// NEW STUFF
-/////////////////////////////////////////////////////////////////////////////
-
-void BoxStack::deleteBox(int z)
-{
-//  Log::getInstance()->log("BoxStack", Log::DEBUG, "Delete box %i of %i", z, numBoxes);
-  RegionList rl;
-  boxSplit(boxes[z]->area, z + 1, numBoxes, 1, rl);
-  while(!rl.empty())
-  {
-    repaintRevealed(z, rl.front());
-    rl.pop_front();
-  }
-}
-
-void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)
-{
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "Update called");
-
-#ifndef WIN32
-  pthread_mutex_lock(&boxLock);
-#else
-  WaitForSingleObject(boxLock, INFINITE);
-#endif
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for update");
-
-  // Get the z index of the box
-  int z = 0;
-  if (toUpdate)
-  {
-    for (z = 0; z < numBoxes; z++)
-    {
-      if (boxes[z] == toUpdate) break;
-    }
-
-    if (z == numBoxes)
-    {
-      // not a Box we have!
-  #ifndef WIN32
-      pthread_mutex_unlock(&boxLock);
-  #else
-      ReleaseMutex(boxLock);
-  #endif 
-      Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for update! box not inside boxstack");
-      return;
-    }
-  }
-  else
-  {
-    toUpdate = boxes[0];
-  }
-
-  // get the region for the whole box, could be less than that
-  // for smaller updates
-
-  Region r = toUpdate->area;
-
-  if (regionToUpdate)
-  {
-    // Can be null if the whole box should be updated
-    // If this is given the numbers are relative to the size of the box, not the screen
-
-    r.x += regionToUpdate->x;
-    r.y += regionToUpdate->y;
-    r.w = regionToUpdate->w;
-    r.h = regionToUpdate->h;
-  }
-
-  RegionList rl;
-
-  Region r2;
-  boxSplit(r, z+1, numBoxes, 1, rl);
-  while(!rl.empty())
-  {
-    r2 = rl.front();
-    r2.z = z;
-    boxes[z]->blt(r2);
-    rl.pop_front();
-  }
-  
-#ifndef WIN32
-  pthread_mutex_unlock(&boxLock);
-#else
-  ReleaseMutex(boxLock);
-#endif  
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for update");
-}
-
-void BoxStack::repaintRevealed(int x, Region r)
-{
-  RegionList rl;
-  boxSplit(r, x - 1, -1, -1, rl);
-
-  Region r2;
-  while(!rl.empty())
-  {
-    r2 = rl.front();
-    boxes[r2.z]->blt(r2);
-    rl.pop_front();
-  }
-}
-
-void BoxStack::boxSplit(Region r, int start, int end, int direction, RegionList& rl)
-{
-//  printf("Y=  S=%i E=%i D=%i: Boxsplit: %i %i %i %i\n", start, end, direction, r.x, r.y, r.w, r.h);
-
-  for(int z = start; z != end; z += direction)
-  {
-    if (r.overlappedBy(boxes[z]->area))
-    {
-//      printf("Z=%i S=%i E=%i D=%i: %i overlaps\n", z, start, end, direction, z);
-
-      int top = r.y;
-      int btm = r.y2();
-
-      if (boxes[z]->area.y > r.y)
-      {
-//        printf("Z=%i S=%i E=%i D=%i: Case 1 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
-        top = boxes[z]->area.y;
-        Region newR;
-        newR.x = r.x;
-        newR.y = r.y;
-        newR.w = r.w;
-        newR.h = boxes[z]->area.y - r.y;
-        boxSplit(newR, z + direction, end, direction, rl);
-
-        if (direction == -1)
-        {
-          Region newR2;
-          newR2.x = r.x;
-          newR2.y = boxes[z]->area.y;
-          newR2.w = r.w;
-          newR2.h = r.h - newR.h;
-          boxSplit(newR2, z, end, -1, rl);
-          return;
-        }
-      }
-
-      if (boxes[z]->area.y2() < r.y2())
-      {
-//        printf("Z=%i S=%i E=%i D=%i: Case 2 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
-        btm = boxes[z]->area.y2();
-        Region newR;
-        newR.x = r.x;
-        newR.y = boxes[z]->area.y2() + 1;
-        newR.w = r.w;
-        newR.h = r.y2() - newR.y + 1;
-        boxSplit(newR, z + direction, end, direction, rl);
-
-        if (direction == -1)
-        {
-          Region newR2;
-          newR2.x = r.x;
-          newR2.y = r.y;
-          newR2.w = r.w;
-          newR2.h = r.h - newR.h;
-          boxSplit(newR2, z, end, -1, rl);
-          return;
-        }
-      }
-
-      if (boxes[z]->area.x > r.x)
-      {
-//        printf("Z=%i S=%i E=%i D=%i: Case 3 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
-        Region newR;
-        newR.x = r.x;
-        newR.y = top;
-        newR.w = boxes[z]->area.x - r.x;
-        newR.h = btm - top + 1;
-        boxSplit(newR, z + direction, end, direction, rl);
-
-        if (direction == -1)
-        {
-          Region newR2;
-          newR2.x = r.x + newR.w;
-          newR2.y = r.y;
-          newR2.w = r.w - newR.w;
-          newR2.h = r.h;
-          boxSplit(newR2, z, end, -1, rl);
-          return;
-        }
-      }
-
-      if (boxes[z]->area.x2() < r.x2())
-      {
-//        printf("Z=%i S=%i E=%i D=%i: Case 4 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);
-        Region newR;
-        newR.x = boxes[z]->area.x2() + 1;
-        newR.y = top;
-        newR.w = r.x2() - newR.x + 1;
-        newR.h = btm - top + 1;
-        boxSplit(newR, z + direction, end, direction, rl);
-
-        if (direction == -1)
-        {
-          Region newR2;
-          newR2.x = r.x;
-          newR2.y = r.y;
-          newR2.w = r.w - newR.w;
-          newR2.h = r.h;
-          boxSplit(newR2, z, end, -1, rl);
-          return;
-        }
-      }
-
-      if (direction == -1)
-      {
-        // we are going down the stack
-        // r is underlapped by boxes[z]
-        // but we have not split
-        // Therefore this region under test is
-        // completely covering boxes[z]
-
-        // don't go any further down, generate a region and quit
-
-//        printf("Repaint region: %i %i %i %i\n", r.x, r.y, r.w, r.h);
-        r.z = z;
-        rl.push_front(r);
-      }
-
-//      printf("Returning from Z=%i\n", z);
-      return;
-    }
-    else
-    {
-//      printf("Z=%i S=%i E=%i D=%i: %i does not overlap\n", z, start, end, direction, z);
-    }
-  }
-
-  // if direction = 1 then we have come to a region that is
-  // entirely clear of higher boxes and needs to be redrawn
-
-  // if direction = -1 then we have come to a region that is on
-  // the very bottom with nothing below it to repaint.
-  // do nothing. stale window data will be left on screen?
-
-  if (direction == 1)
-  {
-    rl.push_front(r);
-  }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// END NEW STUFF
-/////////////////////////////////////////////////////////////////////////////
-
-// ---------------------------------------------------- END OF REMOVE CODE
-
-
-void BoxStack::removeAll()
-{
-  // 1.. Don't delete wallpaper. No point.
-
-  // Need locking on this one??
-  
-  // This is pretty silly now that preDelete needs mutex unlocked
-  
-  Boxx* toDel = NULL;
-  
-  while(numBoxes > 1)
-  {
-    #ifndef WIN32
-      pthread_mutex_lock(&boxLock);
-    #else
-      WaitForSingleObject(boxLock, INFINITE);
-    #endif  
-
-    if (numBoxes == 1)
-    {
-      #ifndef WIN32
-        pthread_mutex_unlock(&boxLock);
-      #else
-        ReleaseMutex(boxLock);
-      #endif
-      break;
-    }    
-  
-    toDel = boxes[numBoxes - 1];
-
-    #ifndef WIN32
-      pthread_mutex_unlock(&boxLock);
-    #else
-      ReleaseMutex(boxLock);
-    #endif
-
-    toDel->preDelete();
-    
-    #ifndef WIN32
-      pthread_mutex_lock(&boxLock);
-    #else
-      WaitForSingleObject(boxLock, INFINITE);
-    #endif  
-
-    // If boxes[numBoxes - 1] isn't toDel then there's a problem
-    if (boxes[numBoxes - 1] == toDel)
-    {
-      --numBoxes;
-    }
-    else
-    {
-      Log::getInstance()->log("BoxStack", Log::ERR, "Can this actually happen? Why?");
-      toDel = NULL;
-    }
-
-    #ifndef WIN32
-      pthread_mutex_unlock(&boxLock);
-    #else
-      ReleaseMutex(boxLock);
-    #endif
-
-    //AVO: do the delete outside the lock to allow for recursive deletes
-    Log::getInstance()->log("BoxStack", Log::DEBUG, "going to delete boxx %p, num=%d", toDel, numBoxes);
-    if (toDel) delete toDel;
-  }
-}
-
-int BoxStack::handleCommand(int command)
-{
-  int retVal;
-  int retVal2 = 0;
-  int i;
-
-  if (command != Remote::NA_NONE)
-  {
-    // handle command return values
-    // 0 - drop through to next box
-    // 1 - dont drop to next box, but not handled
-    // 2 - handled - stop command here
-    // 4 - handled - delete this box
-
-    for (i=numBoxes-1; i>=0; i--)
-    {
-//      Log::getInstance()->log("BoxStack", Log::DEBUG, "Giving command to i=%i", i);
-      retVal = boxes[i]->handleCommand(command);
-      if (retVal == 1)
-      {
-        // not handled but don't give to any more boxes
-        return 0;
-      }
-
-      if (retVal == 2)
-      {
-        // command handled
-        retVal2 = 1;
-        break;
-      }
-      else if (retVal == 4)
-      {
-//        Log::getInstance()->log("BoxStack", Log::DEBUG, "Return 4: i=%i, boxes[i]=%p", i, boxes[i]);
-        remove(boxes[i]);
-        retVal2 = 1;
-        break;
-      }
-    }
-  }
-  else
-  {
-    // fake the return code
-    retVal2 = 2;
-  }
-
-  return retVal2;
-}
-
-void BoxStack::processMessage(Message* m)
-{
-  if (m->to != this)
-  {
-    for (int i = numBoxes-1; i >= 0; i--)
-    {
-      if (boxes[i] == m->to)
-      {
-        Log::getInstance()->log("BoxStack", Log::DEBUG, "sending message from box %p to box %p %lu", m->from, m->to, m->message);
-        boxes[i]->processMessage(m);
-        return;
-      }
-    }
-    return;
-  }
-
-  /* Handle mouse events*/
-  // They come in with m->to = NULL? and just need to be delivered to top box?
-  if ((numBoxes > 1) && ((m->message == Message::MOUSE_MOVE) || (m->message == Message::MOUSE_LBDOWN)))
-  {
-    boxes[numBoxes-1]->processMessage(m);
-    return;
-  }
-
-  Log::getInstance()->log("BoxStack", Log::DEBUG, "it's for meeee!");
-
-  switch(m->message)
-  {
-    case Message::CLOSE_ME:
-    {
-      remove((Boxx*)m->from);
-      break;
-    }
-    case Message::ADD_VIEW: // currently not used by anything but it might come in useful again
-    {
-      Boxx* toAdd = (Boxx*)m->parameter;
-      add(toAdd);
-      toAdd->draw();
-      update(toAdd);
-      break;
-    }
-  }
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "boxstack.h"\r
+\r
+#include "command.h"\r
+#include "remote.h"\r
+#include "log.h"\r
+\r
+BoxStack* BoxStack::instance = NULL;\r
+\r
+BoxStack::BoxStack()\r
+{\r
+  if (instance) return;\r
+  instance = this;\r
+  initted = 0;\r
+  numBoxes = 0;\r
+}\r
+\r
+BoxStack::~BoxStack()\r
+{\r
+  instance = NULL;\r
+}\r
+\r
+BoxStack* BoxStack::getInstance()\r
+{\r
+  return instance;\r
+}\r
+\r
+int BoxStack::init()\r
+{\r
+  if (initted) return 0;\r
+  initted = 1;\r
+  \r
+#ifndef WIN32\r
+  pthread_mutex_init(&boxLock, NULL);\r
+#else\r
+  boxLock = CreateMutex(NULL,FALSE,NULL);\r
+#endif\r
+\r
+  return 1;\r
+}\r
+\r
+int BoxStack::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  // FIXME don't think this can work properly, removeAll leaves the wallpaper there!\r
+  removeAll();\r
+\r
+  initted = 0;\r
+  return 1;\r
+}\r
+\r
+int BoxStack::add(Boxx* v)\r
+{\r
+  if (!initted) return 0;\r
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "add called"); \r
+#ifndef WIN32\r
+  pthread_mutex_lock(&boxLock);\r
+#else\r
+  WaitForSingleObject(boxLock, INFINITE);\r
+#endif\r
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for add");  \r
+  \r
+  if (numBoxes == 16)\r
+  { //Error\r
+    Log::getInstance()->log("BoxStack", Log::ERR, "More than 16 boxes! Unlocked for add"); \r
+#ifndef WIN32\r
+    pthread_mutex_unlock(&boxLock);\r
+#else\r
+    ReleaseMutex(boxLock);\r
+#endif\r
+    return 0;\r
+  }\r
+  boxes[numBoxes++] = v;\r
+\r
+#ifndef WIN32\r
+  pthread_mutex_unlock(&boxLock);\r
+#else\r
+  ReleaseMutex(boxLock);\r
+#endif\r
+\r
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for add");\r
+  \r
+  return 1;\r
+}\r
+\r
+// ---------------------------------------------------- REMOVE CODE\r
+\r
+int BoxStack::remove(Boxx* toDelete)\r
+{\r
+  if (!initted) return 0;\r
+\r
+  #ifndef WIN32\r
+  pthread_mutex_lock(&boxLock);\r
+  #else\r
+  WaitForSingleObject(boxLock, INFINITE);\r
+  #endif\r
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for remove");  \r
+  \r
+  if (numBoxes == 0)\r
+  {\r
+    #ifndef WIN32\r
+    pthread_mutex_unlock(&boxLock);\r
+    #else\r
+    ReleaseMutex(boxLock);\r
+    #endif\r
+    Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove numBoxes == 0");  \r
+    return 0;\r
+  }\r
+\r
+//  Log::getInstance()->log("BoxStack", Log::DEBUG, "entering remove, numBoxes=%i", numBoxes);\r
+\r
+  int i;\r
+\r
+  if (toDelete == NULL)\r
+  {\r
+    toDelete = boxes[numBoxes-1];\r
+    i = numBoxes - 1;\r
+  }\r
+  else\r
+  {\r
+    // to be deleted box is more likely to be at the top\r
+    for (i = numBoxes-1; i >= 0; i--)\r
+    {\r
+//      Log::getInstance()->log("BoxStack", Log::DEBUG, "todel: %p, i=%i, boxes[i]=%p", toDelete, i, boxes[i]);\r
+      if (boxes[i] == toDelete) break;\r
+    }\r
+\r
+    if (i == -1)\r
+    {\r
+      // not a Box we have!\r
+      // FIXME\r
+      #ifndef WIN32\r
+      pthread_mutex_unlock(&boxLock);\r
+      #else\r
+      ReleaseMutex(boxLock);\r
+      #endif\r
+      Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for remove - no boxx deleted");  \r
+      return 0;\r
+    }\r
+  }\r
+\r
+#ifndef WIN32\r
+  pthread_mutex_unlock(&boxLock);\r
+#else\r
+  ReleaseMutex(boxLock);\r
+#endif\r
+\r
+toDelete->preDelete();\r
+\r
+#ifndef WIN32\r
+  pthread_mutex_lock(&boxLock);\r
+#else\r
+  WaitForSingleObject(boxLock, INFINITE);\r
+#endif\r
+\r
+//  Log::getInstance()->log("BoxStack", Log::DEBUG, "Starting deleteBox");\r
+  deleteBox(i);\r
+//  Log::getInstance()->log("BoxStack", Log::DEBUG, "Done deleteBox");\r
+\r
+  // Shift the boxes on top down one\r
+  --numBoxes;\r
+  for(int j = i; j < numBoxes; j++) boxes[j] = boxes[j+1];\r
+\r
+  // If there is only the wallpaper left signal command\r
+  if (numBoxes == 1)\r
+  {\r
+    Message* m = new Message();\r
+    m->to = Command::getInstance();\r
+    m->message = Message::LAST_VIEW_CLOSE;\r
+    Command::getInstance()->postMessageNoLock(m);\r
+  }\r
+\r
+#ifndef WIN32\r
+  pthread_mutex_unlock(&boxLock);\r
+#else\r
+  ReleaseMutex(boxLock);\r
+#endif\r
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for remove");  \r
\r
+  // Delete the box\r
+  //AVO: do this delete outside the lock to allow for recursive calls within the destructor\r
+  //     as this box is not in the stack any more, there is no chance for a second delete\r
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "remove: going to delete boxx %p, num %d", toDelete, numBoxes);  \r
+  delete toDelete;\r
+\r
+  return 1;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// NEW STUFF\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+void BoxStack::deleteBox(int z)\r
+{\r
+//  Log::getInstance()->log("BoxStack", Log::DEBUG, "Delete box %i of %i", z, numBoxes);\r
+  RegionList rl;\r
+  boxSplit(boxes[z]->area, z + 1, numBoxes, 1, rl);\r
+  while(!rl.empty())\r
+  {\r
+    repaintRevealed(z, rl.front());\r
+    rl.pop_front();\r
+  }\r
+}\r
+\r
+void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)\r
+{\r
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "Update called");\r
+\r
+#ifndef WIN32\r
+  pthread_mutex_lock(&boxLock);\r
+#else\r
+  WaitForSingleObject(boxLock, INFINITE);\r
+#endif\r
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for update");\r
+\r
+  // Get the z index of the box\r
+  int z = 0;\r
+  if (toUpdate)\r
+  {\r
+    for (z = 0; z < numBoxes; z++)\r
+    {\r
+      if (boxes[z] == toUpdate) break;\r
+    }\r
+\r
+    if (z == numBoxes)\r
+    {\r
+      // not a Box we have!\r
+  #ifndef WIN32\r
+      pthread_mutex_unlock(&boxLock);\r
+  #else\r
+      ReleaseMutex(boxLock);\r
+  #endif \r
+      Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for update! box not inside boxstack");\r
+      return;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    toUpdate = boxes[0];\r
+  }\r
+\r
+  // get the region for the whole box, could be less than that\r
+  // for smaller updates\r
+\r
+  Region r = toUpdate->area;\r
+\r
+  if (regionToUpdate)\r
+  {\r
+    // Can be null if the whole box should be updated\r
+    // If this is given the numbers are relative to the size of the box, not the screen\r
+\r
+    r.x += regionToUpdate->x;\r
+    r.y += regionToUpdate->y;\r
+    r.w = regionToUpdate->w;\r
+    r.h = regionToUpdate->h;\r
+  }\r
+\r
+  RegionList rl;\r
+\r
+  Region r2;\r
+  boxSplit(r, z+1, numBoxes, 1, rl);\r
+  while(!rl.empty())\r
+  {\r
+    r2 = rl.front();\r
+    r2.z = z;\r
+    boxes[z]->blt(r2);\r
+    rl.pop_front();\r
+  }\r
+  \r
+#ifndef WIN32\r
+  pthread_mutex_unlock(&boxLock);\r
+#else\r
+  ReleaseMutex(boxLock);\r
+#endif  \r
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "Unlocked for update");\r
+}\r
+\r
+void BoxStack::repaintRevealed(int x, Region r)\r
+{\r
+  RegionList rl;\r
+  boxSplit(r, x - 1, -1, -1, rl);\r
+\r
+  Region r2;\r
+  while(!rl.empty())\r
+  {\r
+    r2 = rl.front();\r
+    boxes[r2.z]->blt(r2);\r
+    rl.pop_front();\r
+  }\r
+}\r
+\r
+void BoxStack::boxSplit(Region r, int start, int end, int direction, RegionList& rl)\r
+{\r
+//  printf("Y=  S=%i E=%i D=%i: Boxsplit: %i %i %i %i\n", start, end, direction, r.x, r.y, r.w, r.h);\r
+\r
+  for(int z = start; z != end; z += direction)\r
+  {\r
+    if (r.overlappedBy(boxes[z]->area))\r
+    {\r
+//      printf("Z=%i S=%i E=%i D=%i: %i overlaps\n", z, start, end, direction, z);\r
+\r
+      int top = r.y;\r
+      int btm = r.y2();\r
+\r
+      if (boxes[z]->area.y > r.y)\r
+      {\r
+//        printf("Z=%i S=%i E=%i D=%i: Case 1 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);\r
+        top = boxes[z]->area.y;\r
+        Region newR;\r
+        newR.x = r.x;\r
+        newR.y = r.y;\r
+        newR.w = r.w;\r
+        newR.h = boxes[z]->area.y - r.y;\r
+        boxSplit(newR, z + direction, end, direction, rl);\r
+\r
+        if (direction == -1)\r
+        {\r
+          Region newR2;\r
+          newR2.x = r.x;\r
+          newR2.y = boxes[z]->area.y;\r
+          newR2.w = r.w;\r
+          newR2.h = r.h - newR.h;\r
+          boxSplit(newR2, z, end, -1, rl);\r
+          return;\r
+        }\r
+      }\r
+\r
+      if (boxes[z]->area.y2() < r.y2())\r
+      {\r
+//        printf("Z=%i S=%i E=%i D=%i: Case 2 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);\r
+        btm = boxes[z]->area.y2();\r
+        Region newR;\r
+        newR.x = r.x;\r
+        newR.y = boxes[z]->area.y2() + 1;\r
+        newR.w = r.w;\r
+        newR.h = r.y2() - newR.y + 1;\r
+        boxSplit(newR, z + direction, end, direction, rl);\r
+\r
+        if (direction == -1)\r
+        {\r
+          Region newR2;\r
+          newR2.x = r.x;\r
+          newR2.y = r.y;\r
+          newR2.w = r.w;\r
+          newR2.h = r.h - newR.h;\r
+          boxSplit(newR2, z, end, -1, rl);\r
+          return;\r
+        }\r
+      }\r
+\r
+      if (boxes[z]->area.x > r.x)\r
+      {\r
+//        printf("Z=%i S=%i E=%i D=%i: Case 3 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);\r
+        Region newR;\r
+        newR.x = r.x;\r
+        newR.y = top;\r
+        newR.w = boxes[z]->area.x - r.x;\r
+        newR.h = btm - top + 1;\r
+        boxSplit(newR, z + direction, end, direction, rl);\r
+\r
+        if (direction == -1)\r
+        {\r
+          Region newR2;\r
+          newR2.x = r.x + newR.w;\r
+          newR2.y = r.y;\r
+          newR2.w = r.w - newR.w;\r
+          newR2.h = r.h;\r
+          boxSplit(newR2, z, end, -1, rl);\r
+          return;\r
+        }\r
+      }\r
+\r
+      if (boxes[z]->area.x2() < r.x2())\r
+      {\r
+//        printf("Z=%i S=%i E=%i D=%i: Case 4 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h);\r
+        Region newR;\r
+        newR.x = boxes[z]->area.x2() + 1;\r
+        newR.y = top;\r
+        newR.w = r.x2() - newR.x + 1;\r
+        newR.h = btm - top + 1;\r
+        boxSplit(newR, z + direction, end, direction, rl);\r
+\r
+        if (direction == -1)\r
+        {\r
+          Region newR2;\r
+          newR2.x = r.x;\r
+          newR2.y = r.y;\r
+          newR2.w = r.w - newR.w;\r
+          newR2.h = r.h;\r
+          boxSplit(newR2, z, end, -1, rl);\r
+          return;\r
+        }\r
+      }\r
+\r
+      if (direction == -1)\r
+      {\r
+        // we are going down the stack\r
+        // r is underlapped by boxes[z]\r
+        // but we have not split\r
+        // Therefore this region under test is\r
+        // completely covering boxes[z]\r
+\r
+        // don't go any further down, generate a region and quit\r
+\r
+//        printf("Repaint region: %i %i %i %i\n", r.x, r.y, r.w, r.h);\r
+        r.z = z;\r
+        rl.push_front(r);\r
+      }\r
+\r
+//      printf("Returning from Z=%i\n", z);\r
+      return;\r
+    }\r
+    else\r
+    {\r
+//      printf("Z=%i S=%i E=%i D=%i: %i does not overlap\n", z, start, end, direction, z);\r
+    }\r
+  }\r
+\r
+  // if direction = 1 then we have come to a region that is\r
+  // entirely clear of higher boxes and needs to be redrawn\r
+\r
+  // if direction = -1 then we have come to a region that is on\r
+  // the very bottom with nothing below it to repaint.\r
+  // do nothing. stale window data will be left on screen?\r
+\r
+  if (direction == 1)\r
+  {\r
+    rl.push_front(r);\r
+  }\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// END NEW STUFF\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+// ---------------------------------------------------- END OF REMOVE CODE\r
+\r
+\r
+void BoxStack::removeAll()\r
+{\r
+  // 1.. Don't delete wallpaper. No point.\r
+\r
+  // Need locking on this one??\r
+  \r
+  // This is pretty silly now that preDelete needs mutex unlocked\r
+  \r
+  Boxx* toDel = NULL;\r
+  \r
+  while(numBoxes > 1)\r
+  {\r
+    #ifndef WIN32\r
+      pthread_mutex_lock(&boxLock);\r
+    #else\r
+      WaitForSingleObject(boxLock, INFINITE);\r
+    #endif  \r
+\r
+    if (numBoxes == 1)\r
+    {\r
+      #ifndef WIN32\r
+        pthread_mutex_unlock(&boxLock);\r
+      #else\r
+        ReleaseMutex(boxLock);\r
+      #endif\r
+      break;\r
+    }    \r
+  \r
+    toDel = boxes[numBoxes - 1];\r
+\r
+    #ifndef WIN32\r
+      pthread_mutex_unlock(&boxLock);\r
+    #else\r
+      ReleaseMutex(boxLock);\r
+    #endif\r
+\r
+    toDel->preDelete();\r
+    \r
+    #ifndef WIN32\r
+      pthread_mutex_lock(&boxLock);\r
+    #else\r
+      WaitForSingleObject(boxLock, INFINITE);\r
+    #endif  \r
+\r
+    // If boxes[numBoxes - 1] isn't toDel then there's a problem\r
+    if (boxes[numBoxes - 1] == toDel)\r
+    {\r
+      --numBoxes;\r
+    }\r
+    else\r
+    {\r
+      Log::getInstance()->log("BoxStack", Log::ERR, "Can this actually happen? Why?");\r
+      toDel = NULL;\r
+    }\r
+\r
+    #ifndef WIN32\r
+      pthread_mutex_unlock(&boxLock);\r
+    #else\r
+      ReleaseMutex(boxLock);\r
+    #endif\r
+\r
+    //AVO: do the delete outside the lock to allow for recursive deletes\r
+    Log::getInstance()->log("BoxStack", Log::DEBUG, "going to delete boxx %p, num=%d", toDel, numBoxes);\r
+    if (toDel) delete toDel;\r
+  }\r
+}\r
+\r
+int BoxStack::handleCommand(int command)\r
+{\r
+  int retVal;\r
+  int retVal2 = 0;\r
+  int i;\r
+\r
+  if (command != Remote::NA_NONE)\r
+  {\r
+    // handle command return values\r
+    // 0 - drop through to next box\r
+    // 1 - dont drop to next box, but not handled\r
+    // 2 - handled - stop command here\r
+    // 4 - handled - delete this box\r
+\r
+    for (i=numBoxes-1; i>=0; i--)\r
+    {\r
+//      Log::getInstance()->log("BoxStack", Log::DEBUG, "Giving command to i=%i", i);\r
+      retVal = boxes[i]->handleCommand(command);\r
+      if (retVal == 1)\r
+      {\r
+        // not handled but don't give to any more boxes\r
+        return 0;\r
+      }\r
+\r
+      if (retVal == 2)\r
+      {\r
+        // command handled\r
+        retVal2 = 1;\r
+        break;\r
+      }\r
+      else if (retVal == 4)\r
+      {\r
+//        Log::getInstance()->log("BoxStack", Log::DEBUG, "Return 4: i=%i, boxes[i]=%p", i, boxes[i]);\r
+        remove(boxes[i]);\r
+        retVal2 = 1;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  else\r
+  {\r
+    // fake the return code\r
+    retVal2 = 2;\r
+  }\r
+\r
+  return retVal2;\r
+}\r
+\r
+void BoxStack::processMessage(Message* m)\r
+{\r
+  if (m->to != this)\r
+  {\r
+    for (int i = numBoxes-1; i >= 0; i--)\r
+    {\r
+      if (boxes[i] == m->to)\r
+      {\r
+        Log::getInstance()->log("BoxStack", Log::DEBUG, "sending message from box %p to box %p %lu", m->from, m->to, m->message);\r
+        boxes[i]->processMessage(m);\r
+        return;\r
+      }\r
+    }\r
+    return;\r
+  }\r
+\r
+  /* Handle mouse events*/\r
+  // They come in with m->to = NULL? and just need to be delivered to top box?\r
+  if ((numBoxes > 1) && ((m->message == Message::MOUSE_MOVE) || (m->message == Message::MOUSE_LBDOWN)\r
+                 || (m->message == Message::MOUSE_ANDROID_SCROLL)))\r
+  {\r
+    boxes[numBoxes-1]->processMessage(m);\r
+    return;\r
+  }\r
+\r
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "it's for meeee!");\r
+\r
+  switch(m->message)\r
+  {\r
+    case Message::CLOSE_ME:\r
+    {\r
+      remove((Boxx*)m->from);\r
+      break;\r
+    }\r
+    case Message::ADD_VIEW: // currently not used by anything but it might come in useful again\r
+    {\r
+      Boxx* toAdd = (Boxx*)m->parameter;\r
+      add(toAdd);\r
+      toAdd->draw();\r
+      update(toAdd);\r
+      break;\r
+    }\r
+  }\r
+}\r
diff --git a/boxx.cc b/boxx.cc
index 0bc3570100444634866cff6f196b40ecd3bc2920..1705370c0c84bd29fdc4aeb1f7b34733e1b9e824 100644 (file)
--- a/boxx.cc
+++ b/boxx.cc
-/*
-    Copyright 2007 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "boxx.h"
-#include "bitmap.h"
-#include "log.h"
-#include <stdlib.h>
-
-char Boxx::numBoxxes = 0;
-
-Boxx::Boxx()
-{
-  // I want a parent box or a surface.
-  parent = NULL;
-  surface = NULL;
-
-  area.x = 0;
-  area.y = 0;
-  area.w = 0;
-  area.h = 0;
-
-  paraVSpace = 6; // default gap for drawPara
-
-  backgroundColourSet = false;
-  visible = true;
-
-  numBoxxes++;
-  Log::getInstance()->log("Boxx", Log::DEBUG, "Construct, now %u", numBoxxes);
-}
-
-Boxx::~Boxx()
-{
-  if (surface) delete surface;
-  numBoxxes--;
-  Log::getInstance()->log("Boxx", Log::DEBUG, "Destruct, now %u", numBoxxes);
-}
-
-void Boxx::draw()
-{
-  //Log::getInstance()->log("Boxx", Log::DEBUG, "Draw this %p surface %p", this, surface);
-  if (backgroundColourSet) fillColour(backgroundColour);
-
-  Boxx* currentBoxx;
-  vector<Boxx*>::iterator j;
-  for (j = children.begin(); j != children.end(); j++)
-  {
-    currentBoxx = *j;
-    if (currentBoxx->getVisible()) currentBoxx->draw();
-  }  
-}
-
-void Boxx::setSize(UINT w, UINT h)
-{
-  area.w = w;
-  area.h = h;
-}
-
-void Boxx::setPosition(UINT x, UINT y)
-{
-  area.x = x;
-  area.y = y;
-}
-
-void Boxx::createBuffer()
-{
-  surface = new Surface_TYPE();
-  surface->create(area.w, area.h);
-}
-
-void Boxx::add(Boxx* newChild)
-{
-  newChild->setParent(this);
-  children.push_back(newChild);
-}
-
-void Boxx::remove(Boxx* oldChild)
-{
-  for(vector<Boxx*>::iterator i = children.begin(); i != children.end(); i++)
-  {
-    if (*i == oldChild)
-    {
-      children.erase(i);
-      return;
-    }
-  }
-  Log::getInstance()->log("Boxx", Log::ERR, "Remove child box called, child %p not found", oldChild);
-}
-
-void Boxx::setParent(Boxx* newParent)
-{
-  parent = newParent;
-}
-
-void Boxx::setBackgroundColour(const Colour& Tcolour)
-{
-  backgroundColour = Tcolour;
-  backgroundColourSet = true;
-}
-
-void Boxx::setVisible(bool isVisible)
-{
-  visible = isVisible;
-}
-
-bool Boxx::getVisible()
-{
-  return visible;
-}
-
-void Boxx::setGap(UINT gap)
-{
-  paraVSpace = gap;
-}
-
-void Boxx::blt(Region& r)
-{
-  /* surface update to screen needs:
-  source x distance into this surface
-  source y distance into this surface
-  width of update
-  height of update
-  destination x on screen
-  destination y on screen
-  */
-
-  if (parent) abort(); // if (parent) then this is a child boxx. It can not blt.
-
-  // this shouldn't be here
-  r.x -= area.x;
-  r.y -= area.y;
-
-  surface->updateToScreen(r.x, r.y, r.w, r.h, area.x + r.x, area.y + r.y);
-  
-}
-
-int Boxx::getScreenX()
-{
-  if (parent) return area.x + parent->getScreenX();
-  return area.x;
-}
-
-int Boxx::getScreenY()
-{
-  if (parent) return area.y + parent->getScreenY();
-  return area.y;
-}
-
-int Boxx::getRootBoxOffsetX()  // convert this to be getX and silently do the parent/not thing? same for Y below?
-{
-  if (parent) return area.x + parent->getRootBoxOffsetX();
-  return 0;
-}
-
-int Boxx::getRootBoxOffsetY()
-{
-  if (parent) return area.y + parent->getRootBoxOffsetY();
-  return 0;
-}
-
-int Boxx::getX()
-{
-  return area.x;
-}
-
-int Boxx::getY()
-{
-  return area.y;
-}
-
-int Boxx::getX2()
-{
-  return area.x + area.w;
-}
-
-int Boxx::getY2()
-{
-  return area.y + area.h;
-}
-
-UINT Boxx::getWidth()
-{
-  return area.w;
-}
-
-UINT Boxx::getHeight()
-{
-  return area.h;
-}
-
-// FIXME Clean up the code to use just one of the following
-
-Region* Boxx::getRegion()
-{
-  return &area;
-}
-
-Region Boxx::getRegionR()
-{
-  return area;
-}
-
-void Boxx::getRootBoxRegion(Region* r)
-{
-  // Returns a region that describes the position of this box on the box with the surface
-  // To be used for boxstack->update calls
-
-  r->x = getRootBoxOffsetX();
-  r->y = getRootBoxOffsetY();
-  r->w = area.w;
-  r->h = area.h;  
-}
-
-// Level 1 drawing functions
-
-void Boxx::fillColour(const Colour& colour)
-{
-  rectangle(0, 0, area.w, area.h, colour);
-}
-
-void Boxx::drawPara(const char* text, int x, int y, const Colour& colour)
-{
-  char line[256];
-  int lineHeight = surface->getFontHeight() + paraVSpace;
-
-  int lineWidth;
-  int thisCharWidth;
-  int textPos;
-  int linePos;
-  int ypos;
-  int printLine;
-
-  textPos = 0;
-  ypos = y;
-
-  while(1)
-  {
-    linePos = 0;
-    lineWidth = 0;
-    while(1)
-    {
-      printLine = 0;
-
-      if (text[textPos] == '\0') break;
-
-      if (text[textPos] == '\n')
-      {
-        textPos++; // ignore the \n
-        printLine = 1;
-        break;
-      }
-
-      thisCharWidth = surface->getCharWidth(text[textPos]);
-      if ((lineWidth + thisCharWidth) > (int)(area.w - (2 * paraMargin)))
-      {
-        // this character would break the right margin
-        if (text[textPos] == ' ')
-        {
-          // this char is a space, ignore and break
-          textPos++;
-          break;
-        }
-        else
-        {
-          // Need to go back to the last space in the line
-          while ((text[textPos] != ' ') && (linePos >= 0))
-          {
-            textPos--;
-            linePos--;
-          }
-          // Now take the space we just found
-          textPos++;
-          break;
-        }
-      }
-      line[linePos++] = text[textPos];
-      lineWidth += thisCharWidth;
-      textPos++;
-    }
-
-//    line[linePos++] = '\0';
-    if (linePos>=0) line[linePos++] = '\0'; //Here is the change
-
-    if (printLine || (linePos > 1)) // if some text was put in line
-    {
-      drawText(line, x, ypos, colour);
-      ypos += lineHeight;
-      if (ypos > (int)(area.h - lineHeight)) break;
-    }
-    else
-    {
-      break;
-    }
-  }
-}
-
-void Boxx::rectangle(Region& region, const Colour& colour)
-{
-  rectangle(region.x, region.y, region.w, region.h, colour);
-}
-
-// Level 0 drawing functions
-
-void Boxx::rectangle(UINT x, UINT y, UINT w, UINT h, const Colour& colour)
-{
-  if (parent) parent->rectangle(area.x + x, area.y + y, w, h, colour);
-  else surface->fillblt(x, y, w, h, colour.rgba());
-}
-
-void Boxx::drawText(const char* text, int x, int y, const Colour& colour)
-{
-  if (parent) parent->drawText(text, area.x + x, area.y + y, colour);
-  else surface->drawText(text, x, y, colour.rgba());
-}
-
-void Boxx::drawText(const char* text, int x, int y, int width, const Colour& colour)
-{
-  if (parent) parent->drawText(text, area.x + x, area.y + y, width, colour);
-  else surface->drawText(text, x, y, width, colour.rgba());
-}
-
-void Boxx::drawTextRJ(const char* text, int x, int y, const Colour& colour)
-{
-  if (parent) parent->drawTextRJ(text, area.x + x, area.y + y, colour);
-  else surface->drawTextRJ(text, x, y, colour.rgba());
-}
-
-void Boxx::drawTextCentre(const char* text, int x, int y, const Colour& colour)
-{
-  if (parent) parent->drawTextCentre(text, area.x + x, area.y + y, colour);
-  else surface->drawTextCentre(text, x, y, colour.rgba());
-}
-
-void Boxx::drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw)
-{
-  if (parent) parent->drawPixelAlpha(area.x + x, area.y + y, colour,fastdraw);
-  else
-  {
-    int c = (  (colour.alpha << 24 )
-             | (colour.red    << 16)
-             | (colour.green  <<  8)
-             | (colour.blue        ) );
-
-    surface->drawPixel(x, y, c,fastdraw);
-  }
-}
-
-void Boxx::drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw)
-{
-  if (parent) parent->drawPixel(area.x + x, area.y + y, colour,fastdraw);
-  else
-  {
-    int c = (  (0xFF000000         )
-             | (colour.red    << 16)
-             | (colour.green  <<  8)
-             | (colour.blue        ) );
-
-    surface->drawPixel(x, y, c,fastdraw);
-  }
-}
-void Boxx::drawBitmap(UINT x, UINT y, const Bitmap& bm)
-{
-  if (parent) parent->drawBitmap(area.x + x, area.y + y, bm);
-  else surface->drawBitmap(x, y, bm);
-}
-
-void Boxx::startFastDraw()
-{
-    if (parent) parent->startFastDraw();
-    else
-    {
-        surface->startFastDraw();
-    }
-}
-
-void Boxx::endFastDraw()
-{
-    if (parent) parent->endFastDraw();
-    else
-    {
-        surface->endFastDraw();
-    }
-}
-
-int Boxx::charWidth(char c)
-{
-  if (parent) return parent->charWidth(c);
-  else return surface->getCharWidth(c);
-}
-
-Surface * Boxx::getSurface() {
-  if (parent) return parent->getSurface();
-  return surface;
-}
-
+/*\r
+    Copyright 2007 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "boxx.h"\r
+#include "bitmap.h"\r
+#include "log.h"\r
+#include "osd.h"\r
+#include <stdlib.h>\r
+\r
+char Boxx::numBoxxes = 0;\r
+\r
+Boxx::Boxx()\r
+{\r
+  // I want a parent box or a surface.\r
+  parent = NULL;\r
+  surface = NULL;\r
+\r
+  area.x = 0;\r
+  area.y = 0;\r
+  area.w = 0;\r
+  area.h = 0;\r
+\r
+  paraVSpace = 6; // default gap for drawPara\r
+\r
+  backgroundColourSet = false;\r
+  visible = true;\r
+\r
+  numBoxxes++;\r
+  Log::getInstance()->log("Boxx", Log::DEBUG, "Construct, now %u", numBoxxes);\r
+}\r
+\r
+Boxx::~Boxx()\r
+{\r
+  if (surface) delete surface;\r
+  numBoxxes--;\r
+  Log::getInstance()->log("Boxx", Log::DEBUG, "Destruct, now %u", numBoxxes);\r
+}\r
+\r
+void Boxx::draw()\r
+{\r
+  //Log::getInstance()->log("Boxx", Log::DEBUG, "Draw this %p surface %p", this, surface);\r
+  if (backgroundColourSet) fillColour(backgroundColour);\r
+\r
+  Boxx* currentBoxx;\r
+  vector<Boxx*>::iterator j;\r
+  //int count=0;\r
+  for (j = children.begin(); j != children.end(); j++)\r
+  {\r
+    currentBoxx = *j;\r
+   // Log::getInstance()->log("Boxx", Log::DEBUG, "Draw child %d %d", count,currentBoxx);\r
+    if (currentBoxx->getVisible()) currentBoxx->draw();\r
+   // count++;\r
+  }  \r
+ // Log::getInstance()->log("Boxx", Log::DEBUG, "Draw this %p surface %p End", this, surface);\r
+}\r
+\r
+void Boxx::setSize(UINT w, UINT h)\r
+{\r
+  area.w = w;\r
+  area.h = h;\r
+}\r
+\r
+void Boxx::setPosition(UINT x, UINT y)\r
+{\r
+  area.x = x;\r
+  area.y = y;\r
+}\r
+\r
+void Boxx::createBuffer()\r
+{\r
+  surface = Osd::getInstance()->createNewSurface();\r
+  surface->create(area.w, area.h);\r
+}\r
+\r
+void Boxx::add(Boxx* newChild)\r
+{\r
+  newChild->setParent(this);\r
+  children.push_back(newChild);\r
+}\r
+\r
+void Boxx::remove(Boxx* oldChild)\r
+{\r
+  for(vector<Boxx*>::iterator i = children.begin(); i != children.end(); i++)\r
+  {\r
+    if (*i == oldChild)\r
+    {\r
+      children.erase(i);\r
+      return;\r
+    }\r
+  }\r
+  Log::getInstance()->log("Boxx", Log::ERR, "Remove child box called, child %p not found", oldChild);\r
+}\r
+\r
+void Boxx::setParent(Boxx* newParent)\r
+{\r
+  parent = newParent;\r
+}\r
+\r
+void Boxx::setBackgroundColour(const Colour& Tcolour)\r
+{\r
+  backgroundColour = Tcolour;\r
+  backgroundColourSet = true;\r
+}\r
+\r
+void Boxx::setVisible(bool isVisible)\r
+{\r
+  visible = isVisible;\r
+}\r
+\r
+bool Boxx::getVisible()\r
+{\r
+  return visible;\r
+}\r
+\r
+void Boxx::setGap(UINT gap)\r
+{\r
+  paraVSpace = gap;\r
+}\r
+\r
+void Boxx::blt(Region& r)\r
+{\r
+  /* surface update to screen needs:\r
+  source x distance into this surface\r
+  source y distance into this surface\r
+  width of update\r
+  height of update\r
+  destination x on screen\r
+  destination y on screen\r
+  */\r
+\r
+  if (parent) abort(); // if (parent) then this is a child boxx. It can not blt.\r
+\r
+  // this shouldn't be here\r
+  r.x -= area.x;\r
+  r.y -= area.y;\r
+\r
+  surface->updateToScreen(r.x, r.y, r.w, r.h, area.x + r.x, area.y + r.y);\r
+  \r
+}\r
+\r
+int Boxx::getScreenX()\r
+{\r
+  if (parent) return area.x + parent->getScreenX();\r
+  return area.x;\r
+}\r
+\r
+int Boxx::getScreenY()\r
+{\r
+  if (parent) return area.y + parent->getScreenY();\r
+  return area.y;\r
+}\r
+\r
+int Boxx::getRootBoxOffsetX()  // convert this to be getX and silently do the parent/not thing? same for Y below?\r
+{\r
+  if (parent) return area.x + parent->getRootBoxOffsetX();\r
+  return 0;\r
+}\r
+\r
+int Boxx::getRootBoxOffsetY()\r
+{\r
+  if (parent) return area.y + parent->getRootBoxOffsetY();\r
+  return 0;\r
+}\r
+\r
+int Boxx::getX()\r
+{\r
+  return area.x;\r
+}\r
+\r
+int Boxx::getY()\r
+{\r
+  return area.y;\r
+}\r
+\r
+int Boxx::getX2()\r
+{\r
+  return area.x + area.w;\r
+}\r
+\r
+int Boxx::getY2()\r
+{\r
+  return area.y + area.h;\r
+}\r
+\r
+UINT Boxx::getWidth()\r
+{\r
+  return area.w;\r
+}\r
+\r
+UINT Boxx::getHeight()\r
+{\r
+  return area.h;\r
+}\r
+\r
+// FIXME Clean up the code to use just one of the following\r
+\r
+Region* Boxx::getRegion()\r
+{\r
+  return &area;\r
+}\r
+\r
+Region Boxx::getRegionR()\r
+{\r
+  return area;\r
+}\r
+\r
+void Boxx::getRootBoxRegion(Region* r)\r
+{\r
+  // Returns a region that describes the position of this box on the box with the surface\r
+  // To be used for boxstack->update calls\r
+\r
+  r->x = getRootBoxOffsetX();\r
+  r->y = getRootBoxOffsetY();\r
+  r->w = area.w;\r
+  r->h = area.h;  \r
+}\r
+\r
+// Level 1 drawing functions\r
+\r
+void Boxx::fillColour(const Colour& colour)\r
+{\r
+  rectangle(0, 0, area.w, area.h, colour);\r
+}\r
+\r
+void Boxx::drawPara(const char* text, int x, int y, const Colour& colour)\r
+{\r
+  char line[256];\r
+  int lineHeight = getFontHeight() + paraVSpace;\r
+\r
+  int lineWidth;\r
+  int thisCharWidth;\r
+  int textPos;\r
+  int linePos;\r
+  int ypos;\r
+  int printLine;\r
+\r
+  textPos = 0;\r
+  ypos = y;\r
+\r
+  while(1)\r
+  {\r
+    linePos = 0;\r
+    lineWidth = 0;\r
+    while(1)\r
+    {\r
+      printLine = 0;\r
+\r
+      if (text[textPos] == '\0') break;\r
+\r
+      if (text[textPos] == '\n')\r
+      {\r
+        textPos++; // ignore the \n\r
+        printLine = 1;\r
+        break;\r
+      }\r
+\r
+      thisCharWidth = charWidth(text[textPos]);\r
+      if ((lineWidth + thisCharWidth) > (int)(area.w - (2 * paraMargin)))\r
+      {\r
+        // this character would break the right margin\r
+        if (text[textPos] == ' ')\r
+        {\r
+          // this char is a space, ignore and break\r
+          textPos++;\r
+          break;\r
+        }\r
+        else\r
+        {\r
+          // Need to go back to the last space in the line\r
+          while ((text[textPos] != ' ') && (linePos >= 0))\r
+          {\r
+            textPos--;\r
+            linePos--;\r
+          }\r
+          // Now take the space we just found\r
+          textPos++;\r
+          break;\r
+        }\r
+      }\r
+      line[linePos++] = text[textPos];\r
+      lineWidth += thisCharWidth;\r
+      textPos++;\r
+    }\r
+\r
+//    line[linePos++] = '\0';\r
+    if (linePos>=0) line[linePos++] = '\0'; //Here is the change\r
+\r
+    if (printLine || (linePos > 1)) // if some text was put in line\r
+    {\r
+      drawText(line, x, ypos, colour);\r
+      ypos += lineHeight;\r
+      if (ypos > (int)(area.h - lineHeight)) break;\r
+    }\r
+    else\r
+    {\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+void Boxx::rectangle(Region& region, const Colour& colour)\r
+{\r
+  rectangle(region.x, region.y, region.w, region.h, colour);\r
+}\r
+\r
+// Level 0 drawing functions\r
+\r
+void Boxx::rectangle(UINT x, UINT y, UINT w, UINT h, const Colour& colour)\r
+{\r
+  if (parent) parent->rectangle(area.x + x, area.y + y, w, h, colour);\r
+  else surface->fillblt(x, y, w, h, colour.rgba());\r
+}\r
+\r
+void Boxx::drawText(const char* text, int x, int y, const Colour& colour)\r
+{\r
+  if (parent) parent->drawText(text, area.x + x, area.y + y, colour);\r
+  else surface->drawText(text, x, y, colour.rgba());\r
+}\r
+\r
+void Boxx::drawText(const char* text, int x, int y, int width, const Colour& colour)\r
+{\r
+  if (parent) parent->drawText(text, area.x + x, area.y + y, width, colour);\r
+  else surface->drawText(text, x, y, width, colour.rgba());\r
+}\r
+\r
+void Boxx::drawTextRJ(const char* text, int x, int y, const Colour& colour)\r
+{\r
+  if (parent) parent->drawTextRJ(text, area.x + x, area.y + y, colour);\r
+  else surface->drawTextRJ(text, x, y, colour.rgba());\r
+}\r
+\r
+void Boxx::drawTextCentre(const char* text, int x, int y, const Colour& colour)\r
+{\r
+  if (parent) parent->drawTextCentre(text, area.x + x, area.y + y, colour);\r
+  else  surface->drawTextCentre(text, x, y, colour.rgba());\r
+}\r
+\r
+void Boxx::drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw)\r
+{\r
+  if (parent) parent->drawPixelAlpha(area.x + x, area.y + y, colour,fastdraw);\r
+  else\r
+  {\r
+    int c = (  (colour.alpha << 24 )\r
+             | (colour.red    << 16)\r
+             | (colour.green  <<  8)\r
+             | (colour.blue        ) );\r
+\r
+    surface->drawPixel(x, y, c,fastdraw);\r
+  }\r
+}\r
+\r
+void Boxx::drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw)\r
+{\r
+  if (parent) parent->drawPixel(area.x + x, area.y + y, colour,fastdraw);\r
+  else\r
+  {\r
+    int c = (  (0xFF000000         )\r
+             | (colour.red    << 16)\r
+             | (colour.green  <<  8)\r
+             | (colour.blue        ) );\r
+\r
+    surface->drawPixel(x, y, c,fastdraw);\r
+  }\r
+}\r
+\r
+void Boxx::drawTTChar(int ox, int oy,int x, int y, cTeletextChar c)\r
+{\r
+       if (parent) parent->drawTTChar(area.x + ox, area.y + oy, x,y,c);\r
+       else  if (surface) surface->drawTTChar(ox, oy,x,y,c);\r
+\r
+}\r
+\r
+void Boxx::drawBitmap(UINT x, UINT y, const Bitmap& bm)\r
+{\r
+  if (parent) parent->drawBitmap(area.x + x, area.y + y, bm);\r
+  else  if (surface) surface->drawBitmap(x, y, bm);\r
+}\r
+\r
+void Boxx::drawJpeg(const char *fileName,int x, int y,int *width, int *height)\r
+{\r
+       if (parent) parent->drawJpeg(fileName,area.x +x,area.y +y,width,height);\r
+       else if (surface) surface->drawJpeg(fileName,x,y,width,height);\r
+}\r
+\r
+int Boxx::getFontHeight()\r
+{\r
+       if (parent) return parent->getFontHeight();\r
+       else if (surface) return surface->getFontHeight();\r
+       else return 18;\r
+}\r
+\r
+void Boxx::startFastDraw()\r
+{\r
+    if (parent) parent->startFastDraw();\r
+    else\r
+    {\r
+        if (surface) surface->startFastDraw();\r
+    }\r
+}\r
+\r
+void Boxx::endFastDraw()\r
+{\r
+    if (parent) parent->endFastDraw();\r
+    else\r
+    {\r
+        if (surface) surface->endFastDraw();\r
+    }\r
+}\r
\r
+\r
+int Boxx::charWidth(char c)\r
+{\r
+  if (parent) return parent->charWidth(c);\r
+  else  if (surface) return surface->getCharWidth(c);\r
+  else return 10; //?\r
+}\r
+\r
+Surface * Boxx::getSurface() {\r
+  if (parent) return parent->getSurface();\r
+  return surface;\r
+}\r
+\r
diff --git a/boxx.h b/boxx.h
index b38f0a540f4093dbb18195cbefa6ed578dc3bdd2..5a4da519fa1979fc7d108ed65380f1b09f445be1 100644 (file)
--- a/boxx.h
+++ b/boxx.h
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef BOXX_H
-#define BOXX_H
-
-#include <stdio.h>
-#include <vector>
-
-using namespace std;
-
-#include "colour.h"
-#include "region.h"
-#include "message.h"
-
-#ifdef WIN32
-#include "surfacewin.h"
-#else
-
-#ifdef _MIPS_ARCH
-#include "surfacedirectfb.h"
-#else
-#include "surfacemvp.h"
-#endif
-
-#endif
-
-class Bitmap;
-
-class Boxx
-{
-  public:
-    Boxx();
-    virtual ~Boxx();
-
-    virtual void setSize(UINT w, UINT h);  // virtual? really?
-    void setPosition(UINT x, UINT y); // Set position on parent. Even numbers only!!!
-    void createBuffer(); // Make this a root view that goes in the BoxStack
-    virtual void draw();
-    
-    
-    void setGap(UINT gap);
-    void setBackgroundColour(const Colour& colour);
-    void setVisible(bool isVisible);
-
-
-    // The following are supposed to be abstract functions
-    // However, it is useful to be able to make instances of Boxx
-    // Therefore the following stubs are provided.
-    virtual void preDelete() {}
-    virtual int handleCommand(int x) { return 0; }
-    virtual void processMessage(Message* m) {}
-    virtual bool mouseMove(int x, int y) { return false; }
-    virtual bool mouseLBDOWN(int x, int y) { return false; }
-    virtual void deactivateAllControls() {}
-
-    /* preDelete 
-    
-     I think it's functionally equivalent to e.g. delete timers in Boxx::preDelete
-     because the only place where a Boxx is deleted is in 
-     BoxStack::remove. There is now a call in BoxStack::remove to Boxx::preDelete
-     The reason for this is to stop timercalls calling BoxStack::update at the
-     same time BoxStack::remove is locked trying to delete the Boxx
-    */
-
-    // Get functions
-    int getScreenX();        // where is it on screen
-    int getScreenY();
-    int getRootBoxOffsetX(); // where is it relative to the top-parent in the boxstack
-    int getRootBoxOffsetY();
-    int getX();              // where is it relative to its parent
-    int getX2();             // .. and the right edge
-    int getY();
-    int getY2();
-    UINT getWidth();
-    UINT getHeight();
-    bool getVisible();
-    Region* getRegion();     // Not to be used for changing the region
-    Region getRegionR();     // Same but as an object
-    void getRootBoxRegion(Region*);
-    
-    // Drawing functions level 1
-    void fillColour(const Colour& colour);
-    void drawPara(const char* text, int x, int y, const Colour& colour);
-
-    // Drawing functions level 0
-    void rectangle(UINT x, UINT y, UINT w, UINT h, const Colour& colour);
-    void rectangle(Region& region, const Colour& colour);
-
-    void drawText(const char* text, int x, int y, const Colour& colour);
-    void drawText(const char* text, int x, int y, int width, const Colour& colour);
-    void drawTextRJ(const char* text, int x, int y, const Colour& colour);
-    void drawTextCentre(const char* text, int x, int y, const Colour& colour);
-    void drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw=false);
-    void drawBitmap(UINT x, UINT y, const Bitmap& bm);
-    void drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw=false);
-
-    /* This is for system which need a locking of the drawing surface to speed up drawing */
-    void startFastDraw();
-    void endFastDraw();
-
-    int charWidth(char c);
-
-    void add(Boxx*); // a boxx has a set of child boxxs
-    void remove(Boxx*);
-
-    /*
-    The following function sets the child's parent pointer without adding the child to the children vector.
-    It's a hack (that should be deprecated?) to allow things like WSymbol to be created, do some drawing on
-    the surface and then be deleted again, leaving the drawing present.
-    A better design would be to create many WSymbols - one per symbol and leave them created - then the
-    automatic draw code will be able to redraw the symbols without all that code needing
-    to be in the derived boxx's draw method.
-    */    
-    void TEMPADD(Boxx* child) { child->setParent(this); }
-
-  friend class BoxStack;
-  protected:
-    //get the surface this box is drawing to
-    Surface *getSurface();
-    Boxx* parent;
-    Region area;
-    vector<Boxx*> children;
-
-    void setParent(Boxx*);    
-    void blt(Region& r);
-
-    static const int paraMargin = 10;
-    UINT paraVSpace;
-
-    Colour backgroundColour;
-    bool backgroundColourSet;
-    bool visible;
-
-    static char numBoxxes;
-    Surface* surface;
-};
-
-#endif
-
-
-/*
-
-New Boxx design
-
-It's "Boxx" because "Box" was already taken.
-
-BoxStack replaces Viewman and handles displaying a stack of root boxxs (boxxs with surfaces) on the screen.
-
-Boxx relaces Box, Widget and parts of View and represents a box with or without a surface.
-Let's call a Boxx with a surface a root box, and a boxx without a surface a child box.
-
-A boxx with a surface (root) is like an old View and is handled by BoxStack.
-A boxx without a surface (child) is like and old Widget and needs to be a child box of another boxx (root or not).
-
-Don't add a boxx with a surface to another boxx. That isn't the design.
-
-So, when you create a boxx, either that boxx calls createBuffer() on itself,
-or some other box add()s the new box to itself.
-
-Root boxxs can overlap each other - this is managed by boxstack.
-Child boxxs within a parent boxx do not overlap each other.
-However, a grandchild box can overlap a child box (but must be entirely contained within the child box).
-
-TBBoxx replaces View but is now only a convenience class for the window dressing stuff. It isn't required anymore since
-all the real work that view used to do is done in Boxx now.
-
-Obseleted classes: Box, View, Viewman, Widget, others?
-No code outside boxx should talk about surfaces anymore. Hopefully.
-
-*/
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef BOXX_H\r
+#define BOXX_H\r
+\r
+#include <stdio.h>\r
+#include <vector>\r
+\r
+using namespace std;\r
+\r
+#include "colour.h"\r
+#include "region.h"\r
+#include "message.h"\r
+\r
+\r
+#include "surface.h"\r
+\r
+class Bitmap;\r
+\r
+class Boxx\r
+{\r
+  public:\r
+    Boxx();\r
+    virtual ~Boxx();\r
+\r
+    virtual void setSize(UINT w, UINT h);  // virtual? really?\r
+    void setPosition(UINT x, UINT y); // Set position on parent. Even numbers only!!!\r
+    void createBuffer(); // Make this a root view that goes in the BoxStack\r
+    virtual void draw();\r
+    \r
+    \r
+    void setGap(UINT gap);\r
+    void setBackgroundColour(const Colour& colour);\r
+    void setVisible(bool isVisible);\r
+\r
+\r
+    // The following are supposed to be abstract functions\r
+    // However, it is useful to be able to make instances of Boxx\r
+    // Therefore the following stubs are provided.\r
+    virtual void preDelete() {}\r
+    virtual int handleCommand(int x) { return 0; }\r
+    virtual void processMessage(Message* m) {}\r
+    virtual bool mouseMove(int x, int y) { return false; }\r
+    virtual bool mouseLBDOWN(int x, int y) { return false; }\r
+    virtual bool mouseAndroidScroll(int x, int y,int sx, int sy) { return false; }\r
+    virtual void deactivateAllControls() {}\r
+\r
+    /* preDelete \r
+    \r
+     I think it's functionally equivalent to e.g. delete timers in Boxx::preDelete\r
+     because the only place where a Boxx is deleted is in \r
+     BoxStack::remove. There is now a call in BoxStack::remove to Boxx::preDelete\r
+     The reason for this is to stop timercalls calling BoxStack::update at the\r
+     same time BoxStack::remove is locked trying to delete the Boxx\r
+    */\r
+\r
+    // Get functions\r
+    int getScreenX();        // where is it on screen\r
+    int getScreenY();\r
+    int getRootBoxOffsetX(); // where is it relative to the top-parent in the boxstack\r
+    int getRootBoxOffsetY();\r
+    int getX();              // where is it relative to its parent\r
+    int getX2();             // .. and the right edge\r
+    int getY();\r
+    int getY2();\r
+    UINT getWidth();\r
+    UINT getHeight();\r
+    bool getVisible();\r
+    Region* getRegion();     // Not to be used for changing the region\r
+    Region getRegionR();     // Same but as an object\r
+    void getRootBoxRegion(Region*);\r
+    \r
+    // Drawing functions level 1\r
+    void fillColour(const Colour& colour);\r
+    void drawPara(const char* text, int x, int y, const Colour& colour);\r
+\r
+    // Drawing functions level 0\r
+    void rectangle(UINT x, UINT y, UINT w, UINT h, const Colour& colour);\r
+    void rectangle(Region& region, const Colour& colour);\r
+\r
+    void drawText(const char* text, int x, int y, const Colour& colour);\r
+    void drawText(const char* text, int x, int y, int width, const Colour& colour);\r
+    void drawTextRJ(const char* text, int x, int y, const Colour& colour);\r
+    void drawTextCentre(const char* text, int x, int y, const Colour& colour);\r
+    void drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw=false);\r
+    void drawBitmap(UINT x, UINT y, const Bitmap& bm);\r
+    void drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw=false);\r
+    int getFontHeight();\r
+\r
+    void drawJpeg(const char *fileName,int x, int y,int *width, int *height);\r
+\r
+    void drawTTChar(int ox, int oy,int x, int y, cTeletextChar c);\r
+\r
+    /* This is for system which need a locking of the drawing surface to speed up drawing */\r
+    void startFastDraw();\r
+    void endFastDraw();\r
+\r
+    int charWidth(char c);\r
+\r
+    void add(Boxx*); // a boxx has a set of child boxxs\r
+    void remove(Boxx*);\r
+\r
+    /*\r
+    The following function sets the child's parent pointer without adding the child to the children vector.\r
+    It's a hack (that should be deprecated?) to allow things like WSymbol to be created, do some drawing on\r
+    the surface and then be deleted again, leaving the drawing present.\r
+    A better design would be to create many WSymbols - one per symbol and leave them created - then the\r
+    automatic draw code will be able to redraw the symbols without all that code needing\r
+    to be in the derived boxx's draw method.\r
+    */    \r
+    void TEMPADD(Boxx* child) { child->setParent(this); }\r
+\r
+  friend class BoxStack;\r
+  protected:\r
+    //get the surface this box is drawing to\r
+    Surface *getSurface();\r
+    Boxx* parent;\r
+    Region area;\r
+    vector<Boxx*> children;\r
+\r
+    void setParent(Boxx*);    \r
+    void blt(Region& r);\r
+\r
+    static const int paraMargin = 10;\r
+    UINT paraVSpace;\r
+\r
+    Colour backgroundColour;\r
+    bool backgroundColourSet;\r
+    bool visible;\r
+\r
+    static char numBoxxes;\r
+    Surface* surface;\r
+};\r
+\r
+#endif\r
+\r
+\r
+/*\r
+\r
+New Boxx design\r
+\r
+It's "Boxx" because "Box" was already taken.\r
+\r
+BoxStack replaces Viewman and handles displaying a stack of root boxxs (boxxs with surfaces) on the screen.\r
+\r
+Boxx relaces Box, Widget and parts of View and represents a box with or without a surface.\r
+Let's call a Boxx with a surface a root box, and a boxx without a surface a child box.\r
+\r
+A boxx with a surface (root) is like an old View and is handled by BoxStack.\r
+A boxx without a surface (child) is like and old Widget and needs to be a child box of another boxx (root or not).\r
+\r
+Don't add a boxx with a surface to another boxx. That isn't the design.\r
+\r
+So, when you create a boxx, either that boxx calls createBuffer() on itself,\r
+or some other box add()s the new box to itself.\r
+\r
+Root boxxs can overlap each other - this is managed by boxstack.\r
+Child boxxs within a parent boxx do not overlap each other.\r
+However, a grandchild box can overlap a child box (but must be entirely contained within the child box).\r
+\r
+TBBoxx replaces View but is now only a convenience class for the window dressing stuff. It isn't required anymore since\r
+all the real work that view used to do is done in Boxx now.\r
+\r
+Obseleted classes: Box, View, Viewman, Widget, others?\r
+No code outside boxx should talk about surfaces anymore. Hopefully.\r
+\r
+*/\r
+\r
index d2b222e9d340c04bf42820ad3342be37de229ab2..c7ce89cb177d5f82b6250d1fdedad7ecad85c5b5 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef WIN32
-#include <linux/errno.h>
-#endif
-
-#include "command.h"
-
-#ifdef WIN32
-#include "remotewin.h"
-#endif
-
-#include "led.h"
-#include "video.h"
-#include "audio.h"
-#include "vdr.h"
-#include "vvolume.h"
-#include "vserverselect.h"
-#include "vwelcome.h"
-#include "vmute.h"
-#include "colour.h"
-#include "osd.h"
-#include "i18n.h"
-#include "timerreceiver.h"
-#include "timers.h"
-#include "wol.h"
-#include "vconnect.h"
-#include "message.h"
-#include "remote.h"
-#include "vinfo.h"
-#include "boxx.h"
-#include "boxstack.h"
-#include "log.h"
-#include "vsleeptimer.h"
-
-
-Command* Command::instance = NULL;
-
-Command::Command()
-{
-  if (instance) return;
-  instance = this;
-  initted = 0;
-  isStandby = 0;
-  firstBoot = 1;
-  connLost = NULL;
-  crashed = false;
-  server = NULL;
-}
-
-Command::~Command()
-{
-  instance = NULL;
-}
-
-Command* Command::getInstance()
-{
-  return instance;
-}
-
-int Command::init(bool tcrashed, char* tServer)
-{
-  if (initted) return 0;
-  initted = 1;
-  crashed = tcrashed;
-  server = tServer;
-
-  logger = Log::getInstance();
-  boxstack = BoxStack::getInstance();
-  remote = Remote::getInstance();
-  
-  remote->InitHWCListwithDefaults();
-  
-  if (!logger || !boxstack || !remote)
-  {
-    initted = 0;
-    return 0;
-  }
-#ifndef WIN32
-  pthread_mutex_init(&masterLock, NULL);
-#else
-  masterLock=CreateMutex(NULL,FALSE,NULL);
-#endif
-
-  return 1;
-}
-
-int Command::shutdown()
-{
-  if (!initted) return 0;
-  initted = 0;
-  return 1;
-}
-
-void Command::stop()
-{
-//  VDR::getInstance()->cancelFindingServer();
-       logger->log("Command", Log::NOTICE, "Command stop1...");
-       
-  udp.shutdown();
-  logger->log("Command", Log::NOTICE,  "Command stop2...");
-  irun = 0;
-}
-
-void Command::doWallpaper()
-{
-  Video* video = Video::getInstance();
-
-  // Blue background
-  Boxx* bbg = new Boxx();
-  bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
-  bbg->createBuffer();
-  bbg->fillColour(Colour::VIDEOBLUE);
-  boxstack->add(bbg);
-  boxstack->update(bbg);
-  boxstack->remove(bbg);
-
-  // Wallpaper
-  WJpeg* wallpaperj = new WJpeg();
-  wallpaperj->setSize(video->getScreenWidth(), video->getScreenHeight());
-  wallpaperj->createBuffer();
-
-  if (video->getFormat() == Video::PAL)
-  {
-    logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
-#ifndef _MIPS_ARCH    
-    wallpaperj->init("/wallpaperPAL.jpg");
-#else
-    wallpaperj->init("wallpaperPAL.jpg");
-#endif
-  }
-  else
-  {
-    logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
-    wallpaperj->init("/wallpaperNTSC.jpg");
-  }
-  wallpaperj->draw();
-
-  boxstack->add(wallpaperj);
-  boxstack->update(wallpaperj);
-
-  wallpaper = wallpaperj;
-}
-
-void Command::run()
-{
-  if (!initted) return;
-  irun = 1;
-#ifndef WIN32
-  mainPid = getpid();
-#endif
-
-  // just in case
-  Video::getInstance()->signalOn();
-  Led::getInstance()->on();
-
-  doWallpaper();
-
-  // End of startup. Lock the mutex and put the first view up
-//  logger->log("Command", Log::DEBUG, "WANT LOCK");
-#ifndef WIN32
-  pthread_mutex_lock(&masterLock);
-#else
-  WaitForSingleObject(masterLock, INFINITE );
-#endif
-  //logger->log("Command", Log::DEBUG, "LOCKED");
-
-  if (crashed)
-  {
-    buildCrashedBox();
-  }
-  else
-  {
-    VConnect* vconnect = new VConnect(server);
-    boxstack->add(vconnect);
-    vconnect->run();
-  }
-
-  // Start method 2 of getting commands in...
-  udp.run(this);
-
-  UCHAR button = 0;
-  while(irun)
-  {
-    // unlock and wait
-    //logger->log("Command", Log::DEBUG, "UNLOCK");
-#ifndef WIN32
-    pthread_mutex_unlock(&masterLock);
-#else
-    ReleaseMutex(masterLock);
-#endif
-       
-    button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit 
-    // something happened, lock and process
-       
-    //  logger->log("Command", Log::DEBUG, "WANT LOCK");
-#ifndef WIN32
-    pthread_mutex_lock(&masterLock);
-#else
-    WaitForSingleObject(masterLock, INFINITE );
-#endif
-    // logger->log("Command", Log::DEBUG, "LOCK");
-
-    if ((button == Remote::NA_NONE) /*|| (button == Remote::NA_UNKNOWN)*/) continue;
-
-    if (button != Remote::NA_SIGNAL) handleCommand(button);
-    processMessageQueue();
-  }
-
-  //logger->log("Command", Log::DEBUG, "UNLOCK");
-#ifndef WIN32
-  pthread_mutex_unlock(&masterLock);
-#else
-  ReleaseMutex(masterLock);
-#endif
-   
-}
-
-void Command::postMessage(Message* m)
-{
-  // This is locked here in case the main loop is not waiting for an event, but is processing one
-  // it could be killed but then not react to it because the signal wouldn't cause
-  // remote->getButtonPress to break
-  // locking the mutex ensures that the master thread is waiting on getButtonPress
-
-
-  //logger->log("Command", Log::DEBUG, "WANT LOCK");
-#ifndef WIN32
-  pthread_mutex_lock(&masterLock);
-#else
-  WaitForSingleObject(masterLock, INFINITE );
-#endif
-  //logger->log("Command", Log::DEBUG, "LOCK");
-  MessageQueue::postMessage(m);
-
-#ifndef WIN32
-  kill(mainPid, SIGURG);
-  pthread_mutex_unlock(&masterLock);
-#else
-  ((RemoteWin*)Remote::getInstance())->Signal();
-  ReleaseMutex(masterLock);
-#endif
-  //logger->log("Command", Log::DEBUG, "UNLOCK");
-}
-
-void Command::postMessageNoLock(Message* m)
-{
-  // As above but use this one if this message is being posted because of a button press
-  // the mutex is already locked, locking around postMessage is not needed as the
-  // queue is guaranteed to be run when the button has been processed
-  MessageQueue::postMessage(m);
-}
-
-bool Command::postMessageIfNotBusy(Message* m)
-{
-  // Used for Windows mouse events
-
-  //logger->log("Command", Log::DEBUG, "TRY LOCK");
-#ifndef WIN32
-  if (pthread_mutex_trylock(&masterLock) != EBUSY)
-  {
-    //logger->log("Command", Log::DEBUG, "LOCK");
-    MessageQueue::postMessage(m);
-    kill(mainPid, SIGURG);
-    pthread_mutex_unlock(&masterLock);
-    //logger->log("Command", Log::DEBUG, "UNLOCK");
-    return true;
-  }
-  else
-  {
-    return false;
-  }
-#else
-  switch (WaitForSingleObject(masterLock, 0 ))
-  { //FIXME this is not "if not busy" check
-    case WAIT_OBJECT_0: //but with proper argument 0 this did not work
-    // case WAIT_ABANDONED:
-    MessageQueue::postMessage(m);
-    ((RemoteWin*)Remote::getInstance())->Signal();
-    ReleaseMutex(masterLock);
-    return true;
-
-    case WAIT_ABANDONED: return false;
-    case WAIT_TIMEOUT: return false;
-  }
-    return false;
-#endif
-}
-
-void Command::postMessageFromOuterSpace(Message* m)
-{
-  /*
-  Yet another way of getting messages into Command. This one is for events that
-  are not standard button presses (or UDP generated buttons). It is also not for
-  events that are generated as a result of other events (events that can safely
-  call postMessageNoLock and be guaranteed that the message will be processed
-  because it is known that the queue is currently being processed).
-  This is for events that come from outer space and can occur when the master
-  mutex is locked or not, they need to be queued and executed but it doesn't
-  matter when.
-  Actually so far it is for events caused by the video stream - aspect ratio
-  changes. These can occur when the master mutex is locked and so postMessage
-  doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*
-  locked at the time then the message could be sat around a while before
-  being noticed.
-  The whole message system was at first supposed to prevent the problem of
-  calling a function on an object that had just been deleted, by ordering
-  messages such that all calls are done before object deletion. However,
-  because of the new centralised messaging system and the fact that BoxStack
-  locates the destination object before calling it, the messaging system now
-  allows the kind of sloppy calls it was supposed to stop. Weird huh. This
-  is mentioned here because the video stream might generate an event just as
-  the user hits stop. The mutex is locked, and by the time the message
-  is examined the vvideorec/live has been deleted. This doesn't matter because
-  boxstack will drop the message if it can't find the matching object to
-  deliver it to.
-  Finally, all this is fine and dandy, except that I'm not 100% sure that
-  this sloppy postMessage and hope a queued signal will force it to be processed
-  thingy will actually work. Hmmm.
-  Lastly <g>, I will consider making the naming system a little more sane
-  if this works.
-  */
-
-  logger->log("Command", Log::DEBUG, "PMFOS called");
-  MessageQueue::postMessage(m);
-
-#ifndef WIN32
-  kill(mainPid, SIGURG);
-#else
-  ((RemoteWin*)Remote::getInstance())->Signal();
-#endif
-}
-
-void Command::processMessage(Message* m)
-{
-    // FIXME - a slight modification - how if messagereceivers were to register
-    // themselves as receivers to avoid the calling-a-deleted-object problem
-    // then only deliver/register/unregister would have to be protected
-
-  logger->log("Command", Log::DEBUG, "processing message %i", m->message);
-
-
-  if (m->to == this)
-  {
-    switch(m->message)
-    {
-      // << FIXME OBSELETE
-      case Message::STOP_PLAYBACK:
-      {
-        handleCommand(Remote::STOP); // an odd way of doing it, but so simple
-        break;
-      }
-      // Also connection_lost comes from player - anywhere else?
-      // FIXME OBSELETE >>
-
-
-      case Message::VDR_CONNECTED:
-      {
-        doJustConnected((VConnect*)m->from);
-        break;
-      }
-      case Message::SCREENSHOT:
-      {
-        Osd::getInstance()->screenShot("/out.jpg");
-        break;
-      }
-      case Message::CONNECTION_LOST:
-      {
-        doFromTheTop(true);
-        break;
-      }
-      case Message::UDP_BUTTON:
-      {
-        handleCommand(m->parameter);
-        break;
-      }
-      case Message::CHANGE_LANGUAGE:
-      {
-        boxstack->removeAll();
-        boxstack->update(wallpaper);
-        I18n::initialize();
-        if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
-        VWelcome* vw = new VWelcome();
-        vw->draw();
-        boxstack->add(vw);
-        boxstack->update(vw);
-        break;
-      }
-      case Message::LAST_VIEW_CLOSE:
-      {
-        // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
-        if (crashed)
-        {
-          crashed = false;
-          doFromTheTop(false);        
-        }
-      
-//        VWelcome* vw = new VWelcome();
-//        vw->draw();
-//        boxstack->add(vw);
-//        boxstack->update(vw);
-
-        break;
-      }
-    }
-  }
-  else
-  {
-    /* FIXME
-    
-    Instead of sending through the boxstack, implement a more generic MessageReceiver interface
-    and have potential receivers register with something
-    When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
-    This could all be done using the existing big command mutex to keep it simple
-    */
-  
-    logger->log("Command", Log::DEBUG, "Sending message to boxstack");
-    boxstack->processMessage(m);
-  }
-}
-
-void Command::handleCommand(int button)
-{
-  if (isStandby && (button != Remote::POWER)) return;
-  if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
-
-  // command was not handled
-
-  switch(button)
-  {
-    case Remote::DF_LEFT:
-    case Remote::DF_RIGHT:
-    case Remote::VOLUMEUP:
-    case Remote::VOLUMEDOWN:
-    {
-      VVolume* v = new VVolume();
-      boxstack->add(v);
-      v->handleCommand(button); // this will draw+show
-      return;
-    }
-    case Remote::MUTE:
-    {
-      VMute* v = new VMute();
-      v->draw();
-      boxstack->add(v);
-      boxstack->update(v);
-      return;
-    }
-    case Remote::POWER:
-    {
-      doStandby();
-      return;
-    }
-    case Remote::OK:
-    {
-      // FIXME
-      if (!connLost) return; // if connLost, handle Remote::OK
-      doFromTheTop(false);
-      return;
-    }
-    case Remote::GO:
-    {
-      VSleeptimer* sleep = new VSleeptimer();
-      boxstack->add(sleep);
-      sleep->handleCommand(button); // this will draw+show
-      return;
-    }
-  }
-}
-
-void Command::sig1()
-{
-#ifdef DEV
-  Message* m = new Message(); // break into master mutex
-  m->message = Message::SCREENSHOT;
-  m->to = this;
-  postMessage(m);
-#endif
-}
-
-void Command::doStandby()
-{
-  if (isStandby)
-  {
-    Video::getInstance()->signalOn();
-    Led::getInstance()->on();
-    isStandby = 0;
-
-
-    VConnect* vconnect = new VConnect(server);
-    boxstack->add(vconnect);
-    vconnect->run();
-  }
-  else
-  {
-    boxstack->removeAll();
-    Video::getInstance()->signalOff();
-    boxstack->update(wallpaper);
-
-    VDR::getInstance()->configSave("General", "Last Power State", "Off");
-    logger->netLogOff();
-    VDR::getInstance()->disconnect();
-    Led::getInstance()->off();
-    isStandby = 1;
-    Sleeptimer::getInstance()->shutdown();
-#ifdef WIN32
-    stop(); //different behavoiur on windows, we exit
-#endif
-  }
-}
-
-void Command::doFromTheTop(bool which)
-{
-  if (which)
-  {
-    if (connLost)
-    {
-      logger->log("Command", Log::NOTICE, "Connection lost dialog already present");
-      return;
-    }
-  
-    logger->log("Command", Log::NOTICE, "Doing connection lost dialog");
-    connLost = new VInfo();
-    connLost->setSize(360, 200);
-    connLost->createBuffer();
-    if (Video::getInstance()->getFormat() == Video::PAL)
-      connLost->setPosition(190, 170);
-    else
-      connLost->setPosition(180, 120);
-    connLost->setOneLiner(tr("Connection lost"));
-    connLost->setDropThrough();
-    connLost->setBorderOn(1);
-    connLost->setTitleBarColour(Colour::DANGER);
-    connLost->okButton();
-    connLost->draw();
-    boxstack->add(connLost);
-    boxstack->update(connLost);
-    remote->clearBuffer();
-  }
-  else
-  {
-    logger->netLogOff();
-    VDR::getInstance()->disconnect();
-    boxstack->removeAll();
-    boxstack->update(wallpaper);
-    connLost = NULL;
-    
-    flushMessageQueue();
-    remote->clearBuffer();
-    
-    // at this point, everything should be reset to first-go
-    
-    VConnect* vconnect = new VConnect(server);
-    boxstack->add(vconnect);
-    vconnect->run();
-  }
-}
-
-void Command::doReboot()
-{
-  logger->netLogOff();
-  VDR::getInstance()->disconnect();
-  // just kill it...
-  logger->log("Command", Log::NOTICE, "Reboot");
-#ifndef WIN32
-#ifndef _MIPS_ARCH
-  reboot(LINUX_REBOOT_CMD_RESTART);
-#else
-  stop();
-#endif
-#endif //Would we support this on windows?
-}
-
-void Command::connectionLost()
-{
-  logger->netLogOff();
-  Message* m = new Message(); // break into master mutex
-  m->message = Message::CONNECTION_LOST;
-  m->to = this;
-  postMessageFromOuterSpace(m);
-}
-
-void Command::buildCrashedBox()
-{
-  VInfo* crash = new VInfo();
-  crash->setSize(360, 250);
-  crash->createBuffer();
-  if (Video::getInstance()->getFormat() == Video::PAL)
-    crash->setPosition(190, 146);
-  else
-    crash->setPosition(180, 96);
-  crash->setMainText("Oops, vomp crashed.. :(\nPlease report this crash to the author, with as much detail as possible about what you were doing at the time that might have caused the crash.");
-  crash->setBorderOn(1);
-  crash->setTitleBarColour(Colour::DANGER);
-  crash->okButton();
-  crash->setExitable();
-  crash->draw();
-  boxstack->add(crash);
-  boxstack->update(crash);
-}
-
-void Command::doJustConnected(VConnect* vconnect)
-{
-  I18n::initialize();
-  if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
-  
-  Video* video = Video::getInstance();
-  Audio* audio = Audio::getInstance();  
-  boxstack->remove(vconnect);
-
-  VInfo* vi = new VInfo();
-  vi->setSize(400, 200);
-  vi->createBuffer();
-  if (video->getFormat() == Video::PAL)
-    vi->setPosition(170, 200);
-  else
-    vi->setPosition(160, 150);
-  vi->setOneLiner(tr("Connected, loading config"));
-  vi->draw();
-  boxstack->add(vi);
-  boxstack->update(vi);
-
-  VDR* vdr = VDR::getInstance();
-  char* config;
-
-  // See if we're supposed to do network logging
-  config = vdr->configLoad("Advanced", "Network logging");
-  if (config && !STRCASECMP(config, "On"))
-  {
-    logger->log("Command", Log::INFO, "Turning on network logging");
-    logger->netLogOn();
-  }  
-  else
-  {
-    logger->netLogOn();
-    logger->log("Command", Log::INFO, "Turned off network logging");
-  }
-  if (config) delete[] config;
-
-  // See if config says to override video format (PAL/NTSC)
-  config = vdr->configLoad("General", "Override Video Format");
-  if (config)
-  {
-    logger->log("Command", Log::DEBUG, "Override Video Format is present");
-
-    if (   (!strcmp(config, "PAL") && (video->getFormat() == Video::NTSC))
-        || (!strcmp(config, "NTSC") && (video->getFormat() == Video::PAL))  )
-    {
-      // Oh sheesh, need to switch format. Bye bye TV...
-
-      // Take everything down
-      boxstack->removeAll();
-      boxstack->remove(wallpaper);
-      Osd* osd = Osd::getInstance();
-      osd->shutdown();
-      video->shutdown();
-
-      // Get video and osd back up with the new mode
-      if (!strcmp(config, "PAL"))
-      {
-        logger->log("Command", Log::DEBUG, "Switching to PAL");
-        video->init(Video::PAL);
-      }
-      else if (!strcmp(config, "NTSC"))
-      {
-        logger->log("Command", Log::DEBUG, "Switching to NTSC");
-        video->init(Video::NTSC);
-      }
-      osd->init((char*)("/dev/stbgfx"));
-
-      // Put the wallpaper back
-      doWallpaper();
-
-      // Re add the vinfo
-      vi = new VInfo();
-      vi->setSize(400, 200);
-      vi->createBuffer();
-      if (video->getFormat() == Video::PAL)
-        vi->setPosition(170, 200);
-      else
-        vi->setPosition(160, 150);
-
-      vi->setOneLiner(tr("Connected, loading config"));
-      vi->draw();
-      boxstack->add(vi);
-      boxstack->update(vi);
-    }
-    else
-    {
-      logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
-    }
-  }
-  else
-  {
-    logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
-  }
-
-  // Power off if first boot and config says so
-  if (firstBoot)
-  {
-    firstBoot = 0;
-
-    logger->log("Command", Log::DEBUG, "Load power after boot");
-
-    config = vdr->configLoad("General", "Power After Boot");
-
-    if (config)
-    {
-      if (!STRCASECMP(config, "On"))
-      {
-        logger->log("Command", Log::INFO, "Config says Power After Boot = On");
-      }
-      else if (!STRCASECMP(config, "Off"))
-      {
-        logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
-        doStandby();
-        delete[] config;
-        return; // quit here
-      }
-      else if (!STRCASECMP(config, "Last state"))
-      {
-        char* lastPowerState = vdr->configLoad("General", "Last Power State");
-        if (lastPowerState)
-        {
-          if (!STRCASECMP(lastPowerState, "On"))
-          {
-            logger->log("Command", Log::INFO, "Config says Last Power State = On");
-          }
-          else if (!STRCASECMP(lastPowerState, "Off"))
-          {
-            logger->log("Command", Log::INFO, "Config says Last Power State = Off");
-            doStandby();
-            delete[] config;
-            return; // quit here
-          }
-          else
-          {
-            logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
-          }
-        }
-        else
-        {
-          logger->log("Command", Log::INFO, "Config General/Last Power State not found");
-        }
-      }
-      else
-      {
-        logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
-      }
-      delete[] config;
-    }
-    else
-    {
-      logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
-    }
-  }
-
-
-  // Go S-Video if config says so
-
-  config = vdr->configLoad("TV", "Connection");
-
-  if (config)
-  {
-    if (!STRCASECMP(config, "S-Video"))
-    {
-      logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
-      video->setConnection(Video::SVIDEO);
-    }
-    else
-    {
-      logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
-      video->setConnection(Video::COMPOSITERGB);
-    }
-    delete[] config;
-  }
-  else
-  {
-    logger->log("Command", Log::INFO, "Config TV/S-Video not found");
-  }
-
-  // Set remote type
-
-  config = vdr->configLoad("General", "Remote type");
-
-  if (config)
-  {
-    if (!STRCASECMP(config, "New"))
-    {
-      logger->log("Command", Log::INFO, "Switching to New remote type");
-      remote->setRemoteType(Remote::NEWREMOTE);
-    }
-    else
-    {
-      logger->log("Command", Log::INFO, "Switching to Old remote type");
-      remote->setRemoteType(Remote::OLDREMOTE);
-    }
-    delete[] config;
-  }
-  else
-  {
-    logger->log("Command", Log::INFO, "Config General/Remote type not found");
-    remote->setRemoteType(Remote::OLDREMOTE);
-  }
-
-
-
-
-  // Get TV aspect ratio
-
-  config = vdr->configLoad("TV", "Aspect");
-  if (config)
-  {
-    if (!STRCASECMP(config, "16:9"))
-    {
-      logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
-      video->setTVsize(Video::ASPECT16X9);
-    }
-    else
-    {
-      logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
-      video->setTVsize(Video::ASPECT4X3);
-    }
-    delete[] config;
-  }
-  else
-  {
-    logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
-    video->setTVsize(Video::ASPECT4X3);
-  }
-
-  config = vdr->configLoad("TV", "Widemode");
-  if (config)
-  {
-    if (!STRCASECMP(config, "Letterbox"))
-    {
-      logger->log("Command", Log::INFO, "Setting letterbox mode");
-      video->setMode(Video::LETTERBOX);
-    }
-    else
-    {
-      logger->log("Command", Log::INFO, "Setting chop-sides mode");
-      video->setMode(Video::NORMAL);
-    }
-    delete[] config;
-  }
-  else
-  {
-    logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
-    video->setMode(Video::NORMAL);
-  }
-
-  config = vdr->configLoad("Advanced", "TCP receive window");
-  if (config)
-  {
-    size_t newTCPsize = atoi(config);
-    delete[] config;
-
-    logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
-    vdr->setReceiveWindow(newTCPsize);
-  }
-  else
-  {
-    logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
-    vdr->setReceiveWindow(2048); // Default
-  }
-
-  config = vdr->configLoad("Advanced", "Disable WOL");
-  if (config)
-  {
-    if (!STRCASECMP(config, "Yes"))
-    {
-      logger->log("Command", Log::INFO, "Config says disable WOL");
-      Wol::getInstance()->setEnabled(false);
-    }
-    else
-    {
-      logger->log("Command", Log::INFO, "Config says enable WOL");
-      Wol::getInstance()->setEnabled(true);
-    }
-
-    delete[] config;
-  }
-  else
-  {
-    logger->log("Command", Log::INFO, "By default, enable WOL");
-    Wol::getInstance()->setEnabled(true);
-  }
-  /* device dependend config */
-  audio->loadOptionsfromServer(vdr);
-  video->loadOptionsfromServer(vdr);
-  remote->loadOptionsfromServer(vdr);
-  // config done
-
-  // Save power state = on
-
-  vdr->configSave("General", "Last Power State", "On");
-
-  // Make sure connection didn't die
-  if (!vdr->isConnected())
-  {
-    Command::getInstance()->connectionLost();
-  }
-  else
-  {
-    boxstack->remove(vi);
-
-    VWelcome* vw = new VWelcome();
-    vw->draw();
-    boxstack->add(vw);
-    boxstack->update(vw);
-
-    // Enter pre-keys here
-//    handleCommand(Remote::OK);
-//    handleCommand(Remote::THREE);
-//    handleCommand(Remote::SIX);
-//    handleCommand(Remote::OK);
-//    handleCommand(Remote::UP);
-//    handleCommand(Remote::PLAY);
-//    handleCommand(Remote::DOWN);
-//    handleCommand(Remote::DOWN);
-//    handleCommand(Remote::DOWN);
- //   handleCommand(Remote::OK);
-//    handleCommand(Remote::RED);
-  }
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef WIN32\r
+#include <linux/errno.h>\r
+#endif\r
+\r
+#include "command.h"\r
+\r
+#ifdef WIN32\r
+#include "remotewin.h"\r
+#endif\r
+\r
+#ifdef __ANDROID__\r
+#include "remoteandroid.h"\r
+#endif\r
+\r
+#include "led.h"\r
+#include "video.h"\r
+#include "audio.h"\r
+#include "vdr.h"\r
+#include "vvolume.h"\r
+#include "vserverselect.h"\r
+#include "vwelcome.h"\r
+#include "vmute.h"\r
+#include "colour.h"\r
+#include "osd.h"\r
+#include "i18n.h"\r
+#include "timerreceiver.h"\r
+#include "timers.h"\r
+#include "wol.h"\r
+#include "vconnect.h"\r
+#include "message.h"\r
+#include "remote.h"\r
+#include "vinfo.h"\r
+#include "boxx.h"\r
+#include "boxstack.h"\r
+#include "log.h"\r
+#include "vsleeptimer.h"\r
+\r
+\r
+Command* Command::instance = NULL;\r
+\r
+Command::Command()\r
+{\r
+  if (instance) return;\r
+  instance = this;\r
+  initted = 0;\r
+  isStandby = 0;\r
+  firstBoot = 1;\r
+  connLost = NULL;\r
+  crashed = false;\r
+  server = NULL;\r
+}\r
+\r
+Command::~Command()\r
+{\r
+  instance = NULL;\r
+}\r
+\r
+Command* Command::getInstance()\r
+{\r
+  return instance;\r
+}\r
+\r
+int Command::init(bool tcrashed, char* tServer)\r
+{\r
+  if (initted) return 0;\r
+  initted = 1;\r
+  crashed = tcrashed;\r
+  server = tServer;\r
+\r
+  logger = Log::getInstance();\r
+  boxstack = BoxStack::getInstance();\r
+  remote = Remote::getInstance();\r
+  \r
+  remote->InitHWCListwithDefaults();\r
+  \r
+  if (!logger || !boxstack || !remote)\r
+  {\r
+    initted = 0;\r
+    return 0;\r
+  }\r
+#ifndef WIN32\r
+  pthread_mutex_init(&masterLock, NULL);\r
+#else\r
+  masterLock=CreateMutex(NULL,FALSE,NULL);\r
+#endif\r
+\r
+  return 1;\r
+}\r
+\r
+int Command::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+  initted = 0;\r
+  return 1;\r
+}\r
+\r
+void Command::stop()\r
+{\r
+//  VDR::getInstance()->cancelFindingServer();\r
+       logger->log("Command", Log::NOTICE, "Command stop1...");\r
+       \r
+  udp.shutdown();\r
+  logger->log("Command", Log::NOTICE,  "Command stop2...");\r
+  irun = 0;\r
+}\r
+\r
+void Command::doWallpaper()\r
+{\r
+  Video* video = Video::getInstance();\r
+\r
+  // Blue background\r
+  Boxx* bbg = new Boxx();\r
+  bbg->setSize(video->getScreenWidth(), video->getScreenHeight());\r
+  bbg->createBuffer();\r
+  bbg->fillColour(Colour::VIDEOBLUE);\r
+  boxstack->add(bbg);\r
+  boxstack->update(bbg);\r
+  boxstack->remove(bbg);\r
+\r
+  // Wallpaper\r
+  WJpeg* wallpaperj = new WJpegTYPE();\r
+  wallpaperj->setSize(video->getScreenWidth(), video->getScreenHeight());\r
+  wallpaperj->createBuffer();\r
+\r
+  if (video->getFormat() == Video::PAL)\r
+  {\r
+    logger->log("Command", Log::DEBUG, "PAL wallpaper selected");\r
+#ifndef _MIPS_ARCH    \r
+    wallpaperj->init("/wallpaperPAL.jpg");\r
+#else\r
+    wallpaperj->init("wallpaperPAL.jpg");\r
+#endif\r
+  }\r
+  else\r
+  {\r
+    logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");\r
+    wallpaperj->init("/wallpaperNTSC.jpg");\r
+  }\r
+  wallpaperj->draw();\r
+\r
+  boxstack->add(wallpaperj);\r
+  boxstack->update(wallpaperj);\r
+\r
+  wallpaper = wallpaperj;\r
+}\r
+\r
+void Command::run()\r
+{\r
+  if (!initted) return;\r
+  irun = 1;\r
+#ifndef WIN32\r
+  mainPid = getpid();\r
+#endif\r
+\r
+  // just in case\r
+  Video::getInstance()->signalOn();\r
+  Led::getInstance()->on();\r
+\r
+  doWallpaper();\r
+\r
+  // End of startup. Lock the mutex and put the first view up\r
+//  logger->log("Command", Log::DEBUG, "WANT LOCK");\r
+#ifndef WIN32\r
+  pthread_mutex_lock(&masterLock);\r
+#else\r
+  WaitForSingleObject(masterLock, INFINITE );\r
+#endif\r
+  //logger->log("Command", Log::DEBUG, "LOCKED");\r
+\r
+  if (crashed)\r
+  {\r
+    buildCrashedBox();\r
+  }\r
+  else\r
+  {\r
+    VConnect* vconnect = new VConnect(server);\r
+    boxstack->add(vconnect);\r
+    vconnect->run();\r
+  }\r
+\r
+  // Start method 2 of getting commands in...\r
+  udp.run(this);\r
+\r
+  UCHAR button = 0;\r
+  while(irun)\r
+  {\r
+    // unlock and wait\r
+    //logger->log("Command", Log::DEBUG, "UNLOCK");\r
+#ifndef WIN32\r
+    pthread_mutex_unlock(&masterLock);\r
+#else\r
+    ReleaseMutex(masterLock);\r
+#endif\r
+       \r
+    button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit \r
+    // something happened, lock and process\r
+       \r
+    //  logger->log("Command", Log::DEBUG, "WANT LOCK");\r
+#ifndef WIN32\r
+    pthread_mutex_lock(&masterLock);\r
+#else\r
+    WaitForSingleObject(masterLock, INFINITE );\r
+#endif\r
+    // logger->log("Command", Log::DEBUG, "LOCK");\r
+\r
+    if ((button == Remote::NA_NONE) /*|| (button == Remote::NA_UNKNOWN)*/) continue;\r
+\r
+    if (button != Remote::NA_SIGNAL) handleCommand(button);\r
+    processMessageQueue();\r
+\r
+  }\r
+\r
+  //logger->log("Command", Log::DEBUG, "UNLOCK");\r
+#ifndef WIN32\r
+  pthread_mutex_unlock(&masterLock);\r
+#else\r
+  ReleaseMutex(masterLock);\r
+#endif\r
+\r
+\r
+}\r
+\r
+void Command::postMessage(Message* m)\r
+{\r
+  // This is locked here in case the main loop is not waiting for an event, but is processing one\r
+  // it could be killed but then not react to it because the signal wouldn't cause\r
+  // remote->getButtonPress to break\r
+  // locking the mutex ensures that the master thread is waiting on getButtonPress\r
+\r
+\r
+  //logger->log("Command", Log::DEBUG, "WANT LOCK");\r
+#ifndef WIN32\r
+  pthread_mutex_lock(&masterLock);\r
+#else\r
+  WaitForSingleObject(masterLock, INFINITE );\r
+#endif\r
+  //logger->log("Command", Log::DEBUG, "LOCK");\r
+  MessageQueue::postMessage(m);\r
+\r
+#ifndef WIN32\r
+#ifndef __ANDROID__\r
+  kill(mainPid, SIGURG);\r
+#else\r
+  ((RemoteAndroid*)Remote::getInstance())->Signal();\r
+#endif\r
+  pthread_mutex_unlock(&masterLock);\r
+#else\r
+  ((RemoteWin*)Remote::getInstance())->Signal();\r
+  ReleaseMutex(masterLock);\r
+#endif\r
+  //logger->log("Command", Log::DEBUG, "UNLOCK");\r
+}\r
+\r
+void Command::postMessageNoLock(Message* m)\r
+{\r
+  // As above but use this one if this message is being posted because of a button press\r
+  // the mutex is already locked, locking around postMessage is not needed as the\r
+  // queue is guaranteed to be run when the button has been processed\r
+  MessageQueue::postMessage(m);\r
+}\r
+\r
+bool Command::postMessageIfNotBusy(Message* m)\r
+{\r
+  // Used for Windows mouse events\r
+\r
+  //logger->log("Command", Log::DEBUG, "TRY LOCK");\r
+#ifndef WIN32\r
+  if (pthread_mutex_trylock(&masterLock) != EBUSY)\r
+  {\r
+    //logger->log("Command", Log::DEBUG, "LOCK");\r
+    MessageQueue::postMessage(m);\r
+#ifndef __ANDROID__\r
+    kill(mainPid, SIGURG);\r
+#else\r
+    ((RemoteAndroid*)Remote::getInstance())->Signal();\r
+#endif\r
+    pthread_mutex_unlock(&masterLock);\r
+    //logger->log("Command", Log::DEBUG, "UNLOCK");\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+#else\r
+  switch (WaitForSingleObject(masterLock, 0 ))\r
+  { //FIXME this is not "if not busy" check\r
+    case WAIT_OBJECT_0: //but with proper argument 0 this did not work\r
+    // case WAIT_ABANDONED:\r
+    MessageQueue::postMessage(m);\r
+    ((RemoteWin*)Remote::getInstance())->Signal();\r
+    ReleaseMutex(masterLock);\r
+    return true;\r
+\r
+    case WAIT_ABANDONED: return false;\r
+    case WAIT_TIMEOUT: return false;\r
+  }\r
+    return false;\r
+#endif\r
+}\r
+\r
+void Command::postMessageFromOuterSpace(Message* m)\r
+{\r
+  /*\r
+  Yet another way of getting messages into Command. This one is for events that\r
+  are not standard button presses (or UDP generated buttons). It is also not for\r
+  events that are generated as a result of other events (events that can safely\r
+  call postMessageNoLock and be guaranteed that the message will be processed\r
+  because it is known that the queue is currently being processed).\r
+  This is for events that come from outer space and can occur when the master\r
+  mutex is locked or not, they need to be queued and executed but it doesn't\r
+  matter when.\r
+  Actually so far it is for events caused by the video stream - aspect ratio\r
+  changes. These can occur when the master mutex is locked and so postMessage\r
+  doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*\r
+  locked at the time then the message could be sat around a while before\r
+  being noticed.\r
+  The whole message system was at first supposed to prevent the problem of\r
+  calling a function on an object that had just been deleted, by ordering\r
+  messages such that all calls are done before object deletion. However,\r
+  because of the new centralised messaging system and the fact that BoxStack\r
+  locates the destination object before calling it, the messaging system now\r
+  allows the kind of sloppy calls it was supposed to stop. Weird huh. This\r
+  is mentioned here because the video stream might generate an event just as\r
+  the user hits stop. The mutex is locked, and by the time the message\r
+  is examined the vvideorec/live has been deleted. This doesn't matter because\r
+  boxstack will drop the message if it can't find the matching object to\r
+  deliver it to.\r
+  Finally, all this is fine and dandy, except that I'm not 100% sure that\r
+  this sloppy postMessage and hope a queued signal will force it to be processed\r
+  thingy will actually work. Hmmm.\r
+  Lastly <g>, I will consider making the naming system a little more sane\r
+  if this works.\r
+  */\r
+\r
+  logger->log("Command", Log::DEBUG, "PMFOS called");\r
+  MessageQueue::postMessage(m);\r
+\r
+#ifndef WIN32\r
+#ifndef __ANDROID__\r
+  kill(mainPid, SIGURG);\r
+#else\r
+  ((RemoteAndroid*)Remote::getInstance())->Signal();\r
+#endif\r
+#else\r
+  ((RemoteWin*)Remote::getInstance())->Signal();\r
+#endif\r
+}\r
+\r
+void Command::processMessage(Message* m)\r
+{\r
+    // FIXME - a slight modification - how if messagereceivers were to register\r
+    // themselves as receivers to avoid the calling-a-deleted-object problem\r
+    // then only deliver/register/unregister would have to be protected\r
+\r
+  logger->log("Command", Log::DEBUG, "processing message %i", m->message);\r
+\r
+\r
+  if (m->to == this)\r
+  {\r
+    switch(m->message)\r
+    {\r
+      // << FIXME OBSELETE\r
+      case Message::STOP_PLAYBACK:\r
+      {\r
+        handleCommand(Remote::STOP); // an odd way of doing it, but so simple\r
+        break;\r
+      }\r
+      // Also connection_lost comes from player - anywhere else?\r
+      // FIXME OBSELETE >>\r
+\r
+\r
+      case Message::VDR_CONNECTED:\r
+      {\r
+        doJustConnected((VConnect*)m->from);\r
+        break;\r
+      }\r
+      case Message::SCREENSHOT:\r
+      {\r
+        Osd::getInstance()->screenShot("/out.jpg");\r
+        break;\r
+      }\r
+      case Message::CONNECTION_LOST:\r
+      {\r
+        doFromTheTop(true);\r
+        break;\r
+      }\r
+      case Message::UDP_BUTTON:\r
+      {\r
+        handleCommand(m->parameter);\r
+        break;\r
+      }\r
+      case Message::CHANGE_LANGUAGE:\r
+      {\r
+        boxstack->removeAll();\r
+        boxstack->update(wallpaper);\r
+        I18n::initialize();\r
+        if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }\r
+        VWelcome* vw = new VWelcome();\r
+        vw->draw();\r
+        boxstack->add(vw);\r
+        boxstack->update(vw);\r
+        break;\r
+      }\r
+      case Message::LAST_VIEW_CLOSE:\r
+      {\r
+        // Shouldn't be done like this. Some generic message pass back from vinfo perhaps\r
+        if (crashed)\r
+        {\r
+          crashed = false;\r
+          doFromTheTop(false);        \r
+        }\r
+      \r
+//        VWelcome* vw = new VWelcome();\r
+//        vw->draw();\r
+//        boxstack->add(vw);\r
+//        boxstack->update(vw);\r
+\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  else\r
+  {\r
+    /* FIXME\r
+    \r
+    Instead of sending through the boxstack, implement a more generic MessageReceiver interface\r
+    and have potential receivers register with something\r
+    When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message\r
+    This could all be done using the existing big command mutex to keep it simple\r
+    */\r
+  \r
+    logger->log("Command", Log::DEBUG, "Sending message to boxstack");\r
+    boxstack->processMessage(m);\r
+  }\r
+}\r
+\r
+void Command::handleCommand(int button)\r
+{\r
+  if (isStandby && (button != Remote::POWER)) return;\r
+  if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost\r
+\r
+  // command was not handled\r
+\r
+  switch(button)\r
+  {\r
+    case Remote::DF_LEFT:\r
+    case Remote::DF_RIGHT:\r
+    case Remote::VOLUMEUP:\r
+    case Remote::VOLUMEDOWN:\r
+    {\r
+      VVolume* v = new VVolume();\r
+      boxstack->add(v);\r
+      v->handleCommand(button); // this will draw+show\r
+      return;\r
+    }\r
+    case Remote::MUTE:\r
+    {\r
+      VMute* v = new VMute();\r
+      v->draw();\r
+      boxstack->add(v);\r
+      boxstack->update(v);\r
+      return;\r
+    }\r
+    case Remote::POWER:\r
+    {\r
+      doStandby();\r
+      return;\r
+    }\r
+    case Remote::OK:\r
+    {\r
+      // FIXME\r
+      if (!connLost) return; // if connLost, handle Remote::OK\r
+      doFromTheTop(false);\r
+      return;\r
+    }\r
+    case Remote::GO:\r
+    {\r
+      VSleeptimer* sleep = new VSleeptimer();\r
+      boxstack->add(sleep);\r
+      sleep->handleCommand(button); // this will draw+show\r
+      return;\r
+    }\r
+  }\r
+}\r
+\r
+void Command::sig1()\r
+{\r
+#ifdef DEV\r
+  Message* m = new Message(); // break into master mutex\r
+  m->message = Message::SCREENSHOT;\r
+  m->to = this;\r
+  postMessage(m);\r
+#endif\r
+}\r
+\r
+void Command::doStandby()\r
+{\r
+  if (isStandby)\r
+  {\r
+    Video::getInstance()->signalOn();\r
+    Led::getInstance()->on();\r
+    isStandby = 0;\r
+\r
+\r
+    VConnect* vconnect = new VConnect(server);\r
+    boxstack->add(vconnect);\r
+    vconnect->run();\r
+  }\r
+  else\r
+  {\r
+    boxstack->removeAll();\r
+    Video::getInstance()->signalOff();\r
+    boxstack->update(wallpaper);\r
+\r
+    VDR::getInstance()->configSave("General", "Last Power State", "Off");\r
+    logger->unsetExternLogger();\r
+    VDR::getInstance()->disconnect();\r
+    Led::getInstance()->off();\r
+    isStandby = 1;\r
+    Sleeptimer::getInstance()->shutdown();\r
+#ifdef WIN32\r
+    stop(); //different behavoiur on windows, we exit\r
+#endif\r
+  }\r
+}\r
+\r
+void Command::doFromTheTop(bool which)\r
+{\r
+  if (which)\r
+  {\r
+    if (connLost)\r
+    {\r
+      logger->log("Command", Log::NOTICE, "Connection lost dialog already present");\r
+      return;\r
+    }\r
+  \r
+    logger->log("Command", Log::NOTICE, "Doing connection lost dialog");\r
+    connLost = new VInfo();\r
+    connLost->setSize(360, 200);\r
+    connLost->createBuffer();\r
+    if (Video::getInstance()->getFormat() == Video::PAL)\r
+      connLost->setPosition(190, 170);\r
+    else\r
+      connLost->setPosition(180, 120);\r
+    connLost->setOneLiner(tr("Connection lost"));\r
+    connLost->setDropThrough();\r
+    connLost->setBorderOn(1);\r
+    connLost->setTitleBarColour(Colour::DANGER);\r
+    connLost->okButton();\r
+    connLost->draw();\r
+    boxstack->add(connLost);\r
+    boxstack->update(connLost);\r
+    remote->clearBuffer();\r
+  }\r
+  else\r
+  {\r
+    logger->unsetExternLogger();\r
+    VDR::getInstance()->disconnect();\r
+    boxstack->removeAll();\r
+    boxstack->update(wallpaper);\r
+    connLost = NULL;\r
+    \r
+    flushMessageQueue();\r
+    remote->clearBuffer();\r
+    \r
+    // at this point, everything should be reset to first-go\r
+    \r
+    VConnect* vconnect = new VConnect(server);\r
+    boxstack->add(vconnect);\r
+    vconnect->run();\r
+  }\r
+}\r
+\r
+void Command::doReboot()\r
+{\r
+\r
+  logger->unsetExternLogger();\r
+  VDR::getInstance()->disconnect();\r
+  // just kill it...\r
+  logger->log("Command", Log::NOTICE, "Reboot");\r
+#ifndef WIN32\r
+#ifdef VOMP_PLATTFORM_MVP\r
+  reboot(LINUX_REBOOT_CMD_RESTART);\r
+#else\r
+  stop();\r
+\r
+#ifdef __ANDROID__\r
+  exit(0);\r
+#endif\r
+\r
+#endif\r
+#endif //Would we support this on windows?\r
+}\r
+\r
+void Command::connectionLost()\r
+{\r
+  logger->unsetExternLogger();\r
+  Message* m = new Message(); // break into master mutex\r
+  m->message = Message::CONNECTION_LOST;\r
+  m->to = this;\r
+  postMessageFromOuterSpace(m);\r
+}\r
+\r
+void Command::buildCrashedBox()\r
+{\r
+  VInfo* crash = new VInfo();\r
+  crash->setSize(360, 250);\r
+  crash->createBuffer();\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+    crash->setPosition(190, 146);\r
+  else\r
+    crash->setPosition(180, 96);\r
+  crash->setMainText("Oops, vomp crashed.. :(\nPlease report this crash to the author, with as much detail as possible about what you were doing at the time that might have caused the crash.");\r
+  crash->setBorderOn(1);\r
+  crash->setTitleBarColour(Colour::DANGER);\r
+  crash->okButton();\r
+  crash->setExitable();\r
+  crash->draw();\r
+  boxstack->add(crash);\r
+  boxstack->update(crash);\r
+}\r
+\r
+void Command::doJustConnected(VConnect* vconnect)\r
+{\r
+  I18n::initialize();\r
+  if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }\r
+  \r
+  Video* video = Video::getInstance();\r
+  Audio* audio = Audio::getInstance();  \r
+  boxstack->remove(vconnect);\r
+\r
+  VInfo* vi = new VInfo();\r
+  vi->setSize(400, 200);\r
+  vi->createBuffer();\r
+  if (video->getFormat() == Video::PAL)\r
+    vi->setPosition(170, 200);\r
+  else\r
+    vi->setPosition(160, 150);\r
+  vi->setOneLiner(tr("Connected, loading config"));\r
+  vi->draw();\r
+  boxstack->add(vi);\r
+  boxstack->update(vi);\r
+\r
+  VDR* vdr = VDR::getInstance();\r
+  char* config;\r
+\r
+  // See if we're supposed to do network logging\r
+  config = vdr->configLoad("Advanced", "Network logging");\r
+  if (config && !STRCASECMP(config, "On"))\r
+  {\r
+    logger->log("Command", Log::INFO, "Turning on network logging");\r
+    logger->setExternLogger(vdr);\r
+  }  \r
+  else\r
+  {\r
+         logger->unsetExternLogger();\r
+    logger->log("Command", Log::INFO, "Turned off network logging");\r
+  }\r
+  if (config) delete[] config;\r
+\r
+  // See if config says to override video format (PAL/NTSC)\r
+  config = vdr->configLoad("General", "Override Video Format");\r
+  if (config)\r
+  {\r
+    logger->log("Command", Log::DEBUG, "Override Video Format is present");\r
+\r
+    if (   (!strcmp(config, "PAL") && (video->getFormat() == Video::NTSC))\r
+        || (!strcmp(config, "NTSC") && (video->getFormat() == Video::PAL))  )\r
+    {\r
+      // Oh sheesh, need to switch format. Bye bye TV...\r
+\r
+      // Take everything down\r
+      boxstack->removeAll();\r
+      boxstack->remove(wallpaper);\r
+      Osd* osd = Osd::getInstance();\r
+#ifndef __ANDROID__\r
+      osd->shutdown();\r
+#endif\r
+      video->shutdown();\r
+\r
+      // Get video and osd back up with the new mode\r
+      if (!strcmp(config, "PAL"))\r
+      {\r
+        logger->log("Command", Log::DEBUG, "Switching to PAL");\r
+        video->init(Video::PAL);\r
+      }\r
+      else if (!strcmp(config, "NTSC"))\r
+      {\r
+        logger->log("Command", Log::DEBUG, "Switching to NTSC");\r
+        video->init(Video::NTSC);\r
+      }\r
+#ifndef __ANDROID__\r
+      //we do not init twice\r
+      osd->init((char*)("/dev/stbgfx"));\r
+#endif\r
+\r
+      // Put the wallpaper back\r
+      doWallpaper();\r
+\r
+      // Re add the vinfo\r
+      vi = new VInfo();\r
+      vi->setSize(400, 200);\r
+      vi->createBuffer();\r
+      if (video->getFormat() == Video::PAL)\r
+        vi->setPosition(170, 200);\r
+      else\r
+        vi->setPosition(160, 150);\r
+\r
+      vi->setOneLiner(tr("Connected, loading config"));\r
+      vi->draw();\r
+      boxstack->add(vi);\r
+      boxstack->update(vi);\r
+    }\r
+    else\r
+    {\r
+      logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");\r
+    }\r
+  }\r
+  else\r
+  {\r
+    logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");\r
+  }\r
+\r
+  // Power off if first boot and config says so\r
+  if (firstBoot)\r
+  {\r
+    firstBoot = 0;\r
+\r
+    logger->log("Command", Log::DEBUG, "Load power after boot");\r
+\r
+    config = vdr->configLoad("General", "Power After Boot");\r
+\r
+    if (config)\r
+    {\r
+      if (!STRCASECMP(config, "On"))\r
+      {\r
+        logger->log("Command", Log::INFO, "Config says Power After Boot = On");\r
+      }\r
+      else if (!STRCASECMP(config, "Off"))\r
+      {\r
+        logger->log("Command", Log::INFO, "Config says Power After Boot = Off");\r
+        doStandby();\r
+        delete[] config;\r
+        return; // quit here\r
+      }\r
+      else if (!STRCASECMP(config, "Last state"))\r
+      {\r
+        char* lastPowerState = vdr->configLoad("General", "Last Power State");\r
+        if (lastPowerState)\r
+        {\r
+          if (!STRCASECMP(lastPowerState, "On"))\r
+          {\r
+            logger->log("Command", Log::INFO, "Config says Last Power State = On");\r
+          }\r
+          else if (!STRCASECMP(lastPowerState, "Off"))\r
+          {\r
+            logger->log("Command", Log::INFO, "Config says Last Power State = Off");\r
+            doStandby();\r
+            delete[] config;\r
+            return; // quit here\r
+          }\r
+          else\r
+          {\r
+            logger->log("Command", Log::INFO, "Config General/Last Power State not understood");\r
+          }\r
+        }\r
+        else\r
+        {\r
+          logger->log("Command", Log::INFO, "Config General/Last Power State not found");\r
+        }\r
+      }\r
+      else\r
+      {\r
+        logger->log("Command", Log::INFO, "Config/Power After Boot not understood");\r
+      }\r
+      delete[] config;\r
+    }\r
+    else\r
+    {\r
+      logger->log("Command", Log::INFO, "Config General/Power After Boot not found");\r
+    }\r
+  }\r
+\r
+\r
+  // Go S-Video if config says so\r
+\r
+  config = vdr->configLoad("TV", "Connection");\r
+\r
+  if (config)\r
+  {\r
+    if (!STRCASECMP(config, "S-Video"))\r
+    {\r
+      logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);\r
+      video->setConnection(Video::SVIDEO);\r
+    }\r
+    else\r
+    {\r
+      logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);\r
+      video->setConnection(Video::COMPOSITERGB);\r
+    }\r
+    delete[] config;\r
+  }\r
+  else\r
+  {\r
+    logger->log("Command", Log::INFO, "Config TV/S-Video not found");\r
+  }\r
+\r
+  // Set remote type\r
+\r
+  config = vdr->configLoad("General", "Remote type");\r
+\r
+  if (config)\r
+  {\r
+    if (!STRCASECMP(config, "New"))\r
+    {\r
+      logger->log("Command", Log::INFO, "Switching to New remote type");\r
+      remote->setRemoteType(Remote::NEWREMOTE);\r
+    }\r
+    else\r
+    {\r
+      logger->log("Command", Log::INFO, "Switching to Old remote type");\r
+      remote->setRemoteType(Remote::OLDREMOTE);\r
+    }\r
+    delete[] config;\r
+  }\r
+  else\r
+  {\r
+    logger->log("Command", Log::INFO, "Config General/Remote type not found");\r
+    remote->setRemoteType(Remote::OLDREMOTE);\r
+  }\r
+\r
+\r
+\r
+\r
+  // Get TV aspect ratio\r
+\r
+  config = vdr->configLoad("TV", "Aspect");\r
+  if (config)\r
+  {\r
+    if (!STRCASECMP(config, "16:9"))\r
+    {\r
+      logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");\r
+      video->setTVsize(Video::ASPECT16X9);\r
+    }\r
+    else\r
+    {\r
+      logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");\r
+      video->setTVsize(Video::ASPECT4X3);\r
+    }\r
+    delete[] config;\r
+  }\r
+  else\r
+  {\r
+    logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");\r
+    video->setTVsize(Video::ASPECT4X3);\r
+  }\r
+\r
+  config = vdr->configLoad("TV", "Widemode");\r
+  if (config)\r
+  {\r
+    if (!STRCASECMP(config, "Letterbox"))\r
+    {\r
+      logger->log("Command", Log::INFO, "Setting letterbox mode");\r
+      video->setMode(Video::LETTERBOX);\r
+    }\r
+    else\r
+    {\r
+      logger->log("Command", Log::INFO, "Setting chop-sides mode");\r
+      video->setMode(Video::NORMAL);\r
+    }\r
+    delete[] config;\r
+  }\r
+  else\r
+  {\r
+#ifdef __ANDROID__\r
+        logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting letterbox mode");\r
+        video->setMode(Video::LETTERBOX);\r
+#else\r
+    logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");\r
+    video->setMode(Video::NORMAL);\r
+#endif\r
+  }\r
+\r
+  config = vdr->configLoad("Advanced", "TCP receive window");\r
+  if (config)\r
+  {\r
+    size_t newTCPsize = atoi(config);\r
+    delete[] config;\r
+\r
+    logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);\r
+    vdr->setReceiveWindow(newTCPsize);\r
+  }\r
+  else\r
+  {\r
+    logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");\r
+    vdr->setReceiveWindow(2048); // Default\r
+  }\r
+\r
+  config = vdr->configLoad("Advanced", "Disable WOL");\r
+  if (config)\r
+  {\r
+    if (!STRCASECMP(config, "Yes"))\r
+    {\r
+      logger->log("Command", Log::INFO, "Config says disable WOL");\r
+      Wol::getInstance()->setEnabled(false);\r
+    }\r
+    else\r
+    {\r
+      logger->log("Command", Log::INFO, "Config says enable WOL");\r
+      Wol::getInstance()->setEnabled(true);\r
+    }\r
+\r
+    delete[] config;\r
+  }\r
+  else\r
+  {\r
+    logger->log("Command", Log::INFO, "By default, enable WOL");\r
+    Wol::getInstance()->setEnabled(true);\r
+  }\r
+  /* device dependend config */\r
+  audio->loadOptionsfromServer(vdr);\r
+  video->loadOptionsfromServer(vdr);\r
+  remote->loadOptionsfromServer(vdr);\r
+  // config done\r
+\r
+  // Save power state = on\r
+\r
+  vdr->configSave("General", "Last Power State", "On");\r
+\r
+  // Make sure connection didn't die\r
+  if (!vdr->isConnected())\r
+  {\r
+    Command::getInstance()->connectionLost();\r
+  }\r
+  else\r
+  {\r
+    boxstack->remove(vi);\r
+\r
+    VWelcome* vw = new VWelcome();\r
+    vw->draw();\r
+    boxstack->add(vw);\r
+    boxstack->update(vw);\r
+\r
+    // Enter pre-keys here\r
+//    handleCommand(Remote::OK);\r
+//    handleCommand(Remote::THREE);\r
+//    handleCommand(Remote::SIX);\r
+//    handleCommand(Remote::OK);\r
+//    handleCommand(Remote::UP);\r
+//    handleCommand(Remote::PLAY);\r
+//    handleCommand(Remote::DOWN);\r
+//    handleCommand(Remote::DOWN);\r
+//    handleCommand(Remote::DOWN);\r
+ //   handleCommand(Remote::OK);\r
+//    handleCommand(Remote::RED);\r
+  }\r
+}\r
index f082f533d5518bb3305d44a457e051e121276fcd..7a9abbb19ae9a8564373192b9a04526b2b8f2b3c 100644 (file)
--- a/defines.h
+++ b/defines.h
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef DEFINES_H
-#define DEFINES_H
-
-typedef unsigned char UCHAR;
-typedef unsigned short USHORT;
-typedef unsigned int UINT;
-typedef unsigned long ULONG;
-typedef unsigned long long ULLONG;
-
-#define OPTIONTYPE_TEXT 1
-#define OPTIONTYPE_INT 2
-
-ULLONG htonll(ULLONG a);
-ULLONG ntohll(ULLONG a);
-void MILLISLEEP(ULONG a);
-
-#ifdef WIN32
-
-  #define Surface_TYPE SurfaceWin
-  #define Thread_TYPE ThreadWin
-  #define ThreadID_TYPE unsigned int
-
-  #define SNPRINTF _snprintf
-  #define VSNPRINTF _vsnprintf
-  #define STRCASECMP _stricmp
-  #define STRCASESTR StrStrI
-/*  #define STRTOULL _strtoui64 */
-  #define STRTOUL strtoul
-  #define CLOSESOCKET closesocket
-
-#else
-
-  int max(int, int);
-  int min(UINT, int);
-#ifdef _MIPS_ARCH  
-  #define Surface_TYPE SurfaceDirectFB
-#else
-  #define Surface_TYPE SurfaceMVP
-#endif
-
-  #define Thread_TYPE ThreadP
-  #include <pthread.h>
-  #define ThreadID_TYPE pthread_t
-
-  #define SNPRINTF snprintf
-  #define VSNPRINTF vsnprintf
-  #define STRCASECMP strcasecmp
-  #define STRCASESTR strcasestr
-  #define STRTOUL strtoul
-  #define CLOSESOCKET close
-
-#endif
-
-/*
-typedef struct
-{
-  UINT id;               // Used for working out what has changed at the end
-  char *title;           // Name of the option
-  char *configSection;   // Which section of the config file
-  char *configParam;     // Parameter name in the config file
-  UINT optionType;       // 1 for text, 2 for int
-  UINT optionCount;      // How many choices?
-  UINT defaultOption;    // Serial of the default choice (base 0), or actual option in int mode
-  int startInt;          // Starting int for int mode
-  const char * const * options;  // Text for the options (null for int mode)
-} OPTIONDATA;
-*/
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef DEFINES_H\r
+#define DEFINES_H\r
+\r
+typedef unsigned char UCHAR;\r
+typedef unsigned short USHORT;\r
+typedef unsigned int UINT;\r
+typedef unsigned long ULONG;\r
+typedef unsigned long long ULLONG;\r
+\r
+#define OPTIONTYPE_TEXT 1\r
+#define OPTIONTYPE_INT 2\r
+\r
+//ULLONG htonll(ULLONG a);\r
+//ULLONG ntohll(ULLONG a);\r
+void MILLISLEEP(ULONG a);\r
+\r
+#ifdef WIN32\r
+\r
+  #define Surface_TYPE SurfaceWin\r
+  #define Thread_TYPE ThreadWin\r
+  #define ThreadID_TYPE unsigned int\r
+\r
+  #define SNPRINTF _snprintf\r
+  #define VSNPRINTF _vsnprintf\r
+  #define STRCASECMP _stricmp\r
+  #define STRCASESTR StrStrI\r
+/*  #define STRTOULL _strtoui64 */\r
+  #define STRTOUL strtoul\r
+  #define CLOSESOCKET closesocket\r
+\r
+\r
+#else\r
+\r
+  int max(int, int);\r
+  int min(UINT, int);\r
+/*#ifdef _MIPS_ARCH\r
+  #define Surface_TYPE SurfaceDirectFB\r
+#else\r
+  #define Surface_TYPE SurfaceMVP\r
+#endif*/\r
+#ifdef __ANDROID__\r
+  #define Thread_TYPE ThreadPAndroid\r
+\r
+#else\r
+  #define Thread_TYPE ThreadP\r
+\r
+#endif\r
+  #include <pthread.h>\r
+  #define ThreadID_TYPE pthread_t\r
+\r
+  #define SNPRINTF snprintf\r
+  #define VSNPRINTF vsnprintf\r
+  #define STRCASECMP strcasecmp\r
+  #define STRCASESTR strcasestr\r
+  #define STRTOUL strtoul\r
+  #define CLOSESOCKET close\r
+\r
+// add here defines for plattform specific objects\r
+#ifdef VOMP_PLATTFORM_RASPBERRY\r
+   #define Remote_TYPE RemoteLinux  // Generic Remote under Linux (Konsole!, not X) will support in the end:\r
+   #define RemoteStartDev ""//No devices passed\r
+\r
+  // Keyboard\r
+  // remotes under /dev/event\r
+  // HDMI CEC\r
+  //lirc?\r
+   #define Mtd_TYPE MtdRaspberry  //this is device dependent\r
+   #define Led_TYPE LedRaspberry  //this is device dependent\r
+   #define Osd_TYPE OsdOpenGL   // This OpenGL ES 2.0, in the moment only for raspberry, but might be splitted for other devices\r
+   #define OsdStartDev ""\r
+   #define Audio_TYPE AudioVPE   // This is Audio based on VPE (Vomp Presentation Engine) should support OpenMax and Alsa with ffmpeg in the end\r
+   #define Video_TYPE VideoVPEOGL   // This is Video based on VPE (Vomp Presentation Engine) should support OpenMax and ffmpeg and opengl in the end\r
+\r
+#endif\r
+#ifdef VOMP_PLATTFORM_MVP\r
+  #define Remote_TYPE RemoteMVP\r
+  #define RemoteStartDev "/dev/rawir"\r
+  #define Mtd_TYPE MtdMVP\r
+  #define Led_TYPE LedMVP\r
+  #define Osd_TYPE OsdMVP\r
+  #define OsdStartDev "/dev/stbgfx"\r
+  #define Audio_TYPE AudioMVP\r
+  #define Video_TYPE VideoMVP\r
+#endif\r
+\r
+#ifdef VOMP_PLATTFORM_NMT // This was the attempt to port vomp to nmt, it failed but maybe the code is useful at some time\r
+  #define Remote_TYPE RemoteLirc\r
+  #define RemoteStartDev "/dev/lircd"\r
+  #define Mtd_TYPE MtdNMT\r
+  #define Led_TYPE LedMVP\r
+  #define Osd_TYPE OsdDirectFB\r
+  #define OsdStartDev ""\r
+  #define Audio_TYPE AudioNMT\r
+  #define Video_TYPE VideoNMT\r
+\r
+#endif\r
+\r
+#endif\r
+\r
+/*\r
+typedef struct\r
+{\r
+  UINT id;               // Used for working out what has changed at the end\r
+  char *title;           // Name of the option\r
+  char *configSection;   // Which section of the config file\r
+  char *configParam;     // Parameter name in the config file\r
+  UINT optionType;       // 1 for text, 2 for int\r
+  UINT optionCount;      // How many choices?\r
+  UINT defaultOption;    // Serial of the default choice (base 0), or actual option in int mode\r
+  int startInt;          // Starting int for int mode\r
+  const char * const * options;  // Text for the options (null for int mode)\r
+} OPTIONDATA;\r
+*/\r
+\r
+#endif\r
index 3d3f3585ac4efd1eb873d077475952fe0c890bcb..e2e2fe7ba2e88edbffab53867dfc18b2624a4495 100644 (file)
-/*
-    Copyright 2005-2008 Mark Calderbank
-    Copyright 2007 Marten Richter (AC3 support)
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "demuxer.h"
-
-#include "callback.h"
-#include "dvbsubtitles.h"
-#include "log.h"
-
-#include <cstdlib>
-
-#include <math.h>
-
-#define DEMUXER_SEQ_HEAD 0x000001B3
-#define DEMUXER_PIC_HEAD 0x00000101
-
-#define DEMUXER_H264_ACCESS_UNIT 0x00000109
-#define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107
-
-
-#define SEEK_THRESHOLD 150000 // About 1.5 seconds
-
-// Statics
-const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };
-Demuxer* Demuxer::instance = NULL;
-
-class NALUUnit {
-public:
-    NALUUnit(const UCHAR* buf,UINT length_buf);
-    ~NALUUnit();
-
-inline    UINT getBits(UINT num_bits);
-    UINT getUe();
-    int getSe();
-    bool isEonalu() {return eonalu;};
-
-protected:
-    UCHAR* nalu_buf;
-    UINT nalu_length;
-    UINT pos;
-    UCHAR bit_pos;
-    UCHAR working_byte;
-    UINT last_bytes;
-    bool eonalu;
-};
-
-NALUUnit::NALUUnit(const UCHAR *buf, UINT length_buf)
-{
-    nalu_length=0;
-    nalu_buf=NULL;
-    pos=0;
-    bit_pos=0;
-    working_byte=0;
-    last_bytes=0;
-    eonalu=false;
-
-    UINT nalu_start=0;
-    UINT nalu_end=0;
-    UINT pattern =(((UINT)buf[ 0] << 16) |
-                   ((UINT)buf[1] <<  8) |
-                    (UINT)buf[2]  );
-    nalu_start=3;
-    while (pattern != 0x000001)
-    {
-        if (++nalu_start >= length_buf) return;
-        pattern = ((pattern << 8) | buf[nalu_start])&0x00FFFFFF;
-    }
-    nalu_end=nalu_start+1;
-    pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;
-
-    while (pattern != 0x000001 && pattern != 0x000000)
-    {
-        if (++nalu_end >= length_buf) { nalu_end+=3;break;};
-        pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;
-    }
-    nalu_end-=3;
-    nalu_end=min(length_buf-1,nalu_end);
-    nalu_length=nalu_end-nalu_start;
-    nalu_buf=(UCHAR*)malloc(nalu_length);
-    memcpy(nalu_buf,buf+nalu_start,nalu_length);
-    pos=1;
-}
-
-NALUUnit::~NALUUnit()
-{
-    if (nalu_buf) free(nalu_buf);
-}
-
-inline UINT NALUUnit::getBits(UINT num_bits)
-{
-    if (num_bits==0) return 0; //???
-    UINT remain_bits=num_bits;
-    UINT work=0;
-    //May be slow, but should work!
-    while (remain_bits>0) {
-        if (bit_pos==0) {
-            if (pos<nalu_length)
-            {
-                last_bytes=(last_bytes<<8) & nalu_buf[pos];
-                if ((last_bytes & 0x00FFFFFF) == 0x000003) pos++; //emulation prevention byte
-                 if (pos<nalu_length)
-                 {
-                     working_byte=nalu_buf[pos];
-                     pos++;
-                 } 
-                 else
-                 {
-                     working_byte=0;
-                     eonalu=true;
-                 }
-            } 
-            else
-            {
-                working_byte=0;
-                eonalu=true;
-            }
-
-        }
-        UINT fetch_bits=min(remain_bits,8-bit_pos);
-        work=work <<fetch_bits;
-        //work|=((working_byte>>bit_pos) & (0xFF>>(8-fetch_bits)));
-        work|=(working_byte &(0xFF>>(bit_pos)))>>(8-fetch_bits-bit_pos);
-        remain_bits-=fetch_bits;
-        bit_pos=(bit_pos+fetch_bits)%8;
-    }
-    return work;
-}
-
-UINT NALUUnit::getUe()
-{
-    int leadbits=-1;
-    bool bit;
-    for( bit = 0; !bit && !eonalu; leadbits++ )
-        bit = getBits(1);
-    if (eonalu) return true;
-    return ((1 << leadbits)-1)+getBits(leadbits);
-}
-
-int NALUUnit::getSe()
-{
-    UINT input=getUe();
-    if (input==0) return 0;
-    int output=((input+1)>>1);
-    if (input & 0x1) output*=-1;
-    return output;
-}
-
-
-
-static const int PESPacket_initial_size = 2000;
-
-// PESPacket methods
-PESPacket::PESPacket()
-{
-  data_size = PESPacket_initial_size;
-  data = (UCHAR*)malloc(data_size);
-  data[0] = 0x00;
-  data[1] = 0x00;
-  data[2] = 0x01;
-  init(0);
-}
-
-PESPacket::PESPacket(const PESPacket& packet)
-{
-  copyFrom(packet);
-}
-
-PESPacket& PESPacket::operator=(const PESPacket& packet)
-{
-  if (this != &packet)
-  {
-    if (data) free(data);
-    copyFrom(packet);
-  }
-  return *this;
-}
-
-PESPacket::~PESPacket()
-{
-  if (data) free(data);
-}
-
-void PESPacket::copyFrom(const PESPacket& packet)
-{
-  length = packet.length;
-  size = packet.size;
-  packetType = packet.packetType;
-  substream = packet.substream;
-  seq_header = packet.seq_header;
-  data_size = size;
-  data = (UCHAR*)malloc(data_size);
-  memcpy(data, packet.data, data_size);
-}
-
-void PESPacket::init(UCHAR type, UCHAR sub)
-{
-  length = 0; 
-  size = 6;
-  data[4] = data[5] = 0;
-  data[3] = type;
-  packetType = type;
-  substream = sub;
-  seq_header = 1; // Unknown seq_header status
-}
-
-void PESPacket::truncate()
-{
-  init(packetType,substream);
-}
-
-int PESPacket::write(const UCHAR *buf, int len)
-{
-  if (size + len > 0x10000) return 0;
-  if (size + len > data_size)
-  { // Reallocate
-    UINT new_data_size = max(data_size + data_size / 2, data_size + len);
-    if (new_data_size > 0x10000) new_data_size = 0x10000;
-    data_size = new_data_size;
-    data = (UCHAR*)realloc(data, data_size);
-  }
-  memcpy(data + size, buf, len);
-  length += len;
-  size += len;
-  data[4] = (length >> 8);
-  data[5] = (length & 0xFF);
-  // We have added data - reset seq_header indicator if necessary
-  if (seq_header == 0) seq_header = 1; // Reset to 'unknown'
-  return 1;
-}
-
-ULLONG PESPacket::getPTS() const
-{
-  if ( ( (packetType >= Demuxer::PESTYPE_AUD0 &&
-          packetType <= Demuxer::PESTYPE_AUDMAX)
-        ||
-         (packetType >= Demuxer::PESTYPE_VID0 &&
-          packetType <= Demuxer::PESTYPE_VIDMAX)
-   ||
-          packetType == Demuxer::PESTYPE_PRIVATE_1
-       )
-       && size >= 14 && data[7] & 0x80)
-  {
-    return ( (ULLONG)(data[ 9] & 0x0E) << 29) |
-           ( (ULLONG)(data[10])        << 22 ) |
-           ( (ULLONG)(data[11] & 0xFE) << 14 ) |
-           ( (ULLONG)(data[12])        <<  7 ) |
-           ( (ULLONG)(data[13] & 0xFE) >>  1 );
-  }
-  else return PTS_INVALID;
-}
-
-UCHAR PESPacket::operator[] (UINT index) const
-{
-  if (index >= size)
-    return 0;
-  else
-    return data[index];
-}
-
-UINT PESPacket::findPictureHeader(bool h264) const
-{
-  if (size < 12) return 0;
-  UINT pattern = ( ((UINT)data[ 8] << 24) |
-                   ((UINT)data[ 9] << 16) |
-                   ((UINT)data[10] <<  8) |
-                    (UINT)data[11]  );
-  UINT pos = 11;
-  if (h264) {
-         
-         while (pattern != DEMUXER_H264_ACCESS_UNIT)
-         {
-                 if (++pos >= size) return 0;
-                 pattern = (pattern << 8) | data[pos];
-         }
-         return pos-3;
-  } else {
-         while (pattern != DEMUXER_PIC_HEAD)
-         {
-                 if (++pos >= size) return 0;
-                 pattern = (pattern << 8) | data[pos];
-         }
-         return pos-3;
-  }
-}
-
-UINT PESPacket::countPictureHeaders(bool h264) const
-{
-  if (size < 12) return 0;
-  UINT pattern = ( ((UINT)data[ 8] << 24) |
-                   ((UINT)data[ 9] << 16) |
-                   ((UINT)data[10] <<  8) |
-                    (UINT)data[11]  );
-  UINT pos = 11;
-  UINT count=0;
-  if (h264) {
-         
-         while (pos<size)
-         {
-          pos++;
-                 pattern = (pattern << 8) | data[pos];
-          if (pattern==DEMUXER_H264_ACCESS_UNIT) count++;
-         }
-         return count;
-  } else {
-      while (pos<size)
-         {
-          pos++;
-                 pattern = (pattern << 8) | data[pos];
-          if (pattern==DEMUXER_PIC_HEAD) count++;
-         }
-         return count;
-  }
-}
-
-UINT PESPacket::findSeqHeader(bool h264) const
-{
-  if (seq_header != 1) return seq_header;
-  if (size < 12) return 0;
-  UINT pattern = ( ((UINT)data[ 8] << 24) |
-                   ((UINT)data[ 9] << 16) |
-                   ((UINT)data[10] <<  8) |
-                    (UINT)data[11]  );
-  UINT pos = 11;
-  if (h264) {
-      while ((pattern & 0xFFFFFF1F) != DEMUXER_H264_SEQ_PARAMETER_SET)
-         {
-                 if (++pos >= size)
-                 {
-                         seq_header = 0;
-                         return 0;
-                 }
-                 pattern = (pattern << 8) | data[pos];
-         }
-         seq_header = pos - 3;
-  } 
-  else 
-  {
-         while (pattern != DEMUXER_SEQ_HEAD)
-         {
-                 if (++pos >= size)
-                 {
-                         seq_header = 0;
-                         return 0;
-                 }
-                 pattern = (pattern << 8) | data[pos];
-         }
-         seq_header = pos - 3;
-  }
-  return seq_header;
-}
-
-// Demuxer methods
-Demuxer::Demuxer()
-{
-  if (instance) return;
-  instance = this;
-  initted = false;
-  callback = NULL;
-  arcnt = 0;
-  vid_seeking = aud_seeking = false;
-  video_pts = audio_pts = 0;
-  ispre_1_3_19 = false;
-  packetnum=0;
-  h264 = false;
-  fps = 25.0;
-}
-
-Demuxer::~Demuxer()
-{
-  shutdown();
-  instance = NULL;
-}
-
-Demuxer* Demuxer::getInstance()
-{
-  return instance;
-}
-
-int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, DrainTarget* teletext,
-                  ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT,double infps, DVBSubtitles* tsubtitles)
-{
-  if (!initted)
-  {
-    if ( !videostream.init(video, demuxMemoryV) ||
-         !audiostream.init(audio, demuxMemoryA) ||
-         !teletextstream.init(teletext, demuxMemoryT))
-    {
-      Log::getInstance()->log("Demuxer", Log::CRIT,
-                              "Failed to initialize demuxer");
-      shutdown();
-      return 0;
-    }
-  }
-  if (teletext) {
-      isteletextdecoded = true;
-  } else {
-      isteletextdecoded = false;
-  }
-  fps=infps;
-  reset();
-  initted = true;
-  subtitles = tsubtitles;
-  callback = tcallback;
-  return 1;
-}
-
-void Demuxer::reset()
-{
-  Log::getInstance()->log("Demuxer", Log::DEBUG, "Reset called");
-  flush();
-  video_current = audio_current = teletext_current = subtitle_current = -1;
-  horizontal_size = vertical_size = 0;
-  aspect_ratio = (enum AspectRatio) 0;
-  frame_rate = bit_rate = 0;
-  ispre_1_3_19 = false;
-  h264 = false;
-  packetnum=0;
-
-  for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++)
-  {
-    avail_mpaudchan[i] = false;
-  }
-  for (int i = 0; i <= (PESTYPE_SUBSTREAM_AC3MAX - PESTYPE_SUBSTREAM_AC30); i++)
-  {
-    avail_ac3audchan[i] = false;
-  }
-  for (int i = 0; i <= (PESTYPE_SUBSTREAM_DVBSUBTITLEMAX - PESTYPE_SUBSTREAM_DVBSUBTITLE0); i++)
-  {
-    avail_dvbsubtitlechan[i] = false;
-  }
-}
-
-int Demuxer::shutdown()
-{
-  videostream.shutdown();
-  audiostream.shutdown();
-  teletextstream.shutdown();
-  initted = false;
-  return 1;
-}
-
-void Demuxer::flush()
-{
-  Log::getInstance()->log("Demuxer", Log::DEBUG, "Flush called");
-
-  videostream.flush();
-  audiostream.flush();
-  teletextstream.flush();
-}
-
-void Demuxer::flushAudio()
-{
-  audiostream.flush();
-}
-
-void Demuxer::seek()
-{
-  vid_seeking = aud_seeking = true;
-  video_pts = audio_pts = teletext_pts = 0;
-}
-
-void Demuxer::setAudioStream(int id)
-{
-  audio_current = id;
-}
-
-void Demuxer::setVideoStream(int id)
-{
-  video_current = id;
-}
-
-void Demuxer::setTeletextStream(int id)
-{
-  teletext_current = id;
-}
-
-void Demuxer::setDVBSubtitleStream(int id)
-{
-  subtitle_current = id;
-}
-
-void Demuxer::setAspectRatio(enum AspectRatio ar)
-{
-  if (aspect_ratio != ar)
-  {
-    Log::getInstance()->log("Demux", Log::DEBUG,
-                            "Aspect ratio difference signalled");
-    if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal
-    {
-      arcnt = 0;
-      aspect_ratio = ar;
-      if (callback) callback->call(this);
-    }
-  }
-  else
-    arcnt = 0;
-}
-
-bool Demuxer::writeAudio()
-{
-  return audiostream.drain();
-}
-
-bool Demuxer::writeVideo()
-{
-  return videostream.drain();
-}
-
-bool Demuxer::writeTeletext()
-{
-   return teletextstream.drain();
-}
-
-bool Demuxer::submitPacket(PESPacket& packet)
-{
-  UINT sent = 0;
-  UCHAR packet_type = packet.getPacketType();
-  const UCHAR* packetdata = packet.getData();
-  if (packet_type >= PESTYPE_VID0 && packet_type <= PESTYPE_VIDMAX)
-  {
-    if (video_current == -1) video_current = packet_type;
-    if (video_current == packet_type && !vid_seeking)
-       {
-        sent = videostream.put(&packetdata[0], packet.getSize(), h264?MPTYPE_VIDEO_H264:MPTYPE_VIDEO_MPEG2,packetnum);
-        if (sent) packetnum++;
-       }
-       else
-      sent = packet.getSize();
-  }
-  else if (packet_type >= PESTYPE_AUD0 && packet_type <= PESTYPE_AUDMAX)
-  {
-    if (audio_current == -1) audio_current = packet_type;
-    avail_mpaudchan[packet_type - PESTYPE_AUD0] = true;
-    if (audio_current == packet_type && !aud_seeking)
-       {
-      sent = audiostream.put(&packetdata[0], packet.getSize(), MPTYPE_MPEG_AUDIO,packetnum);
-         if (sent)  packetnum++;
-       }
-       else
-      sent = packet.getSize();
-  }
-  else if (packet_type == PESTYPE_PRIVATE_1 &&
-           packet.getSubstream() >= PESTYPE_SUBSTREAM_AC30 &&
-           packet.getSubstream() <= PESTYPE_SUBSTREAM_AC3MAX)
-  {
-    avail_ac3audchan[packet.getSubstream() - PESTYPE_SUBSTREAM_AC30] = true;
-    if (packet.getSubstream() == audio_current)
-    {
-      sent = audiostream.put(&packetdata[0], packet.getSize(), (ispre_1_3_19)? MPTYPE_AC3_PRE13 : MPTYPE_AC3,packetnum);
-         if (sent) packetnum++;
-    }
-    else
-    {
-      sent = packet.getSize();
-    }
-  }
-  else if (packet_type == PESTYPE_PRIVATE_1 &&
-           packet.getSubstream() >= PESTYPE_SUBSTREAM_DVBSUBTITLE0 &&
-           packet.getSubstream() <= PESTYPE_SUBSTREAM_DVBSUBTITLEMAX)
-  {
-    avail_dvbsubtitlechan[packet.getSubstream()-PESTYPE_SUBSTREAM_DVBSUBTITLE0]=true;
-    if (subtitle_current == -1) subtitle_current = packet.getSubstream();
-    if (subtitles && packet.getSubstream()==subtitle_current)
-    {
-         subtitles->put(packet);
-    }
-    sent = packet.getSize();
-  }
-  else if (isteletextdecoded  && packet_type == PESTYPE_PRIVATE_1 &&
-           packet.getSubstream() >= PESTYPE_SUBSTREAM_TELETEXT0 &&
-           packet.getSubstream() <= PESTYPE_SUBSTREAM_TELETEXTMAX)
-  {
-
-    if (teletext_current == -1) teletext_current = packet.getSubstream();
-    if (teletext_current == packet.getSubstream() )
-    {
-        sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT,packetnum);
-    }
-    else 
-    {
-        sent = packet.getSize();
-    }
-  }
-  else
-  {
-    sent = packet.getSize();
-  }
-
-  if (sent < packet.getSize()) // Stream is full.
-    return false;
-  else
-    return true;
-}
-
-void Demuxer::parsePacketDetails(PESPacket& packet)
-{
-    if (packet.getPacketType() >= PESTYPE_AUD0 &&
-        packet.getPacketType() <= PESTYPE_AUDMAX)
-    {
-        // Extract audio PTS if it exists
-        if (packet.hasPTS())
-        {
-            audio_pts = packet.getPTS();
-            // We continue to seek on the audio if the video PTS that we
-            // are trying to match is ahead of the audio PTS by at most
-            // SEEK_THRESHOLD. We consider the possibility of PTS wrap.
-            if (aud_seeking && !vid_seeking &&
-                !( (video_pts_seek > audio_pts &&
-                video_pts_seek - audio_pts < SEEK_THRESHOLD)
-                ||
-                (video_pts_seek < audio_pts &&
-                video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))
-            {
-                aud_seeking = 0;
-                Log::getInstance()->log("Demuxer", Log::DEBUG,
-                    "Leaving  audio sync: Audio PTS = %llu", audio_pts);
-            }
-        }
-    }
-    else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream
-    {
-        //Inspired by vdr's device.c
-        int payload_begin = packet[8]+9;
-        unsigned char substream_id = packet[payload_begin];
-        unsigned char substream_type = substream_id & 0xF0;
-        unsigned char substream_index = substream_id & 0x1F;
-pre_1_3_19_Recording: //This is for old recordings stuff and live TV
-        if (ispre_1_3_19)
-        {
-            substream_id = PESTYPE_PRIVATE_1;
-            substream_type = 0x80;
-            substream_index = 0;
-        }
-        switch (substream_type)
-        {
-        case 0x20://SPU
-        case 0x30://SPU
-            packet.setSubstream(substream_id);
-            break;
-        case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there?
-            break;
-        case 0x80: //ac3, currently only one ac3 track per recording supported
-            packet.setSubstream(substream_type+substream_index);
-
-            // Extract audio PTS if it exists
-            if (packet.hasPTS())
-            {
-                audio_pts = packet.getPTS();
-                // We continue to seek on the audio if the video PTS that we
-                // are trying to match is ahead of the audio PTS by at most
-                // SEEK_THRESHOLD. We consider the possibility of PTS wrap.
-                if (aud_seeking && !vid_seeking &&
-                    !( (video_pts_seek > audio_pts &&
-                    video_pts_seek - audio_pts < SEEK_THRESHOLD)
-                    ||
-                    (video_pts_seek < audio_pts &&
-                    video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))
-                {
-                    aud_seeking = 0;
-                    Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving  audio sync: Audio PTS = %llu", audio_pts);
-                }
-            }
-            break;
-        case 0x10: //Teletext Is this correct?
-            packet.setSubstream(substream_id);
-            // Extract teletxt PTS if it exists
-            if (packet.hasPTS())
-            {
-                teletext_pts = packet.getPTS();
-            }
-            break;
-        default:
-            if (!ispre_1_3_19)
-            {
-                ispre_1_3_19=true; //switching to compat mode and live tv mode
-                goto pre_1_3_19_Recording;
-            }
-            else
-            {
-                packet.setSubstream(0);
-            }
-            break;
-        }
-    }
-    else if (packet.getPacketType() >= PESTYPE_VID0 &&
-        packet.getPacketType() <= PESTYPE_VIDMAX)
-    {
-        // Extract video PTS if it exists
-        if (packet.hasPTS()) video_pts = packet.getPTS();
-
-        // If there is a sequence header, extract information
-        UINT pos = packet.findSeqHeader(h264);
-        if (pos > 1)
-        {
-            if (!h264) {
-                pos += 4;
-                if (pos+6 >= packet.getSize()) return;
-                horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4);
-                
-                vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2];
-
-                setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4));
-                frame_rate = packet[pos+3] & 0x0f;
-                if (frame_rate >= 1 && frame_rate <= 8)
-                    frame_rate = FrameRates[frame_rate];
-                else
-                    frame_rate = 0;
-                bit_rate = ((int)packet[pos+4] << 10) |
-                    ((int)packet[pos+5] << 2) |
-                    ((int)packet[pos+6] >> 6);
-            } 
-            else
-            {
-                /* Chris and Mark I know this is ugly, should we move this to a method  of PESPacket or to NALUUnit what would be better?
-                This looks so ugly since the header includes variable length parts and I have to parse through the whole header to get the wanted information*/
-                NALUUnit nalu(packet.getData()+pos,packet.getSize()-pos);
-                profile=nalu.getBits(8);
-                nalu.getBits(8); //constraints
-                nalu.getBits(8); //level_idc
-                nalu.getUe(); //seq_parameter_set_id
-                int chroma=1;
-                if (profile==100 || profile==110 || profile==122 || profile==144)
-                {
-                    chroma=nalu.getUe();
-                    if (chroma==3)
-                    {
-                        nalu.getBits(1);
-                    }
-                    nalu.getUe(); //bit depth lume
-                    nalu.getUe(); //bit depth chrome
-                    nalu.getBits(1);
-                    if (nalu.getBits(1))
-                    {
-                        for (int i=0;i<8;i++){
-                            if (nalu.getBits(1))
-                            {
-                                if (i<6)
-                                {
-                                    UINT lastscale=8;
-                                    UINT nextscale=8;
-                                    for (int j=0;j<16;j++) {
-                                        if (nextscale!=0) {
-                                            UINT delta=nalu.getSe();
-                                            nextscale=(lastscale+delta+256)%256;
-                                        }
-                                        lastscale=(nextscale==0)?lastscale:nextscale;
-                                    }
-                                }
-                                else
-                                {
-                                    UINT lastscale=8;
-                                    UINT nextscale=8;
-                                    for (int j=0;j<64;j++) {
-                                        if (nextscale!=0) {
-                                            UINT delta=nalu.getSe();
-                                            nextscale=(lastscale+delta+256)%256;
-                                        }
-                                        lastscale=(nextscale==0)?lastscale:nextscale;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-                int chromunitx=1;
-                int chromunity=1;
-                switch (chroma) {
-                case 0:
-                    chromunitx=chromunity=1; break;
-                case 1:
-                    chromunitx=chromunity=2; break;
-                case 2:
-                    chromunitx=2;chromunity=1; break;
-                case 3:
-                    chromunitx=chromunity=1; break;
-                };
-
-                nalu.getUe(); //log2framenum
-                UINT temp=nalu.getUe();
-                if (temp==0) //pict order
-                    nalu.getUe();
-                else if (temp==1) {
-                    nalu.getBits(1);
-                    nalu.getSe();
-                    nalu.getSe();
-                    UINT temp2=nalu.getUe();
-                    for (int i=0;i<temp2;i++)
-                        nalu.getSe();
-                }
-                nalu.getUe(); //Num refframes
-                nalu.getBits(1);
-                horizontal_size=(nalu.getUe()+1)*16;
-                
-                vertical_size=(nalu.getUe()+1)*16;
-                int interlaced=nalu.getBits(1);
-                vertical_size*=(2-interlaced);
-                
-                if (!interlaced) nalu.getBits(1);
-                nalu.getBits(1);
-                if (nalu.getBits(1))
-                {
-                    horizontal_size-=nalu.getUe()*chromunitx;
-                    horizontal_size-=nalu.getUe()*chromunitx;
-                    vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;
-                    vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;
-                }
-                if (nalu.getBits(1))
-                {
-                    if (nalu.getBits(1))
-                    {
-                        UINT aspectratioidc=nalu.getBits(8);
-                        bool hasaspect=false;
-                        const float aspects[]={1., 1./1.,12./11.,10./11.,16./11.,40./33.,
-                            24./11.,20./11.,32./11.,80./33.,18./11.,15./11.,64./33.,160./99.,4./3.,3./2.,2./1.};
-                      
-                        float aspectratio=((float) horizontal_size)/((float) vertical_size);
-                        if (aspectratioidc<=16) 
-                        {
-                            hasaspect=true;
-                            aspectratio*=aspects[aspectratioidc];
-                           
-                        }
-                        else if (aspectratioidc==255)
-                        {
-                            int t_sar_width=nalu.getBits(16);
-                            int t_sar_height=nalu.getBits(16);
-                            if (t_sar_width!=0 && t_sar_height!=0)
-                            {
-                                hasaspect=true;
-                                aspectratio*=((float)t_sar_width)/((float)t_sar_height);
-                            }
-                        }
-                        if (hasaspect)
-                        {
-                            if (fabs(aspectratio-16./9.)<0.1) setAspectRatio(ASPECT_16_9);
-                            else if (fabs(aspectratio-4./3.)<0.1) setAspectRatio(ASPECT_4_3);
-                        }
-                    }
-
-                }
-
-            }
-           
-            if (vid_seeking)
-            {
-                vid_seeking = 0;
-                video_pts_seek = video_pts;
-                Log::getInstance()->log("Demuxer", Log::DEBUG,
-                    "Entering audio sync: Video PTS = %llu", video_pts);
-                Log::getInstance()->log("Demuxer", Log::DEBUG,
-                    "Entering audio sync: Audio PTS = %llu", audio_pts);
-            }
-            return;
-        } 
-    }
-}
-
-UINT Demuxer::stripAudio(UCHAR* buf, UINT len)
-{
-  UINT read_pos = 0, write_pos = 0;
-  UINT pattern, packet_length;
-  if (len < 4) return 0;
-  pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
-  while (read_pos + 7 <= len)
-  {
-    pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];
-    if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))
-      read_pos++;
-    else
-    {
-      packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;
-      if (read_pos + packet_length > len)
-        read_pos = len;
-      else
-      {
-        if (read_pos != write_pos)
-          memmove(buf+write_pos, buf+read_pos, packet_length);
-        read_pos += packet_length;
-        write_pos += packet_length;
-        pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)
-                                        | (buf[read_pos+2]);
-      }
-    }
-  }
-  return write_pos;
-}
-
-bool Demuxer::scanForVideo(UCHAR* buf, UINT len, bool &ish264)
-{
-  UINT pos = 3;
-  UINT pattern;
-  ish264=false;
-  if (len < 4) return false;
-  pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
-  while (pos < len)
-  {
-    pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++];
-    if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX))
-      return true;
-  }
-  return false;
-}
-
-bool* Demuxer::getmpAudioChannels()
-{
-  return avail_mpaudchan;
-}
-
-bool* Demuxer::getac3AudioChannels()
-{
-  return avail_ac3audchan;
-}
-
-bool* Demuxer::getSubtitleChannels()
-{
-  return avail_dvbsubtitlechan;
-}
-
-int Demuxer::getselSubtitleChannel()
-{
-  return subtitle_current;
-}
-
-int Demuxer::getselAudioChannel()
-{
-  return audio_current;
-}
-
-
+/*\r
+    Copyright 2005-2008 Mark Calderbank\r
+    Copyright 2007 Marten Richter (AC3 support)\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software Foundation, Inc.,\r
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "demuxer.h"\r
+\r
+#include "callback.h"\r
+#include "dvbsubtitles.h"\r
+#include "log.h"\r
+\r
+#include <cstdlib>\r
+\r
+#include <math.h>\r
+\r
+#define DEMUXER_SEQ_HEAD 0x000001B3\r
+#define DEMUXER_PIC_HEAD 0x00000101\r
+\r
+#define DEMUXER_H264_ACCESS_UNIT 0x00000109\r
+#define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107\r
+\r
+\r
+#define SEEK_THRESHOLD 150000 // About 1.5 seconds\r
+\r
+// Statics\r
+const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };\r
+Demuxer* Demuxer::instance = NULL;\r
+\r
+class NALUUnit {\r
+public:\r
+    NALUUnit(const UCHAR* buf,UINT length_buf);\r
+    ~NALUUnit();\r
+\r
+inline    UINT getBits(UINT num_bits);\r
+    UINT getUe();\r
+    int getSe();\r
+    bool isEonalu() {return eonalu;};\r
+\r
+protected:\r
+    UCHAR* nalu_buf;\r
+    UINT nalu_length;\r
+    UINT pos;\r
+    UCHAR bit_pos;\r
+    UCHAR working_byte;\r
+    UINT last_bytes;\r
+    bool eonalu;\r
+};\r
+\r
+NALUUnit::NALUUnit(const UCHAR *buf, UINT length_buf)\r
+{\r
+    nalu_length=0;\r
+    nalu_buf=NULL;\r
+    pos=0;\r
+    bit_pos=0;\r
+    working_byte=0;\r
+    last_bytes=0;\r
+    eonalu=false;\r
+\r
+    UINT nalu_start=0;\r
+    UINT nalu_end=0;\r
+    UINT pattern =(((UINT)buf[ 0] << 16) |\r
+                   ((UINT)buf[1] <<  8) |\r
+                    (UINT)buf[2]  );\r
+    nalu_start=3;\r
+    while (pattern != 0x000001)\r
+    {\r
+        if (++nalu_start >= length_buf) return;\r
+        pattern = ((pattern << 8) | buf[nalu_start])&0x00FFFFFF;\r
+    }\r
+    nalu_end=nalu_start+1;\r
+    pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;\r
+\r
+    while (pattern != 0x000001 && pattern != 0x000000)\r
+    {\r
+        if (++nalu_end >= length_buf) { nalu_end+=3;break;};\r
+        pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;\r
+    }\r
+    nalu_end-=3;\r
+    nalu_end=min(length_buf-1,nalu_end);\r
+    nalu_length=nalu_end-nalu_start;\r
+    nalu_buf=(UCHAR*)malloc(nalu_length);\r
+    memcpy(nalu_buf,buf+nalu_start,nalu_length);\r
+    pos=1;\r
+}\r
+\r
+NALUUnit::~NALUUnit()\r
+{\r
+    if (nalu_buf) free(nalu_buf);\r
+}\r
+\r
+inline UINT NALUUnit::getBits(UINT num_bits)\r
+{\r
+    if (num_bits==0) return 0; //???\r
+    UINT remain_bits=num_bits;\r
+    UINT work=0;\r
+    //May be slow, but should work!\r
+    while (remain_bits>0) {\r
+        if (bit_pos==0) {\r
+            if (pos<nalu_length)\r
+            {\r
+                last_bytes=(last_bytes<<8) & nalu_buf[pos];\r
+                if ((last_bytes & 0x00FFFFFF) == 0x000003) pos++; //emulation prevention byte\r
+                 if (pos<nalu_length)\r
+                 {\r
+                     working_byte=nalu_buf[pos];\r
+                     pos++;\r
+                 } \r
+                 else\r
+                 {\r
+                     working_byte=0;\r
+                     eonalu=true;\r
+                 }\r
+            } \r
+            else\r
+            {\r
+                working_byte=0;\r
+                eonalu=true;\r
+            }\r
+\r
+        }\r
+        UINT fetch_bits=min(remain_bits,8-bit_pos);\r
+        work=work <<fetch_bits;\r
+        //work|=((working_byte>>bit_pos) & (0xFF>>(8-fetch_bits)));\r
+        work|=(working_byte &(0xFF>>(bit_pos)))>>(8-fetch_bits-bit_pos);\r
+        remain_bits-=fetch_bits;\r
+        bit_pos=(bit_pos+fetch_bits)%8;\r
+    }\r
+    return work;\r
+}\r
+\r
+UINT NALUUnit::getUe()\r
+{\r
+    int leadbits=-1;\r
+    bool bit;\r
+    for( bit = 0; !bit && !eonalu; leadbits++ )\r
+        bit = getBits(1);\r
+    if (eonalu) return true;\r
+    return ((1 << leadbits)-1)+getBits(leadbits);\r
+}\r
+\r
+int NALUUnit::getSe()\r
+{\r
+    UINT input=getUe();\r
+    if (input==0) return 0;\r
+    int output=((input+1)>>1);\r
+    if (input & 0x1) output*=-1;\r
+    return output;\r
+}\r
+\r
+\r
+\r
+static const int PESPacket_initial_size = 2000;\r
+\r
+// PESPacket methods\r
+PESPacket::PESPacket()\r
+{\r
+  data_size = PESPacket_initial_size;\r
+  data = (UCHAR*)malloc(data_size);\r
+  data[0] = 0x00;\r
+  data[1] = 0x00;\r
+  data[2] = 0x01;\r
+  init(0);\r
+}\r
+\r
+PESPacket::PESPacket(const PESPacket& packet)\r
+{\r
+  copyFrom(packet);\r
+}\r
+\r
+PESPacket& PESPacket::operator=(const PESPacket& packet)\r
+{\r
+  if (this != &packet)\r
+  {\r
+    if (data) free(data);\r
+    copyFrom(packet);\r
+  }\r
+  return *this;\r
+}\r
+\r
+PESPacket::~PESPacket()\r
+{\r
+  if (data) free(data);\r
+}\r
+\r
+void PESPacket::copyFrom(const PESPacket& packet)\r
+{\r
+  length = packet.length;\r
+  size = packet.size;\r
+  packetType = packet.packetType;\r
+  substream = packet.substream;\r
+  seq_header = packet.seq_header;\r
+  data_size = size;\r
+  data = (UCHAR*)malloc(data_size);\r
+  memcpy(data, packet.data, data_size);\r
+}\r
+\r
+void PESPacket::init(UCHAR type, UCHAR sub)\r
+{\r
+  length = 0; \r
+  size = 6;\r
+  data[4] = data[5] = 0;\r
+  data[3] = type;\r
+  packetType = type;\r
+  substream = sub;\r
+  seq_header = 1; // Unknown seq_header status\r
+\r
+}\r
+\r
+void PESPacket::truncate()\r
+{\r
+  init(packetType,substream);\r
+}\r
+\r
+\r
+\r
+int PESPacket::write(const UCHAR *buf, int len)\r
+{\r
+\r
+\r
+  if (size + len > 0x10000) return 0;\r
+  if (size + len > data_size)\r
+  { // Reallocate\r
+    UINT new_data_size = max(data_size + data_size / 2, data_size + len);\r
+    if (new_data_size > 0x10000) new_data_size = 0x10000;\r
+    data_size = new_data_size;\r
+    data = (UCHAR*)realloc(data, data_size);\r
+  }\r
+  memcpy(data + size, buf, len);\r
+  length += len;\r
+  size += len;\r
+  data[4] = (length >> 8);\r
+  data[5] = (length & 0xFF);\r
+  // We have added data - reset seq_header indicator if necessary\r
+  if (seq_header == 0) seq_header = 1; // Reset to 'unknown'\r
+  return 1;\r
+}\r
+\r
+ULLONG PESPacket::getPTS() const\r
+{\r
+  if ( ( (packetType >= Demuxer::PESTYPE_AUD0 &&\r
+          packetType <= Demuxer::PESTYPE_AUDMAX)\r
+        ||\r
+         (packetType >= Demuxer::PESTYPE_VID0 &&\r
+          packetType <= Demuxer::PESTYPE_VIDMAX)\r
+   ||\r
+          packetType == Demuxer::PESTYPE_PRIVATE_1\r
+       )\r
+       && size >= 14 && data[7] & 0x80)\r
+  {\r
+    return ( (ULLONG)(data[ 9] & 0x0E) << 29) |\r
+           ( (ULLONG)(data[10])        << 22 ) |\r
+           ( (ULLONG)(data[11] & 0xFE) << 14 ) |\r
+           ( (ULLONG)(data[12])        <<  7 ) |\r
+           ( (ULLONG)(data[13] & 0xFE) >>  1 );\r
+  }\r
+  else return PTS_INVALID;\r
+}\r
+\r
+UCHAR PESPacket::operator[] (UINT index) const\r
+{\r
+  if (index >= size)\r
+    return 0;\r
+  else\r
+    return data[index];\r
+}\r
+\r
+UINT PESPacket::findPictureHeader(bool h264) const\r
+{\r
+  if (size < 12) return 0;\r
+  UINT pattern = ( ((UINT)data[ 8] << 24) |\r
+                   ((UINT)data[ 9] << 16) |\r
+                   ((UINT)data[10] <<  8) |\r
+                    (UINT)data[11]  );\r
+  UINT pos = 11;\r
+  if (h264) {\r
+         \r
+         while (pattern != DEMUXER_H264_ACCESS_UNIT)\r
+         {\r
+                 if (++pos >= size) return 0;\r
+                 pattern = (pattern << 8) | data[pos];\r
+         }\r
+         return pos-3;\r
+  } else {\r
+         while (pattern != DEMUXER_PIC_HEAD)\r
+         {\r
+                 if (++pos >= size) return 0;\r
+                 pattern = (pattern << 8) | data[pos];\r
+         }\r
+         return pos-3;\r
+  }\r
+}\r
+\r
+UINT PESPacket::countPictureHeaders(bool h264) const\r
+{\r
+  if (size < 12) return 0;\r
+  UINT pattern = ( ((UINT)data[ 8] << 24) |\r
+                   ((UINT)data[ 9] << 16) |\r
+                   ((UINT)data[10] <<  8) |\r
+                    (UINT)data[11]  );\r
+  UINT pos = 11;\r
+  UINT count=0;\r
+  if (h264) {\r
+         \r
+         while (pos<size)\r
+         {\r
+          pos++;\r
+                 pattern = (pattern << 8) | data[pos];\r
+          if (pattern==DEMUXER_H264_ACCESS_UNIT) count++;\r
+         }\r
+         return count;\r
+  } else {\r
+      while (pos<size)\r
+         {\r
+          pos++;\r
+                 pattern = (pattern << 8) | data[pos];\r
+          if (pattern==DEMUXER_PIC_HEAD) count++;\r
+         }\r
+         return count;\r
+  }\r
+}\r
+\r
+UINT PESPacket::findSeqHeader(bool h264) const\r
+{\r
+  if (seq_header != 1) return seq_header;\r
+  if (size < 12) return 0;\r
+  UINT pattern = ( ((UINT)data[ 8] << 24) |\r
+                   ((UINT)data[ 9] << 16) |\r
+                   ((UINT)data[10] <<  8) |\r
+                    (UINT)data[11]  );\r
+  UINT pos = 11;\r
+  if (h264) {\r
+      while ((pattern & 0xFFFFFF1F) != DEMUXER_H264_SEQ_PARAMETER_SET)\r
+         {\r
+                 if (++pos >= size)\r
+                 {\r
+                         seq_header = 0;\r
+                         return 0;\r
+                 }\r
+                 pattern = (pattern << 8) | data[pos];\r
+         }\r
+         seq_header = pos - 3;\r
+  } \r
+  else \r
+  {\r
+         while (pattern != DEMUXER_SEQ_HEAD)\r
+         {\r
+                 if (++pos >= size)\r
+                 {\r
+                         seq_header = 0;\r
+                         return 0;\r
+                 }\r
+                 pattern = (pattern << 8) | data[pos];\r
+         }\r
+         seq_header = pos - 3;\r
+  }\r
+  return seq_header;\r
+}\r
+\r
+// Demuxer methods\r
+Demuxer::Demuxer()\r
+{\r
+  if (instance) return;\r
+  instance = this;\r
+  initted = false;\r
+  callback = NULL;\r
+  arcnt = 0;\r
+  vid_seeking = aud_seeking = false;\r
+  video_pts = audio_pts = 0;\r
+  ispre_1_3_19 = false;\r
+  packetnum=0;\r
+  h264 = false;\r
+  fps = 25.0;\r
+}\r
+\r
+Demuxer::~Demuxer()\r
+{\r
+  shutdown();\r
+  instance = NULL;\r
+}\r
+\r
+Demuxer* Demuxer::getInstance()\r
+{\r
+  return instance;\r
+}\r
+\r
+int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, DrainTarget* teletext,\r
+                  ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT,double infps, DVBSubtitles* tsubtitles)\r
+{\r
+  if (!initted)\r
+  {\r
+    if ( !videostream.init(video, demuxMemoryV) ||\r
+         !audiostream.init(audio, demuxMemoryA) ||\r
+         !teletextstream.init(teletext, demuxMemoryT))\r
+    {\r
+      Log::getInstance()->log("Demuxer", Log::CRIT,\r
+                              "Failed to initialize demuxer");\r
+      shutdown();\r
+      return 0;\r
+    }\r
+  }\r
+  if (teletext) {\r
+      isteletextdecoded = true;\r
+  } else {\r
+      isteletextdecoded = false;\r
+  }\r
+  fps=infps;\r
+  reset();\r
+  initted = true;\r
+  subtitles = tsubtitles;\r
+  callback = tcallback;\r
+  return 1;\r
+}\r
+\r
+void Demuxer::reset()\r
+{\r
+  Log::getInstance()->log("Demuxer", Log::DEBUG, "Reset called");\r
+  flush();\r
+  video_current = audio_current = teletext_current = subtitle_current = -1;\r
+  horizontal_size = vertical_size = 0;\r
+  aspect_ratio = (enum AspectRatio) 0;\r
+  frame_rate = bit_rate = 0;\r
+  ispre_1_3_19 = false;\r
+  h264 = false;\r
+  packetnum=0;\r
+\r
+  for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++)\r
+  {\r
+    avail_mpaudchan[i] = false;\r
+  }\r
+  for (int i = 0; i <= (PESTYPE_SUBSTREAM_AC3MAX - PESTYPE_SUBSTREAM_AC30); i++)\r
+  {\r
+    avail_ac3audchan[i] = false;\r
+  }\r
+  for (int i = 0; i <= (PESTYPE_SUBSTREAM_DVBSUBTITLEMAX - PESTYPE_SUBSTREAM_DVBSUBTITLE0); i++)\r
+  {\r
+    avail_dvbsubtitlechan[i] = false;\r
+  }\r
+}\r
+\r
+int Demuxer::shutdown()\r
+{\r
+  videostream.shutdown();\r
+  audiostream.shutdown();\r
+  teletextstream.shutdown();\r
+  initted = false;\r
+  return 1;\r
+}\r
+\r
+void Demuxer::flush()\r
+{\r
+  Log::getInstance()->log("Demuxer", Log::DEBUG, "Flush called");\r
+\r
+  videostream.flush();\r
+  audiostream.flush();\r
+  teletextstream.flush();\r
+}\r
+\r
+void Demuxer::flushAudio()\r
+{\r
+  audiostream.flush();\r
+}\r
+\r
+void Demuxer::seek()\r
+{\r
+  vid_seeking = aud_seeking = true;\r
+  video_pts = audio_pts = teletext_pts = 0;\r
+}\r
+\r
+void Demuxer::setAudioStream(int id)\r
+{\r
+  audio_current = id;\r
+}\r
+\r
+void Demuxer::setVideoStream(int id)\r
+{\r
+  video_current = id;\r
+}\r
+\r
+void Demuxer::setTeletextStream(int id)\r
+{\r
+  teletext_current = id;\r
+}\r
+\r
+void Demuxer::setDVBSubtitleStream(int id)\r
+{\r
+  subtitle_current = id;\r
+}\r
+\r
+void Demuxer::setAspectRatio(enum AspectRatio ar)\r
+{\r
+  if (aspect_ratio != ar)\r
+  {\r
+    Log::getInstance()->log("Demux", Log::DEBUG,\r
+                            "Aspect ratio difference signalled");\r
+    if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal\r
+    {\r
+      arcnt = 0;\r
+      aspect_ratio = ar;\r
+      if (callback) callback->call(this);\r
+    }\r
+  }\r
+  else\r
+    arcnt = 0;\r
+}\r
+\r
+bool Demuxer::writeAudio()\r
+{\r
+  return audiostream.drain();\r
+}\r
+\r
+bool Demuxer::writeVideo()\r
+{\r
+  return videostream.drain();\r
+}\r
+\r
+bool Demuxer::writeTeletext()\r
+{\r
+   return teletextstream.drain();\r
+}\r
+\r
+bool Demuxer::submitPacket(PESPacket& packet)\r
+{\r
+  UINT sent = 0;\r
+  UCHAR packet_type = packet.getPacketType();\r
+  const UCHAR* packetdata = packet.getData();\r
+  if (packet_type >= PESTYPE_VID0 && packet_type <= PESTYPE_VIDMAX)\r
+  {\r
+    if (video_current == -1) video_current = packet_type;\r
+    if (video_current == packet_type && !vid_seeking)\r
+       {\r
+        sent = videostream.put(&packetdata[0], packet.getSize(), h264?MPTYPE_VIDEO_H264:MPTYPE_VIDEO_MPEG2,packetnum);\r
+        if (sent) packetnum++;\r
+       }\r
+       else\r
+      sent = packet.getSize();\r
+  }\r
+  else if (packet_type >= PESTYPE_AUD0 && packet_type <= PESTYPE_AUDMAX)\r
+  {\r
+\r
+    if (audio_current == -1) audio_current = packet_type;\r
+    avail_mpaudchan[packet_type - PESTYPE_AUD0] = true;\r
+    if (audio_current == packet_type && !aud_seeking)\r
+       {\r
+      sent = audiostream.put(&packetdata[0], packet.getSize(), MPTYPE_MPEG_AUDIO,packetnum);\r
+         if (sent)  packetnum++;\r
+       }\r
+       else\r
+      sent = packet.getSize();\r
+  }\r
+  else if (packet_type == PESTYPE_PRIVATE_1 &&\r
+           packet.getSubstream() >= PESTYPE_SUBSTREAM_AC30 &&\r
+           packet.getSubstream() <= PESTYPE_SUBSTREAM_AC3MAX)\r
+  {\r
+    avail_ac3audchan[packet.getSubstream() - PESTYPE_SUBSTREAM_AC30] = true;\r
+    if (packet.getSubstream() == audio_current)\r
+    {\r
+      sent = audiostream.put(&packetdata[0], packet.getSize(), (ispre_1_3_19)? MPTYPE_AC3_PRE13 : MPTYPE_AC3,packetnum);\r
+         if (sent) packetnum++;\r
+    }\r
+    else\r
+    {\r
+      sent = packet.getSize();\r
+    }\r
+  }\r
+  else if (packet_type == PESTYPE_PRIVATE_1 &&\r
+           packet.getSubstream() >= PESTYPE_SUBSTREAM_DVBSUBTITLE0 &&\r
+           packet.getSubstream() <= PESTYPE_SUBSTREAM_DVBSUBTITLEMAX)\r
+  {\r
+    avail_dvbsubtitlechan[packet.getSubstream()-PESTYPE_SUBSTREAM_DVBSUBTITLE0]=true;\r
+    if (subtitle_current == -1) subtitle_current = packet.getSubstream();\r
+    if (subtitles && packet.getSubstream()==subtitle_current)\r
+    {\r
+         subtitles->put(packet);\r
+    }\r
+    sent = packet.getSize();\r
+  }\r
+  else if (isteletextdecoded  && packet_type == PESTYPE_PRIVATE_1 &&\r
+           packet.getSubstream() >= PESTYPE_SUBSTREAM_TELETEXT0 &&\r
+           packet.getSubstream() <= PESTYPE_SUBSTREAM_TELETEXTMAX)\r
+  {\r
+\r
+    if (teletext_current == -1) teletext_current = packet.getSubstream();\r
+    if (teletext_current == packet.getSubstream())\r
+    {\r
+        sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT,packetnum);\r
+    }\r
+    else \r
+    {\r
+        sent = packet.getSize();\r
+    }\r
+  }\r
+  else\r
+  {\r
+    sent = packet.getSize();\r
+  }\r
+\r
+  if (sent < packet.getSize()) // Stream is full.\r
+    return false;\r
+  else\r
+    return true;\r
+}\r
+\r
+void Demuxer::parsePacketDetails(PESPacket& packet)\r
+{\r
+    if (packet.getPacketType() >= PESTYPE_AUD0 &&\r
+        packet.getPacketType() <= PESTYPE_AUDMAX)\r
+    {\r
+        // Extract audio PTS if it exists\r
+        if (packet.hasPTS())\r
+        {\r
+            audio_pts = packet.getPTS();\r
+            // We continue to seek on the audio if the video PTS that we\r
+            // are trying to match is ahead of the audio PTS by at most\r
+            // SEEK_THRESHOLD. We consider the possibility of PTS wrap.\r
+            if (aud_seeking && !vid_seeking &&\r
+                !( (video_pts_seek > audio_pts &&\r
+                video_pts_seek - audio_pts < SEEK_THRESHOLD)\r
+                ||\r
+                (video_pts_seek < audio_pts &&\r
+                video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))\r
+            {\r
+                aud_seeking = 0;\r
+                Log::getInstance()->log("Demuxer", Log::DEBUG,\r
+                    "Leaving  audio sync: Audio PTS = %llu", audio_pts);\r
+            }\r
+        }\r
+    }\r
+    else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream\r
+    {\r
+        //Inspired by vdr's device.c\r
+        int payload_begin = packet[8]+9;\r
+        unsigned char substream_id = packet[payload_begin];\r
+        unsigned char substream_type = substream_id & 0xF0;\r
+        unsigned char substream_index = substream_id & 0x1F;\r
+pre_1_3_19_Recording: //This is for old recordings stuff and live TV\r
+        if (ispre_1_3_19)\r
+        {\r
+            substream_id = PESTYPE_PRIVATE_1;\r
+            substream_type = 0x80;\r
+            substream_index = 0;\r
+        }\r
+        switch (substream_type)\r
+        {\r
+        case 0x20://SPU\r
+        case 0x30://SPU\r
+            packet.setSubstream(substream_id);\r
+            break;\r
+        case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there?\r
+            break;\r
+        case 0x80: //ac3, currently only one ac3 track per recording supported\r
+            packet.setSubstream(substream_type+substream_index);\r
+\r
+            // Extract audio PTS if it exists\r
+            if (packet.hasPTS())\r
+            {\r
+                audio_pts = packet.getPTS();\r
+                // We continue to seek on the audio if the video PTS that we\r
+                // are trying to match is ahead of the audio PTS by at most\r
+                // SEEK_THRESHOLD. We consider the possibility of PTS wrap.\r
+                if (aud_seeking && !vid_seeking &&\r
+                    !( (video_pts_seek > audio_pts &&\r
+                    video_pts_seek - audio_pts < SEEK_THRESHOLD)\r
+                    ||\r
+                    (video_pts_seek < audio_pts &&\r
+                    video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))\r
+                {\r
+                    aud_seeking = 0;\r
+                    Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving  audio sync: Audio PTS = %llu", audio_pts);\r
+                }\r
+            }\r
+            break;\r
+        case 0x10: //Teletext Is this correct?\r
+            packet.setSubstream(substream_id);\r
+            // Extract teletxt PTS if it exists\r
+            if (packet.hasPTS())\r
+            {\r
+                teletext_pts = packet.getPTS();\r
+            }\r
+            break;\r
+        default:\r
+            if (!ispre_1_3_19)\r
+            {\r
+                ispre_1_3_19=true; //switching to compat mode and live tv mode\r
+                goto pre_1_3_19_Recording;\r
+            }\r
+            else\r
+            {\r
+                packet.setSubstream(0);\r
+            }\r
+            break;\r
+        }\r
+    }\r
+    else if (packet.getPacketType() >= PESTYPE_VID0 &&\r
+        packet.getPacketType() <= PESTYPE_VIDMAX)\r
+    {\r
+        // Extract video PTS if it exists\r
+        if (packet.hasPTS()) video_pts = packet.getPTS();\r
+\r
+        // If there is a sequence header, extract information\r
+        UINT pos = packet.findSeqHeader(h264);\r
+        if (pos > 1)\r
+        {\r
+            if (!h264) {\r
+                pos += 4;\r
+                if (pos+6 >= packet.getSize()) return;\r
+                horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4);\r
+                \r
+                vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2];\r
+\r
+                setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4));\r
+                frame_rate = packet[pos+3] & 0x0f;\r
+                if (frame_rate >= 1 && frame_rate <= 8)\r
+                    frame_rate = FrameRates[frame_rate];\r
+                else\r
+                    frame_rate = 0;\r
+                bit_rate = ((int)packet[pos+4] << 10) |\r
+                    ((int)packet[pos+5] << 2) |\r
+                    ((int)packet[pos+6] >> 6);\r
+            } \r
+            else\r
+            {\r
+                /* Chris and Mark I know this is ugly, should we move this to a method  of PESPacket or to NALUUnit what would be better?\r
+                This looks so ugly since the header includes variable length parts and I have to parse through the whole header to get the wanted information*/\r
+                NALUUnit nalu(packet.getData()+pos,packet.getSize()-pos);\r
+                profile=nalu.getBits(8);\r
+                nalu.getBits(8); //constraints\r
+                nalu.getBits(8); //level_idc\r
+                nalu.getUe(); //seq_parameter_set_id\r
+                int chroma=1;\r
+                if (profile==100 || profile==110 || profile==122 || profile==144)\r
+                {\r
+                    chroma=nalu.getUe();\r
+                    if (chroma==3)\r
+                    {\r
+                        nalu.getBits(1);\r
+                    }\r
+                    nalu.getUe(); //bit depth lume\r
+                    nalu.getUe(); //bit depth chrome\r
+                    nalu.getBits(1);\r
+                    if (nalu.getBits(1))\r
+                    {\r
+                        for (int i=0;i<8;i++){\r
+                            if (nalu.getBits(1))\r
+                            {\r
+                                if (i<6)\r
+                                {\r
+                                    UINT lastscale=8;\r
+                                    UINT nextscale=8;\r
+                                    for (int j=0;j<16;j++) {\r
+                                        if (nextscale!=0) {\r
+                                            UINT delta=nalu.getSe();\r
+                                            nextscale=(lastscale+delta+256)%256;\r
+                                        }\r
+                                        lastscale=(nextscale==0)?lastscale:nextscale;\r
+                                    }\r
+                                }\r
+                                else\r
+                                {\r
+                                    UINT lastscale=8;\r
+                                    UINT nextscale=8;\r
+                                    for (int j=0;j<64;j++) {\r
+                                        if (nextscale!=0) {\r
+                                            UINT delta=nalu.getSe();\r
+                                            nextscale=(lastscale+delta+256)%256;\r
+                                        }\r
+                                        lastscale=(nextscale==0)?lastscale:nextscale;\r
+                                    }\r
+                                }\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+                int chromunitx=1;\r
+                int chromunity=1;\r
+                switch (chroma) {\r
+                case 0:\r
+                    chromunitx=chromunity=1; break;\r
+                case 1:\r
+                    chromunitx=chromunity=2; break;\r
+                case 2:\r
+                    chromunitx=2;chromunity=1; break;\r
+                case 3:\r
+                    chromunitx=chromunity=1; break;\r
+                };\r
+\r
+                nalu.getUe(); //log2framenum\r
+                UINT temp=nalu.getUe();\r
+                if (temp==0) //pict order\r
+                    nalu.getUe();\r
+                else if (temp==1) {\r
+                    nalu.getBits(1);\r
+                    nalu.getSe();\r
+                    nalu.getSe();\r
+                    UINT temp2=nalu.getUe();\r
+                    for (int i=0;i<temp2;i++)\r
+                        nalu.getSe();\r
+                }\r
+                nalu.getUe(); //Num refframes\r
+                nalu.getBits(1);\r
+                horizontal_size=(nalu.getUe()+1)*16;\r
+                \r
+                vertical_size=(nalu.getUe()+1)*16;\r
+                int interlaced=nalu.getBits(1);\r
+                vertical_size*=(2-interlaced);\r
+                \r
+                if (!interlaced) nalu.getBits(1);\r
+                nalu.getBits(1);\r
+                if (nalu.getBits(1))\r
+                {\r
+                    horizontal_size-=nalu.getUe()*chromunitx;\r
+                    horizontal_size-=nalu.getUe()*chromunitx;\r
+                    vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;\r
+                    vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;\r
+                }\r
+                if (nalu.getBits(1))\r
+                {\r
+                    if (nalu.getBits(1))\r
+                    {\r
+                        UINT aspectratioidc=nalu.getBits(8);\r
+                        bool hasaspect=false;\r
+                        const float aspects[]={1., 1./1.,12./11.,10./11.,16./11.,40./33.,\r
+                            24./11.,20./11.,32./11.,80./33.,18./11.,15./11.,64./33.,160./99.,4./3.,3./2.,2./1.};\r
+                      \r
+                        float aspectratio=((float) horizontal_size)/((float) vertical_size);\r
+                        if (aspectratioidc<=16) \r
+                        {\r
+                            hasaspect=true;\r
+                            aspectratio*=aspects[aspectratioidc];\r
+                           \r
+                        }\r
+                        else if (aspectratioidc==255)\r
+                        {\r
+                            int t_sar_width=nalu.getBits(16);\r
+                            int t_sar_height=nalu.getBits(16);\r
+                            if (t_sar_width!=0 && t_sar_height!=0)\r
+                            {\r
+                                hasaspect=true;\r
+                                aspectratio*=((float)t_sar_width)/((float)t_sar_height);\r
+                            }\r
+                        }\r
+                        if (hasaspect)\r
+                        {\r
+                            if (fabs(aspectratio-16./9.)<0.1) setAspectRatio(ASPECT_16_9);\r
+                            else if (fabs(aspectratio-4./3.)<0.1) setAspectRatio(ASPECT_4_3);\r
+                        }\r
+                    }\r
+\r
+                }\r
+\r
+            }\r
+           \r
+            if (vid_seeking)\r
+            {\r
+                vid_seeking = 0;\r
+                video_pts_seek = video_pts;\r
+                Log::getInstance()->log("Demuxer", Log::DEBUG,\r
+                    "Entering audio sync: Video PTS = %llu", video_pts);\r
+                Log::getInstance()->log("Demuxer", Log::DEBUG,\r
+                    "Entering audio sync: Audio PTS = %llu", audio_pts);\r
+            }\r
+            return;\r
+        } \r
+    }\r
+}\r
+\r
+UINT Demuxer::stripAudio(UCHAR* buf, UINT len)\r
+{\r
+  UINT read_pos = 0, write_pos = 0;\r
+  UINT pattern, packet_length;\r
+  if (len < 4) return 0;\r
+  pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
+  while (read_pos + 7 <= len)\r
+  {\r
+    pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];\r
+    if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))\r
+      read_pos++;\r
+    else\r
+    {\r
+      packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;\r
+      if (read_pos + packet_length > len)\r
+        read_pos = len;\r
+      else\r
+      {\r
+        if (read_pos != write_pos)\r
+          memmove(buf+write_pos, buf+read_pos, packet_length);\r
+        read_pos += packet_length;\r
+        write_pos += packet_length;\r
+        pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)\r
+                                        | (buf[read_pos+2]);\r
+      }\r
+    }\r
+  }\r
+  return write_pos;\r
+}\r
+\r
+void Demuxer::changeTimes(UCHAR* buf, UINT len,UINT playtime)\r
+{\r
+       UINT pattern, packet_length;\r
+       UINT read_pos = 0;\r
+       if (len < 4) return;\r
+       pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
+       while (read_pos + 7 <= len)\r
+       {\r
+          pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];\r
+          if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))\r
+             read_pos++;\r
+          else\r
+          {\r
+             packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;\r
+             // ok we have a packet figure out if pts and dts are present and replace them\r
+             if (read_pos + 19 > len) return;\r
+             ULLONG new_ts=playtime*90; //play time is on ms so multiply it by 90\r
+             if (buf[read_pos+7] & 0x80) { // pts is here, replace it\r
+                 buf[read_pos+9]=0x21 | (( new_ts>>29)& 0xde );\r
+                 buf[read_pos+10]=0x00 |(( new_ts>>22)& 0xff );\r
+                 buf[read_pos+11]=0x01 | (( new_ts>>14)& 0xfe );\r
+                 buf[read_pos+12]=0x00 | (( new_ts>>7)& 0xff );\r
+                 buf[read_pos+13]=0x01 | (( new_ts<<1)& 0xfe );\r
+             }\r
+\r
+             if (buf[read_pos+7] & 0x40) { // pts is here, replace it\r
+                  buf[read_pos+14]=0x21 | (( new_ts>>29)& 0xde );\r
+                  buf[read_pos+15]=0x00 | (( new_ts>>22)& 0xff );\r
+                  buf[read_pos+16]=0x01 | (( new_ts>>14)& 0xfe );\r
+                  buf[read_pos+17]=0x00 | (( new_ts>>7)& 0xff );\r
+                  buf[read_pos+18]=0x01 | (( new_ts<<1)& 0xfe );\r
+             }\r
+             read_pos += packet_length;\r
+             pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)\r
+                                               | (buf[read_pos+2]);\r
+             }\r
+         }\r
+\r
+}\r
+\r
+bool Demuxer::scanForVideo(UCHAR* buf, UINT len, bool &ish264)\r
+{\r
+  UINT pos = 3;\r
+  UINT pattern;\r
+  ish264=false;\r
+  if (len < 4) return false;\r
+  pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
+  while (pos < len)\r
+  {\r
+    pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++];\r
+    if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX))\r
+      return true;\r
+  }\r
+  return false;\r
+}\r
+\r
+bool* Demuxer::getmpAudioChannels()\r
+{\r
+  return avail_mpaudchan;\r
+}\r
+\r
+bool* Demuxer::getac3AudioChannels()\r
+{\r
+  return avail_ac3audchan;\r
+}\r
+\r
+bool* Demuxer::getSubtitleChannels()\r
+{\r
+  return avail_dvbsubtitlechan;\r
+}\r
+\r
+int Demuxer::getselSubtitleChannel()\r
+{\r
+  return subtitle_current;\r
+}\r
+\r
+int Demuxer::getselAudioChannel()\r
+{\r
+  return audio_current;\r
+}\r
+\r
+\r
index 85c347003b1914badca2bf24c827be1da5ae123b..a05f7bcecfe5a551512554a7c9a77215c9dea4db 100644 (file)
--- a/demuxer.h
+++ b/demuxer.h
-/*
-    Copyright 2005-2008 Mark Calderbank
-    Copyright 2007 Marten Richter (AC3 support)
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-/*
-
-Thanks go to Jon Gettler of the MVPMC project and Stephen Rice for
-the demuxer in mvpmc. It was used in the creation of this demuxer;
-however, no code was copied verbatim.
-
-*/
-
-#ifndef DEMUXER_H
-#define DEMUXER_H
-
-#include "stream.h"
-#include "defines.h"
-
-class DVBSubtitles;
-class Callback;
-class DrainTarget;
-
-class PESPacket
-{
-  public:
-    PESPacket();
-    PESPacket(const PESPacket& packet);
-    PESPacket& operator=(const PESPacket& packet);
-    ~PESPacket();
-    void init(UCHAR type, UCHAR sub=0);
-    void truncate();
-    int  write(const UCHAR* buf, int len);
-
-    UCHAR operator[] (UINT index) const;
-                       // return data[index] if in bounds, else 0
-                       // so no proper error condition but never mind for now
-    const UCHAR* getData() const { return data; }
-    UINT getLength() const { return length; }
-    UINT getSize() const { return size; }
-    UCHAR getPacketType() const { return packetType; }
-    void setSubstream(UCHAR s) { substream = s; }
-    UCHAR getSubstream() const { return substream; }
-    ULLONG getPTS() const;
-    bool hasPTS() const { return (getPTS() != PTS_INVALID); }
-
-    UINT findPictureHeader(bool h264) const;
-    UINT findSeqHeader(bool h264) const;
-    UINT countPictureHeaders(bool h264) const;
-    static const ULLONG PTS_INVALID = (1LL << 33);
-  protected:
-    void copyFrom(const PESPacket& packet);
-    UCHAR * data;
-    UINT length, size;
-    UINT data_size;
-    UCHAR packetType;
-    UCHAR substream;
-    UINT mutable seq_header; // 0 = no, 1 = unknown, else = header offset
-};
-
-class Demuxer
-{
-  public:
-    Demuxer();
-    virtual ~Demuxer();
-    static Demuxer* getInstance();
-     int init(Callback* tcallback, DrainTarget* audio, DrainTarget* video,
-         DrainTarget* teletext,
-         ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT, double fps=25.,
-         DVBSubtitles* tsubtitles=NULL);
-    virtual void reset();
-    virtual void flush();
-    void flushAudio();
-    void seek();
-    void setVideoStream(int id);
-    //TODO HANS next virtual necessary?
-    //virtual void setAudioStream(int id);
-    void setAudioStream(int id);
-    void setTeletextStream(int id);
-    void setDVBSubtitleStream(int id);
-    bool writeAudio();
-    bool writeVideo();
-    bool writeTeletext();
-
-    virtual int scan(UCHAR* buf, int len) = 0;
-    virtual int findPTS(UCHAR* buf, int len, ULLONG* dest) = 0;
-    virtual int put(UCHAR* buf, int len) = 0;
-    virtual void setFrameNum(ULONG frame) {}
-    virtual void setPacketNum(ULONG packet) {}
-    virtual ULONG getFrameNumFromPTS(ULLONG pts) {return 0;}
-    virtual ULONG getPacketNum() {return 0;}
-
-    bool* getmpAudioChannels(); //Maybe virtual ?
-    bool* getac3AudioChannels(); //Maybe virtual ?
-    bool* getSubtitleChannels();
-    int getselAudioChannel();
-    int getselSubtitleChannel();
-       bool ish264() {return h264;}
-    void seth264(bool newh264){h264=newh264;}
-
-    int getHorizontalSize() { return horizontal_size; }
-    int getVerticalSize() { return vertical_size; }
-    int getAspectRatio() { return aspect_ratio; }
-    int getFrameRate() { return frame_rate; }
-    int getBitRate() { return bit_rate; }
-    ULLONG getVideoPTS() { return video_pts; }
-    ULLONG getAudioPTS() { return audio_pts; }
-
-    enum AspectRatio
-    {
-      ASPECT_4_3  = 2,
-      ASPECT_16_9 = 3
-    };
-
-    // Remove all data from a buffer apart from video PES packets.
-    // Returns the length of the reduced data.
-    // removed *static function*, due to DemuxerTS
-    virtual UINT stripAudio(UCHAR* buf, UINT len);
-
-    // Scan a buffer to see if video packets are present.
-    // Returns true if video exists; false if not.
-    // removed *static function* for h264 detection
-    static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264);
-
-    enum PESTYPE
-    {
-      PESTYPE_PRIVATE_1 = 0xBD,
-
-      PESTYPE_AUD0 = 0xC0,
-      PESTYPE_AUD1,  PESTYPE_AUD2,  PESTYPE_AUD3,  PESTYPE_AUD4,
-      PESTYPE_AUD5,  PESTYPE_AUD6,  PESTYPE_AUD7,  PESTYPE_AUD8,
-      PESTYPE_AUD9,  PESTYPE_AUD10, PESTYPE_AUD11, PESTYPE_AUD12,
-      PESTYPE_AUD13, PESTYPE_AUD14, PESTYPE_AUD15, PESTYPE_AUD16,
-      PESTYPE_AUD17, PESTYPE_AUD18, PESTYPE_AUD19, PESTYPE_AUD20,
-      PESTYPE_AUD21, PESTYPE_AUD22, PESTYPE_AUD23, PESTYPE_AUD24,
-      PESTYPE_AUD25, PESTYPE_AUD26, PESTYPE_AUD27, PESTYPE_AUD28,
-      PESTYPE_AUD29, PESTYPE_AUD30, PESTYPE_AUD31,
-      PESTYPE_AUDMAX = PESTYPE_AUD31,
-
-      PESTYPE_VID0 = 0xE0,
-      PESTYPE_VID1,  PESTYPE_VID2,  PESTYPE_VID3,  PESTYPE_VID4,
-      PESTYPE_VID5,  PESTYPE_VID6,  PESTYPE_VID7,  PESTYPE_VID8,
-      PESTYPE_VID9,  PESTYPE_VID10, PESTYPE_VID11, PESTYPE_VID12,
-      PESTYPE_VID13, PESTYPE_VID14, PESTYPE_VID15,
-      PESTYPE_VIDMAX = PESTYPE_VID15
-    };
-    enum PESTYPE_SUBSTREAM
-    {
-      PESTYPE_SUBSTREAM_TELETEXT0 = 0x10,
-      PESTYPE_SUBSTREAM_TELETEXT1,PESTYPE_SUBSTREAM_TELETEXT2, PESTYPE_SUBSTREAM_TELETEXT3,
-      PESTYPE_SUBSTREAM_TELETEXT4,PESTYPE_SUBSTREAM_TELETEXT5,PESTYPE_SUBSTREAM_TELETEXT6,
-      PESTYPE_SUBSTREAM_TELETEXT7, PESTYPE_SUBSTREAM_TELETEXT8, PESTYPE_SUBSTREAM_TELETEXT9,
-      PESTYPE_SUBSTREAM_TELETEXT10,PESTYPE_SUBSTREAM_TELETEXT11,PESTYPE_SUBSTREAM_TELETEXT12,
-      PESTYPE_SUBSTREAM_TELETEXT13,PESTYPE_SUBSTREAM_TELETEXT14,PESTYPE_SUBSTREAM_TELETEXT15,
-      PESTYPE_SUBSTREAM_TELETEXTMAX=PESTYPE_SUBSTREAM_TELETEXT15,
-      PESTYPE_SUBSTREAM_DVBSUBTITLE0=0x20,
-      PESTYPE_SUBSTREAM_DVBSUBTITLE1,PESTYPE_SUBSTREAM_DVBSUBTITLE2,PESTYPE_SUBSTREAM_DVBSUBTITLE3,
-      PESTYPE_SUBSTREAM_DVBSUBTITLE4,PESTYPE_SUBSTREAM_DVBSUBTITLE5,PESTYPE_SUBSTREAM_DVBSUBTITLE6,
-      PESTYPE_SUBSTREAM_DVBSUBTITLE7,
-      PESTYPE_SUBSTREAM_DVBSUBTITLEMAX=PESTYPE_SUBSTREAM_DVBSUBTITLE7,
-      PESTYPE_SUBSTREAM_AC30 = 0x80,
-      PESTYPE_SUBSTREAM_AC31,PESTYPE_SUBSTREAM_AC32, PESTYPE_SUBSTREAM_AC33,
-      PESTYPE_SUBSTREAM_AC34,PESTYPE_SUBSTREAM_AC35,PESTYPE_SUBSTREAM_AC36,
-      PESTYPE_SUBSTREAM_AC37,
-      PESTYPE_SUBSTREAM_AC3MAX = PESTYPE_SUBSTREAM_AC37
-    };
-
-  protected:
-    // Operations on PES packets
-    bool submitPacket(PESPacket&);
-    void parsePacketDetails(PESPacket&);
-
-    // General demuxer objects and status indicators
-    static Demuxer* instance;
-    Stream videostream;
-    Stream audiostream;
-    DVBSubtitles* subtitles;
-    Stream teletextstream;
-    int shutdown();
-    bool initted;
-    bool vid_seeking;
-    bool aud_seeking;
-       bool h264;
-    int video_current, audio_current, teletext_current, subtitle_current;
-
-    // Video stream information
-    void setAspectRatio(enum AspectRatio);
-    Callback* callback;
-
-    int horizontal_size;
-    int vertical_size;
-    int profile;
-    enum AspectRatio aspect_ratio;
-    int arcnt;
-    int frame_rate;
-    int bit_rate;
-    ULLONG video_pts;
-    ULLONG video_pts_seek;
-    ULLONG audio_pts;
-    ULLONG teletext_pts;
-    bool isteletextdecoded;
-
-
-       unsigned int packetnum;
-
-    // Constants
-    static const int FrameRates[9];
-
-       double fps;
-
-    bool ispre_1_3_19;
-    bool avail_mpaudchan[PESTYPE_AUDMAX-PESTYPE_AUD0+1];
-    bool avail_ac3audchan[PESTYPE_SUBSTREAM_AC3MAX-PESTYPE_SUBSTREAM_AC30+1];
-    bool avail_dvbsubtitlechan[PESTYPE_SUBSTREAM_DVBSUBTITLEMAX-PESTYPE_SUBSTREAM_DVBSUBTITLE0+1];
-};
-
-#endif
+/*\r
+    Copyright 2005-2008 Mark Calderbank\r
+    Copyright 2007 Marten Richter (AC3 support)\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software Foundation, Inc.,\r
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+Thanks go to Jon Gettler of the MVPMC project and Stephen Rice for\r
+the demuxer in mvpmc. It was used in the creation of this demuxer;\r
+however, no code was copied verbatim.\r
+\r
+*/\r
+\r
+#ifndef DEMUXER_H\r
+#define DEMUXER_H\r
+\r
+#include "stream.h"\r
+#include "defines.h"\r
+\r
+class DVBSubtitles;\r
+class Callback;\r
+class DrainTarget;\r
+\r
+class PESPacket\r
+{\r
+  public:\r
+    PESPacket();\r
+    PESPacket(const PESPacket& packet);\r
+    PESPacket& operator=(const PESPacket& packet);\r
+    ~PESPacket();\r
+    void init(UCHAR type, UCHAR sub=0);\r
+    void truncate();\r
+    int  write(const UCHAR* buf, int len);\r
+\r
+    UCHAR operator[] (UINT index) const;\r
+                       // return data[index] if in bounds, else 0\r
+                       // so no proper error condition but never mind for now\r
+    const UCHAR* getData() const { return data; }\r
+    UINT getLength() const { return length; }\r
+    UINT getSize() const { return size; }\r
+    UCHAR getPacketType() const { return packetType; }\r
+    void setSubstream(UCHAR s) { substream = s; }\r
+    UCHAR getSubstream() const { return substream; }\r
+    ULLONG getPTS() const;\r
+    bool hasPTS() const { return (getPTS() != PTS_INVALID); }\r
+\r
+    UINT findPictureHeader(bool h264) const;\r
+    UINT findSeqHeader(bool h264) const;\r
+    UINT countPictureHeaders(bool h264) const;\r
+    static const ULLONG PTS_INVALID = (1LL << 33);\r
+\r
+\r
+\r
+  protected:\r
+    void copyFrom(const PESPacket& packet);\r
+    UCHAR * data;\r
+    UINT length, size;\r
+    UINT data_size;\r
+    UCHAR packetType;\r
+    UCHAR substream;\r
+    UINT mutable seq_header; // 0 = no, 1 = unknown, else = header offset\r
+};\r
+\r
+class Demuxer\r
+{\r
+  public:\r
+    Demuxer();\r
+    virtual ~Demuxer();\r
+    static Demuxer* getInstance();\r
+     int init(Callback* tcallback, DrainTarget* audio, DrainTarget* video,\r
+         DrainTarget* teletext,\r
+         ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT, double fps=25.,\r
+         DVBSubtitles* tsubtitles=NULL);\r
+    virtual void reset();\r
+    virtual void flush();\r
+    void flushAudio();\r
+    void seek();\r
+    void setVideoStream(int id);\r
+    //TODO HANS next virtual necessary?\r
+    //virtual void setAudioStream(int id);\r
+    void setAudioStream(int id);\r
+    void setTeletextStream(int id);\r
+    void setDVBSubtitleStream(int id);\r
+    bool writeAudio();\r
+    bool writeVideo();\r
+    bool writeTeletext();\r
+\r
+    virtual int scan(UCHAR* buf, int len) = 0;\r
+    virtual int findPTS(UCHAR* buf, int len, ULLONG* dest) = 0;\r
+    virtual int put(UCHAR* buf, int len) = 0;\r
+    virtual void setFrameNum(ULONG frame) {}\r
+    virtual void setPacketNum(ULONG packet) {}\r
+    virtual ULONG getFrameNumFromPTS(ULLONG pts) {return 0;}\r
+    virtual ULONG getPacketNum() {return 0;}\r
+\r
+    bool* getmpAudioChannels(); //Maybe virtual ?\r
+    bool* getac3AudioChannels(); //Maybe virtual ?\r
+    bool* getSubtitleChannels();\r
+    int getselAudioChannel();\r
+    int getselSubtitleChannel();\r
+       bool ish264() {return h264;}\r
+    void seth264(bool newh264){h264=newh264;}\r
+\r
+    int getHorizontalSize() { return horizontal_size; }\r
+    int getVerticalSize() { return vertical_size; }\r
+    int getAspectRatio() { return aspect_ratio; }\r
+    int getFrameRate() { return frame_rate; }\r
+    int getBitRate() { return bit_rate; }\r
+    ULLONG getVideoPTS() { return video_pts; }\r
+    ULLONG getAudioPTS() { return audio_pts; }\r
+\r
+    enum AspectRatio\r
+    {\r
+      ASPECT_4_3  = 2,\r
+      ASPECT_16_9 = 3\r
+    };\r
+\r
+    // Remove all data from a buffer apart from video PES packets.\r
+    // Returns the length of the reduced data.\r
+    // removed *static function*, due to DemuxerTS\r
+    virtual UINT stripAudio(UCHAR* buf, UINT len);\r
+    void changeTimes(UCHAR* buf, UINT len,UINT playtime);\r
+\r
+    // Scan a buffer to see if video packets are present.\r
+    // Returns true if video exists; false if not.\r
+    // removed *static function* for h264 detection\r
+    static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264);\r
+\r
+    enum PESTYPE\r
+    {\r
+      PESTYPE_PRIVATE_1 = 0xBD,\r
+\r
+      PESTYPE_AUD0 = 0xC0,\r
+      PESTYPE_AUD1,  PESTYPE_AUD2,  PESTYPE_AUD3,  PESTYPE_AUD4,\r
+      PESTYPE_AUD5,  PESTYPE_AUD6,  PESTYPE_AUD7,  PESTYPE_AUD8,\r
+      PESTYPE_AUD9,  PESTYPE_AUD10, PESTYPE_AUD11, PESTYPE_AUD12,\r
+      PESTYPE_AUD13, PESTYPE_AUD14, PESTYPE_AUD15, PESTYPE_AUD16,\r
+      PESTYPE_AUD17, PESTYPE_AUD18, PESTYPE_AUD19, PESTYPE_AUD20,\r
+      PESTYPE_AUD21, PESTYPE_AUD22, PESTYPE_AUD23, PESTYPE_AUD24,\r
+      PESTYPE_AUD25, PESTYPE_AUD26, PESTYPE_AUD27, PESTYPE_AUD28,\r
+      PESTYPE_AUD29, PESTYPE_AUD30, PESTYPE_AUD31,\r
+      PESTYPE_AUDMAX = PESTYPE_AUD31,\r
+\r
+      PESTYPE_VID0 = 0xE0,\r
+      PESTYPE_VID1,  PESTYPE_VID2,  PESTYPE_VID3,  PESTYPE_VID4,\r
+      PESTYPE_VID5,  PESTYPE_VID6,  PESTYPE_VID7,  PESTYPE_VID8,\r
+      PESTYPE_VID9,  PESTYPE_VID10, PESTYPE_VID11, PESTYPE_VID12,\r
+      PESTYPE_VID13, PESTYPE_VID14, PESTYPE_VID15,\r
+      PESTYPE_VIDMAX = PESTYPE_VID15\r
+    };\r
+    enum PESTYPE_SUBSTREAM\r
+    {\r
+      PESTYPE_SUBSTREAM_TELETEXT0 = 0x10,\r
+      PESTYPE_SUBSTREAM_TELETEXT1,PESTYPE_SUBSTREAM_TELETEXT2, PESTYPE_SUBSTREAM_TELETEXT3,\r
+      PESTYPE_SUBSTREAM_TELETEXT4,PESTYPE_SUBSTREAM_TELETEXT5,PESTYPE_SUBSTREAM_TELETEXT6,\r
+      PESTYPE_SUBSTREAM_TELETEXT7, PESTYPE_SUBSTREAM_TELETEXT8, PESTYPE_SUBSTREAM_TELETEXT9,\r
+      PESTYPE_SUBSTREAM_TELETEXT10,PESTYPE_SUBSTREAM_TELETEXT11,PESTYPE_SUBSTREAM_TELETEXT12,\r
+      PESTYPE_SUBSTREAM_TELETEXT13,PESTYPE_SUBSTREAM_TELETEXT14,PESTYPE_SUBSTREAM_TELETEXT15,\r
+      PESTYPE_SUBSTREAM_TELETEXTMAX=PESTYPE_SUBSTREAM_TELETEXT15,\r
+      PESTYPE_SUBSTREAM_DVBSUBTITLE0=0x20,\r
+      PESTYPE_SUBSTREAM_DVBSUBTITLE1,PESTYPE_SUBSTREAM_DVBSUBTITLE2,PESTYPE_SUBSTREAM_DVBSUBTITLE3,\r
+      PESTYPE_SUBSTREAM_DVBSUBTITLE4,PESTYPE_SUBSTREAM_DVBSUBTITLE5,PESTYPE_SUBSTREAM_DVBSUBTITLE6,\r
+      PESTYPE_SUBSTREAM_DVBSUBTITLE7,\r
+      PESTYPE_SUBSTREAM_DVBSUBTITLEMAX=PESTYPE_SUBSTREAM_DVBSUBTITLE7,\r
+      PESTYPE_SUBSTREAM_AC30 = 0x80,\r
+      PESTYPE_SUBSTREAM_AC31,PESTYPE_SUBSTREAM_AC32, PESTYPE_SUBSTREAM_AC33,\r
+      PESTYPE_SUBSTREAM_AC34,PESTYPE_SUBSTREAM_AC35,PESTYPE_SUBSTREAM_AC36,\r
+      PESTYPE_SUBSTREAM_AC37,\r
+      PESTYPE_SUBSTREAM_AC3MAX = PESTYPE_SUBSTREAM_AC37\r
+    };\r
+\r
+  protected:\r
+    // Operations on PES packets\r
+    bool submitPacket(PESPacket&);\r
+    void parsePacketDetails(PESPacket&);\r
+\r
+    // General demuxer objects and status indicators\r
+    static Demuxer* instance;\r
+    Stream videostream;\r
+    Stream audiostream;\r
+    DVBSubtitles* subtitles;\r
+    Stream teletextstream;\r
+    int shutdown();\r
+    bool initted;\r
+    bool vid_seeking;\r
+    bool aud_seeking;\r
+       bool h264;\r
+    int video_current, audio_current, teletext_current, subtitle_current;\r
+\r
+    // Video stream information\r
+    void setAspectRatio(enum AspectRatio);\r
+    Callback* callback;\r
+\r
+    int horizontal_size;\r
+    int vertical_size;\r
+    int profile;\r
+    enum AspectRatio aspect_ratio;\r
+    int arcnt;\r
+    int frame_rate;\r
+    int bit_rate;\r
+    ULLONG video_pts;\r
+    ULLONG video_pts_seek;\r
+    ULLONG audio_pts;\r
+    ULLONG teletext_pts;\r
+    bool isteletextdecoded;\r
+\r
+\r
+       unsigned int packetnum;\r
+\r
+    // Constants\r
+    static const int FrameRates[9];\r
+\r
+       double fps;\r
+\r
+    bool ispre_1_3_19;\r
+    bool avail_mpaudchan[PESTYPE_AUDMAX-PESTYPE_AUD0+1];\r
+    bool avail_ac3audchan[PESTYPE_SUBSTREAM_AC3MAX-PESTYPE_SUBSTREAM_AC30+1];\r
+    bool avail_dvbsubtitlechan[PESTYPE_SUBSTREAM_DVBSUBTITLEMAX-PESTYPE_SUBSTREAM_DVBSUBTITLE0+1];\r
+};\r
+\r
+#endif\r
index 2c53b59c30be7fe9fab73008a34b2d5720f201c0..09c7ea07cad592dd099e64fe1b6030e6fc248c9f 100644 (file)
-/*
-    Copyright 2006 Mark Calderbank, Andreas Vogel
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "demuxeraudio.h"
-#include "audio.h"
-#include "i18n.h"
-#include "log.h"
-
-#define HDRBYTE1 0xff
-#define HDRBYTE2 0xe0
-#define HDRBYTE2MASK 0xe0
-
-
-
-class PacketBuffer {
-  
-  public:
-    PacketBuffer(Stream *as,UCHAR strtype) {
-      log=Log::getInstance();
-      audio=as;
-      streamtype=strtype;
-      newStream();
-    }
-    //just handle the data (do not deal with headers)
-    int putInternal(UCHAR* buf,int len,unsigned int &packetnum);
-    void reset(){
-      partPacket=0;
-      bytesWritten=0;
-      framelen=DemuxerAudio::PACKET_SIZE;
-    }
-    void newStream() {
-      reset();
-      numpackets=0;
-      numbytes=0;
-                       skipfactor=0;
-                       numskip=0;
-    }
-    bool bufferFull() {
-      return (partPacket>=framelen);
-    }
-    //can we write a new packet?
-    bool bufferEmpty() {
-      return partPacket==0;
-    }
-    //only set this, if buffer empty
-    //otherwise ignored!
-    bool setFramelen(int len) {
-      if (! bufferEmpty() ) return false;
-      if (len > (int)DemuxerAudio::PACKET_SIZE) return false;
-      framelen=len;
-      return true;
-    }
-    //how much bytes do we need to fill the packet?
-    int bytesMissing() {
-      return framelen-partPacket;
-    }
-    int getFramelen() {
-      return framelen;
-    }
-               void setSkipFactor(int factor) {
-                       skipfactor=factor;
-                       numskip=0;
-               }
-  private:
-    void packetWritten() {
-      numbytes+=framelen;
-      //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written packet %ld l=%d, bytes %ld",numpackets,framelen,numbytes);
-      numpackets++;
-      reset();
-    }
-               bool doSkip();
-    UCHAR store[DemuxerAudio::PACKET_SIZE]; // Storage for partial packets
-    int partPacket;    // Length of partial packet stored from previous put()
-    int bytesWritten;  //if they are !=0 and != framelength the stream is full...
-    int framelen;
-    Log * log;
-    Stream * audio;
-    UCHAR streamtype;
-    //global counters
-    ULONG numpackets;
-    ULONG numbytes;
-               int skipfactor;
-               int numskip;
-};
-
-
-DemuxerAudio::DemuxerAudio(int p_vID, int p_aID)
-{
-  inSync=false;
-  isStarting=true;
-  log=Log::getInstance();
-  readHeaders=0;
-  streamtype=Audio::MP3;
-  buffer=new PacketBuffer(&audiostream,streamtype);
-//  buffer=new PacketBuffer(&teststream,streamtype);
-  globalBytesWritten=0;
-  packetnum=0;
-  id3=NULL;
-  info=NULL;
-       vbr=NULL;
-  reset();
-}
-
-DemuxerAudio::~DemuxerAudio() {
-  delete buffer;
-  if(info) delete info;
-  if(id3) delete id3;
-       if (vbr) delete vbr;
-}
-
-void DemuxerAudio::flush()
-{
-  Demuxer::flushAudio();
-  buffer->newStream();
-  tmpFill=0;
-}
-
-void DemuxerAudio::reset() {
-  buffer->newStream();
-  tmpFill=0;
-  readHeaders=0;
-  packetnum=0;
-  outOfSync=0;
-  globalBytesWritten=0;
-  if (id3) delete id3;
-  id3=NULL;
-  if (info) delete info;
-  info=NULL;
-       if (vbr) delete vbr;
-       vbr=NULL;
-  inSync=false;
-  hasHdrInfo=false;
-  hasVBRInfo=false;
-  isStarting=true;
-  hdrBitrate=128000;
-  hdrSamplingRate=44100;
-  avrBitrate=0;
-  hdrFramelen=0;
-  isStarting=true;
-}
-
-int DemuxerAudio::scan(UCHAR *buf, int len)
-{
-  //no differend pids here
-  return 0;
-}
-
-void DemuxerAudio::setVID(int p_vID)
-{
-}
-
-void DemuxerAudio::setAID(int p_aID,int type)
-{
-}
-
-static char * id3_1_genre[] = {
-  "Blueshhh",
-  "Classic Rock",
-  "Country",
-  "Dance",
-  "Disco",
-  "Funk",
-  "Grunge",
-  "Hip-Hop",
-  "Jazz",
-  "Metal",
-  "New Age",
-  "Oldies",
-  "Other",
-  "Pop",
-  "R&B",
-  "Rap",
-  "Reggae",
-  "Rock",
-  "Techno",
-  "Industrial",
-  "Alternative",
-  "Ska",
-  "Death Metal",
-  "Pranks",
-  "Soundtrack",
-  "Euro-Techno",
-  "Ambient",
-  "Trip-Hop",
-  "Vocal",
-  "Jazz+Funk",
-  "Fusion",
-  "Trance",
-  "Classical",
-  "Instrumental",
-  "Acid",
-  "House",
-  "Game",
-  "Sound Clip",
-  "Gospel",
-  "Noise",
-  "AlternRock",
-  "Bass",
-  "Soul",
-  "Punk",
-  "Space",
-  "Meditative",
-  "Instrumental Pop",
-  "Instrumental Rock",
-  "Ethnic",
-  "Gothic",
-  "Darkwave",
-  "Techno-Industrial",
-  "Electronic",
-  "Pop-Folk",
-  "Eurodance",
-  "Dream",
-  "Southern Rock",
-  "Comedy",
-  "Cult",
-  "Gangsta",
-  "Top 40",
-  "Christian Rap",
-  "Pop/Funk",
-  "Jungle",
-  "Native American",
-  "Cabaret",
-  "New Wave",
-  "Psychadelic",
-  "Rave",
-  "Showtunes",
-  "Trailer",
-  "Lo-Fi",
-  "Tribal",
-  "Acid Punk",
-  "Acid Jazz",
-  "Polka",
-  "Retro",
-  "Musical",
-  "Rock & Roll",
-  "Hard Rock"
-};
-
-
-
-static int bitrateTable[16][5]={
-/*        L1,L2,L3,2L1,2L2 */
-/*0000*/ {-1,-1,-1,-1,-1},
-/*0001*/ {32,32,32,32,8},
-/*0010*/ {64,48,40,48,16},
-/*0011*/ {96,56,48,56,24},
-/*0100*/ {128,64,56,64,32},
-/*0101*/ {160,80,64,80,40},
-/*0110*/ {192,96,80,96,48},
-/*0111*/ {224,112,96,112,56},
-/*1000*/ {256,128,112,128,64},
-/*1001*/ {288,160,128,144,80},
-/*1010*/ {320,192,160,160,96},
-/*1011*/ {352,224,192,176,112},
-/*1100*/ {384,256,224,192,128},
-/*1101*/ {416,320,256,224,144},
-/*1110*/ {448,384,320,256,160},
-/*1111*/ {-1,-1,-1,-1,-1} };
-
-static int  samplingRateTable[4][3]={
-/*00*/ {44100,22050,11025},
-/*01*/ {48000,24000,12000},
-/*10*/ {32000,16000,8000},
-/*11*/ {-1,-1,-1}};
-
-//max 7 char!
-static const char * mpegString(UCHAR code) {
-  switch(code) {
-    case 0:
-      return "MPEG2.5";
-    case 1:
-      return "RESERV";
-    case 2:
-      return "MPEG 2";
-    case 3:
-      return "MPEG 1";
-  }
-  return "UNKNOWN";
-}
-
-static const char * layerString(UCHAR code) {
-  switch(code) {
-    case 0:
-      return "Layer reserved";
-    case 1:
-      return "Layer III";
-    case 2:
-      return "Layer II";
-    case 3:
-      return "Layer I";
-  }
-  return "Layer UNKNOWN";
-}
-/**
-  * parse an id3 Header
-  * provided by Brian Walton
-  * @returns -1 of nothing found
-  */
-  
-int DemuxerAudio::id3_2_3_FrameParse(unsigned char buf[], id3_frame *frame)
-{
-  if (buf[0] < 0x20 || buf[1] < 0x20 || buf [2] < 0x20 ) return -1;
-  frame->size = (buf[4] & 0x7F) << 21 | (buf[5] & 0x7F) << 14 |  (buf[6] & 0x7F) << 7 | (buf[7] & 0x7F);
-  if (frame->size == 0) return -1;
-  //TODO. clearify flags against:
-  //http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b
-  frame->flags.tagAlterPreserv = (buf[8] & 0x80) >> 7;
-  frame->flags.filelterPreserv = (buf[8] & 0x40) >> 6;
-  frame->flags.readOnly = (buf[8] & 0x20) >> 5;
-  frame->flags.groupId = (buf[9] & 0x20) >> 5;
-  frame->flags.compression = (buf[9] & 0x80) >> 7;
-  frame->flags.encryption = (buf[9] & 0x40) >> 6;
-  frame->flags.unsync = 0;
-  frame->flags.dataLen = 0;
-  return 0;
-}
-
- /**
-  * parse an id3 Header
-  * provided by Brian Walton
-  * @returns -1 of nothing found
-  */
-  
-int DemuxerAudio::id3_2_2_FrameParse(unsigned char buf[], id3_frame *frame)
-{
-  if (buf[0] < 0x20 || buf[1] < 0x20 || buf[2] < 0x20) return -1;
-  frame->size = (buf[3] & 0x7F) << 14 |  (buf[4] & 0x7F) << 7 | (buf[5] & 0x7F);
-  if (frame->size == 0) return -1;
-  return 0;
-}
-
-
-//fill an id3tag from a frame payload
-//http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b
-//http://id3.org/id3v2-00
-static struct tagid {
-  const char * bytes;
-  int index;
-} knownFrames[]= {
-  //ID3V2.3
-  {"TIT2",1}, //title
-  {"TPE1",2}, //artist
-  {"TCON",3}, //genre
-  {"TRCK",6}, //track
-  {"TYER",4}, //year
-  {"TALB",5}, //album
-  {"TCOM",7}, //composer
-  {"COMM",8}, //comment
-              //Text encoding           $xx
-              //Language                $xx xx xx
-              //Short content descrip.  <text string according to encoding> $00 (00)
-              //The actual text         <full text string according to encoding>
-  //ID3V2.0
-  {"TT2",1 },
-  {"TP1",2 },
-  {"TCM",7 },
-  {"TCO",3 }, //(genreNumber)
-  {"TAL",5 },
-  {"TRK",6 },
-  {"TYE",4 },
-  {"COM",8 }
-};
-#define NUMKNOWN (sizeof(knownFrames)/sizeof(knownFrames[0]))
-
-/*fill in infos
-  from an ID3 V2.x, V2.3 frame into the tags structure
-  frameData must point to the header
-  framelen is the len without header (10 Bytes for V23, 6 Bytes for v2x)
-  */
-
-#define MAXLEN(tagtype) ((UINT)frameLen<sizeof(tag->tagtype)-1?(UINT)frameLen:sizeof(tag->tagtype)-1)
-bool DemuxerAudio::fillId3Tag(id3_tag * tag,UCHAR * frameData, int frameLen, int dataOffset, bool v23) {
-  int tl=v23?4:3;
-  int tagIndex=-1;
-  if (tag == NULL) return false;
-  if (frameLen < 2) return false;
-  for (UINT i=0;i< NUMKNOWN;i++) {
-    if(strncmp((char *)frameData,knownFrames[i].bytes,tl) == 0) {
-      tagIndex=knownFrames[i].index;
-      break;
-    }
-  }
-  if (tagIndex < 0) return false;
-  UCHAR encoding=*(frameData+dataOffset);
-  dataOffset++;
-  frameLen--;
-  if (encoding != 0) {
-    log->log("DemuxerAudio",Log::DEBUG,"unknown encoding for tag %d, tagid %s",encoding,
-        knownFrames[tagIndex].bytes);
-    return false;
-  }
-  switch(tagIndex) {
-    case 1:  //title
-      strncpy(tag->title,(char*)(frameData+dataOffset),MAXLEN(title));
-      tag->title[MAXLEN(title)]=0;
-      break;
-    case 2:  //artist
-      strncpy(tag->artist,(char*)(frameData+dataOffset),MAXLEN(artist));
-      tag->artist[MAXLEN(artist)]=0;
-      break;
-    case 3:  //genre
-      {
-      UCHAR * st=frameData+dataOffset;
-      int genre=0;
-      if (*st=='(') {
-        genre=atoi((const char *)(st+1)) && 31;
-        st=(UCHAR *)id3_1_genre[genre];
-      }
-      strncpy(tag->genre,(char*)st,MAXLEN(genre));
-      tag->genre[MAXLEN(genre)]=0;
-      break;
-      }
-    case 4:  //year
-      strncpy(tag->year,(char *)(frameData+dataOffset),MAXLEN(year));
-      tag->year[MAXLEN(year)]=0;
-      break;
-    case 5:  //album
-      strncpy(tag->album,(char *)(frameData+dataOffset),MAXLEN(album));
-      tag->album[MAXLEN(album)]=0;
-      break;
-    case 6:  //track
-      strncpy(tag->track,(char *)(frameData+dataOffset),MAXLEN(track));
-      tag->track[MAXLEN(track)]=0;
-      break;
-    case 7:  //composer
-      strncpy(tag->composer,(char *)(frameData+dataOffset),MAXLEN(composer));
-      tag->composer[MAXLEN(composer)]=0;
-      break;
-    case 8:  //comment
-      strncpy(tag->comment,(char *)(frameData+dataOffset),MAXLEN(comment));
-      tag->comment[MAXLEN(comment)]=0;
-      break;
-    default:
-      return false;
-  }
-
-  return true;
-}
-
-/**
-  * parse an id3 Header
-  * based on code provided by Brian Walton
-  * @returns -1 of nothing found
-  *  otherwise the id3 info is filled
-  */
-
-int DemuxerAudio::parseID3V2(UCHAR *data, int len) {
-  int debug=0;
-  UCHAR * start=data;
-  id3_header id3header;
-  id3_frame id3frame;
-  id3_tag * id3tag=NULL;
-  //len = read(fd, data, 10);
-  if (len < 10) {
-    delete id3tag;
-    return -1;
-  }
-  len-=10;
-  if(data[0]=='I' && data[1]=='D' && data[2]=='3')
-  {
-    id3tag=new id3_tag();
-    id3header.major = data[3];
-    id3header.minor = data[4];
-    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 V2.%d.%d found\n", id3header.major, id3header.minor);
-    id3header.flags.unsynchronisation = (data[5] & 0x80)>>7;
-    id3header.flags.extended_header = (data[5] & 0x40)>>6;
-    id3header.flags.experimental = (data[5] & 0x20)>>5;
-    id3header.flags.footer = (data[5] & 0x10)>>4;
-    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Unsynchronisation flag: %d\n", id3header.flags.unsynchronisation);
-    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header flag: %d\n", id3header.flags.extended_header);
-    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Experimental indicator flag: %d\n", id3header.flags.experimental);
-    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Footer present flag: %d\n", id3header.flags.footer);
-    id3header.size = (data[6] & 0x7F) << 21 | (data[7] & 0x7F) << 14 |  (data[8] & 0x7F) << 7 | (data[9] & 0x7F);
-    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 Size: %d\n", id3header.size);
-    data=start+10;
-    if (len <= id3header.size) {
-      if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"header size to big %d, only %d bytes available\n",id3header.size,len);
-      delete id3tag;
-      return -1;
-    }
-    if (id3header.flags.extended_header)
-    {
-      int extended_hdr_hdr=4;  //still to be discussed (id3.org...)
-      //read extended header size
-      if (len < extended_hdr_hdr) {
-        if (debug) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended header found but cannot read\n");
-        delete id3tag;
-        return -1;
-      }
-      if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"remaining %d chars after extended hdr hdr\n", len);
-      id3header.extended_header.size = (data[0] & 0x7F) << 21 | (data[1] & 0x7F) << 14 |  (data[2] & 0x7F) << 7 | (data[3] & 0x7F);
-      if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header size: %d\n", id3header.extended_header.size);
-      if (len <= id3header.extended_header.size+extended_hdr_hdr) {
-      if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended Header to big, only %d bytes available\n",len);
-        delete id3tag;
-        return -1;
-      }
-      //lseek(fd, id3header.extended_header.size - 6, SEEK_CUR);
-      data+=id3header.extended_header.size+extended_hdr_hdr;
-      len-=id3header.extended_header.size+extended_hdr_hdr;
-    }
-    //set the end of the header
-    UCHAR * eob=start+id3header.size+10;
-    bool readNext=true;
-    while (data < eob && readNext)
-    {
-      //skip over some padding - found this in lame MCDI tag...
-      if (*data == 0) {
-        data++;
-        continue;
-      }
-      readNext=false;
-      switch(id3header.major)
-      {
-        case 2: //ID3 V2.2.x
-          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.2 frame, %d : %c %c %c\n", data-start,*data,*(data+1),*(data+2));
-          if (data + 6 >= eob)
-          {
-            break;
-          }
-          if (id3_2_2_FrameParse(data, &id3frame) < 0)
-          {
-            break;
-          }
-          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame size: %d\n", id3frame.size);
-          fillId3Tag(id3tag,data,id3frame.size,6,false);
-          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + 6 +1);
-          data+=6+id3frame.size;
-          readNext=true;
-          break;
-        case 3: //ID3 V2.3.x
-          {
-          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.3 frame, %d : %c %c %c %c\n", data-start,
-              *data,*(data+1),*(data+2),*(data+3));
-          if (data + 10 >= eob)
-          {
-            break;
-          }
-          if (id3_2_3_FrameParse(data, &id3frame) <0)
-          {
-            break;
-          }
-          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame size: %d\n", id3frame.size);
-          int dataOffset=10;
-          if (id3frame.flags.groupId)
-          {
-            dataOffset++;
-            if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame group: %d\n", data[dataOffset]);
-          }
-          if (id3frame.flags.compression)
-          {
-            if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame compressed: %d\n", id3frame.flags.compression);
-          }
-          if (id3frame.flags.encryption)
-          {
-            dataOffset+=1;
-            if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame encryption method: %d\n", data[dataOffset]);
-          }
-          fillId3Tag(id3tag,data,id3frame.size-dataOffset+10,dataOffset,true);
-          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + dataOffset +1);
-          data+=10+id3frame.size;
-          readNext=true;
-          break;
-          }
-        default:
-          //don't support this version
-          delete id3tag;
-          return -1;
-      }
-    }
-
-    data=eob;
-    //store the found tag
-    if (id3) delete id3;
-    id3=id3tag;
-    return data-start;
-  }
-  return -1;
-}
-
-/**
-  * parse an id3v1 Header
-  * based on code provided by Brian Walton
-  * @returns -1 of nothing found
-  *  otherwise the id3 info is filled
-  */
-#define MEMCPY(type,len,offset) {int type##max=sizeof(tag->type)-1<len?sizeof(tag->type)-1:len;strncpy(tag->type,(char*)&data[offset],type##max);tag->type[type##max]=0;}
-
-int DemuxerAudio::parseID3V1(UCHAR *data, int len) {
-  int debug=1;
-  if (len < 128) return -1;
-  if(data[0]=='T' && data[1]=='A' && data[2]=='G')
-  {
-    id3_tag * tag=new id3_tag();
-    if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1 tag found\n");
-    MEMCPY(title,30,3);
-    MEMCPY(artist,30,33);
-    MEMCPY(album,30,63);
-    MEMCPY(year,4,93);
-    if (data[125]==0 && data[126]!=0)
-    { //ID3 V1.1
-      if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.1 tag\n");
-      MEMCPY(comment,29,97);
-      sprintf(tag->track, "%d", data[126]);
-    } else {
-      if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.0 tag\n");
-      MEMCPY(comment,30,97);
-    }
-    if (data[127] < sizeof(id3_1_genre)/sizeof(id3_1_genre[0]))
-    {
-      sprintf(tag->genre, id3_1_genre[data[127]]);
-    }
-    if (id3) delete id3;
-    id3=tag;
-    return 0;
-  }
-  return -1;
-}
-
-//infos from http://www.multiweb.cz/twoinches/MP3inside.htm
-int DemuxerAudio::parseVBR(UCHAR *data, int len) {
-       UCHAR *hdr=findHeader(data,len);
-       //we expect the header exactly here
-       if (hdr != data) return -1;
-       const static char * VBRHDR="Xing";
-       int vbridpos=36;
-  UCHAR mpgtype=(data[1] & 0x18)>>3;
-  UCHAR chmode=(data[2] & 0xc0) >> 6;
-  UCHAR layer=(data[2] & 0x06) >>1;
-       if ( mpgtype == 3 && chmode == 11) vbridpos=21;
-       if ( mpgtype != 3 && chmode != 11) vbridpos=21;
-       if ( mpgtype != 3 && chmode == 11) vbridpos=13;
-       //check for the header ID
-       if (vbridpos+(int)strlen(VBRHDR)+4 >= len) {
-               Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header %d",len);
-               return -1;
-       }
-       for (int i=4;i<vbridpos;i++) {
-               if (data[i] != 0) {
-                 Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"garbage when searching VBR header at pos %d",i);
-                       return -1;
-               }
-       }
-       if ( strncmp((char *)&data[vbridpos],VBRHDR,strlen(VBRHDR)) != 0) {
-               Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"no VBR header at pos %d",vbridpos);
-               return -1;
-       }
-       int framedata=vbridpos+strlen(VBRHDR);
-       int expectedLen=0;
-       //OK we should now have a valid vbr header
-       bool hasFramenum=data[framedata+3] & 1;
-       bool hasBytes=data[framedata+3] & 0x2;
-       bool hasTOC=data[framedata+3] & 0x4;
-       expectedLen+=8;
-       if (hasTOC) expectedLen+=100;
-       if (framedata+expectedLen > len) {
-               Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header data %d, expected %d",
-                               len,framedata+expectedLen);
-               return -1;
-       }
-       if (!hasFramenum || ! hasBytes || ! hasTOC) {
-               //not usefull for us..
-               Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"not all parts in VBR header - ignore");
-               return -1;
-       }
-       framedata+=4;
-       if (vbr) delete vbr;
-       vbr=new vbrInfo();
-       vbr->numFrames=data[framedata] << 24 | data[framedata+1]<<16|
-                       data[framedata+2]<<8 |data[framedata+3];
-       framedata+=4;
-       vbr->numBytes=data[framedata] << 24 | data[framedata+1]<<16|
-                       data[framedata+2]<<8 |data[framedata+3];
-       framedata+=4;
-       for (int ti=0;ti<100;ti++) {
-               vbr->table[ti]=data[framedata+ti];
-       }
-       //compute file size in seconds
-       //should be (#of frames -1) *samplesPerFrame / sampleRate
-       //TODO: difference for Mono?
-       ULONG samplesPerFrame=384; //layer1
-       if (layer != 3) samplesPerFrame=1152;
-       vbr->fileSeconds=(vbr->numFrames-1)*samplesPerFrame/hdrSamplingRate;
-       Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"successfully read VBR %ldbytes, %ld frames, %ldsec",
-                       vbr->numBytes,vbr->numFrames,vbr->fileSeconds);
-       return hdrFramelen;
-}
-
-
-
-
-
-
-
-UCHAR * DemuxerAudio::findHeader(UCHAR *buf, int len, bool writeInfo) {
-  while (len >= 3) //assume hdr+crc
-  {
-    UCHAR pattern=*buf;
-    buf++; len--;
-    if (pattern != HDRBYTE1 ) continue;
-    if ((*buf & HDRBYTE2MASK) != HDRBYTE2) continue;
-    if (readHeader((buf-1),4,writeInfo) != 0) continue;
-    return buf-1;
-  }
-  return NULL;
-}
-
-
-
-int DemuxerAudio::readHeader(UCHAR * hbuf,int len,bool writeInfo) {
-  int curFramelen=0;
-  int curBitrate=0;
-  int curSamplingRate=0;
-  if (*hbuf != HDRBYTE1) return -1;
-  hbuf++;
-  if ((*hbuf & HDRBYTE2MASK) != HDRBYTE2) return -1;
-  UCHAR mpgtype=(*hbuf & 0x18)>>3;
-  if (mpgtype == 1) {
-    log->log("DemuxerAudio",Log::DEBUG,"header invalid mpgtype %s %i %i %i",
-        mpegString(mpgtype),*hbuf,*(hbuf+1),*(hbuf+2));
-    return 1;
-  }
-  UCHAR layer=(*hbuf & 0x06) >>1;
-  //bool hasCRC=!(*hbuf & 1);
-  hbuf++;
-  UCHAR bitrateCode=(*hbuf & 0xf0) >>4;
-  UCHAR samplingCode=(*hbuf & 0x0c) >> 2;
-  bool padding=*hbuf & 0x02;
-  hbuf++;
-  //0 Stereo, 1 JointStereo, 2 Dual, 3 Mono
-  UCHAR chmode=(*hbuf & 0xc0) >> 6;
-  //UCHAR extension=(*hbuf & 0x30) >> 4;
-
-  //layercode: 1-L3, 2-L2, 3-L1
-  //columns 0,1,2 for MPEG1
-  UCHAR bitrateColumn=3-layer;
-  if (bitrateColumn > 2) {
-    log->log("DemuxerAudio",Log::DEBUG,"header invalid layer %s %i %i %i",
-        layerString(layer),*(hbuf-2),*(hbuf-1),*hbuf);
-    return 1;
-  }
-  if (mpgtype != 3) bitrateColumn+=3;
-  if (bitrateColumn>4) bitrateColumn=4;
-  curBitrate=1000*bitrateTable[bitrateCode][bitrateColumn];
-  UCHAR sampleRateColumn=0;
-  if (mpgtype == 10) sampleRateColumn=1;
-  if (mpgtype == 0) sampleRateColumn=2;
-  curSamplingRate=samplingRateTable[samplingCode][sampleRateColumn];
-  if (curSamplingRate < 0 || curBitrate < 0) {
-    log->log("DemuxerAudio",Log::DEBUG,"header invalid rates br=%d sr=%d %i %i %i",
-        curBitrate,curSamplingRate,*(hbuf-2),*(hbuf-1),*hbuf);
-    return 1;
-  }
-  int padbytes=0;
-  if (padding) {
-    if (layer == 3) padbytes=4;
-    else padbytes=1;
-  }
-  if (layer == 3) {
-    //Layer 1
-    //FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4
-    curFramelen=(12*curBitrate/curSamplingRate+padbytes) * 4;
-  }
-  else {
-    //Layer 2/3
-    //FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
-    curFramelen=144*curBitrate/curSamplingRate+padbytes;
-  }
-  //the header itself
-  if (curFramelen < 32) {
-  log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d-invalid %i %i %i",
-      readHeaders,mpegString(mpgtype),layerString(layer),
-      curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf);
-      return 1;
-  }
-  if (writeInfo || isStarting){
-  log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d %i %i %i",
-      readHeaders,mpegString(mpgtype),layerString(layer),
-      curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf);
-    if (info) delete info;
-    info=new mpegInfo();
-    strcpy(info->mpegVersion,mpegString(mpgtype));
-    info->mpegLayer=4-layer;
-    info->bitRate=curBitrate;
-    info->avrBitrate=curBitrate;
-    info->sampleRate=curSamplingRate;
-    const char *chmodStr=tr("Stereo");
-    switch (chmode) {
-      case 1: chmodStr=tr("JointStereo");break;
-      case 2: chmodStr=tr("Dual");break;
-      case 3: chmodStr=tr("Mono");break;
-    }
-    SNPRINTF(info->info,sizeof(info->info)-1,"%s",chmodStr);
-  }
-       if (isStarting) avrBitrate=curBitrate;
-  isStarting=false;
-  readHeaders++;
-  //moving average F=0.005
-  avrBitrate=avrBitrate+((5*(curBitrate-avrBitrate))/1024);
-  hdrBitrate=curBitrate;
-  hdrFramelen=curFramelen;
-  hdrSamplingRate=curSamplingRate;
-       hasHdrInfo=true;
-  return 0;
-}
-
-int DemuxerAudio::findPTS(UCHAR* buf, int len, ULLONG* dest)
-{
-  //we have no PTS number ...
-  *dest=0;
-  return (findHeader(buf,len) != NULL)?1:0;
-}
-
-bool PacketBuffer::doSkip() {
-       if (!bufferFull()) return false;
-       if (skipfactor == 0) return false;
-       numskip++;
-       if (numskip >= skipfactor) {
-               //sent at least always 2 packets
-               if (numskip > skipfactor) numskip=0;
-               return false;
-       }
-       packetWritten();
-       return true;
-}
-       
-// just handle the real stream without dealing with the header
-int PacketBuffer::putInternal(UCHAR * wbuf, int len,unsigned int &packetnum)
-{
-   /* Important, the type passed to stream must be a mediapacket type as defined in 
-       Draintarget.h and not the device setting of the mvp, so we have to translate it here,
-       in order to get it working on windows
-       --MR */
-  UCHAR mptype=0;
-  switch (streamtype) {
-        case Audio::MPEG1_PES: //?
-        case Audio::MPEG2_PES: //Important, this must be a PES !
-            mptype=MPTYPE_MPEG_AUDIO; break;
-        default:
-        case Audio::MP3: //this can be any Mpeg1 Audio not only layer 3 not packed into PES
-           mptype=MPTYPE_MPEG_AUDIO_LAYER3;break;
-  };
-  if (bufferFull()) {
-#ifndef WIN32
-               if (doSkip()) return 0;//NoSkip on Windows
-#endif
-    //we are still full - so try to write
-    int sent=audio->put(store+bytesWritten,framelen-bytesWritten,/*streamtype*/mptype,packetnum);packetnum++;
-    //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream (still full) pp=%d, framelen=%d, written=%d",sent,partPacket,framelen, bytesWritten );
-    if (sent < (framelen - bytesWritten)) {
-      //packet still not written
-      bytesWritten+=sent;
-      return 0;
-    }
-    packetWritten();
-    //let the demuxer come back with the rest - need to check header first
-    return 0;
-  }
-  if (partPacket+len >= framelen) {
-    //now we have at least a complete packet
-    int bytesConsumed=framelen-partPacket;
-    memcpy(store+partPacket,wbuf,bytesConsumed);
-    partPacket=framelen;
-    //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"stored packet %ld, length %d (last %d) for stream %p",numpackets,framelen,bytesConsumed,audio );
-#ifndef WIN32 //No Skip on Windows
-               if (doSkip()) return bytesConsumed;
-#endif
-    int sent=audio->put(store,framelen,mptype,packetnum);packetnum++;
-    bytesWritten+=sent;
-    //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream",sent );
-    if (bytesWritten < framelen) {
-      //still not completely written
-      return bytesConsumed;
-    }
-    packetWritten();
-    //let the player come back...
-    return bytesConsumed;
-  }
-  //OK packet still not complete
-  if (len == 0) return 0;
-  int bytesConsumed=len;
-  memcpy(store+partPacket,wbuf,bytesConsumed);
-  partPacket+=bytesConsumed;
-  return bytesConsumed;
-}
-
-/**
-  major entry for data from a player
-  the demuxer is either in the state headerSearch (packet written or
-  just at the beginning), writing garbage (inSync=false) or
-  handling data (none set)
-  A header is expected at the first byte after the previous packet -
-  otherwise we switch to garbage where we always search for a header
-  (but anyway provide the data to the underlying device - it's probably
-  more intelligent then we are...
-  We only loose a correct position display.
-  */
-int DemuxerAudio::put(UCHAR* wbuf, int len)
-{
-  //return audiostream.put(wbuf,len,streamtype);
-  int framelen=PACKET_SIZE;
-  UCHAR *hdr;
-  int bytesConsumed=0;
-  int oldBytes=0;
-  if (tmpFill != 0 || (buffer->bufferEmpty() && len < HDRLEN)) {
-    //OK we have to copy everything to the tmp buffer
-    int cp=(UINT)len<(PACKET_SIZE-tmpFill)?(UINT)len:(PACKET_SIZE-tmpFill);
-    memcpy(&tmpBuffer[tmpFill],wbuf,cp);
-    oldBytes=tmpFill;
-    tmpFill+=cp;
-    wbuf=tmpBuffer;
-    len=tmpFill;
-    //if there is no header here and our buffer
-    //is empty - just wait for the next header
-    if (len < HDRLEN && buffer->bufferEmpty()) {
-      log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten);
-      return cp;
-    }
-  }
-  while (bytesConsumed < len ) {
-    if (buffer->bufferFull()) {
-      //if this is the first part of the loop, try to write to the stream
-      if (bytesConsumed == 0) buffer->putInternal(wbuf,0,packetnum);
-      //if the buffer is full, no need to continue
-      if (buffer->bufferFull()) break;
-    }
-    //either we are in a packet (buffer != full && buffer != empty)
-    //or we are searching a header
-    if (buffer->bufferEmpty()) {
-      if (len-bytesConsumed < HDRLEN) {
-        // we cannot  still search
-        if (tmpFill != 0) {
-          //we are already working at the buffer
-          break;
-        }
-        memcpy(tmpBuffer,wbuf,len-bytesConsumed);
-        tmpFill=len-bytesConsumed;
-        log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten);
-        return len;
-      }
-
-      int lastFramelen=hdrFramelen;
-      //if the header has been valid before and we are searching
-      //it should be here
-      int maxsearch=((len-bytesConsumed) < (int)PACKET_SIZE)?len-bytesConsumed:(int)PACKET_SIZE;
-      hdr=findHeader(wbuf,maxsearch);
-      if (hdr != NULL) {
-        //log->log("DemuxerAudio",Log::DEBUG,"header found at offset %d",hdr-wbuf);
-        }
-      //hdr now points to the new header
-      if (hdr !=  wbuf) {
-        //still at least bytes before the header
-        inSync=false;
-        outOfSync++;
-        int garbageBytes=(hdr!=NULL)?(hdr-wbuf):maxsearch;
-        //we consider the garbage now as an own packet
-        //we can consume at most our buffer
-        //basically the buffer should be empty here (we are
-        //in header search - and we fill up each garbage
-
-        int nframesize=garbageBytes;
-        if (nframesize > (int)PACKET_SIZE) {
-          nframesize=(int)PACKET_SIZE;
-        }
-        if (! buffer->bufferEmpty()) {
-           log->log("DemuxerAudio",Log::WARN,"buffer not empty when having garbage to store");
-           //at the end no big problem, we only write the remaining bytes that we have...
-        }
-        else {
-          buffer->setFramelen(nframesize);
-        }
-        log->log("DemuxerAudio",Log::DEBUG,"garbage found at packet %ld (bytes %ld) of length %d, "
-            "framelen set to %d (last fl=%d)",
-            readHeaders,globalBytesWritten,garbageBytes,buffer->getFramelen(),lastFramelen);
-#ifndef WIN32        
-        //hmm - we assume that he low level driver is more intelligent
-        //and give him the data "as is"
-        int written=buffer->putInternal(wbuf,garbageBytes,packetnum);
-        globalBytesWritten+=written;
-        bytesConsumed+=written;
-        if (written != garbageBytes || hdr == NULL ) {
-          break;
-        }
-#else //DS is not intelligent
-        globalBytesWritten+=garbageBytes;
-        bytesConsumed+=garbageBytes;
-#endif
-        //OK either all the "garbage" is written  or
-        //we found the next header as expected
-        //continue with the next package
-        wbuf=hdr;
-      }
-      //we have to wait now until the buffer is 
-      //free for the next package
-      if ( ! buffer->bufferEmpty()) return bytesConsumed;
-      //this is the place where we start a new packet
-      framelen=hdrFramelen;
-      if ( !buffer->setFramelen(framelen) ) {
-        log->log("DemuxerAudio",Log::DEBUG,"unable to set framelen should=%d, current=%d",
-            framelen,buffer->getFramelen());
-            }
-      inSync=true;
-    }
-    //now we are surely within a packet
-    int written=buffer->putInternal(wbuf,len-bytesConsumed,packetnum);
-    //update the status
-    globalBytesWritten+=written;
-    wbuf+=written;
-    bytesConsumed+=written;
-    if (written == 0) {
-      //stream is full
-      break;
-    }
-    //OK - handle the rest
-  }
-  if (bytesConsumed >= oldBytes) {
-    //if we consumed more than the old bytes - OK the buffer
-    //can be thrown away
-    tmpFill=0;
-    return bytesConsumed-oldBytes;
-  }
-  else {
-    //only consumed bytes from the buffer
-    if (bytesConsumed == 0) {
-      //restore the buffer
-      tmpFill=oldBytes;
-      return 0;
-    }
-    //shift bytes in buffer
-    for (int i=0;i<oldBytes-bytesConsumed;i++) {
-      tmpBuffer[i]=tmpBuffer[i+bytesConsumed];
-    }
-    tmpFill=oldBytes-bytesConsumed;
-    return 0;
-  }
-}
-
-//info functions
-const id3_tag * DemuxerAudio::getId3Tag() {
-  return id3;
-
-}
-const DemuxerAudio::mpegInfo * DemuxerAudio::getMpegInfo() {
-  if (! hasHdrInfo) return NULL;
-       info->avrBitrate=avrBitrate;
-       info->bitRate=hdrBitrate;
-  return info;
-}
-
-const DemuxerAudio::vbrInfo * DemuxerAudio::getVBRINfo() {
-       return vbr;
-}
-
-int DemuxerAudio::checkStart(UCHAR *b, int len) {
-  UCHAR *start=b;
-  int id3len=parseID3V2(b,len);
-  if (id3len > 0) {
-    char * str=id3->toString();
-    log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 %d bytes of %d",id3len,len);
-    log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 found:%s",str);
-    delete str;
-    b+=id3len;
-    len-=id3len;
-  }
-       int vbrlen=parseVBR(b,len);
-       if (vbrlen > 0 ) {
-               hasVBRInfo=true;
-               b+=vbrlen;
-               len-=vbrlen;
-       }
-  UCHAR * hdr=findHeader(b,len,true);
-  if (hdr == NULL) return -1;
-  return hdr-start;
-}
-
-int DemuxerAudio::checkID3(UCHAR *b, int len) {
-  if (len != 128) return -1;
-  int rt=parseID3V1(b,len);
-  if (rt >= 0) {
-    char * str=id3->toString();
-    log->log("DemuxerAudio",Log::DEBUG,"parseID3V1 found:%s",str);
-    delete str;
-  }
-  return rt;
-}
-
-bool DemuxerAudio::isSync() {
-  return inSync;
-}
-
-UINT DemuxerAudio::getSyncErrors() {
-  return outOfSync;
-}
-
-ULONG DemuxerAudio::getBytesPerSecond()
-{
-  ULONG bps=hdrBitrate;
-  if (! hasHdrInfo) return 0;
-  if (hdrBitrate != avrBitrate) {
-    //we seem to have vbr
-    if (hasVBRInfo) {
-      //vbr stuff TODO
-      bps=avrBitrate;
-    }
-    else {
-      //some guessing
-      bps=avrBitrate;
-    }
-  }
-  bps=bps/8;
-  return bps;
-}
-
-ULONG DemuxerAudio::getSecondsFromLen(ULONG len) {
-  if (! hasHdrInfo) return 0;
-       if (vbr) {
-               //first find the index where we are between
-               //rough starting point:
-               ULONG idx=100*len/vbr->numBytes;
-               if (idx >= 100) idx=99;
-               ULONG idxPos=(vbr->table[idx]) * vbr->numBytes/256;
-               ULONG pbefore=idxPos;
-               ULONG pafter=idxPos;
-               //OK now we know whether we have to go up or down
-               if (idxPos > len) {
-                       //down
-                       while (idxPos > len && idx > 0) {
-                               pafter=idxPos;
-                               idx--;
-                               idxPos=(vbr->table[idx]) * vbr->numBytes/256;
-                               pbefore=idxPos;
-                       }
-                       //OK we are now before our postion
-               }
-               else {
-                       //up
-                       while (idxPos < len && idx < 100 ) {
-                               pbefore=idxPos;
-                               idx++;
-                               idxPos=(vbr->table[idx]) * vbr->numBytes/256;
-                               pafter=idxPos;
-                       }
-                       //after our position
-                       if (idx > 0) idx --;
-               }
-               //idx is now the index before our position
-               //approximate between the 2 points
-               ULONG idxTime=idx * vbr->fileSeconds/100;
-               if (pafter == pbefore) return idxTime;
-               ULONG rt=idxTime+ (len-pbefore)* vbr->fileSeconds/(100 * (pafter-pbefore)) ;
-               if (rt > vbr -> fileSeconds) return vbr->fileSeconds;
-               if (rt < idxTime) return idxTime;
-               return rt;
-       }
-       else {
-               ULONG bps=getBytesPerSecond();
-               if (bps == 0) return 0;
-               return len/bps;
-       }
-}
-  
-ULONG DemuxerAudio::positionFromSeconds(ULONG seconds) {
-  if (! hasHdrInfo) return 0;
-       if (vbr) {
-               ULONG idx=seconds*100/vbr->fileSeconds;
-               if (idx > 99) idx=99;
-               ULONG idxPos=vbr->table[idx] * vbr->numBytes/256;
-               ULONG idx2=idx;
-               if (idx < 99) idx2++;
-               ULONG nextPos=vbr->table[idx] * vbr->numBytes/256;
-               ULONG rt=idxPos+(nextPos-idxPos) * (seconds - idx * vbr->fileSeconds /256);
-               if (rt < idxPos) return idxPos;
-               if ( rt > vbr->numBytes) return vbr->numBytes;
-               return rt;
-       }
-       else {
-               ULONG bps=getBytesPerSecond();
-               return bps*seconds;
-       }
-}
-
-int id3_tag::stringlen(bool withTitle) const {
-       if (!withTitle)
-   return strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+
-    strlen(track)+strlen(composer)+strlen(comment)+8+3+
-    90; //30 chars for each name...
-       else
-   return strlen(title)+strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+
-    strlen(track)+strlen(composer)+strlen(comment)+8+3+
-    120; //30 chars for each name...
-}
-//create a string out of the id3 tag info
-//delete this string afterwards if you did not provide the buffer
-char * id3_tag::toString(char *b, int len, bool withTitle) const {
-  const char *ta=tr("Artist");
-//char *tg=tr("Genre");
-//char *ty=tr("Year");
-  const char *tx=tr("Album");
-//char *to=tr("Composer");
-//char *tc=tr("Comment");
-  const char *tn=tr("Track");
-  /* in the moment:
-     Title: 
-     Artist:
-     Album: year - name
-     Track:
-     */
-  if (b == NULL) {
-    len=stringlen(withTitle);
-    b=new char[len];
-  }
-       const char * del=" - ";
-       if (strlen(year) == 0) del="";
-       if (withTitle){
- const char *tt=tr("Title");
-               SNPRINTF(b,len-1,"%s: %s\n%s: %s\n%s: %s%s%s\n%s: %s",
-                               tt,title,ta,artist,tx,year,del,album,tn,track);
-       }
-       else {
-SNPRINTF(b,len-1,"%s: %s\n%s: %s%s%s\n%s: %s",
-                               ta,artist,tx,year,del,album,tn,track);
-       }
-  b[len-1]=0;
-  return b;
-}
-
-void DemuxerAudio::setSkipFactor(int factor) {
-       Log::getInstance()->log("DemuxerAudio",Log::DEBUG,"set skipfactor %d\n",factor);
-       buffer->setSkipFactor(factor);
-}
-
+/*\r
+    Copyright 2006 Mark Calderbank, Andreas Vogel\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "demuxeraudio.h"\r
+#include "audio.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+\r
+#define HDRBYTE1 0xff\r
+#define HDRBYTE2 0xe0\r
+#define HDRBYTE2MASK 0xe0\r
+\r
+\r
+\r
+class PacketBuffer {\r
+  \r
+  public:\r
+    PacketBuffer(Stream *as,UCHAR strtype) {\r
+      log=Log::getInstance();\r
+      audio=as;\r
+      streamtype=strtype;\r
+      newStream();\r
+    }\r
+    //just handle the data (do not deal with headers)\r
+    int putInternal(UCHAR* buf,int len,unsigned int &packetnum);\r
+    void reset(){\r
+      partPacket=0;\r
+      bytesWritten=0;\r
+      framelen=DemuxerAudio::PACKET_SIZE;\r
+    }\r
+    void newStream() {\r
+      reset();\r
+      numpackets=0;\r
+      numbytes=0;\r
+                       skipfactor=0;\r
+                       numskip=0;\r
+    }\r
+    bool bufferFull() {\r
+      return (partPacket>=framelen);\r
+    }\r
+    //can we write a new packet?\r
+    bool bufferEmpty() {\r
+      return partPacket==0;\r
+    }\r
+    //only set this, if buffer empty\r
+    //otherwise ignored!\r
+    bool setFramelen(int len) {\r
+      if (! bufferEmpty() ) return false;\r
+      if (len > (int)DemuxerAudio::PACKET_SIZE) return false;\r
+      framelen=len;\r
+      return true;\r
+    }\r
+    //how much bytes do we need to fill the packet?\r
+    int bytesMissing() {\r
+      return framelen-partPacket;\r
+    }\r
+    int getFramelen() {\r
+      return framelen;\r
+    }\r
+               void setSkipFactor(int factor) {\r
+                       skipfactor=factor;\r
+                       numskip=0;\r
+               }\r
+  private:\r
+    void packetWritten() {\r
+      numbytes+=framelen;\r
+      //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written packet %ld l=%d, bytes %ld",numpackets,framelen,numbytes);\r
+      numpackets++;\r
+      reset();\r
+    }\r
+               bool doSkip();\r
+    UCHAR store[DemuxerAudio::PACKET_SIZE]; // Storage for partial packets\r
+    int partPacket;    // Length of partial packet stored from previous put()\r
+    int bytesWritten;  //if they are !=0 and != framelength the stream is full...\r
+    int framelen;\r
+    Log * log;\r
+    Stream * audio;\r
+    UCHAR streamtype;\r
+    //global counters\r
+    ULONG numpackets;\r
+    ULONG numbytes;\r
+               int skipfactor;\r
+               int numskip;\r
+};\r
+\r
+\r
+DemuxerAudio::DemuxerAudio(int p_vID, int p_aID)\r
+{\r
+  inSync=false;\r
+  isStarting=true;\r
+  log=Log::getInstance();\r
+  readHeaders=0;\r
+  streamtype=Audio::MP3;\r
+  buffer=new PacketBuffer(&audiostream,streamtype);\r
+//  buffer=new PacketBuffer(&teststream,streamtype);\r
+  globalBytesWritten=0;\r
+  packetnum=0;\r
+  id3=NULL;\r
+  info=NULL;\r
+       vbr=NULL;\r
+  reset();\r
+}\r
+\r
+DemuxerAudio::~DemuxerAudio() {\r
+  delete buffer;\r
+  if(info) delete info;\r
+  if(id3) delete id3;\r
+       if (vbr) delete vbr;\r
+}\r
+\r
+void DemuxerAudio::flush()\r
+{\r
+  Demuxer::flushAudio();\r
+  buffer->newStream();\r
+  tmpFill=0;\r
+}\r
+\r
+void DemuxerAudio::reset() {\r
+  buffer->newStream();\r
+  tmpFill=0;\r
+  readHeaders=0;\r
+  packetnum=0;\r
+  outOfSync=0;\r
+  globalBytesWritten=0;\r
+  if (id3) delete id3;\r
+  id3=NULL;\r
+  if (info) delete info;\r
+  info=NULL;\r
+       if (vbr) delete vbr;\r
+       vbr=NULL;\r
+  inSync=false;\r
+  hasHdrInfo=false;\r
+  hasVBRInfo=false;\r
+  isStarting=true;\r
+  hdrBitrate=128000;\r
+  hdrSamplingRate=44100;\r
+  avrBitrate=0;\r
+  hdrFramelen=0;\r
+  isStarting=true;\r
+}\r
+\r
+int DemuxerAudio::scan(UCHAR *buf, int len)\r
+{\r
+  //no differend pids here\r
+  return 0;\r
+}\r
+\r
+void DemuxerAudio::setVID(int p_vID)\r
+{\r
+}\r
+\r
+void DemuxerAudio::setAID(int p_aID,int type)\r
+{\r
+}\r
+\r
+static const char * id3_1_genre[] = {\r
+  "Blueshhh",\r
+  "Classic Rock",\r
+  "Country",\r
+  "Dance",\r
+  "Disco",\r
+  "Funk",\r
+  "Grunge",\r
+  "Hip-Hop",\r
+  "Jazz",\r
+  "Metal",\r
+  "New Age",\r
+  "Oldies",\r
+  "Other",\r
+  "Pop",\r
+  "R&B",\r
+  "Rap",\r
+  "Reggae",\r
+  "Rock",\r
+  "Techno",\r
+  "Industrial",\r
+  "Alternative",\r
+  "Ska",\r
+  "Death Metal",\r
+  "Pranks",\r
+  "Soundtrack",\r
+  "Euro-Techno",\r
+  "Ambient",\r
+  "Trip-Hop",\r
+  "Vocal",\r
+  "Jazz+Funk",\r
+  "Fusion",\r
+  "Trance",\r
+  "Classical",\r
+  "Instrumental",\r
+  "Acid",\r
+  "House",\r
+  "Game",\r
+  "Sound Clip",\r
+  "Gospel",\r
+  "Noise",\r
+  "AlternRock",\r
+  "Bass",\r
+  "Soul",\r
+  "Punk",\r
+  "Space",\r
+  "Meditative",\r
+  "Instrumental Pop",\r
+  "Instrumental Rock",\r
+  "Ethnic",\r
+  "Gothic",\r
+  "Darkwave",\r
+  "Techno-Industrial",\r
+  "Electronic",\r
+  "Pop-Folk",\r
+  "Eurodance",\r
+  "Dream",\r
+  "Southern Rock",\r
+  "Comedy",\r
+  "Cult",\r
+  "Gangsta",\r
+  "Top 40",\r
+  "Christian Rap",\r
+  "Pop/Funk",\r
+  "Jungle",\r
+  "Native American",\r
+  "Cabaret",\r
+  "New Wave",\r
+  "Psychadelic",\r
+  "Rave",\r
+  "Showtunes",\r
+  "Trailer",\r
+  "Lo-Fi",\r
+  "Tribal",\r
+  "Acid Punk",\r
+  "Acid Jazz",\r
+  "Polka",\r
+  "Retro",\r
+  "Musical",\r
+  "Rock & Roll",\r
+  "Hard Rock"\r
+};\r
+\r
+\r
+\r
+static int bitrateTable[16][5]={\r
+/*        L1,L2,L3,2L1,2L2 */\r
+/*0000*/ {-1,-1,-1,-1,-1},\r
+/*0001*/ {32,32,32,32,8},\r
+/*0010*/ {64,48,40,48,16},\r
+/*0011*/ {96,56,48,56,24},\r
+/*0100*/ {128,64,56,64,32},\r
+/*0101*/ {160,80,64,80,40},\r
+/*0110*/ {192,96,80,96,48},\r
+/*0111*/ {224,112,96,112,56},\r
+/*1000*/ {256,128,112,128,64},\r
+/*1001*/ {288,160,128,144,80},\r
+/*1010*/ {320,192,160,160,96},\r
+/*1011*/ {352,224,192,176,112},\r
+/*1100*/ {384,256,224,192,128},\r
+/*1101*/ {416,320,256,224,144},\r
+/*1110*/ {448,384,320,256,160},\r
+/*1111*/ {-1,-1,-1,-1,-1} };\r
+\r
+static int  samplingRateTable[4][3]={\r
+/*00*/ {44100,22050,11025},\r
+/*01*/ {48000,24000,12000},\r
+/*10*/ {32000,16000,8000},\r
+/*11*/ {-1,-1,-1}};\r
+\r
+//max 7 char!\r
+static const char * mpegString(UCHAR code) {\r
+  switch(code) {\r
+    case 0:\r
+      return "MPEG2.5";\r
+    case 1:\r
+      return "RESERV";\r
+    case 2:\r
+      return "MPEG 2";\r
+    case 3:\r
+      return "MPEG 1";\r
+  }\r
+  return "UNKNOWN";\r
+}\r
+\r
+static const char * layerString(UCHAR code) {\r
+  switch(code) {\r
+    case 0:\r
+      return "Layer reserved";\r
+    case 1:\r
+      return "Layer III";\r
+    case 2:\r
+      return "Layer II";\r
+    case 3:\r
+      return "Layer I";\r
+  }\r
+  return "Layer UNKNOWN";\r
+}\r
+/**\r
+  * parse an id3 Header\r
+  * provided by Brian Walton\r
+  * @returns -1 of nothing found\r
+  */\r
+  \r
+int DemuxerAudio::id3_2_3_FrameParse(unsigned char buf[], id3_frame *frame)\r
+{\r
+  if (buf[0] < 0x20 || buf[1] < 0x20 || buf [2] < 0x20 ) return -1;\r
+  frame->size = (buf[4] & 0x7F) << 21 | (buf[5] & 0x7F) << 14 |  (buf[6] & 0x7F) << 7 | (buf[7] & 0x7F);\r
+  if (frame->size == 0) return -1;\r
+  //TODO. clearify flags against:\r
+  //http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b\r
+  frame->flags.tagAlterPreserv = (buf[8] & 0x80) >> 7;\r
+  frame->flags.filelterPreserv = (buf[8] & 0x40) >> 6;\r
+  frame->flags.readOnly = (buf[8] & 0x20) >> 5;\r
+  frame->flags.groupId = (buf[9] & 0x20) >> 5;\r
+  frame->flags.compression = (buf[9] & 0x80) >> 7;\r
+  frame->flags.encryption = (buf[9] & 0x40) >> 6;\r
+  frame->flags.unsync = 0;\r
+  frame->flags.dataLen = 0;\r
+  return 0;\r
+}\r
+\r
+ /**\r
+  * parse an id3 Header\r
+  * provided by Brian Walton\r
+  * @returns -1 of nothing found\r
+  */\r
+  \r
+int DemuxerAudio::id3_2_2_FrameParse(unsigned char buf[], id3_frame *frame)\r
+{\r
+  if (buf[0] < 0x20 || buf[1] < 0x20 || buf[2] < 0x20) return -1;\r
+  frame->size = (buf[3] & 0x7F) << 14 |  (buf[4] & 0x7F) << 7 | (buf[5] & 0x7F);\r
+  if (frame->size == 0) return -1;\r
+  return 0;\r
+}\r
+\r
+\r
+//fill an id3tag from a frame payload\r
+//http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b\r
+//http://id3.org/id3v2-00\r
+static struct tagid {\r
+  const char * bytes;\r
+  int index;\r
+} knownFrames[]= {\r
+  //ID3V2.3\r
+  {"TIT2",1}, //title\r
+  {"TPE1",2}, //artist\r
+  {"TCON",3}, //genre\r
+  {"TRCK",6}, //track\r
+  {"TYER",4}, //year\r
+  {"TALB",5}, //album\r
+  {"TCOM",7}, //composer\r
+  {"COMM",8}, //comment\r
+              //Text encoding           $xx\r
+              //Language                $xx xx xx\r
+              //Short content descrip.  <text string according to encoding> $00 (00)\r
+              //The actual text         <full text string according to encoding>\r
+  //ID3V2.0\r
+  {"TT2",1 },\r
+  {"TP1",2 },\r
+  {"TCM",7 },\r
+  {"TCO",3 }, //(genreNumber)\r
+  {"TAL",5 },\r
+  {"TRK",6 },\r
+  {"TYE",4 },\r
+  {"COM",8 }\r
+};\r
+#define NUMKNOWN (sizeof(knownFrames)/sizeof(knownFrames[0]))\r
+\r
+/*fill in infos\r
+  from an ID3 V2.x, V2.3 frame into the tags structure\r
+  frameData must point to the header\r
+  framelen is the len without header (10 Bytes for V23, 6 Bytes for v2x)\r
+  */\r
+\r
+#define MAXLEN(tagtype) ((UINT)frameLen<sizeof(tag->tagtype)-1?(UINT)frameLen:sizeof(tag->tagtype)-1)\r
+bool DemuxerAudio::fillId3Tag(id3_tag * tag,UCHAR * frameData, int frameLen, int dataOffset, bool v23) {\r
+  int tl=v23?4:3;\r
+  int tagIndex=-1;\r
+  if (tag == NULL) return false;\r
+  if (frameLen < 2) return false;\r
+  for (UINT i=0;i< NUMKNOWN;i++) {\r
+    if(strncmp((char *)frameData,knownFrames[i].bytes,tl) == 0) {\r
+      tagIndex=knownFrames[i].index;\r
+      break;\r
+    }\r
+  }\r
+  if (tagIndex < 0) return false;\r
+  UCHAR encoding=*(frameData+dataOffset);\r
+  dataOffset++;\r
+  frameLen--;\r
+  if (encoding != 0) {\r
+    log->log("DemuxerAudio",Log::DEBUG,"unknown encoding for tag %d, tagid %s",encoding,\r
+        knownFrames[tagIndex].bytes);\r
+    return false;\r
+  }\r
+  switch(tagIndex) {\r
+    case 1:  //title\r
+      strncpy(tag->title,(char*)(frameData+dataOffset),MAXLEN(title));\r
+      tag->title[MAXLEN(title)]=0;\r
+      break;\r
+    case 2:  //artist\r
+      strncpy(tag->artist,(char*)(frameData+dataOffset),MAXLEN(artist));\r
+      tag->artist[MAXLEN(artist)]=0;\r
+      break;\r
+    case 3:  //genre\r
+      {\r
+      UCHAR * st=frameData+dataOffset;\r
+      int genre=0;\r
+      if (*st=='(') {\r
+        genre=atoi((const char *)(st+1)) && 31;\r
+        st=(UCHAR *)id3_1_genre[genre];\r
+      }\r
+      strncpy(tag->genre,(char*)st,MAXLEN(genre));\r
+      tag->genre[MAXLEN(genre)]=0;\r
+      break;\r
+      }\r
+    case 4:  //year\r
+      strncpy(tag->year,(char *)(frameData+dataOffset),MAXLEN(year));\r
+      tag->year[MAXLEN(year)]=0;\r
+      break;\r
+    case 5:  //album\r
+      strncpy(tag->album,(char *)(frameData+dataOffset),MAXLEN(album));\r
+      tag->album[MAXLEN(album)]=0;\r
+      break;\r
+    case 6:  //track\r
+      strncpy(tag->track,(char *)(frameData+dataOffset),MAXLEN(track));\r
+      tag->track[MAXLEN(track)]=0;\r
+      break;\r
+    case 7:  //composer\r
+      strncpy(tag->composer,(char *)(frameData+dataOffset),MAXLEN(composer));\r
+      tag->composer[MAXLEN(composer)]=0;\r
+      break;\r
+    case 8:  //comment\r
+      strncpy(tag->comment,(char *)(frameData+dataOffset),MAXLEN(comment));\r
+      tag->comment[MAXLEN(comment)]=0;\r
+      break;\r
+    default:\r
+      return false;\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+/**\r
+  * parse an id3 Header\r
+  * based on code provided by Brian Walton\r
+  * @returns -1 of nothing found\r
+  *  otherwise the id3 info is filled\r
+  */\r
+\r
+int DemuxerAudio::parseID3V2(UCHAR *data, int len) {\r
+  int debug=0;\r
+  UCHAR * start=data;\r
+  id3_header id3header;\r
+  id3_frame id3frame;\r
+  id3_tag * id3tag=NULL;\r
+  //len = read(fd, data, 10);\r
+  if (len < 10) {\r
+    delete id3tag;\r
+    return -1;\r
+  }\r
+  len-=10;\r
+  if(data[0]=='I' && data[1]=='D' && data[2]=='3')\r
+  {\r
+    id3tag=new id3_tag();\r
+    id3header.major = data[3];\r
+    id3header.minor = data[4];\r
+    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 V2.%d.%d found\n", id3header.major, id3header.minor);\r
+    id3header.flags.unsynchronisation = (data[5] & 0x80)>>7;\r
+    id3header.flags.extended_header = (data[5] & 0x40)>>6;\r
+    id3header.flags.experimental = (data[5] & 0x20)>>5;\r
+    id3header.flags.footer = (data[5] & 0x10)>>4;\r
+    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Unsynchronisation flag: %d\n", id3header.flags.unsynchronisation);\r
+    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header flag: %d\n", id3header.flags.extended_header);\r
+    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Experimental indicator flag: %d\n", id3header.flags.experimental);\r
+    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Footer present flag: %d\n", id3header.flags.footer);\r
+    id3header.size = (data[6] & 0x7F) << 21 | (data[7] & 0x7F) << 14 |  (data[8] & 0x7F) << 7 | (data[9] & 0x7F);\r
+    if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 Size: %d\n", id3header.size);\r
+    data=start+10;\r
+    if (len <= id3header.size) {\r
+      if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"header size to big %d, only %d bytes available\n",id3header.size,len);\r
+      delete id3tag;\r
+      return -1;\r
+    }\r
+    if (id3header.flags.extended_header)\r
+    {\r
+      int extended_hdr_hdr=4;  //still to be discussed (id3.org...)\r
+      //read extended header size\r
+      if (len < extended_hdr_hdr) {\r
+        if (debug) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended header found but cannot read\n");\r
+        delete id3tag;\r
+        return -1;\r
+      }\r
+      if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"remaining %d chars after extended hdr hdr\n", len);\r
+      id3header.extended_header.size = (data[0] & 0x7F) << 21 | (data[1] & 0x7F) << 14 |  (data[2] & 0x7F) << 7 | (data[3] & 0x7F);\r
+      if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header size: %d\n", id3header.extended_header.size);\r
+      if (len <= id3header.extended_header.size+extended_hdr_hdr) {\r
+      if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended Header to big, only %d bytes available\n",len);\r
+        delete id3tag;\r
+        return -1;\r
+      }\r
+      //lseek(fd, id3header.extended_header.size - 6, SEEK_CUR);\r
+      data+=id3header.extended_header.size+extended_hdr_hdr;\r
+      len-=id3header.extended_header.size+extended_hdr_hdr;\r
+    }\r
+    //set the end of the header\r
+    UCHAR * eob=start+id3header.size+10;\r
+    bool readNext=true;\r
+    while (data < eob && readNext)\r
+    {\r
+      //skip over some padding - found this in lame MCDI tag...\r
+      if (*data == 0) {\r
+        data++;\r
+        continue;\r
+      }\r
+      readNext=false;\r
+      switch(id3header.major)\r
+      {\r
+        case 2: //ID3 V2.2.x\r
+          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.2 frame, %d : %c %c %c\n", data-start,*data,*(data+1),*(data+2));\r
+          if (data + 6 >= eob)\r
+          {\r
+            break;\r
+          }\r
+          if (id3_2_2_FrameParse(data, &id3frame) < 0)\r
+          {\r
+            break;\r
+          }\r
+          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame size: %d\n", id3frame.size);\r
+          fillId3Tag(id3tag,data,id3frame.size,6,false);\r
+          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + 6 +1);\r
+          data+=6+id3frame.size;\r
+          readNext=true;\r
+          break;\r
+        case 3: //ID3 V2.3.x\r
+          {\r
+          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.3 frame, %d : %c %c %c %c\n", data-start,\r
+              *data,*(data+1),*(data+2),*(data+3));\r
+          if (data + 10 >= eob)\r
+          {\r
+            break;\r
+          }\r
+          if (id3_2_3_FrameParse(data, &id3frame) <0)\r
+          {\r
+            break;\r
+          }\r
+          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame size: %d\n", id3frame.size);\r
+          int dataOffset=10;\r
+          if (id3frame.flags.groupId)\r
+          {\r
+            dataOffset++;\r
+            if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame group: %d\n", data[dataOffset]);\r
+          }\r
+          if (id3frame.flags.compression)\r
+          {\r
+            if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame compressed: %d\n", id3frame.flags.compression);\r
+          }\r
+          if (id3frame.flags.encryption)\r
+          {\r
+            dataOffset+=1;\r
+            if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame encryption method: %d\n", data[dataOffset]);\r
+          }\r
+          fillId3Tag(id3tag,data,id3frame.size-dataOffset+10,dataOffset,true);\r
+          if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + dataOffset +1);\r
+          data+=10+id3frame.size;\r
+          readNext=true;\r
+          break;\r
+          }\r
+        default:\r
+          //don't support this version\r
+          delete id3tag;\r
+          return -1;\r
+      }\r
+    }\r
+\r
+    data=eob;\r
+    //store the found tag\r
+    if (id3) delete id3;\r
+    id3=id3tag;\r
+    return data-start;\r
+  }\r
+  return -1;\r
+}\r
+\r
+/**\r
+  * parse an id3v1 Header\r
+  * based on code provided by Brian Walton\r
+  * @returns -1 of nothing found\r
+  *  otherwise the id3 info is filled\r
+  */\r
+#define MEMCPY(type,len,offset) {int type##max=sizeof(tag->type)-1<len?sizeof(tag->type)-1:len;strncpy(tag->type,(char*)&data[offset],type##max);tag->type[type##max]=0;}\r
+\r
+int DemuxerAudio::parseID3V1(UCHAR *data, int len) {\r
+  int debug=1;\r
+  if (len < 128) return -1;\r
+  if(data[0]=='T' && data[1]=='A' && data[2]=='G')\r
+  {\r
+    id3_tag * tag=new id3_tag();\r
+    if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1 tag found\n");\r
+    MEMCPY(title,30,3);\r
+    MEMCPY(artist,30,33);\r
+    MEMCPY(album,30,63);\r
+    MEMCPY(year,4,93);\r
+    if (data[125]==0 && data[126]!=0)\r
+    { //ID3 V1.1\r
+      if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.1 tag\n");\r
+      MEMCPY(comment,29,97);\r
+      sprintf(tag->track, "%d", data[126]);\r
+    } else {\r
+      if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.0 tag\n");\r
+      MEMCPY(comment,30,97);\r
+    }\r
+    if (data[127] < sizeof(id3_1_genre)/sizeof(id3_1_genre[0]))\r
+    {\r
+      sprintf(tag->genre, id3_1_genre[data[127]]);\r
+    }\r
+    if (id3) delete id3;\r
+    id3=tag;\r
+    return 0;\r
+  }\r
+  return -1;\r
+}\r
+\r
+//infos from http://www.multiweb.cz/twoinches/MP3inside.htm\r
+int DemuxerAudio::parseVBR(UCHAR *data, int len) {\r
+       UCHAR *hdr=findHeader(data,len);\r
+       //we expect the header exactly here\r
+       if (hdr != data) return -1;\r
+       const static char * VBRHDR="Xing";\r
+       int vbridpos=36;\r
+  UCHAR mpgtype=(data[1] & 0x18)>>3;\r
+  UCHAR chmode=(data[2] & 0xc0) >> 6;\r
+  UCHAR layer=(data[2] & 0x06) >>1;\r
+       if ( mpgtype == 3 && chmode == 11) vbridpos=21;\r
+       if ( mpgtype != 3 && chmode != 11) vbridpos=21;\r
+       if ( mpgtype != 3 && chmode == 11) vbridpos=13;\r
+       //check for the header ID\r
+       if (vbridpos+(int)strlen(VBRHDR)+4 >= len) {\r
+               Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header %d",len);\r
+               return -1;\r
+       }\r
+       for (int i=4;i<vbridpos;i++) {\r
+               if (data[i] != 0) {\r
+                 Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"garbage when searching VBR header at pos %d",i);\r
+                       return -1;\r
+               }\r
+       }\r
+       if ( strncmp((char *)&data[vbridpos],VBRHDR,strlen(VBRHDR)) != 0) {\r
+               Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"no VBR header at pos %d",vbridpos);\r
+               return -1;\r
+       }\r
+       int framedata=vbridpos+strlen(VBRHDR);\r
+       int expectedLen=0;\r
+       //OK we should now have a valid vbr header\r
+       bool hasFramenum=data[framedata+3] & 1;\r
+       bool hasBytes=data[framedata+3] & 0x2;\r
+       bool hasTOC=data[framedata+3] & 0x4;\r
+       expectedLen+=8;\r
+       if (hasTOC) expectedLen+=100;\r
+       if (framedata+expectedLen > len) {\r
+               Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header data %d, expected %d",\r
+                               len,framedata+expectedLen);\r
+               return -1;\r
+       }\r
+       if (!hasFramenum || ! hasBytes || ! hasTOC) {\r
+               //not usefull for us..\r
+               Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"not all parts in VBR header - ignore");\r
+               return -1;\r
+       }\r
+       framedata+=4;\r
+       if (vbr) delete vbr;\r
+       vbr=new vbrInfo();\r
+       vbr->numFrames=data[framedata] << 24 | data[framedata+1]<<16|\r
+                       data[framedata+2]<<8 |data[framedata+3];\r
+       framedata+=4;\r
+       vbr->numBytes=data[framedata] << 24 | data[framedata+1]<<16|\r
+                       data[framedata+2]<<8 |data[framedata+3];\r
+       framedata+=4;\r
+       for (int ti=0;ti<100;ti++) {\r
+               vbr->table[ti]=data[framedata+ti];\r
+       }\r
+       //compute file size in seconds\r
+       //should be (#of frames -1) *samplesPerFrame / sampleRate\r
+       //TODO: difference for Mono?\r
+       ULONG samplesPerFrame=384; //layer1\r
+       if (layer != 3) samplesPerFrame=1152;\r
+       vbr->fileSeconds=(vbr->numFrames-1)*samplesPerFrame/hdrSamplingRate;\r
+       Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"successfully read VBR %ldbytes, %ld frames, %ldsec",\r
+                       vbr->numBytes,vbr->numFrames,vbr->fileSeconds);\r
+       return hdrFramelen;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+UCHAR * DemuxerAudio::findHeader(UCHAR *buf, int len, bool writeInfo) {\r
+  while (len >= 3) //assume hdr+crc\r
+  {\r
+    UCHAR pattern=*buf;\r
+    buf++; len--;\r
+    if (pattern != HDRBYTE1 ) continue;\r
+    if ((*buf & HDRBYTE2MASK) != HDRBYTE2) continue;\r
+    if (readHeader((buf-1),4,writeInfo) != 0) continue;\r
+    return buf-1;\r
+  }\r
+  return NULL;\r
+}\r
+\r
+\r
+\r
+int DemuxerAudio::readHeader(UCHAR * hbuf,int len,bool writeInfo) {\r
+  int curFramelen=0;\r
+  int curBitrate=0;\r
+  int curSamplingRate=0;\r
+  if (*hbuf != HDRBYTE1) return -1;\r
+  hbuf++;\r
+  if ((*hbuf & HDRBYTE2MASK) != HDRBYTE2) return -1;\r
+  UCHAR mpgtype=(*hbuf & 0x18)>>3;\r
+  if (mpgtype == 1) {\r
+    log->log("DemuxerAudio",Log::DEBUG,"header invalid mpgtype %s %i %i %i",\r
+        mpegString(mpgtype),*hbuf,*(hbuf+1),*(hbuf+2));\r
+    return 1;\r
+  }\r
+  UCHAR layer=(*hbuf & 0x06) >>1;\r
+  //bool hasCRC=!(*hbuf & 1);\r
+  hbuf++;\r
+  UCHAR bitrateCode=(*hbuf & 0xf0) >>4;\r
+  UCHAR samplingCode=(*hbuf & 0x0c) >> 2;\r
+  bool padding=*hbuf & 0x02;\r
+  hbuf++;\r
+  //0 Stereo, 1 JointStereo, 2 Dual, 3 Mono\r
+  UCHAR chmode=(*hbuf & 0xc0) >> 6;\r
+  //UCHAR extension=(*hbuf & 0x30) >> 4;\r
+\r
+  //layercode: 1-L3, 2-L2, 3-L1\r
+  //columns 0,1,2 for MPEG1\r
+  UCHAR bitrateColumn=3-layer;\r
+  if (bitrateColumn > 2) {\r
+    log->log("DemuxerAudio",Log::DEBUG,"header invalid layer %s %i %i %i",\r
+        layerString(layer),*(hbuf-2),*(hbuf-1),*hbuf);\r
+    return 1;\r
+  }\r
+  if (mpgtype != 3) bitrateColumn+=3;\r
+  if (bitrateColumn>4) bitrateColumn=4;\r
+  curBitrate=1000*bitrateTable[bitrateCode][bitrateColumn];\r
+  UCHAR sampleRateColumn=0;\r
+  if (mpgtype == 10) sampleRateColumn=1;\r
+  if (mpgtype == 0) sampleRateColumn=2;\r
+  curSamplingRate=samplingRateTable[samplingCode][sampleRateColumn];\r
+  if (curSamplingRate < 0 || curBitrate < 0) {\r
+    log->log("DemuxerAudio",Log::DEBUG,"header invalid rates br=%d sr=%d %i %i %i",\r
+        curBitrate,curSamplingRate,*(hbuf-2),*(hbuf-1),*hbuf);\r
+    return 1;\r
+  }\r
+  int padbytes=0;\r
+  if (padding) {\r
+    if (layer == 3) padbytes=4;\r
+    else padbytes=1;\r
+  }\r
+  if (layer == 3) {\r
+    //Layer 1\r
+    //FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4\r
+    curFramelen=(12*curBitrate/curSamplingRate+padbytes) * 4;\r
+  }\r
+  else {\r
+    //Layer 2/3\r
+    //FrameLengthInBytes = 144 * BitRate / SampleRate + Padding\r
+    curFramelen=144*curBitrate/curSamplingRate+padbytes;\r
+  }\r
+  //the header itself\r
+  if (curFramelen < 32) {\r
+  log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d-invalid %i %i %i",\r
+      readHeaders,mpegString(mpgtype),layerString(layer),\r
+      curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf);\r
+      return 1;\r
+  }\r
+  if (writeInfo || isStarting){\r
+  log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d %i %i %i",\r
+      readHeaders,mpegString(mpgtype),layerString(layer),\r
+      curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf);\r
+    if (info) delete info;\r
+    info=new mpegInfo();\r
+    strcpy(info->mpegVersion,mpegString(mpgtype));\r
+    info->mpegLayer=4-layer;\r
+    info->bitRate=curBitrate;\r
+    info->avrBitrate=curBitrate;\r
+    info->sampleRate=curSamplingRate;\r
+    const char *chmodStr=tr("Stereo");\r
+    switch (chmode) {\r
+      case 1: chmodStr=tr("JointStereo");break;\r
+      case 2: chmodStr=tr("Dual");break;\r
+      case 3: chmodStr=tr("Mono");break;\r
+    }\r
+    SNPRINTF(info->info,sizeof(info->info)-1,"%s",chmodStr);\r
+  }\r
+       if (isStarting) avrBitrate=curBitrate;\r
+  isStarting=false;\r
+  readHeaders++;\r
+  //moving average F=0.005\r
+  avrBitrate=avrBitrate+((5*(curBitrate-avrBitrate))/1024);\r
+  hdrBitrate=curBitrate;\r
+  hdrFramelen=curFramelen;\r
+  hdrSamplingRate=curSamplingRate;\r
+       hasHdrInfo=true;\r
+  return 0;\r
+}\r
+\r
+int DemuxerAudio::findPTS(UCHAR* buf, int len, ULLONG* dest)\r
+{\r
+  //we have no PTS number ...\r
+  *dest=0;\r
+  return (findHeader(buf,len) != NULL)?1:0;\r
+}\r
+\r
+bool PacketBuffer::doSkip() {\r
+       if (!bufferFull()) return false;\r
+       if (skipfactor == 0) return false;\r
+       numskip++;\r
+       if (numskip >= skipfactor) {\r
+               //sent at least always 2 packets\r
+               if (numskip > skipfactor) numskip=0;\r
+               return false;\r
+       }\r
+       packetWritten();\r
+       return true;\r
+}\r
+       \r
+// just handle the real stream without dealing with the header\r
+int PacketBuffer::putInternal(UCHAR * wbuf, int len,unsigned int &packetnum)\r
+{\r
+   /* Important, the type passed to stream must be a mediapacket type as defined in \r
+       Draintarget.h and not the device setting of the mvp, so we have to translate it here,\r
+       in order to get it working on windows\r
+       --MR */\r
+  UCHAR mptype=0;\r
+  switch (streamtype) {\r
+        case Audio::MPEG1_PES: //?\r
+        case Audio::MPEG2_PES: //Important, this must be a PES !\r
+            mptype=MPTYPE_MPEG_AUDIO; break;\r
+        default:\r
+        case Audio::MP3: //this can be any Mpeg1 Audio not only layer 3 not packed into PES\r
+           mptype=MPTYPE_MPEG_AUDIO_LAYER3;break;\r
+  };\r
+  if (bufferFull()) {\r
+#ifndef WIN32\r
+               if (doSkip()) return 0;//NoSkip on Windows\r
+#endif\r
+    //we are still full - so try to write\r
+    int sent=audio->put(store+bytesWritten,framelen-bytesWritten,/*streamtype*/mptype,packetnum);packetnum++;\r
+    //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream (still full) pp=%d, framelen=%d, written=%d",sent,partPacket,framelen, bytesWritten );\r
+    if (sent < (framelen - bytesWritten)) {\r
+      //packet still not written\r
+      bytesWritten+=sent;\r
+      return 0;\r
+    }\r
+    packetWritten();\r
+    //let the demuxer come back with the rest - need to check header first\r
+    return 0;\r
+  }\r
+  if (partPacket+len >= framelen) {\r
+    //now we have at least a complete packet\r
+    int bytesConsumed=framelen-partPacket;\r
+    memcpy(store+partPacket,wbuf,bytesConsumed);\r
+    partPacket=framelen;\r
+    //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"stored packet %ld, length %d (last %d) for stream %p",numpackets,framelen,bytesConsumed,audio );\r
+#ifndef WIN32 //No Skip on Windows\r
+               if (doSkip()) return bytesConsumed;\r
+#endif\r
+    int sent=audio->put(store,framelen,mptype,packetnum);packetnum++;\r
+    bytesWritten+=sent;\r
+    //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream",sent );\r
+    if (bytesWritten < framelen) {\r
+      //still not completely written\r
+      return bytesConsumed;\r
+    }\r
+    packetWritten();\r
+    //let the player come back...\r
+    return bytesConsumed;\r
+  }\r
+  //OK packet still not complete\r
+  if (len == 0) return 0;\r
+  int bytesConsumed=len;\r
+  memcpy(store+partPacket,wbuf,bytesConsumed);\r
+  partPacket+=bytesConsumed;\r
+  return bytesConsumed;\r
+}\r
+\r
+/**\r
+  major entry for data from a player\r
+  the demuxer is either in the state headerSearch (packet written or\r
+  just at the beginning), writing garbage (inSync=false) or\r
+  handling data (none set)\r
+  A header is expected at the first byte after the previous packet -\r
+  otherwise we switch to garbage where we always search for a header\r
+  (but anyway provide the data to the underlying device - it's probably\r
+  more intelligent then we are...\r
+  We only loose a correct position display.\r
+  */\r
+int DemuxerAudio::put(UCHAR* wbuf, int len)\r
+{\r
+  //return audiostream.put(wbuf,len,streamtype);\r
+  int framelen=PACKET_SIZE;\r
+  UCHAR *hdr;\r
+  int bytesConsumed=0;\r
+  int oldBytes=0;\r
+  if (tmpFill != 0 || (buffer->bufferEmpty() && len < HDRLEN)) {\r
+    //OK we have to copy everything to the tmp buffer\r
+    int cp=(UINT)len<(PACKET_SIZE-tmpFill)?(UINT)len:(PACKET_SIZE-tmpFill);\r
+    memcpy(&tmpBuffer[tmpFill],wbuf,cp);\r
+    oldBytes=tmpFill;\r
+    tmpFill+=cp;\r
+    wbuf=tmpBuffer;\r
+    len=tmpFill;\r
+    //if there is no header here and our buffer\r
+    //is empty - just wait for the next header\r
+    if (len < HDRLEN && buffer->bufferEmpty()) {\r
+      log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten);\r
+      return cp;\r
+    }\r
+  }\r
+  while (bytesConsumed < len ) {\r
+    if (buffer->bufferFull()) {\r
+      //if this is the first part of the loop, try to write to the stream\r
+      if (bytesConsumed == 0) buffer->putInternal(wbuf,0,packetnum);\r
+      //if the buffer is full, no need to continue\r
+      if (buffer->bufferFull()) break;\r
+    }\r
+    //either we are in a packet (buffer != full && buffer != empty)\r
+    //or we are searching a header\r
+    if (buffer->bufferEmpty()) {\r
+      if (len-bytesConsumed < HDRLEN) {\r
+        // we cannot  still search\r
+        if (tmpFill != 0) {\r
+          //we are already working at the buffer\r
+          break;\r
+        }\r
+        memcpy(tmpBuffer,wbuf,len-bytesConsumed);\r
+        tmpFill=len-bytesConsumed;\r
+        log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten);\r
+        return len;\r
+      }\r
+\r
+      int lastFramelen=hdrFramelen;\r
+      //if the header has been valid before and we are searching\r
+      //it should be here\r
+      int maxsearch=((len-bytesConsumed) < (int)PACKET_SIZE)?len-bytesConsumed:(int)PACKET_SIZE;\r
+      hdr=findHeader(wbuf,maxsearch);\r
+      if (hdr != NULL) {\r
+        //log->log("DemuxerAudio",Log::DEBUG,"header found at offset %d",hdr-wbuf);\r
+        }\r
+      //hdr now points to the new header\r
+      if (hdr !=  wbuf) {\r
+        //still at least bytes before the header\r
+        inSync=false;\r
+        outOfSync++;\r
+        int garbageBytes=(hdr!=NULL)?(hdr-wbuf):maxsearch;\r
+        //we consider the garbage now as an own packet\r
+        //we can consume at most our buffer\r
+        //basically the buffer should be empty here (we are\r
+        //in header search - and we fill up each garbage\r
+\r
+        int nframesize=garbageBytes;\r
+        if (nframesize > (int)PACKET_SIZE) {\r
+          nframesize=(int)PACKET_SIZE;\r
+        }\r
+        if (! buffer->bufferEmpty()) {\r
+           log->log("DemuxerAudio",Log::WARN,"buffer not empty when having garbage to store");\r
+           //at the end no big problem, we only write the remaining bytes that we have...\r
+        }\r
+        else {\r
+          buffer->setFramelen(nframesize);\r
+        }\r
+        log->log("DemuxerAudio",Log::DEBUG,"garbage found at packet %ld (bytes %ld) of length %d, "\r
+            "framelen set to %d (last fl=%d)",\r
+            readHeaders,globalBytesWritten,garbageBytes,buffer->getFramelen(),lastFramelen);\r
+#ifndef WIN32        \r
+        //hmm - we assume that he low level driver is more intelligent\r
+        //and give him the data "as is"\r
+        int written=buffer->putInternal(wbuf,garbageBytes,packetnum);\r
+        globalBytesWritten+=written;\r
+        bytesConsumed+=written;\r
+        if (written != garbageBytes || hdr == NULL ) {\r
+          break;\r
+        }\r
+#else //DS is not intelligent\r
+        globalBytesWritten+=garbageBytes;\r
+        bytesConsumed+=garbageBytes;\r
+#endif\r
+        //OK either all the "garbage" is written  or\r
+        //we found the next header as expected\r
+        //continue with the next package\r
+        wbuf=hdr;\r
+      }\r
+      //we have to wait now until the buffer is \r
+      //free for the next package\r
+      if ( ! buffer->bufferEmpty()) return bytesConsumed;\r
+      //this is the place where we start a new packet\r
+      framelen=hdrFramelen;\r
+      if ( !buffer->setFramelen(framelen) ) {\r
+        log->log("DemuxerAudio",Log::DEBUG,"unable to set framelen should=%d, current=%d",\r
+            framelen,buffer->getFramelen());\r
+            }\r
+      inSync=true;\r
+    }\r
+    //now we are surely within a packet\r
+    int written=buffer->putInternal(wbuf,len-bytesConsumed,packetnum);\r
+    //update the status\r
+    globalBytesWritten+=written;\r
+    wbuf+=written;\r
+    bytesConsumed+=written;\r
+    if (written == 0) {\r
+      //stream is full\r
+      break;\r
+    }\r
+    //OK - handle the rest\r
+  }\r
+  if (bytesConsumed >= oldBytes) {\r
+    //if we consumed more than the old bytes - OK the buffer\r
+    //can be thrown away\r
+    tmpFill=0;\r
+    return bytesConsumed-oldBytes;\r
+  }\r
+  else {\r
+    //only consumed bytes from the buffer\r
+    if (bytesConsumed == 0) {\r
+      //restore the buffer\r
+      tmpFill=oldBytes;\r
+      return 0;\r
+    }\r
+    //shift bytes in buffer\r
+    for (int i=0;i<oldBytes-bytesConsumed;i++) {\r
+      tmpBuffer[i]=tmpBuffer[i+bytesConsumed];\r
+    }\r
+    tmpFill=oldBytes-bytesConsumed;\r
+    return 0;\r
+  }\r
+}\r
+\r
+//info functions\r
+const id3_tag * DemuxerAudio::getId3Tag() {\r
+  return id3;\r
+\r
+}\r
+const DemuxerAudio::mpegInfo * DemuxerAudio::getMpegInfo() {\r
+  if (! hasHdrInfo) return NULL;\r
+       info->avrBitrate=avrBitrate;\r
+       info->bitRate=hdrBitrate;\r
+  return info;\r
+}\r
+\r
+const DemuxerAudio::vbrInfo * DemuxerAudio::getVBRINfo() {\r
+       return vbr;\r
+}\r
+\r
+int DemuxerAudio::checkStart(UCHAR *b, int len) {\r
+  UCHAR *start=b;\r
+  int id3len=parseID3V2(b,len);\r
+  if (id3len > 0) {\r
+    char * str=id3->toString();\r
+    log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 %d bytes of %d",id3len,len);\r
+    log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 found:%s",str);\r
+    delete str;\r
+    b+=id3len;\r
+    len-=id3len;\r
+  }\r
+       int vbrlen=parseVBR(b,len);\r
+       if (vbrlen > 0 ) {\r
+               hasVBRInfo=true;\r
+               b+=vbrlen;\r
+               len-=vbrlen;\r
+       }\r
+  UCHAR * hdr=findHeader(b,len,true);\r
+  if (hdr == NULL) return -1;\r
+  return hdr-start;\r
+}\r
+\r
+int DemuxerAudio::checkID3(UCHAR *b, int len) {\r
+  if (len != 128) return -1;\r
+  int rt=parseID3V1(b,len);\r
+  if (rt >= 0) {\r
+    char * str=id3->toString();\r
+    log->log("DemuxerAudio",Log::DEBUG,"parseID3V1 found:%s",str);\r
+    delete str;\r
+  }\r
+  return rt;\r
+}\r
+\r
+bool DemuxerAudio::isSync() {\r
+  return inSync;\r
+}\r
+\r
+UINT DemuxerAudio::getSyncErrors() {\r
+  return outOfSync;\r
+}\r
+\r
+ULONG DemuxerAudio::getBytesPerSecond()\r
+{\r
+  ULONG bps=hdrBitrate;\r
+  if (! hasHdrInfo) return 0;\r
+  if (hdrBitrate != avrBitrate) {\r
+    //we seem to have vbr\r
+    if (hasVBRInfo) {\r
+      //vbr stuff TODO\r
+      bps=avrBitrate;\r
+    }\r
+    else {\r
+      //some guessing\r
+      bps=avrBitrate;\r
+    }\r
+  }\r
+  bps=bps/8;\r
+  return bps;\r
+}\r
+\r
+ULONG DemuxerAudio::getSecondsFromLen(ULONG len) {\r
+  if (! hasHdrInfo) return 0;\r
+       if (vbr) {\r
+               //first find the index where we are between\r
+               //rough starting point:\r
+               ULONG idx=100*len/vbr->numBytes;\r
+               if (idx >= 100) idx=99;\r
+               ULONG idxPos=(vbr->table[idx]) * vbr->numBytes/256;\r
+               ULONG pbefore=idxPos;\r
+               ULONG pafter=idxPos;\r
+               //OK now we know whether we have to go up or down\r
+               if (idxPos > len) {\r
+                       //down\r
+                       while (idxPos > len && idx > 0) {\r
+                               pafter=idxPos;\r
+                               idx--;\r
+                               idxPos=(vbr->table[idx]) * vbr->numBytes/256;\r
+                               pbefore=idxPos;\r
+                       }\r
+                       //OK we are now before our postion\r
+               }\r
+               else {\r
+                       //up\r
+                       while (idxPos < len && idx < 100 ) {\r
+                               pbefore=idxPos;\r
+                               idx++;\r
+                               idxPos=(vbr->table[idx]) * vbr->numBytes/256;\r
+                               pafter=idxPos;\r
+                       }\r
+                       //after our position\r
+                       if (idx > 0) idx --;\r
+               }\r
+               //idx is now the index before our position\r
+               //approximate between the 2 points\r
+               ULONG idxTime=idx * vbr->fileSeconds/100;\r
+               if (pafter == pbefore) return idxTime;\r
+               ULONG rt=idxTime+ (len-pbefore)* vbr->fileSeconds/(100 * (pafter-pbefore)) ;\r
+               if (rt > vbr -> fileSeconds) return vbr->fileSeconds;\r
+               if (rt < idxTime) return idxTime;\r
+               return rt;\r
+       }\r
+       else {\r
+               ULONG bps=getBytesPerSecond();\r
+               if (bps == 0) return 0;\r
+               return len/bps;\r
+       }\r
+}\r
+  \r
+ULONG DemuxerAudio::positionFromSeconds(ULONG seconds) {\r
+  if (! hasHdrInfo) return 0;\r
+       if (vbr) {\r
+               ULONG idx=seconds*100/vbr->fileSeconds;\r
+               if (idx > 99) idx=99;\r
+               ULONG idxPos=vbr->table[idx] * vbr->numBytes/256;\r
+               ULONG idx2=idx;\r
+               if (idx < 99) idx2++;\r
+               ULONG nextPos=vbr->table[idx] * vbr->numBytes/256;\r
+               ULONG rt=idxPos+(nextPos-idxPos) * (seconds - idx * vbr->fileSeconds /256);\r
+               if (rt < idxPos) return idxPos;\r
+               if ( rt > vbr->numBytes) return vbr->numBytes;\r
+               return rt;\r
+       }\r
+       else {\r
+               ULONG bps=getBytesPerSecond();\r
+               return bps*seconds;\r
+       }\r
+}\r
+\r
+int id3_tag::stringlen(bool withTitle) const {\r
+       if (!withTitle)\r
+   return strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+\r
+    strlen(track)+strlen(composer)+strlen(comment)+8+3+\r
+    90; //30 chars for each name...\r
+       else\r
+   return strlen(title)+strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+\r
+    strlen(track)+strlen(composer)+strlen(comment)+8+3+\r
+    120; //30 chars for each name...\r
+}\r
+//create a string out of the id3 tag info\r
+//delete this string afterwards if you did not provide the buffer\r
+char * id3_tag::toString(char *b, int len, bool withTitle) const {\r
+  const char *ta=tr("Artist");\r
+//char *tg=tr("Genre");\r
+//char *ty=tr("Year");\r
+  const char *tx=tr("Album");\r
+//char *to=tr("Composer");\r
+//char *tc=tr("Comment");\r
+  const char *tn=tr("Track");\r
+  /* in the moment:\r
+     Title: \r
+     Artist:\r
+     Album: year - name\r
+     Track:\r
+     */\r
+  if (b == NULL) {\r
+    len=stringlen(withTitle);\r
+    b=new char[len];\r
+  }\r
+       const char * del=" - ";\r
+       if (strlen(year) == 0) del="";\r
+       if (withTitle){\r
+ const char *tt=tr("Title");\r
+               SNPRINTF(b,len-1,"%s: %s\n%s: %s\n%s: %s%s%s\n%s: %s",\r
+                               tt,title,ta,artist,tx,year,del,album,tn,track);\r
+       }\r
+       else {\r
+SNPRINTF(b,len-1,"%s: %s\n%s: %s%s%s\n%s: %s",\r
+                               ta,artist,tx,year,del,album,tn,track);\r
+       }\r
+  b[len-1]=0;\r
+  return b;\r
+}\r
+\r
+void DemuxerAudio::setSkipFactor(int factor) {\r
+       Log::getInstance()->log("DemuxerAudio",Log::DEBUG,"set skipfactor %d\n",factor);\r
+       buffer->setSkipFactor(factor);\r
+}\r
+\r
index 9d0cf32d4f6cef8247547af4e9f3d74b2fa7c601..def7222e2071467dc0efabe800bb6ed6eb28f189 100644 (file)
-/*
-    Copyright 2006-2008 Mark Calderbank
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "demuxerts.h"
-#include "log.h"
-#include "video.h"
-#include "vdr.h"
-
-#define PTS_JUMP_MARGIN   10000
-#define PTS_ALLOWANCE 90000
-
-// TODO: PTS class to handle wrapping arithmetic & comparisons?
-static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)
-{
-  // Assume pts1, pts2 < 2^33; calculate shortest distance between
-  ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;
-  if (ret > (1LL<<32)) ret = (1LL<<33) - ret;
-  return ret;
-}
-
-static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
-{
-  // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
-  if (pts1 > pts2)
-    return pts1 - pts2;
-  else
-    return (1LL<<33) + pts1 - pts2;
-}
-
-DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID)
-{
-  vID = p_vID; vActive = false;
-  aID = p_aID; aActive = false;
-  subID = p_subID; subActive = false;
-  atype = 0;
-  subLength = 0;
-  tID = p_tID;
-  havechannelinfo=false;
-  doubledframerate=false;
-  framereserve=0;
-}
-
-void DemuxerTS::flush()
-{
-  partPacket = 0;
-  parsed = false;
-  havechannelinfo=false;
-  Demuxer::flush();
-  vPacket.init(PESTYPE_VID0);
-  switch (atype)
-  {
-  case 1:
-    aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
-    break;
-  default:
-  case 0:
-    aPacket.init(PESTYPE_AUD0);
-    break;
-  }
-  subPacket.init(PESTYPE_PRIVATE_1);
-tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
-
-  vActive = false;
-  aActive = false;
-  subActive = false;
-  subLength = 0;
-  tActive = false;
-  doubledframerate=false;
-  framereserve=0;
-}
-
-int DemuxerTS::scan(UCHAR *buf, int len)
-{
-  switch (atype)
-  {
-  case 1:
-    return PESTYPE_PRIVATE_1;
-  default:
-  case 0:
-    return PESTYPE_AUD0;
-  }
-}
-
-void DemuxerTS::setVID(int p_vID)
-{
-  vID = p_vID;
-  vPacket.init(PESTYPE_VID0);
-  vActive = false;
-}
-
-void DemuxerTS::setAID(int p_aID, int type)
-{
-  aID = p_aID;
-  atype = type;
-  switch (atype)
-  {
-  case 1:
-    aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
-    setAudioStream(PESTYPE_SUBSTREAM_AC30);
-    break;
-  default:
-  case 0:
-    aPacket.init(PESTYPE_AUD0);
-    setAudioStream(PESTYPE_AUD0);
-    break;
-  }
-  aActive = false;
-}
-
-void DemuxerTS::setSubID(int p_subID)
-{
-  subID = p_subID;
-  subPacket.init(PESTYPE_PRIVATE_1);
-  subActive = false;
-  subLength = 0;
-}
-
-void DemuxerTS::setTID(int p_tID)
-{
-  tID = p_tID;
-  tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
-  tActive = false;
-
-}
-
-
-
-
-int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)
-{
-  int scanaid=0;
-
-  while (len >= TS_SIZE)
-  {
-      if (*buf != TS_SIG) {buf++;len--; continue;} 
-
-    //Pattern scanning won't work for ts
-
-      
-      int datalen = TS_SIZE - 4;
-      int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
-      UCHAR payload = buf[1] & 0x40;
-      
-      if (buf[3] & 0x20) // Adaptation field is present
-          datalen -= (buf[4] + 1);
-
-      UCHAR* curbuf =buf+ (TS_SIZE - datalen);
-     
-
-      if (payload) {
-          if (pid == 0x00) {//PAT, only take first program number, ignore the rest
-              int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);
-              if ((pmtpid >> 13) != 0x07) 
-              {
-                  Log::getInstance()->log("findPTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));
-              } 
-              else 
-              {
-                  pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
-                  PMTPID = pmtpid;
-              }
-          
-          } else if (pid == PMTPID) { //PMT
-              int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);
-              //sectionlength += 4; //include header but subtract crc in the end...
-              int p = 13; //skip fixed part of pmt
-              while ( p < sectionlength) {
-                  int streamtype = *(curbuf+p);
-                  p++;
-                  int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);
-                  p += 2; //skip ES Pid
-                  int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);
-                  p += 2; //skip ES length
-                  if ((foundpid >> 13) != 0x07)
-                  {
-                      Log::getInstance()->log("findPTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));
-                  }
-                  else 
-                  {
-                      foundpid = foundpid & 0x1FFF; //clear upper 3 bits
-                      //int pos=0; UNUSED?
-                      if (streamtype==3 || streamtype ==4) {
-                          scanaid=foundpid;
-                      }
-                  }
-                  p += eslength; //skip es descriptor
-              }
-          } else if (pid == scanaid) {     
-           //   UINT framelength = ((UINT)curbuf[4] << 8) | curbuf[5];  UNUSED?
-              
-              if ( curbuf[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
-              {
-                  *dest = ( (ULLONG)(curbuf[9] & 0x0E) << 29 ) |
-                  ( (ULLONG)(curbuf[10])        << 22 ) |
-                  ( (ULLONG)(curbuf[11] & 0xFE) << 14 ) |
-                  ( (ULLONG)(curbuf[12])        <<  7 ) |
-                  ( (ULLONG)(curbuf[13] & 0xFE) >>  1 );
-                  return 1;
-              }
-          }
-      }
-      len-=TS_SIZE;
-      buf+=TS_SIZE;
-  }
-  // No PTS found.
-  return 0;
-}
-
-void DemuxerTS::setFrameNum(ULONG frame)
-{
-  frameCounting = true;
-  frameNumber = frame;
-  framereserve=0;
-  Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setFrameNum %d", frame);
-}
-
-void DemuxerTS::setPacketNum(ULONG npacket)
-{
-  packetCounting = true;
-  packetNumber = npacket;
-  Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setPacketNum %d", npacket);
-}
-
-
-int DemuxerTS::put(UCHAR* buf, int len)
-{
-  int ret = 0;    // return number of bytes consumed
-
-  while (partPacket)
-  {
-    if (len >= TS_SIZE + 1 - partPacket)
-    { // Remainder of partial packet is available, plus one
-      memcpy(store+partPacket, buf, TS_SIZE - partPacket);
-      ret += TS_SIZE - partPacket;
-      buf += TS_SIZE - partPacket;
-      len -= TS_SIZE - partPacket;
-      partPacket = TS_SIZE;
-      if (*buf == TS_SIG)
-      { // Packet is properly terminated
-        int rc = processTS(store);
-        if (rc)
-          partPacket = 0; // Successfully processed
-        else
-          return ret;     // Try again later.
-      }
-      else
-      { // Packet not terminated. Find another candidate, and shift store
-        Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!");
-        int search = 1;
-        while (search < partPacket && store[search] != TS_SIG)
-          search++;
-        partPacket -= search;
-        if (partPacket) memcpy(store, store+search, partPacket);
-      }
-    }
-    else
-    { // Still don't have complete packet. Consume what we do have.
-      memcpy(store+partPacket, buf, len);
-      partPacket += len;
-      ret += len;
-      return ret;
-    }
-  }
-
-  // Position ourselves at a candidate TS packet
-  while (len > 0 && *buf != TS_SIG)
-  {
-    Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!");
-    buf++; ret++; len--;
-  }
-
-  while (len)
-  {
-    if (len < TS_SIZE + 1)
-    { // Not enough data. Store what we have.
-      memcpy(store, buf, len);
-      partPacket = len;
-      ret += len;
-      return ret;
-    }
-
-    if (buf[TS_SIZE] != TS_SIG)
-    { // Not terminated correctly.
-      buf++; ret++; len--;
-      while (len > 0 && *buf != TS_SIG)
-      {
-        buf++; ret++; len--;
-      }
-    }
-    else
-    {
-      int rc = processTS(buf);
-      if (rc)
-      { // Successfully processed
-        buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE;
-      }
-      else
-      { // Processing failed.
-        return ret;
-      }
-    }
-  }
-  return ret;
-}
-
-int DemuxerTS::processTS(UCHAR* buf)
-{
-  int datalen = TS_SIZE - 4;
-
-  int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
-  UCHAR payload = buf[1] & 0x40;
-
-  if (buf[3] & 0x20) // Adaptation field is present
-    datalen -= (buf[4] + 1);
-  if (datalen < 0) // Error in stream TODO log this
-    return 1;
-  if (datalen == 0) // Null packet
-    return 1;
-  buf += (TS_SIZE - datalen);
-
-  if (payload)
-  {
-      int rc = 1;
-      if (pid == 0x00) {//PAT, only take first program number, ignore the rest
-          int pmtpid = (*(buf+11)<< 8) | *(buf+12);
-          if ((pmtpid >> 13) != 0x07) 
-          {
-              Log::getInstance()->log("ProcessTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(buf+11),*(buf+12), (pmtpid >> 13));
-          } 
-          else 
-          {
-              pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
-              PMTPID = pmtpid;
-          }
-           return 1;
-    }
-    if (pid == PMTPID) 
-    { //PMT
-        int sectionlength = ((*(buf+2) << 8) & 0x0F ) | *(buf+3);
-        //sectionlength += 4; //include header but subtract crc in the end...
-        int p = 13; //skip fixed part of pmt
-        Channel new_channelinfo;
-        new_channelinfo.numAPids=0;
-        new_channelinfo.numDPids=0;
-        new_channelinfo.numSPids=0;
-        new_channelinfo.number=0;
-        new_channelinfo.type=VDR::RADIO;
-        new_channelinfo.name=NULL;
-        new_channelinfo.tpid=0xFFFFF; //unused, check this
-        new_channelinfo.vpid=0xFFFFF; //unused, check this
-        new_channelinfo.index=0;
-
-        new_channelinfo.apids.clear();
-        new_channelinfo.dpids.clear();
-        new_channelinfo.spids.clear();
-        
-        while ( p < sectionlength) {
-            int streamtype = *(buf+p);
-            p++;
-            int foundpid = (*(buf+p)<< 8) | *(buf+p+1);
-            p += 2; //skip ES Pid
-            int eslength = ((*(buf+p) << 8) & 0x0F ) | *(buf+p+1);
-            p += 2; //skip ES length
-            if ((foundpid >> 13) != 0x07)
-            {
-              Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));
-            }
-            else 
-            {
-                foundpid = foundpid & 0x1FFF; //clear upper 3 bits
-                bool notfound=false;
-                int pos=0;
-       //     Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID is %x", foundpid);
-                switch (streamtype)
-                {
-                case 0x1B: //MPEG 4 for future use
-                case 1:
-                case 2: { //video
-                    if (foundpid != getVID())  
-                        setVID(foundpid);
-                    new_channelinfo.type=VDR::VIDEO;
-                                       new_channelinfo.vstreamtype=streamtype;
-                    new_channelinfo.vpid=foundpid;
-                                       if (streamtype==0x1b) h264=true;
-                                       else h264=false;
-
-                //  Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid);
-                        }break;
-                case 3:
-                case 4: { //audio
-                    apid newapid;
-                    newapid.pid = foundpid;
-                    newapid.name = NULL; //set it in player
-                    new_channelinfo.apids.push_back(newapid);
-                    new_channelinfo.numAPids++;
-                    if (getAID() == 0) { //set unset AID to first audio pid that reports itself
-                        setAID(foundpid,0);
-                        Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set audio PID to %x", foundpid);
-                    }
-                        } break;
-                case 5:
-                case 6: { //Private Data 
-                    apid newapid;
-                    newapid.pid = foundpid;
-                    newapid.name = NULL; //set it in player
-                    pos=0;
-                    notfound=true;
-                  
-                    while (pos< eslength && notfound) {
-                        switch (buf[p+pos]) {
-                        case 0x6A: {//Ac3 descriptor 
-                            new_channelinfo.dpids.push_back(newapid);
-                            new_channelinfo.numDPids++;
-                            notfound=false;
-                                   } break; 
-                       case 0x59: {//SubtitlingDescriptor
-                            new_channelinfo.spids.push_back(newapid);
-                            new_channelinfo.numSPids++;
-                            notfound=false;
-                                   } break;
-                       case 0x56: {
-                           new_channelinfo.tpid=foundpid;
-                           notfound=false;
-                                  } break;
-                        };
-                        pos+=2+buf[p+pos+1];
-                    }
-
-                        } break;
-                default://TODO how about subtitles and second audio pids
-                    break;
-                }
-               }
-           
-                p += eslength; //skip es descriptor
-        
-        
-           }
-        bool audioPIDpresent=false; //Check if pids chnages
-        ULONG i;
-        for (i=0;i<channelinfo.numAPids;i++) {
-            if (aID == (int)channelinfo.apids[i].pid) {
-                audioPIDpresent=true;
-            }
-        }
-        for (i=0;i<channelinfo.numDPids && (! audioPIDpresent);i++) {
-            if (aID == (int)channelinfo.dpids[i].pid) {
-                audioPIDpresent=true;
-            }
-        }
-        if (! audioPIDpresent) {
-            if (channelinfo.numAPids>0) {
-                setAID(channelinfo.apids[0].pid,0);
-            } else if (channelinfo.numDPids>0) {
-                setAID(channelinfo.dpids[0].pid,1);
-            }
-        }
-
-        channelinfo=new_channelinfo;
-        havechannelinfo=true;
-
-        return 1;
-    }
-    
-
-    
-
-    if (pid == vID)
-    {
-      if (vActive)
-      {
-        if (!parsed)
-        {
-          parseTSPacketDetails(vPacket);
-          parsed = true;
-        }
-        rc = submitPacket(vPacket);
-      }
-      vActive = true;
-    }
-    if (pid == aID)
-    {
-      if (aActive)
-      {
-        if (!parsed)
-        {
-          parseTSPacketDetails(aPacket);
-          parsed = true;
-        }
-        rc = submitPacket(aPacket);
-      }
-      aActive = true;
-    }
-    if (pid == subID)
-    {
-      if (subActive)
-      {
-        if (!parsed)
-        {
-          parseTSPacketDetails(subPacket);
-          parsed = true;
-        }
-        rc = submitPacket(subPacket);
-      }
-      subActive = true;
-    }
-    if (isteletextdecoded && pid == tID)
-    {
-      if (tActive)
-      {
-        if (!parsed)
-        {
-          parseTSPacketDetails(tPacket);
-          parsed = true;
-        }
-      rc = submitPacket(tPacket);
-      }
-      tActive = true;
-    }
-    if (rc == 0) return 0;
-
-    parsed = false;
-    if (pid == vID)
-    {
-      vPacket.init(PESTYPE_VID0);
-      buf += 6; datalen -= 6;
-    }
-    if (pid == aID)
-    {
-      switch (atype)
-      {
-      case 1:
-        aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
-        break;
-      default:
-      case 0:
-        aPacket.init(PESTYPE_AUD0);
-        break;
-      }
-      buf += 6; datalen -= 6;
-    }
-    if (pid == subID)
-    {
-      subPacket.init(PESTYPE_PRIVATE_1);
-      subLength = (buf[4] << 8) + buf[5];
-      buf += 6; datalen -= 6;
-    }
-    if (isteletextdecoded && pid == tID)
-    {
-        tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
-      buf += 6; datalen -= 6;
-    }
-  }
-
-  if ( (pid == vID && vActive) ||
-       (pid == aID && aActive) ||
-       (pid == tID && tActive) ||
-       (pid == subID && subActive) )
-  {
-    PESPacket* packet = NULL;
-    if (pid == vID) packet = &vPacket;
-    if (pid == aID) packet = &aPacket;
-    if (pid == subID) {
-      packet = &subPacket;
-    }
-    if (pid == tID) packet = &tPacket;
-    if (packet != NULL)
-    {
-      if (packet->write(buf, datalen) == 0)
-      { // Writing to packet failed. It has overflowed.
-        if (!parsed)
-        {
-          parseTSPacketDetails(*packet);
-          parsed = true;
-        }
-        if (submitPacket(*packet) == 0) return 0;
-        parsed = false;
-        packet->truncate();
-        packet->write((UCHAR*)"\200\000\000", 3);
-        packet->write(buf, datalen);
-      }
-    }
-  }
-
-  if (pid == subID && subActive && subPacket.getLength() == subLength)
-  {
-    parsePacketDetails(subPacket);
-Log::getInstance()->log("DEMUXERTS", Log::DEBUG, "SUBMITTING A SUBTITLE PACKET %d %x", subLength, subPacket.getSubstream());
-    submitPacket(subPacket);
-    subActive = false;
-  }
-
-  return 1;
-}
-
-ULONG DemuxerTS::getPacketNum()
-{
-  return packetNumber;
-}
-
-ULONG DemuxerTS::getFrameNumFromPTS(ULLONG pts)
-{
-  ULLONG difference = (1LL<<33);
-  ULONG ref_frame = 0;
-  int total = 0, actual = 0;
-  if (pts==0) return 0; //we are in startup
-  pts_map_mutex.Lock();
-  PTSMap::iterator iter = pts_map.begin();
-  while (iter != pts_map.end())
-  {
-    ++total;
-     //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts1 %lld pts2 %lld", pts, iter->pts);
-    if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
-    {
-      difference = 0;
-      ref_frame = iter->frame;
-      actual = total;
-      break;
-    }
-    ULLONG newdiff = PTSDifference(pts, iter->pts);
-    if (newdiff < difference)
-    {
-      difference = newdiff;
-      ref_frame = iter->frame;
-      actual = total;
-    }
-    ++iter;
-  }
-  if (total > 1 && actual == 1) // We are using the most recent PTS ref.
-  {                             // Delete the rest.
-    iter = pts_map.begin(); iter++;
-    pts_map.erase(iter, pts_map.end());
-  }
-  pts_map_mutex.Unlock();
-  
- //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts %lld deleted %d difference %lld", pts, total,difference);
-
-  if (difference == (1LL<<33))
-    return 0; // We cannot make sense of the pts
-  else
-    return ref_frame + difference * fps / 90000;
-}
-
-
-void DemuxerTS::parseTSPacketDetails(PESPacket &packet) // Only important stuff for paket counting reminas
-{
-    parsePacketDetails(packet);
-    if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
-                        packet.getPacketType() <= PESTYPE_AUDMAX)
-    {
-        packetNumber++;
-    }
-    UINT pictsinpacket=packet.countPictureHeaders(h264);
-    
-    UINT numpicts=0;
-    if (!doubledframerate)
-    {
-        numpicts=pictsinpacket;
-    }
-    else
-    {
-        numpicts=(pictsinpacket+framereserve)>>1;
-        framereserve=(pictsinpacket+framereserve)%2;
-    }
-
-
-  if (frameCounting && numpicts &&
-      packet.getPacketType() >= PESTYPE_VID0 &&
-      packet.getPacketType() <= PESTYPE_VIDMAX)
-  {
-    frameNumber+=numpicts;
-    ULONG frame_num = frameNumber;
-    if ((h264 || packet.findSeqHeader(h264) > 1) && packet.hasPTS())
-    {
-      PTSMapEntry me;
-      pts_map_mutex.Lock();
-      if (pts_map.empty())
-      {
-        me.pts = packet.getPTS();
-        me.frame = frame_num;
-        pts_map_mutex.Unlock();
-        pts_map_mutex.Lock();
-        pts_map.push_front(me);
-      }
-      me = pts_map.front();
-      pts_map_mutex.Unlock();
-
-      //UINT fps = Video::getInstance()->getFPS();
-      double tfps=fps;
-      if (doubledframerate) tfps*=2.;
-      ULLONG pts_expected = me.pts + 90000*((int)(((double)(frame_num - me.frame)) / tfps));
-      while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
-
-      if (!doubledframerate 
-          &&(abs((long long)PTSDistance(pts_expected, packet.getPTS())-1800) <= 1 
-          || abs((long long)PTSDistance(pts_expected, packet.getPTS())-1501) <= 1)) {
-              doubledframerate=true; //Detected  p50 or p60
-      }
-
-      if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
-      {
-        me.pts = packet.getPTS();
-        me.frame = frame_num;
-        pts_map_mutex.Lock();
-        pts_map.push_front(me);
-        pts_map_mutex.Unlock();
-      }
-    }
-  }
-}
-
-
-bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len, bool &ish264)
-{
-    int pmtpidy=0;
-
-  while (len >= TS_SIZE)
-  {
-      if (*buf != TS_SIG) {buf++;len--; continue;} 
-
-    //Pattern scanning won't work for ts
-
-      
-      int datalen = TS_SIZE - 4;
-      int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
-      UCHAR payload = buf[1] & 0x40;
-      
-      if (buf[3] & 0x20) // Adaptation field is present
-          datalen -= (buf[4] + 1);
-
-      UCHAR* curbuf =buf+ (TS_SIZE - datalen);
-     
-      if (payload) {
-          if (pid == 0x00) {//PAT, only take first program number, ignore the rest
-              int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);
-              if ((pmtpid >> 13) != 0x07) 
-              {
-                  Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));
-              } 
-              else 
-              {
-                  pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
-                  pmtpidy = pmtpid;
-                                 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMT pid%02x",pmtpid );
-              }
-          
-          } else if (pid == pmtpidy) { //PMT
-              int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);
-              //sectionlength += 4; //include header but subtract crc in the end...
-              int p = 13; //skip fixed part of pmt
-              while ( p < sectionlength) {
-                  int streamtype = *(curbuf+p);
-                  p++;
-                  int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);
-                  p += 2; //skip ES Pid
-                  int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);
-                  p += 2; //skip ES length
-                  if ((foundpid >> 13) != 0x07)
-                  {
-                      Log::getInstance()->log("DemuxerTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));
-                  }
-                  else 
-                  {
-                      foundpid = foundpid & 0x1FFF; //clear upper 3 bits
-                   //   int pos=0; UNUSED?
-                                         Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Pid found %02x type %02x",foundpid ,streamtype);
-                      if (streamtype==1 || streamtype ==2) {
-                                                 ish264=false;
-                                                 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found Mpeg2 Video");
-                          return true;
-                      }
-                                         if (streamtype==0x1b) {
-                                                 ish264=true;
-                                                 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found h264 Video");
-                                                 return true;
-                                         }
-                  }
-                  p += eslength; //skip es descriptor
-              }
-                         ish264=false;
-              return false;
-          } 
-      }
-      len-=TS_SIZE;
-      buf+=TS_SIZE;
-  }
-  ish264=false;
-  return false;
-}
-
-UINT DemuxerTS::stripAudio(UCHAR* buf, UINT len) //it has to be adapted
-{ 
-    //This function strips all TS Headers and non video payload
-    UINT readpos=0;
-    UINT writepos=0;
-    PESPacket destpaket;
-    bool started=true;
-    while (readpos < len ) {
-        if (buf[readpos] != TS_SIG) {readpos++; continue;} 
-        UINT oldreadpos=readpos;
-
-        int datalen = TS_SIZE - 4;
-        int pid = ( (buf[readpos+1] & 0x1F) << 8 ) | buf[readpos+2];
-        UCHAR payload = buf[readpos+1] & 0x40;
-        if (buf[readpos+3] & 0x20) { // Adaptation field is present
-           datalen -= (buf[readpos+4] + 1);
-        }
-        if (datalen < 0) {// Error in stream TODO log this
-            return 0;
-        }
-        if (datalen == 0) {// Null packet
-             readpos=oldreadpos+TS_SIZE;
-            continue;
-        }
-        readpos += (TS_SIZE - datalen);
-        UINT towrite=min(datalen,len-readpos);
-        if (pid == vID) {
-            if (payload) {
-                if (started) {
-                    parsePacketDetails(destpaket);
-                    memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
-                    writepos+=destpaket.getSize();
-                 }
-                 destpaket.init(PESTYPE_VID0);
-                 readpos += 6; towrite -= 6;
-                 started=true;
-            }
-
-            if (started) {
-                if (!destpaket.write(buf+readpos,towrite)) {
-                    parsePacketDetails(destpaket);
-                    memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
-                    writepos+=destpaket.getSize();
-                    destpaket.truncate();
-                                       destpaket.write((UCHAR*)"\200\000\000", 3);
-                    destpaket.write(buf+readpos,towrite);
-
-                }
-            }
-            
-       
-
-        }
-        readpos=oldreadpos+TS_SIZE;
-    }
-    parsePacketDetails(destpaket);
-    memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
-    writepos+=destpaket.getSize();
-    return writepos;
-}    
-
-
-
+/*\r
+    Copyright 2006-2008 Mark Calderbank\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software Foundation, Inc.,\r
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "demuxerts.h"\r
+#include "log.h"\r
+#include "video.h"\r
+#include "vdr.h"\r
+\r
+#define PTS_JUMP_MARGIN   10000\r
+#define PTS_ALLOWANCE 90000\r
+\r
+// TODO: PTS class to handle wrapping arithmetic & comparisons?\r
+static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)\r
+{\r
+  // Assume pts1, pts2 < 2^33; calculate shortest distance between\r
+  ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;\r
+  if (ret > (1LL<<32)) ret = (1LL<<33) - ret;\r
+  return ret;\r
+}\r
+\r
+static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)\r
+{\r
+  // Assume pts1, pts2 < 2^33; calculate pts1 - pts2\r
+  if (pts1 > pts2)\r
+    return pts1 - pts2;\r
+  else\r
+    return (1LL<<33) + pts1 - pts2;\r
+}\r
+\r
+DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID)\r
+{\r
+  vID = p_vID; vActive = false;\r
+  aID = p_aID; aActive = false;\r
+  subID = p_subID; subActive = false;\r
+  atype = 0;\r
+  subLength = 0;\r
+  tID = p_tID;\r
+  havechannelinfo=false;\r
+  //doubledframerate=false;\r
+  framereserve=0;\r
+}\r
+\r
+void DemuxerTS::flush()\r
+{\r
+  partPacket = 0;\r
+  parsed = false;\r
+  havechannelinfo=false;\r
+  Demuxer::flush();\r
+  vPacket.init(PESTYPE_VID0);\r
+  switch (atype)\r
+  {\r
+  case 1:\r
+    aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);\r
+    break;\r
+  default:\r
+  case 0:\r
+    aPacket.init(PESTYPE_AUD0);\r
+    break;\r
+  }\r
+  subPacket.init(PESTYPE_PRIVATE_1);\r
+tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);\r
+\r
+  vActive = false;\r
+  aActive = false;\r
+  subActive = false;\r
+  subLength = 0;\r
+  tActive = false;\r
+ // doubledframerate=false;\r
+  framereserve=0;\r
+}\r
+\r
+int DemuxerTS::scan(UCHAR *buf, int len)\r
+{\r
+  switch (atype)\r
+  {\r
+  case 1:\r
+    return PESTYPE_PRIVATE_1;\r
+  default:\r
+  case 0:\r
+    return PESTYPE_AUD0;\r
+  }\r
+}\r
+\r
+void DemuxerTS::setVID(int p_vID)\r
+{\r
+  vID = p_vID;\r
+  vPacket.init(PESTYPE_VID0);\r
+  vActive = false;\r
+}\r
+\r
+void DemuxerTS::setAID(int p_aID, int type)\r
+{\r
+  aID = p_aID;\r
+  atype = type;\r
+  switch (atype)\r
+  {\r
+  case 1:\r
+    aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);\r
+    setAudioStream(PESTYPE_SUBSTREAM_AC30);\r
+    break;\r
+  default:\r
+  case 0:\r
+    aPacket.init(PESTYPE_AUD0);\r
+    setAudioStream(PESTYPE_AUD0);\r
+    break;\r
+  }\r
+  aActive = false;\r
+}\r
+\r
+void DemuxerTS::setSubID(int p_subID)\r
+{\r
+  subID = p_subID;\r
+  subPacket.init(PESTYPE_PRIVATE_1);\r
+  subActive = false;\r
+  subLength = 0;\r
+}\r
+\r
+void DemuxerTS::setTID(int p_tID)\r
+{\r
+  tID = p_tID;\r
+  tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);\r
+  tActive = false;\r
+\r
+}\r
+\r
+\r
+\r
+\r
+int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)\r
+{\r
+  int scanaid=0;\r
+\r
+  while (len >= TS_SIZE)\r
+  {\r
+      if (*buf != TS_SIG) {buf++;len--; continue;} \r
+\r
+    //Pattern scanning won't work for ts\r
+\r
+      \r
+      int datalen = TS_SIZE - 4;\r
+      int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];\r
+      UCHAR payload = buf[1] & 0x40;\r
+      \r
+      if (buf[3] & 0x20) // Adaptation field is present\r
+          datalen -= (buf[4] + 1);\r
+\r
+      UCHAR* curbuf =buf+ (TS_SIZE - datalen);\r
+     \r
+\r
+      if (payload) {\r
+          if (pid == 0x00) {//PAT, only take first program number, ignore the rest\r
+              int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);\r
+              if ((pmtpid >> 13) != 0x07) \r
+              {\r
+                  Log::getInstance()->log("findPTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));\r
+              } \r
+              else \r
+              {\r
+                  pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits\r
+                  PMTPID = pmtpid;\r
+              }\r
+          \r
+          } else if (pid == PMTPID) { //PMT\r
+              int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);\r
+              //sectionlength += 4; //include header but subtract crc in the end...\r
+              int p = 13; //skip fixed part of pmt\r
+              while ( p < sectionlength) {\r
+                  int streamtype = *(curbuf+p);\r
+                  p++;\r
+                  int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);\r
+                  p += 2; //skip ES Pid\r
+                  int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);\r
+                  p += 2; //skip ES length\r
+                  if ((foundpid >> 13) != 0x07)\r
+                  {\r
+                      Log::getInstance()->log("findPTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));\r
+                  }\r
+                  else \r
+                  {\r
+                      foundpid = foundpid & 0x1FFF; //clear upper 3 bits\r
+                      //int pos=0; UNUSED?\r
+                      if (streamtype==3 || streamtype ==4) {\r
+                          scanaid=foundpid;\r
+                      }\r
+                  }\r
+                  p += eslength; //skip es descriptor\r
+              }\r
+          } else if (pid == scanaid) {     \r
+           //   UINT framelength = ((UINT)curbuf[4] << 8) | curbuf[5];  UNUSED?\r
+              \r
+              if ( curbuf[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present\r
+              {\r
+                  *dest = ( (ULLONG)(curbuf[9] & 0x0E) << 29 ) |\r
+                  ( (ULLONG)(curbuf[10])        << 22 ) |\r
+                  ( (ULLONG)(curbuf[11] & 0xFE) << 14 ) |\r
+                  ( (ULLONG)(curbuf[12])        <<  7 ) |\r
+                  ( (ULLONG)(curbuf[13] & 0xFE) >>  1 );\r
+                  return 1;\r
+              }\r
+          }\r
+      }\r
+      len-=TS_SIZE;\r
+      buf+=TS_SIZE;\r
+  }\r
+  // No PTS found.\r
+  return 0;\r
+}\r
+\r
+void DemuxerTS::setFrameNum(ULONG frame)\r
+{\r
+  frameCounting = true;\r
+  frameNumber = frame;\r
+  framereserve=0;\r
+  Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setFrameNum %d", frame);\r
+}\r
+\r
+void DemuxerTS::setPacketNum(ULONG npacket)\r
+{\r
+  packetCounting = true;\r
+  packetNumber = npacket;\r
+  Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setPacketNum %d", npacket);\r
+}\r
+\r
+int DemuxerTS::put(UCHAR* buf, int len)\r
+{\r
+  int ret = 0;    // return number of bytes consumed\r
+\r
+  bool misaligned_mess=false;\r
+  while (partPacket)\r
+  {\r
+    if (len >= TS_SIZE + 1 - partPacket)\r
+    { // Remainder of partial packet is available, plus one\r
+      memcpy(store+partPacket, buf, TS_SIZE - partPacket);\r
+      ret += TS_SIZE - partPacket;\r
+      buf += TS_SIZE - partPacket;\r
+      len -= TS_SIZE - partPacket;\r
+      partPacket = TS_SIZE;\r
+      if (*buf == TS_SIG)\r
+      { // Packet is properly terminated\r
+        int rc = processTS(store);\r
+        if (rc)\r
+          partPacket = 0; // Successfully processed\r
+        else\r
+          return ret;     // Try again later.\r
+      }\r
+      else\r
+      { // Packet not terminated. Find another candidate, and shift store\r
+        if (!misaligned_mess) {\r
+               Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!A");\r
+               misaligned_mess=true; // do not alarm more than once\r
+        }\r
+        int search = 1;\r
+        while (search < partPacket && store[search] != TS_SIG)\r
+          search++;\r
+        partPacket -= search;\r
+        if (partPacket) memcpy(store, store+search, partPacket);\r
+      }\r
+    }\r
+    else\r
+    { // Still don't have complete packet. Consume what we do have.\r
+      memcpy(store+partPacket, buf, len);\r
+      partPacket += len;\r
+      ret += len;\r
+      return ret;\r
+    }\r
+  }\r
+\r
+  // Position ourselves at a candidate TS packet\r
+  while (len > 0 && *buf != TS_SIG)\r
+  {\r
+         if (!misaligned_mess) {\r
+                 Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!B");\r
+             misaligned_mess=true; // do not alarm more than once\r
+          }\r
+    buf++; ret++; len--;\r
+  }\r
+\r
+  while (len)\r
+  {\r
+    if (len < TS_SIZE + 1)\r
+    { // Not enough data. Store what we have.\r
+      memcpy(store, buf, len);\r
+      partPacket = len;\r
+      ret += len;\r
+      return ret;\r
+    }\r
+\r
+    if (buf[TS_SIZE] != TS_SIG)\r
+    { // Not terminated correctly.\r
+      buf++; ret++; len--;\r
+      while (len > 0 && *buf != TS_SIG)\r
+      {\r
+        buf++; ret++; len--;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      int rc = processTS(buf);\r
+      if (rc)\r
+      { // Successfully processed\r
+        buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE;\r
+      }\r
+      else\r
+      { // Processing failed.\r
+        return ret;\r
+      }\r
+    }\r
+  }\r
+  return ret;\r
+}\r
+\r
+\r
+int DemuxerTS::processTS(UCHAR* buf)\r
+{\r
+  int datalen = TS_SIZE - 4;\r
+\r
+  int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];\r
+  UCHAR payload = buf[1] & 0x40;\r
+\r
+\r
+  if (buf[3] & 0x20) // Adaptation field is present\r
+    datalen -= (buf[4] + 1);\r
+  if (datalen < 0) // Error in stream TODO log this\r
+    return 1;\r
+  if (datalen == 0) // Null packet\r
+    return 1;\r
+ // if (!(buf[3] &0x10)) return 1; // no payload\r
+  buf += (TS_SIZE - datalen);\r
+\r
+  if (payload)\r
+  {\r
+      int rc = 1;\r
+      if (pid == 0x00) {//PAT, only take first program number, ignore the rest\r
+          int pmtpid = (*(buf+11)<< 8) | *(buf+12);\r
+          if ((pmtpid >> 13) != 0x07) \r
+          {\r
+              Log::getInstance()->log("ProcessTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(buf+11),*(buf+12), (pmtpid >> 13));\r
+          } \r
+          else \r
+          {\r
+              pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits\r
+              PMTPID = pmtpid;\r
+          }\r
+           return 1;\r
+    }\r
+    if (pid == PMTPID) \r
+    { //PMT\r
+        int sectionlength = ((*(buf+2) << 8) & 0x0F ) | *(buf+3);\r
+        //sectionlength += 4; //include header but subtract crc in the end...\r
+        int p = 13; //skip fixed part of pmt\r
+        Channel new_channelinfo;\r
+        new_channelinfo.numAPids=0;\r
+        new_channelinfo.numDPids=0;\r
+        new_channelinfo.numSPids=0;\r
+        new_channelinfo.number=0;\r
+        new_channelinfo.type=VDR::RADIO;\r
+        new_channelinfo.name=NULL;\r
+        new_channelinfo.tpid=0xFFFFF; //unused, check this\r
+        new_channelinfo.vpid=0xFFFFF; //unused, check this\r
+        new_channelinfo.index=0;\r
+\r
+        new_channelinfo.apids.clear();\r
+        new_channelinfo.dpids.clear();\r
+        new_channelinfo.spids.clear();\r
+        \r
+        while ( p < sectionlength) {\r
+            int streamtype = *(buf+p);\r
+            p++;\r
+            int foundpid = (*(buf+p)<< 8) | *(buf+p+1);\r
+            p += 2; //skip ES Pid\r
+            int eslength = ((*(buf+p) << 8) & 0x0F ) | *(buf+p+1);\r
+            p += 2; //skip ES length\r
+            if ((foundpid >> 13) != 0x07)\r
+            {\r
+              Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));\r
+            }\r
+            else \r
+            {\r
+                foundpid = foundpid & 0x1FFF; //clear upper 3 bits\r
+                bool notfound=false;\r
+                int pos=0;\r
+       //     Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID is %x", foundpid);\r
+                switch (streamtype)\r
+                {\r
+                case 0x1B: //MPEG 4 for future use\r
+                case 1:\r
+                case 2: { //video\r
+                    if (foundpid != getVID())  \r
+                        setVID(foundpid);\r
+                    new_channelinfo.type=VDR::VIDEO;\r
+                                       new_channelinfo.vstreamtype=streamtype;\r
+                    new_channelinfo.vpid=foundpid;\r
+                                       if (streamtype==0x1b) h264=true;\r
+                                       else h264=false;\r
+\r
+                //  Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid);\r
+                        }break;\r
+                case 3:\r
+                case 4: { //audio\r
+                    apid newapid;\r
+                    newapid.pid = foundpid;\r
+                    newapid.name = NULL; //set it in player\r
+                    new_channelinfo.apids.push_back(newapid);\r
+                    new_channelinfo.numAPids++;\r
+                    if (getAID() == 0) { //set unset AID to first audio pid that reports itself\r
+                        setAID(foundpid,0);\r
+                        Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set audio PID to %x", foundpid);\r
+                    }\r
+                        } break;\r
+                case 5:\r
+                case 6: { //Private Data \r
+                    apid newapid;\r
+                    newapid.pid = foundpid;\r
+                    newapid.name = NULL; //set it in player\r
+                    pos=0;\r
+                    notfound=true;\r
+                  \r
+                    while (pos< eslength && notfound) {\r
+                        switch (buf[p+pos]) {\r
+                        case 0x6A: {//Ac3 descriptor \r
+                            new_channelinfo.dpids.push_back(newapid);\r
+                            new_channelinfo.numDPids++;\r
+                            notfound=false;\r
+                                   } break; \r
+                       case 0x59: {//SubtitlingDescriptor\r
+                            new_channelinfo.spids.push_back(newapid);\r
+                            new_channelinfo.numSPids++;\r
+                            notfound=false;\r
+                                   } break;\r
+                       case 0x56: {\r
+                           new_channelinfo.tpid=foundpid;\r
+                           notfound=false;\r
+                                  } break;\r
+                        };\r
+                        pos+=2+buf[p+pos+1];\r
+                    }\r
+\r
+                        } break;\r
+                default://TODO how about subtitles and second audio pids\r
+                    break;\r
+                }\r
+               }\r
+           \r
+                p += eslength; //skip es descriptor\r
+        \r
+        \r
+           }\r
+        bool audioPIDpresent=false; //Check if pids chnages\r
+        ULONG i;\r
+        for (i=0;i<channelinfo.numAPids;i++) {\r
+            if (aID == (int)channelinfo.apids[i].pid) {\r
+                audioPIDpresent=true;\r
+            }\r
+        }\r
+        for (i=0;i<channelinfo.numDPids && (! audioPIDpresent);i++) {\r
+            if (aID == (int)channelinfo.dpids[i].pid) {\r
+                audioPIDpresent=true;\r
+            }\r
+        }\r
+        if (! audioPIDpresent) {\r
+            if (channelinfo.numAPids>0) {\r
+                setAID(channelinfo.apids[0].pid,0);\r
+            } else if (channelinfo.numDPids>0) {\r
+                setAID(channelinfo.dpids[0].pid,1);\r
+            }\r
+        }\r
+\r
+        channelinfo=new_channelinfo;\r
+        havechannelinfo=true;\r
+\r
+        return 1;\r
+    }\r
+    \r
+\r
+    \r
+\r
+    if (pid == vID)\r
+    {\r
+      if (vActive)\r
+      {\r
+        if (!parsed)\r
+        {\r
+          parseTSPacketDetails(vPacket);\r
+          parsed = true;\r
+        }\r
+        rc = submitPacket(vPacket);\r
+      }\r
+      vActive = true;\r
+    }\r
+    if (pid == aID)\r
+    {\r
+      if (aActive)\r
+      {\r
+        if (!parsed)\r
+        {\r
+          parseTSPacketDetails(aPacket);\r
+          parsed = true;\r
+        }\r
+        rc = submitPacket(aPacket);\r
+      }\r
+      aActive = true;\r
+    }\r
+    if (pid == subID)\r
+    {\r
+      if (subActive)\r
+      {\r
+        if (!parsed)\r
+        {\r
+          parseTSPacketDetails(subPacket);\r
+          parsed = true;\r
+        }\r
+        rc = submitPacket(subPacket);\r
+      }\r
+      subActive = true;\r
+    }\r
+    if (isteletextdecoded && pid == tID)\r
+    {\r
+      if (tActive)\r
+      {\r
+        if (!parsed)\r
+        {\r
+          parseTSPacketDetails(tPacket);\r
+          parsed = true;\r
+        }\r
+      rc = submitPacket(tPacket);\r
+      }\r
+      tActive = true;\r
+    }\r
+    if (rc == 0) return 0;\r
+\r
+    parsed = false;\r
+    if (pid == vID)\r
+    {\r
+      vPacket.init(PESTYPE_VID0);\r
+      buf += 6; datalen -= 6;\r
+    }\r
+    if (pid == aID)\r
+    {\r
+      switch (atype)\r
+      {\r
+      case 1:\r
+        aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);\r
+        break;\r
+      default:\r
+      case 0:\r
+        aPacket.init(PESTYPE_AUD0);\r
+        break;\r
+      }\r
+      buf += 6; datalen -= 6;\r
+    }\r
+    if (pid == subID)\r
+    {\r
+      subPacket.init(PESTYPE_PRIVATE_1);\r
+      subLength = (buf[4] << 8) + buf[5];\r
+      buf += 6; datalen -= 6;\r
+    }\r
+    if (isteletextdecoded && pid == tID)\r
+    {\r
+        tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);\r
+      buf += 6; datalen -= 6;\r
+    }\r
+  }\r
+\r
+  if ( (pid == vID && vActive) ||\r
+       (pid == aID && aActive) ||\r
+       (pid == tID && tActive) ||\r
+       (pid == subID && subActive) )\r
+  {\r
+    PESPacket* packet = NULL;\r
+    if (pid == vID) packet = &vPacket;\r
+    if (pid == aID) packet = &aPacket;\r
+    if (pid == subID) {\r
+      packet = &subPacket;\r
+    }\r
+    if (pid == tID) packet = &tPacket;\r
+    if (packet != NULL)\r
+    {\r
+      if (packet->write(buf, datalen) == 0)\r
+      { // Writing to packet failed. It has overflowed.\r
+        if (!parsed)\r
+        {\r
+          parseTSPacketDetails(*packet);\r
+          parsed = true;\r
+        }\r
+        if (submitPacket(*packet) == 0) return 0;\r
+        parsed = false;\r
+        packet->truncate();\r
+        packet->write((UCHAR*)"\200\000\000", 3);\r
+        packet->write(buf, datalen);\r
+      }\r
+    }\r
+  }\r
+\r
+  if (pid == subID && subActive && subPacket.getLength() == subLength)\r
+  {\r
+    parsePacketDetails(subPacket);\r
+Log::getInstance()->log("DEMUXERTS", Log::DEBUG, "SUBMITTING A SUBTITLE PACKET %d %x", subLength, subPacket.getSubstream());\r
+    submitPacket(subPacket);\r
+    subActive = false;\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+ULONG DemuxerTS::getPacketNum()\r
+{\r
+  return packetNumber;\r
+}\r
+\r
+ULONG DemuxerTS::getFrameNumFromPTS(ULLONG pts)\r
+{\r
+  ULLONG difference = (1LL<<33);\r
+  ULONG ref_frame = 0;\r
+  int total = 0, actual = 0;\r
+  if (pts==0) return 0; //we are in startup\r
+  pts_map_mutex.Lock();\r
+  PTSMap::iterator iter = pts_map.begin();\r
+  while (iter != pts_map.end())\r
+  {\r
+    ++total;\r
+     //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts1 %lld pts2 %lld", pts, iter->pts);\r
+    if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)\r
+    {\r
+      difference = 0;\r
+      ref_frame = iter->frame;\r
+      actual = total;\r
+      break;\r
+    }\r
+    ULLONG newdiff = PTSDifference(pts, iter->pts);\r
+    if (newdiff < difference)\r
+    {\r
+      difference = newdiff;\r
+      ref_frame = iter->frame;\r
+      actual = total;\r
+    }\r
+    ++iter;\r
+  }\r
+  if (total > 1 && actual == 1) // We are using the most recent PTS ref.\r
+  {                             // Delete the rest.\r
+    iter = pts_map.begin(); iter++;\r
+    pts_map.erase(iter, pts_map.end());\r
+  }\r
+  pts_map_mutex.Unlock();\r
+  \r
+ Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts %lld deleted %d difference %lld", pts, total,difference);\r
+\r
+  if (difference == (1LL<<33))\r
+    return 0; // We cannot make sense of the pts\r
+  else\r
+    return ref_frame + difference * fps / 90000;\r
+}\r
+\r
+\r
+void DemuxerTS::parseTSPacketDetails(PESPacket &packet) // Only important stuff for paket counting reminas\r
+{\r
+    parsePacketDetails(packet);\r
+    if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&\r
+                        packet.getPacketType() <= PESTYPE_AUDMAX)\r
+    {\r
+        packetNumber++;\r
+    }\r
+    UINT pictsinpacket=packet.countPictureHeaders(h264);\r
+    \r
+    UINT numpicts=0;\r
+  /*  if (!doubledframerate)\r
+    {*/\r
+        numpicts=pictsinpacket;\r
+  /*  }\r
+    else\r
+    {\r
+        numpicts=(pictsinpacket+framereserve)>>1;\r
+        framereserve=(pictsinpacket+framereserve)%2;\r
+    }*/\r
+\r
+\r
+  if (frameCounting && numpicts &&\r
+      packet.getPacketType() >= PESTYPE_VID0 &&\r
+      packet.getPacketType() <= PESTYPE_VIDMAX)\r
+  {\r
+    frameNumber+=numpicts;\r
+    ULONG frame_num = frameNumber;\r
+    if ((h264 || packet.findSeqHeader(h264) > 1) && packet.hasPTS())\r
+    {\r
+      PTSMapEntry me;\r
+      pts_map_mutex.Lock();\r
+      if (pts_map.empty())\r
+      {\r
+        me.pts = packet.getPTS();\r
+        me.frame = frame_num;\r
+        pts_map_mutex.Unlock();\r
+        pts_map_mutex.Lock();\r
+        pts_map.push_front(me);\r
+      }\r
+      me = pts_map.front();\r
+      pts_map_mutex.Unlock();\r
+\r
+      //UINT fps = Video::getInstance()->getFPS();\r
+      double tfps=fps;\r
+     // if (doubledframerate) tfps*=2.;\r
+      ULLONG pts_expected = me.pts + 90000*((int)(((double)(frame_num - me.frame)) / tfps));\r
+      while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);\r
+\r
+      // this was a workaround for a vdr bug, now fixed, for older recordings deleter the index file\r
+\r
+      /*\r
+      if (!doubledframerate \r
+          &&(abs((long long)PTSDistance(pts_expected, packet.getPTS())-1800) <= 1 \r
+          || abs((long long)PTSDistance(pts_expected, packet.getPTS())-1501) <= 1)) {\r
+              doubledframerate=true; //Detected  p50 or p60\r
+      }*/\r
+\r
+      if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!\r
+      {\r
+        me.pts = packet.getPTS();\r
+        me.frame = frame_num;\r
+        pts_map_mutex.Lock();\r
+        pts_map.push_front(me);\r
+        pts_map_mutex.Unlock();\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+\r
+bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len, bool &ish264)\r
+{\r
+    int pmtpidy=0;\r
+\r
+  while (len >= TS_SIZE)\r
+  {\r
+      if (*buf != TS_SIG) {buf++;len--; continue;} \r
+\r
+    //Pattern scanning won't work for ts\r
+\r
+      \r
+      int datalen = TS_SIZE - 4;\r
+      int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];\r
+      UCHAR payload = buf[1] & 0x40;\r
+      \r
+      if (buf[3] & 0x20) // Adaptation field is present\r
+          datalen -= (buf[4] + 1);\r
+\r
+      UCHAR* curbuf =buf+ (TS_SIZE - datalen);\r
+     \r
+      if (payload) {\r
+          if (pid == 0x00) {//PAT, only take first program number, ignore the rest\r
+              int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);\r
+              if ((pmtpid >> 13) != 0x07) \r
+              {\r
+                  Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));\r
+              } \r
+              else \r
+              {\r
+                  pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits\r
+                  pmtpidy = pmtpid;\r
+                                 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMT pid%02x",pmtpid );\r
+              }\r
+          \r
+          } else if (pid == pmtpidy) { //PMT\r
+              int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);\r
+              //sectionlength += 4; //include header but subtract crc in the end...\r
+              int p = 13; //skip fixed part of pmt\r
+              while ( p < sectionlength) {\r
+                  int streamtype = *(curbuf+p);\r
+                  p++;\r
+                  int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);\r
+                  p += 2; //skip ES Pid\r
+                  int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);\r
+                  p += 2; //skip ES length\r
+                  if ((foundpid >> 13) != 0x07)\r
+                  {\r
+                      Log::getInstance()->log("DemuxerTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));\r
+                  }\r
+                  else \r
+                  {\r
+                      foundpid = foundpid & 0x1FFF; //clear upper 3 bits\r
+                   //   int pos=0; UNUSED?\r
+                                         Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Pid found %02x type %02x",foundpid ,streamtype);\r
+                      if (streamtype==1 || streamtype ==2) {\r
+                                                 ish264=false;\r
+                                                 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found Mpeg2 Video");\r
+                          return true;\r
+                      }\r
+                                         if (streamtype==0x1b) {\r
+                                                 ish264=true;\r
+                                                 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found h264 Video");\r
+                                                 return true;\r
+                                         }\r
+                  }\r
+                  p += eslength; //skip es descriptor\r
+              }\r
+                         ish264=false;\r
+              return false;\r
+          } \r
+      }\r
+      len-=TS_SIZE;\r
+      buf+=TS_SIZE;\r
+  }\r
+  ish264=false;\r
+  return false;\r
+}\r
+\r
+UINT DemuxerTS::stripAudio(UCHAR* buf, UINT len) //it has to be adapted\r
+{ \r
+    //This function strips all TS Headers and non video payload\r
+    UINT readpos=0;\r
+    UINT writepos=0;\r
+    PESPacket destpaket;\r
+    bool started=true;\r
+    while (readpos < len ) {\r
+        if (buf[readpos] != TS_SIG) {readpos++; continue;} \r
+        UINT oldreadpos=readpos;\r
+\r
+        int datalen = TS_SIZE - 4;\r
+        int pid = ( (buf[readpos+1] & 0x1F) << 8 ) | buf[readpos+2];\r
+        UCHAR payload = buf[readpos+1] & 0x40;\r
+        if (buf[readpos+3] & 0x20) { // Adaptation field is present\r
+           datalen -= (buf[readpos+4] + 1);\r
+        }\r
+        if (datalen < 0) {// Error in stream TODO log this\r
+            return 0;\r
+        }\r
+        if (datalen == 0) {// Null packet\r
+             readpos=oldreadpos+TS_SIZE;\r
+            continue;\r
+        }\r
+        readpos += (TS_SIZE - datalen);\r
+        UINT towrite=min(datalen,len-readpos);\r
+        if (pid == vID) {\r
+            if (payload) {\r
+                if (started) {\r
+                    parsePacketDetails(destpaket);\r
+                    memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());\r
+                    writepos+=destpaket.getSize();\r
+                 }\r
+                 destpaket.init(PESTYPE_VID0);\r
+                 readpos += 6; towrite -= 6;\r
+                 started=true;\r
+            }\r
+\r
+            if (started) {\r
+                if (!destpaket.write(buf+readpos,towrite)) {\r
+                    parsePacketDetails(destpaket);\r
+                    memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());\r
+                    writepos+=destpaket.getSize();\r
+                    destpaket.truncate();\r
+                                       destpaket.write((UCHAR*)"\200\000\000", 3);\r
+                    destpaket.write(buf+readpos,towrite);\r
+\r
+                }\r
+            }\r
+            \r
+       \r
+\r
+        }\r
+        readpos=oldreadpos+TS_SIZE;\r
+    }\r
+    parsePacketDetails(destpaket);\r
+    memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());\r
+    writepos+=destpaket.getSize();\r
\r
+    return writepos;\r
+}    \r
+\r
+\r
+\r
index 9023d3c6f9e438e7fc43b706abe6dc9cca5e89cb..24e5b4d957a072eea415325675c933a9a9c611ee 100644 (file)
@@ -1,96 +1,96 @@
-/*
-    Copyright 2006-2007 Mark Calderbank
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef DEMUXERTS_H
-#define DEMUXERTS_H
-
-#include "mutex.h"
-#include <deque>
-
-#include "demuxer.h"
-#include "defines.h"
-#include "channel.h"
-
-#define TS_SIZE 188
-#define TS_SIG  0x47
-
-class DemuxerTS : public Demuxer
-{
-  public:
-    DemuxerTS(int p_vID = 0, int p_aID = 0, int p_subID = 0, int p_tID = 0);    
-    void flush();
-    int scan(UCHAR* buf, int len);
-    int findPTS(UCHAR* buf, int len, ULLONG* dest);
-    void setVID(int p_vID);
-    void setTID(int p_tID);
-    void setAID(int p_aID, int type);
-    void setSubID(int p_subID);
-    int  getVID() { return vID; }
-    int  getTID() { return tID; }
-    int  getAID() { return aID; }
-    int  getSubID() { return subID; }
-    int put(UCHAR* buf, int len);
-
-    void setFrameNum(ULONG frame);
-    void setPacketNum(ULONG npacket);
-    ULONG getFrameNumFromPTS(ULLONG pts);
-    ULONG getPacketNum();
-    UINT stripAudio(UCHAR* buf, UINT len);
-    static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264);
-    Channel getChannelInfo() {return channelinfo;};
-
-
-  private:
-    int processTS(UCHAR* buf);
-
-    UCHAR store[TS_SIZE]; // Storage for partial packets
-    int partPacket;    // Length of partial packet stored from previous put()
-    bool parsed;       // Whether PES packet to be submitted has been parsed yet
-    PESPacket vPacket; // Video PES packet under construction
-    PESPacket aPacket; // Audio PES packet under construction
-    PESPacket subPacket; // Subtitles PES packet under construction
-    PESPacket tPacket; // Teletext PES packet under construction
-    int vID, aID, subID,tID; // TS IDs for video/audio/subtitles   
-    int PMTPID; //TODO HANS which of these do I Need:
-
-    int atype;
-    bool subActive;        // Same for subtitles
-    UINT subLength;        // Expected length of subtitle packet   
-    bool vActive, aActive, tActive; // Whether video/audio is actively being captured
-
-    bool havechannelinfo;
-    Channel channelinfo;
-    
-
-    //TODO HANS which of next do I need
-    ULONG frameNumber, packetNumber;
-    bool frameCounting, packetCounting;
-    bool doubledframerate;
-    int framereserve;
-    typedef struct { ULLONG pts; ULONG frame; } PTSMapEntry;
-    typedef std::deque<PTSMapEntry> PTSMap;
-    PTSMap pts_map;
-    Mutex pts_map_mutex;
-    void parseTSPacketDetails(PESPacket &packet);
-   
-
-};
-
-#endif
+/*\r
+    Copyright 2006-2007 Mark Calderbank\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef DEMUXERTS_H\r
+#define DEMUXERTS_H\r
+\r
+#include "mutex.h"\r
+#include <deque>\r
+\r
+#include "demuxer.h"\r
+#include "defines.h"\r
+#include "channel.h"\r
+\r
+#define TS_SIZE 188\r
+#define TS_SIG  0x47\r
+\r
+class DemuxerTS : public Demuxer\r
+{\r
+  public:\r
+    DemuxerTS(int p_vID = 0, int p_aID = 0, int p_subID = 0, int p_tID = 0);    \r
+    void flush();\r
+    int scan(UCHAR* buf, int len);\r
+    int findPTS(UCHAR* buf, int len, ULLONG* dest);\r
+    void setVID(int p_vID);\r
+    void setTID(int p_tID);\r
+    void setAID(int p_aID, int type);\r
+    void setSubID(int p_subID);\r
+    int  getVID() { return vID; }\r
+    int  getTID() { return tID; }\r
+    int  getAID() { return aID; }\r
+    int  getSubID() { return subID; }\r
+    int put(UCHAR* buf, int len);\r
+\r
+    void setFrameNum(ULONG frame);\r
+    void setPacketNum(ULONG npacket);\r
+    ULONG getFrameNumFromPTS(ULLONG pts);\r
+    ULONG getPacketNum();\r
+    UINT stripAudio(UCHAR* buf, UINT len);\r
+    static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264);\r
+    Channel getChannelInfo() {return channelinfo;};\r
+\r
+\r
+  private:\r
+    int processTS(UCHAR* buf);\r
+\r
+    UCHAR store[TS_SIZE]; // Storage for partial packets\r
+    int partPacket;    // Length of partial packet stored from previous put()\r
+    bool parsed;       // Whether PES packet to be submitted has been parsed yet\r
+    PESPacket vPacket; // Video PES packet under construction\r
+    PESPacket aPacket; // Audio PES packet under construction\r
+    PESPacket subPacket; // Subtitles PES packet under construction\r
+    PESPacket tPacket; // Teletext PES packet under construction\r
+    int vID, aID, subID,tID; // TS IDs for video/audio/subtitles   \r
+    int PMTPID; //TODO HANS which of these do I Need:\r
+\r
+    int atype;\r
+    bool subActive;        // Same for subtitles\r
+    UINT subLength;        // Expected length of subtitle packet   \r
+    bool vActive, aActive, tActive; // Whether video/audio is actively being captured\r
+\r
+    bool havechannelinfo;\r
+    Channel channelinfo;\r
+    \r
+\r
+    //TODO HANS which of next do I need\r
+    ULONG frameNumber, packetNumber;\r
+    bool frameCounting, packetCounting;\r
+   // bool doubledframerate;\r
+    int framereserve;\r
+    typedef struct { ULLONG pts; ULONG frame; } PTSMapEntry;\r
+    typedef std::deque<PTSMapEntry> PTSMap;\r
+    PTSMap pts_map;\r
+    Mutex pts_map_mutex;\r
+    void parseTSPacketDetails(PESPacket &packet);\r
+   \r
+\r
+};\r
+\r
+#endif\r
index abcb921928de4e859cf67dc346bd311ffeb5601a..c3ddfa5067999f58ded48ca897d627771d5f5c15 100644 (file)
-/*
-    Copyright 2005-2008 Mark Calderbank
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "demuxervdr.h"
-#include "video.h"
-#include "dvbsubtitles.h"
-#include "log.h"
-
-#ifndef WIN32
-#include <endian.h>
-#else
-#define __LITTLE_ENDIAN 1234
-#define __BIG_ENDIAN  4321
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
-
-#define PTS_JUMP_MARGIN   10000
-#define PTS_ALLOWANCE 90000
-
-// TODO: PTS class to handle wrapping arithmetic & comparisons?
-static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)
-{
-  // Assume pts1, pts2 < 2^33; calculate shortest distance between
-  ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;
-  if (ret > (1LL<<32)) ret = (1LL<<33) - ret;
-  return ret;
-}
-
-static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
-{
-  // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
-  if (pts1 > pts2)
-    return pts1 - pts2;
-  else
-    return (1LL<<33) + pts1 - pts2;
-}
-
-DemuxerVDR::DemuxerVDR()
-{
-  frameCounting = false;
-  packetCounting = false;
-  subtitlePacketPosition = 0;
-}
-
-void DemuxerVDR::reset()
-{
-  frameCounting = false;
-  packetCounting = false;
-  pts_map.clear();
-  Demuxer::reset();
-}
-
-void DemuxerVDR::flush()
-{
-  state = 0;
-  submitting = false;
-  subtitlePacketPosition = 0;
-  Demuxer::flush();
-}
-
-int DemuxerVDR::scan(UCHAR *buf, int len)
-{
-  // Temporarily, just look for the lowest audio stream and return it
-  UCHAR HiByte = PESTYPE_AUDMAX;
-  int ret = 0;
-
-  while (len >= 4)
-  {
-    UINT pattern = *(UINT*)buf;
-    buf++; len--;
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-    if (pattern < (UINT)(0x100 | PESTYPE_AUD0) ||
-        pattern > (UINT)(0x100 | HiByte)) continue;
-    HiByte = pattern & 0xFF;
-#else
-    if ((pattern & 0xFFFFFF) != 0x010000 ||
-         pattern < ((UINT)PESTYPE_AUD0 << 24) ||
-         pattern > ((UINT)HiByte << 24)) continue;
-    HiByte = pattern >> 24;
-#endif
-    ret = HiByte;
-    if (HiByte == PESTYPE_AUD0) break;
-  }
-  return ret;
-}
-
-int DemuxerVDR::findPTS(UCHAR* buf, int len, ULLONG* dest)
-{
-  while (len >= 14)
-  {
-    UINT pattern = *(UINT*)buf;
-    buf++; len--;
-#if __BYTE_ORDER == __BIG_ENDIAN
-    if (pattern < (0x100 | PESTYPE_AUD0) ||
-        pattern > (0x100 | PESTYPE_VIDMAX)) continue;
-#else
-    if ((pattern & 0xFFFFFF) != 0x010000 ||
-         pattern < ((UINT)PESTYPE_AUD0 << 24) ||
-         pattern > ((UINT)PESTYPE_VIDMAX << 24)) continue;
-#endif
-    if ((buf[5] & 0xC0) != 0x80) continue;
-
-    UINT packetlength = ((UINT)buf[3] << 8) | buf[4];
-
-    if ( buf[6] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
-    {
-      if ( (buf[8]  & 0x01) != 0x01 ||
-           (buf[10] & 0x01) != 0x01 ||
-           (buf[12] & 0x01) != 0x01) continue;
-
-      *dest = ( (ULLONG)(buf[8]  & 0x0E) << 29 ) |
-              ( (ULLONG)(buf[9])         << 22 ) |
-              ( (ULLONG)(buf[10] & 0xFE) << 14 ) |
-              ( (ULLONG)(buf[11])        <<  7 ) |
-              ( (ULLONG)(buf[12] & 0xFE) >>  1 );
-      return 1;
-    }
-
-    buf += 5; len -= 5;
-    buf += packetlength; len -= packetlength;
-  }
-  // No PTS found.
-  return 0;
-}
-
-void DemuxerVDR::setFrameNum(ULONG frame)
-{
-  frameCounting = true;
-  frameNumber = frame;
-  Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame);
-}
-
-void DemuxerVDR::setPacketNum(ULONG npacket)
-{
-  packetCounting = true;
-  packetNumber = npacket;
-  Log::getInstance()->log("Demuxer", Log::DEBUG, "setPacketNum %d", npacket);
-}
-
-int DemuxerVDR::put(UCHAR* buf, int len)
-{
-  int ret = 0;    // return number of bytes consumed
-  if (submitting)
-  {
-    if (submitPacket(packet) == 0) // Still full!
-      return ret;
-    else
-      submitting = false;
-  }
-
-  if (state > 0) // We are half way through a PES packet.
-  {
-    if (len >= state) // The remainder of the packet is available.
-    {
-      packet.write(buf, state);
-      buf += state; len -= state; ret += state;
-      state = 0;
-      parseVDRPacketDetails();
-      if (submitPacket(packet) == 0) // Stream is full
-      {
-        submitting = true;
-        return ret;
-      }
-    }
-    else // Write what we have, then exit.
-    {
-      packet.write(buf, len);
-      state -= len;
-      return len;
-    }
-  }
-
-  while (len > 0)
-  {
-    switch (state)
-    {
-      case  0:
-      case -1:
-        if (*buf == 0x00) state--; else state = 0;
-        buf++; len--; ret++;
-        break;
-      case -2:
-        if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
-        buf++; len--; ret++;
-        break;
-      case -3:
-        if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
-            (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
-            (*buf == PESTYPE_PRIVATE_1))
-        {
-          packet.init(*buf);
-          state--;
-        }
-        else if (*buf == 0x00)
-          state = -1;
-        else
-          state = 0;
-        buf++; len--; ret++;
-        break;
-      case -4:
-        packetLength = ((UINT)*buf) << 8;
-        state--;
-        buf++; len--; ret++;
-        break;
-      case -5:
-        packetLength += *buf;
-        state--;
-        buf++; len--; ret++;
-        break;
-    }
-
-    if (state == -6) // Packet header complete
-    {
-      if (len >= packetLength) // The entire packet is available.
-      {
-        packet.write(buf, packetLength);
-        buf += packetLength; len -= packetLength; ret += packetLength;
-        state = 0;
-        parseVDRPacketDetails();
-        if (submitPacket(packet) == 0) // Stream is full
-        {
-          submitting = true;
-          return ret;
-        }
-      }
-      else // Write what we have.
-      {
-        packet.write(buf, len);
-        state = packetLength - len;
-        ret += len;
-        len = 0;
-      }
-    }
-  }
-  return ret;
-}
-
-ULONG DemuxerVDR::getPacketNum()
-{
-  return packetNumber;
-}
-
-ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)
-{
-  ULLONG difference = (1LL<<33);
-  ULONG ref_frame = 0;
-  int total = 0, actual = 0;
-  pts_map_mutex.Lock();
-  PTSMap::iterator iter = pts_map.begin();
-  while (iter != pts_map.end())
-  {
-    ++total;
-    if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
-    {
-      difference = 0;
-      ref_frame = iter->frame;
-      actual = total;
-      break;
-    }
-    ULLONG newdiff = PTSDifference(pts, iter->pts);
-    if (newdiff < difference)
-    {
-      difference = newdiff;
-      ref_frame = iter->frame;
-      actual = total;
-    }
-    ++iter;
-  }
-  if (total > 1 && actual == 1) // We are using the most recent PTS ref.
-  {                             // Delete the rest.
-    iter = pts_map.begin(); iter++;
-    pts_map.erase(iter, pts_map.end());
-  }
-  pts_map_mutex.Unlock();
-
-  if (difference == (1LL<<33))
-    return 0; // We cannot make sense of the pts
-  else
-    return ref_frame + (ULONG)((double) (difference / 90000) *fps);
-}
-
-void DemuxerVDR::dealWithSubtitlePacket()
-{
-  const UCHAR* data = packet.getData();
-  UINT packetSize = packet.getSize();
-  if (packetSize < 9) return;
-  UINT payloadOffset = data[8] + 9;
-  if (packetSize < payloadOffset + 5) return;
-  if (data[payloadOffset + 3] == 0x00)
-  { // Not a continuation packet
-    if (packetSize < payloadOffset + 7) return;
-    subtitlePacket.init(data[3]);
-    subtitlePacket.write(&data[6], payloadOffset - 6);
-    subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
-    subtitlePacketPosition = payloadOffset + 2;
-  }
-  else
-  { // Continuation packet
-    if (subtitlePacketPosition == 0) return;
-    subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
-  }
-  
-  const UCHAR* sub_data = subtitlePacket.getData();
-  UINT subSize = subtitlePacket.getSize();
-  while (subtitlePacketPosition < subSize)
-  {
-    if (sub_data[subtitlePacketPosition] == 0xFF)
-    { // Packet is complete. Switch it into the "real" packet to be submitted.
-      packet = subtitlePacket;
-      parsePacketDetails(packet);
-      subtitlePacketPosition = 0; // Wait for next non-continuation packet
-      break;
-    }
-    if (sub_data[subtitlePacketPosition] != 0x0F)
-    {
-      subtitlePacketPosition = 0; // Wait for next non-continuation packet
-      break;
-    }
-    if (subSize < subtitlePacketPosition + 6) break;
-    UINT segmentLength = (sub_data[subtitlePacketPosition + 4] << 8)
-                        + sub_data[subtitlePacketPosition + 5];
-    subtitlePacketPosition += segmentLength + 6;
-  }
-}
-
-void DemuxerVDR::parseVDRPacketDetails()
-{
-  if (packet.getPacketType() == PESTYPE_PRIVATE_1 && packet.getSize() > 8)
-  {
-    UINT payload_begin = packet[8] + 9;
-    if (packet.getSize() > payload_begin)
-    {
-      UCHAR substream_type = packet[payload_begin] & 0xF0;
-      if (substream_type == 0x20) // Subtitles
-      {
-        dealWithSubtitlePacket();
-      }
-      else // Not subtitles
-        parsePacketDetails(packet);
-    }
-  }
-  else // Not a private packet*/
-    parsePacketDetails(packet);
-
-  if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
-                        packet.getPacketType() <= PESTYPE_AUDMAX)
-  {
-    packetNumber++;
-  }
-
-  if (frameCounting && packet.findPictureHeader(h264) &&
-      packet.getPacketType() >= PESTYPE_VID0 &&
-      packet.getPacketType() <= PESTYPE_VIDMAX)
-  {
-    ULONG frame_num = (frameNumber)++;
-    if (packet.findSeqHeader(h264) > 1 && packet.hasPTS())
-    {
-      PTSMapEntry me;
-      pts_map_mutex.Lock();
-      if (pts_map.empty())
-      {
-        me.pts = packet.getPTS();
-        me.frame = frame_num;
-        pts_map_mutex.Unlock();
-Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me.frame);
-        pts_map_mutex.Lock();
-        pts_map.push_front(me);
-      }
-      me = pts_map.front();
-      pts_map_mutex.Unlock();
-
-//      UINT fps = Video::getInstance()->getFPS();
-      ULLONG pts_expected = me.pts + 90000*((ULONG)((double)(frame_num - me.frame)) / fps);
-      while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
-
-      if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
-      {
-Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS JUMP *+ %llu %u", packet.getPTS(), frame_num);
-        me.pts = packet.getPTS();
-        me.frame = frame_num;
-        pts_map_mutex.Lock();
-        pts_map.push_front(me);
-        pts_map_mutex.Unlock();
-      }
-    }
-  }
-}
+/*\r
+    Copyright 2005-2008 Mark Calderbank\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software Foundation, Inc.,\r
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "demuxervdr.h"\r
+#include "video.h"\r
+#include "dvbsubtitles.h"\r
+#include "log.h"\r
+\r
+#ifndef WIN32\r
+#include <endian.h>\r
+#else\r
+#define __LITTLE_ENDIAN 1234\r
+#define __BIG_ENDIAN  4321\r
+#define __BYTE_ORDER __LITTLE_ENDIAN\r
+#endif\r
+\r
+#define PTS_JUMP_MARGIN   10000\r
+#define PTS_ALLOWANCE 90000\r
+\r
+// TODO: PTS class to handle wrapping arithmetic & comparisons?\r
+static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)\r
+{\r
+  // Assume pts1, pts2 < 2^33; calculate shortest distance between\r
+  ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;\r
+  if (ret > (1LL<<32)) ret = (1LL<<33) - ret;\r
+  return ret;\r
+}\r
+\r
+static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)\r
+{\r
+  // Assume pts1, pts2 < 2^33; calculate pts1 - pts2\r
+  if (pts1 > pts2)\r
+    return pts1 - pts2;\r
+  else\r
+    return (1LL<<33) + pts1 - pts2;\r
+}\r
+\r
+DemuxerVDR::DemuxerVDR()\r
+{\r
+  frameCounting = false;\r
+  packetCounting = false;\r
+  subtitlePacketPosition = 0;\r
+}\r
+\r
+void DemuxerVDR::reset()\r
+{\r
+  frameCounting = false;\r
+  packetCounting = false;\r
+  pts_map.clear();\r
+  Demuxer::reset();\r
+}\r
+\r
+void DemuxerVDR::flush()\r
+{\r
+  state = 0;\r
+  submitting = false;\r
+  subtitlePacketPosition = 0;\r
+  Demuxer::flush();\r
+}\r
+\r
+int DemuxerVDR::scan(UCHAR *buf, int len) {\r
+       // Temporarily, just look for the lowest audio stream and return it\r
+       UCHAR HiByte = PESTYPE_AUDMAX;\r
+       int ret = 0;\r
+\r
+       while (len >= 4) {\r
+               UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];\r
+               buf++;\r
+               len--;\r
+\r
+               if (pattern < (UINT)(0x100 | PESTYPE_AUD0) || pattern > (UINT)(\r
+                               0x100 | HiByte))\r
+                       continue;\r
+               HiByte = pattern & 0xFF;\r
+\r
+               ret = HiByte;\r
+               if (HiByte == PESTYPE_AUD0)\r
+                       break;\r
+       }\r
+       return ret;\r
+}\r
+\r
+int DemuxerVDR::findPTS(UCHAR* buf, int len, ULLONG* dest) {\r
+       while (len >= 14) {\r
+               UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];\r
+               buf++;\r
+               len--;\r
+               if (pattern < (0x100 | PESTYPE_AUD0) || pattern > (0x100\r
+                               | PESTYPE_VIDMAX))\r
+                       continue;\r
+\r
+               if ((buf[5] & 0xC0) != 0x80)\r
+                       continue;\r
+\r
+               UINT packetlength = ((UINT) buf[3] << 8) | buf[4];\r
+\r
+               if (buf[6] & 0x80) // PTS_DTS_flags indicate that PTS is present\r
+               {\r
+                       if ((buf[8] & 0x01) != 0x01 || (buf[10] & 0x01) != 0x01 || (buf[12]\r
+                                       & 0x01) != 0x01)\r
+                               continue;\r
+\r
+                       *dest = ((ULLONG)(buf[8] & 0x0E) << 29) | ((ULLONG)(buf[9]) << 22)\r
+                                       | ((ULLONG)(buf[10] & 0xFE) << 14) | ((ULLONG)(buf[11])\r
+                                       << 7) | ((ULLONG)(buf[12] & 0xFE) >> 1);\r
+                       return 1;\r
+               }\r
+\r
+               buf += 5;\r
+               len -= 5;\r
+               buf += packetlength;\r
+               len -= packetlength;\r
+       }\r
+       // No PTS found.\r
+       return 0;\r
+}\r
+\r
+void DemuxerVDR::setFrameNum(ULONG frame)\r
+{\r
+  frameCounting = true;\r
+  frameNumber = frame;\r
+  Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame);\r
+}\r
+\r
+void DemuxerVDR::setPacketNum(ULONG npacket)\r
+{\r
+  packetCounting = true;\r
+  packetNumber = npacket;\r
+  Log::getInstance()->log("Demuxer", Log::DEBUG, "setPacketNum %d", npacket);\r
+}\r
+\r
+int DemuxerVDR::put(UCHAR* buf, int len)\r
+{\r
+  int ret = 0;    // return number of bytes consumed\r
+  if (submitting)\r
+  {\r
+    if (submitPacket(packet) == 0) // Still full!\r
+      return ret;\r
+    else\r
+      submitting = false;\r
+  }\r
+\r
+  if (state > 0) // We are half way through a PES packet.\r
+  {\r
+    if (len >= state) // The remainder of the packet is available.\r
+    {\r
+      packet.write(buf, state);\r
+      buf += state; len -= state; ret += state;\r
+      state = 0;\r
+      parseVDRPacketDetails();\r
+      if (submitPacket(packet) == 0) // Stream is full\r
+      {\r
+        submitting = true;\r
+        return ret;\r
+      }\r
+    }\r
+    else // Write what we have, then exit.\r
+    {\r
+      packet.write(buf, len);\r
+      state -= len;\r
+      return len;\r
+    }\r
+  }\r
+\r
+  while (len > 0)\r
+  {\r
+    switch (state)\r
+    {\r
+      case  0:\r
+      case -1:\r
+        if (*buf == 0x00) state--; else state = 0;\r
+        buf++; len--; ret++;\r
+        break;\r
+      case -2:\r
+        if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;\r
+        buf++; len--; ret++;\r
+        break;\r
+      case -3:\r
+        if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||\r
+            (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||\r
+            (*buf == PESTYPE_PRIVATE_1))\r
+        {\r
+          packet.init(*buf);\r
+          state--;\r
+        }\r
+        else if (*buf == 0x00)\r
+          state = -1;\r
+        else\r
+          state = 0;\r
+        buf++; len--; ret++;\r
+        break;\r
+      case -4:\r
+        packetLength = ((UINT)*buf) << 8;\r
+        state--;\r
+        buf++; len--; ret++;\r
+        break;\r
+      case -5:\r
+        packetLength += *buf;\r
+        state--;\r
+        buf++; len--; ret++;\r
+        break;\r
+    }\r
+\r
+    if (state == -6) // Packet header complete\r
+    {\r
+      if (len >= packetLength) // The entire packet is available.\r
+      {\r
+        packet.write(buf, packetLength);\r
+        buf += packetLength; len -= packetLength; ret += packetLength;\r
+        state = 0;\r
+        parseVDRPacketDetails();\r
+        if (submitPacket(packet) == 0) // Stream is full\r
+        {\r
+          submitting = true;\r
+          return ret;\r
+        }\r
+      }\r
+      else // Write what we have.\r
+      {\r
+        packet.write(buf, len);\r
+        state = packetLength - len;\r
+        ret += len;\r
+        len = 0;\r
+      }\r
+    }\r
+  }\r
+  return ret;\r
+}\r
+\r
+ULONG DemuxerVDR::getPacketNum()\r
+{\r
+  return packetNumber;\r
+}\r
+\r
+ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)\r
+{\r
+  ULLONG difference = (1LL<<33);\r
+  ULONG ref_frame = 0;\r
+  int total = 0, actual = 0;\r
+  pts_map_mutex.Lock();\r
+  PTSMap::iterator iter = pts_map.begin();\r
+  while (iter != pts_map.end())\r
+  {\r
+    ++total;\r
+    if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)\r
+    {\r
+      difference = 0;\r
+      ref_frame = iter->frame;\r
+      actual = total;\r
+      break;\r
+    }\r
+    ULLONG newdiff = PTSDifference(pts, iter->pts);\r
+    if (newdiff < difference)\r
+    {\r
+      difference = newdiff;\r
+      ref_frame = iter->frame;\r
+      actual = total;\r
+    }\r
+    ++iter;\r
+  }\r
+  if (total > 1 && actual == 1) // We are using the most recent PTS ref.\r
+  {                             // Delete the rest.\r
+    iter = pts_map.begin(); iter++;\r
+    pts_map.erase(iter, pts_map.end());\r
+  }\r
+  pts_map_mutex.Unlock();\r
+\r
+  if (difference == (1LL<<33))\r
+    return 0; // We cannot make sense of the pts\r
+  else\r
+    return ref_frame + (ULONG)((double) (difference / 90000) *fps);\r
+}\r
+\r
+void DemuxerVDR::dealWithSubtitlePacket()\r
+{\r
+  const UCHAR* data = packet.getData();\r
+  UINT packetSize = packet.getSize();\r
+  if (packetSize < 9) return;\r
+  UINT payloadOffset = data[8] + 9;\r
+  if (packetSize < payloadOffset + 5) return;\r
+  if (data[payloadOffset + 3] == 0x00)\r
+  { // Not a continuation packet\r
+    if (packetSize < payloadOffset + 7) return;\r
+    subtitlePacket.init(data[3]);\r
+    subtitlePacket.write(&data[6], payloadOffset - 6);\r
+    subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);\r
+    subtitlePacketPosition = payloadOffset + 2;\r
+  }\r
+  else\r
+  { // Continuation packet\r
+    if (subtitlePacketPosition == 0) return;\r
+    subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);\r
+  }\r
+  \r
+  const UCHAR* sub_data = subtitlePacket.getData();\r
+  UINT subSize = subtitlePacket.getSize();\r
+  while (subtitlePacketPosition < subSize)\r
+  {\r
+    if (sub_data[subtitlePacketPosition] == 0xFF)\r
+    { // Packet is complete. Switch it into the "real" packet to be submitted.\r
+      packet = subtitlePacket;\r
+      parsePacketDetails(packet);\r
+      subtitlePacketPosition = 0; // Wait for next non-continuation packet\r
+      break;\r
+    }\r
+    if (sub_data[subtitlePacketPosition] != 0x0F)\r
+    {\r
+      subtitlePacketPosition = 0; // Wait for next non-continuation packet\r
+      break;\r
+    }\r
+    if (subSize < subtitlePacketPosition + 6) break;\r
+    UINT segmentLength = (sub_data[subtitlePacketPosition + 4] << 8)\r
+                        + sub_data[subtitlePacketPosition + 5];\r
+    subtitlePacketPosition += segmentLength + 6;\r
+  }\r
+}\r
+\r
+void DemuxerVDR::parseVDRPacketDetails()\r
+{\r
+  if (packet.getPacketType() == PESTYPE_PRIVATE_1 && packet.getSize() > 8)\r
+  {\r
+    UINT payload_begin = packet[8] + 9;\r
+    if (packet.getSize() > payload_begin)\r
+    {\r
+      UCHAR substream_type = packet[payload_begin] & 0xF0;\r
+      if (substream_type == 0x20) // Subtitles\r
+      {\r
+        dealWithSubtitlePacket();\r
+      }\r
+      else // Not subtitles\r
+        parsePacketDetails(packet);\r
+    }\r
+  }\r
+  else // Not a private packet*/\r
+    parsePacketDetails(packet);\r
+\r
+  if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&\r
+                        packet.getPacketType() <= PESTYPE_AUDMAX)\r
+  {\r
+    packetNumber++;\r
+  }\r
+\r
+  if (frameCounting && packet.findPictureHeader(h264) &&\r
+      packet.getPacketType() >= PESTYPE_VID0 &&\r
+      packet.getPacketType() <= PESTYPE_VIDMAX)\r
+  {\r
+    ULONG frame_num = (frameNumber)++;\r
+    if (packet.findSeqHeader(h264) > 1 && packet.hasPTS())\r
+    {\r
+      PTSMapEntry me;\r
+      pts_map_mutex.Lock();\r
+      if (pts_map.empty())\r
+      {\r
+        me.pts = packet.getPTS();\r
+        me.frame = frame_num;\r
+        pts_map_mutex.Unlock();\r
+Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me.frame);\r
+        pts_map_mutex.Lock();\r
+        pts_map.push_front(me);\r
+      }\r
+      me = pts_map.front();\r
+      pts_map_mutex.Unlock();\r
+\r
+//      UINT fps = Video::getInstance()->getFPS();\r
+      ULLONG pts_expected = me.pts + 90000*((ULONG)((double)(frame_num - me.frame)) / fps);\r
+      while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);\r
+\r
+      if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!\r
+      {\r
+Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS JUMP *+ %llu %u", packet.getPTS(), frame_num);\r
+        me.pts = packet.getPTS();\r
+        me.frame = frame_num;\r
+        pts_map_mutex.Lock();\r
+        pts_map.push_front(me);\r
+        pts_map_mutex.Unlock();\r
+      }\r
+    }\r
+  }\r
+}\r
index dec62ff7c28344df90500daa9c2ac7890d7b67e9..e1587905f6354c5411e4b78125d6e2b9c22bde1e 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "directory.h"
 
-Directory::Directory(char* newName)
+Directory::Directory(const char* newName)
 {
   index = -1;
 
index 7cc49b7ca555cb70f3f767c6f0055b9b47bd9067..1ad4aa8d48e058be4a70a0877204225251f802e0 100644 (file)
@@ -36,7 +36,7 @@ typedef vector<Recording*> RecordingList;
 class Directory
 {
   public:
-    Directory(char* newName);
+    Directory(const char* newName);
     ~Directory();
 
     Directory* getDirByName(char* dirName);
diff --git a/draintarget.cc b/draintarget.cc
deleted file mode 100644 (file)
index fddd58b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "draintarget.h"
-
-DrainTarget::DrainTarget()
-{
-}
-DrainTarget::~DrainTarget()
-{
-}
index 772b606c1ce1a245ed20fcf65c3742cebce02573..fc19a2977aa5ced237a0acd861f8d5881c5d7337 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef DRAINTARGET_H
-#define DRAINTARGET_H
-
-#include "defines.h"
-#include <list>
-
-#define MPTYPE_VIDEO_MPEG2 0x00
-#define MPTYPE_MPEG_AUDIO 0x01
-#define MPTYPE_AC3 0x02
-#define MPTYPE_AC3_PRE13 0x03 //old vdr recording compatmode
-#define MPTYPE_MPEG_AUDIO_LAYER3 0x04 //for media mp3 playback
-#define MPTYPE_TELETEXT 0x05 //for EBU VBI teletext
-#define MPTYPE_VIDEO_H264 0x06
-
-
-
-struct MediaPacket
-{
-  ULONG pos_buffer; //position in stream buffer
-  ULONG length; //length of the packet
-  // The fields below are not needed by the MVP
-  UCHAR type;
-  ULLONG pts;
-  ULLONG dts;
-  bool synched;
-  int index;
-#ifdef WIN32
-  long long presentation_time;/* in 100 ns units*/
-  bool disconti;
-#endif
-};
-
-using namespace std;
-typedef list<MediaPacket> MediaPacketList;
-
-class DrainTarget
-{
-  public:
-    DrainTarget();
-    virtual ~DrainTarget();
-
-    virtual long long SetStartOffset(long long curreftime, bool *rsync)=0;
-    virtual void ResetTimeOffsets()=0;
-
-    virtual bool dtsTimefix(){return false;} //determines if the draintargets needs a mixure of pts and dts or not
-
-// The following two functions are used by the Stream
-// to deliver media packets to the front end (DrainTarget).
-//
-// First, the Stream calls PrepareMediaSample, which gives the front end
-// read-only access to the Stream's MediaPacketList. PrepareMediaSample should
-// examine the list to determine how much it wishes to consume, and
-// should copy any data it requires from the MediaPacket objects into
-// local storage.
-// This function call takes place under a mutex lock to ensure integrity
-// of the list structure. It should be fast and must not contain any
-// cancellation points, such as I/O calls for logging.
-//
-// Second, the Stream releases the mutex and calls DeliverMediaSample.
-// This function delivers data from the Stream buffer to the presentation
-// device and returns information to the Stream regarding how many MediaPackets
-// were consumed. Any data copied from the MediaPackets objects during
-// PrepareMediaSample is guaranteed by the Stream still to be valid
-// during the following DeliverMediaSample call.
-
-    // samplepos is equal to the number of bytes from the first MediaPacket
-    // in the list that have already been consumed in a previous call.
-    virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos)=0;
-
-    // The Stream guarantees that the value of *samplepos passed to
-    // DeliverMediaSample will be equal to the value of samplepos passed to
-    // PrepareMediaSample in the previous call.
-    // This function should consume data from the buffer according to the
-    // decisions made in PrepareMediaSample. Its return value and *samplepos
-    // tell the Stream how much data it consumed.
-    // If DeliverMediaSample returns X, the Stream will remove packets 0 to X-1
-    // (inclusive) from the list before the next call.
-    // DeliverMediaSample must also set *samplepos equal to the number of bytes
-    // processed from packet X (usually zero).
-       // It is allowed, that the draintarget modifies the part of the buffer, which belongs 
-       // to the mediapackets it is processing.
-    virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos)=0;
-};
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef DRAINTARGET_H\r
+#define DRAINTARGET_H\r
+\r
+#include "defines.h"\r
+#include <list>\r
+\r
+#define MPTYPE_VIDEO_MPEG2 0x00\r
+#define MPTYPE_MPEG_AUDIO 0x01\r
+#define MPTYPE_AC3 0x02\r
+#define MPTYPE_AC3_PRE13 0x03 //old vdr recording compatmode\r
+#define MPTYPE_MPEG_AUDIO_LAYER3 0x04 //for media mp3 playback\r
+#define MPTYPE_TELETEXT 0x05 //for EBU VBI teletext\r
+#define MPTYPE_VIDEO_H264 0x06\r
+\r
+\r
+\r
+struct MediaPacket\r
+{\r
+  ULONG pos_buffer; //position in stream buffer\r
+  ULONG length; //length of the packet\r
+  // The fields below are not needed by the MVP\r
+  UCHAR type;\r
+  ULLONG pts;\r
+  ULLONG dts;\r
+  bool synched;\r
+  int index;\r
+#if defined(WIN32) || defined(__ANDROID__)\r
+  long long presentation_time;/* in 100 ns units*/\r
+  bool disconti;\r
+#endif\r
+};\r
+\r
+using namespace std;\r
+typedef list<MediaPacket> MediaPacketList;\r
+\r
+\r
+\r
+class DrainTarget\r
+{\r
+  public:\r
+    DrainTarget() {\r
+\r
+    }\r
+    virtual ~DrainTarget(){\r
+\r
+    }\r
+\r
+    virtual long long SetStartOffset(long long curreftime, bool *rsync)=0;\r
+    virtual void ResetTimeOffsets()=0;\r
+\r
+    virtual bool dtsTimefix(){return false;} //determines if the draintargets needs a mixure of pts and dts or not\r
+\r
+// The following two functions are used by the Stream\r
+// to deliver media packets to the front end (DrainTarget).\r
+//\r
+// First, the Stream calls PrepareMediaSample, which gives the front end\r
+// read-only access to the Stream's MediaPacketList. PrepareMediaSample should\r
+// examine the list to determine how much it wishes to consume, and\r
+// should copy any data it requires from the MediaPacket objects into\r
+// local storage.\r
+// This function call takes place under a mutex lock to ensure integrity\r
+// of the list structure. It should be fast and must not contain any\r
+// cancellation points, such as I/O calls for logging.\r
+//\r
+// Second, the Stream releases the mutex and calls DeliverMediaSample.\r
+// This function delivers data from the Stream buffer to the presentation\r
+// device and returns information to the Stream regarding how many MediaPackets\r
+// were consumed. Any data copied from the MediaPackets objects during\r
+// PrepareMediaSample is guaranteed by the Stream still to be valid\r
+// during the following DeliverMediaSample call.\r
+\r
+    // samplepos is equal to the number of bytes from the first MediaPacket\r
+    // in the list that have already been consumed in a previous call.\r
+    virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos)=0;\r
+\r
+    // The Stream guarantees that the value of *samplepos passed to\r
+    // DeliverMediaSample will be equal to the value of samplepos passed to\r
+    // PrepareMediaSample in the previous call.\r
+    // This function should consume data from the buffer according to the\r
+    // decisions made in PrepareMediaSample. Its return value and *samplepos\r
+    // tell the Stream how much data it consumed.\r
+    // If DeliverMediaSample returns X, the Stream will remove packets 0 to X-1\r
+    // (inclusive) from the list before the next call.\r
+    // DeliverMediaSample must also set *samplepos equal to the number of bytes\r
+    // processed from packet X (usually zero).\r
+       // It is allowed, that the draintarget modifies the part of the buffer, which belongs \r
+       // to the mediapackets it is processing.\r
+    virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos)=0;\r
+    // The drain target might advice the feeder about free buffers with threadSignal\r
+\r
+\r
+};\r
+\r
+#endif\r
index 71531c7289de5f1937775920cc59c97312af68dd..d72039673a092fd2fdf758a94d6ba53221177a56 100644 (file)
 #ifndef DVBSUBTITLES_H
 #define DVBSUBTITLES_H
 
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
+#include "threadsystem.h"
+
 #include "bitmap.h"
 #include "demuxer.h"
 #include <ctime>
diff --git a/i18n.cc b/i18n.cc
index 5d07f75bbdeecdf96eef88154ca54c6ab9f65b90..091701bd688cfb6dc79143a1bd67b313313e2dfb 100644 (file)
--- a/i18n.cc
+++ b/i18n.cc
 
 #include <stdio.h>
 #include <string.h>
-#ifndef WIN32
+
+//Nothing is using this ?
+/*#ifndef WIN32
 #include <glob.h>
-#endif
+#endif*/
 
 #include "vdr.h"
 #include "log.h"
index 3d2bb181d180c76d18ec111ac0af8fb0dca85dc1..533a0571a9dbd2d7c9cba90e98f633f4ff898e30 100644 (file)
-/*
-    Copyright 2004-2006 Chris Tallon, Andreas Vogel
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef IMAGEREADER_H
-#define IMAGEREADER_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef WIN32
-#include <sys/time.h>
-#endif
-#include <time.h>
-
-#include "callback.h"
-#include "thread.h"
-
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
-
-
-
-class MediaProvider;
-class Log;
-
-
-class ImageReader : public Thread_TYPE, public Callback
-{
-  public:
-
-    //create an image reader for a media channel
-    //the channel must already been opened
-    ImageReader(int channel,MediaProvider *p);
-    //call shutdown before destroying the reader!
-    virtual ~ImageReader();
-    //request the next image block
-    //will return the current block (if already read) and request the next from the server
-    //rsize will return the received len: 0 on EOF, -1 on error
-    //the returned buffer has to be freed outside (really use free!)
-    //if the buffer is not filled it will wait until the chunk is received!
-    int getImageChunk(ULLONG offset,UINT len, UINT * rsize,UCHAR **buffer);
-
-    //is the reader still running?
-    bool isReaderRunning();
-
-    void shutdown();
-
-    //stop the reader (waits until the reader thread does not access anything)
-    void stop();
-
-    
-    virtual void call(void * caller);
-
-
-  protected:
-    void threadMethod();
-    void threadPostStopCleanup();
-
-  private:
-    MediaProvider * provider;
-    int  channel;
-    static const int MAXCHUNKS=2;
-    //start the player thread
-    void run();
-    Log* logger;
-
-    bool running;
-    bool readerRunning;
-    void waitTimed(int ms);
-
-    typedef enum {
-      S_REQUEST=1,
-      S_FETCHING=2,
-      S_READY=3,
-      S_BREAK=4,
-      S_FREE=0
-      } rstate;
-
-    class Chunk{
-      public:
-      UCHAR * buffer; //receive buffer (to be deallocated with free)
-      ULLONG offset;  //offset within stream/file
-      UINT reqlen;    //requested len
-      ULONG len;       //received len
-      rstate state;   //current state
-      Chunk() {
-        buffer=NULL;
-        offset=0;
-        reqlen=0;
-        len=0;
-        state=S_FREE;
-        } 
-    };
-    //received data
-    //setting state in this array requires the thread lock
-    Chunk data[MAXCHUNKS];
-
-};
-
-#endif
-
+/*\r
+    Copyright 2004-2006 Chris Tallon, Andreas Vogel\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef IMAGEREADER_H\r
+#define IMAGEREADER_H\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#ifndef WIN32\r
+#include <sys/time.h>\r
+#endif\r
+#include <time.h>\r
+\r
+#include "callback.h"\r
+#include "thread.h"\r
+\r
+#include "threadsystem.h"\r
+\r
+\r
+\r
+class MediaProvider;\r
+class Log;\r
+\r
+\r
+class ImageReader : public Thread_TYPE, public Callback\r
+{\r
+  public:\r
+\r
+    //create an image reader for a media channel\r
+    //the channel must already been opened\r
+    ImageReader(int channel,MediaProvider *p);\r
+    //call shutdown before destroying the reader!\r
+    virtual ~ImageReader();\r
+    //request the next image block\r
+    //will return the current block (if already read) and request the next from the server\r
+    //rsize will return the received len: 0 on EOF, -1 on error\r
+    //the returned buffer has to be freed outside (really use free!)\r
+    //if the buffer is not filled it will wait until the chunk is received!\r
+    int getImageChunk(ULLONG offset,UINT len, UINT * rsize,UCHAR **buffer);\r
+\r
+    //is the reader still running?\r
+    bool isReaderRunning();\r
+\r
+    void shutdown();\r
+\r
+    //stop the reader (waits until the reader thread does not access anything)\r
+    void stop();\r
+\r
+    \r
+    virtual void call(void * caller);\r
+\r
+\r
+  protected:\r
+    void threadMethod();\r
+    void threadPostStopCleanup();\r
+\r
+  private:\r
+    MediaProvider * provider;\r
+    int  channel;\r
+    static const int MAXCHUNKS=2;\r
+    //start the player thread\r
+    void run();\r
+    Log* logger;\r
+\r
+    bool running;\r
+    bool readerRunning;\r
+    void waitTimed(int ms);\r
+\r
+    typedef enum {\r
+      S_REQUEST=1,\r
+      S_FETCHING=2,\r
+      S_READY=3,\r
+      S_BREAK=4,\r
+      S_FREE=0\r
+      } rstate;\r
+\r
+    class Chunk{\r
+      public:\r
+      UCHAR * buffer; //receive buffer (to be deallocated with free)\r
+      ULLONG offset;  //offset within stream/file\r
+      UINT reqlen;    //requested len\r
+      ULONG len;       //received len\r
+      rstate state;   //current state\r
+      Chunk() {\r
+        buffer=NULL;\r
+        offset=0;\r
+        reqlen=0;\r
+        len=0;\r
+        state=S_FREE;\r
+        } \r
+    };\r
+    //received data\r
+    //setting state in this array requires the thread lock\r
+    Chunk data[MAXCHUNKS];\r
+\r
+};\r
+\r
+#endif\r
+\r
index 5ae39f97cd8d2bc48fa940de7858d86efc589f85..b5022164bd5a4e15bdd0ea784258d44b2cb05bfe 100644 (file)
--- a/ledmvp.h
+++ b/ledmvp.h
@@ -32,7 +32,7 @@ class LedMVP : public Led
 {
   public:
     LedMVP();
-    ~LedMVP();
+    virtual ~LedMVP();
 
     int init(int device);
     int shutdown();
diff --git a/log.cc b/log.cc
index 3aff96cd8f90a623f5e9430e7ce967de114ab65f..5ed65f6af30594cf278e9aa108288f0a2deb4357 100644 (file)
--- a/log.cc
+++ b/log.cc
-/*
-    Copyright 2004-2005 Chris Tallon
-    Copyright 2003-2004 University Of Bradford
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "log.h"
-
-#include "vdr.h"
-
-Log* Log::instance = NULL;
-
-Log::Log()
-{
-  if (instance) return;
-  instance = this;
-  logfile = NULL;
-  initted = 0;
-  logLevel = 0;
-  netLog = false;
-}
-
-Log::~Log()
-{
-  instance = NULL;
-}
-
-Log* Log::getInstance()
-{
-  return instance;
-}
-
-void Log::upLogLevel()
-{
-  if (logLevel == Log::DEBUG)
-  {
-    log("Log", logLevel, "Log level is at its highest already");
-    return;
-  }
-
-  logLevel++;
-  log("Log", logLevel, "Log level is now %i", logLevel);
-}
-
-void Log::downLogLevel()
-{
-  if (logLevel == Log::CRAZY)
-  {
-    log("Log", logLevel, "Log level is at its lowest already");
-    return;
-  }
-
-  logLevel--;
-  log("Log", logLevel, "Log level is now %i", logLevel);
-}
-
-int Log::init(int startLogLevel, char* fileName, int tenabled)
-{
-  initted = 1;
-  logLevel = startLogLevel;
-  enabled = tenabled;
-//  logfile = fopen(fileName, "a");
-//  logfile = fopen(stdout, "a");
-  logfile = stdout;
-//  logfile = fopen("/log", "a");
-
-  if (logfile) return 1;
-  else return 0;
-}
-
-int Log::shutdown()
-{
-  if (!initted) return 1;
-  if (enabled) fclose(logfile);
-  return 1;
-}
-
-int Log::log(char *fromModule, int level, char* message, ...)
-{
-  if (!instance || !logfile) return 0;
-
-  if (!enabled && !netLog) return 1;
-  if (level > logLevel) return 1;
-
-  char buffer[151];
-  int spaceLeft = 150;
-
-#ifndef _MSC_VER
-  struct timeval tv;
-  gettimeofday(&tv, NULL);
-  struct tm* tms = localtime(&tv.tv_sec);
-#else
-  struct _timeb tb;
-  _ftime(&tb);
-  struct tm* tms = localtime(&tb.time);
-#endif
-  spaceLeft -= strftime(buffer, spaceLeft, "%H:%M:%S.", tms);
-#ifndef _MSC_VER
-  spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tv.tv_usec);
-#else
-  spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tb.millitm);
-#endif
-
-  char levelString[10];
-  if (level == CRAZY)   strcpy(levelString, "[CRAZY] ");
-  if (level == EMERG)   strcpy(levelString, "[EMERG] ");
-  if (level == ALERT)   strcpy(levelString, "[ALERT] ");
-  if (level == CRIT)    strcpy(levelString, "[CRIT]  ");
-  if (level == ERR)     strcpy(levelString, "[ERR]   ");
-  if (level == WARN)    strcpy(levelString, "[WARN]  ");
-  if (level == NOTICE)  strcpy(levelString, "[notice]");
-  if (level == INFO)    strcpy(levelString, "[info]  ");
-  if (level == DEBUG)   strcpy(levelString, "[debug] ");
-
-#ifndef WIN32
-  spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%s %d %s - ", levelString, getpid(), fromModule);
-#else
-  spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%s %s - ", levelString,  fromModule);
-#endif
-
-  va_list ap;
-  va_start(ap, message);
-  spaceLeft = VSNPRINTF(&buffer[150-spaceLeft], spaceLeft, message, ap);
-  va_end(ap);
-
-  int messageLength = strlen(buffer);
-  if (messageLength < 150)
-  {
-    buffer[messageLength] = '\n';
-    buffer[messageLength+1] = '\0';
-  }
-  else
-  {
-    buffer[149] = '\n';
-    buffer[150] = '\0';
-  }
-  
-  int success = 1;
-  if (enabled)
-  {
-    success = fputs(buffer, logfile);
-    fflush(NULL);
-  }
-
-  if (netLog) vdr->networkLog(buffer);
-
-  if (success != EOF)
-    return 1;
-  else
-    return 0;
-
-}
-
-int Log::status()
-{
-  if (instance && logfile) return 1;
-  else return 0;
-}
-
-void Log::netLogOn()
-{
-  vdr = VDR::getInstance();
-  netLog = true;
-  log("Log", Log::DEBUG, "Network logging started");
-}
-
-void Log::netLogOff()
-{
-  netLog = false;
-  vdr = NULL;
-}
-
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+    Copyright 2003-2004 University Of Bradford\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "log.h"\r
+\r
+#include "vdr.h"\r
+\r
+#ifdef __ANDROID__\r
+#include <android/log.h>\r
+#endif\r
+\r
+Log* Log::instance = NULL;\r
+\r
+Log::Log()\r
+{\r
+  if (instance) return;\r
+  instance = this;\r
+  logfile = NULL;\r
+  initted = 0;\r
+  logLevel = 0;\r
+  extlog = NULL;\r
+}\r
+\r
+Log::~Log()\r
+{\r
+  instance = NULL;\r
+}\r
+\r
+Log* Log::getInstance()\r
+{\r
+  return instance;\r
+}\r
+\r
+void Log::upLogLevel()\r
+{\r
+  if (logLevel == Log::DEBUG)\r
+  {\r
+    log("Log", logLevel, "Log level is at its highest already");\r
+    return;\r
+  }\r
+\r
+  logLevel++;\r
+  log("Log", logLevel, "Log level is now %i", logLevel);\r
+}\r
+\r
+void Log::downLogLevel()\r
+{\r
+  if (logLevel == Log::CRAZY)\r
+  {\r
+    log("Log", logLevel, "Log level is at its lowest already");\r
+    return;\r
+  }\r
+\r
+  logLevel--;\r
+  log("Log", logLevel, "Log level is now %i", logLevel);\r
+}\r
+\r
+int Log::init(int startLogLevel,const char* fileName, int tenabled)\r
+{\r
+  initted = 1;\r
+  logLevel = startLogLevel;\r
+  enabled = tenabled;\r
+//  logfile = fopen(fileName, "a");\r
+//  logfile = fopen(stdout, "a");\r
+  logfile = stdout;\r
+//  logfile = fopen("/log", "a");\r
+\r
+  if (logfile) return 1;\r
+  else return 0;\r
+}\r
+\r
+int Log::shutdown()\r
+{\r
+  if (!initted) return 1;\r
+  if (enabled) fclose(logfile);\r
+  return 1;\r
+}\r
+\r
+int Log::log(const char *fromModule, int level,const char* message, ...)\r
+{\r
+  if (!instance || !logfile) return 0;\r
+\r
+  if (!enabled && !extlog) return 1;\r
+  if (level > logLevel) return 1;\r
+\r
+  char buffer[151];\r
+  int spaceLeft = 150;\r
+\r
+#ifndef _MSC_VER\r
+  struct timeval tv;\r
+  gettimeofday(&tv, NULL);\r
+  struct tm* tms = localtime(&tv.tv_sec);\r
+#else\r
+  struct _timeb tb;\r
+  _ftime(&tb);\r
+  struct tm* tms = localtime(&tb.time);\r
+#endif\r
+  spaceLeft -= strftime(buffer, spaceLeft, "%H:%M:%S.", tms);\r
+#ifndef _MSC_VER\r
+  spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tv.tv_usec);\r
+#else\r
+  spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tb.millitm);\r
+#endif\r
+\r
+  char levelString[10];\r
+  if (level == CRAZY)   strcpy(levelString, "[CRAZY] ");\r
+  if (level == EMERG)   strcpy(levelString, "[EMERG] ");\r
+  if (level == ALERT)   strcpy(levelString, "[ALERT] ");\r
+  if (level == CRIT)    strcpy(levelString, "[CRIT]  ");\r
+  if (level == ERR)     strcpy(levelString, "[ERR]   ");\r
+  if (level == WARN)    strcpy(levelString, "[WARN]  ");\r
+  if (level == NOTICE)  strcpy(levelString, "[notice]");\r
+  if (level == INFO)    strcpy(levelString, "[info]  ");\r
+  if (level == DEBUG)   strcpy(levelString, "[debug] ");\r
+\r
+#ifndef WIN32\r
+  spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%s %d %s - ", levelString, getpid(), fromModule);\r
+#else\r
+  spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%s %s - ", levelString,  fromModule);\r
+#endif\r
+\r
+  va_list ap;\r
+  va_start(ap, message);\r
+  spaceLeft = VSNPRINTF(&buffer[150-spaceLeft], spaceLeft, message, ap);\r
+  va_end(ap);\r
+\r
+  int messageLength = strlen(buffer);\r
+  if (messageLength < 150)\r
+  {\r
+    buffer[messageLength] = '\n';\r
+    buffer[messageLength+1] = '\0';\r
+  }\r
+  else\r
+  {\r
+    buffer[149] = '\n';\r
+    buffer[150] = '\0';\r
+  }\r
+  \r
+  int success = 1;\r
+  if (enabled)\r
+  {\r
+#ifndef __ANDROID__\r
+    success = fputs(buffer, logfile);\r
+    fflush(NULL);\r
+#else\r
+    int and_level=0;\r
+    switch (level) {\r
+    case CRAZY:\r
+    case ALERT:\r
+    case EMERG :\r
+    case CRIT:{\r
+       and_level=ANDROID_LOG_FATAL;\r
+    } break;\r
+    case ERR: {\r
+       and_level=ANDROID_LOG_ERROR;\r
+    } break;\r
+    case WARN: {\r
+       and_level=ANDROID_LOG_WARN;\r
+    } break;\r
+    case NOTICE:\r
+    case INFO: {\r
+        and_level=ANDROID_LOG_INFO;\r
+    } break;\r
+    case DEBUG :{\r
+        and_level=ANDROID_LOG_DEBUG;\r
+    } break;\r
+    };\r
+    __android_log_vprint(and_level, fromModule,\r
+                             message,  ap);\r
+#endif\r
+  }\r
+\r
+  if (extlog) extlog->LogExtern(buffer); //Replacement for network logging\r
+\r
+\r
+  if (success != EOF)\r
+    return 1;\r
+  else\r
+    return 0;\r
+\r
+}\r
+\r
+\r
+\r
+int Log::status()\r
+{\r
+  if (instance && logfile) return 1;\r
+  else return 0;\r
+}\r
+\r
+void Log::setExternLogger(ExternLogger* login) {\r
+       extlog=login;\r
+    log("Log", Log::DEBUG, "Extern logging started");\r
+}\r
+\r
+\r
+\r
+\r
diff --git a/log.h b/log.h
index 5e5e11e4fae3475ce115280695876eba658b3e70..ed24b8bfe3418b5c58a93f42c86c0e5ff83343e6 100644 (file)
--- a/log.h
+++ b/log.h
-/*
-    Copyright 2004-2005 Chris Tallon
-    Copyright 2003-2004 University Of Bradford
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef LOG_H
-#define LOG_H
-
-#include <stdio.h>
-#ifndef WIN32
- #include <unistd.h>
- #include <sys/time.h>
-#else
- #include <sys/timeb.h>
-#endif
-
-#include <time.h>
-#include <string.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include "defines.h"
-
-class VDR;
-
-class Log
-{
-  public:
-    Log();
-    ~Log();
-    static Log* getInstance();
-
-    int init(int defaultLevel, char* fileName, int enabled);
-    int shutdown();
-    int log(char *fromModule, int level, char *message, ...);
-    int status();
-    void upLogLevel();
-    void downLogLevel();
-    void netLogOn();
-    void netLogOff();
-
-    const static int CRAZY  = 0; // mad crazy things that should never happen
-    const static int EMERG  = 1; // human assist required NOW
-    const static int ALERT  = 2; // system unusable, but happy to sit there
-    const static int CRIT   = 3; // still working, but maybe about to die
-    const static int ERR    = 4; // that response is not even listed...
-    const static int WARN   = 5; // this could be a bad thing. still running tho
-    const static int NOTICE = 6; // significant good thing
-    const static int INFO   = 7; // verbose good thing
-    const static int DEBUG  = 8; // debug-level messages
-
-  private:
-    static Log* instance;
-    int initted;
-    int logLevel;
-    int enabled;
-
-    FILE *logfile;
-    
-    bool netLog;
-    VDR* vdr;
-};
-
-#endif
-
-/*
-
-Documentation
--------------
-
-This class is intended to be instatiated once by the core.
-For a one off use:
-
-Log::getInstance()->log("<module-name>", Log::<levelname>, "<message>");
-
-Or, a pointer can be stored and used:
-
-Log *myptr = Log::getInstance();
-
-myptr->log("<module-name>", Log::<levelname>, "<message>");
-myptr->log("<module-name>", Log::<levelname>, "<message>");
-
-Level usages are above.
-
-The message parameter in the log function can be used in the same way as printf, eg.
-
-myptr->log("<module-name>", Log::<levelname>, "Success: %s %i", stringpointer, integer);
-
-*/
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+    Copyright 2003-2004 University Of Bradford\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef LOG_H\r
+#define LOG_H\r
+\r
+#include <stdio.h>\r
+#ifndef WIN32\r
+ #include <unistd.h>\r
+ #include <sys/time.h>\r
+#else\r
+ #include <sys/timeb.h>\r
+#endif\r
+\r
+#include <time.h>\r
+#include <string.h>\r
+#include <stdarg.h>\r
+#include <sys/types.h>\r
+#include "defines.h"\r
+\r
+\r
+class ExternLogger {\r
+public:\r
+       virtual bool LogExtern(const char* message)=0;\r
+};\r
+\r
+\r
+class Log\r
+{\r
+  public:\r
+    Log();\r
+    ~Log();\r
+    static Log* getInstance();\r
+\r
+    int init(int defaultLevel,const char* fileName, int enabled);\r
+    int shutdown();\r
+    int log(const char *fromModule, int level,const char *message, ...);\r
+    int status();\r
+    void upLogLevel();\r
+    void downLogLevel();\r
+    void setExternLogger(ExternLogger* log);\r
+    void unsetExternLogger() {\r
+       extlog=NULL;\r
+    }\r
+\r
+\r
+\r
+    const static int CRAZY  = 0; // mad crazy things that should never happen\r
+    const static int EMERG  = 1; // human assist required NOW\r
+    const static int ALERT  = 2; // system unusable, but happy to sit there\r
+    const static int CRIT   = 3; // still working, but maybe about to die\r
+    const static int ERR    = 4; // that response is not even listed...\r
+    const static int WARN   = 5; // this could be a bad thing. still running tho\r
+    const static int NOTICE = 6; // significant good thing\r
+    const static int INFO   = 7; // verbose good thing\r
+    const static int DEBUG  = 8; // debug-level messages\r
+\r
+  private:\r
+    static Log* instance;\r
+    int initted;\r
+    int logLevel;\r
+    int enabled;\r
+\r
+    FILE *logfile;\r
+    \r
+    ExternLogger* extlog;\r
+\r
+\r
+};\r
+\r
+#endif\r
+\r
+/*\r
+\r
+Documentation\r
+-------------\r
+\r
+This class is intended to be instatiated once by the core.\r
+For a one off use:\r
+\r
+Log::getInstance()->log("<module-name>", Log::<levelname>, "<message>");\r
+\r
+Or, a pointer can be stored and used:\r
+\r
+Log *myptr = Log::getInstance();\r
+\r
+myptr->log("<module-name>", Log::<levelname>, "<message>");\r
+myptr->log("<module-name>", Log::<levelname>, "<message>");\r
+\r
+Level usages are above.\r
+\r
+The message parameter in the log function can be used in the same way as printf, eg.\r
+\r
+myptr->log("<module-name>", Log::<levelname>, "Success: %s %i", stringpointer, integer);\r
+\r
+*/\r
diff --git a/main.cc b/main.cc
index 3d4ad20f644417edca80065404f94aacabdf6328..226f3e21e02d90d923c96657c6378efaf911157d 100644 (file)
--- a/main.cc
+++ b/main.cc
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#ifndef WIN32
-#include <unistd.h>
-#include <endian.h>
-#endif
-
-#include "defines.h"
-#include "log.h"
-#include "timers.h"
-#include "vdr.h"
-#include "boxstack.h"
-#include "command.h"
-
-#ifndef _MIPS_ARCH
-
-#include "mtdmvp.h"
-#include "remotemvp.h"
-#include "ledmvp.h"
-#include "osdmvp.h"
-#include "audiomvp.h"
-#include "videomvp.h"
-
-#else
-
-#include "mtdnmt.h"
-#include "remotelirc.h"
-#include "lednmt.h"
-#include "osddirectfb.h"
-#include "audionmt.h"
-#include "videonmt.h"
-
-#endif
-
-
-#include "wol.h"
-#include "vsleeptimer.h"
-
-
-#ifndef WIN32
-void sighandler(int signalReceived);
-#endif
-
-void shutdown(int code);
-
-#ifndef _MIPS_ARCH
-
-extern "C"
-{
-  int ticonfig_main(int, char**);
-}
-
-#endif
-
-// Global variables --------------------------------------------------------------------------------------------------
-Log* logger;
-Remote* remote;
-Mtd* mtd;
-Led* led;
-Osd* osd;
-Timers* timers;
-BoxStack* boxstack;
-Command* command;
-VDR* vdr;
-Video* video;
-Audio* audio;
-Wol* wol;
-Sleeptimer* sleeptimer;
-
-// Linux MVP main function and sighandler
-#ifndef WIN32
-int main(int argc, char** argv)
-{
-#ifndef _MIPS_ARCH
-  if (strstr(argv[0], "ticonfig")) return ticonfig_main(argc, argv);
-#endif
-
-  bool daemonize = true;
-  bool debugEnabled = false;
-  bool crashed = false;
-  char* setServer = NULL;
-  int c;
-
-  while ((c = getopt(argc, argv, "cdns:")) != -1)
-  {
-    switch (c)
-    {
-      case 'c':
-        crashed = true;
-        break;
-      case 'd':
-        debugEnabled = true; // and...
-      case 'n':
-        daemonize = false;
-        break;        
-      case 's':
-        setServer = optarg;
-        break;
-      case '?':
-        printf("Unknown option\n");
-        return 1;
-      default:
-        printf("Option error\n");
-        return 1;
-    }
-  }
-           
-  // Init global vars ------------------------------------------------------------------------------------------------
-  logger     = new Log();
-  timers     = new Timers();
-  vdr        = new VDR();
-#ifndef _MIPS_ARCH
-  mtd        = new MtdMVP();
-  remote     = new RemoteMVP();
-  led        = new LedMVP();
-  osd        = new OsdMVP();
-  audio      = new AudioMVP();
-  video      = new VideoMVP();
-#else
-  mtd        = new MtdNMT();
-  remote     = new RemoteLirc();
-  led        = new LedNMT();
-  osd        = new OsdDirectFB();
-  audio      = new AudioNMT();
-  video      = new VideoNMT();
-#endif
-
-
-  boxstack   = new BoxStack();
-  command    = new Command();
-  wol        = new Wol();
-  sleeptimer = new Sleeptimer();
-  
-  if (!logger || !remote || !mtd || !led || !osd || !video || !audio || !boxstack || !command || !wol || !sleeptimer)
-  {
-    printf("Could not create objects. Memory problems?\n");
-    shutdown(1);
-  }
-
-  // Get logging module started --------------------------------------------------------------------------------------
-
-  if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0))
-  {
-    printf("Could not initialise log object. Aborting.\n");
-    shutdown(1);
-  }
-
-  logger->log("Core", Log::INFO, "Starting up...");
-
-  // Daemonize if not -d
-
-  if (daemonize)
-  {
-    // Fork away
-    pid_t forkTest = fork();
-    if (forkTest == -1)
-    { printf("Cannot fork (1).\n"); exit(1); }
-    if (forkTest != 0) _exit(0); // PID returned, I am the parent
-    // otherwise, I am the child
-    setsid();
-    forkTest = fork();
-    if (forkTest == -1)
-    { printf("Cannot fork (2).\n"); exit(1); }
-    if (forkTest != 0) _exit(0); // PID returned, I am the parent
-    // otherwise, I am the child
-    close(0);
-    close(1);
-    close(2);
-  }
-
-  // Set up signal handling ------------------------------------------------------------------------------------------
-
-  sighandler_t sigtest;
-
-  sigtest = signal(SIGPIPE, SIG_IGN);
-  if (sigtest == SIG_ERR)
-  {
-    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGPIPE. Aborting.");
-    shutdown(1);
-  }
-  sigtest = signal(SIGINT, sighandler);
-  if (sigtest == SIG_ERR)
-  {
-    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGINT. Aborting.");
-    shutdown(1);
-  }
-  sigtest = signal(SIGTERM, sighandler);
-  if (sigtest == SIG_ERR)
-  {
-    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGTERM. Aborting.");
-    shutdown(1);
-  }
-  sigtest = signal(SIGUSR1, sighandler);
-  if (sigtest == SIG_ERR)
-  {
-    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR1. Aborting.");
-    shutdown(1);
-  }
-/*
-  sigtest = signal(SIGUSR2, sighandler);
-  if (sigtest == SIG_ERR)
-  {
-    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR2. Aborting.");
-    shutdown(1);
-  }
-*/
-  sigtest = signal(SIGURG, sighandler);
-  if (sigtest == SIG_ERR)
-  {
-    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGURG. Aborting.");
-    shutdown(1);
-  }
-
-  logger->log("Core", Log::INFO, "Signal handlers set up successfully");
-
-
-  // Init modules ----------------------------------------------------------------------------------------------------
-  int success;
-#ifndef _MIPS_ARCH
-  success = remote->init("/dev/rawir");
-#else
-  success = remote->init("/dev/lircd");
-#endif
-  if (success)
-  {
-    logger->log("Core", Log::INFO, "Remote module initialised");
-  }
-  else
-  {
-    logger->log("Core", Log::EMERG, "Remote module failed to initialise");
-    shutdown(1);
-  }
-#ifndef _MIPS_ARCH
-  success = led->init(((RemoteMVP*)remote)->getDevice());
-#else
-  success = led->init(-1);
-#endif  
-  if (success)
-  {
-    logger->log("Core", Log::INFO, "LED module initialised");
-  }
-  else
-  {
-    logger->log("Core", Log::EMERG, "LED module failed to initialise");
-    shutdown(1);
-  }
-
-  success = mtd->init();
-  if (success)
-  {
-    logger->log("Core", Log::INFO, "Mtd module initialised");
-  }
-  else
-  {
-    logger->log("Core", Log::EMERG, "Mtd module failed to initialise");
-    shutdown(1);
-  }
-
-  success = timers->init();
-  if (success)
-  {
-    logger->log("Core", Log::INFO, "Timers module initialised");
-  }
-  else
-  {
-    logger->log("Core", Log::EMERG, "Timers module failed to initialise");
-    shutdown(1);
-  }
-
-  UCHAR videoFormat = (UCHAR)mtd->getPALorNTSC();
-  if      (videoFormat == Video::PAL)  logger->log("Core", Log::INFO, "Read from MTD: PAL 720x576");
-  else if (videoFormat == Video::NTSC) logger->log("Core", Log::INFO, "Read from MTD: NTSC 720x480");
-  else                                 logger->log("Core", Log::INFO, "No help from MTD. Assuming NTSC 720x480");
-
-  success = video->init(videoFormat);
-  if (success)
-  {
-    logger->log("Core", Log::INFO, "Video module initialised");
-  }
-  else
-  {
-    logger->log("Core", Log::EMERG, "Video module failed to initialise");
-    shutdown(1);
-  }
-
-  success = osd->init((void*)("/dev/stbgfx"));
-  if (success)
-  {
-    logger->log("Core", Log::INFO, "OSD module initialised");
-  }
-  else
-  {
-    logger->log("Core", Log::EMERG, "OSD module failed to initialise");
-    shutdown(1);
-  }
-
-  success = audio->init(Audio::MPEG2_PES);
-  if (success)
-  {
-    logger->log("Core", Log::INFO, "Audio module initialised");
-  }
-  else
-  {
-    logger->log("Core", Log::EMERG, "Audio module failed to initialise");
-    shutdown(1);
-  }
-
-  success = vdr->init(3024);
-  if (success)
-  {
-    logger->log("Core", Log::INFO, "VDR module initialised");
-  }
-  else
-  {
-    logger->log("Core", Log::EMERG, "VDR module failed to initialise");
-    shutdown(1);
-  }
-
-  success = boxstack->init();
-  if (success)
-  {
-    logger->log("Core", Log::INFO, "BoxStack module initialised");
-  }
-  else
-  {
-    logger->log("Core", Log::EMERG, "BoxStack module failed to initialise");
-    shutdown(1);
-  }
-
-  success = command->init(crashed, setServer);
-  if (success)
-  {
-    logger->log("Core", Log::INFO, "Command module initialised");
-  }
-  else
-  {
-    logger->log("Core", Log::EMERG, "Command module failed to initialise");
-    shutdown(1);
-  }
-
-  // Other init ------------------------------------------------------------------------------------------------------
-
-  logger->log("Core", Log::NOTICE, "Startup successful");
-
-  // Run main loop ---------------------------------------------------------------------------------------------------
-
-  // Ok, all major device components and other bits are loaded and ready
-  command->run();
-
-  // When that returns quit ------------------------------------------------------------------------------------------
-
-  shutdown(0);
-  return 0;
-}
-
-// -------------------------------------------------------------------------------------------------------------------
-
-void sighandler(int signalReceived)
-{
-  logger->log("Core", Log::NOTICE, "Signal %i received", signalReceived);
-
-  switch (signalReceived)
-  {
-    case SIGINT:
-    {
-      logger->log("Core", Log::NOTICE, "Interrupt signal, shutting down...");
-      command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe?
-      break;
-    }
-    case SIGTERM:
-    {
-      logger->log("Core", Log::NOTICE, "Term signal, shutting down...");
-      command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe?
-      break;
-    }
-    case SIGUSR1:
-    {
-      command->sig1();
-      break;
-    }
-/*
-    case SIGUSR1:
-    {
-      logger->log("Core", Log::DEBUG, "SIGUSR1 caught");
-      logger->upLogLevel();
-      break;
-    }
-    case SIGUSR2:
-    {
-      logger->log("Core", Log::DEBUG, "SIGUSR2 caught");
-      logger->downLogLevel();
-      break;
-    }
-*/
-    case SIGURG:
-    {
-      logger->log("Core", Log::DEBUG, "SIGURG caught");
-      break;
-    }
-  }
-}
-#endif
-
-// -------------------------------------------------------------------------------------------------------------------
-
-void shutdown(int code)
-{
-  if (boxstack)
-  {
-    boxstack->shutdown();
-    delete boxstack;
-    logger->log("Core", Log::NOTICE, "BoxStack module shut down");
-  }
-
-  // FIXME, send a del all to boxstack first, then get rid of it after command?
-  if (command) // shut down command here in case views have posted messages
-  {
-    command->shutdown();
-    delete command;
-    logger->log("Core", Log::NOTICE, "Command module shut down");
-  }
-
-  if (vdr)
-  {
-    vdr->shutdown();
-    delete vdr;
-    logger->log("Core", Log::NOTICE, "VDR module shut down");
-  }
-
-  if (osd)
-  {
-    osd->shutdown();
-    delete osd;
-    logger->log("Core", Log::NOTICE, "OSD module shut down");
-  }
-
-  if (audio)
-  {
-    audio->shutdown();
-    delete audio;
-    logger->log("Core", Log::NOTICE, "Audio module shut down");
-  }
-
-  if (video)
-  {
-    video->shutdown();
-    delete video;
-    logger->log("Core", Log::NOTICE, "Video module shut down");
-  }
-
-  if (timers)
-  {
-    timers->shutdown();
-    delete timers;
-    logger->log("Core", Log::NOTICE, "Timers module shut down");
-  }
-
-  if (mtd)
-  {
-    mtd->shutdown();
-    delete mtd;
-    logger->log("Core", Log::NOTICE, "MTD module shut down");
-  }
-
-  if (led)
-  {
-    led->shutdown();
-    delete led;
-    logger->log("Core", Log::NOTICE, "LED module shut down");
-  }
-
-  if (remote)
-  {
-    remote->shutdown();
-    delete remote;
-    logger->log("Core", Log::NOTICE, "Remote module shut down");
-  }
-
-  if (wol)
-  {
-    delete wol;
-    logger->log("Core", Log::NOTICE, "WOL module shut down");
-  }
-
-  if (sleeptimer)
-  {
-    delete sleeptimer;
-    logger->log("Core", Log::NOTICE, "Sleeptimer module shut down");
-  }
-
-  if (logger)
-  {
-    logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");
-    logger->shutdown();
-    delete logger;
-  }
-
-  exit(code);
-}
-
-// -------------------------------------------------------------------------------------------------------------------
-
-ULLONG ntohll(ULLONG a)
-{
-  return htonll(a);
-}
-
-ULLONG htonll(ULLONG a)
-{
-  #if BYTE_ORDER == BIG_ENDIAN
-    return a;
-  #else
-    ULLONG b = 0;
-
-    b = ((a << 56) & 0xFF00000000000000ULL)
-      | ((a << 40) & 0x00FF000000000000ULL)
-      | ((a << 24) & 0x0000FF0000000000ULL)
-      | ((a <<  8) & 0x000000FF00000000ULL)
-      | ((a >>  8) & 0x00000000FF000000ULL)
-      | ((a >> 24) & 0x0000000000FF0000ULL)
-      | ((a >> 40) & 0x000000000000FF00ULL)
-      | ((a >> 56) & 0x00000000000000FFULL) ;
-
-    return b;
-  #endif
-}
-
-void MILLISLEEP(ULONG a)
-{
-#ifndef WIN32
-  struct timespec delayTime;
-  delayTime.tv_sec = a / 1000;
-  delayTime.tv_nsec = (a % 1000) * 1000000;
-  nanosleep(&delayTime, NULL);
-#else
-  Sleep(a);
-#endif
-}
-
-int min(UINT a, int b)
-{
-  if (a > b) return b;
-  else return a;
-}
-
-int max(int a, int b)
-{
-  if (a > b) return a;
-  else return b;
-}
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <signal.h>\r
+#ifndef WIN32\r
+#include <unistd.h>\r
+#include <endian.h>\r
+#endif\r
+\r
+#include "defines.h"\r
+#include "log.h"\r
+#include "timers.h"\r
+#include "vdr.h"\r
+#include "boxstack.h"\r
+#include "command.h"\r
+\r
+\r
+#ifdef VOMP_PLATTFORM_MVP\r
+\r
+\r
+#include "mtdmvp.h"\r
+#include "remotemvp.h"\r
+#include "ledmvp.h"\r
+#include "osdmvp.h"\r
+#include "audiomvp.h"\r
+#include "videomvp.h"\r
+\r
+extern "C"\r
+{\r
+  int ticonfig_main(int, char**);\r
+}\r
+\r
+#endif\r
+\r
+#ifdef VOMP_PLATTFORM_NMT\r
+\r
+#include "mtdnmt.h"\r
+#include "remotelirc.h"\r
+#include "lednmt.h"\r
+#include "osddirectfb.h"\r
+#include "audionmt.h"\r
+#include "videonmt.h"\r
+\r
+#endif\r
+\r
+#ifdef VOMP_PLATTFORM_RASPBERRY\r
+\r
+#include "mtdraspberry.h"\r
+#include "remotelinux.h"\r
+#include "ledraspberry.h"\r
+#include "osdopengl.h"\r
+#include "audiovpe.h"\r
+#include "videovpeogl.h"\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+#include "wol.h"\r
+#include "vsleeptimer.h"\r
+\r
+\r
+#ifndef WIN32\r
+void sighandler(int signalReceived);\r
+#endif\r
+\r
+void shutdown(int code);\r
+\r
+\r
+\r
+// Global variables --------------------------------------------------------------------------------------------------\r
+Log* logger;\r
+Remote* remote;\r
+Mtd* mtd;\r
+Led* led;\r
+Osd* osd;\r
+Timers* timers;\r
+BoxStack* boxstack;\r
+Command* command;\r
+VDR* vdr;\r
+Video* video;\r
+Audio* audio;\r
+Wol* wol;\r
+Sleeptimer* sleeptimer;\r
+\r
+// Linux MVP main function and sighandler\r
+#ifndef WIN32\r
+int main(int argc, char** argv)\r
+{\r
+#ifdef VOMP_PLATTFORM_MVP\r
+  if (strstr(argv[0], "ticonfig")) return ticonfig_main(argc, argv);\r
+#endif\r
+\r
+  bool daemonize = true;\r
+  bool debugEnabled = false;\r
+  bool crashed = false;\r
+  char* setServer = NULL;\r
+  int c;\r
+\r
+  while ((c = getopt(argc, argv, "cdns:")) != -1)\r
+  {\r
+    switch (c)\r
+    {\r
+      case 'c':\r
+        crashed = true;\r
+        break;\r
+      case 'd':\r
+        debugEnabled = true; // and...\r
+      case 'n':\r
+        daemonize = false;\r
+        break;        \r
+      case 's':\r
+        setServer = optarg;\r
+        break;\r
+      case '?':\r
+        printf("Unknown option\n");\r
+        return 1;\r
+      default:\r
+        printf("Option error\n");\r
+        return 1;\r
+    }\r
+  }\r
+           \r
+  // Init global vars ------------------------------------------------------------------------------------------------\r
+  logger     = new Log();\r
+  timers     = new Timers();\r
+  vdr        = new VDR();\r
+\r
+  mtd        = new Mtd_TYPE();\r
+  remote     = new Remote_TYPE();\r
+  led        = new Led_TYPE();\r
+  osd        = new Osd_TYPE();\r
+  audio      = new Audio_TYPE();\r
+  video      = new Video_TYPE();\r
+\r
+\r
+\r
+  boxstack   = new BoxStack();\r
+  command    = new Command();\r
+  wol        = new Wol();\r
+  sleeptimer = new Sleeptimer();\r
+  \r
+  if (!logger || !remote || !mtd || !led || !osd || !video || !audio || !boxstack || !command || !wol || !sleeptimer)\r
+  {\r
+    printf("Could not create objects. Memory problems?\n");\r
+    shutdown(1);\r
+  }\r
+\r
+  // Get logging module started --------------------------------------------------------------------------------------\r
+\r
+  if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0))\r
+  {\r
+    printf("Could not initialise log object. Aborting.\n");\r
+    shutdown(1);\r
+  }\r
+\r
+  logger->log("Core", Log::INFO, "Starting up...");\r
+\r
+  // Daemonize if not -d\r
+\r
+  if (daemonize)\r
+  {\r
+    // Fork away\r
+    pid_t forkTest = fork();\r
+    if (forkTest == -1)\r
+    { printf("Cannot fork (1).\n"); exit(1); }\r
+    if (forkTest != 0) _exit(0); // PID returned, I am the parent\r
+    // otherwise, I am the child\r
+    setsid();\r
+    forkTest = fork();\r
+    if (forkTest == -1)\r
+    { printf("Cannot fork (2).\n"); exit(1); }\r
+    if (forkTest != 0) _exit(0); // PID returned, I am the parent\r
+    // otherwise, I am the child\r
+    close(0);\r
+    close(1);\r
+    close(2);\r
+  }\r
+\r
+  // Set up signal handling ------------------------------------------------------------------------------------------\r
+\r
+  sighandler_t sigtest;\r
+\r
+  sigtest = signal(SIGPIPE, SIG_IGN);\r
+  if (sigtest == SIG_ERR)\r
+  {\r
+    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGPIPE. Aborting.");\r
+    shutdown(1);\r
+  }\r
+  sigtest = signal(SIGINT, sighandler);\r
+  if (sigtest == SIG_ERR)\r
+  {\r
+    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGINT. Aborting.");\r
+    shutdown(1);\r
+  }\r
+  sigtest = signal(SIGTERM, sighandler);\r
+  if (sigtest == SIG_ERR)\r
+  {\r
+    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGTERM. Aborting.");\r
+    shutdown(1);\r
+  }\r
+  sigtest = signal(SIGUSR1, sighandler);\r
+  if (sigtest == SIG_ERR)\r
+  {\r
+    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR1. Aborting.");\r
+    shutdown(1);\r
+  }\r
+/*\r
+  sigtest = signal(SIGUSR2, sighandler);\r
+  if (sigtest == SIG_ERR)\r
+  {\r
+    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR2. Aborting.");\r
+    shutdown(1);\r
+  }\r
+*/\r
+  sigtest = signal(SIGURG, sighandler);\r
+  if (sigtest == SIG_ERR)\r
+  {\r
+    logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGURG. Aborting.");\r
+    shutdown(1);\r
+  }\r
+\r
+  logger->log("Core", Log::INFO, "Signal handlers set up successfully");\r
+\r
+\r
+  // Init modules ----------------------------------------------------------------------------------------------------\r
+  int success;\r
+\r
+  success = remote->init(RemoteStartDev);\r
+\r
+  if (success)\r
+  {\r
+    logger->log("Core", Log::INFO, "Remote module initialised");\r
+  }\r
+  else\r
+  {\r
+    logger->log("Core", Log::EMERG, "Remote module failed to initialise");\r
+    shutdown(1);\r
+  }\r
+#ifdef VOMP_PLATTFORM_MVP\r
+  success = led->init(((RemoteMVP*)remote)->getDevice());\r
+#else\r
+  success = led->init(-1);\r
+#endif  \r
+  if (success)\r
+  {\r
+    logger->log("Core", Log::INFO, "LED module initialised");\r
+  }\r
+  else\r
+  {\r
+    logger->log("Core", Log::EMERG, "LED module failed to initialise");\r
+    shutdown(1);\r
+  }\r
+\r
+  success = mtd->init();\r
+  if (success)\r
+  {\r
+    logger->log("Core", Log::INFO, "Mtd module initialised");\r
+  }\r
+  else\r
+  {\r
+    logger->log("Core", Log::EMERG, "Mtd module failed to initialise");\r
+    shutdown(1);\r
+  }\r
+\r
+  success = timers->init();\r
+  if (success)\r
+  {\r
+    logger->log("Core", Log::INFO, "Timers module initialised");\r
+  }\r
+  else\r
+  {\r
+    logger->log("Core", Log::EMERG, "Timers module failed to initialise");\r
+    shutdown(1);\r
+  }\r
+\r
+  UCHAR videoFormat = (UCHAR)mtd->getPALorNTSC();\r
+  if      (videoFormat == Video::PAL)  logger->log("Core", Log::INFO, "Read from MTD: PAL 720x576");\r
+  else if (videoFormat == Video::NTSC) logger->log("Core", Log::INFO, "Read from MTD: NTSC 720x480");\r
+  else                                 logger->log("Core", Log::INFO, "No help from MTD. Assuming NTSC 720x480");\r
+\r
+  success = video->init(videoFormat);\r
+  if (success)\r
+  {\r
+    logger->log("Core", Log::INFO, "Video module initialised");\r
+  }\r
+  else\r
+  {\r
+    logger->log("Core", Log::EMERG, "Video module failed to initialise");\r
+    shutdown(1);\r
+  }\r
+\r
+  success = osd->init((void*)OsdStartDev);\r
+  if (success)\r
+  {\r
+    logger->log("Core", Log::INFO, "OSD module initialised");\r
+  }\r
+  else\r
+  {\r
+    logger->log("Core", Log::EMERG, "OSD module failed to initialise");\r
+    shutdown(1);\r
+  }\r
+\r
+  success = audio->init(Audio::MPEG2_PES);\r
+  if (success)\r
+  {\r
+    logger->log("Core", Log::INFO, "Audio module initialised");\r
+  }\r
+  else\r
+  {\r
+    logger->log("Core", Log::EMERG, "Audio module failed to initialise");\r
+    shutdown(1);\r
+  }\r
+\r
+  success = vdr->init(3024);\r
+  if (success)\r
+  {\r
+    logger->log("Core", Log::INFO, "VDR module initialised");\r
+  }\r
+  else\r
+  {\r
+    logger->log("Core", Log::EMERG, "VDR module failed to initialise");\r
+    shutdown(1);\r
+  }\r
+\r
+  success = boxstack->init();\r
+  if (success)\r
+  {\r
+    logger->log("Core", Log::INFO, "BoxStack module initialised");\r
+  }\r
+  else\r
+  {\r
+    logger->log("Core", Log::EMERG, "BoxStack module failed to initialise");\r
+    shutdown(1);\r
+  }\r
+\r
+  success = command->init(crashed, setServer);\r
+  if (success)\r
+  {\r
+    logger->log("Core", Log::INFO, "Command module initialised");\r
+  }\r
+  else\r
+  {\r
+    logger->log("Core", Log::EMERG, "Command module failed to initialise");\r
+    shutdown(1);\r
+  }\r
+\r
+  // Other init ------------------------------------------------------------------------------------------------------\r
+\r
+  logger->log("Core", Log::NOTICE, "Startup successful");\r
+\r
+  // Run main loop ---------------------------------------------------------------------------------------------------\r
+\r
+  // Ok, all major device components and other bits are loaded and ready\r
+  command->run();\r
+\r
+  // When that returns quit ------------------------------------------------------------------------------------------\r
+\r
+  shutdown(0);\r
+  return 0;\r
+}\r
+\r
+// -------------------------------------------------------------------------------------------------------------------\r
+\r
+void sighandler(int signalReceived)\r
+{\r
+  logger->log("Core", Log::NOTICE, "Signal %i received", signalReceived);\r
+\r
+  switch (signalReceived)\r
+  {\r
+    case SIGINT:\r
+    {\r
+      logger->log("Core", Log::NOTICE, "Interrupt signal, shutting down...");\r
+      command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe?\r
+      break;\r
+    }\r
+    case SIGTERM:\r
+    {\r
+      logger->log("Core", Log::NOTICE, "Term signal, shutting down...");\r
+      command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe?\r
+      break;\r
+    }\r
+    case SIGUSR1:\r
+    {\r
+      command->sig1();\r
+      break;\r
+    }\r
+/*\r
+    case SIGUSR1:\r
+    {\r
+      logger->log("Core", Log::DEBUG, "SIGUSR1 caught");\r
+      logger->upLogLevel();\r
+      break;\r
+    }\r
+    case SIGUSR2:\r
+    {\r
+      logger->log("Core", Log::DEBUG, "SIGUSR2 caught");\r
+      logger->downLogLevel();\r
+      break;\r
+    }\r
+*/\r
+    case SIGURG:\r
+    {\r
+      logger->log("Core", Log::DEBUG, "SIGURG caught");\r
+      break;\r
+    }\r
+  }\r
+}\r
+#endif\r
+\r
+// -------------------------------------------------------------------------------------------------------------------\r
+\r
+void shutdown(int code)\r
+{\r
+  if (boxstack)\r
+  {\r
+    boxstack->shutdown();\r
+    delete boxstack;\r
+    logger->log("Core", Log::NOTICE, "BoxStack module shut down");\r
+  }\r
+\r
+  // FIXME, send a del all to boxstack first, then get rid of it after command?\r
+  if (command) // shut down command here in case views have posted messages\r
+  {\r
+    command->shutdown();\r
+    delete command;\r
+    logger->log("Core", Log::NOTICE, "Command module shut down");\r
+  }\r
+\r
+  if (vdr)\r
+  {\r
+    vdr->shutdown();\r
+    delete vdr;\r
+    logger->log("Core", Log::NOTICE, "VDR module shut down");\r
+  }\r
+\r
+  if (osd)\r
+  {\r
+    osd->shutdown();\r
+    delete osd;\r
+    logger->log("Core", Log::NOTICE, "OSD module shut down");\r
+  }\r
+\r
+  if (audio)\r
+  {\r
+    audio->shutdown();\r
+    delete audio;\r
+    logger->log("Core", Log::NOTICE, "Audio module shut down");\r
+  }\r
+\r
+  if (video)\r
+  {\r
+    video->shutdown();\r
+    delete video;\r
+    logger->log("Core", Log::NOTICE, "Video module shut down");\r
+  }\r
+\r
+  if (timers)\r
+  {\r
+    timers->shutdown();\r
+    delete timers;\r
+    logger->log("Core", Log::NOTICE, "Timers module shut down");\r
+  }\r
+\r
+  if (mtd)\r
+  {\r
+    mtd->shutdown();\r
+    delete mtd;\r
+    logger->log("Core", Log::NOTICE, "MTD module shut down");\r
+  }\r
+\r
+  if (led)\r
+  {\r
+    led->shutdown();\r
+    delete led;\r
+    logger->log("Core", Log::NOTICE, "LED module shut down");\r
+  }\r
+\r
+  if (remote)\r
+  {\r
+    remote->shutdown();\r
+    delete remote;\r
+    logger->log("Core", Log::NOTICE, "Remote module shut down");\r
+  }\r
+\r
+  if (wol)\r
+  {\r
+    delete wol;\r
+    logger->log("Core", Log::NOTICE, "WOL module shut down");\r
+  }\r
+\r
+  if (sleeptimer)\r
+  {\r
+    delete sleeptimer;\r
+    logger->log("Core", Log::NOTICE, "Sleeptimer module shut down");\r
+  }\r
+\r
+  if (logger)\r
+  {\r
+    logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");\r
+    logger->shutdown();\r
+    delete logger;\r
+  }\r
+\r
+  exit(code);\r
+}\r
+\r
+// -------------------------------------------------------------------------------------------------------------------\r
+\r
+ULLONG htonll(ULLONG a)\r
+{\r
+  #if BYTE_ORDER == BIG_ENDIAN\r
+    return a;\r
+  #else\r
+    ULLONG b = 0;\r
+\r
+    b = ((a << 56) & 0xFF00000000000000ULL)\r
+      | ((a << 40) & 0x00FF000000000000ULL)\r
+      | ((a << 24) & 0x0000FF0000000000ULL)\r
+      | ((a <<  8) & 0x000000FF00000000ULL)\r
+      | ((a >>  8) & 0x00000000FF000000ULL)\r
+      | ((a >> 24) & 0x0000000000FF0000ULL)\r
+      | ((a >> 40) & 0x000000000000FF00ULL)\r
+      | ((a >> 56) & 0x00000000000000FFULL) ;\r
+\r
+    return b;\r
+  #endif\r
+}\r
+\r
+ULLONG ntohll(ULLONG a)\r
+{\r
+  return htonll(a);\r
+}\r
+\r
+void MILLISLEEP(ULONG a)\r
+{\r
+#ifndef WIN32\r
+  struct timespec delayTime;\r
+  delayTime.tv_sec = a / 1000;\r
+  delayTime.tv_nsec = (a % 1000) * 1000000;\r
+  nanosleep(&delayTime, NULL);\r
+#else\r
+  Sleep(a);\r
+#endif\r
+}\r
+\r
+int min(UINT a, int b)\r
+{\r
+  if (a > b) return b;\r
+  else return a;\r
+}\r
+\r
+int max(int a, int b)\r
+{\r
+  if (a > b) return a;\r
+  else return b;\r
+}\r
+\r
index 7d5d794c7e7682b249cb9025ca793e02f3b5105e..a2c854fe4970d1fd0087f94608c6b34cc44d844d 100644 (file)
--- a/message.h
+++ b/message.h
@@ -1,79 +1,82 @@
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef MESSAGE_H
-#define MESSAGE_H
-
-#include <stdio.h>
-#include "defines.h"
-
-// Usage of messages is more dubious now that the single master mutex lock
-// protects all gui actions. Reason(s) for usage:
-// 1. View A wants something to be done by View B *after* View A has been deleted
-// 2. A thread wants its object/view deleting *after* the thread has exited
-
-// Put a justification line after call to Message* m = new  Message() line
-// So that the sources can be grepped for proper message useage
-
-class Message
-{
-  public:
-    Message();
-
-    void* from;
-    void* to;
-    ULONG message;
-    ULONG parameter;
-    ULONG tag;     // use this for identifying which object / question is being replied to
-
-    const static ULONG QUESTION_YES = 1;
-    const static ULONG CLOSE_ME = 2;
-    const static ULONG PLAY_SELECTED_RECORDING = 3;
-    const static ULONG DELETE_SELECTED_RECORDING = 4;
-    const static ULONG SCREENSHOT = 5;
-    const static ULONG CHANNEL_CHANGE = 6;
-    const static ULONG RESUME_SELECTED_RECORDING = 7;
-    const static ULONG STOP_PLAYBACK = 9;
-    const static ULONG SERVER_SELECTED = 10;
-    const static ULONG VDR_CONNECTED = 11;
-    const static ULONG ADD_VIEW = 12;
-    const static ULONG REDRAW_LANG = 14;
-    const static ULONG EPG = 16;
-    const static ULONG EPG_CLOSE = 17;
-    const static ULONG CHANGED_OPTIONS = 18;
-    const static ULONG CONNECTION_LOST = 19;
-    const static ULONG MOVE_RECORDING = 20;
-    const static ULONG UDP_BUTTON = 21;
-    const static ULONG PLAYER_EVENT = 22;
-    const static ULONG AUDIO_CHANGE_CHANNEL = 23;
-    const static ULONG CHILD_CLOSE = 24;
-    const static ULONG MOUSE_MOVE = 25;
-    const static ULONG MOUSE_LBDOWN = 26;
-    const static ULONG CHANGE_LANGUAGE = 27;
-    const static ULONG LAST_VIEW_CLOSE = 28;
-    const static ULONG CHANGED_REMOTECONTROL = 29;
-    const static ULONG DELETE_SELECTED_TIMER = 30;
-    const static ULONG CHANGED_DEVICEOPTIONS = 31;
-    const static ULONG TELETEXTUPDATE = 32;
-    const static ULONG TELETEXTUPDATEFIRSTLINE = 33;
-    const static ULONG SUBTITLE_CHANGE_CHANNEL = 34;
-};
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef MESSAGE_H\r
+#define MESSAGE_H\r
+\r
+#include <stdio.h>\r
+\r
+class Message;\r
+#include "defines.h"\r
+\r
+// Usage of messages is more dubious now that the single master mutex lock\r
+// protects all gui actions. Reason(s) for usage:\r
+// 1. View A wants something to be done by View B *after* View A has been deleted\r
+// 2. A thread wants its object/view deleting *after* the thread has exited\r
+\r
+// Put a justification line after call to Message* m = new  Message() line\r
+// So that the sources can be grepped for proper message useage\r
+\r
+class Message\r
+{\r
+  public:\r
+    Message();\r
+\r
+    void* from;\r
+    void* to;\r
+    ULONG message;\r
+    ULONG parameter;\r
+    ULONG tag;     // use this for identifying which object / question is being replied to\r
+\r
+    const static ULONG QUESTION_YES = 1;\r
+    const static ULONG CLOSE_ME = 2;\r
+    const static ULONG PLAY_SELECTED_RECORDING = 3;\r
+    const static ULONG DELETE_SELECTED_RECORDING = 4;\r
+    const static ULONG SCREENSHOT = 5;\r
+    const static ULONG CHANNEL_CHANGE = 6;\r
+    const static ULONG RESUME_SELECTED_RECORDING = 7;\r
+    const static ULONG STOP_PLAYBACK = 9;\r
+    const static ULONG SERVER_SELECTED = 10;\r
+    const static ULONG VDR_CONNECTED = 11;\r
+    const static ULONG ADD_VIEW = 12;\r
+    const static ULONG REDRAW_LANG = 14;\r
+    const static ULONG EPG = 16;\r
+    const static ULONG EPG_CLOSE = 17;\r
+    const static ULONG CHANGED_OPTIONS = 18;\r
+    const static ULONG CONNECTION_LOST = 19;\r
+    const static ULONG MOVE_RECORDING = 20;\r
+    const static ULONG UDP_BUTTON = 21;\r
+    const static ULONG PLAYER_EVENT = 22;\r
+    const static ULONG AUDIO_CHANGE_CHANNEL = 23;\r
+    const static ULONG CHILD_CLOSE = 24;\r
+    const static ULONG MOUSE_MOVE = 25;\r
+    const static ULONG MOUSE_LBDOWN = 26;\r
+    const static ULONG CHANGE_LANGUAGE = 27;\r
+    const static ULONG LAST_VIEW_CLOSE = 28;\r
+    const static ULONG CHANGED_REMOTECONTROL = 29;\r
+    const static ULONG DELETE_SELECTED_TIMER = 30;\r
+    const static ULONG CHANGED_DEVICEOPTIONS = 31;\r
+    const static ULONG TELETEXTUPDATE = 32;\r
+    const static ULONG TELETEXTUPDATEFIRSTLINE = 33;\r
+    const static ULONG SUBTITLE_CHANGE_CHANNEL = 34;\r
+    const static ULONG MOUSE_ANDROID_SCROLL = 35;\r
+};\r
+\r
+#endif\r
index f7243066929bed7c5d5292540841cd84e213e9c8..ddbd015424305e0923f526145d4f70eb93d3c92b 100644 (file)
@@ -1,28 +1,28 @@
-OBJECTS1 = command.o log.o tcp.o dsock.o thread.o timers.o i18n.o mutex.o        \
-           message.o messagequeue.o udp.o wol.o                                  \
-           vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o     \
-           directory.o mark.o option.o                                           \
-           player.o playerradio.o vfeed.o afeed.o                                \
-           demuxer.o demuxervdr.o demuxerts.o stream.o draintarget.o             \
-           region.o colour.o boxstack.o boxx.o tbboxx.o                          \
-           vinfo.o vquestion.o vrecordinglist.o vrecording.o                     \
-           vmute.o vvolume.o vtimerlist.o vtimeredit.o vrecordingmenu.o          \
-           vchannellist.o vwelcome.o vvideorec.o vepgsettimer.o                  \
-           vchannelselect.o vserverselect.o vconnect.o vepg.o vrecmove.o         \
-           vradiorec.o vaudioselector.o vscreensaver.o vopts.o                   \
-           wselectlist.o wjpeg.o wsymbol.o wbutton.o wtextbox.o wwss.o           \
-           woptionpane.o woptionbox.o wremoteconfig.o wtabbar.o                  \
-           fonts/helvB24.o fonts/helvB18.o                                       \
-           remote.o led.o mtd.o video.o audio.o osd.o surface.o                  \
-           vmedialist.o media.o vpicturebanner.o                                 \
-           audioplayer.o demuxeraudio.o abstractoption.o                         \
-           eventdispatcher.o vdrrequestpacket.o vdrresponsepacket.o              \
-           vvideolivetv.o vsleeptimer.o                                          \
-           playerlivetv.o playerliveradio.o                                      \
-           wprogressbar.o                                                        \
-           bitmap.o dvbsubtitles.o                                               \
-           imagereader.o vcolourtuner.o mediaoptions.o mediaplayer.o mediafile.o \
-           serialize.o localmediafile.o vmediaview.o vvideomedia.o playermedia.o \
-           demuxermedia.o tfeed.o vteletextview.o teletextdecodervbiebu.o        \
-           teletxt/txtfont.o
-
+OBJECTS1 = command.o  tcp.o dsock.o thread.o timers.o i18n.o       \\r
+           message.o messagequeue.o udp.o wol.o audio.o video.o log.o  mutex.o      \\r
+           vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o     \\r
+           directory.o mark.o option.o                                           \\r
+           player.o playerradio.o vfeed.o afeed.o                                \\r
+           demuxer.o demuxervdr.o demuxerts.o stream.o            \\r
+           region.o colour.o boxstack.o boxx.o tbboxx.o                          \\r
+           vinfo.o vquestion.o vrecordinglist.o vrecording.o                     \\r
+           vmute.o vvolume.o vtimerlist.o vtimeredit.o vrecordingmenu.o          \\r
+           vchannellist.o vwelcome.o vvideorec.o vepgsettimer.o                  \\r
+           vchannelselect.o vserverselect.o vconnect.o vepg.o vrecmove.o         \\r
+           vradiorec.o vaudioselector.o vscreensaver.o vopts.o                   \\r
+           wselectlist.o wjpeg.o wsymbol.o wbutton.o wtextbox.o wwss.o           \\r
+           woptionpane.o woptionbox.o wremoteconfig.o wtabbar.o                  \\r
+           fonts/helvB24.o fonts/helvB18.o                                       \\r
+           remote.o led.o mtd.o  osd.o surface.o                  \\r
+            media.o vpicturebanner.o                                 \\r
+           audioplayer.o demuxeraudio.o abstractoption.o                         \\r
+           eventdispatcher.o vdrrequestpacket.o vdrresponsepacket.o              \\r
+           vvideolivetv.o vsleeptimer.o                                          \\r
+           playerlivetv.o playerliveradio.o                                      \\r
+           wprogressbar.o                                                        \\r
+           bitmap.o dvbsubtitles.o                                               \\r
+           imagereader.o  mediaoptions.o mediaplayer.o mediafile.o \\r
+           serialize.o localmediafile.o   playermedia.o \\r
+           demuxermedia.o tfeed.o vteletextview.o teletextdecodervbiebu.o        \\r
+           teletxt/txtfont.o\r
+\r
index 0e7ca7913f90ebe59145cfee29a76ca4f13bfec1..1f4b22ca3b60ead41c8cc768738f81c3833d3db0 100644 (file)
--- a/osdmvp.cc
+++ b/osdmvp.cc
@@ -36,6 +36,11 @@ int OsdMVP::getFD()
   return fdOsd;
 }
 
+Surface * OsdMvp::createNewSurface();{
+       return (Surface*)new SurfaceMvp();
+}
+
+
 int OsdMVP::init(void* device)
 {
   if (initted) return 0;
@@ -69,7 +74,7 @@ int OsdMVP::shutdown()
   return 1;
 }
 
-void OsdMVP::screenShot(char* fileName)
+void OsdMVP::screenShot(const char* fileName)
 {
   screen->screenShot(fileName);
 }
index ac6ba58010783b548a8ee0aaaa1e73a55d07ff55..5cdad84a135445c8aa5e6a07e4b20e7dda923c35 100644 (file)
--- a/osdmvp.h
+++ b/osdmvp.h
@@ -40,9 +40,11 @@ class OsdMVP : public Osd
     int init(void* device);
     int shutdown();
 
+    Surface * createNewSurface();
+
     int getFD();
 
-    void screenShot(char* fileName);
+    void screenShot(const char* fileName);
 
   private:
 };
index 1583460bf9ba07edafec8fc1fb5c82210e8b4034..4f90c5bab6d2ab7e4262700733952c51096cb550 100644 (file)
--- a/osdwin.cc
+++ b/osdwin.cc
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-
-#include "osdwin.h"
-#include "mtd.h"
-#include "videowin.h"
-#include "surfacewin.h"
-
-#include "dsallocator.h"
-#include "message.h"
-#include "command.h"
-
-#define  BACKBUFFER_WIDTH 1280
-#define  BACKBUFFER_HEIGHT 720
-
-
-
-typedef HRESULT (__stdcall *FCT_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager);
-typedef HRESULT (__stdcall *FCT_MFCreateVideoSampleFromSurface)(IUnknown* pUnkSurface, IMFSample** ppSample);
-
-FCT_DXVA2CreateDirect3DDeviceManager9 ptrDXVA2CreateDirect3DDeviceManager9=NULL;
-FCT_MFCreateVideoSampleFromSurface ptrMFCreateVideoSampleFromSurface=NULL;
-
-//This is stuff for rendering the OSD
-
-
-OsdWin::OsdWin()
-{
-  d3d=NULL;
-  d3ddevice=NULL;
-  d3drtsurf=NULL;
-  swappy=NULL;
-  swapsurf=NULL;
-  evrstate=EVR_pres_off;
-  window=NULL;
-
-  external_driving=false;
-  dsallocator=NULL;
-  filter_type=D3DTEXF_FORCE_DWORD;
-  lastrendertime=timeGetTime();
-  event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);
-  d3dmutex = CreateMutex(NULL,FALSE,NULL);
-  /*EVR stuff*/
-  dxvadevicehandle=NULL;
-  evrsupported=true;
-  HMODULE hlib=NULL;
-  hlib=LoadLibrary("dxva2.dll");
-  if (!hlib) {
-         evrsupported=false;
-         return;
-  }
-  ptrDXVA2CreateDirect3DDeviceManager9=(FCT_DXVA2CreateDirect3DDeviceManager9)GetProcAddress(hlib, "DXVA2CreateDirect3DDeviceManager9");
-  if (!ptrDXVA2CreateDirect3DDeviceManager9){
-         evrsupported=false;
-         return;
-  }
-
-  hlib=LoadLibrary("evr.dll");
-  if (!hlib) {
-         evrsupported=false;
-         return;
-  }
-  ptrMFCreateVideoSampleFromSurface = (FCT_MFCreateVideoSampleFromSurface)GetProcAddress(hlib,"MFCreateVideoSampleFromSurface");
-  if (!ptrMFCreateVideoSampleFromSurface){
-         evrsupported=false;
-         return;
-  }
-  
-}
-
-OsdWin::~OsdWin()
-{
-
-  if (initted) 
-  {
-         threadStop();
-               shutdown();
-  }
-  CloseHandle(event);
-  CloseHandle(d3dmutex);
-}
-
-int OsdWin::getFD()
-{
-  if (!initted) return 0;
-  return fdOsd;
-}
-
-int OsdWin::init(void* device)
-{
-  if (initted) return 0;
-   Video* video = Video::getInstance();
-   window=*((HWND*)device);
-  //First Create Direct 3D Object
-  d3d=Direct3DCreate9(D3D_SDK_VERSION);
-  if (!d3d) 
-  {
-    Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 object!");
-    return 0;
-  }
-  // then create the Device
-  D3DPRESENT_PARAMETERS d3dparas;
-  ZeroMemory(&d3dparas,sizeof(d3dparas));
-  d3dparas.BackBufferWidth=BACKBUFFER_WIDTH;
-  d3dparas.BackBufferHeight=BACKBUFFER_HEIGHT;
-  d3dparas.Windowed=TRUE;
-  d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;
-  if (d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,*((HWND*) device),
-         D3DCREATE_SOFTWARE_VERTEXPROCESSING |D3DCREATE_MULTITHREADED,&d3dparas,&d3ddevice)!=D3D_OK) {
-          Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 device!");
-       return 0;
-  }
-  d3ddevice->GetRenderTarget(0,&d3drtsurf);
-
-  /*
-  if (!InitVertexBuffer()) {
-          Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 vertex buf!");
-                 return 0;
-  }*/
-  /* We have to determine which kind of filtering is supported*/
-  D3DCAPS9 caps;
-  d3ddevice->GetDeviceCaps(&caps);
-  if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR)!=0)
-         && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)!=0)) {
-          if (filter_type==D3DTEXF_FORCE_DWORD) {
-                       filter_type=D3DTEXF_LINEAR;
-          }
-  } else {
-      if (filter_type==D3DTEXF_LINEAR)
-      {
-          filter_type=D3DTEXF_POINT;
-      }
-  }
-  
-  if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT)!=0)
-         && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT)!=0)) {
-       if (filter_type==D3DTEXF_FORCE_DWORD) 
-       {
-                 filter_type=D3DTEXF_POINT;
-   }
-   } else {
-       if (filter_type==D3DTEXF_POINT) {
-           filter_type=D3DTEXF_NONE;
-   }
-   }
-   if (filter_type==D3DTEXF_FORCE_DWORD) {
-       filter_type=D3DTEXF_NONE;
-   }
-
-   if (evrsupported)
-   {
-          if (ptrDXVA2CreateDirect3DDeviceManager9(&dxvatoken,&d3ddevman)!=S_OK) evrsupported=false;
-          else {
-                  d3ddevman->ResetDevice(d3ddevice,dxvatoken);
-          }
-   }
-
-
-
-
-  //Now we will create the Screen
-  screen = new SurfaceWin(Surface::SCREEN);
-  SetEvent(event);//Now all devices are ready
-  screen->create(video->getScreenWidth(), video->getScreenHeight());
-  screen->display();
-  initted = 1; // must set this here or create surface won't work
-  threadStart(); 
-
-  return 1;
-}
-
-void OsdWin::LockDevice()
-{
-       if (!evrsupported) return;
-       if (!dxvadevicehandle) 
-       {
-               d3ddevman->OpenDeviceHandle(&dxvadevicehandle);
-       }
-       IDirect3DDevice9 *temp;
-       d3ddevman->LockDevice(dxvadevicehandle,&temp,TRUE);
-
-}
-
-void OsdWin::UnlockDevice()
-{
-       if (!evrsupported) return;
-       if (!initted) return;
-       d3ddevman->UnlockDevice(dxvadevicehandle,TRUE);
-       if (dxvadevicehandle) 
-       {
-               d3ddevman->CloseDeviceHandle(dxvadevicehandle);
-               dxvadevicehandle=NULL;
-       }
-
-}
-
-DWORD OsdWin::getFilterCaps()
-{
-    if (!initted) return NULL;
-    D3DCAPS9 caps;
-    d3ddevice->GetDeviceCaps(&caps);
-    return caps.StretchRectFilterCaps;
-}
-       
-LPDIRECT3DVERTEXBUFFER9  OsdWin::InitVertexBuffer(DWORD width, DWORD height)
-{
-  LPDIRECT3DVERTEXBUFFER9 ret =NULL;
-  Video* video=Video::getInstance();
-  FLOAT texx=((float)video->getScreenWidth())/1024.f;
-  FLOAT texy=((float)video->getScreenHeight())/1024.f;
-  D3DCOLOR osdcolor=D3DCOLOR_RGBA(255,255,255,255);
-  osdvertices[0].c=osdcolor;
-  osdvertices[0].x=0.f-0.5f;
-  osdvertices[0].y=0.f-0.5f;
-  osdvertices[0].z=0.5f;
-  osdvertices[0].rhw=1.f;
-  osdvertices[0].u=0.f;
-  osdvertices[0].v=0.f;
-  osdvertices[1].c=osdcolor;
-  osdvertices[1].x=((float)width)-0.5f;-0.5f;
-  osdvertices[1].y=0.f-0.5f;
-  osdvertices[1].z=0.5f;
-  osdvertices[1].u=texx;
-  osdvertices[1].v=0.f;
-  osdvertices[1].rhw=1.f;
-  osdvertices[2].c=osdcolor;
-  osdvertices[2].x=((float)width)-0.5f;
-  osdvertices[2].y=((float)height)-0.5f;
-  osdvertices[2].z=0.5f;
-  osdvertices[2].rhw=1.f;
-  osdvertices[2].u=texx;
-  osdvertices[2].v=texy;
-  osdvertices[3].c=osdcolor;
-  osdvertices[3].x=0.f-0.5f;
-  osdvertices[3].y=((float)height)-0.5f;
-  osdvertices[3].z=0.5f;
-  osdvertices[3].rhw=1.f;
-  osdvertices[3].u=0.f;
-  osdvertices[3].v=texy;
-  
-  if (d3ddevice->CreateVertexBuffer(4*sizeof(OSDVERTEX),0,D3DFVF_OSDVERTEX,D3DPOOL_MANAGED,
-         &ret,NULL)!=D3D_OK) {
-         return NULL;
-  }
-  void *pvertex=NULL;
-  if (ret->Lock(0,sizeof(osdvertices),&pvertex,0)!=D3D_OK) {
-         return NULL;
-  }
-  memcpy(pvertex,osdvertices,sizeof(osdvertices));
-  ret->Unlock();
-  return ret;
-}
-
-int OsdWin::shutdown()
-{
-  if (!initted) return 0;
-  initted = 0;
-  evrsupported=0;
-  if (d3ddevman) d3ddevman->Release();
-  d3drtsurf->Release();
-  d3ddevice->Release();
-  d3d->Release();
-  if (swapsurf) swapsurf->Release();
-  if (swappy) swappy->Release();
-
-  return 1;
-}
-
-void OsdWin::screenShot(char* fileName)
-{
-  screen->screenShot(fileName);
-}
-
-void OsdWin::threadMethod()
-{
-       while (true)
-       {
-               DWORD waittime=10;
-               if (initted){
-                       if (evrstate==EVR_pres_off || evrstate==EVR_pres_pause) 
-                       {
-                               Render();
-                       } else if (evrstate==EVR_pres_started)
-                       {
-                               LPDIRECT3DSURFACE9 surf;
-                               if (dsallocator) dsallocator->GetNextSurface(&surf,&waittime);
-                               if (surf==NULL)
-                               {
-                                       Render();
-                               }
-                               else
-                               {
-                                       RenderDS(surf);
-                                       surf->Release();
-                                       if (dsallocator) dsallocator->DiscardSurfaceandgetWait(&waittime);
-                               }
-                       }
-               }
-               threadCheckExit();
-               if (waittime!=0) Sleep(min(10,waittime));
-               //Sleep(1);
-       }
-}
-
-
-void OsdWin::threadPostStopCleanup()
-{
-       //Doing nothing
-       //goo;
-}
-
-
-// This function is called from the WinMain function in order to get Screen updates
-void OsdWin::Render()
-{
-       if (!initted) return ;
-       if (external_driving) {
-        DWORD time1=timeGetTime(); //Updates the Menue
-               if ((time1-lastrendertime)>200) {//5 fps for OSD updates are enough, avoids tearing
-                       InternalRendering(NULL);
-                       lastrendertime=timeGetTime();
-        } else {
-                  //Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads
-        }
-       } else {
-               DWORD time1=timeGetTime();
-               if ((time1-lastrendertime)>50) {//10 fps for OSD updates are enough, avoids tearing
-                       InternalRendering(NULL);
-                       lastrendertime=timeGetTime();
-               } else {
-                       //Sleep(5);
-               
-               }
-               
-       }
-}
-
-void OsdWin::RenderDS(LPDIRECT3DSURFACE9 present){
-       if (!initted) return; 
-       if (external_driving) {
-               InternalRendering(present);
-        lastrendertime=timeGetTime();
-       }
-}
-
-
-void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){
-    BeginPainting();
-    HRESULT losty=d3ddevice->TestCooperativeLevel();
-    if (losty==D3DERR_DEVICELOST) {
-        //Sleep(10);
-               EndPainting();
-        return; //Device Lost
-    }
-    if (losty==D3DERR_DEVICENOTRESET){
-          EndPainting();
-       DoLost();
-       return;
-    }
-       WaitForSingleObject(event,INFINITE);
-       
-   
-       
-    
-    LPDIRECT3DSURFACE9 targetsurf;
-       if (swappy)
-       {
-               targetsurf=swapsurf;
-               d3ddevice->SetRenderTarget(0,swapsurf);//Stupid VMR manipulates the render target
-       } 
-       else
-       {
-               targetsurf=d3drtsurf;
-               d3ddevice->SetRenderTarget(0,d3drtsurf);//Stupid VMR manipulates the render target
-       }
-       D3DSURFACE_DESC targetdesc;
-       targetsurf->GetDesc(&targetdesc);
-
-       if (external_driving) {
-               //Copy video to Backbuffer
-               if (present!=NULL ) {
-                       VideoWin* video =(VideoWin*) Video::getInstance();
-                       /*calculating destination rect */
-                       RECT destrect={0,0,/*video->getScreenWidth()*/ targetdesc.Width,
-                               /*video->getScreenHeight()*/targetdesc.Height};
-                       UCHAR mode=video->getMode();
-                       switch (mode) {
-                       case Video::EIGHTH:
-                       destrect.right=destrect.right/2;
-                       destrect.bottom=destrect.bottom/2;
-                       case Video::QUARTER:
-                       destrect.right=destrect.right/2+video->getPosx()*2;
-                       destrect.bottom=destrect.bottom/2+video->getPosy()*2;
-                       destrect.left=video->getPosx()*2;
-                       destrect.top=video->getPosy()*2;
-                       d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
-                       break;
-                       };
-                       D3DSURFACE_DESC surf_desc;
-                       present->GetDesc(&surf_desc);//for chop sides
-                       RECT sourcerect= {0,0,surf_desc.Width,surf_desc.Height};
-                       if (video->getPseudoTVsize()==Video::ASPECT4X3 
-                               && video->getMode()==Video::NORMAL 
-                               && video->getAspectRatio()==Video::ASPECT16X9) {
-                                       unsigned int correction=((double) (surf_desc.Width))*4.*9./3./16.;
-                                       sourcerect.left=(surf_desc.Width-correction)/2;
-                                       sourcerect.right=sourcerect.left+correction;
-                       }
-                       d3ddevice->StretchRect(present,&sourcerect,targetsurf ,&destrect,filter_type);
-
-               }
-       } else {
-               VideoWin* video =(VideoWin*) Video::getInstance();
-               //Clear Background
-               if (!video->isVideoOn()) d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
-       }
-       LPDIRECT3DVERTEXBUFFER9 vb=NULL;
-       vb=InitVertexBuffer(targetdesc.Width,targetdesc.Height);
-
-       //Drawing the OSD
-       if (d3ddevice->BeginScene()==D3D_OK) {
-               d3ddevice->SetStreamSource(0,vb,0,sizeof(OSDVERTEX));
-               d3ddevice->SetFVF(D3DFVF_OSDVERTEX);
-               d3ddevice->SetTexture(0,((SurfaceWin*)screen)->getD3dtexture());
-               //d3ddevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
-               d3ddevice->SetTextureStageState(0, D3DTSS_ALPHAOP,D3DTOP_MODULATE);
-
-        d3ddevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
-        d3ddevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
-
-
-               d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
-               d3ddevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
-               d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
-               d3ddevice->SetRenderState(D3DRS_LIGHTING,FALSE);
-
-
-               d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);
-               d3ddevice->EndScene();
-               //Show it to the user!
-        HRESULT hres;
-               if (swappy)
-               {
-                       if (hres=swappy->Present(NULL,NULL,NULL,NULL,0)==D3DERR_DEVICELOST){
-                               //EndPainting();
-                               if (!external_driving) DoLost();
-                       }
-               } 
-               else
-               {
-                       if (hres=d3ddevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST){
-                               //EndPainting();
-                               if (!external_driving) DoLost();
-                       }
-               }
-               
-       }
-       
-       vb->Release();
-       EndPainting();
-
-       
-//     if (!external_driving) {
-//             Sleep(4);//The User can wait for 4 milliseconds to see his changes
-//     }
-}
-
-bool OsdWin::DoLost(){
-       Log::getInstance()->log("OSD", Log::WARN, "Direct3D Device Lost! Reobtaining...");
-       ResetEvent(event);
-       if (external_driving && dsallocator!=NULL) {
-               dsallocator->LostDevice(d3ddevice,d3d); //Propagate the information through DS
-       }
-       //First we free up all resources
-       Video* video = Video::getInstance();
-       ((SurfaceWin*)screen)->ReleaseSurface();
-       if (d3drtsurf) d3drtsurf->Release();
-    d3drtsurf=NULL;
-       D3DPRESENT_PARAMETERS d3dparas;
-       ZeroMemory(&d3dparas,sizeof(d3dparas));
-       d3dparas.BackBufferWidth=BACKBUFFER_WIDTH;
-       d3dparas.BackBufferHeight=BACKBUFFER_HEIGHT;
-       d3dparas.Windowed=TRUE;
-       d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;
-
-       if (swapsurf) {swapsurf->Release();swapsurf=NULL;};
-       if (swappy) {swappy->Release();swappy=NULL;};
-
-       if (d3ddevice->Reset(&d3dparas)!=D3D_OK){
-               return false;
-       }
-    d3ddevice->GetRenderTarget(0,&d3drtsurf);
-       if (d3ddevman) d3ddevman->ResetDevice(d3ddevice,dxvatoken);
-       //InitVertexBuffer();
-    //Redraw Views, Chris could you add a member function to BoxStack, so that
-       // I can cause it to completely redraw the Views?
-       // Otherwise the OSD would be distorted after Device Lost
-       // FIXME
-       
-       SetEvent(event);
-
-
-       screen->create(video->getScreenWidth(), video->getScreenHeight());
-       screen->display();
-       
-       return true;
-
-}
-LPDIRECT3DDEVICE9 OsdWin::getD3dDev() {
-       WaitForSingleObject(event,INFINITE);//We will only return if we are initted
-       return d3ddevice;
-}
-
-LPDIRECT3D9 OsdWin::getD3d() {
-       WaitForSingleObject(event,INFINITE);//We will only return if we are initted
-       return d3d;
-}
-
-void OsdWin::BeginPainting() {//We synchronize calls to d3d between different threads
-       WaitForSingleObject(d3dmutex,INFINITE);
-       LockDevice();
-}
-
-void OsdWin::EndPainting() {
-       UnlockDevice();
-       ReleaseMutex(d3dmutex);
-}
-
-void OsdWin::setExternalDriving(DsAllocator* dsall,DWORD width, DWORD height) {
-       
-       if (swappy)
-       {
-               BeginPainting();
-               d3ddevice->StretchRect(swapsurf,NULL,d3drtsurf,NULL,filter_type);
-               LPDIRECT3DSWAPCHAIN9 temp=swappy;
-               LPDIRECT3DSURFACE9 tempsurf=swapsurf;
-               swappy=NULL;
-               swapsurf=NULL;
-               EndPainting();
-               tempsurf->Release();
-               temp->Release();
-       }
-
-       if (dsall==NULL) {
-               external_driving=false;
-               dsallocator=NULL;       
-               return;
-       }
-       WaitForSingleObject(event,INFINITE);//We will only return if we are initted
-       BeginPainting();
-
-       if (width>BACKBUFFER_WIDTH || height>BACKBUFFER_HEIGHT) 
-       {
-               D3DPRESENT_PARAMETERS d3dparas;
-               ZeroMemory(&d3dparas,sizeof(d3dparas));
-               d3dparas.BackBufferWidth=width;
-               d3dparas.BackBufferHeight=height;
-               d3dparas.Windowed=TRUE;
-               d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;
-               if (d3ddevice->CreateAdditionalSwapChain(&d3dparas,&swappy)!=D3D_OK){
-                       Log::getInstance()->log("OSD", Log::WARN, "Could not create Swap Chain!");
-                       //return 0;
-               } else {
-                       swappy->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&swapsurf);
-               }
-        Log::getInstance()->log("OSD", Log::INFO, "Create Additional Swap Chain %d %d!",width,height);
-       }
-
-       dsallocator=dsall;
-       external_driving=true;
-       
-       EndPainting();
-}
-
-void OsdWin::Blank() {
-       WaitForSingleObject(event,INFINITE);
-       BeginPainting();
-       d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
-       EndPainting();
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+\r
+#include "osdwin.h"\r
+#include "mtd.h"\r
+#include "videowin.h"\r
+#include "surfacewin.h"\r
+\r
+#include "dsallocator.h"\r
+#include "message.h"\r
+#include "command.h"\r
+\r
+#define  BACKBUFFER_WIDTH 1280\r
+#define  BACKBUFFER_HEIGHT 720\r
+\r
+\r
+\r
+typedef HRESULT (__stdcall *FCT_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager);\r
+typedef HRESULT (__stdcall *FCT_MFCreateVideoSampleFromSurface)(IUnknown* pUnkSurface, IMFSample** ppSample);\r
+\r
+FCT_DXVA2CreateDirect3DDeviceManager9 ptrDXVA2CreateDirect3DDeviceManager9=NULL;\r
+FCT_MFCreateVideoSampleFromSurface ptrMFCreateVideoSampleFromSurface=NULL;\r
+\r
+//This is stuff for rendering the OSD\r
+\r
+\r
+OsdWin::OsdWin()\r
+{\r
+  d3d=NULL;\r
+  d3ddevice=NULL;\r
+  d3drtsurf=NULL;\r
+  swappy=NULL;\r
+  swapsurf=NULL;\r
+  evrstate=EVR_pres_off;\r
+  window=NULL;\r
+\r
+  external_driving=false;\r
+  dsallocator=NULL;\r
+  filter_type=D3DTEXF_FORCE_DWORD;\r
+  lastrendertime=timeGetTime();\r
+  event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);\r
+  d3dmutex = CreateMutex(NULL,FALSE,NULL);\r
+  /*EVR stuff*/\r
+  dxvadevicehandle=NULL;\r
+  evrsupported=true;\r
+  HMODULE hlib=NULL;\r
+  hlib=LoadLibrary("dxva2.dll");\r
+  if (!hlib) {\r
+         evrsupported=false;\r
+         return;\r
+  }\r
+  ptrDXVA2CreateDirect3DDeviceManager9=(FCT_DXVA2CreateDirect3DDeviceManager9)GetProcAddress(hlib, "DXVA2CreateDirect3DDeviceManager9");\r
+  if (!ptrDXVA2CreateDirect3DDeviceManager9){\r
+         evrsupported=false;\r
+         return;\r
+  }\r
+\r
+  hlib=LoadLibrary("evr.dll");\r
+  if (!hlib) {\r
+         evrsupported=false;\r
+         return;\r
+  }\r
\r
+  ptrMFCreateVideoSampleFromSurface = (FCT_MFCreateVideoSampleFromSurface)GetProcAddress(hlib,"MFCreateVideoSampleFromSurface");\r
+  if (!ptrMFCreateVideoSampleFromSurface){\r
+         evrsupported=false;\r
+         return;\r
+  }\r
+  \r
+}\r
+\r
+OsdWin::~OsdWin()\r
+{\r
+\r
+  if (initted) \r
+  {\r
+         threadStop();\r
+               shutdown();\r
+  }\r
+  CloseHandle(event);\r
+  CloseHandle(d3dmutex);\r
+}\r
+\r
+int OsdWin::getFD()\r
+{\r
+  if (!initted) return 0;\r
+  return fdOsd;\r
+}\r
+\r
+Surface * OsdWin::createNewSurface();{\r
+       return (Surface*)new SurfaceWin();\r
+}\r
+\r
+int OsdWin::init(void* device)\r
+{\r
+  if (initted) return 0;\r
+   Video* video = Video::getInstance();\r
+   window=*((HWND*)device);\r
+  //First Create Direct 3D Object\r
+  d3d=Direct3DCreate9(D3D_SDK_VERSION);\r
+  if (!d3d) \r
+  {\r
+    Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 object!");\r
+    return 0;\r
+  }\r
+  // then create the Device\r
+  D3DPRESENT_PARAMETERS d3dparas;\r
+  ZeroMemory(&d3dparas,sizeof(d3dparas));\r
+  d3dparas.BackBufferWidth=BACKBUFFER_WIDTH;\r
+  d3dparas.BackBufferHeight=BACKBUFFER_HEIGHT;\r
+  d3dparas.Windowed=TRUE;\r
+  d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;\r
+  if (d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,*((HWND*) device),\r
+         D3DCREATE_SOFTWARE_VERTEXPROCESSING |D3DCREATE_MULTITHREADED,&d3dparas,&d3ddevice)!=D3D_OK) {\r
+          Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 device!");\r
+       return 0;\r
+  }\r
+  d3ddevice->GetRenderTarget(0,&d3drtsurf);\r
+\r
+  /*\r
+  if (!InitVertexBuffer()) {\r
+          Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 vertex buf!");\r
+                 return 0;\r
+  }*/\r
+  /* We have to determine which kind of filtering is supported*/\r
+  D3DCAPS9 caps;\r
+  d3ddevice->GetDeviceCaps(&caps);\r
+  if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR)!=0)\r
+         && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)!=0)) {\r
+          if (filter_type==D3DTEXF_FORCE_DWORD) {\r
+                       filter_type=D3DTEXF_LINEAR;\r
+          }\r
+  } else {\r
+      if (filter_type==D3DTEXF_LINEAR)\r
+      {\r
+          filter_type=D3DTEXF_POINT;\r
+      }\r
+  }\r
+  \r
+  if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT)!=0)\r
+         && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT)!=0)) {\r
+       if (filter_type==D3DTEXF_FORCE_DWORD) \r
+       {\r
+                 filter_type=D3DTEXF_POINT;\r
+   }\r
+   } else {\r
+       if (filter_type==D3DTEXF_POINT) {\r
+           filter_type=D3DTEXF_NONE;\r
+   }\r
+   }\r
+   if (filter_type==D3DTEXF_FORCE_DWORD) {\r
+       filter_type=D3DTEXF_NONE;\r
+   }\r
+\r
+   if (evrsupported)\r
+   {\r
+          if (ptrDXVA2CreateDirect3DDeviceManager9(&dxvatoken,&d3ddevman)!=S_OK) evrsupported=false;\r
+          else {\r
+                  d3ddevman->ResetDevice(d3ddevice,dxvatoken);\r
+          }\r
+   }\r
+\r
+\r
+\r
+\r
+  //Now we will create the Screen\r
+  screen = new SurfaceWin(Surface::SCREEN);\r
+  SetEvent(event);//Now all devices are ready\r
+  screen->create(video->getScreenWidth(), video->getScreenHeight());\r
+  screen->display();\r
+  initted = 1; // must set this here or create surface won't work\r
+  threadStart(); \r
+\r
+  return 1;\r
+}\r
+\r
+void OsdWin::LockDevice()\r
+{\r
+       if (!evrsupported) return;\r
+       if (!dxvadevicehandle) \r
+       {\r
+               d3ddevman->OpenDeviceHandle(&dxvadevicehandle);\r
+       }\r
+       IDirect3DDevice9 *temp;\r
+       d3ddevman->LockDevice(dxvadevicehandle,&temp,TRUE);\r
+\r
+}\r
+\r
+void OsdWin::UnlockDevice()\r
+{\r
+       if (!evrsupported) return;\r
+       if (!initted) return;\r
+       d3ddevman->UnlockDevice(dxvadevicehandle,TRUE);\r
+       if (dxvadevicehandle) \r
+       {\r
+               d3ddevman->CloseDeviceHandle(dxvadevicehandle);\r
+               dxvadevicehandle=NULL;\r
+       }\r
+\r
+}\r
+\r
+DWORD OsdWin::getFilterCaps()\r
+{\r
+    if (!initted) return NULL;\r
+    D3DCAPS9 caps;\r
+    d3ddevice->GetDeviceCaps(&caps);\r
+    return caps.StretchRectFilterCaps;\r
+}\r
+       \r
+LPDIRECT3DVERTEXBUFFER9  OsdWin::InitVertexBuffer(DWORD width, DWORD height)\r
+{\r
+  LPDIRECT3DVERTEXBUFFER9 ret =NULL;\r
+  Video* video=Video::getInstance();\r
+  FLOAT texx=((float)video->getScreenWidth())/1024.f;\r
+  FLOAT texy=((float)video->getScreenHeight())/1024.f;\r
+  D3DCOLOR osdcolor=D3DCOLOR_RGBA(255,255,255,255);\r
+  osdvertices[0].c=osdcolor;\r
+  osdvertices[0].x=0.f-0.5f;\r
+  osdvertices[0].y=0.f-0.5f;\r
+  osdvertices[0].z=0.5f;\r
+  osdvertices[0].rhw=1.f;\r
+  osdvertices[0].u=0.f;\r
+  osdvertices[0].v=0.f;\r
+  osdvertices[1].c=osdcolor;\r
+  osdvertices[1].x=((float)width)-0.5f;\r
+  osdvertices[1].y=0.f-0.5f;\r
+  osdvertices[1].z=0.5f;\r
+  osdvertices[1].u=texx;\r
+  osdvertices[1].v=0.f;\r
+  osdvertices[1].rhw=1.f;\r
+  osdvertices[2].c=osdcolor;\r
+  osdvertices[2].x=((float)width)-0.5f;\r
+  osdvertices[2].y=((float)height)-0.5f;\r
+  osdvertices[2].z=0.5f;\r
+  osdvertices[2].rhw=1.f;\r
+  osdvertices[2].u=texx;\r
+  osdvertices[2].v=texy;\r
+  osdvertices[3].c=osdcolor;\r
+  osdvertices[3].x=0.f-0.5f;\r
+  osdvertices[3].y=((float)height)-0.5f;\r
+  osdvertices[3].z=0.5f;\r
+  osdvertices[3].rhw=1.f;\r
+  osdvertices[3].u=0.f;\r
+  osdvertices[3].v=texy;\r
+  \r
+  if (d3ddevice->CreateVertexBuffer(4*sizeof(OSDVERTEX),0,D3DFVF_OSDVERTEX,D3DPOOL_MANAGED,\r
+         &ret,NULL)!=D3D_OK) {\r
+         return NULL;\r
+  }\r
+  void *pvertex=NULL;\r
+  if (ret->Lock(0,sizeof(osdvertices),&pvertex,0)!=D3D_OK) {\r
+         return NULL;\r
+  }\r
+  memcpy(pvertex,osdvertices,sizeof(osdvertices));\r
+  ret->Unlock();\r
+  return ret;\r
+}\r
+\r
+int OsdWin::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+  initted = 0;\r
+  evrsupported=0;\r
+  if (d3ddevman) d3ddevman->Release();\r
+  d3drtsurf->Release();\r
+  d3ddevice->Release();\r
+  d3d->Release();\r
+  if (swapsurf) swapsurf->Release();\r
+  if (swappy) swappy->Release();\r
+\r
+  return 1;\r
+}\r
+\r
+void OsdWin::screenShot(const char* fileName)\r
+{\r
+  screen->screenShot(fileName);\r
+}\r
+\r
+void OsdWin::threadMethod()\r
+{\r
+       while (true)\r
+       {\r
+               DWORD waittime=10;\r
+               if (initted){\r
+                       if (evrstate==EVR_pres_off || evrstate==EVR_pres_pause) \r
+                       {\r
+                               Render();\r
+                       } else if (evrstate==EVR_pres_started)\r
+                       {\r
+                               LPDIRECT3DSURFACE9 surf;\r
+                               if (dsallocator) dsallocator->GetNextSurface(&surf,&waittime);\r
+                               if (surf==NULL)\r
+                               {\r
+                                       Render();\r
+                               }\r
+                               else\r
+                               {\r
+                                       RenderDS(surf);\r
+                                       surf->Release();\r
+                                       if (dsallocator) dsallocator->DiscardSurfaceandgetWait(&waittime);\r
+                               }\r
+                       }\r
+               }\r
+               threadCheckExit();\r
+               if (waittime!=0) Sleep(min(10,waittime));\r
+               //Sleep(1);\r
+       }\r
+}\r
+\r
+\r
+void OsdWin::threadPostStopCleanup()\r
+{\r
+       //Doing nothing\r
+       //goo;\r
+}\r
+\r
+\r
+// This function is called from the WinMain function in order to get Screen updates\r
+void OsdWin::Render()\r
+{\r
+       if (!initted) return ;\r
+       if (external_driving) {\r
+        DWORD time1=timeGetTime(); //Updates the Menue\r
+               if ((time1-lastrendertime)>200) {//5 fps for OSD updates are enough, avoids tearing\r
+                       InternalRendering(NULL);\r
+                       lastrendertime=timeGetTime();\r
+        } else {\r
+                  //Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads\r
+        }\r
+       } else {\r
+               DWORD time1=timeGetTime();\r
+               if ((time1-lastrendertime)>50) {//10 fps for OSD updates are enough, avoids tearing\r
+                       InternalRendering(NULL);\r
+                       lastrendertime=timeGetTime();\r
+               } else {\r
+                       //Sleep(5);\r
+               \r
+               }\r
+               \r
+       }\r
+}\r
+\r
+void OsdWin::RenderDS(LPDIRECT3DSURFACE9 present){\r
+       if (!initted) return; \r
+       if (external_driving) {\r
+               InternalRendering(present);\r
+        lastrendertime=timeGetTime();\r
+       }\r
+}\r
+\r
+\r
+void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){\r
+    BeginPainting();\r
+    HRESULT losty=d3ddevice->TestCooperativeLevel();\r
+    if (losty==D3DERR_DEVICELOST) {\r
+        //Sleep(10);\r
+               EndPainting();\r
+        return; //Device Lost\r
+    }\r
+    if (losty==D3DERR_DEVICENOTRESET){\r
+          EndPainting();\r
+       DoLost();\r
+       return;\r
+    }\r
+       WaitForSingleObject(event,INFINITE);\r
+       \r
+   \r
+       \r
+    \r
+    LPDIRECT3DSURFACE9 targetsurf;\r
+       if (swappy)\r
+       {\r
+               targetsurf=swapsurf;\r
+               d3ddevice->SetRenderTarget(0,swapsurf);//Stupid VMR manipulates the render target\r
+       } \r
+       else\r
+       {\r
+               targetsurf=d3drtsurf;\r
+               d3ddevice->SetRenderTarget(0,d3drtsurf);//Stupid VMR manipulates the render target\r
+       }\r
+       D3DSURFACE_DESC targetdesc;\r
+       targetsurf->GetDesc(&targetdesc);\r
+\r
+       if (external_driving) {\r
+               //Copy video to Backbuffer\r
+               if (present!=NULL ) {\r
+                       VideoWin* video =(VideoWin*) Video::getInstance();\r
+                       /*calculating destination rect */\r
+                       RECT destrect={0,0,/*video->getScreenWidth()*/ targetdesc.Width,\r
+                               /*video->getScreenHeight()*/targetdesc.Height};\r
+                       UCHAR mode=video->getMode();\r
+                       switch (mode) {\r
+                       case Video::EIGHTH:\r
+                       destrect.right=destrect.right/2;\r
+                       destrect.bottom=destrect.bottom/2;\r
+                       case Video::QUARTER:\r
+                       destrect.right=destrect.right/2+video->getPosx()*2;\r
+                       destrect.bottom=destrect.bottom/2+video->getPosy()*2;\r
+                       destrect.left=video->getPosx()*2;\r
+                       destrect.top=video->getPosy()*2;\r
+                       d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);\r
+                       break;\r
+                       };\r
+                       D3DSURFACE_DESC surf_desc;\r
+                       present->GetDesc(&surf_desc);//for chop sides\r
+                       RECT sourcerect= {0,0,surf_desc.Width,surf_desc.Height};\r
+                       if (video->getPseudoTVsize()==Video::ASPECT4X3 \r
+                               && video->getMode()==Video::NORMAL \r
+                               && video->getAspectRatio()==Video::ASPECT16X9) {\r
+                                       unsigned int correction=((double) (surf_desc.Width))*4.*9./3./16.;\r
+                                       sourcerect.left=(surf_desc.Width-correction)/2;\r
+                                       sourcerect.right=sourcerect.left+correction;\r
+                       }\r
+                       d3ddevice->StretchRect(present,&sourcerect,targetsurf ,&destrect,filter_type);\r
+\r
+               }\r
+       } else {\r
+               VideoWin* video =(VideoWin*) Video::getInstance();\r
+               //Clear Background\r
+               if (!video->isVideoOn()) d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);\r
+       }\r
+       LPDIRECT3DVERTEXBUFFER9 vb=NULL;\r
+       vb=InitVertexBuffer(targetdesc.Width,targetdesc.Height);\r
+\r
+       //Drawing the OSD\r
+       if (d3ddevice->BeginScene()==D3D_OK) {\r
+               d3ddevice->SetStreamSource(0,vb,0,sizeof(OSDVERTEX));\r
+               d3ddevice->SetFVF(D3DFVF_OSDVERTEX);\r
+               d3ddevice->SetTexture(0,((SurfaceWin*)screen)->getD3dtexture());\r
+               //d3ddevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);\r
+               d3ddevice->SetTextureStageState(0, D3DTSS_ALPHAOP,D3DTOP_MODULATE);\r
+\r
+        d3ddevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);\r
+        d3ddevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);\r
+\r
+\r
+               d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);\r
+               d3ddevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);\r
+               d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);\r
+               d3ddevice->SetRenderState(D3DRS_LIGHTING,FALSE);\r
+\r
+\r
+               d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);\r
+               d3ddevice->EndScene();\r
+               //Show it to the user!\r
+        HRESULT hres;\r
+               if (swappy)\r
+               {\r
+                       if (hres=swappy->Present(NULL,NULL,NULL,NULL,0)==D3DERR_DEVICELOST){\r
+                               //EndPainting();\r
+                               if (!external_driving) DoLost();\r
+                       }\r
+               } \r
+               else\r
+               {\r
+                       if (hres=d3ddevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST){\r
+                               //EndPainting();\r
+                               if (!external_driving) DoLost();\r
+                       }\r
+               }\r
+               \r
+       }\r
+       \r
+       vb->Release();\r
+       EndPainting();\r
+\r
+       \r
+//     if (!external_driving) {\r
+//             Sleep(4);//The User can wait for 4 milliseconds to see his changes\r
+//     }\r
+}\r
+\r
+bool OsdWin::DoLost(){\r
+       Log::getInstance()->log("OSD", Log::WARN, "Direct3D Device Lost! Reobtaining...");\r
+       ResetEvent(event);\r
+       if (external_driving && dsallocator!=NULL) {\r
+               dsallocator->LostDevice(d3ddevice,d3d); //Propagate the information through DS\r
+       }\r
+       //First we free up all resources\r
+       Video* video = Video::getInstance();\r
+       ((SurfaceWin*)screen)->ReleaseSurface();\r
+       if (d3drtsurf) d3drtsurf->Release();\r
+    d3drtsurf=NULL;\r
+       D3DPRESENT_PARAMETERS d3dparas;\r
+       ZeroMemory(&d3dparas,sizeof(d3dparas));\r
+       d3dparas.BackBufferWidth=BACKBUFFER_WIDTH;\r
+       d3dparas.BackBufferHeight=BACKBUFFER_HEIGHT;\r
+       d3dparas.Windowed=TRUE;\r
+       d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;\r
+\r
+       if (swapsurf) {swapsurf->Release();swapsurf=NULL;};\r
+       if (swappy) {swappy->Release();swappy=NULL;};\r
+\r
+       if (d3ddevice->Reset(&d3dparas)!=D3D_OK){\r
+               return false;\r
+       }\r
+    d3ddevice->GetRenderTarget(0,&d3drtsurf);\r
+       if (d3ddevman) d3ddevman->ResetDevice(d3ddevice,dxvatoken);\r
+       //InitVertexBuffer();\r
+    //Redraw Views, Chris could you add a member function to BoxStack, so that\r
+       // I can cause it to completely redraw the Views?\r
+       // Otherwise the OSD would be distorted after Device Lost\r
+       // FIXME\r
+       \r
+       SetEvent(event);\r
+\r
+\r
+       screen->create(video->getScreenWidth(), video->getScreenHeight());\r
+       screen->display();\r
+       \r
+       return true;\r
+\r
+}\r
+LPDIRECT3DDEVICE9 OsdWin::getD3dDev() {\r
+       WaitForSingleObject(event,INFINITE);//We will only return if we are initted\r
+       return d3ddevice;\r
+}\r
+\r
+LPDIRECT3D9 OsdWin::getD3d() {\r
+       WaitForSingleObject(event,INFINITE);//We will only return if we are initted\r
+       return d3d;\r
+}\r
+\r
+void OsdWin::BeginPainting() {//We synchronize calls to d3d between different threads\r
+       WaitForSingleObject(d3dmutex,INFINITE);\r
+       LockDevice();\r
+}\r
+\r
+void OsdWin::EndPainting() {\r
+       UnlockDevice();\r
+       ReleaseMutex(d3dmutex);\r
+}\r
+\r
+void OsdWin::setExternalDriving(DsAllocator* dsall,DWORD width, DWORD height) {\r
+       \r
+       if (swappy)\r
+       {\r
+               BeginPainting();\r
+               d3ddevice->StretchRect(swapsurf,NULL,d3drtsurf,NULL,filter_type);\r
+               LPDIRECT3DSWAPCHAIN9 temp=swappy;\r
+               LPDIRECT3DSURFACE9 tempsurf=swapsurf;\r
+               swappy=NULL;\r
+               swapsurf=NULL;\r
+               EndPainting();\r
+               tempsurf->Release();\r
+               temp->Release();\r
+       }\r
+\r
+       if (dsall==NULL) {\r
+               external_driving=false;\r
+               dsallocator=NULL;       \r
+               return;\r
+       }\r
+       WaitForSingleObject(event,INFINITE);//We will only return if we are initted\r
+       BeginPainting();\r
+\r
+       if (width>BACKBUFFER_WIDTH || height>BACKBUFFER_HEIGHT) \r
+       {\r
+               D3DPRESENT_PARAMETERS d3dparas;\r
+               ZeroMemory(&d3dparas,sizeof(d3dparas));\r
+               d3dparas.BackBufferWidth=width;\r
+               d3dparas.BackBufferHeight=height;\r
+               d3dparas.Windowed=TRUE;\r
+               d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;\r
+               if (d3ddevice->CreateAdditionalSwapChain(&d3dparas,&swappy)!=D3D_OK){\r
+                       Log::getInstance()->log("OSD", Log::WARN, "Could not create Swap Chain!");\r
+                       //return 0;\r
+               } else {\r
+                       swappy->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&swapsurf);\r
+               }\r
+        Log::getInstance()->log("OSD", Log::INFO, "Create Additional Swap Chain %d %d!",width,height);\r
+       }\r
+\r
+       dsallocator=dsall;\r
+       external_driving=true;\r
+       \r
+       EndPainting();\r
+}\r
+\r
+void OsdWin::Blank() {\r
+       WaitForSingleObject(event,INFINITE);\r
+       BeginPainting();\r
+       d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);\r
+       EndPainting();\r
+}\r
index a470fbceffba7a39d7ac35ea912b8a21e924cc6d..81f64f5601e66c0d793431eb6e1586c5a18b0f83 100644 (file)
--- a/osdwin.h
+++ b/osdwin.h
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef OSDWIN_H
-#define OSDWIN_H
-
-#include <stdio.h>
-
-#include "osd.h"
-#include "defines.h"
-#include "log.h"
-#include "threadwin.h"
-#include <winsock2.h>
-#include <d3d9.h>
-#include <Dxva2api.h>
-
-struct OSDVERTEX
-{
-       FLOAT x,y,z,rhw;
-       DWORD c;
-       FLOAT u,v;
-};
-
-#define D3DFVF_OSDVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE| D3DFVF_TEX1)
-
-class DsAllocator;
-
-
-
-class OsdWin : public Osd, public ThreadWin
-{
-  public:
-    OsdWin();
-    ~OsdWin();
-
-    int init(void* device);
-    int shutdown();
-
-    int getFD();
-
-    void screenShot(char* fileName);
-
-       void threadMethod();
-    void threadPostStopCleanup();
-
-       LPDIRECT3DDEVICE9 getD3dDev() ;
-       LPDIRECT3D9 getD3d() ;
-       // This function is called from the WinMain function in order to get Screen updates
-       void Render();
-       void RenderDS(LPDIRECT3DSURFACE9 present);
-       void BeginPainting();
-       void EndPainting();
-       void setExternalDriving(DsAllocator* dsall,DWORD width, DWORD height);
-       void Blank();
-    DWORD getFilterCaps();
-    DWORD getFilterType(){return filter_type;};
-    void setFilterType(D3DTEXTUREFILTERTYPE type) {filter_type=type;};
-
-
-
-       
-
-       enum EVR_state {
-               EVR_pres_off=0,
-               EVR_pres_started,
-               EVR_pres_pause
-       };
-
-       void SetEVRStatus(EVR_state new_state){evrstate=new_state;};
-       
-       IDirect3DDeviceManager9 * getD3dMan() {return d3ddevman;};
-       bool IsEvrSupported() {return evrsupported;};
-       HWND getWindow() {return window;};
-
-private:
-       void LockDevice();
-       void UnlockDevice();
-
-         LPDIRECT3D9 d3d;
-         LPDIRECT3DDEVICE9 d3ddevice;
-//       LPDIRECT3DVERTEXBUFFER9 d3dvb;
-         LPDIRECT3DSURFACE9 d3drtsurf;
-         LPDIRECT3DSWAPCHAIN9 swappy;
-         LPDIRECT3DSURFACE9 swapsurf;
-         DsAllocator* dsallocator;
-       // This indicates, that currently a video is played, thus the osd updates are driven by the Directshow Filtersystem
-       bool external_driving;
-       HANDLE d3dmutex;
-       DWORD lastrendertime;
-       void InternalRendering(LPDIRECT3DSURFACE9 present);
-       bool DoLost();
-       LPDIRECT3DVERTEXBUFFER9 InitVertexBuffer(DWORD width, DWORD height);
-       OSDVERTEX osdvertices[4];
-       HANDLE event;
-       D3DTEXTUREFILTERTYPE filter_type;
-       EVR_state evrstate;
-       bool evrsupported;
-       HWND window;
-
-       UINT dxvatoken;
-       IDirect3DDeviceManager9 *d3ddevman;
-       HANDLE  dxvadevicehandle;
-};
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef OSDWIN_H\r
+#define OSDWIN_H\r
+\r
+#include <stdio.h>\r
+\r
+#include "osd.h"\r
+#include "defines.h"\r
+#include "log.h"\r
+#include "threadwin.h"\r
+#include <winsock2.h>\r
+#include <d3d9.h>\r
+#include <Dxva2api.h>\r
+\r
+struct OSDVERTEX\r
+{\r
+       FLOAT x,y,z,rhw;\r
+       DWORD c;\r
+       FLOAT u,v;\r
+};\r
+\r
+#define D3DFVF_OSDVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE| D3DFVF_TEX1)\r
+\r
+class DsAllocator;\r
+\r
+\r
+\r
+class OsdWin : public Osd, public ThreadWin\r
+{\r
+  public:\r
+    OsdWin();\r
+    ~OsdWin();\r
+\r
+    int init(void* device);\r
+    int shutdown();\r
+\r
+    int getFD();\r
+\r
+    void screenShot(const char* fileName);\r
+\r
+    Surface * createNewSurface();\r
+\r
+       void threadMethod();\r
+    void threadPostStopCleanup();\r
+\r
+       LPDIRECT3DDEVICE9 getD3dDev() ;\r
+       LPDIRECT3D9 getD3d() ;\r
+       // This function is called from the WinMain function in order to get Screen updates\r
+       void Render();\r
+       void RenderDS(LPDIRECT3DSURFACE9 present);\r
+       void BeginPainting();\r
+       void EndPainting();\r
+       void setExternalDriving(DsAllocator* dsall,DWORD width, DWORD height);\r
+       void Blank();\r
+    DWORD getFilterCaps();\r
+    DWORD getFilterType(){return filter_type;};\r
+    void setFilterType(D3DTEXTUREFILTERTYPE type) {filter_type=type;};\r
+\r
+\r
+\r
+       \r
+\r
+       enum EVR_state {\r
+               EVR_pres_off=0,\r
+               EVR_pres_started,\r
+               EVR_pres_pause\r
+       };\r
+\r
+       void SetEVRStatus(EVR_state new_state){evrstate=new_state;};\r
+       \r
+       IDirect3DDeviceManager9 * getD3dMan() {return d3ddevman;};\r
+       bool IsEvrSupported() {return evrsupported;};\r
+       HWND getWindow() {return window;};\r
+\r
+private:\r
+       void LockDevice();\r
+       void UnlockDevice();\r
+\r
+         LPDIRECT3D9 d3d;\r
+         LPDIRECT3DDEVICE9 d3ddevice;\r
+//       LPDIRECT3DVERTEXBUFFER9 d3dvb;\r
+         LPDIRECT3DSURFACE9 d3drtsurf;\r
+         LPDIRECT3DSWAPCHAIN9 swappy;\r
+         LPDIRECT3DSURFACE9 swapsurf;\r
+         DsAllocator* dsallocator;\r
+       // This indicates, that currently a video is played, thus the osd updates are driven by the Directshow Filtersystem\r
+       bool external_driving;\r
+       HANDLE d3dmutex;\r
+       DWORD lastrendertime;\r
+       void InternalRendering(LPDIRECT3DSURFACE9 present);\r
+       bool DoLost();\r
+       LPDIRECT3DVERTEXBUFFER9 InitVertexBuffer(DWORD width, DWORD height);\r
+       OSDVERTEX osdvertices[4];\r
+       HANDLE event;\r
+       D3DTEXTUREFILTERTYPE filter_type;\r
+       EVR_state evrstate;\r
+       bool evrsupported;\r
+       HWND window;\r
+\r
+       UINT dxvatoken;\r
+       IDirect3DDeviceManager9 *d3ddevman;\r
+       HANDLE  dxvadevicehandle;\r
+};\r
+\r
+#endif\r
index f250b355f17228c7aed9e3c32a19141f341d0005..c4f956924470c1310b5e696a066ee9ed55930847 100644 (file)
--- a/player.cc
+++ b/player.cc
-/*
-    Copyright 2004-2008 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "player.h"
-
-#include "log.h"
-#include "audio.h"
-#include "video.h"
-#include "demuxervdr.h"
-#include "demuxerts.h"
-#include "vdr.h"
-#include "messagequeue.h"
-#include "remote.h"
-#include "message.h"
-#include "dvbsubtitles.h"
-#include "osdreceiver.h"
-
-#define USER_RESPONSE_TIME 500 // Milliseconds
-
-// ----------------------------------- Called from outside, one offs or info funcs
-
-Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver)
-: vfeed(this), afeed(this), tfeed(this)
-{
-  messageQueue = tmessageQueue;
-  messageReceiver = tmessageReceiver;
-  osdReceiver = tosdReceiver;
-  audio = Audio::getInstance();
-  video = Video::getInstance();
-  logger = Log::getInstance();
-  vdr = VDR::getInstance();
-  initted = false;
-  lengthBytes = 0;
-  lengthFrames = 0;
-  currentFrameNumber = 0;
-  state = S_STOP;
-  ifactor = 4;
-  is_pesrecording=true;
-
-  subtitlesShowing = false;
-
-  videoStartup = false;
-  threadBuffer = NULL;
-  blockSize = 100000;
-  startupBlockSize = 250000;
-  video->turnVideoOn();
-}
-
-Player::~Player()
-{
-  if (initted) shutdown();
-}
-
-int Player::init(bool p_isPesRecording,double framespersecond)
-{
-  if (initted) return 0;
-#ifndef WIN32
-  pthread_mutex_init(&mutex, NULL);
-#else
-  mutex=CreateMutex(NULL,FALSE,NULL);
-#endif
-  is_pesrecording = p_isPesRecording;
-  fps=framespersecond;
-  if (is_pesrecording)
-    demuxer = new DemuxerVDR();
-  else
-    demuxer = new DemuxerTS();
-  if (!demuxer) return 0;
-  subtitles = new DVBSubtitles(osdReceiver);
-  if (!subtitles) return 0;
-
-  teletext = new TeletextDecoderVBIEBU();
-  if (!teletext) return 0;
-  teletext->setRecordigMode(true);
-  unsigned int demux_video_size=2097152;
-   if (video->supportsh264()) demux_video_size*=5;
-  if (!demuxer->init(this, audio, video,teletext, demux_video_size,524288,65536, framespersecond, subtitles))
-  {
-    logger->log("Player", Log::ERR, "Demuxer failed to init");
-    shutdown();
-    return 0;
-  }
-
-  vfeed.init();
-  afeed.init();
-  tfeed.init();
-
-  video->stop();
-  video->blank();
-  audio->stop();
-
-  initted = true;
-  return 1;
-}
-
-int Player::shutdown()
-{
-  if (!initted) return 0;
-  switchState(S_STOP);
-  initted = false;
-
-  delete demuxer;
-  demuxer = NULL;
-  delete subtitles;
-  subtitles = NULL;
-  delete teletext;
-  teletext = NULL;
-
-#ifdef WIN32
-  CloseHandle(mutex);
-#endif
-
-  return 1;
-}
-
-void Player::setStartFrame(ULONG startFrame)
-{
-  currentFrameNumber = startFrame;
-}
-
-void Player::setLengthBytes(ULLONG length)
-{
-  lengthBytes = length;
-  logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
-}
-
-void Player::setLengthFrames(ULONG length)
-{
-  lengthFrames = length;
-  logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
-}
-
-ULONG Player::getLengthFrames()
-{
-  return lengthFrames;
-}
-
-ULONG Player::getCurrentFrameNum()
-{
-  if (startup) return 0;
-  switch(state)
-  {
-    case S_PLAY:
-    case S_PAUSE_P:
-      return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
-    case S_PAUSE_I:
-    case S_FFWD:
-    case S_FBWD:
-      return currentFrameNumber;
-    default:
-      return 0; // shouldn't happen
-  }
-}
-
-bool* Player::getDemuxerMpegAudioChannels()
-{
-  return demuxer->getmpAudioChannels();
-}
-
-bool* Player::getDemuxerAc3AudioChannels()
-{
-  return demuxer->getac3AudioChannels();
-}
-
-bool* Player::getDemuxerSubtitleChannels()
-{
-  return demuxer->getSubtitleChannels();
-}
-
-int Player::getCurrentAudioChannel()
-{
-    if (is_pesrecording) {
-        return demuxer->getselAudioChannel();
-    } else {
-        return ((DemuxerTS*)demuxer)->getAID();
-    }
-}
-
-int Player::getCurrentSubtitleChannel()
-{
-    if (is_pesrecording) {
-        return demuxer->getselSubtitleChannel();
-    } else {
-        return ((DemuxerTS*)demuxer)->getSubID();
-    }
-}
-
-void Player::setSubtitleChannel(int newChannel)
-{
-    if (is_pesrecording) {
-        return demuxer->setDVBSubtitleStream(newChannel);
-    } else {
-        return ((DemuxerTS*)demuxer)->setSubID(newChannel);
-    }
-}
-
-int *Player::getTeletxtSubtitlePages()
-{
-    return teletext->getSubtitlePages();
-}
-
-void Player::setAudioChannel(int newChannel, int type)
-{
-    if (is_pesrecording) {
-        demuxer->setAudioStream(newChannel);
-        return;
-    } else {
-        ((DemuxerTS*)demuxer)->setAID(newChannel,type);
-        return;
-    }
-}
-
-bool Player::toggleSubtitles()
-{
-  if (!subtitlesShowing)
-  {
-    subtitlesShowing = true;
-    subtitles->show();
-  }
-  else
-  {
-    subtitlesShowing = false;
-    subtitles->hide();
-  }
-  return subtitlesShowing;
-}
-
-void  Player::turnSubtitlesOn(bool ison) {
- if (ison)
-  {
-    subtitlesShowing = true;
-    subtitles->show();
-  }
-  else
-  {
-    subtitlesShowing = false;
-    subtitles->hide();
-  }
-
-}
-
-Channel Player::getDemuxerChannel() {
-    if (!is_pesrecording) {
-        return ((DemuxerTS*) demuxer)->getChannelInfo();
-    } 
-    return Channel(); //Should not happen!
-}
-
-
-// ----------------------------------- Externally called events
-
-void Player::play()
-{
-  if (!initted) return;
-  if (state == S_PLAY) return;
-  lock();
-
-  bool doUnlock = false;
-  if (state == S_PAUSE_P) doUnlock = true;
-  switchState(S_PLAY);
-  if (doUnlock) unLock();
-}
-
-void Player::stop()
-{
-  if (!initted) return;
-  if (state == S_STOP) return;
-  lock();
-  logger->log("Player", Log::DEBUG, "Stop called lock");
-  switchState(S_STOP);
-  unLock();
-}
-
-void Player::pause()
-{
-  if (!initted) return;
-  lock();
-
-  if ((state == S_FFWD) || (state == S_FBWD))
-  {
-    switchState(S_PAUSE_I);
-  }
-  else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
-  {
-    switchState(S_PLAY);
-  }
-  else
-  {
-    switchState(S_PAUSE_P);
-  }
-
-  unLock();
-}
-
-void Player::fastForward()
-{
-  if (!initted) return;
-  lock();
-
-  if (state == S_FFWD)
-  {
-    // change the rate
-    switch(ifactor)
-    {
-      case 4: ifactor = 8; break;
-      case 8: ifactor = 16; break;
-      case 16: ifactor = 32; break;
-      case 32: ifactor = 4; break;
-    }
-  }
-  else
-  {
-    ifactor = 4;
-    switchState(S_FFWD);
-  }
-  unLock();
-}
-
-void Player::fastBackward()
-{
-  if (!initted) return;
-  lock();
-
-  if (state == S_FBWD)
-  {
-    // change the rate
-    switch(ifactor)
-    {
-      case 4: ifactor = 8; break;
-      case 8: ifactor = 16; break;
-      case 16: ifactor = 32; break;
-      case 32: ifactor = 4; break;
-    }
-  }
-  else
-  {
-    ifactor = 4;
-    switchState(S_FBWD);
-  }
-  unLock();
-}
-
-void Player::jumpToPercent(double percent)
-{
-  lock();
-  logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent);
-  ULONG newFrame = (ULONG)(percent * lengthFrames / 100);
-  switchState(S_JUMP, newFrame);
-//  unLock(); - let thread unlock this
-}
-
-void Player::jumpToMark(int mark)
-{
-  lock();
-  logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);
-  switchState(S_JUMP, mark);
-//  unLock(); - let thread unlock this
-}
-
-void Player::jumpToFrameP(int newFrame)
-{
-  lock();
-  logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);
-  switchState(S_JUMP_PI, newFrame);
-  unLock();
-}
-
-void Player::skipForward(int seconds)
-{
-  lock();
-  logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
-  ULONG newFrame = getCurrentFrameNum();
-  if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
-  newFrame +=(ULONG) (((double)seconds) * fps);
-  if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
-  else switchState(S_JUMP, newFrame);
-//  unLock(); - let thread unlock this
-}
-
-void Player::skipBackward(int seconds)
-{
-  lock();
-  logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
-  long newFrame = getCurrentFrameNum();
-  if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
-  newFrame -= (ULONG) (((double)seconds) * fps);
-  if (newFrame < 0) newFrame = 0;
-  switchState(S_JUMP, newFrame);
-//  unLock(); - let thread unlock this
-}
-
-// ----------------------------------- Implementations called events
-
-void Player::switchState(UCHAR toState, ULONG jumpFrame)
-{
-  if (!initted) return;
-
-  logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
-
-  switch(state) // current state selector
-  {
-    case S_PLAY: // from S_PLAY -----------------------------------
-    {
-      switch(toState)
-      {
-        case S_PLAY: // to S_PLAY
-        {
-          return;
-        }
-        case S_PAUSE_P: // to S_PAUSE_P
-        {
-          video->pause();
-          audio->pause();
-          state = S_PAUSE_P;
-          return;
-        }
-        case S_PAUSE_I: // to S_PAUSE_I
-        {
-          // can't occur
-          return;
-        }
-        case S_FFWD: // to S_FFWD
-        {
-          currentFrameNumber = getCurrentFrameNum();
-          audio->systemMuteOn();
-          threadStop();
-          vfeed.stop();
-          afeed.stop();
-          tfeed.stop();
-          subtitles->stop();
-          demuxer->flush();
-          state = S_FFWD;
-          threadStart();
-          return;
-        }
-        case S_FBWD: // to S_FBWD
-        {
-          currentFrameNumber = getCurrentFrameNum();
-          audio->systemMuteOn();
-          threadStop();
-          vfeed.stop();
-          afeed.stop();
-          tfeed.stop();
-          subtitles->stop();
-          demuxer->flush();
-          state = S_FBWD;
-          threadStart();
-          return;
-        }
-        case S_STOP: // to S_STOP
-        {
-          vfeed.stop();
-          afeed.stop();
-          tfeed.stop();
-          subtitles->stop();
-          threadStop();
-          video->stop();
-          video->blank();
-          audio->stop();
-          audio->unPause();
-          video->reset();
-          demuxer->reset();
-          state = S_STOP;
-          return;
-        }
-        case S_JUMP: // to S_JUMP
-        {
-          restartAtFrame(jumpFrame);
-          return;
-        }
-        case S_JUMP_PI: // to S_JUMP_PI
-        {
-          audio->systemMuteOn();
-          threadStop();
-          vfeed.stop();
-          afeed.stop();
-          tfeed.stop();
-          subtitles->stop();
-          demuxer->flush();
-          state = S_PAUSE_I;
-          video->reset();
-          video->play();
-          restartAtFramePI(jumpFrame);
-          return;
-        }
-      }
-    }
-    case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
-    {
-      switch(toState)
-      {
-        case S_PLAY: // to S_PLAY
-        {
-          video->unPause();
-          audio->unPause();
-          state = S_PLAY;
-          return;
-        }
-        case S_PAUSE_P: // to S_PAUSE_P
-        {
-          return;
-        }
-        case S_PAUSE_I: // to S_PAUSE_I
-        {
-          return;
-        }
-        case S_FFWD: // to S_FFWD
-        {
-          currentFrameNumber = getCurrentFrameNum();
-          audio->systemMuteOn();
-          vfeed.stop();
-          afeed.stop();
-          tfeed.stop();
-          subtitles->stop();
-          threadStop();
-          video->unPause();
-          audio->unPause();
-          state = S_FFWD;
-          threadStart();
-          return;
-        }
-        case S_FBWD: // to S_FBWD
-        {
-          currentFrameNumber = getCurrentFrameNum();
-          audio->systemMuteOn();
-          vfeed.stop();
-          afeed.stop();
-          tfeed.stop();
-          subtitles->stop();
-          threadStop();
-          video->unPause();
-          audio->unPause();
-          state = S_FBWD;
-          threadStart();
-          return;
-        }
-        case S_STOP: // to S_STOP
-        {
-          vfeed.stop();
-          afeed.stop();
-          tfeed.stop();
-          subtitles->stop();
-          threadStop();
-          video->stop();
-          video->blank();
-          audio->stop();
-          video->reset();
-          audio->unPause();
-          demuxer->reset();
-          audio->systemMuteOff();
-          state = S_STOP;
-          return;
-        }
-        case S_JUMP: // to S_JUMP
-        {
-          state = S_PLAY;
-          audio->systemMuteOn();
-          audio->unPause();
-          restartAtFrame(jumpFrame);
-          return;
-        }
-        case S_JUMP_PI: // to S_JUMP_PI
-        {
-          audio->systemMuteOn();
-          audio->unPause();
-          threadStop();
-          vfeed.stop();
-          afeed.stop();
-          tfeed.stop();
-          subtitles->stop();
-          demuxer->flush();
-          state = S_PAUSE_I;
-          video->reset();
-          video->play();
-          restartAtFramePI(jumpFrame);
-          return;
-        }
-      }
-    }
-    case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
-    {
-      switch(toState)
-      {
-        case S_PLAY: // to S_PLAY
-        {
-          state = S_PLAY;
-          restartAtFrame(currentFrameNumber);
-          return;
-        }
-        case S_PAUSE_P: // to S_PAUSE_P
-        {
-          return;
-        }
-        case S_PAUSE_I: // to S_PAUSE_I
-        {
-          return;
-        }
-        case S_FFWD: // to S_FFWD
-        {
-          state = S_FFWD;
-          threadStart();
-          return;
-        }
-        case S_FBWD: // to S_FBWD
-        {
-          state = S_FBWD;
-          threadStart();
-          return;
-        }
-        case S_STOP: // to S_STOP
-        {
-          video->stop();
-          video->blank();
-          audio->stop();
-          video->reset();
-          demuxer->reset();
-          audio->systemMuteOff();
-          state = S_STOP;
-          return;
-        }
-        case S_JUMP: // to S_JUMP
-        {
-          state = S_PLAY;
-          restartAtFrame(jumpFrame);
-          return;
-        }
-        case S_JUMP_PI: // to S_JUMP_PI
-        {
-          restartAtFramePI(jumpFrame);
-          return;
-        }
-      }
-    }
-    case S_FFWD: // from S_FFWD -----------------------------------
-    {
-      switch(toState)
-      {
-        case S_PLAY: // to S_PLAY
-        {
-          state = S_PLAY;
-          ULONG stepback = (ULONG)(((double)USER_RESPONSE_TIME * ifactor) * fps / 1000.);
-          if (stepback < currentFrameNumber)
-            currentFrameNumber -= stepback;
-          else
-            currentFrameNumber = 0;
-          restartAtFrame(currentFrameNumber);
-          return;
-        }
-        case S_PAUSE_P: // to S_PAUSE_P
-        {
-          // can't occur
-          return;
-        }
-        case S_PAUSE_I: // to S_PAUSE_I
-        {
-          threadStop();
-          state = S_PAUSE_I;
-          return;
-        }
-        case S_FFWD: // to S_FFWD
-        {
-          return;
-        }
-        case S_FBWD: // to S_FBWD
-        {
-          threadStop();
-          state = S_FBWD;
-          threadStart();
-          return;
-        }
-        case S_STOP: // to S_STOP
-        {
-          threadStop();
-          video->stop();
-          video->blank();
-          audio->stop();
-          video->reset();
-          demuxer->reset();
-          state = S_STOP;
-          return;
-        }
-        case S_JUMP: // to S_JUMP
-        {
-          state = S_PLAY;
-          restartAtFrame(jumpFrame);
-          return;
-        }
-        case S_JUMP_PI: // to S_JUMP_PI
-        {
-          threadStop();
-          state = S_PAUSE_I;
-          restartAtFramePI(jumpFrame);
-          return;
-        }
-      }
-    }
-    case S_FBWD: // from S_FBWD -----------------------------------
-    {
-      switch(toState)
-      {
-        case S_PLAY: // to S_PLAY
-        {
-          state = S_PLAY;
-          restartAtFrame(currentFrameNumber);
-          return;
-        }
-        case S_PAUSE_P: // to S_PAUSE_P
-        {
-          // can't occur
-          return;
-        }
-        case S_PAUSE_I: // to S_PAUSE_I
-        {
-          threadStop();
-          state = S_PAUSE_I;
-          return;
-        }
-        case S_FFWD: // to S_FFWD
-        {
-          threadStop();
-          state = S_FFWD;
-          threadStart();
-          return;
-        }
-        case S_FBWD: // to S_FBWD
-        {
-          return;
-        }
-        case S_STOP: // to S_STOP
-        {
-          threadStop();
-          video->stop();
-          video->blank();
-          audio->stop();
-          video->reset();
-          demuxer->reset();
-          state = S_STOP;
-          return;
-        }
-        case S_JUMP: // to S_JUMP
-        {
-          state = S_PLAY;
-          restartAtFrame(jumpFrame);
-          return;
-        }
-        case S_JUMP_PI: // to S_JUMP_PI
-        {
-          threadStop();
-          state = S_PAUSE_I;
-          restartAtFramePI(jumpFrame);
-          return;
-        }
-      }
-    }
-    case S_STOP: // from S_STOP -----------------------------------
-    {
-      switch(toState)
-      {
-        case S_PLAY: // to S_PLAY
-        {
-          startup = true;
-
-          audio->reset();
-          audio->setStreamType(Audio::MPEG2_PES);
-          audio->systemMuteOff();
-          video->reset();
-          demuxer->reset();
-          // FIXME use restartAtFrame here?
-          if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
-          demuxer->setFrameNum(currentFrameNumber);
-          demuxer->seek();
-          videoStartup = true;
-          state = S_PLAY;
-          threadStart();
-          logger->log("Player", Log::DEBUG, "Immediate play");
-          afeed.start();
-          vfeed.start();
-          tfeed.start();
-          subtitles->start();
-          video->sync();
-          audio->sync();
-          audio->play();
-          video->pause();
-          return;
-        }
-        case S_PAUSE_P: // to S_PAUSE_P
-        {
-          return;
-        }
-        case S_PAUSE_I: // to S_PAUSE_I
-        {
-          return;
-        }
-        case S_FFWD: // to S_FFWD
-        {
-          return;
-        }
-        case S_FBWD: // to S_FBWD
-        {
-          return;
-        }
-        case S_STOP: // to S_STOP
-        {
-          return;
-        }
-        case S_JUMP: // to S_JUMP
-        {
-          return;
-        }
-        case S_JUMP_PI: // to S_JUMP_PI
-        {
-          return;
-        }
-      }
-    }
-    // case S_JUMP cannot be a start state because it auto flips to play
-    // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I
-  }
-}
-
-// ----------------------------------- Internal functions
-
-void Player::lock()
-{
-#ifndef WIN32
-  pthread_mutex_lock(&mutex);
-  logger->log("Player", Log::DEBUG, "LOCKED");
-
-#else
-   WaitForSingleObject(mutex, INFINITE);
-#endif
-}
-
-void Player::unLock()
-{
-#ifndef WIN32
-  logger->log("Player", Log::DEBUG, "UNLOCKING");
-  pthread_mutex_unlock(&mutex);
-#else
-   ReleaseMutex(mutex);
-#endif
-}
-
-void Player::restartAtFrame(ULONG newFrame)
-{
-  vfeed.stop();
-  afeed.stop();
-  tfeed.stop();
-  subtitles->stop();
-  threadStop();
-  video->stop();
-  video->reset();
-  audio->reset();
-  audio->setStreamType(Audio::MPEG2_PES);
-  demuxer->flush();
-  demuxer->seek();
-  currentFrameNumber = newFrame;
-  demuxer->setFrameNum(newFrame);
-  videoStartup = true;
-  afeed.start();
-  tfeed.start();
-  vfeed.start();
-  subtitles->start();
-  threadStart();
-  audio->play();
-  video->sync();
-  audio->sync();
-  audio->systemMuteOff();
-  audio->doMuting();
-}
-
-
-void Player::restartAtFramePI(ULONG newFrame)
-{
-  ULLONG filePos;
-  ULONG nextiframeNumber;
-  ULONG iframeLength;
-  ULONG iframeNumber;
-
-  UCHAR* buffer;
-  UINT amountReceived;
-  UINT videoLength;
-
-  // newFrame could be anywhere, go forwards to next I-Frame
-  if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
-
-  // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
-  vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
-
-  buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
-  if (!vdr->isConnected())
-  {
-    if (buffer) free(buffer);
-    doConnectionLost();
-  }
-  else
-  {
-    videoLength = demuxer->stripAudio(buffer, amountReceived);
-    video->displayIFrame(buffer, videoLength);
-    video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
-    free(buffer);
-    currentFrameNumber = iframeNumber;
-  }
-}
-
-void Player::doConnectionLost()
-{
-  logger->log("Player", Log::DEBUG, "Connection lost, sending message");
-  Message* m = new Message();
-  m->to = messageReceiver;
-  m->from = this;
-  m->message = Message::PLAYER_EVENT;
-  m->parameter = Player::CONNECTION_LOST;
-  messageQueue->postMessage(m);
-}
-
-// ----------------------------------- Callback
-
-void Player::call(void* caller)
-{
-  if (caller == demuxer)
-  {
-    logger->log("Player", Log::DEBUG, "Callback from demuxer");
-
-    if (video->getTVsize() == Video::ASPECT4X3)
-    {
-      logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
-      return;
-    }
-
-    int dxCurrentAspect = demuxer->getAspectRatio();
-    if (dxCurrentAspect == Demuxer::ASPECT_4_3)
-    {
-      logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
-      video->setAspectRatio(Video::ASPECT4X3);
-
-      Message* m = new Message();
-      m->from = this;
-      m->to = messageReceiver;
-      m->message = Message::PLAYER_EVENT;
-      m->parameter = Player::ASPECT43;
-      messageQueue->postMessageFromOuterSpace(m);
-    }
-    else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
-    {
-      logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
-      video->setAspectRatio(Video::ASPECT16X9);
-
-      Message* m = new Message();
-      m->from = this;
-      m->to = messageReceiver;
-      m->message = Message::PLAYER_EVENT;
-      m->parameter = Player::ASPECT169;
-      messageQueue->postMessageFromOuterSpace(m);
-    }
-    else
-    {
-      logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
-    }
-
-  }
-  else
-  {
-    if (videoStartup)
-    {
-      videoStartup = false;
-      video->reset();
-      video->play();
-      video->sync();
-      vfeed.release();
-      unLock();
-    }
-
-    threadSignalNoLock();
-  }
-}
-
-// ----------------------------------- Feed thread
-
-void Player::threadMethod()
-{
-  // this method used to be simple, the only thing it does
-  // is farm out to threadFeed Live/Play/Scan
-  // All the guff is to support scan hitting one end
-
-  if ((state == S_FFWD) || (state == S_FBWD))
-  {
-    threadFeedScan();
-    // if this returns then scan hit one end
-    if (state == S_FFWD) // scan hit the end. stop
-    {
-      threadCheckExit();
-      Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
-      m->to = messageReceiver;
-      m->from = this;
-      m->message = Message::PLAYER_EVENT;
-      m->parameter = STOP_PLAYBACK;
-      logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
-      messageQueue->postMessage(m);
-      logger->log("Player", Log::DEBUG, "Message posted...");
-      return;
-    }
-    // if execution gets to here, threadFeedScan hit the start, go to play mode
-    state = S_PLAY;
-    audio->reset();
-    audio->setStreamType(Audio::MPEG2_PES);
-    demuxer->flush();
-    demuxer->seek();
-    demuxer->setFrameNum(currentFrameNumber);
-    videoStartup = true;
-    afeed.start();
-    tfeed.start();
-    vfeed.start();
-    subtitles->start();
-    audio->play();
-    audio->sync();
-    audio->systemMuteOff();
-    audio->doMuting();
-  }
-
-  if (state == S_PLAY) threadFeedPlay();
-}
-
-void Player::threadFeedPlay()
-{
-  ULLONG feedPosition;
-  UINT thisRead, writeLength, thisWrite, askFor;
-  time_t lastRescan = time(NULL);
-
-  feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
-  if (!vdr->isConnected()) { doConnectionLost(); return; }
-  logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
-
-
-  while(1)
-  {
-    thisRead = 0;
-    writeLength = 0;
-    thisWrite = 0;
-
-    threadCheckExit();
-
-    // If we havn't rescanned for a while..
-    if ((lastRescan + 60) < time(NULL))
-    {
-      lengthBytes = vdr->rescanRecording(&lengthFrames);
-      if (!vdr->isConnected()) { doConnectionLost(); return; }
-      logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
-      lastRescan = time(NULL);
-    }
-
-    if (feedPosition >= lengthBytes) break;  // finished playback
-
-    if (startup)
-    {
-      if (startupBlockSize > lengthBytes)
-        askFor = lengthBytes; // is a very small recording!
-      else
-        askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
-    }
-    else
-    {
-      if ((feedPosition + blockSize) > lengthBytes) // last block of recording
-        askFor = lengthBytes - feedPosition;
-      else // normal
-        askFor = blockSize;
-    }
-    //logger->log("Player", Log::DEBUG, "Get Block in");
-
-    threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
-    //logger->log("Player", Log::DEBUG, "Get Block out");
-
-    feedPosition += thisRead;
-
-    if (!vdr->isConnected())
-    {
-      doConnectionLost();
-      return;
-    }
-
-    if (!threadBuffer) break;
-
-    if (startup)
-    {
-      int a_stream = demuxer->scan(threadBuffer, thisRead);
-      demuxer->setAudioStream(a_stream);
-      logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
-      startup = false;
-    }
-
-    threadCheckExit();
-
-    while(writeLength < thisRead)
-    {
-      //logger->log("Player", Log::DEBUG, "Put in");
-      thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
-      //logger->log("Player", Log::DEBUG, "Put out");
-      writeLength += thisWrite;
-
-      if (!thisWrite)
-      {
-        // demuxer is full and can't take anymore
-        threadLock();
-        threadWaitForSignal();
-        threadUnlock();
-      }
-
-      threadCheckExit();
-    }
-
-    free(threadBuffer);
-    threadBuffer = NULL;
-
-  }
-
-  // end of recording
-  logger->log("Player", Log::DEBUG, "Recording playback ends");
-
-  if (videoStartup) // oh woe. there never was a stream, I was conned!
-  {
-    videoStartup = false;
-    unLock();
-    MILLISLEEP(500); // I think this will solve a race
-  }
-
-  threadCheckExit();
-
-
-  Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
-  m->to = messageReceiver;
-  m->from = this;
-  m->message = Message::PLAYER_EVENT;
-  m->parameter = Player::STOP_PLAYBACK;
-  logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
-  messageQueue->postMessage(m);
-}
-
-void Player::threadFeedScan()
-{
-  // This method is actually really simple - get frame from vdr,
-  // spit it at the video chip, wait for a time. Most of the code here
-  // is to get the wait right so that the scan occurs at the correct rate.
-
-  ULONG direction = 0;
-  ULONG baseFrameNumber = 0;
-  ULONG iframeNumber = 0;
-  ULONG iframeLength = 0;
-  ULLONG filePos;
-  UINT amountReceived;
-  UINT videoLength;
-
-#ifndef WIN32
-  struct timeval clock0 = {0,0};  // Time stamp after fetching I-frame info
-  struct timeval clock1 = {0,0};  // Time stamp after fetching I-frame data
-  struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
-#else
-  DWORD clock0 = 0, clock1 = 0, clock2 = 0;
-#endif
-
-  int frameTimeOffset = 0; // Time in msec between frames
-  int disp_msec = 0;  // Time taken to display data
-  int total_msec = 0; // Time taken to fetch data and display it
-  int sleepTime = 0;
-
-  if (state == S_FFWD) direction = 1; // and 0 for backward
-
-  while(1)
-  {
-    // Fetch I-frames until we get one that can be displayed in good time
-    // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
-
-    baseFrameNumber = currentFrameNumber;
-    do
-    {
-      threadCheckExit();
-      if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
-        return;
-
-      if (iframeNumber >= lengthFrames) return;
-        // scan has got to the end of what we knew to be there before we started scanning
-
-      baseFrameNumber = iframeNumber;
-      frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor));
-#ifndef WIN32
-      gettimeofday(&clock0, NULL);
-#else
-      clock0 = timeGetTime();
-#endif
-    }
-#ifndef WIN32
-    while (clock2.tv_sec != 0 &&
-          (clock0.tv_sec - clock2.tv_sec) * 1000 +
-          (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
-#else
-    while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
-#endif
-    logger->log("Player", Log::DEBUG, "XXX Got frame");
-
-    threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
-    
-    if (!vdr->isConnected())
-    {
-      if (threadBuffer) free(threadBuffer);
-      doConnectionLost();
-      break;
-    }
-    
-#ifndef WIN32
-    gettimeofday(&clock1, NULL);
-    if (clock2.tv_sec != 0)
-      sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
-                + (clock2.tv_usec - clock1.tv_usec) / 1000
-                + frameTimeOffset - disp_msec;
-#else
-    clock1 = timeGetTime();
-    if (clock2 != 0)
-      sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
-#endif
-    if (sleepTime < 0) sleepTime = 0;
-    threadCheckExit();
-    MILLISLEEP(sleepTime);
-   logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
-
-    videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
-    video->displayIFrame(threadBuffer, videoLength);
-    currentFrameNumber = iframeNumber;
-    free(threadBuffer);
-    threadBuffer = NULL;
-
-#ifndef WIN32
-    gettimeofday(&clock2, NULL);
-    total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
-               + (clock2.tv_usec - clock0.tv_usec) / 1000
-               - sleepTime;
-    disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
-              + (clock2.tv_usec - clock1.tv_usec) / 1000
-              - sleepTime;
-#else
-    clock2 = timeGetTime();
-    total_msec = clock2 - clock0 - sleepTime;
-    disp_msec = clock2 - clock1 - sleepTime;
-#endif
-    logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
-  }
-}
-
-void Player::threadPostStopCleanup()
-{
-  if (threadBuffer)
-  {
-    free(threadBuffer);
-    threadBuffer = NULL;
-  }
-}
-
-// ----------------------------------- Dev
-
-#ifdef DEV
-void Player::test1()
-{
-  logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
-}
-
-void Player::test2()
-{
-  logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
-}
-#endif
+/*\r
+    Copyright 2004-2008 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "player.h"\r
+\r
+#include "log.h"\r
+#include "audio.h"\r
+#include "video.h"\r
+#include "demuxervdr.h"\r
+#include "demuxerts.h"\r
+#include "vdr.h"\r
+#include "messagequeue.h"\r
+#include "remote.h"\r
+#include "message.h"\r
+#include "dvbsubtitles.h"\r
+#include "osdreceiver.h"\r
+\r
+#define USER_RESPONSE_TIME 500 // Milliseconds\r
+\r
+// ----------------------------------- Called from outside, one offs or info funcs\r
+\r
+Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver)\r
+: vfeed(this), afeed(this), tfeed(this)\r
+{\r
+  messageQueue = tmessageQueue;\r
+  messageReceiver = tmessageReceiver;\r
+  osdReceiver = tosdReceiver;\r
+  audio = Audio::getInstance();\r
+  video = Video::getInstance();\r
+  logger = Log::getInstance();\r
+  vdr = VDR::getInstance();\r
+  initted = false;\r
+  lengthBytes = 0;\r
+  lengthFrames = 0;\r
+  currentFrameNumber = 0;\r
+  state = S_STOP;\r
+  ifactor = 4;\r
+  is_pesrecording=true;\r
+\r
+  subtitlesShowing = false;\r
+\r
+  videoStartup = false;\r
+  threadBuffer = NULL;\r
\r
+  blockSize = 100000;\r
+  startupBlockSize = 250000;\r
+  video->turnVideoOn();\r
+}\r
+\r
+Player::~Player()\r
+{\r
+  if (initted) shutdown();\r
+}\r
+\r
+int Player::init(bool p_isPesRecording,double framespersecond)\r
+{\r
+  if (initted) return 0;\r
+#ifndef WIN32\r
+  pthread_mutex_init(&mutex, NULL);\r
+#else\r
+  mutex=CreateMutex(NULL,FALSE,NULL);\r
+#endif\r
+  is_pesrecording = p_isPesRecording;\r
+  fps=framespersecond;\r
+  if (is_pesrecording)\r
+    demuxer = new DemuxerVDR();\r
+  else\r
+    demuxer = new DemuxerTS();\r
+  if (!demuxer) return 0;\r
+  subtitles = new DVBSubtitles(osdReceiver);\r
+  if (!subtitles) return 0;\r
+\r
+  teletext = new TeletextDecoderVBIEBU();\r
+  if (!teletext) return 0;\r
+  teletext->setRecordigMode(true);\r
+  unsigned int demux_video_size=2097152;\r
+   if (video->supportsh264()) demux_video_size*=5;\r
\r
+  if (!demuxer->init(this, audio, video,teletext, demux_video_size,524288,65536, framespersecond, subtitles))\r
+  {\r
+    logger->log("Player", Log::ERR, "Demuxer failed to init");\r
+    shutdown();\r
+    return 0;\r
+  }\r
+\r
+  vfeed.init();\r
+  afeed.init();\r
+  tfeed.init();\r
+\r
+  video->stop();\r
+  video->blank();\r
+  audio->stop();\r
+\r
+  initted = true;\r
+  return 1;\r
+}\r
+\r
+int Player::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+  switchState(S_STOP);\r
+  initted = false;\r
+\r
+  delete demuxer;\r
+  demuxer = NULL;\r
+  delete subtitles;\r
+  subtitles = NULL;\r
+  delete teletext;\r
+  teletext = NULL;\r
+\r
+#ifdef WIN32\r
+  CloseHandle(mutex);\r
+#endif\r
+\r
+  return 1;\r
+}\r
+\r
+void Player::setStartFrame(ULONG startFrame)\r
+{\r
+  currentFrameNumber = startFrame;\r
+}\r
+\r
+void Player::setLengthBytes(ULLONG length)\r
+{\r
+  lengthBytes = length;\r
+  logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);\r
+}\r
+\r
+void Player::setLengthFrames(ULONG length)\r
+{\r
+  lengthFrames = length;\r
+  logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);\r
+}\r
+\r
+ULONG Player::getLengthFrames()\r
+{\r
+  return lengthFrames;\r
+}\r
+\r
+ULONG Player::getCurrentFrameNum()\r
+{\r
+  if (startup) return 0;\r
+  switch(state)\r
+  {\r
+    case S_PLAY:\r
+    case S_PAUSE_P:\r
+      return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());\r
+    case S_PAUSE_I:\r
+    case S_FFWD:\r
+    case S_FBWD:\r
+      return currentFrameNumber;\r
+    default:\r
+      return 0; // shouldn't happen\r
+  }\r
+}\r
+\r
+bool* Player::getDemuxerMpegAudioChannels()\r
+{\r
+  return demuxer->getmpAudioChannels();\r
+}\r
+\r
+bool* Player::getDemuxerAc3AudioChannels()\r
+{\r
+  return demuxer->getac3AudioChannels();\r
+}\r
+\r
+bool* Player::getDemuxerSubtitleChannels()\r
+{\r
+  return demuxer->getSubtitleChannels();\r
+}\r
+\r
+int Player::getCurrentAudioChannel()\r
+{\r
+    if (is_pesrecording) {\r
+        return demuxer->getselAudioChannel();\r
+    } else {\r
+        return ((DemuxerTS*)demuxer)->getAID();\r
+    }\r
+}\r
+\r
+int Player::getCurrentSubtitleChannel()\r
+{\r
+    if (is_pesrecording) {\r
+        return demuxer->getselSubtitleChannel();\r
+    } else {\r
+        return ((DemuxerTS*)demuxer)->getSubID();\r
+    }\r
+}\r
+\r
+void Player::setSubtitleChannel(int newChannel)\r
+{\r
+    if (is_pesrecording) {\r
+         demuxer->setDVBSubtitleStream(newChannel);\r
+    } else {\r
+        ((DemuxerTS*)demuxer)->setSubID(newChannel);\r
+    }\r
+}\r
+\r
+int *Player::getTeletxtSubtitlePages()\r
+{\r
+    return teletext->getSubtitlePages();\r
+}\r
+\r
+void Player::setAudioChannel(int newChannel, int type)\r
+{\r
+    if (is_pesrecording) {\r
+        demuxer->setAudioStream(newChannel);\r
+        return;\r
+    } else {\r
+        ((DemuxerTS*)demuxer)->setAID(newChannel,type);\r
+        return;\r
+    }\r
+}\r
+\r
+bool Player::toggleSubtitles()\r
+{\r
+  if (!subtitlesShowing)\r
+  {\r
+    subtitlesShowing = true;\r
+    subtitles->show();\r
+  }\r
+  else\r
+  {\r
+    subtitlesShowing = false;\r
+    subtitles->hide();\r
+  }\r
+  return subtitlesShowing;\r
+}\r
+\r
+void  Player::turnSubtitlesOn(bool ison) {\r
+ if (ison)\r
+  {\r
+    subtitlesShowing = true;\r
+    subtitles->show();\r
+  }\r
+  else\r
+  {\r
+    subtitlesShowing = false;\r
+    subtitles->hide();\r
+  }\r
+\r
+}\r
+\r
+Channel Player::getDemuxerChannel() {\r
+    if (!is_pesrecording) {\r
+        return ((DemuxerTS*) demuxer)->getChannelInfo();\r
+    } \r
+    return Channel(); //Should not happen!\r
+}\r
+\r
+\r
+// ----------------------------------- Externally called events\r
+\r
+void Player::play()\r
+{\r
+  if (!initted) return;\r
+  if (state == S_PLAY) return;\r
+  lock();\r
+\r
+  bool doUnlock = false;\r
+  if (state == S_PAUSE_P) doUnlock = true;\r
+  switchState(S_PLAY);\r
+  if (doUnlock) unLock();\r
+}\r
+\r
+void Player::playpause()\r
+{\r
+  if (!initted) return;\r
+  lock();\r
+\r
+  bool doUnlock = false;\r
+  if (state==S_PLAY) {\r
+         doUnlock=true;\r
+         switchState(S_PAUSE_P);\r
+  } else {\r
+         if (state == S_PAUSE_P) doUnlock = true;\r
+         switchState(S_PLAY);\r
+  }\r
+  if (doUnlock) unLock();\r
+\r
+}\r
+\r
+\r
+\r
+\r
+void Player::stop()\r
+{\r
+  if (!initted) return;\r
+  if (state == S_STOP) return;\r
+  lock();\r
+  logger->log("Player", Log::DEBUG, "Stop called lock");\r
+  switchState(S_STOP);\r
+  unLock();\r
+}\r
+\r
+void Player::pause()\r
+{\r
+  if (!initted) return;\r
+  lock();\r
+\r
+  if ((state == S_FFWD) || (state == S_FBWD))\r
+  {\r
+    switchState(S_PAUSE_I);\r
+  }\r
+  else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))\r
+  {\r
+    switchState(S_PLAY);\r
+  }\r
+  else\r
+  {\r
+    switchState(S_PAUSE_P);\r
+  }\r
+\r
+  unLock();\r
+}\r
+\r
+void Player::fastForward()\r
+{\r
+  if (!initted) return;\r
+  lock();\r
+\r
+  if (state == S_FFWD)\r
+  {\r
+    // change the rate\r
+    switch(ifactor)\r
+    {\r
+      case 4: ifactor = 8; break;\r
+      case 8: ifactor = 16; break;\r
+      case 16: ifactor = 32; break;\r
+      case 32: ifactor = 4; break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    ifactor = 4;\r
+    switchState(S_FFWD);\r
+  }\r
+  unLock();\r
+}\r
+\r
+void Player::fastBackward()\r
+{\r
+  if (!initted) return;\r
+  lock();\r
+\r
+  if (state == S_FBWD)\r
+  {\r
+    // change the rate\r
+    switch(ifactor)\r
+    {\r
+      case 4: ifactor = 8; break;\r
+      case 8: ifactor = 16; break;\r
+      case 16: ifactor = 32; break;\r
+      case 32: ifactor = 4; break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    ifactor = 4;\r
+    switchState(S_FBWD);\r
+  }\r
+  unLock();\r
+}\r
+\r
+void Player::jumpToPercent(double percent)\r
+{\r
+  lock();\r
+  logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent);\r
+  ULONG newFrame = (ULONG)(percent * lengthFrames / 100);\r
+  switchState(S_JUMP, newFrame);\r
+//  unLock(); - let thread unlock this\r
+}\r
+\r
+void Player::jumpToMark(int mark)\r
+{\r
+  lock();\r
+  logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);\r
+  switchState(S_JUMP, mark);\r
+//  unLock(); - let thread unlock this\r
+}\r
+\r
+void Player::jumpToFrameP(int newFrame)\r
+{\r
+  lock();\r
+  logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);\r
+  switchState(S_JUMP_PI, newFrame);\r
+  unLock();\r
+}\r
+\r
+void Player::skipForward(int seconds)\r
+{\r
+  lock();\r
+  logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);\r
+  ULONG newFrame = getCurrentFrameNum();\r
+  if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid\r
+  newFrame +=(ULONG) (((double)seconds) * fps);\r
+  if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }\r
+  else switchState(S_JUMP, newFrame);\r
+//  unLock(); - let thread unlock this\r
+}\r
+\r
+void Player::skipBackward(int seconds)\r
+{\r
+  lock();\r
+  logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);\r
+  long newFrame = getCurrentFrameNum();\r
+  if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid\r
+  newFrame -= (ULONG) (((double)seconds) * fps);\r
+  if (newFrame < 0) newFrame = 0;\r
+  switchState(S_JUMP, newFrame);\r
+//  unLock(); - let thread unlock this\r
+}\r
+\r
+// ----------------------------------- Implementations called events\r
+\r
+void Player::switchState(UCHAR toState, ULONG jumpFrame)\r
+{\r
+  if (!initted) return;\r
+\r
+  logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);\r
+\r
+  switch(state) // current state selector\r
+  {\r
+    case S_PLAY: // from S_PLAY -----------------------------------\r
+    {\r
+      switch(toState)\r
+      {\r
+        case S_PLAY: // to S_PLAY\r
+        {\r
+          return;\r
+        }\r
+        case S_PAUSE_P: // to S_PAUSE_P\r
+        {\r
+          video->pause();\r
+          audio->pause();\r
+          state = S_PAUSE_P;\r
+          return;\r
+        }\r
+        case S_PAUSE_I: // to S_PAUSE_I\r
+        {\r
+          // can't occur\r
+          return;\r
+        }\r
+        case S_FFWD: // to S_FFWD\r
+        {\r
+          currentFrameNumber = getCurrentFrameNum();\r
+          audio->systemMuteOn();\r
+          threadStop();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          tfeed.stop();\r
+          subtitles->stop();\r
+          demuxer->flush();\r
+          state = S_FFWD;\r
+          threadStart();\r
+          return;\r
+        }\r
+        case S_FBWD: // to S_FBWD\r
+        {\r
+          currentFrameNumber = getCurrentFrameNum();\r
+          audio->systemMuteOn();\r
+          threadStop();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          tfeed.stop();\r
+          subtitles->stop();\r
+          demuxer->flush();\r
+          state = S_FBWD;\r
+          threadStart();\r
+          return;\r
+        }\r
+        case S_STOP: // to S_STOP\r
+        {\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          tfeed.stop();\r
+          subtitles->stop();\r
+          threadStop();\r
+          video->stop();\r
+          video->blank();\r
+          audio->stop();\r
+          audio->unPause();\r
+          video->reset();\r
+          demuxer->reset();\r
+          state = S_STOP;\r
+          return;\r
+        }\r
+        case S_JUMP: // to S_JUMP\r
+        {\r
+          restartAtFrame(jumpFrame);\r
+          return;\r
+        }\r
+        case S_JUMP_PI: // to S_JUMP_PI\r
+        {\r
+          audio->systemMuteOn();\r
+          threadStop();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          tfeed.stop();\r
+          subtitles->stop();\r
+          demuxer->flush();\r
+          state = S_PAUSE_I;\r
+          video->reset();\r
+          video->play();\r
+          restartAtFramePI(jumpFrame);\r
+          return;\r
+        }\r
+      }\r
+    }\r
+    case S_PAUSE_P: // from S_PAUSE_P -----------------------------------\r
+    {\r
+      switch(toState)\r
+      {\r
+        case S_PLAY: // to S_PLAY\r
+        {\r
+          video->unPause();\r
+          audio->unPause();\r
+          state = S_PLAY;\r
+          return;\r
+        }\r
+        case S_PAUSE_P: // to S_PAUSE_P\r
+        {\r
+          return;\r
+        }\r
+        case S_PAUSE_I: // to S_PAUSE_I\r
+        {\r
+          return;\r
+        }\r
+        case S_FFWD: // to S_FFWD\r
+        {\r
+          currentFrameNumber = getCurrentFrameNum();\r
+          audio->systemMuteOn();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          tfeed.stop();\r
+          subtitles->stop();\r
+          threadStop();\r
+          video->unPause();\r
+          audio->unPause();\r
+          state = S_FFWD;\r
+          threadStart();\r
+          return;\r
+        }\r
+        case S_FBWD: // to S_FBWD\r
+        {\r
+          currentFrameNumber = getCurrentFrameNum();\r
+          audio->systemMuteOn();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          tfeed.stop();\r
+          subtitles->stop();\r
+          threadStop();\r
+          video->unPause();\r
+          audio->unPause();\r
+          state = S_FBWD;\r
+          threadStart();\r
+          return;\r
+        }\r
+        case S_STOP: // to S_STOP\r
+        {\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          tfeed.stop();\r
+          subtitles->stop();\r
+          threadStop();\r
+          video->stop();\r
+          video->blank();\r
+          audio->stop();\r
+          video->reset();\r
+          audio->unPause();\r
+          demuxer->reset();\r
+          audio->systemMuteOff();\r
+          state = S_STOP;\r
+          return;\r
+        }\r
+        case S_JUMP: // to S_JUMP\r
+        {\r
+          state = S_PLAY;\r
+          audio->systemMuteOn();\r
+          audio->unPause();\r
+          restartAtFrame(jumpFrame);\r
+          return;\r
+        }\r
+        case S_JUMP_PI: // to S_JUMP_PI\r
+        {\r
+          audio->systemMuteOn();\r
+          audio->unPause();\r
+          threadStop();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          tfeed.stop();\r
+          subtitles->stop();\r
+          demuxer->flush();\r
+          state = S_PAUSE_I;\r
+          video->reset();\r
+          video->play();\r
+          restartAtFramePI(jumpFrame);\r
+          return;\r
+        }\r
+      }\r
+    }\r
+    case S_PAUSE_I: // from S_PAUSE_I -----------------------------------\r
+    {\r
+      switch(toState)\r
+      {\r
+        case S_PLAY: // to S_PLAY\r
+        {\r
+          state = S_PLAY;\r
+          restartAtFrame(currentFrameNumber);\r
+          return;\r
+        }\r
+        case S_PAUSE_P: // to S_PAUSE_P\r
+        {\r
+          return;\r
+        }\r
+        case S_PAUSE_I: // to S_PAUSE_I\r
+        {\r
+          return;\r
+        }\r
+        case S_FFWD: // to S_FFWD\r
+        {\r
+          state = S_FFWD;\r
+          threadStart();\r
+          return;\r
+        }\r
+        case S_FBWD: // to S_FBWD\r
+        {\r
+          state = S_FBWD;\r
+          threadStart();\r
+          return;\r
+        }\r
+        case S_STOP: // to S_STOP\r
+        {\r
+          video->stop();\r
+          video->blank();\r
+          audio->stop();\r
+          video->reset();\r
+          demuxer->reset();\r
+          audio->systemMuteOff();\r
+          state = S_STOP;\r
+          return;\r
+        }\r
+        case S_JUMP: // to S_JUMP\r
+        {\r
+          state = S_PLAY;\r
+          restartAtFrame(jumpFrame);\r
+          return;\r
+        }\r
+        case S_JUMP_PI: // to S_JUMP_PI\r
+        {\r
+          restartAtFramePI(jumpFrame);\r
+          return;\r
+        }\r
+      }\r
+    }\r
+    case S_FFWD: // from S_FFWD -----------------------------------\r
+    {\r
+      switch(toState)\r
+      {\r
+        case S_PLAY: // to S_PLAY\r
+        {\r
+          state = S_PLAY;\r
+          ULONG stepback = (ULONG)(((double)USER_RESPONSE_TIME * ifactor) * fps / 1000.);\r
+          if (stepback < currentFrameNumber)\r
+            currentFrameNumber -= stepback;\r
+          else\r
+            currentFrameNumber = 0;\r
+          restartAtFrame(currentFrameNumber);\r
+          return;\r
+        }\r
+        case S_PAUSE_P: // to S_PAUSE_P\r
+        {\r
+          // can't occur\r
+          return;\r
+        }\r
+        case S_PAUSE_I: // to S_PAUSE_I\r
+        {\r
+          threadStop();\r
+          state = S_PAUSE_I;\r
+          return;\r
+        }\r
+        case S_FFWD: // to S_FFWD\r
+        {\r
+          return;\r
+        }\r
+        case S_FBWD: // to S_FBWD\r
+        {\r
+          threadStop();\r
+          state = S_FBWD;\r
+          threadStart();\r
+          return;\r
+        }\r
+        case S_STOP: // to S_STOP\r
+        {\r
+          threadStop();\r
+          video->stop();\r
+          video->blank();\r
+          audio->stop();\r
+          video->reset();\r
+          demuxer->reset();\r
+          state = S_STOP;\r
+          return;\r
+        }\r
+        case S_JUMP: // to S_JUMP\r
+        {\r
+          state = S_PLAY;\r
+          restartAtFrame(jumpFrame);\r
+          return;\r
+        }\r
+        case S_JUMP_PI: // to S_JUMP_PI\r
+        {\r
+          threadStop();\r
+          state = S_PAUSE_I;\r
+          restartAtFramePI(jumpFrame);\r
+          return;\r
+        }\r
+      }\r
+    }\r
+    case S_FBWD: // from S_FBWD -----------------------------------\r
+    {\r
+      switch(toState)\r
+      {\r
+        case S_PLAY: // to S_PLAY\r
+        {\r
+          state = S_PLAY;\r
+          restartAtFrame(currentFrameNumber);\r
+          return;\r
+        }\r
+        case S_PAUSE_P: // to S_PAUSE_P\r
+        {\r
+          // can't occur\r
+          return;\r
+        }\r
+        case S_PAUSE_I: // to S_PAUSE_I\r
+        {\r
+          threadStop();\r
+          state = S_PAUSE_I;\r
+          return;\r
+        }\r
+        case S_FFWD: // to S_FFWD\r
+        {\r
+          threadStop();\r
+          state = S_FFWD;\r
+          threadStart();\r
+          return;\r
+        }\r
+        case S_FBWD: // to S_FBWD\r
+        {\r
+          return;\r
+        }\r
+        case S_STOP: // to S_STOP\r
+        {\r
+          threadStop();\r
+          video->stop();\r
+          video->blank();\r
+          audio->stop();\r
+          video->reset();\r
+          demuxer->reset();\r
+          state = S_STOP;\r
+          return;\r
+        }\r
+        case S_JUMP: // to S_JUMP\r
+        {\r
+          state = S_PLAY;\r
+          restartAtFrame(jumpFrame);\r
+          return;\r
+        }\r
+        case S_JUMP_PI: // to S_JUMP_PI\r
+        {\r
+          threadStop();\r
+          state = S_PAUSE_I;\r
+          restartAtFramePI(jumpFrame);\r
+          return;\r
+        }\r
+      }\r
+    }\r
+    case S_STOP: // from S_STOP -----------------------------------\r
+    {\r
+      switch(toState)\r
+      {\r
+        case S_PLAY: // to S_PLAY\r
+        {\r
+          startup = true;\r
+\r
+          audio->reset();\r
+          audio->setStreamType(Audio::MPEG2_PES);\r
+          audio->systemMuteOff();\r
+          video->reset();\r
+          demuxer->reset();\r
+          // FIXME use restartAtFrame here?\r
+          if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;\r
+          demuxer->setFrameNum(currentFrameNumber);\r
+          demuxer->seek();\r
+          videoStartup = true;\r
+          state = S_PLAY;\r
+          threadStart();\r
+          logger->log("Player", Log::DEBUG, "Immediate play");\r
+          afeed.start();\r
+          vfeed.start();\r
+          tfeed.start();\r
+          subtitles->start();\r
+          video->sync();\r
+          audio->sync();\r
+          audio->play();\r
+          video->pause();\r
+          return;\r
+        }\r
+        case S_PAUSE_P: // to S_PAUSE_P\r
+        {\r
+          return;\r
+        }\r
+        case S_PAUSE_I: // to S_PAUSE_I\r
+        {\r
+          return;\r
+        }\r
+        case S_FFWD: // to S_FFWD\r
+        {\r
+          return;\r
+        }\r
+        case S_FBWD: // to S_FBWD\r
+        {\r
+          return;\r
+        }\r
+        case S_STOP: // to S_STOP\r
+        {\r
+          return;\r
+        }\r
+        case S_JUMP: // to S_JUMP\r
+        {\r
+          return;\r
+        }\r
+        case S_JUMP_PI: // to S_JUMP_PI\r
+        {\r
+          return;\r
+        }\r
+      }\r
+    }\r
+    // case S_JUMP cannot be a start state because it auto flips to play\r
+    // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I\r
+  }\r
+}\r
+\r
+// ----------------------------------- Internal functions\r
+\r
+void Player::lock()\r
+{\r
+#ifndef WIN32\r
+  pthread_mutex_lock(&mutex);\r
+  logger->log("Player", Log::DEBUG, "LOCKED");\r
+\r
+#else\r
+   WaitForSingleObject(mutex, INFINITE);\r
+#endif\r
+}\r
+\r
+void Player::unLock()\r
+{\r
+#ifndef WIN32\r
+  logger->log("Player", Log::DEBUG, "UNLOCKING");\r
+  pthread_mutex_unlock(&mutex);\r
+#else\r
+   ReleaseMutex(mutex);\r
+#endif\r
+}\r
+\r
+void Player::restartAtFrame(ULONG newFrame)\r
+{\r
+  vfeed.stop();\r
+  afeed.stop();\r
+  tfeed.stop();\r
+  subtitles->stop();\r
+  threadStop();\r
+  video->stop();\r
+  video->reset();\r
+  audio->reset();\r
+  audio->setStreamType(Audio::MPEG2_PES);\r
+  demuxer->flush();\r
+  demuxer->seek();\r
+  currentFrameNumber = newFrame;\r
+  demuxer->setFrameNum(newFrame);\r
+  videoStartup = true;\r
+  afeed.start();\r
+  tfeed.start();\r
+  vfeed.start();\r
+  subtitles->start();\r
+  threadStart();\r
+  audio->play();\r
+  video->sync();\r
+  audio->sync();\r
+  audio->systemMuteOff();\r
+  audio->doMuting();\r
+}\r
+\r
+\r
+void Player::restartAtFramePI(ULONG newFrame)\r
+{\r
+  ULLONG filePos;\r
+  ULONG nextiframeNumber;\r
+  ULONG iframeLength;\r
+  ULONG iframeNumber;\r
+\r
+  UCHAR* buffer;\r
+  UINT amountReceived;\r
+  UINT videoLength;\r
+\r
+  // newFrame could be anywhere, go forwards to next I-Frame\r
+  if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;\r
+\r
+  // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame\r
+  vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);\r
+\r
+  buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);\r
+  if (!vdr->isConnected())\r
+  {\r
+    if (buffer) free(buffer);\r
+    doConnectionLost();\r
+  }\r
+  else\r
+  {\r
+    videoLength = demuxer->stripAudio(buffer, amountReceived);\r
+    video->displayIFrame(buffer, videoLength);\r
+    video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)\r
+    free(buffer);\r
+    currentFrameNumber = iframeNumber;\r
+  }\r
+}\r
+\r
+void Player::doConnectionLost()\r
+{\r
+  logger->log("Player", Log::DEBUG, "Connection lost, sending message");\r
+  Message* m = new Message();\r
+  m->to = messageReceiver;\r
+  m->from = this;\r
+  m->message = Message::PLAYER_EVENT;\r
+  m->parameter = Player::CONNECTION_LOST;\r
+  messageQueue->postMessage(m);\r
+}\r
+\r
+// ----------------------------------- Callback\r
+\r
+void Player::call(void* caller)\r
+{\r
+  if (caller == demuxer)\r
+  {\r
+    logger->log("Player", Log::DEBUG, "Callback from demuxer");\r
+\r
+    if (video->getTVsize() == Video::ASPECT4X3)\r
+    {\r
+      logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");\r
+      return;\r
+    }\r
+\r
+    int dxCurrentAspect = demuxer->getAspectRatio();\r
+    if (dxCurrentAspect == Demuxer::ASPECT_4_3)\r
+    {\r
+      logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");\r
+      video->setAspectRatio(Video::ASPECT4X3);\r
+\r
+      Message* m = new Message();\r
+      m->from = this;\r
+      m->to = messageReceiver;\r
+      m->message = Message::PLAYER_EVENT;\r
+      m->parameter = Player::ASPECT43;\r
+      messageQueue->postMessageFromOuterSpace(m);\r
+    }\r
+    else if (dxCurrentAspect == Demuxer::ASPECT_16_9)\r
+    {\r
+      logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");\r
+      video->setAspectRatio(Video::ASPECT16X9);\r
+\r
+      Message* m = new Message();\r
+      m->from = this;\r
+      m->to = messageReceiver;\r
+      m->message = Message::PLAYER_EVENT;\r
+      m->parameter = Player::ASPECT169;\r
+      messageQueue->postMessageFromOuterSpace(m);\r
+    }\r
+    else\r
+    {\r
+      logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");\r
+    }\r
+\r
+  }\r
+  else\r
+  {\r
+    if (videoStartup)\r
+    {\r
+      videoStartup = false;\r
+      video->reset();\r
+      video->play();\r
+      video->sync();\r
+      vfeed.release();\r
+      unLock();\r
+    }\r
+\r
+    threadSignalNoLock();\r
+  }\r
+}\r
+\r
+// ----------------------------------- Feed thread\r
+\r
+void Player::threadMethod()\r
+{\r
+  // this method used to be simple, the only thing it does\r
+  // is farm out to threadFeed Live/Play/Scan\r
+  // All the guff is to support scan hitting one end\r
+\r
+  if ((state == S_FFWD) || (state == S_FBWD))\r
+  {\r
+    if (video->PTSIFramePlayback()) threadPTSFeedScan();\r
+    else threadFeedScan();\r
+    // if this returns then scan hit one end\r
+    if (state == S_FFWD) // scan hit the end. stop\r
+    {\r
+      threadCheckExit();\r
+      Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+      m->to = messageReceiver;\r
+      m->from = this;\r
+      m->message = Message::PLAYER_EVENT;\r
+      m->parameter = STOP_PLAYBACK;\r
+      logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);\r
+      messageQueue->postMessage(m);\r
+      logger->log("Player", Log::DEBUG, "Message posted...");\r
+      return;\r
+    }\r
+    // if execution gets to here, threadFeedScan hit the start, go to play mode\r
+    state = S_PLAY;\r
+    audio->reset();\r
+    audio->setStreamType(Audio::MPEG2_PES);\r
+    demuxer->flush();\r
+    demuxer->seek();\r
+    demuxer->setFrameNum(currentFrameNumber);\r
+    videoStartup = true;\r
+    afeed.start();\r
+    tfeed.start();\r
+    vfeed.start();\r
+    subtitles->start();\r
+    audio->play();\r
+    audio->sync();\r
+    audio->systemMuteOff();\r
+    audio->doMuting();\r
+  }\r
+\r
+  if (state == S_PLAY) threadFeedPlay();\r
+}\r
+\r
+void Player::threadFeedPlay()\r
+{\r
+  ULLONG feedPosition;\r
+  UINT thisRead, writeLength, thisWrite, askFor;\r
+  time_t lastRescan = time(NULL);\r
+\r
+  feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);\r
+  if (!vdr->isConnected()) { doConnectionLost(); return; }\r
+  logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);\r
+\r
+\r
+  while(1)\r
+  {\r
+    thisRead = 0;\r
+    writeLength = 0;\r
+    thisWrite = 0;\r
+\r
+    threadCheckExit();\r
+\r
+    // If we havn't rescanned for a while..\r
+    if ((lastRescan + 60) < time(NULL))\r
+    {\r
+      lengthBytes = vdr->rescanRecording(&lengthFrames);\r
+      if (!vdr->isConnected()) { doConnectionLost(); return; }\r
+      logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);\r
+      lastRescan = time(NULL);\r
+    }\r
+\r
+    if (feedPosition >= lengthBytes) break;  // finished playback\r
+\r
+    if (startup)\r
+    {\r
+      if (startupBlockSize > lengthBytes)\r
+        askFor = lengthBytes; // is a very small recording!\r
+      else\r
+        askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams\r
+    }\r
+    else\r
+    {\r
+      if ((feedPosition + blockSize) > lengthBytes) // last block of recording\r
+        askFor = lengthBytes - feedPosition;\r
+      else // normal\r
+        askFor = blockSize;\r
+    }\r
+    //logger->log("Player", Log::DEBUG, "Get Block in");\r
+\r
+    threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);\r
+    //logger->log("Player", Log::DEBUG, "Get Block out");\r
+\r
+    feedPosition += thisRead;\r
+\r
+    if (!vdr->isConnected())\r
+    {\r
+      doConnectionLost();\r
+      return;\r
+    }\r
+\r
+    if (!threadBuffer) break;\r
+\r
+    if (startup)\r
+    {\r
+      int a_stream = demuxer->scan(threadBuffer, thisRead);\r
+      demuxer->setAudioStream(a_stream);\r
+      logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);\r
+      startup = false;\r
+    }\r
+\r
+    threadCheckExit();\r
+\r
+    while(writeLength < thisRead)\r
+    {\r
+      //logger->log("Player", Log::DEBUG, "Put in");\r
+      thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);\r
+      //logger->log("Player", Log::DEBUG, "Put out");\r
+      writeLength += thisWrite;\r
+\r
+      if (!thisWrite)\r
+      {\r
+        // demuxer is full and can't take anymore\r
+        threadLock();\r
+        threadWaitForSignal();\r
+        threadUnlock();\r
+      }\r
+\r
+      threadCheckExit();\r
+    }\r
+\r
+    free(threadBuffer);\r
+    threadBuffer = NULL;\r
+\r
+  }\r
+\r
+  // end of recording\r
+  logger->log("Player", Log::DEBUG, "Recording playback ends");\r
+\r
+  if (videoStartup) // oh woe. there never was a stream, I was conned!\r
+  {\r
+    videoStartup = false;\r
+    unLock();\r
+    MILLISLEEP(500); // I think this will solve a race\r
+  }\r
+\r
+  threadCheckExit();\r
+\r
+\r
+  Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+  m->to = messageReceiver;\r
+  m->from = this;\r
+  m->message = Message::PLAYER_EVENT;\r
+  m->parameter = Player::STOP_PLAYBACK;\r
+  logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);\r
+  messageQueue->postMessage(m);\r
+}\r
+\r
+\r
+void Player::threadPTSFeedScan()\r
+{\r
+  // This method manipulates the PTS instead of waiting, this is for the android devices, maybe later for windows?\r
+\r
+  ULONG direction = 0;\r
+  int dir_fac=-1;\r
+  ULONG baseFrameNumber = 0;\r
+  ULONG iframeNumber = 0;\r
+  ULONG iframeLength = 0;\r
+  ULONG currentfeedFrameNumber=currentFrameNumber;\r
+  ULONG firstFrameNumber=currentFrameNumber;\r
+  ULLONG filePos;\r
+  UINT amountReceived;\r
+  UINT videoLength;\r
+\r
+  UINT playtime=0;\r
+\r
+#ifndef WIN32\r
+  struct timeval clock0 = {0,0};  // Time stamp after fetching I-frame info\r
+  struct timeval clock1 = {0,0};  // Time stamp after fetching I-frame data\r
+  struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame\r
+#else\r
+  DWORD clock0 = 0, clock1 = 0, clock2 = 0;\r
+#endif\r
+\r
+  int frameTimeOffset = 0; // Time in msec between frames\r
+  int disp_msec = 0;  // Time taken to display data\r
+  int total_msec = 0; // Time taken to fetch data and display it\r
+  int sleepTime = 0;\r
+\r
+  if (state == S_FFWD) {\r
+         direction = 1; // and 0 for backward\r
+         dir_fac=1;\r
+  }\r
+  video->EnterIframePlayback();\r
+\r
+  while(1)\r
+  {\r
+    // Fetch I-frames until we get one that can be displayed in good time\r
+    // Repeat while clock0 + total_msec > clock2 + frameTimeOffset\r
+\r
+    baseFrameNumber = currentfeedFrameNumber;\r
+\r
+    threadCheckExit();\r
+    if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))\r
+       return;\r
+\r
+    if (iframeNumber >= lengthFrames) return;\r
+        // scan has got to the end of what we knew to be there before we started scanning\r
+\r
+    baseFrameNumber = iframeNumber;\r
+\r
+    frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentfeedFrameNumber) * 1000) / (fps * (double)ifactor));\r
+\r
+    logger->log("Player", Log::DEBUG, "XXX Got frame");\r
+\r
+    threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);\r
+\r
+    if (!vdr->isConnected())\r
+    {\r
+      if (threadBuffer) free(threadBuffer);\r
+      doConnectionLost();\r
+      break;\r
+    }\r
+\r
+\r
+    threadCheckExit();\r
+\r
+\r
+    videoLength = demuxer->stripAudio(threadBuffer, amountReceived);\r
+    demuxer->changeTimes(threadBuffer,videoLength,playtime);\r
+    int count=0;\r
+    while (!video->displayIFrame(threadBuffer, videoLength)) // the device might block\r
+    {\r
+       MILLISLEEP(20);\r
+       threadCheckExit();\r
+       count++;\r
+       if (count%300==0) {\r
+               ULLONG cur_time=video->getCurrentTimestamp();\r
+       //       logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",\r
+               //              firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);\r
+               if (cur_time!=0) {\r
+                   currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));\r
+               }\r
+       }\r
+\r
+    }\r
+    playtime +=frameTimeOffset;\r
+    currentfeedFrameNumber = iframeNumber;\r
+    {\r
+               ULLONG cur_time=video->getCurrentTimestamp();\r
+       //       logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",\r
+               //              firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);\r
+               if (cur_time!=0) {\r
+                   currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));\r
+               }\r
+       }\r
+\r
+    free(threadBuffer);\r
+    threadBuffer = NULL;\r
+  }\r
+}\r
+\r
+\r
+\r
+void Player::threadFeedScan()\r
+{\r
+  // This method is actually really simple - get frame from vdr,\r
+  // spit it at the video chip, wait for a time. Most of the code here\r
+  // is to get the wait right so that the scan occurs at the correct rate.\r
+\r
+  ULONG direction = 0;\r
+  ULONG baseFrameNumber = 0;\r
+  ULONG iframeNumber = 0;\r
+  ULONG iframeLength = 0;\r
+  ULLONG filePos;\r
+  UINT amountReceived;\r
+  UINT videoLength;\r
+\r
+#ifndef WIN32\r
+  struct timeval clock0 = {0,0};  // Time stamp after fetching I-frame info\r
+  struct timeval clock1 = {0,0};  // Time stamp after fetching I-frame data\r
+  struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame\r
+#else\r
+  DWORD clock0 = 0, clock1 = 0, clock2 = 0;\r
+#endif\r
+\r
+  int frameTimeOffset = 0; // Time in msec between frames\r
+  int disp_msec = 0;  // Time taken to display data\r
+  int total_msec = 0; // Time taken to fetch data and display it\r
+  int sleepTime = 0;\r
+\r
+  if (state == S_FFWD) direction = 1; // and 0 for backward\r
+\r
+  while(1)\r
+  {\r
+    // Fetch I-frames until we get one that can be displayed in good time\r
+    // Repeat while clock0 + total_msec > clock2 + frameTimeOffset\r
+\r
+    baseFrameNumber = currentFrameNumber;\r
+    do\r
+    {\r
+      threadCheckExit();\r
+      if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))\r
+        return;\r
+\r
+      if (iframeNumber >= lengthFrames) return;\r
+        // scan has got to the end of what we knew to be there before we started scanning\r
+\r
+      baseFrameNumber = iframeNumber;\r
+      frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor));\r
+#ifndef WIN32\r
+      gettimeofday(&clock0, NULL);\r
+#else\r
+      clock0 = timeGetTime();\r
+#endif\r
+    }\r
+#ifndef WIN32\r
+    while (clock2.tv_sec != 0 &&\r
+          (clock0.tv_sec - clock2.tv_sec) * 1000 +\r
+          (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);\r
+#else\r
+    while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);\r
+#endif\r
+    logger->log("Player", Log::DEBUG, "XXX Got frame");\r
+\r
+    threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);\r
+    \r
+    if (!vdr->isConnected())\r
+    {\r
+      if (threadBuffer) free(threadBuffer);\r
+      doConnectionLost();\r
+      break;\r
+    }\r
+    \r
+#ifndef WIN32\r
+    gettimeofday(&clock1, NULL);\r
+    if (clock2.tv_sec != 0)\r
+      sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000\r
+                + (clock2.tv_usec - clock1.tv_usec) / 1000\r
+                + frameTimeOffset - disp_msec;\r
+#else\r
+    clock1 = timeGetTime();\r
+    if (clock2 != 0)\r
+      sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;\r
+#endif\r
+    if (sleepTime < 0) sleepTime = 0;\r
+    threadCheckExit();\r
+    MILLISLEEP(sleepTime);\r
+   logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);\r
+\r
+    videoLength = demuxer->stripAudio(threadBuffer, amountReceived);\r
+    video->displayIFrame(threadBuffer, videoLength);\r
+    currentFrameNumber = iframeNumber;\r
+    free(threadBuffer);\r
+    threadBuffer = NULL;\r
+\r
+#ifndef WIN32\r
+    gettimeofday(&clock2, NULL);\r
+    total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000\r
+               + (clock2.tv_usec - clock0.tv_usec) / 1000\r
+               - sleepTime;\r
+    disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000\r
+              + (clock2.tv_usec - clock1.tv_usec) / 1000\r
+              - sleepTime;\r
+#else\r
+    clock2 = timeGetTime();\r
+    total_msec = clock2 - clock0 - sleepTime;\r
+    disp_msec = clock2 - clock1 - sleepTime;\r
+#endif\r
+    logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);\r
+  }\r
+}\r
+\r
+void Player::threadPostStopCleanup()\r
+{\r
+  if (threadBuffer)\r
+  {\r
+    free(threadBuffer);\r
+    threadBuffer = NULL;\r
+  }\r
+}\r
+\r
+// ----------------------------------- Dev\r
+\r
+#ifdef DEV\r
+void Player::test1()\r
+{\r
+  logger->log("Player", Log::DEBUG, "PLAYER TEST 1");\r
+}\r
+\r
+void Player::test2()\r
+{\r
+  logger->log("Player", Log::DEBUG, "PLAYER TEST 2");\r
+}\r
+#endif\r
index af9bedf3cae4d476a9ab392d71896d988d22d324..9658544b09367d2685954c0867688712d9a6c5fc 100644 (file)
--- a/player.h
+++ b/player.h
-/*
-    Copyright 2004-2008 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef PLAYER_H
-#define PLAYER_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef WIN32
-#include <sys/time.h>
-#endif
-#include <time.h>
-
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
-
-#include "callback.h"
-#include "defines.h"
-#include "vfeed.h"
-#include "afeed.h"
-#include "tfeed.h"
-
-#include "teletextdecodervbiebu.h"
-
-class MessageQueue;
-class Audio;
-class Video;
-class VDR;
-class Log;
-class Demuxer;
-class OSDReceiver;
-class DVBSubtitles;
-class Channel;
-
-class Player : public Thread_TYPE, public Callback
-{
-  public:
-    Player(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* osdReceiver);
-    virtual ~Player();
-
-    int init(bool p_isPesRecording,double framespersec);
-    int shutdown();
-    void setStartFrame(ULONG frameNum);
-    void setLengthBytes(ULLONG length);
-    void setLengthFrames(ULONG length);
-    void setAudioChannel(int newChannel, int type);
-    void setSubtitleChannel(int newChannel);
-    bool toggleSubtitles();
-    void turnSubtitlesOn(bool ison); 
-    bool isSubtitlesOn() { return subtitlesShowing; }
-
-    void play();
-    void stop();
-    void pause();
-    void fastForward();
-    void fastBackward();
-    void jumpToPercent(double percent);
-    void skipForward(int seconds);
-    void skipBackward(int seconds);
-    void jumpToMark(int mark);
-    void jumpToFrameP(int newFrame);
-
-    UCHAR getState() { return state; }
-    ULONG getCurrentFrameNum();
-    ULONG getLengthFrames();
-    UCHAR getIScanRate() { return ifactor; }
-    bool* getDemuxerMpegAudioChannels();
-    bool* getDemuxerAc3AudioChannels();
-    bool* getDemuxerSubtitleChannels();
-    int *getTeletxtSubtitlePages();
-    int getCurrentAudioChannel();
-    int getCurrentSubtitleChannel();
-    bool isPesRecording() { return is_pesrecording; }
-    Channel getDemuxerChannel();
-
-   TeletextDecoderVBIEBU * getTeletextDecoder() { return teletext; }
-
-    void call(void*); // for callback interface
-
-    const static UCHAR S_PLAY = 1;
-    const static UCHAR S_PAUSE_P = 2;
-    const static UCHAR S_PAUSE_I = 3;
-    const static UCHAR S_FFWD = 4;
-    const static UCHAR S_FBWD = 5;
-    const static UCHAR S_STOP = 6;
-    const static UCHAR S_JUMP = 7;
-    const static UCHAR S_JUMP_PI = 8; // Jump to Pause_I mode
-
-    // Player events
-
-    // FIXME so far this just duplicates the old system + the wss
-
-    const static UCHAR CONNECTION_LOST = 1;
-    const static UCHAR STOP_PLAYBACK = 2;
-    const static UCHAR STREAM_END = 3;
-    const static UCHAR ASPECT43 = 4;
-    const static UCHAR ASPECT169 = 5;
-
-#ifdef DEV
-    void test1();
-    void test2();
-#endif
-
-  protected:
-    void threadMethod();
-    void threadPostStopCleanup();
-
-  private:
-    void switchState(UCHAR newState, ULONG jumpFrame=0);
-
-    void threadFeedPlay();
-    void threadFeedScan();
-
-    void doConnectionLost();
-    void restartAtFrame(ULONG newFrame);
-    void restartAtFramePI(ULONG newFrame);
-
-    bool subtitlesShowing;
-    MessageQueue* messageQueue;
-    void* messageReceiver;
-    OSDReceiver* osdReceiver;
-    Log* logger;
-    Audio* audio;
-    Video* video;
-    Demuxer* demuxer;
-    DVBSubtitles* subtitles;
-    VDR* vdr;
-    VFeed vfeed;
-    AFeed afeed;
-    TFeed tfeed;
-    TeletextDecoderVBIEBU *teletext;
-  
-    
-
-    bool initted;
-    bool startup;
-    bool videoStartup;
-
-    bool is_pesrecording;
-       double fps;
-
-#ifndef WIN32
-    pthread_mutex_t mutex;
-#else
-    HANDLE mutex;
-#endif
-    void lock();
-    void unLock();
-
-    ULLONG lengthBytes;
-    ULONG lengthFrames;
-    ULONG currentFrameNumber;
-    UINT blockSize;
-    UINT startupBlockSize;
-    UCHAR* threadBuffer;
-    UCHAR state;
-    UCHAR ifactor;
-};
-
-#endif
-
-
-/*
-
-Possible states:
-
-Play, Pause, FFwd, FBwd, (Stop), [Jump]
-
-                    Possible  Working
-
-Play   -> PauseP       *         *
-       -> PauseI
-       -> FFwd         *         *
-       -> FBwd         *         *
-       -> Stop         *         *
-       -> Jump         *         *
-       -> Jump_PI      *         *
-
-PauseP -> Play         *         *
-       -> PauseI
-       -> FFwd         *         *
-       -> FBwd         *         *
-       -> Stop         *         *
-       -> Jump         *         *
-       -> Jump_PI      *         *
-
-PauseI -> Play         *         *
-       -> PauseP
-       -> FFwd         *         *
-       -> FBwd         *         *
-       -> Stop         *         *
-       -> Jump         *         *
-       -> Jump_PI      *         *
-
-FFwd   -> Play         *         *
-       -> PauseP
-       -> PauseI       *         *
-       -> FBwd         *         *
-       -> Stop         *         *
-       -> Jump         *         *
-       -> Jump_PI      *         *
-
-FBwd   -> Play         *         *
-       -> PauseP
-       -> PauseI       *         *
-       -> FFwd         *         *
-       -> Stop         *         *
-       -> Jump         *         *
-       -> Jump_PI      *         *
-
-Stop   -> Play         *         *
-       -> PauseP
-       -> PauseI
-       -> FFwd
-       -> FBwd
-       -> Jump
-       -> Jump_PI
-
-*/
+/*\r
+    Copyright 2004-2008 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef PLAYER_H\r
+#define PLAYER_H\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#ifndef WIN32\r
+#include <sys/time.h>\r
+#endif\r
+#include <time.h>\r
+\r
+#include "threadsystem.h"\r
+\r
+#include "callback.h"\r
+#include "defines.h"\r
+#include "vfeed.h"\r
+#include "afeed.h"\r
+#include "tfeed.h"\r
+\r
+#include "teletextdecodervbiebu.h"\r
+\r
+class MessageQueue;\r
+class Audio;\r
+class Video;\r
+class VDR;\r
+class Log;\r
+class Demuxer;\r
+class OSDReceiver;\r
+class DVBSubtitles;\r
+class Channel;\r
+\r
+class Player : public Thread_TYPE, public Callback\r
+{\r
+  public:\r
+    Player(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* osdReceiver);\r
+    virtual ~Player();\r
+\r
+    int init(bool p_isPesRecording,double framespersec);\r
+    int shutdown();\r
+    void setStartFrame(ULONG frameNum);\r
+    void setLengthBytes(ULLONG length);\r
+    void setLengthFrames(ULONG length);\r
+    void setAudioChannel(int newChannel, int type);\r
+    void setSubtitleChannel(int newChannel);\r
+    bool toggleSubtitles();\r
+    void turnSubtitlesOn(bool ison); \r
+    bool isSubtitlesOn() { return subtitlesShowing; }\r
+\r
+    void play();\r
+    void stop();\r
+    void pause();\r
+    void playpause();\r
+    void fastForward();\r
+    void fastBackward();\r
+    void jumpToPercent(double percent);\r
+    void skipForward(int seconds);\r
+    void skipBackward(int seconds);\r
+    void jumpToMark(int mark);\r
+    void jumpToFrameP(int newFrame);\r
+\r
+    UCHAR getState() { return state; }\r
+    ULONG getCurrentFrameNum();\r
+    ULONG getLengthFrames();\r
+    UCHAR getIScanRate() { return ifactor; }\r
+    bool* getDemuxerMpegAudioChannels();\r
+    bool* getDemuxerAc3AudioChannels();\r
+    bool* getDemuxerSubtitleChannels();\r
+    int *getTeletxtSubtitlePages();\r
+    int getCurrentAudioChannel();\r
+    int getCurrentSubtitleChannel();\r
+    bool isPesRecording() { return is_pesrecording; }\r
+    Channel getDemuxerChannel();\r
+\r
+   TeletextDecoderVBIEBU * getTeletextDecoder() { return teletext; }\r
+\r
+    void call(void*); // for callback interface\r
+\r
+    const static UCHAR S_PLAY = 1;\r
+    const static UCHAR S_PAUSE_P = 2;\r
+    const static UCHAR S_PAUSE_I = 3;\r
+    const static UCHAR S_FFWD = 4;\r
+    const static UCHAR S_FBWD = 5;\r
+    const static UCHAR S_STOP = 6;\r
+    const static UCHAR S_JUMP = 7;\r
+    const static UCHAR S_JUMP_PI = 8; // Jump to Pause_I mode\r
+\r
+    // Player events\r
+\r
+    // FIXME so far this just duplicates the old system + the wss\r
+\r
+    const static UCHAR CONNECTION_LOST = 1;\r
+    const static UCHAR STOP_PLAYBACK = 2;\r
+    const static UCHAR STREAM_END = 3;\r
+    const static UCHAR ASPECT43 = 4;\r
+    const static UCHAR ASPECT169 = 5;\r
+\r
+#ifdef DEV\r
+    void test1();\r
+    void test2();\r
+#endif\r
+\r
+  protected:\r
+    void threadMethod();\r
+    void threadPostStopCleanup();\r
+\r
+  private:\r
+    void switchState(UCHAR newState, ULONG jumpFrame=0);\r
+\r
+    void threadFeedPlay();\r
+    void threadFeedScan();\r
+    void threadPTSFeedScan();\r
+\r
+    void doConnectionLost();\r
+    void restartAtFrame(ULONG newFrame);\r
+    void restartAtFramePI(ULONG newFrame);\r
+\r
+    bool subtitlesShowing;\r
+    MessageQueue* messageQueue;\r
+    void* messageReceiver;\r
+    OSDReceiver* osdReceiver;\r
+    Log* logger;\r
+    Audio* audio;\r
+    Video* video;\r
+    Demuxer* demuxer;\r
+    DVBSubtitles* subtitles;\r
+    VDR* vdr;\r
+    VFeed vfeed;\r
+    AFeed afeed;\r
+    TFeed tfeed;\r
+    TeletextDecoderVBIEBU *teletext;\r
+  \r
+    \r
+\r
+    bool initted;\r
+    bool startup;\r
+    bool videoStartup;\r
+\r
+    bool is_pesrecording;\r
+       double fps;\r
+\r
+#ifndef WIN32\r
+    pthread_mutex_t mutex;\r
+#else\r
+    HANDLE mutex;\r
+#endif\r
+    void lock();\r
+    void unLock();\r
+\r
+    ULLONG lengthBytes;\r
+    ULONG lengthFrames;\r
+    ULONG currentFrameNumber;\r
+    UINT blockSize;\r
+    UINT startupBlockSize;\r
+    UCHAR* threadBuffer;\r
+    UCHAR state;\r
+    UCHAR ifactor;\r
+};\r
+\r
+#endif\r
+\r
+\r
+/*\r
+\r
+Possible states:\r
+\r
+Play, Pause, FFwd, FBwd, (Stop), [Jump]\r
+\r
+                    Possible  Working\r
+\r
+Play   -> PauseP       *         *\r
+       -> PauseI\r
+       -> FFwd         *         *\r
+       -> FBwd         *         *\r
+       -> Stop         *         *\r
+       -> Jump         *         *\r
+       -> Jump_PI      *         *\r
+\r
+PauseP -> Play         *         *\r
+       -> PauseI\r
+       -> FFwd         *         *\r
+       -> FBwd         *         *\r
+       -> Stop         *         *\r
+       -> Jump         *         *\r
+       -> Jump_PI      *         *\r
+\r
+PauseI -> Play         *         *\r
+       -> PauseP\r
+       -> FFwd         *         *\r
+       -> FBwd         *         *\r
+       -> Stop         *         *\r
+       -> Jump         *         *\r
+       -> Jump_PI      *         *\r
+\r
+FFwd   -> Play         *         *\r
+       -> PauseP\r
+       -> PauseI       *         *\r
+       -> FBwd         *         *\r
+       -> Stop         *         *\r
+       -> Jump         *         *\r
+       -> Jump_PI      *         *\r
+\r
+FBwd   -> Play         *         *\r
+       -> PauseP\r
+       -> PauseI       *         *\r
+       -> FFwd         *         *\r
+       -> Stop         *         *\r
+       -> Jump         *         *\r
+       -> Jump_PI      *         *\r
+\r
+Stop   -> Play         *         *\r
+       -> PauseP\r
+       -> PauseI\r
+       -> FFwd\r
+       -> FBwd\r
+       -> Jump\r
+       -> Jump_PI\r
+\r
+*/\r
index 6b6f35f40c9414210cd0fb5288f2ece2623d044b..90af2b5918632dd3c81b299a94756782b102fa4d 100644 (file)
-/*
-    Copyright 2008 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "playerliveradio.h"
-
-#include "log.h"
-#include "audio.h"
-#include "demuxerts.h"
-#include "vdr.h"
-#include "messagequeue.h"
-#include "remote.h"
-#include "message.h"
-#include "channel.h"
-#include "video.h"
-
-// ----------------------------------- Called from outside, one offs or info funcs
-
-PlayerLiveRadio::PlayerLiveRadio(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
-: afeed(this)
-{
-  messageQueue = tmessageQueue;
-  messageReceiver = tmessageReceiver;
-  chanList = tchanList;
-  
-  audio = Audio::getInstance();
-  logger = Log::getInstance();
-  vdr = VDR::getInstance();
-  initted = false;
-
-  stopNow = false;
-  state = S_STOP;
-  Video::getInstance()->turnVideoOff();
-}
-
-PlayerLiveRadio::~PlayerLiveRadio()
-{
-  if (initted) shutdown();
-}
-
-int PlayerLiveRadio::init()
-{
-  if (initted) return 0;
-
-  demuxer = new DemuxerTS();
-  if (!demuxer) return 0;
-  if (!demuxer->init(this, audio, NULL, NULL, 0, 200000,0))
-  {
-    logger->log("PlayerLiveRadio", Log::ERR, "Demuxer failed to init");
-    shutdown();
-    return 0;
-  }
-
-  afeed.init();
-  audio->stop();
-
-  initted = true;
-  return 1;
-}
-
-int PlayerLiveRadio::shutdown()
-{
-  if (!initted) return 0;
-  stop();
-  initted = false;
-
-  delete demuxer;
-
-
-
-  return 1;
-}
-
-bool* PlayerLiveRadio::getDemuxerMpegAudioChannels()
-{
-  return demuxer->getmpAudioChannels();
-}
-
-bool* PlayerLiveRadio::getDemuxerAc3AudioChannels()
-{
-  return demuxer->getac3AudioChannels();
-}
-
-int PlayerLiveRadio::getCurrentAudioChannel()
-{
-  return demuxer->getAID();
-}
-
-int *PlayerLiveRadio::getTeletxtSubtitlePages(){
-    return NULL;
-}
-
-int PlayerLiveRadio::getCurrentSubtitleChannel(){
-    return demuxer->getSubID();
-}
-
-void PlayerLiveRadio::setAudioChannel(int newChannel, int type)
-{
-  return demuxer->setAID(newChannel, type);
-}
-
-void PlayerLiveRadio::setSubtitleChannel(int newChannel)
-{
-  return demuxer->setSubID(newChannel);
-}
-
-// ----------------------------------- Externally called events
-
-void PlayerLiveRadio::go(ULONG index)
-{
-  struct PLInstruction i;
-  i.instruction = I_SETCHANNEL;
-  i.channelIndex = index;
-  instructions.push(i);
-  threadStart();
-}
-
-void PlayerLiveRadio::setChannel(ULONG index)
-{
-  logger->log("PlayerLiveRadio", Log::DEBUG, "setChannel");
-  struct PLInstruction i;
-  i.instruction = I_SETCHANNEL;
-  i.channelIndex = index;
-  instructions.push(i);  
-  logger->log("PlayerLiveRadio", Log::DEBUG, "posted setChannel instruction, now %i in queue", instructions.size());
-  threadSignalNoLock();
-}
-
-void PlayerLiveRadio::stop()
-{
-  logger->log("PlayerLiveRadio", Log::DEBUG, "stop");
-  struct PLInstruction i;
-  i.instruction = I_STOP;
-  instructions.push(i);
-  threadSignal();
-  threadStop();
-}
-
-// ----------------------------------- Callback
-
-void PlayerLiveRadio::call(void* caller)
-{
-}
-
-// -----------------------------------
-
-void PlayerLiveRadio::streamReceive(ULONG flag, void* data, ULONG len)
-{
-  // Flag:
-  // 0 = normal stream packet
-  // 1 = stream end
-  // 2 = connection lost
-
-  if (flag == 1)
-  {
-    if (data) abort();
-    
-    Message* m = new Message();
-    m->from = this;
-    m->to = messageReceiver;
-    m->message = Message::PLAYER_EVENT;
-    m->parameter = PlayerLiveRadio::STREAM_END;
-    messageQueue->postMessageFromOuterSpace(m);
-  }
-  
-  if (streamChunks.size() < 11)
-  {
-    StreamChunk s;
-    s.data = data;
-    s.len = len;
-    streamChunks.push(s);
-    threadSignalNoLock();
-  }
-  else
-  {
-    // Too many chunks in streamChunks, drop this chunk
-    free(data);
-    logger->log("PlayerLiveRadio", Log::WARN, "Dropped chunk");
-  }
-}
-
-void PlayerLiveRadio::clearStreamChunks()
-{
-  while(streamChunks.size())
-  {
-    logger->log("PlayerLiveRadio", Log::DEBUG, "Dropping chunk from old stream");
-    struct StreamChunk s = streamChunks.front();
-    streamChunks.pop();
-    free(s.data);
-  }
-}
-
-void PlayerLiveRadio::chunkToDemuxer()
-{
-  StreamChunk s = streamChunks.front();
-  streamChunks.pop();
-  //logger->log("PlayerLiveRadio", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
-  /*int a =*/ demuxer->put((UCHAR*)s.data, s.len);
-  //logger->log("PlayerLiveRadio", Log::DEBUG, "put %i to demuxer", a);
-  free(s.data);  
-}
-
-void PlayerLiveRadio::switchState(UCHAR newState)
-{
-  logger->log("PlayerLiveRadio", Log::DEBUG, "Switch from state %u to state %u", state, newState);
-
-  switch(state)
-  {
-    case S_STOP:   // FROM S_STOP
-    {
-      switch(newState)
-      {
-        case S_PREBUFFERING:
-        {
-          audio->stop();
-          audio->unPause();
-          audio->reset();
-          audio->setStreamType(Audio::MPEG2_PES);
-          audio->systemMuteOff();      
-          audio->doMuting();              
-          audio->play();
-          audio->pause();
-          demuxer->reset();
-          afeed.start();
-          
-          state = newState;
-          preBufferCount = 0;
-          return;
-        }
-        default:
-        {
-          logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
-          abort();
-          break;
-        }
-      }
-    }
-
-    case S_PREBUFFERING:    // FROM S_PREBUFFERING
-    {
-      switch(newState)
-      {
-        case S_PLAY:
-        {
-          audio->unPause();
-          state = newState;
-          return;
-        }
-        case S_STOP:
-        {
-          vdr->stopStreaming();
-          clearStreamChunks();
-          afeed.stop();
-          audio->stop();
-          audio->reset();
-          state = newState;
-          return;        
-        }
-        case S_PREBUFFERING:
-        {
-          vdr->stopStreaming();
-          clearStreamChunks();
-          afeed.stop();
-          audio->stop();
-          audio->reset();
-          audio->play();
-          audio->pause();
-          demuxer->reset();
-          afeed.start();
-
-          state = newState;
-          preBufferCount = 0;
-          return;        
-        }
-        default:
-        {
-          logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
-          abort();
-          break;
-        }        
-      }
-    }
-    
-    case S_PLAY:     // FROM S_PLAY
-    {
-      switch(newState)
-      {
-        case S_STOP:
-        { 
-          vdr->stopStreaming();
-          clearStreamChunks();
-          afeed.stop();
-          audio->stop();
-          audio->reset();
-          state = newState;
-          return;
-        }
-        case S_PREBUFFERING: // IS THIS HOW IT WORKS?
-        {
-          vdr->stopStreaming();
-          clearStreamChunks();
-          afeed.stop();
-          audio->stop();
-          audio->reset();
-          audio->play();
-          audio->pause();
-          demuxer->reset();
-          afeed.start();
-
-          state = newState;
-          preBufferCount = 0;
-          return;
-        }
-        default:
-        {
-          logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
-          abort();
-          break;
-        }        
-      }
-    }    
-  }  
-}
-
-bool PlayerLiveRadio::checkError()
-{
-  if (!vdr->isConnected())
-  {
-    switchState(S_STOP);
-    
-    Message* m = new Message();
-    m->from = this;
-    m->to = messageReceiver;
-    m->message = Message::PLAYER_EVENT;
-    m->parameter = PlayerLiveRadio::CONNECTION_LOST;
-    messageQueue->postMessageFromOuterSpace(m);
-    
-    return true;
-  }   
-  return false;
-}
-
-void PlayerLiveRadio::optimizeInstructionQueue()
-{
-  // Walk the list
-  
-  // Currently there are only 2 instruction types, so this is a bit overkill...
-
-  struct PLInstruction i;
-  while(instructions.size() > 1)
-  {
-    i = instructions.front();
-    if (i.instruction == I_SETCHANNEL)
-    {
-      instructions.pop();  // if this is the first of more than 1 command, currently it cannot possibly be relevant
-    }
-    else if (i.instruction == I_STOP)
-    {
-      return; // return here and ensure the next instruction will be stop
-    }
-  }
-}
-
-void PlayerLiveRadio::threadMethod()
-{
-  while(1)
-  {
-    while(!instructions.empty())
-    {
-      if (instructions.size() > 1)
-      {
-        logger->log("PlayerLiveRadio", Log::DEBUG, "Should optimise");
-        optimizeInstructionQueue();
-      }
-
-      struct PLInstruction i = instructions.front();
-      instructions.pop();
-    
-      if (i.instruction == I_SETCHANNEL)
-      {
-        logger->log("PlayerLiveRadio", Log::DEBUG, "start new stream");
-
-        switchState(S_PREBUFFERING);
-
-        if (!checkError())
-        {
-          Channel* chan = (*chanList)[i.channelIndex];
-          chan->loadPids();
-
-          if (chan->numAPids > 0) 
-          {
-            demuxer->setAID(chan->apids[0].pid,0);
-            logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);
-          }
-          else 
-          {
-            logger->log("PlayerLiveRadio", Log::WARN, "Demuxer no pids!");
-          }
-
-          int streamSuccess = vdr->streamChannel(chan->number, this);
-          if (!checkError() && !streamSuccess)
-          {      
-            Message* m = new Message();
-            m->from = this;
-            m->to = messageReceiver;
-            m->message = Message::PLAYER_EVENT;
-            m->parameter = PlayerLiveRadio::STREAM_END;
-            messageQueue->postMessageFromOuterSpace(m);
-          }
-        }
-      }
-      else if (i.instruction == I_STOP)
-      {
-        logger->log("PlayerLiveRadio", Log::DEBUG, "Stopping");
-        switchState(S_STOP);
-        checkError();
-
-        stopNow = true;
-        break;
-      }
-    }
-
-    if (stopNow) break;
-
-    while(streamChunks.size())
-    {
-      chunkToDemuxer();
-
-      if (state == S_PREBUFFERING)
-      {
-        ++preBufferCount;
-        ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
-        logger->log("PlayerLiveRadio", Log::DEBUG, "Prebuffering %lu%%", percentDone);
-        
-        Message* m = new Message();
-        m->from = this;
-        m->to = messageReceiver;
-        m->message = Message::PLAYER_EVENT;
-        m->parameter = PlayerLiveRadio::PREBUFFERING;
-        m->tag = percentDone;
-        messageQueue->postMessageFromOuterSpace(m);
-
-        if (preBufferCount == preBufferAmount)
-        {
-          switchState(S_PLAY);
-          checkError();
-        }
-      }
-    }
-    
-    threadLock();
-    threadWaitForSignal(); // unlocks and waits for signal
-    threadUnlock();
-  }
-
-  logger->log("PlayerLiveRadio", Log::DEBUG, "End of thread");
-}
-
+/*\r
+    Copyright 2008 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "playerliveradio.h"\r
+\r
+#include "log.h"\r
+#include "audio.h"\r
+#include "demuxerts.h"\r
+#include "vdr.h"\r
+#include "messagequeue.h"\r
+#include "remote.h"\r
+#include "message.h"\r
+#include "channel.h"\r
+#include "video.h"\r
+\r
+// ----------------------------------- Called from outside, one offs or info funcs\r
+\r
+PlayerLiveRadio::PlayerLiveRadio(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)\r
+: afeed(this)\r
+{\r
+  messageQueue = tmessageQueue;\r
+  messageReceiver = tmessageReceiver;\r
+  chanList = tchanList;\r
+  \r
+  audio = Audio::getInstance();\r
+  logger = Log::getInstance();\r
+  vdr = VDR::getInstance();\r
+  initted = false;\r
+\r
+  stopNow = false;\r
+  state = S_STOP;\r
+  Video::getInstance()->turnVideoOff();\r
+}\r
+\r
+PlayerLiveRadio::~PlayerLiveRadio()\r
+{\r
+  if (initted) shutdown();\r
+}\r
+\r
+int PlayerLiveRadio::init()\r
+{\r
+  if (initted) return 0;\r
+\r
+  demuxer = new DemuxerTS();\r
+  if (!demuxer) return 0;\r
\r
+  if (!demuxer->init(this, audio, NULL, NULL, 0, 200000,0))\r
+  {\r
+    logger->log("PlayerLiveRadio", Log::ERR, "Demuxer failed to init");\r
+    shutdown();\r
+    return 0;\r
+  }\r
+\r
+  afeed.init();\r
+  audio->stop();\r
+\r
+  initted = true;\r
+  return 1;\r
+}\r
+\r
+int PlayerLiveRadio::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+  stop();\r
+  initted = false;\r
+\r
+  delete demuxer;\r
+\r
+\r
+\r
+  return 1;\r
+}\r
+\r
+bool* PlayerLiveRadio::getDemuxerMpegAudioChannels()\r
+{\r
+  return demuxer->getmpAudioChannels();\r
+}\r
+\r
+bool* PlayerLiveRadio::getDemuxerAc3AudioChannels()\r
+{\r
+  return demuxer->getac3AudioChannels();\r
+}\r
+\r
+int PlayerLiveRadio::getCurrentAudioChannel()\r
+{\r
+  return demuxer->getAID();\r
+}\r
+\r
+int *PlayerLiveRadio::getTeletxtSubtitlePages(){\r
+    return NULL;\r
+}\r
+\r
+int PlayerLiveRadio::getCurrentSubtitleChannel(){\r
+    return demuxer->getSubID();\r
+}\r
+\r
+void PlayerLiveRadio::setAudioChannel(int newChannel, int type)\r
+{\r
+  demuxer->setAID(newChannel, type);\r
+}\r
+\r
+void PlayerLiveRadio::setSubtitleChannel(int newChannel)\r
+{\r
+  demuxer->setSubID(newChannel);\r
+}\r
+\r
+// ----------------------------------- Externally called events\r
+\r
+void PlayerLiveRadio::go(ULONG index)\r
+{\r
+  struct PLInstruction i;\r
+  i.instruction = I_SETCHANNEL;\r
+  i.channelIndex = index;\r
+  instructions.push(i);\r
+  threadStart();\r
+}\r
+\r
+void PlayerLiveRadio::setChannel(ULONG index)\r
+{\r
+  logger->log("PlayerLiveRadio", Log::DEBUG, "setChannel");\r
+  struct PLInstruction i;\r
+  i.instruction = I_SETCHANNEL;\r
+  i.channelIndex = index;\r
+  instructions.push(i);  \r
+  logger->log("PlayerLiveRadio", Log::DEBUG, "posted setChannel instruction, now %i in queue", instructions.size());\r
+  threadSignalNoLock();\r
+}\r
+\r
+void PlayerLiveRadio::stop()\r
+{\r
+  logger->log("PlayerLiveRadio", Log::DEBUG, "stop");\r
+  struct PLInstruction i;\r
+  i.instruction = I_STOP;\r
+  instructions.push(i);\r
+  threadSignal();\r
+  threadStop();\r
+}\r
+\r
+// ----------------------------------- Callback\r
+\r
+void PlayerLiveRadio::call(void* caller)\r
+{\r
+}\r
+\r
+// -----------------------------------\r
+\r
+void PlayerLiveRadio::streamReceive(ULONG flag, void* data, ULONG len)\r
+{\r
+  // Flag:\r
+  // 0 = normal stream packet\r
+  // 1 = stream end\r
+  // 2 = connection lost\r
+\r
+  if (flag == 1)\r
+  {\r
+    if (data) abort();\r
+    \r
+    Message* m = new Message();\r
+    m->from = this;\r
+    m->to = messageReceiver;\r
+    m->message = Message::PLAYER_EVENT;\r
+    m->parameter = PlayerLiveRadio::STREAM_END;\r
+    messageQueue->postMessageFromOuterSpace(m);\r
+  }\r
+  \r
+  if (streamChunks.size() < 11)\r
+  {\r
+    StreamChunk s;\r
+    s.data = data;\r
+    s.len = len;\r
+    streamChunks.push(s);\r
+    threadSignalNoLock();\r
+  }\r
+  else\r
+  {\r
+    // Too many chunks in streamChunks, drop this chunk\r
+    free(data);\r
+    logger->log("PlayerLiveRadio", Log::WARN, "Dropped chunk");\r
+  }\r
+}\r
+\r
+void PlayerLiveRadio::clearStreamChunks()\r
+{\r
+  while(streamChunks.size())\r
+  {\r
+    logger->log("PlayerLiveRadio", Log::DEBUG, "Dropping chunk from old stream");\r
+    struct StreamChunk s = streamChunks.front();\r
+    streamChunks.pop();\r
+    free(s.data);\r
+  }\r
+}\r
+\r
+void PlayerLiveRadio::chunkToDemuxer()\r
+{\r
+  StreamChunk s = streamChunks.front();\r
+  streamChunks.pop();\r
+  //logger->log("PlayerLiveRadio", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);\r
+  /*int a =*/ demuxer->put((UCHAR*)s.data, s.len);\r
+  //logger->log("PlayerLiveRadio", Log::DEBUG, "put %i to demuxer", a);\r
+  free(s.data);  \r
+}\r
+\r
+void PlayerLiveRadio::switchState(UCHAR newState)\r
+{\r
+  logger->log("PlayerLiveRadio", Log::DEBUG, "Switch from state %u to state %u", state, newState);\r
+\r
+  switch(state)\r
+  {\r
+    case S_STOP:   // FROM S_STOP\r
+    {\r
+      switch(newState)\r
+      {\r
+        case S_PREBUFFERING:\r
+        {\r
+          audio->stop();\r
+          audio->unPause();\r
+          audio->reset();\r
+          audio->setStreamType(Audio::MPEG2_PES);\r
+          audio->systemMuteOff();      \r
+          audio->doMuting();              \r
+          audio->play();\r
+          audio->pause();\r
+          demuxer->reset();\r
+          afeed.start();\r
+          \r
+          state = newState;\r
+          preBufferCount = 0;\r
+          return;\r
+        }\r
+        default:\r
+        {\r
+          logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+          abort();\r
+          break;\r
+        }\r
+      }\r
+    }\r
+\r
+    case S_PREBUFFERING:    // FROM S_PREBUFFERING\r
+    {\r
+      switch(newState)\r
+      {\r
+        case S_PLAY:\r
+        {\r
+          audio->unPause();\r
+          state = newState;\r
+          return;\r
+        }\r
+        case S_STOP:\r
+        {\r
+          vdr->stopStreaming();\r
+          clearStreamChunks();\r
+          afeed.stop();\r
+          audio->stop();\r
+          audio->reset();\r
+          state = newState;\r
+          return;        \r
+        }\r
+        case S_PREBUFFERING:\r
+        {\r
+          vdr->stopStreaming();\r
+          clearStreamChunks();\r
+          afeed.stop();\r
+          audio->stop();\r
+          audio->reset();\r
+          audio->play();\r
+          audio->pause();\r
+          demuxer->reset();\r
+          afeed.start();\r
+\r
+          state = newState;\r
+          preBufferCount = 0;\r
+          return;        \r
+        }\r
+        default:\r
+        {\r
+          logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+          abort();\r
+          break;\r
+        }        \r
+      }\r
+    }\r
+    \r
+    case S_PLAY:     // FROM S_PLAY\r
+    {\r
+      switch(newState)\r
+      {\r
+        case S_STOP:\r
+        { \r
+          vdr->stopStreaming();\r
+          clearStreamChunks();\r
+          afeed.stop();\r
+          audio->stop();\r
+          audio->reset();\r
+          state = newState;\r
+          return;\r
+        }\r
+        case S_PREBUFFERING: // IS THIS HOW IT WORKS?\r
+        {\r
+          vdr->stopStreaming();\r
+          clearStreamChunks();\r
+          afeed.stop();\r
+          audio->stop();\r
+          audio->reset();\r
+          audio->play();\r
+          audio->pause();\r
+          demuxer->reset();\r
+          afeed.start();\r
+\r
+          state = newState;\r
+          preBufferCount = 0;\r
+          return;\r
+        }\r
+        default:\r
+        {\r
+          logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+          abort();\r
+          break;\r
+        }        \r
+      }\r
+    }    \r
+  }  \r
+}\r
+\r
+bool PlayerLiveRadio::checkError()\r
+{\r
+  if (!vdr->isConnected())\r
+  {\r
+    switchState(S_STOP);\r
+    \r
+    Message* m = new Message();\r
+    m->from = this;\r
+    m->to = messageReceiver;\r
+    m->message = Message::PLAYER_EVENT;\r
+    m->parameter = PlayerLiveRadio::CONNECTION_LOST;\r
+    messageQueue->postMessageFromOuterSpace(m);\r
+    \r
+    return true;\r
+  }   \r
+  return false;\r
+}\r
+\r
+void PlayerLiveRadio::optimizeInstructionQueue()\r
+{\r
+  // Walk the list\r
+  \r
+  // Currently there are only 2 instruction types, so this is a bit overkill...\r
+\r
+  struct PLInstruction i;\r
+  while(instructions.size() > 1)\r
+  {\r
+    i = instructions.front();\r
+    if (i.instruction == I_SETCHANNEL)\r
+    {\r
+      instructions.pop();  // if this is the first of more than 1 command, currently it cannot possibly be relevant\r
+    }\r
+    else if (i.instruction == I_STOP)\r
+    {\r
+      return; // return here and ensure the next instruction will be stop\r
+    }\r
+  }\r
+}\r
+\r
+void PlayerLiveRadio::threadMethod()\r
+{\r
+  while(1)\r
+  {\r
+    while(!instructions.empty())\r
+    {\r
+      if (instructions.size() > 1)\r
+      {\r
+        logger->log("PlayerLiveRadio", Log::DEBUG, "Should optimise");\r
+        optimizeInstructionQueue();\r
+      }\r
+\r
+      struct PLInstruction i = instructions.front();\r
+      instructions.pop();\r
+    \r
+      if (i.instruction == I_SETCHANNEL)\r
+      {\r
+        logger->log("PlayerLiveRadio", Log::DEBUG, "start new stream");\r
+\r
+        switchState(S_PREBUFFERING);\r
+\r
+        if (!checkError())\r
+        {\r
+          Channel* chan = (*chanList)[i.channelIndex];\r
+          chan->loadPids();\r
+\r
+          if (chan->numAPids > 0) \r
+          {\r
+            demuxer->setAID(chan->apids[0].pid,0);\r
+            logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);\r
+          }\r
+          else \r
+          {\r
+            logger->log("PlayerLiveRadio", Log::WARN, "Demuxer no pids!");\r
+          }\r
+\r
+          int streamSuccess = vdr->streamChannel(chan->number, this);\r
+          if (!checkError() && !streamSuccess)\r
+          {      \r
+            Message* m = new Message();\r
+            m->from = this;\r
+            m->to = messageReceiver;\r
+            m->message = Message::PLAYER_EVENT;\r
+            m->parameter = PlayerLiveRadio::STREAM_END;\r
+            messageQueue->postMessageFromOuterSpace(m);\r
+          }\r
+        }\r
+      }\r
+      else if (i.instruction == I_STOP)\r
+      {\r
+        logger->log("PlayerLiveRadio", Log::DEBUG, "Stopping");\r
+        switchState(S_STOP);\r
+        checkError();\r
+\r
+        stopNow = true;\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (stopNow) break;\r
+\r
+    while(streamChunks.size())\r
+    {\r
+      chunkToDemuxer();\r
+\r
+      if (state == S_PREBUFFERING)\r
+      {\r
+        ++preBufferCount;\r
+        ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);\r
+        logger->log("PlayerLiveRadio", Log::DEBUG, "Prebuffering %lu%%", percentDone);\r
+        \r
+        Message* m = new Message();\r
+        m->from = this;\r
+        m->to = messageReceiver;\r
+        m->message = Message::PLAYER_EVENT;\r
+        m->parameter = PlayerLiveRadio::PREBUFFERING;\r
+        m->tag = percentDone;\r
+        messageQueue->postMessageFromOuterSpace(m);\r
+\r
+        if (preBufferCount == preBufferAmount)\r
+        {\r
+          switchState(S_PLAY);\r
+          checkError();\r
+        }\r
+      }\r
+    }\r
+    \r
+    threadLock();\r
+    threadWaitForSignal(); // unlocks and waits for signal\r
+    threadUnlock();\r
+  }\r
+\r
+  logger->log("PlayerLiveRadio", Log::DEBUG, "End of thread");\r
+}\r
+\r
index 20ff359944222ae9a5d3e3ea2f85c6d261befad5..7113f8eb9b137d9557b0859b9fe55f31f1451980 100644 (file)
-/*
-    Copyright 2007 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "playerlivetv.h"
-
-#include "log.h"
-#include "audio.h"
-#include "video.h"
-#include "demuxerts.h"
-#include "vdr.h"
-#include "messagequeue.h"
-#include "remote.h"
-#include "message.h"
-#include "channel.h"
-#include "dvbsubtitles.h"
-#include "osdreceiver.h"
-
-// ----------------------------------- Called from outside, one offs or info funcs
-
-PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
-: vfeed(this), afeed(this), tfeed(this)
-{
-  messageQueue = tmessageQueue;
-  messageReceiver = tmessageReceiver;
-  osdReceiver = tosdReceiver;
-  chanList = tchanList;
-  
-  audio = Audio::getInstance();
-  video = Video::getInstance();
-  logger = Log::getInstance();
-  vdr = VDR::getInstance();
-  initted = false;
-
-  subtitlesShowing = false;
-  videoStartup = false;
-  pendingAudioPlay = false;
-
-  stopNow = false;
-  state = S_STOP;
-
-  video->turnVideoOn();
-}
-
-PlayerLiveTV::~PlayerLiveTV()
-{
-  if (initted) shutdown();
-}
-
-int PlayerLiveTV::init()
-{
-  if (initted) return 0;
-
-  demuxer = new DemuxerTS();
-  if (!demuxer) return 0;
-  subtitles = new DVBSubtitles(osdReceiver);
-  if (!subtitles) return 0;
-
-  teletext = new TeletextDecoderVBIEBU();
-  
-  unsigned int demux_video_size=2097152;
-  if (video->supportsh264()) demux_video_size*=5;
-  if (!demuxer->init(this, audio, video, teletext, demux_video_size, 524288, 65536,25./*unimportant*/,subtitles))
-  {
-    logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
-    shutdown();
-    return 0;
-  }
-
-  vfeed.init();
-  afeed.init();
-  tfeed.init();
-
-  video->stop();
-  video->blank();
-  audio->stop();
-
-  initted = true;
-  return 1;
-}
-
-int PlayerLiveTV::shutdown()
-{
-  if (!initted) return 0;
-  stop();
-  initted = false;
-
-  delete demuxer;
-  delete subtitles;
-  delete teletext;
-  teletext = NULL;
-  return 1;
-}
-
-bool* PlayerLiveTV::getDemuxerMpegAudioChannels()
-{
-  return demuxer->getmpAudioChannels();
-}
-
-bool* PlayerLiveTV::getDemuxerAc3AudioChannels()
-{
-  return demuxer->getac3AudioChannels();
-}
-
-int PlayerLiveTV::getCurrentAudioChannel()
-{
-  return demuxer->getAID();
-}
-
-void PlayerLiveTV::setAudioChannel(int newChannel, int type)
-{
-  return demuxer->setAID(newChannel,type);
-}
-
-void PlayerLiveTV::setSubtitleChannel(int newChannel)
-{
-  return demuxer->setSubID(newChannel);
-}
-
-int *PlayerLiveTV::getTeletxtSubtitlePages()
-{
-    return teletext->getSubtitlePages();
-}
-
-int PlayerLiveTV::getCurrentSubtitleChannel(){
-    return demuxer->getSubID();
-}
-
-bool PlayerLiveTV::toggleSubtitles()
-{
-  if (!subtitlesShowing)
-  {
-    subtitlesShowing = true;
-    subtitles->show();
-  }
-  else
-  {
-    subtitlesShowing = false;
-    subtitles->hide();
-  }
-  return subtitlesShowing;
-}
-
-
-void  PlayerLiveTV::turnSubtitlesOn(bool ison) {
- if (ison)
-  {
-    subtitlesShowing = true;
-    subtitles->show();
-  }
-  else
-  {
-    subtitlesShowing = false;
-    subtitles->hide();
-  }
-
-}
-// ----------------------------------- Externally called events
-
-void PlayerLiveTV::go(ULONG index)
-{
-  struct PLInstruction i;
-  i.instruction = I_SETCHANNEL;
-  i.channelIndex = index;
-  instructions.push(i);
-  threadStart();
-}
-
-void PlayerLiveTV::setChannel(ULONG index)
-{
-  logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
-  struct PLInstruction i;
-  i.instruction = I_SETCHANNEL;
-  i.channelIndex = index;
-  instructions.push(i);  
-  threadSignalNoLock();
-}
-
-void PlayerLiveTV::stop()
-{
-  logger->log("PlayerLiveTV", Log::DEBUG, "stop");
-  struct PLInstruction i;
-  i.instruction = I_STOP;
-  instructions.push(i);
-  threadSignal();
-  threadStop();
-}
-
-// ----------------------------------- Callback
-
-void PlayerLiveTV::call(void* caller)
-{
-  if (caller == demuxer)
-  {
-    logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");
-
-    int dxCurrentAspect = demuxer->getAspectRatio();
-    if (dxCurrentAspect == Demuxer::ASPECT_4_3)
-    {
-      if (video->getTVsize() == Video::ASPECT16X9)
-      {
-        logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
-        video->setAspectRatio(Video::ASPECT4X3);
-      }
-      else
-      {
-        logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
-      }
-
-      Message* m = new Message();
-      m->from = this;
-      m->to = messageReceiver;
-      m->message = Message::PLAYER_EVENT;
-      m->parameter = PlayerLiveTV::ASPECT43;
-      messageQueue->postMessageFromOuterSpace(m);
-    }
-    else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
-    {
-      if (video->getTVsize() == Video::ASPECT16X9)
-      {
-        logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
-        video->setAspectRatio(Video::ASPECT16X9);
-      }
-      else
-      {
-        logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
-      }    
-
-      Message* m = new Message();
-      m->from = this;
-      m->to = messageReceiver;
-      m->message = Message::PLAYER_EVENT;
-      m->parameter = PlayerLiveTV::ASPECT169;
-      messageQueue->postMessageFromOuterSpace(m);
-    }
-    else
-    {
-      logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... ignoring");
-    }
-  }
-  else if (caller == &afeed)
-  {
-    if (state == S_VIDEOSTARTUP)
-    {
-      logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");
-      videoStartup = true;
-      threadSignalNoLock();
-    }
-  }
-}
-
-// -----------------------------------
-
-void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)
-{
-  // Flag:
-  // 0 = normal stream packet
-  // 1 = stream end
-  // 2 = connection lost
-
-//  logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
-
-  if (flag == 1)
-  {
-    if (data) abort();
-    
-    Message* m = new Message();
-    m->from = this;
-    m->to = messageReceiver;
-    m->message = Message::PLAYER_EVENT;
-    m->parameter = PlayerLiveTV::STREAM_END;
-    messageQueue->postMessageFromOuterSpace(m);
-  }
-        
-  if (streamChunks.size() < 11)
-  {
-    StreamChunk s;
-    s.data = data;
-    s.len = len;
-    streamChunks.push(s);
-    threadSignalNoLock();
-  }
-  else
-  {
-    // Too many chunks in streamChunks, drop this chunk
-    free(data);
-    logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");
-  }
-}
-
-void PlayerLiveTV::clearStreamChunks()
-{
-  while(streamChunks.size())
-  {
-    logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");
-    struct StreamChunk s = streamChunks.front();
-    streamChunks.pop();
-    free(s.data);
-  }
-}
-
-void PlayerLiveTV::chunkToDemuxer()
-{
-  StreamChunk s = streamChunks.front();
-  streamChunks.pop();
-  //logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
-  /*int a = */demuxer->put((UCHAR*)s.data, s.len);
-  //logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);
-  free(s.data);  
-  if (pendingAudioPlay && demuxer->getHorizontalSize()) //Horizontal Size is zero, if not parsed
-  {
-      video->sync();
-      video->play();
-      video->pause();
-      //audio->setStreamType(Audio::MPEG2_PES);
-      audio->sync();
-      audio->play();
-      audio->pause();
-      pendingAudioPlay = false;
-  }
-}
-
-void PlayerLiveTV::switchState(UCHAR newState)
-{
-  logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);
-
-  switch(state)
-  {
-    case S_STOP:   // FROM S_STOP
-    {
-      switch(newState)
-      {
-        case S_VIDEOSTARTUP:
-        {
-          video->blank();
-          video->reset();
-          //video->sync();
-          //video->play();
-          //video->pause();
-
-          audio->stop();
-          audio->unPause();
-          audio->reset();
-          //audio->setStreamType(Audio::MPEG2_PES);
-          //audio->sync();
-          // I make this modification, since the video/audio devices needs to know at least
-          // which kind of video is embedded inside the stream
-          // therefore the demuxer needs to feeded at least with enough data
-          // to have one video header
-          // This is crucial, if we have mixed h264/mpeg2 channels
-          // the information from channels is not enough since some directshow decoders need
-          // width and height information before startup
-          pendingAudioPlay = true;
-
-          //audio->play();
-          //audio->pause();
-
-          demuxer->reset();
-          demuxer->seek();
-
-          afeed.start();
-          vfeed.start();
-          subtitles->start();
-          tfeed.start();
-          
-          state = newState;
-          return;
-        }
-        default:
-        {
-          logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
-          abort();
-          break;
-        }
-      }
-    }
-
-    case S_VIDEOSTARTUP:     // FROM S_VIDEOSTARTUP
-    {
-      switch(newState)
-      {
-        case S_PREBUFFERING:
-        {
-          pendingAudioPlay=false;
-          vfeed.release();
-          state = newState;
-          return;
-        }
-        
-        case S_VIDEOSTARTUP:
-        {
-          vdr->stopStreaming();
-          clearStreamChunks(); 
-          vfeed.stop();
-          afeed.stop();
-          subtitles->stop();
-          tfeed.stop();
-                           
-          video->blank();
-          video->reset();
-          //video->sync();
-          //video->play();
-          //video->pause();
-
-          audio->stop();
-          audio->unPause();
-          audio->reset();
-          //audio->setStreamType(Audio::MPEG2_PES);
-          //audio->sync();
-          pendingAudioPlay = true;
-          //audio->play();
-          //audio->pause();
-
-          demuxer->reset();
-          demuxer->seek();
-
-          afeed.start();
-          vfeed.start();
-          subtitles->start();     
-          tfeed.start();
-          state = newState;
-          return;
-        }        
-        case S_STOP:
-        { 
-          vdr->stopStreaming();
-          pendingAudioPlay=false;
-          clearStreamChunks();
-          vfeed.stop();
-          afeed.stop();
-          subtitles->stop();
-          tfeed.stop();
-          video->stop();
-          video->blank();
-          audio->stop();
-          audio->reset();
-          video->reset();
-          state = newState;
-          return;
-        }
-        default:
-        {
-          logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
-          abort();
-          break;
-        }        
-      }
-    }
-    
-    case S_PREBUFFERING:    // FROM S_PREBUFFERING
-    {
-      switch(newState)
-      {
-        case S_PLAY:
-        {
-          pendingAudioPlay=false;
-          audio->unPause();
-          video->unPause();
-          state = newState;
-          return;
-        }
-        case S_VIDEOSTARTUP:
-        {
-          vdr->stopStreaming();
-          clearStreamChunks();
-          vfeed.stop();
-          afeed.stop();
-          subtitles->stop();
-          tfeed.stop();
-          video->stop();
-          video->blank();
-          audio->stop();
-          audio->unPause();
-          audio->reset();
-
-          video->reset();
-          //video->sync();
-          //video->play();
-          //video->pause();
-
-          //audio->setStreamType(Audio::MPEG2_PES);
-          //audio->sync();
-          pendingAudioPlay = true;
-          //audio->play();
-          //audio->pause();
-
-          demuxer->reset();
-          demuxer->seek();
-
-          afeed.start();
-          vfeed.start();
-          subtitles->start();
-          tfeed.start();
-
-          state = newState;
-          return;
-        }
-        case S_STOP:
-        {
-          pendingAudioPlay=false;
-          vdr->stopStreaming();
-          clearStreamChunks();
-          vfeed.stop();
-          afeed.stop();
-          subtitles->stop();
-          tfeed.stop();
-          video->stop();
-          video->blank();
-          audio->stop();
-          audio->reset();
-          video->reset();
-          state = newState;
-          return;        
-        }
-        default:
-        {
-          logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
-          abort();
-          break;
-        }        
-      }
-    }
-    
-    case S_PLAY:     // FROM S_PLAY
-    {
-      switch(newState)
-      {
-        case S_STOP:
-        { 
-          pendingAudioPlay=false;
-          vdr->stopStreaming();
-          clearStreamChunks();
-          vfeed.stop();
-          afeed.stop();
-          subtitles->stop();
-          tfeed.stop();
-          video->stop();
-          video->blank();
-          audio->stop();
-          audio->reset();
-          video->reset();
-          state = newState;
-          return;
-        }
-        case S_VIDEOSTARTUP:
-        {
-          vdr->stopStreaming();
-          clearStreamChunks();
-          vfeed.stop();
-          afeed.stop();
-          subtitles->stop();
-          tfeed.stop();
-          video->stop();
-          video->blank();
-          audio->stop();
-          audio->unPause();
-          audio->reset();
-
-          video->reset();
-          
-          //video->sync();
-         // video->play();
-          //video->pause();
-
-          //audio->setStreamType(Audio::MPEG2_PES);
-          //audio->sync();
-          //audio->play();
-          //audio->pause();
-          pendingAudioPlay = true;
-
-          demuxer->reset();
-          demuxer->seek();
-
-          afeed.start();
-          vfeed.start();
-          subtitles->start();
-          tfeed.start();
-
-          state = newState;
-          return;
-        }
-        default:
-        {
-          logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
-          abort();
-          break;
-        }        
-      }
-    }    
-  }  
-}
-
-bool PlayerLiveTV::checkError()
-{
-  if (!vdr->isConnected())
-  {
-    if (state != S_STOP) switchState(S_STOP);
-    
-    Message* m = new Message();
-    m->from = this;
-    m->to = messageReceiver;
-    m->message = Message::PLAYER_EVENT;
-    m->parameter = PlayerLiveTV::CONNECTION_LOST;
-    messageQueue->postMessageFromOuterSpace(m);
-    
-    return true;
-  }   
-  return false;
-}
-
-void PlayerLiveTV::optimizeInstructionQueue()
-{
-  // Walk the list
-  
-  // Currently there are only 2 instruction types, so this is a bit overkill...
-
-  struct PLInstruction i;
-  while(instructions.size() > 1)
-  {
-    i = instructions.front();
-    if (i.instruction == I_SETCHANNEL)
-    {
-      instructions.pop();  // if this is the first of more than 1 command, currently it cannot possibly be relevant
-    }
-    else if (i.instruction == I_STOP)
-    {
-      return; // return here and ensure the next instruction will be stop
-    }
-  }
-}
-
-void PlayerLiveTV::threadMethod()
-{
-  while(1)
-  {
-    if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
-    {
-      switchState(S_PREBUFFERING);
-      videoStartup = false;
-      preBufferCount = 0;
-      
-      checkError();
-    }  
-  
-    while(!instructions.empty())
-    {
-      if (instructions.size() > 1) optimizeInstructionQueue();
-
-      struct PLInstruction i = instructions.front();
-      instructions.pop();
-    
-      if (i.instruction == I_SETCHANNEL)
-      {
-        logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");
-       
-        
-        switchState(S_VIDEOSTARTUP);
-        
-        if (!checkError())
-        {
-           Channel* chan = (*chanList)[i.channelIndex];
-           chan->loadPids();
-           h264=chan->vstreamtype==0x1b;
-           demuxer->seth264(h264);
-           video->seth264mode(chan->vstreamtype==0x1b);
-           demuxer->setVID(chan->vpid);
-           video->seth264mode(chan->vstreamtype==0x1b);
-
-          if (chan->numAPids > 0) 
-          {
-            demuxer->setAID(chan->apids[0].pid,0);
-            audio->setStreamType(Audio::MPEG2_PES);
-            logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);
-          }
-          else 
-          {
-              if (chan->numDPids > 0  && audio->maysupportAc3()) 
-              {
-                  demuxer->setAID(chan->dpids[0].pid,1);
-                  logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3)", chan->vpid, chan->dpids[0].pid);
-              } 
-              else
-              {
-                  logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
-              }
-          }
-          if (chan->numSPids > 0)
-            demuxer->setSubID(chan->spids[0].pid);
-          demuxer->setTID(chan->tpid);
-          teletext->ResetDecoder();
-          int streamSuccess = vdr->streamChannel(chan->number, this);
-          if (!checkError() && !streamSuccess)
-          {      
-            Message* m = new Message();
-            m->from = this;
-            m->to = messageReceiver;
-            m->message = Message::PLAYER_EVENT;
-            m->parameter = PlayerLiveTV::STREAM_END;
-            messageQueue->postMessageFromOuterSpace(m);
-          }
-        }
-      }
-      else if (i.instruction == I_STOP)
-      {
-        logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");
-        switchState(S_STOP);
-        checkError();
-
-        stopNow = true;
-        break;
-      }
-    }
-
-    if (stopNow) break;
-
-    while(streamChunks.size())
-    {
-      chunkToDemuxer();
-
-      if (state == S_PREBUFFERING)
-      {
-        ++preBufferCount;
-        ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
-        logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone);
-        
-        Message* m = new Message();
-        m->from = this;
-        m->to = messageReceiver;
-        m->message = Message::PLAYER_EVENT;
-        m->parameter = PlayerLiveTV::PREBUFFERING;
-        m->tag = percentDone;
-        messageQueue->postMessageFromOuterSpace(m);
-
-        if (preBufferCount == preBufferAmount)
-        {
-          switchState(S_PLAY);
-          checkError();
-        }
-      }
-    }
-    
-    threadLock();
-    threadWaitForSignal(); // unlocks and waits for signal
-    threadUnlock();
-  }
-
-  logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");
-}
-
+/*\r
+    Copyright 2007 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "playerlivetv.h"\r
+\r
+#include "log.h"\r
+#include "audio.h"\r
+#include "video.h"\r
+#include "demuxerts.h"\r
+#include "vdr.h"\r
+#include "messagequeue.h"\r
+#include "remote.h"\r
+#include "message.h"\r
+#include "channel.h"\r
+#include "dvbsubtitles.h"\r
+#include "osdreceiver.h"\r
+\r
+// ----------------------------------- Called from outside, one offs or info funcs\r
+\r
+PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)\r
+: vfeed(this), afeed(this), tfeed(this)\r
+{\r
+  messageQueue = tmessageQueue;\r
+  messageReceiver = tmessageReceiver;\r
+  osdReceiver = tosdReceiver;\r
+  chanList = tchanList;\r
+  \r
+  audio = Audio::getInstance();\r
+  video = Video::getInstance();\r
+  logger = Log::getInstance();\r
+  vdr = VDR::getInstance();\r
+  initted = false;\r
+\r
+  subtitlesShowing = false;\r
+  videoStartup = false;\r
+  pendingAudioPlay = false;\r
+\r
+  stopNow = false;\r
+  state = S_STOP;\r
+\r
+  video->turnVideoOn();\r
+}\r
+\r
+PlayerLiveTV::~PlayerLiveTV()\r
+{\r
+  if (initted) shutdown();\r
+}\r
+\r
+int PlayerLiveTV::init()\r
+{\r
+  if (initted) return 0;\r
+\r
+  demuxer = new DemuxerTS();\r
+  if (!demuxer) return 0;\r
+  subtitles = new DVBSubtitles(osdReceiver);\r
+  if (!subtitles) return 0;\r
+\r
+  teletext = new TeletextDecoderVBIEBU();\r
+  \r
+  unsigned int demux_video_size=2097152;\r
+  if (video->supportsh264()) demux_video_size*=5;\r
+\r
+  int text_fak=video->getTeletextBufferFaktor();\r
+\r
\r
+  if (!demuxer->init(this, audio, video, teletext, demux_video_size,524288, 65536*text_fak,25./*unimportant*/,subtitles))\r
+  {\r
+    logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");\r
+    shutdown();\r
+    return 0;\r
+  }\r
+\r
+  vfeed.init();\r
+  afeed.init();\r
+  tfeed.init();\r
+\r
+  video->stop();\r
+  video->blank();\r
+  audio->stop();\r
+\r
+  initted = true;\r
+  return 1;\r
+}\r
+\r
+int PlayerLiveTV::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+  logger->log("PlayerLiveTV", Log::DEBUG, "Shutdown");\r
+  stop();\r
+  initted = false;\r
+\r
+  delete demuxer;\r
+  delete subtitles;\r
+  delete teletext;\r
+  teletext = NULL;\r
+  return 1;\r
+}\r
+\r
+bool* PlayerLiveTV::getDemuxerMpegAudioChannels()\r
+{\r
+  return demuxer->getmpAudioChannels();\r
+}\r
+\r
+bool* PlayerLiveTV::getDemuxerAc3AudioChannels()\r
+{\r
+  return demuxer->getac3AudioChannels();\r
+}\r
+\r
+int PlayerLiveTV::getCurrentAudioChannel()\r
+{\r
+  return demuxer->getAID();\r
+}\r
+\r
+void PlayerLiveTV::setAudioChannel(int newChannel, int type)\r
+{\r
+  demuxer->setAID(newChannel,type);\r
+}\r
+\r
+void PlayerLiveTV::setSubtitleChannel(int newChannel)\r
+{\r
+   demuxer->setSubID(newChannel);\r
+}\r
+\r
+int *PlayerLiveTV::getTeletxtSubtitlePages()\r
+{\r
+    return teletext->getSubtitlePages();\r
+}\r
+\r
+int PlayerLiveTV::getCurrentSubtitleChannel(){\r
+    return demuxer->getSubID();\r
+}\r
+\r
+bool PlayerLiveTV::toggleSubtitles()\r
+{\r
+  if (!subtitlesShowing)\r
+  {\r
+    subtitlesShowing = true;\r
+    subtitles->show();\r
+  }\r
+  else\r
+  {\r
+    subtitlesShowing = false;\r
+    subtitles->hide();\r
+  }\r
+  return subtitlesShowing;\r
+}\r
+\r
+\r
+void  PlayerLiveTV::turnSubtitlesOn(bool ison) {\r
+ if (ison)\r
+  {\r
+    subtitlesShowing = true;\r
+    subtitles->show();\r
+  }\r
+  else\r
+  {\r
+    subtitlesShowing = false;\r
+    subtitles->hide();\r
+  }\r
+\r
+}\r
+// ----------------------------------- Externally called events\r
+\r
+void PlayerLiveTV::go(ULONG index)\r
+{\r
+  struct PLInstruction i;\r
+  i.instruction = I_SETCHANNEL;\r
+  i.channelIndex = index;\r
+  instructions.push(i);\r
+  threadStart();\r
+}\r
+\r
+void PlayerLiveTV::setChannel(ULONG index)\r
+{\r
+  logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");\r
+  struct PLInstruction i;\r
+  i.instruction = I_SETCHANNEL;\r
+  i.channelIndex = index;\r
+  instructions.push(i);  \r
+  threadSignalNoLock();\r
+}\r
+\r
+void PlayerLiveTV::stop()\r
+{\r
+  logger->log("PlayerLiveTV", Log::DEBUG, "stop");\r
+  struct PLInstruction i;\r
+  i.instruction = I_STOP;\r
+  instructions.push(i);\r
+  threadSignal();\r
+  threadStop();\r
+  logger->log("PlayerLiveTV", Log::DEBUG, "stop succesfull");\r
+}\r
+\r
+// ----------------------------------- Callback\r
+\r
+void PlayerLiveTV::call(void* caller)\r
+{\r
+  if (caller == demuxer)\r
+  {\r
+    logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");\r
+\r
+    int dxCurrentAspect = demuxer->getAspectRatio();\r
+    if (dxCurrentAspect == Demuxer::ASPECT_4_3)\r
+    {\r
+      if (video->getTVsize() == Video::ASPECT16X9)\r
+      {\r
+        logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");\r
+        video->setAspectRatio(Video::ASPECT4X3);\r
+      }\r
+      else\r
+      {\r
+        logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");\r
+      }\r
+\r
+      Message* m = new Message();\r
+      m->from = this;\r
+      m->to = messageReceiver;\r
+      m->message = Message::PLAYER_EVENT;\r
+      m->parameter = PlayerLiveTV::ASPECT43;\r
+      messageQueue->postMessageFromOuterSpace(m);\r
+    }\r
+    else if (dxCurrentAspect == Demuxer::ASPECT_16_9)\r
+    {\r
+      if (video->getTVsize() == Video::ASPECT16X9)\r
+      {\r
+        logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");\r
+        video->setAspectRatio(Video::ASPECT16X9);\r
+      }\r
+      else\r
+      {\r
+        logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");\r
+      }    \r
+\r
+      Message* m = new Message();\r
+      m->from = this;\r
+      m->to = messageReceiver;\r
+      m->message = Message::PLAYER_EVENT;\r
+      m->parameter = PlayerLiveTV::ASPECT169;\r
+      messageQueue->postMessageFromOuterSpace(m);\r
+    }\r
+    else\r
+    {\r
+      logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... ignoring");\r
+    }\r
+  }\r
+  else if (caller == &afeed)\r
+  {\r
+    if (state == S_VIDEOSTARTUP)\r
+    {\r
+      logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");\r
+      videoStartup = true;\r
+      threadSignalNoLock();\r
+    }\r
+  }\r
+}\r
+\r
+// -----------------------------------\r
+\r
+void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)\r
+{\r
+  // Flag:\r
+  // 0 = normal stream packet\r
+  // 1 = stream end\r
+  // 2 = connection lost\r
+\r
+  //logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);\r
+\r
+  if (flag == 1)\r
+  {\r
+    if (data) abort();\r
+    \r
+    Message* m = new Message();\r
+    m->from = this;\r
+    m->to = messageReceiver;\r
+    m->message = Message::PLAYER_EVENT;\r
+    m->parameter = PlayerLiveTV::STREAM_END;\r
+    messageQueue->postMessageFromOuterSpace(m);\r
+  }\r
+        \r
+  if (streamChunks.size() < 11)\r
+  {\r
+    StreamChunk s;\r
+    s.data = data;\r
+    s.len = len;\r
+    streamChunks.push(s);\r
+    threadSignalNoLock();\r
+  }\r
+  else\r
+  {\r
+    // Too many chunks in streamChunks, drop this chunk\r
+    free(data);\r
+    logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");\r
+  }\r
+}\r
+\r
+void PlayerLiveTV::clearStreamChunks()\r
+{\r
+  while(streamChunks.size())\r
+  {\r
+    logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");\r
+    struct StreamChunk s = streamChunks.front();\r
+    streamChunks.pop();\r
+    free(s.data);\r
+  }\r
+}\r
+\r
+void PlayerLiveTV::chunkToDemuxer()\r
+{\r
+  StreamChunk s = streamChunks.front();\r
+  streamChunks.pop();\r
+//  logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);\r
+ /* int a =*/ demuxer->put((UCHAR*)s.data, s.len);\r
+//  logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);\r
+  free(s.data);  \r
+  if (pendingAudioPlay && (demuxer->getHorizontalSize()|| !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed\r
+  {\r
+      video->sync();\r
+      video->play();\r
+      video->pause();\r
+      //audio->setStreamType(Audio::MPEG2_PES);\r
+      audio->sync();\r
+      audio->play();\r
+      audio->pause();\r
+      pendingAudioPlay = false;\r
+  }\r
+}\r
+\r
+void PlayerLiveTV::switchState(UCHAR newState)\r
+{\r
+  logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);\r
+\r
+  switch(state)\r
+  {\r
+    case S_STOP:   // FROM S_STOP\r
+    {\r
+      switch(newState)\r
+      {\r
+        case S_VIDEOSTARTUP:\r
+        {\r
+          video->blank();\r
+          video->reset();\r
+          //video->sync();\r
+          //video->play();\r
+          //video->pause();\r
+\r
+          audio->stop();\r
+          audio->unPause();\r
+          audio->reset();\r
+          //audio->setStreamType(Audio::MPEG2_PES);\r
+          //audio->sync();\r
+          // I make this modification, since the video/audio devices needs to know at least\r
+          // which kind of video is embedded inside the stream\r
+          // therefore the demuxer needs to feeded at least with enough data\r
+          // to have one video header\r
+          // This is crucial, if we have mixed h264/mpeg2 channels\r
+          // the information from channels is not enough since some directshow decoders need\r
+          // width and height information before startup\r
+          pendingAudioPlay = true;\r
+\r
+          //audio->play();\r
+          //audio->pause();\r
+\r
+          demuxer->reset();\r
+          demuxer->seek();\r
+\r
+          afeed.start();\r
+          vfeed.start();\r
+          subtitles->start();\r
+          tfeed.start();\r
+          \r
+          state = newState;\r
+          if (!video->independentAVStartUp()){\r
+                 videoStartup = true;\r
+                 threadSignalNoLock();\r
+          }\r
+          return;\r
+        }\r
+        default:\r
+        {\r
+          logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+          abort();\r
+          break;\r
+        }\r
+      }\r
+    }\r
+\r
+    case S_VIDEOSTARTUP:     // FROM S_VIDEOSTARTUP\r
+    {\r
+      switch(newState)\r
+      {\r
+        case S_PREBUFFERING:\r
+        {\r
+          pendingAudioPlay=false;\r
+          vfeed.release();\r
+          state = newState;\r
+          return;\r
+        }\r
+        \r
+        case S_VIDEOSTARTUP:\r
+        {\r
+\r
+          vdr->stopStreaming();\r
+          clearStreamChunks(); \r
+          vfeed.stop();\r
+          afeed.stop();\r
+          subtitles->stop();\r
+          tfeed.stop();\r
+                           \r
+          video->blank();\r
+          video->reset();\r
+          //video->sync();\r
+          //video->play();\r
+          //video->pause();\r
+          audio->stop();\r
+          audio->unPause();\r
+          audio->reset();\r
+          //audio->setStreamType(Audio::MPEG2_PES);\r
+          //audio->sync();\r
+          pendingAudioPlay = true;\r
+          //audio->play();\r
+          //audio->pause();\r
+\r
+          demuxer->reset();\r
+          demuxer->seek();\r
+\r
+          afeed.start();\r
+          vfeed.start();\r
+          subtitles->start();     \r
+          tfeed.start();\r
+          state = newState;\r
+          if (!video->independentAVStartUp()){\r
+              videoStartup = true;\r
+              threadSignalNoLock();\r
+          }\r
+          return;\r
+        }        \r
+        case S_STOP:\r
+        { \r
+          vdr->stopStreaming();\r
+          pendingAudioPlay=false;\r
+          clearStreamChunks();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          subtitles->stop();\r
+          tfeed.stop();\r
+          video->stop();\r
+          video->blank();\r
+          audio->stop();\r
+          audio->reset();\r
+          video->reset();\r
+          state = newState;\r
+          return;\r
+        }\r
+        default:\r
+        {\r
+          logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+          abort();\r
+          break;\r
+        }        \r
+      }\r
+    }\r
+    \r
+    case S_PREBUFFERING:    // FROM S_PREBUFFERING\r
+    {\r
+      switch(newState)\r
+      {\r
+        case S_PLAY:\r
+        {\r
+          pendingAudioPlay=false;\r
+          audio->unPause();\r
+          video->unPause();\r
+          state = newState;\r
+          return;\r
+        }\r
+        case S_VIDEOSTARTUP:\r
+        {\r
+          vdr->stopStreaming();\r
+          clearStreamChunks();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          subtitles->stop();\r
+          tfeed.stop();\r
+          video->stop();\r
+          video->blank();\r
+          audio->stop();\r
+          audio->unPause();\r
+          audio->reset();\r
+\r
+          video->reset();\r
+          //video->sync();\r
+          //video->play();\r
+          //video->pause();\r
+\r
+          //audio->setStreamType(Audio::MPEG2_PES);\r
+          //audio->sync();\r
+          pendingAudioPlay = true;\r
+          //audio->play();\r
+          //audio->pause();\r
+\r
+          demuxer->reset();\r
+          demuxer->seek();\r
+\r
+          afeed.start();\r
+          vfeed.start();\r
+          subtitles->start();\r
+          tfeed.start();\r
+\r
+          state = newState;\r
+          return;\r
+        }\r
+        case S_STOP:\r
+        {\r
+          pendingAudioPlay=false;\r
+          vdr->stopStreaming();\r
+          clearStreamChunks();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          subtitles->stop();\r
+          tfeed.stop();\r
+          video->stop();\r
+          video->blank();\r
+          audio->stop();\r
+          audio->reset();\r
+          video->reset();\r
+          state = newState;\r
+          return;        \r
+        }\r
+        default:\r
+        {\r
+          logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+          abort();\r
+          break;\r
+        }        \r
+      }\r
+    }\r
+    \r
+    case S_PLAY:     // FROM S_PLAY\r
+    {\r
+      switch(newState)\r
+      {\r
+        case S_STOP:\r
+        { \r
+          pendingAudioPlay=false;\r
+          vdr->stopStreaming();\r
+          clearStreamChunks();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          subtitles->stop();\r
+          tfeed.stop();\r
+          video->stop();\r
+          video->blank();\r
+          audio->stop();\r
+          audio->reset();\r
+          video->reset();\r
+          state = newState;\r
+          return;\r
+        }\r
+        case S_VIDEOSTARTUP:\r
+        {\r
+          vdr->stopStreaming();\r
+          clearStreamChunks();\r
+          vfeed.stop();\r
+          afeed.stop();\r
+          subtitles->stop();\r
+          tfeed.stop();\r
+          video->stop();\r
+          video->blank();\r
+          audio->stop();\r
+          audio->unPause();\r
+          audio->reset();\r
+\r
+          video->reset();\r
+          \r
+          //video->sync();\r
+         // video->play();\r
+          //video->pause();\r
+\r
+          //audio->setStreamType(Audio::MPEG2_PES);\r
+          //audio->sync();\r
+          //audio->play();\r
+          //audio->pause();\r
+          pendingAudioPlay = true;\r
+          demuxer->reset();\r
+          demuxer->seek();\r
+\r
+          afeed.start();\r
+          vfeed.start();\r
+          subtitles->start();\r
+          tfeed.start();\r
+          state = newState;\r
+          if (!video->independentAVStartUp()){\r
+                 videoStartup = true;\r
+              threadSignalNoLock();\r
+          }\r
+          return;\r
+        }\r
+        default:\r
+        {\r
+          logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);\r
+          abort();\r
+          break;\r
+        }        \r
+      }\r
+    }    \r
+  }  \r
+}\r
+\r
+bool PlayerLiveTV::checkError()\r
+{\r
+  if (!vdr->isConnected())\r
+  {\r
+    if (state != S_STOP) switchState(S_STOP);\r
+    \r
+    Message* m = new Message();\r
+    m->from = this;\r
+    m->to = messageReceiver;\r
+    m->message = Message::PLAYER_EVENT;\r
+    m->parameter = PlayerLiveTV::CONNECTION_LOST;\r
+    messageQueue->postMessageFromOuterSpace(m);\r
+    \r
+    return true;\r
+  }   \r
+  return false;\r
+}\r
+\r
+void PlayerLiveTV::optimizeInstructionQueue()\r
+{\r
+  // Walk the list\r
+  \r
+  // Currently there are only 2 instruction types, so this is a bit overkill...\r
+\r
+  struct PLInstruction i;\r
+  while(instructions.size() > 1)\r
+  {\r
+    i = instructions.front();\r
+    if (i.instruction == I_SETCHANNEL)\r
+    {\r
+      instructions.pop();  // if this is the first of more than 1 command, currently it cannot possibly be relevant\r
+    }\r
+    else if (i.instruction == I_STOP)\r
+    {\r
+      return; // return here and ensure the next instruction will be stop\r
+    }\r
+  }\r
+}\r
+\r
+void PlayerLiveTV::threadMethod()\r
+{\r
+  while(1)\r
+  {\r
+\r
+//     logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);\r
+    if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data\r
+    {\r
+          logger->log("PlayerLiveTV", Log::DEBUG, "Enter prebuffering");\r
+      switchState(S_PREBUFFERING);\r
+      videoStartup = false;\r
+      preBufferCount = 0;\r
+      \r
+      checkError();\r
+    }  \r
+  \r
+    while(!instructions.empty())\r
+    {\r
+      if (instructions.size() > 1) optimizeInstructionQueue();\r
+\r
+      struct PLInstruction i = instructions.front();\r
+      instructions.pop();\r
+    \r
+      if (i.instruction == I_SETCHANNEL)\r
+      {\r
+        logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");\r
+       \r
+        \r
+        switchState(S_VIDEOSTARTUP);\r
+        \r
+        if (!checkError())\r
+        {\r
+           Channel* chan = (*chanList)[i.channelIndex];\r
+           chan->loadPids();\r
+           h264=chan->vstreamtype==0x1b;\r
+           demuxer->seth264(h264);\r
+           video->seth264mode(chan->vstreamtype==0x1b);\r
+           demuxer->setVID(chan->vpid);\r
+           video->seth264mode(chan->vstreamtype==0x1b);\r
+\r
+          if (chan->numAPids > 0) \r
+          {\r
+            demuxer->setAID(chan->apids[0].pid,0);\r
+            audio->setStreamType(Audio::MPEG2_PES);\r
+            logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);\r
+          }\r
+          else \r
+          {\r
+              if (chan->numDPids > 0  && audio->maysupportAc3()) \r
+              {\r
+                  demuxer->setAID(chan->dpids[0].pid,1);\r
+                  logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3)", chan->vpid, chan->dpids[0].pid);\r
+              } \r
+              else\r
+              {\r
+                  logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);\r
+              }\r
+          }\r
+          if (chan->numSPids > 0)\r
+            demuxer->setSubID(chan->spids[0].pid);\r
+          demuxer->setTID(chan->tpid);\r
+          teletext->ResetDecoder();\r
+          int streamSuccess = vdr->streamChannel(chan->number, this);\r
+          if (!checkError() && !streamSuccess)\r
+          {      \r
+            Message* m = new Message();\r
+            m->from = this;\r
+            m->to = messageReceiver;\r
+            m->message = Message::PLAYER_EVENT;\r
+            m->parameter = PlayerLiveTV::STREAM_END;\r
+            messageQueue->postMessageFromOuterSpace(m);\r
+          }\r
+        }\r
+      }\r
+      else if (i.instruction == I_STOP)\r
+      {\r
+        logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");\r
+        switchState(S_STOP);\r
+        checkError();\r
+\r
+        stopNow = true;\r
+        break;\r
+      }\r
+    }\r
+\r
+       threadCheckExit();\r
+\r
+    if (stopNow) break;\r
+\r
+    while(streamChunks.size())\r
+    {\r
+      chunkToDemuxer();\r
+\r
+      if (state == S_PREBUFFERING)\r
+      {\r
+        ++preBufferCount;\r
+        ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);\r
+        logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone);\r
+        \r
+        Message* m = new Message();\r
+        m->from = this;\r
+        m->to = messageReceiver;\r
+        m->message = Message::PLAYER_EVENT;\r
+        m->parameter = PlayerLiveTV::PREBUFFERING;\r
+        m->tag = percentDone;\r
+        messageQueue->postMessageFromOuterSpace(m);\r
+\r
+        if (preBufferCount == preBufferAmount)\r
+        {\r
+          switchState(S_PLAY);\r
+          checkError();\r
+        }\r
+      }\r
+    }\r
+    threadLock();\r
+    threadWaitForSignal(); // unlocks and waits for signal\r
+    threadUnlock();\r
+  }\r
+\r
+  logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");\r
+}\r
+\r
index cdb10e31e8ae224e1495661e4ee1f0747c1e3689..1b8e8bac3953905a113990b2db3080d9d502b38e 100644 (file)
-/*
-    Copyright 2004-2006 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "playerradio.h"
-
-#include "log.h"
-#include "audio.h"
-#include "video.h"
-#include "demuxervdr.h"
-#include "demuxerts.h"
-#include "remote.h"
-#include "vdr.h"
-#include "message.h"
-#include "messagequeue.h"
-
-// ----------------------------------- Called from outside, one offs or info funcs
-
-PlayerRadio::PlayerRadio(MessageQueue* tmessageQueue, void* tmessageReceiver)
-: afeed(this)
-{
-  messageQueue = tmessageQueue;
-  messageReceiver = tmessageReceiver;
-  audio = Audio::getInstance();
-  logger = Log::getInstance();
-  vdr = VDR::getInstance();
-  initted = false;
-  lengthBytes = 0;
-  lengthPackets = 0;
-  streamPos = 0;
-  state = S_STOP;
-
-  startPTS = 0;
-  lengthSeconds = 0;
-
-  threadBuffer = NULL;
-
-  blockSize = 10000;
-  startupBlockSize = 20000;
-
-  Video::getInstance()->turnVideoOff();
-}
-
-PlayerRadio::~PlayerRadio()
-{
-  if (initted) shutdown();
-}
-
-int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets, bool isPesRecording)
-{
-  if (initted) return 0;
-#ifndef WIN32
-  pthread_mutex_init(&mutex, NULL);
-#else
-  mutex=CreateMutex(NULL,FALSE,NULL);
-#endif
-
-  if (isPesRecording)
-    demuxer = new DemuxerVDR();
-  else
-    demuxer = new DemuxerTS();
-  if (!demuxer) return 0;
-
-  if (!demuxer->init(this, audio, NULL, NULL, 0, 40000, 0))
-  {
-    logger->log("PlayerRadio", Log::ERR, "Demuxer failed to init");
-    shutdown();
-    return 0;
-  }
-
-  afeed.init();
-  audio->stop();
-
-  lengthBytes = tlengthBytes;
-  lengthPackets = tlengthPackets;
-
-  logger->log("PlayerRadio", Log::DEBUG, "PlayerRadio has received length bytes of %llu", lengthBytes);
-
-  UINT thisRead = 0;
-  int success;
-
-  UCHAR* buffer = vdr->getBlock(0, 10000, &thisRead);
-  if (!buffer)
-  {
-    logger->log("PlayerRadio", Log::ERR, "Failed to get start block");
-    shutdown();
-    if (!vdr->isConnected()) doConnectionLost();
-    return 0;
-  }
-
-  success = demuxer->findPTS(buffer, thisRead, &startPTS);
-  if (!success)
-  {
-    logger->log("PlayerRadio", Log::ERR, "Failed to get start PTS");
-    free(buffer);
-    shutdown();
-    return 0;
-  }
-
-  free(buffer);
-
-  if (!setLengthSeconds())
-  {
-    logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds");
-    shutdown();
-    return 0;
-  }
-
-  initted = true;
-  return 1;
-}
-
-bool PlayerRadio::setLengthSeconds()
-{
-  int success;
-  ULLONG endPTS = 0;
-  UINT thisRead = 0;
-  UCHAR* buffer = vdr->getBlock(lengthBytes - 10000, 10000, &thisRead);
-  if (!buffer)
-  {
-    logger->log("PlayerRadio", Log::ERR, "Failed to get end block");
-    if (!vdr->isConnected()) doConnectionLost();    
-    return false;
-  }
-
-  success = demuxer->findPTS(buffer, thisRead, &endPTS);
-  free(buffer);
-  if (!success)
-  {
-    logger->log("PlayerRadio", Log::ERR, "Failed to get end PTS");
-    return false;
-  }
-
-  if (startPTS < endPTS)
-  {
-    lengthSeconds = (endPTS - startPTS) / 90000;
-  }
-  else
-  {
-    lengthSeconds = (startPTS - endPTS) / 90000;
-  }
-
-  return true;
-}
-
-int PlayerRadio::shutdown()
-{
-  if (!initted) return 0;
-  switchState(S_STOP);
-  initted = false;
-
-  delete demuxer;
-  demuxer = NULL;
-
-#ifdef WIN32
-  CloseHandle(mutex);
-#endif
-
-  return 1;
-}
-
-
-void PlayerRadio::setStartBytes(ULLONG startBytes)
-{
-  streamPos = startBytes;
-}
-
-ULONG PlayerRadio::getLengthSeconds()
-{
-  return lengthSeconds;
-}
-
-ULONG PlayerRadio::getCurrentSeconds()
-{
-  if (startup) return 0;
-
-  long long currentPTS = demuxer->getAudioPTS();
-  currentPTS -= startPTS;
-  if (currentPTS < 0) currentPTS += 8589934592ULL;
-  ULONG ret = currentPTS / 90000;
-  return ret;
-}
-
-// ----------------------------------- Externally called events
-
-void PlayerRadio::play()
-{
-  if (!initted) return;
-  if (state == S_PLAY) return;
-  lock();
-  switchState(S_PLAY);
-  unLock();
-}
-
-void PlayerRadio::stop()
-{
-  if (!initted) return;
-  if (state == S_STOP) return;
-  lock();
-  logger->log("PlayerRadio", Log::DEBUG, "Stop called lock");
-  switchState(S_STOP);
-  unLock();
-}
-
-void PlayerRadio::pause()
-{
-  if (!initted) return;
-  lock();
-
-  if (state == S_PAUSE_P)
-  {
-    switchState(S_PLAY);
-  }
-  else
-  {
-    switchState(S_PAUSE_P);
-  }
-
-  unLock();
-}
-
-void PlayerRadio::jumpToPercent(double percent)
-{
-  lock();
-  logger->log("PlayerRadio", Log::DEBUG, "JUMP TO %i%%", percent);
-  ULONG newPacket = (ULONG)(percent * lengthPackets / 100);
-  switchState(S_JUMP, newPacket);
-  unLock();
-}
-
-void PlayerRadio::skipForward(UINT seconds)
-{
-  lock();
-  logger->log("PlayerRadio", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
-  ULONG currentSeconds = getCurrentSeconds();
-  ULONG currentPacket = demuxer->getPacketNum();
-
-  if (currentSeconds == 0) { unLock(); return; } // div by zero
-  if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid
-
-  ULONG newPacket = currentPacket + (currentPacket * seconds / currentSeconds);
-  if (newPacket > lengthPackets) { switchState(S_PLAY); unLock(); }
-  else switchState(S_JUMP, newPacket);
-  unLock();
-}
-
-void PlayerRadio::skipBackward(UINT seconds)
-{
-  lock();
-  logger->log("PlayerRadio", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
-
-  ULONG currentSeconds = getCurrentSeconds();
-  ULONG currentPacket = demuxer->getPacketNum();
-
-  if (currentSeconds == 0) { unLock(); return; } // div by zero
-  if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid
-
-  ULONG newPacket;
-  if ((UINT)seconds > currentSeconds)
-    newPacket = 0;
-  else
-    newPacket = currentPacket - (currentPacket * seconds / currentSeconds);
-
-  switchState(S_JUMP, newPacket);
-  unLock();
-}
-
-// ----------------------------------- Implementations called events
-
-void PlayerRadio::switchState(UCHAR toState, ULONG jumpPacket)
-{
-  if (!initted) return;
-
-  logger->log("PlayerRadio", Log::DEBUG, "Switch state from %u to %u", state, toState);
-
-  switch(state) // current state selector
-  {
-    case S_PLAY: // from S_PLAY -----------------------------------
-    {
-      switch(toState)
-      {
-        case S_PLAY: // to S_PLAY
-        {
-          return;
-        }
-        case S_PAUSE_P: // to S_PAUSE_P
-        {
-          audio->pause();
-          state = S_PAUSE_P;
-          return;
-        }
-        case S_STOP: // to S_STOP
-        {
-          afeed.stop();
-          threadStop();
-          audio->stop();
-          audio->unPause();
-          demuxer->reset();
-          state = S_STOP;
-          return;
-        }
-        case S_JUMP: // to S_JUMP
-        {
-          restartAtPacket(jumpPacket);
-          return;
-        }
-      }
-    }
-    case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
-    {
-      switch(toState)
-      {
-        case S_PLAY: // to S_PLAY
-        {
-          audio->unPause();
-          state = S_PLAY;
-          return;
-        }
-        case S_PAUSE_P: // to S_PAUSE_P
-        {
-          return;
-        }
-        case S_STOP: // to S_STOP
-        {
-          afeed.stop();
-          threadStop();
-          audio->stop();
-          audio->unPause();
-          demuxer->reset();
-          audio->systemMuteOff();
-          state = S_STOP;
-          return;
-        }
-        case S_JUMP: // to S_JUMP
-        {
-          state = S_PLAY;
-          audio->unPause();
-          restartAtPacket(jumpPacket);
-          return;
-        }
-      }
-    }
-    case S_STOP: // from S_STOP -----------------------------------
-    {
-      switch(toState)
-      {
-        case S_PLAY: // to S_PLAY
-        {
-          startup = true;
-
-          audio->reset();
-                                       audio->setStreamType(Audio::MPEG2_PES);
-          audio->systemMuteOff();
-          demuxer->reset();
-
-          // FIXME use restartAtPacket here?
-          if (currentPacketNumber > lengthPackets) currentPacketNumber = 0;
-          demuxer->setPacketNum(currentPacketNumber);
-          state = S_PLAY;
-          threadStart();
-          logger->log("PlayerRadio", Log::DEBUG, "Immediate play");
-          afeed.start();
-          audio->play();
-
-          return;
-        }
-        case S_PAUSE_P: // to S_PAUSE_P
-        {
-          return;
-        }
-        case S_STOP: // to S_STOP
-        {
-          return;
-        }
-        case S_JUMP: // to S_JUMP
-        {
-          return;
-        }
-      }
-    }
-    // case S_JUMP cannot be selected as a start state because it auto flips to play
-  }
-}
-
-// ----------------------------------- Internal functions
-
-void PlayerRadio::lock()
-{
-#ifndef WIN32
-  pthread_mutex_lock(&mutex);
-  logger->log("PlayerRadio", Log::DEBUG, "LOCKED");
-
-#else
-   WaitForSingleObject(mutex, INFINITE);
-#endif
-}
-
-void PlayerRadio::unLock()
-{
-#ifndef WIN32
-  logger->log("PlayerRadio", Log::DEBUG, "UNLOCKING");
-  pthread_mutex_unlock(&mutex);
-#else
-   ReleaseMutex(mutex);
-#endif
-}
-
-void PlayerRadio::restartAtPacket(ULONG newPacket)
-{
-  afeed.stop();
-  threadStop();
-  audio->reset();
-       audio->setStreamType(Audio::MPEG2_PES);
-  demuxer->flush();
-  currentPacketNumber = newPacket;
-  demuxer->setPacketNum(newPacket);
-  afeed.start();
-  threadStart();
-  audio->play();
-  audio->systemMuteOff();
-  audio->doMuting();
-}
-
-void PlayerRadio::doConnectionLost()
-{
-  logger->log("PlayerRadio", Log::DEBUG, "Connection lost, sending message");
-  Message* m = new Message();
-  m->to = messageReceiver;
-  m->from = this;
-  m->message = Message::PLAYER_EVENT;
-  m->parameter = PlayerRadio::CONNECTION_LOST;
-  messageQueue->postMessage(m);
-}
-
-// ----------------------------------- Callback
-
-void PlayerRadio::call(void* caller)
-{
-  threadSignalNoLock();
-}
-
-// ----------------------------------- Feed thread
-
-void PlayerRadio::threadMethod()
-{
-  if (state == S_PLAY) threadFeedPlay();
-}
-
-void PlayerRadio::threadFeedPlay()
-{
-  ULLONG feedPosition;
-  UINT thisRead, writeLength, thisWrite, askFor;
-  time_t lastRescan = time(NULL);
-
-  feedPosition = vdr->positionFromFrameNumber(currentPacketNumber);
-  if (!vdr->isConnected()) { doConnectionLost(); return; }
-  logger->log("PlayerRadio", Log::DEBUG, "startFeedPlay: wantedPacket %i goto %llu", currentPacketNumber, feedPosition);
-
-
-  while(1)
-  {
-    thisRead = 0;
-    writeLength = 0;
-    thisWrite = 0;
-
-    threadCheckExit();
-
-    // If we havn't rescanned for a while..
-    if ((lastRescan + 60) < time(NULL))
-    {
-      lengthBytes = vdr->rescanRecording(&lengthPackets);
-      if (!vdr->isConnected()) { doConnectionLost(); return; }
-      logger->log("PlayerRadio", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
-      lastRescan = time(NULL);
-
-      if (!setLengthSeconds())
-      {
-        logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds in thread");
-        return;
-      }
-    }
-
-    if (feedPosition >= lengthBytes) break;  // finished playback
-
-    if (startup)
-    {
-      if (startupBlockSize > lengthBytes)
-        askFor = lengthBytes; // is a very small recording!
-      else
-        askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
-    }
-    else
-    {
-      if ((feedPosition + blockSize) > lengthBytes) // last block of recording
-        askFor = lengthBytes - feedPosition;
-      else // normal
-        askFor = blockSize;
-    }
-
-    threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
-    feedPosition += thisRead;
-
-    if (!vdr->isConnected())
-    {
-      doConnectionLost();
-      return;
-    }
-
-    if (!threadBuffer) break;
-
-    if (startup)
-    {
-      int a_stream = demuxer->scan(threadBuffer, thisRead);
-      demuxer->setAudioStream(a_stream);
-      logger->log("PlayerRadio", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
-      startup = false;
-    }
-
-    threadCheckExit();
-
-    while(writeLength < thisRead)
-    {
-      thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
-      writeLength += thisWrite;
-
-      if (!thisWrite)
-      {
-        // demuxer is full and can't take anymore
-        threadLock();
-        threadWaitForSignal();
-        threadUnlock();
-      }
-
-      threadCheckExit();
-    }
-
-    free(threadBuffer);
-    threadBuffer = NULL;
-
-  }
-
-  // end of recording
-  logger->log("PlayerRadio", Log::DEBUG, "Recording playback ends");
-
-  threadCheckExit();
-
-
-  Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
-  m->to = messageReceiver;
-  m->from = this;
-  m->message = Message::PLAYER_EVENT;
-  m->parameter = PlayerRadio::STOP_PLAYBACK;
-  logger->log("PlayerRadio", Log::DEBUG, "Posting message to %p...", messageQueue);
-  messageQueue->postMessage(m);
-}
-
-void PlayerRadio::threadPostStopCleanup()
-{
-  if (threadBuffer)
-  {
-    free(threadBuffer);
-    threadBuffer = NULL;
-  }
-}
-
+/*\r
+    Copyright 2004-2006 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "playerradio.h"\r
+\r
+#include "log.h"\r
+#include "audio.h"\r
+#include "video.h"\r
+#include "demuxervdr.h"\r
+#include "demuxerts.h"\r
+#include "remote.h"\r
+#include "vdr.h"\r
+#include "message.h"\r
+#include "messagequeue.h"\r
+\r
+// ----------------------------------- Called from outside, one offs or info funcs\r
+\r
+PlayerRadio::PlayerRadio(MessageQueue* tmessageQueue, void* tmessageReceiver)\r
+: afeed(this)\r
+{\r
+  messageQueue = tmessageQueue;\r
+  messageReceiver = tmessageReceiver;\r
+  audio = Audio::getInstance();\r
+  logger = Log::getInstance();\r
+  vdr = VDR::getInstance();\r
+  initted = false;\r
+  lengthBytes = 0;\r
+  lengthPackets = 0;\r
+  streamPos = 0;\r
+  state = S_STOP;\r
+\r
+  startPTS = 0;\r
+  lengthSeconds = 0;\r
+\r
+  threadBuffer = NULL;\r
+\r
+  blockSize = 10000;\r
+  startupBlockSize = 20000;\r
+\r
+  Video::getInstance()->turnVideoOff();\r
+}\r
+\r
+PlayerRadio::~PlayerRadio()\r
+{\r
+  if (initted) shutdown();\r
+}\r
+\r
+int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets, bool isPesRecording)\r
+{\r
+  if (initted) return 0;\r
+#ifndef WIN32\r
+  pthread_mutex_init(&mutex, NULL);\r
+#else\r
+  mutex=CreateMutex(NULL,FALSE,NULL);\r
+#endif\r
+\r
+  if (isPesRecording)\r
+    demuxer = new DemuxerVDR();\r
+  else\r
+    demuxer = new DemuxerTS();\r
+  if (!demuxer) return 0;\r
+\r
+  if (!demuxer->init(this, audio, NULL, NULL, 0, 40000, 0))\r
+  {\r
+    logger->log("PlayerRadio", Log::ERR, "Demuxer failed to init");\r
+    shutdown();\r
+    return 0;\r
+  }\r
+\r
+  afeed.init();\r
+  audio->stop();\r
+\r
+  lengthBytes = tlengthBytes;\r
+  lengthPackets = tlengthPackets;\r
+\r
+  logger->log("PlayerRadio", Log::DEBUG, "PlayerRadio has received length bytes of %llu", lengthBytes);\r
+\r
+  UINT thisRead = 0;\r
+  int success;\r
+\r
+  UCHAR* buffer = vdr->getBlock(0, 10000, &thisRead);\r
+  if (!buffer)\r
+  {\r
+    logger->log("PlayerRadio", Log::ERR, "Failed to get start block");\r
+    shutdown();\r
+    if (!vdr->isConnected()) doConnectionLost();\r
+    return 0;\r
+  }\r
+\r
+  success = demuxer->findPTS(buffer, thisRead, &startPTS);\r
+  if (!success)\r
+  {\r
+    logger->log("PlayerRadio", Log::ERR, "Failed to get start PTS");\r
+    free(buffer);\r
+    shutdown();\r
+    return 0;\r
+  }\r
+\r
+  free(buffer);\r
+\r
+  if (!setLengthSeconds())\r
+  {\r
+    logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds");\r
+    shutdown();\r
+    return 0;\r
+  }\r
+\r
+  initted = true;\r
+  return 1;\r
+}\r
+\r
+bool PlayerRadio::setLengthSeconds()\r
+{\r
+  int success;\r
+  ULLONG endPTS = 0;\r
+  UINT thisRead = 0;\r
+  UCHAR* buffer = vdr->getBlock(lengthBytes - 10000, 10000, &thisRead);\r
+  if (!buffer)\r
+  {\r
+    logger->log("PlayerRadio", Log::ERR, "Failed to get end block");\r
+    if (!vdr->isConnected()) doConnectionLost();    \r
+    return false;\r
+  }\r
+\r
+  success = demuxer->findPTS(buffer, thisRead, &endPTS);\r
+  free(buffer);\r
+  if (!success)\r
+  {\r
+    logger->log("PlayerRadio", Log::ERR, "Failed to get end PTS");\r
+    return false;\r
+  }\r
+\r
+  if (startPTS < endPTS)\r
+  {\r
+    lengthSeconds = (endPTS - startPTS) / 90000;\r
+  }\r
+  else\r
+  {\r
+    lengthSeconds = (startPTS - endPTS) / 90000;\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+int PlayerRadio::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+  switchState(S_STOP);\r
+  initted = false;\r
+\r
+  delete demuxer;\r
+  demuxer = NULL;\r
+\r
+#ifdef WIN32\r
+  CloseHandle(mutex);\r
+#endif\r
+\r
+  return 1;\r
+}\r
+\r
+\r
+void PlayerRadio::setStartBytes(ULLONG startBytes)\r
+{\r
+  streamPos = startBytes;\r
+}\r
+\r
+ULONG PlayerRadio::getLengthSeconds()\r
+{\r
+  return lengthSeconds;\r
+}\r
+\r
+ULONG PlayerRadio::getCurrentSeconds()\r
+{\r
+  if (startup) return 0;\r
+\r
+  long long currentPTS = demuxer->getAudioPTS();\r
+  currentPTS -= startPTS;\r
+  if (currentPTS < 0) currentPTS += 8589934592ULL;\r
+  ULONG ret = currentPTS / 90000;\r
+  return ret;\r
+}\r
+\r
+// ----------------------------------- Externally called events\r
+\r
+void PlayerRadio::play()\r
+{\r
+  if (!initted) return;\r
+  if (state == S_PLAY) return;\r
+  lock();\r
+  switchState(S_PLAY);\r
+  unLock();\r
+}\r
+\r
+\r
+void PlayerRadio::playpause()\r
+{\r
+  if (!initted) return;\r
+  lock();\r
+  if (state==S_PLAY) {\r
+         switchState(S_PAUSE_P);\r
+  } else {\r
+         switchState(S_PLAY);\r
+  }\r
+  unLock();\r
+}\r
+\r
+void PlayerRadio::stop()\r
+{\r
+  if (!initted) return;\r
+  if (state == S_STOP) return;\r
+  lock();\r
+  logger->log("PlayerRadio", Log::DEBUG, "Stop called lock");\r
+  switchState(S_STOP);\r
+  unLock();\r
+}\r
+\r
+void PlayerRadio::pause()\r
+{\r
+  if (!initted) return;\r
+  lock();\r
+\r
+  if (state == S_PAUSE_P)\r
+  {\r
+    switchState(S_PLAY);\r
+  }\r
+  else\r
+  {\r
+    switchState(S_PAUSE_P);\r
+  }\r
+\r
+  unLock();\r
+}\r
+\r
+void PlayerRadio::jumpToPercent(double percent)\r
+{\r
+  lock();\r
+  logger->log("PlayerRadio", Log::DEBUG, "JUMP TO %i%%", percent);\r
+  ULONG newPacket = (ULONG)(percent * lengthPackets / 100);\r
+  switchState(S_JUMP, newPacket);\r
+  unLock();\r
+}\r
+\r
+void PlayerRadio::skipForward(UINT seconds)\r
+{\r
+  lock();\r
+  logger->log("PlayerRadio", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);\r
+  ULONG currentSeconds = getCurrentSeconds();\r
+  ULONG currentPacket = demuxer->getPacketNum();\r
+\r
+  if (currentSeconds == 0) { unLock(); return; } // div by zero\r
+  if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid\r
+\r
+  ULONG newPacket = currentPacket + (currentPacket * seconds / currentSeconds);\r
+  if (newPacket > lengthPackets) { switchState(S_PLAY); unLock(); }\r
+  else switchState(S_JUMP, newPacket);\r
+  unLock();\r
+}\r
+\r
+void PlayerRadio::skipBackward(UINT seconds)\r
+{\r
+  lock();\r
+  logger->log("PlayerRadio", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);\r
+\r
+  ULONG currentSeconds = getCurrentSeconds();\r
+  ULONG currentPacket = demuxer->getPacketNum();\r
+\r
+  if (currentSeconds == 0) { unLock(); return; } // div by zero\r
+  if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid\r
+\r
+  ULONG newPacket;\r
+  if ((UINT)seconds > currentSeconds)\r
+    newPacket = 0;\r
+  else\r
+    newPacket = currentPacket - (currentPacket * seconds / currentSeconds);\r
+\r
+  switchState(S_JUMP, newPacket);\r
+  unLock();\r
+}\r
+\r
+// ----------------------------------- Implementations called events\r
+\r
+void PlayerRadio::switchState(UCHAR toState, ULONG jumpPacket)\r
+{\r
+  if (!initted) return;\r
+\r
+  logger->log("PlayerRadio", Log::DEBUG, "Switch state from %u to %u", state, toState);\r
+\r
+  switch(state) // current state selector\r
+  {\r
+    case S_PLAY: // from S_PLAY -----------------------------------\r
+    {\r
+      switch(toState)\r
+      {\r
+        case S_PLAY: // to S_PLAY\r
+        {\r
+          return;\r
+        }\r
+        case S_PAUSE_P: // to S_PAUSE_P\r
+        {\r
+          audio->pause();\r
+          state = S_PAUSE_P;\r
+          return;\r
+        }\r
+        case S_STOP: // to S_STOP\r
+        {\r
+          afeed.stop();\r
+          threadStop();\r
+          audio->stop();\r
+          audio->unPause();\r
+          demuxer->reset();\r
+          state = S_STOP;\r
+          return;\r
+        }\r
+        case S_JUMP: // to S_JUMP\r
+        {\r
+          restartAtPacket(jumpPacket);\r
+          return;\r
+        }\r
+      }\r
+    }\r
+    case S_PAUSE_P: // from S_PAUSE_P -----------------------------------\r
+    {\r
+      switch(toState)\r
+      {\r
+        case S_PLAY: // to S_PLAY\r
+        {\r
+          audio->unPause();\r
+          state = S_PLAY;\r
+          return;\r
+        }\r
+        case S_PAUSE_P: // to S_PAUSE_P\r
+        {\r
+          return;\r
+        }\r
+        case S_STOP: // to S_STOP\r
+        {\r
+          afeed.stop();\r
+          threadStop();\r
+          audio->stop();\r
+          audio->unPause();\r
+          demuxer->reset();\r
+          audio->systemMuteOff();\r
+          state = S_STOP;\r
+          return;\r
+        }\r
+        case S_JUMP: // to S_JUMP\r
+        {\r
+          state = S_PLAY;\r
+          audio->unPause();\r
+          restartAtPacket(jumpPacket);\r
+          return;\r
+        }\r
+      }\r
+    }\r
+    case S_STOP: // from S_STOP -----------------------------------\r
+    {\r
+      switch(toState)\r
+      {\r
+        case S_PLAY: // to S_PLAY\r
+        {\r
+          startup = true;\r
+\r
+          audio->reset();\r
+                                       audio->setStreamType(Audio::MPEG2_PES);\r
+          audio->systemMuteOff();\r
+          demuxer->reset();\r
+\r
+          // FIXME use restartAtPacket here?\r
+          if (currentPacketNumber > lengthPackets) currentPacketNumber = 0;\r
+          demuxer->setPacketNum(currentPacketNumber);\r
+          state = S_PLAY;\r
+          threadStart();\r
+          logger->log("PlayerRadio", Log::DEBUG, "Immediate play");\r
+          afeed.start();\r
+          audio->play();\r
+\r
+          return;\r
+        }\r
+        case S_PAUSE_P: // to S_PAUSE_P\r
+        {\r
+          return;\r
+        }\r
+        case S_STOP: // to S_STOP\r
+        {\r
+          return;\r
+        }\r
+        case S_JUMP: // to S_JUMP\r
+        {\r
+          return;\r
+        }\r
+      }\r
+    }\r
+    // case S_JUMP cannot be selected as a start state because it auto flips to play\r
+  }\r
+}\r
+\r
+// ----------------------------------- Internal functions\r
+\r
+void PlayerRadio::lock()\r
+{\r
+#ifndef WIN32\r
+  pthread_mutex_lock(&mutex);\r
+  logger->log("PlayerRadio", Log::DEBUG, "LOCKED");\r
+\r
+#else\r
+   WaitForSingleObject(mutex, INFINITE);\r
+#endif\r
+}\r
+\r
+void PlayerRadio::unLock()\r
+{\r
+#ifndef WIN32\r
+  logger->log("PlayerRadio", Log::DEBUG, "UNLOCKING");\r
+  pthread_mutex_unlock(&mutex);\r
+#else\r
+   ReleaseMutex(mutex);\r
+#endif\r
+}\r
+\r
+void PlayerRadio::restartAtPacket(ULONG newPacket)\r
+{\r
+  afeed.stop();\r
+  threadStop();\r
+  audio->reset();\r
+       audio->setStreamType(Audio::MPEG2_PES);\r
+  demuxer->flush();\r
+  currentPacketNumber = newPacket;\r
+  demuxer->setPacketNum(newPacket);\r
+  afeed.start();\r
+  threadStart();\r
+  audio->play();\r
+  audio->systemMuteOff();\r
+  audio->doMuting();\r
+}\r
+\r
+void PlayerRadio::doConnectionLost()\r
+{\r
+  logger->log("PlayerRadio", Log::DEBUG, "Connection lost, sending message");\r
+  Message* m = new Message();\r
+  m->to = messageReceiver;\r
+  m->from = this;\r
+  m->message = Message::PLAYER_EVENT;\r
+  m->parameter = PlayerRadio::CONNECTION_LOST;\r
+  messageQueue->postMessage(m);\r
+}\r
+\r
+// ----------------------------------- Callback\r
+\r
+void PlayerRadio::call(void* caller)\r
+{\r
+  threadSignalNoLock();\r
+}\r
+\r
+// ----------------------------------- Feed thread\r
+\r
+void PlayerRadio::threadMethod()\r
+{\r
+  if (state == S_PLAY) threadFeedPlay();\r
+}\r
+\r
+void PlayerRadio::threadFeedPlay()\r
+{\r
+  ULLONG feedPosition;\r
+  UINT thisRead, writeLength, thisWrite, askFor;\r
+  time_t lastRescan = time(NULL);\r
+\r
+  feedPosition = vdr->positionFromFrameNumber(currentPacketNumber);\r
+  if (!vdr->isConnected()) { doConnectionLost(); return; }\r
+  logger->log("PlayerRadio", Log::DEBUG, "startFeedPlay: wantedPacket %i goto %llu", currentPacketNumber, feedPosition);\r
+\r
+\r
+  while(1)\r
+  {\r
+    thisRead = 0;\r
+    writeLength = 0;\r
+    thisWrite = 0;\r
+\r
+    threadCheckExit();\r
+\r
+    // If we havn't rescanned for a while..\r
+    if ((lastRescan + 60) < time(NULL))\r
+    {\r
+      lengthBytes = vdr->rescanRecording(&lengthPackets);\r
+      if (!vdr->isConnected()) { doConnectionLost(); return; }\r
+      logger->log("PlayerRadio", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);\r
+      lastRescan = time(NULL);\r
+\r
+      if (!setLengthSeconds())\r
+      {\r
+        logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds in thread");\r
+        return;\r
+      }\r
+    }\r
+\r
+    if (feedPosition >= lengthBytes) break;  // finished playback\r
+\r
+    if (startup)\r
+    {\r
+      if (startupBlockSize > lengthBytes)\r
+        askFor = lengthBytes; // is a very small recording!\r
+      else\r
+        askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams\r
+    }\r
+    else\r
+    {\r
+      if ((feedPosition + blockSize) > lengthBytes) // last block of recording\r
+        askFor = lengthBytes - feedPosition;\r
+      else // normal\r
+        askFor = blockSize;\r
+    }\r
+\r
+    threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);\r
+    feedPosition += thisRead;\r
+\r
+    if (!vdr->isConnected())\r
+    {\r
+      doConnectionLost();\r
+      return;\r
+    }\r
+\r
+    if (!threadBuffer) break;\r
+\r
+    if (startup)\r
+    {\r
+      int a_stream = demuxer->scan(threadBuffer, thisRead);\r
+      demuxer->setAudioStream(a_stream);\r
+      logger->log("PlayerRadio", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);\r
+      startup = false;\r
+    }\r
+\r
+    threadCheckExit();\r
+\r
+    while(writeLength < thisRead)\r
+    {\r
+      thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);\r
+      writeLength += thisWrite;\r
+\r
+      if (!thisWrite)\r
+      {\r
+        // demuxer is full and can't take anymore\r
+        threadLock();\r
+        threadWaitForSignal();\r
+        threadUnlock();\r
+      }\r
+\r
+      threadCheckExit();\r
+    }\r
+\r
+    free(threadBuffer);\r
+    threadBuffer = NULL;\r
+\r
+  }\r
+\r
+  // end of recording\r
+  logger->log("PlayerRadio", Log::DEBUG, "Recording playback ends");\r
+\r
+  threadCheckExit();\r
+\r
+\r
+  Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+  m->to = messageReceiver;\r
+  m->from = this;\r
+  m->message = Message::PLAYER_EVENT;\r
+  m->parameter = PlayerRadio::STOP_PLAYBACK;\r
+  logger->log("PlayerRadio", Log::DEBUG, "Posting message to %p...", messageQueue);\r
+  messageQueue->postMessage(m);\r
+}\r
+\r
+void PlayerRadio::threadPostStopCleanup()\r
+{\r
+  if (threadBuffer)\r
+  {\r
+    free(threadBuffer);\r
+    threadBuffer = NULL;\r
+  }\r
+}\r
+\r
index dbfe1bb8b21bdc4252893df6299b19937bed1d29..a8fed68eba8edc6fbbfd69ebf47151f543a69c95 100644 (file)
-/*
-    Copyright 2004-2006 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef PLAYERRADIO_H
-#define PLAYERRADIO_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef WIN32
-#include <sys/time.h>
-#endif
-#include <time.h>
-
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
-#include "callback.h"
-#include "defines.h"
-#include "afeed.h"
-
-class Log;
-class Audio;
-class Video;
-class Demuxer;
-class VDR;
-class MessageQueue;
-
-class PlayerRadio : public Thread_TYPE, public Callback
-{
-  public:
-    PlayerRadio(MessageQueue* messageQueue, void* messageReceiver);
-    virtual ~PlayerRadio();
-
-    int init(ULLONG lengthBytes, ULONG lengthPackets, bool IsPesRecording);
-    int shutdown();
-    void setStartBytes(ULLONG startBytes);
-
-    void play();
-    void stop();
-    void pause();
-    void jumpToPercent(double percent);
-    void skipForward(UINT seconds);
-    void skipBackward(UINT seconds);
-
-    UCHAR getState() { return state; }
-    ULONG getCurrentSeconds();
-    ULONG getLengthSeconds();
-
-    void call(void*); // for callback interface
-
-    const static UCHAR S_PLAY = 1;
-    const static UCHAR S_PAUSE_P = 2;
-    const static UCHAR S_STOP = 6;
-    const static UCHAR S_JUMP = 7;
-
-    // Player events
-
-    const static UCHAR CONNECTION_LOST = 1;
-    const static UCHAR STOP_PLAYBACK = 2;
-    const static UCHAR STREAM_END = 3;
-
-  protected:
-    void threadMethod();
-    void threadPostStopCleanup();
-
-  private:
-    void switchState(UCHAR newState, ULONG jumpPacket=0);
-
-    void threadFeedPlay();
-    void threadFeedScan();
-
-    void doConnectionLost();
-    void restartAtPacket(ULONG newPacket);
-    bool setLengthSeconds();
-
-    MessageQueue* messageQueue;
-    void* messageReceiver;
-    Log* logger;
-    Audio* audio;
-    Demuxer* demuxer;
-    VDR* vdr;
-    AFeed afeed;
-
-    bool initted;
-    bool startup;
-
-    ULLONG startPTS;
-    ULONG lengthSeconds;
-
-#ifndef WIN32
-    pthread_mutex_t mutex;
-#else
-    HANDLE mutex;
-#endif
-    void lock();
-    void unLock();
-
-    ULLONG lengthBytes;
-    ULLONG streamPos;
-    ULONG lengthPackets;
-    ULONG currentPacketNumber;
-    UINT blockSize;
-    UINT startupBlockSize;
-    UCHAR* threadBuffer;
-    UCHAR state;
-};
-
-#endif
-
-
-/*
-
-Possible states:
-
-Play, Pause, FFwd, FBwd, (Stop), [Jump]
-
-                    Possible  Working
-
-Play   -> PauseP       *         *
-       -> Stop         *         *
-       -> Jump         *         *
-
-PauseP -> Play         *         *
-       -> Stop         *         *
-       -> Jump         *         *
-
-PauseI -> Play         *         *
-       -> PauseP
-       -> Stop         *         *
-       -> Jump         *         *
-
-Stop   -> Play         *         *
-       -> PauseP
-       -> Jump
-
-Jump   -> Play
-       -> PauseP
-       -> Stop
-
-*/
+/*\r
+    Copyright 2004-2006 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef PLAYERRADIO_H\r
+#define PLAYERRADIO_H\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#ifndef WIN32\r
+#include <sys/time.h>\r
+#endif\r
+#include <time.h>\r
+\r
+#include "threadsystem.h"\r
+\r
+#include "callback.h"\r
+#include "defines.h"\r
+#include "afeed.h"\r
+\r
+class Log;\r
+class Audio;\r
+class Video;\r
+class Demuxer;\r
+class VDR;\r
+class MessageQueue;\r
+\r
+class PlayerRadio : public Thread_TYPE, public Callback\r
+{\r
+  public:\r
+    PlayerRadio(MessageQueue* messageQueue, void* messageReceiver);\r
+    virtual ~PlayerRadio();\r
+\r
+    int init(ULLONG lengthBytes, ULONG lengthPackets, bool IsPesRecording);\r
+    int shutdown();\r
+    void setStartBytes(ULLONG startBytes);\r
+\r
+    void play();\r
+    void stop();\r
+    void pause();\r
+    void playpause();\r
+    void jumpToPercent(double percent);\r
+    void skipForward(UINT seconds);\r
+    void skipBackward(UINT seconds);\r
+\r
+    UCHAR getState() { return state; }\r
+    ULONG getCurrentSeconds();\r
+    ULONG getLengthSeconds();\r
+\r
+    void call(void*); // for callback interface\r
+\r
+    const static UCHAR S_PLAY = 1;\r
+    const static UCHAR S_PAUSE_P = 2;\r
+    const static UCHAR S_STOP = 6;\r
+    const static UCHAR S_JUMP = 7;\r
+\r
+    // Player events\r
+\r
+    const static UCHAR CONNECTION_LOST = 1;\r
+    const static UCHAR STOP_PLAYBACK = 2;\r
+    const static UCHAR STREAM_END = 3;\r
+\r
+  protected:\r
+    void threadMethod();\r
+    void threadPostStopCleanup();\r
+\r
+  private:\r
+    void switchState(UCHAR newState, ULONG jumpPacket=0);\r
+\r
+    void threadFeedPlay();\r
+    void threadFeedScan();\r
+\r
+    void doConnectionLost();\r
+    void restartAtPacket(ULONG newPacket);\r
+    bool setLengthSeconds();\r
+\r
+    MessageQueue* messageQueue;\r
+    void* messageReceiver;\r
+    Log* logger;\r
+    Audio* audio;\r
+    Demuxer* demuxer;\r
+    VDR* vdr;\r
+    AFeed afeed;\r
+\r
+    bool initted;\r
+    bool startup;\r
+\r
+    ULLONG startPTS;\r
+    ULONG lengthSeconds;\r
+\r
+#ifndef WIN32\r
+    pthread_mutex_t mutex;\r
+#else\r
+    HANDLE mutex;\r
+#endif\r
+    void lock();\r
+    void unLock();\r
+\r
+    ULLONG lengthBytes;\r
+    ULLONG streamPos;\r
+    ULONG lengthPackets;\r
+    ULONG currentPacketNumber;\r
+    UINT blockSize;\r
+    UINT startupBlockSize;\r
+    UCHAR* threadBuffer;\r
+    UCHAR state;\r
+};\r
+\r
+#endif\r
+\r
+\r
+/*\r
+\r
+Possible states:\r
+\r
+Play, Pause, FFwd, FBwd, (Stop), [Jump]\r
+\r
+                    Possible  Working\r
+\r
+Play   -> PauseP       *         *\r
+       -> Stop         *         *\r
+       -> Jump         *         *\r
+\r
+PauseP -> Play         *         *\r
+       -> Stop         *         *\r
+       -> Jump         *         *\r
+\r
+PauseI -> Play         *         *\r
+       -> PauseP\r
+       -> Stop         *         *\r
+       -> Jump         *         *\r
+\r
+Stop   -> Play         *         *\r
+       -> PauseP\r
+       -> Jump\r
+\r
+Jump   -> Play\r
+       -> PauseP\r
+       -> Stop\r
+\r
+*/\r
index 877d17a764cd36a2abdc5f94defca82caefa783a..82661290d466df7204aa9fd33320456c7bdf80cd 100644 (file)
--- a/recman.h
+++ b/recman.h
 #include <winsock2.h>
 #include <windows.h>
 #define PATH_MAX FILENAME_MAX
+#else
+// added for raspberry pi, should also work on mvp
+#include <linux/limits.h>
+
 #endif
 
 #include "directory.h"
index 2c83ceea42d0ed9914116b54ca6d2418fbace3aa..67fff6db4ee451acbde3dcd69625b618d3e714dd 100644 (file)
--- a/remote.cc
+++ b/remote.cc
 
 Remote* Remote::instance = NULL;
 
+
+const ULONG Remote::NOLEARNMODE;
+// Not buttons
+const  UCHAR Remote::NA_LEARN;
+const  UCHAR Remote::NA_NONE;
+const  UCHAR Remote::NA_UNKNOWN;
+const  UCHAR Remote::NA_SIGNAL;
+const  UCHAR Remote::DF_UP;
+const  UCHAR Remote::DF_DOWN;
+const  UCHAR Remote::DF_LEFT;
+const  UCHAR Remote::DF_RIGHT;
+
+// Problem common buttons
+const  UCHAR Remote::VOLUMEUP;
+const  UCHAR Remote::VOLUMEDOWN;
+const  UCHAR Remote::CHANNELUP;
+const  UCHAR Remote::CHANNELDOWN;
+
+// Common buttons
+const  UCHAR Remote::ZERO;
+const  UCHAR Remote::ONE;
+const  UCHAR Remote::TWO;
+const  UCHAR Remote::THREE;
+const  UCHAR Remote::FOUR;
+const  UCHAR Remote::FIVE;
+const  UCHAR Remote::SIX;
+const  UCHAR Remote::SEVEN;
+const  UCHAR Remote::EIGHT;
+const  UCHAR Remote::NINE;
+const  UCHAR Remote::POWER;
+const  UCHAR Remote::GO;
+const  UCHAR Remote::BACK;
+const  UCHAR Remote::MENU;
+const  UCHAR Remote::RED;
+const  UCHAR Remote::GREEN;
+const  UCHAR Remote::YELLOW;
+const  UCHAR Remote::BLUE;
+const  UCHAR Remote::MUTE;
+const  UCHAR Remote::RADIO;
+const  UCHAR Remote::REVERSE;
+const  UCHAR Remote::PLAY;
+const  UCHAR Remote::FORWARD;
+const  UCHAR Remote::RECORD;
+const  UCHAR Remote::STOP;
+const  UCHAR Remote::PAUSE;
+const  UCHAR Remote::SKIPBACK;
+const  UCHAR Remote::SKIPFORWARD;
+const  UCHAR Remote::OK;
+
+// Old remote only
+const  UCHAR Remote::FULL;
+
+// New remote only
+const  UCHAR Remote::TV;
+const  UCHAR Remote::VIDEOS;
+const  UCHAR Remote::MUSIC;
+const  UCHAR Remote::PICTURES;
+const  UCHAR Remote::GUIDE;
+const  UCHAR Remote::UP;
+const  UCHAR Remote::DOWN;
+const  UCHAR Remote::LEFT;
+const  UCHAR Remote::RIGHT;
+const  UCHAR Remote::PREVCHANNEL;
+const  UCHAR Remote::STAR;
+const  UCHAR Remote::HASH;
+
+// Android only
+const  UCHAR Remote::PLAYPAUSE;
+
+
+// Remote types
+const  UCHAR Remote::OLDREMOTE;
+const  UCHAR Remote::NEWREMOTE;
+
 Remote::Remote()
 {
   if (instance) return;
@@ -189,8 +263,8 @@ char *Remote::SaveKeysConfig()
   RemoteTranslationList::const_iterator it;
   for (it = translist.begin(); it != translist.end(); it++)
   {
-    current+=sprintf(current,"H%08lXI%08lXK%02X",
-      (ULONG)it->first ,(ULONG) (it->first >> 32), it->second);
+         current+=snprintf(current,21,"H%08lXI%08lXK%02X",
+                         (ULONG)it->first ,(ULONG) (it->first >> 32), it->second);
   }
   return output;
 }
@@ -343,6 +417,8 @@ const char *Remote::CommandDesc(UCHAR number)
       return tr("Star");
     case HASH:
       return tr("Hash");
+    case PLAYPAUSE:
+       return tr("Play/Pause");
 
     default:
       return NULL;
index aca649a0e6069b302ff669df62ff90397e2ae7c9..e693b782ba63ebf0be6cfb503756e8759dc73671 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -127,6 +127,10 @@ class Remote: public AbstractOption
     const static UCHAR STAR        = 10;
     const static UCHAR HASH        = 14;
 
+    // Android only
+    const static UCHAR PLAYPAUSE       = 201;
+
+
     // Remote types
     const static UCHAR OLDREMOTE   = 1;
     const static UCHAR NEWREMOTE   = 2;
index 0b1a090700ca005e86591219132b24bdb0c1c26b..eef823a8a069878d0a3525cc02e72de421560e61 100644 (file)
--- a/stream.cc
+++ b/stream.cc
-/*
-    Copyright 2005-2006 Mark Calderbank
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "stream.h"
-#include "log.h"
-
-Stream::Stream()
-{
-  initted = 0;
-  draintarget = NULL;
-  cur_packet_pos = 0;
-}
-
-Stream::~Stream()
-{
-  shutdown();
-}
-
-void Stream::shutdown()
-{
-  if (initted)
-  {
-    free(outbuf);
-#ifdef WIN32
-    CloseHandle(mutex);
-#endif
-      
-  }
-  initted = 0;
-}
-
-int Stream::init(DrainTarget* tdt, int bufsize)
-{
-  outbuf = (UCHAR*) malloc(bufsize);
-  if (!outbuf) return 0;
-  draintarget = tdt;
-  bufferSize = bufsize;
-  initted = 1;
-#ifndef WIN32
-  pthread_mutex_init(&mutex, NULL);
-#else
-  mutex=CreateMutex(NULL,FALSE,NULL);
-#endif
-  return 1;
-}
-
-void Stream::flush()
-{
-  lock();
-
-  mediapackets.clear();
-  unLock();
-  if (draintarget) draintarget->ResetTimeOffsets();
-}
-
-int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index)
-{
-  int ret = 0;
-  if (!draintarget) return 0;
-  MediaPacket newPacket;
-  newPacket.length = len;
-  newPacket.pos_buffer = 0;
-  newPacket.type = type;
-  newPacket.pts=0;
-  newPacket.dts=0;
-  newPacket.synched=false;
-  newPacket.index=index;
-#ifdef WIN32
-  newPacket.disconti=false;
-  newPacket.presentation_time=0;
-#endif
-  if (type!=MPTYPE_MPEG_AUDIO_LAYER3) {//no PES
-    //Extract the pts...
-      bool hasdts=false;
-    if ((inbuf[7] & 0x80) && len>14 ) {
-        newPacket.synched=true;
-        newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |
-                    ( (ULLONG)(inbuf[10])        << 22 ) |
-                    ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |
-                     ( (ULLONG)(inbuf[12])        <<  7 ) |
-                     ( (ULLONG)(inbuf[13] & 0xFE) >>  1 );
-        if ((inbuf[7] & 0x40) && len>19) {
-            newPacket.dts=((ULLONG)(inbuf[14] & 0x0E) << 29 ) |
-                    ( (ULLONG)(inbuf[15])        << 22 ) |
-                    ( (ULLONG)(inbuf[16] & 0xFE) << 14 ) |
-                     ( (ULLONG)(inbuf[17])        <<  7 ) |
-                     ( (ULLONG)(inbuf[18] & 0xFE) >>  1 );
-            hasdts=true;
-        }
-#ifdef WIN32
-        //ok we have the pts now convert it to a continously time code in 100ns units
-        if (hasdts && draintarget->dtsTimefix()) newPacket.presentation_time=(ULLONG)(newPacket.dts*10000LL/90LL);
-        else newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);
-
-        //newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);
-        newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);
-#endif
-    }
-  }
-
-  lock();
-  int front, back;
-  if (mediapackets.empty())
-  {
-    back = 0; front = bufferSize;
-  }
-  else
-  {
-    front = mediapackets.front().pos_buffer;
-    back = mediapackets.back().pos_buffer + mediapackets.back().length;
-    if (back == bufferSize) back = 0;
-  }
-  unLock();
-
-  if (back <= front)
-  {
-    // The free space (if any) is in one continuous chunk.
-    if (len <= front - back) ret = len; // Is there enough of it?
-  }
-  else if (len <= bufferSize - back)
-  {
-    // There is enough space at the end of the buffer
-    ret = len;
-  }
-  else if (len <= front)
-  {
-    // There is enough space at the start of the buffer
-    back = 0;
-    ret = len;
-  }
-
-  if (ret) // Nonzero if we managed to find room for the packet
-  {
-    memcpy(outbuf + back, inbuf, len);
-    newPacket.pos_buffer = back;
-    lock();
-    mediapackets.push_back(newPacket);
-    unLock();
-  }// else {
- //     Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize);
-  //}
-
-  return ret;
-}
-
-bool Stream::drain()
-{
-  bool ret = false;
-  lock();
-  UINT listlength = mediapackets.size();
-  if (listlength != 0)
-  {
-    draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);
-    unLock();
-    UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);
-    lock();
-    if (consumed != 0) ret = true;
-    if (consumed > listlength) consumed = listlength;
-    while (consumed--) 
-    {
-        mediapackets.pop_front();
-    }
-  }
-  unLock();
-  return ret;
-}
-
-void Stream::lock()
-{
-#ifndef WIN32
-  pthread_mutex_lock(&mutex);
-  //logger->log("Player", Log::DEBUG, "LOCKED");
-
-#else
-   WaitForSingleObject(mutex, INFINITE );
-#endif
-}
-
-void Stream::unLock()
-{
-#ifndef WIN32
-  //logger->log("Player", Log::DEBUG, "UNLOCKING");
-  pthread_mutex_unlock(&mutex);
-#else
-   ReleaseMutex(mutex);
-#endif
-}
+/*\r
+    Copyright 2005-2006 Mark Calderbank\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "stream.h"\r
+#include "log.h"\r
+\r
+Stream::Stream()\r
+{\r
+  initted = 0;\r
+  draintarget = NULL;\r
+  cur_packet_pos = 0;\r
+}\r
+\r
+Stream::~Stream()\r
+{\r
+  shutdown();\r
+}\r
+\r
+void Stream::shutdown()\r
+{\r
+  if (initted)\r
+  {\r
+    free(outbuf);\r
+#ifdef WIN32\r
+    CloseHandle(mutex);\r
+#endif\r
+      \r
+  }\r
+  initted = 0;\r
+}\r
+\r
+int Stream::init(DrainTarget* tdt, int bufsize)\r
+{\r
+  outbuf = (UCHAR*) malloc(bufsize);\r
+  if (!outbuf) return 0;\r
+  draintarget = tdt;\r
+  bufferSize = bufsize;\r
+  initted = 1;\r
+#ifndef WIN32\r
+  pthread_mutex_init(&mutex, NULL);\r
+#else\r
+  mutex=CreateMutex(NULL,FALSE,NULL);\r
+#endif\r
+  return 1;\r
+}\r
+\r
+void Stream::flush()\r
+{\r
+  lock();\r
+\r
+  mediapackets.clear();\r
+  unLock();\r
+  if (draintarget) draintarget->ResetTimeOffsets();\r
+}\r
+\r
+int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index)\r
+{\r
+  int ret = 0;\r
+  if (!draintarget) return 0;\r
+  MediaPacket newPacket;\r
+  newPacket.length = len;\r
+  newPacket.pos_buffer = 0;\r
+  newPacket.type = type;\r
+  newPacket.pts=0;\r
+  newPacket.dts=0;\r
+  newPacket.synched=false;\r
+  newPacket.index=index;\r
+#if defined(WIN32) || defined(__ANDROID__)\r
+  newPacket.disconti=false;\r
+  newPacket.presentation_time=0;\r
+#endif\r
+  if (type!=MPTYPE_MPEG_AUDIO_LAYER3) {//no PES\r
+    //Extract the pts...\r
+      bool hasdts=false;\r
+    if ((inbuf[7] & 0x80) && len>14 ) {\r
+        newPacket.synched=true;\r
+        newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |\r
+                    ( (ULLONG)(inbuf[10])        << 22 ) |\r
+                    ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |\r
+                     ( (ULLONG)(inbuf[12])        <<  7 ) |\r
+                     ( (ULLONG)(inbuf[13] & 0xFE) >>  1 );\r
+        if ((inbuf[7] & 0x40) && len>19) {\r
+            newPacket.dts=((ULLONG)(inbuf[14] & 0x0E) << 29 ) |\r
+                    ( (ULLONG)(inbuf[15])        << 22 ) |\r
+                    ( (ULLONG)(inbuf[16] & 0xFE) << 14 ) |\r
+                     ( (ULLONG)(inbuf[17])        <<  7 ) |\r
+                     ( (ULLONG)(inbuf[18] & 0xFE) >>  1 );\r
+            hasdts=true;\r
+        }\r
+#if defined(WIN32) || defined(__ANDROID__)\r
+        //ok we have the pts now convert it to a continously time code in 100ns units\r
+        if (hasdts && draintarget->dtsTimefix()) newPacket.presentation_time=(ULLONG)(newPacket.dts*10000LL/90LL);\r
+        else newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);\r
+\r
+        //newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);\r
+        newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);\r
+#endif\r
+    }\r
+  }\r
+\r
+  lock();\r
+  int front, back;\r
+  if (mediapackets.empty())\r
+  {\r
+    back = 0; front = bufferSize;\r
+  }\r
+  else\r
+  {\r
+    front = mediapackets.front().pos_buffer;\r
+    back = mediapackets.back().pos_buffer + mediapackets.back().length;\r
+    if (back == bufferSize) back = 0;\r
+  }\r
+  unLock();\r
+\r
+  if (back <= front)\r
+  {\r
+    // The free space (if any) is in one continuous chunk.\r
+    if (len <= front - back) ret = len; // Is there enough of it?\r
+  }\r
+  else if (len <= bufferSize - back)\r
+  {\r
+    // There is enough space at the end of the buffer\r
+    ret = len;\r
+  }\r
+  else if (len <= front)\r
+  {\r
+    // There is enough space at the start of the buffer\r
+    back = 0;\r
+    ret = len;\r
+  }\r
+\r
+  if (ret) // Nonzero if we managed to find room for the packet\r
+  {\r
+    memcpy(outbuf + back, inbuf, len);\r
+    newPacket.pos_buffer = back;\r
+    lock();\r
+    mediapackets.push_back(newPacket);\r
+    unLock();\r
+  } else {\r
+     // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize);\r
+  }\r
+\r
+  return ret;\r
+}\r
+\r
+bool Stream::drain()\r
+{\r
+  bool ret = false;\r
+  lock();\r
+  UINT listlength = mediapackets.size();\r
+  if (listlength != 0)\r
+  {\r
+    draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);\r
+    unLock();\r
+    UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);\r
+    lock();\r
+    if (consumed != 0) ret = true;\r
+    if (consumed > listlength) consumed = listlength;\r
+    while (consumed--) \r
+    {\r
+        mediapackets.pop_front();\r
+    }\r
+  }\r
+  unLock();\r
+  return ret;\r
+}\r
+\r
+void Stream::lock()\r
+{\r
+#ifndef WIN32\r
+  pthread_mutex_lock(&mutex);\r
+  //logger->log("Player", Log::DEBUG, "LOCKED");\r
+\r
+#else\r
+   WaitForSingleObject(mutex, INFINITE );\r
+#endif\r
+}\r
+\r
+void Stream::unLock()\r
+{\r
+#ifndef WIN32\r
+  //logger->log("Player", Log::DEBUG, "UNLOCKING");\r
+  pthread_mutex_unlock(&mutex);\r
+#else\r
+   ReleaseMutex(mutex);\r
+#endif\r
+}\r
index a6cb01f5897bb44c3414ad55efe078356692a8d7..d8a98da6ffd69d6d7dafd11c9e8604c81f5d4359 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "surface.h"
-
-#include "osd.h"
-#include "log.h"
-
-Surface* Surface::screen = NULL;
-osd_font_t* Surface::font = &font_helvB18;
-
-Surface::Surface(int id)
-{
-  if (id == SCREEN) screen = this;
-}
-
-Surface::~Surface()
-{
-}
-
-Surface* Surface::getScreen()
-{
-  return screen;
-}
-
-int Surface::drawText(const char* text, int x, int y, ULONG rgba)
-{
-  return drawText(text, x, y, 2000, rgba);
-}
-
-int Surface::drawText(const char* text, int x, int y, int width, ULONG rgba)
-{
-  int h, n, i;
-  int Y, X, cx;
-
-  n = strlen(text);
-  h = font->height;
-
-  X = 0;
-  cx = 0;
-  startFastDraw();
-  for (i=0; i<n; i++)
-  {
-    unsigned char c = text[i];
-    unsigned long *character = &font->content[font->offset[c]];
-    int w = font->width[c];
-    int pixels = 0;
-
-    for (X=0; (X<w) && (X + cx < width); X++)
-    {
-      for (Y=0; Y<h; Y++)
-      {
-        if ((character[Y] >> (32 - X)) & 0x1)
-        {
-          drawPixel(x+X+cx, y+Y, rgba,true);
-          pixels++;
-        }
-      }
-    }
-    cx += w;
-  }
-  endFastDraw();
-  return 1;
-}
-
-int Surface::drawTextRJ(const char* text, int x, int y, ULONG rgba)
-{
-  int i, n, w;
-  w = 0;
-
-  n = strlen(text);
-
-  for (i = 0; i < n; i++)
-  {
-    w += font->width[(unsigned char)text[i]];
-  }
-
-  x -= w;
-
-  if (x < 0) return 0;
-  else return drawText(text, x, y, rgba);
-}
-
-int Surface::drawTextCentre(const char* text, int x, int y, ULONG rgba)
-{
-  int i, n, w;
-  w = 0;
-
-  n = strlen(text);
-
-  for (i = 0; i < n; i++)
-  {
-    w += font->width[(unsigned char)text[i]]; //Characters bigger then 128 can appear
-  }
-
-  x -= w / 2;
-
-  if (x < 0) return 0;
-  else return drawText(text, x, y, rgba);
-}
-
-int Surface::getCharWidth(char c)
-{
-  return font->width[(unsigned char) c];
-}
-
-int Surface::getFontHeight()
-{
-  return font->spacing;
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "surface.h"\r
+\r
+#include <math.h>\r
+#include "osd.h"\r
+#include "log.h"\r
+#include "video.h"\r
+\r
+#include "teletxt/txtfont.h"\r
+\r
+unsigned int interpol_table_fac1[16][22];\r
+unsigned int interpol_table_fac2[16][22];\r
+unsigned int interpol_table_fac3[16][22];\r
+unsigned int interpol_table_fac4[16][22];\r
+int interpol_lowbit[16];\r
+int interpol_upbit[16];\r
+int interpol_lowline[22];\r
+int interpol_upline[22];\r
+bool pol_table_inited=false;\r
+\r
+void initpol_tables(){\r
+    int charsizex;\r
+    int charsizey;\r
+    charsizex=16;\r
+    if (Video::getInstance()->getFormat() == Video::PAL)\r
+    {\r
+        charsizey=22;\r
+    } else {\r
+        charsizey=18;\r
+    }\r
+    int ttcharsizex=12;\r
+    int ttcharsizey=10;\r
+    for (int py=0;py<charsizey;py++) {\r
+        float fposy=((float)(ttcharsizey))/((float)(charsizey))*((float)py);\r
+        float yweight=fposy-floor(fposy);\r
+        float yinvweight=1.-yweight;\r
+        interpol_upline[py]=min((unsigned int)ceil(fposy),9);\r
+        interpol_lowline[py]=max((unsigned int)floor(fposy),0);\r
+        for (int px=0;px<charsizex;px++) {\r
+            float fposx=((float)(ttcharsizex))/((float)(charsizex))*((float)px);\r
+            float xweight=fposx-floor(fposx);\r
+            float xinvweight=1.-xweight;\r
+            interpol_upbit[px]= (min((unsigned int)ceil(fposx),11));\r
+            interpol_lowbit[px]= (max((unsigned int)floor(fposx),0));\r
+\r
+            interpol_table_fac1[px][py]=xweight*yweight*256.;\r
+            interpol_table_fac2[px][py]=xinvweight*yweight*256.;\r
+            interpol_table_fac3[px][py]=xweight*yinvweight*256.;\r
+            interpol_table_fac4[px][py]=xinvweight*yinvweight*256.;\r
+\r
+        }\r
+    }\r
+}\r
+\r
+\r
+Surface* Surface::screen = NULL;\r
+osd_font_t* Surface::font = &font_helvB18;\r
+\r
+Surface::Surface(int id)\r
+{\r
+  if (id == SCREEN) screen = this;\r
+}\r
+\r
+Surface::~Surface()\r
+{\r
+}\r
+\r
+Surface* Surface::getScreen()\r
+{\r
+  return screen;\r
+}\r
+\r
+int Surface::drawText(const char* text, int x, int y, ULONG rgba)\r
+{\r
+  return drawText(text, x, y, 2000, rgba);\r
+}\r
+\r
+int Surface::drawText(const char* text, int x, int y, int width, ULONG rgba)\r
+{\r
+  int h, n, i;\r
+  int Y, X, cx;\r
+\r
+  n = strlen(text);\r
+  h = font->height;\r
+\r
+  X = 0;\r
+  cx = 0;\r
+  startFastDraw();\r
+  for (i=0; i<n; i++)\r
+  {\r
+    unsigned char c = text[i];\r
+    unsigned long *character = &font->content[font->offset[c]];\r
+    int w = font->width[c];\r
+    int pixels = 0;\r
+\r
+    for (X=0; (X<w) && (X + cx < width); X++)\r
+    {\r
+      for (Y=0; Y<h; Y++)\r
+      {\r
+        if ((character[Y] >> (32 - X)) & 0x1)\r
+        {\r
+          drawPixel(x+X+cx, y+Y, rgba,true);\r
+          pixels++;\r
+        }\r
+      }\r
+    }\r
+    cx += w;\r
+  }\r
+  endFastDraw();\r
+  return 1;\r
+}\r
+\r
+int Surface::drawTextRJ(const char* text, int x, int y, ULONG rgba)\r
+{\r
+  int i, n, w;\r
+  w = 0;\r
+\r
+  n = strlen(text);\r
+\r
+  for (i = 0; i < n; i++)\r
+  {\r
+    w += font->width[(unsigned char)text[i]];\r
+  }\r
+\r
+  x -= w;\r
+\r
+  if (x < 0) return 0;\r
+  else return drawText(text, x, y, rgba);\r
+}\r
+\r
+int Surface::drawTextCentre(const char* text, int x, int y, ULONG rgba)\r
+{\r
+  int i, n, w;\r
+  w = 0;\r
+\r
+  n = strlen(text);\r
+\r
+  for (i = 0; i < n; i++)\r
+  {\r
+    w += font->width[(unsigned char)text[i]]; //Characters bigger then 128 can appear\r
+  }\r
+\r
+  x -= w / 2;\r
+\r
+  if (x < 0) return 0;\r
+  else return drawText(text, x, y, rgba);\r
+}\r
+\r
+int Surface::getCharWidth(char c)\r
+{\r
+  return font->width[(unsigned char) c];\r
+}\r
+\r
+int Surface::getFontHeight()\r
+{\r
+  return font->spacing;\r
+}\r
+\r
+//Moved from Teletext view in order to allow device depend optimizations\r
+\r
+Colour Surface::enumTeletextColorToCoulour(enumTeletextColor ttcol)\r
+{\r
+    switch (ttcol) {\r
+        case ttcBlack:\r
+            return Colour(0,0,0);\r
+        case ttcRed:\r
+            return Colour(255,0,0);\r
+        case ttcGreen:\r
+            return Colour(0,255,0);\r
+        case ttcYellow:\r
+            return Colour(255,255,0);\r
+        case ttcBlue:\r
+            return Colour(0,0,255);\r
+        case ttcMagenta:\r
+            return Colour(255,0,255);\r
+        case ttcCyan:\r
+            return Colour(0,255,255);\r
+        case ttcWhite:\r
+            return Colour(255,255,255);\r
+        case ttcTransparent:\r
+            return Colour(0,0,0,0);\r
+        case ttcHalfRed:\r
+            return Colour(127,0,0);\r
+        case ttcHalfGreen:\r
+            return Colour(0,127,0);\r
+        case ttcHalfYellow:\r
+            return Colour(127,127,0);\r
+        case ttcHalfBlue:\r
+            return Colour(0,0,127);\r
+        case ttcHalfMagenta:\r
+            return Colour(127,0,127);\r
+        case ttcHalfCyan:\r
+            return Colour(0,127,127);\r
+        case ttcGrey:\r
+            return Colour(127,127,127);\r
+        default:\r
+            return Colour(0,0,0);\r
+    };\r
+}\r
+\r
+\r
+\r
+//Next function inspired by osdteletext plugin\r
+void Surface::drawTTChar(int ox, int oy, int x, int y, cTeletextChar c)\r
+{\r
+       if (!pol_table_inited){\r
+               initpol_tables();\r
+               pol_table_inited=true;\r
+       }\r
+    unsigned int buffer [10];\r
+    unsigned int * charmap=GetFontChar(c,buffer);\r
+    if (!charmap) { //invalid char\r
+        memset(&buffer,0,10);\r
+        charmap=buffer;\r
+    }\r
+    enumTeletextColor ttforegcolour=c.GetFGColor();\r
+    enumTeletextColor ttbackgcolour=c.GetBGColor();\r
+    if (c.GetBoxedOut()) {\r
+        ttforegcolour=ttcTransparent;\r
+        ttbackgcolour=ttcTransparent;\r
+    }\r
+    int charsizex;\r
+    int charsizey;\r
+    charsizex=16;\r
+\r
+    if (Video::getInstance()->getFormat() == Video::PAL)\r
+    {\r
+        charsizey=22;\r
+    } else {\r
+        charsizey=18;\r
+    }\r
+    int ttcharsizex=12;\r
+    int ttcharsizey=10;\r
+    int screenposx=charsizex*x+ox; //12*40= 480 250\r
+    int screenposy=y*charsizey+oy;\r
+\r
+\r
+   // Log::getInstance()->log("Surface", Log::ERR, "TTpos %d %d %d %d %d %d",x,y,ox,oy,screenposx,screenposy);\r
+    Colour fgcharcl=enumTeletextColorToCoulour(ttforegcolour);\r
+    Colour bgcharcl=enumTeletextColorToCoulour(ttbackgcolour);\r
+\r
+    startFastDraw();\r
+    for (int py=0;py<charsizey;py++) {\r
+        int upperbitline=charmap[interpol_upline[py]];\r
+        int lowerbitline=charmap[interpol_lowline[py]];\r
+        for (int px=0;px<charsizex;px++) {\r
+            int upperbit= interpol_upbit[px];\r
+            int lowerbit= interpol_lowbit[px];\r
+            Colour uuc=( upperbitline &(0x8000>>upperbit)) ? fgcharcl: bgcharcl;\r
+            Colour ulc=( upperbitline &(0x8000>>lowerbit)) ? fgcharcl: bgcharcl;\r
+            Colour luc=( lowerbitline &(0x8000>>upperbit)) ? fgcharcl: bgcharcl;\r
+            Colour llc=( lowerbitline &(0x8000>>lowerbit)) ? fgcharcl: bgcharcl;\r
+            unsigned int fac1,fac2,fac3,fac4;\r
+            fac1=interpol_table_fac1[px][py];\r
+            fac2=interpol_table_fac2[px][py];\r
+            fac3=interpol_table_fac3[px][py];\r
+            fac4=interpol_table_fac4[px][py];\r
+\r
+            Colour res((uuc.red*fac1+ulc.red*fac2+luc.red*fac3+llc.red*fac4)/256,\r
+                (uuc.green*fac1+ulc.green*fac2+luc.green*fac3+llc.green*fac4)/256,\r
+                (uuc.blue*fac1+ulc.blue*fac2+luc.blue*fac3+llc.blue*fac4)/256,\r
+                (uuc.alpha*fac1+ulc.alpha*fac2+luc.alpha*fac3+llc.alpha*fac4)/256); //if this is too slow make a table\r
+            int c = (  (res.alpha << 24 )\r
+                        | (res.red    << 16)\r
+                        | (res.green  <<  8)\r
+                        | (res.blue        ) );\r
+            drawPixel(screenposx+px,screenposy+py,c, true);\r
+        }\r
+    }\r
+\r
+\r
+    endFastDraw();\r
+\r
+\r
+}\r
index ce412ac4da4829858fb8b5ace8d5faceac6ced47..cbf992488e58827b36990f5b2c6a6eda0a88ffc8 100644 (file)
--- a/surface.h
+++ b/surface.h
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef SURFACE_H
-#define SURFACE_H
-
-#include <stdio.h>
-#include "defines.h"
-#include "colour.h"
-
-// Font stuff
-
-typedef struct bogl_font {
-  char *name;     /* Font name. */
-  int height;     /* Height in pixels. */
-  int spacing;     /* Vertical spacing in pixels. */
-  unsigned long *content;   /* 32-bit right-padded bitmap array. */
-  short *offset;      /* 256 offsets into content. */
-  unsigned char *width;   /* 256 character widths. */
-} osd_font_t;
-
-extern osd_font_t font_CaslonRoman_1_25;
-extern osd_font_t font_helvB24;
-extern osd_font_t font_helvB18;
-
-class Bitmap;
-
-class Surface
-{
-  public:
-    Surface(int id = 0);
-    virtual ~Surface();
-
-    static Surface* getScreen();
-    static int getFontHeight();
-    int getCharWidth(char c);
-
-    int drawText(const char* text, int x, int y, ULONG rgba);
-    int drawText(const char* text, int x, int y, int width, ULONG rgba);
-    int drawTextRJ(const char* text, int x, int y, ULONG rgba);
-    int drawTextCentre(const char* text, int x, int y, ULONG rgba);
-
-    virtual int create(UINT width, UINT height)=0;
-    virtual void display()=0;
-
-    virtual int fillblt(int x, int y, int width, int height, unsigned int c)=0;
-    virtual void drawPixel(int x, int y, unsigned int c, bool fastdraw=false)=0;
-    virtual void drawPixel(int x, int y, Colour& c, bool fastdraw=false)=0;    virtual void drawHorzLine(int x1, int x2, int y, unsigned int c)=0;
-    virtual void drawVertLine(int x, int y1, int y2, unsigned int c)=0;
-    virtual void drawBitmap(int x, int y, const Bitmap& bm)=0;
-    virtual int updateToScreen(int sx, int sy, int w, int h, int dx, int dy)=0;
-    virtual void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)=0;
-    virtual void screenShot(char* fileName)=0;
-
-    /* This is for system which need a locking of the drawing surface to speed up drawing */
-    virtual void startFastDraw() {};
-    virtual void endFastDraw() {};
-  
-
-    virtual int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)=0;
-
-    const static int SCREEN = 1;
-    const static int BUFFER = 2;
-
-  protected:
-    static Surface* screen;
-    static osd_font_t* font;
-};
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef SURFACE_H\r
+#define SURFACE_H\r
+\r
+#include <stdio.h>\r
+#include "defines.h"\r
+#include "colour.h"\r
+\r
+#include "teletextdecodervbiebu.h"\r
+\r
+// Font stuff\r
+\r
+typedef struct bogl_font {\r
+  char *name;     /* Font name. */\r
+  int height;     /* Height in pixels. */\r
+  int spacing;     /* Vertical spacing in pixels. */\r
+  unsigned long *content;   /* 32-bit right-padded bitmap array. */\r
+  short *offset;      /* 256 offsets into content. */\r
+  unsigned char *width;   /* 256 character widths. */\r
+} osd_font_t;\r
+\r
+//extern osd_font_t font_CaslonRoman_1_25;\r
+//extern osd_font_t font_helvB24;\r
+extern osd_font_t font_helvB18;\r
+\r
+class Bitmap;\r
+\r
+\r
+\r
+class Surface\r
+{\r
+  public:\r
+    Surface(int id = 0);\r
+    virtual ~Surface();\r
+\r
+    static Surface* getScreen();\r
+    virtual int getFontHeight();\r
+    virtual int getCharWidth(char c);\r
+\r
+    virtual int drawText(const char* text, int x, int y, ULONG rgba);\r
+    virtual int drawText(const char* text, int x, int y, int width, ULONG rgba);\r
+    virtual int drawTextRJ(const char* text, int x, int y, ULONG rgba);\r
+    virtual int drawTextCentre(const char* text, int x, int y, ULONG rgba);\r
+\r
+    virtual void drawJpeg(const char *fileName,int x, int y,int *width, int *height) {}\r
+\r
+    virtual int create(UINT width, UINT height)=0;\r
+    virtual void display()=0;\r
+\r
+    virtual int fillblt(int x, int y, int width, int height, unsigned int c)=0;\r
+    virtual void drawPixel(int x, int y, unsigned int c, bool fastdraw=false)=0;\r
+    virtual void drawPixel(int x, int y, Colour& c, bool fastdraw=false)=0;\r
+    virtual void drawHorzLine(int x1, int x2, int y, unsigned int c)=0;\r
+    virtual void drawVertLine(int x, int y1, int y2, unsigned int c)=0;\r
+    virtual void drawBitmap(int x, int y, const Bitmap& bm)=0;\r
+    virtual int updateToScreen(int sx, int sy, int w, int h, int dx, int dy)=0;\r
+    virtual void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)=0;\r
+    virtual void screenShot(const char* fileName)=0;\r
+\r
+    /* This is for system which need a locking of the drawing surface to speed up drawing */\r
+    virtual void startFastDraw() {};\r
+    virtual void endFastDraw() {};\r
+\r
+\r
+    virtual void drawTTChar(int ox, int oy,int x, int y, cTeletextChar c);\r
+\r
+\r
+  \r
+\r
+   // virtual int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)=0;\r
+\r
+    const static int SCREEN = 1;\r
+    const static int BUFFER = 2;\r
+\r
+  protected:\r
+    static Surface* screen;\r
+    static osd_font_t* font;\r
+    Colour enumTeletextColorToCoulour(enumTeletextColor ttcol);\r
+\r
+};\r
+\r
+#endif\r
index f89770d99acf0800726e02ef3ade4ec78ff072b9..baeeb91791eccc9096a4d640f1bc8e9bb3869b54 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon, 2009 Marten Richter
-    Portions copyright 2008 Jon Gettler
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "surfacedirectfb.h"
-
-#include "osd.h"
-#include "bitmap.h"
-#include "log.h"
-
-#include "osddirectfb.h"
-
-
-
-SurfaceDirectFB::SurfaceDirectFB(int id)
-: Surface(id)
-{
-   surface=NULL;
-}
-
-SurfaceDirectFB::~SurfaceDirectFB()
-{
-   if (surface) surface->Release(surface);
-
-}
-
-int SurfaceDirectFB::create(UINT width, UINT height)
-{
-  int counter=0;
-  while (!Osd::getInstance()->isInitted() && counter<2000) {
-    MILLISLEEP(50); //Wait for Grafiksystem initialization
-    counter++;
-  }
-  if (!Osd::getInstance()->isInitted()) return -1;
-  
-  IDirectFB*dfb=((OsdDirectFB*)Osd::getInstance())->getDfb();
-printf("ich bin doof");fflush(stdout);  
-  if (screen == this) 
-  {
-    IDirectFBDisplayLayer *osd_layer=((OsdDirectFB*)Osd::getInstance())->getOsdLayer();
-    if (osd_layer->GetSurface(osd_layer,&surface)!=DFB_OK) 
-    {
-
-       return 0;
-    }
-    surface->Clear(surface,0x0,0x0,0x0,0xFF);
-  } else {
-    DFBSurfaceDescription dsc;
-    memset(&dsc,0,sizeof(dsc));
-    *((int*)&dsc.flags)=DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT;
-    
-    dsc.width=width;
-    dsc.height=height;
-    dsc.caps= DSCAPS_NONE;
-    if (dfb->CreateSurface(dfb,&dsc,&surface)!=DFB_OK) 
-    {
-       return 0;
-    }
-  }
-  return 1;
-}
-
-void SurfaceDirectFB::display()
-{
-//  unsigned long fb_descriptor[2];
-/*
-  fb_descriptor[0] = surface.sfc.handle;
-  fb_descriptor[1] = 1;
-*/
-//  ioctl(fdOsd, GFX_FB_ATTACH, fb_descriptor);
-}
-
-
-// ----------------------------------------------------------------------------
-
-// Now for the drawing functions
-
-
-int SurfaceDirectFB::fillblt(int x, int y, int width, int height, unsigned int c)
-{
-    int sw,sh;
-    unsigned char r,g,b,a;
-    int nx,ny,nw,nh;
-    nx=x;
-    ny=y;
-    nw=width;
-    nh=height;
-    surface->GetSize(surface,&sw,&sh);
-    
-    if (nx >sw) nx=sw-1;
-    if (ny >sh) ny=sh-1;
-    
-    if ((nx+nw) >= sw) nw=sw-nx; 
-    if ((ny+nh) >= sh) nh=sh-ny; 
-
-    if ((nx<0) || (ny < 0) || (nh <=0) || (nw <=0)) {
-       return 0;
-    }
-    
-    a= (c &0xff000000)>>24;
-    r= (c &0x00ff0000)>>16;
-    g= (c &0x0000ff00)>>8;
-    b= (c &0x000000ff);
-    
-    
-    surface->SetColor(surface,r,g,b,a);
-    surface->FillRectangle(surface,nx,ny,nw,nh);
-    return 0;
-}
-
-void SurfaceDirectFB::drawPixel(int x, int y, unsigned int c, bool fastdraw)
-{
-    int sw,sh;
-    unsigned char r,g,b,a;
-    char *dst=NULL;
-    int offset=0;
-    int pitch;
-    surface->GetSize(surface,&sw,&sh);
-    if (x>=sw) return;
-    if (y>=sh) return;
-    
-
-    
-    a= (c &0xff000000)>>24;
-    r= (c &0x00ff0000)>>16;
-    g= (c &0x0000ff00)>>8;
-    b= (c &0x000000ff);
-
-    //TODO Fastdraw
-    if (surface->Lock(surface,DSLF_WRITE,(void**)(void*)&dst,&pitch) == DFB_OK) {
-       offset= y* pitch+x*4;
-       dst[offset++]=b;
-       dst[offset++]=g;
-       dst[offset++]=r;
-       dst[offset]=a;
-       surface->Unlock(surface);
-     }
-
-}
-
-void SurfaceDirectFB::drawPixel(int x, int y, Colour& c, bool fastdraw)
-{
-    int sw,sh;
-    char *dst=NULL;
-    int offset=0;
-    int pitch;
-    surface->GetSize(surface,&sw,&sh);
-    if (x>=sw) return;
-    if (y>=sh) return;
-    
-    //TODO Fastdraw
-    if (surface->Lock(surface,DSLF_WRITE,(void**)(void*)&dst,&pitch) == DFB_OK) {
-       offset= y* pitch+x*4;
-       dst[offset++]=c.blue;
-       dst[offset++]=c.green;
-       dst[offset++]=c.red;
-       dst[offset]=c.alpha;
-       surface->Unlock(surface);
-     }
-
-}
-void SurfaceDirectFB::drawHorzLine(int x1, int x2, int y, unsigned int c)
-{
-  fillblt(x1, y, x2-x1, 1, c);
-}
-
-void SurfaceDirectFB::drawVertLine(int x, int y1, int y2, unsigned int c)
-{
-  fillblt(x, y1, 1, y2-y1, c);
-}
-
-void SurfaceDirectFB::drawBitmap(int x, int y, const Bitmap& bm)
-{/*
-  UINT bmw = bm.getWidth(); UINT bmh = bm.getHeight();
-  if (bmw == 0 || bmh == 0) return;
-  if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height)) return;
-  int remainder = (surface.sfc.width % 4);
-  UINT line;
-  if (remainder == 0)
-    line = surface.sfc.width;
-  else
-    line = surface.sfc.width + (4 - remainder);
-  const std::vector<UCHAR>& bmdata = bm.rawData();
-  const std::vector<UCHAR>& Y = bm.palette.getYVector();
-  const std::vector<UCHAR>& Cr = bm.palette.getCrVector();
-  const std::vector<UCHAR>& Cb = bm.palette.getCbVector();
-  const std::vector<UCHAR>& A = bm.palette.getAVector();
-  UINT b_offset = 0;
-  UINT s_offset = x + y*line;
-  UINT plotWidth = bmw;
-  UINT plotHeight = bmh;
-  if (x + plotWidth - 1 > surface.sfc.width)
-    plotWidth = surface.sfc.width - x + 1;
-  if (y + plotHeight - 1 > surface.sfc.height)
-    plotHeight = surface.sfc.height - y + 1;
-  for (UINT j = 0; j < plotHeight; ++j)
-  {
-    UINT i = 0;
-    if (x & 1) // odd x - need to plot first column separately
-    {
-      UCHAR index = bmdata[b_offset];
-      *(surface.base[0] + s_offset) = Y[index];
-      *(surface.base[1] + s_offset - 1) = Cb[index];
-      *(surface.base[1] + s_offset) = Cr[index];
-      *(surface.base[2] + s_offset) = A[index];
-      i = 1;
-    }
-    // Now, plot pairs of pixels with averaged chroma values
-    while (i < plotWidth - 1)
-    {
-      UCHAR index1 = bmdata[b_offset + i];
-      UCHAR index2 = bmdata[b_offset + i + 1];
-      *(surface.base[0] + s_offset + i) = Y[index1];
-      *(surface.base[0] + s_offset + i + 1) = Y[index2];
-      *(surface.base[1] + s_offset + i) = (Cb[index1] + Cb[index2]) / 2;
-      *(surface.base[1] + s_offset + i + 1) = (Cr[index1] + Cr[index2]) / 2;
-      *(surface.base[2] + s_offset + i) = A[index1];
-      *(surface.base[2] + s_offset + i + 1) = A[index2];
-      i += 2;
-    }
-    if (i == plotWidth - 1) // One column left to do
-    {
-      UCHAR index = bmdata[b_offset + i];
-      *(surface.base[0] + s_offset + i) = Y[index];
-      *(surface.base[1] + s_offset + i) = Cb[index];
-      *(surface.base[1] + s_offset + i + 1) = Cr[index];
-      *(surface.base[2] + s_offset + i) = A[index];
-    }
-    s_offset += line;
-    b_offset += bmw;
-  }*/
-}
-
-  /* surface update to screen needs:
-  source x distance into this surface
-  source y distance into this surface
-  width of update
-  height of update
-  destination x on screen
-  destination y on screen
-  */
-int SurfaceDirectFB::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME
-{
-  IDirectFBSurface* screensurf=((SurfaceDirectFB*)screen)->getSurfaceDFB();
-  if (!screensurf) return 0;
-  if (this==screen) return 0;
-  
-  DFBRectangle rect;
-  int sw,sh;
-  
-  screensurf->GetSize(screensurf,&sw,&sh);
-//  screensurf->Clear(screensurf,0x0,0x0,0x0,0xFF);
-  rect.x = sx;
-  rect.y=sy;
-  rect.w=w;
-  rect.h=h;
-  
-  DFBRectangle drect; //TODO make osd HD
-  drect.x=dx*sw/720;
-  drect.y=dy*sh/576;
-  drect.w=w*sw/720;
-  drect.h=h*sh/576;
-  
-//  screensurf->Blit(screensurf,surface,&rect,dx,dy);
-  screensurf->StretchBlit(screensurf,surface,&rect,&drect);
-  
-  return 0;//blt(fdOsd, surface.sfc.handle, sx, sy, w, h, ((SurfaceDirectFB*)screen)->getSurfaceHandle(), dx, dy);
-}
-
-int SurfaceDirectFB::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)
-{//Skip it, noone uses this!
-
-  return 0;
-}
-
-void SurfaceDirectFB::screenShot(char* fileName)
-{
-  return;
-  
-}
-
-void SurfaceDirectFB::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)
-{
-  
-}
-
+/*\r
+    Copyright 2004-2005 Chris Tallon, 2009 Marten Richter\r
+    Portions copyright 2008 Jon Gettler\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "surfacedirectfb.h"\r
+\r
+#include "osd.h"\r
+#include "bitmap.h"\r
+#include "log.h"\r
+\r
+#include "osddirectfb.h"\r
+\r
+\r
+\r
+SurfaceDirectFB::SurfaceDirectFB(int id)\r
+: Surface(id)\r
+{\r
+   surface=NULL;\r
+}\r
+\r
+SurfaceDirectFB::~SurfaceDirectFB()\r
+{\r
+   if (surface) surface->Release(surface);\r
+\r
+}\r
+\r
+int SurfaceDirectFB::create(UINT width, UINT height)\r
+{\r
+  int counter=0;\r
+  while (!Osd::getInstance()->isInitted() && counter<2000) {\r
+    MILLISLEEP(50); //Wait for Grafiksystem initialization\r
+    counter++;\r
+  }\r
+  if (!Osd::getInstance()->isInitted()) return -1;\r
+  \r
+  IDirectFB*dfb=((OsdDirectFB*)Osd::getInstance())->getDfb();\r
+printf("ich bin doof");fflush(stdout);  \r
+  if (screen == this) \r
+  {\r
+    IDirectFBDisplayLayer *osd_layer=((OsdDirectFB*)Osd::getInstance())->getOsdLayer();\r
+    if (osd_layer->GetSurface(osd_layer,&surface)!=DFB_OK) \r
+    {\r
+\r
+       return 0;\r
+    }\r
+    surface->Clear(surface,0x0,0x0,0x0,0xFF);\r
+  } else {\r
+    DFBSurfaceDescription dsc;\r
+    memset(&dsc,0,sizeof(dsc));\r
+    *((int*)&dsc.flags)=DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT;\r
+    \r
+    dsc.width=width;\r
+    dsc.height=height;\r
+    dsc.caps= DSCAPS_NONE;\r
+    if (dfb->CreateSurface(dfb,&dsc,&surface)!=DFB_OK) \r
+    {\r
+       return 0;\r
+    }\r
+  }\r
+  return 1;\r
+}\r
+\r
+void SurfaceDirectFB::display()\r
+{\r
+//  unsigned long fb_descriptor[2];\r
+/*\r
+  fb_descriptor[0] = surface.sfc.handle;\r
+  fb_descriptor[1] = 1;\r
+*/\r
+//  ioctl(fdOsd, GFX_FB_ATTACH, fb_descriptor);\r
+}\r
+\r
+\r
+// ----------------------------------------------------------------------------\r
+\r
+// Now for the drawing functions\r
+\r
+\r
+int SurfaceDirectFB::fillblt(int x, int y, int width, int height, unsigned int c)\r
+{\r
+    int sw,sh;\r
+    unsigned char r,g,b,a;\r
+    int nx,ny,nw,nh;\r
+    nx=x;\r
+    ny=y;\r
+    nw=width;\r
+    nh=height;\r
+    surface->GetSize(surface,&sw,&sh);\r
+    \r
+    if (nx >sw) nx=sw-1;\r
+    if (ny >sh) ny=sh-1;\r
+    \r
+    if ((nx+nw) >= sw) nw=sw-nx; \r
+    if ((ny+nh) >= sh) nh=sh-ny; \r
+\r
+    if ((nx<0) || (ny < 0) || (nh <=0) || (nw <=0)) {\r
+       return 0;\r
+    }\r
+    \r
+    a= (c &0xff000000)>>24;\r
+    r= (c &0x00ff0000)>>16;\r
+    g= (c &0x0000ff00)>>8;\r
+    b= (c &0x000000ff);\r
+    \r
+    \r
+    surface->SetColor(surface,r,g,b,a);\r
+    surface->FillRectangle(surface,nx,ny,nw,nh);\r
+    return 0;\r
+}\r
+\r
+void SurfaceDirectFB::drawPixel(int x, int y, unsigned int c, bool fastdraw)\r
+{\r
+    int sw,sh;\r
+    unsigned char r,g,b,a;\r
+    char *dst=NULL;\r
+    int offset=0;\r
+    int pitch;\r
+    surface->GetSize(surface,&sw,&sh);\r
+    if (x>=sw) return;\r
+    if (y>=sh) return;\r
+    \r
+\r
+    \r
+    a= (c &0xff000000)>>24;\r
+    r= (c &0x00ff0000)>>16;\r
+    g= (c &0x0000ff00)>>8;\r
+    b= (c &0x000000ff);\r
+\r
+    //TODO Fastdraw\r
+    if (surface->Lock(surface,DSLF_WRITE,(void**)(void*)&dst,&pitch) == DFB_OK) {\r
+       offset= y* pitch+x*4;\r
+       dst[offset++]=b;\r
+       dst[offset++]=g;\r
+       dst[offset++]=r;\r
+       dst[offset]=a;\r
+       surface->Unlock(surface);\r
+     }\r
+\r
+}\r
+\r
+void SurfaceDirectFB::drawPixel(int x, int y, Colour& c, bool fastdraw)\r
+{\r
+    int sw,sh;\r
+    char *dst=NULL;\r
+    int offset=0;\r
+    int pitch;\r
+    surface->GetSize(surface,&sw,&sh);\r
+    if (x>=sw) return;\r
+    if (y>=sh) return;\r
+    \r
+    //TODO Fastdraw\r
+    if (surface->Lock(surface,DSLF_WRITE,(void**)(void*)&dst,&pitch) == DFB_OK) {\r
+       offset= y* pitch+x*4;\r
+       dst[offset++]=c.blue;\r
+       dst[offset++]=c.green;\r
+       dst[offset++]=c.red;\r
+       dst[offset]=c.alpha;\r
+       surface->Unlock(surface);\r
+     }\r
+\r
+}\r
\r
+void SurfaceDirectFB::drawHorzLine(int x1, int x2, int y, unsigned int c)\r
+{\r
+  fillblt(x1, y, x2-x1, 1, c);\r
+}\r
+\r
+void SurfaceDirectFB::drawVertLine(int x, int y1, int y2, unsigned int c)\r
+{\r
+  fillblt(x, y1, 1, y2-y1, c);\r
+}\r
+\r
+void SurfaceDirectFB::drawBitmap(int x, int y, const Bitmap& bm)\r
+{/*\r
+  UINT bmw = bm.getWidth(); UINT bmh = bm.getHeight();\r
+  if (bmw == 0 || bmh == 0) return;\r
+  if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height)) return;\r
+  int remainder = (surface.sfc.width % 4);\r
+  UINT line;\r
+  if (remainder == 0)\r
+    line = surface.sfc.width;\r
+  else\r
+    line = surface.sfc.width + (4 - remainder);\r
+  const std::vector<UCHAR>& bmdata = bm.rawData();\r
+  const std::vector<UCHAR>& Y = bm.palette.getYVector();\r
+  const std::vector<UCHAR>& Cr = bm.palette.getCrVector();\r
+  const std::vector<UCHAR>& Cb = bm.palette.getCbVector();\r
+  const std::vector<UCHAR>& A = bm.palette.getAVector();\r
+  UINT b_offset = 0;\r
+  UINT s_offset = x + y*line;\r
+  UINT plotWidth = bmw;\r
+  UINT plotHeight = bmh;\r
+  if (x + plotWidth - 1 > surface.sfc.width)\r
+    plotWidth = surface.sfc.width - x + 1;\r
+  if (y + plotHeight - 1 > surface.sfc.height)\r
+    plotHeight = surface.sfc.height - y + 1;\r
+  for (UINT j = 0; j < plotHeight; ++j)\r
+  {\r
+    UINT i = 0;\r
+    if (x & 1) // odd x - need to plot first column separately\r
+    {\r
+      UCHAR index = bmdata[b_offset];\r
+      *(surface.base[0] + s_offset) = Y[index];\r
+      *(surface.base[1] + s_offset - 1) = Cb[index];\r
+      *(surface.base[1] + s_offset) = Cr[index];\r
+      *(surface.base[2] + s_offset) = A[index];\r
+      i = 1;\r
+    }\r
+    // Now, plot pairs of pixels with averaged chroma values\r
+    while (i < plotWidth - 1)\r
+    {\r
+      UCHAR index1 = bmdata[b_offset + i];\r
+      UCHAR index2 = bmdata[b_offset + i + 1];\r
+      *(surface.base[0] + s_offset + i) = Y[index1];\r
+      *(surface.base[0] + s_offset + i + 1) = Y[index2];\r
+      *(surface.base[1] + s_offset + i) = (Cb[index1] + Cb[index2]) / 2;\r
+      *(surface.base[1] + s_offset + i + 1) = (Cr[index1] + Cr[index2]) / 2;\r
+      *(surface.base[2] + s_offset + i) = A[index1];\r
+      *(surface.base[2] + s_offset + i + 1) = A[index2];\r
+      i += 2;\r
+    }\r
+    if (i == plotWidth - 1) // One column left to do\r
+    {\r
+      UCHAR index = bmdata[b_offset + i];\r
+      *(surface.base[0] + s_offset + i) = Y[index];\r
+      *(surface.base[1] + s_offset + i) = Cb[index];\r
+      *(surface.base[1] + s_offset + i + 1) = Cr[index];\r
+      *(surface.base[2] + s_offset + i) = A[index];\r
+    }\r
+    s_offset += line;\r
+    b_offset += bmw;\r
+  }*/\r
+}\r
+\r
+  /* surface update to screen needs:\r
+  source x distance into this surface\r
+  source y distance into this surface\r
+  width of update\r
+  height of update\r
+  destination x on screen\r
+  destination y on screen\r
+  */\r
+int SurfaceDirectFB::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME\r
+{\r
+  IDirectFBSurface* screensurf=((SurfaceDirectFB*)screen)->getSurfaceDFB();\r
+  if (!screensurf) return 0;\r
+  if (this==screen) return 0;\r
+  \r
+  DFBRectangle rect;\r
+  int sw,sh;\r
+  \r
+  screensurf->GetSize(screensurf,&sw,&sh);\r
+//  screensurf->Clear(screensurf,0x0,0x0,0x0,0xFF);\r
+  rect.x = sx;\r
+  rect.y=sy;\r
+  rect.w=w;\r
+  rect.h=h;\r
+  \r
+  DFBRectangle drect; //TODO make osd HD\r
+  drect.x=dx*sw/720;\r
+  drect.y=dy*sh/576;\r
+  drect.w=w*sw/720;\r
+  drect.h=h*sh/576;\r
+  \r
+//  screensurf->Blit(screensurf,surface,&rect,dx,dy);\r
+  screensurf->StretchBlit(screensurf,surface,&rect,&drect);\r
+  \r
+  return 0;//blt(fdOsd, surface.sfc.handle, sx, sy, w, h, ((SurfaceDirectFB*)screen)->getSurfaceHandle(), dx, dy);\r
+}\r
+\r
+int SurfaceDirectFB::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)\r
+{//Skip it, noone uses this!\r
+\r
+  return 0;\r
+}\r
+\r
+void SurfaceDirectFB::screenShot(const char* fileName)\r
+{\r
+  return;\r
+  \r
+}\r
+\r
+void SurfaceDirectFB::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)\r
+{\r
+  \r
+}\r
+\r
index 1171f32fb9f5b5fb44f115844ef94b5834a455f4..74c307b892c464940d1a7e38890ea1e1c0c73c57 100644 (file)
@@ -1,73 +1,73 @@
-/*
-    Copyright 2004-2005 Chris Tallon, 2009 Marten Richter
-    Portions copyright 2004 Jon Gettler
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef SURFACEDirectFB_H
-#define SURFACEDirectFB_H
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-
-extern "C"
-{
-  #include <jpeglib.h>
-}
-
-#include "defines.h"
-#include "surface.h"
-
-#include <directfb.h>
-
-
-
-class SurfaceDirectFB : public Surface
-{
-  public:
-    SurfaceDirectFB(int id = 0);
-    ~SurfaceDirectFB();
-
-    int create(UINT width, UINT height);
-    void display();
-
-    int fillblt(int x, int y, int width, int height, unsigned int rgba);
-    void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);
-    void drawPixel(int x, int y, Colour& c, bool fastdraw=false);
-    void drawHorzLine(int x1, int x2, int y, unsigned int c);
-    void drawVertLine(int x, int y1, int y2, unsigned int c);
-    void drawBitmap(int x, int y, const Bitmap& bm);
-    int updateToScreen(int sx, int sy, int w, int h, int dx, int dy);
-    void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b);
-    void screenShot(char* fileName);
-    IDirectFBSurface* getSurfaceDFB(){return surface;};
-
-
-    int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy);
-
-  private:
-    IDirectFBSurface *surface;
-
-
-
-};
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon, 2009 Marten Richter\r
+    Portions copyright 2004 Jon Gettler\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef SURFACEDirectFB_H\r
+#define SURFACEDirectFB_H\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+#include <sys/mman.h>\r
+#include <sys/ioctl.h>\r
+\r
+extern "C"\r
+{\r
+  #include <jpeglib.h>\r
+}\r
+\r
+#include "defines.h"\r
+#include "surface.h"\r
+\r
+#include <directfb.h>\r
+\r
+\r
+\r
+class SurfaceDirectFB : public Surface\r
+{\r
+  public:\r
+    SurfaceDirectFB(int id = 0);\r
+    ~SurfaceDirectFB();\r
+\r
+    int create(UINT width, UINT height);\r
+    void display();\r
+\r
+    int fillblt(int x, int y, int width, int height, unsigned int rgba);\r
+    void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);\r
+    void drawPixel(int x, int y, Colour& c, bool fastdraw=false);\r
+    void drawHorzLine(int x1, int x2, int y, unsigned int c);\r
+    void drawVertLine(int x, int y1, int y2, unsigned int c);\r
+    void drawBitmap(int x, int y, const Bitmap& bm);\r
+    int updateToScreen(int sx, int sy, int w, int h, int dx, int dy);\r
+    void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b);\r
+    void screenShot(const char* fileName);\r
+    IDirectFBSurface* getSurfaceDFB(){return surface;};\r
+\r
+\r
+    int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy);\r
+\r
+  private:\r
+    IDirectFBSurface *surface;\r
+\r
+\r
+\r
+};\r
+\r
+#endif\r
index 2260ac935aadd09f2678a77be67bfb2568870c4e..373a0c780874e4d7a89dc995f213437880784460 100644 (file)
-/*
-    Copyright 2006 Marten Richter
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "surfacewin.h"
-#include "osdwin.h"
-#include "bitmap.h"
-#include "log.h"
-
-SurfaceWin::SurfaceWin(int id)
-: Surface(id)
-{
-  d3dtexture=NULL;
-  d3dsurface=NULL;
-  sheight=swidth=0;
-//  fastdraw=false;
-  event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);
-}
-
-SurfaceWin::~SurfaceWin()
-{
-       if (d3dsurface) d3dsurface->Release();
-       if (d3dtexture) d3dtexture->Release();
-       CloseHandle(event);
-}
-
-int SurfaceWin::create(UINT width, UINT height)
-{
-       OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-
-
-       LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();
-
-       while (true) {
-               if (screen==this) {
-                       osd->BeginPainting();
-                       if (d3ddev->CreateTexture(1024,1024,0,0,D3DFMT_A8R8G8B8,
-                               // Does every adapter with alpha blending support this?
-                               D3DPOOL_DEFAULT,&d3dtexture ,NULL)!=D3D_OK) {
-                                       osd->EndPainting();
-                                       MILLISLEEP(50);//wait maybe next time it will work
-                                       continue;
-                       }
-                       if (d3dtexture->GetSurfaceLevel(0,&d3dsurface)!=D3D_OK) {
-                               d3dtexture->Release();
-                               d3dtexture=NULL;
-                               MILLISLEEP(50);
-                               osd->EndPainting();
-                               continue;
-                       }
-               } else {
-                       HRESULT hres;
-                       if (hres=d3ddev->CreateOffscreenPlainSurface(width,height,D3DFMT_A8R8G8B8,
-                               D3DPOOL_SYSTEMMEM,&d3dsurface,NULL)!=D3D_OK) {
-                                       osd->EndPainting();
-                                       MILLISLEEP(50);//wait maybe next time it will work
-
-                                       continue;
-                       }
-
-               }
-               osd->EndPainting();
-
-               sheight=height;
-               swidth=width;
-               /* If someone does high performance Animations on the OSD, we have to change the types
-               of surface in order to address these performance issues, if we have only very few updates
-               per second this would be fast enough !*/
-               break;
-       }
-       SetEvent(event);
-       return 1;
-}
-
-void SurfaceWin::display()
-{
-}
-
-int SurfaceWin::fillblt(int x, int y, int width, int height, unsigned int c)
-{
-  WaitForSingleObject(event,INFINITE); //since this might be called before surface
-  //allocation we will wait in this case, hopefully without deadlocks
-  OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-
-  if (!d3dsurface) {
-    return 0; //why does this happen
-  }
-
-  LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();
-
-  if (screen==this) {
-    //This should not happen!
-    return 0;
-
-  } else {
-    osd->BeginPainting();
-    D3DLOCKED_RECT lockrect;
-    int cx,cy,cwidth,cheight;
-    cx=min(max(x,0),swidth-1);
-    cy=min(max(y,0),sheight-1);
-    cwidth=min(width,swidth-x);
-    cheight=min(height,sheight-y);
-    RECT rect={cx,cy,cwidth,cheight};
-
-    if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {
-      return 0;
-    }
-    unsigned int line;
-    unsigned int column;
-    for (line=0;line<cheight;line++) {
-      unsigned int*row=((unsigned int*)(((char*)lockrect.pBits)+lockrect.Pitch*line));
-      for (column=0;column<cwidth;column++) {
-        row[column]=c;
-      }
-    }
-
-    if (d3dsurface->UnlockRect()!=D3D_OK) {
-      osd->EndPainting();
-      return 0;
-    }
-    osd->EndPainting();
-  }
-
-  return 0;
-}
-
-
-void SurfaceWin::startFastDraw(){
-    WaitForSingleObject(event,INFINITE); //since this might be called before surface
-  //allocation we will wait in this case, hopefully without deadlocks
-  if (!d3dsurface) {
-    return; //why does this happen
-  }
-  OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-  LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();
-  if (screen==this) {
-    //This should not happen!
-    return ;
-
-  } else {
-    osd->BeginPainting();
-//    D3DLOCKED_RECT lockrect;
-    RECT rect={0,0,swidth,sheight};
-    if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {
-      osd->EndPainting();
-      return ;
-    }
-  }
-//  fastdraw=true;
-}
-void SurfaceWin::endFastDraw(){
-    OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-    if (d3dsurface->UnlockRect()!=D3D_OK) {
-      osd->EndPainting();
-      return ;
-    }
-    osd->EndPainting();
-//    fastdraw=false;
- }
-
-void SurfaceWin::drawPixel(int x, int y, Colour & colour, bool fastdraw) {
-  int c = (  (0xFF000000         )
-             | (colour.red    << 16)
-             | (colour.green  <<  8)
-             | (colour.blue        ) );
-
-    drawPixel(x, y, c, fastdraw);
-  }
-
-void SurfaceWin::drawPixel(int x, int y, unsigned int c, bool fastdraw)
-{
-  //FixMe: locking for every single Pixel will be painfully slow
-    OsdWin* osd;
-    if (!fastdraw) {
-  WaitForSingleObject(event,INFINITE); //since this might be called before surface
-  //allocation we will wait in this case, hopefully without deadlocks
-  if (!d3dsurface) {
-    return; //why does this happen
-  }
-         osd=((OsdWin*)(Osd::getInstance()));
-    }
-  if (x>=swidth || y>=sheight) return; //do not draw outside the surface
-  if (screen==this) {
-    //This should not happen!
-    return ;
-
-  } else {
-      if (!fastdraw) {
-    osd->BeginPainting();
-//        D3DLOCKED_RECT lockrect;
-    RECT rect={x,y,x+1,y+1};
-    if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {
-      osd->EndPainting();
-      return ;
-    }
-    unsigned int*row=(unsigned int*)(((char*)lockrect.pBits));
-    row[0]=c;
-    if (d3dsurface->UnlockRect()!=D3D_OK) {
-      osd->EndPainting();
-      return ;
-    }
-    osd->EndPainting();
-      } else {
-          unsigned int*row=(unsigned int*)(((char*)lockrect.pBits+lockrect.Pitch*y+4*x));
-          row[0]=c;
-      }
-
-  }
-
-}
-
-void SurfaceWin::drawHorzLine(int x1, int x2, int y, unsigned int c)
-{
-   fillblt(x1, y, x2-x1, 1, c);
-}
-
-void SurfaceWin::drawVertLine(int x, int y1, int y2, unsigned int c)
-{
-  fillblt(x, y1, 1, y2-y1, c);
-}
-
-void SurfaceWin::drawBitmap(int x, int y, const Bitmap& bm)
-{
-  // Temporary code? Draw one pixel at a time using drawPixel()
-  startFastDraw();
-  for (UINT j = 0; j < bm.getHeight(); ++j)
-    for (UINT i = 0; i < bm.getWidth(); ++i)
-      drawPixel(x+i, y+j, bm.getColour(i,j),true);
-  endFastDraw();
-}
-
-int SurfaceWin::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME
-{
-  WaitForSingleObject(event,INFINITE); //since this might be called before surface
-  //allocation we will wait in this case, hopefully without deadlocks
-  if (!d3dsurface) {
-    return 0; //why does this happen
-  }
-  OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-  LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();
-    LPDIRECT3DSURFACE9 screensurface=((SurfaceWin*)screen)->getD3dsurface();
-  if (!screensurface) return 0;
-  RECT sourcerect={sx,sy,sx+w,sy+h};
-  POINT destpoint={dx,dy};
-  osd->BeginPainting();
-  if (d3ddev->UpdateSurface(d3dsurface,&sourcerect,screensurface,&destpoint)!=D3D_OK) {
-    Log::getInstance()->log("Surface", Log::DEBUG, "Could not update to Screen!");
-    osd->EndPainting();
-    return 0;
-  }
-  osd->EndPainting();
-  return 0;
-}
-
-int SurfaceWin::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)
-{
-  //I don't see code using this function, so I skip it, since it is a MVP specific interface
-  return 0;
-}
-
-void SurfaceWin::screenShot(char* fileName)
-{
-  //Isn't this for debugging only, so I won't implement it yet
-}
-
-void SurfaceWin::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)
-{
-  //Isn't this for debugging only, so I won't implement it yet
-}
-void SurfaceWin::ReleaseSurface()
-{
-  ResetEvent(event);
-  LPDIRECT3DSURFACE9 temp_surf=d3dsurface;
-  LPDIRECT3DTEXTURE9 temp_text=d3dtexture;
-  d3dsurface=NULL;
-  d3dtexture=NULL;
-  sheight=swidth=0;
-  if (temp_surf) temp_surf->Release();
-  if (temp_text) temp_text->Release();
-}
-/*
-void SurfaceWin::drawJpeg(char *fileName,DWORD x, DWORD y,DWORD *width, DWORD *height){
-  WaitForSingleObject(event,INFINITE); //since this might be called before surface
-  //allocation we will wait in this case, hopefully without deadlocks
-  if (!d3dsurface) {
-    return ; //why does this happen
-  }
-  OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-
-
-  D3DXIMAGE_INFO image_inf;
-  osd->BeginPainting();
-//  D3DXGetImageInfoFromFile(fileName,&image_inf);
-  D3DXGetImageInfoFromResource(NULL,fileName,&image_inf);
-  RECT dest_rec={x,y,x+image_inf.Width,
-    y+image_inf.Height};
-/*  if (D3DXLoadSurfaceFromFile(
-    d3dsurface,
-    NULL,
-    &dest_rec,
-    fileName,
-    NULL,
-    D3DX_FILTER_NONE,
-    0,
-    &image_inf)!=D3D_OK) {
-      Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");
-
-  }*
-  if (D3DXLoadSurfaceFromResource(
-    d3dsurface,
-    NULL,
-    &dest_rec,
-    NULL,
-    fileName,
-    NULL,
-    D3DX_FILTER_NONE,
-    0,
-    &image_inf)!=D3D_OK) {
-      Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");
-
-  }
-  osd->EndPainting();
-  *width=image_inf.Width;
-  *height=image_inf.Height;
-
-}
-
-void SurfaceWin::drawJpeg(char *buffer,ULONG buflength,DWORD x, DWORD y,DWORD *width, DWORD *height){
-  WaitForSingleObject(event,INFINITE); //since this might be called before surface
-  //allocation we will wait in this case, hopefully without deadlocks
-  if (!d3dsurface) {
-    return ; //why does this happen
-  }
-  OsdWin* osd=((OsdWin*)(Osd::getInstance()));
-
-
-  D3DXIMAGE_INFO image_inf;
-  osd->BeginPainting();
-//  D3DXGetImageInfoFromFile(fileName,&image_inf);
-  D3DXGetImageInfoFromFileInMemory((void*)buffer,buflength,&image_inf);
-  RECT dest_rec={x,y,x+image_inf.Width,
-    y+image_inf.Height};
-/*  if (D3DXLoadSurfaceFromFile(
-    d3dsurface,
-    NULL,
-    &dest_rec,
-    fileName,
-    NULL,
-    D3DX_FILTER_NONE,
-    0,
-    &image_inf)!=D3D_OK) {
-      Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");
-
-  }*/
-/*  if (D3DXLoadSurfaceFromResource(
-    d3dsurface,
-    NULL,
-    &dest_rec,
-    NULL,
-    fileName,
-    NULL,
-    D3DX_FILTER_NONE,
-    0,
-    &image_inf)!=D3D_OK) {
-      Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");
-
-  }*
-  if (D3DXLoadSurfaceFromFileInMemory(
-    d3dsurface,
-    NULL,
-    &dest_rec,
-    (void*)buffer,
-    buflength,
-    NULL,
-    D3DX_FILTER_NONE,
-    0,
-    &image_inf)!=D3D_OK) {
-      Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");
-
-  }
-  osd->EndPainting();
-  *width=image_inf.Width;
-  *height=image_inf.Height;
-
-}*/
-
+/*\r
+    Copyright 2006 Marten Richter\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "surfacewin.h"\r
+#include "osdwin.h"\r
+#include "bitmap.h"\r
+#include "log.h"\r
+\r
+SurfaceWin::SurfaceWin(int id)\r
+: Surface(id)\r
+{\r
+  d3dtexture=NULL;\r
+  d3dsurface=NULL;\r
+  sheight=swidth=0;\r
+//  fastdraw=false;\r
+  event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);\r
+}\r
+\r
+SurfaceWin::~SurfaceWin()\r
+{\r
+       if (d3dsurface) d3dsurface->Release();\r
+       if (d3dtexture) d3dtexture->Release();\r
+       CloseHandle(event);\r
+}\r
+\r
+int SurfaceWin::create(UINT width, UINT height)\r
+{\r
+       OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+\r
+       LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();\r
+\r
+       while (true) {\r
+               if (screen==this) {\r
+                       osd->BeginPainting();\r
+                       if (d3ddev->CreateTexture(1024,1024,0,0,D3DFMT_A8R8G8B8,\r
+                               // Does every adapter with alpha blending support this?\r
+                               D3DPOOL_DEFAULT,&d3dtexture ,NULL)!=D3D_OK) {\r
+                                       osd->EndPainting();\r
+                                       MILLISLEEP(50);//wait maybe next time it will work\r
+                                       continue;\r
+                       }\r
+                       if (d3dtexture->GetSurfaceLevel(0,&d3dsurface)!=D3D_OK) {\r
+                               d3dtexture->Release();\r
+                               d3dtexture=NULL;\r
+                               MILLISLEEP(50);\r
+                               osd->EndPainting();\r
+                               continue;\r
+                       }\r
+               } else {\r
+                       HRESULT hres;\r
+                       if (hres=d3ddev->CreateOffscreenPlainSurface(width,height,D3DFMT_A8R8G8B8,\r
+                               D3DPOOL_SYSTEMMEM,&d3dsurface,NULL)!=D3D_OK) {\r
+                                       osd->EndPainting();\r
+                                       MILLISLEEP(50);//wait maybe next time it will work\r
+\r
+                                       continue;\r
+                       }\r
+\r
+               }\r
+               osd->EndPainting();\r
+\r
+               sheight=height;\r
+               swidth=width;\r
+               /* If someone does high performance Animations on the OSD, we have to change the types\r
+               of surface in order to address these performance issues, if we have only very few updates\r
+               per second this would be fast enough !*/\r
+               break;\r
+       }\r
+       SetEvent(event);\r
+       return 1;\r
+}\r
+\r
+void SurfaceWin::display()\r
+{\r
+}\r
+\r
+int SurfaceWin::fillblt(int x, int y, int width, int height, unsigned int c)\r
+{\r
+  WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+  //allocation we will wait in this case, hopefully without deadlocks\r
+  OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+  if (!d3dsurface) {\r
+    return 0; //why does this happen\r
+  }\r
+\r
+  LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();\r
+\r
+  if (screen==this) {\r
+    //This should not happen!\r
+    return 0;\r
+\r
+  } else {\r
+    osd->BeginPainting();\r
+    D3DLOCKED_RECT lockrect;\r
+    int cx,cy,cwidth,cheight;\r
+    cx=min(max(x,0),swidth-1);\r
+    cy=min(max(y,0),sheight-1);\r
+    cwidth=min(width,swidth-x);\r
+    cheight=min(height,sheight-y);\r
+    RECT rect={cx,cy,cwidth,cheight};\r
+\r
+    if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {\r
+      return 0;\r
+    }\r
+    unsigned int line;\r
+    unsigned int column;\r
+    for (line=0;line<cheight;line++) {\r
+      unsigned int*row=((unsigned int*)(((char*)lockrect.pBits)+lockrect.Pitch*line));\r
+      for (column=0;column<cwidth;column++) {\r
+        row[column]=c;\r
+      }\r
+    }\r
+\r
+    if (d3dsurface->UnlockRect()!=D3D_OK) {\r
+      osd->EndPainting();\r
+      return 0;\r
+    }\r
+    osd->EndPainting();\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+\r
+void SurfaceWin::startFastDraw(){\r
+    WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+  //allocation we will wait in this case, hopefully without deadlocks\r
+  if (!d3dsurface) {\r
+    return; //why does this happen\r
+  }\r
+  OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+  LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();\r
+  if (screen==this) {\r
+    //This should not happen!\r
+    return ;\r
+\r
+  } else {\r
+    osd->BeginPainting();\r
+//    D3DLOCKED_RECT lockrect;\r
+    RECT rect={0,0,swidth,sheight};\r
+    if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {\r
+      osd->EndPainting();\r
+      return ;\r
+    }\r
+  }\r
+//  fastdraw=true;\r
+}\r
+void SurfaceWin::endFastDraw(){\r
+    OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+    if (d3dsurface->UnlockRect()!=D3D_OK) {\r
+      osd->EndPainting();\r
+      return ;\r
+    }\r
+    osd->EndPainting();\r
+//    fastdraw=false;\r
+ }\r
+\r
+void SurfaceWin::drawPixel(int x, int y, Colour & colour, bool fastdraw) {\r
+  int c = (  (0xFF000000         )\r
+             | (colour.red    << 16)\r
+             | (colour.green  <<  8)\r
+             | (colour.blue        ) );\r
+\r
+    drawPixel(x, y, c, fastdraw);\r
+  }\r
+\r
+void SurfaceWin::drawPixel(int x, int y, unsigned int c, bool fastdraw)\r
+{\r
+  //FixMe: locking for every single Pixel will be painfully slow\r
+    OsdWin* osd;\r
+    if (!fastdraw) {\r
+  WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+  //allocation we will wait in this case, hopefully without deadlocks\r
+  if (!d3dsurface) {\r
+    return; //why does this happen\r
+  }\r
+         osd=((OsdWin*)(Osd::getInstance()));\r
+    }\r
+  if (x>=swidth || y>=sheight) return; //do not draw outside the surface\r
+  if (screen==this) {\r
+    //This should not happen!\r
+    return ;\r
+\r
+  } else {\r
+      if (!fastdraw) {\r
+    osd->BeginPainting();\r
+//        D3DLOCKED_RECT lockrect;\r
+    RECT rect={x,y,x+1,y+1};\r
+    if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) {\r
+      osd->EndPainting();\r
+      return ;\r
+    }\r
+    unsigned int*row=(unsigned int*)(((char*)lockrect.pBits));\r
+    row[0]=c;\r
+    if (d3dsurface->UnlockRect()!=D3D_OK) {\r
+      osd->EndPainting();\r
+      return ;\r
+    }\r
+    osd->EndPainting();\r
+      } else {\r
+          unsigned int*row=(unsigned int*)(((char*)lockrect.pBits+lockrect.Pitch*y+4*x));\r
+          row[0]=c;\r
+      }\r
+\r
+  }\r
+\r
+}\r
+\r
+void SurfaceWin::drawHorzLine(int x1, int x2, int y, unsigned int c)\r
+{\r
+   fillblt(x1, y, x2-x1, 1, c);\r
+}\r
+\r
+void SurfaceWin::drawVertLine(int x, int y1, int y2, unsigned int c)\r
+{\r
+  fillblt(x, y1, 1, y2-y1, c);\r
+}\r
+\r
+void SurfaceWin::drawBitmap(int x, int y, const Bitmap& bm)\r
+{\r
+  // Temporary code? Draw one pixel at a time using drawPixel()\r
+  startFastDraw();\r
+  for (UINT j = 0; j < bm.getHeight(); ++j)\r
+    for (UINT i = 0; i < bm.getWidth(); ++i)\r
+      drawPixel(x+i, y+j, bm.getColour(i,j),true);\r
+  endFastDraw();\r
+}\r
+\r
+int SurfaceWin::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME\r
+{\r
+  WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+  //allocation we will wait in this case, hopefully without deadlocks\r
+  if (!d3dsurface) {\r
+    return 0; //why does this happen\r
+  }\r
+  OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+  LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev();\r
+    LPDIRECT3DSURFACE9 screensurface=((SurfaceWin*)screen)->getD3dsurface();\r
+  if (!screensurface) return 0;\r
+  RECT sourcerect={sx,sy,sx+w,sy+h};\r
+  POINT destpoint={dx,dy};\r
+  osd->BeginPainting();\r
+  if (d3ddev->UpdateSurface(d3dsurface,&sourcerect,screensurface,&destpoint)!=D3D_OK) {\r
+    Log::getInstance()->log("Surface", Log::DEBUG, "Could not update to Screen!");\r
+    osd->EndPainting();\r
+    return 0;\r
+  }\r
+  osd->EndPainting();\r
+  return 0;\r
+}\r
+\r
+int SurfaceWin::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)\r
+{\r
+  //I don't see code using this function, so I skip it, since it is a MVP specific interface\r
+  return 0;\r
+}\r
+\r
+void SurfaceWin::screenShot(const char* fileName)\r
+{\r
+  //Isn't this for debugging only, so I won't implement it yet\r
+}\r
+\r
+void SurfaceWin::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)\r
+{\r
+  //Isn't this for debugging only, so I won't implement it yet\r
+}\r
+void SurfaceWin::ReleaseSurface()\r
+{\r
+  ResetEvent(event);\r
+  LPDIRECT3DSURFACE9 temp_surf=d3dsurface;\r
+  LPDIRECT3DTEXTURE9 temp_text=d3dtexture;\r
+  d3dsurface=NULL;\r
+  d3dtexture=NULL;\r
+  sheight=swidth=0;\r
+  if (temp_surf) temp_surf->Release();\r
+  if (temp_text) temp_text->Release();\r
+}\r
+\r
+void SurfaceWin::drawJpeg(const char *fileName,int x, int y,int *width, int *height){\r
+  WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+  //allocation we will wait in this case, hopefully without deadlocks\r
+  if (!d3dsurface) {\r
+    return ; //why does this happen\r
+  }\r
+  OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+\r
+  D3DXIMAGE_INFO image_inf;\r
+  osd->BeginPainting();\r
+//  D3DXGetImageInfoFromFile(fileName,&image_inf);\r
+  D3DXGetImageInfoFromResource(NULL,fileName,&image_inf);\r
+  RECT dest_rec={x,y,x+image_inf.Width,\r
+    y+image_inf.Height};\r
+/*  if (D3DXLoadSurfaceFromFile(\r
+    d3dsurface,\r
+    NULL,\r
+    &dest_rec,\r
+    fileName,\r
+    NULL,\r
+    D3DX_FILTER_NONE,\r
+    0,\r
+    &image_inf)!=D3D_OK) {\r
+      Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+  }*/\r
+  if (D3DXLoadSurfaceFromResource(\r
+    d3dsurface,\r
+    NULL,\r
+    &dest_rec,\r
+    NULL,\r
+    fileName,\r
+    NULL,\r
+    D3DX_FILTER_NONE,\r
+    0,\r
+    &image_inf)!=D3D_OK) {\r
+      Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+  }\r
+  osd->EndPainting();\r
+  *width=image_inf.Width;\r
+  *height=image_inf.Height;\r
+\r
+}\r
+\r
+/*\r
+void SurfaceWin::drawJpeg(char *buffer,ULONG buflength,DWORD x, DWORD y,DWORD *width, DWORD *height){\r
+  WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+  //allocation we will wait in this case, hopefully without deadlocks\r
+  if (!d3dsurface) {\r
+    return ; //why does this happen\r
+  }\r
+  OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+\r
+  D3DXIMAGE_INFO image_inf;\r
+  osd->BeginPainting();\r
+//  D3DXGetImageInfoFromFile(fileName,&image_inf);\r
+  D3DXGetImageInfoFromFileInMemory((void*)buffer,buflength,&image_inf);\r
+  RECT dest_rec={x,y,x+image_inf.Width,\r
+    y+image_inf.Height};\r
+/*  if (D3DXLoadSurfaceFromFile(\r
+    d3dsurface,\r
+    NULL,\r
+    &dest_rec,\r
+    fileName,\r
+    NULL,\r
+    D3DX_FILTER_NONE,\r
+    0,\r
+    &image_inf)!=D3D_OK) {\r
+      Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+  }*/\r
+/*  if (D3DXLoadSurfaceFromResource(\r
+    d3dsurface,\r
+    NULL,\r
+    &dest_rec,\r
+    NULL,\r
+    fileName,\r
+    NULL,\r
+    D3DX_FILTER_NONE,\r
+    0,\r
+    &image_inf)!=D3D_OK) {\r
+      Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+  }*\r
+  if (D3DXLoadSurfaceFromFileInMemory(\r
+    d3dsurface,\r
+    NULL,\r
+    &dest_rec,\r
+    (void*)buffer,\r
+    buflength,\r
+    NULL,\r
+    D3DX_FILTER_NONE,\r
+    0,\r
+    &image_inf)!=D3D_OK) {\r
+      Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+  }\r
+  osd->EndPainting();\r
+  *width=image_inf.Width;\r
+  *height=image_inf.Height;\r
+\r
+}*/\r
+\r
index 8d9cd9dfe63cc051098cc27b79a3857efb8c1edd..99499728d4116cf0464dc2472fda67eeed91a657 100644 (file)
@@ -1,65 +1,65 @@
-/*
-    Copyright 2006 Marten Richter
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef SURFACEWIN_H
-#define SURFACEWIN_H
-
-#include "defines.h"
-#include "surface.h"
-#include <winsock2.h>
-#include <d3d9.h>
-
-class SurfaceWin : public Surface
-{
-  public:
-    SurfaceWin(int id = 0);
-    ~SurfaceWin();
-
-    int create(UINT width, UINT height);
-    void display();
-
-    void startFastDraw();
-    void endFastDraw();
-
-    int fillblt(int x, int y, int width, int height, unsigned int c);
-    void drawPixel(int x, int y, Colour& c, bool fastdraw=false);
-    void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);
-    void drawHorzLine(int x1, int x2, int y, unsigned int c);
-    void drawVertLine(int x, int y1, int y2, unsigned int c);
-    void drawBitmap(int x, int y, const Bitmap& bm);
-    int updateToScreen(int sx, int sy, int w, int h, int dx, int dy);
-    void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b);
-    void screenShot(char* fileName);
-  void ReleaseSurface();
-    int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy);
-/*  void drawJpeg(char *fileName,DWORD x, DWORD y,DWORD *width, DWORD *height);
-  void drawJpeg(char *buffer,ULONG buflength,DWORD x, DWORD y,DWORD *width, DWORD *height);*/
-  LPDIRECT3DSURFACE9 getD3dsurface() {WaitForSingleObject(event,INFINITE);
-    return d3dsurface;};
-  LPDIRECT3DTEXTURE9 getD3dtexture() {return d3dtexture;};
-  private:
-    LPDIRECT3DSURFACE9 d3dsurface;
-    LPDIRECT3DTEXTURE9 d3dtexture;
-    D3DLOCKED_RECT lockrect;
-    UINT sheight,swidth;
-    HANDLE event;
-};
-
-#endif
+/*\r
+    Copyright 2006 Marten Richter\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef SURFACEWIN_H\r
+#define SURFACEWIN_H\r
+\r
+#include "defines.h"\r
+#include "surface.h"\r
+#include <winsock2.h>\r
+#include <d3d9.h>\r
+\r
+class SurfaceWin : public Surface\r
+{\r
+  public:\r
+    SurfaceWin(int id = 0);\r
+    ~SurfaceWin();\r
+\r
+    int create(UINT width, UINT height);\r
+    void display();\r
+\r
+    void startFastDraw();\r
+    void endFastDraw();\r
+\r
+    int fillblt(int x, int y, int width, int height, unsigned int c);\r
+    void drawPixel(int x, int y, Colour& c, bool fastdraw=false);\r
+    void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);\r
+    void drawHorzLine(int x1, int x2, int y, unsigned int c);\r
+    void drawVertLine(int x, int y1, int y2, unsigned int c);\r
+    void drawBitmap(int x, int y, const Bitmap& bm);\r
+    int updateToScreen(int sx, int sy, int w, int h, int dx, int dy);\r
+    void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b);\r
+    void screenShot(const char* fileName);\r
+  void ReleaseSurface();\r
+    int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy);\r
+  void drawJpeg(const char *fileName,int x, int y,int *width, int *height);\r
+/*  void drawJpeg(char *buffer,ULONG buflength,DWORD x, DWORD y,DWORD *width, DWORD *height);*/\r
+  LPDIRECT3DSURFACE9 getD3dsurface() {WaitForSingleObject(event,INFINITE);\r
+    return d3dsurface;};\r
+  LPDIRECT3DTEXTURE9 getD3dtexture() {return d3dtexture;};\r
+  private:\r
+    LPDIRECT3DSURFACE9 d3dsurface;\r
+    LPDIRECT3DTEXTURE9 d3dtexture;\r
+    D3DLOCKED_RECT lockrect;\r
+    UINT sheight,swidth;\r
+    HANDLE event;\r
+};\r
+\r
+#endif\r
index e02700236329d4b9c4bff4d22967c9e3c814b159..1438890168243ba0095bab5d31a9931530c76a74 100644 (file)
--- a/tbboxx.cc
+++ b/tbboxx.cc
@@ -45,7 +45,7 @@ void TBBoxx::setTitleText(const char* takeText, int width)
 
 void TBBoxx::draw()
 {
-  Log::getInstance()->log("TBBoxx", Log::DEBUG, "Draw");
+  //Log::getInstance()->log("TBBoxx", Log::DEBUG, "Draw: %d",this);
   
   fillColour(Colour::VIEWBACKGROUND);
 
index f5d10bc3825fe3be5fce7e537bed0d88829f8ac8..1e97f83a14de258bce2ed3976dfe9ca921d3b53b 100644 (file)
-/*
-    Copyright 2008 Marten Richter
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-
-/* Portions from vdr osdteletext plugin "txtrender.c": */
-/***************************************************************************
- *                                                                         *
- *   txtrender.c - Teletext display abstraction and teletext code          *
- *                 renderer                                                *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   Changelog:                                                            *
- *     2005-03    initial version (c) Udo Richter                          *
- *                                                                         *
- ***************************************************************************/
-
-#include "teletextdecodervbiebu.h"
-#include "teletxt/tables.h"
-#include "message.h"
-#include "command.h"
-#include "video.h"
-
-#ifdef WIN32
-#include <windows.h>
-#endif
-
-TeletextDecoderVBIEBU::TeletextDecoderVBIEBU()
-{
-    selectedpage=0x100;
-    ourpage=false;
-    flags=lang=0; 
-  
-    CleanPage();
-    FirstG0CodePage=0;
-    SecondG0CodePage=0;
-    dirty=false;
-    txtview=NULL;
-    firstlineupdate=0;
-    gotcha=false;
-    char digits[]={'1','0','0'};
-    setKeyinDigits(digits,false);
-    isrecording=false;
-    for (int i=0;i<10;i++) record_pages[i]=-1;
-    
-
-}
-
-TeletextDecoderVBIEBU::~TeletextDecoderVBIEBU()
-{
-
-
-}
-
-long long TeletextDecoderVBIEBU::SetStartOffset(long long curreftime, bool *rsync)
-{
-  return 0;  
-}
-
-void TeletextDecoderVBIEBU::ResetTimeOffsets()
-{
-
-}
-
-
-
-void TeletextDecoderVBIEBU::ResetDecoder()
-{
-    gotcha=false;
-    ourpage=false;
-    firstlineupdate=0;
-    selectedpage=0x100;
-    CleanPage();
-    char digits[]={'1','0','0'};
-    setKeyinDigits(digits,false);
-    for (int i=0;i<10;i++) record_pages[i]=-1;
-  
-}
-
-void TeletextDecoderVBIEBU::setPage(unsigned int newpage)
-{
-    selectedpage=newpage;
-    gotcha=false;
-    ourpage=false;
-    firstlineupdate=0;
-    for (int i=0;i<25;i++) {
-        memset(curpage[i],0,40);
-    }
-}
-
-void TeletextDecoderVBIEBU::CleanPage()
-{
-    int x,y;
-    for (int i=0;i<25;i++) {
-        memset(curpage[i],0,40);
-    }
-    for (y=0;y<25;y++) {
-        for (x=0;x<40;x++) {
-            cTeletextChar c;
-            c.SetFGColor(ttcWhite);
-            c.SetBGColor(ttcBlack);
-            c.SetCharset(CHARSET_LATIN_G0);
-            c.SetChar(' ');
-            if (flags&0x60) {
-                c.SetBoxedOut(true);    
-            }
-            setChar(x,y,c);
-        }
-    } 
-
-}
-void TeletextDecoderVBIEBU::setKeyinDigits(char digits[3],bool inKeying)
-{
-    int x;
-    inkeying=inKeying;
-    for (x=0;x<3;x++) {
-        cTeletextChar c;
-        c.SetFGColor(ttcWhite);
-        c.SetBGColor(ttcBlack);
-        c.SetCharset(CHARSET_LATIN_G0);
-        c.SetChar(digits[x]);
-        if (flags&0x60) {
-            c.SetBoxedOut(true);    
-        }
-        setChar(x+3,0,c);
-        keyindigits[x]=digits[x];
-    }
-}
-
-void TeletextDecoderVBIEBU::PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos)
-{
-    mediapacket = mplist.front();
-}
-
-static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
-{
-  // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
-  if (pts1 > pts2)
-    return pts1 - pts2;
-  else
-    return (1LL<<33) + pts1 - pts2;
-}
-
-UINT TeletextDecoderVBIEBU::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)
-{
-   if (mediapacket.type != MPTYPE_TELETEXT)
-   {
-       *samplepos= 0;
-       return 1; //Skip it! 
-   }
-   unsigned int headerstrip;
-   unsigned char txtdata[43];
-   headerstrip=buffer[mediapacket.pos_buffer+8]+9;
-   //headerstrip+=4; //substream id
-   unsigned int datapos=0;
-   unsigned int datatype=buffer[mediapacket.pos_buffer+headerstrip+0];
-   //Chris should we use here the pts data from mediapacket ?
-   // in this case the data fields should also be added in mediamvp
-   if (mediapacket.synched)
-    { // An entry exists in the work list
-        ULLONG nowPTS = Video::getInstance()->getCurrentTimestamp();
-       if (PTSDifference(mediapacket.pts, nowPTS) >= 1200*90000) {
-            *samplepos=0;
-            return 1;//bad data skip it
-        }
-        if (nowPTS < (mediapacket.pts-4000)  ) {
-            *samplepos=0;
-            return 0;
-        } 
-   }
-   
-   if (( datatype>=0x10 && datatype <=0x1F) ||
-       ( datatype>=0x99 && datatype <=0x9B)) {
-       //EBU VBI DATA
-       datapos++;
-       while (datapos< (mediapacket.length-headerstrip)) {
-           unsigned int unit_id=buffer[mediapacket.pos_buffer+headerstrip+datapos];
-           datapos++;
-           unsigned int unit_length=buffer[mediapacket.pos_buffer+headerstrip+datapos];
-           datapos++;
-           switch (unit_id) {
-               case 0x02:
-               case 0x03: {//Teletext with and without subtitles
-                   //call teletext decoder
-                   unsigned int field=buffer[mediapacket.pos_buffer+headerstrip+datapos];
-
-                   if ((datapos+44)< (mediapacket.length-headerstrip)) {
-                       for (int i=0;i<42;i++) {
-                           txtdata[i]=invtab[buffer[mediapacket.pos_buffer+headerstrip+datapos+2+i]];
-                       }
-                       DecodeTeletext(txtdata,field);
-                   }
-                          }break;
-               case  0xC0: //inverted Teletext
-                   //call teletext decoder
-               break;
-               
-               case 0xC3: //VPS
-                   //what to do with this, in the moment we do not need it
-               break;
-               case 0xC4: //WSS
-                   //what to do with this, in the moment we do not need it
-               break;
-               case 0xC5: //CC
-                   //what to do with this, in the moment we do not need it
-               break;
-               case 0xC6: //monochrome 4:2:2 samples, what is that? 
-                   //what to do with this, in the moment we do not need it
-               break;
-               default:
-               // case 0x00,0x01,0x04..0x7f,0x80..0xbf,0xc1,0xc2,0xc7..0xfe,0xff: //discard
-                   //discard
-               break;
-           };
-           datapos+=unit_length;
-       //    while (buffer[mediapacket.pos_buffer+headerstrip+datapos]==0xFF &&(datapos< (mediapacket.length-headerstrip))) {
-        //       datapos++; //stuffing bytes
-         //  }
-
-           
-       }
-       *samplepos=0;
-       return 1;
-
-
-   } else {
-           *samplepos= 0;
-           return 1; //Skip it! and discard data   
-   }
-
-   return 0;
-
-}
-// This part is inspired by the vdr-plugin-osdteletext of Udo Richter and Marcel Wiesweg
-void TeletextDecoderVBIEBU::DecodeTeletext(const UCHAR* buffer, unsigned int field) //needs to be exactly 42 byte long!!
-{
-   UCHAR hdrbuf[5];
-   for (int i=0;i<5;i++) hdrbuf[i]=(unhamtab[buffer[2*i]]&0xF) | ((unhamtab[buffer[2*i+1]]&0xF)<< 4);
-   int header=hdrbuf[0];
-   int magazin=header & 0x7;
-   int line = (header>>3) & 0x1f;
-   if (magazin==0) magazin=8;
-   if (line==0)
-   {
-       if (ourpage) {
-           gotcha=true;
-           inkeying=false;
-           RenderTeletextCode(false);
-       } else {
-           RenderTeletextCode(true);
-       }
-       int pagenumber=hdrbuf[1];
-       int pagemagazin=magazin<<8 | pagenumber;
-       int pagesubnumber=(hdrbuf[2]) || ((hdrbuf[3]<<8) & 0x3f7f);
-
-       if (pagemagazin == selectedpage) ourpage=true;
-       else ourpage=false;
-       if (isrecording) {
-           for (int i=0;i<10;i++) {
-               if (pagemagazin==record_pages[i]) break;
-               if (record_pages[i]==-1) {
-                   record_pages[i]=pagemagazin;
-                   break;
-               }
-           }
-       }
-       if (hdrbuf[3] &0x80) { //This is a subtitle
-            for (int i=0;i<10;i++) {
-               if (pagemagazin==record_pages[i]) break;
-               if (record_pages[i]==-1) {
-                   record_pages[i]=pagemagazin;
-                   break;
-               }
-           }
-       }
-
-
-       if (ourpage) {
-           lang=((hdrbuf[4]>>5) & 0x07);
-           flags=hdrbuf[2] & 0x80;
-           flags|=(hdrbuf[3]&0x40)|((hdrbuf[3]>>2)&0x20); //??????
-           flags|=((hdrbuf[4]<<4)&0x10)|((hdrbuf[4]<<2)&0x08)|(hdrbuf[4]&0x04)|((hdrbuf[4]>>1)&0x02)|((hdrbuf[4]>>4)&0x01);
-           for (int i=0;i<25;i++) {
-               memset(curpage[i],0,40);
-            }
-       }
-       
-       memcpy(curpage[line],buffer+2,40);
-   } else if (ourpage && (line<=25)) {
-       memcpy(curpage[line],buffer+2,40);
-       
-   }
-}
-
-
-/* from osdteletext plugin: (slightly adapted for vomp)*/
-// Font tables
-
-// teletext uses 7-bit numbers to identify a font set.
-// There are three font sets involved:
-// Primary G0, Secondary G0, and G2 font set.
-
-// Font tables are organized in blocks of 8 fonts:
-
-enumCharsets FontBlockG0_0000[8] = {
-    CHARSET_LATIN_G0_EN,
-    CHARSET_LATIN_G0_DE,
-    CHARSET_LATIN_G0_SV_FI,
-    CHARSET_LATIN_G0_IT,
-    CHARSET_LATIN_G0_FR,
-    CHARSET_LATIN_G0_PT_ES,
-    CHARSET_LATIN_G0_CZ_SK,
-    CHARSET_LATIN_G0
-};
-
-enumCharsets FontBlockG2Latin[8]={
-    CHARSET_LATIN_G2,
-    CHARSET_LATIN_G2,
-    CHARSET_LATIN_G2,
-    CHARSET_LATIN_G2,
-    CHARSET_LATIN_G2,
-    CHARSET_LATIN_G2,
-    CHARSET_LATIN_G2,
-    CHARSET_LATIN_G2
-};
-
-enumCharsets FontBlockG0_0001[8] = {
-    CHARSET_LATIN_G0_PL,
-    CHARSET_LATIN_G0_DE,
-    CHARSET_LATIN_G0_SV_FI,
-    CHARSET_LATIN_G0_IT,
-    CHARSET_LATIN_G0_FR,
-    CHARSET_LATIN_G0,
-    CHARSET_LATIN_G0_CZ_SK,
-    CHARSET_LATIN_G0
-};
-
-enumCharsets FontBlockG0_0010[8] = {
-    CHARSET_LATIN_G0_EN,
-    CHARSET_LATIN_G0_DE,
-    CHARSET_LATIN_G0_SV_FI,
-    CHARSET_LATIN_G0_IT,
-    CHARSET_LATIN_G0_FR,
-    CHARSET_LATIN_G0_PT_ES,
-    CHARSET_LATIN_G0_TR,
-    CHARSET_LATIN_G0
-};
-
-
-enumCharsets FontBlockG0_0011[8] = {
-    CHARSET_LATIN_G0,
-    CHARSET_LATIN_G0,
-    CHARSET_LATIN_G0,
-    CHARSET_LATIN_G0,
-    CHARSET_LATIN_G0,
-    CHARSET_LATIN_G0_SR_HR_SL,
-    CHARSET_LATIN_G0,
-    CHARSET_LATIN_G0_RO
-};
-
-enumCharsets FontBlockG0_0100[8] = {
-    CHARSET_CYRILLIC_G0_SR_HR,
-    CHARSET_LATIN_G0_DE,
-    CHARSET_LATIN_G0_EE,
-    CHARSET_LATIN_G0_LV_LT,
-    CHARSET_CYRILLIC_G0_RU_BG,
-    CHARSET_CYRILLIC_G0_UK,
-    CHARSET_LATIN_G0_CZ_SK,
-    CHARSET_INVALID
-};
-
-enumCharsets FontBlockG2_0100[8] = {
-    CHARSET_CYRILLIC_G2,
-    CHARSET_LATIN_G2,
-    CHARSET_LATIN_G2,
-    CHARSET_LATIN_G2,
-    CHARSET_CYRILLIC_G2,
-    CHARSET_CYRILLIC_G2,
-    CHARSET_LATIN_G2,
-    CHARSET_INVALID
-};
-
-enumCharsets FontBlockG0_0110[8] = {
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_LATIN_G0_TR,
-    CHARSET_GREEK_G0
-};
-
-enumCharsets FontBlockG2_0110[8] = {
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_LATIN_G2,
-    CHARSET_GREEK_G2
-};
-
-enumCharsets FontBlockG0_1000[8] = {
-    CHARSET_LATIN_G0_EN,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_LATIN_G0_FR,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_ARABIC_G0
-};
-
-enumCharsets FontBlockG2_1000[8] = {
-    CHARSET_ARABIC_G2,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_ARABIC_G2,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_ARABIC_G2
-};
-
-enumCharsets FontBlockG0_1010[8] = {
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_HEBREW_G0,
-    CHARSET_INVALID,
-    CHARSET_ARABIC_G0,
-};
-
-enumCharsets FontBlockG2_1010[8] = {
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_ARABIC_G2,
-    CHARSET_INVALID,
-    CHARSET_ARABIC_G2,
-};
-
-enumCharsets FontBlockInvalid[8] = {
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID,
-    CHARSET_INVALID
-};
-
-
-
-// The actual font table definition:
-// Split the 7-bit number into upper 4 and lower 3 bits,
-// use upper 4 bits for outer array,
-// use lower 3 bits for inner array
-
-struct structFontBlock {
-    enumCharsets *G0Block;
-    enumCharsets *G2Block;
-};
-    
-structFontBlock FontTable[16] = {
-    { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block
-    { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block
-    { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block
-    { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block
-    { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block
-    { FontBlockInvalid, FontBlockInvalid }, // 0101 block
-    { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block
-    { FontBlockInvalid, FontBlockInvalid }, // 0111 block
-    { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block
-    { FontBlockInvalid, FontBlockInvalid }, // 1001 block
-    { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block
-    { FontBlockInvalid, FontBlockInvalid }, // 1011 block
-    { FontBlockInvalid, FontBlockInvalid }, // 1100 block
-    { FontBlockInvalid, FontBlockInvalid }, // 1101 block
-    { FontBlockInvalid, FontBlockInvalid }, // 1110 block
-    { FontBlockInvalid, FontBlockInvalid }  // 1111 block
-};
-
-inline enumCharsets GetG0Charset(int codepage) {
-    return FontTable[codepage>>3].G0Block[codepage&7];
-}
-inline enumCharsets GetG2Charset(int codepage) {
-    return FontTable[codepage>>3].G2Block[codepage&7];
-}
-
-enum enumSizeMode {
-    // Possible size modifications of characters
-    sizeNormal,
-    sizeDoubleWidth,
-    sizeDoubleHeight,
-    sizeDoubleSize
-};
-
-void TeletextDecoderVBIEBU::RenderTeletextCode(bool renderfirstlineonly) {
-    int x,y;
-    bool EmptyNextLine=false;
-    // Skip one line, in case double height chars were/will be used
-
-    // Get code pages:
-    int LocalG0CodePage=(FirstG0CodePage & 0x78) 
-            | ((lang & 0x04)>>2) | (lang & 0x02) | ((lang & 0x01)<<2);
-    enumCharsets FirstG0=GetG0Charset(LocalG0CodePage);
-    enumCharsets SecondG0=GetG0Charset(SecondG0CodePage);
-    // Reserved for later use:
-    // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage);
-    
-    for (y=0;y<24;(EmptyNextLine?y+=2:y++)) {
-        // Start of line: Set start of line defaults
-        
-        // Hold Mosaics mode: Remember last mosaic char/charset 
-        // for next spacing code
-        bool HoldMosaics=false;
-        unsigned char HoldMosaicChar=' ';
-        enumCharsets HoldMosaicCharset=FirstG0;
-
-        enumSizeMode Size=sizeNormal;
-        // Font size modification
-        bool SecondCharset=false;
-        // Use primary or secondary G0 charset
-        bool GraphicCharset=false;
-        // Graphics charset used?
-        bool SeparateGraphics=false;
-        // Use separated vs. contiguous graphics charset
-        bool NoNextChar=false;
-        // Skip display of next char, for double-width
-        EmptyNextLine=false;
-        // Skip next line, for double-height
-
-        cTeletextChar c;
-        // auto.initialized to everything off
-        c.SetFGColor(ttcWhite);
-        c.SetBGColor(ttcBlack);
-        c.SetCharset(FirstG0);
-        
-        if (y==0 && (flags&0x10)) {
-            if (!inkeying ) c.SetBoxedOut(true);
-            
-        }
-        if (flags&0x60) {
-           if (!(inkeying && y==0) ) c.SetBoxedOut(true);
-            
-        }
-        if (y==0) {
-            
-            for (x=0;x<8;x++) {
-                cTeletextChar c2=c;
-               
-                if (x>=3 && x<6){
-                    c2.SetChar(keyindigits[x-3]);
-
-                }
-                else
-                    c2.SetChar(' ');
-                setChar(x,0,c2);
-            }
-        }
-
-        // Pre-scan for double-height and double-size codes
-        for (x=0;x<40;x++) {
-            if (y==0 && x<8) x=8;
-            if ((curpage[y][x] & 0x7f)==0x0D || (curpage[y][x] & 0x7f)==0x0F)
-                EmptyNextLine=true;
-        }
-
-        // Move through line
-        for (x=0;x<40;x++) {
-            unsigned char ttc=curpage[y][x] & 0x7f;
-            // skip parity check
-
-            if (y==0 && x<8) continue;
-            if (y==0 && x<31 && renderfirstlineonly && gotcha && !inkeying) continue;
-            // no displayable data here...
-            
-/*          // Debug only: Output line data and spacing codes
-            if (y==6) {
-                if (ttc<0x20)
-                    printf("%s ",names[ttc]);
-                else
-                    printf("%02x ",ttc);
-                if (x==39) printf("\n");
-            }
-*/          
-            
-            // Handle all 'Set-At' spacing codes
-            switch (ttc) {
-            case 0x09: // Steady
-                c.SetBlink(false);
-                break;
-            case 0x0C: // Normal Size
-                if (Size!=sizeNormal) {
-                    Size=sizeNormal;
-                    HoldMosaicChar=' ';
-                    HoldMosaicCharset=FirstG0;
-                }                   
-                break;
-            case 0x18: // Conceal
-                c.SetConceal(true);
-                break;
-            case 0x19: // Contiguous Mosaic Graphics
-                SeparateGraphics=false;
-                if (GraphicCharset)
-                    c.SetCharset(CHARSET_GRAPHICS_G1);
-                break;
-            case 0x1A: // Separated Mosaic Graphics
-                SeparateGraphics=true;
-                if (GraphicCharset)
-                    c.SetCharset(CHARSET_GRAPHICS_G1_SEP);
-                break;
-            case 0x1C: // Black Background
-                c.SetBGColor(ttcBlack);
-                break;
-            case 0x1D: // New Background
-                c.SetBGColor(c.GetFGColor());
-                break;
-            case 0x1E: // Hold Mosaic
-                HoldMosaics=true;               
-                break;
-            }
-
-            // temporary copy of character data:
-            cTeletextChar c2=c;
-            // c2 will be text character or space character or hold mosaic
-            // c2 may also have temporary flags or charsets
-            
-            if (ttc<0x20) {
-                // Spacing code, display space or hold mosaic
-                if (HoldMosaics) {
-                    c2.SetChar(HoldMosaicChar);
-                    c2.SetCharset(HoldMosaicCharset);
-                } else {
-                    c2.SetChar(' ');
-                }
-            } else {
-                // Character code               
-                c2.SetChar(ttc);
-                if (GraphicCharset) {
-                    if (ttc&0x20) {
-                        // real graphics code, remember for HoldMosaics
-                        HoldMosaicChar=ttc;
-                        HoldMosaicCharset=c.GetCharset();
-                    } else {
-                        // invalid code, pass-through to G0
-                        c2.SetCharset(SecondCharset?SecondG0:FirstG0);
-                    }   
-                }
-            }
-            
-            // Handle double-height and double-width extremes
-            if (y>=23) {
-                if (Size==sizeDoubleHeight) Size=sizeNormal;
-                if (Size==sizeDoubleSize) Size=sizeDoubleWidth;
-            }
-            if (x>=38) {
-                if (Size==sizeDoubleWidth) Size=sizeNormal;
-                if (Size==sizeDoubleSize) Size=sizeDoubleHeight;
-            }
-            
-            // Now set character code
-            
-            if (NoNextChar) {
-                // Suppress this char due to double width last char
-                NoNextChar=false;
-            } else {
-                switch (Size) {
-                case sizeNormal:
-                    // Normal sized
-                    setChar(x,y,c2);
-                    if (EmptyNextLine && y<23) {
-                        // Clean up next line
-                        setChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0));
-                    }
-                    break;
-                case sizeDoubleWidth:
-                    // Double width
-                    setChar(x,y,c2.ToDblWidth(dblw_Left));
-                    setChar(x+1,y,c2.ToDblWidth(dblw_Right));
-                    if (EmptyNextLine && y<23) {
-                        // Clean up next line
-                        setChar(x  ,y+1,c2.ToChar(' ').ToCharset(FirstG0));
-                        setChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0));
-                    }
-                    NoNextChar=true;
-                    break;
-                case sizeDoubleHeight:
-                    // Double height
-                    setChar(x,y,c2.ToDblHeight(dblh_Top));
-                    setChar(x,y+1,c2.ToDblHeight(dblh_Bottom));
-                    break;
-                case sizeDoubleSize:
-                    // Double Size
-                    setChar(x  ,  y,c2.ToDblHeight(dblh_Top   ).ToDblWidth(dblw_Left ));
-                    setChar(x+1,  y,c2.ToDblHeight(dblh_Top   ).ToDblWidth(dblw_Right));
-                    setChar(x  ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left ));
-                    setChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right));
-                    NoNextChar=true;
-                    break;
-                }
-            }
-                
-            // Handle all 'Set-After' spacing codes
-             if (ttc>=0x00 &&  ttc<=0x07) { // Set FG color
-                if (GraphicCharset) {
-                    // Actual switch from graphics charset
-                    HoldMosaicChar=' ';
-                    HoldMosaicCharset=FirstG0;
-                }
-                c.SetFGColor((enumTeletextColor)ttc);
-                c.SetCharset(SecondCharset?SecondG0:FirstG0);
-                GraphicCharset=false;
-                c.SetConceal(false);
-             } else if (ttc==0x08) {
-                c.SetBlink(true);
-             } else if (ttc==0x0A) {
-                c.SetBoxedOut(true);
-             } else if (ttc==0x0B) {
-             // Start Box
-                c.SetBoxedOut(false);
-             } else if (ttc==0x0D) {
-                if (Size!=sizeDoubleHeight) {
-                    Size=sizeDoubleHeight;
-                    HoldMosaicChar=' ';
-                    HoldMosaicCharset=FirstG0;
-                }                   
-             } else if (ttc==0x0E) {
-                if (Size!=sizeDoubleWidth) {
-                    Size=sizeDoubleWidth;
-                    HoldMosaicChar=' ';
-                    HoldMosaicCharset=FirstG0;
-                }                   
-             } else if (ttc==0x0E) {
-                if (Size!=sizeDoubleSize) {
-                    Size=sizeDoubleSize;
-                    HoldMosaicChar=' ';
-                    HoldMosaicCharset=FirstG0;
-                }                   
-             } else  if (ttc>=0x10 && ttc<=0x17) { 
-                if (!GraphicCharset) {
-                    // Actual switch to graphics charset
-                    HoldMosaicChar=' ';
-                    HoldMosaicCharset=FirstG0;
-                }
-                c.SetFGColor((enumTeletextColor)(ttc-0x10));
-                c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1);
-                GraphicCharset=true;
-                c.SetConceal(false);
-             } else if (ttc==0x1B) {
-                SecondCharset=!SecondCharset;
-                if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0);
-             } else if (ttc==0x1F) {
-                HoldMosaics=false;
-             }
-            
-        } // end for x
-        if (renderfirstlineonly) break;
-    } // end for y
-    
-    for (x=0;x<40;x++) {
-        // Clean out last line
-        cTeletextChar c;
-        c.SetFGColor(ttcWhite);
-        c.SetBGColor(ttcBlack);
-        c.SetCharset(FirstG0);
-        c.SetChar(' ');
-        if (flags&0x60) {
-            c.SetBoxedOut(true);    
-        }
-        setChar(x,24,c);
-    } 
-    for (y=0;y<25;y++) {
-        for (x=0;x<40;x++) {
-            if (isDirty(x,y)) {
-                dirty=true;
-                break;
-            }
-            if (dirty) break;
-        }
-        if (dirty) break;
-    }
-     
-    if (dirty && txtview!=NULL ) {
-        
-        if ( !renderfirstlineonly) {
-            Message* m= new Message();
-            m->message = Message::TELETEXTUPDATE;
-            m->to = txtview;
-            m->from = this;
-            m->parameter = 0;
-            Command::getInstance()->postMessageFromOuterSpace(m);
-        } else if (firstlineupdate==10) {
-            Message* m= new Message();
-            m->message = Message::TELETEXTUPDATEFIRSTLINE;
-            m->to = txtview;
-            m->from = this;
-            m->parameter = 0;
-            Command::getInstance()->postMessageFromOuterSpace(m);
-            firstlineupdate=0;
-        } else firstlineupdate++;
-        
-       
-    }
-        
-}
+/*\r
+    Copyright 2008 Marten Richter\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+\r
+/* Portions from vdr osdteletext plugin "txtrender.c": */\r
+/***************************************************************************\r
+ *                                                                         *\r
+ *   txtrender.c - Teletext display abstraction and teletext code          *\r
+ *                 renderer                                                *\r
+ *                                                                         *\r
+ *   This program is free software; you can redistribute it and/or modify  *\r
+ *   it under the terms of the GNU General Public License as published by  *\r
+ *   the Free Software Foundation; either version 2 of the License, or     *\r
+ *   (at your option) any later version.                                   *\r
+ *                                                                         *\r
+ *   Changelog:                                                            *\r
+ *     2005-03    initial version (c) Udo Richter                          *\r
+ *                                                                         *\r
+ ***************************************************************************/\r
+\r
+#include "teletextdecodervbiebu.h"\r
+#include "teletxt/tables.h"\r
+#include "message.h"\r
+#include "command.h"\r
+#include "video.h"\r
+\r
+#ifdef WIN32\r
+#include <windows.h>\r
+#endif\r
+\r
+TeletextDecoderVBIEBU::TeletextDecoderVBIEBU()\r
+{\r
+    selectedpage=0x100;\r
+    ourpage=false;\r
+    flags=lang=0; \r
+  \r
+    CleanPage();\r
+    FirstG0CodePage=0;\r
+    SecondG0CodePage=0;\r
+    dirty=false;\r
+    txtview=NULL;\r
+    firstlineupdate=0;\r
+    gotcha=false;\r
+    char digits[]={'1','0','0'};\r
+    setKeyinDigits(digits,false);\r
+    isrecording=false;\r
+    for (int i=0;i<10;i++) record_pages[i]=-1;\r
+    \r
+\r
+}\r
+\r
+TeletextDecoderVBIEBU::~TeletextDecoderVBIEBU()\r
+{\r
+\r
+\r
+}\r
+\r
+long long TeletextDecoderVBIEBU::SetStartOffset(long long curreftime, bool *rsync)\r
+{\r
+  return 0;  \r
+}\r
+\r
+void TeletextDecoderVBIEBU::ResetTimeOffsets()\r
+{\r
+\r
+}\r
+\r
+\r
+\r
+void TeletextDecoderVBIEBU::ResetDecoder()\r
+{\r
+    gotcha=false;\r
+    ourpage=false;\r
+    firstlineupdate=0;\r
+    selectedpage=0x100;\r
+    CleanPage();\r
+    char digits[]={'1','0','0'};\r
+    setKeyinDigits(digits,false);\r
+    for (int i=0;i<10;i++) record_pages[i]=-1;\r
+  \r
+}\r
+\r
+void TeletextDecoderVBIEBU::setPage(unsigned int newpage)\r
+{\r
+    selectedpage=newpage;\r
+    gotcha=false;\r
+    ourpage=false;\r
+    firstlineupdate=0;\r
+    for (int i=0;i<25;i++) {\r
+        memset(curpage[i],0,40);\r
+    }\r
+}\r
+\r
+void TeletextDecoderVBIEBU::CleanPage()\r
+{\r
+    int x,y;\r
+    for (int i=0;i<25;i++) {\r
+        memset(curpage[i],0,40);\r
+    }\r
+    for (y=0;y<25;y++) {\r
+        for (x=0;x<40;x++) {\r
+            cTeletextChar c;\r
+            c.SetFGColor(ttcWhite);\r
+            c.SetBGColor(ttcBlack);\r
+            c.SetCharset(CHARSET_LATIN_G0);\r
+            c.SetChar(' ');\r
+            if (flags&0x60) {\r
+                c.SetBoxedOut(true);    \r
+            }\r
+            setChar(x,y,c);\r
+        }\r
+    } \r
+\r
+}\r
+void TeletextDecoderVBIEBU::setKeyinDigits(char digits[3],bool inKeying)\r
+{\r
+    int x;\r
+    inkeying=inKeying;\r
+    for (x=0;x<3;x++) {\r
+        cTeletextChar c;\r
+        c.SetFGColor(ttcWhite);\r
+        c.SetBGColor(ttcBlack);\r
+        c.SetCharset(CHARSET_LATIN_G0);\r
+        c.SetChar(digits[x]);\r
+        if (flags&0x60) {\r
+            c.SetBoxedOut(true);    \r
+        }\r
+        setChar(x+3,0,c);\r
+        keyindigits[x]=digits[x];\r
+    }\r
+}\r
+\r
+void TeletextDecoderVBIEBU::PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos)\r
+{\r
+    mediapacket = mplist.front();\r
+}\r
+\r
+static ULLONG TxtPTSDifference(ULLONG pts1, ULLONG pts2)\r
+{\r
+  // Assume pts1, pts2 < 2^33; calculate pts1 - pts2\r
+  if (pts1 > pts2)\r
+    return pts1 - pts2;\r
+  else\r
+    return -pts1 + pts2;\r
+}\r
+\r
+UINT TeletextDecoderVBIEBU::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)\r
+{\r
+   if (mediapacket.type != MPTYPE_TELETEXT)\r
+   {\r
+       *samplepos= 0;\r
+       return 1; //Skip it! \r
+   }\r
+   unsigned int headerstrip;\r
+   unsigned char txtdata[43];\r
+   headerstrip=buffer[mediapacket.pos_buffer+8]+9;\r
+   //headerstrip+=4; //substream id\r
+   unsigned int datapos=0;\r
+   unsigned int datatype=buffer[mediapacket.pos_buffer+headerstrip+0];\r
+   //Chris should we use here the pts data from mediapacket ?\r
+   // in this case the data fields should also be added in mediamvp\r
+   if (mediapacket.synched)\r
+    { // An entry exists in the work list\r
+        ULLONG nowPTS = Video::getInstance()->getCurrentTimestamp();\r
+\r
+        ULLONG ptsdifference=TxtPTSDifference(mediapacket.pts, nowPTS);\r
+\r
+       if (ptsdifference >= (120LL*90000LL)) {\r
+            *samplepos=0;\r
+            return 1;//bad data skip it\r
+        }\r
+        if (nowPTS < (mediapacket.pts-4000)  ) {\r
+            *samplepos=0;\r
+            return 0;\r
+        } \r
+   }\r
+   \r
+   if (( datatype>=0x10 && datatype <=0x1F) ||\r
+       ( datatype>=0x99 && datatype <=0x9B)) {\r
+       //EBU VBI DATA\r
+       datapos++;\r
+       while (datapos< (mediapacket.length-headerstrip)) {\r
+           unsigned int unit_id=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
+           datapos++;\r
+           unsigned int unit_length=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
+           datapos++;\r
+           switch (unit_id) {\r
+               case 0x02:\r
+               case 0x03: {//Teletext with and without subtitles\r
+                   //call teletext decoder\r
+                   unsigned int field=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
+\r
+                   if ((datapos+44)< (mediapacket.length-headerstrip)) {\r
+                       for (int i=0;i<42;i++) {\r
+                           txtdata[i]=invtab[buffer[mediapacket.pos_buffer+headerstrip+datapos+2+i]];\r
+                       }\r
+                       DecodeTeletext(txtdata,field);\r
+                   }\r
+                          }break;\r
+               case  0xC0: //inverted Teletext\r
+                   //call teletext decoder\r
+               break;\r
+               \r
+               case 0xC3: //VPS\r
+                   //what to do with this, in the moment we do not need it\r
+               break;\r
+               case 0xC4: //WSS\r
+                   //what to do with this, in the moment we do not need it\r
+               break;\r
+               case 0xC5: //CC\r
+                   //what to do with this, in the moment we do not need it\r
+               break;\r
+               case 0xC6: //monochrome 4:2:2 samples, what is that? \r
+                   //what to do with this, in the moment we do not need it\r
+               break;\r
+               default:\r
+               // case 0x00,0x01,0x04..0x7f,0x80..0xbf,0xc1,0xc2,0xc7..0xfe,0xff: //discard\r
+                   //discard\r
+               break;\r
+           };\r
+           datapos+=unit_length;\r
+       //    while (buffer[mediapacket.pos_buffer+headerstrip+datapos]==0xFF &&(datapos< (mediapacket.length-headerstrip))) {\r
+        //       datapos++; //stuffing bytes\r
+         //  }\r
+\r
+           \r
+       }\r
+       *samplepos=0;\r
+       return 1;\r
+\r
+\r
+   } else {\r
+           *samplepos= 0;\r
+           return 1; //Skip it! and discard data   \r
+   }\r
+\r
+   return 0;\r
+\r
+}\r
+// This part is inspired by the vdr-plugin-osdteletext of Udo Richter and Marcel Wiesweg\r
+void TeletextDecoderVBIEBU::DecodeTeletext(const UCHAR* buffer, unsigned int field) //needs to be exactly 42 byte long!!\r
+{\r
+   UCHAR hdrbuf[5];\r
+   for (int i=0;i<5;i++) hdrbuf[i]=(unhamtab[buffer[2*i]]&0xF) | ((unhamtab[buffer[2*i+1]]&0xF)<< 4);\r
+   int header=hdrbuf[0];\r
+   int magazin=header & 0x7;\r
+   int line = (header>>3) & 0x1f;\r
+   if (magazin==0) magazin=8;\r
+   if (line==0)\r
+   {\r
+       if (ourpage) {\r
+           gotcha=true;\r
+           inkeying=false;\r
+           RenderTeletextCode(false);\r
+       } else {\r
+           RenderTeletextCode(true);\r
+       }\r
+       int pagenumber=hdrbuf[1];\r
+       int pagemagazin=magazin<<8 | pagenumber;\r
+       int pagesubnumber=(hdrbuf[2]) || ((hdrbuf[3]<<8) & 0x3f7f);\r
+\r
+       if (pagemagazin == selectedpage) ourpage=true;\r
+       else ourpage=false;\r
+       if (isrecording) {\r
+           for (int i=0;i<10;i++) {\r
+               if (pagemagazin==record_pages[i]) break;\r
+               if (record_pages[i]==-1) {\r
+                   record_pages[i]=pagemagazin;\r
+                   break;\r
+               }\r
+           }\r
+       }\r
+       if (hdrbuf[3] &0x80) { //This is a subtitle\r
+            for (int i=0;i<10;i++) {\r
+               if (pagemagazin==record_pages[i]) break;\r
+               if (record_pages[i]==-1) {\r
+                   record_pages[i]=pagemagazin;\r
+                   break;\r
+               }\r
+           }\r
+       }\r
+\r
+\r
+       if (ourpage) {\r
+           lang=((hdrbuf[4]>>5) & 0x07);\r
+           flags=hdrbuf[2] & 0x80;\r
+           flags|=(hdrbuf[3]&0x40)|((hdrbuf[3]>>2)&0x20); //??????\r
+           flags|=((hdrbuf[4]<<4)&0x10)|((hdrbuf[4]<<2)&0x08)|(hdrbuf[4]&0x04)|((hdrbuf[4]>>1)&0x02)|((hdrbuf[4]>>4)&0x01);\r
+           for (int i=0;i<25;i++) {\r
+               memset(curpage[i],0,40);\r
+            }\r
+       }\r
+       \r
+       memcpy(curpage[line],buffer+2,40);\r
+   } else if (ourpage && (line<=25)) {\r
+       memcpy(curpage[line],buffer+2,40);\r
+       \r
+   }\r
+}\r
+\r
+\r
+/* from osdteletext plugin: (slightly adapted for vomp)*/\r
+// Font tables\r
+\r
+// teletext uses 7-bit numbers to identify a font set.\r
+// There are three font sets involved:\r
+// Primary G0, Secondary G0, and G2 font set.\r
+\r
+// Font tables are organized in blocks of 8 fonts:\r
+\r
+enumCharsets FontBlockG0_0000[8] = {\r
+    CHARSET_LATIN_G0_EN,\r
+    CHARSET_LATIN_G0_DE,\r
+    CHARSET_LATIN_G0_SV_FI,\r
+    CHARSET_LATIN_G0_IT,\r
+    CHARSET_LATIN_G0_FR,\r
+    CHARSET_LATIN_G0_PT_ES,\r
+    CHARSET_LATIN_G0_CZ_SK,\r
+    CHARSET_LATIN_G0\r
+};\r
+\r
+enumCharsets FontBlockG2Latin[8]={\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2\r
+};\r
+\r
+enumCharsets FontBlockG0_0001[8] = {\r
+    CHARSET_LATIN_G0_PL,\r
+    CHARSET_LATIN_G0_DE,\r
+    CHARSET_LATIN_G0_SV_FI,\r
+    CHARSET_LATIN_G0_IT,\r
+    CHARSET_LATIN_G0_FR,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0_CZ_SK,\r
+    CHARSET_LATIN_G0\r
+};\r
+\r
+enumCharsets FontBlockG0_0010[8] = {\r
+    CHARSET_LATIN_G0_EN,\r
+    CHARSET_LATIN_G0_DE,\r
+    CHARSET_LATIN_G0_SV_FI,\r
+    CHARSET_LATIN_G0_IT,\r
+    CHARSET_LATIN_G0_FR,\r
+    CHARSET_LATIN_G0_PT_ES,\r
+    CHARSET_LATIN_G0_TR,\r
+    CHARSET_LATIN_G0\r
+};\r
+\r
+\r
+enumCharsets FontBlockG0_0011[8] = {\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0_SR_HR_SL,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0_RO\r
+};\r
+\r
+enumCharsets FontBlockG0_0100[8] = {\r
+    CHARSET_CYRILLIC_G0_SR_HR,\r
+    CHARSET_LATIN_G0_DE,\r
+    CHARSET_LATIN_G0_EE,\r
+    CHARSET_LATIN_G0_LV_LT,\r
+    CHARSET_CYRILLIC_G0_RU_BG,\r
+    CHARSET_CYRILLIC_G0_UK,\r
+    CHARSET_LATIN_G0_CZ_SK,\r
+    CHARSET_INVALID\r
+};\r
+\r
+enumCharsets FontBlockG2_0100[8] = {\r
+    CHARSET_CYRILLIC_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_CYRILLIC_G2,\r
+    CHARSET_CYRILLIC_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_INVALID\r
+};\r
+\r
+enumCharsets FontBlockG0_0110[8] = {\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_LATIN_G0_TR,\r
+    CHARSET_GREEK_G0\r
+};\r
+\r
+enumCharsets FontBlockG2_0110[8] = {\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_GREEK_G2\r
+};\r
+\r
+enumCharsets FontBlockG0_1000[8] = {\r
+    CHARSET_LATIN_G0_EN,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_LATIN_G0_FR,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G0\r
+};\r
+\r
+enumCharsets FontBlockG2_1000[8] = {\r
+    CHARSET_ARABIC_G2,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G2,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G2\r
+};\r
+\r
+enumCharsets FontBlockG0_1010[8] = {\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_HEBREW_G0,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G0,\r
+};\r
+\r
+enumCharsets FontBlockG2_1010[8] = {\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G2,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G2,\r
+};\r
+\r
+enumCharsets FontBlockInvalid[8] = {\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID\r
+};\r
+\r
+\r
+\r
+// The actual font table definition:\r
+// Split the 7-bit number into upper 4 and lower 3 bits,\r
+// use upper 4 bits for outer array,\r
+// use lower 3 bits for inner array\r
+\r
+struct structFontBlock {\r
+    enumCharsets *G0Block;\r
+    enumCharsets *G2Block;\r
+};\r
+    \r
+structFontBlock FontTable[16] = {\r
+    { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block\r
+    { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block\r
+    { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block\r
+    { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block\r
+    { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 0101 block\r
+    { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 0111 block\r
+    { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 1001 block\r
+    { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 1011 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 1100 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 1101 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 1110 block\r
+    { FontBlockInvalid, FontBlockInvalid }  // 1111 block\r
+};\r
+\r
+inline enumCharsets GetG0Charset(int codepage) {\r
+    return FontTable[codepage>>3].G0Block[codepage&7];\r
+}\r
+inline enumCharsets GetG2Charset(int codepage) {\r
+    return FontTable[codepage>>3].G2Block[codepage&7];\r
+}\r
+\r
+enum enumSizeMode {\r
+    // Possible size modifications of characters\r
+    sizeNormal,\r
+    sizeDoubleWidth,\r
+    sizeDoubleHeight,\r
+    sizeDoubleSize\r
+};\r
+\r
+void TeletextDecoderVBIEBU::RenderTeletextCode(bool renderfirstlineonly) {\r
+    int x,y;\r
+    bool EmptyNextLine=false;\r
+    // Skip one line, in case double height chars were/will be used\r
+\r
+    // Get code pages:\r
+    int LocalG0CodePage=(FirstG0CodePage & 0x78) \r
+            | ((lang & 0x04)>>2) | (lang & 0x02) | ((lang & 0x01)<<2);\r
+    enumCharsets FirstG0=GetG0Charset(LocalG0CodePage);\r
+    enumCharsets SecondG0=GetG0Charset(SecondG0CodePage);\r
+    // Reserved for later use:\r
+    // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage);\r
+    \r
+    for (y=0;y<24;(EmptyNextLine?y+=2:y++)) {\r
+        // Start of line: Set start of line defaults\r
+        \r
+        // Hold Mosaics mode: Remember last mosaic char/charset \r
+        // for next spacing code\r
+        bool HoldMosaics=false;\r
+        unsigned char HoldMosaicChar=' ';\r
+        enumCharsets HoldMosaicCharset=FirstG0;\r
+\r
+        enumSizeMode Size=sizeNormal;\r
+        // Font size modification\r
+        bool SecondCharset=false;\r
+        // Use primary or secondary G0 charset\r
+        bool GraphicCharset=false;\r
+        // Graphics charset used?\r
+        bool SeparateGraphics=false;\r
+        // Use separated vs. contiguous graphics charset\r
+        bool NoNextChar=false;\r
+        // Skip display of next char, for double-width\r
+        EmptyNextLine=false;\r
+        // Skip next line, for double-height\r
+\r
+        cTeletextChar c;\r
+        // auto.initialized to everything off\r
+        c.SetFGColor(ttcWhite);\r
+        c.SetBGColor(ttcBlack);\r
+        c.SetCharset(FirstG0);\r
+        \r
+        if (y==0 && (flags&0x10)) {\r
+            if (!inkeying ) c.SetBoxedOut(true);\r
+            \r
+        }\r
+        if (flags&0x60) {\r
+           if (!(inkeying && y==0) ) c.SetBoxedOut(true);\r
+            \r
+        }\r
+        if (y==0) {\r
+            \r
+            for (x=0;x<8;x++) {\r
+                cTeletextChar c2=c;\r
+               \r
+                if (x>=3 && x<6){\r
+                    c2.SetChar(keyindigits[x-3]);\r
+\r
+                }\r
+                else\r
+                    c2.SetChar(' ');\r
+                setChar(x,0,c2);\r
+            }\r
+        }\r
+\r
+        // Pre-scan for double-height and double-size codes\r
+        for (x=0;x<40;x++) {\r
+            if (y==0 && x<8) x=8;\r
+            if ((curpage[y][x] & 0x7f)==0x0D || (curpage[y][x] & 0x7f)==0x0F)\r
+                EmptyNextLine=true;\r
+        }\r
+\r
+        // Move through line\r
+        for (x=0;x<40;x++) {\r
+            unsigned char ttc=curpage[y][x] & 0x7f;\r
+            // skip parity check\r
+\r
+            if (y==0 && x<8) continue;\r
+            if (y==0 && x<31 && renderfirstlineonly && gotcha && !inkeying) continue;\r
+            // no displayable data here...\r
+            \r
+/*          // Debug only: Output line data and spacing codes\r
+            if (y==6) {\r
+                if (ttc<0x20)\r
+                    printf("%s ",names[ttc]);\r
+                else\r
+                    printf("%02x ",ttc);\r
+                if (x==39) printf("\n");\r
+            }\r
+*/          \r
+            \r
+            // Handle all 'Set-At' spacing codes\r
+            switch (ttc) {\r
+            case 0x09: // Steady\r
+                c.SetBlink(false);\r
+                break;\r
+            case 0x0C: // Normal Size\r
+                if (Size!=sizeNormal) {\r
+                    Size=sizeNormal;\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }                   \r
+                break;\r
+            case 0x18: // Conceal\r
+                c.SetConceal(true);\r
+                break;\r
+            case 0x19: // Contiguous Mosaic Graphics\r
+                SeparateGraphics=false;\r
+                if (GraphicCharset)\r
+                    c.SetCharset(CHARSET_GRAPHICS_G1);\r
+                break;\r
+            case 0x1A: // Separated Mosaic Graphics\r
+                SeparateGraphics=true;\r
+                if (GraphicCharset)\r
+                    c.SetCharset(CHARSET_GRAPHICS_G1_SEP);\r
+                break;\r
+            case 0x1C: // Black Background\r
+                c.SetBGColor(ttcBlack);\r
+                break;\r
+            case 0x1D: // New Background\r
+                c.SetBGColor(c.GetFGColor());\r
+                break;\r
+            case 0x1E: // Hold Mosaic\r
+                HoldMosaics=true;               \r
+                break;\r
+            }\r
+\r
+            // temporary copy of character data:\r
+            cTeletextChar c2=c;\r
+            // c2 will be text character or space character or hold mosaic\r
+            // c2 may also have temporary flags or charsets\r
+            \r
+            if (ttc<0x20) {\r
+                // Spacing code, display space or hold mosaic\r
+                if (HoldMosaics) {\r
+                    c2.SetChar(HoldMosaicChar);\r
+                    c2.SetCharset(HoldMosaicCharset);\r
+                } else {\r
+                    c2.SetChar(' ');\r
+                }\r
+            } else {\r
+                // Character code               \r
+                c2.SetChar(ttc);\r
+                if (GraphicCharset) {\r
+                    if (ttc&0x20) {\r
+                        // real graphics code, remember for HoldMosaics\r
+                        HoldMosaicChar=ttc;\r
+                        HoldMosaicCharset=c.GetCharset();\r
+                    } else {\r
+                        // invalid code, pass-through to G0\r
+                        c2.SetCharset(SecondCharset?SecondG0:FirstG0);\r
+                    }   \r
+                }\r
+            }\r
+            \r
+            // Handle double-height and double-width extremes\r
+            if (y>=23) {\r
+                if (Size==sizeDoubleHeight) Size=sizeNormal;\r
+                if (Size==sizeDoubleSize) Size=sizeDoubleWidth;\r
+            }\r
+            if (x>=38) {\r
+                if (Size==sizeDoubleWidth) Size=sizeNormal;\r
+                if (Size==sizeDoubleSize) Size=sizeDoubleHeight;\r
+            }\r
+            \r
+            // Now set character code\r
+            \r
+            if (NoNextChar) {\r
+                // Suppress this char due to double width last char\r
+                NoNextChar=false;\r
+            } else {\r
+                switch (Size) {\r
+                case sizeNormal:\r
+                    // Normal sized\r
+                    setChar(x,y,c2);\r
+                    if (EmptyNextLine && y<23) {\r
+                        // Clean up next line\r
+                        setChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
+                    }\r
+                    break;\r
+                case sizeDoubleWidth:\r
+                    // Double width\r
+                    setChar(x,y,c2.ToDblWidth(dblw_Left));\r
+                    setChar(x+1,y,c2.ToDblWidth(dblw_Right));\r
+                    if (EmptyNextLine && y<23) {\r
+                        // Clean up next line\r
+                        setChar(x  ,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
+                        setChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
+                    }\r
+                    NoNextChar=true;\r
+                    break;\r
+                case sizeDoubleHeight:\r
+                    // Double height\r
+                    setChar(x,y,c2.ToDblHeight(dblh_Top));\r
+                    setChar(x,y+1,c2.ToDblHeight(dblh_Bottom));\r
+                    break;\r
+                case sizeDoubleSize:\r
+                    // Double Size\r
+                    setChar(x  ,  y,c2.ToDblHeight(dblh_Top   ).ToDblWidth(dblw_Left ));\r
+                    setChar(x+1,  y,c2.ToDblHeight(dblh_Top   ).ToDblWidth(dblw_Right));\r
+                    setChar(x  ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left ));\r
+                    setChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right));\r
+                    NoNextChar=true;\r
+                    break;\r
+                }\r
+            }\r
+                \r
+            // Handle all 'Set-After' spacing codes\r
+             if (ttc>=0x00 &&  ttc<=0x07) { // Set FG color\r
+                if (GraphicCharset) {\r
+                    // Actual switch from graphics charset\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }\r
+                c.SetFGColor((enumTeletextColor)ttc);\r
+                c.SetCharset(SecondCharset?SecondG0:FirstG0);\r
+                GraphicCharset=false;\r
+                c.SetConceal(false);\r
+             } else if (ttc==0x08) {\r
+                c.SetBlink(true);\r
+             } else if (ttc==0x0A) {\r
+                c.SetBoxedOut(true);\r
+             } else if (ttc==0x0B) {\r
+             // Start Box\r
+                c.SetBoxedOut(false);\r
+             } else if (ttc==0x0D) {\r
+                if (Size!=sizeDoubleHeight) {\r
+                    Size=sizeDoubleHeight;\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }                   \r
+             } else if (ttc==0x0E) {\r
+                if (Size!=sizeDoubleWidth) {\r
+                    Size=sizeDoubleWidth;\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }                   \r
+             } else if (ttc==0x0E) {\r
+                if (Size!=sizeDoubleSize) {\r
+                    Size=sizeDoubleSize;\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }                   \r
+             } else  if (ttc>=0x10 && ttc<=0x17) { \r
+                if (!GraphicCharset) {\r
+                    // Actual switch to graphics charset\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }\r
+                c.SetFGColor((enumTeletextColor)(ttc-0x10));\r
+                c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1);\r
+                GraphicCharset=true;\r
+                c.SetConceal(false);\r
+             } else if (ttc==0x1B) {\r
+                SecondCharset=!SecondCharset;\r
+                if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0);\r
+             } else if (ttc==0x1F) {\r
+                HoldMosaics=false;\r
+             }\r
+            \r
+        } // end for x\r
+        if (renderfirstlineonly) break;\r
+    } // end for y\r
+    \r
+    for (x=0;x<40;x++) {\r
+        // Clean out last line\r
+        cTeletextChar c;\r
+        c.SetFGColor(ttcWhite);\r
+        c.SetBGColor(ttcBlack);\r
+        c.SetCharset(FirstG0);\r
+        c.SetChar(' ');\r
+        if (flags&0x60) {\r
+            c.SetBoxedOut(true);    \r
+        }\r
+        setChar(x,24,c);\r
+    } \r
+    for (y=0;y<25;y++) {\r
+        for (x=0;x<40;x++) {\r
+            if (isDirty(x,y)) {\r
+                dirty=true;\r
+                break;\r
+            }\r
+            if (dirty) break;\r
+        }\r
+        if (dirty) break;\r
+    }\r
+     \r
+    if (dirty && txtview!=NULL ) {\r
+        \r
+        if ( !renderfirstlineonly) {\r
+            Message* m= new Message();\r
+            m->message = Message::TELETEXTUPDATE;\r
+            m->to = txtview;\r
+            m->from = this;\r
+            m->parameter = 0;\r
+            Command::getInstance()->postMessageFromOuterSpace(m);\r
+        } else if (firstlineupdate==10) {\r
+            Message* m= new Message();\r
+            m->message = Message::TELETEXTUPDATEFIRSTLINE;\r
+            m->to = txtview;\r
+            m->from = this;\r
+            m->parameter = 0;\r
+            Command::getInstance()->postMessageFromOuterSpace(m);\r
+            firstlineupdate=0;\r
+        } else firstlineupdate++;\r
+        \r
+       \r
+    }\r
+        \r
+}\r
index d876a5d95200b30f7a5b8d67ff32cb81d02389ec..040fe09fc26b2ae4dacbe7251708e59fdcec4743 100644 (file)
--- a/tfeed.cc
+++ b/tfeed.cc
@@ -1,78 +1,54 @@
-/*\r
-    Copyright 2008 Marten Richter\r
-\r
-    This file is part of VOMP.\r
-\r
+/*\r\r
+    Copyright 2008 Marten Richter\r\r
+    This file is part of VOMP.\r\r
     VOMP is free software; you can redistribute it and/or modify\r
     it under the terms of the GNU General Public License as published by\r
     the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
+    (at your option) any later version.\r\r
     VOMP is distributed in the hope that it will be useful,\r
     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
+    GNU General Public License for more details.\r\r
     You should have received a copy of the GNU General Public License\r
     along with VOMP; if not, write to the Free Software\r
     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "tfeed.h"\r
-\r
-#include "log.h"\r
-#include "demuxer.h"\r
-#include "callback.h"\r
-\r
-TFeed::TFeed(Callback* tcb)\r
-: cb(*tcb)\r
-{\r
-  teletextEnabled = 1;\r
-}\r
-\r
-int TFeed::init()\r
-{\r
-  return 1;\r
-}\r
-\r
-int TFeed::shutdown()\r
-{\r
-  // FIXME\r
-  return 1;\r
-}\r
-\r
-void TFeed::disable()\r
-{\r
-  teletextEnabled = 0;\r
-}\r
-\r
+*/\r\r
+\r\r
+#include "tfeed.h"\r\r
+#include "log.h"\r#include "demuxer.h"\r#include "callback.h"\r\r
+\r\r
+TFeed::TFeed(Callback* tcb)\r: cb(*tcb)\r{\r  teletextEnabled = 1;\r}\r\r
+\r\r
+int TFeed::init()\r{\r  return 1;\r}\r\r
+\r\r
+int TFeed::shutdown()\r{\r\r
+  // FIXME\r  return 1;\r}\r\r
+\r\r
+void TFeed::disable()\r\r
+{\r  teletextEnabled = 0;\r
+}\r\r
+\r\r
 void TFeed::enable()\r
-{\r
-  teletextEnabled = 1;\r
-}\r
-\r
+{\r     teletextEnabled = 1;\r\r
+}\r\r
+\r\r
 int TFeed::start()\r
 {\r
   teletextEnabled = 1;\r
   return threadStart();\r
-}\r
-\r
+}\r\r
+\r\r
 void TFeed::stop()\r
 {\r
   threadCancel();\r
-}\r
-\r
+}\r\r
+\r\r
 void TFeed::threadMethod()\r
 {\r
-  bool tlen;\r
-\r
-  while(1)\r
-  {\r
+  bool tlen;\r\r
+  while(1)\r  {\r
     threadCheckExit();\r
-\r
-    \r
-    tlen = Demuxer::getInstance()->writeTeletext();\r
-\r
+    tlen = Demuxer::getInstance()->writeTeletext();\r\r
     if (tlen)\r
     {\r
       cb.call(this);\r
@@ -83,6 +59,5 @@ void TFeed::threadMethod()
       //MILLISLEEP(100);\r
         MILLISLEEP(20); //Performance Issue Marten\r
     }\r
-    \r
   }\r
-}\r
+}\r
\ No newline at end of file
diff --git a/tfeed.h b/tfeed.h
index 9206a645ba5a16e17c807fff1f44b02f95728964..1c153f136e07ef244f709b2b84d01f559d3810a8 100644 (file)
--- a/tfeed.h
+++ b/tfeed.h
@@ -1,55 +1,21 @@
-/*\r
-    Copyright 2008 Marten Richter\r
-\r
-    This file is part of VOMP.\r
-\r
+/*\r    Copyright 2008 Marten Richter\r\r
+    This file is part of VOMP.\r\r
     VOMP is free software; you can redistribute it and/or modify\r
     it under the terms of the GNU General Public License as published by\r
     the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
+    (at your option) any later version.\r\r
     VOMP is distributed in the hope that it will be useful,\r
     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
+    GNU General Public License for more details.\r\r
     You should have received a copy of the GNU General Public License\r
     along with VOMP; if not, write to the Free Software\r
     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#ifndef TFEED_H\r
-#define TFEED_H\r
-\r
-#include <stdio.h>\r
-#include <time.h>\r
-\r
-#ifdef WIN32\r
-#include "threadwin.h"\r
-#else\r
-#include "threadp.h"\r
-#endif\r
-\r
-class Callback;\r
-\r
-class TFeed : public Thread_TYPE\r
-{\r
-  public:\r
-    TFeed(Callback* tcb);\r
-\r
-    int init();\r
-    int shutdown();\r
-\r
-    int start();\r
-    void stop();\r
-    void enable();\r
-    void disable();\r
-\r
-  private:\r
-    void threadMethod();\r
-    void threadPostStopCleanup() {};\r
-    int teletextEnabled;\r
-    Callback& cb;\r
-};\r
-\r
-#endif\r
+*/\r\r\r
+#ifndef TFEED_H\r#define TFEED_H\r\r
+#include <stdio.h>\r#include <time.h>\r\r
+#include "threadsystem.h"\r\r
+class Callback;\r\r
+class TFeed: public Thread_TYPE {\rpublic:\r     TFeed(Callback* tcb);\r  int init();\r    int shutdown();\r        int start();\r   void stop();\r   void enable();\r void disable();\r\rprivate:\r\r     void threadMethod();\r   void threadPostStopCleanup() {\r };\r\r    int teletextEnabled;\r   Callback& cb;\r};\r\r
+\r\r
+#endif\r\r
index d383760fa2c8b6f242498d43982cb81b1e6c3ab7..fdd7df1ef546bb17ce4db7e8391d878c2f2fd8bc 100644 (file)
@@ -51,6 +51,7 @@ void ThreadP::threadStop()
   this->threadPostStopCleanup();
 }
 
+
 void ThreadP::threadCancel()
 {
   threadActive = 0;
@@ -59,6 +60,7 @@ void ThreadP::threadCancel()
   this->threadPostStopCleanup();
 }
 
+
 void ThreadP::threadCheckExit()
 {
   if (!threadActive) pthread_exit(NULL);
@@ -102,6 +104,7 @@ void ThreadP::threadSetKillable()
   pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 }
 
+
 pthread_t ThreadP::getThreadID() // returns the ID of this thread
 {
   return pthread;
index 86f6b04c73c03f26d3fa6e4e4b2f9cbfd00741e5..0fc2d34fda62682c677b909a08ccbe8ff8737981 100644 (file)
--- a/threadp.h
+++ b/threadp.h
@@ -42,6 +42,7 @@ class ThreadP : public Thread
     void threadSignalNoLock();  // same as above but without locking guarantees. probably not a good idea.
 
     // Methods to use from inside the thread
+
     void threadSetKillable();    // allows threadCancel() to work
     void threadCheckExit();      // terminates thread if threadStop() has been called
     void threadWaitForSignal();  // pauses thread until threadSignal() is called
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 34ab673..b879592
--- a/timers.h
+++ b/timers.h
@@ -80,11 +80,7 @@ Big Mutex.
 #include <stdio.h>
 #include <list>
 
-#ifndef WIN32
-#include "threadp.h"
-#else
-#include "threadwin.h"
-#endif
+#include "threadsystem.h"
 
 #include "defines.h"
 
diff --git a/udp.cc b/udp.cc
old mode 100755 (executable)
new mode 100644 (file)
index 086e4ab..0a775ea
--- a/udp.cc
+++ b/udp.cc
@@ -84,7 +84,7 @@ void UDP::threadMethod()
   int retval;
   while(1)
   {
-    retval = ds->waitforMessage(0);
+    retval = ds->waitforMessage(1);
 
     if (retval == 0)
     {
@@ -93,12 +93,14 @@ void UDP::threadMethod()
     }
     else if (retval == 1)
     {
+      threadCheckExit();
       continue;
     }
     else
     {
       processRequest((UCHAR*)ds->getData(), ds->getDataLength());
     }
+    threadCheckExit();
   }
 }
 
diff --git a/udp.h b/udp.h
old mode 100755 (executable)
new mode 100644 (file)
index cac6647..36b3043
--- a/udp.h
+++ b/udp.h
 
 #include "defines.h"
 
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
+#include "threadsystem.h"
 
 class DatagramSocket;
 class MessageQueue;
index a663fcca485d86f0cacc990a53cb4163a492d635..3ec7713a3c9548f084fb47754644577f2fd4f94b 100644 (file)
@@ -64,6 +64,7 @@ VChannelList::VChannelList(ULONG type)
 
 VChannelList::~VChannelList()
 {
+
   if (chanList)
   {
     for (UINT i = 0; i < chanList->size(); i++)
@@ -236,7 +237,15 @@ int VChannelList::handleCommand(int command)
 
 void VChannelList::processMessage(Message* m)
 {
-  if (m->message == Message::MOUSE_MOVE)
+ /* if (m->message == Message::MOUSE_MOVE) {
+       if (sl.mouseAndroidScroll((m->tag >> 16),(m->tag & 0xFFFF),
+                       (m->parameter >> 16),(m->parameter & 0xFFFF))) {
+               sl.draw();
+               doShowingBar();
+               boxstack->update(this);
+       }
+  }
+  else */if (m->message == Message::MOUSE_MOVE)
   {
     if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
     {
index bba1e1e75348f784631a48970697585a053e4611..d79f7fd79f65d8465e4a2c81f2491a5828e4a809 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon, Andreas Vogel
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vcolourtuner.h"
-
-#include "wsymbol.h"
-#include "remote.h"
-#include "colour.h"
-#include "video.h"
-#include "vinfo.h"
-#include "boxstack.h"
-#include "i18n.h"
-#include "log.h"
-#include "mediaoptions.h"
-
-#define PICTUREFILE "/colourtest.jpg"
-
-int VColourTuner::rfactor=100;
-int VColourTuner::gfactor=100;
-int VColourTuner::bfactor=100;
-
-VColourTuner::VColourTuner()
-{
-  int sw= Video::getInstance()->getScreenWidth();
-  int sh= Video::getInstance()->getScreenHeight();
-  setSize(sw-80,sh-40);
-  setPosition((sw-area.w)/2, (sh-area.h)/2);
-  createBuffer();
-  setTitleBarOn(0);
-  picture.setPosition(160,60);
-  add(&picture);
-  drawPicture=true;
-  vrfactor=rfactor;
-  vbfactor=bfactor;
-  vgfactor=gfactor;
-  hasChanged=false;
-  Log::getInstance()->log("VColourTuner",Log::DEBUG,"created %p",this);
-}
-
-VColourTuner::~VColourTuner()
-{
-  Log::getInstance()->log("VColourTuner",Log::DEBUG,"deleted %p",this);
-}
-
-void VColourTuner::drawBox(int x, int y, int w, int h, Colour &c) {
-  for (int row=y;row<y+h;row++)
-    for (int col=x;col<x+w;col++) {
-      surface->drawPixel(col,row,c);
-    }
-}
-
-
-void VColourTuner::draw()
-{
-    //do not call base classes draw to avoid drawing the picture...
-    Log::getInstance()->log("VColourTuner::draw",Log::DEBUG,"dp %s, rf=%d, gf=%d, bf=%d",
-        (drawPicture?"true":"false"),vrfactor,vgfactor,vbfactor);
-    char valbuf[20];
-    int x=20;
-    int y=20;
-    int bw=50;
-    int bh=50;
-    int picx=picture.getX();
-    Colour bc=Colour(140,140,140);
-    fillColour(bc);
-    bc=Colour(255,255,255);
-    drawText(tr("Colour Tuning"), x+20, y+5, Colour::LIGHTTEXT);
-    drawBox(x, y+50, bw, bh, Colour::RED);
-    drawBox(x, y+130, bw, bh, Colour::GREEN);
-    drawBox(x, y+190, bw, bh, Colour::BLUE);
-    drawBox(x, y+270, bw, bh, bc);
-    sprintf(valbuf,"%03d%%",vrfactor);
-    drawText(valbuf,x+bw+x,y+50, Colour::LIGHTTEXT);
-    drawText("<1 2>",x+bw+x,y+74, Colour::LIGHTTEXT);
-    sprintf(valbuf,"%03d%%",vgfactor);
-    drawText(valbuf,x+bw+x,y+120, Colour::LIGHTTEXT);
-    drawText("<4 5>",x+bw+x,y+144, Colour::LIGHTTEXT);
-    sprintf(valbuf,"%03d%%",vbfactor);
-    drawText(valbuf,x+bw+x,y+190, Colour::LIGHTTEXT);
-    drawText("<7 8>",x+bw+x,y+214, Colour::LIGHTTEXT);
-    sprintf(valbuf,"%03d%%",(vbfactor+vgfactor+vrfactor)/3);
-    drawText(valbuf,x+bw+x,y+270, Colour::LIGHTTEXT);
-    drawText("<3 6>",x+bw+x,y+294, Colour::LIGHTTEXT);
-    drawText("9 norm",x+bw+x,y+318, Colour::LIGHTTEXT);
-    drawText(tr("OK to save, BACK to cancel"), x+20, area.h - 50, Colour::LIGHTTEXT);
-    if (drawPicture) {
-      hasChanged=false;
-      picture.init(PICTUREFILE);
-      picture.draw();
-      drawPicture=false;
-    }
-    int picy=picture.getY();
-    int pich=picture.getHeight();
-    if (hasChanged) drawText(tr("0 to draw picture"), picx+30, picy+pich+10, Colour::LIGHTTEXT);
-}
-
-int VColourTuner::handleCommand(int command)
-{
-  int rt=0;
-  switch(command) {
-      case Remote::ONE:
-      updateFactor(1,-1);
-      rt=2;
-      hasChanged=true;
-      break;
-    case Remote::TWO:
-      updateFactor(1,1);
-      rt=2;
-      hasChanged=true;
-      break;
-    case Remote::FOUR:
-      updateFactor(2,-1);
-      rt=2;
-      hasChanged=true;
-      break;
-    case Remote::FIVE:
-      updateFactor(2,1);
-      rt=2;
-      hasChanged=true;
-      break;
-    case Remote::SEVEN:
-      updateFactor(3,-1);
-      rt=2;
-      hasChanged=true;
-      break;
-    case Remote::EIGHT:
-      updateFactor(3,1);
-      hasChanged=true;
-      rt=2;
-      break;
-    case Remote::THREE:
-      updateFactor(4,-1);
-      hasChanged=true;
-      rt=2;
-      break;
-    case Remote::SIX:
-      updateFactor(4,1);
-      hasChanged=true;
-      rt=2;
-      break;
-    case Remote::NINE:
-      updateFactor(5,0);
-      hasChanged=true;
-      rt=2;
-      break;
-    case Remote::ZERO:
-      drawPicture=true;
-      rt=2;
-      break;
-    case Remote::BACK:
-      vrfactor=rfactor;
-      vgfactor=gfactor;
-      vbfactor=bfactor;
-#ifndef WIN32
-#ifndef _MIPS_ARCH
-    ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);
-#endif
-#endif
-      rt=4;
-      break;
-    case Remote::OK:
-      rfactor=vrfactor;
-      gfactor=vgfactor;
-      bfactor=vbfactor;
-      MediaOptions::getInstance()->setIntOption("FactorRed",rfactor);
-      MediaOptions::getInstance()->setIntOption("FactorGreen",gfactor);
-      MediaOptions::getInstance()->setIntOption("FactorBlue",bfactor);
-      rt=4;
-      break;
-  }
-  if (rt == 2) {
-#ifndef WIN32
-#ifndef _MIPS_ARCH
-    ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);
-#endif
-#endif
-    bool updateAll=drawPicture;
-    draw();
-    if (updateAll) {
-      BoxStack::getInstance()->update(this);
-    }
-    else {
-      Region r;
-      r.x=0;
-      r.w=picture.getX()-1;
-      r.y=0;
-      r.h=area.h;
-      BoxStack::getInstance()->update(this,&r);
-      r.x=picture.getX();
-      r.y=picture.getY();
-      r.h=area.h-r.y;
-      r.w=area.w-picture.getX();
-      BoxStack::getInstance()->update(this,&r);
-    }
-  }
-  return rt;
-}
-
-
-
-void VColourTuner::processMessage(Message* m)
-{
-  if (m->message == Message::MOUSE_MOVE)
-  {
-    
-  }
-  else if (m->message == Message::MOUSE_LBDOWN)
-  {
-    //check if press is outside this view! then simulate cancel
-    int x=(m->parameter>>16)-getScreenX();
-    int y=(m->parameter&0xFFFF)-getScreenY();
-    if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
-    {
-      BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
-    }
-    else if (y>=(int)area.h-24 && y<=(int)area.h-6)
-    {
-      ;
-    }
-  }
-}
-
-void VColourTuner::updateFactor(int color, int amount) {
-  switch (color) {
-    case 1:
-      vrfactor+=amount;
-      if (vrfactor < 20 ) vrfactor=20;
-      if (vrfactor > 200) vrfactor=200;
-      break;
-    case 2:
-      vgfactor+=amount;
-      if (vgfactor < 20 ) vgfactor=20;
-      if (vgfactor > 200) vgfactor=200;
-      break;
-    case 3:
-      vbfactor+=amount;
-      if (vbfactor < 20 ) vbfactor=20;
-      if (vbfactor > 200) vbfactor=200;
-      break;
-    case 4:
-      updateFactor(1,amount);
-      updateFactor(2,amount);
-      updateFactor(3,amount);
-      break;
-    case 5:
-      while ((vrfactor+vbfactor+vgfactor) > 300) updateFactor(4,-1);
-      while ((vrfactor+vbfactor+vgfactor) < 300) updateFactor(4,1);
-  }
-}
-
-void VColourTuner::initFactors(){
-  MediaOptions * options=MediaOptions::getInstance();
-  int rf=options->getIntOption("FactorRed");
-  int gf=options->getIntOption("FactorGreen");
-  int bf=options->getIntOption("FactorBlue");
-  if (rf >= 20 && bf >= 20 && gf >= 20)
-  rfactor=rf;
-  gfactor=gf;
-  bfactor=bf;
-  Log::getInstance()->log("VColourTuner",Log::DEBUG,"setting initial factors r=%d,g=%d,b=%d",rf,gf,bf);
-#ifndef WIN32
-#ifndef _MIPS_ARCH
-  Surface_TYPE::initConversionTables(rfactor,gfactor,bfactor);
-#endif
-#endif
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon, Andreas Vogel\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vcolourtuner.h"\r
+\r
+#include "wsymbol.h"\r
+#include "remote.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "vinfo.h"\r
+#include "boxstack.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+#include "mediaoptions.h"\r
+\r
+#define PICTUREFILE "/colourtest.jpg"\r
+\r
+int VColourTuner::rfactor=100;\r
+int VColourTuner::gfactor=100;\r
+int VColourTuner::bfactor=100;\r
+\r
+VColourTuner::VColourTuner()\r
+{\r
+  int sw= Video::getInstance()->getScreenWidth();\r
+  int sh= Video::getInstance()->getScreenHeight();\r
+  setSize(sw-80,sh-40);\r
+  setPosition((sw-area.w)/2, (sh-area.h)/2);\r
+  createBuffer();\r
+  setTitleBarOn(0);\r
+  picture.setPosition(160,60);\r
+  add(&picture);\r
+  drawPicture=true;\r
+  vrfactor=rfactor;\r
+  vbfactor=bfactor;\r
+  vgfactor=gfactor;\r
+  hasChanged=false;\r
+  Log::getInstance()->log("VColourTuner",Log::DEBUG,"created %p",this);\r
+}\r
+\r
+VColourTuner::~VColourTuner()\r
+{\r
+  Log::getInstance()->log("VColourTuner",Log::DEBUG,"deleted %p",this);\r
+}\r
+\r
+void VColourTuner::drawBox(int x, int y, int w, int h, Colour &c) {\r
+  for (int row=y;row<y+h;row++)\r
+    for (int col=x;col<x+w;col++) {\r
+      surface->drawPixel(col,row,c);\r
+    }\r
+}\r
+\r
+\r
+void VColourTuner::draw()\r
+{\r
+    //do not call base classes draw to avoid drawing the picture...\r
+    Log::getInstance()->log("VColourTuner::draw",Log::DEBUG,"dp %s, rf=%d, gf=%d, bf=%d",\r
+        (drawPicture?"true":"false"),vrfactor,vgfactor,vbfactor);\r
+    char valbuf[20];\r
+    int x=20;\r
+    int y=20;\r
+    int bw=50;\r
+    int bh=50;\r
+    int picx=picture.getX();\r
+    Colour bc=Colour(140,140,140);\r
+    fillColour(bc);\r
+    bc=Colour(255,255,255);\r
+    drawText(tr("Colour Tuning"), x+20, y+5, Colour::LIGHTTEXT);\r
+    drawBox(x, y+50, bw, bh, Colour::RED);\r
+    drawBox(x, y+130, bw, bh, Colour::GREEN);\r
+    drawBox(x, y+190, bw, bh, Colour::BLUE);\r
+    drawBox(x, y+270, bw, bh, bc);\r
+    sprintf(valbuf,"%03d%%",vrfactor);\r
+    drawText(valbuf,x+bw+x,y+50, Colour::LIGHTTEXT);\r
+    drawText("<1 2>",x+bw+x,y+74, Colour::LIGHTTEXT);\r
+    sprintf(valbuf,"%03d%%",vgfactor);\r
+    drawText(valbuf,x+bw+x,y+120, Colour::LIGHTTEXT);\r
+    drawText("<4 5>",x+bw+x,y+144, Colour::LIGHTTEXT);\r
+    sprintf(valbuf,"%03d%%",vbfactor);\r
+    drawText(valbuf,x+bw+x,y+190, Colour::LIGHTTEXT);\r
+    drawText("<7 8>",x+bw+x,y+214, Colour::LIGHTTEXT);\r
+    sprintf(valbuf,"%03d%%",(vbfactor+vgfactor+vrfactor)/3);\r
+    drawText(valbuf,x+bw+x,y+270, Colour::LIGHTTEXT);\r
+    drawText("<3 6>",x+bw+x,y+294, Colour::LIGHTTEXT);\r
+    drawText("9 norm",x+bw+x,y+318, Colour::LIGHTTEXT);\r
+    drawText(tr("OK to save, BACK to cancel"), x+20, area.h - 50, Colour::LIGHTTEXT);\r
+    if (drawPicture) {\r
+      hasChanged=false;\r
+      picture.init(PICTUREFILE);\r
+      picture.draw();\r
+      drawPicture=false;\r
+    }\r
+    int picy=picture.getY();\r
+    int pich=picture.getHeight();\r
+    if (hasChanged) drawText(tr("0 to draw picture"), picx+30, picy+pich+10, Colour::LIGHTTEXT);\r
+}\r
+\r
+int VColourTuner::handleCommand(int command)\r
+{\r
+  int rt=0;\r
+  switch(command) {\r
+      case Remote::ONE:\r
+      updateFactor(1,-1);\r
+      rt=2;\r
+      hasChanged=true;\r
+      break;\r
+    case Remote::TWO:\r
+      updateFactor(1,1);\r
+      rt=2;\r
+      hasChanged=true;\r
+      break;\r
+    case Remote::FOUR:\r
+      updateFactor(2,-1);\r
+      rt=2;\r
+      hasChanged=true;\r
+      break;\r
+    case Remote::FIVE:\r
+      updateFactor(2,1);\r
+      rt=2;\r
+      hasChanged=true;\r
+      break;\r
+    case Remote::SEVEN:\r
+      updateFactor(3,-1);\r
+      rt=2;\r
+      hasChanged=true;\r
+      break;\r
+    case Remote::EIGHT:\r
+      updateFactor(3,1);\r
+      hasChanged=true;\r
+      rt=2;\r
+      break;\r
+    case Remote::THREE:\r
+      updateFactor(4,-1);\r
+      hasChanged=true;\r
+      rt=2;\r
+      break;\r
+    case Remote::SIX:\r
+      updateFactor(4,1);\r
+      hasChanged=true;\r
+      rt=2;\r
+      break;\r
+    case Remote::NINE:\r
+      updateFactor(5,0);\r
+      hasChanged=true;\r
+      rt=2;\r
+      break;\r
+    case Remote::ZERO:\r
+      drawPicture=true;\r
+      rt=2;\r
+      break;\r
+    case Remote::BACK:\r
+      vrfactor=rfactor;\r
+      vgfactor=gfactor;\r
+      vbfactor=bfactor;\r
+#ifndef WIN32\r
+#ifndef _MIPS_ARCH\r
+#ifndef __ANDROID__\r
+    ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);\r
+#endif\r
+#endif\r
+#endif\r
+      rt=4;\r
+      break;\r
+    case Remote::OK:\r
+      rfactor=vrfactor;\r
+      gfactor=vgfactor;\r
+      bfactor=vbfactor;\r
+      MediaOptions::getInstance()->setIntOption("FactorRed",rfactor);\r
+      MediaOptions::getInstance()->setIntOption("FactorGreen",gfactor);\r
+      MediaOptions::getInstance()->setIntOption("FactorBlue",bfactor);\r
+      rt=4;\r
+      break;\r
+  }\r
+  if (rt == 2) {\r
+#ifndef WIN32\r
+#ifndef _MIPS_ARCH\r
+#ifndef __ANDROID__\r
+    ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);\r
+#endif\r
+#endif\r
+#endif\r
+    bool updateAll=drawPicture;\r
+    draw();\r
+    if (updateAll) {\r
+      BoxStack::getInstance()->update(this);\r
+    }\r
+    else {\r
+      Region r;\r
+      r.x=0;\r
+      r.w=picture.getX()-1;\r
+      r.y=0;\r
+      r.h=area.h;\r
+      BoxStack::getInstance()->update(this,&r);\r
+      r.x=picture.getX();\r
+      r.y=picture.getY();\r
+      r.h=area.h-r.y;\r
+      r.w=area.w-picture.getX();\r
+      BoxStack::getInstance()->update(this,&r);\r
+    }\r
+  }\r
+  return rt;\r
+}\r
+\r
+\r
+\r
+void VColourTuner::processMessage(Message* m)\r
+{\r
+  if (m->message == Message::MOUSE_MOVE)\r
+  {\r
+    \r
+  }\r
+  else if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    //check if press is outside this view! then simulate cancel\r
+    int x=(m->parameter>>16)-getScreenX();\r
+    int y=(m->parameter&0xFFFF)-getScreenY();\r
+    if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
+    }\r
+    else if (y>=(int)area.h-24 && y<=(int)area.h-6)\r
+    {\r
+      ;\r
+    }\r
+  }\r
+}\r
+\r
+void VColourTuner::updateFactor(int color, int amount) {\r
+  switch (color) {\r
+    case 1:\r
+      vrfactor+=amount;\r
+      if (vrfactor < 20 ) vrfactor=20;\r
+      if (vrfactor > 200) vrfactor=200;\r
+      break;\r
+    case 2:\r
+      vgfactor+=amount;\r
+      if (vgfactor < 20 ) vgfactor=20;\r
+      if (vgfactor > 200) vgfactor=200;\r
+      break;\r
+    case 3:\r
+      vbfactor+=amount;\r
+      if (vbfactor < 20 ) vbfactor=20;\r
+      if (vbfactor > 200) vbfactor=200;\r
+      break;\r
+    case 4:\r
+      updateFactor(1,amount);\r
+      updateFactor(2,amount);\r
+      updateFactor(3,amount);\r
+      break;\r
+    case 5:\r
+      while ((vrfactor+vbfactor+vgfactor) > 300) updateFactor(4,-1);\r
+      while ((vrfactor+vbfactor+vgfactor) < 300) updateFactor(4,1);\r
+  }\r
+}\r
+\r
+void VColourTuner::initFactors(){\r
+  MediaOptions * options=MediaOptions::getInstance();\r
+  int rf=options->getIntOption("FactorRed");\r
+  int gf=options->getIntOption("FactorGreen");\r
+  int bf=options->getIntOption("FactorBlue");\r
+  if (rf >= 20 && bf >= 20 && gf >= 20)\r
+  rfactor=rf;\r
+  gfactor=gf;\r
+  bfactor=bf;\r
+  Log::getInstance()->log("VColourTuner",Log::DEBUG,"setting initial factors r=%d,g=%d,b=%d",rf,gf,bf);\r
+#ifndef __ANDROID__\r
+#ifndef WIN32\r
+#ifndef _MIPS_ARCH\r
+  Surface_TYPE::initConversionTables(rfactor,gfactor,bfactor);\r
+#endif\r
+#endif\r
+#endif\r
+}\r
index 9666156d9f0761b816b9fe4bc59b1d0f9c425ce2..7c5e427885fbf807bc7a083ab8b23271b755c8c4 100644 (file)
@@ -143,6 +143,7 @@ void VConnect::threadMethod()
     Wol::getInstance()->setWakeUpIP(servers[selectedServer].ip);
     vdr->setServerIP(servers[selectedServer].ip);
 
+
     // Clear the serverIPs vector
     for(UINT k = 0; k < servers.size(); k++)
     {
@@ -151,6 +152,7 @@ void VConnect::threadMethod()
     }
     servers.clear();
 
+
     setOneLiner(tr("Connecting to VDR"));
     draw();
     boxstack->update(this);
@@ -158,7 +160,7 @@ void VConnect::threadMethod()
     success = vdr->connect();
     if (success)
     {
-      logger->log("Command", Log::DEBUG, "Connected ok, doing login");
+      logger->log("VConnect", Log::DEBUG, "Connected ok, doing login");
       success = vdr->doLogin();
 
       if (!success)
@@ -180,6 +182,7 @@ void VConnect::threadMethod()
 
   } while(!success);
 
+
   Message* m = new Message(); // Must be done after this thread ends
   m->from = this;
   m->to = Command::getInstance();
diff --git a/vdr.cc b/vdr.cc
index 3073697872d1dba5dc57d51664d040a4352149d2..b18cac0ca928f71f1e9d2c8240e4bf972a5c2f91 100644 (file)
--- a/vdr.cc
+++ b/vdr.cc
-/*
-    Copyright 2004-2008 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vdr.h"
-
-#include "recman.h"
-#include "tcp.h"
-#include "log.h"
-#include "recinfo.h"
-#include "dsock.h"
-#include "channel.h"
-#include "event.h"
-#include "wol.h"
-#include "vdrrequestpacket.h"
-#include "vdrresponsepacket.h"
-#include "command.h"
-#include "media.h"
-#include "mediaprovider.h"
-#include "mediaproviderids.h"
-#include "vdrcommand.h"
-#include "video.h"
-
-VDR* VDR::instance = NULL;
-//prepare a request
-//will create a request package from a command variable and fill this
-//caller has to destroy buffer
-static SerializeBuffer * prepareRequest(VDR_Command *cmd) {
-  SerializeBuffer *buf=new SerializeBuffer(512,false,true);
-  if (cmd->serialize(buf) != 0) {
-    delete buf;
-    return NULL;
-  }
-  return buf;
-}
-
-//handle request/response
-//TODO avoid copy of buffer (needs extension of requestpacket)
-//TODO avoid command 2x (needs some more restructuring)
-SerializeBuffer * VDR::doRequestResponse(SerializeBuffer *rq,int cmd) {
-  VDR_RequestPacket *rt=new VDR_RequestPacket;
-  if (! rt) {
-    delete rq;
-    return NULL;
-  }
-  if (! rt->init(cmd,true,rq->getCurrent()-rq->getStart())) {
-    delete rq;
-    delete rt;
-    return NULL;
-  }
-  if (! rt->copyin(rq->getStart(),(ULONG)(rq->getCurrent()-rq->getStart()))) {
-    delete rq;
-    delete rt;
-    return NULL;
-  }
-  delete rq;
-  VDR_ResponsePacket *rp=RequestResponse(rt);
-  logger->log("doRequestResponse",Log::DEBUG,"got response %p",rp);
-  if ( !rp) {
-    delete rt;
-    return NULL;
-  }
-  SerializeBuffer *buf=new SerializeBuffer(rp->getUserData(),rp->getUserDataLength(),true,true,false);
-  delete rp;
-  return buf;
-}
-
-
-
-//deserialize a received response
-//delete the package
-//return !=0 on error
-static int decodeResponse(SerializeBuffer *rp,VDR_Command *c) {
-  ULONG expected=c->command;
-  if (c->deserialize(rp) != 0) {
-    delete rp;
-    Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unable to deserialize for command %lu",expected);
-    return -1;
-  }
-  delete rp;
-  if (c->command != expected) {
-   Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unexpected response received 0x%lx, expected 0x%lx",c->command,expected);
-    return -1;
-  }
-  Log::getInstance()->log("VDR", Log::DEBUG, "decodeResponse successfully decoded command 0x%lx",expected);
-  return 0;
-}
-
-
-
-VDR::VDR()
-{
-  if (instance) return;
-  instance = this;
-  initted = 0;
-  findingServer = 0;
-  tcp = NULL;
-  connected = false;
-  maxChannelNumber = 0;
-  channelNumberWidth = 1;
-  TEMP_SINGLE_VDR_PR = NULL;
-  providerId=MPROVIDERID_VDR;
-  subRange=MPROVIDERRANGE_VDR;
-  MediaPlayerRegister::getInstance()->registerMediaProvider(this,MPROVIDERID_VDR,MPROVIDERRANGE_VDR);
-}
-
-VDR::~VDR()
-{
-  instance = NULL;
-  if (initted) shutdown();
-}
-
-VDR* VDR::getInstance()
-{
-  return instance;
-}
-
-int VDR::init(int tport)
-{
-  if (initted) return 0;
-  initted = 1;
-  port = tport;
-  logger = Log::getInstance();
-  return 1;
-}
-
-int VDR::shutdown()
-{
-  if (!initted) return 0;
-  initted = 0;
-  disconnect();
-  return 1;
-}
-
-void VDR::findServers(vector<VDRServer>& servers)
-{
-  Wol* wol = Wol::getInstance();
-  findingServer = 1;
-  char* message = "VOMP";
-
-  DatagramSocket ds(port);
-  int haveAtLeastOne = 0;
-  int retval;
-  int waitType = 1;
-  bool firstloop = true;
-  while(findingServer)
-  {
-    if (waitType == 1)
-    {
-      ds.shutdown();
-      ds.init();
-      logger->log("VDR", Log::NOTICE, "Broadcasting for server");
-      ds.send("255.255.255.255", 3024, message, strlen(message));
-      if(!firstloop) wol->doWakeUp();
-    }
-    retval = ds.waitforMessage(waitType);
-
-    if (retval == 2) // we got a reply
-    {
-      if (!strcmp(ds.getData(), "VOMP")) // echo.....
-      {
-        waitType = 2;
-      }
-      else
-      {
-        VDRServer newServer;
-        newServer.ip = new char[16];
-        strcpy(newServer.ip, ds.getFromIPA());
-
-        if (ds.getDataLength() == 0)
-        {
-          newServer.name = new char[1];
-          newServer.name[0] = '\0';
-        }
-        else
-        {
-          newServer.name = new char[strlen(ds.getData())+1];
-          strcpy(newServer.name, ds.getData());
-        }
-
-        servers.push_back(newServer);
-        waitType = 2;
-        haveAtLeastOne = 1;
-      }
-    }
-    else
-    {
-      if (haveAtLeastOne) break;
-      waitType = 1;
-      firstloop = false;
-    }
-  }
-  sort(servers.begin(), servers.end(), ServerSorter());
-}
-
-void VDR::cancelFindingServer()
-{
-  findingServer = 0;
-}
-
-void VDR::setServerIP(char* newIP)
-{
-  strcpy(serverIP, newIP);
-}
-
-int VDR::connect()
-{
-  maxChannelNumber = 0;
-  channelNumberWidth = 1;
-
-  if (tcp) delete tcp;
-  tcp = new TCP();
-  if (tcp->connectTo(serverIP, 3024))
-  {
-    connected = true;
-    threadStart();
-    return 1;
-  }
-  else
-  {
-    return 0;
-  }
-}
-
-void VDR::disconnect()
-{
-  threadCancel();
-  if (tcp) delete tcp;
-  tcp = NULL;
-  connected = false;
-  logger->log("VDR", Log::DEBUG, "Disconnect");
-}
-
-void VDR::setReceiveWindow(size_t size)
-{
-  if (connected) tcp->setReceiveWindow(size);
-}
-
-///////////////////////////////////////////////////////
-
-void VDR::threadMethod()
-{
-  logger->log("VDR", Log::DEBUG, "VDR RUN");  
-
-  threadSetKillable(); // FIXME - change this to deal with the EDRs
-  
-  ULONG channelID;
-  
-  ULONG requestID;
-  ULONG userDataLength;
-  UCHAR* userData;
-
-  ULONG streamID;
-  ULONG flag;
-
-  VDR_ResponsePacket* vresp;
-  
-  ULONG timeNow = 0;
-  ULONG lastKAsent = 0;
-  ULONG lastKArecv = time(NULL);
-  int readSuccess;
-
-  while(1) 
-  {
-    timeNow = time(NULL);
-    
-    readSuccess = tcp->readData((UCHAR*)&channelID, sizeof(ULONG));  // 2s timeout atm
-
-    if (!readSuccess)
-    {
-      //logger->log("VDR", Log::DEBUG, "Net read timeout");
-      if (!tcp->isConnected()) { connectionDied(); return; } // return to stop this thread
-    }
-      
-    // Error or timeout.
-
-    if (!lastKAsent) // have not sent a KA
-    {
-      if (lastKArecv < (timeNow - 5))
-      {
-        logger->log("VDR", Log::DEBUG, "Sending KA packet");
-        if (!sendKA(timeNow))
-        {
-          logger->log("VDR", Log::DEBUG, "Could not send KA, calling connectionDied");
-          connectionDied();
-          return;
-        }
-        lastKAsent = timeNow;
-      }
-    }
-    else
-    {
-      if (lastKAsent <= (timeNow - 10))
-      {
-        logger->log("VDR", Log::DEBUG, "lastKA over 10s ago, calling connectionDied");
-        connectionDied();
-        return;
-      }    
-    }
-
-    if (!readSuccess) continue; // no data was read but the connection is ok.
-    
-    // Data was read
-            
-    channelID = ntohl(channelID);
-   
-    if (channelID == CHANNEL_REQUEST_RESPONSE)
-    {
-      if (!tcp->readData((UCHAR*)&requestID, sizeof(ULONG))) break;
-      requestID = ntohl(requestID);
-      if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;
-      userDataLength = ntohl(userDataLength);
-      if (userDataLength > 5000000) break; // how big can these packets get?
-      userData = NULL;
-      if (userDataLength > 0)
-      {
-        userData = (UCHAR*)malloc(userDataLength);
-        if (!userData) break;
-        if (!tcp->readData(userData, userDataLength)) break;
-      }
-
-      vresp = new VDR_ResponsePacket();  
-      vresp->setResponse(requestID, userData, userDataLength);
-      logger->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength);
-
-      if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
-      {
-        // If edFindAndCall returns true, edr was called and vresp was handed off.
-        // else, delete vresp here.
-        delete vresp;
-      }
-    }
-    else if (channelID == CHANNEL_STREAM)
-    {
-      if (!tcp->readData((UCHAR*)&streamID, sizeof(ULONG))) break;
-      streamID = ntohl(streamID);
-
-      if (!tcp->readData((UCHAR*)&flag, sizeof(ULONG))) break;
-      flag = ntohl(flag);
-
-      if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break; 
-      userDataLength = ntohl(userDataLength);
-      userData = NULL;
-      if (userDataLength > 0)
-      {
-        userData = (UCHAR*)malloc(userDataLength);
-        if (!userData) break;
-        if (!tcp->readData(userData, userDataLength)) break;
-      }
-
-      vresp = new VDR_ResponsePacket();    
-      vresp->setStream(streamID, flag, userData, userDataLength);
-//      logger->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, flag=%lu, len=%lu", streamID, flag, userDataLength);
-
-      if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
-      {
-        // If edFindAndCall returns true, edr was called and vresp was handed off.
-        // else, delete vresp here.
-        delete vresp;
-      }
-    }
-    else if (channelID == CHANNEL_KEEPALIVE)
-    {
-      ULONG KAreply = 0;
-      if (!tcp->readData((UCHAR*)&KAreply, sizeof(ULONG))) break;
-      KAreply = (ULONG)ntohl(KAreply);
-      if (KAreply == lastKAsent) // successful KA response
-      {
-        lastKAsent = 0;
-        lastKArecv = KAreply;
-        logger->log("VDR", Log::DEBUG, "Rxd correct KA reply");
-      }
-    }
-    else
-    {
-      logger->log("VDR", Log::ERR, "Rxd a response packet on channel %lu !!", channelID);
-      break;
-    }
-
-    // Who deletes vresp?
-    // If RR, the individual protocol functions must delete vresp.
-    // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there.
-  }
-  connectionDied();
-}
-
-void VDR::connectionDied()
-{
-  // Called from within threadMethod to do cleanup if it decides the connection has died
-
-  connected = false; // though actually it could still be connected until someone calls vdr->disconnect
-
-  // Need to wake up any waiting channel 1 request-response threads
-  // Normally this is done by a packet coming in with channelid and requestid      
-  // Instead, go through the list and for each channel 1 edr, make an empty vresp
-  // An empty vresp will have userData == NULL, which means vresp->noResponse() == true
-
-  // If it's a stream receiver, generate a stream packet with flag == connection_lost
-
-  edLock();
-  VDR_PacketReceiver* vdrpr;
-  VDR_ResponsePacket* vresp;
-  while(receivers.size())
-  {
-    vdrpr = (VDR_PacketReceiver*) *(receivers.begin());
-    if (vdrpr->receiverChannel == CHANNEL_REQUEST_RESPONSE)
-    {
-      vresp = new VDR_ResponsePacket();
-      vresp->setResponse(vdrpr->requestSerialNumber, NULL, 0);
-      logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for request serial %lu", vdrpr->requestSerialNumber);
-      edUnlock();
-      if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
-      {
-        // If edFindAndCall returns true, edr was called and vresp was handed off.
-        // else, delete vresp here.
-        logger->log("VDR", Log::ERR, "Timeouts: no waiting thread found for request serial %lu !!!", vdrpr->requestSerialNumber);
-        delete vresp;
-      }
-      edLock();
-    }
-    else if (vdrpr->receiverChannel == CHANNEL_STREAM)
-    {
-      vresp = new VDR_ResponsePacket();
-      vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0);
-      logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for streamid %lu", vdrpr->streamID);
-      edUnlock();
-      if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
-      {
-        // If edFindAndCall returns true, edr was called and vresp was handed off.
-        // else, delete vresp here.
-        logger->log("VDR", Log::ERR, "Timeouts: no waiting stream receiver found for streamid %lu !!!", vdrpr->streamID);
-        delete vresp;
-      }
-      edLock();
-      
-      for(EDRL::iterator i = receivers.begin(); i != receivers.end(); i++)
-        if ((VDR_PacketReceiver*)*i == vdrpr) { receivers.erase(i); break; }
-    }
-  }
-  edUnlock();
-  // Ok, all event receviers should be dealt with. just in case there weren't any, inform command
-  logger->log("VDR", Log::DEBUG, "edUnlock at end of connectionDied");
-
-  Command::getInstance()->connectionLost();
-}
-
-bool VDR::ed_cb_find(EDReceiver* edr, void* userTag)
-{
-  // edr is a VDR_PacketReceiver object made in VDR::RequestResponse
-  // userTag is a VDR_ResponsePacket made in threadMethod
-
-  VDR_PacketReceiver* vdrpr = (VDR_PacketReceiver*)edr;
-  VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
-  
-  // Is vresp for vdrpr ?
-  
-  ULONG packetChannel = vresp->getChannelID();
-  if (vdrpr->receiverChannel != packetChannel) return false;
-
-  if (packetChannel == CHANNEL_REQUEST_RESPONSE)
-  {
-    if (vdrpr->requestSerialNumber == vresp->getRequestID()) return true;
-  }
-  else if (packetChannel == CHANNEL_STREAM)
-  {
-    if (vdrpr->streamID == vresp->getStreamID()) return true;
-  }
-  return false;
-}
-
-VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)
-{
-  //logger->log("VDR", Log::DEBUG, "RR %lu", vrp->getOpcode());
-
-  if (!connected)
-  {
-    logger->log("VDR", Log::DEBUG, "RR when !connected");
-    VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
-    return vresp; // "no-response" return
-  }
-
-  // ED make new VDR and register
-  // make a VDR_PacketReceiver
-  // - init with serial number of request packet
-
-  VDR_PacketReceiver vdrpr;
-//  vdrpr.requestTime = time(NULL);
-  vdrpr.receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE;
-  vdrpr.requestSerialNumber = vrp->getSerial();
-
-  edRegister(&vdrpr);
-   
-  edLock();  
-
-  if ((ULONG)tcp->sendData(vrp->getPtr(), vrp->getLen()) != vrp->getLen())
-  {
-    edUnlock();
-    edUnregister(&vdrpr);
-    VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
-    return vresp; // "no-response" return
-  }
-
-  // Sleep and block this thread. The sleep unlocks the mutex
-  logger->log("VDR", Log::DEBUG, "RR sleep - opcode %lu", vrp->getOpcode());
-  edSleepThisReceiver(&vdrpr);
-  logger->log("VDR", Log::DEBUG, "RR unsleep");
-    
-  // Woken because a response packet has arrived, mutex will be locked
-  
-  edUnlock();
-  return vdrpr.save_vresp;
-}
-
-bool VDR::sendKA(ULONG timeStamp)
-{
-  char buffer[8];
-  *(ULONG*)&buffer[0] = htonl(CHANNEL_KEEPALIVE);
-  *(ULONG*)&buffer[4] = htonl(timeStamp);
-  if ((ULONG)tcp->sendData(buffer, 8) != 8) return false;
-  return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-// Here VDR takes a break for the VDR_PacketReceiver helper class
-
-bool VDR_PacketReceiver::call(void* userTag)
-{
-  if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE)
-  {
-    // It's a RR. Save vresp and, signal the waiting thread and return.
-    // VDR::RequestResponse will be blocking waiting for this to happen.
-    // That function has a pointer to this object and can read save_vresp.
-    save_vresp = (VDR_ResponsePacket*)userTag;
-    return true; // Signals ED to remove edr from receivers and wake up edr thread
-  }
-  
-  if (receiverChannel == VDR::CHANNEL_STREAM)
-  {
-    // It's a stream packet.
-    VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
-    streamReceiver->streamReceive(vresp->getFlag(), vresp->getUserData(), vresp->getUserDataLength());
-    delete vresp;
-    return false;
-  }
-
-  abort(); // unknown receiverChannel, should not happen
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-int VDR::doLogin()
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_LOGIN, true, 6)) return 0;
-
-  char* mactemp[6];
-  tcp->getMAC((char*)mactemp);
-  if (!vrp.copyin((UCHAR*)mactemp, 6)) return 0;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-
-  ULONG vdrTime = vresp->extractULONG();
-  logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
-  long vdrTimeOffset = vresp->extractLONG();
-  logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
-
-  delete vresp;
-
-  // Set the time and zone on the MVP
-
-#ifndef WIN32
-  struct timespec currentTime;
-  currentTime.tv_sec = vdrTime;
-  currentTime.tv_nsec = 0;
-  int b = clock_settime(CLOCK_REALTIME, &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
-
-  return 1;
-}
-
-bool VDR::networkLog(const char* logString)
-{
-  if (!connected) return false;
-  int stringLength = strlen(logString);
-  int packetLength = stringLength + 8;
-  char *buffer=new char[packetLength + 1];
-  *(ULONG*)&buffer[0] = htonl(CHANNEL_NETLOG);
-  *(ULONG*)&buffer[4] = htonl(stringLength);
-  strcpy(&buffer[8], logString);
-  
-  if ((ULONG)tcp->sendData(buffer, packetLength) != packetLength) {
-         delete [] buffer;
-         return false;
-  }
-  delete [] buffer;
-  return true;
-}
-
-bool VDR::getRecordingsList(RecMan* recman)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETRECORDINGLIST, true, 0)) return false;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return false; }
-  
-  ULONG totalSpace = vresp->extractULONG();
-  ULONG freeSpace = vresp->extractULONG();
-  ULONG percent = vresp->extractULONG();
-  recman->setStats(totalSpace, freeSpace, percent);
-
-  ULONG start;
-  char* name;
-  char* fileName;
-
-  while (!vresp->end())
-  {
-    start = vresp->extractULONG();
-    name = vresp->extractString();
-    fileName = vresp->extractString();
-
-    recman->addEntry(start, name, fileName);
-
-    delete[] name;
-    delete[] fileName;
-  }
-
-  delete vresp;
-
-  return true;
-}
-
-int VDR::deleteRecording(char* fileName)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_DELETERECORDING, true, strlen(fileName) + 1)) return 0;
-  if (!vrp.addString(fileName)) return 0;
-  
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-  
-  int toReturn = (int)vresp->extractULONG();
-  delete vresp;
-
-  return toReturn;
-}
-
-char* VDR::moveRecording(char* fileName, char* newPath)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_MOVERECORDING, true, strlen(fileName) + 1 + strlen(newPath) + 1)) return NULL;
-  if (!vrp.addString(fileName)) return NULL;
-  if (!vrp.addString(newPath)) return NULL;
-  
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return NULL; }
-  
-  char* toReturn = NULL;
-  int success = (int)vresp->extractULONG();
-  if (success == 1)
-  {
-    toReturn = vresp->extractString();
-  }
-
-  delete vresp;
-
-  return toReturn;
-}
-
-ChannelList* VDR::getChannelsList(ULONG type)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETCHANNELLIST, true, 0)) return NULL;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return NULL; }
-  
-  ChannelList* chanList = new ChannelList();
-
-  bool h264support=Video::getInstance()->supportsh264();
-
-  while (!vresp->end())
-  {
-    Channel* chan = new Channel();
-    chan->number = vresp->extractULONG();
-    chan->type = vresp->extractULONG();
-    chan->name = vresp->extractString();
-    chan->vstreamtype = vresp->extractULONG();
-
-    if (chan->type == type && (chan->vstreamtype!=0x1b || h264support))
-    {
-      chanList->push_back(chan);
-      logger->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
-      if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;
-    }
-    else
-    {
-      delete chan;
-    }
-  }
-
-  delete vresp;
-
-  if (maxChannelNumber > 99999)
-    channelNumberWidth = 6;
-  else if (maxChannelNumber > 9999)
-    channelNumberWidth = 5;
-  else if (maxChannelNumber > 999)
-    channelNumberWidth = 4;
-  else if (maxChannelNumber > 99)
-    channelNumberWidth = 3;
-  else if (maxChannelNumber > 9)
-    channelNumberWidth = 2;
-  else
-    channelNumberWidth = 1;
-
-  return chanList;
-}
-
-int VDR::streamChannel(ULONG number, StreamReceiver* tstreamReceiver)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_STREAMCHANNEL, true, sizeof(ULONG))) return 0;
-  if (!vrp.addULONG(number)) return 0;
-  
-  
-  VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
-  vdrpr->receiverChannel = VDR::CHANNEL_STREAM;
-  vdrpr->streamID = vrp.getSerial();
-  vdrpr->streamReceiver = tstreamReceiver;
-  edRegister(vdrpr);
-  TEMP_SINGLE_VDR_PR = vdrpr;
-  
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse())
-  {
-    delete vresp;
-    edUnregister(vdrpr);
-    delete vdrpr;
-    return 0;
-  }
-  
-  int toReturn = (int)vresp->extractULONG();
-  logger->log("VDR", Log::DEBUG, "VDR said %lu to start streaming request", toReturn);
-  delete vresp;
-
-  return toReturn;
-}
-
-int VDR::stopStreaming()
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_STOPSTREAMING, true, 0)) return 0;
-
-  if (TEMP_SINGLE_VDR_PR) // this block only needs to be done if it was a live stream
-                          // TEMP_SINGLE_VDR_PR will not be set unless we are streaming a channel
-  {
-    edUnregister(TEMP_SINGLE_VDR_PR);
-    delete TEMP_SINGLE_VDR_PR;
-    TEMP_SINGLE_VDR_PR = NULL;
-  }
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-  
-  int toReturn = (int)vresp->extractULONG();
-  delete vresp;
-
-  return toReturn;
-}
-
-UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETBLOCK, true, sizeof(ULLONG) + sizeof(ULONG))) return NULL;
-  if (!vrp.addULLONG(position)) return NULL;
-  if (!vrp.addULONG(maxAmount)) return NULL;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return NULL; }
-
-  if (vresp->serverError())
-  {
-    logger->log("VDR", Log::DEBUG, "Detected getblock 0");
-    delete vresp;
-    return NULL;
-  }
-
-  // Special handling for getblock
-  UCHAR* toReturn = vresp->getUserData();
-  *amountReceived = vresp->getUserDataLength();
-  
-  delete vresp;
-  
-  return toReturn;
-}
-
-ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames, bool* IsPesRecording)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_STREAMRECORDING, true, strlen(fileName) + 1)) return 0;
-  if (!vrp.addString(fileName)) return 0;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-  
-  ULLONG lengthBytes = vresp->extractULLONG();
-  ULONG lengthFrames = vresp->extractULONG();
-  UCHAR isPesRecording = vresp->extractUCHAR();
-  delete vresp;
-
-  *totalFrames = lengthFrames;
-  *IsPesRecording = (isPesRecording);//convert Uchar to bool
-
-  logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu, IsPesRecording %x", lengthBytes, lengthFrames, *IsPesRecording);
-
-  return lengthBytes;
-}
-
-ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_POSFROMFRAME, true, sizeof(ULONG))) return 0;
-  if (!vrp.addULONG(frameNumber)) return 0;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-  
-  ULLONG position = vresp->extractULLONG();
-  delete vresp;
-  
-  logger->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
-
-  return position;
-}
-
-ULONG VDR::frameNumberFromPosition(ULLONG position)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_FRAMEFROMPOS, true, sizeof(ULLONG))) return 0;
-  if (!vrp.addULLONG(position)) return 0;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-  
-  ULONG framenumber = vresp->extractULONG();
-  delete vresp;
-  
-  logger->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
-
-  return framenumber;
-}
-
-bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETNEXTIFRAME, true, sizeof(ULONG)*2)) return false;
-  if (!vrp.addULONG(frameNumber)) return false;
-  if (!vrp.addULONG(direction)) return false;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return false; }
-  
-  if (vresp->serverError())
-  {
-    logger->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
-    delete vresp;
-    return false;
-  }
-
-  *rfilePosition = vresp->extractULLONG();
-  *rframeNumber = vresp->extractULONG();
-  *rframeLength = vresp->extractULONG();
-
-  delete vresp;
-
-  logger->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
-
-  return true;
-}
-
-EventList* VDR::getChannelSchedule(ULONG number)
-{
-  time_t now;
-  time(&now);
-  return getChannelSchedule(number, now, 24 * 60 * 60);
-}
-
-EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
-{
-// retrieve event list (vector of events) from vdr within filter window. duration is in seconds
-
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETCHANNELSCHEDULE, true, sizeof(ULONG)*3)) return NULL;
-  if (!vrp.addULONG(number)) return NULL;
-  if (!vrp.addULONG(start)) return NULL;
-  if (!vrp.addULONG(duration)) return NULL;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return NULL; }
-  
-  // received a ulong(0) - schedules error in the plugin
-  if (vresp->serverError())
-  {
-    delete vresp;
-    return NULL;
-  }
-
-  EventList* eventList = new EventList();
-
-  while (!vresp->end())
-  {
-    Event* event = new Event();
-    event->id = vresp->extractULONG();
-    event->time = vresp->extractULONG();
-    event->duration = vresp->extractULONG();
-    event->title = vresp->extractString();
-    event->subtitle = vresp->extractString();
-    event->description = vresp->extractString();
-    eventList->push_back(event);
-  }
-
-  delete vresp;
-
-  logger->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
-  return eventList;
-}
-
-int VDR::configSave(const char* section, const char* key, const char* value)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_CONFIGSAVE, false, 0)) return 0;
-  if (!vrp.addString(section)) return 0;
-  if (!vrp.addString(key)) return 0;
-  if (!vrp.addString(value)) return 0;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-  
-  int toReturn = (int)vresp->extractULONG();
-  delete vresp;
-
-  return toReturn;
-}
-
-char* VDR::configLoad(const char* section, const char* key)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_CONFIGLOAD, false, 0)) return NULL;
-  if (!vrp.addString(section)) return NULL;
-  if (!vrp.addString(key)) return NULL;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return NULL; }
-  
-  char* toReturn = vresp->extractString();
-  delete vresp;
-
-  return toReturn;
-}
-
-RecTimerList* VDR::getRecTimersList()
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETTIMERS, true, 0)) return NULL;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return NULL; }
-
-  RecTimerList* recTimerList = new RecTimerList();
-
-  ULONG numTimers = vresp->extractULONG();
-  if (numTimers > 0)
-  {
-    RecTimer* newRecTimer;
-    char* tempString;
-
-    while (!vresp->end())
-    {
-      newRecTimer = new RecTimer();
-      newRecTimer->active = vresp->extractULONG();
-      newRecTimer->recording = vresp->extractULONG();
-      newRecTimer->pending = vresp->extractULONG();
-      newRecTimer->priority = vresp->extractULONG();
-      newRecTimer->lifeTime = vresp->extractULONG();
-      newRecTimer->channelNumber = vresp->extractULONG();
-      newRecTimer->startTime = vresp->extractULONG();
-      newRecTimer->stopTime = vresp->extractULONG();
-      newRecTimer->day = vresp->extractULONG();
-      newRecTimer->weekDays = vresp->extractULONG();
-
-      tempString = vresp->extractString();
-      newRecTimer->setFile(tempString);
-      delete[] tempString;
-
-      recTimerList->push_back(newRecTimer);
-      logger->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
-        newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
-        newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
-    }
-  }
-
-  delete vresp;
-
-  sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
-
-  return recTimerList;
-}
-
-ULONG VDR::setEventTimer(char* timerString)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_SETTIMER, true, strlen(timerString) + 1)) return 0;
-  if (!vrp.addString(timerString)) return 0;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-  
-  ULONG toReturn = vresp->extractULONG();
-  delete vresp;
-
-  return toReturn;
-}
-
-RecInfo* VDR::getRecInfo(char* fileName)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETRECINFO, true, strlen(fileName) + 1)) return NULL;
-  if (!vrp.addString(fileName)) return NULL;
-  
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return NULL; }
-  
-  if (vresp->serverError())
-  {
-    logger->log("VDR", Log::DEBUG, "Could not get rec info");
-    delete vresp;
-    return NULL;
-  }
-
-  RecInfo* recInfo = new RecInfo();
-
-  recInfo->timerStart = vresp->extractULONG();
-  recInfo->timerEnd = vresp->extractULONG();
-  recInfo->resumePoint = vresp->extractULONG();
-  recInfo->summary = vresp->extractString();
-
-  ULONG numComponents = vresp->extractULONG();
-  if (numComponents)
-  {
-    recInfo->setNumComponents(numComponents);
-    for (ULONG i = 0; i < numComponents; i++)
-    {
-      recInfo->streams[i] = vresp->extractUCHAR();
-      recInfo->types[i] = vresp->extractUCHAR();
-      recInfo->languages[i] = vresp->extractString();
-      recInfo->descriptions[i] = vresp->extractString();
-    }
-  }
-  recInfo->fps=vresp->extractdouble();
-  
-
-  recInfo->print();
-
-  delete vresp;
-  return recInfo;
-}
-
-// FIXME obselete
-ULLONG VDR::rescanRecording(ULONG* totalFrames)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_RESCANRECORDING, true, 0)) return 0;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-  
-  ULLONG lengthBytes = vresp->extractULLONG();
-  ULONG lengthFrames = vresp->extractULONG();
-  delete vresp;
-  
-  logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
-
-  *totalFrames = lengthFrames;
-  return lengthBytes;
-}
-
-MarkList* VDR::getMarks(char* fileName)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETMARKS, true, strlen(fileName) + 1)) return NULL;
-  if (!vrp.addString(fileName)) return NULL;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return NULL; }
-  
-  if (vresp->serverError())
-  {
-    delete vresp;
-    return NULL;
-  }
-
-  MarkList* markList = new MarkList();
-
-  while (!vresp->end())
-  {
-    Mark* mark = new Mark();
-    mark->pos = vresp->extractULONG();
-
-    markList->push_back(mark);
-    logger->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);
-  }
-
-  delete vresp;
-  
-  return markList;
-}
-
-void VDR::getChannelPids(Channel* channel)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETCHANNELPIDS, true, sizeof(ULONG))) return ;
-  if (!vrp.addULONG(channel->number)) return ;
-
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return ; }
-  
-  // Format of response
-  // vpid
-  // number of apids
-  // {
-  //    apid
-  //    lang string
-  // }
-
-  channel->vpid = vresp->extractULONG();
-  channel->vstreamtype = vresp->extractULONG();
-  channel->numAPids = vresp->extractULONG();
-
-  for (ULONG i = 0; i < channel->numAPids; i++)
-  {
-    apid newapid;
-    newapid.pid = vresp->extractULONG();
-    newapid.name = vresp->extractString();
-    channel->apids.push_back(newapid);
-  }
-
-  channel->numDPids = vresp->extractULONG();
-
-  for (ULONG i = 0; i < channel->numDPids; i++)
-  {
-    apid newdpid;
-    newdpid.pid = vresp->extractULONG();
-    newdpid.name = vresp->extractString();
-    channel->dpids.push_back(newdpid);
-  }
-
-  channel->numSPids = vresp->extractULONG();
-
-  for (ULONG i = 0; i < channel->numSPids; i++)
-  {
-    apid newspid;
-    newspid.pid = vresp->extractULONG();
-    newspid.name = vresp->extractString();
-    channel->spids.push_back(newspid);
-  }
-  channel->tpid = vresp->extractULONG();
-
-  delete vresp;
-  
-  return ;
-}
-
-
-MediaList * VDR::getRootList() {
-  return getMediaList(NULL);
-}
-/**
-  * media List Request:
-  * mediaURI
-  * Media List response:
-  * mediaList
-*/
-MediaList* VDR::getMediaList(const MediaURI * root)
-{
-  logger->log("VDR", Log::DEBUG, "getMediaList %s,d=%s, prov=%d", (root?root->getName():"NULL"), 
-      ((root && root->hasDisplayName())?root->getDisplayName():"NULL"),
-      (root?root->getProvider():providerId));
-  MediaURI remoteURI(root);
-  VDR_GetMediaListRequest request(&remoteURI);
-  SerializeBuffer *vrp=prepareRequest(&request);
-  if (!vrp) {
-    logger->log("VDR", Log::ERR, "getMediaList unable to create command");
-    return NULL;
-  }
-    
-  SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
-  if (!vresp) {
-    Command::getInstance()->connectionLost();
-    return NULL;
-  }
-  
-  MediaList *rt=new MediaList(NULL);
-  ULONG rtflags=0;
-  VDR_GetMediaListResponse resp(&rtflags,rt);
-  if (decodeResponse(vresp,&resp) != 0) {
-    return NULL;
-  }
-  return rt;
-}
-
-/**
-  * get image Request:
-  * uri,x,y, channel
-  * get media response:
-  * 4 flags
-  * 8 len of image
-*/
-int VDR::openMedium(ULONG channel,const MediaURI *uri,  ULLONG * size, ULONG x, ULONG y)
-{
-  MediaURI remoteURI(uri);
-  VDR_OpenMediumRequest request(&channel,&remoteURI,&x,&y);
-  *size=0;
-  SerializeBuffer *vrp=prepareRequest(&request);
-  if (!vrp) {
-    logger->log("VDR", Log::ERR, "openMedium unable to create command");
-    return -1;
-  }
-  SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
-  if (!vresp) {
-    Command::getInstance()->connectionLost();
-    return -1;
-  }
-  ULONG flags=0;
-  VDR_OpenMediumResponse response(&flags,size);
-  if (decodeResponse(vresp,&response) != 0) {
-    return -1;
-  }
-  logger->log("VDR", Log::DEBUG, "openMedia len=%llu", *size);
-  return 0;
-}
-
-/**
-  * getMediaBlock - no separate response class - simple data block
-  * resp
-  * packet
-  */
-int VDR::getMediaBlock(ULONG channel, ULLONG position, ULONG maxAmount, ULONG* amountReceived, unsigned char **buffer)
-{
-  *amountReceived=0;
-  VDR_GetMediaBlockRequest request(&channel,&position,&maxAmount);
-  SerializeBuffer *vrp=prepareRequest(&request);
-  if (!vrp) {
-    logger->log("VDR", Log::ERR, "getMediaBlock unable to create command");
-    return -1;
-  }
-  SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
-  if (!vresp) {
-    Command::getInstance()->connectionLost();
-    return -1;
-  }
-  
-  // Special handling for getblock
-  *amountReceived = (ULONG)(vresp->getEnd()-vresp->getStart());
-  *buffer = vresp->steelBuffer();
-  delete vresp;
-  return 0;
-}
-
-/**
-  * VDR_GETMEDIAINFO
-  * channel
-  * rt
-  * flags
-  * info
-  */
-
-int VDR::getMediaInfo(ULONG channel, MediaInfo * result) {
-  if (! result) return -1;
-  VDR_GetMediaInfoRequest request(&channel);
-  SerializeBuffer *vrp=prepareRequest(&request);
-  if (!vrp) {
-    logger->log("VDR", Log::ERR, "getMediaInfo unable to create command");
-    return -1;
-  }
-  SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
-  if (!vresp) {
-    Command::getInstance()->connectionLost();
-    return -1;
-  }
-
-  ULONG flags=0;
-  VDR_GetMediaInfoResponse response(&flags,result);
-  if (decodeResponse(vresp,&response) != 0) {
-    return -1;
-  }
-  return 0;
-}
-
-/**
-  * VDR_CLOSECHANNEL
-  * channel
-  * rt
-  * flags
-  */
-
-int VDR::closeMediaChannel(ULONG channel) {
-  VDR_CloseMediaChannelRequest request(&channel);
-  SerializeBuffer *vrp=prepareRequest(&request);
-  if (!vrp) {
-    logger->log("VDR", Log::ERR, "closeMediaChannel unable to create command");
-    return -1;
-  }
-  SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
-  if (!vresp) {
-    Command::getInstance()->connectionLost();
-    return -1;
-  }
-  ULONG flags;
-  VDR_CloseMediaChannelResponse response(&flags);
-  if (decodeResponse(vresp,&response) != 0) return -1;
-  return (flags != 0)?-1:0;
-}
-
-
-
-
-int VDR::deleteTimer(RecTimer* delTimer)
-{
-  logger->log("VDR", Log::DEBUG, "Delete timer called");
-  
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_DELETETIMER, false, 0)) return 0;
-  if (!vrp.addULONG(delTimer->channelNumber)) return 0;
-  if (!vrp.addULONG(delTimer->weekDays)) return 0;    
-  if (!vrp.addULONG(delTimer->day)) return 0;
-  if (!vrp.addULONG(delTimer->startTime)) return 0;  
-  if (!vrp.addULONG(delTimer->stopTime)) return 0; 
-   
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-  
-  int toReturn = (int)vresp->extractULONG();
-  delete vresp;
-
-  return toReturn;
-}
-
-I18n::lang_code_list VDR::getLanguageList()
-{
-  I18n::lang_code_list CodeList;
-  CodeList["en"] = "English"; // Default entry
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETLANGUAGELIST, false, 0)) return CodeList;
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse() || vresp->end())
-  {
-    delete vresp;
-    return CodeList;
-  }
-  CodeList.clear();
-  while (!vresp->end())
-  {
-    char* c_code = vresp->extractString();
-    char* c_name = vresp->extractString();
-    string code = c_code;
-    string name = c_name;
-    CodeList[code] = name;
-    delete[] c_code;
-    delete[] c_name;
-  }
-  delete vresp;
-  return CodeList;
-}
-
-int VDR::getLanguageContent(const std::string code, I18n::trans_table& texts)
-{
-  VDR_RequestPacket vrp;
-  if (!vrp.init(VDR_GETLANGUAGECONTENT, false, 0)) return 0;
-  if (!vrp.addString(code.c_str())) return 0;
-  VDR_ResponsePacket* vresp = RequestResponse(&vrp);
-  if (vresp->noResponse()) { delete vresp; return 0; }
-  texts.clear();
-  while (!vresp->end())
-  {
-    char* c_key = vresp->extractString();
-    char* c_text = vresp->extractString();
-    string key = c_key;
-    string text = c_text;
-    texts[key] = text;
-    delete[] c_key;
-    delete[] c_text;
-  }
-  delete vresp;
-  return 1;
-}
+/*\r
+    Copyright 2004-2008 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vdr.h"\r
+\r
+#include "recman.h"\r
+#include "tcp.h"\r
+#include "log.h"\r
+#include "recinfo.h"\r
+#include "dsock.h"\r
+#include "channel.h"\r
+#include "event.h"\r
+#include "wol.h"\r
+#include "vdrrequestpacket.h"\r
+#include "vdrresponsepacket.h"\r
+#include "command.h"\r
+#include "media.h"\r
+#include "mediaprovider.h"\r
+#include "mediaproviderids.h"\r
+#include "vdrcommand.h"\r
+#include "video.h"\r
+#include "osd.h"\r
+\r
+VDR* VDR::instance = NULL;\r
+//prepare a request\r
+//will create a request package from a command variable and fill this\r
+//caller has to destroy buffer\r
+static SerializeBuffer * prepareRequest(VDR_Command *cmd) {\r
+  SerializeBuffer *buf=new SerializeBuffer(512,false,true);\r
+  if (cmd->serialize(buf) != 0) {\r
+    delete buf;\r
+    return NULL;\r
+  }\r
+  return buf;\r
+}\r
+\r
+//handle request/response\r
+//TODO avoid copy of buffer (needs extension of requestpacket)\r
+//TODO avoid command 2x (needs some more restructuring)\r
+SerializeBuffer * VDR::doRequestResponse(SerializeBuffer *rq,int cmd) {\r
+  VDR_RequestPacket *rt=new VDR_RequestPacket;\r
+  if (! rt) {\r
+    delete rq;\r
+    return NULL;\r
+  }\r
+  if (! rt->init(cmd,true,rq->getCurrent()-rq->getStart())) {\r
+    delete rq;\r
+    delete rt;\r
+    return NULL;\r
+  }\r
+  if (! rt->copyin(rq->getStart(),(ULONG)(rq->getCurrent()-rq->getStart()))) {\r
+    delete rq;\r
+    delete rt;\r
+    return NULL;\r
+  }\r
+  delete rq;\r
+  VDR_ResponsePacket *rp=RequestResponse(rt);\r
+  logger->log("doRequestResponse",Log::DEBUG,"got response %p",rp);\r
+  if ( !rp) {\r
+    delete rt;\r
+    return NULL;\r
+  }\r
+  SerializeBuffer *buf=new SerializeBuffer(rp->getUserData(),rp->getUserDataLength(),true,true,false);\r
+  delete rp;\r
+  return buf;\r
+}\r
+\r
+\r
+\r
+//deserialize a received response\r
+//delete the package\r
+//return !=0 on error\r
+static int decodeResponse(SerializeBuffer *rp,VDR_Command *c) {\r
+  ULONG expected=c->command;\r
+  if (c->deserialize(rp) != 0) {\r
+    delete rp;\r
+    Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unable to deserialize for command %lu",expected);\r
+    return -1;\r
+  }\r
+  delete rp;\r
+  if (c->command != expected) {\r
+   Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unexpected response received 0x%lx, expected 0x%lx",c->command,expected);\r
+    return -1;\r
+  }\r
+  Log::getInstance()->log("VDR", Log::DEBUG, "decodeResponse successfully decoded command 0x%lx",expected);\r
+  return 0;\r
+}\r
+\r
+\r
+\r
+VDR::VDR()\r
+{\r
+  if (instance) return;\r
+  instance = this;\r
+  initted = 0;\r
+  findingServer = 0;\r
+  tcp = NULL;\r
+  connected = false;\r
+  maxChannelNumber = 0;\r
+  channelNumberWidth = 1;\r
+  TEMP_SINGLE_VDR_PR = NULL;\r
+  providerId=MPROVIDERID_VDR;\r
+  subRange=MPROVIDERRANGE_VDR;\r
+  MediaPlayerRegister::getInstance()->registerMediaProvider(this,MPROVIDERID_VDR,MPROVIDERRANGE_VDR);\r
+}\r
+\r
+VDR::~VDR()\r
+{\r
+  instance = NULL;\r
+  if (initted) shutdown();\r
+}\r
+\r
+VDR* VDR::getInstance()\r
+{\r
+  return instance;\r
+}\r
+\r
+int VDR::init(int tport)\r
+{\r
+  if (initted) return 0;\r
+  initted = 1;\r
+  port = tport;\r
+  logger = Log::getInstance();\r
+  return 1;\r
+}\r
+\r
+int VDR::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+  initted = 0;\r
+  disconnect();\r
+  return 1;\r
+}\r
+\r
+void VDR::findServers(vector<VDRServer>& servers)\r
+{\r
+  Wol* wol = Wol::getInstance();\r
+  findingServer = 1;\r
+  char* message = "VOMP";\r
+\r
+  DatagramSocket ds(port);\r
+  int haveAtLeastOne = 0;\r
+  int retval;\r
+  int waitType = 1;\r
+  bool firstloop = true;\r
+  while(findingServer)\r
+  {\r
+    if (waitType == 1)\r
+    {\r
+      ds.shutdown();\r
+      ds.init();\r
+      logger->log("VDR", Log::NOTICE, "Broadcasting for server");\r
+      ds.send("255.255.255.255", 3024, message, strlen(message));\r
+      if(!firstloop) wol->doWakeUp();\r
+    }\r
+    retval = ds.waitforMessage(waitType);\r
+\r
+    if (retval == 2) // we got a reply\r
+    {\r
+      if (!strcmp(ds.getData(), "VOMP")) // echo.....\r
+      {\r
+        waitType = 2;\r
+      }\r
+      else\r
+      {\r
+        VDRServer newServer;\r
+        newServer.ip = new char[16];\r
+        strcpy(newServer.ip, ds.getFromIPA());\r
+\r
+        if (ds.getDataLength() == 0)\r
+        {\r
+          newServer.name = new char[1];\r
+          newServer.name[0] = '\0';\r
+        }\r
+        else\r
+        {\r
+          newServer.name = new char[strlen(ds.getData())+1];\r
+          strcpy(newServer.name, ds.getData());\r
+        }\r
+\r
+        servers.push_back(newServer);\r
+        waitType = 2;\r
+        haveAtLeastOne = 1;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      if (haveAtLeastOne) break;\r
+      waitType = 1;\r
+      firstloop = false;\r
+/* For DEBUGGING *\r
+      { VDRServer newServer;\r
+      newServer.ip = new char[16];\r
+      strcpy(newServer.ip, "192.168.1.7");\r
+      newServer.name = new char[6];\r
+      strcpy(newServer.name,"debug");\r
+      servers.push_back(newServer);\r
+      waitType = 2;\r
+      haveAtLeastOne = 1;}/**/\r
+\r
+\r
+\r
+    }\r
+  }\r
+  logger->log("VDR", Log::NOTICE, "END loop");\r
+  sort(servers.begin(), servers.end(), ServerSorter());\r
+}\r
+\r
+void VDR::cancelFindingServer()\r
+{\r
+  findingServer = 0;\r
+}\r
+\r
+void VDR::setServerIP(char* newIP)\r
+{\r
+  strcpy(serverIP, newIP);\r
+}\r
+\r
+int VDR::connect()\r
+{\r
+  maxChannelNumber = 0;\r
+  channelNumberWidth = 1;\r
+\r
+  if (tcp) delete tcp;\r
+  tcp = new TCP();\r
+  if (tcp->connectTo(serverIP, 3024))\r
+  {\r
+    connected = true;\r
+    threadStart();\r
+    return 1;\r
+  }\r
+  else\r
+  {\r
+    return 0;\r
+  }\r
+}\r
+\r
+void VDR::disconnect()\r
+{\r
+  threadCancel();\r
+  if (tcp) delete tcp;\r
+  tcp = NULL;\r
+  connected = false;\r
+  logger->log("VDR", Log::DEBUG, "Disconnect");\r
+}\r
+\r
+void VDR::setReceiveWindow(size_t size)\r
+{\r
+  if (connected) tcp->setReceiveWindow(size);\r
+}\r
+\r
+///////////////////////////////////////////////////////\r
+\r
+void VDR::threadMethod()\r
+{\r
+  logger->log("VDR", Log::DEBUG, "VDR RUN");  \r
+\r
+  threadSetKillable(); // FIXME - change this to deal with the EDRs\r
+  \r
+  ULONG channelID;\r
+  \r
+  ULONG requestID;\r
+  ULONG userDataLength;\r
+  UCHAR* userData;\r
+\r
+  ULONG streamID;\r
+  ULONG flag;\r
+\r
+  VDR_ResponsePacket* vresp;\r
+  \r
+  ULONG timeNow = 0;\r
+  ULONG lastKAsent = 0;\r
+  ULONG lastKArecv = time(NULL);\r
+  int readSuccess;\r
+\r
+  while(1)\r
+  {\r
+    timeNow = time(NULL);\r
+    \r
+    readSuccess = tcp->readData((UCHAR*)&channelID, sizeof(ULONG));  // 2s timeout atm\r
+\r
+    if (!readSuccess)\r
+    {\r
+      //logger->log("VDR", Log::DEBUG, "Net read timeout");\r
+      if (!tcp->isConnected()) { connectionDied(); return; } // return to stop this thread\r
+    }\r
+      \r
+    // Error or timeout.\r
+\r
+    if (!lastKAsent) // have not sent a KA\r
+    {\r
+      if (lastKArecv < (timeNow - 5))\r
+      {\r
+        logger->log("VDR", Log::DEBUG, "Sending KA packet");\r
+        if (!sendKA(timeNow))\r
+        {\r
+          logger->log("VDR", Log::DEBUG, "Could not send KA, calling connectionDied");\r
+          connectionDied();\r
+          return;\r
+        }\r
+        lastKAsent = timeNow;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      if (lastKAsent <= (timeNow - 10))\r
+      {\r
+        logger->log("VDR", Log::DEBUG, "lastKA over 10s ago, calling connectionDied");\r
+        connectionDied();\r
+        return;\r
+      }    \r
+    }\r
+\r
+    if (!readSuccess) continue; // no data was read but the connection is ok.\r
+    \r
+    // Data was read\r
+            \r
+    channelID = ntohl(channelID);\r
+   \r
+    if (channelID == CHANNEL_REQUEST_RESPONSE)\r
+    {\r
+      if (!tcp->readData((UCHAR*)&requestID, sizeof(ULONG))) break;\r
+      requestID = ntohl(requestID);\r
+      if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;\r
+      userDataLength = ntohl(userDataLength);\r
+      if (userDataLength > 5000000) break; // how big can these packets get?\r
+      userData = NULL;\r
+      if (userDataLength > 0)\r
+      {\r
+        userData = (UCHAR*)malloc(userDataLength);\r
+        if (!userData) break;\r
+        if (!tcp->readData(userData, userDataLength)) break;\r
+      }\r
+\r
+      vresp = new VDR_ResponsePacket();  \r
+      vresp->setResponse(requestID, userData, userDataLength);\r
+      logger->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength);\r
+\r
+      if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
+      {\r
+        // If edFindAndCall returns true, edr was called and vresp was handed off.\r
+        // else, delete vresp here.\r
+        delete vresp;\r
+      }\r
+    }\r
+    else if (channelID == CHANNEL_STREAM)\r
+    {\r
+      if (!tcp->readData((UCHAR*)&streamID, sizeof(ULONG))) break;\r
+      streamID = ntohl(streamID);\r
+\r
+      if (!tcp->readData((UCHAR*)&flag, sizeof(ULONG))) break;\r
+      flag = ntohl(flag);\r
+\r
+      if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break; \r
+      userDataLength = ntohl(userDataLength);\r
+      userData = NULL;\r
+      if (userDataLength > 0)\r
+      {\r
+        userData = (UCHAR*)malloc(userDataLength);\r
+        if (!userData) break;\r
+        if (!tcp->readData(userData, userDataLength)) break;\r
+      }\r
+\r
+      vresp = new VDR_ResponsePacket();    \r
+      vresp->setStream(streamID, flag, userData, userDataLength);\r
+//      logger->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, flag=%lu, len=%lu", streamID, flag, userDataLength);\r
+\r
+      if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
+      {\r
+        // If edFindAndCall returns true, edr was called and vresp was handed off.\r
+        // else, delete vresp here.\r
+        delete vresp;\r
+      }\r
+    }\r
+    else if (channelID == CHANNEL_KEEPALIVE)\r
+    {\r
+      ULONG KAreply = 0;\r
+      if (!tcp->readData((UCHAR*)&KAreply, sizeof(ULONG))) break;\r
+      KAreply = (ULONG)ntohl(KAreply);\r
+      if (KAreply == lastKAsent) // successful KA response\r
+      {\r
+        lastKAsent = 0;\r
+        lastKArecv = KAreply;\r
+        logger->log("VDR", Log::DEBUG, "Rxd correct KA reply");\r
+      }\r
+    }\r
+    else\r
+    {\r
+      logger->log("VDR", Log::ERR, "Rxd a response packet on channel %lu !!", channelID);\r
+      break;\r
+    }\r
+    threadCheckExit();\r
+\r
+\r
+    // Who deletes vresp?\r
+    // If RR, the individual protocol functions must delete vresp.\r
+    // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there.\r
+  }\r
\r
+  connectionDied();\r
+}\r
+\r
+void VDR::connectionDied()\r
+{\r
+  // Called from within threadMethod to do cleanup if it decides the connection has died\r
+\r
+  connected = false; // though actually it could still be connected until someone calls vdr->disconnect\r
+\r
+  // Need to wake up any waiting channel 1 request-response threads\r
+  // Normally this is done by a packet coming in with channelid and requestid      \r
+  // Instead, go through the list and for each channel 1 edr, make an empty vresp\r
+  // An empty vresp will have userData == NULL, which means vresp->noResponse() == true\r
+\r
+  // If it's a stream receiver, generate a stream packet with flag == connection_lost\r
+\r
+  edLock();\r
+  VDR_PacketReceiver* vdrpr;\r
+  VDR_ResponsePacket* vresp;\r
+  while(receivers.size())\r
+  {\r
+    vdrpr = (VDR_PacketReceiver*) *(receivers.begin());\r
+    if (vdrpr->receiverChannel == CHANNEL_REQUEST_RESPONSE)\r
+    {\r
+      vresp = new VDR_ResponsePacket();\r
+      vresp->setResponse(vdrpr->requestSerialNumber, NULL, 0);\r
+      logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for request serial %lu", vdrpr->requestSerialNumber);\r
+      edUnlock();\r
+      if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
+      {\r
+        // If edFindAndCall returns true, edr was called and vresp was handed off.\r
+        // else, delete vresp here.\r
+        logger->log("VDR", Log::ERR, "Timeouts: no waiting thread found for request serial %lu !!!", vdrpr->requestSerialNumber);\r
+        delete vresp;\r
+      }\r
+      edLock();\r
+    }\r
+    else if (vdrpr->receiverChannel == CHANNEL_STREAM)\r
+    {\r
+      vresp = new VDR_ResponsePacket();\r
+      vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0);\r
+      logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for streamid %lu", vdrpr->streamID);\r
+      edUnlock();\r
+      if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
+      {\r
+        // If edFindAndCall returns true, edr was called and vresp was handed off.\r
+        // else, delete vresp here.\r
+        logger->log("VDR", Log::ERR, "Timeouts: no waiting stream receiver found for streamid %lu !!!", vdrpr->streamID);\r
+        delete vresp;\r
+      }\r
+      edLock();\r
+      \r
+      for(EDRL::iterator i = receivers.begin(); i != receivers.end(); i++)\r
+        if ((VDR_PacketReceiver*)*i == vdrpr) { receivers.erase(i); break; }\r
+    }\r
+  }\r
+  edUnlock();\r
+  // Ok, all event receviers should be dealt with. just in case there weren't any, inform command\r
+  logger->log("VDR", Log::DEBUG, "edUnlock at end of connectionDied");\r
+\r
+  Command::getInstance()->connectionLost();\r
+}\r
+\r
+bool VDR::ed_cb_find(EDReceiver* edr, void* userTag)\r
+{\r
+  // edr is a VDR_PacketReceiver object made in VDR::RequestResponse\r
+  // userTag is a VDR_ResponsePacket made in threadMethod\r
+\r
+  VDR_PacketReceiver* vdrpr = (VDR_PacketReceiver*)edr;\r
+  VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;\r
+  \r
+  // Is vresp for vdrpr ?\r
+  \r
+  ULONG packetChannel = vresp->getChannelID();\r
+  if (vdrpr->receiverChannel != packetChannel) return false;\r
+\r
+  if (packetChannel == CHANNEL_REQUEST_RESPONSE)\r
+  {\r
+    if (vdrpr->requestSerialNumber == vresp->getRequestID()) return true;\r
+  }\r
+  else if (packetChannel == CHANNEL_STREAM)\r
+  {\r
+    if (vdrpr->streamID == vresp->getStreamID()) return true;\r
+  }\r
\r
+  return false;\r
+}\r
+\r
+VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)\r
+{\r
+  //logger->log("VDR", Log::DEBUG, "RR %lu", vrp->getOpcode());\r
+\r
+  if (!connected)\r
+  {\r
+    logger->log("VDR", Log::DEBUG, "RR when !connected");\r
+    VDR_ResponsePacket* vresp = new VDR_ResponsePacket();\r
+    return vresp; // "no-response" return\r
+  }\r
+\r
+  // ED make new VDR and register\r
+  // make a VDR_PacketReceiver\r
+  // - init with serial number of request packet\r
+\r
+  VDR_PacketReceiver vdrpr;\r
+//  vdrpr.requestTime = time(NULL);\r
+  vdrpr.receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE;\r
+  vdrpr.requestSerialNumber = vrp->getSerial();\r
+\r
+  edRegister(&vdrpr);\r
+   \r
+  edLock();  \r
+\r
+  if ((ULONG)tcp->sendData(vrp->getPtr(), vrp->getLen()) != vrp->getLen())\r
+  {\r
+    edUnlock();\r
+    edUnregister(&vdrpr);\r
+    VDR_ResponsePacket* vresp = new VDR_ResponsePacket();\r
+    return vresp; // "no-response" return\r
+  }\r
+\r
+  // Sleep and block this thread. The sleep unlocks the mutex\r
+  logger->log("VDR", Log::DEBUG, "RR sleep - opcode %lu", vrp->getOpcode());\r
+  edSleepThisReceiver(&vdrpr);\r
+  logger->log("VDR", Log::DEBUG, "RR unsleep");\r
+    \r
+  // Woken because a response packet has arrived, mutex will be locked\r
+  \r
+  edUnlock();\r
+  return vdrpr.save_vresp;\r
+}\r
+\r
+bool VDR::sendKA(ULONG timeStamp)\r
+{\r
+  char buffer[8];\r
+\r
+  int pos=0;\r
+  ULONG ul=CHANNEL_KEEPALIVE;\r
+  buffer[pos++]=(ul>>24)&0xff;\r
+  buffer[pos++]=(ul>>16)&0xff;\r
+  buffer[pos++]=(ul>>8)&0xff;\r
+  buffer[pos++]=ul &0xff;\r
+  ul=timeStamp;\r
+  buffer[pos++]=(ul>>24)&0xff;\r
+  buffer[pos++]=(ul>>16)&0xff;\r
+  buffer[pos++]=(ul>>8)&0xff;\r
+  buffer[pos++]=ul &0xff;\r
+  if ((ULONG)tcp->sendData(buffer, 8) != 8) return false;\r
+  return true;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+// Here VDR takes a break for the VDR_PacketReceiver helper class\r
+\r
+bool VDR_PacketReceiver::call(void* userTag)\r
+{\r
+  if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE)\r
+  {\r
+    // It's a RR. Save vresp and, signal the waiting thread and return.\r
+    // VDR::RequestResponse will be blocking waiting for this to happen.\r
+    // That function has a pointer to this object and can read save_vresp.\r
+    save_vresp = (VDR_ResponsePacket*)userTag;\r
+    return true; // Signals ED to remove edr from receivers and wake up edr thread\r
+  }\r
+  \r
+  if (receiverChannel == VDR::CHANNEL_STREAM)\r
+  {\r
+    // It's a stream packet.\r
+    VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;\r
+    streamReceiver->streamReceive(vresp->getFlag(), vresp->getUserData(), vresp->getUserDataLength());\r
+    delete vresp;\r
+    return false;\r
+  }\r
+\r
+  abort(); // unknown receiverChannel, should not happen\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+int VDR::doLogin()\r
+{\r
+  VDR_RequestPacket vrp;\r
+  if (!vrp.init(VDR_LOGIN, true, 6)) return 0;\r
+\r
+  char* mactemp[6];\r
+  tcp->getMAC((char*)mactemp);\r
+  if (!vrp.copyin((UCHAR*)mactemp, 6)) return 0;\r
+\r
+  VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+  if (vresp->noResponse()) { delete vresp; return 0; }\r
+\r
+  ULONG vdrTime = vresp->extractULONG();\r
+  logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);\r
+  long vdrTimeOffset = vresp->extractLONG();\r
+  logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);\r
+\r
+  delete vresp;\r
+\r
+  // Set the time and zone on the MVP only\r
+\r
+#if !defined(WIN32) && !defined(__ANDROID__)\r
+  struct timespec currentTime;\r
+  currentTime.tv_sec = vdrTime;\r
+  currentTime.tv_nsec = 0;\r
+\r
+  int b = clock_settime(CLOCK_REALTIME, &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
+    newapid.name = vresp->extractString();\r
+    channel->apids.push_back(newapid);\r
+  }\r
+\r
+  channel->numDPids = vresp->extractULONG();\r
+\r
+  for (ULONG i = 0; i < channel->numDPids; i++)\r
+  {\r
+    apid newdpid;\r
+    newdpid.pid = vresp->extractULONG();\r
+    newdpid.name = vresp->extractString();\r
+    channel->dpids.push_back(newdpid);\r
+  }\r
+\r
+  channel->numSPids = vresp->extractULONG();\r
+\r
+  for (ULONG i = 0; i < channel->numSPids; i++)\r
+  {\r
+    apid newspid;\r
+    newspid.pid = vresp->extractULONG();\r
+    newspid.name = vresp->extractString();\r
+    channel->spids.push_back(newspid);\r
+  }\r
+  channel->tpid = vresp->extractULONG();\r
+\r
+  delete vresp;\r
+  \r
+  return ;\r
+}\r
+\r
+\r
+MediaList * VDR::getRootList() {\r
+  return getMediaList(NULL);\r
+}\r
+/**\r
+  * media List Request:\r
+  * mediaURI\r
+  * Media List response:\r
+  * mediaList\r
+*/\r
+MediaList* VDR::getMediaList(const MediaURI * root)\r
+{\r
+  logger->log("VDR", Log::DEBUG, "getMediaList %s,d=%s, prov=%d", (root?root->getName():"NULL"), \r
+      ((root && root->hasDisplayName())?root->getDisplayName():"NULL"),\r
+      (root?root->getProvider():providerId));\r
+  MediaURI remoteURI(root);\r
+  VDR_GetMediaListRequest request(&remoteURI);\r
+  SerializeBuffer *vrp=prepareRequest(&request);\r
+  if (!vrp) {\r
+    logger->log("VDR", Log::ERR, "getMediaList unable to create command");\r
+    return NULL;\r
+  }\r
+    \r
+  SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
+  if (!vresp) {\r
+    Command::getInstance()->connectionLost();\r
+    return NULL;\r
+  }\r
+  \r
+  MediaList *rt=new MediaList(NULL);\r
+  ULONG rtflags=0;\r
+  VDR_GetMediaListResponse resp(&rtflags,rt);\r
+  if (decodeResponse(vresp,&resp) != 0) {\r
+    return NULL;\r
+  }\r
+  return rt;\r
+}\r
+\r
+/**\r
+  * get image Request:\r
+  * uri,x,y, channel\r
+  * get media response:\r
+  * 4 flags\r
+  * 8 len of image\r
+*/\r
+int VDR::openMedium(ULONG channel,const MediaURI *uri,  ULLONG * size, ULONG x, ULONG y)\r
+{\r
+  MediaURI remoteURI(uri);\r
+  VDR_OpenMediumRequest request(&channel,&remoteURI,&x,&y);\r
+  *size=0;\r
+  SerializeBuffer *vrp=prepareRequest(&request);\r
+  if (!vrp) {\r
+    logger->log("VDR", Log::ERR, "openMedium unable to create command");\r
+    return -1;\r
+  }\r
+  SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
+  if (!vresp) {\r
+    Command::getInstance()->connectionLost();\r
+    return -1;\r
+  }\r
+  ULONG flags=0;\r
+  VDR_OpenMediumResponse response(&flags,size);\r
+  if (decodeResponse(vresp,&response) != 0) {\r
+    return -1;\r
+  }\r
+  logger->log("VDR", Log::DEBUG, "openMedia len=%llu", *size);\r
+  return 0;\r
+}\r
+\r
+/**\r
+  * getMediaBlock - no separate response class - simple data block\r
+  * resp\r
+  * packet\r
+  */\r
+int VDR::getMediaBlock(ULONG channel, ULLONG position, ULONG maxAmount, ULONG* amountReceived, unsigned char **buffer)\r
+{\r
+  *amountReceived=0;\r
+  VDR_GetMediaBlockRequest request(&channel,&position,&maxAmount);\r
+  SerializeBuffer *vrp=prepareRequest(&request);\r
+  if (!vrp) {\r
+    logger->log("VDR", Log::ERR, "getMediaBlock unable to create command");\r
+    return -1;\r
+  }\r
+  SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
+  if (!vresp) {\r
+    Command::getInstance()->connectionLost();\r
+    return -1;\r
+  }\r
+  \r
+  // Special handling for getblock\r
+  *amountReceived = (ULONG)(vresp->getEnd()-vresp->getStart());\r
+  *buffer = vresp->steelBuffer();\r
+  delete vresp;\r
+  return 0;\r
+}\r
+\r
+/**\r
+  * VDR_GETMEDIAINFO\r
+  * channel\r
+  * rt\r
+  * flags\r
+  * info\r
+  */\r
+\r
+int VDR::getMediaInfo(ULONG channel, MediaInfo * result) {\r
+  if (! result) return -1;\r
+  VDR_GetMediaInfoRequest request(&channel);\r
+  SerializeBuffer *vrp=prepareRequest(&request);\r
+  if (!vrp) {\r
+    logger->log("VDR", Log::ERR, "getMediaInfo unable to create command");\r
+    return -1;\r
+  }\r
+  SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
+  if (!vresp) {\r
+    Command::getInstance()->connectionLost();\r
+    return -1;\r
+  }\r
+\r
+  ULONG flags=0;\r
+  VDR_GetMediaInfoResponse response(&flags,result);\r
+  if (decodeResponse(vresp,&response) != 0) {\r
+    return -1;\r
+  }\r
+  return 0;\r
+}\r
+\r
+/**\r
+  * VDR_CLOSECHANNEL\r
+  * channel\r
+  * rt\r
+  * flags\r
+  */\r
+\r
+int VDR::closeMediaChannel(ULONG channel) {\r
+  VDR_CloseMediaChannelRequest request(&channel);\r
+  SerializeBuffer *vrp=prepareRequest(&request);\r
+  if (!vrp) {\r
+    logger->log("VDR", Log::ERR, "closeMediaChannel unable to create command");\r
+    return -1;\r
+  }\r
+  SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
+  if (!vresp) {\r
+    Command::getInstance()->connectionLost();\r
+    return -1;\r
+  }\r
+  ULONG flags;\r
+  VDR_CloseMediaChannelResponse response(&flags);\r
+  if (decodeResponse(vresp,&response) != 0) return -1;\r
+  return (flags != 0)?-1:0;\r
+}\r
+\r
+\r
+\r
+\r
+int VDR::deleteTimer(RecTimer* delTimer)\r
+{\r
+  logger->log("VDR", Log::DEBUG, "Delete timer called");\r
+  \r
+  VDR_RequestPacket vrp;\r
+  if (!vrp.init(VDR_DELETETIMER, false, 0)) return 0;\r
+  if (!vrp.addULONG(delTimer->channelNumber)) return 0;\r
+  if (!vrp.addULONG(delTimer->weekDays)) return 0;    \r
+  if (!vrp.addULONG(delTimer->day)) return 0;\r
+  if (!vrp.addULONG(delTimer->startTime)) return 0;  \r
+  if (!vrp.addULONG(delTimer->stopTime)) return 0; \r
+   \r
+  VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+  if (vresp->noResponse()) { delete vresp; return 0; }\r
+  \r
+  int toReturn = (int)vresp->extractULONG();\r
+  delete vresp;\r
+\r
+  return toReturn;\r
+}\r
+\r
+I18n::lang_code_list VDR::getLanguageList()\r
+{\r
+  I18n::lang_code_list CodeList;\r
+  CodeList["en"] = "English"; // Default entry\r
+  VDR_RequestPacket vrp;\r
+  if (!vrp.init(VDR_GETLANGUAGELIST, false, 0)) return CodeList;\r
+  VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+  if (vresp->noResponse() || vresp->end())\r
+  {\r
+    delete vresp;\r
+    return CodeList;\r
+  }\r
+  CodeList.clear();\r
+  while (!vresp->end())\r
+  {\r
+    char* c_code = vresp->extractString();\r
+    char* c_name = vresp->extractString();\r
+    string code = c_code;\r
+    string name = c_name;\r
+    CodeList[code] = name;\r
+    delete[] c_code;\r
+    delete[] c_name;\r
+  }\r
+  delete vresp;\r
+  return CodeList;\r
+}\r
+\r
+int VDR::getLanguageContent(const std::string code, I18n::trans_table& texts)\r
+{\r
+  VDR_RequestPacket vrp;\r
+  if (!vrp.init(VDR_GETLANGUAGECONTENT, false, 0)) return 0;\r
+  if (!vrp.addString(code.c_str())) return 0;\r
+  VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
+  if (vresp->noResponse()) { delete vresp; return 0; }\r
+  texts.clear();\r
+  while (!vresp->end())\r
+  {\r
+    char* c_key = vresp->extractString();\r
+    char* c_text = vresp->extractString();\r
+    string key = c_key;\r
+    string text = c_text;\r
+    texts[key] = text;\r
+    delete[] c_key;\r
+    delete[] c_text;\r
+  }\r
+  delete vresp;\r
+  return 1;\r
+}\r
diff --git a/vdr.h b/vdr.h
index c3ff0f125eef1600308c96798ad118672c923091..01f6b0fe297834a0bfd9f812264b42b4cee594ea 100644 (file)
--- a/vdr.h
+++ b/vdr.h
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-
-// FIXME - This and the protocol are overly complicated now. Sorry.
-//         I'll clean it up in a couple of releases time...
-
-
-#ifndef VDR_H
-#define VDR_H
-
-#include <stdio.h>
-#include <time.h>
-#include <vector>
-#include <algorithm>
-
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
-#include "defines.h"
-#include "rectimer.h"
-#include "mark.h"
-#include "mediaprovider.h"
-#include "eventdispatcher.h"
-#include "i18n.h"
-
-class TCP;
-class Log;
-class RecInfo;
-class Event;
-class Channel;
-class VDR_RequestPacket;
-class VDR_ResponsePacket;
-class SerializeBuffer;
-
-using namespace std;
-
-typedef vector<Event*> EventList;
-typedef vector<Channel*> ChannelList;
-typedef vector<RecTimer*> RecTimerList;
-
-struct VDRServer
-{
-  char* ip;
-  char* name;
-};
-
-struct RecTimerSorter     // : public binary_function<double, double, bool>
-{
-  bool operator() (const RecTimer* a, const RecTimer* b)
-  {
-    return a->startTime < b->startTime;
-  }
-};
-
-struct ServerSorter
-{
-  bool operator() (const VDRServer& a, const VDRServer& b)
-  {
-    if (strcmp(b.name, a.name) > 0) return true;
-    return false;
-  }
-};
-
-class RecMan;
-
-class StreamReceiver
-{
-  public:
-    virtual void streamReceive(ULONG, void*, ULONG)=0;
-};
-
-class VDR_PacketReceiver : public EDReceiver // implementation in vdr.cc
-{
-  public:
-    virtual bool call(void* userTag);
-
-  friend class VDR;
-  protected:
-//    ULONG requestTime;
-    ULONG receiverChannel;
-    
-    // If receiverChannel == 1:
-    ULONG requestSerialNumber;      // set by RequestResponse, used in ed_cb_find
-    VDR_ResponsePacket* save_vresp; // set by ed_cb_call, used in RequestResponse
-        
-    // If receiverChannel == 2:
-    ULONG streamID;
-    StreamReceiver* streamReceiver;
-};
-
-class VDR : public Thread_TYPE, public EventDispatcher, public MediaProvider
-{
-
-  public:
-    const static ULONG VIDEO = 1;
-    const static ULONG RADIO = 2;
-  
-    const static ULONG CHANNEL_REQUEST_RESPONSE = 1;
-    const static ULONG CHANNEL_STREAM = 2;
-    const static ULONG CHANNEL_KEEPALIVE = 3;
-    const static ULONG CHANNEL_NETLOG = 4;
-  
-    VDR();
-    ~VDR();
-    static VDR* getInstance();
-
-    int init(int port);
-    int shutdown();
-
-    void findServers(vector<VDRServer>& servers);
-    void cancelFindingServer();
-    void setServerIP(char*);
-    void setReceiveWindow(size_t size);
-    int connect();
-    void disconnect();
-    bool isConnected() { return connected; }
-    ULONG getChannelNumberWidth() { return channelNumberWidth; }
-
-    // protocol functions
-    // for the following, if result == false then the connection has died
-    //  doLogin
-    //  getRecordingList
-    //  getChannelsList
-    //  getChannelSchedule
-    //  getRecTimersList
-    // isConnected can be called after the following to determine if still ok
-    //  deleteRecording
-    //  streamRecording
-    //  positionFromFrameNumber
-    //  streamChannel
-    //  getBlock
-    //  stopStreaming
-    //  configLoad
-    //  configSave
-    //  setEventTimer
-
-    int           doLogin();
-    bool          getRecordingsList(RecMan* recman);
-    RecInfo*      getRecInfo(char* fileName);
-    int           deleteRecording(char* fileName);
-    char*         moveRecording(char* fileName, char* newPath);
-    ULLONG        streamRecording(char* fileName, ULONG* lengthFrames, bool* IsPesRecording);
-    ULLONG        positionFromFrameNumber(ULONG frameNumber);
-    ULONG         frameNumberFromPosition(ULLONG position);
-    bool          getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength);
-                  // Direction: 0=backwards, 1=forwards
-    MarkList*     getMarks(char* fileName);
-    int           deleteTimer(RecTimer* delTimer);
-    ChannelList*  getChannelsList(ULONG type);
-    int           streamChannel(ULONG number, StreamReceiver*);
-    int           streamChannel(ULONG number);
-    void          getChannelPids(Channel* channel);
-    UCHAR*        getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived);
-                  //get image blocks separate - we can do this in parallel
-    int           stopStreaming();
-    EventList*    getChannelSchedule(ULONG number);
-    EventList*    getChannelSchedule(ULONG number, time_t start, ULONG duration);
-    int           configSave(const char* section, const char* key, const char* value);
-    char*         configLoad(const char* section, const char* key);
-    ULONG         setEventTimer(char* timerString);
-    RecTimerList* getRecTimersList();
-    bool          networkLog(const char* buffer);
-    
-    /**
-      * the MediaProvider functions
-      *
-      */
-    virtual MediaList* getRootList();
-    virtual MediaList* getMediaList(const MediaURI * parent);
-    virtual int        openMedium(ULONG channel,const MediaURI *uri,ULLONG * size, ULONG xsize,ULONG ysize);
-    virtual int getMediaBlock(ULONG channel, unsigned long long offset, unsigned long len, unsigned long * outlen,
-        unsigned char ** buffer);
-    virtual int getMediaInfo(ULONG channel, struct MediaInfo * result);
-    virtual int closeMediaChannel(ULONG channel);
-
-
-    I18n::lang_code_list getLanguageList();
-    int           getLanguageContent(const string code, I18n::trans_table&);
-
-    // end protocol functions
-
-
-    // obselete
-    ULLONG     rescanRecording(ULONG* lengthFrames);                    // FIXME obselete
-
-
-
-  private:
-    static VDR* instance;
-
-    VDR_ResponsePacket* RequestResponse(VDR_RequestPacket* request);
-    UCHAR* getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived, ULONG cmd);
-    
-    void connectionDied();
-    bool sendKA(ULONG timeStamp);
-    
-    Log* logger;
-    int initted;
-    int findingServer;
-    TCP* tcp;
-    int port;
-    char serverIP[16];
-    bool connected;
-    ULONG maxChannelNumber;
-    ULONG channelNumberWidth;
-    VDR_PacketReceiver* TEMP_SINGLE_VDR_PR;
-
-
-    ULONG providerId;
-    ULONG subRange;
-    SerializeBuffer * doRequestResponse(SerializeBuffer *in,int cmd);
-  protected:
-  
-    // Thread
-    void threadMethod();
-    void threadPostStopCleanup() {};
-
-    // EventDispatcher
-    virtual bool ed_cb_find(EDReceiver* edr, void* userTag);
-};
-
-#endif
-
-/*
-
-index.vdr file format for video:
-
-For every video frame:
-{
-  File offset    4 bytes
-  Picture type   1 byte
-  File number    1 byte
-  Zero           2 bytes
-}
-
-Picture types:
-
-#define NO_PICTURE 0
-#define I_FRAME    1
-#define P_FRAME    2
-#define B_FRAME    3
-
-
-
-Packet formats
-
-Packet format for an RR channel request:
-
-4 bytes = channel ID = 1 (request/response channel)
-4 bytes = request ID (from serialNumber)
-4 bytes = opcode
-4 bytes = length of the rest of the packet
-? bytes = rest of packet. depends on packet
-
-
-Packet format for an RR channel response:
-
-4 bytes = channel ID = 1 (request/response channel)
-4 bytes = request ID (from serialNumber)
-4 bytes = length of the rest of the packet
-? bytes = rest of packet. depends on packet
-
-
-Packet format for a stream packet:
-
-4 bytes = channel ID = 2 (stream channel)
-4 bytes = stream ID (from requestID)
-4 bytes = length of the stream data (rest of packet)
-? bytes = stream data
-
-*/
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+\r
+// FIXME - This and the protocol are overly complicated now. Sorry.\r
+//         I'll clean it up in a couple of releases time...\r
+\r
+\r
+#ifndef VDR_H\r
+#define VDR_H\r
+\r
+#include <stdio.h>\r
+#include <time.h>\r
+#include <vector>\r
+#include <algorithm>\r
+\r
+#include "threadsystem.h"\r
+\r
+#include "defines.h"\r
+#include "rectimer.h"\r
+#include "mark.h"\r
+#include "mediaprovider.h"\r
+#include "eventdispatcher.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+\r
+class TCP;\r
+class Log;\r
+class RecInfo;\r
+class Event;\r
+class Channel;\r
+class VDR_RequestPacket;\r
+class VDR_ResponsePacket;\r
+class SerializeBuffer;\r
+\r
+using namespace std;\r
+\r
+typedef vector<Event*> EventList;\r
+typedef vector<Channel*> ChannelList;\r
+typedef vector<RecTimer*> RecTimerList;\r
+\r
+struct VDRServer\r
+{\r
+  char* ip;\r
+  char* name;\r
+};\r
+\r
+struct RecTimerSorter     // : public binary_function<double, double, bool>\r
+{\r
+  bool operator() (const RecTimer* a, const RecTimer* b)\r
+  {\r
+    return a->startTime < b->startTime;\r
+  }\r
+};\r
+\r
+struct ServerSorter\r
+{\r
+  bool operator() (const VDRServer& a, const VDRServer& b)\r
+  {\r
+    if (strcmp(b.name, a.name) > 0) return true;\r
+    return false;\r
+  }\r
+};\r
+\r
+class RecMan;\r
+\r
+class StreamReceiver\r
+{\r
+  public:\r
+    virtual void streamReceive(ULONG, void*, ULONG)=0;\r
+};\r
+\r
+class VDR_PacketReceiver : public EDReceiver // implementation in vdr.cc\r
+{\r
+  public:\r
+    virtual bool call(void* userTag);\r
+\r
+  friend class VDR;\r
+  protected:\r
+//    ULONG requestTime;\r
+    ULONG receiverChannel;\r
+    \r
+    // If receiverChannel == 1:\r
+    ULONG requestSerialNumber;      // set by RequestResponse, used in ed_cb_find\r
+    VDR_ResponsePacket* save_vresp; // set by ed_cb_call, used in RequestResponse\r
+        \r
+    // If receiverChannel == 2:\r
+    ULONG streamID;\r
+    StreamReceiver* streamReceiver;\r
+};\r
+\r
+class VDR : public Thread_TYPE, public EventDispatcher, public MediaProvider, public ExternLogger\r
+{\r
+\r
+  public:\r
+    const static ULONG VIDEO = 1;\r
+    const static ULONG RADIO = 2;\r
+  \r
+    const static ULONG CHANNEL_REQUEST_RESPONSE = 1;\r
+    const static ULONG CHANNEL_STREAM = 2;\r
+    const static ULONG CHANNEL_KEEPALIVE = 3;\r
+    const static ULONG CHANNEL_NETLOG = 4;\r
+  \r
+    VDR();\r
+    ~VDR();\r
+    static VDR* getInstance();\r
+\r
+    int init(int port);\r
+    int shutdown();\r
+\r
+    void findServers(vector<VDRServer>& servers);\r
+    void cancelFindingServer();\r
+    void setServerIP(char*);\r
+    void setReceiveWindow(size_t size);\r
+    int connect();\r
+    void disconnect();\r
+    bool isConnected() { return connected; }\r
+    ULONG getChannelNumberWidth() { return channelNumberWidth; }\r
+\r
+    // protocol functions\r
+    // for the following, if result == false then the connection has died\r
+    //  doLogin\r
+    //  getRecordingList\r
+    //  getChannelsList\r
+    //  getChannelSchedule\r
+    //  getRecTimersList\r
+    // isConnected can be called after the following to determine if still ok\r
+    //  deleteRecording\r
+    //  streamRecording\r
+    //  positionFromFrameNumber\r
+    //  streamChannel\r
+    //  getBlock\r
+    //  stopStreaming\r
+    //  configLoad\r
+    //  configSave\r
+    //  setEventTimer\r
+\r
+    int           doLogin();\r
+    bool          getRecordingsList(RecMan* recman);\r
+    RecInfo*      getRecInfo(char* fileName);\r
+    int           deleteRecording(char* fileName);\r
+    char*         moveRecording(char* fileName, char* newPath);\r
+    ULLONG        streamRecording(char* fileName, ULONG* lengthFrames, bool* IsPesRecording);\r
+    ULLONG        positionFromFrameNumber(ULONG frameNumber);\r
+    ULONG         frameNumberFromPosition(ULLONG position);\r
+    bool          getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength);\r
+                  // Direction: 0=backwards, 1=forwards\r
+    MarkList*     getMarks(char* fileName);\r
+    int           deleteTimer(RecTimer* delTimer);\r
+    ChannelList*  getChannelsList(ULONG type);\r
+    int           streamChannel(ULONG number, StreamReceiver*);\r
+    int           streamChannel(ULONG number);\r
+    void          getChannelPids(Channel* channel);\r
+    UCHAR*        getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived);\r
+                  //get image blocks separate - we can do this in parallel\r
+    int           stopStreaming();\r
+    EventList*    getChannelSchedule(ULONG number);\r
+    EventList*    getChannelSchedule(ULONG number, time_t start, ULONG duration);\r
+    int           configSave(const char* section, const char* key, const char* value);\r
+    char*         configLoad(const char* section, const char* key);\r
+    ULONG         setEventTimer(char* timerString);\r
+    RecTimerList* getRecTimersList();\r
+    bool          LogExtern(const char* buffer);\r
+    \r
+    bool setCharset(int charset); // 1 latin 2 UTF-8\r
+\r
+    /**\r
+      * the MediaProvider functions\r
+      *\r
+      */\r
+    virtual MediaList* getRootList();\r
+    virtual MediaList* getMediaList(const MediaURI * parent);\r
+    virtual int        openMedium(ULONG channel,const MediaURI *uri,ULLONG * size, ULONG xsize,ULONG ysize);\r
+    virtual int getMediaBlock(ULONG channel, unsigned long long offset, unsigned long len, unsigned long * outlen,\r
+        unsigned char ** buffer);\r
+    virtual int getMediaInfo(ULONG channel, struct MediaInfo * result);\r
+    virtual int closeMediaChannel(ULONG channel);\r
+\r
+\r
+    I18n::lang_code_list getLanguageList();\r
+    int           getLanguageContent(const string code, I18n::trans_table&);\r
+\r
+    // end protocol functions\r
+\r
+\r
+    // obselete\r
+    ULLONG     rescanRecording(ULONG* lengthFrames);                    // FIXME obselete\r
+\r
+\r
+\r
+  private:\r
+    static VDR* instance;\r
+\r
+    VDR_ResponsePacket* RequestResponse(VDR_RequestPacket* request);\r
+    UCHAR* getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived, ULONG cmd);\r
+    \r
+    void connectionDied();\r
+    bool sendKA(ULONG timeStamp);\r
+    \r
+    Log* logger;\r
+    int initted;\r
+    int findingServer;\r
+    TCP* tcp;\r
+    int port;\r
+    char serverIP[16];\r
+    bool connected;\r
+    ULONG maxChannelNumber;\r
+    ULONG channelNumberWidth;\r
+    VDR_PacketReceiver* TEMP_SINGLE_VDR_PR;\r
+\r
+\r
+    ULONG providerId;\r
+    ULONG subRange;\r
+    SerializeBuffer * doRequestResponse(SerializeBuffer *in,int cmd);\r
+  protected:\r
+  \r
+    // Thread\r
+    void threadMethod();\r
+    void threadPostStopCleanup() {};\r
+\r
+    // EventDispatcher\r
+    virtual bool ed_cb_find(EDReceiver* edr, void* userTag);\r
+};\r
+\r
+#endif\r
+\r
+/*\r
+\r
+index.vdr file format for video:\r
+\r
+For every video frame:\r
+{\r
+  File offset    4 bytes\r
+  Picture type   1 byte\r
+  File number    1 byte\r
+  Zero           2 bytes\r
+}\r
+\r
+Picture types:\r
+\r
+#define NO_PICTURE 0\r
+#define I_FRAME    1\r
+#define P_FRAME    2\r
+#define B_FRAME    3\r
+\r
+\r
+\r
+Packet formats\r
+\r
+Packet format for an RR channel request:\r
+\r
+4 bytes = channel ID = 1 (request/response channel)\r
+4 bytes = request ID (from serialNumber)\r
+4 bytes = opcode\r
+4 bytes = length of the rest of the packet\r
+? bytes = rest of packet. depends on packet\r
+\r
+\r
+Packet format for an RR channel response:\r
+\r
+4 bytes = channel ID = 1 (request/response channel)\r
+4 bytes = request ID (from serialNumber)\r
+4 bytes = length of the rest of the packet\r
+? bytes = rest of packet. depends on packet\r
+\r
+\r
+Packet format for a stream packet:\r
+\r
+4 bytes = channel ID = 2 (stream channel)\r
+4 bytes = stream ID (from requestID)\r
+4 bytes = length of the stream data (rest of packet)\r
+? bytes = stream data\r
+\r
+*/\r
+\r
index 9065a5c8ded776fbd0e9315c3dd2917d412704c2..486f00497e637fbf35d99d4cd55f137f34ad969b 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon, Andreas Vogel
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef VDRCOMMAND_H
-#define VDRCOMMAND_H
-
-#include "defines.h"
-#include "serialize.h"
-#include "media.h"
-
-/**
-  * data holder for VDR commands
-  * it's only important to add serializable objects
-  * in the same order on both sides
-  */
-
-//until we really have response - commands we simply take
-//the request+this flag for responses
-//not really necessary but for checks it's better to have a command ID at least in some responses
-const static ULONG VDR_RESPONSE_FLAG =0x1000000;
-
-//as this header is only included by vdr.cc the constants are this way private
-//but can easily be used on the server side as well
-
-const static ULONG VDR_LOGIN               = 1;
-const static ULONG VDR_GETRECORDINGLIST    = 2;
-const static ULONG VDR_DELETERECORDING     = 3;
-const static ULONG VDR_GETCHANNELLIST      = 5;
-const static ULONG VDR_STREAMCHANNEL       = 6;
-const static ULONG VDR_GETBLOCK            = 7;
-const static ULONG VDR_STOPSTREAMING       = 8;
-const static ULONG VDR_STREAMRECORDING     = 9;
-const static ULONG VDR_GETCHANNELSCHEDULE  = 10;
-const static ULONG VDR_CONFIGSAVE          = 11;
-const static ULONG VDR_CONFIGLOAD          = 12;
-const static ULONG VDR_RESCANRECORDING     = 13;  // FIXME obselete
-const static ULONG VDR_GETTIMERS           = 14;
-const static ULONG VDR_SETTIMER            = 15;
-const static ULONG VDR_POSFROMFRAME        = 16;
-const static ULONG VDR_FRAMEFROMPOS        = 17;
-const static ULONG VDR_MOVERECORDING       = 18;
-const static ULONG VDR_GETNEXTIFRAME       = 19;
-const static ULONG VDR_GETRECINFO          = 20;
-const static ULONG VDR_GETMARKS            = 21;
-const static ULONG VDR_GETCHANNELPIDS      = 22;
-const static ULONG VDR_DELETETIMER         = 23;
-const static ULONG VDR_GETLANGUAGELIST     = 33;
-const static ULONG VDR_GETLANGUAGECONTENT  = 34;
-const static ULONG VDR_GETMEDIALIST        = 30;
-const static ULONG VDR_OPENMEDIA           = 31;
-const static ULONG VDR_GETMEDIABLOCK       = 32;
-const static ULONG VDR_GETMEDIAINFO        = 35;
-const static ULONG VDR_CLOSECHANNEL        = 36;
-
-class VDR_Command : public SerializableList {
-  public:
-    VDR_Command(const ULONG cmd) {
-      command=cmd;
-      addParam(&command);
-    }
-    virtual ~VDR_Command(){}
-    ULONG command;
-};
-
-class VDR_GetMediaListRequest : public VDR_Command {
-  public:
-    VDR_GetMediaListRequest(MediaURI *root) :VDR_Command(VDR_GETMEDIALIST) {
-      addParam(root);
-    }
-};
-
-class VDR_GetMediaListResponse : public VDR_Command {
-  public:
-    VDR_GetMediaListResponse(ULONG *flags,MediaList *m) : VDR_Command(VDR_GETMEDIALIST|VDR_RESPONSE_FLAG){
-      addParam(flags);
-      addParam(m);
-    }
-};
-
-class VDR_OpenMediumRequest : public VDR_Command {
-  public:
-    VDR_OpenMediumRequest(ULONG *channel,MediaURI *u,ULONG *xsize, ULONG *ysize) :
-      VDR_Command(VDR_OPENMEDIA) {
-        addParam(channel);
-        addParam(u);
-        addParam(xsize);
-        addParam(ysize);
-      }
-};
-class VDR_OpenMediumResponse : public VDR_Command {
-  public:
-    VDR_OpenMediumResponse(ULONG *flags,ULLONG *size) :
-      VDR_Command(VDR_OPENMEDIA|VDR_RESPONSE_FLAG) {
-        addParam(flags);
-        addParam(size);
-      }
-};
-class VDR_GetMediaBlockRequest : public VDR_Command {
-  public:
-    VDR_GetMediaBlockRequest(ULONG * channel, ULLONG *pos, ULONG *max):
-      VDR_Command(VDR_GETMEDIABLOCK) {
-        addParam(channel);
-        addParam(pos);
-        addParam(max);
-      }
-};
-
-//no response class for GetMediaBlock
-
-
-class VDR_CloseMediaChannelRequest : public VDR_Command {
-  public:
-    VDR_CloseMediaChannelRequest(ULONG * channel):
-      VDR_Command(VDR_CLOSECHANNEL) {
-        addParam(channel);
-      }
-};
-
-class VDR_CloseMediaChannelResponse : public VDR_Command {
-  public:
-    VDR_CloseMediaChannelResponse(ULONG * flags):
-      VDR_Command(VDR_CLOSECHANNEL|VDR_RESPONSE_FLAG) {
-        addParam(flags);
-      }
-};
-
-class VDR_GetMediaInfoRequest : public VDR_Command {
-  public:
-    VDR_GetMediaInfoRequest(ULONG * channel):
-      VDR_Command(VDR_GETMEDIAINFO) {
-        addParam(channel);
-      }
-};
-class VDR_GetMediaInfoResponse : public VDR_Command {
-  public:
-    VDR_GetMediaInfoResponse(ULONG * flags,MediaInfo *info):
-      VDR_Command(VDR_GETMEDIAINFO|VDR_RESPONSE_FLAG) {
-        addParam(flags);
-        addParam(info);
-      }
-};
-
-
-
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon, Andreas Vogel\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef VDRCOMMAND_H\r
+#define VDRCOMMAND_H\r
+\r
+#include "defines.h"\r
+#include "serialize.h"\r
+#include "media.h"\r
+\r
+/**\r
+  * data holder for VDR commands\r
+  * it's only important to add serializable objects\r
+  * in the same order on both sides\r
+  */\r
+\r
+//until we really have response - commands we simply take\r
+//the request+this flag for responses\r
+//not really necessary but for checks it's better to have a command ID at least in some responses\r
+const static ULONG VDR_RESPONSE_FLAG =0x1000000;\r
+\r
+//as this header is only included by vdr.cc the constants are this way private\r
+//but can easily be used on the server side as well\r
+\r
+const static ULONG VDR_LOGIN               = 1;\r
+const static ULONG VDR_GETRECORDINGLIST    = 2;\r
+const static ULONG VDR_DELETERECORDING     = 3;\r
+const static ULONG VDR_GETCHANNELLIST      = 5;\r
+const static ULONG VDR_STREAMCHANNEL       = 6;\r
+const static ULONG VDR_GETBLOCK            = 7;\r
+const static ULONG VDR_STOPSTREAMING       = 8;\r
+const static ULONG VDR_STREAMRECORDING     = 9;\r
+const static ULONG VDR_GETCHANNELSCHEDULE  = 10;\r
+const static ULONG VDR_CONFIGSAVE          = 11;\r
+const static ULONG VDR_CONFIGLOAD          = 12;\r
+const static ULONG VDR_RESCANRECORDING     = 13;  // FIXME obselete\r
+const static ULONG VDR_GETTIMERS           = 14;\r
+const static ULONG VDR_SETTIMER            = 15;\r
+const static ULONG VDR_POSFROMFRAME        = 16;\r
+const static ULONG VDR_FRAMEFROMPOS        = 17;\r
+const static ULONG VDR_MOVERECORDING       = 18;\r
+const static ULONG VDR_GETNEXTIFRAME       = 19;\r
+const static ULONG VDR_GETRECINFO          = 20;\r
+const static ULONG VDR_GETMARKS            = 21;\r
+const static ULONG VDR_GETCHANNELPIDS      = 22;\r
+const static ULONG VDR_DELETETIMER         = 23;\r
+const static ULONG VDR_GETLANGUAGELIST     = 33;\r
+const static ULONG VDR_GETLANGUAGECONTENT  = 34;\r
+const static ULONG VDR_SETCHARSET          = 37;\r
+const static ULONG VDR_GETMEDIALIST        = 30;\r
+const static ULONG VDR_OPENMEDIA           = 31;\r
+const static ULONG VDR_GETMEDIABLOCK       = 32;\r
+const static ULONG VDR_GETMEDIAINFO        = 35;\r
+const static ULONG VDR_CLOSECHANNEL        = 36;\r
+\r
+class VDR_Command : public SerializableList {\r
+  public:\r
+    VDR_Command(const ULONG cmd) {\r
+      command=cmd;\r
+      addParam(&command);\r
+    }\r
+    virtual ~VDR_Command(){}\r
+    ULONG command;\r
+};\r
+\r
+class VDR_GetMediaListRequest : public VDR_Command {\r
+  public:\r
+    VDR_GetMediaListRequest(MediaURI *root) :VDR_Command(VDR_GETMEDIALIST) {\r
+      addParam(root);\r
+    }\r
+};\r
+\r
+class VDR_GetMediaListResponse : public VDR_Command {\r
+  public:\r
+    VDR_GetMediaListResponse(ULONG *flags,MediaList *m) : VDR_Command(VDR_GETMEDIALIST|VDR_RESPONSE_FLAG){\r
+      addParam(flags);\r
+      addParam(m);\r
+    }\r
+};\r
+\r
+class VDR_OpenMediumRequest : public VDR_Command {\r
+  public:\r
+    VDR_OpenMediumRequest(ULONG *channel,MediaURI *u,ULONG *xsize, ULONG *ysize) :\r
+      VDR_Command(VDR_OPENMEDIA) {\r
+        addParam(channel);\r
+        addParam(u);\r
+        addParam(xsize);\r
+        addParam(ysize);\r
+      }\r
+};\r
+class VDR_OpenMediumResponse : public VDR_Command {\r
+  public:\r
+    VDR_OpenMediumResponse(ULONG *flags,ULLONG *size) :\r
+      VDR_Command(VDR_OPENMEDIA|VDR_RESPONSE_FLAG) {\r
+        addParam(flags);\r
+        addParam(size);\r
+      }\r
+};\r
+class VDR_GetMediaBlockRequest : public VDR_Command {\r
+  public:\r
+    VDR_GetMediaBlockRequest(ULONG * channel, ULLONG *pos, ULONG *max):\r
+      VDR_Command(VDR_GETMEDIABLOCK) {\r
+        addParam(channel);\r
+        addParam(pos);\r
+        addParam(max);\r
+      }\r
+};\r
+\r
+//no response class for GetMediaBlock\r
+\r
+\r
+class VDR_CloseMediaChannelRequest : public VDR_Command {\r
+  public:\r
+    VDR_CloseMediaChannelRequest(ULONG * channel):\r
+      VDR_Command(VDR_CLOSECHANNEL) {\r
+        addParam(channel);\r
+      }\r
+};\r
+\r
+class VDR_CloseMediaChannelResponse : public VDR_Command {\r
+  public:\r
+    VDR_CloseMediaChannelResponse(ULONG * flags):\r
+      VDR_Command(VDR_CLOSECHANNEL|VDR_RESPONSE_FLAG) {\r
+        addParam(flags);\r
+      }\r
+};\r
+\r
+class VDR_GetMediaInfoRequest : public VDR_Command {\r
+  public:\r
+    VDR_GetMediaInfoRequest(ULONG * channel):\r
+      VDR_Command(VDR_GETMEDIAINFO) {\r
+        addParam(channel);\r
+      }\r
+};\r
+class VDR_GetMediaInfoResponse : public VDR_Command {\r
+  public:\r
+    VDR_GetMediaInfoResponse(ULONG * flags,MediaInfo *info):\r
+      VDR_Command(VDR_GETMEDIAINFO|VDR_RESPONSE_FLAG) {\r
+        addParam(flags);\r
+        addParam(info);\r
+      }\r
+};\r
+\r
+\r
+\r
+\r
+#endif\r
index bdf5f19d540fc4cc2f5ce73b5ad7bb4f7d6b9ee2..5b98ada64f450754ec6cdb4ec73e8f281ccaed31 100644 (file)
@@ -70,10 +70,27 @@ bool VDR_RequestPacket::init(ULONG topcode, bool setUserDataLength, ULONG userDa
   serialNumber = serialNumberCounter++;
   opcode = topcode;
   
-  *(ULONG*)&buffer[0] = htonl(channel);
-  *(ULONG*)&buffer[4] = htonl(serialNumber);
+  int pos=0;
+  buffer[pos++]=(channel>>24)&0xff;
+  buffer[pos++]=(channel>>16)&0xff;
+  buffer[pos++]=(channel>>8)&0xff;
+  buffer[pos++]=channel &0xff;
+  buffer[pos++]=(serialNumber>>24)&0xff;
+  buffer[pos++]=(serialNumber>>16)&0xff;
+  buffer[pos++]=(serialNumber>>8)&0xff;
+  buffer[pos++]=serialNumber &0xff;
+  buffer[pos++]=(opcode>>24)&0xff;
+  buffer[pos++]=(opcode>>16)&0xff;
+  buffer[pos++]=(opcode>>8)&0xff;
+  buffer[pos++]=opcode &0xff;
+  buffer[pos++]=(userDataLength>>24)&0xff;
+  buffer[pos++]=(userDataLength>>16)&0xff;
+  buffer[pos++]=(userDataLength>>8)&0xff;
+  buffer[pos++]=userDataLength &0xff;
+
+  /**(ULONG*)&buffer[4] = htonl(serialNumber);
   *(ULONG*)&buffer[8] = htonl(opcode);
-  *(ULONG*)&buffer[userDataLenPos] = htonl(userDataLength);
+  *(ULONG*)&buffer[userDataLenPos] = htonl(userDataLength);*/
   bufUsed = headerLength;
 
   return true;
@@ -84,35 +101,77 @@ bool VDR_RequestPacket::copyin(const UCHAR* src, ULONG len)
   if (!checkExtend(len)) return false;
   memcpy(buffer + bufUsed, src, len);
   bufUsed += len;
-  if (!lengthSet) *(ULONG*)&buffer[userDataLenPos] = htonl(bufUsed - headerLength);
+  if (!lengthSet) {
+         int pos=userDataLenPos;
+         ULONG tocopy=bufUsed - headerLength;
+         buffer[pos++]=(tocopy>>24)&0xff;
+         buffer[pos++]=(tocopy>>16)&0xff;
+         buffer[pos++]=(tocopy>>8)&0xff;
+         buffer[pos++]=tocopy &0xff;
+  }
   return true;
 }
 
+
+
 bool VDR_RequestPacket::addString(const char* string)
 {
   ULONG len = strlen(string) + 1;
   if (!checkExtend(len)) return false;
   memcpy(buffer + bufUsed, string, len);
   bufUsed += len;
-  if (!lengthSet) *(ULONG*)&buffer[userDataLenPos] = htonl(bufUsed - headerLength);
+  if (!lengthSet) {
+         int pos=userDataLenPos;
+         ULONG tocopy=bufUsed - headerLength;
+         buffer[pos++]=(tocopy>>24)&0xff;
+         buffer[pos++]=(tocopy>>16)&0xff;
+         buffer[pos++]=(tocopy>>8)&0xff;
+         buffer[pos++]=tocopy &0xff;
+  }
   return true;
 }
 
 bool VDR_RequestPacket::addULONG(ULONG ul)
 {
   if (!checkExtend(sizeof(ULONG))) return false;
-  *(ULONG*)&buffer[bufUsed] = htonl(ul);
-  bufUsed += sizeof(ULONG);
-  if (!lengthSet) *(ULONG*)&buffer[userDataLenPos] = htonl(bufUsed - headerLength);
+//  *(ULONG*)&buffer[bufUsed] = htonl(ul);
+
+  buffer[bufUsed++]=(ul>>24)&0xff;
+  buffer[bufUsed++]=(ul>>16)&0xff;
+  buffer[bufUsed++]=(ul>>8)&0xff;
+  buffer[bufUsed++]=ul &0xff;
+
+  if (!lengthSet) {
+         int pos=userDataLenPos;
+         ULONG tocopy=bufUsed - headerLength;
+         buffer[pos++]=(tocopy>>24)&0xff;
+         buffer[pos++]=(tocopy>>16)&0xff;
+         buffer[pos++]=(tocopy>>8)&0xff;
+         buffer[pos++]=tocopy &0xff;
+  }
   return true;
 }   
 
 bool VDR_RequestPacket::addULLONG(ULLONG ull)
 {
   if (!checkExtend(sizeof(ULLONG))) return false;
-  *(ULLONG*)&buffer[bufUsed] = htonll(ull);
-  bufUsed += sizeof(ULLONG);
-  if (!lengthSet) *(ULONG*)&buffer[userDataLenPos] = htonl(bufUsed - headerLength);
+  buffer[bufUsed++]=(ull>>56)&0xff;
+  buffer[bufUsed++]=(ull>>48)&0xff;
+  buffer[bufUsed++]=(ull>>40)&0xff;
+  buffer[bufUsed++]=(ull>>32)&0xff;
+  buffer[bufUsed++]=(ull>>24)&0xff;
+  buffer[bufUsed++]=(ull>>16)&0xff;
+  buffer[bufUsed++]=(ull>>8)&0xff;
+  buffer[bufUsed++]=ull &0xff;
+
+  if (!lengthSet) {
+         int pos=userDataLenPos;
+         ULONG tocopy=bufUsed - headerLength;
+         buffer[pos++]=(tocopy>>24)&0xff;
+         buffer[pos++]=(tocopy>>16)&0xff;
+         buffer[pos++]=(tocopy>>8)&0xff;
+         buffer[pos++]=tocopy &0xff;
+  }
   return true;
 }
 
index 7d156c0f8d186d88a4a873d5b7dc5c855e3c77ab..8a14fd2a491f069cef755a63e1da571952824394 100644 (file)
-/*
-    Copyright 2007 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vdrresponsepacket.h"
-
-#include "vdr.h"
-#include "tcp.h"
-
-VDR_ResponsePacket::VDR_ResponsePacket()
-{
-  userDataLength = 0;
-  packetPos = 0;
-  userData = NULL;
-  ownBlock = true;
-  
-  channelID = 0;
-  
-  requestID = 0;
-  streamID = 0;
-  
-  flag = 0;
-}
-
-VDR_ResponsePacket::~VDR_ResponsePacket()
-{
-  if (!ownBlock) return; // don't free if it's a getblock
-  
-  if (userData) free(userData);
-}
-
-void VDR_ResponsePacket::setResponse(ULONG trequestID, UCHAR* tuserData, ULONG tuserDataLength)
-{
-  channelID = VDR::CHANNEL_REQUEST_RESPONSE;
-  requestID = trequestID;
-  userData = tuserData;
-  userDataLength = tuserDataLength;
-}
-
-void VDR_ResponsePacket::setStream(ULONG tstreamID, ULONG tflag, UCHAR* tuserData, ULONG tuserDataLength)
-{
-  channelID = VDR::CHANNEL_STREAM;
-  streamID = tstreamID;
-  flag = tflag;
-  userData = tuserData;
-  userDataLength = tuserDataLength;
-}
-
-bool VDR_ResponsePacket::end()
-{
-  return (packetPos >= userDataLength);
-}
-
-void VDR_ResponsePacket::dumpUD()
-{
-  TCP::dump(userData, userDataLength);
-}
-
-int VDR_ResponsePacket::serverError()
-{
-  if ((packetPos == 0) && (userDataLength == 4) && !ntohl(*(ULONG*)userData)) return 1;
-  else return 0;
-}
-
-char* VDR_ResponsePacket::extractString()
-{
-  if (serverError()) return NULL;
-
-  int length = strlen((char*)&userData[packetPos]);
-  if ((packetPos + length) > userDataLength) return NULL;
-  char* str = new char[length + 1];
-  strcpy(str, (char*)&userData[packetPos]);
-  packetPos += length + 1;
-  return str;
-}
-
-UCHAR VDR_ResponsePacket::extractUCHAR()
-{
-  if ((packetPos + sizeof(UCHAR)) > userDataLength) return 0;
-  UCHAR uc = userData[packetPos];
-  packetPos += sizeof(UCHAR);
-  return uc;
-}
-
-ULONG VDR_ResponsePacket::extractULONG()
-{
-  if ((packetPos + sizeof(ULONG)) > userDataLength) return 0;
-  ULONG ul = ntohl(*(ULONG*)&userData[packetPos]);
-  packetPos += sizeof(ULONG);
-  return ul;
-}
-
-ULLONG VDR_ResponsePacket::extractULLONG()
-{
-  if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0;
-  ULLONG ull = ntohll(*(ULLONG*)&userData[packetPos]);
-  packetPos += sizeof(ULLONG);
-  return ull;
-}
-
-double VDR_ResponsePacket::extractdouble()
-{
-  if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0;
-  ULLONG ull = ntohll(*(ULLONG*)&userData[packetPos]);
-  double d;
-  memcpy(&d,&ull,sizeof(double));
-  packetPos += sizeof(ULLONG);
-  return d;
-}
-
-long VDR_ResponsePacket::extractLONG()
-{
-  if ((packetPos + sizeof(long)) > userDataLength) return 0;
-  long l = ntohl(*(long*)&userData[packetPos]);
-  packetPos += sizeof(long);
-  return l;
-}
-
-UCHAR* VDR_ResponsePacket::getUserData()
-{
-  ownBlock = false;
-  return userData;
-}
-
+/*\r
+    Copyright 2007 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vdrresponsepacket.h"\r
+\r
+#include "vdr.h"\r
+#include "tcp.h"\r
+\r
+VDR_ResponsePacket::VDR_ResponsePacket()\r
+{\r
+  userDataLength = 0;\r
+  packetPos = 0;\r
+  userData = NULL;\r
+  ownBlock = true;\r
+  \r
+  channelID = 0;\r
+  \r
+  requestID = 0;\r
+  streamID = 0;\r
+  \r
+  flag = 0;\r
+}\r
+\r
+VDR_ResponsePacket::~VDR_ResponsePacket()\r
+{\r
+  if (!ownBlock) return; // don't free if it's a getblock\r
+  \r
+  if (userData) free(userData);\r
+}\r
+\r
+void VDR_ResponsePacket::setResponse(ULONG trequestID, UCHAR* tuserData, ULONG tuserDataLength)\r
+{\r
+  channelID = VDR::CHANNEL_REQUEST_RESPONSE;\r
+  requestID = trequestID;\r
+  userData = tuserData;\r
+  userDataLength = tuserDataLength;\r
+}\r
+\r
+void VDR_ResponsePacket::setStream(ULONG tstreamID, ULONG tflag, UCHAR* tuserData, ULONG tuserDataLength)\r
+{\r
+  channelID = VDR::CHANNEL_STREAM;\r
+  streamID = tstreamID;\r
+  flag = tflag;\r
+  userData = tuserData;\r
+  userDataLength = tuserDataLength;\r
+}\r
+\r
+bool VDR_ResponsePacket::end()\r
+{\r
+  return (packetPos >= userDataLength);\r
+}\r
+\r
+void VDR_ResponsePacket::dumpUD()\r
+{\r
+  TCP::dump(userData, userDataLength);\r
+}\r
+\r
+int VDR_ResponsePacket::serverError()\r
+{\r
+  if ((packetPos == 0) && (userDataLength == 4) && !ntohl(*(ULONG*)userData)) return 1;\r
+  else return 0;\r
+}\r
+\r
+char* VDR_ResponsePacket::extractString()\r
+{\r
+  if (serverError()) return NULL;\r
+\r
+  int length = strlen((char*)&userData[packetPos]);\r
+  if ((packetPos + length) > userDataLength) return NULL;\r
+  char* str = new char[length + 1];\r
+  strcpy(str, (char*)&userData[packetPos]);\r
+  packetPos += length + 1;\r
+  return str;\r
+}\r
+\r
+UCHAR VDR_ResponsePacket::extractUCHAR()\r
+{\r
+  if ((packetPos + sizeof(UCHAR)) > userDataLength) return 0;\r
+  UCHAR uc = userData[packetPos];\r
+  packetPos += sizeof(UCHAR);\r
+  return uc;\r
+}\r
+\r
+ULONG VDR_ResponsePacket::extractULONG()\r
+{\r
+  if ((packetPos + sizeof(ULONG)) > userDataLength) return 0;\r
+  ULONG ul = userData[packetPos++]<<24;\r
+  ul|= userData[packetPos++]<<16;\r
+  ul|= userData[packetPos++]<<8;\r
+  ul|= userData[packetPos++];\r
+  //packetPos += sizeof(ULONG);\r
+  return ul;\r
+}\r
+\r
+ULLONG VDR_ResponsePacket::extractULLONG()\r
+{\r
+  if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0;\r
+  ULLONG ull= ((ULLONG)userData[packetPos++])<<56;\r
+  ull|= ((ULLONG)userData[packetPos++])<<48;\r
+  ull|= ((ULLONG)userData[packetPos++])<<40;\r
+  ull|= ((ULLONG)userData[packetPos++])<<32;\r
+  ull|= ((ULLONG)userData[packetPos++])<<24;\r
+  ull|= ((ULLONG)userData[packetPos++])<<16;\r
+  ull|= ((ULLONG)userData[packetPos++])<<8;\r
+  ull|= ((ULLONG)userData[packetPos++]);\r
+  return ull;\r
+}\r
+\r
+double VDR_ResponsePacket::extractdouble()\r
+{\r
+  if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0;\r
+  ULLONG ull = extractULLONG();\r
+  double d;\r
+  memcpy(&d,&ull,sizeof(double));\r
+  return d;\r
+}\r
+\r
+long VDR_ResponsePacket::extractLONG()\r
+{\r
+  if ((packetPos + sizeof(long)) > userDataLength) return 0;\r
+  long l = userData[packetPos++]<<24;\r
+  l|= userData[packetPos++]<<16;\r
+  l|= userData[packetPos++]<<8;\r
+  l|= userData[packetPos++];\r
+  return l;\r
+}\r
+\r
+UCHAR* VDR_ResponsePacket::getUserData()\r
+{\r
+  ownBlock = false;\r
+  return userData;\r
+}\r
+\r
diff --git a/vepg.cc b/vepg.cc
index d90a53b2286444e3fe74b307c22ff69d055770db..5505eb815b1d2afbdcd13a7163b846019d5f08ce 100644 (file)
--- a/vepg.cc
+++ b/vepg.cc
-/*
-    Copyright 2005 Brian Walton
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-/*
-    vepg presents a 2 dimensional electronic programme guide with channels down
-    the y axis and time along the x axis.
-    Programmes are layed on the x axis as alterate coloured blocks with as much
-    of the programme title as will fit inside the block shown as text.
-    Up and down commands step through the channels whilst left and right commands
-    move through the programmes of the currently selected channel.
-    When a programme is selected, it highlights in the grid and full programe details
-    (start time, title and description) are displayed in an area at te top left of the screen.
-    Any currently programmed timers will display in the grid and in the orogramme detail window as red
-    It is possible to select a programme to be recorded by pressing the record button.
-    The video stream currently being viewed is shown as quarter screen in the top right.
-*/
-
-#include "vepg.h"
-
-#include "remote.h"
-#include "vchannellist.h"
-#include "command.h"
-#include "video.h"
-#include "vepgsettimer.h"
-#include "timers.h"
-#include "wsymbol.h"
-#include "message.h"
-#include "colour.h"
-#include "boxstack.h"
-#include "channel.h"
-#include "i18n.h"
-#include "log.h"
-
-VEpg* VEpg::instance = NULL;
-
-VEpg::VEpg(void* tparent, UINT tcurrentChannelIndex, ULONG streamType)
-{
-  instance = this;
-  currentChannelIndex = tcurrentChannelIndex;
-
-  // PAL / NTSC sizes -----------------------
-
-  int xsize, ysize;
-  int xpos, ypos;
-  int summaryLines, summaryLowerPadding;
-  int chanNameYpos;
-  //UINT gridRows; // is a class member
-
-  if (Video::getInstance()->getFormat() == Video::PAL)
-  {
-    xsize = 632;
-    ysize = 541;
-    xpos = 60;
-    ypos = 16;
-    summaryLines = 8;
-    summaryLowerPadding = 18;
-    chanNameYpos = 244;
-    gridRows = 7;
-  }
-  else
-  {
-    xsize = 632;
-    ysize = 452;
-    xpos = 50;
-    ypos = 10;
-    summaryLines = 6;
-    summaryLowerPadding = 28;
-    chanNameYpos = 206;
-    gridRows = 5;
-  }
-
-  // initialise variables and pointers
-  boxstack = BoxStack::getInstance();
-  parent = tparent;
-  eventList = NULL;
-  chanList = VDR::getInstance()->getChannelsList(streamType); //TODO want to be able to display video and radio together
-  e = 0;
-
-  for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
-  {
-    // initialise array of pointers to eventlist structures
-    eventLista[listIndex] = NULL;
-  }
-
-  // Create pallet on which to paint our epg view and position it in centre of screen.
-  // Need to reduce size to deal with overscanning TVs.
-
-  setSize(xsize, ysize);
-  createBuffer();
-  setPosition(xpos, ypos);
-
-  // beautify
-//  Colour transparent = Colour(0, 0, 0, 0);
-//  setBackgroundColour(transparent);
-
-//  progTitle.setSurface(surface);
-  progTitle.setPosition(0,0);
-  progTitle.setSize(300,(Surface::getFontHeight() + 4) * 2 + 16); //paragraph line seperation is 4 pixels
-  progTitle.setBackgroundColour(Colour::TITLEBARBACKGROUND);
-  progTitle.setTextPos(5, 16);
-  progTitle.setGap(4);
-  add(&progTitle);
-
-//  progInfo.setSurface(surface);
-  progInfo.setBackgroundColour(Colour::VIEWBACKGROUND);
-  progInfo.setPosition(0, progTitle.getY2());
-  progInfo.setSize(300,((Surface::getFontHeight() + 4) * summaryLines) + summaryLowerPadding);
-  progInfo.setGap(4);
-  add(&progInfo);
-
-//  chanName.setSurface(surface);
-  chanName.setSize(510, (Surface::getFontHeight() + 4));
-  chanName.setPosition(305, chanNameYpos);
-    Colour t1(0, 0, 0, 90);
-  chanName.setBackgroundColour(t1);
-  add(&chanName);
-
-  // create area to display list of channels
-//  chanListbox.setSurface(surface); // add channel list
-  chanListbox.setPosition(0, progInfo.getY2() + Surface::getFontHeight() + 8); // position channel list
-  chanListbox.setSize(150, ((Surface::getFontHeight() + 2) * gridRows) + 5); //listbox line seperation is 2 pixels
-  chanListbox.setGap(2);
-  add(&chanListbox);
-
-  // populate channel list
-  if (chanList)
-  {
-    Channel* chan;
-    int first = 1;
-    for (UINT i = 0; i < chanList->size(); i++)
-    {
-      chan = (*chanList)[i];
-      if (i == currentChannelIndex)
-        first = 1;
-      chan->index = chanListbox.addOption(chan->name, 0, first);
-      first = 0;
-    }
-    chanName.setText((*chanList)[chanListbox.getCurrentOption()]->name);
-  }
-
-  listTop = chanListbox.getTopOption();
-  chanListbox.draw(); // doing this to allow chanListbox.getBottomOption() in updateEventList() to work
-  time(&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
-  Colour transparent = Colour(0, 0, 0, 0);
-  fillColour(transparent);
-  
-  
-  // Moved all the dynamic data drawing to a seperate function
-
-  // Display the status and key stuff at the bottom
-
-  UINT keyx = chanListbox.getRootBoxOffsetX();
-  UINT keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;
-  Colour ref1 = Colour(100, 100, 100, 255);
-  rectangle(keyx, keyy, 605, Surface::getFontHeight() * 2 + 14, ref1);
-
-  WSymbol w;
-  TEMPADD(&w);
-  
-  w.nextSymbol = WSymbol::LEFTARROW;
-  w.setPosition(keyx + 1, keyy + 20);
-  w.draw();
-
-  w.nextSymbol = WSymbol::UP;
-  w.setPosition(keyx + 26, keyy + 3);
-  w.draw();
-
-  w.nextSymbol = WSymbol::DOWN;
-  w.setPosition(keyx + 26, keyy + 36);
-  w.draw();
-
-  w.nextSymbol = WSymbol::RIGHTARROW;
-  w.setPosition(keyx + 50, keyy + 20);
-  w.draw();
-
-  drawText(tr("OK"), keyx + 18, keyy + 20, Colour::LIGHTTEXT);
-
-  Colour ref2 = Colour(200, 0, 0, 255);
-  rectangle(keyx + 72, keyy + 4, 104, Surface::getFontHeight() + 2, ref2);
-  drawText(tr("Page up"), keyx + 74, keyy + 5, Colour::LIGHTTEXT);
-
-  Colour ref3 = Colour(0, 200, 0, 255);
-  rectangle(keyx + 72, keyy + Surface::getFontHeight() + 8, 104, Surface::getFontHeight() + 2, ref3);
-  drawText(tr("Page down"), keyx + 74, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);
-
-  Colour ref4 = Colour(200, 200, 0, 255);
-  rectangle(keyx + 180, keyy + 4, 104, Surface::getFontHeight() + 2, ref4);
-  drawText(tr("-24 hours"), keyx + 182, keyy + 5, Colour::LIGHTTEXT);
-
-  Colour ref5 = Colour(0, 0, 200, 255);
-  rectangle(keyx + 180, keyy + Surface::getFontHeight() + 8, 104, Surface::getFontHeight() + 2, ref5);
-  drawText(tr("+24 hours"), keyx + 182, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);
-
-  Colour ref6 = Colour(180, 180, 180, 255);
-  rectangle(keyx + 290, keyy + 4, 180, Surface::getFontHeight() + 2, ref6);
-  drawText(tr("Guide / Back: Close"), keyx + 292 , keyy + 5, Colour::LIGHTTEXT);
-
-  Colour ref7 = Colour(180, 180, 180, 255);
-  rectangle(keyx + 290, keyy + Surface::getFontHeight() + 8, 180, Surface::getFontHeight() + 2, ref7);
-  Colour red = Colour(130, 0, 0);
-  drawText(tr("Rec: Set timer"), keyx + 292, keyy + Surface::getFontHeight() + 9, red);
-
-  Colour ref8 = Colour(180, 180, 180, 255);
-  rectangle(keyx + 474, keyy + 4, 128, Surface::getFontHeight() + 2, ref8);
-  w.nextSymbol = WSymbol::PLAY;
-  w.setPosition(keyx + 476, keyy + 5);
-  w.draw();
-  drawText(tr("Sel channel"), keyx + 496, keyy + 5, Colour::LIGHTTEXT);
-
-  Colour ref9 = Colour(180, 180, 180, 255);
-  rectangle(keyx + 474, keyy + Surface::getFontHeight() + 8, 128, Surface::getFontHeight() + 2, ref9);
-  drawText(tr("Go: Preview"), keyx + 476, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);
-
-
-  // Draw all the dynamic data
-  drawData();
-}
-
-void VEpg::drawData()
-{
-  // Not doing View::draw() every time causes
-  // things not to be cleared off the surface properly
-  // So, blank out the data area first
-
-  rectangle(
-    chanListbox.getRootBoxOffsetX(),
-    chanListbox.getRootBoxOffsetY() - Surface::getFontHeight() - 3,
-    155 + WINDOW_WIDTH * MINUTE_SCALE,
-    chanListbox.getHeight() + Surface::getFontHeight() + 4,
-    Colour::BLACK);
-
-  chanListbox.draw();
-  drawgrid();
-  chanName.draw(); // TODO this should be dealt with by vvideolive
-
-  progTitle.draw();
-  progInfo.draw();
-
-  // Set timer to redraw to move the current time bar
-  time_t t, dt;
-  time(&t);
-  dt = 60 - (t % 60);
-  if (dt == 0) dt = 60;
-  dt += t;
-  Timers::getInstance()->setTimerT(this, 1, dt);
-}
-
-void VEpg::timercall(int clientReference)
-{
-  drawData();
-  boxstack->update(this);
-}
-
-int VEpg::handleCommand(int command)
-{
-  switch(command)
-  {
-    case Remote::DF_UP:
-    case Remote::UP:
-    { // cursor up the channel list
-      chanListbox.up();
-      drawData();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::DF_DOWN:
-    case Remote::DOWN:
-    { // cursor down the channel list
-      Log::getInstance()->log("VEPG", Log::DEBUG, "Down start");
-      
-      chanListbox.down();
-      drawData();
-      boxstack->update(this);
-      Log::getInstance()->log("VEPG", Log::DEBUG, "Down end");
-
-      return 2;
-    }
-    case Remote::DF_LEFT:
-    case Remote::LEFT:
-    { // cursor left through time
-      selTime = thisEvent.time - 1;
-      drawData();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::DF_RIGHT:
-    case Remote::RIGHT:
-    {
-    // cursor right through time
-      selTime = thisEvent.time + thisEvent.duration;
-      drawData();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::RED:
-    {
-    // cursor up one page
-      chanListbox.pageUp();
-      drawData();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::GREEN:
-    {
-    // cursor down one page
-      chanListbox.pageDown();
-      drawData();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::BLUE:
-    {
-    // step forward 24 hours
-      selTime += 24 * 60 * 60;
-      drawData();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::YELLOW:
-    {
-    // step forward 24 hours
-      selTime -= 24 * 60 * 60;
-      drawData();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::RECORD:
-    {
-      if (!chanList) return 2;
-      Log::getInstance()->log("VEPG", Log::DEBUG, "ID %lu TIME %lu DURATION %lu TITLE %s", thisEvent.id, thisEvent.time, thisEvent.duration, thisEvent.title);
-      VEpgSetTimer* vs = new VEpgSetTimer(&thisEvent, (*chanList)[chanListbox.getCurrentOption()]);
-      vs->draw();
-      boxstack->add(vs);
-      boxstack->update(vs);
-      return 2;
-    }
-    case Remote::PLAY:
-    case Remote::GO:
-    case Remote::OK:
-    {
-      if (!chanList) return 2;
-
-      // select programme and display menu TODO currently just changes to selected channel
-
-      currentChannelIndex = chanListbox.getCurrentOption();
-
-      if (parent)
-      {
-        Message* m = new Message(); // Must be done after this view deleted
-        m->from = this;
-        m->to = parent;
-        m->message = Message::CHANNEL_CHANGE;
-        m->parameter = (*chanList)[currentChannelIndex]->number;
-        Command::getInstance()->postMessageNoLock(m);
-      }
-      
-      setCurrentChannel();
-
-      if(command == Remote::GO)
-        return 2;
-      // GO just changes channel in preview, PLAY changes channel and returns to normal TV
-    }
-    case Remote::BACK:
-    case Remote::GUIDE:
-    {
-      // return to normal TV mode
-      if (parent) // ptr check done in case being tested from videorec
-      {
-        Message* m = new Message(); // Must be done after this view deleted
-        m->from = this;
-        m->to = parent;
-        m->message = Message::EPG_CLOSE;
-        Command::getInstance()->postMessageNoLock(m);
-      }
-      return 4;
-    }
-    case Remote::CHANNELUP:
-    {
-      if (currentChannelIndex == (chanList->size() - 1)) // at the end
-        currentChannelIndex = 0;
-      else
-        ++currentChannelIndex;
-      
-      if (parent)
-      {
-        Message* m = new Message(); // Must be done after this view deleted
-        m->from = this;
-        m->to = parent;
-        m->message = Message::CHANNEL_CHANGE;
-        m->parameter = (*chanList)[currentChannelIndex]->number;
-        Command::getInstance()->postMessageNoLock(m);
-      }
-      
-      setCurrentChannel();
-
-      return 2;
-    }
-    case Remote::CHANNELDOWN:
-    {
-      if (currentChannelIndex == 0) // at the start
-        currentChannelIndex = chanList->size() - 1; // so go to end
-      else
-        --currentChannelIndex;
-
-      if (parent)
-      {
-        Message* m = new Message(); // Must be done after this view deleted
-        m->from = this;
-        m->to = parent;
-        m->message = Message::CHANNEL_CHANGE;
-        m->parameter = (*chanList)[currentChannelIndex]->number;
-        Command::getInstance()->postMessageNoLock(m);
-      }
-      
-      setCurrentChannel();
-
-      return 2;
-    }
-  }
-  // stop command getting to any more views
-  return 1;
-}
-
-void VEpg::drawgrid() // redraws grid and select programme
-{
-  // draw the grid of programmes
-  char timeString[20];
-  time_t t;
-  time(&t); // set t = now
-  if(selTime < t)
-    selTime = t; // don't allow cursor in the past
-  if(listTop != chanListbox.getTopOption())
-  {
-  // chanListbox has scrolled TODO speed up by changing only rows that have changed
-    listTop = chanListbox.getTopOption();
-    updateEventList();
-  }
-  if ((selTime >= ltime + WINDOW_WIDTH * 60) || (selTime <= ltime))
-  {
-  // we have cursored back before left time of window
-  //TODO check that this and above don't happen together
-    ltime = prevHour(&selTime);
-    updateEventList();
-  }
-  // draw time scale
-  Colour white = Colour(255, 255, 255, 255);
-  
-  t = ltime;
-  struct tm* tms;
-  tms = localtime(&t);
-  strftime(timeString, 19, "%a %d %b", tms);
-  int timey = chanListbox.getRootBoxOffsetY() - Surface::getFontHeight() - 3;
-  int timex = 135;
-  drawTextRJ(timeString, timex - 10, timey, Colour::LIGHTTEXT); // print date
-  strftime(timeString, 19, "%H:%M", tms);
-  drawText(timeString, timex, timey, Colour::LIGHTTEXT); // print left time
-  rectangle(155, timey + Surface::getFontHeight(), 2, 7, white);
-  t = t + 3600;
-  tms = localtime(&t);
-  strftime(timeString, 19, "%H:%M", tms);
-  drawText(timeString, timex + 180, timey, Colour::LIGHTTEXT); // print middle time
-  rectangle(335, timey + Surface::getFontHeight(), 2, 7, white);
-  t = t + 3600;
-  tms = localtime(&t);
-  strftime(timeString, 19, "%H:%M", tms);
-  drawText(timeString, timex + 360, timey, Colour::LIGHTTEXT); // print right time
-  rectangle(515, timey + Surface::getFontHeight(), 2, 7, white);
-  // pointer to selTime
-  //rectangle(155 + (selTime - ltime) / 20, timey + Surface::getFontHeight(), 2, 7, Colour(255, 50, 50, 255));
-
-  // current time line
-  time(&t);
-  if ((t >= ltime) && (t < (ltime + 9000)))
-  {
-    rectangle(155 + (t - ltime) / 20, timey + Surface::getFontHeight(), 2, ((Surface::getFontHeight() + 2) * 7) + 7 + 2, Colour::RED);
-  }
-
-  // TODO should the above two comditional statements be combined to avoid calling updateEventList() twice?
-  Event* event;
-  Event noevent; // an event to use if there are gaps in the epg
-  thisEvent.setdescription(tr("There are no programme details available for this period"));
-  thisEvent.duration = WINDOW_WIDTH * 60;
-  thisEvent.time = ltime;
-  thisEvent.settitle(tr("No programme details"));
-  thisEvent.id = 0;
-  bool swapColour = FALSE; // alternate cell colour
-  bool currentRow = FALSE;
-  int y = chanListbox.getRootBoxOffsetY() + 5; // vertical position of cell
-  Colour bg, fg; // background colour of cells in grid
-  // for each displayed channel, find programmes that fall in 2.5 hour time window
-  for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
-  {
-    if (listTop + (int)listIndex >= chanListbox.getBottomOption())
-      continue; // ensure nothing populates grid below last channel
-    currentRow = (listTop + (int)listIndex == chanListbox.getCurrentOption());
-    noevent.time = ltime;
-    noevent.duration = WINDOW_WIDTH * 60;
-    noevent.settitle("");
-    paintCell(&noevent, y, Colour::NOPROGRAMME, Colour::LIGHTTEXT); // fill row with no programme colour to be painted ove with valid programmes
-    if (currentRow)
-    {
-      thisEvent.setdescription(tr("There are no programme details available for this period"));
-      thisEvent.duration = WINDOW_WIDTH * 60;
-      thisEvent.time = ltime;
-      thisEvent.settitle(tr("No programme details"));
-      thisEvent.id = 0;
-    }
-    if (eventLista[listIndex])
-    {
-      sort(eventLista[listIndex]->begin(), eventLista[listIndex]->end(), EventSorter());
-      for(e = 0; e < (eventLista[listIndex])->size(); e++) // step through events for this channel
-      {
-        fg = Colour::LIGHTTEXT;
-        event = (*eventLista[listIndex])[e];
-        if (event)
-        {
-          UINT end = event->time + event->duration; // programme end time
-          if(event->time >= UINT(ltime) + (WINDOW_WIDTH * 60)) // programme starts after RHS of window
-            continue; // that's enough of this channel's events
-          if(end <= UINT(ltime)) // programme ends before LHS of window
-            continue; // this event is before the window - let's try the next event
-          // this event is one we are interested in
-          bg = (swapColour)?Colour::PROGRAMMEA:Colour::PROGRAMMEB; // alternate cell colour
-          swapColour = !swapColour; // it wil be the other colour next time
-          if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow)
-          {
-            // this is the selected programme
-            thisEvent.setdescription(event->description);
-            thisEvent.duration = event->duration;
-            thisEvent.time = event->time;
-            thisEvent.settitle(event->title);
-            thisEvent.id = event->id;
-            if(thisEvent.id == 0)
-              thisEvent.id = 1;
-            bg = Colour::SELECTHIGHLIGHT; // highlight cell
-            fg = Colour::DARKTEXT;
-          }
-          else
-          {
-            if (currentRow && thisEvent.id == 0)
-            {
-              if (end <= UINT(selTime) && end > UINT(thisEvent.time))
-                thisEvent.time = end;
-              if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration)
-                thisEvent.duration = event->time - thisEvent.time;
-            }
-          }
-          paintCell(event, y, bg, fg);
-        }
-      }
-    }
-    else
-    {
-      // no event list for this channel. Already painted noevent colour so just highlight if selected
-      if (currentRow)
-      {
-        bg = Colour::SELECTHIGHLIGHT; // highlight cell
-        fg = Colour::DARKTEXT;
-        paintCell(&thisEvent, y, bg, fg);
-      }
-      else
-      {
-        bg = Colour::NOPROGRAMME;
-        fg = Colour::LIGHTTEXT;
-        noevent.settitle(tr("No programme details"));
-        paintCell(&noevent, y, bg, fg);
-      }
-    }
-    y += Surface::getFontHeight() + 2;
-  }
-  setInfo(&thisEvent);
-}
-
-void VEpg::updateEventList()
-{
-  if (!chanList) return;
-  Channel* chan;
-  for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
-  {
-    if(listTop + listIndex >= UINT(chanListbox.getBottomOption()))
-      continue;
-    chan = (*chanList)[listTop + listIndex];
-
-    eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, ltime - 1, WINDOW_WIDTH * 60 + 2); // ltime - 1 to get prog before window (allows cursor left past ltime). + 2 to get prog after window
-  }
-}
-
-void VEpg::setCurrentChannel()
-{
-  chanName.setText((*chanList)[currentChannelIndex]->name);
-  chanName.draw();
-  Region r;
-  chanName.getRootBoxRegion(&r);
-  boxstack->update(this, &r);
-}
-
-void VEpg::paintCell(Event* event, int yOffset, const Colour& bg, const Colour& fg)
-{
-  int w, x, y, h;
-  w = x = 0; // keep compiler happy
-
-  y =yOffset;
-  h = Surface::getFontHeight(); // TODO if want border around text, need to increae this and wselectlist line height
-  UINT end = event->time + event->duration; // programme end time
-  if(event->time <= UINT(ltime) && end > UINT(ltime)) // spans start of displayed window
-  {
-    x = 155; // LHS of window
-    if (end > (UINT(ltime) + (WINDOW_WIDTH * 60)))
-      w = WINDOW_WIDTH * MINUTE_SCALE; // spans full 2 hour window
-    else
-      w = MINUTE_SCALE * (event->time + event->duration - ltime ) / 60; // get width of remaining programme
-  }
-  if((event->time >= UINT(ltime)) && (event->time <= UINT(ltime) + (WINDOW_WIDTH * 60))) // starts within window
-  {
-    x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);
-    w = MINUTE_SCALE * event->duration / 60;
-    //if (w > 155 + MINUTE_SCALE * WINDOW_WIDTH -x)
-     // w = w + x - 155 - MINUTE_SCALE * WINDOW_WIDTH; // ends outside window
-  }
-  if (w > 155 + WINDOW_WIDTH * MINUTE_SCALE - x)
-    w = 155 + WINDOW_WIDTH * MINUTE_SCALE -x; // limit cells to RHS of window
-  rectangle(x, y, w, h, bg);
-  char* tt = new char[strlen(event->title) + 1];
-  strcpy (tt, event->title);
-  int textWidth = 0;
-  for (UINT textPos = 0; textPos < strlen(tt); textPos++)
-  {
-    int thisCharWidth = surface->getCharWidth(tt[textPos]);
-    if (textWidth + thisCharWidth > w) // text will not fit in cell
-    {
-      textWidth = textPos;
-      break;
-    }
-    textWidth += thisCharWidth;
-  }
-  char* tT = new char[textWidth];
-  if(textWidth > 1)
-  {
-    strncpy(tT, tt, textWidth - 1);
-    tT[textWidth - 1] =  '\0';
-    surface->drawText(tT, x+2, y, fg.rgba());
-  }
-  delete tT;
-
-}
-
-time_t VEpg::prevHour(time_t* t)
-{
-  struct tm* tms;
-  tms = localtime(t);
-  tms->tm_sec = 0;
-  tms->tm_min = 0;
-  return mktime(tms);
-}
-
-void VEpg::processMessage(Message* m)
-{
-  if (m->message == Message::MOUSE_MOVE)
-  {
-    if (chanListbox.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      drawData();
-      boxstack->update(this);
-    }
-  }
-  else if (m->message == Message::MOUSE_LBDOWN)
-  {
-    if (chanListbox.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      boxstack->handleCommand(Remote::OK); //simulate OK press
-    }
-    else
-    {
-      //check if press is outside this view! then simulate cancel
-      int x=(m->parameter>>16)-getScreenX();
-      int y=(m->parameter&0xFFFF)-getScreenY();
-      int keyx = chanListbox.getRootBoxOffsetX();
-      int keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;
-
-      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
-      {
-        boxstack->handleCommand(Remote::BACK); //simulate cancel press
-      }
-      else if (x>=(keyx+72) && y>=(keyy+4) &&x<=(keyx+72+104) &&y<=(keyy+4+Surface::getFontHeight() + 2))
-      {
-        boxstack->handleCommand(Remote::RED);
-      }
-      else if (x>=(keyx+72) && y>=(keyy+ Surface::getFontHeight() + 8) &&x<=(keyx+72+104) &&y<=(keyy+8+2*Surface::getFontHeight() + 2))
-      {
-        boxstack->handleCommand(Remote::GREEN);
-      }
-      else if (x>=(keyx+180) && y>=(keyy+4) &&x<=(keyx+180+104) &&y<=(keyy+4+Surface::getFontHeight() + 2))
-      {
-        boxstack->handleCommand(Remote::YELLOW);
-      }
-      else if (x>=(keyx+180) && y>=(keyy+ Surface::getFontHeight() + 8) &&x<=(keyx+180+104) &&y<=(keyy+8+2*Surface::getFontHeight() + 2))
-      {
-        boxstack->handleCommand(Remote::BLUE);
-      }
-      else if (x>=(keyx+290) && y>=(keyy+4) &&x<=(keyx+180+290) &&y<=(keyy+4+Surface::getFontHeight() + 2))
-      {
-        boxstack->handleCommand(Remote::BACK);
-      }
-      else if (x>=(keyx+290) && y>=(keyy+ Surface::getFontHeight() + 8) &&x<=(keyx+290+180) &&y<=(keyy+8+2*Surface::getFontHeight() + 2))
-      {
-        boxstack->handleCommand(Remote::RECORD);
-      }
-      else if (x>=(keyx+474) && y>=(keyy+4) &&x<=(keyx+128+474) &&y<=(keyy+4+Surface::getFontHeight() + 2))
-      {
-        boxstack->handleCommand(Remote::PLAY);
-      }
-      else if (x>=(keyx+474) && y>=(keyy+ Surface::getFontHeight() + 8) &&x<=(keyx+238+474) &&y<=(keyy+8+2*Surface::getFontHeight() + 2))
-      {
-        boxstack->handleCommand(Remote::GO);
-      }
-      else if ( x>=(chanListbox.getRootBoxOffsetX())
-                && y>=(chanListbox.getRootBoxOffsetY() + 5)
-                // &&x<=(chanListbox.getOffsetX()+155 + WINDOW_WIDTH * MINUTE_SCALE)
-                &&y<=(chanListbox.getRootBoxOffsetY() - Surface::getFontHeight()
-                - 3+(int)chanListbox.getHeight() + Surface::getFontHeight() + 3)
-              )
-      {
-        int cy=y-(chanListbox.getRootBoxOffsetY() + 5);
-        int row=cy/(Surface::getFontHeight()+2);
-        int clistTop = chanListbox.getTopOption();
-        chanListbox.hintSetCurrent(clistTop+row);
-        int cx=x-155;
-        time_t ttime = cx*60/MINUTE_SCALE+ltime;
-        //x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);
-
-        selTime = ttime;
-        drawData();
-        boxstack->update(this);
-      }
-    }
-  }
-}
-
+/*\r
+    Copyright 2005 Brian Walton\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+/*\r
+    vepg presents a 2 dimensional electronic programme guide with channels down\r
+    the y axis and time along the x axis.\r
+    Programmes are layed on the x axis as alterate coloured blocks with as much\r
+    of the programme title as will fit inside the block shown as text.\r
+    Up and down commands step through the channels whilst left and right commands\r
+    move through the programmes of the currently selected channel.\r
+    When a programme is selected, it highlights in the grid and full programe details\r
+    (start time, title and description) are displayed in an area at te top left of the screen.\r
+    Any currently programmed timers will display in the grid and in the orogramme detail window as red\r
+    It is possible to select a programme to be recorded by pressing the record button.\r
+    The video stream currently being viewed is shown as quarter screen in the top right.\r
+*/\r
+\r
+#include "vepg.h"\r
+\r
+#include "remote.h"\r
+#include "vchannellist.h"\r
+#include "command.h"\r
+#include "video.h"\r
+#include "vepgsettimer.h"\r
+#include "timers.h"\r
+#include "wsymbol.h"\r
+#include "message.h"\r
+#include "colour.h"\r
+#include "boxstack.h"\r
+#include "channel.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+\r
+VEpg* VEpg::instance = NULL;\r
+\r
+VEpg::VEpg(void* tparent, UINT tcurrentChannelIndex, ULONG streamType)\r
+{\r
+  instance = this;\r
+  currentChannelIndex = tcurrentChannelIndex;\r
+\r
+  // PAL / NTSC sizes -----------------------\r
+\r
+  int xsize, ysize;\r
+  int xpos, ypos;\r
+  int summaryLines, summaryLowerPadding;\r
+  int chanNameYpos;\r
+  //UINT gridRows; // is a class member\r
+\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+  {\r
+    xsize = 632;\r
+    ysize = 541;\r
+    xpos = 60;\r
+    ypos = 16;\r
+    summaryLines = 8;\r
+    summaryLowerPadding = 18;\r
+    chanNameYpos = 244;\r
+    gridRows = 7;\r
+  }\r
+  else\r
+  {\r
+    xsize = 632;\r
+    ysize = 452;\r
+    xpos = 50;\r
+    ypos = 10;\r
+    summaryLines = 6;\r
+    summaryLowerPadding = 28;\r
+    chanNameYpos = 206;\r
+    gridRows = 5;\r
+  }\r
+\r
+  // initialise variables and pointers\r
+  boxstack = BoxStack::getInstance();\r
+  parent = tparent;\r
+  eventList = NULL;\r
+  chanList = VDR::getInstance()->getChannelsList(streamType); //TODO want to be able to display video and radio together\r
+  e = 0;\r
+\r
+  for(UINT listIndex = 0; listIndex < gridRows; listIndex++)\r
+  {\r
+    // initialise array of pointers to eventlist structures\r
+    eventLista[listIndex] = NULL;\r
+  }\r
+\r
+  // Create pallet on which to paint our epg view and position it in centre of screen.\r
+  // Need to reduce size to deal with overscanning TVs.\r
+\r
+  setSize(xsize, ysize);\r
+  createBuffer();\r
+  setPosition(xpos, ypos);\r
+\r
+  // beautify\r
+//  Colour transparent = Colour(0, 0, 0, 0);\r
+//  setBackgroundColour(transparent);\r
+\r
+//  progTitle.setSurface(surface);\r
+  progTitle.setPosition(0,0);\r
+  progTitle.setSize(300,(getFontHeight() + 4) * 2 + 16); //paragraph line seperation is 4 pixels\r
+  progTitle.setBackgroundColour(Colour::TITLEBARBACKGROUND);\r
+  progTitle.setTextPos(5, 16);\r
+  progTitle.setGap(4);\r
+  add(&progTitle);\r
+\r
+//  progInfo.setSurface(surface);\r
+  progInfo.setBackgroundColour(Colour::VIEWBACKGROUND);\r
+  progInfo.setPosition(0, progTitle.getY2());\r
+  progInfo.setSize(300,((getFontHeight() + 4) * summaryLines) + summaryLowerPadding);\r
+  progInfo.setGap(4);\r
+  add(&progInfo);\r
+\r
+//  chanName.setSurface(surface);\r
+  chanName.setSize(510, (getFontHeight() + 4));\r
+  chanName.setPosition(305, chanNameYpos);\r
+    Colour t1(0, 0, 0, 90);\r
+  chanName.setBackgroundColour(t1);\r
+  add(&chanName);\r
+\r
+  // create area to display list of channels\r
+//  chanListbox.setSurface(surface); // add channel list\r
+  chanListbox.setPosition(0, progInfo.getY2() + getFontHeight() + 8); // position channel list\r
+  chanListbox.setSize(150, ((getFontHeight() + 2) * gridRows) + 5); //listbox line seperation is 2 pixels\r
+  chanListbox.setGap(2);\r
+  add(&chanListbox);\r
+\r
+  // populate channel list\r
+  if (chanList)\r
+  {\r
+    Channel* chan;\r
+    int first = 1;\r
+    for (UINT i = 0; i < chanList->size(); i++)\r
+    {\r
+      chan = (*chanList)[i];\r
+      if (i == currentChannelIndex)\r
+        first = 1;\r
+      chan->index = chanListbox.addOption(chan->name, 0, first);\r
+      first = 0;\r
+    }\r
+    chanName.setText((*chanList)[chanListbox.getCurrentOption()]->name);\r
+  }\r
+\r
+  listTop = chanListbox.getTopOption();\r
+  chanListbox.draw(); // doing this to allow chanListbox.getBottomOption() in updateEventList() to work\r
+  time(&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
+  Colour transparent = Colour(0, 0, 0, 0);\r
+  fillColour(transparent);\r
+  \r
+  \r
+  // Moved all the dynamic data drawing to a seperate function\r
+\r
+  // Display the status and key stuff at the bottom\r
+\r
+  UINT keyx = chanListbox.getRootBoxOffsetX();\r
+  UINT keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;\r
+  Colour ref1 = Colour(100, 100, 100, 255);\r
+  rectangle(keyx, keyy, 605, getFontHeight() * 2 + 14, ref1);\r
+\r
+  WSymbol w;\r
+  TEMPADD(&w);\r
+  \r
+  w.nextSymbol = WSymbol::LEFTARROW;\r
+  w.setPosition(keyx + 1, keyy + 20);\r
+  w.draw();\r
+\r
+  w.nextSymbol = WSymbol::UP;\r
+  w.setPosition(keyx + 26, keyy + 3);\r
+  w.draw();\r
+\r
+  w.nextSymbol = WSymbol::DOWN;\r
+  w.setPosition(keyx + 26, keyy + 36);\r
+  w.draw();\r
+\r
+  w.nextSymbol = WSymbol::RIGHTARROW;\r
+  w.setPosition(keyx + 50, keyy + 20);\r
+  w.draw();\r
+\r
+  drawText(tr("OK"), keyx + 18, keyy + 20, Colour::LIGHTTEXT);\r
+\r
+  Colour ref2 = Colour(200, 0, 0, 255);\r
+  rectangle(keyx + 72, keyy + 4, 104, getFontHeight() + 2, ref2);\r
+  drawText(tr("Page up"), keyx + 74, keyy + 5, Colour::LIGHTTEXT);\r
+\r
+  Colour ref3 = Colour(0, 200, 0, 255);\r
+  rectangle(keyx + 72, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, ref3);\r
+  drawText(tr("Page down"), keyx + 74, keyy + getFontHeight() + 9, Colour::LIGHTTEXT);\r
+\r
+  Colour ref4 = Colour(200, 200, 0, 255);\r
+  rectangle(keyx + 180, keyy + 4, 104, getFontHeight() + 2, ref4);\r
+  drawText(tr("-24 hours"), keyx + 182, keyy + 5, Colour::LIGHTTEXT);\r
+\r
+  Colour ref5 = Colour(0, 0, 200, 255);\r
+  rectangle(keyx + 180, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, ref5);\r
+  drawText(tr("+24 hours"), keyx + 182, keyy + getFontHeight() + 9, Colour::LIGHTTEXT);\r
+\r
+  Colour ref6 = Colour(180, 180, 180, 255);\r
+  rectangle(keyx + 290, keyy + 4, 180, getFontHeight() + 2, ref6);\r
+  drawText(tr("Guide / Back: Close"), keyx + 292 , keyy + 5, Colour::LIGHTTEXT);\r
+\r
+  Colour ref7 = Colour(180, 180, 180, 255);\r
+  rectangle(keyx + 290, keyy + getFontHeight() + 8, 180, getFontHeight() + 2, ref7);\r
+  Colour red = Colour(130, 0, 0);\r
+  drawText(tr("Rec: Set timer"), keyx + 292, keyy + getFontHeight() + 9, red);\r
+\r
+  Colour ref8 = Colour(180, 180, 180, 255);\r
+  rectangle(keyx + 474, keyy + 4, 128, getFontHeight() + 2, ref8);\r
+  w.nextSymbol = WSymbol::PLAY;\r
+  w.setPosition(keyx + 476, keyy + 5);\r
+  w.draw();\r
+  drawText(tr("Sel channel"), keyx + 496, keyy + 5, Colour::LIGHTTEXT);\r
+\r
+  Colour ref9 = Colour(180, 180, 180, 255);\r
+  rectangle(keyx + 474, keyy + getFontHeight() + 8, 128, getFontHeight() + 2, ref9);\r
+  drawText(tr("Go: Preview"), keyx + 476, keyy + getFontHeight() + 9, Colour::LIGHTTEXT);\r
+\r
+\r
+  // Draw all the dynamic data\r
+  drawData();\r
+}\r
+\r
+void VEpg::drawData()\r
+{\r
+  // Not doing View::draw() every time causes\r
+  // things not to be cleared off the surface properly\r
+  // So, blank out the data area first\r
+\r
+  rectangle(\r
+    chanListbox.getRootBoxOffsetX(),\r
+    chanListbox.getRootBoxOffsetY() - getFontHeight() - 3,\r
+    155 + WINDOW_WIDTH * MINUTE_SCALE,\r
+    chanListbox.getHeight() + getFontHeight() + 4,\r
+    Colour::BLACK);\r
+\r
+  chanListbox.draw();\r
+  drawgrid();\r
+  chanName.draw(); // TODO this should be dealt with by vvideolive\r
+\r
+  progTitle.draw();\r
+  progInfo.draw();\r
+\r
+  // Set timer to redraw to move the current time bar\r
+  time_t t, dt;\r
+  time(&t);\r
+  dt = 60 - (t % 60);\r
+  if (dt == 0) dt = 60;\r
+  dt += t;\r
+  Timers::getInstance()->setTimerT(this, 1, dt);\r
+}\r
+\r
+void VEpg::timercall(int clientReference)\r
+{\r
+  drawData();\r
+  boxstack->update(this);\r
+}\r
+\r
+int VEpg::handleCommand(int command)\r
+{\r
+  switch(command)\r
+  {\r
+    case Remote::DF_UP:\r
+    case Remote::UP:\r
+    { // cursor up the channel list\r
+      chanListbox.up();\r
+      drawData();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::DF_DOWN:\r
+    case Remote::DOWN:\r
+    { // cursor down the channel list\r
+      Log::getInstance()->log("VEPG", Log::DEBUG, "Down start");\r
+      \r
+      chanListbox.down();\r
+      drawData();\r
+      boxstack->update(this);\r
+      Log::getInstance()->log("VEPG", Log::DEBUG, "Down end");\r
+\r
+      return 2;\r
+    }\r
+    case Remote::DF_LEFT:\r
+    case Remote::LEFT:\r
+    { // cursor left through time\r
+      selTime = thisEvent.time - 1;\r
+      drawData();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::DF_RIGHT:\r
+    case Remote::RIGHT:\r
+    {\r
+    // cursor right through time\r
+      selTime = thisEvent.time + thisEvent.duration;\r
+      drawData();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::RED:\r
+    {\r
+    // cursor up one page\r
+      chanListbox.pageUp();\r
+      drawData();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::GREEN:\r
+    {\r
+    // cursor down one page\r
+      chanListbox.pageDown();\r
+      drawData();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::BLUE:\r
+    {\r
+    // step forward 24 hours\r
+      selTime += 24 * 60 * 60;\r
+      drawData();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::YELLOW:\r
+    {\r
+    // step forward 24 hours\r
+      selTime -= 24 * 60 * 60;\r
+      drawData();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::RECORD:\r
+    {\r
+      if (!chanList) return 2;\r
+      Log::getInstance()->log("VEPG", Log::DEBUG, "ID %lu TIME %lu DURATION %lu TITLE %s", thisEvent.id, thisEvent.time, thisEvent.duration, thisEvent.title);\r
+      VEpgSetTimer* vs = new VEpgSetTimer(&thisEvent, (*chanList)[chanListbox.getCurrentOption()]);\r
+      vs->draw();\r
+      boxstack->add(vs);\r
+      boxstack->update(vs);\r
+      return 2;\r
+    }\r
+    case Remote::PLAY:\r
+    case Remote::GO:\r
+    case Remote::OK:\r
+    {\r
+      if (!chanList) return 2;\r
+\r
+      // select programme and display menu TODO currently just changes to selected channel\r
+\r
+      currentChannelIndex = chanListbox.getCurrentOption();\r
+\r
+      if (parent)\r
+      {\r
+        Message* m = new Message(); // Must be done after this view deleted\r
+        m->from = this;\r
+        m->to = parent;\r
+        m->message = Message::CHANNEL_CHANGE;\r
+        m->parameter = (*chanList)[currentChannelIndex]->number;\r
+        Command::getInstance()->postMessageNoLock(m);\r
+      }\r
+      \r
+      setCurrentChannel();\r
+\r
+      if(command == Remote::GO)\r
+        return 2;\r
+      // GO just changes channel in preview, PLAY changes channel and returns to normal TV\r
+    }\r
+    case Remote::BACK:\r
+    case Remote::GUIDE:\r
+    {\r
+      // return to normal TV mode\r
+      if (parent) // ptr check done in case being tested from videorec\r
+      {\r
+        Message* m = new Message(); // Must be done after this view deleted\r
+        m->from = this;\r
+        m->to = parent;\r
+        m->message = Message::EPG_CLOSE;\r
+        Command::getInstance()->postMessageNoLock(m);\r
+      }\r
+      return 4;\r
+    }\r
+    case Remote::CHANNELUP:\r
+    {\r
+      if (currentChannelIndex == (chanList->size() - 1)) // at the end\r
+        currentChannelIndex = 0;\r
+      else\r
+        ++currentChannelIndex;\r
+      \r
+      if (parent)\r
+      {\r
+        Message* m = new Message(); // Must be done after this view deleted\r
+        m->from = this;\r
+        m->to = parent;\r
+        m->message = Message::CHANNEL_CHANGE;\r
+        m->parameter = (*chanList)[currentChannelIndex]->number;\r
+        Command::getInstance()->postMessageNoLock(m);\r
+      }\r
+      \r
+      setCurrentChannel();\r
+\r
+      return 2;\r
+    }\r
+    case Remote::CHANNELDOWN:\r
+    {\r
+      if (currentChannelIndex == 0) // at the start\r
+        currentChannelIndex = chanList->size() - 1; // so go to end\r
+      else\r
+        --currentChannelIndex;\r
+\r
+      if (parent)\r
+      {\r
+        Message* m = new Message(); // Must be done after this view deleted\r
+        m->from = this;\r
+        m->to = parent;\r
+        m->message = Message::CHANNEL_CHANGE;\r
+        m->parameter = (*chanList)[currentChannelIndex]->number;\r
+        Command::getInstance()->postMessageNoLock(m);\r
+      }\r
+      \r
+      setCurrentChannel();\r
+\r
+      return 2;\r
+    }\r
+  }\r
+  // stop command getting to any more views\r
+  return 1;\r
+}\r
+\r
+void VEpg::drawgrid() // redraws grid and select programme\r
+{\r
+  // draw the grid of programmes\r
+  char timeString[20];\r
+  time_t t;\r
+  time(&t); // set t = now\r
+  if(selTime < t)\r
+    selTime = t; // don't allow cursor in the past\r
+  if(listTop != chanListbox.getTopOption())\r
+  {\r
+  // chanListbox has scrolled TODO speed up by changing only rows that have changed\r
+    listTop = chanListbox.getTopOption();\r
+    updateEventList();\r
+  }\r
+  if ((selTime >= ltime + WINDOW_WIDTH * 60) || (selTime <= ltime))\r
+  {\r
+  // we have cursored back before left time of window\r
+  //TODO check that this and above don't happen together\r
+    ltime = prevHour(&selTime);\r
+    updateEventList();\r
+  }\r
+  // draw time scale\r
+  Colour white = Colour(255, 255, 255, 255);\r
+  \r
+  t = ltime;\r
+  struct tm* tms;\r
+  tms = localtime(&t);\r
+  strftime(timeString, 19, "%a %d %b", tms);\r
+  int timey = chanListbox.getRootBoxOffsetY() - getFontHeight() - 3;\r
+  int timex = 135;\r
+  drawTextRJ(timeString, timex - 10, timey, Colour::LIGHTTEXT); // print date\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  drawText(timeString, timex, timey, Colour::LIGHTTEXT); // print left time\r
+\r
+  rectangle(155, timey + getFontHeight(), 2, 7, white);\r
+  t = t + 3600;\r
+  tms = localtime(&t);\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  drawText(timeString, timex + 180, timey, Colour::LIGHTTEXT); // print middle time\r
+  rectangle(335, timey + getFontHeight(), 2, 7, white);\r
+  t = t + 3600;\r
+  tms = localtime(&t);\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  drawText(timeString, timex + 360, timey, Colour::LIGHTTEXT); // print right time\r
+  rectangle(515, timey + getFontHeight(), 2, 7, white);\r
+  // pointer to selTime\r
+  //rectangle(155 + (selTime - ltime) / 20, timey + getFontHeight(), 2, 7, Colour(255, 50, 50, 255));\r
+\r
+  // current time line\r
+  time(&t);\r
+  if ((t >= ltime) && (t < (ltime + 9000)))\r
+  {\r
+    rectangle(155 + (t - ltime) / 20, timey + getFontHeight(), 2, ((getFontHeight() + 2) * 7) + 7 + 2, Colour::RED);\r
+  }\r
+\r
+  // TODO should the above two comditional statements be combined to avoid calling updateEventList() twice?\r
+  Event* event;\r
+  Event noevent; // an event to use if there are gaps in the epg\r
+  thisEvent.setdescription(tr("There are no programme details available for this period"));\r
+  thisEvent.duration = WINDOW_WIDTH * 60;\r
+  thisEvent.time = ltime;\r
+  thisEvent.settitle(tr("No programme details"));\r
+  thisEvent.id = 0;\r
+  bool swapColour = false; // alternate cell colour\r
+  bool currentRow = false;\r
+  int y = chanListbox.getRootBoxOffsetY() + 5; // vertical position of cell\r
+  Colour bg, fg; // background colour of cells in grid\r
+  // for each displayed channel, find programmes that fall in 2.5 hour time window\r
+  for(UINT listIndex = 0; listIndex < gridRows; listIndex++)\r
+  {\r
+    if (listTop + (int)listIndex >= chanListbox.getBottomOption())\r
+      continue; // ensure nothing populates grid below last channel\r
+    currentRow = (listTop + (int)listIndex == chanListbox.getCurrentOption());\r
+    noevent.time = ltime;\r
+    noevent.duration = WINDOW_WIDTH * 60;\r
+    noevent.settitle("");\r
+    paintCell(&noevent, y, Colour::NOPROGRAMME, Colour::LIGHTTEXT); // fill row with no programme colour to be painted ove with valid programmes\r
+    if (currentRow)\r
+    {\r
+      thisEvent.setdescription(tr("There are no programme details available for this period"));\r
+      thisEvent.duration = WINDOW_WIDTH * 60;\r
+      thisEvent.time = ltime;\r
+      thisEvent.settitle(tr("No programme details"));\r
+      thisEvent.id = 0;\r
+    }\r
+    if (eventLista[listIndex])\r
+    {\r
+      sort(eventLista[listIndex]->begin(), eventLista[listIndex]->end(), EventSorter());\r
+      for(e = 0; e < (eventLista[listIndex])->size(); e++) // step through events for this channel\r
+      {\r
+        fg = Colour::LIGHTTEXT;\r
+        event = (*eventLista[listIndex])[e];\r
+        if (event)\r
+        {\r
+          UINT end = event->time + event->duration; // programme end time\r
+          if(event->time >= UINT(ltime) + (WINDOW_WIDTH * 60)) // programme starts after RHS of window\r
+            continue; // that's enough of this channel's events\r
+          if(end <= UINT(ltime)) // programme ends before LHS of window\r
+            continue; // this event is before the window - let's try the next event\r
+          // this event is one we are interested in\r
+          bg = (swapColour)?Colour::PROGRAMMEA:Colour::PROGRAMMEB; // alternate cell colour\r
+          swapColour = !swapColour; // it wil be the other colour next time\r
+          if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow)\r
+          {\r
+            // this is the selected programme\r
+            thisEvent.setdescription(event->description);\r
+            thisEvent.duration = event->duration;\r
+            thisEvent.time = event->time;\r
+            thisEvent.settitle(event->title);\r
+            thisEvent.id = event->id;\r
+            if(thisEvent.id == 0)\r
+              thisEvent.id = 1;\r
+            bg = Colour::SELECTHIGHLIGHT; // highlight cell\r
+            fg = Colour::DARKTEXT;\r
+          }\r
+          else\r
+          {\r
+            if (currentRow && thisEvent.id == 0)\r
+            {\r
+              if (end <= UINT(selTime) && end > UINT(thisEvent.time))\r
+                thisEvent.time = end;\r
+              if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration)\r
+                thisEvent.duration = event->time - thisEvent.time;\r
+            }\r
+          }\r
+          paintCell(event, y, bg, fg);\r
+        }\r
+      }\r
+    }\r
+    else\r
+    {\r
+      // no event list for this channel. Already painted noevent colour so just highlight if selected\r
+      if (currentRow)\r
+      {\r
+        bg = Colour::SELECTHIGHLIGHT; // highlight cell\r
+        fg = Colour::DARKTEXT;\r
+        paintCell(&thisEvent, y, bg, fg);\r
+      }\r
+      else\r
+      {\r
+        bg = Colour::NOPROGRAMME;\r
+        fg = Colour::LIGHTTEXT;\r
+        noevent.settitle(tr("No programme details"));\r
+        paintCell(&noevent, y, bg, fg);\r
+      }\r
+    }\r
+    y += getFontHeight() + 2;\r
+  }\r
+  setInfo(&thisEvent);\r
+}\r
+\r
+void VEpg::updateEventList()\r
+{\r
+  if (!chanList) return;\r
+  Channel* chan;\r
+  for(UINT listIndex = 0; listIndex < gridRows; listIndex++)\r
+  {\r
+    if(listTop + listIndex >= UINT(chanListbox.getBottomOption()))\r
+      continue;\r
+    chan = (*chanList)[listTop + listIndex];\r
+\r
+    eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, ltime - 1, WINDOW_WIDTH * 60 + 2); // ltime - 1 to get prog before window (allows cursor left past ltime). + 2 to get prog after window\r
+  }\r
+}\r
+\r
+void VEpg::setCurrentChannel()\r
+{\r
+  chanName.setText((*chanList)[currentChannelIndex]->name);\r
+  chanName.draw();\r
+  Region r;\r
+  chanName.getRootBoxRegion(&r);\r
+  boxstack->update(this, &r);\r
+}\r
+\r
+void VEpg::paintCell(Event* event, int yOffset, const Colour& bg, const Colour& fg)\r
+{\r
+  int w, x, y, h;\r
+  w = x = 0; // keep compiler happy\r
+\r
+  y =yOffset;\r
+  h = getFontHeight(); // TODO if want border around text, need to increae this and wselectlist line height\r
+  UINT end = event->time + event->duration; // programme end time\r
+  if(event->time <= UINT(ltime) && end > UINT(ltime)) // spans start of displayed window\r
+  {\r
+    x = 155; // LHS of window\r
+    if (end > (UINT(ltime) + (WINDOW_WIDTH * 60)))\r
+      w = WINDOW_WIDTH * MINUTE_SCALE; // spans full 2 hour window\r
+    else\r
+      w = MINUTE_SCALE * (event->time + event->duration - ltime ) / 60; // get width of remaining programme\r
+  }\r
+  if((event->time >= UINT(ltime)) && (event->time <= UINT(ltime) + (WINDOW_WIDTH * 60))) // starts within window\r
+  {\r
+    x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);\r
+    w = MINUTE_SCALE * event->duration / 60;\r
+    //if (w > 155 + MINUTE_SCALE * WINDOW_WIDTH -x)\r
+     // w = w + x - 155 - MINUTE_SCALE * WINDOW_WIDTH; // ends outside window\r
+  }\r
+  if (w > 155 + WINDOW_WIDTH * MINUTE_SCALE - x)\r
+    w = 155 + WINDOW_WIDTH * MINUTE_SCALE -x; // limit cells to RHS of window\r
+  rectangle(x, y, w, h, bg);\r
+  char* tt = new char[strlen(event->title) + 1];\r
+  strcpy (tt, event->title);\r
+  int textWidth = 0;\r
+  for (UINT textPos = 0; textPos < strlen(tt); textPos++)\r
+  {\r
+    int thisCharWidth = charWidth(tt[textPos]);\r
+    if (textWidth + thisCharWidth > w) // text will not fit in cell\r
+    {\r
+      textWidth = textPos;\r
+      break;\r
+    }\r
+    textWidth += thisCharWidth;\r
+  }\r
+  char* tT = new char[textWidth];\r
+  if(textWidth > 1)\r
+  {\r
+    strncpy(tT, tt, textWidth - 1);\r
+    tT[textWidth - 1] =  '\0';\r
+    surface->drawText(tT, x+2, y, fg.rgba());\r
+  }\r
+  delete tT;\r
+\r
+}\r
+\r
+time_t VEpg::prevHour(time_t* t)\r
+{\r
+  struct tm* tms;\r
+  tms = localtime(t);\r
+  tms->tm_sec = 0;\r
+  tms->tm_min = 0;\r
+  return mktime(tms);\r
+}\r
+\r
+void VEpg::processMessage(Message* m)\r
+{\r
+  if (m->message == Message::MOUSE_MOVE)\r
+  {\r
+    if (chanListbox.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      drawData();\r
+      boxstack->update(this);\r
+    }\r
+  }\r
+  else if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    if (chanListbox.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      boxstack->handleCommand(Remote::OK); //simulate OK press\r
+    }\r
+    else\r
+    {\r
+      //check if press is outside this view! then simulate cancel\r
+      int x=(m->parameter>>16)-getScreenX();\r
+      int y=(m->parameter&0xFFFF)-getScreenY();\r
+      int keyx = chanListbox.getRootBoxOffsetX();\r
+      int keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;\r
+\r
+      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+      {\r
+        boxstack->handleCommand(Remote::BACK); //simulate cancel press\r
+      }\r
+      else if (x>=(keyx+72) && y>=(keyy+4) &&x<=(keyx+72+104) &&y<=(keyy+4+getFontHeight() + 2))\r
+      {\r
+        boxstack->handleCommand(Remote::RED);\r
+      }\r
+      else if (x>=(keyx+72) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+72+104) &&y<=(keyy+8+2*getFontHeight() + 2))\r
+      {\r
+        boxstack->handleCommand(Remote::GREEN);\r
+      }\r
+      else if (x>=(keyx+180) && y>=(keyy+4) &&x<=(keyx+180+104) &&y<=(keyy+4+getFontHeight() + 2))\r
+      {\r
+        boxstack->handleCommand(Remote::YELLOW);\r
+      }\r
+      else if (x>=(keyx+180) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+180+104) &&y<=(keyy+8+2*getFontHeight() + 2))\r
+      {\r
+        boxstack->handleCommand(Remote::BLUE);\r
+      }\r
+      else if (x>=(keyx+290) && y>=(keyy+4) &&x<=(keyx+180+290) &&y<=(keyy+4+getFontHeight() + 2))\r
+      {\r
+        boxstack->handleCommand(Remote::BACK);\r
+      }\r
+      else if (x>=(keyx+290) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+290+180) &&y<=(keyy+8+2*getFontHeight() + 2))\r
+      {\r
+        boxstack->handleCommand(Remote::RECORD);\r
+      }\r
+      else if (x>=(keyx+474) && y>=(keyy+4) &&x<=(keyx+128+474) &&y<=(keyy+4+getFontHeight() + 2))\r
+      {\r
+        boxstack->handleCommand(Remote::PLAY);\r
+      }\r
+      else if (x>=(keyx+474) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+238+474) &&y<=(keyy+8+2*getFontHeight() + 2))\r
+      {\r
+        boxstack->handleCommand(Remote::GO);\r
+      }\r
+      else if ( x>=(chanListbox.getRootBoxOffsetX())\r
+                && y>=(chanListbox.getRootBoxOffsetY() + 5)\r
+                // &&x<=(chanListbox.getOffsetX()+155 + WINDOW_WIDTH * MINUTE_SCALE)\r
+                &&y<=(chanListbox.getRootBoxOffsetY() - getFontHeight()\r
+                - 3+(int)chanListbox.getHeight() + getFontHeight() + 3)\r
+              )\r
+      {\r
+        int cy=y-(chanListbox.getRootBoxOffsetY() + 5);\r
+        int row=cy/(getFontHeight()+2);\r
+        int clistTop = chanListbox.getTopOption();\r
+        chanListbox.hintSetCurrent(clistTop+row);\r
+        int cx=x-155;\r
+        time_t ttime = cx*60/MINUTE_SCALE+ltime;\r
+        //x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);\r
+\r
+        selTime = ttime;\r
+        drawData();\r
+        boxstack->update(this);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
index 3c5dad45d2e4fb38eb913bcb5401e52618c9df93..4e00ab62c0db956170ededbb2254cd975de237df 100644 (file)
@@ -60,8 +60,8 @@ VEpgSetTimer::VEpgSetTimer(Event* tevent, Channel* tchannel)
   add(&buttonYes);
   add(&buttonNo);
 
-  buttonYes.setPosition(80, 40 + (7 * surface->getFontHeight()));
-  buttonNo.setPosition(220, 40 + (7 * surface->getFontHeight()));
+  buttonYes.setPosition(80, 40 + (7 * getFontHeight()));
+  buttonNo.setPosition(220, 40 + (7 * getFontHeight()));
 
   buttonYes.setText(tr("Yes"));
   buttonNo.setText(tr("No"));
@@ -174,7 +174,7 @@ void VEpgSetTimer::draw()
 {
   TBBoxx::draw();
   drawPara(event->title, 10, 40, Colour::LIGHTTEXT);
-  drawText(channel->name, 10, 40 + (2 * surface->getFontHeight()), Colour::LIGHTTEXT);
+  drawText(channel->name, 10, 40 + (2 * getFontHeight()), Colour::LIGHTTEXT);
 
   char fullString[20];
   time_t t;
@@ -197,8 +197,8 @@ void VEpgSetTimer::draw()
 
   strcat(fullString, timeString); // put it in our buffer
 
-  drawText(fullString, 10, 40 + (3 * surface->getFontHeight()), Colour::LIGHTTEXT);
-  drawText(tr("Create this timer?"), 10, 40 + (5 * surface->getFontHeight()), Colour::LIGHTTEXT);
+  drawText(fullString, 10, 40 + (3 * getFontHeight()), Colour::LIGHTTEXT);
+  drawText(tr("Create this timer?"), 10, 40 + (5 * getFontHeight()), Colour::LIGHTTEXT);
 
   buttonYes.draw();
   buttonNo.draw();
index f15d7139b429c98f94303c4e66606343aac91271..6640a13f150897b7075f888a7d08c326fd1f3c5c 100644 (file)
--- a/vfeed.cc
+++ b/vfeed.cc
@@ -1,82 +1,84 @@
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vfeed.h"
-
-#include "log.h"
-#include "demuxer.h"
-#include "callback.h"
-
-VFeed::VFeed(Callback* tcb)
-: cb(*tcb)
-{
-}
-
-int VFeed::init()
-{
-  return 1;
-}
-
-int VFeed::shutdown()
-{
-  // FIXME
-  return 1;
-}
-
-int VFeed::start()
-{
-  return threadStart();
-}
-
-void VFeed::stop()
-{
-  threadCancel();
-}
-
-void VFeed::release()
-{
-  threadSignal();
-}
-
-void VFeed::threadMethod()
-{
-  bool vlen;
-
-  Log::getInstance()->log("VFeed", Log::DEBUG, "Started");
-  threadWaitForSignal(); // Don't feed video until audio has started
-  Log::getInstance()->log("VFeed", Log::DEBUG, "Released");
-
-  while(1)
-  {
-    threadCheckExit();
-    vlen = Demuxer::getInstance()->writeVideo();
-
-    if (vlen)
-    {
-      cb.call(this);
-    }
-    else
-    {
-      //Log::getInstance()->log("VFeed", Log::DEBUG, "No data delay");
-      MILLISLEEP(5);
-    }
-  }
-}
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vfeed.h"\r
+\r
+#include "log.h"\r
+#include "demuxer.h"\r
+#include "callback.h"\r
+\r
+VFeed::VFeed(Callback* tcb)\r
+: cb(*tcb)\r
+{\r
+}\r
+\r
+int VFeed::init()\r
+{\r
+  return 1;\r
+}\r
+\r
+int VFeed::shutdown()\r
+{\r
+  // FIXME\r
+  return 1;\r
+}\r
+\r
+int VFeed::start()\r
+{\r
+  return threadStart();\r
+}\r
+\r
+void VFeed::stop()\r
+{\r
+       Log::getInstance()->log("VFeed", Log::DEBUG, "Stop1");\r
+  threadCancel();\r
+       Log::getInstance()->log("VFeed", Log::DEBUG, "Stop2");\r
+}\r
+\r
+void VFeed::release()\r
+{\r
+  threadSignal();\r
+}\r
+\r
+void VFeed::threadMethod()\r
+{\r
+  bool vlen;\r
+\r
+  Log::getInstance()->log("VFeed", Log::DEBUG, "Started");\r
+  threadWaitForSignal(); // Don't feed video until audio has started\r
+  Log::getInstance()->log("VFeed", Log::DEBUG, "Released");\r
+\r
+  while(1)\r
+  {\r
+    threadCheckExit();\r
+    vlen = Demuxer::getInstance()->writeVideo();\r
+\r
+    if (vlen)\r
+    {\r
+      cb.call(this);\r
+    }\r
+    else\r
+    {\r
+      //Log::getInstance()->log("VFeed", Log::DEBUG, "No data delay");\r
+      MILLISLEEP(5);\r
+    }\r
+  }\r
+}\r
+\r
diff --git a/vfeed.h b/vfeed.h
index 0233e669e638704213533a5e8ec759eed3e61bbb..0fa27211b3b62818f30ed136346a5507eb5a0c43 100644 (file)
--- a/vfeed.h
+++ b/vfeed.h
 #include <stdio.h>
 #include <time.h>
 
-#ifdef WIN32
-#include "threadwin.h"
+#ifndef WIN32
+#ifdef __ANDROID__
+#include "threadpandroid.h"
 #else
 #include "threadp.h"
 #endif
+#else
+#include "threadwin.h"
+#endif
 
 class Callback;
 
index 1d6254d7ea563707337e77b5c295c82245524803..864c1a06b5628f7afad9034eac41a023071c1e65 100644 (file)
--- a/video.cc
+++ b/video.cc
@@ -1,93 +1,98 @@
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-//portions from vdr by Klaus Schmiding HSMF code
-
-#include "video.h"
-
-Video* Video::instance = NULL;
-
-Video::Video()
-{
-  if (instance) return;
-  instance = this;
-  initted = 0;
-
-  fdVideo = 0;
-
-  format = 0;
-  connection = 0;
-  aspectRatio = 0;
-  mode = 0;
-  tvsize = 0;
-
-  screenWidth = 0;
-  screenHeight = 0;
-}
-
-Video::~Video()
-{
-  instance = NULL;
-}
-
-Video* Video::getInstance()
-{
-  return instance;
-}
-
-/*
-hmsf Video::framesToHMSF(ULONG frames, double fps)
-{
-  hmsf ret;
-  / * from vdr *
-  double Seconds;
-  ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);
-  int s = int(Seconds);
-  ret.seconds=s;
-  ret.minutes = s / 60 % 60;
-  ret.hours = s / 3600;
-
-/ *  if (format == NTSC)
-  {
-    ret.hours = frames / 108000;
-    frames %= 108000;
-    ret.minutes = frames / 1800;
-    frames %= 1800;
-    ret.seconds = frames / 30;
-    ret.frames = frames % 30;
-  }
-  else
-  {
-    ret.hours = frames / 90000;
-    frames %= 90000;
-    ret.minutes = frames / 1500;
-    frames %= 1500;
-    ret.seconds = frames / 25;
-    ret.frames = frames % 25;
-  }* /
-  return ret;
-}*/
-
-/*
-UINT Video::getFPS()
-{
-  if (format == NTSC) return 30;
-  else return 25;
-}
-*/
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+//portions from vdr by Klaus Schmiding HSMF code\r
+\r
+#include "video.h"\r
+\r
+Video* Video::instance = NULL;\r
+\r
+Video::Video()\r
+{\r
+  if (instance) return;\r
+  instance = this;\r
+  initted = 0;\r
+\r
+  fdVideo = 0;\r
+\r
+  format = 0;\r
+  connection = 0;\r
+  aspectRatio = 0;\r
+  mode = 0;\r
+  tvsize = 0;\r
+\r
+  screenWidth = 0;\r
+  screenHeight = 0;\r
+}\r
+\r
+Video::~Video()\r
+{\r
+  instance = NULL;\r
+}\r
+\r
+Video* Video::getInstance()\r
+{\r
+  return instance;\r
+}\r
+/*\r
+void Video::setInstance(Video* inst)\r
+{\r
+  instance=inst;\r
+}*/\r
+\r
+/*\r
+hmsf Video::framesToHMSF(ULONG frames, double fps)\r
+{\r
+  hmsf ret;\r
+  / * from vdr *\r
+  double Seconds;\r
+  ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);\r
+  int s = int(Seconds);\r
+  ret.seconds=s;\r
+  ret.minutes = s / 60 % 60;\r
+  ret.hours = s / 3600;\r
+\r
+/ *  if (format == NTSC)\r
+  {\r
+    ret.hours = frames / 108000;\r
+    frames %= 108000;\r
+    ret.minutes = frames / 1800;\r
+    frames %= 1800;\r
+    ret.seconds = frames / 30;\r
+    ret.frames = frames % 30;\r
+  }\r
+  else\r
+  {\r
+    ret.hours = frames / 90000;\r
+    frames %= 90000;\r
+    ret.minutes = frames / 1500;\r
+    frames %= 1500;\r
+    ret.seconds = frames / 25;\r
+    ret.frames = frames % 25;\r
+  }* /\r
+  return ret;\r
+}*/\r
+\r
+/*\r
+UINT Video::getFPS()\r
+{\r
+  if (format == NTSC) return 30;\r
+  else return 25;\r
+}\r
+*/\r
diff --git a/video.h b/video.h
index 502a1bafa7d8fb14160b1602eafdc239e96e77c8..e09d0176debed9b50e73ae863a471ddff2cde238 100644 (file)
--- a/video.h
+++ b/video.h
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef VIDEO_H
-#define VIDEO_H
-
-#include <stdio.h>
-#include "defines.h"
-#include "draintarget.h"
-#include "abstractoption.h"
-
-typedef struct _hmsf
-{
-  UINT hours;
-  UINT minutes;
-  UINT seconds;
-  UINT frames;
-} hmsf;
-
-class Video: public DrainTarget, public AbstractOption
-{
-  public:
-    Video();
-    virtual ~Video();
-    static Video* getInstance();
-
-    virtual int init(UCHAR format)=0;
-    virtual int shutdown()=0;
-    virtual int setFormat(UCHAR format)=0;
-    virtual int setConnection(UCHAR connection)=0;
-    virtual int setAspectRatio(UCHAR aspectRatio)=0;   // This one does the pin 8 scart widescreen switching
-    virtual int setMode(UCHAR mode)=0;
-    virtual int setTVsize(UCHAR size)=0;               // Is the TV a widescreen?
-    virtual int setDefaultAspect()=0;
-    virtual int setSource()=0;
-    virtual int setPosition(int x, int y)=0;
-    virtual int sync()=0;
-    virtual int play()=0;
-    virtual int stop()=0;
-    virtual int pause()=0;
-    virtual int unPause()=0;
-    virtual int fastForward()=0;
-    virtual int unFastForward()=0;
-    virtual int reset()=0;
-    virtual int blank()=0;
-    virtual int signalOn()=0;
-    virtual int signalOff()=0;
-    virtual int attachFrameBuffer()=0; // What does this do?
-//    virtual ULONG timecodeToFrameNumber(ULLONG timecode)=0; //Obsolete and not HD compatible
-    virtual ULLONG getCurrentTimestamp()=0;
-    virtual void displayIFrame(const UCHAR* buffer, UINT length)=0;
-
-       virtual bool supportsh264(){return false;};
-       virtual void seth264mode(bool ish264) {h264=ish264;};
-
-    virtual void turnVideoOn(){};
-    virtual void turnVideoOff(){};
-//    virtual ULLONG frameNumberToTimecode(ULONG timecode) { return 0; };//Obsolete and not HD compatible
-
-#ifdef DEV
-    virtual int test() { return 0; }
-    virtual int test2() { return 0; }
-#endif
-
-    int getMode()           { return mode; }
-    UCHAR getFormat()       { return format; }
-    UINT getScreenWidth()   { return screenWidth; }
-    UINT getScreenHeight()  { return screenHeight; }
-    UCHAR getTVsize()       { return tvsize; }
-
-    //hmsf framesToHMSF(ULONG frames,double fps);
-   // UINT getFPS(); //removed
-
-    // Video formats - AV_SET_VID_DISP_FMT
-    const static UCHAR NTSC = 0;
-    const static UCHAR PAL = 1;
-
-    // Video connections - AV_SET_VID_OUTPUT
-    const static UCHAR COMPOSITERGB = 1;
-    const static UCHAR SVIDEO = 2;
-
-    // Video aspect ratios - AV_SET_VID_RATIO
-    const static UCHAR ASPECT4X3 = 0;
-    const static UCHAR ASPECT16X9 = 1;
-
-    // Video modes - AV_SET_VID_MODE
-    const static UCHAR NORMAL = 0;
-    const static UCHAR LETTERBOX = 1;
-/*
-    Actual Source Aspect      Aspect IOCTL       Mode IOCTL       MODE A            MODE B
-
-          4:3                     4:3             NORMAL          fullframe43       fullframe43
-          4:3                     16:9            NORMAL          fullframe43       fullframe43      -- invalid?
-          4:3                     4:3             LETTERBOX       fullframe43       fullframe43
-          4:3                     16:9            LETTERBOX       fullframe43       fullframe43      -- invalid?
-          16:9                    4:3             NORMAL          chop sides        fullframe169
-          16:9                    16:9            NORMAL          chop sides        fullframe169
-          16:9                    4:3             LETTERBOX       letterbox         letterbox
-          16:9                    16:9            LETTERBOX       chop sides        fullframe169
-
-    Conclusions
-
-    1. There are two chip modes - accessible by reopening the fd
-    2. The video chip knows the aspect ratio purely from the incoming MPEG
-    3. MODE A is for 4:3 TVs, MODE B is for 16:9 TVs
-
-    To switch to MODE A, set the aspect ioctl to 4:3 and reopen the FD.
-    To switch to MODE B, set the aspect ioctl to 16:9 and reopen the FD.
-*/
-
-    const static UCHAR UNKNOWN2 = 2;
-    const static UCHAR QUARTER = 3;
-    const static UCHAR EIGHTH = 4;
-    const static UCHAR ZOOM = 5;
-    const static UCHAR UNKNOWN6 = 6;
-
-  protected:
-    static Video* instance;
-    int initted;
-    int fdVideo;
-
-    UCHAR tvsize;
-    UCHAR format;
-    UCHAR connection;
-    UCHAR aspectRatio;
-    UCHAR mode;
-       bool h264;
-
-    UINT screenWidth;
-    UINT screenHeight;
-};
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef VIDEO_H\r
+#define VIDEO_H\r
+\r
+#include <stdio.h>\r
+#include "defines.h"\r
+#include "draintarget.h"\r
+#include "abstractoption.h"\r
+\r
+typedef struct _hmsf\r
+{\r
+  UINT hours;\r
+  UINT minutes;\r
+  UINT seconds;\r
+  UINT frames;\r
+} hmsf;\r
+\r
+class Video: public DrainTarget, public AbstractOption\r
+{\r
+  public:\r
+    Video();\r
+    virtual ~Video();\r
+    static Video* getInstance();\r
+    //static void setInstance(Video*);\r
+\r
+    virtual int init(UCHAR format)=0;\r
+    virtual int shutdown()=0;\r
+    virtual int setFormat(UCHAR format)=0;\r
+    virtual int setConnection(UCHAR connection)=0;\r
+    virtual int setAspectRatio(UCHAR aspectRatio)=0;   // This one does the pin 8 scart widescreen switching\r
+    virtual int setMode(UCHAR mode)=0;\r
+    virtual int setTVsize(UCHAR size)=0;               // Is the TV a widescreen?\r
+    virtual int setDefaultAspect()=0;\r
+    virtual int setSource()=0;\r
+    virtual int setPosition(int x, int y)=0;\r
+    virtual int sync()=0;\r
+    virtual int play()=0;\r
+    virtual int stop()=0;\r
+    virtual int pause()=0;\r
+    virtual int unPause()=0;\r
+    virtual int fastForward()=0;\r
+    virtual int unFastForward()=0;\r
+    virtual int reset()=0;\r
+    virtual int blank()=0;\r
+    virtual int signalOn()=0;\r
+    virtual int signalOff()=0;\r
+    virtual int attachFrameBuffer()=0; // What does this do?\r
+//    virtual ULONG timecodeToFrameNumber(ULLONG timecode)=0; //Obsolete and not HD compatible\r
+    virtual ULLONG getCurrentTimestamp()=0;\r
+    virtual bool displayIFrame(const UCHAR* buffer, UINT length)=0;\r
+    virtual int EnterIframePlayback() {return 1;}; // Must not be implemented\r
+\r
+       virtual bool supportsh264(){return false;};\r
+       virtual void seth264mode(bool ish264) {h264=ish264;};\r
+       virtual int getTeletextBufferFaktor(){return 1;};\r
+\r
+       virtual bool independentAVStartUp() {return true;};\r
+\r
+\r
+       //Tells, if the device allows an independent startup of audio and video\r
+       // this needs internal buffers in device and is possible for windows and mvp\r
+\r
+       virtual bool PTSIFramePlayback() {return false;};\r
+       // Tells, if the iframe playback is realized using a manipulation of the pts of the packets\r
+       //android does it like this...\r
+\r
+       virtual bool blockingDrainTarget() { return false;};\r
+       // if the draintargets blocks, the feed has to be stop when pausing\r
+\r
+\r
+    virtual void turnVideoOn(){};\r
+    virtual void turnVideoOff(){};\r
+//    virtual ULLONG frameNumberToTimecode(ULONG timecode) { return 0; };//Obsolete and not HD compatible\r
+\r
+#ifdef DEV\r
+    virtual int test() { return 0; }\r
+    virtual int test2() { return 0; }\r
+#endif\r
+\r
+    int getMode()           { return mode; }\r
+    UCHAR getFormat()       { return format; }\r
+    UINT getScreenWidth()   { return screenWidth; }\r
+    UINT getScreenHeight()  { return screenHeight; }\r
+    UCHAR getTVsize()       { return tvsize; }\r
+\r
+    //hmsf framesToHMSF(ULONG frames,double fps);\r
+   // UINT getFPS(); //removed\r
+\r
+    // Video formats - AV_SET_VID_DISP_FMT\r
+    const static UCHAR NTSC = 0;\r
+    const static UCHAR PAL = 1;\r
+\r
+    // Video connections - AV_SET_VID_OUTPUT\r
+    const static UCHAR COMPOSITERGB = 1;\r
+    const static UCHAR SVIDEO = 2;\r
+\r
+    // Video aspect ratios - AV_SET_VID_RATIO\r
+    const static UCHAR ASPECT4X3 = 0;\r
+    const static UCHAR ASPECT16X9 = 1;\r
+\r
+    // Video modes - AV_SET_VID_MODE\r
+    const static UCHAR NORMAL = 0;\r
+    const static UCHAR LETTERBOX = 1;\r
+/*\r
+    Actual Source Aspect      Aspect IOCTL       Mode IOCTL       MODE A            MODE B\r
+\r
+          4:3                     4:3             NORMAL          fullframe43       fullframe43\r
+          4:3                     16:9            NORMAL          fullframe43       fullframe43      -- invalid?\r
+          4:3                     4:3             LETTERBOX       fullframe43       fullframe43\r
+          4:3                     16:9            LETTERBOX       fullframe43       fullframe43      -- invalid?\r
+          16:9                    4:3             NORMAL          chop sides        fullframe169\r
+          16:9                    16:9            NORMAL          chop sides        fullframe169\r
+          16:9                    4:3             LETTERBOX       letterbox         letterbox\r
+          16:9                    16:9            LETTERBOX       chop sides        fullframe169\r
+\r
+    Conclusions\r
+\r
+    1. There are two chip modes - accessible by reopening the fd\r
+    2. The video chip knows the aspect ratio purely from the incoming MPEG\r
+    3. MODE A is for 4:3 TVs, MODE B is for 16:9 TVs\r
+\r
+    To switch to MODE A, set the aspect ioctl to 4:3 and reopen the FD.\r
+    To switch to MODE B, set the aspect ioctl to 16:9 and reopen the FD.\r
+*/\r
+\r
+    const static UCHAR UNKNOWN2 = 2;\r
+    const static UCHAR QUARTER = 3;\r
+    const static UCHAR EIGHTH = 4;\r
+    const static UCHAR ZOOM = 5;\r
+    const static UCHAR UNKNOWN6 = 6;\r
+\r
+  protected:\r
+    static Video* instance;\r
+    int initted;\r
+    int fdVideo;\r
+\r
+    UCHAR tvsize;\r
+    UCHAR format;\r
+    UCHAR connection;\r
+    UCHAR aspectRatio;\r
+    UCHAR mode;\r
+       bool h264;\r
+\r
+    UINT screenWidth;\r
+    UINT screenHeight;\r
+};\r
+\r
+#endif\r
index 6e627af1a1b3a43d779f1cba499a8b65dadd7578..1c6313b055c36980e8ff8e516a6afb5c8e86ea60 100644 (file)
-/*
-    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()
-{
-}
-
-void VideoMVP::displayIFrame(const UCHAR* buffer, UINT length)
-{
-  write(fdVideo, buffer, length);
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "videomvp.h"\r
+\r
+// temp\r
+#include "log.h"\r
+\r
+VideoMVP::VideoMVP()\r
+{\r
+  if (instance) return;\r
+}\r
+\r
+VideoMVP::~VideoMVP()\r
+{\r
+  instance = NULL;\r
+}\r
+\r
+int VideoMVP::init(UCHAR tformat)\r
+{\r
+  if (initted) return 0;\r
+  initted = 1;\r
+\r
+  if ((fdVideo = open("/dev/vdec_dev", O_WRONLY)) < 0) return 0;\r
+\r
+  if (!setFormat(tformat))           { shutdown(); return 0; }\r
+  if (!setConnection(COMPOSITERGB))  { shutdown(); return 0; }\r
+  if (!setAspectRatio(ASPECT4X3))    { shutdown(); return 0; }\r
+  if (!setMode(NORMAL))              { shutdown(); return 0; }\r
+  if (!setSource())                  { shutdown(); return 0; }\r
+  if (!attachFrameBuffer())          { shutdown(); return 0; }\r
+\r
+  setTVsize(ASPECT4X3);\r
+\r
+  if (format == PAL) setLetterboxBorder("38");\r
+  else setLetterboxBorder("31");\r
+\r
+  stop();\r
+\r
+\r
+  return 1;\r
+}\r
+\r
+void VideoMVP::setLetterboxBorder(char* border)\r
+{\r
+  FILE* fdlbox = fopen("/proc/lbox_border", "w");\r
+  if (!fdlbox) return;\r
+  fputs(border, fdlbox);\r
+  fclose(fdlbox);\r
+}\r
+\r
+int VideoMVP::setTVsize(UCHAR ttvsize)\r
+{\r
+  tvsize = ttvsize;\r
+\r
+  // Override the aspect ratio usage, temporarily use to set the video chip mode\r
+  if (!setAspectRatio(tvsize))       { shutdown(); return 0; }\r
+  close(fdVideo);\r
+  if ((fdVideo = open("/dev/vdec_dev", O_WRONLY)) < 0) return 0;\r
+  if (!setSource())                  { shutdown(); return 0; }\r
+  if (!attachFrameBuffer())          { shutdown(); return 0; }\r
+\r
+  // Reopening the fd causes the scart aspect line to go back to 4:3\r
+  // Set this again to the same as the tv screen size\r
+  if (!setAspectRatio(tvsize))       { shutdown(); return 0; }\r
+\r
+  // mode == LETTERBOX is invalid if the TV is widescreen\r
+  if (tvsize == ASPECT16X9) setMode(NORMAL);\r
+\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::setDefaultAspect()\r
+{\r
+  return setAspectRatio(tvsize);\r
+}\r
+\r
+int VideoMVP::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+  initted = 0;\r
+  close(fdVideo);\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::checkSCART()\r
+{\r
+  // Returns 3 for SCART Composite out\r
+  // Returns 3 for SCART S-Video out\r
+  // Returns 2 for SCART RGB out\r
+  // Returns 3 for SCART not plugged in\r
+\r
+  // So, as you can have RGB and composite out simultaneously,\r
+  // and it can't detect S-Video, what is the point of this?\r
+\r
+  int scart;\r
+  if (ioctl(fdVideo, AV_CHK_SCART, &scart) != 0) return -10;\r
+\r
+  return scart;\r
+}\r
+\r
+int VideoMVP::setFormat(UCHAR tformat)\r
+{\r
+  if (!initted) return 0;\r
+  if ((tformat != PAL) && (tformat != NTSC)) return 0;\r
+  format = tformat;\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_DISP_FMT, format) != 0) return 0;\r
+\r
+  if (format == NTSC)\r
+  {\r
+    screenWidth = 720;\r
+    screenHeight = 480;\r
+  }\r
+  if (format == PAL)\r
+  {\r
+    screenWidth = 720;\r
+    screenHeight = 576;\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::setConnection(UCHAR tconnection)\r
+{\r
+  if (!initted) return 0;\r
+  if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;\r
+  connection = tconnection;\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_OUTPUT, connection) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::setAspectRatio(UCHAR taspectRatio)\r
+{\r
+  if (!initted) return 0;\r
+  if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;\r
+  aspectRatio = taspectRatio;\r
+\r
+  Log::getInstance()->log("Video", Log::DEBUG, "Setting aspect to %i", aspectRatio);\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_RATIO, aspectRatio) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::setMode(UCHAR tmode)\r
+{\r
+  if (!initted) return 0;\r
+\r
+  if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode\r
+\r
+  if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)\r
+      && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;\r
+  mode = tmode;\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_MODE, mode) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::signalOff()\r
+{\r
+  if (ioctl(fdVideo, AV_SET_VID_DENC, 0) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::signalOn()\r
+{\r
+  if (ioctl(fdVideo, AV_SET_VID_DENC, 1) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::setSource()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  // What does this do...\r
+  if (ioctl(fdVideo, AV_SET_VID_SRC, 1) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::setPosition(int x, int y)\r
+{\r
+  if (!initted) return 0;\r
+\r
+//  vid_pos_regs_t pos_d;\r
+//  pos_d.x = x;\r
+//  pos_d.y = y;\r
+\r
+  vid_pos_regs_t pos_d;\r
+\r
+  memset(&pos_d, 0, sizeof(pos_d));\r
+\r
+  pos_d.dest.y = y;\r
+  pos_d.dest.x = x;\r
+/*\r
+typedef struct {\r
+  int w;\r
+  int h;\r
+  int scale;\r
+  int x1;\r
+  int y;\r
+  int x;\r
+  int y2;\r
+  int x3;\r
+  int y3;\r
+  int x4;\r
+  int y4;\r
+} vid_pos_regs_t;\r
+*/\r
+\r
+/*\r
+  pos_d.w = 100;\r
+  pos_d.h = 30;\r
+  pos_d.scale = 2;\r
+  pos_d.x1 = 0;\r
+  pos_d.y = 100;            // Top left X\r
+  pos_d.x = 50;            // Top left Y\r
+  pos_d.y2 = 30;\r
+  pos_d.x3 = 60;\r
+  pos_d.y3 = 90;\r
+  pos_d.x4 = 120;\r
+  pos_d.y4 = 150;\r
+*/\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_POSITION, &pos_d) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::sync()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_SYNC, 2) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::play()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::stop()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_STOP, 0) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::reset()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::pause()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_PAUSE, 0) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::unPause() // FIXME get rid - same as play!!\r
+{\r
+  if (!initted) return 0;\r
+  if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::fastForward()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_FFWD, 1) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::unFastForward()\r
+{\r
+  if (!initted) return 0;\r
+\r
+//  if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0; // don't need this.\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::attachFrameBuffer()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+int VideoMVP::blank(void)\r
+{\r
+  if (ioctl(fdVideo, AV_SET_VID_FB, 1) != 0) return 0;\r
+  if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0;\r
+  return 1;\r
+}\r
+\r
+ULLONG VideoMVP::getCurrentTimestamp()\r
+{\r
+  sync_data_t timestamps;\r
+  if (ioctl(fdVideo, AV_GET_VID_TIMESTAMPS, &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
index fc086e6962eeed8a5a5b94a63503263f068bd378..9184bc3910e5b502fee81e05e7d80b666358126b 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-// Thanks to Jon Gettler and BtB of the MVPMC project for all the hardware information
-
-
-#ifndef VIDEOMVP_H
-#define VIDEOMVP_H
-
-// FIXME - check why so many things include unistd
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <string.h>
-
-#include <stdint.h>
-
-#include "defines.h"
-#include "video.h"
-
-typedef struct
-{
-  int nleft;
-  int state;
-} vid_state_regs_t;
-
-typedef struct
-{
-  uint64_t stc;
-  uint64_t pts;
-} sync_data_t;
-
-typedef struct
-{
-  int y;
-  int x;
-  int w;
-  int h;
-} vid_rect_t;
-
-typedef struct
-{
-  vid_rect_t src;
-  vid_rect_t dest;
-} vid_pos_regs_t;
-
-struct vid_regs
-{
-  UCHAR dummy[44];
-};
-
-#define AV_SET_VID_STOP         _IOW('v', 21, int)
-#define AV_SET_VID_PLAY         _IOW('v', 22, int)
-#define AV_SET_VID_FREEZE       _IOW('v', 23, int)
-#define AV_SET_VID_RESUME       _IOW('v', 24, int)
-#define AV_SET_VID_SRC          _IOW('v', 25, int)
-#define AV_SET_VID_FB           _IOW('v', 26, int)
-#define AV_GET_VID_STATE        _IOR('v', 27, vid_state_regs_t*)
-#define AV_SET_VID_PAUSE        _IOW('v', 28, int)
-#define AV_SET_VID_FFWD         _IOW('v', 29, int)
-#define AV_SET_VID_SLOMO        _IOW('v', 30, int)
-#define AV_SET_VID_BLANK        _IOW('v', 32, int)
-#define AV_SET_VID_POSITION     _IOW('v', 36, vid_pos_regs_t*)
-#define AV_SET_VID_SCALE_ON     _IOW('v', 37, int)
-#define AV_SET_VID_SCALE_OFF    _IOW('v', 38, int)
-#define AV_GET_VID_TIMESTAMPS   _IOR('v', 39, sync_data_t*)
-#define AV_SET_VID_STC          _IOW('v', 40, uint64_t*)
-#define AV_SET_VID_RATIO        _IOW('v', 41, int)
-#define AV_SET_VID_SYNC         _IOW('v', 42, int)
-#define AV_SET_VID_DISABLE_SYNC _IOW('v', 43, int)
-#define AV_SET_VID_DISP_FMT     _IOW('v', 45, int)
-#define AV_SET_VID_RESET        _IOW('v', 51, int)
-#define AV_SET_VID_OUTPUT       _IOW('v', 57, int)
-#define AV_SET_VID_MODE         _IOW('v', 58, int)
-#define AV_GET_VID_REGS         _IOR('v', 61, struct vid_regs*)
-#define AV_SET_VID_COLORBAR     _IOW('v', 62, int)
-#define AV_SET_VID_DENC         _IOW('v', 63, int)
-#define AV_CHK_SCART            _IOW('v', 64, int)
-
-#define WRITE_LENGTH (32*1024) // Consume up to 32K at a time from Stream
-#define WRITE_PACKETS 16       // But no more than 16 packets
-
-class VideoMVP : public Video
-{
-  public:
-    VideoMVP();
-    ~VideoMVP();
-
-    int init(UCHAR format);
-    int shutdown();
-
-    int setFormat(UCHAR format);
-    int setConnection(UCHAR connection);
-    int setAspectRatio(UCHAR aspectRatio);   // This one does the pin 8 scart widescreen switching
-    int setMode(UCHAR mode);
-    int setTVsize(UCHAR size);               // Is the TV a widescreen?
-    int setDefaultAspect();
-    int setSource();
-    int setPosition(int x, int y);
-    int sync();
-    int play();
-    int stop();
-    int pause();
-    int unPause();
-    int fastForward();
-    int unFastForward();
-    int reset();
-    int blank();
-    int signalOn();
-    int signalOff();
-    int attachFrameBuffer(); // What does this do?
-    ULONG timecodeToFrameNumber(ULLONG timecode);
-    ULLONG getCurrentTimestamp();
-    void displayIFrame(const UCHAR* buffer, UINT length);
-
-    // Writing Data to Videodevice
-    virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);
-    virtual UINT DeliverMediaSample( UCHAR* buffer, UINT* samplepos);
-    virtual long long SetStartOffset(long long curreftime, bool *rsync)
-    { return 0; };
-    virtual void ResetTimeOffsets();
-
-#ifdef DEV
-    int test();
-    int test2();
-#endif
-
-  private:
-    int checkSCART();
-    void setLetterboxBorder(char* border);
-
-    UINT deliver_start, deliver_length, deliver_count;
-    UINT mediapacket_len[WRITE_PACKETS];
-};
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+// Thanks to Jon Gettler and BtB of the MVPMC project for all the hardware information\r
+\r
+\r
+#ifndef VIDEOMVP_H\r
+#define VIDEOMVP_H\r
+\r
+// FIXME - check why so many things include unistd\r
+\r
+#include <stdio.h>\r
+#include <unistd.h>\r
+#include <fcntl.h>\r
+#include <sys/ioctl.h>\r
+#include <string.h>\r
+\r
+#include <stdint.h>\r
+\r
+#include "defines.h"\r
+#include "video.h"\r
+\r
+typedef struct\r
+{\r
+  int nleft;\r
+  int state;\r
+} vid_state_regs_t;\r
+\r
+typedef struct\r
+{\r
+  uint64_t stc;\r
+  uint64_t pts;\r
+} sync_data_t;\r
+\r
+typedef struct\r
+{\r
+  int y;\r
+  int x;\r
+  int w;\r
+  int h;\r
+} vid_rect_t;\r
+\r
+typedef struct\r
+{\r
+  vid_rect_t src;\r
+  vid_rect_t dest;\r
+} vid_pos_regs_t;\r
+\r
+struct vid_regs\r
+{\r
+  UCHAR dummy[44];\r
+};\r
+\r
+#define AV_SET_VID_STOP         _IOW('v', 21, int)\r
+#define AV_SET_VID_PLAY         _IOW('v', 22, int)\r
+#define AV_SET_VID_FREEZE       _IOW('v', 23, int)\r
+#define AV_SET_VID_RESUME       _IOW('v', 24, int)\r
+#define AV_SET_VID_SRC          _IOW('v', 25, int)\r
+#define AV_SET_VID_FB           _IOW('v', 26, int)\r
+#define AV_GET_VID_STATE        _IOR('v', 27, vid_state_regs_t*)\r
+#define AV_SET_VID_PAUSE        _IOW('v', 28, int)\r
+#define AV_SET_VID_FFWD         _IOW('v', 29, int)\r
+#define AV_SET_VID_SLOMO        _IOW('v', 30, int)\r
+#define AV_SET_VID_BLANK        _IOW('v', 32, int)\r
+#define AV_SET_VID_POSITION     _IOW('v', 36, vid_pos_regs_t*)\r
+#define AV_SET_VID_SCALE_ON     _IOW('v', 37, int)\r
+#define AV_SET_VID_SCALE_OFF    _IOW('v', 38, int)\r
+#define AV_GET_VID_TIMESTAMPS   _IOR('v', 39, sync_data_t*)\r
+#define AV_SET_VID_STC          _IOW('v', 40, uint64_t*)\r
+#define AV_SET_VID_RATIO        _IOW('v', 41, int)\r
+#define AV_SET_VID_SYNC         _IOW('v', 42, int)\r
+#define AV_SET_VID_DISABLE_SYNC _IOW('v', 43, int)\r
+#define AV_SET_VID_DISP_FMT     _IOW('v', 45, int)\r
+#define AV_SET_VID_RESET        _IOW('v', 51, int)\r
+#define AV_SET_VID_OUTPUT       _IOW('v', 57, int)\r
+#define AV_SET_VID_MODE         _IOW('v', 58, int)\r
+#define AV_GET_VID_REGS         _IOR('v', 61, struct vid_regs*)\r
+#define AV_SET_VID_COLORBAR     _IOW('v', 62, int)\r
+#define AV_SET_VID_DENC         _IOW('v', 63, int)\r
+#define AV_CHK_SCART            _IOW('v', 64, int)\r
+\r
+#define WRITE_LENGTH (32*1024) // Consume up to 32K at a time from Stream\r
+#define WRITE_PACKETS 16       // But no more than 16 packets\r
+\r
+class VideoMVP : public Video\r
+{\r
+  public:\r
+    VideoMVP();\r
+    ~VideoMVP();\r
+\r
+    int init(UCHAR format);\r
+    int shutdown();\r
+\r
+    int setFormat(UCHAR format);\r
+    int setConnection(UCHAR connection);\r
+    int setAspectRatio(UCHAR aspectRatio);   // This one does the pin 8 scart widescreen switching\r
+    int setMode(UCHAR mode);\r
+    int setTVsize(UCHAR size);               // Is the TV a widescreen?\r
+    int setDefaultAspect();\r
+    int setSource();\r
+    int setPosition(int x, int y);\r
+    int sync();\r
+    int play();\r
+    int stop();\r
+    int pause();\r
+    int unPause();\r
+    int fastForward();\r
+    int unFastForward();\r
+    int reset();\r
+    int blank();\r
+    int signalOn();\r
+    int signalOff();\r
+    int attachFrameBuffer(); // What does this do?\r
+    ULONG timecodeToFrameNumber(ULLONG timecode);\r
+    ULLONG getCurrentTimestamp();\r
+    bool displayIFrame(const UCHAR* buffer, UINT length);\r
+\r
+    // Writing Data to Videodevice\r
+    virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);\r
+    virtual UINT DeliverMediaSample( UCHAR* buffer, UINT* samplepos);\r
+    virtual long long SetStartOffset(long long curreftime, bool *rsync)\r
+    { return 0; };\r
+    virtual void ResetTimeOffsets();\r
+\r
+#ifdef DEV\r
+    int test();\r
+    int test2();\r
+#endif\r
+\r
+  private:\r
+    int checkSCART();\r
+    void setLetterboxBorder(char* border);\r
+\r
+    UINT deliver_start, deliver_length, deliver_count;\r
+    UINT mediapacket_len[WRITE_PACKETS];\r
+};\r
+\r
+#endif\r
index b62861c7d55124a6c34473faf010e4a926c1a885..8979151bbe6a1bdb0364b2ace98a78a8bebf8c80 100644 (file)
-/*
-    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);
-}
-
-void VideoWin::displayIFrame(const UCHAR* buffer, UINT length)
-{
-       if (!iframemode) EnterIframePlayback();
-       if (!isdsinited()) return ;
-       
-#ifdef DO_VIDEO
-  IMediaSample* ms=NULL;
-  REFERENCE_TIME reftime1=0;
-  REFERENCE_TIME reftime2=0;
-  if (!videoon) return;
-  if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
-    MILLISLEEP(10);
-    return ;
-  }
-  BYTE *ms_buf;
-  DWORD ms_length;
-  ms->GetPointer(&ms_buf);
-  ms_length=ms->GetSize();
-  
-  /*First Check, if we have an video sample*/
-  DWORD read_pos = 0, write_pos = 0;
-  DWORD pattern, packet_length;
-  DWORD headerstrip=0;
-  bool first=true;
-  if (length < 4) return ;
-  //Now we strip the pes header
-  pattern = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]);
-  while (read_pos + 7 <= length)
-  {
-    pattern = ((pattern << 8) & 0xFFFFFFFF) | buffer[read_pos+3];
-    if (pattern < 0x000001E0 || pattern > 0x000001EF) {
-      read_pos++;
-      continue;
-    }
-    else
-    {
-         headerstrip=buffer[read_pos+8]+9/*is this right*/;
-      packet_length = ((buffer[read_pos+4] << 8) | (buffer[read_pos+5])) + 6;
-      if (read_pos + packet_length > length)
-        read_pos = length;
-      else
-      {
-                 if ( (headerstrip < packet_length) &&
-              (write_pos+packet_length-headerstrip)>ms_length) {
-                         if (first) {
-                  ms->SetSyncPoint(TRUE);
-                  ms->SetDiscontinuity(TRUE);
-                  first=false;
-              } else ms->SetSyncPoint(FALSE);
-                         ms->SetTime(NULL,NULL);
-                         ms->SetMediaTime(NULL, NULL);
-                         ms->SetActualDataLength(write_pos);
-                         DeliverVideoMediaSample();
-
-                         if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
-                               MILLISLEEP(10);
-                               return ;
-                         }
-                         write_pos=0;
-                         ms_length=ms->GetSize();
-                         ms->GetPointer(&ms_buf);
-                 }
-                 if (packet_length>headerstrip) {
-                       memcpy(ms_buf+write_pos, buffer+read_pos+headerstrip, packet_length-headerstrip);
-                       write_pos += packet_length-headerstrip;
-                 }
-                 read_pos += packet_length;
-                 
-                 pattern = (buffer[read_pos] << 16) | (buffer[read_pos+1] << 8)
-                                        | (buffer[read_pos+2]);
-      }
-    }
-  }
-  if (first) {ms->SetSyncPoint(TRUE);
-  ms->SetDiscontinuity(TRUE);
-  first=false;} 
-  else ms->SetSyncPoint(FALSE);
-  ms->SetTime(NULL,NULL);
-  ms->SetMediaTime(NULL, NULL);
-  ms->SetActualDataLength(write_pos);
-  DeliverVideoMediaSample();
-
-#else
-
-    //   *samplepos+=packet.length;
-      MILLISLEEP(0); //yet not implemented//bad idea
-       return ;
-#endif
-}
-
-bool VideoWin::supportsAc3(){
-    if (sourcefilter != NULL) {
-        return sourcefilter->supportsAc3();
-    } else {
-        return false;
-    }
-}
-
-bool VideoWin::supportsh264()
-{
-       if (videoH264filterlist.size()>0) return true;
-       else return false;
-}
-
-
-bool VideoWin::changeAType(int type,IMediaSample* ms){
-    if (sourcefilter!= NULL) {
-        lastaudiomode=type;
-        return sourcefilter->changeAType(type,ms);
-    }
-    else 
-    {
-        return false;
-    }
-}
-
-#ifdef DEV
-int VideoWin::test()
-{
-  return 0;
-}
-
-int VideoWin::test2()
-{
-  return 0;
-}
-#endif
-
-
-
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+#include "videowin.h"\r
+#include "log.h"\r
+#include "dssourcefilter.h"\r
+#include "dsallocator.h"\r
+#include "vdr.h"\r
+#include "osdwin.h"\r
+#include "audiowin.h"\r
+#include "wwinvideofilter.h"\r
+#include "wwinvideoh264filter.h"\r
+#include "wtabbar.h"\r
+#include "woptionpane.h"\r
+#include "i18n.h"\r
+#include "demuxer.h"\r
+\r
+#include <Mfapi.h>\r
+#include <mferror.h>\r
+\r
+void AdjustWindow();\r
+\r
+\r
+\r
+VideoWin::VideoWin()\r
+{\r
+  dsinited=false;\r
+  dsgraphbuilder=NULL;\r
+  dsmediacontrol=NULL;\r
+  dsrenderer=NULL;\r
+  dsrefclock=NULL;\r
+  dsmediafilter=NULL;\r
+  dsbasicaudio=NULL;\r
+  sourcefilter=NULL;\r
+  allocatorvmr=NULL;\r
+  cr_time=0;\r
+  lastaudiomode=MPTYPE_MPEG_AUDIO;\r
+  //lastaudiomode=MPTYPE_AC3;\r
+  dsvmrsurfnotify=NULL;\r
+  filtermutex=CreateMutex(NULL,FALSE,NULL);\r
+  offsetnotset=true;\r
+  offsetvideonotset=true;\r
+  offsetaudionotset=true;\r
+  startoffset=0;\r
+  lastrefaudiotime=0;\r
+  lastrefvideotime=0;\r
+  lastreftimeRT=0;\r
+  lastreftimePTS=0;\r
+  firstsynched=false;\r
+  cur_audio_media_sample=NULL;\r
+  cur_video_media_sample=NULL;\r
+  videoon=true;\r
+  audioon=true;\r
+  audiovolume=0;\r
+  pseudotvsize=0;\r
+  videoposx=0;\r
+  videoposy=0;\r
+  aud_type=Audio::MPEG2_PES;\r
+  iframemode=false;//We are not in Iframe mode at begining\r
+  vmrdeinterlacing=2;//Best\r
+  videofilterselected=-1;\r
+  videoH264filterselected=-1;\r
+  OSVERSIONINFO verinfo;\r
+  verinfo.dwOSVersionInfoSize=sizeof(verinfo);\r
+  GetVersionEx(&verinfo);\r
+\r
+  if (verinfo.dwMajorVersion>=6) {\r
+  currentpresenter=EVR;\r
+  } else {\r
+      currentpresenter=VMR9;\r
+  }\r
+  videoH264dtsfix=false;\r
+  videompeg2dtsfix=false;\r
+\r
+\r
+\r
+\r
+}\r
+\r
+VideoWin::~VideoWin()\r
+{\r
+  CleanupDS();\r
+  CloseHandle(filtermutex);\r
+  unsigned int i;\r
+  for (i=0;i<videofilterlist.size();i++)\r
+  {\r
+   if (videofilterlist[i].displayname) delete [] videofilterlist[i].displayname;\r
+   if (videofilterlist[i].friendlyname) delete [] videofilterlist[i].friendlyname;\r
+  }\r
+  videofilterlist.clear();\r
+\r
+  for (i=0;i<videoH264filterlist.size();i++)\r
+  {\r
+   if (videoH264filterlist[i].displayname) delete [] videoH264filterlist[i].displayname;\r
+   if (videoH264filterlist[i].friendlyname) delete [] videoH264filterlist[i].friendlyname;\r
+  }\r
+  videoH264filterlist.clear();\r
+\r
+\r
+\r
+\r
+  instance = NULL;\r
+}\r
+\r
+int VideoWin::init(UCHAR tformat)\r
+{\r
+  if (initted) return 0;\r
+\r
+  initted = 1;\r
+  tvsize=Video::ASPECT16X9; //Internally Vomp should think we are a 16:9 TV\r
+  videoposx=0;\r
+  videoposy=0;\r
+  initFilterDatabase();\r
+  initH264FilterDatabase();\r
+\r
+  if (!setFormat(tformat)){ shutdown(); return 0; }\r
+  return 1;\r
+}\r
+\r
+\r
+\r
+int VideoWin::setTVsize(UCHAR ttvsize)\r
+{\r
+  pseudotvsize=ttvsize;\r
+  return 1;\r
+}\r
+\r
+int VideoWin::setDefaultAspect()\r
+{\r
+  return setAspectRatio(Video::ASPECT4X3);\r
+}\r
+\r
+int VideoWin::shutdown()\r
+{\r
+  if (!initted) return 0;\r
+  initted = 0;\r
+  return 1;\r
+}\r
+\r
+int VideoWin::setFormat(UCHAR tformat)\r
+{\r
+  if (!initted) return 0;\r
+  if ((tformat != PAL) && (tformat != NTSC)) return 0;\r
+  format = tformat;\r
+  if (format == NTSC)\r
+  {\r
+    screenWidth = 720;\r
+    screenHeight = 480;\r
+  }\r
+  if (format == PAL)\r
+  {\r
+    screenWidth = 720;\r
+    screenHeight = 576;\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+int VideoWin::setConnection(UCHAR tconnection)\r
+{\r
+  if (!initted) return 0;\r
+  if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;\r
+  connection = tconnection;\r
+\r
+  return 1;\r
+}\r
+\r
+int VideoWin::setAspectRatio(UCHAR taspectRatio)\r
+{\r
+  if (!initted) return 0;\r
+  if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;\r
+  aspectRatio = taspectRatio;\r
+  AdjustWindow();\r
+  return 1;\r
+}\r
+\r
+int VideoWin::setMode(UCHAR tmode)\r
+{\r
+  if (!initted) return 0;\r
+\r
+  //if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode\r
+\r
+  if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)\r
+      && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;\r
+  mode = tmode;\r
+  videoposx=0;\r
+  videoposy=0;\r
+  AdjustWindow();\r
+\r
+  return 1;\r
+}\r
+\r
+int VideoWin::signalOff()\r
+{\r
+  return 1;\r
+}\r
+\r
+int VideoWin::signalOn()\r
+{\r
+  return 1;\r
+}\r
+\r
+int VideoWin::setSource()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  return 1;\r
+}\r
+\r
+int VideoWin::setPosition(int x, int y)\r
+{\r
+  if (!initted) return 0;\r
+  if (mode==QUARTER || mode==EIGHTH) {\r
+  videoposx=x;\r
+  videoposy=y;\r
+  }\r
+  return 1;\r
+}\r
+\r
+int VideoWin::sync()\r
+{\r
+  if (!initted) return 0;\r
+\r
+  return 1;\r
+}\r
+void VideoWin::initFilterDatabase()\r
+{\r
+    /* This method should determine all availiable DirectShow Filters */\r
+    IFilterMapper2* filtmap=NULL;\r
+    HRESULT result;\r
+    result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,\r
+                IID_IFilterMapper2,(void**)&filtmap);\r
+    if (result != S_OK)\r
+    {\r
+        Log::getInstance()->log("VideoWin", Log::ERR , "Unable to create FilterMapper!");\r
+        return;\r
+    }\r
+    /* Wishlist, what Mediatypes do we want */\r
+    GUID mtypesin[]={MEDIATYPE_Video,MEDIASUBTYPE_MPEG2_VIDEO};\r
+    IEnumMoniker *myenum;\r
+    result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,\r
+                    TRUE,1,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);\r
+    if (result != S_OK)\r
+    {\r
+        filtmap->Release();\r
+        Log::getInstance()->log("VideoWin", Log::ERR , "Unable to enum Filters!");\r
+        return;\r
+    }\r
+    ULONG gethowmany;\r
+    IMoniker * moni;\r
+    while(myenum->Next(1,&moni,&gethowmany)==S_OK)\r
+    {\r
+        VideoFilterDesc desc;\r
+        ZeroMemory(&desc,sizeof(desc));\r
+   \r
+        LPOLESTR string;\r
+        moni->GetDisplayName(0,0,&string);\r
+        desc.displayname=new char[wcslen(string)+1];\r
+        wcstombs(desc.displayname,string,wcslen(string)+1);\r
+        CoTaskMemFree(string);\r
+        IPropertyBag *bag;\r
+        if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)\r
+        {\r
+            VARIANT vari;\r
+            VariantInit(&vari);\r
+            result = bag->Read(L"FriendlyName",&vari,NULL);\r
+            if (result == S_OK)\r
+            {\r
+                desc.friendlyname=new char[wcslen(vari.bstrVal)+1];\r
+                wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);\r
+            }\r
+            VariantClear(&vari);\r
+            bag->Release();\r
+\r
+        }\r
+        \r
+       \r
+        videofilterlist.push_back(desc);\r
+       \r
+\r
+        \r
+        moni->Release();\r
+       // bctx->Release();\r
+    }\r
+    int i;\r
+    videofilterselected=-1;\r
+    \r
+    \r
+  \r
+    myenum->Release();\r
+\r
+\r
+\r
+    filtmap->Release();\r
+}\r
+\r
+void VideoWin::initH264FilterDatabase()\r
+{\r
+    /* This method should determine all availiable DirectShow Filters */\r
+    IFilterMapper2* filtmap=NULL;\r
+    HRESULT result;\r
+    result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,\r
+                IID_IFilterMapper2,(void**)&filtmap);\r
+    if (result != S_OK)\r
+    {\r
+        Log::getInstance()->log("VideoWin", Log::ERR , "Unable to create FilterMapper!");\r
+        return;\r
+    }\r
+    /* Wishlist, what Mediatypes do we want */\r
+    GUID mtypesin[]={MEDIATYPE_Video,MEDIASUBTYPE_H264};\r
+    IEnumMoniker *myenum;\r
+    result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,\r
+                    TRUE,1,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);\r
+    if (result != S_OK)\r
+    {\r
+        filtmap->Release();\r
+        Log::getInstance()->log("VideoWin", Log::ERR , "Unable to enum Filters!");\r
+        return;\r
+    }\r
+    ULONG gethowmany;\r
+    IMoniker * moni;\r
+    while(myenum->Next(1,&moni,&gethowmany)==S_OK)\r
+    {\r
+        VideoFilterDesc desc;\r
+        ZeroMemory(&desc,sizeof(desc));\r
+   \r
+        LPOLESTR string;\r
+        moni->GetDisplayName(0,0,&string);\r
+        desc.displayname=new char[wcslen(string)+1];\r
+        wcstombs(desc.displayname,string,wcslen(string)+1);\r
+        CoTaskMemFree(string);\r
+        IPropertyBag *bag;\r
+        if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)\r
+        {\r
+            VARIANT vari;\r
+            VariantInit(&vari);\r
+            result = bag->Read(L"FriendlyName",&vari,NULL);\r
+            if (result == S_OK)\r
+            {\r
+                desc.friendlyname=new char[wcslen(vari.bstrVal)+1];\r
+                wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);\r
+            }\r
+            VariantClear(&vari);\r
+            bag->Release();\r
+\r
+        }\r
+        \r
+       \r
+        videoH264filterlist.push_back(desc);\r
+       \r
+\r
+        \r
+        moni->Release();\r
+       // bctx->Release();\r
+    }\r
+    int i;\r
+    videoH264filterselected=-1;\r
+    \r
+    \r
+  \r
+    myenum->Release();\r
+\r
+\r
+\r
+    filtmap->Release();\r
+}\r
+\r
+bool VideoWin::loadOptionsfromServer(VDR* vdr)\r
+{\r
+    char *name=vdr->configLoad("DirectShow","VideoFilter");\r
+    \r
+    if (name != NULL) \r
+    {\r
+        for (int i = 0;i <videofilterlist.size();i++)\r
+        {\r
+            if (strcmp(name,videofilterlist[i].displayname)==0)\r
+            {\r
+                videofilterselected = i;\r
+                break;\r
+            }\r
+        }\r
+   }\r
+   name=vdr->configLoad("DirectShow","VideoH264Filter");\r
+    \r
+    if (name != NULL) \r
+    {\r
+        for (int i = 0;i <videoH264filterlist.size();i++)\r
+        {\r
+            if (strcmp(name,videoH264filterlist[i].displayname)==0)\r
+            {\r
+                videoH264filterselected = i;\r
+                break;\r
+            }\r
+        }\r
+   }\r
+   name=vdr->configLoad("DirectShow","VMR9DeinterlacingMode");\r
+   if (name != NULL) \r
+   {\r
+       if (STRCASECMP(name,"NoMix")==0)  {\r
+           vmrdeinterlacing=0;\r
+       } else if (STRCASECMP(name,"None")==0)  {\r
+           vmrdeinterlacing=1;\r
+       } else if (STRCASECMP(name,"Best")==0)  {\r
+           vmrdeinterlacing=2;\r
+       } else if (STRCASECMP(name,"Bob")==0)  {\r
+           vmrdeinterlacing=3;\r
+       } else if (STRCASECMP(name,"Weave")==0)  {\r
+           vmrdeinterlacing=4;\r
+       }\r
+   }\r
+\r
+   name=vdr->configLoad("DirectShow", "VideoPresenter");\r
+   if (name!=NULL) {\r
+       if (STRCASECMP(name,"VMR9")==0) {\r
+           currentpresenter=VMR9;\r
+          } else if (STRCASECMP(name,"EVR")==0) {\r
+           currentpresenter=EVR;\r
+       } \r
+   }\r
+   if (!((OsdWin*)Osd::getInstance())->IsEvrSupported()) {\r
+           currentpresenter=VMR9;\r
+   }\r
+\r
+   name=vdr->configLoad("DirectShow","videoH264dtsfix");\r
+   if (name!=NULL) {\r
+       if (STRCASECMP(name,"YES")==0) {\r
+           videoH264dtsfix=true;\r
+       } else {\r
+           videoH264dtsfix=false;\r
+       }\r
+   }\r
+   name=vdr->configLoad("DirectShow","videompeg2dtsfix");\r
+   if (name!=NULL) {\r
+       if (STRCASECMP(name,"YES")==0) {\r
+           videompeg2dtsfix=true;\r
+       } else {\r
+           videompeg2dtsfix=false;\r
+       }\r
+   }\r
+\r
+   name=vdr->configLoad("DirectGraphics", "StretchFiltering");\r
+   if (name!=NULL) {\r
+       if (STRCASECMP(name,"None")==0) {\r
+           ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_NONE);\r
+       } else if (STRCASECMP(name,"Point")==0) {\r
+           ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_POINT);\r
+       } else if (STRCASECMP(name,"Linear")==0) {\r
+           ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_LINEAR);\r
+       }\r
+   }\r
+\r
+   \r
+\r
+\r
+   return true;\r
+\r
+}\r
+\r
+bool VideoWin::handleOptionChanges(Option* option)\r
+{\r
+    if( Video::handleOptionChanges(option)) return true;\r
+    switch(option->id) {\r
+        case 1: {\r
+            if (STRCASECMP(option->options[option->userSetChoice],"None")==0) {\r
+                ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_NONE);\r
+            } else if (STRCASECMP(option->options[option->userSetChoice],"Point")==0) {\r
+                ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_POINT);\r
+            } else if (STRCASECMP(option->options[option->userSetChoice],"Linear")==0) {\r
+                ((OsdWin*)Osd::getInstance())->setFilterType(D3DTEXF_LINEAR);\r
+            }\r
+   return true;\r
+                } break;\r
+        case 2: {\r
+            if (STRCASECMP(option->options[option->userSetChoice],"NoMix")==0)  {\r
+                vmrdeinterlacing=0;\r
+            } else if (STRCASECMP(option->options[option->userSetChoice],"None")==0)  {\r
+                vmrdeinterlacing=1;\r
+            } else if (STRCASECMP(option->options[option->userSetChoice],"Best")==0)  {\r
+                vmrdeinterlacing=2;\r
+            } else if (STRCASECMP(option->options[option->userSetChoice],"Bob")==0)  {\r
+                vmrdeinterlacing=3;\r
+            } else if (STRCASECMP(option->options[option->userSetChoice],"Weave")==0)  {\r
+                vmrdeinterlacing=4;\r
+            } \r
+                }break;\r
+                case 3: {\r
+            if (STRCASECMP(option->options[option->userSetChoice],"VMR9")==0)  {\r
+                currentpresenter=VMR9;\r
+            } else if (STRCASECMP(option->options[option->userSetChoice],"EVR")==0)  {\r
+                currentpresenter=EVR;\r
+            } \r
+                }break;\r
+         case 4: {\r
+             if (STRCASECMP(option->options[option->userSetChoice],"Yes")==0) {\r
+                videoH264dtsfix=true;\r
+             } else {\r
+                 videoH264dtsfix=false;\r
+             }\r
+                 }break;\r
+         case 5: {\r
+             if (STRCASECMP(option->options[option->userSetChoice],"Yes")==0) {\r
+                videompeg2dtsfix=true;\r
+             } else {\r
+                 videompeg2dtsfix=false;\r
+             }\r
+                 }break;\r
+    };\r
+    return false;\r
+\r
+}\r
+\r
+bool VideoWin::saveOptionstoServer()\r
+{\r
+    if (videofilterselected!=-1) {\r
+        VDR::getInstance()->configSave("DirectShow",\r
+            "VideoFilter",videofilterlist[videofilterselected].displayname);\r
+                VDR::getInstance()->configSave("DirectShow",\r
+            "VideoH264Filter",videoH264filterlist[videoH264filterselected].displayname);\r
+    }\r
+    return true;\r
+}\r
+\r
+/*Option(UINT id, const char* displayText, const char* configSection, const char* configKey, UINT optionType, \r
+           UINT numChoices, UINT defaultChoice, UINT startInt,\r
+           const char * const * options, const char * const * optionkeys = NULL, AbstractOption* handler=NULL);*/\r
+\r
+bool VideoWin::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane)\r
+{\r
+    if (!Video::addOptionsToPanes(panenumber,options,pane)) return false;\r
+\r
+\r
+    Option* option;\r
+    if (panenumber == 2) \r
+    {\r
+        DWORD scalingcaps=((OsdWin*)Osd::getInstance())->getFilterCaps();\r
+        char **scalingopts=new char *[3];\r
+        int i=0;\r
+        scalingopts[i]=new char[strlen("None")+1];\r
+        strcpy(scalingopts[i],"None");\r
+        i++;\r
+        if ((scalingcaps & D3DPTFILTERCAPS_MINFPOINT)!=0 \r
+            && (scalingcaps & D3DPTFILTERCAPS_MAGFPOINT)!=0) {\r
+            scalingopts[i]=new char[strlen("Point")+1];\r
+            strcpy(scalingopts[i],"Point");\r
+            i++;\r
+        }\r
+        if ((scalingcaps & D3DPTFILTERCAPS_MINFLINEAR)!=0 \r
+            && (scalingcaps & D3DPTFILTERCAPS_MAGFLINEAR)!=0) {\r
+            scalingopts[i]=new char[strlen("Linear")+1];\r
+            strcpy(scalingopts[i],"Linear");\r
+            i++;\r
+        }\r
+        option = new Option(1 ,tr("Video Stretching Filter"), "DirectGraphics", "StretchFiltering", Option::TYPE_TEXT, i, (i-1), 0, scalingopts,NULL,true, this);\r
+        options->push_back(option);\r
+        pane->addOptionLine(option);\r
+        static const char* deintopts[]={"NoMix","None","Best","Bob","Weave"};\r
+        option = new Option(2,tr("VMR9 Deinterlacing Mode"), "DirectShow","VMR9DeinterlacingMode",Option::TYPE_TEXT,5,2,0,deintopts,NULL,false,this);\r
+        options->push_back(option);\r
+        pane->addOptionLine(option);\r
+\r
+               if (((OsdWin*)Osd::getInstance())->IsEvrSupported()) \r
+               {\r
+                       static const char* presenteropts[]={"EVR","VMR9"};\r
+            option = new Option(3,tr("Video Presenter Filter"),"DirectShow", "VideoPresenter",Option::TYPE_TEXT,2,\r
+                (currentpresenter==EVR)?0:1,0,presenteropts,NULL,false,this);\r
+               } else {\r
+                       static const char* presenteropts[]={"VMR9"};\r
+                       option = new Option(3,tr("Video Presenter Filter"),"DirectShow", "VideoPresenter",Option::TYPE_TEXT,1,0,0,presenteropts,NULL,false,this);\r
+               }\r
+               options->push_back(option);\r
+        pane->addOptionLine(option);\r
+\r
+        static const char* yesnoopts[]={"Yes","No"};\r
+        option = new Option(4,tr("Video H264 fix dts time"), "DirectShow","videoH264dtsfix",Option::TYPE_TEXT,2,1,0,yesnoopts,NULL,false,this);\r
+        options->push_back(option);\r
+        pane->addOptionLine(option);\r
+\r
+        option = new Option(5,tr("Video Mpeg2 fix dts time"), "DirectShow","videompeg2dtsfix",Option::TYPE_TEXT,2,1,0,yesnoopts,NULL,false,this);\r
+        options->push_back(option);\r
+        pane->addOptionLine(option);\r
+\r
+\r
+      \r
+    }\r
+\r
+    return true;\r
+}\r
+\r
+IBaseFilter *VideoWin::getVideoFilter()\r
+{\r
+    IBaseFilter *curfilter= NULL;\r
+    if (videofilterselected == -1)\r
+    {\r
+        int i;\r
+        for (i = 0;i <videofilterlist.size();i++)\r
+        {\r
+            \r
+            if (videofilterlist[i].vmr9tested == true)\r
+            {\r
+                if (videofilterlist[i].vmr9 == true)\r
+                {\r
+                    videofilterselected = i;\r
+                    break;\r
+                } \r
+                else\r
+                {\r
+                    continue;\r
+                }\r
+            }\r
+            else\r
+            {\r
+                IMoniker * moni=NULL;\r
+                IBindCtx *bindctx=NULL;\r
+                if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+                LPCOLESTR name=(LPCOLESTR)new WCHAR[strlen(videofilterlist[i].displayname)+1];\r
+                mbstowcs((wchar_t*)name,videofilterlist[i].displayname,strlen(videofilterlist[i].displayname)+1);\r
+                ULONG eater=0;\r
+                \r
+\r
+                if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+                {\r
+                    if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+                    {\r
+                        IAMDecoderCaps* desccaps=NULL;\r
+                        if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+                        {\r
+                            DWORD caps;\r
+                            desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+                            if (caps == DECODER_CAP_SUPPORTED)\r
+                            {\r
+                                videofilterlist[i].vmr9tested =  true;\r
+                                videofilterlist[i].vmr9 = true;\r
+                                videofilterselected = i;\r
+                            } \r
+                            else\r
+                            {\r
+                                videofilterlist[i].vmr9tested =  true;\r
+                                videofilterlist[i].vmr9 = false;\r
+                                \r
+                                curfilter->Release();\r
+                                curfilter=NULL;\r
+                            }\r
+                        }\r
+                        desccaps->Release();\r
+                    }\r
+                    moni->Release();\r
+                } \r
+                delete [] name;\r
+                bindctx->Release();\r
+            }\r
+            if (videofilterlist[i].vmr9) break;\r
+            \r
+        }\r
+        if (curfilter != NULL)\r
+        {\r
+            VDR *vdr=VDR::getInstance();\r
+            if (vdr != NULL)\r
+            {\r
+                vdr->configSave("DirectShow","VideoFilter",\r
+                    videofilterlist[videofilterselected].displayname);\r
+            }\r
+            return curfilter;\r
+        }\r
+    } \r
+    else\r
+    {\r
+        IBindCtx *bindctx=NULL;\r
+        if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+        IMoniker * moni=NULL;\r
+        LPCOLESTR name=new WCHAR[strlen(videofilterlist[videofilterselected].displayname)+1];\r
+        mbstowcs((wchar_t*)name,videofilterlist[videofilterselected].displayname,\r
+            strlen(videofilterlist[videofilterselected].displayname)+1);\r
+        ULONG eater;\r
+        if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+        {\r
+            if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+            {\r
+                    IAMDecoderCaps* desccaps=NULL;\r
+                    if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+                    {\r
+                        DWORD caps;\r
+                        desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+                        if (caps == DECODER_CAP_SUPPORTED)\r
+                        {\r
+                            videofilterlist[videofilterselected].vmr9tested =  true;\r
+                            videofilterlist[videofilterselected].vmr9 = true;\r
+                        } \r
+                        else\r
+                        {\r
+                            videofilterlist[videofilterselected].vmr9tested =  true;\r
+                            videofilterlist[videofilterselected].vmr9 = false;\r
+                            Log::getInstance()->log("VideoWin", Log::WARN ,"Filter does not support VMR9, but is selected, manual selection!");\r
+                        }\r
+                    }\r
+                    moni->Release();\r
+                    delete [] name;\r
+                    bindctx->Release();\r
+                    return curfilter;\r
+             } \r
+            moni->Release();\r
+        }\r
+        bindctx->Release();\r
+        delete [] name;\r
+        return NULL;         \r
+    }\r
+    return NULL;\r
+    \r
+}\r
+\r
+IBaseFilter *VideoWin::getVideoH264Filter()\r
+{\r
+    IBaseFilter *curfilter= NULL;\r
+    if (videoH264filterselected == -1)\r
+    {\r
+        int i;\r
+        for (i = 0;i <videoH264filterlist.size();i++)\r
+        {\r
+            \r
+            if (videoH264filterlist[i].vmr9tested == true)\r
+            {\r
+                if (videoH264filterlist[i].vmr9 == true)\r
+                {\r
+                    videoH264filterselected = i;\r
+                    break;\r
+                } \r
+                else\r
+                {\r
+                    continue;\r
+                }\r
+            }\r
+            else\r
+            {\r
+                IMoniker * moni=NULL;\r
+                IBindCtx *bindctx=NULL;\r
+                if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+                LPCOLESTR name=(LPCOLESTR)new WCHAR[strlen(videoH264filterlist[i].displayname)+1];\r
+                mbstowcs((wchar_t*)name,videoH264filterlist[i].displayname,strlen(videoH264filterlist[i].displayname)+1);\r
+                ULONG eater=0;\r
+                               Log::getInstance()->log("VideoWin", Log::DEBUG ,"Creating filter: %s",videoH264filterlist[i].friendlyname);\r
+\r
+                \r
+\r
+                if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+                {\r
+                    if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+                    {\r
+                        IAMDecoderCaps* desccaps=NULL;\r
+                        if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+                        {\r
+                            DWORD caps;\r
+                            desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+                            if (caps == DECODER_CAP_SUPPORTED)\r
+                            {\r
+                                videoH264filterlist[i].vmr9tested =  true;\r
+                                videoH264filterlist[i].vmr9 = true;\r
+                                videoH264filterselected = i;\r
+                            } \r
+                            else\r
+                            {\r
+                                videoH264filterlist[i].vmr9tested =  true;\r
+                                videoH264filterlist[i].vmr9 = false;\r
+                                \r
+                                curfilter->Release();\r
+                                curfilter=NULL;\r
+                            }\r
+                        }\r
+                        desccaps->Release();\r
+                    }\r
+                    moni->Release();\r
+                } \r
+                delete [] name;\r
+                bindctx->Release();\r
+            }\r
+            if (videoH264filterlist[i].vmr9) break;\r
+            \r
+        }\r
+        if (curfilter != NULL)\r
+        {\r
+            VDR *vdr=VDR::getInstance();\r
+            if (vdr != NULL)\r
+            {\r
+                vdr->configSave("DirectShow","VideoH264Filter",\r
+                    videoH264filterlist[videoH264filterselected].displayname);\r
+            }\r
+            return curfilter;\r
+        }\r
+    } \r
+    else\r
+    {\r
+        IBindCtx *bindctx=NULL;\r
+        if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+        IMoniker * moni=NULL;\r
+        LPCOLESTR name=new WCHAR[strlen(videoH264filterlist[videoH264filterselected].displayname)+1];\r
+        mbstowcs((wchar_t*)name,videoH264filterlist[videoH264filterselected].displayname,\r
+            strlen(videoH264filterlist[videoH264filterselected].displayname)+1);\r
+        ULONG eater;\r
+               Log::getInstance()->log("VideoWin", Log::DEBUG ,"Creating filter: %s",videoH264filterlist[videoH264filterselected].friendlyname);\r
+        if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+        {\r
+            if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+            {\r
+                    IAMDecoderCaps* desccaps=NULL;\r
+                    if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+                    {\r
+                        DWORD caps;\r
+                        desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+                        if (caps == DECODER_CAP_SUPPORTED)\r
+                        {\r
+                            videoH264filterlist[videoH264filterselected].vmr9tested =  true;\r
+                            videoH264filterlist[videoH264filterselected].vmr9 = true;\r
+                        } \r
+                        else\r
+                        {\r
+                            videoH264filterlist[videoH264filterselected].vmr9tested =  true;\r
+                            videoH264filterlist[videoH264filterselected].vmr9 = false;\r
+                            Log::getInstance()->log("VideoWin", Log::WARN ,"Filter does not support VMR9, but is selected, manual selection!");\r
+                        }\r
+                    }\r
+                    moni->Release();\r
+                    delete [] name;\r
+                    bindctx->Release();\r
+                    return curfilter;\r
+             } \r
+            moni->Release();\r
+        }\r
+        bindctx->Release();\r
+        delete [] name;\r
+        return NULL;         \r
+    }\r
+    return NULL;\r
+    \r
+}\r
+\r
+\r
+#ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions\r
+#include "dshelper.h"\r
+#endif\r
+\r
+#define DO_VIDEO\r
+\r
+int VideoWin::play()\r
+{\r
+  if (!initted) return 0;\r
+  return 1;\r
+}\r
+\r
+bool VideoWin::addOptionPagesToWTB(WTabBar *wtb)\r
+{\r
+    Boxx *box=new WWinVideoFilter();\r
+    wtb->addTab(tr("Video Filter"), box);\r
+       box=new WWinVideoH264Filter();\r
+    wtb->addTab(tr("H264 Filter"), box);\r
+    return true;\r
+}\r
+\r
+const VideoFilterDescList *VideoWin::getVideoFilterList(int &selected)\r
+{\r
+    selected=videofilterselected;\r
+    return &videofilterlist;\r
+}\r
+\r
+const VideoFilterDescList *VideoWin::getVideoH264FilterList(int &selected)\r
+{\r
+    selected=videoH264filterselected;\r
+    return &videoH264filterlist;\r
+}\r
+\r
+bool VideoWin::selectVideoFilter(int filter)\r
+{\r
+    IBindCtx *bindctx=NULL;\r
+    if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+    IMoniker * moni=NULL;\r
+    LPCOLESTR name=new WCHAR[strlen(videofilterlist[filter].displayname)+1];\r
+    mbstowcs((wchar_t*)name,videofilterlist[filter].displayname,\r
+    strlen(videofilterlist[filter].displayname)+1);\r
+    ULONG eater;\r
+    bool success=false;\r
+    if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+    {\r
+        IBaseFilter* curfilter=NULL;\r
+        if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+        {\r
+            IAMDecoderCaps* desccaps=NULL;\r
+            if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+            {\r
+                DWORD caps;\r
+                HRESULT hres=desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+                if (caps == DECODER_CAP_SUPPORTED)\r
+                {\r
+                    videofilterlist[filter].vmr9tested =  true;\r
+                    videofilterlist[filter].vmr9 = true;\r
+                    success=true;\r
+                } \r
+                else\r
+                {\r
+                    videofilterlist[filter].vmr9tested =  true;\r
+                    videofilterlist[filter].vmr9 = false;\r
+                    success=false;\r
+                 }\r
+                desccaps->Release();\r
+            } else {\r
+                videofilterlist[filter].vmr9tested =  true;\r
+                videofilterlist[filter].vmr9 = false;\r
+                success=false;\r
+            }\r
+\r
+             curfilter->Release();\r
+             \r
+        } \r
+        moni->Release();\r
+    }\r
+    bindctx->Release();\r
+    delete [] name;\r
+    if (success || true) \r
+    {\r
+        videofilterselected=filter;\r
+        return true;\r
+    } \r
+    else\r
+    {\r
+        return false;\r
+    }\r
+}\r
+\r
+bool VideoWin::selectVideoH264Filter(int filter)\r
+{\r
+    IBindCtx *bindctx=NULL;\r
+    if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;\r
+    IMoniker * moni=NULL;\r
+    LPCOLESTR name=new WCHAR[strlen(videoH264filterlist[filter].displayname)+1];\r
+    mbstowcs((wchar_t*)name,videoH264filterlist[filter].displayname,\r
+    strlen(videoH264filterlist[filter].displayname)+1);\r
+    ULONG eater;\r
+    bool success=false;\r
+    if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)\r
+    {\r
+        IBaseFilter* curfilter=NULL;\r
+        if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)\r
+        {\r
+            IAMDecoderCaps* desccaps=NULL;\r
+            if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)\r
+            {\r
+                DWORD caps;\r
+                HRESULT hres=desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);\r
+                if (caps == DECODER_CAP_SUPPORTED)\r
+                {\r
+                    videoH264filterlist[filter].vmr9tested =  true;\r
+                    videoH264filterlist[filter].vmr9 = true;\r
+                    success=true;\r
+                } \r
+                else\r
+                {\r
+                    videoH264filterlist[filter].vmr9tested =  true;\r
+                    videoH264filterlist[filter].vmr9 = false;\r
+                    success=false;\r
+                 }\r
+                desccaps->Release();\r
+            } else {\r
+                videoH264filterlist[filter].vmr9tested =  true;\r
+                videoH264filterlist[filter].vmr9 = false;\r
+                success=false;\r
+            }\r
+\r
+             curfilter->Release();\r
+             \r
+        } \r
+        moni->Release();\r
+    }\r
+    bindctx->Release();\r
+    delete [] name;\r
+    if (success || true) \r
+    {\r
+        videoH264filterselected=filter;\r
+        return true;\r
+    } \r
+    else\r
+    {\r
+        return false;\r
+    }\r
+}\r
+\r
+int VideoWin::dsInitVideoFilter()\r
+{\r
+    #ifdef DO_VIDEO\r
+    HRESULT hres;\r
+    if (videoon) {\r
+    //We alloc the vmr9 as next step\r
+               if (currentpresenter==VMR9) \r
+               {\r
+                       Log::getInstance()->log("VideoWin", Log::INFO ,"VMR9 Videopresenter selected!");\r
+                       if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0,\r
+                               CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsrenderer)!=S_OK) \r
+                       {\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!");\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                       }\r
+                       /*VMR 9 stuff**/\r
+                       if (hres=dsgraphbuilder->AddFilter(dsrenderer,L"VMR9")!=S_OK)\r
+                       {\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!");\r
+                               return 0;\r
+                       }\r
+                       IVMRFilterConfig9* vmrfilconfig;\r
+                       if (dsrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK)\r
+                       {\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!");\r
+                               return 0;\r
+                       }\r
+                       if (vmrdeinterlacing!=0) vmrfilconfig->SetNumberOfStreams(1);//Enter Mixing Mode\r
+                       vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless);\r
+                       vmrfilconfig->Release();\r
+                       if (dsrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,\r
+                               (void**)& dsvmrsurfnotify) != S_OK)\r
+                       {\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!");\r
+                               return 0;\r
+                       }\r
+                       allocatorvmr=new DsAllocator();\r
+                       dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr);\r
+                       allocatorvmr->AdviseNotify(dsvmrsurfnotify);\r
+                       \r
+                       IVMRDeinterlaceControl9* deintctrl;\r
+                       if (dsrenderer->QueryInterface(IID_IVMRDeinterlaceControl9,(void**)&deintctrl)!=S_OK)\r
+                       {\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Deinterlace control!");\r
+                               return 0;\r
+                       }\r
+                       /*turnoff*/\r
+                       switch (vmrdeinterlacing)\r
+                       {\r
+                       case 1: //No Deinterlasing\r
+                        deintctrl->SetDeinterlaceMode(0xFFFFFFFF,(LPGUID)&GUID_NULL);//Turn Off\r
+            break;\r
+                       case 2: //Best\r
+             deintctrl->SetDeinterlacePrefs(DeinterlacePref_NextBest);//Choose Next Best\r
+            break;\r
+                       case 3: //Bob\r
+             deintctrl->SetDeinterlacePrefs(DeinterlacePref_BOB);//Choose NBob\r
+                       break;\r
+                       case 4: //Weave\r
+             deintctrl->SetDeinterlacePrefs(DeinterlacePref_Weave);//Choose Weave\r
+             break;\r
+                       };\r
+                       deintctrl->Release();\r
+                       /*VMR 9 stuff end */\r
+               }\r
+               else if (currentpresenter==EVR)\r
+               {\r
+                       Log::getInstance()->log("VideoWin", Log::INFO ,"EVR Videopresenter selected!");\r
+                       if (hres=CoCreateInstance(CLSID_EnhancedVideoRenderer,0,\r
+                               CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsrenderer)!=S_OK) \r
+                       {\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating EVR renderer!");\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                       }\r
+                       /*EVR stuff**/\r
+                       if (hres=dsgraphbuilder->AddFilter(dsrenderer,L"EVR")!=S_OK)\r
+                       {\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding EVR renderer!");\r
+                               return 0;\r
+                       }\r
+                       \r
+                       \r
+                       IMFGetService *evr_services;\r
+                       if (dsrenderer->QueryInterface(IID_IMFGetService,(void**)&evr_services)!=S_OK)\r
+                       {\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFGetServices interface!");\r
+                               return 0;\r
+                       }\r
+\r
+                       IMFVideoDisplayControl* mfvideodisplaycontrol;\r
+                       if (evr_services->GetService(MR_VIDEO_RENDER_SERVICE,IID_IMFVideoDisplayControl,(void**)&mfvideodisplaycontrol)!=S_OK)\r
+                       {\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFVideoDisplayControl interface!");\r
+                               return 0;\r
+                       }\r
+\r
+                       evr_services->Release();\r
+                       mfvideodisplaycontrol->SetVideoWindow(((OsdWin*) Osd::getInstance())->getWindow());\r
+                       //RECT client;\r
+                   //GetClientRect(((OsdWin*) Osd::getInstance())->getWindow(), &client);\r
+                       //mfvideodisplaycontrol->SetVideoPosition(NULL,&client);\r
+\r
+                       mfvideodisplaycontrol->Release();\r
+\r
+\r
+               ///     if (vmrdeinterlacing!=0) vmrfilconfig->SetNumberOfStreams(1);//Enter Mixing Mode //always the case for evr!\r
+\r
+                       IMFVideoRenderer *mfvideorenderer;\r
+                       if (dsrenderer->QueryInterface(IID_IMFVideoRenderer,(void**)&mfvideorenderer)!=S_OK)\r
+                       {\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFVideoRenderer interface!");\r
+                               return 0;\r
+                       }\r
+                       \r
+                       allocatorvmr=new DsAllocator();\r
+                       HRESULT hres=mfvideorenderer->InitializeRenderer(NULL,allocatorvmr);\r
+\r
+                       mfvideorenderer->Release();\r
+                       //How should I do this in EVR?\r
+               /*      IVMRDeinterlaceControl9* deintctrl;\r
+                       if (dsrenderer->QueryInterface(IID_IVMRDeinterlaceControl9,(void**)&deintctrl)!=S_OK)\r
+                       {\r
+                               ReleaseMutex(filtermutex);\r
+                               CleanupDS();\r
+                               Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Deinterlace control!");\r
+                               return 0;\r
+                       }\r
+                       /*turnoff*\r
+                       switch (vmrdeinterlacing)\r
+                       {\r
+                       case 1: //No Deinterlasing\r
+                        deintctrl->SetDeinterlaceMode(0xFFFFFFFF,(LPGUID)&GUID_NULL);//Turn Off\r
+            break;\r
+                       case 2: //Best\r
+             deintctrl->SetDeinterlacePrefs(DeinterlacePref_NextBest);//Choose Next Best\r
+            break;\r
+                       case 3: //Bob\r
+             deintctrl->SetDeinterlacePrefs(DeinterlacePref_BOB);//Choose NBob\r
+                       break;\r
+                       case 4: //Weave\r
+             deintctrl->SetDeinterlacePrefs(DeinterlacePref_Weave);//Choose Weave\r
+             break;\r
+                       };\r
+                       deintctrl->Release();*/\r
+                       /*EVR stuff end */\r
+               } else {\r
+                       Log::getInstance()->log("VideoWin", Log::ERR ,"No videopresenter selected! Please post on the forum!");\r
+                       return -1;\r
+               }\r
+        IFilterGraph2*fg2=NULL;\r
+        if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK)\r
+        {\r
+            Log::getInstance()->log("VideoWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");\r
+            ReleaseMutex(filtermutex);\r
+               CleanupDS();\r
+            return 0;\r
+        }\r
+/*#ifndef NEW_DS_MECHANISMENS\r
+        \r
+        if (hres=fg2->RenderEx((IPin*)sourcefilter->GetVideoPin()/*video*,\r
+            AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL) != S_OK) \r
+        {\r
+            Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering Video!");\r
+               fg2->Release();\r
+               ReleaseMutex(filtermutex);\r
+               CleanupDS();\r
+            return 0;\r
+        }\r
+        \r
+#else*/\r
+        IBaseFilter*videofilter;\r
+               if (h264)  \r
+               {\r
+                       Log::getInstance()->log("VideoWin", Log::DEBUG ,"Entering h264 playback...");\r
+                       videofilter=getVideoH264Filter();\r
+               } \r
+               else\r
+               {\r
+                       Log::getInstance()->log("VideoWin", Log::DEBUG ,"Entering MPEG2 playback...");\r
+                       videofilter=getVideoFilter();\r
+               }\r
+        if (hres=dsgraphbuilder->AddFilter(videofilter,NULL) != S_OK) \r
+        {\r
+            Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Video Filter!");\r
+            ReleaseMutex(filtermutex);\r
+            CleanupDS();\r
+            return 0;\r
+        }\r
+        IEnumPins *pinenum=NULL;\r
+        bool error=false;\r
+\r
+        mptype_video_detail vid_details;\r
+        Demuxer* demux=Demuxer::getInstance();\r
+        vid_details.width=demux->getHorizontalSize();\r
+        vid_details.height=demux->getVerticalSize();\r
+\r
+               if (h264)\r
+               {\r
+            if (vid_details.width!=0 && vid_details.height!=0)\r
+            {\r
+                       sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_H264,&vid_details);\r
+               }\r
+               else\r
+               {\r
+                           sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_H264,NULL);\r
+            }\r
+\r
+               }\r
+               else\r
+               {\r
+            if (vid_details.width!=0 && vid_details.height!=0)\r
+            {\r
+                       sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_MPEG2,&vid_details);\r
+               }\r
+            else\r
+            {\r
+                sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_MPEG2,NULL);\r
+            } \r
+               }\r
+        if (videofilter->EnumPins(&pinenum) == S_OK)\r
+        {\r
+            IPin *current=NULL;\r
+            ULONG fetch=0;\r
+            bool firststep=false;\r
+\r
+            while (pinenum->Next(1,&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
index 7090d6cac7c4bc8b0d172bb86ab38f402a32ddf6..f57f4b74d0193fe90f75999a5b4c4745970c4a47 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef VIDEOWIN_H
-#define VIDEOWIN_H
-
-#include <stdio.h>
-#include <string.h>
-#include <winsock2.h>
-#include <dshow.h>
-#include <d3d9.h>
-#include <vmr9.h>
-#include <vector>
-
-#include "defines.h"
-#include "video.h"
-
-//#define DS_DEBUG
-#define NEW_DS_MECHANISMENS
-
-#ifdef NEW_DS_MECHANISMENS
-struct VideoFilterDesc {
-    char * displayname;
-    char * friendlyname;
-    bool vmr9;
-    bool vmr9tested;
-};
-using namespace std;
-typedef vector<VideoFilterDesc> VideoFilterDescList;
-#endif
-
-class DsSourceFilter;
-class DsAllocator;
-
-class VideoWin : public Video
-{
-public:
-       VideoWin();
-       ~VideoWin();
-
-       int init(UCHAR format);
-       int shutdown();
-
-       int setFormat(UCHAR format);
-       int setConnection(UCHAR connection);
-       int setAspectRatio(UCHAR aspectRatio);   // This one does the pin 8 scart widescreen switching
-       UCHAR getAspectRatio(){return aspectRatio;};
-       UCHAR getMode(){return mode;};
-       UCHAR getPseudoTVsize() {return pseudotvsize;};
-       int setMode(UCHAR mode);
-       int setTVsize(UCHAR size);               // Is the TV a widescreen?
-       int setDefaultAspect();
-       int setSource();
-       int setPosition(int x, int y);
-       int sync();
-       int play();
-       int dsplay();
-       bool InIframemode() {return iframemode;};
-       int stop();
-       int dsstop();
-       int pause();
-       int dspause();
-       int unPause();
-       int dsunPause();
-       int fastForward();
-       int unFastForward();
-       int reset();
-       int dsreset();
-       int blank();
-       int signalOn();
-       int signalOff();
-       int attachFrameBuffer(); // What does this do?
-//     ULONG timecodeToFrameNumber(ULLONG timecode);
-//     ULLONG frameNumberToTimecode(ULONG framenumber);
-       ULLONG getCurrentTimestamp();
-
-       bool loadOptionsfromServer(VDR* vdr);
-       bool saveOptionstoServer();
-       bool addOptionPagesToWTB(WTabBar *wtb);
-       bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane);
-       bool handleOptionChanges(Option* option);
-
-       //Writing Data to Videodevice
-       virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);
-       virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos);
-       UINT DeliverMediaPacket(const MediaPacket packet, const UCHAR* buffer, UINT *samplepos);
-    virtual  bool dtsTimefix() {if (h264)return videoH264dtsfix; else return videompeg2dtsfix;}
-
-       virtual bool supportsh264();
-
-
-       virtual bool supportsAc3();
-
-       enum VideoPresenter {
-               VMR9,
-               EVR
-       } ;
-
-
-
-private:
-       MediaPacket mediapacket;
-public:
-
-       int getCurrentAudioMediaSample(IMediaSample** ms);
-       int DeliverAudioMediaSample();
-
-       int getCurrentVideoMediaSample(IMediaSample** ms);
-       int DeliverVideoMediaSample();
-       int setAudioStreamType(UCHAR type);
-
-       virtual long long SetStartOffset(long long curreftime, bool *rsync);
-       long long SetStartAudioOffset(long long curreftime, bool *rsync);
-       virtual void ResetTimeOffsets();
-
-       void SetAudioState(bool state){audioon=state;};
-       void SetAudioVolume(long volume);
-
-       void turnVideoOn(){videoon=true;};
-       void turnVideoOff(){videoon=false;};
-
-       virtual void displayIFrame(const UCHAR* buffer, UINT length);
-
-       unsigned int getPosx() {return videoposx;};
-       unsigned int getPosy() {return videoposy;};
-       bool isVideoOn() {return videoon;};
-       bool isdsinited() {return dsinited;};
-       int lastAType() {return lastaudiomode;};
-       bool changeAType(int type,IMediaSample* ms);
-
-
-       const VideoFilterDescList *getVideoFilterList(int &selected);
-       bool selectVideoFilter(int filter);
-       DsSourceFilter* getSourceFilter() {return sourcefilter;};
-
-       const VideoFilterDescList *getVideoH264FilterList(int &selected);
-       bool selectVideoH264Filter(int filter);
-
-
-#ifdef DEV
-       int test();
-       int test2();
-#endif
-private:
-       int EnterIframePlayback();
-#ifdef NEW_DS_MECHANISMENS
-       void dstest();  
-       void initFilterDatabase();
-       IBaseFilter *getVideoFilter();  
-       VideoFilterDescList videofilterlist;
-       int  videofilterselected;
-
-       void initH264FilterDatabase();
-       IBaseFilter *getVideoH264Filter();  
-       VideoFilterDescList videoH264filterlist;
-       int  videoH264filterselected;
-    bool videoH264dtsfix;
-    bool videompeg2dtsfix;
-#endif
-       int dsInitVideoFilter();
-       IMediaControl* dsmediacontrol;
-
-       IGraphBuilder* dsgraphbuilder;
-       IMediaSample* cur_audio_media_sample;
-       IMediaSample* cur_video_media_sample;
-       IBaseFilter* dsrenderer;
-       IVMRSurfaceAllocatorNotify9  *dsvmrsurfnotify;
-       IReferenceClock *dsrefclock;
-       IMediaFilter* dsmediafilter;
-       IBasicAudio* dsbasicaudio;
-       REFERENCE_TIME cr_time;
-
-       DsSourceFilter* sourcefilter;
-       DsAllocator* allocatorvmr;
-       HANDLE filtermutex;
-       void CleanupDS();
-       bool offsetnotset;
-       bool offsetvideonotset;
-       bool offsetaudionotset;
-       long long startoffset;
-       long long lastrefvideotime;
-       long long lastrefaudiotime;
-       bool dsinited;
-       bool firstsynched;
-       bool audioon;
-       bool videoon;
-       bool iframemode;
-       UCHAR pseudotvsize;
-       REFERENCE_TIME lastreftimeRT;
-       ULLONG lastreftimePTS;
-       unsigned int videoposx;
-       unsigned int videoposy;
-       int lastaudiomode;
-       int audiovolume;
-       UCHAR aud_type;
-       unsigned int vmrdeinterlacing; 
-       VideoPresenter currentpresenter;
-#ifdef DS_DEBUG
-       DWORD graphidentifier;
-#endif
-};
-
-#endif
-
-
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef VIDEOWIN_H\r
+#define VIDEOWIN_H\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <winsock2.h>\r
+#include <dshow.h>\r
+#include <d3d9.h>\r
+#include <vmr9.h>\r
+#include <vector>\r
+\r
+#include "defines.h"\r
+#include "video.h"\r
+\r
+//#define DS_DEBUG\r
+#define NEW_DS_MECHANISMENS\r
+\r
+#ifdef NEW_DS_MECHANISMENS\r
+struct VideoFilterDesc {\r
+    char * displayname;\r
+    char * friendlyname;\r
+    bool vmr9;\r
+    bool vmr9tested;\r
+};\r
+using namespace std;\r
+typedef vector<VideoFilterDesc> VideoFilterDescList;\r
+#endif\r
+\r
+class DsSourceFilter;\r
+class DsAllocator;\r
+\r
+class VideoWin : public Video\r
+{\r
+public:\r
+       VideoWin();\r
+       virtual ~VideoWin();\r
+\r
+       int init(UCHAR format);\r
+       int shutdown();\r
+\r
+       int setFormat(UCHAR format);\r
+       int setConnection(UCHAR connection);\r
+       int setAspectRatio(UCHAR aspectRatio);   // This one does the pin 8 scart widescreen switching\r
+       UCHAR getAspectRatio(){return aspectRatio;};\r
+       UCHAR getMode(){return mode;};\r
+       UCHAR getPseudoTVsize() {return pseudotvsize;};\r
+       int setMode(UCHAR mode);\r
+       int setTVsize(UCHAR size);               // Is the TV a widescreen?\r
+       int setDefaultAspect();\r
+       int setSource();\r
+       int setPosition(int x, int y);\r
+       int sync();\r
+       int play();\r
+       int dsplay();\r
+       bool InIframemode() {return iframemode;};\r
+       int stop();\r
+       int dsstop();\r
+       int pause();\r
+       int dspause();\r
+       int unPause();\r
+       int dsunPause();\r
+       int fastForward();\r
+       int unFastForward();\r
+       int reset();\r
+       int dsreset();\r
+       int blank();\r
+       int signalOn();\r
+       int signalOff();\r
+       int attachFrameBuffer(); // What does this do?\r
+//     ULONG timecodeToFrameNumber(ULLONG timecode);\r
+//     ULLONG frameNumberToTimecode(ULONG framenumber);\r
+       ULLONG getCurrentTimestamp();\r
+\r
+       bool loadOptionsfromServer(VDR* vdr);\r
+       bool saveOptionstoServer();\r
+       bool addOptionPagesToWTB(WTabBar *wtb);\r
+       bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane);\r
+       bool handleOptionChanges(Option* option);\r
+\r
+       //Writing Data to Videodevice\r
+       virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);\r
+       virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos);\r
+       UINT DeliverMediaPacket(const MediaPacket packet, const UCHAR* buffer, UINT *samplepos);\r
+    virtual  bool dtsTimefix() {if (h264)return videoH264dtsfix; else return videompeg2dtsfix;}\r
+\r
+       virtual bool supportsh264();\r
+\r
+\r
+       virtual bool supportsAc3();\r
+\r
+       enum VideoPresenter {\r
+               VMR9,\r
+               EVR\r
+       } ;\r
+\r
+\r
+\r
+private:\r
+       MediaPacket mediapacket;\r
+public:\r
+\r
+       int getCurrentAudioMediaSample(IMediaSample** ms);\r
+       int DeliverAudioMediaSample();\r
+\r
+       int getCurrentVideoMediaSample(IMediaSample** ms);\r
+       int DeliverVideoMediaSample();\r
+       int setAudioStreamType(UCHAR type);\r
+\r
+       virtual long long SetStartOffset(long long curreftime, bool *rsync);\r
+       long long SetStartAudioOffset(long long curreftime, bool *rsync);\r
+       virtual void ResetTimeOffsets();\r
+\r
+       void SetAudioState(bool state){audioon=state;};\r
+       void SetAudioVolume(long volume);\r
+\r
+       void turnVideoOn(){videoon=true;};\r
+       void turnVideoOff(){videoon=false;};\r
+\r
+       virtual bool displayIFrame(const UCHAR* buffer, UINT length);\r
+\r
+       unsigned int getPosx() {return videoposx;};\r
+       unsigned int getPosy() {return videoposy;};\r
+       bool isVideoOn() {return videoon;};\r
+       bool isdsinited() {return dsinited;};\r
+       int lastAType() {return lastaudiomode;};\r
+       bool changeAType(int type,IMediaSample* ms);\r
+\r
+\r
+       const VideoFilterDescList *getVideoFilterList(int &selected);\r
+       bool selectVideoFilter(int filter);\r
+       DsSourceFilter* getSourceFilter() {return sourcefilter;};\r
+\r
+       const VideoFilterDescList *getVideoH264FilterList(int &selected);\r
+       bool selectVideoH264Filter(int filter);\r
+\r
+\r
+#ifdef DEV\r
+       int test();\r
+       int test2();\r
+#endif\r
+private:\r
+       int EnterIframePlayback();\r
+#ifdef NEW_DS_MECHANISMENS\r
+       void dstest();  \r
+       void initFilterDatabase();\r
+       IBaseFilter *getVideoFilter();  \r
+       VideoFilterDescList videofilterlist;\r
+       int  videofilterselected;\r
+\r
+       void initH264FilterDatabase();\r
+       IBaseFilter *getVideoH264Filter();  \r
+       VideoFilterDescList videoH264filterlist;\r
+       int  videoH264filterselected;\r
+    bool videoH264dtsfix;\r
+    bool videompeg2dtsfix;\r
+#endif\r
+       int dsInitVideoFilter();\r
+       IMediaControl* dsmediacontrol;\r
+\r
+       IGraphBuilder* dsgraphbuilder;\r
+       IMediaSample* cur_audio_media_sample;\r
+       IMediaSample* cur_video_media_sample;\r
+       IBaseFilter* dsrenderer;\r
+       IVMRSurfaceAllocatorNotify9  *dsvmrsurfnotify;\r
+       IReferenceClock *dsrefclock;\r
+       IMediaFilter* dsmediafilter;\r
+       IBasicAudio* dsbasicaudio;\r
+       REFERENCE_TIME cr_time;\r
+\r
+       DsSourceFilter* sourcefilter;\r
+       DsAllocator* allocatorvmr;\r
+       HANDLE filtermutex;\r
+       void CleanupDS();\r
+       bool offsetnotset;\r
+       bool offsetvideonotset;\r
+       bool offsetaudionotset;\r
+       long long startoffset;\r
+       long long lastrefvideotime;\r
+       long long lastrefaudiotime;\r
+       bool dsinited;\r
+       bool firstsynched;\r
+       bool audioon;\r
+       bool videoon;\r
+       bool iframemode;\r
+       UCHAR pseudotvsize;\r
+       REFERENCE_TIME lastreftimeRT;\r
+       ULLONG lastreftimePTS;\r
+       unsigned int videoposx;\r
+       unsigned int videoposy;\r
+       int lastaudiomode;\r
+       int audiovolume;\r
+       UCHAR aud_type;\r
+       unsigned int vmrdeinterlacing; \r
+       VideoPresenter currentpresenter;\r
+#ifdef DS_DEBUG\r
+       DWORD graphidentifier;\r
+#endif\r
+};\r
+\r
+#endif\r
+\r
+\r
+\r
index af6cd2cfea272f7fe0d81c251abc8d0841b1fb98..0e9f274a515c9accd38935265412e78998169f38 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon, Andreas Vogel
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include <time.h>
-
-#include "vmediaview.h"
-
-#include "vpicturebanner.h"
-#include "vcolourtuner.h"
-#include "audioplayer.h"
-#include "timers.h"
-#include "boxx.h"
-#include "wselectlist.h"
-#include "remote.h"
-#include "wsymbol.h"
-#include "boxstack.h"
-#include "vdr.h"
-#include "media.h"
-#include "video.h"
-#include "vinfo.h"
-#include "i18n.h"
-#include "message.h"
-#include "command.h"
-#include "mediaoptions.h"
-#include "mediaplayer.h"
-#include "log.h"
-
-const int VMediaView::EVENT_SLIDESHOW=100;
-const int VMediaView::EVENT_DRAWINGDONE=101;
-const int VMediaView::EVENT_DRAWINGERROR=102;
-const int VMediaView::EVENT_DIRECTORYDONE=103;
-
-
-/**
-  * the combined user interface for pictures and audio
-  * has 2 surfaces to enable drawing in a separate thread
-  * the info display can either show a picture info or and audio info
-  * if the audio player comes on top it disables the picture info display
-  * basically we have 3 modes:
-  *   - HIDDEN viewer is hidden (pictureEnabled=false, audioEnabled=false)
-  *     if justPlaying=true the audioplayer is still running
-  *   - PICTURE picture viewer on top ("slide show") - pictureEnabled=true, audioEnabled=false
-  *     no AudioBanner visible
-  *     if justPlaying=true the audio player runs in bg
-  *   - AUDIO audioPlayer on top ("playlist mode") - pictureEnabled=true, audioEnabled=true
-  *     the picture viewer is currently halted (should be able to continue if no AudioInfo)
-  *     no picture banner (we should have an audio banner to indicate the audio player on top!)
-  * state transitions (via setPictureMode, setAudioMode)
-  *   - show Picture -> pictureEnabled=true, 
-  *     only called from command handler if audioEnabled=false
-  *     call from mediaList only possible if audioEnabled=false
-  *         *** TODO: would be better to have separate function for external call/internal call
-  *   - play [Audio] -> if activate is set -> audioEnabled=true (-> Mode AUDIO)
-  *                     used for calls from medialist
-  *                     internal calls do not set activate!
-  *   - YELLOW key - toggle
-  *     if audioActive==true -> audioActive=false (new mode depends on pictureEnabled - either HIDDEN or PICTURE)
-  *     if audioActive==false -> audioActive=true (new mode AUDIO)
-  *          *** open handling if no audio file there (ignore key???) - currently empty player
-  *   - BACK if mode AUDIO -> audioEnabled=false, justPlaying=false
-  *   - BACK if mode PICTURE -> pictureEnabled=false;
-  *   - player StreamEnd -> audioEnabled=false (new mode depends on pciture - either HIDDEN or PICTURE)
-  * info/banner handling:
-  *   - AudioInfo - alternativ to pictureInfo
-  *     off when disabling audio or after timer or with OK in AUDIO mode
-  *     on currently any command or player event (end/new song) when audioEnabled==true and retriggerAudioInfo=true
-  *     on on OK in AUDIO mode
-  *   - Picture Info
-  *     off when disabling Picture or after timer, OK, green
-  *     on only on green when pictureEnabled==true
-  *   - PictureBanner
-  *     2 modes: loading/normal
-  *       normal:
-  *       off when disabling picture, OK, after timer
-  *       on when enabling picture, with OK
-  *       loading:
-  *       off when disabling picture and when loading done
-  *       on on start loading
-  *          *** open: do not show when audio enabled and slide show running (currently slideshow is paused)
-  *   - AudioBanner
-  *       always shown when audioEnabled=true
-  *       on when enabling Audio
-  *       off when disabling audio
-  *       update in play
-  * timers: 1 - slide show
-  *         2 - pictureBanner
-  *         3 - info showtime
-  *         4 - audio short update
-  */
-
-#define DRAWING_THREAD
-
-Colour VMediaView::pictureBack=Colour(140,140,140);
-Colour VMediaView::infoBack=Colour(110,110,110);
-Colour VMediaView::audioBannerBack=Colour(110,110,110,20);
-//the jpeg reader
-
-//how long do we wait for a single picture chunk
-//the unit is 100ms (the timeout on the server side)
-#define MAXTRY 100 
-class VPreader : public JpegReader {
-  private:
-    ImageReader *reader;
-    VMediaView * parent;
-    ULLONG size;
-    bool dobreak;;
-  public:
-  VPreader(VMediaView *p,ImageReader *r){ 
-    parent=p;
-    size=0;
-    reader=r;
-    dobreak=false;
-  };
-  virtual ULONG readChunk(ULONG offset,ULONG len,char ** buf) {
-     Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "read chunk o=%d,len=%d,buf=%p",
-        offset,len,*buf);
-     UINT numrec=0;
-     int rt=0;
-     for (int trycount=0;trycount < MAXTRY && ! dobreak && numrec == 0 && rt == 0;trycount++) {
-       if (dobreak) {
-         *buf=NULL;
-         rt=-1;
-       }
-       else {
-         rt=reader->getImageChunk((ULLONG)offset,(UINT)len,&numrec,(UCHAR **)buf);
-       }
-     }
-     Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "got n=%d,buf=%p,rt=%d",
-        numrec,*buf,rt);
-     return numrec;
-     }
-  virtual int initRead(const MediaURI *uri,ULLONG *sz,ULONG factor=100) {
-     Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s",uri->getDisplayName());
-     Video* video = Video::getInstance();
-     dobreak=false;
-     int rt=MediaPlayer::getInstance()->openMedium(1,uri,sz,video->getScreenWidth()*factor/100, video->getScreenHeight()*factor/100);
-     if (rt < 0) *sz=0;
-     size=*sz;
-     Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s returned %llu",uri->getDisplayName(),size);
-     return rt;
-     }
-  virtual ULONG getSize() {return size;}
-  //seems to be thread safe (more or less...)
-  void setBreak() {
-    dobreak=true;
-  }
-};
-
-/**
-  * a separate thread for drawing pictures
-  * will be started with the sfc and the draw control
-  * will send a player event when done
-  */
-class DrawingThread : public Thread_TYPE {
-  private:
-    VMediaView *_parent;
-    VPreader * _reader;
-    WJpeg::JpegControl *_ctl;
-    Surface *_sfc;
-    Colour _colour;
-    bool _interrupted;
-  public:
-    DrawingThread(VMediaView *parent) {
-      _parent=parent;
-      _reader=NULL;
-      _ctl=NULL;
-      _sfc=NULL;
-      _interrupted=false;
-    }
-    virtual ~DrawingThread(){}
-    bool isRunning() {
-      return (threadIsActive()!=0);
-    }
-    bool start(WJpeg::JpegControl *ctl,Surface *sfc,VPreader *reader,Colour &c) {
-      if (isRunning()) {
-        return false;
-      }
-      _interrupted=false;
-      _ctl=ctl;
-      _sfc=sfc;
-      _reader=reader;
-      _colour=c;
-      return (threadStart() == 1);
-    }
-    bool stop() {
-      Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop initiated");
-      if (threadIsActive()) {
-        _interrupted=true;
-        if (_reader) _reader->setBreak();
-        threadStop();
-      }
-      Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop done");
-      _reader=NULL;
-      return true;
-    }
-  protected:
-    virtual void threadMethod() {
-      Log::getInstance()->log("DrawingThread",Log::DEBUG,"started");
-      bool rt=WJpeg::drawJpeg(_ctl,_sfc,_reader,_colour);
-      _reader=NULL;
-      if (! _interrupted) {
-        Message* m = new Message(); 
-        //we misuse PLAYER_EVENT here
-        m->message = Message::PLAYER_EVENT;
-        m->to = _parent;
-        m->from = _parent;
-        m->parameter= rt?VMediaView::EVENT_DRAWINGDONE:VMediaView::EVENT_DRAWINGERROR;
-        Command::getInstance()->postMessageFromOuterSpace(m);
-      }
-      Log::getInstance()->log("DrawingThread",Log::DEBUG,"finishing interrupt=%d",(int)_interrupted);
-    }
-    virtual void threadPostStopCleanup() {}
-
-};
-
-
-VMediaView::VMediaView(VMediaList *p)
-{
-  Log::getInstance()->log("VMediaView::VMediaView", Log::DEBUG, "p=%p", this);
-  audioEnabled=false;
-  pictureEnabled=false;
-  parent=p;
-  ireader=new ImageReader(1,MediaPlayer::getInstance());
-  reader=new VPreader(this,ireader);
-  //the surface handling
-  Video* video = Video::getInstance();
-  setSize(video->getScreenWidth(), video->getScreenHeight());
-  createBuffer();
-  sfc2=getSurface();
-  surface=NULL;
-  //create the second surface
-  createBuffer();
-  sfc1=getSurface();
-  originalh=area.h;
-  originalw=area.w;
-  //disable the surface
-  area.h=1;
-  area.w=1;
-  //banners and infos
-  pictureBanner=NULL;
-  slideshow=false;
-  pictureError=NULL;
-  currentPicture=NULL;
-  info=NULL;
-  pictureLoading=false;
-
-  //picture settings
-  showtime=INITIAL_SHOWTIME;
-  rotate=WJpeg::ROT_0;
-  currentScale=1;
-  options=MediaOptions::getInstance();
-  VColourTuner::initFactors();
-  int st=options->getIntOption("SlideShowInterval");
-  if (st > 0) showtime=st;
-  ctl.area.w=originalw;
-  ctl.area.h=originalh;
-  ctl.enlarge=false;
-  ctl.scaleafter=options->getIntOption("ScaleFactor");
-  const char * mode=options->getStringOption("PictureMode");
-  if (strcmp(mode,"clip") == 0) ctl.mode=WJpeg::CROP;
-  else if (strcmp(mode,"letter") == 0) ctl.mode=WJpeg::LETTER;
-  else if (strcmp(mode,"clipfactor") == 0) ctl.mode=WJpeg::CROPPERCENT;
-  ctl.scaleAmount=options->getIntOption("PictureSize");
-  if (ctl.scaleAmount < 10) ctl.scaleAmount=10;
-  if (ctl.scaleAmount > 200) ctl.scaleAmount=200;
-  ctl2=ctl;
-  cropmode=ctl.mode;
-  //current control is the one used for DISPLAY (not the one for drawing - this is the other one)
-  //this is closely coupled to the surface - i.e. ctl is for sfc1, ctl2 for sfc2
-  currentControl=&ctl;
-  bannerEnabled=true;
-  pictureShowing=false;
-
-  //audio player
-
-  barBlue.set(0, 0, 150, 150);
-  audioError=NULL;
-  currentAudio=NULL;
-  justPlaying=false;
-  playall=false;
-  retriggerAudioInfo=false;
-  audioBanner=NULL;
-  drawingThread=new DrawingThread(this);
-}
-
-VMediaView::~VMediaView()
-{
-  Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "p=%p,secondSfc=%s", this,(secondSurface()?"true":"false"));
-  destroyPictureBanner();
-  if (currentPicture) delete currentPicture;
-  Timers::getInstance()->cancelTimer(this,1);
-  Timers::getInstance()->cancelTimer(this,2);
-  Timers::getInstance()->cancelTimer(this,3);
-  Timers::getInstance()->cancelTimer(this,4);
-  Timers::getInstance()->cancelTimer(this,5);
-  destroyInfo();
-  destroyAudioBanner();
-  if (getPlayer(false)) {
-    AudioPlayer::getInstance(NULL,false)->shutdown();
-  }
-  if (currentAudio) delete currentAudio;
-  drawingThread->stop();
-  ireader->shutdown();
-  delete ireader;
-  delete reader;
-  if (secondSurface()) {
-    delete sfc1;
-    sfc1=NULL;
-  }
-  else {
-    delete sfc2;
-    sfc2=NULL;
-  }
-  MediaPlayer::getInstance()->closeMediaChannel(1);
-  MediaPlayer::getInstance()->closeMediaChannel(2);
-  Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "done p=%p", this);
-}
-
-void VMediaView::setPictureMode(bool act) {
-  Log::getInstance()->log("VMediaView", Log::DEBUG, "set pictureMode %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);
-  if ( act) {
-    if ( ! pictureEnabled && ! audioEnabled) {
-      area.h=originalh;
-      area.w=originalw;
-      showPictureBanner();
-      parent->updateAll();
-    }
-    if (! pictureEnabled) {
-      //we newly enable the picture - so clear the screen
-      draw();
-      BoxStack::getInstance()->update(this);
-      if (slideshow) startSlideshow();
-    }
-  }
-  else 
-  {
-    if ( pictureEnabled) {
-      destroyPictureBanner();
-      stopSlideshow(false);
-#ifdef DRAWING_THREAD
-      drawingThread->stop();
-#endif
-      if (! audioEnabled) {
-        destroyInfo();
-        area.w=1;
-        area.h=1;
-        draw();
-        parent->updateAll();
-      }
-    }
-    pictureShowing=false;
-  }
-  pictureEnabled=act;
-}
-
-//we can disable audio without automatically hiding us
-//this will become strange - we are visible but do not handle
-//keys - so if you call setAudioMode(false,false) be sure
-//to call setAudioMode(false,true) afterwards
-//it is only here to give the list a chance to start a new play
-//when we call directoryDone
-void VMediaView::setAudioMode(bool act,bool doHiding) {
-  Log::getInstance()->log("VMediaView", Log::DEBUG, "setAudioMode  %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);
-  if ( act) {
-    if (! audioEnabled) {
-      if (! pictureEnabled) {
-        area.w=originalw;
-        area.h=originalh;
-        draw(); //empty screen if no picture
-        parent->updateAll();
-      }
-      destroyPictureBanner();
-
-    }
-    audioEnabled=true;
-    showAudioBanner();
-    showAudioInfo();
-  }
-  else 
-  {
-    if ( audioEnabled) {
-      audioEnabled=false;
-      destroyInfo();
-      destroyAudioBanner();
-    }
-    if (! pictureEnabled  && doHiding) {
-      area.w=1;
-      area.h=1;
-      draw();
-      parent->updateAll();
-    }
-    else {
-      //picture now on top
-      if (havePictureBanner && ! pictureBanner) showPictureBanner();
-    }
-  }
-}
-
-
-
-void VMediaView::draw()
-{
-  Log::getInstance()->log("VMediaView::draw", Log::DEBUG, "pictureError=%s,p=%p", pictureError,this);
-  
-  if (pictureShowing ) fillColour(pictureBack);
-  else fillColour(Colour::BLACK);
-  if (pictureError) {
-    drawText(pictureError,100,area.h/2,Colour::LIGHTTEXT);
-    return;
-    }
-}
-
-
-int VMediaView::handleCommand(int command)
-{
-  Log::getInstance()->log("VMediaView::handleCommand", Log::DEBUG, "cmd=%d,p=%p", command,this);
-  if ( !audioEnabled && ! pictureEnabled ) {
-    //only handle YELLOW
-    if (command == Remote::YELLOW) {
-      setAudioMode(true);
-      return 1;
-    }
-    return 0;
-  }
-  if ( ! audioEnabled) {
-    //------------------------- command in mode PICTURE (i.e. picture is on top) ----------------
-    //picture on top
-    int rt=1;
-    switch(command)
-    {
-      case Remote::DF_UP:
-      case Remote::UP:
-      case Remote::SKIPBACK:
-        rotate=WJpeg::ROT_0;
-        showPicture(VMediaList::MV_PREV,slideshow,true);
-        rt= 2;
-        break;
-      case Remote::FORWARD:
-        if (showtime > 1) showtime--;
-        updatePictureBanner(true);
-        break;
-      case Remote::DF_DOWN:
-      case Remote::DOWN:
-      case Remote::SKIPFORWARD:
-        rotate=WJpeg::ROT_0;
-        showPicture(VMediaList::MV_NEXT,slideshow,true);
-        rt= 2;
-        break;
-      case Remote::REVERSE:
-        if (showtime < 50 ) showtime++;
-        updatePictureBanner(true);
-        break;
-      case Remote::OK:
-      {
-        if (pictureBanner) {
-          destroyPictureBanner();
-          destroyInfo();
-          havePictureBanner=false;
-          }
-        else {
-          havePictureBanner=true;
-          showPictureBanner(pictureLoading);
-        }
-        rt= 2;
-      }
-      break;
-      case Remote::PLAY:
-      {
-        slideshow=true;
-        rotate=WJpeg::ROT_0;
-        showPicture(VMediaList::MV_NEXT,slideshow,true);
-        rt= 2;
-      }
-      break;
-      case Remote::PAUSE:
-        if (slideshow) {
-          stopSlideshow(true);
-          updatePictureBanner();
-        }
-        else {
-          slideshow=true;
-          rotate=WJpeg::ROT_0;
-          showPicture(VMediaList::MV_NEXT,slideshow,true);
-        }
-        rt= 2;
-        break;
-      case Remote::STOP:
-        stopSlideshow(true);
-        showtime=INITIAL_SHOWTIME;
-        updatePictureBanner();
-        rt= 2;
-        break;
-      case Remote::RED:
-        switch(rotate) {
-          case WJpeg::ROT_0:
-            rotate=WJpeg::ROT_90;
-            break;
-          case WJpeg::ROT_90:
-            rotate=WJpeg::ROT_180;
-            break;
-          case WJpeg::ROT_180:
-            rotate=WJpeg::ROT_270;
-            break;
-          case WJpeg::ROT_270:
-            rotate=WJpeg::ROT_0;
-            break;
-          }
-        showPicture(VMediaList::MV_NONE,slideshow,true);
-        rt=2;
-        break;
-      case Remote::GREEN:
-        if (info) destroyInfo();
-        else showPictureInfo();
-        rt=2;
-        break;
-      case Remote::BLUE:
-        switch (cropmode) {
-          case WJpeg::CROP:
-            cropmode=WJpeg::LETTER;
-            break;
-          case WJpeg::LETTER:
-            cropmode=WJpeg::CROPPERCENT;
-            break;
-          default:
-            cropmode=WJpeg::CROP;
-            break;
-        }
-        showPicture(VMediaList::MV_NONE,slideshow,true);
-        rt=2;
-        break;
-      case Remote::MENU: {
-        stopSlideshow(true);
-        destroyPictureBanner();
-        destroyInfo();
-        VColourTuner *ct=new VColourTuner();
-        BoxStack::getInstance()->add(ct);
-        ct->draw();
-        BoxStack::getInstance()->update(ct);
-        rt=2;
-       
-                         } break;
-      case Remote::BACK:
-      {
-        setPictureMode(false);
-        rt= 2;
-      }
-      break;
-      case Remote::YELLOW:
-      {
-        setAudioMode(true);
-      }
-    }
-    return rt;
-  } 
-  else 
-  {
-    int rt=1;
-    bool updateInfo=false;
-    //------------------------- command in mode AUDIO (i.e. audio is on top) ----------------
-    switch(command)
-    {
-      case Remote::YELLOW:
-        setAudioMode(false);
-        rt=2;
-        break;
-      case Remote::DF_UP:
-      case Remote::UP:
-        play(playall,false,VMediaList::MV_PREV);
-        rt= 2;
-        break;
-      case Remote::FORWARD:
-        if (! audioError) getPlayer()->fastForward();
-        updateInfo=true;
-        rt=2;
-        break;
-      case Remote::DF_DOWN:
-      case Remote::DOWN:
-        play(playall,false,VMediaList::MV_NEXT);
-        rt= 2;
-        break;
-      case Remote::SKIPFORWARD:
-        if (! audioError) getPlayer()->skipForward(10);
-        rt=2;
-        break;
-      case Remote::SKIPBACK:
-        if (! audioError) getPlayer()->skipBackward(10);
-        rt=2;
-        break;
-      case Remote::REVERSE:
-        rt=2;
-        break;
-      case Remote::ZERO:
-        if (! audioError) getPlayer()->jumpToPercent(0);
-        rt=2;
-        break;
-      case Remote::ONE:
-        if (! audioError) getPlayer()->jumpToPercent(10);
-        rt=2;
-        break;
-      case Remote::TWO:
-        if (! audioError) getPlayer()->jumpToPercent(20);
-        rt=2;
-        break;
-      case Remote::THREE:
-        if (! audioError) getPlayer()->jumpToPercent(30);
-        rt=2;
-        break;
-      case Remote::FOUR:
-        if (! audioError) getPlayer()->jumpToPercent(40);
-        rt=2;
-        break;
-      case Remote::FIVE:
-        if (! audioError) getPlayer()->jumpToPercent(50);
-        rt=2;
-        break;
-      case Remote::SIX:
-        if (! audioError) getPlayer()->jumpToPercent(60);
-        rt=2;
-        break;
-      case Remote::SEVEN:
-        if (! audioError) getPlayer()->jumpToPercent(70);
-        rt=2;
-        break;
-      case Remote::EIGHT:
-        if (! audioError) getPlayer()->jumpToPercent(80);
-        rt=2;
-        break;
-      case Remote::NINE:
-        if (! audioError) getPlayer()->jumpToPercent(90);
-        rt=2;
-        break;
-      case Remote::OK:
-      case Remote::GREEN:
-      {
-        if (info) {
-          destroyInfo();
-          retriggerAudioInfo=false;
-          }
-        else {
-          retriggerAudioInfo=true;
-          showAudioInfo();
-        }
-        if (getPlayer()->getState() == AudioPlayer::S_ERROR) {
-          if (playall) play(playall,false,VMediaList::MV_NEXT);
-        }
-        rt= 2;
-      }
-      break;
-      case Remote::PLAY:
-      {
-        if (! audioError) getPlayer()->unpause();
-        updateInfo=true;
-        if (getPlayer()->getState() != AudioPlayer::S_ERROR) ;
-        else if (playall) play(playall,false,VMediaList::MV_NEXT);
-        rt= 2;
-      }
-      break;
-      case Remote::PAUSE:
-        if (! audioError) getPlayer()->pause();
-        updateInfo=true;
-        rt= 2;
-        break;
-      case Remote::STOP:
-        getPlayer()->stop();
-        justPlaying=false;
-        updateInfo=true;
-        rt= 2;
-        break;
-      case Remote::BACK:
-      {
-        getPlayer()->stop();
-        playall=false;
-        retriggerAudioInfo=false;
-        justPlaying=false;
-        setAudioMode(false);
-        if (! pictureShowing) setPictureMode(false); //could have been delayed
-        rt= 2;
-      }
-      break;
-    }
-    if (audioEnabled && updateInfo) updateAudioInfo();
-    return rt;
-  }
-}
-
-void VMediaView::processMessage(Message* m)
-{
-  Log::getInstance()->log("VMediaView::processMessage", Log::DEBUG, "cmd=%lu,p=%lu", m->message,m->parameter);
-  if (m->message == Message::MOUSE_MOVE)
-  {
-    ;
-  }
-  else if (m->message == Message::MOUSE_LBDOWN)
-  {
-    
-    //check if press is outside this view! then simulate cancel
-    int x=(m->parameter>>16)-getScreenX();
-    int y=(m->parameter&0xFFFF)-getScreenY();
-    if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
-    {
-      BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
-    }
-  }
-  else if (m->message = Message::PLAYER_EVENT) {
-    switch (m->parameter) {
-      case EVENT_SLIDESHOW:
-        if (! pictureEnabled) break; //old timer msg...
-        //if (! audioEnabled) {
-        if (true) {
-          if (slideshow) {
-            rotate=WJpeg::ROT_0;
-            showPicture(VMediaList::MV_NEXT,true,false);
-            startSlideshow();
-          }
-        }
-        break;
-      case EVENT_DRAWINGERROR:
-        drawingDone(true);
-        break;
-      case EVENT_DRAWINGDONE:
-        drawingDone(false);
-        break;
-      case EVENT_DIRECTORYDONE:
-        //just disable audio without (poetntially) hiding us
-        //this gives the list a chance to decide whether audio
-        //should be on top afterwards without showing the list
-        //immediately
-        setAudioMode(false,false);
-        parent->directoryDone();
-        if (! pictureShowing) setPictureMode(false);
-        if (! justPlaying) setAudioMode(false);
-        break;
-      case AudioPlayer::STREAM_ERR:
-      case AudioPlayer::STREAM_END:
-        if (playall) play(playall,false,VMediaList::MV_NEXT);
-        else {
-          setAudioMode(false);
-          justPlaying=false;
-        }
-        break;
-      case AudioPlayer::SHORT_UPDATE:
-                               if (info && audioEnabled ) {
-                                       drawAudioClocks();
-                                       BoxStack::getInstance()->update(info,&clocksRegion);
-                                 BoxStack::getInstance()->update(info,&barRegion);
-                                       Timers::getInstance()->setTimerD(this, 4, 1);
-                               }
-        break;
-      case AudioPlayer::NEW_SONG:
-        if (audioEnabled) updateAudioInfo();
-        break;
-      case AudioPlayer::CONNECTION_LOST:
-        if (audioEnabled) destroyInfo();
-        if (AudioPlayer *player=getPlayer(false)) {
-          player->shutdown();
-          player=NULL;
-        }
-        Command::getInstance()->connectionLost();
-        break;
-    }
-  }
-}
-
-
-VMediaView * VMediaView::createViewer(VMediaList * mparent) {
-   Log::getInstance()->log("VMediaView::createViewer", Log::DEBUG, "p=%p",
-        mparent);
-   VMediaView *vmn=new VMediaView(mparent);
-   BoxStack::getInstance()->add(vmn);
-   vmn->draw();
-   BoxStack::getInstance()->update(vmn);
-   return vmn;
-}
-
-void VMediaView::startSlideshow() {
-   slideshow=true;
-   if (! pictureLoading) Timers::getInstance()->setTimerD(this,1,showtime);
-}
-
-void VMediaView::stopSlideshow(bool hard) {
-   if (hard) slideshow=false;
-   Timers::getInstance()->cancelTimer(this,1);
-}
-
-
-void VMediaView::showPicture(ULONG move,bool bslideshow,bool activateBanner) {
-  pictureShowing=true;
-  setPictureMode(true);
-  stopSlideshow(true);
-#ifdef DRAWING_THREAD
-  drawingThread->stop();
-#endif
-  slideshow=bslideshow;
-  Media *newPicture=parent->getMedia(MEDIA_TYPE_PICTURE,move);
-  if ( ! newPicture) {
-    pictureShowing=false;
-    if (!audioEnabled) {
-      //within the event handler first directoryDone is called
-      //and afterwards everything is stopped if nothing new
-      sendCommandMsg(EVENT_DIRECTORYDONE);
-    }
-    slideshow=false;
-  }
-  else 
-  {
-    pictureShowing=true;
-    if (currentPicture) {
-      delete currentPicture;
-      currentPicture=NULL;
-    }
-    currentPicture=newPicture;
-    loadPicture(currentPicture,activateBanner);
-  }
-}
-
-//the real picture drawing method
-//will start drawing on a new surface and will switch it wehn done
-
-int VMediaView::loadPicture(Media *md,bool activateBanner) {
-  pictureError=NULL;
-  if (! md) return 1;
-  if (! md->getURI()) {
-    pictureError=tr("No media found");
-    Log::getInstance()->log("VMediaView::load",Log::ERR,"no URI in media");
-    return 1;
-  }
-  Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",
-        md->getURI()->getName(),this);
-  //do we have a pictureBanner?
-  havePictureBanner=pictureBanner!=NULL || activateBanner;
-  pictureLoading=true;
-#ifdef DRAWING_THREAD
-  if (!audioEnabled && havePictureBanner ) showPictureBanner(true);
-  drawingThread->stop();
-#else
-  showPictureBanner(true);
-#endif
-  ireader->stop();
-  ULLONG size=0;
-  int rtok=reader->initRead(md->getURI(),&size,ctl.scaleAmount); //scaleAmount is the same for both...
-  if (rtok == 0) {
-     //now we can really draw
-     //get the surface for drawing
-     Surface * drawSurface=NULL;
-     WJpeg::JpegControl *drawCtl=NULL;
-     getDrawingParam(drawSurface,drawCtl);
-     drawCtl->error[0]=0;
-     drawCtl->rotation=rotate;
-     drawCtl->mode=cropmode;
-     drawCtl->compressedSize=size;
-#ifdef DRAWING_THREAD
-     bool ok=drawingThread->start(drawCtl,drawSurface,reader,pictureBack);
-     if (! ok) {
-       Log::getInstance()->log("VMediaView::load", Log::ERR, "unable to start drawing thread");
-       pictureError=tr("JpegError");
-       pictureLoading=false;
-       destroyPictureBanner();
-       return 1;
-     }
-     return 0;
-#else
-     //here we could hand this over to the drawing thread
-     bool ok=WJpeg::drawJpeg(drawCtl,drawSurface,reader,pictureBack);
-     drawingDone(!ok);
-     return ok?0:1;
-#endif
-  }
-  pictureLoading=false;
-  return 1;
-}
-
-void VMediaView::drawingDone(bool hasError) {
-  pictureLoading=false;
-  destroyPictureBanner(); //disable loading indication (or real banner)
-  if (! hasError) {
-    switchSurface();
-    Log::getInstance()->log("VMediaView::drawingDone", Log::DEBUG, "success: sfc now=%p",surface);
-    pictureError=NULL;
-    //only show the pictureBanner if it was there before
-    if (havePictureBanner && ! audioEnabled) showPictureBanner();
-    Log::getInstance()->log("VMediaView::load", Log::DEBUG, "success" );
-    updatePictureInfo(); //will only do somethng if pictureEnabled
-  }
-  else 
-  {
-    pictureError=tr("JpegError");
-    if (pictureEnabled) {
-      draw();
-      destroyInfo();
-    }
-  }
-  MediaPlayer::getInstance()->closeMediaChannel(1);
-#ifndef DRAWING_THREAD
-  if (audioEnabled) showAudioBanner();
-#endif
-  if (slideshow) startSlideshow();
-  BoxStack::getInstance()->update(this);
-}
-
-void VMediaView::showPictureBanner(bool loading) {
-  //we are in the main thread - so we can (and must) safely hard destroy/create the banner
-  Timers::getInstance()->cancelTimer(this,2);
-  if (! currentPicture) {
-    //hmm...
-    destroyPictureBanner(false);
-    return;
-    }
-  if (pictureBanner) destroyPictureBanner(false);
-  if (! pictureEnabled || ! bannerEnabled) return;
-  pictureBanner= new VPictureBanner(loading, slideshow);
-  pictureBanner->fillColour(infoBack);
-  if (! loading) {
-    int len=strlen(currentPicture->getFileName())+Media::TIMEBUFLEN+20;
-    char *buf=new char[len];
-    char tbuf[Media::TIMEBUFLEN];
-    SNPRINTF(buf,len,"%c%02ds%c %s %s " ,
-      slideshow?' ':'[',
-      showtime,
-      slideshow?' ':']',
-      currentPicture->getTimeString(tbuf),
-      currentPicture->getFileName()
-      );
-    pictureBanner->setText(buf);
-    delete [] buf;
-  }
-  else {
-    char *buf=new char[strlen(currentPicture->getDisplayName())+50];
-    SNPRINTF(buf,50,"%s %s",tr("Loading"), currentPicture->getDisplayName());
-    pictureBanner->setText(buf);
-    delete buf;
-  }
-  pictureBanner->draw();
-  if (! loading )   Timers::getInstance()->setTimerD(this,2,8);
-  BoxStack::getInstance()->add(pictureBanner);
-  BoxStack::getInstance()->update(pictureBanner);
-  }
-
-void VMediaView::destroyPictureBanner(bool fromTimer) {
-  if (pictureBanner) {
-    if (fromTimer) sendViewMsg(pictureBanner); 
-    else BoxStack::getInstance()->remove(pictureBanner);
-    pictureBanner=NULL;
-    if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);
-    }
-}
-void VMediaView::updatePictureBanner(bool loading) {
-  if (pictureBanner ) {
-    showPictureBanner(loading);
-    }
-}
-void VMediaView::timercall(int clientref) {
-   Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "id=%d",clientref);
-   switch(clientref)
-   {
-      case 4:
-        {
-          sendCommandMsg(AudioPlayer::SHORT_UPDATE);
-          break;
-        }
-      case 3:
-        {
-          Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "infoEnd");
-          destroyInfo(true);
-          if (audioEnabled) {
-            //we only did show the audio error info if audio is enabled
-            bool stillError=false;
-            if (AudioPlayer * player=getPlayer(false)) {
-              stillError=player->getState()==AudioPlayer::S_ERROR;
-            }
-            if (stillError) {
-              sendCommandMsg(AudioPlayer::STREAM_END);
-            }
-          }
-          break;
-        }
-      case 1:
-        if (! slideshow) return;
-        Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "slideshow");
-        sendCommandMsg(EVENT_SLIDESHOW);
-        break;
-      case 2:
-        Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "pictureBannerEnd");
-        destroyPictureBanner(true);
-        break;
-    }
-   
-  }
-
-#define INFOBUF 2000
-void VMediaView::showPictureInfo(){
-  if (! pictureEnabled || audioEnabled) return;
-  if (info) destroyInfo();
-  if (! currentPicture) return;
-
-  info=new VInfo();
-  info->setTitleText(currentPicture->getFileName());
-  info->setDropThrough();
-  info->setSize(500, 300);
-  info->createBuffer();
-  info->setBorderOn(1);
-  info->setTitleBarOn(1);
-
-  if (Video::getInstance()->getFormat() == Video::PAL)
-        info->setPosition(100, 180);
-  else
-        info->setPosition(100, 150);
-  char buf[INFOBUF];
-  char tbuf[Media::TIMEBUFLEN];
-  //modes should come from mediaoptions...
-  const char *mode=NULL;
-  switch (currentControl->mode) {
-    case WJpeg::CROPPERCENT:
-      mode="clipfactor";
-      break;
-    case WJpeg::LETTER:
-      mode="letter";
-      break;
-    default:
-      mode="clip";
-      break;
-  }
-  const char *dirname=parent->getDirname(MEDIA_TYPE_PICTURE);
-  int ldir=0;
-  const char *prfx="";
-  if (dirname) ldir=strlen(dirname);
-  if (ldir > 35){
-    dirname=dirname+ldir-35;
-    prfx="...";
-  }
-  SNPRINTF(buf,INFOBUF,"%s= %s%s\n%s= %u x %u\n%s= %lu kBytes\n%s= %s\n%s= %u\n%s= %u%%\n%s= %s",
-     tr("Directory"), prfx,dirname,
-     tr("Format(px)"),currentControl->picw,currentControl->pich,
-     tr("Filesize"),currentControl->compressedSize/1000,
-     tr("Time"),currentPicture->getTimeString(tbuf),
-     tr("Rotation"),90*currentControl->finalRotation,
-     tr("Scale"),currentControl->scale,
-     tr("Picture Mode"),mode );
-  info->setMainText(buf);
-  info->draw();
-  BoxStack::getInstance()->add(info);
-  BoxStack::getInstance()->update(info);
-  Timers::getInstance()->setTimerD(this,3,8);
-}
-void VMediaView::updatePictureInfo(){
-  if (info) {
-    showPictureInfo();
-    }
-}
-void VMediaView::destroyInfo(bool fromTimer){
-  if (info) {
-    if (! fromTimer) {
-      Log::getInstance()->log("VMediaView",Log::DEBUG,"remove info %p",info);
-      BoxStack::getInstance()->remove(info);
-    }
-    else {
-      Log::getInstance()->log("VMediaView",Log::DEBUG,"trigger remove info %p",info);
-      sendViewMsg(info);
-    }
-    info=NULL;
-    }
-  if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);
-  if (! fromTimer) Timers::getInstance()->cancelTimer(this,4);
-}
-
-void VMediaView::sendViewMsg(Boxx *v) {
-  Message* m = new Message(); 
-  m->message = Message::CLOSE_ME;
-  m->to = BoxStack::getInstance();
-  m->from = v;
-  m->parameter=(ULONG)v;
-  Command::getInstance()->postMessageFromOuterSpace(m);
-}
-void VMediaView::sendCommandMsg(int command) {
-  Message* m = new Message(); 
-  //we misuse PLAYER_EVENT here
-  m->message = Message::PLAYER_EVENT;
-  m->to = this;
-  m->from = this;
-  m->parameter= command;
-  Command::getInstance()->postMessageFromOuterSpace(m);
-}
-
-void VMediaView::enableBanner(bool enable) {
-  bannerEnabled=false;
-  updatePictureBanner();
-}
-
-void VMediaView::getDrawingParam(Surface *&sfc,WJpeg::JpegControl *&c){
-  if (secondSurface()) {
-    //we currently display on sfc2
-    sfc=sfc1;
-    c=&ctl;
-  }
-  else {
-    sfc=sfc2;
-    c=&ctl2;
-  }
-}
-void VMediaView::switchSurface(){
-  if (secondSurface()) {
-    //now we switch to sfc1
-    surface=sfc1;
-    currentControl=&ctl;
-  }
-  else {
-    surface=sfc2;
-    currentControl=&ctl2;
-  }
-}
-
-AudioPlayer * VMediaView::getPlayer(bool createIfNeeded)
-{
-  AudioPlayer* rt=AudioPlayer::getInstance(this,false);
-  if (! createIfNeeded && rt == NULL) return NULL;
-  if (rt == NULL) {
-    rt=AudioPlayer::getInstance(this);
-    rt->run();
-  }
-  return rt;
-}
-
-bool VMediaView::isAudioPlaying() {
-  Log::getInstance()->log("VMediaView::isPlaying", Log::DEBUG, "rt=%s", justPlaying?"true":"false");
-  return justPlaying;
-}
-
-
-
-
-
-
-int VMediaView::play(bool all,bool activate,ULONG move,bool showInfo) {
-  int rt=0;
-  if (getPlayer(false)) getPlayer(false)->stop();
-  justPlaying=false;
-  if (currentAudio) delete currentAudio;
-  currentAudio=NULL;
-  playall=all;
-  currentAudio=parent->getMedia(MEDIA_TYPE_AUDIO,move);
-  audioError=NULL;
-  if ( ! currentAudio || ! currentAudio->getURI()) {
-    Log::getInstance()->log("VMediaView::load", Log::ERR, "no URI in media");
-    audioError=tr("no audio file");
-    if (audioEnabled) sendCommandMsg(EVENT_DIRECTORYDONE);
-    rt= -1;
-  }
-  else {
-    Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",
-      currentAudio->getURI()->getName(),this);
-    int wseq=getPlayer()->play(currentAudio->getURI());
-    if (getPlayer()->waitForSequence(5,wseq)<0) {
-       audioError=tr("unable to open audio file");
-       rt= -1;
-    }
-    else {
-      justPlaying=true;
-      rt=0;
-    }
-    Log::getInstance()->log("VMediaView", Log::DEBUG, "player started for %s",currentAudio->getURI()->getName());
-  }
-  if (activate && ! audioEnabled){
-    if (showInfo) retriggerAudioInfo=true;
-    setAudioMode(true);
-  }
-  else {
-    //avoid duplicate creation of banner and info
-    showAudioBanner();
-    showAudioInfo();
-  }
-  if (activate && (! currentPicture || ! pictureShowing)) draw();
-  BoxStack::getInstance()->update(this);
-  return rt;
-}
-
-void VMediaView::showAudioInfo() {
-  if (! audioEnabled) return;
-  Timers::getInstance()->cancelTimer(this,4);
-  Timers::getInstance()->cancelTimer(this,3);
-  if (info) destroyInfo();
-  if (! retriggerAudioInfo) return;
-  drawAudioInfo();
-  bool playerError=getPlayer()->getState()==AudioPlayer::S_ERROR || audioError;
-  if (! playerError) Timers::getInstance()->setTimerD(this,3,AUDIOBANNER_TIME);
-  else Timers::getInstance()->setTimerD(this,3,AUDIOERROR_TIME);
-       if (! playerError) Timers::getInstance()->setTimerD(this,4, 1);
-  BoxStack::getInstance()->update(info);
-  }
-
-void VMediaView::updateAudioInfo() {
-  if (info) {
-    showAudioInfo();
-    }
-}
-
-void VMediaView::drawAudioInfo(){
-  Log::getInstance()->log("VMediaView",Log::DEBUG, "draw banner for %p",info);
-  const char *title=NULL;
-  char *playerTitle=NULL;
-  bool playerError=false;
-  int numlines=0;
-  int len=0;
-  int num=0;
-  const char *pl=tr("Playlist");
-  const char *first=NULL;
-  char *playerInfo=NULL;
-  if (audioError) {
-    if (getPlayer()->getState() == AudioPlayer::S_PLAY) audioError=NULL;
-  }
-  if (! currentAudio && ! audioError) audioError=tr("no audio file");
-  if (audioError ) {
-    title=tr("MediaError");
-  }
-  else {
-    playerTitle=getPlayer()->getTitle();
-    if (playerTitle) title=playerTitle;
-    else title=currentAudio->getDisplayName();
-    num=parent->getNumEntries(MEDIA_TYPE_AUDIO,currentAudio->index);
-    playerError=getPlayer()->getState() == AudioPlayer::S_ERROR;
-    //1more line for long dirs
-    numlines=playall?5:4;
-  }
-  if (playerError) {
-    numlines=3;
-    first=tr("Unable to play audio file");
-    len=strlen(first)+3;
-  }
-  else if (audioError) {
-    numlines=3;
-    first=audioError;
-    len=strlen(first)+3;
-  }
-  else {
-    playerInfo=getPlayer()->getID3Info();drawText(tr("Loading"),5,3,Colour::LIGHTTEXT);
-    len=strlen(currentAudio->getDisplayName())+strlen(pl)+30+strlen(parent->getDirname(MEDIA_TYPE_AUDIO))+Media::TIMEBUFLEN+110;
-    if (playerInfo) {
-      for (UINT i=0;i<strlen(playerInfo);i++) 
-        if (playerInfo[i] == '\n') numlines++;
-      len+=strlen(playerInfo);
-      first=playerInfo;
-    }
-    else {
-      first="";
-    }
-  }
-  destroyInfo();
-  info=new VInfo();
-  UINT height=numlines*30+60;
-  UINT vheight=Video::getInstance()->getScreenHeight();
-  UINT vwidth=Video::getInstance()->getScreenWidth();
-  if (height > vheight-2*AUDIOBANNER_BOTTOM_MARGIN)
-    height=vheight-2*AUDIOBANNER_BOTTOM_MARGIN;
-  info->setSize(vwidth -2*AUDIOBANNER_X_MARGIN, height);
-  info->createBuffer();
-  if (Video::getInstance()->getFormat() == Video::PAL)
-  {
-    info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);
-  }
-  else
-  {
-    info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);
-  }
-
-  info->setTitleBarOn(0);
-  info->setDropThrough();
-  //from vvideorec 
-       //set the regions for the closcks and bars on banner
-  barRegion.x = info->getWidth()-AUDIOBARLEN-20;
-  barRegion.y = info->getHeight() - 30;   // FIXME, need to be - 1? and below?
-  barRegion.w = info->getWidth()-AUDIOBARLEN+10;
-  barRegion.h = 30;
-
-  clocksRegion.x = 130;
-  clocksRegion.y = barRegion.y + 3;
-  clocksRegion.w = 190;
-  clocksRegion.h = surface->getFontHeight();
-  Log::getInstance()->log("VMediaView",Log::DEBUG,"created AudioInfo %p",info);
-  BoxStack::getInstance()->add(info);
-  char *buf=new char [len];
-  if (playerError || audioError) {
-    SNPRINTF(buf,len,"%s",first);
-  }
-  else {
-    char tbuf[Media::TIMEBUFLEN];
-    if (playall) {
-    SNPRINTF(buf,len,"%s\n"
-        "%s:%s\n"
-        "%s: %d/%d\n"
-        "%s:%s\n"
-        "%s:%s\n",
-        first,
-        tr("FileName"),currentAudio->getDisplayName(),
-        pl,num,parent->getNumEntries(MEDIA_TYPE_AUDIO),
-        tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),
-        tr("Time"),currentAudio->getTimeString(tbuf));
-    }
-    else {
-    SNPRINTF(buf,len,"%s\n"
-        "%s:%s\n"
-        "%s:%s\n"
-        "%s:%s\n",
-        first,
-        tr("FileName"),currentAudio->getDisplayName(),
-        tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),
-        tr("Time"),currentAudio->getTimeString(tbuf));
-    }
-  }
-  Log::getInstance()->log("VMediaView",Log::DEBUG,"info: (%d)%s",strlen(buf),buf);
-  //now the real drawing functions
-  info->draw();
-  //title
-  info->rectangle(0, 0, info->getWidth(), 30, Colour::TITLEBARBACKGROUND);
-  info->drawText(title, 5, 5, Colour::LIGHTTEXT);
-  info->drawPara(buf,5,32,Colour::LIGHTTEXT);
-  delete [] buf;
-  if (! audioError) {
-    WSymbol w;
-    info->TEMPADD(&w);
-    int x=10;
-    int ybottom=info->getHeight();
-    info->rectangle(0, ybottom - barRegion.h, info->getWidth(), barRegion.h, Colour::TITLEBARBACKGROUND);
-    bool drawSymbol=true;
-    switch(getPlayer()->getState()) {
-      case AudioPlayer::S_PAUSE:
-        w.nextSymbol = WSymbol::PAUSE;
-        break;
-      case AudioPlayer::S_PLAY:
-        w.nextSymbol = WSymbol::PLAY;
-        break;
-      case AudioPlayer::S_DONE:
-        if (playall) 
-          w.nextSymbol = WSymbol::PLAY;
-        else
-          drawSymbol=false;
-        break;
-      case AudioPlayer::S_BACK:
-        w.nextSymbol = WSymbol::FBWD ;
-        break;
-      case AudioPlayer::S_FF:
-        w.nextSymbol = WSymbol::FFWD ;
-        break;
-      default:
-        drawSymbol=false;
-        break;
-    }
-    if (drawSymbol) {
-      w.setPosition(x, ybottom-24);
-      w.draw();
-    }
-    else {
-      //stop symbol
-      info->rectangle(x, ybottom - 23, 18, 16, Colour::LIGHTTEXT);
-    }
-    x+=30;
-    drawAudioClocks();
-  }
-  if (playerInfo) delete playerInfo;
-  if (playerTitle) delete playerTitle;
-}
-
-void VMediaView::drawAudioClocks() {
-       if (! info || ! audioEnabled) return;
-       Log::getInstance()->log("VMediaView::drawAudioClocks", Log::DEBUG, "");
-  //draw clocks and bar
-  info->rectangle(clocksRegion, Colour::TITLEBARBACKGROUND);
-
-  time_t currentSec = (time_t)(getPlayer()->getCurrentTimes());
-  time_t lengthSec=(time_t)(getPlayer()->getSonglen());
-       struct tm cpos;
-       struct tm slen;
-/*     gmtime_r(&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, Colour::LIGHTTEXT);
-  
-       // Draw progress bar
-  int progBarXbase = 0;
-       int barlen=250;
-
-  info->rectangle(barRegion.x + progBarXbase, barRegion.y + 3, barlen+10, 24, Colour::LIGHTTEXT);
-  info->rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 5, barlen+6, 20, barBlue);
-
-  if (currentSec > lengthSec) currentSec=lengthSec;
-  if (lengthSec == 0) return;
-
-  // Draw yellow portion
-  int progressWidth = (barlen+2) * currentSec / lengthSec;
-  info->rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 7, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-
-}
-
-void VMediaView::showAudioBanner() {
-  destroyAudioBanner();
-  if (! audioEnabled) return;
-  audioBanner=new VInfo();
-  Log::getInstance()->log("VMediaView",Log::DEBUG,"creating AudioBanner %p", audioBanner);
-  Video *v=Video::getInstance();
-  audioBanner->setSize(v->getScreenWidth()-100, 36);
-  audioBanner->createBuffer();
-  audioBanner->setPosition(50, v->getScreenHeight()-50);
-  audioBanner->fillColour(audioBannerBack);
-  audioBanner->setTitleBarOn(0);
-  audioBanner->setDropThrough();
-  if ( ! currentAudio || ! currentAudio->getDisplayName() || audioError) {
-    audioBanner->drawText(tr("AudioPlayer - not playing"),5,3,Colour::LIGHTTEXT);
-  }
-  else {
-    char * buf=new char[strlen(currentAudio->getDisplayName())+50];
-    SNPRINTF(buf,50,"%s %s",tr("AudioPlayer"),currentAudio->getDisplayName());
-    audioBanner->drawText(buf,5,3,Colour::LIGHTTEXT);
-    delete buf;
-  }
-  BoxStack::getInstance()->add(audioBanner);
-  BoxStack::getInstance()->update(audioBanner);
-}
-
-void VMediaView::destroyAudioBanner() {
-  if (audioBanner) {
-    Log::getInstance()->log("VMediaView",Log::DEBUG,"deleting AudioBanner %p",audioBanner);
-    BoxStack::getInstance()->remove(audioBanner);
-    audioBanner=NULL;
-  }
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon, Andreas Vogel\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include <time.h>\r
+\r
+#include "vmediaview.h"\r
+\r
+#include "vpicturebanner.h"\r
+#include "vcolourtuner.h"\r
+#include "audioplayer.h"\r
+#include "timers.h"\r
+#include "boxx.h"\r
+#include "wselectlist.h"\r
+#include "remote.h"\r
+#include "wsymbol.h"\r
+#include "boxstack.h"\r
+#include "vdr.h"\r
+#include "media.h"\r
+#include "video.h"\r
+#include "vinfo.h"\r
+#include "i18n.h"\r
+#include "message.h"\r
+#include "command.h"\r
+#include "mediaoptions.h"\r
+#include "mediaplayer.h"\r
+#include "log.h"\r
+\r
+const int VMediaView::EVENT_SLIDESHOW=100;\r
+const int VMediaView::EVENT_DRAWINGDONE=101;\r
+const int VMediaView::EVENT_DRAWINGERROR=102;\r
+const int VMediaView::EVENT_DIRECTORYDONE=103;\r
+\r
+\r
+/**\r
+  * the combined user interface for pictures and audio\r
+  * has 2 surfaces to enable drawing in a separate thread\r
+  * the info display can either show a picture info or and audio info\r
+  * if the audio player comes on top it disables the picture info display\r
+  * basically we have 3 modes:\r
+  *   - HIDDEN viewer is hidden (pictureEnabled=false, audioEnabled=false)\r
+  *     if justPlaying=true the audioplayer is still running\r
+  *   - PICTURE picture viewer on top ("slide show") - pictureEnabled=true, audioEnabled=false\r
+  *     no AudioBanner visible\r
+  *     if justPlaying=true the audio player runs in bg\r
+  *   - AUDIO audioPlayer on top ("playlist mode") - pictureEnabled=true, audioEnabled=true\r
+  *     the picture viewer is currently halted (should be able to continue if no AudioInfo)\r
+  *     no picture banner (we should have an audio banner to indicate the audio player on top!)\r
+  * state transitions (via setPictureMode, setAudioMode)\r
+  *   - show Picture -> pictureEnabled=true, \r
+  *     only called from command handler if audioEnabled=false\r
+  *     call from mediaList only possible if audioEnabled=false\r
+  *         *** TODO: would be better to have separate function for external call/internal call\r
+  *   - play [Audio] -> if activate is set -> audioEnabled=true (-> Mode AUDIO)\r
+  *                     used for calls from medialist\r
+  *                     internal calls do not set activate!\r
+  *   - YELLOW key - toggle\r
+  *     if audioActive==true -> audioActive=false (new mode depends on pictureEnabled - either HIDDEN or PICTURE)\r
+  *     if audioActive==false -> audioActive=true (new mode AUDIO)\r
+  *          *** open handling if no audio file there (ignore key???) - currently empty player\r
+  *   - BACK if mode AUDIO -> audioEnabled=false, justPlaying=false\r
+  *   - BACK if mode PICTURE -> pictureEnabled=false;\r
+  *   - player StreamEnd -> audioEnabled=false (new mode depends on pciture - either HIDDEN or PICTURE)\r
+  * info/banner handling:\r
+  *   - AudioInfo - alternativ to pictureInfo\r
+  *     off when disabling audio or after timer or with OK in AUDIO mode\r
+  *     on currently any command or player event (end/new song) when audioEnabled==true and retriggerAudioInfo=true\r
+  *     on on OK in AUDIO mode\r
+  *   - Picture Info\r
+  *     off when disabling Picture or after timer, OK, green\r
+  *     on only on green when pictureEnabled==true\r
+  *   - PictureBanner\r
+  *     2 modes: loading/normal\r
+  *       normal:\r
+  *       off when disabling picture, OK, after timer\r
+  *       on when enabling picture, with OK\r
+  *       loading:\r
+  *       off when disabling picture and when loading done\r
+  *       on on start loading\r
+  *          *** open: do not show when audio enabled and slide show running (currently slideshow is paused)\r
+  *   - AudioBanner\r
+  *       always shown when audioEnabled=true\r
+  *       on when enabling Audio\r
+  *       off when disabling audio\r
+  *       update in play\r
+  * timers: 1 - slide show\r
+  *         2 - pictureBanner\r
+  *         3 - info showtime\r
+  *         4 - audio short update\r
+  */\r
+\r
+#define DRAWING_THREAD\r
+\r
+Colour VMediaView::pictureBack=Colour(140,140,140);\r
+Colour VMediaView::infoBack=Colour(110,110,110);\r
+Colour VMediaView::audioBannerBack=Colour(110,110,110,20);\r
+//the jpeg reader\r
+\r
+//how long do we wait for a single picture chunk\r
+//the unit is 100ms (the timeout on the server side)\r
+#define MAXTRY 100 \r
+class VPreader : public JpegReader {\r
+  private:\r
+    ImageReader *reader;\r
+    VMediaView * parent;\r
+    ULLONG size;\r
+    bool dobreak;;\r
+  public:\r
+  VPreader(VMediaView *p,ImageReader *r){ \r
+    parent=p;\r
+    size=0;\r
+    reader=r;\r
+    dobreak=false;\r
+  };\r
+  virtual ULONG readChunk(ULONG offset,ULONG len,char ** buf) {\r
+     Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "read chunk o=%d,len=%d,buf=%p",\r
+        offset,len,*buf);\r
+     UINT numrec=0;\r
+     int rt=0;\r
+     for (int trycount=0;trycount < MAXTRY && ! dobreak && numrec == 0 && rt == 0;trycount++) {\r
+       if (dobreak) {\r
+         *buf=NULL;\r
+         rt=-1;\r
+       }\r
+       else {\r
+         rt=reader->getImageChunk((ULLONG)offset,(UINT)len,&numrec,(UCHAR **)buf);\r
+       }\r
+     }\r
+     Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "got n=%d,buf=%p,rt=%d",\r
+        numrec,*buf,rt);\r
+     return numrec;\r
+     }\r
+  virtual int initRead(const MediaURI *uri,ULLONG *sz,ULONG factor=100) {\r
+     Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s",uri->getDisplayName());\r
+     Video* video = Video::getInstance();\r
+     dobreak=false;\r
+     int rt=MediaPlayer::getInstance()->openMedium(1,uri,sz,video->getScreenWidth()*factor/100, video->getScreenHeight()*factor/100);\r
+     if (rt < 0) *sz=0;\r
+     size=*sz;\r
+     Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s returned %llu",uri->getDisplayName(),size);\r
+     return rt;\r
+     }\r
+  virtual ULONG getSize() {return size;}\r
+  //seems to be thread safe (more or less...)\r
+  void setBreak() {\r
+    dobreak=true;\r
+  }\r
+};\r
+\r
+/**\r
+  * a separate thread for drawing pictures\r
+  * will be started with the sfc and the draw control\r
+  * will send a player event when done\r
+  */\r
+class DrawingThread : public Thread_TYPE {\r
+  private:\r
+    VMediaView *_parent;\r
+    VPreader * _reader;\r
+    WJpeg::JpegControl *_ctl;\r
+    Surface *_sfc;\r
+    Colour _colour;\r
+    bool _interrupted;\r
+  public:\r
+    DrawingThread(VMediaView *parent) {\r
+      _parent=parent;\r
+      _reader=NULL;\r
+      _ctl=NULL;\r
+      _sfc=NULL;\r
+      _interrupted=false;\r
+    }\r
+    virtual ~DrawingThread(){}\r
+    bool isRunning() {\r
+      return (threadIsActive()!=0);\r
+    }\r
+    bool start(WJpeg::JpegControl *ctl,Surface *sfc,VPreader *reader,Colour &c) {\r
+      if (isRunning()) {\r
+        return false;\r
+      }\r
+      _interrupted=false;\r
+      _ctl=ctl;\r
+      _sfc=sfc;\r
+      _reader=reader;\r
+      _colour=c;\r
+      return (threadStart() == 1);\r
+    }\r
+    bool stop() {\r
+      Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop initiated");\r
+      if (threadIsActive()) {\r
+        _interrupted=true;\r
+        if (_reader) _reader->setBreak();\r
+        threadStop();\r
+      }\r
+      Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop done");\r
+      _reader=NULL;\r
+      return true;\r
+    }\r
+  protected:\r
+    virtual void threadMethod() {\r
+      Log::getInstance()->log("DrawingThread",Log::DEBUG,"started");\r
+      bool rt=WJpeg::drawJpeg(_ctl,_sfc,_reader,_colour);\r
+      _reader=NULL;\r
+      if (! _interrupted) {\r
+        Message* m = new Message(); \r
+        //we misuse PLAYER_EVENT here\r
+        m->message = Message::PLAYER_EVENT;\r
+        m->to = _parent;\r
+        m->from = _parent;\r
+        m->parameter= rt?VMediaView::EVENT_DRAWINGDONE:VMediaView::EVENT_DRAWINGERROR;\r
+        Command::getInstance()->postMessageFromOuterSpace(m);\r
+      }\r
+      Log::getInstance()->log("DrawingThread",Log::DEBUG,"finishing interrupt=%d",(int)_interrupted);\r
+    }\r
+    virtual void threadPostStopCleanup() {}\r
+\r
+};\r
+\r
+\r
+VMediaView::VMediaView(VMediaList *p)\r
+{\r
+  Log::getInstance()->log("VMediaView::VMediaView", Log::DEBUG, "p=%p", this);\r
+  audioEnabled=false;\r
+  pictureEnabled=false;\r
+  parent=p;\r
+  ireader=new ImageReader(1,MediaPlayer::getInstance());\r
+  reader=new VPreader(this,ireader);\r
+  //the surface handling\r
+  Video* video = Video::getInstance();\r
+  setSize(video->getScreenWidth(), video->getScreenHeight());\r
+  createBuffer();\r
+  sfc2=getSurface();\r
+  surface=NULL;\r
+  //create the second surface\r
+  createBuffer();\r
+  sfc1=getSurface();\r
+  originalh=area.h;\r
+  originalw=area.w;\r
+  //disable the surface\r
+  area.h=1;\r
+  area.w=1;\r
+  //banners and infos\r
+  pictureBanner=NULL;\r
+  slideshow=false;\r
+  pictureError=NULL;\r
+  currentPicture=NULL;\r
+  info=NULL;\r
+  pictureLoading=false;\r
+\r
+  //picture settings\r
+  showtime=INITIAL_SHOWTIME;\r
+  rotate=WJpeg::ROT_0;\r
+  currentScale=1;\r
+  options=MediaOptions::getInstance();\r
+  VColourTuner::initFactors();\r
+  int st=options->getIntOption("SlideShowInterval");\r
+  if (st > 0) showtime=st;\r
+  ctl.area.w=originalw;\r
+  ctl.area.h=originalh;\r
+  ctl.enlarge=false;\r
+  ctl.scaleafter=options->getIntOption("ScaleFactor");\r
+  const char * mode=options->getStringOption("PictureMode");\r
+  if (strcmp(mode,"clip") == 0) ctl.mode=WJpeg::CROP;\r
+  else if (strcmp(mode,"letter") == 0) ctl.mode=WJpeg::LETTER;\r
+  else if (strcmp(mode,"clipfactor") == 0) ctl.mode=WJpeg::CROPPERCENT;\r
+  ctl.scaleAmount=options->getIntOption("PictureSize");\r
+  if (ctl.scaleAmount < 10) ctl.scaleAmount=10;\r
+  if (ctl.scaleAmount > 200) ctl.scaleAmount=200;\r
+  ctl2=ctl;\r
+  cropmode=ctl.mode;\r
+  //current control is the one used for DISPLAY (not the one for drawing - this is the other one)\r
+  //this is closely coupled to the surface - i.e. ctl is for sfc1, ctl2 for sfc2\r
+  currentControl=&ctl;\r
+  bannerEnabled=true;\r
+  pictureShowing=false;\r
+\r
+  //audio player\r
+\r
+  barBlue.set(0, 0, 150, 150);\r
+  audioError=NULL;\r
+  currentAudio=NULL;\r
+  justPlaying=false;\r
+  playall=false;\r
+  retriggerAudioInfo=false;\r
+  audioBanner=NULL;\r
+  drawingThread=new DrawingThread(this);\r
+}\r
+\r
+VMediaView::~VMediaView()\r
+{\r
+  Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "p=%p,secondSfc=%s", this,(secondSurface()?"true":"false"));\r
+  destroyPictureBanner();\r
+  if (currentPicture) delete currentPicture;\r
+  Timers::getInstance()->cancelTimer(this,1);\r
+  Timers::getInstance()->cancelTimer(this,2);\r
+  Timers::getInstance()->cancelTimer(this,3);\r
+  Timers::getInstance()->cancelTimer(this,4);\r
+  Timers::getInstance()->cancelTimer(this,5);\r
+  destroyInfo();\r
+  destroyAudioBanner();\r
+  if (getPlayer(false)) {\r
+    AudioPlayer::getInstance(NULL,false)->shutdown();\r
+  }\r
+  if (currentAudio) delete currentAudio;\r
+  drawingThread->stop();\r
+  ireader->shutdown();\r
+  delete ireader;\r
+  delete reader;\r
+  if (secondSurface()) {\r
+    delete sfc1;\r
+    sfc1=NULL;\r
+  }\r
+  else {\r
+    delete sfc2;\r
+    sfc2=NULL;\r
+  }\r
+  MediaPlayer::getInstance()->closeMediaChannel(1);\r
+  MediaPlayer::getInstance()->closeMediaChannel(2);\r
+  Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "done p=%p", this);\r
+}\r
+\r
+void VMediaView::setPictureMode(bool act) {\r
+  Log::getInstance()->log("VMediaView", Log::DEBUG, "set pictureMode %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);\r
+  if ( act) {\r
+    if ( ! pictureEnabled && ! audioEnabled) {\r
+      area.h=originalh;\r
+      area.w=originalw;\r
+      showPictureBanner();\r
+      parent->updateAll();\r
+    }\r
+    if (! pictureEnabled) {\r
+      //we newly enable the picture - so clear the screen\r
+      draw();\r
+      BoxStack::getInstance()->update(this);\r
+      if (slideshow) startSlideshow();\r
+    }\r
+  }\r
+  else \r
+  {\r
+    if ( pictureEnabled) {\r
+      destroyPictureBanner();\r
+      stopSlideshow(false);\r
+#ifdef DRAWING_THREAD\r
+      drawingThread->stop();\r
+#endif\r
+      if (! audioEnabled) {\r
+        destroyInfo();\r
+        area.w=1;\r
+        area.h=1;\r
+        draw();\r
+        parent->updateAll();\r
+      }\r
+    }\r
+    pictureShowing=false;\r
+  }\r
+  pictureEnabled=act;\r
+}\r
+\r
+//we can disable audio without automatically hiding us\r
+//this will become strange - we are visible but do not handle\r
+//keys - so if you call setAudioMode(false,false) be sure\r
+//to call setAudioMode(false,true) afterwards\r
+//it is only here to give the list a chance to start a new play\r
+//when we call directoryDone\r
+void VMediaView::setAudioMode(bool act,bool doHiding) {\r
+  Log::getInstance()->log("VMediaView", Log::DEBUG, "setAudioMode  %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);\r
+  if ( act) {\r
+    if (! audioEnabled) {\r
+      if (! pictureEnabled) {\r
+        area.w=originalw;\r
+        area.h=originalh;\r
+        draw(); //empty screen if no picture\r
+        parent->updateAll();\r
+      }\r
+      destroyPictureBanner();\r
+\r
+    }\r
+    audioEnabled=true;\r
+    showAudioBanner();\r
+    showAudioInfo();\r
+  }\r
+  else \r
+  {\r
+    if ( audioEnabled) {\r
+      audioEnabled=false;\r
+      destroyInfo();\r
+      destroyAudioBanner();\r
+    }\r
+    if (! pictureEnabled  && doHiding) {\r
+      area.w=1;\r
+      area.h=1;\r
+      draw();\r
+      parent->updateAll();\r
+    }\r
+    else {\r
+      //picture now on top\r
+      if (havePictureBanner && ! pictureBanner) showPictureBanner();\r
+    }\r
+  }\r
+}\r
+\r
+\r
+\r
+void VMediaView::draw()\r
+{\r
+  Log::getInstance()->log("VMediaView::draw", Log::DEBUG, "pictureError=%s,p=%p", pictureError,this);\r
+  \r
+  if (pictureShowing ) fillColour(pictureBack);\r
+  else fillColour(Colour::BLACK);\r
+  if (pictureError) {\r
+    drawText(pictureError,100,area.h/2,Colour::LIGHTTEXT);\r
+    return;\r
+    }\r
+}\r
+\r
+\r
+int VMediaView::handleCommand(int command)\r
+{\r
+  Log::getInstance()->log("VMediaView::handleCommand", Log::DEBUG, "cmd=%d,p=%p", command,this);\r
+  if ( !audioEnabled && ! pictureEnabled ) {\r
+    //only handle YELLOW\r
+    if (command == Remote::YELLOW) {\r
+      setAudioMode(true);\r
+      return 1;\r
+    }\r
+    return 0;\r
+  }\r
+  if ( ! audioEnabled) {\r
+    //------------------------- command in mode PICTURE (i.e. picture is on top) ----------------\r
+    //picture on top\r
+    int rt=1;\r
+    switch(command)\r
+    {\r
+      case Remote::DF_UP:\r
+      case Remote::UP:\r
+      case Remote::SKIPBACK:\r
+        rotate=WJpeg::ROT_0;\r
+        showPicture(VMediaList::MV_PREV,slideshow,true);\r
+        rt= 2;\r
+        break;\r
+      case Remote::FORWARD:\r
+        if (showtime > 1) showtime--;\r
+        updatePictureBanner(true);\r
+        break;\r
+      case Remote::DF_DOWN:\r
+      case Remote::DOWN:\r
+      case Remote::SKIPFORWARD:\r
+        rotate=WJpeg::ROT_0;\r
+        showPicture(VMediaList::MV_NEXT,slideshow,true);\r
+        rt= 2;\r
+        break;\r
+      case Remote::REVERSE:\r
+        if (showtime < 50 ) showtime++;\r
+        updatePictureBanner(true);\r
+        break;\r
+      case Remote::OK:\r
+      {\r
+        if (pictureBanner) {\r
+          destroyPictureBanner();\r
+          destroyInfo();\r
+          havePictureBanner=false;\r
+          }\r
+        else {\r
+          havePictureBanner=true;\r
+          showPictureBanner(pictureLoading);\r
+        }\r
+        rt= 2;\r
+      }\r
+      break;\r
+      case Remote::PLAY:\r
+      {\r
+        slideshow=true;\r
+        rotate=WJpeg::ROT_0;\r
+        showPicture(VMediaList::MV_NEXT,slideshow,true);\r
+        rt= 2;\r
+      }\r
+      break;\r
+      case Remote::PAUSE:\r
+        if (slideshow) {\r
+          stopSlideshow(true);\r
+          updatePictureBanner();\r
+        }\r
+        else {\r
+          slideshow=true;\r
+          rotate=WJpeg::ROT_0;\r
+          showPicture(VMediaList::MV_NEXT,slideshow,true);\r
+        }\r
+        rt= 2;\r
+        break;\r
+      case Remote::STOP:\r
+        stopSlideshow(true);\r
+        showtime=INITIAL_SHOWTIME;\r
+        updatePictureBanner();\r
+        rt= 2;\r
+        break;\r
+      case Remote::RED:\r
+        switch(rotate) {\r
+          case WJpeg::ROT_0:\r
+            rotate=WJpeg::ROT_90;\r
+            break;\r
+          case WJpeg::ROT_90:\r
+            rotate=WJpeg::ROT_180;\r
+            break;\r
+          case WJpeg::ROT_180:\r
+            rotate=WJpeg::ROT_270;\r
+            break;\r
+          case WJpeg::ROT_270:\r
+            rotate=WJpeg::ROT_0;\r
+            break;\r
+          }\r
+        showPicture(VMediaList::MV_NONE,slideshow,true);\r
+        rt=2;\r
+        break;\r
+      case Remote::GREEN:\r
+        if (info) destroyInfo();\r
+        else showPictureInfo();\r
+        rt=2;\r
+        break;\r
+      case Remote::BLUE:\r
+        switch (cropmode) {\r
+          case WJpeg::CROP:\r
+            cropmode=WJpeg::LETTER;\r
+            break;\r
+          case WJpeg::LETTER:\r
+            cropmode=WJpeg::CROPPERCENT;\r
+            break;\r
+          default:\r
+            cropmode=WJpeg::CROP;\r
+            break;\r
+        }\r
+        showPicture(VMediaList::MV_NONE,slideshow,true);\r
+        rt=2;\r
+        break;\r
+      case Remote::MENU: {\r
+        stopSlideshow(true);\r
+        destroyPictureBanner();\r
+        destroyInfo();\r
+        VColourTuner *ct=new VColourTuner();\r
+        BoxStack::getInstance()->add(ct);\r
+        ct->draw();\r
+        BoxStack::getInstance()->update(ct);\r
+        rt=2;\r
+       \r
+                         } break;\r
+      case Remote::BACK:\r
+      {\r
+        setPictureMode(false);\r
+        rt= 2;\r
+      }\r
+      break;\r
+      case Remote::YELLOW:\r
+      {\r
+        setAudioMode(true);\r
+      }\r
+    }\r
+    return rt;\r
+  } \r
+  else \r
+  {\r
+    int rt=1;\r
+    bool updateInfo=false;\r
+    //------------------------- command in mode AUDIO (i.e. audio is on top) ----------------\r
+    switch(command)\r
+    {\r
+      case Remote::YELLOW:\r
+        setAudioMode(false);\r
+        rt=2;\r
+        break;\r
+      case Remote::DF_UP:\r
+      case Remote::UP:\r
+        play(playall,false,VMediaList::MV_PREV);\r
+        rt= 2;\r
+        break;\r
+      case Remote::FORWARD:\r
+        if (! audioError) getPlayer()->fastForward();\r
+        updateInfo=true;\r
+        rt=2;\r
+        break;\r
+      case Remote::DF_DOWN:\r
+      case Remote::DOWN:\r
+        play(playall,false,VMediaList::MV_NEXT);\r
+        rt= 2;\r
+        break;\r
+      case Remote::SKIPFORWARD:\r
+        if (! audioError) getPlayer()->skipForward(10);\r
+        rt=2;\r
+        break;\r
+      case Remote::SKIPBACK:\r
+        if (! audioError) getPlayer()->skipBackward(10);\r
+        rt=2;\r
+        break;\r
+      case Remote::REVERSE:\r
+        rt=2;\r
+        break;\r
+      case Remote::ZERO:\r
+        if (! audioError) getPlayer()->jumpToPercent(0);\r
+        rt=2;\r
+        break;\r
+      case Remote::ONE:\r
+        if (! audioError) getPlayer()->jumpToPercent(10);\r
+        rt=2;\r
+        break;\r
+      case Remote::TWO:\r
+        if (! audioError) getPlayer()->jumpToPercent(20);\r
+        rt=2;\r
+        break;\r
+      case Remote::THREE:\r
+        if (! audioError) getPlayer()->jumpToPercent(30);\r
+        rt=2;\r
+        break;\r
+      case Remote::FOUR:\r
+        if (! audioError) getPlayer()->jumpToPercent(40);\r
+        rt=2;\r
+        break;\r
+      case Remote::FIVE:\r
+        if (! audioError) getPlayer()->jumpToPercent(50);\r
+        rt=2;\r
+        break;\r
+      case Remote::SIX:\r
+        if (! audioError) getPlayer()->jumpToPercent(60);\r
+        rt=2;\r
+        break;\r
+      case Remote::SEVEN:\r
+        if (! audioError) getPlayer()->jumpToPercent(70);\r
+        rt=2;\r
+        break;\r
+      case Remote::EIGHT:\r
+        if (! audioError) getPlayer()->jumpToPercent(80);\r
+        rt=2;\r
+        break;\r
+      case Remote::NINE:\r
+        if (! audioError) getPlayer()->jumpToPercent(90);\r
+        rt=2;\r
+        break;\r
+      case Remote::OK:\r
+      case Remote::GREEN:\r
+      {\r
+        if (info) {\r
+          destroyInfo();\r
+          retriggerAudioInfo=false;\r
+          }\r
+        else {\r
+          retriggerAudioInfo=true;\r
+          showAudioInfo();\r
+        }\r
+        if (getPlayer()->getState() == AudioPlayer::S_ERROR) {\r
+          if (playall) play(playall,false,VMediaList::MV_NEXT);\r
+        }\r
+        rt= 2;\r
+      }\r
+      break;\r
+      case Remote::PLAY:\r
+      {\r
+        if (! audioError) getPlayer()->unpause();\r
+        updateInfo=true;\r
+        if (getPlayer()->getState() != AudioPlayer::S_ERROR) ;\r
+        else if (playall) play(playall,false,VMediaList::MV_NEXT);\r
+        rt= 2;\r
+      }\r
+      break;\r
+      case Remote::PAUSE:\r
+        if (! audioError) getPlayer()->pause();\r
+        updateInfo=true;\r
+        rt= 2;\r
+        break;\r
+      case Remote::STOP:\r
+        getPlayer()->stop();\r
+        justPlaying=false;\r
+        updateInfo=true;\r
+        rt= 2;\r
+        break;\r
+      case Remote::BACK:\r
+      {\r
+        getPlayer()->stop();\r
+        playall=false;\r
+        retriggerAudioInfo=false;\r
+        justPlaying=false;\r
+        setAudioMode(false);\r
+        if (! pictureShowing) setPictureMode(false); //could have been delayed\r
+        rt= 2;\r
+      }\r
+      break;\r
+    }\r
+    if (audioEnabled && updateInfo) updateAudioInfo();\r
+    return rt;\r
+  }\r
+}\r
+\r
+void VMediaView::processMessage(Message* m)\r
+{\r
+  Log::getInstance()->log("VMediaView::processMessage", Log::DEBUG, "cmd=%lu,p=%lu", m->message,m->parameter);\r
+  if (m->message == Message::MOUSE_MOVE)\r
+  {\r
+    ;\r
+  }\r
+  else if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    \r
+    //check if press is outside this view! then simulate cancel\r
+    int x=(m->parameter>>16)-getScreenX();\r
+    int y=(m->parameter&0xFFFF)-getScreenY();\r
+    if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
+    }\r
+  }\r
+  else if (m->message = Message::PLAYER_EVENT) {\r
+    switch (m->parameter) {\r
+      case EVENT_SLIDESHOW:\r
+        if (! pictureEnabled) break; //old timer msg...\r
+        //if (! audioEnabled) {\r
+        if (true) {\r
+          if (slideshow) {\r
+            rotate=WJpeg::ROT_0;\r
+            showPicture(VMediaList::MV_NEXT,true,false);\r
+            startSlideshow();\r
+          }\r
+        }\r
+        break;\r
+      case EVENT_DRAWINGERROR:\r
+        drawingDone(true);\r
+        break;\r
+      case EVENT_DRAWINGDONE:\r
+        drawingDone(false);\r
+        break;\r
+      case EVENT_DIRECTORYDONE:\r
+        //just disable audio without (poetntially) hiding us\r
+        //this gives the list a chance to decide whether audio\r
+        //should be on top afterwards without showing the list\r
+        //immediately\r
+        setAudioMode(false,false);\r
+        parent->directoryDone();\r
+        if (! pictureShowing) setPictureMode(false);\r
+        if (! justPlaying) setAudioMode(false);\r
+        break;\r
+      case AudioPlayer::STREAM_ERR:\r
+      case AudioPlayer::STREAM_END:\r
+        if (playall) play(playall,false,VMediaList::MV_NEXT);\r
+        else {\r
+          setAudioMode(false);\r
+          justPlaying=false;\r
+        }\r
+        break;\r
+      case AudioPlayer::SHORT_UPDATE:\r
+                               if (info && audioEnabled ) {\r
+                                       drawAudioClocks();\r
+                                       BoxStack::getInstance()->update(info,&clocksRegion);\r
+                                 BoxStack::getInstance()->update(info,&barRegion);\r
+                                       Timers::getInstance()->setTimerD(this, 4, 1);\r
+                               }\r
+        break;\r
+      case AudioPlayer::NEW_SONG:\r
+        if (audioEnabled) updateAudioInfo();\r
+        break;\r
+      case AudioPlayer::CONNECTION_LOST:\r
+        if (audioEnabled) destroyInfo();\r
+        if (AudioPlayer *player=getPlayer(false)) {\r
+          player->shutdown();\r
+          player=NULL;\r
+        }\r
+        Command::getInstance()->connectionLost();\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+VMediaView * VMediaView::createViewer(VMediaList * mparent) {\r
+   Log::getInstance()->log("VMediaView::createViewer", Log::DEBUG, "p=%p",\r
+        mparent);\r
+   VMediaView *vmn=new VMediaView(mparent);\r
+   BoxStack::getInstance()->add(vmn);\r
+   vmn->draw();\r
+   BoxStack::getInstance()->update(vmn);\r
+   return vmn;\r
+}\r
+\r
+void VMediaView::startSlideshow() {\r
+   slideshow=true;\r
+   if (! pictureLoading) Timers::getInstance()->setTimerD(this,1,showtime);\r
+}\r
+\r
+void VMediaView::stopSlideshow(bool hard) {\r
+   if (hard) slideshow=false;\r
+   Timers::getInstance()->cancelTimer(this,1);\r
+}\r
+\r
+\r
+void VMediaView::showPicture(ULONG move,bool bslideshow,bool activateBanner) {\r
+  pictureShowing=true;\r
+  setPictureMode(true);\r
+  stopSlideshow(true);\r
+#ifdef DRAWING_THREAD\r
+  drawingThread->stop();\r
+#endif\r
+  slideshow=bslideshow;\r
+  Media *newPicture=parent->getMedia(MEDIA_TYPE_PICTURE,move);\r
+  if ( ! newPicture) {\r
+    pictureShowing=false;\r
+    if (!audioEnabled) {\r
+      //within the event handler first directoryDone is called\r
+      //and afterwards everything is stopped if nothing new\r
+      sendCommandMsg(EVENT_DIRECTORYDONE);\r
+    }\r
+    slideshow=false;\r
+  }\r
+  else \r
+  {\r
+    pictureShowing=true;\r
+    if (currentPicture) {\r
+      delete currentPicture;\r
+      currentPicture=NULL;\r
+    }\r
+    currentPicture=newPicture;\r
+    loadPicture(currentPicture,activateBanner);\r
+  }\r
+}\r
+\r
+//the real picture drawing method\r
+//will start drawing on a new surface and will switch it wehn done\r
+\r
+int VMediaView::loadPicture(Media *md,bool activateBanner) {\r
+  pictureError=NULL;\r
+  if (! md) return 1;\r
+  if (! md->getURI()) {\r
+    pictureError=tr("No media found");\r
+    Log::getInstance()->log("VMediaView::load",Log::ERR,"no URI in media");\r
+    return 1;\r
+  }\r
+  Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",\r
+        md->getURI()->getName(),this);\r
+  //do we have a pictureBanner?\r
+  havePictureBanner=pictureBanner!=NULL || activateBanner;\r
+  pictureLoading=true;\r
+#ifdef DRAWING_THREAD\r
+  if (!audioEnabled && havePictureBanner ) showPictureBanner(true);\r
+  drawingThread->stop();\r
+#else\r
+  showPictureBanner(true);\r
+#endif\r
+  ireader->stop();\r
+  ULLONG size=0;\r
+  int rtok=reader->initRead(md->getURI(),&size,ctl.scaleAmount); //scaleAmount is the same for both...\r
+  if (rtok == 0) {\r
+     //now we can really draw\r
+     //get the surface for drawing\r
+     Surface * drawSurface=NULL;\r
+     WJpeg::JpegControl *drawCtl=NULL;\r
+     getDrawingParam(drawSurface,drawCtl);\r
+     drawCtl->error[0]=0;\r
+     drawCtl->rotation=rotate;\r
+     drawCtl->mode=cropmode;\r
+     drawCtl->compressedSize=size;\r
+#ifdef DRAWING_THREAD\r
+     bool ok=drawingThread->start(drawCtl,drawSurface,reader,pictureBack);\r
+     if (! ok) {\r
+       Log::getInstance()->log("VMediaView::load", Log::ERR, "unable to start drawing thread");\r
+       pictureError=tr("JpegError");\r
+       pictureLoading=false;\r
+       destroyPictureBanner();\r
+       return 1;\r
+     }\r
+     return 0;\r
+#else\r
+     //here we could hand this over to the drawing thread\r
+     bool ok=WJpeg::drawJpeg(drawCtl,drawSurface,reader,pictureBack);\r
+     drawingDone(!ok);\r
+     return ok?0:1;\r
+#endif\r
+  }\r
+  pictureLoading=false;\r
+  return 1;\r
+}\r
+\r
+void VMediaView::drawingDone(bool hasError) {\r
+  pictureLoading=false;\r
+  destroyPictureBanner(); //disable loading indication (or real banner)\r
+  if (! hasError) {\r
+    switchSurface();\r
+    Log::getInstance()->log("VMediaView::drawingDone", Log::DEBUG, "success: sfc now=%p",surface);\r
+    pictureError=NULL;\r
+    //only show the pictureBanner if it was there before\r
+    if (havePictureBanner && ! audioEnabled) showPictureBanner();\r
+    Log::getInstance()->log("VMediaView::load", Log::DEBUG, "success" );\r
+    updatePictureInfo(); //will only do somethng if pictureEnabled\r
+  }\r
+  else \r
+  {\r
+    pictureError=tr("JpegError");\r
+    if (pictureEnabled) {\r
+      draw();\r
+      destroyInfo();\r
+    }\r
+  }\r
+  MediaPlayer::getInstance()->closeMediaChannel(1);\r
+#ifndef DRAWING_THREAD\r
+  if (audioEnabled) showAudioBanner();\r
+#endif\r
+  if (slideshow) startSlideshow();\r
+  BoxStack::getInstance()->update(this);\r
+}\r
+\r
+void VMediaView::showPictureBanner(bool loading) {\r
+  //we are in the main thread - so we can (and must) safely hard destroy/create the banner\r
+  Timers::getInstance()->cancelTimer(this,2);\r
+  if (! currentPicture) {\r
+    //hmm...\r
+    destroyPictureBanner(false);\r
+    return;\r
+    }\r
+  if (pictureBanner) destroyPictureBanner(false);\r
+  if (! pictureEnabled || ! bannerEnabled) return;\r
+  pictureBanner= new VPictureBanner(loading, slideshow);\r
+  pictureBanner->fillColour(infoBack);\r
+  if (! loading) {\r
+    int len=strlen(currentPicture->getFileName())+Media::TIMEBUFLEN+20;\r
+    char *buf=new char[len];\r
+    char tbuf[Media::TIMEBUFLEN];\r
+    SNPRINTF(buf,len,"%c%02ds%c %s %s " ,\r
+      slideshow?' ':'[',\r
+      showtime,\r
+      slideshow?' ':']',\r
+      currentPicture->getTimeString(tbuf),\r
+      currentPicture->getFileName()\r
+      );\r
+    pictureBanner->setText(buf);\r
+    delete [] buf;\r
+  }\r
+  else {\r
+    char *buf=new char[strlen(currentPicture->getDisplayName())+50];\r
+    SNPRINTF(buf,50,"%s %s",tr("Loading"), currentPicture->getDisplayName());\r
+    pictureBanner->setText(buf);\r
+    delete buf;\r
+  }\r
+  pictureBanner->draw();\r
+  if (! loading )   Timers::getInstance()->setTimerD(this,2,8);\r
+  BoxStack::getInstance()->add(pictureBanner);\r
+  BoxStack::getInstance()->update(pictureBanner);\r
+  }\r
+\r
+void VMediaView::destroyPictureBanner(bool fromTimer) {\r
+  if (pictureBanner) {\r
+    if (fromTimer) sendViewMsg(pictureBanner); \r
+    else BoxStack::getInstance()->remove(pictureBanner);\r
+    pictureBanner=NULL;\r
+    if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);\r
+    }\r
+}\r
+void VMediaView::updatePictureBanner(bool loading) {\r
+  if (pictureBanner ) {\r
+    showPictureBanner(loading);\r
+    }\r
+}\r
+void VMediaView::timercall(int clientref) {\r
+   Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "id=%d",clientref);\r
+   switch(clientref)\r
+   {\r
+      case 4:\r
+        {\r
+          sendCommandMsg(AudioPlayer::SHORT_UPDATE);\r
+          break;\r
+        }\r
+      case 3:\r
+        {\r
+          Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "infoEnd");\r
+          destroyInfo(true);\r
+          if (audioEnabled) {\r
+            //we only did show the audio error info if audio is enabled\r
+            bool stillError=false;\r
+            if (AudioPlayer * player=getPlayer(false)) {\r
+              stillError=player->getState()==AudioPlayer::S_ERROR;\r
+            }\r
+            if (stillError) {\r
+              sendCommandMsg(AudioPlayer::STREAM_END);\r
+            }\r
+          }\r
+          break;\r
+        }\r
+      case 1:\r
+        if (! slideshow) return;\r
+        Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "slideshow");\r
+        sendCommandMsg(EVENT_SLIDESHOW);\r
+        break;\r
+      case 2:\r
+        Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "pictureBannerEnd");\r
+        destroyPictureBanner(true);\r
+        break;\r
+    }\r
+   \r
+  }\r
+\r
+#define INFOBUF 2000\r
+void VMediaView::showPictureInfo(){\r
+  if (! pictureEnabled || audioEnabled) return;\r
+  if (info) destroyInfo();\r
+  if (! currentPicture) return;\r
+\r
+  info=new VInfo();\r
+  info->setTitleText(currentPicture->getFileName());\r
+  info->setDropThrough();\r
+  info->setSize(500, 300);\r
+  info->createBuffer();\r
+  info->setBorderOn(1);\r
+  info->setTitleBarOn(1);\r
+\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+        info->setPosition(100, 180);\r
+  else\r
+        info->setPosition(100, 150);\r
+  char buf[INFOBUF];\r
+  char tbuf[Media::TIMEBUFLEN];\r
+  //modes should come from mediaoptions...\r
+  const char *mode=NULL;\r
+  switch (currentControl->mode) {\r
+    case WJpeg::CROPPERCENT:\r
+      mode="clipfactor";\r
+      break;\r
+    case WJpeg::LETTER:\r
+      mode="letter";\r
+      break;\r
+    default:\r
+      mode="clip";\r
+      break;\r
+  }\r
+  const char *dirname=parent->getDirname(MEDIA_TYPE_PICTURE);\r
+  int ldir=0;\r
+  const char *prfx="";\r
+  if (dirname) ldir=strlen(dirname);\r
+  if (ldir > 35){\r
+    dirname=dirname+ldir-35;\r
+    prfx="...";\r
+  }\r
+  SNPRINTF(buf,INFOBUF,"%s= %s%s\n%s= %u x %u\n%s= %lu kBytes\n%s= %s\n%s= %u\n%s= %u%%\n%s= %s",\r
+     tr("Directory"), prfx,dirname,\r
+     tr("Format(px)"),currentControl->picw,currentControl->pich,\r
+     tr("Filesize"),currentControl->compressedSize/1000,\r
+     tr("Time"),currentPicture->getTimeString(tbuf),\r
+     tr("Rotation"),90*currentControl->finalRotation,\r
+     tr("Scale"),currentControl->scale,\r
+     tr("Picture Mode"),mode );\r
+  info->setMainText(buf);\r
+  info->draw();\r
+  BoxStack::getInstance()->add(info);\r
+  BoxStack::getInstance()->update(info);\r
+  Timers::getInstance()->setTimerD(this,3,8);\r
+}\r
+void VMediaView::updatePictureInfo(){\r
+  if (info) {\r
+    showPictureInfo();\r
+    }\r
+}\r
+void VMediaView::destroyInfo(bool fromTimer){\r
+  if (info) {\r
+    if (! fromTimer) {\r
+      Log::getInstance()->log("VMediaView",Log::DEBUG,"remove info %p",info);\r
+      BoxStack::getInstance()->remove(info);\r
+    }\r
+    else {\r
+      Log::getInstance()->log("VMediaView",Log::DEBUG,"trigger remove info %p",info);\r
+      sendViewMsg(info);\r
+    }\r
+    info=NULL;\r
+    }\r
+  if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);\r
+  if (! fromTimer) Timers::getInstance()->cancelTimer(this,4);\r
+}\r
+\r
+void VMediaView::sendViewMsg(Boxx *v) {\r
+  Message* m = new Message(); \r
+  m->message = Message::CLOSE_ME;\r
+  m->to = BoxStack::getInstance();\r
+  m->from = v;\r
+  m->parameter=(ULONG)v;\r
+  Command::getInstance()->postMessageFromOuterSpace(m);\r
+}\r
+void VMediaView::sendCommandMsg(int command) {\r
+  Message* m = new Message(); \r
+  //we misuse PLAYER_EVENT here\r
+  m->message = Message::PLAYER_EVENT;\r
+  m->to = this;\r
+  m->from = this;\r
+  m->parameter= command;\r
+  Command::getInstance()->postMessageFromOuterSpace(m);\r
+}\r
+\r
+void VMediaView::enableBanner(bool enable) {\r
+  bannerEnabled=false;\r
+  updatePictureBanner();\r
+}\r
+\r
+void VMediaView::getDrawingParam(Surface *&sfc,WJpeg::JpegControl *&c){\r
+  if (secondSurface()) {\r
+    //we currently display on sfc2\r
+    sfc=sfc1;\r
+    c=&ctl;\r
+  }\r
+  else {\r
+    sfc=sfc2;\r
+    c=&ctl2;\r
+  }\r
+}\r
+void VMediaView::switchSurface(){\r
+  if (secondSurface()) {\r
+    //now we switch to sfc1\r
+    surface=sfc1;\r
+    currentControl=&ctl;\r
+  }\r
+  else {\r
+    surface=sfc2;\r
+    currentControl=&ctl2;\r
+  }\r
+}\r
+\r
+AudioPlayer * VMediaView::getPlayer(bool createIfNeeded)\r
+{\r
+  AudioPlayer* rt=AudioPlayer::getInstance(this,false);\r
+  if (! createIfNeeded && rt == NULL) return NULL;\r
+  if (rt == NULL) {\r
+    rt=AudioPlayer::getInstance(this);\r
+    rt->run();\r
+  }\r
+  return rt;\r
+}\r
+\r
+bool VMediaView::isAudioPlaying() {\r
+  Log::getInstance()->log("VMediaView::isPlaying", Log::DEBUG, "rt=%s", justPlaying?"true":"false");\r
+  return justPlaying;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+int VMediaView::play(bool all,bool activate,ULONG move,bool showInfo) {\r
+  int rt=0;\r
+  if (getPlayer(false)) getPlayer(false)->stop();\r
+  justPlaying=false;\r
+  if (currentAudio) delete currentAudio;\r
+  currentAudio=NULL;\r
+  playall=all;\r
+  currentAudio=parent->getMedia(MEDIA_TYPE_AUDIO,move);\r
+  audioError=NULL;\r
+  if ( ! currentAudio || ! currentAudio->getURI()) {\r
+    Log::getInstance()->log("VMediaView::load", Log::ERR, "no URI in media");\r
+    audioError=tr("no audio file");\r
+    if (audioEnabled) sendCommandMsg(EVENT_DIRECTORYDONE);\r
+    rt= -1;\r
+  }\r
+  else {\r
+    Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",\r
+      currentAudio->getURI()->getName(),this);\r
+    int wseq=getPlayer()->play(currentAudio->getURI());\r
+    if (getPlayer()->waitForSequence(5,wseq)<0) {\r
+       audioError=tr("unable to open audio file");\r
+       rt= -1;\r
+    }\r
+    else {\r
+      justPlaying=true;\r
+      rt=0;\r
+    }\r
+    Log::getInstance()->log("VMediaView", Log::DEBUG, "player started for %s",currentAudio->getURI()->getName());\r
+  }\r
+  if (activate && ! audioEnabled){\r
+    if (showInfo) retriggerAudioInfo=true;\r
+    setAudioMode(true);\r
+  }\r
+  else {\r
+    //avoid duplicate creation of banner and info\r
+    showAudioBanner();\r
+    showAudioInfo();\r
+  }\r
+  if (activate && (! currentPicture || ! pictureShowing)) draw();\r
+  BoxStack::getInstance()->update(this);\r
+  return rt;\r
+}\r
+\r
+void VMediaView::showAudioInfo() {\r
+  if (! audioEnabled) return;\r
+  Timers::getInstance()->cancelTimer(this,4);\r
+  Timers::getInstance()->cancelTimer(this,3);\r
+  if (info) destroyInfo();\r
+  if (! retriggerAudioInfo) return;\r
+  drawAudioInfo();\r
+  bool playerError=getPlayer()->getState()==AudioPlayer::S_ERROR || audioError;\r
+  if (! playerError) Timers::getInstance()->setTimerD(this,3,AUDIOBANNER_TIME);\r
+  else Timers::getInstance()->setTimerD(this,3,AUDIOERROR_TIME);\r
+       if (! playerError) Timers::getInstance()->setTimerD(this,4, 1);\r
+  BoxStack::getInstance()->update(info);\r
+  }\r
+\r
+void VMediaView::updateAudioInfo() {\r
+  if (info) {\r
+    showAudioInfo();\r
+    }\r
+}\r
+\r
+void VMediaView::drawAudioInfo(){\r
+  Log::getInstance()->log("VMediaView",Log::DEBUG, "draw banner for %p",info);\r
+  const char *title=NULL;\r
+  char *playerTitle=NULL;\r
+  bool playerError=false;\r
+  int numlines=0;\r
+  int len=0;\r
+  int num=0;\r
+  const char *pl=tr("Playlist");\r
+  const char *first=NULL;\r
+  char *playerInfo=NULL;\r
+  if (audioError) {\r
+    if (getPlayer()->getState() == AudioPlayer::S_PLAY) audioError=NULL;\r
+  }\r
+  if (! currentAudio && ! audioError) audioError=tr("no audio file");\r
+  if (audioError ) {\r
+    title=tr("MediaError");\r
+  }\r
+  else {\r
+    playerTitle=getPlayer()->getTitle();\r
+    if (playerTitle) title=playerTitle;\r
+    else title=currentAudio->getDisplayName();\r
+    num=parent->getNumEntries(MEDIA_TYPE_AUDIO,currentAudio->index);\r
+    playerError=getPlayer()->getState() == AudioPlayer::S_ERROR;\r
+    //1more line for long dirs\r
+    numlines=playall?5:4;\r
+  }\r
+  if (playerError) {\r
+    numlines=3;\r
+    first=tr("Unable to play audio file");\r
+    len=strlen(first)+3;\r
+  }\r
+  else if (audioError) {\r
+    numlines=3;\r
+    first=audioError;\r
+    len=strlen(first)+3;\r
+  }\r
+  else {\r
+    playerInfo=getPlayer()->getID3Info();drawText(tr("Loading"),5,3,Colour::LIGHTTEXT);\r
+    len=strlen(currentAudio->getDisplayName())+strlen(pl)+30+strlen(parent->getDirname(MEDIA_TYPE_AUDIO))+Media::TIMEBUFLEN+110;\r
+    if (playerInfo) {\r
+      for (UINT i=0;i<strlen(playerInfo);i++) \r
+        if (playerInfo[i] == '\n') numlines++;\r
+      len+=strlen(playerInfo);\r
+      first=playerInfo;\r
+    }\r
+    else {\r
+      first="";\r
+    }\r
+  }\r
+  destroyInfo();\r
+  info=new VInfo();\r
+  UINT height=numlines*30+60;\r
+  UINT vheight=Video::getInstance()->getScreenHeight();\r
+  UINT vwidth=Video::getInstance()->getScreenWidth();\r
+  if (height > vheight-2*AUDIOBANNER_BOTTOM_MARGIN)\r
+    height=vheight-2*AUDIOBANNER_BOTTOM_MARGIN;\r
+  info->setSize(vwidth -2*AUDIOBANNER_X_MARGIN, height);\r
+  info->createBuffer();\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+  {\r
+    info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);\r
+  }\r
+  else\r
+  {\r
+    info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);\r
+  }\r
+\r
+  info->setTitleBarOn(0);\r
+  info->setDropThrough();\r
+  //from vvideorec \r
+       //set the regions for the closcks and bars on banner\r
+  barRegion.x = info->getWidth()-AUDIOBARLEN-20;\r
+  barRegion.y = info->getHeight() - 30;   // FIXME, need to be - 1? and below?\r
+  barRegion.w = info->getWidth()-AUDIOBARLEN+10;\r
+  barRegion.h = 30;\r
+\r
+  clocksRegion.x = 130;\r
+  clocksRegion.y = barRegion.y + 3;\r
+  clocksRegion.w = 190;\r
+  clocksRegion.h = getFontHeight();\r
+  Log::getInstance()->log("VMediaView",Log::DEBUG,"created AudioInfo %p",info);\r
+  BoxStack::getInstance()->add(info);\r
+  char *buf=new char [len];\r
+  if (playerError || audioError) {\r
+    SNPRINTF(buf,len,"%s",first);\r
+  }\r
+  else {\r
+    char tbuf[Media::TIMEBUFLEN];\r
+    if (playall) {\r
+    SNPRINTF(buf,len,"%s\n"\r
+        "%s:%s\n"\r
+        "%s: %d/%d\n"\r
+        "%s:%s\n"\r
+        "%s:%s\n",\r
+        first,\r
+        tr("FileName"),currentAudio->getDisplayName(),\r
+        pl,num,parent->getNumEntries(MEDIA_TYPE_AUDIO),\r
+        tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),\r
+        tr("Time"),currentAudio->getTimeString(tbuf));\r
+    }\r
+    else {\r
+    SNPRINTF(buf,len,"%s\n"\r
+        "%s:%s\n"\r
+        "%s:%s\n"\r
+        "%s:%s\n",\r
+        first,\r
+        tr("FileName"),currentAudio->getDisplayName(),\r
+        tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),\r
+        tr("Time"),currentAudio->getTimeString(tbuf));\r
+    }\r
+  }\r
+  Log::getInstance()->log("VMediaView",Log::DEBUG,"info: (%d)%s",strlen(buf),buf);\r
+  //now the real drawing functions\r
+  info->draw();\r
+  //title\r
+  info->rectangle(0, 0, info->getWidth(), 30, Colour::TITLEBARBACKGROUND);\r
+  info->drawText(title, 5, 5, Colour::LIGHTTEXT);\r
+  info->drawPara(buf,5,32,Colour::LIGHTTEXT);\r
+  delete [] buf;\r
+  if (! audioError) {\r
+    WSymbol w;\r
+    info->TEMPADD(&w);\r
+    int x=10;\r
+    int ybottom=info->getHeight();\r
+    info->rectangle(0, ybottom - barRegion.h, info->getWidth(), barRegion.h, Colour::TITLEBARBACKGROUND);\r
+    bool drawSymbol=true;\r
+    switch(getPlayer()->getState()) {\r
+      case AudioPlayer::S_PAUSE:\r
+        w.nextSymbol = WSymbol::PAUSE;\r
+        break;\r
+      case AudioPlayer::S_PLAY:\r
+        w.nextSymbol = WSymbol::PLAY;\r
+        break;\r
+      case AudioPlayer::S_DONE:\r
+        if (playall) \r
+          w.nextSymbol = WSymbol::PLAY;\r
+        else\r
+          drawSymbol=false;\r
+        break;\r
+      case AudioPlayer::S_BACK:\r
+        w.nextSymbol = WSymbol::FBWD ;\r
+        break;\r
+      case AudioPlayer::S_FF:\r
+        w.nextSymbol = WSymbol::FFWD ;\r
+        break;\r
+      default:\r
+        drawSymbol=false;\r
+        break;\r
+    }\r
+    if (drawSymbol) {\r
+      w.setPosition(x, ybottom-24);\r
+      w.draw();\r
+    }\r
+    else {\r
+      //stop symbol\r
+      info->rectangle(x, ybottom - 23, 18, 16, Colour::LIGHTTEXT);\r
+    }\r
+    x+=30;\r
+    drawAudioClocks();\r
+  }\r
+  if (playerInfo) delete playerInfo;\r
+  if (playerTitle) delete playerTitle;\r
+}\r
+\r
+void VMediaView::drawAudioClocks() {\r
+       if (! info || ! audioEnabled) return;\r
+       Log::getInstance()->log("VMediaView::drawAudioClocks", Log::DEBUG, "");\r
+  //draw clocks and bar\r
+  info->rectangle(clocksRegion, Colour::TITLEBARBACKGROUND);\r
+\r
+  time_t currentSec = (time_t)(getPlayer()->getCurrentTimes());\r
+  time_t lengthSec=(time_t)(getPlayer()->getSonglen());\r
+       struct tm cpos;\r
+       struct tm slen;\r
+/*     gmtime_r(&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, Colour::LIGHTTEXT);\r
+  \r
+       // Draw progress bar\r
+  int progBarXbase = 0;\r
+       int barlen=250;\r
+\r
+  info->rectangle(barRegion.x + progBarXbase, barRegion.y + 3, barlen+10, 24, Colour::LIGHTTEXT);\r
+  info->rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 5, barlen+6, 20, barBlue);\r
+\r
+  if (currentSec > lengthSec) currentSec=lengthSec;\r
+  if (lengthSec == 0) return;\r
+\r
+  // Draw yellow portion\r
+  int progressWidth = (barlen+2) * currentSec / lengthSec;\r
+  info->rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 7, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+\r
+}\r
+\r
+void VMediaView::showAudioBanner() {\r
+  destroyAudioBanner();\r
+  if (! audioEnabled) return;\r
+  audioBanner=new VInfo();\r
+  Log::getInstance()->log("VMediaView",Log::DEBUG,"creating AudioBanner %p", audioBanner);\r
+  Video *v=Video::getInstance();\r
+  audioBanner->setSize(v->getScreenWidth()-100, 36);\r
+  audioBanner->createBuffer();\r
+  audioBanner->setPosition(50, v->getScreenHeight()-50);\r
+  audioBanner->fillColour(audioBannerBack);\r
+  audioBanner->setTitleBarOn(0);\r
+  audioBanner->setDropThrough();\r
+  if ( ! currentAudio || ! currentAudio->getDisplayName() || audioError) {\r
+    audioBanner->drawText(tr("AudioPlayer - not playing"),5,3,Colour::LIGHTTEXT);\r
+  }\r
+  else {\r
+    char * buf=new char[strlen(currentAudio->getDisplayName())+50];\r
+    SNPRINTF(buf,50,"%s %s",tr("AudioPlayer"),currentAudio->getDisplayName());\r
+    audioBanner->drawText(buf,5,3,Colour::LIGHTTEXT);\r
+    delete buf;\r
+  }\r
+  BoxStack::getInstance()->add(audioBanner);\r
+  BoxStack::getInstance()->update(audioBanner);\r
+}\r
+\r
+void VMediaView::destroyAudioBanner() {\r
+  if (audioBanner) {\r
+    Log::getInstance()->log("VMediaView",Log::DEBUG,"deleting AudioBanner %p",audioBanner);\r
+    BoxStack::getInstance()->remove(audioBanner);\r
+    audioBanner=NULL;\r
+  }\r
+}\r
index bacf5879a8f00b6e0d8e21e1f78df5aeb2f11cf4..bb40d7351875b11d3d916a842e393e0a3d4d59ab 100644 (file)
--- a/vopts.cc
+++ b/vopts.cc
-/*
-    Copyright 2007 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vopts.h"
-
-#include "colour.h"
-#include "video.h"
-#include "audio.h"
-#include "remote.h"
-#include "boxstack.h"
-#include "woptionpane.h"
-#include "wremoteconfig.h"
-#include "log.h"
-#include "option.h"
-#include "vdr.h"
-#include "command.h"
-#include "mediaoptions.h"
-
-//#include "vdr.h"
-//#include "command.h"
-
-VOpts::VOpts()
-{
-  setTitleBarOn(1);
-  setTitleBarColour(Colour::TITLEBARBACKGROUND);
-  setTitleText(tr("Options"));
-
-  setSize(520, 360);
-  createBuffer();
-  if (Video::getInstance()->getFormat() == Video::PAL)
-    setPosition(100, 110);
-  else
-    setPosition(90, 90);
-  
-  tabbar.setPosition(6, 32);
-  tabbar.setSize(getWidth() - 12, getHeight() - 34);
-  add(&tabbar);
-  
-  Option* option;
-  WOptionPane* wop;
-  
-  //  --- edit options start here
-  
-  static const char* options1[] = {"Old", "New"};
-  static const char* options3[] = {"RGB+composite", "S-Video"};
-  static const char* options4[] = {"4:3", "16:9"};
-  static const char* options5[] = {"Chop sides", "Letterbox"};
-  static const char* options6[] = {"On", "Off", "Last state"};
-  static const char* options7[] = {"All", "FTA only"};
-  static const char* options15[] = {"Alphabetical", "Chronological"};
-
-  static const char* options13[] = {"1024", "2048", "4096", "8192", "16384", "32768", "65536"};
-  static const char* options14[] = {"No", "Yes"};
-
-  // Get list of languages from VDR and construct options table
-  LangCode = VDR::getInstance()->getLanguageList();
-  options2 = new const char*[LangCode.size()];
-  options2keys = new const char*[LangCode.size()];
-  I18n::lang_code_list::const_iterator iter;
-  UINT LangNumber = 0;
-  for (iter = LangCode.begin(); iter != LangCode.end(); ++iter,++LangNumber)
-  {
-    options2[LangNumber] = iter->second.c_str();
-    options2keys[LangNumber] = iter->first.c_str();
-  }
-
-  numPanes = 4;
-  panes = new Boxx*[numPanes];
-  wop = new WOptionPane(); 
-  tabbar.addTab(tr("General"), wop);
-  panes[0] = wop;
-  
-  option = new Option(1, "Remote control type",      "General", "Remote type",           Option::TYPE_TEXT, 2, 0, 0, options1);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(2, "Language",                 "General", "LangCode",              Option::TYPE_KEYED_TEXT, LangCode.size(), 0, 0, options2, options2keys);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(3, "TV connection type",       "TV",      "Connection",            Option::TYPE_TEXT, 2, 0, 0, options3);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(4, "TV aspect ratio",          "TV",      "Aspect",                Option::TYPE_TEXT, 2, 0, 0, options4);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(5, "16:9 on 4:3 display mode", "TV",      "Widemode",              Option::TYPE_TEXT, 2, 0, 0, options5);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(6, "Power state after bootup", "General", "Power After Boot",      Option::TYPE_TEXT, 3, 0, 0, options6);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(7, "Display channels",         "General", "Channels",              Option::TYPE_TEXT, 2, 0, 0, options7);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(15, "Recordings sort order",   "General", "Recordings Sort Order", Option::TYPE_TEXT, 2, 0, 0, options15);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  
-  Remote::getInstance()->addOptionsToPanes(0,&options,wop);
-  Video::getInstance()->addOptionsToPanes(0,&options,wop);
-  Audio::getInstance()->addOptionsToPanes(0,&options,wop);
-  
-    
-/*  WRemoteConfig* wrc = new WRemoteConfig();
-  tabbar.addTab(tr("Remote Control"), wrc);*/
-  Remote::getInstance()->addOptionPagesToWTB(&tabbar);
- // panes[1] = wrc;
-
-  Video::getInstance()->addOptionPagesToWTB(&tabbar);
-  Audio::getInstance()->addOptionPagesToWTB(&tabbar);
-  MediaOptions::getInstance()->addOptionPagesToWTB(&tabbar);
-  
-  
-  wop = new WOptionPane(); 
-  tabbar.addTab(tr("Timers"), wop);
-  panes[1] = wop;
-  
-  option = new Option(9, "Default start margin (minutes)",  "Timers", "Start margin",  Option::TYPE_INT, 20, 5, 0, NULL);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(10, "Default end margin (minutes)",   "Timers", "End margin",    Option::TYPE_INT, 20, 5, 0, NULL);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(11, "Default priority",               "Timers", "Priority",      Option::TYPE_INT, 100, 99, 0, NULL);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(12, "Default lifetime",               "Timers", "Lifetime",      Option::TYPE_INT, 100, 99, 0, NULL);
-  options.push_back(option);
-  wop->addOptionLine(option);
-
-  Remote::getInstance()->addOptionsToPanes(1,&options,wop);
-  Video::getInstance()->addOptionsToPanes(1,&options,wop);
-  Audio::getInstance()->addOptionsToPanes(1,&options,wop);
-
-    
-  wop = new WOptionPane(); 
-  tabbar.addTab(tr("Advanced"), wop);
-  panes[2] = wop;
-  
-  option = new Option(8, "VDR-Pri 0=OK !See forums!",  "General",  "Live priority",      Option::TYPE_INT,  100, 0, 0, NULL);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(13, "TCP receive window size",   "Advanced", "TCP receive window", Option::TYPE_TEXT, 7, 1, 0, options13);
-  options.push_back(option);
-  wop->addOptionLine(option);
-  option = new Option(14, "Use WSS (PAL only)",        "General",  "WSS",                Option::TYPE_TEXT, 2, 0, 0, options14);
-  options.push_back(option);
-  wop->addOptionLine(option);  
-
-  Remote::getInstance()->addOptionsToPanes(2,&options,wop);
-  Video::getInstance()->addOptionsToPanes(2,&options,wop);
-  Audio::getInstance()->addOptionsToPanes(2,&options,wop);
-}
-
-VOpts::~VOpts()
-{
- // for (int i = 0; i < numPanes; i++) delete panes[i]; //Move to TabBar, Marten
-  delete[] panes;
-
-  for(vector<Option*>::iterator j = options.begin(); j != options.end(); j++) delete *j;
-  delete[] options2;
-  delete[] options2keys;
-}
-
-int VOpts::handleCommand(int command)
-{
-  // either is active, handle back
-  if (command == Remote::BACK)
-  {
-    doSave();
-    return 4;
-  }
-  else
-  {
-    int retval = tabbar.handleCommand(command);
-    if (retval == 1)
-    {
-      BoxStack::getInstance()->update(this);
-      return 2;
-    }
-    else if (retval == 2)
-    {
-      // command was taken and actively ignored
-      return 2;
-    }
-    else
-    {
-      return 1; // ???
-    }
-  }
-}
-
-void VOpts::doSave()
-{
-  VDR* vdr = VDR::getInstance();
-
-  Remote::getInstance()->saveOptionstoServer(); //Remote
-  Video::getInstance()->saveOptionstoServer(); //Video
-  Audio::getInstance()->saveOptionstoServer(); //Remote
-  MediaOptions::getInstance()->saveOptionstoServer(); //Media
-
-  // Damn, and the dynamic idea was going *so* well...
-  //Whats about a check with typeid operator?
-  WOptionPane* wop;
-  wop = (WOptionPane*)panes[0];
-  wop->saveOpts();  
-  wop = (WOptionPane*)panes[1];
-  wop->saveOpts();  
-  wop = (WOptionPane*)panes[2];
-  wop->saveOpts();  
-
-
-  for (UINT i = 0; i < options.size(); i++)
-  {
-    if (options[i]->configChoice == options[i]->userSetChoice) continue; // no change
-
-    Log::getInstance()->log("Options", Log::DEBUG, "Option %i has changed", i);
-
-    // Save to vdr
-
-    if (options[i]->optionType == Option::TYPE_TEXT)
-    {
-      vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->options[options[i]->userSetChoice]);
-    }
-    else if (options[i]->optionType == Option::TYPE_KEYED_TEXT)
-    {
-      vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->optionkeys[options[i]->userSetChoice]);
-    }
-    else
-    {
-      char buffer[20];
-      sprintf(buffer, "%i", options[i]->userSetChoice);
-      vdr->configSave(options[i]->configSection, options[i]->configKey, buffer);
-    }
-    
-    // Set new setting
-    if (options[i]->opthandler == NULL) //Ok, noone else is handling this, we are doing it
-    {
-      switch(options[i]->id)
-      {
-        case 1:
-        {
-          if (options[i]->userSetChoice == 1)
-          {
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting New Remote");
-            Remote::getInstance()->setRemoteType(Remote::NEWREMOTE);
-          }
-          else
-          {
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting Old Remote");
-            Remote::getInstance()->setRemoteType(Remote::OLDREMOTE);
-          }
-          break;
-        }
-        case 2:
-        {
-          Message* m = new Message();
-          m->message = Message::CHANGE_LANGUAGE;
-          m->to = Command::getInstance();
-          Command::getInstance()->postMessageNoLock(m);
-          break;
-        }
-        case 3:
-        {
-          if (options[i]->userSetChoice == 1)
-          {
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting S-Video");
-            Video::getInstance()->setConnection(Video::SVIDEO);
-          }
-          else
-          {
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting RGB/Composite");
-            Video::getInstance()->setConnection(Video::COMPOSITERGB);
-          }
-          break;
-        }
-        case 4:
-        {
-          if (options[i]->userSetChoice == 1)
-          {
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting 16:9 TV");
-            Video::getInstance()->setTVsize(Video::ASPECT16X9);
-          }
-          else
-          {
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting 4:3 TV");
-            Video::getInstance()->setTVsize(Video::ASPECT4X3);
-          }
-          break;
-        }
-        case 5:
-        {
-          if (options[i]->userSetChoice == 1)
-          {
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting letterbox");
-            Video::getInstance()->setMode(Video::LETTERBOX);
-          }
-          else
-          {
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting chop-sides");
-            Video::getInstance()->setMode(Video::NORMAL);
-          }
-          break;
-        }
-        case 13:
-        {
-          size_t newTCPsize = 2048;
-          if (options[i]->userSetChoice == 0) newTCPsize = 1024;
-          else if (options[i]->userSetChoice == 1) newTCPsize = 2048;
-          else if (options[i]->userSetChoice == 2) newTCPsize = 4096;
-          else if (options[i]->userSetChoice == 3) newTCPsize = 8192;
-          else if (options[i]->userSetChoice == 4) newTCPsize = 16384;
-          else if (options[i]->userSetChoice == 5) newTCPsize = 32768;
-          else if (options[i]->userSetChoice == 6) newTCPsize = 65536;
-          Log::getInstance()->log("Options", Log::DEBUG, "Setting TCP window size %i", newTCPsize);
-          VDR::getInstance()->setReceiveWindow(newTCPsize);
-          break;
-        }
-      }
-    }
-    else
-    {
-      options[i]->opthandler->handleOptionChanges(options[i]);
-    }
-  }
-}
-
-void VOpts::processMessage(Message* m)
-{
-  if (m->message == Message::MOUSE_MOVE)
-  {
-    int x=(m->parameter>>16)-getScreenX();
-    int y=(m->parameter&0xFFFF)-getScreenY();
-    if (tabbar.mouseMove(x,y))
-    {
-      BoxStack::getInstance()->update(this);
-    }
-    
-  }
-  else if (m->message == Message::MOUSE_LBDOWN)
-  {
-    int x=(m->parameter>>16)-getScreenX();
-    int y=(m->parameter&0xFFFF)-getScreenY();
-    if (tabbar.mouseLBDOWN(x,y)) 
-    {
-      BoxStack::getInstance()->update(this);
-    } 
-    else if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
-    {
-      BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
-    }
-  }
-}
+/*\r
+    Copyright 2007 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vopts.h"\r
+\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "audio.h"\r
+#include "remote.h"\r
+#include "boxstack.h"\r
+#include "woptionpane.h"\r
+#include "wremoteconfig.h"\r
+#include "log.h"\r
+#include "option.h"\r
+#include "vdr.h"\r
+#include "command.h"\r
+\r
+#ifdef VOMP_PLATTFORM_MVP\r
+#include "mediaoptions.h"\r
+#endif\r
+//#include "vdr.h"\r
+//#include "command.h"\r
+\r
+VOpts::VOpts()\r
+{\r
+  setTitleBarOn(1);\r
+  setTitleBarColour(Colour::TITLEBARBACKGROUND);\r
+  setTitleText(tr("Options"));\r
+\r
+\r
+  setSize(520, 360);\r
+  createBuffer();\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+    setPosition(100, 110);\r
+  else\r
+    setPosition(90, 90);\r
+  \r
+  tabbar.setPosition(6, 32);\r
+  tabbar.setSize(getWidth() - 12, getHeight() - 34);\r
+  add(&tabbar);\r
+  \r
+  Option* option;\r
+  WOptionPane* wop;\r
+  \r
+  //  --- edit options start here\r
+  \r
+  static const char* options1[] = {"Old", "New"};\r
+  static const char* options3[] = {"RGB+composite", "S-Video"};\r
+  static const char* options4[] = {"4:3", "16:9"};\r
+  static const char* options5[] = {"Chop sides", "Letterbox"};\r
+  static const char* options6[] = {"On", "Off", "Last state"};\r
+  static const char* options7[] = {"All", "FTA only"};\r
+  static const char* options15[] = {"Alphabetical", "Chronological"};\r
+\r
+  static const char* options13[] = {"1024", "2048", "4096", "8192", "16384", "32768", "65536"};\r
+  static const char* options14[] = {"No", "Yes"};\r
+  // Get list of languages from VDR and construct options table\r
+  LangCode = VDR::getInstance()->getLanguageList();\r
+  options2 = new const char*[LangCode.size()];\r
+  options2keys = new const char*[LangCode.size()];\r
+  I18n::lang_code_list::const_iterator iter;\r
+  UINT LangNumber = 0;\r
+  for (iter = LangCode.begin(); iter != LangCode.end(); ++iter,++LangNumber)\r
+  {\r
+    options2[LangNumber] = iter->second.c_str();\r
+    options2keys[LangNumber] = iter->first.c_str();\r
+  }\r
+\r
+  numPanes = 4;\r
+  panes = new Boxx*[numPanes];\r
 
+  wop = new WOptionPane();\r
+  tabbar.addTab(tr("General"), wop);\r
+  panes[0] = wop;\r
+  option = new Option(1, "Remote control type",      "General", "Remote type",           Option::TYPE_TEXT, 2, 0, 0, options1);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(2, "Language",                 "General", "LangCode",              Option::TYPE_KEYED_TEXT, LangCode.size(), 0, 0, options2, options2keys);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(3, "TV connection type",       "TV",      "Connection",            Option::TYPE_TEXT, 2, 0, 0, options3);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(4, "TV aspect ratio",          "TV",      "Aspect",                Option::TYPE_TEXT, 2, 0, 0, options4);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(5, "16:9 on 4:3 display mode", "TV",      "Widemode",              Option::TYPE_TEXT, 2, 0, 0, options5);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(6, "Power state after bootup", "General", "Power After Boot",      Option::TYPE_TEXT, 3, 0, 0, options6);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(7, "Display channels",         "General", "Channels",              Option::TYPE_TEXT, 2, 0, 0, options7);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(15, "Recordings sort order",   "General", "Recordings Sort Order", Option::TYPE_TEXT, 2, 0, 0, options15);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+\r
+  Remote::getInstance()->addOptionsToPanes(0,&options,wop);\r
+  Video::getInstance()->addOptionsToPanes(0,&options,wop);\r
+  Audio::getInstance()->addOptionsToPanes(0,&options,wop);\r
+\r
+    \r
+/*  WRemoteConfig* wrc = new WRemoteConfig();\r
+  tabbar.addTab(tr("Remote Control"), wrc);*/\r
+  Remote::getInstance()->addOptionPagesToWTB(&tabbar);\r
+ // panes[1] = wrc;\r
+\r
+  Video::getInstance()->addOptionPagesToWTB(&tabbar);\r
+  Audio::getInstance()->addOptionPagesToWTB(&tabbar);\r
+#ifdef VOMP_PLATTFORM_MVP\r
+  MediaOptions::getInstance()->addOptionPagesToWTB(&tabbar);\r
+#endif\r
+\r
+\r
+  wop = new WOptionPane(); \r
+  tabbar.addTab(tr("Timers"), wop);\r
+  panes[1] = wop;\r
+  \r
+  option = new Option(9, "Default start margin (minutes)",  "Timers", "Start margin",  Option::TYPE_INT, 20, 5, 0, NULL);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(10, "Default end margin (minutes)",   "Timers", "End margin",    Option::TYPE_INT, 20, 5, 0, NULL);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(11, "Default priority",               "Timers", "Priority",      Option::TYPE_INT, 100, 99, 0, NULL);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(12, "Default lifetime",               "Timers", "Lifetime",      Option::TYPE_INT, 100, 99, 0, NULL);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+\r
+  Remote::getInstance()->addOptionsToPanes(1,&options,wop);\r
+  Video::getInstance()->addOptionsToPanes(1,&options,wop);\r
+  Audio::getInstance()->addOptionsToPanes(1,&options,wop);\r
+\r
+    \r
+  wop = new WOptionPane(); \r
+  tabbar.addTab(tr("Advanced"), wop);\r
+  panes[2] = wop;\r
+  \r
+  option = new Option(8, "VDR-Pri 0=OK !See forums!",  "General",  "Live priority",      Option::TYPE_INT,  100, 0, 0, NULL);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(13, "TCP receive window size",   "Advanced", "TCP receive window", Option::TYPE_TEXT, 7, 1, 0, options13);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);\r
+  option = new Option(14, "Use WSS (PAL only)",        "General",  "WSS",                Option::TYPE_TEXT, 2, 0, 0, options14);\r
+  options.push_back(option);\r
+  wop->addOptionLine(option);  \r
+\r
+  Remote::getInstance()->addOptionsToPanes(2,&options,wop);\r
+  Video::getInstance()->addOptionsToPanes(2,&options,wop);\r
+  Audio::getInstance()->addOptionsToPanes(2,&options,wop);\r
+}\r
+\r
+VOpts::~VOpts()\r
+{\r
+ // for (int i = 0; i < numPanes; i++) delete panes[i]; //Move to TabBar, Marten\r
+  delete[] panes;\r
+\r
+  for(vector<Option*>::iterator j = options.begin(); j != options.end(); j++) delete *j;\r
+  delete[] options2;\r
+  delete[] options2keys;\r
+}\r
+\r
+int VOpts::handleCommand(int command)\r
+{\r
+  // either is active, handle back\r
+  if (command == Remote::BACK)\r
+  {\r
+    doSave();\r
+    return 4;\r
+  }\r
+  else\r
+  {\r
+    int retval = tabbar.handleCommand(command);\r
+    if (retval == 1)\r
+    {\r
+      BoxStack::getInstance()->update(this);\r
+      return 2;\r
+    }\r
+    else if (retval == 2)\r
+    {\r
+      // command was taken and actively ignored\r
+      return 2;\r
+    }\r
+    else\r
+    {\r
+      return 1; // ???\r
+    }\r
+  }\r
+}\r
+\r
+void VOpts::doSave()\r
+{\r
+  VDR* vdr = VDR::getInstance();\r
+\r
+  Remote::getInstance()->saveOptionstoServer(); //Remote\r
+  Video::getInstance()->saveOptionstoServer(); //Video\r
+  Audio::getInstance()->saveOptionstoServer(); //Remote\r
+#ifdef VOMP_PLATTFORM_MVP\r
+  MediaOptions::getInstance()->saveOptionstoServer(); //Media\r
+#endif\r
+\r
+  // Damn, and the dynamic idea was going *so* well...\r
+  //Whats about a check with typeid operator?\r
+  WOptionPane* wop;\r
+  wop = (WOptionPane*)panes[0];\r
+  wop->saveOpts();  \r
+  wop = (WOptionPane*)panes[1];\r
+  wop->saveOpts();  \r
+  wop = (WOptionPane*)panes[2];\r
+  wop->saveOpts();  \r
+\r
+\r
+  for (UINT i = 0; i < options.size(); i++)\r
+  {\r
+    if (options[i]->configChoice == options[i]->userSetChoice) continue; // no change\r
+\r
+    Log::getInstance()->log("Options", Log::DEBUG, "Option %i has changed", i);\r
+\r
+    // Save to vdr\r
+\r
+    if (options[i]->optionType == Option::TYPE_TEXT)\r
+    {\r
+      vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->options[options[i]->userSetChoice]);\r
+    }\r
+    else if (options[i]->optionType == Option::TYPE_KEYED_TEXT)\r
+    {\r
+      vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->optionkeys[options[i]->userSetChoice]);\r
+    }\r
+    else\r
+    {\r
+      char buffer[20];\r
+      sprintf(buffer, "%i", options[i]->userSetChoice);\r
+      vdr->configSave(options[i]->configSection, options[i]->configKey, buffer);\r
+    }\r
+    \r
+    // Set new setting\r
+    if (options[i]->opthandler == NULL) //Ok, noone else is handling this, we are doing it\r
+    {\r
+      switch(options[i]->id)\r
+      {\r
+        case 1:\r
+        {\r
+          if (options[i]->userSetChoice == 1)\r
+          {\r
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting New Remote");\r
+            Remote::getInstance()->setRemoteType(Remote::NEWREMOTE);\r
+          }\r
+          else\r
+          {\r
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting Old Remote");\r
+            Remote::getInstance()->setRemoteType(Remote::OLDREMOTE);\r
+          }\r
+          break;\r
+        }\r
+        case 2:\r
+        {\r
+          Message* m = new Message();\r
+          m->message = Message::CHANGE_LANGUAGE;\r
+          m->to = Command::getInstance();\r
+          Command::getInstance()->postMessageNoLock(m);\r
+          break;\r
+        }\r
+        case 3:\r
+        {\r
+          if (options[i]->userSetChoice == 1)\r
+          {\r
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting S-Video");\r
+            Video::getInstance()->setConnection(Video::SVIDEO);\r
+          }\r
+          else\r
+          {\r
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting RGB/Composite");\r
+            Video::getInstance()->setConnection(Video::COMPOSITERGB);\r
+          }\r
+          break;\r
+        }\r
+        case 4:\r
+        {\r
+          if (options[i]->userSetChoice == 1)\r
+          {\r
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting 16:9 TV");\r
+            Video::getInstance()->setTVsize(Video::ASPECT16X9);\r
+          }\r
+          else\r
+          {\r
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting 4:3 TV");\r
+            Video::getInstance()->setTVsize(Video::ASPECT4X3);\r
+          }\r
+          break;\r
+        }\r
+        case 5:\r
+        {\r
+          if (options[i]->userSetChoice == 1)\r
+          {\r
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting letterbox");\r
+            Video::getInstance()->setMode(Video::LETTERBOX);\r
+          }\r
+          else\r
+          {\r
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting chop-sides");\r
+            Video::getInstance()->setMode(Video::NORMAL);\r
+          }\r
+          break;\r
+        }\r
+        case 13:\r
+        {\r
+          size_t newTCPsize = 2048;\r
+          if (options[i]->userSetChoice == 0) newTCPsize = 1024;\r
+          else if (options[i]->userSetChoice == 1) newTCPsize = 2048;\r
+          else if (options[i]->userSetChoice == 2) newTCPsize = 4096;\r
+          else if (options[i]->userSetChoice == 3) newTCPsize = 8192;\r
+          else if (options[i]->userSetChoice == 4) newTCPsize = 16384;\r
+          else if (options[i]->userSetChoice == 5) newTCPsize = 32768;\r
+          else if (options[i]->userSetChoice == 6) newTCPsize = 65536;\r
+          Log::getInstance()->log("Options", Log::DEBUG, "Setting TCP window size %i", newTCPsize);\r
+          VDR::getInstance()->setReceiveWindow(newTCPsize);\r
+          break;\r
+        }\r
+      }\r
+    }\r
+    else\r
+    {\r
+      options[i]->opthandler->handleOptionChanges(options[i]);\r
+    }\r
+  }\r
+}\r
+\r
+void VOpts::processMessage(Message* m)\r
+{\r
+  if (m->message == Message::MOUSE_MOVE)\r
+  {\r
+    int x=(m->parameter>>16)-getScreenX();\r
+    int y=(m->parameter&0xFFFF)-getScreenY();\r
+    if (tabbar.mouseMove(x,y))\r
+    {\r
+      BoxStack::getInstance()->update(this);\r
+    }\r
+    \r
+  }\r
+  else if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    int x=(m->parameter>>16)-getScreenX();\r
+    int y=(m->parameter&0xFFFF)-getScreenY();\r
+    if (tabbar.mouseLBDOWN(x,y)) \r
+    {\r
+      BoxStack::getInstance()->update(this);\r
+    } \r
+    else if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
+    }\r
+  }\r
+}\r
+\r
index 3308bb4439cb5952f253304c5d8364b98a6ad6d8..ec0d3a5eae1784c57bbbe24ba34b2f59fb184ea4 100644 (file)
-/*
-    Copyright 2004-2006 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vradiorec.h"
-
-#include "command.h"
-#include "osd.h"
-#include "player.h"
-#include "wsymbol.h"
-#include "recording.h"
-#include "message.h"
-#include "vdr.h"
-#include "video.h"
-#include "timers.h"
-#include "playerradio.h"
-#include "boxstack.h"
-#include "remote.h"
-#include "vinfo.h"
-#include "i18n.h"
-#include "log.h"
-
-VRadioRec::VRadioRec(Recording* rec)
-{
-  boxstack = BoxStack::getInstance();
-  vdr = VDR::getInstance();
-  video = Video::getInstance();
-  timers = Timers::getInstance();
-  myRec = rec;
-  playing = false;
-  startMargin = 0;
-  endMargin = 0;
-
-  player = new PlayerRadio(Command::getInstance(), this);
-
-  char* cstartMargin = vdr->configLoad("Timers", "Start margin");
-  char* cendMargin = vdr->configLoad("Timers", "End margin");
-  if (!cstartMargin)
-  {
-    startMargin = 300; // 5 mins default
-  }
-  else
-  {
-    startMargin = atoi(cstartMargin) * 60;
-    delete[] cstartMargin;
-  }
-
-  if (!cendMargin)
-  {
-    endMargin = 300; // 5 mins default
-  }
-  else
-  {
-    endMargin = atoi(cendMargin) * 60;
-    delete[] cendMargin;
-  }
-
-  Log::getInstance()->log("VRadioRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);
-
-  setSize(video->getScreenWidth(), video->getScreenHeight());
-  createBuffer();
-  setPosition(0, 0);
-
-  barRegion.x = 0;
-  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?
-  barRegion.w = video->getScreenWidth();
-  barRegion.h = 58;
-
-  clocksRegion.x = barRegion.x + 140;
-  clocksRegion.y = barRegion.y + 12;
-  clocksRegion.w = 170;
-  clocksRegion.h = surface->getFontHeight();
-
-
-  barBlue.set(0, 0, 150, 150);
-
-  barShowing = false;
-}
-
-void VRadioRec::preDelete()
-{
-  timers->cancelTimer(this, 1);
-  timers->cancelTimer(this, 2);
-}
-
-VRadioRec::~VRadioRec()
-{
-  if (playing) stopPlay();
-
-
-  // kill recInfo in case resumePoint has changed (likely)
-  myRec->dropRecInfo();
-  // FIXME - do this properly - save the resume point back to the server manually and update
-  // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well
-}
-
-void VRadioRec::draw()
-{
-  fillColour(Colour::BLACK);
-}
-
-void VRadioRec::go()
-{
-  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Starting stream: %s", myRec->getFileName());
-  ULONG lengthFrames = 0;
-  bool isPesRecording;
-  ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);
-  myRec->IsPesRecording = isPesRecording;
-
-  bool cantStart = false;
-
-  if (!lengthBytes) cantStart = true;
-  else if (!player->init(lengthBytes, lengthFrames, myRec->IsPesRecording)) cantStart = true;
-  else
-  {
-    doBar(0);
-  //  player->setStartBytes(startBytes);
-    player->play();
-    playing = true;
-  }
-
-  if (cantStart)
-  {
-    stopPlay(); // clean up
-
-    if (!vdr->isConnected())
-    {
-      Command::getInstance()->connectionLost();
-      return;
-    }
-
-    Message* m = new Message();
-    m->message = Message::CLOSE_ME;
-    m->from = this;
-    m->to = boxstack;
-    Command::getInstance()->postMessageNoLock(m);
-
-    VInfo* vi = new VInfo();
-    vi->setSize(400, 150);
-    vi->createBuffer();
-    if (video->getFormat() == Video::PAL)
-      vi->setPosition(170, 200);
-    else
-      vi->setPosition(160, 150);
-    vi->setExitable();
-    vi->setBorderOn(1);
-    vi->setTitleBarOn(0);
-    vi->setOneLiner(tr("Error playing recording"));
-    vi->draw();
-
-    m = new Message();
-    m->message = Message::ADD_VIEW;
-    m->to = boxstack;
-    m->parameter = (ULONG)vi;
-    Command::getInstance()->postMessageNoLock(m);
-  }
-}
-
-int VRadioRec::handleCommand(int command)
-{
-  switch(command)
-  {
-    case Remote::PLAY:
-    {
-      player->play();
-      doBar(0);
-      return 2;
-    }
-
-    case Remote::STOP:
-    case Remote::BACK:
-    case Remote::MENU:
-    {
-      if (playing) stopPlay();
-      return 4;
-    }
-    case Remote::PAUSE:
-    {
-      player->pause();
-      doBar(0);
-      return 2;
-    }
-    case Remote::SKIPFORWARD:
-    {
-      doBar(3);
-      player->skipForward(60);
-      return 2;
-    }
-    case Remote::SKIPBACK:
-    {
-      doBar(4);
-      player->skipBackward(60);
-      return 2;
-    }
-    case Remote::YELLOW:
-    {
-      doBar(2);
-      player->skipBackward(10);
-      return 2;
-    }
-    case Remote::BLUE:
-    {
-      doBar(1);
-      player->skipForward(10);
-      return 2;
-    }
-    case Remote::OK:
-    {
-      if (barShowing) removeBar();
-      else doBar(0);
-      return 2;
-    }
-
-    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;
-    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;
-    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;
-    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;
-    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;
-    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;
-    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;
-    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;
-    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;
-    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;
-
-#ifdef DEV
-    case Remote::RED:
-    {
-      //player->test1();
-
-      return 2;
-    }
-    case Remote::GREEN:
-    {
-      //player->test2();
-      return 2;
-    }
-#endif
-
-  }
-
-  return 1;
-}
-
-void VRadioRec::processMessage(Message* m)
-{
-  if (m->message == Message::MOUSE_LBDOWN)
-  {
-    int x=(m->parameter>>16)-(int)getScreenX();
-    int y=(m->parameter&0xFFFF)-(int)getScreenY();
-    if (!barShowing)
-    {
-      boxstack->handleCommand(Remote::OK); //simulate rok press
-    }
-    else if ((int)barRegion.x<=x && (int)barRegion.y<=y && ((int)barRegion.x+(int)barRegion.w)>=x
-             &&  ((int)barRegion.y+(int)barRegion.h)>=y)
-    {
-      int progBarXbase = barRegion.x + 300;
-      if (x>=(int)barRegion.x + progBarXbase + 24
-        && x<=(int)barRegion.x + progBarXbase + 4 + 302
-        && y>=(int)barRegion.y + 12 - 2
-        && y<=(int)barRegion.y + 12 - 2+28)
-      {
-        int cx=x-(barRegion.x + progBarXbase + 4);
-        double percent=((double)cx)/302.*100.;
-        player->jumpToPercent(percent);
-        doBar(3);
-        return;
-        //  int progressWidth = 302 * currentFrameNum / lengthFrames;
-        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-      }
-    }
-    else
-    {
-      boxstack->handleCommand(Remote::OK); //simulate rok press
-    }
-  }
-  else if (m->message == Message::PLAYER_EVENT)
-  {
-    if (m->from != player) return;
-
-    Log::getInstance()->log("VRadioRec", Log::DEBUG, "Message received");
-
-    switch(m->parameter)
-    {
-      case Player::CONNECTION_LOST: // connection lost detected
-      {
-        // I can't handle this, send it to command
-        Message* m2 = new Message();
-        m2->to = Command::getInstance();
-        m2->message = Message::CONNECTION_LOST;
-        Command::getInstance()->postMessageNoLock(m2);
-        break;
-      }
-      case Player::STOP_PLAYBACK:
-      {
-        // FIXME Obselete ish - improve this
-        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
-        m2->to = Command::getInstance();
-        m2->message = Message::STOP_PLAYBACK;
-        Command::getInstance()->postMessageNoLock(m2);
-        break;
-      }
-    }
-  }
-}
-
-void VRadioRec::stopPlay()
-{
-  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Pre stopPlay");
-
-  removeBar();
-  player->stop();
-  vdr->stopStreaming();
-  delete player;
-
-  playing = false;
-
-  if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
-  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Post stopPlay");
-}
-
-void VRadioRec::doBar(int action)
-{
-  barShowing = true;
-
-  rectangle(barRegion, barBlue);
-
-  /* Work out what to display - choices:
-
-  Playing  >
-  Paused   ||
-
-  Specials, informed by parameter
-
-  Skip forward 10s    >|
-  Skip backward 10s   |<
-  Skip forward 1m     >>|
-  Skip backward 1m    |<<
-
-  */
-
-  WSymbol w;
-  TEMPADD(&w);
-  w.nextSymbol = 0;
-  w.setPosition(barRegion.x + 66, barRegion.y + 16);
-
-  UCHAR playerState = 0;
-
-  if (action)
-  {
-    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
-    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
-    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
-    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
-  }
-  else
-  {
-    playerState = player->getState();
-    if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
-    else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
-    else                                       w.nextSymbol = WSymbol::PLAY;
-  }
-
-  w.draw();
-
-  drawBarClocks();
-
-  BoxStack::getInstance()->update(this, &barRegion);
-
-  timers->setTimerD(this, 1, 4); // only set the getridofbar timer if not ffwd/fbwd
-  timers->setTimerD(this, 2, 0, 200000000);
-}
-
-void VRadioRec::timercall(int clientReference)
-{
-  switch(clientReference)
-  {
-    case 1:
-    {
-      // Remove bar
-      removeBar();
-      break;
-    }
-    case 2:
-    {
-      // Update clock
-      if (!barShowing) break;
-      drawBarClocks();
-      boxstack->update(this, &barRegion);
-      
-      timers->setTimerD(this, 2, 0, 200000000);
-      break;
-    }
-  }
-}
-
-void VRadioRec::drawBarClocks()
-{
-  Log* logger = Log::getInstance();
-  logger->log("VRadioRec", Log::DEBUG, "Draw bar clocks");
-
-  // Draw RTC
-  // Blank the area first
-  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
-  char timeString[20];
-  time_t t;
-  time(&t);
-  struct tm* tms = localtime(&t);
-  strftime(timeString, 19, "%H:%M", tms);
-  drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
-
-  // Draw clocks
-
-  rectangle(clocksRegion, barBlue);
-
-/*
-  ULONG currentFrameNum = player->getCurrentFrameNum();
-  ULONG lengthFrames;
-  if (myRec->recInfo->timerEnd > time(NULL))
-  {
-    // chasing playback
-    // Work out an approximate length in frames (good to 1s...)
-    lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
-  }
-  else
-  {
-//    lengthFrames = player->getLengthFrames();
-    lengthFrames = 0;
-  }
-
-  hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);
-  hmsf lengthHMSF = video->framesToHMSF(lengthFrames);
-
-  char buffer[100];
-  if (currentFrameNum >= lengthFrames)
-  {
-    strcpy(buffer, "-:--:-- / -:--:--");
-  }
-  else
-  {
-    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
-    logger->log("VRadioRec", Log::DEBUG, buffer);
-  }
-*/
-
-  ULONG currentSeconds = player->getCurrentSeconds();
-  ULONG lengthSeconds = player->getLengthSeconds();
-  char buffer[100];
-
-  if (lengthSeconds && (currentSeconds < lengthSeconds))
-  {
-    ULONG dcurrentSeconds = currentSeconds;
-    ULONG dlengthSeconds = lengthSeconds;
-
-    ULONG currentHours = dcurrentSeconds / 3600;
-    dcurrentSeconds %= 3600;
-    ULONG currentMinutes = dcurrentSeconds / 60;
-    dcurrentSeconds %= 60;
-
-    ULONG lengthHours = dlengthSeconds / 3600;
-    dlengthSeconds %= 3600;
-    ULONG lengthMinutes = dlengthSeconds / 60;
-    dlengthSeconds %= 60;
-
-    SNPRINTF(buffer, 99, "%01lu:%02lu:%02lu / %01lu:%02lu:%02lu", currentHours, currentMinutes, dcurrentSeconds, lengthHours, lengthMinutes, dlengthSeconds);
-    logger->log("VRadioRec", Log::DEBUG, buffer);
-  }
-  else
-  {
-    strcpy(buffer, "-:--:-- / -:--:--");
-  }
-
-  drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
-
-  // Draw progress bar
-  int progBarXbase = barRegion.x + 300;
-
-  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
-  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
-
-  if (currentSeconds > lengthSeconds) return;
-  if (lengthSeconds == 0) return;
-
-  // Draw yellow portion
-  int progressWidth = 302 * currentSeconds / lengthSeconds;
-  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-/*
-
-  if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
-  {
-    int nrWidth = (int)(302 * ((double)(lengthFrames - 0) / lengthFrames)); // 0 inserted instead of getlengthframes
-
-    Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
-//    Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
-    Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
-    rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);
-  }
-*/
-
-  logger->log("VRadioRec", Log::DEBUG, "blips");
-
-  // Now calc position for start margin blips
-  int posPix;
-
-  posPix = 302 * startMargin / lengthSeconds;
-  logger->log("VRadioRec", Log::DEBUG, "posPix %i", posPix);
-
-  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
-  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
-
-  posPix = 302 * (lengthSeconds - endMargin) / lengthSeconds;
-
-  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
-  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
-}
-
-void VRadioRec::removeBar()
-{
-  if (!barShowing) return;
-  timers->cancelTimer(this, 2);
-  barShowing = false;
-  rectangle(barRegion, Colour::BLACK);
-  boxstack->update(this, &barRegion);
-}
-
+/*\r
+    Copyright 2004-2006 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vradiorec.h"\r
+\r
+#include "command.h"\r
+#include "osd.h"\r
+#include "player.h"\r
+#include "wsymbol.h"\r
+#include "recording.h"\r
+#include "message.h"\r
+#include "vdr.h"\r
+#include "video.h"\r
+#include "timers.h"\r
+#include "playerradio.h"\r
+#include "boxstack.h"\r
+#include "remote.h"\r
+#include "vinfo.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+\r
+VRadioRec::VRadioRec(Recording* rec)\r
+{\r
+  boxstack = BoxStack::getInstance();\r
+  vdr = VDR::getInstance();\r
+  video = Video::getInstance();\r
+  timers = Timers::getInstance();\r
+  myRec = rec;\r
+  playing = false;\r
+  startMargin = 0;\r
+  endMargin = 0;\r
+\r
+  player = new PlayerRadio(Command::getInstance(), this);\r
+\r
+  char* cstartMargin = vdr->configLoad("Timers", "Start margin");\r
+  char* cendMargin = vdr->configLoad("Timers", "End margin");\r
+  if (!cstartMargin)\r
+  {\r
+    startMargin = 300; // 5 mins default\r
+  }\r
+  else\r
+  {\r
+    startMargin = atoi(cstartMargin) * 60;\r
+    delete[] cstartMargin;\r
+  }\r
+\r
+  if (!cendMargin)\r
+  {\r
+    endMargin = 300; // 5 mins default\r
+  }\r
+  else\r
+  {\r
+    endMargin = atoi(cendMargin) * 60;\r
+    delete[] cendMargin;\r
+  }\r
+\r
+  Log::getInstance()->log("VRadioRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);\r
+\r
+  setSize(video->getScreenWidth(), video->getScreenHeight());\r
+  createBuffer();\r
+  setPosition(0, 0);\r
+\r
+  barRegion.x = 0;\r
+  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?\r
+  barRegion.w = video->getScreenWidth();\r
+  barRegion.h = 58;\r
+\r
+  clocksRegion.x = barRegion.x + 140;\r
+  clocksRegion.y = barRegion.y + 12;\r
+  clocksRegion.w = 170;\r
+  clocksRegion.h = getFontHeight();\r
+\r
+\r
+  barBlue.set(0, 0, 150, 150);\r
+\r
+  barShowing = false;\r
+}\r
+\r
+void VRadioRec::preDelete()\r
+{\r
+  timers->cancelTimer(this, 1);\r
+  timers->cancelTimer(this, 2);\r
+}\r
+\r
+VRadioRec::~VRadioRec()\r
+{\r
+  if (playing) stopPlay();\r
+\r
+\r
+  // kill recInfo in case resumePoint has changed (likely)\r
+  myRec->dropRecInfo();\r
+  // FIXME - do this properly - save the resume point back to the server manually and update\r
+  // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well\r
+}\r
+\r
+void VRadioRec::draw()\r
+{\r
+  fillColour(Colour::BLACK);\r
+}\r
+\r
+void VRadioRec::go()\r
+{\r
+  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Starting stream: %s", myRec->getFileName());\r
+  ULONG lengthFrames = 0;\r
+  bool isPesRecording;\r
+  ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);\r
+  myRec->IsPesRecording = isPesRecording;\r
+\r
+  bool cantStart = false;\r
+\r
+  if (!lengthBytes) cantStart = true;\r
+  else if (!player->init(lengthBytes, lengthFrames, myRec->IsPesRecording)) cantStart = true;\r
+  else\r
+  {\r
+    doBar(0);\r
+  //  player->setStartBytes(startBytes);\r
+    player->play();\r
+    playing = true;\r
+  }\r
+\r
+  if (cantStart)\r
+  {\r
+    stopPlay(); // clean up\r
+\r
+    if (!vdr->isConnected())\r
+    {\r
+      Command::getInstance()->connectionLost();\r
+      return;\r
+    }\r
+\r
+    Message* m = new Message();\r
+    m->message = Message::CLOSE_ME;\r
+    m->from = this;\r
+    m->to = boxstack;\r
+    Command::getInstance()->postMessageNoLock(m);\r
+\r
+    VInfo* vi = new VInfo();\r
+    vi->setSize(400, 150);\r
+    vi->createBuffer();\r
+    if (video->getFormat() == Video::PAL)\r
+      vi->setPosition(170, 200);\r
+    else\r
+      vi->setPosition(160, 150);\r
+    vi->setExitable();\r
+    vi->setBorderOn(1);\r
+    vi->setTitleBarOn(0);\r
+    vi->setOneLiner(tr("Error playing recording"));\r
+    vi->draw();\r
+\r
+    m = new Message();\r
+    m->message = Message::ADD_VIEW;\r
+    m->to = boxstack;\r
+    m->parameter = (ULONG)vi;\r
+    Command::getInstance()->postMessageNoLock(m);\r
+  }\r
+}\r
+\r
+int VRadioRec::handleCommand(int command)\r
+{\r
+  switch(command)\r
+  {\r
+    case Remote::PLAY:\r
+    {\r
+      player->play();\r
+      doBar(0);\r
+      return 2;\r
+    }\r
+    case Remote::PLAYPAUSE:\r
+    {\r
+       player->playpause();\r
+        doBar(0);\r
+        return 2;\r
+    }\r
+\r
+    case Remote::STOP:\r
+    case Remote::BACK:\r
+    case Remote::MENU:\r
+    {\r
+      if (playing) stopPlay();\r
+      return 4;\r
+    }\r
+    case Remote::PAUSE:\r
+    {\r
+      player->pause();\r
+      doBar(0);\r
+      return 2;\r
+    }\r
+    case Remote::SKIPFORWARD:\r
+    {\r
+      doBar(3);\r
+      player->skipForward(60);\r
+      return 2;\r
+    }\r
+    case Remote::SKIPBACK:\r
+    {\r
+      doBar(4);\r
+      player->skipBackward(60);\r
+      return 2;\r
+    }\r
+    case Remote::YELLOW:\r
+    {\r
+      doBar(2);\r
+      player->skipBackward(10);\r
+      return 2;\r
+    }\r
+    case Remote::BLUE:\r
+    {\r
+      doBar(1);\r
+      player->skipForward(10);\r
+      return 2;\r
+    }\r
+    case Remote::OK:\r
+    {\r
+      if (barShowing) removeBar();\r
+      else doBar(0);\r
+      return 2;\r
+    }\r
+\r
+    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;\r
+    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;\r
+    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;\r
+    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;\r
+    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;\r
+    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;\r
+    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;\r
+    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;\r
+    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;\r
+    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;\r
+\r
+#ifdef DEV\r
+    case Remote::RED:\r
+    {\r
+      //player->test1();\r
+\r
+      return 2;\r
+    }\r
+    case Remote::GREEN:\r
+    {\r
+      //player->test2();\r
+      return 2;\r
+    }\r
+#endif\r
+\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+void VRadioRec::processMessage(Message* m)\r
+{\r
+  if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    int x=(m->parameter>>16)-(int)getScreenX();\r
+    int y=(m->parameter&0xFFFF)-(int)getScreenY();\r
+    if (!barShowing)\r
+    {\r
+      boxstack->handleCommand(Remote::OK); //simulate rok press\r
+    }\r
+    else if ((int)barRegion.x<=x && (int)barRegion.y<=y && ((int)barRegion.x+(int)barRegion.w)>=x\r
+             &&  ((int)barRegion.y+(int)barRegion.h)>=y)\r
+    {\r
+      int progBarXbase = barRegion.x + 300;\r
+      if (x>=(int)barRegion.x + progBarXbase + 24\r
+        && x<=(int)barRegion.x + progBarXbase + 4 + 302\r
+        && y>=(int)barRegion.y + 12 - 2\r
+        && y<=(int)barRegion.y + 12 - 2+28)\r
+      {\r
+        int cx=x-(barRegion.x + progBarXbase + 4);\r
+        double percent=((double)cx)/302.*100.;\r
+        player->jumpToPercent(percent);\r
+        doBar(3);\r
+        return;\r
+        //  int progressWidth = 302 * currentFrameNum / lengthFrames;\r
+        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+      }\r
+    }\r
+    else\r
+    {\r
+      boxstack->handleCommand(Remote::OK); //simulate rok press\r
+    }\r
+  }\r
+  else if (m->message == Message::PLAYER_EVENT)\r
+  {\r
+    if (m->from != player) return;\r
+\r
+    Log::getInstance()->log("VRadioRec", Log::DEBUG, "Message received");\r
+\r
+    switch(m->parameter)\r
+    {\r
+      case Player::CONNECTION_LOST: // connection lost detected\r
+      {\r
+        // I can't handle this, send it to command\r
+        Message* m2 = new Message();\r
+        m2->to = Command::getInstance();\r
+        m2->message = Message::CONNECTION_LOST;\r
+        Command::getInstance()->postMessageNoLock(m2);\r
+        break;\r
+      }\r
+      case Player::STOP_PLAYBACK:\r
+      {\r
+        // FIXME Obselete ish - improve this\r
+        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+        m2->to = Command::getInstance();\r
+        m2->message = Message::STOP_PLAYBACK;\r
+        Command::getInstance()->postMessageNoLock(m2);\r
+        break;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+void VRadioRec::stopPlay()\r
+{\r
+  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Pre stopPlay");\r
+\r
+  removeBar();\r
+  player->stop();\r
+  vdr->stopStreaming();\r
+  delete player;\r
+\r
+  playing = false;\r
+\r
+  if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }\r
+  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Post stopPlay");\r
+}\r
+\r
+void VRadioRec::doBar(int action)\r
+{\r
+  barShowing = true;\r
+\r
+  rectangle(barRegion, barBlue);\r
+\r
+  /* Work out what to display - choices:\r
+\r
+  Playing  >\r
+  Paused   ||\r
+\r
+  Specials, informed by parameter\r
+\r
+  Skip forward 10s    >|\r
+  Skip backward 10s   |<\r
+  Skip forward 1m     >>|\r
+  Skip backward 1m    |<<\r
+\r
+  */\r
+\r
+  WSymbol w;\r
+  TEMPADD(&w);\r
+  w.nextSymbol = 0;\r
+  w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
+\r
+  UCHAR playerState = 0;\r
+\r
+  if (action)\r
+  {\r
+    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;\r
+    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;\r
+    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;\r
+    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;\r
+  }\r
+  else\r
+  {\r
+    playerState = player->getState();\r
+    if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;\r
+    else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;\r
+    else                                       w.nextSymbol = WSymbol::PLAY;\r
+  }\r
+\r
+  w.draw();\r
+\r
+  drawBarClocks();\r
+\r
+  BoxStack::getInstance()->update(this, &barRegion);\r
+\r
+  timers->setTimerD(this, 1, 4); // only set the getridofbar timer if not ffwd/fbwd\r
+  timers->setTimerD(this, 2, 0, 200000000);\r
+}\r
+\r
+void VRadioRec::timercall(int clientReference)\r
+{\r
+  switch(clientReference)\r
+  {\r
+    case 1:\r
+    {\r
+      // Remove bar\r
+      removeBar();\r
+      break;\r
+    }\r
+    case 2:\r
+    {\r
+      // Update clock\r
+      if (!barShowing) break;\r
+      drawBarClocks();\r
+      boxstack->update(this, &barRegion);\r
+      \r
+      timers->setTimerD(this, 2, 0, 200000000);\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+void VRadioRec::drawBarClocks()\r
+{\r
+  Log* logger = Log::getInstance();\r
+  logger->log("VRadioRec", Log::DEBUG, "Draw bar clocks");\r
+\r
+  // Draw RTC\r
+  // Blank the area first\r
+  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
+  char timeString[20];\r
+  time_t t;\r
+  time(&t);\r
+  struct tm* tms = localtime(&t);\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);\r
+\r
+  // Draw clocks\r
+\r
+  rectangle(clocksRegion, barBlue);\r
+\r
+/*\r
+  ULONG currentFrameNum = player->getCurrentFrameNum();\r
+  ULONG lengthFrames;\r
+  if (myRec->recInfo->timerEnd > time(NULL))\r
+  {\r
+    // chasing playback\r
+    // Work out an approximate length in frames (good to 1s...)\r
+    lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();\r
+  }\r
+  else\r
+  {\r
+//    lengthFrames = player->getLengthFrames();\r
+    lengthFrames = 0;\r
+  }\r
+\r
+  hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);\r
+  hmsf lengthHMSF = video->framesToHMSF(lengthFrames);\r
+\r
+  char buffer[100];\r
+  if (currentFrameNum >= lengthFrames)\r
+  {\r
+    strcpy(buffer, "-:--:-- / -:--:--");\r
+  }\r
+  else\r
+  {\r
+    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
+    logger->log("VRadioRec", Log::DEBUG, buffer);\r
+  }\r
+*/\r
+\r
+  ULONG currentSeconds = player->getCurrentSeconds();\r
+  ULONG lengthSeconds = player->getLengthSeconds();\r
+  char buffer[100];\r
+\r
+  if (lengthSeconds && (currentSeconds < lengthSeconds))\r
+  {\r
+    ULONG dcurrentSeconds = currentSeconds;\r
+    ULONG dlengthSeconds = lengthSeconds;\r
+\r
+    ULONG currentHours = dcurrentSeconds / 3600;\r
+    dcurrentSeconds %= 3600;\r
+    ULONG currentMinutes = dcurrentSeconds / 60;\r
+    dcurrentSeconds %= 60;\r
+\r
+    ULONG lengthHours = dlengthSeconds / 3600;\r
+    dlengthSeconds %= 3600;\r
+    ULONG lengthMinutes = dlengthSeconds / 60;\r
+    dlengthSeconds %= 60;\r
+\r
+    SNPRINTF(buffer, 99, "%01lu:%02lu:%02lu / %01lu:%02lu:%02lu", currentHours, currentMinutes, dcurrentSeconds, lengthHours, lengthMinutes, dlengthSeconds);\r
+    logger->log("VRadioRec", Log::DEBUG, buffer);\r
+  }\r
+  else\r
+  {\r
+    strcpy(buffer, "-:--:-- / -:--:--");\r
+  }\r
+\r
+  drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);\r
+\r
+  // Draw progress bar\r
+  int progBarXbase = barRegion.x + 300;\r
+\r
+  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);\r
+  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
+\r
+  if (currentSeconds > lengthSeconds) return;\r
+  if (lengthSeconds == 0) return;\r
+\r
+  // Draw yellow portion\r
+  int progressWidth = 302 * currentSeconds / lengthSeconds;\r
+  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+/*\r
+\r
+  if (myRec->recInfo->timerEnd > time(NULL)) // if chasing\r
+  {\r
+    int nrWidth = (int)(302 * ((double)(lengthFrames - 0) / lengthFrames)); // 0 inserted instead of getlengthframes\r
+\r
+    Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);\r
+//    Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());\r
+    Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);\r
+    rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);\r
+  }\r
+*/\r
+\r
+  logger->log("VRadioRec", Log::DEBUG, "blips");\r
+\r
+  // Now calc position for start margin blips\r
+  int posPix;\r
+\r
+  posPix = 302 * startMargin / lengthSeconds;\r
+  logger->log("VRadioRec", Log::DEBUG, "posPix %i", posPix);\r
+\r
+  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);\r
+  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);\r
+\r
+  posPix = 302 * (lengthSeconds - endMargin) / lengthSeconds;\r
+\r
+  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);\r
+  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);\r
+}\r
+\r
+void VRadioRec::removeBar()\r
+{\r
+  if (!barShowing) return;\r
+  timers->cancelTimer(this, 2);\r
+  barShowing = false;\r
+  rectangle(barRegion, Colour::BLACK);\r
+  boxstack->update(this, &barRegion);\r
+}\r
+\r
index 4a6a7fecfa1495b72c1eb3c8ea2b1edeeda91f0a..0ba3b165b586ba30d8b794e1eee69ba62a985fff 100644 (file)
@@ -72,7 +72,7 @@ void VRecMove::setParent(void* tparent)
   parent = tparent;
 }
 
-void VRecMove::addDirs(Directory* dir, char* prefix)
+void VRecMove::addDirs(Directory* dir,const char* prefix)
 {
   Directory* currentDir;
   for(DirectoryList::iterator i = dir->dirList.begin(); i != dir->dirList.end(); i++)
index c38afe426f606fb2e5ba2d8baa7d8232a9e04067..1c6fa936ba9c170c7dc9caf8edb9d2734d8a103e 100644 (file)
@@ -46,7 +46,7 @@ class VRecMove : public TBBoxx
     void* parent;
     RecMan* recman;
     WSelectList sl;
-    void addDirs(Directory* dir, char* prefix);
+    void addDirs(Directory* dir,const char* prefix);
 };
 
 #endif
index f655ae01e12a0389dddf6c185ba8f4be01b23aa0..104ff5bc7d97c8f5e6f7bf20b1456ef3afaa9d95 100644 (file)
-/*
-    Copyright 2004-2008 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vrecording.h"
-
-#include "remote.h"
-#include "recinfo.h"
-#include "vquestion.h"
-#include "vinfo.h"
-#include "vdr.h"
-#include "colour.h"
-#include "video.h"
-#include "i18n.h"
-#include "command.h"
-#include "vrecmove.h"
-#include "boxstack.h"
-#include "recman.h"
-#include "vrecordinglist.h"
-#include "recording.h"
-#include "message.h"
-#include "log.h"
-
-VRecording::VRecording(RecMan* trecman, Recording* trec)
-{
-  rec = trec;
-  recman = trecman;
-  
-  Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());
-  rec->loadRecInfo();
-  Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());
-
-  setSize(570, 420);
-  createBuffer();
-  if (Video::getInstance()->getFormat() == Video::PAL)
-  {
-    setPosition(80, 70);
-  }
-  else
-  {
-    setPosition(70, 35);
-  }
-
-  setTitleBarOn(1);
-  setBorderOn(1);
-  setTitleText(rec->getProgName());
-  setTitleBarColour(Colour::TITLEBARBACKGROUND);
-
-  summary.setPosition(10, 30 + 5);
-  summary.setSize(area.w - 20, area.h - 30 - 15 - 50);
-  summary.setParaMode(true);
-
-  if (rec->recInfo &&strlen(rec->recInfo->summary))
-    summary.setText(rec->recInfo->summary);
-  else
-    summary.setText(tr("Summary unavailable"));
-
-  add(&summary);
-  
-  
-  buttonPlay.setPosition(10, area.h - 40);
-  buttonResume.setPosition(150, area.h - 40);
-  buttonMove.setPosition(290, area.h - 40);
-  buttonDelete.setPosition(430, area.h - 40);
-  
-  int sfh = Surface::getFontHeight();
-  
-  buttonPlay.setSize(130, sfh);
-  buttonResume.setSize(130, sfh);
-  buttonMove.setSize(130, sfh);
-  buttonDelete.setSize(130, sfh);
-  
-  buttonRegion.x = 10;
-  buttonRegion.y = area.h - 40;
-  buttonRegion.w = 550;
-  buttonRegion.h = sfh;
-
-  buttonPlay.setText(tr("Play"));
-  buttonResume.setText(tr("Resume"));
-  buttonMove.setText(tr("Move"));
-  buttonDelete.setText(tr("Delete"));
-  
-  add(&buttonPlay);
-  add(&buttonResume);    
-  add(&buttonMove);
-  add(&buttonDelete);
-  
-  buttonPlay.setActive(1);
-  selected = 1;
-}
-
-VRecording::~VRecording()
-{
-}
-
-void VRecording::setParent(VRecordingList* tvRecList)
-{
-  vRecList = tvRecList;
-}
-
-void VRecording::draw()
-{
-  TBBoxx::draw();
-}
-
-int VRecording::handleCommand(int command)
-{
-  switch(command)
-  {
-    case Remote::LEFT:
-    case Remote::DF_LEFT:
-    case Remote::DF_UP:
-    case Remote::UP:
-    {
-      doLeft();
-      return 2;
-    }
-    case Remote::RIGHT:
-    case Remote::DF_RIGHT:
-    case Remote::DF_DOWN:
-    case Remote::DOWN:
-    {
-      doRight();
-      return 2;
-    }
-    case Remote::OK:
-    {
-
-      if (selected == 1)
-      {
-        Message* m = new Message(); // Must be done after this view deleted
-        m->from = this;
-        m->to = vRecList;
-        m->message = Message::PLAY_SELECTED_RECORDING;
-        Command::getInstance()->postMessageNoLock(m);
-        return 4;
-      }
-
-      if (selected == 2)
-      {
-        Message* m = new Message(); // Must be done after this view deleted
-        m->from = this;
-        m->to = vRecList;
-        m->message = Message::RESUME_SELECTED_RECORDING;
-        Command::getInstance()->postMessageNoLock(m);
-        return 4;
-      }
-
-      if (selected == 3)
-      {
-        VRecMove* vrm = new VRecMove(recman);
-        vrm->setParent(this);
-        vrm->draw();
-        BoxStack::getInstance()->add(vrm);
-        BoxStack::getInstance()->update(vrm);
-        return 2;
-      }
-
-      if (selected == 4)
-      {
-        VQuestion* v = new VQuestion(this);
-        v->setSize(260, 180);
-        v->createBuffer();
-        v->setTitleBarColour(Colour::DANGER);
-        v->setTitleBarOn(1);
-        v->setBorderOn(1);
-        v->setTitleText(tr("Delete recording"));
-        v->setMainText(tr("Are you sure you want to delete this recording?"));
-        v->setDefault(VQuestion::NO);
-        if (Video::getInstance()->getFormat() == Video::PAL)
-        {
-          v->setPosition(230, 160);
-        }
-        else
-        {
-          v->setPosition(220, 140);
-        }
-
-        v->draw();
-        BoxStack::getInstance()->add(v);
-        BoxStack::getInstance()->update(v);
-        return 2;
-      }
-    }
-
-    case Remote::BACK:
-    {
-      return 4;
-    }
-  }
-  // stop command getting to any more views
-  return 1;
-}
-
-void VRecording::doRight()
-{
-  switch(selected)
-  {
-    case 1:
-      buttonPlay.setActive(0);
-      buttonResume.setActive(1);
-      buttonPlay.draw();
-      buttonResume.draw();
-      break;
-    case 2:
-      buttonResume.setActive(0);
-      buttonMove.setActive(1);
-      buttonResume.draw();
-      buttonMove.draw();
-      break;
-    case 3:
-      buttonMove.setActive(0);
-      buttonDelete.setActive(1);
-      buttonMove.draw();
-      buttonDelete.draw();
-      break;
-    case 4:
-      buttonDelete.setActive(0);
-      buttonPlay.setActive(1);
-      buttonDelete.draw();
-      buttonPlay.draw();
-      break;
-  }
-  
-  if (++selected == 5) selected = 1;
-  
-  BoxStack::getInstance()->update(this, &buttonRegion);
-}
-
-void VRecording::doLeft()
-{
-  switch(selected)
-  {
-    case 1:
-      buttonPlay.setActive(0);
-      buttonDelete.setActive(1);
-      buttonPlay.draw();
-      buttonDelete.draw();
-      break;
-    case 2:
-      buttonResume.setActive(0);
-      buttonPlay.setActive(1);
-      buttonResume.draw();
-      buttonPlay.draw();
-      break;
-    case 3:
-      buttonMove.setActive(0);
-      buttonResume.setActive(1);
-      buttonMove.draw();
-      buttonResume.draw();
-      break;
-    case 4:
-      buttonDelete.setActive(0);
-      buttonMove.setActive(1);
-      buttonDelete.draw();
-      buttonMove.draw();
-      break;
-  }
-  
-  if (--selected == 0) selected = 4;
-  
-  BoxStack::getInstance()->update(this, &buttonRegion);
-}
-
-void VRecording::processMessage(Message* m)
-{
-  if (m->message == Message::MOUSE_MOVE)
-  {
-    if (buttonPlay.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      buttonPlay.setActive(1);
-      buttonResume.setActive(0);
-      buttonMove.setActive(0);
-      buttonDelete.setActive(0);
-      selected=1;
-      draw();
-      BoxStack::getInstance()->update(this);
-    }
-    else if (buttonResume.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      buttonPlay.setActive(0);
-      buttonResume.setActive(1);
-      buttonMove.setActive(0);
-      buttonDelete.setActive(0);
-      selected=2;
-      draw();
-      BoxStack::getInstance()->update(this);
-    }
-    else if (buttonMove.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      buttonPlay.setActive(0);
-      buttonResume.setActive(0);
-      buttonMove.setActive(1);
-      buttonDelete.setActive(0);
-      selected=3;
-      draw();
-      BoxStack::getInstance()->update(this);
-    }
-    else if (buttonDelete.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      buttonPlay.setActive(0);
-      buttonResume.setActive(0);
-      buttonMove.setActive(0);
-      buttonDelete.setActive(1);
-      selected=4;
-      draw();
-      BoxStack::getInstance()->update(this);
-    }
-  }
-  else if (m->message == Message::MOUSE_LBDOWN)
-  {
-    if (buttonPlay.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
-    }
-    else if (buttonResume.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
-    }
-    else if (buttonMove.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
-    }
-    else if (buttonDelete.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
-    }
-    else
-    {
-      //check if press is outside this view! then simulate cancel
-      int x=(m->parameter>>16)-getScreenX();
-      int y=(m->parameter&0xFFFF)-getScreenY();
-      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
-      {
-        BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
-      }
-    }
-  }
-  else if (m->message == Message::QUESTION_YES)
-  {
-    if (selected == 4)
-    {
-      Message* m2 = new Message(); // Delete self
-      m2->from = this;
-      m2->to = BoxStack::getInstance();
-      m2->message = Message::CLOSE_ME;
-      Command::getInstance()->postMessageNoLock(m2);
-
-      m2 = new Message(); // OK. Want this to delete before this message does its job
-      m2->from = this;
-      m2->to = vRecList;
-      m2->message = Message::DELETE_SELECTED_RECORDING;
-      Command::getInstance()->postMessageNoLock(m2);
-    }
-  }
-  else if (m->message == Message::MOVE_RECORDING)
-  {
-    Message* m2 = new Message(); // Delete self
-    m2->from = this;
-    m2->to = BoxStack::getInstance();
-    m2->message = Message::CLOSE_ME;
-    Command::getInstance()->postMessageNoLock(m2);
-
-    m2 = new Message();
-    m2->from = this;
-    m2->to = vRecList;
-    m2->message = Message::MOVE_RECORDING;
-    m2->parameter = m->parameter;
-    Command::getInstance()->postMessageNoLock(m2);
-  }
-}
-
+/*\r
+    Copyright 2004-2008 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vrecording.h"\r
+\r
+#include "remote.h"\r
+#include "recinfo.h"\r
+#include "vquestion.h"\r
+#include "vinfo.h"\r
+#include "vdr.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "i18n.h"\r
+#include "command.h"\r
+#include "vrecmove.h"\r
+#include "boxstack.h"\r
+#include "recman.h"\r
+#include "vrecordinglist.h"\r
+#include "recording.h"\r
+#include "message.h"\r
+#include "log.h"\r
+\r
+VRecording::VRecording(RecMan* trecman, Recording* trec)\r
+{\r
+  rec = trec;\r
+  recman = trecman;\r
+  \r
+  Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());\r
+  rec->loadRecInfo();\r
+  Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());\r
+\r
+  setSize(570, 420);\r
+  createBuffer();\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+  {\r
+    setPosition(80, 70);\r
+  }\r
+  else\r
+  {\r
+    setPosition(70, 35);\r
+  }\r
+\r
+  setTitleBarOn(1);\r
+  setBorderOn(1);\r
+  setTitleText(rec->getProgName());\r
+  setTitleBarColour(Colour::TITLEBARBACKGROUND);\r
+\r
+  summary.setPosition(10, 30 + 5);\r
+  summary.setSize(area.w - 20, area.h - 30 - 15 - 50);\r
+  summary.setParaMode(true);\r
+\r
+  if (rec->recInfo &&strlen(rec->recInfo->summary))\r
+    summary.setText(rec->recInfo->summary);\r
+  else\r
+    summary.setText(tr("Summary unavailable"));\r
+\r
+  add(&summary);\r
+  \r
+  \r
+  buttonPlay.setPosition(10, area.h - 40);\r
+  buttonResume.setPosition(150, area.h - 40);\r
+  buttonMove.setPosition(290, area.h - 40);\r
+  buttonDelete.setPosition(430, area.h - 40);\r
+  \r
+  int sfh = getFontHeight();\r
+  \r
+  buttonPlay.setSize(130, sfh);\r
+  buttonResume.setSize(130, sfh);\r
+  buttonMove.setSize(130, sfh);\r
+  buttonDelete.setSize(130, sfh);\r
+  \r
+  buttonRegion.x = 10;\r
+  buttonRegion.y = area.h - 40;\r
+  buttonRegion.w = 550;\r
+  buttonRegion.h = sfh;\r
+\r
+  buttonPlay.setText(tr("Play"));\r
+  buttonResume.setText(tr("Resume"));\r
+  buttonMove.setText(tr("Move"));\r
+  buttonDelete.setText(tr("Delete"));\r
+  \r
+  add(&buttonPlay);\r
+  add(&buttonResume);    \r
+  add(&buttonMove);\r
+  add(&buttonDelete);\r
+  \r
+  buttonPlay.setActive(1);\r
+  selected = 1;\r
+}\r
+\r
+VRecording::~VRecording()\r
+{\r
+}\r
+\r
+void VRecording::setParent(VRecordingList* tvRecList)\r
+{\r
+  vRecList = tvRecList;\r
+}\r
+\r
+void VRecording::draw()\r
+{\r
+  TBBoxx::draw();\r
+}\r
+\r
+int VRecording::handleCommand(int command)\r
+{\r
+  switch(command)\r
+  {\r
+    case Remote::LEFT:\r
+    case Remote::DF_LEFT:\r
+    case Remote::DF_UP:\r
+    case Remote::UP:\r
+    {\r
+      doLeft();\r
+      return 2;\r
+    }\r
+    case Remote::RIGHT:\r
+    case Remote::DF_RIGHT:\r
+    case Remote::DF_DOWN:\r
+    case Remote::DOWN:\r
+    {\r
+      doRight();\r
+      return 2;\r
+    }\r
+    case Remote::OK:\r
+    {\r
+\r
+      if (selected == 1)\r
+      {\r
+        Message* m = new Message(); // Must be done after this view deleted\r
+        m->from = this;\r
+        m->to = vRecList;\r
+        m->message = Message::PLAY_SELECTED_RECORDING;\r
+        Command::getInstance()->postMessageNoLock(m);\r
+        return 4;\r
+      }\r
+\r
+      if (selected == 2)\r
+      {\r
+        Message* m = new Message(); // Must be done after this view deleted\r
+        m->from = this;\r
+        m->to = vRecList;\r
+        m->message = Message::RESUME_SELECTED_RECORDING;\r
+        Command::getInstance()->postMessageNoLock(m);\r
+        return 4;\r
+      }\r
+\r
+      if (selected == 3)\r
+      {\r
+        VRecMove* vrm = new VRecMove(recman);\r
+        vrm->setParent(this);\r
+        vrm->draw();\r
+        BoxStack::getInstance()->add(vrm);\r
+        BoxStack::getInstance()->update(vrm);\r
+        return 2;\r
+      }\r
+\r
+      if (selected == 4)\r
+      {\r
+        VQuestion* v = new VQuestion(this);\r
+        v->setSize(260, 180);\r
+        v->createBuffer();\r
+        v->setTitleBarColour(Colour::DANGER);\r
+        v->setTitleBarOn(1);\r
+        v->setBorderOn(1);\r
+        v->setTitleText(tr("Delete recording"));\r
+        v->setMainText(tr("Are you sure you want to delete this recording?"));\r
+        v->setDefault(VQuestion::NO);\r
+        if (Video::getInstance()->getFormat() == Video::PAL)\r
+        {\r
+          v->setPosition(230, 160);\r
+        }\r
+        else\r
+        {\r
+          v->setPosition(220, 140);\r
+        }\r
+\r
+        v->draw();\r
+        BoxStack::getInstance()->add(v);\r
+        BoxStack::getInstance()->update(v);\r
+        return 2;\r
+      }\r
+    }\r
+\r
+    case Remote::BACK:\r
+    {\r
+      return 4;\r
+    }\r
+  }\r
+  // stop command getting to any more views\r
+  return 1;\r
+}\r
+\r
+void VRecording::doRight()\r
+{\r
+  switch(selected)\r
+  {\r
+    case 1:\r
+      buttonPlay.setActive(0);\r
+      buttonResume.setActive(1);\r
+      buttonPlay.draw();\r
+      buttonResume.draw();\r
+      break;\r
+    case 2:\r
+      buttonResume.setActive(0);\r
+      buttonMove.setActive(1);\r
+      buttonResume.draw();\r
+      buttonMove.draw();\r
+      break;\r
+    case 3:\r
+      buttonMove.setActive(0);\r
+      buttonDelete.setActive(1);\r
+      buttonMove.draw();\r
+      buttonDelete.draw();\r
+      break;\r
+    case 4:\r
+      buttonDelete.setActive(0);\r
+      buttonPlay.setActive(1);\r
+      buttonDelete.draw();\r
+      buttonPlay.draw();\r
+      break;\r
+  }\r
+  \r
+  if (++selected == 5) selected = 1;\r
+  \r
+  BoxStack::getInstance()->update(this, &buttonRegion);\r
+}\r
+\r
+void VRecording::doLeft()\r
+{\r
+  switch(selected)\r
+  {\r
+    case 1:\r
+      buttonPlay.setActive(0);\r
+      buttonDelete.setActive(1);\r
+      buttonPlay.draw();\r
+      buttonDelete.draw();\r
+      break;\r
+    case 2:\r
+      buttonResume.setActive(0);\r
+      buttonPlay.setActive(1);\r
+      buttonResume.draw();\r
+      buttonPlay.draw();\r
+      break;\r
+    case 3:\r
+      buttonMove.setActive(0);\r
+      buttonResume.setActive(1);\r
+      buttonMove.draw();\r
+      buttonResume.draw();\r
+      break;\r
+    case 4:\r
+      buttonDelete.setActive(0);\r
+      buttonMove.setActive(1);\r
+      buttonDelete.draw();\r
+      buttonMove.draw();\r
+      break;\r
+  }\r
+  \r
+  if (--selected == 0) selected = 4;\r
+  \r
+  BoxStack::getInstance()->update(this, &buttonRegion);\r
+}\r
+\r
+void VRecording::processMessage(Message* m)\r
+{\r
+  if (m->message == Message::MOUSE_MOVE)\r
+  {\r
+    if (buttonPlay.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      buttonPlay.setActive(1);\r
+      buttonResume.setActive(0);\r
+      buttonMove.setActive(0);\r
+      buttonDelete.setActive(0);\r
+      selected=1;\r
+      draw();\r
+      BoxStack::getInstance()->update(this);\r
+    }\r
+    else if (buttonResume.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      buttonPlay.setActive(0);\r
+      buttonResume.setActive(1);\r
+      buttonMove.setActive(0);\r
+      buttonDelete.setActive(0);\r
+      selected=2;\r
+      draw();\r
+      BoxStack::getInstance()->update(this);\r
+    }\r
+    else if (buttonMove.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      buttonPlay.setActive(0);\r
+      buttonResume.setActive(0);\r
+      buttonMove.setActive(1);\r
+      buttonDelete.setActive(0);\r
+      selected=3;\r
+      draw();\r
+      BoxStack::getInstance()->update(this);\r
+    }\r
+    else if (buttonDelete.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      buttonPlay.setActive(0);\r
+      buttonResume.setActive(0);\r
+      buttonMove.setActive(0);\r
+      buttonDelete.setActive(1);\r
+      selected=4;\r
+      draw();\r
+      BoxStack::getInstance()->update(this);\r
+    }\r
+  }\r
+  else if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    if (buttonPlay.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
+    }\r
+    else if (buttonResume.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
+    }\r
+    else if (buttonMove.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
+    }\r
+    else if (buttonDelete.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
+    }\r
+    else\r
+    {\r
+      //check if press is outside this view! then simulate cancel\r
+      int x=(m->parameter>>16)-getScreenX();\r
+      int y=(m->parameter&0xFFFF)-getScreenY();\r
+      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+      {\r
+        BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
+      }\r
+    }\r
+  }\r
+  else if (m->message == Message::QUESTION_YES)\r
+  {\r
+    if (selected == 4)\r
+    {\r
+      Message* m2 = new Message(); // Delete self\r
+      m2->from = this;\r
+      m2->to = BoxStack::getInstance();\r
+      m2->message = Message::CLOSE_ME;\r
+      Command::getInstance()->postMessageNoLock(m2);\r
+\r
+      m2 = new Message(); // OK. Want this to delete before this message does its job\r
+      m2->from = this;\r
+      m2->to = vRecList;\r
+      m2->message = Message::DELETE_SELECTED_RECORDING;\r
+      Command::getInstance()->postMessageNoLock(m2);\r
+    }\r
+  }\r
+  else if (m->message == Message::MOVE_RECORDING)\r
+  {\r
+    Message* m2 = new Message(); // Delete self\r
+    m2->from = this;\r
+    m2->to = BoxStack::getInstance();\r
+    m2->message = Message::CLOSE_ME;\r
+    Command::getInstance()->postMessageNoLock(m2);\r
+\r
+    m2 = new Message();\r
+    m2->from = this;\r
+    m2->to = vRecList;\r
+    m2->message = Message::MOVE_RECORDING;\r
+    m2->parameter = m->parameter;\r
+    Command::getInstance()->postMessageNoLock(m2);\r
+  }\r
+}\r
+\r
index bf96f2b693f4c56cab1d3bd180a74a943c247114..f46050cdee6f3c3dfca16df525c078c1fc73aece 100644 (file)
-/*
-    Copyright 2004-2007 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vrecordinglist.h"
-
-#include "recman.h"
-#include "directory.h"
-#include "recording.h"
-#include "remote.h"
-#include "wsymbol.h"
-#include "boxstack.h"
-#include "vrecordingmenu.h"
-#include "vrecording.h"
-#include "vdr.h"
-#include "vvideorec.h"
-#include "vradiorec.h"
-#include "colour.h"
-#include "video.h"
-#include "i18n.h"
-#include "command.h"
-#include "vinfo.h"
-#include "log.h"
-
-VRecordingList::VRecordingList()
-{
-  boxstack = BoxStack::getInstance();
-  recman = NULL;
-  loading = true;
-
-  setSize(570, 420);
-  createBuffer();
-  if (Video::getInstance()->getFormat() == Video::PAL)
-  {
-    setPosition(80, 70);
-  }
-  else
-  {
-    setPosition(70, 35);
-  }
-
-  setTitleBarOn(1);
-  setTitleBarColour(Colour::TITLEBARBACKGROUND);
-
-  sl.setPosition(10, 30 + 5);
-  sl.setSize(area.w - 20, area.h - 30 - 15 - 30);
-  add(&sl);
-}
-
-VRecordingList::~VRecordingList()
-{
-  delete recman;
-}
-
-void VRecordingList::drawData(bool doIndexPop)
-{
-  int saveIndex = sl.getCurrentOption();
-  int saveTop = sl.getTopOption();
-
-  sl.clear();
-  sl.addColumn(0);
-  sl.addColumn(110);
-
-  int first = 1;
-
-  char tempA[300]; // FIXME  this is guesswork!
-  char tempB[300]; // FIXME
-  struct tm* btime;
-
-  Directory* currentSubDir;
-  DirectoryList::iterator i;
-  DirectoryList* dirList = recman->getDirectories();
-  for (i = dirList->begin(); i != dirList->end(); i++)
-  {
-    currentSubDir = *i;
-    SNPRINTF(tempA, 299, tr("<dir> %lu\t%s"), currentSubDir->getNumRecordings(), currentSubDir->name);
-    currentSubDir->index = sl.addOption(tempA, 0, first);
-    first = 0;
-  }
-
-  // FIXME convert the whole program to time_t's
-
-  Recording* currentRec;
-  RecordingList::iterator j;
-  RecordingList* recList = recman->getRecordings();
-  for (j = recList->begin(); j != recList->end(); j++)
-  {
-    currentRec = *j;
-    time_t recStartTime = (time_t)currentRec->getStartTime();
-    btime = localtime(&recStartTime);
-//NMT does not like this too!
-       //#ifndef _MSC_VER
-//    strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime);
-//#else
-    strftime(tempA, 299, "%d/%m %H:%M ", btime);
-//#endif
-    sprintf(tempB, "%s\t%s", tempA, currentRec->getProgName());
-    currentRec->index = sl.addOption(tempB, 0, first);
-    first = 0;
-  }
-
-  if (doIndexPop)
-  {
-    sl.hintSetCurrent(slIndexStack.top());
-    slIndexStack.pop();
-  }
-  else
-  {
-    sl.hintSetCurrent(saveIndex);
-    sl.hintSetTop(saveTop);
-  }
-  sl.draw();
-  doShowingBar();
-}
-
-void VRecordingList::draw(bool doIndexPop)
-{
-  if (!loading)
-  {
-    if (recman->isSubDir())
-    {
-      char title[300];
-      SNPRINTF(title, 299, tr("Recordings - %s"), recman->getCurDirName());
-      setTitleText(title, 364);
-    }
-    else
-    {
-      setTitleText(tr("Recordings"));
-    }
-  }
-
-  TBBoxx::draw();
-
-  if (loading)
-  {
-    drawText(tr("Loading..."), 240, 180, Colour::LIGHTTEXT);
-  }
-  else
-  {
-    char freeSpace[50];
-    int gigFree = recman->getFreeSpace() / 1024;
-    SNPRINTF(freeSpace, 49, tr("%lu%% used, %iGB free"), recman->getUsedPercent(), gigFree);
-    drawTextRJ(freeSpace, 560, 5, Colour::LIGHTTEXT);
-
-    // Symbols
-
-    WSymbol w;
-    TEMPADD(&w);
-
-    w.nextSymbol = WSymbol::UP;
-    w.setPosition(20, 385);
-    w.draw();
-
-    w.nextSymbol = WSymbol::DOWN;
-    w.setPosition(50, 385);
-    w.draw();
-
-    w.nextSymbol = WSymbol::SKIPBACK;
-    w.setPosition(85, 385);
-    w.draw();
-
-    w.nextSymbol = WSymbol::SKIPFORWARD;
-    w.setPosition(115, 385);
-    w.draw();
-
-    w.nextSymbol = WSymbol::PLAY;
-    w.setPosition(150, 385);
-    w.draw();
-
-    drawTextRJ(tr("[ok] = menu"), 560, 385, Colour::LIGHTTEXT);
-
-    // All static stuff done
-
-    drawData(doIndexPop);
-  }
-}
-
-void VRecordingList::doShowingBar()
-{
-  int topOption = sl.getTopOption() + 1;
-  if (sl.getNumOptions() == 0) topOption = 0;
-
-  rectangle(220, 385, 180, 25, Colour::VIEWBACKGROUND);
-  char showing[200];
-  sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());
-  drawText(showing, 220, 385, Colour::LIGHTTEXT);
-}
-
-void VRecordingList::processMessage(Message* m)
-{
-  Log::getInstance()->log("VRecordingList", Log::DEBUG, "Got message value %lu", m->message);
-
-  if (m->message == Message::MOUSE_MOVE)
-  {
-    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      sl.draw();
-      doShowingBar();
-      boxstack->update(this);
-    }
-  }
-  else if (m->message == Message::MOUSE_LBDOWN)
-  {
-    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      boxstack->handleCommand(Remote::OK); //simulate OK press
-    }
-    else
-    {
-      //check if press is outside this view! then simulate cancel
-      int x=(m->parameter>>16)-getScreenX();
-      int y=(m->parameter&0xFFFF)-getScreenY();
-      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
-      {
-        boxstack->handleCommand(Remote::BACK); //simulate cancel press
-      }
-    }
-  }
-  else if (m->message == Message::DELETE_SELECTED_RECORDING)
-  {
-    Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing delete selected");
-    doDeleteSelected();
-  }
-  else if (m->message == Message::MOVE_RECORDING)
-  {
-    Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing move recording");
-    doMoveRecording((Directory*)m->parameter);
-  }
-  else if (m->message == Message::PLAY_SELECTED_RECORDING)
-  {
-    doPlay(false);
-  }
-  else if (m->message == Message::RESUME_SELECTED_RECORDING)
-  {
-    doPlay(true);
-  }
-}
-
-void VRecordingList::doDeleteSelected()
-{
-  Recording* toDelete = getCurrentOptionRecording();
-
-  if (!toDelete) return;
-
-  Log::getInstance()->log("VRecordingList", Log::DEBUG, "FOUND: %i %s %s", toDelete->index, toDelete->getProgName(), toDelete->getFileName());
-
-  int success = recman->deleteRecording(toDelete);
-  if (!VDR::getInstance()->isConnected())
-  {
-    Command::getInstance()->connectionLost();
-    return;
-  }
-
-  if (success != 1)
-  {
-    VInfo* vi = new VInfo();
-    vi->setSize(360, 200);
-    vi->createBuffer();
-    if (Video::getInstance()->getFormat() == Video::PAL)
-      vi->setPosition(190, 170);
-    else
-      vi->setPosition(180, 120);
-    vi->setOneLiner(tr("Failed to delete recording"));
-    vi->setExitable();
-    vi->setBorderOn(1);
-    vi->setTitleBarColour(Colour::DANGER);
-    vi->okButton();
-    vi->draw();
-    boxstack->add(vi);
-    boxstack->update(vi);
-  }
-  else
-  {
-    draw();
-    boxstack->update(this);
-  }
-
-}
-
-void VRecordingList::doMoveRecording(Directory* toDir)
-{
-  Recording* toMove = getCurrentOptionRecording();
-  if (!toMove || !toDir) return;
-
-  Log::getInstance()->log("VRecordingList", Log::DEBUG, "MOVE: %s %s", toMove->getProgName(), toDir->name);
-
-  int success = recman->moveRecording(toMove, toDir);
-  if (!VDR::getInstance()->isConnected())
-  {
-    Command::getInstance()->connectionLost();
-    return;
-  }
-
-  if (success != 1)
-  {
-    VInfo* vi = new VInfo();
-    vi->setSize(360, 200);
-    vi->createBuffer();
-    if (Video::getInstance()->getFormat() == Video::PAL)
-      vi->setPosition(190, 170);
-    else
-      vi->setPosition(180, 120);
-    vi->setOneLiner(tr("Failed to move recording"));
-    vi->setExitable();
-    vi->setBorderOn(1);
-    vi->setTitleBarColour(Colour::DANGER);
-    vi->okButton();
-    vi->draw();
-    boxstack->add(vi);
-    boxstack->update(vi);
-  }
-  else
-  {
-    draw();
-    boxstack->update(this);
-  }
-}
-
-int VRecordingList::doPlay(bool resume)
-{
-  Recording* toPlay = getCurrentOptionRecording();
-  if (toPlay)
-  {
-    toPlay->loadRecInfo(); // check if still need this
-    toPlay->loadMarks();
-       bool ish264;
-
-    bool isRadio = toPlay->isRadio(ish264);
-
-    if (isRadio)
-    {
-      VRadioRec* radrec = new VRadioRec(toPlay);
-      radrec->draw();
-      boxstack->add(radrec);
-      boxstack->update(radrec);
-      radrec->go();
-    }
-    else
-    {
-               if (ish264 && !Video::getInstance()->supportsh264()) {
-                       VInfo* vi = new VInfo();
-                       vi->setSize(360, 200);
-                       vi->createBuffer();
-                       if (Video::getInstance()->getFormat() == Video::PAL)
-                               vi->setPosition(190, 170);
-                       else
-                               vi->setPosition(180, 120);
-                       vi->setOneLiner(tr("H264 video not supported"));
-                       vi->setExitable();
-                       vi->setBorderOn(1);
-                       vi->setTitleBarColour(Colour::DANGER);
-                       vi->okButton();
-                       vi->draw();
-                       boxstack->add(vi);
-                       boxstack->update(vi);
-                       
-               } else {
-                       VVideoRec* vidrec = new VVideoRec(toPlay, ish264);
-                       vidrec->draw();
-                       boxstack->add(vidrec);
-                       boxstack->update(vidrec);
-                       vidrec->go(resume);
-               }
-    }
-    return 1;
-  }
-  // should not get to here
-  return 0;
-}
-
-Recording* VRecordingList::getCurrentOptionRecording()
-{
-  Recording* currentRec;
-  RecordingList::iterator j;
-  RecordingList* recList = recman->getRecordings();
-  for (j = recList->begin(); j != recList->end(); j++)
-  {
-    currentRec = *j;
-    if (currentRec->index == sl.getCurrentOption()) return currentRec;
-  }
-
-  return NULL;
-}
-
-int VRecordingList::handleCommand(int command)
-{
-  switch(command)
-  {
-    case Remote::DF_UP:
-    case Remote::UP:
-    {
-      sl.up();
-      sl.draw();
-
-      doShowingBar();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::DF_DOWN:
-    case Remote::DOWN:
-    {
-      sl.down();
-      sl.draw();
-
-      doShowingBar();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::SKIPBACK:
-    {
-      sl.pageUp();
-      sl.draw();
-
-      doShowingBar();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::SKIPFORWARD:
-    {
-      sl.pageDown();
-      sl.draw();
-
-      doShowingBar();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::OK:
-    {
-      if (sl.getNumOptions() == 0) return 2;
-
-      // Check to see if it is a sub directory
-      Directory* currentSubDir;
-      DirectoryList::iterator i;
-      DirectoryList* dirList = recman->getDirectories();
-      for (i = dirList->begin(); i != dirList->end(); i++)
-      {
-        currentSubDir = *i;
-        if (currentSubDir->index == sl.getCurrentOption())
-        {
-          if (recman->down(currentSubDir))
-          {
-            slIndexStack.push(sl.getCurrentOption());
-            sl.clear();
-            draw();
-            boxstack->update(this);
-          }
-          return 2;
-        }
-      }
-
-      // check to see if it's a recording
-      Recording* current = getCurrentOptionRecording();
-      if (current)
-      {
-        Log::getInstance()->log("VRecordingList", Log::DEBUG, "Found the option you pointed at. %s %s", current->getProgName(), current->getFileName());
-
-/*
-        VRecordingMenu* v = new VRecordingMenu(recman);
-        v->setParent(this);
-        v->setRecording(current);
-        v->draw();
-        boxstack->add(v);
-        boxstack->update(v);
-*/        
-        VRecording* vr = new VRecording(recman, current);
-        vr->setParent(this);
-        vr->draw();
-        boxstack->add(vr);
-        boxstack->update(vr);
-        
-        return 2;
-      }
-      // should not get to here
-      return 1;
-    }
-    case Remote::BACK:
-    {
-      if (recman->isSubDir())
-      {
-        recman->up();
-        sl.clear();
-        draw(true);
-        boxstack->update(this);
-        return 2;
-      }
-      else
-      {
-        return 4;
-      }
-    }
-    case Remote::PLAY:
-    {
-      if (doPlay(true)) return 2;
-      return 1;
-    }
-    case Remote::LEFT:
-    case Remote::RIGHT:
-    case Remote::ZERO:
-    {
-      reSort();
-      return 2;
-    }
-  }
-  // stop command getting to any more views
-  return 1;
-}
-
-bool VRecordingList::load()
-{
-  VDR* vdr = VDR::getInstance();
-
-  recman = new RecMan();
-  bool success = vdr->getRecordingsList(recman);
-  if (success)
-  {
-    loading = false;
-
-    char* defaultSortOrder = vdr->configLoad("General", "Recordings Sort Order");
-    if (defaultSortOrder)
-    {
-      if (!STRCASECMP(defaultSortOrder, "Chronological")) recman->setSortOrderChron();
-      delete[] defaultSortOrder;
-    }
-
-    recman->sort();
-
-    draw();
-    boxstack->update(this);
-  }
-
-  return success;
-}
-
-void VRecordingList::reSort()
-{
-  recman->toggleSortOrder();
-  recman->sort();
-  sl.clear();
-  draw();
-  boxstack->update(this);
-}
-
+/*\r
+    Copyright 2004-2007 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vrecordinglist.h"\r
+\r
+#include "recman.h"\r
+#include "directory.h"\r
+#include "recording.h"\r
+#include "remote.h"\r
+#include "wsymbol.h"\r
+#include "boxstack.h"\r
+#include "vrecordingmenu.h"\r
+#include "vrecording.h"\r
+#include "vdr.h"\r
+#include "vvideorec.h"\r
+#include "vradiorec.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "i18n.h"\r
+#include "command.h"\r
+#include "vinfo.h"\r
+#include "log.h"\r
+\r
+VRecordingList::VRecordingList()\r
+{\r
+  boxstack = BoxStack::getInstance();\r
+  recman = NULL;\r
+  loading = true;\r
+\r
+  setSize(570, 420);\r
+  createBuffer();\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+  {\r
+    setPosition(80, 70);\r
+  }\r
+  else\r
+  {\r
+    setPosition(70, 35);\r
+  }\r
+\r
+  setTitleBarOn(1);\r
+  setTitleBarColour(Colour::TITLEBARBACKGROUND);\r
+\r
+  sl.setPosition(10, 30 + 5);\r
+  sl.setSize(area.w - 20, area.h - 30 - 15 - 30);\r
+  add(&sl);\r
+}\r
+\r
+VRecordingList::~VRecordingList()\r
+{\r
+  delete recman;\r
+}\r
+\r
+void VRecordingList::drawData(bool doIndexPop)\r
+{\r
+  int saveIndex = sl.getCurrentOption();\r
+  int saveTop = sl.getTopOption();\r
+  sl.clear();\r
+  sl.addColumn(0);\r
+  sl.addColumn(110);\r
+\r
+  int first = 1;\r
+\r
+  char tempA[300]; // FIXME  this is guesswork!\r
+  char tempB[300]; // FIXME\r
+  struct tm* btime;\r
+\r
+  Directory* currentSubDir;\r
+  DirectoryList::iterator i;\r
+  DirectoryList* dirList = recman->getDirectories();\r
+  for (i = dirList->begin(); i != dirList->end(); i++)\r
+  {\r
+    currentSubDir = *i;\r
+    SNPRINTF(tempA, 299, tr("<dir> %lu\t%s"), currentSubDir->getNumRecordings(), currentSubDir->name);\r
+    currentSubDir->index = sl.addOption(tempA, 0, first);\r
+    first = 0;\r
+  }\r
+  // FIXME convert the whole program to time_t's\r
+\r
+  Recording* currentRec;\r
+  RecordingList::iterator j;\r
+  RecordingList* recList = recman->getRecordings();\r
+  for (j = recList->begin(); j != recList->end(); j++)\r
+  {\r
+    currentRec = *j;\r
+    time_t recStartTime = (time_t)currentRec->getStartTime();\r
+    btime = localtime(&recStartTime);\r
+//NMT does not like this too!\r
+       //#ifndef _MSC_VER\r
+//    strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime);\r
+//#else\r
+    strftime(tempA, 299, "%d/%m %H:%M ", btime);\r
+//#endif\r
+    sprintf(tempB, "%s\t%s", tempA, currentRec->getProgName());\r
+    currentRec->index = sl.addOption(tempB, 0, first);\r
+    first = 0;\r
+  }\r
+\r
+  if (doIndexPop)\r
+  {\r
+    sl.hintSetCurrent(slIndexStack.top());\r
+    slIndexStack.pop();\r
+  }\r
+  else\r
+  {\r
+    sl.hintSetCurrent(saveIndex);\r
+    sl.hintSetTop(saveTop);\r
+  }\r
+  sl.draw();\r
+  doShowingBar();\r
+}\r
+\r
+void VRecordingList::draw(bool doIndexPop)\r
+{\r
+  if (!loading)\r
+  {\r
+    if (recman->isSubDir())\r
+    {\r
+      char title[300];\r
+      SNPRINTF(title, 299, tr("Recordings - %s"), recman->getCurDirName());\r
+      setTitleText(title, 364);\r
+    }\r
+    else\r
+    {\r
+      setTitleText(tr("Recordings"));\r
+    }\r
+  }\r
+\r
+  TBBoxx::draw();\r
+\r
+  if (loading)\r
+  {\r
+    drawText(tr("Loading..."), 240, 180, Colour::LIGHTTEXT);\r
+  }\r
+  else\r
+  {\r
+    char freeSpace[50];\r
+    int gigFree = recman->getFreeSpace() / 1024;\r
+    SNPRINTF(freeSpace, 49, tr("%lu%% used, %iGB free"), recman->getUsedPercent(), gigFree);\r
+    drawTextRJ(freeSpace, 560, 5, Colour::LIGHTTEXT);\r
+    // Symbols\r
+\r
+    WSymbol w;\r
+    TEMPADD(&w);\r
+    w.nextSymbol = WSymbol::UP;\r
+    w.setPosition(20, 385);\r
+    w.draw();\r
+    w.nextSymbol = WSymbol::DOWN;\r
+    w.setPosition(50, 385);\r
+    w.draw();\r
+    w.nextSymbol = WSymbol::SKIPBACK;\r
+    w.setPosition(85, 385);\r
+    w.draw();\r
+    w.nextSymbol = WSymbol::SKIPFORWARD;\r
+    w.setPosition(115, 385);\r
+    w.draw();\r
+    w.nextSymbol = WSymbol::PLAY;\r
+    w.setPosition(150, 385);\r
+    w.draw();\r
+    drawTextRJ(tr("[ok] = menu"), 560, 385, Colour::LIGHTTEXT);\r
+\r
+    // All static stuff done\r
+    drawData(doIndexPop);\r
+  }\r
+}\r
+\r
+void VRecordingList::doShowingBar()\r
+{\r
+  int topOption = sl.getTopOption() + 1;\r
+  if (sl.getNumOptions() == 0) topOption = 0;\r
+\r
+  rectangle(220, 385, 180, 25, Colour::VIEWBACKGROUND);\r
+  char showing[200];\r
+  sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());\r
+  drawText(showing, 220, 385, Colour::LIGHTTEXT);\r
+}\r
+\r
+void VRecordingList::processMessage(Message* m)\r
+{\r
+  Log::getInstance()->log("VRecordingList", Log::DEBUG, "Got message value %lu", m->message);\r
+\r
+  if (m->message == Message::MOUSE_MOVE)\r
+  {\r
+    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      sl.draw();\r
+      doShowingBar();\r
+      boxstack->update(this);\r
+    }\r
+  }\r
+  else if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      boxstack->handleCommand(Remote::OK); //simulate OK press\r
+    }\r
+    else\r
+    {\r
+      //check if press is outside this view! then simulate cancel\r
+      int x=(m->parameter>>16)-getScreenX();\r
+      int y=(m->parameter&0xFFFF)-getScreenY();\r
+      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+      {\r
+        boxstack->handleCommand(Remote::BACK); //simulate cancel press\r
+      }\r
+    }\r
+  }\r
+  else if (m->message == Message::DELETE_SELECTED_RECORDING)\r
+  {\r
+    Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing delete selected");\r
+    doDeleteSelected();\r
+  }\r
+  else if (m->message == Message::MOVE_RECORDING)\r
+  {\r
+    Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing move recording");\r
+    doMoveRecording((Directory*)m->parameter);\r
+  }\r
+  else if (m->message == Message::PLAY_SELECTED_RECORDING)\r
+  {\r
+    doPlay(false);\r
+  }\r
+  else if (m->message == Message::RESUME_SELECTED_RECORDING)\r
+  {\r
+    doPlay(true);\r
+  }\r
+}\r
+\r
+void VRecordingList::doDeleteSelected()\r
+{\r
+  Recording* toDelete = getCurrentOptionRecording();\r
+\r
+  if (!toDelete) return;\r
+\r
+  Log::getInstance()->log("VRecordingList", Log::DEBUG, "FOUND: %i %s %s", toDelete->index, toDelete->getProgName(), toDelete->getFileName());\r
+\r
+  int success = recman->deleteRecording(toDelete);\r
+  if (!VDR::getInstance()->isConnected())\r
+  {\r
+    Command::getInstance()->connectionLost();\r
+    return;\r
+  }\r
+\r
+  if (success != 1)\r
+  {\r
+    VInfo* vi = new VInfo();\r
+    vi->setSize(360, 200);\r
+    vi->createBuffer();\r
+    if (Video::getInstance()->getFormat() == Video::PAL)\r
+      vi->setPosition(190, 170);\r
+    else\r
+      vi->setPosition(180, 120);\r
+    vi->setOneLiner(tr("Failed to delete recording"));\r
+    vi->setExitable();\r
+    vi->setBorderOn(1);\r
+    vi->setTitleBarColour(Colour::DANGER);\r
+    vi->okButton();\r
+    vi->draw();\r
+    boxstack->add(vi);\r
+    boxstack->update(vi);\r
+  }\r
+  else\r
+  {\r
+    draw();\r
+    boxstack->update(this);\r
+  }\r
+\r
+}\r
+\r
+void VRecordingList::doMoveRecording(Directory* toDir)\r
+{\r
+  Recording* toMove = getCurrentOptionRecording();\r
+  if (!toMove || !toDir) return;\r
+\r
+  Log::getInstance()->log("VRecordingList", Log::DEBUG, "MOVE: %s %s", toMove->getProgName(), toDir->name);\r
+\r
+  int success = recman->moveRecording(toMove, toDir);\r
+  if (!VDR::getInstance()->isConnected())\r
+  {\r
+    Command::getInstance()->connectionLost();\r
+    return;\r
+  }\r
+\r
+  if (success != 1)\r
+  {\r
+    VInfo* vi = new VInfo();\r
+    vi->setSize(360, 200);\r
+    vi->createBuffer();\r
+    if (Video::getInstance()->getFormat() == Video::PAL)\r
+      vi->setPosition(190, 170);\r
+    else\r
+      vi->setPosition(180, 120);\r
+    vi->setOneLiner(tr("Failed to move recording"));\r
+    vi->setExitable();\r
+    vi->setBorderOn(1);\r
+    vi->setTitleBarColour(Colour::DANGER);\r
+    vi->okButton();\r
+    vi->draw();\r
+    boxstack->add(vi);\r
+    boxstack->update(vi);\r
+  }\r
+  else\r
+  {\r
+    draw();\r
+    boxstack->update(this);\r
+  }\r
+}\r
+\r
+int VRecordingList::doPlay(bool resume)\r
+{\r
+  Recording* toPlay = getCurrentOptionRecording();\r
+  if (toPlay)\r
+  {\r
+    toPlay->loadRecInfo(); // check if still need this\r
+    toPlay->loadMarks();\r
+       bool ish264;\r
+\r
+    bool isRadio = toPlay->isRadio(ish264);\r
+\r
+    if (isRadio)\r
+    {\r
+      VRadioRec* radrec = new VRadioRec(toPlay);\r
+      radrec->draw();\r
+      boxstack->add(radrec);\r
+      boxstack->update(radrec);\r
+      radrec->go();\r
+    }\r
+    else\r
+    {\r
+               if (ish264 && !Video::getInstance()->supportsh264()) {\r
+                       VInfo* vi = new VInfo();\r
+                       vi->setSize(360, 200);\r
+                       vi->createBuffer();\r
+                       if (Video::getInstance()->getFormat() == Video::PAL)\r
+                               vi->setPosition(190, 170);\r
+                       else\r
+                               vi->setPosition(180, 120);\r
+                       vi->setOneLiner(tr("H264 video not supported"));\r
+                       vi->setExitable();\r
+                       vi->setBorderOn(1);\r
+                       vi->setTitleBarColour(Colour::DANGER);\r
+                       vi->okButton();\r
+                       vi->draw();\r
+                       boxstack->add(vi);\r
+                       boxstack->update(vi);\r
+                       \r
+               } else {\r
+                       VVideoRec* vidrec = new VVideoRec(toPlay, ish264);\r
+                       vidrec->draw();\r
+                       boxstack->add(vidrec);\r
+                       boxstack->update(vidrec);\r
+                       vidrec->go(resume);\r
+               }\r
+    }\r
+    return 1;\r
+  }\r
+  // should not get to here\r
+  return 0;\r
+}\r
+\r
+Recording* VRecordingList::getCurrentOptionRecording()\r
+{\r
+  Recording* currentRec;\r
+  RecordingList::iterator j;\r
+  RecordingList* recList = recman->getRecordings();\r
+  for (j = recList->begin(); j != recList->end(); j++)\r
+  {\r
+    currentRec = *j;\r
+    if (currentRec->index == sl.getCurrentOption()) return currentRec;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+int VRecordingList::handleCommand(int command)\r
+{\r
+  switch(command)\r
+  {\r
+    case Remote::DF_UP:\r
+    case Remote::UP:\r
+    {\r
+      sl.up();\r
+      sl.draw();\r
+\r
+      doShowingBar();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::DF_DOWN:\r
+    case Remote::DOWN:\r
+    {\r
+      sl.down();\r
+      sl.draw();\r
+\r
+      doShowingBar();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::SKIPBACK:\r
+    {\r
+      sl.pageUp();\r
+      sl.draw();\r
+\r
+      doShowingBar();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::SKIPFORWARD:\r
+    {\r
+      sl.pageDown();\r
+      sl.draw();\r
+\r
+      doShowingBar();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::OK:\r
+    {\r
+      if (sl.getNumOptions() == 0) return 2;\r
+\r
+      // Check to see if it is a sub directory\r
+      Directory* currentSubDir;\r
+      DirectoryList::iterator i;\r
+      DirectoryList* dirList = recman->getDirectories();\r
+      for (i = dirList->begin(); i != dirList->end(); i++)\r
+      {\r
+        currentSubDir = *i;\r
+        if (currentSubDir->index == sl.getCurrentOption())\r
+        {\r
+          if (recman->down(currentSubDir))\r
+          {\r
+            slIndexStack.push(sl.getCurrentOption());\r
+            sl.clear();\r
+            draw();\r
+            boxstack->update(this);\r
+          }\r
+          return 2;\r
+        }\r
+      }\r
+\r
+      // check to see if it's a recording\r
+      Recording* current = getCurrentOptionRecording();\r
+      if (current)\r
+      {\r
+        Log::getInstance()->log("VRecordingList", Log::DEBUG, "Found the option you pointed at. %s %s", current->getProgName(), current->getFileName());\r
+\r
+/*\r
+        VRecordingMenu* v = new VRecordingMenu(recman);\r
+        v->setParent(this);\r
+        v->setRecording(current);\r
+        v->draw();\r
+        boxstack->add(v);\r
+        boxstack->update(v);\r
+*/        \r
+        VRecording* vr = new VRecording(recman, current);\r
+        vr->setParent(this);\r
+        vr->draw();\r
+        boxstack->add(vr);\r
+        boxstack->update(vr);\r
+        \r
+        return 2;\r
+      }\r
+      // should not get to here\r
+      return 1;\r
+    }\r
+    case Remote::BACK:\r
+    {\r
+      if (recman->isSubDir())\r
+      {\r
+        recman->up();\r
+        sl.clear();\r
+        draw(true);\r
+        boxstack->update(this);\r
+        return 2;\r
+      }\r
+      else\r
+      {\r
+        return 4;\r
+      }\r
+    }\r
+    case Remote::PLAYPAUSE:\r
+    case Remote::PLAY:\r
+    {\r
+      if (doPlay(true)) return 2;\r
+      return 1;\r
+    }\r
+    case Remote::LEFT:\r
+    case Remote::RIGHT:\r
+    case Remote::ZERO:\r
+    {\r
+      reSort();\r
+      return 2;\r
+    }\r
+  }\r
+  // stop command getting to any more views\r
+  return 1;\r
+}\r
+\r
+bool VRecordingList::load()\r
+{\r
+  VDR* vdr = VDR::getInstance();\r
+\r
+  recman = new RecMan();\r
+\r
+  bool success = vdr->getRecordingsList(recman);\r
+\r
+  if (success)\r
+  {\r
+    loading = false;\r
+    char* defaultSortOrder = vdr->configLoad("General", "Recordings Sort Order");\r
+    if (defaultSortOrder)\r
+    {\r
+      if (!STRCASECMP(defaultSortOrder, "Chronological")) recman->setSortOrderChron();\r
+      delete[] defaultSortOrder;\r
+    }\r
+    recman->sort();\r
+    draw();\r
+    boxstack->update(this);\r
+  }\r
+\r
+  return success;\r
+}\r
+\r
+void VRecordingList::reSort()\r
+{\r
+  recman->toggleSortOrder();\r
+  recman->sort();\r
+  sl.clear();\r
+  draw();\r
+  boxstack->update(this);\r
+}\r
+\r
index f64d0e4af52654822244d0daf1a5c59eb37cd756..684755e3574899421ff10ad9ceaeb19631385938 100644 (file)
 
 #include "boxx.h"
 
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
+#include "threadsystem.h"
 
 
 class VScreensaver : public Boxx, public Thread_TYPE
 {
   public:
     VScreensaver();
-    ~VScreensaver();
+    virtual ~VScreensaver();
 
     int handleCommand(int command);
     void draw();
index cafc282f24d7ca474a9560f0e2ff6c3b60ae8489..d5bb518642d723f51ed449659f7656e247d58d1d 100644 (file)
 #include "boxx.h"
 #include "timerreceiver.h"
 
-#ifndef WIN32
-#include "threadp.h"
-#else
-#include "threadwin.h"
-#endif
+#include "threadsystem.h"
 
 class Sleeptimer : public Thread_TYPE
 {
index 168f65d828b55d8713bd5a0afe744f8798016f3e..113bf6b3a40a4132bdde8091a9f1da9a1090d0c0 100644 (file)
-/*
-    Copyright 2005-2008 Chris Tallon, Marten Richter
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-#include <math.h>
-#include "vteletextview.h"
-#include "video.h"
-#include "timers.h"
-#include "boxstack.h"
-#include "remote.h"
-#include "teletxt/txtfont.h"
-
-unsigned int interpol_table_fac1[16][22];
-unsigned int interpol_table_fac2[16][22];
-unsigned int interpol_table_fac3[16][22];
-unsigned int interpol_table_fac4[16][22];
-int interpol_lowbit[16];
-int interpol_upbit[16];
-int interpol_lowline[22];
-int interpol_upline[22];
-
-void initpol_tables(){
-    int charsizex;
-    int charsizey;
-    charsizex=16;
-    if (Video::getInstance()->getFormat() == Video::PAL)
-    { 
-        charsizey=22;
-    } else {
-        charsizey=18;
-    }
-    int ttcharsizex=12;
-    int ttcharsizey=10;
-    for (int py=0;py<charsizey;py++) {
-        float fposy=((float)(ttcharsizey))/((float)(charsizey))*((float)py);
-        float yweight=fposy-floor(fposy);
-        float yinvweight=1.-yweight;
-        interpol_upline[py]=min((unsigned int)ceil(fposy),9);
-        interpol_lowline[py]=max((unsigned int)floor(fposy),0);
-        for (int px=0;px<charsizex;px++) {
-            float fposx=((float)(ttcharsizex))/((float)(charsizex))*((float)px);
-            float xweight=fposx-floor(fposx);
-            float xinvweight=1.-xweight;
-            interpol_upbit[px]= (min((unsigned int)ceil(fposx),11));
-            interpol_lowbit[px]= (max((unsigned int)floor(fposx),0));
-
-            interpol_table_fac1[px][py]=xweight*yweight*256.;
-            interpol_table_fac2[px][py]=xinvweight*yweight*256.;
-            interpol_table_fac3[px][py]=xweight*yinvweight*256.;
-            interpol_table_fac4[px][py]=xinvweight*yinvweight*256.;
-
-        }
-    }
-}
-
-VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder,Boxx* playerview)
-{   
-    ttdecoder=TTdecoder;
-    pv=playerview;
-    subtitlemode=false;
-    initpol_tables();
-    
-    
-    if (Video::getInstance()->getFormat() == Video::PAL)
-    { 
-        //setSize(680, 550);
-        setSize(680,22); //Only first line
-        setPosition(40, 26);
-    }
-    else
-    {
-        setPosition(40, 30);
-        //setSize(680, 450);
-        setSize(680,18);//only first line
-    }
-    createBuffer();
-    keyindigit=1;
-    page=0x100;
-    
-}
-
-VTeletextView::~VTeletextView ()
-{
-    // Make sure the timer is deleted
-  pv->draw();
-  BoxStack::getInstance()->update(pv);
-  Timers::getInstance()->cancelTimer(this, 1);
-  ttdecoder->unRegisterTeletextView(this);
-    
-}
-
-void VTeletextView::draw(bool completedraw, bool onlyfirstline)
-{
-    Boxx::draw();
-    int x,y;
-    
-    for (y=0;y<25;y++) {
-        for (x=0;x<40;x++) {
-            if (ttdecoder->isDirty(x,y) || completedraw) {
-                cTeletextChar c=ttdecoder->getChar(x,y);
-                c.SetDirty(false);
-                //Skip Blinking and conceal
-                drawChar(x,y,c);
-                ttdecoder->setChar(x,y,c);
-            }
-        }
-        if (onlyfirstline) break;
-    }
-   
-    
-}
-
-Colour VTeletextView::enumTeletextColorToCoulour(enumTeletextColor ttcol)
-{
-    switch (ttcol) {
-        case ttcBlack:
-            return Colour(0,0,0);
-        case ttcRed:
-            return Colour(255,0,0);
-        case ttcGreen:
-            return Colour(0,255,0);
-        case ttcYellow:
-            return Colour(255,255,0);
-        case ttcBlue:
-            return Colour(0,0,255);
-        case ttcMagenta:
-            return Colour(255,0,255);
-        case ttcCyan:
-            return Colour(0,255,255);
-        case ttcWhite:
-            return Colour(255,255,255);
-        case ttcTransparent:
-            return Colour(0,0,0,0);
-        case ttcHalfRed:
-            return Colour(127,0,0);
-        case ttcHalfGreen:
-            return Colour(0,127,0);
-        case ttcHalfYellow:
-            return Colour(127,127,0);
-        case ttcHalfBlue:
-            return Colour(0,0,127);
-        case ttcHalfMagenta:
-            return Colour(127,0,127);
-        case ttcHalfCyan:
-            return Colour(0,127,127);
-        case ttcGrey:
-            return Colour(127,127,127);
-        default:
-            return Colour(0,0,0);
-    };
-}
-
-//Next function inspired by osdteletext plugin
-void VTeletextView::drawChar(int x, int y, cTeletextChar c)
-{
-    unsigned int buffer [10];
-    unsigned int * charmap=GetFontChar(c,buffer);
-    if (!charmap) { //invalid char
-        memset(&buffer,0,10);
-        charmap=buffer;
-    } 
-    enumTeletextColor ttforegcolour=c.GetFGColor();
-    enumTeletextColor ttbackgcolour=c.GetBGColor();
-    if (c.GetBoxedOut()) {
-        ttforegcolour=ttcTransparent;
-        ttbackgcolour=ttcTransparent;
-    }
-    int charsizex;
-    int charsizey;
-    charsizex=16;
-    bool firstline=false;
-    if (y==0) firstline=true;
-    if (Video::getInstance()->getFormat() == Video::PAL)
-    { 
-        charsizey=22;
-    } else {
-        charsizey=18;
-    }
-    int ttcharsizex=12;
-    int ttcharsizey=10;
-    int screenposx=charsizex*x; //12*40= 480 250
-    int screenposy=y*charsizey;
-    Boxx* drawtarget=this;
-    if (!firstline) {
-  
-        drawtarget=pv;
-        screenposy+=this->getScreenY();
-        screenposx+=this->getScreenX();
-
-    }
-
-    Colour fgcharcl=enumTeletextColorToCoulour(ttforegcolour);
-    Colour bgcharcl=enumTeletextColorToCoulour(ttbackgcolour);
-
-    drawtarget->startFastDraw();
-    for (int py=0;py<charsizey;py++) {
-        int upperbitline=charmap[interpol_upline[py]];
-        int lowerbitline=charmap[interpol_lowline[py]];
-        for (int px=0;px<charsizex;px++) {
-            int upperbit= interpol_upbit[px];
-            int lowerbit= interpol_lowbit[px];
-            Colour uuc=( upperbitline &(0x8000>>upperbit)) ? fgcharcl: bgcharcl;
-            Colour ulc=( upperbitline &(0x8000>>lowerbit)) ? fgcharcl: bgcharcl;
-            Colour luc=( lowerbitline &(0x8000>>upperbit)) ? fgcharcl: bgcharcl;
-            Colour llc=( lowerbitline &(0x8000>>lowerbit)) ? fgcharcl: bgcharcl;
-            unsigned int fac1,fac2,fac3,fac4;
-            fac1=interpol_table_fac1[px][py];
-            fac2=interpol_table_fac2[px][py];
-            fac3=interpol_table_fac3[px][py];
-            fac4=interpol_table_fac4[px][py];
-         
-            Colour res((uuc.red*fac1+ulc.red*fac2+luc.red*fac3+llc.red*fac4)/256,
-                (uuc.green*fac1+ulc.green*fac2+luc.green*fac3+llc.green*fac4)/256,
-                (uuc.blue*fac1+ulc.blue*fac2+luc.blue*fac3+llc.blue*fac4)/256,
-                (uuc.alpha*fac1+ulc.alpha*fac2+luc.alpha*fac3+llc.alpha*fac4)/256); //if this is too slow make a table
-            drawtarget->drawPixelAlpha(screenposx+px,screenposy+py,res, true);
-        }
-    }
-
-   
-    drawtarget->endFastDraw();
-
-
-}
-
-int VTeletextView::handleCommand(int command) {
-    if (subtitlemode) return 0; //Ok we are in  subtitle mode, we are a slave of the player
-    switch (command) {
-    case Remote::OK:
-        return 2;
-    case Remote::BACK:
-        return 4;
-     case Remote::ZERO:
-    case Remote::ONE:
-    case Remote::TWO:
-    case Remote::THREE:
-    case Remote::FOUR:
-    case Remote::FIVE:
-    case Remote::SIX:
-    case Remote::SEVEN:
-    case Remote::EIGHT:
-    case Remote::NINE:
-    {
-      // key in teletext page
-      doKey(command);
-      return 2;
-    }
-    };
-
-    return 0;
-    
-}
-
-void VTeletextView::doKey(int command)
-{
-    char pagenums[3];
-    if (keyindigit==1){
-        if (command==9) return; //not allowed
-        page=command<<8;
-        pagenums[0]=command+ 48;
-        pagenums[1]='-';
-        pagenums[2]='-';
-        keyindigit++;
-    } else if (keyindigit==2) {
-        page|=command<<4;
-        pagenums[0]=48+((page &0xF00)>>8);
-        pagenums[1]=command+ 48;
-        pagenums[2]='-';
-        keyindigit++;
-    } else if (keyindigit==3) {
-        page|=command;
-        pagenums[0]=48+((page &0xF00)>>8);
-        pagenums[1]=48+((page &0x0F0)>>4);
-        pagenums[2]=48+command;
-        keyindigit=1;
-        ttdecoder->setPage(page);
-    }
-    ttdecoder->setKeyinDigits(pagenums,true);
-    Region toupdate;
-    toupdate.w=16*40;
-    if (Video::getInstance()->getFormat() == Video::PAL) {
-        toupdate.h=22;
-        
-     } else {
-        toupdate.h=18;
-        
-      }
-     toupdate.x=0;
-     toupdate.y=0;
-            
-     draw(false,true);
-     BoxStack::getInstance()->update(this,&toupdate);
-
-}
-
-void VTeletextView::timercall(int clientReference)
-{
-    
-}
-
-void VTeletextView::processMessage(Message* m)
-{
-    if (m->message == Message::TELETEXTUPDATE)
-    {
-        draw(false,false);
-        BoxStack::getInstance()->update(this);
-        BoxStack::getInstance()->update(pv);
-
-    } else if (m->message == Message::TELETEXTUPDATEFIRSTLINE) 
-    {
-        Region toupdate;
-        toupdate.w=16*40;
-        if (Video::getInstance()->getFormat() == Video::PAL) {
-            toupdate.h=22;
-            
-        } else {
-            toupdate.h=18;
-            
-        }
-        toupdate.x=0;
-        toupdate.y=0;
-
-
-            
-        draw(false,true);
-        BoxStack::getInstance()->update(this,&toupdate);
-
-    }
-}
-
-
+/*\r
+    Copyright 2005-2008 Chris Tallon, Marten Richter\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+#include <math.h>\r
+#include "vteletextview.h"\r
+#include "video.h"\r
+#include "timers.h"\r
+#include "boxstack.h"\r
+#include "remote.h"\r
+\r
+\r
+VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder,Boxx* playerview)\r
+{   \r
+    ttdecoder=TTdecoder;\r
+    pv=playerview;\r
+    subtitlemode=false;\r
+    \r
+    \r
+\r
+    if (Video::getInstance()->getFormat() == Video::PAL)\r
+    { \r
+        //setSize(680, 550);\r
+        setSize(680,22); //Only first line\r
+        setPosition(40, 26);\r
+    }\r
+    else\r
+    {\r
+        setPosition(40, 30);\r
+        //setSize(680, 450);\r
+        setSize(680,18);//only first line\r
+    }\r
+    createBuffer();\r
+    keyindigit=1;\r
+    page=0x100;\r
+    \r
+}\r
+\r
+VTeletextView::~VTeletextView ()\r
+{\r
+    // Make sure the timer is deleted\r
+       Log::getInstance()->log("VTeletextView", Log::DEBUG, "VTeletextView destruct");\r
+  pv->draw();\r
+  BoxStack::getInstance()->update(pv);\r
+  Timers::getInstance()->cancelTimer(this, 1);\r
+  ttdecoder->unRegisterTeletextView(this);\r
+    \r
+}\r
+\r
+void VTeletextView::draw(bool completedraw, bool onlyfirstline)\r
+{\r
+       //Log::getInstance()->log("VTeletextView", Log::ERR, "Start draw");\r
+    Boxx::draw();\r
+    int x,y;\r
+    \r
+    Boxx *drawtarget=NULL;\r
+    int ox,oy;\r
+    for (y=0;y<25;y++) {\r
+       if (y==0) {\r
+               drawtarget=this;\r
+               ox=0;\r
+               oy=0;\r
+       } else {\r
+               drawtarget=pv;\r
+               ox=this->getScreenX();\r
+               oy=this->getScreenY();\r
+       }\r
+\r
+        for (x=0;x<40;x++) {\r
+            if (ttdecoder->isDirty(x,y) || completedraw) {\r
+                cTeletextChar c=ttdecoder->getChar(x,y);\r
+                c.SetDirty(false);\r
+                //Skip Blinking and conceal\r
+                drawtarget->drawTTChar(ox,oy,x,y,c);\r
+                ttdecoder->setChar(x,y,c);\r
+            }\r
+        }\r
+    //    Log::getInstance()->log("VTeletextView", Log::ERR, "Line %d",y);\r
+        if (onlyfirstline) break;\r
+    }\r
+  //  Log::getInstance()->log("VTeletextView", Log::ERR, "Start end");\r
+   \r
+    \r
+}\r
+\r
+\r
+\r
+\r
+\r
+int VTeletextView::handleCommand(int command) {\r
+    if (subtitlemode) return 0; //Ok we are in  subtitle mode, we are a slave of the player\r
+    switch (command) {\r
+    case Remote::OK:\r
+        return 2;\r
+    case Remote::BACK:\r
+        return 4;\r
+     case Remote::ZERO:\r
+    case Remote::ONE:\r
+    case Remote::TWO:\r
+    case Remote::THREE:\r
+    case Remote::FOUR:\r
+    case Remote::FIVE:\r
+    case Remote::SIX:\r
+    case Remote::SEVEN:\r
+    case Remote::EIGHT:\r
+    case Remote::NINE:\r
+    {\r
+      // key in teletext page\r
+      doKey(command);\r
+      return 2;\r
+    }\r
+    };\r
+\r
+    return 0;\r
+    \r
+}\r
+\r
+void VTeletextView::doKey(int command)\r
+{\r
+    char pagenums[3];\r
+    if (keyindigit==1){\r
+        if (command==9) return; //not allowed\r
+        page=command<<8;\r
+        pagenums[0]=command+ 48;\r
+        pagenums[1]='-';\r
+        pagenums[2]='-';\r
+        keyindigit++;\r
+    } else if (keyindigit==2) {\r
+        page|=command<<4;\r
+        pagenums[0]=48+((page &0xF00)>>8);\r
+        pagenums[1]=command+ 48;\r
+        pagenums[2]='-';\r
+        keyindigit++;\r
+    } else if (keyindigit==3) {\r
+        page|=command;\r
+        pagenums[0]=48+((page &0xF00)>>8);\r
+        pagenums[1]=48+((page &0x0F0)>>4);\r
+        pagenums[2]=48+command;\r
+        keyindigit=1;\r
+        ttdecoder->setPage(page);\r
+    }\r
+    ttdecoder->setKeyinDigits(pagenums,true);\r
+    Region toupdate;\r
+    toupdate.w=16*40;\r
+    if (Video::getInstance()->getFormat() == Video::PAL) {\r
+        toupdate.h=22;\r
+        \r
+     } else {\r
+        toupdate.h=18;\r
+        \r
+      }\r
+     toupdate.x=0;\r
+     toupdate.y=0;\r
+            \r
+     draw(false,true);\r
+     BoxStack::getInstance()->update(this,&toupdate);\r
+\r
+}\r
+\r
+void VTeletextView::timercall(int clientReference)\r
+{\r
+    \r
+}\r
+\r
+void VTeletextView::processMessage(Message* m)\r
+{\r
+    if (m->message == Message::TELETEXTUPDATE)\r
+    {\r
+        draw(false,false);\r
+        BoxStack::getInstance()->update(this);\r
+        BoxStack::getInstance()->update(pv);\r
+\r
+    } else if (m->message == Message::TELETEXTUPDATEFIRSTLINE) \r
+    {\r
+        Region toupdate;\r
+        toupdate.w=16*40;\r
+        if (Video::getInstance()->getFormat() == Video::PAL) {\r
+            toupdate.h=22;\r
+            \r
+        } else {\r
+            toupdate.h=18;\r
+            \r
+        }\r
+        toupdate.x=0;\r
+        toupdate.y=0;\r
+\r
+\r
+            \r
+        draw(false,true);\r
+        BoxStack::getInstance()->update(this,&toupdate);\r
+\r
+    }\r
+}\r
+\r
+\r
index d69a4a65b87cb83c4e67072279345757a0346f9a..af3b5c9efd1490fb10febdebd7b60b21f4803cde 100644 (file)
@@ -1,64 +1,64 @@
-/*
-    Copyright 2005-2008 Chris Tallon, Marten Richter
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef VTELETEXTVIEW_H
-#define VTELETEXTVIEW_H
-
-#include <stdio.h>
-
-#include "boxx.h"
-#include "timerreceiver.h"
-#include "teletextdecodervbiebu.h"
-
-class VTeletextView : public Boxx, public TimerReceiver
-{
-  public:
-    VTeletextView (TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview);
-    ~VTeletextView ();
-    void draw(bool completedraw, bool onlyfirstline);
-    void draw() {draw(true,false);};
-    void drawChar(int x, int y, cTeletextChar c);
-
-    Colour enumTeletextColorToCoulour(enumTeletextColor ttcol);
-
-    void processMessage(Message* m);
-
-    void setSubtitleMode(bool mode) {subtitlemode=mode;};
-    bool isInSubtitleMode() {return subtitlemode;};
-
-    int handleCommand(int command);
-    void timercall(int clientReference);
-   
-
-  private:
-      void doKey(int command);
-    
-
-  protected:
-      TeletextDecoderVBIEBU* ttdecoder;
-      int keyindigit;
-      int page;
-      bool subtitlemode;
-     Boxx* pv;
-    
-
-};
-
-#endif
+/*\r
+    Copyright 2005-2008 Chris Tallon, Marten Richter\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef VTELETEXTVIEW_H\r
+#define VTELETEXTVIEW_H\r
+\r
+#include <stdio.h>\r
+\r
+#include "boxx.h"\r
+#include "timerreceiver.h"\r
+#include "teletextdecodervbiebu.h"\r
+\r
+class VTeletextView : public Boxx, public TimerReceiver\r
+{\r
+  public:\r
+    VTeletextView (TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview);\r
+    ~VTeletextView ();\r
+    void draw(bool completedraw, bool onlyfirstline);\r
+    void draw() {draw(true,false);};\r
+\r
+\r
+\r
+\r
+    void processMessage(Message* m);\r
+\r
+    void setSubtitleMode(bool mode) {subtitlemode=mode;};\r
+    bool isInSubtitleMode() {return subtitlemode;};\r
+\r
+    int handleCommand(int command);\r
+    void timercall(int clientReference);\r
+   \r
+\r
+  private:\r
+      void doKey(int command);\r
+    \r
+\r
+  protected:\r
+      TeletextDecoderVBIEBU* ttdecoder;\r
+      int keyindigit;\r
+      int page;\r
+      bool subtitlemode;\r
+     Boxx* pv;\r
+    \r
+\r
+};\r
+\r
+#endif\r
index dbc042e3011620638ad2a7e942361d5b211d7eb1..9b8ae1cf4828ef82d4b43fc578366b239f1def1c 100644 (file)
@@ -74,18 +74,19 @@ void VTimerEdit::draw()
 
   int xpos = 20;
   int ypos = 50;
-  drawText(tr("Active"), xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
-  drawText(tr("Channel"), xpos, ypos, Colour::LIGHTTEXT);        ypos += surface->getFontHeight();
-  drawText(tr("Name"), xpos, ypos, Colour::LIGHTTEXT);           ypos += surface->getFontHeight();
-  drawText(tr("Directory"), xpos, ypos, Colour::LIGHTTEXT);      ypos += surface->getFontHeight();
-                                                             ypos += surface->getFontHeight();
-  drawText(tr("Start"), xpos, ypos, Colour::LIGHTTEXT);          ypos += surface->getFontHeight();
-  drawText(tr("Stop"), xpos, ypos, Colour::LIGHTTEXT);           ypos += surface->getFontHeight();
-  drawText(tr("Priority"), xpos, ypos, Colour::LIGHTTEXT);       ypos += surface->getFontHeight();
-  drawText(tr("Lifetime"), xpos, ypos, Colour::LIGHTTEXT);       ypos += surface->getFontHeight();
-                                                             ypos += surface->getFontHeight();
-  drawText(tr("Current"), xpos, ypos, Colour::LIGHTTEXT);        ypos += surface->getFontHeight();
-  drawText(tr("Recording"), xpos, ypos, Colour::LIGHTTEXT);      ypos += surface->getFontHeight();
+  int fontheight=getFontHeight();
+  drawText(tr("Active"), xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
+  drawText(tr("Channel"), xpos, ypos, Colour::LIGHTTEXT);        ypos += fontheight;
+  drawText(tr("Name"), xpos, ypos, Colour::LIGHTTEXT);           ypos += fontheight;
+  drawText(tr("Directory"), xpos, ypos, Colour::LIGHTTEXT);      ypos += fontheight;
+                                                             ypos += fontheight;
+  drawText(tr("Start"), xpos, ypos, Colour::LIGHTTEXT);          ypos += fontheight;
+  drawText(tr("Stop"), xpos, ypos, Colour::LIGHTTEXT);           ypos += fontheight;
+  drawText(tr("Priority"), xpos, ypos, Colour::LIGHTTEXT);       ypos += fontheight;
+  drawText(tr("Lifetime"), xpos, ypos, Colour::LIGHTTEXT);       ypos += fontheight;
+                                                             ypos += fontheight;
+  drawText(tr("Current"), xpos, ypos, Colour::LIGHTTEXT);        ypos += fontheight;
+  drawText(tr("Recording"), xpos, ypos, Colour::LIGHTTEXT);      ypos += fontheight;
 
 
   // Temp
@@ -97,50 +98,50 @@ void VTimerEdit::draw()
   // Active
   if (recTimer->active) strcpy(buffer, "Yes");
   else                  strcpy(buffer, "No");
-  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
+  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
 
   // Channel
   SNPRINTF(buffer, 999, "%lu", recTimer->channelNumber);
-  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
+  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
 
   // Name
   SNPRINTF(buffer, 999, "%s", recTimer->getName());
-  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
+  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
 
   // Directory
   if (recTimer->getDirectory()) SNPRINTF(buffer, 999, "%s", recTimer->getDirectory());
   else strcpy(buffer, "");
-  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
-                                                           ypos += surface->getFontHeight();
+  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
+                                                           ypos += fontheight;
 
   // Start
   tms = localtime((time_t*)&recTimer->startTime);
   strftime(buffer, 999, "%d/%m %H:%M", tms);
-  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
+  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
 
   // Stop
   tms = localtime((time_t*)&recTimer->stopTime);
   strftime(buffer, 999, "%d/%m %H:%M", tms);
-  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
+  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
 
   // Priority
   SNPRINTF(buffer, 999, "%lu", recTimer->priority);
-  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
+  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
 
   // Lifetime
   SNPRINTF(buffer, 999, "%lu", recTimer->lifeTime);
-  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
-                                                           ypos += surface->getFontHeight();
+  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
+                                                           ypos += fontheight;
 
   // Current
   if (recTimer->pending) strcpy(buffer, "Yes");
   else                   strcpy(buffer, "No");
-  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
+  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
 
   // Recording now
   if (recTimer->recording) strcpy(buffer, "Yes");
   else                     strcpy(buffer, "No");
-  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += surface->getFontHeight();
+  drawText(buffer, xpos, ypos, Colour::LIGHTTEXT);         ypos += fontheight;
 }
 
 void VTimerEdit::swap()
index aa29360e2ecdb2731e52db2fd7adf30f94d5ae09..3eb5f1e99f74a4a9eed4bc51796e838638c30550 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vtimerlist.h"
-
-#include "message.h"
-#include "remote.h"
-#include "wsymbol.h"
-#include "colour.h"
-#include "video.h"
-#include "i18n.h"
-#include "timers.h"
-#include "vtimeredit.h"
-#include "command.h"
-#include "boxstack.h"
-#include "vdr.h"
-#include "vinfo.h"
-#include "log.h"
-
-VTimerList::VTimerList()
-{
-  recTimerList = NULL;
-
-  clockRegion.x = 420;
-  clockRegion.y = 0;
-  clockRegion.w = 150;
-  clockRegion.h = 30;
-
-  indicatorsRegion.x = 6;
-  indicatorsRegion.y = 44;
-  indicatorsRegion.w = 18;
-  indicatorsRegion.h = 15 * (surface->getFontHeight() + 1);
-
-  flipflop = true;
-
-  setSize(570, 420);
-  createBuffer();
-  if (Video::getInstance()->getFormat() == Video::PAL)
-  {
-    setPosition(80, 70);
-  }
-  else
-  {
-    setPosition(70, 35);
-  }
-
-  setTitleBarOn(1);
-  setTitleText(tr("Timers"));
-  setTitleBarColour(Colour::TITLEBARBACKGROUND);
-
-  sl.setPosition(30, 30 + 5);
-  sl.setSize(area.w - 40, area.h - 30 - 15 - 30);
-  add(&sl);
-}
-
-void VTimerList::preDelete()
-{
-  Timers::getInstance()->cancelTimer(this, 1);
-}
-
-VTimerList::~VTimerList()
-{
-  if (recTimerList)
-  {
-    for (UINT i = 0; i < recTimerList->size(); i++)
-    {
-      delete (*recTimerList)[i];
-    }
-
-    recTimerList->clear();
-    delete recTimerList;
-  }
-}
-
-void VTimerList::draw()
-{
-  // Draw statics
-
-  TBBoxx::draw();
-
-  WSymbol w;
-  TEMPADD(&w);
-
-  w.nextSymbol = WSymbol::UP;
-  w.setPosition(20, 385);
-  w.draw();
-
-  w.nextSymbol = WSymbol::DOWN;
-  w.setPosition(50, 385);
-  w.draw();
-
-  w.nextSymbol = WSymbol::SKIPBACK;
-  w.setPosition(85, 385);
-  w.draw();
-
-  w.nextSymbol = WSymbol::SKIPFORWARD;
-  w.setPosition(115, 385);
-  w.draw();
-
-  drawTextRJ("[ok] = edit", 560, 385, Colour::LIGHTTEXT);
-
-  drawClock();
-  drawShowing();
-  drawIndicators();
-}
-
-bool VTimerList::load()
-{
-  recTimerList = VDR::getInstance()->getRecTimersList();
-
-  if (!recTimerList) return false;
-
-  char strA[300];
-  char strB[300];
-
-  struct tm* btime;
-
-  // FIXME all drawing stuff in this class and sl.clear somewhere?!
-
-  sl.addColumn(0);
-  sl.addColumn(110);
-
-  RecTimer* recTimer;
-  int first = 1;
-
-  for (UINT i = 0; i < recTimerList->size(); i++)
-  {
-    recTimer = (*recTimerList)[i];
-
-    btime = localtime((time_t*)&recTimer->startTime);
-    strftime(strA, 299, "%d/%m %H:%M ", btime);
-    SNPRINTF(strB, 299, "%s\t%s", strA, recTimer->getName());
-    sl.addOption(strB, (ULONG)recTimer, first);
-    first = 0;
-  }
-
-  return true;
-}
-
-void VTimerList::drawClock()
-{
-  // Blank the area first
-  rectangle(area.w - 150, 0, 150, 30, titleBarColour);
-
-  char timeString[20];
-  time_t t;
-  time(&t);
-  struct tm* tms = localtime(&t);
-  strftime(timeString, 19, "%d/%m %H:%M:%S", tms);
-  drawTextRJ(timeString, 560, 5, Colour::LIGHTTEXT);
-
-  Timers::getInstance()->setTimerT(this, 1, t + 1);
-}
-
-void VTimerList::drawShowing()
-{
-  int topOption = sl.getTopOption() + 1;
-  if (sl.getNumOptions() == 0) topOption = 0;
-
-  rectangle(220, 385, 180, 25, Colour::VIEWBACKGROUND);
-  char showing[200];
-  sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());
-  drawText(showing, 220, 385, Colour::LIGHTTEXT);
-}
-
-void VTimerList::drawIndicators()
-{
-  int top = sl.getTopOption();
-  int bottom = sl.getBottomOption();
-  int yinc = surface->getFontHeight() + 1;
-  RecTimer* recTimer;
-
-  rectangle(6, 44, 18, 15*yinc, Colour::VIEWBACKGROUND);
-
-  // The indexes recorded from the wselectlist into the index member of the RecTimer
-  // Is the same as the position in the vector of RecTimers
-  // Because they are in order, they don't change order and wselectlist starts from 0 up consecutively
-
-  int ypos = 44;
-  for (int current = top; current < bottom; current++)
-  {
-    recTimer = (*recTimerList)[current];
-
-    if (recTimer->recording) // Flashing red square
-    {
-      if (flipflop)
-      {
-        rectangle(6, ypos, 18, 16, Colour::RED);
-        drawText("R", 8, ypos-3, Colour::LIGHTTEXT);
-      }
-    }
-    else if (recTimer->pending)
-    {
-      rectangle(6, ypos, 18, 16, Colour::RED);
-      drawText("X", 8, ypos-3, Colour::BLACK);
-    }
-    else if (recTimer->active == 0)
-    {
-      rectangle(6, ypos, 18, 16, Colour::SELECTHIGHLIGHT);
-      drawText("X", 8, ypos-3, Colour::BLACK);
-    }
-    else
-    {
-//      if (flipflop) rectangle(6, ypos, 18, 16, Colour::GREEN);
-    }
-
-    ypos += yinc;
-  }
-}
-
-void VTimerList::timercall(int clientReference)
-{
-  drawClock();
-  BoxStack::getInstance()->update(this, &clockRegion);
-
-  flipflop = !flipflop;
-  drawIndicators();
-  BoxStack::getInstance()->update(this, &indicatorsRegion);
-}
-
-int VTimerList::handleCommand(int command)
-{
-  switch(command)
-  {
-    case Remote::DF_UP:
-    case Remote::UP:
-    {
-      sl.up();
-      sl.draw();
-      drawShowing();
-      drawIndicators();
-      BoxStack::getInstance()->update(this);
-      return 2;
-    }
-    case Remote::DF_DOWN:
-    case Remote::DOWN:
-    {
-      sl.down();
-      sl.draw();
-      drawShowing();
-      drawIndicators();
-      BoxStack::getInstance()->update(this);
-      return 2;
-    }
-    case Remote::SKIPBACK:
-    {
-      sl.pageUp();
-      sl.draw();
-      drawShowing();
-      drawIndicators();
-      BoxStack::getInstance()->update(this);
-      return 2;
-    }
-    case Remote::SKIPFORWARD:
-    {
-      sl.pageDown();
-      sl.draw();
-      drawShowing();
-      drawIndicators();
-      BoxStack::getInstance()->update(this);
-      return 2;
-    }
-    case Remote::OK:
-    {
-      RecTimer* recTimer = NULL;
-      if (recTimerList) recTimer = (RecTimer*)sl.getCurrentOptionData();
-      if (recTimer == NULL) return 2;
-
-      VTimerEdit* v = new VTimerEdit(recTimer);
-      v->setParent(this);
-      v->draw();
-      BoxStack::getInstance()->add(v);
-      BoxStack::getInstance()->update(v);
-
-      return 2;
-    }
-    case Remote::BACK:
-    {
-      return 4;
-    }
-  }
-  // stop command getting to any more views
-  return 1;
-}
-
-void VTimerList::processMessage(Message* m)
-{
-  if (m->message == Message::MOUSE_MOVE)
-  {
-    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      sl.draw();
-      BoxStack::getInstance()->update(this);
-    }
-  }
-  else if (m->message == Message::MOUSE_LBDOWN)
-  {
-    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
-    }
-    else
-    {
-      //check if press is outside this view! then simulate cancel
-      int x=(m->parameter>>16)-getScreenX();
-      int y=(m->parameter&0xFFFF)-getScreenY();
-      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
-      {
-        BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
-      }
-    }
-  }
-  else if (m->message == Message::DELETE_SELECTED_TIMER)
-  {
-    RecTimer* recTimer = (RecTimer*)sl.getCurrentOptionData();
-    if (recTimer == NULL) return;
-    Log::getInstance()->log("VTimerList", Log::DEBUG, "Got timer to delete");
-
-  
-    ULONG retval = VDR::getInstance()->deleteTimer(recTimer);
-    if (!VDR::getInstance()->isConnected()) { Command::getInstance()->connectionLost(); return; }
-    Log::getInstance()->log("VTimerList", Log::DEBUG, "Got return fron delete timer: %lu", retval);
-    
-    if (retval != 10)
-    {
-      VInfo* errorBox = new VInfo();
-      errorBox->setSize(360, 200);
-      errorBox->createBuffer();
-      if (Video::getInstance()->getFormat() == Video::PAL)
-        errorBox->setPosition(190, 170);
-      else
-        errorBox->setPosition(180, 120);
-
-    
-      if (retval == 1) errorBox->setOneLiner(tr("Timers being edited at VDR, please try later"));
-      else if (retval == 3)  errorBox->setOneLiner(tr("Unable to delete timer - timer is running"));
-      else if (retval == 4)  errorBox->setOneLiner(tr("Error - timer not found at VDR"));
-      else                   errorBox->setOneLiner(tr("Unknown error"));
-
-      errorBox->setExitable();
-      errorBox->setBorderOn(1);
-      errorBox->setTitleBarColour(Colour::DANGER);
-      errorBox->okButton();
-      errorBox->draw();
-      BoxStack::getInstance()->add(errorBox);
-      BoxStack::getInstance()->update(errorBox);
-    }
-    
-    int saveIndex = sl.getCurrentOption();
-    int saveTop = sl.getTopOption();
-     
-    if (recTimerList)
-    {
-      for (UINT i = 0; i < recTimerList->size(); i++)
-      {
-        delete (*recTimerList)[i];
-      }
-
-      recTimerList->clear();
-      delete recTimerList;
-    }
-
-    sl.clear();
-    load();
-
-    sl.hintSetCurrent(saveIndex);
-    sl.hintSetTop(saveTop);
-    draw();
-    BoxStack::getInstance()->update(this);
-  }
-}
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vtimerlist.h"\r
+\r
+#include "message.h"\r
+#include "remote.h"\r
+#include "wsymbol.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "i18n.h"\r
+#include "timers.h"\r
+#include "vtimeredit.h"\r
+#include "command.h"\r
+#include "boxstack.h"\r
+#include "vdr.h"\r
+#include "vinfo.h"\r
+#include "log.h"\r
+\r
+VTimerList::VTimerList()\r
+{\r
+  recTimerList = NULL;\r
+\r
+  clockRegion.x = 420;\r
+  clockRegion.y = 0;\r
+  clockRegion.w = 150;\r
+  clockRegion.h = 30;\r
+\r
+\r
+\r
+  flipflop = true;\r
+\r
+  setSize(570, 420);\r
+  createBuffer();\r
+\r
+  indicatorsRegion.x = 6;\r
+  indicatorsRegion.y = 44;\r
+  indicatorsRegion.w = 18;\r
+  indicatorsRegion.h = 15 * (getFontHeight() + 1);\r
+\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+  {\r
+    setPosition(80, 70);\r
+  }\r
+  else\r
+  {\r
+    setPosition(70, 35);\r
+  }\r
+\r
+  setTitleBarOn(1);\r
+  setTitleText(tr("Timers"));\r
+  setTitleBarColour(Colour::TITLEBARBACKGROUND);\r
+\r
+  sl.setPosition(30, 30 + 5);\r
+  sl.setSize(area.w - 40, area.h - 30 - 15 - 30);\r
+  add(&sl);\r
+}\r
+\r
+void VTimerList::preDelete()\r
+{\r
+  Timers::getInstance()->cancelTimer(this, 1);\r
+}\r
+\r
+VTimerList::~VTimerList()\r
+{\r
+  if (recTimerList)\r
+  {\r
+    for (UINT i = 0; i < recTimerList->size(); i++)\r
+    {\r
+      delete (*recTimerList)[i];\r
+    }\r
+\r
+    recTimerList->clear();\r
+    delete recTimerList;\r
+  }\r
+}\r
+\r
+void VTimerList::draw()\r
+{\r
+  // Draw statics\r
+\r
+  TBBoxx::draw();\r
+\r
+  WSymbol w;\r
+  TEMPADD(&w);\r
+\r
+  w.nextSymbol = WSymbol::UP;\r
+  w.setPosition(20, 385);\r
+  w.draw();\r
+\r
+  w.nextSymbol = WSymbol::DOWN;\r
+  w.setPosition(50, 385);\r
+  w.draw();\r
+\r
+  w.nextSymbol = WSymbol::SKIPBACK;\r
+  w.setPosition(85, 385);\r
+  w.draw();\r
+\r
+  w.nextSymbol = WSymbol::SKIPFORWARD;\r
+  w.setPosition(115, 385);\r
+  w.draw();\r
+\r
+  drawTextRJ("[ok] = edit", 560, 385, Colour::LIGHTTEXT);\r
+\r
+  drawClock();\r
+  drawShowing();\r
+  drawIndicators();\r
+}\r
+\r
+bool VTimerList::load()\r
+{\r
+  recTimerList = VDR::getInstance()->getRecTimersList();\r
+\r
+  if (!recTimerList) return false;\r
+\r
+  char strA[300];\r
+  char strB[300];\r
+\r
+  struct tm* btime;\r
+\r
+  // FIXME all drawing stuff in this class and sl.clear somewhere?!\r
+\r
+  sl.addColumn(0);\r
+  sl.addColumn(110);\r
+\r
+  RecTimer* recTimer;\r
+  int first = 1;\r
+\r
+  for (UINT i = 0; i < recTimerList->size(); i++)\r
+  {\r
+    recTimer = (*recTimerList)[i];\r
+\r
+    btime = localtime((time_t*)&recTimer->startTime);\r
+    strftime(strA, 299, "%d/%m %H:%M ", btime);\r
+    SNPRINTF(strB, 299, "%s\t%s", strA, recTimer->getName());\r
+    sl.addOption(strB, (ULONG)recTimer, first);\r
+    first = 0;\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+void VTimerList::drawClock()\r
+{\r
+  // Blank the area first\r
+  rectangle(area.w - 150, 0, 150, 30, titleBarColour);\r
+\r
+  char timeString[20];\r
+  time_t t;\r
+  time(&t);\r
+  struct tm* tms = localtime(&t);\r
+  strftime(timeString, 19, "%d/%m %H:%M:%S", tms);\r
+  drawTextRJ(timeString, 560, 5, Colour::LIGHTTEXT);\r
+\r
+  Timers::getInstance()->setTimerT(this, 1, t + 1);\r
+}\r
+\r
+void VTimerList::drawShowing()\r
+{\r
+  int topOption = sl.getTopOption() + 1;\r
+  if (sl.getNumOptions() == 0) topOption = 0;\r
+\r
+  rectangle(220, 385, 180, 25, Colour::VIEWBACKGROUND);\r
+  char showing[200];\r
+  sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());\r
+  drawText(showing, 220, 385, Colour::LIGHTTEXT);\r
+}\r
+\r
+void VTimerList::drawIndicators()\r
+{\r
+  int top = sl.getTopOption();\r
+  int bottom = sl.getBottomOption();\r
+  int yinc = getFontHeight() + 1;\r
+  RecTimer* recTimer;\r
+\r
+  rectangle(6, 44, 18, 15*yinc, Colour::VIEWBACKGROUND);\r
+\r
+  // The indexes recorded from the wselectlist into the index member of the RecTimer\r
+  // Is the same as the position in the vector of RecTimers\r
+  // Because they are in order, they don't change order and wselectlist starts from 0 up consecutively\r
+\r
+  int ypos = 44;\r
+  for (int current = top; current < bottom; current++)\r
+  {\r
+    recTimer = (*recTimerList)[current];\r
+\r
+    if (recTimer->recording) // Flashing red square\r
+    {\r
+      if (flipflop)\r
+      {\r
+        rectangle(6, ypos, 18, 16, Colour::RED);\r
+        drawText("R", 8, ypos-3, Colour::LIGHTTEXT);\r
+      }\r
+    }\r
+    else if (recTimer->pending)\r
+    {\r
+      rectangle(6, ypos, 18, 16, Colour::RED);\r
+      drawText("X", 8, ypos-3, Colour::BLACK);\r
+    }\r
+    else if (recTimer->active == 0)\r
+    {\r
+      rectangle(6, ypos, 18, 16, Colour::SELECTHIGHLIGHT);\r
+      drawText("X", 8, ypos-3, Colour::BLACK);\r
+    }\r
+    else\r
+    {\r
+//      if (flipflop) rectangle(6, ypos, 18, 16, Colour::GREEN);\r
+    }\r
+\r
+    ypos += yinc;\r
+  }\r
+}\r
+\r
+void VTimerList::timercall(int clientReference)\r
+{\r
+  drawClock();\r
+  BoxStack::getInstance()->update(this, &clockRegion);\r
+\r
+  flipflop = !flipflop;\r
+  drawIndicators();\r
+  BoxStack::getInstance()->update(this, &indicatorsRegion);\r
+}\r
+\r
+int VTimerList::handleCommand(int command)\r
+{\r
+  switch(command)\r
+  {\r
+    case Remote::DF_UP:\r
+    case Remote::UP:\r
+    {\r
+      sl.up();\r
+      sl.draw();\r
+      drawShowing();\r
+      drawIndicators();\r
+      BoxStack::getInstance()->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::DF_DOWN:\r
+    case Remote::DOWN:\r
+    {\r
+      sl.down();\r
+      sl.draw();\r
+      drawShowing();\r
+      drawIndicators();\r
+      BoxStack::getInstance()->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::SKIPBACK:\r
+    {\r
+      sl.pageUp();\r
+      sl.draw();\r
+      drawShowing();\r
+      drawIndicators();\r
+      BoxStack::getInstance()->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::SKIPFORWARD:\r
+    {\r
+      sl.pageDown();\r
+      sl.draw();\r
+      drawShowing();\r
+      drawIndicators();\r
+      BoxStack::getInstance()->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::OK:\r
+    {\r
+      RecTimer* recTimer = NULL;\r
+      if (recTimerList) recTimer = (RecTimer*)sl.getCurrentOptionData();\r
+      if (recTimer == NULL) return 2;\r
+\r
+      VTimerEdit* v = new VTimerEdit(recTimer);\r
+      v->setParent(this);\r
+      v->draw();\r
+      BoxStack::getInstance()->add(v);\r
+      BoxStack::getInstance()->update(v);\r
+\r
+      return 2;\r
+    }\r
+    case Remote::BACK:\r
+    {\r
+      return 4;\r
+    }\r
+  }\r
+  // stop command getting to any more views\r
+  return 1;\r
+}\r
+\r
+void VTimerList::processMessage(Message* m)\r
+{\r
+  if (m->message == Message::MOUSE_MOVE)\r
+  {\r
+    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      sl.draw();\r
+      BoxStack::getInstance()->update(this);\r
+    }\r
+  }\r
+  else if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
+    }\r
+    else\r
+    {\r
+      //check if press is outside this view! then simulate cancel\r
+      int x=(m->parameter>>16)-getScreenX();\r
+      int y=(m->parameter&0xFFFF)-getScreenY();\r
+      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
+      {\r
+        BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
+      }\r
+    }\r
+  }\r
+  else if (m->message == Message::DELETE_SELECTED_TIMER)\r
+  {\r
+    RecTimer* recTimer = (RecTimer*)sl.getCurrentOptionData();\r
+    if (recTimer == NULL) return;\r
+    Log::getInstance()->log("VTimerList", Log::DEBUG, "Got timer to delete");\r
+\r
+  \r
+    ULONG retval = VDR::getInstance()->deleteTimer(recTimer);\r
+    if (!VDR::getInstance()->isConnected()) { Command::getInstance()->connectionLost(); return; }\r
+    Log::getInstance()->log("VTimerList", Log::DEBUG, "Got return fron delete timer: %lu", retval);\r
+    \r
+    if (retval != 10)\r
+    {\r
+      VInfo* errorBox = new VInfo();\r
+      errorBox->setSize(360, 200);\r
+      errorBox->createBuffer();\r
+      if (Video::getInstance()->getFormat() == Video::PAL)\r
+        errorBox->setPosition(190, 170);\r
+      else\r
+        errorBox->setPosition(180, 120);\r
+\r
+    \r
+      if (retval == 1) errorBox->setOneLiner(tr("Timers being edited at VDR, please try later"));\r
+      else if (retval == 3)  errorBox->setOneLiner(tr("Unable to delete timer - timer is running"));\r
+      else if (retval == 4)  errorBox->setOneLiner(tr("Error - timer not found at VDR"));\r
+      else                   errorBox->setOneLiner(tr("Unknown error"));\r
+\r
+      errorBox->setExitable();\r
+      errorBox->setBorderOn(1);\r
+      errorBox->setTitleBarColour(Colour::DANGER);\r
+      errorBox->okButton();\r
+      errorBox->draw();\r
+      BoxStack::getInstance()->add(errorBox);\r
+      BoxStack::getInstance()->update(errorBox);\r
+    }\r
+    \r
+    int saveIndex = sl.getCurrentOption();\r
+    int saveTop = sl.getTopOption();\r
+     \r
+    if (recTimerList)\r
+    {\r
+      for (UINT i = 0; i < recTimerList->size(); i++)\r
+      {\r
+        delete (*recTimerList)[i];\r
+      }\r
+\r
+      recTimerList->clear();\r
+      delete recTimerList;\r
+    }\r
+\r
+    sl.clear();\r
+    load();\r
+\r
+    sl.hintSetCurrent(saveIndex);\r
+    sl.hintSetTop(saveTop);\r
+    draw();\r
+    BoxStack::getInstance()->update(this);\r
+  }\r
+}\r
+\r
index 8d50bf2026dd5fd9095f5e39210a45ebcdc9c0be..0e49830a2410253781cd35b2cf617ee44bee2052 100644 (file)
-/*
-    Copyright 2007-2008 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vvideolivetv.h"
-
-#include "vchannellist.h"
-#include "video.h"
-#include "playerlive.h"
-#include "playerlivetv.h"
-#include "playerliveradio.h"
-#include "channel.h"
-#include "boxstack.h"
-#include "colour.h"
-#include "osd.h"
-#include "command.h"
-#include "i18n.h"
-#include "wtextbox.h"
-#include "remote.h"
-#include "vaudioselector.h"
-#include "colour.h"
-#include "event.h"
-#include "timers.h"
-#include "vepg.h"
-#include "bitmap.h"
-#include "log.h"
-#include "vteletextview.h"
-
-VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
-{
-  vdr = VDR::getInstance();
-  boxstack = BoxStack::getInstance();
-  video = Video::getInstance();
-  
-  vas = NULL;
-
-  chanList = tchanList;
-  vchannelList = tvchannelList;
-  numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
-
-  currentChannelIndex = 0;
-  previousChannelIndex = 0;
-  osdChannelIndex = 0;
-  keying = 0;
-  preBuffering = 0;
-
-  playing = false;
-
-  // Convert channel number to index
-  UINT i;
-  for(i = 0; i < chanList->size(); i++)
-  {
-    if ((*chanList)[i]->number == (UINT)initialChannelNumber)
-    {
-      currentChannelIndex = i;
-      osdChannelIndex = i;
-      break;
-    }
-  }
-
-  eventList = NULL;
-
-  videoMode = video->getMode();
-  
-  if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
-  {
-    streamType = VDR::VIDEO;
-    player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);
-  }
-  else
-  {
-    streamType = VDR::RADIO;
-    player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
-  }
-  player->init();
-
-  setSize(video->getScreenWidth(), video->getScreenHeight());
-  createBuffer();
-  Colour transparent(0, 0, 0, 0);
-  setBackgroundColour(transparent);
-
-  dowss = false;
-  char* optionWSS = vdr->configLoad("General", "WSS");
-  if (optionWSS)
-  {
-    if (strstr(optionWSS, "Yes")) dowss = true;
-    delete[] optionWSS;
-  }
-  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
-
-  if (dowss)
-  {
-    wss.setFormat(video->getFormat());
-    wss.setWide(true);
-    add(&wss);
-    
-    wssRegion.x = 0;
-    wssRegion.y = 6;
-    wssRegion.w = video->getScreenWidth();
-    wssRegion.h = 2;
-  }
-  
-  // This variable is set to true if the user pressed OK to bring the OSD on screen
-  // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling
-  okTriggeredOSD = false;
-  
-  Colour osdBack = Colour(0, 0, 0, 128);
-  
-  osd.setBackgroundColour(osdBack);
-  osd.setPosition(0, video->getScreenHeight() - 150);
-  osd.setSize(video->getScreenWidth(), 150);
-  osd.setVisible(false);
-  add(&osd);
-  
-  clock.setBackgroundColour(osdBack);
-  clock.setPosition(osd.getWidth() - 100, 4);
-  clock.setSize(90, 30);
-  osd.add(&clock);
-
-  osdChanNum.setBackgroundColour(osdBack);
-  osdChanNum.setPosition(50, 4);
-  osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font
-  osd.add(&osdChanNum);  
-
-  osdChanName.setBackgroundColour(osdBack);
-  osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
-  osdChanName.setSize(300, 30);
-  osd.add(&osdChanName);
-  
-  boxRed.setBackgroundColour(Colour::RED);
-  boxRed.setPosition(54, 104);
-  boxRed.setSize(18, 16);
-  osd.add(&boxRed);
-
-  boxGreen.setBackgroundColour(Colour::GREEN);
-  boxGreen.setPosition(220, 104);
-  boxGreen.setSize(18, 16);
-  osd.add(&boxGreen);
-
-  boxYellow.setBackgroundColour(Colour::YELLOW);
-  boxYellow.setPosition(390, 104);
-  boxYellow.setSize(18, 16);
-  osd.add(&boxYellow);
-
-  boxBlue.setBackgroundColour(Colour::BLUE);
-  boxBlue.setPosition(560, 104);
-  boxBlue.setSize(18, 16);
-  osd.add(&boxBlue);  
-  
-  textRed.setBackgroundColour(osdBack);
-  textRed.setPosition(boxRed.getX2(), 98);
-  textRed.setSize(boxGreen.getX() - boxRed.getX2(), 30);
-  textRed.setText(tr("Summary"));
-  osd.add(&textRed);  
-    
-  if (streamType == VDR::VIDEO)
-  {
-    textGreen.setBackgroundColour(osdBack);
-    textGreen.setPosition(boxGreen.getX2(), 98);
-    textGreen.setSize(boxYellow.getX() - boxGreen.getX2(), 30);
-    textGreen.setText(tr("Audio"));
-    osd.add(&textGreen);  
-  }
-    
-  textYellow.setBackgroundColour(osdBack);
-  textYellow.setPosition(boxYellow.getX2(), 98);
-  textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);
-  textYellow.setText("Teletext");
-  osd.add(&textYellow);  
-    
-  textBlue.setBackgroundColour(osdBack);
-  textBlue.setPosition(boxBlue.getX2(), 98);
-  textBlue.setSize(osd.getX2() - boxBlue.getX2(), 30);
-  textBlue.setText(tr("EPG"));
-  osd.add(&textBlue);  
-    
-  sl.setBackgroundColour(osdBack);
-  sl.setPosition(70, 36);
-  sl.setSize(500, 58);
-  sl.setNoLoop();
-  osd.add(&sl);
-  
-  // Summary Box
-  summary.setBackgroundColour(osdBack);
-  summary.setPosition(0, video->getScreenHeight() - 300);
-  summary.setSize(video->getScreenWidth(), 150);
-  summary.setVisible(false);
-  add(&summary);  
-  
-  textSummary.setBackgroundColour(osdBack);
-  textSummary.setPosition(40, 10);
-  textSummary.setSize(video->getScreenWidth() - 80, 130);
-  textSummary.setParaMode(true);
-  summary.add(&textSummary);
-  
-  summaryBlackLine.setBackgroundColour(Colour::BLACK);
-  summaryBlackLine.setPosition(0, summary.getHeight() - 4);
-  summaryBlackLine.setSize(summary.getWidth(), 4);
-  summary.add(&summaryBlackLine);
-  
-  sAspectRatio.setPosition(osd.getWidth() - 90, 40);
-  sAspectRatio.nextColour = Colour::SELECTHIGHLIGHT;
-  sAspectRatio.setVisible(false);
-  osd.add(&sAspectRatio);
-  
-  bufferBar.setPosition(osd.getWidth() - 90, 70);
-  bufferBar.setSize(40, 20);
-  bufferBar.setVisible(true);
-  osd.add(&bufferBar);
-  
-  sAudioChannels.setPosition(osd.getWidth() - 130, 40);
-  sAudioChannels.nextColour = Colour::SELECTHIGHLIGHT;
-  sAudioChannels.setVisible(false);
-  osd.add(&sAudioChannels);
-  
-  textUnavailable.setBackgroundColour(osdBack);
-  textUnavailable.setPosition(60, 30);
-  textUnavailable.setSize(osd.getWidth() - 120, 30);
-  textUnavailable.setText(tr("Channel Unavailable"));
-  textUnavailable.setVisible(false);
-  add(&textUnavailable);
-  
-  // FIXME painful
-  Region r1 = summary.getRegionR();
-  Region r2 = osd.getRegionR();
-  osdSummaryRegion = r1 + r2;
-}
-
-void VVideoLiveTV::preDelete()
-{
-  if (playing) stop();
-}
-
-VVideoLiveTV::~VVideoLiveTV()
-{
-  delete player;
-  video->setDefaultAspect();
-  delData();
-}
-
-void VVideoLiveTV::delData()
-{
-  if (eventList)
-  {
-    int eventListSize = eventList->size();
-    for(int i = 0; i < eventListSize; i++)
-    {
-      delete (*eventList)[i];
-    }
-    eventList->clear();
-    delete eventList;
-
-  }
-  sl.clear();
-}
-
-int VVideoLiveTV::handleCommand(int command)
-{
-  switch(command)
-  {
-    case Remote::BACK:
-    {
-      if (osd.getVisible() && !textUnavailable.getVisible())
-      {
-        clearScreen();
-        return 2;
-      }
-      // else drop through to stop
-    }
-    case Remote::STOP:
-    {
-      stop();
-      vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
-      return 4;
-    }
-    
-    // NEW REMOTE ONLY - navigate EPG, bring it onscreen if it's not there
-    case Remote::UP:
-    {
-      doUpDown(false);
-      return 2;
-    }
-    case Remote::DOWN:
-    {
-      doUpDown(true);
-      return 2;
-    }
-    case Remote::LEFT:
-    {
-      doLeftRight(false);
-      return 2;
-    }
-    case Remote::RIGHT:
-    {
-      doLeftRight(true);
-      return 2;
-    }
-    // Continue new remote only...
-    case Remote::CHANNELUP:
-    {
-      doChanUpDown(UP);
-      return 2;
-    }
-    case Remote::CHANNELDOWN:
-    {
-      doChanUpDown(DOWN);
-      return 2;
-    }
-
-    // END NEW REMOTE ONLY, START OLD REMOTE ONLY
-    
-    // DF_LEFT and DF_RIGHT never get here because they are stolen
-    // by command as vol- and vol+
-    
-    // Old remote. Decide what to do based on whether
-    // OK was pressed - osd shown manually, use up/down for epg nav
-    // UP/DOWN was pressed to change channel, osd was shown auto, use up/down for ch+/ch-
-    
-    case Remote::DF_UP:
-    {
-      // Old remote, decide what to do based on okTriggeredOSD
-      if (okTriggeredOSD) doUpDown(false);
-      else doChanUpDown(UP);
-      return 2;
-    }
-    case Remote::DF_DOWN:
-    {
-      // Old remote, decide what to do based on okTriggeredOSD
-      if (okTriggeredOSD) doUpDown(true);
-      else doChanUpDown(DOWN);
-      return 2;
-    }
-
-    // END NEW/OLD REMOTE STUFF
-
-    case Remote::PREVCHANNEL:
-    {
-      channelChange(PREVIOUS, 0);
-      osdChannelIndex = currentChannelIndex;
-      displayOSD(true);
-      return 2;
-    }
-    case Remote::OK:
-    {
-      doOK();
-      return 2;
-    }
-    case Remote::RED:
-    case Remote::MENU:
-    {
-      doSummary();
-      return 2;
-    }
-    case Remote::FULL:
-    case Remote::TV:
-    {
-      toggleChopSides();
-      return 2;
-    }
-
-    case Remote::ZERO:
-    case Remote::ONE:
-    case Remote::TWO:
-    case Remote::THREE:
-    case Remote::FOUR:
-    case Remote::FIVE:
-    case Remote::SIX:
-    case Remote::SEVEN:
-    case Remote::EIGHT:
-    case Remote::NINE:
-    {
-      // key in channel number
-      doKey(command);
-      return 2;
-    }
-
-    case Remote::GREEN:
-    {
-      if (streamType == VDR::VIDEO) doAudioSelector();
-      return 2;   
-    }
-    case Remote::YELLOW:
-    {
-      if (streamType ==VDR::VIDEO) doTeletext(); //TODO: Add a selector for subtitles or teletext
-      return 2;
-    }
-    case Remote::GUIDE:
-    case Remote::BLUE:
-    {
-      doEPG();
-      return 2;
-    }
-    case Remote::RECORD:
-      if (streamType = VDR::VIDEO)
-        (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();
-      return 2;
-  }
-
-  return 1;
-}
-
-void VVideoLiveTV::go()
-{
-  playing = true;
-  draw();
-  boxstack->update(this);
-
-  setClock();
-  displayOSD(true);
-  
-  player->go(currentChannelIndex);
-}
-
-void VVideoLiveTV::stop()
-{
-  Timers::getInstance()->cancelTimer(this, 1);
-  Timers::getInstance()->cancelTimer(this, 2);
-  player->stop();
-  playing = false;
-}
-
-void VVideoLiveTV::doLeftRight(bool right)
-{
-  if (osd.getVisible())
-  {
-    if (right) osdChannelIndex = upChannel(osdChannelIndex);
-    else       osdChannelIndex = downChannel(osdChannelIndex);
-  }
-  else
-  {
-    osdChannelIndex = currentChannelIndex;
-  }
-  displayOSD(true);
-}
-
-void VVideoLiveTV::doUpDown(bool down)
-{
-  if (osd.getVisible())
-  {
-    if (down) sl.down();
-    else      sl.up();
-    sl.draw();
-    
-    displayOSD(false);
-  }
-  else
-  {
-    displayOSD(true);
-  }
-}
-
-void VVideoLiveTV::doChanUpDown(int which)
-{
-  channelChange(OFFSET, which);
-  osdChannelIndex = currentChannelIndex;
-  displayOSD(true);
-}
-
-void VVideoLiveTV::doOK()
-{
-  if (osd.getVisible())
-  {
-    if (keying)
-    {
-      UINT newChannel = 0;
-      for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
-      
-      channelChange(NUMBER, newChannel);
-      osdChannelIndex = currentChannelIndex;
-      displayOSD(true);
-    }
-    else if (osdChannelIndex == currentChannelIndex)
-    {
-      clearScreen();
-    }
-    else
-    {
-      channelChange(INDEX, osdChannelIndex);
-      displayOSD(true);
-    }
-  }
-  else
-  {
-    osdChannelIndex = currentChannelIndex;
-    displayOSD(true);
-    okTriggeredOSD = true;
-  }
-}
-
-void VVideoLiveTV::doSummary()
-{
-  if (summary.getVisible())
-  {
-    summary.setVisible(false);
-    draw();
-    boxstack->update(this, summary.getRegion());
-    Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd
-    return;
-  }
-
-  summary.setVisible(true);
-
-  if (osd.getVisible())
-  {
-    Timers::getInstance()->cancelTimer(this, 1);
-    displayOSD(false);
-  }
-  else
-  {
-    displayOSD(true);
-  }
-}
-
-void VVideoLiveTV::doKey(int command)
-{
-  if (!osd.getVisible()) // First key. prep the data
-  {
-    setNowNextData();
-    keying = 0;    
-  }
-
-  int i;
-  for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
-  keyingInput[0] = command;
-  keying++;
-
-  char* keyingString = new char[numberWidth + 1];
-  for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
-  keyingString[numberWidth] = '\0';
-
-  for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
-  
-  if (keying == numberWidth)
-  {
-    UINT newChannel = 0;
-    for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
-    
-    channelChange(NUMBER, newChannel);
-    osdChannelIndex = currentChannelIndex;
-    Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,
-    displayOSD(true); // this will put one back if required
-  }
-  else
-  {
-    osdChanNum.setText(keyingString);
-
-    if (!osd.getVisible())
-    {
-      osd.setVisible(true);
-      draw();
-    }
-    else
-    {
-      osdChanNum.draw();
-    }
-    boxstack->update(this, osd.getRegion());
-    Timers::getInstance()->setTimerD(this, 1, 3);  // 3s for keying input
-  }
-  delete[] keyingString;
-}
-
-void VVideoLiveTV::doTeletext(bool subtitlemode)
-{
-  if (streamType !=VDR::VIDEO) return;
-  bool exists=true;
-
-  // Cancel keying
-  if (keying)
-  {
-    keying = 0;
-    // and reset the display - this is a copy from setNowNextData
-    char formatChanNum[20];
-    SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
-    osdChanNum.setText(formatChanNum);
-    osdChanName.setText((*chanList)[osdChannelIndex]->name);
-  }
-  if (osd.getVisible()) clearScreen();
-  // Draw the teletxt
-  VTeletextView *vtxv=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
-  if (vtxv==NULL) {
-       vtxv= new VTeletextView(((PlayerLiveTV*)player)->getTeletextDecoder(),this);
-      ((PlayerLiveTV*)player)->getTeletextDecoder()->registerTeletextView(vtxv);
-      exists=false;
-  }
-  vtxv->setSubtitleMode(subtitlemode);
-  vtxv->draw();
-  draw();
-  
-  if (!exists) {
-      BoxStack::getInstance()->add(vtxv);
-  }
-  BoxStack::getInstance()->update(this);
-  BoxStack::getInstance()->update(vtxv); 
-}
-
-void VVideoLiveTV::doAudioSelector()
-{
-  // If the osd is already visisble there might be a timer for it
-  Timers::getInstance()->cancelTimer(this, 1);
-  //This causes a deadlock with the timertrhread itself is locked
-
-
-  // Cancel keying
-  if (keying)
-  {
-    keying = 0;
-    // and reset the display - this is a copy from setNowNextData
-    char formatChanNum[20];
-    SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
-    osdChanNum.setText(formatChanNum);
-    osdChanName.setText((*chanList)[osdChannelIndex]->name);
-  }
-  int subtitleChannel=((PlayerLiveTV*)player)->getCurrentSubtitleChannel();
-  int subtitleType=0x10;
-  if (!(static_cast<PlayerLiveTV*>(player))->isSubtitlesOn()) {
-      if (((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView() &&
-          ((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() 
-          ) {
-              subtitleChannel=((PlayerLiveTV*)player)->getTeletextDecoder()->getPage();
-              subtitleType=0x11;
-          
-      } else {
-          subtitleType=0xFF; //turnedOff
-          subtitleChannel=0;
-      }
-  }
-
-  // Draw the selector
-  vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel(),
-      subtitleType,subtitleChannel,NULL);
-  Colour osdBack = Colour(0, 0, 0, 128);
-  vas->setBackgroundColour(osdBack);
-  vas->setPosition(0, osd.getScreenY() - vas->getHeight());
-  vas->draw();
-
-  // make vas != null and displayOSD will not set a timer or do any boxstack update
-  summary.setVisible(false);
-  if (osd.getVisible()) displayOSD(false);
-  else displayOSD(true);
-  draw();
-
-  BoxStack::getInstance()->add(vas);
-  BoxStack::getInstance()->update(this);        
-  BoxStack::getInstance()->update(vas);     
-}      
-      
-void VVideoLiveTV::doEPG()
-{
-  if (osd.getVisible()) clearScreen();
-
-  video->setMode(Video::QUARTER);
-  video->setPosition(170, 5); //TODO need to deal with 4:3 switching
-
-  VEpg* vepg = new VEpg(this, currentChannelIndex, streamType);
-  vepg->draw();
-  boxstack->add(vepg);
-  boxstack->update(vepg);
-}
-
-void VVideoLiveTV::setNowNextData()
-{
-  delData();
-  
-  Channel* currentChannel = (*chanList)[osdChannelIndex];
-
-  char formatChanNum[20];
-  SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
-  osdChanNum.setText(formatChanNum);
-  osdChanName.setText(currentChannel->name);
-
-  eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
-
-  if (!eventList)
-  {
-    sl.addOption(tr("No channel data available"), 0, 1);
-  }
-  else
-  {
-    sort(eventList->begin(), eventList->end(), EventSorter());
-
-    char tempString[300];
-    char tempString2[300];
-    struct tm* btime;
-    Event* event;
-    int eventListSize = eventList->size();
-    for(int i = 0; i < eventListSize; i++)
-    {
-      event = (*eventList)[i];
-
-      //btime = localtime((time_t*)&event->time);
-      time_t etime = event->time;
-      btime = localtime(&etime);
-#ifndef _MSC_VER
-      strftime(tempString2, 299, "%0H:%0M ", btime);
-#else
-      strftime(tempString2, 299, "%H:%M ", btime);
-#endif
-      SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
-      
-      sl.addOption(tempString, (ULONG)event, (i==0));
-    }
-  }
-}
-
-void VVideoLiveTV::setSummaryData()
-{
-  // If osd is not being displayed, sl will be filled with now, current channel
-  // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now
-  Event* selectedEvent = (Event*)sl.getCurrentOptionData();
-  
-  if (!selectedEvent)
-  {
-    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary");  
-    textSummary.setText(tr("No summary available"));
-  }
-  else
-  {
-    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description);  
-    textSummary.setText(selectedEvent->description);
-  }
-}
-
-void VVideoLiveTV::displayOSD(bool newNowNextData)
-{
-  osd.setVisible(true);
-  if (newNowNextData)
-  {
-    setNowNextData();
-    keying = 0;
-  }
-  osd.draw();
-  
-  if (summary.getVisible())
-  {
-    setSummaryData();
-    summary.draw();
-    boxstack->update(this, &osdSummaryRegion);
-  }
-  else
-  {
-    boxstack->update(this, osd.getRegion());
-  }
-  
-  bool setTimer = true;
-  if (vas) setTimer = false;
-  if (summary.getVisible()) setTimer = false;
-  if (textUnavailable.getVisible()) setTimer = false;
-
-  if (setTimer) Timers::getInstance()->setTimerD(this, 1, 4);
-}
-
-void VVideoLiveTV::clearScreen()
-{  
-  if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);
-
-  textUnavailable.setVisible(false);
-  osd.setVisible(false);
-  summary.setVisible(false);
-
-  okTriggeredOSD = false;
-
-  draw();
-  boxstack->update(this);
-}
-
-void VVideoLiveTV::showUnavailable()
-{
-  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Show unavailable called");  
-  textUnavailable.setVisible(true);
-  textUnavailable.draw();
-  
-  if (!osd.getVisible()) displayOSD(true);
-
-  boxstack->update(this, textUnavailable.getRegion());  
-}
-
-void VVideoLiveTV::setClock()
-{
-  char timeString[20];
-  time_t t;
-  time(&t);
-  struct tm* tms = localtime(&t);
-  strftime(timeString, 19, "%H:%M", tms);
-  clock.setText(timeString);
-
-  time_t dt = 60 - (t % 60);  // seconds to the next minute
-  if (dt == 0) dt = 60; // advance a whole minute if necessary
-  dt += t;  // get a time_t value for it rather than using duration
-  // (so it will occur at the actual second and not second and a half)
-
-  Timers::getInstance()->setTimerT(this, 2, dt);
-}
-
-void VVideoLiveTV::timercall(int ref)
-{
-  if (ref == 1)
-  {
-    if (keying)
-    {
-         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key start."); 
-      UINT newChannel = 0;
-      for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
-      
-      Message* m = new Message();
-      m->message = Message::CHANNEL_CHANGE;
-      m->to = this;
-      m->parameter = newChannel;
-      m->tag = 1; // signal to call displayOSD();
-      Command::getInstance()->postMessageFromOuterSpace(m);
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key end."); 
-    }
-    else
-    {
-        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 not key start."); 
-      // We have received a timer, we are not keying. If still prebuffering, don't remove the bar
-      if (preBuffering < 100)
-      {
-        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Still prebuffering, not removing osd...");  
-        Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s
-        return;
-      }
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 1."); 
-      osd.setVisible(false);
-      okTriggeredOSD = false;
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 2."); 
-      draw();
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 4."); 
-      boxstack->update(this, osd.getRegion());
-
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 3."); 
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey end."); 
-    }
-  }
-  else if (ref == 2)
-  {
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2  start."); 
-    setClock();
-    if (osd.getVisible())
-    {
-      clock.draw();
-      boxstack->update(this, osd.getRegion());
-    }
-    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 end."); 
-  }
-}
-
-bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
-{
-  UINT newChannel = 0;
-  if (streamType ==VDR::VIDEO) {
-  VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
-    if (vtxt ) {
-         BoxStack::getInstance()->remove(vtxt);
-
-    }
-  }
-  if (changeType == INDEX)
-  {
-    newChannel = newData;
-  }
-  else if (changeType == NUMBER)
-  {
-    UINT i;
-    for(i = 0; i < chanList->size(); i++)
-    {
-      if ((*chanList)[i]->number == (UINT)newData)
-      {
-        newChannel = i;
-        break;
-      }
-    }
-
-    if (i == chanList->size())
-    {
-      // no such channel
-      return false;
-    }
-  }
-  else if (changeType == OFFSET)
-  {
-    if (newData == UP) newChannel = upChannel(currentChannelIndex);
-    else newChannel = downChannel(currentChannelIndex);
-  }
-  else if (changeType == PREVIOUS)
-  {
-    newChannel = previousChannelIndex;
-  }
-  else
-  {
-    return false; // bad input
-  }
-
-  if (newChannel == currentChannelIndex) return true;
-
-  previousChannelIndex = currentChannelIndex;
-  currentChannelIndex = newChannel;
-  
-  preBuffering = 0;
-  
-  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
-  player->setChannel(currentChannelIndex);
-  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);
-
-  // Blank out the symbols
-  sAspectRatio.setVisible(false);
-  bufferBar.setPercent(0);
-  sAudioChannels.setVisible(false);
-  
-  // Remove other stuff
-  if (textUnavailable.getVisible())
-  {
-    textUnavailable.setVisible(false);
-    
-  }
-
-    draw();
-    BoxStack::getInstance()->update(this);
-  
-  return true;
-}
-
-void VVideoLiveTV::processMessage(Message* m)
-{
-  if (m->message == Message::MOUSE_LBDOWN)
-  {
-    //check if press is outside this view! then simulate cancel
-    int x=(m->parameter>>16)-osd.getScreenX();
-    int y=(m->parameter&0xFFFF)-osd.getScreenY();
-    if (osd.getVisible()) {
-    
-        if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&
-            (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {
-            BoxStack::getInstance()->handleCommand(Remote::RED);
-        } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&
-            (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){
-            BoxStack::getInstance()->handleCommand(Remote::GREEN);
-        } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&
-            (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){
-            BoxStack::getInstance()->handleCommand(Remote::YELLOW);
-        } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&
-            (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){
-            BoxStack::getInstance()->handleCommand(Remote::BLUE);
-        } else {
-            BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
-        }
-
-    } else {
-        BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
-    }
-  }
-  else if (m->message == Message::CHANNEL_CHANGE)
-  {
-    channelChange(NUMBER, m->parameter);
-    osdChannelIndex = currentChannelIndex;
-    if (m->tag == 1) displayOSD(true);
-  }
-  else if (m->message == Message::EPG_CLOSE)
-  {
-    video->setMode(videoMode);
-  }
-  else if (m->message == Message::CHILD_CLOSE)
-  {
-    if (m->from == vas)
-    {
-      vas = NULL;
-      displayOSD(false);
-    }
-  }
-  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
-  {
-    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
-    player->setAudioChannel((m->parameter & 0xFFFF),(m->parameter & 0xFF0000)>>16);
-  } 
-  else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
-  {
-    if (streamType !=VDR::VIDEO) return;
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);
-      int type=((m->parameter & 0xFF0000)>>16);
-      switch (type) {
-      case 0x10: { //dvbsubtitle
-          if (streamType = VDR::VIDEO){
-              player->setSubtitleChannel((m->parameter & 0xFFFF));
-              (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(true);
-              VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
-              if (vtxt && vtxt->isInSubtitleMode()) {
-                  BoxStack::getInstance()->remove(vtxt);
-              }
-          }
-                 } break;
-      case 0xFF: { //nosubtitles
-          if (streamType = VDR::VIDEO){
-              (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
-              VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
-              if (vtxt && vtxt->isInSubtitleMode()) {
-                  BoxStack::getInstance()->remove(vtxt);
-              }  
-          }
-                 } break;
-      case 0x11: { //videotext
-          (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
-          doTeletext(true);
-          ((PlayerLiveTV*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
-                 } break;
-      };
-      if (vas) {
-        BoxStack::getInstance()->update(vas);
-        //BoxStack::getInstance()->update(&osd); //eveil error
-      }
-      BoxStack::getInstance()->update(this, osd.getRegion());
-
-      
-  }
-  else if (m->message == Message::PLAYER_EVENT)
-  {
-    switch(m->parameter)
-    {
-      case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
-      {
-        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
-        Command::getInstance()->connectionLost();
-        break;
-      }
-      
-      case PlayerLiveTV::STREAM_END:
-      {
-        // Message comes from playerlivetv through master mutex, so can do anything here
-        showUnavailable();        
-        break;
-      }
-      
-      case PlayerLiveTV::ASPECT43:
-      {
-        if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
-        {
-          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
-          wss.setWide(false);
-          wss.draw();
-          BoxStack::getInstance()->update(this, &wssRegion);
-        }
-        
-        sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;
-        sAspectRatio.setVisible(true);
-        
-        if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
-        {
-          osd.draw();
-          BoxStack::getInstance()->update(this, osd.getRegion());
-        }
-        
-        break;
-      }
-      case PlayerLiveTV::ASPECT169:
-      {
-        if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
-        {
-          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
-          wss.setWide(true);
-          wss.draw();
-          BoxStack::getInstance()->update(this, &wssRegion);
-        }
-        
-        sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;
-        sAspectRatio.setVisible(true);
-
-        if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
-        {
-          osd.draw();
-          BoxStack::getInstance()->update(this, osd.getRegion());
-        }
-                
-        break;
-      }
-      case PlayerLiveTV::PREBUFFERING:
-      {
-        preBuffering = m->tag;
-        Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", preBuffering);
-        bufferBar.setPercent(preBuffering);
-
-        if (osd.getVisible())
-        {
-          bufferBar.setVisible(true);
-          bufferBar.draw();
-          Region r;
-          bufferBar.getRootBoxRegion(&r);                       ///////// FIXME !!!
-          BoxStack::getInstance()->update(this, &r);
-          
-          if (preBuffering == 100)
-          {
-            doAudioChannelSymbol();
-          }
-        }
-      }
-    }
-  }
-}
-
-void VVideoLiveTV::doAudioChannelSymbol()
-{
-  // get the doobery
-  Channel* currentChannel = (*chanList)[osdChannelIndex];
-    
-  bool multiAudio = false;
-  #if WIN32
-  if (currentChannel->numDPids > 1) multiAudio = true;
-  #endif
-  if (currentChannel->numAPids > 1) multiAudio = true;
-  
-  // draw the doobery
-  
-  if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO;
-  else            sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO;
-  sAudioChannels.setVisible(true);
-  
-  if (osd.getVisible())
-  {
-    sAudioChannels.draw();
-    Region r;
-    sAudioChannels.getRootBoxRegion(&r);                       ///////// FIXME !!!
-    // Fix this n'all.
-    r.w = 32;
-    r.h = 16;
-    BoxStack::getInstance()->update(this, &r);
-  }
-}
-
-UINT VVideoLiveTV::upChannel(UINT index)
-{
-  if (index == (chanList->size() - 1)) // at the end
-    return 0; // so go to start
-  else
-    return index + 1;
-}
-
-UINT VVideoLiveTV::downChannel(UINT index)
-{
-  if (index == 0) // at the start
-    return chanList->size() - 1; // so go to end
-  else
-    return index - 1;
-}
-
-void VVideoLiveTV::toggleChopSides()
-{
-  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
-
-  if (videoMode == Video::NORMAL)
-  {
-    videoMode = Video::LETTERBOX;
-    video->setMode(Video::LETTERBOX);
-  }
-  else
-  {
-    videoMode = Video::NORMAL;
-    video->setMode(Video::NORMAL);
-  }
-}
-
-void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)
-{
-  drawBitmap(posX, posY, bm);
-  Region r;
-  r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
-  boxstack->update(this, &r);
-}
-
-void VVideoLiveTV::clearOSD()
-{
-  rectangle(area, Colour(0,0,0,0));
-  boxstack->update(this, &area);
-}
-
-void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)
-{
-  Region r;
-  r.x = posX; r.y = posY; r.w = width; r.h = height;
-  rectangle(r, Colour(0,0,0,0));
-  boxstack->update(this, &r);
-}
+/*\r
+    Copyright 2007-2008 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vvideolivetv.h"\r
+\r
+#include "vchannellist.h"\r
+#include "video.h"\r
+#include "audio.h"\r
+#include "playerlive.h"\r
+#include "playerlivetv.h"\r
+#include "playerliveradio.h"\r
+#include "channel.h"\r
+#include "boxstack.h"\r
+#include "colour.h"\r
+#include "osd.h"\r
+#include "command.h"\r
+#include "i18n.h"\r
+#include "wtextbox.h"\r
+#include "remote.h"\r
+#include "vaudioselector.h"\r
+#include "colour.h"\r
+#include "event.h"\r
+#include "timers.h"\r
+#include "vepg.h"\r
+#include "bitmap.h"\r
+#include "log.h"\r
+#include "vteletextview.h"\r
+\r
+VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)\r
+{\r
+  vdr = VDR::getInstance();\r
+  boxstack = BoxStack::getInstance();\r
+  video = Video::getInstance();\r
+  \r
+  vas = NULL;\r
+\r
+  chanList = tchanList;\r
+  vchannelList = tvchannelList;\r
+  numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();\r
+\r
+  currentChannelIndex = 0;\r
+  previousChannelIndex = 0;\r
+  osdChannelIndex = 0;\r
+  keying = 0;\r
+  preBuffering = 0;\r
+\r
+  playing = false;\r
+\r
+  // Convert channel number to index\r
+  UINT i;\r
+  for(i = 0; i < chanList->size(); i++)\r
+  {\r
+    if ((*chanList)[i]->number == (UINT)initialChannelNumber)\r
+    {\r
+      currentChannelIndex = i;\r
+      osdChannelIndex = i;\r
+      break;\r
+    }\r
+  }\r
+\r
+  eventList = NULL;\r
+\r
+  videoMode = video->getMode();\r
+  \r
+  if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)\r
+  {\r
+    streamType = VDR::VIDEO;\r
+    player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);\r
+  }\r
+  else\r
+  {\r
+    streamType = VDR::RADIO;\r
+    player = new PlayerLiveRadio(Command::getInstance(), this, chanList);\r
+  }\r
+  player->init();\r
+\r
+  setSize(video->getScreenWidth(), video->getScreenHeight());\r
+  createBuffer();\r
+  Colour transparent(0, 0, 0, 0);\r
+  setBackgroundColour(transparent);\r
+\r
+  dowss = false;\r
+  char* optionWSS = vdr->configLoad("General", "WSS");\r
+  if (optionWSS)\r
+  {\r
+    if (strstr(optionWSS, "Yes")) dowss = true;\r
+    delete[] optionWSS;\r
+  }\r
+  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);\r
+\r
+  if (dowss)\r
+  {\r
+    wss.setFormat(video->getFormat());\r
+    wss.setWide(true);\r
+    add(&wss);\r
+    \r
+    wssRegion.x = 0;\r
+    wssRegion.y = 6;\r
+    wssRegion.w = video->getScreenWidth();\r
+    wssRegion.h = 2;\r
+  }\r
+  \r
+  // This variable is set to true if the user pressed OK to bring the OSD on screen\r
+  // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling\r
+  okTriggeredOSD = false;\r
+  \r
+  Colour osdBack = Colour(0, 0, 0, 128);\r
+  \r
+  osd.setBackgroundColour(osdBack);\r
+  osd.setPosition(0, video->getScreenHeight() - 150);\r
+  osd.setSize(video->getScreenWidth(), 150);\r
+  osd.setVisible(false);\r
+  add(&osd);\r
+  \r
+  clock.setBackgroundColour(osdBack);\r
+  clock.setPosition(osd.getWidth() - 100, 4);\r
+  clock.setSize(90, 30);\r
+  osd.add(&clock);\r
+\r
+  osdChanNum.setBackgroundColour(osdBack);\r
+  osdChanNum.setPosition(50, 4);\r
+  osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font\r
+  osd.add(&osdChanNum);  \r
+\r
+  osdChanName.setBackgroundColour(osdBack);\r
+  osdChanName.setPosition(osdChanNum.getX2() + 10, 4);\r
+  osdChanName.setSize(300, 30);\r
+  osd.add(&osdChanName);\r
+  \r
+  boxRed.setBackgroundColour(Colour::RED);\r
+  boxRed.setPosition(54, 104);\r
+  boxRed.setSize(18, 16);\r
+  osd.add(&boxRed);\r
+\r
+  boxGreen.setBackgroundColour(Colour::GREEN);\r
+  boxGreen.setPosition(220, 104);\r
+  boxGreen.setSize(18, 16);\r
+  osd.add(&boxGreen);\r
+\r
+  boxYellow.setBackgroundColour(Colour::YELLOW);\r
+  boxYellow.setPosition(390, 104);\r
+  boxYellow.setSize(18, 16);\r
+  osd.add(&boxYellow);\r
+\r
+  boxBlue.setBackgroundColour(Colour::BLUE);\r
+  boxBlue.setPosition(560, 104);\r
+  boxBlue.setSize(18, 16);\r
+  osd.add(&boxBlue);  \r
+  \r
+  textRed.setBackgroundColour(osdBack);\r
+  textRed.setPosition(boxRed.getX2(), 98);\r
+  textRed.setSize(boxGreen.getX() - boxRed.getX2(), 30);\r
+  textRed.setText(tr("Summary"));\r
+  osd.add(&textRed);  \r
+    \r
+  if (streamType == VDR::VIDEO)\r
+  {\r
+    textGreen.setBackgroundColour(osdBack);\r
+    textGreen.setPosition(boxGreen.getX2(), 98);\r
+    textGreen.setSize(boxYellow.getX() - boxGreen.getX2(), 30);\r
+    textGreen.setText(tr("Audio"));\r
+    osd.add(&textGreen);  \r
+  }\r
+    \r
+  textYellow.setBackgroundColour(osdBack);\r
+  textYellow.setPosition(boxYellow.getX2(), 98);\r
+  textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);\r
+  textYellow.setText(tr("Teletext"));\r
+  osd.add(&textYellow);  \r
+    \r
+  textBlue.setBackgroundColour(osdBack);\r
+  textBlue.setPosition(boxBlue.getX2(), 98);\r
+  textBlue.setSize(osd.getX2() - boxBlue.getX2(), 30);\r
+  textBlue.setText(tr("EPG"));\r
+  osd.add(&textBlue);  \r
+    \r
+  sl.setBackgroundColour(osdBack);\r
+  sl.setPosition(70, 36);\r
+  sl.setSize(500, 58);\r
+  sl.setNoLoop();\r
+  osd.add(&sl);\r
+  \r
+  // Summary Box\r
+  summary.setBackgroundColour(osdBack);\r
+  summary.setPosition(0, video->getScreenHeight() - 300);\r
+  summary.setSize(video->getScreenWidth(), 150);\r
+  summary.setVisible(false);\r
+  add(&summary);  \r
+  \r
+  textSummary.setBackgroundColour(osdBack);\r
+  textSummary.setPosition(40, 10);\r
+  textSummary.setSize(video->getScreenWidth() - 80, 130);\r
+  textSummary.setParaMode(true);\r
+  summary.add(&textSummary);\r
+  \r
+  summaryBlackLine.setBackgroundColour(Colour::BLACK);\r
+  summaryBlackLine.setPosition(0, summary.getHeight() - 4);\r
+  summaryBlackLine.setSize(summary.getWidth(), 4);\r
+  summary.add(&summaryBlackLine);\r
+  \r
+  sAspectRatio.setPosition(osd.getWidth() - 90, 40);\r
+  sAspectRatio.nextColour = Colour::SELECTHIGHLIGHT;\r
+  sAspectRatio.setVisible(false);\r
+  osd.add(&sAspectRatio);\r
+  \r
+  bufferBar.setPosition(osd.getWidth() - 90, 70);\r
+  bufferBar.setSize(40, 20);\r
+  bufferBar.setVisible(true);\r
+  osd.add(&bufferBar);\r
+  \r
+  sAudioChannels.setPosition(osd.getWidth() - 130, 40);\r
+  sAudioChannels.nextColour = Colour::SELECTHIGHLIGHT;\r
+  sAudioChannels.setVisible(false);\r
+  osd.add(&sAudioChannels);\r
+  \r
+  textUnavailable.setBackgroundColour(osdBack);\r
+  textUnavailable.setPosition(60, 30);\r
+  textUnavailable.setSize(osd.getWidth() - 120, 30);\r
+  textUnavailable.setText(tr("Channel Unavailable"));\r
+  textUnavailable.setVisible(false);\r
+  add(&textUnavailable);\r
+  \r
+  // FIXME painful\r
+  Region r1 = summary.getRegionR();\r
+  Region r2 = osd.getRegionR();\r
+  osdSummaryRegion = r1 + r2;\r
+}\r
+\r
+void VVideoLiveTV::preDelete()\r
+{\r
+  if (playing) stop();\r
+}\r
+\r
+VVideoLiveTV::~VVideoLiveTV()\r
+{\r
+  delete player;\r
+  video->setDefaultAspect();\r
+  delData();\r
+}\r
+\r
+void VVideoLiveTV::delData()\r
+{\r
+  if (eventList)\r
+  {\r
+    int eventListSize = eventList->size();\r
+    for(int i = 0; i < eventListSize; i++)\r
+    {\r
+      delete (*eventList)[i];\r
+    }\r
+    eventList->clear();\r
+    delete eventList;\r
+\r
+  }\r
+  sl.clear();\r
+}\r
+\r
+int VVideoLiveTV::handleCommand(int command)\r
+{\r
+  switch(command)\r
+  {\r
+    case Remote::BACK:\r
+    {\r
+      if (osd.getVisible() && !textUnavailable.getVisible())\r
+      {\r
+        clearScreen();\r
+        return 2;\r
+      }\r
+      // else drop through to stop\r
+    }\r
+    case Remote::STOP:\r
+    {\r
+      stop();\r
+      vchannelList->highlightChannel((*chanList)[currentChannelIndex]);\r
+      return 4;\r
+    }\r
+    \r
+    // NEW REMOTE ONLY - navigate EPG, bring it onscreen if it's not there\r
+    case Remote::UP:\r
+    {\r
+      doUpDown(false);\r
+      return 2;\r
+    }\r
+    case Remote::DOWN:\r
+    {\r
+      doUpDown(true);\r
+      return 2;\r
+    }\r
+    case Remote::LEFT:\r
+    {\r
+      doLeftRight(false);\r
+      return 2;\r
+    }\r
+    case Remote::RIGHT:\r
+    {\r
+      doLeftRight(true);\r
+      return 2;\r
+    }\r
+    // Continue new remote only...\r
+    case Remote::CHANNELUP:\r
+    {\r
+      doChanUpDown(UP);\r
+      return 2;\r
+    }\r
+    case Remote::CHANNELDOWN:\r
+    {\r
+      doChanUpDown(DOWN);\r
+      return 2;\r
+    }\r
+\r
+    // END NEW REMOTE ONLY, START OLD REMOTE ONLY\r
+    \r
+    // DF_LEFT and DF_RIGHT never get here because they are stolen\r
+    // by command as vol- and vol+\r
+    \r
+    // Old remote. Decide what to do based on whether\r
+    // OK was pressed - osd shown manually, use up/down for epg nav\r
+    // UP/DOWN was pressed to change channel, osd was shown auto, use up/down for ch+/ch-\r
+    \r
+    case Remote::DF_UP:\r
+    {\r
+      // Old remote, decide what to do based on okTriggeredOSD\r
+      if (okTriggeredOSD) doUpDown(false);\r
+      else doChanUpDown(UP);\r
+      return 2;\r
+    }\r
+    case Remote::DF_DOWN:\r
+    {\r
+      // Old remote, decide what to do based on okTriggeredOSD\r
+      if (okTriggeredOSD) doUpDown(true);\r
+      else doChanUpDown(DOWN);\r
+      return 2;\r
+    }\r
+\r
+    // END NEW/OLD REMOTE STUFF\r
+\r
+    case Remote::PREVCHANNEL:\r
+    {\r
+      channelChange(PREVIOUS, 0);\r
+      osdChannelIndex = currentChannelIndex;\r
+      displayOSD(true);\r
+      return 2;\r
+    }\r
+    case Remote::OK:\r
+    {\r
+      doOK();\r
+      return 2;\r
+    }\r
+    case Remote::RED:\r
+    case Remote::MENU:\r
+    {\r
+      doSummary();\r
+      return 2;\r
+    }\r
+    case Remote::FULL:\r
+    case Remote::TV:\r
+    {\r
+      toggleChopSides();\r
+      return 2;\r
+    }\r
+\r
+    case Remote::ZERO:\r
+    case Remote::ONE:\r
+    case Remote::TWO:\r
+    case Remote::THREE:\r
+    case Remote::FOUR:\r
+    case Remote::FIVE:\r
+    case Remote::SIX:\r
+    case Remote::SEVEN:\r
+    case Remote::EIGHT:\r
+    case Remote::NINE:\r
+    {\r
+      // key in channel number\r
+      doKey(command);\r
+      return 2;\r
+    }\r
+\r
+    case Remote::GREEN:\r
+    {\r
+      if (streamType == VDR::VIDEO) doAudioSelector();\r
+      return 2;   \r
+    }\r
+    case Remote::YELLOW:\r
+    {\r
+      if (streamType ==VDR::VIDEO) doTeletext(); //TODO: Add a selector for subtitles or teletext\r
+      return 2;\r
+    }\r
+    case Remote::GUIDE:\r
+    case Remote::BLUE:\r
+    {\r
+      doEPG();\r
+      return 2;\r
+    }\r
+    case Remote::RECORD:\r
+      if (streamType == VDR::VIDEO)\r
+        (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();\r
+      return 2;\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+void VVideoLiveTV::go()\r
+{\r
+  playing = true;\r
+  draw();\r
+  boxstack->update(this);\r
+\r
+  setClock();\r
+  displayOSD(true);\r
+  \r
+  player->go(currentChannelIndex);\r
+}\r
+\r
+void VVideoLiveTV::stop()\r
+{\r
+  Timers::getInstance()->cancelTimer(this, 1);\r
+  Timers::getInstance()->cancelTimer(this, 2);\r
+  player->stop();\r
+  playing = false;\r
+}\r
+\r
+void VVideoLiveTV::doLeftRight(bool right)\r
+{\r
+  if (osd.getVisible())\r
+  {\r
+    if (right) osdChannelIndex = upChannel(osdChannelIndex);\r
+    else       osdChannelIndex = downChannel(osdChannelIndex);\r
+  }\r
+  else\r
+  {\r
+    osdChannelIndex = currentChannelIndex;\r
+  }\r
+  displayOSD(true);\r
+}\r
+\r
+void VVideoLiveTV::doUpDown(bool down)\r
+{\r
+  if (osd.getVisible())\r
+  {\r
+    if (down) sl.down();\r
+    else      sl.up();\r
+    sl.draw();\r
+    \r
+    displayOSD(false);\r
+  }\r
+  else\r
+  {\r
+    displayOSD(true);\r
+  }\r
+}\r
+\r
+void VVideoLiveTV::doChanUpDown(int which)\r
+{\r
+  channelChange(OFFSET, which);\r
+  osdChannelIndex = currentChannelIndex;\r
+  displayOSD(true);\r
+}\r
+\r
+void VVideoLiveTV::doOK()\r
+{\r
+  if (osd.getVisible())\r
+  {\r
+    if (keying)\r
+    {\r
+      UINT newChannel = 0;\r
+      for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);\r
+      \r
+      channelChange(NUMBER, newChannel);\r
+      osdChannelIndex = currentChannelIndex;\r
+      displayOSD(true);\r
+    }\r
+    else if (osdChannelIndex == currentChannelIndex)\r
+    {\r
+      clearScreen();\r
+    }\r
+    else\r
+    {\r
+      channelChange(INDEX, osdChannelIndex);\r
+      displayOSD(true);\r
+    }\r
+  }\r
+  else\r
+  {\r
+    osdChannelIndex = currentChannelIndex;\r
+    displayOSD(true);\r
+    okTriggeredOSD = true;\r
+  }\r
+}\r
+\r
+void VVideoLiveTV::doSummary()\r
+{\r
+  if (summary.getVisible())\r
+  {\r
+    summary.setVisible(false);\r
+    draw();\r
+    boxstack->update(this, summary.getRegion());\r
+    Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd\r
+    return;\r
+  }\r
+\r
+  summary.setVisible(true);\r
+\r
+  if (osd.getVisible())\r
+  {\r
+    Timers::getInstance()->cancelTimer(this, 1);\r
+    displayOSD(false);\r
+  }\r
+  else\r
+  {\r
+    displayOSD(true);\r
+  }\r
+}\r
+\r
+void VVideoLiveTV::doKey(int command)\r
+{\r
+  if (!osd.getVisible()) // First key. prep the data\r
+  {\r
+    setNowNextData();\r
+    keying = 0;    \r
+  }\r
+\r
+  int i;\r
+  for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];\r
+  keyingInput[0] = command;\r
+  keying++;\r
+\r
+  char* keyingString = new char[numberWidth + 1];\r
+  for (i = 0; i < numberWidth; i++) keyingString[i] = '_';\r
+  keyingString[numberWidth] = '\0';\r
+\r
+  for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;\r
+  \r
+  if (keying == numberWidth)\r
+  {\r
+    UINT newChannel = 0;\r
+    for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);\r
+    \r
+    channelChange(NUMBER, newChannel);\r
+    osdChannelIndex = currentChannelIndex;\r
+    Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,\r
+    displayOSD(true); // this will put one back if required\r
+  }\r
+  else\r
+  {\r
+    osdChanNum.setText(keyingString);\r
+\r
+    if (!osd.getVisible())\r
+    {\r
+      osd.setVisible(true);\r
+      draw();\r
+    }\r
+    else\r
+    {\r
+      osdChanNum.draw();\r
+    }\r
+    boxstack->update(this, osd.getRegion());\r
+    Timers::getInstance()->setTimerD(this, 1, 3);  // 3s for keying input\r
+  }\r
+  delete[] keyingString;\r
+}\r
+\r
+void VVideoLiveTV::doTeletext(bool subtitlemode)\r
+{\r
+  if (streamType !=VDR::VIDEO) return;\r
+  bool exists=true;\r
+\r
+  // Cancel keying\r
+  if (keying)\r
+  {\r
+    keying = 0;\r
+    // and reset the display - this is a copy from setNowNextData\r
+    char formatChanNum[20];\r
+    SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);\r
+    osdChanNum.setText(formatChanNum);\r
+    osdChanName.setText((*chanList)[osdChannelIndex]->name);\r
+  }\r
+  if (osd.getVisible()) clearScreen();\r
+  // Draw the teletxt\r
+  VTeletextView *vtxv=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
+  if (vtxv==NULL) {\r
+       vtxv= new VTeletextView(((PlayerLiveTV*)player)->getTeletextDecoder(),this);\r
+      ((PlayerLiveTV*)player)->getTeletextDecoder()->registerTeletextView(vtxv);\r
+      exists=false;\r
+  }\r
+  vtxv->setSubtitleMode(subtitlemode);\r
+  vtxv->draw();\r
+  draw();\r
+  \r
+  if (!exists) {\r
+      BoxStack::getInstance()->add(vtxv);\r
+  }\r
+  BoxStack::getInstance()->update(this);\r
+  BoxStack::getInstance()->update(vtxv); \r
+}\r
+\r
+void VVideoLiveTV::doAudioSelector()\r
+{\r
+  // If the osd is already visisble there might be a timer for it\r
+  Timers::getInstance()->cancelTimer(this, 1);\r
+  //This causes a deadlock with the timertrhread itself is locked\r
+\r
+\r
+  // Cancel keying\r
+  if (keying)\r
+  {\r
+    keying = 0;\r
+    // and reset the display - this is a copy from setNowNextData\r
+    char formatChanNum[20];\r
+    SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);\r
+    osdChanNum.setText(formatChanNum);\r
+    osdChanName.setText((*chanList)[osdChannelIndex]->name);\r
+  }\r
+  int subtitleChannel=((PlayerLiveTV*)player)->getCurrentSubtitleChannel();\r
+  int subtitleType=0x10;\r
+  if (!(static_cast<PlayerLiveTV*>(player))->isSubtitlesOn()) {\r
+      if (((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView() &&\r
+          ((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() \r
+          ) {\r
+              subtitleChannel=((PlayerLiveTV*)player)->getTeletextDecoder()->getPage();\r
+              subtitleType=0x11;\r
+          \r
+      } else {\r
+          subtitleType=0xFF; //turnedOff\r
+          subtitleChannel=0;\r
+      }\r
+  }\r
+\r
+  // Draw the selector\r
+  vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel(),\r
+      subtitleType,subtitleChannel,NULL);\r
+  Colour osdBack = Colour(0, 0, 0, 128);\r
+  vas->setBackgroundColour(osdBack);\r
+  vas->setPosition(0, osd.getScreenY() - vas->getHeight());\r
+  vas->draw();\r
+\r
+  // make vas != null and displayOSD will not set a timer or do any boxstack update\r
+  summary.setVisible(false);\r
+  if (osd.getVisible()) displayOSD(false);\r
+  else displayOSD(true);\r
+  draw();\r
+\r
+  BoxStack::getInstance()->add(vas);\r
+  BoxStack::getInstance()->update(this);        \r
+  BoxStack::getInstance()->update(vas);     \r
+}      \r
+      \r
+void VVideoLiveTV::doEPG()\r
+{\r
+  if (osd.getVisible()) clearScreen();\r
+\r
+  video->setMode(Video::QUARTER);\r
+  video->setPosition(170, 5); //TODO need to deal with 4:3 switching\r
+\r
+  VEpg* vepg = new VEpg(this, currentChannelIndex, streamType);\r
+  vepg->draw();\r
+  boxstack->add(vepg);\r
+  boxstack->update(vepg);\r
+}\r
+\r
+void VVideoLiveTV::setNowNextData()\r
+{\r
+  delData();\r
+  \r
+  Channel* currentChannel = (*chanList)[osdChannelIndex];\r
+\r
+  char formatChanNum[20];\r
+  SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);\r
+  osdChanNum.setText(formatChanNum);\r
+  osdChanName.setText(currentChannel->name);\r
+\r
+  eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);\r
+\r
+  if (!eventList)\r
+  {\r
+    sl.addOption(tr("No channel data available"), 0, 1);\r
+  }\r
+  else\r
+  {\r
+    sort(eventList->begin(), eventList->end(), EventSorter());\r
+\r
+    char tempString[300];\r
+    char tempString2[300];\r
+    struct tm* btime;\r
+    Event* event;\r
+    int eventListSize = eventList->size();\r
+    for(int i = 0; i < eventListSize; i++)\r
+    {\r
+      event = (*eventList)[i];\r
+\r
+      //btime = localtime((time_t*)&event->time);\r
+      time_t etime = event->time;\r
+      btime = localtime(&etime);\r
+#ifndef _MSC_VER\r
+      strftime(tempString2, 299, "%0H:%0M ", btime);\r
+#else\r
+      strftime(tempString2, 299, "%H:%M ", btime);\r
+#endif\r
+      SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);\r
+      \r
+      sl.addOption(tempString, (ULONG)event, (i==0));\r
+    }\r
+  }\r
+}\r
+\r
+void VVideoLiveTV::setSummaryData()\r
+{\r
+  // If osd is not being displayed, sl will be filled with now, current channel\r
+  // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now\r
+  Event* selectedEvent = (Event*)sl.getCurrentOptionData();\r
+  \r
+  if (!selectedEvent)\r
+  {\r
+    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary");  \r
+    textSummary.setText(tr("No summary available"));\r
+  }\r
+  else\r
+  {\r
+    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description);  \r
+    textSummary.setText(selectedEvent->description);\r
+  }\r
+}\r
+\r
+void VVideoLiveTV::displayOSD(bool newNowNextData)\r
+{\r
+  osd.setVisible(true);\r
+  if (newNowNextData)\r
+  {\r
+    setNowNextData();\r
+    keying = 0;\r
+  }\r
+  osd.draw();\r
+  \r
+  if (summary.getVisible())\r
+  {\r
+    setSummaryData();\r
+    summary.draw();\r
+    boxstack->update(this, &osdSummaryRegion);\r
+  }\r
+  else\r
+  {\r
+    boxstack->update(this, osd.getRegion());\r
+  }\r
+  \r
+  bool setTimer = true;\r
+  if (vas) setTimer = false;\r
+  if (summary.getVisible()) setTimer = false;\r
+  if (textUnavailable.getVisible()) setTimer = false;\r
+\r
+  if (setTimer) Timers::getInstance()->setTimerD(this, 1, 4);\r
+}\r
+\r
+void VVideoLiveTV::clearScreen()\r
+{  \r
+  if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);\r
+\r
+  textUnavailable.setVisible(false);\r
+  osd.setVisible(false);\r
+  summary.setVisible(false);\r
+\r
+  okTriggeredOSD = false;\r
+\r
+  draw();\r
+  boxstack->update(this);\r
+}\r
+\r
+void VVideoLiveTV::showUnavailable()\r
+{\r
+  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Show unavailable called");  \r
+  textUnavailable.setVisible(true);\r
+  textUnavailable.draw();\r
+  \r
+  if (!osd.getVisible()) displayOSD(true);\r
+\r
+  boxstack->update(this, textUnavailable.getRegion());  \r
+}\r
+\r
+void VVideoLiveTV::setClock()\r
+{\r
+  char timeString[20];\r
+  time_t t;\r
+  time(&t);\r
+  struct tm* tms = localtime(&t);\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  clock.setText(timeString);\r
+\r
+  time_t dt = 60 - (t % 60);  // seconds to the next minute\r
+  if (dt == 0) dt = 60; // advance a whole minute if necessary\r
+  dt += t;  // get a time_t value for it rather than using duration\r
+  // (so it will occur at the actual second and not second and a half)\r
+\r
+  Timers::getInstance()->setTimerT(this, 2, dt);\r
+}\r
+\r
+void VVideoLiveTV::timercall(int ref)\r
+{\r
+  if (ref == 1)\r
+  {\r
+    if (keying)\r
+    {\r
+         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key start."); \r
+      UINT newChannel = 0;\r
+      for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);\r
+      \r
+      Message* m = new Message();\r
+      m->message = Message::CHANNEL_CHANGE;\r
+      m->to = this;\r
+      m->parameter = newChannel;\r
+      m->tag = 1; // signal to call displayOSD();\r
+      Command::getInstance()->postMessageFromOuterSpace(m);\r
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key end."); \r
+    }\r
+    else\r
+    {\r
+        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 not key start."); \r
+      // We have received a timer, we are not keying. If still prebuffering, don't remove the bar\r
+      if (preBuffering < 100)\r
+      {\r
+        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Still prebuffering, not removing osd...");  \r
+        Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s\r
+        return;\r
+      }\r
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 1."); \r
+      osd.setVisible(false);\r
+      okTriggeredOSD = false;\r
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 2."); \r
+      draw();\r
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 4."); \r
+      boxstack->update(this, osd.getRegion());\r
+\r
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 3."); \r
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey end."); \r
+    }\r
+  }\r
+  else if (ref == 2)\r
+  {\r
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2  start."); \r
+    setClock();\r
+    if (osd.getVisible())\r
+    {\r
+      clock.draw();\r
+      boxstack->update(this, osd.getRegion());\r
+    }\r
+    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 end."); \r
+  }\r
+}\r
+\r
+bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)\r
+{\r
+  UINT newChannel = 0;\r
+  if (streamType ==VDR::VIDEO) {\r
+  VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
+    if (vtxt ) {\r
+         BoxStack::getInstance()->remove(vtxt);\r
+\r
+    }\r
+  }\r
+  if (changeType == INDEX)\r
+  {\r
+    newChannel = newData;\r
+  }\r
+  else if (changeType == NUMBER)\r
+  {\r
+    UINT i;\r
+    for(i = 0; i < chanList->size(); i++)\r
+    {\r
+      if ((*chanList)[i]->number == (UINT)newData)\r
+      {\r
+        newChannel = i;\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (i == chanList->size())\r
+    {\r
+      // no such channel\r
+      return false;\r
+    }\r
+  }\r
+  else if (changeType == OFFSET)\r
+  {\r
+    if (newData == UP) newChannel = upChannel(currentChannelIndex);\r
+    else newChannel = downChannel(currentChannelIndex);\r
+  }\r
+  else if (changeType == PREVIOUS)\r
+  {\r
+    newChannel = previousChannelIndex;\r
+  }\r
+  else\r
+  {\r
+    return false; // bad input\r
+  }\r
+\r
+  if (newChannel == currentChannelIndex) return true;\r
+\r
+  previousChannelIndex = currentChannelIndex;\r
+  currentChannelIndex = newChannel;\r
+  \r
+  preBuffering = 0;\r
+  \r
+  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);\r
+  player->setChannel(currentChannelIndex);\r
+  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);\r
+\r
+  // Blank out the symbols\r
+  sAspectRatio.setVisible(false);\r
+  bufferBar.setPercent(0);\r
+  sAudioChannels.setVisible(false);\r
+  \r
+  // Remove other stuff\r
+  if (textUnavailable.getVisible())\r
+  {\r
+    textUnavailable.setVisible(false);\r
+    \r
+  }\r
+\r
+    draw();\r
+    BoxStack::getInstance()->update(this);\r
+  \r
+  return true;\r
+}\r
+\r
+void VVideoLiveTV::processMessage(Message* m)\r
+{\r
+  if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    //check if press is outside this view! then simulate cancel\r
+    int x=(m->parameter>>16)-osd.getScreenX();\r
+    int y=(m->parameter&0xFFFF)-osd.getScreenY();\r
+    if (osd.getVisible()) {\r
+    \r
+        if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&\r
+            (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {\r
+            BoxStack::getInstance()->handleCommand(Remote::RED);\r
+        } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&\r
+            (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){\r
+            BoxStack::getInstance()->handleCommand(Remote::GREEN);\r
+        } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&\r
+            (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){\r
+            BoxStack::getInstance()->handleCommand(Remote::YELLOW);\r
+        } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&\r
+            (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){\r
+            BoxStack::getInstance()->handleCommand(Remote::BLUE);\r
+        } else {\r
+            BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+        }\r
+\r
+    } else {\r
+        BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+    }\r
+  }\r
+  else if (m->message == Message::CHANNEL_CHANGE)\r
+  {\r
+    channelChange(NUMBER, m->parameter);\r
+    osdChannelIndex = currentChannelIndex;\r
+    if (m->tag == 1) displayOSD(true);\r
+  }\r
+  else if (m->message == Message::EPG_CLOSE)\r
+  {\r
+    video->setMode(videoMode);\r
+  }\r
+  else if (m->message == Message::CHILD_CLOSE)\r
+  {\r
+    if (m->from == vas)\r
+    {\r
+      vas = NULL;\r
+      displayOSD(false);\r
+    }\r
+  }\r
+  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)\r
+  {\r
+    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);\r
+    player->setAudioChannel((m->parameter & 0xFFFF),(m->parameter & 0xFF0000)>>16);\r
+  } \r
+  else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)\r
+  {\r
+    if (streamType !=VDR::VIDEO) return;\r
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);\r
+      int type=((m->parameter & 0xFF0000)>>16);\r
+      switch (type) {\r
+      case 0x10: { //dvbsubtitle\r
+          if (streamType == VDR::VIDEO){\r
+              player->setSubtitleChannel((m->parameter & 0xFFFF));\r
+              (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(true);\r
+              VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
+              if (vtxt && vtxt->isInSubtitleMode()) {\r
+                  BoxStack::getInstance()->remove(vtxt);\r
+              }\r
+          }\r
+                 } break;\r
+      case 0xFF: { //nosubtitles\r
+          if (streamType == VDR::VIDEO){\r
+              (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);\r
+              VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
+              if (vtxt && vtxt->isInSubtitleMode()) {\r
+                  BoxStack::getInstance()->remove(vtxt);\r
+              }  \r
+          }\r
+                 } break;\r
+      case 0x11: { //videotext\r
+          (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);\r
+          doTeletext(true);\r
+          ((PlayerLiveTV*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));\r
+                 } break;\r
+      };\r
+      if (vas) {\r
+        BoxStack::getInstance()->update(vas);\r
+        //BoxStack::getInstance()->update(&osd); //eveil error\r
+      }\r
+      BoxStack::getInstance()->update(this, osd.getRegion());\r
+\r
+      \r
+  }\r
+  else if (m->message == Message::PLAYER_EVENT)\r
+  {\r
+    switch(m->parameter)\r
+    {\r
+      case PlayerLiveTV::CONNECTION_LOST: // connection lost detected\r
+      {\r
+        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");\r
+        Command::getInstance()->connectionLost();\r
+        break;\r
+      }\r
+      \r
+      case PlayerLiveTV::STREAM_END:\r
+      {\r
+        // Message comes from playerlivetv through master mutex, so can do anything here\r
+        showUnavailable();        \r
+        break;\r
+      }\r
+      \r
+      case PlayerLiveTV::ASPECT43:\r
+      {\r
+        if ((video->getTVsize() == Video::ASPECT16X9) && dowss)\r
+        {\r
+          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");\r
+          wss.setWide(false);\r
+          wss.draw();\r
+          BoxStack::getInstance()->update(this, &wssRegion);\r
+        }\r
+        \r
+        sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;\r
+        sAspectRatio.setVisible(true);\r
+        \r
+        if (osd.getVisible()) // don't wake up the whole osd just for a aspect change\r
+        {\r
+          osd.draw();\r
+          BoxStack::getInstance()->update(this, osd.getRegion());\r
+        }\r
+        \r
+        break;\r
+      }\r
+      case PlayerLiveTV::ASPECT169:\r
+      {\r
+        if ((video->getTVsize() == Video::ASPECT16X9) && dowss)\r
+        {\r
+          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");\r
+          wss.setWide(true);\r
+          wss.draw();\r
+          BoxStack::getInstance()->update(this, &wssRegion);\r
+        }\r
+        \r
+        sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;\r
+        sAspectRatio.setVisible(true);\r
+\r
+        if (osd.getVisible()) // don't wake up the whole osd just for a aspect change\r
+        {\r
+          osd.draw();\r
+          BoxStack::getInstance()->update(this, osd.getRegion());\r
+        }\r
+                \r
+        break;\r
+      }\r
+      case PlayerLiveTV::PREBUFFERING:\r
+      {\r
+        preBuffering = m->tag;\r
+        Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", preBuffering);\r
+        bufferBar.setPercent(preBuffering);\r
+\r
+        if (osd.getVisible())\r
+        {\r
+          bufferBar.setVisible(true);\r
+          bufferBar.draw();\r
+          Region r;\r
+          bufferBar.getRootBoxRegion(&r);                       ///////// FIXME !!!\r
+          BoxStack::getInstance()->update(this, &r);\r
+\r
+          if (preBuffering == 100)\r
+          {\r
+            doAudioChannelSymbol();\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+void VVideoLiveTV::doAudioChannelSymbol()\r
+{\r
+  // get the doobery\r
+  Channel* currentChannel = (*chanList)[osdChannelIndex];\r
+    \r
+  bool multiAudio = false;\r
+  if (Audio::getInstance()->supportsAc3()) {\r
+         if ((currentChannel->numDPids+currentChannel->numAPids) > 1) multiAudio = true;\r
+  }\r
+  if (currentChannel->numAPids > 1) multiAudio = true;\r
+  \r
+  // draw the doobery\r
+  \r
+  if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO;\r
+  else            sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO;\r
+  sAudioChannels.setVisible(true);\r
+  \r
+  if (osd.getVisible())\r
+  {\r
+    sAudioChannels.draw();\r
+    Region r;\r
+    sAudioChannels.getRootBoxRegion(&r);                       ///////// FIXME !!!\r
+    // Fix this n'all.\r
+    r.w = 32;\r
+    r.h = 16;\r
+    BoxStack::getInstance()->update(this, &r);\r
+  }\r
+}\r
+\r
+UINT VVideoLiveTV::upChannel(UINT index)\r
+{\r
+  if (index == (chanList->size() - 1)) // at the end\r
+    return 0; // so go to start\r
+  else\r
+    return index + 1;\r
+}\r
+\r
+UINT VVideoLiveTV::downChannel(UINT index)\r
+{\r
+  if (index == 0) // at the start\r
+    return chanList->size() - 1; // so go to end\r
+  else\r
+    return index - 1;\r
+}\r
+\r
+void VVideoLiveTV::toggleChopSides()\r
+{\r
+  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs\r
+\r
+  if (videoMode == Video::NORMAL)\r
+  {\r
+    videoMode = Video::LETTERBOX;\r
+    video->setMode(Video::LETTERBOX);\r
+  }\r
+  else\r
+  {\r
+    videoMode = Video::NORMAL;\r
+    video->setMode(Video::NORMAL);\r
+  }\r
+}\r
+\r
+void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)\r
+{\r
+  drawBitmap(posX, posY, bm);\r
+  Region r;\r
+  r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();\r
+  boxstack->update(this, &r);\r
+}\r
+\r
+void VVideoLiveTV::clearOSD()\r
+{\r
+  rectangle(area, Colour(0,0,0,0));\r
+  boxstack->update(this, &area);\r
+}\r
+\r
+void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)\r
+{\r
+  Region r;\r
+  r.x = posX; r.y = posY; r.w = width; r.h = height;\r
+  rectangle(r, Colour(0,0,0,0));\r
+  boxstack->update(this, &r);\r
+}\r
index daca8b17bcf910295af9f0526e7cb1c3de85f0df..9365a7c4c045c740bf22764ce2161cf83852a646 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vvideomedia.h"
-#include "vmedialist.h"
-#include "media.h"
-#include "mediaplayer.h"
-
-#include "command.h"
-#include "osd.h"
-#include "wsymbol.h"
-#include "audio.h"
-#include "video.h"
-#include "timers.h"
-#include "playermedia.h"
-#include "recording.h"
-#include "vaudioselector.h"
-#include "message.h"
-#include "remote.h"
-#include "boxstack.h"
-#include "vinfo.h"
-#include "i18n.h"
-#include "log.h"
-#include "recinfo.h"
-
-//use the picture channel
-#define MEDIACHANNEL 1
-
-//we misuse PLAYER_EVENTS for timer messages
-//this should be larger then any player message
-#define PLAYER_TIMER_BASE 100
-
-VVideoMedia::VVideoMedia(Media* media, VMediaList *p)
-{
-  lparent=p;
-  boxstack = BoxStack::getInstance();
-  video = Video::getInstance();
-  timers = Timers::getInstance();
-  vas = NULL;
-  vsummary = NULL;
-  lengthBytes=0;
-  myMedia = new Media(media);
-
-  player = new PlayerMedia(this);
-  player->run();
-
-  videoMode = video->getMode();
-
-  playing = false;
-
-
-  setSize(video->getScreenWidth(), video->getScreenHeight());
-  createBuffer();
-  transparent.set(0, 0, 0, 0);
-  setBackgroundColour(transparent);
-
-  barRegion.x = 0;
-  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?
-  barRegion.w = video->getScreenWidth();
-  barRegion.h = 58;
-
-  clocksRegion.x = barRegion.x + 140;
-  clocksRegion.y = barRegion.y + 12;
-  clocksRegion.w = 170;
-  clocksRegion.h = surface->getFontHeight();
-
-
-  barBlue.set(0, 0, 150, 150);
-
-  barShowing = false;
-  barGenHold = false;
-  barScanHold = false;
-  barVasHold = false;
-
-  dowss = false;
-  char* optionWSS = VDR::getInstance()->configLoad("General", "WSS");
-  if (optionWSS)
-  {
-    if (strstr(optionWSS, "Yes")) dowss = true;
-    delete[] optionWSS;
-  }
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Do WSS: %u", dowss);
-
-  if (dowss)
-  {
-    wss.setFormat(video->getFormat());
-    wss.setWide(true);
-    add(&wss);
-
-    wssRegion.x = 0;
-    wssRegion.y = 0;
-    wssRegion.w = video->getScreenWidth();
-    wssRegion.h = 300;
-  }
-}
-
-VVideoMedia::~VVideoMedia()
-{
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Entering  destructor");
-
-  if (vas)
-  {
-    boxstack->remove(vas);
-    vas = NULL;
-  }
-
-  if (vsummary) {
-    remove(vsummary);
-    delete vsummary;
-  }
-
-  if (playing) stopPlay();
-  video->setDefaultAspect();
-
-  timers->cancelTimer(this, 1);
-  timers->cancelTimer(this, 2);
-
-  delete myMedia;
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "shutting down player");
-  player->shutdown();
-  delete player;
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "deleted");
-}
-
-void VVideoMedia::go(bool resume)
-{
-  ULONG startFrameNum=0;
-
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Starting stream: %s at frame: %lu", myMedia->getFileName(), startFrameNum);
-
-  lengthBytes = 0;
-
-  int rt=0;
-  const MediaURI *u=myMedia->getURI();
-  if (!u) {
-    Log::getInstance()->log("VVideoMedia", Log::ERR, "stream: %s has no URI", myMedia->getFileName());
-    rt=-1;
-  }
-  else {
-    rt=MediaPlayer::getInstance()->openMedium(MEDIACHANNEL,u,&lengthBytes,area.w,area.h);
-  }
-  if (rt==0)
-  {
-    //TODO: figure out len in frames
-    int seq=player->playNew(MEDIACHANNEL,lengthBytes,0);
-    int ok=player->waitForSequence(2,seq);
-    if (ok < 0) rt=-1; 
-    else {
-      playing = true;
-      doBar(0);
-    }
-  }
-  if (rt != 0)
-  {
-    stopPlay(); // clean up
-
-    Message* m = new Message();
-    m->message = Message::CLOSE_ME;
-    m->from = this;
-    m->to = boxstack;
-    Command::getInstance()->postMessageNoLock(m);
-
-    VInfo* vi = new VInfo();
-    vi->setSize(400, 150);
-    vi->createBuffer();
-    if (video->getFormat() == Video::PAL)
-      vi->setPosition(170, 200);
-    else
-      vi->setPosition(160, 150);
-    vi->setExitable();
-    vi->setBorderOn(1);
-    vi->setTitleBarOn(0);
-    vi->setOneLiner(tr("Error playing media"));
-    vi->draw();
-
-    m = new Message();
-    m->message = Message::ADD_VIEW;
-    m->to = boxstack;
-    m->parameter = (ULONG)vi;
-    Command::getInstance()->postMessageNoLock(m);
-  }
-}
-
-int VVideoMedia::handleCommand(int command)
-{
-  switch(command)
-  {
-    case Remote::PLAY:
-    {
-      player->play();
-      doBar(0);
-      return 2;
-    }
-
-    case Remote::BACK:
-    {
-      if (vsummary)
-      {
-        removeSummary();
-        return 2;
-      }
-    } // DROP THROUGH
-    case Remote::STOP:
-    case Remote::MENU:
-    {
-      if (playing) stopPlay();
-
-      return 4;
-    }
-    case Remote::PAUSE:
-    {
-      player->pause();
-      doBar(0);
-      return 2;
-    }
-    case Remote::SKIPFORWARD:
-    {
-      doBar(3);
-      player->skipForward(60);
-      return 2;
-    }
-    case Remote::SKIPBACK:
-    {
-      doBar(4);
-      player->skipBackward(60);
-      return 2;
-    }
-    case Remote::FORWARD:
-    {
-      player->fastForward();
-      doBar(0);
-      return 2;
-    }
-    case Remote::REVERSE:
-    {
-      player->fastBackward();
-      doBar(0);
-      return 2;
-    }
-    case Remote::RED:
-    {
-      if (vsummary) removeSummary();
-      else doSummary();
-      return 2;
-    }
-    case Remote::GREEN:
-    {
-      doAudioSelector();
-      return 2;
-    }
-    case Remote::YELLOW:
-    {
-      doBar(2);
-      player->skipBackward(10);
-      return 2;
-    }
-    case Remote::BLUE:
-    {
-      doBar(1);
-      player->skipForward(10);
-      return 2;
-    }
-    case Remote::STAR:
-    {
-      doBar(2);
-      player->skipBackward(10);
-      return 2;
-    }
-    case Remote::HASH:
-    {
-      doBar(1);
-      player->skipForward(10);
-      return 2;
-    }
-    case Remote::FULL:
-    case Remote::TV:
-    {
-      toggleChopSides();
-      return 2;
-    }
-
-    case Remote::OK:
-    {
-      if (vsummary)
-      {
-        removeSummary();
-        return 2;
-      }
-      
-      if (barShowing) removeBar();
-      else {
-        doBar(0);
-        barGenHold=true;
-      }
-      return 2;
-    }
-
-    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;
-    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;
-    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;
-    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;
-    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;
-    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;
-    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;
-    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;
-    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;
-    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;
-
-
-  }
-
-  return 1;
-}
-
-void VVideoMedia::processMessage(Message* m)
-{
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Message received");
-
-  if (m->message == Message::MOUSE_LBDOWN)
-  {
-    UINT x = (m->parameter>>16) - getScreenX();
-    UINT y = (m->parameter&0xFFFF) - getScreenY();
-
-    if (!barShowing)
-    {
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
-    }
-    else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
-    {
-      int progBarXbase = barRegion.x + 300;
-      if (x>=barRegion.x + progBarXbase + 24
-          && x<=barRegion.x + progBarXbase + 4 + 302
-          && y>=barRegion.y + 12 - 2
-          && y<=barRegion.y + 12 - 2+28)
-      {
-        int cx=x-(barRegion.x + progBarXbase + 4);
-        double percent=((double)cx)/302.*100.;
-        player->jumpToPercent(percent);
-        doBar(3);
-        return;
-        //  int progressWidth = 302 * currentFrameNum / lengthFrames;
-        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-      }
-    }
-    else
-    {
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
-    }
-  }
-  else if (m->message == Message::PLAYER_EVENT)
-  {
-    switch(m->parameter)
-    {
-      case PlayerMedia::CONNECTION_LOST: // connection lost detected
-      {
-        // I can't handle this, send it to command
-        Message* m2 = new Message();
-        m2->to = Command::getInstance();
-        m2->message = Message::CONNECTION_LOST;
-        Command::getInstance()->postMessageNoLock(m2);
-        break;
-      }
-      case PlayerMedia::STREAM_END:
-      {
-        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
-        m2->to = BoxStack::getInstance();
-        m2->message = Message::CLOSE_ME;
-        Command::getInstance()->postMessageNoLock(m2);
-        break;
-      }
-      case PlayerMedia::STATUS_CHANGE:
-        doBar(0);
-        break;
-      case PlayerMedia::ASPECT43:
-      {
-        if (dowss)
-        {
-          Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 43");
-          wss.setWide(false);
-          wss.draw();
-          boxstack->update(this, &wssRegion);
-        }
-        break;
-      }
-      case PlayerMedia::ASPECT169:
-      {
-        if (dowss)
-        {
-          Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 169");
-          wss.setWide(true);
-          wss.draw();
-          boxstack->update(this, &wssRegion);
-        }
-        break;
-      }
-      case (PLAYER_TIMER_BASE+1) :
-        //timer1:
-        // Remove bar
-        removeBar();
-        break;
-      case (PLAYER_TIMER_BASE+2) :
-        //timer2:
-        // Update clock
-        if (!barShowing) break;
-        drawBarClocks();
-        BoxStack::getInstance()->update(this,&barRegion);
-        if (player->getLengthFrames() != 0)   timers->setTimerD(this, 2, 0, 200000000);
-        else   timers->setTimerD(this, 2, 1);
-        break;
-    }
-  }
-  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
-  {
-    Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received change audio channel to %i", m->parameter);
-    player->setAudioChannel(m->parameter);
-  }
-  else if (m->message == Message::CHILD_CLOSE)
-  {
-    if (m->from == vas)
-    {
-      vas = NULL;
-      barVasHold = false;
-      if (!barGenHold && !barScanHold && !barVasHold) removeBar();
-    }
-  }
-}
-
-void VVideoMedia::stopPlay()
-{
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Pre stopPlay");
-
-  removeBar();
-
-  player->stop();
-
-  playing = false;
-  MediaPlayer::getInstance()->closeMediaChannel(MEDIACHANNEL);
-
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Post stopPlay");
-}
-
-void VVideoMedia::toggleChopSides()
-{
-  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
-
-  if (videoMode == Video::NORMAL)
-  {
-    videoMode = Video::LETTERBOX;
-    video->setMode(Video::LETTERBOX);
-  }
-  else
-  {
-    videoMode = Video::NORMAL;
-    video->setMode(Video::NORMAL);
-  }
-}
-
-void VVideoMedia::doAudioSelector()
-{
-  bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
-  bool* availableAc3AudioChannels = 0;
-  int currentAudioChannel = player->getCurrentAudioChannel();
-  if (Audio::getInstance()->supportsAc3())
-  {
-      availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
-  }
-
-
-  RecInfo ri;
-  ri.summary=new char[strlen(myMedia->getDisplayName())+1];
-  strcpy(ri.summary,myMedia->getDisplayName());
-  vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, NULL,NULL,0,0, &ri);
-  vas->setBackgroundColour(barBlue);
-  vas->setPosition(0, barRegion.y - 120);
-
-// pal 62, ntsc 57
-
-  barVasHold = true;
-  doBar(0);
-
-  vas->draw();
-  boxstack->add(vas);
-  boxstack->update(vas);
-}
-
-void VVideoMedia::doBar(int action)
-{
-  Log::getInstance()->log("VVideoMedia",Log::DEBUG,"doBar %d",action);
-  barShowing = true;
-
-  rectangle(barRegion, barBlue);
-
-  /* Work out what to display - choices:
-
-  Playing  >
-  Paused   ||
-  FFwd     >>
-  FBwd     <<
-
-  Specials, informed by parameter
-
-  Skip forward 10s    >|
-  Skip backward 10s   |<
-  Skip forward 1m     >>|
-  Skip backward 1m    |<<
-
-  */
-
-  WSymbol w;
-  TEMPADD(&w);
-  w.nextSymbol = 0;
-  w.setPosition(barRegion.x + 66, barRegion.y + 16);
-
-  UCHAR playerState = 0;
-
-  if (action)
-  {
-    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
-    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
-    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
-    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
-  }
-  else
-  {
-    playerState = player->getState();
-    if (playerState == PlayerMedia::S_PLAY)      w.nextSymbol = WSymbol::PLAY;
-    else if (playerState == PlayerMedia::S_FF)    w.nextSymbol = WSymbol::FFWD;
-    else if (playerState == PlayerMedia::S_BACK)    w.nextSymbol = WSymbol::FBWD;
-    else if (playerState == PlayerMedia::S_SEEK)    w.nextSymbol = WSymbol::RIGHTARROW;
-    else if (playerState == PlayerMedia::S_STOP)    w.nextSymbol = WSymbol::PAUSE;
-    else                                       w.nextSymbol = WSymbol::PAUSE;
-  }
-
-  w.draw();
-
-  if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK))
-  {
-    // draw blips to show how fast the scan is
-    UCHAR scanrate = 2;//player->getIScanRate();
-    if (scanrate >= 2)
-    {
-      char text[5];
-      SNPRINTF(text, 5, "%ux", scanrate);
-      drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);
-    }
-  }
-
-  drawBarClocks();
-  boxstack->update(this, &barRegion);
-
-  timers->cancelTimer(this, 1);
-
-
-  if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK)) barScanHold = true;
-  else barScanHold = false;
-
-  if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
-
-  if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);
-  else timers->setTimerD(this, 2, 1);
-}
-
-void VVideoMedia::timercall(int clientReference)
-{
-  Message *m=new Message();
-  m->message=Message::PLAYER_EVENT;
-  m->to=this;
-  m->from=this;
-  m->parameter=PLAYER_TIMER_BASE+clientReference;
-  Command::getInstance()->postMessageFromOuterSpace(m);
-}
-
-void VVideoMedia::drawBarClocks()
-{
-  if (barScanHold)
-  {
-    UCHAR playerState = player->getState();
-    // sticky bar is set if we are in ffwd/fbwd mode
-    // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
-    // will repaint all the bar (it will call this function again, but
-    // this section won't run because stickyBarF will then == false)
-
-    if ((playerState != PlayerMedia::S_FF) && (playerState != PlayerMedia::S_BACK))
-    {
-      barScanHold = false;
-      doBar(0);
-      return; 
-    }
-  }
-
-  Log* logger = Log::getInstance();
-  logger->log("VVideoMedia", Log::DEBUG, "Draw bar clocks");
-
-  // Draw RTC
-  // Blank the area first
-  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
-  char timeString[20];
-  time_t t;
-  time(&t);
-  struct tm* tms = localtime(&t);
-  strftime(timeString, 19, "%H:%M", tms);
-  drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
-
-  ULLONG lenPTS=player->getLenPTS();
-  // Draw clocks
-
-  rectangle(clocksRegion, barBlue);
-
-  ULLONG currentPTS = player->getCurrentPTS();
-
-  hmsf currentFrameHMSF = ptsToHMS(currentPTS);
-  hmsf lengthHMSF = ptsToHMS(lenPTS);
-
-  char buffer[100];
-  if (currentPTS > lenPTS && lenPTS != 0)
-  {
-    strcpy(buffer, "-:--:-- / -:--:--");
-  }
-  else
-  {
-    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
-  }
-    logger->log("VVideoMedia", Log::DEBUG, "cur %llu,len %llu, txt %s",currentPTS,lenPTS,buffer);
-
-  drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
-
-
-
-
-
-
-
-  // Draw progress bar
-  int progBarXbase = barRegion.x + 300;
-
-  if (lenPTS == 0) return;
-  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
-  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
-
-  if (currentPTS > lenPTS) return;
-
-  // Draw yellow portion
-  int progressWidth = 302 * currentPTS / lenPTS;
-  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-
-}
-
-void VVideoMedia::removeBar()
-{
-  if (!barShowing) return;
-  timers->cancelTimer(this, 2);
-  barShowing = false;
-  barGenHold = false;
-  barScanHold = false;
-  barVasHold = false;
-  rectangle(barRegion, transparent);
-  BoxStack::getInstance()->update(this, &barRegion);
-}
-
-void VVideoMedia::doSummary()
-{
-  vsummary = new VInfo();
-  vsummary->setTitleText(myMedia->getDisplayName());
-  vsummary->setBorderOn(1);
-  vsummary->setExitable();
-  const MediaURI *u=myMedia->getURI();
-  int stlen=0;
-  if (u) {
-    stlen+=strlen(myMedia->getFileName());
-    stlen+=strlen(tr("FileName"))+10;
-  }
-  stlen+=strlen(tr("Size"))+50;
-  stlen+=strlen(tr("Directory"))+500;
-  stlen+=strlen(tr("Time"))+50;
-  char *pinfo=player->getInfo();
-  stlen+=strlen(pinfo)+10;
-  char *buf=new char [stlen];
-  char *tsbuf=new char [stlen];
-  char *tsbuf2=new char [stlen];
-  char *tbuf=new char[Media::TIMEBUFLEN];
-  SNPRINTF(buf,stlen,"%s\n" 
-                   "%s: %llu Bytes\n"
-                   "%s\n"
-                   "%s: %s\n"
-                   "%s",
-      shortendedText(tr("FileName"),": ",myMedia->getFileName(),tsbuf,vsummary->getWidth()),
-      tr("Size"),
-      lengthBytes,
-      shortendedText(tr("Directory"),": ",lparent->getDirname(MEDIA_TYPE_VIDEO),tsbuf2,vsummary->getWidth()),
-      tr("Time"),
-      myMedia->getTimeString(tbuf),
-      pinfo
-      );
-  //TODO more info
-  if (u) {
-      Log::getInstance()->log("VVideoMedia",Log::DEBUG,"info %s",buf);
-      vsummary->setMainText(buf);
-  }
-  else vsummary->setMainText(tr("Info unavailable"));
-  delete pinfo;
-  if (Video::getInstance()->getFormat() == Video::PAL)
-  {
-    vsummary->setPosition(70, 100);
-  }
-  else
-  {
-    vsummary->setPosition(40, 70);
-  }
-  vsummary->setSize(580, 350);
-  add(vsummary);
-  vsummary->draw();
-
-  BoxStack::getInstance()->update(this);
-   delete [] buf;
-  delete []  tsbuf;
-  delete [] tsbuf2;
-  delete []  tbuf;
-}
-
-void VVideoMedia::removeSummary()
-{
-  if (vsummary)
-  {
-    remove(vsummary);
-    delete vsummary;
-    vsummary = NULL;
-    draw();
-    BoxStack::getInstance()->update(this);
-  }
-}
-
-
-hmsf VVideoMedia::ptsToHMS(ULLONG pts) {
-  ULLONG secs=pts/90000;
-  hmsf rt;
-  rt.frames=0;
-  rt.seconds=secs%60;
-  secs=secs/60;
-  rt.minutes=secs%60;
-  secs=secs/60;
-  rt.hours=secs;
-  return rt;
-}
-  
-char * VVideoMedia::shortendedText(const char * title, const char * title2,const char * intext,char *buffer,UINT width) {
-  if (! intext) {
-    intext="";
-  }
-  UINT twidth=0;
-  for (const char *p=title;*p!=0;p++) twidth+=charWidth(*p);
-  for (const char *p=title2;*p!=0;p++) twidth+=charWidth(*p);
-  const char *prfx="...";
-  UINT prfwidth=3*charWidth('.');
-  const char *istart=intext+strlen(intext);
-  UINT iwidth=0;
-  while (twidth+iwidth+prfwidth < width-2*paraMargin && istart> intext) {
-    istart--;
-    iwidth+=charWidth(*istart);
-  }
-  if (twidth+iwidth+prfwidth >= width-2*paraMargin && istart < intext+strlen(intext)) istart++;
-  if (istart == intext) prfx="";
-  sprintf(buffer,"%s%s%s%s",title,title2,prfx,intext);
-  return buffer;
-}
-
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vvideomedia.h"\r
+#include "vmedialist.h"\r
+#include "media.h"\r
+#include "mediaplayer.h"\r
+\r
+#include "command.h"\r
+#include "osd.h"\r
+#include "wsymbol.h"\r
+#include "audio.h"\r
+#include "video.h"\r
+#include "timers.h"\r
+#include "playermedia.h"\r
+#include "recording.h"\r
+#include "vaudioselector.h"\r
+#include "message.h"\r
+#include "remote.h"\r
+#include "boxstack.h"\r
+#include "vinfo.h"\r
+#include "i18n.h"\r
+#include "log.h"\r
+#include "recinfo.h"\r
+\r
+//use the picture channel\r
+#define MEDIACHANNEL 1\r
+\r
+//we misuse PLAYER_EVENTS for timer messages\r
+//this should be larger then any player message\r
+#define PLAYER_TIMER_BASE 100\r
+\r
+VVideoMedia::VVideoMedia(Media* media, VMediaList *p)\r
+{\r
+  lparent=p;\r
+  boxstack = BoxStack::getInstance();\r
+  video = Video::getInstance();\r
+  timers = Timers::getInstance();\r
+  vas = NULL;\r
+  vsummary = NULL;\r
+  lengthBytes=0;\r
+  myMedia = new Media(media);\r
+\r
+  player = new PlayerMedia(this);\r
+  player->run();\r
+\r
+  videoMode = video->getMode();\r
+\r
+  playing = false;\r
+\r
+\r
+  setSize(video->getScreenWidth(), video->getScreenHeight());\r
+  createBuffer();\r
+  transparent.set(0, 0, 0, 0);\r
+  setBackgroundColour(transparent);\r
+\r
+  barRegion.x = 0;\r
+  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?\r
+  barRegion.w = video->getScreenWidth();\r
+  barRegion.h = 58;\r
+\r
+  clocksRegion.x = barRegion.x + 140;\r
+  clocksRegion.y = barRegion.y + 12;\r
+  clocksRegion.w = 170;\r
+  clocksRegion.h = getFontHeight();\r
+\r
+\r
+  barBlue.set(0, 0, 150, 150);\r
+\r
+  barShowing = false;\r
+  barGenHold = false;\r
+  barScanHold = false;\r
+  barVasHold = false;\r
+\r
+  dowss = false;\r
+  char* optionWSS = VDR::getInstance()->configLoad("General", "WSS");\r
+  if (optionWSS)\r
+  {\r
+    if (strstr(optionWSS, "Yes")) dowss = true;\r
+    delete[] optionWSS;\r
+  }\r
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Do WSS: %u", dowss);\r
+\r
+  if (dowss)\r
+  {\r
+    wss.setFormat(video->getFormat());\r
+    wss.setWide(true);\r
+    add(&wss);\r
+\r
+    wssRegion.x = 0;\r
+    wssRegion.y = 0;\r
+    wssRegion.w = video->getScreenWidth();\r
+    wssRegion.h = 300;\r
+  }\r
+}\r
+\r
+VVideoMedia::~VVideoMedia()\r
+{\r
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Entering  destructor");\r
+\r
+  if (vas)\r
+  {\r
+    boxstack->remove(vas);\r
+    vas = NULL;\r
+  }\r
+\r
+  if (vsummary) {\r
+    remove(vsummary);\r
+    delete vsummary;\r
+  }\r
+\r
+  if (playing) stopPlay();\r
+  video->setDefaultAspect();\r
+\r
+  timers->cancelTimer(this, 1);\r
+  timers->cancelTimer(this, 2);\r
+\r
+  delete myMedia;\r
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "shutting down player");\r
+  player->shutdown();\r
+  delete player;\r
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "deleted");\r
+}\r
+\r
+void VVideoMedia::go(bool resume)\r
+{\r
+  ULONG startFrameNum=0;\r
+\r
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Starting stream: %s at frame: %lu", myMedia->getFileName(), startFrameNum);\r
+\r
+  lengthBytes = 0;\r
+\r
+  int rt=0;\r
+  const MediaURI *u=myMedia->getURI();\r
+  if (!u) {\r
+    Log::getInstance()->log("VVideoMedia", Log::ERR, "stream: %s has no URI", myMedia->getFileName());\r
+    rt=-1;\r
+  }\r
+  else {\r
+    rt=MediaPlayer::getInstance()->openMedium(MEDIACHANNEL,u,&lengthBytes,area.w,area.h);\r
+  }\r
+  if (rt==0)\r
+  {\r
+    //TODO: figure out len in frames\r
+    int seq=player->playNew(MEDIACHANNEL,lengthBytes,0);\r
+    int ok=player->waitForSequence(2,seq);\r
+    if (ok < 0) rt=-1; \r
+    else {\r
+      playing = true;\r
+      doBar(0);\r
+    }\r
+  }\r
+  if (rt != 0)\r
+  {\r
+    stopPlay(); // clean up\r
+\r
+    Message* m = new Message();\r
+    m->message = Message::CLOSE_ME;\r
+    m->from = this;\r
+    m->to = boxstack;\r
+    Command::getInstance()->postMessageNoLock(m);\r
+\r
+    VInfo* vi = new VInfo();\r
+    vi->setSize(400, 150);\r
+    vi->createBuffer();\r
+    if (video->getFormat() == Video::PAL)\r
+      vi->setPosition(170, 200);\r
+    else\r
+      vi->setPosition(160, 150);\r
+    vi->setExitable();\r
+    vi->setBorderOn(1);\r
+    vi->setTitleBarOn(0);\r
+    vi->setOneLiner(tr("Error playing media"));\r
+    vi->draw();\r
+\r
+    m = new Message();\r
+    m->message = Message::ADD_VIEW;\r
+    m->to = boxstack;\r
+    m->parameter = (ULONG)vi;\r
+    Command::getInstance()->postMessageNoLock(m);\r
+  }\r
+}\r
+\r
+int VVideoMedia::handleCommand(int command)\r
+{\r
+  switch(command)\r
+  {\r
+    case Remote::PLAY:\r
+    {\r
+      player->play();\r
+      doBar(0);\r
+      return 2;\r
+    }\r
+\r
+    case Remote::BACK:\r
+    {\r
+      if (vsummary)\r
+      {\r
+        removeSummary();\r
+        return 2;\r
+      }\r
+    } // DROP THROUGH\r
+    case Remote::STOP:\r
+    case Remote::MENU:\r
+    {\r
+      if (playing) stopPlay();\r
+\r
+      return 4;\r
+    }\r
+    case Remote::PAUSE:\r
+    {\r
+      player->pause();\r
+      doBar(0);\r
+      return 2;\r
+    }\r
+    case Remote::SKIPFORWARD:\r
+    {\r
+      doBar(3);\r
+      player->skipForward(60);\r
+      return 2;\r
+    }\r
+    case Remote::SKIPBACK:\r
+    {\r
+      doBar(4);\r
+      player->skipBackward(60);\r
+      return 2;\r
+    }\r
+    case Remote::FORWARD:\r
+    {\r
+      player->fastForward();\r
+      doBar(0);\r
+      return 2;\r
+    }\r
+    case Remote::REVERSE:\r
+    {\r
+      player->fastBackward();\r
+      doBar(0);\r
+      return 2;\r
+    }\r
+    case Remote::RED:\r
+    {\r
+      if (vsummary) removeSummary();\r
+      else doSummary();\r
+      return 2;\r
+    }\r
+    case Remote::GREEN:\r
+    {\r
+      doAudioSelector();\r
+      return 2;\r
+    }\r
+    case Remote::YELLOW:\r
+    {\r
+      doBar(2);\r
+      player->skipBackward(10);\r
+      return 2;\r
+    }\r
+    case Remote::BLUE:\r
+    {\r
+      doBar(1);\r
+      player->skipForward(10);\r
+      return 2;\r
+    }\r
+    case Remote::STAR:\r
+    {\r
+      doBar(2);\r
+      player->skipBackward(10);\r
+      return 2;\r
+    }\r
+    case Remote::HASH:\r
+    {\r
+      doBar(1);\r
+      player->skipForward(10);\r
+      return 2;\r
+    }\r
+    case Remote::FULL:\r
+    case Remote::TV:\r
+    {\r
+      toggleChopSides();\r
+      return 2;\r
+    }\r
+\r
+    case Remote::OK:\r
+    {\r
+      if (vsummary)\r
+      {\r
+        removeSummary();\r
+        return 2;\r
+      }\r
+      \r
+      if (barShowing) removeBar();\r
+      else {\r
+        doBar(0);\r
+        barGenHold=true;\r
+      }\r
+      return 2;\r
+    }\r
+\r
+    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;\r
+    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;\r
+    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;\r
+    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;\r
+    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;\r
+    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;\r
+    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;\r
+    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;\r
+    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;\r
+    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;\r
+\r
+\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+void VVideoMedia::processMessage(Message* m)\r
+{\r
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Message received");\r
+\r
+  if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    UINT x = (m->parameter>>16) - getScreenX();\r
+    UINT y = (m->parameter&0xFFFF) - getScreenY();\r
+\r
+    if (!barShowing)\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+    }\r
+    else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)\r
+    {\r
+      int progBarXbase = barRegion.x + 300;\r
+      if (x>=barRegion.x + progBarXbase + 24\r
+          && x<=barRegion.x + progBarXbase + 4 + 302\r
+          && y>=barRegion.y + 12 - 2\r
+          && y<=barRegion.y + 12 - 2+28)\r
+      {\r
+        int cx=x-(barRegion.x + progBarXbase + 4);\r
+        double percent=((double)cx)/302.*100.;\r
+        player->jumpToPercent(percent);\r
+        doBar(3);\r
+        return;\r
+        //  int progressWidth = 302 * currentFrameNum / lengthFrames;\r
+        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+      }\r
+    }\r
+    else\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+    }\r
+  }\r
+  else if (m->message == Message::PLAYER_EVENT)\r
+  {\r
+    switch(m->parameter)\r
+    {\r
+      case PlayerMedia::CONNECTION_LOST: // connection lost detected\r
+      {\r
+        // I can't handle this, send it to command\r
+        Message* m2 = new Message();\r
+        m2->to = Command::getInstance();\r
+        m2->message = Message::CONNECTION_LOST;\r
+        Command::getInstance()->postMessageNoLock(m2);\r
+        break;\r
+      }\r
+      case PlayerMedia::STREAM_END:\r
+      {\r
+        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+        m2->to = BoxStack::getInstance();\r
+        m2->message = Message::CLOSE_ME;\r
+        Command::getInstance()->postMessageNoLock(m2);\r
+        break;\r
+      }\r
+      case PlayerMedia::STATUS_CHANGE:\r
+        doBar(0);\r
+        break;\r
+      case PlayerMedia::ASPECT43:\r
+      {\r
+        if (dowss)\r
+        {\r
+          Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 43");\r
+          wss.setWide(false);\r
+          wss.draw();\r
+          boxstack->update(this, &wssRegion);\r
+        }\r
+        break;\r
+      }\r
+      case PlayerMedia::ASPECT169:\r
+      {\r
+        if (dowss)\r
+        {\r
+          Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 169");\r
+          wss.setWide(true);\r
+          wss.draw();\r
+          boxstack->update(this, &wssRegion);\r
+        }\r
+        break;\r
+      }\r
+      case (PLAYER_TIMER_BASE+1) :\r
+        //timer1:\r
+        // Remove bar\r
+        removeBar();\r
+        break;\r
+      case (PLAYER_TIMER_BASE+2) :\r
+        //timer2:\r
+        // Update clock\r
+        if (!barShowing) break;\r
+        drawBarClocks();\r
+        BoxStack::getInstance()->update(this,&barRegion);\r
+        if (player->getLengthFrames() != 0)   timers->setTimerD(this, 2, 0, 200000000);\r
+        else   timers->setTimerD(this, 2, 1);\r
+        break;\r
+    }\r
+  }\r
+  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)\r
+  {\r
+    Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received change audio channel to %i", m->parameter);\r
+    player->setAudioChannel(m->parameter);\r
+  }\r
+  else if (m->message == Message::CHILD_CLOSE)\r
+  {\r
+    if (m->from == vas)\r
+    {\r
+      vas = NULL;\r
+      barVasHold = false;\r
+      if (!barGenHold && !barScanHold && !barVasHold) removeBar();\r
+    }\r
+  }\r
+}\r
+\r
+void VVideoMedia::stopPlay()\r
+{\r
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Pre stopPlay");\r
+\r
+  removeBar();\r
+\r
+  player->stop();\r
+\r
+  playing = false;\r
+  MediaPlayer::getInstance()->closeMediaChannel(MEDIACHANNEL);\r
+\r
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Post stopPlay");\r
+}\r
+\r
+void VVideoMedia::toggleChopSides()\r
+{\r
+  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs\r
+\r
+  if (videoMode == Video::NORMAL)\r
+  {\r
+    videoMode = Video::LETTERBOX;\r
+    video->setMode(Video::LETTERBOX);\r
+  }\r
+  else\r
+  {\r
+    videoMode = Video::NORMAL;\r
+    video->setMode(Video::NORMAL);\r
+  }\r
+}\r
+\r
+void VVideoMedia::doAudioSelector()\r
+{\r
+  bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();\r
+  bool* availableAc3AudioChannels = 0;\r
+  int currentAudioChannel = player->getCurrentAudioChannel();\r
+  if (Audio::getInstance()->supportsAc3())\r
+  {\r
+      availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();\r
+  }\r
+\r
+\r
+  RecInfo ri;\r
+  ri.summary=new char[strlen(myMedia->getDisplayName())+1];\r
+  strcpy(ri.summary,myMedia->getDisplayName());\r
+  vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, NULL,NULL,0,0, &ri);\r
\r
+  vas->setBackgroundColour(barBlue);\r
+  vas->setPosition(0, barRegion.y - 120);\r
+\r
+// pal 62, ntsc 57\r
+\r
+  barVasHold = true;\r
+  doBar(0);\r
+\r
+  vas->draw();\r
+  boxstack->add(vas);\r
+  boxstack->update(vas);\r
+}\r
+\r
+void VVideoMedia::doBar(int action)\r
+{\r
+  Log::getInstance()->log("VVideoMedia",Log::DEBUG,"doBar %d",action);\r
+  barShowing = true;\r
+\r
+  rectangle(barRegion, barBlue);\r
+\r
+  /* Work out what to display - choices:\r
+\r
+  Playing  >\r
+  Paused   ||\r
+  FFwd     >>\r
+  FBwd     <<\r
+\r
+  Specials, informed by parameter\r
+\r
+  Skip forward 10s    >|\r
+  Skip backward 10s   |<\r
+  Skip forward 1m     >>|\r
+  Skip backward 1m    |<<\r
+\r
+  */\r
+\r
+  WSymbol w;\r
+  TEMPADD(&w);\r
+  w.nextSymbol = 0;\r
+  w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
+\r
+  UCHAR playerState = 0;\r
+\r
+  if (action)\r
+  {\r
+    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;\r
+    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;\r
+    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;\r
+    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;\r
+  }\r
+  else\r
+  {\r
+    playerState = player->getState();\r
+    if (playerState == PlayerMedia::S_PLAY)      w.nextSymbol = WSymbol::PLAY;\r
+    else if (playerState == PlayerMedia::S_FF)    w.nextSymbol = WSymbol::FFWD;\r
+    else if (playerState == PlayerMedia::S_BACK)    w.nextSymbol = WSymbol::FBWD;\r
+    else if (playerState == PlayerMedia::S_SEEK)    w.nextSymbol = WSymbol::RIGHTARROW;\r
+    else if (playerState == PlayerMedia::S_STOP)    w.nextSymbol = WSymbol::PAUSE;\r
+    else                                       w.nextSymbol = WSymbol::PAUSE;\r
+  }\r
+\r
+  w.draw();\r
+\r
+  if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK))\r
+  {\r
+    // draw blips to show how fast the scan is\r
+    UCHAR scanrate = 2;//player->getIScanRate();\r
+    if (scanrate >= 2)\r
+    {\r
+      char text[5];\r
+      SNPRINTF(text, 5, "%ux", scanrate);\r
+      drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);\r
+    }\r
+  }\r
+\r
+  drawBarClocks();\r
+  boxstack->update(this, &barRegion);\r
+\r
+  timers->cancelTimer(this, 1);\r
+\r
+\r
+  if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK)) barScanHold = true;\r
+  else barScanHold = false;\r
+\r
+  if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);\r
+\r
+  if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);\r
+  else timers->setTimerD(this, 2, 1);\r
+}\r
+\r
+void VVideoMedia::timercall(int clientReference)\r
+{\r
+  Message *m=new Message();\r
+  m->message=Message::PLAYER_EVENT;\r
+  m->to=this;\r
+  m->from=this;\r
+  m->parameter=PLAYER_TIMER_BASE+clientReference;\r
+  Command::getInstance()->postMessageFromOuterSpace(m);\r
+}\r
+\r
+void VVideoMedia::drawBarClocks()\r
+{\r
+  if (barScanHold)\r
+  {\r
+    UCHAR playerState = player->getState();\r
+    // sticky bar is set if we are in ffwd/fbwd mode\r
+    // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which\r
+    // will repaint all the bar (it will call this function again, but\r
+    // this section won't run because stickyBarF will then == false)\r
+\r
+    if ((playerState != PlayerMedia::S_FF) && (playerState != PlayerMedia::S_BACK))\r
+    {\r
+      barScanHold = false;\r
+      doBar(0);\r
+      return; \r
+    }\r
+  }\r
+\r
+  Log* logger = Log::getInstance();\r
+  logger->log("VVideoMedia", Log::DEBUG, "Draw bar clocks");\r
+\r
+  // Draw RTC\r
+  // Blank the area first\r
+  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
+  char timeString[20];\r
+  time_t t;\r
+  time(&t);\r
+  struct tm* tms = localtime(&t);\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);\r
+\r
+  ULLONG lenPTS=player->getLenPTS();\r
+  // Draw clocks\r
+\r
+  rectangle(clocksRegion, barBlue);\r
+\r
+  ULLONG currentPTS = player->getCurrentPTS();\r
+\r
+  hmsf currentFrameHMSF = ptsToHMS(currentPTS);\r
+  hmsf lengthHMSF = ptsToHMS(lenPTS);\r
+\r
+  char buffer[100];\r
+  if (currentPTS > lenPTS && lenPTS != 0)\r
+  {\r
+    strcpy(buffer, "-:--:-- / -:--:--");\r
+  }\r
+  else\r
+  {\r
+    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
+  }\r
+    logger->log("VVideoMedia", Log::DEBUG, "cur %llu,len %llu, txt %s",currentPTS,lenPTS,buffer);\r
+\r
+  drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+  // Draw progress bar\r
+  int progBarXbase = barRegion.x + 300;\r
+\r
+  if (lenPTS == 0) return;\r
+  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);\r
+  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
+\r
+  if (currentPTS > lenPTS) return;\r
+\r
+  // Draw yellow portion\r
+  int progressWidth = 302 * currentPTS / lenPTS;\r
+  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+\r
+}\r
+\r
+void VVideoMedia::removeBar()\r
+{\r
+  if (!barShowing) return;\r
+  timers->cancelTimer(this, 2);\r
+  barShowing = false;\r
+  barGenHold = false;\r
+  barScanHold = false;\r
+  barVasHold = false;\r
+  rectangle(barRegion, transparent);\r
+  BoxStack::getInstance()->update(this, &barRegion);\r
+}\r
+\r
+void VVideoMedia::doSummary()\r
+{\r
+  vsummary = new VInfo();\r
+  vsummary->setTitleText(myMedia->getDisplayName());\r
+  vsummary->setBorderOn(1);\r
+  vsummary->setExitable();\r
+  const MediaURI *u=myMedia->getURI();\r
+  int stlen=0;\r
+  if (u) {\r
+    stlen+=strlen(myMedia->getFileName());\r
+    stlen+=strlen(tr("FileName"))+10;\r
+  }\r
+  stlen+=strlen(tr("Size"))+50;\r
+  stlen+=strlen(tr("Directory"))+500;\r
+  stlen+=strlen(tr("Time"))+50;\r
+  char *pinfo=player->getInfo();\r
+  stlen+=strlen(pinfo)+10;\r
+  char *buf=new char [stlen];\r
+  char *tsbuf=new char [stlen];\r
+  char *tsbuf2=new char [stlen];\r
+  char *tbuf=new char[Media::TIMEBUFLEN];\r
+  SNPRINTF(buf,stlen,"%s\n" \r
+                   "%s: %llu Bytes\n"\r
+                   "%s\n"\r
+                   "%s: %s\n"\r
+                   "%s",\r
+      shortendedText(tr("FileName"),": ",myMedia->getFileName(),tsbuf,vsummary->getWidth()),\r
+      tr("Size"),\r
+      lengthBytes,\r
+      shortendedText(tr("Directory"),": ",lparent->getDirname(MEDIA_TYPE_VIDEO),tsbuf2,vsummary->getWidth()),\r
+      tr("Time"),\r
+      myMedia->getTimeString(tbuf),\r
+      pinfo\r
+      );\r
+  //TODO more info\r
+  if (u) {\r
+      Log::getInstance()->log("VVideoMedia",Log::DEBUG,"info %s",buf);\r
+      vsummary->setMainText(buf);\r
+  }\r
+  else vsummary->setMainText(tr("Info unavailable"));\r
+  delete pinfo;\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+  {\r
+    vsummary->setPosition(70, 100);\r
+  }\r
+  else\r
+  {\r
+    vsummary->setPosition(40, 70);\r
+  }\r
+  vsummary->setSize(580, 350);\r
+  add(vsummary);\r
+  vsummary->draw();\r
+\r
+  BoxStack::getInstance()->update(this);\r
+   delete [] buf;\r
+  delete []  tsbuf;\r
+  delete [] tsbuf2;\r
+  delete []  tbuf;\r
+}\r
+\r
+void VVideoMedia::removeSummary()\r
+{\r
+  if (vsummary)\r
+  {\r
+    remove(vsummary);\r
+    delete vsummary;\r
+    vsummary = NULL;\r
+    draw();\r
+    BoxStack::getInstance()->update(this);\r
+  }\r
+}\r
+\r
+\r
+hmsf VVideoMedia::ptsToHMS(ULLONG pts) {\r
+  ULLONG secs=pts/90000;\r
+  hmsf rt;\r
+  rt.frames=0;\r
+  rt.seconds=secs%60;\r
+  secs=secs/60;\r
+  rt.minutes=secs%60;\r
+  secs=secs/60;\r
+  rt.hours=secs;\r
+  return rt;\r
+}\r
+  \r
+char * VVideoMedia::shortendedText(const char * title, const char * title2,const char * intext,char *buffer,UINT width) {\r
+  if (! intext) {\r
+    intext="";\r
+  }\r
+  UINT twidth=0;\r
+  for (const char *p=title;*p!=0;p++) twidth+=charWidth(*p);\r
+  for (const char *p=title2;*p!=0;p++) twidth+=charWidth(*p);\r
+  const char *prfx="...";\r
+  UINT prfwidth=3*charWidth('.');\r
+  const char *istart=intext+strlen(intext);\r
+  UINT iwidth=0;\r
+  while (twidth+iwidth+prfwidth < width-2*paraMargin && istart> intext) {\r
+    istart--;\r
+    iwidth+=charWidth(*istart);\r
+  }\r
+  if (twidth+iwidth+prfwidth >= width-2*paraMargin && istart < intext+strlen(intext)) istart++;\r
+  if (istart == intext) prfx="";\r
+  sprintf(buffer,"%s%s%s%s",title,title2,prfx,intext);\r
+  return buffer;\r
+}\r
+\r
+\r
index c84c9a6fac86c6eba5e1af535e9f4c324faa0e82..e651dd07129109a519457f979b47eec232fd3bd3 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include <math.h>
-
-#include "vvideorec.h"
-#include "vteletextview.h"
-
-#include "command.h"
-#include "osd.h"
-#include "wsymbol.h"
-#include "audio.h"
-#include "vdr.h"
-#include "video.h"
-#include "timers.h"
-#include "player.h"
-#include "recording.h"
-#include "vaudioselector.h"
-#include "message.h"
-#include "remote.h"
-#include "boxstack.h"
-#include "vinfo.h"
-#include "i18n.h"
-#include "bitmap.h"
-#include "recinfo.h"
-#include "log.h"
-#include "channel.h"
-VVideoRec::VVideoRec(Recording* rec, bool ish264)
-{
-  boxstack = BoxStack::getInstance();
-  vdr = VDR::getInstance();
-  video = Video::getInstance();
-  timers = Timers::getInstance();
-  vas = NULL;
-  vsummary = NULL;
-
-  videoMode = video->getMode();
-  myRec = rec;
-
-  video->seth264mode(ish264);
-
-  player = new Player(Command::getInstance(), this, this);
-  player->init(myRec->IsPesRecording,myRec->recInfo->fps);
-
-  playing = false;
-
-  startMargin = 0;
-  endMargin = 0;
-  char* cstartMargin = vdr->configLoad("Timers", "Start margin");
-  char* cendMargin = vdr->configLoad("Timers", "End margin");
-  if (!cstartMargin)
-  {
-    startMargin = 300; // 5 mins default
-  }
-  else
-  {
-    startMargin = atoi(cstartMargin) * 60;
-    delete[] cstartMargin;
-  }
-
-  if (!cendMargin)
-  {
-    endMargin = 300; // 5 mins default
-  }
-  else
-  {
-    endMargin = atoi(cendMargin) * 60;
-    delete[] cendMargin;
-  }
-
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);
-
-  setSize(video->getScreenWidth(), video->getScreenHeight());
-  createBuffer();
-  transparent.set(0, 0, 0, 0);
-  setBackgroundColour(transparent);
-
-  barRegion.x = 0;
-  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?
-  barRegion.w = video->getScreenWidth();
-  barRegion.h = 58;
-
-  clocksRegion.x = barRegion.x + 140;
-  clocksRegion.y = barRegion.y + 12;
-  clocksRegion.w = 170;
-  clocksRegion.h = surface->getFontHeight();
-//  barBlue.set(0, 0, 150, 150);
-  barBlue.set(0, 0, 0, 128);
-
-  barShowing = false;
-  barGenHold = false;
-  barScanHold = false;
-  barVasHold = false;
-
-  dowss = false;
-  char* optionWSS = vdr->configLoad("General", "WSS");
-  if (optionWSS)
-  {
-    if (strstr(optionWSS, "Yes")) dowss = true;
-    delete[] optionWSS;
-  }
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Do WSS: %u", dowss);
-
-  if (dowss)
-  {
-    wss.setFormat(video->getFormat());
-    wss.setWide(true);
-    add(&wss);
-
-    wssRegion.x = 0;
-    wssRegion.y = 0;
-    wssRegion.w = video->getScreenWidth();
-    wssRegion.h = 300;
-  }
-}
-
-void VVideoRec::preDelete()
-{
-  timers->cancelTimer(this, 1);
-  timers->cancelTimer(this, 2);
-
-  if (vas)
-  {
-    boxstack->remove(vas);
-    vas = NULL;
-  }
-
-  if (vsummary) delete vsummary;
-
-  if (playing) stopPlay();
-}
-
-VVideoRec::~VVideoRec()
-{
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Entering vvideorec destructor");
-
-  video->setDefaultAspect();
-
-  // kill recInfo in case resumePoint has changed (likely)
-  myRec->dropRecInfo();
-  // FIXME - do this properly - save the resume point back to the server manually and update
-  // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well
-}
-
-void VVideoRec::go(bool resume)
-{
-  ULONG startFrameNum;
-  if (resume)
-    startFrameNum = myRec->recInfo->resumePoint;
-  else
-    startFrameNum = 0;
-
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Starting stream: %s at frame: %lu", myRec->getFileName(), startFrameNum);
-  ULONG lengthFrames = 0;
-  bool isPesRecording;
-  ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);
-  myRec->IsPesRecording = isPesRecording;
-  if (lengthBytes)
-  {
-    player->setLengthBytes(lengthBytes);
-    player->setLengthFrames(lengthFrames);
-    player->setStartFrame(startFrameNum);
-    player->play();
-    playing = true;
-    doBar(0);
-  }
-  else
-  {
-    stopPlay(); // clean up
-
-    if (!vdr->isConnected())
-    {
-      Command::getInstance()->connectionLost();
-      return;
-    }
-
-    Message* m = new Message();
-    m->message = Message::CLOSE_ME;
-    m->from = this;
-    m->to = boxstack;
-    Command::getInstance()->postMessageNoLock(m);
-
-    VInfo* vi = new VInfo();
-    vi->setSize(400, 150);
-    vi->createBuffer();
-    if (video->getFormat() == Video::PAL)
-      vi->setPosition(170, 200);
-    else
-      vi->setPosition(160, 150);
-    vi->setExitable();
-    vi->setBorderOn(1);
-    vi->setTitleBarOn(0);
-    vi->setOneLiner(tr("Error playing recording"));
-    vi->draw();
-
-    m = new Message();
-    m->message = Message::ADD_VIEW;
-    m->to = boxstack;
-    m->parameter = (ULONG)vi;
-    Command::getInstance()->postMessageNoLock(m);
-  }
-}
-
-int VVideoRec::handleCommand(int command)
-{
-  switch(command)
-  {
-    case Remote::PLAY:
-    {
-      player->play();
-      doBar(0);
-      return 2;
-    }
-
-    case Remote::BACK:
-    {
-      if (vsummary)
-      {
-        removeSummary();
-        return 2;
-      }
-    } // DROP THROUGH
-    case Remote::STOP:
-    case Remote::MENU:
-    {
-      if (playing) stopPlay();
-
-      return 4;
-    }
-    case Remote::PAUSE:
-    {
-      player->pause();
-      doBar(0);
-      return 2;
-    }
-    case Remote::SKIPFORWARD:
-    {
-      doBar(3);
-      player->skipForward(60);
-      return 2;
-    }
-    case Remote::SKIPBACK:
-    {
-      doBar(4);
-      player->skipBackward(60);
-      return 2;
-    }
-    case Remote::FORWARD:
-    {
-      player->fastForward();
-      doBar(0);
-      return 2;
-    }
-    case Remote::REVERSE:
-    {
-      player->fastBackward();
-      doBar(0);
-      return 2;
-    }
-    case Remote::RED:
-    {
-      if (vsummary) removeSummary();
-      else doSummary();
-      return 2;
-    }
-    case Remote::GREEN:
-    {
-      doAudioSelector();
-      return 2;
-    }
-    case Remote::YELLOW:
-    {
-      if (myRec->hasMarks())
-      {
-        // skip to previous mark
-        Log* logger = Log::getInstance();
-        int currentFrame = (player->getCurrentFrameNum()); // get current Frame
-        currentFrame -= 5. * myRec->recInfo->fps; // subtrack 5 seconds, else you cannot skip more than once back ..
-
-        int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame
-        if (prevMark)
-        {
-          logger->log("VVideoRec", Log::NOTICE, "jump back from pos %i to mark at %i",currentFrame,prevMark);
-          player->jumpToMark(prevMark);
-        }
-        doBar(4);
-      }
-      else
-      {
-        doBar(2);
-        player->skipBackward(10);
-      }
-      return 2;
-    }
-    case Remote::BLUE:
-    {
-      if (myRec->hasMarks())
-      {
-        // skip to next mark
-        Log* logger = Log::getInstance();
-        int currentFrame = (player->getCurrentFrameNum());
-
-        int nextMark = myRec->getNextMark(currentFrame);
-
-        if (nextMark)
-        {
-          logger->log("VVideoRec", Log::NOTICE, "jump forward from pos %i to mark at %i",currentFrame,nextMark);
-          player->jumpToMark(nextMark);
-        }
-        doBar(3);
-      }
-      else
-      {
-        doBar(1);
-        player->skipForward(10);
-      }
-      return 2;
-    }
-    case Remote::STAR:
-    {
-      doBar(2);
-      player->skipBackward(10);
-      return 2;
-    }
-    case Remote::HASH:
-    {
-      doBar(1);
-      player->skipForward(10);
-      return 2;
-    }
-    case Remote::FULL:
-    case Remote::TV:
-    {
-      toggleChopSides();
-      return 2;
-    }
-
-    case Remote::OK:
-    {
-      if (vsummary)
-      {
-        removeSummary();
-        return 2;
-      }
-      
-      if (barShowing) removeBar();
-      else doBar(0);
-      return 2;
-    }
-
-    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;
-    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;
-    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;
-    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;
-    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;
-    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;
-    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;
-    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;
-    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;
-    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;
-
-    case Remote::RECORD: player->toggleSubtitles(); return 2;
-#ifdef DEV
-//    case Remote::RED:
-//    {
-      //Don't use RED for anything. It will eventually be recording summary
-
-      //player->test1();
-
-
-      /*
-      // for testing EPG in NTSC with a NTSC test video
-      Video::getInstance()->setMode(Video::QUARTER);
-      Video::getInstance()->setPosition(170, 5);
-      VEpg* vepg = new VEpg(NULL, 0);
-      vepg->draw();
-      BoxStack::getInstance()->add(vepg);
-      BoxStack::getInstance()->update(vepg);
-      */
-
-//      return 2;
-//    }
-
-#endif
-
-  }
-
-  return 1;
-}
-
-void VVideoRec::doTeletext()
-{
-  
-  bool exists=true;
-
-  
-  // Draw the teletxt
-  VTeletextView *vtxv=player->getTeletextDecoder()->getTeletxtView();
-  if (vtxv==NULL) {
-       vtxv= new VTeletextView((player)->getTeletextDecoder(),this);
-      (player)->getTeletextDecoder()->registerTeletextView(vtxv);
-      exists=false;
-  }
-  vtxv->setSubtitleMode(true);
-  vtxv->draw();
-  draw();
-  
-  if (!exists) {
-      BoxStack::getInstance()->add(vtxv);
-  }
-  BoxStack::getInstance()->update(this);
-  BoxStack::getInstance()->update(vtxv); 
-}
-
-void VVideoRec::processMessage(Message* m)
-{
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");
-
-  if (m->message == Message::MOUSE_LBDOWN)
-  {
-    UINT x = (m->parameter>>16) - getScreenX();
-    UINT y = (m->parameter&0xFFFF) - getScreenY();
-
-    if (!barShowing)
-    {
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
-    }
-    else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
-    {
-      int progBarXbase = barRegion.x + 300;
-      if (myRec->hasMarks())
-      {
-        MarkList* markList = myRec->getMarkList();
-        MarkList::iterator i;
-        Mark* loopMark = NULL;
-        int posPix;
-        ULONG lengthFrames;
-        if (myRec->recInfo->timerEnd > time(NULL))
-        {
-          // chasing playback
-          // Work out an approximate length in frames (good to 1s...)
-                       lengthFrames = (ULONG)((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);
-        }
-        else
-        {
-          lengthFrames = player->getLengthFrames();
-        }
-        for(i = markList->begin(); i != markList->end(); i++)
-        {
-          loopMark = *i;
-          if (loopMark->pos)
-          {
-            posPix = 302 * loopMark->pos / lengthFrames;
-            rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
-            if (x>=barRegion.x + progBarXbase + 2 + posPix
-                && x<=barRegion.x + progBarXbase + 2 + posPix+3
-                && y>=barRegion.y + 12 - 2
-                && y<=barRegion.y + 12 - 2+28)
-            {
-              player->jumpToMark(loopMark->pos);
-              doBar(3);
-              return;
-            }
-          }
-        }
-      }
-
-      if (x>=barRegion.x + progBarXbase + 24
-          && x<=barRegion.x + progBarXbase + 4 + 302
-          && y>=barRegion.y + 12 - 2
-          && y<=barRegion.y + 12 - 2+28)
-      {
-        int cx=x-(barRegion.x + progBarXbase + 4);
-        double percent=((double)cx)/302.*100.;
-        player->jumpToPercent(percent);
-        doBar(3);
-        return;
-        //  int progressWidth = 302 * currentFrameNum / lengthFrames;
-        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-      }
-    }
-    else
-    {
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
-    }
-  }
-  else if (m->from == player)
-  {
-    if (m->message != Message::PLAYER_EVENT) return;
-    switch(m->parameter)
-    {
-      case Player::CONNECTION_LOST: // connection lost detected
-      {
-        // I can't handle this, send it to command
-        Message* m2 = new Message();
-        m2->to = Command::getInstance();
-        m2->message = Message::CONNECTION_LOST;
-        Command::getInstance()->postMessageNoLock(m2);
-        break;
-      }
-      case Player::STOP_PLAYBACK:
-      {
-        // FIXME Obselete ish - improve this
-        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
-        m2->to = Command::getInstance();
-        m2->message = Message::STOP_PLAYBACK;
-        Command::getInstance()->postMessageNoLock(m2);
-        break;
-      }
-      case Player::ASPECT43:
-      {
-        if (dowss)
-        {
-          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
-          wss.setWide(false);
-          wss.draw();
-          boxstack->update(this, &wssRegion);
-        }
-        break;
-      }
-      case Player::ASPECT169:
-      {
-        if (dowss)
-        {
-          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
-          wss.setWide(true);
-          wss.draw();
-          boxstack->update(this, &wssRegion);
-        }
-        break;
-      }
-    }
-  }
-  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
-  {
-    Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change audio channel to %i", m->parameter);
-    player->setAudioChannel(m->parameter&0xFFFF,(m->parameter&0xFF0000)>> 16 );
-  }
-  else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
-  {
-      Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);
-      int type=((m->parameter & 0xFF0000)>>16);
-      switch (type) {
-      case 0x10: { //dvbsubtitle
-          player->setSubtitleChannel((m->parameter & 0xFFFF));
-          player->turnSubtitlesOn(true);
-          VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();
-          if (vtxt && vtxt->isInSubtitleMode()) {
-              BoxStack::getInstance()->remove(vtxt);
-          }
-                 } break;
-      case 0xFF: { //nosubtitles
-          
-           player->turnSubtitlesOn(false);
-           VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();
-           if (vtxt && vtxt->isInSubtitleMode()) {
-              BoxStack::getInstance()->remove(vtxt);
-           }  
-          
-                 } break;
-      case 0x11: { //videotext
-          player->turnSubtitlesOn(false);
-          doTeletext();
-          ((Player*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
-                 } break;
-      };
-      if (vas) {
-        BoxStack::getInstance()->update(vas);
-      }
-      BoxStack::getInstance()->update(this);
-
-      
-  } 
-  else if (m->message == Message::CHILD_CLOSE)
-  {
-    if (m->from == vas)
-    {
-      vas = NULL;
-      barVasHold = false;
-      if (!barGenHold && !barScanHold && !barVasHold) removeBar();
-    }
-  }
-}
-
-void VVideoRec::stopPlay()
-{
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Pre stopPlay");
-
-  removeBar();
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "1");
-  player->stop();
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "2");
-  vdr->stopStreaming();
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "3");
-  delete player;
-
-  playing = false;
-
-  if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Post stopPlay");
-}
-
-void VVideoRec::toggleChopSides()
-{
-  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
-
-  if (videoMode == Video::NORMAL)
-  {
-    videoMode = Video::LETTERBOX;
-    video->setMode(Video::LETTERBOX);
-  }
-  else
-  {
-    videoMode = Video::NORMAL;
-    video->setMode(Video::NORMAL);
-  }
-}
-
-void VVideoRec::doAudioSelector()
-{
-    int subtitleChannel=player->getCurrentSubtitleChannel();
-    int subtitleType=0x10;
-    if (!(player)->isSubtitlesOn()) {
-        if ((player)->getTeletextDecoder()->getTeletxtView() &&
-            (player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() 
-            ) {
-                subtitleChannel=(player)->getTeletextDecoder()->getPage();
-                subtitleType=0x11;
-      
-           } else {
-                subtitleType=0xFF; //turnedOff
-                subtitleChannel=0;
-          }
-    }
-    if (player->isPesRecording()) {
-        bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
-        bool* availableAc3AudioChannels = NULL;
-        bool* availableSubtitleChannels = player->getDemuxerSubtitleChannels();
-        int *availableTTxtpages = player->getTeletxtSubtitlePages();
-        int currentAudioChannel = player->getCurrentAudioChannel();
-        if (Audio::getInstance()->supportsAc3())
-        {
-            availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
-        }
-        
-        vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel,availableSubtitleChannels, availableTTxtpages,
-            subtitleChannel, subtitleType, myRec->recInfo);
-    } else {
-        // Draw the selector
-        Channel temp_channel=player->getDemuxerChannel();
-        RecInfo *cur_info= myRec->recInfo;
-        unsigned char numchan_recinfo = cur_info->numComponents;
-        unsigned char numchan_subtitles_siz = temp_channel.numSPids;
-        ULONG mp_audcounter = 0;
-        ULONG ac3_counter = 0;
-        int dvb_subcounter = 1;
-        
-        unsigned char type;
-        char* lang;
-        char* description;
-        int i;
-        for (i = 0; i < numchan_recinfo; i++)
-        {   
-            apid* ac = NULL;
-            type = cur_info->types[i];
-            lang = cur_info->languages[i];
-            description = cur_info->descriptions[i];
-            
-
-            if (cur_info->streams[i] == 2) {
-                switch (type)
-                {
-                case 1: //mpaudio mono
-                case 3: //mpaudio stereo
-                    if (mp_audcounter < temp_channel.numAPids) ac = &temp_channel.apids[mp_audcounter];
-                    
-                    mp_audcounter++;
-                    break;
-                case 5: //ac3
-                    if (ac3_counter < temp_channel.numDPids) ac = &temp_channel.dpids[ac3_counter];
-                    ac3_counter++;
-                    break;
-                }
-            } else if (cur_info->streams[i] == 3){
-                if (dvb_subcounter < numchan_subtitles_siz) ac = &temp_channel.spids[dvb_subcounter];
-            } else continue; //neither audio nor subtitle
-            if (ac)
-            {
-                if (description && (strlen(description) > 0))
-                {
-                    ac->name = new char[strlen(description) + 1];
-                    strcpy(ac->name, description);
-                    
-                } else if (lang && strlen(lang) > 0)
-                {
-                    ac->name = new char[strlen(lang) + 1];
-                    strcpy(ac->name, lang);
-                    
-                }
-            }
-        }
-        for (i=0;i<temp_channel.numAPids;i++) {
-            apid *ac=&temp_channel.apids[i];
-            if (ac->name==NULL) {
-                ac->name = new char[strlen(tr("unknown")) + 1];
-                strcpy(ac->name, tr("unknown"));
-            }
-        }
-        for (i=0;i<temp_channel.numDPids;i++) {
-            apid *ac=&temp_channel.dpids[i];
-            if (ac->name==NULL) {
-                ac->name = new char[strlen(tr("unknown")) + 1];
-                strcpy(ac->name, tr("unknown"));
-            }
-        }
-        for (i=0;i<temp_channel.numSPids;i++) {
-            apid *ac=&temp_channel.spids[i];
-            if (ac->name==NULL) {
-                ac->name = new char[strlen(tr("unknown")) + 1];
-                strcpy(ac->name, tr("unknown"));
-            }
-        }
-
-        vas = new VAudioSelector(this,&temp_channel , (player)->getCurrentAudioChannel(),
-            subtitleType,subtitleChannel,player->getTeletxtSubtitlePages());  
-         for (i=0;i<temp_channel.numAPids;i++) {
-            apid *ac=&temp_channel.apids[i];
-            delete[] ac->name;
-            ac->name=NULL;
-        }
-        for (i=0;i<temp_channel.numDPids;i++) {
-            apid *ac=&temp_channel.dpids[i];
-            delete[] ac->name;
-            ac->name=NULL;
-        }
-        for (i=0;i<temp_channel.numSPids;i++) {
-            apid *ac=&temp_channel.spids[i];
-            delete[] ac->name;
-            ac->name=NULL;
-        }
-    }
-
-
-  vas->setBackgroundColour(barBlue);
-  vas->setPosition(0, barRegion.y - 120);
-
-// pal 62, ntsc 57
-
-  barVasHold = true;
-  doBar(0);
-
-  vas->draw();
-  boxstack->add(vas);
-  boxstack->update(vas);
-}
-
-void VVideoRec::doBar(int action)
-{
-  barShowing = true;
-
-  rectangle(barRegion, barBlue);
-
-  /* Work out what to display - choices:
-
-  Playing  >
-  Paused   ||
-  FFwd     >>
-  FBwd     <<
-
-  Specials, informed by parameter
-
-  Skip forward 10s    >|
-  Skip backward 10s   |<
-  Skip forward 1m     >>|
-  Skip backward 1m    |<<
-
-  */
-
-  WSymbol w;
-  TEMPADD(&w);
-  w.nextSymbol = 0;
-  w.setPosition(barRegion.x + 66, barRegion.y + 16);
-
-  UCHAR playerState = 0;
-
-  if (action)
-  {
-    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
-    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
-    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
-    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
-  }
-  else
-  {
-    playerState = player->getState();
-    if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
-    else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
-    else if (playerState == Player::S_FFWD)    w.nextSymbol = WSymbol::FFWD;
-    else if (playerState == Player::S_FBWD)    w.nextSymbol = WSymbol::FBWD;
-    else                                       w.nextSymbol = WSymbol::PLAY;
-  }
-
-  w.draw();
-
-  if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))
-  {
-    // draw blips to show how fast the scan is
-    UCHAR scanrate = player->getIScanRate();
-    if (scanrate >= 2)
-    {
-      char text[5];
-      SNPRINTF(text, 5, "%ux", scanrate);
-      drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);
-    }
-  }
-
-  drawBarClocks();
-
-  boxstack->update(this, &barRegion);
-
-  timers->cancelTimer(this, 1);
-
-
-  if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;
-  else barScanHold = false;
-
-  if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
-
-  timers->setTimerD(this, 2, 0, 200000000);
-}
-
-void VVideoRec::timercall(int clientReference)
-{
-  switch(clientReference)
-  {
-    case 1:
-    {
-      // Remove bar
-      removeBar();
-      break;
-    }
-    case 2:
-    {
-      // Update clock
-      if (!barShowing) break;
-      drawBarClocks();
-      boxstack->update(this, &barRegion);
-      
-      timers->setTimerD(this, 2, 0, 200000000);
-      break;
-    }
-  }
-}
-
-hmsf VVideoRec::framesToHMSF(ULONG frames)
-{
-  hmsf ret;
-  /* from vdr */
-  double Seconds;
-  double fps=myRec->recInfo->fps;
-  ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);
-  int s = int(Seconds);
-  ret.seconds=s % 60;
-  ret.minutes = s / 60 % 60;
-  ret.hours = s / 3600;
-
-
-  return ret;
-}
-
-void VVideoRec::drawBarClocks()
-{
-  if (barScanHold)
-  {
-    UCHAR playerState = player->getState();
-    // sticky bar is set if we are in ffwd/fbwd mode
-    // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
-    // will repaint all the bar (it will call this function again, but
-    // this section won't run because stickyBarF will then == false)
-
-    if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))
-    {
-      barScanHold = false;
-      doBar(0);
-      return; // doBar will call this function and do the rest
-    }
-  }
-
-  Log* logger = Log::getInstance();
-  logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");
-
-  // Draw RTC
-  // Blank the area first
-  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
-  char timeString[20];
-  time_t t;
-  time(&t);
-  struct tm* tms = localtime(&t);
-  strftime(timeString, 19, "%H:%M", tms);
-  drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
-
-  // Draw clocks
-
-  rectangle(clocksRegion, barBlue);
-
-  ULONG currentFrameNum = player->getCurrentFrameNum();
-  ULONG lengthFrames;
-  if (myRec->recInfo->timerEnd > time(NULL))
-  {
-    // chasing playback
-    // Work out an approximate length in frames (good to 1s...)
-    lengthFrames =(ULONG) ((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);
-  }
-  else
-  {
-    lengthFrames = player->getLengthFrames();
-  }
-
-  hmsf currentFrameHMSF = framesToHMSF(currentFrameNum);
-  hmsf lengthHMSF = framesToHMSF(lengthFrames);
-
-  char buffer[100];
-  if (currentFrameNum >= lengthFrames)
-  {
-    strcpy(buffer, "-:--:-- / -:--:--");
-  }
-  else
-  {
-    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
-    logger->log("VVideoRec", Log::DEBUG, buffer);
-  }
-
-  drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
-
-
-
-
-
-
-
-  // Draw progress bar
-  int progBarXbase = barRegion.x + 300;
-
-  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
-  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
-
-  if (currentFrameNum > lengthFrames) return;
-  if (lengthFrames == 0) return;
-
-  // Draw yellow portion
-  int progressWidth = 302 * currentFrameNum / lengthFrames;
-  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
-
-  if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
-  {
-    int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));
-
-    Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
-    Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
-    Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
-    rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);
-  }
-
-  int posPix;
-  // Now calc position for blips
-
-  if (myRec->hasMarks())
-  {
-    // Draw blips where there are cut marks
-    MarkList* markList = myRec->getMarkList();
-    MarkList::iterator i;
-    Mark* loopMark = NULL;
-
-    for(i = markList->begin(); i != markList->end(); i++)
-    {
-      loopMark = *i;
-      if (loopMark->pos)
-      {
-        logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);
-        posPix = 302 * loopMark->pos / lengthFrames;
-        rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
-      }
-    }
-  }
-  else
-  {
-    // Draw blips where start and end margins probably are
-
-         posPix =(int) (302. * myRec->recInfo->fps * ((double)startMargin) /((double) lengthFrames));
-
-    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
-    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
-
-    posPix = (int)(302. * ((double)lengthFrames - ((double)endMargin) * myRec->recInfo->fps) / ((double)lengthFrames));
-
-    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
-    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
-  }
-}
-
-void VVideoRec::removeBar()
-{
-  if (!barShowing) return;
-  timers->cancelTimer(this, 2);
-  barShowing = false;
-  barGenHold = false;
-  barScanHold = false;
-  barVasHold = false;
-  rectangle(barRegion, transparent);
-  boxstack->update(this, &barRegion);
-}
-
-void VVideoRec::doSummary()
-{
-  vsummary = new VInfo();
-  vsummary->setTitleText(myRec->getProgName());
-  vsummary->setBorderOn(1);
-  vsummary->setExitable();
-  if (myRec->recInfo->summary) vsummary->setMainText(myRec->recInfo->summary);
-  else vsummary->setMainText(tr("Summary unavailable"));
-  if (Video::getInstance()->getFormat() == Video::PAL)
-  {
-    vsummary->setPosition(120, 130);
-  }
-  else
-  {
-    vsummary->setPosition(110, 90);
-  }
-  vsummary->setSize(510, 270);
-  add(vsummary);
-  vsummary->draw();
-
-  BoxStack::getInstance()->update(this);
-}
-
-void VVideoRec::removeSummary()
-{
-  if (vsummary)
-  {
-    remove(vsummary);
-    delete vsummary;
-    vsummary = NULL;
-    draw();
-    BoxStack::getInstance()->update(this);
-  }
-}
-
-void VVideoRec::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)
-{
-  drawBitmap(posX, posY, bm);
-  Region r;
-  r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
-  boxstack->update(this, &r);
-}
-
-void VVideoRec::clearOSD()
-{
-  rectangle(area, transparent);
-  boxstack->update(this, &area);
-}
-
-void VVideoRec::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)
-{
-  Region r;
-  r.x = posX; r.y = posY; r.w = width; r.h = height;
-  rectangle(r, transparent);
-  boxstack->update(this, &r);
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include <math.h>\r
+\r
+#include "vvideorec.h"\r
+#include "vteletextview.h"\r
+\r
+#include "command.h"\r
+#include "osd.h"\r
+#include "wsymbol.h"\r
+#include "audio.h"\r
+#include "vdr.h"\r
+#include "video.h"\r
+#include "timers.h"\r
+#include "player.h"\r
+#include "recording.h"\r
+#include "vaudioselector.h"\r
+#include "message.h"\r
+#include "remote.h"\r
+#include "boxstack.h"\r
+#include "vinfo.h"\r
+#include "i18n.h"\r
+#include "bitmap.h"\r
+#include "recinfo.h"\r
+#include "log.h"\r
+#include "channel.h"\r
\r
+VVideoRec::VVideoRec(Recording* rec, bool ish264)\r
+{\r
+  boxstack = BoxStack::getInstance();\r
+  vdr = VDR::getInstance();\r
+  video = Video::getInstance();\r
+  timers = Timers::getInstance();\r
+  vas = NULL;\r
+  vsummary = NULL;\r
+\r
+  videoMode = video->getMode();\r
+  myRec = rec;\r
+\r
+  video->seth264mode(ish264);\r
+\r
+  player = new Player(Command::getInstance(), this, this);\r
+  player->init(myRec->IsPesRecording,myRec->recInfo->fps);\r
+\r
+  playing = false;\r
+\r
+  startMargin = 0;\r
+  endMargin = 0;\r
+  char* cstartMargin = vdr->configLoad("Timers", "Start margin");\r
+  char* cendMargin = vdr->configLoad("Timers", "End margin");\r
+  if (!cstartMargin)\r
+  {\r
+    startMargin = 300; // 5 mins default\r
+  }\r
+  else\r
+  {\r
+    startMargin = atoi(cstartMargin) * 60;\r
+    delete[] cstartMargin;\r
+  }\r
+\r
+  if (!cendMargin)\r
+  {\r
+    endMargin = 300; // 5 mins default\r
+  }\r
+  else\r
+  {\r
+    endMargin = atoi(cendMargin) * 60;\r
+    delete[] cendMargin;\r
+  }\r
+\r
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);\r
+\r
+  setSize(video->getScreenWidth(), video->getScreenHeight());\r
+  createBuffer();\r
+  transparent.set(0, 0, 0, 0);\r
+  setBackgroundColour(transparent);\r
+\r
+  barRegion.x = 0;\r
+  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?\r
+  barRegion.w = video->getScreenWidth();\r
+  barRegion.h = 58;\r
+\r
+  clocksRegion.x = barRegion.x + 140;\r
+  clocksRegion.y = barRegion.y + 12;\r
+  clocksRegion.w = 170;\r
+  clocksRegion.h = getFontHeight();\r
+//  barBlue.set(0, 0, 150, 150);\r
+  barBlue.set(0, 0, 0, 128);\r
+\r
+  barShowing = false;\r
+  barGenHold = false;\r
+  barScanHold = false;\r
+  barVasHold = false;\r
+\r
+  dowss = false;\r
+  char* optionWSS = vdr->configLoad("General", "WSS");\r
+  if (optionWSS)\r
+  {\r
+    if (strstr(optionWSS, "Yes")) dowss = true;\r
+    delete[] optionWSS;\r
+  }\r
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Do WSS: %u", dowss);\r
+\r
+  if (dowss)\r
+  {\r
+    wss.setFormat(video->getFormat());\r
+    wss.setWide(true);\r
+    add(&wss);\r
+\r
+    wssRegion.x = 0;\r
+    wssRegion.y = 0;\r
+    wssRegion.w = video->getScreenWidth();\r
+    wssRegion.h = 300;\r
+  }\r
+}\r
+\r
+void VVideoRec::preDelete()\r
+{\r
+  timers->cancelTimer(this, 1);\r
+  timers->cancelTimer(this, 2);\r
+\r
+  if (vas)\r
+  {\r
+    boxstack->remove(vas);\r
+    vas = NULL;\r
+  }\r
+\r
+  if (vsummary) delete vsummary;\r
+\r
+  if (playing) stopPlay();\r
+}\r
+\r
+VVideoRec::~VVideoRec()\r
+{\r
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Entering vvideorec destructor");\r
+\r
+  video->setDefaultAspect();\r
+\r
+  // kill recInfo in case resumePoint has changed (likely)\r
+  myRec->dropRecInfo();\r
+  // FIXME - do this properly - save the resume point back to the server manually and update\r
+  // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well\r
+}\r
+\r
+void VVideoRec::go(bool resume)\r
+{\r
+  ULONG startFrameNum;\r
+  if (resume)\r
+    startFrameNum = myRec->recInfo->resumePoint;\r
+  else\r
+    startFrameNum = 0;\r
+\r
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Starting stream: %s at frame: %lu", myRec->getFileName(), startFrameNum);\r
+  ULONG lengthFrames = 0;\r
+  bool isPesRecording;\r
+  ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);\r
+  myRec->IsPesRecording = isPesRecording;\r
+  if (lengthBytes)\r
+  {\r
+    player->setLengthBytes(lengthBytes);\r
+    player->setLengthFrames(lengthFrames);\r
+    player->setStartFrame(startFrameNum);\r
+    player->play();\r
+    playing = true;\r
+    doBar(0);\r
+  }\r
+  else\r
+  {\r
+    stopPlay(); // clean up\r
+\r
+    if (!vdr->isConnected())\r
+    {\r
+      Command::getInstance()->connectionLost();\r
+      return;\r
+    }\r
+\r
+    Message* m = new Message();\r
+    m->message = Message::CLOSE_ME;\r
+    m->from = this;\r
+    m->to = boxstack;\r
+    Command::getInstance()->postMessageNoLock(m);\r
+\r
+    VInfo* vi = new VInfo();\r
+    vi->setSize(400, 150);\r
+    vi->createBuffer();\r
+    if (video->getFormat() == Video::PAL)\r
+      vi->setPosition(170, 200);\r
+    else\r
+      vi->setPosition(160, 150);\r
+    vi->setExitable();\r
+    vi->setBorderOn(1);\r
+    vi->setTitleBarOn(0);\r
+    vi->setOneLiner(tr("Error playing recording"));\r
+    vi->draw();\r
+\r
+    m = new Message();\r
+    m->message = Message::ADD_VIEW;\r
+    m->to = boxstack;\r
+    m->parameter = (ULONG)vi;\r
+    Command::getInstance()->postMessageNoLock(m);\r
+  }\r
+}\r
+\r
+int VVideoRec::handleCommand(int command)\r
+{\r
+  switch(command)\r
+  {\r
+    case Remote::PLAY:\r
+    {\r
+      player->play();\r
+      doBar(0);\r
+      return 2;\r
+    }\r
+\r
+    case Remote::PLAYPAUSE:\r
+    {\r
+       player->playpause();\r
+        doBar(0);\r
+        return 2;\r
+    }\r
+\r
+    case Remote::BACK:\r
+    {\r
+      if (vsummary)\r
+      {\r
+        removeSummary();\r
+        return 2;\r
+      }\r
+    } // DROP THROUGH\r
+    case Remote::STOP:\r
+    case Remote::MENU:\r
+    {\r
+      if (playing) stopPlay();\r
+\r
+      return 4;\r
+    }\r
+    case Remote::PAUSE:\r
+    {\r
+      player->pause();\r
+      doBar(0);\r
+      return 2;\r
+    }\r
+    case Remote::SKIPFORWARD:\r
+    {\r
+      doBar(3);\r
+      player->skipForward(60);\r
+      return 2;\r
+    }\r
+    case Remote::SKIPBACK:\r
+    {\r
+      doBar(4);\r
+      player->skipBackward(60);\r
+      return 2;\r
+    }\r
+    case Remote::FORWARD:\r
+    {\r
+      player->fastForward();\r
+      doBar(0);\r
+      return 2;\r
+    }\r
+    case Remote::REVERSE:\r
+    {\r
+      player->fastBackward();\r
+      doBar(0);\r
+      return 2;\r
+    }\r
+    case Remote::RED:\r
+    {\r
+      if (vsummary) removeSummary();\r
+      else doSummary();\r
+      return 2;\r
+    }\r
+    case Remote::GREEN:\r
+    {\r
+      doAudioSelector();\r
+      return 2;\r
+    }\r
+    case Remote::YELLOW:\r
+    {\r
+      if (myRec->hasMarks())\r
+      {\r
+        // skip to previous mark\r
+        Log* logger = Log::getInstance();\r
+        int currentFrame = (player->getCurrentFrameNum()); // get current Frame\r
+        currentFrame -= 5. * myRec->recInfo->fps; // subtrack 5 seconds, else you cannot skip more than once back ..\r
+\r
+        int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame\r
+        if (prevMark)\r
+        {\r
+          logger->log("VVideoRec", Log::NOTICE, "jump back from pos %i to mark at %i",currentFrame,prevMark);\r
+          player->jumpToMark(prevMark);\r
+        }\r
+        doBar(4);\r
+      }\r
+      else\r
+      {\r
+        doBar(2);\r
+        player->skipBackward(10);\r
+      }\r
+      return 2;\r
+    }\r
+    case Remote::BLUE:\r
+    {\r
+      if (myRec->hasMarks())\r
+      {\r
+        // skip to next mark\r
+        Log* logger = Log::getInstance();\r
+        int currentFrame = (player->getCurrentFrameNum());\r
+\r
+        int nextMark = myRec->getNextMark(currentFrame);\r
+\r
+        if (nextMark)\r
+        {\r
+          logger->log("VVideoRec", Log::NOTICE, "jump forward from pos %i to mark at %i",currentFrame,nextMark);\r
+          player->jumpToMark(nextMark);\r
+        }\r
+        doBar(3);\r
+      }\r
+      else\r
+      {\r
+        doBar(1);\r
+        player->skipForward(10);\r
+      }\r
+      return 2;\r
+    }\r
+    case Remote::STAR:\r
+    {\r
+      doBar(2);\r
+      player->skipBackward(10);\r
+      return 2;\r
+    }\r
+    case Remote::HASH:\r
+    {\r
+      doBar(1);\r
+      player->skipForward(10);\r
+      return 2;\r
+    }\r
+    case Remote::FULL:\r
+    case Remote::TV:\r
+    {\r
+      toggleChopSides();\r
+      return 2;\r
+    }\r
+\r
+    case Remote::OK:\r
+    {\r
+      if (vsummary)\r
+      {\r
+        removeSummary();\r
+        return 2;\r
+      }\r
+      \r
+      if (barShowing) removeBar();\r
+      else doBar(0);\r
+      return 2;\r
+    }\r
+\r
+    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;\r
+    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;\r
+    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;\r
+    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;\r
+    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;\r
+    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;\r
+    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;\r
+    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;\r
+    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;\r
+    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;\r
+\r
+    case Remote::RECORD: player->toggleSubtitles(); return 2;\r
+#ifdef DEV\r
+//    case Remote::RED:\r
+//    {\r
+      //Don't use RED for anything. It will eventually be recording summary\r
+\r
+      //player->test1();\r
+\r
+\r
+      /*\r
+      // for testing EPG in NTSC with a NTSC test video\r
+      Video::getInstance()->setMode(Video::QUARTER);\r
+      Video::getInstance()->setPosition(170, 5);\r
+      VEpg* vepg = new VEpg(NULL, 0);\r
+      vepg->draw();\r
+      BoxStack::getInstance()->add(vepg);\r
+      BoxStack::getInstance()->update(vepg);\r
+      */\r
+\r
+//      return 2;\r
+//    }\r
+\r
+#endif\r
+\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+void VVideoRec::doTeletext()\r
+{\r
+  \r
+  bool exists=true;\r
+\r
+  \r
+  // Draw the teletxt\r
+  VTeletextView *vtxv=player->getTeletextDecoder()->getTeletxtView();\r
+  if (vtxv==NULL) {\r
+       vtxv= new VTeletextView((player)->getTeletextDecoder(),this);\r
+      (player)->getTeletextDecoder()->registerTeletextView(vtxv);\r
+      exists=false;\r
+  }\r
+  vtxv->setSubtitleMode(true);\r
+  vtxv->draw();\r
+  draw();\r
+  \r
+  if (!exists) {\r
+      BoxStack::getInstance()->add(vtxv);\r
+  }\r
+  BoxStack::getInstance()->update(this);\r
+  BoxStack::getInstance()->update(vtxv); \r
+}\r
+\r
+void VVideoRec::processMessage(Message* m)\r
+{\r
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");\r
+\r
+  if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    UINT x = (m->parameter>>16) - getScreenX();\r
+    UINT y = (m->parameter&0xFFFF) - getScreenY();\r
+\r
+    if (!barShowing)\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+    }\r
+    else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)\r
+    {\r
+      int progBarXbase = barRegion.x + 300;\r
+      if (myRec->hasMarks())\r
+      {\r
+        MarkList* markList = myRec->getMarkList();\r
+        MarkList::iterator i;\r
+        Mark* loopMark = NULL;\r
+        int posPix;\r
+        ULONG lengthFrames;\r
+        if (myRec->recInfo->timerEnd > time(NULL))\r
+        {\r
+          // chasing playback\r
+          // Work out an approximate length in frames (good to 1s...)\r
+                       lengthFrames = (ULONG)((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);\r
+        }\r
+        else\r
+        {\r
+          lengthFrames = player->getLengthFrames();\r
+        }\r
+        for(i = markList->begin(); i != markList->end(); i++)\r
+        {\r
+          loopMark = *i;\r
+          if (loopMark->pos)\r
+          {\r
+            posPix = 302 * loopMark->pos / lengthFrames;\r
+            rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);\r
+            if (x>=barRegion.x + progBarXbase + 2 + posPix\r
+                && x<=barRegion.x + progBarXbase + 2 + posPix+3\r
+                && y>=barRegion.y + 12 - 2\r
+                && y<=barRegion.y + 12 - 2+28)\r
+            {\r
+              player->jumpToMark(loopMark->pos);\r
+              doBar(3);\r
+              return;\r
+            }\r
+          }\r
+        }\r
+      }\r
+\r
+      if (x>=barRegion.x + progBarXbase + 24\r
+          && x<=barRegion.x + progBarXbase + 4 + 302\r
+          && y>=barRegion.y + 12 - 2\r
+          && y<=barRegion.y + 12 - 2+28)\r
+      {\r
+        int cx=x-(barRegion.x + progBarXbase + 4);\r
+        double percent=((double)cx)/302.*100.;\r
+        player->jumpToPercent(percent);\r
+        doBar(3);\r
+        return;\r
+        //  int progressWidth = 302 * currentFrameNum / lengthFrames;\r
+        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+      }\r
+    }\r
+    else\r
+    {\r
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
+    }\r
+  }\r
+  else if (m->from == player)\r
+  {\r
+    if (m->message != Message::PLAYER_EVENT) return;\r
+    switch(m->parameter)\r
+    {\r
+      case Player::CONNECTION_LOST: // connection lost detected\r
+      {\r
+        // I can't handle this, send it to command\r
+        Message* m2 = new Message();\r
+        m2->to = Command::getInstance();\r
+        m2->message = Message::CONNECTION_LOST;\r
+        Command::getInstance()->postMessageNoLock(m2);\r
+        break;\r
+      }\r
+      case Player::STOP_PLAYBACK:\r
+      {\r
+        // FIXME Obselete ish - improve this\r
+        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
+        m2->to = Command::getInstance();\r
+        m2->message = Message::STOP_PLAYBACK;\r
+        Command::getInstance()->postMessageNoLock(m2);\r
+        break;\r
+      }\r
+      case Player::ASPECT43:\r
+      {\r
+        if (dowss)\r
+        {\r
+          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");\r
+          wss.setWide(false);\r
+          wss.draw();\r
+          boxstack->update(this, &wssRegion);\r
+        }\r
+        break;\r
+      }\r
+      case Player::ASPECT169:\r
+      {\r
+        if (dowss)\r
+        {\r
+          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");\r
+          wss.setWide(true);\r
+          wss.draw();\r
+          boxstack->update(this, &wssRegion);\r
+        }\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)\r
+  {\r
+    Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change audio channel to %i", m->parameter);\r
+    player->setAudioChannel(m->parameter&0xFFFF,(m->parameter&0xFF0000)>> 16 );\r
+  }\r
+  else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)\r
+  {\r
+      Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);\r
+      int type=((m->parameter & 0xFF0000)>>16);\r
+      switch (type) {\r
+      case 0x10: { //dvbsubtitle\r
+          player->setSubtitleChannel((m->parameter & 0xFFFF));\r
+          player->turnSubtitlesOn(true);\r
+          VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();\r
+          if (vtxt && vtxt->isInSubtitleMode()) {\r
+              BoxStack::getInstance()->remove(vtxt);\r
+          }\r
+                 } break;\r
+      case 0xFF: { //nosubtitles\r
+          \r
+           player->turnSubtitlesOn(false);\r
+           VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();\r
+           if (vtxt && vtxt->isInSubtitleMode()) {\r
+              BoxStack::getInstance()->remove(vtxt);\r
+           }  \r
+          \r
+                 } break;\r
+      case 0x11: { //videotext\r
+          player->turnSubtitlesOn(false);\r
+          doTeletext();\r
+          ((Player*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));\r
+                 } break;\r
+      };\r
+      if (vas) {\r
+        BoxStack::getInstance()->update(vas);\r
+      }\r
+      BoxStack::getInstance()->update(this);\r
+\r
+      \r
+  } \r
+  else if (m->message == Message::CHILD_CLOSE)\r
+  {\r
+    if (m->from == vas)\r
+    {\r
+      vas = NULL;\r
+      barVasHold = false;\r
+      if (!barGenHold && !barScanHold && !barVasHold) removeBar();\r
+    }\r
+  }\r
+}\r
+\r
+void VVideoRec::stopPlay()\r
+{\r
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Pre stopPlay");\r
+\r
+  removeBar();\r
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "1");\r
+  player->stop();\r
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "2");\r
+  vdr->stopStreaming();\r
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "3");\r
+  delete player;\r
+\r
+  playing = false;\r
+\r
+  if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }\r
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Post stopPlay");\r
+}\r
+\r
+void VVideoRec::toggleChopSides()\r
+{\r
+  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs\r
+\r
+  if (videoMode == Video::NORMAL)\r
+  {\r
+    videoMode = Video::LETTERBOX;\r
+    video->setMode(Video::LETTERBOX);\r
+  }\r
+  else\r
+  {\r
+    videoMode = Video::NORMAL;\r
+    video->setMode(Video::NORMAL);\r
+  }\r
+}\r
+\r
+void VVideoRec::doAudioSelector()\r
+{\r
+    int subtitleChannel=player->getCurrentSubtitleChannel();\r
+    int subtitleType=0x10;\r
+    if (!(player)->isSubtitlesOn()) {\r
+        if ((player)->getTeletextDecoder()->getTeletxtView() &&\r
+            (player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() \r
+            ) {\r
+                subtitleChannel=(player)->getTeletextDecoder()->getPage();\r
+                subtitleType=0x11;\r
+      \r
+           } else {\r
+                subtitleType=0xFF; //turnedOff\r
+                subtitleChannel=0;\r
+          }\r
+    }\r
+    if (player->isPesRecording()) {\r
+        bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();\r
+        bool* availableAc3AudioChannels = NULL;\r
+        bool* availableSubtitleChannels = player->getDemuxerSubtitleChannels();\r
+        int *availableTTxtpages = player->getTeletxtSubtitlePages();\r
+        int currentAudioChannel = player->getCurrentAudioChannel();\r
+        if (Audio::getInstance()->supportsAc3())\r
+        {\r
+            availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();\r
+        }\r
+        \r
+        vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel,availableSubtitleChannels, availableTTxtpages,\r
+            subtitleChannel, subtitleType, myRec->recInfo);\r
+    } else {\r
+        // Draw the selector\r
+        Channel temp_channel=player->getDemuxerChannel();\r
+        RecInfo *cur_info= myRec->recInfo;\r
+        unsigned char numchan_recinfo = cur_info->numComponents;\r
+        unsigned char numchan_subtitles_siz = temp_channel.numSPids;\r
+        ULONG mp_audcounter = 0;\r
+        ULONG ac3_counter = 0;\r
+        int dvb_subcounter = 1;\r
+        \r
+        unsigned char type;\r
+        char* lang;\r
+        char* description;\r
+        int i;\r
+        for (i = 0; i < numchan_recinfo; i++)\r
+        {   \r
+            apid* ac = NULL;\r
+            type = cur_info->types[i];\r
+            lang = cur_info->languages[i];\r
+            description = cur_info->descriptions[i];\r
+            \r
+\r
+            if (cur_info->streams[i] == 2) {\r
+                switch (type)\r
+                {\r
+                case 1: //mpaudio mono\r
+                case 3: //mpaudio stereo\r
+                    if (mp_audcounter < temp_channel.numAPids) ac = &temp_channel.apids[mp_audcounter];\r
+                    \r
+                    mp_audcounter++;\r
+                    break;\r
+                case 5: //ac3\r
+                    if (ac3_counter < temp_channel.numDPids) ac = &temp_channel.dpids[ac3_counter];\r
+                    ac3_counter++;\r
+                    break;\r
+                }\r
+            } else if (cur_info->streams[i] == 3){\r
+                if (dvb_subcounter < numchan_subtitles_siz) ac = &temp_channel.spids[dvb_subcounter];\r
+            } else continue; //neither audio nor subtitle\r
+            if (ac)\r
+            {\r
+                if (description && (strlen(description) > 0))\r
+                {\r
+                    ac->name = new char[strlen(description) + 1];\r
+                    strcpy(ac->name, description);\r
+                    \r
+                } else if (lang && strlen(lang) > 0)\r
+                {\r
+                    ac->name = new char[strlen(lang) + 1];\r
+                    strcpy(ac->name, lang);\r
+                    \r
+                }\r
+            }\r
+        }\r
+        for (i=0;i<temp_channel.numAPids;i++) {\r
+            apid *ac=&temp_channel.apids[i];\r
+            if (ac->name==NULL) {\r
+                ac->name = new char[strlen(tr("unknown")) + 1];\r
+                strcpy(ac->name, tr("unknown"));\r
+            }\r
+        }\r
+        for (i=0;i<temp_channel.numDPids;i++) {\r
+            apid *ac=&temp_channel.dpids[i];\r
+            if (ac->name==NULL) {\r
+                ac->name = new char[strlen(tr("unknown")) + 1];\r
+                strcpy(ac->name, tr("unknown"));\r
+            }\r
+        }\r
+        for (i=0;i<temp_channel.numSPids;i++) {\r
+            apid *ac=&temp_channel.spids[i];\r
+            if (ac->name==NULL) {\r
+                ac->name = new char[strlen(tr("unknown")) + 1];\r
+                strcpy(ac->name, tr("unknown"));\r
+            }\r
+        }\r
+\r
+        vas = new VAudioSelector(this,&temp_channel , (player)->getCurrentAudioChannel(),\r
+            subtitleType,subtitleChannel,player->getTeletxtSubtitlePages());  \r
+         for (i=0;i<temp_channel.numAPids;i++) {\r
+            apid *ac=&temp_channel.apids[i];\r
+            delete[] ac->name;\r
+            ac->name=NULL;\r
+        }\r
+        for (i=0;i<temp_channel.numDPids;i++) {\r
+            apid *ac=&temp_channel.dpids[i];\r
+            delete[] ac->name;\r
+            ac->name=NULL;\r
+        }\r
+        for (i=0;i<temp_channel.numSPids;i++) {\r
+            apid *ac=&temp_channel.spids[i];\r
+            delete[] ac->name;\r
+            ac->name=NULL;\r
+        }\r
+    }\r
+\r
+\r
+  vas->setBackgroundColour(barBlue);\r
+  vas->setPosition(0, barRegion.y - 120);\r
+\r
+// pal 62, ntsc 57\r
+\r
+  barVasHold = true;\r
+  doBar(0);\r
+\r
+  vas->draw();\r
+  boxstack->add(vas);\r
+  boxstack->update(vas);\r
+}\r
+\r
+void VVideoRec::doBar(int action)\r
+{\r
+  barShowing = true;\r
+\r
+  rectangle(barRegion, barBlue);\r
+\r
+  /* Work out what to display - choices:\r
+\r
+  Playing  >\r
+  Paused   ||\r
+  FFwd     >>\r
+  FBwd     <<\r
+\r
+  Specials, informed by parameter\r
+\r
+  Skip forward 10s    >|\r
+  Skip backward 10s   |<\r
+  Skip forward 1m     >>|\r
+  Skip backward 1m    |<<\r
+\r
+  */\r
+\r
+  WSymbol w;\r
+  TEMPADD(&w);\r
+  w.nextSymbol = 0;\r
+  w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
+\r
+  UCHAR playerState = 0;\r
+\r
+  if (action)\r
+  {\r
+    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;\r
+    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;\r
+    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;\r
+    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;\r
+  }\r
+  else\r
+  {\r
+    playerState = player->getState();\r
+    if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;\r
+    else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;\r
+    else if (playerState == Player::S_FFWD)    w.nextSymbol = WSymbol::FFWD;\r
+    else if (playerState == Player::S_FBWD)    w.nextSymbol = WSymbol::FBWD;\r
+    else                                       w.nextSymbol = WSymbol::PLAY;\r
+  }\r
+\r
+  w.draw();\r
+\r
+  if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))\r
+  {\r
+    // draw blips to show how fast the scan is\r
+    UCHAR scanrate = player->getIScanRate();\r
+    if (scanrate >= 2)\r
+    {\r
+      char text[5];\r
+      SNPRINTF(text, 5, "%ux", scanrate);\r
+      drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);\r
+    }\r
+  }\r
+\r
+  drawBarClocks();\r
+\r
+  boxstack->update(this, &barRegion);\r
+\r
+  timers->cancelTimer(this, 1);\r
+\r
+\r
+  if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;\r
+  else barScanHold = false;\r
+\r
+  if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);\r
+\r
+  timers->setTimerD(this, 2, 0, 200000000);\r
+}\r
+\r
+void VVideoRec::timercall(int clientReference)\r
+{\r
+  switch(clientReference)\r
+  {\r
+    case 1:\r
+    {\r
+      // Remove bar\r
+      removeBar();\r
+      break;\r
+    }\r
+    case 2:\r
+    {\r
+      // Update clock\r
+      if (!barShowing) break;\r
+      drawBarClocks();\r
+      boxstack->update(this, &barRegion);\r
+      \r
+      timers->setTimerD(this, 2, 0, 200000000);\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+hmsf VVideoRec::framesToHMSF(ULONG frames)\r
+{\r
+  hmsf ret;\r
+  /* from vdr */\r
+  double Seconds;\r
+  double fps=myRec->recInfo->fps;\r
+  ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);\r
+  int s = int(Seconds);\r
+  ret.seconds=s % 60;\r
+  ret.minutes = s / 60 % 60;\r
+  ret.hours = s / 3600;\r
+\r
+\r
+  return ret;\r
+}\r
+\r
+void VVideoRec::drawBarClocks()\r
+{\r
+  if (barScanHold)\r
+  {\r
+    UCHAR playerState = player->getState();\r
+    // sticky bar is set if we are in ffwd/fbwd mode\r
+    // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which\r
+    // will repaint all the bar (it will call this function again, but\r
+    // this section won't run because stickyBarF will then == false)\r
+\r
+    if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))\r
+    {\r
+      barScanHold = false;\r
+      doBar(0);\r
+      return; // doBar will call this function and do the rest\r
+    }\r
+  }\r
+\r
+  Log* logger = Log::getInstance();\r
+  logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");\r
+\r
+  // Draw RTC\r
+  // Blank the area first\r
+  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
+  char timeString[20];\r
+  time_t t;\r
+  time(&t);\r
+  struct tm* tms = localtime(&t);\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);\r
+\r
+  // Draw clocks\r
+\r
+  rectangle(clocksRegion, barBlue);\r
+\r
+  ULONG currentFrameNum = player->getCurrentFrameNum();\r
+  ULONG lengthFrames;\r
+  if (myRec->recInfo->timerEnd > time(NULL))\r
+  {\r
+    // chasing playback\r
+    // Work out an approximate length in frames (good to 1s...)\r
+    lengthFrames =(ULONG) ((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);\r
+  }\r
+  else\r
+  {\r
+    lengthFrames = player->getLengthFrames();\r
+  }\r
+\r
+  hmsf currentFrameHMSF = framesToHMSF(currentFrameNum);\r
+  hmsf lengthHMSF = framesToHMSF(lengthFrames);\r
+\r
+  char buffer[100];\r
+  if (currentFrameNum >= lengthFrames)\r
+  {\r
+    strcpy(buffer, "-:--:-- / -:--:--");\r
+  }\r
+  else\r
+  {\r
+    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
+    logger->log("VVideoRec", Log::DEBUG, buffer);\r
+  }\r
+\r
+  drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+  // Draw progress bar\r
+  int progBarXbase = barRegion.x + 300;\r
+\r
+  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);\r
+  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
+\r
+  if (currentFrameNum > lengthFrames) return;\r
+  if (lengthFrames == 0) return;\r
+\r
+  // Draw yellow portion\r
+  int progressWidth = 302 * currentFrameNum / lengthFrames;\r
+  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);\r
+\r
+  if (myRec->recInfo->timerEnd > time(NULL)) // if chasing\r
+  {\r
+    int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));\r
+\r
+    Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);\r
+    Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());\r
+    Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);\r
+    rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);\r
+  }\r
+\r
+  int posPix;\r
+  // Now calc position for blips\r
+\r
+  if (myRec->hasMarks())\r
+  {\r
+    // Draw blips where there are cut marks\r
+    MarkList* markList = myRec->getMarkList();\r
+    MarkList::iterator i;\r
+    Mark* loopMark = NULL;\r
+\r
+    for(i = markList->begin(); i != markList->end(); i++)\r
+    {\r
+      loopMark = *i;\r
+      if (loopMark->pos)\r
+      {\r
+        logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);\r
+        posPix = 302 * loopMark->pos / lengthFrames;\r
+        rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);\r
+      }\r
+    }\r
+  }\r
+  else\r
+  {\r
+    // Draw blips where start and end margins probably are\r
+\r
+         posPix =(int) (302. * myRec->recInfo->fps * ((double)startMargin) /((double) lengthFrames));\r
+\r
+    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);\r
+    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);\r
+\r
+    posPix = (int)(302. * ((double)lengthFrames - ((double)endMargin) * myRec->recInfo->fps) / ((double)lengthFrames));\r
+\r
+    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);\r
+    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);\r
+  }\r
+}\r
+\r
+void VVideoRec::removeBar()\r
+{\r
+  if (!barShowing) return;\r
+  timers->cancelTimer(this, 2);\r
+  barShowing = false;\r
+  barGenHold = false;\r
+  barScanHold = false;\r
+  barVasHold = false;\r
+  rectangle(barRegion, transparent);\r
+  boxstack->update(this, &barRegion);\r
+}\r
+\r
+void VVideoRec::doSummary()\r
+{\r
+  vsummary = new VInfo();\r
+  vsummary->setTitleText(myRec->getProgName());\r
+  vsummary->setBorderOn(1);\r
+  vsummary->setExitable();\r
+  if (myRec->recInfo->summary) vsummary->setMainText(myRec->recInfo->summary);\r
+  else vsummary->setMainText(tr("Summary unavailable"));\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+  {\r
+    vsummary->setPosition(120, 130);\r
+  }\r
+  else\r
+  {\r
+    vsummary->setPosition(110, 90);\r
+  }\r
+  vsummary->setSize(510, 270);\r
+  add(vsummary);\r
+  vsummary->draw();\r
+\r
+  BoxStack::getInstance()->update(this);\r
+}\r
+\r
+void VVideoRec::removeSummary()\r
+{\r
+  if (vsummary)\r
+  {\r
+    remove(vsummary);\r
+    delete vsummary;\r
+    vsummary = NULL;\r
+    draw();\r
+    BoxStack::getInstance()->update(this);\r
+  }\r
+}\r
+\r
+void VVideoRec::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)\r
+{\r
+  drawBitmap(posX, posY, bm);\r
+  Region r;\r
+  r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();\r
+  boxstack->update(this, &r);\r
+}\r
+\r
+void VVideoRec::clearOSD()\r
+{\r
+  rectangle(area, transparent);\r
+  boxstack->update(this, &area);\r
+}\r
+\r
+void VVideoRec::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)\r
+{\r
+  Region r;\r
+  r.x = posX; r.y = posY; r.w = width; r.h = height;\r
+  rectangle(r, transparent);\r
+  boxstack->update(this, &r);\r
+}\r
index 3f927930ddb1979b7eb2cb7733921ff1cf5b6c2d..cb88da6c99e5a15a541241946afda39918194f7d 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "vwelcome.h"
-
-#include "remote.h"
-#include "vdr.h"
-#include "vchannellist.h"
-#include "vrecordinglist.h"
-#include "vtimerlist.h"
-#include "command.h"
-#include "message.h"
-#include "colour.h"
-#include "video.h"
-#include "i18n.h"
-#include "timers.h"
-#include "vscreensaver.h"
-#include "vmedialist.h"
-#include "boxstack.h"
-#include "vopts.h"
-
-VWelcome::VWelcome()
-{
-  boxstack = BoxStack::getInstance();
-
-  clockRegion.x = 400;
-  clockRegion.y = 0;
-  clockRegion.w = 60;
-  clockRegion.h = 30;
-
-  setSize(460, 220);
-  createBuffer();
-  if (Video::getInstance()->getFormat() == Video::PAL)
-  {
-    setPosition(140, 170);
-  }
-  else
-  {
-    setPosition(130, 140);
-  }
-
-  setTitleBarOn(1);
-  setTitleBarColour(Colour::TITLEBARBACKGROUND);
-
-  sl.setPosition(20, 40);
-  sl.setSize(200, 160);
-  add(&sl);
-
-  setTitleText(tr("Welcome"));
-  sl.addOption(tr("1. Live TV"), 1, 1);
-  sl.addOption(tr("2. Radio"), 2, 0);
-  sl.addOption(tr("3. Recordings"), 3, 0);
-  sl.addOption(tr("4. Timers"), 4, 0);
-#ifndef _MIPS_ARCH 
-#ifndef WIN32 
-  sl.addOption(tr("5. MediaPlayer"), 5, 0);
-#endif
-#endif
-  sl.addOption(tr("6. Options"), 6, 0);
-#ifndef _MIPS_ARCH
-  sl.addOption(tr("7. Reboot"), 7, 0);
-#else
-    sl.addOption(tr("7. Exit to Gaya"), 7, 0);
-#endif
-
-  jpeg.setPosition(240, 60);
-#ifndef _MIPS_ARCH  
-  jpeg.init("/vdr.jpg");
-#else
-  jpeg.init("vdr.jpg");
-#endif
-  add(&jpeg);
-}
-
-void VWelcome::preDelete()
-{
-  Timers::getInstance()->cancelTimer(this, 1);
-}
-
-VWelcome::~VWelcome()
-{
-}
-
-void VWelcome::draw()
-{
-  TBBoxx::draw();
-  drawClock();
-}
-
-void VWelcome::drawClock()
-{
-  // Blank the area first
-  rectangle(area.w - 60, 0, 60, 30, titleBarColour);
-
-  char timeString[20];
-  time_t t;
-  time(&t);
-  struct tm* tms = localtime(&t);
-  strftime(timeString, 19, "%H:%M", tms);
-  drawTextRJ(timeString, 450, 5, Colour::LIGHTTEXT);
-
-  time_t dt = 60 - (t % 60);  // seconds to the next minute
-  if (dt == 0) dt = 60; // advance a whole minute if necessary
-  dt += t;  // get a time_t value for it rather than using duration
-  // (so it will occur at the actual second and not second and a half)
-
-  Timers::getInstance()->setTimerT(this, 1, dt);
-}
-
-void VWelcome::timercall(int clientReference)
-{
-  drawClock();
-  boxstack->update(this, &clockRegion);
-}
-
-int VWelcome::handleCommand(int command)
-{
-  switch(command)
-  {
-    case Remote::DF_UP:
-    case Remote::UP:
-    {
-      sl.up();
-      sl.draw();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::DF_DOWN:
-    case Remote::DOWN:
-    {
-      sl.down();
-      sl.draw();
-      boxstack->update(this);
-      return 2;
-    }
-    case Remote::ONE:
-    {
-      doChannelsList();
-      return 2;
-    }
-    case Remote::TWO:
-    {
-      doRadioList();
-      return 2;
-    }
-    case Remote::THREE:
-    {
-      doRecordingsList();
-      return 2;
-    }
-    case Remote::FOUR:
-    {
-      doTimersList();
-      return 2;
-    }
-    case Remote::FIVE:
-    {
-      doMediaList();
-      return 2;
-    }
-    case Remote::SIX:
-    {
-      doOptions();
-      return 2;
-    }
-    case Remote::SEVEN:
-    {
-      Command::getInstance()->doReboot();
-    }
-    case Remote::OK:
-    {
-      ULONG option = sl.getCurrentOptionData();
-      if (option == 1)
-      {
-        doChannelsList();
-        return 2;
-      }
-      else if (option == 2)
-      {
-        doRadioList();
-        return 2;
-      }
-      else if (option == 3)
-      {
-        doRecordingsList();
-        return 2;
-      }
-      else if (option == 4)
-      {
-        doTimersList();
-        return 2;
-      }
-      else if (option == 5)
-      {
-        doMediaList();
-        return 2;
-      }
-      else if (option == 6)
-      {
-        doOptions();
-        return 2;
-      }
-      else if (option == 7)
-      {
-        Command::getInstance()->doReboot();
-        return 2;
-      }
-      return 2; // never gets here
-    }
-//#ifdef DEV
-    case Remote::NINE:
-    {
-      VScreensaver* vscreensaver = new VScreensaver();
-      boxstack->add(vscreensaver);
-      vscreensaver->draw();
-//      boxstack->update(vscreensaver);
-
-      return 2;
-    }
-//#endif
-
-    // Test
-//    case Remote::BACK:
-//    {
-//      return 4;
-//    }
-
-  }
-  return 1;
-}
-
-void VWelcome::doChannelsList()
-{
-  ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO);
-
-  if (chanList)
-  {
-    VChannelList* vchan = new VChannelList(VDR::VIDEO);
-    vchan->setList(chanList);
-
-    vchan->draw();
-    boxstack->add(vchan);
-    boxstack->update(vchan);
-  }
-  else
-  {
-    Command::getInstance()->connectionLost();
-  }
-}
-
-void VWelcome::doRadioList()
-{
-  ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::RADIO);
-
-  if (chanList)
-  {
-    VChannelList* vchan = new VChannelList(VDR::RADIO);
-    vchan->setList(chanList);
-
-    vchan->draw();
-    boxstack->add(vchan);
-    boxstack->update(vchan);
-  }
-  else
-  {
-    Command::getInstance()->connectionLost();
-  }
-}
-
-void VWelcome::doRecordingsList()
-{
-  VRecordingList* vrec = new VRecordingList();
-  vrec->draw();
-  boxstack->add(vrec);
-  boxstack->update(vrec);
-
-  if (!vrec->load())
-  {
-    Command::getInstance()->connectionLost();
-  }
-}
-
-void VWelcome::doMediaList()
-{
-  VMediaList::createList();
-}
-
-void VWelcome::doTimersList()
-{
-  VTimerList* vtl = new VTimerList();
-  if (!vtl->load())
-  {
-    delete vtl;
-    Command::getInstance()->connectionLost();
-    return;
-  }
-  
-  vtl->draw();
-  boxstack->add(vtl);
-  boxstack->update(vtl);
-}
-
-void VWelcome::doOptions()
-{
-//  VOptionsMenu* voptionsmenu = new VOptionsMenu();
-//  voptionsmenu->draw();
-//  boxstack->add(voptionsmenu);
-//  boxstack->updateView(voptionsmenu);
-
-  VOpts* vopts = new VOpts();
-  vopts->draw();
-  boxstack->add(vopts);
-  boxstack->update(vopts);
-}
-
-void VWelcome::processMessage(Message* m)
-{
-  if (m->message == Message::MOUSE_MOVE)
-  {
-    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      sl.draw();
-      boxstack->update(this);
-    }
-  }
-  else if (m->message == Message::MOUSE_LBDOWN)
-  {
-    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      boxstack->handleCommand(Remote::OK); //simulate OK press
-    }
-  }
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "vwelcome.h"\r
+\r
+#include "remote.h"\r
+#include "vdr.h"\r
+#include "vchannellist.h"\r
+#include "vrecordinglist.h"\r
+#include "vtimerlist.h"\r
+#include "command.h"\r
+#include "message.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "i18n.h"\r
+#include "timers.h"\r
+#include "vscreensaver.h"\r
+#include "vmedialist.h"\r
+#include "boxstack.h"\r
+#include "vopts.h"\r
+\r
+#include "log.h"\r
+\r
+VWelcome::VWelcome()\r
+{\r
+  boxstack = BoxStack::getInstance();\r
+\r
+  clockRegion.x = 400;\r
+  clockRegion.y = 0;\r
+  clockRegion.w = 60;\r
+  clockRegion.h = 30;\r
+\r
+  setSize(460, 220);\r
+  createBuffer();\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+  {\r
+    setPosition(140, 170);\r
+  }\r
+  else\r
+  {\r
+    setPosition(130, 140);\r
+  }\r
+\r
+  setTitleBarOn(1);\r
+  setTitleBarColour(Colour::TITLEBARBACKGROUND);\r
+\r
+  sl.setPosition(20, 40);\r
+  sl.setSize(200, 160);\r
+  add(&sl);\r
+\r
+  setTitleText(tr("Welcome"));\r
+  sl.addOption(tr("1. Live TV"), 1, 1);\r
+  sl.addOption(tr("2. Radio"), 2, 0);\r
+  sl.addOption(tr("3. Recordings"), 3, 0);\r
+  sl.addOption(tr("4. Timers"), 4, 0);\r
+#ifdef VOMP_PLATTFORM_MVP\r
+  sl.addOption(tr("5. MediaPlayer"), 5, 0);\r
+#endif\r
+\r
+  sl.addOption(tr("6. Options"), 6, 0);\r
+#ifdef VOMP_PLATTFORM_MVP\r
+  sl.addOption(tr("7. Reboot"), 7, 0);\r
+#else\r
+    sl.addOption(tr("7. Exit"), 7, 0);\r
+#endif\r
+\r
+  jpeg.setPosition(240, 60);\r
+#ifndef _MIPS_ARCH  \r
+  jpeg.init("/vdr.jpg");\r
+#else\r
+  jpeg.init("vdr.jpg");\r
+#endif\r
+  add(&jpeg);\r
+}\r
+\r
+void VWelcome::preDelete()\r
+{\r
+  Timers::getInstance()->cancelTimer(this, 1);\r
+}\r
+\r
+VWelcome::~VWelcome()\r
+{\r
+}\r
+\r
+void VWelcome::draw()\r
+{\r
+  Log::getInstance()->log("VWelcome", Log::DEBUG, "Mark1");\r
+  TBBoxx::draw();\r
+  Log::getInstance()->log("VWelcome", Log::DEBUG, "Mark2");\r
+  drawClock();\r
+  Log::getInstance()->log("VWelcome", Log::DEBUG, "Mark3");\r
+}\r
+\r
+void VWelcome::drawClock()\r
+{\r
+  // Blank the area first\r
+  rectangle(area.w - 60, 0, 60, 30, titleBarColour);\r
+\r
+  char timeString[20];\r
+  time_t t;\r
+  time(&t);\r
+  struct tm* tms = localtime(&t);\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  drawTextRJ(timeString, 450, 5, Colour::LIGHTTEXT);\r
+\r
+  time_t dt = 60 - (t % 60);  // seconds to the next minute\r
+  if (dt == 0) dt = 60; // advance a whole minute if necessary\r
+  dt += t;  // get a time_t value for it rather than using duration\r
+  // (so it will occur at the actual second and not second and a half)\r
+\r
+  Timers::getInstance()->setTimerT(this, 1, dt);\r
+}\r
+\r
+void VWelcome::timercall(int clientReference)\r
+{\r
+  drawClock();\r
+  boxstack->update(this, &clockRegion);\r
+}\r
+\r
+int VWelcome::handleCommand(int command)\r
+{\r
+  switch(command)\r
+  {\r
+    case Remote::DF_UP:\r
+    case Remote::UP:\r
+    {\r
+      sl.up();\r
+      sl.draw();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::DF_DOWN:\r
+    case Remote::DOWN:\r
+    {\r
+      sl.down();\r
+      sl.draw();\r
+      boxstack->update(this);\r
+      return 2;\r
+    }\r
+    case Remote::ONE:\r
+    {\r
+      doChannelsList();\r
+      return 2;\r
+    }\r
+    case Remote::TWO:\r
+    {\r
+      doRadioList();\r
+      return 2;\r
+    }\r
+    case Remote::THREE:\r
+    {\r
+      doRecordingsList();\r
+      return 2;\r
+    }\r
+    case Remote::FOUR:\r
+    {\r
+      doTimersList();\r
+      return 2;\r
+    }\r
+    case Remote::FIVE:\r
+    {\r
+#ifdef VOMP_PLATTFORM_MVP\r
+      doMediaList();\r
+#endif\r
+      return 2;\r
+    }\r
+    case Remote::SIX:\r
+    {\r
+      doOptions();\r
+      return 2;\r
+    }\r
+    case Remote::SEVEN:\r
+    {\r
+      Command::getInstance()->doReboot();\r
+    }\r
+    case Remote::OK:\r
+    {\r
+      ULONG option = sl.getCurrentOptionData();\r
+      if (option == 1)\r
+      {\r
+        doChannelsList();\r
+        return 2;\r
+      }\r
+      else if (option == 2)\r
+      {\r
+        doRadioList();\r
+        return 2;\r
+      }\r
+      else if (option == 3)\r
+      {\r
+        doRecordingsList();\r
+        return 2;\r
+      }\r
+      else if (option == 4)\r
+      {\r
+        doTimersList();\r
+        return 2;\r
+      }\r
+      else if (option == 5)\r
+      {\r
+        doMediaList();\r
+        return 2;\r
+      }\r
+      else if (option == 6)\r
+      {\r
+        doOptions();\r
+        return 2;\r
+      }\r
+      else if (option == 7)\r
+      {\r
+        Command::getInstance()->doReboot();\r
+        return 2;\r
+      }\r
+      return 2; // never gets here\r
+    }\r
+//#ifdef DEV\r
+    case Remote::NINE:\r
+    {\r
+      VScreensaver* vscreensaver = new VScreensaver();\r
+      boxstack->add(vscreensaver);\r
+      vscreensaver->draw();\r
+//      boxstack->update(vscreensaver);\r
+\r
+      return 2;\r
+    }\r
+//#endif\r
+\r
+    // Test\r
+//    case Remote::BACK:\r
+//    {\r
+//      return 4;\r
+//    }\r
+\r
+  }\r
+  return 1;\r
+}\r
+\r
+void VWelcome::doChannelsList()\r
+{\r
+  ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO);\r
+\r
+  if (chanList)\r
+  {\r
+    VChannelList* vchan = new VChannelList(VDR::VIDEO);\r
+    vchan->setList(chanList);\r
+\r
+    vchan->draw();\r
+    boxstack->add(vchan);\r
+    boxstack->update(vchan);\r
+  }\r
+  else\r
+  {\r
+    Command::getInstance()->connectionLost();\r
+  }\r
+}\r
+\r
+void VWelcome::doRadioList()\r
+{\r
+  ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::RADIO);\r
+\r
+  if (chanList)\r
+  {\r
+    VChannelList* vchan = new VChannelList(VDR::RADIO);\r
+    vchan->setList(chanList);\r
+\r
+    vchan->draw();\r
+    boxstack->add(vchan);\r
+    boxstack->update(vchan);\r
+  }\r
+  else\r
+  {\r
+    Command::getInstance()->connectionLost();\r
+  }\r
+}\r
+\r
+void VWelcome::doRecordingsList()\r
+{\r
+  VRecordingList* vrec = new VRecordingList();\r
+  vrec->draw();\r
+  boxstack->add(vrec);\r
+  boxstack->update(vrec);\r
+\r
+  if (!vrec->load())\r
+  {\r
+    Command::getInstance()->connectionLost();\r
+  }\r
+}\r
+\r
+void VWelcome::doMediaList()\r
+{\r
+#ifdef VOMP_MEDIAPLAYER\r
+  VMediaList::createList();\r
+#endif\r
+}\r
+\r
+void VWelcome::doTimersList()\r
+{\r
+  VTimerList* vtl = new VTimerList();\r
+  if (!vtl->load())\r
+  {\r
+    delete vtl;\r
+    Command::getInstance()->connectionLost();\r
+    return;\r
+  }\r
+  \r
+  vtl->draw();\r
+  boxstack->add(vtl);\r
+  boxstack->update(vtl);\r
+}\r
+\r
+void VWelcome::doOptions()\r
+{\r
+//  VOptionsMenu* voptionsmenu = new VOptionsMenu();\r
+//  voptionsmenu->draw();\r
+//  boxstack->add(voptionsmenu);\r
+//  boxstack->updateView(voptionsmenu);\r
+\r
+  VOpts* vopts = new VOpts();\r
+  vopts->draw();\r
+  boxstack->add(vopts);\r
+  boxstack->update(vopts);\r
+}\r
+\r
+void VWelcome::processMessage(Message* m)\r
+{\r
+  if (m->message == Message::MOUSE_MOVE)\r
+  {\r
+    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      sl.draw();\r
+      boxstack->update(this);\r
+    }\r
+  }\r
+  else if (m->message == Message::MOUSE_LBDOWN)\r
+  {\r
+    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
+    {\r
+      boxstack->handleCommand(Remote::OK); //simulate OK press\r
+    }\r
+  }\r
+}\r
index 90cf754debe29228e14470304aac15977e16560a..88e1fcb1670e0d5ef01be73e7856ef1445e0ab28 100644 (file)
@@ -29,6 +29,7 @@
 #include "wselectlist.h"
 #include "wjpeg.h"
 #include "region.h"
+#include "defines.h"
 
 class Message;
 class BoxStack;
@@ -48,7 +49,7 @@ class VWelcome : public TBBoxx, public TimerReceiver
 
   private:
     WSelectList sl;
-    WJpeg jpeg;
+    WJpegTYPE jpeg;
 
     BoxStack* boxstack;
 
index 7340cf147d8873ea8f4d66e1daee3820aabad343..5f4a6fc6f2b8ac4abf71c80f6bfb015972a90258 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "wbutton.h"
-
-#include "colour.h"
-
-WButton::WButton()
-{
-  int fontHeight = Surface::getFontHeight();
-  setSize(70, fontHeight);
-
-  mytext = NULL;
-  active = 0;
-  tag = 0;
-  dimmed = false;
-}
-
-WButton::~WButton()
-{
-  if (mytext) delete[] mytext;
-}
-
-void WButton::setText(const char* takeText)
-{
-  int length = strlen(takeText);
-  mytext = new char[length + 1];
-  strcpy(mytext, takeText);
-}
-
-void WButton::setActive(UCHAR tactive)
-{
-  dimmed = false;
-  active = tactive;
-}
-
-void WButton::dim()
-{
-  // a bolt on for now - an active but dimmed state
-  dimmed = true;
-  active = false;
-}
-
-void WButton::draw()
-{
-  if (dimmed)
-  {
-    fillColour(Colour::BLACK);
-    drawTextCentre(mytext, area.w / 2, 0, Colour::SELECTHIGHLIGHT);
-  }
-  else if (active)
-  {
-    fillColour(Colour::SELECTHIGHLIGHT);
-    drawTextCentre(mytext, area.w / 2, 0, Colour::DARKTEXT);
-  }
-  else
-  {
-    fillColour(Colour::BUTTONBACKGROUND);
-    drawTextCentre(mytext, area.w / 2, 0, Colour::LIGHTTEXT);
-  }
-}
-
-void WButton::setTag(int newTag)
-{
-  tag = newTag;
-}
-
-int WButton::getTag()
-{
-  return tag;
-}
-
-// Sorry, I've broken these in the boxx upgrade - chris
-
-bool WButton::mouseMove(int x, int y)
-{
-  if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0
-    && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && !active)
-  {
-    setActive(1);
-    return true;
-  }
-  return false;
-}
-
-bool WButton::mouseLBDOWN(int x, int y)
-{
-  if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0
-    && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && active)
-  {
-    return true;
-  }
-  return false;
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "wbutton.h"\r
+\r
+#include "colour.h"\r
+\r
+WButton::WButton()\r
+{\r
+\r
+  setSize(70, 21/*fontHeight*/);\r
+\r
+  mytext = NULL;\r
+  active = 0;\r
+  tag = 0;\r
+  dimmed = false;\r
+}\r
+\r
+WButton::~WButton()\r
+{\r
+  if (mytext) delete[] mytext;\r
+}\r
+\r
+void WButton::setText(const char* takeText)\r
+{\r
+  int length = strlen(takeText);\r
+  mytext = new char[length + 1];\r
+  strcpy(mytext, takeText);\r
+}\r
+\r
+void WButton::setActive(UCHAR tactive)\r
+{\r
+  dimmed = false;\r
+  active = tactive;\r
+}\r
+\r
+void WButton::dim()\r
+{\r
+  // a bolt on for now - an active but dimmed state\r
+  dimmed = true;\r
+  active = false;\r
+}\r
+\r
+void WButton::draw()\r
+{\r
+  if (dimmed)\r
+  {\r
+    fillColour(Colour::BLACK);\r
+    drawTextCentre(mytext, area.w / 2, 0, Colour::SELECTHIGHLIGHT);\r
+  }\r
+  else if (active)\r
+  {\r
+    fillColour(Colour::SELECTHIGHLIGHT);\r
+    drawTextCentre(mytext, area.w / 2, 0, Colour::DARKTEXT);\r
+  }\r
+  else\r
+  {\r
+    fillColour(Colour::BUTTONBACKGROUND);\r
+    drawTextCentre(mytext, area.w / 2, 0, Colour::LIGHTTEXT);\r
+  }\r
+}\r
+\r
+void WButton::setTag(int newTag)\r
+{\r
+  tag = newTag;\r
+}\r
+\r
+int WButton::getTag()\r
+{\r
+  return tag;\r
+}\r
+\r
+// Sorry, I've broken these in the boxx upgrade - chris\r
+\r
+bool WButton::mouseMove(int x, int y)\r
+{\r
+  if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0\r
+    && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && !active)\r
+  {\r
+    setActive(1);\r
+    return true;\r
+  }\r
+  return false;\r
+}\r
+\r
+bool WButton::mouseLBDOWN(int x, int y)\r
+{\r
+  if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0\r
+    && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && active)\r
+  {\r
+    return true;\r
+  }\r
+  return false;\r
+}\r
index 35febac5628a552f9d8e366d6e95246527b8c6d3..7e0b7caa3f25204a73ef2cdd420db6b2abdeee1f 100644 (file)
--- a/wbutton.h
+++ b/wbutton.h
@@ -31,7 +31,7 @@ class WButton : public Boxx
 {
   public:
     WButton();
-    ~WButton();
+    virtual ~WButton();
     void setText(const char* text);
     void setActive(UCHAR tactive);
     void dim();
index 2d6b387493ca3622e192a90c075a7e369d2a309d..6e0993b1d60e2fd43d588f53a717fad106ace529 100644 (file)
--- a/wjpeg.cc
+++ b/wjpeg.cc
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-#include "boxx.h"
-#include "wjpeg.h"
-#include <setjmp.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifndef WIN32
-#include <unistd.h>
-#else
-
-#endif
-
-#include "i18n.h"
-#include "log.h"
-#include "surface.h"
-extern "C"
-{
-  #include <jpeglib.h>
-}
-
-
-//#define USE_BUFFER
-//#define EXTENDED_JPEGLIB
-
-//a struct to store user data for the jpeg decompressor
-class jpegUserData{
-  public:
-    WJpeg::JpegControl * ctl;
-    JpegReader *reader;
-    jpegUserData() {
-      ctl=NULL;
-      reader=NULL;
-      }
-  };
-
-//the scale factors supported by the jpeg lib
-
-struct scale{
-  UINT num;
-  UINT denom;
-};
-
-
-struct scale jpegFactors[]={
-#ifndef EXTENDED_JPEGLIB
-  {1,1},{1,2},{1,4},{1,8}
-#else
-  {1,1},{7,8},{3,4},{5,8},{1,2},{3,8},{1,4},{1,8}
-#endif
-};
-  
-
-#ifdef WIN32
-#define LocalReader WindowsResourceJpegReader
-class WindowsResourceJpegReader: public JpegReader {
-  public:
-  virtual ULONG initRead(const char *filename);
-  virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
-  virtual ULONG getSize();
-  virtual ~WindowsResourceJpegReader();
-protected:
-  HGLOBAL hres;
-  LPVOID buffer;
-  DWORD size;
-};
-
-ULONG WindowsResourceJpegReader::initRead(const char *filename)
-{
-    HRSRC res=FindResource(NULL,filename,RT_RCDATA);
-    hres=LoadResource(NULL,res);
-    buffer=LockResource(hres);
-    size=SizeofResource(NULL,res);
-    //CloseHandle(hres);
-    return size;
-}
-
- ULONG WindowsResourceJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
-{
-    if (offset>size) return 0;
-    ULONG toread=min(size-offset,len);
-    char* buffy=(char*)malloc(toread);
-    memcpy(buffy,((char*)buffer)+offset,toread);
-    *buf=buffy;
-    return toread;
-}
-
- WindowsResourceJpegReader::~WindowsResourceJpegReader(){
-    buffer=NULL;
-    size=0;
-    FreeResource(hres);
- }
-
- ULONG WindowsResourceJpegReader::getSize(){
-   return (ULONG)size;
-}
-#else
-
-#define LocalReader LocalJpegReader
-class LocalJpegReader: public JpegReader {
-  public:
-  virtual ULONG initRead(const char *filename);
-  virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
-  virtual ~LocalJpegReader();
-  virtual ULONG getSize();
-  LocalJpegReader();
-protected:
-  FILE *file;
-  ULONG size;
-};
-
-LocalJpegReader::LocalJpegReader(){
-  file=NULL;
-  size=0;
-}
-
-ULONG LocalJpegReader::initRead(const char *filename)
-{
-    if (file) fclose(file);
-    size=0;
-    file=fopen(filename,"r");
-    if (file) {
-      struct stat st;
-      if (fstat(fileno(file), &st) != 0) return 0;
-      size= st.st_size;
-      return size;
-    }
-    Log::getInstance()->log("WJepg", Log::ERR, "localReader unable to open File %s", filename);
-    return 0;
-}
-
-ULONG LocalJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
-{
-   *buf=NULL;
-   ULONG bread=0;
-   if (file) {
-     ULLONG cpos=ftell(file);
-     if (offset != cpos) {
-      fseek(file,offset-cpos,SEEK_CUR);
-     }
-     if (offset != (ULONG)ftell(file)) {
-       Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
-     }
-     else {
-       *buf=(char *)malloc(len);
-       if ( ! (*buf)) {
-         Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
-       }
-       else {
-         bread=fread(*buf,1,len,file);
-       }
-     }
-   }
-   return bread;
-}
-
-LocalJpegReader::~LocalJpegReader(){
-  if (file) fclose(file);
-  file=NULL;
-}
-ULONG LocalJpegReader::getSize(){
-  return size;
-}
-#endif
-
-/*----------------------------------------------------------------
-  the jpeg lib routines
-  ----------------------------------------------------------------
- */
-
-extern "C" {
-
-
-struct my_error_mgr {
-  struct jpeg_error_mgr pub;    /* "public" fields */
-
-  jmp_buf setjmp_buffer;        /* for return to caller */
-};
-
-typedef struct my_error_mgr * my_error_ptr;
-
-/*
- * Here's the routine that will replace the standard error_exit method:
- */
-
-METHODDEF(void)
-my_error_exit (j_common_ptr cinfo)
-{
-  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
-  my_error_ptr myerr = (my_error_ptr) cinfo->err;
-
-  /* Always display the message. */
-  /* We could postpone this until after returning, if we chose. */
-  (*cinfo->err->output_message) (cinfo);
-  /* Return control to the setjmp point */
-  longjmp(myerr->setjmp_buffer, 1);
-}
-
-ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {
-  jpegUserData *user=(jpegUserData *)cb;
-  return user->reader->readChunk(offset,size,buf);
-}
-//the memory buffer reader for the jpeg lib
-//taken from jdatasrc.c
-
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jerror.h"
-
-
-typedef struct {
-  struct jpeg_source_mgr pub;   /* public fields */
-
-  JOCTET * buffer;              /* start of buffer */
-  boolean start_of_file;        /* have we gotten any data yet? */
-  void * userdata;              /* used for callback */
-  ULONG offset;
-} my_source_mgr;
-
-typedef my_source_mgr * my_src_ptr;
-
-#define INPUT_BUF_SIZE  (64*4096)       /* choose an efficiently fread'able size */
-
-
-/*
- * Initialize source --- called by jpeg_read_header
- * before any data is actually read.
- */
-
-METHODDEF(void)
-linit_source (j_decompress_ptr cinfo)
-{
-  my_src_ptr src = (my_src_ptr) cinfo->src;
-
-  /* We reset the empty-input-file flag for each image,
-   * but we don't clear the input buffer.
-   * This is correct behavior for reading a series of images from one source.
-   */
-  src->start_of_file = TRUE;
-  src->offset=0;
-}
-
-
-/*
- * Fill the input buffer --- called whenever buffer is emptied.
- *
- * In typical applications, this should read fresh data into the buffer
- * (ignoring the current state of next_input_byte & bytes_in_buffer),
- * reset the pointer & count to the start of the buffer, and return TRUE
- * indicating that the buffer has been reloaded.  It is not necessary to
- * fill the buffer entirely, only to obtain at least one more byte.
- *
- * There is no such thing as an EOF return.  If the end of the file has been
- * reached, the routine has a choice of ERREXIT() or inserting fake data into
- * the buffer.  In most cases, generating a warning message and inserting a
- * fake EOI marker is the best course of action --- this will allow the
- * decompressor to output however much of the image is there.  However,
- * the resulting error message is misleading if the real problem is an empty
- * input file, so we handle that case specially.
- *
- * In applications that need to be able to suspend compression due to input
- * not being available yet, a FALSE return indicates that no more data can be
- * obtained right now, but more may be forthcoming later.  In this situation,
- * the decompressor will return to its caller (with an indication of the
- * number of scanlines it has read, if any).  The application should resume
- * decompression after it has loaded more data into the input buffer.  Note
- * that there are substantial restrictions on the use of suspension --- see
- * the documentation.
- *
- * When suspending, the decompressor will back up to a convenient restart point
- * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
- * indicate where the restart point will be if the current call returns FALSE.
- * Data beyond this point must be rescanned after resumption, so move it to
- * the front of the buffer rather than discarding it.
- */
-
-METHODDEF(boolean)
-lfill_input_buffer (j_decompress_ptr cinfo)
-{
-  my_src_ptr src = (my_src_ptr) cinfo->src;
-  size_t nbytes;
-  if (src->buffer) free(src->buffer);
-  src->buffer=NULL;
-  nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);
-
-  if (nbytes <= 0) {
-    WARNMS(cinfo, JWRN_JPEG_EOF);
-    src->buffer =  (JOCTET *)malloc(2);
-    src->buffer[0] = (JOCTET) 0xFF;
-    src->buffer[1] = (JOCTET) JPEG_EOI;
-    nbytes = 2;
-
-  }
-  src->offset+=nbytes;
-
-  src->pub.next_input_byte = src->buffer;
-  src->pub.bytes_in_buffer = nbytes;
-  src->start_of_file = FALSE;
-
-  return TRUE;
-}
-
-
-/*
- * Skip data --- used to skip over a potentially large amount of
- * uninteresting data (such as an APPn marker).
- *
- * Writers of suspendable-input applications must note that skip_input_data
- * is not granted the right to give a suspension return.  If the skip extends
- * beyond the data currently in the buffer, the buffer can be marked empty so
- * that the next read will cause a fill_input_buffer call that can suspend.
- * Arranging for additional bytes to be discarded before reloading the input
- * buffer is the application writer's problem.
- */
-
-METHODDEF(void)
-lskip_input_data (j_decompress_ptr cinfo, long num_bytes)
-{
-  my_src_ptr src = (my_src_ptr) cinfo->src;
-
-  /* Just a dumb implementation for now.  Could use fseek() except
-   * it doesn't work on pipes.  Not clear that being smart is worth
-   * any trouble anyway --- large skips are infrequent.
-   */
-  if (num_bytes > 0) {
-    while (num_bytes > (long) src->pub.bytes_in_buffer) {
-      num_bytes -= (long) src->pub.bytes_in_buffer;
-      (void) lfill_input_buffer(cinfo);
-      /* note we assume that fill_input_buffer will never return FALSE,
-       * so suspension need not be handled.
-       */
-    }
-    src->pub.next_input_byte += (size_t) num_bytes;
-    src->pub.bytes_in_buffer -= (size_t) num_bytes;
-  }
-}
-
-
-/*
- * An additional method that can be provided by data source modules is the
- * resync_to_restart method for error recovery in the presence of RST markers.
- * For the moment, this source module just uses the default resync method
- * provided by the JPEG library.  That method assumes that no backtracking
- * is possible.
- */
-
-
-/*
- * Terminate source --- called by jpeg_finish_decompress
- * after all data has been read.  Often a no-op.
- *
- * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
- * application must deal with any cleanup that should happen even
- * for error exit.
- */
-
-METHODDEF(void)
-lterm_source (j_decompress_ptr cinfo)
-{
-  /* no work necessary here */
-}
-
-
-/*
- * Prepare for input from a stdio stream.
- * The caller must have already opened the stream, and is responsible
- * for closing it after finishing decompression.
- */
-
-extern "C" void
-jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)
-{
-  my_src_ptr src;
-
-  /* The source object and input buffer are made permanent so that a series
-   * of JPEG images can be read from the same file by calling jpeg_stdio_src
-   * only before the first one.  (If we discarded the buffer at the end of
-   * one image, we'd likely lose the start of the next one.)
-   * This makes it unsafe to use this manager and a different source
-   * manager serially with the same JPEG object.  Caveat programmer.
-   */
-  if (cinfo->src == NULL) {     /* first time for this JPEG object? */
-    cinfo->src = (struct jpeg_source_mgr *)
-      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
-                                  SIZEOF(my_source_mgr));
-    src = (my_src_ptr) cinfo->src;
-    src->buffer = NULL;
-  }
-
-  src = (my_src_ptr) cinfo->src;
-  src->pub.init_source = linit_source;
-  src->pub.fill_input_buffer = lfill_input_buffer;
-  src->pub.skip_input_data = lskip_input_data;
-  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
-  src->pub.term_source = lterm_source;
-  src->userdata=userdata;
-  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
-  src->pub.next_input_byte = NULL; /* until buffer loaded */
-  src->offset=0;
-  src->userdata=userdata;
-  if (src->buffer) {
-     free(src->buffer);
-     src->buffer=NULL;
-     }
-}
-/* cleanup to be called before cleanup of cinfo*/
-extern "C" void
-jpeg_memio_cleanup (j_decompress_ptr cinfo) {
-  my_src_ptr src=(my_src_ptr)cinfo->src;
-  Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));
-  if (src && src->buffer) {
-    free(src->buffer);
-    src->buffer=NULL;
-    }
-}
-
-//taken from mvpmc
-//http://git.mvpmc.org/cgi-bin/gitweb.cgi?p=mvpmc.git;a=blob_plain;h=02d4354c0cbbed802a9aa1478918a49fcbf61d00;f=libs/libwidget/image_jpeg.c
-
-#define GET2BYTES(cinfo, V, swap, offset) do { \
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
-                cinfo->src->bytes_in_buffer--; \
-                V = (*cinfo->src->next_input_byte++) << (swap?0:8); \
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
-                cinfo->src->bytes_in_buffer--; \
-                V += (*cinfo->src->next_input_byte++) << (swap?8:0); \
-                offset += 2; } while(0) 
-
-#define GET4BYTES(cinfo, V, swap, offset) do { \
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
-                cinfo->src->bytes_in_buffer--; \
-                V = (*cinfo->src->next_input_byte++) << (swap?0:24); \
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
-                cinfo->src->bytes_in_buffer--; \
-                V += (*cinfo->src->next_input_byte++) << (swap?8:16); \
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
-                cinfo->src->bytes_in_buffer--; \
-                V += (*cinfo->src->next_input_byte++) << (swap?16:8); \
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
-                cinfo->src->bytes_in_buffer--; \
-                V += (*cinfo->src->next_input_byte++) << (swap?24:0); \
-                offset += 4; } while(0)
-
-static boolean
-get_exif_orient (j_decompress_ptr cinfo)
-/* Get the Exif orientation info */
-{
-        unsigned int tmp, offset, length, numtags;
-        int orient=-1;
-        jpegUserData * ud=0;
-        boolean swap;
-        orient = 1;
-        offset = 0;
-        my_src_ptr mysrc = (my_src_ptr) cinfo->src;
-
-        /* marker length */
-        GET2BYTES(cinfo, length, 0, offset);
-        if (length<8) goto err;
-        /* Exif header */
-        GET4BYTES(cinfo, tmp, 0, offset);
-        if (tmp != 0x45786966) goto err;
-        GET2BYTES(cinfo, tmp, 0, offset);
-        if (tmp != 0x0000) goto err;
-        /* Byte-order */
-        GET2BYTES(cinfo, tmp, 0, offset);
-        if (tmp == 0x4949) swap = 1;
-        else if (tmp == 0x4d4d) swap = 0;
-        else goto err;
-        GET2BYTES(cinfo, tmp, swap, offset);
-        if (tmp != 0x002A) goto err;
-        /* offset to first IFD */
-        GET4BYTES(cinfo, tmp, swap, offset);
-        offset += tmp-8;
-        (*mysrc->pub.skip_input_data)(cinfo, tmp-8);
-        /* number of tags in IFD */
-        GET2BYTES(cinfo, numtags, swap, offset);
-        if (numtags == 0) goto err;
-        
-        /* Search for Orientation Tag in IFD0 */
-        for (;;) {
-                if (offset > length-12) goto err;
-                GET2BYTES(cinfo, tmp, swap, offset);
-                if (tmp == 0x0112) break; /* found Orientation Tag */
-                if (--numtags == 0) goto err;
-                offset += 10;
-                (*mysrc->pub.skip_input_data)(cinfo, 10);
-        }
-        offset += 6;
-        (*mysrc->pub.skip_input_data)(cinfo, 6);
-        GET2BYTES(cinfo, orient, swap, offset);
-        if( orient==0 || orient>8 ) orient = 1;
-        
-        Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);
-        ud=(jpegUserData *)(mysrc->userdata);
-        switch(orient) {
-          case 3:
-            ud->ctl->exifRotation=WJpeg::ROT_180;
-            break;
-          case 6:
-            ud->ctl->exifRotation=WJpeg::ROT_90;
-            break;
-          case 8:
-            ud->ctl->exifRotation=WJpeg::ROT_270;
-            break;
-        }
-
-err:
-        (*mysrc->pub.skip_input_data)(cinfo, length-offset);
-        return TRUE;
-}
-}
-
-/*----------------------------------------------------------------
-  the implementation
-  ----------------------------------------------------------------
- */
-
-
-WJpeg::WJpeg(){
-  reader=NULL;
-  owningReader=false;
-  errbuf[0]=0;
-}
-
-WJpeg::~WJpeg() {
-  if (owningReader && reader) delete reader;
-}
-
-int WJpeg::init(char* tfileName)
-{
-  if (owningReader && reader) delete reader;
-  errbuf[0]=0; //clean error state
-  LocalReader *myreader=new LocalReader();
-  reader=myreader;
-  owningReader=true;
-  ULONG psize=myreader->initRead(tfileName);
-  if (psize == 0) {
-    delete reader;
-    reader=NULL;
-    owningReader=false;
-    SNPRINTF(errbuf,200,"unable to open %s",tfileName);
-    return 0;
-  }
-  return 1;
-}
-
-
-
-
-bool WJpeg::hasError() {
-  return (errbuf[0] != 0);
-}
-void WJpeg::draw()
-{
-  bool ok=false;
-  JpegControl ctl;
-  if (reader) {
-    Region myRegion;
-    Surface *sfc=getSurface(myRegion);
-    myRegion.w=area.w;
-    myRegion.h=area.h;
-    ctl.area=myRegion;
-    ctl.enlarge=true;
-    if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;
-  }
-  else {
-    SNPRINTF(errbuf,200,"jpeg reader not initialized");
-  }
-  if (! ok) {
-    drawTextCentre(tr("Jpeg ERROR"), 240, 170, Colour::LIGHTTEXT);
-    if (errbuf[0] != 0) drawTextCentre(errbuf,240,200, Colour::LIGHTTEXT);
-    if (ctl.error[0] != 0) drawTextCentre(ctl.error,240,230, Colour::LIGHTTEXT);
-  }
-}
-
-/**
-  the main drawing function
-  this will read the pciture via the reader
-  and draw directly into the surface
-  it will compute an appropriate scale and set the infos in the
-  JpegControl structure
-**/  
-
-bool WJpeg::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, Colour & backgroundColour) {
-  Log* logger = Log::getInstance();
-  if (! rdr || ! sfc) {
-    logger->log("BJpeg", Log::ERR, "JPEG error rdr=NULL or sfc=NULL");
-    return false;
-  }
-  logger->log("BJpeg", Log::DEBUG, "draw Jpeg Started sfc=%p, rdr=%p",sfc,rdr);
-  unsigned char* buffer =NULL;
-  struct jpeg_decompress_struct cinfo;
-  struct my_error_mgr jerr;
-  cinfo.err = jpeg_std_error(&jerr.pub);
-  jerr.pub.error_exit = my_error_exit;
-  /* Establish the setjmp return context for my_error_exit to use. */
-  if (setjmp(jerr.setjmp_buffer)) {
-    /* If we get here, the JPEG code has signaled an error.
-     * We need to clean up the JPEG object, close the input file, and return.
-     */
-    if (rdr) jpeg_memio_cleanup(&cinfo);
-    jpeg_destroy_decompress(&cinfo);
-    logger->log("BJpeg", Log::ERR, "JPEG error");
-    if (buffer) free(buffer);
-    return false;
-  }
-  jpegUserData userdata;
-  int xpos=0;
-  int ypos=0;
-  jpeg_create_decompress(&cinfo);
-  userdata.reader=rdr;
-  userdata.ctl=ctl;
-  ctl->exifRotation=ROT_0;
-  ctl->error[0]=0;
-  ctl->exifDate[0]=0;
-  //create the input for the jpeg lib
-  jpeg_memio_src(&cinfo,(void *)(&userdata));
-  //processor for EXIF data
-  jpeg_set_marker_processor(&cinfo, JPEG_APP0+1, get_exif_orient);
-  //read in header info
-  jpeg_read_header(&cinfo, TRUE);
-  ctl->picw=cinfo.image_width;
-  ctl->pich=cinfo.image_height;
-  ctl->compressedSize=rdr->getSize();
-  //now we have important info available in ctl (pictuerw,h, exif orientation,size)
-  //compute rotation due to the defined enum values we can simply add them
-  ctl->finalRotation=(enum Rotation)((ctl->rotation+ctl->exifRotation)%4);
-  logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", ctl->picw,ctl->pich,ctl->finalRotation);
-  //now we have to compute the scale
-  //input: ctl->picw,ctl->pich,ctl->finalRotation,ctl->mode,ctl->scaleAmount, ctl->scaleafter
-  //       list of available jpeg scale factors
-  //out:   scalenum,scaledenom,scaleafter
-
-  UINT picturew=ctl->picw;
-  UINT pictureh=ctl->pich;
-  switch (ctl->finalRotation){
-    case ROT_90:
-    case ROT_270:
-      pictureh=ctl->picw;
-      picturew=ctl->pich;
-      break;
-    default:
-      break;
-  }
-  UINT scalenum=1;
-  UINT scaledenom=1;
-  UINT scaleafter=1;
-  if (! ctl->enlarge) {
-    //scale - compute the factors to fit 100%
-    int scalew=1000*picturew/ctl->area.w;
-    int scaleh=1000*pictureh/ctl->area.h;
-    int scale=scaleh;
-    if (scalew > scaleh) scale=scalew;
-
-    //OK now find out which is the optimal setting
-    //rule: find settings being nearest to:
-    //   mode=LETTER - smaller or equal screen size (i.e. scale*scalefactor <= 1000)
-    //   mode=CROP   - bigger or equal screen size (i.e. scale *scalefactor>= 1000)
-    //   mode=CROPPERCENT - smaller or equal screensize*scaleamount (i.e. scale*scalefactor<= 1000*scaleamount)
-    //                      scaleamount is in % - so in reality we use scaleamount*10 instead scaleamount*1000
-    //the scalefactor computes as scalenum/(scaledenom*scaleafter)
-    scaledenom=8;
-    int minDiff=1000;
-    logger->log("BJpeg", Log::DEBUG, "start scaling screenw=%u, screenh=%u, pw=%u,ph=%u, scale=%d, mode=%d, %%=%u, after=%u",
-       ctl->area.w,ctl->area.h,picturew,pictureh,scale,(int)ctl->mode,ctl->scaleAmount, ctl->scaleafter); 
-    for (UINT j=0;j<sizeof(jpegFactors)/sizeof(jpegFactors[0]);j++) {
-      for (UINT sa=1;sa<=ctl->scaleafter;sa++) {
-        int curf=(scale*jpegFactors[j].num)/(jpegFactors[j].denom*sa);
-        bool setThis=false;
-        logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,num=%u,denom=%u,after=%u,minDiff=%d", 
-            curf,jpegFactors[j].num,jpegFactors[j].denom,sa,minDiff);
-        switch(ctl->mode) {
-          case CROP:
-            if (curf >= 1000 && curf < (minDiff +1000)) {
-              setThis=true;
-              minDiff=curf-1000;
-            }
-            break;
-          case LETTER:
-            if (curf <= 1000 && curf > (1000-minDiff)) {
-              setThis=true;
-              minDiff=1000-curf;
-            }
-            break;
-          case CROPPERCENT:
-            if (curf <= 10*(int)ctl->scaleAmount ) {
-              int abs=curf-1000;
-              if (abs < 0) abs=-abs;
-              if (abs < minDiff) {
-                   setThis=true;
-                   minDiff=abs;
-              }
-            }
-            break;
-        }
-        if (setThis) {
-          logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);
-          scalenum=jpegFactors[j].num;
-          scaledenom=jpegFactors[j].denom;
-          scaleafter=sa;
-        }
-      }
-    }
-    ctl->scale=100*scalenum/(scaledenom*scaleafter);
-
-    logger->log("BJpeg", Log::DEBUG, "JPEG scaling found scale=%i num=%i denom=%i after=%i result=%i scale=%i%% ",
-        scale,scalenum,scaledenom,scaleafter,scale*ctl->scale/100,ctl->scale);
-
-    cinfo.scale_denom=scaledenom;
-    cinfo.scale_num=scalenum;
-    }
-  else
-  {
-    //set drawing area according to picture
-    ctl->area.w=ctl->picw;
-    ctl->area.h=ctl->pich;
-  }
-
-  //now we know the scaling
-  //compute the scaled size and position
-
-  jpeg_start_decompress(&cinfo);
-  //picturew/h is now the output width from the decompressor and afterscaler
-  //this is unrotated 
-  picturew=cinfo.output_width;
-  pictureh=cinfo.output_height;
-  if (scaleafter > 1) {
-    picturew=picturew/scaleafter;
-    pictureh=pictureh/scaleafter;
-  }
-  //if our image is smaller - center it
-  if (! ctl->enlarge) {
-    if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {
-      int dim=pictureh;
-      xpos=(((int)ctl->area.w)-dim)/2;
-      dim=picturew;
-      ypos=(((int)ctl->area.h)-dim)/2;
-    } else {
-      int dim=picturew;
-      xpos=(((int)ctl->area.w)-dim)/2;
-      dim=pictureh;
-      ypos=(((int)ctl->area.h)-dim)/2;
-    }
-    if (xpos <0) xpos=0;
-    if (ypos <0) ypos=0;
-  }
-  xpos+=ctl->area.x;
-  ypos+=ctl->area.y;
-  //remember the jpeg dimensions for computing the buffer
-  UINT jpegwidth=cinfo.output_width;
-  UINT jpegheight=cinfo.output_height;
-  logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, jw=%i, jh=%i, rot=%d", 
-      picturew, pictureh,xpos,ypos,jpegwidth,jpegheight,(int)ctl->finalRotation*90);
-
-  //fill the background
-  sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour.rgba());
-
-  //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
-  int linelen=jpegwidth*3;
-#ifdef USE_BUFFER
-  // MAKE THE 2D ARRAY
-  buffer = (unsigned char*)malloc(jpegheight * linelen);
-  logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, lines = %i linelen = %i", buffer, jpegheight, linelen);
-  if (buffer == NULL) {
-    if (rdr) jpeg_memio_cleanup(&cinfo);
-    jpeg_destroy_decompress(&cinfo);
-    logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");
-    SNPRINTF(ctl->error,100,"no room for buffer");
-    return false;
-  }
-#endif
-
-#ifndef USE_BUFFER
-  //unsigned char lbuf[linelen];
-  unsigned char *lbuf=new unsigned char[linelen*scaleafter];
-  unsigned char * ptr=lbuf;
-  UINT outy=0;
-#else
-  unsigned char * ptr=buffer;
-#endif
-
-  int rowsread = 0;
-
-  Colour c;
-  sfc->startFastDraw();//Tell the surface, that we will draw a lot of pixel,
-  //so that performance, can be optimized
-  logger->log("BJpeg", Log::DEBUG, "start drawing ");
-  UINT colincr=0;
-  //factors to base 1024
-  UINT fac=1024;
-  if (scaleafter > 1) {
-     colincr=3*scaleafter-3;
-     fac=1024/(scaleafter*scaleafter);
-     }
-  logger->log("BJpeg", Log::DEBUG, "jpeg  draw scale %d image: %u %u, picture: %u %u", scaleafter,picturew,pictureh,jpegwidth,jpegheight);
-  while (cinfo.output_scanline < jpegheight)
-  {
-//  logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
-    rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
-#ifdef USE_BUFFER
-    ptr+=linelen;
-#else
-    if (scaleafter > 1) {
-      if (rowsread % scaleafter != scaleafter-1) {
-        //this simple approach wold maybe forget scaleafter -1 lines at the end...
-        ptr+=linelen;
-        continue;
-      }
-      ptr=lbuf;
-    }
-    drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);
-    outy++;
-    
-#endif
-  }
-  sfc->endFastDraw();
-
-  logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
-
-  jpeg_finish_decompress(&cinfo);
-  jpeg_memio_cleanup(&cinfo);
-  jpeg_destroy_decompress(&cinfo);
-
-  logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");
-  rdr->drawingDone();
-
-#ifdef USE_BUFFER
-  UINT y;
-  //Tell the surface, that we will draw a lot of pixel,
-  //so that performance, can be optimized
-  sfc->startFastDraw();
-  logger->log("BJpeg", Log::DEBUG, "jpeg start buffer draw" );
-  unsigned char* p=buffer; //start of first row
-  UINT rowincr=linelen*scaleafter;
-  //for simplicity omit last line to avoid running out of buffer
-  for (y = 0; y < pictureh-1 ;y++)
-  {
-    drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);
-    p+=rowincr;
-  }
-  sfc->endFastDraw();
-  logger->log("BJpeg", Log::DEBUG, "end draw");
-  free(buffer);
-#else
-  delete[] lbuf;
-#endif
-  logger->log("BJpeg", Log::DEBUG, "deleted buffer");
-  return true;
-}
-
-//get my own surface
-Surface * WJpeg::getSurface(Region & r) {
-  r.x=getRootBoxOffsetX();
-  r.y=getRootBoxOffsetY();
-  r.w=area.w;
-  r.h=area.h;
-  return Boxx::getSurface();
-}
-
-
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+#include "boxx.h"\r
+#include "wjpeg.h"\r
+#include <setjmp.h>\r
+#include <sys/types.h>\r
+#include <sys/stat.h>\r
+\r
+#ifndef WIN32\r
+#include <unistd.h>\r
+#else\r
+\r
+#endif\r
+\r
+#include "i18n.h"\r
+#include "log.h"\r
+#include "surface.h"\r
+\r
+\r
+/*----------------------------------------------------------------\r
+  the implementation\r
+  ----------------------------------------------------------------\r
+ */\r
+\r
+\r
+WJpeg::WJpeg(){\r
+\r
+}\r
+\r
+WJpeg::~WJpeg() {\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+void WJpeg::draw()\r
+{\r
+\r
+}\r
+\r
+\r
diff --git a/wjpeg.h b/wjpeg.h
index 154cfc9bbea9152b322bd5000bf5f0f03600fe42..4de5478e8b634c9988f42774782480f0f2bc5747 100644 (file)
--- a/wjpeg.h
+++ b/wjpeg.h
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef WJPEG_H
-#define WJPEG_H
-
-#include <stdio.h>
-#include <malloc.h>
-
-#ifdef WIN32
-
-#include <winsock2.h>
-#include <windows.h>
-
-
-//#define NEED_FAR_POINTERS
-#define XMD_H //workaround some compiling issues
-#endif
-
-class Surface;
-class Boxx;
-
-//a reader to be implemented by the caller
-class JpegReader {
-  public:
-  //read the next chunk of jpeg data
-  //offset - from start of file
-  //len I buf len (max bytes to read)
-  //return read len, 0 on EOF, -1 on error, *buf set to buffer
-  //will be released with free(!!!) after decoding
-  virtual ULONG readChunk(ULONG offset,ULONG len,char **buf)=0;
-  //a callback when the drawing is complete
-  //the implementation is optional
-  virtual void drawingDone(){};
-  //get the size of the current picture
-  virtual ULONG getSize(){ return 0;}
-  virtual ~JpegReader(){};
-};
-class WJpeg : public Boxx
-{
-  public:
-  
-    // temp for boxx
-    void setDimensions(int width, int height) {area.w=width;area.h=height;};
-  
-  
-    WJpeg();
-    virtual ~WJpeg();
-    //old style usage - load local file
-    //the sequence is init(filename), draw
-    //the new usage is drawJpeg (with having the right offsets computed)
-    int init(char* fileName);
-    void draw();
-
-    bool hasError();
-    
-    //mode for scaling pictures
-    enum ScaleMode {
-        LETTER=0,
-        CROP=1,
-        CROPPERCENT=2};
-    //rotations
-    enum Rotation{
-     ROT_0=0,
-     ROT_90=1,
-     ROT_180=2,
-     ROT_270=3
-    };
-    //jpeg info 
-    struct JpegControl {
-      public:
-      //the available drawing area
-      Region area;
-      bool enlarge;
-      //the maximum allowed scale factor after decompress
-      UINT scaleafter;
-      //the scale mode
-      enum ScaleMode mode;
-      //the size value if scaleMode==cropPercent
-      //%of the drawing area size
-      UINT  scaleAmount;
-      //the rotation (user defined as input)
-      //if exif rotation is found this will be added
-      enum Rotation rotation;
-
-      //paremeters filled during Jpeg parsing
-      enum Rotation exifRotation;
-      char exifDate[30];
-      char error[100];
-      UINT picw;
-      UINT pich;
-      ULONG compressedSize;
-
-      //parameters computed to display picture
-      enum Rotation finalRotation;
-      //scale in %
-      UINT scale;
-      JpegControl() {
-        area.x=0;
-        area.y=0;
-        area.w=0;
-        area.h=0;
-        enlarge=false;
-        scaleafter=3;
-        scaleAmount=110;
-        mode=CROPPERCENT;
-        rotation=ROT_0;
-        exifRotation=ROT_0;
-        finalRotation=ROT_0;
-        exifDate[0]='\0';
-        error[0]='\0';
-        picw=0;
-        pich=0;
-        compressedSize=0;
-        scale=100;
-      }
-    };
-
-    //the standalone drawing function
-    //this will draw into the provided surface
-    //the reader has to be initialized before
-    //calling this function does not need a WJpeg being instantiated
-    //it simply draws into the surface
-    bool static drawJpeg(JpegControl * control, Surface* sfc, JpegReader *rdr, Colour & backgroundColour);
-
-  private:
-    //our drawPixel with considers rotation
-    /* handle picture rotation
-       90: xr=h-y
-           yr=x
-       180:xr=w-x
-           yr=h-y
-       270:xr=y
-           yr=w-x
-    */
-    inline static void  drawPixel(Surface * sfc,enum Rotation rotate,int x, int y,int w,int h,int xpos, int ypos,Colour c){
-    int xb=0;
-    int yb=0;
-    switch(rotate) {
-       case ROT_0:
-          xb=x;
-          yb=y;
-          break;
-       case ROT_90:
-          xb=h-y;
-          yb=x;
-          break;
-       case ROT_180:
-          xb=w-x;
-          yb=h-y;
-          break;
-       case ROT_270:
-          xb=y;
-          yb=w-x;
-          break;
-       }
-       xb+=xpos;
-       yb+=ypos;
-       if (xb < 0 || yb < 0 ) {
-         return;
-       }
-       sfc->drawPixel((UINT)xb,(UINT)yb,c,true);
-    }
-
-    /**
-      draw a line of pixels coming from the decompressor
-      if scaleafter > 1 we draw that many lines (numlines is the# lines in the buffer)
-      picturew is the resulting width of the picture
-    **/  
-    inline static void drawLine(Surface *sfc,enum Rotation rotate, unsigned char *cp,UINT scaleafter,UINT picturew,UINT pictureh, 
-        UINT xpos, UINT ypos, UINT outy, UINT linelen,UINT pixeloffset, UINT numlines, UINT fac) {
-      Colour c;
-      for (UINT x = 0; x < picturew; x++)
-      {
-        if (scaleafter > 1 ) {
-           //boxfilter scalefactor*scalefactor
-           //take 0...scalefactor pixels in x and y direction
-           for (int colornum=0;colornum<3;colornum++) {
-             UINT comp=0;
-             unsigned char * accp=cp;
-             for (UINT rows=0;rows<scaleafter;rows++) {
-               unsigned char * pp=accp;
-               for (UINT cols=0;cols<scaleafter;cols++) {
-                 comp+=(UINT)*pp;
-                 if (pp-accp < (int)linelen-3) pp+=3;
-                 }
-               if (rows < numlines) accp+=linelen;
-               }
-             comp=(comp*fac) >> 10;
-             if (colornum == 0) c.red=comp;
-             if (colornum == 1) c.green=comp;
-             if (colornum == 2) c.blue=comp;
-             cp++;
-           }
-          
-        }
-        else {
-          c.red = *cp;cp++;
-          c.green = *cp;cp++;
-          c.blue = *cp;cp++;
-        }
-        cp+=pixeloffset;
-        drawPixel(sfc,rotate,x, outy, picturew,pictureh,xpos,ypos,c);
-      }
-    }
-    //find my own surface and fill the area with my x and y offset within
-    Surface * getSurface(Region &a);
-
-    JpegReader *reader;
-    bool owningReader;
-    char errbuf[200];
-};
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef WJPEG_H\r
+#define WJPEG_H\r
+\r
+#include <stdio.h>\r
+#include <malloc.h>\r
+#include "boxx.h"\r
+\r
+\r
+\r
+\r
+class WJpeg : public Boxx\r
+{\r
+  public:\r
+  \r
+    // temp for boxx\r
+    void setDimensions(int width, int height) {area.w=width;area.h=height;};\r
+  \r
+  \r
+    WJpeg();\r
+    virtual ~WJpeg();\r
+    //old style usage - load local file\r
+    //the sequence is init(filename), draw\r
+    //the new usage is drawJpeg (with having the right offsets computed)\r
+    virtual int init(const char* fileName)=0;\r
+    virtual void draw();\r
+\r
+\r
+};\r
+\r
+\r
+#if !defined(WIN32) || !defined(__ANDROID)\r
+#define WJpegTYPE WJpegSimple\r
+#include "wjpegsimple.h"\r
+#else\r
+#define WJpegTYPE WJpegComplex\r
+#include "wjpegcomplex.h"\r
+#endif\r
+\r
+#endif\r
diff --git a/wol.cc b/wol.cc
index 22751c82cd229ab622819f158496fd6941065165..6b23680f1a01f9c320bbbbb171e1968538a6db3a 100644 (file)
--- a/wol.cc
+++ b/wol.cc
 
 #include <ctype.h>
 #include <errno.h>
+
+
+#if !defined(__ANDROID__) && !defined(WIN32)
+#include <net/ethernet.h>
+#else
+#define ETH_ALEN               6
+#endif
+
+
 #ifndef WIN32
 #include <unistd.h>
-#include <net/ethernet.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #else
-#define ETH_ALEN               6
-
 #include <winsock2.h>
 #include <errno.h>
 #include <Ws2tcpip.h>
index b487ab8787f89e428c1621b4d9dec7c07f9a957e..6e43230527cf6b6ae07b0ce8d4a47167d5288ca6 100644 (file)
@@ -21,6 +21,7 @@
 #include "woptionbox.h"
 
 #include "colour.h"
+#include "log.h"
 #ifndef WIN32
 #include "unistd.h"
 #endif
@@ -31,11 +32,10 @@ WOptionBox::WOptionBox()
   options = NULL;
   active = 0;
   currentOption = 0;
-
   mode = MODE_TEXT;
   
   textbox.setPosition(20, 0);
-  textbox.setSize(10, surface->getFontHeight());
+  textbox.setSize(10, getFontHeight());
   textbox.setParaMode(false);
   textbox.setTextPos(0, 0);
   add(&textbox);
@@ -60,7 +60,7 @@ WOptionBox::~WOptionBox()
 void WOptionBox::setSize(UINT w, UINT h)
 {
   Boxx::setSize(w, h);
-  textbox.setSize(w - 40, surface->getFontHeight());
+  textbox.setSize(w - 40, getFontHeight());
   rightArrow.setPosition(w - 18, 2);
 }
 
index 036ad1226e26f925983752abe95892cf774f0680..00df78234c568c443943d03a927383b52f8446b9 100644 (file)
@@ -60,18 +60,19 @@ void WOptionPane::saveOpts()
 
 void WOptionPane::addOptionLine(Option* option)
 {
-  int fontHeight = surface->getFontHeight();
+  int fontHeight = getFontHeight();
+
 
   options.resize(numOptions+1);
   options[numOptions] = option;
-  
+
   WTextbox* tb = new WTextbox();
   tb->setPosition(4, 4 + (numOptions * 30));
   tb->setSize(300, fontHeight);
   tb->setText(tr(option->displayText));
   tb->setTextPos(0, 0);
   add(tb);
-  
+
   textBoxes.resize(numOptions+1);
   textBoxes[numOptions] = tb;
 
@@ -79,10 +80,10 @@ void WOptionPane::addOptionLine(Option* option)
   ob->setPosition(310, 4 + (numOptions * 30));
   ob->setSize(190, fontHeight);  
   add(ob);
-  
+
   optionBoxes.resize(numOptions+1);
   optionBoxes[numOptions] = ob;
-  
+
   if (option->optionType == Option::TYPE_TEXT ||
       option->optionType == Option::TYPE_KEYED_TEXT)
   {
index 707932dd5952f4b008750efe9efad4737f1fd615..73177f45748da3adef6a210e79a39283552ec9da 100644 (file)
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#include "wselectlist.h"
-
-#include "colour.h"
-
-WSelectList::WSelectList()
-{
-  selectedOption = 0;
-  topOption = 0;
-  numOptionsDisplayable = 0;
-  numColumns = 0;
-  noLoop = 0;
-  gap = 1;
-  showseloption = true;
-  darkseloption = false;
-  backgroundColour = Colour::VIEWBACKGROUND;
-}
-
-WSelectList::~WSelectList()
-{
-  clear();
-}
-
-void WSelectList::clear()
-{
-  int vsize = options.size();
-  for (int i = 0; i < vsize; i++)
-  {
-    delete[] options[i].text;
-  }
-  options.clear();
-
-  selectedOption = 0;
-  topOption = 0;
-  numOptionsDisplayable = 0;
-  numColumns = 0;
-}
-
-void WSelectList::setNoLoop()
-{
-  noLoop = 1;
-}
-
-void WSelectList::setBackgroundColour(const Colour& colour)
-{
-  backgroundColour = colour;
-}
-
-void WSelectList::hintSetCurrent(int idx)
-{
-  selectedOption = idx;
-  if (selectedOption >= options.size()) selectedOption = options.size() - 1;
-}
-
-void WSelectList::hintSetTop(int idx)
-{
-  topOption = idx;
-}
-
-int WSelectList::addOption(const char* text, ULONG data, int selected)
-{
-  int thisNewOption = options.size();
-
-  wsloption wslo;
-  wslo.text = new char[strlen(text) + 1];
-  strcpy(wslo.text, text);
-  wslo.data = data;
-  options.push_back(wslo);
-  if (selected) selectedOption = thisNewOption;
-  return thisNewOption;
-}
-
-void WSelectList::draw()
-{
-  int fontHeight = surface->getFontHeight();
-  int ySeperation = fontHeight + gap;
-
-  numOptionsDisplayable = (area.h - 5) / ySeperation;
-
-  if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;
-  if (selectedOption == ((UINT)topOption - 1)) topOption--;
-  // if still not visible...
-  if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))
-  {
-    topOption = selectedOption - (numOptionsDisplayable / 2);
-  }
-
-  if (topOption < 0) topOption = 0;
-
-
-  fillColour(backgroundColour);
-
-  UINT ypos = 5;
-  for (UINT i = topOption; i < (topOption + numOptionsDisplayable); i++)
-  {
-    if (i == options.size()) return;
-    if ((ypos + ySeperation) > area.h) break;
-
-    if (i == selectedOption && showseloption)
-    {
-      rectangle(0, ypos, area.w, fontHeight, darkseloption ? Colour::SELECTDARKHIGHLIGHT: Colour::SELECTHIGHLIGHT);
-      drawOptionLine(options[i].text, 5, ypos, area.w - 5, Colour::DARKTEXT);
-    }
-    else
-    {
-      drawOptionLine(options[i].text, 5, ypos, area.w - 5, Colour::LIGHTTEXT);
-    }
-    ypos += ySeperation;
-  }
-}
-
-void WSelectList::addColumn(int x)
-{
-  if (numColumns == 10) return;
-  columns[numColumns++] = x;
-}
-
-void WSelectList::drawOptionLine(char* text, int xpos, int ypos, int width, const Colour& colour)
-{
-  if (!numColumns)
-  {
-    drawText(text, xpos, ypos, width, colour);
-  }
-  else
-  {
-    char buffer[200];
-    strncpy(buffer, text, 199);
-    int currentColumn = 0;
-    char* pointer;
-
-    pointer = strtok(buffer, "\t");
-    while(pointer)
-    {
-      drawText(pointer, xpos + columns[currentColumn], ypos, width - columns[currentColumn], colour);
-      currentColumn++;
-      if (currentColumn == 10) return;
-      pointer = strtok(NULL, "\t");
-    }
-  }
-}
-
-void WSelectList::up()
-{
-  if (selectedOption > 0)
-  {
-    selectedOption--;
-  }
-  else
-  {
-    if (!noLoop) selectedOption = options.size() - 1;
-  }
-}
-
-void WSelectList::down()
-{
-  if (selectedOption < options.size() - 1)
-  {
-    selectedOption++;
-  }
-  else
-  {
-    if (!noLoop) selectedOption = 0;
-  }
-}
-
-void WSelectList::pageUp()
-{
-  topOption -= numOptionsDisplayable;
-  if (topOption < 0) topOption = 0;
-
-  selectedOption = topOption;
-}
-
-void WSelectList::pageDown()
-{
-  if ((topOption + numOptionsDisplayable) >= options.size())
-  {
-    selectedOption = options.size() - 1;
-  }
-  else
-  {
-    topOption += numOptionsDisplayable;
-    selectedOption = topOption;
-  }
-}
-
-int WSelectList::getTopOption()
-{
-  return topOption;
-}
-
-int WSelectList::getNumOptions()
-{
-  return options.size();
-}
-
-int WSelectList::getBottomOption()
-{
-  UINT retval = topOption + numOptionsDisplayable;
-  if (retval > options.size()) return options.size();
-  else return retval;
-}
-
-int WSelectList::getCurrentOption()
-{
-  return selectedOption;
-}
-
-ULONG WSelectList::getCurrentOptionData()
-{
-  if (!options.size()) return 0;
-  return options[selectedOption].data;
-}
-
-bool WSelectList::mouseMove(int x, int y)
-{
-  int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());
-  if (ml>=0 && ml!=(int)selectedOption)
-  {
-    selectedOption = ml;
-    return true;
-  }
-  return false;
-}
-
-bool WSelectList::mouseLBDOWN(int x, int y)
-{
-  int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());
-  if (ml == (int)selectedOption)
-  {
-    /* caller should generate a OK message*/
-    return true;
-  }
-  return false;
-}
-
-int WSelectList::getMouseLine(int x,int y)
-{
-  int fontHeight = surface->getFontHeight();
-  int ySeperation = fontHeight + gap;
-
-  if (y<0) return -1;
-  if (x<0 || x>(int)area.w) return -1;
-  if (y>(int)(10+numOptionsDisplayable*ySeperation)) return -1;
-
-  int cy = y - 5;
-
-  int selected=cy/ySeperation;
-  if (y<5) selected=-1;
-  if (selected> ((int)numOptionsDisplayable)) return -1;
-  /* Important: should be the same algorithm used in draw! */
-  if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;
-  if (selectedOption == ((UINT)topOption - 1)) topOption--;
-  // if still not visible...
-  if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))
-  {
-    topOption = selectedOption - (numOptionsDisplayable / 2);
-  }
-
-  if (topOption < 0) topOption = 0;
-
-  if ((selected+topOption >= (int) options.size()) ||
-      (selected + topOption < 0)) return -1;
-
-  return selected + topOption;
-}
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "wselectlist.h"\r
+\r
+#include "colour.h"\r
+#include "log.h"\r
+\r
+WSelectList::WSelectList()\r
+{\r
+  selectedOption = 0;\r
+  topOption = 0;\r
+  numOptionsDisplayable = 0;\r
+  numColumns = 0;\r
+  noLoop = 0;\r
+  gap = 1;\r
+  showseloption = true;\r
+  darkseloption = false;\r
+  backgroundColour = Colour::VIEWBACKGROUND;\r
+}\r
+\r
+WSelectList::~WSelectList()\r
+{\r
+  clear();\r
+}\r
+\r
+void WSelectList::clear()\r
+{\r
+  int vsize = options.size();\r
+  for (int i = 0; i < vsize; i++)\r
+  {\r
+    delete[] options[i].text;\r
+  }\r
+  options.clear();\r
+\r
+  selectedOption = 0;\r
+  topOption = 0;\r
+  numOptionsDisplayable = 0;\r
+  numColumns = 0;\r
+}\r
+\r
+void WSelectList::setNoLoop()\r
+{\r
+  noLoop = 1;\r
+}\r
+\r
+void WSelectList::setBackgroundColour(const Colour& colour)\r
+{\r
+  backgroundColour = colour;\r
+}\r
+\r
+void WSelectList::hintSetCurrent(int idx)\r
+{\r
+  selectedOption = idx;\r
+  if (selectedOption >= options.size()) selectedOption = options.size() - 1;\r
+}\r
+\r
+void WSelectList::hintSetTop(int idx)\r
+{\r
+  topOption = idx;\r
+}\r
+\r
+int WSelectList::addOption(const char* text, ULONG data, int selected)\r
+{\r
+  int thisNewOption = options.size();\r
+\r
+  wsloption wslo;\r
+  wslo.text = new char[strlen(text) + 1];\r
+  strcpy(wslo.text, text);\r
+  wslo.data = data;\r
+  options.push_back(wslo);\r
+  if (selected) selectedOption = thisNewOption;\r
+  return thisNewOption;\r
+}\r
+\r
+void WSelectList::draw()\r
+{\r
+  int fontHeight = getFontHeight();\r
+  int ySeperation = fontHeight + gap;\r
+\r
+  numOptionsDisplayable = (area.h - 5) / ySeperation;\r
+\r
+  if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;\r
+  if (selectedOption == ((UINT)topOption - 1)) topOption--;\r
+  // if still not visible...\r
+  if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))\r
+  {\r
+    topOption = selectedOption - (numOptionsDisplayable / 2);\r
+  }\r
+\r
+  if (topOption < 0) topOption = 0;\r
+\r
+\r
+  fillColour(backgroundColour);\r
+\r
+  UINT ypos = 5;\r
+  for (UINT i = topOption; i < (topOption + numOptionsDisplayable); i++)\r
+  {\r
+    if (i == options.size()) return;\r
+    if ((ypos + ySeperation) > area.h) break;\r
+\r
+    if (i == selectedOption && showseloption)\r
+    {\r
+\r
+      rectangle(0, ypos, area.w, fontHeight, darkseloption ? Colour::SELECTDARKHIGHLIGHT: Colour::SELECTHIGHLIGHT);\r
+\r
+      drawOptionLine(options[i].text, 5, ypos, area.w - 5, Colour::DARKTEXT);\r
+    }\r
+    else\r
+    {\r
+\r
+      drawOptionLine(options[i].text, 5, ypos, area.w - 5, Colour::LIGHTTEXT);\r
+    }\r
+    ypos += ySeperation;\r
+  }\r
+\r
+}\r
+\r
+void WSelectList::addColumn(int x)\r
+{\r
+  if (numColumns == 10) return;\r
+  columns[numColumns++] = x;\r
+}\r
+\r
+void WSelectList::drawOptionLine(char* text, int xpos, int ypos, int width, const Colour& colour)\r
+{\r
+  if (!numColumns)\r
+  {\r
+\r
+    drawText(text, xpos, ypos, width, colour);\r
+  }\r
+  else\r
+  {\r
+    char buffer[200];\r
+    strncpy(buffer, text, 199);\r
+    int currentColumn = 0;\r
+    char* pointer;\r
+\r
+    pointer = strtok(buffer, "\t");\r
+    while(pointer)\r
+    {\r
+\r
+      drawText(pointer, xpos + columns[currentColumn], ypos, width - columns[currentColumn], colour);\r
+\r
+      currentColumn++;\r
+      if (currentColumn == 10) return;\r
+      pointer = strtok(NULL, "\t");\r
+    }\r
+  }\r
+}\r
+\r
+void WSelectList::up()\r
+{\r
+  if (selectedOption > 0)\r
+  {\r
+    selectedOption--;\r
+  }\r
+  else\r
+  {\r
+    if (!noLoop) selectedOption = options.size() - 1;\r
+  }\r
+}\r
+\r
+void WSelectList::down()\r
+{\r
+  if (selectedOption < options.size() - 1)\r
+  {\r
+    selectedOption++;\r
+  }\r
+  else\r
+  {\r
+    if (!noLoop) selectedOption = 0;\r
+  }\r
+}\r
+\r
+void WSelectList::pageUp()\r
+{\r
+  topOption -= numOptionsDisplayable;\r
+  if (topOption < 0) topOption = 0;\r
+\r
+  selectedOption = topOption;\r
+}\r
+\r
+void WSelectList::pageDown()\r
+{\r
+  if ((topOption + numOptionsDisplayable) >= options.size())\r
+  {\r
+    selectedOption = options.size() - 1;\r
+  }\r
+  else\r
+  {\r
+    topOption += numOptionsDisplayable;\r
+    selectedOption = topOption;\r
+  }\r
+}\r
+\r
+int WSelectList::getTopOption()\r
+{\r
+  return topOption;\r
+}\r
+\r
+int WSelectList::getNumOptions()\r
+{\r
+  return options.size();\r
+}\r
+\r
+int WSelectList::getBottomOption()\r
+{\r
+  UINT retval = topOption + numOptionsDisplayable;\r
+  if (retval > options.size()) return options.size();\r
+  else return retval;\r
+}\r
+\r
+int WSelectList::getCurrentOption()\r
+{\r
+  return selectedOption;\r
+}\r
+\r
+ULONG WSelectList::getCurrentOptionData()\r
+{\r
+  if (!options.size()) return 0;\r
+  return options[selectedOption].data;\r
+}\r
+\r
+bool WSelectList::mouseAndroidScroll(int x, int y,int sx, int sy)\r
+{\r
+/*     int fontHeight = getFontHeight();\r
+       int movelines= sy/fontHeight;\r
+\r
+       int seloption=selectedOption+movelines;\r
+       if (seloption<0) seloption=0;\r
+       else if (seloption>options.size()-1) seloption=options.size()-1;\r
+       selectedOption=seloption;*/\r
+\r
+}\r
+\r
+bool WSelectList::mouseMove(int x, int y)\r
+{\r
+  int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());\r
+  if (ml>=0 && ml!=(int)selectedOption)\r
+  {\r
+    selectedOption = ml;\r
+    return true;\r
+  }\r
+  return false;\r
+}\r
+\r
+bool WSelectList::mouseLBDOWN(int x, int y)\r
+{\r
+  int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());\r
+  if (ml == (int)selectedOption)\r
+  {\r
+    /* caller should generate a OK message*/\r
+    return true;\r
+  }\r
+  return false;\r
+}\r
+\r
+int WSelectList::getMouseLine(int x,int y)\r
+{\r
+  int fontHeight = getFontHeight();\r
+  int ySeperation = fontHeight + gap;\r
+\r
+  if (y<0) return -1;\r
+  if (x<0 || x>(int)area.w) return -1;\r
+  if (y>(int)(10+numOptionsDisplayable*ySeperation)) return -1;\r
+\r
+  int cy = y - 5;\r
+\r
+  int selected=cy/ySeperation;\r
+  if (y<5) selected=-1;\r
+  if (selected> ((int)numOptionsDisplayable)) return -1;\r
+  /* Important: should be the same algorithm used in draw! */\r
+  if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;\r
+  if (selectedOption == ((UINT)topOption - 1)) topOption--;\r
+  // if still not visible...\r
+  if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))\r
+  {\r
+    topOption = selectedOption - (numOptionsDisplayable / 2);\r
+  }\r
+\r
+  if (topOption < 0) topOption = 0;\r
+\r
+  if ((selected+topOption >= (int) options.size()) ||\r
+      (selected + topOption < 0)) return -1;\r
+\r
+  return selected + topOption;\r
+}\r
index 03ba36105d9ee40208ebc77990e2f7791566dddf..c27f73eebff0b0f95f0b7b519cbc70dd32298448 100644 (file)
@@ -1,89 +1,90 @@
-/*
-    Copyright 2004-2005 Chris Tallon
-
-    This file is part of VOMP.
-
-    VOMP is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    VOMP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef WSELECTLIST_H
-#define WSELECTLIST_H
-
-#include <stdio.h>
-#include <string.h>
-
-#include <vector>
-
-#include "defines.h"
-#include "boxx.h"
-
-using namespace std;
-
-typedef struct
-{
-  char* text;
-  ULONG data;
-} wsloption;
-
-class WSelectList : public Boxx
-{
-  public:
-    WSelectList();
-    ~WSelectList();
-    void clear();
-    void addColumn(int x);
-
-    void setNoLoop();
-    void setShowSelOption(bool set) { showseloption = set; };
-    void setDarkSelOption(bool set) { darkseloption = set; };
-    int addOption(const char* text, ULONG data, int selected);
-    void draw();
-    void setBackgroundColour(const Colour& colour);
-
-    void down();
-    void up();
-    void pageUp();
-    void pageDown();
-
-    int getTopOption();
-    int getNumOptions();
-    int getBottomOption();     // actually returns bottom + 1 i.e. the one just past display ?!
-    int getCurrentOption();
-    ULONG getCurrentOptionData();
-
-    void hintSetCurrent(int index);
-    void hintSetTop(int index);
-
-    virtual bool mouseMove(int x, int y);
-    virtual bool mouseLBDOWN(int x, int y);
-
-  private:
-    void drawOptionLine(char* text, int xpos, int ypos, int width, const Colour& colour);
-    int getMouseLine(int x, int y);
-
-    vector<wsloption> options;
-    UINT selectedOption;
-    int topOption;
-    UINT numOptionsDisplayable;
-    int columns[10];
-    int numColumns;
-    int noLoop;
-    bool showseloption, darkseloption;
-    
-    UINT gap;
-    Colour backgroundColour;
-};
-
-#endif
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef WSELECTLIST_H\r
+#define WSELECTLIST_H\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#include <vector>\r
+\r
+#include "defines.h"\r
+#include "boxx.h"\r
+\r
+using namespace std;\r
+\r
+typedef struct\r
+{\r
+  char* text;\r
+  ULONG data;\r
+} wsloption;\r
+\r
+class WSelectList : public Boxx\r
+{\r
+  public:\r
+    WSelectList();\r
+    ~WSelectList();\r
+    void clear();\r
+    void addColumn(int x);\r
+\r
+    void setNoLoop();\r
+    void setShowSelOption(bool set) { showseloption = set; };\r
+    void setDarkSelOption(bool set) { darkseloption = set; };\r
+    int addOption(const char* text, ULONG data, int selected);\r
+    void draw();\r
+    void setBackgroundColour(const Colour& colour);\r
+\r
+    void down();\r
+    void up();\r
+    void pageUp();\r
+    void pageDown();\r
+\r
+    int getTopOption();\r
+    int getNumOptions();\r
+    int getBottomOption();     // actually returns bottom + 1 i.e. the one just past display ?!\r
+    int getCurrentOption();\r
+    ULONG getCurrentOptionData();\r
+\r
+    void hintSetCurrent(int index);\r
+    void hintSetTop(int index);\r
+\r
+    virtual bool mouseMove(int x, int y);\r
+    virtual bool mouseLBDOWN(int x, int y);\r
+    virtual bool mouseAndroidScroll(int x, int y,int sx, int sy);\r
+\r
+  private:\r
+    void drawOptionLine(char* text, int xpos, int ypos, int width, const Colour& colour);\r
+    int getMouseLine(int x, int y);\r
+\r
+    vector<wsloption> options;\r
+    UINT selectedOption;\r
+    int topOption;\r
+    UINT numOptionsDisplayable;\r
+    int columns[10];\r
+    int numColumns;\r
+    int noLoop;\r
+    bool showseloption, darkseloption;\r
+    \r
+    UINT gap;\r
+    Colour backgroundColour;\r
+};\r
+\r
+#endif\r
index a4d826245c4927dae8f5d779b8090d3e95ab93f8..903f1e6485a8ebeea5e431740f7b2ba0109dbea1 100644 (file)
@@ -1078,6 +1078,7 @@ void WSymbol::draw()
 
   int x, y, bytesIn, bitsIn;
 
+  startFastDraw();
   for (y = 0; y < sHeight; y++)
   {
     for (x = 0; x < widthBits; x++)
@@ -1087,10 +1088,11 @@ void WSymbol::draw()
 
       if ((base[bytesIn] >> (7 - bitsIn)) & 0x01)
       {
-        drawPixel(x, y, nextColour);
+        drawPixel(x, y, nextColour,true);
       }
     }
   }
+  endFastDraw();
 }
 
 bool WSymbol::mouseLBDOWN(int x, int y)
index 2194b2c7870b57231a5c975fa2f1ef78a5aeabd5..eb8ec53af15184e6be00ad0e6118b853d9bea409 100644 (file)
@@ -67,7 +67,7 @@ void WTabBar::addTab(const char* name, Boxx* boxx)
   WButton* newButton = new WButton();
   newButton->setText(name);
   newButton->setPosition(newButtonX, 2);
-  newButton->setSize(td.nameWidth + 6, Surface::getFontHeight());
+  newButton->setSize(td.nameWidth + 6, getFontHeight());
   if ((newButtonX + newButton->getWidth()) > (getWidth() - 22)) newButton->setVisible(false);
   add(newButton);