#include <string>
#include <lib/service/servicedvb.h>
#include <lib/service/service.h>
+#include <lib/base/estring.h>
#include <lib/base/init_num.h>
#include <lib/base/init.h>
-
+#include <lib/base/nconfig.h> // access to python config
#include <lib/dvb/dvb.h>
#include <lib/dvb/db.h>
#include <lib/dvb/decoder.h>
#include <lib/dvb/tstools.h>
#include <lib/python/python.h>
+ /* for subtitles */
+#include <lib/gui/esubtitle.h>
+
#include <sys/vfs.h>
+#include <sys/stat.h>
#include <byteswap.h>
#include <netinet/in.h>
-#include <dvbsi++/event_information_section.h>
-
#ifndef BYTE_ORDER
#error no byte order defined!
#endif
eStaticServiceDVBPVRInformation(const eServiceReference &ref);
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 getInfo(const eServiceReference &ref, int w);
std::string getInfoString(const eServiceReference &ref,int w);
};
return m_parser.m_description;
case iServiceInformation::sServiceref:
return m_parser.m_ref.toString();
+ case iServiceInformation::sTags:
+ return m_parser.m_tags;
default:
return "";
}
}
+RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
+{
+ 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()))
+ {
+ evt = event;
+ return 0;
+ }
+ }
+ evt = 0;
+ return -1;
+}
+
class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
{
DECLARE_REF(eDVBPVRServiceOfflineOperations);
if (!eraser)
eDebug("FATAL !! can't get background file eraser");
- /* TODO: deferred removing.. */
for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
{
eDebug("Removing %s...", i->c_str());
eServiceCenter::getPrivInstance(sc);
if (sc)
sc->addServiceFactory(eServiceFactoryDVB::id, this);
+
+ m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
+ m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
}
eServiceFactoryDVB::~eServiceFactoryDVB()
return 0;
}
-RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
-{
- eServiceReferenceDVB ref;
-
- if (!m_query || !list || !PyList_Check(list))
- return -1;
-
- std::list<eServiceReferenceDVB> tmplist;
-
- while (!m_query->getNextResult(ref))
- tmplist.push_back(ref);
-
- if (sorted)
- tmplist.sort(iListableServiceCompare(this));
-
- for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
- it != tmplist.end(); ++it)
- {
- PyObject *refobj = New_eServiceReference(*it);
- PyList_Append(list, refobj);
- Py_DECREF(refobj);
- }
- return 0;
-}
-
RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
{
eServiceReferenceDVB ref;
return 0;
}
+// The first argument of this function is a format string to specify the order and
+// the content of the returned list
+// useable format options are
+// R = Service Reference (as swig object .. this is very slow)
+// S = Service Reference (as python string object .. same as ref.toString())
+// C = Service Reference (as python string object .. same as ref.toCompareString())
+// N = Service Name (as python string object)
+// when exactly one return value per service is selected in the format string,
+// then each value is directly a list entry
+// when more than one value is returned per service, then the list is a list of
+// python tuples
+// unknown format string chars are returned as python None values !
+PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
+{
+ PyObject *ret=0;
+ std::list<eServiceReference> tmplist;
+ int retcount=1;
+
+ if (!format || !(retcount=strlen(format)))
+ format = "R"; // just return service reference swig object ...
+
+ if (!getContent(tmplist, sorted))
+ {
+ int services=tmplist.size();
+ ePtr<iStaticServiceInformation> sptr;
+ eServiceCenterPtr service_center;
+
+ if (strchr(format, 'N'))
+ eServiceCenter::getPrivInstance(service_center);
+
+ ret = PyList_New(services);
+ std::list<eServiceReference>::iterator it(tmplist.begin());
+
+ for (int cnt=0; cnt < services; ++cnt)
+ {
+ eServiceReference &ref=*it++;
+ PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
+ for (int i=0; i < retcount; ++i)
+ {
+ PyObject *tmp=0;
+ switch(format[i])
+ {
+ case 'R': // service reference (swig)object
+ tmp = New_eServiceReference(ref);
+ break;
+ case 'C': // service reference compare string
+ tmp = PyString_FromString(ref.toCompareString().c_str());
+ break;
+ case 'S': // service reference string
+ tmp = PyString_FromString(ref.toString().c_str());
+ break;
+ case 'N': // service name
+ if (service_center)
+ {
+ service_center->info(ref, sptr);
+ if (sptr)
+ {
+ std::string name;
+ sptr->getName(ref, name);
+ if (name.length())
+ tmp = PyString_FromString(name.c_str());
+ }
+ }
+ if (!tmp)
+ tmp = PyString_FromString("<n/a>");
+ break;
+ default:
+ if (tuple)
+ {
+ tmp = Py_None;
+ Py_INCREF(Py_None);
+ }
+ break;
+ }
+ if (tmp)
+ {
+ if (tuple)
+ PyTuple_SET_ITEM(tuple, i, tmp);
+ else
+ PyList_SET_ITEM(ret, cnt, tmp);
+ }
+ }
+ if (tuple)
+ PyList_SET_ITEM(ret, cnt, tuple);
+ }
+ }
+ return ret ? ret : PyList_New(0);
+}
+
RESULT eDVBServiceList::getNext(eServiceReference &ref)
{
if (!m_query)
return -1;
}
-RESULT eDVBServiceList::addService(eServiceReference &ref)
+RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
{
if (!m_bouquet)
return -1;
- return m_bouquet->addService(ref);
+ return m_bouquet->addService(ref, before);
}
RESULT eDVBServiceList::removeService(eServiceReference &ref)
if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
{
if ( !ref.name.empty() ) // satellites or providers list
- ptr = new eStaticServiceDVBInformation;
+ ptr = m_StaticServiceDVBInfo;
else // a dvb bouquet
- ptr = new eStaticServiceDVBBouquetInformation;
+ ptr = m_StaticServiceDVBBouquetInfo;
}
else if (!ref.path.empty()) /* do we have a PVR service? */
ptr = new eStaticServiceDVBPVRInformation(ref);
{
ePtr<eDVBService> service;
if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
- ptr = new eStaticServiceDVBInformation;
+ ptr = m_StaticServiceDVBInfo;
else
/* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
ptr = service;
}
eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
- m_reference(ref), m_dvb_service(service), m_is_paused(0)
+ 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_cuesheet_changed = 0;
m_cutlist_enabled = 1;
+
+ m_subtitle_widget = 0;
+
+ CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
}
eDVBServicePlay::~eDVBServicePlay()
{
+ delete m_subtitle_widget;
}
void eDVBServicePlay::gotNewEvent()
m_first_program_info = 1;
eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
r = m_service_handler.tune(service, m_is_pvr, m_cue);
-
+
/* inject EIT if there is a stored one */
if (m_is_pvr)
{
std::string filename = service.path;
filename.erase(filename.length()-2, 2);
filename+="eit";
- int fd = ::open( filename.c_str(), O_RDONLY );
- if ( fd > -1 )
+ ePtr<eServiceEvent> event = new eServiceEvent;
+ if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
{
- __u8 buf[4096];
- int rd = ::read(fd, buf, 4096);
- ::close(fd);
- if ( rd > 12 /*EIT_LOOP_SIZE*/ )
- {
- Event ev(buf);
- ePtr<eServiceEvent> event = new eServiceEvent;
- ePtr<eServiceEvent> empty;
- event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
- m_event_handler.inject(event, 0);
- m_event_handler.inject(empty, 1);
- eDebug("injected");
- }
+ ePtr<eServiceEvent> empty;
+ m_event_handler.inject(event, 0);
+ m_event_handler.inject(empty, 1);
}
}
-
+
if (m_is_pvr)
loadCuesheet();
RESULT eDVBServicePlay::stop()
{
+ /* add bookmark for last play position */
+ if (m_is_pvr)
+ {
+ pts_t play_position;
+ if (!getPlayPosition(play_position))
+ {
+ /* remove last position */
+ for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
+ {
+ if (i->what == 3) /* current play position */
+ {
+ m_cue_entries.erase(i);
+ i = m_cue_entries.begin();
+ continue;
+ } else
+ ++i;
+ }
+
+ m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
+ m_cuesheet_changed = 1;
+ }
+ }
+
stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
m_service_handler_timeshift.free();
m_service_handler.free();
if (m_is_pvr && m_cuesheet_changed)
- saveCuesheet();
+ {
+ struct stat s;
+ /* save cuesheet only when main file is accessible. */
+ if (!::stat(m_reference.path.c_str(), &s))
+ saveCuesheet();
+ }
return 0;
}
return m_is_pvr || m_timeshift_active;
}
-RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
+RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
{
ptr = this;
return 0;
return 0;
}
+RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
+{
+ ptr = this;
+ return 0;
+}
+
RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
{
ptr = this;
RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
{
ptr = 0;
- if (m_timeshift_enabled || !m_is_pvr)
+ if (m_have_video_pid && // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
+ (m_timeshift_enabled || !m_is_pvr))
{
if (!m_timeshift_enabled)
{
return -1;
}
+RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
+{
+ ptr = this;
+ return 0;
+}
+
+RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
+{
+ ptr = this;
+ return 0;
+}
+
+RESULT eDVBServicePlay::radioText(ePtr<iRadioText> &ptr)
+{
+ ptr = this;
+ return 0;
+}
+
RESULT eDVBServicePlay::getName(std::string &name)
{
if (m_is_pvr)
{
eDVBServicePMTHandler::program program;
- if (m_service_handler.getProgramInfo(program))
+ if (w == sCAIDs)
+ return resIsPyObject;
+
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+
+ if (h.getProgramInfo(program))
return -1;
switch (w)
}
}
return -1;
- case sIsCrypted: return program.isCrypted;
+ case sIsCrypted: return program.isCrypted();
case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
- case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
+ case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
+ case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
case sPCRPID: return program.pcrPid;
case sPMTPID: return program.pmtPid;
case sTXTPID: return program.textPid;
}
std::string eDVBServicePlay::getInfoString(int w)
-{
+{
switch (w)
{
case sProvider:
if (!m_dvb_service) return "";
return m_dvb_service->m_provider_name;
default:
- return "";
+ break;
+ }
+ return iServiceInformation::getInfoString(w);
+}
+
+PyObject *eDVBServicePlay::getInfoObject(int w)
+{
+ switch (w)
+ {
+ case sCAIDs:
+ return m_service_handler.getCaIds();
+ default:
+ break;
}
+ return iServiceInformation::getInfoObject(w);
}
int eDVBServicePlay::getNumberOfTracks()
{
eDVBServicePMTHandler::program program;
- if (m_service_handler.getProgramInfo(program))
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ if (h.getProgramInfo(program))
return 0;
return program.audioStreams.size();
}
RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
{
eDVBServicePMTHandler::program program;
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
- if (m_service_handler.getProgramInfo(program))
+ if (h.getProgramInfo(program))
return -1;
if (i >= program.audioStreams.size())
info.m_description = "MPEG";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
info.m_description = "AC3";
+ else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
+ info.m_description = "AAC";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
info.m_description = "DTS";
else
int eDVBServicePlay::selectAudioStream(int i)
{
eDVBServicePMTHandler::program program;
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
- if (m_service_handler.getProgramInfo(program))
+ if (h.getProgramInfo(program))
return -1;
if ((unsigned int)i >= program.audioStreams.size())
if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
return -4;
+ if (m_radiotext_parser)
+ m_radiotext_parser->start(program.audioStreams[i].pid);
+
if (m_dvb_service && !m_is_pvr)
{
if (program.audioStreams[i].type == eDVBAudio::aMPEG)
{
- m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
- m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
- } else
+ m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
+ m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
+ }
+ else
{
- m_dvb_service->setCachePID(eDVBService::cAPID, -1);
- m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
+ m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
+ m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
}
}
- m_current_audio_stream = i;
+ h.resetCachedProgram();
return 0;
}
-int eDVBServicePlay::getFrontendInfo(int w)
+int eDVBServicePlay::getCurrentChannel()
+{
+ return m_decoder ? m_decoder->getAudioChannel() : STEREO;
+}
+
+RESULT eDVBServicePlay::selectChannel(int i)
+{
+ if (i < LEFT || i > RIGHT || i == STEREO)
+ i = -1; // Stereo
+ if (m_dvb_service)
+ m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
+ if (m_decoder)
+ m_decoder->setAudioChannel(i);
+ return 0;
+}
+
+std::string eDVBServicePlay::getRadioText(int x)
+{
+ if (m_radiotext_parser)
+ switch(x)
+ {
+ case 0:
+ return convertLatin1UTF8(m_radiotext_parser->getCurrentText());
+ }
+ return "";
+}
+
+void eDVBServicePlay::radioTextUpdated()
+{
+ m_event((iPlayableService*)this, evUpdatedRadioText);
+}
+
+int eDVBServiceBase::getFrontendInfo(int w)
{
- if (m_is_pvr)
- return 0;
eUsePtr<iDVBChannel> channel;
if(m_service_handler.getChannel(channel))
return 0;
return fe->readFrontendData(w);
}
-PyObject *eDVBServicePlay::getFrontendData(bool original)
+PyObject *eDVBServiceBase::getFrontendData(bool original)
{
PyObject *ret=0;
return;
eDVBServicePMTHandler::program program;
- if (m_service_handler.getProgramInfo(program))
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+
+ if (h.getProgramInfo(program))
return;
else
{
m_cue = 0;
m_decoder = 0;
m_decode_demux = 0;
+ m_teletext_parser = 0;
+ m_radiotext_parser = 0;
+ m_subtitle_parser = 0;
+ m_new_dvb_subtitle_page_connection = 0;
+ m_new_subtitle_page_connection = 0;
+ m_radiotext_updated_connection = 0;
+
/* free the timeshift service handler, we need the resources */
m_service_handler_timeshift.free();
m_timeshift_active = 0;
-
+
m_event((iPlayableService*)this, evSeekableStatusChanged);
-
+
updateDecoder();
}
{
if (m_timeshift_active)
return;
-
+
m_decode_demux = 0;
m_decoder = 0;
-
+ m_teletext_parser = 0;
+ m_radiotext_parser = 0;
+ m_subtitle_parser = 0;
+ m_new_subtitle_page_connection = 0;
+ m_new_dvb_subtitle_page_connection = 0;
+ m_radiotext_updated_connection = 0;
+
m_timeshift_active = 1;
m_event((iPlayableService*)this, evSeekableStatusChanged);
-
+
eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
r.path = m_timeshift_file;
-
+
m_cue = new eCueSheet();
m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
updateDecoder(); /* mainly to switch off PCR */
void eDVBServicePlay::updateDecoder()
{
- int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
+ int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
+
eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ bool defaultac3=false;
+ std::string default_ac3;
+
+ if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
+ defaultac3 = default_ac3 == "True";
+
eDVBServicePMTHandler::program program;
if (h.getProgramInfo(program))
eDebug("getting program info failed.");
{
eDebugNoNewLine(" (");
for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
- i(program.videoStreams.begin());
+ i(program.videoStreams.begin());
i != program.videoStreams.end(); ++i)
{
if (vpid == -1)
+ {
vpid = i->pid;
+ vpidtype = i->type;
+ }
if (i != program.videoStreams.begin())
eDebugNoNewLine(", ");
eDebugNoNewLine("%04x", i->pid);
{
eDebugNoNewLine(" (");
for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
- i(program.audioStreams.begin());
+ i(program.audioStreams.begin());
i != program.audioStreams.end(); ++i)
{
- if (apid == -1)
+ if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
{
- apid = i->pid;
- apidtype = i->type;
+ if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
+ {
+ apid = i->pid;
+ apidtype = i->type;
+ }
}
if (i != program.audioStreams.begin())
eDebugNoNewLine(", ");
m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
if (m_cue)
m_cue->setDecodingDemux(m_decode_demux, m_decoder);
+ m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
+ m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
+ m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
+ m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
}
if (m_decoder)
{
- m_decoder->setVideoPID(vpid);
- m_current_audio_stream = 0;
+ if (m_dvb_service)
+ {
+ achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
+ ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
+ pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
+ }
+ else // subservice or recording
+ {
+ eServiceReferenceDVB ref;
+ m_service_handler.getServiceReference(ref);
+ eServiceReferenceDVB parent = ref.getParentServiceReference();
+ if (!parent)
+ parent = ref;
+ if (parent)
+ {
+ ePtr<eDVBResourceManager> res_mgr;
+ if (!eDVBResourceManager::getInstance(res_mgr))
+ {
+ ePtr<iDVBChannelList> db;
+ if (!res_mgr->getChannelList(db))
+ {
+ ePtr<eDVBService> origService;
+ if (!db->getService(parent, origService))
+ {
+ ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
+ pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
+ }
+ }
+ }
+ }
+ }
+ m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
+ m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
+
+ m_decoder->setVideoPID(vpid, vpidtype);
m_decoder->setAudioPID(apid, apidtype);
if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
+ {
m_decoder->setSyncPCR(pcrpid);
+ if (apid != -1)
+ {
+ ePtr<iDVBDemux> data_demux;
+ if (!h.getDataDemux(data_demux))
+ {
+ m_radiotext_parser = new eDVBRadioTextParser(data_demux);
+ m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection);
+ m_radiotext_parser->start(apid);
+ }
+ }
+ }
else
m_decoder->setSyncPCR(-1);
+
m_decoder->setTextPID(tpid);
+
+ m_teletext_parser->start(program.textPid);
+
if (!m_is_primary)
m_decoder->setTrickmode(1);
+
m_decoder->start();
+
+ if (vpid > 0 && vpid < 0x2000)
+ ;
+ else
+ {
+ std::string radio_pic;
+ if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
+ m_decoder->setRadioPic(radio_pic);
+ }
+
+ m_decoder->setAudioChannel(achannel);
+
// how we can do this better?
// update cache pid when the user changed the audio track or video track
// TODO handling of difference audio types.. default audio types..
{
if (apidtype == eDVBAudio::aMPEG)
{
- m_dvb_service->setCachePID(eDVBService::cAPID, apid);
- m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
+ m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
+ m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
}
else
{
- m_dvb_service->setCachePID(eDVBService::cAPID, -1);
- m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
+ m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
+ m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
}
- m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
- m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
- m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
+ m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
+ m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
+ m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
+ m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
}
}
+ m_have_video_pid = (vpid > 0 && vpid < 0x2000);
}
void eDVBServicePlay::loadCuesheet()
#endif
what = ntohl(what);
- if (what > 2)
+ if (what > 3)
break;
m_cue_entries.insert(cueEntry(where, what));
if (!m_cutlist_enabled)
{
m_cue->commitSpans();
- eDebug("cutlists where disabled");
+ eDebug("cutlists were disabled");
return;
}
continue;
} else if (i->what == 1) /* out */
out = i++->where;
- else /* mark */
+ else /* mark (2) or last play position (3) */
{
i++;
continue;
m_cue->commitSpans();
}
+RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *tuple)
+{
+ if (m_subtitle_widget)
+ disableSubtitles(parent);
+
+ PyObject *entry = 0;
+ int tuplesize = PyTuple_Size(tuple);
+ int type = 0;
+
+ if (!PyTuple_Check(tuple))
+ goto error_out;
+
+ if (tuplesize < 1)
+ goto error_out;
+
+ entry = PyTuple_GET_ITEM(tuple, 0);
+
+ if (!PyInt_Check(entry))
+ goto error_out;
+
+ type = PyInt_AsLong(entry);
+
+ if (type == 1) // teletext subtitles
+ {
+ int page, magazine, pid;
+ if (tuplesize < 4)
+ goto error_out;
+
+ if (!m_teletext_parser)
+ {
+ eDebug("enable teletext subtitles.. no parser !!!");
+ return -1;
+ }
+
+ entry = PyTuple_GET_ITEM(tuple, 1);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ pid = PyInt_AsLong(entry);
+
+ entry = PyTuple_GET_ITEM(tuple, 2);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ page = PyInt_AsLong(entry);
+
+ entry = PyTuple_GET_ITEM(tuple, 3);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ magazine = PyInt_AsLong(entry);
+
+ m_subtitle_widget = new eSubtitleWidget(parent);
+ m_subtitle_widget->resize(parent->size()); /* full size */
+ m_teletext_parser->setPageAndMagazine(page, magazine);
+ if (m_dvb_service)
+ m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE,((pid&0xFFFF)<<16)|((page&0xFF)<<8)|(magazine&0xFF));
+ }
+ else if (type == 0)
+ {
+ int pid = 0, composition_page_id = 0, ancillary_page_id = 0;
+ if (!m_subtitle_parser)
+ {
+ eDebug("enable dvb subtitles.. no parser !!!");
+ return -1;
+ }
+ if (tuplesize < 4)
+ goto error_out;
+
+ entry = PyTuple_GET_ITEM(tuple, 1);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ pid = PyInt_AsLong(entry);
+
+ entry = PyTuple_GET_ITEM(tuple, 2);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ composition_page_id = PyInt_AsLong(entry);
+
+ entry = PyTuple_GET_ITEM(tuple, 3);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ ancillary_page_id = PyInt_AsLong(entry);
+
+ m_subtitle_widget = new eSubtitleWidget(parent);
+ m_subtitle_widget->resize(parent->size()); /* full size */
+ m_subtitle_parser->start(pid, composition_page_id, ancillary_page_id);
+ if (m_dvb_service)
+ m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, ((pid&0xFFFF)<<16)|((composition_page_id&0xFF)<<8)|(ancillary_page_id&0xFF));
+ }
+ else
+ goto error_out;
+ return 0;
+error_out:
+ eDebug("enableSubtitles needs a tuple as 2nd argument!\n"
+ "for teletext subtitles (0, pid, teletext_page, teletext_magazine)\n"
+ "for dvb subtitles (1, pid, composition_page_id, ancillary_page_id)");
+ return -1;
+}
+
+RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
+{
+ delete m_subtitle_widget;
+ m_subtitle_widget = 0;
+ if (m_subtitle_parser)
+ {
+ m_subtitle_parser->stop();
+ m_dvb_subtitle_pages.clear();
+ }
+ if (m_teletext_parser)
+ {
+ m_teletext_parser->setPageAndMagazine(-1, -1);
+ m_subtitle_pages.clear();
+ }
+ if (m_dvb_service)
+ m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, -1);
+ return 0;
+}
+
+PyObject *eDVBServicePlay::getCachedSubtitle()
+{
+ if (m_dvb_service)
+ {
+ int tmp = m_dvb_service->getCacheEntry(eDVBService::cSUBTITLE);
+ if (tmp != -1)
+ {
+ unsigned int data = (unsigned int)tmp;
+ int pid = (data&0xFFFF0000)>>16;
+ PyObject *tuple = PyTuple_New(4);
+ eDVBServicePMTHandler::program program;
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ if (!h.getProgramInfo(program))
+ {
+ if (program.textPid==pid) // teletext
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
+ else
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong((data&0xFFFF0000)>>16)); // pid
+ PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
+ PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
+ return tuple;
+ }
+ }
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *eDVBServicePlay::getSubtitleList()
+{
+ if (!m_teletext_parser)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ PyObject *l = PyList_New(0);
+ std::set<int> added_ttx_pages;
+
+ std::set<eDVBServicePMTHandler::subtitleStream> &subs =
+ m_teletext_parser->m_found_subtitle_pages;
+
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ eDVBServicePMTHandler::program program;
+ if (h.getProgramInfo(program))
+ eDebug("getting program info failed.");
+ else
+ {
+ for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
+ it != program.subtitleStreams.end(); ++it)
+ {
+ switch(it->subtitling_type)
+ {
+ case 0x01: // ebu teletext subtitles
+ {
+ int page_number = it->teletext_page_number & 0xFF;
+ int magazine_number = it->teletext_magazine_number & 7;
+ int hash = magazine_number << 8 | page_number;
+ if (added_ttx_pages.find(hash) == added_ttx_pages.end())
+ {
+ PyObject *tuple = PyTuple_New(5);
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+ PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
+ PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
+ PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
+ PyList_Append(l, tuple);
+ Py_DECREF(tuple);
+ added_ttx_pages.insert(hash);
+ }
+ break;
+ }
+ case 0x10 ... 0x13:
+ case 0x20 ... 0x23: // dvb subtitles
+ {
+ PyObject *tuple = PyTuple_New(5);
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+ PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->composition_page_id));
+ PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->ancillary_page_id));
+ PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
+ PyList_Insert(l, 0, tuple);
+ Py_DECREF(tuple);
+ break;
+ }
+ }
+ }
+ }
+
+ for (std::set<eDVBServicePMTHandler::subtitleStream>::iterator it(subs.begin());
+ it != subs.end(); ++it)
+ {
+ int page_number = it->teletext_page_number & 0xFF;
+ int magazine_number = it->teletext_magazine_number & 7;
+ int hash = magazine_number << 8 | page_number;
+ if (added_ttx_pages.find(hash) == added_ttx_pages.end())
+ {
+ PyObject *tuple = PyTuple_New(5);
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+ PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
+ PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
+ PyTuple_SET_ITEM(tuple, 4, PyString_FromString("und")); // undetermined
+ PyList_Append(l, tuple);
+ Py_DECREF(tuple);
+ }
+ }
+
+ return l;
+}
+
+void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
+{
+ if (m_subtitle_widget)
+ {
+ m_subtitle_pages.push_back(page);
+ checkSubtitleTiming();
+ }
+}
+
+void eDVBServicePlay::checkSubtitleTiming()
+{
+// eDebug("checkSubtitleTiming");
+ if (!m_subtitle_widget)
+ return;
+ while (1)
+ {
+ enum { TELETEXT, DVB } type;
+ eDVBTeletextSubtitlePage page;
+ eDVBSubtitlePage dvb_page;
+ pts_t show_time;
+ if (!m_subtitle_pages.empty())
+ {
+ page = m_subtitle_pages.front();
+ type = TELETEXT;
+ show_time = page.m_pts;
+ }
+ else if (!m_dvb_subtitle_pages.empty())
+ {
+ dvb_page = m_dvb_subtitle_pages.front();
+ type = DVB;
+ show_time = dvb_page.m_show_time;
+ }
+ else
+ return;
+
+ pts_t pos = 0;
+
+ if (m_decoder)
+ m_decoder->getPTS(0, pos);
+
+// eDebug("%lld %lld", pos, show_time);
+ int diff = show_time - pos;
+ if (diff < 0)
+ {
+ eDebug("[late (%d ms)]", -diff / 90);
+ diff = 0;
+ }
+ if (diff > 900000)
+ {
+ eDebug("[invalid]");
+ diff = 0;
+ }
+
+ if (!diff)
+ {
+ if (type == TELETEXT)
+ {
+ eDebug("display teletext subtitle page");
+ m_subtitle_widget->setPage(page);
+ m_subtitle_pages.pop_front();
+ }
+ else
+ {
+ eDebug("display dvb subtitle Page");
+ m_subtitle_widget->setPage(dvb_page);
+ m_dvb_subtitle_pages.pop_front();
+ }
+ } else
+ {
+// eDebug("start subtitle delay %d", diff / 90);
+ m_subtitle_sync_timer.start(diff / 90, 1);
+ break;
+ }
+ }
+}
+
+void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
+{
+ if (m_subtitle_widget)
+ {
+ m_dvb_subtitle_pages.push_back(p);
+ checkSubtitleTiming();
+ }
+}
+
+int eDVBServicePlay::getAC3Delay()
+{
+ if (m_dvb_service)
+ return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
+ else if (m_decoder)
+ return m_decoder->getAC3Delay();
+ else
+ return 0;
+}
+
+int eDVBServicePlay::getPCMDelay()
+{
+ if (m_dvb_service)
+ return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
+ else if (m_decoder)
+ return m_decoder->getPCMDelay();
+ else
+ return 0;
+}
+
+void eDVBServicePlay::setAC3Delay(int delay)
+{
+ if (m_dvb_service)
+ m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
+ if (m_decoder)
+ m_decoder->setAC3Delay(delay);
+}
+
+void eDVBServicePlay::setPCMDelay(int delay)
+{
+ if (m_dvb_service)
+ m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
+ if (m_decoder)
+ m_decoder->setPCMDelay(delay);
+}
+
DEFINE_REF(eDVBServicePlay)
eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");