Пример #1
0
int eDVBPMTParser::getProgramInfo(program &program)
{
	ePtr<eTable<ProgramMapSection> > ptr;
	int ret = -1;

	clearProgramInfo(program);

	if (!m_PMT.getCurrent(ptr))
	{
		audioStream *prev_audio = 0;
		eDVBTableSpec table_spec;
		ptr->getSpec(table_spec);
		program.pmtPid = table_spec.pid < 0x1fff ? table_spec.pid : -1;
		std::vector<ProgramMapSection*>::const_iterator i;
		for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
		{
			const ProgramMapSection &pmt = **i;
			int is_hdmv = 0;

			program.serviceId = pmt.getProgramNumber();
			program.pcrPid = pmt.getPcrPid();

			for (DescriptorConstIterator desc = pmt.getDescriptors()->begin();
				desc != pmt.getDescriptors()->end(); ++desc)
			{
				if ((*desc)->getTag() == CA_DESCRIPTOR)
				{
					CaDescriptor *descr = (CaDescriptor*)(*desc);
					program::capid_pair pair;
					pair.caid = descr->getCaSystemId();
					pair.capid = descr->getCaPid();
					program.caids.push_back(pair);
				}
				else if ((*desc)->getTag() == REGISTRATION_DESCRIPTOR)
				{
					RegistrationDescriptor *d = (RegistrationDescriptor*)(*desc);
					if (d->getFormatIdentifier() == 0x48444d56) // HDMV
						is_hdmv = 1;
				}
			}

			ElementaryStreamInfoConstIterator es;
			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 (streamtype)
				{
				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;
					forced_video = 1;
					//break; fall through !!!
				case 0x03: // MPEG 1 audio
				case 0x04: // MPEG 2 audio:
					if (!isvideo) {
						isaudio = 1;
						forced_audio = 1;
					}
					//break; fall through !!!
				case 0x0f: // MPEG 2 AAC
					if (!isvideo && !isaudio)
					{
						isaudio = 1;
						audio.type = audioStream::atAAC;
						forced_audio = 1;
					}
					//break; fall through !!!
				case 0x11: // MPEG 4 AAC
					if (!isvideo && !isaudio)
					{
						isaudio = 1;
						audio.type = audioStream::atAACHE;
						forced_audio = 1;
					}
				case 0x80: // user private ... but bluray LPCM
				case 0xA0: // bluray secondary LPCM
					if (!isvideo && !isaudio && is_hdmv)
					{
						isaudio = 1;
						audio.type = audioStream::atLPCM;
					}
				case 0x81: // user private ... but bluray AC3
				case 0xA1: // bluray secondary AC3
					if (!isvideo && !isaudio)
					{
						isaudio = 1;
						audio.type = audioStream::atAC3;
					}
				case 0x82: // bluray DTS (dvb user private...)
				case 0xA2: // bluray secondary DTS
					if (!isvideo && !isaudio && is_hdmv)
					{
						isaudio = 1;
						audio.type = audioStream::atDTS;
					}
				case 0x86: // bluray DTS-HD (dvb user private...)
				case 0xA6: // bluray secondary DTS-HD
					if (!isvideo && !isaudio && is_hdmv)
					{
						isaudio = 1;
						audio.type = audioStream::atDTSHD;
					}
				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)
							{
							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);
								const SubtitlingList *list = d->getSubtitlings();
								subtitleStream s;
								s.pid = (*es)->getPid();
								for (SubtitlingConstIterator it(list->begin()); it != list->end(); ++it)
								{
									s.subtitling_type = (*it)->getSubtitlingType();
									switch(s.subtitling_type)
									{
									case 0x10 ... 0x13: // dvb subtitles normal
									case 0x20 ... 0x23: // dvb subtitles hearing impaired
										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();
									std::string language = (*it)->getIso639LanguageCode();
									s.language_code = language;
//								eDebug("add dvb subtitle %s PID %04x, type %d, composition page %d, ancillary_page %d", s.language_code.c_str(), s.pid, s.subtitling_type, s.composition_page_id, s.ancillary_page_id);
									issubtitle = 1;
									program.subtitleStreams.push_back(s);
								}
								break;
							}
							case TELETEXT_DESCRIPTOR:
								if (program.textPid == -1)
								{
									subtitleStream s;
									s.subtitling_type = 0x01; // EBU TELETEXT SUBTITLES
									s.pid = program.textPid = (*es)->getPid();
									TeletextDescriptor *d = (TeletextDescriptor*)(*desc);
									isteletext = 1;
									const VbiTeletextList *list = d->getVbiTeletexts();
									std::string language;
									for (VbiTeletextConstIterator it(list->begin()); it != list->end(); ++it)
									{
										switch((*it)->getTeletextType())
										{
										case 0x02: // Teletext subtitle page
										case 0x05: // Teletext subtitle page for hearing impaired pepople
											language = (*it)->getIso639LanguageCode();
											s.language_code = language;
											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);
											issubtitle=1;
										default:
											break;
										}
									}
								}
								break;
							case DTS_DESCRIPTOR:
								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::atAACHE; // MPEG4-AAC
								break;
							case AC3_DESCRIPTOR:
								isaudio = 1;
								audio.type = audioStream::atAC3;
								break;
							case ENHANCED_AC3_DESCRIPTOR:
								isaudio = 1;
								audio.type = audioStream::atDDP;
								break;
							case REGISTRATION_DESCRIPTOR: /* some services don't have a separate AC3 descriptor */
							{
								RegistrationDescriptor *d = (RegistrationDescriptor*)(*desc);
								switch (d->getFormatIdentifier())
								{
								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'
								{
									const AdditionalIdentificationInfoVector *vec = d->getAdditionalIdentificationInfo();
									if (vec->size() > 1 && (*vec)[0] == 0x01) // subdescriptor tag
									{
										if ((*vec)[1] >= 0x90) // profile_level
											video.type = videoStream::vtVC1; // advanced profile
										else
											video.type = videoStream::vtVC1_SM; // simple main
										isvideo = 1;
									}
								}
								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;
							default:
								break;
							}
						}
						switch (tag)
						{
						case ISO_639_LANGUAGE_DESCRIPTOR:
							if (!isvideo)
							{
								const Iso639LanguageList *languages = ((Iso639LanguageDescriptor*)*desc)->getIso639Languages();
								/* use last language code */
								int cnt=0;
								for (Iso639LanguageConstIterator i=languages->begin(); i != languages->end(); ++i)
								{
									std::string language=(*i)->getIso639LanguageCode();
									if ( cnt==0 )
										audio.language_code = language;
									else
										audio.language_code += "/" + language;
									cnt++;
								}
							}
							break;
						case STREAM_IDENTIFIER_DESCRIPTOR:
							audio.component_tag =
								video.component_tag =
									((StreamIdentifierDescriptor*)*desc)->getComponentTag();
							break;
						case CA_DESCRIPTOR:
						{
							CaDescriptor *descr = (CaDescriptor*)(*desc);
							program::capid_pair pair;
							pair.caid = descr->getCaSystemId();
							pair.capid = descr->getCaPid();
							program.caids.push_back(pair);
							break;
						}
						default:
							break;
						}
					}
					if (!num_descriptors && streamtype == 0x06 && prev_audio)
					{
						prev_audio->rdsPid = (*es)->getPid();
						eDebug("Rds PID %04x detected ? ! ?", prev_audio->rdsPid);
					}
					prev_audio = 0;
					break;
				}
				case 0x05: /* ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private sections */
				{
					for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
						desc != (*es)->getDescriptors()->end(); ++desc)
					{
						switch ((*desc)->getTag())
						{
						case APPLICATION_SIGNALLING_DESCRIPTOR:
							program.aitPid = (*es)->getPid();
							break;
						}
					}
					break;
				}
				case 0x0b: /* ISO/IEC 13818-6 DSM-CC U-N Messages */
				{
					for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
						desc != (*es)->getDescriptors()->end(); ++desc)
					{
						switch ((*desc)->getTag())
						{
						case CAROUSEL_IDENTIFIER_DESCRIPTOR:
							program.dsmccPid = (*es)->getPid();
							break;
						case STREAM_IDENTIFIER_DESCRIPTOR:
							break;
						}
					}
					break;
				}
				default:
					break;
				}
				if (isteletext && (isaudio || isvideo))
				{
					eDebug("ambiguous streamtype for PID %04x detected.. forced as teletext!", (*es)->getPid());
					continue; // continue with next PID
				}
				else if (issubtitle && (isaudio || isvideo))
					eDebug("ambiguous streamtype for PID %04x detected.. forced as subtitle!", (*es)->getPid());
				else if (isaudio && isvideo)
					eDebug("ambiguous streamtype for PID %04x detected.. forced as video!", (*es)->getPid());
				if (issubtitle) // continue with next PID
					continue;
				else if (isvideo)
				{
					video.pid = (*es)->getPid();
					program.videoStreams.push_back(video);
				}
				else if (isaudio)
				{
					audio.pid = (*es)->getPid();
					program.audioStreams.push_back(audio);
					prev_audio = &program.audioStreams.back();
				}
				else
					continue;
			}
		}
		ret = 0;
	}
