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
}
}
}
virtual int mute()=0;
virtual int unMute()=0;
virtual bool supportsAc3()=0;
+ virtual bool maysupportAc3(){return false;}
int volumeUp();
int volumeDown();
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);
//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();
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) {
else return 0;
}
-UINT AudioWin::DeliverMediaPacket(MediaPacket packet,
- const UCHAR* buffer,
+UINT AudioWin::DeliverMediaPacket(const MediaPacket packet,
+ UCHAR* buffer,
UINT *samplepos)
{
UINT haveToCopy;
if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample
//samplepos=0;
- MILLISLEEP(10);
+ //MILLISLEEP(10);
return *samplepos;
}
ms_pos=ms->GetActualDataLength();
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();
// 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);
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:
#include "boxx.h"
#include "bitmap.h"
#include "log.h"
+#include <stdlib.h>
char Boxx::numBoxxes = 0;
#ifdef WIN32
#include "surfacewin.h"
#else
+
+#ifdef _MIPS_ARCH
+#include "surfacedirectfb.h"
+#else
#include "surfacemvp.h"
#endif
+#endif
+
class Bitmap;
class Boxx
numDPids = 0;
numSPids = 0;
+ vstreamtype=2; //Mpeg2
+
}
Channel::~Channel()
ULONG number;
ULONG type;
+ UCHAR vstreamtype;
char* name;
int index;
void Command::stop()
{
// VDR::getInstance()->cancelFindingServer();
+ logger->log("Command", Log::NOTICE, "Command stop1...");
+
udp.shutdown();
+ logger->log("Command", Log::NOTICE, "Command stop2...");
irun = 0;
}
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
{
#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);
#else
ReleaseMutex(masterLock);
#endif
+
}
void Command::postMessage(Message* m)
// 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?
}
int max(int, int);
int min(UINT, int);
-
+#ifdef _MIPS_ARCH
+ #define Surface_TYPE SurfaceDirectFB
+#else
#define Surface_TYPE SurfaceMVP
+#endif
+
#define Thread_TYPE ThreadP
#include <pthread.h>
#define ThreadID_TYPE pthread_t
#include <cstdlib>
+#include <math.h>
+
#define DEMUXER_SEQ_HEAD 0x000001B3
#define DEMUXER_PIC_HEAD 0x00000101
+
+#define DEMUXER_H264_ACCESS_UNIT 0x00000109
+#define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107
+
+
#define SEEK_THRESHOLD 150000 // About 1.5 seconds
// Statics
const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };
Demuxer* Demuxer::instance = NULL;
+class NALUUnit {
+public:
+ NALUUnit(const UCHAR* buf,UINT length_buf);
+ ~NALUUnit();
+
+inline UINT getBits(UINT num_bits);
+ UINT getUe();
+ int getSe();
+ bool isEonalu() {return eonalu;};
+
+protected:
+ UCHAR* nalu_buf;
+ UINT nalu_length;
+ UINT pos;
+ UCHAR bit_pos;
+ UCHAR working_byte;
+ UINT last_bytes;
+ bool eonalu;
+};
+
+NALUUnit::NALUUnit(const UCHAR *buf, UINT length_buf)
+{
+ nalu_length=0;
+ nalu_buf=NULL;
+ pos=0;
+ bit_pos=0;
+ working_byte=0;
+ last_bytes=0;
+ eonalu=false;
+
+ UINT nalu_start=0;
+ UINT nalu_end=0;
+ UINT pattern =(((UINT)buf[ 0] << 16) |
+ ((UINT)buf[1] << 8) |
+ (UINT)buf[2] );
+ nalu_start=3;
+ while (pattern != 0x000001)
+ {
+ if (++nalu_start >= length_buf) return;
+ pattern = ((pattern << 8) | buf[nalu_start])&0x00FFFFFF;
+ }
+ nalu_end=nalu_start+1;
+ pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;
+
+ while (pattern != 0x000001 && pattern != 0x000000)
+ {
+ if (++nalu_end >= length_buf) { nalu_end+=3;break;};
+ pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;
+ }
+ nalu_end-=3;
+ nalu_end=min(length_buf-1,nalu_end);
+ nalu_length=nalu_end-nalu_start;
+ nalu_buf=(UCHAR*)malloc(nalu_length);
+ memcpy(nalu_buf,buf+nalu_start,nalu_length);
+ pos=1;
+}
+
+NALUUnit::~NALUUnit()
+{
+ if (nalu_buf) free(nalu_buf);
+}
+
+inline UINT NALUUnit::getBits(UINT num_bits)
+{
+ if (num_bits==0) return 0; //???
+ UINT remain_bits=num_bits;
+ UINT work=0;
+ //May be slow, but should work!
+ while (remain_bits>0) {
+ if (bit_pos==0) {
+ if (pos<nalu_length)
+ {
+ last_bytes=(last_bytes<<8) & nalu_buf[pos];
+ if ((last_bytes & 0x00FFFFFF) == 0x000003) pos++; //emulation prevention byte
+ if (pos<nalu_length)
+ {
+ working_byte=nalu_buf[pos];
+ pos++;
+ }
+ else
+ {
+ working_byte=0;
+ eonalu=true;
+ }
+ }
+ else
+ {
+ working_byte=0;
+ eonalu=true;
+ }
+
+ }
+ UINT fetch_bits=min(remain_bits,8-bit_pos);
+ work=work <<fetch_bits;
+ //work|=((working_byte>>bit_pos) & (0xFF>>(8-fetch_bits)));
+ work|=(working_byte &(0xFF>>(bit_pos)))>>(8-fetch_bits-bit_pos);
+ remain_bits-=fetch_bits;
+ bit_pos=(bit_pos+fetch_bits)%8;
+ }
+ return work;
+}
+
+UINT NALUUnit::getUe()
+{
+ int leadbits=-1;
+ bool bit;
+ for( bit = 0; !bit && !eonalu; leadbits++ )
+ bit = getBits(1);
+ if (eonalu) return true;
+ return ((1 << leadbits)-1)+getBits(leadbits);
+}
+
+int NALUUnit::getSe()
+{
+ UINT input=getUe();
+ if (input==0) return 0;
+ int output=((input+1)>>1);
+ if (input & 0x1) output*=-1;
+ return output;
+}
+
+
+
static const int PESPacket_initial_size = 2000;
// PESPacket methods
return data[index];
}
-UINT PESPacket::findPictureHeader() const
+UINT PESPacket::findPictureHeader(bool h264) const
{
if (size < 12) return 0;
UINT pattern = ( ((UINT)data[ 8] << 24) |
((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;
((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;
}
vid_seeking = aud_seeking = false;
video_pts = audio_pts = 0;
ispre_1_3_19 = false;
+ packetnum=0;
+ h264 = false;
+ fps = 25.0;
}
Demuxer::~Demuxer()
}
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)
{
} else {
isteletextdecoded = false;
}
-
+ fps=infps;
reset();
initted = true;
subtitles = tsubtitles;
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++)
{
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)
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 &&
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
{
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
{
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;i<temp2;i++)
+ nalu.getSe();
+ }
+ nalu.getUe(); //Num refframes
+ nalu.getBits(1);
+ horizontal_size=(nalu.getUe()+1)*16;
+
+ vertical_size=(nalu.getUe()+1)*16;
+ int interlaced=nalu.getBits(1);
+ vertical_size*=(2-interlaced);
+
+ if (!interlaced) nalu.getBits(1);
+ nalu.getBits(1);
+ if (nalu.getBits(1))
+ {
+ nalu.getUe();
+ nalu.getUe();
+ nalu.getUe();
+ nalu.getUe();
+ }
+ if (nalu.getBits(1))
+ {
+ if (nalu.getBits(1))
+ {
+ UINT aspectratioidc=nalu.getBits(8);
+ bool hasaspect=false;
+ const float aspects[]={1., 1./1.,12./11.,10./11.,16./11.,40./33.,
+ 24./11.,20./11.,32./11.,80./33.,18./11.,15./11.,64./33.,160./99.,4./3.,3./2.,2./1.};
+
+ float aspectratio=((float) horizontal_size)/((float) vertical_size);
+ if (aspectratioidc<=16)
+ {
+ hasaspect=true;
+ aspectratio*=aspects[aspectratioidc];
+
+ }
+ else if (aspectratioidc==255)
+ {
+ int t_sar_width=nalu.getBits(16);
+ int t_sar_height=nalu.getBits(16);
+ if (t_sar_width!=0 && t_sar_height!=0)
+ {
+ hasaspect=true;
+ aspectratio*=((float)t_sar_width)/((float)t_sar_height);
+ }
+ }
+ if (hasaspect)
+ {
+ if (fabs(aspectratio-16./9.)<0.1) setAspectRatio(ASPECT_16_9);
+ else if (fabs(aspectratio-4./3.)<0.1) setAspectRatio(ASPECT_4_3);
+ }
+ }
+
+ }
+
+ }
+
+ if (vid_seeking)
+ {
+ vid_seeking = 0;
+ video_pts_seek = video_pts;
+ Log::getInstance()->log("Demuxer", Log::DEBUG,
+ "Entering audio sync: Video PTS = %llu", video_pts);
+ Log::getInstance()->log("Demuxer", Log::DEBUG,
+ "Entering audio sync: Audio PTS = %llu", audio_pts);
+ }
+ return;
+ }
}
- }
}
UINT Demuxer::stripAudio(UCHAR* buf, UINT len)
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)
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);
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();
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; }
// 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
{
bool initted;
bool vid_seeking;
bool aud_seeking;
+ bool h264;
int video_current, audio_current, teletext_current, subtitle_current;
// Video stream information
int horizontal_size;
int vertical_size;
+ int profile;
enum AspectRatio aspect_ratio;
int arcnt;
int frame_rate;
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];
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;
buffer=new PacketBuffer(&audiostream,streamtype);
// buffer=new PacketBuffer(&teststream,streamtype);
globalBytesWritten=0;
+ packetnum=0;
id3=NULL;
info=NULL;
vbr=NULL;
buffer->newStream();
tmpFill=0;
readHeaders=0;
+ packetnum=0;
outOfSync=0;
globalBytesWritten=0;
if (id3) delete id3;
}
// 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,
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
#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) {
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;
}
#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 ) {
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;
mpegInfo *info;
vbrInfo *vbr;
+ unsigned int packetnum;
+
};
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;
}
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) {
// 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
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 &&
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();
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!
}
-bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len)
+bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len, bool &ish264)
{
int pmtpidy=0;
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
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;
}
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);
}
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;};
typedef std::deque<PTSMapEntry> PTSMap;
PTSMap pts_map;
Mutex pts_map_mutex;
- void parseTSPacketDetails(PESPacket packet);
+ void parseTSPacketDetails(PESPacket &packet);
};
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()
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();
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!
#include "defines.h"
#include <list>
-#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
{
// 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
// (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
/*
- Copyright 2004-2005 Chris Tallon
+ Copyright 2004-2005 Chris Tallon, Marten Richter
This file is part of VOMP.
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 <math.h>
+
+#include <mfidl.h>
+#include <Mfapi.h>
+#include <mferror.h>
+
+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;i<surfaces.size();i++) {
- if (surfaces[i]!=NULL) surfaces[i]->Release();
- 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;i<surfaces.size();i++) {
+ if (surfaces[i]!=NULL) surfaces[i]->Release();
+ 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<IVMRSurfaceAllocator9*>(this);
- AddRef();
- return S_OK;
- } else if (refiid==IID_IVMRImagePresenter9) {
- *obj=static_cast<IVMRImagePresenter9*>(this);
- AddRef();
- return S_OK;
- }
- return E_NOINTERFACE;
+ if (refiid==IID_IVMRSurfaceAllocator9) {
+ *obj=static_cast<IVMRSurfaceAllocator9*>(this);
+ AddRef();
+ return S_OK;
+ } else if (refiid==IID_IVMRImagePresenter9) {
+ *obj=static_cast<IVMRImagePresenter9*>(this);
+ AddRef();
+ return S_OK;
+ } else if (refiid==IID_IMFVideoDeviceID) {
+ *obj=static_cast<IMFVideoDeviceID*> (this);
+ AddRef();
+ return S_OK;
+ } else if (refiid==IID_IMFTopologyServiceLookupClient ) {
+ *obj=static_cast<IMFTopologyServiceLookupClient*> (this);
+ AddRef();
+ return S_OK;
+ } else if (refiid==IID_IQualProp ) {
+ *obj=static_cast<IQualProp*> (this);
+ AddRef();
+ return S_OK;
+ } else if (refiid==IID_IMFGetService) {
+ *obj=static_cast<IMFGetService*> (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;i<surfaces.size();i++) {
+ if (surfaces[i]!=NULL)
+ {
+ IMFSample *sample=NULL;
+ ptrMFCreateVideoSampleFromSurface(surfaces[i],&sample);
+ if (sample) emptyevrsamples.push(sample);
+ }
+ }
+ Unlock();
+
+}
+
+void DsAllocator::FlushEVRSamples()
+{
+ Lock();
+ while(fullevrsamples.size()>0)
+ {
+ 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<n_stats;i++)
+ {
+ sync_offset[i]=0;
+ jitter_offset[i]=0;
+ }
+ framesdrawn=0;
+ lastdelframe=0;
+ framesdropped=0;
+ avg_sync_offset=0;
+ dev_sync_offset=0;
+ jitter=0;
+ sync_pos=0;
+ jitter_pos=0;
+ avgfps=0;
+}
+
+void DsAllocator::CalcSyncOffsets(int sync)
+{
+ sync_offset[sync_pos]=sync;
+ sync_pos=(sync_pos +1)%n_stats;
+
+ double mean_value=0;
+ for (int i=0;i<n_stats;i++)
+ {
+ mean_value+=sync_offset[i];
+ }
+ mean_value/=(double) n_stats;
+ double std_dev=0;
+ for (int i=0;i<n_stats;i++)
+ {
+ double temp_dev=(mean_value-(double)sync_offset[i]);
+ std_dev+=temp_dev*temp_dev;
+ }
+ std_dev/=(double)n_stats;
+ avg_sync_offset=mean_value;
+ dev_sync_offset=sqrt(std_dev);
+}
+
+void DsAllocator::CalcJitter(int jitter)
+{
+ jitter_offset[jitter_pos]=jitter;
+ jitter_pos=(jitter_pos +1)%n_stats;
+
+
+ double mean_value=0;
+ for (int i=0;i<n_stats;i++)
+ {
+ mean_value+=jitter_offset[i];
+ }
+ mean_value/=(double) n_stats;
+ avgfps=1000./mean_value*100.;
+ double std_dev=0;
+ for (int i=0;i<n_stats;i++)
+ {
+ double temp_dev=(mean_value-(double)jitter_offset[i]);
+ std_dev+=temp_dev*temp_dev;
+ }
+ std_dev/=(double)n_stats;
+ jitter=sqrt(std_dev);
+}
+
+
+HRESULT STDMETHODCALLTYPE DsAllocator::get_FramesDrawn(int *val)
+{
+ *val=framesdrawn;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE DsAllocator::get_AvgFrameRate(int *val)
+{
+ *val=avgfps;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE DsAllocator::get_Jitter(int *val)
+{
+ *val=jitter;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE DsAllocator::get_AvgSyncOffset(int *val)
+{
+ *val=avg_sync_offset;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE DsAllocator::get_DevSyncOffset(int *val)
+{
+ *val=dev_sync_offset;
+ return S_OK;
+}
+HRESULT STDMETHODCALLTYPE DsAllocator::get_FramesDroppedInRenderer(int *val)
+{
+ *val=framesdropped;
+ return S_OK;
+}
/*
- Copyright 2004-2005 Chris Tallon
+ Copyright 2004-2005 Chris Tallon, Marten Richter
This file is part of VOMP.
#ifndef DSALLOCATOR_H
#define DSALLOCATOR_H
+#include <queue>
#include <vector>
+
+
using namespace std;
+
#include <winsock2.h>
#include <d3d9.h>
#include <dshow.h>
#include <vmr9.h>
+#include <evr.h>
#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();
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<IDirect3DSurface9* > surfaces;
+ vector<IDirect3DSurface9*> surfaces;
+ queue<IMFSample*> emptyevrsamples;
+ queue<IMFSample*> 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;
};
+
#endif
return true;
}
+bool DsSourceFilter::changeVType(int type,IMediaSample* ms,void * details)
+{
+ if (!videopin ) {
+ return false;
+ }
+ videopin->SetPinMode(type,details);
+ videopin->SetMsToMt(ms);
+
+
+ return true;
+}
+
#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 {
bool supportsAc3();
bool changeAType(int type,IMediaSample* ms);
+ bool changeVType(int type,IMediaSample* ms, void *details);
protected:
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) {
connected=NULL;
connectedinput=NULL;
allocator=NULL;
+
+ v_width=640;
+ v_height=480;
+
if (isaudiopin)
{
pinmode=MPTYPE_MPEG_AUDIO;
}
else
{
- pinmode=MPTYPE_VIDEO;
+
+ pinmode=MPTYPE_VIDEO_MPEG2;
}
}
}
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;
}
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));
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);
}
res = S_FALSE ;
}
break;
- case MPTYPE_VIDEO:
+ case MPTYPE_VIDEO_MPEG2:
if (pmt->majortype==MEDIATYPE_Video &&
pmt-> subtype==MEDIASUBTYPE_MPEG2_VIDEO)
{
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);
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;
}
}
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);
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;
AM_MEDIA_TYPE medtype;
IMemAllocator* allocator;
-
-
-
+ int v_width;
+ int v_height;
};
*/
#include "eventdispatcher.h"
+#include <stdlib.h>
+
EventDispatcher::EventDispatcher()
{
class EventDispatcher
{
- typedef list<EDReceiver*> EDRL;
public:
+ typedef list<EDReceiver*> EDRL;
+
EventDispatcher();
virtual ~EventDispatcher() {};
#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;
#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;
}
// 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();
// 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");
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");
#include "media.h"
#include <sys/stat.h>
#include <sys/types.h>
+#include <stdlib.h>
#include <iostream>
#include "log.h"
virtual int init(void* device)=0;
virtual int shutdown()=0;
+ bool isInitted() {return initted;};
virtual int getFD()=0;
#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
{
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);
}
{
if (initted) return 0;
Video* video = Video::getInstance();
+ window=*((HWND*)device);
//First Create Direct 3D Object
d3d=Direct3DCreate9(D3D_SDK_VERSION);
if (!d3d)
// 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),
}
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);
filter_type=D3DTEXF_NONE;
}
+ if (evrsupported)
+ {
+ if (ptrDXVA2CreateDirect3DDeviceManager9(&dxvatoken,&d3ddevman)!=S_OK) evrsupported=false;
+ else {
+ d3ddevman->ResetDevice(d3ddevice,dxvatoken);
+ }
+ }
+
+
//Now we will create the Screen
screen->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;
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);
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;
}
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()
{
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();
InternalRendering(NULL);
lastrendertime=timeGetTime();
} else {
- Sleep(5);
+ //Sleep(5);
}
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:
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 {
//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);
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(){
((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
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() {
#include "osd.h"
#include "defines.h"
#include "log.h"
+#include "threadwin.h"
#include <winsock2.h>
#include <d3d9.h>
+#include <Dxva2api.h>
struct OSDVERTEX
{
class DsAllocator;
-class OsdWin : public Osd
+
+
+class OsdWin : public Osd, public ThreadWin
{
public:
OsdWin();
void screenShot(char* fileName);
+ void threadMethod();
+ void threadPostStopCleanup();
+
LPDIRECT3DDEVICE9 getD3dDev() ;
LPDIRECT3D9 getD3d() ;
// This function is called from the WinMain function in order to get Screen updates
void 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;
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
videoStartup = false;
threadBuffer = NULL;
-
+
blockSize = 100000;
startupBlockSize = 250000;
video->turnVideoOn();
if (initted) shutdown();
}
-int Player::init(bool p_isPesRecording)
+int Player::init(bool p_isPesRecording,double framespersecond)
{
if (initted) return 0;
#ifndef WIN32
mutex=CreateMutex(NULL,FALSE,NULL);
#endif
is_pesrecording = p_isPesRecording;
+ fps=framespersecond;
if (is_pesrecording)
demuxer = new DemuxerVDR();
else
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();
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
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
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
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())
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)
// 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
#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);
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);
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);
}
}
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);
bool videoStartup;
bool is_pesrecording;
+ double fps;
#ifndef WIN32
pthread_mutex_t mutex;
subtitlesShowing = false;
videoStartup = false;
+ pendingAudioPlay = false;
stopNow = false;
state = S_STOP;
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();
/*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)
{
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();
{
case S_PREBUFFERING:
{
+ pendingAudioPlay=false;
vfeed.release();
state = newState;
return;
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();
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();
{
case S_PLAY:
{
+ pendingAudioPlay=false;
audio->unPause();
video->unPause();
state = newState;
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();
}
case S_STOP:
{
+ pendingAudioPlay=false;
vdr->stopStreaming();
clearStreamChunks();
vfeed.stop();
{
case S_STOP:
{
+ pendingAudioPlay=false;
vdr->stopStreaming();
clearStreamChunks();
vfeed.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();
{
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;
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);
bool checkError();
bool videoStartup;
+ bool pendingAudioPlay;
bool stopNow;
+ bool h264;
int preBufferCount;
const static int preBufferAmount = 3;
* 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
================================
ULONG resumePoint;
char* summary;
+ double fps;
+
ULONG numComponents;
UCHAR* streams;
UCHAR* types;
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);
}
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);
void loadRecInfo();
void dropRecInfo();
- bool isRadio();
+ bool isRadio(bool &h264);
bool IsPesRecording;
void loadMarks();
#ifdef WIN32
CloseHandle(mutex);
#endif
+
}
initted = 0;
}
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;
newPacket.pos_buffer = 0;
newPacket.type = type;
newPacket.pts=0;
+ newPacket.dts=0;
newPacket.synched=false;
+ newPacket.index=index;
#ifdef WIN32
newPacket.disconti=false;
newPacket.presentation_time=0;
#endif
if (type!=MPTYPE_MPEG_AUDIO_LAYER3) {//no PES
//Extract the pts...
+ bool hasdts=false;
if ((inbuf[7] & 0x80) && len>14 ) {
newPacket.synched=true;
newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |
( (ULLONG)(inbuf[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
}
}
lock();
mediapackets.push_back(newPacket);
unLock();
- }
+ }// else {
+ // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize);
+ //}
+
return ret;
}
lock();
if (consumed != 0) ret = true;
if (consumed > listlength) consumed = listlength;
- while (consumed--) mediapackets.pop_front();
+ while (consumed--)
+ {
+ mediapackets.pop_front();
+ }
}
unLock();
return ret;
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:
for (i = 0; i < n; i++)
{
- w += font->width[text[i]];
+ w += font->width[(unsigned char)text[i]];
}
x -= w;
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;
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()
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
-/*\r
- Copyright 2008 Marten Richter\r
-\r
- This file is part of VOMP.\r
-\r
- VOMP is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation; either version 2 of the License, or\r
- (at your option) any later version.\r
-\r
- VOMP is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
- You should have received a copy of the GNU General Public License\r
- along with VOMP; if not, write to the Free Software\r
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
-*/\r
-\r
-\r
-/* Portions from vdr osdteletext plugin "txtrender.c": */\r
-/***************************************************************************\r
- * *\r
- * txtrender.c - Teletext display abstraction and teletext code *\r
- * renderer *\r
- * *\r
- * This program is free software; you can redistribute it and/or modify *\r
- * it under the terms of the GNU General Public License as published by *\r
- * the Free Software Foundation; either version 2 of the License, or *\r
- * (at your option) any later version. *\r
- * *\r
- * Changelog: *\r
- * 2005-03 initial version (c) Udo Richter *\r
- * *\r
- ***************************************************************************/\r
-\r
-#include "teletextdecodervbiebu.h"\r
-#include "teletxt/tables.h"\r
-#include "message.h"\r
-#include "command.h"\r
-#include "video.h"\r
-\r
-#ifdef WIN32\r
-#include <windows.h>\r
-#endif\r
-\r
-TeletextDecoderVBIEBU::TeletextDecoderVBIEBU()\r
-{\r
- selectedpage=0x100;\r
- ourpage=false;\r
- flags=lang=0; \r
- \r
- CleanPage();\r
- FirstG0CodePage=0;\r
- SecondG0CodePage=0;\r
- dirty=false;\r
- txtview=NULL;\r
- firstlineupdate=0;\r
- gotcha=false;\r
- char digits[]={'1','0','0'};\r
- setKeyinDigits(digits,false);\r
- isrecording=false;\r
- for (int i=0;i<10;i++) record_pages[i]=-1;\r
- \r
-\r
-}\r
-\r
-TeletextDecoderVBIEBU::~TeletextDecoderVBIEBU()\r
-{\r
-\r
-\r
-}\r
-\r
-long long TeletextDecoderVBIEBU::SetStartOffset(long long curreftime, bool *rsync)\r
-{\r
- return 0; \r
-}\r
-\r
-void TeletextDecoderVBIEBU::ResetTimeOffsets()\r
-{\r
-\r
-}\r
-\r
-\r
-\r
-void TeletextDecoderVBIEBU::ResetDecoder()\r
-{\r
- gotcha=false;\r
- ourpage=false;\r
- firstlineupdate=0;\r
- selectedpage=0x100;\r
- CleanPage();\r
- char digits[]={'1','0','0'};\r
- setKeyinDigits(digits,false);\r
- for (int i=0;i<10;i++) record_pages[i]=-1;\r
- \r
-}\r
-\r
-void TeletextDecoderVBIEBU::setPage(unsigned int newpage)\r
-{\r
- selectedpage=newpage;\r
- gotcha=false;\r
- ourpage=false;\r
- firstlineupdate=0;\r
- for (int i=0;i<25;i++) {\r
- memset(curpage[i],0,40);\r
- }\r
-}\r
-\r
-void TeletextDecoderVBIEBU::CleanPage()\r
-{\r
- int x,y;\r
- for (int i=0;i<25;i++) {\r
- memset(curpage[i],0,40);\r
- }\r
- for (y=0;y<25;y++) {\r
- for (x=0;x<40;x++) {\r
- cTeletextChar c;\r
- c.SetFGColor(ttcWhite);\r
- c.SetBGColor(ttcBlack);\r
- c.SetCharset(CHARSET_LATIN_G0);\r
- c.SetChar(' ');\r
- if (flags&0x60) {\r
- c.SetBoxedOut(true); \r
- }\r
- setChar(x,y,c);\r
- }\r
- } \r
-\r
-}\r
-void TeletextDecoderVBIEBU::setKeyinDigits(char digits[3],bool inKeying)\r
-{\r
- int x;\r
- inkeying=inKeying;\r
- for (x=0;x<3;x++) {\r
- cTeletextChar c;\r
- c.SetFGColor(ttcWhite);\r
- c.SetBGColor(ttcBlack);\r
- c.SetCharset(CHARSET_LATIN_G0);\r
- c.SetChar(digits[x]);\r
- if (flags&0x60) {\r
- c.SetBoxedOut(true); \r
- }\r
- setChar(x+3,0,c);\r
- keyindigits[x]=digits[x];\r
- }\r
-}\r
-\r
-void TeletextDecoderVBIEBU::PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos)\r
-{\r
- mediapacket = mplist.front();\r
-}\r
-\r
-static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)\r
-{\r
- // Assume pts1, pts2 < 2^33; calculate pts1 - pts2\r
- if (pts1 > pts2)\r
- return pts1 - pts2;\r
- else\r
- return (1LL<<33) + pts1 - pts2;\r
-}\r
-\r
-UINT TeletextDecoderVBIEBU::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos)\r
-{\r
- if (mediapacket.type != MPTYPE_TELETEXT)\r
- {\r
- *samplepos= 0;\r
- return 1; //Skip it! \r
- }\r
- unsigned int headerstrip;\r
- unsigned char txtdata[43];\r
- headerstrip=buffer[mediapacket.pos_buffer+8]+9;\r
- //headerstrip+=4; //substream id\r
- unsigned int datapos=0;\r
- unsigned int datatype=buffer[mediapacket.pos_buffer+headerstrip+0];\r
- //Chris should we use here the pts data from mediapacket ?\r
- // in this case the data fields should also be added in mediamvp\r
- if (mediapacket.synched)\r
- { // An entry exists in the work list\r
- ULLONG nowPTS = Video::getInstance()->getCurrentTimestamp();\r
- if (PTSDifference(mediapacket.pts, nowPTS) >= 1200*90000) {\r
- *samplepos=0;\r
- return 1;//bad data skip it\r
- }\r
- if (nowPTS < (mediapacket.pts-4000) ) {\r
- *samplepos=0;\r
- return 0;\r
- } \r
- }\r
- \r
- if (( datatype>=0x10 && datatype <=0x1F) ||\r
- ( datatype>=0x99 && datatype <=0x9B)) {\r
- //EBU VBI DATA\r
- datapos++;\r
- while (datapos< (mediapacket.length-headerstrip)) {\r
- unsigned int unit_id=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
- datapos++;\r
- unsigned int unit_length=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
- datapos++;\r
- switch (unit_id) {\r
- case 0x02:\r
- case 0x03: {//Teletext with and without subtitles\r
- //call teletext decoder\r
- unsigned int field=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
-\r
- if ((datapos+44)< (mediapacket.length-headerstrip)) {\r
- for (int i=0;i<42;i++) {\r
- txtdata[i]=invtab[buffer[mediapacket.pos_buffer+headerstrip+datapos+2+i]];\r
- }\r
- DecodeTeletext(txtdata,field);\r
- }\r
- }break;\r
- case 0xC0: //inverted Teletext\r
- //call teletext decoder\r
- break;\r
- \r
- case 0xC3: //VPS\r
- //what to do with this, in the moment we do not need it\r
- break;\r
- case 0xC4: //WSS\r
- //what to do with this, in the moment we do not need it\r
- break;\r
- case 0xC5: //CC\r
- //what to do with this, in the moment we do not need it\r
- break;\r
- case 0xC6: //monochrome 4:2:2 samples, what is that? \r
- //what to do with this, in the moment we do not need it\r
- break;\r
- default:\r
- // case 0x00,0x01,0x04..0x7f,0x80..0xbf,0xc1,0xc2,0xc7..0xfe,0xff: //discard\r
- //discard\r
- break;\r
- };\r
- datapos+=unit_length;\r
- // while (buffer[mediapacket.pos_buffer+headerstrip+datapos]==0xFF &&(datapos< (mediapacket.length-headerstrip))) {\r
- // datapos++; //stuffing bytes\r
- // }\r
-\r
- \r
- }\r
- *samplepos=0;\r
- return 1;\r
-\r
-\r
- } else {\r
- *samplepos= 0;\r
- return 1; //Skip it! and discard data \r
- }\r
-\r
- return 0;\r
-\r
-}\r
-// This part is inspired by the vdr-plugin-osdteletext of Udo Richter and Marcel Wiesweg\r
-void TeletextDecoderVBIEBU::DecodeTeletext(const UCHAR* buffer, unsigned int field) //needs to be exactly 42 byte long!!\r
-{\r
- UCHAR hdrbuf[5];\r
- for (int i=0;i<5;i++) hdrbuf[i]=(unhamtab[buffer[2*i]]&0xF) | ((unhamtab[buffer[2*i+1]]&0xF)<< 4);\r
- int header=hdrbuf[0];\r
- int magazin=header & 0x7;\r
- int line = (header>>3) & 0x1f;\r
- if (magazin==0) magazin=8;\r
- if (line==0)\r
- {\r
- if (ourpage) {\r
- gotcha=true;\r
- inkeying=false;\r
- RenderTeletextCode(false);\r
- } else {\r
- RenderTeletextCode(true);\r
- }\r
- int pagenumber=hdrbuf[1];\r
- int pagemagazin=magazin<<8 | pagenumber;\r
- int pagesubnumber=(hdrbuf[2]) || ((hdrbuf[3]<<8) & 0x3f7f);\r
-\r
- if (pagemagazin == selectedpage) ourpage=true;\r
- else ourpage=false;\r
- if (isrecording) {\r
- for (int i=0;i<10;i++) {\r
- if (pagemagazin==record_pages[i]) break;\r
- if (record_pages[i]==-1) {\r
- record_pages[i]=pagemagazin;\r
- break;\r
- }\r
- }\r
- }\r
- if (hdrbuf[3] &0x80) { //This is a subtitle\r
- for (int i=0;i<10;i++) {\r
- if (pagemagazin==record_pages[i]) break;\r
- if (record_pages[i]==-1) {\r
- record_pages[i]=pagemagazin;\r
- break;\r
- }\r
- }\r
- }\r
-\r
-\r
- if (ourpage) {\r
- lang=((hdrbuf[4]>>5) & 0x07);\r
- flags=hdrbuf[2] & 0x80;\r
- flags|=(hdrbuf[3]&0x40)|((hdrbuf[3]>>2)&0x20); //??????\r
- flags|=((hdrbuf[4]<<4)&0x10)|((hdrbuf[4]<<2)&0x08)|(hdrbuf[4]&0x04)|((hdrbuf[4]>>1)&0x02)|((hdrbuf[4]>>4)&0x01);\r
- for (int i=0;i<25;i++) {\r
- memset(curpage[i],0,40);\r
- }\r
- }\r
- \r
- memcpy(curpage[line],buffer+2,40);\r
- } else if (ourpage && (line<=25)) {\r
- memcpy(curpage[line],buffer+2,40);\r
- \r
- }\r
-}\r
-\r
-\r
-/* from osdteletext plugin: (slightly adapted for vomp)*/\r
-// Font tables\r
-\r
-// teletext uses 7-bit numbers to identify a font set.\r
-// There are three font sets involved:\r
-// Primary G0, Secondary G0, and G2 font set.\r
-\r
-// Font tables are organized in blocks of 8 fonts:\r
-\r
-enumCharsets FontBlockG0_0000[8] = {\r
- CHARSET_LATIN_G0_EN,\r
- CHARSET_LATIN_G0_DE,\r
- CHARSET_LATIN_G0_SV_FI,\r
- CHARSET_LATIN_G0_IT,\r
- CHARSET_LATIN_G0_FR,\r
- CHARSET_LATIN_G0_PT_ES,\r
- CHARSET_LATIN_G0_CZ_SK,\r
- CHARSET_LATIN_G0\r
-};\r
-\r
-enumCharsets FontBlockG2Latin[8]={\r
- CHARSET_LATIN_G2,\r
- CHARSET_LATIN_G2,\r
- CHARSET_LATIN_G2,\r
- CHARSET_LATIN_G2,\r
- CHARSET_LATIN_G2,\r
- CHARSET_LATIN_G2,\r
- CHARSET_LATIN_G2,\r
- CHARSET_LATIN_G2\r
-};\r
-\r
-enumCharsets FontBlockG0_0001[8] = {\r
- CHARSET_LATIN_G0_PL,\r
- CHARSET_LATIN_G0_DE,\r
- CHARSET_LATIN_G0_SV_FI,\r
- CHARSET_LATIN_G0_IT,\r
- CHARSET_LATIN_G0_FR,\r
- CHARSET_LATIN_G0,\r
- CHARSET_LATIN_G0_CZ_SK,\r
- CHARSET_LATIN_G0\r
-};\r
-\r
-enumCharsets FontBlockG0_0010[8] = {\r
- CHARSET_LATIN_G0_EN,\r
- CHARSET_LATIN_G0_DE,\r
- CHARSET_LATIN_G0_SV_FI,\r
- CHARSET_LATIN_G0_IT,\r
- CHARSET_LATIN_G0_FR,\r
- CHARSET_LATIN_G0_PT_ES,\r
- CHARSET_LATIN_G0_TR,\r
- CHARSET_LATIN_G0\r
-};\r
-\r
-\r
-enumCharsets FontBlockG0_0011[8] = {\r
- CHARSET_LATIN_G0,\r
- CHARSET_LATIN_G0,\r
- CHARSET_LATIN_G0,\r
- CHARSET_LATIN_G0,\r
- CHARSET_LATIN_G0,\r
- CHARSET_LATIN_G0_SR_HR_SL,\r
- CHARSET_LATIN_G0,\r
- CHARSET_LATIN_G0_RO\r
-};\r
-\r
-enumCharsets FontBlockG0_0100[8] = {\r
- CHARSET_CYRILLIC_G0_SR_HR,\r
- CHARSET_LATIN_G0_DE,\r
- CHARSET_LATIN_G0_EE,\r
- CHARSET_LATIN_G0_LV_LT,\r
- CHARSET_CYRILLIC_G0_RU_BG,\r
- CHARSET_CYRILLIC_G0_UK,\r
- CHARSET_LATIN_G0_CZ_SK,\r
- CHARSET_INVALID\r
-};\r
-\r
-enumCharsets FontBlockG2_0100[8] = {\r
- CHARSET_CYRILLIC_G2,\r
- CHARSET_LATIN_G2,\r
- CHARSET_LATIN_G2,\r
- CHARSET_LATIN_G2,\r
- CHARSET_CYRILLIC_G2,\r
- CHARSET_CYRILLIC_G2,\r
- CHARSET_LATIN_G2,\r
- CHARSET_INVALID\r
-};\r
-\r
-enumCharsets FontBlockG0_0110[8] = {\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_LATIN_G0_TR,\r
- CHARSET_GREEK_G0\r
-};\r
-\r
-enumCharsets FontBlockG2_0110[8] = {\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_LATIN_G2,\r
- CHARSET_GREEK_G2\r
-};\r
-\r
-enumCharsets FontBlockG0_1000[8] = {\r
- CHARSET_LATIN_G0_EN,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_LATIN_G0_FR,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_ARABIC_G0\r
-};\r
-\r
-enumCharsets FontBlockG2_1000[8] = {\r
- CHARSET_ARABIC_G2,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_ARABIC_G2,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_ARABIC_G2\r
-};\r
-\r
-enumCharsets FontBlockG0_1010[8] = {\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_HEBREW_G0,\r
- CHARSET_INVALID,\r
- CHARSET_ARABIC_G0,\r
-};\r
-\r
-enumCharsets FontBlockG2_1010[8] = {\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_ARABIC_G2,\r
- CHARSET_INVALID,\r
- CHARSET_ARABIC_G2,\r
-};\r
-\r
-enumCharsets FontBlockInvalid[8] = {\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID,\r
- CHARSET_INVALID\r
-};\r
-\r
-\r
-\r
-// The actual font table definition:\r
-// Split the 7-bit number into upper 4 and lower 3 bits,\r
-// use upper 4 bits for outer array,\r
-// use lower 3 bits for inner array\r
-\r
-struct structFontBlock {\r
- enumCharsets *G0Block;\r
- enumCharsets *G2Block;\r
-};\r
- \r
-structFontBlock FontTable[16] = {\r
- { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block\r
- { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block\r
- { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block\r
- { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block\r
- { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block\r
- { FontBlockInvalid, FontBlockInvalid }, // 0101 block\r
- { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block\r
- { FontBlockInvalid, FontBlockInvalid }, // 0111 block\r
- { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block\r
- { FontBlockInvalid, FontBlockInvalid }, // 1001 block\r
- { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block\r
- { FontBlockInvalid, FontBlockInvalid }, // 1011 block\r
- { FontBlockInvalid, FontBlockInvalid }, // 1100 block\r
- { FontBlockInvalid, FontBlockInvalid }, // 1101 block\r
- { FontBlockInvalid, FontBlockInvalid }, // 1110 block\r
- { FontBlockInvalid, FontBlockInvalid } // 1111 block\r
-};\r
-\r
-inline enumCharsets GetG0Charset(int codepage) {\r
- return FontTable[codepage>>3].G0Block[codepage&7];\r
-}\r
-inline enumCharsets GetG2Charset(int codepage) {\r
- return FontTable[codepage>>3].G2Block[codepage&7];\r
-}\r
-\r
-enum enumSizeMode {\r
- // Possible size modifications of characters\r
- sizeNormal,\r
- sizeDoubleWidth,\r
- sizeDoubleHeight,\r
- sizeDoubleSize\r
-};\r
-\r
-void TeletextDecoderVBIEBU::RenderTeletextCode(bool renderfirstlineonly) {\r
- int x,y;\r
- bool EmptyNextLine=false;\r
- // Skip one line, in case double height chars were/will be used\r
-\r
- // Get code pages:\r
- int LocalG0CodePage=(FirstG0CodePage & 0x78) \r
- | ((lang & 0x04)>>2) | (lang & 0x02) | ((lang & 0x01)<<2);\r
- enumCharsets FirstG0=GetG0Charset(LocalG0CodePage);\r
- enumCharsets SecondG0=GetG0Charset(SecondG0CodePage);\r
- // Reserved for later use:\r
- // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage);\r
- \r
- for (y=0;y<24;(EmptyNextLine?y+=2:y++)) {\r
- // Start of line: Set start of line defaults\r
- \r
- // Hold Mosaics mode: Remember last mosaic char/charset \r
- // for next spacing code\r
- bool HoldMosaics=false;\r
- unsigned char HoldMosaicChar=' ';\r
- enumCharsets HoldMosaicCharset=FirstG0;\r
-\r
- enumSizeMode Size=sizeNormal;\r
- // Font size modification\r
- bool SecondCharset=false;\r
- // Use primary or secondary G0 charset\r
- bool GraphicCharset=false;\r
- // Graphics charset used?\r
- bool SeparateGraphics=false;\r
- // Use separated vs. contiguous graphics charset\r
- bool NoNextChar=false;\r
- // Skip display of next char, for double-width\r
- EmptyNextLine=false;\r
- // Skip next line, for double-height\r
-\r
- cTeletextChar c;\r
- // auto.initialized to everything off\r
- c.SetFGColor(ttcWhite);\r
- c.SetBGColor(ttcBlack);\r
- c.SetCharset(FirstG0);\r
- \r
- if (y==0 && (flags&0x10)) {\r
- if (!inkeying ) c.SetBoxedOut(true);\r
- \r
- }\r
- if (flags&0x60) {\r
- if (!(inkeying && y==0) ) c.SetBoxedOut(true);\r
- \r
- }\r
- if (y==0) {\r
- \r
- for (x=0;x<8;x++) {\r
- cTeletextChar c2=c;\r
- \r
- if (x>=3 && x<6){\r
- c2.SetChar(keyindigits[x-3]);\r
-\r
- }\r
- else\r
- c2.SetChar(' ');\r
- setChar(x,0,c2);\r
- }\r
- }\r
-\r
- // Pre-scan for double-height and double-size codes\r
- for (x=0;x<40;x++) {\r
- if (y==0 && x<8) x=8;\r
- if ((curpage[y][x] & 0x7f)==0x0D || (curpage[y][x] & 0x7f)==0x0F)\r
- EmptyNextLine=true;\r
- }\r
-\r
- // Move through line\r
- for (x=0;x<40;x++) {\r
- unsigned char ttc=curpage[y][x] & 0x7f;\r
- // skip parity check\r
-\r
- if (y==0 && x<8) continue;\r
- if (y==0 && x<31 && renderfirstlineonly && gotcha && !inkeying) continue;\r
- // no displayable data here...\r
- \r
-/* // Debug only: Output line data and spacing codes\r
- if (y==6) {\r
- if (ttc<0x20)\r
- printf("%s ",names[ttc]);\r
- else\r
- printf("%02x ",ttc);\r
- if (x==39) printf("\n");\r
- }\r
-*/ \r
- \r
- // Handle all 'Set-At' spacing codes\r
- switch (ttc) {\r
- case 0x09: // Steady\r
- c.SetBlink(false);\r
- break;\r
- case 0x0C: // Normal Size\r
- if (Size!=sizeNormal) {\r
- Size=sizeNormal;\r
- HoldMosaicChar=' ';\r
- HoldMosaicCharset=FirstG0;\r
- } \r
- break;\r
- case 0x18: // Conceal\r
- c.SetConceal(true);\r
- break;\r
- case 0x19: // Contiguous Mosaic Graphics\r
- SeparateGraphics=false;\r
- if (GraphicCharset)\r
- c.SetCharset(CHARSET_GRAPHICS_G1);\r
- break;\r
- case 0x1A: // Separated Mosaic Graphics\r
- SeparateGraphics=true;\r
- if (GraphicCharset)\r
- c.SetCharset(CHARSET_GRAPHICS_G1_SEP);\r
- break;\r
- case 0x1C: // Black Background\r
- c.SetBGColor(ttcBlack);\r
- break;\r
- case 0x1D: // New Background\r
- c.SetBGColor(c.GetFGColor());\r
- break;\r
- case 0x1E: // Hold Mosaic\r
- HoldMosaics=true; \r
- break;\r
- }\r
-\r
- // temporary copy of character data:\r
- cTeletextChar c2=c;\r
- // c2 will be text character or space character or hold mosaic\r
- // c2 may also have temporary flags or charsets\r
- \r
- if (ttc<0x20) {\r
- // Spacing code, display space or hold mosaic\r
- if (HoldMosaics) {\r
- c2.SetChar(HoldMosaicChar);\r
- c2.SetCharset(HoldMosaicCharset);\r
- } else {\r
- c2.SetChar(' ');\r
- }\r
- } else {\r
- // Character code \r
- c2.SetChar(ttc);\r
- if (GraphicCharset) {\r
- if (ttc&0x20) {\r
- // real graphics code, remember for HoldMosaics\r
- HoldMosaicChar=ttc;\r
- HoldMosaicCharset=c.GetCharset();\r
- } else {\r
- // invalid code, pass-through to G0\r
- c2.SetCharset(SecondCharset?SecondG0:FirstG0);\r
- } \r
- }\r
- }\r
- \r
- // Handle double-height and double-width extremes\r
- if (y>=23) {\r
- if (Size==sizeDoubleHeight) Size=sizeNormal;\r
- if (Size==sizeDoubleSize) Size=sizeDoubleWidth;\r
- }\r
- if (x>=38) {\r
- if (Size==sizeDoubleWidth) Size=sizeNormal;\r
- if (Size==sizeDoubleSize) Size=sizeDoubleHeight;\r
- }\r
- \r
- // Now set character code\r
- \r
- if (NoNextChar) {\r
- // Suppress this char due to double width last char\r
- NoNextChar=false;\r
- } else {\r
- switch (Size) {\r
- case sizeNormal:\r
- // Normal sized\r
- setChar(x,y,c2);\r
- if (EmptyNextLine && y<23) {\r
- // Clean up next line\r
- setChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
- }\r
- break;\r
- case sizeDoubleWidth:\r
- // Double width\r
- setChar(x,y,c2.ToDblWidth(dblw_Left));\r
- setChar(x+1,y,c2.ToDblWidth(dblw_Right));\r
- if (EmptyNextLine && y<23) {\r
- // Clean up next line\r
- setChar(x ,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
- setChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
- }\r
- NoNextChar=true;\r
- break;\r
- case sizeDoubleHeight:\r
- // Double height\r
- setChar(x,y,c2.ToDblHeight(dblh_Top));\r
- setChar(x,y+1,c2.ToDblHeight(dblh_Bottom));\r
- break;\r
- case sizeDoubleSize:\r
- // Double Size\r
- setChar(x , y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Left ));\r
- setChar(x+1, y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Right));\r
- setChar(x ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left ));\r
- setChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right));\r
- NoNextChar=true;\r
- break;\r
- }\r
- }\r
- \r
- // Handle all 'Set-After' spacing codes\r
- if (ttc>=0x00 && ttc<=0x07) { // Set FG color\r
- if (GraphicCharset) {\r
- // Actual switch from graphics charset\r
- HoldMosaicChar=' ';\r
- HoldMosaicCharset=FirstG0;\r
- }\r
- c.SetFGColor((enumTeletextColor)ttc);\r
- c.SetCharset(SecondCharset?SecondG0:FirstG0);\r
- GraphicCharset=false;\r
- c.SetConceal(false);\r
- } else if (ttc==0x08) {\r
- c.SetBlink(true);\r
- } else if (ttc==0x0A) {\r
- c.SetBoxedOut(true);\r
- } else if (ttc==0x0B) {\r
- // Start Box\r
- c.SetBoxedOut(false);\r
- } else if (ttc==0x0D) {\r
- if (Size!=sizeDoubleHeight) {\r
- Size=sizeDoubleHeight;\r
- HoldMosaicChar=' ';\r
- HoldMosaicCharset=FirstG0;\r
- } \r
- } else if (ttc==0x0E) {\r
- if (Size!=sizeDoubleWidth) {\r
- Size=sizeDoubleWidth;\r
- HoldMosaicChar=' ';\r
- HoldMosaicCharset=FirstG0;\r
- } \r
- } else if (ttc==0x0E) {\r
- if (Size!=sizeDoubleSize) {\r
- Size=sizeDoubleSize;\r
- HoldMosaicChar=' ';\r
- HoldMosaicCharset=FirstG0;\r
- } \r
- } else if (ttc>=0x10 && ttc<=0x17) { \r
- if (!GraphicCharset) {\r
- // Actual switch to graphics charset\r
- HoldMosaicChar=' ';\r
- HoldMosaicCharset=FirstG0;\r
- }\r
- c.SetFGColor((enumTeletextColor)(ttc-0x10));\r
- c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1);\r
- GraphicCharset=true;\r
- c.SetConceal(false);\r
- } else if (ttc==0x1B) {\r
- SecondCharset=!SecondCharset;\r
- if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0);\r
- } else if (ttc==0x1F) {\r
- HoldMosaics=false;\r
- }\r
- \r
- } // end for x\r
- if (renderfirstlineonly) break;\r
- } // end for y\r
- \r
- for (x=0;x<40;x++) {\r
- // Clean out last line\r
- cTeletextChar c;\r
- c.SetFGColor(ttcWhite);\r
- c.SetBGColor(ttcBlack);\r
- c.SetCharset(FirstG0);\r
- c.SetChar(' ');\r
- if (flags&0x60) {\r
- c.SetBoxedOut(true); \r
- }\r
- setChar(x,24,c);\r
- } \r
- for (y=0;y<25;y++) {\r
- for (x=0;x<40;x++) {\r
- if (isDirty(x,y)) {\r
- dirty=true;\r
- break;\r
- }\r
- if (dirty) break;\r
- }\r
- if (dirty) break;\r
- }\r
- \r
- if (dirty && txtview!=NULL ) {\r
- \r
- if ( !renderfirstlineonly) {\r
- Message* m= new Message();\r
- m->message = Message::TELETEXTUPDATE;\r
- m->to = txtview;\r
- m->from = this;\r
- m->parameter = 0;\r
- Command::getInstance()->postMessageFromOuterSpace(m);\r
- } else if (firstlineupdate==10) {\r
- Message* m= new Message();\r
- m->message = Message::TELETEXTUPDATEFIRSTLINE;\r
- m->to = txtview;\r
- m->from = this;\r
- m->parameter = 0;\r
- Command::getInstance()->postMessageFromOuterSpace(m);\r
- firstlineupdate=0;\r
- } else firstlineupdate++;\r
- \r
- \r
- }\r
- \r
-}\r
+/*
+ Copyright 2008 Marten Richter
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+
+/* Portions from vdr osdteletext plugin "txtrender.c": */
+/***************************************************************************
+ * *
+ * txtrender.c - Teletext display abstraction and teletext code *
+ * renderer *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Changelog: *
+ * 2005-03 initial version (c) Udo Richter *
+ * *
+ ***************************************************************************/
+
+#include "teletextdecodervbiebu.h"
+#include "teletxt/tables.h"
+#include "message.h"
+#include "command.h"
+#include "video.h"
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+TeletextDecoderVBIEBU::TeletextDecoderVBIEBU()
+{
+ selectedpage=0x100;
+ ourpage=false;
+ flags=lang=0;
+
+ CleanPage();
+ FirstG0CodePage=0;
+ SecondG0CodePage=0;
+ dirty=false;
+ txtview=NULL;
+ firstlineupdate=0;
+ gotcha=false;
+ char digits[]={'1','0','0'};
+ setKeyinDigits(digits,false);
+ isrecording=false;
+ for (int i=0;i<10;i++) record_pages[i]=-1;
+
+
+}
+
+TeletextDecoderVBIEBU::~TeletextDecoderVBIEBU()
+{
+
+
+}
+
+long long TeletextDecoderVBIEBU::SetStartOffset(long long curreftime, bool *rsync)
+{
+ return 0;
+}
+
+void TeletextDecoderVBIEBU::ResetTimeOffsets()
+{
+
+}
+
+
+
+void TeletextDecoderVBIEBU::ResetDecoder()
+{
+ gotcha=false;
+ ourpage=false;
+ firstlineupdate=0;
+ selectedpage=0x100;
+ CleanPage();
+ char digits[]={'1','0','0'};
+ setKeyinDigits(digits,false);
+ for (int i=0;i<10;i++) record_pages[i]=-1;
+
+}
+
+void TeletextDecoderVBIEBU::setPage(unsigned int newpage)
+{
+ selectedpage=newpage;
+ gotcha=false;
+ ourpage=false;
+ firstlineupdate=0;
+ for (int i=0;i<25;i++) {
+ memset(curpage[i],0,40);
+ }
+}
+
+void TeletextDecoderVBIEBU::CleanPage()
+{
+ int x,y;
+ for (int i=0;i<25;i++) {
+ memset(curpage[i],0,40);
+ }
+ for (y=0;y<25;y++) {
+ for (x=0;x<40;x++) {
+ cTeletextChar c;
+ c.SetFGColor(ttcWhite);
+ c.SetBGColor(ttcBlack);
+ c.SetCharset(CHARSET_LATIN_G0);
+ c.SetChar(' ');
+ if (flags&0x60) {
+ c.SetBoxedOut(true);
+ }
+ setChar(x,y,c);
+ }
+ }
+
+}
+void TeletextDecoderVBIEBU::setKeyinDigits(char digits[3],bool inKeying)
+{
+ int x;
+ inkeying=inKeying;
+ for (x=0;x<3;x++) {
+ cTeletextChar c;
+ c.SetFGColor(ttcWhite);
+ c.SetBGColor(ttcBlack);
+ c.SetCharset(CHARSET_LATIN_G0);
+ c.SetChar(digits[x]);
+ if (flags&0x60) {
+ c.SetBoxedOut(true);
+ }
+ setChar(x+3,0,c);
+ keyindigits[x]=digits[x];
+ }
+}
+
+void TeletextDecoderVBIEBU::PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos)
+{
+ mediapacket = mplist.front();
+}
+
+static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
+{
+ // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
+ if (pts1 > pts2)
+ return pts1 - pts2;
+ else
+ return (1LL<<33) + pts1 - pts2;
+}
+
+UINT TeletextDecoderVBIEBU::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)
+{
+ if (mediapacket.type != MPTYPE_TELETEXT)
+ {
+ *samplepos= 0;
+ return 1; //Skip it!
+ }
+ unsigned int headerstrip;
+ unsigned char txtdata[43];
+ headerstrip=buffer[mediapacket.pos_buffer+8]+9;
+ //headerstrip+=4; //substream id
+ unsigned int datapos=0;
+ unsigned int datatype=buffer[mediapacket.pos_buffer+headerstrip+0];
+ //Chris should we use here the pts data from mediapacket ?
+ // in this case the data fields should also be added in mediamvp
+ if (mediapacket.synched)
+ { // An entry exists in the work list
+ ULLONG nowPTS = Video::getInstance()->getCurrentTimestamp();
+ if (PTSDifference(mediapacket.pts, nowPTS) >= 1200*90000) {
+ *samplepos=0;
+ return 1;//bad data skip it
+ }
+ if (nowPTS < (mediapacket.pts-4000) ) {
+ *samplepos=0;
+ return 0;
+ }
+ }
+
+ if (( datatype>=0x10 && datatype <=0x1F) ||
+ ( datatype>=0x99 && datatype <=0x9B)) {
+ //EBU VBI DATA
+ datapos++;
+ while (datapos< (mediapacket.length-headerstrip)) {
+ unsigned int unit_id=buffer[mediapacket.pos_buffer+headerstrip+datapos];
+ datapos++;
+ unsigned int unit_length=buffer[mediapacket.pos_buffer+headerstrip+datapos];
+ datapos++;
+ switch (unit_id) {
+ case 0x02:
+ case 0x03: {//Teletext with and without subtitles
+ //call teletext decoder
+ unsigned int field=buffer[mediapacket.pos_buffer+headerstrip+datapos];
+
+ if ((datapos+44)< (mediapacket.length-headerstrip)) {
+ for (int i=0;i<42;i++) {
+ txtdata[i]=invtab[buffer[mediapacket.pos_buffer+headerstrip+datapos+2+i]];
+ }
+ DecodeTeletext(txtdata,field);
+ }
+ }break;
+ case 0xC0: //inverted Teletext
+ //call teletext decoder
+ break;
+
+ case 0xC3: //VPS
+ //what to do with this, in the moment we do not need it
+ break;
+ case 0xC4: //WSS
+ //what to do with this, in the moment we do not need it
+ break;
+ case 0xC5: //CC
+ //what to do with this, in the moment we do not need it
+ break;
+ case 0xC6: //monochrome 4:2:2 samples, what is that?
+ //what to do with this, in the moment we do not need it
+ break;
+ default:
+ // case 0x00,0x01,0x04..0x7f,0x80..0xbf,0xc1,0xc2,0xc7..0xfe,0xff: //discard
+ //discard
+ break;
+ };
+ datapos+=unit_length;
+ // while (buffer[mediapacket.pos_buffer+headerstrip+datapos]==0xFF &&(datapos< (mediapacket.length-headerstrip))) {
+ // datapos++; //stuffing bytes
+ // }
+
+
+ }
+ *samplepos=0;
+ return 1;
+
+
+ } else {
+ *samplepos= 0;
+ return 1; //Skip it! and discard data
+ }
+
+ return 0;
+
+}
+// This part is inspired by the vdr-plugin-osdteletext of Udo Richter and Marcel Wiesweg
+void TeletextDecoderVBIEBU::DecodeTeletext(const UCHAR* buffer, unsigned int field) //needs to be exactly 42 byte long!!
+{
+ UCHAR hdrbuf[5];
+ for (int i=0;i<5;i++) hdrbuf[i]=(unhamtab[buffer[2*i]]&0xF) | ((unhamtab[buffer[2*i+1]]&0xF)<< 4);
+ int header=hdrbuf[0];
+ int magazin=header & 0x7;
+ int line = (header>>3) & 0x1f;
+ if (magazin==0) magazin=8;
+ if (line==0)
+ {
+ if (ourpage) {
+ gotcha=true;
+ inkeying=false;
+ RenderTeletextCode(false);
+ } else {
+ RenderTeletextCode(true);
+ }
+ int pagenumber=hdrbuf[1];
+ int pagemagazin=magazin<<8 | pagenumber;
+ int pagesubnumber=(hdrbuf[2]) || ((hdrbuf[3]<<8) & 0x3f7f);
+
+ if (pagemagazin == selectedpage) ourpage=true;
+ else ourpage=false;
+ if (isrecording) {
+ for (int i=0;i<10;i++) {
+ if (pagemagazin==record_pages[i]) break;
+ if (record_pages[i]==-1) {
+ record_pages[i]=pagemagazin;
+ break;
+ }
+ }
+ }
+ if (hdrbuf[3] &0x80) { //This is a subtitle
+ for (int i=0;i<10;i++) {
+ if (pagemagazin==record_pages[i]) break;
+ if (record_pages[i]==-1) {
+ record_pages[i]=pagemagazin;
+ break;
+ }
+ }
+ }
+
+
+ if (ourpage) {
+ lang=((hdrbuf[4]>>5) & 0x07);
+ flags=hdrbuf[2] & 0x80;
+ flags|=(hdrbuf[3]&0x40)|((hdrbuf[3]>>2)&0x20); //??????
+ flags|=((hdrbuf[4]<<4)&0x10)|((hdrbuf[4]<<2)&0x08)|(hdrbuf[4]&0x04)|((hdrbuf[4]>>1)&0x02)|((hdrbuf[4]>>4)&0x01);
+ for (int i=0;i<25;i++) {
+ memset(curpage[i],0,40);
+ }
+ }
+
+ memcpy(curpage[line],buffer+2,40);
+ } else if (ourpage && (line<=25)) {
+ memcpy(curpage[line],buffer+2,40);
+
+ }
+}
+
+
+/* from osdteletext plugin: (slightly adapted for vomp)*/
+// Font tables
+
+// teletext uses 7-bit numbers to identify a font set.
+// There are three font sets involved:
+// Primary G0, Secondary G0, and G2 font set.
+
+// Font tables are organized in blocks of 8 fonts:
+
+enumCharsets FontBlockG0_0000[8] = {
+ CHARSET_LATIN_G0_EN,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_SV_FI,
+ CHARSET_LATIN_G0_IT,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_LATIN_G0_PT_ES,
+ CHARSET_LATIN_G0_CZ_SK,
+ CHARSET_LATIN_G0
+};
+
+enumCharsets FontBlockG2Latin[8]={
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2
+};
+
+enumCharsets FontBlockG0_0001[8] = {
+ CHARSET_LATIN_G0_PL,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_SV_FI,
+ CHARSET_LATIN_G0_IT,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0_CZ_SK,
+ CHARSET_LATIN_G0
+};
+
+enumCharsets FontBlockG0_0010[8] = {
+ CHARSET_LATIN_G0_EN,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_SV_FI,
+ CHARSET_LATIN_G0_IT,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_LATIN_G0_PT_ES,
+ CHARSET_LATIN_G0_TR,
+ CHARSET_LATIN_G0
+};
+
+
+enumCharsets FontBlockG0_0011[8] = {
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0_SR_HR_SL,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0_RO
+};
+
+enumCharsets FontBlockG0_0100[8] = {
+ CHARSET_CYRILLIC_G0_SR_HR,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_EE,
+ CHARSET_LATIN_G0_LV_LT,
+ CHARSET_CYRILLIC_G0_RU_BG,
+ CHARSET_CYRILLIC_G0_UK,
+ CHARSET_LATIN_G0_CZ_SK,
+ CHARSET_INVALID
+};
+
+enumCharsets FontBlockG2_0100[8] = {
+ CHARSET_CYRILLIC_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_CYRILLIC_G2,
+ CHARSET_CYRILLIC_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_INVALID
+};
+
+enumCharsets FontBlockG0_0110[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_LATIN_G0_TR,
+ CHARSET_GREEK_G0
+};
+
+enumCharsets FontBlockG2_0110[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_LATIN_G2,
+ CHARSET_GREEK_G2
+};
+
+enumCharsets FontBlockG0_1000[8] = {
+ CHARSET_LATIN_G0_EN,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G0
+};
+
+enumCharsets FontBlockG2_1000[8] = {
+ CHARSET_ARABIC_G2,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2
+};
+
+enumCharsets FontBlockG0_1010[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_HEBREW_G0,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G0,
+};
+
+enumCharsets FontBlockG2_1010[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2,
+};
+
+enumCharsets FontBlockInvalid[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID
+};
+
+
+
+// The actual font table definition:
+// Split the 7-bit number into upper 4 and lower 3 bits,
+// use upper 4 bits for outer array,
+// use lower 3 bits for inner array
+
+struct structFontBlock {
+ enumCharsets *G0Block;
+ enumCharsets *G2Block;
+};
+
+structFontBlock FontTable[16] = {
+ { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block
+ { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block
+ { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block
+ { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block
+ { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block
+ { FontBlockInvalid, FontBlockInvalid }, // 0101 block
+ { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block
+ { FontBlockInvalid, FontBlockInvalid }, // 0111 block
+ { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1001 block
+ { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1011 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1100 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1101 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1110 block
+ { FontBlockInvalid, FontBlockInvalid } // 1111 block
+};
+
+inline enumCharsets GetG0Charset(int codepage) {
+ return FontTable[codepage>>3].G0Block[codepage&7];
+}
+inline enumCharsets GetG2Charset(int codepage) {
+ return FontTable[codepage>>3].G2Block[codepage&7];
+}
+
+enum enumSizeMode {
+ // Possible size modifications of characters
+ sizeNormal,
+ sizeDoubleWidth,
+ sizeDoubleHeight,
+ sizeDoubleSize
+};
+
+void TeletextDecoderVBIEBU::RenderTeletextCode(bool renderfirstlineonly) {
+ int x,y;
+ bool EmptyNextLine=false;
+ // Skip one line, in case double height chars were/will be used
+
+ // Get code pages:
+ int LocalG0CodePage=(FirstG0CodePage & 0x78)
+ | ((lang & 0x04)>>2) | (lang & 0x02) | ((lang & 0x01)<<2);
+ enumCharsets FirstG0=GetG0Charset(LocalG0CodePage);
+ enumCharsets SecondG0=GetG0Charset(SecondG0CodePage);
+ // Reserved for later use:
+ // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage);
+
+ for (y=0;y<24;(EmptyNextLine?y+=2:y++)) {
+ // Start of line: Set start of line defaults
+
+ // Hold Mosaics mode: Remember last mosaic char/charset
+ // for next spacing code
+ bool HoldMosaics=false;
+ unsigned char HoldMosaicChar=' ';
+ enumCharsets HoldMosaicCharset=FirstG0;
+
+ enumSizeMode Size=sizeNormal;
+ // Font size modification
+ bool SecondCharset=false;
+ // Use primary or secondary G0 charset
+ bool GraphicCharset=false;
+ // Graphics charset used?
+ bool SeparateGraphics=false;
+ // Use separated vs. contiguous graphics charset
+ bool NoNextChar=false;
+ // Skip display of next char, for double-width
+ EmptyNextLine=false;
+ // Skip next line, for double-height
+
+ cTeletextChar c;
+ // auto.initialized to everything off
+ c.SetFGColor(ttcWhite);
+ c.SetBGColor(ttcBlack);
+ c.SetCharset(FirstG0);
+
+ if (y==0 && (flags&0x10)) {
+ if (!inkeying ) c.SetBoxedOut(true);
+
+ }
+ if (flags&0x60) {
+ if (!(inkeying && y==0) ) c.SetBoxedOut(true);
+
+ }
+ if (y==0) {
+
+ for (x=0;x<8;x++) {
+ cTeletextChar c2=c;
+
+ if (x>=3 && x<6){
+ c2.SetChar(keyindigits[x-3]);
+
+ }
+ else
+ c2.SetChar(' ');
+ setChar(x,0,c2);
+ }
+ }
+
+ // Pre-scan for double-height and double-size codes
+ for (x=0;x<40;x++) {
+ if (y==0 && x<8) x=8;
+ if ((curpage[y][x] & 0x7f)==0x0D || (curpage[y][x] & 0x7f)==0x0F)
+ EmptyNextLine=true;
+ }
+
+ // Move through line
+ for (x=0;x<40;x++) {
+ unsigned char ttc=curpage[y][x] & 0x7f;
+ // skip parity check
+
+ if (y==0 && x<8) continue;
+ if (y==0 && x<31 && renderfirstlineonly && gotcha && !inkeying) continue;
+ // no displayable data here...
+
+/* // Debug only: Output line data and spacing codes
+ if (y==6) {
+ if (ttc<0x20)
+ printf("%s ",names[ttc]);
+ else
+ printf("%02x ",ttc);
+ if (x==39) printf("\n");
+ }
+*/
+
+ // Handle all 'Set-At' spacing codes
+ switch (ttc) {
+ case 0x09: // Steady
+ c.SetBlink(false);
+ break;
+ case 0x0C: // Normal Size
+ if (Size!=sizeNormal) {
+ Size=sizeNormal;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ break;
+ case 0x18: // Conceal
+ c.SetConceal(true);
+ break;
+ case 0x19: // Contiguous Mosaic Graphics
+ SeparateGraphics=false;
+ if (GraphicCharset)
+ c.SetCharset(CHARSET_GRAPHICS_G1);
+ break;
+ case 0x1A: // Separated Mosaic Graphics
+ SeparateGraphics=true;
+ if (GraphicCharset)
+ c.SetCharset(CHARSET_GRAPHICS_G1_SEP);
+ break;
+ case 0x1C: // Black Background
+ c.SetBGColor(ttcBlack);
+ break;
+ case 0x1D: // New Background
+ c.SetBGColor(c.GetFGColor());
+ break;
+ case 0x1E: // Hold Mosaic
+ HoldMosaics=true;
+ break;
+ }
+
+ // temporary copy of character data:
+ cTeletextChar c2=c;
+ // c2 will be text character or space character or hold mosaic
+ // c2 may also have temporary flags or charsets
+
+ if (ttc<0x20) {
+ // Spacing code, display space or hold mosaic
+ if (HoldMosaics) {
+ c2.SetChar(HoldMosaicChar);
+ c2.SetCharset(HoldMosaicCharset);
+ } else {
+ c2.SetChar(' ');
+ }
+ } else {
+ // Character code
+ c2.SetChar(ttc);
+ if (GraphicCharset) {
+ if (ttc&0x20) {
+ // real graphics code, remember for HoldMosaics
+ HoldMosaicChar=ttc;
+ HoldMosaicCharset=c.GetCharset();
+ } else {
+ // invalid code, pass-through to G0
+ c2.SetCharset(SecondCharset?SecondG0:FirstG0);
+ }
+ }
+ }
+
+ // Handle double-height and double-width extremes
+ if (y>=23) {
+ if (Size==sizeDoubleHeight) Size=sizeNormal;
+ if (Size==sizeDoubleSize) Size=sizeDoubleWidth;
+ }
+ if (x>=38) {
+ if (Size==sizeDoubleWidth) Size=sizeNormal;
+ if (Size==sizeDoubleSize) Size=sizeDoubleHeight;
+ }
+
+ // Now set character code
+
+ if (NoNextChar) {
+ // Suppress this char due to double width last char
+ NoNextChar=false;
+ } else {
+ switch (Size) {
+ case sizeNormal:
+ // Normal sized
+ setChar(x,y,c2);
+ if (EmptyNextLine && y<23) {
+ // Clean up next line
+ setChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0));
+ }
+ break;
+ case sizeDoubleWidth:
+ // Double width
+ setChar(x,y,c2.ToDblWidth(dblw_Left));
+ setChar(x+1,y,c2.ToDblWidth(dblw_Right));
+ if (EmptyNextLine && y<23) {
+ // Clean up next line
+ setChar(x ,y+1,c2.ToChar(' ').ToCharset(FirstG0));
+ setChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0));
+ }
+ NoNextChar=true;
+ break;
+ case sizeDoubleHeight:
+ // Double height
+ setChar(x,y,c2.ToDblHeight(dblh_Top));
+ setChar(x,y+1,c2.ToDblHeight(dblh_Bottom));
+ break;
+ case sizeDoubleSize:
+ // Double Size
+ setChar(x , y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Left ));
+ setChar(x+1, y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Right));
+ setChar(x ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left ));
+ setChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right));
+ NoNextChar=true;
+ break;
+ }
+ }
+
+ // Handle all 'Set-After' spacing codes
+ if (ttc>=0x00 && ttc<=0x07) { // Set FG color
+ if (GraphicCharset) {
+ // Actual switch from graphics charset
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ c.SetFGColor((enumTeletextColor)ttc);
+ c.SetCharset(SecondCharset?SecondG0:FirstG0);
+ GraphicCharset=false;
+ c.SetConceal(false);
+ } else if (ttc==0x08) {
+ c.SetBlink(true);
+ } else if (ttc==0x0A) {
+ c.SetBoxedOut(true);
+ } else if (ttc==0x0B) {
+ // Start Box
+ c.SetBoxedOut(false);
+ } else if (ttc==0x0D) {
+ if (Size!=sizeDoubleHeight) {
+ Size=sizeDoubleHeight;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ } else if (ttc==0x0E) {
+ if (Size!=sizeDoubleWidth) {
+ Size=sizeDoubleWidth;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ } else if (ttc==0x0E) {
+ if (Size!=sizeDoubleSize) {
+ Size=sizeDoubleSize;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ } else if (ttc>=0x10 && ttc<=0x17) {
+ if (!GraphicCharset) {
+ // Actual switch to graphics charset
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ c.SetFGColor((enumTeletextColor)(ttc-0x10));
+ c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1);
+ GraphicCharset=true;
+ c.SetConceal(false);
+ } else if (ttc==0x1B) {
+ SecondCharset=!SecondCharset;
+ if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0);
+ } else if (ttc==0x1F) {
+ HoldMosaics=false;
+ }
+
+ } // end for x
+ if (renderfirstlineonly) break;
+ } // end for y
+
+ for (x=0;x<40;x++) {
+ // Clean out last line
+ cTeletextChar c;
+ c.SetFGColor(ttcWhite);
+ c.SetBGColor(ttcBlack);
+ c.SetCharset(FirstG0);
+ c.SetChar(' ');
+ if (flags&0x60) {
+ c.SetBoxedOut(true);
+ }
+ setChar(x,24,c);
+ }
+ for (y=0;y<25;y++) {
+ for (x=0;x<40;x++) {
+ if (isDirty(x,y)) {
+ dirty=true;
+ break;
+ }
+ if (dirty) break;
+ }
+ if (dirty) break;
+ }
+
+ if (dirty && txtview!=NULL ) {
+
+ if ( !renderfirstlineonly) {
+ Message* m= new Message();
+ m->message = Message::TELETEXTUPDATE;
+ m->to = txtview;
+ m->from = this;
+ m->parameter = 0;
+ Command::getInstance()->postMessageFromOuterSpace(m);
+ } else if (firstlineupdate==10) {
+ Message* m= new Message();
+ m->message = Message::TELETEXTUPDATEFIRSTLINE;
+ m->to = txtview;
+ m->from = this;
+ m->parameter = 0;
+ Command::getInstance()->postMessageFromOuterSpace(m);
+ firstlineupdate=0;
+ } else firstlineupdate++;
+
+
+ }
+
+}
-/*\r
- Copyright 2008 Marten Richter\r
-\r
- This file is part of VOMP.\r
-\r
- VOMP is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation; either version 2 of the License, or\r
- (at your option) any later version.\r
-\r
- VOMP is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
- You should have received a copy of the GNU General Public License\r
- along with VOMP; if not, write to the Free Software\r
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
-*/\r
-/* Portions from vdr osdteletext plugin "txtrender.c": */\r
-/***************************************************************************\r
- * *\r
- * txtrender.h - Teletext display abstraction and teletext code *\r
- * renderer *\r
- * *\r
- * This program is free software; you can redistribute it and/or modify *\r
- * it under the terms of the GNU General Public License as published by *\r
- * the Free Software Foundation; either version 2 of the License, or *\r
- * (at your option) any later version. *\r
- * *\r
- * Changelog: *\r
- * 2005-03 initial version (c) Udo Richter *\r
- * *\r
- ***************************************************************************/\r
-\r
-#ifndef TXTDECVBIEBU_H\r
-#define TXTDECVBIEBU_H\r
-\r
-#include "draintarget.h"\r
-#include "log.h"\r
-\r
-/* from osdteletext begin */\r
-\r
-// Teletext character sets\r
-enum enumCharsets {\r
- CHARSET_LATIN_G0 = 0x0000, // native latin (partially todo)\r
- CHARSET_LATIN_G0_CZ_SK = 0x0100, // Czech/Slovak (todo)\r
- CHARSET_LATIN_G0_EN = 0x0200, // English\r
- CHARSET_LATIN_G0_EE = 0x0300, // Estonian (todo)\r
- CHARSET_LATIN_G0_FR = 0x0400, // French\r
- CHARSET_LATIN_G0_DE = 0x0500, // German\r
- CHARSET_LATIN_G0_IT = 0x0600, // Italian\r
- CHARSET_LATIN_G0_LV_LT = 0x0700, // Lettish/Lithuanian (todo)\r
- CHARSET_LATIN_G0_PL = 0x0800, // Polish (todo)\r
- CHARSET_LATIN_G0_PT_ES = 0x0900, // Portugese/Spanish\r
- CHARSET_LATIN_G0_RO = 0x0A00, // Romanian (todo)\r
- CHARSET_LATIN_G0_SR_HR_SL = 0x0B00, // Serbian/Croatian/Slovenian (todo)\r
- CHARSET_LATIN_G0_SV_FI = 0x0C00, // Swedish/Finnish\r
- CHARSET_LATIN_G0_TR = 0x0D00, // Turkish (todo)\r
- CHARSET_LATIN_G2 = 0x0E00, // Latin G2 supplementary set (todo)\r
- CHARSET_CYRILLIC_G0_SR_HR = 0x0F00, // Serbian/Croatian (todo)\r
- CHARSET_CYRILLIC_G0_RU_BG = 0x1000, // Russian/Bulgarian (todo)\r
- CHARSET_CYRILLIC_G0_UK = 0x1100, // Ukrainian (todo)\r
- CHARSET_CYRILLIC_G2 = 0x1200, // Cyrillic G2 Supplementary (todo)\r
- CHARSET_GREEK_G0 = 0x1300, // Greek G0 (todo)\r
- CHARSET_GREEK_G2 = 0x1400, // Greeek G2 (todo)\r
- CHARSET_ARABIC_G0 = 0x1500, // Arabic G0 (todo)\r
- CHARSET_ARABIC_G2 = 0x1600, // Arabic G2 (todo)\r
- CHARSET_HEBREW_G0 = 0x1700, // Hebrew G0 (todo)\r
- CHARSET_GRAPHICS_G1 = 0x1800, // G1 graphics set\r
- CHARSET_GRAPHICS_G1_SEP = 0x1900, // G1 graphics set, separated\r
- CHARSET_GRAPHICS_G3 = 0x1A00, // G3 graphics set (todo)\r
- CHARSET_INVALID = 0x1F00 // no charset defined\r
-};\r
-\r
-// Macro to get the lowest non-0 bit position from a bit mask\r
-// Should evaluate to const on a const mask\r
-#define LowestSet2Bit(mask) ((mask)&0x0001?0:1)\r
-#define LowestSet4Bit(mask) ((mask)&0x0003?LowestSet2Bit(mask):LowestSet2Bit((mask)>>2)+2)\r
-#define LowestSet8Bit(mask) ((mask)&0x000f?LowestSet4Bit(mask):LowestSet4Bit((mask)>>4)+4)\r
-#define LowestSet16Bit(mask) ((mask)&0x00ff?LowestSet8Bit(mask):LowestSet8Bit((mask)>>8)+8)\r
-#define LowestSet32Bit(mask) ((mask)&0xffff?LowestSet16Bit(mask):LowestSet16Bit((mask)>>16)+16)\r
-\r
-\r
-// Character modifcation double height:\r
-enum enumDblHeight {\r
- dblh_Normal=0x00000000, // normal height\r
- dblh_Top =0x04000000, // upper half character\r
- dblh_Bottom=0x08000000 // lower half character\r
-};\r
-// Character modifcation double width:\r
-enum enumDblWidth {\r
- dblw_Normal=0x00000000, // normal width\r
- dblw_Left =0x10000000, // left half character\r
- dblw_Right =0x20000000 // right half character\r
-};\r
-\r
-// Teletext colors\r
-enum enumTeletextColor {\r
- // level 1:\r
- ttcBlack=0,\r
- ttcRed=1,\r
- ttcGreen=2,\r
- ttcYellow=3,\r
- ttcBlue=4,\r
- ttcMagenta=5,\r
- ttcCyan=6,\r
- ttcWhite=7,\r
- // level 2.5:\r
- ttcTransparent=8,\r
- ttcHalfRed=9,\r
- ttcHalfGreen=10,\r
- ttcHalfYellow=11,\r
- ttcHalfBlue=12,\r
- ttcHalfMagenta=13,\r
- ttcHalfCyan=14,\r
- ttcGrey=15,\r
- // unnamed, level 2.5:\r
- ttcColor16=16, ttcColor17=17, ttcColor18=18, ttcColor19=19,\r
- ttcColor20=20, ttcColor21=21, ttcColor22=22, ttcColor23=23,\r
- ttcColor24=24, ttcColor25=25, ttcColor26=26, ttcColor27=27,\r
- ttcColor28=28, ttcColor29=29, ttcColor30=30, ttcColor31=31,\r
- \r
- ttcFirst=0, ttcLast=31\r
-};\r
-inline enumTeletextColor& operator++(enumTeletextColor& c) { return c=enumTeletextColor(int(c)+1); }\r
-inline enumTeletextColor operator++(enumTeletextColor& c, int) { enumTeletextColor tmp(c); ++c; return tmp; }\r
- \r
-class cTeletextChar {\r
- // Wrapper class that represents a teletext character,\r
- // including colors and effects. Should optimize back\r
- // to 4 byte unsigned int on compile.\r
- \r
-protected:\r
- unsigned int c;\r
-\r
- static const unsigned int CHAR = 0x000000FF;\r
- // character code\r
- static const unsigned int CHARSET = 0x00001F00;\r
- // character set code, see below\r
- static const unsigned int BOXOUT = 0x00004000;\r
- // 'boxed' mode hidden area\r
- static const unsigned int DIRTY = 0x00008000;\r
- // 'dirty' bit - internal marker only\r
- static const unsigned int FGCOLOR = 0x001F0000;\r
- // 5-bit foreground color code, 3 bit used for now\r
- static const unsigned int BGCOLOR = 0x03E00000;\r
- // 5-bit background color code, 3 bit used for now\r
- static const unsigned int DBLHEIGHT = 0x0C000000;\r
- // show double height\r
- static const unsigned int DBLWIDTH = 0x30000000;\r
- // show double width (todo)\r
- static const unsigned int CONCEAL = 0x40000000;\r
- // character concealed\r
- static const unsigned int BLINK = 0x80000000;\r
- // blinking character\r
-\r
- cTeletextChar(unsigned int cc) { c=cc; }\r
-\r
-public:\r
- cTeletextChar() { c=0; }\r
- \r
- // inline helper functions:\r
- // For each parameter encoded into the 32-bit int, there is\r
- // a Get...() to read, a Set...() to write, and a To...() to\r
- // return a modified copy\r
- \r
- inline unsigned char GetChar() \r
- { return c&CHAR; }\r
- inline void SetChar(unsigned char chr)\r
- { c=(c&~CHAR)|chr; }\r
- inline cTeletextChar ToChar(unsigned char chr)\r
- { return cTeletextChar((c&~CHAR)|chr); }\r
- \r
- inline enumCharsets GetCharset() \r
- { return (enumCharsets)(c&CHARSET); }\r
- inline void SetCharset(enumCharsets charset) \r
- { c=(c&~CHARSET)|charset; }\r
- inline cTeletextChar ToCharset(enumCharsets charset) \r
- { return cTeletextChar((c&~CHARSET)|charset); }\r
- \r
- inline enumTeletextColor GetFGColor() \r
- { return (enumTeletextColor)((c&FGCOLOR) >> LowestSet32Bit(FGCOLOR)); }\r
- inline void SetFGColor(enumTeletextColor fgc) \r
- { c=(c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR)); }\r
- inline cTeletextChar ToFGColor(enumTeletextColor fgc) \r
- { return cTeletextChar((c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR))); }\r
- \r
- inline enumTeletextColor GetBGColor() \r
- { return (enumTeletextColor)((c&BGCOLOR) >> LowestSet32Bit(BGCOLOR)); }\r
- inline void SetBGColor(enumTeletextColor bgc) \r
- { c=(c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR)); }\r
- inline cTeletextChar ToBGColor(enumTeletextColor bgc) \r
- { return cTeletextChar((c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR))); }\r
- \r
- inline bool GetBoxedOut() \r
- { return c&BOXOUT; }\r
- inline void SetBoxedOut(bool BoxedOut) \r
- { c=(BoxedOut)?(c|BOXOUT):(c&~BOXOUT); }\r
- inline cTeletextChar ToBoxedOut(bool BoxedOut) \r
- { return cTeletextChar((BoxedOut)?(c|BOXOUT):(c&~BOXOUT)); }\r
- \r
- inline bool GetDirty() \r
- { return c&DIRTY; }\r
- inline void SetDirty(bool Dirty) \r
- { c=(Dirty)?(c|DIRTY):(c&~DIRTY); }\r
- inline cTeletextChar ToDirty(bool Dirty) \r
- { return cTeletextChar((Dirty)?(c|DIRTY):(c&~DIRTY)); }\r
- \r
- inline enumDblHeight GetDblHeight() \r
- { return (enumDblHeight)(c&DBLHEIGHT); }\r
- inline void SetDblHeight(enumDblHeight dh) \r
- { c=(c&~(DBLHEIGHT)) | dh; }\r
- inline cTeletextChar ToDblHeight(enumDblHeight dh) \r
- { return cTeletextChar((c&~(DBLHEIGHT)) | dh); }\r
- \r
- inline enumDblWidth GetDblWidth() \r
- { return (enumDblWidth)(c&DBLWIDTH); }\r
- inline void SetDblWidth(enumDblWidth dw) \r
- { c=(c&~(DBLWIDTH)) | dw; }\r
- inline cTeletextChar ToDblWidth(enumDblWidth dw) \r
- { return cTeletextChar((c&~(DBLWIDTH)) | dw); }\r
- \r
- inline bool GetConceal() \r
- { return c&CONCEAL; }\r
- inline void SetConceal(bool Conceal) \r
- { c=(Conceal)?(c|CONCEAL):(c&~CONCEAL); }\r
- inline cTeletextChar ToConceal(bool Conceal) \r
- { return cTeletextChar((Conceal)?(c|CONCEAL):(c&~CONCEAL)); }\r
- \r
- inline bool GetBlink() \r
- { return c&BLINK; }\r
- inline void SetBlink(bool Blink) \r
- { c=(Blink)?(c|BLINK):(c&~BLINK); }\r
- inline cTeletextChar ToBlink(bool Blink) \r
- { return cTeletextChar((Blink)?(c|BLINK):(c&~BLINK)); }\r
- \r
- bool operator==(cTeletextChar &chr) { return c==chr.c; }\r
- bool operator!=(cTeletextChar &chr) { return c!=chr.c; }\r
-};\r
-/* from osdteletext end*/\r
-\r
-class VTeletextView;\r
-\r
-/* Decoder of teletext matrial present in Data stream for VBI reinsertion more or less according to EBU specs*/ \r
-class TeletextDecoderVBIEBU: public DrainTarget {\r
-public:\r
- TeletextDecoderVBIEBU();\r
- virtual ~TeletextDecoderVBIEBU();\r
-\r
- virtual long long SetStartOffset(long long curreftime, bool *rsync);\r
- virtual void ResetTimeOffsets();\r
-\r
- void ResetDecoder();\r
- void setKeyinDigits(char digits[3],bool inKeying);\r
- void setPage(unsigned int newpage);\r
- int getPage() {return selectedpage;};\r
- void setRecordigMode(bool isrecord) {isrecording=isrecord;};\r
- int *getSubtitlePages() {return record_pages;};\r
-\r
-\r
- virtual void PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos);\r
- virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos);\r
-\r
- void registerTeletextView(VTeletextView* view) {txtview=view;};\r
- void unRegisterTeletextView(VTeletextView* view) {if (txtview==view) txtview=NULL;};\r
- VTeletextView* getTeletxtView() {return txtview;};\r
-\r
- cTeletextChar getChar(int x, int y) {\r
- // Read character content from page\r
- if (x<0 || x>=40 || y<0 || y>=25) {\r
- Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds read access to teletext page");\r
- return cTeletextChar();\r
- }\r
- return Page[x][y].ToDirty(false);\r
- }\r
- bool isDirty(int x, int y) {\r
- if (x<0 || x>=40 || y<0 || y>=25) {\r
- Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds dirty access to teletext page");\r
- return false;\r
- }\r
- return Page[x][y].GetDirty();\r
- }\r
- void setChar(int x, int y, cTeletextChar c) {\r
- // Set character at given location\r
- \r
- if (x<0 || x>=40 || y<0 || y>=25) {\r
- Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds write access to teletext page");\r
- return;\r
- }\r
- if (getChar(x,y) != c) {\r
- Page[x][y]=c.ToDirty(true);\r
- dirty=true; \r
- } \r
- }\r
-\r
-\r
-protected:\r
- void DecodeTeletext(const UCHAR* buffer, unsigned int field);\r
- void RenderTeletextCode(bool renderfirstlineonly);\r
- void CleanPage();\r
-\r
- int selectedpage;\r
- int lang;\r
- int flags;\r
- UCHAR curpage[25][40]; //Line DataCache\r
- cTeletextChar Page[40][25];\r
- char keyindigits[3];\r
-\r
-\r
- // Font Code pages\r
- int FirstG0CodePage; // 7-bit number, lower 3 bits ignored\r
- int SecondG0CodePage; // 7-bit number\r
- \r
- bool ourpage;\r
- bool dirty;\r
- bool gotcha;\r
- bool inkeying;\r
- bool isrecording;\r
- int record_pages[10];//Only 10 Pages per record;\r
- unsigned int firstlineupdate;\r
- VTeletextView *txtview;\r
-private:\r
- MediaPacket mediapacket;\r
- \r
- \r
-\r
-};\r
-\r
-#endif\r
+/*
+ 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
return 2;
}
case Remote::LEFT:
+ case Remote::DF_LEFT:
{
if (editsubtitles && subtitles) {
ssl.setDarkSelOption(true);
return 2;
}
case Remote::RIGHT:
+ case Remote::DF_RIGHT:
{
if (!editsubtitles && subtitles) {
ssl.setDarkSelOption(false);
vgfactor=gfactor;
vbfactor=bfactor;
#ifndef WIN32
+#ifndef _MIPS_ARCH
((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);
+#endif
#endif
rt=4;
break;
}
if (rt == 2) {
#ifndef WIN32
+#ifndef _MIPS_ARCH
((Surface_TYPE *)surface)->initConversionTables(vrfactor,vgfactor,vbfactor);
+#endif
#endif
bool updateAll=drawPicture;
draw();
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
}
#include "mediaprovider.h"
#include "mediaproviderids.h"
#include "vdrcommand.h"
+#include "video.h"
VDR* VDR::instance = NULL;
//prepare a request
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;
}
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);
recInfo->descriptions[i] = vresp->extractString();
}
}
+ recInfo->fps=vresp->extractdouble();
+
recInfo->print();
// }
channel->vpid = vresp->extractULONG();
+ channel->vstreamtype = vresp->extractULONG();
channel->numAPids = vresp->extractULONG();
for (ULONG i = 0; i < channel->numAPids; i++)
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;
ULONG extractULONG();
ULLONG extractULLONG();
long extractLONG();
+ double extractdouble();
bool end();
}
else
{
-// Log::getInstance()->log("VFeed", Log::DEBUG, "No data delay");
- MILLISLEEP(20);
+ //Log::getInstance()->log("VFeed", Log::DEBUG, "No data delay");
+ MILLISLEEP(5);
}
}
}
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"
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;
frames %= 1500;
ret.seconds = frames / 25;
ret.frames = frames % 25;
- }
+ }* /
return ret;
-}
+}*/
+/*
UINT Video::getFPS()
{
if (format == NTSC) return 30;
else return 25;
}
+*/
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; }
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;
UCHAR connection;
UCHAR aspectRatio;
UCHAR mode;
+ bool h264;
UINT screenWidth;
UINT screenHeight;
}
}
-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;}
// 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();
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+
+
#include "videowin.h"
#include "log.h"
#include "dssourcefilter.h"
#include "osdwin.h"
#include "audiowin.h"
#include "wwinvideofilter.h"
+#include "wwinvideoh264filter.h"
#include "wtabbar.h"
#include "woptionpane.h"
#include "i18n.h"
+#include "demuxer.h"
+
+#include <Mfapi.h>
+#include <mferror.h>
void AdjustWindow();
dsinited=false;
dsgraphbuilder=NULL;
dsmediacontrol=NULL;
- dsvmrrenderer=NULL;
+ dsrenderer=NULL;
dsrefclock=NULL;
dsmediafilter=NULL;
dsbasicaudio=NULL;
iframemode=false;//We are not in Iframe mode at begining
vmrdeinterlacing=2;//Best
videofilterselected=-1;
+ videoH264filterselected=-1;
+ currentpresenter=EVR;
{
CleanupDS();
CloseHandle(filtermutex);
- int i;
+ unsigned int i;
for (i=0;i<videofilterlist.size();i++)
{
if (videofilterlist[i].displayname) delete [] videofilterlist[i].displayname;
}
videofilterlist.clear();
+ for (i=0;i<videoH264filterlist.size();i++)
+ {
+ if (videoH264filterlist[i].displayname) delete [] videoH264filterlist[i].displayname;
+ if (videoH264filterlist[i].friendlyname) delete [] videoH264filterlist[i].friendlyname;
+ }
+ videoH264filterlist.clear();
+
videoposx=0;
videoposy=0;
initFilterDatabase();
+ initH264FilterDatabase();
if (!setFormat(tformat)){ shutdown(); return 0; }
return 1;
+ filtmap->Release();
+}
+
+void VideoWin::initH264FilterDatabase()
+{
+ /* This method should determine all availiable DirectShow Filters */
+ IFilterMapper2* filtmap=NULL;
+ HRESULT result;
+ result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
+ IID_IFilterMapper2,(void**)&filtmap);
+ if (result != S_OK)
+ {
+ Log::getInstance()->log("VideoWin", Log::ERR , "Unable to create FilterMapper!");
+ return;
+ }
+ /* Wishlist, what Mediatypes do we want */
+ GUID mtypesin[]={MEDIATYPE_Video,MEDIASUBTYPE_H264};
+ IEnumMoniker *myenum;
+ result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
+ TRUE,1,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
+ if (result != S_OK)
+ {
+ filtmap->Release();
+ Log::getInstance()->log("VideoWin", Log::ERR , "Unable to enum Filters!");
+ return;
+ }
+ ULONG gethowmany;
+ IMoniker * moni;
+ while(myenum->Next(1,&moni,&gethowmany)==S_OK)
+ {
+ VideoFilterDesc desc;
+ ZeroMemory(&desc,sizeof(desc));
+
+ LPOLESTR string;
+ moni->GetDisplayName(0,0,&string);
+ desc.displayname=new char[wcslen(string)+1];
+ wcstombs(desc.displayname,string,wcslen(string)+1);
+ CoTaskMemFree(string);
+ IPropertyBag *bag;
+ if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
+ {
+ VARIANT vari;
+ VariantInit(&vari);
+ result = bag->Read(L"FriendlyName",&vari,NULL);
+ if (result == S_OK)
+ {
+ desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
+ wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
+ }
+ VariantClear(&vari);
+ bag->Release();
+
+ }
+
+
+ videoH264filterlist.push_back(desc);
+
+
+
+ moni->Release();
+ // bctx->Release();
+ }
+ int i;
+ videoH264filterselected=-1;
+
+
+
+ myenum->Release();
+
+
+
filtmap->Release();
}
}
}
}
+ name=vdr->configLoad("DirectShow","VideoH264Filter");
+
+ if (name != NULL)
+ {
+ for (int i = 0;i <videoH264filterlist.size();i++)
+ {
+ if (strcmp(name,videoH264filterlist[i].displayname)==0)
+ {
+ videoH264filterselected = i;
+ break;
+ }
+ }
+ }
name=vdr->configLoad("DirectShow","VMR9DeinterlacingMode");
if (name != NULL)
{
}
}
+ 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) {
}
}
+
+
return true;
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;
if (videofilterselected!=-1) {
VDR::getInstance()->configSave("DirectShow",
"VideoFilter",videofilterlist[videofilterselected].displayname);
+ VDR::getInstance()->configSave("DirectShow",
+ "VideoH264Filter",videoH264filterlist[videoH264filterselected].displayname);
}
return true;
}
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);
+
}
}
+IBaseFilter *VideoWin::getVideoH264Filter()
+{
+ IBaseFilter *curfilter= NULL;
+ if (videoH264filterselected == -1)
+ {
+ int i;
+ for (i = 0;i <videoH264filterlist.size();i++)
+ {
+
+ if (videoH264filterlist[i].vmr9tested == true)
+ {
+ if (videoH264filterlist[i].vmr9 == true)
+ {
+ videoH264filterselected = i;
+ break;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ else
+ {
+ IMoniker * moni=NULL;
+ IBindCtx *bindctx=NULL;
+ if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
+ LPCOLESTR name=(LPCOLESTR)new WCHAR[strlen(videoH264filterlist[i].displayname)+1];
+ mbstowcs((wchar_t*)name,videoH264filterlist[i].displayname,strlen(videoH264filterlist[i].displayname)+1);
+ ULONG eater=0;
+ Log::getInstance()->log("VideoWin", Log::DEBUG ,"Creating filter: %s",videoH264filterlist[i].friendlyname);
+
+
+
+ if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
+ {
+ if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
+ {
+ IAMDecoderCaps* desccaps=NULL;
+ if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
+ {
+ DWORD caps;
+ desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
+ if (caps == DECODER_CAP_SUPPORTED)
+ {
+ videoH264filterlist[i].vmr9tested = true;
+ videoH264filterlist[i].vmr9 = true;
+ videoH264filterselected = i;
+ }
+ else
+ {
+ videoH264filterlist[i].vmr9tested = true;
+ videoH264filterlist[i].vmr9 = false;
+
+ curfilter->Release();
+ curfilter=NULL;
+ }
+ }
+ desccaps->Release();
+ }
+ moni->Release();
+ }
+ delete [] name;
+ bindctx->Release();
+ }
+ if (videoH264filterlist[i].vmr9) break;
+
+ }
+ if (curfilter != NULL)
+ {
+ VDR *vdr=VDR::getInstance();
+ if (vdr != NULL)
+ {
+ vdr->configSave("DirectShow","VideoH264Filter",
+ videoH264filterlist[videoH264filterselected].displayname);
+ }
+ return curfilter;
+ }
+ }
+ else
+ {
+ IBindCtx *bindctx=NULL;
+ if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
+ IMoniker * moni=NULL;
+ LPCOLESTR name=new WCHAR[strlen(videoH264filterlist[videoH264filterselected].displayname)+1];
+ mbstowcs((wchar_t*)name,videoH264filterlist[videoH264filterselected].displayname,
+ strlen(videoH264filterlist[videoH264filterselected].displayname)+1);
+ ULONG eater;
+ Log::getInstance()->log("VideoWin", Log::DEBUG ,"Creating filter: %s",videoH264filterlist[videoH264filterselected].friendlyname);
+ if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
+ {
+ if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
+ {
+ IAMDecoderCaps* desccaps=NULL;
+ if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
+ {
+ DWORD caps;
+ desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
+ if (caps == DECODER_CAP_SUPPORTED)
+ {
+ videoH264filterlist[videoH264filterselected].vmr9tested = true;
+ videoH264filterlist[videoH264filterselected].vmr9 = true;
+ }
+ else
+ {
+ videoH264filterlist[videoH264filterselected].vmr9tested = true;
+ videoH264filterlist[videoH264filterselected].vmr9 = false;
+ Log::getInstance()->log("VideoWin", Log::WARN ,"Filter does not support VMR9, but is selected, manual selection!");
+ }
+ }
+ moni->Release();
+ delete [] name;
+ bindctx->Release();
+ return curfilter;
+ }
+ moni->Release();
+ }
+ bindctx->Release();
+ delete [] name;
+ return NULL;
+ }
+ return NULL;
+
+}
+
#ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions
#include "dshelper.h"
{
Boxx *box=new WWinVideoFilter();
wtb->addTab(tr("Video Filter"), box);
+ box=new WWinVideoH264Filter();
+ wtb->addTab(tr("H264 Filter"), box);
return true;
}
return &videofilterlist;
}
+const VideoFilterDescList *VideoWin::getVideoH264FilterList(int &selected)
+{
+ selected=videoH264filterselected;
+ return &videoH264filterlist;
+}
+
bool VideoWin::selectVideoFilter(int filter)
{
IBindCtx *bindctx=NULL;
}
}
+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()
{
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)
{
}
#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!");
}
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;
return result;
}
-
+/* //to beremoved
ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode)
{
if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);
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);
dsvmrsurfnotify->Release();
dsvmrsurfnotify=NULL;
}
- if (dsvmrrenderer) {
- dsvmrrenderer->Release();
- dsvmrrenderer=NULL;
+ if (dsrenderer) {
+ dsrenderer->Release();
+ dsrenderer=NULL;
}
if (allocatorvmr) {
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) {
}
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
}
{
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 ;
}
}
}
-
- 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);
}
}
+bool VideoWin::supportsh264()
+{
+ if (videoH264filterlist.size()>0) return true;
+ else return false;
+}
+
+
bool VideoWin::changeAType(int type,IMediaSample* ms){
if (sourcefilter!= NULL) {
lastaudiomode=type;
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
};
#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
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:
};
+
+
#endif
class Video;
class PlayerRadio;
class Timers;
+class BoxStack;
class VRadioRec : public Boxx, public TimerReceiver
{
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"));
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;
{
toPlay->loadRecInfo(); // check if still need this
toPlay->loadMarks();
+ bool ish264;
- bool isRadio = toPlay->isRadio();
+ bool isRadio = toPlay->isRadio(ish264);
if (isRadio)
{
}
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;
}
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <math.h>
+
#include "vvideorec.h"
#include "vteletextview.h"
#include "log.h"
#include "channel.h"
-VVideoRec::VVideoRec(Recording* rec)
+VVideoRec::VVideoRec(Recording* rec, bool ish264)
{
boxstack = BoxStack::getInstance();
vdr = VDR::getInstance();
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;
// 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)
{
// 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
{
}
}
+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)
{
// 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)
{
// 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);
#include "colour.h"
#include "osdreceiver.h"
+#include "video.h"
+
class VDR;
-class Video;
class Timers;
class Player;
class Recording;
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);
void doTeletext();
+ hmsf framesToHMSF(ULONG frames); //moved from video, this is a recording property, if needed elsewhere -> recording
+
private:
BoxStack* boxstack;
VDR* vdr;
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);
}
};
}
} else {
- //Render
- ((OsdWin*)osd)->Render();
+ //Render, moved to OSD !
+ Sleep(20);
+ //((OsdWin*)osd)->Render();
}
}
// When that returns quit ------------------------------------------------------------------------------------------
}
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) {
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:
{
unsigned int tmp, offset, length, numtags;
int orient=-1;
+ jpegUserData * ud=0;
boolean swap;
orient = 1;
offset = 0;
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;