#include <lib/dvb/tstools.h>
#include <lib/python/python.h>
#include <lib/base/nconfig.h> // access to python config
+#include <lib/base/httpstream.h>
/* for subtitles */
#include <lib/gui/esubtitle.h>
RESULT getName(const eServiceReference &ref, std::string &name);
int getLength(const eServiceReference &ref);
RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
- int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; }
+ int isPlayable(const eServiceReference &ref, const eServiceReference &ignore, bool simulate) { return 1; }
int getInfo(const eServiceReference &ref, int w);
std::string getInfoString(const eServiceReference &ref,int w);
PyObject *getInfoObject(const eServiceReference &r, int what);
RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
{
ASSERT(ref == m_ref);
- if (m_parser.m_name.size())
+ if (!ref.name.empty())
+ name = ref.name;
+ else if (!m_parser.m_name.empty())
name = m_parser.m_name;
else
{
{
if (!ref.path.empty())
{
- ePtr<eServiceEvent> event = new eServiceEvent;
- std::string filename = ref.path;
- filename.erase(filename.length()-2, 2);
- filename+="eit";
- if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
+ if (ref.path.substr(0, 7) == "http://")
{
- evt = event;
- return 0;
+ eServiceReference equivalentref(ref);
+ /* this might be a scrambled stream (id + 0x100), force equivalent dvb type */
+ equivalentref.type = eServiceFactoryDVB::id;
+ equivalentref.path.clear();
+ return eEPGCache::getInstance()->lookupEventTime(equivalentref, start_time, evt);
+ }
+ else
+ {
+ ePtr<eServiceEvent> event = new eServiceEvent;
+ std::string filename = ref.path;
+ filename.erase(filename.length()-2, 2);
+ filename+="eit";
+ if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
+ {
+ evt = event;
+ return 0;
+ }
}
}
evt = 0;
int err = f.open(m_ref.path.c_str(), 0);
if (err < 0)
return -1;
-
+
+ off_t offset = 0;
off_t length = f.length();
unsigned char buffer[188*256*4];
while (1)
{
- off_t offset = f.lseek(0, SEEK_CUR);
eDebug("at %08llx / %08llx (%d %%)", offset, length, (int)(offset * 100 / length));
- int r = f.read(buffer, sizeof(buffer));
+ int r = f.read(offset, buffer, sizeof(buffer));
if (!r)
break;
if (r < 0)
return r;
+ offset += r;
parser.parseData(offset, buffer, r);
}
return 0;
} else
{
+ bool isstream = ref.path.substr(0, 7) == "http://";
+ if(isstream)
+ {
+ ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref, isstream);
+ return 0;
+ }
ptr = 0;
return -1;
}
/* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
{
- eDebug("getService failed!");
+// eDebug("getService failed!");
return err;
}
}
return 0;
}
-eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
+eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
{
m_is_primary = 1;
- m_is_pvr = !m_reference.path.empty();
+ m_is_stream = m_reference.path.substr(0, 7) == "http://";
+ m_is_pvr = (!m_reference.path.empty() && !m_is_stream);
m_timeshift_enabled = m_timeshift_active = 0, m_timeshift_changed = 0;
m_skipmode = m_fastforward = m_slowmotion = 0;
updateTimeshiftPids();
if (!m_timeshift_active)
updateDecoder();
- if (m_first_program_info && m_is_pvr)
+ if (m_first_program_info & 1 && m_is_pvr)
{
- m_first_program_info = 0;
+ m_first_program_info &= ~1;
seekTo(0);
}
- m_event((iPlayableService*)this, evUpdatedInfo);
+ if (!m_timeshift_active)
+ m_event((iPlayableService*)this, evUpdatedInfo);
break;
}
case eDVBServicePMTHandler::eventPreStart:
case eDVBServicePMTHandler::eventSOF:
m_event((iPlayableService*)this, evSOF);
break;
+ case eDVBServicePMTHandler::eventHBBTVInfo:
+ m_event((iPlayableService*)this, evHBBTVInfo);
+ break;
}
}
switch (event)
{
case eDVBServicePMTHandler::eventNewProgramInfo:
+ eDebug("eventNewProgramInfo TS");
if (m_timeshift_active)
+ {
updateDecoder();
+ if (m_first_program_info & 2)
+ {
+ if (m_slowmotion)
+ {
+ eDebug("re-apply slowmotion after timeshift file change");
+ m_decoder->setSlowMotion(m_slowmotion);
+ }
+ if (m_fastforward)
+ {
+ eDebug("re-apply skip %d, ratio %d after timeshift file change", m_skipmode, m_fastforward);
+ if (m_skipmode)
+ m_cue->setSkipmode(m_skipmode * 90000); /* convert to 90000 per second */
+ if (m_fastforward != 1)
+ m_decoder->setFastForward(m_fastforward);
+ else
+ m_decoder->setTrickmode();
+ }
+ else
+ seekTo(0);
+ m_first_program_info &= ~2;
+ }
+ m_event((iPlayableService*)this, evUpdatedInfo);
+ }
break;
case eDVBServicePMTHandler::eventSOF:
- m_event((iPlayableService*)this, evSOF);
+#if 0
+ if (!m_timeshift_file_next.empty())
+ {
+ eDebug("timeshift SOF, switch to next file");
+ m_decoder->pause();
+
+ m_first_program_info |= 2;
+
+ eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
+ r.path = m_timeshift_file_next;
+
+ /* free the timeshift service handler, we need the resources */
+ m_service_handler_timeshift.free();
+ resetTimeshift(1);
+
+ if (m_skipmode < 0)
+ m_cue->seekTo(0, -1000);
+ ePtr<iTsSource> source = createTsSource(r);
+ m_service_handler_timeshift.tuneExt(r, 1, source, r.path.c_str(), m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
+
+ m_event((iPlayableService*)this, evUser+1);
+ }
+ else
+#endif
+ m_event((iPlayableService*)this, evSOF);
break;
case eDVBServicePMTHandler::eventEOF:
if ((!m_is_paused) && (m_skipmode >= 0))
{
- eDebug("timeshift EOF, so let's go live");
- switchToLive();
+ if (m_timeshift_file_next.empty())
+ {
+ eDebug("timeshift EOF, so let's go live");
+ switchToLive();
+ }
+ else
+ {
+ eDebug("timeshift EOF, switch to next file");
+
+ m_first_program_info |= 2;
+
+ eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
+ r.path = m_timeshift_file_next;
+
+ /* free the timeshift service handler, we need the resources */
+ m_service_handler_timeshift.free();
+ resetTimeshift(1);
+
+ ePtr<iTsSource> source = createTsSource(r);
+ m_service_handler_timeshift.tuneExt(r, 1, source, m_timeshift_file_next.c_str(), m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
+
+ m_event((iPlayableService*)this, evUser+1);
+ }
}
break;
}
m_event(this, evStart);
m_first_program_info = 1;
- m_service_handler.tune(service, m_is_pvr, m_cue, false, m_dvb_service);
+ ePtr<iTsSource> source = createTsSource(service);
+ m_service_handler.tuneExt(service, m_is_pvr, source, service.path.c_str(), m_cue, false, m_dvb_service, m_is_stream);
if (m_is_pvr)
{
if (length)
{
- int perc = play_position * 100LL / length;
-
- /* only store last play position when between 1% and 99% */
- if ((1 < perc) && (perc < 99))
- m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
+ m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
}
m_cuesheet_changed = 1;
}
if (m_decoder)
{
ret = (m_is_pvr || m_timeshift_active) ? 3 : 0; // fast forward/backward possible and seeking possible
- if (m_decoder->getVideoWidth() == -1)
+ if (m_decoder->getVideoProgressive() == -1)
ret &= ~2;
}
return ret;
{
ptr = 0;
if (m_have_video_pid && // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
- (m_timeshift_enabled || !m_is_pvr))
+ (m_timeshift_enabled || (!m_is_pvr&&!m_is_stream)))
{
if (!m_timeshift_enabled)
{
ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
return i->getName(m_reference, name);
}
+ else if (m_is_stream)
+ {
+ name = m_reference.name;
+ if (name.empty())
+ {
+ name = m_reference.path;
+ }
+ if (name.empty())
+ {
+ name = "(...)";
+ }
+ }
else if (m_dvb_service)
{
m_dvb_service->getName(m_reference, name);
{
eDVBServicePMTHandler::program program;
- if (w == sCAIDs)
+ if (w == sCAIDs || w == sCAIDPIDs)
return resIsPyObject;
eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
return m_dvb_service->m_provider_name;
case sServiceref:
return m_reference.toString();
+ case sHBBTVUrl:
+ {
+ std::string url;
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ h.getHBBTVUrl(url);
+ return url;
+ }
default:
break;
}
{
case sCAIDs:
return m_service_handler.getCaIds();
+ case sCAIDPIDs:
+ return m_service_handler.getCaIds(true);
case sTransponderData:
return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
+ case sHBBTVUrl:
+ {
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ return h.getHbbTVApplications();
+ }
default:
break;
}
if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
info.m_description = "MPEG";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
- info.m_description = "AC3";
+ info.m_description = "Dolby Digital";
+ else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDDP)
+ info.m_description = "Dolby Digital+";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
info.m_description = "AAC";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAACHE)
info.m_description = "AAC-HE";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
info.m_description = "DTS";
+ else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTSHD)
+ info.m_description = "DTS-HD";
else
info.m_description = "???";
return 0;
}
-RESULT eDVBServicePlay::stopTimeshift()
+RESULT eDVBServicePlay::stopTimeshift(bool swToLive)
{
if (!m_timeshift_enabled)
return -1;
- switchToLive();
+ if (swToLive)
+ switchToLive();
m_timeshift_enabled = 0;
}
}
+RESULT eDVBServicePlay::setNextPlaybackFile(const char *f)
+{
+ m_timeshift_file_next = f;
+ return 0;
+}
+
void eDVBServicePlay::switchToLive()
{
if (!m_timeshift_active)
return;
-
+
eDebug("SwitchToLive");
-
+
+ resetTimeshift(0);
+
+ m_is_paused = m_skipmode = m_fastforward = m_slowmotion = 0; /* not supported in live mode */
+
+ /* free the timeshift service handler, we need the resources */
+ m_service_handler_timeshift.free();
+
+ updateDecoder(true);
+}
+
+void eDVBServicePlay::resetTimeshift(int start)
+{
m_cue = 0;
- m_decoder = 0;
m_decode_demux = 0;
+ m_decoder = 0;
m_teletext_parser = 0;
m_rds_decoder = 0;
m_subtitle_parser = 0;
- m_new_dvb_subtitle_page_connection = 0;
m_new_subtitle_page_connection = 0;
+ m_new_dvb_subtitle_page_connection = 0;
m_rds_decoder_event_connection = 0;
m_video_event_connection = 0;
- m_is_paused = m_skipmode = m_fastforward = m_slowmotion = 0; /* not supported in live mode */
-
- /* free the timeshift service handler, we need the resources */
- m_service_handler_timeshift.free();
- m_timeshift_active = 0;
m_timeshift_changed = 1;
+ m_timeshift_file_next.clear();
- m_event((iPlayableService*)this, evSeekableStatusChanged);
+ if (start)
+ {
+ m_cue = new eCueSheet();
+ m_timeshift_active = 1;
+ }
+ else
+ m_timeshift_active = 0;
+}
- updateDecoder();
+ePtr<iTsSource> eDVBServicePlay::createTsSource(eServiceReferenceDVB &ref)
+{
+ if (m_is_stream)
+ {
+ eHttpStream *f = new eHttpStream();
+ f->open(ref.path.c_str());
+ return ePtr<iTsSource>(f);
+ }
+ else
+ {
+ eRawFile *f = new eRawFile();
+ f->open(ref.path.c_str());
+ return ePtr<iTsSource>(f);
+ }
}
void eDVBServicePlay::switchToTimeshift()
if (m_timeshift_active)
return;
- m_decode_demux = 0;
- m_decoder = 0;
- m_teletext_parser = 0;
- m_rds_decoder = 0;
- m_subtitle_parser = 0;
- m_new_subtitle_page_connection = 0;
- m_new_dvb_subtitle_page_connection = 0;
- m_rds_decoder_event_connection = 0;
- m_video_event_connection = 0;
-
- m_timeshift_active = 1;
- m_timeshift_changed = 1;
+ resetTimeshift(1);
eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
r.path = m_timeshift_file;
- m_cue = new eCueSheet();
m_cue->seekTo(0, -1000);
- m_service_handler_timeshift.tune(r, 1, m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
+
+ ePtr<iTsSource> source = createTsSource(r);
+ m_service_handler_timeshift.tuneExt(r, 1, source, m_timeshift_file.c_str(), m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
pause();
- updateDecoder(); /* mainly to switch off PCR, and to set pause */
-
- m_event((iPlayableService*)this, evSeekableStatusChanged);
+ updateDecoder(true); /* mainly to switch off PCR, and to set pause */
}
-void eDVBServicePlay::updateDecoder()
+void eDVBServicePlay::updateDecoder(bool sendSeekableStateChanged)
{
int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
bool mustPlay = false;
eDebug("getting program info failed.");
else
{
- eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
+ eDebugNoNewLine("have %zd video stream(s)", program.videoStreams.size());
if (!program.videoStreams.empty())
{
eDebugNoNewLine(" (");
}
eDebugNoNewLine(")");
}
- eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
+ eDebugNoNewLine(", and %zd audio stream(s)", program.audioStreams.size());
if (!program.audioStreams.empty())
{
eDebugNoNewLine(" (");
if (!m_decoder)
{
h.getDecodeDemux(m_decode_demux);
- if (m_timeshift_changed)
- m_decoder = 0;
if (m_decode_demux)
{
m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
if (m_decoder)
{
+ bool wasSeekable = m_decoder->getVideoProgressive() != -1;
if (m_dvb_service)
{
achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
m_decoder->setVideoPID(vpid, vpidtype);
selectAudioStream();
- if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
+ if (!(m_is_pvr || m_is_stream || m_timeshift_active || !m_is_primary))
m_decoder->setSyncPCR(pcrpid);
else
m_decoder->setSyncPCR(-1);
m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
}
+ if (!sendSeekableStateChanged && (m_decoder->getVideoProgressive() != -1) != wasSeekable)
+ sendSeekableStateChanged = true;
}
m_have_video_pid = (vpid > 0 && vpid < 0x2000);
+
+ if (sendSeekableStateChanged)
+ m_event((iPlayableService*)this, evSeekableStatusChanged);
}
void eDVBServicePlay::loadCuesheet()
m_cue_entries.insert(cueEntry(where, what));
}
fclose(f);
- eDebug("%d entries", m_cue_entries.size());
+ eDebug("%zd entries", m_cue_entries.size());
} else
eDebug("cutfile not found!");
{
if (i == m_cue_entries.end())
{
- if (!have_any_span)
+ if (!have_any_span && !in)
break;
out = length;
} else {
{
have_any_span = 1;
m_cue->addSourceSpan(in, out);
+ in = out = 0;
}
in = length;