*/
#include "channel.h"
+#include "vdr.h"
Channel::Channel()
{
name = NULL;
index = -1;
+ vpid = 0;
+ numAPids = 0;
}
Channel::~Channel()
{
if (name) delete[] name;
index = -1; // just in case
+
+ for(ULONG i = 0; i < numAPids; i++) delete[] apids[i].name;
+}
+
+void Channel::loadPids()
+{
+ // Clear the list if this is a reload
+ if (numAPids)
+ {
+ for(ULONG i = 0; i < numAPids; i++) delete[] apids[i].name;
+ apids.clear();
+ vpid = 0;
+ numAPids = 0;
+ }
+
+ VDR::getInstance()->getChannelPids(this); // FIXME sort out this system
+
+ Log::getInstance()->log("Channel", Log::DEBUG, "C.%lu loaded, VPid=%lu, numApids=%lu", number, vpid, numAPids);
+ for (ULONG i = 0; i < numAPids; i++)
+ {
+ Log::getInstance()->log("Channel", Log::DEBUG, "APid %lu %s", apids[i].pid, apids[i].name);
+ }
}
#define CHANNEL_H
#include <stdio.h>
+#include <vector>
+#include "log.h"
#include "defines.h"
+// A struct to hold a audio pid pair
+
+typedef struct _apid
+{
+ ULONG pid;
+ char* name;
+} apid;
+
+typedef vector<apid> APidList;
+
class Channel
{
public:
Channel();
~Channel();
+ void loadPids();
+
ULONG number;
ULONG type;
char* name;
int index;
+
+ ULONG vpid;
+ ULONG numAPids;
+ APidList apids;
};
#endif
seq_header = false;
}
+void Demuxer::PESPacket::truncate()
+{
+ init(packetType);
+}
+
int Demuxer::PESPacket::write(UCHAR *buf, int len)
{
if (closed) return 0;
public:
PESPacket();
void init(UCHAR type);
+ void truncate();
int write(UCHAR* buf, int len);
int submit();
protected:
--- /dev/null
+/*
+ Copyright 2006 Mark Calderbank
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "demuxerts.h"
+
+DemuxerTS::DemuxerTS(int p_vID = 0, int p_aID = 0)
+{
+ vID = p_vID;
+ aID = p_aID;
+}
+
+void DemuxerTS::flush()
+{
+ partPacket = 0;
+ Demuxer::flush();
+ vPacket.init(0xE0);
+ aPacket.init(0xC0);
+}
+
+int DemuxerTS::scan(UCHAR *buf, int len)
+{
+ // Temporarily, just look for the lowest audio stream and return it
+
+ UINT LoPattern = 0x100 | PESTYPE_AUD0,
+ HiPattern = 0x100 | PESTYPE_AUDMAX;
+ int ret = 0;
+
+ while (len >= 4)
+ {
+ UINT pattern = *(UINT*)buf;
+ buf++; len--;
+
+ if (pattern < LoPattern || pattern > HiPattern) continue;
+ ret = pattern & 0xFF;
+ HiPattern = pattern;
+ if (HiPattern == LoPattern) break;
+ }
+ return ret;
+}
+
+void DemuxerTS::setVID(int p_vID)
+{
+ vID = p_vID;
+}
+
+void DemuxerTS::setAID(int p_aID)
+{
+ aID = p_aID;
+}
+
+int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)
+{
+ UINT LoPattern = 0x100 | PESTYPE_VID0,
+ HiPattern = 0x100 | PESTYPE_VIDMAX;
+
+ while (len >= 14)
+ {
+ UINT pattern = *(UINT*)buf;
+ buf++; len--;
+ if (pattern < LoPattern || pattern > HiPattern) continue;
+
+ UINT framelength = ((UINT)buf[3] << 8) | buf[4];
+ buf += 5; len -= 5;
+
+ if ( buf[1] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
+ {
+ *dest = ( (ULLONG)(buf[3] & 0x0E) << 29 ) |
+ ( (ULLONG)(buf[4]) << 22 ) |
+ ( (ULLONG)(buf[5] & 0xFE) << 14 ) |
+ ( (ULLONG)(buf[6]) << 7 ) |
+ ( (ULLONG)(buf[7] & 0xFE) >> 1 );
+ return 1;
+ }
+
+ buf += framelength; len -= framelength;
+ }
+ // No PTS found.
+ return 0;
+}
+
+int DemuxerTS::put(UCHAR* buf, int len)
+{
+ int ret = 0; // return number of bytes consumed
+
+ while (partPacket)
+ {
+ if (len >= TS_SIZE + 1 - partPacket)
+ { // Remainder of partial packet is available, plus one
+ memcpy(store+partPacket, buf, TS_SIZE - partPacket);
+ ret += TS_SIZE - partPacket;
+ buf += TS_SIZE - partPacket;
+ len -= TS_SIZE - partPacket;
+ partPacket = TS_SIZE;
+ if (*buf == TS_SIG)
+ { // Packet is properly terminated
+ int rc = processTS(store);
+ if (rc)
+ partPacket = 0; // Successfully processed
+ else
+ return ret; // Try again later.
+ }
+ else
+ { // Packet not terminated. Find another candidate, and shift store
+ Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!");
+ int search = 1;
+ while (search < partPacket && store[search] != TS_SIG)
+ search++;
+ partPacket -= search;
+ if (partPacket) memcpy(store, store+search, partPacket);
+ }
+ }
+ else
+ { // Still don't have complete packet. Consume what we do have.
+ memcpy(store+partPacket, buf, len);
+ partPacket += len;
+ ret += len;
+ return ret;
+ }
+ }
+
+ // Position ourselves at a candidate TS packet
+ while (*buf != TS_SIG && len)
+ {
+ Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!");
+ buf++; ret++; len--;
+ }
+
+ while (len)
+ {
+ if (len < TS_SIZE + 1)
+ { // Not enough data. Store what we have.
+ memcpy(store, buf, len);
+ partPacket = len;
+ ret += len;
+ return ret;
+ }
+
+ if (buf[TS_SIZE] != TS_SIG)
+ { // Not terminated correctly.
+ while (*buf != TS_SIG && len)
+ {
+ buf++; ret++; len--;
+ }
+ }
+ else
+ {
+ int rc = processTS(buf);
+ if (rc)
+ { // Successfully processed
+ buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE;
+ }
+ else
+ { // Processing failed.
+ return ret;
+ }
+ }
+ }
+ return ret;
+}
+
+int DemuxerTS::processTS(UCHAR* buf)
+{
+ int datalen = TS_SIZE - 4;
+ int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
+ UCHAR payload = buf[1] & 0x40;
+
+ if (buf[3] & 0x20) // Adaptation field is present
+ datalen -= (buf[4] + 1);
+ if (datalen < 0) // Error in stream TODO log this
+ return 1;
+ if (datalen == 0) // Null packet
+ return 1;
+ buf += (TS_SIZE - datalen);
+
+ if (payload)
+ {
+ int rc = 1;
+
+ if (pid == vID) rc = vPacket.submit();
+ if (pid == aID) rc = aPacket.submit();
+ if (rc == 0) return 0;
+
+ if (pid == vID)
+ {
+ vPacket.init(0xE0);
+ buf += 6; datalen -= 6;
+ }
+ if (pid == aID)
+ {
+ aPacket.init(0xC0);
+ buf += 6; datalen -= 6;
+ }
+// int pesID = -1;
+// if (datalen >= 4) pesID = buf[3];
+// switch (pesID)
+// {
+// case PESTYPE_VID0 ... PESTYPE_VIDMAX:
+// if (video_current == -1) video_current = pesID;
+// if (video_current == pesID)
+// {
+// vPID = pid;
+// vPacket.init(pesID);
+// buf += 6; datalen -= 6;
+// }
+// break;
+// case PESTYPE_AUD0 ... PESTYPE_AUDMAX:
+// if (audio_current == -1) audio_current = pesID;
+// if (audio_current == pesID)
+// {
+// aPID = pid;
+// aPacket.init(pesID);
+// buf += 6; datalen -= 6;
+// }
+// break;
+// }
+ }
+
+ PESPacket* packet = NULL;
+ if (pid == vID) packet = &vPacket;
+ if (pid == aID) packet = &aPacket;
+ if (packet != NULL)
+ {
+ if (packet->write(buf, datalen) == 0)
+ { // Writing to packet failed. It has overflowed.
+ Log::getInstance()->log("TS Demuxer", Log::DEBUG, "Packet overflow, pid %d", pid);
+ if (packet->submit() == 0)
+ return 0;
+ packet->truncate();
+ packet->write((UCHAR*)"\200\000\000", 3);
+ packet->write(buf, datalen);
+ }
+ }
+
+ return 1;
+}
--- /dev/null
+/*
+ Copyright 2006 Mark Calderbank
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef DEMUXERTS_H
+#define DEMUXERTS_H
+
+#include "demuxer.h"
+#include "defines.h"
+
+#define TS_SIZE 188
+#define TS_SIG 0x47
+
+class DemuxerTS : public Demuxer
+{
+ public:
+ DemuxerTS(int p_vID = 0, int p_aID = 0);
+ void flush();
+ int scan(UCHAR* buf, int len);
+ int findPTS(UCHAR* buf, int len, ULLONG* dest);
+ void setVID(int p_vID);
+ void setAID(int p_aID);
+ int put(UCHAR* buf, int len);
+
+ private:
+ int processTS(UCHAR* buf);
+
+ UCHAR store[TS_SIZE]; // Storage for partial packets
+ int partPacket; // Length of partial packet stored from previous put()
+ PESPacket vPacket; // Video PES packet under construction
+ PESPacket aPacket; // Audio PES packet under construction
+ int vID, aID; // TS IDs for video/audio
+};
+
+#endif
vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o \\r
directory.o mark.o \\r
player.o playerradio.o vfeed.o afeed.o \\r
- demuxer.o demuxervdr.o stream.o draintarget.o \\r
+ demuxer.o demuxervdr.o demuxerts.o stream.o draintarget.o \\r
viewman.o box.o region.o colour.o view.o \\r
vinfo.o vquestion.o vwallpaper.o vrecordinglist.o vlivebanner.o \\r
- vmute.o vvolume.o voptions.o \\r
+ vmute.o vvolume.o voptions.o \\r
vtimerlist.o vtimeredit.o voptionsmenu.o vrecordingmenu.o \\r
vchannellist.o vwelcome.o vvideolive.o vvideorec.o vepgsettimer.o \\r
vchannelselect.o vserverselect.o vconnect.o vepg.o vrecmove.o \\r
vradiorec.o vaudioselector.o \\r
widget.o wselectlist.o wjpeg.o wsymbol.o wbutton.o \\r
- woptionbox.o wtextbox.o wwss.o \\r
+ woptionbox.o wtextbox.o wwss.o \\r
fonts/helvB24.o fonts/helvB18.o \\r
remote.o led.o mtd.o video.o audio.o osd.o surface.o\r
mutex=CreateMutex(NULL,FALSE,NULL);
#endif
- demuxer = new DemuxerVDR();
+ if (isRecording)
+ demuxer = new DemuxerVDR();
+ else
+ demuxer = new DemuxerTS();
if (!demuxer) return 0;
if (!demuxer->init(this, audio, video, 2097152, 524288))
// ----------------------------------- Externally called events
+void Player::play(ULONG Vpid, ULONG Apid)
+{
+ // TS mode
+ DemuxerTS* dts = (DemuxerTS*)demuxer;
+ dts->setVID(Vpid);
+ dts->setAID(Apid);
+ play();
+}
+
void Player::play()
{
if (!initted) return;
if (state == S_PLAY) return;
lock();
+
bool doUnlock = false;
if (state == S_PAUSE_P) doUnlock = true;
switchState(S_PLAY);
thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
writeLength += thisWrite;
+// logger->log("Player", Log::DEBUG, "Player put %u to demuxer", thisWrite);
+
if (!thisWrite)
{
+// logger->log("Player", Log::DEBUG, "Demuxer full");
// demuxer is full and can't take anymore
threadLock();
threadWaitForSignal();
#include "audio.h"
#include "video.h"
#include "demuxervdr.h"
+#include "demuxerts.h"
#include "vfeed.h"
#include "afeed.h"
#include "remote.h"
void setLengthFrames(ULONG length);
void setAudioChannel(int newChannel);
- void play();
+ void play(); // Recording
+ void play(ULONG vpid, ULONG apid); // Live TV
void stop();
void pause();
void fastForward();
mutex=CreateMutex(NULL,FALSE,NULL);
#endif
- demuxer = new DemuxerVDR();
+ if (isRecording)
+ demuxer = new DemuxerVDR();
+ else
+ demuxer = new DemuxerTS();
if (!demuxer) return 0;
if (!demuxer->init(this, audio, NULL, 0, 40000))
// ----------------------------------- Externally called events
+void PlayerRadio::play(ULONG Apid)
+{
+ // TS mode
+ DemuxerTS* dts = (DemuxerTS*)demuxer;
+ dts->setAID(Apid);
+ play();
+}
+
void PlayerRadio::play()
{
if (!initted) return;
#include "audio.h"
#include "video.h"
#include "demuxervdr.h"
+#include "demuxerts.h"
#include "afeed.h"
#include "remote.h"
#include "vdr.h"
void setStartBytes(ULLONG startBytes);
void play();
+ void play(ULONG apid); // Live radio
void stop();
void pause();
void jumpToPercent(int percent);
return markList;
}
+
+void VDR::getChannelPids(Channel* channel)
+{
+ UCHAR buffer[12];
+
+ *(unsigned long*)&buffer[0] = htonl(8);
+ *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELPIDS);
+ *(unsigned long*)&buffer[8] = htonl(channel->number);
+
+ MUTEX_LOCK(&mutex);
+ if (!connected) { MUTEX_UNLOCK(&mutex); return ; }
+
+ int a = tcp->sendPacket(buffer, 12);
+
+ if (a != 12)
+ {
+ disconnect();
+ MUTEX_UNLOCK(&mutex);
+ return ;
+ }
+
+ if (!getPacket())
+ {
+ MUTEX_UNLOCK(&mutex);
+ return ;
+ }
+
+ // Format of response
+ // vpid
+ // number of apids
+ // {
+ // apid
+ // lang string
+ // }
+
+ channel->vpid = extractULONG();
+ channel->numAPids = extractULONG();
+
+ for (ULONG i = 0; i < channel->numAPids; i++)
+ {
+ apid newapid;
+ newapid.pid = extractULONG();
+ newapid.name = extractString();
+ channel->apids.push_back(newapid);
+ }
+
+ freePacket();
+ MUTEX_UNLOCK(&mutex);
+
+ return ;
+}
ChannelList* getChannelsList(ULONG type);
int streamChannel(ULONG number);
+ void getChannelPids(Channel* channel);
UCHAR* getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived);
int stopStreaming();
const static ULONG VDR_GETNEXTIFRAME = 19;
const static ULONG VDR_GETRECINFO = 20;
const static ULONG VDR_GETMARKS = 21;
+ const static ULONG VDR_GETCHANNELPIDS = 22;
int getPacket();
void freePacket();
if (vlen)
{
- // Log::getInstance()->log("VFeed", Log::DEBUG, "Written %i", vlen);
cb.call(this);
}
else
{
if (!noShowVLB) doBanner(false);
+ // FIXME - change this streamType thingy to the new system using getPids
+ // FIXME - upgrade PlayerRadio to new getPids
+
+ Channel* toPlay = (*chanList)[currentChannel];
+ toPlay->loadPids();
+
if (streamType == VDR::RADIO)
{
- ((PlayerRadio*)player)->play();
+ ((PlayerRadio*)player)->play(toPlay->apids[0].pid);
}
else
{
- ((Player*)player)->play();
+ ((Player*)player)->play(toPlay->vpid, toPlay->apids[0].pid);
}
}
}