From 88e8e833cbe6bda6a96210b590942b9338d8209e Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sat, 22 Apr 2006 23:35:06 +0000 Subject: [PATCH] Windows port. New sync code. Various other bug fixes. --- Makefile | 2 +- afeed.cc | 12 ++ afeed.h | 11 +- afeedr.cc | 14 ++ afeedr.h | 11 +- audio.h | 3 +- audiomvp.cc | 7 + audiomvp.h | 4 + audiowin.cc | 114 +++++++++- audiowin.h | 6 + command.cc | 41 ++-- defines.h | 6 +- demuxer.cc | 20 +- demuxer.h | 11 + draintarget.cc | 27 +++ draintarget.h | 66 ++++++ dsock.h | 3 +- dssourcefilter.cc | 103 +++++++++ dssourcefilter.h | 47 +++++ dssourcepin.cc | 143 +++++++++++++ dssourcepin.h | 48 +++++ ledwin.cc | 1 - log.cc | 6 +- log.h | 1 - main.cc | 2 +- mtdwin.cc | 4 +- mtdwin.h | 6 +- osd.h | 2 +- osdmvp.cc | 4 +- osdmvp.h | 2 +- osdwin.cc | 191 ++++++++++++++++- osdwin.h | 32 ++- player.cc | 159 +++++--------- player.h | 2 + remotewin.cc | 153 +++++++++++++- remotewin.h | 12 ++ stream.cc | 140 ++++++++++++- stream.h | 13 ++ surfacewin.cc | 183 +++++++++++++++- surfacewin.h | 13 +- tcp.cc | 34 ++- threadwin.cc | 20 +- threadwin.h | 4 +- timers.cc | 7 +- vepg.cc | 12 +- vepgsettimer.cc | 9 + vfeed.cc | 13 ++ vfeed.h | 12 +- video.h | 5 +- videomvp.cc | 11 + videomvp.h | 4 + videowin.cc | 349 ++++++++++++++++++++++++++++++- videowin.h | 45 ++++ vlivebanner.cc | 4 + vompreswin.h | 30 +++ vompwin.rc | 43 ++++ vrecordinglist.cc | 4 + vvideolive.cc | 12 ++ winmain.cc | 519 ++++++++++++++++++++++++++++++++++++++++++++++ wjpeg.cc | 6 + 60 files changed, 2577 insertions(+), 191 deletions(-) create mode 100644 draintarget.cc create mode 100644 draintarget.h create mode 100644 dssourcefilter.cc create mode 100644 dssourcefilter.h create mode 100644 dssourcepin.cc create mode 100644 dssourcepin.h create mode 100644 vompreswin.h create mode 100644 vompwin.rc create mode 100644 winmain.cc diff --git a/Makefile b/Makefile index 3a47e85..4987f72 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ CROSSLIBS = ../jpeg-6b/libjpeg.a OBJECTS1 = main.o command.o log.o tcp.o dsock.o thread.o timers.o i18n.o \ message.o messagequeue.o \ vdr.o recording.o channel.o rectimer.o event.o directory.o \ - player.o demuxer.o stream.o vfeed.o afeed.o afeedr.o \ + player.o demuxer.o stream.o vfeed.o afeed.o afeedr.o draintarget.o \ viewman.o box.o region.o colour.o view.o \ vinfo.o vwallpaper.o vvolume.o vrecordinglist.o vlivebanner.o vmute.o \ vtimerlist.o vtimeredit.o voptionsmenu.o vrecordingmenu.o vquestion.o \ diff --git a/afeed.cc b/afeed.cc index a61f286..bb15a73 100644 --- a/afeed.cc +++ b/afeed.cc @@ -26,11 +26,19 @@ AFeed::AFeed(Callback* tcb) audioEnabled = 1; } +#ifndef NEW_DEMUXER int AFeed::init(int tfd) { fd = tfd; return 1; } +#else +int AFeed::init(DrainTarget* tdt) +{ + dt = tdt; + return 1; +} +#endif int AFeed::shutdown() { @@ -71,7 +79,11 @@ void AFeed::threadMethod() if (audioEnabled) { +#ifndef NEW_DEMUXER alen = Demuxer::getInstance()->writeAudio(fd); // FIXME ? +#else + alen = Demuxer::getInstance()->writeAudio(dt); // FIXME ? +#endif if (alen) { diff --git a/afeed.h b/afeed.h index d5739fb..f67770b 100644 --- a/afeed.h +++ b/afeed.h @@ -27,6 +27,7 @@ #include "log.h" #include "demuxer.h" #include "callback.h" +#include "draintarget.h" #ifdef WIN32 #include "threadwin.h" @@ -34,12 +35,16 @@ #include "threadp.h" #endif + class AFeed : public Thread_TYPE { public: AFeed(Callback* tcb); - +#ifndef NEW_DEMUXER int init(int fd); +#else + int init(DrainTarget* tdt); +#endif int shutdown(); int start(); @@ -51,7 +56,11 @@ class AFeed : public Thread_TYPE void threadMethod(); void threadPostStopCleanup() {}; int audioEnabled; +#ifndef NEW_DEMUXER int fd; +#else + DrainTarget* dt; +#endif Callback& cb; }; diff --git a/afeedr.cc b/afeedr.cc index 6abc737..f88c996 100644 --- a/afeedr.cc +++ b/afeedr.cc @@ -25,11 +25,20 @@ AFeedR::AFeedR(Callback* tcb, Stream* tstream) { } +#ifndef NEW_DEMUXER int AFeedR::init(int tfd) { fd = tfd; return 1; } +#else +int AFeedR::init(DrainTarget* tdt) +{ + dt = tdt; + return 1; +} +#endif + int AFeedR::shutdown() { @@ -55,7 +64,12 @@ void AFeedR::threadMethod() while(1) { +#ifndef NEW_DEMUXER alen = stream.drain(fd); +#else + alen = stream.drain(dt); + threadCheckExit(); +#endif if (alen) { diff --git a/afeedr.h b/afeedr.h index 8f12e20..9967420 100644 --- a/afeedr.h +++ b/afeedr.h @@ -27,6 +27,7 @@ #include "log.h" #include "callback.h" #include "stream.h" +#include "draintarget.h" #ifdef WIN32 #include "threadwin.h" @@ -38,8 +39,11 @@ class AFeedR : public Thread_TYPE { public: AFeedR(Callback* tcb, Stream* tstream); - +#ifndef NEW_DEMUXER int init(int fd); +#else + int init(DrainTarget* tdt); +#endif int shutdown(); int start(); @@ -48,8 +52,11 @@ class AFeedR : public Thread_TYPE private: void threadMethod(); void threadPostStopCleanup() {}; - +#ifndef NEW_DEMUXER int fd; +#else + DrainTarget* dt; +#endif Callback& cb; Stream& stream; }; diff --git a/audio.h b/audio.h index 8144d97..23751d8 100644 --- a/audio.h +++ b/audio.h @@ -24,6 +24,7 @@ #include #include "defines.h" #include "log.h" +#include "draintarget.h" typedef struct { @@ -35,7 +36,7 @@ typedef struct unsigned char lfe; } audio_volume; -class Audio +class Audio : public DrainTarget { public: Audio(); diff --git a/audiomvp.cc b/audiomvp.cc index 9ab5253..d9218c6 100644 --- a/audiomvp.cc +++ b/audiomvp.cc @@ -239,3 +239,10 @@ int AudioMVP::test() } #endif + + +// unused +UINT AudioMVP::DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos) +{ + return 0; +} diff --git a/audiomvp.h b/audiomvp.h index 7b48a10..a9223b3 100644 --- a/audiomvp.h +++ b/audiomvp.h @@ -57,6 +57,10 @@ class AudioMVP : public Audio int write(char *buf, int len); int getFD(); + //Writing Data to Audiodevice -- unused in MVP code so far + virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos); + virtual long long SetStartOffset(long long curreftime, bool *rsync) { return 0; }; + #ifdef DEV int test(); #endif diff --git a/audiowin.cc b/audiowin.cc index 75019e3..db3f932 100644 --- a/audiowin.cc +++ b/audiowin.cc @@ -19,15 +19,23 @@ */ #include "audiowin.h" +#include "videowin.h" + + + + AudioWin::AudioWin() { - if (instance) return; initted = 0; + firstsynched=false; + + } AudioWin::~AudioWin() { + } int AudioWin::init(UCHAR tstreamType) @@ -81,6 +89,8 @@ int AudioWin::sync() int AudioWin::play() { if (!initted) return 0; + firstsynched=false; + return 1; } @@ -118,15 +128,117 @@ int AudioWin::setVolume(int tvolume) int AudioWin::mute() { if (!initted) return 0; + ((VideoWin*)Video::getInstance())->SetAudioState(false); return 1; } int AudioWin::unMute() { if (!initted) return 0; + ((VideoWin*)Video::getInstance())->SetAudioState(true); return 1; } +UINT AudioWin::DeliverMediaSample(MediaPacket packet, + UCHAR* buffer, + UINT *samplepos) +{ + /*First Check, if we have an audio sample*/ + VideoWin *vw=(VideoWin*)Video::getInstance(); + IMediaSample* ms=NULL; + REFERENCE_TIME reftime1=0; + REFERENCE_TIME reftime2=0; + + UINT headerstrip=0; + if (packet.disconti) { + firstsynched=false; + vw->DeliverVideoMediaSample(); + } + + + + /*Inspect PES-Header */ +/* UINT header_length=buffer[(packet.pos_buffer+8)%bufferlength]+8/*is this right*; +*/ + if (*samplepos==0) {//stripheader + headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/; + *samplepos+=headerstrip; + if ( packet.synched ) { + vw->DeliverAudioMediaSample();//write out old data + if (packet.presentation_time<0) { //Preroll? + *samplepos=packet.length;//if we have not processed at least one + return packet.length;//synched packet ignore it! + } + + reftime1=packet.presentation_time; + reftime2=reftime1+1; + firstsynched=true; + } else { + if (!firstsynched) {// + *samplepos=packet.length;//if we have not processed at least one + return packet.length;//synched packet ignore it! + } + } + } + BYTE *ms_buf; + UINT ms_length; + UINT ms_pos; + UINT haveToCopy; + if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample + samplepos=0; + MILLISLEEP(10); + return 0; + } + ms_pos=ms->GetActualDataLength(); + ms_length=ms->GetSize(); + haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos); + if ((ms_length-ms_pos)<1) { + vw->DeliverAudioMediaSample(); //we are full! + if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample + samplepos=0; + MILLISLEEP(10); + return 0; + } + ms_pos=ms->GetActualDataLength(); + ms_length=ms->GetSize(); + haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos); + } + ms->GetPointer(&ms_buf); + + if (ms_pos==0) {//will only be changed on first packet + if (packet.disconti) { + ms->SetDiscontinuity(TRUE); + } else { + ms->SetDiscontinuity(FALSE); + } + if (packet.synched) { + ms->SetSyncPoint(TRUE); + ms->SetTime(&reftime1,&reftime2); + //ms->SetTime(NULL,NULL); + ms->SetMediaTime(NULL, NULL); + }else { + ms->SetSyncPoint(FALSE); + ms->SetTime(NULL,NULL); + ms->SetMediaTime(NULL, NULL); + ms->SetSyncPoint(TRUE); + } + } + + + memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy); + ms->SetActualDataLength(haveToCopy+ms_pos); + + *samplepos+=haveToCopy; + + return haveToCopy+headerstrip; + +} + +long long AudioWin::SetStartOffset(long long curreftime, bool *rsync){ + VideoWin *vw=(VideoWin*)Video::getInstance(); + return vw->SetStartAudioOffset(curreftime,rsync); +} + #ifdef DEV int AudioWin::test() { diff --git a/audiowin.h b/audiowin.h index e1c2e0c..a31bf91 100644 --- a/audiowin.h +++ b/audiowin.h @@ -49,6 +49,12 @@ class AudioWin : public Audio int write(char *buf, int len); int getFD(); + // Writing Data to Audiodevice + virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos); + virtual long long SetStartOffset(long long curreftime, bool *rsync); + +private: + bool firstsynched; #ifdef DEV int test(); #endif diff --git a/command.cc b/command.cc index 023debc..63b3817 100644 --- a/command.cc +++ b/command.cc @@ -19,6 +19,9 @@ */ #include "command.h" +#ifdef WIN32 +#include "remotewin.h" +#endif Command* Command::instance = NULL; @@ -147,9 +150,9 @@ void Command::run() // something happened, lock and process #ifndef WIN32 - pthread_mutex_lock(&masterLock); + pthread_mutex_lock(&masterLock); #else - WaitForSingleObject(masterLock, INFINITE ); + WaitForSingleObject(masterLock, INFINITE ); #endif if ((button == Remote::NA_NONE) || (button == Remote::NA_UNKNOWN)) continue; @@ -159,9 +162,9 @@ void Command::run() } #ifndef WIN32 - pthread_mutex_unlock(&masterLock); + pthread_mutex_unlock(&masterLock); #else - ReleaseMutex(masterLock); + ReleaseMutex(masterLock); #endif } @@ -174,18 +177,18 @@ void Command::postMessage(Message* m) #ifndef WIN32 - pthread_mutex_lock(&masterLock); + pthread_mutex_lock(&masterLock); #else - WaitForSingleObject(masterLock, INFINITE ); + WaitForSingleObject(masterLock, INFINITE ); #endif - MessageQueue::postMessage(m); + MessageQueue::postMessage(m); #ifndef WIN32 - kill(mainPid, SIGURG); - pthread_mutex_unlock(&masterLock); + kill(mainPid, SIGURG); + pthread_mutex_unlock(&masterLock); #else - //TODO: send Window Message - ReleaseMutex(masterLock); + ((RemoteWin*)Remote::getInstance())->Signal(); + ReleaseMutex(masterLock); #endif } @@ -215,17 +218,19 @@ bool Command::postMessageIfNotBusy(Message* m) return false; } #else - if (WaitForSingleObject(masterLock, INFINITE ) == WAIT_OBJECT_0) - { + switch (WaitForSingleObject(masterLock, 0 )) + { //FIXME this is not "if not busy" check + case WAIT_OBJECT_0: //but with proper argument 0 this did not work + // case WAIT_ABANDONED: MessageQueue::postMessage(m); - //TODO: send Window Message + ((RemoteWin*)Remote::getInstance())->Signal(); ReleaseMutex(masterLock); return true; + + case WAIT_ABANDONED: return false; + case WAIT_TIMEOUT: return false; } - else - { return false; - } #endif } @@ -459,7 +464,7 @@ void Command::doJustConnected(VConnect* vconnect) logger->log("Command", Log::DEBUG, "Switching to NTSC"); video->init(Video::NTSC); } - osd->init("/dev/stbgfx"); + osd->init((char*)("/dev/stbgfx")); // Put the wallpaper back doWallpaper(); diff --git a/defines.h b/defines.h index d4c13bc..2fc1292 100644 --- a/defines.h +++ b/defines.h @@ -21,6 +21,10 @@ #ifndef DEFINES_H #define DEFINES_H +//#define NEW_DEMUXER //Switch for the new demuxer code +//At the beginning the changed code will be switchable +//in order to apply the changes also to the mvp code + typedef unsigned char UCHAR; typedef unsigned short USHORT; typedef unsigned int UINT; @@ -41,7 +45,7 @@ void MILLISLEEP(ULONG a); #define SNPRINTF _snprintf #define VSNPRINTF _vsnprintf - #define STRCASECMP stricmp + #define STRCASECMP _stricmp #define STRCASESTR StrStrI #define STRTOULL _strtoui64 #define CLOSESOCKET closesocket diff --git a/demuxer.cc b/demuxer.cc index f9c22f9..1911f44 100644 --- a/demuxer.cc +++ b/demuxer.cc @@ -52,10 +52,14 @@ int Demuxer::init(Callback* tcallback) !audiostream.init(demuxMemoryA) || !(local_frame = (UCHAR *) malloc(0x10000))) { - // printf("failed to initialize demuxer\n"); + Log::getInstance()->log("Demuxer", Log::CRIT, "Failed to initialize demuxer"); shutdown(); return 0; } +#ifdef NEW_DEMUXER + videostream.setDrainTarget(Video::getInstance()); + audiostream.setDrainTarget(Audio::getInstance()); +#endif } reset(); @@ -125,7 +129,7 @@ void Demuxer::setAspectRatio(enum AspectRatio ar) else arcnt = 0; } - +#ifndef NEW_DEMUXER int Demuxer::writeAudio(int fd) { return audiostream.drain(fd); @@ -135,6 +139,18 @@ int Demuxer::writeVideo(int fd) { return videostream.drain(fd); } +#else +int Demuxer::writeAudio(DrainTarget* dt) +{ + return audiostream.drain(dt); +} + +int Demuxer::writeVideo(DrainTarget* dt) +{ + return videostream.drain(dt); +} +#endif + int Demuxer::scan(UCHAR *buf, int len) { diff --git a/demuxer.h b/demuxer.h index f935dbc..604b3cd 100644 --- a/demuxer.h +++ b/demuxer.h @@ -36,6 +36,11 @@ however, no code was copied verbatim. #include "log.h" #include "defines.h" #include "callback.h" +#include "draintarget.h" + +#include "audio.h" +#include "video.h" + class Demuxer { @@ -50,8 +55,14 @@ class Demuxer void seek(); void setVideoStream(int id); void setAudioStream(int id); +#ifndef NEW_DEMUXER int writeAudio(int fd); int writeVideo(int fd); +#else + int writeAudio(DrainTarget* dt); + int writeVideo(DrainTarget* dt); +#endif + int scan(UCHAR* buf, int len); int findVideoPTS(UCHAR* buf, int len, ULLONG* dest); int put(UCHAR* buf, int len); diff --git a/draintarget.cc b/draintarget.cc new file mode 100644 index 0000000..25b89e4 --- /dev/null +++ b/draintarget.cc @@ -0,0 +1,27 @@ +/* + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include "draintarget.h" +DrainTarget::DrainTarget(){ + + +} +DrainTarget::~DrainTarget(){ + +} \ No newline at end of file diff --git a/draintarget.h b/draintarget.h new file mode 100644 index 0000000..4196e2a --- /dev/null +++ b/draintarget.h @@ -0,0 +1,66 @@ +/* + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DRAINTARGET_H +#define DRAINTARGET_H + +#include "defines.h" +#include + + + + +struct MediaPacket{ + ULLONG recording_byte_pos; //position in recording + ULLONG pts; + ULONG pos_buffer; //position in stream buffer + ULONG length; //length of the packet + //The last to are only needed on windows, for memory reasons they can be excluded in mvp + long long presentation_time;/* in 100 ns units*/ + bool synched; + bool disconti; +}; + +using namespace std; + +typedef list MediaPacketList; + + +class DrainTarget { +public: + DrainTarget(); + virtual ~DrainTarget(); + virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, + UINT *samplepos)=0; + +/* This function behaviour should be: +Try to deliver the Data from packet.pos_buffer+samplepos to packet.pos_buffer+packet.length, +with considering the bufferwraparound according to buffersize. +Then increasing samplepos, so that on the next call delivering can proceed. So if writebytes are +writen samplepos=samplepos+writebytes! +If samplepos>=packet.length is returned, the next packet can be used for the next call.*/ + + virtual long long SetStartOffset(long long curreftime, bool *rsync)=0; +}; + + + + +#endif \ No newline at end of file diff --git a/dsock.h b/dsock.h index 15f3700..ba99d47 100644 --- a/dsock.h +++ b/dsock.h @@ -32,14 +32,13 @@ #include #endif -#include +#include #ifndef WIN32 #include #else #include #endif - #include #include #include diff --git a/dssourcefilter.cc b/dssourcefilter.cc new file mode 100644 index 0000000..c779dfd --- /dev/null +++ b/dssourcefilter.cc @@ -0,0 +1,103 @@ +/* + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include "dssourcefilter.h" + +DsSourceFilter::DsSourceFilter():CBaseFilter("Vomp Source Filter",NULL,&crit_sec,_uuidof(this)) +{ + //add audio pin + HRESULT res; + audiopin=new DsSourcePin(this,&crit_sec,&res,L"Vomp Audio Out",true); + videopin=new DsSourcePin(this,&crit_sec,&res,L"Vomp Video Out",false); + +} + +DsSourceFilter::~DsSourceFilter() +{ + if (audiopin) delete audiopin; + if (videopin) delete videopin; +} + +int DsSourceFilter::GetPinCount() +{ + return 2; //audio and video +} + +CBasePin *DsSourceFilter::GetPin(int n){ + switch (n) { + case 0: + return audiopin; + case 1: + return videopin; + default: + return 0; + }; +} + +int DsSourceFilter::getCurrentAudioMediaSample(IMediaSample** ms) +{ + if (!audiopin || !IsActive()) { + return 0; + } + if (audiopin->GetDeliveryBuffer(ms,NULL,NULL,0)!=S_OK) { + return 0; + } + return 1; +} + +int DsSourceFilter::getCurrentVideoMediaSample(IMediaSample** ms) +{ + if (!videopin || !IsActive()) { + return 0; + } + if (videopin->GetDeliveryBuffer(ms,NULL,NULL,0)!=S_OK) { + return 0; + } + return 1; +} + +int DsSourceFilter::DeliverAudioMediaSample(IMediaSample* ms) +{ + if (!audiopin || !IsActive()) { + ms->Release(); + return 0; + } + if (audiopin->Deliver(ms)!=S_OK) { + ms->Release(); + return 0; + } + ms->Release(); + return 1; + +} + +int DsSourceFilter::DeliverVideoMediaSample(IMediaSample* ms) +{ + if (!videopin || !IsActive()) { + ms->Release(); + return 0; + } + if (videopin->Deliver(ms)!=S_OK) { + ms->Release(); + return 0; + } + ms->Release(); + return 1; + +} diff --git a/dssourcefilter.h b/dssourcefilter.h new file mode 100644 index 0000000..e0d4597 --- /dev/null +++ b/dssourcefilter.h @@ -0,0 +1,47 @@ +/* + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DSSOURCEFILTER_H +#define DSSOURCEFILTER_H + + +#include "dssourcepin.h" + +[uuid("EB87AB22-7A95-49c3-8CCE-2F6D61A87009")] +class DsSourceFilter: public CBaseFilter { +public: + DsSourceFilter(); + ~DsSourceFilter(); + CCritSec* GetLock(){return &crit_sec;}; + virtual int GetPinCount(); + virtual CBasePin *GetPin(int n); + int getCurrentAudioMediaSample(IMediaSample** ms); + int DeliverAudioMediaSample(IMediaSample* ms); + int getCurrentVideoMediaSample(IMediaSample** ms); + int DeliverVideoMediaSample(IMediaSample* ms); +protected: + CCritSec crit_sec; + DsSourcePin *audiopin; + DsSourcePin *videopin; + + +}; + +#endif \ No newline at end of file diff --git a/dssourcepin.cc b/dssourcepin.cc new file mode 100644 index 0000000..70286ee --- /dev/null +++ b/dssourcepin.cc @@ -0,0 +1,143 @@ +/* + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include "dssourcepin.h" +#include "dssourcefilter.h" +#include +#include + +DsSourcePin::DsSourcePin(DsSourceFilter *pFilter, + CCritSec *pLock,HRESULT *phr,LPCWSTR pName,bool audio): +CBaseOutputPin(NAME("dssourcepin"),pFilter,pLock,phr,pName) +{ + isaudiopin=audio; + m_pFilter=pFilter; + +} + +DsSourcePin::~DsSourcePin() +{ + + +} + +HRESULT DsSourcePin::GetMediaType(int iPosition, CMediaType *pmt) +{ + HRESULT hr; + ASSERT(pmt); + pmt->InitMediaType(); + if (isaudiopin){ + if (iPosition==0) { + pmt->SetType(&MEDIATYPE_Audio); + MPEG1WAVEFORMAT wfe; + ZeroMemory(&wfe,sizeof(wfe)); + wfe.wfx.cbSize=22; + wfe.wfx.nSamplesPerSec=48000; + wfe.wfx.nChannels=2; + wfe.wfx.nAvgBytesPerSec=32000; + wfe.wfx.nBlockAlign=768; + wfe.wfx.wFormatTag=WAVE_FORMAT_MPEG; + wfe.fwHeadLayer=2; + wfe.dwHeadBitrate=256000; + wfe.fwHeadMode=ACM_MPEG_STEREO; + wfe.fwHeadModeExt=1; + wfe.wHeadEmphasis=1; + wfe.fwHeadFlags=ACM_MPEG_ID_MPEG1 |ACM_MPEG_ORIGINALHOME | ACM_MPEG_PROTECTIONBIT; + pmt->SetSubtype(&MEDIASUBTYPE_MPEG2_AUDIO); + pmt->SetFormatType(&FORMAT_WaveFormatEx); + pmt->SetFormat((BYTE*)&wfe,sizeof(wfe)); + pmt->SetSampleSize(0); + hr=S_OK; + + + } else { + hr=VFW_S_NO_MORE_ITEMS ; + } + } else { + if (iPosition == 0) { + pmt->SetType(&MEDIATYPE_Video); + hr=S_OK; + pmt->SetSubtype(&MEDIASUBTYPE_MPEG2_VIDEO); + pmt->SetFormatType(&FORMAT_MPEG2Video); + + MPEG2VIDEOINFO hdr; + ZeroMemory(&hdr,sizeof(hdr)); + hdr.dwProfile=AM_MPEG2Profile_Main; + hdr.dwLevel=AM_MPEG2Level_Main; + hdr.hdr.bmiHeader.biSize = sizeof(hdr.hdr.bmiHeader); + hdr.hdr.bmiHeader.biWidth = 720; + hdr.hdr.bmiHeader.biHeight = 568; + pmt->SetFormat((BYTE*)&hdr,sizeof(hdr)); + } else { + hr=VFW_S_NO_MORE_ITEMS; + } + } + return hr ; +} + +// No description +HRESULT DsSourcePin::CheckMediaType(const CMediaType *pmt) +{ + HRESULT res; + ASSERT (pmt); + if (isaudiopin) { + bool subtype=false; +#if 0 /* For future demands ac3 */ + subtype=pmt->subtype==(MEDIASUBTYPE_DOLBY_AC3); +#endif + subtype=(pmt->subtype==(MEDIASUBTYPE_MPEG2_AUDIO)); + if (pmt->majortype==MEDIATYPE_Audio && subtype) { + res = S_OK ; + } else { + res = S_FALSE ; + } + } else { + if (pmt->majortype==MEDIATYPE_Video && + pmt-> subtype==MEDIASUBTYPE_MPEG2_VIDEO) { + res = S_OK ; + } else { + res = S_FALSE ; + } + } + return res; +} + +HRESULT DsSourcePin::DecideBufferSize(IMemAllocator *pa,ALLOCATOR_PROPERTIES *all_pp){ + HRESULT hr; + CAutoLock al(m_pFilter->GetLock()); + CheckPointer(pa, E_POINTER); + CheckPointer(all_pp, E_POINTER); + if (all_pp->cBuffers*all_pp->cbBuffer < 300*64*1024) + { + all_pp->cBuffers = 300; + all_pp->cbBuffer = 64*1024; + } + ALLOCATOR_PROPERTIES all_pp_cur; + hr =pa->SetProperties(all_pp,&all_pp_cur); + if (FAILED(hr)) + { + return hr; + } + if (all_pp_cur.cbBuffer*all_pp_cur.cBuffers < all_pp->cBuffers*all_pp->cbBuffer) + { + return E_FAIL; + } + + return S_OK; +} \ No newline at end of file diff --git a/dssourcepin.h b/dssourcepin.h new file mode 100644 index 0000000..4fe80d3 --- /dev/null +++ b/dssourcepin.h @@ -0,0 +1,48 @@ +/* + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DSPINFILTER_H +#define DSPINFILTER_H + +#include + +class DsSourceFilter; + +[uuid("17F931AB-9A87-4c65-B99E-84F5BC5F7B09")] +class DsSourcePin: public CBaseOutputPin { +public: + DsSourcePin(DsSourceFilter *pFilter, + CCritSec *pLock,HRESULT *phr,LPCWSTR pName,bool audio); + ~DsSourcePin(); + + virtual HRESULT DecideBufferSize(IMemAllocator *pa,ALLOCATOR_PROPERTIES *all_pp); +protected: + virtual HRESULT CheckMediaType(const CMediaType *pmt); + virtual HRESULT GetMediaType(int iPosition, CMediaType *pmt); + bool isaudiopin; + DsSourceFilter *m_pFilter; + + + +}; + + + +#endif \ No newline at end of file diff --git a/ledwin.cc b/ledwin.cc index 5968ca9..100e623 100644 --- a/ledwin.cc +++ b/ledwin.cc @@ -22,7 +22,6 @@ LedWin::LedWin() { - if (instance) return; initted = 0; } diff --git a/log.cc b/log.cc index 812ad13..5aa1f4c 100644 --- a/log.cc +++ b/log.cc @@ -104,10 +104,12 @@ int Log::log(char *fromModule, int level, char* message, ...) _ftime(&tb); struct tm* tms = localtime(&tb.time); #endif - spaceLeft -= strftime(buffer, spaceLeft, "%H:%M:%S.", tms); +#ifndef _MSC_VER spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tv.tv_usec); - +#else + spaceLeft -= SNPRINTF(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tb.millitm); +#endif char levelString[10]; if (level == CRAZY) strcpy(levelString, "[CRAZY] "); diff --git a/log.h b/log.h index 4f8e80c..0b5c197 100644 --- a/log.h +++ b/log.h @@ -26,7 +26,6 @@ #ifndef WIN32 #include #else - #include #include #endif diff --git a/main.cc b/main.cc index ddff33e..7c8e147 100644 --- a/main.cc +++ b/main.cc @@ -237,7 +237,7 @@ int main(int argc, char** argv) shutdown(1); } - success = osd->init("/dev/stbgfx"); + success = osd->init((void*)("/dev/stbgfx")); if (success) { logger->log("Core", Log::INFO, "OSD module initialised"); diff --git a/mtdwin.cc b/mtdwin.cc index 0c7e338..51cc3c6 100644 --- a/mtdwin.cc +++ b/mtdwin.cc @@ -19,10 +19,10 @@ */ #include "mtdwin.h" +#include "video.h" MtdWin::MtdWin() { - if (instance) return; initted = 0; } @@ -46,5 +46,5 @@ int MtdWin::shutdown() short MtdWin::getPALorNTSC() { - return 0; + return Video::PAL; //Fixme! } diff --git a/mtdwin.h b/mtdwin.h index 4a6086e..debd5d4 100644 --- a/mtdwin.h +++ b/mtdwin.h @@ -29,10 +29,10 @@ class MtdWin : public Mtd MtdWin(); ~MtdWin(); - int init(char* device); - int shutdown(); + virtual int init(char* device); + virtual int shutdown(); - short getPALorNTSC(); +virtual short getPALorNTSC(); private: int initted; diff --git a/osd.h b/osd.h index e0d57b2..c22dfe0 100644 --- a/osd.h +++ b/osd.h @@ -32,7 +32,7 @@ class Osd virtual ~Osd(); static Osd* getInstance(); - virtual int init(char* device)=0; + virtual int init(void* device)=0; virtual int shutdown()=0; virtual int getFD()=0; diff --git a/osdmvp.cc b/osdmvp.cc index a86f9a0..531d570 100644 --- a/osdmvp.cc +++ b/osdmvp.cc @@ -36,11 +36,11 @@ int OsdMVP::getFD() return fdOsd; } -int OsdMVP::init(char* device) +int OsdMVP::init(void* device) { if (initted) return 0; - fdOsd = open(device, O_RDWR); + fdOsd = open((char*)device, O_RDWR); if (!fdOsd) { Log::getInstance()->log("OSD", Log::DEBUG, "Could not open OSD device!"); diff --git a/osdmvp.h b/osdmvp.h index 5b6dfc4..ce91121 100644 --- a/osdmvp.h +++ b/osdmvp.h @@ -37,7 +37,7 @@ class OsdMVP : public Osd OsdMVP(); ~OsdMVP(); - int init(char* device); + int init(void* device); int shutdown(); int getFD(); diff --git a/osdwin.cc b/osdwin.cc index 9e4c9a5..8b2a2c4 100644 --- a/osdwin.cc +++ b/osdwin.cc @@ -19,15 +19,29 @@ */ #include "osdwin.h" +#include "mtd.h" +#include "video.h" +#include "surfacewin.h" + +//This is stuff for rendering the OSD + OsdWin::OsdWin() { - if (instance) return; + d3d=NULL; + d3ddevice=NULL; + d3dvb=NULL; + external_driving=false; + event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL); + d3dmutex = CreateMutex(NULL,FALSE,NULL); + } OsdWin::~OsdWin() { if (initted) shutdown(); + CloseHandle(event); + CloseHandle(d3dmutex); } int OsdWin::getFD() @@ -36,18 +50,104 @@ int OsdWin::getFD() return fdOsd; } -int OsdWin::init(char* device) +int OsdWin::init(void* device) { if (initted) return 0; + Video* video = Video::getInstance(); + //First Create Direct 3D Object + d3d=Direct3DCreate9(D3D_SDK_VERSION); + if (!d3d) + { + Log::getInstance()->log("OSD", Log::DEBUG, "Could not create Direct3D9 object!"); + return 0; + } + // then create the Device + D3DPRESENT_PARAMETERS d3dparas; + ZeroMemory(&d3dparas,sizeof(d3dparas)); + d3dparas.BackBufferWidth=video->getScreenWidth(); + d3dparas.BackBufferHeight=video->getScreenHeight(); + d3dparas.Windowed=TRUE; + d3dparas.SwapEffect=D3DSWAPEFFECT_COPY; + if (d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,*((HWND*) device), + D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dparas,&d3ddevice)!=D3D_OK) { + Log::getInstance()->log("OSD", Log::DEBUG, "Could not create Direct3D9 device!"); + return 0; + } + //TODO a render function and a device lost detection + + if (!InitVertexBuffer()) { + Log::getInstance()->log("OSD", Log::DEBUG, "Could not create Direct3D9 vertex buf!"); + return 0; + } + + //Now we will create the Screen + screen = new SurfaceWin(Surface::SCREEN); + SetEvent(event);//Now all devices are ready + screen->create(video->getScreenWidth(), video->getScreenHeight()); + screen->display(); initted = 1; // must set this here or create surface won't work return 1; } + +int OsdWin::InitVertexBuffer() { + Video* video = Video::getInstance(); + FLOAT texx=((float)video->getScreenWidth())/1024.f; + FLOAT texy=((float)video->getScreenHeight())/1024.f; + D3DCOLOR osdcolor=D3DCOLOR_RGBA(255,255,255,255); + osdvertices[0].c=osdcolor; + osdvertices[0].x=0.f-0.5f; + osdvertices[0].y=0.f-0.5f; + osdvertices[0].z=0.5f; + osdvertices[0].rhw=1.f; + osdvertices[0].u=0.f; + osdvertices[0].v=0.f; + osdvertices[1].c=osdcolor; + osdvertices[1].x=((float)video->getScreenWidth())-0.5f;-0.5f; + osdvertices[1].y=0.f-0.5f; + osdvertices[1].z=0.5f; + osdvertices[1].u=texx; + osdvertices[1].v=0.f; + osdvertices[1].rhw=1.f; + osdvertices[2].c=osdcolor; + osdvertices[2].x=((float)video->getScreenWidth())-0.5f; + osdvertices[2].y=((float)video->getScreenHeight())-0.5f; + osdvertices[2].z=0.5f; + osdvertices[2].rhw=1.f; + osdvertices[2].u=texx; + osdvertices[2].v=texy; + osdvertices[3].c=osdcolor; + osdvertices[3].x=0.f-0.5f; + osdvertices[3].y=((float)video->getScreenHeight())-0.5f; + osdvertices[3].z=0; + osdvertices[3].rhw=1.f; + osdvertices[3].u=0.f; + osdvertices[3].v=texy; + if (d3dvb) { + d3dvb->Release(); + d3dvb=NULL; + } + if (d3ddevice->CreateVertexBuffer(4*sizeof(OSDVERTEX),0,D3DFVF_OSDVERTEX,D3DPOOL_MANAGED, + &d3dvb,NULL)!=D3D_OK) { + return 0; + } + void *pvertex=NULL; + if (d3dvb->Lock(0,sizeof(osdvertices),&pvertex,0)!=D3D_OK) { + return 0; + } + memcpy(pvertex,osdvertices,sizeof(osdvertices)); + d3dvb->Unlock(); + return 1; +} + int OsdWin::shutdown() { if (!initted) return 0; initted = 0; + d3ddevice->Release(); + d3d->Release(); + return 1; } @@ -55,3 +155,90 @@ void OsdWin::screenShot(char* fileName) { screen->screenShot(fileName); } + +// This function is called from the WinMain function in order to get Screen updates +void OsdWin::Render() +{ + if (!initted) return ; + if (external_driving) { + Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads + } else { + InternalRendering(); + } +} + + +void OsdWin::InternalRendering(){ + WaitForSingleObject(event,INFINITE); + BeginPainting(); + if (external_driving) { + //Copy video to Backbuffer + } else { + //Clear Background + d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,255),1.0f,0); + } + //Drawing the OSD + if (d3ddevice->BeginScene()==D3D_OK) { + d3ddevice->SetStreamSource(0,d3dvb,0,sizeof(OSDVERTEX)); + d3ddevice->SetFVF(D3DFVF_OSDVERTEX); + d3ddevice->SetTexture(0,((SurfaceWin*)screen)->getD3dtexture()); + //d3ddevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE); + d3ddevice->SetTextureStageState(0, D3DTSS_ALPHAOP,D3DTOP_MODULATE); + d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE); + d3ddevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA); + d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + d3ddevice->SetRenderState(D3DRS_LIGHTING,FALSE); + + + d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2); + d3ddevice->EndScene(); + //Show it to the user! + if (d3ddevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST){ + EndPainting(); + DoLost(); + } + EndPainting(); + } + if (!external_driving) { + Sleep(4);//The User can wait for 4 milliseconds to see his changes + } +} + +void OsdWin::DoLost(){ + Log::getInstance()->log("OSD", Log::DEBUG, "Direct3D Device Lost! Reobtaining..."); + ResetEvent(event); + //First we free up all resources + Video* video = Video::getInstance(); + ((SurfaceWin*)screen)->ReleaseSurface(); + d3dvb->Release(); + d3dvb=NULL; + D3DPRESENT_PARAMETERS d3dparas; + ZeroMemory(&d3dparas,sizeof(d3dparas)); + d3dparas.BackBufferWidth=video->getScreenWidth(); + d3dparas.BackBufferHeight=video->getScreenHeight(); + d3dparas.Windowed=TRUE; + d3dparas.SwapEffect=D3DSWAPEFFECT_COPY; + if (d3ddevice->Reset(&d3dparas)!=D3D_OK){ + return; + } + screen->create(video->getScreenWidth(), video->getScreenHeight()); + screen->display(); + InitVertexBuffer(); + //Redraw Views, Chris could you add a member function to viewman, so that + // I can cause it to completely redraw the Views? + // Otherwise the OSD would be distorted after Device Lost + SetEvent(event); + +} +LPDIRECT3DDEVICE9 OsdWin::getD3dDev() { + WaitForSingleObject(event,INFINITE);//We will only return if we are initted + return d3ddevice; +} + +void OsdWin::BeginPainting() {//We synchronize calls to d3d between different threads + WaitForSingleObject(d3dmutex,INFINITE); +} + +void OsdWin::EndPainting() { + ReleaseMutex(d3dmutex); +} diff --git a/osdwin.h b/osdwin.h index 0a084be..a22f356 100644 --- a/osdwin.h +++ b/osdwin.h @@ -26,6 +26,18 @@ #include "osd.h" #include "defines.h" #include "log.h" +#include +#include + +struct OSDVERTEX +{ + FLOAT x,y,z,rhw; + DWORD c; + FLOAT u,v; +}; + +#define D3DFVF_OSDVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE| D3DFVF_TEX1) + class OsdWin : public Osd { @@ -33,14 +45,30 @@ class OsdWin : public Osd OsdWin(); ~OsdWin(); - int init(char* device); + int init(void* device); int shutdown(); int getFD(); void screenShot(char* fileName); - private: + LPDIRECT3DDEVICE9 getD3dDev() ; + // This function is called from the WinMain function in order to get Screen updates + void Render(); + void BeginPainting(); + void EndPainting(); +private: + LPDIRECT3D9 d3d; + LPDIRECT3DDEVICE9 d3ddevice; + LPDIRECT3DVERTEXBUFFER9 d3dvb; + // This indicates, that currently a video is played, thus the osd updates are driven by the Directshow Filtersystem + bool external_driving; + HANDLE d3dmutex; + void InternalRendering(); + void DoLost(); + int InitVertexBuffer(); + OSDVERTEX osdvertices[4]; + HANDLE event; }; #endif diff --git a/player.cc b/player.cc index 3dc1876..e17d736 100644 --- a/player.cc +++ b/player.cc @@ -35,6 +35,7 @@ Player::Player(MessageQueue* messageQueue, UCHAR tIsRecording, UCHAR isRadio) streamLength = 0; feedPosition = 0; feedMode = MODE_NORMAL; + videoStartup = false; isRecording = tIsRecording; lastRescan = 0; startTS = 0; @@ -46,11 +47,13 @@ Player::Player(MessageQueue* messageQueue, UCHAR tIsRecording, UCHAR isRadio) { blockSize = 20000; startupBlockSize = 60000; + video->turnVideoOff(); } else { blockSize = 100000; startupBlockSize = 250000; + video->turnVideoOn(); } } @@ -69,9 +72,13 @@ int Player::init() shutdown(); return 0; } - +#ifndef NEW_DEMUXER vfeed.init(video->getFD()); afeed.init(audio->getFD()); +#else + vfeed.init(video); + afeed.init(audio); +#endif video->stop(); video->blank(); @@ -166,29 +173,17 @@ int Player::play() demuxer.reset(); // ------------------------ This one works, but doesn't allow any pre-buffering. + videoStartup = true; threadStart(); - vfeed.start(); afeed.start(); - audio->play(); - video->play(); video->sync(); audio->sync(); + audio->play(); + video->pause(); + - resyncVideo(); // ------------------------ This one doesn't work, but it should, and would allow for prebuffering. -/* - threadStart(); -// MILLISLEEP(1000); - - vfeed.start(); - afeed.start(); - video->play(); - audio->play(); - audio->sync(); - video->sync(); - resyncVideo(); -*/ // ------------------------------------------------------------------------------------------------ @@ -263,13 +258,12 @@ void Player::setLength(ULLONG length) logger->log("Player", Log::DEBUG, "Player has received length of %llu", streamLength); } -void Player::skipForward(int seconds) +void Player::restartAt(ULLONG timecode) { - logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds); - if (paused) togglePause(); + if (ffwd) toggleFastForward(); - ULONG wantedFrameNumber = video->timecodeToFrameNumber(getPositionTS() + (seconds * 90000)); + ULONG wantedFrameNumber = video->timecodeToFrameNumber(timecode); ULLONG newPosition = VDR::getInstance()->positionFromFrameNumber(wantedFrameNumber); if (!VDR::getInstance()->isConnected()) { doConnectionLost(); return; } logger->log("Player", Log::DEBUG, "wantedframe %i feedpos %llu goto %llu", wantedFrameNumber, feedPosition, newPosition); @@ -280,66 +274,38 @@ void Player::skipForward(int seconds) video->stop(); video->reset(); audio->reset(); - audio->doMuting(); // ??? demuxer.flush(); feedPosition = newPosition; - vfeed.start(); + videoStartup = true; afeed.start(); threadStart(); audio->play(); - video->play(); video->sync(); audio->sync(); audio->systemMuteOff(); audio->doMuting(); - ffwd = false; fbwd = false; - paused = false; +} - resyncVideo(); +void Player::skipForward(int seconds) +{ + logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds); + restartAt(getPositionTS() + (seconds * 90000)); } void Player::skipBackward(int seconds) { logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds); - - if (paused) togglePause(); - - ULLONG newPosition = 0; - long long newTimeCode = getPositionTS() - (seconds * 90000); - if (newTimeCode > 0) - { - ULONG wantedFrameNumber = video->timecodeToFrameNumber((ULLONG)newTimeCode); - newPosition = VDR::getInstance()->positionFromFrameNumber(wantedFrameNumber); - if (!VDR::getInstance()->isConnected()) { doConnectionLost(); return; } - logger->log("Player", Log::DEBUG, "wantedframe %i feedpos %llu goto %llu", wantedFrameNumber, feedPosition, newPosition); - } - - vfeed.stop(); - afeed.stop(); - threadStop(); - video->stop(); - audio->stop(); - video->reset(); - audio->reset(); - audio->doMuting(); // ??? - demuxer.flush(); - feedPosition = newPosition; - vfeed.start(); - afeed.start(); - threadStart(); - audio->play(); - video->play(); - video->sync(); - audio->sync(); - audio->systemMuteOff(); - audio->doMuting(); - ffwd = false; - fbwd = false; - paused = false; + if (newTimeCode < 0) newTimeCode = 0; + restartAt(newTimeCode); +} - resyncVideo(); +void Player::jumpToPercent(int percent) +{ + logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent); + ULLONG newTimeCode = (ULLONG)(getEndTS() * ((float)percent / 100)); + restartAt(newTimeCode); } void Player::toggleFastForward() @@ -353,41 +319,25 @@ void Player::toggleFastForward() if (ffwd) { ffwd = false; -// video->unFastForward(); - - + threadStop(); vfeed.stop(); afeed.stop(); - threadStop(); video->stop(); audio->stop(); video->reset(); audio->reset(); demuxer.flush(); -// demuxer.seek(); - vfeed.start(); + + videoStartup = true; afeed.enable(); afeed.start(); threadStart(); - video->play(); - audio->play(); - video->sync(); - audio->sync(); - - audio->systemMuteOff(); - - resyncVideo(); -/* - demuxer.flushAudio(); - audio->reset(); - afeed.enable(); - //video->reset(); audio->play(); - video->play(); video->sync(); audio->sync(); audio->systemMuteOff(); -*/ + audio->doMuting(); + fbwd = false; } else { @@ -431,32 +381,6 @@ void Player::toggleFastBackward() } } -void Player::jumpToPercent(int percent) -{ - if (paused) togglePause(); - if (ffwd) toggleFastForward(); - - vfeed.stop(); - afeed.stop(); - threadStop(); - video->stop(); - audio->stop(); - video->reset(); - audio->reset(); - demuxer.flush(); - demuxer.seek(); - feedPosition = streamLength * percent / 100; - vfeed.start(); - afeed.start(); - threadStart(); - audio->play(); - video->play(); - video->sync(); - audio->sync(); - - resyncVideo(); -} - ULLONG Player::getPositionTS() { if (startup) return 0ULL; @@ -503,10 +427,21 @@ void Player::call(void* caller) } else { + if (videoStartup) + { + videoStartup = false; + logger->log("Player", Log::DEBUG, "Starting VFeed"); + MILLISLEEP(500); + logger->log("Player", Log::DEBUG, "Starting VFeed2"); + video->reset(); + video->play(); + video->sync(); + vfeed.start(); + } + threadSignalNoLock(); } } - void Player::doConnectionLost() { Message* m = new Message(); @@ -698,10 +633,12 @@ void Player::setEndTS() void Player::test1() { logger->log("Player", Log::DEBUG, "PLAYER TEST 1"); + video->setAspectRatio(Video::ASPECT4X3); } void Player::test2() { logger->log("Player", Log::DEBUG, "PLAYER TEST 2"); + video->setAspectRatio(Video::ASPECT16X9); } #endif diff --git a/player.h b/player.h index d7a5ec7..0fef7a1 100644 --- a/player.h +++ b/player.h @@ -81,6 +81,7 @@ class Player : public Thread_TYPE, public Callback void setStartTS(UINT dataInBuffer); void setEndTS(); void doConnectionLost(); + void restartAt(ULLONG timeCode); int initted; MessageQueue* commandMessageQueue; @@ -91,6 +92,7 @@ class Player : public Thread_TYPE, public Callback int startup; VFeed vfeed; AFeed afeed; + bool videoStartup; ULLONG startTS; ULLONG endTS; diff --git a/remotewin.cc b/remotewin.cc index 04e5475..37e1fac 100644 --- a/remotewin.cc +++ b/remotewin.cc @@ -20,10 +20,12 @@ #include "remotewin.h" + RemoteWin::RemoteWin() { - if (instance) return; initted = 0; + curevent=NA_NONE; + signal=false; } RemoteWin::~RemoteWin() @@ -34,6 +36,8 @@ int RemoteWin::init(char* devName) { if (initted) return 0; initted = 1; + event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL); + return 1; } @@ -41,6 +45,7 @@ int RemoteWin::init(char* devName) int RemoteWin::shutdown() { if (!initted) return 0; + CloseHandle(event); initted = 0; return 1; } @@ -52,11 +57,155 @@ UCHAR RemoteWin::getButtonPress(int waitType) how = 2 - continue wait how = 3 - no wait */ + DWORD wait; + if (curevent!=NA_NONE) { + UCHAR temp=curevent; + curevent=NA_NONE; + return temp; + } + if (waitType==3) { + return NA_NONE; + } + if (waitType==0) { + wait=INFINITE; + } else { //We do not distingish between 2 and 3 + wait=1000; + + } + WaitForSingleObject(event,wait); + ResetEvent(event); + if (curevent==NA_NONE) { + if (signal) { + signal=false; + return NA_SIGNAL; //Since we have no signals on windows, we simulate this + } else { + return NA_NONE; + } + } + UCHAR temp2=curevent; + curevent=NA_NONE; + return temp2; - return NA_UNKNOWN; } void RemoteWin::clearBuffer() { } + +int RemoteWin::ReceiveButtonVK(UINT button) { + UCHAR pb=NA_NONE; + //should we use a translation table ? No APPCOMMAND iS DWORD! + switch (button) { //Processing VK_Messages + case VK_DOWN: + pb=DOWN; break; + case VK_RETURN: + case VK_SPACE: + pb=OK;break; + case VK_LEFT: + pb=LEFT;break; + case '9': + case VK_NUMPAD9: + pb=NINE;break; + case '8': + case VK_NUMPAD8: + pb=EIGHT;break; + case '7': + case VK_NUMPAD7: + pb=SEVEN;break; + case '6': + case VK_NUMPAD6: + pb=SIX;break; + case '5': + case VK_NUMPAD5: + pb=FIVE;break; + case '4': + case VK_NUMPAD4: + pb=FOUR;break; + case '3': + case VK_NUMPAD3: + pb=THREE;break; + case '2': + case VK_NUMPAD2: + pb=TWO;break; + case '1': + case VK_NUMPAD1: + pb=ONE;break; + case '0': + case VK_NUMPAD0: + pb=ZERO;break; + case VK_RIGHT: + pb=RIGHT;break; + case VK_UP: + pb=UP;break; + case VK_MULTIPLY: + pb=STAR;break; + case 'J'://j for JUMP TO instead of go to + pb=GO;break; + case VK_ESCAPE: + pb=POWER;break; + case VK_BACK: + pb=BACK;break; + case 'M': + pb=MENU;break; + case 'R': + pb=RED;break; + case 'G': + pb=GREEN;break; + case 'Y': + pb=YELLOW;break; + case 'B': + pb=BLUE; break; + + + }; //All other commands are process via APPCOMMAND_MESSAGES + if (pb==NA_NONE) return 0; + curevent=pb; + //PulseEvent(event); + SetEvent(event); + return 1; +} + +int RemoteWin::ReceiveButtonAP(UINT button) { + UCHAR pb=NA_NONE; + //should we use a translation table ? No APPCOMMAND iS DWORD! + switch (button) { //Processing VK_Messages + case APPCOMMAND_MEDIA_CHANNEL_DOWN: + pb=CHANNELDOWN;break; + case APPCOMMAND_MEDIA_CHANNEL_UP: + pb=CHANNELUP;break; + case APPCOMMAND_MEDIA_FAST_FORWARD: + pb=FORWARD;break; + case APPCOMMAND_VOLUME_MUTE: + pb=MUTE;break; + case APPCOMMAND_MEDIA_PAUSE: + pb=PAUSE;break; + case APPCOMMAND_MEDIA_PLAY: + pb=PLAY;break; + case APPCOMMAND_MEDIA_RECORD: + pb=RECORD;break; + case APPCOMMAND_MEDIA_PREVIOUSTRACK: + pb=SKIPBACK;break; + case APPCOMMAND_MEDIA_REWIND: + pb=REVERSE;break; + case APPCOMMAND_MEDIA_NEXTTRACK: + pb=SKIPFORWARD;break; + case APPCOMMAND_MEDIA_STOP: + pb=STOP;break; + case APPCOMMAND_VOLUME_DOWN: + pb=VOLUMEDOWN;break; + case APPCOMMAND_VOLUME_UP: + pb=VOLUMEUP;break; + }; + if (pb==NA_NONE) return 0; + curevent=pb; + //PulseEvent(event); + SetEvent(event); + return 1; +} + +void RemoteWin::Signal() { + signal=true; + //PulseEvent(event); + SetEvent(event); +} diff --git a/remotewin.h b/remotewin.h index 1ec0047..4d12235 100644 --- a/remotewin.h +++ b/remotewin.h @@ -27,6 +27,12 @@ #include "log.h" #include "remote.h" +#define _WIN32_WINNT 0x501 +#include +#include + + + class RemoteWin : public Remote { public: @@ -38,9 +44,15 @@ class RemoteWin : public Remote int getDevice(); UCHAR getButtonPress(int how); void clearBuffer(); + void Signal(); + int ReceiveButtonVK(UINT button);//Windows Message from WND_PROC + int ReceiveButtonAP(UINT button); private: int initted; + bool signal; + UCHAR curevent; + HANDLE event; }; #endif diff --git a/stream.cc b/stream.cc index a04088b..a5ba6a4 100644 --- a/stream.cc +++ b/stream.cc @@ -23,6 +23,10 @@ Stream::Stream() { initted = 0; +#ifdef NEW_DEMUXER + cur_packet_pos=0; + draintarget=NULL; +#endif } Stream::~Stream() @@ -32,9 +36,7 @@ Stream::~Stream() void Stream::shutdown() { - if (initted) { - free(outbuf); - } + if (initted) free(outbuf); initted = 0; } @@ -52,11 +54,15 @@ int Stream::init(int bufsize) void Stream::flush() { +#ifdef NEW_DEMUXER + mediapackets.clear(); +#endif bufferHead = 0; bufferTail = 0; bufferMark = -1; } +#ifndef NEW_DEMUXER int Stream::put(UCHAR* inbuf, int len) { int ret = 0; @@ -93,7 +99,77 @@ int Stream::put(UCHAR* inbuf, int len) } return ret; } - +#else +int Stream::put(UCHAR* inbuf, int len) +{ + int ret = 0; + int tail = bufferTail; + int head = bufferHead; + if (tail == 0) tail = bufferSize; + + if (!draintarget) return 0; + MediaPacket newPacket; + newPacket.length=len; + newPacket.pos_buffer=0; + newPacket.recording_byte_pos=0; + newPacket.synched=false; + newPacket.disconti=false; + newPacket.pts=0; + newPacket.presentation_time=0; + //Extract the pts... + if ((inbuf[7] & 0x80) && len>14 ) { + newPacket.synched=true; + newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) | + ( (ULLONG)(inbuf[10]) << 22 ) | + ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) | + ( (ULLONG)(inbuf[12]) << 7 ) | + ( (ULLONG)(inbuf[13] & 0xFE) >> 1 ); + //ok we have the pts now convert it to a continously time code in 100ns units + newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL); + newPacket.presentation_time-=draintarget->SetStartOffset(newPacket.presentation_time,&newPacket.disconti); + } + + if (head < tail) + { + // The free space is in one continuous chunk. + if (len < tail - head) + { + memcpy(outbuf + head, inbuf, len); + bufferHead += len; + ret = len; + newPacket.pos_buffer=head; + mediapackets.push_front(newPacket); + } + } + else if (len <= bufferSize - head) + { + // There is enough space above the Head. + memcpy(outbuf + head, inbuf, len); + if (head + len == bufferSize) + bufferHead = 0; + else + bufferHead += len; + + newPacket.pos_buffer=head; + mediapackets.push_front(newPacket); + + ret = len; + } + else if (len < tail) + { + bufferMark = head; + memcpy(outbuf, inbuf, len); + bufferHead = len; + ret = len; + newPacket.pos_buffer=0; + mediapackets.push_front(newPacket); + } + return ret; +} +#endif + +#ifndef NEW_DEMUXER + int Stream::drain(int fd) { int ret = 0; @@ -101,13 +177,18 @@ int Stream::drain(int fd) int tail = bufferTail; int mark = bufferMark; int written; -#ifndef WIN32 + if (mark == -1 && tail > head) mark = bufferSize; if (mark >= 0) { // Drain up to the marker. +#ifndef WIN32 written = write(fd, outbuf + tail, (mark - tail)); +#else + written=mark-tail; + MILLISLEEP(1); +#endif if (written < 0) return ret; ret += written; if (written == (mark - tail)) @@ -123,14 +204,55 @@ int Stream::drain(int fd) } if (tail == head) return ret; // Empty - +#ifndef WIN32 written = write(fd, outbuf + tail, (head - tail)); +#else + written=(head - tail); + MILLISLEEP(1); +#endif if (written < 0) return ret; ret += written; bufferTail = tail + written; return ret; - #else - return 0; //to do! - #endif //Again this have to betransformed into abstract base class and derived class +} +#else +int Stream::drain(DrainTarget* dt) +{ + int ret = 0; + int written=1; + draintarget=dt; + + + if (mediapackets.empty()) { + return 0; + } + // using mediapackets, may be this is slower but it is more flexible + // while (!mediapackets.empty() && written) { + + int head = bufferHead; + int tail = bufferTail; + int mark = bufferMark; + if (mark == -1 && tail > head) mark = bufferSize; + MediaPacket cur_mp=mediapackets.back(); + written=0; + written=dt->DeliverMediaSample(cur_mp,outbuf,&cur_packet_pos); + + ret+=written; + + if (cur_packet_pos==cur_mp.length) { + cur_packet_pos=0; + mediapackets.pop_back(); + if ((int)(tail+cur_mp.length) < mark) { + bufferTail=tail+cur_mp.length; + } else { + bufferTail=0; + bufferMark=-1; + } + + } + + return ret; } + +#endif diff --git a/stream.h b/stream.h index d7d02ea..0b48840 100644 --- a/stream.h +++ b/stream.h @@ -27,6 +27,9 @@ #endif #include #include "defines.h" +#include "draintarget.h" + + class Stream { @@ -37,9 +40,19 @@ class Stream void shutdown(); void flush(); int put(UCHAR* inbuf, int len); +#ifndef NEW_DEMUXER int drain(int fd); +#else + int drain(DrainTarget* fd); + void setDrainTarget(DrainTarget *dt) {draintarget=dt;}; +#endif private: +#ifdef NEW_DEMUXER + MediaPacketList mediapackets; + UINT cur_packet_pos; + DrainTarget* draintarget; +#endif int initted; UCHAR* outbuf; diff --git a/surfacewin.cc b/surfacewin.cc index 34034d5..d17195c 100644 --- a/surfacewin.cc +++ b/surfacewin.cc @@ -20,20 +20,60 @@ */ #include "surfacewin.h" -#include "osd.h" +#include "osdwin.h" +#include SurfaceWin::SurfaceWin(int id) : Surface(id) { + d3dtexture=NULL; + d3dsurface=NULL; + sheight=swidth=0; + event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL); } SurfaceWin::~SurfaceWin() { + if (d3dsurface) d3dsurface->Release(); + if (d3dtexture) d3dtexture->Release(); + CloseHandle(event); } int SurfaceWin::create(UINT width, UINT height) { - return 0; + LPDIRECT3DDEVICE9 d3ddev=((OsdWin*)(Osd::getInstance()))->getD3dDev(); + while (true) { + if (screen==this) { + if (d3ddev->CreateTexture(1024,1024,0,0,D3DFMT_A8R8G8B8, + // Does every adapter with alpha blending support this? + D3DPOOL_DEFAULT,&d3dtexture ,NULL)!=D3D_OK) { + MILLISLEEP(50);//wait maybe next time it will work + continue; + } + if (d3dtexture->GetSurfaceLevel(0,&d3dsurface)!=D3D_OK) { + d3dtexture->Release(); + d3dtexture=NULL; + MILLISLEEP(50); + continue; + } + } else { + HRESULT hres; + if (hres=d3ddev->CreateOffscreenPlainSurface(width,height,D3DFMT_A8R8G8B8, + D3DPOOL_SYSTEMMEM,&d3dsurface,NULL)!=D3D_OK) { + MILLISLEEP(50);//wait maybe next time it will work + continue; + } + + } + sheight=height; + swidth=width; + /* If someone does high performance Animations on the OSD, we have to change the types + of surface in order to address these performance issues, if we have only very few updates + per second this would be fast enough !*/ + break; + } + SetEvent(event); + return 1; } void SurfaceWin::display() @@ -42,35 +82,174 @@ void SurfaceWin::display() int SurfaceWin::fillblt(int x, int y, int width, int height, unsigned int c) { + WaitForSingleObject(event,INFINITE); //since this might be called before surface + //allocation we will wait in this case, hopefully without deadlocks + OsdWin* osd=((OsdWin*)(Osd::getInstance())); + + if (!d3dsurface) { + return 0; //why does this happen + } + + LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev(); + + if (screen==this) { + //This should not happen! + return 0; + + } else { + osd->BeginPainting(); + D3DLOCKED_RECT lockrect; + int cx,cy,cwidth,cheight; + cx=min(max(x,0),swidth); + cy=min(max(y,0),sheight); + cwidth=min(width,swidth-x); + cheight=min(height,sheight-y); + RECT rect={cx,cy,cwidth,cheight}; + + if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) { + return 0; + } + unsigned int line; + unsigned int column; + for (line=0;lineUnlockRect()!=D3D_OK) { + osd->EndPainting(); + return 0; + } + osd->EndPainting(); + } + return 0; } void SurfaceWin::drawPixel(int x, int y, unsigned int c) { + //FixMe: locking for every single Pixel will be painfully slow + WaitForSingleObject(event,INFINITE); //since this might be called before surface + //allocation we will wait in this case, hopefully without deadlocks + if (!d3dsurface) { + return; //why does this happen + } + OsdWin* osd=((OsdWin*)(Osd::getInstance())); + LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev(); + if (x>swidth || y>sheight) return; //do not draw outside the surface + if (screen==this) { + //This should not happen! + return ; + + } else { + osd->BeginPainting(); + D3DLOCKED_RECT lockrect; + RECT rect={x,y,x+1,y+1}; + if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) { + osd->EndPainting(); + return ; + } + unsigned int*row=(unsigned int*)(((char*)lockrect.pBits)); + row[0]=c; + if (d3dsurface->UnlockRect()!=D3D_OK) { + osd->EndPainting(); + return ; + } + osd->EndPainting(); + } + } void SurfaceWin::drawHorzLine(int x1, int x2, int y, unsigned int c) { + fillblt(x1, y, x2-x1, 1, c); } void SurfaceWin::drawVertLine(int x, int y1, int y2, unsigned int c) { + fillblt(x, y1, 1, y2-y1, c); } int SurfaceWin::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME { + WaitForSingleObject(event,INFINITE); //since this might be called before surface + //allocation we will wait in this case, hopefully without deadlocks + if (!d3dsurface) { + return 0; //why does this happen + } + OsdWin* osd=((OsdWin*)(Osd::getInstance())); + LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev(); + LPDIRECT3DSURFACE9 screensurface=((SurfaceWin*)screen)->getD3dsurface(); + if (!screensurface) return 0; + RECT sourcerect={sx,sy,sx+w,sy+h}; + POINT destpoint={dx,dy}; + osd->BeginPainting(); + if (d3ddev->UpdateSurface(d3dsurface,&sourcerect,screensurface,&destpoint)!=D3D_OK) { + Log::getInstance()->log("Surface", Log::DEBUG, "Could not update to Screen!"); + osd->EndPainting(); + return 0; + } + osd->EndPainting(); return 0; } int SurfaceWin::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy) { + //I don't see code using this function, so I skip it, since it is a MVP specific interface return 0; } void SurfaceWin::screenShot(char* fileName) { + //Isn't this for debugging only, so I won't implement it yet } void SurfaceWin::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b) { + //Isn't this for debugging only, so I won't implement it yet +} +void SurfaceWin::ReleaseSurface() +{ + ResetEvent(event); + LPDIRECT3DSURFACE9 temp_surf=d3dsurface; + LPDIRECT3DTEXTURE9 temp_text=d3dtexture; + d3dsurface=NULL; + d3dtexture=NULL; + sheight=swidth=0; + if (temp_surf) temp_surf->Release(); + if (temp_text) temp_text->Release(); +} + +void SurfaceWin::drawJpeg(char *fileName,DWORD x, DWORD y,DWORD *width, DWORD *height){ + WaitForSingleObject(event,INFINITE); //since this might be called before surface + //allocation we will wait in this case, hopefully without deadlocks + if (!d3dsurface) { + return ; //why does this happen + } + OsdWin* osd=((OsdWin*)(Osd::getInstance())); + + + D3DXIMAGE_INFO image_inf; + osd->BeginPainting(); + D3DXGetImageInfoFromFile(fileName,&image_inf); + RECT dest_rec={x,y,x+image_inf.Width, + y+image_inf.Height}; + if (D3DXLoadSurfaceFromFile( + d3dsurface, + NULL, + &dest_rec, + fileName, + NULL, + D3DX_FILTER_NONE, + 0, + &image_inf)!=D3D_OK) { + Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!"); + + } + osd->EndPainting(); + *width=image_inf.Width; + *height=image_inf.Height; + } diff --git a/surfacewin.h b/surfacewin.h index 6b7eb70..104aec6 100644 --- a/surfacewin.h +++ b/surfacewin.h @@ -25,6 +25,8 @@ #include "defines.h" #include "log.h" #include "surface.h" +#include +#include class SurfaceWin : public Surface { @@ -42,10 +44,17 @@ class SurfaceWin : public Surface int updateToScreen(int sx, int sy, int w, int h, int dx, int dy); void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b); void screenShot(char* fileName); - + void ReleaseSurface(); int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy); - + void drawJpeg(char *fileName,DWORD x, DWORD y,DWORD *width, DWORD *height); + LPDIRECT3DSURFACE9 getD3dsurface() {WaitForSingleObject(event,INFINITE); + return d3dsurface;}; + LPDIRECT3DTEXTURE9 getD3dtexture() {return d3dtexture;}; private: + LPDIRECT3DSURFACE9 d3dsurface; + LPDIRECT3DTEXTURE9 d3dtexture; + UINT sheight,swidth; + HANDLE event; }; #endif diff --git a/tcp.cc b/tcp.cc index 6c56e38..2600635 100644 --- a/tcp.cc +++ b/tcp.cc @@ -20,6 +20,9 @@ */ #include "tcp.h" +#ifdef WIN32 +#include +#endif TCP::TCP() { @@ -51,7 +54,36 @@ void TCP::getMAC(char* dest) memcpy(dest, ifr.ifr_hwaddr.sa_data, 6); #else //TODO: Get MAC Address for windows - memcpy(dest, "ABCDEF", 6); + PIP_ADAPTER_INFO daptinfo=NULL; + DWORD size=0; + GetAdaptersInfo(daptinfo,&size); + daptinfo=(PIP_ADAPTER_INFO)new char[size+1]; + memcpy(dest,"ABCDEF", 6);//Dummy Address + sockaddr_in sock_address; + int sockname_len=sizeof(sock_address); + getsockname(sock,(sockaddr*)&sock_address,&sockname_len); + ULONG sockip=sock_address.sin_addr.s_addr; + if (GetAdaptersInfo(daptinfo,&size)==ERROR_SUCCESS) + { + PIP_ADAPTER_INFO daptinfo_it=daptinfo; + while (daptinfo_it!=NULL) + { + ULONG ipaddress=inet_addr(daptinfo_it->IpAddressList.IpAddress.String); + if (ipaddress==sockip) + { //Is it our MAC? + memcpy(dest,daptinfo_it->Address, 6); + break; + } + daptinfo_it=daptinfo_it->Next; + if (daptinfo_it==daptinfo) break; + } + } + else + { + // Marten? + } + + delete [] daptinfo; #endif } diff --git a/threadwin.cc b/threadwin.cc index cc9645b..2d445bd 100644 --- a/threadwin.cc +++ b/threadwin.cc @@ -30,7 +30,7 @@ DWORD WINAPI threadInternalStart(void *arg) int ThreadWin::threadStart() { - threadCond = CreateEvent(NULL,FALSE,FALSE,NULL); + threadCond = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL); if (threadCond == NULL) return 0; threadCondMutex = CreateMutex(NULL,FALSE,NULL); if (threadCondMutex == NULL) @@ -63,7 +63,8 @@ void ThreadWin::threadStop() void ThreadWin::threadCancel() { threadActive = 0; - TerminateThread(pthread, 0); + //TerminateThread(pthread, 0); + threadSignalNoLock(); WaitForSingleObject(pthread, INFINITE); this->threadPostStopCleanup(); } @@ -86,30 +87,37 @@ void ThreadWin::threadUnlock() void ThreadWin::threadSignal() { WaitForSingleObject(threadCondMutex, INFINITE); - PulseEvent(threadCond); + // PulseEvent(threadCond); + SetEvent(threadCond); ReleaseMutex(threadCondMutex); } void ThreadWin::threadSignalNoLock() { - PulseEvent(threadCond); +// PulseEvent(threadCond); + SetEvent(threadCond); } void ThreadWin::threadWaitForSignal() { + threadUnlock(); WaitForSingleObject(threadCond,INFINITE); + ResetEvent(threadCond); + threadLock(); } void ThreadWin::threadWaitForSignalTimed(struct timespec* ts) { + threadUnlock(); HANDLE handles[2] ={threadCond, NULL}; LARGE_INTEGER duration; - duration.QuadPart=ts->tv_sec*1000*1000*10+ts->tv_nsec/100; - + duration.QuadPart=(ts->tv_sec*1000*1000*10+ts->tv_nsec/100)+WINDOWS_TIME_BASE_OFFSET; handles[1]=CreateWaitableTimer(NULL,TRUE,NULL); SetWaitableTimer(handles[1], &duration, 0, NULL, NULL, 0); WaitForMultipleObjects(2,handles,FALSE,INFINITE); + ResetEvent(threadCond); CloseHandle(handles[1]); + threadLock(); } void ThreadWin::threadSetKillable() diff --git a/threadwin.h b/threadwin.h index 1e55507..bc363dc 100644 --- a/threadwin.h +++ b/threadwin.h @@ -21,7 +21,8 @@ #ifndef THREADWIN_H #define THREADWIN_H -#define _WIN32_WINNT 0x400 + +#define _WIN32_WINNT 0x501 #include #include typedef struct timespec @@ -29,6 +30,7 @@ typedef struct timespec long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ } timespec; +#define WINDOWS_TIME_BASE_OFFSET 116444736000000000 #include "thread.h" diff --git a/timers.cc b/timers.cc index c94ee58..11fb3af 100755 --- a/timers.cc +++ b/timers.cc @@ -139,8 +139,9 @@ int Timers::setTimerD(TimerReceiver* client, int clientReference, long int reque __int64 test; GetSystemTime(&systime); SystemTimeToFileTime(&systime,(FILETIME*)&filetime); - currentTime.tv_sec=filetime/(10*1000*1000); - currentTime.tv_nsec=(filetime%(10*1000*1000))*100; + currentTime.tv_sec=(filetime-WINDOWS_TIME_BASE_OFFSET)/(10*1000*1000); + //#error "Hier gibt was zu tun!" + currentTime.tv_nsec=((filetime-WINDOWS_TIME_BASE_OFFSET)%(10*1000*1000))*100; #endif long int requestedTime; @@ -278,7 +279,7 @@ void Timers::threadMethod() // Check for reset.. // This can be caused by an addition or deletion to the list - if (resetThreadFlag) continue; + if (resetThreadFlag || (nextTimer == NULL)) continue; // timer ran out diff --git a/vepg.cc b/vepg.cc index ae4def1..afeb6d3 100644 --- a/vepg.cc +++ b/vepg.cc @@ -171,11 +171,19 @@ void VEpg::setInfo(Event* event) int length = strlen(event->title); // calculate length of programme title string char* title = new char[length + 15]; // create string to hold start time, end time and programme title btime = localtime((time_t*)&event->time); //get programme start time - strftime(timeString, 9, "%0H:%0M - ", btime); // and format it as hh:mm - +#ifndef _MSC_VER + strftime(timeString, 9, "%0H:%0M - ", btime); // and format it as hh:mm - +#else + strftime(timeString, 9, "%H:%M - ", btime); // and format it as hh:mm - +#endif strcpy(title, timeString); // put it in our buffer t = event->time + event->duration; //get programme end time btime = localtime(&t); - strftime(timeString, 7, "%0H:%0M ", btime); // and format it as hh:mm - +#ifndef _MSC_VER + strftime(timeString, 7, "%0H:%0M ", btime); // and format it as hh:mm - +#else + strftime(timeString, 7, "%H:%M ", btime); // and format it as hh:mm - +#endif strcat(title, timeString); // put it in our buffer strcat(title, event->title); // then add the programme title progTitle.setText(title); // sput this sring in our text box diff --git a/vepgsettimer.cc b/vepgsettimer.cc index a997fb9..b406fed 100644 --- a/vepgsettimer.cc +++ b/vepgsettimer.cc @@ -170,11 +170,20 @@ void VEpgSetTimer::draw() struct tm* btime; char timeString[10]; btime = localtime((time_t*)&event->time); +#ifndef _MSC_VER strftime(timeString, 9, "%0H:%0M - ", btime); // and format it as hh:mm - +#else + strftime(timeString, 9, "%H:%M - ", btime); // and format it as hh:mm - +#endif strcpy(fullString, timeString); // put it in our buffer t = event->time + event->duration; //get programme end time btime = localtime(&t); +#ifndef _MSC_VER strftime(timeString, 9, "%0H:%0M", btime); // and format it as hh:mm - +#else + strftime(timeString, 9, "%H:%M", btime); // and format it as hh:mm - +#endif + strcat(fullString, timeString); // put it in our buffer drawText(fullString, 10, 40 + (3 * surface->getFontHeight()), Colour::LIGHTTEXT); diff --git a/vfeed.cc b/vfeed.cc index aaf7285..7890abd 100644 --- a/vfeed.cc +++ b/vfeed.cc @@ -25,11 +25,19 @@ VFeed::VFeed(Callback* tcb) { } +#ifndef NEW_DEMUXER int VFeed::init(int tfd) { fd = tfd; return 1; } +#else +int VFeed::init(DrainTarget* tdt) +{ + dt = tdt; + return 1; +} +#endif int VFeed::shutdown() { @@ -55,7 +63,12 @@ void VFeed::threadMethod() while(1) { +#ifndef NEW_DEMUXER vlen = Demuxer::getInstance()->writeVideo(fd); // FIXME +#else + threadCheckExit(); + vlen = Demuxer::getInstance()->writeVideo(dt); // FIXME +#endif if (vlen) { // Log::getInstance()->log("VFeed", Log::DEBUG, "Written %i", vlen); diff --git a/vfeed.h b/vfeed.h index c8e6b0c..1525b41 100644 --- a/vfeed.h +++ b/vfeed.h @@ -27,6 +27,7 @@ #include "log.h" #include "demuxer.h" #include "callback.h" +#include "draintarget.h" #ifdef WIN32 #include "threadwin.h" @@ -38,8 +39,12 @@ class VFeed : public Thread_TYPE { public: VFeed(Callback* tcb); - +#ifndef NEW_DEMUXER int init(int fd); +#else + int init(DrainTarget *tdt); +#endif + int shutdown(); int start(); @@ -48,7 +53,12 @@ class VFeed : public Thread_TYPE private: void threadMethod(); void threadPostStopCleanup() {}; +#ifndef NEW_DEMUXER int fd; +#else + DrainTarget *dt; +#endif + Callback& cb; }; diff --git a/video.h b/video.h index 21b00d7..91d0459 100644 --- a/video.h +++ b/video.h @@ -23,8 +23,9 @@ #include #include "defines.h" +#include "draintarget.h" -class Video +class Video: public DrainTarget { public: Video(); @@ -56,6 +57,8 @@ class Video virtual ULONG timecodeToFrameNumber(ULLONG timecode)=0; virtual int getFD()=0; virtual ULLONG getCurrentTimestamp()=0; + virtual void turnVideoOn(){}; + virtual void turnVideoOff(){}; #ifdef DEV virtual int test() { return 0; } diff --git a/videomvp.cc b/videomvp.cc index f3e33cb..8869322 100644 --- a/videomvp.cc +++ b/videomvp.cc @@ -20,6 +20,9 @@ #include "videomvp.h" +// temp +#include "log.h" + VideoMVP::VideoMVP() { if (instance) return; @@ -151,6 +154,8 @@ int VideoMVP::setAspectRatio(UCHAR taspectRatio) 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; } @@ -367,3 +372,9 @@ int VideoMVP::test2() return 0; } #endif + +// unused +UINT VideoMVP::DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos) +{ + return 0; +} diff --git a/videomvp.h b/videomvp.h index be955ee..b984185 100644 --- a/videomvp.h +++ b/videomvp.h @@ -69,6 +69,10 @@ class VideoMVP : public Video int getFD(); ULLONG getCurrentTimestamp(); + //Writing Data to Videodevice + virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos); + virtual long long SetStartOffset(long long curreftime, bool *rsync) { return 0; }; + #ifdef DEV int test(); int test2(); diff --git a/videowin.cc b/videowin.cc index b993812..f7e7da6 100644 --- a/videowin.cc +++ b/videowin.cc @@ -19,21 +19,48 @@ */ #include "videowin.h" +#include "dssourcefilter.h" + + + + VideoWin::VideoWin() { - if (instance) return; + dsgraphbuilder=NULL; + dsmediacontrol=NULL; + sourcefilter=NULL; + filtermutex=CreateMutex(NULL,FALSE,NULL); + offsetnotset=true; + offsetvideonotset=true; + offsetaudionotset=true; + startoffset=0; + lastrefaudiotime=0; + lastrefvideotime=0; + firstsynched=false; + cur_audio_media_sample=NULL; + cur_video_media_sample=NULL; + videoon=true; + audioon=true; + + } VideoWin::~VideoWin() { + CleanupDS(); + CloseHandle(filtermutex); + + instance = NULL; } int VideoWin::init(UCHAR tformat) { if (initted) return 0; + initted = 1; + if (!setFormat(tformat)){ shutdown(); return 0; } return 1; } @@ -59,6 +86,16 @@ int VideoWin::setFormat(UCHAR tformat) if (!initted) return 0; if ((tformat != PAL) && (tformat != NTSC)) return 0; format = tformat; + if (format == NTSC) + { + screenWidth = 720; + screenHeight = 480; + } + if (format == PAL) + { + screenWidth = 720; + screenHeight = 576; + } return 1; } @@ -125,10 +162,62 @@ int VideoWin::sync() return 1; } +#ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions +#include "dshelper.h" +#endif + +#define DO_VIDEO + int VideoWin::play() { if (!initted) return 0; + //Build filter graph + HRESULT hres; + if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER, + IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) { + return 0; + } + #ifdef DS_DEBUG + AddToRot(dsgraphbuilder,&graphidentifier); + #endif + //This is just a try to see if building the graph works +// dsgraphbuilder->RenderFile(L"D:\\Projekte\\VTP Client\\test.mpa" ,NULL); + //So this is the real code, this prevents the feeder from calling noexisting objects! + WaitForSingleObject(filtermutex,INFINITE); + offsetnotset=true; + offsetvideonotset=true; + offsetaudionotset=true; + firstsynched=false; + sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data + // to DirectShow + if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) { + CleanupDS(); + ReleaseMutex(filtermutex); + return 0; + } + if (audioon) { + if (hres=dsgraphbuilder->Render(sourcefilter->GetPin(0)/*audio*/)!=S_OK) { + CleanupDS(); + ReleaseMutex(filtermutex); + return 0; + } + } +#ifdef DO_VIDEO + if (videoon) { + if (hres=dsgraphbuilder->Render(sourcefilter->GetPin(1)/*video*/)!=S_OK) { + CleanupDS(); + ReleaseMutex(filtermutex); + return 0; + } + } +#endif + + + + dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol); + dsmediacontrol->Run(); + ReleaseMutex(filtermutex); return 1; } @@ -136,6 +225,9 @@ int VideoWin::stop() { if (!initted) return 0; + CleanupDS(); + + return 1; } @@ -149,13 +241,14 @@ int VideoWin::reset() int VideoWin::pause() { if (!initted) return 0; - + if (dsmediacontrol) dsmediacontrol->Pause(); return 1; } int VideoWin::unPause() // FIXME get rid - same as play!! -{ +{//No on windows this is not the same, I don't get rid of! if (!initted) return 0; + if (dsmediacontrol) dsmediacontrol->Run(); return 1; } @@ -200,6 +293,256 @@ ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode) else return (ULONG)(((double)timecode / (double)90000) * (double)30); } +void VideoWin::CleanupDS() +{ + WaitForSingleObject(filtermutex,INFINITE); + if (cur_audio_media_sample) { + cur_audio_media_sample->Release(); + cur_audio_media_sample=NULL; + } + if (cur_video_media_sample) { + cur_video_media_sample->Release(); + cur_video_media_sample=NULL; + } + + if (dsmediacontrol) { + dsmediacontrol->Stop(); + dsmediacontrol->Release(); + dsmediacontrol=NULL; + } + if (dsgraphbuilder){ +#ifdef DS_DEBUG + RemoveFromRot(graphidentifier); +#endif + dsgraphbuilder->Release(); + dsgraphbuilder=NULL; + sourcefilter=NULL; //The Graph Builder destroys our SourceFilter + } + ReleaseMutex(filtermutex); + +} + + +UINT VideoWin::DeliverMediaSample(MediaPacket packet, + UCHAR* buffer, + UINT *samplepos) +{ + /*First Check, if we have an audio sample*/ +#ifdef DO_VIDEO + /*First Check, if we have an audio sample*/ + + IMediaSample* ms=NULL; + REFERENCE_TIME reftime1=0; + REFERENCE_TIME reftime2=0; + + UINT headerstrip=0; + if (packet.disconti) { + firstsynched=false; + DeliverVideoMediaSample(); + + } + + + /*Inspect PES-Header */ + + if (*samplepos==0) {//stripheader + headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/; + *samplepos+=headerstrip; + if ( packet.synched ) { + DeliverVideoMediaSample();//write out old data + if (packet.presentation_time<0) { //Preroll? + *samplepos=packet.length;//if we have not processed at least one + return packet.length;//synched packet ignore it! + } + + reftime1=packet.presentation_time; + reftime2=reftime1+1; + firstsynched=true; + } else { + if (!firstsynched) {// + *samplepos=packet.length;//if we have not processed at least one + return packet.length;//synched packet ignore it! + } + } + } + BYTE *ms_buf; + UINT ms_length; + UINT ms_pos; + UINT haveToCopy; + if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample + samplepos=0; + MILLISLEEP(10); + return 0; + } + ms_pos=ms->GetActualDataLength(); + ms_length=ms->GetSize(); + haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos); + if ((ms_length-ms_pos)<1) { + DeliverVideoMediaSample(); //we are full! + if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample + samplepos=0; + MILLISLEEP(10); + return 0; + } + ms_pos=ms->GetActualDataLength(); + ms_length=ms->GetSize(); + haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos); + } + ms->GetPointer(&ms_buf); + + + if (ms_pos==0) {//will only be changed on first packet + if (packet.disconti) { + ms->SetDiscontinuity(TRUE); + } else { + ms->SetDiscontinuity(FALSE); + } + if (packet.synched) { + ms->SetSyncPoint(TRUE); + ms->SetTime(&reftime1,&reftime2); + //ms->SetTime(NULL,NULL); + ms->SetMediaTime(NULL, NULL); + }else { + ms->SetSyncPoint(FALSE); + ms->SetTime(NULL,NULL); + ms->SetMediaTime(NULL, NULL); + ms->SetSyncPoint(TRUE); + } + } + + + memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy); + ms->SetActualDataLength(haveToCopy+ms_pos); + + *samplepos+=haveToCopy; + + return haveToCopy+headerstrip; + +#else + + *samplepos+=packet.length; + MILLISLEEP(0); //yet not implemented//bad idea + return packet.length; +#endif +} + +int VideoWin::getCurrentAudioMediaSample(IMediaSample** ms) +{ + //WaitForSingleObject(filtermutex,INFINITE); + if (!sourcefilter){ + // ReleaseMutex(filtermutex); + return 0; + } + if (cur_audio_media_sample) { + *ms=cur_audio_media_sample;//already open + return 1; + } + if (!sourcefilter->getCurrentAudioMediaSample(ms)) { + // ReleaseMutex(filtermutex); + } + if (*ms) (*ms)->SetActualDataLength(0); + cur_audio_media_sample=*ms; + //Don't release the mutex before deliver + return 1; +} + +int VideoWin::getCurrentVideoMediaSample(IMediaSample** ms) +{ + //WaitForSingleObject(filtermutex,INFINITE); + if (!sourcefilter){ + // ReleaseMutex(filtermutex); + return 0; + } + if (cur_video_media_sample) { + *ms=cur_video_media_sample;//already open + return 1; + } + if (!sourcefilter->getCurrentVideoMediaSample(ms)) { + // ReleaseMutex(filtermutex); + } + if (*ms) (*ms)->SetActualDataLength(0); + + cur_video_media_sample=*ms; + //Don't release the mutex before deliver + return 1; +} + +int VideoWin::DeliverAudioMediaSample(){ + if (cur_audio_media_sample) { + sourcefilter->DeliverAudioMediaSample(cur_audio_media_sample); + cur_audio_media_sample=NULL; + } + //ReleaseMutex(filtermutex); + return 1; +} + +int VideoWin::DeliverVideoMediaSample(){ + if (cur_video_media_sample) { + sourcefilter->DeliverVideoMediaSample(cur_video_media_sample); + cur_video_media_sample=NULL; + } + //ReleaseMutex(filtermutex); + return 1; +} + +long long VideoWin::SetStartOffset(long long curreftime, bool *rsync) +{ + *rsync=false; + if (offsetnotset) { + startoffset=curreftime;//offset is set for audio + offsetnotset=false; + offsetvideonotset=false; + } else { + if (offsetvideonotset) { + offsetvideonotset=false; + *rsync=true; + } else { + if ( (curreftime-lastrefvideotime)>10000000LL + || (curreftime-lastrefvideotime)<-10000000LL) {//if pts jumps to big resync + startoffset+=curreftime-lastrefvideotime; + //lastrefaudiotime+=curreftime-lastrefvideotime; + *rsync=true; + offsetaudionotset=true; + + } + } + + } + lastrefvideotime=curreftime; + return startoffset; + +} + +long long VideoWin::SetStartAudioOffset(long long curreftime, bool *rsync) +{ + *rsync=false; + if (offsetnotset) { + startoffset=curreftime; + offsetnotset=false; + offsetaudionotset=false; + } else { + if (offsetaudionotset) { + offsetaudionotset=false; + *rsync=true; + } else { + if ( (curreftime-lastrefaudiotime)>10000000LL + || (curreftime-lastrefaudiotime)<-10000000LL) {//if pts jumps to big resync + startoffset+=curreftime-lastrefaudiotime; + lastrefvideotime+=curreftime-lastrefaudiotime; + *rsync=true; + offsetvideonotset=true; + + } + } + + } + lastrefaudiotime=curreftime; + return startoffset; + +} + + + #ifdef DEV int VideoWin::test() { diff --git a/videowin.h b/videowin.h index b736954..6b4f2cb 100644 --- a/videowin.h +++ b/videowin.h @@ -23,10 +23,16 @@ #include #include +#include +#include #include "defines.h" #include "video.h" +#define DS_DEBUG + +class DsSourceFilter; + class VideoWin : public Video { public: @@ -60,10 +66,49 @@ class VideoWin : public Video int getFD(); ULLONG getCurrentTimestamp(); + //Writing Data to Videodevice + virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos); + + int getCurrentAudioMediaSample(IMediaSample** ms); + int DeliverAudioMediaSample(); + + int getCurrentVideoMediaSample(IMediaSample** ms); + int DeliverVideoMediaSample(); + + long long SetStartOffset(long long curreftime, bool *rsync); + long long SetStartAudioOffset(long long curreftime, bool *rsync); + + void SetAudioState(bool state){audioon=state;}; + + void turnVideoOn(){videoon=true;}; + void turnVideoOff(){videoon=false;}; + #ifdef DEV int test(); int test2(); #endif +private: + IMediaControl* dsmediacontrol; + IGraphBuilder* dsgraphbuilder; + IMediaSample* cur_audio_media_sample; + IMediaSample* cur_video_media_sample; + + DsSourceFilter* sourcefilter; + HANDLE filtermutex; + void CleanupDS(); + bool offsetnotset; + bool offsetvideonotset; + bool offsetaudionotset; + long long startoffset; + long long lastrefvideotime; + long long lastrefaudiotime; + + bool firstsynched; + bool audioon; + bool videoon; +#ifdef DS_DEBUG + DWORD graphidentifier; +#endif }; #endif diff --git a/vlivebanner.cc b/vlivebanner.cc index afb411d..63d9a22 100644 --- a/vlivebanner.cc +++ b/vlivebanner.cc @@ -117,7 +117,11 @@ void VLiveBanner::setChannel(Channel* tChannel) event = (*eventList)[i]; btime = localtime((time_t*)&event->time); +#ifndef _MSC_VER strftime(tempString2, 299, "%0H:%0M ", btime); +#else + strftime(tempString2, 299, "%H:%M ", btime); +#endif SNPRINTF(tempString, 299, "%s %s", tempString2, event->title); event->index = sl.addOption(tempString, first); first = 0; diff --git a/vompreswin.h b/vompreswin.h new file mode 100644 index 0000000..28facbe --- /dev/null +++ b/vompreswin.h @@ -0,0 +1,30 @@ + +/* + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VOMPRESWIN_H +#define _WIN32_WINNT 0x501 + +#include +#include +#define VOMPACCELERATOR 1 + +#define VOMPRESWIN_H +#endif diff --git a/vompwin.rc b/vompwin.rc new file mode 100644 index 0000000..103371a --- /dev/null +++ b/vompwin.rc @@ -0,0 +1,43 @@ + + +#include "vompreswin.h" + + + +//1 TEXTINCLUDE +//BEGIN +// "#include ""winsock2.h""\r\n" +// "#include ""vompreswin.h""\r\n" +// "\0" +//END + + + + + +VOMPACCELERATOR ACCELERATORS +BEGIN + VK_INSERT, APPCOMMAND_MEDIA_CHANNEL_DOWN, VIRTKEY, CONTROL, + NOINVERT + VK_INSERT, APPCOMMAND_MEDIA_CHANNEL_DOWN, VIRTKEY, NOINVERT + VK_PRIOR, APPCOMMAND_MEDIA_CHANNEL_DOWN, VIRTKEY, NOINVERT + VK_OEM_PLUS, APPCOMMAND_MEDIA_CHANNEL_UP, VIRTKEY, CONTROL, NOINVERT + VK_OEM_PLUS, APPCOMMAND_MEDIA_CHANNEL_UP, VIRTKEY, NOINVERT + VK_NEXT, APPCOMMAND_MEDIA_CHANNEL_UP, VIRTKEY, NOINVERT + "F", APPCOMMAND_MEDIA_FAST_FORWARD, VIRTKEY, SHIFT, CONTROL, + NOINVERT + VK_F8, APPCOMMAND_VOLUME_MUTE, VIRTKEY, NOINVERT + "P", APPCOMMAND_MEDIA_PAUSE, VIRTKEY, CONTROL, NOINVERT + "P", APPCOMMAND_MEDIA_PLAY, VIRTKEY, SHIFT, CONTROL, + NOINVERT + "R", APPCOMMAND_MEDIA_RECORD, VIRTKEY, CONTROL, NOINVERT + "B", APPCOMMAND_MEDIA_PREVIOUSTRACK, VIRTKEY, CONTROL, + NOINVERT + "F", APPCOMMAND_MEDIA_NEXTTRACK, VIRTKEY, CONTROL, NOINVERT + "S", APPCOMMAND_MEDIA_STOP, VIRTKEY, CONTROL, NOINVERT + VK_F9, APPCOMMAND_VOLUME_DOWN, VIRTKEY, NOINVERT + VK_F10, APPCOMMAND_VOLUME_UP, VIRTKEY, NOINVERT +END + + + diff --git a/vrecordinglist.cc b/vrecordinglist.cc index c62c9d8..aea31ca 100644 --- a/vrecordinglist.cc +++ b/vrecordinglist.cc @@ -111,7 +111,11 @@ void VRecordingList::drawData() { rec = recDir->recList[j]; btime = localtime((time_t*)&rec->start); +#ifndef _MSC_VER strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime); +#else + strftime(tempA, 299, "%d/%m %H:%M ", btime); +#endif sprintf(tempB, "%s\t%s", tempA, rec->getProgName()); rec->index = sl.addOption(tempB, first); first = 0; diff --git a/vvideolive.cc b/vvideolive.cc index f854de4..5281013 100644 --- a/vvideolive.cc +++ b/vvideolive.cc @@ -154,6 +154,18 @@ int VVideoLive::handleCommand(int command) viewman->updateView(v); return 2; } +#ifdef DEV + case Remote::YELLOW: + { + player->test1(); + break; + } + case Remote::BLUE: + { + player->test2(); + break; + } +#endif } return 1; diff --git a/winmain.cc b/winmain.cc new file mode 100644 index 0000000..5ad7e89 --- /dev/null +++ b/winmain.cc @@ -0,0 +1,519 @@ +/* + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifdef WIN32 +#include +#include +#include +#include + +#define _WIN32_WINNT 0x501 +#include +#include + +#include "vompreswin.h" + +#include "defines.h" +#include "log.h" +#include "remotewin.h" +#include "ledwin.h" +#include "mtdwin.h" +#include "timers.h" +#include "videowin.h" +#include "audiowin.h" +#include "vdr.h" +#include "osdwin.h" +#include "viewman.h" +#include "command.h" + +void sighandler(int signalReceived); +void shutdown(int code); + +// Global variables -------------------------------------------------------------------------------------------------- +int debugEnabled = 0; +Log* logger; +Remote* remote; +Mtd* mtd; +Led* led; +Osd* osd; +Timers* timers; +ViewMan* viewman; +Command* command; +VDR* vdr; +Video* video; +Audio* audio; + + +void MILLISLEEP(ULONG a) +{ + + Sleep(a); + +} + +DWORD WINAPI commandthreadStart(void *arg) +{ + command->run(); + return 0; +} + +bool InitApp(HINSTANCE hinst,int cmdshow); + +HWND win;//global window handle +HACCEL acc; + +#define ERROR_MSG(str) MessageBox(win,str,"Error!",MB_OK|MB_ICONWARNING) +INT WINAPI WinMain( HINSTANCE hinst , HINSTANCE previnst, LPSTR cmdline, int cmdshow) +{ + //On Windows we have to init a window, we use DXUT + if (!InitApp(hinst,cmdshow)) return false; + //Starting Network support + WSADATA wsadat; + int result = WSAStartup(MAKEWORD(2,2),&wsadat); + if (result!=NO_ERROR) { + ERROR_MSG("Initialising WinSocked: Error at WSAStartup()\n"); + return 0; + } + result= CoInitializeEx(NULL,COINIT_MULTITHREADED );//Initialize COM for DirectShow + if (result!=S_OK) { + ERROR_MSG("Initialising COM: Error at Coinitialize()\n"); + return 0; + } + + + + + // Init global vars ------------------------------------------------------------------------------------------------ + + logger = new Log(); + remote = new RemoteWin(); + mtd = new MtdWin(); + led = new LedWin(); + timers = new Timers(); + osd = new OsdWin(); + vdr = new VDR(); + video = new VideoWin(); + audio = new AudioWin(); + viewman = new ViewMan(); + command = new Command(); + + if (!logger || !remote || !mtd || !led || !osd || !video || !audio || !viewman || !command) + { + ERROR_MSG("Could not create objects. Memory problems?\n"); + shutdown(1); + WSACleanup(); + return 0; + } + + // Get logging module started -------------------------------------------------------------------------------------- + + if (!logger->init(Log::DEBUG, "vompwin.log", true)) + { + ERROR_MSG("Could not initialise log object. Aborting.\n"); + shutdown(1); + WSACleanup(); + return 0; + } + + logger->log("Core", Log::INFO, "Starting up..."); + + + + // Init modules ---------------------------------------------------------------------------------------------------- + int success; + + success = remote->init("/dev/rawir"); + if (success) + { + logger->log("Core", Log::INFO, "Remote module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Remote module failed to initialise"); + shutdown(1); + WSACleanup(); + return 0; + } + + success = led->init(0); + if (success) + { + logger->log("Core", Log::INFO, "LED module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "LED module failed to initialise"); + shutdown(1); + WSACleanup(); + return 0; + } + + success = mtd->init("/dev/mtd1"); + if (success) + { + logger->log("Core", Log::INFO, "Mtd module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Mtd module failed to initialise"); + shutdown(1); + WSACleanup(); + return 0; + } + + success = timers->init(); + if (success) + { + logger->log("Core", Log::INFO, "Timers module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Timers module failed to initialise"); + shutdown(1); + WSACleanup(); + return 0; + } + + UCHAR videoFormat = (UCHAR)mtd->getPALorNTSC(); + if (videoFormat == Video::PAL) logger->log("Core", Log::INFO, "Read from MTD: PAL 720x576"); + else if (videoFormat == Video::NTSC) logger->log("Core", Log::INFO, "Read from MTD: NTSC 720x480"); + else logger->log("Core", Log::INFO, "No help from MTD. Assuming NTSC 720x480"); + + success = video->init(videoFormat); + if (success) + { + logger->log("Core", Log::INFO, "Video module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Video module failed to initialise"); + shutdown(1); + WSACleanup(); + return 0; + } + + success = osd->init((void*)&win); + if (success) + { + logger->log("Core", Log::INFO, "OSD module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "OSD module failed to initialise"); + shutdown(1); + WSACleanup(); + return 0; + } + + success = audio->init(Audio::MPEG2_PES); + if (success) + { + logger->log("Core", Log::INFO, "Audio module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Audio module failed to initialise"); + shutdown(1); + WSACleanup(); + return 0; + } + + success = vdr->init(3024); + if (success) + { + logger->log("Core", Log::INFO, "VDR module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "VDR module failed to initialise"); + shutdown(1); + WSACleanup(); + return 0; + } + + success = viewman->init(); + if (success) + { + logger->log("Core", Log::INFO, "ViewMan module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "ViewMan module failed to initialise"); + shutdown(1); + WSACleanup(); + return 0; + } + + success = command->init(); + if (success) + { + logger->log("Core", Log::INFO, "Command module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Command module failed to initialise"); + shutdown(1); + WSACleanup(); + return 0; + } + + // Other init ------------------------------------------------------------------------------------------------------ + + logger->log("Core", Log::NOTICE, "Startup successful"); + + // Run main loop --------------------------------------------------------------------------------------------------- + + // Ok, all major device components and other bits are loaded and ready + + HANDLE commandthread; + commandthread= CreateThread(NULL, 0, commandthreadStart, NULL,0, + NULL); + MSG message; + message.message=WM_NULL; + bool run=true; + while(run && WaitForSingleObject(commandthread,0)==WAIT_TIMEOUT) { + if (PeekMessage(&message, NULL, 0,0,PM_REMOVE)!=0) { + if (TranslateAccelerator(win,acc,&message)==NULL) { + TranslateMessage(&message); + DispatchMessage(&message); + switch (message.message) { + case WM_QUIT: + run=false; //TODO post exit to command Messages + }; + } + } else { + //Render + ((OsdWin*)osd)->Render(); + } + } + // When that returns quit ------------------------------------------------------------------------------------------ + WaitForSingleObject(commandthread,INFINITE); + shutdown(0); + WSACleanup(); + return 0; + +} + +LONG FAR PASCAL WindowProc(HWND win, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) { + case WM_DESTROY: { + //TODO: call command + logger->log("Core", Log::NOTICE, "Window closed, shutting down..."); + command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe? + ((RemoteWin*)Remote::getInstance())->Signal(); + PostQuitMessage(0); + }break; + case WM_SIZE: { + int width = LOWORD(lparam); + int height = HIWORD(lparam); + //Call device + } + break; + case WM_PAINT: + RECT r; + PAINTSTRUCT ps; + if (GetUpdateRect(win, &r, FALSE)) { + BeginPaint(win, &ps); + //Call Painting Mechanism + EndPaint(win, &ps); + } + break; + case WM_KEYDOWN: + if (((RemoteWin*)remote)->ReceiveButtonVK(wparam)) { + return 0L; //We process that Key + } else { + return DefWindowProc(win, msg, wparam, lparam); + } + + break; + case WM_APPCOMMAND: + if (((RemoteWin*)remote)->ReceiveButtonAP(GET_APPCOMMAND_LPARAM(lparam))){ + return TRUE; //yes we process that message + } else { + return DefWindowProc(win, msg, wparam, lparam); + } + + break; + case WM_COMMAND: + if (((RemoteWin*)remote)->ReceiveButtonAP(LOWORD(wparam))){ + return 0; //yes we process that message + } else { + return DefWindowProc(win, msg, wparam, lparam); + } + + break; + default: + return DefWindowProc(win, msg, wparam, lparam); + } + return 0L; +} + + +bool InitApp(HINSTANCE hinst,int cmdshow) { + WNDCLASS wcs; + DWORD flags; + wcs.style = CS_HREDRAW | CS_VREDRAW; + wcs.lpfnWndProc = WindowProc; + wcs.cbClsExtra = 0; + wcs.cbWndExtra = sizeof(DWORD); + wcs.hInstance = hinst; + wcs.hIcon = NULL; + wcs.hCursor = NULL; + wcs.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wcs.lpszMenuName = NULL; + wcs.lpszClassName = "vomp"; + acc=LoadAccelerators(hinst,MAKEINTRESOURCE(VOMPACCELERATOR)); + if (!RegisterClass(&wcs)) + return false; + flags =WS_VISIBLE | WS_POPUP | WS_CAPTION | WS_SYSMENU + |WS_MINIMIZEBOX | WS_SIZEBOX |WS_MAXIMIZEBOX; + RECT wnted={0,0,720,576}; + AdjustWindowRect(&wnted,flags ,false); + win=CreateWindow("vomp","vomp",flags, CW_USEDEFAULT,CW_USEDEFAULT, + wnted.right-wnted.left,wnted.bottom-wnted.top,NULL,NULL,hinst,NULL); + if (!win) + return FALSE; + ShowWindow(win,SW_SHOWNORMAL); + UpdateWindow(win); + return TRUE; +} + + + + + +// ------------------------------------------------------------------------------------------------------------------- + +void shutdown(int code) +{ + if (viewman) + { + viewman->shutdown(); + delete viewman; + logger->log("Core", Log::NOTICE, "ViewMan module shut down"); + } + + if (command) // shut down command here in case views have posted messages + { + command->shutdown(); + delete command; + logger->log("Core", Log::NOTICE, "Command module shut down"); + } + + if (vdr) + { + vdr->shutdown(); + delete vdr; + logger->log("Core", Log::NOTICE, "VDR module shut down"); + } + + if (osd) + { + osd->shutdown(); + delete osd; + logger->log("Core", Log::NOTICE, "OSD module shut down"); + } + + if (audio) + { + audio->shutdown(); + delete audio; + logger->log("Core", Log::NOTICE, "Audio module shut down"); + } + + if (video) + { + video->shutdown(); + delete video; + logger->log("Core", Log::NOTICE, "Video module shut down"); + } + + if (timers) + { + timers->shutdown(); + delete timers; + logger->log("Core", Log::NOTICE, "Timers module shut down"); + } + + if (mtd) + { + mtd->shutdown(); + delete mtd; + logger->log("Core", Log::NOTICE, "MTD module shut down"); + } + + if (led) + { + led->shutdown(); + delete led; + logger->log("Core", Log::NOTICE, "LED module shut down"); + } + + if (remote) + { + remote->shutdown(); + delete remote; + logger->log("Core", Log::NOTICE, "Remote module shut down"); + } + + if (logger) + { + logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n"); + logger->shutdown(); + delete logger; + } + ExitProcess(0); + +} + +// ------------------------------------------------------------------------------------------------------------------- + +ULLONG ntohll(ULLONG a) +{ + return htonll(a); +} + +ULLONG htonll(ULLONG a) +{ +/* + #if BYTE_ORDER == BIG_ENDIAN + return a; + #else + ULLONG b = 0; + + b = ((a << 56) & 0xFF00000000000000ULL) + | ((a << 40) & 0x00FF000000000000ULL) + | ((a << 24) & 0x0000FF0000000000ULL) + | ((a << 8) & 0x000000FF00000000ULL) + | ((a >> 8) & 0x00000000FF000000ULL) + | ((a >> 24) & 0x0000000000FF0000ULL) + | ((a >> 40) & 0x000000000000FF00ULL) + | ((a >> 56) & 0x00000000000000FFULL) ; + + return b; + #endif*///This macro switching does not work for windows, here is a implementation without + // using BYTE_ORDER + //#define ntohll(x) (((_int64)(ntohl((int)((x << 32) >> 32))) << 32) | + // (unsigned int)ntohl(((int)(x >> 32)))) //By Runner + + return (((ULLONG)htonl((ULONG)((a<<32)>> 32))<<32) + |(ULONG)htonl(((ULONG) (a >> 32)))); +} +#endif \ No newline at end of file diff --git a/wjpeg.cc b/wjpeg.cc index 361a489..91805d6 100644 --- a/wjpeg.cc +++ b/wjpeg.cc @@ -106,7 +106,13 @@ void WJpeg::draw() free(buffer); logger->log("BJpeg", Log::DEBUG, "deleted buffer"); +#else + DWORD width,height; + width=height=1; + ((SurfaceWin*)surface)->drawJpeg(fileName+1,offsetX,offsetY,&width,&height);//This should went into the abstract base classes? + //Windows has a problem with the leading / fixme + setDimensions(width, height); #endif } -- 2.39.5