2 Copyright 2007 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "playerlivetv.h"
26 #include "demuxerts.h"
28 #include "messagequeue.h"
33 // ----------------------------------- Called from outside, one offs or info funcs
35 PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
36 : vfeed(this), afeed(this)
38 messageQueue = tmessageQueue;
39 messageReceiver = tmessageReceiver;
42 audio = Audio::getInstance();
43 video = Video::getInstance();
44 logger = Log::getInstance();
45 vdr = VDR::getInstance();
56 PlayerLiveTV::~PlayerLiveTV()
58 if (initted) shutdown();
61 int PlayerLiveTV::init()
63 if (initted) return 0;
65 demuxer = new DemuxerTS();
66 if (!demuxer) return 0;
68 if (!demuxer->init(this, audio, video, 2097152, 524288))
70 logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
86 int PlayerLiveTV::shutdown()
88 if (!initted) return 0;
101 bool* PlayerLiveTV::getDemuxerMpegAudioChannels()
103 return demuxer->getmpAudioChannels();
106 bool* PlayerLiveTV::getDemuxerAc3AudioChannels()
108 return demuxer->getac3AudioChannels();
111 int PlayerLiveTV::getCurrentAudioChannel()
113 return demuxer->getAID();
116 void PlayerLiveTV::setAudioChannel(int newChannel)
118 return demuxer->setAID(newChannel);
121 // ----------------------------------- Externally called events
123 void PlayerLiveTV::go(ULONG index)
125 struct PLTVInstruction i;
127 i.channelIndex = index;
128 instructions.push(i);
132 void PlayerLiveTV::setChannel(ULONG index)
134 logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
135 struct PLTVInstruction i;
137 i.channelIndex = index;
138 instructions.push(i);
139 threadSignalNoLock();
142 void PlayerLiveTV::stop()
144 logger->log("PlayerLiveTV", Log::DEBUG, "stop");
145 struct PLTVInstruction i;
147 instructions.push(i);
152 // ----------------------------------- Callback
154 void PlayerLiveTV::call(void* caller)
156 if (caller == demuxer)
158 logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");
160 if (video->getTVsize() == Video::ASPECT4X3)
162 logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
166 int dxCurrentAspect = demuxer->getAspectRatio();
167 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
169 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
170 video->setAspectRatio(Video::ASPECT4X3);
172 Message* m = new Message();
174 m->to = messageReceiver;
175 m->message = Message::PLAYER_EVENT;
176 m->parameter = PlayerLiveTV::ASPECT43;
177 messageQueue->postMessageFromOuterSpace(m);
179 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
181 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
182 video->setAspectRatio(Video::ASPECT16X9);
184 Message* m = new Message();
186 m->to = messageReceiver;
187 m->message = Message::PLAYER_EVENT;
188 m->parameter = PlayerLiveTV::ASPECT169;
189 messageQueue->postMessageFromOuterSpace(m);
193 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... ignoring");
196 else if (caller == &afeed)
198 if (state == S_VIDEOSTARTUP)
200 logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");
202 threadSignalNoLock();
207 // -----------------------------------
209 void PlayerLiveTV::streamReceive(void* data, ULONG len)
211 if (streamChunks.size() < 11)
216 streamChunks.push(s);
217 threadSignalNoLock();
221 // Too many chunks in streamChunks, drop this chunk
223 logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");
227 void PlayerLiveTV::clearStreamChunks()
229 while(streamChunks.size())
231 logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");
232 struct StreamChunk s = streamChunks.front();
238 void PlayerLiveTV::chunkToDemuxer()
240 StreamChunk s = streamChunks.front();
242 //logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
243 /*int a = */demuxer->put((UCHAR*)s.data, s.len);
244 //logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);
248 void PlayerLiveTV::switchState(UCHAR newState)
250 logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);
254 case S_STOP: // FROM S_STOP
269 audio->setStreamType(Audio::MPEG2_PES);
285 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
292 case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP
305 vdr->stopStreaming();
319 audio->setStreamType(Audio::MPEG2_PES);
335 vdr->stopStreaming();
349 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
356 case S_PREBUFFERING: // FROM S_PREBUFFERING
369 vdr->stopStreaming();
384 audio->setStreamType(Audio::MPEG2_PES);
400 vdr->stopStreaming();
414 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
421 case S_PLAY: // FROM S_PLAY
427 vdr->stopStreaming();
441 vdr->stopStreaming();
456 audio->setStreamType(Audio::MPEG2_PES);
472 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
481 void PlayerLiveTV::threadMethod()
485 if (videoStartup) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
487 switchState(S_PREBUFFERING);
488 videoStartup = false;
489 videoStartup2Counter = 0;
492 while(!instructions.empty())
494 struct PLTVInstruction i = instructions.front();
497 logger->log("PlayerLiveTV", Log::DEBUG, "%u %lu", i.instruction, i.channelIndex);
500 if (i.instruction == 1)
502 logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");
504 switchState(S_VIDEOSTARTUP);
506 Channel* chan = (*chanList)[i.channelIndex];
508 demuxer->setVID(chan->vpid);
509 demuxer->setAID(chan->apids[0].pid);
510 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);
511 vdr->streamChannel(chan->number, this);
514 else if (i.instruction == 2)
516 logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");
526 while(streamChunks.size())
530 if (state == S_PREBUFFERING)
532 if (++videoStartup2Counter == 3)
540 threadWaitForSignal(); // unlocks and waits for signal
545 logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");