From 5d70fb1fa8db9464b4721f1beeb9f7e421b8308d Mon Sep 17 00:00:00 2001 From: ghost Date: Tue, 11 Aug 2009 19:28:32 +0200 Subject: [PATCH] add support for rds data on own pids (i.e. hitradio ffh, harmony fm) --- lib/dvb/pmt.cpp | 19 ++++++++++++++++++- lib/dvb/pmt.h | 4 ++-- lib/dvb/radiotext.cpp | 29 +++++++++++++++++++---------- lib/dvb/radiotext.h | 7 +++++-- lib/service/servicedvb.cpp | 17 +++++++++++------ 5 files changed, 55 insertions(+), 21 deletions(-) diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index fb81fa4c..a4fa212d 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -184,6 +184,8 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) int first_ac3 = -1; program.defaultAudioStream = 0; + int rdsPid = -1; + audioStream *prev_audio = 0; if ( m_service && !m_service->cacheEmpty() ) { @@ -215,13 +217,15 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es) { int isaudio = 0, isvideo = 0, issubtitle = 0, forced_video = 0, forced_audio = 0, isteletext = 0; + int streamtype = (*es)->getType(); videoStream video; audioStream audio; audio.component_tag=video.component_tag=-1; video.type = videoStream::vtMPEG2; audio.type = audioStream::atMPEG; + audio.rdsPid = -1; - switch ((*es)->getType()) + switch (streamtype) { case 0x1b: // AVC Video Stream (MPEG4 H264) video.type = videoStream::vtMPEG4_H264; @@ -285,11 +289,14 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) } case 0x06: // PES Private case 0xEA: // TS_PSI_ST_SMPTE_VC1 + { + int num_descriptors = 0; for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin(); desc != (*es)->getDescriptors()->end(); ++desc) { uint8_t tag = (*desc)->getTag(); /* check descriptors to get the exakt stream type. */ + ++num_descriptors; if (!forced_video && !forced_audio) { switch (tag) @@ -458,6 +465,13 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) break; } } + if (!num_descriptors && streamtype == 0x06 && prev_audio) + { + prev_audio->rdsPid = (*es)->getPid(); + eDebug("Rds PID %04x detected ? ! ?", prev_audio->rdsPid); + } + prev_audio = 0; + } default: break; } @@ -496,6 +510,7 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) first_ac3 = program.audioStreams.size(); program.audioStreams.push_back(audio); + prev_audio = &program.audioStreams.back(); } else continue; @@ -548,6 +563,7 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) audioStream s; s.type = audioStream::atAC3; s.pid = cached_apid_ac3; + s.rdsPid = -1; program.audioStreams.push_back(s); ++cnt; } @@ -556,6 +572,7 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program) audioStream s; s.type = audioStream::atMPEG; s.pid = cached_apid_mpeg; + s.rdsPid = -1; program.audioStreams.push_back(s); ++cnt; } diff --git a/lib/dvb/pmt.h b/lib/dvb/pmt.h index e27135e3..a9ca23f2 100644 --- a/lib/dvb/pmt.h +++ b/lib/dvb/pmt.h @@ -141,7 +141,8 @@ public: struct audioStream { - int pid; + int pid, + rdsPid; // hack for some radio services which transmit radiotext on different pid (i.e. harmony fm, HIT RADIO FFH, ...) enum { atMPEG, atAC3, atDTS, atAAC, atAACHE, atLPCM }; int type; // mpeg2, ac3, dts, ... @@ -188,7 +189,6 @@ public: int pmtPid; int textPid; bool isCrypted() { return !caids.empty(); } - PyObject *createPythonObject(); }; diff --git a/lib/dvb/radiotext.cpp b/lib/dvb/radiotext.cpp index 9f8cf5f0..e9bdd63a 100644 --- a/lib/dvb/radiotext.cpp +++ b/lib/dvb/radiotext.cpp @@ -5,9 +5,9 @@ DEFINE_REF(eDVBRdsDecoder); -eDVBRdsDecoder::eDVBRdsDecoder(iDVBDemux *demux) +eDVBRdsDecoder::eDVBRdsDecoder(iDVBDemux *demux, int type) :msgPtr(0), bsflag(0), qdar_pos(0), t_ptr(0), qdarmvi_show(0), state(0) - ,m_abortTimer(eTimer::create(eApp)) + ,m_type(type), m_pid(-1), m_abortTimer(eTimer::create(eApp)) { setStreamID(0xC0, 0xC0); @@ -16,8 +16,10 @@ eDVBRdsDecoder::eDVBRdsDecoder(iDVBDemux *demux) if (demux->createPESReader(eApp, m_pes_reader)) eDebug("failed to create PES reader!"); - else + else if (type == 0) m_pes_reader->connectRead(slot(*this, &eDVBRdsDecoder::processData), m_read_connection); + else + m_pes_reader->connectRead(slot(*this, &eDVBRdsDecoder::gotAncillaryData), m_read_connection); CONNECT(m_abortTimer->timeout, eDVBRdsDecoder::abortNonAvail); } @@ -196,7 +198,7 @@ void eDVBRdsDecoder::processPESPacket(__u8 *data, int len) m_abortTimer->stop(); int ancillary_len = 1 + data[offs - 1]; offs -= ancillary_len; - gotAncillaryData(data+offs, ancillary_len); + gotAncillaryData(data+offs, ancillary_len-1); } } } @@ -310,13 +312,19 @@ void eDVBRdsDecoder::process_qdar(unsigned char *buf) } } -inline void eDVBRdsDecoder::gotAncillaryData(__u8 *buf, int len) +void eDVBRdsDecoder::gotAncillaryData(const __u8 *buf, int len) { - int cnt=buf[--len]; - while ( cnt-- > 0 ) + if (len <= 0) + return; + int pos = m_type ? 0 : len-1; + while ( len ) { - unsigned char c = buf[--len]; - + unsigned char c = buf[pos]; + + pos += m_type ? 1 : -1; + + --len; + if (bsflag == 1) // byte stuffing { bsflag=2; @@ -638,8 +646,9 @@ std::string eDVBRdsDecoder::getRassPicture(int page, int subpage) int eDVBRdsDecoder::start(int pid) { int ret = -1; - if (m_pes_reader && !(ret = m_pes_reader->start(pid))) + if (m_pes_reader && !(ret = m_pes_reader->start(pid)) && m_type == 0) m_abortTimer->startLongTimer(20); + m_pid = pid; return ret; } diff --git a/lib/dvb/radiotext.h b/lib/dvb/radiotext.h index ace7b6ec..7a73eea3 100644 --- a/lib/dvb/radiotext.h +++ b/lib/dvb/radiotext.h @@ -18,9 +18,11 @@ class eDVBRdsDecoder: public iObject, public ePESParser, public Object unsigned char rass_picture_mask[5]; // 40 bits... (10 * 4 pictures) void addToPictureMask(int id); void removeFromPictureMask(int id); + int m_type; + int m_pid; public: enum { RadioTextChanged, RtpTextChanged, RassInteractivePicMaskChanged, RecvRassSlidePic }; - eDVBRdsDecoder(iDVBDemux *demux); + eDVBRdsDecoder(iDVBDemux *demux, int type); ~eDVBRdsDecoder(); int start(int pid); void connectEvent(const Slot1 &slot, ePtr &connection); @@ -29,10 +31,11 @@ public: ePyObject getRassPictureMask(); std::string getRassPicture(int page, int subpage); std::string getRassSlideshowPicture() { return "/tmp/RassLast.mvi"; } + int getPid() { return m_pid; } private: void abortNonAvail(); void processPESPacket(__u8 *pkt, int len); - inline void gotAncillaryData(__u8 *data, int len); + void gotAncillaryData(const __u8 *data, int len); void process_qdar(unsigned char*); ePtr m_pes_reader; ePtr m_read_connection; diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp index a75c6cac..d04039df 100644 --- a/lib/service/servicedvb.cpp +++ b/lib/service/servicedvb.cpp @@ -1758,21 +1758,26 @@ int eDVBServicePlay::selectAudioStream(int i) return -4; } + int rdsPid = apid; + /* if we are not in PVR mode, timeshift is not active and we are not in pip mode, check if we need to enable the rds reader */ if (!(m_is_pvr || m_timeshift_active || !m_is_primary)) - if (!m_rds_decoder) + { + int different_pid = program.videoStreams.empty() && program.audioStreams.size() == 1 && program.audioStreams[stream].rdsPid != -1; + if (different_pid) + rdsPid = program.audioStreams[stream].rdsPid; + if (!m_rds_decoder || m_rds_decoder->getPid() != rdsPid) { + m_rds_decoder = 0; ePtr data_demux; if (!h.getDataDemux(data_demux)) { - m_rds_decoder = new eDVBRdsDecoder(data_demux); + m_rds_decoder = new eDVBRdsDecoder(data_demux, different_pid); m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection); + m_rds_decoder->start(rdsPid); } } - - /* if we decided that we need one, update the pid */ - if (m_rds_decoder) - m_rds_decoder->start(apid); + } /* store new pid as default only when: a.) we have an entry in the service db for the current service, -- 2.30.2