X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=blobdiff_plain;f=lib%2Fdvb%2Fpmt.cpp;h=5b89e8a0d120932980d0569fe13906aeb9670fe0;hp=4ad4e76f0a962e51a1c5b4b296756d430f46e7e6;hb=59df7d4b4fc7d1740f30d36290553972c4a3a652;hpb=aaa6a9751a34e2c0041210eedc3b4fb5915439ce diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index 4ad4e76..5b89e8a 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -18,16 +18,28 @@ #include #include #include +#include + +#include +#include +#include +#include + eDVBServicePMTHandler::eDVBServicePMTHandler() :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF), m_no_pat_entry_delay(eTimer::create()) { m_use_decode_demux = 0; m_pmt_pid = -1; + m_dsmcc_pid = -1; + m_isstreamclient = false; eDVBResourceManager::getInstance(m_resourceManager); CONNECT(m_PMT.tableReady, eDVBServicePMTHandler::PMTready); CONNECT(m_PAT.tableReady, eDVBServicePMTHandler::PATready); CONNECT(m_no_pat_entry_delay->timeout, eDVBServicePMTHandler::sendEventNoPatEntry); + + CONNECT(m_AIT.tableReady, eDVBServicePMTHandler::AITready); + CONNECT(m_OC.tableReady, eDVBServicePMTHandler::OCready); } eDVBServicePMTHandler::~eDVBServicePMTHandler() @@ -44,8 +56,15 @@ void eDVBServicePMTHandler::channelStateChanged(iDVBChannel *channel) && (state == iDVBChannel::state_ok) && (!m_demux)) { if (m_channel) - if (m_channel->getDemux(m_demux, (!m_use_decode_demux) ? 0 : iDVBChannel::capDecode)) + { + if (m_pvr_demux_tmp) + { + m_demux = m_pvr_demux_tmp; + m_pvr_demux_tmp = NULL; + } + else if (m_channel->getDemux(m_demux, (!m_use_decode_demux) ? 0 : iDVBChannel::capDecode)) eDebug("Allocating %s-decoding a demux for now tuned-in channel failed.", m_use_decode_demux ? "" : "non-"); + } serviceEvent(eventTuned); @@ -98,10 +117,11 @@ void eDVBServicePMTHandler::PMTready(int error) { m_have_cached_program = false; serviceEvent(eventNewProgramInfo); + mDemuxId = m_decode_demux_num; if (!m_pvr_channel) // don't send campmt to camd.socket for playbacked services { eEPGCache::getInstance()->PMTready(this); - if(!m_ca_servicePtr) + if(!m_ca_servicePtr && !m_isstreamclient) { int demuxes[2] = {0,0}; uint8_t tmp; @@ -180,6 +200,217 @@ void eDVBServicePMTHandler::PATready(int) serviceEvent(eventNoPAT); } +static void eraseHbbTVApplications(HbbTVApplicationInfoList *applications) +{ + if(applications->size() == 0) + return; + for(HbbTVApplicationInfoListConstIterator info = applications->begin() ; info != applications->end() ; ++info) + delete(*info); + applications->clear(); +} + +void saveData(int orgid, unsigned char* data, int sectionLength) +{ + int fd = 0, rc = 0; + char fileName[255] = {0}; + sprintf(fileName, "/tmp/ait.%d", orgid); + if((fd = open(fileName, O_RDWR|O_CREAT|O_TRUNC)) < 0) + { + eDebug("Fail to save a AIT Data."); + return; + } + rc = write(fd, data, sectionLength); + eDebug("Save Data Len : [%d]", rc); + close(fd); +} + +#include +#include +#include +#define PACK_VERSION(major,minor,micro) (((major) << 16) + ((minor) << 8) + (micro)) +#define UNPACK_VERSION(version,major,minor,micro) { \ + major = (version)&0xff; \ + minor = (version>>8)&0xff; \ + micro = (version>>16)&0xff; \ +} +void eDVBServicePMTHandler::AITready(int error) +{ + eDebug("AITready"); + ePtr > ptr; + if (!m_AIT.getCurrent(ptr)) + { + short profilecode = 0; + int orgid = 0, appid = 0, profileVersion = 0; + m_ApplicationName = m_HBBTVUrl = ""; + + eraseHbbTVApplications(&m_HbbTVApplications); + + memcpy(m_AITData, ptr->getBufferData(), 4096); + + int sectionLength = 0; + for (std::vector::const_iterator it = ptr->getSections().begin(); it != ptr->getSections().end(); ++it) + { + std::list::const_iterator i = (*it)->getApplicationInformation()->begin(); + sectionLength += (*it)->getSectionLength(); + eDebug("Section Length : %d, Total Section Length : %d", (*it)->getSectionLength(), sectionLength); + for (; i != (*it)->getApplicationInformation()->end(); ++i) + { + std::string hbbtvUrl = "", applicaionName = ""; + std::string boundaryExtension = ""; + + int controlCode = (*i)->getApplicationControlCode(); + ApplicationIdentifier * applicationIdentifier = (*i)->getApplicationIdentifier(); + profilecode = 0; + orgid = applicationIdentifier->getOrganisationId(); + appid = applicationIdentifier->getApplicationId(); + eDebug("found applicaions ids >> pid : %x, orgid : %d, appid : %d", m_ait_pid, orgid, appid); + if (controlCode == 1 || controlCode == 2) /* 1:AUTOSTART, 2:ETC */ + { + for (DescriptorConstIterator desc = (*i)->getDescriptors()->begin(); + desc != (*i)->getDescriptors()->end(); ++desc) + { + switch ((*desc)->getTag()) + { + case APPLICATION_DESCRIPTOR: + { + ApplicationDescriptor* applicationDescriptor = (ApplicationDescriptor*)(*desc); + ApplicationProfileList* applicationProfiles = applicationDescriptor->getApplicationProfiles(); + ApplicationProfileConstIterator interactionit = applicationProfiles->begin(); + for(; interactionit != applicationProfiles->end(); ++interactionit) + { + profilecode = (*interactionit)->getApplicationProfile(); + profileVersion = PACK_VERSION( + (*interactionit)->getVersionMajor(), + (*interactionit)->getVersionMinor(), + (*interactionit)->getVersionMicro() + ); + } + break; + } + case APPLICATION_NAME_DESCRIPTOR: + { + ApplicationNameDescriptor *nameDescriptor = (ApplicationNameDescriptor*)(*desc); + ApplicationNameConstIterator interactionit = nameDescriptor->getApplicationNames()->begin(); + for(; interactionit != nameDescriptor->getApplicationNames()->end(); ++interactionit) + { + applicaionName = (*interactionit)->getApplicationName(); + if(controlCode == 1) m_ApplicationName = applicaionName; + break; + } + break; + } + case TRANSPORT_PROTOCOL_DESCRIPTOR: + { + TransportProtocolDescriptor *transport = (TransportProtocolDescriptor*)(*desc); + switch (transport->getProtocolId()) + { + case 1: /* object carousel */ + if (m_dsmcc_pid >= 0) + { + m_OC.begin(eApp, eDVBDSMCCDLDataSpec(m_dsmcc_pid), m_demux); + } + break; + case 2: /* ip */ + break; + case 3: /* interaction */ + { + InterActionTransportConstIterator interactionit = transport->getInteractionTransports()->begin(); + for(; interactionit != transport->getInteractionTransports()->end(); ++interactionit) + { + hbbtvUrl = (*interactionit)->getUrlBase()->getUrl(); + break; + } + break; + } + } + break; + } + case GRAPHICS_CONSTRAINTS_DESCRIPTOR: + break; + case SIMPLE_APPLICATION_LOCATION_DESCRIPTOR: + { + SimpleApplicationLocationDescriptor *applicationlocation = (SimpleApplicationLocationDescriptor*)(*desc); + hbbtvUrl += applicationlocation->getInitialPath(); + break; + } + case APPLICATION_USAGE_DESCRIPTOR: + break; + case SIMPLE_APPLICATION_BOUNDARY_DESCRIPTOR: + break; + } + } + } + if(!hbbtvUrl.empty()) + { + char* uu = hbbtvUrl.c_str(); + if(!strncmp(uu, "http://", 7) || !strncmp(uu, "dvb://", 6) || !strncmp(uu, "https://", 8)) + { + if(controlCode == 1) m_HBBTVUrl = hbbtvUrl; + switch(profileVersion) + { + case 65793: + case 66049: + m_HbbTVApplications.push_back(new HbbTVApplicationInfo(controlCode, orgid, appid, hbbtvUrl, applicaionName, profilecode)); + break; + case 1280: + case 65538: + default: + m_HbbTVApplications.push_back(new HbbTVApplicationInfo((-1)*controlCode, orgid, appid, hbbtvUrl, applicaionName, profilecode)); + break; + } + } + else if (!boundaryExtension.empty()) { + if(boundaryExtension.at(boundaryExtension.length()-1) != '/') { + boundaryExtension += "/"; + } + boundaryExtension += hbbtvUrl; + if(controlCode == 1) m_HBBTVUrl = boundaryExtension; + switch(profileVersion) + { + case 65793: + case 66049: + m_HbbTVApplications.push_back(new HbbTVApplicationInfo(controlCode, orgid, appid, boundaryExtension, applicaionName, profilecode)); + break; + case 1280: + case 65538: + default: + m_HbbTVApplications.push_back(new HbbTVApplicationInfo((-1)*controlCode, orgid, appid, boundaryExtension, applicaionName, profilecode)); + break; + } + } + } + } + } + + if (m_HbbTVApplications.size()) + { + saveData(orgid, m_AITData, sectionLength);//4096); + for(HbbTVApplicationInfoListConstIterator infoiter = m_HbbTVApplications.begin() ; infoiter != m_HbbTVApplications.end() ; ++infoiter) + eDebug("Found : control[%d], name[%s], url[%s]", + (*infoiter)->m_ControlCode, (*infoiter)->m_ApplicationName.c_str(), (*infoiter)->m_HbbTVUrl.c_str()); + serviceEvent(eventHBBTVInfo); + } + else eDebug("No found anything."); + } + /* for now, do not keep listening for table updates */ + m_AIT.stop(); +} + +void eDVBServicePMTHandler::OCready(int error) +{ + eDebug("OCready"); + ePtr > ptr; + if (!m_OC.getCurrent(ptr)) + { + for (std::vector::const_iterator it = ptr->getSections().begin(); it != ptr->getSections().end(); ++it) + { + unsigned char* sectionData = (*it)->getData(); + } + } + /* for now, do not keep listening for table updates */ + m_OC.stop(); +} + PyObject *eDVBServicePMTHandler::getCaIds(bool pair) { ePyObject ret; @@ -218,6 +449,27 @@ PyObject *eDVBServicePMTHandler::getCaIds(bool pair) return ret ? (PyObject*)ret : (PyObject*)PyList_New(0); } +PyObject *eDVBServicePMTHandler::getHbbTVApplications(void) +{ + ePyObject ret= PyList_New(0);; + if(m_HbbTVApplications.size()) + { + for(HbbTVApplicationInfoListConstIterator infoiter = m_HbbTVApplications.begin() ; infoiter != m_HbbTVApplications.end() ; ++infoiter) + { + ePyObject tuple = PyTuple_New(6); + PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong((*infoiter)->m_ControlCode)); + PyTuple_SET_ITEM(tuple, 1, PyString_FromString((*infoiter)->m_ApplicationName.c_str())); + PyTuple_SET_ITEM(tuple, 2, PyString_FromString((*infoiter)->m_HbbTVUrl.c_str())); + PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong((*infoiter)->m_OrgId)); + PyTuple_SET_ITEM(tuple, 4, PyInt_FromLong((*infoiter)->m_AppId)); + PyTuple_SET_ITEM(tuple, 5, PyInt_FromLong((*infoiter)->m_ProfileCode)); + PyList_Append(ret, tuple); + Py_DECREF(tuple); + } + } + return (PyObject*)ret; +} + int eDVBServicePMTHandler::getProgramInfo(program &program) { ePtr > ptr; @@ -232,6 +484,7 @@ int eDVBServicePMTHandler::getProgramInfo(program &program) program.pcrPid = -1; program.pmtPid = -1; program.textPid = -1; + program.aitPid = -1; int first_ac3 = -1; program.defaultAudioStream = 0; @@ -464,9 +717,28 @@ int eDVBServicePMTHandler::getProgramInfo(program &program) audio.type = audioStream::atAACHE; // MPEG4-AAC break; case AC3_DESCRIPTOR: - isaudio = 1; + { + Ac3Descriptor *ac = (Ac3Descriptor*)(*desc); + + isaudio = 1; audio.type = audioStream::atAC3; + + if(ac->getAc3TypeFlag()) + { + + uint8_t ac3type = ac->getAc3Type(); + if( ( ac3type & 0x80 ) && ( (ac3type<<5) == 0xA0 || (ac3type<<5) == 0xC0) ) // From EN-300 468 v1.7.1 Table D.1 + audio.type = audioStream::atDDP; + } + 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); @@ -555,6 +827,38 @@ int eDVBServicePMTHandler::getProgramInfo(program &program) } prev_audio = 0; } + 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) + { + m_ait_pid = -1; + switch ((*desc)->getTag()) + { + case APPLICATION_SIGNALLING_DESCRIPTOR: + m_ait_pid = 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; } @@ -755,12 +1059,13 @@ int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux, return tuneExt(ref, use_decode_demux, s, NULL, cue, simulate, service); } -int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_demux, ePtr &source, const char *streaminfo_file, eCueSheet *cue, bool simulate, eDVBService *service) +int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_demux, ePtr &source, const char *streaminfo_file, eCueSheet *cue, bool simulate, eDVBService *service, bool isstreamclient) { RESULT res=0; m_reference = ref; m_use_decode_demux = use_decode_demux; m_no_pat_entry_delay->stop(); + m_isstreamclient = isstreamclient; /* use given service as backup. This is used for timeshift where we want to clone the live stream using the cache, but in fact have a PVR channel */ m_service = service; @@ -804,7 +1109,9 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem } eDebug("alloc PVR"); /* allocate PVR */ - res = m_resourceManager->allocatePVRChannel(m_pvr_channel); + eDVBChannelID chid; + if (m_isstreamclient) ref.getChannelID(chid); + res = m_resourceManager->allocatePVRChannel(chid, m_pvr_channel); if (res) eDebug("allocatePVRChannel failed!\n"); m_channel = m_pvr_channel; @@ -842,7 +1149,18 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem if (m_pvr_channel) { m_pvr_channel->setCueSheet(cue); - if (source) + + if (m_pvr_channel->getDemux(m_pvr_demux_tmp, (!m_use_decode_demux) ? 0 : iDVBChannel::capDecode)) + { + if (m_isstreamclient) + { + eDebug("Allocating %s-decoding a demux for http channel failed.", m_use_decode_demux ? "" : "non-"); + return -2; + } + else + eDebug("Allocating %s-decoding a demux for PVR channel failed.", m_use_decode_demux ? "" : "non-"); + } + else if (source) m_pvr_channel->playSource(source, streaminfo_file); else m_pvr_channel->playFile(ref.path.c_str()); @@ -881,6 +1199,9 @@ void eDVBServicePMTHandler::free() m_pvr_channel->setCueSheet(0); } + m_OC.stop(); + m_AIT.stop(); + m_PMT.stop(); m_PAT.stop(); m_service = 0;