#include "demuxer.h"
#include "callback.h"
+#include "dvbsubtitles.h"
#include "log.h"
#define DEMUXER_SEQ_HEAD 0x000001B3
sent = packet.getSize();
}
}
+ else if (packet_type == PESTYPE_PRIVATE_1 &&
+ packet.getSubstream() == 0x20)
+ {
+ if (subtitles) subtitles->put(packet);
+ sent = packet.getSize();
+ }
else
{
sent = packet.getSize();
{
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;
/*
- Copyright 2006-2007 Mark Calderbank
+ Copyright 2006-2008 Mark Calderbank
This file is part of VOMP.
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.
+ along with VOMP; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "demuxerts.h"
#include "log.h"
-DemuxerTS::DemuxerTS(int p_vID, int p_aID)
+DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID)
{
- vID = p_vID;
- aID = p_aID;
+ vID = p_vID; vActive = false;
+ aID = p_aID; aActive = false;
+ subID = p_subID; subActive = false;
atype = 0;
+ subLength = 0;
}
void DemuxerTS::flush()
parsed = false;
Demuxer::flush();
vPacket.init(PESTYPE_VID0);
- switch (atype) {
+ switch (atype)
+ {
case 1:
- aPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_AC30);break;
+ aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
+ break;
default:
case 0:
- aPacket.init(PESTYPE_AUD0);break;
- };
+ aPacket.init(PESTYPE_AUD0);
+ break;
+ }
+ subPacket.init(PESTYPE_PRIVATE_1);
vActive = false;
aActive = false;
+ subActive = false;
+ subLength = 0;
}
int DemuxerTS::scan(UCHAR *buf, int len)
{
- switch (atype) {
+ switch (atype)
+ {
case 1:
- return PESTYPE_PRIVATE_1;
+ return PESTYPE_PRIVATE_1;
default:
case 0:
- return PESTYPE_AUD0;
- };
-
+ return PESTYPE_AUD0;
+ }
}
void DemuxerTS::setVID(int p_vID)
{
aID = p_aID;
atype = type;
- switch (atype) {
+ switch (atype)
+ {
case 1:
- aPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_AC30);
- setAudioStream(PESTYPE_SUBSTREAM_AC30);break;
+ aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
+ setAudioStream(PESTYPE_SUBSTREAM_AC30);
+ break;
default:
case 0:
- aPacket.init(PESTYPE_AUD0);
- setAudioStream(PESTYPE_AUD0);
- break;
- };
+ aPacket.init(PESTYPE_AUD0);
+ setAudioStream(PESTYPE_AUD0);
+ break;
+ }
aActive = false;
}
+void DemuxerTS::setSubID(int p_subID)
+{
+ subID = p_subID;
+ subPacket.init(PESTYPE_PRIVATE_1);
+ subActive = false;
+ subLength = 0;
+}
+
int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)
{
UINT LoPattern = 0x100 | PESTYPE_VID0,
parsePacketDetails(vPacket);
parsed = true;
}
- rc = submitPacket(vPacket);
+ rc = submitPacket(vPacket);
}
vActive = true;
}
parsePacketDetails(aPacket);
parsed = true;
}
- rc = submitPacket(aPacket);
+ rc = submitPacket(aPacket);
}
aActive = true;
}
+ if (pid == subID)
+ {
+ if (subActive)
+ {
+ if (!parsed)
+ {
+ parsePacketDetails(subPacket);
+ parsed = true;
+ }
+ rc = submitPacket(subPacket);
+ }
+ subActive = true;
+ }
+
if (rc == 0) return 0;
parsed = false;
}
if (pid == aID)
{
- switch (atype) {
+ switch (atype)
+ {
case 1:
- aPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_AC30);break;
+ aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
+ break;
default:
case 0:
- aPacket.init(PESTYPE_AUD0);break;
- };
+ aPacket.init(PESTYPE_AUD0);
+ break;
+ }
+ buf += 6; datalen -= 6;
+ }
+ if (pid == subID)
+ {
+ subPacket.init(PESTYPE_PRIVATE_1);
+ subLength = (buf[4] << 8) + buf[5];
buf += 6; datalen -= 6;
}
}
if ( (pid == vID && vActive) ||
- (pid == aID && aActive) )
+ (pid == aID && aActive) ||
+ (pid == subID && subActive) )
{
PESPacket* packet = NULL;
if (pid == vID) packet = &vPacket;
if (pid == aID) packet = &aPacket;
+ if (pid == subID) packet = &subPacket;
if (packet != NULL)
{
if (packet->write(buf, datalen) == 0)
}
}
+ if (pid == subID && subActive && subPacket.getLength() == subLength)
+ {
+ parsePacketDetails(subPacket);
+Log::getInstance()->log("DEMUXERTS", Log::DEBUG, "SUBMITTING A SUBTITLE PACKET %d %x", subLength, subPacket.getSubstream());
+ submitPacket(subPacket);
+ subActive = false;
+ }
+
return 1;
}
class DemuxerTS : public Demuxer
{
public:
- DemuxerTS(int p_vID = 0, int p_aID = 0);
+ DemuxerTS(int p_vID = 0, int p_aID = 0, int p_subID = 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 type);
+ void setSubID(int p_subID);
int getVID() { return vID; }
int getAID() { return aID; }
+ int getSubID() { return subID; }
int put(UCHAR* buf, int len);
private:
bool parsed; // Whether PES packet to be submitted has been parsed yet
PESPacket vPacket; // Video PES packet under construction
PESPacket aPacket; // Audio PES packet under construction
- int vID, aID; // TS IDs for video/audio
+ PESPacket subPacket; // Subtitles PES packet under construction
+ int vID, aID, subID; // TS IDs for video/audio/subtitles
int atype;
bool vActive, aActive; // Whether video/audio is actively being captured
+ bool subActive; // Same for subtitles
+ UINT subLength; // Expected length of subtitle packet
};
#endif
while (subtitlePacketPosition < subSize)
{
if (sub_data[subtitlePacketPosition] == 0xFF)
- {
- subtitles->put(subtitlePacket);
+ { // Packet is complete. Switch it into the "real" packet to be submitted.
+ packet = subtitlePacket;
+ parsePacketDetails(packet);
subtitlePacketPosition = 0; // Wait for next non-continuation packet
break;
}
{
if (packet.getPTS() != PESPacket::PTS_INVALID)
{
- worklist.push_back(packet);
- nudge();
+ worklist.push_back(packet);
+ nudge();
}
}
unlockInput();
#include "remote.h"
#include "message.h"
#include "channel.h"
+#include "dvbsubtitles.h"
+#include "osdreceiver.h"
// ----------------------------------- Called from outside, one offs or info funcs
-PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
+PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
: vfeed(this), afeed(this)
{
messageQueue = tmessageQueue;
messageReceiver = tmessageReceiver;
+ osdReceiver = tosdReceiver;
chanList = tchanList;
audio = Audio::getInstance();
vdr = VDR::getInstance();
initted = false;
+ subtitlesShowing = false;
videoStartup = false;
stopNow = false;
demuxer = new DemuxerTS();
if (!demuxer) return 0;
+ subtitles = new DVBSubtitles(osdReceiver);
+ if (!subtitles) return 0;
- if (!demuxer->init(this, audio, video, 2097152, 524288))
+ if (!demuxer->init(this, audio, video, 2097152, 524288, subtitles))
{
logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
shutdown();
initted = false;
delete demuxer;
+ delete subtitles;
return 1;
}
return demuxer->setAID(newChannel,type);
}
+bool PlayerLiveTV::toggleSubtitles()
+{
+ if (!subtitlesShowing)
+ {
+ subtitlesShowing = true;
+ subtitles->show();
+ }
+ else
+ {
+ subtitlesShowing = false;
+ subtitles->hide();
+ }
+ return subtitlesShowing;
+}
+
// ----------------------------------- Externally called events
void PlayerLiveTV::go(ULONG index)
afeed.start();
vfeed.start();
+ subtitles->start();
state = newState;
return;
clearStreamChunks();
vfeed.stop();
afeed.stop();
+ subtitles->stop();
video->blank();
video->reset();
afeed.start();
vfeed.start();
+ subtitles->start();
state = newState;
return;
clearStreamChunks();
vfeed.stop();
afeed.stop();
+ subtitles->stop();
video->stop();
video->blank();
audio->stop();
clearStreamChunks();
vfeed.stop();
afeed.stop();
+ subtitles->stop();
video->stop();
video->blank();
audio->stop();
afeed.start();
vfeed.start();
+ subtitles->start();
state = newState;
return;
clearStreamChunks();
vfeed.stop();
afeed.stop();
+ subtitles->stop();
video->stop();
video->blank();
audio->stop();
clearStreamChunks();
vfeed.stop();
afeed.stop();
+ subtitles->stop();
video->stop();
video->blank();
audio->stop();
clearStreamChunks();
vfeed.stop();
afeed.stop();
+ subtitles->stop();
video->stop();
video->blank();
audio->stop();
afeed.start();
vfeed.start();
+ subtitles->start();
state = newState;
return;
{
logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
}
+ if (chan->numSPids > 0)
+ demuxer->setSubID(chan->spids[0].pid);
int streamSuccess = vdr->streamChannel(chan->number, this);
if (!checkError() && !streamSuccess)
class Video;
class Log;
class DemuxerTS;
+class OSDReceiver;
+class DVBSubtitles;
class PlayerLiveTV : public PlayerLive, public Thread_TYPE, public Callback, public StreamReceiver
{
public:
- PlayerLiveTV(MessageQueue* messageQueue, void* messageReceiver, ChannelList* chanList);
+ PlayerLiveTV(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* tosdReceiver, ChannelList* chanList);
virtual ~PlayerLiveTV();
virtual int init();
virtual void setChannel(ULONG index);
virtual void stop();
virtual void setAudioChannel(int newChannel,int type);
+ virtual bool toggleSubtitles();
virtual bool* getDemuxerMpegAudioChannels();
virtual bool* getDemuxerAc3AudioChannels();
void threadPostStopCleanup() {};
private:
+ bool subtitlesShowing;
MessageQueue* messageQueue;
void* messageReceiver;
+ OSDReceiver* osdReceiver;
Log* logger;
Audio* audio;
Video* video;
DemuxerTS* demuxer;
+ DVBSubtitles* subtitles;
VDR* vdr;
VFeed vfeed;
AFeed afeed;
#include "event.h"
#include "timers.h"
#include "vepg.h"
+#include "bitmap.h"
VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
{
if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
{
streamType = VDR::VIDEO;
- player = new PlayerLiveTV(Command::getInstance(), this, chanList);
+ player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);
}
else
{
doEPG();
return 2;
}
+ case Remote::RECORD:
+ if (streamType = VDR::VIDEO)
+ (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();
+ return 2;
}
return 1;
}
}
+void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)
+{
+ drawBitmap(posX, posY, bm);
+ Region r;
+ r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
+ boxstack->update(this, &r);
+}
+
+void VVideoLiveTV::clearOSD()
+{
+ rectangle(area, Colour(0,0,0,0));
+ boxstack->update(this, &area);
+}
+
+void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)
+{
+ Region r;
+ r.x = posX; r.y = posY; r.w = width; r.h = height;
+ rectangle(r, Colour(0,0,0,0));
+ boxstack->update(this, &r);
+}
#include "timerreceiver.h"
#include "wsymbol.h"
#include "wprogressbar.h"
+#include "osdreceiver.h"
class VChannelList;
class Video;
class WTextbox;
class PlayerLive;
class VAudioSelector;
+class Bitmap;
-class VVideoLiveTV : public Boxx, public TimerReceiver
+class VVideoLiveTV : public Boxx, public TimerReceiver, public OSDReceiver
{
public:
VVideoLiveTV(ChannelList* chanList, ULONG initialChannelNumber, VChannelList* vchannelList);
void timercall(int ref);
+ void drawOSDBitmap(UINT posX, UINT posY, const Bitmap&);
+ void clearOSD();
+ void clearOSDArea(UINT posX, UINT posY, UINT width, UINT height);
+
private:
BoxStack* boxstack;
VDR* vdr;