prepare for dvb subtitle support (not finished yet)
authorAndreas Monzner <andreas.monzner@multimedia-labs.de>
Mon, 23 Oct 2006 10:52:20 +0000 (10:52 +0000)
committerAndreas Monzner <andreas.monzner@multimedia-labs.de>
Mon, 23 Oct 2006 10:52:20 +0000 (10:52 +0000)
cache query of eDVBServicePMThandler::getProgram

lib/dvb/Makefile.am
lib/dvb/pmt.cpp
lib/dvb/pmt.h
lib/dvb/subtitle.cpp [new file with mode: 0644]
lib/dvb/subtitle.h [new file with mode: 0644]
lib/dvb/teletext.cpp
lib/service/servicedvb.cpp
lib/service/servicedvb.h

index 98f4030..bac0375 100644 (file)
@@ -6,5 +6,5 @@ noinst_LIBRARIES = libenigma_dvb.a
 libenigma_dvb_a_SOURCES = dvb.cpp demux.cpp frontend.cpp esection.cpp db.cpp \
        sec.cpp scan.cpp crc32.cpp pmt.cpp decoder.cpp eit.cpp rotor_calc.cpp \
        epgcache.cpp dvbtime.cpp metaparser.cpp volume.cpp tstools.cpp pvrparse.cpp \
-       pesparse.cpp teletext.cpp radiotext.cpp
+       pesparse.cpp teletext.cpp radiotext.cpp subtitle.cpp
 
index d6f002e..ccc7796 100644 (file)
@@ -12,6 +12,7 @@
 #include <dvbsi++/descriptor_tag.h>
 #include <dvbsi++/iso639_language_descriptor.h>
 #include <dvbsi++/stream_identifier_descriptor.h>
+#include <dvbsi++/subtitling_descriptor.h>
 
 eDVBServicePMTHandler::eDVBServicePMTHandler()
        :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF)
@@ -83,6 +84,7 @@ void eDVBServicePMTHandler::PMTready(int error)
                serviceEvent(eventNoPMT);
        else
        {
+               m_have_cached_program = false;
                serviceEvent(eventNewProgramInfo);
                eEPGCache::getInstance()->PMTready(this);
                if (!m_pvr_channel) // don't send campmt to camd.socket for playbacked services
@@ -164,6 +166,7 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program)
        int cached_apid_mpeg = -1;
        int cached_vpid = -1;
        int cached_tpid = -1;
+       int ret = -1;
 
        program.videoStreams.clear();
        program.audioStreams.clear();
@@ -181,136 +184,151 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program)
 
        if ( ((m_service && m_service->usePMT()) || !m_service) && !m_PMT.getCurrent(ptr))
        {
-               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)
+               if (m_have_cached_program)
                {
-                       const ProgramMapSection &pmt = **i;
-                       program.pcrPid = pmt.getPcrPid();
-                       
-                       ElementaryStreamInfoConstIterator es;
-                       for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
+                       program = m_cached_program;
+                       ret = 0;
+               }
+               else
+               {
+                       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)
                        {
-                               int isaudio = 0, isvideo = 0;
-                               videoStream video;
-                               audioStream audio;
-                               audio.component_tag=-1;
-                               video.component_tag=-1;
-
-                               video.pid = (*es)->getPid();
-                               audio.pid = (*es)->getPid();
-                               video.type = videoStream::vtMPEG2;
-
-                               switch ((*es)->getType())
+                               const ProgramMapSection &pmt = **i;
+                               program.pcrPid = pmt.getPcrPid();
+                       
+                               ElementaryStreamInfoConstIterator es;
+                               for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
                                {
-                               case 0x1b: // AVC Video Stream (MPEG4 H264)
-                                       video.type = videoStream::vtMPEG4_H264;
-                               case 0x01: // MPEG 1 video
-                               case 0x02: // MPEG 2 video
-                                       isvideo = 1;
-                                       //break; fall through !!!
-                               case 0x03: // MPEG 1 audio
-                               case 0x04: // MPEG 2 audio:
-                                       if (!isvideo)
-                                       {
-                                               isaudio = 1;
-                                               audio.type = audioStream::atMPEG;
-                                       }
-                                       //break; fall through !!!
-                               case 0x06: // PES Private
-                                               /* PES private can contain AC-3, DTS or lots of other stuff.
-                                                  check descriptors to get the exact type. */
-                                       for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
-                                                       desc != (*es)->getDescriptors()->end(); ++desc)
+                                       int isaudio = 0, isvideo = 0;
+                                       videoStream video;
+                                       audioStream audio;
+                                       audio.component_tag=video.component_tag=-1;
+                                       video.type = videoStream::vtMPEG2;
+
+                                       switch ((*es)->getType())
                                        {
-                                               switch ((*desc)->getTag())
+                                       case 0x1b: // AVC Video Stream (MPEG4 H264)
+                                               video.type = videoStream::vtMPEG4_H264;
+                                       case 0x01: // MPEG 1 video
+                                       case 0x02: // MPEG 2 video
+                                               isvideo = 1;
+                                               //break; fall through !!!
+                                       case 0x03: // MPEG 1 audio
+                                       case 0x04: // MPEG 2 audio:
+                                               if (!isvideo)
+                                               {
+                                                       isaudio = 1;
+                                                       audio.type = audioStream::atMPEG;
+                                               }
+                                               //break; fall through !!!
+                                       case 0x06: // PES Private
+                                                       /* PES private can contain AC-3, DTS or lots of other stuff.
+                                                          check descriptors to get the exact type. */
+                                               for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
+                                                               desc != (*es)->getDescriptors()->end(); ++desc)
                                                {
-                                               case TELETEXT_DESCRIPTOR:
-                                                       if ( program.textPid == -1 || (*es)->getPid() == cached_tpid )
-                                                               program.textPid = (*es)->getPid();
-                                                       break;
-                                               case DTS_DESCRIPTOR:
-                                                       if (!isvideo)
+                                                       switch ((*desc)->getTag())
                                                        {
+                                                       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();
+                                                                       s.composition_page_id = (*it)->getCompositionPageId();
+                                                                       s.ancillary_page_id = (*it)->getAncillaryPageId();
+                                                                       s.language_code = (*it)->getIso639LanguageCode();
+                                                                       program.subtitleStreams.push_back(s);
+                                                               }
+                                                               break;
+                                                       }
+                                                       case TELETEXT_DESCRIPTOR:
+                                                               if ( program.textPid == -1 || (*es)->getPid() == cached_tpid )
+                                                                       program.textPid = (*es)->getPid();
+                                                               break;
+                                                       case DTS_DESCRIPTOR:
                                                                isaudio = 1;
                                                                audio.type = audioStream::atDTS;
-                                                       }
-                                                       break;
-                                               case AAC_DESCRIPTOR:
-                                                       if (!isvideo)
-                                                       {
+                                                               break;
+                                                       case AAC_DESCRIPTOR:
                                                                isaudio = 1;
                                                                audio.type = audioStream::atAAC;
-                                                       }
-                                                       break;
-                                               case AC3_DESCRIPTOR:
-                                                       if (!isvideo)
-                                                       {
+                                                               break;
+                                                       case AC3_DESCRIPTOR:
                                                                isaudio = 1;
                                                                audio.type = audioStream::atAC3;
-                                                       }
-                                                       break;
-                                               case ISO_639_LANGUAGE_DESCRIPTOR:
-                                                       if (!isvideo)
+                                                               break;
+                                                       case ISO_639_LANGUAGE_DESCRIPTOR:
+                                                               if (!isvideo)
+                                                               {
+                                                                       const Iso639LanguageList *languages = ((Iso639LanguageDescriptor*)*desc)->getIso639Languages();
+                                                                               /* use last language code */
+                                                                       for (Iso639LanguageConstIterator i(languages->begin()); i != languages->end(); ++i)
+                                                                               audio.language_code = (*i)->getIso639LanguageCode();
+                                                               }
+                                                               break;
+                                                       case STREAM_IDENTIFIER_DESCRIPTOR:
+                                                               audio.component_tag =
+                                                                       video.component_tag =
+                                                                               ((StreamIdentifierDescriptor*)*desc)->getComponentTag();
+                                                               break;
+                                                       case CA_DESCRIPTOR:
                                                        {
-                                                               const Iso639LanguageList *languages = ((Iso639LanguageDescriptor*)*desc)->getIso639Languages();
-                                                                       /* use last language code */
-                                                               for (Iso639LanguageConstIterator i(languages->begin()); i != languages->end(); ++i)
-                                                                       audio.language_code = (*i)->getIso639LanguageCode();
+                                                               CaDescriptor *descr = (CaDescriptor*)(*desc);
+                                                               program.caids.insert(descr->getCaSystemId());
+                                                               break;
+                                                       }
                                                        }