Пример #2
0
bool CPmt::ParseEsInfo(ElementaryStreamInfo *esinfo, CZapitChannel * const channel)
{
	std::string description = "";
	unsigned char componentTag = 0xFF;
	CZapitAudioChannel::ZapitAudioChannelType audio_type = CZapitAudioChannel::UNKNOWN;

	uint8_t stream_type = esinfo->getType();

	bool audio = false;

	const DescriptorList * dlist = esinfo->getDescriptors();
	DescriptorConstIterator dit;
	for (dit = dlist->begin(); dit != dlist->end(); ++dit) {
		Descriptor * d = *dit;
		switch (d->getTag()) {
		case REGISTRATION_DESCRIPTOR:
			{
				RegistrationDescriptor *sd = (RegistrationDescriptor*) d;
				switch (sd->getFormatIdentifier()) {
				case 0x44545331:
				case 0x44545332:
				case 0x44545333:
					audio_type = CZapitAudioChannel::DTS;
					break;
				case 0x41432d33:
					audio_type = CZapitAudioChannel::AC3;
					break;
				default:
#ifdef DEBUG_PMT
					printf("PMT: REGISTRATION_DESCRIPTOR: %x\n", sd->getFormatIdentifier());
#endif
					break;
				}
			}
			break;
		case ISO_639_LANGUAGE_DESCRIPTOR:
			{
				Iso639LanguageDescriptor * sd = (Iso639LanguageDescriptor*) d;
				const Iso639LanguageList *languages = sd->getIso639Languages();
				Iso639LanguageConstIterator it;
				for (it = languages->begin(); it != languages->end(); ++it) {
					description = (*it)->getIso639LanguageCode();
					break;
				}
			}
			break;
		case STREAM_IDENTIFIER_DESCRIPTOR:
			{
				StreamIdentifierDescriptor *sd = (StreamIdentifierDescriptor*) d;
				componentTag = sd->getComponentTag();
			}
			break;
		case TELETEXT_DESCRIPTOR:
			{
				TeletextDescriptor *td = (TeletextDescriptor*)d;
				const VbiTeletextList *vbilist = td->getVbiTeletexts();
				VbiTeletextConstIterator it;
				DBG("teletext pid %04x\n", esinfo->getPid());
				for (it = vbilist->begin(); it != vbilist->end(); ++it) {
					VbiTeletext * vbi = *it;

					std::string lang = vbi->getIso639LanguageCode();
					uint8_t page = vbi->getTeletextPageNumber();
					uint8_t magazine = vbi->getTeletextMagazineNumber();
					DBG("teletext type %d mag %d page %d lang [%s]\n",
							vbi->getTeletextType(), magazine, page, lang.c_str());
					if (vbi->getTeletextType() == 0x01)
						channel->setTeletextLang(lang);
					else if (vbi->getTeletextType() == 0x02)
						channel->addTTXSubtitle(esinfo->getPid(), lang, magazine, page);
					else if (vbi->getTeletextType() == 0x05)
						channel->addTTXSubtitle(esinfo->getPid(), lang, magazine, page, true);
				}
				channel->setTeletextPid(esinfo->getPid());
			}
			break;
		case SUBTITLING_DESCRIPTOR:
			if(stream_type == 0x06) {
				SubtitlingDescriptor *sd = (SubtitlingDescriptor*) d;
				const SubtitlingList *sublist = sd->getSubtitlings();
				SubtitlingConstIterator it;
				for (it = sublist->begin(); it != sublist->end(); ++it) {
					Subtitling * sub = *it;

					uint16_t composition_page_id = sub->getCompositionPageId();
					uint16_t ancillary_page_id = sub->getAncillaryPageId();
					std::string lang = sub->getIso639LanguageCode();

					channel->addDVBSubtitle(esinfo->getPid(), lang, sub->getSubtitlingType(),
							composition_page_id, ancillary_page_id);
				}
			}
			break;
		case AC3_DESCRIPTOR:
			audio_type = CZapitAudioChannel::AC3;
			break;
		case ENHANCED_AC3_DESCRIPTOR:
			audio_type = CZapitAudioChannel::EAC3;
			break;
		case DTS_DESCRIPTOR:
			audio_type = CZapitAudioChannel::DTS;
			break;
		case AAC_DESCRIPTOR:
			audio_type = CZapitAudioChannel::AAC;
			break;
		case 0xC5: /* User Private descriptor - Canal+ Radio */
			if(d->getLength() >= 25) {
				uint8_t *buf = new uint8_t[2 + d->getLength()];
				if(buf){
					d->writeToBuffer(buf);
					int tsidonid =  channel->getTransportStreamId() << 16 | channel->getOriginalNetworkId();
					description = convertDVBUTF8((const char*)&buf[3], 24, 2, tsidonid);
					delete []buf;
				}
			}
			break;
		case AUDIO_STREAM_DESCRIPTOR:
			break;
		case VIDEO_STREAM_DESCRIPTOR:
			break;
		case CA_DESCRIPTOR:
			break;
		default:
			{
#ifdef DEBUG_PMT_UNUSED
				printf("PMT: descriptor %02x: ", d->getTag());
				uint8_t len = 2+d->getLength();
				uint8_t buf[len];
				d->writeToBuffer(buf);
				for(uint8_t i = 0; i < len; i++)
					printf("%02x ", buf[i]);
				printf("\n");
#endif
			}
			break;
		}
	}
	switch (stream_type) {
	case 0x01:
	case 0x02:
	case 0x1b: // AVC Video Stream (MPEG4 H264)
		channel->setVideoPid(esinfo->getPid());
		channel->type = (stream_type == 0x1b); //FIXME
		DBG("vpid %04x stream %d type %d\n", esinfo->getPid(), stream_type, channel->type);
		break;
	case 0x03:
	case 0x04:
		audio_type = CZapitAudioChannel::MPEG;
		audio = true;
		break;
	case 0x06:
		if(audio_type != CZapitAudioChannel::UNKNOWN)
			audio = true;
		break;
	case 0x0F: // AAC ADTS
	case 0x11: // AAC LATM
		audio_type = CZapitAudioChannel::AAC;
		audio = true;
		break;
	case 0x81:
		audio_type = CZapitAudioChannel::AC3;
		audio = true;
		break;
	default:
#ifdef DEBUG_PMT_UNUSED
		printf("PMT: pid %04x stream_type: %02x\n", esinfo->getPid(), stream_type);
#endif
		break;
	}
	if(audio) {
		if(description.empty()) {
			char str[DESC_MAX_LEN];
//			snprintf(str, DESC_MAX_LEN, "Unknown 0x%04x", esinfo->getPid());
			snprintf(str, DESC_MAX_LEN, "Unknown");
			description = str;
		}
		DBG("apid %04x stream %02x type %d [%s]\n", esinfo->getPid(), stream_type,
				(int) audio_type, description.c_str());
		if(CServiceScan::getInstance()->Scanning()) {
			if(channel->getPreAudioPid() == 0)
				channel->setAudioPid(esinfo->getPid());
		} else
			channel->addAudioChannel(esinfo->getPid(), audio_type, description, componentTag);
	}
	return true;
}
Пример #3
0
void eDVBScan::PMTready(int err)
{
	SCAN_eDebug("[eDVBScan] got pmt %d", err);
	if (!err)
	{
		bool scrambled = false;
		bool have_audio = false;
		bool have_video = false;
		unsigned short pcrpid = 0xFFFF;
		std::vector<ProgramMapSection*>::const_iterator i;

		for (i = m_PMT->getSections().begin(); i != m_PMT->getSections().end(); ++i)
		{
			const ProgramMapSection &pmt = **i;
			if (pcrpid == 0xFFFF)
				pcrpid = pmt.getPcrPid();
			else
				SCAN_eDebug("[eDVBScan]   already have a pcrpid %04x %04x", pcrpid, pmt.getPcrPid());
			ElementaryStreamInfoConstIterator es;
			for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
			{
				int isaudio = 0, isvideo = 0, is_scrambled = 0, forced_audio = 0, forced_video = 0;
				switch ((*es)->getType())
				{
				case 0x1b: // AVC Video Stream (MPEG4 H264)
				case 0x24: // H265 HEVC
				case 0x10: // MPEG 4 Part 2
				case 0x01: // MPEG 1 video
				case 0x02: // MPEG 2 video
					isvideo = 1;
					forced_video = 1;
					//break; fall through !!!
				case 0x03: // MPEG 1 audio
				case 0x04: // MPEG 2 audio
				case 0x0f: // MPEG 2 AAC
				case 0x11: // MPEG 4 AAC
					if (!isvideo)
					{
						forced_audio = 1;
						isaudio = 1;
					}
				case 0x06: // PES Private
				case 0x81: // user private
				case 0xEA: // TS_PSI_ST_SMPTE_VC1
					for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
							desc != (*es)->getDescriptors()->end(); ++desc)
					{
						uint8_t tag = (*desc)->getTag();
						/* PES private can contain AC-3, DTS or lots of other stuff.
						   check descriptors to get the exakt type. */
						if (!forced_video && !forced_audio)
						{
							switch (tag)
							{
							case 0x1C: // TS_PSI_DT_MPEG4_Audio
							case 0x2B: // TS_PSI_DT_MPEG2_AAC
							case AAC_DESCRIPTOR:
							case AC3_DESCRIPTOR:
							case DTS_DESCRIPTOR:
							case AUDIO_STREAM_DESCRIPTOR:
								isaudio = 1;
								break;
							case 0x28: // TS_PSI_DT_AVC
							case 0x1B: // TS_PSI_DT_MPEG4_Video
							case VIDEO_STREAM_DESCRIPTOR:
								isvideo = 1;
								break;
							case REGISTRATION_DESCRIPTOR: /* some services don't have a separate AC3 descriptor */
							{
								RegistrationDescriptor *d = (RegistrationDescriptor*)(*desc);
								switch (d->getFormatIdentifier())
								{
								case 0x44545331 ... 0x44545333: // DTS1/DTS2/DTS3
								case 0x41432d33: // == 'AC-3'
								case 0x42535344: // == 'BSSD' (LPCM)
									isaudio = 1;
									break;
								case 0x56432d31: // == 'VC-1'
									isvideo = 1;
									break;
								default:
									break;
								}
							}
							default:
								break;
							}
						}
						if (tag == CA_DESCRIPTOR)
							is_scrambled = 1;
					}
				default:
					break;
				}
				if (isvideo)
					have_video = true;
				else if (isaudio)
					have_audio = true;
				else
					continue;
				if (is_scrambled)
					scrambled = true;
			}
			for (DescriptorConstIterator desc = pmt.getDescriptors()->begin();
				desc != pmt.getDescriptors()->end(); ++desc)
			{
				if ((*desc)->getTag() == CA_DESCRIPTOR)
					scrambled = true;
			}
		}
		m_pmt_in_progress->second.scrambled = scrambled;
		if ( have_video )
			m_pmt_in_progress->second.serviceType = 1;
		else if ( have_audio )
			m_pmt_in_progress->second.serviceType = 2;
		else
			m_pmt_in_progress->second.serviceType = 100;
	}
