--- /dev/null
+/*
+ Copyright 2004-2005 Chris Tallon, 2009 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 "audiovpe.h"
+#include "videovpeogl.h"
+#include "log.h"
+
+AudioVPE::AudioVPE()
+{
+ if (instance) return;
+ initted = 0;
+ lastpacketnum=-1;
+ currentpacketnum=-1;
+ streamType = 0;
+ volume = 20;
+ muted = 0;
+ lastAType = MPTYPE_MPEG_AUDIO;
+}
+
+AudioVPE::~AudioVPE()
+{
+}
+
+int AudioVPE::init(UCHAR tstreamType)
+{
+ if (initted) return 0;
+ initted = 1;
+
+// // if ((fdAudio = open("/dev/adec_mpg", O_RDWR | O_NONBLOCK)) < 0) return 0;
+ // if ((fdAudio = open("/dev/adec_mpg", O_WRONLY)) < 0) return 0;
+
+ streamType = tstreamType;
+
+ if (!initAllParams())
+ {
+ shutdown();
+ return 0;
+ }
+
+ unMute();
+
+ // Set the volume variable to what the hardware is set at now
+ int hwvol = -1;
+/* int hwvolFail = ioctl(fdAudio, AV_GET_AUD_VOLUME, &hwvol);
+ if (!hwvolFail)
+ {
+ volume = 20 - ((hwvol >> 16) & 0xFF);
+ if ((volume < 0) || (volume > 20)) volume = 20;
+ }*/
+
+ return 1;
+}
+
+int AudioVPE::initAllParams()
+{
+ return (setStreamType(streamType) && setChannel() && setSource());
+}
+
+int AudioVPE::shutdown()
+{
+ if (!initted) return 0;
+ initted = 0;
+ //close(fdAudio);
+ return 1;
+}
+
+int AudioVPE::setStreamType(UCHAR type)
+{
+ if (!initted) return 0;
+
+ // if (ioctl(fdAudio, AV_SET_AUD_STREAMTYPE, type) != 0) return 0;
+ return 1;
+}
+
+int AudioVPE::setChannel()
+{
+ if (!initted) return 0;
+
+ // if (ioctl(fdAudio, AV_SET_AUD_CHANNEL, 0) != 0) return 0;
+ return 1;
+}
+
+int AudioVPE::setSource()
+{
+ if (!initted) return 0;
+
+ // if (ioctl(fdAudio, AV_SET_AUD_SRC, 1) != 0) return 0;
+ return 1;
+}
+
+int AudioVPE::sync()
+{
+ if (!initted) return 0;
+
+ // if (ioctl(fdAudio, AV_SET_AUD_SYNC, 2) != 0) return 0;
+ return 1;
+}
+
+int AudioVPE::play()
+{
+ if (!initted) return 0;
+ lastpacketnum=-1;
+ currentpacketnum=-1;
+ ((VideoVPEOGL*) Video::getInstance())->initMuxer();
+
+ //if (ioctl(fdAudio, AV_SET_AUD_PLAY, 0) != 0) return 0;
+ return 1;
+}
+
+int AudioVPE::stop()
+{
+ if (!initted) return 0;
+ ((VideoVPEOGL*) Video::getInstance())->deinitMuxer();
+
+ //if (ioctl(fdAudio, AV_SET_AUD_RESET, 0x11) != 0) return 0;
+ return 1;
+}
+
+int AudioVPE::mute()
+{
+ if (!initted) return 0;
+
+// if (ioctl(fdAudio, AV_SET_AUD_MUTE, 1) != 0) return 0;
+ Log::getInstance()->log("Audio", Log::DEBUG, "MUTE MUTE MUTE");
+
+ muted = 1;
+ return 1;
+}
+
+int AudioVPE::unMute()
+{
+ if (!initted) return 0;
+
+// if (ioctl(fdAudio, AV_SET_AUD_MUTE, 0) != 0) return 0;
+ Log::getInstance()->log("Audio", Log::DEBUG, "MUTE OFF OFF OFF");
+
+ muted = 0;
+ return 1;
+}
+
+int AudioVPE::pause()
+{
+ if (!initted) return 0;
+
+ // if (ioctl(fdAudio, AV_SET_AUD_PAUSE, 1) != 0) return 0;
+ return 1;
+}
+
+int AudioVPE::unPause()
+{
+ if (!initted) return 0;
+
+ // if (ioctl(fdAudio, AV_SET_AUD_UNPAUSE, 1) != 0) return 0;
+ return 1;
+}
+
+int AudioVPE::reset()
+{
+ if (!initted) return 0;
+//test();
+ Log::getInstance()->log("Audio", Log::DEBUG, "reset called");
+ ((VideoVPEOGL*) Video::getInstance())->deinitMuxer();
+
+// if (ioctl(fdAudio, AV_SET_AUD_RESET, 0x11) != 0) return 0;
+// Log::getInstance()->log("Audio", Log::DEBUG, "reset back");
+ // if (ioctl(fdAudio, AV_SET_AUD_PLAY, 0) != 0) return 0;
+
+ doMuting();
+ return 1;
+}
+
+int AudioVPE::setVolume(int tvolume)
+{
+ // parameter: 0 for silence, 20 for full
+ if ((tvolume < 0) || (tvolume > 20)) return 0;
+
+// volume = 2 * (20 - volume);
+// Right, that one was rubbish... 0-10 were almost
+// inaudible, 11-20 did what should have been done
+// over the whole 0-20 range
+
+ tvolume = 20 - tvolume;
+
+ audio_volume Avolume;
+ Avolume.frontleft = tvolume + Aoffset.frontleft;
+ Avolume.frontright = tvolume + Aoffset.frontright;
+ Avolume.rearleft = tvolume + Aoffset.rearleft;
+ Avolume.rearright = tvolume + Aoffset.rearright;
+ Avolume.center = tvolume + Aoffset.center;
+ Avolume.lfe = tvolume + Aoffset.lfe;
+
+// if (ioctl(fdAudio, AV_SET_AUD_VOLUME, &Avolume) != 0) return 0;
+
+// unsigned long vol = (tvolume << 24) | (tvolume << 16);
+//
+// Log::getInstance()->log("Audio", Log::DEBUG, "%lx", vol);
+// Log::getInstance()->log("Audio", Log::DEBUG, "%i", tvolume);
+
+// if (ioctl(fdAudio, AV_SET_AUD_VOLUME, &vol) != 0) return 0;
+ return 1;
+}
+
+#ifdef DEV
+int AudioVPE::test()
+{
+// ULLONG stc = 0;
+// return ioctl(fdAudio, AV_SET_AUD_STC, &stc);
+
+/* aud_sync_parms_t a;
+ a.parm1 = 0;
+ a.parm2 = 0;
+*/
+// int b = ioctl(fdAudio, AV_SET_AUD_DISABLE_SYNC, &a);
+
+
+ /*OK*/ //printf("Audio sync disable = %i\n", b);
+
+ return 1;
+
+
+}
+#endif
+
+void AudioVPE::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)
+{
+ packet = mplist.front();
+}
+
+UINT AudioVPE::DeliverMediaSample(UCHAR* buffer, UINT* samplepos)
+{/*
+ VideoVPEOGL *video=(VideoVPEOGL*)Video::getInstance();
+ //Log::getInstance()->log("Audio", Log::DEBUG, "lastpacket %d lastbuddypacket %d currentpacket %d",lastpacketnum,video->getLastPacketNum(),packet.index);
+ currentpacketnum=packet.index;
+ if (lastpacketnum!=-1 && packet.index-1!=lastpacketnum && packet.index-1>video->getLastPacketNum()) return 0; //Not in order
+
+ //format pes
+ switch (packet.type) {
+ case MPTYPE_MPEG_AUDIO:
+ buffer[packet.pos_buffer + 3]=0xc0; break;
+ case MPTYPE_AC3:
+ buffer[packet.pos_buffer +buffer[packet.pos_buffer+8]+9]=0x80;
+ buffer[packet.pos_buffer + 3]=0xbd; break;
+ break;
+ default:
+ case MPTYPE_AC3_PRE13://Not tested no recording availiable
+ buffer[packet.pos_buffer + 3]=0xbd; break;
+ break;
+ };
+
+ if (packet.type!=lastAType && lastpacketnum!=-1){//Format Change //Push data out !
+ video->deinitMuxer();
+ lastAType=packet.type;
+ video->initMuxer();
+ }
+ lastAType=packet.type;
+
+
+ /* Mutex *mutex=video->getMuxMutex();
+ mutex->Lock();
+ FILE *muxout=video->getMuxFile();
+ if (!muxout) {mutex->Unlock(); return 0;}*
+ int written=0;
+ //written=fwrite(buffer + packet.pos_buffer,1,packet.length,muxout);
+ written=video->WriteOutTS(buffer + packet.pos_buffer,packet.length,packet.type);
+ lastpacketnum=packet.index;
+
+ //mutex->Unlock();
+
+ //Log::getInstance()->log("Audio", Log::DEBUG, "wrote %d bytes to mux",written);
+
+ if (written == (int)packet.length) { *samplepos = 0; return 1;}
+ if (written <= 0) {
+ return 0;
+ }
+ *samplepos = written;*/
+ // Handle a partial write. Is this possible? Should we bother? No!
+
+ return 1;
+}
+
+void AudioVPE::ResetTimeOffsets()
+{
+}
--- /dev/null
+/*\r
+ Copyright 2004-2005 Chris Tallon, 2009 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 AUDIOVPE_H\r
+#define AUDIOVPE_H\r
+\r
+#include <stdio.h>\r
+#include <unistd.h>\r
+#include <fcntl.h>\r
+#include <sys/ioctl.h>\r
+\r
+#include "defines.h"\r
+#include "audio.h"\r
+\r
+\r
+\r
+\r
+\r
+class AudioVPE : public Audio\r
+{\r
+ public:\r
+ AudioVPE();\r
+ virtual ~AudioVPE();\r
+\r
+ int init(UCHAR streamType);\r
+ int shutdown();\r
+\r
+ int setStreamType(UCHAR streamType);\r
+ int setChannel();\r
+ int setSource();\r
+ int sync();\r
+ int play();\r
+ int stop();\r
+ int pause();\r
+ int unPause();\r
+ int reset();\r
+ int setVolume(int volume);\r
+ int mute();\r
+ int unMute();\r
+ bool supportsAc3() { return true; }\r
+\r
+ //Writing Data to Audiodevice\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) { return 0; };\r
+ virtual void ResetTimeOffsets();\r
+\r
+ int getLastPacketNum() {return lastpacketnum;}; \r
+ int getCurrentPacketNum(){return currentpacketnum;};\r
+ UCHAR getLastAType() {return lastAType;}\r
+\r
+#ifdef DEV\r
+ int test();\r
+#endif\r
+\r
+ private:\r
+ int initAllParams();\r
+ UCHAR streamType;\r
+ UCHAR lastAType;\r
+ int lastpacketnum;\r
+ int currentpacketnum;\r
+\r
+ MediaPacket packet;\r
+ UINT packetpos;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ Copyright 2011 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef FEED_H\r
+#define FEED_H\r
+\r
+class Feed{\r
+public:\r
+ virtual void SignalFeeder()=0;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*
+ Copyright 2004-2005 Chris Tallon, 2011 Marten Richter
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "ledraspberry.h"
+
+LedRaspberry::LedRaspberry()
+{
+ initted = 0;
+}
+
+LedRaspberry::~LedRaspberry()
+{
+}
+
+int LedRaspberry::init(int tdevice)
+{
+ if (initted) return 0;
+ initted = 1;
+ return 1;
+}
+
+int LedRaspberry::shutdown()
+{
+ if (!initted) return 0;
+ initted = 0;
+ return 1;
+}
+
+int LedRaspberry::on()
+{
+ if (!initted) return 0;
+ return 0;
+}
+
+int LedRaspberry::off()
+{
+ if (!initted) return 0;
+ return 0;
+}
--- /dev/null
+/*
+ Copyright 2004-2005 Chris Tallon
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LEDRASPBERRY_H
+#define LEDRASPBERRY_H
+
+#include <stdio.h>
+
+#include "led.h"
+
+class LedRaspberry : public Led
+{
+ public:
+ LedRaspberry();
+ virtual ~LedRaspberry();
+
+ int init(int device);
+ int shutdown();
+
+ int on();
+ int off();
+
+ private:
+ int initted;
+};
+
+#endif
--- /dev/null
+/*
+ Copyright 2004-2005 Chris Tallon
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "mtdraspberry.h"
+#include "video.h"
+
+MtdRaspberry::MtdRaspberry()
+{
+ initted = 0;
+}
+
+MtdRaspberry::~MtdRaspberry()
+{
+}
+
+int MtdRaspberry::init()
+{
+ if (initted) return 0;
+ initted = 1;
+ return 1;
+}
+
+int MtdRaspberry::shutdown()
+{
+ if (!initted) return 0;
+ initted = 0;
+ return 1;
+}
+
+short MtdRaspberry::getPALorNTSC()
+{
+ return Video::PAL; //Fixme!
+}
+
--- /dev/null
+/*
+ Copyright 2004-2005 Chris Tallon, 2011 Marten Richter
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MTDRASPBERRY_H
+#define MTDRASPBERRY_H
+
+#include "mtd.h"
+
+class MtdRaspberry: public Mtd {
+public:
+ MtdRaspberry();
+ virtual ~MtdRaspberry();
+
+ virtual int init();
+ virtual int shutdown();
+
+ virtual short getPALorNTSC();
+
+private:
+ int initted;
+};
+
+#endif
+
--- /dev/null
+/*\r
+ Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+\r
+#include "osdopengl.h"\r
+#include "mtd.h"\r
+#include "videovpeogl.h"\r
+#include "surfaceopengl.h"\r
+\r
+\r
+#include "message.h"\r
+#include "command.h"\r
+\r
+#include "shaders/generic__vertex_shader.h"\r
+#include "shaders/osd__frag_shader.h"\r
+\r
+#define BACKBUFFER_WIDTH 1920\r
+#define BACKBUFFER_HEIGHT 1080\r
+\r
+\r
+\r
+long long getTimeMS() {\r
+ struct timespec ts;\r
+ clock_gettime(CLOCK_MONOTONIC, &ts);\r
+ return ts.tv_sec*1000+ts.tv_nsec/1000000LL;\r
+}\r
+\r
+\r
+\r
+OsdOpenGL::OsdOpenGL()\r
+{\r
+ glmutex.Lock();\r
+\r
+ external_driving=false;\r
+\r
+ lastrendertime=getTimeMS();\r
+ display_height=0;\r
+ display_width=0;\r
+ osd_shader=0;\r
+ gen_shader=0;\r
+ osd_program=0;\r
+\r
+\r
+ \r
+}\r
+\r
+OsdOpenGL::~OsdOpenGL()\r
+{\r
+\r
+ if (initted) \r
+ {\r
+ threadStop();\r
+ shutdown();\r
+ }\r
+\r
+\r
+ glmutex.Unlock();\r
+}\r
+\r
+int OsdOpenGL::getFD()\r
+{\r
+ if (!initted) return 0;\r
+ return fdOsd;\r
+}\r
+\r
+Surface * OsdOpenGL::createNewSurface() {\r
+ return (Surface*)new SurfaceOpenGL();\r
+}\r
+\r
+int OsdOpenGL::init(void* device)\r
+{\r
+ if (initted) return 0;\r
+ Video* video = Video::getInstance();\r
+ //window=*((HWND*)device);\r
+ \r
+ // May be this device specific part should go to a device specific child class\r
+\r
+ //init broadcom chipset (Move to video?)\r
+ bcm_host_init();\r
+\r
+ //First get connection to egl\r
+ egl_display=eglGetDisplay(EGL_DEFAULT_DISPLAY);\r
+\r
+ if (egl_display==EGL_NO_DISPLAY) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Could not get egl display!",eglGetError());\r
+ return 0;\r
+ }\r
+\r
+ if (eglInitialize(egl_display, NULL, NULL)==EGL_FALSE) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Initialising display failed! %d",eglGetError());\r
+ return 0;\r
+ }\r
+\r
+ const EGLint attributs[]={\r
+ EGL_RED_SIZE,8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,\r
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,\r
+ EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,\r
+ EGL_NONE\r
+ }; // Here, we might have to select the resolution!\r
+\r
+ EGLConfig ourconfig; //maybe accept more configs?\r
+ EGLint number;\r
+\r
+ if (eglChooseConfig(egl_display, attributs, &ourconfig, 1, &number)==EGL_FALSE) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Choosing egl config failed! %d",eglGetError());\r
+ return 0;\r
+ }\r
+\r
+ const EGLint attr_context[]={\r
+ EGL_CONTEXT_CLIENT_VERSION,2,\r
+ EGL_NONE\r
+ };\r
+\r
+ egl_context=eglCreateContext(egl_display,ourconfig,EGL_NO_CONTEXT,attr_context);\r
+ if (egl_context==EGL_NO_CONTEXT) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Creating egl context failed! %d",eglGetError());\r
+ return 0;\r
+ }\r
+\r
+ // warning broadcom specific, get display size!\r
+ display_width=display_height=0;\r
+ if (graphics_get_display_size(0, &display_width, &display_height)<0) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Getting display size failed! (BCM API) ");\r
+ return 0;\r
+ }\r
+ Log::getInstance()->log("OSD", Log::NOTICE, "Displaysize is %d x %d ",display_width, display_height);\r
+ VC_RECT_T dst_rect ={0,0,display_width,display_height};\r
+ VC_RECT_T src_rect={0,0,display_width<<16,display_height<<16};\r
+ DISPMANX_DISPLAY_HANDLE_T bcm_display;\r
+ DISPMANX_ELEMENT_HANDLE_T bcm_element;\r
+ DISPMANX_UPDATE_HANDLE_T bcm_update;\r
+\r
+\r
+ bcm_display=vc_dispmanx_display_open(0);\r
+ bcm_update=vc_dispmanx_update_start(0);\r
+ bcm_element=vc_dispmanx_element_add(bcm_update,bcm_display,\r
+ 0,&dst_rect, 0,\r
+ &src_rect,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);\r
+\r
+ vc_dispmanx_update_submit_sync(bcm_update);\r
+ static EGL_DISPMANX_WINDOW_T nativewindow;\r
+ nativewindow.element=bcm_element;\r
+ nativewindow.height=display_height;\r
+ nativewindow.width=display_width;\r
+\r
+ egl_surface = eglCreateWindowSurface(egl_display,ourconfig, &nativewindow,NULL );\r
+ if (egl_surface==EGL_NO_SURFACE) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Creating egl window surface failed!");\r
+ return 0;\r
+ }\r
+\r
+ if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed");\r
+ return 0;\r
+ }\r
+ // Test stuff\r
+\r
+\r
+\r
+ //Now we will create the Screen\r
+ screen = (Surface*) new SurfaceOpenGL(Surface::SCREEN);\r
+\r
+ screen->create(video->getScreenWidth(), video->getScreenHeight());\r
+ screen->display();\r
+ initted = 1; // must set this here or create surface won't work\r
+\r
+ //glGenBuffers(1, &vB);\r
+ //glGenBuffers(1, &iB);\r
+\r
+ //Preparing the Shaders\r
+\r
+ gen_shader=CreateShader(generic_vertex_shader, GL_VERTEX_SHADER);\r
+ osd_shader=CreateShader(osd_frag_shader, GL_FRAGMENT_SHADER);\r
+\r
+\r
+ osd_program=glCreateProgram();\r
+ if (osd_program==0) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Creating glsl program failed!%d",glGetError());\r
+ return 0;\r
+ }\r
+ glAttachShader(osd_program,gen_shader);\r
+ glAttachShader(osd_program,osd_shader);\r
+ glBindAttribLocation(osd_program,0,"vec_pos");\r
+ glBindAttribLocation(osd_program,1,"tex_coord");\r
+\r
+ osd_sampler_loc=glGetUniformLocation(osd_program,"texture");\r
+\r
+ glLinkProgram(osd_program);\r
+ GLint link_status;\r
+ glGetShaderiv(osd_program,GL_LINK_STATUS, &link_status);\r
+\r
+ if (!link_status) {\r
+ char buffer[1024];\r
+ glGetProgramInfoLog(osd_program,1024,NULL,buffer);\r
+ Log::getInstance()->log("OSD", Log::WARN, "Compiling Programm failed!");\r
+ Log::getInstance()->log("OSD", Log::WARN, "%s",buffer);\r
+ glDeleteProgram(osd_program);\r
+ return 0;\r
+ }\r
+\r
+ glClearColor(0.0f,0.0f,0.0f,1.f);\r
+\r
+ eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
+ glmutex.Unlock();\r
+ threadStart();\r
+\r
+ return 1;\r
+}\r
+\r
+\r
+GLuint OsdOpenGL::CreateShader(const GLchar * source, GLenum type)\r
+{\r
+ GLuint ret_shad=0;\r
+\r
+ ret_shad=glCreateShader(type);\r
+ if (ret_shad==0 ) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Creating Shader failed! %d",glGetError());\r
+ return 0;\r
+ }\r
+ glShaderSource(ret_shad,1,&source,NULL);\r
+ glCompileShader(ret_shad);\r
+ GLint comp_status;\r
+ glGetShaderiv(ret_shad,GL_COMPILE_STATUS, &comp_status);\r
+\r
+ if (!comp_status) {\r
+ char buffer[1024];\r
+ Log::getInstance()->log("OSD", Log::WARN, "Compiling Shader failed!");\r
+ glGetShaderInfoLog(ret_shad,1024,NULL,buffer);\r
+ Log::getInstance()->log("OSD", Log::WARN, "%s",buffer);\r
+ glDeleteShader(ret_shad);\r
+ return 0;\r
+ }\r
+ return ret_shad;\r
+}\r
+\r
+ \r
+void OsdOpenGL::InitVertexBuffer(float scalex,float scaley)\r
+{\r
+ Video* video=Video::getInstance();\r
+ float texx=((float)video->getScreenWidth())/1024.f;\r
+ float texy=((float)video->getScreenHeight())/1024.f;\r
+ OSDCOLOR osdcolor={1.f,1.f,1.f,1.f};\r
+\r
+ // osdvertices[0].c=osdcolor;\r
+ osdvertices[0].x= (scalex);\r
+ osdvertices[0].y=-scaley;\r
+ osdvertices[0].z=0.5;\r
+ osdvertices[0].u=texx;\r
+ osdvertices[0].v=texy;\r
+ // osdvertices[1].c=osdcolor;\r
+ osdvertices[1].x=(scalex);\r
+ osdvertices[1].y=(scaley);\r
+ osdvertices[1].z=0.5f;\r
+ osdvertices[1].u=texx;\r
+ osdvertices[1].v=0.f;\r
+ // osdvertices[0].c=osdcolor;\r
+ osdvertices[2].x=(-scalex);\r
+ osdvertices[2].y=-scaley;\r
+ osdvertices[2].z=0.5f;\r
+ osdvertices[2].u=0.f;\r
+ osdvertices[2].v=texy;\r
+ // osdvertices[3].c=osdcolor;\r
+ osdvertices[3].x=-scalex;\r
+ osdvertices[3].y=(scaley);\r
+ osdvertices[3].z=0.5f;\r
+ osdvertices[3].u=0.f;\r
+ osdvertices[3].v=0.f;\r
+ \r
+ osdindices[0]=0;\r
+ osdindices[1]=1;\r
+ osdindices[2]=2;\r
+ osdindices[3]=0;\r
+ osdindices[4]=2;\r
+ osdindices[5]=3;\r
+\r
+\r
+\r
+\r
+ // glBindBuffer(GL_ARRAY_BUFFER, vB);\r
+ // glBufferData(GL_ARRAY_BUFFER, sizeof(osdvertices), osdvertices, GL_STATIC_DRAW);\r
+\r
+\r
+ // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iB);\r
+ //glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(osdindices), osdindices, GL_STATIC_DRAW);\r
+\r
+\r
+\r
+ return;\r
+}\r
+\r
+int OsdOpenGL::shutdown()\r
+{\r
+ if (!initted) return 0;\r
+ initted = 0;\r
+\r
+\r
+ if (osd_shader!=0) glDeleteShader(osd_shader);\r
+ if (gen_shader!=0) glDeleteShader(gen_shader);\r
+ if (osd_program!=0) glDeleteProgram(osd_program);\r
+\r
+ glClear(GL_COLOR_BUFFER_BIT);\r
+ eglSwapBuffers(egl_display, egl_surface);\r
+ eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
+ eglDestroySurface(egl_display,egl_surface);\r
+ eglDestroyContext(egl_display,egl_context);\r
+ eglTerminate(egl_display );\r
+\r
+ return 1;\r
+}\r
+\r
+void OsdOpenGL::screenShot(const char* fileName)\r
+{\r
+ screen->screenShot(fileName);\r
+}\r
+\r
+void OsdOpenGL::threadMethod()\r
+{\r
+ // We have to claim the gl context for this thread\r
+ //glmutex.Lock();\r
+\r
+ //glmutex.Unlock();\r
+ while (true)\r
+ {\r
+ unsigned int waittime=10;\r
+ if (initted){\r
+ // if (evrstate==EVR_pres_off || evrstate==EVR_pres_pause)\r
+ // {\r
+ Render();\r
+ //TODO get surfaces from Video object\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) MILLISLEEP(min(10,waittime));\r
+ //Sleep(1);\r
+ }\r
+ //eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
+}\r
+\r
+\r
+void OsdOpenGL::threadPostStopCleanup()\r
+{\r
+ //Doing nothing\r
+ //goo;\r
+}\r
+\r
+\r
+// This function is called from the WinMain function in order to get Screen updates\r
+void OsdOpenGL::Render()\r
+{\r
+ if (!initted) return ;\r
+ if (external_driving) {\r
+ long long time1=getTimeMS();\r
+\r
+ if ((time1-lastrendertime)>200) {//5 fps for OSD updates are enough, avoids tearing\r
+ InternalRendering(NULL);\r
+ lastrendertime=getTimeMS();\r
+ } else {\r
+ //Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads\r
+ }\r
+ } else {\r
+ struct timespec ts;\r
+ clock_gettime(CLOCK_MONOTONIC, &ts);\r
+ long long time1=ts.tv_sec*1000+ts.tv_nsec/1000000LL;\r
+ if ((time1-lastrendertime)>50) {//10 fps for OSD updates are enough, avoids tearing\r
+ InternalRendering(NULL);\r
+ lastrendertime=getTimeMS();\r
+ } else {\r
+ //Sleep(5);\r
+ \r
+ }\r
+ \r
+ }\r
+}\r
+\r
+void OsdOpenGL::RenderDS(GLuint present){\r
+ if (!initted) return; \r
+ if (external_driving) {\r
+ InternalRendering(present);\r
+ lastrendertime=getTimeMS();\r
+ }\r
+}\r
+\r
+\r
+void OsdOpenGL::InternalRendering(GLuint 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
+\r
+\r
+ //InitVertexBuffer(display_width,display_height);\r
+ InitVertexBuffer(1.f,1.f);\r
+\r
+\r
+ glViewport(0, 0, display_width,display_height);\r
+\r
+ glClear(GL_COLOR_BUFFER_BIT);\r
+ glUseProgram(osd_program);\r
+\r
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), osdvertices);\r
+ glEnableVertexAttribArray(0);\r
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), &(osdvertices[0].u));\r
+ glEnableVertexAttribArray(1);\r
+\r
+\r
+\r
+\r
+ glActiveTexture(GL_TEXTURE0);\r
+ glBindTexture(GL_TEXTURE_2D,((SurfaceOpenGL*)screen)->getTexture());\r
+\r
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);\r
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);\r
+\r
+ glUniform1i(osd_sampler_loc,0);\r
+\r
+ glEnable(GL_BLEND);\r
+ glBlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_ZERO,GL_ONE);\r
+\r
+/* glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX),\r
+ (GLvoid*)(((char*)osdvertices)+3*sizeof(GLfloat)));\r
+ glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX),\r
+ (GLvoid*)(((char*)osdvertices)+3*sizeof(GLfloat)+sizeof(OSDCOLOR)));*/\r
+ //glDisable(GL_LIGHTING);\r
+ //glEnable(GL_TEXTURE_2D);\r
+ //glEnable(GL_BLEND);\r
+ //glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
+ //glDepthFunc(GL_ALWAYS);\r
+ //glDisable(GL_DEPTH_TEST);\r
+ //glDisable(GL_STENCIL_TEST);\r
+ //glDisable(GL_CULL_FACE);\r
+\r
+\r
+\r
+/*\r
+ glActiveTexture(GL_TEXTURE0);\r
+ glBindTexture(GL_TEXTURE_2D,((SurfaceOpenGL*)screen)->getTexture());\r
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);\r
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);*/\r
+// glUniform1i(mTextureUniformHandle, present);\r
+\r
+\r
+\r
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);\r
+\r
+ //glDrawElements(GL_TRIANGLES, sizeof(osdindices)/sizeof(osdindices[0]), GL_UNSIGNED_BYTE, 0);\r
+\r
+\r
+\r
+\r
+/* glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX), 0);\r
+ glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX),\r
+ (GLvoid*)(3*sizeof(GLfloat)));\r
+ glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE,sizeof(OSDVERTEX),\r
+ (GLvoid*)(3*sizeof(GLfloat)+sizeof(OSDCOLOR)));*/\r
+\r
+ //glDisable(GL_BLEND);\r
+ //glDisable(GL_TEXTURE_2D);\r
+ \r
+ //Show it to the user!\r
+ eglSwapBuffers(egl_display, egl_surface);\r
+\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 OsdOpenGL::DoLost(){\r
+ /*\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
+\r
+\r
+void OsdOpenGL::BeginPainting() {//We synchronize calls to d3d between different threads\r
+ glmutex.Lock();\r
+ if (initted) {\r
+ if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {\r
+ Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in thread %d",eglGetError());\r
+ return;\r
+ }\r
+ }\r
+}\r
+\r
+void OsdOpenGL::EndPainting() {\r
+ eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );\r
+ glmutex.Unlock();\r
+}\r
+\r
+void OsdOpenGL::setExternalDriving(/*DsAllocator* dsall,*/unsigned int width, unsigned 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 OsdOpenGL::Blank() {\r
+ BeginPainting();\r
+ glClearColor(0.15f, 0.25f, 0.35f, 1.0f); // change this to black after testing\r
+ glClear( GL_COLOR_BUFFER_BIT );\r
+ glClear( GL_DEPTH_BUFFER_BIT );\r
+ EndPainting();\r
+}\r
--- /dev/null
+/*\r
+ Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef OSDOPENGL_H\r
+#define OSDOPENGL_H\r
+\r
+#include <stdio.h>\r
+\r
+#include <bcm_host.h>\r
+\r
+#include <GLES2/gl2.h>\r
+#include <EGL/egl.h>\r
+#include <EGL/eglext.h>\r
+\r
+#include "osd.h"\r
+#include "defines.h"\r
+#include "log.h"\r
+#include "threadp.h"\r
+#include "mutex.h"\r
+\r
+\r
+\r
+\r
+\r
+\r
+struct OSDCOLOR{\r
+ GLfloat r;\r
+ GLfloat g;\r
+ GLfloat b;\r
+ GLfloat a;\r
+};\r
+\r
+\r
+struct OSDVERTEX {\r
+ GLfloat x;\r
+ GLfloat y;\r
+ GLfloat z;\r
+/* OSDCOLOR c;*/\r
+ GLfloat u;\r
+ GLfloat v;\r
+};\r
+\r
+\r
+\r
+\r
+\r
+\r
+class OsdOpenGL : public Osd, public Thread_TYPE\r
+{\r
+ public:\r
+ OsdOpenGL();\r
+ virtual ~OsdOpenGL();\r
+\r
+ int init(void* device);\r
+ int shutdown();\r
+\r
+ int getFD();\r
+\r
+ void screenShot(const char* fileName);\r
+\r
+ Surface * createNewSurface();\r
+\r
+\r
+\r
+\r
+ // This function is called from the threadMethod function in order to get Screen updates\r
+ void Render();\r
+ void RenderDS(GLuint present);\r
+ void BeginPainting();\r
+ void EndPainting();\r
+\r
+ void setExternalDriving(/*DsAllocator* dsall,*/ unsigned int width, unsigned int height);\r
+ void Blank();\r
+\r
+\r
+\r
+\r
+private:\r
+\r
+ //Maybe move the following stuff to a generic opengl object also for boosting DCT etc.\r
+\r
+ GLuint CreateShader(const GLchar * source, GLenum type);\r
+\r
+ void threadMethod();\r
+ void threadPostStopCleanup();\r
+\r
+ // This indicates, that currently a video is played, thus the osd updates are driven by the Videosystem\r
+ bool external_driving;\r
+ Mutex glmutex;\r
+ long long lastrendertime;\r
+ void InternalRendering(GLuint present);\r
+ bool DoLost();\r
+ void InitVertexBuffer(float scalex,float scaley);\r
+ OSDVERTEX osdvertices[4];\r
+ GLubyte osdindices[6];\r
+\r
+\r
+ GLuint osd_shader;\r
+ GLuint gen_shader;\r
+\r
+ GLuint osd_program;\r
+\r
+ GLint osd_sampler_loc;\r
+\r
+ /* BCM specific */\r
+\r
+ uint32_t display_height;\r
+ uint32_t display_width;\r
+\r
+ EGLDisplay egl_display;\r
+ EGLSurface egl_surface;\r
+ EGLContext egl_context;\r
+\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*
+ Copyright 2004-2005 Chris Tallon; 2012 Marten Richter
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "remotelinux.h"
+#include "i18n.h"
+#include <linux/input.h>
+#include <sys/types.h>
+
+
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+
+
+#define W_G_HCW(type,code) ( (((ULLONG)(type))<<32) | code)
+
+#define W_HCW_KC 1 /* key code as defined by kernel for keyboard and remotes through /dev/input */
+#define W_HCW_CEC 2 /* HDMI_CEC */
+#define W_HCW_LIRC 3 /* remote control LIRC*/
+
+
+RemoteLinux::RemoteLinux()
+{
+ initted = 0;
+ curevent=0;
+ hascurevent=false;
+ signal=false;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+}
+
+RemoteLinux::~RemoteLinux()
+{
+ for (unsigned int i=0; i<devices.size();i++) {
+ close(devices[i]);
+ }
+}
+
+#define test_bit(input,b) ((1 << ((b) % 8))&(input)[b / 8] )
+
+
+int RemoteLinux::init(char* devName)
+{
+ if (initted) return 0;
+ initted = 1;
+
+ InitKeymap();
+
+ for (int eventid=0;eventid<100;eventid++){
+ char buffer[1024];
+ sprintf(buffer,"/dev/input/event%d",eventid);
+
+
+ struct stat test_buf;
+ if (stat(buffer,&test_buf)==0) {
+ Log::getInstance()->log("Remote", Log::NOTICE, "Probe /dev/input/event%d",eventid);
+ // file exists
+ unsigned long ev_type=0;
+ int new_fd=open(buffer,O_RDONLY);
+ if (new_fd<0) {
+ Log::getInstance()->log("Remote", Log::NOTICE, "Can not open /dev/input/event%d",eventid);
+ continue;
+ }
+ if (ioctl(new_fd, EVIOCGBIT(0, EV_MAX), &ev_type) < 0) {
+ Log::getInstance()->log("Remote", Log::NOTICE, "Ioctl failed /dev/input/event%d %d",eventid,errno);
+ close(new_fd);
+ }
+ //Now test if it generates keyboard presses
+ if (test_bit((char*)&ev_type , EV_KEY)) {
+ Log::getInstance()->log("Remote", Log::NOTICE, "Add /dev/input/event%d to List",eventid);
+ devices.push_back(new_fd);
+ } else {
+ close(new_fd);
+ }
+
+
+
+
+ }
+
+ }
+
+
+
+
+ return 1;
+}
+
+int RemoteLinux::shutdown()
+{
+ if (!initted) return 0;
+
+ initted = 0;
+ return 1;
+}
+
+UCHAR RemoteLinux::getButtonPress(int waitType)
+{
+ /* how = 0 - block
+ how = 1 - start new wait
+ how = 2 - continue wait
+ how = 3 - no wait
+ */
+
+
+ struct timeval* passToSelect = NULL;
+ int retval;
+ fd_set readfds;
+
+ if (waitType == 0)
+ {
+ passToSelect = NULL;
+ }
+ else if (waitType == 1)
+ {
+ tv.tv_sec = 1;
+ tv.tv_usec = 000000;
+ passToSelect = &tv;
+ }
+ else if (waitType == 2)
+ {
+ if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) // protection in case timer = 0
+ {
+ tv.tv_sec = 1;
+ tv.tv_usec = 000000;
+ }
+ passToSelect = &tv;
+ }
+ else if (waitType == 3)
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ passToSelect = &tv;
+ }
+ FD_ZERO(&readfds);
+
+ int maxfd=0;
+ for (int i=0; i<devices.size();i++) {
+ int cur_fd=devices[i];
+ maxfd=max(cur_fd,maxfd);
+ FD_SET(cur_fd, &readfds);
+ }
+
+
+
+ retval = select(maxfd + 1, &readfds, NULL, NULL, &tv);
+ // 0 = nothing happened
+ // 1 = data arrived (actually num of descriptors that changed)
+ // other value = signal or error
+ if (retval == 0) return NA_NONE;
+ if (retval == -1) return NA_SIGNAL;
+
+
+ for (int i=0; i<devices.size();i++) {
+ int cur_fd=devices[i];
+ if (FD_ISSET(cur_fd, &readfds)) {
+ struct input_event ev;
+ int count = read(cur_fd, &ev, sizeof(ev));
+ if (count==sizeof(ev)) {
+ if (ev.type==EV_KEY && ev.value==1) {
+ return (UCHAR) TranslateHWC(W_G_HCW(W_HCW_KC,ev.code));
+ }
+ }
+
+ }
+
+ }
+
+ return NA_UNKNOWN;
+
+}
+
+void RemoteLinux::clearBuffer()
+{
+ while(getButtonPress(3) != NA_NONE);
+}
+
+UCHAR RemoteLinux::TranslateHWCFixed(ULLONG code)
+{
+ switch (code)
+ {
+ case W_G_HCW(W_HCW_KC,KEY_DOWN):
+ return DOWN;
+ case W_G_HCW(W_HCW_KC,KEY_UP):
+ return UP;
+ case W_G_HCW(W_HCW_KC,KEY_LEFT):
+ return LEFT;
+ case W_G_HCW(W_HCW_KC,KEY_RIGHT):
+ return RIGHT;
+ case W_G_HCW(W_HCW_KC,KEY_M):
+ return MENU;
+ case W_G_HCW(W_HCW_KC,KEY_BACKSPACE):
+ return BACK;
+ case W_G_HCW(W_HCW_KC,KEY_ENTER):
+ case W_G_HCW(W_HCW_KC,KEY_SPACE):
+ case W_G_HCW(W_HCW_KC,KEY_OK):
+ return OK;
+ case POWER:
+ return POWER;
+ default:
+ return NA_UNKNOWN;
+ };
+}
+
+const char*RemoteLinux::HardcodedTranslateStr(UCHAR command)
+{
+ switch (command)
+ {
+ case DOWN:
+ return tr("Down");
+ case UP:
+ return tr("Up");
+ case LEFT:
+ return tr("Left");
+ case RIGHT:
+ return tr("Right");
+ case MENU:
+ return tr("M");
+ case BACK:
+ return tr("Backspace, Back");
+ case OK:
+ return tr("Return, Space");
+ default:
+ return NULL;
+ };
+
+}
+
+
+void RemoteLinux::InitHWCListwithDefaults()
+{
+ //Processing VK_Messages
+ translist[W_G_HCW(W_HCW_KC,KEY_9)] = NINE;
+ translist[W_G_HCW(W_HCW_KC,KEY_8)] = EIGHT;
+ translist[W_G_HCW(W_HCW_KC,KEY_7)] = SEVEN;
+ translist[W_G_HCW(W_HCW_KC,KEY_6)] = SIX;
+ translist[W_G_HCW(W_HCW_KC,KEY_5)] = FIVE;
+ translist[W_G_HCW(W_HCW_KC,KEY_4)] = FOUR;
+ translist[W_G_HCW(W_HCW_KC,KEY_3)] = THREE;
+ translist[W_G_HCW(W_HCW_KC,KEY_2)] = TWO;
+ translist[W_G_HCW(W_HCW_KC,KEY_1)] = ONE;
+ translist[W_G_HCW(W_HCW_KC,KEY_0)] = ZERO;
+ translist[W_G_HCW(W_HCW_KC,KEY_KPDOT)] = STAR;
+ // translist[W_G_HCW(W_HCW_KC,KEY_#)] = HASH;
+
+ translist[W_G_HCW(W_HCW_KC,KEY_KP9)] = NINE;
+ translist[W_G_HCW(W_HCW_KC,KEY_KP8)] = EIGHT;
+ translist[W_G_HCW(W_HCW_KC,KEY_KP7)] = SEVEN;
+ translist[W_G_HCW(W_HCW_KC,KEY_KP6)] = SIX;
+ translist[W_G_HCW(W_HCW_KC,KEY_KP5)] = FIVE;
+ translist[W_G_HCW(W_HCW_KC,KEY_KP4)] = FOUR;
+ translist[W_G_HCW(W_HCW_KC,KEY_KP3)] = THREE;
+ translist[W_G_HCW(W_HCW_KC,KEY_KP2)] = TWO;
+ translist[W_G_HCW(W_HCW_KC,KEY_KP1)] = ONE;
+ translist[W_G_HCW(W_HCW_KC,KEY_KP0)] = ZERO;
+
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_9)] = NINE;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_8)] = EIGHT;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_7)] = SEVEN;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_6)] = SIX;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_5)] = FIVE;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_4)] = FOUR;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_3)] = THREE;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_2)] = TWO;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_1)] = ONE;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_0)] = ZERO;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_STAR)] = STAR;
+ translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_POUND)] = HASH;
+
+
+ translist[W_G_HCW(W_HCW_KC,KEY_J)] = GO; //j for JUMP TO instead of go to
+ translist[W_G_HCW(W_HCW_KC,KEY_R)] = RED;
+ translist[W_G_HCW(W_HCW_KC,KEY_G)] = GREEN;
+ translist[W_G_HCW(W_HCW_KC,KEY_Y)] = YELLOW;
+ translist[W_G_HCW(W_HCW_KC,KEY_B)] = BLUE;
+ //Processing Remote Style Messages
+ translist[W_G_HCW(W_HCW_KC,KEY_GREEN)] = GREEN;
+ translist[W_G_HCW(W_HCW_KC,KEY_RED)] = RED;
+ translist[W_G_HCW(W_HCW_KC,KEY_YELLOW)] = YELLOW;
+ translist[W_G_HCW(W_HCW_KC,KEY_BLUE)] = BLUE;
+ translist[W_G_HCW(W_HCW_KC,KEY_MENU)] = MENU;
+
+ translist[W_G_HCW(W_HCW_KC,KEY_RECORD)] = RECORD;
+ translist[W_G_HCW(W_HCW_KC,KEY_PLAY)] = PLAY; //Playback Televison
+ translist[W_G_HCW(W_HCW_KC,KEY_PAUSE)] = PAUSE;
+ translist[W_G_HCW(W_HCW_KC,KEY_STOP)] = STOP;
+ translist[W_G_HCW(W_HCW_KC,KEY_PLAYPAUSE)] = PLAYPAUSE;
+ translist[W_G_HCW(W_HCW_KC,KEY_P)] = PLAYPAUSE;
+ translist[W_G_HCW(W_HCW_KC,KEY_NEXT)] = SKIPFORWARD;
+ translist[W_G_HCW(W_HCW_KC,KEY_PREVIOUS)] = SKIPBACK;
+ translist[W_G_HCW(W_HCW_KC,KEY_FORWARD)] = FORWARD;
+ translist[W_G_HCW(W_HCW_KC,KEY_BACK)] = REVERSE;
+ translist[W_G_HCW(W_HCW_KC,KEY_MUTE)] = MUTE;
+ translist[W_G_HCW(W_HCW_KC,KEY_F9)] = VOLUMEUP;
+ translist[W_G_HCW(W_HCW_KC,KEY_F10)] = VOLUMEDOWN;
+ translist[W_G_HCW(W_HCW_KC,KEY_VOLUMEUP)] = VOLUMEUP;
+ translist[W_G_HCW(W_HCW_KC,KEY_VOLUMEDOWN)] = VOLUMEDOWN;
+ translist[W_G_HCW(W_HCW_KC,KEY_CHANNELUP)] = CHANNELUP;
+ translist[W_G_HCW(W_HCW_KC,KEY_CHANNELDOWN)] = CHANNELDOWN;
+ translist[W_G_HCW(W_HCW_KC,KEY_PAGEUP)] = CHANNELUP;
+ translist[W_G_HCW(W_HCW_KC,KEY_PAGEDOWN)] = CHANNELDOWN;
+
+
+}
+
+#define NAMETRICK(pre, code) linux_keymap[pre ## code]= #code
+//extracte from linux/input.h
+
+static const char * linux_keymap[KEY_MAX+1];
+
+void RemoteLinux::InitKeymap()
+{
+ for (int i=0;i<KEY_MAX+1;i++) {
+ linux_keymap[i]=NULL;
+ }
+ NAMETRICK(KEY_,RESERVED);
+ NAMETRICK(KEY_,ESC);
+ NAMETRICK(KEY_,1);
+ NAMETRICK(KEY_,2);
+ NAMETRICK(KEY_,3);
+ NAMETRICK(KEY_,4);
+ NAMETRICK(KEY_,5);
+ NAMETRICK(KEY_,6);
+ NAMETRICK(KEY_,7);
+ NAMETRICK(KEY_,8);
+ NAMETRICK(KEY_,9);
+ NAMETRICK(KEY_,0);
+ NAMETRICK(KEY_,MINUS);
+ NAMETRICK(KEY_,EQUAL);
+ NAMETRICK(KEY_,BACKSPACE);
+ NAMETRICK(KEY_,TAB);
+ NAMETRICK(KEY_,Q);
+ NAMETRICK(KEY_,W);
+ NAMETRICK(KEY_,E);
+ NAMETRICK(KEY_,R);
+ NAMETRICK(KEY_,T);
+ NAMETRICK(KEY_,Y);
+ NAMETRICK(KEY_,U);
+ NAMETRICK(KEY_,I);
+ NAMETRICK(KEY_,O);
+ NAMETRICK(KEY_,P);
+ NAMETRICK(KEY_,LEFTBRACE);
+ NAMETRICK(KEY_,RIGHTBRACE);
+ NAMETRICK(KEY_,ENTER);
+ NAMETRICK(KEY_,LEFTCTRL);
+ NAMETRICK(KEY_,A);
+ NAMETRICK(KEY_,S);
+ NAMETRICK(KEY_,D);
+ NAMETRICK(KEY_,F);
+ NAMETRICK(KEY_,G);
+ NAMETRICK(KEY_,H);
+ NAMETRICK(KEY_,J);
+ NAMETRICK(KEY_,K);
+ NAMETRICK(KEY_,L);
+ NAMETRICK(KEY_,SEMICOLON);
+ NAMETRICK(KEY_,APOSTROPHE);
+ NAMETRICK(KEY_,GRAVE);
+ NAMETRICK(KEY_,LEFTSHIFT);
+ NAMETRICK(KEY_,BACKSLASH);
+ NAMETRICK(KEY_,Z);
+ NAMETRICK(KEY_,X);
+ NAMETRICK(KEY_,C);
+ NAMETRICK(KEY_,V);
+ NAMETRICK(KEY_,B);
+ NAMETRICK(KEY_,N);
+ NAMETRICK(KEY_,M);
+ NAMETRICK(KEY_,COMMA);
+ NAMETRICK(KEY_,DOT);
+ NAMETRICK(KEY_,SLASH);
+ NAMETRICK(KEY_,RIGHTSHIFT);
+ NAMETRICK(KEY_,KPASTERISK);
+ NAMETRICK(KEY_,LEFTALT);
+ NAMETRICK(KEY_,SPACE);
+ NAMETRICK(KEY_,CAPSLOCK);
+ NAMETRICK(KEY_,F1);
+ NAMETRICK(KEY_,F2);
+ NAMETRICK(KEY_,F3);
+ NAMETRICK(KEY_,F4);
+ NAMETRICK(KEY_,F5);
+ NAMETRICK(KEY_,F6);
+ NAMETRICK(KEY_,F7);
+ NAMETRICK(KEY_,F8);
+ NAMETRICK(KEY_,F9);
+ NAMETRICK(KEY_,F10);
+ NAMETRICK(KEY_,NUMLOCK);
+ NAMETRICK(KEY_,SCROLLLOCK);
+ NAMETRICK(KEY_,KP7);
+ NAMETRICK(KEY_,KP8);
+ NAMETRICK(KEY_,KP9);
+ NAMETRICK(KEY_,KPMINUS);
+ NAMETRICK(KEY_,KP4);
+ NAMETRICK(KEY_,KP5);
+ NAMETRICK(KEY_,KP6);
+ NAMETRICK(KEY_,KPPLUS);
+ NAMETRICK(KEY_,KP1);
+ NAMETRICK(KEY_,KP2);
+ NAMETRICK(KEY_,KP3);
+ NAMETRICK(KEY_,KP0);
+ NAMETRICK(KEY_,KPDOT);
+ NAMETRICK(KEY_,F11);
+ NAMETRICK(KEY_,F12);
+ NAMETRICK(KEY_,KPENTER);
+ NAMETRICK(KEY_,RIGHTCTRL);
+ NAMETRICK(KEY_,KPSLASH);
+ NAMETRICK(KEY_,SYSRQ);
+ NAMETRICK(KEY_,RIGHTALT);
+ NAMETRICK(KEY_,LINEFEED);
+ NAMETRICK(KEY_,HOME);
+ NAMETRICK(KEY_,UP);
+ NAMETRICK(KEY_,PAGEUP);
+ NAMETRICK(KEY_,LEFT);
+ NAMETRICK(KEY_,RIGHT);
+ NAMETRICK(KEY_,END);
+ NAMETRICK(KEY_,DOWN);
+ NAMETRICK(KEY_,PAGEDOWN);
+ NAMETRICK(KEY_,INSERT);
+ NAMETRICK(KEY_,DELETE);
+ NAMETRICK(KEY_,MACRO);
+ NAMETRICK(KEY_,MUTE);
+ NAMETRICK(KEY_,VOLUMEDOWN);
+ NAMETRICK(KEY_,VOLUMEUP);
+ NAMETRICK(KEY_,POWER);
+ NAMETRICK(KEY_,KPEQUAL);
+ NAMETRICK(KEY_,KPPLUSMINUS);
+ NAMETRICK(KEY_,PLAY);
+ NAMETRICK(KEY_,PAUSE);
+ NAMETRICK(KEY_,SCALE);
+ NAMETRICK(KEY_,KPCOMMA);
+ NAMETRICK(KEY_,YEN);
+ NAMETRICK(KEY_,LEFTMETA);
+ NAMETRICK(KEY_,RIGHTMETA);
+ NAMETRICK(KEY_,COMPOSE);
+ NAMETRICK(KEY_,STOP);
+ NAMETRICK(KEY_,AGAIN);
+ NAMETRICK(KEY_,PROPS);
+ NAMETRICK(KEY_,UNDO);
+ NAMETRICK(KEY_,FRONT);
+ NAMETRICK(KEY_,COPY);
+ NAMETRICK(KEY_,OPEN);
+ NAMETRICK(KEY_,PASTE);
+ NAMETRICK(KEY_,FIND);
+ NAMETRICK(KEY_,CUT);
+ NAMETRICK(KEY_,HELP);
+ NAMETRICK(KEY_,MENU);
+ NAMETRICK(KEY_,CALC);
+ NAMETRICK(KEY_,SETUP);
+ NAMETRICK(KEY_,SLEEP);
+ NAMETRICK(KEY_,WAKEUP);
+ NAMETRICK(KEY_,FILE);
+ NAMETRICK(KEY_,SENDFILE);
+ NAMETRICK(KEY_,DELETEFILE);
+ NAMETRICK(KEY_,XFER);
+ NAMETRICK(KEY_,PROG1);
+ NAMETRICK(KEY_,PROG2);
+ NAMETRICK(KEY_,WWW);
+ NAMETRICK(KEY_,MSDOS);
+ NAMETRICK(KEY_,COFFEE);
+ NAMETRICK(KEY_,DIRECTION);
+ NAMETRICK(KEY_,CYCLEWINDOWS);
+ NAMETRICK(KEY_,MAIL);
+ NAMETRICK(KEY_,BOOKMARKS);
+ NAMETRICK(KEY_,COMPUTER);
+ NAMETRICK(KEY_,BACK);
+ NAMETRICK(KEY_,FORWARD);
+ NAMETRICK(KEY_,CLOSECD);
+ NAMETRICK(KEY_,EJECTCD);
+ NAMETRICK(KEY_,EJECTCLOSECD);
+ NAMETRICK(KEY_,NEXTSONG);
+ NAMETRICK(KEY_,PLAYPAUSE);
+ NAMETRICK(KEY_,PREVIOUSSONG);
+ NAMETRICK(KEY_,STOPCD);
+ NAMETRICK(KEY_,RECORD);
+ NAMETRICK(KEY_,REWIND);
+ NAMETRICK(KEY_,PHONE);
+ NAMETRICK(KEY_,ISO);
+ NAMETRICK(KEY_,CONFIG);
+ NAMETRICK(KEY_,HOMEPAGE);
+ NAMETRICK(KEY_,REFRESH);
+ NAMETRICK(KEY_,EXIT);
+ NAMETRICK(KEY_,MOVE);
+ NAMETRICK(KEY_,EDIT);
+ NAMETRICK(KEY_,SCROLLUP);
+ NAMETRICK(KEY_,SCROLLDOWN);
+ NAMETRICK(KEY_,KPLEFTPAREN);
+ NAMETRICK(KEY_,KPRIGHTPAREN);
+ NAMETRICK(KEY_,NEW);
+ NAMETRICK(KEY_,REDO);
+ NAMETRICK(KEY_,OK);
+ NAMETRICK(KEY_,SELECT);
+ NAMETRICK(KEY_,GOTO);
+ NAMETRICK(KEY_,CLEAR);
+ NAMETRICK(KEY_,POWER2);
+ NAMETRICK(KEY_,OPTION);
+ NAMETRICK(KEY_,INFO);
+ NAMETRICK(KEY_,TIME);
+ NAMETRICK(KEY_,VENDOR);
+ NAMETRICK(KEY_,ARCHIVE);
+ NAMETRICK(KEY_,PROGRAM);
+ NAMETRICK(KEY_,CHANNEL);
+ NAMETRICK(KEY_,FAVORITES);
+ NAMETRICK(KEY_,EPG);
+ NAMETRICK(KEY_,PVR);
+ NAMETRICK(KEY_,MHP);
+ NAMETRICK(KEY_,LANGUAGE);
+ NAMETRICK(KEY_,TITLE);
+ NAMETRICK(KEY_,SUBTITLE);
+ NAMETRICK(KEY_,ANGLE);
+ NAMETRICK(KEY_,ZOOM);
+ NAMETRICK(KEY_,MODE);
+ NAMETRICK(KEY_,KEYBOARD);
+ NAMETRICK(KEY_,SCREEN);
+ NAMETRICK(KEY_,RED);
+ NAMETRICK(KEY_,GREEN);
+ NAMETRICK(KEY_,YELLOW);
+ NAMETRICK(KEY_,BLUE);
+ NAMETRICK(KEY_,CHANNELUP);
+ NAMETRICK(KEY_,CHANNELDOWN);
+ NAMETRICK(KEY_,FIRST);
+ NAMETRICK(KEY_,LAST);
+ NAMETRICK(KEY_,AB);
+ NAMETRICK(KEY_,NEXT);
+ NAMETRICK(KEY_,RESTART);
+ NAMETRICK(KEY_,SLOW);
+ NAMETRICK(KEY_,SHUFFLE);
+ NAMETRICK(KEY_,BREAK);
+ NAMETRICK(KEY_,PREVIOUS);
+ NAMETRICK(KEY_,DIGITS);
+ NAMETRICK(KEY_,TEEN);
+ NAMETRICK(KEY_,TWEN);
+ NAMETRICK(KEY_,VIDEOPHONE);
+ NAMETRICK(KEY_,GAMES);
+ NAMETRICK(KEY_,ZOOMIN);
+ NAMETRICK(KEY_,ZOOMOUT);
+ NAMETRICK(KEY_,ZOOMRESET);
+ NAMETRICK(KEY_,DOLLAR);
+ NAMETRICK(KEY_,EURO);
+ NAMETRICK(KEY_,FRAMEBACK);
+ NAMETRICK(KEY_,FRAMEFORWARD);
+ NAMETRICK(KEY_,CONTEXT_MENU);
+ NAMETRICK(KEY_,MEDIA_REPEAT);
+ NAMETRICK(KEY_,NUMERIC_0);
+ NAMETRICK(KEY_,NUMERIC_1);
+ NAMETRICK(KEY_,NUMERIC_2);
+ NAMETRICK(KEY_,NUMERIC_3);
+ NAMETRICK(KEY_,NUMERIC_4);
+ NAMETRICK(KEY_,NUMERIC_5);
+ NAMETRICK(KEY_,NUMERIC_6);
+ NAMETRICK(KEY_,NUMERIC_7);
+ NAMETRICK(KEY_,NUMERIC_8);
+ NAMETRICK(KEY_,NUMERIC_9);
+ NAMETRICK(KEY_,NUMERIC_STAR);
+ NAMETRICK(KEY_,NUMERIC_POUND);
+
+
+
+}
+
+
+
+char* RemoteLinux::HCWDesc(unsigned long long hcw)
+{
+ //Determine type
+ unsigned int type = hcw >> 32;
+ char *rt=NULL;
+ switch(type)
+ {
+ case W_HCW_KC:{
+ unsigned int vk=(ULONG)hcw;
+ rt=new char[10];
+ const char *desc=linux_keymap[vk];
+ if (desc) {
+ strncpy(rt,desc,9);
+ } else {
+ sprintf(rt,"0x%x",vk);
+ }
+ }break;
+ //TODO
+ /* case W_HCW_CEC:{
+ ULONG ch=(ULONG)hcw;
+ ULONG scancode=OemKeyScan(ch);
+
+ rt=new char[10];
+ GetKeyNameText(scancode << 16,rt,10);
+ }break;
+ case W_HCW_LIRC:{
+ ULONG ri=(ULONG)hcw;
+ rt=new char[10];
+ sprintf(rt,"R: %X",ri);
+ }break;*/
+
+ };
+ return rt;
+}
+
+
+
+
+
+
+
+/*
+void RemoteLinux::Signal() {
+ signal=true;
+ //PulseEvent(event);
+ SetEvent(event);
+}
+
+void RemoteLinux::SendPower()
+{
+
+ curevent=POWER;
+ hascurevent=true;
+ SetEvent(event);
+}*/
+
--- /dev/null
+/*
+ Copyright 2004-2005 Chris Tallon; 2012 Marten Richter
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef REMOTELINUX_H
+#define REMOTELINUX_H
+
+#include <stdio.h>
+
+#include "defines.h"
+#include "log.h"
+#include "remote.h"
+
+#include <vector>
+
+
+
+
+
+class RemoteLinux : public Remote
+{
+ public:
+ RemoteLinux();
+ virtual ~RemoteLinux();
+
+ int init(char *devName);
+ int shutdown();
+ int getDevice();
+ UCHAR getButtonPress(int how);
+ void clearBuffer();
+ // void Signal();
+
+// void SendPower();
+ void InitHWCListwithDefaults();
+ const char*HardcodedTranslateStr(UCHAR command);
+ char* HCWDesc(ULLONG hcw);
+
+
+
+ private:
+ int initted;
+ bool signal;
+ UCHAR curevent;
+ bool hascurevent;
+
+ UCHAR TranslateHWCFixed(ULLONG code);
+ void InitKeymap();
+ vector<int> devices;
+ struct timeval tv;
+
+};
+
+#endif
+
--- /dev/null
+/*\r
+ Copyright 2012 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef OSD_GEN_SHADER_H\r
+#define OSD_GEN_SHADER_H\r
+\r
+const GLchar generic_vertex_shader[] =\r
+ "attribute vec4 vec_pos;\n"\r
+ "attribute vec2 tex_coord;\n"\r
+ "varying vec2 out_texCoord;\n"\r
+ "void main()\n"\r
+ "{\n"\r
+ " gl_Position=vec_pos;\n"\r
+ " out_texCoord=tex_coord;\n"\r
+ "}\n";\r
+#endif\r
--- /dev/null
+/*\r
+ Copyright 2012 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef OSD_FRAG_SHADER_H\r
+#define OSD_FRAG_SHADER_H\r
+\r
+const GLchar osd_frag_shader[] =\r
+ "precision mediump float;\n"\r
+ "uniform sampler2D texture;"\r
+ "varying vec2 out_texCoord;\n"\r
+ "void main()\n"\r
+ "{\n"\r
+ // " vec4 temp=vec4(0.3,0.4,0.5,0.5);\n"\r
+ // " temp.r=0.6;\n"\r
+ " gl_FragColor=texture2D(texture,out_texCoord);\n"\r
+ // " temp.r=temp2.r;\n"\r
+ // " temp.b=temp2.b;\n"\r
+ // "gl_FragColor=temp;\n"\r
+ "}\n";\r
+#endif\r
+//"vec4 temp=vec4(0.3,0.4,0.5);\n"\r
+// "temp.a=1.0f;\n"\r
+// " gl_FragColor.r=texture2D(texture,out_texCoord.st).r;\n"\r
+// " gl_FragColor.b=0.2f;\n"\r
+// " gl_FragColor.g=0.2f;\n"\r
+// "gl_FragColor.a=0.5f;\n"\r
+//"gl_FragColor=vec4(0.3,0.4,0.5,0.5);\n"\r
--- /dev/null
+/*\r
+ Copyright 2006 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#include <stdlib.h>\r
+\r
+#include "surfaceopengl.h"\r
+#include "osdopengl.h"\r
+#include "bitmap.h"\r
+#include "log.h"\r
+#include "mutex.h"\r
+\r
+inline unsigned int InternalColour(unsigned int c){\r
+ return (c &0x000000FF)<<16 |\r
+ (c &0x0000FF00) |\r
+ (c &0x00FF0000)>>16 |\r
+ (c &0xFF000000);\r
+}\r
+\r
+SurfaceOpenGL::SurfaceOpenGL(int id)\r
+: Surface(id)\r
+{\r
+ gltexture=0;\r
+ data=NULL;\r
+ sheight=swidth=0;\r
+// fastdraw=false;\r
+ srf_mutex.Lock();\r
+}\r
+\r
+SurfaceOpenGL::~SurfaceOpenGL()\r
+{\r
+ srf_mutex.Lock();\r
+ if (data) {\r
+ free(data);\r
+ data=NULL;\r
+ } else {\r
+ glDeleteTextures(1,&gltexture);\r
+ }\r
+ srf_mutex.Unlock();\r
+}\r
+\r
+int SurfaceOpenGL::create(UINT width, UINT height)\r
+{\r
+ OsdOpenGL* osd=((OsdOpenGL*)(Osd::getInstance()));\r
+ //osd->BeginPainting();\r
+\r
+\r
+ if (this == screen) { // We do not need locking here, since the osd calls this\r
+ sheight = 64;\r
+ swidth = 64;\r
+ while (sheight < height) { // should be a power of 2\r
+ sheight *= 2;\r
+ }\r
+ while (swidth < width) { // should be a power of 2\r
+ swidth *= 2;\r
+ }\r
+ glGenTextures(1, &gltexture);\r
+\r
+ glBindTexture(GL_TEXTURE_2D, gltexture);\r
+\r
+ void *image = malloc(sheight * swidth * 4);\r
+ memset(image, 0, sheight * swidth * 4);\r
+ /* for (int i=0;i< sheight * swidth * 4; i++) { //fill it with garbage, useful for debugging\r
+ ((char*)image)[i]=i%255;\r
+ }*/\r
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, swidth, sheight, 0, GL_RGBA,\r
+ GL_UNSIGNED_BYTE, image);\r
+\r
+ } else {\r
+ sheight = height;\r
+ swidth = width;\r
+ data=(char*)malloc(sizeof(uint32_t)*width*height);\r
+ }\r
+\r
+\r
+ //osd->EndPainting();\r
+ srf_mutex.Unlock();\r
+ return 1;\r
+}\r
+\r
+void SurfaceOpenGL::display()\r
+{\r
+}\r
+\r
+int SurfaceOpenGL::fillblt(int x, int y, int width, int height, unsigned int c) {\r
+ srf_mutex.Lock();\r
+ //since this might be called before surface\r
+ //allocation we will wait in this case, hopefully without deadlocks\r
+ if (screen == this || !data ) {\r
+ //This should not happen!\r
+ srf_mutex.Unlock();\r
+ return 0;\r
+\r
+ }\r
+ /* OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+ osd->BeginPainting();\r
+\r
+ glViewport(0,0,swidth,sheight);*/\r
+\r
+ //osd->EndPainting();\r
+ srf_mutex.Unlock();\r
+\r
+ unsigned int my_c=InternalColour(c);\r
+\r
+ int iheight=height;\r
+ if (height+y>sheight) iheight=sheight-y;\r
+ int iwidth=width;\r
+ if (width+x>swidth) iwidth=swidth-y;\r
+\r
+ unsigned int line;\r
+ unsigned int column;\r
+ for (line = y; line < (iheight + y); line++) {\r
+ uint32_t *row = ((unsigned int*) (((char*) data) + (swidth * line + x)\r
+ * sizeof(uint32_t)));\r
+ for (column = 0; column < iwidth; column++) {\r
+ row[column] = my_c;\r
+ }\r
+ }\r
+\r
+/* if (d3dsurface->UnlockRect() != D3D_OK) {\r
+ osd->EndPainting();\r
+ return 0;\r
+ }\r
+ osd->EndPainting();*/\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+void SurfaceOpenGL::startFastDraw(){\r
+ srf_mutex.Lock();\r
+\r
+}\r
+void SurfaceOpenGL::endFastDraw(){\r
+ srf_mutex.Unlock();\r
+ }\r
+\r
+void SurfaceOpenGL::drawPixel(int x, int y, Colour & colour, bool fastdraw) {\r
+ int c = ( (0xFF000000 )\r
+ | (colour.red << 16)\r
+ | (colour.green << 8)\r
+ | (colour.blue ) );\r
+\r
+ drawPixel(x, y, c, fastdraw);\r
+ }\r
+\r
+void SurfaceOpenGL::drawPixel(int x, int y, unsigned int c, bool fastdraw) {\r
+ //FixMe: locking for every single Pixel will be painfully slow\r
+ if (screen == this) {\r
+ //This should not happen!\r
+ return ;\r
+ }\r
+ if (!data) {\r
+ return; //why does this happen\r
+ }\r
+ //OsdWin* osd;\r
+ if (!fastdraw) {\r
+ srf_mutex.Lock(); //since this might be called before surface\r
+ }\r
+ //allocation we will wait in this case, hopefully without deadlocks\r
+\r
+ //osd = ((OsdWin*) (Osd::getInstance()));\r
+\r
+ if (x >= swidth || y >= sheight)\r
+ return; //do not draw outside the surface\r
+\r
+ unsigned int my_c=InternalColour(c);\r
+\r
+ unsigned int*row = (unsigned int*) (((char*) data + (swidth * y + x)\r
+ * sizeof(uint32_t)));\r
+ row[0] = my_c;\r
+\r
+ if (!fastdraw) {\r
+ srf_mutex.Unlock(); //since this might be called before surface\r
+ }\r
+\r
+}\r
+\r
+void SurfaceOpenGL::drawHorzLine(int x1, int x2, int y, unsigned int c)\r
+{\r
+ fillblt(x1, y, x2-x1, 1, c);\r
+}\r
+\r
+void SurfaceOpenGL::drawVertLine(int x, int y1, int y2, unsigned int c)\r
+{\r
+ fillblt(x, y1, 1, y2-y1, c);\r
+}\r
+\r
+void SurfaceOpenGL::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 SurfaceOpenGL::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME\r
+{\r
+ srf_mutex.Lock();//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
+ OsdOpenGL* osd=((OsdOpenGL*)(Osd::getInstance()));\r
+\r
+ GLuint screengltexture=((SurfaceOpenGL*)screen)->getTexture();\r
+\r
+ osd->BeginPainting();\r
+ glBindTexture(GL_TEXTURE_2D, screengltexture);\r
+ //Log::getInstance()->log("Surface", Log::WARN, "UTS Mark3 %d",glGetError());\r
+\r
+ for (int y=0;y<h;y++) { //hopefully this is not too slow\r
+ glTexSubImage2D(GL_TEXTURE_2D,0,dx,(dy+y),w,1,GL_RGBA,GL_UNSIGNED_BYTE,\r
+ data+((y+sy)*swidth+sx)*sizeof(uint32_t));\r
+ // Log::getInstance()->log("Surface", Log::WARN, "UTS Mark43 %d",glGetError());\r
+\r
+ }\r
+ //Log::getInstance()->log("Surface", Log::WARN, "UTS Mark4 %d",glGetError());\r
+ osd->EndPainting();\r
+ srf_mutex.Unlock();\r
+ return 0;\r
+}\r
+\r
+int SurfaceOpenGL::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)\r
+{\r
+ //I don't see code using this function, so I skip it, since it is a MVP specific interface\r
+ return 0;\r
+}\r
+\r
+void SurfaceOpenGL::screenShot(const char* fileName)\r
+{\r
+ //Isn't this for debugging only, so I won't implement it yet\r
+}\r
+\r
+void SurfaceOpenGL::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)\r
+{\r
+ //Isn't this for debugging only, so I won't implement it yet\r
+}\r
+\r
+\r
+void SurfaceOpenGL::drawJpeg(const char *fileName,int x, int y,int *width, int *height){\r
+}/*\r
+ WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+ //allocation we will wait in this case, hopefully without deadlocks\r
+ if (!d3dsurface) {\r
+ return ; //why does this happen\r
+ }\r
+ OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+\r
+ D3DXIMAGE_INFO image_inf;\r
+ osd->BeginPainting();\r
+// D3DXGetImageInfoFromFile(fileName,&image_inf);\r
+ D3DXGetImageInfoFromResource(NULL,fileName,&image_inf);\r
+ RECT dest_rec={x,y,x+image_inf.Width,\r
+ y+image_inf.Height};\r
+/* if (D3DXLoadSurfaceFromFile(\r
+ d3dsurface,\r
+ NULL,\r
+ &dest_rec,\r
+ fileName,\r
+ NULL,\r
+ D3DX_FILTER_NONE,\r
+ 0,\r
+ &image_inf)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+ }*\r
+ if (D3DXLoadSurfaceFromResource(\r
+ d3dsurface,\r
+ NULL,\r
+ &dest_rec,\r
+ NULL,\r
+ fileName,\r
+ NULL,\r
+ D3DX_FILTER_NONE,\r
+ 0,\r
+ &image_inf)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+ }\r
+ osd->EndPainting();\r
+ *width=image_inf.Width;\r
+ *height=image_inf.Height;\r
+\r
+}*/\r
+\r
+/*\r
+void SurfaceOpenGL::drawJpeg(char *buffer,ULONG buflength,DWORD x, DWORD y,DWORD *width, DWORD *height){\r
+ WaitForSingleObject(event,INFINITE); //since this might be called before surface\r
+ //allocation we will wait in this case, hopefully without deadlocks\r
+ if (!d3dsurface) {\r
+ return ; //why does this happen\r
+ }\r
+ OsdWin* osd=((OsdWin*)(Osd::getInstance()));\r
+\r
+\r
+ D3DXIMAGE_INFO image_inf;\r
+ osd->BeginPainting();\r
+// D3DXGetImageInfoFromFile(fileName,&image_inf);\r
+ D3DXGetImageInfoFromFileInMemory((void*)buffer,buflength,&image_inf);\r
+ RECT dest_rec={x,y,x+image_inf.Width,\r
+ y+image_inf.Height};\r
+/* if (D3DXLoadSurfaceFromFile(\r
+ d3dsurface,\r
+ NULL,\r
+ &dest_rec,\r
+ fileName,\r
+ NULL,\r
+ D3DX_FILTER_NONE,\r
+ 0,\r
+ &image_inf)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+ }*/\r
+/* if (D3DXLoadSurfaceFromResource(\r
+ d3dsurface,\r
+ NULL,\r
+ &dest_rec,\r
+ NULL,\r
+ fileName,\r
+ NULL,\r
+ D3DX_FILTER_NONE,\r
+ 0,\r
+ &image_inf)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+ }*\r
+ if (D3DXLoadSurfaceFromFileInMemory(\r
+ d3dsurface,\r
+ NULL,\r
+ &dest_rec,\r
+ (void*)buffer,\r
+ buflength,\r
+ NULL,\r
+ D3DX_FILTER_NONE,\r
+ 0,\r
+ &image_inf)!=D3D_OK) {\r
+ Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!");\r
+\r
+ }\r
+ osd->EndPainting();\r
+ *width=image_inf.Width;\r
+ *height=image_inf.Height;\r
+\r
+}*/\r
+\r
--- /dev/null
+/*\r
+ Copyright 2006, 2011-2012 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef SURFACEOPENGL_H\r
+#define SURFACEOPENGL_H\r
+\r
+#include "defines.h"\r
+#include "surface.h"\r
+#include "mutex.h"\r
+#include <GLES2/gl2.h>\r
+\r
+class SurfaceOpenGL : public Surface\r
+{\r
+ public:\r
+ SurfaceOpenGL(int id = 0);\r
+ virtual ~SurfaceOpenGL();\r
+\r
+ int create(UINT width, UINT height);\r
+ void display();\r
+\r
+ void startFastDraw();\r
+ void endFastDraw();\r
+\r
+ int fillblt(int x, int y, int width, int height, 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
+\r
+ GLuint getTexture() {return gltexture;};\r
+\r
+\r
+\r
+ private:\r
+ GLuint gltexture;\r
+ UINT sheight,swidth;\r
+ char * data;\r
+\r
+\r
+\r
+ Mutex srf_mutex;\r
+\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*
+ Copyright 2004-2005 Chris Tallon
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "threadpandroid.h"
+#include "log.h"
+
+// Undeclared functions, only for use in this file to start the thread
+void threadPAndroidInternalStart(void *arg)
+{
+ // I don't want signals
+ sigset_t sigs;
+ sigfillset(&sigs);
+ pthread_sigmask(SIG_BLOCK, &sigs, NULL);
+
+ Thread *t = (Thread *)arg;
+ t->threadInternalStart2();
+}
+
+int ThreadPAndroid ::threadStart()
+{
+ pthread_cond_init(&threadCond, NULL);
+ pthread_cond_init(&threadKillable, NULL);
+ pthread_mutex_init(&threadCondMutex, NULL);
+
+ threadActive = 1;
+ killable=false;
+ if (pthread_create(&pthread, NULL, (void*(*)(void*))threadPAndroidInternalStart, (void *)this) == -1) return 0;
+ return 1;
+}
+
+void ThreadPAndroid ::threadStop()
+{
+ threadActive = 0;
+ // Signal thread here in case it's waiting
+ threadSignal();
+ pthread_join(pthread, NULL);
+ this->threadPostStopCleanup();
+}
+
+
+void ThreadPAndroid ::threadCancel()
+{
+ threadActive = 0;
+ threadSignalNoLock();
+ if (killable) pthread_cond_wait(&threadKillable,&threadCondMutex);
+ // pthread_cancel(pthread);
+ pthread_join(pthread, NULL);
+ this->threadPostStopCleanup();
+}
+
+
+
+void ThreadPAndroid ::threadCheckExit()
+{
+ if (!threadActive) {
+ pthread_cond_signal(&threadKillable);
+ pthread_exit(NULL);
+ }
+}
+
+void ThreadPAndroid ::threadLock()
+{
+ pthread_mutex_lock(&threadCondMutex);
+}
+
+void ThreadPAndroid ::threadUnlock()
+{
+ pthread_mutex_unlock(&threadCondMutex);
+}
+
+void ThreadPAndroid ::threadSignal()
+{
+ pthread_mutex_lock(&threadCondMutex);
+ pthread_cond_signal(&threadCond);
+ pthread_mutex_unlock(&threadCondMutex);
+}
+
+void ThreadPAndroid ::threadSignalNoLock()
+{
+ pthread_cond_signal(&threadCond);
+}
+
+void ThreadPAndroid ::threadWaitForSignal()
+{
+ pthread_cond_wait(&threadCond, &threadCondMutex);
+}
+
+void ThreadPAndroid ::threadWaitForSignalTimed(struct timespec* ts)
+{
+ pthread_cond_timedwait(&threadCond, &threadCondMutex, ts);
+}
+
+void ThreadPAndroid ::threadSetKillable()
+{
+ //pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ killable=true;
+ pthread_cond_signal(&threadKillable);
+}
+
+
+pthread_t ThreadPAndroid ::getThreadID() // returns the ID of this thread
+{
+ return pthread;
+}
+
+// Static functions
+
+void ThreadPAndroid ::threadSuicide()
+{
+ if(!pthread_detach(pthread_self()))
+ {
+ MILLISLEEP(1000);
+ if(!pthread_detach(pthread_self()))
+ {
+ MILLISLEEP(1000);
+ pthread_detach(pthread_self());
+ }
+ }
+
+ pthread_exit(NULL);
+}
+
+pthread_t ThreadPAndroid ::thisThreadID() // returns the ID of the calling thread
+{
+ return pthread_self();
+}
--- /dev/null
+/*
+ Copyright 2004-2005 Chris Tallon
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef THREADPANDROID_H
+#define THREADPANDROID_H
+
+#include <pthread.h>
+#include <signal.h>
+
+#include "defines.h"
+#include "thread.h"
+
+class ThreadPAndroid : public Thread
+{
+ protected:
+ // Override this method in derived classes
+ virtual void threadMethod()=0;
+ virtual void threadPostStopCleanup()=0;
+
+ // Methods to use from outside the thread
+ int threadStart(); // start the thread. threadMethod() will be called in derived class
+ void threadStop(); // stop the thread nicely. thread will be stopped when it next calls threadCheckExit()
+ void threadCancel(); // stop thread immediately. thread will be stopped at the next cancellation point
+ void threadSignal(); // releases a thread that has called threadWaitForSignal
+ 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
+ void threadWaitForSignalTimed(struct timespec*); // pauses thread until threadSignal() is called or timer expires
+ void threadLock(); // locks the mutex used for internal cond/signal stuff
+ void threadUnlock(); // unlocks.
+
+ // Internal bits and pieces
+
+ pthread_t pthread;
+ pthread_cond_t threadCond;
+ pthread_cond_t threadKillable;
+ pthread_mutex_t threadCondMutex;
+
+ public:
+ pthread_t getThreadID(); // returns the ID of the thread represented by this object
+
+
+ static pthread_t thisThreadID(); // Self identification - returns ID of calling thread
+ static void threadSuicide(); // Self termination
+ bool killable;
+};
+
+#endif
--- /dev/null
+/*\r
+ Copyright 2011 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+#ifndef WIN32\r
+#ifdef __ANDROID__\r
+#include "threadpandroid.h"\r
+#else\r
+#include "threadp.h"\r
+#endif\r
+#else\r
+#include "threadwin.h"\r
+#endif\r
--- /dev/null
+/*
+ Copyright 2004-2005 Chris Tallon, 2009 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 "videovpeogl.h"
+#include "audiovpe.h"
+#include "mtdraspberry.h"
+#include "demuxer.h"
+// temp
+#include "log.h"
+
+
+
+//taken from libsi
+//taken and adapted from libdtv, (c) Rolf Hakenes
+// CRC32 lookup table for polynomial 0x04c11db7
+unsigned int crc_table[256] = {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
+ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
+ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
+ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
+ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
+ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
+ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
+ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
+ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
+ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
+ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
+ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
+ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
+
+unsigned int crc32 (const char *d, int len, unsigned int crc)
+{
+ register int i;
+ const unsigned char *u=(unsigned char*)d; // Saves '& 0xff'
+
+ for (i=0; i<len; i++)
+ crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *u++)];
+
+ return crc;
+}
+
+
+
+VideoVPEOGL::VideoVPEOGL()
+{
+ if (instance) return;
+ muxout=NULL;
+ muxnumber=0;
+ lastpacketnum=-1;
+ audioconti=videoconti=0;
+ pmtversion=patversion=0;
+
+}
+
+VideoVPEOGL::~VideoVPEOGL()
+{
+ instance = NULL;
+}
+
+int VideoVPEOGL::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;
+}
+
+
+
+int VideoVPEOGL::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 VideoVPEOGL::setDefaultAspect()
+{
+ return setAspectRatio(tvsize);
+}
+
+int VideoVPEOGL::shutdown()
+{
+ if (!initted) return 0;
+ initted = 0;
+// close(fdVideo);
+ return 1;
+}
+
+
+int VideoVPEOGL::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 VideoVPEOGL::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 VideoVPEOGL::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 VideoVPEOGL::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 VideoVPEOGL::signalOff()
+{
+// if (ioctl(fdVideo, AV_SET_VID_DENC, 0) != 0) return 0;
+ return 1;
+}
+
+int VideoVPEOGL::signalOn()
+{
+// if (ioctl(fdVideo, AV_SET_VID_DENC, 1) != 0) return 0;
+ return 1;
+}
+
+int VideoVPEOGL::setSource()
+{
+ if (!initted) return 0;
+
+ // What does this do...
+// if (ioctl(fdVideo, AV_SET_VID_SRC, 1) != 0) return 0;
+ return 1;
+}
+
+int VideoVPEOGL::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 VideoVPEOGL::sync()
+{
+ if (!initted) return 0;
+
+// if (ioctl(fdVideo, AV_SET_VID_SYNC, 2) != 0) return 0;
+ return 1;
+}
+
+void VideoVPEOGL::initMuxer(bool iframe)
+{
+ char buffer[1024];
+ lastpacketnum=-1;
+ iframemode=iframe;
+ if (muxout) return;
+ sprintf(buffer,"/share/dev/muxout%d.ts",muxnumber);
+ filemutex.Lock();
+ audioconti=videoconti=0;
+ muxout=fopen(buffer,"wb");
+ filemutex.Unlock();
+ WriteOutPATPMT();
+ Log::getInstance()->log("Video", Log::DEBUG,
+ "Create file %s with result %d",buffer,muxout);
+}
+
+void VideoVPEOGL::deinitMuxer()
+{
+ if (muxout)
+ {
+ filemutex.Lock();
+ FILE*temp=muxout;
+ muxout=NULL;
+ audioconti=videoconti=0;
+ filemutex.Unlock();
+ Log::getInstance()->log("Video", Log::DEBUG,
+ "Close mux");
+
+ fclose(temp);
+ muxnumber++;
+ }
+}
+
+
+int VideoVPEOGL::play()
+{
+ if (!initted) return 0;
+
+
+
+// if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0;
+ return 1;
+}
+
+int VideoVPEOGL::stop()
+{
+ if (!initted) return 0;
+
+
+
+// if (ioctl(fdVideo, AV_SET_VID_STOP, 0) != 0) return 0;
+ return 1;
+}
+
+int VideoVPEOGL::reset()
+{
+ if (!initted) return 0;
+
+// if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0;
+ return 1;
+}
+
+int VideoVPEOGL::pause()
+{
+ if (!initted) return 0;
+
+// if (ioctl(fdVideo, AV_SET_VID_PAUSE, 0) != 0) return 0;
+ return 1;
+}
+
+int VideoVPEOGL::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 VideoVPEOGL::fastForward()
+{
+ if (!initted) return 0;
+
+// if (ioctl(fdVideo, AV_SET_VID_FFWD, 1) != 0) return 0;
+ return 1;
+}
+
+int VideoVPEOGL::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 VideoVPEOGL::attachFrameBuffer()
+{
+ if (!initted) return 0;
+
+// if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0;
+ return 1;
+}
+
+int VideoVPEOGL::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 VideoVPEOGL::getCurrentTimestamp()
+{
+/* sync_data_t timestamps;
+ if (ioctl(fdVideo, AV_GET_VID_TIMESTAMPS, ×tamps) == 0)
+ {
+ // FIXME are these the right way around?
+
+ timestamps.stc = (timestamps.stc >> 31 ) | (timestamps.stc & 1);
+ timestamps.pts = (timestamps.pts >> 31 ) | (timestamps.pts & 1);
+
+ return timestamps.stc;
+ }
+ else
+ {
+ return 0;
+ }*/
+ return 0;
+}
+
+ULONG VideoVPEOGL::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 VideoVPEOGL::test()
+{
+ return 0;
+
+// ULLONG stc = 0;
+// return ioctl(fdVideo, AV_SET_VID_STC, &stc);
+/*
+ // reset();
+ return 1;
+*/
+}
+
+int VideoVPEOGL::test2()
+{
+ return 0;
+}
+#endif
+
+void VideoVPEOGL::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)
+{
+ mediapacket = mplist.front();
+}
+
+UINT VideoVPEOGL::DeliverMediaSample(UCHAR* buffer, UINT* samplepos)
+{
+ if (!muxout) return 0;
+
+ AudioVPE *audio=((AudioVPE*)audio->getInstance());
+ // Log::getInstance()->log("Video", Log::DEBUG, "lastpacket %d lastbuddypacket %d currentpacket %d",lastpacketnum,audio->getLastPacketNum(),mediapacket.index);
+
+ //format pes
+ switch (mediapacket.type) {
+ case MPTYPE_VIDEO_MPEG2:
+ h264=false;
+ buffer[mediapacket.pos_buffer + 3]=0xe0; break;
+ case MPTYPE_VIDEO_H264:
+ h264=true;
+ buffer[mediapacket.pos_buffer + 3]=0xe0; break;
+ };
+
+
+ if (lastpacketnum!=-1 && mediapacket.index-1!=lastpacketnum && mediapacket.index-1>audio->getLastPacketNum() && mediapacket.index>audio->getCurrentPacketNum()) {
+ Log::getInstance()->log("Video", Log::DEBUG, "Packet not in order, packet num %d, lastpacketnum %d, audio lastpacketnum %d",mediapacket.index,lastpacketnum,audio->getLastPacketNum());
+ return 0; //Not in order
+ }
+
+
+/* filemutex.Lock();
+ int written=fwrite(buffer + mediapacket.pos_buffer,1,mediapacket.length,muxout);*/
+ if (mediapacket.synched) WriteOutPATPMT();
+
+ int written=WriteOutTS(buffer + mediapacket.pos_buffer,mediapacket.length, mediapacket.type);
+ lastpacketnum=mediapacket.index;
+ //filemutex.Unlock();
+ //Log::getInstance()->log("Video", Log::DEBUG, "wrote %d bytes to mux",written);
+
+
+ if (written == (int)mediapacket.length) { *samplepos = 0; return 1;}
+ if (written <= 0) {
+ return 0;
+ }
+ *samplepos = written;
+ // Handle a partial write. Is this possible? Should we bother? No!
+
+ return 1;
+}
+/*
+
+int VideoVPEOGL::WriteOutPCR(ULLONG pts)
+{
+ unsigned char ts_buffer[188];
+ unsigned char ts_crc[4];
+ unsigned char conti;
+ memset(ts_buffer,0xFF,188);
+
+ conti=videoconti;
+ ts_buffer[0]=0x47; //TS_SYNC
+ ts_buffer[1]=0x40; //Payload_start
+ ts_buffer[2]=100;
+ ts_buffer[3]=0x20| conti;
+ ts_buffer[4]=183;
+ ts_buffer[5]=0x10; //PCR!
+
+
+
+ int tocopy=length;
+ unsigned char *dest=buffer;
+ filemutex.Lock();
+ unsigned int outlength=184;
+ while (tocopy>=outlength) {
+
+ ts_buffer[3]=0x10 | conti;
+ fwrite(ts_buffer,1,4,muxout); //Header out
+
+ fwrite(dest,1, outlength,muxout);
+
+
+ dest+=outlength;
+ tocopy-=outlength;
+ conti++;
+ conti&=0x0F;
+ ts_buffer[1]=0x00; //Payload_start
+ }
+ if (tocopy>0) {
+ ts_buffer[3]=0x30 | conti;//we have an adpation field
+ fwrite(ts_buffer,1,4,muxout); //Header out
+ unsigned char adaptionfield[2]={outlength-tocopy-1,0x00};
+ if (tocopy<183) fwrite(adaptionfield,1,2,muxout);
+ else fwrite(adaptionfield,1,1,muxout);
+ unsigned char paddy=0xFF;
+ if (outlength>tocopy+2) {
+ for (int i=0;i<(outlength-tocopy-2);i++) fwrite(&paddy,1,1,muxout);
+ }
+ fwrite(dest,1,tocopy,muxout);
+ }
+
+
+ conti++;
+ conti&=0x0F;
+ filemutex.Unlock();
+
+
+ videoconti=conti;
+
+}*/
+
+int VideoVPEOGL::WriteOutTS(const unsigned char *buffer,int length, int type)
+{
+ unsigned char ts_buffer[4];
+ unsigned char ts_crc[4];
+ unsigned char conti;
+ ts_buffer[0]=0x47; //TS_SYNC
+ ts_buffer[1]=0x40; //Payload_start
+ switch (type) {
+ case MPTYPE_VIDEO_MPEG2:
+ case MPTYPE_VIDEO_H264:
+ conti=videoconti;
+ ts_buffer[2]=100; break;
+
+ case MPTYPE_MPEG_AUDIO:
+ conti=audioconti;
+ ts_buffer[2]=101; break;
+ case MPTYPE_AC3:
+ case MPTYPE_AC3_PRE13:
+ conti=audioconti;
+ ts_buffer[2]=102; break;
+ default:
+ return 0; break; //????
+ };
+ int tocopy=length;
+ const unsigned char *dest=buffer;
+ filemutex.Lock();
+ unsigned int outlength=184;
+ while (tocopy>=outlength) {
+
+ ts_buffer[3]=0x10 | conti;
+ fwrite(ts_buffer,1,4,muxout); //Header out
+
+ fwrite(dest,1, outlength,muxout);
+
+
+ dest+=outlength;
+ tocopy-=outlength;
+ conti++;
+ conti&=0x0F;
+ ts_buffer[1]=0x00; //Payload_start
+ }
+ if (tocopy>0) {
+ ts_buffer[3]=0x30 | conti;//we have an adpation field
+ fwrite(ts_buffer,1,4,muxout); //Header out
+ unsigned char adaptionfield[2]={outlength-tocopy-1,0x00};
+ if (tocopy<183) fwrite(adaptionfield,1,2,muxout);
+ else fwrite(adaptionfield,1,1,muxout);
+ unsigned char paddy=0xFF;
+ if (outlength>tocopy+2) {
+ for (int i=0;i<(outlength-tocopy-2);i++) fwrite(&paddy,1,1,muxout);
+ }
+ fwrite(dest,1,tocopy,muxout);
+ }
+
+
+ conti++;
+ conti&=0x0F;
+ filemutex.Unlock();
+
+ switch (type) {
+ case MPTYPE_VIDEO_MPEG2:
+ case MPTYPE_VIDEO_H264:
+ videoconti=conti; break;
+
+ case MPTYPE_MPEG_AUDIO:
+ case MPTYPE_AC3:
+ case MPTYPE_AC3_PRE13:
+ audioconti=conti;
+ break;
+ };
+ return length;
+
+}
+
+void VideoVPEOGL::WriteOutPATPMT()
+{
+ unsigned char ts_buffer[188];
+ //PAT
+ memset(ts_buffer,0xFF,188);
+ ts_buffer[0]=0x47; //TS_SYNC
+ ts_buffer[1]=0x40; //Payload_start
+ ts_buffer[2]=0x00;
+ ts_buffer[3]=0x10;
+ ts_buffer[4]=0x00;
+ ts_buffer[5]=0x00;//table id
+ ts_buffer[6]=0xB0; //Section syntax
+ ts_buffer[7]=13; //Section length
+ ts_buffer[8]=0x80;//PSID
+ ts_buffer[9]=0x08;//PSID lo
+ ts_buffer[10]=0xC1 | (patversion << 1);
+ ts_buffer[11]=0x00;//section numbrt
+ ts_buffer[12]=0x00;
+ ts_buffer[13]=0x00; //hi program number
+ ts_buffer[14]=98;
+ ts_buffer[15]=0xe0;
+ ts_buffer[16]=98;
+ int crc =crc32((const char *)ts_buffer+5, 12, 0xFFFFFFFF);
+ int i = 0;
+ ts_buffer[17] = crc >> 24;
+ ts_buffer[18] = crc >> 16;
+ ts_buffer[19] = crc >> 8;
+ ts_buffer[20] = crc;
+ patversion++;
+ patversion&=0x1F;
+ filemutex.Lock();
+ fwrite(ts_buffer,1,188,muxout); //Header out
+ filemutex.Unlock();
+
+ //PMT
+ memset(ts_buffer,0xFF,188);
+ ts_buffer[0]=0x47; //TS_SYNC
+ ts_buffer[1]=0x40; //Payload_start
+ ts_buffer[2]=98;
+ ts_buffer[3]=0x10;
+ ts_buffer[4]=0x00;
+ ts_buffer[5]=0x02;//table id
+ ts_buffer[6]=0xB0; //Section syntax
+ ts_buffer[7]=23; //Section length
+ ts_buffer[8]=0x00;//PSID
+ ts_buffer[9]=98;//PSID lo
+ ts_buffer[10]=0xC1 | (pmtversion << 1);
+ ts_buffer[11]=0x00;//section numbrt
+ ts_buffer[12]=0x00;
+ ts_buffer[13]=0xE0 | 0x1F;
+ ts_buffer[14]=0xFF;//Video is pcr
+ ts_buffer[15]=0xF0;//dummy
+ ts_buffer[16]=0x00; //program info
+ //Video
+
+ if (h264)
+ {
+ ts_buffer[17] = 0x1B; // stream type video
+ }
+ else
+ {
+ ts_buffer[17] = 0x02; // stream type video
+ }
+ ts_buffer[18] = 0xE0; //
+ ts_buffer[19]=100; //Video pid
+ ts_buffer[20]= 0xF0; //
+ ts_buffer[21]= 0x00; //
+ // audio
+ int add_length=0;
+ unsigned char atype=((AudioVPE*)Audio::getInstance())->getLastAType();
+ switch (atype) {
+ default:
+ case MPTYPE_MPEG_AUDIO:
+ ts_buffer[22] = 0x04; // stream type audio
+ ts_buffer[23] = 0xE0; //
+ ts_buffer[24]=101; //Audio pid
+ ts_buffer[25]= 0xF0; //
+ ts_buffer[26]= 0x00; //
+ break;
+ case MPTYPE_AC3:
+ case MPTYPE_AC3_PRE13:
+ ts_buffer[22] = 0x06; // stream type private
+ ts_buffer[23] = 0xE0; //
+ ts_buffer[24]=102; //ac3
+ ts_buffer[25]= 0xF0; //
+ ts_buffer[26]= 0x03; //
+ ts_buffer[27] = 0x6A;
+ ts_buffer[28] = 0x01; // length
+ ts_buffer[29] = 0x00;
+ ts_buffer[7]+=3;
+ add_length=3;
+ break;
+ };
+ crc =crc32((const char *)ts_buffer+5, 22+add_length, 0xFFFFFFFF);
+ ts_buffer[27+add_length] = crc >> 24;
+ ts_buffer[28+add_length] = crc >> 16;
+ ts_buffer[29+add_length] = crc >> 8;
+ ts_buffer[30+add_length] = crc;
+ pmtversion++;
+ pmtversion&=0x1F;
+ filemutex.Lock();
+ fwrite(ts_buffer,1,188,muxout); //Header out
+ filemutex.Unlock();
+
+
+
+}
+
+
+void VideoVPEOGL::ResetTimeOffsets()
+{
+}
+
+bool VideoVPEOGL::displayIFrame(const UCHAR* buffer, UINT length)
+{
+ //write(fdVideo, buffer, length);
+ if (!iframemode) EnterIframePlayback();
+ WriteOutTS(buffer,length, h264?MPTYPE_VIDEO_H264 :MPTYPE_VIDEO_MPEG2 );
+
+ lastpacketnum=-1;
+ return true;
+}
+
+int VideoVPEOGL::EnterIframePlayback()
+{
+ deinitMuxer();
+ initMuxer(true);
+ return 0;
+}
+
--- /dev/null
+/*\r
+ Copyright 2004-2005 Chris Tallon 2009 Marten Richter\r
+\r
+ This file is part of VOMP.\r
+\r
+ VOMP is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ VOMP is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with VOMP; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+*/\r
+\r
+\r
+#ifndef VIDEOVPEOGL_H\r
+#define VIDEOVPEOGL_H\r
+\r
+#include "mutex.h"\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
+#define WRITE_PACKETS 16\r
+#define WRITE_LENGTH (32*1024)\r
+\r
+\r
+class VideoVPEOGL : public Video\r
+{\r
+ public:\r
+ VideoVPEOGL();\r
+ virtual ~VideoVPEOGL();\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
+ virtual bool supportsh264(){return true;};\r
+\r
+ int WriteOutTS(const unsigned char *buffer,int length, int type);\r
+ void WriteOutPATPMT();\r
+\r
+\r
+ Mutex *getMuxMutex() {return &filemutex;}; //File must be pointer of pointer Thread safety!\r
+ FILE *getMuxFile() {return muxout;}; //File must be pointer of pointer Thread safety!\r
+ void initMuxer(bool iframe=false);\r
+ void deinitMuxer();\r
+\r
+ int getLastPacketNum() {return lastpacketnum;}; \r
+#ifdef DEV\r
+ int test();\r
+ int test2();\r
+#endif\r
+\r
+ private:\r
+ int EnterIframePlayback();\r
+ bool iframemode;\r
+ \r
+ FILE* muxout;\r
+ int muxnumber;\r
+ Mutex filemutex;\r
+ int lastpacketnum;\r
+ unsigned char audioconti,videoconti;\r
+ unsigned int patversion,pmtversion;\r
+ \r
+ MediaPacket mediapacket;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\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 "wjpegcomplex.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
+#ifndef __ANDROID__\r
+extern "C"\r
+{\r
+ #include <jpeglib.h>\r
+}\r
+#endif\r
+\r
+#ifndef __ANDROID__\r
+//#define USE_BUFFER\r
+//#define EXTENDED_JPEGLIB\r
+\r
+//a struct to store user data for the jpeg decompressor\r
+class jpegUserData{\r
+ public:\r
+ WJpeg::JpegControl * ctl;\r
+ JpegReader *reader;\r
+ jpegUserData() {\r
+ ctl=NULL;\r
+ reader=NULL;\r
+ }\r
+ };\r
+\r
+//the scale factors supported by the jpeg lib\r
+\r
+struct scale{\r
+ UINT num;\r
+ UINT denom;\r
+};\r
+\r
+\r
+struct scale jpegFactors[]={\r
+#ifndef EXTENDED_JPEGLIB\r
+ {1,1},{1,2},{1,4},{1,8}\r
+#else\r
+ {1,1},{7,8},{3,4},{5,8},{1,2},{3,8},{1,4},{1,8}\r
+#endif\r
+};\r
+#endif\r
+\r
+#ifdef WIN32\r
+#define LocalReader WindowsResourceJpegReader\r
+class WindowsResourceJpegReader: public JpegReader {\r
+ public:\r
+ virtual ULONG initRead(const char *filename);\r
+ virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);\r
+ virtual ULONG getSize();\r
+ virtual ~WindowsResourceJpegReader();\r
+protected:\r
+ HGLOBAL hres;\r
+ LPVOID buffer;\r
+ DWORD size;\r
+};\r
+\r
+ULONG WindowsResourceJpegReader::initRead(const char *filename)\r
+{\r
+ HRSRC res=FindResource(NULL,filename,RT_RCDATA);\r
+ hres=LoadResource(NULL,res);\r
+ buffer=LockResource(hres);\r
+ size=SizeofResource(NULL,res);\r
+ //CloseHandle(hres);\r
+ return size;\r
+}\r
+\r
+ ULONG WindowsResourceJpegReader::readChunk(ULONG offset,ULONG len,char **buf)\r
+{\r
+ if (offset>size) return 0;\r
+ ULONG toread=min(size-offset,len);\r
+ char* buffy=(char*)malloc(toread);\r
+ memcpy(buffy,((char*)buffer)+offset,toread);\r
+ *buf=buffy;\r
+ return toread;\r
+}\r
+\r
+ WindowsResourceJpegReader::~WindowsResourceJpegReader(){\r
+ buffer=NULL;\r
+ size=0;\r
+ FreeResource(hres);\r
+ }\r
+\r
+ ULONG WindowsResourceJpegReader::getSize(){\r
+ return (ULONG)size;\r
+}\r
+#else\r
+\r
+#define LocalReader LocalJpegReader\r
+class LocalJpegReader: public JpegReader {\r
+ public:\r
+ virtual ULONG initRead(const char *filename);\r
+ virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);\r
+ virtual ~LocalJpegReader();\r
+ virtual ULONG getSize();\r
+ LocalJpegReader();\r
+protected:\r
+ FILE *file;\r
+ ULONG size;\r
+};\r
+\r
+LocalJpegReader::LocalJpegReader(){\r
+ file=NULL;\r
+ size=0;\r
+}\r
+\r
+ULONG LocalJpegReader::initRead(const char *filename)\r
+{\r
+ if (file) fclose(file);\r
+ size=0;\r
+ file=fopen(filename,"r");\r
+ if (file) {\r
+ struct stat st;\r
+ if (fstat(fileno(file), &st) != 0) return 0;\r
+ size= st.st_size;\r
+ return size;\r
+ }\r
+ Log::getInstance()->log("WJepg", Log::ERR, "localReader unable to open File %s", filename);\r
+ return 0;\r
+}\r
+\r
+ULONG LocalJpegReader::readChunk(ULONG offset,ULONG len,char **buf)\r
+{\r
+ *buf=NULL;\r
+ ULONG bread=0;\r
+ if (file) {\r
+ ULLONG cpos=ftell(file);\r
+ if (offset != cpos) {\r
+ fseek(file,offset-cpos,SEEK_CUR);\r
+ }\r
+ if (offset != (ULONG)ftell(file)) {\r
+ Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);\r
+ }\r
+ else {\r
+ *buf=(char *)malloc(len);\r
+ if ( ! (*buf)) {\r
+ Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);\r
+ }\r
+ else {\r
+ bread=fread(*buf,1,len,file);\r
+ }\r
+ }\r
+ }\r
+ return bread;\r
+}\r
+\r
+LocalJpegReader::~LocalJpegReader(){\r
+ if (file) fclose(file);\r
+ file=NULL;\r
+}\r
+ULONG LocalJpegReader::getSize(){\r
+ return size;\r
+}\r
+#endif\r
+\r
+#ifndef __ANDROID__\r
+/*----------------------------------------------------------------\r
+ the jpeg lib routines\r
+ ----------------------------------------------------------------\r
+ */\r
+\r
+extern "C" {\r
+\r
+\r
+struct my_error_mgr {\r
+ struct jpeg_error_mgr pub; /* "public" fields */\r
+\r
+ jmp_buf setjmp_buffer; /* for return to caller */\r
+};\r
+\r
+typedef struct my_error_mgr * my_error_ptr;\r
+\r
+/*\r
+ * Here's the routine that will replace the standard error_exit method:\r
+ */\r
+\r
+METHODDEF(void)\r
+my_error_exit (j_common_ptr cinfo)\r
+{\r
+ /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */\r
+ my_error_ptr myerr = (my_error_ptr) cinfo->err;\r
+\r
+ /* Always display the message. */\r
+ /* We could postpone this until after returning, if we chose. */\r
+ (*cinfo->err->output_message) (cinfo);\r
+ /* Return control to the setjmp point */\r
+ longjmp(myerr->setjmp_buffer, 1);\r
+}\r
+\r
+ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {\r
+ jpegUserData *user=(jpegUserData *)cb;\r
+ return user->reader->readChunk(offset,size,buf);\r
+}\r
+//the memory buffer reader for the jpeg lib\r
+//taken from jdatasrc.c\r
+\r
+#include "jinclude.h"\r
+#include "jpeglib.h"\r
+#include "jerror.h"\r
+\r
+\r
+typedef struct {\r
+ struct jpeg_source_mgr pub; /* public fields */\r
+\r
+ JOCTET * buffer; /* start of buffer */\r
+ boolean start_of_file; /* have we gotten any data yet? */\r
+ void * userdata; /* used for callback */\r
+ ULONG offset;\r
+} my_source_mgr;\r
+\r
+typedef my_source_mgr * my_src_ptr;\r
+\r
+#define INPUT_BUF_SIZE (64*4096) /* choose an efficiently fread'able size */\r
+\r
+\r
+/*\r
+ * Initialize source --- called by jpeg_read_header\r
+ * before any data is actually read.\r
+ */\r
+\r
+METHODDEF(void)\r
+linit_source (j_decompress_ptr cinfo)\r
+{\r
+ my_src_ptr src = (my_src_ptr) cinfo->src;\r
+\r
+ /* We reset the empty-input-file flag for each image,\r
+ * but we don't clear the input buffer.\r
+ * This is correct behavior for reading a series of images from one source.\r
+ */\r
+ src->start_of_file = TRUE;\r
+ src->offset=0;\r
+}\r
+\r
+\r
+/*\r
+ * Fill the input buffer --- called whenever buffer is emptied.\r
+ *\r
+ * In typical applications, this should read fresh data into the buffer\r
+ * (ignoring the current state of next_input_byte & bytes_in_buffer),\r
+ * reset the pointer & count to the start of the buffer, and return TRUE\r
+ * indicating that the buffer has been reloaded. It is not necessary to\r
+ * fill the buffer entirely, only to obtain at least one more byte.\r
+ *\r
+ * There is no such thing as an EOF return. If the end of the file has been\r
+ * reached, the routine has a choice of ERREXIT() or inserting fake data into\r
+ * the buffer. In most cases, generating a warning message and inserting a\r
+ * fake EOI marker is the best course of action --- this will allow the\r
+ * decompressor to output however much of the image is there. However,\r
+ * the resulting error message is misleading if the real problem is an empty\r
+ * input file, so we handle that case specially.\r
+ *\r
+ * In applications that need to be able to suspend compression due to input\r
+ * not being available yet, a FALSE return indicates that no more data can be\r
+ * obtained right now, but more may be forthcoming later. In this situation,\r
+ * the decompressor will return to its caller (with an indication of the\r
+ * number of scanlines it has read, if any). The application should resume\r
+ * decompression after it has loaded more data into the input buffer. Note\r
+ * that there are substantial restrictions on the use of suspension --- see\r
+ * the documentation.\r
+ *\r
+ * When suspending, the decompressor will back up to a convenient restart point\r
+ * (typically the start of the current MCU). next_input_byte & bytes_in_buffer\r
+ * indicate where the restart point will be if the current call returns FALSE.\r
+ * Data beyond this point must be rescanned after resumption, so move it to\r
+ * the front of the buffer rather than discarding it.\r
+ */\r
+\r
+METHODDEF(boolean)\r
+lfill_input_buffer (j_decompress_ptr cinfo)\r
+{\r
+ my_src_ptr src = (my_src_ptr) cinfo->src;\r
+ size_t nbytes;\r
+ if (src->buffer) free(src->buffer);\r
+ src->buffer=NULL;\r
+ nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);\r
+\r
+ if (nbytes <= 0) {\r
+ WARNMS(cinfo, JWRN_JPEG_EOF);\r
+ src->buffer = (JOCTET *)malloc(2);\r
+ src->buffer[0] = (JOCTET) 0xFF;\r
+ src->buffer[1] = (JOCTET) JPEG_EOI;\r
+ nbytes = 2;\r
+\r
+ }\r
+ src->offset+=nbytes;\r
+\r
+ src->pub.next_input_byte = src->buffer;\r
+ src->pub.bytes_in_buffer = nbytes;\r
+ src->start_of_file = FALSE;\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/*\r
+ * Skip data --- used to skip over a potentially large amount of\r
+ * uninteresting data (such as an APPn marker).\r
+ *\r
+ * Writers of suspendable-input applications must note that skip_input_data\r
+ * is not granted the right to give a suspension return. If the skip extends\r
+ * beyond the data currently in the buffer, the buffer can be marked empty so\r
+ * that the next read will cause a fill_input_buffer call that can suspend.\r
+ * Arranging for additional bytes to be discarded before reloading the input\r
+ * buffer is the application writer's problem.\r
+ */\r
+\r
+METHODDEF(void)\r
+lskip_input_data (j_decompress_ptr cinfo, long num_bytes)\r
+{\r
+ my_src_ptr src = (my_src_ptr) cinfo->src;\r
+\r
+ /* Just a dumb implementation for now. Could use fseek() except\r
+ * it doesn't work on pipes. Not clear that being smart is worth\r
+ * any trouble anyway --- large skips are infrequent.\r
+ */\r
+ if (num_bytes > 0) {\r
+ while (num_bytes > (long) src->pub.bytes_in_buffer) {\r
+ num_bytes -= (long) src->pub.bytes_in_buffer;\r
+ (void) lfill_input_buffer(cinfo);\r
+ /* note we assume that fill_input_buffer will never return FALSE,\r
+ * so suspension need not be handled.\r
+ */\r
+ }\r
+ src->pub.next_input_byte += (size_t) num_bytes;\r
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * An additional method that can be provided by data source modules is the\r
+ * resync_to_restart method for error recovery in the presence of RST markers.\r
+ * For the moment, this source module just uses the default resync method\r
+ * provided by the JPEG library. That method assumes that no backtracking\r
+ * is possible.\r
+ */\r
+\r
+\r
+/*\r
+ * Terminate source --- called by jpeg_finish_decompress\r
+ * after all data has been read. Often a no-op.\r
+ *\r
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding\r
+ * application must deal with any cleanup that should happen even\r
+ * for error exit.\r
+ */\r
+\r
+METHODDEF(void)\r
+lterm_source (j_decompress_ptr cinfo)\r
+{\r
+ /* no work necessary here */\r
+}\r
+\r
+\r
+/*\r
+ * Prepare for input from a stdio stream.\r
+ * The caller must have already opened the stream, and is responsible\r
+ * for closing it after finishing decompression.\r
+ */\r
+\r
+extern "C" void\r
+jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)\r
+{\r
+ my_src_ptr src;\r
+\r
+ /* The source object and input buffer are made permanent so that a series\r
+ * of JPEG images can be read from the same file by calling jpeg_stdio_src\r
+ * only before the first one. (If we discarded the buffer at the end of\r
+ * one image, we'd likely lose the start of the next one.)\r
+ * This makes it unsafe to use this manager and a different source\r
+ * manager serially with the same JPEG object. Caveat programmer.\r
+ */\r
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */\r
+ cinfo->src = (struct jpeg_source_mgr *)\r
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,\r
+ SIZEOF(my_source_mgr));\r
+ src = (my_src_ptr) cinfo->src;\r
+ src->buffer = NULL;\r
+ }\r
+\r
+ src = (my_src_ptr) cinfo->src;\r
+ src->pub.init_source = linit_source;\r
+ src->pub.fill_input_buffer = lfill_input_buffer;\r
+ src->pub.skip_input_data = lskip_input_data;\r
+ src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */\r
+ src->pub.term_source = lterm_source;\r
+ src->userdata=userdata;\r
+ src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */\r
+ src->pub.next_input_byte = NULL; /* until buffer loaded */\r
+ src->offset=0;\r
+ src->userdata=userdata;\r
+ if (src->buffer) {\r
+ free(src->buffer);\r
+ src->buffer=NULL;\r
+ }\r
+}\r
+/* cleanup to be called before cleanup of cinfo*/\r
+extern "C" void\r
+jpeg_memio_cleanup (j_decompress_ptr cinfo) {\r
+ my_src_ptr src=(my_src_ptr)cinfo->src;\r
+ Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));\r
+ if (src && src->buffer) {\r
+ free(src->buffer);\r
+ src->buffer=NULL;\r
+ }\r
+}\r
+\r
+//taken from mvpmc\r
+//http://git.mvpmc.org/cgi-bin/gitweb.cgi?p=mvpmc.git;a=blob_plain;h=02d4354c0cbbed802a9aa1478918a49fcbf61d00;f=libs/libwidget/image_jpeg.c\r
+\r
+#define GET2BYTES(cinfo, V, swap, offset) do { \\r
+ if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
+ cinfo->src->bytes_in_buffer--; \\r
+ V = (*cinfo->src->next_input_byte++) << (swap?0:8); \\r
+ if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
+ cinfo->src->bytes_in_buffer--; \\r
+ V += (*cinfo->src->next_input_byte++) << (swap?8:0); \\r
+ offset += 2; } while(0) \r
+\r
+#define GET4BYTES(cinfo, V, swap, offset) do { \\r
+ if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
+ cinfo->src->bytes_in_buffer--; \\r
+ V = (*cinfo->src->next_input_byte++) << (swap?0:24); \\r
+ if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
+ cinfo->src->bytes_in_buffer--; \\r
+ V += (*cinfo->src->next_input_byte++) << (swap?8:16); \\r
+ if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
+ cinfo->src->bytes_in_buffer--; \\r
+ V += (*cinfo->src->next_input_byte++) << (swap?16:8); \\r
+ if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
+ cinfo->src->bytes_in_buffer--; \\r
+ V += (*cinfo->src->next_input_byte++) << (swap?24:0); \\r
+ offset += 4; } while(0)\r
+\r
+static boolean\r
+get_exif_orient (j_decompress_ptr cinfo)\r
+/* Get the Exif orientation info */\r
+{\r
+ unsigned int tmp, offset, length, numtags;\r
+ int orient=-1;\r
+ jpegUserData * ud=0;\r
+ boolean swap;\r
+ orient = 1;\r
+ offset = 0;\r
+ my_src_ptr mysrc = (my_src_ptr) cinfo->src;\r
+\r
+ /* marker length */\r
+ GET2BYTES(cinfo, length, 0, offset);\r
+ if (length<8) goto err;\r
+ /* Exif header */\r
+ GET4BYTES(cinfo, tmp, 0, offset);\r
+ if (tmp != 0x45786966) goto err;\r
+ GET2BYTES(cinfo, tmp, 0, offset);\r
+ if (tmp != 0x0000) goto err;\r
+ /* Byte-order */\r
+ GET2BYTES(cinfo, tmp, 0, offset);\r
+ if (tmp == 0x4949) swap = 1;\r
+ else if (tmp == 0x4d4d) swap = 0;\r
+ else goto err;\r
+ GET2BYTES(cinfo, tmp, swap, offset);\r
+ if (tmp != 0x002A) goto err;\r
+ /* offset to first IFD */\r
+ GET4BYTES(cinfo, tmp, swap, offset);\r
+ offset += tmp-8;\r
+ (*mysrc->pub.skip_input_data)(cinfo, tmp-8);\r
+ /* number of tags in IFD */\r
+ GET2BYTES(cinfo, numtags, swap, offset);\r
+ if (numtags == 0) goto err;\r
+ \r
+ /* Search for Orientation Tag in IFD0 */\r
+ for (;;) {\r
+ if (offset > length-12) goto err;\r
+ GET2BYTES(cinfo, tmp, swap, offset);\r
+ if (tmp == 0x0112) break; /* found Orientation Tag */\r
+ if (--numtags == 0) goto err;\r
+ offset += 10;\r
+ (*mysrc->pub.skip_input_data)(cinfo, 10);\r
+ }\r
+ offset += 6;\r
+ (*mysrc->pub.skip_input_data)(cinfo, 6);\r
+ GET2BYTES(cinfo, orient, swap, offset);\r
+ if( orient==0 || orient>8 ) orient = 1;\r
+ \r
+ Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);\r
+ ud=(jpegUserData *)(mysrc->userdata);\r
+ switch(orient) {\r
+ case 3:\r
+ ud->ctl->exifRotation=WJpeg::ROT_180;\r
+ break;\r
+ case 6:\r
+ ud->ctl->exifRotation=WJpeg::ROT_90;\r
+ break;\r
+ case 8:\r
+ ud->ctl->exifRotation=WJpeg::ROT_270;\r
+ break;\r
+ }\r
+\r
+err:\r
+ (*mysrc->pub.skip_input_data)(cinfo, length-offset);\r
+ return TRUE;\r
+}\r
+}\r
+#endif\r
+/*----------------------------------------------------------------\r
+ the implementation\r
+ ----------------------------------------------------------------\r
+ */\r
+\r
+\r
+WJpegComplex::WJpegComplex(){\r
+ reader=NULL;\r
+ owningReader=false;\r
+ errbuf[0]=0;\r
+}\r
+\r
+WJpegComplex::~WJpegComplex() {\r
+ if (owningReader && reader) delete reader;\r
+}\r
+\r
+int WJpegComplex::init(const char* tfileName)\r
+{\r
+ if (owningReader && reader) delete reader;\r
+ errbuf[0]=0; //clean error state\r
+ LocalReader *myreader=new LocalReader();\r
+ reader=myreader;\r
+ owningReader=true;\r
+ ULONG psize=myreader->initRead(tfileName);\r
+ if (psize == 0) {\r
+ delete reader;\r
+ reader=NULL;\r
+ owningReader=false;\r
+ SNPRINTF(errbuf,200,"unable to open %s",tfileName);\r
+ return 0;\r
+ }\r
+ return 1;\r
+}\r
+\r
+\r
+\r
+\r
+bool WJpegComplex::hasError() {\r
+ return (errbuf[0] != 0);\r
+}\r
+void WJpegComplex::draw()\r
+{\r
+ bool ok=false;\r
+ JpegControl ctl;\r
+ if (reader) {\r
+ Region myRegion;\r
+ Surface *sfc=getSurface(myRegion);\r
+ myRegion.w=area.w;\r
+ myRegion.h=area.h;\r
+ ctl.area=myRegion;\r
+ ctl.enlarge=true;\r
+ if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;\r
+ }\r
+ else {\r
+ SNPRINTF(errbuf,200,"jpeg reader not initialized");\r
+ }\r
+ if (! ok) {\r
+ drawTextCentre(tr("Jpeg ERROR"), 240, 170, Colour::LIGHTTEXT);\r
+ if (errbuf[0] != 0) drawTextCentre(errbuf,240,200, Colour::LIGHTTEXT);\r
+ if (ctl.error[0] != 0) drawTextCentre(ctl.error,240,230, Colour::LIGHTTEXT);\r
+ }\r
+}\r
+\r
+\r
+\r
+/**\r
+ the main drawing function\r
+ this will read the pciture via the reader\r
+ and draw directly into the surface\r
+ it will compute an appropriate scale and set the infos in the\r
+ JpegControl structure\r
+**/ \r
+\r
+#ifndef __ANDROID__\r
+\r
+bool WJpegComplex::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, Colour & backgroundColour) {\r
+ Log* logger = Log::getInstance();\r
+ if (! rdr || ! sfc) {\r
+ logger->log("BJpeg", Log::ERR, "JPEG error rdr=NULL or sfc=NULL");\r
+ return false;\r
+ }\r
+ logger->log("BJpeg", Log::DEBUG, "draw Jpeg Started sfc=%p, rdr=%p",sfc,rdr);\r
+ unsigned char* buffer =NULL;\r
+ struct jpeg_decompress_struct cinfo;\r
+ struct my_error_mgr jerr;\r
+ cinfo.err = jpeg_std_error(&jerr.pub);\r
+ jerr.pub.error_exit = my_error_exit;\r
+ /* Establish the setjmp return context for my_error_exit to use. */\r
+ if (setjmp(jerr.setjmp_buffer)) {\r
+ /* If we get here, the JPEG code has signaled an error.\r
+ * We need to clean up the JPEG object, close the input file, and return.\r
+ */\r
+ if (rdr) jpeg_memio_cleanup(&cinfo);\r
+ jpeg_destroy_decompress(&cinfo);\r
+ logger->log("BJpeg", Log::ERR, "JPEG error");\r
+ if (buffer) free(buffer);\r
+ return false;\r
+ }\r
+ jpegUserData userdata;\r
+ int xpos=0;\r
+ int ypos=0;\r
+ jpeg_create_decompress(&cinfo);\r
+ userdata.reader=rdr;\r
+ userdata.ctl=ctl;\r
+ ctl->exifRotation=ROT_0;\r
+ ctl->error[0]=0;\r
+ ctl->exifDate[0]=0;\r
+ //create the input for the jpeg lib\r
+ jpeg_memio_src(&cinfo,(void *)(&userdata));\r
+ //processor for EXIF data\r
+ jpeg_set_marker_processor(&cinfo, JPEG_APP0+1, get_exif_orient);\r
+ //read in header info\r
+ jpeg_read_header(&cinfo, TRUE);\r
+ ctl->picw=cinfo.image_width;\r
+ ctl->pich=cinfo.image_height;\r
+ ctl->compressedSize=rdr->getSize();\r
+ //now we have important info available in ctl (pictuerw,h, exif orientation,size)\r
+ //compute rotation due to the defined enum values we can simply add them\r
+ ctl->finalRotation=(enum Rotation)((ctl->rotation+ctl->exifRotation)%4);\r
+ logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", ctl->picw,ctl->pich,ctl->finalRotation);\r
+ //now we have to compute the scale\r
+ //input: ctl->picw,ctl->pich,ctl->finalRotation,ctl->mode,ctl->scaleAmount, ctl->scaleafter\r
+ // list of available jpeg scale factors\r
+ //out: scalenum,scaledenom,scaleafter\r
+\r
+ UINT picturew=ctl->picw;\r
+ UINT pictureh=ctl->pich;\r
+ switch (ctl->finalRotation){\r
+ case ROT_90:\r
+ case ROT_270:\r
+ pictureh=ctl->picw;\r
+ picturew=ctl->pich;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ UINT scalenum=1;\r
+ UINT scaledenom=1;\r
+ UINT scaleafter=1;\r
+ if (! ctl->enlarge) {\r
+ //scale - compute the factors to fit 100%\r
+ int scalew=1000*picturew/ctl->area.w;\r
+ int scaleh=1000*pictureh/ctl->area.h;\r
+ int scale=scaleh;\r
+ if (scalew > scaleh) scale=scalew;\r
+\r
+ //OK now find out which is the optimal setting\r
+ //rule: find settings being nearest to:\r
+ // mode=LETTER - smaller or equal screen size (i.e. scale*scalefactor <= 1000)\r
+ // mode=CROP - bigger or equal screen size (i.e. scale *scalefactor>= 1000)\r
+ // mode=CROPPERCENT - smaller or equal screensize*scaleamount (i.e. scale*scalefactor<= 1000*scaleamount)\r
+ // scaleamount is in % - so in reality we use scaleamount*10 instead scaleamount*1000\r
+ //the scalefactor computes as scalenum/(scaledenom*scaleafter)\r
+ scaledenom=8;\r
+ int minDiff=1000;\r
+ logger->log("BJpeg", Log::DEBUG, "start scaling screenw=%u, screenh=%u, pw=%u,ph=%u, scale=%d, mode=%d, %%=%u, after=%u",\r
+ ctl->area.w,ctl->area.h,picturew,pictureh,scale,(int)ctl->mode,ctl->scaleAmount, ctl->scaleafter); \r
+ for (UINT j=0;j<sizeof(jpegFactors)/sizeof(jpegFactors[0]);j++) {\r
+ for (UINT sa=1;sa<=ctl->scaleafter;sa++) {\r
+ int curf=(scale*jpegFactors[j].num)/(jpegFactors[j].denom*sa);\r
+ bool setThis=false;\r
+ logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,num=%u,denom=%u,after=%u,minDiff=%d", \r
+ curf,jpegFactors[j].num,jpegFactors[j].denom,sa,minDiff);\r
+ switch(ctl->mode) {\r
+ case CROP:\r
+ if (curf >= 1000 && curf < (minDiff +1000)) {\r
+ setThis=true;\r
+ minDiff=curf-1000;\r
+ }\r
+ break;\r
+ case LETTER:\r
+ if (curf <= 1000 && curf > (1000-minDiff)) {\r
+ setThis=true;\r
+ minDiff=1000-curf;\r
+ }\r
+ break;\r
+ case CROPPERCENT:\r
+ if (curf <= 10*(int)ctl->scaleAmount ) {\r
+ int abs=curf-1000;\r
+ if (abs < 0) abs=-abs;\r
+ if (abs < minDiff) {\r
+ setThis=true;\r
+ minDiff=abs;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ if (setThis) {\r
+ logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);\r
+ scalenum=jpegFactors[j].num;\r
+ scaledenom=jpegFactors[j].denom;\r
+ scaleafter=sa;\r
+ }\r
+ }\r
+ }\r
+ ctl->scale=100*scalenum/(scaledenom*scaleafter);\r
+\r
+ logger->log("BJpeg", Log::DEBUG, "JPEG scaling found scale=%i num=%i denom=%i after=%i result=%i scale=%i%% ",\r
+ scale,scalenum,scaledenom,scaleafter,scale*ctl->scale/100,ctl->scale);\r
+\r
+ cinfo.scale_denom=scaledenom;\r
+ cinfo.scale_num=scalenum;\r
+ }\r
+ else\r
+ {\r
+ //set drawing area according to picture\r
+ ctl->area.w=ctl->picw;\r
+ ctl->area.h=ctl->pich;\r
+ }\r
+\r
+ //now we know the scaling\r
+ //compute the scaled size and position\r
+\r
+ jpeg_start_decompress(&cinfo);\r
+ //picturew/h is now the output width from the decompressor and afterscaler\r
+ //this is unrotated \r
+ picturew=cinfo.output_width;\r
+ pictureh=cinfo.output_height;\r
+ if (scaleafter > 1) {\r
+ picturew=picturew/scaleafter;\r
+ pictureh=pictureh/scaleafter;\r
+ }\r
+ //if our image is smaller - center it\r
+ if (! ctl->enlarge) {\r
+ if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {\r
+ int dim=pictureh;\r
+ xpos=(((int)ctl->area.w)-dim)/2;\r
+ dim=picturew;\r
+ ypos=(((int)ctl->area.h)-dim)/2;\r
+ } else {\r
+ int dim=picturew;\r
+ xpos=(((int)ctl->area.w)-dim)/2;\r
+ dim=pictureh;\r
+ ypos=(((int)ctl->area.h)-dim)/2;\r
+ }\r
+ if (xpos <0) xpos=0;\r
+ if (ypos <0) ypos=0;\r
+ }\r
+ xpos+=ctl->area.x;\r
+ ypos+=ctl->area.y;\r
+ //remember the jpeg dimensions for computing the buffer\r
+ UINT jpegwidth=cinfo.output_width;\r
+ UINT jpegheight=cinfo.output_height;\r
+ logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, jw=%i, jh=%i, rot=%d", \r
+ picturew, pictureh,xpos,ypos,jpegwidth,jpegheight,(int)ctl->finalRotation*90);\r
+\r
+ //fill the background\r
+ sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour.rgba());\r
+\r
+ //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)\r
+ int linelen=jpegwidth*3;\r
+#ifdef USE_BUFFER\r
+ // MAKE THE 2D ARRAY\r
+ buffer = (unsigned char*)malloc(jpegheight * linelen);\r
+ logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, lines = %i linelen = %i", buffer, jpegheight, linelen);\r
+ if (buffer == NULL) {\r
+ if (rdr) jpeg_memio_cleanup(&cinfo);\r
+ jpeg_destroy_decompress(&cinfo);\r
+ logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");\r
+ SNPRINTF(ctl->error,100,"no room for buffer");\r
+ return false;\r
+ }\r
+#endif\r
+\r
+#ifndef USE_BUFFER\r
+ //unsigned char lbuf[linelen];\r
+ unsigned char *lbuf=new unsigned char[linelen*scaleafter];\r
+ unsigned char * ptr=lbuf;\r
+ UINT outy=0;\r
+#else\r
+ unsigned char * ptr=buffer;\r
+#endif\r
+\r
+ int rowsread = 0;\r
+\r
+ Colour c;\r
+ sfc->startFastDraw();//Tell the surface, that we will draw a lot of pixel,\r
+ //so that performance, can be optimized\r
+ logger->log("BJpeg", Log::DEBUG, "start drawing ");\r
+ UINT colincr=0;\r
+ //factors to base 1024\r
+ UINT fac=1024;\r
+ if (scaleafter > 1) {\r
+ colincr=3*scaleafter-3;\r
+ fac=1024/(scaleafter*scaleafter);\r
+ }\r
+ logger->log("BJpeg", Log::DEBUG, "jpeg draw scale %d image: %u %u, picture: %u %u", scaleafter,picturew,pictureh,jpegwidth,jpegheight);\r
+ while (cinfo.output_scanline < jpegheight)\r
+ {\r
+// logger->log("BJpeg", Log::DEBUG, "%i", rowsread);\r
+ rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);\r
+#ifdef USE_BUFFER\r
+ ptr+=linelen;\r
+#else\r
+ if (scaleafter > 1) {\r
+ if (rowsread % scaleafter != scaleafter-1) {\r
+ //this simple approach wold maybe forget scaleafter -1 lines at the end...\r
+ ptr+=linelen;\r
+ continue;\r
+ }\r
+ ptr=lbuf;\r
+ }\r
+ drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);\r
+ outy++;\r
+ \r
+#endif\r
+ }\r
+ sfc->endFastDraw();\r
+\r
+ logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");\r
+\r
+ jpeg_finish_decompress(&cinfo);\r
+ jpeg_memio_cleanup(&cinfo);\r
+ jpeg_destroy_decompress(&cinfo);\r
+\r
+ logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");\r
+ rdr->drawingDone();\r
+\r
+#ifdef USE_BUFFER\r
+ UINT y;\r
+ //Tell the surface, that we will draw a lot of pixel,\r
+ //so that performance, can be optimized\r
+ sfc->startFastDraw();\r
+ logger->log("BJpeg", Log::DEBUG, "jpeg start buffer draw" );\r
+ unsigned char* p=buffer; //start of first row\r
+ UINT rowincr=linelen*scaleafter;\r
+ //for simplicity omit last line to avoid running out of buffer\r
+ for (y = 0; y < pictureh-1 ;y++)\r
+ {\r
+ drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);\r
+ p+=rowincr;\r
+ }\r
+ sfc->endFastDraw();\r
+ logger->log("BJpeg", Log::DEBUG, "end draw");\r
+ free(buffer);\r
+#else\r
+ delete[] lbuf;\r
+#endif\r
+ logger->log("BJpeg", Log::DEBUG, "deleted buffer");\r
+ return true;\r
+}\r
+\r
+\r
+#else\r
+bool WJpegComplex::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, Colour & backgroundColour) {\r
+ return true;\r
+}\r
+#endif\r
+\r
+//get my own surface\r
+Surface * WJpegComplex::getSurface(Region & r) {\r
+ r.x=getRootBoxOffsetX();\r
+ r.y=getRootBoxOffsetY();\r
+ r.w=area.w;\r
+ r.h=area.h;\r
+ return Boxx::getSurface();\r
+}\r
+\r
--- /dev/null
+/*\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 WJPEGCOMPLEX_H\r
+#define WJPEGCOMPLEX_H\r
+\r
+// This is the complex jpeg readeing stuff not supported on all plattforms\r
+\r
+\r
+#include <stdio.h>\r
+#include <malloc.h>\r
+\r
+#ifdef WIN32\r
+\r
+#include <winsock2.h>\r
+#include <windows.h>\r
+\r
+\r
+//#define NEED_FAR_POINTERS\r
+#define XMD_H //workaround some compiling issues\r
+#endif\r
+\r
+class Surface;\r
+class Boxx;\r
+\r
+//a reader to be implemented by the caller\r
+class JpegReader {\r
+ public:\r
+ //read the next chunk of jpeg data\r
+ //offset - from start of file\r
+ //len I buf len (max bytes to read)\r
+ //return read len, 0 on EOF, -1 on error, *buf set to buffer\r
+ //will be released with free(!!!) after decoding\r
+ virtual ULONG readChunk(ULONG offset,ULONG len,char **buf)=0;\r
+ //a callback when the drawing is complete\r
+ //the implementation is optional\r
+ virtual void drawingDone(){};\r
+ //get the size of the current picture\r
+ virtual ULONG getSize(){ return 0;}\r
+ virtual ~JpegReader(){};\r
+};\r
+class WJpegComplex : public WJpeg\r
+{\r
+ public:\r
+ \r
+ // temp for boxx\r
+ void setDimensions(int width, int height) {area.w=width;area.h=height;};\r
+ \r
+ \r
+ WJpegComplex();\r
+ virtual ~WJpegComplex();\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
+ int init(const char* fileName);\r
+ void draw();\r
+\r
+ bool hasError();\r
+ \r
+ //mode for scaling pictures\r
+ enum ScaleMode {\r
+ LETTER=0,\r
+ CROP=1,\r
+ CROPPERCENT=2};\r
+ //rotations\r
+ enum Rotation{\r
+ ROT_0=0,\r
+ ROT_90=1,\r
+ ROT_180=2,\r
+ ROT_270=3\r
+ };\r
+ //jpeg info \r
+ struct JpegControl {\r
+ public:\r
+ //the available drawing area\r
+ Region area;\r
+ bool enlarge;\r
+ //the maximum allowed scale factor after decompress\r
+ UINT scaleafter;\r
+ //the scale mode\r
+ enum ScaleMode mode;\r
+ //the size value if scaleMode==cropPercent\r
+ //%of the drawing area size\r
+ UINT scaleAmount;\r
+ //the rotation (user defined as input)\r
+ //if exif rotation is found this will be added\r
+ enum Rotation rotation;\r
+\r
+ //paremeters filled during Jpeg parsing\r
+ enum Rotation exifRotation;\r
+ char exifDate[30];\r
+ char error[100];\r
+ UINT picw;\r
+ UINT pich;\r
+ ULONG compressedSize;\r
+\r
+ //parameters computed to display picture\r
+ enum Rotation finalRotation;\r
+ //scale in %\r
+ UINT scale;\r
+ JpegControl() {\r
+ area.x=0;\r
+ area.y=0;\r
+ area.w=0;\r
+ area.h=0;\r
+ enlarge=false;\r
+ scaleafter=3;\r
+ scaleAmount=110;\r
+ mode=CROPPERCENT;\r
+ rotation=ROT_0;\r
+ exifRotation=ROT_0;\r
+ finalRotation=ROT_0;\r
+ exifDate[0]='\0';\r
+ error[0]='\0';\r
+ picw=0;\r
+ pich=0;\r
+ compressedSize=0;\r
+ scale=100;\r
+ }\r
+ };\r
+\r
+ //the standalone drawing function\r
+ //this will draw into the provided surface\r
+ //the reader has to be initialized before\r
+ //calling this function does not need a WJpeg being instantiated\r
+ //it simply draws into the surface\r
+ bool static drawJpeg(JpegControl * control, Surface* sfc, JpegReader *rdr, Colour & backgroundColour);\r
+\r
+ private:\r
+ //our drawPixel with considers rotation\r
+ /* handle picture rotation\r
+ 90: xr=h-y\r
+ yr=x\r
+ 180:xr=w-x\r
+ yr=h-y\r
+ 270:xr=y\r
+ yr=w-x\r
+ */\r
+#ifndef __ANDROID__\r
+ inline static void drawPixel(Surface * sfc,enum Rotation rotate,int x, int y,int w,int h,int xpos, int ypos,Colour c){\r
+ int xb=0;\r
+ int yb=0;\r
+ switch(rotate) {\r
+ case ROT_0:\r
+ xb=x;\r
+ yb=y;\r
+ break;\r
+ case ROT_90:\r
+ xb=h-y;\r
+ yb=x;\r
+ break;\r
+ case ROT_180:\r
+ xb=w-x;\r
+ yb=h-y;\r
+ break;\r
+ case ROT_270:\r
+ xb=y;\r
+ yb=w-x;\r
+ break;\r
+ }\r
+ xb+=xpos;\r
+ yb+=ypos;\r
+ if (xb < 0 || yb < 0 ) {\r
+ return;\r
+ }\r
+ sfc->drawPixel((UINT)xb,(UINT)yb,c,true);\r
+ }\r
+\r
+ /**\r
+ draw a line of pixels coming from the decompressor\r
+ if scaleafter > 1 we draw that many lines (numlines is the# lines in the buffer)\r
+ picturew is the resulting width of the picture\r
+ **/ \r
+ inline static void drawLine(Surface *sfc,enum Rotation rotate, unsigned char *cp,UINT scaleafter,UINT picturew,UINT pictureh, \r
+ UINT xpos, UINT ypos, UINT outy, UINT linelen,UINT pixeloffset, UINT numlines, UINT fac) {\r
+ Colour c;\r
+ for (UINT x = 0; x < picturew; x++)\r
+ {\r
+ if (scaleafter > 1 ) {\r
+ //boxfilter scalefactor*scalefactor\r
+ //take 0...scalefactor pixels in x and y direction\r
+ for (int colornum=0;colornum<3;colornum++) {\r
+ UINT comp=0;\r
+ unsigned char * accp=cp;\r
+ for (UINT rows=0;rows<scaleafter;rows++) {\r
+ unsigned char * pp=accp;\r
+ for (UINT cols=0;cols<scaleafter;cols++) {\r
+ comp+=(UINT)*pp;\r
+ if (pp-accp < (int)linelen-3) pp+=3;\r
+ }\r
+ if (rows < numlines) accp+=linelen;\r
+ }\r
+ comp=(comp*fac) >> 10;\r
+ if (colornum == 0) c.red=comp;\r
+ if (colornum == 1) c.green=comp;\r
+ if (colornum == 2) c.blue=comp;\r
+ cp++;\r
+ }\r
+ \r
+ }\r
+ else {\r
+ c.red = *cp;cp++;\r
+ c.green = *cp;cp++;\r
+ c.blue = *cp;cp++;\r
+ }\r
+ cp+=pixeloffset;\r
+ drawPixel(sfc,rotate,x, outy, picturew,pictureh,xpos,ypos,c);\r
+ }\r
+ }\r
+#endif\r
+ //find my own surface and fill the area with my x and y offset within\r
+ Surface * getSurface(Region &a);\r
+\r
+ JpegReader *reader;\r
+ bool owningReader;\r
+ char errbuf[200];\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\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 "wjpegsimple.h"\r
+#include <setjmp.h>\r
+#include <sys/types.h>\r
+#include <sys/stat.h>\r
+\r
+\r
+\r
+#include "i18n.h"\r
+#include "log.h"\r
+#include "surface.h"\r
+\r
+\r
+\r
+\r
+WJpegSimple::WJpegSimple(){\r
+\r
+}\r
+\r
+WJpegSimple::~WJpegSimple() {\r
+\r
+}\r
+\r
+int WJpegSimple::init(const char* tfileName)\r
+{\r
+ fileName=tfileName;\r
+\r
+ return 1;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+void WJpegSimple::draw()\r
+{\r
+ int width,height;\r
+ width=height=1;\r
+ drawJpeg(fileName,0,0,&width,&height);//This should went into the abstract base classes?\r
+ //Windows has a problem with the leading / fixme\r
+ setDimensions(width, height);\r
+\r
+}\r
+\r
+\r
+\r
+\r
--- /dev/null
+/*\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 WJPEGSIMPLE_H\r
+#define WJPEGSIMPLE_H\r
+\r
+#include <stdio.h>\r
+#include <malloc.h>\r
+#include "wjpeg.h"\r
+\r
+\r
+class WJpegSimple : public WJpeg\r
+{\r
+public:\r
+ \r
+ // temp for boxx\r
+ void setDimensions(int width, int height) {area.w=width;area.h=height;};\r
+ \r
+ \r
+ WJpegSimple();\r
+ virtual ~WJpegSimple();\r
+ // Only old style usage - load local file\r
+\r
+ int init(const char* fileName);\r
+ void draw();\r
+\r
+private:\r
+ const char* fileName;\r
+\r
+\r
+};\r
+\r
+#endif\r