#include <lib/base/nconfig.h> // access to python config
#include <lib/base/httpstream.h>
+#include <lib/service/servicedvbfcc.h>
+
/* for subtitles */
#include <lib/gui/esubtitle.h>
#include <byteswap.h>
#include <netinet/in.h>
+#include <lib/dvb/fcc.h>
+
#ifndef BYTE_ORDER
#error no byte order defined!
#endif
else
{
eDVBChannelID chid, chid_ignore;
+ int system;
((const eServiceReferenceDVB&)ref).getChannelID(chid);
((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
- return res_mgr->canAllocateChannel(chid, chid_ignore);
+ return res_mgr->canAllocateChannel(chid, chid_ignore, system);
}
return false;
}
{ 1, 2, 3 }, // -T -C -S
{ 2, 1, 3 } // -T -S -C
};
+ int system;
((const eServiceReferenceDVB&)*it).getChannelID(chid);
- int tmp=res->canAllocateChannel(chid, chid_ignore, simulate);
- switch(tmp)
+ int tmp = res->canAllocateChannel(chid, chid_ignore, system, simulate);
+ if (tmp > 0)
{
- case 0:
- break;
- case 30000: // cached DVB-T channel
- case 1: // DVB-T frontend
- tmp = prio_map[prio_order][2];
- break;
- case 40000: // cached DVB-C channel
- case 2:
- tmp = prio_map[prio_order][1];
- break;
- default: // DVB-S
- tmp = prio_map[prio_order][0];
- break;
+ switch (system)
+ {
+ case iDVBFrontend::feTerrestrial:
+ tmp = prio_map[prio_order][2];
+ break;
+ case iDVBFrontend::feCable:
+ tmp = prio_map[prio_order][1];
+ break;
+ default:
+ case iDVBFrontend::feSatellite:
+ tmp = prio_map[prio_order][0];
+ break;
+ }
}
if (tmp > cur)
{
return m_parser.m_time_create;
else
return iServiceInformation::resNA;
+ case iServiceInformation::sIsScrambled:
+ return m_parser.m_scrambled;
default:
return iServiceInformation::resNA;
}
RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
{
ePtr<eDVBService> service;
+
int r = lookupService(service, ref);
if (r)
service = 0;
// check resources...
- ptr = new eDVBServicePlay(ref, service);
+ if (eFCCServiceManager::checkAvailable(ref))
+ ptr = new eDVBServiceFCCPlay(ref, service);
+ else
+ ptr = new eDVBServicePlay(ref, service);
return 0;
}
RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
{
- if (ref.path.empty())
- {
- ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
- 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;
- }
+ bool isstream = ref.path.substr(0, 7) == "http://";
+ ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref, isstream);
+ return 0;
}
RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
return 0;
}
-eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
+eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service, bool connect_event):
m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
{
m_is_primary = 1;
+ m_decoder_index = 0;
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;
-
- CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
+
+ if (connect_event)
+ CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
+
CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
m_subtitle_sync_timer = eTimer::create(eApp);
+ m_current_video_pid_type = 0;
+
+ m_qpip_mode = false;
+
+ m_play_audio = true;
+
CONNECT(m_subtitle_sync_timer->timeout, eDVBServicePlay::checkSubtitleTiming);
}
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_service_handler_timeshift.tuneExt(r, 1, source, r.path.c_str(), m_cue, 0, m_dvb_service, false); /* use the decoder demux for everything */
m_event((iPlayableService*)this, evUser+1);
}
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 */
+ int use_decode_demux = 1;
+ eDVBServicePMTHandler::serviceType type = eDVBServicePMTHandler::timeshift_playback;
+ m_service_handler_timeshift.tuneExt(r, use_decode_demux, source, m_timeshift_file_next.c_str(), m_cue, 0, m_dvb_service, type, false); /* use the decoder demux for everything */
m_event((iPlayableService*)this, evUser+1);
}
}
break;
+ case eDVBServicePMTHandler::eventNoDiskSpace:
+ eDebug("No space!");
+ m_event((iPlayableService*)this, evUser+3);
+ break;
}
}
RESULT eDVBServicePlay::start()
{
eServiceReferenceDVB service = (eServiceReferenceDVB&)m_reference;
+ bool scrambled = true;
+ eDVBServicePMTHandler::serviceType type = eDVBServicePMTHandler::livetv;
+
+ int use_decode_demux = 0;
/* in pvr mode, we only want to use one demux. in tv mode, we're using
two (one for decoding, one for data source), as we must be prepared
to start recording from the data demux. */
if (m_is_pvr)
{
+ use_decode_demux = 1;
eDVBMetaParser meta;
if (!meta.parseFile(m_reference.path))
{
service = meta.m_ref;
service.path = m_reference.path;
+ scrambled = meta.m_scrambled;
+ }
+ else
+ {
+ /* when there is no meta file we need to handle ts/m2ts as descrambled */
+ scrambled = false;
}
m_cue = new eCueSheet();
+ type = eDVBServicePMTHandler::playback;
}
else
m_event(this, evStart);
+ if (m_is_stream)
+ {
+ scrambled = true;
+ type = eDVBServicePMTHandler::streamclient;
+ }
+
m_first_program_info = 1;
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);
+ m_service_handler.tuneExt(service, use_decode_demux, source, service.path.c_str(), m_cue, false, m_dvb_service, type, scrambled);
if (m_is_pvr)
{
RESULT eDVBServicePlay::setTarget(int target)
{
m_is_primary = !target;
+ m_decoder_index = target;
return 0;
}
{
eDebug("setting cue skipmode to %d", skipmode);
if (m_cue)
- m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
+ {
+ long long _skipmode = skipmode;
+ if (m_current_video_pid_type == eDVBServicePMTHandler::videoStream::vtH265_HEVC)
+ {
+ if (ratio < 0)
+ _skipmode = skipmode * 3;
+ else
+ _skipmode = skipmode * 4;
+ }
+
+ m_cue->setSkipmode(_skipmode * 90000); /* convert to 90000 per second */
+ }
}
m_skipmode = skipmode;
case sAudioPID:
if (m_dvb_service)
{
- int apid = m_dvb_service->getCacheEntry(eDVBService::cAPID);
+ int apid = m_dvb_service->getCacheEntry(eDVBService::cMPEGAPID);
if (apid != -1)
return apid;
apid = m_dvb_service->getCacheEntry(eDVBService::cAC3PID);
if (apid != -1)
return apid;
+ apid = m_dvb_service->getCacheEntry(eDVBService::cDDPPID);
+ if (apid != -1)
+ return apid;
+ apid = m_dvb_service->getCacheEntry(eDVBService::cAACHEAPID);
+ if (apid != -1)
+ return apid;
+ apid = m_dvb_service->getCacheEntry(eDVBService::cAACAPID);
+ if (apid != -1)
+ return apid;
}
if (no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
case sPCRPID:
h.getHBBTVUrl(url);
return url;
}
+ case sLiveStreamDemuxId:
+ {
+ int id;
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ h.getDemuxID(id);
+
+ std::string demux;
+ demux += id + '0';
+ return demux;
+ }
default:
break;
}
m_current_audio_pid = apid;
- if (m_is_primary && m_decoder->setAudioPID(apid, apidtype))
+ if ((m_is_primary || (m_qpip_mode && m_play_audio)) && m_decoder->setAudioPID(apid, apidtype))
{
eDebug("set audio pid failed");
return -4;
case the real default is not yet available.)
*/
if (m_dvb_service && ((i != -1)
- || ((m_dvb_service->getCacheEntry(eDVBService::cAPID) == -1) && (m_dvb_service->getCacheEntry(eDVBService::cAC3PID)==-1))))
+ || ((m_dvb_service->getCacheEntry(eDVBService::cMPEGAPID) == -1)
+ && (m_dvb_service->getCacheEntry(eDVBService::cAC3PID)==-1)
+ && (m_dvb_service->getCacheEntry(eDVBService::cDDPPID)==-1)
+ && (m_dvb_service->getCacheEntry(eDVBService::cAACHEAPID)==-1)
+ && (m_dvb_service->getCacheEntry(eDVBService::cAACAPID)==-1))))
{
- if (apidtype == eDVBAudio::aMPEG)
- {
- m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
- m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
- }
- else if (apidtype == eDVBAudio::aAC3)
- {
- m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
- m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
- }
- else
- {
- m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
- m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
- }
+ m_dvb_service->setCacheEntry(eDVBService::cMPEGAPID, apidtype == eDVBAudio::aMPEG ? apid : -1);
+ m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apidtype == eDVBAudio::aAC3 ? apid : -1);
+ m_dvb_service->setCacheEntry(eDVBService::cDDPPID, apidtype == eDVBAudio::aDDP ? apid : -1);
+ m_dvb_service->setCacheEntry(eDVBService::cAACHEAPID, apidtype == eDVBAudio::aAACHE ? apid : -1);
+ m_dvb_service->setCacheEntry(eDVBService::cAACAPID, apidtype == eDVBAudio::aAAC ? apid : -1);
}
h.resetCachedProgram();
}
m_record->setTargetFD(m_timeshift_fd);
+ m_record->setTargetFilename(m_timeshift_file.c_str());
+ m_record->enableAccessPoints(false);
+ m_record->setTimeshift(true);
m_timeshift_enabled = 1;
close(m_timeshift_fd);
eDebug("remove timeshift file");
eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
+
+ {
+ std::string timeshift_file_sc = m_timeshift_file + ".sc";
+ eBackgroundFileEraser::getInstance()->erase(timeshift_file_sc.c_str());
+ }
return 0;
}
return;
else
{
+ int timing_pid = -1;
+ int timing_pid_type = -1;
std::set<int> pids_to_record;
pids_to_record.insert(0); // PAT
if (program.pmtPid != -1)
for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
i(program.videoStreams.begin());
i != program.videoStreams.end(); ++i)
+ {
pids_to_record.insert(i->pid);
+ if (timing_pid == -1)
+ {
+ timing_pid = i->pid;
+ timing_pid_type = i->type;
+ }
+ }
+
for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
i(program.audioStreams.begin());
i != program.audioStreams.end(); ++i)
- pids_to_record.insert(i->pid);
+ {
+ pids_to_record.insert(i->pid);
+
+ if (timing_pid == -1)
+ {
+ timing_pid = i->pid;
+ timing_pid_type = -1;
+ }
+ }
for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
i(program.subtitleStreams.begin());
for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
m_record->removePID(*i);
+
+ if (timing_pid != -1)
+ m_record->setTimingPID(timing_pid, timing_pid_type);
}
}
m_cue->seekTo(0, -1000);
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 */
+ int use_decode_demux = 1;
+ eDVBServicePMTHandler::serviceType type = eDVBServicePMTHandler::timeshift_playback;
+ m_service_handler_timeshift.tuneExt(r, use_decode_demux, source, m_timeshift_file.c_str(), m_cue, 0, m_dvb_service, type, false); /* use the decoder demux for everything */
eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
pause();
h.getDecodeDemux(m_decode_demux);
if (m_decode_demux)
{
- m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
+ m_decode_demux->getMPEGDecoder(m_decoder, m_decoder_index);
if (m_decoder)
m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
if (m_is_primary)
setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
m_decoder->setVideoPID(vpid, vpidtype);
- selectAudioStream();
+ m_current_video_pid_type = vpidtype;
+
+ if (!m_qpip_mode || m_play_audio) // 1) no qpip mode, 2) qpip mode & play audio
+ selectAudioStream();
- if (!(m_is_pvr || m_is_stream || m_timeshift_active || !m_is_primary))
+ //if (!(m_is_pvr || m_is_stream || m_timeshift_active || !m_is_primary))
+ if (!(m_is_pvr || m_is_stream || m_timeshift_active))
m_decoder->setSyncPCR(pcrpid);
else
m_decoder->setSyncPCR(-1);
{
if (m_subtitle_widget)
{
+ int subtitledelay = 0;
pts_t pos = 0;
if (m_decoder)
m_decoder->getPTS(0, pos);
+ if (m_is_pvr || m_timeshift_enabled)
+ {
+ eDebug("Subtitle in recording/timeshift");
+ subtitledelay = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_noPTSrecordingdelay", 315000);
+ }
+ else
+ {
+ /* check the setting for subtitle delay in live playback, either with pos, or without pos */
+ subtitledelay = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bad_timing_delay", 0);
+ }
+
eDebug("got new subtitle page %lld %lld %d", pos, page.m_pts, page.m_have_pts);
- m_subtitle_pages.push_back(page);
+ eDVBTeletextSubtitlePage tmppage = page;
+ tmppage.m_have_pts = true;
+
+ if (abs(tmppage.m_pts - pos) > 20*90000)
+ tmppage.m_pts = pos; // fix abnormal pos diffs
+
+ tmppage.m_pts += subtitledelay;
+ m_subtitle_pages.push_back(tmppage);
checkSubtitleTiming();
}
}
if (m_decoder)
m_decoder->getPTS(0, pos);
eDebug("got new subtitle page %lld %lld", pos, p.m_show_time);
- m_dvb_subtitle_pages.push_back(p);
+ if ( abs(pos-p.m_show_time)>1800000 && (m_is_pvr || m_timeshift_enabled))
+ {
+ eDebug("[eDVBServicePlay] Subtitle without PTS and recording");
+ int subtitledelay = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_noPTSrecordingdelay", 315000);
+
+ eDVBSubtitlePage tmppage;
+ tmppage = p;
+ tmppage.m_show_time = pos + subtitledelay;
+ m_dvb_subtitle_pages.push_back(tmppage);
+ }
+ else
+ {
+ int subtitledelay = ePythonConfigQuery::getConfigIntValue("config.subtitles.subtitle_bad_timing_delay", 0);
+ if (subtitledelay != 0)
+ {
+ eDVBSubtitlePage tmppage;
+ tmppage = p;
+ tmppage.m_show_time += subtitledelay;
+ m_dvb_subtitle_pages.push_back(tmppage);
+ }
+ else
+ m_dvb_subtitle_pages.push_back(p);
+ }
checkSubtitleTiming();
}
}
return r;
}
+void eDVBServicePlay::setQpipMode(bool value, bool audio)
+{
+ m_qpip_mode = value;
+ m_play_audio = audio;
+
+ if(m_decoder)
+ {
+ if (m_play_audio)
+ {
+ selectAudioStream();
+ }
+ else
+ {
+ m_decoder->setAudioPID(-1, -1);
+ }
+ m_decoder->set();
+ }
+}
DEFINE_REF(eDVBServicePlay)