Пример #4
0
int eDVBServicePMTHandler::getProgramInfo(program &program)
{
	ePtr<eTable<ProgramMapSection> > ptr;
	int cached_apid_ac3 = -1;
	int cached_apid_mpeg = -1;
	int cached_vpid = -1;
	int cached_tpid = -1;
	int ret = -1;

	if (m_have_cached_program)
	{
		program = m_cached_program;
		return 0;
	}

	program.videoStreams.clear();
	program.audioStreams.clear();
	program.subtitleStreams.clear();
	program.pcrPid = -1;
	program.pmtPid = -1;
	program.textPid = -1;
	program.aitPid = -1;

	program.defaultAudioStream = 0;
	program.defaultSubtitleStream = -1;

	if ( m_service && !m_service->cacheEmpty() )
	{
		cached_vpid = m_service->getCacheEntry(eDVBService::cVPID);
		cached_apid_mpeg = m_service->getCacheEntry(eDVBService::cAPID);
		cached_apid_ac3 = m_service->getCacheEntry(eDVBService::cAC3PID);
		cached_tpid = m_service->getCacheEntry(eDVBService::cTPID);
	}

	if ( ((m_service && m_service->usePMT()) || !m_service) && !m_PMT.getCurrent(ptr))
	{
		int first_ac3 = -1;
		int audio_cached = -1;
		int autoaudio_mpeg = -1;
		int autoaudio_ac3 = -1;
		int autoaudio_level = 4;

		std::string configvalue;
		std::vector<std::string> autoaudio_languages;
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.audio_autoselect1", configvalue) && configvalue != "None")
			autoaudio_languages.push_back(configvalue);
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.audio_autoselect2", configvalue) && configvalue != "None")
			autoaudio_languages.push_back(configvalue);
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.audio_autoselect3", configvalue) && configvalue != "None")
			autoaudio_languages.push_back(configvalue);
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.audio_autoselect4", configvalue) && configvalue != "None")
			autoaudio_languages.push_back(configvalue);

		audioStream *prev_audio = 0;

		int autosub_txt_normal = -1;
		int autosub_txt_hearing = -1;
		int autosub_dvb_normal = -1;
		int autosub_dvb_hearing = -1;
		int autosub_level =4;

		std::vector<std::string> autosub_languages;
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.subtitle_autoselect1", configvalue) && configvalue != "None")
			autosub_languages.push_back(configvalue);
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.subtitle_autoselect2", configvalue) && configvalue != "None")
			autosub_languages.push_back(configvalue);
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.subtitle_autoselect3", configvalue) && configvalue != "None")
			autosub_languages.push_back(configvalue);
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.subtitle_autoselect4", configvalue) && configvalue != "None")
			autosub_languages.push_back(configvalue);

		eDVBTableSpec table_spec;
		ptr->getSpec(table_spec);
		program.pmtPid = table_spec.pid < 0x1fff ? table_spec.pid : -1;
		std::vector<ProgramMapSection*>::const_iterator i;
		for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
		{
			const ProgramMapSection &pmt = **i;
			int is_hdmv = 0;

			program.pcrPid = pmt.getPcrPid();

			for (DescriptorConstIterator desc = pmt.getDescriptors()->begin();
				desc != pmt.getDescriptors()->end(); ++desc)
			{
				if ((*desc)->getTag() == CA_DESCRIPTOR)
				{
					CaDescriptor *descr = (CaDescriptor*)(*desc);
					program::capid_pair pair;
					pair.caid = descr->getCaSystemId();
					pair.capid = descr->getCaPid();
					program.caids.push_back(pair);
				}
				else if ((*desc)->getTag() == REGISTRATION_DESCRIPTOR)
				{
					RegistrationDescriptor *d = (RegistrationDescriptor*)(*desc);
					if (d->getFormatIdentifier() == 0x48444d56) // HDMV
						is_hdmv = 1;
				}
			}

			ElementaryStreamInfoConstIterator es;
			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 (streamtype)
				{
				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;
					forced_video = 1;
					//break; fall through !!!
				case 0x03: // MPEG 1 audio
				case 0x04: // MPEG 2 audio:
					if (!isvideo) {
						isaudio = 1;
						forced_audio = 1;
					}
					//break; fall through !!!
				case 0x0f: // MPEG 2 AAC
					if (!isvideo && !isaudio)
					{
						isaudio = 1;
						audio.type = audioStream::atAAC;
						forced_audio = 1;
					}
					//break; fall through !!!
				case 0x11: // MPEG 4 AAC
					if (!isvideo && !isaudio)
					{
						isaudio = 1;
						audio.type = audioStream::atAACHE;
						forced_audio = 1;
					}
				case 0x80: // user private ... but bluray LPCM
				case 0xA0: // bluray secondary LPCM
					if (!isvideo && !isaudio && is_hdmv)
					{
						isaudio = 1;
						audio.type = audioStream::atLPCM;
					}
				case 0x81: // user private ... but bluray AC3
				case 0xA1: // bluray secondary AC3
					if (!isvideo && !isaudio)
					{
						isaudio = 1;
						audio.type = audioStream::atAC3;
					}
				case 0x82: // bluray DTS (dvb user private...)
				case 0xA2: // bluray secondary DTS
					if (!isvideo && !isaudio && is_hdmv)
					{
						isaudio = 1;
						audio.type = audioStream::atDTS;
					}
				case 0x86: // bluray DTS-HD (dvb user private...)
				case 0xA6: // bluray secondary DTS-HD
					if (!isvideo && !isaudio && is_hdmv)
					{
						isaudio = 1;
						audio.type = audioStream::atDTSHD;
					}
				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)
							{
							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);
								const SubtitlingList *list = d->getSubtitlings();
								subtitleStream s;
								s.pid = (*es)->getPid();
								for (SubtitlingConstIterator it(list->begin()); it != list->end(); ++it)
								{
									s.subtitling_type = (*it)->getSubtitlingType();
									switch(s.subtitling_type)
									{
									case 0x10 ... 0x13: // dvb subtitles normal
									case 0x20 ... 0x23: // dvb subtitles hearing impaired
										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();
									std::string language = (*it)->getIso639LanguageCode();
									s.language_code = language;
//								eDebug("add dvb subtitle %s PID %04x, type %d, composition page %d, ancillary_page %d", s.language_code.c_str(), s.pid, s.subtitling_type, s.composition_page_id, s.ancillary_page_id);

									if (!language.empty())
									{
										int x = 1;
										for (std::vector<std::string>::iterator it2 = autosub_languages.begin();x <= autosub_level && it2 != autosub_languages.end();x++,it2++)
										{
											if ((*it2).find(language) != std::string::npos)
											{
												autosub_level = x;
												if (s.subtitling_type >= 0x20)
													autosub_dvb_hearing = program.subtitleStreams.size();
												else
													autosub_dvb_normal = program.subtitleStreams.size();
												break;
											}
										}
									}
									issubtitle = 1;
									program.subtitleStreams.push_back(s);
								}
								break;
							}
							case TELETEXT_DESCRIPTOR:
								if ( program.textPid == -1 || (*es)->getPid() == cached_tpid )
								{
									subtitleStream s;
									s.subtitling_type = 0x01; // EBU TELETEXT SUBTITLES
									s.pid = program.textPid = (*es)->getPid();
									TeletextDescriptor *d = (TeletextDescriptor*)(*desc);
									isteletext = 1;
									const VbiTeletextList *list = d->getVbiTeletexts();
									std::string language;
									for (VbiTeletextConstIterator it(list->begin()); it != list->end(); ++it)
									{
										switch((*it)->getTeletextType())
										{
										case 0x02: // Teletext subtitle page
										case 0x05: // Teletext subtitle page for hearing impaired pepople
											language = (*it)->getIso639LanguageCode();
											s.language_code = language;
											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);
											if (!language.empty())
											{
												int x = 1;
												for (std::vector<std::string>::iterator it2 = autosub_languages.begin();x <= autosub_level && it2 != autosub_languages.end();x++,it2++)
												{
													if ((*it2).find(language) != std::string::npos)
													{
														autosub_level = x;
														if (s.subtitling_type == 0x05)
															autosub_txt_hearing = program.subtitleStreams.size();
														else
															autosub_txt_normal = program.subtitleStreams.size();
														break;
													}
												}
											}
											program.subtitleStreams.push_back(s);
											issubtitle=1;
										default:
											break;
										}
									}
								}
								break;
							case DTS_DESCRIPTOR:
								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::atAACHE; // MPEG4-AAC
								break;
							case AC3_DESCRIPTOR:
								isaudio = 1;
								audio.type = audioStream::atAC3;
								break;
							case ENHANCED_AC3_DESCRIPTOR:
								isaudio = 1;
								audio.type = audioStream::atDDP;
								break;
							case REGISTRATION_DESCRIPTOR: /* some services don't have a separate AC3 descriptor */
							{
								RegistrationDescriptor *d = (RegistrationDescriptor*)(*desc);
								switch (d->getFormatIdentifier())
								{
								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'
								{
									const AdditionalIdentificationInfoVector *vec = d->getAdditionalIdentificationInfo();
									if (vec->size() > 1 && (*vec)[0] == 0x01) // subdescriptor tag
									{
										if ((*vec)[1] >= 0x90) // profile_level
											video.type = videoStream::vtVC1; // advanced profile
										else
											video.type = videoStream::vtVC1_SM; // simple main
										isvideo = 1;
									}
								}
								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;
							default:
								break;
							}
						}
						switch (tag)
						{
						case ISO_639_LANGUAGE_DESCRIPTOR:
							if (!isvideo)
							{
								const Iso639LanguageList *languages = ((Iso639LanguageDescriptor*)*desc)->getIso639Languages();
								/* use last language code */
								int cnt=0;
								for (Iso639LanguageConstIterator i=languages->begin(); i != languages->end(); ++i)
								{
									std::string language=(*i)->getIso639LanguageCode();
									if ( cnt==0 )
										audio.language_code = language;
									else
										audio.language_code += "/" + language;
									cnt++;
										
									if (!language.empty())
									{
										int x = 1;
										for (std::vector<std::string>::iterator it = autoaudio_languages.begin();x <= autoaudio_level && it != autoaudio_languages.end();x++,it++)
										{
											if ((*it).find(language) != std::string::npos)
											{
												if (audio.type == audioStream::atMPEG && (autoaudio_level > x || autoaudio_mpeg == -1)) 
													autoaudio_mpeg = program.audioStreams.size();
												else if (audio.type != audioStream::atMPEG && (autoaudio_level > x || autoaudio_ac3 == -1))
													autoaudio_ac3 = program.audioStreams.size();
												autoaudio_level = x;
												break;
											}
										}
									}
								}
							}
							break;
						case STREAM_IDENTIFIER_DESCRIPTOR:
							audio.component_tag =
								video.component_tag =
									((StreamIdentifierDescriptor*)*desc)->getComponentTag();
							break;
						case CA_DESCRIPTOR:
						{
							CaDescriptor *descr = (CaDescriptor*)(*desc);
							program::capid_pair pair;
							pair.caid = descr->getCaSystemId();
							pair.capid = descr->getCaPid();
							program.caids.push_back(pair);
							break;
						}
						default:
							break;
						}
					}
					if (!num_descriptors && streamtype == 0x06 && prev_audio)
					{
						prev_audio->rdsPid = (*es)->getPid();
						eDebug("Rds PID %04x detected ? ! ?", prev_audio->rdsPid);
					}
					prev_audio = 0;
					break;
				}
				case 0x05: /* ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private sections */
				{
					for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
						desc != (*es)->getDescriptors()->end(); ++desc)
					{
						switch ((*desc)->getTag())
						{
						case APPLICATION_SIGNALLING_DESCRIPTOR:
							program.aitPid = (*es)->getPid();
							m_AIT.begin(eApp, eDVBAITSpec(program.aitPid), m_demux);
							break;
						}
					}
					break;
				}
				case 0x0b: /* ISO/IEC 13818-6 DSM-CC U-N Messages */
				{
					for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
						desc != (*es)->getDescriptors()->end(); ++desc)
					{
						switch ((*desc)->getTag())
						{
						case CAROUSEL_IDENTIFIER_DESCRIPTOR:
							m_dsmcc_pid = (*es)->getPid();
							break;
						case STREAM_IDENTIFIER_DESCRIPTOR:
							break;
						}
					}
					break;
				}
				default:
					break;
				}
				if (isteletext && (isaudio || isvideo))
				{
					eDebug("ambiguous streamtype for PID %04x detected.. forced as teletext!", (*es)->getPid());
					continue; // continue with next PID
				}
				else if (issubtitle && (isaudio || isvideo))
					eDebug("ambiguous streamtype for PID %04x detected.. forced as subtitle!", (*es)->getPid());
				else if (isaudio && isvideo)
					eDebug("ambiguous streamtype for PID %04x detected.. forced as video!", (*es)->getPid());
				if (issubtitle) // continue with next PID
					continue;
				else if (isvideo)
				{
					video.pid = (*es)->getPid();
					if ( !program.videoStreams.empty() && video.pid == cached_vpid )
					{
						program.videoStreams.push_back(program.videoStreams[0]);
						program.videoStreams[0] = video;
					}
					else
						program.videoStreams.push_back(video);
				}
				else if (isaudio)
				{
					audio.pid = (*es)->getPid();

					/* if we find the cached pids, this will be our default stream */
					if (audio.pid == cached_apid_ac3 || audio.pid == cached_apid_mpeg)
						audio_cached = program.audioStreams.size();

					/* also, we need to know the first non-mpeg (i.e. "ac3"/dts/...) stream */
					if ((audio.type != audioStream::atMPEG) && ((first_ac3 == -1) || (audio.pid == cached_apid_ac3)))
						first_ac3 = program.audioStreams.size();

					program.audioStreams.push_back(audio);
					prev_audio = &program.audioStreams.back();
				}
				else
					continue;
			}
		}
		ret = 0;

		bool defaultac3 = false;
		bool useaudio_cache = false;

		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.audio_defaultac3", configvalue))
			defaultac3 = configvalue == "True";
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.audio_usecache", configvalue))
			useaudio_cache = configvalue == "True";

		if (useaudio_cache && audio_cached != -1)
			program.defaultAudioStream = audio_cached;
		else if ( defaultac3 )
		{
			if ( autoaudio_ac3 != -1 )
				program.defaultAudioStream = autoaudio_ac3;
			else if ( autoaudio_mpeg != -1 )
				program.defaultAudioStream = autoaudio_mpeg;
			else if ( first_ac3 != -1 )
				program.defaultAudioStream = first_ac3;
		}
		else
		{
			if ( autoaudio_mpeg != -1 )
				program.defaultAudioStream = autoaudio_mpeg;
			else if ( autoaudio_ac3 != -1 )
				program.defaultAudioStream = autoaudio_ac3;
		}

		bool allow_hearingimpaired = false;
		bool default_hearingimpaired = false;
		bool defaultdvb = false;
		int equallanguagemask = false;

		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.subtitle_hearingimpaired", configvalue))
			allow_hearingimpaired = configvalue == "True";
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.subtitle_defaultimpaired", configvalue))
			default_hearingimpaired = configvalue == "True";
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.subtitle_defaultdvb", configvalue))
			defaultdvb = configvalue == "True";
		if (!ePythonConfigQuery::getConfigValue("config.autolanguage.equal_languages", configvalue))
			equallanguagemask = atoi(configvalue.c_str());

		if (defaultdvb)
		{
			if (allow_hearingimpaired && default_hearingimpaired && autosub_dvb_hearing != -1)
				program.defaultSubtitleStream = autosub_dvb_hearing;
			else if (autosub_dvb_normal != -1)
				program.defaultSubtitleStream = autosub_dvb_normal;
			else if (allow_hearingimpaired && autosub_dvb_hearing != -1)
				program.defaultSubtitleStream = autosub_dvb_hearing;
			else if (allow_hearingimpaired && default_hearingimpaired && autosub_txt_hearing != -1)
				program.defaultSubtitleStream = autosub_txt_hearing;
			else if (autosub_txt_normal != -1)
				program.defaultSubtitleStream = autosub_txt_normal;
			else if (allow_hearingimpaired && autosub_dvb_hearing != -1)
				program.defaultSubtitleStream = autosub_txt_hearing;
		}
		else
		{
			if (allow_hearingimpaired && default_hearingimpaired && autosub_txt_hearing != -1)
				program.defaultSubtitleStream = autosub_txt_hearing;
			else if (autosub_txt_normal != -1)
				program.defaultSubtitleStream = autosub_txt_normal;
			else if (allow_hearingimpaired && autosub_txt_hearing != -1)
				program.defaultSubtitleStream = autosub_txt_hearing;
			else if (allow_hearingimpaired && default_hearingimpaired && autosub_dvb_hearing != -1)
				program.defaultSubtitleStream = autosub_dvb_hearing;
			else if (autosub_dvb_normal != -1)
				program.defaultSubtitleStream = autosub_dvb_normal;
			else if (allow_hearingimpaired && autosub_dvb_hearing != -1)
				program.defaultSubtitleStream = autosub_dvb_hearing;
		}
		if (program.defaultSubtitleStream != -1 && (equallanguagemask & (1<<(autosub_level-1))) == 0 && program.subtitleStreams[program.defaultSubtitleStream].language_code.compare(program.audioStreams[program.defaultAudioStream].language_code) == 0 )
			program.defaultSubtitleStream = -1;
	}