-                                                       break;
-                                               case STREAM_IDENTIFIER_DESCRIPTOR:
-                                                       audio.component_tag =
-                                                               video.component_tag =
-                                                                       ((StreamIdentifierDescriptor*)*desc)->getComponentTag();
-                                                       break;
-                                               case CA_DESCRIPTOR:
-                                               {
-                                                       CaDescriptor *descr = (CaDescriptor*)(*desc);
-                                                       program.caids.insert(descr->getCaSystemId());
-                                                       break;
                                                }
+                                               break;
+                                       }
+                                       if (isaudio)
+                                       {
+                                               audio.pid = (*es)->getPid();
+                                               if ( !program.audioStreams.empty() &&
+                                                       ( audio.pid == cached_apid_ac3 || audio.pid == cached_apid_mpeg) )
+                                               {
+                                                       program.audioStreams.push_back(program.audioStreams[0]);
+                                                       program.audioStreams[0] = audio;
                                                }
+                                               else
+                                                       program.audioStreams.push_back(audio);
                                        }
-                                       break;
-                               }
-                               if (isaudio)
-                               {
-                                       if ( !program.audioStreams.empty() &&
-                                               ( audio.pid == cached_apid_ac3 || audio.pid == cached_apid_mpeg) )
+                                       else if (isvideo)
                                        {
-                                               program.audioStreams.push_back(program.audioStreams[0]);
-                                               program.audioStreams[0] = audio;
+                                               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
-                                               program.audioStreams.push_back(audio);
+                                               continue;
                                }
-                               else if (isvideo)
+                               for (DescriptorConstIterator desc = pmt.getDescriptors()->begin();
+                                       desc != pmt.getDescriptors()->end(); ++desc)
                                {
-                                       if ( !program.videoStreams.empty() && video.pid == cached_vpid )
+                                       if ((*desc)->getTag() == CA_DESCRIPTOR)
                                        {
-                                               program.videoStreams.push_back(program.videoStreams[0]);
-                                               program.videoStreams[0] = video;
+                                               CaDescriptor *descr = (CaDescriptor*)(*desc);
+                                               program.caids.insert(descr->getCaSystemId());
                                        }
-                                       else
-                                               program.videoStreams.push_back(video);
-                               }
-                               else
-                                       continue;
-                       }
-                       for (DescriptorConstIterator desc = pmt.getDescriptors()->begin();
-                               desc != pmt.getDescriptors()->end(); ++desc)
-                       {
-                               if ((*desc)->getTag() == CA_DESCRIPTOR)
-                               {
-                                       CaDescriptor *descr = (CaDescriptor*)(*desc);
-                                       program.caids.insert(descr->getCaSystemId());
                                }
                        }
+                       ret = 0;
+                       m_cached_program = program;
+                       m_have_cached_program = true;
                }
-               return 0;
        } else if ( m_service && !m_service->cacheEmpty() )
        {
                int cached_pcrpid = m_service->getCacheEntry(eDVBService::cPCRPID),
@@ -356,9 +374,9 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program)
                for (CAID_LIST::iterator it(caids.begin()); it != caids.end(); ++it)
                        program.caids.insert(*it);
                if ( cnt )
-                       return 0;
+                       ret = 0;
        }
-       return -1;
+       return ret;
 }
 
 int eDVBServicePMTHandler::getChannel(eUsePtr<iDVBChannel> &channel)
@@ -517,7 +535,6 @@ int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux,
 
 void eDVBServicePMTHandler::free()
 {
-       eDVBScan *tmp = m_dvb_scan;  // do a copy on stack (recursive call of free()) !!!
        m_dvb_scan = 0;
        delete m_dvb_scan;
 
index fc8b15d..701930d 100644 (file)
@@ -72,9 +72,10 @@ class eDVBServicePMTHandler: public Object
        void PMTready(int error);
        void PATready(int error);
        
+       int m_pmt_pid;
+       
        int m_use_decode_demux;
        uint8_t m_decode_demux_num;
-
 public:
        eDVBServicePMTHandler();
        ~eDVBServicePMTHandler();
@@ -112,11 +113,21 @@ public:
                int component_tag;
                std::string language_code; /* iso-639, if available. */
        };
