another small ttx subtitles fix
[enigma2.git] / lib / dvb / pmt.cpp
index c0447b47f8f0aa527fbfb2afea24497d118222c3..279ec74f723eb5e1092f32b79ea833d6cebb669d 100644 (file)
@@ -1,3 +1,4 @@
+#include <lib/base/nconfig.h> // access to python config
 #include <lib/base/eerror.h>
 #include <lib/dvb/pmt.h>
 #include <lib/dvb/specs.h>
@@ -6,6 +7,7 @@
 #include <lib/dvb_ci/dvbci.h>
 #include <lib/dvb/epgcache.h>
 #include <lib/dvb/scan.h>
+#include <lib/dvb_ci/dvbci_session.h>
 #include <dvbsi++/ca_descriptor.h>
 #include <dvbsi++/ca_program_map_section.h>
 #include <dvbsi++/teletext_descriptor.h>
@@ -14,7 +16,7 @@
 #include <dvbsi++/stream_identifier_descriptor.h>
 #include <dvbsi++/subtitling_descriptor.h>
 #include <dvbsi++/teletext_descriptor.h>
-#include <lib/base/nconfig.h> // access to python config
+#include <dvbsi++/video_stream_descriptor.h>
 
 eDVBServicePMTHandler::eDVBServicePMTHandler()
        :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF)
@@ -49,10 +51,13 @@ void eDVBServicePMTHandler::channelStateChanged(iDVBChannel *channel)
                {
                        eDebug("ok ... now we start!!");
 
-                       if (m_pmt_pid == -1)
-                               m_PAT.begin(eApp, eDVBPATSpec(), m_demux);
-                       else
-                               m_PMT.begin(eApp, eDVBPMTSpec(m_pmt_pid, m_reference.getServiceID().get()), m_demux);
+                       if (!m_service || m_service->usePMT())
+                       {
+                               if (m_pmt_pid == -1)
+                                       m_PAT.begin(eApp, eDVBPATSpec(), m_demux);
+                               else
+                                       m_PMT.begin(eApp, eDVBPMTSpec(m_pmt_pid, m_reference.getServiceID().get()), m_demux);
+                       }
 
                        if ( m_service && !m_service->cacheEmpty() )
                                serviceEvent(eventNewProgramInfo);
@@ -213,25 +218,49 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program)
                                        audioStream audio;
                                        audio.component_tag=video.component_tag=-1;
                                        video.type = videoStream::vtMPEG2;
