Support turbo2.
[vuplus_dvbapp] / 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", " ",table), "\t", " ",table);
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 (eed->getText().empty() && m_short_description.size() >= 180)
76                                         {
77                                                 m_extended_description = m_short_description;
78                                                 m_short_description = "";
79                                         }
80                                         if (table == 0) // Two Char Mapping EED must be processed in one pass
81                                         {
82                                                 m_tmp_extended_description += eed->getText();
83                                                 if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber())
84                                                 {
85                                                         m_extended_description += convertDVBUTF8(m_tmp_extended_description, table, tsidonid);
86                                                 }
87                                         }
88                                         else
89                                         {
90                                                 m_extended_description += convertDVBUTF8(eed->getText(), table, tsidonid);
91                                         }
92                                         retval=1;
93                                 }
94 #if 0
95                                 const ExtendedEventList *itemlist = eed->getItems();
96                                 for (ExtendedEventConstIterator it = itemlist->begin(); it != itemlist->end(); ++it)
97                                 {
98                                         m_extended_description += '\n';
99                                         m_extended_description += convertDVBUTF8((*it)->getItemDescription());
100                                         m_extended_description += ' ';
101                                         m_extended_description += convertDVBUTF8((*it)->getItem());
102                                 }
103 #endif
104                                 break;
105                         }
106                         default:
107                                 break;
108                 }
109         }
110         if ( retval == 1 )
111         {
112                 for (DescriptorConstIterator desc = evt->getDescriptors()->begin(); desc != evt->getDescriptors()->end(); ++desc)
113                 {
114                         switch ((*desc)->getTag())
115                         {
116                                 case COMPONENT_DESCRIPTOR:
117                                 {
118                                         const ComponentDescriptor *cp = (ComponentDescriptor*)*desc;
119                                         eComponentData data;
120                                         data.m_streamContent = cp->getStreamContent();
121                                         data.m_componentType = cp->getComponentType();
122                                         data.m_componentTag = cp->getComponentTag();
123                                         data.m_iso639LanguageCode = cp->getIso639LanguageCode();
124                                         std::transform(data.m_iso639LanguageCode.begin(), data.m_iso639LanguageCode.end(), data.m_iso639LanguageCode.begin(), tolower);
125                                         int table=encodingHandler.getCountryCodeDefaultMapping(data.m_iso639LanguageCode);
126                                         data.m_text = convertDVBUTF8(cp->getText(),table,tsidonid);
127                                         m_component_data.push_back(data);
128                                         break;
129                                 }
130                                 case LINKAGE_DESCRIPTOR:
131                                 {
132                                         const LinkageDescriptor  *ld = (LinkageDescriptor*)*desc;
133                                         if ( ld->getLinkageType() == 0xB0 )
134                                         {
135                                                 eServiceReferenceDVB dvb_ref;
136                                                 dvb_ref.type = eServiceReference::idDVB;
137                                                 dvb_ref.setServiceType(1);
138                                                 dvb_ref.setTransportStreamID(ld->getTransportStreamId());
139                                                 dvb_ref.setOriginalNetworkID(ld->getOriginalNetworkId());
140                                                 dvb_ref.setServiceID(ld->getServiceId());
141                                                 const PrivateDataByteVector *privateData = ld->getPrivateDataBytes();
142                                                 dvb_ref.name = convertDVBUTF8((const unsigned char*)&((*privateData)[0]), privateData->size(), 1, tsidonid);
143                                                 m_linkage_services.push_back(dvb_ref);
144                                         }
145                                         break;
146                                 }
147                                 case CONTENT_DESCRIPTOR:
148                                 {
149                                         const ContentDescriptor *cd = (ContentDescriptor *)*desc;
150                                         const ContentClassificationList *con = cd->getClassifications();
151                                         for (ContentClassificationConstIterator it = con->begin(); it != con->end(); ++it)
152                                         {
153                                                 eGenreData data;
154                                                 data.m_level1 = (*it)->getContentNibbleLevel1();
155                                                 data.m_level2 = (*it)->getContentNibbleLevel2();
156                                                 data.m_user1  = (*it)->getUserNibble1();
157                                                 data.m_user2  = (*it)->getUserNibble2();
158                                                 m_genres.push_back(data);
159                                         }
160                                         break;
161                                 }
162                                 case PARENTAL_RATING_DESCRIPTOR:
163                                 {
164                                         const ParentalRatingDescriptor *prd = (ParentalRatingDescriptor *)*desc;
165                                         const ParentalRatingList *par = prd->getParentalRatings();
166                                         for (ParentalRatingConstIterator it = par->begin(); it != par->end(); ++it)
167                                         {
168                                                 eParentalData data;
169
170                                                 data.m_country_code = (*it)->getCountryCode();
171                                                 data.m_rating = (*it)->getRating();
172                                                 m_ratings.push_back(data);
173                                         }
174                                         break;
175                                 }
176                                 case PDC_DESCRIPTOR:
177                                 {
178                                         const PdcDescriptor *pdcd = (PdcDescriptor *)*desc;
179                                         m_pdc_pil = pdcd->getProgrammeIdentificationLabel();
180                                         break;
181                                 }
182                         }
183                 }
184         }
185         if ( m_extended_description.find(m_short_description) == 0 )
186                 m_short_description="";
187         return retval;
188 }
189
190 RESULT eServiceEvent::parseFrom(Event *evt, int tsidonid)
191 {
192         m_begin = parseDVBtime(evt->getStartTimeMjd(), evt->getStartTimeBcd());
193         m_event_id = evt->getEventId();
194         uint32_t duration = evt->getDuration();
195         m_duration = fromBCD(duration>>16)*3600+fromBCD(duration>>8)*60+fromBCD(duration);
196         uint8_t running_status = evt->getRunningStatus();
197         m_running_status = running_status;
198         if (m_language != "---" && loadLanguage(evt, m_language, tsidonid))
199                 return 0;
200         if (m_language_alternative != "---" && loadLanguage(evt, m_language_alternative, tsidonid))
201                 return 0;
202         if (loadLanguage(evt, "---", tsidonid))
203                 return 0;
204         return 0;
205 }
206
207 RESULT eServiceEvent::parseFrom(const std::string &filename, int tsidonid)
208 {
209         if (!filename.empty())
210         {
211                 int fd = ::open( filename.c_str(), O_RDONLY );
212                 if ( fd > -1 )
213                 {
214                         uint8_t buf[4096];
215                         int rd = ::read(fd, buf, 4096);
216                         ::close(fd);
217                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
218                         {
219                                 Event ev(buf);
220                                 parseFrom(&ev, tsidonid);
221                                 return 0;
222                         }
223                 }
224         }
225         return -1;
226 }
227
228 std::string eServiceEvent::getBeginTimeString() const
229 {
230         tm t;
231         localtime_r(&m_begin, &t);
232         char tmp[13];
233         snprintf(tmp, 13, "%02d.%02d, %02d:%02d",
234                 t.tm_mday, t.tm_mon+1,
235                 t.tm_hour, t.tm_min);
236         return std::string(tmp, 12);
237 }
238
239 RESULT eServiceEvent::getGenreData(ePtr<eGenreData> &dest) const
240 {
241         std::list<eGenreData>::const_iterator it = m_genres.begin();
242         for(;it != m_genres.end(); ++it) {
243                 dest = new eGenreData(*it);
244                 //  for now just return the first item on the list
245                 return 0;
246         }
247         dest = 0;
248         return -1;
249 }
250
251 PyObject *eServiceEvent::getGenreData() const
252 {
253         ePyObject ret = PyList_New(m_genres.size());
254         int cnt=0;
255         for (std::list<eGenreData>::const_iterator it(m_genres.begin()); it != m_genres.end(); ++it)
256         {
257                 ePyObject tuple = PyTuple_New(4);
258                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->getLevel1()));
259                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getLevel2()));
260                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->getUser1()));
261                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->getUser2()));
262                 PyList_SET_ITEM(ret, cnt++, tuple);
263         }
264         return ret;
265 }
266
267 RESULT eServiceEvent::getParentalData(ePtr<eParentalData> &dest) const
268 {
269         std::list<eParentalData>::const_iterator it = m_ratings.begin();
270         for(;it != m_ratings.end(); ++it) {
271                 dest = new eParentalData(*it);
272                 //  for now just return the first item on the list
273                 return 0;
274         }
275         dest = 0;
276         return -1;
277 }
278
279 PyObject *eServiceEvent::getParentalData() const
280 {
281         ePyObject ret = PyList_New(m_ratings.size());
282         int cnt = 0;
283         for (std::list<eParentalData>::const_iterator it(m_ratings.begin()); it != m_ratings.end(); ++it)
284         {
285                 ePyObject tuple = PyTuple_New(2);
286                 PyTuple_SET_ITEM(tuple, 0, PyString_FromString(it->getCountryCode().c_str()));
287                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getRating()));
288                 PyList_SET_ITEM(ret, cnt++, tuple);
289         }
290         return ret;
291 }
292
293 RESULT eServiceEvent::getComponentData(ePtr<eComponentData> &dest, int tagnum) const
294 {
295         std::list<eComponentData>::const_iterator it =
296                 m_component_data.begin();
297         for(;it != m_component_data.end(); ++it)
298         {
299                 if ( it->m_componentTag == tagnum )
300                 {
301                         dest=new eComponentData(*it);
302                         return 0;
303                 }
304         }
305         dest = 0;
306         return -1;
307 }
308
309 PyObject *eServiceEvent::getComponentData() const
310 {
311         ePyObject ret = PyList_New(m_component_data.size());
312         int cnt = 0;
313         for (std::list<eComponentData>::const_iterator it(m_component_data.begin()); it != m_component_data.end(); ++it)
314         {
315                 ePyObject tuple = PyTuple_New(5);
316                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->m_componentTag));
317                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->m_componentType));
318                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->m_streamContent));
319                 PyTuple_SET_ITEM(tuple, 3, PyString_FromString(it->m_iso639LanguageCode.c_str()));
320                 PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->m_text.c_str()));
321                 PyList_SET_ITEM(ret, cnt++, tuple);
322         }
323         return ret;
324 }
325
326 RESULT eServiceEvent::getLinkageService(eServiceReference &service, eServiceReference &parent, int num) const
327 {
328         std::list<eServiceReference>::const_iterator it =
329                 m_linkage_services.begin();
330         while( it != m_linkage_services.end() && num-- )
331                 ++it;
332         if ( it != m_linkage_services.end() )
333         {
334                 service = *it;
335                 eServiceReferenceDVB &subservice = (eServiceReferenceDVB&) service;
336                 eServiceReferenceDVB &current = (eServiceReferenceDVB&) parent;
337                 subservice.setDVBNamespace(current.getDVBNamespace());
338                 if ( current.getParentTransportStreamID().get() )
339                 {
340                         subservice.setParentTransportStreamID( current.getParentTransportStreamID() );
341                         subservice.setParentServiceID( current.getParentServiceID() );
342                 }
343                 else
344                 {
345                         subservice.setParentTransportStreamID( current.getTransportStreamID() );
346                         subservice.setParentServiceID( current.getServiceID() );
347                 }
348                 if ( subservice.getParentTransportStreamID() == subservice.getTransportStreamID() &&
349                         subservice.getParentServiceID() == subservice.getServiceID() )
350                 {
351                         subservice.setParentTransportStreamID( eTransportStreamID(0) );
352                         subservice.setParentServiceID( eServiceID(0) );
353                 }
354                 return 0;
355         }
356         service.type = eServiceReference::idInvalid;
357         return -1;
358 }
359
360 DEFINE_REF(eDebugClass);