eServiceEvent: parse PDC descriptor
[openblackhole/openblackhole-enigma2.git] / lib / service / event.cpp
1 #include <lib/service/event.h>
2 #include <lib/base/estring.h>
3 #include <lib/base/encoding.h>
4 #include <lib/dvb/dvbtime.h>
5 #include <lib/dvb/idvb.h>
6 #include <dvbsi++/event_information_section.h>
7 #include <dvbsi++/short_event_descriptor.h>
8 #include <dvbsi++/extended_event_descriptor.h>
9 #include <dvbsi++/linkage_descriptor.h>
10 #include <dvbsi++/component_descriptor.h>
11 #include <dvbsi++/content_descriptor.h>
12 #include <dvbsi++/parental_rating_descriptor.h>
13 #include <dvbsi++/descriptor_tag.h>
14 #include <dvbsi++/pdc_descriptor.h>
15
16 #include <sys/types.h>
17 #include <fcntl.h>
18
19 // static members / methods
20 std::string eServiceEvent::m_language = "---";
21 std::string eServiceEvent::m_language_alternative = "---";
22
23 ///////////////////////////
24
25 DEFINE_REF(eServiceEvent);
26 DEFINE_REF(eComponentData);
27 DEFINE_REF(eGenreData);
28 DEFINE_REF(eParentalData);
29
30 /* search for the presence of language from given EIT event descriptors*/
31 bool eServiceEvent::loadLanguage(Event *evt, const std::string &lang, int tsidonid)
32 {
33         bool retval=0;
34         std::string language = lang;
35         for (DescriptorConstIterator desc = evt->getDescriptors()->begin(); desc != evt->getDescriptors()->end(); ++desc)
36         {
37                 switch ((*desc)->getTag())
38                 {
39                         case LINKAGE_DESCRIPTOR:
40                                 m_linkage_services.clear();
41                                 break;
42                         case SHORT_EVENT_DESCRIPTOR:
43                         {
44                                 const ShortEventDescriptor *sed = (ShortEventDescriptor*)*desc;
45                                 std::string cc = sed->getIso639LanguageCode();
46                                 std::transform(cc.begin(), cc.end(), cc.begin(), tolower);
47                                 int table=encodingHandler.getCountryCodeDefaultMapping(cc);
48                                 if (language == "---" || language.find(cc) != std::string::npos)
49                                 {
50                                         /* stick to this language, avoid merging or mixing descriptors of different languages */
51                                         language = cc;
52                                         m_event_name += replace_all(replace_all(convertDVBUTF8(sed->getEventName(), table, tsidonid), "\n", " "), "\t", " ");
53                                         m_short_description += convertDVBUTF8(sed->getText(), table, tsidonid);
54                                         retval=1;
55                                 }
56                                 break;
57                         }
58                         case EXTENDED_EVENT_DESCRIPTOR:
59                         {
60                                 const ExtendedEventDescriptor *eed = (ExtendedEventDescriptor*)*desc;
61                                 std::string cc = eed->getIso639LanguageCode();
62                                 std::transform(cc.begin(), cc.end(), cc.begin(), tolower);
63                                 int table=encodingHandler.getCountryCodeDefaultMapping(cc);
64                                 if (language == "---" || language.find(cc) != std::string::npos)
65                                 {
66                                         /* stick to this language, avoid merging or mixing descriptors of different languages */
67                                         language = cc;
68                                         /*
69                                          * Bit of a hack, some providers put the event description partly in the short descriptor,
70                                          * and the remainder in extended event descriptors.
71                                          * In that case, we cannot really treat short/extended description as separate descriptions.
72                                          * Unfortunately we cannot recognise this, but we'll use the length of the short description
73                                          * to guess whether we should concatenate both descriptions (without any spaces)
74                                          */
75                                         if (m_extended_description.empty() && m_short_description.size() >= 180)
76                                         {
77                                                 m_extended_description = m_short_description;
78                                                 m_short_description = "";
79                                         }
80                                         m_extended_description += convertDVBUTF8(eed->getText(), table, tsidonid);
81                                         retval=1;
82                                 }
83 #if 0
84                                 const ExtendedEventList *itemlist = eed->getItems();
85                                 for (ExtendedEventConstIterator it = itemlist->begin(); it != itemlist->end(); ++it)
86                                 {
87                                         m_extended_description += '\n';
88                                         m_extended_description += convertDVBUTF8((*it)->getItemDescription());
89                                         m_extended_description += ' ';
90                                         m_extended_description += convertDVBUTF8((*it)->getItem());
91                                 }
92 #endif
93                                 break;
94                         }
95                         default:
96                                 break;
97                 }
98         }
99         if ( retval == 1 )
100         {
101                 for (DescriptorConstIterator desc = evt->getDescriptors()->begin(); desc != evt->getDescriptors()->end(); ++desc)
102                 {
103                         switch ((*desc)->getTag())
104                         {
105                                 case COMPONENT_DESCRIPTOR:
106                                 {
107                                         const ComponentDescriptor *cp = (ComponentDescriptor*)*desc;
108                                         eComponentData data;
109                                         data.m_streamContent = cp->getStreamContent();
110                                         data.m_componentType = cp->getComponentType();
111                                         data.m_componentTag = cp->getComponentTag();
112                                         data.m_iso639LanguageCode = cp->getIso639LanguageCode();
113                                         std::transform(data.m_iso639LanguageCode.begin(), data.m_iso639LanguageCode.end(), data.m_iso639LanguageCode.begin(), tolower);
114                                         int table=encodingHandler.getCountryCodeDefaultMapping(data.m_iso639LanguageCode);
115                                         data.m_text = convertDVBUTF8(cp->getText(),table,tsidonid);
116                                         m_component_data.push_back(data);
117                                         break;
118                                 }
119                                 case LINKAGE_DESCRIPTOR:
120                                 {
121                                         const LinkageDescriptor  *ld = (LinkageDescriptor*)*desc;
122                                         if ( ld->getLinkageType() == 0xB0 )
123                                         {
124                                                 eServiceReferenceDVB dvb_ref;
125                                                 dvb_ref.type = eServiceReference::idDVB;
126                                                 dvb_ref.setServiceType(1);
127                                                 dvb_ref.setTransportStreamID(ld->getTransportStreamId());
128                                                 dvb_ref.setOriginalNetworkID(ld->getOriginalNetworkId());
129                                                 dvb_ref.setServiceID(ld->getServiceId());
130                                                 const PrivateDataByteVector *privateData = ld->getPrivateDataBytes();
131                                                 dvb_ref.name = convertDVBUTF8((const unsigned char*)&((*privateData)[0]), privateData->size(), 1, tsidonid);
132                                                 m_linkage_services.push_back(dvb_ref);
133                                         }
134                                         break;
135                                 }
136                                 case CONTENT_DESCRIPTOR:
137                                 {
138                                         const ContentDescriptor *cd = (ContentDescriptor *)*desc;
139                                         const ContentClassificationList *con = cd->getClassifications();
140                                         for (ContentClassificationConstIterator it = con->begin(); it != con->end(); ++it)
141                                         {
142                                                 eGenreData data;
143                                                 data.m_level1 = (*it)->getContentNibbleLevel1();
144                                                 data.m_level2 = (*it)->getContentNibbleLevel2();
145                                                 data.m_user1  = (*it)->getUserNibble1();
146                                                 data.m_user2  = (*it)->getUserNibble2();
147                                                 m_genres.push_back(data);
148                                         }
149                                         break;
150                                 }
151                                 case PARENTAL_RATING_DESCRIPTOR:
152                                 {
153                                         const ParentalRatingDescriptor *prd = (ParentalRatingDescriptor *)*desc;
154                                         const ParentalRatingList *par = prd->getParentalRatings();
155                                         for (ParentalRatingConstIterator it = par->begin(); it != par->end(); ++it)
156                                         {
157                                                 eParentalData data;
158
159                                                 data.m_country_code = (*it)->getCountryCode();
160                                                 data.m_rating = (*it)->getRating();
161                                                 m_ratings.push_back(data);
162                                         }
163                                         break;
164                                 }
165                                 case PDC_DESCRIPTOR:
166                                 {
167                                         const PdcDescriptor *pdcd = (PdcDescriptor *)*desc;
168                                         m_pdc_pil = pdcd->getProgrammeIdentificationLabel();
169                                         break;
170                                 }
171                         }
172                 }
173         }
174         if ( m_extended_description.find(m_short_description) == 0 )
175                 m_short_description="";
176         return retval;
177 }
178
179 RESULT eServiceEvent::parseFrom(Event *evt, int tsidonid)
180 {
181         m_begin = parseDVBtime(evt->getStartTimeMjd(), evt->getStartTimeBcd());
182         m_event_id = evt->getEventId();
183         uint32_t duration = evt->getDuration();
184         m_duration = fromBCD(duration>>16)*3600+fromBCD(duration>>8)*60+fromBCD(duration);
185         if (m_language != "---" && loadLanguage(evt, m_language, tsidonid))
186                 return 0;
187         if (m_language_alternative != "---" && loadLanguage(evt, m_language_alternative, tsidonid))
188                 return 0;
189         if (loadLanguage(evt, "eng", tsidonid))
190                 return 0;
191         if (loadLanguage(evt, "---", tsidonid))
192                 return 0;
193         return 0;
194 }
195
196 RESULT eServiceEvent::parseFrom(const std::string& filename, int tsidonid)
197 {
198         if (!filename.empty())
199         {
200                 int fd = ::open( filename.c_str(), O_RDONLY );
201                 if ( fd > -1 )
202                 {
203                         uint8_t buf[4096];
204                         int rd = ::read(fd, buf, 4096);
205                         ::close(fd);
206                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
207                         {
208                                 Event ev(buf);
209                                 parseFrom(&ev, tsidonid);
210                                 return 0;
211                         }
212                 }
213         }
214         return -1;
215 }
216
217 std::string eServiceEvent::getBeginTimeString() const
218 {
219         tm t;
220         localtime_r(&m_begin, &t);
221         char tmp[13];
222         snprintf(tmp, 13, "%02d.%02d, %02d:%02d",
223                 t.tm_mday, t.tm_mon+1,
224                 t.tm_hour, t.tm_min);
225         return std::string(tmp, 12);
226 }
227
228 RESULT eServiceEvent::getGenreData(ePtr<eGenreData> &dest) const
229 {
230         std::list<eGenreData>::const_iterator it = m_genres.begin();
231         for(;it != m_genres.end(); ++it) {
232                 dest = new eGenreData(*it);
233                 //  for now just return the first item on the list
234                 return 0;
235         }
236         dest = 0;
237         return -1;
238 }
239
240 PyObject *eServiceEvent::getGenreData() const
241 {
242         ePyObject ret = PyList_New(m_genres.size());
243         int cnt=0;
244         for (std::list<eGenreData>::const_iterator it(m_genres.begin()); it != m_genres.end(); ++it)
245         {
246                 ePyObject tuple = PyTuple_New(4);
247                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->getLevel1()));
248                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getLevel2()));
249                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->getUser1()));
250                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->getUser2()));
251                 PyList_SET_ITEM(ret, cnt++, tuple);
252         }
253         return ret;
254 }
255
256 RESULT eServiceEvent::getParentalData(ePtr<eParentalData> &dest) const
257 {
258         std::list<eParentalData>::const_iterator it = m_ratings.begin();
259         for(;it != m_ratings.end(); ++it) {
260                 dest = new eParentalData(*it);
261                 //  for now just return the first item on the list
262                 return 0;
263         }
264         dest = 0;
265         return -1;
266 }
267
268 PyObject *eServiceEvent::getParentalData() const
269 {
270         ePyObject ret = PyList_New(m_ratings.size());
271         int cnt = 0;
272         for (std::list<eParentalData>::const_iterator it(m_ratings.begin()); it != m_ratings.end(); ++it)
273         {
274                 ePyObject tuple = PyTuple_New(2);
275                 PyTuple_SET_ITEM(tuple, 0, PyString_FromString(it->getCountryCode().c_str()));
276                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getRating()));
277                 PyList_SET_ITEM(ret, cnt++, tuple);
278         }
279         return ret;
280 }
281
282 RESULT eServiceEvent::getComponentData(ePtr<eComponentData> &dest, int tagnum) const
283 {
284         std::list<eComponentData>::const_iterator it =
285                 m_component_data.begin();
286         for(;it != m_component_data.end(); ++it)
287         {
288                 if ( it->m_componentTag == tagnum )
289                 {
290                         dest=new eComponentData(*it);
291                         return 0;
292                 }
293         }
294         dest = 0;
295         return -1;
296 }
297
298 PyObject *eServiceEvent::getComponentData() const
299 {
300         ePyObject ret = PyList_New(m_component_data.size());
301         int cnt = 0;
302         for (std::list<eComponentData>::const_iterator it(m_component_data.begin()); it != m_component_data.end(); ++it)
303         {
304                 ePyObject tuple = PyTuple_New(5);
305                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->m_componentTag));
306                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->m_componentType));
307                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->m_streamContent));
308                 PyTuple_SET_ITEM(tuple, 3, PyString_FromString(it->m_iso639LanguageCode.c_str()));
309                 PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->m_text.c_str()));
310                 PyList_SET_ITEM(ret, cnt++, tuple);
311         }
312         return ret;
313 }
314
315 RESULT eServiceEvent::getLinkageService(eServiceReference &service, eServiceReference &parent, int num) const
316 {
317         std::list<eServiceReference>::const_iterator it =
318                 m_linkage_services.begin();
319         while( it != m_linkage_services.end() && num-- )
320                 ++it;
321         if ( it != m_linkage_services.end() )
322         {
323                 service = *it;
324                 eServiceReferenceDVB &subservice = (eServiceReferenceDVB&) service;
325                 eServiceReferenceDVB &current = (eServiceReferenceDVB&) parent;
326                 subservice.setDVBNamespace(current.getDVBNamespace());
327                 if ( current.getParentTransportStreamID().get() )
328                 {
329                         subservice.setParentTransportStreamID( current.getParentTransportStreamID() );
330                         subservice.setParentServiceID( current.getParentServiceID() );
331                 }
332                 else
333                 {
334                         subservice.setParentTransportStreamID( current.getTransportStreamID() );
335                         subservice.setParentServiceID( current.getServiceID() );
336                 }
337                 if ( subservice.getParentTransportStreamID() == subservice.getTransportStreamID() &&
338                         subservice.getParentServiceID() == subservice.getServiceID() )
339                 {
340                         subservice.setParentTransportStreamID( eTransportStreamID(0) );
341                         subservice.setParentServiceID( eServiceID(0) );
342                 }
343                 return 0;
344         }
345         service.type = eServiceReference::idInvalid;
346         return -1;
347 }
348
349 DEFINE_REF(eDebugClass);