X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/13fecd9a0a17ba5a02d3a9afa7e1e0067d3e1fec..df4309aea023598d3565a588440b2dc3c5c8eaad:/lib/dvb/pmt.cpp diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index 555ffa79..8e007f8d 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -1,3 +1,4 @@ +#include // access to python config #include #include #include @@ -6,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -14,7 +16,7 @@ #include #include #include -#include // access to python config +#include eDVBServicePMTHandler::eDVBServicePMTHandler() :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF) @@ -49,10 +51,13 @@ void eDVBServicePMTHandler::channelStateChanged(iDVBChannel *channel) { eDebug("ok ... now we start!!"); - if (m_pmt_pid == -1) - m_PAT.begin(eApp, eDVBPATSpec(), m_demux); - else - m_PMT.begin(eApp, eDVBPMTSpec(m_pmt_pid, m_reference.getServiceID().get()), m_demux); + if (!m_service || m_service->usePMT()) + { + if (m_pmt_pid == -1) + m_PAT.begin(eApp, eDVBPATSpec(), m_demux); + else + m_PMT.begin(eApp, eDVBPMTSpec(m_pmt_pid, m_reference.getServiceID().get()), m_demux); + } if ( m_service && !m_service->cacheEmpty() ) serviceEvent(eventNewProgramInfo); @@ -204,7 +209,7 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) { const ProgramMapSection &pmt = **i; program.pcrPid = pmt.getPcrPid(); - + ElementaryStreamInfoConstIterator es; for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es) { @@ -213,32 +218,85 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) audioStream audio; audio.component_tag=video.component_tag=-1; video.type = videoStream::vtMPEG2; + audio.type = audioStream::atMPEG; switch ((*es)->getType()) { case 0x1b: // AVC Video Stream (MPEG4 H264) video.type = videoStream::vtMPEG4_H264; + isvideo = 1; + //break; fall through !!! + case 0x10: // MPEG 4 Part 2 + if (!isvideo) + { + video.type = videoStream::vtMPEG4_Part2; + isvideo = 1; + } + //break; fall through !!! case 0x01: // MPEG 1 video + if (!isvideo) + video.type = videoStream::vtMPEG1; + //break; fall through !!! case 0x02: // MPEG 2 video isvideo = 1; //break; fall through !!! case 0x03: // MPEG 1 audio case 0x04: // MPEG 2 audio: if (!isvideo) + isaudio = 1; + //break; fall through !!! + case 0x0f: // MPEG 2 AAC + if (!isvideo && !isaudio) { isaudio = 1; - audio.type = audioStream::atMPEG; + audio.type = audioStream::atAAC; } //break; fall through !!! + case 0x11: // MPEG 4 AAC + if (!isvideo && !isaudio) + { + isaudio = 1; + audio.type = audioStream::atAACHE; + } + case 0x80: // user private ... but blueray LPCM + if (!isvideo && !isaudio) + { + isaudio = 1; + audio.type = audioStream::atLPCM; + } + case 0x81: // user private ... but blueray AC3 + if (!isvideo && !isaudio) + { + isaudio = 1; + audio.type = audioStream::atAC3; + } + case 0x82: // Blueray DTS (dvb user private...) + case 0xA2: // Blueray secondary DTS + if (!isvideo && !isaudio) + { + isaudio = 1; + audio.type = audioStream::atDTS; + } case 0x06: // PES Private - case 0x81: // user private - /* PES private can contain AC-3, DTS or lots of other stuff. - check descriptors to get the exact type. */ + case 0xEA: // TS_PSI_ST_SMPTE_VC1 for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin(); desc != (*es)->getDescriptors()->end(); ++desc) { - switch ((*desc)->getTag()) + uint8_t tag = (*desc)->getTag(); + /* check descriptors to get the exakt stream type. */ + switch (tag) + { + case AUDIO_STREAM_DESCRIPTOR: + isaudio = 1; + break; + case VIDEO_STREAM_DESCRIPTOR: { + isvideo = 1; + VideoStreamDescriptor *d = (VideoStreamDescriptor*)(*desc); + if (d->getMpeg1OnlyFlag()) + video.type = videoStream::vtMPEG1; + break; + } case SUBTITLING_DESCRIPTOR: { SubtitlingDescriptor *d = (SubtitlingDescriptor*)(*desc); @@ -248,6 +306,17 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) for (SubtitlingConstIterator it(list->begin()); it != list->end(); ++it) { s.subtitling_type = (*it)->getSubtitlingType(); + switch(s.subtitling_type) + { + case 0x10 ... 0x13: + case 0x20 ... 0x23: // dvb subtitles + break; + default: + eDebug("dvb subtitle %s PID %04x with wrong subtitling type (%02x)... force 0x10!!", + s.language_code.c_str(), s.pid, s.subtitling_type); + s.subtitling_type = 0x10; + break; + } s.composition_page_id = (*it)->getCompositionPageId(); s.ancillary_page_id = (*it)->getAncillaryPageId(); s.language_code = (*it)->getIso639LanguageCode(); @@ -269,15 +338,15 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) { switch((*it)->getTeletextType()) { - case 0x02: // Teletext subtitle page - case 0x05: // Teletext subtitle page for hearing impaired pepople - s.language_code = (*it)->getIso639LanguageCode(); - s.teletext_page_number = (*it)->getTeletextPageNumber(); - s.teletext_magazine_number = (*it)->getTeletextMagazineNumber(); -// eDebug("add teletext subtitle %s PID %04x, page number %d, magazine number %d", -// s.language_code.c_str(), s.pid, s.teletext_page_number, s.teletext_magazine_number); - program.subtitleStreams.push_back(s); - break; + case 0x02: // Teletext subtitle page + case 0x05: // Teletext subtitle page for hearing impaired pepople + s.language_code = (*it)->getIso639LanguageCode(); + s.teletext_page_number = (*it)->getTeletextPageNumber(); + s.teletext_magazine_number = (*it)->getTeletextMagazineNumber(); +// eDebug("add teletext subtitle %s PID %04x, page number %d, magazine number %d", +// s.language_code.c_str(), s.pid, s.teletext_page_number, s.teletext_magazine_number); + program.subtitleStreams.push_back(s); + break; } } } @@ -286,21 +355,77 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) isaudio = 1; audio.type = audioStream::atDTS; break; + case 0x2B: // TS_PSI_DT_MPEG2_AAC + isaudio = 1; + audio.type = audioStream::atAAC; // MPEG2-AAC + break; + case 0x1C: // TS_PSI_DT_MPEG4_Audio case AAC_DESCRIPTOR: isaudio = 1; - audio.type = audioStream::atAAC; + audio.type = audioStream::atAACHE; // MPEG4-AAC break; case AC3_DESCRIPTOR: isaudio = 1; audio.type = audioStream::atAC3; break; + case REGISTRATION_DESCRIPTOR: /* some services don't have a separate AC3 descriptor */ + { + /* libdvbsi++ doesn't yet support this descriptor type, so work around. */ + if ((*desc)->getLength() < 4) + break; + unsigned char descr[6]; + (*desc)->writeToBuffer(descr); + int format_identifier = (descr[2] << 24) | (descr[3] << 16) | (descr[4] << 8) | (descr[5]); + switch (format_identifier) + { + case 0x44545331 ... 0x44545333: // DTS1/DTS2/DTS3 + isaudio = 1; + audio.type = audioStream::atDTS; + break; + case 0x41432d33: // == 'AC-3' + isaudio = 1; + audio.type = audioStream::atAC3; + break; + case 0x42535344: // == 'BSSD' (LPCM) + isaudio = 1; + audio.type = audioStream::atLPCM; + break; + case 0x56432d31: // == 'VC-1' + if (descr[6] == 0x01) // subdescriptor tag + { + if (descr[7] >= 0x90) // profile_level + video.type = videoStream::vtVC1; // advanced profile + else + video.type = videoStream::vtVC1_SM; // simple main + isvideo = 1; + } + break; + default: + break; + } + break; + } + case 0x28: // TS_PSI_DT_AVC + isvideo = 1; + video.type = videoStream::vtMPEG4_H264; + break; + case 0x1B: // TS_PSI_DT_MPEG4_Video + isvideo = 1; + video.type = videoStream::vtMPEG4_Part2; + break; case ISO_639_LANGUAGE_DESCRIPTOR: if (!isvideo) { + int cnt=0; const Iso639LanguageList *languages = ((Iso639LanguageDescriptor*)*desc)->getIso639Languages(); /* use last language code */ - for (Iso639LanguageConstIterator i(languages->begin()); i != languages->end(); ++i) - audio.language_code = (*i)->getIso639LanguageCode(); + for (Iso639LanguageConstIterator i(languages->begin()); i != languages->end(); ++i, ++cnt) + { + if (cnt == 0) + audio.language_code = (*i)->getIso639LanguageCode(); + else + audio.language_code += "/" + (*i)->getIso639LanguageCode(); + } } break; case STREAM_IDENTIFIER_DESCRIPTOR: @@ -314,28 +439,10 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) program.caids.insert(descr->getCaSystemId()); break; } - case REGISTRATION_DESCRIPTOR: /* some services don't have a separate AC3 descriptor */ - { - /* libdvbsi++ doesn't yet support this descriptor type, so work around. */ - if ((*desc)->getLength() != 4) - break; - unsigned char descr[6]; - (*desc)->writeToBuffer(descr); - int format_identifier = (descr[2] << 24) | (descr[3] << 16) | (descr[4] << 8) | (descr[5]); - switch (format_identifier) - { - case 0x41432d33: - isaudio = 1; - audio.type = audioStream::atAC3; - break; - default: - break; - } + default: break; } - } } - break; } if (isaudio) { @@ -502,8 +609,15 @@ void eDVBServicePMTHandler::SDTScanEvent(int event) eDebug("no channel list"); else { - m_dvb_scan->insertInto(db, true); - eDebug("sdt update done!"); + eDVBChannelID chid; + m_reference.getChannelID(chid); + if (chid == m_dvb_scan->getCurrentChannelID()) + { + m_dvb_scan->insertInto(db, true); + eDebug("sdt update done!"); + } + else + eDebug("ignore sdt update data.... incorrect transponder tuned!!!"); } break; } @@ -513,28 +627,32 @@ void eDVBServicePMTHandler::SDTScanEvent(int event) } } -int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux, eCueSheet *cue) +int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux, eCueSheet *cue, bool simulate, eDVBService *service) { - RESULT res; + RESULT res=0; m_reference = ref; m_use_decode_demux = use_decode_demux; + + /* use given service as backup. This is used for timeshift where we want to clone the live stream using the cache, but in fact have a PVR channel */ + m_service = service; /* is this a normal (non PVR) channel? */ if (ref.path.empty()) { eDVBChannelID chid; ref.getChannelID(chid); - res = m_resourceManager->allocateChannel(chid, m_channel); - eDebug("allocate Channel: res %d", res); + res = m_resourceManager->allocateChannel(chid, m_channel, simulate); + if (!simulate) + eDebug("allocate Channel: res %d", res); ePtr db; if (!m_resourceManager->getChannelList(db)) - db->getService((eServiceReferenceDVB&)m_reference, m_service); + db->getService((eServiceReferenceDVB&)m_reference, m_service); - if (!res) + if (!res && !simulate) eDVBCIInterfaces::getInstance()->addPMTHandler(this); - } else + } else if (!simulate) // no simulation of playback services { eDVBMetaParser parser; @@ -566,37 +684,40 @@ int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux, m_channel = m_pvr_channel; } - if (m_channel) + if (!simulate) { - m_channel->connectStateChange( - slot(*this, &eDVBServicePMTHandler::channelStateChanged), - m_channelStateChanged_connection); - m_last_channel_state = -1; - channelStateChanged(m_channel); - - m_channel->connectEvent( - slot(*this, &eDVBServicePMTHandler::channelEvent), - m_channelEvent_connection); + if (m_channel) + { + m_channel->connectStateChange( + slot(*this, &eDVBServicePMTHandler::channelStateChanged), + m_channelStateChanged_connection); + m_last_channel_state = -1; + channelStateChanged(m_channel); + + m_channel->connectEvent( + slot(*this, &eDVBServicePMTHandler::channelEvent), + m_channelEvent_connection); - if (ref.path.empty()) + if (ref.path.empty()) + { + m_dvb_scan = 0; + m_dvb_scan = new eDVBScan(m_channel, true, false); + m_dvb_scan->connectEvent(slot(*this, &eDVBServicePMTHandler::SDTScanEvent), m_scan_event_connection); + } + } else { - delete m_dvb_scan; - m_dvb_scan = new eDVBScan(m_channel, false, false); - m_dvb_scan->connectEvent(slot(*this, &eDVBServicePMTHandler::SDTScanEvent), m_scan_event_connection); + if (res == eDVBResourceManager::errAllSourcesBusy) + serviceEvent(eventNoResources); + else /* errChidNotFound, errNoChannelList, errChannelNotInList, errNoSourceFound */ + serviceEvent(eventMisconfiguration); + return res; } - } else - { - if (res == eDVBResourceManager::errAllSourcesBusy) - serviceEvent(eventNoResources); - else /* errChidNotFound, errNoChannelList, errChannelNotInList, errNoSourceFound */ - serviceEvent(eventMisconfiguration); - return res; - } - if (m_pvr_channel) - { - m_pvr_channel->setCueSheet(cue); - m_pvr_channel->playFile(ref.path.c_str()); + if (m_pvr_channel) + { + m_pvr_channel->setCueSheet(cue); + m_pvr_channel->playFile(ref.path.c_str()); + } } return res; @@ -605,7 +726,6 @@ int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux, void eDVBServicePMTHandler::free() { m_dvb_scan = 0; - delete m_dvb_scan; if (m_ca_servicePtr) { @@ -631,6 +751,7 @@ void eDVBServicePMTHandler::free() m_pvr_channel->stopFile(); m_pvr_channel->setCueSheet(0); } + m_PMT.stop(); m_PAT.stop(); m_service = 0; @@ -644,10 +765,10 @@ ChannelMap eDVBCAService::exist_channels; ePtr eDVBCAService::m_chanAddedConn; eDVBCAService::eDVBCAService() - :m_sn(0), m_prev_build_hash(0), m_sendstate(0), m_retryTimer(eApp) + :m_buffer(512), m_prev_build_hash(0), m_sendstate(0), m_retryTimer(eTimer::create(eApp)) { memset(m_used_demux, 0xFF, sizeof(m_used_demux)); - CONNECT(m_retryTimer.timeout, eDVBCAService::sendCAPMT); + CONNECT(m_retryTimer->timeout, eDVBCAService::sendCAPMT); Connect(); } @@ -655,7 +776,6 @@ eDVBCAService::~eDVBCAService() { eDebug("[eDVBCAService] free service %s", m_service.toString().c_str()); ::close(m_sock); - delete m_sn; } // begin static methods @@ -832,27 +952,105 @@ channel_data *eDVBCAService::getChannelData(eDVBChannelID &chid) } // end static methods +#define CA_REPLY_DEBUG +#define MAX_LENGTH_BYTES 4 +#define MIN_LENGTH_BYTES 1 + void eDVBCAService::socketCB(int what) { - if (what & eSocketNotifier::Read) - /*eDebug("[eDVBCAService] data to read\n")*/; - if (what & eSocketNotifier::Priority) - /*eDebug("[eDVBCAService] priority data to read\n")*/; + if (what & (eSocketNotifier::Read | eSocketNotifier::Priority)) + { + char msgbuffer[4096]; + ssize_t length = read(m_sock, msgbuffer, sizeof(msgbuffer)); + if (length == -1) + { + if (errno != EAGAIN && errno != EINTR && errno != EBUSY) + { + eDebug("[eSocketMMIHandler] read (%m)"); + what |= eSocketNotifier::Error; + } + } else if (length == 0) + { + what |= eSocketNotifier::Hungup; + } else + { + int len = length; + unsigned char *data = (unsigned char*)msgbuffer; + int clear = 1; + // If a new message starts, then the previous message + // should already have been processed. Otherwise the + // previous message was incomplete and should therefore + // be deleted. + if ((len >= 1) && ((data[0] & 0xFF) != 0x9f)) + clear = 0; + if ((len >= 2) && ((data[1] & 0x80) != 0x80)) + clear = 0; + if ((len >= 3) && ((data[2] & 0x80) != 0x00)) + clear = 0; + if (clear) + { + m_buffer.clear(); +#ifdef CA_REPLY_DEBUG + eDebug("clear buffer"); +#endif + } +#ifdef CA_REPLY_DEBUG + eDebug("Put to buffer:"); + for (int i=0; i < len; ++i) + eDebugNoNewLine("%02x ", data[i]); + eDebug("\n--------"); +#endif + m_buffer.write( data, len ); + + while ( m_buffer.size() >= (3 + MIN_LENGTH_BYTES) ) + { + unsigned char tmp[3+MAX_LENGTH_BYTES]; + m_buffer.peek(tmp, 3+MIN_LENGTH_BYTES); + if (((tmp[0] & 0xFF) != 0x9f) || ((tmp[1] & 0x80) != 0x80) || ((tmp[2] & 0x80) != 0x00)) + { + m_buffer.skip(1); +#ifdef CA_REPLY_DEBUG + eDebug("skip %02x", tmp[0]); +#endif + continue; + } + if (tmp[3] & 0x80) + { + int peekLength = (tmp[3] & 0x7f) + 4; + if (m_buffer.size() < peekLength) + continue; + m_buffer.peek(tmp, peekLength); + } + int size=0; + int LengthBytes=eDVBCISession::parseLengthField(tmp+3, size); + int messageLength = 3+LengthBytes+size; + if ( m_buffer.size() >= messageLength ) + { + unsigned char dest[messageLength]; + m_buffer.read(dest, messageLength); +#ifdef CA_REPLY_DEBUG + eDebug("dump ca reply:"); + for (int i=0; i < messageLength; ++i) + eDebugNoNewLine("%02x ", dest[i]); + eDebug("\n--------"); +#endif +// /*emit*/ mmi_progress(0, dest, (const void*)(dest+3+LengthBytes), messageLength-3-LengthBytes); + } + } + } + } if (what & eSocketNotifier::Hungup) { - /*eDebug("[eDVBCAService] connection closed\n")*/; + /*eDebug("[eDVBCAService] connection closed")*/; m_sendstate=1; sendCAPMT(); } if (what & eSocketNotifier::Error) - /*eDebug("[eDVBCAService] connection error\n")*/; + eDebug("[eDVBCAService] connection error"); } void eDVBCAService::Connect() { - if (m_sn) { - delete m_sn; - m_sn=0; - } + m_sn=0; memset(&m_servaddr, 0, sizeof(struct sockaddr_un)); m_servaddr.sun_family = AF_UNIX; strcpy(m_servaddr.sun_path, "/tmp/camd.socket"); @@ -865,7 +1063,7 @@ void eDVBCAService::Connect() int val=1; fcntl(m_sock, F_SETFL, O_NONBLOCK); setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, &val, 4); - m_sn = new eSocketNotifier(eApp, m_sock, + m_sn = eSocketNotifier::create(eApp, m_sock, eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Error|eSocketNotifier::Hungup); CONNECT(m_sn->activated, eDVBCAService::socketCB); @@ -1017,11 +1215,11 @@ void eDVBCAService::sendCAPMT() { case 0xFFFFFFFF: ++m_sendstate; - m_retryTimer.start(0,true); + m_retryTimer->start(0,true); // eDebug("[eDVBCAService] send failed .. immediate retry"); break; default: - m_retryTimer.start(5000,true); + m_retryTimer->start(5000,true); // eDebug("[eDVBCAService] send failed .. retry in 5 sec"); break; } @@ -1032,8 +1230,8 @@ void eDVBCAService::sendCAPMT() static PyObject *createTuple(int pid, const char *type) { PyObject *r = PyTuple_New(2); - PyTuple_SetItem(r, 0, PyInt_FromLong(pid)); - PyTuple_SetItem(r, 1, PyString_FromString(type)); + PyTuple_SET_ITEM(r, 0, PyInt_FromLong(pid)); + PyTuple_SET_ITEM(r, 1, PyString_FromString(type)); return r; } @@ -1043,17 +1241,18 @@ static inline void PyList_AppendSteal(PyObject *list, PyObject *item) Py_DECREF(item); } +extern void PutToDict(ePyObject &dict, const char*key, ePyObject item); // defined in dvb/frontend.cpp + PyObject *eDVBServicePMTHandler::program::createPythonObject() { - PyObject *r = PyDict_New(); + ePyObject r = PyDict_New(); + ePyObject l = PyList_New(0); - PyObject *l = PyList_New(0); - PyList_AppendSteal(l, createTuple(0, "pat")); if (pmtPid != -1) PyList_AppendSteal(l, createTuple(pmtPid, "pmt")); - + for (std::vector::const_iterator i(videoStreams.begin()); i != videoStreams.end(); ++i) @@ -1073,7 +1272,8 @@ PyObject *eDVBServicePMTHandler::program::createPythonObject() if (textPid != -1) PyList_AppendSteal(l, createTuple(textPid, "text")); - - PyDict_SetItemString(r, "pids", l); + + PutToDict(r, "pids", l); + return r; }