-       
+
+       struct subtitleStream
+       {
+               int pid;
+               int subtitling_type;
+               int composition_page_id;
+               int ancillary_page_id;
+               std::string language_code;
+       };
+
        struct program
        {
                std::vector<videoStream> videoStreams;
                std::vector<audioStream> audioStreams;
+               std::vector<subtitleStream> subtitleStreams;
                std::set<uint16_t> caids;
                int pcrPid;
                int pmtPid;
@@ -137,8 +148,9 @@ public:
 
        int tune(eServiceReferenceDVB &ref, int use_decode_demux, eCueSheet *sg=0);
        void free();
-
-       int m_pmt_pid;
+private:
+       bool m_have_cached_program;
+       program m_cached_program;
 };
 
 #endif
diff --git a/lib/dvb/subtitle.cpp b/lib/dvb/subtitle.cpp
new file mode 100644 (file)
index 0000000..5510997
--- /dev/null
@@ -0,0 +1,996 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <time.h>
+
+#include <asm/types.h>
+#include <lib/dvb/idemux.h>
+#include <lib/dvb/subtitle.h>
+#include <lib/base/smartptr.h>
+#include <lib/base/eerror.h>
+#include <lib/gdi/gpixmap.h>
+
+void bitstream_init(struct bitstream *bit, const void *buffer, int size)
+{
+       bit->data = (__u8*) buffer;
+       bit->size = size;
+       bit->avail = 8;
+       bit->consumed = 0;
+}
+
+int bitstream_get(struct bitstream *bit)
+{
+       int val;
+       bit->avail -= bit->size;
+       val = ((*bit->data) >> bit->avail) & ((1<<bit->size) - 1);
+       if (!bit->avail)
+       {
+               bit->data++;
+               bit->consumed++;
+               bit->avail = 8;
+       }
+       return val;
+}
+
+static int extract_pts(pts_t &pts, const __u8 *pkt)
+{
+       pkt += 7;
+       int flags = *pkt++;
+
+       pkt++; // header length
+
+       if (flags & 0x80) /* PTS present? */
+       {
+                       /* damn gcc bug */
+               pts  = ((unsigned long long)(((pkt[0] >> 1) & 7))) << 30;
+               pts |=   pkt[1] << 22;
+               pts |=  (pkt[2]>>1) << 15;
+               pts |=   pkt[3] << 7;
+               pts |=  (pkt[5]>>1);
+
+               return 0;
+       } else
+               return -1;
+}
+
+void eDVBSubtitleParser::subtitle_process_line(struct subtitle_page *page, int object_id, int line, const __u8 *data, int len)
+{
+       struct subtitle_region *region = page->regions;
+//     eDebug("line for %d:%d", page->page_id, object_id);
+       while (region)
+       {
+               struct subtitle_region_object *object = region->region_objects;
+               while (object)
+               {
+                       if (object->object_id == object_id)
+                       {
+                               int x = object->object_horizontal_position;
+                               int y = object->object_vertical_position + line;
+                               if (x + len > region->region_width)
+                               {
+                                       //eDebug("[SUB] !!!! XCLIP %d + %d > %d", x, len, region->region_width);
+                                       len = region->region_width - x;
+                               }
+                               if (len < 0)
+                                       break;
+                               if (y >= region->region_height)
+                               {
+                                       //eDebug("[SUB] !!!! YCLIP %d >= %d", y, region->region_height);
+                                       break;
+                               }
+//                             //eDebug("inserting %d bytes (into region %d)", len, region->region_id);
+                               memcpy((__u8*)region->region_buffer->surface->data + region->region_width * y + x, data, len);
+                       }
+                       object = object->next;
+               }
+               region = region->next;
+       }
+}
+
+int eDVBSubtitleParser::subtitle_process_pixel_data(struct subtitle_page *page, int object_id, int *linenr, int *linep, const __u8 *data)
+{
+       int data_type = *data++;
+       static __u8 line[720];
+
+       struct bitstream bit;
+       bit.size=0;
+       switch (data_type)
+       {
+       case 0x10: // 2bit pixel data
+               bitstream_init(&bit, data, 2);
+               while (1)
+               {
+                       int len=0, col=0;
+                       int code = bitstream_get(&bit);
+                       if (code)
+                       {
+                               col = code;
+                               len = 1;
+                       } else
+                       {
+                               code = bitstream_get(&bit);
+                               if (!code)
+                               {
+                                       code = bitstream_get(&bit);
+                                       if (code == 1)
+                                       {
+                                               col = 0;
+                                               len = 2;
+                                       } else if (code == 2)
+                                       {
+                                               len = bitstream_get(&bit) << 2;
+                                               len |= bitstream_get(&bit);
+                                               len += 12;
+                                               col = bitstream_get(&bit);
+                                       } else if (code == 3)
+                                       {
+                                               len = bitstream_get(&bit) << 6;
+                                               len |= bitstream_get(&bit) << 4;
+                                               len |= bitstream_get(&bit) << 2;
+                                               len |= bitstream_get(&bit);
+                                               len += 29;
+                                               col = bitstream_get(&bit);
+                                       } else
+                                               break;
+                               } else if (code==1)
+                               {
+                                       col = 0;
+                                       len = 1;
+                               } else if (code&2)  
+                               {
+                                       if (code&1)
+                                               len = 3 + 4 + bitstream_get(&bit);
+                                       else
+                                               len = 3 + bitstream_get(&bit);
+                                       col = bitstream_get(&bit);
+                               }
+                       }
+                       while (len && ((*linep) < 720))
+                       {
+                               line[(*linep)++] = col;
+                               len--;
+                       }
+               }
+               while (bit.avail != 8)
+                       bitstream_get(&bit);
+               return bit.consumed + 1;
+       case 0x11: // 4bit pixel data
+               bitstream_init(&bit, data, 4);
+               while (1)
+               {
+                       int len=0, col=0;
+                       int code = bitstream_get(&bit);
+                       if (code)
+                       {
+                               col = code;
+                               len = 1;
+                       } else
+                       {
+                               code = bitstream_get(&bit);
+                               if (!code)
+                                       break;
+                               else if (code == 0xC)
+                               {
+                                       col = 0;
+                                       len = 1;
+                               } else if (code == 0xD)
+                               {
+                                       col = 0;
+                                       len = 2;
+                               } else if (code < 8)
+                               {
+                                       col = 0;
+                                       len = (code & 7) + 2;
+                               } else if ((code & 0xC) == 0x8)
+                               {
+                                       col = bitstream_get(&bit);
+                                       len = (code & 3) + 4;
+                               } else if (code == 0xE)
+                               {
+                                       len = bitstream_get(&bit) + 9;
+                                       col = bitstream_get(&bit);
+                               } else if (code == 0xF)
+                               {
+                                       len  = bitstream_get(&bit) << 4;
+                                       len |= bitstream_get(&bit);
+                                       len += 25;
+                                       col  = bitstream_get(&bit);
+                               }
+                       }
+                       while (len && ((*linep) < 720))
+                       {
+                               line[(*linep)++] = col;
+                               len--;
+                       }
+               }
+               while (bit.avail != 8)
+                       bitstream_get(&bit);
+               return bit.consumed + 1;
+       case 0x12: // 8bit pixel data
+               bitstream_init(&bit, data, 8);
+               while(1)
+               {
+                       int len=0, col=0;
+                       int code = bitstream_get(&bit);
+                       if (code)
+                       {
+                               col = code;
+                               len = 1;
+                       } else
+                       {
+                               code = bitstream_get(&bit);
+                               if ((code & 0x80) == 0x80)
+                               {
+                                       len = code&0x7F;
+                                       col = bitstream_get(&bit);
+                               } else if (code&0x7F)
+                               {
+                                       len = code&0x7F;
+                                       col = 0;
+                               } else
+                                       break;
+                       }
+                       while (len && ((*linep) < 720))
+                       {
+                               line[(*linep)++] = col;
+                               len--;
+                       }
+               }
+               return bit.consumed + 1;
+       case 0x20:  // ignore 2 -> 4bit map table
+               bitstream_init(&bit, data, 4);
+               for ( int i=0; i < 4; ++i )
+                       bitstream_get(&bit);
+               break;
+       case 0x21:  // ignore 2 -> 8bit map table
+               bitstream_init(&bit, data, 8);
+               for ( int i=0; i < 4; ++i )
+                       bitstream_get(&bit);
+               break;
+       case 0x22:  // ignore 4 -> 8bit map table
+               bitstream_init(&bit, data, 8);
+               for ( int i=0; i < 16; ++i )
+                       bitstream_get(&bit);
+               break;
+       case 0xF0:
+               subtitle_process_line(page, object_id, *linenr, line, *linep);
+/*             {
+                       int i;
+                       for (i=0; i<720; ++i)
+                               //eDebugNoNewLine("%d ", line[i]);
+                       //eDebug("");
+               } */
+               (*linenr)+=2; // interlaced
+               *linep = 0;
+//             //eDebug("[SUB] EOL");
+               return 1;
+       default:
+               eDebug("subtitle_process_pixel_data: invalid data_type %02x", data_type);
+               return -1;
+       }
+       return 0;
+}
+
+int eDVBSubtitleParser::subtitle_process_segment(const __u8 *segment)
+{
+       int segment_type, page_id, segment_length, processed_length;
+       if (*segment++ !=  0x0F)
+       {
+               eDebug("out of sync.");
+               return -1;
+       }
+       segment_type = *segment++;
+       page_id  = *segment++ << 8;
+       page_id |= *segment++;
+       segment_length  = *segment++ << 8;
+       segment_length |= *segment++;
+       if (segment_type == 0xFF)
+               return segment_length + 6;
+//     //eDebug("have %d bytes of segment data", segment_length);
+       
+//     //eDebug("page_id %d, segtype %02x", page_id, segment_type);
+       
+       struct subtitle_page *page, **ppage;
+               
+       page = this->pages; ppage = &this->pages;
+
+       while (page)
+       {
+               if (page->page_id == page_id)
+                       break;
+               ppage = &page->next;
+               page = page->next;
+       }
+
+       processed_length = 0;
+
+       switch (segment_type)
+       {
+       case 0x10: // page composition segment
+       {
+               int page_time_out = *segment++; processed_length++;
+               int page_version_number = *segment >> 4;
+               int page_state = (*segment >> 2) & 0x3;
+               //eDebug("pcs with %d bytes data (%d:%d:%d)", segment_length, page_id, page_version_number, page_state);
+               segment++;
+               processed_length++;
+
+               //eDebug("page time out: %d", page_time_out);
+               //eDebug("page_version_number: %d" ,page_version_number);
+               //eDebug("page_state: %d", page_state);
+
+               if (!page)
+               {
+                       //eDebug("page not found");
+                       page = new subtitle_page;
+                       page->page_regions = 0;
+                       page->regions = 0;
+                       page->page_id = page_id;
+                       page->cluts = 0;
+                       page->next = 0;
+                       *ppage = page;
+               } else
+               {
+                       if (page->pcs_size != segment_length)
+                               page->page_version_number = -1;
+                               // if no update, just skip this data.
+                       if (page->page_version_number == page_version_number)
+                       {
+                               eDebug("skip data... ");
+                               break;
+                       }
+               }
+
+//             eDebug("page updated: old: %d, new: %d", page->page_version_number, page_version_number);
+                       // when acquisition point or mode change: remove all displayed pages.
+               if ((page_state == 1) || (page_state == 2))
+               {
+                       while (page->page_regions)
+                       {
+                               struct subtitle_page_region *p = page->page_regions->next;
+                               delete page->page_regions;
+                               page->page_regions = p;
+                       }
+               }
+
+//             eDebug("new page.. (%d)", page_state);
+
+               page->page_time_out = page_time_out;
+
+               page->page_version_number = page_version_number;
+
+               struct subtitle_page_region **r = &page->page_regions;
+
+               //eDebug("%d  / %d data left", processed_length, segment_length);
+
+                       // go to last entry
+               while (*r)
+                       r = &(*r)->next;
+
+               while (processed_length < segment_length)
+               {
+                       struct subtitle_page_region *pr;
+
+                               // append new entry to list
+                       pr = new subtitle_page_region;
+                       pr->next = 0;
+                       *r = pr;
+                       r = &pr->next;
+
+                       pr->region_id = *segment++; processed_length++;
+                       segment++; processed_length++;
+
+                       pr->region_horizontal_address  = *segment++ << 8;
+                       pr->region_horizontal_address |= *segment++;
+                       processed_length += 2;
+
+                       pr->region_vertical_address  = *segment++ << 8;
+                       pr->region_vertical_address |= *segment++;
+                       processed_length += 2;
+
+                       //eDebug("appended active region");
+               }
+
+               if (processed_length != segment_length)
+                       eDebug("%d != %d", processed_length, segment_length);
+               break;
+       }
+       case 0x11: // region composition segment
+       {
+               int region_id = *segment++; processed_length++;
+               int region_version_number = *segment >> 4;
+               int region_fill_flag = (*segment >> 3) & 1;
+               segment++; processed_length++;
+
+                       // if we didn't yet received the pcs for this page, drop the region
+               if (!page)
+               {
+                       eDebug("ignoring region %x, since page %02x doesn't yet exist.", region_id, page_id);
+                       break;
+               }
+
+               struct subtitle_region *region, **pregion;
+
+               region = page->regions; pregion = &page->regions;
+
+               while (region)
+               {
+                       fflush(stdout);
+                       if (region->region_id == region_id)
+                               break;
+                       pregion = &region->next;
+                       region = region->next;
+               }
+
+               if (!region)
+               {
+                       *pregion = region = new subtitle_region;
+                       region->next = 0;
+               }
+               else if (region->region_version_number != region_version_number)
+               {
+                       struct subtitle_region_object *objects = region->region_objects;
+                       while (objects)
+                       {
+                               struct subtitle_region_object *n = objects->next;
+                               delete objects;
+                               objects = n;
+                       }
+                       if (region->region_buffer)
+                       {
+                               if (region->region_buffer->surface)
+                                       delete region->region_buffer->surface;
+                               region->region_buffer=0;
+                       }
+               }
+               else
+                       break;
+
+               //eDebug("region %d:%d update", page_id, region_id);
+
+               region->region_id = region_id;
+               region->region_version_number = region_version_number;
+
+               region->region_width  = *segment++ << 8;
+               region->region_width |= *segment++;
+               processed_length += 2;
+
+               region->region_height  = *segment++ << 8;
+               region->region_height |= *segment++;
+               processed_length += 2;
+
+               region->region_buffer = new gPixmap(eSize(region->region_width, region->region_height), 8);
+
+               int region_level_of_compatibility, region_depth;
+
+               region_level_of_compatibility = (*segment >> 5) & 7;
+               region_depth = (*segment++ >> 2) & 7;
+               region->region_depth = (subtitle_region::depth) region_depth;
+               processed_length++;
+
+               int CLUT_id = *segment++; processed_length++;
+
+               region->clut_id = CLUT_id;
+
+               int region_8bit_pixel_code, region_4bit_pixel_code, region_2bit_pixel_code;
+               region_8bit_pixel_code = *segment++; processed_length++;
+               region_4bit_pixel_code = *segment >> 4;
+               region_2bit_pixel_code = (*segment++ >> 2) & 3;
+               processed_length++;
+
+               if (!region_fill_flag)
+               {
+                       region_2bit_pixel_code = region_4bit_pixel_code = region_8bit_pixel_code = 0;
+                       region_fill_flag = 1;
+               }
+
+               if (region_fill_flag)
+               {
+                       if (region_depth == 1)
+                               memset(region->region_buffer->surface->data, region_2bit_pixel_code, region->region_height * region->region_width);
+                       else if (region_depth == 2)
+                               memset(region->region_buffer->surface->data, region_4bit_pixel_code, region->region_height * region->region_width);
+                       else if (region_depth == 3)
+                               memset(region->region_buffer->surface->data, region_8bit_pixel_code, region->region_height * region->region_width);
+                       else
+                               eDebug("!!!! invalid depth");
+               }
+
+               //eDebug("region %02x, version %d, %dx%d", region->region_id, region->region_version_number, region->region_width, region->region_height);
+
+               region->region_objects = 0;
+               struct subtitle_region_object **pobject = &region->region_objects;
+
+               while (processed_length < segment_length)
+               {
+
+                       struct subtitle_region_object *object;
+
+                       object = new subtitle_region_object;
+
+                       *pobject = object;
+                       object->next = 0;
+                       pobject = &object->next;
+
+                       object->object_id  = *segment++ << 8;
+                       object->object_id |= *segment++; processed_length += 2;
+
+                       object->object_type = *segment >> 6;
+                       object->object_provider_flag = (*segment >> 4) & 3;
+                       object->object_horizontal_position  = (*segment++ & 0xF) << 8;
+                       object->object_horizontal_position |= *segment++;
+                       processed_length += 2;
+
+                       object->object_vertical_position  = *segment++ << 8;
+                       object->object_vertical_position |= *segment++ ;
+                       processed_length += 2;
+
+                       if ((object->object_type == 1) || (object->object_type == 2))
+                       {
+                               object->foreground_pixel_value = *segment++;
+                               object->background_pixel_value = *segment++;
+                               processed_length += 2;
+                       }
+               }
+
+               if (processed_length != segment_length)
+                       eDebug("too less data! (%d < %d)", segment_length, processed_length);
+
+               break;
+       }
+       case 0x12: // CLUT definition segment
+       {
+               int CLUT_id, CLUT_version_number;
+               struct subtitle_clut *clut, **pclut;
+
+               if (!page)
+                       break;
+
+               //eDebug("CLUT: %02x", *segment);
+               CLUT_id = *segment++;
+
+               CLUT_version_number = *segment++ >> 4;
+               processed_length += 2;
+
+               //eDebug("page %d, CLUT %02x, version %d", page->page_id, CLUT_id, CLUT_version_number);
+
+               clut = page->cluts; pclut = &page->cluts;
+
+               while (clut)
+               {
+                       if (clut->clut_id == CLUT_id)
+                               break;
+                       pclut = &clut->next;
+                       clut = clut->next;
+               }
+
+               if (!clut)
+               {
+                       *pclut = clut = new subtitle_clut;
+                       clut->next = 0;
+                       clut->clut_id = CLUT_id;
+               }
+               else if (clut->CLUT_version_number == CLUT_version_number)
+                       break;
+
+               clut->CLUT_version_number=CLUT_version_number;
+               clut->size_2 = clut->size_4 = clut->size_8 = 0;
+
+                       /* invalidate CLUT if updated. */
+               if ((this->current_clut_page_id == page_id) && (this->current_clut_id == CLUT_id))
+                       this->current_clut_id = -1;
+
+               //eDebug("new clut");
+               while (processed_length < segment_length)
+               {
+                       int CLUT_entry_id, entry_CLUT_flag, full_range;
+                       int v_Y, v_Cr, v_Cb, v_T;
+
+                       CLUT_entry_id = *segment++;
+                       full_range = *segment & 1;
+                       entry_CLUT_flag = (*segment++ & 0xE0) >> 5;
+                       processed_length += 2;
+
+                       if (full_range)
+                       {
+                               v_Y  = *segment++;
+                               v_Cr = *segment++;
+                               v_Cb = *segment++;
+                               v_T  = *segment++;
+                               processed_length += 4;
+                       } else
+                       {
+                               v_Y   = *segment & 0xFC;
+                               v_Cr  = (*segment++ & 3) << 6;
+                               v_Cr |= (*segment & 0xC0) >> 2;
+                               v_Cb  = (*segment & 0x3C) << 2;
+                               v_T   = (*segment++ & 3) << 6;
+                               processed_length += 2;
+                       }
+
+                       if (entry_CLUT_flag & 1) // 8bit
+                       {
+                               ASSERT(CLUT_entry_id < 256);
+                               ++clut->size_8;
+                               clut->entries_8bit[CLUT_entry_id].Y = v_Y;
+                               clut->entries_8bit[CLUT_entry_id].Cr = v_Cr;
+                               clut->entries_8bit[CLUT_entry_id].Cb = v_Cb;
+                               clut->entries_8bit[CLUT_entry_id].T = v_T;
+                       }
+                       if (entry_CLUT_flag & 2) // 4bit
+                       {
+                               ASSERT(CLUT_entry_id < 16);
+                               ++clut->size_4;
+                               clut->entries_4bit[CLUT_entry_id].Y = v_Y;
+                               clut->entries_4bit[CLUT_entry_id].Cr = v_Cr;
+                               clut->entries_4bit[CLUT_entry_id].Cb = v_Cb;
+                               clut->entries_4bit[CLUT_entry_id].T = v_T;
+                       }
+                       if (entry_CLUT_flag & 4) // 2bit
+                       {
+                               ASSERT(CLUT_entry_id < 4);
+                               ++clut->size_2;
+                               clut->entries_2bit[CLUT_entry_id].Y = v_Y;
+                               clut->entries_2bit[CLUT_entry_id].Cr = v_Cr;
+                               clut->entries_2bit[CLUT_entry_id].Cb = v_Cb;
+                               clut->entries_2bit[CLUT_entry_id].T = v_T;
+                       }
+                       //eDebug("  %04x %02x %02x %02x %02x", CLUT_entry_id, v_Y, v_Cb, v_Cr, v_T);
+               }
+               break;
+       }
+       case 0x13: // object data segment
+       {
+               int object_id, object_version_number, object_coding_method, non_modifying_color_flag;
+
+               object_id  = *segment++ << 8;
+               object_id |= *segment++;
+               processed_length += 2;
+
+               object_version_number = *segment >> 4;
+               object_coding_method  = (*segment >> 2) & 3;
+               non_modifying_color_flag = (*segment++ >> 1) & 1;
+               processed_length++;
+
+               //eDebug("object id %04x, version %d, object_coding_method %d (page_id %d)", object_id, object_version_number, object_coding_method, page_id);
+
+               if (object_coding_method == 0)
+               {
+                       int top_field_data_blocklength, bottom_field_data_blocklength;
+                       int i, line, linep;
+
+                       top_field_data_blocklength  = *segment++ << 8;
+                       top_field_data_blocklength |= *segment++;
+
+                       bottom_field_data_blocklength  = *segment++ << 8;
+                       bottom_field_data_blocklength |= *segment++;
+                       //eDebug("%d / %d bytes", top_field_data_blocklength, bottom_field_data_blocklength);
+                       processed_length += 4;
+
+                       i = 0;
+                       line = 0;
+                       linep = 0;
+                       while (i < top_field_data_blocklength)
+                       {
+                               int len;
+                               len = subtitle_process_pixel_data(page, object_id, &line, &linep, segment);
+                               if (len < 0)
+                                       return -1;
+                               segment += len;
+                               processed_length += len;
+                               i += len;
+                       }
+
+                       line = 1;
+                       linep = 0;
+
+                       if (bottom_field_data_blocklength)
+                       {
+                               i = 0;
+                               while (i < bottom_field_data_blocklength)
+                               {
+                                       int len;
+                                       len = subtitle_process_pixel_data(page, object_id, &line, &linep, segment);
+                                       if (len < 0)
+                                               return -1;
+                                       segment += len;
+                                       processed_length += len;
+                                       i += len;
+                               }
+                       }
+                       else if (top_field_data_blocklength)
+                               eDebug("!!!! unimplemented: no bottom field! (%d : %d)", top_field_data_blocklength, bottom_field_data_blocklength);
+
+                       if ((top_field_data_blocklength + bottom_field_data_blocklength) & 1)
+                       {
+                               segment++; processed_length++;
+                       }
+               }
+               else if (object_coding_method == 1)
+                       eDebug("---- object_coding_method 1 unsupported!");
+
+               break;
+       }
+       case 0x80: // end of display set segment
+       {
+//             eDebug("end of display set segment");
+               subtitle_redraw_all();
+       }
+       case 0xFF: // stuffing
+               break;
+       default:
+               eDebug("unhandled segment type %02x", segment_type);
+       }
+
+       return segment_length + 6;
+}
+
+void eDVBSubtitleParser::subtitle_process_pes(const __u8 *pkt, int len)
+{
+       if (!extract_pts(show_time, pkt))
+       {
+               pkt += 6; len -= 6;
+               // skip PES header
+               pkt++; len--;
+               pkt++; len--;
+
+               int hdr_len = *pkt++; len--;
+
+               pkt+=hdr_len; len-=hdr_len;
+
+               if (*pkt != 0x20)
+               {
+                       //eDebug("data identifier is 0x%02x, but not 0x20", *pkt);
+                       return;
+               }
+               pkt++; len--; // data identifier
+               *pkt++; len--; // stream id;
+
+               if (len <= 0)
+               {
+                       //eDebug("no data left (%d)", len);
+                       return;
+               }
+
+               while (len && *pkt == 0x0F)
+               {
+                       int l = subtitle_process_segment(pkt);
+                       if (l < 0)
+                               break;
+                       pkt += l;
+                       len -= l;
+               }
+       //      if (len && *pkt != 0xFF)
+       //              eDebug("strange data at the end");
+       }
+       else
+               eDebug("dvb subtitle packet without PTS.. ignore!!");
+}
+
+void eDVBSubtitleParser::subtitle_clear_screen()
+{
+               /* clear bbox */
+       int y;
+
+       //eDebug("BBOX clear %d:%d -> %d:%d", this->bbox_left, this->bbox_top, this->bbox_right, this->bbox_bottom);
+
+       // do not draw when anyone has locked the
+       // framebuffer ( non enigma plugins... )
+       this->bbox_right = 720;
+       if (this->bbox_right > this->bbox_left)
+               for (y=this->bbox_top; y < this->bbox_bottom; ++y)
+                       ; // TODO fixmee clear subtitle screen
+
+       this->bbox_right = 0;
+       this->bbox_left = this->screen_width;
+       this->bbox_top = this->screen_height;
+       this->bbox_bottom = 0;
+}
+
+void eDVBSubtitleParser::subtitle_redraw_all()
+{
+#if 1
+       struct subtitle_page *page = this->pages;
+       if ( page )
+       {
+               struct subtitle_page_region *region = page->page_regions;
+               if ( region )
+                       subtitle_clear_screen();
+       }
+       while(page)
+       {
+               subtitle_redraw(page->page_id);
+               page = page->next;
+       }
+#else
+       subtitle_clear_screen();
+
+       struct subtitle_page *page = this->pages;
+       //eDebug("----------- end of display set");
+       //eDebug("active pages:");
+       while (page)
+       {
+               //eDebug("  page_id %02x", page->page_id);
+               //eDebug("  page_version_number: %d", page->page_version_number);
+               //eDebug("  active regions:");
+               {
+                       struct subtitle_page_region *region = page->page_regions;
+                       while (region)
+                       {
+                               //eDebug("    region_id: %04x", region->region_id);
+                               //eDebug("    region_horizontal_address: %d", region->region_horizontal_address);
+                               //eDebug("    region_vertical_address: %d", region->region_vertical_address);
+
+                               region = region->next;
+                       }
+               }
+
+               subtitle_redraw(page->page_id);
+               //eDebug("defined regions:");
+               struct subtitle_region *region = page->regions;
+               while (region)
+               {
+                       //eDebug("  region_id %04x, version %d, %dx%d", region->region_id, region->region_version_number, region->region_width, region->region_height);
+
+                       struct subtitle_region_object *object = region->region_objects;
+                       while (object)
+                       {
+                               //eDebug("  object %02x, type %d, %d:%d", object->object_id, object->object_type, object->object_horizontal_position, object->object_vertical_position);
+                               object = object->next;
+                       }
+                       region = region->next;
+               }
+               page = page->next;
+       }
+#endif
+}
+
+void eDVBSubtitleParser::subtitle_reset()
+{
+       while (struct subtitle_page *page = this->pages)
+       {
+                       /* free page regions */
+               while (page->page_regions)
+               {
+                       struct subtitle_page_region *p = page->page_regions->next;
+                       delete page->page_regions;
+                       page->page_regions = p;
+               }
+                       /* free regions */
+               while (page->regions)
+               {
+                       struct subtitle_region *region = page->regions;
+
+                       while (region->region_objects)
+                       {
+                               struct subtitle_region_object *obj = region->region_objects;
+                               region->region_objects = obj->next;
+                               delete obj;
+                       }
+
+                       if (region->region_buffer)
+                       {
+                               if (region->region_buffer->surface)
+                                       delete region->region_buffer->surface;
+                               region->region_buffer=0;
+                       }
+
+                       page->regions = region->next;
+                       delete region;
+               }
+
+                       /* free CLUTs */
+               while (page->cluts)
+               {
+                       struct subtitle_clut *clut = page->cluts;
+                       page->cluts = clut->next;
+                       delete clut;
+               }
+
+               this->pages = page->next;
+               delete page;
+       }
+}
+
+void eDVBSubtitleParser::subtitle_redraw(int page_id)
+{
+       struct subtitle_page *page = this->pages;
+
+       //eDebug("displaying page id %d", page_id);
+
+       while (page)
+       {
+               if (page->page_id == page_id)
+                       break;
+               page = page->next;
+       }
+       if (!page)
+       {
+               //eDebug("page not found");
+               return;
+       }
+
+
+       //eDebug("iterating regions..");
+               /* iterate all regions in this pcs */
+       struct subtitle_page_region *region = page->page_regions;
+       while (region)
+       {
+               //eDebug("region %d", region->region_id);
+                       /* find corresponding region */
+               struct subtitle_region *reg = page->regions;
+               while (reg)
+               {
+                       if (reg->region_id == region->region_id)
+                               break;
+                       reg = reg->next;
+               }
+               if (reg)
+               {
+                       int y;
+                       //eDebug("copy region %d to %d, %d", region->region_id, region->region_horizontal_address, region->region_vertical_address);
+
+                       int x0 = region->region_horizontal_address;
+                       int y0 = region->region_vertical_address;
+                       int x1 = x0 + reg->region_width;
+                       int y1 = y0 + reg->region_height;
+
+                       if ((x0 < 0) || (y0 < 0) || (x0 > this->screen_width) || (x0 > this->screen_height))
+                               continue;
+
+                               /* adjust bbox */
+                       if (x0 < this->bbox_left)
+                               this->bbox_left = x0;
+                       if (y0 < this->bbox_top)
+                               this->bbox_top = y0;
+                       if (x1 > this->bbox_right)
+                               this->bbox_right = x1;
+                       if (y1 > this->bbox_bottom)
+                               this->bbox_bottom = y1;
+
+                       int timeout = page->page_time_out;
+
+                       /* find corresponding clut */
+                       struct subtitle_clut *clut = page->cluts;
+                       while (clut)
+                       {
+                       //eDebug("have %d, want %d", clut->clut_id, main_clut_id);
+                               if (clut->clut_id == reg->clut_id)
+                                       break;
+                               clut = clut->next;
+                       }
+                       if (clut)
+                       {
+                               // TODO fill region->surface->clut !!!!!
+                       }
+                       else
+                       {
+                               // apply default clut depending on region->region_depth
+                               // TODO fill region->surface->clut !!!!!
+                       }
+                       // TODO Blit Region Pixmap !!!
+               }
+               else
+                       eDebug("region not found");
+               region = region->next;
+       }
+       //eDebug("schon gut.");
+}
+
+DEFINE_REF(eDVBSubtitleParser);
+
+eDVBSubtitleParser::eDVBSubtitleParser(iDVBDemux *demux)
+{
+       setStreamID(0xBD);
+
+       if (demux->createPESReader(eApp, m_pes_reader))
+               eDebug("failed to create dvb subtitle PES reader!");
+       else
+               m_pes_reader->connectRead(slot(*this, &eDVBSubtitleParser::subtitle_process_pes), m_read_connection);
+}
+
+eDVBSubtitleParser::~eDVBSubtitleParser()
+{
+       subtitle_reset();
+}
diff --git a/lib/dvb/subtitle.h b/lib/dvb/subtitle.h
new file mode 100644 (file)
index 0000000..0d364f8
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef __lib_dvb_subtitle_h
+#define __lib_dvb_subtitle_h
+
+#include <lib/base/object.h>
+#include <lib/dvb/idvb.h>
+#include <lib/dvb/pesparse.h>
+#include <lib/gdi/gpixmap.h>
+
+typedef unsigned char __u8;
+
+struct subtitle_clut_entry
+{
+       __u8 Y, Cr, Cb, T;
+};
+
+struct subtitle_clut
+{
+       unsigned char clut_id;
+       unsigned char size_2, size_4, size_8;
+       unsigned char CLUT_version_number;
+       struct subtitle_clut_entry entries_2bit[4];
+       struct subtitle_clut_entry entries_4bit[16];
+       struct subtitle_clut_entry entries_8bit[256];
+       struct subtitle_clut *next;
+};
+
+struct subtitle_page_region
+{
+       int region_id;
+       int region_horizontal_address;
+       int region_vertical_address;
+       struct subtitle_page_region *next;
+};
+
+struct subtitle_region_object
+{
+       int object_id;
+       int object_type;
+       int object_provider_flag;
+       
+       int object_horizontal_position;
+       int object_vertical_position;
+       
+               // not supported right now...
+       int foreground_pixel_value;
+       int background_pixel_value;
+
+       struct subtitle_region_object *next;
+};
+
+struct subtitle_region
+{
+       int region_id;
+       int region_version_number;
+       int region_height, region_width;
+       enum depth { bpp2=1, bpp4=2, bpp8=3 } region_depth;
+       ePtr<gPixmap> region_buffer;
+       
+       int clut_id;
+       
+       struct subtitle_region_object *region_objects;
+       
+       struct subtitle_region *next;
+};
+
+struct subtitle_page
+{
+       int page_id;
+       time_t page_time_out;
+       int page_version_number;
+       int pcs_size;
+       struct subtitle_page_region *page_regions;
+       
+       struct subtitle_region *regions;
+
+       struct subtitle_clut *cluts;
+
+       struct subtitle_page *next;
+};
+
+struct bitstream
+{
+       __u8 *data;
+       int size;
+       int avail;
+       int consumed;
+};
+
+struct eDVBSubtitleRegion
+{
+       pts_t show_time;
+       int timeout;
+       ePtr<gPixmap> region;
+};
+
+class eDVBSubtitleParser
+       :public iObject, public ePESParser, public Object
+{
+       DECLARE_REF(eDVBSubtitleParser);
+       struct subtitle_page *pages;
+       int current_clut_id, current_clut_page_id;
+       int screen_width, screen_height;
+       int bbox_left, bbox_top, bbox_right, bbox_bottom;
+       ePtr<iDVBPESReader> m_pes_reader;
+       ePtr<eConnection> m_read_connection;
+       pts_t show_time;
+public:
+       eDVBSubtitleParser(iDVBDemux *demux);
+       virtual ~eDVBSubtitleParser();
+       int start(int pid);
+private:
+       void subtitle_process_line(struct subtitle_page *page, int object_id, int line, const __u8 *data, int len);
+       int subtitle_process_pixel_data(struct subtitle_page *page, int object_id, int *linenr, int *linep, const __u8 *data);
+       int subtitle_process_segment(const __u8 *segment);
+       void subtitle_process_pes(const __u8 *buffer, int len);
+       void subtitle_clear_screen();
+       void subtitle_redraw_all();
+       void subtitle_reset();
+       void subtitle_redraw(int page_id);
+};
+
+#endif
index a8c9bda..2a44f4f 100644 (file)
@@ -73,7 +73,7 @@ eDVBTeletextParser::eDVBTeletextParser(iDVBDemux *demux)
        setPage(-1);
        
        if (demux->createPESReader(eApp, m_pes_reader))
