From 8186963908659ab349ef7062be8ee2ce5f5f2ec6 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Mon, 8 Feb 2010 15:12:52 +0000 Subject: [PATCH] HDTV for Windows --- afeed.cc | 7 +- audio.h | 1 + audiomvp.cc | 2 +- audiomvp.h | 2 +- audiowin.cc | 10 +- audiowin.h | 5 +- boxx.cc | 1 + boxx.h | 6 + channel.cc | 2 + channel.h | 1 + command.cc | 17 +- defines.h | 6 +- demuxer.cc | 560 +++++++++---- demuxer.h | 19 +- demuxeraudio.cc | 16 +- demuxeraudio.h | 2 + demuxermedia.cc | 6 +- demuxerts.cc | 38 +- demuxerts.h | 4 +- demuxervdr.cc | 10 +- draintarget.h | 12 +- dsallocator.cc | 858 ++++++++++++++++++-- dsallocator.h | 77 +- dssourcefilter.cc | 12 + dssourcefilter.h | 5 + dssourcepin.cc | 97 ++- dssourcepin.h | 8 +- eventdispatcher.cc | 2 + eventdispatcher.h | 3 +- main.cc | 45 +- mediafile.cc | 1 + osd.h | 1 + osdwin.cc | 292 +++++-- osdwin.h | 44 +- player.cc | 28 +- player.h | 3 +- playerlivetv.cc | 125 ++- playerlivetv.h | 2 + readme.win | 34 +- recinfo.h | 2 + recording.cc | 9 +- recording.h | 2 +- stream.cc | 32 +- stream.h | 2 +- surface.cc | 4 +- surfacewin.cc | 83 +- tcp.cc | 4 +- teletextdecodervbiebu.cc | 1668 +++++++++++++++++++------------------- teletextdecodervbiebu.h | 660 +++++++-------- vaudioselector.cc | 2 + vcolourtuner.cc | 6 + vdr.cc | 19 +- vdrresponsepacket.cc | 10 + vdrresponsepacket.h | 1 + vfeed.cc | 4 +- video.cc | 19 +- video.h | 12 +- videomvp.cc | 2 +- videomvp.h | 2 +- videowin.cc | 817 +++++++++++++++---- videowin.h | 288 ++++--- vmediaview.cc | 6 + vmediaview.h | 10 +- vradiorec.h | 1 + vrecording.cc | 2 +- vrecordinglist.cc | 41 +- vvideorec.cc | 38 +- vvideorec.h | 10 +- vwelcome.cc | 12 + winmain.cc | 22 +- wjpeg.cc | 3 +- 71 files changed, 4171 insertions(+), 1986 deletions(-) diff --git a/afeed.cc b/afeed.cc index 22b5b45..43e8c86 100644 --- a/afeed.cc +++ b/afeed.cc @@ -76,20 +76,21 @@ void AFeed::threadMethod() if (alen) { - cb.call(this); + cb.call(this); // Log::getInstance()->log("Afeed", Log::DEBUG, "written"); } else { //MILLISLEEP(100); - MILLISLEEP(20); //Performance Issue Marten + MILLISLEEP(5); //Performance Issue Marten } } else { Demuxer::getInstance()->flushAudio(); + //Log::getInstance()->log("AFeed", Log::DEBUG, "No data delay"); //MILLISLEEP(100); - MILLISLEEP(20); //Performance Issue + MILLISLEEP(5); //Performance Issue } } } diff --git a/audio.h b/audio.h index a2a3263..082bc27 100644 --- a/audio.h +++ b/audio.h @@ -58,6 +58,7 @@ class Audio : public DrainTarget, public AbstractOption virtual int mute()=0; virtual int unMute()=0; virtual bool supportsAc3()=0; + virtual bool maysupportAc3(){return false;} int volumeUp(); int volumeDown(); diff --git a/audiomvp.cc b/audiomvp.cc index 8e6034d..b9ba62e 100644 --- a/audiomvp.cc +++ b/audiomvp.cc @@ -235,7 +235,7 @@ void AudioMVP::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos) packet = mplist.front(); } -UINT AudioMVP::DeliverMediaSample(const UCHAR* buffer, UINT* samplepos) +UINT AudioMVP::DeliverMediaSample(UCHAR* buffer, UINT* samplepos) { int written = ::write(fdAudio, buffer + packet.pos_buffer + *samplepos, packet.length - *samplepos); diff --git a/audiomvp.h b/audiomvp.h index 0ac1ccc..b1d9ff6 100644 --- a/audiomvp.h +++ b/audiomvp.h @@ -89,7 +89,7 @@ class AudioMVP : public Audio //Writing Data to Audiodevice virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); - virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos); + virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos); virtual long long SetStartOffset(long long curreftime, bool *rsync) { return 0; }; virtual void ResetTimeOffsets(); diff --git a/audiowin.cc b/audiowin.cc index f6a51b2..aeb8347 100644 --- a/audiowin.cc +++ b/audiowin.cc @@ -353,7 +353,7 @@ bool AudioWin::saveOptionstoServer() return true; } -UINT AudioWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos) +UINT AudioWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos) { DeliverMediaPacket(mediapacket, buffer, samplepos); if (*samplepos == mediapacket.length) { @@ -363,8 +363,8 @@ UINT AudioWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos) else return 0; } -UINT AudioWin::DeliverMediaPacket(MediaPacket packet, - const UCHAR* buffer, +UINT AudioWin::DeliverMediaPacket(const MediaPacket packet, + UCHAR* buffer, UINT *samplepos) { @@ -418,7 +418,7 @@ UINT AudioWin::DeliverMediaPacket(MediaPacket packet, UINT haveToCopy; if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample //samplepos=0; - MILLISLEEP(10); + //MILLISLEEP(10); return *samplepos; } ms_pos=ms->GetActualDataLength(); @@ -428,7 +428,7 @@ UINT AudioWin::DeliverMediaPacket(MediaPacket packet, vw->DeliverAudioMediaSample(); //we are full! if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample //samplepos=0; - MILLISLEEP(10); + //MILLISLEEP(10); return *samplepos; } ms_pos=ms->GetActualDataLength(); diff --git a/audiowin.h b/audiowin.h index e71c14a..69e66d8 100644 --- a/audiowin.h +++ b/audiowin.h @@ -66,8 +66,8 @@ class AudioWin : public Audio // Writing Data to Audiodevice virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); - virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos); - UINT DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, UINT *samplepos); + virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos); + UINT DeliverMediaPacket(MediaPacket packet, UCHAR* buffer, UINT *samplepos); int dsInitAudioFilter(IGraphBuilder* dsgraphbuilder); const AudioFilterDescList *getAudioFilterList(int &selected); @@ -77,6 +77,7 @@ class AudioWin : public Audio bool selectMp3AudioFilter(int filter); virtual bool supportsAc3(); + virtual bool maysupportAc3(){return true;} // We are not sure maybe we support this, allows the player to select ac3, if there is no other option private: MediaPacket mediapacket; public: diff --git a/boxx.cc b/boxx.cc index 81b8878..0bc3570 100644 --- a/boxx.cc +++ b/boxx.cc @@ -21,6 +21,7 @@ #include "boxx.h" #include "bitmap.h" #include "log.h" +#include char Boxx::numBoxxes = 0; diff --git a/boxx.h b/boxx.h index 0e7a4b9..b38f0a5 100644 --- a/boxx.h +++ b/boxx.h @@ -33,9 +33,15 @@ using namespace std; #ifdef WIN32 #include "surfacewin.h" #else + +#ifdef _MIPS_ARCH +#include "surfacedirectfb.h" +#else #include "surfacemvp.h" #endif +#endif + class Bitmap; class Boxx diff --git a/channel.cc b/channel.cc index 052d042..8f2f5bc 100644 --- a/channel.cc +++ b/channel.cc @@ -37,6 +37,8 @@ Channel::Channel() numDPids = 0; numSPids = 0; + vstreamtype=2; //Mpeg2 + } Channel::~Channel() diff --git a/channel.h b/channel.h index a813470..c3688f2 100644 --- a/channel.h +++ b/channel.h @@ -47,6 +47,7 @@ class Channel ULONG number; ULONG type; + UCHAR vstreamtype; char* name; int index; diff --git a/command.cc b/command.cc index a4f7ae6..d2b222e 100644 --- a/command.cc +++ b/command.cc @@ -113,7 +113,10 @@ int Command::shutdown() void Command::stop() { // VDR::getInstance()->cancelFindingServer(); + logger->log("Command", Log::NOTICE, "Command stop1..."); + udp.shutdown(); + logger->log("Command", Log::NOTICE, "Command stop2..."); irun = 0; } @@ -138,7 +141,11 @@ void Command::doWallpaper() if (video->getFormat() == Video::PAL) { logger->log("Command", Log::DEBUG, "PAL wallpaper selected"); +#ifndef _MIPS_ARCH wallpaperj->init("/wallpaperPAL.jpg"); +#else + wallpaperj->init("wallpaperPAL.jpg"); +#endif } else { @@ -200,9 +207,10 @@ void Command::run() #else ReleaseMutex(masterLock); #endif - button = remote->getButtonPress(2); // FIXME why is this set to 2 and not 0? so it can quit + + button = remote->getButtonPress(2); // FIXME why is this set to 2 and not 0? so it can quit // something happened, lock and process - + // logger->log("Command", Log::DEBUG, "WANT LOCK"); #ifndef WIN32 pthread_mutex_lock(&masterLock); @@ -223,6 +231,7 @@ void Command::run() #else ReleaseMutex(masterLock); #endif + } void Command::postMessage(Message* m) @@ -572,7 +581,11 @@ void Command::doReboot() // just kill it... logger->log("Command", Log::NOTICE, "Reboot"); #ifndef WIN32 +#ifndef _MIPS_ARCH reboot(LINUX_REBOOT_CMD_RESTART); +#else + stop(); +#endif #endif //Would we support this on windows? } diff --git a/defines.h b/defines.h index 9f5815e..f082f53 100644 --- a/defines.h +++ b/defines.h @@ -52,8 +52,12 @@ void MILLISLEEP(ULONG a); int max(int, int); int min(UINT, int); - +#ifdef _MIPS_ARCH + #define Surface_TYPE SurfaceDirectFB +#else #define Surface_TYPE SurfaceMVP +#endif + #define Thread_TYPE ThreadP #include #define ThreadID_TYPE pthread_t diff --git a/demuxer.cc b/demuxer.cc index 054baca..0c07d00 100644 --- a/demuxer.cc +++ b/demuxer.cc @@ -27,14 +27,144 @@ #include +#include + #define DEMUXER_SEQ_HEAD 0x000001B3 #define DEMUXER_PIC_HEAD 0x00000101 + +#define DEMUXER_H264_ACCESS_UNIT 0x00000109 +#define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107 + + #define SEEK_THRESHOLD 150000 // About 1.5 seconds // Statics const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 }; Demuxer* Demuxer::instance = NULL; +class NALUUnit { +public: + NALUUnit(const UCHAR* buf,UINT length_buf); + ~NALUUnit(); + +inline UINT getBits(UINT num_bits); + UINT getUe(); + int getSe(); + bool isEonalu() {return eonalu;}; + +protected: + UCHAR* nalu_buf; + UINT nalu_length; + UINT pos; + UCHAR bit_pos; + UCHAR working_byte; + UINT last_bytes; + bool eonalu; +}; + +NALUUnit::NALUUnit(const UCHAR *buf, UINT length_buf) +{ + nalu_length=0; + nalu_buf=NULL; + pos=0; + bit_pos=0; + working_byte=0; + last_bytes=0; + eonalu=false; + + UINT nalu_start=0; + UINT nalu_end=0; + UINT pattern =(((UINT)buf[ 0] << 16) | + ((UINT)buf[1] << 8) | + (UINT)buf[2] ); + nalu_start=3; + while (pattern != 0x000001) + { + if (++nalu_start >= length_buf) return; + pattern = ((pattern << 8) | buf[nalu_start])&0x00FFFFFF; + } + nalu_end=nalu_start+1; + pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF; + + while (pattern != 0x000001 && pattern != 0x000000) + { + if (++nalu_end >= length_buf) { nalu_end+=3;break;}; + pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF; + } + nalu_end-=3; + nalu_end=min(length_buf-1,nalu_end); + nalu_length=nalu_end-nalu_start; + nalu_buf=(UCHAR*)malloc(nalu_length); + memcpy(nalu_buf,buf+nalu_start,nalu_length); + pos=1; +} + +NALUUnit::~NALUUnit() +{ + if (nalu_buf) free(nalu_buf); +} + +inline UINT NALUUnit::getBits(UINT num_bits) +{ + if (num_bits==0) return 0; //??? + UINT remain_bits=num_bits; + UINT work=0; + //May be slow, but should work! + while (remain_bits>0) { + if (bit_pos==0) { + if (pos>bit_pos) & (0xFF>>(8-fetch_bits))); + work|=(working_byte &(0xFF>>(bit_pos)))>>(8-fetch_bits-bit_pos); + remain_bits-=fetch_bits; + bit_pos=(bit_pos+fetch_bits)%8; + } + return work; +} + +UINT NALUUnit::getUe() +{ + int leadbits=-1; + bool bit; + for( bit = 0; !bit && !eonalu; leadbits++ ) + bit = getBits(1); + if (eonalu) return true; + return ((1 << leadbits)-1)+getBits(leadbits); +} + +int NALUUnit::getSe() +{ + UINT input=getUe(); + if (input==0) return 0; + int output=((input+1)>>1); + if (input & 0x1) output*=-1; + return output; +} + + + static const int PESPacket_initial_size = 2000; // PESPacket methods @@ -145,7 +275,7 @@ UCHAR PESPacket::operator[] (UINT index) const return data[index]; } -UINT PESPacket::findPictureHeader() const +UINT PESPacket::findPictureHeader(bool h264) const { if (size < 12) return 0; UINT pattern = ( ((UINT)data[ 8] << 24) | @@ -153,15 +283,25 @@ UINT PESPacket::findPictureHeader() const ((UINT)data[10] << 8) | (UINT)data[11] ); UINT pos = 11; - while (pattern != DEMUXER_PIC_HEAD) - { - if (++pos >= size) return 0; - pattern = (pattern << 8) | data[pos]; + if (h264) { + + while (pattern != DEMUXER_H264_ACCESS_UNIT) + { + if (++pos >= size) return 0; + pattern = (pattern << 8) | data[pos]; + } + return pos-3; + } else { + while (pattern != DEMUXER_PIC_HEAD) + { + if (++pos >= size) return 0; + pattern = (pattern << 8) | data[pos]; + } + return pos-3; } - return pos-3; } -UINT PESPacket::findSeqHeader() const +UINT PESPacket::findSeqHeader(bool h264) const { if (seq_header != 1) return seq_header; if (size < 12) return 0; @@ -170,16 +310,31 @@ UINT PESPacket::findSeqHeader() const ((UINT)data[10] << 8) | (UINT)data[11] ); UINT pos = 11; - while (pattern != DEMUXER_SEQ_HEAD) + if (h264) { + while ((pattern & 0xFFFFFF1F) != DEMUXER_H264_SEQ_PARAMETER_SET) + { + if (++pos >= size) + { + seq_header = 0; + return 0; + } + pattern = (pattern << 8) | data[pos]; + } + seq_header = pos - 3; + } + else { - if (++pos >= size) - { - seq_header = 0; - return 0; - } - pattern = (pattern << 8) | data[pos]; + while (pattern != DEMUXER_SEQ_HEAD) + { + if (++pos >= size) + { + seq_header = 0; + return 0; + } + pattern = (pattern << 8) | data[pos]; + } + seq_header = pos - 3; } - seq_header = pos - 3; return seq_header; } @@ -194,6 +349,9 @@ Demuxer::Demuxer() vid_seeking = aud_seeking = false; video_pts = audio_pts = 0; ispre_1_3_19 = false; + packetnum=0; + h264 = false; + fps = 25.0; } Demuxer::~Demuxer() @@ -208,7 +366,7 @@ Demuxer* Demuxer::getInstance() } int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, DrainTarget* teletext, - ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT, DVBSubtitles* tsubtitles) + ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT,double infps, DVBSubtitles* tsubtitles) { if (!initted) { @@ -227,7 +385,7 @@ int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, D } else { isteletextdecoded = false; } - + fps=infps; reset(); initted = true; subtitles = tsubtitles; @@ -244,6 +402,8 @@ void Demuxer::reset() aspect_ratio = (enum AspectRatio) 0; frame_rate = bit_rate = 0; ispre_1_3_19 = false; + h264 = false; + packetnum=0; for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++) { @@ -345,13 +505,15 @@ bool Demuxer::submitPacket(PESPacket& packet) UINT sent = 0; UCHAR packet_type = packet.getPacketType(); const UCHAR* packetdata = packet.getData(); - if (packet_type >= PESTYPE_VID0 && packet_type <= PESTYPE_VIDMAX) { if (video_current == -1) video_current = packet_type; if (video_current == packet_type && !vid_seeking) - sent = videostream.put(&packetdata[0], packet.getSize(), MPTYPE_VIDEO); - else + { + sent = videostream.put(&packetdata[0], packet.getSize(), h264?MPTYPE_VIDEO_H264:MPTYPE_VIDEO_MPEG2,packetnum); + if (sent) packetnum++; + } + else sent = packet.getSize(); } else if (packet_type >= PESTYPE_AUD0 && packet_type <= PESTYPE_AUDMAX) @@ -359,8 +521,11 @@ bool Demuxer::submitPacket(PESPacket& packet) if (audio_current == -1) audio_current = packet_type; avail_mpaudchan[packet_type - PESTYPE_AUD0] = true; if (audio_current == packet_type && !aud_seeking) - sent = audiostream.put(&packetdata[0], packet.getSize(), MPTYPE_MPEG_AUDIO); - else + { + sent = audiostream.put(&packetdata[0], packet.getSize(), MPTYPE_MPEG_AUDIO,packetnum); + if (sent) packetnum++; + } + else sent = packet.getSize(); } else if (packet_type == PESTYPE_PRIVATE_1 && @@ -370,7 +535,8 @@ bool Demuxer::submitPacket(PESPacket& packet) avail_ac3audchan[packet.getSubstream() - PESTYPE_SUBSTREAM_AC30] = true; if (packet.getSubstream() == audio_current) { - sent = audiostream.put(&packetdata[0], packet.getSize(), (ispre_1_3_19)? MPTYPE_AC3_PRE13 : MPTYPE_AC3); + sent = audiostream.put(&packetdata[0], packet.getSize(), (ispre_1_3_19)? MPTYPE_AC3_PRE13 : MPTYPE_AC3,packetnum); + if (sent) packetnum++; } else { @@ -397,7 +563,7 @@ bool Demuxer::submitPacket(PESPacket& packet) if (teletext_current == -1) teletext_current = packet.getSubstream(); if (teletext_current == packet.getSubstream() ) { - sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT); + sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT,packetnum); } else { @@ -417,129 +583,250 @@ bool Demuxer::submitPacket(PESPacket& packet) void Demuxer::parsePacketDetails(PESPacket& packet) { - if (packet.getPacketType() >= PESTYPE_AUD0 && - packet.getPacketType() <= PESTYPE_AUDMAX) - { - // Extract audio PTS if it exists - if (packet.hasPTS()) + if (packet.getPacketType() >= PESTYPE_AUD0 && + packet.getPacketType() <= PESTYPE_AUDMAX) { - audio_pts = packet.getPTS(); - // We continue to seek on the audio if the video PTS that we - // are trying to match is ahead of the audio PTS by at most - // SEEK_THRESHOLD. We consider the possibility of PTS wrap. - if (aud_seeking && !vid_seeking && - !( (video_pts_seek > audio_pts && - video_pts_seek - audio_pts < SEEK_THRESHOLD) - || - (video_pts_seek < audio_pts && - video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) )) - { - aud_seeking = 0; - Log::getInstance()->log("Demuxer", Log::DEBUG, - "Leaving audio sync: Audio PTS = %llu", audio_pts); - } - } - } - else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream - { - //Inspired by vdr's device.c - int payload_begin = packet[8]+9; - unsigned char substream_id = packet[payload_begin]; - unsigned char substream_type = substream_id & 0xF0; - unsigned char substream_index = substream_id & 0x1F; -pre_1_3_19_Recording: //This is for old recordings stuff and live TV - if (ispre_1_3_19) - { - substream_id = PESTYPE_PRIVATE_1; - substream_type = 0x80; - substream_index = 0; - } - switch (substream_type) - { - case 0x20://SPU - case 0x30://SPU - packet.setSubstream(substream_id); - break; - case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there? - break; - case 0x80: //ac3, currently only one ac3 track per recording supported - packet.setSubstream(substream_type+substream_index); - // Extract audio PTS if it exists if (packet.hasPTS()) { - audio_pts = packet.getPTS(); - // We continue to seek on the audio if the video PTS that we - // are trying to match is ahead of the audio PTS by at most - // SEEK_THRESHOLD. We consider the possibility of PTS wrap. - if (aud_seeking && !vid_seeking && - !( (video_pts_seek > audio_pts && - video_pts_seek - audio_pts < SEEK_THRESHOLD) - || - (video_pts_seek < audio_pts && - video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) )) - { - aud_seeking = 0; - Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving audio sync: Audio PTS = %llu", audio_pts); - } + audio_pts = packet.getPTS(); + // We continue to seek on the audio if the video PTS that we + // are trying to match is ahead of the audio PTS by at most + // SEEK_THRESHOLD. We consider the possibility of PTS wrap. + if (aud_seeking && !vid_seeking && + !( (video_pts_seek > audio_pts && + video_pts_seek - audio_pts < SEEK_THRESHOLD) + || + (video_pts_seek < audio_pts && + video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) )) + { + aud_seeking = 0; + Log::getInstance()->log("Demuxer", Log::DEBUG, + "Leaving audio sync: Audio PTS = %llu", audio_pts); + } } - break; - case 0x10: //Teletext Is this correct? - packet.setSubstream(substream_id); - // Extract teletxt PTS if it exists - if (packet.hasPTS()) - { - teletext_pts = packet.getPTS(); - } - break; - default: - if (!ispre_1_3_19) + } + else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream + { + //Inspired by vdr's device.c + int payload_begin = packet[8]+9; + unsigned char substream_id = packet[payload_begin]; + unsigned char substream_type = substream_id & 0xF0; + unsigned char substream_index = substream_id & 0x1F; +pre_1_3_19_Recording: //This is for old recordings stuff and live TV + if (ispre_1_3_19) { - ispre_1_3_19=true; //switching to compat mode and live tv mode - goto pre_1_3_19_Recording; + substream_id = PESTYPE_PRIVATE_1; + substream_type = 0x80; + substream_index = 0; } - else + switch (substream_type) { - packet.setSubstream(0); + case 0x20://SPU + case 0x30://SPU + packet.setSubstream(substream_id); + break; + case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there? + break; + case 0x80: //ac3, currently only one ac3 track per recording supported + packet.setSubstream(substream_type+substream_index); + + // Extract audio PTS if it exists + if (packet.hasPTS()) + { + audio_pts = packet.getPTS(); + // We continue to seek on the audio if the video PTS that we + // are trying to match is ahead of the audio PTS by at most + // SEEK_THRESHOLD. We consider the possibility of PTS wrap. + if (aud_seeking && !vid_seeking && + !( (video_pts_seek > audio_pts && + video_pts_seek - audio_pts < SEEK_THRESHOLD) + || + (video_pts_seek < audio_pts && + video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) )) + { + aud_seeking = 0; + Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving audio sync: Audio PTS = %llu", audio_pts); + } + } + break; + case 0x10: //Teletext Is this correct? + packet.setSubstream(substream_id); + // Extract teletxt PTS if it exists + if (packet.hasPTS()) + { + teletext_pts = packet.getPTS(); + } + break; + default: + if (!ispre_1_3_19) + { + ispre_1_3_19=true; //switching to compat mode and live tv mode + goto pre_1_3_19_Recording; + } + else + { + packet.setSubstream(0); + } + break; } - break; } - } - else if (packet.getPacketType() >= PESTYPE_VID0 && - packet.getPacketType() <= PESTYPE_VIDMAX) - { - // Extract video PTS if it exists - if (packet.hasPTS()) video_pts = packet.getPTS(); - - // If there is a sequence header, extract information - UINT pos = packet.findSeqHeader(); - if (pos > 1) + else if (packet.getPacketType() >= PESTYPE_VID0 && + packet.getPacketType() <= PESTYPE_VIDMAX) { - pos += 4; - if (pos+6 >= packet.getSize()) return; - horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4); - vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2]; - setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4)); - frame_rate = packet[pos+3] & 0x0f; - if (frame_rate >= 1 && frame_rate <= 8) - frame_rate = FrameRates[frame_rate]; - else - frame_rate = 0; - bit_rate = ((int)packet[pos+4] << 10) | - ((int)packet[pos+5] << 2) | - ((int)packet[pos+6] >> 6); - if (vid_seeking) - { - vid_seeking = 0; - video_pts_seek = video_pts; - Log::getInstance()->log("Demuxer", Log::DEBUG, - "Entering audio sync: Video PTS = %llu", video_pts); - Log::getInstance()->log("Demuxer", Log::DEBUG, - "Entering audio sync: Audio PTS = %llu", audio_pts); - } - return; + // Extract video PTS if it exists + if (packet.hasPTS()) video_pts = packet.getPTS(); + + // If there is a sequence header, extract information + UINT pos = packet.findSeqHeader(h264); + if (pos > 1) + { + if (!h264) { + pos += 4; + if (pos+6 >= packet.getSize()) return; + horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4); + + vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2]; + + setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4)); + frame_rate = packet[pos+3] & 0x0f; + if (frame_rate >= 1 && frame_rate <= 8) + frame_rate = FrameRates[frame_rate]; + else + frame_rate = 0; + bit_rate = ((int)packet[pos+4] << 10) | + ((int)packet[pos+5] << 2) | + ((int)packet[pos+6] >> 6); + } + else + { + /* Chris and Mark I know this is ugly, should we move this to a method of PESPacket or to NALUUnit what would be better? + This looks so ugly since the header includes variable length parts and I have to parse through the whole header to get the wanted information*/ + NALUUnit nalu(packet.getData()+pos,packet.getSize()-pos); + profile=nalu.getBits(8); + nalu.getBits(8); //constraints + nalu.getBits(8); //level_idc + nalu.getUe(); //seq_parameter_set_id + if (profile==100 || profile==110 || profile==122 || profile==144) + { + if (nalu.getUe()==3) + { + nalu.getBits(1); + } + nalu.getUe(); //bit depth lume + nalu.getUe(); //bit depth chrome + nalu.getBits(1); + if (nalu.getBits(1)) + { + for (int i=0;i<8;i++){ + if (nalu.getBits(1)) + { + if (i<6) + { + UINT lastscale=8; + UINT nextscale=8; + for (int j=0;j<16;j++) { + if (nextscale!=0) { + UINT delta=nalu.getSe(); + nextscale=(lastscale+delta+256)%256; + } + lastscale=(nextscale==0)?lastscale:nextscale; + } + } + else + { + UINT lastscale=8; + UINT nextscale=8; + for (int j=0;j<64;j++) { + if (nextscale!=0) { + UINT delta=nalu.getSe(); + nextscale=(lastscale+delta+256)%256; + } + lastscale=(nextscale==0)?lastscale:nextscale; + } + } + } + } + } + } + nalu.getUe(); //log2framenum + UINT temp=nalu.getUe(); + if (temp==0) //pict order + nalu.getUe(); + else if (temp==1) { + nalu.getBits(1); + nalu.getSe(); + nalu.getSe(); + UINT temp2=nalu.getUe(); + for (int i=0;ilog("Demuxer", Log::DEBUG, + "Entering audio sync: Video PTS = %llu", video_pts); + Log::getInstance()->log("Demuxer", Log::DEBUG, + "Entering audio sync: Audio PTS = %llu", audio_pts); + } + return; + } } - } } UINT Demuxer::stripAudio(UCHAR* buf, UINT len) @@ -572,10 +859,11 @@ UINT Demuxer::stripAudio(UCHAR* buf, UINT len) return write_pos; } -bool Demuxer::scanForVideo(UCHAR* buf, UINT len) +bool Demuxer::scanForVideo(UCHAR* buf, UINT len, bool &ish264) { UINT pos = 3; UINT pattern; + ish264=false; if (len < 4) return false; pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]); while (pos < len) diff --git a/demuxer.h b/demuxer.h index 54cd1b3..c0acf85 100644 --- a/demuxer.h +++ b/demuxer.h @@ -60,8 +60,8 @@ class PESPacket ULLONG getPTS() const; bool hasPTS() const { return (getPTS() != PTS_INVALID); } - UINT findPictureHeader() const; - UINT findSeqHeader() const; + UINT findPictureHeader(bool h264) const; + UINT findSeqHeader(bool h264) const; static const ULLONG PTS_INVALID = (1LL << 33); protected: void copyFrom(const PESPacket& packet); @@ -81,7 +81,7 @@ class Demuxer static Demuxer* getInstance(); int init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, DrainTarget* teletext, - ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT, + ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT, double fps=25., DVBSubtitles* tsubtitles=NULL); virtual void reset(); virtual void flush(); @@ -110,6 +110,8 @@ class Demuxer bool* getSubtitleChannels(); int getselAudioChannel(); int getselSubtitleChannel(); + bool ish264() {return h264;} + void seth264(bool newh264){h264=newh264;} int getHorizontalSize() { return horizontal_size; } int getVerticalSize() { return vertical_size; } @@ -132,8 +134,8 @@ class Demuxer // Scan a buffer to see if video packets are present. // Returns true if video exists; false if not. - // *static function* - static bool scanForVideo(UCHAR* buf, UINT len); + // removed *static function* for h264 detection + static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264); enum PESTYPE { @@ -193,6 +195,7 @@ class Demuxer bool initted; bool vid_seeking; bool aud_seeking; + bool h264; int video_current, audio_current, teletext_current, subtitle_current; // Video stream information @@ -201,6 +204,7 @@ class Demuxer int horizontal_size; int vertical_size; + int profile; enum AspectRatio aspect_ratio; int arcnt; int frame_rate; @@ -211,9 +215,14 @@ class Demuxer ULLONG teletext_pts; bool isteletextdecoded; + + unsigned int packetnum; + // Constants static const int FrameRates[9]; + double fps; + bool ispre_1_3_19; bool avail_mpaudchan[PESTYPE_AUDMAX-PESTYPE_AUD0+1]; bool avail_ac3audchan[PESTYPE_SUBSTREAM_AC3MAX-PESTYPE_SUBSTREAM_AC30+1]; diff --git a/demuxeraudio.cc b/demuxeraudio.cc index f3d8bae..2c53b59 100644 --- a/demuxeraudio.cc +++ b/demuxeraudio.cc @@ -39,7 +39,7 @@ class PacketBuffer { newStream(); } //just handle the data (do not deal with headers) - int putInternal(UCHAR* buf,int len); + int putInternal(UCHAR* buf,int len,unsigned int &packetnum); void reset(){ partPacket=0; bytesWritten=0; @@ -111,6 +111,7 @@ DemuxerAudio::DemuxerAudio(int p_vID, int p_aID) buffer=new PacketBuffer(&audiostream,streamtype); // buffer=new PacketBuffer(&teststream,streamtype); globalBytesWritten=0; + packetnum=0; id3=NULL; info=NULL; vbr=NULL; @@ -135,6 +136,7 @@ void DemuxerAudio::reset() { buffer->newStream(); tmpFill=0; readHeaders=0; + packetnum=0; outOfSync=0; globalBytesWritten=0; if (id3) delete id3; @@ -840,7 +842,7 @@ bool PacketBuffer::doSkip() { } // just handle the real stream without dealing with the header -int PacketBuffer::putInternal(UCHAR * wbuf, int len) +int PacketBuffer::putInternal(UCHAR * wbuf, int len,unsigned int &packetnum) { /* Important, the type passed to stream must be a mediapacket type as defined in Draintarget.h and not the device setting of the mvp, so we have to translate it here, @@ -860,7 +862,7 @@ int PacketBuffer::putInternal(UCHAR * wbuf, int len) if (doSkip()) return 0;//NoSkip on Windows #endif //we are still full - so try to write - int sent=audio->put(store+bytesWritten,framelen-bytesWritten,/*streamtype*/mptype); + int sent=audio->put(store+bytesWritten,framelen-bytesWritten,/*streamtype*/mptype,packetnum);packetnum++; //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream (still full) pp=%d, framelen=%d, written=%d",sent,partPacket,framelen, bytesWritten ); if (sent < (framelen - bytesWritten)) { //packet still not written @@ -880,7 +882,7 @@ int PacketBuffer::putInternal(UCHAR * wbuf, int len) #ifndef WIN32 //No Skip on Windows if (doSkip()) return bytesConsumed; #endif - int sent=audio->put(store,framelen,mptype); + int sent=audio->put(store,framelen,mptype,packetnum);packetnum++; bytesWritten+=sent; //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream",sent ); if (bytesWritten < framelen) { @@ -935,7 +937,7 @@ int DemuxerAudio::put(UCHAR* wbuf, int len) while (bytesConsumed < len ) { if (buffer->bufferFull()) { //if this is the first part of the loop, try to write to the stream - if (bytesConsumed == 0) buffer->putInternal(wbuf,0); + if (bytesConsumed == 0) buffer->putInternal(wbuf,0,packetnum); //if the buffer is full, no need to continue if (buffer->bufferFull()) break; } @@ -990,7 +992,7 @@ int DemuxerAudio::put(UCHAR* wbuf, int len) #ifndef WIN32 //hmm - we assume that he low level driver is more intelligent //and give him the data "as is" - int written=buffer->putInternal(wbuf,garbageBytes); + int written=buffer->putInternal(wbuf,garbageBytes,packetnum); globalBytesWritten+=written; bytesConsumed+=written; if (written != garbageBytes || hdr == NULL ) { @@ -1017,7 +1019,7 @@ int DemuxerAudio::put(UCHAR* wbuf, int len) inSync=true; } //now we are surely within a packet - int written=buffer->putInternal(wbuf,len-bytesConsumed); + int written=buffer->putInternal(wbuf,len-bytesConsumed,packetnum); //update the status globalBytesWritten+=written; wbuf+=written; diff --git a/demuxeraudio.h b/demuxeraudio.h index 6a3f985..4bbb868 100644 --- a/demuxeraudio.h +++ b/demuxeraudio.h @@ -168,6 +168,8 @@ class DemuxerAudio : public Demuxer mpegInfo *info; vbrInfo *vbr; + unsigned int packetnum; + }; diff --git a/demuxermedia.cc b/demuxermedia.cc index 777a96c..813d49b 100644 --- a/demuxermedia.cc +++ b/demuxermedia.cc @@ -252,12 +252,12 @@ void DemuxerMedia::parseVDRPacketDetails() packetNumber++; } - if (frameCounting && packet.findPictureHeader() && + if (frameCounting && packet.findPictureHeader(h264) && packet.getPacketType() >= PESTYPE_VID0 && packet.getPacketType() <= PESTYPE_VIDMAX) { ULLONG pts=packet.getPTS(); - if (packet.findSeqHeader() > 1 && pts != PESPacket::PTS_INVALID) + if (packet.findSeqHeader(h264) > 1 && pts != PESPacket::PTS_INVALID) { if (firstPTS == 0) firstPTS=pts; currentPTS=pts; @@ -266,7 +266,7 @@ void DemuxerMedia::parseVDRPacketDetails() } if (packet.getPacketType() >= PESTYPE_VID0 && packet.getPacketType() <= PESTYPE_VIDMAX && - packet.findSeqHeader()) { + packet.findSeqHeader(h264)) { //check video size if (horizontal_size != last_horizontal_size || vertical_size != last_vertical_size) { diff --git a/demuxerts.cc b/demuxerts.cc index e2f8b57..330e7ad 100644 --- a/demuxerts.cc +++ b/demuxerts.cc @@ -385,15 +385,18 @@ int DemuxerTS::processTS(UCHAR* buf) // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID is %x", foundpid); switch (streamtype) { - // case 0x1B: //MPEG 4 for future use + case 0x1B: //MPEG 4 for future use case 1: case 2: { //video if (foundpid != getVID()) setVID(foundpid); new_channelinfo.type=VDR::VIDEO; + new_channelinfo.vstreamtype=streamtype; new_channelinfo.vpid=foundpid; + if (streamtype==0x1b) h264=true; + else h264=false; - // Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid); + // Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid); }break; case 3: case 4: { //audio @@ -643,11 +646,11 @@ ULONG DemuxerTS::getFrameNumFromPTS(ULLONG pts) if (difference == (1LL<<33)) return 0; // We cannot make sense of the pts else - return ref_frame + difference * Video::getInstance()->getFPS() / 90000; + return ref_frame + difference * fps / 90000; } -void DemuxerTS::parseTSPacketDetails(PESPacket packet) // Only important stuff for paket counting reminas +void DemuxerTS::parseTSPacketDetails(PESPacket &packet) // Only important stuff for paket counting reminas { parsePacketDetails(packet); if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 && @@ -656,12 +659,12 @@ void DemuxerTS::parseTSPacketDetails(PESPacket packet) // Only important stuff f packetNumber++; } - if (frameCounting && packet.findPictureHeader() && + if (frameCounting && packet.findPictureHeader(h264) && packet.getPacketType() >= PESTYPE_VID0 && packet.getPacketType() <= PESTYPE_VIDMAX) { ULONG frame_num = (frameNumber)++; - if (packet.findSeqHeader() > 1 && packet.hasPTS()) + if ((h264 || packet.findSeqHeader(h264) > 1) && packet.hasPTS()) { PTSMapEntry me; pts_map_mutex.Lock(); @@ -676,8 +679,8 @@ void DemuxerTS::parseTSPacketDetails(PESPacket packet) // Only important stuff f me = pts_map.front(); pts_map_mutex.Unlock(); - UINT fps = Video::getInstance()->getFPS(); - ULLONG pts_expected = me.pts + 90000*(frame_num - me.frame) / fps; + //UINT fps = Video::getInstance()->getFPS(); + ULLONG pts_expected = me.pts + 90000*((int)(((double)(frame_num - me.frame)) / fps)); while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33); if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump! @@ -693,7 +696,7 @@ void DemuxerTS::parseTSPacketDetails(PESPacket packet) // Only important stuff f } -bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len) +bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len, bool &ish264) { int pmtpidy=0; @@ -718,12 +721,13 @@ bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len) int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12); if ((pmtpid >> 13) != 0x07) { - Log::getInstance()->log("findPTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13)); + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13)); } else { pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits pmtpidy = pmtpid; + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMT pid%02x",pmtpid ); } } else if (pid == pmtpidy) { //PMT @@ -739,24 +743,34 @@ bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len) p += 2; //skip ES length if ((foundpid >> 13) != 0x07) { - Log::getInstance()->log("findPTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13)); + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13)); } else { foundpid = foundpid & 0x1FFF; //clear upper 3 bits // int pos=0; UNUSED? + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Pid found %02x type %02x",foundpid ,streamtype); if (streamtype==1 || streamtype ==2) { + ish264=false; + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found Mpeg2 Video"); return true; } + if (streamtype==0x1b) { + ish264=true; + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found h264 Video"); + return true; + } } p += eslength; //skip es descriptor } + ish264=false; return false; } } len-=TS_SIZE; buf+=TS_SIZE; } + ish264=false; return false; } @@ -804,7 +818,7 @@ UINT DemuxerTS::stripAudio(UCHAR* buf, UINT len) //it has to be adapted memcpy(buf+writepos,destpaket.getData(),destpaket.getSize()); writepos+=destpaket.getSize(); destpaket.truncate(); - destpaket.write((UCHAR*)"\200\000\000", 3); + destpaket.write((UCHAR*)"\200\000\000", 3); destpaket.write(buf+readpos,towrite); } diff --git a/demuxerts.h b/demuxerts.h index b65c29e..4d58840 100644 --- a/demuxerts.h +++ b/demuxerts.h @@ -53,7 +53,7 @@ class DemuxerTS : public Demuxer ULONG getFrameNumFromPTS(ULLONG pts); ULONG getPacketNum(); UINT stripAudio(UCHAR* buf, UINT len); - static bool scanForVideo(UCHAR* buf, UINT len); + static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264); Channel getChannelInfo() {return channelinfo;}; @@ -85,7 +85,7 @@ class DemuxerTS : public Demuxer typedef std::deque PTSMap; PTSMap pts_map; Mutex pts_map_mutex; - void parseTSPacketDetails(PESPacket packet); + void parseTSPacketDetails(PESPacket &packet); }; diff --git a/demuxervdr.cc b/demuxervdr.cc index 3ac8818..abcb921 100644 --- a/demuxervdr.cc +++ b/demuxervdr.cc @@ -294,7 +294,7 @@ ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts) if (difference == (1LL<<33)) return 0; // We cannot make sense of the pts else - return ref_frame + difference * Video::getInstance()->getFPS() / 90000; + return ref_frame + (ULONG)((double) (difference / 90000) *fps); } void DemuxerVDR::dealWithSubtitlePacket() @@ -366,12 +366,12 @@ void DemuxerVDR::parseVDRPacketDetails() packetNumber++; } - if (frameCounting && packet.findPictureHeader() && + if (frameCounting && packet.findPictureHeader(h264) && packet.getPacketType() >= PESTYPE_VID0 && packet.getPacketType() <= PESTYPE_VIDMAX) { ULONG frame_num = (frameNumber)++; - if (packet.findSeqHeader() > 1 && packet.hasPTS()) + if (packet.findSeqHeader(h264) > 1 && packet.hasPTS()) { PTSMapEntry me; pts_map_mutex.Lock(); @@ -387,8 +387,8 @@ Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me = pts_map.front(); pts_map_mutex.Unlock(); - UINT fps = Video::getInstance()->getFPS(); - ULLONG pts_expected = me.pts + 90000*(frame_num - me.frame) / fps; +// UINT fps = Video::getInstance()->getFPS(); + ULLONG pts_expected = me.pts + 90000*((ULONG)((double)(frame_num - me.frame)) / fps); while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33); if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump! diff --git a/draintarget.h b/draintarget.h index 4c73612..e40bcd0 100644 --- a/draintarget.h +++ b/draintarget.h @@ -24,12 +24,15 @@ #include "defines.h" #include -#define MPTYPE_VIDEO 0x00 +#define MPTYPE_VIDEO_MPEG2 0x00 #define MPTYPE_MPEG_AUDIO 0x01 #define MPTYPE_AC3 0x02 #define MPTYPE_AC3_PRE13 0x03 //old vdr recording compatmode #define MPTYPE_MPEG_AUDIO_LAYER3 0x04 //for media mp3 playback #define MPTYPE_TELETEXT 0x05 //for EBU VBI teletext +#define MPTYPE_VIDEO_H264 0x06 + + struct MediaPacket { @@ -38,9 +41,10 @@ struct MediaPacket // The fields below are not needed by the MVP UCHAR type; ULLONG pts; + ULLONG dts; bool synched; + int index; #ifdef WIN32 - ULLONG recording_byte_pos; //position in recording long long presentation_time;/* in 100 ns units*/ bool disconti; #endif @@ -91,7 +95,9 @@ class DrainTarget // (inclusive) from the list before the next call. // DeliverMediaSample must also set *samplepos equal to the number of bytes // processed from packet X (usually zero). - virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos)=0; + // It is allowed, that the draintarget modifies the part of the buffer, which belongs + // to the mediapackets it is processing. + virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos)=0; }; #endif diff --git a/dsallocator.cc b/dsallocator.cc index ae2760d..f405730 100644 --- a/dsallocator.cc +++ b/dsallocator.cc @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon + Copyright 2004-2005 Chris Tallon, Marten Richter This file is part of VOMP. @@ -17,123 +17,847 @@ along with VOMP; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define INITGUID + #include "osdwin.h" #include "dsallocator.h" +#include + +#include +#include +#include + +typedef HRESULT (__stdcall *FCT_MFCreateVideoSampleFromSurface)(IUnknown* pUnkSurface, IMFSample** ppSample); + +extern FCT_MFCreateVideoSampleFromSurface ptrMFCreateVideoSampleFromSurface; + DsAllocator::DsAllocator() { - surfallocnotify=NULL; - refcount=1; - + surfallocnotify=NULL; + refcount=1; + inevrmode=false; + mftransform=NULL; + mediasink=NULL; + mfclock=NULL; + mfmediatype=NULL; + endofstream=false; + ResetSyncOffsets(); + } DsAllocator::~DsAllocator() { - CleanupSurfaces(); + ((OsdWin*)Osd::getInstance())->setExternalDriving(NULL,vwidth,vheight); + ((OsdWin*)Osd::getInstance())->SetEVRStatus(OsdWin::EVR_pres_off); + CleanupSurfaces(); } void DsAllocator::CleanupSurfaces() { - for (int i=0;iRelease(); - surfaces[i]=NULL; - } + Lock(); + while(fullevrsamples.size()>0) + { + IMFSample *sample=fullevrsamples.front(); + fullevrsamples.pop(); + sample->Release(); + } + while(emptyevrsamples.size()>0) + { + IMFSample *sample=emptyevrsamples.front(); + emptyevrsamples.pop(); + sample->Release(); + } + + for (int i=0;iRelease(); + surfaces[i]=NULL; + } + Unlock(); } HRESULT STDMETHODCALLTYPE DsAllocator::InitializeDevice(DWORD_PTR userid,VMR9AllocationInfo* allocinf,DWORD*numbuf){ - if (!surfallocnotify) return S_FALSE; - Lock(); - CleanupSurfaces(); + if (!surfallocnotify) return S_FALSE; - surfaces.resize(*numbuf); - HRESULT hres= surfallocnotify->AllocateSurfaceHelper(allocinf,numbuf,&surfaces.at(0)); - Unlock(); - return hres; + CleanupSurfaces(); + Lock(); + surfaces.resize(*numbuf); + HRESULT hres= surfallocnotify->AllocateSurfaceHelper(allocinf,numbuf,&surfaces.at(0)); + vheight=allocinf->dwHeight; + vwidth=allocinf->dwWidth; + Unlock(); + /* char buffer[1024]; + sprintf(buffer,"%d * %d",allocinf->dwWidth,allocinf->dwHeight); + MessageBox(0,"hi",buffer,0);*/ + return hres; } void DsAllocator::LostDevice(IDirect3DDevice9 *d3ddev, IDirect3D9* d3d) { - if (!surfallocnotify) return ; - Lock(); - CleanupSurfaces(); -// d3ddev=((OsdWin*)Osd::getInstance())->getD3dDev(); - HMONITOR hmon=d3d->GetAdapterMonitor(D3DADAPTER_DEFAULT); - surfallocnotify->ChangeD3DDevice(d3ddev,hmon); - Unlock(); + if (!surfallocnotify) return ; + CleanupSurfaces(); + Lock(); + // d3ddev=((OsdWin*)Osd::getInstance())->getD3dDev(); + HMONITOR hmon=d3d->GetAdapterMonitor(D3DADAPTER_DEFAULT); + surfallocnotify->ChangeD3DDevice(d3ddev,hmon); + Unlock(); } HRESULT STDMETHODCALLTYPE DsAllocator::TerminateDevice(DWORD_PTR userid){ - Lock(); - CleanupSurfaces(); - Unlock(); - return S_OK; //Do nothing + CleanupSurfaces(); + + return S_OK; //Do nothing } HRESULT STDMETHODCALLTYPE DsAllocator::GetSurface(DWORD_PTR userid,DWORD surfindex,DWORD surfflags, IDirect3DSurface9** surf) { - if (surfindex>=surfaces.size()) return E_FAIL; - if (surf==NULL) return E_POINTER; + if (surfindex>=surfaces.size()) return E_FAIL; + if (surf==NULL) return E_POINTER; - Lock(); - surfaces[surfindex]->AddRef(); - *surf=surfaces[surfindex]; - Unlock(); - return S_OK; + Lock(); + surfaces[surfindex]->AddRef(); + *surf=surfaces[surfindex]; + Unlock(); + return S_OK; } HRESULT STDMETHODCALLTYPE DsAllocator::AdviseNotify(IVMRSurfaceAllocatorNotify9* allnoty){ - Lock(); - surfallocnotify=allnoty; - IDirect3DDevice9 *d3ddev; - //OK lets set the direct3d object from the osd - d3ddev=((OsdWin*)Osd::getInstance())->getD3dDev(); - HMONITOR hmon=((OsdWin*)Osd::getInstance())->getD3d()->GetAdapterMonitor(D3DADAPTER_DEFAULT); - HRESULT hres=surfallocnotify->SetD3DDevice(d3ddev,hmon); - Unlock(); - return hres; + Lock(); + surfallocnotify=allnoty; + IDirect3DDevice9 *d3ddev; + //OK lets set the direct3d object from the osd + d3ddev=((OsdWin*)Osd::getInstance())->getD3dDev(); + HMONITOR hmon=((OsdWin*)Osd::getInstance())->getD3d()->GetAdapterMonitor(D3DADAPTER_DEFAULT); + HRESULT hres=surfallocnotify->SetD3DDevice(d3ddev,hmon); + Unlock(); + return hres; } HRESULT STDMETHODCALLTYPE DsAllocator::StartPresenting(DWORD_PTR userid){ - ((OsdWin*)Osd::getInstance())->setExternalDriving(this); - return S_OK; + //MessageBox(0,"drive me","drive me",0); + ((OsdWin*)Osd::getInstance())->setExternalDriving(this,vwidth,vheight); + return S_OK; } + HRESULT STDMETHODCALLTYPE DsAllocator::StopPresenting(DWORD_PTR userid){ - ((OsdWin*)Osd::getInstance())->setExternalDriving(NULL); - return S_OK; + ((OsdWin*)Osd::getInstance())->setExternalDriving(NULL,0,0); + return S_OK; } HRESULT STDMETHODCALLTYPE DsAllocator::PresentImage(DWORD_PTR userid,VMR9PresentationInfo* presinf){ - ((OsdWin*)Osd::getInstance())->RenderDS(presinf->lpSurf); //render and return - return S_OK; + ((OsdWin*)Osd::getInstance())->RenderDS(presinf->lpSurf); //render and return + return S_OK; } HRESULT STDMETHODCALLTYPE DsAllocator::QueryInterface(REFIID refiid,void ** obj){ - if (obj==NULL) return E_POINTER; + if (obj==NULL) return E_POINTER; - if (refiid==IID_IVMRSurfaceAllocator9) { - *obj=static_cast(this); - AddRef(); - return S_OK; - } else if (refiid==IID_IVMRImagePresenter9) { - *obj=static_cast(this); - AddRef(); - return S_OK; - } - return E_NOINTERFACE; + if (refiid==IID_IVMRSurfaceAllocator9) { + *obj=static_cast(this); + AddRef(); + return S_OK; + } else if (refiid==IID_IVMRImagePresenter9) { + *obj=static_cast(this); + AddRef(); + return S_OK; + } else if (refiid==IID_IMFVideoDeviceID) { + *obj=static_cast (this); + AddRef(); + return S_OK; + } else if (refiid==IID_IMFTopologyServiceLookupClient ) { + *obj=static_cast (this); + AddRef(); + return S_OK; + } else if (refiid==IID_IQualProp ) { + *obj=static_cast (this); + AddRef(); + return S_OK; + } else if (refiid==IID_IMFGetService) { + *obj=static_cast (this); + AddRef(); + return S_OK; + } else if (refiid==IID_IDirect3DDeviceManager9) { + IDirect3DDeviceManager9 *d3dman=((OsdWin*)Osd::getInstance())->getD3dMan(); + if (d3dman){ + return d3dman->QueryInterface(refiid,obj); + } + else + { + return E_NOINTERFACE; + } + } + return E_NOINTERFACE; } + + ULONG STDMETHODCALLTYPE DsAllocator::AddRef(){ - return InterlockedIncrement(&refcount); + return InterlockedIncrement(&refcount); } ULONG STDMETHODCALLTYPE DsAllocator::Release(){ - ULONG ref=0; - ref=InterlockedDecrement(&refcount); - if (ref==NULL) { - delete this; //Commit suicide - } - return ref; + ULONG ref=0; + ref=InterlockedDecrement(&refcount); + if (ref==NULL) { + delete this; //Commit suicide + } + return ref; +} + +HRESULT STDMETHODCALLTYPE DsAllocator::GetDeviceID(IID *pDid) +{ + if (pDid==NULL) + return E_POINTER; + + *pDid=__uuidof(IDirect3DDevice9); + return S_OK; } +HRESULT STDMETHODCALLTYPE DsAllocator::InitServicePointers(IMFTopologyServiceLookup *plooky) +{ + if (!plooky) return E_POINTER; + Lock(); + inevrmode=true; + /* get all interfaces we need*/ + + DWORD dwobjcts=1; + plooky->LookupService(MF_SERVICE_LOOKUP_GLOBAL,0,MR_VIDEO_MIXER_SERVICE, + __uuidof(IMFTransform),(void**)&mftransform, &dwobjcts); + plooky->LookupService(MF_SERVICE_LOOKUP_GLOBAL,0,MR_VIDEO_RENDER_SERVICE, + __uuidof(IMediaEventSink),(void**)&mediasink, &dwobjcts); + plooky->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, + __uuidof(IMFClock),(void**)&mfclock,&dwobjcts); + + + Unlock(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DsAllocator::ReleaseServicePointers() +{ + Lock(); + inevrmode=false; + /* TODO Set RenderState , sample type etc.*/ + + ((OsdWin*)Osd::getInstance())->setExternalDriving(NULL,0,0); + + if (mftransform) mftransform->Release(); + mftransform=NULL; + + if (mediasink) mediasink->Release(); + mediasink=NULL; + + if (mfclock) mfclock->Release(); + mfclock=NULL; + if (mfmediatype) mfmediatype->Release(); + mfmediatype=NULL; + + Unlock(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DsAllocator::GetService(const GUID &guid,const IID &iid,LPVOID *obj) +{ + if (guid==MR_VIDEO_ACCELERATION_SERVICE) + { + IDirect3DDeviceManager9 *d3dman=((OsdWin*)Osd::getInstance())->getD3dMan(); + if (d3dman) + { + return d3dman->QueryInterface (__uuidof(IDirect3DDeviceManager9), (void**) obj); + } + else + { + return E_NOINTERFACE; + } + + } + else if (guid==MR_VIDEO_RENDER_SERVICE) + { + return QueryInterface(iid,obj); + } + else + { + return E_NOINTERFACE; + } +} + + +void DsAllocator::GetEVRSamples() +{ + MFCLOCK_STATE clockstate; + if (mfclock) mfclock->GetState(0,&clockstate); + //MessageBox(0,"get samples","samples",0); + Lock(); + if (mfclock && clockstate==MFCLOCK_STATE_STOPPED && fullevrsamples.size()>0) + { + Unlock(); + return; + } + + while (emptyevrsamples.size()>0) + { + + MFT_OUTPUT_DATA_BUFFER outdatabuffer; + ZeroMemory(&outdatabuffer,sizeof(outdatabuffer)); + outdatabuffer.pSample=emptyevrsamples.front(); + DWORD status=0; + LONGLONG starttime,endtime; + MFTIME dummy; + starttime=0; + endtime=0; + + if (mfclock) + { + mfclock->GetCorrelatedTime(0,&starttime,&dummy); + if (lastdelframe) CalcJitter( (starttime-lastdelframe)/10000); + lastdelframe=starttime; + } + + HRESULT hres=mftransform->ProcessOutput(0,1,&outdatabuffer,&status); + + + if (hres==MF_E_TRANSFORM_NEED_MORE_INPUT) + { + if (endofstream) + { + + endofstream=false; + mediasink->Notify(EC_COMPLETE,(LONG_PTR) S_OK,0); + + } + break; + } + else if (hres==MF_E_TRANSFORM_STREAM_CHANGE) + { + if (mfmediatype) mfmediatype->Release(); + mfmediatype=NULL; + break; + } + else if (hres==MF_E_TRANSFORM_TYPE_NOT_SET) + { + if (mfmediatype) mfmediatype->Release(); + mfmediatype=NULL; + RenegotiateEVRMediaType(); + break; + } + else if (hres==S_OK) + { + LONGLONG prestime=0; + hres=outdatabuffer.pSample->GetSampleTime(&prestime); + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "Got EVR Sample %lld",prestime); + IMFSample *temp=emptyevrsamples.front(); + emptyevrsamples.pop(); + + + + fullevrsamples.push(temp); + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "got evr sample %d, %d", + // emptyevrsamples.size(),fullevrsamples.size()); + if (mfclock){ + mfclock->GetCorrelatedTime(0,&endtime,&dummy); + LONGLONG delay=endtime-starttime; + mediasink->Notify( EC_PROCESSING_LATENCY,(LONG_PTR)&delay,0); + } + } else break; + + } + Unlock(); +} + +HRESULT STDMETHODCALLTYPE DsAllocator::ProcessMessage(MFVP_MESSAGE_TYPE mess,ULONG_PTR mess_para) +{ + switch (mess) { + case MFVP_MESSAGE_FLUSH:{ + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "EVR Message MFVP_MESSAGE_FLUSH received"); + FlushEVRSamples(); }break; + case MFVP_MESSAGE_INVALIDATEMEDIATYPE: { + Log::getInstance()->log("DsAllocator", Log::DEBUG , "EVR Message MFVP_MESSAGE_INVALIDATEMEDIATYPE received"); + if (mfmediatype) mfmediatype->Release(); + mfmediatype=NULL; + RenegotiateEVRMediaType();}break; + case MFVP_MESSAGE_PROCESSINPUTNOTIFY: { + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "EVR Message MFVP_MESSAGE_PROCESSINPUTNOTIFY received"); + GetEVRSamples(); } break; + case MFVP_MESSAGE_BEGINSTREAMING:{ + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "EVR Message MFVP_MESSAGE_BEGINSTREAMING received"); + ResetSyncOffsets(); + ((OsdWin*)Osd::getInstance())->setExternalDriving(this,vwidth,vheight); + ((OsdWin*)Osd::getInstance())->SetEVRStatus(OsdWin::EVR_pres_started); + endofstream=false; + }break; + case MFVP_MESSAGE_ENDSTREAMING: { + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "EVR Message MFVP_MESSAGE_ENDSTREAMING received"); + ((OsdWin*)Osd::getInstance())->SetEVRStatus(OsdWin::EVR_pres_off); + ((OsdWin*)Osd::getInstance())->setExternalDriving(NULL,vwidth,vheight); + //FlushEVRSamples(); + //if (mfmediatype) mfmediatype->Release(); + //mfmediatype=NULL; + } break; + case MFVP_MESSAGE_ENDOFSTREAM: { + Log::getInstance()->log("DsAllocator", Log::DEBUG , "EVR Message MFVP_MESSAGE_ENDOFSTREAM received"); + MessageBox(0,"endofstream","endofstream",0); + endofstream=true; + } break; + case MFVP_MESSAGE_STEP: { + Log::getInstance()->log("DsAllocator", Log::DEBUG , "EVR Message MFVP_MESSAGE_STEP received"); + ((OsdWin*)Osd::getInstance())->setExternalDriving(this,vwidth,vheight); + ((OsdWin*)Osd::getInstance())->SetEVRStatus(OsdWin::EVR_pres_pause); + MessageBox(0,"steppy","steppy",0); + FlushEVRSamples(/*LOWORD(mess_para)*/); //Message sending, has to be done after compeletion + }; break; + case MFVP_MESSAGE_CANCELSTEP: { + Log::getInstance()->log("DsAllocator", Log::DEBUG , "EVR Message MFVP_MESSAGE_CANCELSTEP received"); + //??? + }; break; + default: + MessageBox(0,"unhandled","unhandled",0); + }; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DsAllocator::OnClockStart(MFTIME systime,LONGLONG startoffset) +{ + //((OsdWin*)Osd::getInstance())->SetEVRTimes(systime,startoffset); + timeBeginPeriod(1); + + if (PRESENTATION_CURRENT_POSITION!=startoffset) FlushEVRSamples(); + ((OsdWin*)Osd::getInstance())->setExternalDriving(this,vwidth,vheight); + ((OsdWin*)Osd::getInstance())->SetEVRStatus(OsdWin::EVR_pres_started); + GetEVRSamples(); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DsAllocator::OnClockStop(MFTIME systime) +{ + timeEndPeriod(1); + + ((OsdWin*)Osd::getInstance())->SetEVRStatus(OsdWin::EVR_pres_off); + ((OsdWin*)Osd::getInstance())->setExternalDriving(NULL,vwidth,vheight); + FlushEVRSamples(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DsAllocator::OnClockPause(MFTIME systime) +{ + timeEndPeriod(1); + ((OsdWin*)Osd::getInstance())->setExternalDriving(this,vwidth,vheight); + ((OsdWin*)Osd::getInstance())->SetEVRStatus(OsdWin::EVR_pres_pause); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DsAllocator::OnClockRestart(MFTIME systime) +{ + ((OsdWin*)Osd::getInstance())->setExternalDriving(this,vwidth,vheight); + ((OsdWin*)Osd::getInstance())->SetEVRStatus(OsdWin::EVR_pres_started); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DsAllocator::OnClockSetRate(MFTIME systime,float rate) +{ + timeBeginPeriod(1); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DsAllocator::GetCurrentMediaType(IMFVideoMediaType **mtype) +{ MessageBox(0,"mediatype","mediatype",0); +if (mtype==NULL) return E_POINTER; +Lock(); +if (mfmediatype==NULL) +{ + Unlock(); + *mtype=NULL; + return MF_E_NOT_INITIALIZED; +} +HRESULT hres=mfmediatype->QueryInterface(IID_IMFVideoMediaType,(void**)mtype); +Unlock(); +return hres; +} + +void DsAllocator::RenegotiateEVRMediaType() +{ + if (!mftransform) { + Log::getInstance()->log("DsAllocator", Log::DEBUG , "Cannot renegotiate without transform!"); + return ; + } + bool gotcha=false; + DWORD index=0; + + while (!gotcha) { + IMFMediaType *mixtype=NULL; + HRESULT hres; + if (hres=mftransform->GetOutputAvailableType(0,index++,&mixtype)!=S_OK) + { + Log::getInstance()->log("DsAllocator", Log::DEBUG , "No more types availiable from EVR %d !",hres); + break; + } + + //Type check + BOOL compressed; + mixtype->IsCompressedFormat(&compressed); + if (compressed) + { + mixtype->Release(); + continue; + } + UINT32 helper; + mixtype->GetUINT32(MF_MT_INTERLACE_MODE,&helper); + if (helper!=MFVideoInterlace_Progressive) { + Log::getInstance()->log("DsAllocator", Log::DEBUG , "Skip media type interlaced!"); + mixtype->Release(); + continue; + } + GUID temp; + mixtype->GetMajorType(&temp); + if (temp!=MEDIATYPE_Video) { + Log::getInstance()->log("DsAllocator", Log::DEBUG , "Skip media type no video!"); + mixtype->Release(); + continue; + } + if(mftransform->SetOutputType(0,mixtype,MFT_SET_TYPE_TEST_ONLY)!=S_OK) + { + Log::getInstance()->log("DsAllocator", Log::DEBUG , "Skip media type test failed!"); + mixtype->Release(); + continue; + } + //Type is ok! + + gotcha=true; + + Lock(); + if (mfmediatype) mfmediatype->Release(); + mfmediatype=NULL; + + mfmediatype=mixtype; + AllocateEVRSurfaces(); + Unlock(); + + hres=mftransform->SetOutputType(0,mixtype,0); + + + + if (hres!=S_OK) + { + Lock(); + if (mfmediatype) mfmediatype->Release(); + mfmediatype=NULL; + gotcha=false; + + Unlock(); + } + + + Log::getInstance()->log("DsAllocator", Log::DEBUG , "Output type set! %d",hres); + } + if (!gotcha) Log::getInstance()->log("DsAllocator", Log::DEBUG , "No suitable output type!"); + + + +} + +void DsAllocator::AllocateEVRSurfaces() +{ + + LARGE_INTEGER temp64; + mfmediatype->GetUINT64(MF_MT_FRAME_SIZE, (UINT64*)&temp64); + vwidth=temp64.HighPart; + vheight=temp64.LowPart; + GUID subtype; + subtype.Data1=D3DFMT_X8R8G8B8; + mfmediatype->GetGUID(MF_MT_SUBTYPE,&subtype); + D3DFORMAT format=(D3DFORMAT)subtype.Data1; + Log::getInstance()->log("DsAllocator", Log::DEBUG , "Surfaceformat is %d, width %d, height %d",format,vwidth,vheight); + format=D3DFMT_X8R8G8B8; + + CleanupSurfaces(); + Lock(); + OsdWin* osdwin=(OsdWin*)Osd::getInstance(); + LPDIRECT3DDEVICE9 d3ddev=osdwin->getD3dDev(); + osdwin->BeginPainting(); + surfaces.resize(10); + for (int i=0;i<10;i++) + { + HRESULT hres; + LPDIRECT3DSURFACE9 surfy; + + hres=d3ddev->CreateRenderTarget(vwidth,vheight,format, + D3DMULTISAMPLE_NONE,0,FALSE,&surfy,NULL); + if (hres==S_OK) + { + surfaces[i]=surfy; + } + else + { + surfaces[i]=NULL; + } + } + osdwin->EndPainting(); + + + + for (int i=0;i0) + { + IMFSample *sample=fullevrsamples.front(); + fullevrsamples.pop(); + emptyevrsamples.push(sample); + } + Unlock(); +} +#define FAC 1 + +void DsAllocator::GetNextSurface(LPDIRECT3DSURFACE9* surf,DWORD *waittime) +{ + + *surf=NULL; + *waittime=10; + if (fullevrsamples.size()==0) GetEVRSamples(); + Lock(); + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "Enter Get Next Surface"); + + while (fullevrsamples.size()>0) + { + //MessageBox(0,"Got a sample","got a sample",0); + IMFSample *sample=fullevrsamples.front(); + LONGLONG prestime=0; + MFTIME systime=0; + LONGLONG currenttime=0; + + HRESULT hres=sample->GetSampleTime(&prestime); + if (hres==S_OK) + { + if (mfclock) mfclock->GetCorrelatedTime(0,¤ttime,&systime); + } + LONGLONG delta=prestime-currenttime; + + + + if (delta<-10000*20 && false) { //SkipIT + LONGLONG latency=-delta; + //mediasink->Notify(EC_SAMPLE_LATENCY,(LONG_PTR) &latency,0); + LARGE_INTEGER helper; + helper.QuadPart=-delta; + Log::getInstance()->log("DsAllocator", Log::DEBUG , "skip 1 frame %d %d prestime %lld",helper.LowPart,helper.HighPart,prestime); + CalcSyncOffsets(delta/10000LL); + // emptyevrsamples.size(),fullevrsamples.size()); + fullevrsamples.pop(); + emptyevrsamples.push(sample); + framesdropped++; + continue; + } + + if (delta<10000*20 || !mfclock ) + { + *waittime=0; + IMFMediaBuffer* buffy=NULL; + //MessageBox(0,"its showtime","showtimw",0); + CalcSyncOffsets(delta/10000LL); + framesdrawn++; + hres=sample->GetBufferByIndex(0,&buffy); + //LARGE_INTEGER helper; + //helper.QuadPart=-delta; + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "Paint 1 frame %d %d, frames %d prestime %lld", + // helper.LowPart,helper.HighPart,fullevrsamples.size(),prestime); + if (hres!=S_OK) { //SkipIT + fullevrsamples.pop(); + emptyevrsamples.push(sample); + continue; + } + IMFGetService* service; + hres=buffy->QueryInterface(IID_IMFGetService,(void**)&service); + buffy->Release(); + if (hres!=S_OK) { //SkipIT + fullevrsamples.pop(); + emptyevrsamples.push(sample); + continue; + } + LPDIRECT3DSURFACE9 tempsurf; + hres=service->GetService(MR_BUFFER_SERVICE,IID_IDirect3DSurface9 ,(void**) &tempsurf); + service->Release(); + if (hres!=S_OK) { //SkipIT + fullevrsamples.pop(); + emptyevrsamples.push(sample); + continue; + } + *surf=tempsurf; + break; + } else { + *waittime=delta/10000-10; + *surf=NULL; + break; + } + } + + Unlock(); + +} + +void DsAllocator::DiscardSurfaceandgetWait(DWORD *waittime) +{ + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "Discard surface and get Wait"); + GetEVRSamples(); + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "Discard surface and get Wait2"); + Lock(); + if (fullevrsamples.size()==0) { + *waittime=0; + Unlock(); + return; + } + IMFSample *sample=fullevrsamples.front(); + fullevrsamples.pop(); + emptyevrsamples.push(sample); + *waittime=0; + + while (fullevrsamples.size()>0) + { + + IMFSample *sample=fullevrsamples.front(); + LONGLONG prestime=0; + MFTIME systime=0; + LONGLONG currenttime=0; + + HRESULT hres=sample->GetSampleTime(&prestime); + if (hres==S_OK) + { + mfclock->GetCorrelatedTime(0,¤ttime,&systime); + } + LONGLONG delta=prestime-currenttime; + + + if (delta<-10000*20 ) { //SkipIT + LONGLONG latency=-delta; + // mediasink->Notify(EC_SAMPLE_LATENCY,(LONG_PTR) &latency,0); + //LARGE_INTEGER helper; + //helper.QuadPart=-delta; + //Log::getInstance()->log("DsAllocator", Log::DEBUG , "skip 1 frame %d %d time %lld",helper.LowPart,helper.HighPart,prestime); + CalcSyncOffsets(delta/10000LL); + // emptyevrsamples.size(),fullevrsamples.size()); + fullevrsamples.pop(); + emptyevrsamples.push(sample); + framesdropped++; + continue; + } + + *waittime=min(delta/10000/2-10,1); + + break; + } + Unlock(); + +} +void DsAllocator::ResetSyncOffsets() +{ + for (int i=0;i #include + + using namespace std; + #include #include #include #include +#include #include "mutex.h" +//The Allocator and Presenter for VMR9 is also a Presnter for EVR - -class DsAllocator: public IVMRSurfaceAllocator9, IVMRImagePresenter9,Mutex { +class DsAllocator: public IVMRSurfaceAllocator9, IVMRImagePresenter9, Mutex,IMFVideoDeviceID, + IMFTopologyServiceLookupClient,public IMFVideoPresenter,IMFGetService, IQualProp { public: DsAllocator(); virtual ~DsAllocator(); @@ -54,14 +60,74 @@ public: void LostDevice(IDirect3DDevice9 *d3ddev, IDirect3D9* d3d); + /* EVR members */ + virtual HRESULT STDMETHODCALLTYPE GetDeviceID(IID *pDid); + + virtual HRESULT STDMETHODCALLTYPE InitServicePointers(IMFTopologyServiceLookup *plooky); + virtual HRESULT STDMETHODCALLTYPE ReleaseServicePointers(); + + virtual HRESULT STDMETHODCALLTYPE ProcessMessage(MFVP_MESSAGE_TYPE mess,ULONG_PTR mess_para); + + virtual HRESULT STDMETHODCALLTYPE OnClockStart(MFTIME systime,LONGLONG startoffset); + virtual HRESULT STDMETHODCALLTYPE OnClockStop(MFTIME systime); + virtual HRESULT STDMETHODCALLTYPE OnClockPause(MFTIME systime); + virtual HRESULT STDMETHODCALLTYPE OnClockRestart(MFTIME systime); + virtual HRESULT STDMETHODCALLTYPE OnClockSetRate(MFTIME systime,float rate); + virtual HRESULT STDMETHODCALLTYPE GetCurrentMediaType(IMFVideoMediaType **mtype); + + virtual HRESULT STDMETHODCALLTYPE GetService(const GUID &guid,const IID &iid,LPVOID *obj); + + virtual HRESULT STDMETHODCALLTYPE get_FramesDrawn(int *val); + virtual HRESULT STDMETHODCALLTYPE get_AvgFrameRate(int *val); + virtual HRESULT STDMETHODCALLTYPE get_Jitter(int *val); + virtual HRESULT STDMETHODCALLTYPE get_AvgSyncOffset(int *val); + virtual HRESULT STDMETHODCALLTYPE get_DevSyncOffset(int *val); + virtual HRESULT STDMETHODCALLTYPE get_FramesDroppedInRenderer(int *val); + + void GetNextSurface(LPDIRECT3DSURFACE9 *surf,DWORD *waittime); + void DiscardSurfaceandgetWait(DWORD *waittime); + + protected: + + void RenegotiateEVRMediaType(); + void AllocateEVRSurfaces(); + void FlushEVRSamples(); + void GetEVRSamples(); + + void ResetSyncOffsets(); + void CalcSyncOffsets(int sync); + void CalcJitter(int jitter); - vector surfaces; + vector surfaces; + queue emptyevrsamples; + queue fullevrsamples; //CCritSec objCritSec; IVMRSurfaceAllocatorNotify9* surfallocnotify; void CleanupSurfaces(); LONG refcount; - + DWORD vheight; + DWORD vwidth; + bool inevrmode; + bool endofstream; + + IMFTransform* mftransform; + IMediaEventSink* mediasink; + IMFClock* mfclock; + IMFMediaType *mfmediatype; + + static const int n_stats=126; + int sync_offset[n_stats]; + int jitter_offset[n_stats]; + unsigned int sync_pos; + unsigned int jitter_pos; + int framesdrawn; + int framesdropped; + int avg_sync_offset; + int dev_sync_offset; + int jitter; + int avgfps; + LONGLONG lastdelframe; }; @@ -71,4 +137,5 @@ protected: + #endif diff --git a/dssourcefilter.cc b/dssourcefilter.cc index 543e59c..6e94b69 100644 --- a/dssourcefilter.cc +++ b/dssourcefilter.cc @@ -454,4 +454,16 @@ bool DsSourceFilter::changeAType(int type,IMediaSample* ms) return true; } +bool DsSourceFilter::changeVType(int type,IMediaSample* ms,void * details) +{ + if (!videopin ) { + return false; + } + videopin->SetPinMode(type,details); + videopin->SetMsToMt(ms); + + + return true; +} + diff --git a/dssourcefilter.h b/dssourcefilter.h index ad1ef0e..ab34c9d 100644 --- a/dssourcefilter.h +++ b/dssourcefilter.h @@ -25,6 +25,10 @@ #include "mutex.h" #include "dssourcepin.h" +struct mptype_video_detail{ //here should be all information added the Video Draintarget needs for rendering, to be extended in the future + UINT width; + UINT height; +}; [uuid("EB87AB22-7A95-49c3-8CCE-2F6D61A87009")] class DsSourceFilter: public IBaseFilter { @@ -68,6 +72,7 @@ public: bool supportsAc3(); bool changeAType(int type,IMediaSample* ms); + bool changeVType(int type,IMediaSample* ms, void *details); protected: diff --git a/dssourcepin.cc b/dssourcepin.cc index d5aa13a..d9f665d 100644 --- a/dssourcepin.cc +++ b/dssourcepin.cc @@ -135,6 +135,8 @@ void CopyMType(AM_MEDIA_TYPE* dest,const AM_MEDIA_TYPE*source) { if (source->pbFormat!=NULL) { dest->pbFormat=(BYTE*)CoTaskMemAlloc(dest->cbFormat); memcpy(dest->pbFormat,source->pbFormat,dest->cbFormat); + } else { + dest->pbFormat=NULL; } } void ReleaseMType(AM_MEDIA_TYPE* free) { @@ -151,6 +153,10 @@ DsSourcePin::DsSourcePin(DsSourceFilter *pFilter, connected=NULL; connectedinput=NULL; allocator=NULL; + + v_width=640; + v_height=480; + if (isaudiopin) { pinmode=MPTYPE_MPEG_AUDIO; @@ -158,7 +164,8 @@ DsSourcePin::DsSourcePin(DsSourceFilter *pFilter, } else { - pinmode=MPTYPE_VIDEO; + + pinmode=MPTYPE_VIDEO_MPEG2; } } @@ -428,7 +435,9 @@ HRESULT STDMETHODCALLTYPE DsSourcePin::NewSegment(REFERENCE_TIME start,REFERENCE } HRESULT DsSourcePin::getCurrentMediaSample(IMediaSample**ms){ - if (allocator!=NULL) return allocator->GetBuffer(ms,NULL,NULL,0); + if (allocator!=NULL) { + return allocator->GetBuffer(ms,NULL,NULL,0); + } else return E_NOINTERFACE; } @@ -749,11 +758,47 @@ HRESULT DsSourcePin::GetMediaTypeMpegVideo(int iPosition, AM_MEDIA_TYPE *pmt) 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; + hdr.hdr.bmiHeader.biWidth = v_width; + hdr.hdr.bmiHeader.biHeight = v_height; /* Vista compat*/ - hdr.hdr.dwPictAspectRatioX=1; - hdr.hdr.dwPictAspectRatioY=1; + hdr.hdr.dwPictAspectRatioX=1;//v_sar_width; + hdr.hdr.dwPictAspectRatioY=1;//v_sar_height; + /* Vista compat*/ + pmt->cbFormat = sizeof(hdr); + pmt->pbFormat = (BYTE*)CoTaskMemAlloc(sizeof(hdr)); + memcpy(pmt->pbFormat,&hdr,sizeof(hdr)); + } else { + hr=VFW_S_NO_MORE_ITEMS; + } + + return hr; +} + +HRESULT DsSourcePin::GetMediaTypeH264Video(int iPosition, AM_MEDIA_TYPE *pmt) +{ + HRESULT hr; + if (iPosition == 0) + { + ZeroMemory(pmt,sizeof(*pmt)); + pmt->lSampleSize = 1; + pmt->bFixedSizeSamples = TRUE; + pmt->majortype = MEDIATYPE_Video; + hr = S_OK; + pmt->subtype =MEDIASUBTYPE_H264;// MAKEFOURCC('H','2','6','4'); + pmt->formattype = FORMAT_VideoInfo2 ; + + + VIDEOINFOHEADER2 hdr; + ZeroMemory(&hdr,sizeof(hdr)); + //hdr.dwProfile = AM_MPEG2Profile_Main; + //hdr.dwLevel = AM_MPEG2Level_Main; + hdr.bmiHeader.biSize = sizeof(hdr.bmiHeader); + hdr.bmiHeader.biWidth = v_width;//720; + hdr.bmiHeader.biHeight = v_height;//568; + hdr.bmiHeader.biCompression = MAKEFOURCC('H','2','6','4'); + /* Vista compat*/ + hdr.dwPictAspectRatioX=1;//v_sar_width; + hdr.dwPictAspectRatioY=1;//v_sar_height; /* Vista compat*/ pmt->cbFormat = sizeof(hdr); pmt->pbFormat = (BYTE*)CoTaskMemAlloc(sizeof(hdr)); @@ -776,19 +821,30 @@ HRESULT DsSourcePin::GetMediaType(int iPosition, AM_MEDIA_TYPE *pmt) case MPTYPE_MPEG_AUDIO: return GetMediaTypeMpegAudio(iPosition,pmt); break; - case MPTYPE_VIDEO: + case MPTYPE_VIDEO_MPEG2: return GetMediaTypeMpegVideo(iPosition,pmt); break; + case MPTYPE_VIDEO_H264: + return GetMediaTypeH264Video(iPosition,pmt); + break; case MPTYPE_AC3_PRE13: case MPTYPE_AC3: return GetMediaTypeAc3(iPosition,pmt); }; } -void DsSourcePin::SetPinMode(int mode) { +void DsSourcePin::SetPinMode(int mode, void* details) { pinmode=mode; AM_MEDIA_TYPE amtype; ReleaseMType(&medtype); + if (details) + { + if (!isaudiopin) + { + v_width=((mptype_video_detail*) details)->width; + v_height=((mptype_video_detail*) details)->height; + } + } GetMediaType(0,&medtype); } @@ -841,7 +897,7 @@ HRESULT DsSourcePin::CheckMediaType(const AM_MEDIA_TYPE *pmt) res = S_FALSE ; } break; - case MPTYPE_VIDEO: + case MPTYPE_VIDEO_MPEG2: if (pmt->majortype==MEDIATYPE_Video && pmt-> subtype==MEDIASUBTYPE_MPEG2_VIDEO) { @@ -852,6 +908,17 @@ HRESULT DsSourcePin::CheckMediaType(const AM_MEDIA_TYPE *pmt) res = S_FALSE ; } break; + case MPTYPE_VIDEO_H264: + if (pmt->majortype==MEDIATYPE_Video && + pmt-> subtype==MEDIASUBTYPE_H264) + { + res = S_OK ; + } + else + { + res = S_FALSE ; + } + break; case MPTYPE_AC3_PRE13: case MPTYPE_AC3: subtype=pmt->subtype==(MEDIASUBTYPE_DOLBY_AC3); @@ -875,18 +942,18 @@ HRESULT DsSourcePin::DecideBufferSize(IMemAllocator *pa,ALLOCATOR_PROPERTIES *al if (pa==NULL)return E_POINTER; if (all_pp==NULL) return E_POINTER; if (isaudiopin) { - if (all_pp->cBuffers*all_pp->cbBuffer < 300*64*1024) + if (all_pp->cBuffers*all_pp->cbBuffer < 100*16*1024) { //all_pp->cBuffers = 300;//old - all_pp->cBuffers = 50; - all_pp->cbBuffer = 64*1024; + all_pp->cBuffers = 100; + all_pp->cbBuffer = 16*1024; } } else { - if (all_pp->cBuffers*all_pp->cbBuffer < 300*64*1024) + if (all_pp->cBuffers*all_pp->cbBuffer < 50*64*1024*5) { //all_pp->cBuffers = 300;//old - all_pp->cBuffers = 300; - all_pp->cbBuffer = 64*1024; + all_pp->cBuffers = 50; + all_pp->cbBuffer = 64*1024*5; } } diff --git a/dssourcepin.h b/dssourcepin.h index 670712f..740aa40 100644 --- a/dssourcepin.h +++ b/dssourcepin.h @@ -42,7 +42,7 @@ public: HRESULT deliver(IMediaSample * ms); void SetMsToMt(IMediaSample *ms); bool supportsAc3(); - void SetPinMode(int mode); + void SetPinMode(int mode, void* details=NULL); virtual HRESULT DecideBufferSize(IMemAllocator *pa,ALLOCATOR_PROPERTIES *all_pp); @@ -80,6 +80,7 @@ protected: HRESULT GetMediaTypeMp3Audio(int iPosition, AM_MEDIA_TYPE *pmt); HRESULT GetMediaTypeAc3(int iPosition, AM_MEDIA_TYPE *pmt); HRESULT GetMediaTypeMpegVideo(int iPosition, AM_MEDIA_TYPE *pmt); + HRESULT GetMediaTypeH264Video(int iPosition, AM_MEDIA_TYPE *pmt); int pinmode; bool isaudiopin; @@ -89,9 +90,8 @@ protected: AM_MEDIA_TYPE medtype; IMemAllocator* allocator; - - - + int v_width; + int v_height; }; diff --git a/eventdispatcher.cc b/eventdispatcher.cc index 9042164..eba132a 100644 --- a/eventdispatcher.cc +++ b/eventdispatcher.cc @@ -19,6 +19,8 @@ */ #include "eventdispatcher.h" +#include + EventDispatcher::EventDispatcher() { diff --git a/eventdispatcher.h b/eventdispatcher.h index 77212b4..3b0a5ee 100644 --- a/eventdispatcher.h +++ b/eventdispatcher.h @@ -58,9 +58,10 @@ class EDReceiver //(implementation in eventdispatcher.cc) class EventDispatcher { - typedef list EDRL; public: + typedef list EDRL; + EventDispatcher(); virtual ~EventDispatcher() {}; diff --git a/main.cc b/main.cc index fee7214..3d4ad20 100644 --- a/main.cc +++ b/main.cc @@ -34,25 +34,46 @@ #include "boxstack.h" #include "command.h" +#ifndef _MIPS_ARCH + #include "mtdmvp.h" #include "remotemvp.h" #include "ledmvp.h" #include "osdmvp.h" #include "audiomvp.h" #include "videomvp.h" + +#else + +#include "mtdnmt.h" +#include "remotelirc.h" +#include "lednmt.h" +#include "osddirectfb.h" +#include "audionmt.h" +#include "videonmt.h" + +#endif + + #include "wol.h" #include "vsleeptimer.h" + + #ifndef WIN32 void sighandler(int signalReceived); #endif void shutdown(int code); +#ifndef _MIPS_ARCH + extern "C" { int ticonfig_main(int, char**); } +#endif + // Global variables -------------------------------------------------------------------------------------------------- Log* logger; Remote* remote; @@ -72,7 +93,9 @@ Sleeptimer* sleeptimer; #ifndef WIN32 int main(int argc, char** argv) { +#ifndef _MIPS_ARCH if (strstr(argv[0], "ticonfig")) return ticonfig_main(argc, argv); +#endif bool daemonize = true; bool debugEnabled = false; @@ -105,16 +128,26 @@ int main(int argc, char** argv) } // Init global vars ------------------------------------------------------------------------------------------------ - logger = new Log(); timers = new Timers(); vdr = new VDR(); +#ifndef _MIPS_ARCH mtd = new MtdMVP(); remote = new RemoteMVP(); led = new LedMVP(); osd = new OsdMVP(); audio = new AudioMVP(); video = new VideoMVP(); +#else + mtd = new MtdNMT(); + remote = new RemoteLirc(); + led = new LedNMT(); + osd = new OsdDirectFB(); + audio = new AudioNMT(); + video = new VideoNMT(); +#endif + + boxstack = new BoxStack(); command = new Command(); wol = new Wol(); @@ -205,8 +238,11 @@ int main(int argc, char** argv) // Init modules ---------------------------------------------------------------------------------------------------- int success; - +#ifndef _MIPS_ARCH success = remote->init("/dev/rawir"); +#else + success = remote->init("/dev/lircd"); +#endif if (success) { logger->log("Core", Log::INFO, "Remote module initialised"); @@ -216,8 +252,11 @@ int main(int argc, char** argv) logger->log("Core", Log::EMERG, "Remote module failed to initialise"); shutdown(1); } - +#ifndef _MIPS_ARCH success = led->init(((RemoteMVP*)remote)->getDevice()); +#else + success = led->init(-1); +#endif if (success) { logger->log("Core", Log::INFO, "LED module initialised"); diff --git a/mediafile.cc b/mediafile.cc index d01f1ae..e0c1191 100644 --- a/mediafile.cc +++ b/mediafile.cc @@ -29,6 +29,7 @@ #include "media.h" #include #include +#include #include #include "log.h" diff --git a/osd.h b/osd.h index 558db62..bd1eba5 100644 --- a/osd.h +++ b/osd.h @@ -34,6 +34,7 @@ class Osd virtual int init(void* device)=0; virtual int shutdown()=0; + bool isInitted() {return initted;}; virtual int getFD()=0; diff --git a/osdwin.cc b/osdwin.cc index aff35f7..e433a86 100644 --- a/osdwin.cc +++ b/osdwin.cc @@ -28,6 +28,16 @@ #include "message.h" #include "command.h" +#define BACKBUFFER_WIDTH 1280 +#define BACKBUFFER_HEIGHT 720 + + + +typedef HRESULT (__stdcall *FCT_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager); +typedef HRESULT (__stdcall *FCT_MFCreateVideoSampleFromSurface)(IUnknown* pUnkSurface, IMFSample** ppSample); + +FCT_DXVA2CreateDirect3DDeviceManager9 ptrDXVA2CreateDirect3DDeviceManager9=NULL; +FCT_MFCreateVideoSampleFromSurface ptrMFCreateVideoSampleFromSurface=NULL; //This is stuff for rendering the OSD @@ -36,20 +46,55 @@ OsdWin::OsdWin() { d3d=NULL; d3ddevice=NULL; - d3dvb=NULL; d3drtsurf=NULL; + swappy=NULL; + swapsurf=NULL; + evrstate=EVR_pres_off; + window=NULL; + external_driving=false; dsallocator=NULL; filter_type=D3DTEXF_FORCE_DWORD; lastrendertime=timeGetTime(); event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL); d3dmutex = CreateMutex(NULL,FALSE,NULL); + /*EVR stuff*/ + dxvadevicehandle=NULL; + evrsupported=true; + HMODULE hlib=NULL; + hlib=LoadLibrary("dxva2.dll"); + if (!hlib) { + evrsupported=false; + return; + } + ptrDXVA2CreateDirect3DDeviceManager9=(FCT_DXVA2CreateDirect3DDeviceManager9)GetProcAddress(hlib, "DXVA2CreateDirect3DDeviceManager9"); + if (!ptrDXVA2CreateDirect3DDeviceManager9){ + evrsupported=false; + return; + } + + hlib=LoadLibrary("evr.dll"); + if (!hlib) { + evrsupported=false; + return; + } + + ptrMFCreateVideoSampleFromSurface = (FCT_MFCreateVideoSampleFromSurface)GetProcAddress(hlib,"MFCreateVideoSampleFromSurface"); + if (!ptrMFCreateVideoSampleFromSurface){ + evrsupported=false; + return; + } } OsdWin::~OsdWin() { - if (initted) shutdown(); + + if (initted) + { + threadStop(); + shutdown(); + } CloseHandle(event); CloseHandle(d3dmutex); } @@ -64,6 +109,7 @@ int OsdWin::init(void* device) { if (initted) return 0; Video* video = Video::getInstance(); + window=*((HWND*)device); //First Create Direct 3D Object d3d=Direct3DCreate9(D3D_SDK_VERSION); if (!d3d) @@ -74,8 +120,8 @@ int OsdWin::init(void* device) // then create the Device D3DPRESENT_PARAMETERS d3dparas; ZeroMemory(&d3dparas,sizeof(d3dparas)); - d3dparas.BackBufferWidth=video->getScreenWidth(); - d3dparas.BackBufferHeight=video->getScreenHeight(); + d3dparas.BackBufferWidth=BACKBUFFER_WIDTH; + d3dparas.BackBufferHeight=BACKBUFFER_HEIGHT; d3dparas.Windowed=TRUE; d3dparas.SwapEffect=D3DSWAPEFFECT_COPY; if (d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,*((HWND*) device), @@ -85,10 +131,11 @@ int OsdWin::init(void* device) } d3ddevice->GetRenderTarget(0,&d3drtsurf); + /* if (!InitVertexBuffer()) { Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 vertex buf!"); return 0; - } + }*/ /* We have to determine which kind of filtering is supported*/ D3DCAPS9 caps; d3ddevice->GetDeviceCaps(&caps); @@ -119,6 +166,15 @@ int OsdWin::init(void* device) filter_type=D3DTEXF_NONE; } + if (evrsupported) + { + if (ptrDXVA2CreateDirect3DDeviceManager9(&dxvatoken,&d3ddevman)!=S_OK) evrsupported=false; + else { + d3ddevman->ResetDevice(d3ddevice,dxvatoken); + } + } + + //Now we will create the Screen @@ -127,10 +183,36 @@ int OsdWin::init(void* device) screen->create(video->getScreenWidth(), video->getScreenHeight()); screen->display(); initted = 1; // must set this here or create surface won't work - + threadStart(); + return 1; } +void OsdWin::LockDevice() +{ + if (!evrsupported) return; + if (!dxvadevicehandle) + { + d3ddevman->OpenDeviceHandle(&dxvadevicehandle); + } + IDirect3DDevice9 *temp; + d3ddevman->LockDevice(dxvadevicehandle,&temp,TRUE); + +} + +void OsdWin::UnlockDevice() +{ + if (!evrsupported) return; + if (!initted) return; + d3ddevman->UnlockDevice(dxvadevicehandle,TRUE); + if (dxvadevicehandle) + { + d3ddevman->CloseDeviceHandle(dxvadevicehandle); + dxvadevicehandle=NULL; + } + +} + DWORD OsdWin::getFilterCaps() { if (!initted) return NULL; @@ -138,9 +220,11 @@ DWORD OsdWin::getFilterCaps() d3ddevice->GetDeviceCaps(&caps); return caps.StretchRectFilterCaps; } - -int OsdWin::InitVertexBuffer() { - Video* video = Video::getInstance(); + +LPDIRECT3DVERTEXBUFFER9 OsdWin::InitVertexBuffer(DWORD width, DWORD height) +{ + LPDIRECT3DVERTEXBUFFER9 ret =NULL; + Video* video=Video::getInstance(); FLOAT texx=((float)video->getScreenWidth())/1024.f; FLOAT texy=((float)video->getScreenHeight())/1024.f; D3DCOLOR osdcolor=D3DCOLOR_RGBA(255,255,255,255); @@ -152,50 +236,51 @@ int OsdWin::InitVertexBuffer() { 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].x=((float)width)-0.5f;-0.5f; osdvertices[1].y=0.f-0.5f; osdvertices[1].z=0.5f; osdvertices[1].u=texx; osdvertices[1].v=0.f; osdvertices[1].rhw=1.f; osdvertices[2].c=osdcolor; - osdvertices[2].x=((float)video->getScreenWidth())-0.5f; - osdvertices[2].y=((float)video->getScreenHeight())-0.5f; + osdvertices[2].x=((float)width)-0.5f; + osdvertices[2].y=((float)height)-0.5f; osdvertices[2].z=0.5f; osdvertices[2].rhw=1.f; osdvertices[2].u=texx; osdvertices[2].v=texy; osdvertices[3].c=osdcolor; osdvertices[3].x=0.f-0.5f; - osdvertices[3].y=((float)video->getScreenHeight())-0.5f; + osdvertices[3].y=((float)height)-0.5f; osdvertices[3].z=0.5f; osdvertices[3].rhw=1.f; osdvertices[3].u=0.f; osdvertices[3].v=texy; - if (d3dvb) { - d3dvb->Release(); - d3dvb=NULL; - } + if (d3ddevice->CreateVertexBuffer(4*sizeof(OSDVERTEX),0,D3DFVF_OSDVERTEX,D3DPOOL_MANAGED, - &d3dvb,NULL)!=D3D_OK) { - return 0; + &ret,NULL)!=D3D_OK) { + return NULL; } void *pvertex=NULL; - if (d3dvb->Lock(0,sizeof(osdvertices),&pvertex,0)!=D3D_OK) { - return 0; + if (ret->Lock(0,sizeof(osdvertices),&pvertex,0)!=D3D_OK) { + return NULL; } memcpy(pvertex,osdvertices,sizeof(osdvertices)); - d3dvb->Unlock(); - return 1; + ret->Unlock(); + return ret; } int OsdWin::shutdown() { if (!initted) return 0; initted = 0; + evrsupported=0; + if (d3ddevman) d3ddevman->Release(); d3drtsurf->Release(); d3ddevice->Release(); d3d->Release(); + if (swapsurf) swapsurf->Release(); + if (swappy) swappy->Release(); return 1; } @@ -205,6 +290,45 @@ void OsdWin::screenShot(char* fileName) screen->screenShot(fileName); } +void OsdWin::threadMethod() +{ + while (true) + { + DWORD waittime=10; + if (initted){ + if (evrstate==EVR_pres_off || evrstate==EVR_pres_pause) + { + Render(); + } else if (evrstate==EVR_pres_started) + { + LPDIRECT3DSURFACE9 surf; + dsallocator->GetNextSurface(&surf,&waittime); + if (surf==NULL) + { + Render(); + } + else + { + RenderDS(surf); + surf->Release(); + dsallocator->DiscardSurfaceandgetWait(&waittime); + } + } + } + threadCheckExit(); + if (waittime!=0) Sleep(min(10,waittime)); + //Sleep(1); + } +} + + +void OsdWin::threadPostStopCleanup() +{ + //Doing nothing + //goo; +} + + // This function is called from the WinMain function in order to get Screen updates void OsdWin::Render() { @@ -215,7 +339,7 @@ void OsdWin::Render() InternalRendering(NULL); lastrendertime=timeGetTime(); } else { - Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads + //Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads } } else { DWORD time1=timeGetTime(); @@ -223,7 +347,7 @@ void OsdWin::Render() InternalRendering(NULL); lastrendertime=timeGetTime(); } else { - Sleep(5); + //Sleep(5); } @@ -240,27 +364,44 @@ void OsdWin::RenderDS(LPDIRECT3DSURFACE9 present){ void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){ - WaitForSingleObject(d3dmutex,INFINITE); + BeginPainting(); HRESULT losty=d3ddevice->TestCooperativeLevel(); if (losty==D3DERR_DEVICELOST) { - Sleep(10); + //Sleep(10); + EndPainting(); return; //Device Lost } if (losty==D3DERR_DEVICENOTRESET){ + EndPainting(); DoLost(); return; } WaitForSingleObject(event,INFINITE); - BeginPainting(); - d3ddevice->SetRenderTarget(0,d3drtsurf);//Stupid VMR manipulates the render target + + + LPDIRECT3DSURFACE9 targetsurf; + if (swappy) + { + targetsurf=swapsurf; + d3ddevice->SetRenderTarget(0,swapsurf);//Stupid VMR manipulates the render target + } + else + { + targetsurf=d3drtsurf; + d3ddevice->SetRenderTarget(0,d3drtsurf);//Stupid VMR manipulates the render target + } + D3DSURFACE_DESC targetdesc; + targetsurf->GetDesc(&targetdesc); + if (external_driving) { //Copy video to Backbuffer if (present!=NULL ) { VideoWin* video =(VideoWin*) Video::getInstance(); /*calculating destination rect */ - RECT destrect={0,0,video->getScreenWidth(),video->getScreenHeight()}; + RECT destrect={0,0,/*video->getScreenWidth()*/ targetdesc.Width, + /*video->getScreenHeight()*/targetdesc.Height}; UCHAR mode=video->getMode(); switch (mode) { case Video::EIGHTH: @@ -284,7 +425,7 @@ void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){ sourcerect.left=(surf_desc.Width-correction)/2; sourcerect.right=sourcerect.left+correction; } - d3ddevice->StretchRect(present,&sourcerect,d3drtsurf ,&destrect,filter_type); + d3ddevice->StretchRect(present,&sourcerect,targetsurf ,&destrect,filter_type); } } else { @@ -292,9 +433,12 @@ void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){ //Clear Background if (!video->isVideoOn()) d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0); } + LPDIRECT3DVERTEXBUFFER9 vb=NULL; + vb=InitVertexBuffer(targetdesc.Width,targetdesc.Height); + //Drawing the OSD if (d3ddevice->BeginScene()==D3D_OK) { - d3ddevice->SetStreamSource(0,d3dvb,0,sizeof(OSDVERTEX)); + d3ddevice->SetStreamSource(0,vb,0,sizeof(OSDVERTEX)); d3ddevice->SetFVF(D3DFVF_OSDVERTEX); d3ddevice->SetTexture(0,((SurfaceWin*)screen)->getD3dtexture()); //d3ddevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE); @@ -314,16 +458,30 @@ void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){ d3ddevice->EndScene(); //Show it to the user! HRESULT hres; - if (hres=d3ddevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST){ - EndPainting(); - if (!external_driving) DoLost(); + if (swappy) + { + if (hres=swappy->Present(NULL,NULL,NULL,NULL,0)==D3DERR_DEVICELOST){ + //EndPainting(); + if (!external_driving) DoLost(); + } + } + else + { + if (hres=d3ddevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST){ + //EndPainting(); + if (!external_driving) DoLost(); + } } - EndPainting(); - } - ReleaseMutex(d3dmutex); - if (!external_driving) { - Sleep(4);//The User can wait for 4 milliseconds to see his changes + } + + vb->Release(); + EndPainting(); + + +// if (!external_driving) { +// Sleep(4);//The User can wait for 4 milliseconds to see his changes +// } } bool OsdWin::DoLost(){ @@ -337,19 +495,22 @@ bool OsdWin::DoLost(){ ((SurfaceWin*)screen)->ReleaseSurface(); if (d3drtsurf) d3drtsurf->Release(); d3drtsurf=NULL; - if (d3dvb) d3dvb->Release(); - d3dvb=NULL; D3DPRESENT_PARAMETERS d3dparas; ZeroMemory(&d3dparas,sizeof(d3dparas)); - d3dparas.BackBufferWidth=video->getScreenWidth(); - d3dparas.BackBufferHeight=video->getScreenHeight(); + d3dparas.BackBufferWidth=BACKBUFFER_WIDTH; + d3dparas.BackBufferHeight=BACKBUFFER_HEIGHT; d3dparas.Windowed=TRUE; d3dparas.SwapEffect=D3DSWAPEFFECT_COPY; + + if (swapsurf) {swapsurf->Release();swapsurf=NULL;}; + if (swappy) {swappy->Release();swappy=NULL;}; + if (d3ddevice->Reset(&d3dparas)!=D3D_OK){ return false; } d3ddevice->GetRenderTarget(0,&d3drtsurf); - InitVertexBuffer(); + if (d3ddevman) d3ddevman->ResetDevice(d3ddevice,dxvatoken); + //InitVertexBuffer(); //Redraw Views, Chris could you add a member function to BoxStack, so that // I can cause it to completely redraw the Views? // Otherwise the OSD would be distorted after Device Lost @@ -376,21 +537,58 @@ LPDIRECT3D9 OsdWin::getD3d() { void OsdWin::BeginPainting() {//We synchronize calls to d3d between different threads WaitForSingleObject(d3dmutex,INFINITE); + LockDevice(); } void OsdWin::EndPainting() { + UnlockDevice(); ReleaseMutex(d3dmutex); } -void OsdWin::setExternalDriving(DsAllocator* dsall) { +void OsdWin::setExternalDriving(DsAllocator* dsall,DWORD width, DWORD height) { + + if (swappy) + { + BeginPainting(); + d3ddevice->StretchRect(swapsurf,NULL,d3drtsurf,NULL,filter_type); + LPDIRECT3DSWAPCHAIN9 temp=swappy; + LPDIRECT3DSURFACE9 tempsurf=swapsurf; + swappy=NULL; + swapsurf=NULL; + EndPainting(); + tempsurf->Release(); + temp->Release(); + } + if (dsall==NULL) { external_driving=false; - dsallocator=NULL; + dsallocator=NULL; return; } WaitForSingleObject(event,INFINITE);//We will only return if we are initted + BeginPainting(); + + if (width>BACKBUFFER_WIDTH || height>BACKBUFFER_HEIGHT) + { + D3DPRESENT_PARAMETERS d3dparas; + ZeroMemory(&d3dparas,sizeof(d3dparas)); + d3dparas.BackBufferWidth=width; + d3dparas.BackBufferHeight=height; + d3dparas.Windowed=TRUE; + d3dparas.SwapEffect=D3DSWAPEFFECT_COPY; + if (d3ddevice->CreateAdditionalSwapChain(&d3dparas,&swappy)!=D3D_OK){ + Log::getInstance()->log("OSD", Log::WARN, "Could not create Swap Chain!"); + //return 0; + } else { + swappy->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&swapsurf); + } + Log::getInstance()->log("OSD", Log::INFO, "Create Additional Swap Chain %d %d!",width,height); + } + dsallocator=dsall; external_driving=true; + + EndPainting(); } void OsdWin::Blank() { diff --git a/osdwin.h b/osdwin.h index 756520d..a470fbc 100644 --- a/osdwin.h +++ b/osdwin.h @@ -26,8 +26,10 @@ #include "osd.h" #include "defines.h" #include "log.h" +#include "threadwin.h" #include #include +#include struct OSDVERTEX { @@ -40,7 +42,9 @@ struct OSDVERTEX class DsAllocator; -class OsdWin : public Osd + + +class OsdWin : public Osd, public ThreadWin { public: OsdWin(); @@ -53,6 +57,9 @@ class OsdWin : public Osd void screenShot(char* fileName); + void threadMethod(); + void threadPostStopCleanup(); + LPDIRECT3DDEVICE9 getD3dDev() ; LPDIRECT3D9 getD3d() ; // This function is called from the WinMain function in order to get Screen updates @@ -60,16 +67,38 @@ class OsdWin : public Osd void RenderDS(LPDIRECT3DSURFACE9 present); void BeginPainting(); void EndPainting(); - void setExternalDriving(DsAllocator* dsall); + void setExternalDriving(DsAllocator* dsall,DWORD width, DWORD height); void Blank(); DWORD getFilterCaps(); DWORD getFilterType(){return filter_type;}; void setFilterType(D3DTEXTUREFILTERTYPE type) {filter_type=type;}; + + + + + + enum EVR_state { + EVR_pres_off=0, + EVR_pres_started, + EVR_pres_pause + }; + + void SetEVRStatus(EVR_state new_state){evrstate=new_state;}; + + IDirect3DDeviceManager9 * getD3dMan() {return d3ddevman;}; + bool IsEvrSupported() {return evrsupported;}; + HWND getWindow() {return window;}; + private: + void LockDevice(); + void UnlockDevice(); + LPDIRECT3D9 d3d; LPDIRECT3DDEVICE9 d3ddevice; - LPDIRECT3DVERTEXBUFFER9 d3dvb; +// LPDIRECT3DVERTEXBUFFER9 d3dvb; LPDIRECT3DSURFACE9 d3drtsurf; + LPDIRECT3DSWAPCHAIN9 swappy; + LPDIRECT3DSURFACE9 swapsurf; DsAllocator* dsallocator; // This indicates, that currently a video is played, thus the osd updates are driven by the Directshow Filtersystem bool external_driving; @@ -77,10 +106,17 @@ private: DWORD lastrendertime; void InternalRendering(LPDIRECT3DSURFACE9 present); bool DoLost(); - int InitVertexBuffer(); + LPDIRECT3DVERTEXBUFFER9 InitVertexBuffer(DWORD width, DWORD height); OSDVERTEX osdvertices[4]; HANDLE event; D3DTEXTUREFILTERTYPE filter_type; + EVR_state evrstate; + bool evrsupported; + HWND window; + + UINT dxvatoken; + IDirect3DDeviceManager9 *d3ddevman; + HANDLE dxvadevicehandle; }; #endif diff --git a/player.cc b/player.cc index 359cbef..f250b35 100644 --- a/player.cc +++ b/player.cc @@ -58,7 +58,7 @@ Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* videoStartup = false; threadBuffer = NULL; - + blockSize = 100000; startupBlockSize = 250000; video->turnVideoOn(); @@ -69,7 +69,7 @@ Player::~Player() if (initted) shutdown(); } -int Player::init(bool p_isPesRecording) +int Player::init(bool p_isPesRecording,double framespersecond) { if (initted) return 0; #ifndef WIN32 @@ -78,6 +78,7 @@ int Player::init(bool p_isPesRecording) mutex=CreateMutex(NULL,FALSE,NULL); #endif is_pesrecording = p_isPesRecording; + fps=framespersecond; if (is_pesrecording) demuxer = new DemuxerVDR(); else @@ -89,8 +90,10 @@ int Player::init(bool p_isPesRecording) teletext = new TeletextDecoderVBIEBU(); if (!teletext) return 0; teletext->setRecordigMode(true); + unsigned int demux_video_size=2097152; + if (video->supportsh264()) demux_video_size*=5; - if (!demuxer->init(this, audio, video,teletext, 2097152, 524288,65536, subtitles)) + if (!demuxer->init(this, audio, video,teletext, demux_video_size,524288,65536, framespersecond, subtitles)) { logger->log("Player", Log::ERR, "Demuxer failed to init"); shutdown(); @@ -387,7 +390,7 @@ void Player::skipForward(int seconds) logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds); ULONG newFrame = getCurrentFrameNum(); if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid - newFrame += seconds * video->getFPS(); + newFrame +=(ULONG) (((double)seconds) * fps); if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); } else switchState(S_JUMP, newFrame); // unLock(); - let thread unlock this @@ -399,7 +402,7 @@ void Player::skipBackward(int seconds) logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds); long newFrame = getCurrentFrameNum(); if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid - newFrame -= seconds * video->getFPS(); + newFrame -= (ULONG) (((double)seconds) * fps); if (newFrame < 0) newFrame = 0; switchState(S_JUMP, newFrame); // unLock(); - let thread unlock this @@ -654,7 +657,7 @@ void Player::switchState(UCHAR toState, ULONG jumpFrame) case S_PLAY: // to S_PLAY { state = S_PLAY; - ULONG stepback = USER_RESPONSE_TIME * video->getFPS() * ifactor / 1000; + ULONG stepback = (ULONG)(((double)USER_RESPONSE_TIME * ifactor) * fps / 1000.); if (stepback < currentFrameNumber) currentFrameNumber -= stepback; else @@ -1081,8 +1084,11 @@ void Player::threadFeedPlay() else // normal askFor = blockSize; } + //logger->log("Player", Log::DEBUG, "Get Block in"); threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead); + //logger->log("Player", Log::DEBUG, "Get Block out"); + feedPosition += thisRead; if (!vdr->isConnected()) @@ -1105,7 +1111,9 @@ void Player::threadFeedPlay() while(writeLength < thisRead) { + //logger->log("Player", Log::DEBUG, "Put in"); thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength); + //logger->log("Player", Log::DEBUG, "Put out"); writeLength += thisWrite; if (!thisWrite) @@ -1191,7 +1199,7 @@ void Player::threadFeedScan() // scan has got to the end of what we knew to be there before we started scanning baseFrameNumber = iframeNumber; - frameTimeOffset = abs((int)iframeNumber - (int)currentFrameNumber) * 1000 / (video->getFPS() * ifactor); + frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor)); #ifndef WIN32 gettimeofday(&clock0, NULL); #else @@ -1205,7 +1213,7 @@ void Player::threadFeedScan() #else while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset); #endif -// logger->log("Player", Log::DEBUG, "XXX Got frame"); + logger->log("Player", Log::DEBUG, "XXX Got frame"); threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived); @@ -1230,7 +1238,7 @@ void Player::threadFeedScan() if (sleepTime < 0) sleepTime = 0; threadCheckExit(); MILLISLEEP(sleepTime); -// logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime); + logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime); videoLength = demuxer->stripAudio(threadBuffer, amountReceived); video->displayIFrame(threadBuffer, videoLength); @@ -1251,7 +1259,7 @@ void Player::threadFeedScan() total_msec = clock2 - clock0 - sleepTime; disp_msec = clock2 - clock1 - sleepTime; #endif -// logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec); + logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec); } } diff --git a/player.h b/player.h index 135292f..af9bedf 100644 --- a/player.h +++ b/player.h @@ -58,7 +58,7 @@ class Player : public Thread_TYPE, public Callback Player(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* osdReceiver); virtual ~Player(); - int init(bool p_isPesRecording); + int init(bool p_isPesRecording,double framespersec); int shutdown(); void setStartFrame(ULONG frameNum); void setLengthBytes(ULLONG length); @@ -157,6 +157,7 @@ class Player : public Thread_TYPE, public Callback bool videoStartup; bool is_pesrecording; + double fps; #ifndef WIN32 pthread_mutex_t mutex; diff --git a/playerlivetv.cc b/playerlivetv.cc index f08d800..20ff359 100644 --- a/playerlivetv.cc +++ b/playerlivetv.cc @@ -50,6 +50,7 @@ PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, subtitlesShowing = false; videoStartup = false; + pendingAudioPlay = false; stopNow = false; state = S_STOP; @@ -72,8 +73,11 @@ int PlayerLiveTV::init() if (!subtitles) return 0; teletext = new TeletextDecoderVBIEBU(); + + unsigned int demux_video_size=2097152; + if (video->supportsh264()) demux_video_size*=5; - if (!demuxer->init(this, audio, video, teletext, 2097152, 524288, 65536, subtitles)) + if (!demuxer->init(this, audio, video, teletext, demux_video_size, 524288, 65536,25./*unimportant*/,subtitles)) { logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init"); shutdown(); @@ -320,6 +324,17 @@ void PlayerLiveTV::chunkToDemuxer() /*int a = */demuxer->put((UCHAR*)s.data, s.len); //logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a); free(s.data); + if (pendingAudioPlay && demuxer->getHorizontalSize()) //Horizontal Size is zero, if not parsed + { + video->sync(); + video->play(); + video->pause(); + //audio->setStreamType(Audio::MPEG2_PES); + audio->sync(); + audio->play(); + audio->pause(); + pendingAudioPlay = false; + } } void PlayerLiveTV::switchState(UCHAR newState) @@ -336,17 +351,26 @@ void PlayerLiveTV::switchState(UCHAR newState) { video->blank(); video->reset(); - video->sync(); - video->play(); - video->pause(); + //video->sync(); + //video->play(); + //video->pause(); audio->stop(); audio->unPause(); audio->reset(); - audio->setStreamType(Audio::MPEG2_PES); - audio->sync(); - audio->play(); - audio->pause(); + //audio->setStreamType(Audio::MPEG2_PES); + //audio->sync(); + // I make this modification, since the video/audio devices needs to know at least + // which kind of video is embedded inside the stream + // therefore the demuxer needs to feeded at least with enough data + // to have one video header + // This is crucial, if we have mixed h264/mpeg2 channels + // the information from channels is not enough since some directshow decoders need + // width and height information before startup + pendingAudioPlay = true; + + //audio->play(); + //audio->pause(); demuxer->reset(); demuxer->seek(); @@ -374,6 +398,7 @@ void PlayerLiveTV::switchState(UCHAR newState) { case S_PREBUFFERING: { + pendingAudioPlay=false; vfeed.release(); state = newState; return; @@ -390,17 +415,18 @@ void PlayerLiveTV::switchState(UCHAR newState) video->blank(); video->reset(); - video->sync(); - video->play(); - video->pause(); + //video->sync(); + //video->play(); + //video->pause(); audio->stop(); audio->unPause(); audio->reset(); - audio->setStreamType(Audio::MPEG2_PES); - audio->sync(); - audio->play(); - audio->pause(); + //audio->setStreamType(Audio::MPEG2_PES); + //audio->sync(); + pendingAudioPlay = true; + //audio->play(); + //audio->pause(); demuxer->reset(); demuxer->seek(); @@ -415,12 +441,14 @@ void PlayerLiveTV::switchState(UCHAR newState) case S_STOP: { vdr->stopStreaming(); + pendingAudioPlay=false; clearStreamChunks(); vfeed.stop(); afeed.stop(); -subtitles->stop(); - tfeed.stop(); - video->stop(); video->blank(); + subtitles->stop(); + tfeed.stop(); + video->stop(); + video->blank(); audio->stop(); audio->reset(); video->reset(); @@ -442,6 +470,7 @@ subtitles->stop(); { case S_PLAY: { + pendingAudioPlay=false; audio->unPause(); video->unPause(); state = newState; @@ -462,14 +491,15 @@ subtitles->stop(); audio->reset(); video->reset(); - video->sync(); - video->play(); - video->pause(); + //video->sync(); + //video->play(); + //video->pause(); - audio->setStreamType(Audio::MPEG2_PES); - audio->sync(); - audio->play(); - audio->pause(); + //audio->setStreamType(Audio::MPEG2_PES); + //audio->sync(); + pendingAudioPlay = true; + //audio->play(); + //audio->pause(); demuxer->reset(); demuxer->seek(); @@ -484,6 +514,7 @@ subtitles->stop(); } case S_STOP: { + pendingAudioPlay=false; vdr->stopStreaming(); clearStreamChunks(); vfeed.stop(); @@ -513,6 +544,7 @@ subtitles->stop(); { case S_STOP: { + pendingAudioPlay=false; vdr->stopStreaming(); clearStreamChunks(); vfeed.stop(); @@ -542,14 +574,16 @@ subtitles->stop(); audio->reset(); video->reset(); - video->sync(); - video->play(); - video->pause(); + + //video->sync(); + // video->play(); + //video->pause(); - audio->setStreamType(Audio::MPEG2_PES); - audio->sync(); - audio->play(); - audio->pause(); + //audio->setStreamType(Audio::MPEG2_PES); + //audio->sync(); + //audio->play(); + //audio->pause(); + pendingAudioPlay = true; demuxer->reset(); demuxer->seek(); @@ -616,7 +650,7 @@ void PlayerLiveTV::threadMethod() { while(1) { - if (videoStartup) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data + if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data { switchState(S_PREBUFFERING); videoStartup = false; @@ -635,22 +669,37 @@ void PlayerLiveTV::threadMethod() if (i.instruction == I_SETCHANNEL) { logger->log("PlayerLiveTV", Log::DEBUG, "start new stream"); - + + switchState(S_VIDEOSTARTUP); if (!checkError()) { - Channel* chan = (*chanList)[i.channelIndex]; - chan->loadPids(); - demuxer->setVID(chan->vpid); + Channel* chan = (*chanList)[i.channelIndex]; + chan->loadPids(); + h264=chan->vstreamtype==0x1b; + demuxer->seth264(h264); + video->seth264mode(chan->vstreamtype==0x1b); + demuxer->setVID(chan->vpid); + video->seth264mode(chan->vstreamtype==0x1b); + if (chan->numAPids > 0) { demuxer->setAID(chan->apids[0].pid,0); + audio->setStreamType(Audio::MPEG2_PES); logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid); } else { - logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid); + if (chan->numDPids > 0 && audio->maysupportAc3()) + { + demuxer->setAID(chan->dpids[0].pid,1); + logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3)", chan->vpid, chan->dpids[0].pid); + } + else + { + logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid); + } } if (chan->numSPids > 0) demuxer->setSubID(chan->spids[0].pid); diff --git a/playerlivetv.h b/playerlivetv.h index ebc3a46..1ed46d0 100644 --- a/playerlivetv.h +++ b/playerlivetv.h @@ -134,7 +134,9 @@ class PlayerLiveTV : public PlayerLive, public Thread_TYPE, public Callback, pub bool checkError(); bool videoStartup; + bool pendingAudioPlay; bool stopNow; + bool h264; int preBufferCount; const static int preBufferAmount = 3; diff --git a/readme.win b/readme.win index 738b31a..9c45c6f 100644 --- a/readme.win +++ b/readme.win @@ -20,38 +20,14 @@ The vomp client on Windows requires: * Windows 2000 or later * Windows XP for full remote control support +* Windows Vista for EVR support * DirectX 8 graphics card (some older cards might work also) -* A DirectShow MPEG2 decoder, which supports Video Mixing Renderer 9 (VMR-9), - mostly included within DVD software player +* A DirectShow MPEG2 decoder, which supports Video Mixing Renderer 9 (VMR-9) +or the Enhanced Video Renderer (EVR) mostly included within DVD software player +* For h264 palyback a DirectShow h264 decoder, supporting +the Video Mixing Renderer 9 (VMR-9) or the Enhanced Video Renderer (EVR) * A network connection to the vompserver computer -Compatibility List for MPEG2 Decoders -===================================== -Compatible MPEG2 decoders: -* Cyberlink PowerDVD 6 -* Ulead MovieFactory 5 (Intervideo Filter shipped within) - -Incompatible MPEG2 decoders: - - -Old Compatibility List for MPEG2 Decoders (for Vomp < 0.2.7) -============================================================ -Compatible MPEG2 decoders: -* Cyberlink PowerDVD 5 (build 2214 and later, look for the update at cyberlinks webpage) -* Cyberlink PowerDVD 6 -* Cyberlink PowerDVD 7 -* Nero Showtime 2 (from Nero Suite 6) -* MPV Decoder Filter -* Ulead MovieFactory 5 (Intervideo Filter shipped within) - -Incompatible MPEG2 decoders: -* Cyberlink PowerDVD 4 -* MainConcept Video Decoder version 1.0.0.38 (comes with some Hauppauge software) - - -These lists are provided without any warranty. -These lists will be extended, please report success or failure with your decoder -at the forum at http://www.loggytronic.com . Remote Control Buttons Reference ================================ diff --git a/recinfo.h b/recinfo.h index 922d855..260bd5f 100644 --- a/recinfo.h +++ b/recinfo.h @@ -36,6 +36,8 @@ class RecInfo ULONG resumePoint; char* summary; + double fps; + ULONG numComponents; UCHAR* streams; UCHAR* types; diff --git a/recording.cc b/recording.cc index c0e2f2a..5d932f9 100644 --- a/recording.cc +++ b/recording.cc @@ -122,7 +122,7 @@ void Recording::loadMarks() if (!VDR::getInstance()->isConnected()) Command::getInstance()->connectionLost(); } -bool Recording::isRadio() +bool Recording::isRadio(bool &h264) { ULONG lengthFrames = 0; ULLONG lengthBytes = vdr->streamRecording(getFileName(), &lengthFrames, &IsPesRecording); @@ -139,10 +139,13 @@ bool Recording::isRadio() } bool hasVideo = false; + bool ish264=false; if (IsPesRecording) - hasVideo = Demuxer::scanForVideo(buffer, thisRead); + hasVideo = Demuxer::scanForVideo(buffer, thisRead, ish264); else - hasVideo = DemuxerTS::scanForVideo(buffer, thisRead); + hasVideo = DemuxerTS::scanForVideo(buffer, thisRead,ish264); + + h264=ish264; free(buffer); diff --git a/recording.h b/recording.h index e114281..2103bc2 100644 --- a/recording.h +++ b/recording.h @@ -47,7 +47,7 @@ class Recording void loadRecInfo(); void dropRecInfo(); - bool isRadio(); + bool isRadio(bool &h264); bool IsPesRecording; void loadMarks(); diff --git a/stream.cc b/stream.cc index f053f02..b0318ae 100644 --- a/stream.cc +++ b/stream.cc @@ -41,6 +41,7 @@ void Stream::shutdown() #ifdef WIN32 CloseHandle(mutex); #endif + } initted = 0; } @@ -63,12 +64,13 @@ int Stream::init(DrainTarget* tdt, int bufsize) void Stream::flush() { lock(); + mediapackets.clear(); unLock(); if (draintarget) draintarget->ResetTimeOffsets(); } -int Stream::put(const UCHAR* inbuf, int len, UCHAR type) +int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index) { int ret = 0; if (!draintarget) return 0; @@ -77,13 +79,16 @@ int Stream::put(const UCHAR* inbuf, int len, UCHAR type) newPacket.pos_buffer = 0; newPacket.type = type; newPacket.pts=0; + newPacket.dts=0; newPacket.synched=false; + newPacket.index=index; #ifdef WIN32 newPacket.disconti=false; newPacket.presentation_time=0; #endif if (type!=MPTYPE_MPEG_AUDIO_LAYER3) {//no PES //Extract the pts... + bool hasdts=false; if ((inbuf[7] & 0x80) && len>14 ) { newPacket.synched=true; newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) | @@ -91,10 +96,21 @@ int Stream::put(const UCHAR* inbuf, int len, UCHAR type) ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) | ( (ULLONG)(inbuf[12]) << 7 ) | ( (ULLONG)(inbuf[13] & 0xFE) >> 1 ); + if ((inbuf[7] & 0x40) && len>19) { + newPacket.dts=((ULLONG)(inbuf[14] & 0x0E) << 29 ) | + ( (ULLONG)(inbuf[15]) << 22 ) | + ( (ULLONG)(inbuf[16] & 0xFE) << 14 ) | + ( (ULLONG)(inbuf[17]) << 7 ) | + ( (ULLONG)(inbuf[18] & 0xFE) >> 1 ); + hasdts=true; + } #ifdef WIN32 //ok we have the pts now convert it to a continously time code in 100ns units - newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL); - newPacket.presentation_time-=draintarget->SetStartOffset(newPacket.presentation_time,&newPacket.disconti); + if (hasdts ) newPacket.presentation_time=(ULLONG)(newPacket.dts*10000LL/90LL); + else newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL); + + //newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti); + newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti); #endif } } @@ -137,7 +153,10 @@ int Stream::put(const UCHAR* inbuf, int len, UCHAR type) lock(); mediapackets.push_back(newPacket); unLock(); - } + }// else { + // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize); + //} + return ret; } @@ -154,7 +173,10 @@ bool Stream::drain() lock(); if (consumed != 0) ret = true; if (consumed > listlength) consumed = listlength; - while (consumed--) mediapackets.pop_front(); + while (consumed--) + { + mediapackets.pop_front(); + } } unLock(); return ret; diff --git a/stream.h b/stream.h index aba2fda..26916eb 100644 --- a/stream.h +++ b/stream.h @@ -45,7 +45,7 @@ class Stream int init(DrainTarget* tdt, int bufsize); void shutdown(); void flush(); - int put(const UCHAR* inbuf, int len, UCHAR type); + int put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index); bool drain(); private: diff --git a/surface.cc b/surface.cc index 13a1daa..a6cb01f 100644 --- a/surface.cc +++ b/surface.cc @@ -89,7 +89,7 @@ int Surface::drawTextRJ(const char* text, int x, int y, ULONG rgba) for (i = 0; i < n; i++) { - w += font->width[text[i]]; + w += font->width[(unsigned char)text[i]]; } x -= w; @@ -107,7 +107,7 @@ int Surface::drawTextCentre(const char* text, int x, int y, ULONG rgba) for (i = 0; i < n; i++) { - w += font->width[text[i]]; + w += font->width[(unsigned char)text[i]]; //Characters bigger then 128 can appear } x -= w / 2; diff --git a/surfacewin.cc b/surfacewin.cc index 5153c38..2260ac9 100644 --- a/surfacewin.cc +++ b/surfacewin.cc @@ -35,46 +35,57 @@ SurfaceWin::SurfaceWin(int id) SurfaceWin::~SurfaceWin() { - if (d3dsurface) d3dsurface->Release(); - if (d3dtexture) d3dtexture->Release(); - CloseHandle(event); + if (d3dsurface) d3dsurface->Release(); + if (d3dtexture) d3dtexture->Release(); + CloseHandle(event); } int SurfaceWin::create(UINT width, UINT height) { - 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; + OsdWin* osd=((OsdWin*)(Osd::getInstance())); + + + LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev(); + + while (true) { + if (screen==this) { + osd->BeginPainting(); + if (d3ddev->CreateTexture(1024,1024,0,0,D3DFMT_A8R8G8B8, + // Does every adapter with alpha blending support this? + D3DPOOL_DEFAULT,&d3dtexture ,NULL)!=D3D_OK) { + osd->EndPainting(); + MILLISLEEP(50);//wait maybe next time it will work + continue; + } + if (d3dtexture->GetSurfaceLevel(0,&d3dsurface)!=D3D_OK) { + d3dtexture->Release(); + d3dtexture=NULL; + MILLISLEEP(50); + osd->EndPainting(); + continue; + } + } else { + HRESULT hres; + if (hres=d3ddev->CreateOffscreenPlainSurface(width,height,D3DFMT_A8R8G8B8, + D3DPOOL_SYSTEMMEM,&d3dsurface,NULL)!=D3D_OK) { + osd->EndPainting(); + MILLISLEEP(50);//wait maybe next time it will work + + continue; + } + + } + osd->EndPainting(); + + sheight=height; + swidth=width; + /* If someone does high performance Animations on the OSD, we have to change the types + of surface in order to address these performance issues, if we have only very few updates + per second this would be fast enough !*/ + break; + } + SetEvent(event); + return 1; } void SurfaceWin::display() diff --git a/tcp.cc b/tcp.cc index 753bed3..05b108c 100644 --- a/tcp.cc +++ b/tcp.cc @@ -290,9 +290,9 @@ int TCP::readData(UCHAR* buffer, int totalBytes) FD_SET(sock, &readSet); timeout.tv_sec = 2; timeout.tv_usec = 0; - Log::getInstance()->log("TCP", Log::DEBUG, "Going to select"); + // Log::getInstance()->log("TCP", Log::DEBUG, "Going to select"); success = select(sock + 1, &readSet, NULL, NULL, passToSelect); - Log::getInstance()->log("TCP", Log::DEBUG, "Back from select with success = %i", success); + // Log::getInstance()->log("TCP", Log::DEBUG, "Back from select with success = %i", success); if (success < 1) { return 0; // error, or timeout diff --git a/teletextdecodervbiebu.cc b/teletextdecodervbiebu.cc index 44e2c16..f5d10bc 100644 --- a/teletextdecodervbiebu.cc +++ b/teletextdecodervbiebu.cc @@ -1,834 +1,834 @@ -/* - Copyright 2008 Marten Richter - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -/* Portions from vdr osdteletext plugin "txtrender.c": */ -/*************************************************************************** - * * - * txtrender.c - Teletext display abstraction and teletext code * - * renderer * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * Changelog: * - * 2005-03 initial version (c) Udo Richter * - * * - ***************************************************************************/ - -#include "teletextdecodervbiebu.h" -#include "teletxt/tables.h" -#include "message.h" -#include "command.h" -#include "video.h" - -#ifdef WIN32 -#include -#endif - -TeletextDecoderVBIEBU::TeletextDecoderVBIEBU() -{ - selectedpage=0x100; - ourpage=false; - flags=lang=0; - - CleanPage(); - FirstG0CodePage=0; - SecondG0CodePage=0; - dirty=false; - txtview=NULL; - firstlineupdate=0; - gotcha=false; - char digits[]={'1','0','0'}; - setKeyinDigits(digits,false); - isrecording=false; - for (int i=0;i<10;i++) record_pages[i]=-1; - - -} - -TeletextDecoderVBIEBU::~TeletextDecoderVBIEBU() -{ - - -} - -long long TeletextDecoderVBIEBU::SetStartOffset(long long curreftime, bool *rsync) -{ - return 0; -} - -void TeletextDecoderVBIEBU::ResetTimeOffsets() -{ - -} - - - -void TeletextDecoderVBIEBU::ResetDecoder() -{ - gotcha=false; - ourpage=false; - firstlineupdate=0; - selectedpage=0x100; - CleanPage(); - char digits[]={'1','0','0'}; - setKeyinDigits(digits,false); - for (int i=0;i<10;i++) record_pages[i]=-1; - -} - -void TeletextDecoderVBIEBU::setPage(unsigned int newpage) -{ - selectedpage=newpage; - gotcha=false; - ourpage=false; - firstlineupdate=0; - for (int i=0;i<25;i++) { - memset(curpage[i],0,40); - } -} - -void TeletextDecoderVBIEBU::CleanPage() -{ - int x,y; - for (int i=0;i<25;i++) { - memset(curpage[i],0,40); - } - for (y=0;y<25;y++) { - for (x=0;x<40;x++) { - cTeletextChar c; - c.SetFGColor(ttcWhite); - c.SetBGColor(ttcBlack); - c.SetCharset(CHARSET_LATIN_G0); - c.SetChar(' '); - if (flags&0x60) { - c.SetBoxedOut(true); - } - setChar(x,y,c); - } - } - -} -void TeletextDecoderVBIEBU::setKeyinDigits(char digits[3],bool inKeying) -{ - int x; - inkeying=inKeying; - for (x=0;x<3;x++) { - cTeletextChar c; - c.SetFGColor(ttcWhite); - c.SetBGColor(ttcBlack); - c.SetCharset(CHARSET_LATIN_G0); - c.SetChar(digits[x]); - if (flags&0x60) { - c.SetBoxedOut(true); - } - setChar(x+3,0,c); - keyindigits[x]=digits[x]; - } -} - -void TeletextDecoderVBIEBU::PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos) -{ - mediapacket = mplist.front(); -} - -static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2) -{ - // Assume pts1, pts2 < 2^33; calculate pts1 - pts2 - if (pts1 > pts2) - return pts1 - pts2; - else - return (1LL<<33) + pts1 - pts2; -} - -UINT TeletextDecoderVBIEBU::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos) -{ - if (mediapacket.type != MPTYPE_TELETEXT) - { - *samplepos= 0; - return 1; //Skip it! - } - unsigned int headerstrip; - unsigned char txtdata[43]; - headerstrip=buffer[mediapacket.pos_buffer+8]+9; - //headerstrip+=4; //substream id - unsigned int datapos=0; - unsigned int datatype=buffer[mediapacket.pos_buffer+headerstrip+0]; - //Chris should we use here the pts data from mediapacket ? - // in this case the data fields should also be added in mediamvp - if (mediapacket.synched) - { // An entry exists in the work list - ULLONG nowPTS = Video::getInstance()->getCurrentTimestamp(); - if (PTSDifference(mediapacket.pts, nowPTS) >= 1200*90000) { - *samplepos=0; - return 1;//bad data skip it - } - if (nowPTS < (mediapacket.pts-4000) ) { - *samplepos=0; - return 0; - } - } - - if (( datatype>=0x10 && datatype <=0x1F) || - ( datatype>=0x99 && datatype <=0x9B)) { - //EBU VBI DATA - datapos++; - while (datapos< (mediapacket.length-headerstrip)) { - unsigned int unit_id=buffer[mediapacket.pos_buffer+headerstrip+datapos]; - datapos++; - unsigned int unit_length=buffer[mediapacket.pos_buffer+headerstrip+datapos]; - datapos++; - switch (unit_id) { - case 0x02: - case 0x03: {//Teletext with and without subtitles - //call teletext decoder - unsigned int field=buffer[mediapacket.pos_buffer+headerstrip+datapos]; - - if ((datapos+44)< (mediapacket.length-headerstrip)) { - for (int i=0;i<42;i++) { - txtdata[i]=invtab[buffer[mediapacket.pos_buffer+headerstrip+datapos+2+i]]; - } - DecodeTeletext(txtdata,field); - } - }break; - case 0xC0: //inverted Teletext - //call teletext decoder - break; - - case 0xC3: //VPS - //what to do with this, in the moment we do not need it - break; - case 0xC4: //WSS - //what to do with this, in the moment we do not need it - break; - case 0xC5: //CC - //what to do with this, in the moment we do not need it - break; - case 0xC6: //monochrome 4:2:2 samples, what is that? - //what to do with this, in the moment we do not need it - break; - default: - // case 0x00,0x01,0x04..0x7f,0x80..0xbf,0xc1,0xc2,0xc7..0xfe,0xff: //discard - //discard - break; - }; - datapos+=unit_length; - // while (buffer[mediapacket.pos_buffer+headerstrip+datapos]==0xFF &&(datapos< (mediapacket.length-headerstrip))) { - // datapos++; //stuffing bytes - // } - - - } - *samplepos=0; - return 1; - - - } else { - *samplepos= 0; - return 1; //Skip it! and discard data - } - - return 0; - -} -// This part is inspired by the vdr-plugin-osdteletext of Udo Richter and Marcel Wiesweg -void TeletextDecoderVBIEBU::DecodeTeletext(const UCHAR* buffer, unsigned int field) //needs to be exactly 42 byte long!! -{ - UCHAR hdrbuf[5]; - for (int i=0;i<5;i++) hdrbuf[i]=(unhamtab[buffer[2*i]]&0xF) | ((unhamtab[buffer[2*i+1]]&0xF)<< 4); - int header=hdrbuf[0]; - int magazin=header & 0x7; - int line = (header>>3) & 0x1f; - if (magazin==0) magazin=8; - if (line==0) - { - if (ourpage) { - gotcha=true; - inkeying=false; - RenderTeletextCode(false); - } else { - RenderTeletextCode(true); - } - int pagenumber=hdrbuf[1]; - int pagemagazin=magazin<<8 | pagenumber; - int pagesubnumber=(hdrbuf[2]) || ((hdrbuf[3]<<8) & 0x3f7f); - - if (pagemagazin == selectedpage) ourpage=true; - else ourpage=false; - if (isrecording) { - for (int i=0;i<10;i++) { - if (pagemagazin==record_pages[i]) break; - if (record_pages[i]==-1) { - record_pages[i]=pagemagazin; - break; - } - } - } - if (hdrbuf[3] &0x80) { //This is a subtitle - for (int i=0;i<10;i++) { - if (pagemagazin==record_pages[i]) break; - if (record_pages[i]==-1) { - record_pages[i]=pagemagazin; - break; - } - } - } - - - if (ourpage) { - lang=((hdrbuf[4]>>5) & 0x07); - flags=hdrbuf[2] & 0x80; - flags|=(hdrbuf[3]&0x40)|((hdrbuf[3]>>2)&0x20); //?????? - flags|=((hdrbuf[4]<<4)&0x10)|((hdrbuf[4]<<2)&0x08)|(hdrbuf[4]&0x04)|((hdrbuf[4]>>1)&0x02)|((hdrbuf[4]>>4)&0x01); - for (int i=0;i<25;i++) { - memset(curpage[i],0,40); - } - } - - memcpy(curpage[line],buffer+2,40); - } else if (ourpage && (line<=25)) { - memcpy(curpage[line],buffer+2,40); - - } -} - - -/* from osdteletext plugin: (slightly adapted for vomp)*/ -// Font tables - -// teletext uses 7-bit numbers to identify a font set. -// There are three font sets involved: -// Primary G0, Secondary G0, and G2 font set. - -// Font tables are organized in blocks of 8 fonts: - -enumCharsets FontBlockG0_0000[8] = { - CHARSET_LATIN_G0_EN, - CHARSET_LATIN_G0_DE, - CHARSET_LATIN_G0_SV_FI, - CHARSET_LATIN_G0_IT, - CHARSET_LATIN_G0_FR, - CHARSET_LATIN_G0_PT_ES, - CHARSET_LATIN_G0_CZ_SK, - CHARSET_LATIN_G0 -}; - -enumCharsets FontBlockG2Latin[8]={ - CHARSET_LATIN_G2, - CHARSET_LATIN_G2, - CHARSET_LATIN_G2, - CHARSET_LATIN_G2, - CHARSET_LATIN_G2, - CHARSET_LATIN_G2, - CHARSET_LATIN_G2, - CHARSET_LATIN_G2 -}; - -enumCharsets FontBlockG0_0001[8] = { - CHARSET_LATIN_G0_PL, - CHARSET_LATIN_G0_DE, - CHARSET_LATIN_G0_SV_FI, - CHARSET_LATIN_G0_IT, - CHARSET_LATIN_G0_FR, - CHARSET_LATIN_G0, - CHARSET_LATIN_G0_CZ_SK, - CHARSET_LATIN_G0 -}; - -enumCharsets FontBlockG0_0010[8] = { - CHARSET_LATIN_G0_EN, - CHARSET_LATIN_G0_DE, - CHARSET_LATIN_G0_SV_FI, - CHARSET_LATIN_G0_IT, - CHARSET_LATIN_G0_FR, - CHARSET_LATIN_G0_PT_ES, - CHARSET_LATIN_G0_TR, - CHARSET_LATIN_G0 -}; - - -enumCharsets FontBlockG0_0011[8] = { - CHARSET_LATIN_G0, - CHARSET_LATIN_G0, - CHARSET_LATIN_G0, - CHARSET_LATIN_G0, - CHARSET_LATIN_G0, - CHARSET_LATIN_G0_SR_HR_SL, - CHARSET_LATIN_G0, - CHARSET_LATIN_G0_RO -}; - -enumCharsets FontBlockG0_0100[8] = { - CHARSET_CYRILLIC_G0_SR_HR, - CHARSET_LATIN_G0_DE, - CHARSET_LATIN_G0_EE, - CHARSET_LATIN_G0_LV_LT, - CHARSET_CYRILLIC_G0_RU_BG, - CHARSET_CYRILLIC_G0_UK, - CHARSET_LATIN_G0_CZ_SK, - CHARSET_INVALID -}; - -enumCharsets FontBlockG2_0100[8] = { - CHARSET_CYRILLIC_G2, - CHARSET_LATIN_G2, - CHARSET_LATIN_G2, - CHARSET_LATIN_G2, - CHARSET_CYRILLIC_G2, - CHARSET_CYRILLIC_G2, - CHARSET_LATIN_G2, - CHARSET_INVALID -}; - -enumCharsets FontBlockG0_0110[8] = { - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_LATIN_G0_TR, - CHARSET_GREEK_G0 -}; - -enumCharsets FontBlockG2_0110[8] = { - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_LATIN_G2, - CHARSET_GREEK_G2 -}; - -enumCharsets FontBlockG0_1000[8] = { - CHARSET_LATIN_G0_EN, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_LATIN_G0_FR, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_ARABIC_G0 -}; - -enumCharsets FontBlockG2_1000[8] = { - CHARSET_ARABIC_G2, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_ARABIC_G2, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_ARABIC_G2 -}; - -enumCharsets FontBlockG0_1010[8] = { - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_HEBREW_G0, - CHARSET_INVALID, - CHARSET_ARABIC_G0, -}; - -enumCharsets FontBlockG2_1010[8] = { - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_ARABIC_G2, - CHARSET_INVALID, - CHARSET_ARABIC_G2, -}; - -enumCharsets FontBlockInvalid[8] = { - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID, - CHARSET_INVALID -}; - - - -// The actual font table definition: -// Split the 7-bit number into upper 4 and lower 3 bits, -// use upper 4 bits for outer array, -// use lower 3 bits for inner array - -struct structFontBlock { - enumCharsets *G0Block; - enumCharsets *G2Block; -}; - -structFontBlock FontTable[16] = { - { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block - { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block - { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block - { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block - { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block - { FontBlockInvalid, FontBlockInvalid }, // 0101 block - { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block - { FontBlockInvalid, FontBlockInvalid }, // 0111 block - { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block - { FontBlockInvalid, FontBlockInvalid }, // 1001 block - { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block - { FontBlockInvalid, FontBlockInvalid }, // 1011 block - { FontBlockInvalid, FontBlockInvalid }, // 1100 block - { FontBlockInvalid, FontBlockInvalid }, // 1101 block - { FontBlockInvalid, FontBlockInvalid }, // 1110 block - { FontBlockInvalid, FontBlockInvalid } // 1111 block -}; - -inline enumCharsets GetG0Charset(int codepage) { - return FontTable[codepage>>3].G0Block[codepage&7]; -} -inline enumCharsets GetG2Charset(int codepage) { - return FontTable[codepage>>3].G2Block[codepage&7]; -} - -enum enumSizeMode { - // Possible size modifications of characters - sizeNormal, - sizeDoubleWidth, - sizeDoubleHeight, - sizeDoubleSize -}; - -void TeletextDecoderVBIEBU::RenderTeletextCode(bool renderfirstlineonly) { - int x,y; - bool EmptyNextLine=false; - // Skip one line, in case double height chars were/will be used - - // Get code pages: - int LocalG0CodePage=(FirstG0CodePage & 0x78) - | ((lang & 0x04)>>2) | (lang & 0x02) | ((lang & 0x01)<<2); - enumCharsets FirstG0=GetG0Charset(LocalG0CodePage); - enumCharsets SecondG0=GetG0Charset(SecondG0CodePage); - // Reserved for later use: - // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage); - - for (y=0;y<24;(EmptyNextLine?y+=2:y++)) { - // Start of line: Set start of line defaults - - // Hold Mosaics mode: Remember last mosaic char/charset - // for next spacing code - bool HoldMosaics=false; - unsigned char HoldMosaicChar=' '; - enumCharsets HoldMosaicCharset=FirstG0; - - enumSizeMode Size=sizeNormal; - // Font size modification - bool SecondCharset=false; - // Use primary or secondary G0 charset - bool GraphicCharset=false; - // Graphics charset used? - bool SeparateGraphics=false; - // Use separated vs. contiguous graphics charset - bool NoNextChar=false; - // Skip display of next char, for double-width - EmptyNextLine=false; - // Skip next line, for double-height - - cTeletextChar c; - // auto.initialized to everything off - c.SetFGColor(ttcWhite); - c.SetBGColor(ttcBlack); - c.SetCharset(FirstG0); - - if (y==0 && (flags&0x10)) { - if (!inkeying ) c.SetBoxedOut(true); - - } - if (flags&0x60) { - if (!(inkeying && y==0) ) c.SetBoxedOut(true); - - } - if (y==0) { - - for (x=0;x<8;x++) { - cTeletextChar c2=c; - - if (x>=3 && x<6){ - c2.SetChar(keyindigits[x-3]); - - } - else - c2.SetChar(' '); - setChar(x,0,c2); - } - } - - // Pre-scan for double-height and double-size codes - for (x=0;x<40;x++) { - if (y==0 && x<8) x=8; - if ((curpage[y][x] & 0x7f)==0x0D || (curpage[y][x] & 0x7f)==0x0F) - EmptyNextLine=true; - } - - // Move through line - for (x=0;x<40;x++) { - unsigned char ttc=curpage[y][x] & 0x7f; - // skip parity check - - if (y==0 && x<8) continue; - if (y==0 && x<31 && renderfirstlineonly && gotcha && !inkeying) continue; - // no displayable data here... - -/* // Debug only: Output line data and spacing codes - if (y==6) { - if (ttc<0x20) - printf("%s ",names[ttc]); - else - printf("%02x ",ttc); - if (x==39) printf("\n"); - } -*/ - - // Handle all 'Set-At' spacing codes - switch (ttc) { - case 0x09: // Steady - c.SetBlink(false); - break; - case 0x0C: // Normal Size - if (Size!=sizeNormal) { - Size=sizeNormal; - HoldMosaicChar=' '; - HoldMosaicCharset=FirstG0; - } - break; - case 0x18: // Conceal - c.SetConceal(true); - break; - case 0x19: // Contiguous Mosaic Graphics - SeparateGraphics=false; - if (GraphicCharset) - c.SetCharset(CHARSET_GRAPHICS_G1); - break; - case 0x1A: // Separated Mosaic Graphics - SeparateGraphics=true; - if (GraphicCharset) - c.SetCharset(CHARSET_GRAPHICS_G1_SEP); - break; - case 0x1C: // Black Background - c.SetBGColor(ttcBlack); - break; - case 0x1D: // New Background - c.SetBGColor(c.GetFGColor()); - break; - case 0x1E: // Hold Mosaic - HoldMosaics=true; - break; - } - - // temporary copy of character data: - cTeletextChar c2=c; - // c2 will be text character or space character or hold mosaic - // c2 may also have temporary flags or charsets - - if (ttc<0x20) { - // Spacing code, display space or hold mosaic - if (HoldMosaics) { - c2.SetChar(HoldMosaicChar); - c2.SetCharset(HoldMosaicCharset); - } else { - c2.SetChar(' '); - } - } else { - // Character code - c2.SetChar(ttc); - if (GraphicCharset) { - if (ttc&0x20) { - // real graphics code, remember for HoldMosaics - HoldMosaicChar=ttc; - HoldMosaicCharset=c.GetCharset(); - } else { - // invalid code, pass-through to G0 - c2.SetCharset(SecondCharset?SecondG0:FirstG0); - } - } - } - - // Handle double-height and double-width extremes - if (y>=23) { - if (Size==sizeDoubleHeight) Size=sizeNormal; - if (Size==sizeDoubleSize) Size=sizeDoubleWidth; - } - if (x>=38) { - if (Size==sizeDoubleWidth) Size=sizeNormal; - if (Size==sizeDoubleSize) Size=sizeDoubleHeight; - } - - // Now set character code - - if (NoNextChar) { - // Suppress this char due to double width last char - NoNextChar=false; - } else { - switch (Size) { - case sizeNormal: - // Normal sized - setChar(x,y,c2); - if (EmptyNextLine && y<23) { - // Clean up next line - setChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0)); - } - break; - case sizeDoubleWidth: - // Double width - setChar(x,y,c2.ToDblWidth(dblw_Left)); - setChar(x+1,y,c2.ToDblWidth(dblw_Right)); - if (EmptyNextLine && y<23) { - // Clean up next line - setChar(x ,y+1,c2.ToChar(' ').ToCharset(FirstG0)); - setChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0)); - } - NoNextChar=true; - break; - case sizeDoubleHeight: - // Double height - setChar(x,y,c2.ToDblHeight(dblh_Top)); - setChar(x,y+1,c2.ToDblHeight(dblh_Bottom)); - break; - case sizeDoubleSize: - // Double Size - setChar(x , y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Left )); - setChar(x+1, y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Right)); - setChar(x ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left )); - setChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right)); - NoNextChar=true; - break; - } - } - - // Handle all 'Set-After' spacing codes - if (ttc>=0x00 && ttc<=0x07) { // Set FG color - if (GraphicCharset) { - // Actual switch from graphics charset - HoldMosaicChar=' '; - HoldMosaicCharset=FirstG0; - } - c.SetFGColor((enumTeletextColor)ttc); - c.SetCharset(SecondCharset?SecondG0:FirstG0); - GraphicCharset=false; - c.SetConceal(false); - } else if (ttc==0x08) { - c.SetBlink(true); - } else if (ttc==0x0A) { - c.SetBoxedOut(true); - } else if (ttc==0x0B) { - // Start Box - c.SetBoxedOut(false); - } else if (ttc==0x0D) { - if (Size!=sizeDoubleHeight) { - Size=sizeDoubleHeight; - HoldMosaicChar=' '; - HoldMosaicCharset=FirstG0; - } - } else if (ttc==0x0E) { - if (Size!=sizeDoubleWidth) { - Size=sizeDoubleWidth; - HoldMosaicChar=' '; - HoldMosaicCharset=FirstG0; - } - } else if (ttc==0x0E) { - if (Size!=sizeDoubleSize) { - Size=sizeDoubleSize; - HoldMosaicChar=' '; - HoldMosaicCharset=FirstG0; - } - } else if (ttc>=0x10 && ttc<=0x17) { - if (!GraphicCharset) { - // Actual switch to graphics charset - HoldMosaicChar=' '; - HoldMosaicCharset=FirstG0; - } - c.SetFGColor((enumTeletextColor)(ttc-0x10)); - c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1); - GraphicCharset=true; - c.SetConceal(false); - } else if (ttc==0x1B) { - SecondCharset=!SecondCharset; - if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0); - } else if (ttc==0x1F) { - HoldMosaics=false; - } - - } // end for x - if (renderfirstlineonly) break; - } // end for y - - for (x=0;x<40;x++) { - // Clean out last line - cTeletextChar c; - c.SetFGColor(ttcWhite); - c.SetBGColor(ttcBlack); - c.SetCharset(FirstG0); - c.SetChar(' '); - if (flags&0x60) { - c.SetBoxedOut(true); - } - setChar(x,24,c); - } - for (y=0;y<25;y++) { - for (x=0;x<40;x++) { - if (isDirty(x,y)) { - dirty=true; - break; - } - if (dirty) break; - } - if (dirty) break; - } - - if (dirty && txtview!=NULL ) { - - if ( !renderfirstlineonly) { - Message* m= new Message(); - m->message = Message::TELETEXTUPDATE; - m->to = txtview; - m->from = this; - m->parameter = 0; - Command::getInstance()->postMessageFromOuterSpace(m); - } else if (firstlineupdate==10) { - Message* m= new Message(); - m->message = Message::TELETEXTUPDATEFIRSTLINE; - m->to = txtview; - m->from = this; - m->parameter = 0; - Command::getInstance()->postMessageFromOuterSpace(m); - firstlineupdate=0; - } else firstlineupdate++; - - - } - -} +/* + Copyright 2008 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +/* Portions from vdr osdteletext plugin "txtrender.c": */ +/*************************************************************************** + * * + * txtrender.c - Teletext display abstraction and teletext code * + * renderer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * Changelog: * + * 2005-03 initial version (c) Udo Richter * + * * + ***************************************************************************/ + +#include "teletextdecodervbiebu.h" +#include "teletxt/tables.h" +#include "message.h" +#include "command.h" +#include "video.h" + +#ifdef WIN32 +#include +#endif + +TeletextDecoderVBIEBU::TeletextDecoderVBIEBU() +{ + selectedpage=0x100; + ourpage=false; + flags=lang=0; + + CleanPage(); + FirstG0CodePage=0; + SecondG0CodePage=0; + dirty=false; + txtview=NULL; + firstlineupdate=0; + gotcha=false; + char digits[]={'1','0','0'}; + setKeyinDigits(digits,false); + isrecording=false; + for (int i=0;i<10;i++) record_pages[i]=-1; + + +} + +TeletextDecoderVBIEBU::~TeletextDecoderVBIEBU() +{ + + +} + +long long TeletextDecoderVBIEBU::SetStartOffset(long long curreftime, bool *rsync) +{ + return 0; +} + +void TeletextDecoderVBIEBU::ResetTimeOffsets() +{ + +} + + + +void TeletextDecoderVBIEBU::ResetDecoder() +{ + gotcha=false; + ourpage=false; + firstlineupdate=0; + selectedpage=0x100; + CleanPage(); + char digits[]={'1','0','0'}; + setKeyinDigits(digits,false); + for (int i=0;i<10;i++) record_pages[i]=-1; + +} + +void TeletextDecoderVBIEBU::setPage(unsigned int newpage) +{ + selectedpage=newpage; + gotcha=false; + ourpage=false; + firstlineupdate=0; + for (int i=0;i<25;i++) { + memset(curpage[i],0,40); + } +} + +void TeletextDecoderVBIEBU::CleanPage() +{ + int x,y; + for (int i=0;i<25;i++) { + memset(curpage[i],0,40); + } + for (y=0;y<25;y++) { + for (x=0;x<40;x++) { + cTeletextChar c; + c.SetFGColor(ttcWhite); + c.SetBGColor(ttcBlack); + c.SetCharset(CHARSET_LATIN_G0); + c.SetChar(' '); + if (flags&0x60) { + c.SetBoxedOut(true); + } + setChar(x,y,c); + } + } + +} +void TeletextDecoderVBIEBU::setKeyinDigits(char digits[3],bool inKeying) +{ + int x; + inkeying=inKeying; + for (x=0;x<3;x++) { + cTeletextChar c; + c.SetFGColor(ttcWhite); + c.SetBGColor(ttcBlack); + c.SetCharset(CHARSET_LATIN_G0); + c.SetChar(digits[x]); + if (flags&0x60) { + c.SetBoxedOut(true); + } + setChar(x+3,0,c); + keyindigits[x]=digits[x]; + } +} + +void TeletextDecoderVBIEBU::PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos) +{ + mediapacket = mplist.front(); +} + +static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2) +{ + // Assume pts1, pts2 < 2^33; calculate pts1 - pts2 + if (pts1 > pts2) + return pts1 - pts2; + else + return (1LL<<33) + pts1 - pts2; +} + +UINT TeletextDecoderVBIEBU::DeliverMediaSample(UCHAR* buffer, UINT *samplepos) +{ + if (mediapacket.type != MPTYPE_TELETEXT) + { + *samplepos= 0; + return 1; //Skip it! + } + unsigned int headerstrip; + unsigned char txtdata[43]; + headerstrip=buffer[mediapacket.pos_buffer+8]+9; + //headerstrip+=4; //substream id + unsigned int datapos=0; + unsigned int datatype=buffer[mediapacket.pos_buffer+headerstrip+0]; + //Chris should we use here the pts data from mediapacket ? + // in this case the data fields should also be added in mediamvp + if (mediapacket.synched) + { // An entry exists in the work list + ULLONG nowPTS = Video::getInstance()->getCurrentTimestamp(); + if (PTSDifference(mediapacket.pts, nowPTS) >= 1200*90000) { + *samplepos=0; + return 1;//bad data skip it + } + if (nowPTS < (mediapacket.pts-4000) ) { + *samplepos=0; + return 0; + } + } + + if (( datatype>=0x10 && datatype <=0x1F) || + ( datatype>=0x99 && datatype <=0x9B)) { + //EBU VBI DATA + datapos++; + while (datapos< (mediapacket.length-headerstrip)) { + unsigned int unit_id=buffer[mediapacket.pos_buffer+headerstrip+datapos]; + datapos++; + unsigned int unit_length=buffer[mediapacket.pos_buffer+headerstrip+datapos]; + datapos++; + switch (unit_id) { + case 0x02: + case 0x03: {//Teletext with and without subtitles + //call teletext decoder + unsigned int field=buffer[mediapacket.pos_buffer+headerstrip+datapos]; + + if ((datapos+44)< (mediapacket.length-headerstrip)) { + for (int i=0;i<42;i++) { + txtdata[i]=invtab[buffer[mediapacket.pos_buffer+headerstrip+datapos+2+i]]; + } + DecodeTeletext(txtdata,field); + } + }break; + case 0xC0: //inverted Teletext + //call teletext decoder + break; + + case 0xC3: //VPS + //what to do with this, in the moment we do not need it + break; + case 0xC4: //WSS + //what to do with this, in the moment we do not need it + break; + case 0xC5: //CC + //what to do with this, in the moment we do not need it + break; + case 0xC6: //monochrome 4:2:2 samples, what is that? + //what to do with this, in the moment we do not need it + break; + default: + // case 0x00,0x01,0x04..0x7f,0x80..0xbf,0xc1,0xc2,0xc7..0xfe,0xff: //discard + //discard + break; + }; + datapos+=unit_length; + // while (buffer[mediapacket.pos_buffer+headerstrip+datapos]==0xFF &&(datapos< (mediapacket.length-headerstrip))) { + // datapos++; //stuffing bytes + // } + + + } + *samplepos=0; + return 1; + + + } else { + *samplepos= 0; + return 1; //Skip it! and discard data + } + + return 0; + +} +// This part is inspired by the vdr-plugin-osdteletext of Udo Richter and Marcel Wiesweg +void TeletextDecoderVBIEBU::DecodeTeletext(const UCHAR* buffer, unsigned int field) //needs to be exactly 42 byte long!! +{ + UCHAR hdrbuf[5]; + for (int i=0;i<5;i++) hdrbuf[i]=(unhamtab[buffer[2*i]]&0xF) | ((unhamtab[buffer[2*i+1]]&0xF)<< 4); + int header=hdrbuf[0]; + int magazin=header & 0x7; + int line = (header>>3) & 0x1f; + if (magazin==0) magazin=8; + if (line==0) + { + if (ourpage) { + gotcha=true; + inkeying=false; + RenderTeletextCode(false); + } else { + RenderTeletextCode(true); + } + int pagenumber=hdrbuf[1]; + int pagemagazin=magazin<<8 | pagenumber; + int pagesubnumber=(hdrbuf[2]) || ((hdrbuf[3]<<8) & 0x3f7f); + + if (pagemagazin == selectedpage) ourpage=true; + else ourpage=false; + if (isrecording) { + for (int i=0;i<10;i++) { + if (pagemagazin==record_pages[i]) break; + if (record_pages[i]==-1) { + record_pages[i]=pagemagazin; + break; + } + } + } + if (hdrbuf[3] &0x80) { //This is a subtitle + for (int i=0;i<10;i++) { + if (pagemagazin==record_pages[i]) break; + if (record_pages[i]==-1) { + record_pages[i]=pagemagazin; + break; + } + } + } + + + if (ourpage) { + lang=((hdrbuf[4]>>5) & 0x07); + flags=hdrbuf[2] & 0x80; + flags|=(hdrbuf[3]&0x40)|((hdrbuf[3]>>2)&0x20); //?????? + flags|=((hdrbuf[4]<<4)&0x10)|((hdrbuf[4]<<2)&0x08)|(hdrbuf[4]&0x04)|((hdrbuf[4]>>1)&0x02)|((hdrbuf[4]>>4)&0x01); + for (int i=0;i<25;i++) { + memset(curpage[i],0,40); + } + } + + memcpy(curpage[line],buffer+2,40); + } else if (ourpage && (line<=25)) { + memcpy(curpage[line],buffer+2,40); + + } +} + + +/* from osdteletext plugin: (slightly adapted for vomp)*/ +// Font tables + +// teletext uses 7-bit numbers to identify a font set. +// There are three font sets involved: +// Primary G0, Secondary G0, and G2 font set. + +// Font tables are organized in blocks of 8 fonts: + +enumCharsets FontBlockG0_0000[8] = { + CHARSET_LATIN_G0_EN, + CHARSET_LATIN_G0_DE, + CHARSET_LATIN_G0_SV_FI, + CHARSET_LATIN_G0_IT, + CHARSET_LATIN_G0_FR, + CHARSET_LATIN_G0_PT_ES, + CHARSET_LATIN_G0_CZ_SK, + CHARSET_LATIN_G0 +}; + +enumCharsets FontBlockG2Latin[8]={ + CHARSET_LATIN_G2, + CHARSET_LATIN_G2, + CHARSET_LATIN_G2, + CHARSET_LATIN_G2, + CHARSET_LATIN_G2, + CHARSET_LATIN_G2, + CHARSET_LATIN_G2, + CHARSET_LATIN_G2 +}; + +enumCharsets FontBlockG0_0001[8] = { + CHARSET_LATIN_G0_PL, + CHARSET_LATIN_G0_DE, + CHARSET_LATIN_G0_SV_FI, + CHARSET_LATIN_G0_IT, + CHARSET_LATIN_G0_FR, + CHARSET_LATIN_G0, + CHARSET_LATIN_G0_CZ_SK, + CHARSET_LATIN_G0 +}; + +enumCharsets FontBlockG0_0010[8] = { + CHARSET_LATIN_G0_EN, + CHARSET_LATIN_G0_DE, + CHARSET_LATIN_G0_SV_FI, + CHARSET_LATIN_G0_IT, + CHARSET_LATIN_G0_FR, + CHARSET_LATIN_G0_PT_ES, + CHARSET_LATIN_G0_TR, + CHARSET_LATIN_G0 +}; + + +enumCharsets FontBlockG0_0011[8] = { + CHARSET_LATIN_G0, + CHARSET_LATIN_G0, + CHARSET_LATIN_G0, + CHARSET_LATIN_G0, + CHARSET_LATIN_G0, + CHARSET_LATIN_G0_SR_HR_SL, + CHARSET_LATIN_G0, + CHARSET_LATIN_G0_RO +}; + +enumCharsets FontBlockG0_0100[8] = { + CHARSET_CYRILLIC_G0_SR_HR, + CHARSET_LATIN_G0_DE, + CHARSET_LATIN_G0_EE, + CHARSET_LATIN_G0_LV_LT, + CHARSET_CYRILLIC_G0_RU_BG, + CHARSET_CYRILLIC_G0_UK, + CHARSET_LATIN_G0_CZ_SK, + CHARSET_INVALID +}; + +enumCharsets FontBlockG2_0100[8] = { + CHARSET_CYRILLIC_G2, + CHARSET_LATIN_G2, + CHARSET_LATIN_G2, + CHARSET_LATIN_G2, + CHARSET_CYRILLIC_G2, + CHARSET_CYRILLIC_G2, + CHARSET_LATIN_G2, + CHARSET_INVALID +}; + +enumCharsets FontBlockG0_0110[8] = { + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_LATIN_G0_TR, + CHARSET_GREEK_G0 +}; + +enumCharsets FontBlockG2_0110[8] = { + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_LATIN_G2, + CHARSET_GREEK_G2 +}; + +enumCharsets FontBlockG0_1000[8] = { + CHARSET_LATIN_G0_EN, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_LATIN_G0_FR, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_ARABIC_G0 +}; + +enumCharsets FontBlockG2_1000[8] = { + CHARSET_ARABIC_G2, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_ARABIC_G2, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_ARABIC_G2 +}; + +enumCharsets FontBlockG0_1010[8] = { + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_HEBREW_G0, + CHARSET_INVALID, + CHARSET_ARABIC_G0, +}; + +enumCharsets FontBlockG2_1010[8] = { + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_ARABIC_G2, + CHARSET_INVALID, + CHARSET_ARABIC_G2, +}; + +enumCharsets FontBlockInvalid[8] = { + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID, + CHARSET_INVALID +}; + + + +// The actual font table definition: +// Split the 7-bit number into upper 4 and lower 3 bits, +// use upper 4 bits for outer array, +// use lower 3 bits for inner array + +struct structFontBlock { + enumCharsets *G0Block; + enumCharsets *G2Block; +}; + +structFontBlock FontTable[16] = { + { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block + { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block + { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block + { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block + { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block + { FontBlockInvalid, FontBlockInvalid }, // 0101 block + { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block + { FontBlockInvalid, FontBlockInvalid }, // 0111 block + { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block + { FontBlockInvalid, FontBlockInvalid }, // 1001 block + { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block + { FontBlockInvalid, FontBlockInvalid }, // 1011 block + { FontBlockInvalid, FontBlockInvalid }, // 1100 block + { FontBlockInvalid, FontBlockInvalid }, // 1101 block + { FontBlockInvalid, FontBlockInvalid }, // 1110 block + { FontBlockInvalid, FontBlockInvalid } // 1111 block +}; + +inline enumCharsets GetG0Charset(int codepage) { + return FontTable[codepage>>3].G0Block[codepage&7]; +} +inline enumCharsets GetG2Charset(int codepage) { + return FontTable[codepage>>3].G2Block[codepage&7]; +} + +enum enumSizeMode { + // Possible size modifications of characters + sizeNormal, + sizeDoubleWidth, + sizeDoubleHeight, + sizeDoubleSize +}; + +void TeletextDecoderVBIEBU::RenderTeletextCode(bool renderfirstlineonly) { + int x,y; + bool EmptyNextLine=false; + // Skip one line, in case double height chars were/will be used + + // Get code pages: + int LocalG0CodePage=(FirstG0CodePage & 0x78) + | ((lang & 0x04)>>2) | (lang & 0x02) | ((lang & 0x01)<<2); + enumCharsets FirstG0=GetG0Charset(LocalG0CodePage); + enumCharsets SecondG0=GetG0Charset(SecondG0CodePage); + // Reserved for later use: + // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage); + + for (y=0;y<24;(EmptyNextLine?y+=2:y++)) { + // Start of line: Set start of line defaults + + // Hold Mosaics mode: Remember last mosaic char/charset + // for next spacing code + bool HoldMosaics=false; + unsigned char HoldMosaicChar=' '; + enumCharsets HoldMosaicCharset=FirstG0; + + enumSizeMode Size=sizeNormal; + // Font size modification + bool SecondCharset=false; + // Use primary or secondary G0 charset + bool GraphicCharset=false; + // Graphics charset used? + bool SeparateGraphics=false; + // Use separated vs. contiguous graphics charset + bool NoNextChar=false; + // Skip display of next char, for double-width + EmptyNextLine=false; + // Skip next line, for double-height + + cTeletextChar c; + // auto.initialized to everything off + c.SetFGColor(ttcWhite); + c.SetBGColor(ttcBlack); + c.SetCharset(FirstG0); + + if (y==0 && (flags&0x10)) { + if (!inkeying ) c.SetBoxedOut(true); + + } + if (flags&0x60) { + if (!(inkeying && y==0) ) c.SetBoxedOut(true); + + } + if (y==0) { + + for (x=0;x<8;x++) { + cTeletextChar c2=c; + + if (x>=3 && x<6){ + c2.SetChar(keyindigits[x-3]); + + } + else + c2.SetChar(' '); + setChar(x,0,c2); + } + } + + // Pre-scan for double-height and double-size codes + for (x=0;x<40;x++) { + if (y==0 && x<8) x=8; + if ((curpage[y][x] & 0x7f)==0x0D || (curpage[y][x] & 0x7f)==0x0F) + EmptyNextLine=true; + } + + // Move through line + for (x=0;x<40;x++) { + unsigned char ttc=curpage[y][x] & 0x7f; + // skip parity check + + if (y==0 && x<8) continue; + if (y==0 && x<31 && renderfirstlineonly && gotcha && !inkeying) continue; + // no displayable data here... + +/* // Debug only: Output line data and spacing codes + if (y==6) { + if (ttc<0x20) + printf("%s ",names[ttc]); + else + printf("%02x ",ttc); + if (x==39) printf("\n"); + } +*/ + + // Handle all 'Set-At' spacing codes + switch (ttc) { + case 0x09: // Steady + c.SetBlink(false); + break; + case 0x0C: // Normal Size + if (Size!=sizeNormal) { + Size=sizeNormal; + HoldMosaicChar=' '; + HoldMosaicCharset=FirstG0; + } + break; + case 0x18: // Conceal + c.SetConceal(true); + break; + case 0x19: // Contiguous Mosaic Graphics + SeparateGraphics=false; + if (GraphicCharset) + c.SetCharset(CHARSET_GRAPHICS_G1); + break; + case 0x1A: // Separated Mosaic Graphics + SeparateGraphics=true; + if (GraphicCharset) + c.SetCharset(CHARSET_GRAPHICS_G1_SEP); + break; + case 0x1C: // Black Background + c.SetBGColor(ttcBlack); + break; + case 0x1D: // New Background + c.SetBGColor(c.GetFGColor()); + break; + case 0x1E: // Hold Mosaic + HoldMosaics=true; + break; + } + + // temporary copy of character data: + cTeletextChar c2=c; + // c2 will be text character or space character or hold mosaic + // c2 may also have temporary flags or charsets + + if (ttc<0x20) { + // Spacing code, display space or hold mosaic + if (HoldMosaics) { + c2.SetChar(HoldMosaicChar); + c2.SetCharset(HoldMosaicCharset); + } else { + c2.SetChar(' '); + } + } else { + // Character code + c2.SetChar(ttc); + if (GraphicCharset) { + if (ttc&0x20) { + // real graphics code, remember for HoldMosaics + HoldMosaicChar=ttc; + HoldMosaicCharset=c.GetCharset(); + } else { + // invalid code, pass-through to G0 + c2.SetCharset(SecondCharset?SecondG0:FirstG0); + } + } + } + + // Handle double-height and double-width extremes + if (y>=23) { + if (Size==sizeDoubleHeight) Size=sizeNormal; + if (Size==sizeDoubleSize) Size=sizeDoubleWidth; + } + if (x>=38) { + if (Size==sizeDoubleWidth) Size=sizeNormal; + if (Size==sizeDoubleSize) Size=sizeDoubleHeight; + } + + // Now set character code + + if (NoNextChar) { + // Suppress this char due to double width last char + NoNextChar=false; + } else { + switch (Size) { + case sizeNormal: + // Normal sized + setChar(x,y,c2); + if (EmptyNextLine && y<23) { + // Clean up next line + setChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0)); + } + break; + case sizeDoubleWidth: + // Double width + setChar(x,y,c2.ToDblWidth(dblw_Left)); + setChar(x+1,y,c2.ToDblWidth(dblw_Right)); + if (EmptyNextLine && y<23) { + // Clean up next line + setChar(x ,y+1,c2.ToChar(' ').ToCharset(FirstG0)); + setChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0)); + } + NoNextChar=true; + break; + case sizeDoubleHeight: + // Double height + setChar(x,y,c2.ToDblHeight(dblh_Top)); + setChar(x,y+1,c2.ToDblHeight(dblh_Bottom)); + break; + case sizeDoubleSize: + // Double Size + setChar(x , y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Left )); + setChar(x+1, y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Right)); + setChar(x ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left )); + setChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right)); + NoNextChar=true; + break; + } + } + + // Handle all 'Set-After' spacing codes + if (ttc>=0x00 && ttc<=0x07) { // Set FG color + if (GraphicCharset) { + // Actual switch from graphics charset + HoldMosaicChar=' '; + HoldMosaicCharset=FirstG0; + } + c.SetFGColor((enumTeletextColor)ttc); + c.SetCharset(SecondCharset?SecondG0:FirstG0); + GraphicCharset=false; + c.SetConceal(false); + } else if (ttc==0x08) { + c.SetBlink(true); + } else if (ttc==0x0A) { + c.SetBoxedOut(true); + } else if (ttc==0x0B) { + // Start Box + c.SetBoxedOut(false); + } else if (ttc==0x0D) { + if (Size!=sizeDoubleHeight) { + Size=sizeDoubleHeight; + HoldMosaicChar=' '; + HoldMosaicCharset=FirstG0; + } + } else if (ttc==0x0E) { + if (Size!=sizeDoubleWidth) { + Size=sizeDoubleWidth; + HoldMosaicChar=' '; + HoldMosaicCharset=FirstG0; + } + } else if (ttc==0x0E) { + if (Size!=sizeDoubleSize) { + Size=sizeDoubleSize; + HoldMosaicChar=' '; + HoldMosaicCharset=FirstG0; + } + } else if (ttc>=0x10 && ttc<=0x17) { + if (!GraphicCharset) { + // Actual switch to graphics charset + HoldMosaicChar=' '; + HoldMosaicCharset=FirstG0; + } + c.SetFGColor((enumTeletextColor)(ttc-0x10)); + c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1); + GraphicCharset=true; + c.SetConceal(false); + } else if (ttc==0x1B) { + SecondCharset=!SecondCharset; + if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0); + } else if (ttc==0x1F) { + HoldMosaics=false; + } + + } // end for x + if (renderfirstlineonly) break; + } // end for y + + for (x=0;x<40;x++) { + // Clean out last line + cTeletextChar c; + c.SetFGColor(ttcWhite); + c.SetBGColor(ttcBlack); + c.SetCharset(FirstG0); + c.SetChar(' '); + if (flags&0x60) { + c.SetBoxedOut(true); + } + setChar(x,24,c); + } + for (y=0;y<25;y++) { + for (x=0;x<40;x++) { + if (isDirty(x,y)) { + dirty=true; + break; + } + if (dirty) break; + } + if (dirty) break; + } + + if (dirty && txtview!=NULL ) { + + if ( !renderfirstlineonly) { + Message* m= new Message(); + m->message = Message::TELETEXTUPDATE; + m->to = txtview; + m->from = this; + m->parameter = 0; + Command::getInstance()->postMessageFromOuterSpace(m); + } else if (firstlineupdate==10) { + Message* m= new Message(); + m->message = Message::TELETEXTUPDATEFIRSTLINE; + m->to = txtview; + m->from = this; + m->parameter = 0; + Command::getInstance()->postMessageFromOuterSpace(m); + firstlineupdate=0; + } else firstlineupdate++; + + + } + +} diff --git a/teletextdecodervbiebu.h b/teletextdecodervbiebu.h index 0566a40..123486b 100644 --- a/teletextdecodervbiebu.h +++ b/teletextdecodervbiebu.h @@ -1,330 +1,330 @@ -/* - Copyright 2008 Marten Richter - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -/* Portions from vdr osdteletext plugin "txtrender.c": */ -/*************************************************************************** - * * - * txtrender.h - Teletext display abstraction and teletext code * - * renderer * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * Changelog: * - * 2005-03 initial version (c) Udo Richter * - * * - ***************************************************************************/ - -#ifndef TXTDECVBIEBU_H -#define TXTDECVBIEBU_H - -#include "draintarget.h" -#include "log.h" - -/* from osdteletext begin */ - -// Teletext character sets -enum enumCharsets { - CHARSET_LATIN_G0 = 0x0000, // native latin (partially todo) - CHARSET_LATIN_G0_CZ_SK = 0x0100, // Czech/Slovak (todo) - CHARSET_LATIN_G0_EN = 0x0200, // English - CHARSET_LATIN_G0_EE = 0x0300, // Estonian (todo) - CHARSET_LATIN_G0_FR = 0x0400, // French - CHARSET_LATIN_G0_DE = 0x0500, // German - CHARSET_LATIN_G0_IT = 0x0600, // Italian - CHARSET_LATIN_G0_LV_LT = 0x0700, // Lettish/Lithuanian (todo) - CHARSET_LATIN_G0_PL = 0x0800, // Polish (todo) - CHARSET_LATIN_G0_PT_ES = 0x0900, // Portugese/Spanish - CHARSET_LATIN_G0_RO = 0x0A00, // Romanian (todo) - CHARSET_LATIN_G0_SR_HR_SL = 0x0B00, // Serbian/Croatian/Slovenian (todo) - CHARSET_LATIN_G0_SV_FI = 0x0C00, // Swedish/Finnish - CHARSET_LATIN_G0_TR = 0x0D00, // Turkish (todo) - CHARSET_LATIN_G2 = 0x0E00, // Latin G2 supplementary set (todo) - CHARSET_CYRILLIC_G0_SR_HR = 0x0F00, // Serbian/Croatian (todo) - CHARSET_CYRILLIC_G0_RU_BG = 0x1000, // Russian/Bulgarian (todo) - CHARSET_CYRILLIC_G0_UK = 0x1100, // Ukrainian (todo) - CHARSET_CYRILLIC_G2 = 0x1200, // Cyrillic G2 Supplementary (todo) - CHARSET_GREEK_G0 = 0x1300, // Greek G0 (todo) - CHARSET_GREEK_G2 = 0x1400, // Greeek G2 (todo) - CHARSET_ARABIC_G0 = 0x1500, // Arabic G0 (todo) - CHARSET_ARABIC_G2 = 0x1600, // Arabic G2 (todo) - CHARSET_HEBREW_G0 = 0x1700, // Hebrew G0 (todo) - CHARSET_GRAPHICS_G1 = 0x1800, // G1 graphics set - CHARSET_GRAPHICS_G1_SEP = 0x1900, // G1 graphics set, separated - CHARSET_GRAPHICS_G3 = 0x1A00, // G3 graphics set (todo) - CHARSET_INVALID = 0x1F00 // no charset defined -}; - -// Macro to get the lowest non-0 bit position from a bit mask -// Should evaluate to const on a const mask -#define LowestSet2Bit(mask) ((mask)&0x0001?0:1) -#define LowestSet4Bit(mask) ((mask)&0x0003?LowestSet2Bit(mask):LowestSet2Bit((mask)>>2)+2) -#define LowestSet8Bit(mask) ((mask)&0x000f?LowestSet4Bit(mask):LowestSet4Bit((mask)>>4)+4) -#define LowestSet16Bit(mask) ((mask)&0x00ff?LowestSet8Bit(mask):LowestSet8Bit((mask)>>8)+8) -#define LowestSet32Bit(mask) ((mask)&0xffff?LowestSet16Bit(mask):LowestSet16Bit((mask)>>16)+16) - - -// Character modifcation double height: -enum enumDblHeight { - dblh_Normal=0x00000000, // normal height - dblh_Top =0x04000000, // upper half character - dblh_Bottom=0x08000000 // lower half character -}; -// Character modifcation double width: -enum enumDblWidth { - dblw_Normal=0x00000000, // normal width - dblw_Left =0x10000000, // left half character - dblw_Right =0x20000000 // right half character -}; - -// Teletext colors -enum enumTeletextColor { - // level 1: - ttcBlack=0, - ttcRed=1, - ttcGreen=2, - ttcYellow=3, - ttcBlue=4, - ttcMagenta=5, - ttcCyan=6, - ttcWhite=7, - // level 2.5: - ttcTransparent=8, - ttcHalfRed=9, - ttcHalfGreen=10, - ttcHalfYellow=11, - ttcHalfBlue=12, - ttcHalfMagenta=13, - ttcHalfCyan=14, - ttcGrey=15, - // unnamed, level 2.5: - ttcColor16=16, ttcColor17=17, ttcColor18=18, ttcColor19=19, - ttcColor20=20, ttcColor21=21, ttcColor22=22, ttcColor23=23, - ttcColor24=24, ttcColor25=25, ttcColor26=26, ttcColor27=27, - ttcColor28=28, ttcColor29=29, ttcColor30=30, ttcColor31=31, - - ttcFirst=0, ttcLast=31 -}; -inline enumTeletextColor& operator++(enumTeletextColor& c) { return c=enumTeletextColor(int(c)+1); } -inline enumTeletextColor operator++(enumTeletextColor& c, int) { enumTeletextColor tmp(c); ++c; return tmp; } - -class cTeletextChar { - // Wrapper class that represents a teletext character, - // including colors and effects. Should optimize back - // to 4 byte unsigned int on compile. - -protected: - unsigned int c; - - static const unsigned int CHAR = 0x000000FF; - // character code - static const unsigned int CHARSET = 0x00001F00; - // character set code, see below - static const unsigned int BOXOUT = 0x00004000; - // 'boxed' mode hidden area - static const unsigned int DIRTY = 0x00008000; - // 'dirty' bit - internal marker only - static const unsigned int FGCOLOR = 0x001F0000; - // 5-bit foreground color code, 3 bit used for now - static const unsigned int BGCOLOR = 0x03E00000; - // 5-bit background color code, 3 bit used for now - static const unsigned int DBLHEIGHT = 0x0C000000; - // show double height - static const unsigned int DBLWIDTH = 0x30000000; - // show double width (todo) - static const unsigned int CONCEAL = 0x40000000; - // character concealed - static const unsigned int BLINK = 0x80000000; - // blinking character - - cTeletextChar(unsigned int cc) { c=cc; } - -public: - cTeletextChar() { c=0; } - - // inline helper functions: - // For each parameter encoded into the 32-bit int, there is - // a Get...() to read, a Set...() to write, and a To...() to - // return a modified copy - - inline unsigned char GetChar() - { return c&CHAR; } - inline void SetChar(unsigned char chr) - { c=(c&~CHAR)|chr; } - inline cTeletextChar ToChar(unsigned char chr) - { return cTeletextChar((c&~CHAR)|chr); } - - inline enumCharsets GetCharset() - { return (enumCharsets)(c&CHARSET); } - inline void SetCharset(enumCharsets charset) - { c=(c&~CHARSET)|charset; } - inline cTeletextChar ToCharset(enumCharsets charset) - { return cTeletextChar((c&~CHARSET)|charset); } - - inline enumTeletextColor GetFGColor() - { return (enumTeletextColor)((c&FGCOLOR) >> LowestSet32Bit(FGCOLOR)); } - inline void SetFGColor(enumTeletextColor fgc) - { c=(c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR)); } - inline cTeletextChar ToFGColor(enumTeletextColor fgc) - { return cTeletextChar((c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR))); } - - inline enumTeletextColor GetBGColor() - { return (enumTeletextColor)((c&BGCOLOR) >> LowestSet32Bit(BGCOLOR)); } - inline void SetBGColor(enumTeletextColor bgc) - { c=(c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR)); } - inline cTeletextChar ToBGColor(enumTeletextColor bgc) - { return cTeletextChar((c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR))); } - - inline bool GetBoxedOut() - { return c&BOXOUT; } - inline void SetBoxedOut(bool BoxedOut) - { c=(BoxedOut)?(c|BOXOUT):(c&~BOXOUT); } - inline cTeletextChar ToBoxedOut(bool BoxedOut) - { return cTeletextChar((BoxedOut)?(c|BOXOUT):(c&~BOXOUT)); } - - inline bool GetDirty() - { return c&DIRTY; } - inline void SetDirty(bool Dirty) - { c=(Dirty)?(c|DIRTY):(c&~DIRTY); } - inline cTeletextChar ToDirty(bool Dirty) - { return cTeletextChar((Dirty)?(c|DIRTY):(c&~DIRTY)); } - - inline enumDblHeight GetDblHeight() - { return (enumDblHeight)(c&DBLHEIGHT); } - inline void SetDblHeight(enumDblHeight dh) - { c=(c&~(DBLHEIGHT)) | dh; } - inline cTeletextChar ToDblHeight(enumDblHeight dh) - { return cTeletextChar((c&~(DBLHEIGHT)) | dh); } - - inline enumDblWidth GetDblWidth() - { return (enumDblWidth)(c&DBLWIDTH); } - inline void SetDblWidth(enumDblWidth dw) - { c=(c&~(DBLWIDTH)) | dw; } - inline cTeletextChar ToDblWidth(enumDblWidth dw) - { return cTeletextChar((c&~(DBLWIDTH)) | dw); } - - inline bool GetConceal() - { return c&CONCEAL; } - inline void SetConceal(bool Conceal) - { c=(Conceal)?(c|CONCEAL):(c&~CONCEAL); } - inline cTeletextChar ToConceal(bool Conceal) - { return cTeletextChar((Conceal)?(c|CONCEAL):(c&~CONCEAL)); } - - inline bool GetBlink() - { return c&BLINK; } - inline void SetBlink(bool Blink) - { c=(Blink)?(c|BLINK):(c&~BLINK); } - inline cTeletextChar ToBlink(bool Blink) - { return cTeletextChar((Blink)?(c|BLINK):(c&~BLINK)); } - - bool operator==(cTeletextChar &chr) { return c==chr.c; } - bool operator!=(cTeletextChar &chr) { return c!=chr.c; } -}; -/* from osdteletext end*/ - -class VTeletextView; - -/* Decoder of teletext matrial present in Data stream for VBI reinsertion more or less according to EBU specs*/ -class TeletextDecoderVBIEBU: public DrainTarget { -public: - TeletextDecoderVBIEBU(); - virtual ~TeletextDecoderVBIEBU(); - - virtual long long SetStartOffset(long long curreftime, bool *rsync); - virtual void ResetTimeOffsets(); - - void ResetDecoder(); - void setKeyinDigits(char digits[3],bool inKeying); - void setPage(unsigned int newpage); - int getPage() {return selectedpage;}; - void setRecordigMode(bool isrecord) {isrecording=isrecord;}; - int *getSubtitlePages() {return record_pages;}; - - - virtual void PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos); - virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos); - - void registerTeletextView(VTeletextView* view) {txtview=view;}; - void unRegisterTeletextView(VTeletextView* view) {if (txtview==view) txtview=NULL;}; - VTeletextView* getTeletxtView() {return txtview;}; - - cTeletextChar getChar(int x, int y) { - // Read character content from page - if (x<0 || x>=40 || y<0 || y>=25) { - Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds read access to teletext page"); - return cTeletextChar(); - } - return Page[x][y].ToDirty(false); - } - bool isDirty(int x, int y) { - if (x<0 || x>=40 || y<0 || y>=25) { - Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds dirty access to teletext page"); - return false; - } - return Page[x][y].GetDirty(); - } - void setChar(int x, int y, cTeletextChar c) { - // Set character at given location - - if (x<0 || x>=40 || y<0 || y>=25) { - Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds write access to teletext page"); - return; - } - if (getChar(x,y) != c) { - Page[x][y]=c.ToDirty(true); - dirty=true; - } - } - - -protected: - void DecodeTeletext(const UCHAR* buffer, unsigned int field); - void RenderTeletextCode(bool renderfirstlineonly); - void CleanPage(); - - int selectedpage; - int lang; - int flags; - UCHAR curpage[25][40]; //Line DataCache - cTeletextChar Page[40][25]; - char keyindigits[3]; - - - // Font Code pages - int FirstG0CodePage; // 7-bit number, lower 3 bits ignored - int SecondG0CodePage; // 7-bit number - - bool ourpage; - bool dirty; - bool gotcha; - bool inkeying; - bool isrecording; - int record_pages[10];//Only 10 Pages per record; - unsigned int firstlineupdate; - VTeletextView *txtview; -private: - MediaPacket mediapacket; - - - -}; - -#endif +/* + Copyright 2008 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +/* Portions from vdr osdteletext plugin "txtrender.c": */ +/*************************************************************************** + * * + * txtrender.h - Teletext display abstraction and teletext code * + * renderer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * Changelog: * + * 2005-03 initial version (c) Udo Richter * + * * + ***************************************************************************/ + +#ifndef TXTDECVBIEBU_H +#define TXTDECVBIEBU_H + +#include "draintarget.h" +#include "log.h" + +/* from osdteletext begin */ + +// Teletext character sets +enum enumCharsets { + CHARSET_LATIN_G0 = 0x0000, // native latin (partially todo) + CHARSET_LATIN_G0_CZ_SK = 0x0100, // Czech/Slovak (todo) + CHARSET_LATIN_G0_EN = 0x0200, // English + CHARSET_LATIN_G0_EE = 0x0300, // Estonian (todo) + CHARSET_LATIN_G0_FR = 0x0400, // French + CHARSET_LATIN_G0_DE = 0x0500, // German + CHARSET_LATIN_G0_IT = 0x0600, // Italian + CHARSET_LATIN_G0_LV_LT = 0x0700, // Lettish/Lithuanian (todo) + CHARSET_LATIN_G0_PL = 0x0800, // Polish (todo) + CHARSET_LATIN_G0_PT_ES = 0x0900, // Portugese/Spanish + CHARSET_LATIN_G0_RO = 0x0A00, // Romanian (todo) + CHARSET_LATIN_G0_SR_HR_SL = 0x0B00, // Serbian/Croatian/Slovenian (todo) + CHARSET_LATIN_G0_SV_FI = 0x0C00, // Swedish/Finnish + CHARSET_LATIN_G0_TR = 0x0D00, // Turkish (todo) + CHARSET_LATIN_G2 = 0x0E00, // Latin G2 supplementary set (todo) + CHARSET_CYRILLIC_G0_SR_HR = 0x0F00, // Serbian/Croatian (todo) + CHARSET_CYRILLIC_G0_RU_BG = 0x1000, // Russian/Bulgarian (todo) + CHARSET_CYRILLIC_G0_UK = 0x1100, // Ukrainian (todo) + CHARSET_CYRILLIC_G2 = 0x1200, // Cyrillic G2 Supplementary (todo) + CHARSET_GREEK_G0 = 0x1300, // Greek G0 (todo) + CHARSET_GREEK_G2 = 0x1400, // Greeek G2 (todo) + CHARSET_ARABIC_G0 = 0x1500, // Arabic G0 (todo) + CHARSET_ARABIC_G2 = 0x1600, // Arabic G2 (todo) + CHARSET_HEBREW_G0 = 0x1700, // Hebrew G0 (todo) + CHARSET_GRAPHICS_G1 = 0x1800, // G1 graphics set + CHARSET_GRAPHICS_G1_SEP = 0x1900, // G1 graphics set, separated + CHARSET_GRAPHICS_G3 = 0x1A00, // G3 graphics set (todo) + CHARSET_INVALID = 0x1F00 // no charset defined +}; + +// Macro to get the lowest non-0 bit position from a bit mask +// Should evaluate to const on a const mask +#define LowestSet2Bit(mask) ((mask)&0x0001?0:1) +#define LowestSet4Bit(mask) ((mask)&0x0003?LowestSet2Bit(mask):LowestSet2Bit((mask)>>2)+2) +#define LowestSet8Bit(mask) ((mask)&0x000f?LowestSet4Bit(mask):LowestSet4Bit((mask)>>4)+4) +#define LowestSet16Bit(mask) ((mask)&0x00ff?LowestSet8Bit(mask):LowestSet8Bit((mask)>>8)+8) +#define LowestSet32Bit(mask) ((mask)&0xffff?LowestSet16Bit(mask):LowestSet16Bit((mask)>>16)+16) + + +// Character modifcation double height: +enum enumDblHeight { + dblh_Normal=0x00000000, // normal height + dblh_Top =0x04000000, // upper half character + dblh_Bottom=0x08000000 // lower half character +}; +// Character modifcation double width: +enum enumDblWidth { + dblw_Normal=0x00000000, // normal width + dblw_Left =0x10000000, // left half character + dblw_Right =0x20000000 // right half character +}; + +// Teletext colors +enum enumTeletextColor { + // level 1: + ttcBlack=0, + ttcRed=1, + ttcGreen=2, + ttcYellow=3, + ttcBlue=4, + ttcMagenta=5, + ttcCyan=6, + ttcWhite=7, + // level 2.5: + ttcTransparent=8, + ttcHalfRed=9, + ttcHalfGreen=10, + ttcHalfYellow=11, + ttcHalfBlue=12, + ttcHalfMagenta=13, + ttcHalfCyan=14, + ttcGrey=15, + // unnamed, level 2.5: + ttcColor16=16, ttcColor17=17, ttcColor18=18, ttcColor19=19, + ttcColor20=20, ttcColor21=21, ttcColor22=22, ttcColor23=23, + ttcColor24=24, ttcColor25=25, ttcColor26=26, ttcColor27=27, + ttcColor28=28, ttcColor29=29, ttcColor30=30, ttcColor31=31, + + ttcFirst=0, ttcLast=31 +}; +inline enumTeletextColor& operator++(enumTeletextColor& c) { return c=enumTeletextColor(int(c)+1); } +inline enumTeletextColor operator++(enumTeletextColor& c, int) { enumTeletextColor tmp(c); ++c; return tmp; } + +class cTeletextChar { + // Wrapper class that represents a teletext character, + // including colors and effects. Should optimize back + // to 4 byte unsigned int on compile. + +protected: + unsigned int c; + + static const unsigned int CHAR = 0x000000FF; + // character code + static const unsigned int CHARSET = 0x00001F00; + // character set code, see below + static const unsigned int BOXOUT = 0x00004000; + // 'boxed' mode hidden area + static const unsigned int DIRTY = 0x00008000; + // 'dirty' bit - internal marker only + static const unsigned int FGCOLOR = 0x001F0000; + // 5-bit foreground color code, 3 bit used for now + static const unsigned int BGCOLOR = 0x03E00000; + // 5-bit background color code, 3 bit used for now + static const unsigned int DBLHEIGHT = 0x0C000000; + // show double height + static const unsigned int DBLWIDTH = 0x30000000; + // show double width (todo) + static const unsigned int CONCEAL = 0x40000000; + // character concealed + static const unsigned int BLINK = 0x80000000; + // blinking character + + cTeletextChar(unsigned int cc) { c=cc; } + +public: + cTeletextChar() { c=0; } + + // inline helper functions: + // For each parameter encoded into the 32-bit int, there is + // a Get...() to read, a Set...() to write, and a To...() to + // return a modified copy + + inline unsigned char GetChar() + { return c&CHAR; } + inline void SetChar(unsigned char chr) + { c=(c&~CHAR)|chr; } + inline cTeletextChar ToChar(unsigned char chr) + { return cTeletextChar((c&~CHAR)|chr); } + + inline enumCharsets GetCharset() + { return (enumCharsets)(c&CHARSET); } + inline void SetCharset(enumCharsets charset) + { c=(c&~CHARSET)|charset; } + inline cTeletextChar ToCharset(enumCharsets charset) + { return cTeletextChar((c&~CHARSET)|charset); } + + inline enumTeletextColor GetFGColor() + { return (enumTeletextColor)((c&FGCOLOR) >> LowestSet32Bit(FGCOLOR)); } + inline void SetFGColor(enumTeletextColor fgc) + { c=(c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR)); } + inline cTeletextChar ToFGColor(enumTeletextColor fgc) + { return cTeletextChar((c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR))); } + + inline enumTeletextColor GetBGColor() + { return (enumTeletextColor)((c&BGCOLOR) >> LowestSet32Bit(BGCOLOR)); } + inline void SetBGColor(enumTeletextColor bgc) + { c=(c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR)); } + inline cTeletextChar ToBGColor(enumTeletextColor bgc) + { return cTeletextChar((c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR))); } + + inline bool GetBoxedOut() + { return c&BOXOUT; } + inline void SetBoxedOut(bool BoxedOut) + { c=(BoxedOut)?(c|BOXOUT):(c&~BOXOUT); } + inline cTeletextChar ToBoxedOut(bool BoxedOut) + { return cTeletextChar((BoxedOut)?(c|BOXOUT):(c&~BOXOUT)); } + + inline bool GetDirty() + { return c&DIRTY; } + inline void SetDirty(bool Dirty) + { c=(Dirty)?(c|DIRTY):(c&~DIRTY); } + inline cTeletextChar ToDirty(bool Dirty) + { return cTeletextChar((Dirty)?(c|DIRTY):(c&~DIRTY)); } + + inline enumDblHeight GetDblHeight() + { return (enumDblHeight)(c&DBLHEIGHT); } + inline void SetDblHeight(enumDblHeight dh) + { c=(c&~(DBLHEIGHT)) | dh; } + inline cTeletextChar ToDblHeight(enumDblHeight dh) + { return cTeletextChar((c&~(DBLHEIGHT)) | dh); } + + inline enumDblWidth GetDblWidth() + { return (enumDblWidth)(c&DBLWIDTH); } + inline void SetDblWidth(enumDblWidth dw) + { c=(c&~(DBLWIDTH)) | dw; } + inline cTeletextChar ToDblWidth(enumDblWidth dw) + { return cTeletextChar((c&~(DBLWIDTH)) | dw); } + + inline bool GetConceal() + { return c&CONCEAL; } + inline void SetConceal(bool Conceal) + { c=(Conceal)?(c|CONCEAL):(c&~CONCEAL); } + inline cTeletextChar ToConceal(bool Conceal) + { return cTeletextChar((Conceal)?(c|CONCEAL):(c&~CONCEAL)); } + + inline bool GetBlink() + { return c&BLINK; } + inline void SetBlink(bool Blink) + { c=(Blink)?(c|BLINK):(c&~BLINK); } + inline cTeletextChar ToBlink(bool Blink) + { return cTeletextChar((Blink)?(c|BLINK):(c&~BLINK)); } + + bool operator==(cTeletextChar &chr) { return c==chr.c; } + bool operator!=(cTeletextChar &chr) { return c!=chr.c; } +}; +/* from osdteletext end*/ + +class VTeletextView; + +/* Decoder of teletext matrial present in Data stream for VBI reinsertion more or less according to EBU specs*/ +class TeletextDecoderVBIEBU: public DrainTarget { +public: + TeletextDecoderVBIEBU(); + virtual ~TeletextDecoderVBIEBU(); + + virtual long long SetStartOffset(long long curreftime, bool *rsync); + virtual void ResetTimeOffsets(); + + void ResetDecoder(); + void setKeyinDigits(char digits[3],bool inKeying); + void setPage(unsigned int newpage); + int getPage() {return selectedpage;}; + void setRecordigMode(bool isrecord) {isrecording=isrecord;}; + int *getSubtitlePages() {return record_pages;}; + + + virtual void PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos); + virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos); + + void registerTeletextView(VTeletextView* view) {txtview=view;}; + void unRegisterTeletextView(VTeletextView* view) {if (txtview==view) txtview=NULL;}; + VTeletextView* getTeletxtView() {return txtview;}; + + cTeletextChar getChar(int x, int y) { + // Read character content from page + if (x<0 || x>=40 || y<0 || y>=25) { + Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds read access to teletext page"); + return cTeletextChar(); + } + return Page[x][y].ToDirty(false); + } + bool isDirty(int x, int y) { + if (x<0 || x>=40 || y<0 || y>=25) { + Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds dirty access to teletext page"); + return false; + } + return Page[x][y].GetDirty(); + } + void setChar(int x, int y, cTeletextChar c) { + // Set character at given location + + if (x<0 || x>=40 || y<0 || y>=25) { + Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds write access to teletext page"); + return; + } + if (getChar(x,y) != c) { + Page[x][y]=c.ToDirty(true); + dirty=true; + } + } + + +protected: + void DecodeTeletext(const UCHAR* buffer, unsigned int field); + void RenderTeletextCode(bool renderfirstlineonly); + void CleanPage(); + + int selectedpage; + int lang; + int flags; + UCHAR curpage[25][40]; //Line DataCache + cTeletextChar Page[40][25]; + char keyindigits[3]; + + + // Font Code pages + int FirstG0CodePage; // 7-bit number, lower 3 bits ignored + int SecondG0CodePage; // 7-bit number + + bool ourpage; + bool dirty; + bool gotcha; + bool inkeying; + bool isrecording; + int record_pages[10];//Only 10 Pages per record; + unsigned int firstlineupdate; + VTeletextView *txtview; +private: + MediaPacket mediapacket; + + + +}; + +#endif diff --git a/vaudioselector.cc b/vaudioselector.cc index 6347adc..4908b4f 100644 --- a/vaudioselector.cc +++ b/vaudioselector.cc @@ -527,6 +527,7 @@ int VAudioSelector::handleCommand(int command) return 2; } case Remote::LEFT: + case Remote::DF_LEFT: { if (editsubtitles && subtitles) { ssl.setDarkSelOption(true); @@ -539,6 +540,7 @@ int VAudioSelector::handleCommand(int command) return 2; } case Remote::RIGHT: + case Remote::DF_RIGHT: { if (!editsubtitles && subtitles) { ssl.setDarkSelOption(false); diff --git a/vcolourtuner.cc b/vcolourtuner.cc index f173d22..bba1e1e 100644 --- a/vcolourtuner.cc +++ b/vcolourtuner.cc @@ -169,7 +169,9 @@ int VColourTuner::handleCommand(int command) vgfactor=gfactor; vbfactor=bfactor; #ifndef WIN32 +#ifndef _MIPS_ARCH ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor); +#endif #endif rt=4; break; @@ -185,7 +187,9 @@ int VColourTuner::handleCommand(int command) } if (rt == 2) { #ifndef WIN32 +#ifndef _MIPS_ARCH ((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor); +#endif #endif bool updateAll=drawPicture; draw(); @@ -272,6 +276,8 @@ void VColourTuner::initFactors(){ bfactor=bf; Log::getInstance()->log("VColourTuner",Log::DEBUG,"setting initial factors r=%d,g=%d,b=%d",rf,gf,bf); #ifndef WIN32 +#ifndef _MIPS_ARCH Surface_TYPE::initConversionTables(rfactor,gfactor,bfactor); #endif +#endif } diff --git a/vdr.cc b/vdr.cc index c28d41e..3073697 100644 --- a/vdr.cc +++ b/vdr.cc @@ -35,6 +35,7 @@ #include "mediaprovider.h" #include "mediaproviderids.h" #include "vdrcommand.h" +#include "video.h" VDR* VDR::instance = NULL; //prepare a request @@ -628,12 +629,16 @@ bool VDR::networkLog(const char* logString) if (!connected) return false; int stringLength = strlen(logString); int packetLength = stringLength + 8; - char buffer[packetLength + 1]; + char *buffer=new char[packetLength + 1]; *(ULONG*)&buffer[0] = htonl(CHANNEL_NETLOG); *(ULONG*)&buffer[4] = htonl(stringLength); strcpy(&buffer[8], logString); - - if ((ULONG)tcp->sendData(buffer, packetLength) != packetLength) return false; + + if ((ULONG)tcp->sendData(buffer, packetLength) != packetLength) { + delete [] buffer; + return false; + } + delete [] buffer; return true; } @@ -718,14 +723,17 @@ ChannelList* VDR::getChannelsList(ULONG type) ChannelList* chanList = new ChannelList(); + bool h264support=Video::getInstance()->supportsh264(); + while (!vresp->end()) { Channel* chan = new Channel(); chan->number = vresp->extractULONG(); chan->type = vresp->extractULONG(); chan->name = vresp->extractString(); + chan->vstreamtype = vresp->extractULONG(); - if (chan->type == type) + if (chan->type == type && (chan->vstreamtype!=0x1b || h264support)) { chanList->push_back(chan); logger->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name); @@ -1095,6 +1103,8 @@ RecInfo* VDR::getRecInfo(char* fileName) recInfo->descriptions[i] = vresp->extractString(); } } + recInfo->fps=vresp->extractdouble(); + recInfo->print(); @@ -1170,6 +1180,7 @@ void VDR::getChannelPids(Channel* channel) // } channel->vpid = vresp->extractULONG(); + channel->vstreamtype = vresp->extractULONG(); channel->numAPids = vresp->extractULONG(); for (ULONG i = 0; i < channel->numAPids; i++) diff --git a/vdrresponsepacket.cc b/vdrresponsepacket.cc index c7a077e..7d156c0 100644 --- a/vdrresponsepacket.cc +++ b/vdrresponsepacket.cc @@ -114,6 +114,16 @@ ULLONG VDR_ResponsePacket::extractULLONG() return ull; } +double VDR_ResponsePacket::extractdouble() +{ + if ((packetPos + sizeof(ULLONG)) > userDataLength) return 0; + ULLONG ull = ntohll(*(ULLONG*)&userData[packetPos]); + double d; + memcpy(&d,&ull,sizeof(double)); + packetPos += sizeof(ULLONG); + return d; +} + long VDR_ResponsePacket::extractLONG() { if ((packetPos + sizeof(long)) > userDataLength) return 0; diff --git a/vdrresponsepacket.h b/vdrresponsepacket.h index 3d8d5f3..0d60be0 100644 --- a/vdrresponsepacket.h +++ b/vdrresponsepacket.h @@ -55,6 +55,7 @@ class VDR_ResponsePacket ULONG extractULONG(); ULLONG extractULLONG(); long extractLONG(); + double extractdouble(); bool end(); diff --git a/vfeed.cc b/vfeed.cc index b351cf8..f15d713 100644 --- a/vfeed.cc +++ b/vfeed.cc @@ -74,8 +74,8 @@ void VFeed::threadMethod() } else { -// Log::getInstance()->log("VFeed", Log::DEBUG, "No data delay"); - MILLISLEEP(20); + //Log::getInstance()->log("VFeed", Log::DEBUG, "No data delay"); + MILLISLEEP(5); } } } diff --git a/video.cc b/video.cc index 0a1388c..1d6254d 100644 --- a/video.cc +++ b/video.cc @@ -17,6 +17,7 @@ along with VOMP; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +//portions from vdr by Klaus Schmiding HSMF code #include "video.h" @@ -50,11 +51,19 @@ Video* Video::getInstance() return instance; } -hmsf Video::framesToHMSF(ULONG frames) +/* +hmsf Video::framesToHMSF(ULONG frames, double fps) { hmsf ret; + / * from vdr * + double Seconds; + ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1); + int s = int(Seconds); + ret.seconds=s; + ret.minutes = s / 60 % 60; + ret.hours = s / 3600; - if (format == NTSC) +/ * if (format == NTSC) { ret.hours = frames / 108000; frames %= 108000; @@ -71,12 +80,14 @@ hmsf Video::framesToHMSF(ULONG frames) frames %= 1500; ret.seconds = frames / 25; ret.frames = frames % 25; - } + }* / return ret; -} +}*/ +/* UINT Video::getFPS() { if (format == NTSC) return 30; else return 25; } +*/ diff --git a/video.h b/video.h index 2429583..502a1ba 100644 --- a/video.h +++ b/video.h @@ -63,13 +63,16 @@ class Video: public DrainTarget, public AbstractOption virtual int signalOn()=0; virtual int signalOff()=0; virtual int attachFrameBuffer()=0; // What does this do? - virtual ULONG timecodeToFrameNumber(ULLONG timecode)=0; +// virtual ULONG timecodeToFrameNumber(ULLONG timecode)=0; //Obsolete and not HD compatible virtual ULLONG getCurrentTimestamp()=0; virtual void displayIFrame(const UCHAR* buffer, UINT length)=0; + virtual bool supportsh264(){return false;}; + virtual void seth264mode(bool ish264) {h264=ish264;}; + virtual void turnVideoOn(){}; virtual void turnVideoOff(){}; - virtual ULLONG frameNumberToTimecode(ULONG timecode) { return 0; }; +// virtual ULLONG frameNumberToTimecode(ULONG timecode) { return 0; };//Obsolete and not HD compatible #ifdef DEV virtual int test() { return 0; } @@ -82,8 +85,8 @@ class Video: public DrainTarget, public AbstractOption UINT getScreenHeight() { return screenHeight; } UCHAR getTVsize() { return tvsize; } - hmsf framesToHMSF(ULONG frames); - UINT getFPS(); + //hmsf framesToHMSF(ULONG frames,double fps); + // UINT getFPS(); //removed // Video formats - AV_SET_VID_DISP_FMT const static UCHAR NTSC = 0; @@ -138,6 +141,7 @@ class Video: public DrainTarget, public AbstractOption UCHAR connection; UCHAR aspectRatio; UCHAR mode; + bool h264; UINT screenWidth; UINT screenHeight; diff --git a/videomvp.cc b/videomvp.cc index a66e0f9..6e627af 100644 --- a/videomvp.cc +++ b/videomvp.cc @@ -383,7 +383,7 @@ void VideoMVP::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos) } } -UINT VideoMVP::DeliverMediaSample(const UCHAR* buffer, UINT* samplepos) +UINT VideoMVP::DeliverMediaSample(UCHAR* buffer, UINT* samplepos) { int written = ::write(fdVideo, buffer + deliver_start, deliver_length); if (written == (int)deliver_length) { *samplepos = 0; return deliver_count;} diff --git a/videomvp.h b/videomvp.h index dd94a45..fc086e6 100644 --- a/videomvp.h +++ b/videomvp.h @@ -134,7 +134,7 @@ class VideoMVP : public Video // Writing Data to Videodevice virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); - virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT* samplepos); + virtual UINT DeliverMediaSample( UCHAR* buffer, UINT* samplepos); virtual long long SetStartOffset(long long curreftime, bool *rsync) { return 0; }; virtual void ResetTimeOffsets(); diff --git a/videowin.cc b/videowin.cc index 1f1b635..8e0a4dd 100644 --- a/videowin.cc +++ b/videowin.cc @@ -18,6 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + + #include "videowin.h" #include "log.h" #include "dssourcefilter.h" @@ -26,9 +28,14 @@ #include "osdwin.h" #include "audiowin.h" #include "wwinvideofilter.h" +#include "wwinvideoh264filter.h" #include "wtabbar.h" #include "woptionpane.h" #include "i18n.h" +#include "demuxer.h" + +#include +#include void AdjustWindow(); @@ -39,7 +46,7 @@ VideoWin::VideoWin() dsinited=false; dsgraphbuilder=NULL; dsmediacontrol=NULL; - dsvmrrenderer=NULL; + dsrenderer=NULL; dsrefclock=NULL; dsmediafilter=NULL; dsbasicaudio=NULL; @@ -71,6 +78,8 @@ VideoWin::VideoWin() iframemode=false;//We are not in Iframe mode at begining vmrdeinterlacing=2;//Best videofilterselected=-1; + videoH264filterselected=-1; + currentpresenter=EVR; @@ -81,7 +90,7 @@ VideoWin::~VideoWin() { CleanupDS(); CloseHandle(filtermutex); - int i; + unsigned int i; for (i=0;iRelease(); +} + +void VideoWin::initH264FilterDatabase() +{ + /* This method should determine all availiable DirectShow Filters */ + IFilterMapper2* filtmap=NULL; + HRESULT result; + result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC, + IID_IFilterMapper2,(void**)&filtmap); + if (result != S_OK) + { + Log::getInstance()->log("VideoWin", Log::ERR , "Unable to create FilterMapper!"); + return; + } + /* Wishlist, what Mediatypes do we want */ + GUID mtypesin[]={MEDIATYPE_Video,MEDIASUBTYPE_H264}; + IEnumMoniker *myenum; + result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1, + TRUE,1,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL); + if (result != S_OK) + { + filtmap->Release(); + Log::getInstance()->log("VideoWin", Log::ERR , "Unable to enum Filters!"); + return; + } + ULONG gethowmany; + IMoniker * moni; + while(myenum->Next(1,&moni,&gethowmany)==S_OK) + { + VideoFilterDesc desc; + ZeroMemory(&desc,sizeof(desc)); + + LPOLESTR string; + moni->GetDisplayName(0,0,&string); + desc.displayname=new char[wcslen(string)+1]; + wcstombs(desc.displayname,string,wcslen(string)+1); + CoTaskMemFree(string); + IPropertyBag *bag; + if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK) + { + VARIANT vari; + VariantInit(&vari); + result = bag->Read(L"FriendlyName",&vari,NULL); + if (result == S_OK) + { + desc.friendlyname=new char[wcslen(vari.bstrVal)+1]; + wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1); + } + VariantClear(&vari); + bag->Release(); + + } + + + videoH264filterlist.push_back(desc); + + + + moni->Release(); + // bctx->Release(); + } + int i; + videoH264filterselected=-1; + + + + myenum->Release(); + + + filtmap->Release(); } @@ -301,6 +389,19 @@ bool VideoWin::loadOptionsfromServer(VDR* vdr) } } } + name=vdr->configLoad("DirectShow","VideoH264Filter"); + + if (name != NULL) + { + for (int i = 0;i configLoad("DirectShow","VMR9DeinterlacingMode"); if (name != NULL) { @@ -317,6 +418,18 @@ bool VideoWin::loadOptionsfromServer(VDR* vdr) } } + name=vdr->configLoad("DirectShow", "VideoPresenter"); + if (name!=NULL) { + if (STRCASECMP(name,"VMR9")==0) { + currentpresenter=VMR9; + } else if (STRCASECMP(name,"EVR")==0) { + currentpresenter=EVR; + } + } + if (!((OsdWin*)Osd::getInstance())->IsEvrSupported()) { + currentpresenter=VMR9; + } + name=vdr->configLoad("DirectGraphics", "StretchFiltering"); if (name!=NULL) { if (STRCASECMP(name,"None")==0) { @@ -328,6 +441,8 @@ bool VideoWin::loadOptionsfromServer(VDR* vdr) } } + + return true; @@ -360,6 +475,13 @@ bool VideoWin::handleOptionChanges(Option* option) vmrdeinterlacing=4; } }break; + case 3: { + if (STRCASECMP(option->options[option->userSetChoice],"VMR9")==0) { + currentpresenter=VMR9; + } else if (STRCASECMP(option->options[option->userSetChoice],"EVR")==0) { + currentpresenter=EVR; + } + }break; }; return false; @@ -370,6 +492,8 @@ bool VideoWin::saveOptionstoServer() if (videofilterselected!=-1) { VDR::getInstance()->configSave("DirectShow", "VideoFilter",videofilterlist[videofilterselected].displayname); + VDR::getInstance()->configSave("DirectShow", + "VideoH264Filter",videoH264filterlist[videoH264filterselected].displayname); } return true; } @@ -404,14 +528,25 @@ bool VideoWin::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pa strcpy(scalingopts[i],"Linear"); i++; } - option = new Option(1 , "Video Stretching Filter", "DirectGraphics", "StretchFiltering", Option::TYPE_TEXT, i, (i-1), 0, scalingopts,NULL,true, this); + option = new Option(1 ,tr("Video Stretching Filter"), "DirectGraphics", "StretchFiltering", Option::TYPE_TEXT, i, (i-1), 0, scalingopts,NULL,true, this); options->push_back(option); pane->addOptionLine(option); static const char* deintopts[]={"NoMix","None","Best","Bob","Weave"}; - option = new Option(2,"VMR9 Deinterlacing Mode", "DirectShow","VMR9DeinterlacingMode",Option::TYPE_TEXT,5,2,0,deintopts,NULL,false,this); + option = new Option(2,tr("VMR9 Deinterlacing Mode"), "DirectShow","VMR9DeinterlacingMode",Option::TYPE_TEXT,5,2,0,deintopts,NULL,false,this); options->push_back(option); pane->addOptionLine(option); + if (((OsdWin*)Osd::getInstance())->IsEvrSupported()) + { + static const char* presenteropts[]={"EVR","VMR9"}; + option = new Option(3,tr("Video Presenter Filter"),"DirectShow", "VideoPresenter",Option::TYPE_TEXT,2,0,0,presenteropts,NULL,false,this); + } else { + static const char* presenteropts[]={"VMR9"}; + option = new Option(3,tr("Video Presenter Filter"),"DirectShow", "VideoPresenter",Option::TYPE_TEXT,1,0,0,presenteropts,NULL,false,this); + } + options->push_back(option); + pane->addOptionLine(option); + } @@ -539,6 +674,130 @@ IBaseFilter *VideoWin::getVideoFilter() } +IBaseFilter *VideoWin::getVideoH264Filter() +{ + IBaseFilter *curfilter= NULL; + if (videoH264filterselected == -1) + { + int i; + for (i = 0;i log("VideoWin", Log::DEBUG ,"Creating filter: %s",videoH264filterlist[i].friendlyname); + + + + if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK) + { + if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK) + { + IAMDecoderCaps* desccaps=NULL; + if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK) + { + DWORD caps; + desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps); + if (caps == DECODER_CAP_SUPPORTED) + { + videoH264filterlist[i].vmr9tested = true; + videoH264filterlist[i].vmr9 = true; + videoH264filterselected = i; + } + else + { + videoH264filterlist[i].vmr9tested = true; + videoH264filterlist[i].vmr9 = false; + + curfilter->Release(); + curfilter=NULL; + } + } + desccaps->Release(); + } + moni->Release(); + } + delete [] name; + bindctx->Release(); + } + if (videoH264filterlist[i].vmr9) break; + + } + if (curfilter != NULL) + { + VDR *vdr=VDR::getInstance(); + if (vdr != NULL) + { + vdr->configSave("DirectShow","VideoH264Filter", + videoH264filterlist[videoH264filterselected].displayname); + } + return curfilter; + } + } + else + { + IBindCtx *bindctx=NULL; + if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL; + IMoniker * moni=NULL; + LPCOLESTR name=new WCHAR[strlen(videoH264filterlist[videoH264filterselected].displayname)+1]; + mbstowcs((wchar_t*)name,videoH264filterlist[videoH264filterselected].displayname, + strlen(videoH264filterlist[videoH264filterselected].displayname)+1); + ULONG eater; + Log::getInstance()->log("VideoWin", Log::DEBUG ,"Creating filter: %s",videoH264filterlist[videoH264filterselected].friendlyname); + if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK) + { + if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK) + { + IAMDecoderCaps* desccaps=NULL; + if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK) + { + DWORD caps; + desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps); + if (caps == DECODER_CAP_SUPPORTED) + { + videoH264filterlist[videoH264filterselected].vmr9tested = true; + videoH264filterlist[videoH264filterselected].vmr9 = true; + } + else + { + videoH264filterlist[videoH264filterselected].vmr9tested = true; + videoH264filterlist[videoH264filterselected].vmr9 = false; + Log::getInstance()->log("VideoWin", Log::WARN ,"Filter does not support VMR9, but is selected, manual selection!"); + } + } + moni->Release(); + delete [] name; + bindctx->Release(); + return curfilter; + } + moni->Release(); + } + bindctx->Release(); + delete [] name; + return NULL; + } + return NULL; + +} + #ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions #include "dshelper.h" @@ -556,6 +815,8 @@ bool VideoWin::addOptionPagesToWTB(WTabBar *wtb) { Boxx *box=new WWinVideoFilter(); wtb->addTab(tr("Video Filter"), box); + box=new WWinVideoH264Filter(); + wtb->addTab(tr("H264 Filter"), box); return true; } @@ -565,6 +826,12 @@ const VideoFilterDescList *VideoWin::getVideoFilterList(int &selected) return &videofilterlist; } +const VideoFilterDescList *VideoWin::getVideoH264FilterList(int &selected) +{ + selected=videoH264filterselected; + return &videoH264filterlist; +} + bool VideoWin::selectVideoFilter(int filter) { IBindCtx *bindctx=NULL; @@ -622,6 +889,62 @@ bool VideoWin::selectVideoFilter(int filter) } } +bool VideoWin::selectVideoH264Filter(int filter) +{ + IBindCtx *bindctx=NULL; + if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL; + IMoniker * moni=NULL; + LPCOLESTR name=new WCHAR[strlen(videoH264filterlist[filter].displayname)+1]; + mbstowcs((wchar_t*)name,videoH264filterlist[filter].displayname, + strlen(videoH264filterlist[filter].displayname)+1); + ULONG eater; + bool success=false; + if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK) + { + IBaseFilter* curfilter=NULL; + if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK) + { + IAMDecoderCaps* desccaps=NULL; + if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK) + { + DWORD caps; + HRESULT hres=desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps); + if (caps == DECODER_CAP_SUPPORTED) + { + videoH264filterlist[filter].vmr9tested = true; + videoH264filterlist[filter].vmr9 = true; + success=true; + } + else + { + videoH264filterlist[filter].vmr9tested = true; + videoH264filterlist[filter].vmr9 = false; + success=false; + } + desccaps->Release(); + } else { + videoH264filterlist[filter].vmr9tested = true; + videoH264filterlist[filter].vmr9 = false; + success=false; + } + + curfilter->Release(); + + } + moni->Release(); + } + bindctx->Release(); + delete [] name; + if (success || true) + { + videoH264filterselected=filter; + return true; + } + else + { + return false; + } +} int VideoWin::dsInitVideoFilter() { @@ -629,74 +952,167 @@ int VideoWin::dsInitVideoFilter() HRESULT hres; if (videoon) { //We alloc the vmr9 as next step - if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0, - CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsvmrrenderer)!=S_OK) - { - Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!"); - ReleaseMutex(filtermutex); - CleanupDS(); - } - /*VMR 9 stuff**/ - if (hres=dsgraphbuilder->AddFilter(dsvmrrenderer,L"VMR9")!=S_OK) - { - ReleaseMutex(filtermutex); - CleanupDS(); - Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!"); - return 0; - } - IVMRFilterConfig9* vmrfilconfig; - if (dsvmrrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK) - { - ReleaseMutex(filtermutex); - CleanupDS(); - Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!"); - return 0; - } - if (vmrdeinterlacing!=0) vmrfilconfig->SetNumberOfStreams(1);//Enter Mixing Mode - vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless); - - vmrfilconfig->Release(); - - if (dsvmrrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9, - (void**)& dsvmrsurfnotify) != S_OK) - { - ReleaseMutex(filtermutex); - CleanupDS(); - Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!"); - return 0; - } - allocatorvmr=new DsAllocator(); - dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr); - allocatorvmr->AdviseNotify(dsvmrsurfnotify); - - IVMRDeinterlaceControl9* deintctrl; - if (dsvmrrenderer->QueryInterface(IID_IVMRDeinterlaceControl9,(void**)&deintctrl)!=S_OK) - { - ReleaseMutex(filtermutex); - CleanupDS(); - Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Deinterlace control!"); - return 0; - } - /*turnoff*/ - switch (vmrdeinterlacing) - { - case 1: //No Deinterlasing - deintctrl->SetDeinterlaceMode(0xFFFFFFFF,(LPGUID)&GUID_NULL);//Turn Off + if (currentpresenter==VMR9) + { + Log::getInstance()->log("VideoWin", Log::INFO ,"VMR9 Videopresenter selected!"); + if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0, + CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsrenderer)!=S_OK) + { + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!"); + ReleaseMutex(filtermutex); + CleanupDS(); + } + /*VMR 9 stuff**/ + if (hres=dsgraphbuilder->AddFilter(dsrenderer,L"VMR9")!=S_OK) + { + ReleaseMutex(filtermutex); + CleanupDS(); + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!"); + return 0; + } + IVMRFilterConfig9* vmrfilconfig; + if (dsrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK) + { + ReleaseMutex(filtermutex); + CleanupDS(); + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!"); + return 0; + } + if (vmrdeinterlacing!=0) vmrfilconfig->SetNumberOfStreams(1);//Enter Mixing Mode + vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless); + vmrfilconfig->Release(); + if (dsrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9, + (void**)& dsvmrsurfnotify) != S_OK) + { + ReleaseMutex(filtermutex); + CleanupDS(); + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!"); + return 0; + } + allocatorvmr=new DsAllocator(); + dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr); + allocatorvmr->AdviseNotify(dsvmrsurfnotify); + + IVMRDeinterlaceControl9* deintctrl; + if (dsrenderer->QueryInterface(IID_IVMRDeinterlaceControl9,(void**)&deintctrl)!=S_OK) + { + ReleaseMutex(filtermutex); + CleanupDS(); + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Deinterlace control!"); + return 0; + } + /*turnoff*/ + switch (vmrdeinterlacing) + { + case 1: //No Deinterlasing + deintctrl->SetDeinterlaceMode(0xFFFFFFFF,(LPGUID)&GUID_NULL);//Turn Off break; - case 2: //Best - deintctrl->SetDeinterlacePrefs(DeinterlacePref_NextBest);//Choose Next Best - + case 2: //Best + deintctrl->SetDeinterlacePrefs(DeinterlacePref_NextBest);//Choose Next Best break; - case 3: //Bob - deintctrl->SetDeinterlacePrefs(DeinterlacePref_BOB);//Choose NBob - break; - case 4: //Weave - deintctrl->SetDeinterlacePrefs(DeinterlacePref_Weave);//Choose Weave + case 3: //Bob + deintctrl->SetDeinterlacePrefs(DeinterlacePref_BOB);//Choose NBob + break; + case 4: //Weave + deintctrl->SetDeinterlacePrefs(DeinterlacePref_Weave);//Choose Weave + break; + }; + deintctrl->Release(); + /*VMR 9 stuff end */ + } + else if (currentpresenter==EVR) + { + Log::getInstance()->log("VideoWin", Log::INFO ,"EVR Videopresenter selected!"); + if (hres=CoCreateInstance(CLSID_EnhancedVideoRenderer,0, + CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsrenderer)!=S_OK) + { + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating EVR renderer!"); + ReleaseMutex(filtermutex); + CleanupDS(); + } + /*EVR stuff**/ + if (hres=dsgraphbuilder->AddFilter(dsrenderer,L"EVR")!=S_OK) + { + ReleaseMutex(filtermutex); + CleanupDS(); + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding EVR renderer!"); + return 0; + } + + + IMFGetService *evr_services; + if (dsrenderer->QueryInterface(IID_IMFGetService,(void**)&evr_services)!=S_OK) + { + ReleaseMutex(filtermutex); + CleanupDS(); + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFGetServices interface!"); + return 0; + } + + IMFVideoDisplayControl* mfvideodisplaycontrol; + if (evr_services->GetService(MR_VIDEO_RENDER_SERVICE,IID_IMFVideoDisplayControl,(void**)&mfvideodisplaycontrol)!=S_OK) + { + ReleaseMutex(filtermutex); + CleanupDS(); + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFVideoDisplayControl interface!"); + return 0; + } + + evr_services->Release(); + mfvideodisplaycontrol->SetVideoWindow(((OsdWin*) Osd::getInstance())->getWindow()); + //RECT client; + //GetClientRect(((OsdWin*) Osd::getInstance())->getWindow(), &client); + //mfvideodisplaycontrol->SetVideoPosition(NULL,&client); + + mfvideodisplaycontrol->Release(); + + + /// if (vmrdeinterlacing!=0) vmrfilconfig->SetNumberOfStreams(1);//Enter Mixing Mode //always the case for evr! + + IMFVideoRenderer *mfvideorenderer; + if (dsrenderer->QueryInterface(IID_IMFVideoRenderer,(void**)&mfvideorenderer)!=S_OK) + { + ReleaseMutex(filtermutex); + CleanupDS(); + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting EVR IMFVideoRenderer interface!"); + return 0; + } + + allocatorvmr=new DsAllocator(); + HRESULT hres=mfvideorenderer->InitializeRenderer(NULL,allocatorvmr); + + mfvideorenderer->Release(); + //How should I do this in EVR? + /* IVMRDeinterlaceControl9* deintctrl; + if (dsrenderer->QueryInterface(IID_IVMRDeinterlaceControl9,(void**)&deintctrl)!=S_OK) + { + ReleaseMutex(filtermutex); + CleanupDS(); + Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Deinterlace control!"); + return 0; + } + /*turnoff* + switch (vmrdeinterlacing) + { + case 1: //No Deinterlasing + deintctrl->SetDeinterlaceMode(0xFFFFFFFF,(LPGUID)&GUID_NULL);//Turn Off break; - }; - deintctrl->Release(); - - /*VMR 9 stuff end */ + case 2: //Best + deintctrl->SetDeinterlacePrefs(DeinterlacePref_NextBest);//Choose Next Best + break; + case 3: //Bob + deintctrl->SetDeinterlacePrefs(DeinterlacePref_BOB);//Choose NBob + break; + case 4: //Weave + deintctrl->SetDeinterlacePrefs(DeinterlacePref_Weave);//Choose Weave + break; + }; + deintctrl->Release();*/ + /*EVR stuff end */ + } else { + Log::getInstance()->log("VideoWin", Log::ERR ,"No videopresenter selected! Please post on the forum!"); + return -1; + } IFilterGraph2*fg2=NULL; if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK) { @@ -718,7 +1134,17 @@ int VideoWin::dsInitVideoFilter() } #else*/ - IBaseFilter*videofilter=getVideoFilter(); + IBaseFilter*videofilter; + if (h264) + { + Log::getInstance()->log("VideoWin", Log::DEBUG ,"Entering h264 playback..."); + videofilter=getVideoH264Filter(); + } + else + { + Log::getInstance()->log("VideoWin", Log::DEBUG ,"Entering MPEG2 playback..."); + videofilter=getVideoFilter(); + } if (hres=dsgraphbuilder->AddFilter(videofilter,NULL) != S_OK) { Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Video Filter!"); @@ -728,6 +1154,20 @@ int VideoWin::dsInitVideoFilter() } IEnumPins *pinenum=NULL; bool error=false; + + mptype_video_detail vid_details; + Demuxer* demux=Demuxer::getInstance(); + vid_details.width=demux->getHorizontalSize(); + vid_details.height=demux->getVerticalSize(); + + if (h264) + { + sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_H264,&vid_details); + } + else + { + sourcefilter->GetVideoPin()->SetPinMode(MPTYPE_VIDEO_MPEG2,&vid_details); + } if (videofilter->EnumPins(&pinenum) == S_OK) { IPin *current=NULL; @@ -1055,7 +1495,7 @@ ULLONG VideoWin::getCurrentTimestamp() return result; } - +/* //to beremoved ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode) { if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25); @@ -1067,7 +1507,7 @@ ULLONG VideoWin::frameNumberToTimecode(ULONG framenumber) if (format == PAL) return (ULLONG)(((double)framenumber * (double)90000) / (double)25); else return (ULLONG)(((double)framenumber * (double)90000) / (double)30); } - +*/ void VideoWin::CleanupDS() { WaitForSingleObject(filtermutex,INFINITE); @@ -1089,9 +1529,9 @@ void VideoWin::CleanupDS() dsvmrsurfnotify->Release(); dsvmrsurfnotify=NULL; } - if (dsvmrrenderer) { - dsvmrrenderer->Release(); - dsvmrrenderer=NULL; + if (dsrenderer) { + dsrenderer->Release(); + dsrenderer=NULL; } if (allocatorvmr) { @@ -1134,7 +1574,7 @@ void VideoWin::PrepareMediaSample(const MediaPacketList& mplist, mediapacket = mplist.front(); } -UINT VideoWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos) +UINT VideoWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos) { DeliverMediaPacket(mediapacket, buffer, samplepos); if (*samplepos == mediapacket.length) { @@ -1145,123 +1585,141 @@ UINT VideoWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos) } UINT VideoWin::DeliverMediaPacket(MediaPacket packet, - const UCHAR* buffer, - UINT *samplepos) + const UCHAR* buffer, + UINT *samplepos) { - - /*First Check, if we have an audio sample*/ - if (!isdsinited()) return 0; + + /*First Check, if we have an audio sample*/ + if (!isdsinited()) return 0; + if (packet.type == MPTYPE_VIDEO_H264) + { + h264=true; + } + else + { + h264=false; + } + #ifdef DO_VIDEO - if (!videoon) { - *samplepos+=packet.length; - MILLISLEEP(0); //yet not implemented//bad idea - return packet.length; - } - /*First Check, if we have an audio sample*/ - if (iframemode) { - samplepos=0; - MILLISLEEP(10); - return 0; //Not in iframe mode! - } - IMediaSample* ms=NULL; - REFERENCE_TIME reftime1=0; - REFERENCE_TIME reftime2=0; + if (!videoon) { + *samplepos+=packet.length; + MILLISLEEP(0); //yet not implemented//bad idea + return packet.length; + } + /*First Check, if we have an audio sample*/ + if (iframemode) { + //samplepos=0; + MILLISLEEP(10); + return 0; //Not in iframe mode! + } + IMediaSample* ms=NULL; + REFERENCE_TIME reftime1=0; + REFERENCE_TIME reftime2=0; - UINT headerstrip=0; - if (packet.disconti) { - firstsynched=false; - DeliverVideoMediaSample(); + 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! - } + + + /*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! + 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; + //samplepos=0; + //MessageBox(0,"da isser","hei",0); + //MILLISLEEP(1); + return 0; } ms_pos=ms->GetActualDataLength(); ms_length=ms->GetSize(); haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos); - } - ms->GetPointer(&ms_buf); + if ((ms_length-ms_pos)<1 ) { + DeliverVideoMediaSample(); //we are full! + if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample + //samplepos=0; + //MessageBox(0,"da isser","hei",0); + //MILLISLEEP(10); + return 0; + } + ms_pos=ms->GetActualDataLength(); + ms_length=ms->GetSize(); + haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos); + } + ms->GetPointer(&ms_buf); - if (ms_pos==0) {//will only be changed on first packet - if (packet.disconti) { - ms->SetDiscontinuity(TRUE); - } else { - ms->SetDiscontinuity(FALSE); - } - if (packet.synched) { - ms->SetSyncPoint(TRUE); - ms->SetTime(&reftime1,&reftime2); - //ms->SetTime(NULL,NULL); - ms->SetMediaTime(NULL, NULL); - if (reftime1<0) ms->SetPreroll(TRUE); - else ms->SetPreroll(FALSE); - /*Timecode handling*/ - lastreftimeRT=reftime1; - lastreftimePTS=packet.pts; - - }else { - ms->SetSyncPoint(FALSE); - ms->SetTime(NULL,NULL); - ms->SetMediaTime(NULL, NULL); - ms->SetPreroll(FALSE); - - // ms->SetSyncPoint(TRUE); + if (ms_pos==0) {//will only be changed on first packet + if (packet.disconti) { + ms->SetDiscontinuity(TRUE); + } else { + ms->SetDiscontinuity(FALSE); + } + if (packet.synched) { + ms->SetSyncPoint(TRUE); + ms->SetTime(&reftime1,&reftime2); + //Log::getInstance()->log("VideoWin", Log::DEBUG , "Setted videotime to %lld %lld",reftime1,reftime2); + //Log::getInstance()->log("VideoWin", Log::DEBUG , "Packet pts %lld dts %lld",packet.pts,packet.dts); + //ms->SetTime(NULL,NULL); + ms->SetMediaTime(NULL, NULL); + if (reftime1<0) ms->SetPreroll(TRUE); + else ms->SetPreroll(FALSE); + /*Timecode handling*/ + lastreftimeRT=reftime1; + lastreftimePTS=packet.pts; + + } + else + { + ms->SetSyncPoint(FALSE); + ms->SetTime(NULL,NULL); + ms->SetMediaTime(NULL, NULL); + ms->SetPreroll(FALSE); + + // ms->SetSyncPoint(TRUE); + } } - } + - memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy); + memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy); ms->SetActualDataLength(haveToCopy+ms_pos); - *samplepos+=haveToCopy; + *samplepos+=haveToCopy; - return haveToCopy+headerstrip; + return haveToCopy+headerstrip; #else - *samplepos+=packet.length; - MILLISLEEP(0); //yet not implemented//bad idea - return packet.length; + *samplepos+=packet.length; + MILLISLEEP(0); //yet not implemented//bad idea + return packet.length; #endif } @@ -1406,12 +1864,12 @@ void VideoWin::displayIFrame(const UCHAR* buffer, UINT length) { if (!iframemode) EnterIframePlayback(); if (!isdsinited()) return ; + #ifdef DO_VIDEO IMediaSample* ms=NULL; REFERENCE_TIME reftime1=0; REFERENCE_TIME reftime2=0; if (!videoon) return; - if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample MILLISLEEP(10); return ; @@ -1475,8 +1933,10 @@ void VideoWin::displayIFrame(const UCHAR* buffer, UINT length) } } } - - if (first) {ms->SetSyncPoint(TRUE);first=false;} + + if (first) {ms->SetSyncPoint(TRUE); + ms->SetDiscontinuity(TRUE); + first=false;} else ms->SetSyncPoint(FALSE); ms->SetTime(NULL,NULL); ms->SetMediaTime(NULL, NULL); @@ -1499,6 +1959,13 @@ bool VideoWin::supportsAc3(){ } } +bool VideoWin::supportsh264() +{ + if (videoH264filterlist.size()>0) return true; + else return false; +} + + bool VideoWin::changeAType(int type,IMediaSample* ms){ if (sourcefilter!= NULL) { lastaudiomode=type; diff --git a/videowin.h b/videowin.h index 7bc868e..814efdc 100644 --- a/videowin.h +++ b/videowin.h @@ -51,148 +51,166 @@ class DsAllocator; class VideoWin : public Video { - public: - VideoWin(); - ~VideoWin(); - - int init(UCHAR format); - int shutdown(); - - int setFormat(UCHAR format); - int setConnection(UCHAR connection); - int setAspectRatio(UCHAR aspectRatio); // This one does the pin 8 scart widescreen switching - UCHAR getAspectRatio(){return aspectRatio;}; - UCHAR getMode(){return mode;}; - UCHAR getPseudoTVsize() {return pseudotvsize;}; - int setMode(UCHAR mode); - int setTVsize(UCHAR size); // Is the TV a widescreen? - int setDefaultAspect(); - int setSource(); - int setPosition(int x, int y); - int sync(); - int play(); - int dsplay(); - bool InIframemode() {return iframemode;}; - int stop(); - int dsstop(); - int pause(); - int dspause(); - int unPause(); - int dsunPause(); - int fastForward(); - int unFastForward(); - int reset(); - int dsreset(); - int blank(); - int signalOn(); - int signalOff(); - int attachFrameBuffer(); // What does this do? - ULONG timecodeToFrameNumber(ULLONG timecode); - ULLONG frameNumberToTimecode(ULONG framenumber); - ULLONG getCurrentTimestamp(); - - bool loadOptionsfromServer(VDR* vdr); - bool saveOptionstoServer(); - bool addOptionPagesToWTB(WTabBar *wtb); - bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane); - bool handleOptionChanges(Option* option); - - //Writing Data to Videodevice - virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); - virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos); - UINT DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, UINT *samplepos); - - - - virtual bool supportsAc3(); - - - private: - MediaPacket mediapacket; - public: - - int getCurrentAudioMediaSample(IMediaSample** ms); - int DeliverAudioMediaSample(); - - int getCurrentVideoMediaSample(IMediaSample** ms); - int DeliverVideoMediaSample(); - int setAudioStreamType(UCHAR type); - - virtual long long SetStartOffset(long long curreftime, bool *rsync); - long long SetStartAudioOffset(long long curreftime, bool *rsync); - virtual void ResetTimeOffsets(); - - void SetAudioState(bool state){audioon=state;}; - void SetAudioVolume(long volume); - - void turnVideoOn(){videoon=true;}; - void turnVideoOff(){videoon=false;}; - - virtual void displayIFrame(const UCHAR* buffer, UINT length); - - unsigned int getPosx() {return videoposx;}; - unsigned int getPosy() {return videoposy;}; - bool isVideoOn() {return videoon;}; - bool isdsinited() {return dsinited;}; - int lastAType() {return lastaudiomode;}; - bool changeAType(int type,IMediaSample* ms); - - - const VideoFilterDescList *getVideoFilterList(int &selected); - bool selectVideoFilter(int filter); - DsSourceFilter* getSourceFilter() {return sourcefilter;}; +public: + VideoWin(); + ~VideoWin(); + + int init(UCHAR format); + int shutdown(); + + int setFormat(UCHAR format); + int setConnection(UCHAR connection); + int setAspectRatio(UCHAR aspectRatio); // This one does the pin 8 scart widescreen switching + UCHAR getAspectRatio(){return aspectRatio;}; + UCHAR getMode(){return mode;}; + UCHAR getPseudoTVsize() {return pseudotvsize;}; + int setMode(UCHAR mode); + int setTVsize(UCHAR size); // Is the TV a widescreen? + int setDefaultAspect(); + int setSource(); + int setPosition(int x, int y); + int sync(); + int play(); + int dsplay(); + bool InIframemode() {return iframemode;}; + int stop(); + int dsstop(); + int pause(); + int dspause(); + int unPause(); + int dsunPause(); + int fastForward(); + int unFastForward(); + int reset(); + int dsreset(); + int blank(); + int signalOn(); + int signalOff(); + int attachFrameBuffer(); // What does this do? +// ULONG timecodeToFrameNumber(ULLONG timecode); +// ULLONG frameNumberToTimecode(ULONG framenumber); + ULLONG getCurrentTimestamp(); + + bool loadOptionsfromServer(VDR* vdr); + bool saveOptionstoServer(); + bool addOptionPagesToWTB(WTabBar *wtb); + bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane); + bool handleOptionChanges(Option* option); + + //Writing Data to Videodevice + virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); + virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos); + UINT DeliverMediaPacket(const MediaPacket packet, const UCHAR* buffer, UINT *samplepos); + + virtual bool supportsh264(); + + + virtual bool supportsAc3(); + + enum VideoPresenter { + VMR9, + EVR + } ; + + + +private: + MediaPacket mediapacket; +public: + + int getCurrentAudioMediaSample(IMediaSample** ms); + int DeliverAudioMediaSample(); + + int getCurrentVideoMediaSample(IMediaSample** ms); + int DeliverVideoMediaSample(); + int setAudioStreamType(UCHAR type); + + virtual long long SetStartOffset(long long curreftime, bool *rsync); + long long SetStartAudioOffset(long long curreftime, bool *rsync); + virtual void ResetTimeOffsets(); + + void SetAudioState(bool state){audioon=state;}; + void SetAudioVolume(long volume); + + void turnVideoOn(){videoon=true;}; + void turnVideoOff(){videoon=false;}; + + virtual void displayIFrame(const UCHAR* buffer, UINT length); + + unsigned int getPosx() {return videoposx;}; + unsigned int getPosy() {return videoposy;}; + bool isVideoOn() {return videoon;}; + bool isdsinited() {return dsinited;}; + int lastAType() {return lastaudiomode;}; + bool changeAType(int type,IMediaSample* ms); + + + const VideoFilterDescList *getVideoFilterList(int &selected); + bool selectVideoFilter(int filter); + DsSourceFilter* getSourceFilter() {return sourcefilter;}; + + const VideoFilterDescList *getVideoH264FilterList(int &selected); + bool selectVideoH264Filter(int filter); + #ifdef DEV - int test(); - int test2(); + int test(); + int test2(); #endif private: - int EnterIframePlayback(); + int EnterIframePlayback(); #ifdef NEW_DS_MECHANISMENS - void dstest(); - void initFilterDatabase(); - IBaseFilter *getVideoFilter(); VideoFilterDescList videofilterlist; - int videofilterselected; + void dstest(); + void initFilterDatabase(); + IBaseFilter *getVideoFilter(); + VideoFilterDescList videofilterlist; + int videofilterselected; + + void initH264FilterDatabase(); + IBaseFilter *getVideoH264Filter(); + VideoFilterDescList videoH264filterlist; + int videoH264filterselected; #endif - int dsInitVideoFilter(); - IMediaControl* dsmediacontrol; - - IGraphBuilder* dsgraphbuilder; - IMediaSample* cur_audio_media_sample; - IMediaSample* cur_video_media_sample; - IBaseFilter* dsvmrrenderer; - IVMRSurfaceAllocatorNotify9 *dsvmrsurfnotify; - IReferenceClock *dsrefclock; - IMediaFilter* dsmediafilter; - IBasicAudio* dsbasicaudio; - REFERENCE_TIME cr_time; - - DsSourceFilter* sourcefilter; - DsAllocator* allocatorvmr; - HANDLE filtermutex; - void CleanupDS(); - bool offsetnotset; - bool offsetvideonotset; - bool offsetaudionotset; - long long startoffset; - long long lastrefvideotime; - long long lastrefaudiotime; - bool dsinited; - bool firstsynched; - bool audioon; - bool videoon; - bool iframemode; - UCHAR pseudotvsize; - REFERENCE_TIME lastreftimeRT; - ULLONG lastreftimePTS; - unsigned int videoposx; - unsigned int videoposy; - int lastaudiomode; - int audiovolume; - UCHAR aud_type; - unsigned int vmrdeinterlacing; + int dsInitVideoFilter(); + IMediaControl* dsmediacontrol; + + IGraphBuilder* dsgraphbuilder; + IMediaSample* cur_audio_media_sample; + IMediaSample* cur_video_media_sample; + IBaseFilter* dsrenderer; + IVMRSurfaceAllocatorNotify9 *dsvmrsurfnotify; + IReferenceClock *dsrefclock; + IMediaFilter* dsmediafilter; + IBasicAudio* dsbasicaudio; + REFERENCE_TIME cr_time; + + DsSourceFilter* sourcefilter; + DsAllocator* allocatorvmr; + HANDLE filtermutex; + void CleanupDS(); + bool offsetnotset; + bool offsetvideonotset; + bool offsetaudionotset; + long long startoffset; + long long lastrefvideotime; + long long lastrefaudiotime; + bool dsinited; + bool firstsynched; + bool audioon; + bool videoon; + bool iframemode; + UCHAR pseudotvsize; + REFERENCE_TIME lastreftimeRT; + ULLONG lastreftimePTS; + unsigned int videoposx; + unsigned int videoposy; + int lastaudiomode; + int audiovolume; + UCHAR aud_type; + unsigned int vmrdeinterlacing; + VideoPresenter currentpresenter; #ifdef DS_DEBUG - DWORD graphidentifier; + DWORD graphidentifier; #endif }; diff --git a/vmediaview.cc b/vmediaview.cc index 00a7c06..af6cd2c 100644 --- a/vmediaview.cc +++ b/vmediaview.cc @@ -42,6 +42,12 @@ #include "mediaplayer.h" #include "log.h" +const int VMediaView::EVENT_SLIDESHOW=100; +const int VMediaView::EVENT_DRAWINGDONE=101; +const int VMediaView::EVENT_DRAWINGERROR=102; +const int VMediaView::EVENT_DIRECTORYDONE=103; + + /** * the combined user interface for pictures and audio * has 2 surfaces to enable drawing in a separate thread diff --git a/vmediaview.h b/vmediaview.h index ba4164c..14073e4 100644 --- a/vmediaview.h +++ b/vmediaview.h @@ -75,10 +75,10 @@ class VMediaView : public Boxx, public TimerReceiver bool isAudioPlaying(); //player event parameters - no interference with audioplayer! - so we start at 100 - const static int EVENT_SLIDESHOW=100; - const static int EVENT_DRAWINGDONE=101; - const static int EVENT_DRAWINGERROR=102; - const static int EVENT_DIRECTORYDONE=103; + const static int EVENT_SLIDESHOW; + const static int EVENT_DRAWINGDONE; + const static int EVENT_DRAWINGERROR; + const static int EVENT_DIRECTORYDONE; private: @@ -194,4 +194,6 @@ class VMediaView : public Boxx, public TimerReceiver }; + + #endif diff --git a/vradiorec.h b/vradiorec.h index 73db089..eeaaf4c 100644 --- a/vradiorec.h +++ b/vradiorec.h @@ -35,6 +35,7 @@ class VDR; class Video; class PlayerRadio; class Timers; +class BoxStack; class VRadioRec : public Boxx, public TimerReceiver { diff --git a/vrecording.cc b/vrecording.cc index 965bbd9..f655ae0 100644 --- a/vrecording.cc +++ b/vrecording.cc @@ -66,7 +66,7 @@ VRecording::VRecording(RecMan* trecman, Recording* trec) summary.setSize(area.w - 20, area.h - 30 - 15 - 50); summary.setParaMode(true); - if (strlen(rec->recInfo->summary)) + if (rec->recInfo &&strlen(rec->recInfo->summary)) summary.setText(rec->recInfo->summary); else summary.setText(tr("Summary unavailable")); diff --git a/vrecordinglist.cc b/vrecordinglist.cc index 2e96a36..bf96f2b 100644 --- a/vrecordinglist.cc +++ b/vrecordinglist.cc @@ -104,11 +104,12 @@ void VRecordingList::drawData(bool doIndexPop) currentRec = *j; time_t recStartTime = (time_t)currentRec->getStartTime(); btime = localtime(&recStartTime); -#ifndef _MSC_VER - strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime); -#else +//NMT does not like this too! + //#ifndef _MSC_VER +// strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime); +//#else strftime(tempA, 299, "%d/%m %H:%M ", btime); -#endif +//#endif sprintf(tempB, "%s\t%s", tempA, currentRec->getProgName()); currentRec->index = sl.addOption(tempB, 0, first); first = 0; @@ -338,8 +339,9 @@ int VRecordingList::doPlay(bool resume) { toPlay->loadRecInfo(); // check if still need this toPlay->loadMarks(); + bool ish264; - bool isRadio = toPlay->isRadio(); + bool isRadio = toPlay->isRadio(ish264); if (isRadio) { @@ -351,11 +353,30 @@ int VRecordingList::doPlay(bool resume) } else { - VVideoRec* vidrec = new VVideoRec(toPlay); - vidrec->draw(); - boxstack->add(vidrec); - boxstack->update(vidrec); - vidrec->go(resume); + if (ish264 && !Video::getInstance()->supportsh264()) { + VInfo* vi = new VInfo(); + vi->setSize(360, 200); + vi->createBuffer(); + if (Video::getInstance()->getFormat() == Video::PAL) + vi->setPosition(190, 170); + else + vi->setPosition(180, 120); + vi->setOneLiner(tr("H264 video not supported")); + vi->setExitable(); + vi->setBorderOn(1); + vi->setTitleBarColour(Colour::DANGER); + vi->okButton(); + vi->draw(); + boxstack->add(vi); + boxstack->update(vi); + + } else { + VVideoRec* vidrec = new VVideoRec(toPlay, ish264); + vidrec->draw(); + boxstack->add(vidrec); + boxstack->update(vidrec); + vidrec->go(resume); + } } return 1; } diff --git a/vvideorec.cc b/vvideorec.cc index 1a506ed..c84c9a6 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -18,6 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include + #include "vvideorec.h" #include "vteletextview.h" @@ -41,7 +43,7 @@ #include "log.h" #include "channel.h" -VVideoRec::VVideoRec(Recording* rec) +VVideoRec::VVideoRec(Recording* rec, bool ish264) { boxstack = BoxStack::getInstance(); vdr = VDR::getInstance(); @@ -53,8 +55,10 @@ VVideoRec::VVideoRec(Recording* rec) videoMode = video->getMode(); myRec = rec; + video->seth264mode(ish264); + player = new Player(Command::getInstance(), this, this); - player->init(myRec->IsPesRecording); + player->init(myRec->IsPesRecording,myRec->recInfo->fps); playing = false; @@ -289,7 +293,7 @@ int VVideoRec::handleCommand(int command) // skip to previous mark Log* logger = Log::getInstance(); int currentFrame = (player->getCurrentFrameNum()); // get current Frame - currentFrame -= 5 * video->getFPS(); // subtrack 5 seconds, else you cannot skip more than once back .. + currentFrame -= 5. * myRec->recInfo->fps; // subtrack 5 seconds, else you cannot skip more than once back .. int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame if (prevMark) @@ -453,7 +457,7 @@ void VVideoRec::processMessage(Message* m) { // chasing playback // Work out an approximate length in frames (good to 1s...) - lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS(); + lengthFrames = (ULONG)((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps); } else { @@ -866,6 +870,22 @@ void VVideoRec::timercall(int clientReference) } } +hmsf VVideoRec::framesToHMSF(ULONG frames) +{ + hmsf ret; + /* from vdr */ + double Seconds; + double fps=myRec->recInfo->fps; + ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1); + int s = int(Seconds); + ret.seconds=s % 60; + ret.minutes = s / 60 % 60; + ret.hours = s / 3600; + + + return ret; +} + void VVideoRec::drawBarClocks() { if (barScanHold) @@ -907,15 +927,15 @@ void VVideoRec::drawBarClocks() { // chasing playback // Work out an approximate length in frames (good to 1s...) - lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS(); + lengthFrames =(ULONG) ((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps); } else { lengthFrames = player->getLengthFrames(); } - hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum); - hmsf lengthHMSF = video->framesToHMSF(lengthFrames); + hmsf currentFrameHMSF = framesToHMSF(currentFrameNum); + hmsf lengthHMSF = framesToHMSF(lengthFrames); char buffer[100]; if (currentFrameNum >= lengthFrames) @@ -984,12 +1004,12 @@ void VVideoRec::drawBarClocks() { // Draw blips where start and end margins probably are - posPix = 302 * startMargin * video->getFPS() / lengthFrames; + posPix =(int) (302. * myRec->recInfo->fps * ((double)startMargin) /((double) lengthFrames)); rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); - posPix = 302 * (lengthFrames - endMargin * video->getFPS()) / lengthFrames; + posPix = (int)(302. * ((double)lengthFrames - ((double)endMargin) * myRec->recInfo->fps) / ((double)lengthFrames)); rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); diff --git a/vvideorec.h b/vvideorec.h index 081c88b..3f10acf 100644 --- a/vvideorec.h +++ b/vvideorec.h @@ -30,8 +30,9 @@ #include "colour.h" #include "osdreceiver.h" +#include "video.h" + class VDR; -class Video; class Timers; class Player; class Recording; @@ -41,12 +42,15 @@ class BoxStack; class VInfo; class Bitmap; + + + //#include "vepg.h" // for testing EPG in NTSC with a NTSC test video class VVideoRec : public Boxx, public TimerReceiver, public OSDReceiver { public: - VVideoRec(Recording* rec); + VVideoRec(Recording* rec, bool ish264); ~VVideoRec(); void preDelete(); int handleCommand(int command); @@ -61,6 +65,8 @@ class VVideoRec : public Boxx, public TimerReceiver, public OSDReceiver void doTeletext(); + hmsf framesToHMSF(ULONG frames); //moved from video, this is a recording property, if needed elsewhere -> recording + private: BoxStack* boxstack; VDR* vdr; diff --git a/vwelcome.cc b/vwelcome.cc index 6306fc6..3f92793 100644 --- a/vwelcome.cc +++ b/vwelcome.cc @@ -68,12 +68,24 @@ VWelcome::VWelcome() sl.addOption(tr("2. Radio"), 2, 0); sl.addOption(tr("3. Recordings"), 3, 0); sl.addOption(tr("4. Timers"), 4, 0); +#ifndef _MIPS_ARCH +#ifndef WIN32 sl.addOption(tr("5. MediaPlayer"), 5, 0); +#endif +#endif sl.addOption(tr("6. Options"), 6, 0); +#ifndef _MIPS_ARCH sl.addOption(tr("7. Reboot"), 7, 0); +#else + sl.addOption(tr("7. Exit to Gaya"), 7, 0); +#endif jpeg.setPosition(240, 60); +#ifndef _MIPS_ARCH jpeg.init("/vdr.jpg"); +#else + jpeg.init("vdr.jpg"); +#endif add(&jpeg); } diff --git a/winmain.cc b/winmain.cc index befa190..9b261f0 100644 --- a/winmain.cc +++ b/winmain.cc @@ -341,8 +341,9 @@ INT WINAPI WinMain( HINSTANCE hinst , HINSTANCE previnst, LPSTR cmdline, int cmd }; } } else { - //Render - ((OsdWin*)osd)->Render(); + //Render, moved to OSD ! + Sleep(20); + //((OsdWin*)osd)->Render(); } } // When that returns quit ------------------------------------------------------------------------------------------ @@ -386,9 +387,15 @@ void CalculateWindowSize(RECT * size,ULONG size_mode) { } width=size->right-size->left-adjwidth; height=size->bottom-size->top-adjheight; - UCHAR mode=video->getMode(); - UCHAR aspect=((VideoWin*)video)->getAspectRatio(); - UCHAR tvsize=((VideoWin*)video)->getPseudoTVsize(); + UCHAR mode=Video::PAL; + UCHAR aspect=Video::ASPECT4X3; + UCHAR tvsize=Video::ASPECT4X3; + if (video) { + mode=video->getMode(); + aspect=((VideoWin*)video)->getAspectRatio(); + tvsize=((VideoWin*)video)->getPseudoTVsize(); + } + double aspectrt=4./3.; if (tvsize==Video::ASPECT16X9) { if (aspect==Video::ASPECT16X9) { @@ -568,10 +575,11 @@ LONG FAR PASCAL WindowProc(HWND wind, UINT msg, WPARAM wparam, LPARAM lparam) if (wparam == SIZE_MAXIMIZED) { ToggleFullscreen(); return 0; - } else if (wparam == SIZE_MINIMIZED) { + } /*else if (wparam == SIZE_MINIMIZED) { ToggleFullscreen(); return 0; - } + }*/ + //AdjustWindow(); } break; case WM_PAINT: diff --git a/wjpeg.cc b/wjpeg.cc index 7b25abb..2d6b387 100644 --- a/wjpeg.cc +++ b/wjpeg.cc @@ -464,6 +464,7 @@ get_exif_orient (j_decompress_ptr cinfo) { unsigned int tmp, offset, length, numtags; int orient=-1; + jpegUserData * ud=0; boolean swap; orient = 1; offset = 0; @@ -507,7 +508,7 @@ get_exif_orient (j_decompress_ptr cinfo) if( orient==0 || orient>8 ) orient = 1; Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient); - jpegUserData * ud=(jpegUserData *)(mysrc->userdata); + ud=(jpegUserData *)(mysrc->userdata); switch(orient) { case 3: ud->ctl->exifRotation=WJpeg::ROT_180; -- 2.39.2