+                                       audio.type = audioStream::atMPEG;
 
                                        switch ((*es)->getType())
                                        {
                                        case 0x1b: // AVC Video Stream (MPEG4 H264)
                                                video.type = videoStream::vtMPEG4_H264;
+                                               isvideo = 1;
+                                               //break; fall through !!!
+                                       case 0x10: // MPEG 4 Part 2
+                                               if (!isvideo)
+                                               {
+                                                       video.type = videoStream::vtMPEG4_Part2;
+                                                       isvideo = 1;
+                                               }
+                                               //break; fall through !!!
                                        case 0x01: // MPEG 1 video
+                                               if (!isvideo)
+                                                       video.type = videoStream::vtMPEG1;
+                                               //break; fall through !!!
                                        case 0x02: // MPEG 2 video
                                                isvideo = 1;
                                                //break; fall through !!!
                                        case 0x03: // MPEG 1 audio
                                        case 0x04: // MPEG 2 audio:
                                                if (!isvideo)
+                                                       isaudio = 1;
+                                               //break; fall through !!!
+                                       case 0x0f: // MPEG 2 AAC
+                                               if (!isvideo && !isaudio)
                                                {
                                                        isaudio = 1;
-                                                       audio.type = audioStream::atMPEG;
+                                                       audio.type = audioStream::atAAC;
                                                }
                                                //break; fall through !!!
+                                       case 0x11: // MPEG 4 AAC
+                                               if (!isvideo && !isaudio)
+                                               {
+                                                       isaudio = 1;
+                                                       audio.type = audioStream::atAACHE;
+                                               }
                                        case 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)
                                                {
@@ -242,6 +271,17 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program)
                                                                   check descriptors to get the exakt type. */
                                                                switch (tag)
                                                                {
+                                                               case AUDIO_STREAM_DESCRIPTOR:
+                                                                       isaudio = 1;
+                                                                       break;
+                                                               case VIDEO_STREAM_DESCRIPTOR:
+                                                               {
+                                                                       isvideo = 1;
+                                                                       VideoStreamDescriptor *d = (VideoStreamDescriptor*)(*desc);
+                                                                       if (d->getMpeg1OnlyFlag())
+                                                                               video.type = videoStream::vtMPEG1;
+                                                                       break;
+                                                               }
                                                                case SUBTITLING_DESCRIPTOR:
                                                                {
                                                                        SubtitlingDescriptor *d = (SubtitlingDescriptor*)(*desc);
@@ -300,9 +340,14 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program)
                                                                        isaudio = 1;
                                                                        audio.type = audioStream::atDTS;
                                                                        break;
+                                                               case 0x2B: // TS_PSI_DT_MPEG2_AAC
+                                                                       isaudio = 1;
+                                                                       audio.type = audioStream::atAAC; // MPEG2-AAC
+                                                                       break;
+                                                               case 0x1C: // TS_PSI_DT_MPEG4_Audio
                                                                case AAC_DESCRIPTOR:
                                                                        isaudio = 1;
-                                                                       audio.type = audioStream::atAAC;
+                                                                       audio.type = audioStream::atAACHE; // MPEG4-AAC
                                                                        break;
                                                                case AC3_DESCRIPTOR:
                                                                        isaudio = 1;
@@ -311,7 +356,7 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program)
                                                                case REGISTRATION_DESCRIPTOR: /* some services don't have a separate AC3 descriptor */
                                                                {
                                                                                /* libdvbsi++ doesn't yet support this descriptor type, so work around. */
-                                                                       if ((*desc)->getLength() != 4)
+                                                                       if ((*desc)->getLength() < 4)
                                                                                break;
                                                                        unsigned char descr[6];
                                                                        (*desc)->writeToBuffer(descr);
@@ -322,11 +367,29 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program)
                                                                                isaudio = 1;
                                                                                audio.type = audioStream::atAC3;
                                                                                break;
+                                                                       case 0x56432d31:
+                                                                               if (descr[6] == 0x01) // subdescriptor tag
+                                                                               {
+                                                                                       if (descr[7] >= 0x90) // profile_level
+                                                                                               video.type = videoStream::vtVC1; // advanced profile
+                                                                                       else
+                                                                                               video.type = videoStream::vtVC1_SM; // simple main
+                                                                                       isvideo = 1;
+                                                                               }
+                                                                               break;
                                                                        default:
                                                                                break;
                                                                        }
                                                                        break;
                                                                }
+                                                               case 0x28: // TS_PSI_DT_AVC
+                                                                       isvideo = 1;
+                                                                       video.type = videoStream::vtMPEG4_H264;
+                                                                       break;
+                                                               case 0x1B: // TS_PSI_DT_MPEG4_Video
+                                                                       isvideo = 1;
+                                                                       video.type = videoStream::vtMPEG4_Part2;
+                                                                       break;
                                                                default:
                                                                        break;
                                                                }
@@ -524,8 +587,15 @@ void eDVBServicePMTHandler::SDTScanEvent(int event)
                                eDebug("no channel list");
                        else
                        {
-                               m_dvb_scan->insertInto(db, true);
-                               eDebug("sdt update done!");
+                               eDVBChannelID chid;
+                               m_reference.getChannelID(chid);
+                               if (chid == m_dvb_scan->getCurrentChannelID())
+                               {
+                                       m_dvb_scan->insertInto(db, true);
+                                       eDebug("sdt update done!");
+                               }
+                               else
+                                       eDebug("ignore sdt update data.... incorrect transponder tuned!!!");
                        }
                        break;
                }
@@ -605,7 +675,7 @@ int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux,
 
                        if (ref.path.empty())
                        {
-                               delete m_dvb_scan;
+                               m_dvb_scan = 0;
                                m_dvb_scan = new eDVBScan(m_channel, true, false);
                                m_dvb_scan->connectEvent(slot(*this, &eDVBServicePMTHandler::SDTScanEvent), m_scan_event_connection);
                        }
