Ticket #3263: dvbdescriptors.cpp

File dvbdescriptors.cpp, 13.2 KB (added by osind@…, 17 years ago)
Line 
1#include "dvbdescriptors.h"
2#include "iso6937tables.h"
3
4#include <unistd.h>
5#include <qtextcodec.h>
6#include <qdeepcopy.h>
7
8// Only some of the QTextCodec calls are reenterant.
9// If you use this please verify that you are using a reenterant call.
10static const QTextCodec *iso8859_codecs[16] =
11{
12    QTextCodec::codecForName("Latin1"),
13    QTextCodec::codecForName("ISO8859-1"),  // Western
14    QTextCodec::codecForName("ISO8859-2"),  // Central European
15    QTextCodec::codecForName("ISO8859-3"),  // Central European
16    QTextCodec::codecForName("ISO8859-4"),  // Baltic
17    QTextCodec::codecForName("ISO8859-5"),  // Cyrillic
18    QTextCodec::codecForName("ISO8859-6"),  // Arabic
19    QTextCodec::codecForName("ISO8859-7"),  // Greek
20    QTextCodec::codecForName("ISO8859-8"),  // Hebrew, visually ordered
21    QTextCodec::codecForName("ISO8859-9"),  // Turkish
22    QTextCodec::codecForName("ISO8859-10"),
23    QTextCodec::codecForName("ISO8859-11"),
24    QTextCodec::codecForName("ISO8859-12"),
25    QTextCodec::codecForName("ISO8859-13"),
26    QTextCodec::codecForName("ISO8859-14"),
27    QTextCodec::codecForName("ISO8859-15"), // Western
28};
29
30static QString decode_iso6937(const unsigned char *buf, uint length)
31{
32    // ISO/IEC 6937 to unicode (UCS2) convertor...
33    // This is a composed encoding - accent first then plain character
34    QString result = "";
35    ushort ch = 0x20;
36    for (uint i = 0; (i < length) && buf[i]; i++)
37    {
38        if (ch == 0xFFFF)
39        {
40            // Process second byte of two byte character
41            ch = iso6937table_secondary[buf[i-1]][buf[i]];
42            if (ch == 0xFFFF)
43            {
44                // If no valid code found in secondary table,
45                // reprocess this second byte as first byte.
46                ch = iso6937table_base[buf[i]];
47                if (ch == 0xFFFF)
48                    continue; // process second byte
49            }
50        }
51        else
52        {
53            // Process first character of two possible characters.
54            // double byte characters have a sentinel (0xffff) in this table.
55            ch = iso6937table_base[buf[i]];
56            if (ch == 0xFFFF)
57                continue; // process second byte
58
59        }
60        result += QChar(ch);
61    }
62    return result;
63}
64
65// Decode a text string according to ETSI EN 300 468 Annex A
66QString dvb_decode_text(const unsigned char *src, uint raw_length,
67                        const unsigned char *encoding_override,
68                        uint encoding_override_length)
69{       
70    if (!raw_length)
71        return "";
72       
73    if ((0x10 < src[0]) && (src[0] < 0x20))
74    {
75        // TODO: Handle multi-byte encodings
76        VERBOSE(VB_SIPARSER, "dvb_decode_text: "
77                "Multi-byte coded text is not yet supported.");
78        return "";
79    }
80
81    // Strip formatting characters
82    // Also, if a override encoding is specified copy it in front of the text
83    unsigned char dst[raw_length + encoding_override_length];
84    uint length = encoding_override_length;
85    if (encoding_override)
86        memcpy(dst, encoding_override, encoding_override_length);
87                   
88    for (uint i = 0; i < raw_length; i++)
89    {
90        if ((src[i] < 0x80) || (src[i] > 0x9F))
91        {
92            dst[length] = src[i];
93            length++;
94        }
95    }
96    const unsigned char *buf = dst;
97
98    // Exit on empty string, sans formatting.
99    if (!length)
100        return "";
101
102    // Decode using the correct text codec
103    if (buf[0] >= 0x20)
104    {
105        return decode_iso6937(buf, length);
106    }
107    else if ((buf[0] >= 0x01) && (buf[0] <= 0x0B))
108    {
109        return iso8859_codecs[4 + buf[0]]->toUnicode((char*)(buf + 1), length - 1);
110    }
111    else if (buf[0] == 0x10)
112    {
113        // If the first byte of the text field has a value "0x10"
114        // then the following two bytes carry a 16-bit value (uimsbf) N
115        // to indicate that the remaining data of the text field is
116        // coded using the character code table specified by
117        // ISO Standard 8859, parts 1 to 9
118
119        uint code = buf[1] << 8 | buf[2];
120        if (code <= 15)
121            return iso8859_codecs[code]->toUnicode((char*)(buf + 3), length - 3);
122        else
123            return QString::fromLocal8Bit((char*)(buf + 3), length - 3);
124    }
125    else
126    {
127        // Unknown/invalid encoding - assume local8Bit
128        return QString::fromLocal8Bit((char*)(buf + 1), length - 1);
129    }
130
131}
132
133QMutex            ContentDescriptor::categoryLock;
134map<uint,QString> ContentDescriptor::categoryDesc;
135bool              ContentDescriptor::categoryDescExists = false;
136
137QString myth_category_type_to_string(uint category_type)
138{
139    static const char *cattype[] =
140        { "", "movie", "series", "sports", "tvshow", };
141
142    if ((category_type > kCategoryNone) && (category_type < kCategoryLast))
143        return QString(cattype[category_type]);
144
145    return QString::null;
146}
147
148MythCategoryType string_to_myth_category_type(const QString &category_type)
149{
150    static const char *cattype[] =
151        { "", "movie", "series", "sports", "tvshow", };
152
153    for (uint i = 1; i < 5; i++)
154        if (category_type == cattype[i])
155            return (MythCategoryType) i;
156    return kCategoryNone;
157}
158
159MythCategoryType ContentDescriptor::GetMythCategory(uint i) const
160{
161    if (0x1 == Nibble1(i))
162        return kCategoryMovie;
163    if (0x4 == Nibble1(i))
164        return kCategorySports;
165    return kCategoryTVShow;
166}
167
168QString ContentDescriptor::GetDescription(uint i) const
169{
170    if (!categoryDescExists)
171        Init();
172
173    QMutexLocker locker(&categoryLock);
174
175    // Try to get detailed description
176    map<uint,QString>::const_iterator it = categoryDesc.find(Nibble(i));
177    if (it != categoryDesc.end())
178        return QDeepCopy<QString>((*it).second);
179
180    // Fall back to category description
181    it = categoryDesc.find(Nibble1(i)<<4);
182    if (it != categoryDesc.end())
183        return QDeepCopy<QString>((*it).second);
184
185    // Found nothing? Just return empty string.
186    return "";
187}
188
189QString ContentDescriptor::toString() const
190{
191    QString tmp("");
192    for (uint i = 0; i < Count(); i++)
193        tmp += GetMythCategory(i) + " : " + GetDescription(i);
194    return tmp;
195}
196
197void ContentDescriptor::Init(void)
198{
199    QMutexLocker locker(&categoryLock);
200
201    if (categoryDescExists)
202        return;
203
204    categoryDesc[0x10] = QObject::tr("Movie");
205    categoryDesc[0x11] = QObject::tr("Movie") + " - " +
206        QObject::tr("Detective/Thriller");
207    categoryDesc[0x12] = QObject::tr("Movie")+ " - " +
208        QObject::tr("Adventure/Western/War");
209    categoryDesc[0x13] = QObject::tr("Movie")+ " - " +
210        QObject::tr("Science Fiction/Fantasy/Horror");
211    categoryDesc[0x14] = QObject::tr("Movie")+ " - " +
212        QObject::tr("Comedy");
213    categoryDesc[0x15] = QObject::tr("Movie")+ " - " +
214        QObject::tr("Soap/melodrama/folkloric");
215    categoryDesc[0x16] = QObject::tr("Movie")+ " - " +
216        QObject::tr("Romance");
217    categoryDesc[0x17] = QObject::tr("Movie")+ " - " +
218        QObject::tr("Serious/Classical/Religious/Historical Movie/Drama");
219    categoryDesc[0x18] = QObject::tr("Movie")+ " - " +
220        QObject::tr("Adult", "Adult Movie");
221   
222    categoryDesc[0x20] = QObject::tr("News");
223    categoryDesc[0x21] = QObject::tr("News/weather report");
224    categoryDesc[0x22] = QObject::tr("News magazine");
225    categoryDesc[0x23] = QObject::tr("Documentary");
226    categoryDesc[0x24] = QObject::tr("Intelligent Programmes");
227   
228    categoryDesc[0x30] = QObject::tr("Show/game Show");
229    categoryDesc[0x31] = QObject::tr("Game Show");
230    categoryDesc[0x32] = QObject::tr("Variety Show");
231    categoryDesc[0x33] = QObject::tr("Talk Show");
232   
233    categoryDesc[0x40] = QObject::tr("Sports");
234    categoryDesc[0x41] =
235        QObject::tr("Special Events (World Cup, World Series..)");
236    categoryDesc[0x42] = QObject::tr("Sports Magazines");
237    categoryDesc[0x43] = QObject::tr("Football (Soccer)");
238    categoryDesc[0x44] = QObject::tr("Tennis/Squash");
239    categoryDesc[0x45] =
240        QObject::tr("Misc. Team Sports"); // not football/soccer
241    categoryDesc[0x46] = QObject::tr("Athletics");
242    categoryDesc[0x47] = QObject::tr("Motor Sport");
243    categoryDesc[0x48] = QObject::tr("Water Sport");
244    categoryDesc[0x49] = QObject::tr("Winter Sports");
245    categoryDesc[0x4A] = QObject::tr("Equestrian");
246    categoryDesc[0x4B] = QObject::tr("Martial Sports");
247   
248    categoryDesc[0x50] = QObject::tr("Kids");
249    categoryDesc[0x51] = QObject::tr("Pre-School Children's Programmes");
250    categoryDesc[0x52] = QObject::tr("Entertainment Programmes for 6 to 14");
251    categoryDesc[0x53] = QObject::tr("Entertainment Programmes for 10 to 16");
252    categoryDesc[0x54] = QObject::tr("Informational/Educational");
253    categoryDesc[0x55] = QObject::tr("Cartoons/Puppets");
254   
255    categoryDesc[0x60] = QObject::tr("Music/Ballet/Dance");
256    categoryDesc[0x61] = QObject::tr("Rock/Pop");
257    categoryDesc[0x62] = QObject::tr("Classical Music");
258    categoryDesc[0x63] = QObject::tr("Folk Music");
259    categoryDesc[0x64] = QObject::tr("Jazz");
260    categoryDesc[0x65] = QObject::tr("Musical/Opera");
261    categoryDesc[0x66] = QObject::tr("Ballet");
262
263    categoryDesc[0x70] = QObject::tr("Arts/Culture");
264    categoryDesc[0x71] = QObject::tr("Performing Arts");
265    categoryDesc[0x72] = QObject::tr("Fine Arts");
266    categoryDesc[0x73] = QObject::tr("Religion");
267    categoryDesc[0x74] = QObject::tr("Popular Culture/Traditional Arts");
268    categoryDesc[0x75] = QObject::tr("Literature");
269    categoryDesc[0x76] = QObject::tr("Film/Cinema");
270    categoryDesc[0x77] = QObject::tr("Experimental Film/Video");
271    categoryDesc[0x78] = QObject::tr("Broadcasting/Press");
272    categoryDesc[0x79] = QObject::tr("New Media");
273    categoryDesc[0x7A] = QObject::tr("Arts/Culture Magazines");
274    categoryDesc[0x7B] = QObject::tr("Fashion");
275   
276    categoryDesc[0x80] = QObject::tr("Social/Policical/Economics");
277    categoryDesc[0x81] = QObject::tr("Magazines/Reports/Documentary");
278    categoryDesc[0x82] = QObject::tr("Economics/Social Advisory");
279    categoryDesc[0x83] = QObject::tr("Remarkable People");
280   
281    categoryDesc[0x90] = QObject::tr("Education/Science/Factual");
282    categoryDesc[0x91] = QObject::tr("Nature/animals/Environment");
283    categoryDesc[0x92] = QObject::tr("Technology/Natural Sciences");
284    categoryDesc[0x93] = QObject::tr("Medicine/Physiology/Psychology");
285    categoryDesc[0x94] = QObject::tr("Foreign Countries/Expeditions");
286    categoryDesc[0x95] = QObject::tr("Social/Spiritual Sciences");
287    categoryDesc[0x96] = QObject::tr("Further Education");
288    categoryDesc[0x97] = QObject::tr("Languages");
289   
290    categoryDesc[0xA0] = QObject::tr("Leisure/Hobbies");
291    categoryDesc[0xA1] = QObject::tr("Tourism/Travel");
292    categoryDesc[0xA2] = QObject::tr("Handicraft");
293    categoryDesc[0xA3] = QObject::tr("Motoring");
294    categoryDesc[0xA4] = QObject::tr("Fitness & Health");
295    categoryDesc[0xA5] = QObject::tr("Cooking");
296    categoryDesc[0xA6] = QObject::tr("Advertizement/Shopping");
297    categoryDesc[0xA7] = QObject::tr("Gardening");
298    // Special
299    categoryDesc[0xB0] = QObject::tr("Original Language");
300    categoryDesc[0xB1] = QObject::tr("Black & White");
301    categoryDesc[0xB2] = QObject::tr("\"Unpublished\" Programmes");
302    categoryDesc[0xB3] = QObject::tr("Live Broadcast");
303    // UK Freeview custom id
304    categoryDesc[0xF0] = QObject::tr("Drama");
305
306    categoryDescExists = true;
307}
308
309QString FrequencyListDescriptor::toString() const
310{
311    QString str = "FrequencyListDescriptor: frequencies: ";
312
313    for (uint i = 0; i < FrequencyCount(); i++)
314        str.append(QString(" %1").arg(FrequencyHz(i)));
315
316    return str;
317}
318
319QString ServiceDescriptor::toString() const
320{
321    QString str = QString("ServiceDescriptor: %1").arg(ServiceName());
322
323    if (IsDTV())
324        str.append(" (TV)");
325    else if (IsDigitalAudio())
326        str.append(" (Radio)");
327    else if (IsHDTV())
328        str.append(" (HDTV)");
329    else if (IsTeletext())
330        str.append(" (Teletext)");
331    else
332        str.append(QString(" (Unknown %1)").arg(ServiceType(),2,16));
333
334    return str;
335}
336
337QString CableDeliverySystemDescriptor::toString() const
338{
339    QString str = QString("CableDeliverySystemDescriptor: ");
340
341    str.append(QString("Frequency: %1\n").arg(FrequencyHz()));
342    str.append(QString("      Mod=%1, SymbR=%2, FECInner=%3, FECOuter=%4")
343        .arg(ModulationString())
344        .arg(SymbolRateHz())
345        .arg(FECInnerString())
346        .arg(FECOuterString()));
347
348    return str;
349}
350
351QString SatelliteDeliverySystemDescriptor::toString() const
352{
353    QString str = QString("SatelliteDeliverySystemDescriptor: ");
354
355    str.append(QString("Frequency: %1\n").arg(FrequencyHz()));
356    str.append(QString("      Mod=%1, SymbR=%2, FECInner=%3, Orbit=%4, Pol=%5")
357        .arg(ModulationString())
358        .arg(SymbolRateHz())
359        .arg(FECInnerString())
360        .arg(OrbitalPositionString())
361        .arg(PolarizationString()));
362
363    return str;
364}
365
366QString TerrestrialDeliverySystemDescriptor::toString() const
367{
368    QString str = QString("TerrestrialDeliverySystemDescriptor: ");
369
370    str.append(QString("Frequency: %1\n").arg(FrequencyHz()));
371    str.append(QString("      BW=%1k, C=%2, HP=%3, LP=%4, GI=%5, TransMode=%6k")
372        .arg(BandwidthString())
373        .arg(ConstellationString())
374        .arg(CodeRateHPString())
375        .arg(CodeRateLPString())
376        .arg(GuardIntervalString())
377        .arg(TransmissionModeString()));
378
379    return str;
380}
381