From: Chris Tallon Date: Sat, 22 Apr 2006 23:35:06 +0000 (+0000) Subject: Windows port. New sync code. Various other bug fixes. X-Git-Url: https://git.vomp.tv/gitweb/?a=commitdiff_plain;h=88e8e833cbe6bda6a96210b590942b9338d8209e;p=vompclient-marten.git Windows port. New sync code. Various other bug fixes. --- 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 }