@@ -631,7 +701,6 @@ int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux,
 void eDVBServicePMTHandler::free()
 {
        m_dvb_scan = 0;
-       delete m_dvb_scan;
 
        if (m_ca_servicePtr)
        {
@@ -671,10 +740,10 @@ ChannelMap eDVBCAService::exist_channels;
 ePtr<eConnection> eDVBCAService::m_chanAddedConn;
 
 eDVBCAService::eDVBCAService()
-       :m_sn(0), m_prev_build_hash(0), m_sendstate(0), m_retryTimer(eApp)
+       :m_buffer(512), m_prev_build_hash(0), m_sendstate(0), m_retryTimer(eTimer::create(eApp))
 {
        memset(m_used_demux, 0xFF, sizeof(m_used_demux));
-       CONNECT(m_retryTimer.timeout, eDVBCAService::sendCAPMT);
+       CONNECT(m_retryTimer->timeout, eDVBCAService::sendCAPMT);
        Connect();
 }
 
@@ -682,7 +751,6 @@ eDVBCAService::~eDVBCAService()
 {
        eDebug("[eDVBCAService] free service %s", m_service.toString().c_str());
        ::close(m_sock);
-       delete m_sn;
 }
 
 // begin static methods
@@ -859,27 +927,105 @@ channel_data *eDVBCAService::getChannelData(eDVBChannelID &chid)
 }
 // end static methods
 
+#define CA_REPLY_DEBUG
+#define MAX_LENGTH_BYTES 4
+#define MIN_LENGTH_BYTES 1
+
 void eDVBCAService::socketCB(int what)
 {
-       if (what & eSocketNotifier::Read)
-               /*eDebug("[eDVBCAService] data to read\n")*/;
-       if (what & eSocketNotifier::Priority)
-               /*eDebug("[eDVBCAService] priority data to read\n")*/;
+       if (what & (eSocketNotifier::Read | eSocketNotifier::Priority))
+       {
+               char msgbuffer[4096];
+               ssize_t length = read(m_sock, msgbuffer, sizeof(msgbuffer));
+               if (length == -1)
+               {
+                       if (errno != EAGAIN && errno != EINTR && errno != EBUSY)
+                       {
+                               eDebug("[eSocketMMIHandler] read (%m)");
+                               what |= eSocketNotifier::Error;
+                       }
+               } else if (length == 0)
+               {
+                       what |= eSocketNotifier::Hungup;
+               } else
+               {
+                       int len = length;
+                       unsigned char *data = (unsigned char*)msgbuffer;
+                       int clear = 1;
+       // If a new message starts, then the previous message
+       // should already have been processed. Otherwise the
+       // previous message was incomplete and should therefore
+       // be deleted.
+                       if ((len >= 1) && ((data[0] & 0xFF) != 0x9f))
+                               clear = 0;
+                       if ((len >= 2) && ((data[1] & 0x80) != 0x80))
+                               clear = 0;
+                       if ((len >= 3) && ((data[2] & 0x80) != 0x00))
+                               clear = 0;
+                       if (clear)
+                       {
+                               m_buffer.clear();
+#ifdef CA_REPLY_DEBUG
+                               eDebug("clear buffer");
+#endif
+                       }
+#ifdef CA_REPLY_DEBUG
+                       eDebug("Put to buffer:");
+                       for (int i=0; i < len; ++i)
+                               eDebugNoNewLine("%02x ", data[i]);
+                       eDebug("\n--------");
+#endif
+                       m_buffer.write( data, len );
+
+                       while ( m_buffer.size() >= (3 + MIN_LENGTH_BYTES) )
+                       {
+                               unsigned char tmp[3+MAX_LENGTH_BYTES];
+                               m_buffer.peek(tmp, 3+MIN_LENGTH_BYTES);
+                               if (((tmp[0] & 0xFF) != 0x9f) || ((tmp[1] & 0x80) != 0x80) || ((tmp[2] & 0x80) != 0x00))
+                               {
+                                       m_buffer.skip(1);
+#ifdef CA_REPLY_DEBUG
+                                       eDebug("skip %02x", tmp[0]);
+#endif
+                                       continue;
+                               }
+                               if (tmp[3] & 0x80)
+                               {
+                                       int peekLength = (tmp[3] & 0x7f) + 4;
+                                       if (m_buffer.size() < peekLength)
+                                               continue;
+                                       m_buffer.peek(tmp, peekLength);
+                               }
+                               int size=0;
+                               int LengthBytes=eDVBCISession::parseLengthField(tmp+3, size);
+                               int messageLength = 3+LengthBytes+size;
+                               if ( m_buffer.size() >= messageLength )
+                               {
+                                       unsigned char dest[messageLength];
+                                       m_buffer.read(dest, messageLength);
+#ifdef CA_REPLY_DEBUG
+                                       eDebug("dump ca reply:");
+                                       for (int i=0; i < messageLength; ++i)
+                                               eDebugNoNewLine("%02x ", dest[i]);
+                                       eDebug("\n--------");
+#endif
+//                                     /*emit*/ mmi_progress(0, dest, (const void*)(dest+3+LengthBytes), messageLength-3-LengthBytes);
+                               }
+                       }
+               }
+       }
        if (what & eSocketNotifier::Hungup) {
-               /*eDebug("[eDVBCAService] connection closed\n")*/;
+               /*eDebug("[eDVBCAService] connection closed")*/;
                m_sendstate=1;
                sendCAPMT();
        }
        if (what & eSocketNotifier::Error)
-               /*eDebug("[eDVBCAService] connection error\n")*/;
+               eDebug("[eDVBCAService] connection error");
 }
 
 void eDVBCAService::Connect()
 {
-       if (m_sn) {
-               delete m_sn;
-               m_sn=0;
-       }
+       m_sn=0;
        memset(&m_servaddr, 0, sizeof(struct sockaddr_un));
        m_servaddr.sun_family = AF_UNIX;
        strcpy(m_servaddr.sun_path, "/tmp/camd.socket");
@@ -892,7 +1038,7 @@ void eDVBCAService::Connect()
                        int val=1;
                        fcntl(m_sock, F_SETFL, O_NONBLOCK);
                        setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, &val, 4);
-                       m_sn = new eSocketNotifier(eApp, m_sock,
+                       m_sn = eSocketNotifier::create(eApp, m_sock,
                                eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Error|eSocketNotifier::Hungup);
                        CONNECT(m_sn->activated, eDVBCAService::socketCB);
                        
@@ -1044,11 +1190,11 @@ void eDVBCAService::sendCAPMT()
                {
                        case 0xFFFFFFFF:
                                ++m_sendstate;
-                               m_retryTimer.start(0,true);
+                               m_retryTimer->start(0,true);
 //                             eDebug("[eDVBCAService] send failed .. immediate retry");
                                break;
                        default:
-                               m_retryTimer.start(5000,true);
+                               m_retryTimer->start(5000,true);
 //                             eDebug("[eDVBCAService] send failed .. retry in 5 sec");
                                break;
                }
@@ -1059,8 +1205,8 @@ void eDVBCAService::sendCAPMT()
 static PyObject *createTuple(int pid, const char *type)
 {
        PyObject *r = PyTuple_New(2);
-       PyTuple_SetItem(r, 0, PyInt_FromLong(pid));
-       PyTuple_SetItem(r, 1, PyString_FromString(type));
+       PyTuple_SET_ITEM(r, 0, PyInt_FromLong(pid));
+       PyTuple_SET_ITEM(r, 1, PyString_FromString(type));
        return r;
 }
 
@@ -1070,17 +1216,18 @@ static inline void PyList_AppendSteal(PyObject *list, PyObject *item)
        Py_DECREF(item);
 }
 
+extern void PutToDict(ePyObject &dict, const char*key, ePyObject item); // defined in dvb/frontend.cpp
+
 PyObject *eDVBServicePMTHandler::program::createPythonObject()
 {
-       PyObject *r = PyDict_New();
+       ePyObject r = PyDict_New();
+       ePyObject l = PyList_New(0);
 
-       PyObject *l = PyList_New(0);
-       
        PyList_AppendSteal(l, createTuple(0, "pat"));
 
        if (pmtPid != -1)
                PyList_AppendSteal(l, createTuple(pmtPid, "pmt"));
-       
+
        for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
                        i(videoStreams.begin()); 
                        i != videoStreams.end(); ++i)
@@ -1100,7 +1247,8 @@ PyObject *eDVBServicePMTHandler::program::createPythonObject()
 
        if (textPid != -1)
                PyList_AppendSteal(l, createTuple(textPid, "text"));
-               
-       PyDict_SetItemString(r, "pids", l);
+
+       PutToDict(r, "pids", l);
+
        return r;
 }