-               eDebug("failed to create PES reader!");
+               eDebug("failed to create teletext subtitle PES reader!");
        else
                m_pes_reader->connectRead(slot(*this, &eDVBTeletextParser::processData), m_read_connection);
 }
index 2cf5b6e..b63420a 100644 (file)
@@ -2075,6 +2075,14 @@ void eDVBServicePlay::checkSubtitleTiming()
        }
 }
 
+void eDVBServicePlay::newDVBSubtitleRegion(const eDVBSubtitleRegion &p)
+{
+}
+
+void eDVBServicePlay::checkDvbSubtitleTiming()
+{
+}
+
 int eDVBServicePlay::getAC3Delay()
 {
        if (m_dvb_service)
index b2306e1..3f133d6 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <lib/dvb/pmt.h>
 #include <lib/dvb/eit.h>
+#include <lib/dvb/subtitle.h>
 #include <lib/dvb/teletext.h>
 #include <lib/dvb/radiotext.h>
 #include <lib/base/filepush.h>
@@ -238,19 +239,25 @@ private:
        
        void cutlistToCuesheet();
        
+       eSubtitleWidget *m_subtitle_widget;
+       
                /* teletext subtitles */
+       ePtr<eDVBTeletextParser> m_teletext_parser;
        void newSubtitlePage(const eDVBTeletextSubtitlePage &p);
        ePtr<eConnection> m_new_subtitle_page_connection;
-       
-       ePtr<eDVBTeletextParser> m_teletext_parser;
-       ePtr<eDVBRadioTextParser> m_radiotext_parser;
-       eSubtitleWidget *m_subtitle_widget;
        eTimer m_subtitle_sync_timer;
        std::list<eDVBTeletextSubtitlePage> m_subtitle_pages;
-       
        void checkSubtitleTiming();
+       
+               /* dvb subtitles */
+       void newDVBSubtitleRegion(const eDVBSubtitleRegion &p);
+       ePtr<eConnection> m_new_dvb_subtitle_region_connection;
+       eTimer m_dvb_subtitle_sync_timer;
+       std::list<eDVBSubtitleRegion> m_dvb_subtitle_regions;
+       void checkDvbSubtitleTiming();
 
                /* radiotext */
+       ePtr<eDVBRadioTextParser> m_radiotext_parser;
        ePtr<eConnection> m_radiotext_updated_connection;
        void radioTextUpdated();
 };