From 8a3e426abad81aecada3e5e5de204092aeb7d074 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Wed, 5 Dec 2012 05:42:54 +0100 Subject: [PATCH 01/12] vdr-plugin-vnsiserver: drop incomplete and needless lookup table for pmt stream types --- .../vdr-plugin-vnsiserver/receiver.c | 50 +++++-------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c index 2a2627c62..2bdbab542 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c @@ -117,30 +117,6 @@ cLivePatFilter::cLivePatFilter(cLiveStreamer *Streamer, const cChannel *Channel) } -static const char * const psStreamTypes[] = { - "UNKNOWN", - "ISO/IEC 11172 Video", - "ISO/IEC 13818-2 Video", - "ISO/IEC 11172 Audio", - "ISO/IEC 13818-3 Audio", - "ISO/IEC 13818-1 Privete sections", - "ISO/IEC 13818-1 Private PES data", - "ISO/IEC 13512 MHEG", - "ISO/IEC 13818-1 Annex A DSM CC", - "0x09", - "ISO/IEC 13818-6 Multiprotocol encapsulation", - "ISO/IEC 13818-6 DSM-CC U-N Messages", - "ISO/IEC 13818-6 Stream Descriptors", - "ISO/IEC 13818-6 Sections (any type, including private data)", - "ISO/IEC 13818-1 auxiliary", - "ISO/IEC 13818-7 Audio with ADTS transport sytax", - "ISO/IEC 14496-2 Visual (MPEG-4)", - "ISO/IEC 14496-3 Audio with LATM transport syntax", - "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1a", - "ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264)", - "", -}; - void cLivePatFilter::GetLanguage(SI::PMT::Stream& stream, char *langs) { SI::Descriptor *d; @@ -180,20 +156,20 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan case 0x01: // ISO/IEC 11172 Video case 0x02: // ISO/IEC 13818-2 Video case 0x80: // ATSC Video MPEG2 (ATSC DigiCipher QAM) - DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%s)\n", stream.getPid(), psStreamTypes[stream.getStreamType()]); + DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d)\n", stream.getPid(), stream.getStreamType()); *type = stMPEG2VIDEO; return stream.getPid(); case 0x03: // ISO/IEC 11172 Audio case 0x04: // ISO/IEC 13818-3 Audio *type = stMPEG2AUDIO; GetLanguage(stream, langs); - DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%s) (%s)\n", stream.getPid(), psStreamTypes[stream.getStreamType()], langs); + DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d) (%s)\n", stream.getPid(), stream.getStreamType(), langs); return stream.getPid(); case 0x0f: // ISO/IEC 13818-7 Audio with ADTS transport syntax case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax *type = stAAC; GetLanguage(stream, langs); - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s (%s)\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "AAC", langs); + DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AAC", langs); return stream.getPid(); #if 1 case 0x07: // ISO/IEC 13512 MHEG @@ -205,10 +181,10 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan case 0x0e: // ISO/IEC 13818-1 auxiliary #endif case 0x10: // ISO/IEC 14496-2 Visual (MPEG-4) - DEBUGLOG("cStreamdevPatFilter PMT scanner: Not adding PID %d (%s) (skipped)\n", stream.getPid(), psStreamTypes[stream.getStreamType()]); + DEBUGLOG("cStreamdevPatFilter PMT scanner: Not adding PID %d (%d) (skipped)\n", stream.getPid(), stream.getStreamType()); break; case 0x1b: // ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264) - DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%s)\n", stream.getPid(), psStreamTypes[stream.getStreamType()]); + DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d)\n", stream.getPid(), stream.getStreamType()); *type = stH264; return stream.getPid(); case 0x05: // ISO/IEC 13818-1 private sections @@ -218,31 +194,31 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan switch (d->getDescriptorTag()) { case SI::AC3DescriptorTag: - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s (%s)\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "AC3", langs); + DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AC3", langs); *type = stAC3; GetLanguage(stream, langs); delete d; return stream.getPid(); case SI::EnhancedAC3DescriptorTag: - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s (%s)\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "EAC3", langs); + DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "EAC3", langs); *type = stEAC3; GetLanguage(stream, langs); delete d; return stream.getPid(); case SI::DTSDescriptorTag: - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s (%s)\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "DTS", langs); + DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "DTS", langs); *type = stDTS; GetLanguage(stream, langs); delete d; return stream.getPid(); case SI::AACDescriptorTag: - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s (%s)\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "AAC", langs); + DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AAC", langs); *type = stAAC; GetLanguage(stream, langs); delete d; return stream.getPid(); case SI::TeletextDescriptorTag: - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "Teletext"); + DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s\n", stream.getPid(), stream.getStreamType(), "Teletext"); *type = stTELETEXT; delete d; return stream.getPid(); @@ -273,11 +249,11 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan } } delete d; - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "DVBSUB"); + DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s\n", stream.getPid(), stream.getStreamType(), "DVBSUB"); return stream.getPid(); } default: - DEBUGLOG("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s (%i)\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "UNKNOWN", d->getDescriptorTag()); + DEBUGLOG("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%d) %s (%i)\n", stream.getPid(), stream.getStreamType(), "UNKNOWN", d->getDescriptorTag()); break; } delete d; @@ -324,7 +300,7 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan DEBUGLOG("NOT adding PID %d (type 0x%x) RegDesc not found -> UNKNOWN\n", stream.getPid(), stream.getStreamType()); } } - DEBUGLOG("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()<0x1c?stream.getStreamType():0], "UNKNOWN"); + DEBUGLOG("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%d) %s\n", stream.getPid(), stream.getStreamType(), "UNKNOWN"); break; } *type = stNone; From 354045f273e5534b7076eb9141b3df538cc69e96 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Wed, 5 Dec 2012 06:00:42 +0100 Subject: [PATCH 02/12] vdr-plugin-vnsiserver: adopt AAC patch from tvheadend: https://github.com/tvheadend/tvheadend/commit/3e3a197fa55e6e2850375822fb6e8a1dcbf96385 --- .../vdr-plugin-vnsiserver/demuxer_AAC.c | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c index c8a7e6e6b..33639fdf0 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c @@ -257,19 +257,34 @@ void cParserAAC::ReadStreamMuxConfig(cBitstream *bs) void cParserAAC::ReadAudioSpecificConfig(cBitstream *bs) { + int sr; int aot = bs->readBits(5); - if (aot != 2) - return; + static const int sample_rates[16] = { + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000, 7350 + }; m_SampleRateIndex = bs->readBits(4); if (m_SampleRateIndex == 0xf) - return; + sr = bs->readBits(24); + else + sr = sample_rates[m_SampleRateIndex & 0xf]; m_SampleRate = aac_sample_rates[m_SampleRateIndex]; m_FrameDuration = 1024 * 90000 / m_SampleRate; m_ChannelConfig = bs->readBits(4); + if (aot == 5) { // AOT_SBR + if (bs->readBits(4) == 0xf) { // extensionSamplingFrequencyIndex + bs->skipBits(24); + } + aot = bs->readBits(5); // this is the main object type (i.e. non-extended) + } + + if(aot != 2) + return; + bs->skipBits(1); //framelen_flag if (bs->readBits1()) // depends_on_coder bs->skipBits(14); From 05620ce6264d2953ac86caec32e1f3cf4a978de2 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Wed, 5 Dec 2012 07:20:04 +0100 Subject: [PATCH 03/12] vdr-plugin-vnsiserver: open demuxer for EAC3 --- .../pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c index 2bdbab542..9f4275f56 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c @@ -1081,6 +1081,11 @@ void cLiveStreamer::ensureDemuxers() demuxer = new cTSDemuxer(this, stAC3, it->pID); demuxer->SetLanguage(it->language); } + else if (it->type == stEAC3) + { + demuxer = new cTSDemuxer(this, stEAC3, it->pID); + demuxer->SetLanguage(it->language); + } else if (it->type == stDVBSUB) { demuxer = new cTSDemuxer(this, stDVBSUB, it->pID); @@ -1150,6 +1155,10 @@ void cLiveStreamer::confChannelDemuxers() { newStream.pID = *APids; newStream.type = stMPEG2AUDIO; +#if APIVERSNUM >= 10715 + if (m_Channel->Atype(index) == 0x0F || m_Channel->Atype(index) == 0x11) + newStream.type = stAAC; +#endif newStream.SetLanguage(m_Channel->Alang(index)); AddStream(newStream); } @@ -1164,6 +1173,10 @@ void cLiveStreamer::confChannelDemuxers() { newStream.pID = *DPids; newStream.type = stAC3; +#if APIVERSNUM >= 10715 + if (m_Channel->Dtype(index) == SI::EnhancedAC3DescriptorTag) + newStream.type = stEAC3; +#endif newStream.SetLanguage(m_Channel->Dlang(index)); AddStream(newStream); } From a8c28e5ec75aabc50ca88103ecd66040130bb018 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Wed, 5 Dec 2012 10:12:13 +0100 Subject: [PATCH 04/12] vdr-plugin-vnsiserver: align pmt filter with method in vdr --- .../vdr-plugin-vnsiserver/receiver.c | 93 +++++++++++-------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c index 9f4275f56..d80f603a1 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c @@ -126,6 +126,7 @@ void cLivePatFilter::GetLanguage(SI::PMT::Stream& stream, char *langs) { case SI::ISO639LanguageDescriptorTag: { + langs[MAXLANGCODE1] = 0; SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; strn0cpy(langs, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1); break; @@ -155,7 +156,6 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan { case 0x01: // ISO/IEC 11172 Video case 0x02: // ISO/IEC 13818-2 Video - case 0x80: // ATSC Video MPEG2 (ATSC DigiCipher QAM) DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d)\n", stream.getPid(), stream.getStreamType()); *type = stMPEG2VIDEO; return stream.getPid(); @@ -165,7 +165,7 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan GetLanguage(stream, langs); DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d) (%s)\n", stream.getPid(), stream.getStreamType(), langs); return stream.getPid(); - case 0x0f: // ISO/IEC 13818-7 Audio with ADTS transport syntax + case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax *type = stAAC; GetLanguage(stream, langs); @@ -232,6 +232,7 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan SI::SubtitlingDescriptor *sd = (SI::SubtitlingDescriptor *)d; SI::SubtitlingDescriptor::Subtitling sub; char *s = langs; + s[MAXLANGCODE1] = 0; int n = 0; for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) { @@ -259,47 +260,65 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan delete d; } break; - default: - /* This following section handles all the cases where the audio track - * info is stored in PMT user info with stream id >= 0x81 - * we check the registration format identifier to see if it - * holds "AC-3" - */ - if (stream.getStreamType() >= 0x81) + case 0x80: + if (Setup.StandardCompliance == STANDARD_ANSISCTE) + { // DigiCipher II VIDEO (ANSI/SCTE 57) + DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d)\n", stream.getPid(), stream.getStreamType()); + *type = stMPEG2VIDEO; + return stream.getPid(); + } + // fall through + case 0x81: // STREAMTYPE_USER_PRIVATE + if (Setup.StandardCompliance == STANDARD_ANSISCTE) + { // ATSC A/53 AUDIO (ANSI/SCTE 57) + DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AC3", langs); + *type = stAC3; + GetLanguage(stream, langs); + return stream.getPid(); + } + // fall through + case 0x83 ... 0xFF: // STREAMTYPE_USER_PRIVATE { - bool found = false; - for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) + bool IsAc3 = false; + langs[MAXLANGCODE1] = 0; + SI::Descriptor *d; + for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) + { + switch (d->getDescriptorTag()) { - switch (d->getDescriptorTag()) - { - case SI::RegistrationDescriptorTag: - /* unfortunately libsi does not implement RegistrationDescriptor */ - if (d->getLength() >= 4) + case SI::RegistrationDescriptorTag: { - found = true; - SI::CharArray rawdata = d->getData(); - if (/*rawdata[0] == 5 && rawdata[1] >= 4 && */ - rawdata[2] == 'A' && rawdata[3] == 'C' && - rawdata[4] == '-' && rawdata[5] == '3') - { - DEBUGLOG("cStreamdevPatFilter PMT scanner: Adding pid %d (type 0x%x) RegDesc len %d (%c%c%c%c)\n", - stream.getPid(), stream.getStreamType(), d->getLength(), rawdata[2], rawdata[3], rawdata[4], rawdata[5]); - *type = stAC3; - delete d; - return stream.getPid(); - } + SI::RegistrationDescriptor *rd = (SI::RegistrationDescriptor *)d; + // http://www.smpte-ra.org/mpegreg/mpegreg.html + switch (rd->getFormatIdentifier()) + { + case 0x41432D33: // 'AC-3' + IsAc3 = true; + break; + default: + break; + } } break; - default: + case SI::ISO639LanguageDescriptorTag: + { + SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; + strn0cpy(langs, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1); + } break; - } - delete d; - } - if (!found) - { - DEBUGLOG("NOT adding PID %d (type 0x%x) RegDesc not found -> UNKNOWN\n", stream.getPid(), stream.getStreamType()); + default: ; } + delete d; } + if (IsAc3) + { + DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AC3", langs); + *type = stAC3; + return stream.getPid(); + } + } + break; + default: DEBUGLOG("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%d) %s\n", stream.getPid(), stream.getStreamType(), "UNKNOWN"); break; } @@ -327,11 +346,12 @@ void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Le int prevPmtPid = m_pmtPid; if (0 != (m_pmtPid = assoc.getPid())) { - m_pmtSid = assoc.getServiceId(); if (m_pmtPid != prevPmtPid) { + m_pmtSid = assoc.getServiceId(); Add(m_pmtPid, 0x02); m_pmtVersion = -1; + break; } return; } @@ -351,7 +371,6 @@ void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Le { if (m_pmtVersion != pmt.getVersionNumber()) { -// printf("cStreamdevPatFilter: PMT version changed, detaching all pids\n"); cFilter::Del(m_pmtPid, 0x02); m_pmtPid = 0; // this triggers PAT scan } From f13e16e97872d67d896682d2c3b4a8c5aa3bc273 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Fri, 7 Dec 2012 07:02:27 +0100 Subject: [PATCH 05/12] vdr-plugin-vnsiserver: add debug switch to makefile --- addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile index 176aacdf2..1e8aa2b33 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile @@ -47,6 +47,10 @@ INCLUDES += -I$(VDRDIR)/include -I$(VDRDIR) DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -DVNSI_SERVER_VERSION='"$(VERSION)"' +ifeq ($(DEBUG),1) +DEFINES += -DDEBUG +endif + ### The object files (add further files here): OBJS = vnsi.o bitstream.o vnsiclient.o config.o cxsocket.o demuxer.o demuxer_AAC.o \ From aec43df18260b35cddba52711b077b21e05deb0f Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Fri, 7 Dec 2012 12:31:11 +0100 Subject: [PATCH 06/12] vdr-plugin-vnsiserver: distinguish aac adst from latm, implement parsing for adst --- .../vdr-plugin-vnsiserver/demuxer.c | 6 +- .../vdr-plugin-vnsiserver/demuxer.h | 5 +- .../vdr-plugin-vnsiserver/demuxer_AAC.c | 91 +++++++++++++++---- .../vdr-plugin-vnsiserver/demuxer_AAC.h | 2 +- .../vdr-plugin-vnsiserver/receiver.c | 41 +++++++-- 5 files changed, 113 insertions(+), 32 deletions(-) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.c index d29fdb458..b490ee957 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.c @@ -226,8 +226,8 @@ void cParser::SendPacket(sStreamPacket *pkt) cTSDemuxer::cTSDemuxer(cLiveStreamer *streamer, eStreamType type, int pid) : m_Streamer(streamer) - , m_pID(pid) , m_streamType(type) + , m_pID(pid) { m_pesError = false; m_pesParser = NULL; @@ -249,7 +249,9 @@ cTSDemuxer::cTSDemuxer(cLiveStreamer *streamer, eStreamType type, int pid) m_pesParser = new cParserH264(this, m_Streamer, m_pID); else if (m_streamType == stMPEG2AUDIO) m_pesParser = new cParserMPEG2Audio(this, m_Streamer, m_pID); - else if (m_streamType == stAAC) + else if (m_streamType == stAACADST) + m_pesParser = new cParserAAC(this, m_Streamer, m_pID); + else if (m_streamType == stAACLATM) m_pesParser = new cParserAAC(this, m_Streamer, m_pID); else if (m_streamType == stAC3) m_pesParser = new cParserAC3(this, m_Streamer, m_pID); diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.h index 404499ef0..417636342 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.h @@ -174,7 +174,8 @@ enum eStreamType stAC3, stMPEG2AUDIO, stEAC3, - stAAC, + stAACADST, + stAACLATM, stDTS, stMPEG2VIDEO, stH264, @@ -242,9 +243,9 @@ class cTSDemuxer { private: cLiveStreamer *m_Streamer; + eStreamType m_streamType; const int m_pID; eStreamContent m_streamContent; - eStreamType m_streamType; bool m_pesError; cParser *m_pesParser; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c index 33639fdf0..654b1743f 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c @@ -41,7 +41,7 @@ cParserAAC::cParserAAC(cTSDemuxer *demuxer, cLiveStreamer *streamer, int pID) m_demuxer = demuxer; m_streamBuffer = NULL; m_streamBufferSize = 0; - m_streamBufferPtr = 0; + m_streamBufferDataSize = 0; m_streamParserPtr = 0; m_firstPUSIseen = false; @@ -62,7 +62,7 @@ void cParserAAC::Parse(unsigned char *data, int size, bool pusi) { /* Payload unit start */ m_firstPUSIseen = true; - m_streamBufferPtr = 0; + m_streamBufferDataSize = 0; m_streamParserPtr = 0; } @@ -75,18 +75,18 @@ void cParserAAC::Parse(unsigned char *data, int size, bool pusi) m_streamBuffer = (uint8_t*)malloc(m_streamBufferSize); } - if(m_streamBufferPtr + size >= m_streamBufferSize) + if(m_streamBufferDataSize + size >= m_streamBufferSize) { m_streamBufferSize += size * 4; m_streamBuffer = (uint8_t*)realloc(m_streamBuffer, m_streamBufferSize); } - memcpy(m_streamBuffer + m_streamBufferPtr, data, size); - m_streamBufferPtr += size; + memcpy(m_streamBuffer + m_streamBufferDataSize, data, size); + m_streamBufferDataSize += size; if (m_streamParserPtr == 0) { - if (m_streamBufferPtr < 9) + if (m_streamBufferDataSize < 9) return; int hlen = ParsePESHeader(data, size); @@ -99,21 +99,76 @@ void cParserAAC::Parse(unsigned char *data, int size, bool pusi) int p = m_streamParserPtr; int l; - while ((l = m_streamBufferPtr - p) > 3) + if (m_demuxer->Type() == stAACLATM) { - if(m_streamBuffer[p] == 0x56 && (m_streamBuffer[p + 1] & 0xe0) == 0xe0) + while ((l = m_streamBufferDataSize - p) > 3) { - int muxlen = (m_streamBuffer[p + 1] & 0x1f) << 8 | m_streamBuffer[p + 2]; + if(m_streamBuffer[p] == 0x56 && (m_streamBuffer[p + 1] & 0xe0) == 0xe0) + { + int muxlen = (m_streamBuffer[p + 1] & 0x1f) << 8 | m_streamBuffer[p + 2]; - if(l < muxlen + 3) - break; + if(l < muxlen + 3) + break; - ParseLATMAudioMuxElement(m_streamBuffer + p + 3, muxlen); - p += muxlen + 3; + ParseLATMAudioMuxElement(m_streamBuffer + p + 3, muxlen); + p += muxlen + 3; + } + else + { + p++; + } } - else + } + else if (m_demuxer->Type() == stAACADST) + { + while ((l = m_streamBufferDataSize - p) > 3) { - p++; + if(m_streamBuffer[p] == 0xFF && (m_streamBuffer[p + 1] & 0xF0) == 0xF0) + { + // need at least 7 bytes for header + if (l < 7) + break; + + cBitstream bs(&m_streamBuffer[p], l * 8); + bs.skipBits(15); + + // check if CRC is present, means header is 9 byte long + int noCrc = bs.readBits(1); + if (!noCrc && (l < 9)) + break; + + bs.skipBits(2); // profile + m_SampleRateIndex = bs.readBits(4); + bs.skipBits(1); // private + m_ChannelConfig = bs.readBits(3); + bs.skipBits(4); + + int frameLen = bs.readBits(13); + + if (l < frameLen) + break; + + m_SampleRate = aac_sample_rates[m_SampleRateIndex & 0x0E]; + if (m_SampleRate) + m_FrameDuration = 1024 * 90000 / m_SampleRate; + + sStreamPacket pkt; + pkt.id = m_pID; + pkt.size = frameLen; + pkt.data = &m_streamBuffer[p]; + pkt.dts = m_curDTS; + pkt.pts = m_curDTS; + pkt.duration = m_FrameDuration; + + m_curDTS += m_FrameDuration; + SendPacket(&pkt); + + p += frameLen; + } + else + { + p++; + } } } m_streamParserPtr = p; @@ -259,17 +314,13 @@ void cParserAAC::ReadAudioSpecificConfig(cBitstream *bs) { int sr; int aot = bs->readBits(5); - static const int sample_rates[16] = { - 96000, 88200, 64000, 48000, 44100, 32000, - 24000, 22050, 16000, 12000, 11025, 8000, 7350 - }; m_SampleRateIndex = bs->readBits(4); if (m_SampleRateIndex == 0xf) sr = bs->readBits(24); else - sr = sample_rates[m_SampleRateIndex & 0xf]; + sr = aac_sample_rates[m_SampleRateIndex & 0xf]; m_SampleRate = aac_sample_rates[m_SampleRateIndex]; m_FrameDuration = 1024 * 90000 / m_SampleRate; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.h index 5ca61b530..8e9966e9c 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.h @@ -36,7 +36,7 @@ class cParserAAC : public cParser cTSDemuxer *m_demuxer; uint8_t *m_streamBuffer; int m_streamBufferSize; - int m_streamBufferPtr; + int m_streamBufferDataSize; int m_streamParserPtr; bool m_firstPUSIseen; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c index d80f603a1..3fb7253f8 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c @@ -166,8 +166,12 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d) (%s)\n", stream.getPid(), stream.getStreamType(), langs); return stream.getPid(); case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax + *type = stAACADST; + GetLanguage(stream, langs); + DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AAC", langs); + return stream.getPid(); case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax - *type = stAAC; + *type = stAACLATM; GetLanguage(stream, langs); DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AAC", langs); return stream.getPid(); @@ -213,7 +217,7 @@ int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *lan return stream.getPid(); case SI::AACDescriptorTag: DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AAC", langs); - *type = stAAC; + *type = stAACADST; GetLanguage(stream, langs); delete d; return stream.getPid(); @@ -786,7 +790,17 @@ void cLiveStreamer::sendStreamChange() resp->add_U32((*it)->CompositionPageId()); resp->add_U32((*it)->AncillaryPageId()); } - else if ((*it)->Type() == stAAC) + else if ((*it)->Type() == stAACADST) + { + resp->add_String("AAC"); + resp->add_String((*it)->GetLanguage()); + resp->add_U32((*it)->GetChannels()); + resp->add_U32((*it)->GetSampleRate()); + resp->add_U32((*it)->GetBlockAlign()); + resp->add_U32((*it)->GetBitRate()); + resp->add_U32((*it)->GetBitsPerSample()); + } + else if ((*it)->Type() == stAACLATM) { resp->add_String("AAC"); resp->add_String((*it)->GetLanguage()); @@ -997,7 +1011,8 @@ void cLiveStreamer::sendStreamInfo() (*it)->Type() == stAC3 || (*it)->Type() == stEAC3 || (*it)->Type() == stDTS || - (*it)->Type() == stAAC) + (*it)->Type() == stAACADST || + (*it)->Type() == stAACLATM) { resp->add_U32((*it)->GetPID()); resp->add_String((*it)->GetLanguage()); @@ -1057,7 +1072,7 @@ void cLiveStreamer::ensureDemuxers() std::list::iterator its; for (its = m_Streams.begin(); its != m_Streams.end(); ++its) { - if (its->pID == (*it)->GetPID()) + if ((its->pID == (*it)->GetPID()) && (its->type == (*it)->Type())) { break; } @@ -1095,6 +1110,16 @@ void cLiveStreamer::ensureDemuxers() demuxer = new cTSDemuxer(this, stMPEG2AUDIO, it->pID); demuxer->SetLanguage(it->language); } + else if (it->type == stAACADST) + { + demuxer = new cTSDemuxer(this, stAACADST, it->pID); + demuxer->SetLanguage(it->language); + } + else if (it->type == stAACLATM) + { + demuxer = new cTSDemuxer(this, stAACLATM, it->pID); + demuxer->SetLanguage(it->language); + } else if (it->type == stAC3) { demuxer = new cTSDemuxer(this, stAC3, it->pID); @@ -1175,8 +1200,10 @@ void cLiveStreamer::confChannelDemuxers() newStream.pID = *APids; newStream.type = stMPEG2AUDIO; #if APIVERSNUM >= 10715 - if (m_Channel->Atype(index) == 0x0F || m_Channel->Atype(index) == 0x11) - newStream.type = stAAC; + if (m_Channel->Atype(index) == 0x0F) + newStream.type = stAACADST; + else if (m_Channel->Atype(index) == 0x11) + newStream.type = stAACLATM; #endif newStream.SetLanguage(m_Channel->Alang(index)); AddStream(newStream); From 4f964c8269d59441843a05ae586fceead9ea0b34 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Fri, 7 Dec 2012 16:06:38 +0100 Subject: [PATCH 07/12] vdr-plugin-vnsiserver: fix aac latm, use latm codec instead of repacking into adts --- .../vdr-plugin-vnsiserver/demuxer_AAC.c | 52 ++++++------------- .../vdr-plugin-vnsiserver/receiver.c | 2 +- 2 files changed, 16 insertions(+), 38 deletions(-) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c index 654b1743f..e09a90352 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c @@ -103,9 +103,10 @@ void cParserAAC::Parse(unsigned char *data, int size, bool pusi) { while ((l = m_streamBufferDataSize - p) > 3) { - if(m_streamBuffer[p] == 0x56 && (m_streamBuffer[p + 1] & 0xe0) == 0xe0) + cBitstream bs(&m_streamBuffer[p], l * 8); + if(bs.readBits(11) == 0x2B7) { - int muxlen = (m_streamBuffer[p + 1] & 0x1f) << 8 | m_streamBuffer[p + 2]; + int muxlen = bs.readBits(13); if(l < muxlen + 3) break; @@ -203,38 +204,12 @@ void cParserAAC::ParseLATMAudioMuxElement(uint8_t *data, int len) sStreamPacket pkt; pkt.id = m_pID; - pkt.size = slotLen + 7; - pkt.data = (uint8_t*)malloc(pkt.size); + pkt.size = len + 3; + pkt.data = data-3; pkt.dts = m_curDTS; pkt.pts = m_curDTS; pkt.duration = m_FrameDuration; - /* 7 bytes of ADTS header */ - cBitstream out(pkt.data, 56); - - out.putBits(0xfff, 12); // Sync marker - out.putBits(0, 1); // ID 0 = MPEG 4 - out.putBits(0, 2); // Layer - out.putBits(1, 1); // Protection absent - out.putBits(2, 2); // AOT - out.putBits(m_SampleRateIndex, 4); - out.putBits(1, 1); // Private bit - out.putBits(m_ChannelConfig, 3); - out.putBits(1, 1); // Original - out.putBits(1, 1); // Copy - out.putBits(1, 1); // Copyright identification bit - out.putBits(1, 1); // Copyright identification start - out.putBits(slotLen, 13); - out.putBits(0, 11); // Buffer fullness - out.putBits(0, 2); // RDB in frame - - assert(out.remainingBits() == 0); - - /* AAC RDB */ - uint8_t *buf = pkt.data + 7; - for (unsigned int i = 0; i < slotLen; i++) - *buf++ = bs.readBits(8); - m_curDTS += m_FrameDuration; SendPacket(&pkt); @@ -252,7 +227,7 @@ void cParserAAC::ReadStreamMuxConfig(cBitstream *bs) return; if (AudioMuxVersion) - LATMGetValue(bs); // taraFullness + LATMGetValue(bs); // taraFullness bs->skipBits(1); // allStreamSameTimeFraming = 1 bs->skipBits(6); // numSubFrames = 0 @@ -290,7 +265,7 @@ void cParserAAC::ReadStreamMuxConfig(cBitstream *bs) if (bs->readBits(1)) { // other data? - if (AudioMuxVersion) + if (AudioMuxVersion == 1) { LATMGetValue(bs); // other_data_bits } @@ -312,18 +287,19 @@ void cParserAAC::ReadStreamMuxConfig(cBitstream *bs) void cParserAAC::ReadAudioSpecificConfig(cBitstream *bs) { - int sr; int aot = bs->readBits(5); + if (aot == 31) + aot = 32 + bs->readBits(6); m_SampleRateIndex = bs->readBits(4); if (m_SampleRateIndex == 0xf) - sr = bs->readBits(24); + m_SampleRate = bs->readBits(24); else - sr = aac_sample_rates[m_SampleRateIndex & 0xf]; + m_SampleRate = aac_sample_rates[m_SampleRateIndex & 0xf]; - m_SampleRate = aac_sample_rates[m_SampleRateIndex]; - m_FrameDuration = 1024 * 90000 / m_SampleRate; + if (m_SampleRate) + m_FrameDuration = 1024 * 90000 / m_SampleRate; m_ChannelConfig = bs->readBits(4); if (aot == 5) { // AOT_SBR @@ -331,6 +307,8 @@ void cParserAAC::ReadAudioSpecificConfig(cBitstream *bs) bs->skipBits(24); } aot = bs->readBits(5); // this is the main object type (i.e. non-extended) + if (aot == 31) + aot = 32 + bs->readBits(6); } if(aot != 2) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c index 3fb7253f8..64e5e51f6 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c @@ -802,7 +802,7 @@ void cLiveStreamer::sendStreamChange() } else if ((*it)->Type() == stAACLATM) { - resp->add_String("AAC"); + resp->add_String("AACLATM"); resp->add_String((*it)->GetLanguage()); resp->add_U32((*it)->GetChannels()); resp->add_U32((*it)->GetSampleRate()); From 134d59edd6241006b25e448c7066fd043b4f0344 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sat, 8 Dec 2012 11:53:59 +0100 Subject: [PATCH 08/12] vdr-plugin-vnsiserver: keep pat/pmt in sync with buffer --- .../vdr-plugin-vnsiserver/receiver.c | 608 ++++++++++-------- .../vdr-plugin-vnsiserver/receiver.h | 12 +- 2 files changed, 344 insertions(+), 276 deletions(-) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c index 64e5e51f6..06a0be7a4 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c @@ -75,10 +75,7 @@ cLiveReceiver::~cLiveReceiver() //void cLiveReceiver void cLiveReceiver::Receive(uchar *Data, int Length) { - int p = m_Streamer->Put(Data, Length); - - if (p != Length) - m_Streamer->ReportOverflow(Length - p); + m_Streamer->Receive(Data, Length); } inline void cLiveReceiver::Activate(bool On) @@ -97,8 +94,6 @@ class cLivePatFilter : public cFilter const cChannel *m_Channel; cLiveStreamer *m_Streamer; - int GetPid(SI::PMT::Stream& stream, eStreamType *type, char *langs, int *subtitlingType, int *compositionPageId, int *ancillaryPageId); - void GetLanguage(SI::PMT::Stream& stream, char *langs); virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length); public: @@ -117,219 +112,6 @@ cLivePatFilter::cLivePatFilter(cLiveStreamer *Streamer, const cChannel *Channel) } -void cLivePatFilter::GetLanguage(SI::PMT::Stream& stream, char *langs) -{ - SI::Descriptor *d; - for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) - { - switch (d->getDescriptorTag()) - { - case SI::ISO639LanguageDescriptorTag: - { - langs[MAXLANGCODE1] = 0; - SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; - strn0cpy(langs, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1); - break; - } - default: ; - } - delete d; - } -} - -int cLivePatFilter::GetPid(SI::PMT::Stream& stream, eStreamType *type, char *langs, int *subtitlingType, int *compositionPageId, int *ancillaryPageId) -{ - SI::Descriptor *d; - *langs = 0; - - if (!stream.getPid()) - return 0; - - if(m_Channel->Tpid() == stream.getPid()) - { - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d %s\n", stream.getPid(), "Teletext"); - *type = stTELETEXT; - return stream.getPid(); - } - - switch (stream.getStreamType()) - { - case 0x01: // ISO/IEC 11172 Video - case 0x02: // ISO/IEC 13818-2 Video - DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d)\n", stream.getPid(), stream.getStreamType()); - *type = stMPEG2VIDEO; - return stream.getPid(); - case 0x03: // ISO/IEC 11172 Audio - case 0x04: // ISO/IEC 13818-3 Audio - *type = stMPEG2AUDIO; - GetLanguage(stream, langs); - DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d) (%s)\n", stream.getPid(), stream.getStreamType(), langs); - return stream.getPid(); - case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax - *type = stAACADST; - GetLanguage(stream, langs); - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AAC", langs); - return stream.getPid(); - case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax - *type = stAACLATM; - GetLanguage(stream, langs); - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AAC", langs); - return stream.getPid(); -#if 1 - case 0x07: // ISO/IEC 13512 MHEG - case 0x08: // ISO/IEC 13818-1 Annex A DSM CC - case 0x0a: // ISO/IEC 13818-6 Multiprotocol encapsulation - case 0x0b: // ISO/IEC 13818-6 DSM-CC U-N Messages - case 0x0c: // ISO/IEC 13818-6 Stream Descriptors - case 0x0d: // ISO/IEC 13818-6 Sections (any type, including private data) - case 0x0e: // ISO/IEC 13818-1 auxiliary -#endif - case 0x10: // ISO/IEC 14496-2 Visual (MPEG-4) - DEBUGLOG("cStreamdevPatFilter PMT scanner: Not adding PID %d (%d) (skipped)\n", stream.getPid(), stream.getStreamType()); - break; - case 0x1b: // ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264) - DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d)\n", stream.getPid(), stream.getStreamType()); - *type = stH264; - return stream.getPid(); - case 0x05: // ISO/IEC 13818-1 private sections - case 0x06: // ISO/IEC 13818-1 PES packets containing private data - for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) - { - switch (d->getDescriptorTag()) - { - case SI::AC3DescriptorTag: - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AC3", langs); - *type = stAC3; - GetLanguage(stream, langs); - delete d; - return stream.getPid(); - case SI::EnhancedAC3DescriptorTag: - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "EAC3", langs); - *type = stEAC3; - GetLanguage(stream, langs); - delete d; - return stream.getPid(); - case SI::DTSDescriptorTag: - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "DTS", langs); - *type = stDTS; - GetLanguage(stream, langs); - delete d; - return stream.getPid(); - case SI::AACDescriptorTag: - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AAC", langs); - *type = stAACADST; - GetLanguage(stream, langs); - delete d; - return stream.getPid(); - case SI::TeletextDescriptorTag: - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s\n", stream.getPid(), stream.getStreamType(), "Teletext"); - *type = stTELETEXT; - delete d; - return stream.getPid(); - case SI::SubtitlingDescriptorTag: - { - *type = stDVBSUB; - *langs = 0; - *subtitlingType = 0; - *compositionPageId = 0; - *ancillaryPageId = 0; - SI::SubtitlingDescriptor *sd = (SI::SubtitlingDescriptor *)d; - SI::SubtitlingDescriptor::Subtitling sub; - char *s = langs; - s[MAXLANGCODE1] = 0; - int n = 0; - for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) - { - if (sub.languageCode[0]) - { - *subtitlingType = sub.getSubtitlingType(); - *compositionPageId = sub.getCompositionPageId(); - *ancillaryPageId = sub.getAncillaryPageId(); - if (n > 0) - *s++ = '+'; - strn0cpy(s, I18nNormalizeLanguageCode(sub.languageCode), MAXLANGCODE1); - s += strlen(s); - if (n++ > 1) - break; - } - } - delete d; - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s\n", stream.getPid(), stream.getStreamType(), "DVBSUB"); - return stream.getPid(); - } - default: - DEBUGLOG("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%d) %s (%i)\n", stream.getPid(), stream.getStreamType(), "UNKNOWN", d->getDescriptorTag()); - break; - } - delete d; - } - break; - case 0x80: - if (Setup.StandardCompliance == STANDARD_ANSISCTE) - { // DigiCipher II VIDEO (ANSI/SCTE 57) - DEBUGLOG("cStreamdevPatFilter PMT scanner adding PID %d (%d)\n", stream.getPid(), stream.getStreamType()); - *type = stMPEG2VIDEO; - return stream.getPid(); - } - // fall through - case 0x81: // STREAMTYPE_USER_PRIVATE - if (Setup.StandardCompliance == STANDARD_ANSISCTE) - { // ATSC A/53 AUDIO (ANSI/SCTE 57) - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AC3", langs); - *type = stAC3; - GetLanguage(stream, langs); - return stream.getPid(); - } - // fall through - case 0x83 ... 0xFF: // STREAMTYPE_USER_PRIVATE - { - bool IsAc3 = false; - langs[MAXLANGCODE1] = 0; - SI::Descriptor *d; - for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) - { - switch (d->getDescriptorTag()) - { - case SI::RegistrationDescriptorTag: - { - SI::RegistrationDescriptor *rd = (SI::RegistrationDescriptor *)d; - // http://www.smpte-ra.org/mpegreg/mpegreg.html - switch (rd->getFormatIdentifier()) - { - case 0x41432D33: // 'AC-3' - IsAc3 = true; - break; - default: - break; - } - } - break; - case SI::ISO639LanguageDescriptorTag: - { - SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; - strn0cpy(langs, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1); - } - break; - default: ; - } - delete d; - } - if (IsAc3) - { - DEBUGLOG("cStreamdevPatFilter PMT scanner: adding PID %d (%d) %s (%s)\n", stream.getPid(), stream.getStreamType(), "AC3", langs); - *type = stAC3; - return stream.getPid(); - } - } - break; - default: - DEBUGLOG("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%d) %s\n", stream.getPid(), stream.getStreamType(), "UNKNOWN"); - break; - } - *type = stNone; - return 0; -} - void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length) { if (Pid == 0x00) @@ -382,19 +164,233 @@ void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Le } m_pmtVersion = pmt.getVersionNumber(); - SI::PMT::Stream stream; - sStream newStream; - m_Streamer->m_DemuxerLock.Lock(); - for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) - { - newStream.pID = GetPid(stream, &newStream.type, (char*)&newStream.language, &newStream.subtitlingType, &newStream.compositionPageId, &newStream.ancillaryPageId); - if (newStream.pID != 0) - { - m_Streamer->AddStream(newStream); - m_Streamer->CheckDemuxers(); - } - } - m_Streamer->m_DemuxerLock.Unlock(); + cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), pmt.getServiceId()); + if (Channel) { + // Scan the stream-specific loop: + SI::PMT::Stream stream; + int Vpid = 0; + int Ppid = 0; + int Vtype = 0; + int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated + int Atypes[MAXAPIDS + 1] = { 0 }; + int Dpids[MAXDPIDS + 1] = { 0 }; + int Dtypes[MAXDPIDS + 1] = { 0 }; + int Spids[MAXSPIDS + 1] = { 0 }; + uchar SubtitlingTypes[MAXSPIDS + 1] = { 0 }; + uint16_t CompositionPageIds[MAXSPIDS + 1] = { 0 }; + uint16_t AncillaryPageIds[MAXSPIDS + 1] = { 0 }; + char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" }; + char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" }; + char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" }; + int Tpid = 0; + int NumApids = 0; + int NumDpids = 0; + int NumSpids = 0; + for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) { + bool ProcessCaDescriptors = false; + int esPid = stream.getPid(); + switch (stream.getStreamType()) { + case 1: // STREAMTYPE_11172_VIDEO + case 2: // STREAMTYPE_13818_VIDEO + case 0x1B: // MPEG4 + Vpid = esPid; + Ppid = pmt.getPCRPid(); + Vtype = stream.getStreamType(); + ProcessCaDescriptors = true; + break; + case 3: // STREAMTYPE_11172_AUDIO + case 4: // STREAMTYPE_13818_AUDIO + case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax + case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax + { + if (NumApids < MAXAPIDS) { + Apids[NumApids] = esPid; + Atypes[NumApids] = stream.getStreamType(); + SI::Descriptor *d; + for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) { + switch (d->getDescriptorTag()) { + case SI::ISO639LanguageDescriptorTag: { + SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; + SI::ISO639LanguageDescriptor::Language l; + char *s = ALangs[NumApids]; + int n = 0; + for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) { + if (*ld->languageCode != '-') { // some use "---" to indicate "none" + if (n > 0) + *s++ = '+'; + strn0cpy(s, I18nNormalizeLanguageCode(l.languageCode), MAXLANGCODE1); + s += strlen(s); + if (n++ > 1) + break; + } + } + } + break; + default: ; + } + delete d; + } + NumApids++; + } + ProcessCaDescriptors = true; + } + break; + case 5: // STREAMTYPE_13818_PRIVATE + case 6: // STREAMTYPE_13818_PES_PRIVATE + //XXX case 8: // STREAMTYPE_13818_DSMCC + { + int dpid = 0; + int dtype = 0; + char lang[MAXLANGCODE1] = { 0 }; + SI::Descriptor *d; + for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) { + switch (d->getDescriptorTag()) { + case SI::AC3DescriptorTag: + case SI::EnhancedAC3DescriptorTag: + dpid = esPid; + dtype = d->getDescriptorTag(); + ProcessCaDescriptors = true; + break; + case SI::SubtitlingDescriptorTag: + if (NumSpids < MAXSPIDS) { + Spids[NumSpids] = esPid; + SI::SubtitlingDescriptor *sd = (SI::SubtitlingDescriptor *)d; + SI::SubtitlingDescriptor::Subtitling sub; + char *s = SLangs[NumSpids]; + int n = 0; + for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) { + if (sub.languageCode[0]) { + SubtitlingTypes[NumSpids] = sub.getSubtitlingType(); + CompositionPageIds[NumSpids] = sub.getCompositionPageId(); + AncillaryPageIds[NumSpids] = sub.getAncillaryPageId(); + if (n > 0) + *s++ = '+'; + strn0cpy(s, I18nNormalizeLanguageCode(sub.languageCode), MAXLANGCODE1); + s += strlen(s); + if (n++ > 1) + break; + } + } + NumSpids++; + } + break; + case SI::TeletextDescriptorTag: + Tpid = esPid; + break; + case SI::ISO639LanguageDescriptorTag: { + SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; + strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1); + } + break; + default: ; + } + delete d; + } + if (dpid) { + if (NumDpids < MAXDPIDS) { + Dpids[NumDpids] = dpid; + Dtypes[NumDpids] = dtype; + strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1); + NumDpids++; + } + } + } + break; + case 0x80: // STREAMTYPE_USER_PRIVATE + if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // DigiCipher II VIDEO (ANSI/SCTE 57) + Vpid = esPid; + Ppid = pmt.getPCRPid(); + Vtype = 0x02; // compression based upon MPEG-2 + ProcessCaDescriptors = true; + break; + } + // fall through + case 0x81: // STREAMTYPE_USER_PRIVATE + if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // ATSC A/53 AUDIO (ANSI/SCTE 57) + char lang[MAXLANGCODE1] = { 0 }; + SI::Descriptor *d; + for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) { + switch (d->getDescriptorTag()) { + case SI::ISO639LanguageDescriptorTag: { + SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; + strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1); + } + break; + default: ; + } + delete d; + } + if (NumDpids < MAXDPIDS) { + Dpids[NumDpids] = esPid; + Dtypes[NumDpids] = SI::AC3DescriptorTag; + strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1); + NumDpids++; + } + ProcessCaDescriptors = true; + break; + } + // fall through + case 0x82: // STREAMTYPE_USER_PRIVATE + if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // STANDARD SUBTITLE (ANSI/SCTE 27) + //TODO + break; + } + // fall through + case 0x83 ... 0xFF: // STREAMTYPE_USER_PRIVATE + { + char lang[MAXLANGCODE1] = { 0 }; + bool IsAc3 = false; + SI::Descriptor *d; + for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) { + switch (d->getDescriptorTag()) { + case SI::RegistrationDescriptorTag: { + SI::RegistrationDescriptor *rd = (SI::RegistrationDescriptor *)d; + // http://www.smpte-ra.org/mpegreg/mpegreg.html + switch (rd->getFormatIdentifier()) { + case 0x41432D33: // 'AC-3' + IsAc3 = true; + break; + default: + //printf("Format identifier: 0x%08X (pid: %d)\n", rd->getFormatIdentifier(), esPid); + break; + } + } + break; + case SI::ISO639LanguageDescriptorTag: { + SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; + strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1); + } + break; + default: ; + } + delete d; + } + if (IsAc3) { + if (NumDpids < MAXDPIDS) { + Dpids[NumDpids] = esPid; + Dtypes[NumDpids] = SI::AC3DescriptorTag; + strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1); + NumDpids++; + } + ProcessCaDescriptors = true; + } + } + break; + default: ;//printf("PID: %5d %5d %2d %3d %3d\n", pmt.getServiceId(), stream.getPid(), stream.getStreamType(), pmt.getVersionNumber(), Channel->Number()); + } + } + cChannel pmtChannel(*Channel); + pmtChannel.SetPids(Vpid, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid); + pmtChannel.SetSubtitlingDescriptors(SubtitlingTypes, CompositionPageIds, AncillaryPageIds); + m_Streamer->SetTpid(Tpid); + cPatPmtGenerator patPmtGenerator(&pmtChannel); + m_Streamer->m_bufferLock.Lock(); + m_Streamer->Put(patPmtGenerator.GetPat(), TS_SIZE); + int Index = 0; + while (uchar *pmt = patPmtGenerator.GetPmt(Index)) + m_Streamer->Put(pmt, TS_SIZE); + m_Streamer->m_bufferLock.Unlock(); + } } } @@ -419,6 +415,7 @@ cLiveStreamer::cLiveStreamer(uint32_t timeout) m_SignalLost = false; m_IFrameSeen = false; m_PidChange = false; + m_Tpid = 0; m_requestStreamChange = false; @@ -496,17 +493,28 @@ cLiveStreamer::~cLiveStreamer() DEBUGLOG("Finished to delete live streamer"); } +void cLiveStreamer::Receive(uchar *Data, int Length) +{ + m_bufferLock.Lock(); + int p = Put(Data, Length); + + if (p != Length) + ReportOverflow(Length - p); + m_bufferLock.Unlock(); +} + void cLiveStreamer::Action(void) { int size = 0; int used = 0; unsigned char *buf = NULL; m_startup = true; - cTimeMs last_info; cTimeMs starttime; - m_last_tick.Set(0); + cPatPmtParser patPmtParser; + cTSDemuxer *demuxer; + int oldPmtVersion = -1; while (Running()) { @@ -524,12 +532,9 @@ void cLiveStreamer::Action(void) if (m_Demuxers.size() == 0 && starttime.Elapsed() > 2000) { INFOLOG("Got no PMT, using channel conf for creating demuxers"); - confChannelDemuxers(); + confChannelDemuxers(m_Channel); } - if (m_checkDemuxers) - ensureDemuxers(); - // no data if (buf == NULL || size <= TS_SIZE) { @@ -571,9 +576,29 @@ void cLiveStreamer::Action(void) break; } - unsigned int ts_pid = TsPid(buf); - cTSDemuxer *demuxer = FindStreamDemuxer(ts_pid); - if (demuxer) + int ts_pid = TsPid(buf); + + if (ts_pid == PATPID) + { + patPmtParser.ParsePat(buf, TS_SIZE); + } + else if (ts_pid == patPmtParser.PmtPid()) + { + int patVersion, pmtVersion; + patPmtParser.ParsePmt(buf, TS_SIZE); + if (patPmtParser.GetVersions(patVersion, pmtVersion)) + { + if (pmtVersion != oldPmtVersion) + { + cChannel pmtChannel(*m_Channel); + setChannelPids(&pmtChannel, &patPmtParser); + confChannelDemuxers(&pmtChannel); + patPmtParser.Reset(); + oldPmtVersion = pmtVersion; + } + } + } + else if (demuxer = FindStreamDemuxer(ts_pid)) { if (!demuxer->ProcessTSPacket(buf)) { @@ -733,8 +758,6 @@ void cLiveStreamer::sendStreamChange() return; } - m_DemuxerLock.Lock(); - for (std::list::iterator it = m_Demuxers.begin(); it != m_Demuxers.end(); ++it) { resp->add_U32((*it)->GetPID()); @@ -832,8 +855,6 @@ void cLiveStreamer::sendStreamChange() } } - m_DemuxerLock.Unlock(); - resp->finaliseStream(); m_Socket->write(resp->getPtr(), resp->getLen(), -1, true); delete resp; @@ -1003,8 +1024,6 @@ void cLiveStreamer::sendStreamInfo() return; } - m_DemuxerLock.Lock(); - for (std::list::iterator it = m_Demuxers.begin(); it != m_Demuxers.end(); ++it) { if ((*it)->Type() == stMPEG2AUDIO || @@ -1040,8 +1059,6 @@ void cLiveStreamer::sendStreamInfo() } } - m_DemuxerLock.Unlock(); - resp->finaliseStream(); m_Socket->write(resp->getPtr(), resp->getLen()); delete resp; @@ -1064,8 +1081,6 @@ void cLiveStreamer::sendStreamStatus() void cLiveStreamer::ensureDemuxers() { - cMutexLock Lock(&m_DemuxerLock); - std::list::iterator it = m_Demuxers.begin(); while (it != m_Demuxers.end()) { @@ -1172,17 +1187,16 @@ void cLiveStreamer::ensureDemuxers() } m_Streams.clear(); - m_checkDemuxers = false; } -void cLiveStreamer::confChannelDemuxers() +void cLiveStreamer::confChannelDemuxers(const cChannel *channel) { sStream newStream; - if (m_Channel->Vpid()) + if (channel->Vpid()) { - newStream.pID = m_Channel->Vpid(); + newStream.pID = channel->Vpid(); #if APIVERSNUM >= 10701 - if (m_Channel->Vtype() == 0x1B) + if (channel->Vtype() == 0x1B) newStream.type = stH264; else #endif @@ -1191,7 +1205,7 @@ void cLiveStreamer::confChannelDemuxers() AddStream(newStream); } - const int *APids = m_Channel->Apids(); + const int *APids = channel->Apids(); for ( ; *APids; APids++) { int index = 0; @@ -1200,18 +1214,18 @@ void cLiveStreamer::confChannelDemuxers() newStream.pID = *APids; newStream.type = stMPEG2AUDIO; #if APIVERSNUM >= 10715 - if (m_Channel->Atype(index) == 0x0F) + if (channel->Atype(index) == 0x0F) newStream.type = stAACADST; - else if (m_Channel->Atype(index) == 0x11) + else if (channel->Atype(index) == 0x11) newStream.type = stAACLATM; #endif - newStream.SetLanguage(m_Channel->Alang(index)); + newStream.SetLanguage(channel->Alang(index)); AddStream(newStream); } index++; } - const int *DPids = m_Channel->Dpids(); + const int *DPids = channel->Dpids(); for ( ; *DPids; DPids++) { int index = 0; @@ -1220,16 +1234,16 @@ void cLiveStreamer::confChannelDemuxers() newStream.pID = *DPids; newStream.type = stAC3; #if APIVERSNUM >= 10715 - if (m_Channel->Dtype(index) == SI::EnhancedAC3DescriptorTag) + if (channel->Dtype(index) == SI::EnhancedAC3DescriptorTag) newStream.type = stEAC3; #endif - newStream.SetLanguage(m_Channel->Dlang(index)); + newStream.SetLanguage(channel->Dlang(index)); AddStream(newStream); } index++; } - const int *SPids = m_Channel->Spids(); + const int *SPids = channel->Spids(); if (SPids) { int index = 0; @@ -1239,11 +1253,11 @@ void cLiveStreamer::confChannelDemuxers() { newStream.pID = *SPids; newStream.type = stDVBSUB; - newStream.SetLanguage(m_Channel->Slang(index)); + newStream.SetLanguage(channel->Slang(index)); #if APIVERSNUM >= 10709 - newStream.subtitlingType = m_Channel->SubtitlingType(index); - newStream.compositionPageId = m_Channel->CompositionPageId(index); - newStream.ancillaryPageId = m_Channel->AncillaryPageId(index); + newStream.subtitlingType = channel->SubtitlingType(index); + newStream.compositionPageId = channel->CompositionPageId(index); + newStream.ancillaryPageId = channel->AncillaryPageId(index); #endif AddStream(newStream); } @@ -1251,12 +1265,64 @@ void cLiveStreamer::confChannelDemuxers() } } - if (m_Channel->Tpid()) + if (m_Tpid) { - newStream.pID = m_Channel->Tpid(); + newStream.pID = m_Tpid; newStream.type = stTELETEXT; AddStream(newStream); } - CheckDemuxers(); + ensureDemuxers(); +} + +void cLiveStreamer::setChannelPids(cChannel *channel, cPatPmtParser *patPmtParser) +{ + int Apids[MAXAPIDS + 1] = { 0 }; + int Atypes[MAXAPIDS + 1] = { 0 }; + int Dpids[MAXDPIDS + 1] = { 0 }; + int Dtypes[MAXDPIDS + 1] = { 0 }; + int Spids[MAXSPIDS + 1] = { 0 }; + char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" }; + char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" }; + char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" }; + int index = 0; + + const int *aPids = patPmtParser->Apids(); + index = 0; + for ( ; *aPids; aPids++) + { + Apids[index] = patPmtParser->Apid(index); + Atypes[index] = patPmtParser->Atype(index); + strn0cpy(ALangs[index], patPmtParser->Alang(index), MAXLANGCODE2); + index++; + } + + const int *dPids = patPmtParser->Dpids(); + index = 0; + for ( ; *dPids; dPids++) + { + Dpids[index] = patPmtParser->Dpid(index); + Dtypes[index] = patPmtParser->Dtype(index); + strn0cpy(DLangs[index], patPmtParser->Dlang(index), MAXLANGCODE2); + index++; + } + + const int *sPids = patPmtParser->Spids(); + index = 0; + for ( ; *sPids; sPids++) + { + Spids[index] = patPmtParser->Spid(index); + strn0cpy(SLangs[index], patPmtParser->Slang(index), MAXLANGCODE2); + index++; + } + + int Vpid = patPmtParser->Vpid(); + int Ppid = patPmtParser->Ppid(); + int VType = patPmtParser->Vtype(); + int Tpid = m_Channel->Tpid(); + channel->SetPids(Vpid, Ppid, VType, + Apids, Atypes, ALangs, + Dpids, Dtypes, DLangs, + Spids, SLangs, + Tpid); } diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.h index 4e14cd2df..ba0acbee7 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.h @@ -69,6 +69,7 @@ class cLiveStreamer : public cThread private: friend class cParser; friend class cLivePatFilter; + friend class cLiveReceiver; cTSDemuxer *FindStreamDemuxer(int Pid); @@ -78,7 +79,9 @@ class cLiveStreamer : public cThread void sendStreamInfo(); void sendStreamStatus(); void ensureDemuxers(); - void confChannelDemuxers(); + void confChannelDemuxers(const cChannel *channel); + void setChannelPids(cChannel *channel, cPatPmtParser *patPmtParser); + void Receive(uchar *Data, int Length); const cChannel *m_Channel; /*!> Channel to stream */ cDevice *m_Device; /*!> The receiving device the channel depents to */ @@ -97,7 +100,6 @@ class cLiveStreamer : public cThread bool m_IsMPEGPS; /*!> TS Stream contains MPEG PS data like from pvrinput */ cResponsePacket* m_packetEmpty; /*!> Empty stream packet */ bool m_requestStreamChange; - bool m_checkDemuxers; uint32_t m_scanTimeout; /*!> Channel scanning timeout (in seconds) */ cTimeMs m_last_tick; bool m_SignalLost; @@ -106,6 +108,8 @@ class cLiveStreamer : public cThread std::list m_Demuxers; std::list m_Streams; bool m_PidChange; + int m_Tpid; + cMutex m_bufferLock; protected: virtual void Action(void); @@ -123,9 +127,7 @@ class cLiveStreamer : public cThread bool IsAudioOnly() { return m_IsAudioOnly; } bool IsMPEGPS() { return m_IsMPEGPS; } void AddStream(sStream &stream); - void CheckDemuxers() {m_checkDemuxers = true; }; - - cMutex m_DemuxerLock; + void SetTpid(int tPid) { m_Tpid = tPid; } }; #endif // VNSI_RECEIVER_H From 8d5cf0e62a89770df0aa212f946f7ee69764435c Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sat, 8 Dec 2012 12:40:17 +0100 Subject: [PATCH 09/12] vdr-plugin-vnsiserver: make pmt timeout a setup parameter --- .../vdr-plugin-vnsiserver/Makefile | 2 +- .../vdr-plugin-vnsiserver/receiver.c | 3 +- .../vdr-plugin-vnsiserver/setup.c | 36 ++++++++++++++++++ .../vdr-plugin-vnsiserver/setup.h | 38 +++++++++++++++++++ .../pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.c | 9 ++++- .../pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.h | 2 + 6 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/setup.c create mode 100644 addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/setup.h diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile index 1e8aa2b33..92fc90def 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile @@ -56,7 +56,7 @@ endif OBJS = vnsi.o bitstream.o vnsiclient.o config.o cxsocket.o demuxer.o demuxer_AAC.o \ demuxer_AC3.o demuxer_DTS.o demuxer_h264.o demuxer_MPEGAudio.o demuxer_MPEGVideo.o \ demuxer_Subtitle.o demuxer_Teletext.o receiver.o recplayer.o requestpacket.o responsepacket.o \ - vnsiserver.o hash.o recordingscache.o + vnsiserver.o hash.o recordingscache.o setup.o ### Implicit rules: diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c index 06a0be7a4..e3104c473 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c @@ -39,6 +39,7 @@ #include "cxsocket.h" #include "vnsicommand.h" #include "responsepacket.h" +#include "vnsi.h" // --- cLiveReceiver ------------------------------------------------- @@ -529,7 +530,7 @@ void cLiveStreamer::Action(void) } // if we got no pmt, create demuxers with info in channels.conf - if (m_Demuxers.size() == 0 && starttime.Elapsed() > 2000) + if (m_Demuxers.size() == 0 && starttime.Elapsed() > (unsigned int)PmtTimeout*1000) { INFOLOG("Got no PMT, using channel conf for creating demuxers"); confChannelDemuxers(m_Channel); diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/setup.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/setup.c new file mode 100644 index 000000000..f68ab1022 --- /dev/null +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/setup.c @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2005-2012 Team XBMC +* http://www.xbmc.org +* +* This Program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This Program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with XBMC; see the file COPYING. If not, see +* . +* +*/ + +#include "setup.h" + +int PmtTimeout = 2; + +cMenuSetupVNSI::cMenuSetupVNSI(void) +{ + newPmtTimeout = PmtTimeout; + Add(new cMenuEditIntItem( tr("PMT Timeout (0-10)"), &newPmtTimeout)); +} + +void cMenuSetupVNSI::Store(void) +{ + if (newPmtTimeout > 10 || newPmtTimeout < 0) + newPmtTimeout = 2; + SetupStore(CONFNAME_PMTTIMEOUT, PmtTimeout = newPmtTimeout); +} diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/setup.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/setup.h new file mode 100644 index 000000000..b266f74bd --- /dev/null +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/setup.h @@ -0,0 +1,38 @@ +/* +* Copyright (C) 2005-2012 Team XBMC +* http://www.xbmc.org +* +* This Program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This Program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with XBMC; see the file COPYING. If not, see +* . +* +*/ + +#ifndef VNSI_SETUP_H +#define VNSI_SETUP_H + +#include + +#define CONFNAME_PMTTIMEOUT "LogLevel" + +class cMenuSetupVNSI : public cMenuSetupPage +{ +private: + int newPmtTimeout; +protected: + virtual void Store(void); +public: + cMenuSetupVNSI(void); +}; + +#endif // VNSI_SETUP_H diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.c index 7b2513095..1a62f6107 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.c @@ -26,6 +26,7 @@ #include #include #include "vnsi.h" +#include "setup.h" cPluginVNSIServer::cPluginVNSIServer(void) { @@ -108,13 +109,17 @@ time_t cPluginVNSIServer::WakeupTime(void) cMenuSetupPage *cPluginVNSIServer::SetupMenu(void) { // Return a setup menu in case the plugin supports one. - return NULL; + return new cMenuSetupVNSI; } bool cPluginVNSIServer::SetupParse(const char *Name, const char *Value) { // Parse your own setup parameters and store their values. - return false; + if (!strcasecmp(Name, CONFNAME_PMTTIMEOUT)) + PmtTimeout = atoi(Value); + else + return false; + return true; } bool cPluginVNSIServer::Service(const char *Id, void *Data) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.h index 5adcf5924..fd548d60e 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.h @@ -30,6 +30,8 @@ static const char *VERSION = "0.9.0"; static const char *DESCRIPTION = "VDR-Network-Streaming-Interface (VNSI) Server"; +extern int PmtTimeout; + class cPluginVNSIServer : public cPlugin { private: cVNSIServer *Server; From 1080c3b84828d7a1ca69e63ca9cf4dd07e7fa962 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 8 Dec 2012 13:29:11 +0100 Subject: [PATCH 10/12] vnsi: use latm codec, the server no longer encapsulates latm into adts --- addons/pvr.vdr.vnsi/src/VNSIDemux.cpp | 6 ++++++ addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/addons/pvr.vdr.vnsi/src/VNSIDemux.cpp b/addons/pvr.vdr.vnsi/src/VNSIDemux.cpp index fe9ef0a0c..9d1655e3a 100644 --- a/addons/pvr.vdr.vnsi/src/VNSIDemux.cpp +++ b/addons/pvr.vdr.vnsi/src/VNSIDemux.cpp @@ -251,6 +251,12 @@ void cVNSIDemux::StreamChange(cResponsePacket *resp) streams.stream[streams.iStreamCount].iCodecType = AVMEDIA_TYPE_AUDIO; streams.stream[streams.iStreamCount].iCodecId = CODEC_ID_AAC; } + else if(!strcmp(type, "AACLATM")) + { + streams.stream[streams.iStreamCount].iPhysicalId = pid; + streams.stream[streams.iStreamCount].iCodecType = AVMEDIA_TYPE_AUDIO; + streams.stream[streams.iStreamCount].iCodecId = CODEC_ID_AAC_LATM; + } else if(!strcmp(type, "DTS")) { streams.stream[streams.iStreamCount].iPhysicalId = pid; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c index e09a90352..810ae39d1 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AAC.c @@ -321,5 +321,6 @@ void cParserAAC::ReadAudioSpecificConfig(cBitstream *bs) if (bs->readBits(1)) // ext_flag bs->skipBits(1); // ext3_flag - m_demuxer->SetAudioInformation(m_ChannelConfig, m_SampleRate, 0, 0, 0); + // ffmpeg won't get started if this info is set +// m_demuxer->SetAudioInformation(m_ChannelConfig, m_SampleRate, 0, 0, 0); } From 4c39b0bdc6bb8f87fb30b83fbcf5939673ad57fc Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Mon, 10 Dec 2012 09:27:29 +0100 Subject: [PATCH 11/12] vdr-plugin-vnsiserver: fix eac3 --- .../vdr-plugin-vnsiserver/demuxer_AC3.c | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AC3.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AC3.c index 7d711a026..448eec31b 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AC3.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer_AC3.c @@ -127,6 +127,9 @@ cParserAC3::cParserAC3(cTSDemuxer *demuxer, cLiveStreamer *streamer, int pID) m_NextDTS = 0; m_AC3BufferPtr = 0; m_HeaderFound = false; + m_FrameOffset = 0; + m_CurrentOffset = 0; + m_NextFrameOffset = 0; for (int i = 0; i < AV_PARSER_PTS_NB; i++) { @@ -238,7 +241,8 @@ int cParserAC3::FindHeaders(uint8_t **poutbuf, int *poutbuf_size, uint8_t *buf_ptr = buf; while (buf_size > 0) { - if (buf_ptr[0] == 0x0b && buf_ptr[1] == 0x77 && !m_HeaderFound) + if (!m_HeaderFound && (buf_size >= 9) && + (buf_ptr[0] == 0x0b && buf_ptr[1] == 0x77)) { cBitstream bs(buf_ptr + 2, AC3_HEADER_SIZE * 8); @@ -288,8 +292,8 @@ int cParserAC3::FindHeaders(uint8_t **poutbuf, int *poutbuf_size, /*int substreamid =*/ bs.readBits(3); - int framesize = (bs.readBits(11) + 1) << 1; - if (framesize < AC3_HEADER_SIZE) + m_FrameSize = (bs.readBits(11) + 1) << 1; + if (m_FrameSize < AC3_HEADER_SIZE) return -1; int numBlocks = 6; @@ -310,14 +314,23 @@ int cParserAC3::FindHeaders(uint8_t **poutbuf, int *poutbuf_size, int channelMode = bs.readBits(3); int lfeon = bs.readBits(1); - m_BitRate = (uint32_t)(8.0 * framesize * m_SampleRate / (numBlocks * 256.0)); + m_BitRate = (uint32_t)(8.0 * m_FrameSize * m_SampleRate / (numBlocks * 256.0)); m_Channels = AC3ChannelsTable[channelMode] + lfeon; } m_HeaderFound = true; } if (m_HeaderFound) - m_AC3Buffer[m_AC3BufferPtr++] = buf_ptr[0]; + { + if (m_AC3BufferPtr > AC3_MAX_CODED_FRAME_SIZE - 1) + { + ERRORLOG("error in AC3 frame size"); + m_AC3BufferPtr = 0; + m_HeaderFound = false; + } + else + m_AC3Buffer[m_AC3BufferPtr++] = buf_ptr[0]; + } if (m_FrameSize && m_AC3BufferPtr >= m_FrameSize) { From e3486c2e94a96b02ec6607d0a757d9c051a4c131 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Mon, 10 Dec 2012 17:10:38 +0100 Subject: [PATCH 12/12] vdr-plugin-vnsiserver: fix compile error for vdr versions lower 1.7.28 --- .../pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c index e3104c473..ae53f491a 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/receiver.c @@ -298,7 +298,10 @@ void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Le } break; case 0x80: // STREAMTYPE_USER_PRIVATE - if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // DigiCipher II VIDEO (ANSI/SCTE 57) +#if APIVERSNUM >= 10728 + if (Setup.StandardCompliance == STANDARD_ANSISCTE) +#endif + { // DigiCipher II VIDEO (ANSI/SCTE 57) Vpid = esPid; Ppid = pmt.getPCRPid(); Vtype = 0x02; // compression based upon MPEG-2 @@ -307,7 +310,10 @@ void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Le } // fall through case 0x81: // STREAMTYPE_USER_PRIVATE - if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // ATSC A/53 AUDIO (ANSI/SCTE 57) +#if APIVERSNUM >= 10728 + if (Setup.StandardCompliance == STANDARD_ANSISCTE) +#endif + { // ATSC A/53 AUDIO (ANSI/SCTE 57) char lang[MAXLANGCODE1] = { 0 }; SI::Descriptor *d; for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) { @@ -332,7 +338,10 @@ void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Le } // fall through case 0x82: // STREAMTYPE_USER_PRIVATE - if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // STANDARD SUBTITLE (ANSI/SCTE 27) +#if APIVERSNUM >= 10728 + if (Setup.StandardCompliance == STANDARD_ANSISCTE) +#endif + { // STANDARD SUBTITLE (ANSI/SCTE 27) //TODO break; }